@destyler/splitter 0.0.3 → 0.0.4
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 +7 -0
- package/dist/component.cjs +2008 -11
- package/dist/component.d.cts +654 -4
- package/dist/component.d.mts +654 -4
- package/dist/component.d.ts +654 -4
- package/dist/component.mjs +2001 -7
- package/dist/index.cjs +16 -1820
- package/dist/index.d.cts +4 -409
- package/dist/index.d.mts +4 -409
- package/dist/index.d.ts +4 -409
- package/dist/index.mjs +5 -1817
- package/dist/resolver.cjs +9 -6
- package/dist/resolver.d.cts +3 -3
- package/dist/resolver.d.mts +3 -3
- package/dist/resolver.d.ts +3 -3
- package/dist/resolver.mjs +8 -5
- package/package.json +15 -17
package/dist/component.mjs
CHANGED
|
@@ -1,7 +1,2001 @@
|
|
|
1
|
-
|
|
2
|
-
import '
|
|
3
|
-
import '@destyler/
|
|
4
|
-
import '@destyler/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import { watchEffect, defineComponent, ref, computed, watch, h, toRefs, onMounted, onUnmounted } from 'vue';
|
|
2
|
+
import { primitiveProps, Primitive } from '@destyler/primitive';
|
|
3
|
+
import { isBrowser, createContext, areEqual } from '@destyler/shared';
|
|
4
|
+
import { useId, useDirection, useForwardExpose } from '@destyler/composition';
|
|
5
|
+
|
|
6
|
+
function assert(expectedCondition, message = "Assertion failed!") {
|
|
7
|
+
if (!expectedCondition) {
|
|
8
|
+
console.error(message);
|
|
9
|
+
throw new Error(message);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getPanelGroupElement(id, rootElement = document) {
|
|
14
|
+
if (!isBrowser)
|
|
15
|
+
return null;
|
|
16
|
+
if (rootElement instanceof HTMLElement && rootElement?.dataset?.panelGroupId === id) {
|
|
17
|
+
return rootElement;
|
|
18
|
+
}
|
|
19
|
+
const element = rootElement.querySelector(
|
|
20
|
+
`[data-panel-group][data-panel-group-id="${id}"]`
|
|
21
|
+
);
|
|
22
|
+
if (element)
|
|
23
|
+
return element;
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
function getResizeHandleElement(id, scope = document) {
|
|
27
|
+
if (!isBrowser)
|
|
28
|
+
return null;
|
|
29
|
+
const element = scope.querySelector(`[data-panel-resize-handle-id="${id}"]`);
|
|
30
|
+
if (element)
|
|
31
|
+
return element;
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
function getResizeHandleElementIndex(groupId, id, scope = document) {
|
|
35
|
+
if (!isBrowser)
|
|
36
|
+
return null;
|
|
37
|
+
const handles = getResizeHandleElementsForGroup(groupId, scope);
|
|
38
|
+
const index = handles.findIndex(
|
|
39
|
+
(handle) => handle.getAttribute("data-panel-resize-handle-id") === id
|
|
40
|
+
);
|
|
41
|
+
return index ?? null;
|
|
42
|
+
}
|
|
43
|
+
function getResizeHandleElementsForGroup(groupId, scope = document) {
|
|
44
|
+
if (!isBrowser)
|
|
45
|
+
return [];
|
|
46
|
+
return Array.from(
|
|
47
|
+
scope.querySelectorAll(
|
|
48
|
+
`[data-panel-resize-handle-id][data-panel-group-id="${groupId}"]`
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
function getResizeHandlePanelIds(groupId, handleId, panelsArray, scope = document) {
|
|
53
|
+
const handle = getResizeHandleElement(handleId, scope);
|
|
54
|
+
const handles = getResizeHandleElementsForGroup(groupId, scope);
|
|
55
|
+
const index = handle ? handles.indexOf(handle) : -1;
|
|
56
|
+
const idBefore = panelsArray[index]?.id ?? null;
|
|
57
|
+
const idAfter = panelsArray[index + 1]?.id ?? null;
|
|
58
|
+
return [idBefore, idAfter];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function useWindowSplitterResizeHandlerBehavior({
|
|
62
|
+
disabled,
|
|
63
|
+
handleId,
|
|
64
|
+
resizeHandler,
|
|
65
|
+
panelGroupElement
|
|
66
|
+
}) {
|
|
67
|
+
watchEffect((onCleanup) => {
|
|
68
|
+
const _panelGroupElement = panelGroupElement.value;
|
|
69
|
+
if (disabled.value || resizeHandler.value === null || _panelGroupElement === null)
|
|
70
|
+
return;
|
|
71
|
+
const handleElement = getResizeHandleElement(handleId, _panelGroupElement);
|
|
72
|
+
if (handleElement == null)
|
|
73
|
+
return;
|
|
74
|
+
const onKeyDown = (event) => {
|
|
75
|
+
if (event.defaultPrevented)
|
|
76
|
+
return;
|
|
77
|
+
switch (event.key) {
|
|
78
|
+
case "ArrowDown":
|
|
79
|
+
case "ArrowLeft":
|
|
80
|
+
case "ArrowRight":
|
|
81
|
+
case "ArrowUp":
|
|
82
|
+
case "End":
|
|
83
|
+
case "Home": {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
resizeHandler.value?.(event);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
case "F6": {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
91
|
+
assert(groupId);
|
|
92
|
+
const handles = getResizeHandleElementsForGroup(
|
|
93
|
+
groupId,
|
|
94
|
+
_panelGroupElement
|
|
95
|
+
);
|
|
96
|
+
const index = getResizeHandleElementIndex(
|
|
97
|
+
groupId,
|
|
98
|
+
handleId,
|
|
99
|
+
_panelGroupElement
|
|
100
|
+
);
|
|
101
|
+
assert(index !== null);
|
|
102
|
+
const nextIndex = event.shiftKey ? index > 0 ? index - 1 : handles.length - 1 : index + 1 < handles.length ? index + 1 : 0;
|
|
103
|
+
const nextHandle = handles[nextIndex];
|
|
104
|
+
nextHandle.focus();
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
handleElement.addEventListener("keydown", onKeyDown);
|
|
110
|
+
onCleanup(() => {
|
|
111
|
+
handleElement.removeEventListener("keydown", onKeyDown);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let currentCursorStyle = null;
|
|
117
|
+
let styleElement = null;
|
|
118
|
+
function getCursorStyle(state, constraintFlags) {
|
|
119
|
+
if (constraintFlags) {
|
|
120
|
+
const horizontalMin = (constraintFlags & EXCEEDED_HORIZONTAL_MIN) !== 0;
|
|
121
|
+
const horizontalMax = (constraintFlags & EXCEEDED_HORIZONTAL_MAX) !== 0;
|
|
122
|
+
const verticalMin = (constraintFlags & EXCEEDED_VERTICAL_MIN) !== 0;
|
|
123
|
+
const verticalMax = (constraintFlags & EXCEEDED_VERTICAL_MAX) !== 0;
|
|
124
|
+
if (horizontalMin) {
|
|
125
|
+
if (verticalMin)
|
|
126
|
+
return "se-resize";
|
|
127
|
+
else if (verticalMax)
|
|
128
|
+
return "ne-resize";
|
|
129
|
+
else
|
|
130
|
+
return "e-resize";
|
|
131
|
+
} else if (horizontalMax) {
|
|
132
|
+
if (verticalMin)
|
|
133
|
+
return "sw-resize";
|
|
134
|
+
else if (verticalMax)
|
|
135
|
+
return "nw-resize";
|
|
136
|
+
else
|
|
137
|
+
return "w-resize";
|
|
138
|
+
} else if (verticalMin) {
|
|
139
|
+
return "s-resize";
|
|
140
|
+
} else if (verticalMax) {
|
|
141
|
+
return "n-resize";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
switch (state) {
|
|
145
|
+
case "horizontal":
|
|
146
|
+
return "ew-resize";
|
|
147
|
+
case "intersection":
|
|
148
|
+
return "move";
|
|
149
|
+
case "vertical":
|
|
150
|
+
return "ns-resize";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function resetGlobalCursorStyle() {
|
|
154
|
+
if (styleElement !== null) {
|
|
155
|
+
document.head.removeChild(styleElement);
|
|
156
|
+
currentCursorStyle = null;
|
|
157
|
+
styleElement = null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function setGlobalCursorStyle(state, constraintFlags) {
|
|
161
|
+
const style = getCursorStyle(state, constraintFlags);
|
|
162
|
+
if (currentCursorStyle === style)
|
|
163
|
+
return;
|
|
164
|
+
currentCursorStyle = style;
|
|
165
|
+
if (styleElement === null) {
|
|
166
|
+
styleElement = document.createElement("style");
|
|
167
|
+
document.head.appendChild(styleElement);
|
|
168
|
+
}
|
|
169
|
+
styleElement.innerHTML = `*{cursor: ${style}!important;}`;
|
|
170
|
+
}
|
|
171
|
+
function computePanelFlexBoxStyle({
|
|
172
|
+
defaultSize,
|
|
173
|
+
dragState,
|
|
174
|
+
layout,
|
|
175
|
+
panelData,
|
|
176
|
+
panelIndex,
|
|
177
|
+
precision = 3
|
|
178
|
+
}) {
|
|
179
|
+
const size = layout[panelIndex];
|
|
180
|
+
let flexGrow;
|
|
181
|
+
if (size == null) {
|
|
182
|
+
flexGrow = defaultSize !== void 0 ? defaultSize.toPrecision(precision) : "1";
|
|
183
|
+
} else if (panelData.length === 1) {
|
|
184
|
+
flexGrow = "1";
|
|
185
|
+
} else {
|
|
186
|
+
flexGrow = size.toPrecision(precision);
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
flexBasis: 0,
|
|
190
|
+
flexGrow,
|
|
191
|
+
flexShrink: 1,
|
|
192
|
+
overflow: "hidden",
|
|
193
|
+
pointerEvents: dragState !== null ? "none" : void 0
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function isKeyDown(event) {
|
|
198
|
+
return event.type === "keydown";
|
|
199
|
+
}
|
|
200
|
+
function isMouseEvent(event) {
|
|
201
|
+
return event.type.startsWith("mouse");
|
|
202
|
+
}
|
|
203
|
+
function isTouchEvent(event) {
|
|
204
|
+
return event.type.startsWith("touch");
|
|
205
|
+
}
|
|
206
|
+
function getResizeEventCoordinates(event) {
|
|
207
|
+
if (isMouseEvent(event)) {
|
|
208
|
+
return {
|
|
209
|
+
x: event.clientX,
|
|
210
|
+
y: event.clientY
|
|
211
|
+
};
|
|
212
|
+
} else if (isTouchEvent(event)) {
|
|
213
|
+
const touch = event.touches[0];
|
|
214
|
+
if (touch && touch.clientX && touch.clientY) {
|
|
215
|
+
return {
|
|
216
|
+
x: touch.clientX,
|
|
217
|
+
y: touch.clientY
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
x: Number.POSITIVE_INFINITY,
|
|
223
|
+
y: Number.POSITIVE_INFINITY
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function getResizeEventCursorPosition(direction, event) {
|
|
227
|
+
const isHorizontal = direction === "horizontal";
|
|
228
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
229
|
+
return isHorizontal ? x : y;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function intersects(rectOne, rectTwo, strict) {
|
|
233
|
+
if (strict) {
|
|
234
|
+
return rectOne.x < rectTwo.x + rectTwo.width && rectOne.x + rectOne.width > rectTwo.x && rectOne.y < rectTwo.y + rectTwo.height && rectOne.y + rectOne.height > rectTwo.y;
|
|
235
|
+
} else {
|
|
236
|
+
return rectOne.x <= rectTwo.x + rectTwo.width && rectOne.x + rectOne.width >= rectTwo.x && rectOne.y <= rectTwo.y + rectTwo.height && rectOne.y + rectOne.height >= rectTwo.y;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function compare(a, b) {
|
|
241
|
+
if (a === b)
|
|
242
|
+
throw new Error("Cannot compare node with itself");
|
|
243
|
+
const ancestors = {
|
|
244
|
+
a: getAncestors(a),
|
|
245
|
+
b: getAncestors(b)
|
|
246
|
+
};
|
|
247
|
+
let common_ancestor;
|
|
248
|
+
while (ancestors.a.at(-1) === ancestors.b.at(-1)) {
|
|
249
|
+
a = ancestors.a.pop();
|
|
250
|
+
b = ancestors.b.pop();
|
|
251
|
+
common_ancestor = a;
|
|
252
|
+
}
|
|
253
|
+
assert(common_ancestor);
|
|
254
|
+
const z_indexes = {
|
|
255
|
+
a: getZIndex(findStackingContext(ancestors.a)),
|
|
256
|
+
b: getZIndex(findStackingContext(ancestors.b))
|
|
257
|
+
};
|
|
258
|
+
if (z_indexes.a === z_indexes.b) {
|
|
259
|
+
const children = common_ancestor.childNodes;
|
|
260
|
+
const furthest_ancestors = {
|
|
261
|
+
a: ancestors.a.at(-1),
|
|
262
|
+
b: ancestors.b.at(-1)
|
|
263
|
+
};
|
|
264
|
+
let i = children.length;
|
|
265
|
+
while (i--) {
|
|
266
|
+
const child = children[i];
|
|
267
|
+
if (child === furthest_ancestors.a)
|
|
268
|
+
return 1;
|
|
269
|
+
if (child === furthest_ancestors.b)
|
|
270
|
+
return -1;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return Math.sign(z_indexes.a - z_indexes.b);
|
|
274
|
+
}
|
|
275
|
+
const props = /\b(?:position|zIndex|opacity|transform|webkitTransform|mixBlendMode|filter|webkitFilter|isolation)\b/;
|
|
276
|
+
function isFlexItem(node) {
|
|
277
|
+
const display = getComputedStyle(getParent(node)).display;
|
|
278
|
+
return display === "flex" || display === "inline-flex";
|
|
279
|
+
}
|
|
280
|
+
function createsStackingContext(node) {
|
|
281
|
+
const style = getComputedStyle(node);
|
|
282
|
+
if (style.position === "fixed")
|
|
283
|
+
return true;
|
|
284
|
+
if (style.zIndex !== "auto" && (style.position !== "static" || isFlexItem(node))) {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (+style.opacity < 1)
|
|
288
|
+
return true;
|
|
289
|
+
if ("transform" in style && style.transform !== "none")
|
|
290
|
+
return true;
|
|
291
|
+
if ("webkitTransform" in style && style.webkitTransform !== "none")
|
|
292
|
+
return true;
|
|
293
|
+
if ("mixBlendMode" in style && style.mixBlendMode !== "normal")
|
|
294
|
+
return true;
|
|
295
|
+
if ("filter" in style && style.filter !== "none")
|
|
296
|
+
return true;
|
|
297
|
+
if ("webkitFilter" in style && style.webkitFilter !== "none")
|
|
298
|
+
return true;
|
|
299
|
+
if ("isolation" in style && style.isolation === "isolate")
|
|
300
|
+
return true;
|
|
301
|
+
if (props.test(style.willChange))
|
|
302
|
+
return true;
|
|
303
|
+
if (style.webkitOverflowScrolling === "touch")
|
|
304
|
+
return true;
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
function findStackingContext(nodes) {
|
|
308
|
+
let i = nodes.length;
|
|
309
|
+
while (i--) {
|
|
310
|
+
const node = nodes[i];
|
|
311
|
+
assert(node);
|
|
312
|
+
if (createsStackingContext(node))
|
|
313
|
+
return node;
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
function getZIndex(node) {
|
|
318
|
+
return node && Number(getComputedStyle(node).zIndex) || 0;
|
|
319
|
+
}
|
|
320
|
+
function getAncestors(node) {
|
|
321
|
+
const ancestors = [];
|
|
322
|
+
while (node) {
|
|
323
|
+
ancestors.push(node);
|
|
324
|
+
node = getParent(node);
|
|
325
|
+
}
|
|
326
|
+
return ancestors;
|
|
327
|
+
}
|
|
328
|
+
function getParent(node) {
|
|
329
|
+
return node.parentNode?.host || node.parentNode;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const EXCEEDED_HORIZONTAL_MIN = 1;
|
|
333
|
+
const EXCEEDED_HORIZONTAL_MAX = 2;
|
|
334
|
+
const EXCEEDED_VERTICAL_MIN = 4;
|
|
335
|
+
const EXCEEDED_VERTICAL_MAX = 8;
|
|
336
|
+
function getInputType() {
|
|
337
|
+
if (typeof matchMedia === "function")
|
|
338
|
+
return matchMedia("(pointer:coarse)").matches ? "coarse" : "fine";
|
|
339
|
+
}
|
|
340
|
+
const isCoarsePointer = getInputType() === "coarse";
|
|
341
|
+
const intersectingHandles = [];
|
|
342
|
+
let isPointerDown = false;
|
|
343
|
+
const ownerDocumentCounts = /* @__PURE__ */ new Map();
|
|
344
|
+
const panelConstraintFlags = /* @__PURE__ */ new Map();
|
|
345
|
+
const registeredResizeHandlers = /* @__PURE__ */ new Set();
|
|
346
|
+
function registerResizeHandle(resizeHandleId, element, direction, hitAreaMargins, setResizeHandlerState) {
|
|
347
|
+
const { ownerDocument } = element;
|
|
348
|
+
const data = {
|
|
349
|
+
direction,
|
|
350
|
+
element,
|
|
351
|
+
hitAreaMargins,
|
|
352
|
+
setResizeHandlerState
|
|
353
|
+
};
|
|
354
|
+
const count = ownerDocumentCounts.get(ownerDocument) ?? 0;
|
|
355
|
+
ownerDocumentCounts.set(ownerDocument, count + 1);
|
|
356
|
+
registeredResizeHandlers.add(data);
|
|
357
|
+
updateListeners();
|
|
358
|
+
return function unregisterResizeHandle() {
|
|
359
|
+
panelConstraintFlags.delete(resizeHandleId);
|
|
360
|
+
registeredResizeHandlers.delete(data);
|
|
361
|
+
const count2 = ownerDocumentCounts.get(ownerDocument) ?? 1;
|
|
362
|
+
ownerDocumentCounts.set(ownerDocument, count2 - 1);
|
|
363
|
+
updateListeners();
|
|
364
|
+
if (count2 === 1)
|
|
365
|
+
ownerDocumentCounts.delete(ownerDocument);
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
function handlePointerDown(event) {
|
|
369
|
+
const { target } = event;
|
|
370
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
371
|
+
isPointerDown = true;
|
|
372
|
+
recalculateIntersectingHandles({ target, x, y });
|
|
373
|
+
updateListeners();
|
|
374
|
+
if (intersectingHandles.length > 0) {
|
|
375
|
+
updateResizeHandlerStates("down", event);
|
|
376
|
+
event.preventDefault();
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function handlePointerMove(event) {
|
|
380
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
381
|
+
if (!isPointerDown) {
|
|
382
|
+
const { target } = event;
|
|
383
|
+
recalculateIntersectingHandles({ target, x, y });
|
|
384
|
+
}
|
|
385
|
+
updateResizeHandlerStates("move", event);
|
|
386
|
+
updateCursor();
|
|
387
|
+
if (intersectingHandles.length > 0)
|
|
388
|
+
event.preventDefault();
|
|
389
|
+
}
|
|
390
|
+
function handlePointerUp(event) {
|
|
391
|
+
const { target } = event;
|
|
392
|
+
const { x, y } = getResizeEventCoordinates(event);
|
|
393
|
+
panelConstraintFlags.clear();
|
|
394
|
+
isPointerDown = false;
|
|
395
|
+
if (intersectingHandles.length > 0)
|
|
396
|
+
event.preventDefault();
|
|
397
|
+
updateResizeHandlerStates("up", event);
|
|
398
|
+
recalculateIntersectingHandles({ target, x, y });
|
|
399
|
+
updateCursor();
|
|
400
|
+
updateListeners();
|
|
401
|
+
}
|
|
402
|
+
function recalculateIntersectingHandles({
|
|
403
|
+
target,
|
|
404
|
+
x,
|
|
405
|
+
y
|
|
406
|
+
}) {
|
|
407
|
+
intersectingHandles.splice(0);
|
|
408
|
+
let targetElement = null;
|
|
409
|
+
if (target instanceof HTMLElement)
|
|
410
|
+
targetElement = target;
|
|
411
|
+
registeredResizeHandlers.forEach((data) => {
|
|
412
|
+
const { element: dragHandleElement, hitAreaMargins } = data;
|
|
413
|
+
const dragHandleRect = dragHandleElement.getBoundingClientRect();
|
|
414
|
+
const { bottom, left, right, top } = dragHandleRect;
|
|
415
|
+
const margin = isCoarsePointer ? hitAreaMargins.coarse : hitAreaMargins.fine;
|
|
416
|
+
const eventIntersects = x >= left - margin && x <= right + margin && y >= top - margin && y <= bottom + margin;
|
|
417
|
+
if (eventIntersects) {
|
|
418
|
+
if (targetElement !== null && dragHandleElement !== targetElement && !dragHandleElement.contains(targetElement) && !targetElement.contains(dragHandleElement) && compare(targetElement, dragHandleElement) > 0) {
|
|
419
|
+
let currentElement = targetElement;
|
|
420
|
+
let didIntersect = false;
|
|
421
|
+
while (currentElement) {
|
|
422
|
+
if (currentElement.contains(dragHandleElement)) {
|
|
423
|
+
break;
|
|
424
|
+
} else if (intersects(
|
|
425
|
+
currentElement.getBoundingClientRect(),
|
|
426
|
+
dragHandleRect,
|
|
427
|
+
true
|
|
428
|
+
)) {
|
|
429
|
+
didIntersect = true;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
currentElement = currentElement.parentElement;
|
|
433
|
+
}
|
|
434
|
+
if (didIntersect)
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
intersectingHandles.push(data);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
function reportConstraintsViolation(resizeHandleId, flag) {
|
|
442
|
+
panelConstraintFlags.set(resizeHandleId, flag);
|
|
443
|
+
}
|
|
444
|
+
function updateCursor() {
|
|
445
|
+
let intersectsHorizontal = false;
|
|
446
|
+
let intersectsVertical = false;
|
|
447
|
+
intersectingHandles.forEach((data) => {
|
|
448
|
+
const { direction } = data;
|
|
449
|
+
if (direction === "horizontal")
|
|
450
|
+
intersectsHorizontal = true;
|
|
451
|
+
else
|
|
452
|
+
intersectsVertical = true;
|
|
453
|
+
});
|
|
454
|
+
let constraintFlags = 0;
|
|
455
|
+
panelConstraintFlags.forEach((flag) => {
|
|
456
|
+
constraintFlags |= flag;
|
|
457
|
+
});
|
|
458
|
+
if (intersectsHorizontal && intersectsVertical)
|
|
459
|
+
setGlobalCursorStyle("intersection", constraintFlags);
|
|
460
|
+
else if (intersectsHorizontal)
|
|
461
|
+
setGlobalCursorStyle("horizontal", constraintFlags);
|
|
462
|
+
else if (intersectsVertical)
|
|
463
|
+
setGlobalCursorStyle("vertical", constraintFlags);
|
|
464
|
+
else
|
|
465
|
+
resetGlobalCursorStyle();
|
|
466
|
+
}
|
|
467
|
+
function updateListeners() {
|
|
468
|
+
ownerDocumentCounts.forEach((_, ownerDocument) => {
|
|
469
|
+
const { body } = ownerDocument;
|
|
470
|
+
body.removeEventListener("contextmenu", handlePointerUp);
|
|
471
|
+
body.removeEventListener("mousedown", handlePointerDown);
|
|
472
|
+
body.removeEventListener("mouseleave", handlePointerMove);
|
|
473
|
+
body.removeEventListener("mousemove", handlePointerMove);
|
|
474
|
+
body.removeEventListener("touchmove", handlePointerMove);
|
|
475
|
+
body.removeEventListener("touchstart", handlePointerDown);
|
|
476
|
+
});
|
|
477
|
+
window.removeEventListener("mouseup", handlePointerUp);
|
|
478
|
+
window.removeEventListener("touchcancel", handlePointerUp);
|
|
479
|
+
window.removeEventListener("touchend", handlePointerUp);
|
|
480
|
+
if (registeredResizeHandlers.size > 0) {
|
|
481
|
+
if (isPointerDown) {
|
|
482
|
+
if (intersectingHandles.length > 0) {
|
|
483
|
+
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
484
|
+
const { body } = ownerDocument;
|
|
485
|
+
if (count > 0) {
|
|
486
|
+
body.addEventListener("contextmenu", handlePointerUp);
|
|
487
|
+
body.addEventListener("mouseleave", handlePointerMove);
|
|
488
|
+
body.addEventListener("mousemove", handlePointerMove);
|
|
489
|
+
body.addEventListener("touchmove", handlePointerMove, {
|
|
490
|
+
passive: false
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
window.addEventListener("mouseup", handlePointerUp);
|
|
496
|
+
window.addEventListener("touchcancel", handlePointerUp);
|
|
497
|
+
window.addEventListener("touchend", handlePointerUp);
|
|
498
|
+
} else {
|
|
499
|
+
ownerDocumentCounts.forEach((count, ownerDocument) => {
|
|
500
|
+
const { body } = ownerDocument;
|
|
501
|
+
if (count > 0) {
|
|
502
|
+
body.addEventListener("mousedown", handlePointerDown);
|
|
503
|
+
body.addEventListener("mousemove", handlePointerMove);
|
|
504
|
+
body.addEventListener("touchmove", handlePointerMove, {
|
|
505
|
+
passive: false
|
|
506
|
+
});
|
|
507
|
+
body.addEventListener("touchstart", handlePointerDown);
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
function updateResizeHandlerStates(action, event) {
|
|
514
|
+
registeredResizeHandlers.forEach((data) => {
|
|
515
|
+
const { setResizeHandlerState } = data;
|
|
516
|
+
const isActive = intersectingHandles.includes(data);
|
|
517
|
+
setResizeHandlerState(action, isActive, event);
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function debounce(callback, durationMs = 10) {
|
|
522
|
+
let timeoutId = null;
|
|
523
|
+
const callable = (...args) => {
|
|
524
|
+
if (timeoutId !== null)
|
|
525
|
+
clearTimeout(timeoutId);
|
|
526
|
+
timeoutId = setTimeout(() => {
|
|
527
|
+
callback(...args);
|
|
528
|
+
}, durationMs);
|
|
529
|
+
};
|
|
530
|
+
return callable;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
function determinePivotIndices(groupId, dragHandleId, panelGroupElement) {
|
|
534
|
+
const index = getResizeHandleElementIndex(
|
|
535
|
+
groupId,
|
|
536
|
+
dragHandleId,
|
|
537
|
+
panelGroupElement
|
|
538
|
+
);
|
|
539
|
+
return index != null ? [index, index + 1] : [-1, -1];
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const PRECISION = 10;
|
|
543
|
+
|
|
544
|
+
function fuzzyCompareNumbers(actual, expected, fractionDigits = PRECISION) {
|
|
545
|
+
actual = Number.parseFloat(actual.toFixed(fractionDigits));
|
|
546
|
+
expected = Number.parseFloat(expected.toFixed(fractionDigits));
|
|
547
|
+
const delta = actual - expected;
|
|
548
|
+
if (delta === 0)
|
|
549
|
+
return 0;
|
|
550
|
+
else
|
|
551
|
+
return delta > 0 ? 1 : -1;
|
|
552
|
+
}
|
|
553
|
+
function fuzzyNumbersEqual(actual, expected, fractionDigits) {
|
|
554
|
+
return fuzzyCompareNumbers(actual, expected, fractionDigits) === 0;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function resizePanel({
|
|
558
|
+
panelConstraints: panelConstraintsArray,
|
|
559
|
+
panelIndex,
|
|
560
|
+
size
|
|
561
|
+
}) {
|
|
562
|
+
const panelConstraints = panelConstraintsArray[panelIndex];
|
|
563
|
+
assert(panelConstraints != null);
|
|
564
|
+
const { collapsedSize = 0, collapsible, maxSize = 100, minSize = 0 } = panelConstraints;
|
|
565
|
+
if (fuzzyCompareNumbers(size, minSize) < 0) {
|
|
566
|
+
if (collapsible) {
|
|
567
|
+
const halfwayPoint = (collapsedSize + minSize) / 2;
|
|
568
|
+
if (fuzzyCompareNumbers(size, halfwayPoint) < 0)
|
|
569
|
+
size = collapsedSize;
|
|
570
|
+
else
|
|
571
|
+
size = minSize;
|
|
572
|
+
} else {
|
|
573
|
+
size = minSize;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
size = Math.min(maxSize, size);
|
|
577
|
+
size = Number.parseFloat(size.toFixed(PRECISION));
|
|
578
|
+
return size;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function validatePanelGroupLayout({
|
|
582
|
+
layout: prevLayout,
|
|
583
|
+
panelConstraints
|
|
584
|
+
}) {
|
|
585
|
+
const nextLayout = [...prevLayout];
|
|
586
|
+
const nextLayoutTotalSize = nextLayout.reduce(
|
|
587
|
+
(accumulated, current) => accumulated + current,
|
|
588
|
+
0
|
|
589
|
+
);
|
|
590
|
+
if (nextLayout.length !== panelConstraints.length) {
|
|
591
|
+
throw new Error(
|
|
592
|
+
`Invalid ${panelConstraints.length} panel layout: ${nextLayout.map((size) => `${size}%`).join(", ")}`
|
|
593
|
+
);
|
|
594
|
+
} else if (!fuzzyNumbersEqual(nextLayoutTotalSize, 100)) {
|
|
595
|
+
{
|
|
596
|
+
console.warn(
|
|
597
|
+
`WARNING: Invalid layout total size: ${nextLayout.map((size) => `${size}%`).join(", ")}. Layout normalization will be applied.`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
for (let index = 0; index < panelConstraints.length; index++) {
|
|
601
|
+
const unsafeSize = nextLayout[index];
|
|
602
|
+
assert(unsafeSize != null);
|
|
603
|
+
const safeSize = 100 / nextLayoutTotalSize * unsafeSize;
|
|
604
|
+
nextLayout[index] = safeSize;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
let remainingSize = 0;
|
|
608
|
+
for (let index = 0; index < panelConstraints.length; index++) {
|
|
609
|
+
const unsafeSize = nextLayout[index];
|
|
610
|
+
assert(unsafeSize != null);
|
|
611
|
+
const safeSize = resizePanel({
|
|
612
|
+
panelConstraints,
|
|
613
|
+
panelIndex: index,
|
|
614
|
+
size: unsafeSize
|
|
615
|
+
});
|
|
616
|
+
if (unsafeSize !== safeSize) {
|
|
617
|
+
remainingSize += unsafeSize - safeSize;
|
|
618
|
+
nextLayout[index] = safeSize;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (!fuzzyNumbersEqual(remainingSize, 0)) {
|
|
622
|
+
for (let index = 0; index < panelConstraints.length; index++) {
|
|
623
|
+
const prevSize = nextLayout[index];
|
|
624
|
+
assert(prevSize != null);
|
|
625
|
+
const unsafeSize = prevSize + remainingSize;
|
|
626
|
+
const safeSize = resizePanel({
|
|
627
|
+
panelConstraints,
|
|
628
|
+
panelIndex: index,
|
|
629
|
+
size: unsafeSize
|
|
630
|
+
});
|
|
631
|
+
if (prevSize !== safeSize) {
|
|
632
|
+
remainingSize -= safeSize - prevSize;
|
|
633
|
+
nextLayout[index] = safeSize;
|
|
634
|
+
if (fuzzyNumbersEqual(remainingSize, 0))
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return nextLayout;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function callPanelCallbacks(panelsArray, layout, panelIdToLastNotifiedSizeMap) {
|
|
643
|
+
layout.forEach((size, index) => {
|
|
644
|
+
const panelData = panelsArray[index];
|
|
645
|
+
assert(panelData);
|
|
646
|
+
const { callbacks, constraints, id: panelId } = panelData;
|
|
647
|
+
const { collapsedSize = 0, collapsible } = constraints;
|
|
648
|
+
const lastNotifiedSize = panelIdToLastNotifiedSizeMap[panelId];
|
|
649
|
+
if (lastNotifiedSize == null || size !== lastNotifiedSize) {
|
|
650
|
+
panelIdToLastNotifiedSizeMap[panelId] = size;
|
|
651
|
+
const { onCollapse, onExpand, onResize } = callbacks;
|
|
652
|
+
if (onResize)
|
|
653
|
+
onResize(size, lastNotifiedSize);
|
|
654
|
+
if (collapsible && (onCollapse || onExpand)) {
|
|
655
|
+
if (onExpand && (lastNotifiedSize == null || lastNotifiedSize === collapsedSize) && size !== collapsedSize) {
|
|
656
|
+
onExpand();
|
|
657
|
+
}
|
|
658
|
+
if (onCollapse && (lastNotifiedSize == null || lastNotifiedSize !== collapsedSize) && size === collapsedSize) {
|
|
659
|
+
onCollapse();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
function compareLayouts(a, b) {
|
|
667
|
+
if (a.length !== b.length) {
|
|
668
|
+
return false;
|
|
669
|
+
} else {
|
|
670
|
+
for (let index = 0; index < a.length; index++) {
|
|
671
|
+
if (a[index] !== b[index])
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
function adjustLayoutByDelta({
|
|
678
|
+
delta,
|
|
679
|
+
layout: prevLayout,
|
|
680
|
+
panelConstraints: panelConstraintsArray,
|
|
681
|
+
pivotIndices,
|
|
682
|
+
trigger
|
|
683
|
+
}) {
|
|
684
|
+
if (fuzzyNumbersEqual(delta, 0))
|
|
685
|
+
return prevLayout;
|
|
686
|
+
const nextLayout = [...prevLayout];
|
|
687
|
+
const [firstPivotIndex, secondPivotIndex] = pivotIndices;
|
|
688
|
+
assert(firstPivotIndex != null);
|
|
689
|
+
assert(secondPivotIndex != null);
|
|
690
|
+
let deltaApplied = 0;
|
|
691
|
+
{
|
|
692
|
+
if (trigger === "keyboard") {
|
|
693
|
+
{
|
|
694
|
+
const index = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
695
|
+
const panelConstraints = panelConstraintsArray[index];
|
|
696
|
+
assert(panelConstraints);
|
|
697
|
+
if (panelConstraints.collapsible) {
|
|
698
|
+
const prevSize = prevLayout[index];
|
|
699
|
+
assert(prevSize != null);
|
|
700
|
+
const panelConstraints2 = panelConstraintsArray[index];
|
|
701
|
+
assert(panelConstraints2);
|
|
702
|
+
const { collapsedSize = 0, minSize = 0 } = panelConstraints2;
|
|
703
|
+
if (fuzzyNumbersEqual(prevSize, collapsedSize)) {
|
|
704
|
+
const localDelta = minSize - prevSize;
|
|
705
|
+
if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0)
|
|
706
|
+
delta = delta < 0 ? 0 - localDelta : localDelta;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
{
|
|
711
|
+
const index = delta < 0 ? firstPivotIndex : secondPivotIndex;
|
|
712
|
+
const panelConstraints = panelConstraintsArray[index];
|
|
713
|
+
assert(panelConstraints);
|
|
714
|
+
const { collapsible } = panelConstraints;
|
|
715
|
+
if (collapsible) {
|
|
716
|
+
const prevSize = prevLayout[index];
|
|
717
|
+
assert(prevSize != null);
|
|
718
|
+
const panelConstraints2 = panelConstraintsArray[index];
|
|
719
|
+
assert(panelConstraints2);
|
|
720
|
+
const { collapsedSize = 0, minSize = 0 } = panelConstraints2;
|
|
721
|
+
if (fuzzyNumbersEqual(prevSize, minSize)) {
|
|
722
|
+
const localDelta = prevSize - collapsedSize;
|
|
723
|
+
if (fuzzyCompareNumbers(localDelta, Math.abs(delta)) > 0)
|
|
724
|
+
delta = delta < 0 ? 0 - localDelta : localDelta;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
{
|
|
731
|
+
const increment = delta < 0 ? 1 : -1;
|
|
732
|
+
let index = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
733
|
+
let maxAvailableDelta = 0;
|
|
734
|
+
while (true) {
|
|
735
|
+
const prevSize = prevLayout[index];
|
|
736
|
+
assert(prevSize != null);
|
|
737
|
+
const maxSafeSize = resizePanel({
|
|
738
|
+
panelConstraints: panelConstraintsArray,
|
|
739
|
+
panelIndex: index,
|
|
740
|
+
size: 100
|
|
741
|
+
});
|
|
742
|
+
const delta2 = maxSafeSize - prevSize;
|
|
743
|
+
maxAvailableDelta += delta2;
|
|
744
|
+
index += increment;
|
|
745
|
+
if (index < 0 || index >= panelConstraintsArray.length)
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
const minAbsDelta = Math.min(Math.abs(delta), Math.abs(maxAvailableDelta));
|
|
749
|
+
delta = delta < 0 ? 0 - minAbsDelta : minAbsDelta;
|
|
750
|
+
}
|
|
751
|
+
{
|
|
752
|
+
const pivotIndex = delta < 0 ? firstPivotIndex : secondPivotIndex;
|
|
753
|
+
let index = pivotIndex;
|
|
754
|
+
while (index >= 0 && index < panelConstraintsArray.length) {
|
|
755
|
+
const deltaRemaining = Math.abs(delta) - Math.abs(deltaApplied);
|
|
756
|
+
const prevSize = prevLayout[index];
|
|
757
|
+
assert(prevSize != null);
|
|
758
|
+
const unsafeSize = prevSize - deltaRemaining;
|
|
759
|
+
const safeSize = resizePanel({
|
|
760
|
+
panelConstraints: panelConstraintsArray,
|
|
761
|
+
panelIndex: index,
|
|
762
|
+
size: unsafeSize
|
|
763
|
+
});
|
|
764
|
+
if (!fuzzyNumbersEqual(prevSize, safeSize)) {
|
|
765
|
+
deltaApplied += prevSize - safeSize;
|
|
766
|
+
nextLayout[index] = safeSize;
|
|
767
|
+
if (deltaApplied.toPrecision(3).localeCompare(Math.abs(delta).toPrecision(3), void 0, {
|
|
768
|
+
numeric: true
|
|
769
|
+
}) >= 0) {
|
|
770
|
+
break;
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (delta < 0)
|
|
774
|
+
index--;
|
|
775
|
+
else
|
|
776
|
+
index++;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (fuzzyNumbersEqual(deltaApplied, 0)) {
|
|
780
|
+
return prevLayout;
|
|
781
|
+
}
|
|
782
|
+
{
|
|
783
|
+
const pivotIndex = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
784
|
+
const prevSize = prevLayout[pivotIndex];
|
|
785
|
+
assert(prevSize != null);
|
|
786
|
+
const unsafeSize = prevSize + deltaApplied;
|
|
787
|
+
const safeSize = resizePanel({
|
|
788
|
+
panelConstraints: panelConstraintsArray,
|
|
789
|
+
panelIndex: pivotIndex,
|
|
790
|
+
size: unsafeSize
|
|
791
|
+
});
|
|
792
|
+
nextLayout[pivotIndex] = safeSize;
|
|
793
|
+
if (!fuzzyNumbersEqual(safeSize, unsafeSize)) {
|
|
794
|
+
let deltaRemaining = unsafeSize - safeSize;
|
|
795
|
+
const pivotIndex2 = delta < 0 ? secondPivotIndex : firstPivotIndex;
|
|
796
|
+
let index = pivotIndex2;
|
|
797
|
+
while (index >= 0 && index < panelConstraintsArray.length) {
|
|
798
|
+
const prevSize2 = nextLayout[index];
|
|
799
|
+
assert(prevSize2 != null);
|
|
800
|
+
const unsafeSize2 = prevSize2 + deltaRemaining;
|
|
801
|
+
const safeSize2 = resizePanel({
|
|
802
|
+
panelConstraints: panelConstraintsArray,
|
|
803
|
+
panelIndex: index,
|
|
804
|
+
size: unsafeSize2
|
|
805
|
+
});
|
|
806
|
+
if (!fuzzyNumbersEqual(prevSize2, safeSize2)) {
|
|
807
|
+
deltaRemaining -= safeSize2 - prevSize2;
|
|
808
|
+
nextLayout[index] = safeSize2;
|
|
809
|
+
}
|
|
810
|
+
if (fuzzyNumbersEqual(deltaRemaining, 0))
|
|
811
|
+
break;
|
|
812
|
+
if (delta > 0)
|
|
813
|
+
index--;
|
|
814
|
+
else
|
|
815
|
+
index++;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
const totalSize = nextLayout.reduce((total, size) => size + total, 0);
|
|
820
|
+
if (!fuzzyNumbersEqual(totalSize, 100))
|
|
821
|
+
return prevLayout;
|
|
822
|
+
return nextLayout;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
function calculateDragOffsetPercentage(event, dragHandleId, direction, initialDragState, panelGroupElement) {
|
|
826
|
+
const isHorizontal = direction === "horizontal";
|
|
827
|
+
const handleElement = getResizeHandleElement(dragHandleId, panelGroupElement);
|
|
828
|
+
assert(handleElement);
|
|
829
|
+
const groupId = handleElement.getAttribute("data-panel-group-id");
|
|
830
|
+
assert(groupId);
|
|
831
|
+
const { initialCursorPosition } = initialDragState;
|
|
832
|
+
const cursorPosition = getResizeEventCursorPosition(direction, event);
|
|
833
|
+
const groupElement = getPanelGroupElement(groupId, panelGroupElement);
|
|
834
|
+
assert(groupElement);
|
|
835
|
+
const groupRect = groupElement.getBoundingClientRect();
|
|
836
|
+
const groupSizeInPixels = isHorizontal ? groupRect.width : groupRect.height;
|
|
837
|
+
const offsetPixels = cursorPosition - initialCursorPosition;
|
|
838
|
+
const offsetPercentage = offsetPixels / groupSizeInPixels * 100;
|
|
839
|
+
return offsetPercentage;
|
|
840
|
+
}
|
|
841
|
+
function calculateDeltaPercentage(event, dragHandleId, direction, initialDragState, keyboardResizeBy, panelGroupElement) {
|
|
842
|
+
if (isKeyDown(event)) {
|
|
843
|
+
const isHorizontal = direction === "horizontal";
|
|
844
|
+
let delta = 0;
|
|
845
|
+
if (event.shiftKey)
|
|
846
|
+
delta = 100;
|
|
847
|
+
else
|
|
848
|
+
delta = keyboardResizeBy ?? 10;
|
|
849
|
+
let movement = 0;
|
|
850
|
+
switch (event.key) {
|
|
851
|
+
case "ArrowDown":
|
|
852
|
+
movement = isHorizontal ? 0 : delta;
|
|
853
|
+
break;
|
|
854
|
+
case "ArrowLeft":
|
|
855
|
+
movement = isHorizontal ? -delta : 0;
|
|
856
|
+
break;
|
|
857
|
+
case "ArrowRight":
|
|
858
|
+
movement = isHorizontal ? delta : 0;
|
|
859
|
+
break;
|
|
860
|
+
case "ArrowUp":
|
|
861
|
+
movement = isHorizontal ? 0 : -delta;
|
|
862
|
+
break;
|
|
863
|
+
case "End":
|
|
864
|
+
movement = 100;
|
|
865
|
+
break;
|
|
866
|
+
case "Home":
|
|
867
|
+
movement = -100;
|
|
868
|
+
break;
|
|
869
|
+
}
|
|
870
|
+
return movement;
|
|
871
|
+
} else {
|
|
872
|
+
if (initialDragState == null)
|
|
873
|
+
return 0;
|
|
874
|
+
return calculateDragOffsetPercentage(
|
|
875
|
+
event,
|
|
876
|
+
dragHandleId,
|
|
877
|
+
direction,
|
|
878
|
+
initialDragState,
|
|
879
|
+
panelGroupElement
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
function calculateAriaValues({
|
|
884
|
+
layout,
|
|
885
|
+
panelsArray,
|
|
886
|
+
pivotIndices
|
|
887
|
+
}) {
|
|
888
|
+
let currentMinSize = 0;
|
|
889
|
+
let currentMaxSize = 100;
|
|
890
|
+
let totalMinSize = 0;
|
|
891
|
+
let totalMaxSize = 0;
|
|
892
|
+
const firstIndex = pivotIndices[0];
|
|
893
|
+
assert(firstIndex != null);
|
|
894
|
+
panelsArray.forEach((panelData, index) => {
|
|
895
|
+
const { constraints } = panelData;
|
|
896
|
+
const { maxSize = 100, minSize = 0 } = constraints;
|
|
897
|
+
if (index === firstIndex) {
|
|
898
|
+
currentMinSize = minSize;
|
|
899
|
+
currentMaxSize = maxSize;
|
|
900
|
+
} else {
|
|
901
|
+
totalMinSize += minSize;
|
|
902
|
+
totalMaxSize += maxSize;
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
const valueMax = Math.min(currentMaxSize, 100 - totalMinSize);
|
|
906
|
+
const valueMin = Math.max(currentMinSize, 100 - totalMaxSize);
|
|
907
|
+
const valueNow = layout[firstIndex];
|
|
908
|
+
return {
|
|
909
|
+
valueMax,
|
|
910
|
+
valueMin,
|
|
911
|
+
valueNow
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
function calculateUnsafeDefaultLayout({
|
|
915
|
+
panelDataArray
|
|
916
|
+
}) {
|
|
917
|
+
const layout = Array(panelDataArray.length);
|
|
918
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
919
|
+
(panelData) => panelData.constraints
|
|
920
|
+
);
|
|
921
|
+
let numPanelsWithSizes = 0;
|
|
922
|
+
let remainingSize = 100;
|
|
923
|
+
for (let index = 0; index < panelDataArray.length; index++) {
|
|
924
|
+
const panelConstraints = panelConstraintsArray[index];
|
|
925
|
+
assert(panelConstraints);
|
|
926
|
+
const { defaultSize } = panelConstraints;
|
|
927
|
+
if (defaultSize != null) {
|
|
928
|
+
numPanelsWithSizes++;
|
|
929
|
+
layout[index] = defaultSize;
|
|
930
|
+
remainingSize -= defaultSize;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
for (let index = 0; index < panelDataArray.length; index++) {
|
|
934
|
+
const panelConstraints = panelConstraintsArray[index];
|
|
935
|
+
assert(panelConstraints);
|
|
936
|
+
const { defaultSize } = panelConstraints;
|
|
937
|
+
if (defaultSize != null)
|
|
938
|
+
continue;
|
|
939
|
+
const numRemainingPanels = panelDataArray.length - numPanelsWithSizes;
|
|
940
|
+
const size = remainingSize / numRemainingPanels;
|
|
941
|
+
numPanelsWithSizes++;
|
|
942
|
+
layout[index] = size;
|
|
943
|
+
remainingSize -= size;
|
|
944
|
+
}
|
|
945
|
+
return layout;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
function initializeDefaultStorage(storageObject) {
|
|
949
|
+
try {
|
|
950
|
+
if (typeof localStorage !== "undefined") {
|
|
951
|
+
storageObject.getItem = (name) => {
|
|
952
|
+
return localStorage.getItem(name);
|
|
953
|
+
};
|
|
954
|
+
storageObject.setItem = (name, value) => {
|
|
955
|
+
localStorage.setItem(name, value);
|
|
956
|
+
};
|
|
957
|
+
} else {
|
|
958
|
+
throw new TypeError("localStorage not supported in this environment");
|
|
959
|
+
}
|
|
960
|
+
} catch (error) {
|
|
961
|
+
console.error(error);
|
|
962
|
+
storageObject.getItem = () => null;
|
|
963
|
+
storageObject.setItem = () => {
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
function getPanelGroupKey(autoSaveId) {
|
|
968
|
+
return `destyler:${autoSaveId}`;
|
|
969
|
+
}
|
|
970
|
+
function getPanelKey(panels) {
|
|
971
|
+
return panels.map((panel) => {
|
|
972
|
+
const { constraints, id, idIsFromProps, order } = panel;
|
|
973
|
+
if (idIsFromProps) {
|
|
974
|
+
return id;
|
|
975
|
+
} else {
|
|
976
|
+
return order ? `${order}:${JSON.stringify(constraints)}` : JSON.stringify(constraints);
|
|
977
|
+
}
|
|
978
|
+
}).sort((a, b) => a.localeCompare(b)).join(",");
|
|
979
|
+
}
|
|
980
|
+
function loadSerializedPanelGroupState(autoSaveId, storage) {
|
|
981
|
+
try {
|
|
982
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
983
|
+
const serialized = storage.getItem(panelGroupKey);
|
|
984
|
+
if (serialized) {
|
|
985
|
+
const parsed = JSON.parse(serialized);
|
|
986
|
+
if (typeof parsed === "object" && parsed != null)
|
|
987
|
+
return parsed;
|
|
988
|
+
}
|
|
989
|
+
} catch (error) {
|
|
990
|
+
}
|
|
991
|
+
return null;
|
|
992
|
+
}
|
|
993
|
+
function loadPanelGroupState(autoSaveId, panels, storage) {
|
|
994
|
+
const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {};
|
|
995
|
+
const panelKey = getPanelKey(panels);
|
|
996
|
+
return state[panelKey] ?? null;
|
|
997
|
+
}
|
|
998
|
+
function savePanelGroupState(autoSaveId, panels, panelSizesBeforeCollapse, sizes, storage) {
|
|
999
|
+
const panelGroupKey = getPanelGroupKey(autoSaveId);
|
|
1000
|
+
const panelKey = getPanelKey(panels);
|
|
1001
|
+
const state = loadSerializedPanelGroupState(autoSaveId, storage) ?? {};
|
|
1002
|
+
state[panelKey] = {
|
|
1003
|
+
expandToSizes: Object.fromEntries(panelSizesBeforeCollapse.entries()),
|
|
1004
|
+
layout: sizes
|
|
1005
|
+
};
|
|
1006
|
+
try {
|
|
1007
|
+
storage.setItem(panelGroupKey, JSON.stringify(state));
|
|
1008
|
+
} catch (error) {
|
|
1009
|
+
console.error(error);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
function useWindowSplitterPanelGroupBehavior({
|
|
1014
|
+
eagerValuesRef,
|
|
1015
|
+
groupId,
|
|
1016
|
+
layout,
|
|
1017
|
+
panelDataArray,
|
|
1018
|
+
panelGroupElement,
|
|
1019
|
+
setLayout
|
|
1020
|
+
}) {
|
|
1021
|
+
watchEffect((onCleanup) => {
|
|
1022
|
+
const _panelGroupElement = panelGroupElement.value;
|
|
1023
|
+
if (!_panelGroupElement)
|
|
1024
|
+
return;
|
|
1025
|
+
const resizeHandleElements = getResizeHandleElementsForGroup(
|
|
1026
|
+
groupId,
|
|
1027
|
+
_panelGroupElement
|
|
1028
|
+
);
|
|
1029
|
+
for (let index = 0; index < panelDataArray.length - 1; index++) {
|
|
1030
|
+
const { valueMax, valueMin, valueNow } = calculateAriaValues({
|
|
1031
|
+
layout: layout.value,
|
|
1032
|
+
panelsArray: panelDataArray,
|
|
1033
|
+
pivotIndices: [index, index + 1]
|
|
1034
|
+
});
|
|
1035
|
+
const resizeHandleElement = resizeHandleElements[index];
|
|
1036
|
+
if (resizeHandleElement == null) {
|
|
1037
|
+
if (import.meta.env.DEV)
|
|
1038
|
+
console.warn(`WARNING: Missing resize handle for PanelGroup "${groupId}"`);
|
|
1039
|
+
} else {
|
|
1040
|
+
const panelData = panelDataArray[index];
|
|
1041
|
+
assert(panelData);
|
|
1042
|
+
resizeHandleElement.setAttribute("aria-controls", panelData.id);
|
|
1043
|
+
resizeHandleElement.setAttribute(
|
|
1044
|
+
"aria-valuemax",
|
|
1045
|
+
`${Math.round(valueMax)}`
|
|
1046
|
+
);
|
|
1047
|
+
resizeHandleElement.setAttribute(
|
|
1048
|
+
"aria-valuemin",
|
|
1049
|
+
`${Math.round(valueMin)}`
|
|
1050
|
+
);
|
|
1051
|
+
resizeHandleElement.setAttribute(
|
|
1052
|
+
"aria-valuenow",
|
|
1053
|
+
valueNow != null ? `${Math.round(valueNow)}` : ""
|
|
1054
|
+
);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
onCleanup(() => {
|
|
1058
|
+
resizeHandleElements.forEach((resizeHandleElement) => {
|
|
1059
|
+
resizeHandleElement.removeAttribute("aria-controls");
|
|
1060
|
+
resizeHandleElement.removeAttribute("aria-valuemax");
|
|
1061
|
+
resizeHandleElement.removeAttribute("aria-valuemin");
|
|
1062
|
+
resizeHandleElement.removeAttribute("aria-valuenow");
|
|
1063
|
+
});
|
|
1064
|
+
});
|
|
1065
|
+
});
|
|
1066
|
+
watchEffect((onCleanup) => {
|
|
1067
|
+
const _panelGroupElement = panelGroupElement.value;
|
|
1068
|
+
if (!_panelGroupElement)
|
|
1069
|
+
return;
|
|
1070
|
+
const eagerValues = eagerValuesRef.value;
|
|
1071
|
+
assert(eagerValues);
|
|
1072
|
+
const { panelDataArray: panelDataArray2 } = eagerValues;
|
|
1073
|
+
const groupElement = getPanelGroupElement(groupId, _panelGroupElement);
|
|
1074
|
+
assert(groupElement != null, `No group found for id "${groupId}"`);
|
|
1075
|
+
const handles = getResizeHandleElementsForGroup(groupId, _panelGroupElement);
|
|
1076
|
+
assert(handles);
|
|
1077
|
+
const cleanupFunctions = handles.map((handle) => {
|
|
1078
|
+
const handleId = handle.getAttribute("data-panel-resize-handle-id");
|
|
1079
|
+
assert(handleId);
|
|
1080
|
+
const [idBefore, idAfter] = getResizeHandlePanelIds(
|
|
1081
|
+
groupId,
|
|
1082
|
+
handleId,
|
|
1083
|
+
panelDataArray2,
|
|
1084
|
+
_panelGroupElement
|
|
1085
|
+
);
|
|
1086
|
+
if (idBefore == null || idAfter == null)
|
|
1087
|
+
return () => {
|
|
1088
|
+
};
|
|
1089
|
+
const onKeyDown = (event) => {
|
|
1090
|
+
if (event.defaultPrevented)
|
|
1091
|
+
return;
|
|
1092
|
+
switch (event.key) {
|
|
1093
|
+
case "Enter": {
|
|
1094
|
+
event.preventDefault();
|
|
1095
|
+
const index = panelDataArray2.findIndex(
|
|
1096
|
+
(panelData) => panelData.id === idBefore
|
|
1097
|
+
);
|
|
1098
|
+
if (index >= 0) {
|
|
1099
|
+
const panelData = panelDataArray2[index];
|
|
1100
|
+
assert(panelData);
|
|
1101
|
+
const size = layout.value[index];
|
|
1102
|
+
const {
|
|
1103
|
+
collapsedSize = 0,
|
|
1104
|
+
collapsible,
|
|
1105
|
+
minSize = 0
|
|
1106
|
+
} = panelData.constraints;
|
|
1107
|
+
if (size != null && collapsible) {
|
|
1108
|
+
const nextLayout = adjustLayoutByDelta({
|
|
1109
|
+
delta: fuzzyNumbersEqual(size, collapsedSize) ? minSize - collapsedSize : collapsedSize - size,
|
|
1110
|
+
layout: layout.value,
|
|
1111
|
+
panelConstraints: panelDataArray2.map(
|
|
1112
|
+
(panelData2) => panelData2.constraints
|
|
1113
|
+
),
|
|
1114
|
+
pivotIndices: determinePivotIndices(
|
|
1115
|
+
groupId,
|
|
1116
|
+
handleId,
|
|
1117
|
+
_panelGroupElement
|
|
1118
|
+
),
|
|
1119
|
+
trigger: "keyboard"
|
|
1120
|
+
});
|
|
1121
|
+
if (layout.value !== nextLayout)
|
|
1122
|
+
setLayout(nextLayout);
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
break;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
handle.addEventListener("keydown", onKeyDown);
|
|
1130
|
+
return () => {
|
|
1131
|
+
handle.removeEventListener("keydown", onKeyDown);
|
|
1132
|
+
};
|
|
1133
|
+
});
|
|
1134
|
+
onCleanup(() => {
|
|
1135
|
+
cleanupFunctions.forEach((cleanupFunction) => cleanupFunction());
|
|
1136
|
+
});
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
const defaultStorage = {
|
|
1141
|
+
getItem: (name) => {
|
|
1142
|
+
initializeDefaultStorage(defaultStorage);
|
|
1143
|
+
return defaultStorage.getItem(name);
|
|
1144
|
+
},
|
|
1145
|
+
setItem: (name, value) => {
|
|
1146
|
+
initializeDefaultStorage(defaultStorage);
|
|
1147
|
+
defaultStorage.setItem(name, value);
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
const splitterGroupProps = {
|
|
1151
|
+
...primitiveProps,
|
|
1152
|
+
/**
|
|
1153
|
+
* Group id; falls back to `useId` when not provided.
|
|
1154
|
+
*/
|
|
1155
|
+
id: {
|
|
1156
|
+
type: String,
|
|
1157
|
+
required: false
|
|
1158
|
+
},
|
|
1159
|
+
/**
|
|
1160
|
+
* Unique id used to auto-save group
|
|
1161
|
+
* arrangement via `localStorage`.
|
|
1162
|
+
*
|
|
1163
|
+
* @default null
|
|
1164
|
+
*/
|
|
1165
|
+
autoSaveId: {
|
|
1166
|
+
type: String,
|
|
1167
|
+
required: false,
|
|
1168
|
+
default: null
|
|
1169
|
+
},
|
|
1170
|
+
/**
|
|
1171
|
+
* The group orientation of splitter.
|
|
1172
|
+
*/
|
|
1173
|
+
direction: {
|
|
1174
|
+
type: String,
|
|
1175
|
+
required: true
|
|
1176
|
+
},
|
|
1177
|
+
/**
|
|
1178
|
+
* Step size when arrow key was pressed.
|
|
1179
|
+
*
|
|
1180
|
+
* @default 10
|
|
1181
|
+
*/
|
|
1182
|
+
keyboardResizeBy: {
|
|
1183
|
+
type: Number,
|
|
1184
|
+
required: false,
|
|
1185
|
+
default: 10
|
|
1186
|
+
},
|
|
1187
|
+
/**
|
|
1188
|
+
* Custom storage API; defaults to localStorage
|
|
1189
|
+
*
|
|
1190
|
+
* @default () => defaultStorage
|
|
1191
|
+
*/
|
|
1192
|
+
storage: {
|
|
1193
|
+
type: Object,
|
|
1194
|
+
required: false,
|
|
1195
|
+
default: () => defaultStorage
|
|
1196
|
+
}
|
|
1197
|
+
};
|
|
1198
|
+
const splitterGroupEmits = {
|
|
1199
|
+
/**
|
|
1200
|
+
* Event handler called when group layout changes
|
|
1201
|
+
*/
|
|
1202
|
+
layout: (_layout) => true
|
|
1203
|
+
};
|
|
1204
|
+
const [injectPanelGroupContext, providePanelGroupContext] = createContext("PanelGroup");
|
|
1205
|
+
const SplitterGroup = defineComponent({
|
|
1206
|
+
name: "DestylerSplitterGroup",
|
|
1207
|
+
props: splitterGroupProps,
|
|
1208
|
+
emits: splitterGroupEmits,
|
|
1209
|
+
slots: Object,
|
|
1210
|
+
setup(props, { emit }) {
|
|
1211
|
+
const LOCAL_STORAGE_DEBOUNCE_INTERVAL = 100;
|
|
1212
|
+
const debounceMap = {};
|
|
1213
|
+
const groupId = useId(props.id, "destyler-splitter-group");
|
|
1214
|
+
const dir = useDirection();
|
|
1215
|
+
const { forwardRef, currentElement: panelGroupElementRef } = useForwardExpose();
|
|
1216
|
+
const dragState = ref(null);
|
|
1217
|
+
const layout = ref([]);
|
|
1218
|
+
const panelIdToLastNotifiedSizeMapRef = ref({});
|
|
1219
|
+
const panelSizeBeforeCollapseRef = ref(/* @__PURE__ */ new Map());
|
|
1220
|
+
const prevDeltaRef = ref(0);
|
|
1221
|
+
const committedValuesRef = computed(() => ({
|
|
1222
|
+
autoSaveId: props.autoSaveId,
|
|
1223
|
+
direction: props.direction,
|
|
1224
|
+
dragState: dragState.value,
|
|
1225
|
+
id: groupId,
|
|
1226
|
+
keyboardResizeBy: props.keyboardResizeBy,
|
|
1227
|
+
storage: props.storage
|
|
1228
|
+
}));
|
|
1229
|
+
const eagerValuesRef = ref({
|
|
1230
|
+
layout: layout.value,
|
|
1231
|
+
panelDataArray: [],
|
|
1232
|
+
panelDataArrayChanged: false
|
|
1233
|
+
});
|
|
1234
|
+
const setLayout = (val) => layout.value = val;
|
|
1235
|
+
useWindowSplitterPanelGroupBehavior({
|
|
1236
|
+
eagerValuesRef,
|
|
1237
|
+
groupId,
|
|
1238
|
+
layout,
|
|
1239
|
+
panelDataArray: eagerValuesRef.value.panelDataArray,
|
|
1240
|
+
setLayout,
|
|
1241
|
+
panelGroupElement: panelGroupElementRef
|
|
1242
|
+
});
|
|
1243
|
+
watchEffect(() => {
|
|
1244
|
+
const { panelDataArray } = eagerValuesRef.value;
|
|
1245
|
+
const { autoSaveId } = props;
|
|
1246
|
+
if (autoSaveId) {
|
|
1247
|
+
if (layout.value.length === 0 || layout.value.length !== panelDataArray.length)
|
|
1248
|
+
return;
|
|
1249
|
+
let debouncedSave = debounceMap[autoSaveId];
|
|
1250
|
+
if (!debouncedSave) {
|
|
1251
|
+
debouncedSave = debounce(
|
|
1252
|
+
savePanelGroupState,
|
|
1253
|
+
LOCAL_STORAGE_DEBOUNCE_INTERVAL
|
|
1254
|
+
);
|
|
1255
|
+
debounceMap[autoSaveId] = debouncedSave;
|
|
1256
|
+
}
|
|
1257
|
+
const clonedPanelDataArray = [...panelDataArray];
|
|
1258
|
+
const clonedPanelSizesBeforeCollapse = new Map(
|
|
1259
|
+
panelSizeBeforeCollapseRef.value
|
|
1260
|
+
);
|
|
1261
|
+
debouncedSave(
|
|
1262
|
+
autoSaveId,
|
|
1263
|
+
clonedPanelDataArray,
|
|
1264
|
+
clonedPanelSizesBeforeCollapse,
|
|
1265
|
+
layout.value,
|
|
1266
|
+
props.storage
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
function getPanelStyle(panelData, defaultSize) {
|
|
1271
|
+
const { panelDataArray } = eagerValuesRef.value;
|
|
1272
|
+
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
1273
|
+
return computePanelFlexBoxStyle({
|
|
1274
|
+
defaultSize,
|
|
1275
|
+
dragState: dragState.value,
|
|
1276
|
+
layout: layout.value,
|
|
1277
|
+
panelData: panelDataArray,
|
|
1278
|
+
panelIndex
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
function registerPanel(panelData) {
|
|
1282
|
+
const { panelDataArray } = eagerValuesRef.value;
|
|
1283
|
+
panelDataArray.push(panelData);
|
|
1284
|
+
panelDataArray.sort((panelA, panelB) => {
|
|
1285
|
+
const orderA = panelA.order;
|
|
1286
|
+
const orderB = panelB.order;
|
|
1287
|
+
if (orderA == null && orderB == null)
|
|
1288
|
+
return 0;
|
|
1289
|
+
else if (orderA == null)
|
|
1290
|
+
return -1;
|
|
1291
|
+
else if (orderB == null)
|
|
1292
|
+
return 1;
|
|
1293
|
+
else
|
|
1294
|
+
return orderA - orderB;
|
|
1295
|
+
});
|
|
1296
|
+
eagerValuesRef.value.panelDataArrayChanged = true;
|
|
1297
|
+
}
|
|
1298
|
+
watch(() => eagerValuesRef.value.panelDataArrayChanged, () => {
|
|
1299
|
+
if (eagerValuesRef.value.panelDataArrayChanged) {
|
|
1300
|
+
eagerValuesRef.value.panelDataArrayChanged = false;
|
|
1301
|
+
const { autoSaveId, storage } = committedValuesRef.value;
|
|
1302
|
+
const { layout: prevLayout, panelDataArray } = eagerValuesRef.value;
|
|
1303
|
+
let unsafeLayout = null;
|
|
1304
|
+
if (autoSaveId) {
|
|
1305
|
+
const state = loadPanelGroupState(autoSaveId, panelDataArray, storage);
|
|
1306
|
+
if (state) {
|
|
1307
|
+
panelSizeBeforeCollapseRef.value = new Map(
|
|
1308
|
+
Object.entries(state.expandToSizes)
|
|
1309
|
+
);
|
|
1310
|
+
unsafeLayout = state.layout;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
if (unsafeLayout === null) {
|
|
1314
|
+
unsafeLayout = calculateUnsafeDefaultLayout({
|
|
1315
|
+
panelDataArray
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
const nextLayout = validatePanelGroupLayout({
|
|
1319
|
+
layout: unsafeLayout,
|
|
1320
|
+
panelConstraints: panelDataArray.map(
|
|
1321
|
+
(panelData) => panelData.constraints
|
|
1322
|
+
)
|
|
1323
|
+
});
|
|
1324
|
+
if (!areEqual(prevLayout, nextLayout)) {
|
|
1325
|
+
setLayout(nextLayout);
|
|
1326
|
+
eagerValuesRef.value.layout = nextLayout;
|
|
1327
|
+
emit("layout", nextLayout);
|
|
1328
|
+
callPanelCallbacks(
|
|
1329
|
+
panelDataArray,
|
|
1330
|
+
nextLayout,
|
|
1331
|
+
panelIdToLastNotifiedSizeMapRef.value
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
function registerResizeHandle(dragHandleId) {
|
|
1337
|
+
return function resizeHandler(event) {
|
|
1338
|
+
event.preventDefault();
|
|
1339
|
+
const panelGroupElement = panelGroupElementRef.value;
|
|
1340
|
+
if (!panelGroupElement)
|
|
1341
|
+
return () => null;
|
|
1342
|
+
const { direction, dragState: dragState2, id: groupId2, keyboardResizeBy } = committedValuesRef.value;
|
|
1343
|
+
const { layout: prevLayout, panelDataArray } = eagerValuesRef.value;
|
|
1344
|
+
const { initialLayout } = dragState2 ?? {};
|
|
1345
|
+
const pivotIndices = determinePivotIndices(
|
|
1346
|
+
groupId2,
|
|
1347
|
+
dragHandleId,
|
|
1348
|
+
panelGroupElement
|
|
1349
|
+
);
|
|
1350
|
+
let delta = calculateDeltaPercentage(
|
|
1351
|
+
event,
|
|
1352
|
+
dragHandleId,
|
|
1353
|
+
direction,
|
|
1354
|
+
dragState2,
|
|
1355
|
+
keyboardResizeBy,
|
|
1356
|
+
panelGroupElement
|
|
1357
|
+
);
|
|
1358
|
+
if (delta === 0)
|
|
1359
|
+
return;
|
|
1360
|
+
const isHorizontal = direction === "horizontal";
|
|
1361
|
+
if (dir.value === "rtl" && isHorizontal)
|
|
1362
|
+
delta = -delta;
|
|
1363
|
+
const panelConstraints = panelDataArray.map((panelData) => panelData.constraints);
|
|
1364
|
+
const nextLayout = adjustLayoutByDelta({
|
|
1365
|
+
delta,
|
|
1366
|
+
layout: initialLayout ?? prevLayout,
|
|
1367
|
+
panelConstraints,
|
|
1368
|
+
pivotIndices,
|
|
1369
|
+
trigger: isKeyDown(event) ? "keyboard" : "mouse-or-touch"
|
|
1370
|
+
});
|
|
1371
|
+
const layoutChanged = !compareLayouts(prevLayout, nextLayout);
|
|
1372
|
+
if (isMouseEvent(event) || isTouchEvent(event)) {
|
|
1373
|
+
if (prevDeltaRef.value !== delta) {
|
|
1374
|
+
prevDeltaRef.value = delta;
|
|
1375
|
+
if (!layoutChanged) {
|
|
1376
|
+
if (isHorizontal) {
|
|
1377
|
+
reportConstraintsViolation(
|
|
1378
|
+
dragHandleId,
|
|
1379
|
+
delta < 0 ? EXCEEDED_HORIZONTAL_MIN : EXCEEDED_HORIZONTAL_MAX
|
|
1380
|
+
);
|
|
1381
|
+
} else {
|
|
1382
|
+
reportConstraintsViolation(
|
|
1383
|
+
dragHandleId,
|
|
1384
|
+
delta < 0 ? EXCEEDED_VERTICAL_MIN : EXCEEDED_VERTICAL_MAX
|
|
1385
|
+
);
|
|
1386
|
+
}
|
|
1387
|
+
} else {
|
|
1388
|
+
reportConstraintsViolation(dragHandleId, 0);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
if (layoutChanged) {
|
|
1393
|
+
setLayout(nextLayout);
|
|
1394
|
+
eagerValuesRef.value.layout = nextLayout;
|
|
1395
|
+
emit("layout", nextLayout);
|
|
1396
|
+
callPanelCallbacks(
|
|
1397
|
+
panelDataArray,
|
|
1398
|
+
nextLayout,
|
|
1399
|
+
panelIdToLastNotifiedSizeMapRef.value
|
|
1400
|
+
);
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
function resizePanel(panelData, unsafePanelSize) {
|
|
1405
|
+
const { layout: prevLayout, panelDataArray } = eagerValuesRef.value;
|
|
1406
|
+
const panelConstraintsArray = panelDataArray.map((panelData2) => panelData2.constraints);
|
|
1407
|
+
const { panelSize, pivotIndices } = panelDataHelper(
|
|
1408
|
+
panelDataArray,
|
|
1409
|
+
panelData,
|
|
1410
|
+
prevLayout
|
|
1411
|
+
);
|
|
1412
|
+
assert(panelSize != null);
|
|
1413
|
+
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
1414
|
+
const delta = isLastPanel ? panelSize - unsafePanelSize : unsafePanelSize - panelSize;
|
|
1415
|
+
const nextLayout = adjustLayoutByDelta({
|
|
1416
|
+
delta,
|
|
1417
|
+
layout: prevLayout,
|
|
1418
|
+
panelConstraints: panelConstraintsArray,
|
|
1419
|
+
pivotIndices,
|
|
1420
|
+
trigger: "imperative-api"
|
|
1421
|
+
});
|
|
1422
|
+
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1423
|
+
setLayout(nextLayout);
|
|
1424
|
+
eagerValuesRef.value.layout = nextLayout;
|
|
1425
|
+
emit("layout", nextLayout);
|
|
1426
|
+
callPanelCallbacks(
|
|
1427
|
+
panelDataArray,
|
|
1428
|
+
nextLayout,
|
|
1429
|
+
panelIdToLastNotifiedSizeMapRef.value
|
|
1430
|
+
);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
function reevaluatePanelConstraints(panelData, prevConstraints) {
|
|
1434
|
+
const { layout: layout2, panelDataArray } = eagerValuesRef.value;
|
|
1435
|
+
const {
|
|
1436
|
+
collapsedSize: prevCollapsedSize = 0,
|
|
1437
|
+
collapsible: prevCollapsible
|
|
1438
|
+
} = prevConstraints;
|
|
1439
|
+
const {
|
|
1440
|
+
collapsedSize: nextCollapsedSize = 0,
|
|
1441
|
+
collapsible: nextCollapsible,
|
|
1442
|
+
maxSize: nextMaxSize = 100,
|
|
1443
|
+
minSize: nextMinSize = 0
|
|
1444
|
+
} = panelData.constraints;
|
|
1445
|
+
const { panelSize: prevPanelSize } = panelDataHelper(
|
|
1446
|
+
panelDataArray,
|
|
1447
|
+
panelData,
|
|
1448
|
+
layout2
|
|
1449
|
+
);
|
|
1450
|
+
if (prevPanelSize === null) {
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
if (prevCollapsible && nextCollapsible && prevPanelSize === prevCollapsedSize) {
|
|
1454
|
+
if (prevCollapsedSize !== nextCollapsedSize) {
|
|
1455
|
+
resizePanel(panelData, nextCollapsedSize);
|
|
1456
|
+
}
|
|
1457
|
+
} else if (prevPanelSize < nextMinSize) {
|
|
1458
|
+
resizePanel(panelData, nextMinSize);
|
|
1459
|
+
} else if (prevPanelSize > nextMaxSize) {
|
|
1460
|
+
resizePanel(panelData, nextMaxSize);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
function startDragging(dragHandleId, event) {
|
|
1464
|
+
const { direction } = committedValuesRef.value;
|
|
1465
|
+
const { layout: layout2 } = eagerValuesRef.value;
|
|
1466
|
+
if (!panelGroupElementRef.value)
|
|
1467
|
+
return;
|
|
1468
|
+
const handleElement = getResizeHandleElement(
|
|
1469
|
+
dragHandleId,
|
|
1470
|
+
panelGroupElementRef.value
|
|
1471
|
+
);
|
|
1472
|
+
assert(handleElement);
|
|
1473
|
+
const initialCursorPosition = getResizeEventCursorPosition(
|
|
1474
|
+
direction,
|
|
1475
|
+
event
|
|
1476
|
+
);
|
|
1477
|
+
dragState.value = {
|
|
1478
|
+
dragHandleId,
|
|
1479
|
+
dragHandleRect: handleElement.getBoundingClientRect(),
|
|
1480
|
+
initialCursorPosition,
|
|
1481
|
+
initialLayout: layout2
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
function stopDragging() {
|
|
1485
|
+
dragState.value = null;
|
|
1486
|
+
}
|
|
1487
|
+
function unregisterPanel(panelData) {
|
|
1488
|
+
const { panelDataArray } = eagerValuesRef.value;
|
|
1489
|
+
const index = findPanelDataIndex(panelDataArray, panelData);
|
|
1490
|
+
if (index >= 0) {
|
|
1491
|
+
panelDataArray.splice(index, 1);
|
|
1492
|
+
delete panelIdToLastNotifiedSizeMapRef.value[panelData.id];
|
|
1493
|
+
eagerValuesRef.value.panelDataArrayChanged = true;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
function collapsePanel(panelData) {
|
|
1497
|
+
const { layout: prevLayout, panelDataArray } = eagerValuesRef.value;
|
|
1498
|
+
if (panelData.constraints.collapsible) {
|
|
1499
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
1500
|
+
(panelData2) => panelData2.constraints
|
|
1501
|
+
);
|
|
1502
|
+
const {
|
|
1503
|
+
collapsedSize = 0,
|
|
1504
|
+
panelSize,
|
|
1505
|
+
pivotIndices
|
|
1506
|
+
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
1507
|
+
assert(
|
|
1508
|
+
panelSize != null,
|
|
1509
|
+
`Panel size not found for panel "${panelData.id}"`
|
|
1510
|
+
);
|
|
1511
|
+
if (panelSize !== collapsedSize) {
|
|
1512
|
+
panelSizeBeforeCollapseRef.value.set(panelData.id, panelSize);
|
|
1513
|
+
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
1514
|
+
const delta = isLastPanel ? panelSize - collapsedSize : collapsedSize - panelSize;
|
|
1515
|
+
const nextLayout = adjustLayoutByDelta({
|
|
1516
|
+
delta,
|
|
1517
|
+
layout: prevLayout,
|
|
1518
|
+
panelConstraints: panelConstraintsArray,
|
|
1519
|
+
pivotIndices,
|
|
1520
|
+
trigger: "imperative-api"
|
|
1521
|
+
});
|
|
1522
|
+
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1523
|
+
setLayout(nextLayout);
|
|
1524
|
+
eagerValuesRef.value.layout = nextLayout;
|
|
1525
|
+
emit("layout", nextLayout);
|
|
1526
|
+
callPanelCallbacks(
|
|
1527
|
+
panelDataArray,
|
|
1528
|
+
nextLayout,
|
|
1529
|
+
panelIdToLastNotifiedSizeMapRef.value
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
function expandPanel(panelData) {
|
|
1536
|
+
const { layout: prevLayout, panelDataArray } = eagerValuesRef.value;
|
|
1537
|
+
if (panelData.constraints.collapsible) {
|
|
1538
|
+
const panelConstraintsArray = panelDataArray.map(
|
|
1539
|
+
(panelData2) => panelData2.constraints
|
|
1540
|
+
);
|
|
1541
|
+
const {
|
|
1542
|
+
collapsedSize = 0,
|
|
1543
|
+
panelSize,
|
|
1544
|
+
minSize = 0,
|
|
1545
|
+
pivotIndices
|
|
1546
|
+
} = panelDataHelper(panelDataArray, panelData, prevLayout);
|
|
1547
|
+
if (panelSize === collapsedSize) {
|
|
1548
|
+
const prevPanelSize = panelSizeBeforeCollapseRef.value.get(
|
|
1549
|
+
panelData.id
|
|
1550
|
+
);
|
|
1551
|
+
const baseSize = prevPanelSize != null && prevPanelSize >= minSize ? prevPanelSize : minSize;
|
|
1552
|
+
const isLastPanel = findPanelDataIndex(panelDataArray, panelData) === panelDataArray.length - 1;
|
|
1553
|
+
const delta = isLastPanel ? panelSize - baseSize : baseSize - panelSize;
|
|
1554
|
+
const nextLayout = adjustLayoutByDelta({
|
|
1555
|
+
delta,
|
|
1556
|
+
layout: prevLayout,
|
|
1557
|
+
panelConstraints: panelConstraintsArray,
|
|
1558
|
+
pivotIndices,
|
|
1559
|
+
trigger: "imperative-api"
|
|
1560
|
+
});
|
|
1561
|
+
if (!compareLayouts(prevLayout, nextLayout)) {
|
|
1562
|
+
setLayout(nextLayout);
|
|
1563
|
+
eagerValuesRef.value.layout = nextLayout;
|
|
1564
|
+
emit("layout", nextLayout);
|
|
1565
|
+
callPanelCallbacks(
|
|
1566
|
+
panelDataArray,
|
|
1567
|
+
nextLayout,
|
|
1568
|
+
panelIdToLastNotifiedSizeMapRef.value
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
function getPanelSize(panelData) {
|
|
1575
|
+
const { layout: layout2, panelDataArray } = eagerValuesRef.value;
|
|
1576
|
+
const { panelSize } = panelDataHelper(panelDataArray, panelData, layout2);
|
|
1577
|
+
assert(
|
|
1578
|
+
panelSize != null,
|
|
1579
|
+
`Panel size not found for panel "${panelData.id}"`
|
|
1580
|
+
);
|
|
1581
|
+
return panelSize;
|
|
1582
|
+
}
|
|
1583
|
+
function isPanelCollapsed(panelData) {
|
|
1584
|
+
const { layout: layout2, panelDataArray } = eagerValuesRef.value;
|
|
1585
|
+
const {
|
|
1586
|
+
collapsedSize = 0,
|
|
1587
|
+
collapsible,
|
|
1588
|
+
panelSize
|
|
1589
|
+
} = panelDataHelper(panelDataArray, panelData, layout2);
|
|
1590
|
+
return collapsible === true && panelSize === collapsedSize;
|
|
1591
|
+
}
|
|
1592
|
+
function isPanelExpanded(panelData) {
|
|
1593
|
+
const { layout: layout2, panelDataArray } = eagerValuesRef.value;
|
|
1594
|
+
const {
|
|
1595
|
+
collapsedSize = 0,
|
|
1596
|
+
collapsible,
|
|
1597
|
+
panelSize
|
|
1598
|
+
} = panelDataHelper(panelDataArray, panelData, layout2);
|
|
1599
|
+
assert(
|
|
1600
|
+
panelSize != null,
|
|
1601
|
+
`Panel size not found for panel "${panelData.id}"`
|
|
1602
|
+
);
|
|
1603
|
+
return !collapsible || panelSize > collapsedSize;
|
|
1604
|
+
}
|
|
1605
|
+
providePanelGroupContext({
|
|
1606
|
+
direction: props.direction,
|
|
1607
|
+
dragState: dragState.value,
|
|
1608
|
+
groupId,
|
|
1609
|
+
reevaluatePanelConstraints,
|
|
1610
|
+
registerPanel,
|
|
1611
|
+
registerResizeHandle,
|
|
1612
|
+
resizePanel,
|
|
1613
|
+
startDragging,
|
|
1614
|
+
stopDragging,
|
|
1615
|
+
unregisterPanel,
|
|
1616
|
+
panelGroupElement: panelGroupElementRef,
|
|
1617
|
+
collapsePanel,
|
|
1618
|
+
expandPanel,
|
|
1619
|
+
isPanelCollapsed,
|
|
1620
|
+
isPanelExpanded,
|
|
1621
|
+
getPanelSize,
|
|
1622
|
+
getPanelStyle
|
|
1623
|
+
});
|
|
1624
|
+
function findPanelDataIndex(panelDataArray, panelData) {
|
|
1625
|
+
return panelDataArray.findIndex(
|
|
1626
|
+
(prevPanelData) => prevPanelData === panelData || prevPanelData.id === panelData.id
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
function panelDataHelper(panelDataArray, panelData, layout2) {
|
|
1630
|
+
const panelIndex = findPanelDataIndex(panelDataArray, panelData);
|
|
1631
|
+
const isLastPanel = panelIndex === panelDataArray.length - 1;
|
|
1632
|
+
const pivotIndices = isLastPanel ? [panelIndex - 1, panelIndex] : [panelIndex, panelIndex + 1];
|
|
1633
|
+
const panelSize = layout2[panelIndex];
|
|
1634
|
+
return {
|
|
1635
|
+
...panelData.constraints,
|
|
1636
|
+
panelSize,
|
|
1637
|
+
pivotIndices
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
return {
|
|
1641
|
+
forwardRef,
|
|
1642
|
+
groupId,
|
|
1643
|
+
layout
|
|
1644
|
+
};
|
|
1645
|
+
},
|
|
1646
|
+
render() {
|
|
1647
|
+
return h(Primitive, {
|
|
1648
|
+
"as": this.$props.as,
|
|
1649
|
+
"asChild": this.$props.asChild,
|
|
1650
|
+
"ref": (el) => this.forwardRef(el),
|
|
1651
|
+
"style": {
|
|
1652
|
+
display: "flex",
|
|
1653
|
+
flexDirection: this.$props.direction === "horizontal" ? "row" : "column",
|
|
1654
|
+
height: "100%",
|
|
1655
|
+
overflow: "hidden",
|
|
1656
|
+
width: "100%"
|
|
1657
|
+
},
|
|
1658
|
+
"data-panel-group": "",
|
|
1659
|
+
"data-orientation": this.$props.direction,
|
|
1660
|
+
"data-panel-group-id": this.groupId
|
|
1661
|
+
}, () => this.$slots.default?.({ layout: this.layout }));
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
const splitterResizeHandleProps = {
|
|
1666
|
+
...primitiveProps,
|
|
1667
|
+
/**
|
|
1668
|
+
* Resize handle id (unique within group);
|
|
1669
|
+
* falls back to `useId` when not provided
|
|
1670
|
+
*/
|
|
1671
|
+
id: {
|
|
1672
|
+
type: String,
|
|
1673
|
+
required: false
|
|
1674
|
+
},
|
|
1675
|
+
/**
|
|
1676
|
+
* Allow this much margin when determining resizable handle hit detection
|
|
1677
|
+
*/
|
|
1678
|
+
hitAreaMargins: {
|
|
1679
|
+
type: Object,
|
|
1680
|
+
required: false
|
|
1681
|
+
},
|
|
1682
|
+
/**
|
|
1683
|
+
* Tabindex for the handle
|
|
1684
|
+
*
|
|
1685
|
+
* @default 0
|
|
1686
|
+
*/
|
|
1687
|
+
tabindex: {
|
|
1688
|
+
type: Number,
|
|
1689
|
+
required: false,
|
|
1690
|
+
default: 0
|
|
1691
|
+
},
|
|
1692
|
+
/**
|
|
1693
|
+
* Disable drag handle
|
|
1694
|
+
*/
|
|
1695
|
+
disabled: {
|
|
1696
|
+
type: Boolean,
|
|
1697
|
+
required: false
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
const splitterResizeHandleEmits = {
|
|
1701
|
+
/**
|
|
1702
|
+
* Event handler called when dragging the handler.
|
|
1703
|
+
*/
|
|
1704
|
+
dragging: (_isDragging) => true
|
|
1705
|
+
};
|
|
1706
|
+
const SplitterResizeHandle = defineComponent({
|
|
1707
|
+
name: "DestylerSplitterResizeHandle",
|
|
1708
|
+
props: splitterResizeHandleProps,
|
|
1709
|
+
emits: splitterResizeHandleEmits,
|
|
1710
|
+
setup(props, { emit }) {
|
|
1711
|
+
const { forwardRef, currentElement } = useForwardExpose();
|
|
1712
|
+
const { disabled } = toRefs(props);
|
|
1713
|
+
const panelGroupContext = injectPanelGroupContext();
|
|
1714
|
+
if (panelGroupContext === null) {
|
|
1715
|
+
throw new Error(
|
|
1716
|
+
"DestylerSplitterResizeHandle components must be rendered within a PanelGroup container"
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
const {
|
|
1720
|
+
direction,
|
|
1721
|
+
groupId,
|
|
1722
|
+
registerResizeHandle: registerResizeHandleWithParentGroup,
|
|
1723
|
+
startDragging,
|
|
1724
|
+
stopDragging,
|
|
1725
|
+
panelGroupElement
|
|
1726
|
+
} = panelGroupContext;
|
|
1727
|
+
const resizeHandleId = useId(props.id, "destyler-splitter-resize-handle");
|
|
1728
|
+
const state = ref("inactive");
|
|
1729
|
+
const isFocused = ref(false);
|
|
1730
|
+
const resizeHandler = ref(null);
|
|
1731
|
+
watch(disabled, () => {
|
|
1732
|
+
if (!isBrowser)
|
|
1733
|
+
return;
|
|
1734
|
+
if (disabled.value)
|
|
1735
|
+
resizeHandler.value = null;
|
|
1736
|
+
else
|
|
1737
|
+
resizeHandler.value = registerResizeHandleWithParentGroup(resizeHandleId);
|
|
1738
|
+
}, { immediate: true });
|
|
1739
|
+
watchEffect((onCleanup) => {
|
|
1740
|
+
if (disabled.value || resizeHandler.value === null)
|
|
1741
|
+
return;
|
|
1742
|
+
const element = currentElement.value;
|
|
1743
|
+
if (!element)
|
|
1744
|
+
return;
|
|
1745
|
+
assert(element);
|
|
1746
|
+
const setResizeHandlerState = (action, isActive, event) => {
|
|
1747
|
+
if (isActive) {
|
|
1748
|
+
switch (action) {
|
|
1749
|
+
case "down": {
|
|
1750
|
+
state.value = "drag";
|
|
1751
|
+
startDragging(resizeHandleId, event);
|
|
1752
|
+
emit("dragging", true);
|
|
1753
|
+
break;
|
|
1754
|
+
}
|
|
1755
|
+
case "move": {
|
|
1756
|
+
if (state.value !== "drag")
|
|
1757
|
+
state.value = "hover";
|
|
1758
|
+
resizeHandler.value?.(event);
|
|
1759
|
+
break;
|
|
1760
|
+
}
|
|
1761
|
+
case "up": {
|
|
1762
|
+
state.value = "hover";
|
|
1763
|
+
stopDragging();
|
|
1764
|
+
emit("dragging", false);
|
|
1765
|
+
break;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
} else {
|
|
1769
|
+
state.value = "inactive";
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
onCleanup(registerResizeHandle(
|
|
1773
|
+
resizeHandleId,
|
|
1774
|
+
element,
|
|
1775
|
+
direction,
|
|
1776
|
+
{
|
|
1777
|
+
coarse: props.hitAreaMargins?.coarse ?? 15,
|
|
1778
|
+
fine: props.hitAreaMargins?.fine ?? 5
|
|
1779
|
+
},
|
|
1780
|
+
setResizeHandlerState
|
|
1781
|
+
));
|
|
1782
|
+
});
|
|
1783
|
+
useWindowSplitterResizeHandlerBehavior({
|
|
1784
|
+
disabled,
|
|
1785
|
+
resizeHandler,
|
|
1786
|
+
handleId: resizeHandleId,
|
|
1787
|
+
panelGroupElement
|
|
1788
|
+
});
|
|
1789
|
+
return {
|
|
1790
|
+
resizeHandleId,
|
|
1791
|
+
disabled,
|
|
1792
|
+
state,
|
|
1793
|
+
direction,
|
|
1794
|
+
groupId,
|
|
1795
|
+
isFocused,
|
|
1796
|
+
forwardRef
|
|
1797
|
+
};
|
|
1798
|
+
},
|
|
1799
|
+
render() {
|
|
1800
|
+
return h(Primitive, {
|
|
1801
|
+
"id": this.resizeHandleId,
|
|
1802
|
+
"ref": (el) => this.forwardRef(el),
|
|
1803
|
+
"style": {
|
|
1804
|
+
touchAction: "none",
|
|
1805
|
+
userSelect: "none"
|
|
1806
|
+
},
|
|
1807
|
+
"role": "separator",
|
|
1808
|
+
"data-resize-handle": "",
|
|
1809
|
+
"tabindex": this.$props.tabindex,
|
|
1810
|
+
"data-state": this.state,
|
|
1811
|
+
"data-disabled": this.disabled ? "" : void 0,
|
|
1812
|
+
"data-orientation": this.direction,
|
|
1813
|
+
"data-panel-group-id": this.groupId,
|
|
1814
|
+
"data-resize-handle-active": this.state === "drag" ? "pointer" : this.isFocused ? "keyboard" : void 0,
|
|
1815
|
+
"data-resize-handle-state": this.state,
|
|
1816
|
+
"data-panel-resize-handle-enabled": !this.disabled,
|
|
1817
|
+
"data-panel-resize-handle-id": this.resizeHandleId,
|
|
1818
|
+
"onBlur": () => {
|
|
1819
|
+
this.isFocused = false;
|
|
1820
|
+
},
|
|
1821
|
+
"onFocus": () => {
|
|
1822
|
+
this.isFocused = false;
|
|
1823
|
+
}
|
|
1824
|
+
}, () => this.$slots.default?.());
|
|
1825
|
+
}
|
|
1826
|
+
});
|
|
1827
|
+
|
|
1828
|
+
const splitterPanelProps = {
|
|
1829
|
+
...primitiveProps,
|
|
1830
|
+
/**
|
|
1831
|
+
* The size of panel when it is collapsed.
|
|
1832
|
+
*/
|
|
1833
|
+
collapsedSize: {
|
|
1834
|
+
type: Number,
|
|
1835
|
+
required: false
|
|
1836
|
+
},
|
|
1837
|
+
/**
|
|
1838
|
+
* Should panel collapse when resized beyond its `minSize`. When `true`, it will be collapsed to `collapsedSize`.
|
|
1839
|
+
*/
|
|
1840
|
+
collapsible: {
|
|
1841
|
+
type: Boolean,
|
|
1842
|
+
required: false
|
|
1843
|
+
},
|
|
1844
|
+
/**
|
|
1845
|
+
* Initial size of panel (numeric value between 1-100)
|
|
1846
|
+
*
|
|
1847
|
+
* @default false
|
|
1848
|
+
*/
|
|
1849
|
+
defaultSize: {
|
|
1850
|
+
type: Number,
|
|
1851
|
+
required: false
|
|
1852
|
+
},
|
|
1853
|
+
/*
|
|
1854
|
+
* Panel id (unique within group);
|
|
1855
|
+
falls back to `useId` when not provided
|
|
1856
|
+
*/
|
|
1857
|
+
id: {
|
|
1858
|
+
type: String,
|
|
1859
|
+
required: false
|
|
1860
|
+
},
|
|
1861
|
+
/**
|
|
1862
|
+
* The maximum allowable size of panel (numeric value between 1-100); defaults to `100`
|
|
1863
|
+
*/
|
|
1864
|
+
maxSize: {
|
|
1865
|
+
type: Number,
|
|
1866
|
+
required: false
|
|
1867
|
+
},
|
|
1868
|
+
/**
|
|
1869
|
+
* The minimum allowable size of panel (numeric value between 1-100); defaults to `10`
|
|
1870
|
+
*/
|
|
1871
|
+
minSize: {
|
|
1872
|
+
type: Number,
|
|
1873
|
+
required: false
|
|
1874
|
+
},
|
|
1875
|
+
/**
|
|
1876
|
+
* The order of panel within group; required for groups with conditionally rendered panels
|
|
1877
|
+
*/
|
|
1878
|
+
order: {
|
|
1879
|
+
type: Number,
|
|
1880
|
+
required: false
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1883
|
+
const splitterPanelEmits = {
|
|
1884
|
+
/**
|
|
1885
|
+
* Event handler called when panel is collapsed.
|
|
1886
|
+
*/
|
|
1887
|
+
collapse: () => true,
|
|
1888
|
+
/**
|
|
1889
|
+
* Event handler called when panel is expanded.
|
|
1890
|
+
*/
|
|
1891
|
+
expand: () => true,
|
|
1892
|
+
/**
|
|
1893
|
+
* Event handler called when panel is resized;
|
|
1894
|
+
* size parameter is a numeric value
|
|
1895
|
+
* between 1-100.
|
|
1896
|
+
*/
|
|
1897
|
+
resize: (_size, _prevSize) => true
|
|
1898
|
+
};
|
|
1899
|
+
const SplitterPanel = defineComponent({
|
|
1900
|
+
name: "DestylerSplitterPanel",
|
|
1901
|
+
props: splitterPanelProps,
|
|
1902
|
+
emits: splitterPanelEmits,
|
|
1903
|
+
slots: Object,
|
|
1904
|
+
setup(props, { emit, expose }) {
|
|
1905
|
+
const panelGroupContext = injectPanelGroupContext();
|
|
1906
|
+
if (panelGroupContext === null) {
|
|
1907
|
+
throw new Error(
|
|
1908
|
+
"SplitterPanel components must be rendered within a SplitterGroup container"
|
|
1909
|
+
);
|
|
1910
|
+
}
|
|
1911
|
+
const { collapsePanel, expandPanel, getPanelSize, getPanelStyle, isPanelCollapsed, resizePanel, groupId, reevaluatePanelConstraints, registerPanel, unregisterPanel } = panelGroupContext;
|
|
1912
|
+
const panelId = useId(props.id, "destyler-splitter-panel");
|
|
1913
|
+
const panelDataRef = computed(() => ({
|
|
1914
|
+
callbacks: {
|
|
1915
|
+
onCollapse: () => emit("collapse"),
|
|
1916
|
+
onExpand: () => emit("expand"),
|
|
1917
|
+
onResize: (...args) => emit("resize", ...args)
|
|
1918
|
+
},
|
|
1919
|
+
constraints: {
|
|
1920
|
+
collapsedSize: props.collapsedSize,
|
|
1921
|
+
collapsible: props.collapsible,
|
|
1922
|
+
defaultSize: props.defaultSize,
|
|
1923
|
+
maxSize: props.maxSize,
|
|
1924
|
+
minSize: props.minSize
|
|
1925
|
+
},
|
|
1926
|
+
id: panelId,
|
|
1927
|
+
idIsFromProps: props.id !== void 0,
|
|
1928
|
+
order: props.order
|
|
1929
|
+
}));
|
|
1930
|
+
watch(() => panelDataRef.value.constraints, (prevConstraints, constraints) => {
|
|
1931
|
+
if (prevConstraints.collapsedSize !== constraints.collapsedSize || prevConstraints.collapsible !== constraints.collapsible || prevConstraints.maxSize !== constraints.maxSize || prevConstraints.minSize !== constraints.minSize) {
|
|
1932
|
+
reevaluatePanelConstraints(panelDataRef.value, prevConstraints);
|
|
1933
|
+
}
|
|
1934
|
+
}, { deep: true });
|
|
1935
|
+
onMounted(() => {
|
|
1936
|
+
const panelData = panelDataRef.value;
|
|
1937
|
+
registerPanel(panelData);
|
|
1938
|
+
onUnmounted(() => {
|
|
1939
|
+
unregisterPanel(panelData);
|
|
1940
|
+
});
|
|
1941
|
+
});
|
|
1942
|
+
const style = computed(() => getPanelStyle(panelDataRef.value, props.defaultSize));
|
|
1943
|
+
const isCollapsed = computed(() => isPanelCollapsed(panelDataRef.value));
|
|
1944
|
+
const isExpanded = computed(() => !isCollapsed.value);
|
|
1945
|
+
expose({
|
|
1946
|
+
collapse: () => {
|
|
1947
|
+
collapsePanel(panelDataRef.value);
|
|
1948
|
+
},
|
|
1949
|
+
expand: () => {
|
|
1950
|
+
expandPanel(panelDataRef.value);
|
|
1951
|
+
},
|
|
1952
|
+
getSize() {
|
|
1953
|
+
return getPanelSize(panelDataRef.value);
|
|
1954
|
+
},
|
|
1955
|
+
resize: (size) => {
|
|
1956
|
+
resizePanel(panelDataRef.value, size);
|
|
1957
|
+
},
|
|
1958
|
+
isCollapsed,
|
|
1959
|
+
isExpanded
|
|
1960
|
+
});
|
|
1961
|
+
return {
|
|
1962
|
+
groupId,
|
|
1963
|
+
panelId,
|
|
1964
|
+
style,
|
|
1965
|
+
isCollapsed,
|
|
1966
|
+
isExpanded
|
|
1967
|
+
};
|
|
1968
|
+
},
|
|
1969
|
+
render() {
|
|
1970
|
+
return h(Primitive, {
|
|
1971
|
+
"id": this.groupId,
|
|
1972
|
+
"as": this.$props.as,
|
|
1973
|
+
"asChild": this.$props.asChild,
|
|
1974
|
+
"style": this.style,
|
|
1975
|
+
"data-panel": "",
|
|
1976
|
+
"data-panel-collapsible": this.$props.collapsible || void 0,
|
|
1977
|
+
"data-panel-group-id": this.groupId,
|
|
1978
|
+
"data-panel-id": this.panelId,
|
|
1979
|
+
"data-panel-size": Number.parseFloat(`${this.style.flexGrow}`).toFixed(1)
|
|
1980
|
+
}, () => this.$slots.default?.({ isCollapsed: this.isCollapsed, isExpanded: this.isExpanded }));
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
|
|
1984
|
+
const splitterRootProps = {
|
|
1985
|
+
...primitiveProps
|
|
1986
|
+
};
|
|
1987
|
+
const SplitterRoot = defineComponent({
|
|
1988
|
+
name: "DestylerSplitterRoot",
|
|
1989
|
+
props: splitterRootProps,
|
|
1990
|
+
setup(_) {
|
|
1991
|
+
useForwardExpose();
|
|
1992
|
+
},
|
|
1993
|
+
render() {
|
|
1994
|
+
return h(Primitive, {
|
|
1995
|
+
as: this.$props.as,
|
|
1996
|
+
asChild: this.$props.asChild
|
|
1997
|
+
}, () => this.$slots.default?.());
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
|
|
2001
|
+
export { SplitterGroup, SplitterPanel, SplitterResizeHandle, SplitterRoot, splitterGroupEmits, splitterGroupProps, splitterPanelEmits, splitterPanelProps, splitterResizeHandleEmits, splitterResizeHandleProps, splitterRootProps };
|