react-zeugma 2.3.0 → 4.0.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 CHANGED
@@ -15,7 +15,7 @@
15
15
  ### Core Features
16
16
 
17
17
  - **Recursive Split Trees**: Nest rows and columns to any depth using a simple serialized JSON node structure.
18
- - **5-Zone Docking Previews**: Drag panels on the top, bottom, left, or right edges of another pane to split it, or onto the center to swap their positions.
18
+ - **4-Zone Docking Previews**: Drag panels on the top, bottom, left, or right edges of another pane to split it.
19
19
  - **Native Flexbox Resizers**: Fluid, non-blocking split handles built on pointer events.
20
20
  - **Accessible Drag-and-Drop**: Built on top of the performant and accessible [`@dnd-kit`](https://dndkit.com) toolkit.
21
21
  - **Fullscreen Zoom Toggle**: Programmatically expand any pane to cover the entire viewport and snap it back instantly.
@@ -37,23 +37,22 @@ npm install react-zeugma
37
37
 
38
38
  ## Quick Start
39
39
 
40
- Import the core components and configure the layout state inside your React application.
40
+ Import the core components and configure the layout state inside your React application using the `useZeugma` hook.
41
41
 
42
42
  ```tsx
43
- import { useState } from 'react'
44
- import { Zeugma, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
43
+ import { useZeugma, Zeugma, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
45
44
 
46
45
  const initialLayout: TreeNode = {
47
46
  type: 'split',
48
47
  direction: 'row',
49
48
  splitPercentage: 20,
50
- first: { type: 'pane', paneId: 'explorer' },
49
+ first: { type: 'pane', id: 'explorer', tabs: ['explorer'], activeTabId: 'explorer' },
51
50
  second: {
52
51
  type: 'split',
53
52
  direction: 'row',
54
53
  splitPercentage: 50,
55
- first: { type: 'pane', paneId: 'editor' },
56
- second: { type: 'pane', paneId: 'preview' },
54
+ first: { type: 'pane', id: 'editor', tabs: ['editor'], activeTabId: 'editor' },
55
+ second: { type: 'pane', id: 'preview', tabs: ['preview'], activeTabId: 'preview' },
57
56
  },
58
57
  }
59
58
 
@@ -78,10 +77,10 @@ function MyPane({ id }: { id: string }) {
78
77
  }
79
78
 
80
79
  export default function Dashboard() {
81
- const [layout, setLayout] = useState<TreeNode | null>(initialLayout)
80
+ const zeugma = useZeugma({ initialLayout })
82
81
 
83
82
  return (
84
- <Zeugma layout={layout} onChange={setLayout} renderPane={(id) => <MyPane id={id} />}>
83
+ <Zeugma {...zeugma} renderPane={(id) => <MyPane id={id} />}>
85
84
  <div className="w-screen h-screen">
86
85
  <PaneTree />
87
86
  </div>
@@ -96,29 +95,37 @@ export default function Dashboard() {
96
95
 
97
96
  ### `<Zeugma>`
98
97
 
99
- The context provider that sets up the drag-and-drop state machine, monitors active drags, and registers layout change notifications.
100
-
101
- | Prop | Type | Required | Description |
102
- | ------------------------ | --------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
103
- | `layout` | `TreeNode \| null` | Yes | The serializable tree layout schema. |
104
- | `onChange` | `(layout: TreeNode \| null) => void` | Yes | Fires when resizes, splits, swaps, or removes modify the tree. |
105
- | `renderPane` | `(paneId: string) => ReactNode` | Yes | Renderer function lookup that returns a `<Pane>` structure. |
106
- | `classNames` | `ZeugmaClassNames` | No | Custom classes for overriding pane, resizer, and drop preview overlays. |
107
- | `fullscreenPaneId` | `string \| null` | No | Active ID of the pane taking full viewport coverage. |
108
- | `renderDragOverlay` | `(activeId: string) => ReactNode` | No | Renders a custom cursor-following drag preview overlay. |
109
- | `onFullscreenChange` | `(paneId: string \| null) => void` | No | Callback triggered when a pane enters or leaves fullscreen. |
110
- | `onRemove` | `(paneId: string) => void` | No | Callback triggered when a pane is closed/removed from the layout tree. |
111
- | `dragActivationDistance` | `number` | No | Minimum pointer drag distance (in pixels) required to activate dragging. Defaults to `8`. |
112
- | `enableDragToDismiss` | `boolean` | No | If true, enables the drag-out-to-dismiss gesture where panes can be closed by dragging them outside. Defaults to `false`. |
113
- | `dragOutThreshold` | `number` | No | Distance in pixels outside the container bounds required to trigger drag-out mode. Defaults to `60`. |
114
- | `onDragOutChange` | `(activeId: string \| null) => void` | No | Callback triggered when the drag-out state changes. Receives the pane ID or `null`. |
115
- | `onDragStart` | `(activeId: string) => void` | No | Callback triggered when dragging starts on a pane. |
116
- | `onDragEnd` | `(activeId: string, overId: string \| null, dropAction: any) => void` | No | Callback triggered when dragging ends, providing swap or split details. |
117
- | `onResizeStart` | `(currentNode: SplitNode) => void` | No | Callback triggered when resizing starts on a split node. |
118
- | `onResize` | `(currentNode: SplitNode, percentage: number) => void` | No | Callback triggered continuously while resizing a split node. |
119
- | `onResizeEnd` | `(currentNode: SplitNode, percentage: number) => void` | No | Callback triggered when resizing ends on a split node. |
120
- | `minSplitPercentage` | `number` | No | Minimum resizing limit percentage. Defaults to `5`. |
121
- | `maxSplitPercentage` | `number` | No | Maximum resizing limit percentage. Defaults to `95`. |
98
+ The context provider that sets up the drag-and-drop state machine, monitors active drags, and registers layout change notifications. It extends `ZeugmaController` directly; you typically spread the controller object returned by `useZeugma` onto it.
99
+
100
+ | Prop | Type | Required | Description |
101
+ | -------------------- | -------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------- |
102
+ | `...controllerProps` | `ZeugmaController` | Yes | All properties returned by `useZeugma(options)`. Usually passed by spreading the controller object (e.g., `{...zeugma}`). |
103
+ | `renderPane` | `(paneId: string) => ReactNode` | Yes | Renderer function lookup that returns a `<Pane>` structure. |
104
+ | `classNames` | `ZeugmaClassNames` | No | Custom classes for overriding pane, resizer, and drop preview overlays. |
105
+ | `renderDragOverlay` | `(activeId: string, type: 'pane' \| 'tab') => ReactNode` | No | Renders a custom cursor-following drag preview overlay. |
106
+ | `renderWidget` | `(tabId: string) => ReactNode` | No | Render function mapping tab IDs to React elements. Used to render tab widgets inside portals. |
107
+
108
+ ### `useZeugma(options)`
109
+
110
+ A custom state hook that initializes and manages the recursive layout tree and handles drag-and-drop actions.
111
+
112
+ | Option | Type | Default | Description |
113
+ | ------------------------ | --------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------- |
114
+ | `initialLayout` | `TreeNode \| null` | Yes | Initial layout tree structure. |
115
+ | `locked` | `boolean` | `false` | If true, layout resizes and drags are disabled. |
116
+ | `dragActivationDistance` | `number` | `8` | Minimum pointer drag distance (in pixels) required to activate dragging. |
117
+ | `snapThreshold` | `number` | `8` | Threshold in pixels to snap layout resizers to adjacent edges. |
118
+ | `minSplitPercentage` | `number` | `5` | Minimum resizing limit percentage. |
119
+ | `maxSplitPercentage` | `number` | `95` | Maximum resizing limit percentage. |
120
+ | `enableDragToDismiss` | `boolean` | `false` | If true, enables the drag-out-to-dismiss gesture to close widgets. |
121
+ | `dismissThreshold` | `number` | `60` | Distance in pixels outside container bounds required to trigger dismissal. |
122
+ | `onRemove` | `(paneId: string) => void` | — | Callback triggered when a pane is removed. |
123
+ | `onDragStart` | `(activeId: string) => void` | — | Callback triggered when dragging starts. |
124
+ | `onDragEnd` | `(activeId: string, overId: string \| null, dropAction: any) => void` | — | Callback triggered when dragging ends. |
125
+ | `onResizeStart` | `(currentNode: SplitNode) => void` | — | Callback triggered when resizing starts. |
126
+ | `onResize` | `(currentNode: SplitNode, percentage: number) => void` | — | Callback triggered during resizing. |
127
+ | `onResizeEnd` | `(currentNode: SplitNode, percentage: number) => void` | — | Callback triggered when resizing ends. |
128
+ | `onDismissIntentChange` | `(paneId: string \| null) => void` | — | Callback triggered when drag-out intent changes. |
122
129
 
123
130
  ### `<PaneTree>`
124
131
 
@@ -140,12 +147,13 @@ Wraps the individual pane components inside the renderer. Utilizes a render prop
140
147
 
141
148
  #### Render Props: `PaneRenderProps`
142
149
 
143
- | Parameter | Type | Description |
144
- | ------------------ | ------------ | ------------------------------------------------------------- |
145
- | `isDragging` | `boolean` | Returns `true` if the node wrapper is actively being dragged. |
146
- | `isFullscreen` | `boolean` | Returns `true` if the pane is zoomed/fullscreen. |
147
- | `toggleFullscreen` | `() => void` | Callback to toggle fullscreen viewport coverage. |
148
- | `remove` | `() => void` | Triggers removal of this pane from the layout tree. |
150
+ | Parameter | Type | Description |
151
+ | ------------------ | ----------------- | -------------------------------------------------------------------------------- |
152
+ | `isDragging` | `boolean` | Returns `true` if the node wrapper is actively being dragged. |
153
+ | `isFullscreen` | `boolean` | Returns `true` if the pane is zoomed/fullscreen. |
154
+ | `toggleFullscreen` | `() => void` | Callback to toggle fullscreen viewport coverage. |
155
+ | `remove` | `() => void` | Triggers removal of this pane from the layout tree. |
156
+ | `renderActiveTab` | `() => ReactNode` | Renders the target placeholder element for the currently active tab in the pane. |
149
157
 
150
158
  ### `<DragHandle>`
151
159
 
@@ -187,10 +195,6 @@ Recursively scans the layout tree, removes the targeted pane node, and collapses
187
195
 
188
196
  Recursively matches the bottommost/rightmost pane leaf in the tree, splits it, and inserts the target `paneToAdd`.
189
197
 
190
- #### `swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null`
191
-
192
- Swaps the positions of `idA` and `idB` nodes directly inside the tree structure.
193
-
194
198
  #### `splitPane(tree, targetId, direction, splitType, paneToAdd)`
195
199
 
196
200
  Splits the targeted `targetId` pane inside the tree with `direction` (_row_ / _column_) and type (_left_, _right_, _top_, _bottom_) to insert `paneToAdd`.
@@ -207,17 +211,13 @@ Use custom CSS or styling rules to style resizers, dragging states, drop preview
207
211
 
208
212
  ```tsx
209
213
  <Zeugma
210
- layout={layout}
211
- onChange={setLayout}
212
- renderPane={renderPane}
214
+ {...zeugma}
213
215
  classNames={{
214
216
  // resizer handles
215
217
  resizer:
216
218
  'bg-transparent hover:bg-indigo-500/50 active:bg-indigo-500 transition-colors duration-150',
217
219
  // split previews
218
220
  dropPreview: 'bg-indigo-500/10 border-2 border-dashed border-indigo-500/50 backdrop-blur-xs',
219
- // swap previews
220
- swapPreview: 'bg-amber-500/10 border-2 border-dashed border-amber-500/50 backdrop-blur-xs',
221
221
  }}
222
222
  >
223
223
  <PaneTree />
@@ -248,62 +248,6 @@ export interface PaneNode {
248
248
  }
249
249
 
250
250
  export type TreeNode = SplitNode | PaneNode
251
-
252
- export interface ZeugmaClassNames {
253
- pane?: string
254
- dropPreview?: string
255
- swapPreview?: string
256
- dragOverlay?: string
257
- resizer?: string
258
- dragOut?: string
259
- }
260
-
261
- export interface PaneRenderProps {
262
- isDragging: boolean
263
- isFullscreen: boolean
264
- toggleFullscreen: () => void
265
- remove: () => void
266
- metadata: Record<string, unknown> | undefined
267
- updateMetadata: (
268
- updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
269
- ) => void
270
- }
271
-
272
- export interface ZeugmaStateValue {
273
- layout: TreeNode | null
274
- onLayoutChange: (newLayout: TreeNode | null) => void
275
- renderPane: (paneId: string) => ReactNode
276
- activeId: string | null
277
- dismissIntentId: string | null
278
- setContainerRef: (element: HTMLElement | null) => void
279
- fullscreenPaneId: string | null
280
- classNames: ZeugmaClassNames
281
- onRemove?: (paneId: string) => void
282
- onFullscreenChange?: (paneId: string | null) => void
283
- snapThreshold?: number
284
- onResizeStart?: (currentNode: SplitNode) => void
285
- onResize?: (currentNode: SplitNode, percentage: number) => void
286
- onResizeEnd?: (currentNode: SplitNode, percentage: number) => void
287
- minSplitPercentage?: number
288
- maxSplitPercentage?: number
289
- }
290
-
291
- export interface ZeugmaActionsValue {
292
- removePane: (paneId: string) => void
293
- addPane: (paneId: string) => void
294
- swapPanes: (paneIdA: string, paneIdB: string) => void
295
- splitPane: (
296
- targetId: string,
297
- direction: SplitDirection,
298
- splitType: 'left' | 'right' | 'top' | 'bottom',
299
- paneToAdd: string,
300
- ) => void
301
- updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void
302
- updatePaneMetadata: (
303
- paneId: string,
304
- updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
305
- ) => void
306
- }
307
251
  ```
308
252
 
309
253
  ---
@@ -363,25 +307,33 @@ The root context provider. It handles the drag-and-drop event loop and coordinat
363
307
 
364
308
  #### Props
365
309
 
366
- - `layout: TreeNode | null` — The current dashboard layout tree.
367
- - `onChange: (newLayout: TreeNode | null) => void` — Callback triggered when the layout tree changes (resizing, dragging to split, dragging to swap).
310
+ - `...controllerProps: ZeugmaController` — The controller properties returned by the `useZeugma` hook (typically passed via `{...zeugma}`).
368
311
  - `renderPane: (paneId: string) => ReactNode` — Callback to render the contents of a pane given its ID.
369
- - `renderDragOverlay?: (activeId: string) => ReactNode` — (Optional) Renders a custom cursor-following drag preview.
312
+ - `renderDragOverlay?: (activeId: string, type: 'pane' | 'tab') => ReactNode` — (Optional) Renders a custom cursor-following drag preview.
370
313
  - `classNames?: ZeugmaClassNames` — (Optional) CSS class overrides for styling various layout elements.
371
- - `fullscreenPaneId?: string | null` — (Optional) ID of the pane currently in fullscreen mode.
372
- - `onFullscreenChange?: (paneId: string | null) => void` — (Optional) Callback triggered when a pane enters/leaves fullscreen.
373
- - `onRemove?: (paneId: string) => void` — (Optional) Callback triggered when a pane is closed/removed.
374
- - `dragActivationDistance?: number` — (Optional) Minimum pointer drag distance (in pixels) required to activate dragging. Defaults to `8`.
375
- - `enableDragToDismiss?: boolean` — (Optional) Whether to enable the drag-out-to-dismiss gesture. Defaults to `false`.
376
- - `dragOutThreshold?: number` — (Optional) Distance in pixels outside the container boundaries required to activate drag-out mode. Defaults to `60`.
377
- - `onDragOutChange?: (activeId: string | null) => void` — (Optional) Callback triggered when the drag-out state changes.
378
- - `onDragStart?: (activeId: string) => void` — (Optional) Callback triggered when dragging starts on a pane.
379
- - `onDragEnd?: (activeId: string, overId: string | null, dropAction: any) => void` — (Optional) Callback triggered when dragging ends, providing swap or split details.
380
- - `onResizeStart?: (currentNode: SplitNode) => void` — (Optional) Callback triggered when resizing starts.
381
- - `onResize?: (currentNode: SplitNode, percentage: number) => void` (Optional) Callback triggered during resizing.
382
- - `onResizeEnd?: (currentNode: SplitNode, percentage: number) => void` (Optional) Callback triggered when resizing ends.
383
- - `minSplitPercentage?: number` — (Optional) Minimum resizing limit percentage (defaults to `5`).
384
- - `maxSplitPercentage?: number` — (Optional) Maximum resizing limit percentage (defaults to `95`).
314
+ - `renderWidget?: (tabId: string) => ReactNode` — (Optional) Render function mapping tab IDs to React elements. Used to render tab widgets inside portals.
315
+
316
+ ### `useZeugma(options)`
317
+
318
+ A custom hook to manage the dashboard layout state.
319
+
320
+ #### Options
321
+
322
+ - `initialLayout: TreeNode | null` — Initial layout tree.
323
+ - `locked?: boolean` — Whether the layout is globally locked.
324
+ - `dragActivationDistance?: number` Minimum pointer drag distance (in pixels) required to activate dragging (defaults to `8`).
325
+ - `snapThreshold?: number` Threshold in pixels to snap layout resizers to adjacent edges (defaults to `8`).
326
+ - `minSplitPercentage?: number` — Minimum resizing limit percentage (defaults to `5`).
327
+ - `maxSplitPercentage?: number` — Maximum resizing limit percentage (defaults to `95`).
328
+ - `enableDragToDismiss?: boolean` — Whether to enable drag-out-to-dismiss (defaults to `false`).
329
+ - `dismissThreshold?: number` — Distance in pixels outside container bounds required to trigger dismissal (defaults to `60`).
330
+ - `onRemove?: (paneId: string) => void` — Callback when a pane is removed.
331
+ - `onDragStart?: (activeId: string) => void` — Callback when dragging starts.
332
+ - `onDragEnd?: (activeId: string, overId: string | null, dropAction: any) => void` — Callback when dragging ends.
333
+ - `onResizeStart?: (currentNode: SplitNode) => void` — Callback when resizing starts.
334
+ - `onResize?: (currentNode: SplitNode, percentage: number) => void` — Callback during resizing.
335
+ - `onResizeEnd?: (currentNode: SplitNode, percentage: number) => void` — Callback when resizing ends.
336
+ - `onDismissIntentChange?: (paneId: string | null) => void` — Callback when drag-out intent changes.
385
337
 
386
338
  ### `<PaneTree>`
387
339
 
@@ -413,6 +365,16 @@ interface PaneRenderProps {
413
365
  updateMetadata: (
414
366
  updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
415
367
  ) => void
368
+ tabs: string[]
369
+ activeTabId: string
370
+ selectTab: (tabId: string) => void
371
+ removeTab: (tabId: string) => void
372
+ tabsMetadata: Record<string, Record<string, unknown>> | undefined
373
+ updateTabMetadata: (
374
+ tabId: string,
375
+ updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined,
376
+ ) => void
377
+ renderActiveTab: () => ReactNode
416
378
  }
417
379
  ```
418
380
 
@@ -452,41 +414,24 @@ Import these helpers from `react-zeugma` to manipulate the tree layout programma
452
414
  Removes a pane from the tree and collapses the leftover sibling split node.
453
415
  - **`splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null`**
454
416
  Splits a specific target pane by nesting it under a new `SplitNode` along with a new pane.
455
- - **`swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null`**
456
- Swaps the positions of two panes in the tree.
457
- - **`updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null`**
458
- Updates the metadata of a specific pane.
417
+ - **`updateTabMetadata(tree: TreeNode | null, tabId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null`**
418
+ Updates the metadata of a specific tab.
459
419
  - **`findPane(tree: TreeNode | null, paneId: string): PaneNode | null`**
460
420
  Recursively searches the layout tree and returns the target `PaneNode` if found, or `null` otherwise.
461
421
 
462
- Alternatively, you can consume state and mutation helpers directly from the context hooks:
463
-
464
- - **`useZeugmaState()`**: Returns the reactive state values (e.g., `layout`, `activeId`, `classNames`). Consumers of this hook will re-render whenever layout state updates.
465
- - **`useZeugmaActions()`**: Returns the stable layout mutation actions (e.g., `removePane`, `splitPane`). Because these actions have a permanent identity, consumers of this hook **will not** re-render when layout state changes, providing a significant performance optimization.
466
-
467
- The actions returned by `useZeugmaActions()` are:
468
-
469
- - **`removePane(paneId: string) => void`**
470
- - **`addPane(paneId: string) => void`**
471
- - **`swapPanes(paneIdA: string, paneIdB: string) => void`**
472
- - **`splitPane(targetId: string, direction: SplitDirection, splitType: string, paneToAdd: string) => void`**
473
- - **`updateSplitPercentage(currentNode: SplitNode, percentage: number) => void`**
474
- - **`updatePaneMetadata(paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void`**
475
-
476
422
  ---
477
423
 
478
424
  ## 4. Basic Integration Recipe
479
425
 
480
426
  ```tsx
481
- import { useState } from 'react'
482
- import { Zeugma, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
427
+ import { useZeugma, Zeugma, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
483
428
 
484
429
  const initialLayout: TreeNode = {
485
430
  type: 'split',
486
431
  direction: 'row',
487
432
  splitPercentage: 50,
488
- first: { type: 'pane', paneId: 'sidebar' },
489
- second: { type: 'pane', paneId: 'main' },
433
+ first: { type: 'pane', id: 'sidebar', tabs: ['sidebar'], activeTabId: 'sidebar' },
434
+ second: { type: 'pane', id: 'main', tabs: ['main'], activeTabId: 'main' },
490
435
  }
491
436
 
492
437
  function CustomPane({ id }: { id: string }) {
@@ -511,23 +456,12 @@ function CustomPane({ id }: { id: string }) {
511
456
  }
512
457
 
513
458
  export default function App() {
514
- const [layout, setLayout] = useState<TreeNode | null>(initialLayout)
515
- const [fullscreenId, setFullscreenId] = useState<string | null>(null)
516
-
517
- const handleRemove = (paneId: string) => {
518
- // Remove the pane and update layout
519
- setLayout((prev) => removePane(prev, paneId))
520
- }
459
+ const zeugma = useZeugma({
460
+ initialLayout,
461
+ })
521
462
 
522
463
  return (
523
- <Zeugma
524
- layout={layout}
525
- onChange={setLayout}
526
- renderPane={(id) => <CustomPane id={id} />}
527
- fullscreenPaneId={fullscreenId}
528
- onFullscreenChange={setFullscreenId}
529
- onRemove={handleRemove}
530
- >
464
+ <Zeugma {...zeugma} renderPane={(id) => <CustomPane id={id} />}>
531
465
  <div style={{ width: '100vw', height: '100vh' }}>
532
466
  <PaneTree />
533
467
  </div>
@@ -546,7 +480,6 @@ export default function App() {
546
480
  interface ZeugmaClassNames {
547
481
  pane?: string // Applied to the outer wrapper of <Pane>
548
482
  dropPreview?: string // Applied to the preview box when hovering over edge dropzones
549
- swapPreview?: string // Applied to the preview box when hovering over center dropzone
550
483
  dragOverlay?: string // Applied to the cursor-following drag preview portal
551
484
  resizer?: string // Applied to the drag-to-resize split bar
552
485
  }
@@ -565,16 +498,6 @@ interface ZeugmaClassNames {
565
498
  }
566
499
 
567
500
  /* Edge drop previews */
568
- .my-drop-preview {
569
- background-color: rgba(59, 130, 246, 0.2);
570
- border: 2px dashed #3b82f6;
571
- }
572
-
573
- /* Center swap preview */
574
- .my-swap-preview {
575
- background-color: rgba(16, 185, 129, 0.25);
576
- border: 2px solid #10b981;
577
- }
578
501
  ```
579
502
  ````
580
503
 
package/dist/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
- 'use strict';var react=require('react'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');var ve=react.createContext(void 0),be=react.createContext(void 0);var G=()=>{let e=react.useContext(ve);if(!e)throw new Error("useZeugmaState must be used within a Zeugma provider");return e},Te=()=>{let e=react.useContext(be);if(!e)throw new Error("useZeugmaActions must be used within a Zeugma provider");return e};function Ue(e){let t=react.useRef(null);return react.useEffect(()=>{if(!e){t.current=null;return}let o=n=>{t.current={x:n.clientX,y:n.clientY};},r=n=>{let i=n.touches[0]||n.changedTouches[0];i&&(t.current={x:i.clientX,y:i.clientY});};return window.addEventListener("pointermove",o,{passive:true}),window.addEventListener("touchmove",r,{passive:true}),()=>{window.removeEventListener("pointermove",o),window.removeEventListener("touchmove",r);}},[e]),t}function We(e){react.useEffect(()=>(e?document.body.style.setProperty("cursor","not-allowed","important"):document.body.style.removeProperty("cursor"),()=>{document.body.style.removeProperty("cursor");}),[e]);}function ae(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let o=ae(e.first,t),r=ae(e.second,t);return o===null?r:r===null?o:{...e,first:o,second:r}}function ue(e,t,o,r,n){if(e===null)return typeof n=="string"?{type:"pane",paneId:n}:n;if(e.type==="pane"){if(e.paneId===t){let i=typeof n=="string"?{type:"pane",paneId:n}:n,s=r==="left"||r==="top";return {type:"split",direction:o,first:s?i:e,second:s?e:i,splitPercentage:50}}return e}return {...e,first:ue(e.first,t,o,r,n)||e.first,second:ue(e.second,t,o,r,n)||e.second}}function ze(e,t,o){if(e===null)return null;let r=B(e,t),n=B(e,o);if(!r||!n)return e;function i(s){return s.type==="pane"?s.paneId===t?{...n}:s.paneId===o?{...r}:s:{...s,first:i(s.first),second:i(s.second)}}return i(e)}function Be(e,t){if(e===null)return {type:"pane",paneId:t};function o(r,n){return r.type==="pane"?{type:"split",direction:n==="row"?"column":"row",splitPercentage:50,first:r,second:{type:"pane",paneId:t}}:{...r,second:o(r.second,r.direction)}}return o(e,null)}function te(e,t,o){return e===null?null:e===t?{...e,splitPercentage:o}:e.type==="split"?{...e,first:te(e.first,t,o)||e.first,second:te(e.second,t,o)||e.second}:e}function B(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:B(e.first,t)??B(e.second,t)}function he(e,t,o){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){let r=o(e.metadata);if(r===void 0){let{metadata:n,...i}=e;return i}return {...e,metadata:r}}return e}return {...e,first:he(e.first,t,o)??e.first,second:he(e.second,t,o)??e.second}}function Pe(e,t,o){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){if(o===false){let{locked:r,...n}=e;return n}return {...e,locked:o}}return e}return {...e,first:Pe(e.first,t,o)??e.first,second:Pe(e.second,t,o)??e.second}}var st=8,at=8,Xt=4;var Xe=({activeId:e,render:t,className:o})=>{let r=react.useRef(null);return react.useEffect(()=>{let n=i=>{r.current&&(r.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",n),()=>document.removeEventListener("pointermove",n)},[]),jsxRuntime.jsx("div",{ref:r,className:o,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})};var xe=class extends core.PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},ye=class extends core.TouchSensor{static activators=[{eventName:"onTouchStart",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]};function Ke(e){if(e instanceof MouseEvent||e instanceof PointerEvent)return {x:e.clientX,y:e.clientY};if(typeof TouchEvent<"u"&&e instanceof TouchEvent){let t=e.touches[0]||e.changedTouches[0];if(t)return {x:t.clientX,y:t.clientY}}return null}var vt=({layout:e,onChange:t,renderPane:o,renderDragOverlay:r,classNames:n={},fullscreenPaneId:i=null,onFullscreenChange:s,onRemove:c,dragActivationDistance:x=8,snapThreshold:y=8,onDragStart:z,onDragEnd:a,onResizeStart:R,onResize:m,onResizeEnd:d,minSplitPercentage:E=5,maxSplitPercentage:L=95,enableDragToDismiss:S=false,dismissThreshold:f=60,onDismissIntentChange:v,locked:w=false,children:D})=>{let[u,b]=react.useState(e),[X,N]=react.useState(e);e!==X&&(N(e),b(e));let[k,Z]=react.useState(null),[I,C]=react.useState(null),Y=react.useRef(null),g=react.useRef(null),A=Ue(k),W=react.useCallback(l=>{Y.current=l;},[]),[O,M]=react.useState(false);We(O);let H=react.useCallback(l=>o(l),[o]),oe=react.useMemo(()=>n,[n.pane,n.paneLocked,n.dropPreview,n.swapPreview,n.dragOverlay,n.resizer,n.dismissPreview,n.dashboardLocked,n.lockedPreview]),Le=core.useSensors(core.useSensor(xe,{activationConstraint:{distance:x}}),core.useSensor(ye,{activationConstraint:{delay:250,tolerance:5}})),me=l=>{let p=l.active.id.toString();Z(p);let T=l.activatorEvent;A.current=Ke(T),S&&Y.current?g.current=Y.current.getBoundingClientRect():g.current=null,z&&z(p);},re=l=>{let{over:p}=l,P=(p?.id.toString()||"").startsWith("drop-locked-");if(M(P),!S)return;let K=l.active.id.toString(),h=g.current;if(!h){I!==null&&(C(null),v?.(null));return}let J=l.activatorEvent,U=null,F=null;if(A.current)U=A.current.x,F=A.current.y;else {let $=Ke(J);$&&(U=$.x+l.delta.x,F=$.y+l.delta.y);}let Q=0;if(U!==null&&F!==null){let $=0,V=0;U<h.left?$=h.left-U:U>h.right&&($=U-h.right),F<h.top?V=h.top-F:F>h.bottom&&(V=F-h.bottom),Q=Math.sqrt($*$+V*V);}else {let $=l.active.rect.current.translated;if($){let V=$.left+$.width/2,j=$.top+$.height/2,q=0,ee=0;V<h.left?q=h.left-V:V>h.right&&(q=V-h.right),j<h.top?ee=h.top-j:j>h.bottom&&(ee=j-h.bottom),Q=Math.sqrt(q*q+ee*ee);}}Q>f?I!==K&&(C(K),v?.(K)):I!==null&&(C(null),v?.(null));},ge=l=>{Z(null),M(false);let{active:p,over:T}=l,P=p.id.toString(),K=S&&I===P;if(C(null),v?.(null),g.current=null,K){c?c(P):le(P),a&&a(P,null,null);return}if(!T){a&&a(P,null,null);return}let h=T.id.toString();if(h.startsWith("drop-locked-")){a&&a(P,null,null);return}let J=h.match(/^drop-center-(.+)$/);if(J){let[,q]=J;if(P!==q){let ee=ze(u,P,q);b(ee),t(ee);}a&&a(P,q,{type:"swap",position:"center"});return}let U=h.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!U){a&&a(P,null,null);return}let[,F,Q]=U;if(P===Q){a&&a(P,null,null);return}let Ne=F==="left"||F==="right"?"row":"column",$=B(u,P)??{type:"pane",paneId:P},V=ae(u,P),j=ue(V,Q,Ne,F,$);b(j),t(j),a&&a(P,Q,{type:"split",direction:Ne,position:F});},ie=react.useCallback((l,p=false)=>{b(l),p||t(l);},[t]),le=react.useCallback(l=>{let p=ae(u,l);b(p),t(p);},[u,t]),ce=react.useCallback(l=>{let p=Be(u,l);b(p),t(p);},[u,t]),se=react.useCallback((l,p)=>{let T=ze(u,l,p);b(T),t(T);},[u,t]),Ae=react.useCallback((l,p,T,P)=>{let K=B(u,P)??{type:"pane",paneId:P},h=ae(u,P),J=ue(h,l,p,T,K);b(J),t(J);},[u,t]),ke=react.useCallback((l,p)=>{let T=te(u,l,p);b(T),t(T);},[u,t]),He=react.useCallback((l,p)=>{let T=he(u,l,p);b(T),t(T);},[u,t]),Fe=react.useCallback((l,p)=>{let T=Pe(u,l,p);b(T),t(T);},[u,t]),Oe=react.useCallback((l,p)=>{d&&d(l,p);},[d]),ot=react.useMemo(()=>({layout:u,onLayoutChange:ie,renderPane:H,activeId:k,dismissIntentId:I,setContainerRef:W,fullscreenPaneId:i,classNames:oe,onRemove:c,onFullscreenChange:s,snapThreshold:y,onResizeStart:R,onResize:m,onResizeEnd:Oe,minSplitPercentage:E,maxSplitPercentage:L,locked:w}),[u,k,I,W,i,oe,c,s,y,R,m,E,L,ie,H,Oe,w]),rt=react.useMemo(()=>({removePane:le,addPane:ce,swapPanes:se,splitPane:Ae,updateSplitPercentage:ke,updatePaneMetadata:He,updatePaneLock:Fe}),[le,ce,se,Ae,ke,He,Fe]);return jsxRuntime.jsx(be.Provider,{value:rt,children:jsxRuntime.jsxs(ve.Provider,{value:ot,children:[jsxRuntime.jsx(core.DndContext,{id:"zeugma-dnd-context",sensors:Le,collisionDetection:core.pointerWithin,onDragStart:me,onDragMove:re,onDragEnd:ge,children:D}),k&&r&&jsxRuntime.jsx(Xe,{activeId:k,render:r,className:`${n.dragOverlay||""} ${k===I?n.dismissPreview||"zeugma-dismiss-preview":""}`.trim()})]})})};function Se({cursor:e,resizerEl:t,onMove:o,onEnd:r}){document.body.classList.add("zeugma-resizing");let n=document.createElement("style");n.id="zeugma-global-cursor-style",n.textContent=`
1
+ 'use strict';var en=require('react'),reactDom=require('react-dom'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var en__default=/*#__PURE__*/_interopDefault(en);var ze=en.createContext(void 0),Ie=en.createContext(void 0);var oe=()=>{let e=en.useContext(ze);if(!e)throw new Error("useZeugmaState must be used within a Zeugma provider");return e},nt=()=>{let e=en.useContext(Ie);if(!e)throw new Error("useZeugmaActions must be used within a Zeugma provider");return e};function rt(e){let t=en.useRef(null);return en.useEffect(()=>{if(!e){t.current=null;return}let r=n=>{t.current={x:n.clientX,y:n.clientY};},o=n=>{let s=n.touches[0]||n.changedTouches[0];s&&(t.current={x:s.clientX,y:s.clientY});};return window.addEventListener("pointermove",r,{passive:true}),window.addEventListener("touchmove",o,{passive:true}),()=>{window.removeEventListener("pointermove",r),window.removeEventListener("touchmove",o);}},[e]),t}function ot(e){en.useEffect(()=>(e?document.body.style.setProperty("cursor","not-allowed","important"):document.body.style.removeProperty("cursor"),()=>{document.body.style.removeProperty("cursor");}),[e]);}function st(){let[e,t]=en.useState({}),r=en.useCallback((o,n)=>{t(s=>s[o]===n?s:{...s,[o]:n});},[]);return {portalTargets:e,registerPortalTarget:r}}var $e=en.createContext(void 0);var Ht=8,Zt=8,An=4;function ie(){return "pane-"+Math.random().toString(36).substring(2,11)}function be(e,t){if(e===null)return null;if(e.type==="pane")return e.id===t?null:e;let r=be(e.first,t),o=be(e.second,t);return r===null?o:o===null?r:{...e,first:r,second:o}}function de(e,t){if(e===null)return null;if(e.type==="pane"){if(e.tabs.includes(t)){let n=e.tabs.filter(a=>a!==t);if(n.length===0)return null;let s=e.activeTabId;e.activeTabId===t&&(s=n[0]);let i={...e.tabsMetadata};return delete i[t],{...e,tabs:n,activeTabId:s,tabsMetadata:Object.keys(i).length>0?i:void 0}}return e}let r=de(e.first,t),o=de(e.second,t);return r===null?o:o===null?r:{...e,first:r,second:o}}function ye(e,t,r,o,n){if(e===null)return typeof n=="string"?{type:"pane",id:ie(),tabs:[n],activeTabId:n}:n;if(e.type==="pane"){if(e.id===t||e.tabs.includes(t)){let s=typeof n=="string"?{type:"pane",id:ie(),tabs:[n],activeTabId:n}:n,i=o==="left"||o==="top";return {type:"split",direction:r,first:i?s:e,second:i?e:s,splitPercentage:50}}return e}return {...e,first:ye(e.first,t,r,o,n)||e.first,second:ye(e.second,t,r,o,n)||e.second}}function it(e,t){if(e===null)return {type:"pane",id:ie(),tabs:[t],activeTabId:t};function r(o,n){return o.type==="pane"?{type:"split",direction:n==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",id:ie(),tabs:[t],activeTabId:t}}:{...o,second:r(o.second,o.direction)}}return r(e,null)}function ve(e,t,r){return e===null?null:e===t?{...e,splitPercentage:r}:e.type==="split"?{...e,first:ve(e.first,t,r)||e.first,second:ve(e.second,t,r)||e.second}:e}function q(e,t){return e===null?null:e.type==="pane"?e.id===t||e.tabs.includes(t)?e:null:q(e.first,t)??q(e.second,t)}function ke(e,t,r){if(e===null)return null;if(e.type==="pane"){if(e.id===t||e.tabs.includes(t)){let o=e.tabsMetadata||{},n=o[t],s=r(n),i={...o};return s===void 0?delete i[t]:i[t]=s,{...e,tabsMetadata:Object.keys(i).length>0?i:void 0}}return e}return {...e,first:ke(e.first,t,r)??e.first,second:ke(e.second,t,r)??e.second}}function He(e,t,r){if(e===null)return null;if(e.type==="pane"){if(e.id===t||e.tabs.includes(t)){if(r===false){let{locked:o,...n}=e;return n}return {...e,locked:r}}return e}return {...e,first:He(e.first,t,r)??e.first,second:He(e.second,t,r)??e.second}}function Ze(e,t,r){return e===null?null:e.type==="pane"?e.id===t||e.tabs.includes(t)?{...e,activeTabId:r}:e:{...e,first:Ze(e.first,t,r)??e.first,second:Ze(e.second,t,r)??e.second}}function at(e,t,r){if(e===null)return null;let n=q(e,t)?.tabsMetadata?.[t],s=de(e,t);if(s===null)return {type:"pane",id:ie(),tabs:[t],activeTabId:t,tabsMetadata:n?{[t]:n}:void 0};function i(a){if(a.type==="pane"){if(a.id===r||a.tabs.includes(r)){let l=[...a.tabs];l.includes(t)||l.push(t);let y={...a.tabsMetadata};return n&&(y[t]=n),{...a,tabs:l,activeTabId:t,tabsMetadata:Object.keys(y).length>0?y:void 0}}return a}return {...a,first:i(a.first),second:i(a.second)}}return i(s)}function lt(e,t,r,o="before"){if(e===null)return null;let s=q(e,t)?.tabsMetadata?.[t],i=de(e,t);if(i===null)return {type:"pane",id:ie(),tabs:[t],activeTabId:t,tabsMetadata:s?{[t]:s}:void 0};function a(l){if(l.type==="pane"){if(l.id===r||l.tabs.includes(r)){let D=[...l.tabs].filter(T=>T!==t),c=D.indexOf(r);c<0&&(c=0),o==="after"&&(c+=1),D.splice(c,0,t);let x={...l.tabsMetadata};return s&&(x[t]=s),{...l,tabs:D,activeTabId:t,tabsMetadata:Object.keys(x).length>0?x:void 0}}return l}return {...l,first:a(l.first),second:a(l.second)}}return a(i)}function se(e,t=0,r=0,o=100,n=100,s="root"){if(e===null)return {panes:[],splitters:[]};if(e.type==="pane")return {panes:[{paneId:e.id,left:t,top:r,width:o,height:n,node:e}],splitters:[]};let{direction:i,splitPercentage:a,first:l,second:y}=e,c={id:`splitter-${s}-${i}`,currentNode:e,direction:i,left:i==="row"?t+o*(a/100):t,top:i==="column"?r+n*(a/100):r,width:i==="row"?0:o,height:i==="column"?0:n,parentLeft:t,parentTop:r,parentWidth:o,parentHeight:n},x={panes:[],splitters:[]},T={panes:[],splitters:[]};if(i==="row"){let v=o*(a/100);x=se(l,t,r,v,n,`${s}-L`),T=se(y,t+v,r,o-v,n,`${s}-R`);}else {let v=n*(a/100);x=se(l,t,r,o,v,`${s}-T`),T=se(y,t,r+v,o,n-v,`${s}-B`);}return {panes:[...x.panes,...T.panes],splitters:[c,...x.splitters,...T.splitters]}}function At(e){let{initialLayout:t,onChange:r,fullscreenPaneId:o,onFullscreenChange:n,locked:s=false,dragActivationDistance:i=8,snapThreshold:a=8,minSplitPercentage:l=5,maxSplitPercentage:y=95,enableDragToDismiss:D=false,dismissThreshold:c=60,onRemove:x,onDragStart:T,onDragEnd:v,onResizeStart:R,onResize:E,onResizeEnd:L,onDismissIntentChange:p}=e,[b,f]=en.useState(t),[z,A]=en.useState(o||null),[I,V]=en.useState(s),[w,K]=en.useState(null),[h,F]=en.useState(null),[Y,O]=en.useState(null),m=en.useRef(null),$=en.useCallback(u=>{m.current=u;},[]),_=en.useCallback(u=>{A(u),n?.(u);},[n]);en.useEffect(()=>{V(s);},[s]),en.useEffect(()=>{o!==void 0&&A(o);},[o]);let k=en.useRef(true);en.useEffect(()=>{if(k.current){k.current=false;return}r?.(b);},[b,r]);let N=en.useCallback(u=>{f(S=>be(S,u));},[]),d=en.useCallback(u=>{f(S=>it(S,u));},[]),B=en.useCallback((u,S,P,te)=>{f(Re=>{let _e=q(Re,te)??{type:"pane",id:te,tabs:[te],activeTabId:te},Ye=be(Re,te);return ye(Ye,u,S,P,_e)});},[]),ae=en.useCallback((u,S)=>{f(P=>ve(P,u,S));},[]),W=en.useCallback((u,S)=>{f(P=>ke(P,u,S));},[]),ee=en.useCallback((u,S)=>{f(P=>He(P,u,S));},[]),le=en.useCallback((u,S)=>{f(P=>Ze(P,u,S));},[]),fe=en.useCallback((u,S)=>{f(P=>at(P,u,S));},[]),me=en.useCallback((u,S,P)=>{f(te=>lt(te,u,S,P));},[]),j=en.useCallback(u=>{f(S=>de(S,u));},[]);return {layout:b,setLayout:f,fullscreenPaneId:z,setFullscreenPaneId:_,locked:I,setLocked:V,activeId:w,setActiveId:K,activeType:h,setActiveType:F,dismissIntentId:Y,setDismissIntentId:O,containerRef:m,setContainerRef:$,dragActivationDistance:i,snapThreshold:a,minSplitPercentage:l,maxSplitPercentage:y,enableDragToDismiss:D,dismissThreshold:c,onRemove:x,onDragStart:T,onDragEnd:v,onResizeStart:R,onResize:E,onResizeEnd:L,onDismissIntentChange:p,removePane:N,addPane:d,splitPane:B,updateSplitPercentage:ae,updateTabMetadata:W,updatePaneLock:ee,selectTab:le,mergeTab:fe,moveTab:me,removeTab:j}}var ut=({activeId:e,render:t,className:r})=>{let o=en.useRef(null);return en.useEffect(()=>{let n=s=>{o.current&&(o.current.style.transform=`translate(${s.clientX+12}px, ${s.clientY+12}px)`);};return document.addEventListener("pointermove",n),()=>document.removeEventListener("pointermove",n)},[]),jsxRuntime.jsx("div",{ref:o,className:r,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})};var Ae=class extends core.PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},Fe=class extends core.TouchSensor{static activators=[{eventName:"onTouchStart",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]};function qe(e){if(e instanceof MouseEvent||e instanceof PointerEvent)return {x:e.clientX,y:e.clientY};if(typeof TouchEvent<"u"&&e instanceof TouchEvent){let t=e.touches[0]||e.changedTouches[0];if(t)return {x:t.clientX,y:t.clientY}}return null}var Kt=e=>{let{renderPane:t,renderWidget:r,renderDragOverlay:o,classNames:n={},children:s,layout:i,setLayout:a,fullscreenPaneId:l,setFullscreenPaneId:y,locked:D,activeId:c,setActiveId:x,activeType:T,setActiveType:v,dismissIntentId:R,setDismissIntentId:E,containerRef:L,setContainerRef:p,dragActivationDistance:b,snapThreshold:f,minSplitPercentage:z,maxSplitPercentage:A,enableDragToDismiss:I,dismissThreshold:V,onRemove:w,onDragStart:K,onDragEnd:h,onResizeStart:F,onResize:Y,onResizeEnd:O,onDismissIntentChange:m,removePane:$,addPane:_,splitPane:k,updateSplitPercentage:N,updateTabMetadata:d,updatePaneLock:B,selectTab:ae,mergeTab:W,moveTab:ee,removeTab:le}=e,{portalTargets:fe,registerPortalTarget:me}=st(),j=en.useRef(null),u=rt(c),[S,P]=en.useState(false);ot(S);let te=en.useCallback(g=>t(g),[t]),Re=en.useMemo(()=>n,[n.pane,n.paneLocked,n.dropPreview,n.dragOverlay,n.resizer,n.dismissPreview,n.dashboardLocked,n.lockedPreview]),_e=core.useSensors(core.useSensor(Ae,{activationConstraint:{distance:b}}),core.useSensor(Fe,{activationConstraint:{delay:250,tolerance:5}})),Ye=en.useCallback(g=>{let H=core.pointerWithin(g);if(H.length>0)return H;if(g.active.id.toString().startsWith("tab-header-")){let ne=g.droppableContainers.filter(J=>J.id.toString().startsWith("tab-drop-"));return core.closestCenter({...g,droppableContainers:ne})}return []},[]),Rt=g=>{let H=g.active.id.toString(),U=H.startsWith("tab-header-"),ne=U?H.substring(11):H;x(ne),v(U?"tab":"pane");let J=g.activatorEvent;u.current=qe(J),I&&L.current?j.current=L.current.getBoundingClientRect():j.current=null,K&&K(ne);},St=g=>{let{over:H}=g,ne=(H?.id.toString()||"").startsWith("drop-locked-");if(P(ne),!I)return;let J=g.active.id.toString(),Se=J.startsWith("tab-header-")?J.substring(11):J,M=j.current;if(!M){R!==null&&(E(null),m?.(null));return}let we=g.activatorEvent,re=null,X=null;if(u.current)re=u.current.x,X=u.current.y;else {let Z=qe(we);Z&&(re=Z.x+g.delta.x,X=Z.y+g.delta.y);}let ce=0;if(re!==null&&X!==null){let Z=0,Q=0;re<M.left?Z=M.left-re:re>M.right&&(Z=re-M.right),X<M.top?Q=M.top-X:X>M.bottom&&(Q=X-M.bottom),ce=Math.sqrt(Z*Z+Q*Q);}else {let Z=g.active.rect.current.translated;if(Z){let Q=Z.left+Z.width/2,ge=Z.top+Z.height/2,ue=0,Pe=0;Q<M.left?ue=M.left-Q:Q>M.right&&(ue=Q-M.right),ge<M.top?Pe=M.top-ge:ge>M.bottom&&(Pe=ge-M.bottom),ce=Math.sqrt(ue*ue+Pe*Pe);}}ce>V?R!==Se&&(E(Se),m?.(Se)):R!==null&&(E(null),m?.(null));},Dt=g=>{x(null),v(null),P(false);let{active:H,over:U}=g,ne=H.id.toString(),J=ne.startsWith("tab-header-"),C=J?ne.substring(11):ne,Se=I&&R===C;if(E(null),m?.(null),j.current=null,Se){w?w(C):le(C),h&&h(C,null,null);return}if(!U){h&&h(C,null,null);return}let M=U.id.toString();if(M.startsWith("drop-locked-")){h&&h(C,null,null);return}let we=M.match(/^tab-drop-(.+)$/);if(we){let[,Ne]=we;if(C!==Ne){let Ee="before",Je=U.rect,Lt=g.activatorEvent,Me=null;if(u.current)Me=u.current.x;else {let Le=qe(Lt);Le&&(Me=Le.x+g.delta.x);}if(Me!==null){let Le=Je.left+Je.width/2;Me>Le&&(Ee="after");}ee(C,Ne,Ee);}h&&h(C,Ne,{type:"swap",position:"center"});return}let re=M.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!re){h&&h(C,null,null);return}let[,X,ce]=re,De=q(i,C),Z=De&&De.id===ce,Q=De&&De.tabs.length===1;if(C===ce||Z&&Q){h&&h(C,null,null);return}let ge=X==="left"||X==="right"?"row":"column",ue;if(J){let Ee=q(i,C)?.tabsMetadata?.[C];ue={type:"pane",id:ie(),tabs:[C],activeTabId:C,tabsMetadata:Ee?{[C]:Ee}:void 0};}else ue=q(i,C)??{type:"pane",id:ie(),tabs:[C],activeTabId:C};let Pe=J?de(i,C):be(i,C),Mt=ye(Pe,ce,ge,X,ue);a(Mt),h&&h(C,ce,{type:"split",direction:ge,position:X});},je=en.useCallback((g,H)=>{O&&O(g,H);},[O]),Et=en.useMemo(()=>({layout:i,onLayoutChange:g=>a(g),renderPane:te,activeId:c,dismissIntentId:R,setContainerRef:p,fullscreenPaneId:l,classNames:Re,onRemove:w,onFullscreenChange:y,snapThreshold:f,onResizeStart:F,onResize:Y,onResizeEnd:je,minSplitPercentage:z,maxSplitPercentage:A,locked:D}),[i,c,R,p,l,Re,w,y,f,F,Y,z,A,a,te,je,D]),Ct=en.useMemo(()=>({removePane:$,addPane:_,splitPane:k,updateSplitPercentage:N,updateTabMetadata:d,updatePaneLock:B,selectTab:ae,mergeTab:W,moveTab:ee,removeTab:le}),[$,_,k,N,d,B,ae,W,ee,le]),wt=en.useMemo(()=>{let g=[];function H(U){U&&(U.type==="pane"?g.push(...U.tabs):(H(U.first),H(U.second)));}return H(i),g},[i]),Nt=en.useMemo(()=>({registerPortalTarget:me}),[me]);return jsxRuntime.jsx(Ie.Provider,{value:Ct,children:jsxRuntime.jsx(ze.Provider,{value:Et,children:jsxRuntime.jsxs($e.Provider,{value:Nt,children:[jsxRuntime.jsx(core.DndContext,{id:"zeugma-dnd-context",sensors:_e,collisionDetection:Ye,onDragStart:Rt,onDragMove:St,onDragEnd:Dt,children:s}),c&&T&&o&&jsxRuntime.jsx(ut,{activeId:c,render:g=>o(g,T),className:`${n.dragOverlay||""} ${c===R?n.dismissPreview||"zeugma-dismiss-preview":""}`.trim()}),jsxRuntime.jsx("div",{id:"zeugma-portal-host",style:{display:"none"},children:wt.map(g=>jsxRuntime.jsx(jt,{tabId:g,target:fe[g]||null,renderWidget:r},g))})]})})})},jt=({tabId:e,target:t,renderWidget:r})=>{let o=en.useRef(null);!o.current&&typeof window<"u"&&(o.current=document.createElement("div"),o.current.className=`zeugma-portal-wrapper-${e}`,o.current.style.width="100%",o.current.style.height="100%");let n=o.current;return en.useEffect(()=>{if(n)if(t)t.appendChild(n);else {let s=document.getElementById("zeugma-hidden-portal-container");s||(s=document.createElement("div"),s.id="zeugma-hidden-portal-container",s.style.display="none",document.body.appendChild(s)),s.appendChild(n);}},[t,n]),en.useEffect(()=>()=>{o.current&&o.current.remove();},[]),!n||!r?null:reactDom.createPortal(r(e),n)};function Oe({cursor:e,resizerEl:t,onMove:r,onEnd:o}){document.body.classList.add("zeugma-resizing");let n=document.createElement("style");n.id="zeugma-global-cursor-style",n.textContent=`
2
2
  * {
3
3
  cursor: ${e} !important;
4
4
  user-select: none !important;
5
5
  }
6
- `,document.head.appendChild(n),t.setAttribute("data-resizing","true");let i=c=>{o(c);},s=()=>{document.body.classList.remove("zeugma-resizing"),t.removeAttribute("data-resizing");let c=document.getElementById("zeugma-global-cursor-style");c&&c.remove(),document.removeEventListener("pointermove",i),document.removeEventListener("pointerup",s),r();};document.addEventListener("pointermove",i),document.addEventListener("pointerup",s);}function Ce({containerRef:e,isRow:t,direction:o,splitPercentage:r,resizerSize:n,snapThreshold:i,layout:s,currentNode:c,onLayoutChange:x,onResizeStart:y,onResizeEnd:z,parentLeft:a,parentTop:R,parentWidth:m,parentHeight:d}){let{onResizeStart:E,onResize:L,onResizeEnd:S,minSplitPercentage:f=5,maxSplitPercentage:v=95,locked:w=false}=G();return react.useCallback(D=>{if(w)return;D.preventDefault();let u=e.current;if(!u)return;y&&y(),E&&E(c);let b=u.getBoundingClientRect(),X=D.clientX,N=D.clientY,k=r,Z=D.currentTarget,I=b.left+b.width*(a/100),C=b.top+b.height*(R/100),Y=b.width*(m/100),g=b.height*(d/100),W=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(M=>M!==Z&&M.getAttribute("data-direction")===o).map(M=>{let H=M.getBoundingClientRect();return t?H.left+H.width/2:H.top+H.height/2}),O=k;Se({cursor:t?"col-resize":"row-resize",resizerEl:Z,onMove:M=>{let H=t?(M.clientX-X)/Y*100:(M.clientY-N)/g*100,oe=k+H,Le=t?I+(Y-n)*(oe/100)+n/2:C+(g-n)*(oe/100)+n/2,me=1/0,re=null;for(let ce of W){let se=Math.abs(Le-ce);se<i&&se<me&&(me=se,re=ce);}let ge=oe;re!==null&&(ge=t?(re-n/2-I)/(Y-n)*100:(re-n/2-C)/(g-n)*100);let ie=Math.max(f,Math.min(v,ge));O=ie;let le=te(s,c,ie);x(le,true),L&&L(c,ie);},onEnd:()=>{let M=te(s,c,O);x(M),z&&z(),S&&S(c,O);}});},[e,t,o,r,n,i,s,c,x,y,z,E,L,S,f,v,a,R,m,d])}function pe(e,t=0,o=0,r=100,n=100,i="root"){if(e.type==="pane")return {panes:[{paneId:e.paneId,left:t,top:o,width:r,height:n,node:e}],splitters:[]};let{direction:s,splitPercentage:c,first:x,second:y}=e,a={id:`splitter-${i}-${s}`,currentNode:e,direction:s,left:s==="row"?t+r*(c/100):t,top:s==="column"?o+n*(c/100):o,width:s==="row"?0:r,height:s==="column"?0:n,parentLeft:t,parentTop:o,parentWidth:r,parentHeight:n},R={panes:[],splitters:[]},m={panes:[],splitters:[]};if(s==="row"){let d=r*(c/100);R=pe(x,t,o,d,n,`${i}-L`),m=pe(y,t+d,o,r-d,n,`${i}-R`);}else {let d=n*(c/100);R=pe(x,t,o,r,d,`${i}-T`),m=pe(y,t,o+d,r,n-d,`${i}-B`);}return {panes:[...R.panes,...m.panes],splitters:[a,...R.splitters,...m.splitters]}}var St=({splitter:e,resizerSize:t,snapThreshold:o,containerRef:r})=>{let{layout:n,onLayoutChange:i,classNames:s,locked:c}=G(),[x,y]=react.useState(false),{currentNode:z,direction:a,left:R,top:m,width:d,height:E,parentLeft:L,parentTop:S,parentWidth:f,parentHeight:v}=e,w=a==="row",D=Ce({containerRef:r,isRow:w,direction:a,splitPercentage:z.splitPercentage,resizerSize:t,snapThreshold:o,layout:n,currentNode:z,onLayoutChange:i,onResizeStart:()=>y(true),onResizeEnd:()=>y(false),parentLeft:L,parentTop:S,parentWidth:f,parentHeight:v}),u=w?{position:"absolute",left:`calc(${R}% - ${t/2}px)`,top:`${m}%`,width:`${t}px`,height:`${E}%`,cursor:c?"default":"col-resize",pointerEvents:c?"none":"auto",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box"}:{position:"absolute",left:`${R}%`,top:`calc(${m}% - ${t/2}px)`,width:`${d}%`,height:`${t}px`,cursor:c?"default":"row-resize",pointerEvents:c?"none":"auto",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box"};return jsxRuntime.jsx("div",{className:`zeugma-resizer ${s.resizer||""}`.trim(),"data-direction":a,"data-resizing":x||void 0,style:u,onPointerDown:D,role:"separator","aria-valuenow":z.splitPercentage,"aria-valuemin":5,"aria-valuemax":95})},wt=({tree:e,resizerSize:t=4,snapThreshold:o})=>{let{layout:r,renderPane:n,activeId:i,dismissIntentId:s,setContainerRef:c,fullscreenPaneId:x,snapThreshold:y,locked:z,classNames:a}=G(),R=o!==void 0?o:y??8,m=e!==void 0?e:r,d=react.useRef(null),{panes:E,splitters:L}=react.useMemo(()=>m?pe(m):{panes:[],splitters:[]},[m]);if(!m)return null;let S=()=>jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[E.map(f=>{let v=x===f.paneId;return jsxRuntime.jsx("div",{style:{position:"absolute",left:v?"0%":`${f.left}%`,top:v?"0%":`${f.top}%`,width:v?"100%":`${f.width}%`,height:v?"100%":`${f.height}%`,overflow:"hidden",zIndex:v?20:1,display:x&&!v?"none":"block",padding:v?"0px":`${t/2}px`,boxSizing:"border-box"},children:n(f.paneId)},f.paneId)}),!x&&L.map(f=>jsxRuntime.jsx(St,{splitter:f,resizerSize:t,snapThreshold:R,containerRef:d},f.id))]});if(e===void 0){let f=i!==null&&i===s,v=D=>{c(D),d.current=D;},w=`zeugma-dashboard-root ${f?"zeugma-dashboard-dismiss-active":""} ${z?a.dashboardLocked||"zeugma-dashboard-locked":""}`.trim();return jsxRuntime.jsx("div",{ref:v,className:w,style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:S()})}return jsxRuntime.jsx("div",{ref:d,style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:S()})};var et="zeugma-height:",Tt="default-pane";function zt(e){try{let t=localStorage.getItem(et+e);if(t!==null){let o=Number(t);if(Number.isFinite(o)&&o>0)return o}}catch{}return null}function je(e,t){try{localStorage.setItem(et+e,String(Math.round(t)));}catch{}}var tt=({children:e,active:t=true,height:o,onHeightChange:r,minHeight:n=100,maxHeight:i=1/0,persist:s,localStorageKey:c,resizerHeight:x=6,className:y,resizerClassName:z})=>{let a=s?c||Tt:null,R=()=>{let w=(a?zt(a):null)??o??400;return we(w,n,i)},[m,d]=react.useState(R),E=react.useRef(null),L=a?m:o??m,S=react.useRef(o);react.useEffect(()=>{if(o!==void 0&&o!==S.current){let w=we(o,n,i);d(w),a&&je(a,w);}S.current=o;},[o,n,i,a]);let f=react.useCallback(()=>i,[i]),v=react.useCallback(w=>{w.preventDefault();let D=w.clientY,u=L,b=f(),X=w.currentTarget,N=nt(E.current),k=N?N.scrollTop:0,Z=D,I=null,C=(g,A)=>{let W=A-k,M=g-D+W,H=we(u+M,n,b);return E.current&&(E.current.style.height=`${H}px`),H},Y=()=>{if(!N)return;let g=N===document.documentElement||N===document.body?{top:0,bottom:window.innerHeight}:N.getBoundingClientRect(),A=40,W=10,O=0;Z>g.bottom-A?O=Math.min(1,(Z-(g.bottom-A))/A)*W:Z<g.top+A&&(O=-Math.min(1,(g.top+A-Z)/A)*W),O!==0&&(N.scrollTop+=O,C(Z,N.scrollTop)),I=requestAnimationFrame(Y);};I=requestAnimationFrame(Y),Se({cursor:"row-resize",resizerEl:X,onMove:g=>{Z=g.clientY,N&&C(Z,N.scrollTop);},onEnd:()=>{I!==null&&cancelAnimationFrame(I);let g=u;E.current&&(g=E.current.getBoundingClientRect().height),g=we(g,n,b),d(g),r&&r(g),a&&je(a,g);}});},[L,n,f,r,a]);return t?jsxRuntime.jsxs("div",{ref:E,className:`zeugma-resizable-container ${y||""}`.trim(),style:{height:`${L}px`,position:"relative",overflow:"hidden",boxSizing:"border-box"},children:[jsxRuntime.jsx("div",{style:{height:`calc(100% - ${x}px)`,overflow:"hidden"},children:e}),jsxRuntime.jsx("div",{className:`zeugma-resizable-handle ${z||""}`.trim(),style:{height:`${x}px`,cursor:"row-resize",position:"relative",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:v,role:"separator","aria-orientation":"horizontal","aria-valuenow":Math.round(L),"aria-valuemin":n,"aria-valuemax":i===1/0?void 0:i})]}):jsxRuntime.jsx("div",{className:`zeugma-resizable-container disabled ${y||""}`.trim(),style:{height:"100%",position:"relative",overflow:"hidden",boxSizing:"border-box"},children:jsxRuntime.jsx("div",{style:{height:"100%",overflow:"hidden"},children:e})})};function we(e,t,o){return Math.max(t,Math.min(o,e))}function nt(e){if(typeof window>"u"||!e)return null;let t=e.parentElement;if(!t)return document.documentElement;let r=window.getComputedStyle(t).overflowY;return r==="auto"||r==="scroll"?t:nt(t)}var Ee=react.createContext(null);var $t={top:{position:"absolute",top:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},left:{position:"absolute",top:"25%",left:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:"25%",right:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"},full:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:20,pointerEvents:"auto",cursor:"not-allowed"}},Zt={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},center:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"},full:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"}},$e=({id:e,position:t,activeClassName:o})=>{let{setNodeRef:r,isOver:n}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:r,style:$t[t]}),n&&jsxRuntime.jsx("div",{className:o,style:Zt[t]})]})},At=({id:e,children:t,style:o,locked:r=false})=>{let{layout:n,activeId:i,classNames:s,fullscreenPaneId:c,onRemove:x,onFullscreenChange:y,locked:z}=G(),{removePane:a,updatePaneMetadata:R}=Te(),m=react.useMemo(()=>B(n,e),[n,e]),d=m?.metadata,E=m?.locked??false,L=r||E,S=z||L,f=z||L,v=i!==null&&i!==e&&!f,{attributes:w,listeners:D,setNodeRef:u,isDragging:b}=core.useDraggable({id:e,disabled:S}),X=i===e||b,N=c===e,k=react.useMemo(()=>({isDragging:X,isFullscreen:N,toggleFullscreen:()=>y?.(N?null:e),remove:()=>{N&&y?.(null),x?x(e):a(e);},metadata:d,updateMetadata:C=>{R(e,C);},locked:S}),[X,N,y,e,x,a,d,R,S]),Z=react.useMemo(()=>S?{disabled:true}:{...D,...w},[D,w,S]),I=`${s.pane||""} ${L?s.paneLocked||"zeugma-pane-locked":""}`.trim();return jsxRuntime.jsx(Ee.Provider,{value:Z,children:jsxRuntime.jsxs("div",{ref:u,className:I,style:{position:"relative",width:"100%",height:"100%",...o},children:[t(k),v&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(C=>jsxRuntime.jsx($e,{id:`drop-${C}-${e}`,position:C,activeClassName:s.dropPreview},C)),jsxRuntime.jsx($e,{id:`drop-center-${e}`,position:"center",activeClassName:s.swapPreview})]}),i!==null&&i!==e&&f&&jsxRuntime.jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:jsxRuntime.jsx($e,{id:`drop-locked-${e}`,position:"full",activeClassName:s.lockedPreview||"zeugma-locked-preview"})})]})})};var Ft=({children:e,className:t,style:o})=>{let r=react.useContext(Ee);if(!r)throw new Error("<DragHandle> must be used inside a <Pane>");let{disabled:n,...i}=r;return jsxRuntime.jsx("div",{className:t,style:{cursor:n?"default":"grab",userSelect:n?"auto":"none",touchAction:n?"auto":"none",...o},...n?{}:i,children:e})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=at;exports.DEFAULT_RESIZER_SIZE=Xt;exports.DEFAULT_SNAP_THRESHOLD=st;exports.DragHandle=Ft;exports.Pane=At;exports.PaneTree=wt;exports.ResizableContainer=tt;exports.Zeugma=vt;exports.addPane=Be;exports.createDragSession=Se;exports.findPane=B;exports.removePane=ae;exports.splitPane=ue;exports.swapPanes=ze;exports.updatePaneLock=Pe;exports.updatePaneMetadata=he;exports.updateSplitPercentage=te;exports.useResizer=Ce;exports.useZeugmaActions=Te;exports.useZeugmaState=G;//# sourceMappingURL=index.cjs.map
6
+ `,document.head.appendChild(n),t.setAttribute("data-resizing","true");let s=a=>{r(a);},i=()=>{document.body.classList.remove("zeugma-resizing"),t.removeAttribute("data-resizing");let a=document.getElementById("zeugma-global-cursor-style");a&&a.remove(),document.removeEventListener("pointermove",s),document.removeEventListener("pointerup",i),o();};document.addEventListener("pointermove",s),document.addEventListener("pointerup",i);}function Ge({containerRef:e,isRow:t,direction:r,splitPercentage:o,resizerSize:n,snapThreshold:s,layout:i,currentNode:a,onLayoutChange:l,onResizeStart:y,onResizeEnd:D,parentLeft:c,parentTop:x,parentWidth:T,parentHeight:v}){let{onResizeStart:R,onResize:E,onResizeEnd:L,minSplitPercentage:p=5,maxSplitPercentage:b=95,locked:f=false}=oe();return en.useCallback(z=>{if(f)return;z.preventDefault();let A=e.current;if(!A)return;y&&y(),R&&R(a);let I=A.getBoundingClientRect(),V=z.clientX,w=z.clientY,K=o,h=z.currentTarget,F=I.left+I.width*(c/100),Y=I.top+I.height*(x/100),O=I.width*(T/100),m=I.height*(v/100),_=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(N=>N!==h&&N.getAttribute("data-direction")===r).map(N=>{let d=N.getBoundingClientRect();return t?d.left+d.width/2:d.top+d.height/2}),k=K;Oe({cursor:t?"col-resize":"row-resize",resizerEl:h,onMove:N=>{let d=t?(N.clientX-V)/O*100:(N.clientY-w)/m*100,B=K+d,ae=t?F+(O-n)*(B/100)+n/2:Y+(m-n)*(B/100)+n/2,W=1/0,ee=null;for(let j of _){let u=Math.abs(ae-j);u<s&&u<W&&(W=u,ee=j);}let le=B;ee!==null&&(le=t?(ee-n/2-F)/(O-n)*100:(ee-n/2-Y)/(m-n)*100);let fe=Math.max(p,Math.min(b,le));k=fe;let me=ve(i,a,fe);if(me){let{panes:j,splitters:u}=se(me),S=e.current;if(S){for(let P of j)S.style.setProperty(`--pane-left-${P.paneId}`,`${P.left}%`),S.style.setProperty(`--pane-top-${P.paneId}`,`${P.top}%`),S.style.setProperty(`--pane-width-${P.paneId}`,`${P.width}%`),S.style.setProperty(`--pane-height-${P.paneId}`,`${P.height}%`);for(let P of u)S.style.setProperty(`--splitter-pos-${P.id}`,`${P.direction==="row"?P.left:P.top}%`);}}E&&E(a,fe);},onEnd:()=>{let N=ve(i,a,k),d=e.current;if(d){let{panes:B,splitters:ae}=se(N);for(let W of B)d.style.removeProperty(`--pane-left-${W.paneId}`),d.style.removeProperty(`--pane-top-${W.paneId}`),d.style.removeProperty(`--pane-width-${W.paneId}`),d.style.removeProperty(`--pane-height-${W.paneId}`);for(let W of ae)d.style.removeProperty(`--splitter-pos-${W.id}`);}l(N),D&&D(),L&&L(a,k);}});},[e,t,r,o,n,s,i,a,l,y,D,R,E,L,p,b,c,x,T,v])}var on=({splitter:e,resizerSize:t,snapThreshold:r,containerRef:o})=>{let{layout:n,onLayoutChange:s,classNames:i,locked:a}=oe(),[l,y]=en.useState(false),{currentNode:D,direction:c,left:x,top:T,width:v,height:R,parentLeft:E,parentTop:L,parentWidth:p,parentHeight:b}=e,f=c==="row",z=Ge({containerRef:o,isRow:f,direction:c,splitPercentage:D.splitPercentage,resizerSize:t,snapThreshold:r,layout:n,currentNode:D,onLayoutChange:s,onResizeStart:()=>y(true),onResizeEnd:()=>y(false),parentLeft:E,parentTop:L,parentWidth:p,parentHeight:b}),A=f?{position:"absolute",left:`calc(var(--splitter-pos-${e.id}, ${x}%) - ${t/2}px)`,top:`calc(${T}% + ${t/2}px)`,width:`${t}px`,height:`calc(${R}% - ${t}px)`,cursor:a?"default":"col-resize",pointerEvents:a?"none":"auto",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box"}:{position:"absolute",left:`calc(${x}% + ${t/2}px)`,top:`calc(var(--splitter-pos-${e.id}, ${T}%) - ${t/2}px)`,width:`calc(${v}% - ${t}px)`,height:`${t}px`,cursor:a?"default":"row-resize",pointerEvents:a?"none":"auto",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box"};return jsxRuntime.jsx("div",{className:`zeugma-resizer ${i.resizer||""}`.trim(),"data-direction":c,"data-resizing":l||void 0,style:A,onPointerDown:z,role:"separator","aria-valuenow":D.splitPercentage,"aria-valuemin":5,"aria-valuemax":95})},sn=en__default.default.memo(({paneId:e,renderPane:t})=>jsxRuntime.jsx(jsxRuntime.Fragment,{children:t(e)}),(e,t)=>e.paneId===t.paneId&&e.renderPane===t.renderPane),an=({tree:e,resizerSize:t=4,snapThreshold:r})=>{let{layout:o,renderPane:n,activeId:s,dismissIntentId:i,setContainerRef:a,fullscreenPaneId:l,snapThreshold:y,locked:D,classNames:c}=oe(),x=r!==void 0?r:y??8,T=e!==void 0?e:o,v=en.useRef(null),{panes:R,splitters:E}=en.useMemo(()=>T?se(T):{panes:[],splitters:[]},[T]);if(!T)return null;let L=()=>jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[R.map(p=>{let b=l===p.paneId;return jsxRuntime.jsx("div",{style:{position:"absolute",left:b?"0%":`var(--pane-left-${p.paneId}, ${p.left}%)`,top:b?"0%":`var(--pane-top-${p.paneId}, ${p.top}%)`,width:b?"100%":`var(--pane-width-${p.paneId}, ${p.width}%)`,height:b?"100%":`var(--pane-height-${p.paneId}, ${p.height}%)`,overflow:"hidden",zIndex:b?20:1,display:l&&!b?"none":"block",padding:b?"0px":`${t/2}px`,boxSizing:"border-box"},children:jsxRuntime.jsx(sn,{paneId:p.paneId,renderPane:n})},p.paneId)}),!l&&E.map(p=>jsxRuntime.jsx(on,{splitter:p,resizerSize:t,snapThreshold:x,containerRef:v},p.id))]});if(e===void 0){let p=s!==null&&s===i,b=z=>{a(z),v.current=z;},f=`zeugma-dashboard-root ${p?"zeugma-dashboard-dismiss-active":""} ${D?c.dashboardLocked||"zeugma-dashboard-locked":""}`.trim();return jsxRuntime.jsx("div",{ref:b,className:f,style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:L()})}return jsxRuntime.jsx("div",{ref:v,style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:L()})};var ht="zeugma-height:",dn="default-pane";function pn(e){try{let t=localStorage.getItem(ht+e);if(t!==null){let r=Number(t);if(Number.isFinite(r)&&r>0)return r}}catch{}return null}function vt(e,t){try{localStorage.setItem(ht+e,String(Math.round(t)));}catch{}}var Pt=({children:e,active:t=true,height:r,onHeightChange:o,minHeight:n=100,maxHeight:s=1/0,persist:i,localStorageKey:a,resizerHeight:l=6,className:y,resizerClassName:D})=>{let c=i?a||dn:null,x=()=>{let f=(c?pn(c):null)??r??400;return Ve(f,n,s)},[T,v]=en.useState(x),R=en.useRef(null),E=c?T:r??T,L=en.useRef(r);en.useEffect(()=>{if(r!==void 0&&r!==L.current){let f=Ve(r,n,s);v(f),c&&vt(c,f);}L.current=r;},[r,n,s,c]);let p=en.useCallback(()=>s,[s]),b=en.useCallback(f=>{f.preventDefault();let z=f.clientY,A=E,I=p(),V=f.currentTarget,w=yt(R.current),K=w?w.scrollTop:0,h=z,F=null,Y=(m,$)=>{let _=$-K,N=m-z+_,d=Ve(A+N,n,I);return R.current&&(R.current.style.height=`${d}px`),d},O=()=>{if(!w)return;let m=w===document.documentElement||w===document.body?{top:0,bottom:window.innerHeight}:w.getBoundingClientRect(),$=40,_=10,k=0;h>m.bottom-$?k=Math.min(1,(h-(m.bottom-$))/$)*_:h<m.top+$&&(k=-Math.min(1,(m.top+$-h)/$)*_),k!==0&&(w.scrollTop+=k,Y(h,w.scrollTop)),F=requestAnimationFrame(O);};F=requestAnimationFrame(O),Oe({cursor:"row-resize",resizerEl:V,onMove:m=>{h=m.clientY,w&&Y(h,w.scrollTop);},onEnd:()=>{F!==null&&cancelAnimationFrame(F);let m=A;R.current&&(m=R.current.getBoundingClientRect().height),m=Ve(m,n,I),v(m),o&&o(m),c&&vt(c,m);}});},[E,n,p,o,c]);return t?jsxRuntime.jsxs("div",{ref:R,className:`zeugma-resizable-container ${y||""}`.trim(),style:{height:`${E}px`,position:"relative",overflow:"hidden",boxSizing:"border-box"},children:[jsxRuntime.jsx("div",{style:{height:`calc(100% - ${l}px)`,overflow:"hidden"},children:e}),jsxRuntime.jsx("div",{className:`zeugma-resizable-handle ${D||""}`.trim(),style:{height:`${l}px`,cursor:"row-resize",position:"relative",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:b,role:"separator","aria-orientation":"horizontal","aria-valuenow":Math.round(E),"aria-valuemin":n,"aria-valuemax":s===1/0?void 0:s})]}):jsxRuntime.jsx("div",{className:`zeugma-resizable-container disabled ${y||""}`.trim(),style:{height:"100%",position:"relative",overflow:"hidden",boxSizing:"border-box"},children:jsxRuntime.jsx("div",{style:{height:"100%",overflow:"hidden"},children:e})})};function Ve(e,t,r){return Math.max(t,Math.min(r,e))}function yt(e){if(typeof window>"u"||!e)return null;let t=e.parentElement;if(!t)return document.documentElement;let o=window.getComputedStyle(t).overflowY;return o==="auto"||o==="scroll"?t:yt(t)}var Ue=en.createContext(null);var yn={top:{position:"absolute",top:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:"25%",width:"50%",height:"25%",zIndex:20,pointerEvents:"auto"},left:{position:"absolute",top:"25%",left:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:"25%",right:0,width:"25%",height:"50%",zIndex:20,pointerEvents:"auto"},full:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:20,pointerEvents:"auto",cursor:"not-allowed"}},Tn={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:21,pointerEvents:"none",boxSizing:"border-box"},full:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:21,pointerEvents:"none",boxSizing:"border-box"}},Tt=({id:e,position:t,activeClassName:r})=>{let{setNodeRef:o,isOver:n}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:o,style:yn[t]}),n&&jsxRuntime.jsx("div",{className:r,style:Tn[t]})]})},xn=({id:e,children:t,style:r,locked:o=false})=>{let{layout:n,activeId:s,classNames:i,fullscreenPaneId:a,onFullscreenChange:l,locked:y}=oe(),{removePane:D,updateTabMetadata:c,selectTab:x,removeTab:T}=nt(),v=en.useContext($e);if(!v)throw new Error("Pane must be used within a Zeugma provider");let{registerPortalTarget:R}=v,E=en.useMemo(()=>q(n,e),[n,e]),L=E?.id??e,p=E?.tabs??[e],b=E?.activeTabId??e,f=E?.tabsMetadata,z=f?.[e],A=E?.locked??false,I=o||A,V=y||I,w=y||I,K=s!==null&&s!==e&&(!p.includes(s)||p.length>1)&&!w,{attributes:h,listeners:F,setNodeRef:Y}=core.useDraggable({id:e,disabled:V}),O=s!==null&&p.includes(s),m=a===e,$=en.useCallback(()=>jsxRuntime.jsx("div",{id:`zeugma-tab-target-${b}`,className:"zeugma-tab-content-wrapper",style:{height:"100%",width:"100%"}}),[b]);en.useEffect(()=>{let d=document.getElementById(`zeugma-tab-target-${b}`);return R(b,d),()=>{R(b,null);}},[b,R]);let _=en.useMemo(()=>({isDragging:O,isFullscreen:m,toggleFullscreen:()=>l?.(m?null:e),remove:()=>{m&&l?.(null),D(L);},metadata:z,updateMetadata:d=>{c(e,d);},locked:V,tabs:p,activeTabId:b,selectTab:d=>x(L,d),removeTab:d=>{m&&d===b&&l?.(null),T(d);},tabsMetadata:f,updateTabMetadata:(d,B)=>{c(d,B);},renderActiveTab:$}),[O,m,l,e,T,z,c,V,p,b,x,L,f,$]),k=en.useMemo(()=>V?{disabled:true}:{...F,...h},[F,h,V]),N=`${i.pane||""} ${I?i.paneLocked||"zeugma-pane-locked":""}`.trim();return jsxRuntime.jsx(Ue.Provider,{value:k,children:jsxRuntime.jsxs("div",{ref:Y,className:N,style:{position:"relative",width:"100%",height:"100%",...r},children:[t(_),K&&jsxRuntime.jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:["top","bottom","left","right"].map(d=>jsxRuntime.jsx(Tt,{id:`drop-${d}-${e}`,position:d,activeClassName:i.dropPreview},d))}),s!==null&&s!==e&&w&&jsxRuntime.jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:jsxRuntime.jsx(Tt,{id:`drop-locked-${e}`,position:"full",activeClassName:i.lockedPreview||"zeugma-locked-preview"})})]})})};var Dn=({children:e,className:t,style:r})=>{let o=en.useContext(Ue);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");let{disabled:n,...s}=o;return jsxRuntime.jsx("div",{className:t,style:{cursor:n?"default":"grab",userSelect:n?"auto":"none",touchAction:n?"auto":"none",...r},...n?{}:s,children:e})};var Nn=({id:e,locked:t=false,children:r,className:o,style:n})=>{let{locked:s}=oe(),i=t||s,{attributes:a,listeners:l,setNodeRef:y,isDragging:D}=core.useDraggable({id:`tab-header-${e}`,disabled:i}),{setNodeRef:c,isOver:x}=core.useDroppable({id:`tab-drop-${e}`,disabled:i});return jsxRuntime.jsx("div",{ref:v=>{y(v),c(v);},className:o,style:{display:"inline-flex",cursor:i?"default":"grab",...n},...i?{}:l,...i?{}:a,children:r({isDragging:D,isOver:x})})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=Zt;exports.DEFAULT_RESIZER_SIZE=An;exports.DEFAULT_SNAP_THRESHOLD=Ht;exports.DragHandle=Dn;exports.Pane=xn;exports.PaneTree=an;exports.ResizableContainer=Pt;exports.Tab=Nn;exports.Zeugma=Kt;exports.addPane=it;exports.computeLayout=se;exports.createDragSession=Oe;exports.findPane=q;exports.generateUniqueId=ie;exports.mergeTab=at;exports.moveTab=lt;exports.removePane=be;exports.removeTab=de;exports.selectTab=Ze;exports.splitPane=ye;exports.updatePaneLock=He;exports.updateSplitPercentage=ve;exports.updateTabMetadata=ke;exports.useResizer=Ge;exports.useZeugma=At;//# sourceMappingURL=index.cjs.map
7
7
  //# sourceMappingURL=index.cjs.map