react-zeugma 1.4.1 → 2.1.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 +41 -47
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -41
- package/dist/index.d.ts +97 -41
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ Import the core components and configure the layout state inside your React appl
|
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
43
|
import { useState } from 'react'
|
|
44
|
-
import {
|
|
44
|
+
import { Zeugma, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
|
|
45
45
|
|
|
46
46
|
const initialLayout: TreeNode = {
|
|
47
47
|
type: 'split',
|
|
@@ -81,11 +81,11 @@ export default function Dashboard() {
|
|
|
81
81
|
const [layout, setLayout] = useState<TreeNode | null>(initialLayout)
|
|
82
82
|
|
|
83
83
|
return (
|
|
84
|
-
<
|
|
84
|
+
<Zeugma layout={layout} onChange={setLayout} renderPane={(id) => <MyPane id={id} />}>
|
|
85
85
|
<div className="w-screen h-screen">
|
|
86
86
|
<PaneTree />
|
|
87
87
|
</div>
|
|
88
|
-
</
|
|
88
|
+
</Zeugma>
|
|
89
89
|
)
|
|
90
90
|
}
|
|
91
91
|
```
|
|
@@ -94,35 +94,35 @@ export default function Dashboard() {
|
|
|
94
94
|
|
|
95
95
|
## API Reference
|
|
96
96
|
|
|
97
|
-
### `<
|
|
97
|
+
### `<Zeugma>`
|
|
98
98
|
|
|
99
99
|
The context provider that sets up the drag-and-drop state machine, monitors active drags, and registers layout change notifications.
|
|
100
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`.
|
|
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`. |
|
|
122
122
|
|
|
123
123
|
### `<PaneTree>`
|
|
124
124
|
|
|
125
|
-
Recursively renders the split nodes and pane nodes. Must be placed inside `<
|
|
125
|
+
Recursively renders the split nodes and pane nodes. Must be placed inside `<Zeugma>`.
|
|
126
126
|
|
|
127
127
|
| Prop | Type | Required | Description |
|
|
128
128
|
| ------------- | ------------------ | -------- | ------------------------------------------------------------------- |
|
|
@@ -195,10 +195,6 @@ Swaps the positions of `idA` and `idB` nodes directly inside the tree structure.
|
|
|
195
195
|
|
|
196
196
|
Splits the targeted `targetId` pane inside the tree with `direction` (_row_ / _column_) and type (_left_, _right_, _top_, _bottom_) to insert `paneToAdd`.
|
|
197
197
|
|
|
198
|
-
#### `splitRoot(tree, draggingId, splitType)`
|
|
199
|
-
|
|
200
|
-
Splits the entire dashboard tree at the root, placing the dragged `draggingId` pane on one half and the rest of the layout tree on the other.
|
|
201
|
-
|
|
202
198
|
#### `findPane(tree: TreeNode | null, paneId: string): PaneNode | null`
|
|
203
199
|
|
|
204
200
|
Recursively searches the layout tree and returns the target `PaneNode` if found, or `null` otherwise.
|
|
@@ -210,7 +206,7 @@ Recursively searches the layout tree and returns the target `PaneNode` if found,
|
|
|
210
206
|
Use custom CSS or styling rules to style resizers, dragging states, drop previews, or active nodes by overriding `classNames` in the provider.
|
|
211
207
|
|
|
212
208
|
```tsx
|
|
213
|
-
<
|
|
209
|
+
<Zeugma
|
|
214
210
|
layout={layout}
|
|
215
211
|
onChange={setLayout}
|
|
216
212
|
renderPane={renderPane}
|
|
@@ -225,7 +221,7 @@ Use custom CSS or styling rules to style resizers, dragging states, drop preview
|
|
|
225
221
|
}}
|
|
226
222
|
>
|
|
227
223
|
<PaneTree />
|
|
228
|
-
</
|
|
224
|
+
</Zeugma>
|
|
229
225
|
```
|
|
230
226
|
|
|
231
227
|
---
|
|
@@ -273,12 +269,12 @@ export interface PaneRenderProps {
|
|
|
273
269
|
) => void
|
|
274
270
|
}
|
|
275
271
|
|
|
276
|
-
export interface
|
|
272
|
+
export interface ZeugmaStateValue {
|
|
277
273
|
layout: TreeNode | null
|
|
278
274
|
onLayoutChange: (newLayout: TreeNode | null) => void
|
|
279
275
|
renderPane: (paneId: string) => ReactNode
|
|
280
276
|
activeId: string | null
|
|
281
|
-
|
|
277
|
+
dismissIntentId: string | null
|
|
282
278
|
setContainerRef: (element: HTMLElement | null) => void
|
|
283
279
|
fullscreenPaneId: string | null
|
|
284
280
|
classNames: ZeugmaClassNames
|
|
@@ -292,7 +288,7 @@ export interface DashboardStateValue {
|
|
|
292
288
|
maxSplitPercentage?: number
|
|
293
289
|
}
|
|
294
290
|
|
|
295
|
-
export interface
|
|
291
|
+
export interface ZeugmaActionsValue {
|
|
296
292
|
removePane: (paneId: string) => void
|
|
297
293
|
addPane: (paneId: string) => void
|
|
298
294
|
swapPanes: (paneIdA: string, paneIdB: string) => void
|
|
@@ -361,7 +357,7 @@ export type TreeNode = SplitNode | PaneNode
|
|
|
361
357
|
|
|
362
358
|
## 2. Core Components
|
|
363
359
|
|
|
364
|
-
### `<
|
|
360
|
+
### `<Zeugma>`
|
|
365
361
|
|
|
366
362
|
The root context provider. It handles the drag-and-drop event loop and coordinates the layout state.
|
|
367
363
|
|
|
@@ -380,7 +376,7 @@ The root context provider. It handles the drag-and-drop event loop and coordinat
|
|
|
380
376
|
- `dragOutThreshold?: number` — (Optional) Distance in pixels outside the container boundaries required to activate drag-out mode. Defaults to `60`.
|
|
381
377
|
- `onDragOutChange?: (activeId: string | null) => void` — (Optional) Callback triggered when the drag-out state changes.
|
|
382
378
|
- `onDragStart?: (activeId: string) => void` — (Optional) Callback triggered when dragging starts on a pane.
|
|
383
|
-
- `onDragEnd?: (activeId: string, overId: string | null, dropAction: any) => void` — (Optional) Callback triggered when dragging ends
|
|
379
|
+
- `onDragEnd?: (activeId: string, overId: string | null, dropAction: any) => void` — (Optional) Callback triggered when dragging ends, providing swap or split details.
|
|
384
380
|
- `onResizeStart?: (currentNode: SplitNode) => void` — (Optional) Callback triggered when resizing starts.
|
|
385
381
|
- `onResize?: (currentNode: SplitNode, percentage: number) => void` — (Optional) Callback triggered during resizing.
|
|
386
382
|
- `onResizeEnd?: (currentNode: SplitNode, percentage: number) => void` — (Optional) Callback triggered when resizing ends.
|
|
@@ -389,7 +385,7 @@ The root context provider. It handles the drag-and-drop event loop and coordinat
|
|
|
389
385
|
|
|
390
386
|
### `<PaneTree>`
|
|
391
387
|
|
|
392
|
-
Recursively renders the split nodes and pane nodes. Must be placed inside `<
|
|
388
|
+
Recursively renders the split nodes and pane nodes. Must be placed inside `<Zeugma>`.
|
|
393
389
|
|
|
394
390
|
#### Props
|
|
395
391
|
|
|
@@ -456,8 +452,6 @@ Import these helpers from `react-zeugma` to manipulate the tree layout programma
|
|
|
456
452
|
Removes a pane from the tree and collapses the leftover sibling split node.
|
|
457
453
|
- **`splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null`**
|
|
458
454
|
Splits a specific target pane by nesting it under a new `SplitNode` along with a new pane.
|
|
459
|
-
- **`splitRoot(tree: TreeNode | null, draggingId: string, splitType: 'left' | 'right' | 'top' | 'bottom'): TreeNode | null`**
|
|
460
|
-
Splits the entire dashboard tree at the root, placing the dragged pane on one half and the remaining layout tree on the other.
|
|
461
455
|
- **`swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null`**
|
|
462
456
|
Swaps the positions of two panes in the tree.
|
|
463
457
|
- **`updatePaneMetadata(tree: TreeNode | null, paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined): TreeNode | null`**
|
|
@@ -467,10 +461,10 @@ Import these helpers from `react-zeugma` to manipulate the tree layout programma
|
|
|
467
461
|
|
|
468
462
|
Alternatively, you can consume state and mutation helpers directly from the context hooks:
|
|
469
463
|
|
|
470
|
-
- **`
|
|
471
|
-
- **`
|
|
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.
|
|
472
466
|
|
|
473
|
-
The actions returned by `
|
|
467
|
+
The actions returned by `useZeugmaActions()` are:
|
|
474
468
|
|
|
475
469
|
- **`removePane(paneId: string) => void`**
|
|
476
470
|
- **`addPane(paneId: string) => void`**
|
|
@@ -485,7 +479,7 @@ The actions returned by `useDashboardActions()` are:
|
|
|
485
479
|
|
|
486
480
|
```tsx
|
|
487
481
|
import { useState } from 'react'
|
|
488
|
-
import {
|
|
482
|
+
import { Zeugma, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
|
|
489
483
|
|
|
490
484
|
const initialLayout: TreeNode = {
|
|
491
485
|
type: 'split',
|
|
@@ -526,7 +520,7 @@ export default function App() {
|
|
|
526
520
|
}
|
|
527
521
|
|
|
528
522
|
return (
|
|
529
|
-
<
|
|
523
|
+
<Zeugma
|
|
530
524
|
layout={layout}
|
|
531
525
|
onChange={setLayout}
|
|
532
526
|
renderPane={(id) => <CustomPane id={id} />}
|
|
@@ -537,7 +531,7 @@ export default function App() {
|
|
|
537
531
|
<div style={{ width: '100vw', height: '100vh' }}>
|
|
538
532
|
<PaneTree />
|
|
539
533
|
</div>
|
|
540
|
-
</
|
|
534
|
+
</Zeugma>
|
|
541
535
|
)
|
|
542
536
|
}
|
|
543
537
|
```
|
|
@@ -546,7 +540,7 @@ export default function App() {
|
|
|
546
540
|
|
|
547
541
|
## 5. Styling Customization
|
|
548
542
|
|
|
549
|
-
`react-zeugma` is style-agnostic and relies on class name configuration for visual states. Define classes in your styling framework and pass them via the `classNames` prop on `<
|
|
543
|
+
`react-zeugma` is style-agnostic and relies on class name configuration for visual states. Define classes in your styling framework and pass them via the `classNames` prop on `<Zeugma>`:
|
|
550
544
|
|
|
551
545
|
```ts
|
|
552
546
|
interface ZeugmaClassNames {
|
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
|
|
1
|
+
'use strict';var react=require('react'),core=require('@dnd-kit/core'),jsxRuntime=require('react/jsx-runtime');var re=react.createContext(void 0),ie=react.createContext(void 0);var B=()=>{let e=react.useContext(re);if(!e)throw new Error("useZeugmaState must be used within a Zeugma provider");return e},he=()=>{let e=react.useContext(ie);if(!e)throw new Error("useZeugmaActions must be used within a Zeugma provider");return e};function Q(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=Q(e.first,t),r=Q(e.second,t);return n===null?r:r===null?n:{...e,first:n,second:r}}function ne(e,t,n,r,o){if(e===null)return typeof o=="string"?{type:"pane",paneId:o}:o;if(e.type==="pane"){if(e.paneId===t){let i=typeof o=="string"?{type:"pane",paneId:o}:o,u=r==="left"||r==="top";return {type:"split",direction:n,first:u?i:e,second:u?e:i,splitPercentage:50}}return e}return {...e,first:ne(e.first,t,n,r,o)||e.first,second:ne(e.second,t,n,r,o)||e.second}}function be(e,t,n){if(e===null)return null;let r=k(e,t),o=k(e,n);if(!r||!o)return e;function i(u){return u.type==="pane"?u.paneId===t?{...o}:u.paneId===n?{...r}:u:{...u,first:i(u.first),second:i(u.second)}}return i(e)}function He(e,t){if(e===null)return {type:"pane",paneId:t};function n(r,o){return r.type==="pane"?{type:"split",direction:o==="row"?"column":"row",splitPercentage:50,first:r,second:{type:"pane",paneId:t}}:{...r,second:n(r.second,r.direction)}}return n(e,null)}function G(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:G(e.first,t,n)||e.first,second:G(e.second,t,n)||e.second}:e}function k(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:k(e.first,t)??k(e.second,t)}function se(e,t,n){if(e===null)return null;if(e.type==="pane"){if(e.paneId===t){let r=n(e.metadata);if(r===void 0){let{metadata:o,...i}=e;return i}return {...e,metadata:r}}return e}return {...e,first:se(e.first,t,n)??e.first,second:se(e.second,t,n)??e.second}}var Ge=8,Ke=8,Mt=4;var $e=({activeId:e,render:t,className:n})=>{let r=react.useRef(null);return react.useEffect(()=>{let o=i=>{r.current&&(r.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",o),()=>document.removeEventListener("pointermove",o)},[]),jsxRuntime.jsx("div",{ref:r,className:n,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")}]},le=class extends core.TouchSensor{static activators=[{eventName:"onTouchStart",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]};var it=({layout:e,onChange:t,renderPane:n,renderDragOverlay:r,classNames:o={},fullscreenPaneId:i=null,onFullscreenChange:u,onRemove:p,dragActivationDistance:y=8,snapThreshold:S=8,onDragStart:E,onDragEnd:s,onResizeStart:b,onResize:P,onResizeEnd:L,minSplitPercentage:z=5,maxSplitPercentage:N=95,enableDragToDismiss:w=false,dismissThreshold:R=60,onDismissIntentChange:H,children:D})=>{let[c,m]=react.useState(e),[j,ee]=react.useState(e);e!==j&&(ee(e),m(e));let[h,T]=react.useState(null),[v,C]=react.useState(null),O=react.useRef(null),F=react.useRef(null),g=react.useCallback(l=>{O.current=l;},[]),I=react.useCallback(l=>n(l),[n]),Z=react.useMemo(()=>o,[o.pane,o.dropPreview,o.swapPreview,o.dragOverlay,o.resizer,o.dismissPreview]),_=core.useSensors(core.useSensor(ae,{activationConstraint:{distance:y}}),core.useSensor(le,{activationConstraint:{delay:250,tolerance:5}})),X=l=>{let f=l.active.id.toString();T(f),w&&O.current?F.current=O.current.getBoundingClientRect():F.current=null,E&&E(f);},q=l=>{if(!w)return;let f=l.active.id.toString(),a=F.current;if(!a){v!==null&&(C(null),H?.(null));return}let d=l.activatorEvent,$=null,A=null;if(d instanceof MouseEvent||d instanceof PointerEvent)$=d.clientX+l.delta.x,A=d.clientY+l.delta.y;else if(typeof TouchEvent<"u"&&d instanceof TouchEvent){let x=d.touches[0]||d.changedTouches[0];x&&($=x.clientX+l.delta.x,A=x.clientY+l.delta.y);}let Y=0;if($!==null&&A!==null){let x=0,M=0;$<a.left?x=a.left-$:$>a.right&&(x=$-a.right),A<a.top?M=a.top-A:A>a.bottom&&(M=A-a.bottom),Y=Math.sqrt(x*x+M*M);}else {let x=l.active.rect.current.translated;if(x){let M=x.left+x.width/2,W=x.top+x.height/2,K=0,J=0;M<a.left?K=a.left-M:M>a.right&&(K=M-a.right),W<a.top?J=a.top-W:W>a.bottom&&(J=W-a.bottom),Y=Math.sqrt(K*K+J*J);}}Y>R?v!==f&&(C(f),H?.(f)):v!==null&&(C(null),H?.(null));},te=l=>{T(null);let{active:f,over:a}=l,d=f.id.toString(),$=w&&v===d;if(C(null),H?.(null),F.current=null,$){p?p(d):me(d),s&&s(d,null,null);return}if(!a){s&&s(d,null,null);return}let A=a.id.toString(),Y=A.match(/^drop-center-(.+)$/);if(Y){let[,ve]=Y;if(d!==ve){let Me=be(c,d,ve);m(Me),t(Me);}s&&s(d,ve,{type:"swap",position:"center"});return}let ge=A.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!ge){s&&s(d,null,null);return}let[,x,M]=ge;if(d===M){s&&s(d,null,null);return}let W=x==="left"||x==="right"?"row":"column",K=k(c,d)??{type:"pane",paneId:d},J=Q(c,d),Ce=ne(J,M,W,x,K);m(Ce),t(Ce),s&&s(d,M,{type:"split",direction:W,position:x});},Ee=react.useCallback(l=>{m(l),t(l);},[t]),me=react.useCallback(l=>{let f=Q(c,l);m(f),t(f);},[c,t]),Ne=react.useCallback(l=>{let f=He(c,l);m(f),t(f);},[c,t]),ze=react.useCallback((l,f)=>{let a=be(c,l,f);m(a),t(a);},[c,t]),De=react.useCallback((l,f,a,d)=>{let $=k(c,d)??{type:"pane",paneId:d},A=Q(c,d),Y=ne(A,l,f,a,$);m(Y),t(Y);},[c,t]),Te=react.useCallback((l,f)=>{let a=G(c,l,f);m(a),t(a);},[c,t]),Ie=react.useCallback((l,f)=>{let a=se(c,l,f);m(a),t(a);},[c,t]),Le=react.useCallback((l,f)=>{let a=G(c,l,f);m(a),t(a),L&&L(l,f);},[c,t,L]),qe=react.useMemo(()=>({layout:c,onLayoutChange:Ee,renderPane:I,activeId:h,dismissIntentId:v,setContainerRef:g,fullscreenPaneId:i,classNames:Z,onRemove:p,onFullscreenChange:u,snapThreshold:S,onResizeStart:b,onResize:P,onResizeEnd:Le,minSplitPercentage:z,maxSplitPercentage:N}),[c,h,v,g,i,Z,p,u,S,b,P,z,N,Ee,I,Le]),We=react.useMemo(()=>({removePane:me,addPane:Ne,swapPanes:ze,splitPane:De,updateSplitPercentage:Te,updatePaneMetadata:Ie}),[me,Ne,ze,De,Te,Ie]);return jsxRuntime.jsx(ie.Provider,{value:We,children:jsxRuntime.jsxs(re.Provider,{value:qe,children:[jsxRuntime.jsx(core.DndContext,{id:"zeugma-dnd-context",sensors:_,collisionDetection:core.pointerWithin,onDragStart:X,onDragMove:q,onDragEnd:te,children:D}),h&&r&&jsxRuntime.jsx($e,{activeId:h,render:r,className:`${o.dragOverlay||""} ${h===v?o.dismissPreview||"zeugma-dismiss-preview":""}`.trim()})]})})};function ue({cursor:e,resizerEl:t,onMove:n,onEnd:r}){document.body.classList.add("zeugma-resizing");let o=document.createElement("style");o.id="zeugma-global-cursor-style",o.textContent=`
|
|
2
2
|
* {
|
|
3
3
|
cursor: ${e} !important;
|
|
4
4
|
user-select: none !important;
|
|
5
5
|
}
|
|
6
|
-
`,document.head.appendChild(o),t.setAttribute("data-resizing","true");let i=
|
|
6
|
+
`,document.head.appendChild(o),t.setAttribute("data-resizing","true");let i=p=>{n(p);},u=()=>{document.body.classList.remove("zeugma-resizing"),t.removeAttribute("data-resizing");let p=document.getElementById("zeugma-global-cursor-style");p&&p.remove(),document.removeEventListener("pointermove",i),document.removeEventListener("pointerup",u),r();};document.addEventListener("pointermove",i),document.addEventListener("pointerup",u);}function Se({containerRef:e,isRow:t,direction:n,splitPercentage:r,resizerSize:o,snapThreshold:i,layout:u,currentNode:p,onLayoutChange:y,onResizeStart:S,onResizeEnd:E}){let{onResizeStart:s,onResize:b,onResizeEnd:P,minSplitPercentage:L=5,maxSplitPercentage:z=95}=B();return react.useCallback(N=>{N.preventDefault();let w=e.current;if(!w)return;S&&S(),s&&s(p);let R=w.getBoundingClientRect(),H=N.clientX,D=N.clientY,c=r,m=N.currentTarget,ee=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(T=>T!==m&&T.getAttribute("data-direction")===n).map(T=>{let v=T.getBoundingClientRect();return t?v.left+v.width/2:v.top+v.height/2}),h=c;ue({cursor:t?"col-resize":"row-resize",resizerEl:m,onMove:T=>{let v=t?(T.clientX-H)/R.width*100:(T.clientY-D)/R.height*100,C=c+v,O=t?R.left+(R.width-o)*(C/100)+o/2:R.top+(R.height-o)*(C/100)+o/2,F=1/0,g=null;for(let q of ee){let te=Math.abs(O-q);te<i&&te<F&&(F=te,g=q);}let I=C;g!==null&&(I=t?(g-o/2-R.left)/(R.width-o)*100:(g-o/2-R.top)/(R.height-o)*100);let Z=Math.max(L,Math.min(z,I));h=Z;let _=w.children[0],X=w.children[w.children.length-1];_&&X&&(_.style.flex=`${Z} 1 0%`,X.style.flex=`${100-Z} 1 0%`),b&&b(p,Z);},onEnd:()=>{let T=G(u,p,h);y(T),E&&E(),P&&P(p,h);}});},[e,t,n,r,o,i,u,p,y,S,E,s,b,P,L,z])}var ut=({currentNode:e,resizerSize:t,snapThreshold:n})=>{let{layout:r,onLayoutChange:o,classNames:i}=B(),[u,p]=react.useState(false),y=react.useRef(null),{direction:S,first:E,second:s,splitPercentage:b}=e,P=S==="row",L=Se({containerRef:y,isRow:P,direction:S,splitPercentage:b,resizerSize:t,snapThreshold:n??8,layout:r,currentNode:e,onLayoutChange:o,onResizeStart:()=>p(true),onResizeEnd:()=>p(false)});return jsxRuntime.jsxs("div",{ref:y,style:{display:"flex",flexDirection:P?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${b} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(ye,{tree:E,resizerSize:t,snapThreshold:n})}),jsxRuntime.jsx("div",{className:`zeugma-resizer ${i.resizer||""}`.trim(),"data-direction":S,"data-resizing":u||void 0,style:{width:P?`${t}px`:"100%",height:P?"100%":`${t}px`,cursor:P?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:L,role:"separator","aria-valuenow":b,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-b} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(ye,{tree:s,resizerSize:t,snapThreshold:n})})]})},ye=({tree:e,resizerSize:t=4,snapThreshold:n})=>{let{layout:r,renderPane:o,activeId:i,dismissIntentId:u,setContainerRef:p,fullscreenPaneId:y,snapThreshold:S}=B(),E=n!==void 0?n:S;if(y&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:o(y)});let s=e!==void 0?e:r;if(!s)return null;let b=()=>s.type==="pane"?jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:o(s.paneId)}):jsxRuntime.jsx(ut,{currentNode:s,resizerSize:t,snapThreshold:E});return e===void 0?jsxRuntime.jsx("div",{ref:p,className:`zeugma-dashboard-root ${i!==null&&i===u?"zeugma-dashboard-dismiss-active":""}`.trim(),style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:b()}):b()};var Ue="zeugma-height:",mt="default-pane";function gt(e){try{let t=localStorage.getItem(Ue+e);if(t!==null){let n=Number(t);if(Number.isFinite(n)&&n>0)return n}}catch{}return null}function ke(e,t){try{localStorage.setItem(Ue+e,String(Math.round(t)));}catch{}}var Oe=({children:e,active:t=true,height:n,onHeightChange:r,minHeight:o=100,maxHeight:i=1/0,persist:u,localStorageKey:p,resizerHeight:y=6,className:S,resizerClassName:E})=>{let s=u?p||mt:null,b=()=>{let D=(s?gt(s):null)??n??400;return de(D,o,i)},[P,L]=react.useState(b),z=react.useRef(null),N=s?P:n??P,w=react.useRef(n);react.useEffect(()=>{if(n!==void 0&&n!==w.current){let D=de(n,o,i);L(D),s&&ke(s,D);}w.current=n;},[n,o,i,s]);let R=react.useCallback(()=>i,[i]),H=react.useCallback(D=>{D.preventDefault();let c=D.clientY,m=N,j=R(),ee=D.currentTarget,h=Xe(z.current),T=h?h.scrollTop:0,v=c,C=null,O=(g,I)=>{let Z=I-T,X=g-c+Z,q=de(m+X,o,j);return z.current&&(z.current.style.height=`${q}px`),q},F=()=>{if(!h)return;let g=h===document.documentElement||h===document.body?{top:0,bottom:window.innerHeight}:h.getBoundingClientRect(),I=40,Z=10,_=0;v>g.bottom-I?_=Math.min(1,(v-(g.bottom-I))/I)*Z:v<g.top+I&&(_=-Math.min(1,(g.top+I-v)/I)*Z),_!==0&&(h.scrollTop+=_,O(v,h.scrollTop)),C=requestAnimationFrame(F);};C=requestAnimationFrame(F),ue({cursor:"row-resize",resizerEl:ee,onMove:g=>{v=g.clientY,h&&O(v,h.scrollTop);},onEnd:()=>{C!==null&&cancelAnimationFrame(C);let g=m;z.current&&(g=z.current.getBoundingClientRect().height),g=de(g,o,j),L(g),r&&r(g),s&&ke(s,g);}});},[N,o,R,r,s]);return t?jsxRuntime.jsxs("div",{ref:z,className:`zeugma-resizable-container ${S||""}`.trim(),style:{height:`${N}px`,position:"relative",overflow:"hidden",boxSizing:"border-box"},children:[jsxRuntime.jsx("div",{style:{height:`calc(100% - ${y}px)`,overflow:"hidden"},children:e}),jsxRuntime.jsx("div",{className:`zeugma-resizable-handle ${E||""}`.trim(),style:{height:`${y}px`,cursor:"row-resize",position:"relative",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:H,role:"separator","aria-orientation":"horizontal","aria-valuenow":Math.round(N),"aria-valuemin":o,"aria-valuemax":i===1/0?void 0:i})]}):jsxRuntime.jsx("div",{className:`zeugma-resizable-container disabled ${S||""}`.trim(),style:{height:"100%",position:"relative",overflow:"hidden",boxSizing:"border-box"},children:jsxRuntime.jsx("div",{style:{height:"100%",overflow:"hidden"},children:e})})};function de(e,t,n){return Math.max(t,Math.min(n,e))}function Xe(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:Xe(t)}var fe=react.createContext(null);var xt={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"}},St={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"}},Be=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:r,isOver:o}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:r,style:xt[t]}),o&&jsxRuntime.jsx("div",{className:n,style:St[t]})]})},yt=({id:e,children:t,style:n})=>{let{layout:r,activeId:o,classNames:i,fullscreenPaneId:u,onRemove:p,onFullscreenChange:y}=B(),{removePane:S,updatePaneMetadata:E}=he(),s=o!==null&&o!==e,{attributes:b,listeners:P,setNodeRef:L,isDragging:z}=core.useDraggable({id:e}),N=o===e||z,w=u===e,H=react.useMemo(()=>k(r,e),[r,e])?.metadata,D=react.useMemo(()=>({isDragging:N,isFullscreen:w,toggleFullscreen:()=>y?.(w?null:e),remove:()=>{w&&y?.(null),p?p(e):S(e);},metadata:H,updateMetadata:m=>{E(e,m);}}),[N,w,y,e,p,S,H,E]),c=react.useMemo(()=>({...P,...b}),[P,b]);return jsxRuntime.jsx(fe.Provider,{value:c,children:jsxRuntime.jsxs("div",{ref:L,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(D),s&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(m=>jsxRuntime.jsx(Be,{id:`drop-${m}-${e}`,position:m,activeClassName:i.dropPreview},m)),jsxRuntime.jsx(Be,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var Et=({children:e,className:t,style:n})=>{let r=react.useContext(fe);if(!r)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",touchAction:"none",...n},...r,children:e})};exports.DEFAULT_DRAG_ACTIVATION_DISTANCE=Ke;exports.DEFAULT_RESIZER_SIZE=Mt;exports.DEFAULT_SNAP_THRESHOLD=Ge;exports.DragHandle=Et;exports.Pane=yt;exports.PaneTree=ye;exports.ResizableContainer=Oe;exports.Zeugma=it;exports.addPane=He;exports.createDragSession=ue;exports.findPane=k;exports.removePane=Q;exports.splitPane=ne;exports.swapPanes=be;exports.updatePaneMetadata=se;exports.updateSplitPercentage=G;exports.useResizer=Se;exports.useZeugmaActions=he;exports.useZeugmaState=B;//# sourceMappingURL=index.cjs.map
|
|
7
7
|
//# sourceMappingURL=index.cjs.map
|