|
17 | 17 |
|
18 | 18 |
|
19 | 19 |
|
20 | | -A library for resizable & repositionable panel layouts, using |
21 | | -[CSS `grid`](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout). |
| 20 | +A library for resizable & repositionable panel layouts. |
22 | 21 |
|
23 | 22 | - Zero depedencies, pure TypeScript, tiny. |
24 | 23 | - Implemented as a [Web Component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components), |
25 | | - interoperable with any framework and fully customizable. |
| 24 | + interoperable with any framework. |
| 25 | +- Zero DOM mutation at runtime, implemented entirely by generating using |
| 26 | +[CSS `grid`](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Grid_layout) rules. |
| 27 | +- Supports arbitrary theming via CSS [variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascading_variables/Using_custom_properties) and [`::part`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/::part). |
| 28 | +- Supports async-aware container rendering for smooth animations even when rendering ovvurs over an event loop boundary. |
26 | 29 | - Covered in bees. |
27 | 30 |
|
| 31 | +## Demo |
| 32 | + |
| 33 | +<a href="https://texodus.github.io/regular-layout/"><img src="./examples/PREVIEW.png" /></a> |
| 34 | + |
28 | 35 | ## Installation |
29 | 36 |
|
30 | 37 | ```bash |
31 | 38 | npm install regular-layout |
32 | 39 | ``` |
33 | 40 |
|
34 | | -## Usage |
| 41 | +## Quick Start |
35 | 42 |
|
36 | | -Add the `<regular-layout>` custom element to your HTML: |
| 43 | +Import the library and add `<regular-layout>` to your HTML. Children are |
| 44 | +matched to layout slots by their `name` attribute. |
37 | 45 |
|
38 | 46 | ```html |
| 47 | +<script type="module" src="regular-layout/dist/index.js"></script> |
| 48 | + |
39 | 49 | <regular-layout> |
40 | 50 | <div name="main">Main content</div> |
41 | 51 | <div name="sidebar">Sidebar content</div> |
42 | 52 | </regular-layout> |
43 | 53 | ``` |
44 | 54 |
|
45 | | -Create and manipulate layouts programmatically: |
| 55 | +For draggable, tabbed panels, use `<regular-layout-frame>`: |
| 56 | + |
| 57 | +```html |
| 58 | +<regular-layout> |
| 59 | + <regular-layout-frame name="main"> |
| 60 | + Main content |
| 61 | + </regular-layout-frame> |
| 62 | + <regular-layout-frame name="sidebar"> |
| 63 | + Sidebar content |
| 64 | + </regular-layout-frame> |
| 65 | +</regular-layout> |
| 66 | +``` |
| 67 | + |
| 68 | +Panels must be added and remove programmatically (e.g they are not |
| 69 | +auto-registered): |
46 | 70 |
|
47 | 71 | ```javascript |
48 | | -import "regular-layout/dist/index.js"; |
| 72 | +const layout = document.querySelector("regular-layout"); |
49 | 73 |
|
50 | | -const layout = document.querySelector('regular-layout'); |
| 74 | +// This adds the panel definition to the layout (and makes it visible via CSS), |
| 75 | +// but does not mutat the DOM. |
| 76 | +layout.insertPanel("main"); |
| 77 | +layout.insertPanel("sidebar"); |
51 | 78 |
|
52 | | -// Add panels |
53 | | -layout.insertPanel('main'); |
54 | | -layout.insertPanel('sidebar'); |
| 79 | +// This removes the panel from the layout (and hides it via CSS) but does not |
| 80 | +// mutate the DOM. |
| 81 | +layout.removePanel("sidebar"); |
| 82 | +``` |
55 | 83 |
|
56 | | -// Save layout state |
| 84 | +## Save/Restore |
| 85 | + |
| 86 | +Layout state serializes to a JSON tree of splits and tabs, which can be |
| 87 | +persisted and restored: |
| 88 | + |
| 89 | +```javascript |
57 | 90 | const state = layout.save(); |
| 91 | +localStorage.setItem("layout", JSON.stringify(state)); |
| 92 | + |
| 93 | +// Later... |
| 94 | +layout.restore(JSON.parse(localStorage.getItem("layout"))); |
| 95 | +``` |
58 | 96 |
|
59 | | -// Remove panels (this does not change the DOM, the element is unslotted). |
60 | | -layout.removePanel('sidebar'); |
| 97 | +`restore()` dispatches a cancelable `regular-layout-resize-before` event before |
| 98 | +applying the new state. Call `preventDefault()` to suspend the update, then |
| 99 | +`layout.resumeResize()` when ready: |
61 | 100 |
|
62 | | -// Restore saved state |
63 | | -layout.restore(state); |
| 101 | +```javascript |
| 102 | +layout.addEventListener("regular-layout-resize-before", (event) => { |
| 103 | + event.preventDefault(); |
| 104 | + // ... prepare for resize ... |
| 105 | + layout.resumeResize(); |
| 106 | +}); |
64 | 107 | ``` |
65 | 108 |
|
66 | | -Create repositionable panels using `<regular-layout-frame>`: |
| 109 | +The `restore()` API can also be used as an alternative to |
| 110 | +`insertPanel`/`removePanel` for initializing a `<regular-layout>`. |
| 111 | + |
| 112 | +## Theming |
| 113 | + |
| 114 | +Themes are plain CSS files that style the layout and its `::part()` selectors, |
| 115 | +scoped by a class on `<regular-layout>`. Apply a theme by adding its stylesheet |
| 116 | +and setting the class: |
67 | 117 |
|
68 | 118 | ```html |
69 | | -<regular-layout> |
70 | | - <regular-layout-frame name="main"> |
71 | | - Main content |
72 | | - </regular-layout-frame> |
| 119 | +<link rel="stylesheet" href="regular-layout/themes/chicago.css"> |
| 120 | + |
| 121 | +<regular-layout class="chicago"> |
| 122 | + ... |
73 | 123 | </regular-layout> |
74 | | -``` |
| 124 | +``` |
| 125 | + |
| 126 | +`<regular-layout-frame>` exposes these CSS parts: |
| 127 | + |
| 128 | +| Part | Description | |
| 129 | +|------|-------------| |
| 130 | +| `titlebar` | Tab bar container | |
| 131 | +| `tab` | Individual tab | |
| 132 | +| `active-tab` | Currently selected tab | |
| 133 | +| `close` | Close button | |
| 134 | +| `active-close` | Close button on the active tab | |
| 135 | +| `container` | Content area | |
| 136 | + |
| 137 | +```css |
| 138 | +regular-layout.mytheme regular-layout-frame::part(titlebar) { |
| 139 | + background: #333; |
| 140 | +} |
| 141 | + |
| 142 | +regular-layout.mytheme regular-layout-frame::part(active-tab) { |
| 143 | + background: #fff; |
| 144 | + color: #000; |
| 145 | +} |
| 146 | +``` |
| 147 | + |
| 148 | +See [the example `themes/`](./themes) directory for examples of how to write a |
| 149 | +complete theme for `<regular-layout>` and `regular-layout-frame>`. |
| 150 | + |
| 151 | +## Events |
| 152 | + |
| 153 | +| Event | Detail | Cancelable | Description | |
| 154 | +|-------|--------|------------|-------------| |
| 155 | +| `regular-layout-resize-before` | `{ calculatePresizePaths() }` | Yes | Fired before any layout change. Cancel to suspend until `resumeResize()`. | |
| 156 | +| `regular-layout-update` | `Layout` | No | Fired after layout state is updated. | |
| 157 | + |
| 158 | +```javascript |
| 159 | +layout.addEventListener("regular-layout-update", (event) => { |
| 160 | + console.log("New layout:", event.detail); |
| 161 | +}); |
| 162 | +``` |
0 commit comments