@corvu-next/resizable 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1587 @@
1
+ import { createContext, merge, omit, createSignal, createEffect, createMemo, untrack, useContext, Show, createUniqueId } from 'solid-js';
2
+ import { useKeyedContext, createKeyedContext } from '@corvu-next/utils/create/keyedContext';
3
+ import { createComponent, mergeProps, effect, setStyleProperty, memo, template } from 'solid-js/web';
4
+ import { combineStyle, sortByDocumentPosition, callEventHandler } from '@corvu-next/utils/dom';
5
+ import { Dynamic } from '@corvu-next/utils/dynamic';
6
+ import { mergeRefs, some } from '@corvu-next/utils/reactivity';
7
+ import { dataIf, isFunction } from '@corvu-next/utils';
8
+ import createOnce from '@corvu-next/utils/create/once';
9
+ import createControllableSignal from '@corvu-next/utils/create/controllableSignal';
10
+ import createSize from '@corvu-next/utils/create/size';
11
+
12
+ // src/context.ts
13
+ var ResizableContext = createContext(null);
14
+ var createResizableContext = (contextId) => {
15
+ if (contextId === void 0) return ResizableContext;
16
+ const context = createKeyedContext(
17
+ `resizable-${contextId}`
18
+ );
19
+ return context;
20
+ };
21
+ var useResizableContext = (contextId) => {
22
+ if (contextId === void 0) {
23
+ const context2 = useContext(ResizableContext);
24
+ if (!context2) {
25
+ throw new Error(
26
+ "[corvu]: Resizable context not found. Make sure to wrap Resizable components in <Resizable.Root>"
27
+ );
28
+ }
29
+ return context2;
30
+ }
31
+ const context = useKeyedContext(
32
+ `resizable-${contextId}`
33
+ );
34
+ if (!context) {
35
+ throw new Error(
36
+ `[corvu]: Resizable context with id "${contextId}" not found. Make sure to wrap Resizable components in <Resizable.Root contextId="${contextId}">`
37
+ );
38
+ }
39
+ return context;
40
+ };
41
+ var InternalResizableContext = createContext(null);
42
+ var createInternalResizableContext = (contextId) => {
43
+ if (contextId === void 0) return InternalResizableContext;
44
+ const context = createKeyedContext(
45
+ `resizable-internal-${contextId}`
46
+ );
47
+ return context;
48
+ };
49
+ var useInternalResizableContext = (contextId) => {
50
+ if (contextId === void 0) {
51
+ const context2 = useContext(InternalResizableContext);
52
+ if (!context2) {
53
+ throw new Error(
54
+ "[corvu]: Resizable context not found. Make sure to wrap Resizable components in <Resizable.Root>"
55
+ );
56
+ }
57
+ return context2;
58
+ }
59
+ const context = useKeyedContext(
60
+ `resizable-internal-${contextId}`
61
+ );
62
+ if (!context) {
63
+ throw new Error(
64
+ `[corvu]: Resizable context with id "${contextId}" not found. Make sure to wrap Resizable components in <Resizable.Root contextId="${contextId}">`
65
+ );
66
+ }
67
+ return context;
68
+ };
69
+
70
+ // src/lib/utils.ts
71
+ var resolveSize = (size, rootSize) => {
72
+ if (typeof size === "number") {
73
+ return size;
74
+ }
75
+ if (!size.endsWith("px")) {
76
+ throw new Error(
77
+ `[corvu] Sizes must be a number or a string ending with 'px'. Got ${size}`
78
+ );
79
+ }
80
+ return fixToPrecision(parseFloat(size) / rootSize);
81
+ };
82
+ var splitPanels = (props) => {
83
+ const precedingPanels = props.panels.filter(
84
+ (panel) => !!(props.focusedElement.compareDocumentPosition(panel.data.element) & Node.DOCUMENT_POSITION_PRECEDING)
85
+ );
86
+ const followingPanels = props.panels.filter(
87
+ (panel) => !!(props.focusedElement.compareDocumentPosition(panel.data.element) & Node.DOCUMENT_POSITION_FOLLOWING)
88
+ );
89
+ return [precedingPanels, followingPanels];
90
+ };
91
+ var PRECISION = 6;
92
+ var fixToPrecision = (value) => parseFloat(value.toFixed(PRECISION));
93
+
94
+ // src/lib/cursor.ts
95
+ var globalCursorStyle = null;
96
+ var cursorStyleElement = null;
97
+ var globalResizeConstraints = 0;
98
+ var constraintToCursorMap = {
99
+ 1: "e-resize",
100
+ 2: "w-resize",
101
+ 3: "ew-resize",
102
+ 4: "s-resize",
103
+ 8: "n-resize",
104
+ 12: "ns-resize",
105
+ 5: "se-resize",
106
+ 9: "ne-resize",
107
+ 6: "sw-resize",
108
+ 10: "nw-resize"
109
+ };
110
+ var cachedCursorStyle = null;
111
+ var updateCursorStyle = () => {
112
+ if (!globalCursorStyle) {
113
+ if (cursorStyleElement) {
114
+ cachedCursorStyle = null;
115
+ cursorStyleElement.remove();
116
+ cursorStyleElement = null;
117
+ }
118
+ return;
119
+ }
120
+ let cursorStyle = constraintToCursorMap[globalResizeConstraints] ?? null;
121
+ if (cursorStyle === null) {
122
+ switch (globalCursorStyle) {
123
+ case "horizontal":
124
+ cursorStyle = "col-resize";
125
+ break;
126
+ case "vertical":
127
+ cursorStyle = "row-resize";
128
+ break;
129
+ case "both":
130
+ cursorStyle = "move";
131
+ break;
132
+ }
133
+ }
134
+ if (cursorStyle === cachedCursorStyle) return;
135
+ cachedCursorStyle = cursorStyle;
136
+ if (!cursorStyleElement) {
137
+ cursorStyleElement = document.createElement("style");
138
+ document.head.appendChild(cursorStyleElement);
139
+ }
140
+ cursorStyleElement.innerHTML = `*{cursor: ${cursorStyle}!important;}`;
141
+ };
142
+ var reportResizeConstraints = (orientation, constraints) => {
143
+ switch (orientation) {
144
+ case "horizontal":
145
+ if (constraints === 1) {
146
+ globalResizeConstraints |= 1;
147
+ globalResizeConstraints &= -3;
148
+ } else if (constraints === 2) {
149
+ globalResizeConstraints |= 2;
150
+ globalResizeConstraints &= -2;
151
+ } else if (constraints === 3) {
152
+ globalResizeConstraints |= 3;
153
+ } else {
154
+ globalResizeConstraints &= -4;
155
+ }
156
+ break;
157
+ case "vertical":
158
+ if (constraints === 1) {
159
+ globalResizeConstraints |= 4;
160
+ globalResizeConstraints &= -9;
161
+ } else if (constraints === 2) {
162
+ globalResizeConstraints |= 8;
163
+ globalResizeConstraints &= -5;
164
+ } else if (constraints === 3) {
165
+ globalResizeConstraints |= 12;
166
+ } else {
167
+ globalResizeConstraints &= -13;
168
+ }
169
+ break;
170
+ }
171
+ updateCursorStyle();
172
+ };
173
+ var resetResizeConstraints = () => {
174
+ globalResizeConstraints = 0;
175
+ updateCursorStyle();
176
+ };
177
+ var setGlobalCursorStyle = (cursorStyle) => {
178
+ globalCursorStyle = cursorStyle;
179
+ updateCursorStyle();
180
+ };
181
+ var handleResizeConstraints = (props) => {
182
+ if (fixToPrecision(props.distributablePercentage) !== fixToPrecision(props.desiredPercentage)) {
183
+ let constraints = null;
184
+ if (props.betweenCollapse === true) {
185
+ constraints = 3;
186
+ } else if (props.desiredPercentage < props.distributablePercentage && props.revertConstraints !== true || props.desiredPercentage > props.distributablePercentage && props.revertConstraints === true) {
187
+ constraints = 1;
188
+ } else {
189
+ constraints = 2;
190
+ }
191
+ reportResizeConstraints(props.orientation, constraints);
192
+ } else {
193
+ reportResizeConstraints(props.orientation, 0);
194
+ }
195
+ };
196
+ var handles = [];
197
+ var dragStartPos = null;
198
+ var globalHovered = null;
199
+ var INTERSECTION_TOLERANCE = 1;
200
+ var equalsWithTolerance = (a, b) => Math.abs(a - b) <= INTERSECTION_TOLERANCE;
201
+ var registerHandle = (handle) => {
202
+ handles.push(handle);
203
+ for (const handle2 of handles) {
204
+ for (const compareHandle of handles) {
205
+ if (handle2.orientation === compareHandle.orientation || handle2.element === compareHandle.element) {
206
+ continue;
207
+ }
208
+ const handleRect = handle2.element.getBoundingClientRect();
209
+ const compareHandleRect = compareHandle.element.getBoundingClientRect();
210
+ if (handle2.orientation === "horizontal") {
211
+ if (handleRect.left > compareHandleRect.right || handleRect.right < compareHandleRect.left) {
212
+ continue;
213
+ }
214
+ }
215
+ if (handle2.orientation === "vertical") {
216
+ if (handleRect.top > compareHandleRect.bottom || handleRect.bottom < compareHandleRect.top) {
217
+ continue;
218
+ }
219
+ }
220
+ const isStartIntersection = handle2.orientation === "horizontal" ? equalsWithTolerance(handleRect.top, compareHandleRect.bottom) : equalsWithTolerance(handleRect.left, compareHandleRect.right);
221
+ const isEndIntersection = handle2.orientation === "horizontal" ? equalsWithTolerance(handleRect.bottom, compareHandleRect.top) : equalsWithTolerance(handleRect.right, compareHandleRect.left);
222
+ if (isStartIntersection) {
223
+ handle2.startIntersection.setHandle(compareHandle);
224
+ }
225
+ if (isEndIntersection) {
226
+ handle2.endIntersection.setHandle(compareHandle);
227
+ }
228
+ }
229
+ }
230
+ return {
231
+ onDragStart: (event, target) => onDragStart(handle, event, target),
232
+ onHoveredChange: (state) => {
233
+ globalHovered = state;
234
+ const dragging = !!dragStartPos;
235
+ let cursorStyle = null;
236
+ switch (state) {
237
+ case "handle": {
238
+ const startHandle = handle.startIntersection.handle();
239
+ const endHandle = handle.endIntersection.handle();
240
+ if (!dragging) {
241
+ handle.setActive(true);
242
+ startHandle?.setActive(false);
243
+ endHandle?.setActive(false);
244
+ }
245
+ startHandle?.setHoveredAsIntersection(false);
246
+ endHandle?.setHoveredAsIntersection(false);
247
+ cursorStyle = handle.orientation;
248
+ break;
249
+ }
250
+ case "startIntersection": {
251
+ const startHandle = handle.startIntersection.handle();
252
+ if (!dragging) {
253
+ startHandle?.setActive(true);
254
+ }
255
+ startHandle?.setHoveredAsIntersection(true);
256
+ cursorStyle = "both";
257
+ break;
258
+ }
259
+ case "endIntersection": {
260
+ const endHandle = handle.endIntersection.handle();
261
+ if (!dragging) {
262
+ endHandle?.setActive(true);
263
+ }
264
+ endHandle?.setHoveredAsIntersection(true);
265
+ cursorStyle = "both";
266
+ break;
267
+ }
268
+ case null: {
269
+ const startHandle = handle.startIntersection.handle();
270
+ const endHandle = handle.endIntersection.handle();
271
+ if (!dragging && !handle.focused()) {
272
+ handle.setActive(false);
273
+ startHandle?.setActive(false);
274
+ endHandle?.setActive(false);
275
+ }
276
+ startHandle?.setHoveredAsIntersection(false);
277
+ endHandle?.setHoveredAsIntersection(false);
278
+ cursorStyle = null;
279
+ break;
280
+ }
281
+ }
282
+ if (!dragging && handle.handleCursorStyle()) {
283
+ setGlobalCursorStyle(cursorStyle);
284
+ }
285
+ }
286
+ };
287
+ };
288
+ var unregisterHandle = (handle) => {
289
+ handles.splice(handles.indexOf(handle), 1);
290
+ };
291
+ var onDragStart = (handle, event, target) => {
292
+ dragStartPos = { x: event.clientX, y: event.clientY };
293
+ handle.setDragging(true);
294
+ if (target === "startIntersection") {
295
+ handle.startIntersection.handle()?.setDragging(true);
296
+ }
297
+ if (target === "endIntersection") {
298
+ handle.endIntersection.handle()?.setDragging(true);
299
+ }
300
+ window.addEventListener("pointermove", onPointerMove);
301
+ window.addEventListener("touchmove", onTouchMove);
302
+ window.addEventListener("pointerup", onDragEnd);
303
+ window.addEventListener("touchend", onDragEnd);
304
+ window.addEventListener("contextmenu", onDragEnd);
305
+ };
306
+ var onPointerMove = (event) => onMove(event.clientX, event.clientY, event.altKey);
307
+ var onTouchMove = (event) => {
308
+ if (!event.touches[0]) return;
309
+ onMove(event.touches[0].clientX, event.touches[0].clientY, event.altKey);
310
+ };
311
+ var altKeyCache = false;
312
+ var onMove = (x, y, altKey) => {
313
+ if (!dragStartPos) return;
314
+ if (handles.some((handle) => handle.dragging() && handle.altKey === "only")) {
315
+ altKey = true;
316
+ }
317
+ if (handles.some((handle) => handle.dragging() && handle.altKey === false)) {
318
+ altKey = false;
319
+ }
320
+ if (altKeyCache !== altKey) {
321
+ dragStartPos = { x, y };
322
+ altKeyCache = altKey;
323
+ }
324
+ for (const handle of handles) {
325
+ if (!handle.dragging()) continue;
326
+ handle.onDrag(
327
+ handle.orientation === "horizontal" ? x - dragStartPos.x : y - dragStartPos.y,
328
+ altKey
329
+ );
330
+ }
331
+ };
332
+ var onDragEnd = (event) => {
333
+ for (const handle of handles) {
334
+ if (!handle.dragging()) {
335
+ if (some(handle.hovered, handle.focused, handle.hoveredAsIntersection)) {
336
+ handle.setActive(true);
337
+ if (handle.handleCursorStyle()) {
338
+ setGlobalCursorStyle(handle.orientation);
339
+ }
340
+ }
341
+ } else {
342
+ handle.setDragging(false);
343
+ handle.onDragEnd(event);
344
+ if (!handle.hovered() && !handle.hoveredAsIntersection()) {
345
+ handle.setActive(false);
346
+ }
347
+ if (!globalHovered && handle.handleCursorStyle()) {
348
+ setGlobalCursorStyle(null);
349
+ }
350
+ }
351
+ }
352
+ resetResizeConstraints();
353
+ dragStartPos = null;
354
+ window.removeEventListener("pointermove", onPointerMove);
355
+ window.removeEventListener("touchmove", onTouchMove);
356
+ window.removeEventListener("pointerup", onDragEnd);
357
+ window.removeEventListener("touchend", onDragEnd);
358
+ window.removeEventListener("contextmenu", onDragEnd);
359
+ };
360
+ var _tmpl$ = /* @__PURE__ */ template(`<div data-corvu-resizable-handle-start-intersection style="position:absolute;aspect-ratio:1 / 1;top:0;left:0;z-index:1">`);
361
+ var _tmpl$2 = /* @__PURE__ */ template(`<div data-corvu-resizable-handle-end-intersection style="position:absolute;aspect-ratio:1 / 1;bottom:0;right:0;z-index:1">`);
362
+ var ResizableHandle = (props) => {
363
+ const defaultedProps = merge({
364
+ startIntersection: true,
365
+ endIntersection: true,
366
+ altKey: true
367
+ }, props);
368
+ const localProps = defaultedProps;
369
+ const otherProps = omit(defaultedProps, "startIntersection", "endIntersection", "altKey", "onHandleDragStart", "onHandleDrag", "onHandleDragEnd", "contextId", "ref", "style", "disabled", "children", "onMouseEnter", "onMouseLeave", "onKeyDown", "onKeyUp", "onFocus", "onBlur", "onPointerDown");
370
+ const [ref, setRef] = createSignal(null);
371
+ const [hoveredAsIntersection, setHoveredAsIntersection] = createSignal(false);
372
+ const [hovered, setHovered] = createSignal(null);
373
+ const [focused, setFocused] = createSignal(false);
374
+ const [active, setActive] = createSignal(false);
375
+ const [dragging, setDragging] = createSignal(false);
376
+ const [startIntersectionHandle, setStartIntersectionHandle] = createSignal(null);
377
+ const [endIntersectionHandle, setEndIntersectionHandle] = createSignal(null);
378
+ const context = createMemo(() => useInternalResizableContext(localProps.contextId));
379
+ const ariaInformation = createMemo(() => {
380
+ const handle = ref();
381
+ if (!handle) {
382
+ return void 0;
383
+ }
384
+ const panels = context().panels();
385
+ const [precidingPanels, followingPanels] = splitPanels({
386
+ panels,
387
+ focusedElement: handle
388
+ });
389
+ const ariaControls = precidingPanels[precidingPanels.length - 1]?.data.id;
390
+ const ariaValueMax = followingPanels.reduce((acc, panel) => acc - resolveSize(panel.data.minSize, context().rootSize()), 1);
391
+ const ariaValueMin = precidingPanels.reduce((acc, panel) => acc + resolveSize(panel.data.minSize, context().rootSize()), 0);
392
+ const ariaValueNow = precidingPanels.reduce((acc, panel) => acc + resolveSize(panel.size(), context().rootSize()), 0);
393
+ return {
394
+ ariaControls,
395
+ ariaValueMax: fixToPrecision(ariaValueMax),
396
+ ariaValueMin: fixToPrecision(ariaValueMin),
397
+ ariaValueNow: fixToPrecision(ariaValueNow)
398
+ };
399
+ });
400
+ let globalHandleCallbacks = null;
401
+ createEffect((_prev) => {
402
+ if (localProps.disabled === true) return void 0;
403
+ const element = ref();
404
+ if (!element) return void 0;
405
+ const globalHandle = {
406
+ element,
407
+ orientation: context().orientation(),
408
+ handleCursorStyle: context().handleCursorStyle,
409
+ altKey: localProps.altKey,
410
+ startIntersection: {
411
+ handle: startIntersectionHandle,
412
+ setHandle: (handle) => {
413
+ if (localProps.startIntersection !== true) return;
414
+ setStartIntersectionHandle(handle);
415
+ }
416
+ },
417
+ endIntersection: {
418
+ handle: endIntersectionHandle,
419
+ setHandle: (handle) => {
420
+ if (localProps.endIntersection !== true) return;
421
+ setEndIntersectionHandle(handle);
422
+ }
423
+ },
424
+ hovered,
425
+ focused,
426
+ hoveredAsIntersection,
427
+ setHoveredAsIntersection,
428
+ active,
429
+ setActive,
430
+ dragging,
431
+ setDragging,
432
+ onDrag: (delta, altKey) => {
433
+ if (localProps.onHandleDrag !== void 0) {
434
+ const dragEvent = new CustomEvent("drag", {
435
+ cancelable: true
436
+ });
437
+ localProps.onHandleDrag(dragEvent);
438
+ if (dragEvent.defaultPrevented) return;
439
+ }
440
+ context().onDrag(element, delta, altKey);
441
+ },
442
+ onDragEnd: (event) => {
443
+ localProps.onHandleDragEnd?.(event);
444
+ context().onDragEnd();
445
+ }
446
+ };
447
+ globalHandleCallbacks = registerHandle(globalHandle);
448
+ return globalHandle;
449
+ }, (prevHandle) => {
450
+ if (prevHandle) {
451
+ unregisterHandle(prevHandle);
452
+ globalHandleCallbacks = null;
453
+ }
454
+ });
455
+ createEffect(() => {
456
+ const state = hovered();
457
+ return state;
458
+ }, (state) => {
459
+ globalHandleCallbacks?.onHoveredChange(state);
460
+ });
461
+ const onMouseEnter = (e) => {
462
+ if (callEventHandler(localProps.onMouseEnter, e) || localProps.disabled === true) return;
463
+ setHovered("handle");
464
+ };
465
+ const onMouseLeave = (e) => {
466
+ if (callEventHandler(localProps.onMouseLeave, e)) return;
467
+ setHovered(null);
468
+ };
469
+ const onKeyDown = (e) => {
470
+ if (callEventHandler(localProps.onKeyDown, e) || dragging()) return;
471
+ const element = ref();
472
+ if (!element) return;
473
+ const altKey = localProps.altKey === "only" || localProps.altKey !== false && e.altKey;
474
+ context().onKeyDown(element, e, altKey);
475
+ };
476
+ const onKeyUp = (e) => {
477
+ if (callEventHandler(localProps.onKeyUp, e) || e.key !== "Tab") return;
478
+ setFocused(true);
479
+ };
480
+ const onFocus = (e) => {
481
+ if (callEventHandler(localProps.onFocus, e) || hovered()) return;
482
+ setFocused(true);
483
+ setActive(true);
484
+ };
485
+ const onBlur = (e) => {
486
+ if (callEventHandler(localProps.onBlur, e)) return;
487
+ setFocused(false);
488
+ if (hovered()) return;
489
+ setActive(false);
490
+ };
491
+ const onPointerDown = (e) => {
492
+ if (callEventHandler(localProps.onPointerDown, e)) return;
493
+ if (callEventHandler(localProps.onHandleDragStart, e)) return;
494
+ const targetElement = e.target;
495
+ targetElement.setPointerCapture(e.pointerId);
496
+ let target = "handle";
497
+ if (targetElement.hasAttribute("data-corvu-resizable-handle-start-intersection")) {
498
+ target = "startIntersection";
499
+ }
500
+ if (targetElement.hasAttribute("data-corvu-resizable-handle-end-intersection")) {
501
+ target = "endIntersection";
502
+ }
503
+ globalHandleCallbacks?.onDragStart(e, target);
504
+ };
505
+ return createComponent(Dynamic, mergeProps({
506
+ as: "button",
507
+ ref(r$) {
508
+ var _ref$ = mergeRefs(setRef, localProps.ref);
509
+ typeof _ref$ === "function" && _ref$(r$);
510
+ },
511
+ get style() {
512
+ return combineStyle({
513
+ position: "relative",
514
+ cursor: context().handleCursorStyle() ? "inherit" : void 0,
515
+ "touch-action": "none",
516
+ "flex-shrink": 0
517
+ }, localProps.style);
518
+ },
519
+ get disabled() {
520
+ return localProps.disabled;
521
+ },
522
+ onBlur,
523
+ onFocus,
524
+ onKeyDown,
525
+ onKeyUp,
526
+ onMouseEnter,
527
+ onMouseLeave,
528
+ onPointerDown,
529
+ role: "separator",
530
+ get ["aria-controls"]() {
531
+ return ariaInformation()?.ariaControls;
532
+ },
533
+ get ["aria-orientation"]() {
534
+ return context().orientation();
535
+ },
536
+ get ["aria-valuemax"]() {
537
+ return ariaInformation()?.ariaValueMax;
538
+ },
539
+ get ["aria-valuemin"]() {
540
+ return ariaInformation()?.ariaValueMin;
541
+ },
542
+ get ["aria-valuenow"]() {
543
+ return ariaInformation()?.ariaValueNow;
544
+ },
545
+ get ["data-active"]() {
546
+ return dataIf(active());
547
+ },
548
+ get ["data-dragging"]() {
549
+ return dataIf(dragging());
550
+ },
551
+ get ["data-orientation"]() {
552
+ return context().orientation();
553
+ },
554
+ "data-corvu-resizable-handle": ""
555
+ }, otherProps, {
556
+ get children() {
557
+ return [createComponent(Show, {
558
+ get when() {
559
+ return startIntersectionHandle();
560
+ },
561
+ get children() {
562
+ var _el$ = _tmpl$();
563
+ _el$.addEventListener("mouseleave", (e) => {
564
+ if (ref()?.contains(e.relatedTarget) === true) {
565
+ setHovered("handle");
566
+ } else {
567
+ setHovered(null);
568
+ }
569
+ });
570
+ _el$.addEventListener("mouseenter", () => setHovered("startIntersection"));
571
+ effect((_p$) => {
572
+ var _v$ = context().orientation() === "horizontal" ? void 0 : "100%", _v$2 = context().orientation() === "horizontal" ? "100%" : void 0, _v$3 = context().orientation() === "horizontal" ? "translate3d(0, -100%, 0)" : "translate3d(-100%, 0, 0)";
573
+ _v$ !== _p$.e && setStyleProperty(_el$, "height", _p$.e = _v$);
574
+ _v$2 !== _p$.t && setStyleProperty(_el$, "width", _p$.t = _v$2);
575
+ _v$3 !== _p$.a && setStyleProperty(_el$, "transform", _p$.a = _v$3);
576
+ return _p$;
577
+ }, {
578
+ e: void 0,
579
+ t: void 0,
580
+ a: void 0
581
+ });
582
+ return _el$;
583
+ }
584
+ }), memo(() => localProps.children), createComponent(Show, {
585
+ get when() {
586
+ return endIntersectionHandle();
587
+ },
588
+ get children() {
589
+ var _el$2 = _tmpl$2();
590
+ _el$2.addEventListener("mouseleave", (e) => {
591
+ if (ref()?.contains(e.relatedTarget) === true) {
592
+ setHovered("handle");
593
+ } else {
594
+ setHovered(null);
595
+ }
596
+ });
597
+ _el$2.addEventListener("mouseenter", () => setHovered("endIntersection"));
598
+ effect((_p$) => {
599
+ var _v$4 = context().orientation() === "horizontal" ? void 0 : "100%", _v$5 = context().orientation() === "horizontal" ? "100%" : void 0, _v$6 = context().orientation() === "horizontal" ? "translate3d(0, 100%, 0)" : "translate3d(100%, 0, 0)";
600
+ _v$4 !== _p$.e && setStyleProperty(_el$2, "height", _p$.e = _v$4);
601
+ _v$5 !== _p$.t && setStyleProperty(_el$2, "width", _p$.t = _v$5);
602
+ _v$6 !== _p$.a && setStyleProperty(_el$2, "transform", _p$.a = _v$6);
603
+ return _p$;
604
+ }, {
605
+ e: void 0,
606
+ t: void 0,
607
+ a: void 0
608
+ });
609
+ return _el$2;
610
+ }
611
+ })];
612
+ }
613
+ }));
614
+ };
615
+ var Handle_default = ResizableHandle;
616
+ var ResizablePanelContext = createContext(null);
617
+ var createResizablePanelContext = (contextId) => {
618
+ if (contextId === void 0) return ResizablePanelContext;
619
+ const context = createKeyedContext(
620
+ `resizable-panel-${contextId}`
621
+ );
622
+ return context;
623
+ };
624
+ var useResizablePanelContext = (contextId) => {
625
+ if (contextId === void 0) {
626
+ const context2 = useContext(ResizablePanelContext);
627
+ if (!context2) {
628
+ throw new Error(
629
+ "[corvu]: Resizable panel context not found. Make sure to call usePanelContext under <Resizable.Panel>"
630
+ );
631
+ }
632
+ return context2;
633
+ }
634
+ const context = useKeyedContext(
635
+ `resizable-panel-${contextId}`
636
+ );
637
+ if (!context) {
638
+ throw new Error(
639
+ `[corvu]: Resizable context with id "${contextId}" not found. Make sure to call usePanelContext under <Resizable.Panel contextId="${contextId}">`
640
+ );
641
+ }
642
+ return context;
643
+ };
644
+ var ResizablePanel = (props) => {
645
+ const defaultedProps = merge({
646
+ initialSize: null,
647
+ minSize: 0,
648
+ maxSize: 1,
649
+ collapsible: false,
650
+ collapsedSize: 0,
651
+ collapseThreshold: 0.05,
652
+ panelId: createUniqueId()
653
+ }, props);
654
+ const localProps = defaultedProps;
655
+ const otherProps = omit(defaultedProps, "initialSize", "minSize", "maxSize", "collapsible", "collapsedSize", "collapseThreshold", "onResize", "onCollapse", "onExpand", "contextId", "panelId", "ref", "style", "children");
656
+ const [ref, setRef] = createSignal(null);
657
+ const context = createMemo(() => useInternalResizableContext(localProps.contextId));
658
+ const [panelInstance, setPanelInstance] = createSignal(null);
659
+ createEffect((prev) => {
660
+ const element = ref();
661
+ if (!element) return void 0;
662
+ const _context = context();
663
+ const instance = untrack(() => {
664
+ return _context.registerPanel({
665
+ id: localProps.panelId,
666
+ element,
667
+ initialSize: localProps.initialSize,
668
+ minSize: localProps.minSize,
669
+ maxSize: localProps.maxSize,
670
+ collapsible: localProps.collapsible,
671
+ collapsedSize: localProps.collapsedSize,
672
+ collapseThreshold: localProps.collapseThreshold,
673
+ onResize: localProps.onResize
674
+ });
675
+ });
676
+ setPanelInstance(instance);
677
+ return {
678
+ instance,
679
+ contextRef: context
680
+ };
681
+ }, (_prev) => {
682
+ if (_prev) {
683
+ _prev.contextRef().unregisterPanel(_prev.instance.data.id);
684
+ }
685
+ });
686
+ const panelSize = () => {
687
+ const instance = panelInstance();
688
+ if (!instance) {
689
+ if (typeof localProps.initialSize === "number") {
690
+ return localProps.initialSize;
691
+ }
692
+ return 1;
693
+ }
694
+ return instance.size();
695
+ };
696
+ const collapsed = createMemo((prev) => {
697
+ const instance = panelInstance();
698
+ if (localProps.collapsible !== true) {
699
+ return false;
700
+ }
701
+ const collapsed2 = instance ? instance.size() === resolveSize(localProps.collapsedSize, context().rootSize()) : false;
702
+ if (instance && prev !== collapsed2) {
703
+ if (collapsed2 && localProps.onCollapse !== void 0) {
704
+ localProps.onCollapse(instance.size());
705
+ } else if (!collapsed2 && localProps.onExpand !== void 0) {
706
+ localProps.onExpand(instance.size());
707
+ }
708
+ }
709
+ return collapsed2;
710
+ });
711
+ const resize2 = (size, strategy) => {
712
+ const instance = panelInstance();
713
+ if (!instance) {
714
+ return;
715
+ }
716
+ instance.resize(size, strategy ?? "both");
717
+ };
718
+ const collapse = (strategy) => {
719
+ const instance = panelInstance();
720
+ if (!instance) {
721
+ return;
722
+ }
723
+ instance.collapse(strategy ?? "both");
724
+ };
725
+ const expand = (strategy) => {
726
+ const instance = panelInstance();
727
+ if (!instance) {
728
+ return;
729
+ }
730
+ instance.expand(strategy ?? "both");
731
+ };
732
+ const childrenProps = {
733
+ get size() {
734
+ return panelSize();
735
+ },
736
+ get minSize() {
737
+ return localProps.minSize;
738
+ },
739
+ get maxSize() {
740
+ return localProps.maxSize;
741
+ },
742
+ get collapsible() {
743
+ return localProps.collapsible;
744
+ },
745
+ get collapsedSize() {
746
+ return localProps.collapsedSize;
747
+ },
748
+ get collapseThreshold() {
749
+ return localProps.collapseThreshold;
750
+ },
751
+ get collapsed() {
752
+ return collapsed();
753
+ },
754
+ resize: resize2,
755
+ collapse,
756
+ expand,
757
+ get panelId() {
758
+ return localProps.panelId;
759
+ }
760
+ };
761
+ const memoizedChildren = createOnce(() => localProps.children);
762
+ const resolveChildren = () => {
763
+ const children = memoizedChildren()();
764
+ if (isFunction(children)) {
765
+ return children(childrenProps);
766
+ }
767
+ return children;
768
+ };
769
+ const memoizedResizablePanel = createMemo(() => {
770
+ const ResizablePanelContext2 = createResizablePanelContext(localProps.contextId);
771
+ return createComponent(ResizablePanelContext2, {
772
+ value: {
773
+ size: panelSize,
774
+ minSize: () => localProps.minSize,
775
+ maxSize: () => localProps.maxSize,
776
+ collapsible: () => localProps.collapsible,
777
+ collapsedSize: () => localProps.collapsedSize,
778
+ collapseThreshold: () => localProps.collapseThreshold,
779
+ collapsed,
780
+ resize: resize2,
781
+ collapse,
782
+ expand,
783
+ panelId: () => localProps.panelId
784
+ },
785
+ get children() {
786
+ return createComponent(Dynamic, mergeProps({
787
+ as: "div",
788
+ ref(r$) {
789
+ var _ref$ = mergeRefs(setRef, localProps.ref);
790
+ typeof _ref$ === "function" && _ref$(r$);
791
+ },
792
+ get style() {
793
+ return combineStyle({
794
+ "flex-basis": panelSize() * 100 + "%"
795
+ }, localProps.style);
796
+ },
797
+ get id() {
798
+ return localProps.panelId;
799
+ },
800
+ get ["data-collapsed"]() {
801
+ return dataIf(collapsed());
802
+ },
803
+ get ["data-expanded"]() {
804
+ return dataIf(localProps.collapsible === true && !collapsed());
805
+ },
806
+ get ["data-orientation"]() {
807
+ return context().orientation();
808
+ },
809
+ "data-corvu-resizable-panel": ""
810
+ }, otherProps, {
811
+ get children() {
812
+ return untrack(() => resolveChildren());
813
+ }
814
+ }));
815
+ }
816
+ });
817
+ });
818
+ return memoizedResizablePanel;
819
+ };
820
+ var Panel_default = ResizablePanel;
821
+ var getDistributablePercentage = (props) => {
822
+ let distributablePercentage = props.desiredPercentage >= 0 ? Infinity : -Infinity;
823
+ let newSizes = props.initialSizes;
824
+ for (const resizeAction of props.resizeActions) {
825
+ const desiredPercentage = resizeAction.negate !== true ? props.desiredPercentage : -props.desiredPercentage;
826
+ let [
827
+ distributedPercentagePreceding,
828
+ // eslint-disable-next-line prefer-const
829
+ distributedSizesPreceding,
830
+ // eslint-disable-next-line prefer-const
831
+ collapsedPreceding
832
+ ] = distributePercentage({
833
+ desiredPercentage,
834
+ side: "preceding",
835
+ panels: resizeAction.precedingPanels,
836
+ initialSizes: newSizes,
837
+ initialSizesStartIndex: 0,
838
+ collapsible: props.collapsible,
839
+ rootSize: props.resizableData.rootSize
840
+ });
841
+ let [
842
+ distributedPercentageFollowing,
843
+ // eslint-disable-next-line prefer-const
844
+ distributedSizesFollowing,
845
+ // eslint-disable-next-line prefer-const
846
+ collapsedFollowing
847
+ ] = distributePercentage({
848
+ desiredPercentage,
849
+ side: "following",
850
+ panels: resizeAction.followingPanels,
851
+ initialSizes: newSizes,
852
+ initialSizesStartIndex: resizeAction.precedingPanels.length,
853
+ collapsible: props.collapsible,
854
+ rootSize: props.resizableData.rootSize
855
+ });
856
+ if (resizeAction.negate === true) {
857
+ distributedPercentagePreceding = -distributedPercentagePreceding;
858
+ distributedPercentageFollowing = -distributedPercentageFollowing;
859
+ }
860
+ if (collapsedPreceding) {
861
+ distributedPercentageFollowing = distributedPercentagePreceding;
862
+ }
863
+ if (collapsedFollowing) {
864
+ distributedPercentagePreceding = distributedPercentageFollowing;
865
+ }
866
+ if (props.desiredPercentage >= 0) {
867
+ distributablePercentage = Math.min(
868
+ distributablePercentage,
869
+ Math.min(
870
+ distributedPercentagePreceding,
871
+ distributedPercentageFollowing
872
+ )
873
+ );
874
+ } else {
875
+ distributablePercentage = Math.max(
876
+ distributablePercentage,
877
+ Math.max(
878
+ distributedPercentagePreceding,
879
+ distributedPercentageFollowing
880
+ )
881
+ );
882
+ }
883
+ newSizes = [...distributedSizesPreceding, ...distributedSizesFollowing];
884
+ }
885
+ return distributablePercentage;
886
+ };
887
+ var distributePercentage = (props) => {
888
+ props.desiredPercentage = fixToPrecision(props.desiredPercentage);
889
+ const resizeDirection = getResizeDirection({
890
+ side: props.side,
891
+ desiredPercentage: props.desiredPercentage
892
+ });
893
+ let distributedPercentage = 0;
894
+ const distributedSizes = props.initialSizes.slice(
895
+ props.initialSizesStartIndex,
896
+ props.initialSizesStartIndex + props.panels.length
897
+ );
898
+ for (let i = props.side === "preceding" ? props.panels.length - 1 : 0; props.side === "preceding" ? i >= 0 : i < props.panels.length; props.side === "preceding" ? i-- : i++) {
899
+ const panel2 = props.panels[i];
900
+ const panelSize2 = props.initialSizes[i + props.initialSizesStartIndex];
901
+ const collapsedSize2 = resolveSize(
902
+ panel2.data.collapsedSize ?? 0,
903
+ props.rootSize
904
+ );
905
+ if (panel2.data.collapsible && panelSize2 === collapsedSize2) continue;
906
+ const availablePercentage2 = fixToPrecision(
907
+ props.desiredPercentage - distributedPercentage
908
+ );
909
+ if (availablePercentage2 === 0) break;
910
+ switch (resizeDirection) {
911
+ case "precedingDecreasing": {
912
+ const minSize2 = resolveSize(panel2.data.minSize, props.rootSize);
913
+ distributedSizes[i] = Math.max(minSize2, panelSize2 + availablePercentage2);
914
+ distributedPercentage += distributedSizes[i] - panelSize2;
915
+ break;
916
+ }
917
+ case "followingDecreasing": {
918
+ const minSize2 = resolveSize(panel2.data.minSize, props.rootSize);
919
+ distributedSizes[i] = Math.max(minSize2, panelSize2 - availablePercentage2);
920
+ distributedPercentage -= distributedSizes[i] - panelSize2;
921
+ break;
922
+ }
923
+ case "precedingIncreasing": {
924
+ const maxSize = resolveSize(panel2.data.maxSize, props.rootSize);
925
+ distributedSizes[i] = Math.min(maxSize, panelSize2 + availablePercentage2);
926
+ distributedPercentage += distributedSizes[i] - panelSize2;
927
+ break;
928
+ }
929
+ case "followingIncreasing": {
930
+ const maxSize = resolveSize(panel2.data.maxSize, props.rootSize);
931
+ distributedSizes[i] = Math.min(maxSize, panelSize2 - availablePercentage2);
932
+ distributedPercentage -= distributedSizes[i] - panelSize2;
933
+ break;
934
+ }
935
+ }
936
+ }
937
+ distributedPercentage = fixToPrecision(distributedPercentage);
938
+ if (!props.collapsible || distributedPercentage === props.desiredPercentage) {
939
+ return [distributedPercentage, distributedSizes, false];
940
+ }
941
+ const panelIndex = props.side === "preceding" ? props.panels.length - 1 : 0;
942
+ const panel = props.panels[panelIndex];
943
+ if (!panel.data.collapsible) {
944
+ return [distributedPercentage, distributedSizes, false];
945
+ }
946
+ const availablePercentage = fixToPrecision(
947
+ props.desiredPercentage - distributedPercentage
948
+ );
949
+ let collapsed = false;
950
+ const panelSize = props.initialSizes[panelIndex + props.initialSizesStartIndex];
951
+ const minSize = resolveSize(panel.data.minSize, props.rootSize);
952
+ const collapsedSize = resolveSize(
953
+ panel.data.collapsedSize ?? 0,
954
+ props.rootSize
955
+ );
956
+ const collapseThreshold = Math.min(
957
+ resolveSize(panel.data.collapseThreshold ?? 0, props.rootSize),
958
+ minSize - collapsedSize
959
+ );
960
+ const isCollapsed = panelSize === collapsedSize;
961
+ if (resizeDirection === "precedingDecreasing" && !isCollapsed && Math.abs(availablePercentage) >= collapseThreshold) {
962
+ distributedPercentage -= distributedSizes[panelIndex] - panelSize;
963
+ distributedSizes[panelIndex] = collapsedSize;
964
+ distributedPercentage += distributedSizes[panelIndex] - panelSize;
965
+ collapsed = true;
966
+ } else if (resizeDirection === "precedingIncreasing" && isCollapsed && Math.abs(availablePercentage) >= collapseThreshold) {
967
+ const minSize2 = resolveSize(panel.data.minSize, props.rootSize);
968
+ distributedSizes[panelIndex] = minSize2;
969
+ if (Math.abs(availablePercentage) >= minSize2 - collapsedSize) {
970
+ const maxSize = resolveSize(panel.data.maxSize, props.rootSize);
971
+ distributedSizes[panelIndex] = Math.min(
972
+ maxSize,
973
+ panelSize + availablePercentage
974
+ );
975
+ } else {
976
+ collapsed = true;
977
+ }
978
+ distributedPercentage += distributedSizes[panelIndex] - panelSize;
979
+ } else if (resizeDirection === "followingDecreasing" && !isCollapsed && Math.abs(availablePercentage) >= collapseThreshold) {
980
+ distributedPercentage += distributedSizes[panelIndex] - panelSize;
981
+ distributedSizes[panelIndex] = collapsedSize;
982
+ distributedPercentage -= distributedSizes[panelIndex] - panelSize;
983
+ collapsed = true;
984
+ } else if (resizeDirection === "followingIncreasing" && isCollapsed && Math.abs(availablePercentage) >= collapseThreshold) {
985
+ const minSize2 = resolveSize(panel.data.minSize, props.rootSize);
986
+ distributedSizes[panelIndex] = minSize2;
987
+ if (Math.abs(availablePercentage) >= minSize2 - collapsedSize) {
988
+ const maxSize = resolveSize(panel.data.maxSize, props.rootSize);
989
+ distributedSizes[panelIndex] = Math.min(
990
+ maxSize,
991
+ panelSize - availablePercentage
992
+ );
993
+ } else {
994
+ collapsed = true;
995
+ }
996
+ distributedPercentage -= distributedSizes[panelIndex] - panelSize;
997
+ }
998
+ return [distributedPercentage, distributedSizes, collapsed];
999
+ };
1000
+ var getResizeDirection = (props) => {
1001
+ switch (props.side) {
1002
+ case "preceding":
1003
+ return props.desiredPercentage >= 0 ? "precedingIncreasing" : "precedingDecreasing";
1004
+ case "following":
1005
+ return props.desiredPercentage >= 0 ? "followingDecreasing" : "followingIncreasing";
1006
+ }
1007
+ };
1008
+ var resize = (props) => {
1009
+ let newSizes = props.initialSizes;
1010
+ for (const resizeAction of props.resizeActions) {
1011
+ const [, distributedSizesPreceding] = distributePercentage({
1012
+ desiredPercentage: resizeAction.deltaPercentage,
1013
+ side: "preceding",
1014
+ panels: resizeAction.precedingPanels,
1015
+ initialSizes: newSizes,
1016
+ initialSizesStartIndex: 0,
1017
+ collapsible: props.collapsible,
1018
+ rootSize: props.resizableData.rootSize
1019
+ });
1020
+ const [, distributedSizesFollowing] = distributePercentage({
1021
+ desiredPercentage: resizeAction.deltaPercentage,
1022
+ side: "following",
1023
+ panels: resizeAction.followingPanels,
1024
+ initialSizes: newSizes,
1025
+ initialSizesStartIndex: resizeAction.precedingPanels.length,
1026
+ collapsible: props.collapsible,
1027
+ rootSize: props.resizableData.rootSize
1028
+ });
1029
+ newSizes = [...distributedSizesPreceding, ...distributedSizesFollowing];
1030
+ }
1031
+ newSizes = newSizes.map(fixToPrecision);
1032
+ const totalSize = newSizes.reduce((totalSize2, size) => totalSize2 + size, 0);
1033
+ if (totalSize !== 1) {
1034
+ const offset = totalSize - 1;
1035
+ const offsetPerPanel = offset / newSizes.length;
1036
+ newSizes = newSizes.map((size) => size - offsetPerPanel);
1037
+ }
1038
+ props.resizableData.setSizes(newSizes.map(fixToPrecision));
1039
+ };
1040
+ var resizePanel = (props) => {
1041
+ let [precedingPanels, followingPanels] = splitPanels({
1042
+ panels: props.panels,
1043
+ focusedElement: props.panel.data.element
1044
+ });
1045
+ const panelIndex = props.panels.indexOf(props.panel);
1046
+ if (panelIndex === 0) {
1047
+ props.strategy = "following";
1048
+ } else if (panelIndex === props.panels.length - 1) {
1049
+ props.strategy = "preceding";
1050
+ }
1051
+ if (props.strategy === "both") {
1052
+ const precedingPanelsIncluding = [...precedingPanels, props.panel];
1053
+ const followingPanelsIncluding = [props.panel, ...followingPanels];
1054
+ const distributablePercentage = getDistributablePercentage({
1055
+ desiredPercentage: props.deltaPercentage / 2,
1056
+ initialSizes: props.initialSizes,
1057
+ collapsible: true,
1058
+ resizeActions: [
1059
+ {
1060
+ precedingPanels: precedingPanelsIncluding,
1061
+ followingPanels
1062
+ },
1063
+ {
1064
+ precedingPanels,
1065
+ followingPanels: followingPanelsIncluding,
1066
+ negate: true
1067
+ }
1068
+ ],
1069
+ resizableData: {
1070
+ rootSize: props.resizableData.rootSize
1071
+ }
1072
+ });
1073
+ resize({
1074
+ initialSizes: props.initialSizes,
1075
+ collapsible: true,
1076
+ resizeActions: [
1077
+ {
1078
+ precedingPanels: precedingPanelsIncluding,
1079
+ followingPanels,
1080
+ deltaPercentage: distributablePercentage
1081
+ },
1082
+ {
1083
+ precedingPanels,
1084
+ followingPanels: followingPanelsIncluding,
1085
+ deltaPercentage: -distributablePercentage
1086
+ }
1087
+ ],
1088
+ resizableData: props.resizableData
1089
+ });
1090
+ } else {
1091
+ precedingPanels = props.strategy === "preceding" ? precedingPanels : [...precedingPanels, props.panel];
1092
+ followingPanels = props.strategy === "following" ? followingPanels : [props.panel, ...followingPanels];
1093
+ if (props.strategy === "preceding") {
1094
+ props.deltaPercentage = -props.deltaPercentage;
1095
+ }
1096
+ const distributablePercentage = getDistributablePercentage({
1097
+ desiredPercentage: props.deltaPercentage,
1098
+ initialSizes: props.initialSizes,
1099
+ collapsible: props.collapsible,
1100
+ resizeActions: [
1101
+ {
1102
+ precedingPanels,
1103
+ followingPanels
1104
+ }
1105
+ ],
1106
+ resizableData: {
1107
+ rootSize: props.resizableData.rootSize
1108
+ }
1109
+ });
1110
+ resize({
1111
+ initialSizes: props.initialSizes,
1112
+ collapsible: true,
1113
+ resizeActions: [
1114
+ {
1115
+ precedingPanels,
1116
+ followingPanels,
1117
+ deltaPercentage: distributablePercentage
1118
+ }
1119
+ ],
1120
+ resizableData: props.resizableData
1121
+ });
1122
+ }
1123
+ };
1124
+ var deltaResize = (props) => {
1125
+ if (props.altKey && props.panels.length > 2) {
1126
+ let panelIndex = props.panels.filter(
1127
+ (panel2) => !!(props.handle.compareDocumentPosition(panel2.data.element) & Node.DOCUMENT_POSITION_PRECEDING)
1128
+ ).length - 1;
1129
+ const isPrecedingHandle = panelIndex === 0;
1130
+ if (isPrecedingHandle) {
1131
+ panelIndex++;
1132
+ props.deltaPercentage = -props.deltaPercentage;
1133
+ }
1134
+ const panel = props.panels[panelIndex];
1135
+ const panelSize = props.initialSizes[panelIndex];
1136
+ const minDelta = resolveSize(panel.data.minSize, props.resizableData.rootSize) - panelSize;
1137
+ const maxDelta = resolveSize(panel.data.maxSize, props.resizableData.rootSize) - panelSize;
1138
+ const cappedDeltaPercentage = Math.max(minDelta, Math.min(props.deltaPercentage * 2, maxDelta)) / 2;
1139
+ const [precedingPanels, followingPanels] = splitPanels({
1140
+ panels: props.panels,
1141
+ focusedElement: panel.data.element
1142
+ });
1143
+ const precedingPanelsIncluding = [...precedingPanels, panel];
1144
+ const followingPanelsIncluding = [panel, ...followingPanels];
1145
+ const distributablePercentage = getDistributablePercentage({
1146
+ desiredPercentage: cappedDeltaPercentage,
1147
+ initialSizes: props.initialSizes,
1148
+ collapsible: false,
1149
+ resizeActions: [
1150
+ {
1151
+ precedingPanels: precedingPanelsIncluding,
1152
+ followingPanels
1153
+ },
1154
+ {
1155
+ precedingPanels,
1156
+ followingPanels: followingPanelsIncluding,
1157
+ negate: true
1158
+ }
1159
+ ],
1160
+ resizableData: {
1161
+ rootSize: props.resizableData.rootSize
1162
+ }
1163
+ });
1164
+ if (props.resizableData.handleCursorStyle === true) {
1165
+ handleResizeConstraints({
1166
+ orientation: props.resizableData.orientation,
1167
+ desiredPercentage: props.deltaPercentage,
1168
+ distributablePercentage,
1169
+ revertConstraints: isPrecedingHandle
1170
+ });
1171
+ }
1172
+ resize({
1173
+ initialSizes: props.initialSizes,
1174
+ collapsible: false,
1175
+ resizeActions: [
1176
+ {
1177
+ precedingPanels: precedingPanelsIncluding,
1178
+ followingPanels,
1179
+ deltaPercentage: distributablePercentage
1180
+ },
1181
+ {
1182
+ precedingPanels,
1183
+ followingPanels: followingPanelsIncluding,
1184
+ deltaPercentage: -distributablePercentage
1185
+ }
1186
+ ],
1187
+ resizableData: props.resizableData
1188
+ });
1189
+ } else {
1190
+ const [precedingPanels, followingPanels] = splitPanels({
1191
+ panels: props.panels,
1192
+ focusedElement: props.handle
1193
+ });
1194
+ const distributablePercentage = getDistributablePercentage({
1195
+ desiredPercentage: props.deltaPercentage,
1196
+ initialSizes: props.initialSizes,
1197
+ collapsible: true,
1198
+ resizeActions: [
1199
+ {
1200
+ precedingPanels,
1201
+ followingPanels
1202
+ }
1203
+ ],
1204
+ resizableData: {
1205
+ rootSize: props.resizableData.rootSize
1206
+ }
1207
+ });
1208
+ resize({
1209
+ initialSizes: props.initialSizes,
1210
+ collapsible: true,
1211
+ resizeActions: [
1212
+ {
1213
+ precedingPanels,
1214
+ followingPanels,
1215
+ deltaPercentage: distributablePercentage
1216
+ }
1217
+ ],
1218
+ resizableData: props.resizableData
1219
+ });
1220
+ if (props.resizableData.handleCursorStyle) {
1221
+ const fixedDesiredPercentage = fixToPrecision(props.deltaPercentage);
1222
+ const fixedDistributablePercentage = fixToPrecision(
1223
+ distributablePercentage
1224
+ );
1225
+ let betweenCollapse = false;
1226
+ const precedingPanel = precedingPanels[precedingPanels.length - 1];
1227
+ if (precedingPanel.data.collapsible) {
1228
+ const precedingCollapsedSize = resolveSize(
1229
+ precedingPanel.data.collapsedSize ?? 0,
1230
+ props.resizableData.rootSize
1231
+ );
1232
+ if (precedingPanel.size() === precedingCollapsedSize && fixedDesiredPercentage > fixedDistributablePercentage || precedingPanel.size() !== precedingCollapsedSize && fixedDesiredPercentage < fixedDistributablePercentage) {
1233
+ betweenCollapse = true;
1234
+ }
1235
+ }
1236
+ const followingPanel = followingPanels[0];
1237
+ if (followingPanel.data.collapsible) {
1238
+ const followingCollapsedSize = resolveSize(
1239
+ followingPanel.data.collapsedSize ?? 0,
1240
+ props.resizableData.rootSize
1241
+ );
1242
+ if (followingPanel.size() === followingCollapsedSize && fixedDesiredPercentage < fixedDistributablePercentage || followingPanel.size() !== followingCollapsedSize && fixedDesiredPercentage > fixedDistributablePercentage) {
1243
+ betweenCollapse = true;
1244
+ }
1245
+ }
1246
+ handleResizeConstraints({
1247
+ orientation: props.resizableData.orientation,
1248
+ desiredPercentage: props.deltaPercentage,
1249
+ distributablePercentage,
1250
+ betweenCollapse
1251
+ });
1252
+ }
1253
+ }
1254
+ };
1255
+ var ResizableRoot = (props) => {
1256
+ const defaultedProps = merge({
1257
+ orientation: "horizontal",
1258
+ initialSizes: [],
1259
+ keyboardDelta: 0.1,
1260
+ handleCursorStyle: true
1261
+ }, props);
1262
+ const localProps = defaultedProps;
1263
+ const otherProps = omit(defaultedProps, "orientation", "sizes", "onSizesChange", "initialSizes", "keyboardDelta", "handleCursorStyle", "contextId", "ref", "style", "children");
1264
+ const [sizes, setSizes] = createControllableSignal({
1265
+ value: () => localProps.sizes,
1266
+ initialValue: [],
1267
+ onChange: localProps.onSizesChange
1268
+ });
1269
+ const [ref, setRef] = createSignal(null);
1270
+ const rootSize = createSize({
1271
+ element: ref,
1272
+ dimension: () => localProps.orientation === "horizontal" ? "width" : "height"
1273
+ });
1274
+ const [panels, setPanels] = createSignal([]);
1275
+ const sizesToIds = [];
1276
+ const registerPanel = (panelData) => {
1277
+ const _panels = panels();
1278
+ const panelIndex = _panels.filter((panel2) => !!(panelData.element.compareDocumentPosition(panel2.data.element) & Node.DOCUMENT_POSITION_PRECEDING)).length;
1279
+ const idExists = sizesToIds[panelIndex] === void 0 || sizesToIds[panelIndex] === panelData.id;
1280
+ const sizeExists = sizes()[panelIndex] !== void 0;
1281
+ let panelSize = null;
1282
+ if (panelData.initialSize !== null) {
1283
+ panelSize = resolveSize(panelData.initialSize, rootSize());
1284
+ } else if (localProps.initialSizes[panelIndex] !== void 0 && idExists) {
1285
+ panelSize = resolveSize(localProps.initialSizes[panelIndex], rootSize());
1286
+ }
1287
+ panelSize = panelSize ?? 0.5;
1288
+ setSizes((sizes2) => {
1289
+ let newSizes = [...sizes2];
1290
+ const previousTotalSize = newSizes.reduce((totalSize, size) => totalSize + size, 0);
1291
+ if ((idExists && !sizeExists || !idExists) && previousTotalSize === 1) {
1292
+ const offsetPerPanel = panelSize / newSizes.length;
1293
+ newSizes = newSizes.map((size) => size - offsetPerPanel);
1294
+ }
1295
+ if (idExists) {
1296
+ if (!sizeExists) {
1297
+ newSizes[panelIndex] = panelSize;
1298
+ }
1299
+ sizesToIds[panelIndex] = panelData.id;
1300
+ } else {
1301
+ newSizes.splice(panelIndex, 0, panelSize);
1302
+ sizesToIds.splice(panelIndex, 0, panelData.id);
1303
+ }
1304
+ return newSizes;
1305
+ });
1306
+ const panelSizeMemo = createMemo(() => {
1307
+ const index = sizesToIds.indexOf(panelData.id);
1308
+ return sizes()[index];
1309
+ });
1310
+ createEffect(() => panelData.onResize?.(panelSizeMemo()));
1311
+ const panel = {
1312
+ data: panelData,
1313
+ size: panelSizeMemo,
1314
+ resize: (size, strategy) => resize2(sizesToIds.indexOf(panelData.id), size, strategy),
1315
+ collapse: (strategy) => collapse(sizesToIds.indexOf(panelData.id), strategy),
1316
+ expand: (strategy) => expand(sizesToIds.indexOf(panelData.id), strategy)
1317
+ };
1318
+ setPanels((panels2) => {
1319
+ const newPanels = [...panels2];
1320
+ newPanels.push(panel);
1321
+ newPanels.sort((a, b) => sortByDocumentPosition(a.data.element, b.data.element));
1322
+ return newPanels;
1323
+ });
1324
+ return panel;
1325
+ };
1326
+ const unregisterPanel = (id) => {
1327
+ setPanels((panels2) => panels2.filter((panel) => panel.data.id !== id));
1328
+ const panelSizeIndex = sizesToIds.indexOf(id);
1329
+ sizesToIds.splice(panelSizeIndex, 1);
1330
+ setSizes((sizes2) => {
1331
+ let newSizes = [...sizes2];
1332
+ newSizes.splice(panelSizeIndex, 1);
1333
+ const totalSize = newSizes.reduce((totalSize2, size) => totalSize2 + size, 0);
1334
+ const offset = totalSize - 1;
1335
+ const offsetPerPanel = offset / newSizes.length;
1336
+ newSizes = newSizes.map((size) => size + offsetPerPanel);
1337
+ return newSizes;
1338
+ });
1339
+ };
1340
+ createEffect(() => {
1341
+ if (localProps.onSizesChange !== void 0) {
1342
+ localProps.onSizesChange(sizes());
1343
+ }
1344
+ });
1345
+ const resize2 = (panelIndex, size, strategy) => {
1346
+ untrack(() => {
1347
+ const panel = panels()[panelIndex];
1348
+ if (!panel) return;
1349
+ const minSize = resolveSize(panel.data.minSize, rootSize());
1350
+ const maxSize = resolveSize(panel.data.maxSize, rootSize());
1351
+ const newSize = resolveSize(size, rootSize());
1352
+ const allowedSize = Math.max(minSize, Math.min(newSize, maxSize));
1353
+ const deltaPercentage = allowedSize - sizes()[panelIndex];
1354
+ resizePanel({
1355
+ deltaPercentage,
1356
+ strategy: strategy ?? "both",
1357
+ panel,
1358
+ panels: panels(),
1359
+ initialSizes: panels().map((panel2) => panel2.size()),
1360
+ collapsible: false,
1361
+ resizableData: {
1362
+ rootSize: rootSize(),
1363
+ orientation: localProps.orientation,
1364
+ setSizes
1365
+ }
1366
+ });
1367
+ });
1368
+ };
1369
+ const collapse = (panelIndex, strategy) => {
1370
+ untrack(() => {
1371
+ const panel = panels()[panelIndex];
1372
+ if (!panel) return;
1373
+ const panelSize = sizes()[panelIndex];
1374
+ const collapsedSize = resolveSize(panel.data.collapsedSize ?? 0, rootSize());
1375
+ if (!panel.data.collapsible || panelSize === collapsedSize) return;
1376
+ const deltaPercentage = collapsedSize - panelSize;
1377
+ resizePanel({
1378
+ deltaPercentage,
1379
+ strategy: strategy ?? "both",
1380
+ panel,
1381
+ panels: panels(),
1382
+ initialSizes: panels().map((panel2) => panel2.size()),
1383
+ collapsible: true,
1384
+ resizableData: {
1385
+ rootSize: rootSize(),
1386
+ orientation: localProps.orientation,
1387
+ setSizes
1388
+ }
1389
+ });
1390
+ });
1391
+ };
1392
+ const expand = (panelIndex, strategy) => {
1393
+ untrack(() => {
1394
+ const panel = panels()[panelIndex];
1395
+ if (!panel) return;
1396
+ const panelSize = sizes()[panelIndex];
1397
+ const collapsedSize = resolveSize(panel.data.collapsedSize ?? 0, rootSize());
1398
+ if (!panel.data.collapsible || panelSize !== collapsedSize) return;
1399
+ const minSize = resolveSize(panel.data.minSize, rootSize());
1400
+ const deltaPercentage = minSize - panelSize;
1401
+ resizePanel({
1402
+ deltaPercentage,
1403
+ strategy: strategy ?? "both",
1404
+ panel,
1405
+ panels: panels(),
1406
+ initialSizes: panels().map((panel2) => panel2.size()),
1407
+ collapsible: true,
1408
+ resizableData: {
1409
+ rootSize: rootSize(),
1410
+ orientation: localProps.orientation,
1411
+ setSizes
1412
+ }
1413
+ });
1414
+ });
1415
+ };
1416
+ let initialSizes = null;
1417
+ let altKeyCache2 = false;
1418
+ const onDrag = (handle, delta, altKey) => {
1419
+ if (initialSizes === null || altKeyCache2 !== altKey) {
1420
+ initialSizes = panels().map((panel) => panel.size());
1421
+ altKeyCache2 = altKey;
1422
+ }
1423
+ deltaResize({
1424
+ deltaPercentage: delta / rootSize(),
1425
+ altKey,
1426
+ handle,
1427
+ panels: panels(),
1428
+ initialSizes,
1429
+ resizableData: {
1430
+ rootSize: rootSize(),
1431
+ handleCursorStyle: localProps.handleCursorStyle,
1432
+ orientation: localProps.orientation,
1433
+ setSizes
1434
+ }
1435
+ });
1436
+ };
1437
+ const onKeyDown = (handle, event, altKey) => {
1438
+ if (event.key === "Enter") {
1439
+ const [precedingPanels, followingPanels] = splitPanels({
1440
+ panels: panels(),
1441
+ focusedElement: handle
1442
+ });
1443
+ let collapsiblePanel = precedingPanels[precedingPanels.length - 1];
1444
+ if (!collapsiblePanel || !collapsiblePanel.data.collapsible) {
1445
+ collapsiblePanel = followingPanels[0];
1446
+ if (!collapsiblePanel || !collapsiblePanel.data.collapsible) return;
1447
+ }
1448
+ const size = collapsiblePanel.size();
1449
+ const collapsedSize = resolveSize(collapsiblePanel.data.collapsedSize ?? 0, rootSize());
1450
+ if (size === collapsedSize) {
1451
+ collapsiblePanel.expand("following");
1452
+ } else {
1453
+ collapsiblePanel.collapse("following");
1454
+ }
1455
+ return;
1456
+ }
1457
+ let deltaPercentage = null;
1458
+ if (localProps.orientation === "horizontal" && event.key === "ArrowLeft" || localProps.orientation === "vertical" && event.key === "ArrowUp" || event.key === "Home") {
1459
+ if (event.shiftKey || event.key === "Home") {
1460
+ deltaPercentage = -1;
1461
+ } else {
1462
+ deltaPercentage = -resolveSize(localProps.keyboardDelta, rootSize());
1463
+ }
1464
+ } else if (localProps.orientation === "horizontal" && event.key === "ArrowRight" || localProps.orientation === "vertical" && event.key === "ArrowDown" || event.key === "End") {
1465
+ if (event.shiftKey || event.key === "End") {
1466
+ deltaPercentage = 1;
1467
+ } else {
1468
+ deltaPercentage = resolveSize(localProps.keyboardDelta, rootSize());
1469
+ }
1470
+ }
1471
+ if (deltaPercentage === null) return;
1472
+ event.preventDefault();
1473
+ const initialSizes2 = panels().map((panel) => panel.size());
1474
+ deltaResize({
1475
+ deltaPercentage,
1476
+ altKey,
1477
+ handle,
1478
+ panels: panels(),
1479
+ initialSizes: initialSizes2,
1480
+ resizableData: {
1481
+ rootSize: rootSize(),
1482
+ handleCursorStyle: false,
1483
+ orientation: localProps.orientation,
1484
+ setSizes
1485
+ }
1486
+ });
1487
+ };
1488
+ const childrenProps = {
1489
+ get sizes() {
1490
+ return sizes();
1491
+ },
1492
+ setSizes,
1493
+ get orientation() {
1494
+ return localProps.orientation;
1495
+ },
1496
+ get keyboardDelta() {
1497
+ return localProps.keyboardDelta;
1498
+ },
1499
+ get handleCursorStyle() {
1500
+ return localProps.handleCursorStyle;
1501
+ },
1502
+ resize: resize2,
1503
+ collapse,
1504
+ expand
1505
+ };
1506
+ const memoizedChildren = createOnce(() => localProps.children);
1507
+ const resolveChildren = () => {
1508
+ const children = memoizedChildren()();
1509
+ if (isFunction(children)) {
1510
+ return children(childrenProps);
1511
+ }
1512
+ return children;
1513
+ };
1514
+ const memoizedResizableRoot = createMemo(() => {
1515
+ const ResizableContext2 = createResizableContext(localProps.contextId);
1516
+ const InternalResizableContext2 = createInternalResizableContext(localProps.contextId);
1517
+ return createComponent(ResizableContext2, {
1518
+ value: {
1519
+ sizes,
1520
+ setSizes,
1521
+ orientation: () => localProps.orientation,
1522
+ keyboardDelta: () => localProps.keyboardDelta,
1523
+ handleCursorStyle: () => localProps.handleCursorStyle,
1524
+ resize: resize2,
1525
+ collapse,
1526
+ expand
1527
+ },
1528
+ get children() {
1529
+ return createComponent(InternalResizableContext2, {
1530
+ value: {
1531
+ sizes,
1532
+ setSizes,
1533
+ orientation: () => localProps.orientation,
1534
+ keyboardDelta: () => localProps.keyboardDelta,
1535
+ handleCursorStyle: () => localProps.handleCursorStyle,
1536
+ rootSize,
1537
+ panels,
1538
+ registerPanel,
1539
+ unregisterPanel,
1540
+ onDrag,
1541
+ onDragEnd: () => initialSizes = null,
1542
+ onKeyDown,
1543
+ resize: resize2,
1544
+ collapse,
1545
+ expand
1546
+ },
1547
+ get children() {
1548
+ return createComponent(Dynamic, mergeProps({
1549
+ as: "div",
1550
+ ref(r$) {
1551
+ var _ref$ = mergeRefs(setRef, localProps.ref);
1552
+ typeof _ref$ === "function" && _ref$(r$);
1553
+ },
1554
+ get style() {
1555
+ return combineStyle({
1556
+ display: "flex",
1557
+ "flex-direction": localProps.orientation === "horizontal" ? "row" : "column"
1558
+ }, localProps.style);
1559
+ },
1560
+ get ["data-orientation"]() {
1561
+ return localProps.orientation;
1562
+ },
1563
+ "data-corvu-resizable-root": ""
1564
+ }, otherProps, {
1565
+ get children() {
1566
+ return untrack(() => resolveChildren());
1567
+ }
1568
+ }));
1569
+ }
1570
+ });
1571
+ }
1572
+ });
1573
+ });
1574
+ return memoizedResizableRoot;
1575
+ };
1576
+ var Root_default = ResizableRoot;
1577
+
1578
+ // src/index.ts
1579
+ var Resizable = Object.assign(Root_default, {
1580
+ Panel: Panel_default,
1581
+ Handle: Handle_default,
1582
+ useContext: useResizableContext,
1583
+ usePanelContext: useResizablePanelContext
1584
+ });
1585
+ var index_default = Resizable;
1586
+
1587
+ export { Handle_default as Handle, Panel_default as Panel, Root_default as Root, index_default as default, useResizableContext as useContext, useResizablePanelContext as usePanelContext };