react-zeugma 0.1.1 → 0.2.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 +175 -64
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -15,128 +15,238 @@ Combines the tree-based, arbitrary splitting of [react-mosaic](https://github.co
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
-
##
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
## Introduction
|
|
19
|
+
|
|
20
|
+
**react-zeugma** is a recursive drag-and-drop dashboard layout engine for React. It combines the tree-based, arbitrary splitting of _react-mosaic_ with the declarative, state-driven API of _react-grid-layout_, built on top of [`@dnd-kit`](https://dndkit.com).
|
|
21
|
+
|
|
22
|
+
> **Headless Design System** — react-zeugma is entirely style-agnostic and relies on your class name configurations for styling visual states. You bring your own CSS/Tailwind rules, and we handle the complex drag-and-drop mechanics, resize handle math, and layout tree calculations.
|
|
23
|
+
|
|
24
|
+
### Core Features
|
|
25
|
+
|
|
26
|
+
- **Recursive Split Trees** — Nest rows and columns to any depth using a simple serialized JSON node structure.
|
|
27
|
+
- **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.
|
|
28
|
+
- **Native Flexbox Resizers** — Fluid, non-blocking split handles built on pointer events.
|
|
29
|
+
- **Accessible Drag-and-Drop** — Built on top of the performant and accessible [`@dnd-kit`](https://dndkit.com) toolkit.
|
|
30
|
+
- **Fullscreen Zoom Toggle** — Programmatically expand any pane to cover the entire viewport and snap it back instantly.
|
|
26
31
|
- **Tree-shakeable & Tiny** — ESM-first with zero runtime CSS. Bring your own styles.
|
|
27
32
|
|
|
28
33
|
---
|
|
29
34
|
|
|
30
35
|
## Installation
|
|
31
36
|
|
|
37
|
+
Install the package into your React project using your preferred package manager.
|
|
38
|
+
|
|
32
39
|
```bash
|
|
33
|
-
npm install react-zeugma
|
|
40
|
+
npm install react-zeugma
|
|
34
41
|
```
|
|
35
42
|
|
|
36
|
-
> **Peer
|
|
43
|
+
> **Peer Dependencies:** react-zeugma is compatible with both **React 18** and **React 19** (along with matching `react-dom`).
|
|
37
44
|
|
|
38
45
|
---
|
|
39
46
|
|
|
40
47
|
## Quick Start
|
|
41
48
|
|
|
49
|
+
Import the core components and configure the layout state inside your React application.
|
|
50
|
+
|
|
42
51
|
```tsx
|
|
43
|
-
import { useState } from 'react'
|
|
44
|
-
import { DashboardProvider, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
|
|
52
|
+
import { useState } from 'react'
|
|
53
|
+
import { DashboardProvider, PaneTree, Pane, DragHandle, TreeNode } from 'react-zeugma'
|
|
45
54
|
|
|
46
55
|
const initialLayout: TreeNode = {
|
|
47
56
|
type: 'split',
|
|
48
57
|
direction: 'row',
|
|
49
|
-
splitPercentage:
|
|
50
|
-
first: { type: 'pane', paneId: '
|
|
58
|
+
splitPercentage: 20,
|
|
59
|
+
first: { type: 'pane', paneId: 'explorer' },
|
|
51
60
|
second: {
|
|
52
61
|
type: 'split',
|
|
53
|
-
direction: '
|
|
54
|
-
splitPercentage:
|
|
55
|
-
first: { type: 'pane', paneId: '
|
|
56
|
-
second: { type: 'pane', paneId: '
|
|
62
|
+
direction: 'row',
|
|
63
|
+
splitPercentage: 50,
|
|
64
|
+
first: { type: 'pane', paneId: 'editor' },
|
|
65
|
+
second: { type: 'pane', paneId: 'preview' },
|
|
57
66
|
},
|
|
58
|
-
}
|
|
67
|
+
}
|
|
59
68
|
|
|
60
69
|
function MyPane({ id }: { id: string }) {
|
|
61
70
|
return (
|
|
62
71
|
<Pane id={id}>
|
|
63
|
-
{({ isDragging }) => (
|
|
64
|
-
<div
|
|
72
|
+
{({ isDragging, remove }) => (
|
|
73
|
+
<div className={`h-full flex flex-col bg-[#18181b] ${isDragging ? 'opacity-30' : ''}`}>
|
|
65
74
|
<DragHandle>
|
|
66
|
-
<div
|
|
67
|
-
{id}
|
|
75
|
+
<div className="px-3 py-2 bg-[#27272a] border-b border-[#3f3f46] flex items-center justify-between cursor-grab">
|
|
76
|
+
<span className="text-xs uppercase text-zinc-300 font-bold">{id}</span>
|
|
77
|
+
<button onClick={remove} className="text-zinc-500 hover:text-rose-400 text-xs">
|
|
78
|
+
×
|
|
79
|
+
</button>
|
|
68
80
|
</div>
|
|
69
81
|
</DragHandle>
|
|
70
|
-
<div
|
|
82
|
+
<div className="flex-1 p-4 text-sm text-zinc-400">Content for {id}</div>
|
|
71
83
|
</div>
|
|
72
84
|
)}
|
|
73
85
|
</Pane>
|
|
74
|
-
)
|
|
86
|
+
)
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
export default function Dashboard() {
|
|
78
|
-
const [layout, setLayout] = useState<TreeNode | null>(initialLayout)
|
|
90
|
+
const [layout, setLayout] = useState<TreeNode | null>(initialLayout)
|
|
79
91
|
|
|
80
92
|
return (
|
|
81
93
|
<DashboardProvider layout={layout} onChange={setLayout} renderPane={(id) => <MyPane id={id} />}>
|
|
82
|
-
<div
|
|
94
|
+
<div className="w-screen h-screen">
|
|
83
95
|
<PaneTree />
|
|
84
96
|
</div>
|
|
85
97
|
</DashboardProvider>
|
|
86
|
-
)
|
|
98
|
+
)
|
|
87
99
|
}
|
|
88
100
|
```
|
|
89
101
|
|
|
90
102
|
---
|
|
91
103
|
|
|
92
|
-
## API
|
|
104
|
+
## API Reference
|
|
105
|
+
|
|
106
|
+
### `<DashboardProvider>`
|
|
107
|
+
|
|
108
|
+
The context provider that sets up the drag-and-drop state machine, monitors active drags, and registers layout change notifications.
|
|
109
|
+
|
|
110
|
+
| Prop | Type | Required | Description |
|
|
111
|
+
| -------------------- | ------------------------------------ | -------- | ----------------------------------------------------------------------- |
|
|
112
|
+
| `layout` | `TreeNode \| null` | Yes | The serializable tree layout schema. |
|
|
113
|
+
| `onChange` | `(layout: TreeNode \| null) => void` | Yes | Fires when resizes, splits, swaps, or removes modify the tree. |
|
|
114
|
+
| `renderPane` | `(paneId: string) => ReactNode` | Yes | Renderer function lookup that returns a `<Pane>` structure. |
|
|
115
|
+
| `renderDragOverlay` | `(activeId: string) => ReactNode` | No | Renders a custom cursor-following drag preview. |
|
|
116
|
+
| `classNames` | `ZeugmaClassNames` | No | Custom classes for overriding pane, resizer, and drop preview overlays. |
|
|
117
|
+
| `fullscreenPaneId` | `string \| null` | No | Active ID of the pane taking full viewport coverage. |
|
|
118
|
+
| `onFullscreenChange` | `(paneId: string \| null) => void` | No | Callback triggered when a pane enters/leaves fullscreen. |
|
|
119
|
+
| `onRemove` | `(paneId: string) => void` | No | Callback triggered when a pane is closed/removed. |
|
|
120
|
+
|
|
121
|
+
### `<PaneTree>`
|
|
122
|
+
|
|
123
|
+
Recursively renders the split nodes and pane nodes. Must be placed inside `<DashboardProvider>`.
|
|
124
|
+
|
|
125
|
+
| Prop | Type | Required | Description |
|
|
126
|
+
| ------------- | ------------------ | -------- | ------------------------------------------------------------------- |
|
|
127
|
+
| `tree` | `TreeNode \| null` | No | Custom subtree to render. Defaults to the provider's root `layout`. |
|
|
128
|
+
| `resizerSize` | `number` | No | Thickness of the split resizer bars in pixels. Defaults to `4`. |
|
|
129
|
+
|
|
130
|
+
### `<Pane id>`
|
|
131
|
+
|
|
132
|
+
Wraps the individual pane components inside the renderer. Utilizes a render prop passing active layout attributes.
|
|
133
|
+
|
|
134
|
+
| Prop | Type | Required | Description |
|
|
135
|
+
| ---------- | --------------------------------------- | -------- | ------------------------------------------------------- |
|
|
136
|
+
| `id` | `string` | Yes | The unique ID corresponding to a `PaneNode`'s `paneId`. |
|
|
137
|
+
| `children` | `(props: PaneRenderProps) => ReactNode` | Yes | Render prop function. |
|
|
138
|
+
|
|
139
|
+
#### Render Props: `PaneRenderProps`
|
|
140
|
+
|
|
141
|
+
| Parameter | Type | Description |
|
|
142
|
+
| ------------------ | ------------ | ------------------------------------------------------------- |
|
|
143
|
+
| `isDragging` | `boolean` | Returns `true` if the node wrapper is actively being dragged. |
|
|
144
|
+
| `isFullscreen` | `boolean` | Returns `true` if the pane is zoomed/fullscreen. |
|
|
145
|
+
| `toggleFullscreen` | `() => void` | Callback to toggle fullscreen viewport coverage. |
|
|
146
|
+
| `remove` | `() => void` | Triggers removal of this pane from the layout tree. |
|
|
147
|
+
|
|
148
|
+
### `<DragHandle>`
|
|
149
|
+
|
|
150
|
+
Defines the interactive drag region inside a `<Pane>`. **Must be placed inside a `<Pane>` component.**
|
|
151
|
+
|
|
152
|
+
| Prop | Type | Required | Description |
|
|
153
|
+
| ----------- | --------------------- | -------- | ---------------------------------------------------------------- |
|
|
154
|
+
| `children` | `React.ReactNode` | Yes | Element(s) that function as the drag handle (e.g., pane header). |
|
|
155
|
+
| `className` | `string` | No | Custom CSS class for the drag handle wrapper. |
|
|
156
|
+
| `style` | `React.CSSProperties` | No | Inline styles for the drag handle wrapper. |
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Tree Utilities
|
|
161
|
+
|
|
162
|
+
react-zeugma exposes serializable tree utility functions for programmatically mutating layout schemas.
|
|
163
|
+
|
|
164
|
+
#### `removePane(tree: TreeNode | null, id: string): TreeNode | null`
|
|
93
165
|
|
|
94
|
-
|
|
95
|
-
| --------------------- | ------------------------------------------------------------------------------------------------- |
|
|
96
|
-
| `<DashboardProvider>` | Root context provider. Accepts `layout`, `onChange`, `renderPane`, and optional class overrides. |
|
|
97
|
-
| `<PaneTree />` | Recursively renders the tree layout. Place inside `DashboardProvider`. |
|
|
98
|
-
| `<Pane id>` | Wraps individual pane content. Provides render props like `isDragging`, `isFullscreen`, `remove`. |
|
|
99
|
-
| `<DragHandle>` | Designates the draggable area within a pane (typically the header/title bar). |
|
|
166
|
+
Recursively scans the layout tree, removes the targeted pane node, and collapses redundant split boundaries.
|
|
100
167
|
|
|
101
|
-
|
|
168
|
+
#### `addPane(tree: TreeNode | null, paneToAdd: string): TreeNode`
|
|
102
169
|
|
|
103
|
-
|
|
104
|
-
| -------------------------- | ---------------------------------------------------- |
|
|
105
|
-
| `removePane(tree, paneId)` | Returns a new tree with the specified pane removed. |
|
|
106
|
-
| `splitPane(tree, ...)` | Programmatically splits a pane in a given direction. |
|
|
107
|
-
| `swapPanes(tree, ...)` | Swaps two panes by their IDs. |
|
|
170
|
+
Recursively matches the bottommost/rightmost pane leaf in the tree, splits it, and inserts the target `paneToAdd`.
|
|
108
171
|
|
|
109
|
-
|
|
172
|
+
#### `swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null`
|
|
110
173
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
| `ZeugmaClassNames` | Optional CSS class overrides for pane, resizer, drop preview, etc. |
|
|
174
|
+
Swaps the positions of `idA` and `idB` nodes directly inside the tree structure.
|
|
175
|
+
|
|
176
|
+
#### `splitPane(tree, targetId, direction, splitType, paneToAdd)`
|
|
177
|
+
|
|
178
|
+
Splits the targeted `targetId` pane inside the tree with `direction` (_row_ / _column_) and type (_left_, _right_, _top_, _bottom_) to insert `paneToAdd`.
|
|
117
179
|
|
|
118
180
|
---
|
|
119
181
|
|
|
120
|
-
##
|
|
182
|
+
## Custom Styling
|
|
183
|
+
|
|
184
|
+
Use custom CSS or styling rules to style resizers, dragging states, drop previews, or active nodes by overriding `classNames` in the provider.
|
|
121
185
|
|
|
122
|
-
|
|
186
|
+
```tsx
|
|
187
|
+
<DashboardProvider
|
|
188
|
+
layout={layout}
|
|
189
|
+
onChange={setLayout}
|
|
190
|
+
renderPane={renderPane}
|
|
191
|
+
classNames={{
|
|
192
|
+
// resizer handles
|
|
193
|
+
resizer:
|
|
194
|
+
'bg-transparent hover:bg-indigo-500/50 active:bg-indigo-500 transition-colors duration-150',
|
|
195
|
+
// split previews
|
|
196
|
+
dropPreview: 'bg-indigo-500/10 border-2 border-dashed border-indigo-500/50 backdrop-blur-xs',
|
|
197
|
+
// swap previews
|
|
198
|
+
swapPreview: 'bg-amber-500/10 border-2 border-dashed border-amber-500/50 backdrop-blur-xs',
|
|
199
|
+
}}
|
|
200
|
+
>
|
|
201
|
+
<PaneTree />
|
|
202
|
+
</DashboardProvider>
|
|
203
|
+
```
|
|
123
204
|
|
|
124
|
-
|
|
205
|
+
---
|
|
125
206
|
|
|
126
|
-
|
|
207
|
+
## Types Reference
|
|
127
208
|
|
|
128
|
-
|
|
209
|
+
Full TypeScript type definitions utilized in the dashboard layout configuration.
|
|
129
210
|
|
|
130
|
-
|
|
211
|
+
```ts
|
|
212
|
+
export type SplitDirection = 'row' | 'column'
|
|
131
213
|
|
|
132
|
-
|
|
214
|
+
export interface SplitNode {
|
|
215
|
+
type: 'split'
|
|
216
|
+
direction: SplitDirection
|
|
217
|
+
first: TreeNode
|
|
218
|
+
second: TreeNode
|
|
219
|
+
splitPercentage: number
|
|
220
|
+
}
|
|
133
221
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
222
|
+
export interface PaneNode {
|
|
223
|
+
type: 'pane'
|
|
224
|
+
paneId: string
|
|
225
|
+
}
|
|
138
226
|
|
|
139
|
-
|
|
227
|
+
export type TreeNode = SplitNode | PaneNode
|
|
228
|
+
|
|
229
|
+
export interface ZeugmaClassNames {
|
|
230
|
+
pane?: string
|
|
231
|
+
dropPreview?: string
|
|
232
|
+
swapPreview?: string
|
|
233
|
+
dragOverlay?: string
|
|
234
|
+
resizer?: string
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface PaneRenderProps {
|
|
238
|
+
isDragging: boolean
|
|
239
|
+
isFullscreen: boolean
|
|
240
|
+
toggleFullscreen: () => void
|
|
241
|
+
remove: () => void
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## SKILL.md
|
|
248
|
+
|
|
249
|
+
A comprehensive developer skill configuration is published alongside the docs for AI agents and reference integrations. Download it from the [documentation site](https://react-zeugma.com/docs#skill-md).
|
|
140
250
|
|
|
141
251
|
---
|
|
142
252
|
|
|
@@ -172,9 +282,10 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines on how to get started.
|
|
|
172
282
|
|
|
173
283
|
---
|
|
174
284
|
|
|
175
|
-
|
|
285
|
+
## The Story of Zeugma
|
|
176
286
|
|
|
177
|
-
_Zeugma_ is an ancient
|
|
178
|
-
This library draws its name from those mosaics: **many tiles, one masterpiece.**
|
|
287
|
+
_Zeugma_ is an ancient city of Commagene, located in modern-day **Gaziantep, Turkey**. Positioned along a critical crossing point of the Euphrates river, Zeugma became a central hub of trade and cultural exchanges.
|
|
179
288
|
|
|
180
|
-
|
|
289
|
+
During modern excavation efforts, archeologists discovered some of the most breathtaking Greco-Roman mosaic panels in history, now housed inside the **Zeugma Mosaic Museum** in Gaziantep. The famous _"Gypsy Girl" (Çingene Kızı)_ mosaic, with her hauntingly detailed eyes, has become a global icon of the city.
|
|
290
|
+
|
|
291
|
+
> _"We chose the name Zeugma because of this ancient craftsmanship. Mosaics are assembled from hundreds of tiny, individual tesserae tiles to form a magnificent, cohesive picture. In the same spirit, react-zeugma lets you build beautiful, customized application workspaces from simple, individual components. Many tiles, one masterpiece."_
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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 O=react.createContext(void 0),I=()=>{let e=react.useContext(O);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function S(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=S(e.first,t),o=S(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function C(e,t,n,o,r){if(e===null)return {type:"pane",paneId:r};if(e.type==="pane"){if(e.paneId===t){let i={type:"pane",paneId:r},c={type:"pane",paneId:t},s=o==="left"||o==="top";return {type:"split",direction:n,first:s?i:c,second:s?c:i,splitPercentage:50}}return e}return {...e,first:C(e.first,t,n,o,r)||e.first,second:C(e.second,t,n,o,r)||e.second}}function E(e,t,n){return e===null?null:e.type==="pane"?e.paneId===t?{...e,paneId:n}:e.paneId===n?{...e,paneId:t}:e:{...e,first:E(e.first,t,n)||e.first,second:E(e.second,t,n)||e.second}}function B(e,t){if(e===null)return {type:"pane",paneId:t};function n(o,r){return o.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",paneId:t}}:{...o,second:n(o.second,o.direction)}}return n(e,null)}var j=({activeId:e,render:t,className:n})=>{let o=react.useRef(null);return react.useEffect(()=>{let r=i=>{o.current&&(o.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",r),()=>document.removeEventListener("pointermove",r)},[]),jsxRuntime.jsx("div",{ref:o,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},A=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:i=null,onFullscreenChange:c,onRemove:s,dragActivationDistance:a=8,children:x})=>{let[g,h]=react.useState(null),p=core.useSensors(core.useSensor(core.PointerSensor,{activationConstraint:{distance:a}})),l=d=>{h(d.active.id.toString());},f=d=>{h(null);let{active:u,over:N}=d;if(!N)return;let v=u.id.toString(),y=N.id.toString(),R=y.match(/^drop-center-(.+)$/);if(R){let[,M]=R;v!==M&&t(E(e,v,M));return}let D=y.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!D)return;let[,P,w]=D;if(v===w)return;let z=P==="left"||P==="right"?"row":"column",L=S(e,v),T=C(L,w,z,P,v);t(T);};return jsxRuntime.jsxs(O.Provider,{value:{layout:e,onLayoutChange:t,renderPane:n,activeId:g,fullscreenPaneId:i,classNames:r,onRemove:s,onFullscreenChange:c},children:[jsxRuntime.jsx(core.DndContext,{sensors:p,collisionDetection:core.pointerWithin,onDragStart:l,onDragEnd:f,children:x}),g&&o&&jsxRuntime.jsx(j,{activeId:g,render:o,className:r.dragOverlay})]})};function $(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:$(e.first,t,n)||e.first,second:$(e.second,t,n)||e.second}:e}var Z=({tree:e,resizerSize:t=4})=>{let{layout:n,onLayoutChange:o,renderPane:r,fullscreenPaneId:i,classNames:c}=I(),s=react.useRef(null);if(i&&!e)return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(i)});let a=e!==void 0?e:n;if(!a)return null;if(a.type==="pane")return jsxRuntime.jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(a.paneId)});let{direction:x,first:g,second:h,splitPercentage:p}=a,l=x==="row",f=d=>{d.preventDefault();let u=s.current;if(!u)return;document.body.classList.add("zeugma-resizing");let N=u.getBoundingClientRect(),v=d.clientX,y=d.clientY,R=p,D=w=>{let z=l?(w.clientX-v)/N.width*100:(w.clientY-y)/N.height*100,L=Math.max(5,Math.min(95,R+z)),T=$(n,a,L);o(T);},P=()=>{document.body.classList.remove("zeugma-resizing"),document.removeEventListener("pointermove",D),document.removeEventListener("pointerup",P);};document.addEventListener("pointermove",D),document.addEventListener("pointerup",P);};return jsxRuntime.jsxs("div",{ref:s,style:{display:"flex",flexDirection:l?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsxRuntime.jsx("div",{style:{flex:`${p} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(Z,{tree:g,resizerSize:t})}),jsxRuntime.jsx("div",{className:c.resizer,style:{width:l?`${t}px`:"100%",height:l?"100%":`${t}px`,cursor:l?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:f,role:"separator","aria-valuenow":p,"aria-valuemin":5,"aria-valuemax":95}),jsxRuntime.jsx("div",{style:{flex:`${100-p} 1 0%`,overflow:"hidden"},children:jsxRuntime.jsx(Z,{tree:h,resizerSize:t})})]})};var Y=react.createContext(null),ae={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:0,bottom:0,left:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},le={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"}},X=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=core.useDroppable({id:e});return jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{ref:o,style:ae[t]}),r&&jsxRuntime.jsx("div",{className:n,style:le[t]})]})},de=({id:e,children:t,style:n})=>{let{activeId:o,classNames:r,fullscreenPaneId:i,onRemove:c,onFullscreenChange:s}=I(),a=o!==null&&o!==e,{attributes:x,listeners:g,setNodeRef:h,isDragging:p}=core.useDraggable({id:e}),l=o===e||p,f=i===e,d={isDragging:l,isFullscreen:f,toggleFullscreen:()=>s?.(f?null:e),remove:()=>{f&&s?.(null),c?.(e);}};return jsxRuntime.jsx(Y.Provider,{value:{...g,...x},children:jsxRuntime.jsxs("div",{ref:h,className:r.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(d),a&&jsxRuntime.jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(u=>jsxRuntime.jsx(X,{id:`drop-${u}-${e}`,position:u,activeClassName:r.dropPreview},u)),jsxRuntime.jsx(X,{id:`drop-center-${e}`,position:"center",activeClassName:r.swapPreview})]})]})})},ce=({children:e,className:t,style:n})=>{let o=react.useContext(Y);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");return jsxRuntime.jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...n},...o,children:e})};exports.DashboardProvider=A;exports.DragHandle=ce;exports.Pane=de;exports.PaneTree=Z;exports.addPane=B;exports.removePane=S;exports.splitPane=C;exports.swapPanes=E;exports.useDashboard=I;//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/dashboard-provider.tsx","../src/components/pane-tree.tsx","../src/components/pane.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","originalNode","isFirst","swapPanes","idA","idB","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","jsxs","DndContext","pointerWithin","updateSplitPercentage","target","newPercentage","PaneTree","resizerSize","onLayoutChange","containerRef","currentNode","first","second","splitPercentage","isRow","handlePointerDown","container","rect","startX","startY","startPercentage","handlePointerMove","moveEvent","delta","handlePointerUp","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","pos","DragHandle","dragProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } from 'react';\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core';\nimport { TreeNode, SplitDirection, PaneNode } from '../types';\n\nexport interface ZeugmaClassNames {\n pane?: string;\n dropPreview?: string;\n swapPreview?: string;\n dragOverlay?: string;\n resizer?: string;\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null;\n onLayoutChange: (newLayout: TreeNode | null) => void;\n renderPane: (paneId: string) => ReactNode;\n activeId: string | null;\n fullscreenPaneId: string | null;\n classNames: ZeugmaClassNames;\n onRemove?: (paneId: string) => void;\n onFullscreenChange?: (paneId: string | null) => void;\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined);\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext);\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider');\n }\n return context;\n};\n\n// Tree Helper: Remove a pane and consolidate the tree\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null;\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree;\n }\n const newFirst = removePane(tree.first, idToRemove);\n const newSecond = removePane(tree.second, idToRemove);\n if (newFirst === null) return newSecond;\n if (newSecond === null) return newFirst;\n return { ...tree, first: newFirst, second: newSecond };\n}\n\n// Tree Helper: Insert a pane by splitting an existing target\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd };\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd };\n const originalNode: PaneNode = { type: 'pane', paneId: targetId };\n const isFirst = splitType === 'left' || splitType === 'top';\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : addedNode,\n splitPercentage: 50,\n };\n }\n return tree;\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n };\n}\n\n// Tree Helper: Swap two pane positions in the tree\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null;\n if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB };\n if (tree.paneId === idB) return { ...tree, paneId: idA };\n return tree;\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n };\n}\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{ activeId: string; render: (id: string) => ReactNode; className?: string }> = ({\n activeId,\n render,\n className,\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`;\n }\n };\n document.addEventListener('pointermove', handleMove);\n return () => document.removeEventListener('pointermove', handleMove);\n }, []);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n );\n};\n\ninterface DashboardProviderProps {\n layout: TreeNode | null;\n onChange: (newLayout: TreeNode | null) => void;\n renderPane: (paneId: string) => ReactNode;\n renderDragOverlay?: (activeId: string) => ReactNode;\n classNames?: ZeugmaClassNames;\n fullscreenPaneId?: string | null;\n onFullscreenChange?: (paneId: string | null) => void;\n onRemove?: (paneId: string) => void;\n children: ReactNode;\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null);\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: 8 },\n })\n );\n\n const handleDragStart = (event: DragStartEvent) => {\n setActiveId(event.active.id.toString());\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null);\n const { active, over } = event;\n if (!over) return;\n\n const draggingId = active.id.toString();\n const overIdStr = over.id.toString();\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/);\n if (swapMatch) {\n const [, targetId] = swapMatch;\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId));\n }\n return;\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/);\n if (!match) return;\n\n const [, dropZone, targetId] = match;\n if (draggingId === targetId) return;\n\n const direction: SplitDirection = (dropZone === 'left' || dropZone === 'right') ? 'row' : 'column';\n const treeWithoutDragging = removePane(layout, draggingId);\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggingId\n );\n onChange(newLayout);\n };\n\n return (\n <DashboardContext.Provider\n value={{\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n }}\n >\n <DndContext sensors={sensors} collisionDetection={pointerWithin} onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay activeId={activeId} render={renderDragOverlay} className={classNames.dragOverlay} />\n )}\n </DashboardContext.Provider>\n );\n};\n","import React, { useRef } from 'react';\nimport { useDashboard } from './dashboard-provider';\nimport { TreeNode, SplitNode } from '../types';\n\ninterface PaneTreeProps {\n tree?: TreeNode | null;\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number;\n}\n\nfunction updateSplitPercentage(tree: TreeNode | null, target: SplitNode, newPercentage: number): TreeNode | null {\n if (tree === null) return null;\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode;\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n };\n }\n return tree;\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({ tree, resizerSize = 4 }) => {\n const { layout, onLayoutChange, renderPane, fullscreenPaneId, classNames } = useDashboard();\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n );\n }\n\n const currentNode = tree !== undefined ? tree : layout;\n\n if (!currentNode) return null;\n\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n );\n }\n\n const { direction, first, second, splitPercentage } = currentNode;\n const isRow = direction === 'row';\n\n const handlePointerDown = (e: React.PointerEvent) => {\n e.preventDefault();\n const container = containerRef.current;\n if (!container) return;\n\n const rect = container.getBoundingClientRect();\n const startX = e.clientX;\n const startY = e.clientY;\n const startPercentage = splitPercentage;\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100;\n const newPercentage = Math.max(5, Math.min(95, startPercentage + delta));\n const newLayout = updateSplitPercentage(layout, currentNode, newPercentage);\n onLayoutChange(newLayout);\n };\n\n const handlePointerUp = () => {\n document.removeEventListener('pointermove', handlePointerMove);\n document.removeEventListener('pointerup', handlePointerUp);\n };\n\n document.addEventListener('pointermove', handlePointerMove);\n document.addEventListener('pointerup', handlePointerUp);\n };\n\n return (\n <div\n ref={containerRef}\n style={{ display: 'flex', flexDirection: isRow ? 'row' : 'column', width: '100%', height: '100%', overflow: 'hidden' }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={first} resizerSize={resizerSize} />\n </div>\n <div\n className={classNames.resizer}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} />\n </div>\n </div>\n );\n};\n","import React, { createContext, useContext } from 'react';\nimport { useDraggable, useDroppable } from '@dnd-kit/core';\nimport { useDashboard } from './dashboard-provider';\n\n// Internal context for drag listeners\nconst DragListenersCtx = createContext<Record<string, unknown> | null>(null);\n\ninterface DropZoneProps {\n id: string;\n position: 'top' | 'bottom' | 'left' | 'right' | 'center';\n activeClassName?: string;\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: { position: 'absolute', top: 0, left: '25%', width: '50%', height: '25%', zIndex: 20, pointerEvents: 'auto' },\n bottom: { position: 'absolute', bottom: 0, left: '25%', width: '50%', height: '25%', zIndex: 20, pointerEvents: 'auto' },\n left: { position: 'absolute', top: 0, bottom: 0, left: 0, width: '25%', height: '100%', zIndex: 20, pointerEvents: 'auto' },\n right: { position: 'absolute', top: 0, bottom: 0, right: 0, width: '25%', height: '100%', zIndex: 20, pointerEvents: 'auto' },\n center: { position: 'absolute', top: '25%', left: '25%', width: '50%', height: '50%', zIndex: 20, pointerEvents: 'auto' },\n};\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: { position: 'absolute', top: 0, left: 0, right: 0, height: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n bottom: { position: 'absolute', bottom: 0, left: 0, right: 0, height: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n left: { position: 'absolute', top: 0, bottom: 0, left: 0, width: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n right: { position: 'absolute', top: 0, bottom: 0, right: 0, width: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n center: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n};\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id });\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n );\n};\n\nexport interface PaneRenderProps {\n isDragging: boolean;\n isFullscreen: boolean;\n toggleFullscreen: () => void;\n remove: () => void;\n}\n\ninterface PaneProps {\n id: string;\n children: (props: PaneRenderProps) => React.ReactNode;\n style?: React.CSSProperties;\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = useDashboard();\n const showDropZones = activeId !== null && activeId !== id;\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id });\n const dragging = activeId === id || isDragging;\n const isFullscreen = fullscreenPaneId === id;\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => onRemove?.(id),\n };\n\n return (\n <DragListenersCtx.Provider value={{ ...listeners, ...attributes }}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 15, pointerEvents: 'none' }}>\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n );\n};\n\n/**\n * Place inside a Pane to make an element the drag handle.\n */\ninterface DragHandleProps {\n children: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx);\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>');\n }\n return (\n <div className={className} style={{ cursor: 'grab', userSelect: 'none', ...style }} {...dragProps}>\n {children}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/dashboard-provider.tsx","../src/components/pane-tree.tsx","../src/components/pane.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","originalNode","isFirst","swapPanes","idA","idB","addPane","insert","node","parentDirection","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","jsxs","DndContext","pointerWithin","updateSplitPercentage","target","newPercentage","PaneTree","resizerSize","onLayoutChange","containerRef","currentNode","first","second","splitPercentage","isRow","handlePointerDown","container","rect","startX","startY","startPercentage","handlePointerMove","moveEvent","delta","handlePointerUp","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","pos","DragHandle","dragProps"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, PaneNode } from '../types'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n\n// Tree Helper: Remove a pane and consolidate the tree\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n// Tree Helper: Insert a pane by splitting an existing target\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd }\n const originalNode: PaneNode = { type: 'pane', paneId: targetId }\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n// Tree Helper: Swap two pane positions in the tree\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB }\n if (tree.paneId === idB) return { ...tree, paneId: idA }\n return tree\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n }\n}\n\n// Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = 8,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n setActiveId(event.active.id.toString())\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n if (!over) return\n\n const draggingId = active.id.toString()\n const overIdStr = over.id.toString()\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId))\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) return\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) return\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const treeWithoutDragging = removePane(layout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggingId,\n )\n onChange(newLayout)\n }\n\n return (\n <DashboardContext.Provider\n value={{\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n }}\n >\n <DndContext\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React, { useRef } from 'react'\nimport { useDashboard } from './dashboard-provider'\nimport { TreeNode, SplitNode } from '../types'\n\ninterface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n}\n\nfunction updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({ tree, resizerSize = 4 }) => {\n const { layout, onLayoutChange, renderPane, fullscreenPaneId, classNames } = useDashboard()\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = (e: React.PointerEvent) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const newPercentage = Math.max(5, Math.min(95, startPercentage + delta))\n const newLayout = updateSplitPercentage(layout, currentNode, newPercentage)\n onLayoutChange(newLayout)\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n }\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={first} resizerSize={resizerSize} />\n </div>\n <div\n className={classNames.resizer}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} />\n </div>\n </div>\n )\n}\n","import React, { createContext, useContext } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from './dashboard-provider'\n\n// Internal context for drag listeners\nconst DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\nexport interface PaneRenderProps {\n isDragging: boolean\n isFullscreen: boolean\n toggleFullscreen: () => void\n remove: () => void\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n onRemove?.(id)\n },\n }\n\n return (\n <DragListenersCtx.Provider value={{ ...listeners, ...attributes }}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n\n/**\n * Place inside a Pane to make an element the drag handle.\n */\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -35,6 +35,7 @@ declare const useDashboard: () => DashboardContextValue;
|
|
|
35
35
|
declare function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null;
|
|
36
36
|
declare function splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null;
|
|
37
37
|
declare function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null;
|
|
38
|
+
declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
|
|
38
39
|
interface DashboardProviderProps {
|
|
39
40
|
layout: TreeNode | null;
|
|
40
41
|
onChange: (newLayout: TreeNode | null) => void;
|
|
@@ -44,6 +45,7 @@ interface DashboardProviderProps {
|
|
|
44
45
|
fullscreenPaneId?: string | null;
|
|
45
46
|
onFullscreenChange?: (paneId: string | null) => void;
|
|
46
47
|
onRemove?: (paneId: string) => void;
|
|
48
|
+
dragActivationDistance?: number;
|
|
47
49
|
children: ReactNode;
|
|
48
50
|
}
|
|
49
51
|
declare const DashboardProvider: React.FC<DashboardProviderProps>;
|
|
@@ -77,4 +79,4 @@ interface DragHandleProps {
|
|
|
77
79
|
}
|
|
78
80
|
declare const DragHandle: React.FC<DragHandleProps>;
|
|
79
81
|
|
|
80
|
-
export { DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, removePane, splitPane, swapPanes, useDashboard };
|
|
82
|
+
export { DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, removePane, splitPane, swapPanes, useDashboard };
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ declare const useDashboard: () => DashboardContextValue;
|
|
|
35
35
|
declare function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null;
|
|
36
36
|
declare function splitPane(tree: TreeNode | null, targetId: string, direction: SplitDirection, splitType: 'left' | 'right' | 'top' | 'bottom', paneToAdd: string): TreeNode | null;
|
|
37
37
|
declare function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null;
|
|
38
|
+
declare function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode;
|
|
38
39
|
interface DashboardProviderProps {
|
|
39
40
|
layout: TreeNode | null;
|
|
40
41
|
onChange: (newLayout: TreeNode | null) => void;
|
|
@@ -44,6 +45,7 @@ interface DashboardProviderProps {
|
|
|
44
45
|
fullscreenPaneId?: string | null;
|
|
45
46
|
onFullscreenChange?: (paneId: string | null) => void;
|
|
46
47
|
onRemove?: (paneId: string) => void;
|
|
48
|
+
dragActivationDistance?: number;
|
|
47
49
|
children: ReactNode;
|
|
48
50
|
}
|
|
49
51
|
declare const DashboardProvider: React.FC<DashboardProviderProps>;
|
|
@@ -77,4 +79,4 @@ interface DragHandleProps {
|
|
|
77
79
|
}
|
|
78
80
|
declare const DragHandle: React.FC<DragHandleProps>;
|
|
79
81
|
|
|
80
|
-
export { DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, removePane, splitPane, swapPanes, useDashboard };
|
|
82
|
+
export { DashboardProvider, DragHandle, Pane, type PaneNode, type PaneRenderProps, PaneTree, type SplitDirection, type SplitNode, type TreeNode, type ZeugmaClassNames, addPane, removePane, splitPane, swapPanes, useDashboard };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {createContext,useContext,useState,useRef,useEffect}from'react';import {useSensors,useSensor,PointerSensor,DndContext,pointerWithin,useDraggable,useDroppable}from'@dnd-kit/core';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var
|
|
1
|
+
import {createContext,useContext,useState,useRef,useEffect}from'react';import {useSensors,useSensor,PointerSensor,DndContext,pointerWithin,useDraggable,useDroppable}from'@dnd-kit/core';import {jsxs,jsx,Fragment}from'react/jsx-runtime';var O=createContext(void 0),I=()=>{let e=useContext(O);if(!e)throw new Error("useDashboard must be used within a DashboardProvider");return e};function S(e,t){if(e===null)return null;if(e.type==="pane")return e.paneId===t?null:e;let n=S(e.first,t),o=S(e.second,t);return n===null?o:o===null?n:{...e,first:n,second:o}}function C(e,t,n,o,r){if(e===null)return {type:"pane",paneId:r};if(e.type==="pane"){if(e.paneId===t){let i={type:"pane",paneId:r},c={type:"pane",paneId:t},s=o==="left"||o==="top";return {type:"split",direction:n,first:s?i:c,second:s?c:i,splitPercentage:50}}return e}return {...e,first:C(e.first,t,n,o,r)||e.first,second:C(e.second,t,n,o,r)||e.second}}function E(e,t,n){return e===null?null:e.type==="pane"?e.paneId===t?{...e,paneId:n}:e.paneId===n?{...e,paneId:t}:e:{...e,first:E(e.first,t,n)||e.first,second:E(e.second,t,n)||e.second}}function B(e,t){if(e===null)return {type:"pane",paneId:t};function n(o,r){return o.type==="pane"?{type:"split",direction:r==="row"?"column":"row",splitPercentage:50,first:o,second:{type:"pane",paneId:t}}:{...o,second:n(o.second,o.direction)}}return n(e,null)}var j=({activeId:e,render:t,className:n})=>{let o=useRef(null);return useEffect(()=>{let r=i=>{o.current&&(o.current.style.transform=`translate(${i.clientX+12}px, ${i.clientY+12}px)`);};return document.addEventListener("pointermove",r),()=>document.removeEventListener("pointermove",r)},[]),jsx("div",{ref:o,className:n,style:{position:"fixed",top:0,left:0,zIndex:9999,pointerEvents:"none"},children:t(e)})},A=({layout:e,onChange:t,renderPane:n,renderDragOverlay:o,classNames:r={},fullscreenPaneId:i=null,onFullscreenChange:c,onRemove:s,dragActivationDistance:a=8,children:x})=>{let[g,h]=useState(null),p=useSensors(useSensor(PointerSensor,{activationConstraint:{distance:a}})),l=d=>{h(d.active.id.toString());},f=d=>{h(null);let{active:u,over:N}=d;if(!N)return;let v=u.id.toString(),y=N.id.toString(),R=y.match(/^drop-center-(.+)$/);if(R){let[,M]=R;v!==M&&t(E(e,v,M));return}let D=y.match(/^drop-(left|right|top|bottom)-(.+)$/);if(!D)return;let[,P,w]=D;if(v===w)return;let z=P==="left"||P==="right"?"row":"column",L=S(e,v),T=C(L,w,z,P,v);t(T);};return jsxs(O.Provider,{value:{layout:e,onLayoutChange:t,renderPane:n,activeId:g,fullscreenPaneId:i,classNames:r,onRemove:s,onFullscreenChange:c},children:[jsx(DndContext,{sensors:p,collisionDetection:pointerWithin,onDragStart:l,onDragEnd:f,children:x}),g&&o&&jsx(j,{activeId:g,render:o,className:r.dragOverlay})]})};function $(e,t,n){return e===null?null:e===t?{...e,splitPercentage:n}:e.type==="split"?{...e,first:$(e.first,t,n)||e.first,second:$(e.second,t,n)||e.second}:e}var Z=({tree:e,resizerSize:t=4})=>{let{layout:n,onLayoutChange:o,renderPane:r,fullscreenPaneId:i,classNames:c}=I(),s=useRef(null);if(i&&!e)return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(i)});let a=e!==void 0?e:n;if(!a)return null;if(a.type==="pane")return jsx("div",{style:{width:"100%",height:"100%",position:"relative"},children:r(a.paneId)});let{direction:x,first:g,second:h,splitPercentage:p}=a,l=x==="row",f=d=>{d.preventDefault();let u=s.current;if(!u)return;document.body.classList.add("zeugma-resizing");let N=u.getBoundingClientRect(),v=d.clientX,y=d.clientY,R=p,D=w=>{let z=l?(w.clientX-v)/N.width*100:(w.clientY-y)/N.height*100,L=Math.max(5,Math.min(95,R+z)),T=$(n,a,L);o(T);},P=()=>{document.body.classList.remove("zeugma-resizing"),document.removeEventListener("pointermove",D),document.removeEventListener("pointerup",P);};document.addEventListener("pointermove",D),document.addEventListener("pointerup",P);};return jsxs("div",{ref:s,style:{display:"flex",flexDirection:l?"row":"column",width:"100%",height:"100%",overflow:"hidden"},children:[jsx("div",{style:{flex:`${p} 1 0%`,overflow:"hidden"},children:jsx(Z,{tree:g,resizerSize:t})}),jsx("div",{className:c.resizer,style:{width:l?`${t}px`:"100%",height:l?"100%":`${t}px`,cursor:l?"col-resize":"row-resize",position:"relative",zIndex:10,userSelect:"none",boxSizing:"border-box",flexShrink:0},onPointerDown:f,role:"separator","aria-valuenow":p,"aria-valuemin":5,"aria-valuemax":95}),jsx("div",{style:{flex:`${100-p} 1 0%`,overflow:"hidden"},children:jsx(Z,{tree:h,resizerSize:t})})]})};var Y=createContext(null),ae={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:0,bottom:0,left:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},right:{position:"absolute",top:0,bottom:0,right:0,width:"25%",height:"100%",zIndex:20,pointerEvents:"auto"},center:{position:"absolute",top:"25%",left:"25%",width:"50%",height:"50%",zIndex:20,pointerEvents:"auto"}},le={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"}},X=({id:e,position:t,activeClassName:n})=>{let{setNodeRef:o,isOver:r}=useDroppable({id:e});return jsxs(Fragment,{children:[jsx("div",{ref:o,style:ae[t]}),r&&jsx("div",{className:n,style:le[t]})]})},de=({id:e,children:t,style:n})=>{let{activeId:o,classNames:r,fullscreenPaneId:i,onRemove:c,onFullscreenChange:s}=I(),a=o!==null&&o!==e,{attributes:x,listeners:g,setNodeRef:h,isDragging:p}=useDraggable({id:e}),l=o===e||p,f=i===e,d={isDragging:l,isFullscreen:f,toggleFullscreen:()=>s?.(f?null:e),remove:()=>{f&&s?.(null),c?.(e);}};return jsx(Y.Provider,{value:{...g,...x},children:jsxs("div",{ref:h,className:r.pane,style:{position:"relative",width:"100%",height:"100%",...n},children:[t(d),a&&jsxs("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,zIndex:15,pointerEvents:"none"},children:[["top","bottom","left","right"].map(u=>jsx(X,{id:`drop-${u}-${e}`,position:u,activeClassName:r.dropPreview},u)),jsx(X,{id:`drop-center-${e}`,position:"center",activeClassName:r.swapPreview})]})]})})},ce=({children:e,className:t,style:n})=>{let o=useContext(Y);if(!o)throw new Error("<DragHandle> must be used inside a <Pane>");return jsx("div",{className:t,style:{cursor:"grab",userSelect:"none",...n},...o,children:e})};export{A as DashboardProvider,ce as DragHandle,de as Pane,Z as PaneTree,B as addPane,S as removePane,C as splitPane,E as swapPanes,I as useDashboard};//# sourceMappingURL=index.js.map
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/dashboard-provider.tsx","../src/components/pane-tree.tsx","../src/components/pane.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","originalNode","isFirst","swapPanes","idA","idB","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","jsxs","DndContext","pointerWithin","updateSplitPercentage","target","newPercentage","PaneTree","resizerSize","onLayoutChange","containerRef","currentNode","first","second","splitPercentage","isRow","handlePointerDown","container","rect","startX","startY","startPercentage","handlePointerMove","moveEvent","delta","handlePointerUp","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","pos","DragHandle","dragProps"],"mappings":"2OA+BO,IAAMA,CAAAA,CAAmBC,aAAAA,CAAiD,MAAS,EAE7EC,CAAAA,CAAe,IAAM,CAChC,IAAMC,CAAAA,CAAUC,WAAWJ,CAAgB,CAAA,CAC3C,GAAI,CAACG,EACH,MAAM,IAAI,KAAA,CAAM,sDAAsD,EAExE,OAAOA,CACT,EAGO,SAASE,EAAWC,CAAAA,CAAuBC,CAAAA,CAAqC,CACrF,GAAID,CAAAA,GAAS,KAAM,OAAO,IAAA,CAC1B,GAAIA,CAAAA,CAAK,OAAS,MAAA,CAChB,OAAOA,EAAK,MAAA,GAAWC,CAAAA,CAAa,KAAOD,CAAAA,CAE7C,IAAME,CAAAA,CAAWH,CAAAA,CAAWC,EAAK,KAAA,CAAOC,CAAU,EAC5CE,CAAAA,CAAYJ,CAAAA,CAAWC,EAAK,MAAA,CAAQC,CAAU,CAAA,CACpD,OAAIC,IAAa,IAAA,CAAaC,CAAAA,CAC1BA,CAAAA,GAAc,IAAA,CAAaD,EACxB,CAAE,GAAGF,CAAAA,CAAM,KAAA,CAAOE,EAAU,MAAA,CAAQC,CAAU,CACvD,CAGO,SAASC,EACdJ,CAAAA,CACAK,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,EACiB,CACjB,GAAIR,IAAS,IAAA,CAAM,OAAO,CAAE,IAAA,CAAM,MAAA,CAAQ,MAAA,CAAQQ,CAAU,EAC5D,GAAIR,CAAAA,CAAK,OAAS,MAAA,CAAQ,CACxB,GAAIA,CAAAA,CAAK,MAAA,GAAWK,CAAAA,CAAU,CAC5B,IAAMI,CAAAA,CAAsB,CAAE,IAAA,CAAM,MAAA,CAAQ,OAAQD,CAAU,CAAA,CACxDE,CAAAA,CAAyB,CAAE,KAAM,MAAA,CAAQ,MAAA,CAAQL,CAAS,CAAA,CAC1DM,CAAAA,CAAUJ,IAAc,MAAA,EAAUA,CAAAA,GAAc,KAAA,CACtD,OAAO,CACL,IAAA,CAAM,OAAA,CACN,UAAAD,CAAAA,CACA,KAAA,CAAOK,EAAUF,CAAAA,CAAYC,CAAAA,CAC7B,MAAA,CAAQC,CAAAA,CAAUD,EAAeD,CAAAA,CACjC,eAAA,CAAiB,EACnB,CACF,CACA,OAAOT,CACT,CACA,OAAO,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOI,CAAAA,CAAUJ,CAAAA,CAAK,MAAOK,CAAAA,CAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,GAAKR,CAAAA,CAAK,KAAA,CAChF,OAAQI,CAAAA,CAAUJ,CAAAA,CAAK,OAAQK,CAAAA,CAAUC,CAAAA,CAAWC,CAAAA,CAAWC,CAAS,GAAKR,CAAAA,CAAK,MACpF,CACF,CAGO,SAASY,EAAUZ,CAAAA,CAAuBa,CAAAA,CAAaC,CAAAA,CAA8B,CAC1F,OAAId,CAAAA,GAAS,IAAA,CAAa,KACtBA,CAAAA,CAAK,IAAA,GAAS,OACZA,CAAAA,CAAK,MAAA,GAAWa,CAAAA,CAAY,CAAE,GAAGb,CAAAA,CAAM,MAAA,CAAQc,CAAI,CAAA,CACnDd,EAAK,MAAA,GAAWc,CAAAA,CAAY,CAAE,GAAGd,EAAM,MAAA,CAAQa,CAAI,EAChDb,CAAAA,CAEF,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOY,CAAAA,CAAUZ,CAAAA,CAAK,MAAOa,CAAAA,CAAKC,CAAG,GAAKd,CAAAA,CAAK,KAAA,CAC/C,OAAQY,CAAAA,CAAUZ,CAAAA,CAAK,MAAA,CAAQa,CAAAA,CAAKC,CAAG,CAAA,EAAKd,CAAAA,CAAK,MACnD,CACF,KAGMe,CAAAA,CAAuG,CAAC,CAC5G,QAAA,CAAAC,EACA,MAAA,CAAAC,CAAAA,CACA,SAAA,CAAAC,CACF,IAAM,CACJ,IAAMC,CAAAA,CAAMC,MAAAA,CAAuB,IAAI,CAAA,CAEvC,OAAAC,UAAU,IAAM,CACd,IAAMC,CAAAA,CAAcC,CAAAA,EAAoB,CAClCJ,CAAAA,CAAI,UACNA,CAAAA,CAAI,OAAA,CAAQ,MAAM,SAAA,CAAY,CAAA,UAAA,EAAaI,EAAE,OAAA,CAAU,EAAE,CAAA,IAAA,EAAOA,CAAAA,CAAE,QAAU,EAAE,CAAA,GAAA,CAAA,EAElF,EACA,OAAA,QAAA,CAAS,gBAAA,CAAiB,cAAeD,CAAU,CAAA,CAC5C,IAAM,QAAA,CAAS,oBAAoB,aAAA,CAAeA,CAAU,CACrE,CAAA,CAAG,EAAE,CAAA,CAGHE,GAAAA,CAAC,KAAA,CAAA,CACC,GAAA,CAAKL,EACL,SAAA,CAAWD,CAAAA,CACX,MAAO,CACL,QAAA,CAAU,QACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CAAA,CACN,OAAQ,IAAA,CACR,aAAA,CAAe,MACjB,CAAA,CAEC,QAAA,CAAAD,EAAOD,CAAQ,CAAA,CAClB,CAEJ,CAAA,CAcaS,EAAsD,CAAC,CAClE,OAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,UAAA,CAAAC,CAAAA,CACA,iBAAA,CAAAC,CAAAA,CACA,WAAAC,CAAAA,CAAa,EAAC,CACd,gBAAA,CAAAC,EAAmB,IAAA,CACnB,kBAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,QAAA,CAAAC,CACF,IAAM,CACJ,GAAM,CAAClB,CAAAA,CAAUmB,CAAW,CAAA,CAAIC,QAAAA,CAAwB,IAAI,CAAA,CAEtDC,CAAAA,CAAUC,WACdC,SAAAA,CAAUC,aAAAA,CAAe,CACvB,oBAAA,CAAsB,CAAE,QAAA,CAAU,CAAE,CACtC,CAAC,CACH,EAEMC,CAAAA,CAAmBC,CAAAA,EAA0B,CACjDP,CAAAA,CAAYO,CAAAA,CAAM,MAAA,CAAO,EAAA,CAAG,UAAU,EACxC,CAAA,CAEMC,CAAAA,CAAiBD,GAAwB,CAC7CP,CAAAA,CAAY,IAAI,CAAA,CAChB,GAAM,CAAE,MAAA,CAAAS,EAAQ,IAAA,CAAAC,CAAK,EAAIH,CAAAA,CACzB,GAAI,CAACG,CAAAA,CAAM,OAEX,IAAMC,CAAAA,CAAaF,EAAO,EAAA,CAAG,QAAA,GACvBG,CAAAA,CAAYF,CAAAA,CAAK,EAAA,CAAG,QAAA,GAGpBG,CAAAA,CAAYD,CAAAA,CAAU,MAAM,oBAAoB,CAAA,CACtD,GAAIC,CAAAA,CAAW,CACb,GAAM,EAAG3C,CAAQ,CAAA,CAAI2C,CAAAA,CACjBF,CAAAA,GAAezC,GACjBsB,CAAAA,CAASf,CAAAA,CAAUc,CAAAA,CAAQoB,CAAAA,CAAYzC,CAAQ,CAAC,CAAA,CAElD,MACF,CAGA,IAAM4C,EAAQF,CAAAA,CAAU,KAAA,CAAM,qCAAqC,CAAA,CACnE,GAAI,CAACE,CAAAA,CAAO,OAEZ,GAAM,EAAGC,CAAAA,CAAU7C,CAAQ,CAAA,CAAI4C,CAAAA,CAC/B,GAAIH,CAAAA,GAAezC,CAAAA,CAAU,OAE7B,IAAMC,CAAAA,CAA6B4C,IAAa,MAAA,EAAUA,CAAAA,GAAa,OAAA,CAAW,KAAA,CAAQ,SACpFC,CAAAA,CAAsBpD,CAAAA,CAAW2B,CAAAA,CAAQoB,CAAU,EAEnDM,CAAAA,CAAYhD,CAAAA,CAChB+C,CAAAA,CACA9C,CAAAA,CACAC,EACA4C,CAAAA,CACAJ,CACF,EACAnB,CAAAA,CAASyB,CAAS,EACpB,CAAA,CAEA,OACEC,IAAAA,CAAC3D,CAAAA,CAAiB,SAAjB,CACC,KAAA,CAAO,CACL,MAAA,CAAAgC,CAAAA,CACA,eAAgBC,CAAAA,CAChB,UAAA,CAAAC,CAAAA,CACA,QAAA,CAAAZ,EACA,gBAAA,CAAAe,CAAAA,CACA,WAAAD,CAAAA,CACA,QAAA,CAAAG,EACA,kBAAA,CAAAD,CACF,CAAA,CAEA,QAAA,CAAA,CAAAR,IAAC8B,UAAAA,CAAA,CAAW,OAAA,CAASjB,CAAAA,CAAS,mBAAoBkB,aAAAA,CAAe,WAAA,CAAad,CAAAA,CAAiB,SAAA,CAAWE,EACvG,QAAA,CAAAT,CAAAA,CACH,EACClB,CAAAA,EAAYa,CAAAA,EACXL,IAACT,CAAAA,CAAA,CAAc,QAAA,CAAUC,CAAAA,CAAU,OAAQa,CAAAA,CAAmB,SAAA,CAAWC,EAAW,WAAA,CAAa,CAAA,CAAA,CAErG,CAEJ,EC3NA,SAAS0B,CAAAA,CAAsBxD,CAAAA,CAAuByD,CAAAA,CAAmBC,CAAAA,CAAwC,CAC/G,OAAI1D,CAAAA,GAAS,IAAA,CAAa,IAAA,CACtBA,IAASyD,CAAAA,CACJ,CAAE,GAAGzD,CAAAA,CAAM,gBAAiB0D,CAAc,CAAA,CAE/C1D,EAAK,IAAA,GAAS,OAAA,CACT,CACL,GAAGA,CAAAA,CACH,KAAA,CAAOwD,CAAAA,CAAsBxD,EAAK,KAAA,CAAOyD,CAAAA,CAAQC,CAAa,CAAA,EAAK1D,CAAAA,CAAK,MACxE,MAAA,CAAQwD,CAAAA,CAAsBxD,CAAAA,CAAK,MAAA,CAAQyD,EAAQC,CAAa,CAAA,EAAK1D,EAAK,MAC5E,CAAA,CAEKA,CACT,CAEO,IAAM2D,CAAAA,CAAoC,CAAC,CAAE,IAAA,CAAA3D,CAAAA,CAAM,WAAA,CAAA4D,CAAAA,CAAc,CAAE,CAAA,GAAM,CAC9E,GAAM,CAAE,OAAAlC,CAAAA,CAAQ,cAAA,CAAAmC,EAAgB,UAAA,CAAAjC,CAAAA,CAAY,iBAAAG,CAAAA,CAAkB,UAAA,CAAAD,CAAW,CAAA,CAAIlC,GAAa,CACpFkE,CAAAA,CAAe1C,OAAuB,IAAI,CAAA,CAGhD,GAAIW,CAAAA,EAAoB,CAAC/B,CAAAA,CACvB,OACEwB,IAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,KAAA,CAAO,MAAA,CAAQ,OAAQ,MAAA,CAAQ,QAAA,CAAU,UAAW,CAAA,CAC/D,SAAAI,CAAAA,CAAWG,CAAgB,EAC9B,CAAA,CAIJ,IAAMgC,EAAc/D,CAAAA,GAAS,MAAA,CAAYA,CAAAA,CAAO0B,CAAAA,CAEhD,GAAI,CAACqC,CAAAA,CAAa,OAAO,IAAA,CAEzB,GAAIA,EAAY,IAAA,GAAS,MAAA,CACvB,OACEvC,GAAAA,CAAC,OAAI,KAAA,CAAO,CAAE,MAAO,MAAA,CAAQ,MAAA,CAAQ,OAAQ,QAAA,CAAU,UAAW,CAAA,CAC/D,QAAA,CAAAI,EAAWmC,CAAAA,CAAY,MAAM,EAChC,CAAA,CAIJ,GAAM,CAAE,SAAA,CAAAzD,CAAAA,CAAW,KAAA,CAAA0D,CAAAA,CAAO,OAAAC,CAAAA,CAAQ,eAAA,CAAAC,CAAgB,CAAA,CAAIH,EAChDI,CAAAA,CAAQ7D,CAAAA,GAAc,KAAA,CAEtB8D,CAAAA,CAAqB7C,GAA0B,CACnDA,CAAAA,CAAE,gBAAe,CACjB,IAAM8C,EAAYP,CAAAA,CAAa,OAAA,CAC/B,GAAI,CAACO,EAAW,OAEhB,IAAMC,EAAOD,CAAAA,CAAU,qBAAA,GACjBE,CAAAA,CAAShD,CAAAA,CAAE,OAAA,CACXiD,CAAAA,CAASjD,EAAE,OAAA,CACXkD,CAAAA,CAAkBP,EAElBQ,CAAAA,CAAqBC,CAAAA,EAA4B,CACrD,IAAMC,CAAAA,CAAQT,CAAAA,CAAAA,CACRQ,CAAAA,CAAU,QAAUJ,CAAAA,EAAUD,CAAAA,CAAK,KAAA,CAAS,GAAA,CAAA,CAC5CK,EAAU,OAAA,CAAUH,CAAAA,EAAUF,CAAAA,CAAK,MAAA,CAAU,IAC7CZ,CAAAA,CAAgB,IAAA,CAAK,IAAI,CAAA,CAAG,IAAA,CAAK,IAAI,EAAA,CAAIe,CAAAA,CAAkBG,CAAK,CAAC,EACjExB,CAAAA,CAAYI,CAAAA,CAAsB9B,EAAQqC,CAAAA,CAAaL,CAAa,EAC1EG,CAAAA,CAAeT,CAAS,EAC1B,CAAA,CAEMyB,EAAkB,IAAM,CAC5B,SAAS,mBAAA,CAAoB,aAAA,CAAeH,CAAiB,CAAA,CAC7D,QAAA,CAAS,mBAAA,CAAoB,WAAA,CAAaG,CAAe,EAC3D,CAAA,CAEA,QAAA,CAAS,gBAAA,CAAiB,cAAeH,CAAiB,CAAA,CAC1D,QAAA,CAAS,gBAAA,CAAiB,YAAaG,CAAe,EACxD,EAEA,OACExB,IAAAA,CAAC,OACC,GAAA,CAAKS,CAAAA,CACL,KAAA,CAAO,CAAE,QAAS,MAAA,CAAQ,aAAA,CAAeK,EAAQ,KAAA,CAAQ,QAAA,CAAU,MAAO,MAAA,CAAQ,MAAA,CAAQ,MAAA,CAAQ,QAAA,CAAU,QAAS,CAAA,CAErH,QAAA,CAAA,CAAA3C,IAAC,KAAA,CAAA,CAAI,KAAA,CAAO,CAAE,IAAA,CAAM,CAAA,EAAG0C,CAAe,CAAA,KAAA,CAAA,CAAS,SAAU,QAAS,CAAA,CAChE,QAAA,CAAA1C,GAAAA,CAACmC,EAAA,CAAS,IAAA,CAAMK,CAAAA,CAAO,WAAA,CAAaJ,EAAa,CAAA,CACnD,CAAA,CACApC,IAAC,KAAA,CAAA,CACC,SAAA,CAAWM,EAAW,OAAA,CACtB,KAAA,CAAO,CACL,KAAA,CAAOqC,EAAQ,CAAA,EAAGP,CAAW,KAAO,MAAA,CACpC,MAAA,CAAQO,EAAQ,MAAA,CAAS,CAAA,EAAGP,CAAW,CAAA,EAAA,CAAA,CACvC,OAAQO,CAAAA,CAAQ,YAAA,CAAe,aAC/B,QAAA,CAAU,UAAA,CACV,OAAQ,EAAA,CACR,UAAA,CAAY,MAAA,CACZ,SAAA,CAAW,aACX,UAAA,CAAY,CACd,CAAA,CACA,aAAA,CAAeC,EACf,IAAA,CAAK,WAAA,CACL,eAAA,CAAeF,CAAAA,CACf,gBAAe,CAAA,CACf,eAAA,CAAe,GACjB,CAAA,CACA1C,GAAAA,CAAC,OAAI,KAAA,CAAO,CAAE,IAAA,CAAM,CAAA,EAAG,IAAM0C,CAAe,CAAA,KAAA,CAAA,CAAS,SAAU,QAAS,CAAA,CACtE,SAAA1C,GAAAA,CAACmC,CAAAA,CAAA,CAAS,IAAA,CAAMM,EAAQ,WAAA,CAAaL,CAAAA,CAAa,EACpD,CAAA,CAAA,CACF,CAEJ,EC3GA,IAAMkB,EAAmBnF,aAAAA,CAA8C,IAAI,CAAA,CAQrEoF,EAAAA,CAA2D,CAC/D,GAAA,CAAK,CAAE,SAAU,UAAA,CAAY,GAAA,CAAK,EAAG,IAAA,CAAM,KAAA,CAAO,KAAA,CAAO,KAAA,CAAO,OAAQ,KAAA,CAAO,MAAA,CAAQ,GAAI,aAAA,CAAe,MAAO,EACjH,MAAA,CAAQ,CAAE,QAAA,CAAU,UAAA,CAAY,OAAQ,CAAA,CAAG,IAAA,CAAM,KAAA,CAAO,KAAA,CAAO,MAAO,MAAA,CAAQ,KAAA,CAAO,MAAA,CAAQ,EAAA,CAAI,cAAe,MAAO,CAAA,CACvH,KAAM,CAAE,QAAA,CAAU,WAAY,GAAA,CAAK,CAAA,CAAG,MAAA,CAAQ,CAAA,CAAG,KAAM,CAAA,CAAG,KAAA,CAAO,MAAO,MAAA,CAAQ,MAAA,CAAQ,OAAQ,EAAA,CAAI,aAAA,CAAe,MAAO,CAAA,CAC1H,MAAO,CAAE,QAAA,CAAU,WAAY,GAAA,CAAK,CAAA,CAAG,OAAQ,CAAA,CAAG,KAAA,CAAO,CAAA,CAAG,KAAA,CAAO,MAAO,MAAA,CAAQ,MAAA,CAAQ,OAAQ,EAAA,CAAI,aAAA,CAAe,MAAO,CAAA,CAC5H,MAAA,CAAQ,CAAE,QAAA,CAAU,WAAY,GAAA,CAAK,KAAA,CAAO,KAAM,KAAA,CAAO,KAAA,CAAO,MAAO,MAAA,CAAQ,KAAA,CAAO,MAAA,CAAQ,EAAA,CAAI,cAAe,MAAO,CAC1H,EAEMC,EAAAA,CAAwD,CAC5D,IAAK,CAAE,QAAA,CAAU,UAAA,CAAY,GAAA,CAAK,EAAG,IAAA,CAAM,CAAA,CAAG,MAAO,CAAA,CAAG,MAAA,CAAQ,MAAO,MAAA,CAAQ,EAAA,CAAI,aAAA,CAAe,MAAA,CAAQ,UAAW,YAAa,CAAA,CAClI,MAAA,CAAQ,CAAE,SAAU,UAAA,CAAY,MAAA,CAAQ,CAAA,CAAG,IAAA,CAAM,EAAG,KAAA,CAAO,CAAA,CAAG,OAAQ,KAAA,CAAO,MAAA,CAAQ,GAAI,aAAA,CAAe,MAAA,CAAQ,SAAA,CAAW,YAAa,EACxI,IAAA,CAAM,CAAE,SAAU,UAAA,CAAY,GAAA,CAAK,EAAG,MAAA,CAAQ,CAAA,CAAG,IAAA,CAAM,CAAA,CAAG,MAAO,KAAA,CAAO,MAAA,CAAQ,GAAI,aAAA,CAAe,MAAA,CAAQ,UAAW,YAAa,CAAA,CACnI,KAAA,CAAO,CAAE,SAAU,UAAA,CAAY,GAAA,CAAK,CAAA,CAAG,MAAA,CAAQ,EAAG,KAAA,CAAO,CAAA,CAAG,KAAA,CAAO,KAAA,CAAO,OAAQ,EAAA,CAAI,aAAA,CAAe,OAAQ,SAAA,CAAW,YAAa,EACrI,MAAA,CAAQ,CAAE,QAAA,CAAU,UAAA,CAAY,IAAK,CAAA,CAAG,IAAA,CAAM,EAAG,KAAA,CAAO,CAAA,CAAG,OAAQ,CAAA,CAAG,MAAA,CAAQ,EAAA,CAAI,aAAA,CAAe,OAAQ,SAAA,CAAW,YAAa,CACnI,CAAA,CAEMC,CAAAA,CAAoC,CAAC,CAAE,EAAA,CAAAC,CAAAA,CAAI,QAAA,CAAAC,EAAU,eAAA,CAAAC,CAAgB,CAAA,GAAM,CAC/E,GAAM,CAAE,UAAA,CAAAC,CAAAA,CAAY,MAAA,CAAAC,CAAO,CAAA,CAAIC,YAAAA,CAAa,CAAE,EAAA,CAAAL,CAAG,CAAC,CAAA,CAClD,OACE7B,IAAAA,CAAAmC,QAAAA,CAAA,CACE,QAAA,CAAA,CAAAhE,GAAAA,CAAC,OAAI,GAAA,CAAK6D,CAAAA,CAAY,MAAON,EAAAA,CAAoBI,CAAQ,CAAA,CAAG,CAAA,CAC3DG,GAAU9D,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAW4D,CAAAA,CAAiB,KAAA,CAAOJ,GAAiBG,CAAQ,CAAA,CAAG,CAAA,CAAA,CACjF,CAEJ,EAeaM,EAAAA,CAA4B,CAAC,CAAE,EAAA,CAAAP,CAAAA,CAAI,SAAAhD,CAAAA,CAAU,KAAA,CAAAwD,CAAM,CAAA,GAAM,CACpE,GAAM,CAAE,SAAA1E,CAAAA,CAAU,UAAA,CAAAc,EAAY,gBAAA,CAAAC,CAAAA,CAAkB,QAAA,CAAAE,CAAAA,CAAU,mBAAAD,CAAmB,CAAA,CAAIpC,GAAa,CACxF+F,CAAAA,CAAgB3E,IAAa,IAAA,EAAQA,CAAAA,GAAakE,CAAAA,CAElD,CAAE,WAAAU,CAAAA,CAAY,SAAA,CAAAC,EAAW,UAAA,CAAAR,CAAAA,CAAY,WAAAS,CAAW,CAAA,CAAIC,YAAAA,CAAa,CAAE,GAAAb,CAAG,CAAC,CAAA,CACvEc,CAAAA,CAAWhF,IAAakE,CAAAA,EAAMY,CAAAA,CAC9BG,CAAAA,CAAelE,CAAAA,GAAqBmD,EAEpCgB,CAAAA,CAA+B,CACnC,WAAYF,CAAAA,CACZ,YAAA,CAAAC,EACA,gBAAA,CAAkB,IAAMjE,CAAAA,GAAqBiE,CAAAA,CAAe,KAAOf,CAAE,CAAA,CACrE,OAAQ,IAAMjD,CAAAA,GAAWiD,CAAE,CAC7B,CAAA,CAEA,OACE1D,GAAAA,CAACsD,EAAiB,QAAA,CAAjB,CAA0B,MAAO,CAAE,GAAGe,EAAW,GAAGD,CAAW,CAAA,CAC9D,QAAA,CAAAvC,KAAC,KAAA,CAAA,CACC,GAAA,CAAKgC,CAAAA,CACL,SAAA,CAAWvD,EAAW,IAAA,CACtB,KAAA,CAAO,CAAE,QAAA,CAAU,WAAY,KAAA,CAAO,MAAA,CAAQ,OAAQ,MAAA,CAAQ,GAAG4D,CAAM,CAAA,CAEtE,QAAA,CAAA,CAAAxD,CAAAA,CAASgE,CAAW,EAEpBP,CAAAA,EACCtC,IAAAA,CAAC,OAAI,KAAA,CAAO,CAAE,SAAU,UAAA,CAAY,GAAA,CAAK,CAAA,CAAG,IAAA,CAAM,EAAG,KAAA,CAAO,CAAA,CAAG,OAAQ,CAAA,CAAG,MAAA,CAAQ,GAAI,aAAA,CAAe,MAAO,CAAA,CACxG,QAAA,CAAA,CAAA,CAAC,MAAO,QAAA,CAAU,MAAA,CAAQ,OAAO,CAAA,CAAY,IAAK8C,CAAAA,EAClD3E,GAAAA,CAACyD,CAAAA,CAAA,CAEC,GAAI,CAAA,KAAA,EAAQkB,CAAG,IAAIjB,CAAE,CAAA,CAAA,CACrB,SAAUiB,CAAAA,CACV,eAAA,CAAiBrE,CAAAA,CAAW,WAAA,CAAA,CAHvBqE,CAIP,CACD,CAAA,CACD3E,IAACyD,CAAAA,CAAA,CACC,GAAI,CAAA,YAAA,EAAeC,CAAE,CAAA,CAAA,CACrB,QAAA,CAAS,SACT,eAAA,CAAiBpD,CAAAA,CAAW,YAC9B,CAAA,CAAA,CACF,CAAA,CAAA,CAEJ,EACF,CAEJ,CAAA,CAWasE,EAAAA,CAAwC,CAAC,CAAE,QAAA,CAAAlE,CAAAA,CAAU,UAAAhB,CAAAA,CAAW,KAAA,CAAAwE,CAAM,CAAA,GAAM,CACvF,IAAMW,CAAAA,CAAYvG,WAAWgF,CAAgB,CAAA,CAC7C,GAAI,CAACuB,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,2CAA2C,CAAA,CAE7D,OACE7E,GAAAA,CAAC,KAAA,CAAA,CAAI,UAAWN,CAAAA,CAAW,KAAA,CAAO,CAAE,MAAA,CAAQ,MAAA,CAAQ,UAAA,CAAY,MAAA,CAAQ,GAAGwE,CAAM,CAAA,CAAI,GAAGW,CAAAA,CACrF,QAAA,CAAAnE,EACH,CAEJ","file":"index.js","sourcesContent":["import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } from 'react';\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core';\nimport { TreeNode, SplitDirection, PaneNode } from '../types';\n\nexport interface ZeugmaClassNames {\n pane?: string;\n dropPreview?: string;\n swapPreview?: string;\n dragOverlay?: string;\n resizer?: string;\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null;\n onLayoutChange: (newLayout: TreeNode | null) => void;\n renderPane: (paneId: string) => ReactNode;\n activeId: string | null;\n fullscreenPaneId: string | null;\n classNames: ZeugmaClassNames;\n onRemove?: (paneId: string) => void;\n onFullscreenChange?: (paneId: string | null) => void;\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined);\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext);\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider');\n }\n return context;\n};\n\n// Tree Helper: Remove a pane and consolidate the tree\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null;\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree;\n }\n const newFirst = removePane(tree.first, idToRemove);\n const newSecond = removePane(tree.second, idToRemove);\n if (newFirst === null) return newSecond;\n if (newSecond === null) return newFirst;\n return { ...tree, first: newFirst, second: newSecond };\n}\n\n// Tree Helper: Insert a pane by splitting an existing target\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd };\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd };\n const originalNode: PaneNode = { type: 'pane', paneId: targetId };\n const isFirst = splitType === 'left' || splitType === 'top';\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : addedNode,\n splitPercentage: 50,\n };\n }\n return tree;\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n };\n}\n\n// Tree Helper: Swap two pane positions in the tree\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null;\n if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB };\n if (tree.paneId === idB) return { ...tree, paneId: idA };\n return tree;\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n };\n}\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{ activeId: string; render: (id: string) => ReactNode; className?: string }> = ({\n activeId,\n render,\n className,\n}) => {\n const ref = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`;\n }\n };\n document.addEventListener('pointermove', handleMove);\n return () => document.removeEventListener('pointermove', handleMove);\n }, []);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n );\n};\n\ninterface DashboardProviderProps {\n layout: TreeNode | null;\n onChange: (newLayout: TreeNode | null) => void;\n renderPane: (paneId: string) => ReactNode;\n renderDragOverlay?: (activeId: string) => ReactNode;\n classNames?: ZeugmaClassNames;\n fullscreenPaneId?: string | null;\n onFullscreenChange?: (paneId: string | null) => void;\n onRemove?: (paneId: string) => void;\n children: ReactNode;\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null);\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: 8 },\n })\n );\n\n const handleDragStart = (event: DragStartEvent) => {\n setActiveId(event.active.id.toString());\n };\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null);\n const { active, over } = event;\n if (!over) return;\n\n const draggingId = active.id.toString();\n const overIdStr = over.id.toString();\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/);\n if (swapMatch) {\n const [, targetId] = swapMatch;\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId));\n }\n return;\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/);\n if (!match) return;\n\n const [, dropZone, targetId] = match;\n if (draggingId === targetId) return;\n\n const direction: SplitDirection = (dropZone === 'left' || dropZone === 'right') ? 'row' : 'column';\n const treeWithoutDragging = removePane(layout, draggingId);\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggingId\n );\n onChange(newLayout);\n };\n\n return (\n <DashboardContext.Provider\n value={{\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n }}\n >\n <DndContext sensors={sensors} collisionDetection={pointerWithin} onDragStart={handleDragStart} onDragEnd={handleDragEnd}>\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay activeId={activeId} render={renderDragOverlay} className={classNames.dragOverlay} />\n )}\n </DashboardContext.Provider>\n );\n};\n","import React, { useRef } from 'react';\nimport { useDashboard } from './dashboard-provider';\nimport { TreeNode, SplitNode } from '../types';\n\ninterface PaneTreeProps {\n tree?: TreeNode | null;\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number;\n}\n\nfunction updateSplitPercentage(tree: TreeNode | null, target: SplitNode, newPercentage: number): TreeNode | null {\n if (tree === null) return null;\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode;\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n };\n }\n return tree;\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({ tree, resizerSize = 4 }) => {\n const { layout, onLayoutChange, renderPane, fullscreenPaneId, classNames } = useDashboard();\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n );\n }\n\n const currentNode = tree !== undefined ? tree : layout;\n\n if (!currentNode) return null;\n\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n );\n }\n\n const { direction, first, second, splitPercentage } = currentNode;\n const isRow = direction === 'row';\n\n const handlePointerDown = (e: React.PointerEvent) => {\n e.preventDefault();\n const container = containerRef.current;\n if (!container) return;\n\n const rect = container.getBoundingClientRect();\n const startX = e.clientX;\n const startY = e.clientY;\n const startPercentage = splitPercentage;\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100;\n const newPercentage = Math.max(5, Math.min(95, startPercentage + delta));\n const newLayout = updateSplitPercentage(layout, currentNode, newPercentage);\n onLayoutChange(newLayout);\n };\n\n const handlePointerUp = () => {\n document.removeEventListener('pointermove', handlePointerMove);\n document.removeEventListener('pointerup', handlePointerUp);\n };\n\n document.addEventListener('pointermove', handlePointerMove);\n document.addEventListener('pointerup', handlePointerUp);\n };\n\n return (\n <div\n ref={containerRef}\n style={{ display: 'flex', flexDirection: isRow ? 'row' : 'column', width: '100%', height: '100%', overflow: 'hidden' }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={first} resizerSize={resizerSize} />\n </div>\n <div\n className={classNames.resizer}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} />\n </div>\n </div>\n );\n};\n","import React, { createContext, useContext } from 'react';\nimport { useDraggable, useDroppable } from '@dnd-kit/core';\nimport { useDashboard } from './dashboard-provider';\n\n// Internal context for drag listeners\nconst DragListenersCtx = createContext<Record<string, unknown> | null>(null);\n\ninterface DropZoneProps {\n id: string;\n position: 'top' | 'bottom' | 'left' | 'right' | 'center';\n activeClassName?: string;\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: { position: 'absolute', top: 0, left: '25%', width: '50%', height: '25%', zIndex: 20, pointerEvents: 'auto' },\n bottom: { position: 'absolute', bottom: 0, left: '25%', width: '50%', height: '25%', zIndex: 20, pointerEvents: 'auto' },\n left: { position: 'absolute', top: 0, bottom: 0, left: 0, width: '25%', height: '100%', zIndex: 20, pointerEvents: 'auto' },\n right: { position: 'absolute', top: 0, bottom: 0, right: 0, width: '25%', height: '100%', zIndex: 20, pointerEvents: 'auto' },\n center: { position: 'absolute', top: '25%', left: '25%', width: '50%', height: '50%', zIndex: 20, pointerEvents: 'auto' },\n};\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: { position: 'absolute', top: 0, left: 0, right: 0, height: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n bottom: { position: 'absolute', bottom: 0, left: 0, right: 0, height: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n left: { position: 'absolute', top: 0, bottom: 0, left: 0, width: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n right: { position: 'absolute', top: 0, bottom: 0, right: 0, width: '50%', zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n center: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 21, pointerEvents: 'none', boxSizing: 'border-box' },\n};\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id });\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n );\n};\n\nexport interface PaneRenderProps {\n isDragging: boolean;\n isFullscreen: boolean;\n toggleFullscreen: () => void;\n remove: () => void;\n}\n\ninterface PaneProps {\n id: string;\n children: (props: PaneRenderProps) => React.ReactNode;\n style?: React.CSSProperties;\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = useDashboard();\n const showDropZones = activeId !== null && activeId !== id;\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id });\n const dragging = activeId === id || isDragging;\n const isFullscreen = fullscreenPaneId === id;\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => onRemove?.(id),\n };\n\n return (\n <DragListenersCtx.Provider value={{ ...listeners, ...attributes }}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 15, pointerEvents: 'none' }}>\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n );\n};\n\n/**\n * Place inside a Pane to make an element the drag handle.\n */\ninterface DragHandleProps {\n children: React.ReactNode;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx);\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>');\n }\n return (\n <div className={className} style={{ cursor: 'grab', userSelect: 'none', ...style }} {...dragProps}>\n {children}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/dashboard-provider.tsx","../src/components/pane-tree.tsx","../src/components/pane.tsx"],"names":["DashboardContext","createContext","useDashboard","context","useContext","removePane","tree","idToRemove","newFirst","newSecond","splitPane","targetId","direction","splitType","paneToAdd","addedNode","originalNode","isFirst","swapPanes","idA","idB","addPane","insert","node","parentDirection","CursorOverlay","activeId","render","className","ref","useRef","useEffect","handleMove","e","jsx","DashboardProvider","layout","onChange","renderPane","renderDragOverlay","classNames","fullscreenPaneId","onFullscreenChange","onRemove","dragActivationDistance","children","setActiveId","useState","sensors","useSensors","useSensor","PointerSensor","handleDragStart","event","handleDragEnd","active","over","draggingId","overIdStr","swapMatch","match","dropZone","treeWithoutDragging","newLayout","jsxs","DndContext","pointerWithin","updateSplitPercentage","target","newPercentage","PaneTree","resizerSize","onLayoutChange","containerRef","currentNode","first","second","splitPercentage","isRow","handlePointerDown","container","rect","startX","startY","startPercentage","handlePointerMove","moveEvent","delta","handlePointerUp","DragListenersCtx","activationPositions","previewPositions","DropZone","id","position","activeClassName","setNodeRef","isOver","useDroppable","Fragment","Pane","style","showDropZones","attributes","listeners","isDragging","useDraggable","dragging","isFullscreen","renderProps","pos","DragHandle","dragProps"],"mappings":"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","file":"index.js","sourcesContent":["import React, { createContext, useContext, useState, useEffect, useRef, ReactNode } from 'react'\nimport {\n DndContext,\n useSensor,\n useSensors,\n PointerSensor,\n DragStartEvent,\n DragEndEvent,\n pointerWithin,\n} from '@dnd-kit/core'\nimport { TreeNode, SplitDirection, PaneNode } from '../types'\n\nexport interface ZeugmaClassNames {\n pane?: string\n dropPreview?: string\n swapPreview?: string\n dragOverlay?: string\n resizer?: string\n}\n\nexport interface DashboardContextValue {\n layout: TreeNode | null\n onLayoutChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n activeId: string | null\n fullscreenPaneId: string | null\n classNames: ZeugmaClassNames\n onRemove?: (paneId: string) => void\n onFullscreenChange?: (paneId: string | null) => void\n}\n\nexport const DashboardContext = createContext<DashboardContextValue | undefined>(undefined)\n\nexport const useDashboard = () => {\n const context = useContext(DashboardContext)\n if (!context) {\n throw new Error('useDashboard must be used within a DashboardProvider')\n }\n return context\n}\n\n// Tree Helper: Remove a pane and consolidate the tree\nexport function removePane(tree: TreeNode | null, idToRemove: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n return tree.paneId === idToRemove ? null : tree\n }\n const newFirst = removePane(tree.first, idToRemove)\n const newSecond = removePane(tree.second, idToRemove)\n if (newFirst === null) return newSecond\n if (newSecond === null) return newFirst\n return { ...tree, first: newFirst, second: newSecond }\n}\n\n// Tree Helper: Insert a pane by splitting an existing target\nexport function splitPane(\n tree: TreeNode | null,\n targetId: string,\n direction: SplitDirection,\n splitType: 'left' | 'right' | 'top' | 'bottom',\n paneToAdd: string,\n): TreeNode | null {\n if (tree === null) return { type: 'pane', paneId: paneToAdd }\n if (tree.type === 'pane') {\n if (tree.paneId === targetId) {\n const addedNode: PaneNode = { type: 'pane', paneId: paneToAdd }\n const originalNode: PaneNode = { type: 'pane', paneId: targetId }\n const isFirst = splitType === 'left' || splitType === 'top'\n return {\n type: 'split',\n direction,\n first: isFirst ? addedNode : originalNode,\n second: isFirst ? originalNode : addedNode,\n splitPercentage: 50,\n }\n }\n return tree\n }\n return {\n ...tree,\n first: splitPane(tree.first, targetId, direction, splitType, paneToAdd) || tree.first,\n second: splitPane(tree.second, targetId, direction, splitType, paneToAdd) || tree.second,\n }\n}\n\n// Tree Helper: Swap two pane positions in the tree\nexport function swapPanes(tree: TreeNode | null, idA: string, idB: string): TreeNode | null {\n if (tree === null) return null\n if (tree.type === 'pane') {\n if (tree.paneId === idA) return { ...tree, paneId: idB }\n if (tree.paneId === idB) return { ...tree, paneId: idA }\n return tree\n }\n return {\n ...tree,\n first: swapPanes(tree.first, idA, idB) || tree.first,\n second: swapPanes(tree.second, idA, idB) || tree.second,\n }\n}\n\n// Tree Helper: Add a pane by recursively splitting the rightmost/bottommost pane in the tree\nexport function addPane(tree: TreeNode | null, paneToAdd: string): TreeNode {\n if (tree === null) {\n return { type: 'pane', paneId: paneToAdd }\n }\n\n function insert(node: TreeNode, parentDirection: SplitDirection | null): TreeNode {\n if (node.type === 'pane') {\n const direction: SplitDirection = parentDirection === 'row' ? 'column' : 'row'\n return {\n type: 'split',\n direction,\n splitPercentage: 50,\n first: node,\n second: { type: 'pane', paneId: paneToAdd },\n }\n }\n\n return {\n ...node,\n second: insert(node.second, node.direction),\n }\n }\n\n return insert(tree, null)\n}\n\n/** Cursor-following overlay rendered via portal */\nconst CursorOverlay: React.FC<{\n activeId: string\n render: (id: string) => ReactNode\n className?: string\n}> = ({ activeId, render, className }) => {\n const ref = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n const handleMove = (e: PointerEvent) => {\n if (ref.current) {\n ref.current.style.transform = `translate(${e.clientX + 12}px, ${e.clientY + 12}px)`\n }\n }\n document.addEventListener('pointermove', handleMove)\n return () => document.removeEventListener('pointermove', handleMove)\n }, [])\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n zIndex: 9999,\n pointerEvents: 'none',\n }}\n >\n {render(activeId)}\n </div>\n )\n}\n\ninterface DashboardProviderProps {\n layout: TreeNode | null\n onChange: (newLayout: TreeNode | null) => void\n renderPane: (paneId: string) => ReactNode\n renderDragOverlay?: (activeId: string) => ReactNode\n classNames?: ZeugmaClassNames\n fullscreenPaneId?: string | null\n onFullscreenChange?: (paneId: string | null) => void\n onRemove?: (paneId: string) => void\n dragActivationDistance?: number\n children: ReactNode\n}\n\nexport const DashboardProvider: React.FC<DashboardProviderProps> = ({\n layout,\n onChange,\n renderPane,\n renderDragOverlay,\n classNames = {},\n fullscreenPaneId = null,\n onFullscreenChange,\n onRemove,\n dragActivationDistance = 8,\n children,\n}) => {\n const [activeId, setActiveId] = useState<string | null>(null)\n\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: { distance: dragActivationDistance },\n }),\n )\n\n const handleDragStart = (event: DragStartEvent) => {\n setActiveId(event.active.id.toString())\n }\n\n const handleDragEnd = (event: DragEndEvent) => {\n setActiveId(null)\n const { active, over } = event\n if (!over) return\n\n const draggingId = active.id.toString()\n const overIdStr = over.id.toString()\n\n // Check for center (swap) drop\n const swapMatch = overIdStr.match(/^drop-center-(.+)$/)\n if (swapMatch) {\n const [, targetId] = swapMatch\n if (draggingId !== targetId) {\n onChange(swapPanes(layout, draggingId, targetId))\n }\n return\n }\n\n // Check for edge (split) drop\n const match = overIdStr.match(/^drop-(left|right|top|bottom)-(.+)$/)\n if (!match) return\n\n const [, dropZone, targetId] = match\n if (draggingId === targetId) return\n\n const direction: SplitDirection = dropZone === 'left' || dropZone === 'right' ? 'row' : 'column'\n const treeWithoutDragging = removePane(layout, draggingId)\n\n const newLayout = splitPane(\n treeWithoutDragging,\n targetId,\n direction,\n dropZone as 'left' | 'right' | 'top' | 'bottom',\n draggingId,\n )\n onChange(newLayout)\n }\n\n return (\n <DashboardContext.Provider\n value={{\n layout,\n onLayoutChange: onChange,\n renderPane,\n activeId,\n fullscreenPaneId,\n classNames,\n onRemove,\n onFullscreenChange,\n }}\n >\n <DndContext\n sensors={sensors}\n collisionDetection={pointerWithin}\n onDragStart={handleDragStart}\n onDragEnd={handleDragEnd}\n >\n {children}\n </DndContext>\n {activeId && renderDragOverlay && (\n <CursorOverlay\n activeId={activeId}\n render={renderDragOverlay}\n className={classNames.dragOverlay}\n />\n )}\n </DashboardContext.Provider>\n )\n}\n","import React, { useRef } from 'react'\nimport { useDashboard } from './dashboard-provider'\nimport { TreeNode, SplitNode } from '../types'\n\ninterface PaneTreeProps {\n tree?: TreeNode | null\n /** Size of the resizer in pixels (default 4) */\n resizerSize?: number\n}\n\nfunction updateSplitPercentage(\n tree: TreeNode | null,\n target: SplitNode,\n newPercentage: number,\n): TreeNode | null {\n if (tree === null) return null\n if (tree === target) {\n return { ...tree, splitPercentage: newPercentage } as SplitNode\n }\n if (tree.type === 'split') {\n return {\n ...tree,\n first: updateSplitPercentage(tree.first, target, newPercentage) || tree.first,\n second: updateSplitPercentage(tree.second, target, newPercentage) || tree.second,\n }\n }\n return tree\n}\n\nexport const PaneTree: React.FC<PaneTreeProps> = ({ tree, resizerSize = 4 }) => {\n const { layout, onLayoutChange, renderPane, fullscreenPaneId, classNames } = useDashboard()\n const containerRef = useRef<HTMLDivElement>(null)\n\n // Fullscreen bypass\n if (fullscreenPaneId && !tree) {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(fullscreenPaneId)}\n </div>\n )\n }\n\n const currentNode = tree !== undefined ? tree : layout\n\n if (!currentNode) return null\n\n if (currentNode.type === 'pane') {\n return (\n <div style={{ width: '100%', height: '100%', position: 'relative' }}>\n {renderPane(currentNode.paneId)}\n </div>\n )\n }\n\n const { direction, first, second, splitPercentage } = currentNode\n const isRow = direction === 'row'\n\n const handlePointerDown = (e: React.PointerEvent) => {\n e.preventDefault()\n const container = containerRef.current\n if (!container) return\n\n document.body.classList.add('zeugma-resizing')\n\n const rect = container.getBoundingClientRect()\n const startX = e.clientX\n const startY = e.clientY\n const startPercentage = splitPercentage\n\n const handlePointerMove = (moveEvent: PointerEvent) => {\n const delta = isRow\n ? ((moveEvent.clientX - startX) / rect.width) * 100\n : ((moveEvent.clientY - startY) / rect.height) * 100\n const newPercentage = Math.max(5, Math.min(95, startPercentage + delta))\n const newLayout = updateSplitPercentage(layout, currentNode, newPercentage)\n onLayoutChange(newLayout)\n }\n\n const handlePointerUp = () => {\n document.body.classList.remove('zeugma-resizing')\n document.removeEventListener('pointermove', handlePointerMove)\n document.removeEventListener('pointerup', handlePointerUp)\n }\n\n document.addEventListener('pointermove', handlePointerMove)\n document.addEventListener('pointerup', handlePointerUp)\n }\n\n return (\n <div\n ref={containerRef}\n style={{\n display: 'flex',\n flexDirection: isRow ? 'row' : 'column',\n width: '100%',\n height: '100%',\n overflow: 'hidden',\n }}\n >\n <div style={{ flex: `${splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={first} resizerSize={resizerSize} />\n </div>\n <div\n className={classNames.resizer}\n style={{\n width: isRow ? `${resizerSize}px` : '100%',\n height: isRow ? '100%' : `${resizerSize}px`,\n cursor: isRow ? 'col-resize' : 'row-resize',\n position: 'relative',\n zIndex: 10,\n userSelect: 'none',\n boxSizing: 'border-box',\n flexShrink: 0,\n }}\n onPointerDown={handlePointerDown}\n role=\"separator\"\n aria-valuenow={splitPercentage}\n aria-valuemin={5}\n aria-valuemax={95}\n />\n <div style={{ flex: `${100 - splitPercentage} 1 0%`, overflow: 'hidden' }}>\n <PaneTree tree={second} resizerSize={resizerSize} />\n </div>\n </div>\n )\n}\n","import React, { createContext, useContext } from 'react'\nimport { useDraggable, useDroppable } from '@dnd-kit/core'\nimport { useDashboard } from './dashboard-provider'\n\n// Internal context for drag listeners\nconst DragListenersCtx = createContext<Record<string, unknown> | null>(null)\n\ninterface DropZoneProps {\n id: string\n position: 'top' | 'bottom' | 'left' | 'right' | 'center'\n activeClassName?: string\n}\n\nconst activationPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: '25%',\n width: '50%',\n height: '25%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '25%',\n height: '100%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n center: {\n position: 'absolute',\n top: '25%',\n left: '25%',\n width: '50%',\n height: '50%',\n zIndex: 20,\n pointerEvents: 'auto',\n },\n}\n\nconst previewPositions: Record<string, React.CSSProperties> = {\n top: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n bottom: {\n position: 'absolute',\n bottom: 0,\n left: 0,\n right: 0,\n height: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n left: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n left: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n right: {\n position: 'absolute',\n top: 0,\n bottom: 0,\n right: 0,\n width: '50%',\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n center: {\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 21,\n pointerEvents: 'none',\n boxSizing: 'border-box',\n },\n}\n\nconst DropZone: React.FC<DropZoneProps> = ({ id, position, activeClassName }) => {\n const { setNodeRef, isOver } = useDroppable({ id })\n return (\n <>\n <div ref={setNodeRef} style={activationPositions[position]} />\n {isOver && <div className={activeClassName} style={previewPositions[position]} />}\n </>\n )\n}\n\nexport interface PaneRenderProps {\n isDragging: boolean\n isFullscreen: boolean\n toggleFullscreen: () => void\n remove: () => void\n}\n\ninterface PaneProps {\n id: string\n children: (props: PaneRenderProps) => React.ReactNode\n style?: React.CSSProperties\n}\n\nexport const Pane: React.FC<PaneProps> = ({ id, children, style }) => {\n const { activeId, classNames, fullscreenPaneId, onRemove, onFullscreenChange } = useDashboard()\n const showDropZones = activeId !== null && activeId !== id\n\n const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id })\n const dragging = activeId === id || isDragging\n const isFullscreen = fullscreenPaneId === id\n\n const renderProps: PaneRenderProps = {\n isDragging: dragging,\n isFullscreen,\n toggleFullscreen: () => onFullscreenChange?.(isFullscreen ? null : id),\n remove: () => {\n if (isFullscreen) {\n onFullscreenChange?.(null)\n }\n onRemove?.(id)\n },\n }\n\n return (\n <DragListenersCtx.Provider value={{ ...listeners, ...attributes }}>\n <div\n ref={setNodeRef}\n className={classNames.pane}\n style={{ position: 'relative', width: '100%', height: '100%', ...style }}\n >\n {children(renderProps)}\n\n {showDropZones && (\n <div\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 15,\n pointerEvents: 'none',\n }}\n >\n {(['top', 'bottom', 'left', 'right'] as const).map((pos) => (\n <DropZone\n key={pos}\n id={`drop-${pos}-${id}`}\n position={pos}\n activeClassName={classNames.dropPreview}\n />\n ))}\n <DropZone\n id={`drop-center-${id}`}\n position=\"center\"\n activeClassName={classNames.swapPreview}\n />\n </div>\n )}\n </div>\n </DragListenersCtx.Provider>\n )\n}\n\n/**\n * Place inside a Pane to make an element the drag handle.\n */\ninterface DragHandleProps {\n children: React.ReactNode\n className?: string\n style?: React.CSSProperties\n}\n\nexport const DragHandle: React.FC<DragHandleProps> = ({ children, className, style }) => {\n const dragProps = useContext(DragListenersCtx)\n if (!dragProps) {\n throw new Error('<DragHandle> must be used inside a <Pane>')\n }\n return (\n <div\n className={className}\n style={{ cursor: 'grab', userSelect: 'none', ...style }}\n {...dragProps}\n >\n {children}\n </div>\n )\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-zeugma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Recursive drag-and-drop dashboard layout engine for React — combining the tree-based splitting of react-mosaic with the declarative API of react-grid-layout.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"bugs": {
|
|
29
29
|
"url": "https://github.com/yusufarsln98/react-zeugma/issues"
|
|
30
30
|
},
|
|
31
|
-
"homepage": "https://
|
|
31
|
+
"homepage": "https://github.com/yusufarsln98/react-zeugma#readme",
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public",
|
|
34
34
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -56,19 +56,21 @@
|
|
|
56
56
|
"typecheck": "tsc --noEmit",
|
|
57
57
|
"format": "prettier --write \"src/**/*.{ts,tsx}\" \"docs/**/*.{ts,tsx,mdx}\"",
|
|
58
58
|
"format:check": "prettier --check \"src/**/*.{ts,tsx}\" \"docs/**/*.{ts,tsx,mdx}\"",
|
|
59
|
-
"demo": "npm run dev --workspace=
|
|
59
|
+
"demo": "npm run dev --workspace=homepage",
|
|
60
|
+
"build:demo": "npm run build && npm run build --workspace=homepage",
|
|
60
61
|
"storybook": "storybook dev -p 6006",
|
|
61
|
-
"build
|
|
62
|
+
"build:storybook": "storybook build -o storybook-static",
|
|
62
63
|
"prepare": "husky",
|
|
63
|
-
"
|
|
64
|
-
"
|
|
64
|
+
"version": "changeset version",
|
|
65
|
+
"release": "npm run build && changeset publish"
|
|
65
66
|
},
|
|
66
67
|
"peerDependencies": {
|
|
67
68
|
"react": "^18.0.0 || ^19.0.0",
|
|
68
69
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
69
70
|
},
|
|
70
71
|
"workspaces": [
|
|
71
|
-
"
|
|
72
|
+
".",
|
|
73
|
+
"homepage"
|
|
72
74
|
],
|
|
73
75
|
"dependencies": {
|
|
74
76
|
"@dnd-kit/core": "^6.3.1",
|