react-zeugma 6.0.4 → 6.0.5
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 +298 -81
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -26
- package/dist/index.d.ts +1 -26
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,24 +113,26 @@ The context provider that sets up the drag-and-drop state machine, monitors acti
|
|
|
113
113
|
|
|
114
114
|
A custom state hook that initializes and manages the recursive layout tree and handles drag-and-drop actions.
|
|
115
115
|
|
|
116
|
-
| Option | Type
|
|
117
|
-
| ------------------------ |
|
|
118
|
-
| `initialLayout` | `TreeNode \| null`
|
|
119
|
-
| `layout` | `TreeNode \| null`
|
|
120
|
-
| `
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
124
|
-
| `
|
|
125
|
-
| `
|
|
126
|
-
| `
|
|
127
|
-
| `
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
116
|
+
| Option | Type | Default | Description |
|
|
117
|
+
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `initialLayout` | `TreeNode \| null` | — | Initial layout tree structure for uncontrolled mode. Only used on initial mount. |
|
|
119
|
+
| `layout` | `TreeNode \| null` | — | Controlled layout tree structure. If provided, the hook runs in controlled mode and synchronizes with it. |
|
|
120
|
+
| `fullscreenPaneId` | `string \| null` | — | Controlled fullscreen pane ID. Pass `null` for no fullscreen pane. |
|
|
121
|
+
| `onFullscreenChange` | `(paneId: string \| null) => void` | — | Callback triggered when a pane is toggled to/from fullscreen mode. |
|
|
122
|
+
| `locked` | `boolean` | `false` | If true, layout resizes and drags are disabled. |
|
|
123
|
+
| `dragActivationDistance` | `number` | `8` | Minimum pointer drag distance (in pixels) required to activate dragging. |
|
|
124
|
+
| `snapThreshold` | `number` | `8` | Threshold in pixels to snap layout resizers to adjacent edges. |
|
|
125
|
+
| `minSplitPercentage` | `number` | `5` | Minimum resizing limit percentage. |
|
|
126
|
+
| `maxSplitPercentage` | `number` | `95` | Maximum resizing limit percentage. |
|
|
127
|
+
| `enableDragToDismiss` | `boolean` | `false` | If true, enables the drag-out-to-dismiss gesture to close widgets. |
|
|
128
|
+
| `dismissThreshold` | `number` | `60` | Distance in pixels outside container bounds required to trigger dismissal. |
|
|
129
|
+
| `onRemove` | `(paneId: string) => void` | — | Callback triggered when a pane is removed. |
|
|
130
|
+
| `onDragStart` | `(activeId: string) => void` | — | Callback triggered when dragging starts. |
|
|
131
|
+
| `onDragEnd` | `(activeId: string, overId: string \| null, dropAction: { type: 'split' \| 'move'; direction?: SplitDirection; position?: string } \| null) => void` | — | Callback triggered when dragging ends, with drop target and action details. |
|
|
132
|
+
| `onResizeStart` | `(currentNode: SplitNode) => void` | — | Callback triggered when resizing starts. |
|
|
133
|
+
| `onResize` | `(currentNode: SplitNode, percentage: number) => void` | — | Callback triggered during resizing. |
|
|
134
|
+
| `onResizeEnd` | `(currentNode: SplitNode, percentage: number) => void` | — | Callback triggered when resizing ends. |
|
|
135
|
+
| `onDismissIntentChange` | `(paneId: string \| null) => void` | — | Callback triggered when drag-out intent changes. |
|
|
134
136
|
|
|
135
137
|
### `useZeugmaContext()`
|
|
136
138
|
|
|
@@ -155,36 +157,67 @@ Recursively renders the split nodes and pane nodes. Must be placed inside `<Zeug
|
|
|
155
157
|
|
|
156
158
|
Wraps the individual pane components inside the renderer. Utilizes a render prop passing active layout attributes.
|
|
157
159
|
|
|
158
|
-
| Prop | Type | Required | Description
|
|
159
|
-
| ---------- | --------------------------------------- | -------- |
|
|
160
|
-
| `id` | `string` | Yes | The unique ID corresponding to a `PaneNode`'s `paneId`.
|
|
161
|
-
| `children` | `(props: PaneRenderProps) => ReactNode` | Yes | Render prop function.
|
|
160
|
+
| Prop | Type | Required | Description |
|
|
161
|
+
| ---------- | --------------------------------------- | -------- | ---------------------------------------------------------------------- |
|
|
162
|
+
| `id` | `string` | Yes | The unique ID corresponding to a `PaneNode`'s `paneId`. |
|
|
163
|
+
| `children` | `(props: PaneRenderProps) => ReactNode` | Yes | Render prop function. |
|
|
164
|
+
| `style` | `React.CSSProperties` | No | Optional inline CSS styles applied to the pane outer container. |
|
|
165
|
+
| `locked` | `boolean` | No | Optional override to lock this specific pane (disables drag and drop). |
|
|
162
166
|
|
|
163
167
|
#### Render Props: `PaneRenderProps`
|
|
164
168
|
|
|
165
|
-
| Parameter
|
|
166
|
-
|
|
|
167
|
-
| `isDragging`
|
|
168
|
-
| `isFullscreen`
|
|
169
|
-
| `toggleFullscreen`
|
|
170
|
-
| `remove`
|
|
171
|
-
| `
|
|
169
|
+
| Parameter | Type | Description |
|
|
170
|
+
| ------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
171
|
+
| `isDragging` | `boolean` | `true` if the pane is actively being dragged. |
|
|
172
|
+
| `isFullscreen` | `boolean` | `true` if the pane currently occupies the fullscreen view. |
|
|
173
|
+
| `toggleFullscreen` | `() => void` | Toggles the pane to and from fullscreen/zoomed mode. |
|
|
174
|
+
| `remove` | `() => void` | Removes this pane (and its active tab) from the layout tree. |
|
|
175
|
+
| `metadata` | `Record<string, unknown> \| undefined` | The metadata values associated with the active tab. |
|
|
176
|
+
| `updateMetadata` | `(updater: (current: Record<string, unknown> \| undefined) => Record<string, unknown> \| undefined) => void` | Updates metadata of the active tab via an updater function. |
|
|
177
|
+
| `locked` | `boolean` | `true` if this specific pane or the dashboard globally is locked. |
|
|
178
|
+
| `tabs` | `string[]` | The array of tab IDs in this pane. |
|
|
179
|
+
| `activeTabId` | `string` | The currently active tab ID. |
|
|
180
|
+
| `selectTab` | `(tabId: string) => void` | Selects a specific tab to make it active. |
|
|
181
|
+
| `removeTab` | `(tabId: string) => void` | Removes/closes a specific tab. |
|
|
182
|
+
| `tabsMetadata` | `Record<string, Record<string, unknown>> \| undefined` | Metadata values associated with all tabs in this pane. |
|
|
183
|
+
| `updateTabMetadata` | `(tabId: string, updater: (current: Record<string, unknown> \| undefined) => Record<string, unknown> \| undefined) => void` | Updates the metadata of a specific tab. |
|
|
184
|
+
| `renderActiveTab` | `() => ReactNode` | Renders the portal placeholder for the currently active tab in the pane. |
|
|
172
185
|
|
|
173
186
|
### `<Tabs>`
|
|
174
187
|
|
|
175
188
|
A helper component that renders a list of tab items for a pane, wrapping the internal drag-and-drop tab logic.
|
|
176
189
|
|
|
177
|
-
| Prop | Type
|
|
178
|
-
| :------------- |
|
|
179
|
-
| `tabs` | `string[]`
|
|
180
|
-
| `activeTabId` | `string`
|
|
181
|
-
| `locked` | `boolean`
|
|
182
|
-
| `tabsMetadata` | `Record<string, Record<string, any>>`
|
|
183
|
-
| `selectTab` | `(id: string) => void`
|
|
184
|
-
| `removeTab` | `(id: string) => void`
|
|
185
|
-
| `classNames` | `{ container?: string; tab?: string \| ((tabId: string) => string) }`
|
|
186
|
-
| `styles` | `{ container?: CSSProperties; tab?: CSSProperties \| ((tabId: string) => CSSProperties) }`
|
|
187
|
-
| `renderTab` | `(props: { tabId: string; activeTabId: string; isDragging: boolean; isOver: boolean; metadata?: Record<string,
|
|
190
|
+
| Prop | Type | Required | Description |
|
|
191
|
+
| :------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------- |
|
|
192
|
+
| `tabs` | `string[]` | Yes | The list of tab IDs in this pane. |
|
|
193
|
+
| `activeTabId` | `string` | Yes | The currently active tab ID. |
|
|
194
|
+
| `locked` | `boolean` | No | Whether dragging/reordering tabs is disabled (defaults to `false`). |
|
|
195
|
+
| `tabsMetadata` | `Record<string, Record<string, any>>` | No | Metadata associated with each tab. |
|
|
196
|
+
| `selectTab` | `(id: string) => void` | Yes | Callback when a tab is selected. |
|
|
197
|
+
| `removeTab` | `(id: string) => void` | Yes | Callback when a tab is closed/removed. |
|
|
198
|
+
| `classNames` | `{ container?: string; tab?: string \| ((tabId: string) => string) }` | No | Custom class names for the container and individual tab items. |
|
|
199
|
+
| `styles` | `{ container?: CSSProperties; tab?: CSSProperties \| ((tabId: string) => CSSProperties) }` | No | Custom inline CSS styles for the container and individual tab items. |
|
|
200
|
+
| `renderTab` | `(props: { tabId: string; activeTabId: string; isDragging: boolean; isOver: boolean; metadata?: Record<string, unknown>; selectTab: (id: string) => void; removeTab: (id: string) => void }) => ReactNode` | Yes | Render prop function called for each tab item. |
|
|
201
|
+
|
|
202
|
+
### `useTabContext()`
|
|
203
|
+
|
|
204
|
+
A context hook that provides per-tab state from within a `<Tab>` component rendered inside `<Tabs>`. Must be used within a rendered tab child.
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
const { tabId, isActive, isDragging, isOver, metadata, locked, selectTab, removeTab } =
|
|
208
|
+
useTabContext()
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
| Property | Type | Description |
|
|
212
|
+
| ------------ | -------------------------------------- | -------------------------------------------------- |
|
|
213
|
+
| `tabId` | `string` | The ID of the tab this context belongs to. |
|
|
214
|
+
| `isActive` | `boolean` | Whether this tab is the currently active tab. |
|
|
215
|
+
| `isDragging` | `boolean` | Whether this tab is currently being dragged. |
|
|
216
|
+
| `isOver` | `boolean` | Whether a dragged item is currently over this tab. |
|
|
217
|
+
| `metadata` | `Record<string, unknown> \| undefined` | Custom metadata associated with this tab. |
|
|
218
|
+
| `locked` | `boolean` | Whether this tab (or the dashboard) is locked. |
|
|
219
|
+
| `selectTab` | `() => void` | Selects this tab (no argument needed). |
|
|
220
|
+
| `removeTab` | `() => void` | Removes/closes this tab (no argument needed). |
|
|
188
221
|
|
|
189
222
|
### `<DragHandle>`
|
|
190
223
|
|
|
@@ -196,39 +229,57 @@ Defines the interactive drag region inside a `<Pane>`. **Must be placed inside a
|
|
|
196
229
|
| `className` | `string` | No | Custom CSS class for the drag handle wrapper. |
|
|
197
230
|
| `style` | `React.CSSProperties` | No | Inline styles for the drag handle wrapper. |
|
|
198
231
|
|
|
199
|
-
|
|
232
|
+
## Tree Utilities
|
|
200
233
|
|
|
201
|
-
|
|
234
|
+
Import these serializable tree utility functions from `react-zeugma/utils` for programmatically mutating or querying layout schemas.
|
|
202
235
|
|
|
203
|
-
|
|
204
|
-
| :----------------- | :------------------------- | :------- | :--------------- | :--------------------------------------------------------------- |
|
|
205
|
-
| `height` | `number` | No | `400` | Controlled height in pixels (or initial height if uncontrolled). |
|
|
206
|
-
| `onHeightChange` | `(height: number) => void` | No | — | Callback function triggered during or after dragging to resize. |
|
|
207
|
-
| `minHeight` | `number` | No | `100` | Minimum allowed height in pixels. |
|
|
208
|
-
| `maxHeight` | `number` | No | `Infinity` | Maximum allowed height in pixels. |
|
|
209
|
-
| `persist` | `boolean` | No | — | Whether to persist height changes in localStorage. |
|
|
210
|
-
| `localStorageKey` | `string` | No | `'default-pane'` | Custom localStorage key name (prefixed by `zeugma-height:`). |
|
|
211
|
-
| `resizerHeight` | `number` | No | `6` | Height of the resizer drag handle in pixels. |
|
|
212
|
-
| `className` | `string` | No | — | Custom CSS class applied to the outer container. |
|
|
213
|
-
| `resizerClassName` | `string` | No | — | Custom CSS class applied to the drag handle. |
|
|
236
|
+
#### `generateUniqueId(): string`
|
|
214
237
|
|
|
215
|
-
|
|
238
|
+
Generates a unique pane ID string (e.g., `'pane-abc123xyz'`). Useful when creating new pane nodes programmatically.
|
|
216
239
|
|
|
217
|
-
|
|
240
|
+
#### `removePane(tree: TreeNode | null, paneId: string): TreeNode | null`
|
|
218
241
|
|
|
219
|
-
|
|
242
|
+
Recursively scans the layout tree, removes the targeted pane node, and collapses redundant split boundaries.
|
|
220
243
|
|
|
221
|
-
#### `
|
|
244
|
+
#### `removeTab(tree: TreeNode | null, tabId: string): TreeNode | null`
|
|
222
245
|
|
|
223
|
-
|
|
246
|
+
Removes a single tab from its parent pane. If the pane has no remaining tabs after removal, the pane itself is collapsed out of the tree.
|
|
247
|
+
|
|
248
|
+
#### `addPane(tree: TreeNode | null, paneToAdd: string, metadata?: Record<string, unknown>): TreeNode`
|
|
249
|
+
|
|
250
|
+
Recursively matches the bottommost/rightmost pane leaf in the tree, splits it, and inserts the target `paneToAdd`. Optionally sets initial metadata for the new pane's tab.
|
|
224
251
|
|
|
225
|
-
#### `
|
|
252
|
+
#### `addTab(tree: TreeNode | null, targetPaneId: string, tabId: string, metadata?: Record<string, unknown>): TreeNode | null`
|
|
226
253
|
|
|
227
|
-
|
|
254
|
+
Appends a tab directly into a specific target pane node by its ID. Sets the new tab as the active tab. Does nothing if `targetPaneId` is not found.
|
|
228
255
|
|
|
229
256
|
#### `splitPane(tree, targetId, direction, splitType, paneToAdd)`
|
|
230
257
|
|
|
231
|
-
Splits the targeted `targetId` pane inside the tree with `direction` (_row_ / _column_) and type (_left_, _right_, _top_, _bottom_) to insert `paneToAdd`.
|
|
258
|
+
Splits the targeted `targetId` pane inside the tree with `direction` (_row_ / _column_) and type (_left_, _right_, _top_, _bottom_) to insert `paneToAdd`. `paneToAdd` may be a tab ID string or a full `PaneNode` object.
|
|
259
|
+
|
|
260
|
+
#### `updateSplitPercentage(tree: TreeNode | null, target: SplitNode, newPercentage: number): TreeNode | null`
|
|
261
|
+
|
|
262
|
+
Finds the target `SplitNode` by reference in the tree and updates its `splitPercentage`.
|
|
263
|
+
|
|
264
|
+
#### `selectTab(tree: TreeNode | null, paneId: string, tabId: string): TreeNode | null`
|
|
265
|
+
|
|
266
|
+
Activates the specified `tabId` within the `paneId` pane node. Returns the tree unchanged if the tab is already active or the pane is not found.
|
|
267
|
+
|
|
268
|
+
#### `mergeTab(tree: TreeNode | null, draggedTabId: string, targetPaneId: string): TreeNode | null`
|
|
269
|
+
|
|
270
|
+
Moves `draggedTabId` from its current pane into `targetPaneId`, preserving tab metadata. Collapses the source pane if it becomes empty. Sets the moved tab as the active tab in the target pane.
|
|
271
|
+
|
|
272
|
+
#### `moveTab(tree: TreeNode | null, draggedTabId: string, targetTabId: string, position?: 'before' | 'after'): TreeNode | null`
|
|
273
|
+
|
|
274
|
+
Reorders `draggedTabId` adjacent to `targetTabId` within the same pane (or moves it cross-pane). `position` defaults to `'before'`.
|
|
275
|
+
|
|
276
|
+
#### `updateTabMetadata(tree: TreeNode | null, tabId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null`
|
|
277
|
+
|
|
278
|
+
Updates the metadata of a specific tab using an updater function. Returning `undefined` from the updater removes the entry.
|
|
279
|
+
|
|
280
|
+
#### `updatePaneLock(tree: TreeNode | null, paneId: string, locked: boolean): TreeNode | null`
|
|
281
|
+
|
|
282
|
+
Sets the `locked` flag on the specified pane node. When `locked` is `false`, the field is removed from the node entirely to keep the tree clean.
|
|
232
283
|
|
|
233
284
|
#### `findPaneById(tree: TreeNode | null, paneId: string): PaneNode | null`
|
|
234
285
|
|
|
@@ -242,6 +293,10 @@ Recursively searches the layout tree and returns the `PaneNode` containing the s
|
|
|
242
293
|
|
|
243
294
|
Searches the layout tree for the given `tabId` and returns computed details (parent `paneId`, `isActive`, `index`, and custom `metadata`).
|
|
244
295
|
|
|
296
|
+
#### `computeLayout(node: TreeNode | null, left?, top?, width?, height?): { panes: ComputedPane[]; splitters: ComputedSplitter[] }`
|
|
297
|
+
|
|
298
|
+
Recursively computes the absolute position and dimensions (as percentages relative to the container) for every pane and splitter in the tree. Useful for building custom render layers or analytics on top of the layout engine.
|
|
299
|
+
|
|
245
300
|
#### `calculateTabDropIndex(tabs: string[], activeType: string | null, overTabId: string | null, overTabPosition: 'before' | 'after' | null): number`
|
|
246
301
|
|
|
247
302
|
Calculates the target insertion index for a dragged tab within a list of tabs. Returns `-1` if the drop target is not in the list.
|
|
@@ -261,17 +316,38 @@ Use custom CSS or styling rules to style resizers, dragging states, drop preview
|
|
|
261
316
|
'bg-transparent hover:bg-indigo-500/50 active:bg-indigo-500 transition-colors duration-150',
|
|
262
317
|
// split previews
|
|
263
318
|
dropPreview: 'bg-indigo-500/10 border-2 border-dashed border-indigo-500/50 backdrop-blur-xs',
|
|
319
|
+
// tab separator line
|
|
320
|
+
tabSeparator: 'w-px h-4 bg-zinc-700',
|
|
264
321
|
}}
|
|
265
322
|
>
|
|
266
323
|
<PaneTree />
|
|
267
324
|
</Zeugma>
|
|
268
325
|
```
|
|
269
326
|
|
|
327
|
+
### `ZeugmaClassNames` reference
|
|
328
|
+
|
|
329
|
+
| Key | Applied to |
|
|
330
|
+
| ------------------------ | --------------------------------------------------------------------------------- |
|
|
331
|
+
| `dashboard` | Root dashboard container. |
|
|
332
|
+
| `dashboardDismissActive` | Root container when a drag-out dismiss is active. |
|
|
333
|
+
| `dashboardLocked` | Root container when the dashboard is globally locked. |
|
|
334
|
+
| `pane` | Outer wrapper `<div>` of each `<Pane>`. |
|
|
335
|
+
| `paneLocked` | Pane container when locked. |
|
|
336
|
+
| `dropPreview` | Drop zone preview box when hovering over a split-edge drop zone. |
|
|
337
|
+
| `dragOverlay` | Cursor-following drag preview portal wrapper. |
|
|
338
|
+
| `resizer` | Drag-to-resize split bar handles. |
|
|
339
|
+
| `dismissPreview` | Background dismiss zone indicator during a drag-out dismiss gesture. |
|
|
340
|
+
| `lockedPreview` | Drop zone indicator when hovering over a locked pane. |
|
|
341
|
+
| `tabDropPreview` | Placeholder line element rendered at the target insertion point during tab drags. |
|
|
342
|
+
| `tabSeparator` | Separator line rendered between non-active adjacent tabs in `<Tabs>`. |
|
|
343
|
+
|
|
270
344
|
---
|
|
271
345
|
|
|
272
346
|
## Types Reference
|
|
273
347
|
|
|
274
|
-
Full TypeScript type definitions
|
|
348
|
+
Full TypeScript type definitions exported from `react-zeugma`.
|
|
349
|
+
|
|
350
|
+
### Layout Tree
|
|
275
351
|
|
|
276
352
|
```ts
|
|
277
353
|
export type SplitDirection = 'row' | 'column'
|
|
@@ -281,7 +357,7 @@ export interface SplitNode {
|
|
|
281
357
|
direction: SplitDirection
|
|
282
358
|
first: TreeNode
|
|
283
359
|
second: TreeNode
|
|
284
|
-
splitPercentage: number
|
|
360
|
+
splitPercentage: number // 0–100
|
|
285
361
|
}
|
|
286
362
|
|
|
287
363
|
export interface PaneNode {
|
|
@@ -304,6 +380,164 @@ export interface TabDetails {
|
|
|
304
380
|
}
|
|
305
381
|
```
|
|
306
382
|
|
|
383
|
+
### Component Props
|
|
384
|
+
|
|
385
|
+
````ts
|
|
386
|
+
export interface PaneProps {
|
|
387
|
+
id: string
|
|
388
|
+
children: (props: PaneRenderProps) => React.ReactNode
|
|
389
|
+
style?: React.CSSProperties
|
|
390
|
+
locked?: boolean
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface DragHandleProps {
|
|
394
|
+
children?: React.ReactNode
|
|
395
|
+
className?: string
|
|
396
|
+
style?: React.CSSProperties
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export interface TabsProps {
|
|
400
|
+
tabs: string[]
|
|
401
|
+
activeTabId: string
|
|
402
|
+
locked?: boolean
|
|
403
|
+
tabsMetadata?: Record<string, Record<string, unknown>>
|
|
404
|
+
selectTab: (id: string) => void
|
|
405
|
+
removeTab: (id: string) => void
|
|
406
|
+
renderTab: (props: {
|
|
407
|
+
tabId: string
|
|
408
|
+
activeTabId: string
|
|
409
|
+
isDragging: boolean
|
|
410
|
+
isOver: boolean
|
|
411
|
+
metadata?: Record<string, unknown>
|
|
412
|
+
selectTab: (id: string) => void
|
|
413
|
+
removeTab: (id: string) => void
|
|
414
|
+
}) => React.ReactNode
|
|
415
|
+
classNames?: {
|
|
416
|
+
container?: string
|
|
417
|
+
tab?: string | ((tabId: string) => string)
|
|
418
|
+
}
|
|
419
|
+
styles?: {
|
|
420
|
+
container?: React.CSSProperties
|
|
421
|
+
tab?: React.CSSProperties | ((tabId: string) => React.CSSProperties)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
### Render Props
|
|
426
|
+
|
|
427
|
+
```ts
|
|
428
|
+
export interface PaneRenderProps {
|
|
429
|
+
isDragging: boolean
|
|
430
|
+
isFullscreen: boolean
|
|
431
|
+
toggleFullscreen: () => void
|
|
432
|
+
remove: () => void
|
|
433
|
+
metadata: Record<string, unknown> | undefined
|
|
434
|
+
updateMetadata: (
|
|
435
|
+
updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
|
|
436
|
+
) => void
|
|
437
|
+
locked: boolean
|
|
438
|
+
tabs: string[]
|
|
439
|
+
activeTabId: string
|
|
440
|
+
selectTab: (tabId: string) => void
|
|
441
|
+
removeTab: (tabId: string) => void
|
|
442
|
+
tabsMetadata: Record<string, Record<string, unknown>> | undefined
|
|
443
|
+
updateTabMetadata: (
|
|
444
|
+
tabId: string,
|
|
445
|
+
updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
|
|
446
|
+
) => void
|
|
447
|
+
renderActiveTab: () => ReactNode
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
export interface TabContextValue {
|
|
451
|
+
tabId: string
|
|
452
|
+
isActive: boolean
|
|
453
|
+
isDragging: boolean
|
|
454
|
+
isOver: boolean
|
|
455
|
+
metadata?: Record<string, unknown>
|
|
456
|
+
locked: boolean
|
|
457
|
+
selectTab: () => void
|
|
458
|
+
removeTab: () => void
|
|
459
|
+
}
|
|
460
|
+
````
|
|
461
|
+
|
|
462
|
+
### Controller & Context
|
|
463
|
+
|
|
464
|
+
```ts
|
|
465
|
+
export interface UseZeugmaOptions { /* see useZeugma() section above */ }
|
|
466
|
+
|
|
467
|
+
export interface ZeugmaController {
|
|
468
|
+
// State
|
|
469
|
+
layout: TreeNode | null
|
|
470
|
+
setLayout: Dispatch<SetStateAction<TreeNode | null>>
|
|
471
|
+
fullscreenPaneId: string | null
|
|
472
|
+
setFullscreenPaneId: (paneId: string | null) => void
|
|
473
|
+
locked: boolean
|
|
474
|
+
setLocked: Dispatch<SetStateAction<boolean>>
|
|
475
|
+
|
|
476
|
+
// DnD state
|
|
477
|
+
activeId: string | null
|
|
478
|
+
activeType: 'pane' | 'tab' | null
|
|
479
|
+
dismissIntentId: string | null
|
|
480
|
+
|
|
481
|
+
// Config
|
|
482
|
+
dragActivationDistance: number
|
|
483
|
+
snapThreshold: number
|
|
484
|
+
minSplitPercentage: number
|
|
485
|
+
maxSplitPercentage: number
|
|
486
|
+
enableDragToDismiss: boolean
|
|
487
|
+
dismissThreshold: number
|
|
488
|
+
|
|
489
|
+
// Public actions
|
|
490
|
+
removePane: (paneId: string) => void
|
|
491
|
+
addPane: (paneId: string, metadata?: Record<string, unknown>) => void
|
|
492
|
+
addTab: (paneId: string, tabId: string, metadata?: Record<string, unknown>) => void
|
|
493
|
+
updateTabMetadata: (tabId: string, updater: ...) => void
|
|
494
|
+
updatePaneLock: (paneId: string, locked: boolean) => void
|
|
495
|
+
selectTab: (paneId: string, tabId: string) => void
|
|
496
|
+
mergeTab: (draggedTabId: string, targetPaneId: string) => void
|
|
497
|
+
removeTab: (tabId: string) => void
|
|
498
|
+
splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void
|
|
499
|
+
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void
|
|
500
|
+
moveTab: (draggedTabId: string, targetTabId: string, position?: 'before' | 'after') => void
|
|
501
|
+
|
|
502
|
+
// Public queries
|
|
503
|
+
findPaneById: (paneId: string) => PaneNode | null
|
|
504
|
+
findPaneContainingTab: (tabId: string) => PaneNode | null
|
|
505
|
+
findTabById: (tabId: string) => TabDetails | null
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// ZeugmaContextValue is the combined state + actions interface
|
|
509
|
+
// exposed by useZeugmaContext(). It includes all of ZeugmaController
|
|
510
|
+
// plus the renderPane and classNames configuration.
|
|
511
|
+
export interface ZeugmaContextValue extends ZeugmaStateValue, ZeugmaActionsValue {}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
### Computed Layout Types (from `react-zeugma/utils`)
|
|
515
|
+
|
|
516
|
+
```ts
|
|
517
|
+
export interface ComputedPane {
|
|
518
|
+
paneId: string
|
|
519
|
+
left: number // percentage
|
|
520
|
+
top: number // percentage
|
|
521
|
+
width: number // percentage
|
|
522
|
+
height: number // percentage
|
|
523
|
+
node: PaneNode
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
export interface ComputedSplitter {
|
|
527
|
+
id: string
|
|
528
|
+
currentNode: SplitNode
|
|
529
|
+
direction: SplitDirection
|
|
530
|
+
left: number
|
|
531
|
+
top: number
|
|
532
|
+
width: number
|
|
533
|
+
height: number
|
|
534
|
+
parentLeft: number
|
|
535
|
+
parentTop: number
|
|
536
|
+
parentWidth: number
|
|
537
|
+
parentHeight: number
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
307
541
|
---
|
|
308
542
|
|
|
309
543
|
## SKILL.md
|
|
@@ -481,24 +715,6 @@ Defines the interactive drag region inside a `<Pane>`. **Must be placed inside a
|
|
|
481
715
|
- `className?: string`
|
|
482
716
|
- `style?: React.CSSProperties`
|
|
483
717
|
|
|
484
|
-
---
|
|
485
|
-
|
|
486
|
-
### `<ResizableContainer>`
|
|
487
|
-
|
|
488
|
-
A vertical-resize container wrapper that wraps any node (typically `<PaneTree />` or a dashboard component) and allows the user to resize its height by dragging a handle at the bottom edge. Includes smooth scroll parent propagation and drag-to-scroll infinite scrolling behavior.
|
|
489
|
-
|
|
490
|
-
#### Props
|
|
491
|
-
|
|
492
|
-
- `height?: number` — Controlled height in pixels (or initial height if uncontrolled). Defaults to `400`.
|
|
493
|
-
- `onHeightChange?: (height: number) => void` — Callback function triggered during or after dragging to resize.
|
|
494
|
-
- `minHeight?: number` — Minimum allowed height in pixels (defaults to `100`).
|
|
495
|
-
- `maxHeight?: number` — Maximum allowed height in pixels (defaults to `Infinity`).
|
|
496
|
-
- `persist?: boolean` — Whether to persist height changes in localStorage.
|
|
497
|
-
- `localStorageKey?: string` — Custom localStorage key name (defaults to `'default-pane'`).
|
|
498
|
-
- `resizerHeight?: number` — Height of the resizer drag handle in pixels (defaults to `6`).
|
|
499
|
-
- `className?: string` — Custom CSS class applied to the outer container.
|
|
500
|
-
- `resizerClassName?: string` — Custom CSS class applied to the drag handle.
|
|
501
|
-
|
|
502
718
|
## 3. Programmatic State Utilities
|
|
503
719
|
|
|
504
720
|
Import these helpers from `react-zeugma/utils` to manipulate or query the tree layout programmatically in your state handlers:
|
|
@@ -591,6 +807,7 @@ interface ZeugmaClassNames {
|
|
|
591
807
|
dismissPreview?: string // Applied to the background dismiss zone indicator during a drag-out dismiss gesture
|
|
592
808
|
lockedPreview?: string // Applied to drop zone indicator when hovering over a locked pane
|
|
593
809
|
tabDropPreview?: string // Applied to the drop placeholder line element during tab drags
|
|
810
|
+
tabSeparator?: string // Applied to the separator line between non-active adjacent tabs
|
|
594
811
|
}
|
|
595
812
|
```
|
|
596
813
|
|