@dxos/react-ui-mosaic 0.9.1-staging.ee54ba693a → 0.11.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/dist/lib/chunk-Mosaic.mjs +1024 -0
- package/dist/lib/chunk-Mosaic.mjs.map +1 -0
- package/dist/lib/index.mjs +653 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/playwright.mjs +200 -0
- package/dist/lib/playwright.mjs.map +1 -0
- package/dist/lib/testing.mjs +127 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +11 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/components/Board/Board.d.ts +7 -27
- package/dist/types/src/components/Board/Board.d.ts.map +1 -1
- package/dist/types/src/components/Board/Board.stories.d.ts.map +1 -1
- package/dist/types/src/components/Board/BoardColumnContext.d.ts +10 -0
- package/dist/types/src/components/Board/BoardColumnContext.d.ts.map +1 -0
- package/dist/types/src/components/Board/BoardContext.d.ts +26 -0
- package/dist/types/src/components/Board/BoardContext.d.ts.map +1 -0
- package/dist/types/src/components/Board/Column.d.ts +2 -7
- package/dist/types/src/components/Board/Column.d.ts.map +1 -1
- package/dist/types/src/components/Board/index.d.ts +2 -0
- package/dist/types/src/components/Board/index.d.ts.map +1 -1
- package/dist/types/src/components/Focus/Focus.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Container.d.ts +6 -34
- package/dist/types/src/components/Mosaic/Container.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Mosaic.d.ts +10 -15
- package/dist/types/src/components/Mosaic/Mosaic.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/MosaicContainerContext.d.ts +34 -0
- package/dist/types/src/components/Mosaic/MosaicContainerContext.d.ts.map +1 -0
- package/dist/types/src/components/Mosaic/MosaicTileContext.d.ts +31 -0
- package/dist/types/src/components/Mosaic/MosaicTileContext.d.ts.map +1 -0
- package/dist/types/src/components/Mosaic/Placeholder.d.ts +3 -3
- package/dist/types/src/components/Mosaic/Placeholder.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Stack.d.ts +8 -2
- package/dist/types/src/components/Mosaic/Stack.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Stack.stories.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/Tile.d.ts +6 -32
- package/dist/types/src/components/Mosaic/Tile.d.ts.map +1 -1
- package/dist/types/src/components/Mosaic/VirtualStackPagination.stories.d.ts +13 -0
- package/dist/types/src/components/Mosaic/VirtualStackPagination.stories.d.ts.map +1 -0
- package/dist/types/src/components/Mosaic/index.d.ts +0 -1
- package/dist/types/src/components/Mosaic/index.d.ts.map +1 -1
- package/dist/types/src/components/SearchStack/SearchStack.d.ts +1 -1
- package/dist/types/src/components/SearchStack/SearchStack.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +1 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useDefaultColumnEventHandler.d.ts +2 -2
- package/dist/types/src/hooks/useDefaultColumnEventHandler.d.ts.map +1 -1
- package/dist/types/src/hooks/useEventHandlerAdapter.d.ts +3 -3
- package/dist/types/src/hooks/useEventHandlerAdapter.d.ts.map +1 -1
- package/dist/types/src/hooks/useVirtualizerPagination.d.ts +60 -0
- package/dist/types/src/hooks/useVirtualizerPagination.d.ts.map +1 -0
- package/dist/types/src/hooks/useVirtualizerPagination.test.d.ts +2 -0
- package/dist/types/src/hooks/useVirtualizerPagination.test.d.ts.map +1 -0
- package/dist/types/src/hooks/useVisibleItems.d.ts +2 -2
- package/dist/types/src/hooks/useVisibleItems.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +35 -37
- package/src/components/Board/Board.stories.tsx +7 -6
- package/src/components/Board/Board.tsx +9 -54
- package/src/components/Board/BoardColumnContext.ts +25 -0
- package/src/components/Board/BoardContext.ts +43 -0
- package/src/components/Board/Column.tsx +13 -27
- package/src/components/Board/Item.tsx +2 -2
- package/src/components/Board/index.ts +3 -0
- package/src/components/Mosaic/Container.tsx +31 -53
- package/src/components/Mosaic/DragHandle.tsx +1 -1
- package/src/components/Mosaic/{Mosaic.tsx → Mosaic.ts} +5 -16
- package/src/components/Mosaic/MosaicContainerContext.ts +44 -0
- package/src/components/Mosaic/MosaicTileContext.ts +34 -0
- package/src/components/Mosaic/Placeholder.tsx +7 -8
- package/src/components/Mosaic/ResizeHandle.stories.tsx +4 -4
- package/src/components/Mosaic/ResizeHandle.tsx +2 -2
- package/src/components/Mosaic/Stack.stories.tsx +49 -13
- package/src/components/Mosaic/Stack.tsx +30 -9
- package/src/components/Mosaic/Tile.tsx +33 -33
- package/src/components/Mosaic/VirtualStackPagination.stories.tsx +423 -0
- package/src/components/Mosaic/index.ts +0 -1
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useDefaultColumnEventHandler.ts +2 -2
- package/src/hooks/useEventHandlerAdapter.ts +4 -5
- package/src/hooks/useVirtualizerPagination.test.tsx +105 -0
- package/src/hooks/useVirtualizerPagination.ts +473 -0
- package/src/hooks/useVisibleItems.ts +2 -2
- package/src/playwright/smoke.spec.ts +4 -1
- package/src/testing/DefaultStackTile.tsx +1 -1
- package/src/testing/decorator.tsx +3 -3
- package/dist/lib/browser/chunk-OBVIYZLR.mjs +0 -1119
- package/dist/lib/browser/chunk-OBVIYZLR.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -701
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/playwright/index.mjs +0 -256
- package/dist/lib/browser/playwright/index.mjs.map +0 -7
- package/dist/lib/browser/testing/index.mjs +0 -136
- package/dist/lib/browser/testing/index.mjs.map +0 -7
- package/dist/lib/browser/translations.mjs +0 -18
- package/dist/lib/browser/translations.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-4IEMCMIV.mjs +0 -1121
- package/dist/lib/node-esm/chunk-4IEMCMIV.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -702
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/playwright/index.mjs +0 -258
- package/dist/lib/node-esm/playwright/index.mjs.map +0 -7
- package/dist/lib/node-esm/testing/index.mjs +0 -137
- package/dist/lib/node-esm/testing/index.mjs.map +0 -7
- package/dist/lib/node-esm/translations.mjs +0 -20
- package/dist/lib/node-esm/translations.mjs.map +0 -7
- package/dist/types/src/components/Mosaic/Root.d.ts +0 -35
- package/dist/types/src/components/Mosaic/Root.d.ts.map +0 -1
- package/dist/types/src/components/Mosaic/types.d.ts +0 -86
- package/dist/types/src/components/Mosaic/types.d.ts.map +0 -1
- package/src/components/Mosaic/Root.tsx +0 -288
- package/src/components/Mosaic/types.ts +0 -94
- /package/src/components/Focus/{Focus.tsx → Focus.ts} +0 -0
|
@@ -1,1121 +0,0 @@
|
|
|
1
|
-
import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
|
|
2
|
-
|
|
3
|
-
// src/hooks/useVisibleItems.ts
|
|
4
|
-
import { useMemo } from "react";
|
|
5
|
-
var useVisibleItems = ({ id, items, dragging, getId }) => {
|
|
6
|
-
const visibleItems = useMemo(() => {
|
|
7
|
-
if (!items || !dragging || id !== dragging.containerId) {
|
|
8
|
-
return items ?? [];
|
|
9
|
-
}
|
|
10
|
-
const idx = items.findIndex((item) => getId(item) === dragging.id);
|
|
11
|
-
if (idx === -1) {
|
|
12
|
-
return items;
|
|
13
|
-
}
|
|
14
|
-
const visibleItems2 = items.slice();
|
|
15
|
-
visibleItems2.splice(idx, 1);
|
|
16
|
-
return visibleItems2;
|
|
17
|
-
}, [
|
|
18
|
-
id,
|
|
19
|
-
items,
|
|
20
|
-
dragging,
|
|
21
|
-
getId
|
|
22
|
-
]);
|
|
23
|
-
return visibleItems;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// src/components/Focus/Focus.tsx
|
|
27
|
-
import { Focus, useFocus } from "@dxos/react-ui";
|
|
28
|
-
|
|
29
|
-
// src/components/Mosaic/styles.ts
|
|
30
|
-
var styles = {
|
|
31
|
-
placeholder: {
|
|
32
|
-
root: [
|
|
33
|
-
"group opacity-0",
|
|
34
|
-
'group-data-[mosaic-debug="true"]:opacity-100',
|
|
35
|
-
'group-data-[mosaic-debug="true"]:bg-orange-500',
|
|
36
|
-
"data-[mosaic-placeholder-state=active]:opacity-100",
|
|
37
|
-
"data-[mosaic-placeholder-orientation=vertical]:snap-start",
|
|
38
|
-
"data-[mosaic-placeholder-orientation=vertical]:py-1",
|
|
39
|
-
"data-[mosaic-placeholder-orientation=vertical]:data-[mosaic-placeholder-state=active]:py-2.5",
|
|
40
|
-
"data-[mosaic-placeholder-orientation=horizontal]:px-1",
|
|
41
|
-
"data-[mosaic-placeholder-orientation=horizontal]:data-[mosaic-placeholder-state=active]:px-2.5"
|
|
42
|
-
],
|
|
43
|
-
content: [
|
|
44
|
-
"transition-all duration-0",
|
|
45
|
-
// Placeholders open instantly (`duration-0`). The source slot is reserved on drag start by
|
|
46
|
-
// activating its placeholder (see Stack.tsx), so the stack no longer collapses/flickers when the
|
|
47
|
-
// dragged item is removed. NOTE: if the open animation below is ever enabled, exempt the source
|
|
48
|
-
// placeholder — animating its reserved gap from 0 would reintroduce the start-of-drag flicker.
|
|
49
|
-
// 'group-data-[mosaic-placeholder-state=active]:duration-200',
|
|
50
|
-
"group-data-[mosaic-placeholder-orientation=vertical]:h-0",
|
|
51
|
-
"group-data-[mosaic-placeholder-orientation=vertical]:group-data-[mosaic-placeholder-state=active]:h-[var(--mosaic-placeholder-height)]",
|
|
52
|
-
"group-data-[mosaic-placeholder-orientation=horizontal]:w-0",
|
|
53
|
-
"group-data-[mosaic-placeholder-orientation=horizontal]:group-data-[mosaic-placeholder-state=active]:w-[var(--mosaic-placeholder-width)]"
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// src/components/Mosaic/types.ts
|
|
59
|
-
var getSourceData = (source) => {
|
|
60
|
-
return source.data.type === "tile" ? source.data : null;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// src/components/Mosaic/Root.tsx
|
|
64
|
-
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
|
65
|
-
import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
66
|
-
import { useComposedRefs } from "@radix-ui/react-compose-refs";
|
|
67
|
-
import { createContext } from "@radix-ui/react-context";
|
|
68
|
-
import { Primitive } from "@radix-ui/react-primitive";
|
|
69
|
-
import { Slot } from "@radix-ui/react-slot";
|
|
70
|
-
import React, { forwardRef, useCallback, useEffect, useRef, useState } from "react";
|
|
71
|
-
import { log } from "@dxos/log";
|
|
72
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/ui/react-ui-mosaic/src/components/Mosaic/Root.tsx";
|
|
73
|
-
var [MosaicRootContextProvider, useMosaicRootContext] = createContext("MosaicRoot");
|
|
74
|
-
var MOSAIC_ROOT_NAME = "Mosaic.Root";
|
|
75
|
-
var MOSAIC_ROOT_DEBUG_ATTR = "mosaic-debug";
|
|
76
|
-
var MosaicRoot = /* @__PURE__ */ forwardRef(({ children, asChild, debug }, forwardedRef) => {
|
|
77
|
-
const rootRef = useRef(null);
|
|
78
|
-
const composedRef = useComposedRefs(rootRef, forwardedRef);
|
|
79
|
-
const Comp = asChild ? Slot : Primitive.div;
|
|
80
|
-
const [handlers, setHandlers] = useState({});
|
|
81
|
-
const [dragging, setDragging] = useState();
|
|
82
|
-
const getSourceHandler = useCallback((source) => {
|
|
83
|
-
const data = source.data;
|
|
84
|
-
return {
|
|
85
|
-
data,
|
|
86
|
-
handler: handlers[data.containerId]
|
|
87
|
-
};
|
|
88
|
-
}, [
|
|
89
|
-
handlers
|
|
90
|
-
]);
|
|
91
|
-
const getTargetHandler = useCallback((location) => {
|
|
92
|
-
for (const target of location.current.dropTargets) {
|
|
93
|
-
const data = target.data;
|
|
94
|
-
let containerId;
|
|
95
|
-
switch (data.type) {
|
|
96
|
-
case "tile":
|
|
97
|
-
case "placeholder":
|
|
98
|
-
containerId = data.containerId;
|
|
99
|
-
break;
|
|
100
|
-
case "container":
|
|
101
|
-
containerId = data.id;
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
const handler = handlers[containerId];
|
|
105
|
-
if (handler) {
|
|
106
|
-
return {
|
|
107
|
-
data,
|
|
108
|
-
handler
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return {};
|
|
113
|
-
}, [
|
|
114
|
-
handlers
|
|
115
|
-
]);
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
const handleChange = ({ source, location }) => {
|
|
118
|
-
const { data: sourceData } = getSourceHandler(source);
|
|
119
|
-
const { data: targetData, handler } = getTargetHandler(location);
|
|
120
|
-
setDragging((dragging2) => {
|
|
121
|
-
dragging2?.target?.handler?.onCancel?.();
|
|
122
|
-
return {
|
|
123
|
-
source: {
|
|
124
|
-
data: sourceData,
|
|
125
|
-
handler: handlers[sourceData.containerId],
|
|
126
|
-
// TODO(burdon): Check id matches.
|
|
127
|
-
container: location.initial.dropTargets.find((target) => target.data.type === "container")?.element
|
|
128
|
-
},
|
|
129
|
-
target: targetData && {
|
|
130
|
-
data: targetData,
|
|
131
|
-
handler
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
});
|
|
135
|
-
};
|
|
136
|
-
const handleCancel = () => {
|
|
137
|
-
setDragging((dragging2) => {
|
|
138
|
-
requestAnimationFrame(() => {
|
|
139
|
-
dragging2?.target?.handler?.onCancel?.();
|
|
140
|
-
dragging2?.source?.container?.dispatchEvent(new CustomEvent("dnd:cancel", {
|
|
141
|
-
bubbles: true
|
|
142
|
-
}));
|
|
143
|
-
});
|
|
144
|
-
return void 0;
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
|
-
let noTargetTimeout;
|
|
148
|
-
return combine(monitorForElements({
|
|
149
|
-
// Only monitor Mosaic tile drags; other pragmatic-dnd sources under this root are not ours to handle.
|
|
150
|
-
canMonitor: ({ source }) => source.data.type === "tile",
|
|
151
|
-
/**
|
|
152
|
-
* Dragging started within any container.
|
|
153
|
-
*/
|
|
154
|
-
onDragStart: ({ source, location }) => {
|
|
155
|
-
log("Root.onDragStart", {
|
|
156
|
-
source: source.data,
|
|
157
|
-
location: location.current.dropTargets.map((target) => target.data)
|
|
158
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 98, S: void 0 });
|
|
159
|
-
handleChange({
|
|
160
|
-
source,
|
|
161
|
-
location
|
|
162
|
-
});
|
|
163
|
-
},
|
|
164
|
-
/**
|
|
165
|
-
* Dragging entered a new container.
|
|
166
|
-
*/
|
|
167
|
-
onDropTargetChange: ({ source, location }) => {
|
|
168
|
-
clearTimeout(noTargetTimeout);
|
|
169
|
-
log("Root.onDropTargetChange", {
|
|
170
|
-
source: source.data,
|
|
171
|
-
location: location.current.dropTargets.map((target) => target.data)
|
|
172
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 111, S: void 0 });
|
|
173
|
-
if (location.current.dropTargets.length === 0) {
|
|
174
|
-
noTargetTimeout = setTimeout(() => setDragging(void 0), 1e3);
|
|
175
|
-
} else {
|
|
176
|
-
handleChange({
|
|
177
|
-
source,
|
|
178
|
-
location
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
/**
|
|
183
|
-
* Dragging within any container.
|
|
184
|
-
*/
|
|
185
|
-
onDrag: ({ source, location }) => {
|
|
186
|
-
const { data } = getSourceHandler(source);
|
|
187
|
-
const { handler } = getTargetHandler(location);
|
|
188
|
-
if (handler) {
|
|
189
|
-
const { clientX: x, clientY: y } = location.current.input;
|
|
190
|
-
handler.onDrag?.({
|
|
191
|
-
source: data,
|
|
192
|
-
position: {
|
|
193
|
-
x,
|
|
194
|
-
y
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
},
|
|
199
|
-
/**
|
|
200
|
-
* Dragging ended.
|
|
201
|
-
*/
|
|
202
|
-
onDrop: ({ source, location }) => {
|
|
203
|
-
log.info("Root.onDrop", {
|
|
204
|
-
source: source.data,
|
|
205
|
-
location: location.current.dropTargets.map((target) => target.data)
|
|
206
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 144, S: void 0 });
|
|
207
|
-
const { data: sourceData, handler: sourceHandler } = getSourceHandler(source);
|
|
208
|
-
if (!sourceHandler) {
|
|
209
|
-
log.warn("invalid source", {
|
|
210
|
-
source: sourceData,
|
|
211
|
-
handlers: Object.keys(handlers)
|
|
212
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 151, S: void 0 });
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
try {
|
|
216
|
-
if (location.current.dropTargets.length === 0) {
|
|
217
|
-
log.info("cancelled", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 165, S: void 0 });
|
|
218
|
-
} else {
|
|
219
|
-
const { data: targetData, handler: targetHandler } = getTargetHandler(location);
|
|
220
|
-
if (!targetHandler) {
|
|
221
|
-
log.warn("invalid target", {
|
|
222
|
-
source: sourceData,
|
|
223
|
-
location,
|
|
224
|
-
handlers: Object.keys(handlers)
|
|
225
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 170, S: void 0 });
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
if (sourceHandler === targetHandler) {
|
|
229
|
-
targetHandler.onDrop?.({
|
|
230
|
-
source: sourceData,
|
|
231
|
-
target: targetData
|
|
232
|
-
});
|
|
233
|
-
} else {
|
|
234
|
-
if (!sourceHandler.onTake) {
|
|
235
|
-
log.warn("invalid source", {
|
|
236
|
-
source: sourceData
|
|
237
|
-
}, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 185, S: void 0 });
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
sourceHandler.onTake?.({
|
|
241
|
-
source: sourceData
|
|
242
|
-
}, async (object) => {
|
|
243
|
-
targetHandler.onDrop?.({
|
|
244
|
-
source: {
|
|
245
|
-
...sourceData,
|
|
246
|
-
data: object
|
|
247
|
-
},
|
|
248
|
-
target: targetData
|
|
249
|
-
});
|
|
250
|
-
return true;
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
} finally {
|
|
255
|
-
handleCancel();
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}));
|
|
259
|
-
}, [
|
|
260
|
-
handlers,
|
|
261
|
-
getSourceHandler,
|
|
262
|
-
getTargetHandler
|
|
263
|
-
]);
|
|
264
|
-
return /* @__PURE__ */ React.createElement(MosaicRootContextProvider, {
|
|
265
|
-
containers: handlers,
|
|
266
|
-
addContainer: (container) => setHandlers((containers) => ({
|
|
267
|
-
...containers,
|
|
268
|
-
[container.id]: container
|
|
269
|
-
})),
|
|
270
|
-
removeContainer: (id) => setHandlers((containers) => {
|
|
271
|
-
delete containers[id];
|
|
272
|
-
return {
|
|
273
|
-
...containers
|
|
274
|
-
};
|
|
275
|
-
}),
|
|
276
|
-
dragging
|
|
277
|
-
}, /* @__PURE__ */ React.createElement(Comp, {
|
|
278
|
-
className: "contents group",
|
|
279
|
-
[`data-${MOSAIC_ROOT_DEBUG_ATTR}`]: debug,
|
|
280
|
-
ref: composedRef
|
|
281
|
-
}, children));
|
|
282
|
-
});
|
|
283
|
-
MosaicRoot.displayName = MOSAIC_ROOT_NAME;
|
|
284
|
-
|
|
285
|
-
// src/components/Mosaic/Container.tsx
|
|
286
|
-
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
|
287
|
-
import { combine as combine2 } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
|
288
|
-
import { dropTargetForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
289
|
-
import { useComposedRefs as useComposedRefs2 } from "@radix-ui/react-compose-refs";
|
|
290
|
-
import { createContext as createContext2 } from "@radix-ui/react-context";
|
|
291
|
-
import { Primitive as Primitive2 } from "@radix-ui/react-primitive";
|
|
292
|
-
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
293
|
-
import { bind } from "bind-event-listener";
|
|
294
|
-
import React2, { useCallback as useCallback2, useEffect as useEffect2, useImperativeHandle, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
295
|
-
import { composable, composableProps } from "@dxos/react-ui";
|
|
296
|
-
import { isTruthy } from "@dxos/util";
|
|
297
|
-
var MOSAIC_CONTAINER_NAME = "Mosaic.Container";
|
|
298
|
-
var [MosaicContainerContextProvider, useMosaicContainerContext] = createContext2("MosaicContainer");
|
|
299
|
-
var MOSAIC_CONTAINER_STATE_ATTR = "mosaic-container-state";
|
|
300
|
-
var MOSAIC_CONTAINER_PLACEHOLDER_WIDTH = "--mosaic-placeholder-width";
|
|
301
|
-
var MOSAIC_CONTAINER_PLACEHOLDER_HEIGHT = "--mosaic-placeholder-height";
|
|
302
|
-
var counter = 0;
|
|
303
|
-
var MosaicContainer = composable(({ children, eventHandler: eventHandlerProp, orientation = "vertical", asChild, autoScroll: autoscrollElement, withFocus, controllerRef, currentId, onCurrentChange, selectedIds, onSelectionChange, debug, ...props }, forwardedRef) => {
|
|
304
|
-
const Comp = asChild ? Slot2 : Primitive2.div;
|
|
305
|
-
const rootRef = useRef2(null);
|
|
306
|
-
const composedRef = useComposedRefs2(rootRef, forwardedRef);
|
|
307
|
-
const eventHandler = useMemo2(() => eventHandlerProp ?? {
|
|
308
|
-
id: `mosaic-container-${counter++}`
|
|
309
|
-
}, [
|
|
310
|
-
eventHandlerProp
|
|
311
|
-
]);
|
|
312
|
-
const { dragging } = useMosaicRootContext(MOSAIC_CONTAINER_NAME);
|
|
313
|
-
const [state, setState] = useState2({
|
|
314
|
-
type: "idle"
|
|
315
|
-
});
|
|
316
|
-
const [activeLocation, setActiveLocation] = useState2();
|
|
317
|
-
const [scrolling, setScrolling] = useState2(false);
|
|
318
|
-
const setCurrentId = useCallback2((id) => onCurrentChange?.(id), [
|
|
319
|
-
onCurrentChange
|
|
320
|
-
]);
|
|
321
|
-
const setSelected = useCallback2((id, selected) => onSelectionChange?.(id, selected), [
|
|
322
|
-
onSelectionChange
|
|
323
|
-
]);
|
|
324
|
-
const scrollToRef = useRef2(void 0);
|
|
325
|
-
const registerScrollTo = useCallback2((fn) => {
|
|
326
|
-
scrollToRef.current = fn;
|
|
327
|
-
}, []);
|
|
328
|
-
useImperativeHandle(controllerRef, () => ({
|
|
329
|
-
scrollToItem: (id) => scrollToRef.current?.(id)
|
|
330
|
-
}), []);
|
|
331
|
-
useEffect2(() => {
|
|
332
|
-
if (currentId) {
|
|
333
|
-
scrollToRef.current?.(currentId);
|
|
334
|
-
}
|
|
335
|
-
}, [
|
|
336
|
-
currentId
|
|
337
|
-
]);
|
|
338
|
-
const { setFocus } = useFocus();
|
|
339
|
-
useEffect2(() => {
|
|
340
|
-
if (withFocus) {
|
|
341
|
-
setFocus?.(state.type === "active" ? "active" : void 0);
|
|
342
|
-
}
|
|
343
|
-
}, [
|
|
344
|
-
setFocus,
|
|
345
|
-
withFocus,
|
|
346
|
-
state
|
|
347
|
-
]);
|
|
348
|
-
const { addContainer, removeContainer } = useMosaicRootContext(eventHandler.id);
|
|
349
|
-
useEffect2(() => {
|
|
350
|
-
addContainer(eventHandler);
|
|
351
|
-
return () => removeContainer(eventHandler.id);
|
|
352
|
-
}, [
|
|
353
|
-
eventHandler
|
|
354
|
-
]);
|
|
355
|
-
const data = useMemo2(() => ({
|
|
356
|
-
type: "container",
|
|
357
|
-
id: eventHandler.id
|
|
358
|
-
}), [
|
|
359
|
-
eventHandler.id
|
|
360
|
-
]);
|
|
361
|
-
useEffect2(() => {
|
|
362
|
-
if (!rootRef.current) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
let timeout;
|
|
366
|
-
const handleScroll = () => {
|
|
367
|
-
setScrolling(true);
|
|
368
|
-
clearTimeout(timeout);
|
|
369
|
-
timeout = setTimeout(() => {
|
|
370
|
-
setScrolling(false);
|
|
371
|
-
}, 500);
|
|
372
|
-
};
|
|
373
|
-
return combine2(...[
|
|
374
|
-
/**
|
|
375
|
-
* Custom event for dragging cancellation.
|
|
376
|
-
*/
|
|
377
|
-
bind(rootRef.current, {
|
|
378
|
-
type: "dnd:cancel",
|
|
379
|
-
listener: () => {
|
|
380
|
-
setState({
|
|
381
|
-
type: "idle"
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
}),
|
|
385
|
-
// Target.
|
|
386
|
-
dropTargetForElements({
|
|
387
|
-
element: rootRef.current,
|
|
388
|
-
getData: () => data,
|
|
389
|
-
/**
|
|
390
|
-
* Test if permitted to drop here.
|
|
391
|
-
* NOTE: Contained Tile and Placeholder elements do the same.
|
|
392
|
-
*/
|
|
393
|
-
canDrop: ({ source }) => {
|
|
394
|
-
const data2 = getSourceData(source);
|
|
395
|
-
return data2 && eventHandler.canDrop?.({
|
|
396
|
-
source: data2
|
|
397
|
-
}) || false;
|
|
398
|
-
},
|
|
399
|
-
// Reorder is a move, not a copy — otherwise the browser shows the green "+" copy cursor.
|
|
400
|
-
getDropEffect: () => "move",
|
|
401
|
-
/**
|
|
402
|
-
* Dragging started in this container.
|
|
403
|
-
*/
|
|
404
|
-
onDragStart: ({ source }) => {
|
|
405
|
-
const sourceData = source.data;
|
|
406
|
-
setState({
|
|
407
|
-
type: "active",
|
|
408
|
-
bounds: sourceData.bounds
|
|
409
|
-
});
|
|
410
|
-
},
|
|
411
|
-
/**
|
|
412
|
-
* Dragging entered this container.
|
|
413
|
-
*/
|
|
414
|
-
onDragEnter: ({ source }) => {
|
|
415
|
-
const sourceData = source.data;
|
|
416
|
-
setState({
|
|
417
|
-
type: "active",
|
|
418
|
-
bounds: sourceData.bounds
|
|
419
|
-
});
|
|
420
|
-
},
|
|
421
|
-
/**
|
|
422
|
-
* Dragging left this container.
|
|
423
|
-
* NOTE: If the container isn't full-height, then when the dragged item is temporarily removed the container will shrink,
|
|
424
|
-
* triggering `onDragLeave`, which then causes the item to be added and removed continually (flickering).
|
|
425
|
-
*/
|
|
426
|
-
onDragLeave: ({ source }) => {
|
|
427
|
-
const sourceData = source.data;
|
|
428
|
-
if (sourceData.containerId !== eventHandler.id) {
|
|
429
|
-
setState({
|
|
430
|
-
type: "idle"
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
},
|
|
434
|
-
/**
|
|
435
|
-
* Dropped in this container.
|
|
436
|
-
*/
|
|
437
|
-
onDrop: () => {
|
|
438
|
-
setState({
|
|
439
|
-
type: "idle"
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
}),
|
|
443
|
-
// Autoscroll.
|
|
444
|
-
// NOTE: When used with Scrollable we get a spurious warning (in dev mode).
|
|
445
|
-
// "Auto scrolling has been attached to an element that appears not to be scrollable."
|
|
446
|
-
autoscrollElement && [
|
|
447
|
-
autoScrollForElements({
|
|
448
|
-
element: autoscrollElement,
|
|
449
|
-
// Only autoscroll for tile (reorder) drags. Resize-handle drags carry no tile data, so
|
|
450
|
-
// resizing a tile near a viewport edge must not scroll the container.
|
|
451
|
-
canScroll: ({ source }) => getSourceData(source) != null,
|
|
452
|
-
getAllowedAxis: () => orientation,
|
|
453
|
-
getConfiguration: () => ({
|
|
454
|
-
maxScrollSpeed: "fast"
|
|
455
|
-
})
|
|
456
|
-
}),
|
|
457
|
-
bind(autoscrollElement, {
|
|
458
|
-
type: "scroll",
|
|
459
|
-
listener: handleScroll
|
|
460
|
-
}),
|
|
461
|
-
() => setScrolling(false)
|
|
462
|
-
]
|
|
463
|
-
].filter(isTruthy).flatMap((x) => x));
|
|
464
|
-
}, [
|
|
465
|
-
rootRef,
|
|
466
|
-
eventHandler,
|
|
467
|
-
data,
|
|
468
|
-
autoscrollElement
|
|
469
|
-
]);
|
|
470
|
-
return /* @__PURE__ */ React2.createElement(MosaicContainerContextProvider, {
|
|
471
|
-
id: eventHandler.id,
|
|
472
|
-
eventHandler,
|
|
473
|
-
orientation,
|
|
474
|
-
state,
|
|
475
|
-
dragging: state.type === "active" ? dragging : void 0,
|
|
476
|
-
scrolling,
|
|
477
|
-
activeLocation,
|
|
478
|
-
setActiveLocation,
|
|
479
|
-
currentId,
|
|
480
|
-
setCurrentId,
|
|
481
|
-
selectedIds,
|
|
482
|
-
setSelected,
|
|
483
|
-
registerScrollTo
|
|
484
|
-
}, /* @__PURE__ */ React2.createElement(Comp, {
|
|
485
|
-
...composableProps(props, {
|
|
486
|
-
classNames: "h-full",
|
|
487
|
-
style: {
|
|
488
|
-
[MOSAIC_CONTAINER_PLACEHOLDER_WIDTH]: state.type === "active" && state.bounds ? `${state.bounds.width}px` : "0px",
|
|
489
|
-
[MOSAIC_CONTAINER_PLACEHOLDER_HEIGHT]: state.type === "active" && state.bounds ? `${state.bounds.height}px` : "0px"
|
|
490
|
-
}
|
|
491
|
-
}),
|
|
492
|
-
[`data-${MOSAIC_CONTAINER_STATE_ATTR}`]: state.type,
|
|
493
|
-
ref: composedRef
|
|
494
|
-
}, children), debug?.());
|
|
495
|
-
});
|
|
496
|
-
MosaicContainer.displayName = MOSAIC_CONTAINER_NAME;
|
|
497
|
-
|
|
498
|
-
// src/components/Mosaic/Tile.tsx
|
|
499
|
-
import { attachClosestEdge, extractClosestEdge } from "@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge";
|
|
500
|
-
import { combine as combine3 } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
|
501
|
-
import { draggable, dropTargetForElements as dropTargetForElements2 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
502
|
-
import { preserveOffsetOnSource } from "@atlaskit/pragmatic-drag-and-drop/element/preserve-offset-on-source";
|
|
503
|
-
import { setCustomNativeDragPreview } from "@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview";
|
|
504
|
-
import { composeRefs } from "@radix-ui/react-compose-refs";
|
|
505
|
-
import { createContext as createContext3 } from "@radix-ui/react-context";
|
|
506
|
-
import { Primitive as Primitive3 } from "@radix-ui/react-primitive";
|
|
507
|
-
import { Slot as Slot3 } from "@radix-ui/react-slot";
|
|
508
|
-
import React3, { useCallback as useCallback3, useLayoutEffect, useMemo as useMemo3, useRef as useRef3, useState as useState3 } from "react";
|
|
509
|
-
import { createPortal } from "react-dom";
|
|
510
|
-
import { composableProps as composableProps2, slottable } from "@dxos/react-ui";
|
|
511
|
-
import { resizeAttributes, sizeStyle } from "@dxos/react-ui-dnd";
|
|
512
|
-
var MOSAIC_TILE_NAME = "Mosaic.Tile";
|
|
513
|
-
var [MosaicTileContextProvider, useMosaicTileContext] = createContext3("MosaicTile");
|
|
514
|
-
var MOSAIC_TILE_STATE_ATTR = "mosaic-tile-state";
|
|
515
|
-
var MosaicTile = slottable(({ children, asChild, dragHandle: dragHandleProp, allowedEdges: allowedEdgesProp, location, id, data: dataProp, draggable: draggableProp, current, selected, size: sizeProp, onSizeChange, minSize, maxSize, debug: _, ...props }, forwardedRef) => {
|
|
516
|
-
const Comp = asChild ? Slot3 : Primitive3.div;
|
|
517
|
-
const rootRef = useRef3(null);
|
|
518
|
-
const composedRef = composeRefs(rootRef, forwardedRef);
|
|
519
|
-
const { id: containerId, eventHandler, orientation, scrolling, setActiveLocation } = useMosaicContainerContext(MOSAIC_TILE_NAME);
|
|
520
|
-
const [state, setState] = useState3({
|
|
521
|
-
type: "idle"
|
|
522
|
-
});
|
|
523
|
-
const [registeredDragHandle, setRegisteredDragHandle] = useState3(null);
|
|
524
|
-
const dragHandle = dragHandleProp ?? registeredDragHandle;
|
|
525
|
-
const [size, setInternalSize] = useState3(sizeProp);
|
|
526
|
-
const setSize = useCallback3((nextSize, commit) => {
|
|
527
|
-
setInternalSize(nextSize);
|
|
528
|
-
if (commit) {
|
|
529
|
-
onSizeChange?.(nextSize);
|
|
530
|
-
}
|
|
531
|
-
}, [
|
|
532
|
-
onSizeChange
|
|
533
|
-
]);
|
|
534
|
-
const allowedEdges = useMemo3(() => allowedEdgesProp || (orientation === "vertical" ? [
|
|
535
|
-
"top",
|
|
536
|
-
"bottom"
|
|
537
|
-
] : [
|
|
538
|
-
"left",
|
|
539
|
-
"right"
|
|
540
|
-
]), [
|
|
541
|
-
allowedEdgesProp,
|
|
542
|
-
orientation
|
|
543
|
-
]);
|
|
544
|
-
const data = useMemo3(() => ({
|
|
545
|
-
type: "tile",
|
|
546
|
-
id,
|
|
547
|
-
containerId,
|
|
548
|
-
data: dataProp,
|
|
549
|
-
location
|
|
550
|
-
}), [
|
|
551
|
-
containerId,
|
|
552
|
-
location,
|
|
553
|
-
dataProp
|
|
554
|
-
]);
|
|
555
|
-
useLayoutEffect(() => {
|
|
556
|
-
const root = rootRef.current;
|
|
557
|
-
if (!draggableProp || !root || !containerId || scrolling) {
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
const handleChange = ({ self, source }) => {
|
|
561
|
-
if (source.data.id !== dataProp.id) {
|
|
562
|
-
const closestEdge = extractClosestEdge(self.data);
|
|
563
|
-
const location2 = data.location + (closestEdge === "top" || closestEdge === "left" ? -0.5 : 0.5);
|
|
564
|
-
setActiveLocation(location2);
|
|
565
|
-
setState({
|
|
566
|
-
type: "target",
|
|
567
|
-
closestEdge
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
};
|
|
571
|
-
const handleNativeDragStart = (event) => {
|
|
572
|
-
if (event.dataTransfer) {
|
|
573
|
-
event.dataTransfer.effectAllowed = "move";
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
root.addEventListener("dragstart", handleNativeDragStart);
|
|
577
|
-
return combine3(
|
|
578
|
-
() => root.removeEventListener("dragstart", handleNativeDragStart),
|
|
579
|
-
// Source.
|
|
580
|
-
draggable({
|
|
581
|
-
element: root,
|
|
582
|
-
dragHandle: dragHandle && state.type !== "preview" ? dragHandle : void 0,
|
|
583
|
-
canDrag: () => true,
|
|
584
|
-
getInitialData: () => data,
|
|
585
|
-
onGenerateDragPreview: ({ location: location2, nativeSetDragImage }) => {
|
|
586
|
-
setCustomNativeDragPreview({
|
|
587
|
-
nativeSetDragImage,
|
|
588
|
-
getOffset: preserveOffsetOnSource({
|
|
589
|
-
element: root,
|
|
590
|
-
input: location2.current.input
|
|
591
|
-
}),
|
|
592
|
-
render: ({ container }) => {
|
|
593
|
-
data.bounds = root.getBoundingClientRect();
|
|
594
|
-
setState({
|
|
595
|
-
type: "preview",
|
|
596
|
-
container,
|
|
597
|
-
rect: root.getBoundingClientRect()
|
|
598
|
-
});
|
|
599
|
-
return () => setState({
|
|
600
|
-
type: "dragging"
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
});
|
|
604
|
-
},
|
|
605
|
-
onDragStart: () => {
|
|
606
|
-
setState({
|
|
607
|
-
type: "dragging"
|
|
608
|
-
});
|
|
609
|
-
},
|
|
610
|
-
onDrop: () => {
|
|
611
|
-
setState({
|
|
612
|
-
type: "idle"
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
}),
|
|
616
|
-
// Target.
|
|
617
|
-
dropTargetForElements2({
|
|
618
|
-
element: root,
|
|
619
|
-
getData: ({ input, element }) => attachClosestEdge(data, {
|
|
620
|
-
input,
|
|
621
|
-
element,
|
|
622
|
-
allowedEdges
|
|
623
|
-
}),
|
|
624
|
-
canDrop: ({ source }) => {
|
|
625
|
-
const data2 = getSourceData(source);
|
|
626
|
-
return data2 && eventHandler.canDrop?.({
|
|
627
|
-
source: data2
|
|
628
|
-
}) || false;
|
|
629
|
-
},
|
|
630
|
-
// Reorder is a move, not a copy — otherwise the browser shows the green "+" copy cursor.
|
|
631
|
-
getDropEffect: () => "move",
|
|
632
|
-
onDragEnter: ({ self, source }) => {
|
|
633
|
-
handleChange({
|
|
634
|
-
self,
|
|
635
|
-
source
|
|
636
|
-
});
|
|
637
|
-
},
|
|
638
|
-
onDragLeave: () => {
|
|
639
|
-
setState({
|
|
640
|
-
type: "idle"
|
|
641
|
-
});
|
|
642
|
-
setActiveLocation(void 0);
|
|
643
|
-
},
|
|
644
|
-
onDrag: ({ self, source }) => {
|
|
645
|
-
handleChange({
|
|
646
|
-
self,
|
|
647
|
-
source
|
|
648
|
-
});
|
|
649
|
-
},
|
|
650
|
-
onDrop: () => {
|
|
651
|
-
setState({
|
|
652
|
-
type: "idle"
|
|
653
|
-
});
|
|
654
|
-
setActiveLocation(void 0);
|
|
655
|
-
}
|
|
656
|
-
})
|
|
657
|
-
);
|
|
658
|
-
}, [
|
|
659
|
-
rootRef,
|
|
660
|
-
forwardedRef,
|
|
661
|
-
containerId,
|
|
662
|
-
dragHandle,
|
|
663
|
-
eventHandler,
|
|
664
|
-
data,
|
|
665
|
-
scrolling,
|
|
666
|
-
allowedEdges,
|
|
667
|
-
setActiveLocation
|
|
668
|
-
]);
|
|
669
|
-
const { className, ...rest } = composableProps2(props, {
|
|
670
|
-
classNames: "relative outline-none"
|
|
671
|
-
});
|
|
672
|
-
const vertical = orientation === "vertical";
|
|
673
|
-
const sized = size != null;
|
|
674
|
-
const bounded = sized || minSize != null || maxSize != null;
|
|
675
|
-
const sizeStyles = {
|
|
676
|
-
...sized && sizeStyle(size, vertical ? "vertical" : "horizontal"),
|
|
677
|
-
...minSize != null && {
|
|
678
|
-
[vertical ? "minBlockSize" : "minInlineSize"]: `${minSize}rem`
|
|
679
|
-
},
|
|
680
|
-
...maxSize != null && {
|
|
681
|
-
[vertical ? "maxBlockSize" : "maxInlineSize"]: `${maxSize}rem`
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
return /* @__PURE__ */ React3.createElement(MosaicTileContextProvider, {
|
|
685
|
-
state,
|
|
686
|
-
setDragHandle: setRegisteredDragHandle,
|
|
687
|
-
size,
|
|
688
|
-
setSize,
|
|
689
|
-
minSize,
|
|
690
|
-
maxSize
|
|
691
|
-
}, /* @__PURE__ */ React3.createElement(Comp, {
|
|
692
|
-
...rest,
|
|
693
|
-
...bounded && resizeAttributes,
|
|
694
|
-
...bounded && {
|
|
695
|
-
style: {
|
|
696
|
-
...rest.style,
|
|
697
|
-
...sizeStyles
|
|
698
|
-
}
|
|
699
|
-
},
|
|
700
|
-
"data-object-id": id,
|
|
701
|
-
[`data-${MOSAIC_TILE_STATE_ATTR}`]: state.type,
|
|
702
|
-
role: "listitem",
|
|
703
|
-
// Pair `current` / `selected` props with `aria-current` / `aria-selected`
|
|
704
|
-
// so the `dx-current` / `dx-selected` / `dx-hover` utilities (which key
|
|
705
|
-
// off those attributes) actually fire. Without this the props are purely
|
|
706
|
-
// advisory and the corresponding styling silently no-ops.
|
|
707
|
-
"aria-current": current ? "true" : void 0,
|
|
708
|
-
"aria-selected": selected ? "true" : void 0,
|
|
709
|
-
className,
|
|
710
|
-
ref: composedRef
|
|
711
|
-
}, children), state.type === "preview" && /* @__PURE__ */ createPortal(/* @__PURE__ */ React3.createElement(Comp, {
|
|
712
|
-
// NOTE: Use to control appearance while dragging.
|
|
713
|
-
[`data-${MOSAIC_TILE_STATE_ATTR}`]: state.type,
|
|
714
|
-
className,
|
|
715
|
-
style: {
|
|
716
|
-
width: `${state.rect.width}px`,
|
|
717
|
-
height: `${state.rect.height}px`
|
|
718
|
-
}
|
|
719
|
-
}, children), state.container));
|
|
720
|
-
});
|
|
721
|
-
MosaicTile.displayName = MOSAIC_TILE_NAME;
|
|
722
|
-
|
|
723
|
-
// src/components/Mosaic/DragHandle.tsx
|
|
724
|
-
import { composeRefs as composeRefs2 } from "@radix-ui/react-compose-refs";
|
|
725
|
-
import React4, { forwardRef as forwardRef2 } from "react";
|
|
726
|
-
import { Button, IconButton, useTranslation } from "@dxos/react-ui";
|
|
727
|
-
var MOSAIC_DRAG_HANDLE_NAME = "Mosaic.DragHandle";
|
|
728
|
-
var REACT_UI_TRANSLATION_KEY = "@dxos/react-ui";
|
|
729
|
-
var MosaicDragHandle = /* @__PURE__ */ forwardRef2(({ icon = "ph--dots-six-vertical--regular", label, variant = "ghost", classNames, testId, children }, forwardedRef) => {
|
|
730
|
-
const { t } = useTranslation(REACT_UI_TRANSLATION_KEY);
|
|
731
|
-
const { setDragHandle } = useMosaicTileContext(MOSAIC_DRAG_HANDLE_NAME);
|
|
732
|
-
const ref = composeRefs2(forwardedRef, setDragHandle);
|
|
733
|
-
const testIdProps = testId ? {
|
|
734
|
-
"data-testid": testId
|
|
735
|
-
} : {};
|
|
736
|
-
if (children) {
|
|
737
|
-
return /* @__PURE__ */ React4.createElement(Button, {
|
|
738
|
-
ref,
|
|
739
|
-
variant,
|
|
740
|
-
tabIndex: -1,
|
|
741
|
-
classNames: [
|
|
742
|
-
"grid place-items-center cursor-grab",
|
|
743
|
-
classNames
|
|
744
|
-
],
|
|
745
|
-
...testIdProps
|
|
746
|
-
}, children, /* @__PURE__ */ React4.createElement("span", {
|
|
747
|
-
className: "sr-only"
|
|
748
|
-
}, label ?? t("toolbar-drag-handle.label")));
|
|
749
|
-
}
|
|
750
|
-
return /* @__PURE__ */ React4.createElement(IconButton, {
|
|
751
|
-
ref,
|
|
752
|
-
iconOnly: true,
|
|
753
|
-
noTooltip: true,
|
|
754
|
-
tabIndex: -1,
|
|
755
|
-
variant,
|
|
756
|
-
icon,
|
|
757
|
-
label: label ?? t("toolbar-drag-handle.label"),
|
|
758
|
-
classNames: [
|
|
759
|
-
"cursor-grab",
|
|
760
|
-
classNames
|
|
761
|
-
],
|
|
762
|
-
...testIdProps
|
|
763
|
-
});
|
|
764
|
-
});
|
|
765
|
-
MosaicDragHandle.displayName = MOSAIC_DRAG_HANDLE_NAME;
|
|
766
|
-
|
|
767
|
-
// src/components/Mosaic/Placeholder.tsx
|
|
768
|
-
import { DropIndicator as NaturalDropIndicator } from "@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box";
|
|
769
|
-
import { dropTargetForElements as dropTargetForElements3 } from "@atlaskit/pragmatic-drag-and-drop/element/adapter";
|
|
770
|
-
import { Primitive as Primitive4 } from "@radix-ui/react-primitive";
|
|
771
|
-
import { Slot as Slot4 } from "@radix-ui/react-slot";
|
|
772
|
-
import React5, { useLayoutEffect as useLayoutEffect2, useMemo as useMemo4, useRef as useRef4 } from "react";
|
|
773
|
-
import { mx } from "@dxos/ui-theme";
|
|
774
|
-
var MOSAIC_PLACEHOLDER_NAME = "Mosaic.Placeholder";
|
|
775
|
-
var MOSAIC_PLACEHOLDER_ORIENTATION_ATTR = "mosaic-placeholder-orientation";
|
|
776
|
-
var MOSAIC_PLACEHOLDER_STATE_ATTR = "mosaic-placeholder-state";
|
|
777
|
-
var MOSAIC_PLACEHOLDER_LOCATION_ATTR = "mosaic-placeholder-location";
|
|
778
|
-
var MosaicPlaceholder = ({ classNames, children, asChild, orientation = "vertical", location }) => {
|
|
779
|
-
const rootRef = useRef4(null);
|
|
780
|
-
const Comp = asChild ? Slot4 : Primitive4.div;
|
|
781
|
-
const { id: containerId, eventHandler, scrolling, activeLocation, setActiveLocation } = useMosaicContainerContext(MOSAIC_PLACEHOLDER_NAME);
|
|
782
|
-
const data = useMemo4(() => ({
|
|
783
|
-
type: "placeholder",
|
|
784
|
-
containerId,
|
|
785
|
-
location
|
|
786
|
-
}), [
|
|
787
|
-
containerId,
|
|
788
|
-
location
|
|
789
|
-
]);
|
|
790
|
-
useLayoutEffect2(() => {
|
|
791
|
-
const root = rootRef.current;
|
|
792
|
-
if (!root || scrolling) {
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
return dropTargetForElements3({
|
|
796
|
-
element: root,
|
|
797
|
-
getData: () => data,
|
|
798
|
-
canDrop: ({ source }) => {
|
|
799
|
-
const data2 = getSourceData(source);
|
|
800
|
-
return data2 && eventHandler.canDrop?.({
|
|
801
|
-
source: data2
|
|
802
|
-
}) || false;
|
|
803
|
-
},
|
|
804
|
-
// Reorder is a move, not a copy — otherwise the browser shows the green "+" copy cursor.
|
|
805
|
-
getDropEffect: () => "move",
|
|
806
|
-
onDragEnter: () => {
|
|
807
|
-
setActiveLocation(data.location);
|
|
808
|
-
},
|
|
809
|
-
onDragLeave: () => {
|
|
810
|
-
setActiveLocation(void 0);
|
|
811
|
-
},
|
|
812
|
-
onDrop: () => {
|
|
813
|
-
setActiveLocation(void 0);
|
|
814
|
-
}
|
|
815
|
-
});
|
|
816
|
-
}, [
|
|
817
|
-
rootRef,
|
|
818
|
-
data,
|
|
819
|
-
scrolling,
|
|
820
|
-
setActiveLocation
|
|
821
|
-
]);
|
|
822
|
-
return /* @__PURE__ */ React5.createElement(Comp, {
|
|
823
|
-
[`data-${MOSAIC_PLACEHOLDER_ORIENTATION_ATTR}`]: orientation,
|
|
824
|
-
[`data-${MOSAIC_PLACEHOLDER_STATE_ATTR}`]: data.location === activeLocation ? "active" : "idle",
|
|
825
|
-
[`data-${MOSAIC_PLACEHOLDER_LOCATION_ATTR}`]: String(location),
|
|
826
|
-
role: "none",
|
|
827
|
-
className: mx("relative", classNames),
|
|
828
|
-
ref: rootRef
|
|
829
|
-
}, children);
|
|
830
|
-
};
|
|
831
|
-
MosaicPlaceholder.displayName = MOSAIC_PLACEHOLDER_NAME;
|
|
832
|
-
var DROP_INDICATOR_NAME = "Mosaic.DropIndicator";
|
|
833
|
-
var MosaicDropIndicator = (props) => {
|
|
834
|
-
const { state } = useMosaicTileContext(DROP_INDICATOR_NAME);
|
|
835
|
-
return state.type === "target" && state.closestEdge ? /* @__PURE__ */ React5.createElement(NaturalDropIndicator, {
|
|
836
|
-
...props,
|
|
837
|
-
edge: state.closestEdge
|
|
838
|
-
}) : null;
|
|
839
|
-
};
|
|
840
|
-
MosaicDropIndicator.displayName = DROP_INDICATOR_NAME;
|
|
841
|
-
|
|
842
|
-
// src/components/Mosaic/ResizeHandle.tsx
|
|
843
|
-
import React6 from "react";
|
|
844
|
-
import { ResizeHandle } from "@dxos/react-ui-dnd";
|
|
845
|
-
var MOSAIC_RESIZE_HANDLE_NAME = "Mosaic.ResizeHandle";
|
|
846
|
-
var MIN_WIDTH = 20;
|
|
847
|
-
var MIN_HEIGHT = 3;
|
|
848
|
-
var DEFAULT_EXTRINSIC_SIZE = 50;
|
|
849
|
-
var MosaicResizeHandle = ({ minSize, maxSize, fallbackSize = DEFAULT_EXTRINSIC_SIZE }) => {
|
|
850
|
-
const { orientation = "vertical" } = useMosaicContainerContext(MOSAIC_RESIZE_HANDLE_NAME);
|
|
851
|
-
const { size, setSize, minSize: tileMinSize, maxSize: tileMaxSize } = useMosaicTileContext(MOSAIC_RESIZE_HANDLE_NAME);
|
|
852
|
-
const horizontal = orientation === "horizontal";
|
|
853
|
-
return /* @__PURE__ */ React6.createElement(ResizeHandle, {
|
|
854
|
-
side: horizontal ? "inline-end" : "block-end",
|
|
855
|
-
fallbackSize,
|
|
856
|
-
minSize: minSize ?? tileMinSize ?? (horizontal ? MIN_WIDTH : MIN_HEIGHT),
|
|
857
|
-
maxSize: maxSize ?? tileMaxSize,
|
|
858
|
-
size,
|
|
859
|
-
onSizeChange: setSize
|
|
860
|
-
});
|
|
861
|
-
};
|
|
862
|
-
MosaicResizeHandle.displayName = MOSAIC_RESIZE_HANDLE_NAME;
|
|
863
|
-
|
|
864
|
-
// src/components/Mosaic/Stack.tsx
|
|
865
|
-
import { useComposedRefs as useComposedRefs3 } from "@radix-ui/react-compose-refs";
|
|
866
|
-
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
867
|
-
import React7, { Fragment, forwardRef as forwardRef3, useCallback as useCallback4, useEffect as useEffect3, useLayoutEffect as useLayoutEffect3, useMemo as useMemo5, useRef as useRef5 } from "react";
|
|
868
|
-
import { invariant } from "@dxos/invariant";
|
|
869
|
-
import { composable as composable2, composableProps as composableProps3 } from "@dxos/react-ui";
|
|
870
|
-
import { mx as mx2 } from "@dxos/ui-theme";
|
|
871
|
-
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/react-ui-mosaic/src/components/Mosaic/Stack.tsx";
|
|
872
|
-
var MOSAIC_STACK_NAME = "MosaicStack";
|
|
873
|
-
var MosaicStackInner = composable2(({ orientation: orientationProp = "vertical", getId, items, scrollIntoView = true, Tile, draggable: draggable2 = true, debug, ...props }, forwardedRef) => {
|
|
874
|
-
const { id, orientation = orientationProp, dragging, currentId, selectedIds, registerScrollTo, setActiveLocation } = useMosaicContainerContext(MOSAIC_STACK_NAME);
|
|
875
|
-
const visibleItems = useVisibleItems({
|
|
876
|
-
id,
|
|
877
|
-
items,
|
|
878
|
-
dragging: dragging?.source.data,
|
|
879
|
-
getId
|
|
880
|
-
});
|
|
881
|
-
invariant(orientation === "vertical" || orientation === "horizontal", `Invalid orientation: ${orientation}`, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 46, S: void 0, A: ["orientation === 'vertical' || orientation === 'horizontal'", "`Invalid orientation: ${orientation}`"] });
|
|
882
|
-
const draggingSource = dragging?.source.data;
|
|
883
|
-
const sourceIndex = useMemo5(() => {
|
|
884
|
-
if (!items || !draggingSource || draggingSource.containerId !== id) {
|
|
885
|
-
return -1;
|
|
886
|
-
}
|
|
887
|
-
return items.findIndex((item) => getId(item) === draggingSource.id);
|
|
888
|
-
}, [
|
|
889
|
-
items,
|
|
890
|
-
draggingSource,
|
|
891
|
-
id,
|
|
892
|
-
getId
|
|
893
|
-
]);
|
|
894
|
-
useLayoutEffect3(() => {
|
|
895
|
-
if (sourceIndex >= 0) {
|
|
896
|
-
setActiveLocation(sourceIndex + 0.5);
|
|
897
|
-
}
|
|
898
|
-
}, [
|
|
899
|
-
sourceIndex,
|
|
900
|
-
setActiveLocation
|
|
901
|
-
]);
|
|
902
|
-
const rootRef = useRef5(null);
|
|
903
|
-
const scrollToId = useCallback4((targetId) => {
|
|
904
|
-
if (!scrollIntoView) {
|
|
905
|
-
return;
|
|
906
|
-
}
|
|
907
|
-
const el = rootRef.current?.querySelector(`[data-object-id="${CSS.escape(targetId)}"]`);
|
|
908
|
-
el?.scrollIntoView({
|
|
909
|
-
block: "nearest",
|
|
910
|
-
behavior: "smooth"
|
|
911
|
-
});
|
|
912
|
-
}, [
|
|
913
|
-
scrollIntoView
|
|
914
|
-
]);
|
|
915
|
-
useEffect3(() => {
|
|
916
|
-
registerScrollTo(scrollToId);
|
|
917
|
-
return () => registerScrollTo(void 0);
|
|
918
|
-
}, [
|
|
919
|
-
registerScrollTo,
|
|
920
|
-
scrollToId
|
|
921
|
-
]);
|
|
922
|
-
const composedRef = useComposedRefs3(rootRef, forwardedRef);
|
|
923
|
-
return /* @__PURE__ */ React7.createElement("div", {
|
|
924
|
-
...composableProps3(props, {
|
|
925
|
-
role: "list",
|
|
926
|
-
classNames: [
|
|
927
|
-
"flex",
|
|
928
|
-
orientation === "horizontal" && "h-full [&>*]:shrink-0",
|
|
929
|
-
orientation === "vertical" && "flex-col"
|
|
930
|
-
]
|
|
931
|
-
}),
|
|
932
|
-
ref: composedRef
|
|
933
|
-
}, draggable2 && /* @__PURE__ */ React7.createElement(InternalPlaceholder, {
|
|
934
|
-
orientation,
|
|
935
|
-
location: 0.5
|
|
936
|
-
}), visibleItems?.map((item, index) => /* @__PURE__ */ React7.createElement(Fragment, {
|
|
937
|
-
key: getId(item)
|
|
938
|
-
}, /* @__PURE__ */ React7.createElement(Tile, {
|
|
939
|
-
id: getId(item),
|
|
940
|
-
data: item,
|
|
941
|
-
location: index + 1,
|
|
942
|
-
draggable: draggable2,
|
|
943
|
-
current: getId(item) === currentId,
|
|
944
|
-
selected: selectedIds?.has(getId(item)),
|
|
945
|
-
debug
|
|
946
|
-
}), draggable2 && /* @__PURE__ */ React7.createElement(InternalPlaceholder, {
|
|
947
|
-
orientation,
|
|
948
|
-
location: index + 1.5
|
|
949
|
-
}))));
|
|
950
|
-
});
|
|
951
|
-
MosaicStackInner.displayName = MOSAIC_STACK_NAME;
|
|
952
|
-
var MosaicStack = MosaicStackInner;
|
|
953
|
-
var MOSAIC_VIRTUAL_STACK_NAME = "MosaicVirtualStack";
|
|
954
|
-
var MosaicVirtualStackInner = /* @__PURE__ */ forwardRef3(({ orientation = "vertical", getId, items, scrollIntoView = true, Tile, estimateSize, getScrollElement, overscan = 8, gap, onChange, draggable: draggable2 = true, debug, ...props }, forwardedRef) => {
|
|
955
|
-
invariant(Tile, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 128, S: void 0, A: ["Tile", ""] });
|
|
956
|
-
const { id, dragging, currentId, selectedIds, registerScrollTo } = useMosaicContainerContext(MOSAIC_VIRTUAL_STACK_NAME);
|
|
957
|
-
const visibleItems = useVisibleItems({
|
|
958
|
-
id,
|
|
959
|
-
items,
|
|
960
|
-
dragging: dragging?.source.data,
|
|
961
|
-
getId
|
|
962
|
-
});
|
|
963
|
-
const wrappedEstimateSize = draggable2 ? (index) => index % 2 === 0 ? 0 : estimateSize(Math.floor(index / 2)) : estimateSize;
|
|
964
|
-
const virtualizer = useVirtualizer({
|
|
965
|
-
// NOTE: When draggable we double the number of items to allow for placeholders.
|
|
966
|
-
count: draggable2 ? visibleItems.length * 2 + 1 : visibleItems.length,
|
|
967
|
-
estimateSize: wrappedEstimateSize,
|
|
968
|
-
gap,
|
|
969
|
-
// Inset the stack from both ends by `gap` (matching the inter-item spacing). The virtualizer
|
|
970
|
-
// folds this into item offsets, getTotalSize(), and scrollToIndex, so no manual compensation.
|
|
971
|
-
paddingStart: gap,
|
|
972
|
-
paddingEnd: gap,
|
|
973
|
-
// Key measurements by stable item ID so the size cache survives scrolling;
|
|
974
|
-
// without this, measurements are indexed by position and are lost when items reorder.
|
|
975
|
-
getItemKey: draggable2 ? (index) => index % 2 === 0 ? `ph-${index}` : getId(visibleItems[Math.floor(index / 2)]) : (index) => getId(visibleItems[index]),
|
|
976
|
-
getScrollElement,
|
|
977
|
-
overscan,
|
|
978
|
-
onChange
|
|
979
|
-
});
|
|
980
|
-
const scrollToId = useCallback4((targetId) => {
|
|
981
|
-
const itemIndex = visibleItems.findIndex((item) => getId(item) === targetId);
|
|
982
|
-
if (itemIndex >= 0) {
|
|
983
|
-
if (!scrollIntoView) {
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
const virtualIndex = draggable2 ? itemIndex * 2 + 1 : itemIndex;
|
|
987
|
-
const [offset] = virtualizer.getOffsetForIndex(virtualIndex, "start") ?? [];
|
|
988
|
-
if (offset != null) {
|
|
989
|
-
virtualizer.scrollToOffset(Math.max(0, offset - (gap ?? 0)), {
|
|
990
|
-
behavior: "smooth"
|
|
991
|
-
});
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
}, [
|
|
995
|
-
visibleItems,
|
|
996
|
-
getId,
|
|
997
|
-
draggable2,
|
|
998
|
-
virtualizer,
|
|
999
|
-
scrollIntoView,
|
|
1000
|
-
gap
|
|
1001
|
-
]);
|
|
1002
|
-
useEffect3(() => {
|
|
1003
|
-
registerScrollTo(scrollToId);
|
|
1004
|
-
return () => registerScrollTo(void 0);
|
|
1005
|
-
}, [
|
|
1006
|
-
registerScrollTo,
|
|
1007
|
-
scrollToId
|
|
1008
|
-
]);
|
|
1009
|
-
const virtualItems = virtualizer.getVirtualItems();
|
|
1010
|
-
const getData = (index) => {
|
|
1011
|
-
if (draggable2) {
|
|
1012
|
-
if (index % 2 === 0) {
|
|
1013
|
-
return {
|
|
1014
|
-
location: Math.floor(index / 2) + 0.5
|
|
1015
|
-
};
|
|
1016
|
-
} else {
|
|
1017
|
-
return {
|
|
1018
|
-
data: visibleItems[Math.floor(index / 2)],
|
|
1019
|
-
location: Math.floor(index / 2) + 1
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
} else {
|
|
1023
|
-
return {
|
|
1024
|
-
data: visibleItems[index],
|
|
1025
|
-
location: index + 1
|
|
1026
|
-
};
|
|
1027
|
-
}
|
|
1028
|
-
};
|
|
1029
|
-
return /* @__PURE__ */ React7.createElement("div", {
|
|
1030
|
-
...composableProps3(props, {
|
|
1031
|
-
role: "list",
|
|
1032
|
-
classNames: [
|
|
1033
|
-
// shrink-0 is required: this div sets an explicit height via inline style (getTotalSize).
|
|
1034
|
-
// Without it, a parent flex container (e.g. ScrollArea.Viewport) would shrink this div
|
|
1035
|
-
// to the viewport height, collapsing the scroll content and causing scrollbar drift.
|
|
1036
|
-
"flex shrink-0",
|
|
1037
|
-
orientation === "horizontal" && "h-full [&>*]:shrink-0",
|
|
1038
|
-
orientation === "vertical" && "flex-col"
|
|
1039
|
-
]
|
|
1040
|
-
}),
|
|
1041
|
-
style: {
|
|
1042
|
-
position: "relative",
|
|
1043
|
-
...orientation === "vertical" ? {
|
|
1044
|
-
width: "100%",
|
|
1045
|
-
height: virtualizer.getTotalSize()
|
|
1046
|
-
} : {
|
|
1047
|
-
width: virtualizer.getTotalSize(),
|
|
1048
|
-
height: "100%"
|
|
1049
|
-
}
|
|
1050
|
-
},
|
|
1051
|
-
ref: forwardedRef
|
|
1052
|
-
}, virtualItems.map(({ key, index, start }) => {
|
|
1053
|
-
const { data, location } = getData(index);
|
|
1054
|
-
return /* @__PURE__ */ React7.createElement("div", {
|
|
1055
|
-
key,
|
|
1056
|
-
"data-index": index,
|
|
1057
|
-
style: {
|
|
1058
|
-
position: "absolute",
|
|
1059
|
-
top: 0,
|
|
1060
|
-
left: 0,
|
|
1061
|
-
...orientation === "vertical" ? {
|
|
1062
|
-
width: "100%",
|
|
1063
|
-
transform: `translateY(${start}px)`
|
|
1064
|
-
} : {
|
|
1065
|
-
height: "100%",
|
|
1066
|
-
transform: `translateX(${start}px)`
|
|
1067
|
-
}
|
|
1068
|
-
},
|
|
1069
|
-
ref: virtualizer.measureElement
|
|
1070
|
-
}, data ? /* @__PURE__ */ React7.createElement(Tile, {
|
|
1071
|
-
id: getId(data),
|
|
1072
|
-
data,
|
|
1073
|
-
location,
|
|
1074
|
-
draggable: draggable2,
|
|
1075
|
-
current: getId(data) === currentId,
|
|
1076
|
-
selected: selectedIds?.has(getId(data)),
|
|
1077
|
-
debug
|
|
1078
|
-
}) : /* @__PURE__ */ React7.createElement(InternalPlaceholder, {
|
|
1079
|
-
orientation,
|
|
1080
|
-
location
|
|
1081
|
-
}));
|
|
1082
|
-
}));
|
|
1083
|
-
});
|
|
1084
|
-
MosaicVirtualStackInner.displayName = MOSAIC_VIRTUAL_STACK_NAME;
|
|
1085
|
-
var MosaicVirtualStack = MosaicVirtualStackInner;
|
|
1086
|
-
MosaicVirtualStack[/* @__PURE__ */ Symbol.for("dxos.composable")] = true;
|
|
1087
|
-
var InternalPlaceholder = (props) => {
|
|
1088
|
-
return /* @__PURE__ */ React7.createElement(MosaicPlaceholder, {
|
|
1089
|
-
...props,
|
|
1090
|
-
classNames: styles.placeholder.root
|
|
1091
|
-
}, /* @__PURE__ */ React7.createElement("div", {
|
|
1092
|
-
className: mx2("flex h-full bg-base-surface border border-dashed border-separator rounded-xs", styles.placeholder.content)
|
|
1093
|
-
}));
|
|
1094
|
-
};
|
|
1095
|
-
InternalPlaceholder.displayName = "InternalPlaceholder";
|
|
1096
|
-
|
|
1097
|
-
// src/components/Mosaic/Mosaic.tsx
|
|
1098
|
-
var Mosaic = {
|
|
1099
|
-
Root: MosaicRoot,
|
|
1100
|
-
Container: MosaicContainer,
|
|
1101
|
-
Tile: MosaicTile,
|
|
1102
|
-
DragHandle: MosaicDragHandle,
|
|
1103
|
-
ResizeHandle: MosaicResizeHandle,
|
|
1104
|
-
Placeholder: MosaicPlaceholder,
|
|
1105
|
-
DropIndicator: MosaicDropIndicator,
|
|
1106
|
-
Stack: MosaicStack,
|
|
1107
|
-
VirtualStack: MosaicVirtualStack
|
|
1108
|
-
};
|
|
1109
|
-
|
|
1110
|
-
export {
|
|
1111
|
-
useVisibleItems,
|
|
1112
|
-
Focus,
|
|
1113
|
-
useFocus,
|
|
1114
|
-
styles,
|
|
1115
|
-
getSourceData,
|
|
1116
|
-
useMosaicRootContext,
|
|
1117
|
-
useMosaicContainerContext,
|
|
1118
|
-
useMosaicTileContext,
|
|
1119
|
-
Mosaic
|
|
1120
|
-
};
|
|
1121
|
-
//# sourceMappingURL=chunk-4IEMCMIV.mjs.map
|