react-zeugma 1.4.0 → 2.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 +19 -19
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +97 -37
- package/dist/index.d.ts +97 -37
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -16,81 +16,128 @@ interface PaneNode {
|
|
|
16
16
|
type TreeNode = SplitNode | PaneNode;
|
|
17
17
|
|
|
18
18
|
interface ZeugmaClassNames {
|
|
19
|
+
/** CSS class applied to the outer container div of each `<Pane>`. */
|
|
19
20
|
pane?: string;
|
|
21
|
+
/** CSS class applied to drop zone indicators when hovering over layout edges to split a pane. */
|
|
20
22
|
dropPreview?: string;
|
|
23
|
+
/** CSS class applied to the drop zone indicator when hovering over the center of a pane to swap. */
|
|
21
24
|
swapPreview?: string;
|
|
25
|
+
/** CSS class applied to the custom cursor-following drag preview portal wrapper. */
|
|
22
26
|
dragOverlay?: string;
|
|
27
|
+
/** CSS class applied to the drag-to-resize split bar handles. */
|
|
23
28
|
resizer?: string;
|
|
29
|
+
/** CSS class applied to the background dismiss zone indicator during a drag-out dismiss gesture. */
|
|
24
30
|
dismissPreview?: string;
|
|
25
31
|
}
|
|
32
|
+
interface ZeugmaProps {
|
|
33
|
+
/** The layout tree model (TreeNode) defining pane organization and split percentages. Set to null for empty layout. */
|
|
34
|
+
layout: TreeNode | null;
|
|
35
|
+
/** Callback triggered when the layout changes via drag-and-drop actions, splits, swaps, or resizes. */
|
|
36
|
+
onChange: (newLayout: TreeNode | null) => void;
|
|
37
|
+
/** Render function mapping unique pane IDs to React elements. Usually renders a <Pane> wrapper. */
|
|
38
|
+
renderPane: (paneId: string) => ReactNode;
|
|
39
|
+
/** Custom overlay renderer function used to customize the cursor-following drag preview for an active pane. */
|
|
40
|
+
renderDragOverlay?: (activeId: string) => ReactNode;
|
|
41
|
+
/** Optional CSS class name mapping overrides for custom styles of components like panes, drop/swap previews, overlays, etc. */
|
|
42
|
+
classNames?: ZeugmaClassNames;
|
|
43
|
+
/** The ID of the pane that is currently taking up the full dashboard area. Null if no pane is fullscreen. */
|
|
44
|
+
fullscreenPaneId?: string | null;
|
|
45
|
+
/** Callback triggered when a pane is toggled to/from fullscreen mode. Passes the active fullscreen paneId or null. */
|
|
46
|
+
onFullscreenChange?: (paneId: string | null) => void;
|
|
47
|
+
/** Callback triggered when a pane is removed from the dashboard layout tree. */
|
|
48
|
+
onRemove?: (paneId: string) => void;
|
|
49
|
+
/** Minimum pixel distance that a user must drag a pane handle before dragging triggers. Defaults to 8. */
|
|
50
|
+
dragActivationDistance?: number;
|
|
51
|
+
/** Threshold value in pixels for snapping layout resizing handles to adjacent edges. Defaults to 8. */
|
|
52
|
+
snapThreshold?: number;
|
|
53
|
+
/** Callback triggered when dragging starts for a pane. */
|
|
54
|
+
onDragStart?: (activeId: string) => void;
|
|
55
|
+
/** Callback triggered when dragging ends, providing details on target pane and drop action (split or swap). */
|
|
56
|
+
onDragEnd?: (activeId: string, overId: string | null, dropAction: {
|
|
57
|
+
type: 'split' | 'swap';
|
|
58
|
+
direction?: SplitDirection;
|
|
59
|
+
position?: 'top' | 'bottom' | 'left' | 'right' | 'center';
|
|
60
|
+
} | null) => void;
|
|
61
|
+
/** Callback triggered when the user starts dragging a resizing handle between split panes. */
|
|
62
|
+
onResizeStart?: (currentNode: SplitNode) => void;
|
|
63
|
+
/** Callback triggered continuously while the user is dragging a resizing handle. Passes the new split percentage. */
|
|
64
|
+
onResize?: (currentNode: SplitNode, percentage: number) => void;
|
|
65
|
+
/** Callback triggered when the user stops dragging a resizing handle. Passes the final split percentage. */
|
|
66
|
+
onResizeEnd?: (currentNode: SplitNode, percentage: number) => void;
|
|
67
|
+
/** Minimum split percentage allowed when resizing split panes. Defaults to 5. */
|
|
68
|
+
minSplitPercentage?: number;
|
|
69
|
+
/** Maximum split percentage allowed when resizing split panes. Defaults to 95. */
|
|
70
|
+
maxSplitPercentage?: number;
|
|
71
|
+
/** Whether dragging a pane far enough outside the container triggers a drag-out/dismiss action. Defaults to false. */
|
|
72
|
+
enableDragToDismiss?: boolean;
|
|
73
|
+
/** The threshold in pixels beyond the container boundaries required to activate the drag-out/dismiss action. */
|
|
74
|
+
dismissThreshold?: number;
|
|
75
|
+
/** Callback triggered when the drag-out/dismiss intent changes (active pane ID or null when drag returns inside bounds). */
|
|
76
|
+
onDismissIntentChange?: (paneId: string | null) => void;
|
|
77
|
+
/** Child nodes nested inside the Zeugma context, usually containing a <PaneTree> or similar layout viewer. */
|
|
78
|
+
children: ReactNode;
|
|
79
|
+
}
|
|
26
80
|
/**
|
|
27
81
|
* State context — holds reactive values that change during runtime.
|
|
28
82
|
* All consumers of this context will re-render when any of these values change.
|
|
29
83
|
*/
|
|
30
|
-
interface
|
|
84
|
+
interface ZeugmaStateValue {
|
|
85
|
+
/** The current active layout tree structure, or null if empty. */
|
|
31
86
|
layout: TreeNode | null;
|
|
87
|
+
/** Callback to update the layout tree. */
|
|
32
88
|
onLayoutChange: (newLayout: TreeNode | null) => void;
|
|
89
|
+
/** Renders the inner content of a pane given its unique ID. */
|
|
33
90
|
renderPane: (paneId: string) => ReactNode;
|
|
91
|
+
/** The ID of the pane currently being dragged, or null. */
|
|
34
92
|
activeId: string | null;
|
|
93
|
+
/** The ID of the pane currently targeted for dismiss/drag-out, or null. */
|
|
35
94
|
dismissIntentId: string | null;
|
|
95
|
+
/** Ref setter to measure and track the dashboard root container element. */
|
|
36
96
|
setContainerRef: (element: HTMLElement | null) => void;
|
|
97
|
+
/** The ID of the pane currently zoomed to fullscreen, or null. */
|
|
37
98
|
fullscreenPaneId: string | null;
|
|
99
|
+
/** Normalized or overridden CSS classes for custom layout styling. */
|
|
38
100
|
classNames: ZeugmaClassNames;
|
|
101
|
+
/** Callback triggered when a pane is closed/removed from the dashboard. */
|
|
39
102
|
onRemove?: (paneId: string) => void;
|
|
103
|
+
/** Callback triggered to toggle fullscreen status for a pane. */
|
|
40
104
|
onFullscreenChange?: (paneId: string | null) => void;
|
|
105
|
+
/** Threshold in pixels to snap layout resizers to adjacent edges. */
|
|
41
106
|
snapThreshold?: number;
|
|
107
|
+
/** Callback triggered when a split pane starts being resized. */
|
|
42
108
|
onResizeStart?: (currentNode: SplitNode) => void;
|
|
109
|
+
/** Callback triggered continuously during a split pane resize. */
|
|
43
110
|
onResize?: (currentNode: SplitNode, percentage: number) => void;
|
|
111
|
+
/** Callback triggered when a split pane resize action is completed. */
|
|
44
112
|
onResizeEnd?: (currentNode: SplitNode, percentage: number) => void;
|
|
113
|
+
/** Minimum split percentage allowed when resizing. */
|
|
45
114
|
minSplitPercentage?: number;
|
|
115
|
+
/** Maximum split percentage allowed when resizing. */
|
|
46
116
|
maxSplitPercentage?: number;
|
|
47
117
|
}
|
|
48
118
|
/**
|
|
49
119
|
* Actions context — holds stable dispatch functions with permanent identity.
|
|
50
120
|
* Consumers of only this context will never re-render from layout/drag state changes.
|
|
51
121
|
*/
|
|
52
|
-
interface
|
|
122
|
+
interface ZeugmaActionsValue {
|
|
123
|
+
/** Removes the specified pane from the layout tree and collapses its parent split. */
|
|
53
124
|
removePane: (paneId: string) => void;
|
|
125
|
+
/** Appends/inserts a pane at the bottom-rightmost leaf of the layout tree. */
|
|
54
126
|
addPane: (paneId: string) => void;
|
|
127
|
+
/** Swaps the positions of two panes in the layout tree. */
|
|
55
128
|
swapPanes: (paneIdA: string, paneIdB: string) => void;
|
|
129
|
+
/** Splits a target pane with a new pane in the specified direction and side. */
|
|
56
130
|
splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void;
|
|
131
|
+
/** Updates the split percentage of a specific split branch node. */
|
|
57
132
|
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
|
|
133
|
+
/** Stable callback to update metadata for a specific pane. */
|
|
58
134
|
updatePaneMetadata: (paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
|
|
59
135
|
}
|
|
60
136
|
|
|
61
|
-
|
|
62
|
-
declare const
|
|
63
|
-
/** Returns only stable action dispatchers. Consumers of this hook never re-render from state changes. */
|
|
64
|
-
declare const useDashboardActions: () => DashboardActionsValue;
|
|
137
|
+
declare const useZeugmaState: () => ZeugmaStateValue;
|
|
138
|
+
declare const useZeugmaActions: () => ZeugmaActionsValue;
|
|
65
139
|
|
|
66
|
-
|
|
67
|
-
layout: TreeNode | null;
|
|
68
|
-
onChange: (newLayout: TreeNode | null) => void;
|
|
69
|
-
renderPane: (paneId: string) => ReactNode;
|
|
70
|
-
renderDragOverlay?: (activeId: string) => ReactNode;
|
|
71
|
-
classNames?: ZeugmaClassNames;
|
|
72
|
-
fullscreenPaneId?: string | null;
|
|
73
|
-
onFullscreenChange?: (paneId: string | null) => void;
|
|
74
|
-
onRemove?: (paneId: string) => void;
|
|
75
|
-
dragActivationDistance?: number;
|
|
76
|
-
snapThreshold?: number;
|
|
77
|
-
onDragStart?: (activeId: string) => void;
|
|
78
|
-
onDragEnd?: (activeId: string, overId: string | null, dropAction: {
|
|
79
|
-
type: 'split' | 'swap';
|
|
80
|
-
direction?: SplitDirection;
|
|
81
|
-
position?: 'top' | 'bottom' | 'left' | 'right' | 'center';
|
|
82
|
-
} | null) => void;
|
|
83
|
-
onResizeStart?: (currentNode: SplitNode) => void;
|
|
84
|
-
onResize?: (currentNode: SplitNode, percentage: number) => void;
|
|
85
|
-
onResizeEnd?: (currentNode: SplitNode, percentage: number) => void;
|
|
86
|
-
minSplitPercentage?: number;
|
|
87
|
-
maxSplitPercentage?: number;
|
|
88
|
-
enableDragToDismiss?: boolean;
|
|
89
|
-
dismissThreshold?: number;
|
|
90
|
-
onDismissIntentChange?: (paneId: string | null) => void;
|
|
91
|
-
children: ReactNode;
|
|
92
|
-
}
|
|
93
|
-
declare const DashboardProvider: React.FC<DashboardProviderProps>;
|
|
140
|
+
declare const Zeugma: React.FC<ZeugmaProps>;
|
|
94
141
|
|
|
95
142
|
interface UseResizerProps {
|
|
96
143
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
@@ -108,10 +155,11 @@ interface UseResizerProps {
|
|
|
108
155
|
declare function useResizer({ containerRef, isRow, direction, splitPercentage, resizerSize, snapThreshold, layout, currentNode, onLayoutChange, onResizeStart: localOnResizeStart, onResizeEnd: localOnResizeEnd, }: UseResizerProps): (e: React.PointerEvent<HTMLDivElement>) => void;
|
|
109
156
|
|
|
110
157
|
interface PaneTreeProps {
|
|
158
|
+
/** The layout subtree node to render. If not specified, defaults to the root layout tree from the Zeugma context. */
|
|
111
159
|
tree?: TreeNode | null;
|
|
112
|
-
/** Size of the resizer in pixels (default 4) */
|
|
160
|
+
/** Size/thickness of the split handle resizer bars in pixels (default 4). */
|
|
113
161
|
resizerSize?: number;
|
|
114
|
-
/** Threshold in pixels to snap to adjacent
|
|
162
|
+
/** Threshold distance in pixels to snap layout resizers to adjacent edges (default 8). */
|
|
115
163
|
snapThreshold?: number;
|
|
116
164
|
}
|
|
117
165
|
declare const PaneTree: React.FC<PaneTreeProps>;
|
|
@@ -142,24 +190,36 @@ interface ResizableContainerProps {
|
|
|
142
190
|
declare const ResizableContainer: React.FC<ResizableContainerProps>;
|
|
143
191
|
|
|
144
192
|
interface PaneRenderProps {
|
|
193
|
+
/** True if the pane is actively being dragged. */
|
|
145
194
|
isDragging: boolean;
|
|
195
|
+
/** True if the pane currently occupies the fullscreen view. */
|
|
146
196
|
isFullscreen: boolean;
|
|
197
|
+
/** Toggles the pane to and from fullscreen/zoomed mode. */
|
|
147
198
|
toggleFullscreen: () => void;
|
|
199
|
+
/** Closes and removes the pane from the layout tree. */
|
|
148
200
|
remove: () => void;
|
|
201
|
+
/** The metadata values associated with this pane, or undefined. */
|
|
149
202
|
metadata: Record<string, unknown> | undefined;
|
|
203
|
+
/** Updates the metadata of this pane using an updater function. */
|
|
150
204
|
updateMetadata: (updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
|
|
151
205
|
}
|
|
152
206
|
|
|
153
207
|
interface PaneProps {
|
|
208
|
+
/** The unique ID of the pane, matching a `paneId` in the layout tree schema. */
|
|
154
209
|
id: string;
|
|
210
|
+
/** Render prop function providing pane state (isDragging, isFullscreen, etc.) and handlers. */
|
|
155
211
|
children: (props: PaneRenderProps) => React.ReactNode;
|
|
212
|
+
/** Optional inline CSS styles applied to the pane outer container. */
|
|
156
213
|
style?: React.CSSProperties;
|
|
157
214
|
}
|
|
158
215
|
declare const Pane: React.FC<PaneProps>;
|
|
159
216
|
|
|
160
217
|
interface DragHandleProps {
|
|
218
|
+
/** The children elements that will trigger dragging when held and dragged. */
|
|
161
219
|
children: React.ReactNode;
|
|
220
|
+
/** Custom CSS class applied to the drag handle element. */
|
|
162
221
|
className?: string;
|
|
222
|
+
/** Optional inline CSS styles applied to the drag handle. */
|
|
163
223
|
style?: React.CSSProperties;
|
|
164
224
|
}
|
|
165
225
|
declare const DragHandle: React.FC<DragHandleProps>;
|
|
@@ -226,4 +286,4 @@ interface DragSessionConfig {
|
|
|
226
286
|
}
|
|
227
287
|
declare function createDragSession({ cursor, resizerEl, onMove, onEnd }: DragSessionConfig): void;
|
|
228
288
|
|
|
229
|
-
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD,
|
|
289
|
+
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, DragHandle, type DragHandleProps, type DragSessionConfig, Pane, type PaneNode, type PaneProps, type PaneRenderProps, PaneTree, ResizableContainer, type ResizableContainerProps, type SplitDirection, type SplitNode, type TreeNode, Zeugma, type ZeugmaActionsValue, type ZeugmaClassNames, type ZeugmaProps, type ZeugmaStateValue, addPane, createDragSession, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useResizer, useZeugmaActions, useZeugmaState };
|
package/dist/index.d.ts
CHANGED
|
@@ -16,81 +16,128 @@ interface PaneNode {
|
|
|
16
16
|
type TreeNode = SplitNode | PaneNode;
|
|
17
17
|
|
|
18
18
|
interface ZeugmaClassNames {
|
|
19
|
+
/** CSS class applied to the outer container div of each `<Pane>`. */
|
|
19
20
|
pane?: string;
|
|
21
|
+
/** CSS class applied to drop zone indicators when hovering over layout edges to split a pane. */
|
|
20
22
|
dropPreview?: string;
|
|
23
|
+
/** CSS class applied to the drop zone indicator when hovering over the center of a pane to swap. */
|
|
21
24
|
swapPreview?: string;
|
|
25
|
+
/** CSS class applied to the custom cursor-following drag preview portal wrapper. */
|
|
22
26
|
dragOverlay?: string;
|
|
27
|
+
/** CSS class applied to the drag-to-resize split bar handles. */
|
|
23
28
|
resizer?: string;
|
|
29
|
+
/** CSS class applied to the background dismiss zone indicator during a drag-out dismiss gesture. */
|
|
24
30
|
dismissPreview?: string;
|
|
25
31
|
}
|
|
32
|
+
interface ZeugmaProps {
|
|
33
|
+
/** The layout tree model (TreeNode) defining pane organization and split percentages. Set to null for empty layout. */
|
|
34
|
+
layout: TreeNode | null;
|
|
35
|
+
/** Callback triggered when the layout changes via drag-and-drop actions, splits, swaps, or resizes. */
|
|
36
|
+
onChange: (newLayout: TreeNode | null) => void;
|
|
37
|
+
/** Render function mapping unique pane IDs to React elements. Usually renders a <Pane> wrapper. */
|
|
38
|
+
renderPane: (paneId: string) => ReactNode;
|
|
39
|
+
/** Custom overlay renderer function used to customize the cursor-following drag preview for an active pane. */
|
|
40
|
+
renderDragOverlay?: (activeId: string) => ReactNode;
|
|
41
|
+
/** Optional CSS class name mapping overrides for custom styles of components like panes, drop/swap previews, overlays, etc. */
|
|
42
|
+
classNames?: ZeugmaClassNames;
|
|
43
|
+
/** The ID of the pane that is currently taking up the full dashboard area. Null if no pane is fullscreen. */
|
|
44
|
+
fullscreenPaneId?: string | null;
|
|
45
|
+
/** Callback triggered when a pane is toggled to/from fullscreen mode. Passes the active fullscreen paneId or null. */
|
|
46
|
+
onFullscreenChange?: (paneId: string | null) => void;
|
|
47
|
+
/** Callback triggered when a pane is removed from the dashboard layout tree. */
|
|
48
|
+
onRemove?: (paneId: string) => void;
|
|
49
|
+
/** Minimum pixel distance that a user must drag a pane handle before dragging triggers. Defaults to 8. */
|
|
50
|
+
dragActivationDistance?: number;
|
|
51
|
+
/** Threshold value in pixels for snapping layout resizing handles to adjacent edges. Defaults to 8. */
|
|
52
|
+
snapThreshold?: number;
|
|
53
|
+
/** Callback triggered when dragging starts for a pane. */
|
|
54
|
+
onDragStart?: (activeId: string) => void;
|
|
55
|
+
/** Callback triggered when dragging ends, providing details on target pane and drop action (split or swap). */
|
|
56
|
+
onDragEnd?: (activeId: string, overId: string | null, dropAction: {
|
|
57
|
+
type: 'split' | 'swap';
|
|
58
|
+
direction?: SplitDirection;
|
|
59
|
+
position?: 'top' | 'bottom' | 'left' | 'right' | 'center';
|
|
60
|
+
} | null) => void;
|
|
61
|
+
/** Callback triggered when the user starts dragging a resizing handle between split panes. */
|
|
62
|
+
onResizeStart?: (currentNode: SplitNode) => void;
|
|
63
|
+
/** Callback triggered continuously while the user is dragging a resizing handle. Passes the new split percentage. */
|
|
64
|
+
onResize?: (currentNode: SplitNode, percentage: number) => void;
|
|
65
|
+
/** Callback triggered when the user stops dragging a resizing handle. Passes the final split percentage. */
|
|
66
|
+
onResizeEnd?: (currentNode: SplitNode, percentage: number) => void;
|
|
67
|
+
/** Minimum split percentage allowed when resizing split panes. Defaults to 5. */
|
|
68
|
+
minSplitPercentage?: number;
|
|
69
|
+
/** Maximum split percentage allowed when resizing split panes. Defaults to 95. */
|
|
70
|
+
maxSplitPercentage?: number;
|
|
71
|
+
/** Whether dragging a pane far enough outside the container triggers a drag-out/dismiss action. Defaults to false. */
|
|
72
|
+
enableDragToDismiss?: boolean;
|
|
73
|
+
/** The threshold in pixels beyond the container boundaries required to activate the drag-out/dismiss action. */
|
|
74
|
+
dismissThreshold?: number;
|
|
75
|
+
/** Callback triggered when the drag-out/dismiss intent changes (active pane ID or null when drag returns inside bounds). */
|
|
76
|
+
onDismissIntentChange?: (paneId: string | null) => void;
|
|
77
|
+
/** Child nodes nested inside the Zeugma context, usually containing a <PaneTree> or similar layout viewer. */
|
|
78
|
+
children: ReactNode;
|
|
79
|
+
}
|
|
26
80
|
/**
|
|
27
81
|
* State context — holds reactive values that change during runtime.
|
|
28
82
|
* All consumers of this context will re-render when any of these values change.
|
|
29
83
|
*/
|
|
30
|
-
interface
|
|
84
|
+
interface ZeugmaStateValue {
|
|
85
|
+
/** The current active layout tree structure, or null if empty. */
|
|
31
86
|
layout: TreeNode | null;
|
|
87
|
+
/** Callback to update the layout tree. */
|
|
32
88
|
onLayoutChange: (newLayout: TreeNode | null) => void;
|
|
89
|
+
/** Renders the inner content of a pane given its unique ID. */
|
|
33
90
|
renderPane: (paneId: string) => ReactNode;
|
|
91
|
+
/** The ID of the pane currently being dragged, or null. */
|
|
34
92
|
activeId: string | null;
|
|
93
|
+
/** The ID of the pane currently targeted for dismiss/drag-out, or null. */
|
|
35
94
|
dismissIntentId: string | null;
|
|
95
|
+
/** Ref setter to measure and track the dashboard root container element. */
|
|
36
96
|
setContainerRef: (element: HTMLElement | null) => void;
|
|
97
|
+
/** The ID of the pane currently zoomed to fullscreen, or null. */
|
|
37
98
|
fullscreenPaneId: string | null;
|
|
99
|
+
/** Normalized or overridden CSS classes for custom layout styling. */
|
|
38
100
|
classNames: ZeugmaClassNames;
|
|
101
|
+
/** Callback triggered when a pane is closed/removed from the dashboard. */
|
|
39
102
|
onRemove?: (paneId: string) => void;
|
|
103
|
+
/** Callback triggered to toggle fullscreen status for a pane. */
|
|
40
104
|
onFullscreenChange?: (paneId: string | null) => void;
|
|
105
|
+
/** Threshold in pixels to snap layout resizers to adjacent edges. */
|
|
41
106
|
snapThreshold?: number;
|
|
107
|
+
/** Callback triggered when a split pane starts being resized. */
|
|
42
108
|
onResizeStart?: (currentNode: SplitNode) => void;
|
|
109
|
+
/** Callback triggered continuously during a split pane resize. */
|
|
43
110
|
onResize?: (currentNode: SplitNode, percentage: number) => void;
|
|
111
|
+
/** Callback triggered when a split pane resize action is completed. */
|
|
44
112
|
onResizeEnd?: (currentNode: SplitNode, percentage: number) => void;
|
|
113
|
+
/** Minimum split percentage allowed when resizing. */
|
|
45
114
|
minSplitPercentage?: number;
|
|
115
|
+
/** Maximum split percentage allowed when resizing. */
|
|
46
116
|
maxSplitPercentage?: number;
|
|
47
117
|
}
|
|
48
118
|
/**
|
|
49
119
|
* Actions context — holds stable dispatch functions with permanent identity.
|
|
50
120
|
* Consumers of only this context will never re-render from layout/drag state changes.
|
|
51
121
|
*/
|
|
52
|
-
interface
|
|
122
|
+
interface ZeugmaActionsValue {
|
|
123
|
+
/** Removes the specified pane from the layout tree and collapses its parent split. */
|
|
53
124
|
removePane: (paneId: string) => void;
|
|
125
|
+
/** Appends/inserts a pane at the bottom-rightmost leaf of the layout tree. */
|
|
54
126
|
addPane: (paneId: string) => void;
|
|
127
|
+
/** Swaps the positions of two panes in the layout tree. */
|
|
55
128
|
swapPanes: (paneIdA: string, paneIdB: string) => void;
|
|
129
|
+
/** Splits a target pane with a new pane in the specified direction and side. */
|
|
56
130
|
splitPane: (targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string) => void;
|
|
131
|
+
/** Updates the split percentage of a specific split branch node. */
|
|
57
132
|
updateSplitPercentage: (currentNode: SplitNode, percentage: number) => void;
|
|
133
|
+
/** Stable callback to update metadata for a specific pane. */
|
|
58
134
|
updatePaneMetadata: (paneId: string, updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
|
|
59
135
|
}
|
|
60
136
|
|
|
61
|
-
|
|
62
|
-
declare const
|
|
63
|
-
/** Returns only stable action dispatchers. Consumers of this hook never re-render from state changes. */
|
|
64
|
-
declare const useDashboardActions: () => DashboardActionsValue;
|
|
137
|
+
declare const useZeugmaState: () => ZeugmaStateValue;
|
|
138
|
+
declare const useZeugmaActions: () => ZeugmaActionsValue;
|
|
65
139
|
|
|
66
|
-
|
|
67
|
-
layout: TreeNode | null;
|
|
68
|
-
onChange: (newLayout: TreeNode | null) => void;
|
|
69
|
-
renderPane: (paneId: string) => ReactNode;
|
|
70
|
-
renderDragOverlay?: (activeId: string) => ReactNode;
|
|
71
|
-
classNames?: ZeugmaClassNames;
|
|
72
|
-
fullscreenPaneId?: string | null;
|
|
73
|
-
onFullscreenChange?: (paneId: string | null) => void;
|
|
74
|
-
onRemove?: (paneId: string) => void;
|
|
75
|
-
dragActivationDistance?: number;
|
|
76
|
-
snapThreshold?: number;
|
|
77
|
-
onDragStart?: (activeId: string) => void;
|
|
78
|
-
onDragEnd?: (activeId: string, overId: string | null, dropAction: {
|
|
79
|
-
type: 'split' | 'swap';
|
|
80
|
-
direction?: SplitDirection;
|
|
81
|
-
position?: 'top' | 'bottom' | 'left' | 'right' | 'center';
|
|
82
|
-
} | null) => void;
|
|
83
|
-
onResizeStart?: (currentNode: SplitNode) => void;
|
|
84
|
-
onResize?: (currentNode: SplitNode, percentage: number) => void;
|
|
85
|
-
onResizeEnd?: (currentNode: SplitNode, percentage: number) => void;
|
|
86
|
-
minSplitPercentage?: number;
|
|
87
|
-
maxSplitPercentage?: number;
|
|
88
|
-
enableDragToDismiss?: boolean;
|
|
89
|
-
dismissThreshold?: number;
|
|
90
|
-
onDismissIntentChange?: (paneId: string | null) => void;
|
|
91
|
-
children: ReactNode;
|
|
92
|
-
}
|
|
93
|
-
declare const DashboardProvider: React.FC<DashboardProviderProps>;
|
|
140
|
+
declare const Zeugma: React.FC<ZeugmaProps>;
|
|
94
141
|
|
|
95
142
|
interface UseResizerProps {
|
|
96
143
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
@@ -108,10 +155,11 @@ interface UseResizerProps {
|
|
|
108
155
|
declare function useResizer({ containerRef, isRow, direction, splitPercentage, resizerSize, snapThreshold, layout, currentNode, onLayoutChange, onResizeStart: localOnResizeStart, onResizeEnd: localOnResizeEnd, }: UseResizerProps): (e: React.PointerEvent<HTMLDivElement>) => void;
|
|
109
156
|
|
|
110
157
|
interface PaneTreeProps {
|
|
158
|
+
/** The layout subtree node to render. If not specified, defaults to the root layout tree from the Zeugma context. */
|
|
111
159
|
tree?: TreeNode | null;
|
|
112
|
-
/** Size of the resizer in pixels (default 4) */
|
|
160
|
+
/** Size/thickness of the split handle resizer bars in pixels (default 4). */
|
|
113
161
|
resizerSize?: number;
|
|
114
|
-
/** Threshold in pixels to snap to adjacent
|
|
162
|
+
/** Threshold distance in pixels to snap layout resizers to adjacent edges (default 8). */
|
|
115
163
|
snapThreshold?: number;
|
|
116
164
|
}
|
|
117
165
|
declare const PaneTree: React.FC<PaneTreeProps>;
|
|
@@ -142,24 +190,36 @@ interface ResizableContainerProps {
|
|
|
142
190
|
declare const ResizableContainer: React.FC<ResizableContainerProps>;
|
|
143
191
|
|
|
144
192
|
interface PaneRenderProps {
|
|
193
|
+
/** True if the pane is actively being dragged. */
|
|
145
194
|
isDragging: boolean;
|
|
195
|
+
/** True if the pane currently occupies the fullscreen view. */
|
|
146
196
|
isFullscreen: boolean;
|
|
197
|
+
/** Toggles the pane to and from fullscreen/zoomed mode. */
|
|
147
198
|
toggleFullscreen: () => void;
|
|
199
|
+
/** Closes and removes the pane from the layout tree. */
|
|
148
200
|
remove: () => void;
|
|
201
|
+
/** The metadata values associated with this pane, or undefined. */
|
|
149
202
|
metadata: Record<string, unknown> | undefined;
|
|
203
|
+
/** Updates the metadata of this pane using an updater function. */
|
|
150
204
|
updateMetadata: (updater: (current: Record<string, unknown> | undefined) => Record<string, unknown> | undefined) => void;
|
|
151
205
|
}
|
|
152
206
|
|
|
153
207
|
interface PaneProps {
|
|
208
|
+
/** The unique ID of the pane, matching a `paneId` in the layout tree schema. */
|
|
154
209
|
id: string;
|
|
210
|
+
/** Render prop function providing pane state (isDragging, isFullscreen, etc.) and handlers. */
|
|
155
211
|
children: (props: PaneRenderProps) => React.ReactNode;
|
|
212
|
+
/** Optional inline CSS styles applied to the pane outer container. */
|
|
156
213
|
style?: React.CSSProperties;
|
|
157
214
|
}
|
|
158
215
|
declare const Pane: React.FC<PaneProps>;
|
|
159
216
|
|
|
160
217
|
interface DragHandleProps {
|
|
218
|
+
/** The children elements that will trigger dragging when held and dragged. */
|
|
161
219
|
children: React.ReactNode;
|
|
220
|
+
/** Custom CSS class applied to the drag handle element. */
|
|
162
221
|
className?: string;
|
|
222
|
+
/** Optional inline CSS styles applied to the drag handle. */
|
|
163
223
|
style?: React.CSSProperties;
|
|
164
224
|
}
|
|
165
225
|
declare const DragHandle: React.FC<DragHandleProps>;
|
|
@@ -226,4 +286,4 @@ interface DragSessionConfig {
|
|
|
226
286
|
}
|
|
227
287
|
declare function createDragSession({ cursor, resizerEl, onMove, onEnd }: DragSessionConfig): void;
|
|
228
288
|
|
|
229
|
-
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD,
|
|
289
|
+
export { DEFAULT_DRAG_ACTIVATION_DISTANCE, DEFAULT_RESIZER_SIZE, DEFAULT_SNAP_THRESHOLD, DragHandle, type DragHandleProps, type DragSessionConfig, Pane, type PaneNode, type PaneProps, type PaneRenderProps, PaneTree, ResizableContainer, type ResizableContainerProps, type SplitDirection, type SplitNode, type TreeNode, Zeugma, type ZeugmaActionsValue, type ZeugmaClassNames, type ZeugmaProps, type ZeugmaStateValue, addPane, createDragSession, findPane, removePane, splitPane, splitRoot, swapPanes, updatePaneMetadata, updateSplitPercentage, useResizer, useZeugmaActions, useZeugmaState };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {createContext,useContext,useState,useRef,useCallback,useMemo,useEffect}from'react';import {useSensors,useSensor,DndContext,pointerWithin,useDraggable,PointerSensor,TouchSensor,useDroppable}from'@dnd-kit/core';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var
|
|
1
|
+
import {createContext,useContext,useState,useRef,useCallback,useMemo,useEffect}from'react';import {useSensors,useSensor,DndContext,pointerWithin,useDraggable,PointerSensor,TouchSensor,useDroppable}from'@dnd-kit/core';import {jsx,jsxs,Fragment}from'react/jsx-runtime';var se=createContext(void 0),ae=createContext(void 0);var G=()=>{let e=useContext(se);if(!e)throw new Error("useZeugmaState must be used within a Zeugma provider");return e},Pe=()=>{let e=useContext(ae);if(!e)throw new Error("useZeugmaActions must be used within a Zeugma provider");return e};function k(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=k(e.first,t),r=k(e.second,t);return n===null?r:r===null?n:{...e,first:n,second:r}}function re(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,c=r==="left"||r==="top";return {type:"split",direction:n,first:c?i:e,second:c?e:i,splitPercentage:50}}return e}return {...e,first:re(e.first,t,n,r,o)||e.first,second:re(e.second,t,n,r,o)||e.second}}function xe(e,t,n){if(e===null)return null;let r=V(e,t),o=V(e,n);if(!r||!o)return e;function i(c){return c.type==="pane"?c.paneId===t?{...o}:c.paneId===n?{...r}:c:{...c,first:i(c.first),second:i(c.second)}}return i(e)}function Fe(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 Q(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:Q(e.first,t,n)||e.first,second:Q(e.second,t,n)||e.second}:e}function $e(e,t,n){let r=V(e,t)??{type:"pane",paneId:t},o=k(e,t);if(o===null)return {...r};let i=n==="left"||n==="right"?"row":"column",c=n==="left"||n==="top",u={...r};return {type:"split",direction:i,first:c?u:o,second:c?o:u,splitPercentage:50}}function V(e,t){return e===null?null:e.type==="pane"?e.paneId===t?e:null:V(e.first,t)??V(e.second,t)}function le(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:le(e.first,t,n)??e.first,second:le(e.second,t,n)??e.second}}var et=8,tt=8,Xt=4;var _e=({activeId:e,render:t,className:n})=>{let r=useRef(null);return 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)},[]),jsx("div",{ref:r,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})};var ce=class extends PointerSensor{static activators=[{eventName:"onPointerDown",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]},ue=class extends TouchSensor{static activators=[{eventName:"onTouchStart",handler:({nativeEvent:t})=>!t.target?.closest(".drag-cancel")}]};var ut=({layout:e,onChange:t,renderPane:n,renderDragOverlay:r,classNames:o={},fullscreenPaneId:i=null,onFullscreenChange:c,onRemove:u,dragActivationDistance:w=8,snapThreshold:P=8,onDragStart:N,onDragEnd:s,onResizeStart:x,onResize:g,onResizeEnd:y,minSplitPercentage:z=5,maxSplitPercentage:D=95,enableDragToDismiss:S=false,dismissThreshold:E=60,onDismissIntentChange:H,children:I})=>{let[d,m]=useState(e),[ee,te]=useState(e);e!==ee&&(te(e),m(e));let[b,T]=useState(null),[h,M]=useState(null),X=useRef(null),$=useRef(null),v=useCallback(l=>{X.current=l;},[]),C=useCallback(l=>n(l),[n]),A=useMemo(()=>o,[o.pane,o.dropPreview,o.swapPreview,o.dragOverlay,o.resizer,o.dismissPreview]),_=useSensors(useSensor(ce,{activationConstraint:{distance:w}}),useSensor(ue,{activationConstraint:{delay:250,tolerance:5}})),B=l=>{let f=l.active.id.toString();T(f),S&&X.current?$.current=X.current.getBoundingClientRect():$.current=null,N&&N(f);},K=l=>{if(!S)return;let f=l.active.id.toString(),a=$.current;if(!a){h!==null&&(M(null),H?.(null));return}let p=l.activatorEvent,F=null,Z=null;if(p instanceof MouseEvent||p instanceof PointerEvent)F=p.clientX+l.delta.x,Z=p.clientY+l.delta.y;else if(typeof TouchEvent<"u"&&p instanceof TouchEvent){let R=p.touches[0]||p.changedTouches[0];R&&(F=R.clientX+l.delta.x,Z=R.clientY+l.delta.y);}let Y=0;if(F!==null&&Z!==null){let R=0,L=0;F<a.left?R=a.left-F:F>a.right&&(R=F-a.right),Z<a.top?L=a.top-Z:Z>a.bottom&&(L=Z-a.bottom),Y=Math.sqrt(R*R+L*L);}else {let R=l.active.rect.current.translated;if(R){let L=R.left+R.width/2,q=R.top+R.height/2,J=0,j=0;L<a.left?J=a.left-L:L>a.right&&(J=L-a.right),q<a.top?j=a.top-q:q>a.bottom&&(j=q-a.bottom),Y=Math.sqrt(J*J+j*j);}}Y>E?h!==f&&(M(f),H?.(f)):h!==null&&(M(null),H?.(null));},ne=l=>{T(null);let{active:f,over:a}=l,p=f.id.toString(),F=S&&h===p;if(M(null),H?.(null),$.current=null,F){u?u(p):he(p),s&&s(p,null,null);return}if(!a){s&&s(p,null,null);return}let Z=a.id.toString(),Y=Z.match(/^drop-root-(left|right|top|bottom)$/);if(Y){let[,W]=Y,oe=$e(d,p,W);m(oe),t(oe),s&&s(p,"root",{type:"split",direction:W==="left"||W==="right"?"row":"column",position:W});return}let be=Z.match(/^drop-center-(.+)$/);if(be){let[,W]=be;if(p!==W){let oe=xe(d,p,W);m(oe),t(oe);}s&&s(p,W,{type:"swap",position:"center"});return}let R=Z.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!R){s&&s(p,null,null);return}let[,L,q]=R;if(p===q){s&&s(p,null,null);return}let J=L==="left"||L==="right"?"row":"column",j=V(d,p)??{type:"pane",paneId:p},je=k(d,p),Ze=re(je,q,J,L,j);m(Ze),t(Ze),s&&s(p,q,{type:"split",direction:J,position:L});},ze=useCallback(l=>{m(l),t(l);},[t]),he=useCallback(l=>{let f=k(d,l);m(f),t(f);},[d,t]),De=useCallback(l=>{let f=Fe(d,l);m(f),t(f);},[d,t]),Ie=useCallback((l,f)=>{let a=xe(d,l,f);m(a),t(a);},[d,t]),Te=useCallback((l,f,a,p)=>{let F=V(d,p)??{type:"pane",paneId:p},Z=k(d,p),Y=re(Z,l,f,a,F);m(Y),t(Y);},[d,t]),Ce=useCallback((l,f)=>{let a=Q(d,l,f);m(a),t(a);},[d,t]),Le=useCallback((l,f)=>{let a=le(d,l,f);m(a),t(a);},[d,t]),Me=useCallback((l,f)=>{let a=Q(d,l,f);m(a),t(a),y&&y(l,f);},[d,t,y]),Je=useMemo(()=>({layout:d,onLayoutChange:ze,renderPane:C,activeId:b,dismissIntentId:h,setContainerRef:v,fullscreenPaneId:i,classNames:A,onRemove:u,onFullscreenChange:c,snapThreshold:P,onResizeStart:x,onResize:g,onResizeEnd:Me,minSplitPercentage:z,maxSplitPercentage:D}),[d,b,h,v,i,A,u,c,P,x,g,z,D,ze,C,Me]),Qe=useMemo(()=>({removePane:he,addPane:De,swapPanes:Ie,splitPane:Te,updateSplitPercentage:Ce,updatePaneMetadata:Le}),[he,De,Ie,Te,Ce,Le]);return jsx(ae.Provider,{value:Qe,children:jsxs(se.Provider,{value:Je,children:[jsx(DndContext,{id:"zeugma-dnd-context",sensors:_,collisionDetection:pointerWithin,onDragStart:B,onDragMove:K,onDragEnd:ne,children:I}),b&&r&&jsx(_e,{activeId:b,render:r,className:`${o.dragOverlay||""} ${b===h?o.dismissPreview||"zeugma-dismiss-preview":""}`.trim()})]})})};var ft={top:{position:"absolute",top:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"32px",zIndex:30,pointerEvents:"auto"},left:{position:"absolute",top:0,bottom:0,left:0,width:"32px",zIndex:30,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"32px",zIndex:30,pointerEvents:"auto"}},mt={top:{position:"absolute",top:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},bottom:{position:"absolute",bottom:0,left:0,right:0,height:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},left:{position:"absolute",top:0,bottom:0,left:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"},right:{position:"absolute",top:0,bottom:0,right:0,width:"50%",zIndex:31,pointerEvents:"none",boxSizing:"border-box"}},gt=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:r,isOver:o}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:r,style:ft[t]}),o&&jsx("div",{className:n,style:mt[t]})]})},Ye=({activeId:e,hasOtherPanes:t,dropPreviewClassName:n})=>!e||!t?null:jsx("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:30,pointerEvents:"none"},children:["top","bottom","left","right"].map(r=>jsx(gt,{id:`drop-root-${r}`,position:r,activeClassName:n},r))});function fe({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=u=>{n(u);},c=()=>{document.body.classList.remove("zeugma-resizing"),t.removeAttribute("data-resizing");let u=document.getElementById("zeugma-global-cursor-style");u&&u.remove(),document.removeEventListener("pointermove",i),document.removeEventListener("pointerup",c),r();};document.addEventListener("pointermove",i),document.addEventListener("pointerup",c);}function we({containerRef:e,isRow:t,direction:n,splitPercentage:r,resizerSize:o,snapThreshold:i,layout:c,currentNode:u,onLayoutChange:w,onResizeStart:P,onResizeEnd:N}){let{onResizeStart:s,onResize:x,onResizeEnd:g,minSplitPercentage:y=5,maxSplitPercentage:z=95}=G();return useCallback(D=>{D.preventDefault();let S=e.current;if(!S)return;P&&P(),s&&s(u);let E=S.getBoundingClientRect(),H=D.clientX,I=D.clientY,d=r,m=D.currentTarget,te=Array.from(document.querySelectorAll('div[role="separator"][data-direction]')).filter(T=>T!==m&&T.getAttribute("data-direction")===n).map(T=>{let h=T.getBoundingClientRect();return t?h.left+h.width/2:h.top+h.height/2}),b=d;fe({cursor:t?"col-resize":"row-resize",resizerEl:m,onMove:T=>{let h=t?(T.clientX-H)/E.width*100:(T.clientY-I)/E.height*100,M=d+h,X=t?E.left+(E.width-o)*(M/100)+o/2:E.top+(E.height-o)*(M/100)+o/2,$=1/0,v=null;for(let K of te){let ne=Math.abs(X-K);ne<i&&ne<$&&($=ne,v=K);}let C=M;v!==null&&(C=t?(v-o/2-E.left)/(E.width-o)*100:(v-o/2-E.top)/(E.height-o)*100);let A=Math.max(y,Math.min(z,C));b=A;let _=S.children[0],B=S.children[S.children.length-1];_&&B&&(_.style.flex=`${A} 1 0%`,B.style.flex=`${100-A} 1 0%`),x&&x(u,A);},onEnd:()=>{let T=Q(c,u,b);w(T),N&&N(),g&&g(u,b);}});},[e,t,n,r,o,i,c,u,w,P,N,s,x,g,y,z])}var Rt=({currentNode:e,resizerSize:t,snapThreshold:n})=>{let{layout:r,onLayoutChange:o,classNames:i}=G(),[c,u]=useState(false),w=useRef(null),{direction:P,first:N,second:s,splitPercentage:x}=e,g=P==="row",y=we({containerRef:w,isRow:g,direction:P,splitPercentage:x,resizerSize:t,snapThreshold:n??8,layout:r,currentNode:e,onLayoutChange:o,onResizeStart:()=>u(true),onResizeEnd:()=>u(false)});return jsxs("div",{ref:w,style:{display:"flex",flexDirection:g?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${x} 1 0%`,overflow:"hidden"},children:jsx(ye,{tree:N,resizerSize:t,snapThreshold:n})}),jsx("div",{className:`zeugma-resizer ${i.resizer||""}`.trim(),"data-direction":P,"data-resizing":c||void 0,style:{width:g?`${t}px`:"100%",height:g?"100%":`${t}px`,cursor:g?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",touchAction:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:y,role:"separator","aria-valuenow":x,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-x} 1 0%`,overflow:"hidden"},children:jsx(ye,{tree:s,resizerSize:t,snapThreshold:n})})]})},ye=({tree:e,resizerSize:t=4,snapThreshold:n})=>{let{layout:r,renderPane:o,activeId:i,dismissIntentId:c,setContainerRef:u,classNames:w,fullscreenPaneId:P,snapThreshold:N}=G(),s=n!==void 0?n:N,x=useMemo(()=>e!==void 0||!i?false:k(r,i)!==null,[e,r,i]);if(P&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:o(P)});let g=e!==void 0?e:r;if(!g)return null;let y=()=>g.type==="pane"?jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:o(g.paneId)}):jsx(Rt,{currentNode:g,resizerSize:t,snapThreshold:s});return e===void 0?jsxs("div",{ref:u,className:`zeugma-dashboard-root ${i!==null&&i===c?"zeugma-dashboard-dismiss-active":""}`.trim(),style:{position:"relative",width:"100%",height:"100%",overflow:"hidden"},children:[y(),jsx(Ye,{activeId:i,hasOtherPanes:x,dropPreviewClassName:w.dropPreview})]}):y()};var qe="zeugma-height:",Et="default-pane";function Nt(e){try{let t=localStorage.getItem(qe+e);if(t!==null){let n=Number(t);if(Number.isFinite(n)&&n>0)return n}}catch{}return null}function Be(e,t){try{localStorage.setItem(qe+e,String(Math.round(t)));}catch{}}var We=({children:e,active:t=true,height:n,onHeightChange:r,minHeight:o=100,maxHeight:i=1/0,persist:c,localStorageKey:u,resizerHeight:w=6,className:P,resizerClassName:N})=>{let s=c?u||Et:null,x=()=>{let I=(s?Nt(s):null)??n??400;return me(I,o,i)},[g,y]=useState(x),z=useRef(null),D=s?g:n??g,S=useRef(n);useEffect(()=>{if(n!==void 0&&n!==S.current){let I=me(n,o,i);y(I),s&&Be(s,I);}S.current=n;},[n,o,i,s]);let E=useCallback(()=>i,[i]),H=useCallback(I=>{I.preventDefault();let d=I.clientY,m=D,ee=E(),te=I.currentTarget,b=Ge(z.current),T=b?b.scrollTop:0,h=d,M=null,X=(v,C)=>{let A=C-T,B=v-d+A,K=me(m+B,o,ee);return z.current&&(z.current.style.height=`${K}px`),K},$=()=>{if(!b)return;let v=b===document.documentElement||b===document.body?{top:0,bottom:window.innerHeight}:b.getBoundingClientRect(),C=40,A=10,_=0;h>v.bottom-C?_=Math.min(1,(h-(v.bottom-C))/C)*A:h<v.top+C&&(_=-Math.min(1,(v.top+C-h)/C)*A),_!==0&&(b.scrollTop+=_,X(h,b.scrollTop)),M=requestAnimationFrame($);};M=requestAnimationFrame($),fe({cursor:"row-resize",resizerEl:te,onMove:v=>{h=v.clientY,b&&X(h,b.scrollTop);},onEnd:()=>{M!==null&&cancelAnimationFrame(M);let v=m;z.current&&(v=z.current.getBoundingClientRect().height),v=me(v,o,ee),y(v),r&&r(v),s&&Be(s,v);}});},[D,o,E,r,s]);return t?jsxs("div",{ref:z,className:`zeugma-resizable-container ${P||""}`.trim(),style:{height:`${D}px`,position:"relative",overflow:"hidden",boxSizing:"border-box"},children:[jsx("div",{style:{height:`calc(100% - ${w}px)`,overflow:"hidden"},children:e}),jsx("div",{className:`zeugma-resizable-handle ${N||""}`.trim(),style:{height:`${w}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(D),"aria-valuemin":o,"aria-valuemax":i===1/0?void 0:i})]}):jsx("div",{className:`zeugma-resizable-container disabled ${P||""}`.trim(),style:{height:"100%",position:"relative",overflow:"hidden",boxSizing:"border-box"},children:jsx("div",{style:{height:"100%",overflow:"hidden"},children:e})})};function me(e,t,n){return Math.max(t,Math.min(n,e))}function Ge(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:Ge(t)}var ve=createContext(null);var Ct={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"}},Lt={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"}},Ke=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:r,isOver:o}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:r,style:Ct[t]}),o&&jsx("div",{className:n,style:Lt[t]})]})},Mt=({id:e,children:t,style:n})=>{let{layout:r,activeId:o,classNames:i,fullscreenPaneId:c,onRemove:u,onFullscreenChange:w}=G(),{removePane:P,updatePaneMetadata:N}=Pe(),s=o!==null&&o!==e,{attributes:x,listeners:g,setNodeRef:y,isDragging:z}=useDraggable({id:e}),D=o===e||z,S=c===e,H=useMemo(()=>V(r,e),[r,e])?.metadata,I=useMemo(()=>({isDragging:D,isFullscreen:S,toggleFullscreen:()=>w?.(S?null:e),remove:()=>{S&&w?.(null),u?u(e):P(e);},metadata:H,updateMetadata:m=>{N(e,m);}}),[D,S,w,e,u,P,H,N]),d=useMemo(()=>({...g,...x}),[g,x]);return jsx(ve.Provider,{value:d,children:jsxs("div",{ref:y,className:i.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(I),s&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(m=>jsx(Ke,{id:`drop-${m}-${e}`,position:m,activeClassName:i.dropPreview},m)),jsx(Ke,{id:`drop-center-${e}`,position:"center",activeClassName:i.swapPreview})]})]})})};var Ht=({children:e,className:t,style:n})=>{let r=useContext(ve);if(!r)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",touchAction:"none",...n},...r,children:e})};export{tt as DEFAULT_DRAG_ACTIVATION_DISTANCE,Xt as DEFAULT_RESIZER_SIZE,et as DEFAULT_SNAP_THRESHOLD,Ht as DragHandle,Mt as Pane,ye as PaneTree,We as ResizableContainer,ut as Zeugma,Fe as addPane,fe as createDragSession,V as findPane,k as removePane,re as splitPane,$e as splitRoot,xe as swapPanes,le as updatePaneMetadata,Q as updateSplitPercentage,we as useResizer,Pe as useZeugmaActions,G as useZeugmaState};//# sourceMappingURL=index.js.map
|
|
7
7
|
//# sourceMappingURL=index.js.map
|