@witchcraft/layout 0.4.2 → 0.4.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/dist/module.json +1 -1
- package/dist/runtime/components/LayoutDragEdgeGrabbed.vue +1 -1
- package/dist/runtime/components/LayoutDragEdgeHandle.vue +1 -2
- package/dist/runtime/components/LayoutWindow.d.vue.ts +12 -0
- package/dist/runtime/components/LayoutWindow.vue +5 -4
- package/dist/runtime/components/LayoutWindow.vue.d.ts +12 -0
- package/dist/runtime/composables/useFrames.d.ts +38 -22
- package/dist/runtime/composables/useFrames.js +44 -8
- package/dist/runtime/demo/tailwind.css +1 -1
- package/dist/runtime/drag/CloseAction.d.ts +3 -0
- package/dist/runtime/drag/CloseAction.js +5 -0
- package/dist/runtime/drag/DragActionHandler.d.ts +4 -1
- package/dist/runtime/drag/DragActionHandler.js +2 -2
- package/dist/runtime/drag/FrameDragAction.d.ts +3 -0
- package/dist/runtime/drag/FrameDragAction.js +5 -0
- package/dist/runtime/drag/SplitAction.d.ts +3 -0
- package/dist/runtime/drag/SplitAction.js +8 -3
- package/dist/runtime/helpers/findEdgesTouchingWindow.d.ts +7 -0
- package/dist/runtime/helpers/findEdgesTouchingWindow.js +20 -0
- package/dist/runtime/helpers/index.d.ts +8 -1
- package/dist/runtime/helpers/index.js +8 -1
- package/dist/runtime/layout/debugFrame.js +5 -1
- package/dist/runtime/layout/getFrameCollapseInfo.d.ts +1 -1
- package/dist/runtime/layout/getFrameCollapseInfo.js +9 -29
- package/dist/runtime/layout/getFrameDockInfo.d.ts +1 -1
- package/dist/runtime/layout/getFrameDockInfo.js +61 -44
- package/dist/runtime/layout/getFrameExpandInfo.d.ts +11 -0
- package/dist/runtime/layout/getFrameExpandInfo.js +49 -0
- package/dist/runtime/layout/getFrameShrinkInfo.d.ts +14 -0
- package/dist/runtime/layout/getFrameShrinkInfo.js +48 -0
- package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +1 -1
- package/dist/runtime/layout/getFrameUncollapseInfo.js +6 -20
- package/dist/runtime/layout/getUpdateWindowSizeInfo.js +10 -12
- package/dist/runtime/layout/index.d.ts +3 -0
- package/dist/runtime/layout/index.js +3 -0
- package/dist/runtime/settings.js +1 -1
- package/dist/runtime/types/index.d.ts +72 -0
- package/dist/runtime/types/index.js +2 -1
- package/dist/runtime/types/vue.d.ts +12 -3
- package/package.json +3 -2
- package/src/runtime/components/LayoutDragEdgeGrabbed.vue +1 -1
- package/src/runtime/components/LayoutDragEdgeHandle.vue +1 -2
- package/src/runtime/components/LayoutWindow.vue +8 -6
- package/src/runtime/composables/useFrames.ts +61 -32
- package/src/runtime/demo/tailwind.css +4 -0
- package/src/runtime/drag/CloseAction.ts +7 -0
- package/src/runtime/drag/DragActionHandler.ts +3 -3
- package/src/runtime/drag/FrameDragAction.ts +9 -0
- package/src/runtime/drag/SplitAction.ts +11 -3
- package/src/runtime/helpers/findEdgesTouchingWindow.ts +30 -0
- package/src/runtime/helpers/index.ts +8 -1
- package/src/runtime/layout/debugFrame.ts +6 -1
- package/src/runtime/layout/getFrameCollapseInfo.ts +12 -41
- package/src/runtime/layout/getFrameDockInfo.ts +77 -57
- package/src/runtime/layout/getFrameExpandInfo.ts +84 -0
- package/src/runtime/layout/getFrameShrinkInfo.ts +87 -0
- package/src/runtime/layout/getFrameUncollapseInfo.ts +8 -30
- package/src/runtime/layout/getUpdateWindowSizeInfo.ts +16 -22
- package/src/runtime/layout/index.ts +3 -0
- package/src/runtime/settings.ts +1 -1
- package/src/runtime/types/index.ts +41 -1
- package/src/runtime/types/vue.ts +5 -3
- package/dist/runtime/drag/defaultDragActions.d.ts +0 -9
- package/dist/runtime/drag/defaultDragActions.js +0 -10
- package/src/runtime/drag/defaultDragActions.ts +0 -20
|
@@ -12,13 +12,16 @@ export { getFillEmptySpaceInfo } from "./getFillEmptySpaceInfo.js";
|
|
|
12
12
|
export { getFrameCollapseInfo } from "./getFrameCollapseInfo.js";
|
|
13
13
|
export { getFrameDockInfo } from "./getFrameDockInfo.js";
|
|
14
14
|
export { getFrameDragZones } from "./getFrameDragZones.js";
|
|
15
|
+
export { getFrameExpandInfo } from "./getFrameExpandInfo.js";
|
|
15
16
|
export { getFrameRearrangeInfo } from "./getFrameRearrangeInfo.js";
|
|
17
|
+
export { getFrameShrinkInfo } from "./getFrameShrinkInfo.js";
|
|
16
18
|
export { getFrameSplitInfo } from "./getFrameSplitInfo.js";
|
|
17
19
|
export { getFramesRedistributeInfo } from "./getFramesRedistributeInfo.js";
|
|
18
20
|
export { getFrameSwapInfo } from "./getFrameSwapInfo.js";
|
|
19
21
|
export { getFrameTo } from "./getFrameTo.js";
|
|
20
22
|
export { getFrameUncollapseInfo } from "./getFrameUncollapseInfo.js";
|
|
21
23
|
export { getFrameUndockInfo } from "./getFrameUndockInfo.js";
|
|
24
|
+
export { getRelaxFramesInfo } from "./getRelaxFramesInfo.js";
|
|
22
25
|
export { getUpdateWindowSizeInfo } from "./getUpdateWindowSizeInfo.js";
|
|
23
26
|
export { getWindowDragZones } from "./getWindowDragZones.js";
|
|
24
27
|
export { isPointInRect } from "./isPointInRect.js";
|
package/dist/runtime/settings.js
CHANGED
|
@@ -105,6 +105,8 @@ export declare const zEdge: z.ZodObject<{
|
|
|
105
105
|
frame: LayoutFrame;
|
|
106
106
|
} | {
|
|
107
107
|
frame: LayoutFrame;
|
|
108
|
+
} | {
|
|
109
|
+
frame: LayoutFrame;
|
|
108
110
|
}>, KnownError<LayoutError, {} | {
|
|
109
111
|
id: string | undefined;
|
|
110
112
|
} | {
|
|
@@ -162,6 +164,8 @@ export declare const zEdge: z.ZodObject<{
|
|
|
162
164
|
frame: LayoutFrame;
|
|
163
165
|
} | {
|
|
164
166
|
frame: LayoutFrame;
|
|
167
|
+
} | {
|
|
168
|
+
frame: LayoutFrame;
|
|
165
169
|
}>>, z.ZodObject<{
|
|
166
170
|
code: z.ZodString;
|
|
167
171
|
message: z.ZodString;
|
|
@@ -504,6 +508,8 @@ declare const zLayoutShape: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
504
508
|
frame: LayoutFrame;
|
|
505
509
|
} | {
|
|
506
510
|
frame: LayoutFrame;
|
|
511
|
+
} | {
|
|
512
|
+
frame: LayoutFrame;
|
|
507
513
|
}>, KnownError<LayoutError, {} | {
|
|
508
514
|
id: string | undefined;
|
|
509
515
|
} | {
|
|
@@ -561,6 +567,8 @@ declare const zLayoutShape: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
561
567
|
frame: LayoutFrame;
|
|
562
568
|
} | {
|
|
563
569
|
frame: LayoutFrame;
|
|
570
|
+
} | {
|
|
571
|
+
frame: LayoutFrame;
|
|
564
572
|
}>>, z.ZodObject<{
|
|
565
573
|
code: z.ZodString;
|
|
566
574
|
message: z.ZodString;
|
|
@@ -643,6 +651,8 @@ declare const zBaseDeco: z.ZodObject<{
|
|
|
643
651
|
frame: LayoutFrame;
|
|
644
652
|
} | {
|
|
645
653
|
frame: LayoutFrame;
|
|
654
|
+
} | {
|
|
655
|
+
frame: LayoutFrame;
|
|
646
656
|
}>, KnownError<LayoutError, {} | {
|
|
647
657
|
id: string | undefined;
|
|
648
658
|
} | {
|
|
@@ -700,6 +710,8 @@ declare const zBaseDeco: z.ZodObject<{
|
|
|
700
710
|
frame: LayoutFrame;
|
|
701
711
|
} | {
|
|
702
712
|
frame: LayoutFrame;
|
|
713
|
+
} | {
|
|
714
|
+
frame: LayoutFrame;
|
|
703
715
|
}>>, z.ZodObject<{
|
|
704
716
|
code: z.ZodString;
|
|
705
717
|
message: z.ZodString;
|
|
@@ -783,6 +795,8 @@ export declare const zSplitDeco: z.ZodObject<{
|
|
|
783
795
|
frame: LayoutFrame;
|
|
784
796
|
} | {
|
|
785
797
|
frame: LayoutFrame;
|
|
798
|
+
} | {
|
|
799
|
+
frame: LayoutFrame;
|
|
786
800
|
}>, KnownError<LayoutError, {} | {
|
|
787
801
|
id: string | undefined;
|
|
788
802
|
} | {
|
|
@@ -840,6 +854,8 @@ export declare const zSplitDeco: z.ZodObject<{
|
|
|
840
854
|
frame: LayoutFrame;
|
|
841
855
|
} | {
|
|
842
856
|
frame: LayoutFrame;
|
|
857
|
+
} | {
|
|
858
|
+
frame: LayoutFrame;
|
|
843
859
|
}>>, z.ZodObject<{
|
|
844
860
|
code: z.ZodString;
|
|
845
861
|
message: z.ZodString;
|
|
@@ -944,6 +960,8 @@ declare const zCloseDeco: z.ZodObject<{
|
|
|
944
960
|
frame: LayoutFrame;
|
|
945
961
|
} | {
|
|
946
962
|
frame: LayoutFrame;
|
|
963
|
+
} | {
|
|
964
|
+
frame: LayoutFrame;
|
|
947
965
|
}>, KnownError<LayoutError, {} | {
|
|
948
966
|
id: string | undefined;
|
|
949
967
|
} | {
|
|
@@ -1001,6 +1019,8 @@ declare const zCloseDeco: z.ZodObject<{
|
|
|
1001
1019
|
frame: LayoutFrame;
|
|
1002
1020
|
} | {
|
|
1003
1021
|
frame: LayoutFrame;
|
|
1022
|
+
} | {
|
|
1023
|
+
frame: LayoutFrame;
|
|
1004
1024
|
}>>, z.ZodObject<{
|
|
1005
1025
|
code: z.ZodString;
|
|
1006
1026
|
message: z.ZodString;
|
|
@@ -1087,6 +1107,8 @@ declare const zFrameDragDeco: z.ZodObject<{
|
|
|
1087
1107
|
frame: LayoutFrame;
|
|
1088
1108
|
} | {
|
|
1089
1109
|
frame: LayoutFrame;
|
|
1110
|
+
} | {
|
|
1111
|
+
frame: LayoutFrame;
|
|
1090
1112
|
}>, KnownError<LayoutError, {} | {
|
|
1091
1113
|
id: string | undefined;
|
|
1092
1114
|
} | {
|
|
@@ -1144,6 +1166,8 @@ declare const zFrameDragDeco: z.ZodObject<{
|
|
|
1144
1166
|
frame: LayoutFrame;
|
|
1145
1167
|
} | {
|
|
1146
1168
|
frame: LayoutFrame;
|
|
1169
|
+
} | {
|
|
1170
|
+
frame: LayoutFrame;
|
|
1147
1171
|
}>>, z.ZodObject<{
|
|
1148
1172
|
code: z.ZodString;
|
|
1149
1173
|
message: z.ZodString;
|
|
@@ -1237,6 +1261,8 @@ export declare const zDeco: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1237
1261
|
frame: LayoutFrame;
|
|
1238
1262
|
} | {
|
|
1239
1263
|
frame: LayoutFrame;
|
|
1264
|
+
} | {
|
|
1265
|
+
frame: LayoutFrame;
|
|
1240
1266
|
}>, KnownError<LayoutError, {} | {
|
|
1241
1267
|
id: string | undefined;
|
|
1242
1268
|
} | {
|
|
@@ -1294,6 +1320,8 @@ export declare const zDeco: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1294
1320
|
frame: LayoutFrame;
|
|
1295
1321
|
} | {
|
|
1296
1322
|
frame: LayoutFrame;
|
|
1323
|
+
} | {
|
|
1324
|
+
frame: LayoutFrame;
|
|
1297
1325
|
}>>, z.ZodObject<{
|
|
1298
1326
|
code: z.ZodString;
|
|
1299
1327
|
message: z.ZodString;
|
|
@@ -1384,6 +1412,8 @@ export declare const zDeco: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1384
1412
|
frame: LayoutFrame;
|
|
1385
1413
|
} | {
|
|
1386
1414
|
frame: LayoutFrame;
|
|
1415
|
+
} | {
|
|
1416
|
+
frame: LayoutFrame;
|
|
1387
1417
|
}>, KnownError<LayoutError, {} | {
|
|
1388
1418
|
id: string | undefined;
|
|
1389
1419
|
} | {
|
|
@@ -1441,6 +1471,8 @@ export declare const zDeco: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1441
1471
|
frame: LayoutFrame;
|
|
1442
1472
|
} | {
|
|
1443
1473
|
frame: LayoutFrame;
|
|
1474
|
+
} | {
|
|
1475
|
+
frame: LayoutFrame;
|
|
1444
1476
|
}>>, z.ZodObject<{
|
|
1445
1477
|
code: z.ZodString;
|
|
1446
1478
|
message: z.ZodString;
|
|
@@ -1525,6 +1557,8 @@ export declare const zDeco: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1525
1557
|
frame: LayoutFrame;
|
|
1526
1558
|
} | {
|
|
1527
1559
|
frame: LayoutFrame;
|
|
1560
|
+
} | {
|
|
1561
|
+
frame: LayoutFrame;
|
|
1528
1562
|
}>, KnownError<LayoutError, {} | {
|
|
1529
1563
|
id: string | undefined;
|
|
1530
1564
|
} | {
|
|
@@ -1582,6 +1616,8 @@ export declare const zDeco: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
1582
1616
|
frame: LayoutFrame;
|
|
1583
1617
|
} | {
|
|
1584
1618
|
frame: LayoutFrame;
|
|
1619
|
+
} | {
|
|
1620
|
+
frame: LayoutFrame;
|
|
1585
1621
|
}>>, z.ZodObject<{
|
|
1586
1622
|
code: z.ZodString;
|
|
1587
1623
|
message: z.ZodString;
|
|
@@ -1627,6 +1663,7 @@ export declare const LAYOUT_ERROR: {
|
|
|
1627
1663
|
CANT_UNCOLLAPSE_NOT_COLLAPSED: "CANT_UNCOLLAPSE_NOT_COLLAPSED";
|
|
1628
1664
|
NO_FILL_CANDIDATES: "NO_FILL_CANDIDATES";
|
|
1629
1665
|
CANT_RESIZE_COLLAPSED_FRAME: "CANT_RESIZE_COLLAPSED_FRAME";
|
|
1666
|
+
CANT_RESIZE_SINGLE_FRAME: "CANT_RESIZE_SINGLE_FRAME";
|
|
1630
1667
|
};
|
|
1631
1668
|
export type LayoutError = EnumLike<typeof LAYOUT_ERROR>;
|
|
1632
1669
|
export type LayoutErrorInfo<T extends LayoutError> = LayoutErrorsInfo[T] extends undefined ? never : LayoutErrorsInfo[T];
|
|
@@ -1710,6 +1747,9 @@ export type LayoutErrorsInfo = {
|
|
|
1710
1747
|
[LAYOUT_ERROR.CANT_RESIZE_COLLAPSED_FRAME]: {
|
|
1711
1748
|
frame: LayoutFrame;
|
|
1712
1749
|
};
|
|
1750
|
+
[LAYOUT_ERROR.CANT_RESIZE_SINGLE_FRAME]: {
|
|
1751
|
+
frame: LayoutFrame;
|
|
1752
|
+
};
|
|
1713
1753
|
[LAYOUT_ERROR.REDISTRIBUTE_WOULD_RESULT_IN_INVALID_FRAMES]: {
|
|
1714
1754
|
problemEdgeCoordinates: number[];
|
|
1715
1755
|
};
|
|
@@ -1808,6 +1848,8 @@ export type DragState = {
|
|
|
1808
1848
|
dragDirections: Record<Orientation, Direction | undefined>;
|
|
1809
1849
|
/** The curren point (in scaled window coordinates) the user is dragging at. */
|
|
1810
1850
|
dragPoint?: Point;
|
|
1851
|
+
/** Cumulative pixel distance the user has dragged from the initial click point. 0 on start, increases on each move. */
|
|
1852
|
+
dragDistance: number;
|
|
1811
1853
|
/** Whether the user is currently dragging and what type of drag. Is truthy string during all drag events. */
|
|
1812
1854
|
isDragging: boolean | "frame" | "edge";
|
|
1813
1855
|
/** Whether to show the moved frames while dragging. */
|
|
@@ -1850,6 +1892,8 @@ export type DragState = {
|
|
|
1850
1892
|
* Whether the drag was initiated from a point along the window edge.
|
|
1851
1893
|
*/
|
|
1852
1894
|
isDraggingFromWindowEdge: boolean;
|
|
1895
|
+
/** Custom context passed to dragStart, available to action handlers via state.eventContext. */
|
|
1896
|
+
eventContext?: Record<string, unknown>;
|
|
1853
1897
|
win: LayoutWindow;
|
|
1854
1898
|
};
|
|
1855
1899
|
export interface ActionDragChangeResult {
|
|
@@ -1954,6 +1998,34 @@ export type EdgeDragStartData = {
|
|
|
1954
1998
|
export type FrameDragStartData = {
|
|
1955
1999
|
frameId: FrameId;
|
|
1956
2000
|
};
|
|
2001
|
+
/**
|
|
2002
|
+
* Handler interface for drag actions.
|
|
2003
|
+
*/
|
|
2004
|
+
export interface ActionHandler {
|
|
2005
|
+
eventHandler: (e: KeyboardEvent, state: DragState, forceRecalculateEdges: () => void) => void;
|
|
2006
|
+
/**
|
|
2007
|
+
* Called when the drag coordinates change (during any event). Should return true to allow the edges to be updated/moved, or false to prevent it.
|
|
2008
|
+
*
|
|
2009
|
+
* Can return anything for the end event as it's ignored.
|
|
2010
|
+
*
|
|
2011
|
+
* Can be used to save some context/info to later apply safely during onDragApply.
|
|
2012
|
+
*/
|
|
2013
|
+
onDragChange: (...args: Parameters<DragChangeHandler>) => DragChangeResult;
|
|
2014
|
+
/**
|
|
2015
|
+
* Called when drag will be applied. If dragEnd was called with apply false, it will not be called.
|
|
2016
|
+
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
2017
|
+
*/
|
|
2018
|
+
onDragApply: (state: DragState, forceRecalculateEdges: () => void) => {
|
|
2019
|
+
/** Whether to apply the regular drag end changes. Return false to reset to the position before dragging. */
|
|
2020
|
+
apply: boolean;
|
|
2021
|
+
/** Value to resolve the drag promise with. Ignored if `apply` is false. */
|
|
2022
|
+
result: any;
|
|
2023
|
+
};
|
|
2024
|
+
/**
|
|
2025
|
+
* Called after visual edges are recalculated. Action handlers can annotate edges with error info.
|
|
2026
|
+
*/
|
|
2027
|
+
annotateEdges?: (edges: Edge[], frames: LayoutFrame[]) => void;
|
|
2028
|
+
}
|
|
1957
2029
|
export type DragStartFn = {
|
|
1958
2030
|
(e: PointerEvent, type: "edge", data: EdgeDragStartData): void;
|
|
1959
2031
|
(e: PointerEvent, type: "frame", data: FrameDragStartData): void;
|
|
@@ -153,7 +153,8 @@ export const LAYOUT_ERROR = enumFromArray([
|
|
|
153
153
|
"CANT_COLLAPSE_NOT_DOCKED",
|
|
154
154
|
"CANT_UNCOLLAPSE_NOT_COLLAPSED",
|
|
155
155
|
"NO_FILL_CANDIDATES",
|
|
156
|
-
"CANT_RESIZE_COLLAPSED_FRAME"
|
|
156
|
+
"CANT_RESIZE_COLLAPSED_FRAME",
|
|
157
|
+
"CANT_RESIZE_SINGLE_FRAME"
|
|
157
158
|
]);
|
|
158
159
|
export const zWindowCreate = zLayoutWindowLoose.partial({ id: true, pxWidth: true, pxHeight: true, pxX: true, pxY: true }).extend({ frames: zLayoutWindow.shape.frames.optional() });
|
|
159
160
|
export const zLayoutCreate = baseLayout.loose().extend({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey, Ref } from "vue";
|
|
2
|
-
import type { Direction, DragState, Edge, FrameId, IntersectionEntry, LayoutFrame, LayoutShape, LayoutWindow, Orientation, Point } from "./index.js";
|
|
2
|
+
import type { ActionHandler, Direction, DragState, Edge, FrameId, IntersectionEntry, LayoutFrame, LayoutShape, LayoutWindow, Orientation, Point } from "./index.js";
|
|
3
3
|
export type LayoutContext = ComputedRef<{
|
|
4
4
|
/** The owning window, needed so we can correctly scale coordinates. */
|
|
5
5
|
win: LayoutWindow;
|
|
@@ -8,14 +8,23 @@ export type LayoutContext = ComputedRef<{
|
|
|
8
8
|
}>;
|
|
9
9
|
export declare const layoutContextInjectionKey: InjectionKey<LayoutContext>;
|
|
10
10
|
export interface UseFramesContext {
|
|
11
|
+
actionHandler: ActionHandler;
|
|
11
12
|
dragStart: {
|
|
12
13
|
(e: PointerEvent, type: "edge", data: {
|
|
13
14
|
edge?: Edge;
|
|
14
15
|
intersection?: IntersectionEntry;
|
|
15
|
-
}
|
|
16
|
+
}, opts?: {
|
|
17
|
+
moveEvent?: string;
|
|
18
|
+
endEvent?: string;
|
|
19
|
+
context?: Record<string, unknown>;
|
|
20
|
+
}): Promise<any>;
|
|
16
21
|
(e: PointerEvent, type: "frame", data: {
|
|
17
22
|
frameId: FrameId;
|
|
18
|
-
}
|
|
23
|
+
}, opts?: {
|
|
24
|
+
moveEvent?: string;
|
|
25
|
+
endEvent?: string;
|
|
26
|
+
context?: Record<string, unknown>;
|
|
27
|
+
}): Promise<any>;
|
|
19
28
|
};
|
|
20
29
|
dragMove: (e: PointerEvent) => void;
|
|
21
30
|
dragEnd: (e?: PointerEvent, options?: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@witchcraft/layout",
|
|
3
3
|
"description": "Headless layout manager.",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.4",
|
|
5
5
|
"main": "./dist/runtime/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@alanscodelog/semantic-release-config": "^6.0.2",
|
|
50
50
|
"@alanscodelog/tsconfigs": "^6.3.0",
|
|
51
51
|
"@alanscodelog/vite-config": "^0.0.7",
|
|
52
|
+
"@babel/runtime": "^7.20.7",
|
|
52
53
|
"@commitlint/cli": "^19.8.1",
|
|
53
54
|
"@nuxt/eslint-config": "^1.15.2",
|
|
54
55
|
"@nuxt/kit": "^4.4.6",
|
|
@@ -145,6 +146,6 @@
|
|
|
145
146
|
"doc:dev": "concurrently \"pnpm doc:watch\" \"pnpm doc:serve\"",
|
|
146
147
|
"doc:check-invalid": "typedoc --listInvalidSymbolLinks",
|
|
147
148
|
"actions:debug": "act -r -v -j release",
|
|
148
|
-
"gen:exports": "indexit update --ignore **/*.d.ts **.vue src/assets/** -o '${path}.js'"
|
|
149
|
+
"gen:exports": "indexit update --ignore **/*.d.ts **.vue src/assets/** **/demo/** **/dist/** -o '${path}.js'"
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
flex
|
|
8
8
|
flex-col
|
|
9
9
|
`,
|
|
10
|
-
isDragging && `dragging cursor-pointer`,
|
|
10
|
+
isDragging && `dragging cursor-pointer user-select-none pointer-events-none`,
|
|
11
11
|
requestType && `request-${requestType}`,
|
|
12
12
|
($attrs as any).class
|
|
13
13
|
)"
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
<script lang="ts" setup>
|
|
71
71
|
import { useGlobalResizeObserver } from "@witchcraft/ui/composables/useGlobalResizeObserver"
|
|
72
72
|
import { twMerge } from "@witchcraft/ui/utils/twMerge"
|
|
73
|
-
import { computed, provide, reactive, ref, useAttrs, watch } from "vue"
|
|
73
|
+
import { computed, markRaw, provide, reactive, ref, useAttrs, watch } from "vue"
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
import { useFrames } from "../composables/useFrames.js"
|
|
@@ -90,6 +90,8 @@ const $attrs = useAttrs()
|
|
|
90
90
|
const win = defineModel<LayoutWindow>("win", { required: true })
|
|
91
91
|
|
|
92
92
|
const props = withDefaults(defineProps<{
|
|
93
|
+
/** If you really need it, you can provide your own drag action handler (remember to markRaw it), note the actionHandler's prop will no longer have any effect.*/
|
|
94
|
+
dragActionHandler?: DragActionHandler<any, any>
|
|
93
95
|
/** Custom drag action handlers. Falls back to default split/close/frame handlers if not provided. */
|
|
94
96
|
actionHandlers?: IDragAction[]
|
|
95
97
|
textHints?: {text:string, classes?:string}[]
|
|
@@ -120,9 +122,9 @@ const windowEl = ref<HTMLElement | null>(null)
|
|
|
120
122
|
|
|
121
123
|
const requestType = ref<string | undefined | string>()
|
|
122
124
|
|
|
123
|
-
const dragActionHandler = new DragActionHandler(
|
|
125
|
+
const dragActionHandler = props.dragActionHandler ?? markRaw(new DragActionHandler(
|
|
124
126
|
[
|
|
125
|
-
...(props.actionHandlers ?? createDefaultHandlers())
|
|
127
|
+
...(props.actionHandlers ?? createDefaultHandlers())
|
|
126
128
|
],
|
|
127
129
|
{
|
|
128
130
|
onEvent: (e, cancel) => {
|
|
@@ -132,14 +134,14 @@ const dragActionHandler = new DragActionHandler(
|
|
|
132
134
|
}
|
|
133
135
|
},
|
|
134
136
|
onRequestChange: type => {
|
|
135
|
-
requestType.value = type
|
|
137
|
+
requestType.value = type as any
|
|
136
138
|
},
|
|
137
139
|
onEnd: () => {
|
|
138
140
|
requestType.value = undefined
|
|
139
141
|
showDragging.value = true
|
|
140
142
|
},
|
|
141
143
|
}
|
|
142
|
-
)
|
|
144
|
+
))
|
|
143
145
|
dragActionHandler.shapes = reactive([])
|
|
144
146
|
dragActionHandler.textHints = reactive({ actions: [], errors: [] })
|
|
145
147
|
const shapes = dragActionHandler.shapes
|
|
@@ -12,30 +12,11 @@ import { moveEdge } from "../helpers/moveEdge.js"
|
|
|
12
12
|
import { toWindowCoord } from "../helpers/toWindowCoord.js"
|
|
13
13
|
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
|
|
14
14
|
import { isPointInRect } from "../layout/isPointInRect.js"
|
|
15
|
-
import type {
|
|
15
|
+
import type { ActionHandler, Direction, DragState, Edge, EdgeDragStartData, FrameDragStartData, FrameId, IntersectionEntry, LayoutFrame, LayoutWindow, Orientation, Point } from "../types/index.js"
|
|
16
16
|
|
|
17
17
|
export function useFrames(
|
|
18
18
|
win: Ref<LayoutWindow>,
|
|
19
|
-
handler:
|
|
20
|
-
eventHandler: (e: KeyboardEvent, state: DragState, forceRecalculateEdges: () => void) => void
|
|
21
|
-
/**
|
|
22
|
-
* Called when the drag coordinates change (during any event). Should return true to allow the edges to be updated/moved, or false to prevent it.
|
|
23
|
-
*
|
|
24
|
-
* Can return anything for the end event as it's ignored.
|
|
25
|
-
*
|
|
26
|
-
* Can be used to save some context/info to later apply safely during onDragApply.
|
|
27
|
-
*/
|
|
28
|
-
onDragChange: (...args: Parameters<DragChangeHandler>) => DragChangeResult
|
|
29
|
-
/**
|
|
30
|
-
* Called when drag will be applied. If dragEnd was called with apply false, it will not be called.
|
|
31
|
-
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
32
|
-
*/
|
|
33
|
-
onDragApply: ((state: DragState, forceRecalculateEdges: () => void) => boolean)
|
|
34
|
-
/**
|
|
35
|
-
* Called after visual edges are recalculated. Action handlers can annotate edges with error info.
|
|
36
|
-
*/
|
|
37
|
-
annotateEdges?: (edges: Edge[], frames: LayoutFrame[]) => void
|
|
38
|
-
}
|
|
19
|
+
handler: ActionHandler
|
|
39
20
|
) {
|
|
40
21
|
const draggingEdges = ref<Edge[]>([])
|
|
41
22
|
|
|
@@ -59,10 +40,14 @@ export function useFrames(
|
|
|
59
40
|
|
|
60
41
|
const dragDirections = ref<Record<Orientation, Direction | undefined>>({} as any)
|
|
61
42
|
|
|
43
|
+
let dragStartPoint: Point | undefined
|
|
44
|
+
const dragDistance = ref(-1)
|
|
45
|
+
|
|
62
46
|
const draggingIntersection = ref<IntersectionEntry | undefined>(undefined)
|
|
63
47
|
const isDraggingFromWindowEdge = ref<boolean>(false)
|
|
64
48
|
|
|
65
49
|
const frameDragFrameId = ref<FrameId | undefined>()
|
|
50
|
+
const eventContext = ref<Record<string, unknown> | undefined>()
|
|
66
51
|
|
|
67
52
|
const frames = computed(() =>
|
|
68
53
|
isDragging.value && showDragging.value
|
|
@@ -110,6 +95,7 @@ export function useFrames(
|
|
|
110
95
|
const state = computed(() => ({
|
|
111
96
|
dragDirections: dragDirections.value,
|
|
112
97
|
dragPoint: dragPoint.value,
|
|
98
|
+
dragDistance: dragDistance.value,
|
|
113
99
|
isDragging: isDragging.value,
|
|
114
100
|
showDragging: showDragging.value,
|
|
115
101
|
draggingFrameId: frameDragFrameId.value,
|
|
@@ -122,18 +108,29 @@ export function useFrames(
|
|
|
122
108
|
dragHoveredFrame: dragHoveredFrame.value,
|
|
123
109
|
intersections: intersections.value,
|
|
124
110
|
isDraggingFromWindowEdge: isDraggingFromWindowEdge.value,
|
|
111
|
+
eventContext: eventContext.value,
|
|
125
112
|
win: win.value
|
|
126
113
|
} satisfies DragState))
|
|
127
114
|
|
|
128
115
|
let controller: AbortController
|
|
116
|
+
let dragResolve: ((result: any) => void) | undefined
|
|
117
|
+
let dragResult: any
|
|
129
118
|
|
|
130
119
|
function resetState(): void {
|
|
120
|
+
dragStartPoint = undefined
|
|
121
|
+
|
|
122
|
+
dragResolve?.(dragResult)
|
|
123
|
+
dragResolve = undefined
|
|
124
|
+
dragResult = undefined
|
|
125
|
+
|
|
131
126
|
draggingEdges.value = []
|
|
132
127
|
draggingIntersection.value = undefined
|
|
133
128
|
isDragging.value = false
|
|
134
129
|
dragPoint.value = undefined
|
|
130
|
+
dragDistance.value = -1
|
|
135
131
|
touchingFrames.value = []
|
|
136
132
|
frameDragFrameId.value = undefined
|
|
133
|
+
eventContext.value = undefined
|
|
137
134
|
dragDirStore.reset()
|
|
138
135
|
showDragging.value = false
|
|
139
136
|
forceRecalculateEdges()
|
|
@@ -143,18 +140,38 @@ export function useFrames(
|
|
|
143
140
|
e: PointerEvent,
|
|
144
141
|
type: T,
|
|
145
142
|
// someday this will work
|
|
146
|
-
data: T extends "edge" ? EdgeDragStartData : FrameDragStartData
|
|
147
|
-
|
|
143
|
+
data: T extends "edge" ? EdgeDragStartData : FrameDragStartData,
|
|
144
|
+
{
|
|
145
|
+
moveEvent = "pointermove",
|
|
146
|
+
endEvent = "pointerup",
|
|
147
|
+
context
|
|
148
|
+
}: {
|
|
149
|
+
moveEvent?: string
|
|
150
|
+
endEvent?: string
|
|
151
|
+
context?: Record<string, unknown>
|
|
152
|
+
} = {}
|
|
153
|
+
): Promise<any> {
|
|
154
|
+
// if already dragging, abort previous (resetState resolves the old promise)
|
|
155
|
+
if (controller) {
|
|
156
|
+
controller.abort()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const promise = new Promise<any>(resolve => {
|
|
160
|
+
dragResolve = resolve
|
|
161
|
+
})
|
|
162
|
+
|
|
148
163
|
controller = new AbortController()
|
|
149
164
|
controller.signal.addEventListener("abort", () => resetState())
|
|
150
165
|
|
|
151
166
|
e.preventDefault()
|
|
152
|
-
window.addEventListener(
|
|
153
|
-
window.addEventListener(
|
|
167
|
+
window.addEventListener(moveEvent, dragMove as EventListener, { signal: controller.signal })
|
|
168
|
+
window.addEventListener(endEvent, dragEnd as EventListener, { signal: controller.signal })
|
|
154
169
|
|
|
155
170
|
const point = toWindowCoord(win.value, e)
|
|
156
171
|
dragPoint.value = point
|
|
172
|
+
dragStartPoint = { ...point }
|
|
157
173
|
dragDirStore.update(point)
|
|
174
|
+
eventContext.value = context
|
|
158
175
|
|
|
159
176
|
isDragging.value = type
|
|
160
177
|
showDragging.value = true
|
|
@@ -166,7 +183,7 @@ export function useFrames(
|
|
|
166
183
|
draggingIntersection.value = intersection
|
|
167
184
|
|
|
168
185
|
draggingEdges.value = edge
|
|
169
|
-
? [edge]
|
|
186
|
+
? [edge!]
|
|
170
187
|
: [
|
|
171
188
|
...(draggingIntersection.value?.sharedEdges.horizontal ?? []),
|
|
172
189
|
...(draggingIntersection.value?.sharedEdges.vertical ?? [])
|
|
@@ -198,6 +215,7 @@ export function useFrames(
|
|
|
198
215
|
|
|
199
216
|
const res = handler.onDragChange("start", e, state.value, forceRecalculateEdges, cancel)
|
|
200
217
|
showDragging.value = res.showDragging ?? true
|
|
218
|
+
return promise
|
|
201
219
|
}
|
|
202
220
|
|
|
203
221
|
function dragMove(e: PointerEvent): void {
|
|
@@ -205,6 +223,13 @@ export function useFrames(
|
|
|
205
223
|
const point = toWindowCoord(win.value, e)
|
|
206
224
|
const didChange = dragDirStore.update(point)
|
|
207
225
|
dragPoint.value = point
|
|
226
|
+
// at least one drag move has happened
|
|
227
|
+
dragDistance.value = 0
|
|
228
|
+
if (dragStartPoint) {
|
|
229
|
+
dragDistance.value = Math.sqrt(
|
|
230
|
+
Math.pow(point.x - dragStartPoint.x, 2) + Math.pow(point.y - dragStartPoint.y, 2)
|
|
231
|
+
)
|
|
232
|
+
}
|
|
208
233
|
if (!didChange) return
|
|
209
234
|
const res = handler.onDragChange("move", e, state.value, forceRecalculateEdges, cancel)
|
|
210
235
|
|
|
@@ -231,17 +256,20 @@ export function useFrames(
|
|
|
231
256
|
dragPoint.value = point
|
|
232
257
|
}
|
|
233
258
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
259
|
+
if (apply) {
|
|
260
|
+
const applyResult = handler.onDragApply(state.value, forceRecalculateEdges)
|
|
261
|
+
dragResult = applyResult.result
|
|
262
|
+
if (applyResult.apply) {
|
|
263
|
+
for (const frame of touchingFramesArrays.value.flat()) {
|
|
264
|
+
win!.value.frames[frame.id] = frame
|
|
265
|
+
}
|
|
238
266
|
}
|
|
239
267
|
}
|
|
240
268
|
|
|
241
269
|
handler.onDragChange("end", e, state.value, forceRecalculateEdges, cancel)
|
|
242
270
|
|
|
243
271
|
// this can get called from elsewhere
|
|
244
|
-
// also takes care of cleanup
|
|
272
|
+
// also takes care of cleanup nd resolving promise
|
|
245
273
|
controller?.abort()
|
|
246
274
|
}
|
|
247
275
|
function cancel(): void {
|
|
@@ -281,6 +309,7 @@ export function useFrames(
|
|
|
281
309
|
forceRecalculateEdges,
|
|
282
310
|
state,
|
|
283
311
|
showDragging,
|
|
284
|
-
frameDragFrameId
|
|
312
|
+
frameDragFrameId,
|
|
313
|
+
actionHandler: handler
|
|
285
314
|
}
|
|
286
315
|
}
|
|
@@ -13,6 +13,7 @@ export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError
|
|
|
13
13
|
|
|
14
14
|
export class CloseAction implements IDragAction {
|
|
15
15
|
name = "close" as const
|
|
16
|
+
minDragDistance = 5
|
|
16
17
|
|
|
17
18
|
state: {
|
|
18
19
|
allowed: true
|
|
@@ -62,12 +63,15 @@ export class CloseAction implements IDragAction {
|
|
|
62
63
|
config?: {
|
|
63
64
|
debug?: boolean | string
|
|
64
65
|
closeHints?: Partial<CloseAction["closeHints"]>
|
|
66
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
67
|
+
minDragDistance?: number
|
|
65
68
|
}
|
|
66
69
|
) {
|
|
67
70
|
if (handleEvent !== undefined) this.handleEvent = handleEvent
|
|
68
71
|
if (modifyDecos !== undefined) this.modifyDecos = modifyDecos
|
|
69
72
|
this.hooks = hooks
|
|
70
73
|
if (config?.debug) this.debug = true
|
|
74
|
+
if (config?.minDragDistance !== undefined) this.minDragDistance = config.minDragDistance
|
|
71
75
|
this.reset()
|
|
72
76
|
}
|
|
73
77
|
|
|
@@ -151,6 +155,9 @@ export class CloseAction implements IDragAction {
|
|
|
151
155
|
_e: PointerEvent | undefined,
|
|
152
156
|
state: DragState
|
|
153
157
|
): ActionDragChangeResult {
|
|
158
|
+
if (state.dragDistance <= this.minDragDistance) {
|
|
159
|
+
return { updateEdges: false, shapes: [] }
|
|
160
|
+
}
|
|
154
161
|
const {
|
|
155
162
|
touchingFramesArrays,
|
|
156
163
|
dragDirections,
|
|
@@ -191,14 +191,14 @@ export class DragActionHandler<
|
|
|
191
191
|
onDragApply(
|
|
192
192
|
state: DragState,
|
|
193
193
|
forceRecalculateEdges: () => void
|
|
194
|
-
): boolean {
|
|
194
|
+
): { apply: boolean, result: any } {
|
|
195
195
|
if (this.activeAction) {
|
|
196
196
|
const res = this.actions[this.activeAction]!.onDragApply(state, forceRecalculateEdges)
|
|
197
197
|
this.hooks.onEnd?.({ cancelled: false, applied: res })
|
|
198
|
-
return
|
|
198
|
+
return { apply: res, result: undefined }
|
|
199
199
|
}
|
|
200
200
|
this.hooks.onEnd?.({ cancelled: false, applied: false })
|
|
201
|
-
return true
|
|
201
|
+
return { apply: true, result: undefined }
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
cancel(e: PointerEvent | KeyboardEvent | undefined, state: DragState): void {
|