react-zeugma 6.5.1 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +340 -394
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/{types-DO2k-HLr.d.cts → types-CqFrNqQ6.d.cts} +11 -6
- package/dist/{types-DO2k-HLr.d.ts → types-CqFrNqQ6.d.ts} +11 -6
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,84 +1,59 @@
|
|
|
1
1
|
# react-zeugma
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
`react-zeugma` combines the tree-based, arbitrary splitting capabilities of `react-mosaic` with the declarative, state-driven API model of `react-grid-layout`. Built with React 18+, TypeScript, and [`@dnd-kit`](https://dndkit.com).
|
|
3
|
+
A recursive, drag-and-drop dashboard layout engine for React. It combines the tree-based, arbitrary splitting capabilities of `react-mosaic` with the declarative, state-driven API model of `react-grid-layout`, powered by `@dnd-kit/core`.
|
|
6
4
|
|
|
7
5
|
[](https://www.npmjs.com/package/react-zeugma)
|
|
8
6
|
[](https://bundlephobia.com/package/react-zeugma)
|
|
9
7
|
[](./LICENSE)
|
|
10
8
|
[](https://www.typescriptlang.org)
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
> **Headless Design System** — react-zeugma is entirely style-agnostic and relies on your class name configurations for styling visual states. You bring your own CSS/Tailwind rules, and we handle the complex drag-and-drop mechanics, resize handle math, and layout tree calculations.
|
|
14
|
-
|
|
15
|
-
### Core Features
|
|
16
|
-
|
|
17
|
-
- **Recursive Split Trees**: Nest rows and columns to any depth using a simple serialized JSON node structure.
|
|
18
|
-
- **4-Zone Docking Previews**: Drag panels on the top, bottom, left, or right edges of another pane to split it.
|
|
19
|
-
- **Native Flexbox Resizers**: Fluid, non-blocking split handles built on pointer events.
|
|
20
|
-
- **Accessible Drag-and-Drop**: Built on top of the performant and accessible [`@dnd-kit`](https://dndkit.com) toolkit.
|
|
21
|
-
- **Fullscreen Zoom Toggle**: Programmatically expand any pane to cover the entire viewport and snap it back instantly.
|
|
22
|
-
|
|
23
|
-
---
|
|
10
|
+
It is completely style-agnostic (headless), meaning you style all container states, resizers, and drop previews with your own class names.
|
|
24
11
|
|
|
25
12
|
## Installation
|
|
26
13
|
|
|
27
|
-
Install the package into your React project using your preferred package manager.
|
|
28
|
-
|
|
29
14
|
```bash
|
|
30
15
|
npm install react-zeugma
|
|
31
16
|
```
|
|
32
17
|
|
|
33
|
-
> [!NOTE]
|
|
34
|
-
> **Peer Dependencies** — react-zeugma is compatible with both **React 18** and **React 19** (along with matching `react-dom`).
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
18
|
## Quick Start
|
|
39
19
|
|
|
40
|
-
|
|
20
|
+
Initialize your layout tree with `useZeugma` and render the dashboard using `<Zeugma>`.
|
|
41
21
|
|
|
42
22
|
```tsx
|
|
43
|
-
import { useZeugma, Zeugma,
|
|
23
|
+
import { useZeugma, Zeugma, Pane, TreeNode } from 'react-zeugma'
|
|
44
24
|
|
|
25
|
+
// 1. Define the initial layout tree structure
|
|
45
26
|
const initialLayout: TreeNode = {
|
|
46
27
|
type: 'split',
|
|
47
28
|
direction: 'row',
|
|
48
|
-
splitPercentage:
|
|
49
|
-
first: { type: 'pane', id: '
|
|
50
|
-
second: {
|
|
51
|
-
type: 'split',
|
|
52
|
-
direction: 'row',
|
|
53
|
-
splitPercentage: 50,
|
|
54
|
-
first: { type: 'pane', id: 'editor', tabs: ['editor'], activeTabId: 'editor' },
|
|
55
|
-
second: { type: 'pane', id: 'preview', tabs: ['preview'], activeTabId: 'preview' },
|
|
56
|
-
},
|
|
29
|
+
splitPercentage: 30,
|
|
30
|
+
first: { type: 'pane', id: 'left-panel', tabs: ['left-panel'], activeTabId: 'left-panel' },
|
|
31
|
+
second: { type: 'pane', id: 'right-panel', tabs: ['right-panel'], activeTabId: 'right-panel' },
|
|
57
32
|
}
|
|
58
33
|
|
|
59
|
-
|
|
34
|
+
// 2. Build your custom pane wrapper
|
|
35
|
+
function DashboardPane({ id }: { id: string }) {
|
|
60
36
|
return (
|
|
61
37
|
<Pane id={id}>
|
|
62
|
-
<div className="
|
|
63
|
-
<Pane.DragHandle>
|
|
64
|
-
|
|
65
|
-
<span className="text-xs uppercase text-zinc-300 font-bold">{id}</span>
|
|
66
|
-
</div>
|
|
38
|
+
<div className="flex flex-col h-full bg-zinc-900 border border-zinc-700">
|
|
39
|
+
<Pane.DragHandle className="p-2 bg-zinc-800 cursor-grab text-zinc-300 font-semibold">
|
|
40
|
+
{id}
|
|
67
41
|
</Pane.DragHandle>
|
|
68
|
-
<Pane.Content className="flex-1 p-4 text-
|
|
69
|
-
{(tab) => <div>Content
|
|
42
|
+
<Pane.Content className="flex-1 p-4 text-zinc-400">
|
|
43
|
+
{(tab) => <div>Active Tab Content: {tab.id}</div>}
|
|
70
44
|
</Pane.Content>
|
|
71
45
|
</div>
|
|
72
46
|
</Pane>
|
|
73
47
|
)
|
|
74
48
|
}
|
|
75
49
|
|
|
76
|
-
|
|
50
|
+
// 3. Mount the layout controller and dashboard renderer
|
|
51
|
+
export default function DashboardApp() {
|
|
77
52
|
const controller = useZeugma({ initialLayout })
|
|
78
53
|
|
|
79
54
|
return (
|
|
80
55
|
<div className="w-screen h-screen">
|
|
81
|
-
<Zeugma controller={controller} renderPane={(
|
|
56
|
+
<Zeugma controller={controller} renderPane={(paneId) => <DashboardPane id={paneId} />} />
|
|
82
57
|
</div>
|
|
83
58
|
)
|
|
84
59
|
}
|
|
@@ -88,427 +63,398 @@ export default function Dashboard() {
|
|
|
88
63
|
|
|
89
64
|
## API Reference
|
|
90
65
|
|
|
91
|
-
###
|
|
92
|
-
|
|
93
|
-
The main visual dashboard grid renderer and context provider.
|
|
94
|
-
|
|
95
|
-
- **With Children (Provider Mode)**: If `<Zeugma>` is rendered with children, it acts as the context provider. You must pass the `controller` prop to it, and the children will have access to the Zeugma context functions.
|
|
96
|
-
- **Without Children (Renderer/Standalone Mode)**: If `<Zeugma>` is rendered without children, it acts as both the provider and the visual layout renderer. If it is nested within a parent `<Zeugma>` provider, it automatically reads the state, configuration, and callbacks directly from the parent context.
|
|
97
|
-
|
|
98
|
-
| Prop | Type | Required | Description |
|
|
99
|
-
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | --------------------------------------------------------------------------------------------- |
|
|
100
|
-
| `controller` | `ZeugmaController` | Standalone only | The Zeugma controller object returned by `useZeugma(options)`. |
|
|
101
|
-
| `renderPane` | `(paneId: string) => ReactNode` | Standalone only | Renderer function lookup that returns a `<Pane>` structure. |
|
|
102
|
-
| `classNames` | `ZeugmaClassNames` | No | Custom classes for overriding pane, resizer, and drop preview overlays. |
|
|
103
|
-
| `renderDragOverlay` | `(active: DragOverlayActiveItem) => ReactNode` | No | Renders a custom cursor-following drag preview overlay. |
|
|
104
|
-
| `resizerSize` | `number` | No | Thickness of the split resizer bars in pixels. Defaults to `4`. |
|
|
105
|
-
| `dragActivationDistance` | `number` | No | Minimum pointer drag distance (in pixels) required to activate dragging (defaults to `8`). |
|
|
106
|
-
| `snapThreshold` | `number` | No | Threshold in pixels to snap layout resizers to adjacent edges (defaults to `8`). |
|
|
107
|
-
| `minSplitPercentage` | `number` | No | Minimum resizing limit percentage (defaults to `5`). |
|
|
108
|
-
| `maxSplitPercentage` | `number` | No | Maximum resizing limit percentage (defaults to `95`). |
|
|
109
|
-
| `enableDragToDismiss` | `boolean` | No | If true, enables the drag-out-to-dismiss gesture to close widgets (defaults to `false`). |
|
|
110
|
-
| `dismissThreshold` | `number` | No | Distance in pixels outside container bounds required to trigger dismissal (defaults to `60`). |
|
|
111
|
-
| `onRemove` | `(paneId: string) => void` | No | Callback triggered when a pane is removed. |
|
|
112
|
-
| `onDragStart` | `(activeId: string) => void` | No | Callback triggered when dragging starts. |
|
|
113
|
-
| `onDragEnd` | `(activeId: string, overId: string \| null, dropAction: { type: 'split' \| 'move'; direction?: SplitDirection; position?: string } \| null) => void` | No | Callback triggered when dragging ends. |
|
|
114
|
-
| `onResizeStart` | `(currentNode: SplitNode) => void` | No | Callback triggered when resizing starts. |
|
|
115
|
-
| `onResize` | `(currentNode: SplitNode, percentage: number) => void` | No | Callback triggered during resizing. |
|
|
116
|
-
| `onResizeEnd` | `(currentNode: SplitNode, percentage: number) => void` | No | Callback triggered when resizing ends. |
|
|
117
|
-
| `onDismissIntentChange` | `(paneId: string \| null) => void` | No | Callback triggered when drag-out intent changes. |
|
|
118
|
-
|
|
119
|
-
### `useZeugma(options)`
|
|
120
|
-
|
|
121
|
-
A custom state hook that initializes and manages the layout tree, locked state, and fullscreen mode.
|
|
122
|
-
|
|
123
|
-
| Option | Type | Default | Description |
|
|
124
|
-
| -------------------- | --------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
|
|
125
|
-
| `initialLayout` | `TreeNode \| null` | — | Initial layout tree structure for uncontrolled mode. Only used on initial mount. |
|
|
126
|
-
| `layout` | `TreeNode \| null` | — | Controlled layout tree structure. If provided, the hook runs in controlled mode and synchronizes with it. |
|
|
127
|
-
| `onChange` | `(newLayout: TreeNode \| null) => void` | — | Callback triggered when the layout changes. |
|
|
128
|
-
| `fullscreenPaneId` | `string \| null` | — | Controlled fullscreen pane ID. Pass `null` for no fullscreen pane. |
|
|
129
|
-
| `onFullscreenChange` | `(paneId: string \| null) => void` | — | Callback triggered when a pane is toggled to/from fullscreen mode. |
|
|
130
|
-
| `locked` | `boolean` | `false` | If true, layout resizes and drags are disabled. |
|
|
131
|
-
|
|
132
|
-
### `useZeugmaContext()`
|
|
133
|
-
|
|
134
|
-
A custom React context hook that returns the unified layout controller properties and state actions. Must be used within a `<Zeugma>` provider component.
|
|
135
|
-
|
|
136
|
-
Provides direct access to the current layout state (e.g., `layout`, `locked`), state setters (e.g., `setLocked`), queries (e.g., `findTabById`, `findPaneContainingTab`, `findPaneById`), and mutation actions (e.g., `addTab`, `removePane`, `selectTab`, etc.).
|
|
66
|
+
### Components
|
|
137
67
|
|
|
138
|
-
|
|
139
|
-
const { layout, locked, findTabById, setLocked, removePane } = useZeugmaContext()
|
|
140
|
-
```
|
|
68
|
+
#### `<Zeugma>`
|
|
141
69
|
|
|
142
|
-
|
|
70
|
+
The root provider and layout renderer. It configures the drag-and-drop context, calculates panel positions, and renders resize splitters.
|
|
143
71
|
|
|
144
|
-
|
|
72
|
+
##### Usage
|
|
145
73
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
-
|
|
163
|
-
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Provides direct access to the pane's state and action handlers from within any child component of `<Pane>`. Returns `PaneContextValue` which extends `PaneRenderProps`:
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
const { id, isDragging, isFullscreen, toggleFullscreen, remove, tabs, activeTabId } =
|
|
173
|
-
usePaneContext()
|
|
74
|
+
```tsx
|
|
75
|
+
import { Zeugma } from 'react-zeugma'
|
|
76
|
+
|
|
77
|
+
;<Zeugma
|
|
78
|
+
controller={controller}
|
|
79
|
+
renderPane={(paneId) => <MyPane id={paneId} />}
|
|
80
|
+
resizerSize={4}
|
|
81
|
+
dragActivationDistance={8}
|
|
82
|
+
snapThreshold={8}
|
|
83
|
+
minSplitPercentage={5}
|
|
84
|
+
maxSplitPercentage={95}
|
|
85
|
+
enableDragToDismiss={false}
|
|
86
|
+
dismissThreshold={60}
|
|
87
|
+
classNames={{
|
|
88
|
+
dashboard: 'bg-zinc-950',
|
|
89
|
+
pane: 'rounded-lg overflow-hidden',
|
|
90
|
+
resizer: 'bg-zinc-800 hover:bg-indigo-500 transition-colors',
|
|
91
|
+
dropPreview: 'bg-indigo-500/20 border border-indigo-500',
|
|
92
|
+
}}
|
|
93
|
+
onRemove={(paneId) => console.log(`Pane ${paneId} closed`)}
|
|
94
|
+
onResizeEnd={(currentNode, percentage) => console.log('Resized to', percentage)}
|
|
95
|
+
/>
|
|
174
96
|
```
|
|
175
97
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
| `
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
188
|
-
| `
|
|
189
|
-
| `
|
|
190
|
-
| `
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
|
199
|
-
| :------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------- |
|
|
200
|
-
| `tabs` | `string[]` | Yes | The list of tab IDs in this pane. |
|
|
201
|
-
| `activeTabId` | `string` | Yes | The currently active tab ID. |
|
|
202
|
-
| `locked` | `boolean` | No | Whether dragging/reordering tabs is disabled (defaults to `false`). |
|
|
203
|
-
| `tabsMetadata` | `Record<string, Record<string, any>>` | No | Metadata associated with each tab. |
|
|
204
|
-
| `selectTab` | `(id: string) => void` | Yes | Callback when a tab is selected. |
|
|
205
|
-
| `removeTab` | `(id: string) => void` | Yes | Callback when a tab is closed/removed. |
|
|
206
|
-
| `classNames` | `{ container?: string; tab?: string \| ((tabId: string) => string) }` | No | Custom class names for the container and individual tab items. |
|
|
207
|
-
| `styles` | `{ container?: CSSProperties; tab?: CSSProperties \| ((tabId: string) => CSSProperties) }` | No | Custom inline CSS styles for the container and individual tab items. |
|
|
208
|
-
| `renderTab` | `(props: { tabId: string; activeTabId: string; isDragging: boolean; isOver: boolean; metadata?: Record<string, unknown>; onSelect: () => void; onRemove: () => void }) => ReactNode` | Yes | Render prop function called for each tab item. |
|
|
209
|
-
|
|
210
|
-
### `<DragHandle>`
|
|
98
|
+
##### Props
|
|
99
|
+
|
|
100
|
+
| Property | Description | Type | Default |
|
|
101
|
+
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
|
|
102
|
+
| `controller` | The layout state controller returned by `useZeugma(options)`. | `ZeugmaController` | - |
|
|
103
|
+
| `children` | Children components rendered inside the context provider. | `ReactNode` | - |
|
|
104
|
+
| `renderPane` | Callback function to map active pane IDs to custom pane structures. Required in standalone mode (without children) and must not be passed in provider mode. | `(paneId: string) => ReactNode` | - |
|
|
105
|
+
| `renderDragOverlay` | Custom overlay renderer function for the drag-under-cursor preview. | `(active: DragOverlayActiveItem) => ReactNode` | - |
|
|
106
|
+
| `classNames` | CSS class name mapping overrides for custom dashboard and overlay styling. | `ZeugmaClassNames` | - |
|
|
107
|
+
| `resizerSize` | Thickness of the split resizer bars in pixels. | `number` | `4` |
|
|
108
|
+
| `dragActivationDistance` | Minimum pointer drag distance (in pixels) required to activate dragging. | `number` | `8` |
|
|
109
|
+
| `snapThreshold` | Threshold in pixels to snap layout resizers to adjacent edges. | `number` | `8` |
|
|
110
|
+
| `minSplitPercentage` | Minimum split limit percentage allowed for resized panes. | `number` | `5` |
|
|
111
|
+
| `maxSplitPercentage` | Maximum split limit percentage allowed for resized panes. | `number` | `95` |
|
|
112
|
+
| `enableDragToDismiss` | Enables drag-out-to-dismiss gesture for widgets. | `boolean` | `false` |
|
|
113
|
+
| `dismissThreshold` | Distance in pixels outside container bounds required to trigger dismissal. | `number` | `60` |
|
|
114
|
+
| `onRemove` | Callback triggered when a pane is removed. | `(paneId: string) => void` | - |
|
|
115
|
+
| `onDragStart` | Callback triggered when a drag gesture begins. | `(activeId: string) => void` | - |
|
|
116
|
+
| `onDragEnd` | Callback triggered when a drag gesture ends, containing active pane, target pane, and action metadata. | `(activeId: string, overId: string \| null, dropAction: { type: 'split' \| 'move'; direction?: SplitDirection; position?: 'top' \| 'bottom' \| 'left' \| 'right' \| 'center' } \| null) => void` | - |
|
|
117
|
+
| `onResizeStart` | Callback triggered when resizing begins. | `(currentNode: SplitNode) => void` | - |
|
|
118
|
+
| `onResize` | Callback triggered during pane resizing. | `(currentNode: SplitNode, percentage: number) => void` | - |
|
|
119
|
+
| `onResizeEnd` | Callback triggered when pane resizing completes. | `(currentNode: SplitNode, percentage: number) => void` | - |
|
|
120
|
+
| `onDismissIntentChange` | Callback triggered when drag-out dismiss intent changes. | `(paneId: string \| null) => void` | - |
|
|
211
121
|
|
|
212
|
-
|
|
122
|
+
---
|
|
213
123
|
|
|
214
|
-
|
|
215
|
-
| ----------- | --------------------- | -------- | ---------------------------------------------------------------- |
|
|
216
|
-
| `children` | `ReactNode` | Yes | Element(s) that function as the drag handle (e.g., pane header). |
|
|
217
|
-
| `className` | `string` | No | Custom CSS class for the drag handle wrapper. |
|
|
218
|
-
| `style` | `React.CSSProperties` | No | Inline styles for the drag handle wrapper. |
|
|
124
|
+
#### `<PaneTree>`
|
|
219
125
|
|
|
220
|
-
|
|
126
|
+
Recursively renders the dashboard grid hierarchy (resizers, split panels, and active pane contents). **Must be rendered when using `<Zeugma>` as a context provider.**
|
|
221
127
|
|
|
222
|
-
|
|
128
|
+
##### Usage
|
|
223
129
|
|
|
224
|
-
|
|
130
|
+
```tsx
|
|
131
|
+
import { Zeugma, PaneTree } from 'react-zeugma'
|
|
225
132
|
|
|
226
|
-
|
|
133
|
+
;<Zeugma controller={controller}>
|
|
134
|
+
<div className="workspace">
|
|
135
|
+
<PaneTree renderPane={(paneId) => <MyPane id={paneId} />} />
|
|
136
|
+
</div>
|
|
137
|
+
</Zeugma>
|
|
138
|
+
```
|
|
227
139
|
|
|
228
|
-
|
|
140
|
+
##### Props
|
|
229
141
|
|
|
230
|
-
|
|
142
|
+
| Property | Description | Type | Default |
|
|
143
|
+
| --------------- | ----------------------------------------------------------------------------------------- | ------------------------------- | ------- |
|
|
144
|
+
| `renderPane` | **Required**. Callback function mapping unique pane IDs to custom `<Pane>` components. | `(paneId: string) => ReactNode` | - |
|
|
145
|
+
| `tree` | Optional layout subtree to render (defaults to the root layout tree from the controller). | `TreeNode \| null` | - |
|
|
146
|
+
| `resizerSize` | Optional override for the thickness of split resizer handles in pixels. | `number` | `4` |
|
|
147
|
+
| `snapThreshold` | Optional override for the snapping threshold of resizer handles in pixels. | `number` | `8` |
|
|
231
148
|
|
|
232
|
-
|
|
149
|
+
---
|
|
233
150
|
|
|
234
|
-
|
|
151
|
+
#### `<Pane>`
|
|
235
152
|
|
|
236
|
-
|
|
153
|
+
Wraps each individual pane/widget within the dashboard, establishing drag-and-drop boundaries.
|
|
237
154
|
|
|
238
|
-
|
|
155
|
+
- **`<Pane.DragHandle>`**: Defines the interactive header or area used to drag the pane.
|
|
156
|
+
- **`<Pane.Content>`**: Renders the active tab's content. Accepts a child render function `(tab) => React.ReactNode` or static ReactNode.
|
|
157
|
+
- **`<Pane.Controls>`**: Renders standard control buttons for closing or maximizing the pane.
|
|
239
158
|
|
|
240
|
-
|
|
159
|
+
##### Usage
|
|
241
160
|
|
|
242
|
-
|
|
161
|
+
```tsx
|
|
162
|
+
import { Pane } from 'react-zeugma'
|
|
163
|
+
|
|
164
|
+
;<Pane id="pane-1" locked={false}>
|
|
165
|
+
<Pane.DragHandle className="p-2 cursor-grab bg-zinc-800">
|
|
166
|
+
<span>Pane Title</span>
|
|
167
|
+
</Pane.DragHandle>
|
|
168
|
+
<Pane.Controls />
|
|
169
|
+
<Pane.Content className="p-4">
|
|
170
|
+
{(tab) => <div>Rendered content for tab: {tab.id}</div>}
|
|
171
|
+
</Pane.Content>
|
|
172
|
+
</Pane>
|
|
173
|
+
```
|
|
243
174
|
|
|
244
|
-
|
|
175
|
+
##### Props
|
|
245
176
|
|
|
246
|
-
|
|
177
|
+
| Property | Description | Type | Default |
|
|
178
|
+
| ---------- | ------------------------------------------------------------------ | --------------------- | ------- |
|
|
179
|
+
| `id` | The unique ID corresponding to the layout node. | `string` | - |
|
|
180
|
+
| `children` | Children components rendered inside the pane. | `React.ReactNode` | - |
|
|
181
|
+
| `style` | Optional inline CSS styles applied to the outer pane container. | `React.CSSProperties` | - |
|
|
182
|
+
| `locked` | Optional override to lock this specific pane and disable dragging. | `boolean` | `false` |
|
|
247
183
|
|
|
248
|
-
|
|
184
|
+
---
|
|
249
185
|
|
|
250
|
-
|
|
186
|
+
#### `<Tabs>`
|
|
251
187
|
|
|
252
|
-
|
|
188
|
+
A helper component to render and reorder a list of tabs inside a pane.
|
|
253
189
|
|
|
254
|
-
|
|
190
|
+
##### Usage
|
|
255
191
|
|
|
256
|
-
|
|
192
|
+
```tsx
|
|
193
|
+
import { Tabs } from 'react-zeugma'
|
|
194
|
+
|
|
195
|
+
;<Tabs
|
|
196
|
+
tabs={['tab1', 'tab2']}
|
|
197
|
+
activeTabId="tab1"
|
|
198
|
+
selectTab={(tabId) => console.log('Select tab:', tabId)}
|
|
199
|
+
removeTab={(tabId) => console.log('Close tab:', tabId)}
|
|
200
|
+
renderTab={({ tabId, activeTabId, onSelect, onRemove }) => (
|
|
201
|
+
<button
|
|
202
|
+
onClick={onSelect}
|
|
203
|
+
className={`px-3 py-1 ${tabId === activeTabId ? 'bg-zinc-800 text-white' : 'text-zinc-400'}`}
|
|
204
|
+
>
|
|
205
|
+
{tabId}
|
|
206
|
+
<span
|
|
207
|
+
className="ml-2 cursor-pointer"
|
|
208
|
+
onClick={(e) => {
|
|
209
|
+
e.stopPropagation()
|
|
210
|
+
onRemove()
|
|
211
|
+
}}
|
|
212
|
+
>
|
|
213
|
+
×
|
|
214
|
+
</span>
|
|
215
|
+
</button>
|
|
216
|
+
)}
|
|
217
|
+
/>
|
|
218
|
+
```
|
|
257
219
|
|
|
258
|
-
|
|
220
|
+
##### Props
|
|
259
221
|
|
|
260
|
-
|
|
222
|
+
| Property | Description | Type | Default |
|
|
223
|
+
| -------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- |
|
|
224
|
+
| `tabs` | Array of tab IDs. | `string[]` | - |
|
|
225
|
+
| `activeTabId` | The currently active tab ID. | `string` | - |
|
|
226
|
+
| `locked` | Whether tab dragging/reordering is disabled. | `boolean` | `false` |
|
|
227
|
+
| `tabsMetadata` | Metadata mapping associated with each tab in the pane. | `Record<string, Record<string, unknown>>` | - |
|
|
228
|
+
| `selectTab` | Callback when a tab is selected. | `(id: string) => void` | - |
|
|
229
|
+
| `removeTab` | Callback when a tab is closed. | `(id: string) => void` | - |
|
|
230
|
+
| `classNames` | Custom class names for the container and tabs. | `{ container?: string; tab?: string \| ((tabId: string) => string) }` | - |
|
|
231
|
+
| `styles` | Custom CSS style overrides for the container and tabs. | `{ container?: CSSProperties; tab?: CSSProperties \| ((tabId: string) => CSSProperties) }` | - |
|
|
232
|
+
| `renderTab` | Render prop function called for each tab item. | `(props: { tabId: string; activeTabId: string; isDragging: boolean; isOver: boolean; metadata?: Record<string, unknown>; onSelect: () => void; onRemove: () => void }) => ReactNode` | - |
|
|
261
233
|
|
|
262
|
-
|
|
234
|
+
---
|
|
263
235
|
|
|
264
|
-
|
|
236
|
+
### Hooks
|
|
265
237
|
|
|
266
|
-
|
|
238
|
+
#### `useZeugma(options)`
|
|
267
239
|
|
|
268
|
-
|
|
240
|
+
A custom state hook that instantiates the dashboard layout engine and returns the controller.
|
|
269
241
|
|
|
270
|
-
|
|
242
|
+
##### Usage
|
|
271
243
|
|
|
272
|
-
|
|
244
|
+
```tsx
|
|
245
|
+
import { useZeugma } from 'react-zeugma'
|
|
246
|
+
|
|
247
|
+
const controller = useZeugma({
|
|
248
|
+
initialLayout: myInitialLayoutTree, // used on mount
|
|
249
|
+
layout: myControlledLayout, // used for controlled mode
|
|
250
|
+
onChange: (nextLayout) => {}, // layout update callback
|
|
251
|
+
locked: false, // lock all dragging and resizing
|
|
252
|
+
fullscreenPaneId: null, // ID of pane to zoom fullscreen
|
|
253
|
+
onFullscreenChange: (paneId) => {}, // callback when pane zoom toggled
|
|
254
|
+
})
|
|
255
|
+
```
|
|
273
256
|
|
|
274
|
-
|
|
257
|
+
##### Options
|
|
275
258
|
|
|
276
|
-
|
|
259
|
+
| Parameter | Description | Type | Default |
|
|
260
|
+
| -------------------- | --------------------------------------------------------------------------- | --------------------------------------- | ------- |
|
|
261
|
+
| `initialLayout` | Initial layout tree structure. Only used on mount. | `TreeNode \| null` | `null` |
|
|
262
|
+
| `layout` | Controlled layout tree structure. Hook runs in controlled mode if provided. | `TreeNode \| null` | `null` |
|
|
263
|
+
| `onChange` | Callback triggered when the layout tree updates. | `(newLayout: TreeNode \| null) => void` | - |
|
|
264
|
+
| `fullscreenPaneId` | Controlled fullscreen pane ID. | `string \| null` | `null` |
|
|
265
|
+
| `onFullscreenChange` | Callback triggered when fullscreen state toggles. | `(paneId: string \| null) => void` | - |
|
|
266
|
+
| `locked` | Global lock status to disable resizing and drag-and-drop operations. | `boolean` | `false` |
|
|
277
267
|
|
|
278
|
-
|
|
268
|
+
---
|
|
279
269
|
|
|
280
|
-
#### `
|
|
270
|
+
#### `useZeugmaContext()`
|
|
281
271
|
|
|
282
|
-
|
|
272
|
+
Context hook to retrieve layout state, queries, and mutation actions from anywhere under the `<Zeugma>` tree.
|
|
283
273
|
|
|
284
|
-
|
|
274
|
+
##### Usage
|
|
285
275
|
|
|
286
|
-
|
|
276
|
+
```tsx
|
|
277
|
+
import { useZeugmaContext } from 'react-zeugma'
|
|
287
278
|
|
|
288
|
-
|
|
279
|
+
const { layout, locked, setLocked, addTab, removePane, selectTab, findPaneById } =
|
|
280
|
+
useZeugmaContext()
|
|
281
|
+
```
|
|
289
282
|
|
|
290
|
-
|
|
283
|
+
##### Context Values
|
|
284
|
+
|
|
285
|
+
| Property / Method | Description | Type |
|
|
286
|
+
| ----------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
287
|
+
| `layout` | The current active layout tree structure. | `TreeNode \| null` |
|
|
288
|
+
| `fullscreenPaneId` | The ID of the maximized fullscreen pane. | `string \| null` |
|
|
289
|
+
| `locked` | Whether the dashboard layout is globally locked. | `boolean` |
|
|
290
|
+
| `setLayout` | React state setter to update the layout tree. | `Dispatch<SetStateAction<TreeNode \| null>>` |
|
|
291
|
+
| `setFullscreenPaneId` | Updates the active fullscreen pane ID. | `(paneId: string \| null) => void` |
|
|
292
|
+
| `setLocked` | Updates the global layout lock state. | `Dispatch<SetStateAction<boolean>>` |
|
|
293
|
+
| `removePane` | Removes a pane and collapses the split. | `(paneId: string) => void` |
|
|
294
|
+
| `addTab` | Adds a tab to a pane, or splits/creates one if target is omitted. | `(tabId: string, targetPaneId?: string, metadata?: Record<string, unknown>) => void` |
|
|
295
|
+
| `updateMetadata` | Mutates a specific tab's metadata. | `(id: string, updater: (current: Record<string, unknown> \| undefined) => Record<string, unknown> \| undefined) => void` |
|
|
296
|
+
| `updatePaneLock` | Toggles the lock status of a specific pane. | `(paneId: string, locked: boolean) => void` |
|
|
297
|
+
| `selectTab` | Focuses/activates a tab within a pane. | `(paneId: string, tabId: string) => void` |
|
|
298
|
+
| `mergeTab` | Programmatically drags and drops a tab from one pane to another. | `(draggedTabId: string, targetPaneId: string) => void` |
|
|
299
|
+
| `removeTab` | Programmatically closes a tab. | `(tabId: string) => void` |
|
|
300
|
+
| `splitPane` | Programmatically splits a pane node and adds a new one. | `(targetId: string, direction: SplitDirection, splitType: 'left' \| 'right' \| 'top' \| 'bottom', paneToAdd: string) => void` |
|
|
301
|
+
| `updateSplitPercentage` | Updates a SplitNode percentage. | `(currentNode: SplitNode, percentage: number) => void` |
|
|
302
|
+
| `moveTab` | Reorders a tab next to another. | `(draggedTabId: string, targetTabId: string, position?: 'before' \| 'after') => void` |
|
|
303
|
+
| `findPaneById` | Queries a PaneNode by its unique ID. | `(paneId: string) => PaneNode \| null` |
|
|
304
|
+
| `findPaneContainingTab` | Queries the parent PaneNode of a tab ID. | `(tabId: string) => PaneNode \| null` |
|
|
305
|
+
| `findTabById` | Queries detailed tab location and state metadata. | `(tabId: string) => TabDetails \| null` |
|
|
306
|
+
| `getTabMetadata` | Gets metadata for a tab ID. | `(tabId: string) => Record<string, unknown> \| undefined` |
|
|
307
|
+
| `getActiveTabMetadata` | Gets metadata for the active tab in a pane. | `(paneId: string) => Record<string, unknown> \| undefined` |
|
|
291
308
|
|
|
292
309
|
---
|
|
293
310
|
|
|
294
|
-
|
|
311
|
+
#### `usePaneContext()`
|
|
312
|
+
|
|
313
|
+
Context hook to access the state and actions of a specific pane. Must be used inside a `<Pane>` component.
|
|
295
314
|
|
|
296
|
-
|
|
315
|
+
##### Usage
|
|
297
316
|
|
|
298
317
|
```tsx
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
318
|
+
import { usePaneContext } from 'react-zeugma'
|
|
319
|
+
|
|
320
|
+
const {
|
|
321
|
+
id,
|
|
322
|
+
tabs,
|
|
323
|
+
activeTabId,
|
|
324
|
+
isDragging,
|
|
325
|
+
isFullscreen,
|
|
326
|
+
toggleFullscreen,
|
|
327
|
+
remove,
|
|
328
|
+
selectTab,
|
|
329
|
+
removeTab,
|
|
330
|
+
updateMetadata,
|
|
331
|
+
} = usePaneContext()
|
|
313
332
|
```
|
|
314
333
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
|
318
|
-
|
|
|
319
|
-
| `
|
|
320
|
-
| `
|
|
321
|
-
| `
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
324
|
-
| `
|
|
325
|
-
| `
|
|
326
|
-
| `
|
|
327
|
-
| `
|
|
328
|
-
| `
|
|
329
|
-
| `
|
|
330
|
-
| `
|
|
334
|
+
##### Context Values
|
|
335
|
+
|
|
336
|
+
| Property / Method | Description | Type |
|
|
337
|
+
| ------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
338
|
+
| `id` | The ID of the current pane. | `string` |
|
|
339
|
+
| `tabs` | List of tab IDs inside the pane. | `string[]` |
|
|
340
|
+
| `activeTabId` | Currently active tab ID. | `string` |
|
|
341
|
+
| `isDragging` | `true` if this pane is being dragged. | `boolean` |
|
|
342
|
+
| `isFullscreen` | `true` if this pane is maximized. | `boolean` |
|
|
343
|
+
| `toggleFullscreen` | Toggles maximized state for this pane. | `() => void` |
|
|
344
|
+
| `remove` | Removes this pane from the layout tree. | `() => void` |
|
|
345
|
+
| `selectTab` | Activates a tab within this pane. | `(tabId: string) => void` |
|
|
346
|
+
| `removeTab` | Closes a tab from this pane. | `(tabId: string) => void` |
|
|
347
|
+
| `metadata` | Active tab's custom metadata. | `Record<string, unknown> \| undefined` |
|
|
348
|
+
| `updateMetadata` | Updates active tab's metadata. | `(updater: (current: Record<string, unknown> \| undefined) => Record<string, unknown> \| undefined) => void` |
|
|
349
|
+
| `locked` | Whether the pane or the dashboard is locked. | `boolean` |
|
|
350
|
+
| `tabsMetadata` | Tab metadata mapping for all tabs inside this pane. | `Record<string, Record<string, unknown>> \| undefined` |
|
|
351
|
+
| `updateTabMetadata` | Updates metadata for a specific tab in the pane. | `(tabId: string, updater: (current: Record<string, unknown> \| undefined) => Record<string, unknown> \| undefined) => void` |
|
|
331
352
|
|
|
332
353
|
---
|
|
333
354
|
|
|
334
|
-
|
|
355
|
+
#### `useResizer(props)`
|
|
335
356
|
|
|
336
|
-
|
|
357
|
+
Low-level hook for implementing custom pane resizing handles.
|
|
337
358
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
```ts
|
|
341
|
-
export type SplitDirection = 'row' | 'column'
|
|
342
|
-
|
|
343
|
-
export interface SplitNode {
|
|
344
|
-
type: 'split'
|
|
345
|
-
direction: SplitDirection
|
|
346
|
-
first: TreeNode
|
|
347
|
-
second: TreeNode
|
|
348
|
-
splitPercentage: number // 0–100
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
export interface PaneNode {
|
|
352
|
-
type: 'pane'
|
|
353
|
-
id: string
|
|
354
|
-
tabs: string[]
|
|
355
|
-
activeTabId: string
|
|
356
|
-
locked?: boolean
|
|
357
|
-
tabsMetadata?: Record<string, Record<string, unknown>>
|
|
358
|
-
}
|
|
359
|
+
##### Usage
|
|
359
360
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
361
|
+
```tsx
|
|
362
|
+
import { useResizer } from 'react-zeugma'
|
|
363
|
+
|
|
364
|
+
const handlePointerDown = useResizer({
|
|
365
|
+
containerRef,
|
|
366
|
+
isRow,
|
|
367
|
+
direction,
|
|
368
|
+
splitPercentage,
|
|
369
|
+
resizerSize,
|
|
370
|
+
snapThreshold,
|
|
371
|
+
layout,
|
|
372
|
+
currentNode,
|
|
373
|
+
onLayoutChange: (nextTree) => {},
|
|
374
|
+
})
|
|
369
375
|
```
|
|
370
376
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
```ts
|
|
374
|
-
export interface PaneProps {
|
|
375
|
-
id: string
|
|
376
|
-
children: React.ReactNode
|
|
377
|
-
style?: React.CSSProperties
|
|
378
|
-
locked?: boolean
|
|
379
|
-
}
|
|
377
|
+
---
|
|
380
378
|
|
|
381
|
-
|
|
382
|
-
children?: React.ReactNode
|
|
383
|
-
className?: string
|
|
384
|
-
style?: React.CSSProperties
|
|
385
|
-
}
|
|
379
|
+
## Layout Utilities
|
|
386
380
|
|
|
387
|
-
|
|
388
|
-
tabs: string[]
|
|
389
|
-
activeTabId: string
|
|
390
|
-
locked?: boolean
|
|
391
|
-
tabsMetadata?: Record<string, Record<string, unknown>>
|
|
392
|
-
selectTab: (id: string) => void
|
|
393
|
-
removeTab: (id: string) => void
|
|
394
|
-
renderTab: (props: {
|
|
395
|
-
tabId: string
|
|
396
|
-
activeTabId: string
|
|
397
|
-
isDragging: boolean
|
|
398
|
-
isOver: boolean
|
|
399
|
-
metadata?: Record<string, unknown>
|
|
400
|
-
onSelect: () => void
|
|
401
|
-
onRemove: () => void
|
|
402
|
-
}) => React.ReactNode
|
|
403
|
-
classNames?: {
|
|
404
|
-
container?: string
|
|
405
|
-
tab?: string | ((tabId: string) => string)
|
|
406
|
-
}
|
|
407
|
-
styles?: {
|
|
408
|
-
container?: React.CSSProperties
|
|
409
|
-
tab?: React.CSSProperties | ((tabId: string) => React.CSSProperties)
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
```
|
|
381
|
+
Import utility functions from `react-zeugma/utils` to programmatically query or update the serialized layout tree.
|
|
413
382
|
|
|
414
|
-
|
|
383
|
+
##### Usage
|
|
415
384
|
|
|
416
385
|
```ts
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
386
|
+
import {
|
|
387
|
+
generateUniqueId,
|
|
388
|
+
splitPane,
|
|
389
|
+
removePane,
|
|
390
|
+
addTab,
|
|
391
|
+
removeTab,
|
|
392
|
+
selectTab,
|
|
393
|
+
mergeTab,
|
|
394
|
+
moveTab,
|
|
395
|
+
findPaneById,
|
|
396
|
+
findPaneContainingTab,
|
|
397
|
+
findTabById,
|
|
398
|
+
computeLayout,
|
|
399
|
+
} from 'react-zeugma/utils'
|
|
400
|
+
|
|
401
|
+
// 1. Generate a random unique pane ID
|
|
402
|
+
const newPaneId = generateUniqueId()
|
|
403
|
+
|
|
404
|
+
// 2. Programmatically split a target pane in the tree
|
|
405
|
+
const updatedTree = splitPane(currentTree, 'explorer', 'row', 'right', 'terminal')
|
|
406
|
+
|
|
407
|
+
// 3. Programmatically add a tab to a pane
|
|
408
|
+
const updatedTree = addTab(currentTree, 'editor', 'new-file.js', { status: 'unsaved' })
|
|
409
|
+
|
|
410
|
+
// 4. Find which pane contains a specific tab
|
|
411
|
+
const parentPane = findPaneContainingTab(currentTree, 'new-file.js')
|
|
439
412
|
```
|
|
440
413
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
```ts
|
|
444
|
-
export interface ZeugmaState {
|
|
445
|
-
layout: TreeNode | null
|
|
446
|
-
fullscreenPaneId: string | null
|
|
447
|
-
locked: boolean
|
|
448
|
-
}
|
|
414
|
+
---
|
|
449
415
|
|
|
450
|
-
|
|
451
|
-
setLayout: Dispatch<SetStateAction<TreeNode | null>>
|
|
452
|
-
setFullscreenPaneId: (paneId: string | null) => void
|
|
453
|
-
setLocked: Dispatch<SetStateAction<boolean>>
|
|
454
|
-
}
|
|
416
|
+
## Styling & Class Names
|
|
455
417
|
|
|
456
|
-
|
|
457
|
-
removePane: (paneId: string) => void
|
|
458
|
-
addTab: (tabId: string, targetPaneId?: string, metadata?: Record<string, unknown>) => void
|
|
459
|
-
updateMetadata: (
|
|
460
|
-
id: string,
|
|
461
|
-
updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
|
|
462
|
-
) => void
|
|
463
|
-
updatePaneLock: (paneId: string, locked: boolean) => void
|
|
464
|
-
selectTab: (paneId: string, tabId: string) => void
|
|
465
|
-
mergeTab: (draggedTabId: string, targetPaneId: string) => void
|
|
466
|
-
removeTab: (tabId: string) => void
|
|
467
|
-
splitPane: (
|
|
468
|
-
targetId: string,
|
|
469
|
-
direction: SplitDirection,
|
|
470
|
-
splitType: 'left' | 'right' | 'top' | 'bottom',
|
|
471
|
-
paneToAdd: string,
|
|
472
|
-
) => void
|
|
473
|
-
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void
|
|
474
|
-
moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void
|
|
475
|
-
}
|
|
418
|
+
`react-zeugma` is 100% headless. You must style resizers, previews, and containers by providing custom class names.
|
|
476
419
|
|
|
477
|
-
|
|
478
|
-
findPaneById: (paneId: string) => PaneNode | null
|
|
479
|
-
findPaneContainingTab: (tabId: string) => PaneNode | null
|
|
480
|
-
findTabById: (tabId: string) => TabDetails | null
|
|
481
|
-
getTabMetadata: (tabId: string) => Record<string, unknown> | undefined
|
|
482
|
-
getActiveTabMetadata: (paneId: string) => Record<string, unknown> | undefined
|
|
483
|
-
}
|
|
420
|
+
##### Usage
|
|
484
421
|
|
|
485
|
-
|
|
486
|
-
|
|
422
|
+
```tsx
|
|
423
|
+
<Zeugma
|
|
424
|
+
controller={controller}
|
|
425
|
+
classNames={{
|
|
426
|
+
dashboard: 'dashboard-root',
|
|
427
|
+
pane: 'pane-wrapper',
|
|
428
|
+
resizer: 'custom-resizer-line',
|
|
429
|
+
dropPreview: 'drop-preview-box',
|
|
430
|
+
tabDropPreview: 'tab-line-preview',
|
|
431
|
+
}}
|
|
432
|
+
/>
|
|
487
433
|
```
|
|
488
434
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
435
|
+
##### Class Names Mapping
|
|
436
|
+
|
|
437
|
+
| Class Key | Description |
|
|
438
|
+
| ------------------------ | ------------------------------------------------------------------- |
|
|
439
|
+
| `dashboard` | Root dashboard grid container. |
|
|
440
|
+
| `dashboardDismissActive` | Dashboard container when active item is dragged outside to dismiss. |
|
|
441
|
+
| `dashboardLocked` | Dashboard container when layout is globally locked. |
|
|
442
|
+
| `pane` | Outer container div of each `<Pane>`. |
|
|
443
|
+
| `paneLocked` | Pane container wrapper when locked. |
|
|
444
|
+
| `paneContainer` | Pane inner content container wrapper. |
|
|
445
|
+
| `paneHeader` | Drag header wrapper inside the pane. |
|
|
446
|
+
| `paneControls` | Controls wrapper container (maximizing, close, lock). |
|
|
447
|
+
| `paneButton` | Maximize/Close control buttons. |
|
|
448
|
+
| `dropPreview` | Preview indicator box for edge layout splits. |
|
|
449
|
+
| `rootDropPreview` | Preview indicator for full layout splits. |
|
|
450
|
+
| `dragOverlay` | Absolute portal wrapper following the dragging cursor. |
|
|
451
|
+
| `resizer` | Pointer-drag splitter handle bars. |
|
|
452
|
+
| `dismissPreview` | Background indicator showing visual drag-to-dismiss zones. |
|
|
453
|
+
| `lockedPreview` | Hover visual feedback indicator for locked pane zones. |
|
|
454
|
+
| `tabDropPreview` | Tab list insertion indicator line. |
|
|
455
|
+
| `tabSeparator` | Line separator between static tabs. |
|
|
456
|
+
| `tabContentWrapper` | Custom tab content element wrapper. |
|
|
457
|
+
| `tabsContainer` | Layout tabs container header bar. |
|
|
458
|
+
| `tab` | Individual tab list items. |
|
|
459
|
+
| `tabCloseButton` | Close button inside a tab item. |
|
|
460
|
+
| `dragHandle` | Drag target region. |
|