@witchcraft/layout 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -74
- package/dist/module.json +1 -1
- package/dist/module.mjs +6 -1
- package/dist/runtime/components/FrameDragHandle.vue +1 -1
- package/dist/runtime/components/LayoutDecosEdges.d.vue.ts +15 -0
- package/dist/runtime/components/LayoutDecosEdges.vue +34 -0
- package/dist/runtime/components/LayoutDecosEdges.vue.d.ts +15 -0
- package/dist/runtime/components/LayoutDecosRects.d.vue.ts +15 -0
- package/dist/runtime/components/LayoutDecosRects.vue +37 -0
- package/dist/runtime/components/LayoutDecosRects.vue.d.ts +15 -0
- package/dist/runtime/components/LayoutDragEdgeGrabbed.d.vue.ts +2 -0
- package/dist/runtime/components/LayoutDragEdgeGrabbed.vue +43 -0
- package/dist/runtime/components/LayoutDragEdgeGrabbed.vue.d.ts +2 -0
- package/dist/runtime/components/LayoutDragEdgeHandle.d.vue.ts +9 -0
- package/dist/runtime/components/LayoutDragEdgeHandle.vue +44 -0
- package/dist/runtime/components/LayoutDragEdgeHandle.vue.d.ts +9 -0
- package/dist/runtime/components/{LayoutDecos.d.vue.ts → LayoutDragEdgeVisible.d.vue.ts} +3 -2
- package/dist/runtime/components/LayoutDragEdgeVisible.vue +38 -0
- package/dist/runtime/components/{LayoutDecos.vue.d.ts → LayoutDragEdgeVisible.vue.d.ts} +3 -2
- package/dist/runtime/components/LayoutDragEdges.d.vue.ts +21 -0
- package/dist/runtime/components/LayoutDragEdges.vue +67 -0
- package/dist/runtime/components/LayoutDragEdges.vue.d.ts +21 -0
- package/dist/runtime/components/LayoutEdgesActiveFrame.d.vue.ts +2 -0
- package/dist/runtime/components/LayoutEdgesActiveFrame.vue +35 -0
- package/dist/runtime/components/LayoutEdgesActiveFrame.vue.d.ts +2 -0
- package/dist/runtime/components/LayoutFrame.d.vue.ts +7 -6
- package/dist/runtime/components/LayoutFrame.vue +18 -14
- package/dist/runtime/components/LayoutFrame.vue.d.ts +7 -6
- package/dist/runtime/components/LayoutIntersectionHandle.d.vue.ts +10 -0
- package/dist/runtime/components/LayoutIntersectionHandle.vue +36 -0
- package/dist/runtime/components/LayoutIntersectionHandle.vue.d.ts +10 -0
- package/dist/runtime/components/LayoutIntersectionVisible.d.vue.ts +6 -0
- package/dist/runtime/components/LayoutIntersectionVisible.vue +34 -0
- package/dist/runtime/components/LayoutIntersectionVisible.vue.d.ts +6 -0
- package/dist/runtime/components/LayoutIntersections.d.vue.ts +21 -0
- package/dist/runtime/components/LayoutIntersections.vue +52 -0
- package/dist/runtime/components/LayoutIntersections.vue.d.ts +21 -0
- package/dist/runtime/components/{LayoutShapeSquare.d.vue.ts → LayoutShapeRect.d.vue.ts} +2 -2
- package/dist/runtime/components/{LayoutShapeSquare.vue.d.ts → LayoutShapeRect.vue.d.ts} +2 -2
- package/dist/runtime/components/LayoutWindow.d.vue.ts +252 -14
- package/dist/runtime/components/LayoutWindow.vue +27 -48
- package/dist/runtime/components/LayoutWindow.vue.d.ts +252 -14
- package/dist/runtime/composables/useFrames.d.ts +859 -2
- package/dist/runtime/composables/useFrames.js +2 -0
- package/dist/runtime/demo/App.vue +122 -74
- package/dist/runtime/demo/DemoControls.vue +7 -5
- package/dist/runtime/demo/index.html +12 -0
- package/dist/runtime/demo/tailwind.css +1 -1
- package/dist/runtime/drag/CloseAction.d.ts +1 -2
- package/dist/runtime/drag/CloseAction.js +1 -1
- package/dist/runtime/drag/DragActionHandler.d.ts +5 -3
- package/dist/runtime/drag/DragActionHandler.js +40 -6
- package/dist/runtime/drag/FrameDragAction.js +6 -7
- package/dist/runtime/drag/SplitAction.d.ts +1 -2
- package/dist/runtime/drag/SplitAction.js +1 -1
- package/dist/runtime/drag/createDefaultHandlers.d.ts +1 -1
- package/dist/runtime/drag/defaultDragActions.d.ts +1 -1
- package/dist/runtime/helpers/consoleDebugWindow.d.ts +43 -0
- package/dist/runtime/helpers/consoleDebugWindow.js +222 -0
- package/dist/runtime/helpers/convertLayoutWindowToWorkspace.js +2 -2
- package/dist/runtime/helpers/framesRedistributeFix.d.ts +87 -0
- package/dist/runtime/helpers/framesRedistributeFix.js +54 -0
- package/dist/runtime/helpers/getMoveEdgeInfo.d.ts +6 -2
- package/dist/runtime/helpers/getMoveEdgeInfo.js +11 -2
- package/dist/runtime/helpers/getPinnedEdgesForCollapsedFrames.d.ts +5 -0
- package/dist/runtime/helpers/getPinnedEdgesForCollapsedFrames.js +18 -0
- package/dist/runtime/helpers/getShapeRectCss.d.ts +7 -0
- package/dist/runtime/helpers/{getShapeSquareCss.js → getShapeRectCss.js} +1 -1
- package/dist/runtime/helpers/index.d.ts +3 -3
- package/dist/runtime/helpers/index.js +3 -3
- package/dist/runtime/helpers/moveEdge.js +3 -1
- package/dist/runtime/helpers/pxSizeToScaledSize.d.ts +2 -0
- package/dist/runtime/helpers/{numberToScaledSize.js → pxSizeToScaledSize.js} +1 -1
- package/dist/runtime/helpers/updateWindowSizeWithEvent.d.ts +3 -0
- package/dist/runtime/helpers/validateLayoutShape.d.ts +5 -0
- package/dist/runtime/helpers/validateLayoutShape.js +28 -0
- package/dist/runtime/layout/applyFrameChanges.js +6 -0
- package/dist/runtime/layout/createSplitDecoShapes.js +1 -1
- package/dist/runtime/layout/getFrameCollapseInfo.d.ts +5 -2
- package/dist/runtime/layout/getFrameCollapseInfo.js +16 -46
- package/dist/runtime/layout/getFrameDockInfo.d.ts +1 -1
- package/dist/runtime/layout/getFrameDockInfo.js +5 -1
- package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +5 -2
- package/dist/runtime/layout/getFrameUncollapseInfo.js +16 -50
- package/dist/runtime/layout/getFramesRedistributeInfo.d.ts +20 -4
- package/dist/runtime/layout/getFramesRedistributeInfo.js +31 -2
- package/dist/runtime/layout/getRelaxFramesInfo.d.ts +7 -0
- package/dist/runtime/layout/getRelaxFramesInfo.js +91 -0
- package/dist/runtime/layout/getUpdateWindowSizeInfo.d.ts +13 -0
- package/dist/runtime/layout/getUpdateWindowSizeInfo.js +65 -0
- package/dist/runtime/layout/index.d.ts +1 -0
- package/dist/runtime/layout/index.js +1 -0
- package/dist/runtime/layout/resizeFrame.js +1 -3
- package/dist/runtime/settings.d.ts +26 -19
- package/dist/runtime/settings.js +57 -22
- package/dist/runtime/types/index.d.ts +1243 -30
- package/dist/runtime/types/index.js +22 -8
- package/dist/runtime/types/vue.d.ts +41 -0
- package/dist/runtime/{drag/types.js → types/vue.js} +1 -0
- package/dist/runtime/utils/cssToKey.d.ts +5 -0
- package/dist/runtime/utils/cssToKey.js +3 -0
- package/package.json +11 -12
- package/src/module.ts +6 -1
- package/src/runtime/components/FrameDragHandle.vue +1 -1
- package/src/runtime/components/LayoutDecosEdges.vue +38 -0
- package/src/runtime/components/LayoutDecosRects.vue +42 -0
- package/src/runtime/components/LayoutDragEdgeGrabbed.vue +50 -0
- package/src/runtime/components/LayoutDragEdgeHandle.vue +52 -0
- package/src/runtime/components/LayoutDragEdgeVisible.vue +45 -0
- package/src/runtime/components/LayoutDragEdges.vue +78 -0
- package/src/runtime/components/LayoutEdgesActiveFrame.vue +43 -0
- package/src/runtime/components/LayoutFrame.vue +22 -15
- package/src/runtime/components/LayoutIntersectionHandle.vue +45 -0
- package/src/runtime/components/LayoutIntersectionVisible.vue +41 -0
- package/src/runtime/components/LayoutIntersections.vue +64 -0
- package/src/runtime/components/{LayoutShapeSquare.vue → LayoutShapeRect.vue} +2 -2
- package/src/runtime/components/LayoutWindow.vue +29 -49
- package/src/runtime/composables/useFrames.ts +7 -2
- package/src/runtime/demo/App.vue +128 -78
- package/src/runtime/demo/DemoControls.vue +7 -5
- package/src/runtime/demo/index.html +12 -0
- package/src/runtime/demo/tailwind.css +3 -0
- package/src/runtime/drag/CloseAction.ts +2 -3
- package/src/runtime/drag/DragActionHandler.ts +48 -10
- package/src/runtime/drag/FrameDragAction.ts +4 -5
- package/src/runtime/drag/SplitAction.ts +4 -3
- package/src/runtime/drag/createDefaultHandlers.ts +2 -1
- package/src/runtime/drag/defaultDragActions.ts +2 -1
- package/src/runtime/helpers/consoleDebugWindow.ts +331 -0
- package/src/runtime/helpers/convertLayoutWindowToWorkspace.ts +2 -2
- package/src/runtime/helpers/framesRedistributeFix.ts +162 -0
- package/src/runtime/helpers/getMoveEdgeInfo.ts +22 -5
- package/src/runtime/helpers/getPinnedEdgesForCollapsedFrames.ts +29 -0
- package/src/runtime/helpers/{getShapeSquareCss.ts → getShapeRectCss.ts} +3 -3
- package/src/runtime/helpers/index.ts +4 -3
- package/src/runtime/helpers/moveEdge.ts +3 -1
- package/src/runtime/helpers/{numberToScaledSize.ts → pxSizeToScaledSize.ts} +2 -2
- package/src/runtime/helpers/updateWindowSizeWithEvent.ts +3 -0
- package/src/runtime/helpers/validateLayoutShape.ts +46 -0
- package/src/runtime/layout/applyFrameChanges.ts +5 -0
- package/src/runtime/layout/createSplitDecoShapes.ts +1 -1
- package/src/runtime/layout/getFrameCollapseInfo.ts +26 -85
- package/src/runtime/layout/getFrameDockInfo.ts +8 -1
- package/src/runtime/layout/getFrameUncollapseInfo.ts +29 -96
- package/src/runtime/layout/getFramesRedistributeInfo.ts +60 -5
- package/src/runtime/layout/getRelaxFramesInfo.ts +139 -0
- package/src/runtime/layout/getUpdateWindowSizeInfo.ts +105 -0
- package/src/runtime/layout/index.ts +1 -0
- package/src/runtime/layout/resizeFrame.ts +4 -3
- package/src/runtime/settings.ts +78 -25
- package/src/runtime/types/index.ts +205 -33
- package/src/runtime/types/vue.ts +41 -0
- package/src/runtime/utils/cssToKey.ts +8 -0
- package/dist/runtime/components/LayoutDecos.vue +0 -26
- package/dist/runtime/components/LayoutEdges.d.vue.ts +0 -17
- package/dist/runtime/components/LayoutEdges.vue +0 -144
- package/dist/runtime/components/LayoutEdges.vue.d.ts +0 -17
- package/dist/runtime/drag/types.d.ts +0 -161
- package/dist/runtime/helpers/clampNumber.d.ts +0 -1
- package/dist/runtime/helpers/clampNumber.js +0 -3
- package/dist/runtime/helpers/getShapeSquareCss.d.ts +0 -7
- package/dist/runtime/helpers/numberToScaledSize.d.ts +0 -2
- package/src/runtime/components/LayoutDecos.vue +0 -28
- package/src/runtime/components/LayoutEdges.vue +0 -170
- package/src/runtime/drag/types.ts +0 -177
- package/src/runtime/helpers/clampNumber.ts +0 -9
- /package/dist/runtime/components/{LayoutShapeSquare.vue → LayoutShapeRect.vue} +0 -0
|
@@ -47,6 +47,7 @@ export function useFrames(win, handler) {
|
|
|
47
47
|
const intersections = computed(() => getIntersections(visualEdges.value));
|
|
48
48
|
const debounceGetDraggableEdges = debounce((f) => {
|
|
49
49
|
visualEdges.value = getVisualEdges(f, { includeWindowEdges: true });
|
|
50
|
+
handler.annotateEdges?.(visualEdges.value, f);
|
|
50
51
|
}, 50, {});
|
|
51
52
|
watch([isDragging, frames], () => {
|
|
52
53
|
if (isDragging.value) return;
|
|
@@ -55,6 +56,7 @@ export function useFrames(win, handler) {
|
|
|
55
56
|
debounceGetDraggableEdges(Object.values(frames.value));
|
|
56
57
|
function forceRecalculateEdges() {
|
|
57
58
|
visualEdges.value = getVisualEdges(Object.values(frames.value), { includeWindowEdges: true });
|
|
59
|
+
handler.annotateEdges?.(visualEdges.value, Object.values(frames.value));
|
|
58
60
|
}
|
|
59
61
|
const dragDirStore = new DragDirectionStore({
|
|
60
62
|
onUpdate: (dir) => dragDirections.value = dir
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
:win="win"
|
|
13
13
|
:dragActionHandler="dragActionHandler"
|
|
14
14
|
/>
|
|
15
|
+
|
|
15
16
|
<LayoutWindow
|
|
16
17
|
ref="layoutComponent"
|
|
17
18
|
v-if="win"
|
|
@@ -19,25 +20,11 @@
|
|
|
19
20
|
`
|
|
20
21
|
flex-1
|
|
21
22
|
w-full
|
|
23
|
+
self-stretch
|
|
22
24
|
border-1
|
|
23
25
|
border-neutral-300
|
|
24
26
|
dark:border-neutral-700
|
|
25
27
|
rounded-md
|
|
26
|
-
self-stretch
|
|
27
|
-
[&_.frame]:flex
|
|
28
|
-
[&_.frame]:flex-col
|
|
29
|
-
[&_.frame]:outline-hidden
|
|
30
|
-
[&_.active-frame-edge]:rounded-md
|
|
31
|
-
[&_.active-frame-edge]:border-none
|
|
32
|
-
[&_.drag-edge:hover+.edge]:bg-accent-500/20
|
|
33
|
-
[&_.grabbed-edge]:bg-accent-500
|
|
34
|
-
[&.request-split_.grabbed-edge]:hidden
|
|
35
|
-
[&.request-split_.drag-edge]:hidden
|
|
36
|
-
[&.deco-split-error]:rounded-md
|
|
37
|
-
[&_.deco-split-new-frame]:rounded-md
|
|
38
|
-
[&_.deco-close-frame]:rounded-md
|
|
39
|
-
[&_.deco-close-frame-force]:rounded-md
|
|
40
|
-
[&_.deco-frame-drag]:rounded-md
|
|
41
28
|
`,
|
|
42
29
|
collapsedDocks.top && `border-t-2 border-t-green-500`,
|
|
43
30
|
collapsedDocks.bottom && `border-b-2 border-b-green-500`,
|
|
@@ -50,60 +37,110 @@
|
|
|
50
37
|
@is-showing-drag="isShowingDrag = $event"
|
|
51
38
|
@drag-state="dragState = $event"
|
|
52
39
|
>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
40
|
+
<LayoutFrame class="
|
|
41
|
+
flex
|
|
42
|
+
flex-col
|
|
43
|
+
outline-hidden
|
|
44
|
+
">
|
|
45
|
+
<template #[`frame-${f.id}`] v-for="f in frames" :key="f.id" >
|
|
46
|
+
<div
|
|
47
|
+
v-if="!(f.collapsed && (f.width === 0 || f.height === 0))"
|
|
48
|
+
:data-is-active="win.activeFrame === f.id"
|
|
49
|
+
:class="twMerge(
|
|
58
50
|
`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
51
|
+
border-2
|
|
52
|
+
border-neutral-500
|
|
53
|
+
h-full
|
|
54
|
+
rounded-md
|
|
55
|
+
overflow-auto
|
|
56
|
+
`,
|
|
65
57
|
win.activeFrame === f.id && `border-blue-500`
|
|
66
58
|
)"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
59
|
+
@click="win.activeFrame = f.id"
|
|
60
|
+
>
|
|
61
|
+
<!--
|
|
62
|
+
Avoid placing the padding on the first div in the frame.
|
|
63
|
+
Set it on the first child instead, so that the frame can shrink as small as possible.
|
|
64
|
+
Too big a border can also be a problem, but usually it's small enough that it's beneath the min frame width/height allowed.
|
|
65
|
+
-->
|
|
66
|
+
<div class="p-2 flex flex-col">
|
|
67
|
+
<FrameDragHandle :frame-id="f.id">
|
|
68
|
+
<div
|
|
69
|
+
class="cursor-grab bg-neutral-200 dark:bg-neutral-700 px-2 py-1 text-xs select-none"
|
|
70
|
+
>
|
|
71
|
+
⠿ Drag to move frame
|
|
72
|
+
</div>
|
|
73
|
+
</FrameDragHandle>
|
|
74
|
+
<div class="flex gap-1 px-2 py-1 flex-wrap">
|
|
75
|
+
<button
|
|
76
|
+
v-if="f.docked && !f.collapsed"
|
|
77
|
+
class="bg-neutral-200 dark:bg-neutral-700 px-2 py-0.5 text-xs rounded"
|
|
78
|
+
@click="handleUndock(f.id)"
|
|
79
|
+
>Undock</button>
|
|
80
|
+
<button
|
|
81
|
+
v-if="f.docked && !f.collapsed"
|
|
82
|
+
class="bg-neutral-200 dark:bg-neutral-700 px-2 py-0.5 text-xs rounded"
|
|
83
|
+
@click="handleCollapse(f.id)"
|
|
84
|
+
>Collapse</button>
|
|
85
|
+
<button
|
|
86
|
+
v-if="f.docked && f.collapsed"
|
|
87
|
+
class="bg-neutral-200 dark:bg-neutral-700 px-2 py-0.5 text-xs rounded"
|
|
88
|
+
@click="handleUncollapse(f.id)"
|
|
89
|
+
>Uncollapse</button>
|
|
90
|
+
</div>
|
|
91
|
+
<div class="p-2 whitespace-pre-wrap">
|
|
92
|
+
{{ debugFrame(f) }}
|
|
93
|
+
</div>
|
|
80
94
|
</div>
|
|
81
|
-
</FrameDragHandle>
|
|
82
|
-
<div class="flex gap-1 px-2 py-1 flex-wrap">
|
|
83
|
-
<button
|
|
84
|
-
v-if="f.docked && !f.collapsed"
|
|
85
|
-
class="bg-neutral-200 dark:bg-neutral-700 px-2 py-0.5 text-xs rounded"
|
|
86
|
-
@click="handleUndock(f.id)"
|
|
87
|
-
>Undock</button>
|
|
88
|
-
<button
|
|
89
|
-
v-if="f.docked && !f.collapsed"
|
|
90
|
-
class="bg-neutral-200 dark:bg-neutral-700 px-2 py-0.5 text-xs rounded"
|
|
91
|
-
@click="handleCollapse(f.id)"
|
|
92
|
-
>Collapse</button>
|
|
93
|
-
<button
|
|
94
|
-
v-if="f.docked && typeof f.collapsed === 'number'"
|
|
95
|
-
class="bg-neutral-200 dark:bg-neutral-700 px-2 py-0.5 text-xs rounded"
|
|
96
|
-
@click="handleUncollapse(f.id)"
|
|
97
|
-
>Uncollapse</button>
|
|
98
95
|
</div>
|
|
99
|
-
<div
|
|
100
|
-
{{ debugFrame(f) }}
|
|
96
|
+
<div v-else>
|
|
101
97
|
</div>
|
|
102
|
-
</
|
|
103
|
-
</
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
98
|
+
</template>
|
|
99
|
+
</LayoutFrame>
|
|
100
|
+
<LayoutEdgesActiveFrame class="rounded-md border-none"/>
|
|
101
|
+
<!-- Following slot usage is just done as an example for how to override the slots and further customize the components. You could place classes on the parent LayoutWindow instead or if you don't need to customize anything you can just do:
|
|
102
|
+
<LayoutIntersections/>
|
|
103
|
+
...
|
|
104
|
+
<LayoutDragEdges/>
|
|
105
|
+
-->
|
|
106
|
+
<LayoutDragEdges>
|
|
107
|
+
<template #handle="slotProps">
|
|
108
|
+
<LayoutDragEdgeHandle
|
|
109
|
+
class="..."
|
|
110
|
+
v-bind="slotProps"
|
|
111
|
+
/>
|
|
112
|
+
</template>
|
|
113
|
+
<template #indicator="slotProps">
|
|
114
|
+
<LayoutDragEdgeVisible
|
|
115
|
+
class="..."
|
|
116
|
+
v-bind="slotProps"
|
|
117
|
+
/>
|
|
118
|
+
</template>
|
|
119
|
+
</LayoutDragEdges>
|
|
120
|
+
<LayoutDecosEdges/>
|
|
121
|
+
<!-- Decos add only the most basic color indicators (which you can override, we also pretty them up here with from rounded edges. -->
|
|
122
|
+
<LayoutDecosRects class="
|
|
123
|
+
[&.deco-split-error]:rounded-md
|
|
124
|
+
[&.deco-split-new-frame]:rounded-md
|
|
125
|
+
[&.deco-close-frame]:rounded-md
|
|
126
|
+
[&.deco-close-frame-force]:rounded-md
|
|
127
|
+
[&.deco-frame-drag]:rounded-md
|
|
128
|
+
"/>
|
|
129
|
+
<LayoutDragEdgeGrabbed class="bg-accent-500"/>
|
|
130
|
+
<LayoutIntersections>
|
|
131
|
+
<template #handler="slotProps">
|
|
132
|
+
<LayoutIntersectionHandle
|
|
133
|
+
class="..."
|
|
134
|
+
v-bind="slotProps"
|
|
135
|
+
/>
|
|
136
|
+
</template>
|
|
137
|
+
<template #indicator="slotProps">
|
|
138
|
+
<LayoutIntersectionVisible
|
|
139
|
+
class="..."
|
|
140
|
+
v-bind="slotProps"
|
|
141
|
+
/>
|
|
142
|
+
</template>
|
|
143
|
+
</LayoutIntersections>
|
|
107
144
|
</LayoutWindow>
|
|
108
145
|
</WRoot>
|
|
109
146
|
</template>
|
|
@@ -116,7 +153,14 @@ import { computed, onBeforeMount, ref } from "vue";
|
|
|
116
153
|
import DemoControls from "./DemoControls.vue";
|
|
117
154
|
import { app } from "./sharedLayoutInstance.js";
|
|
118
155
|
import FrameDragHandle from "../components/FrameDragHandle.vue";
|
|
119
|
-
import
|
|
156
|
+
import LayoutFrame from "../components/LayoutFrame.vue";
|
|
157
|
+
import LayoutDecosEdges from "../components/LayoutDecosEdges.vue";
|
|
158
|
+
import LayoutDecosRects from "../components/LayoutDecosRects.vue";
|
|
159
|
+
import LayoutDragEdgeGrabbed from "../components/LayoutDragEdgeGrabbed.vue";
|
|
160
|
+
import LayoutIntersections from "../components/LayoutIntersections.vue";
|
|
161
|
+
import LayoutEdgesActiveFrame from "../components/LayoutEdgesActiveFrame.vue";
|
|
162
|
+
import LayoutDragEdges from "../components/LayoutDragEdges.vue";
|
|
163
|
+
import LayoutIntersectionHandle from "../components/LayoutIntersectionHandle.vue";
|
|
120
164
|
import { applyFrameChanges } from "../layout/applyFrameChanges.js";
|
|
121
165
|
import { debugFrame } from "../layout/debugFrame.js";
|
|
122
166
|
import { getFrameCollapseInfo } from "../layout/getFrameCollapseInfo.js";
|
|
@@ -132,9 +176,13 @@ import { settings } from "../settings.js";
|
|
|
132
176
|
import { throwIfError } from "@alanscodelog/utils/throwIfError";
|
|
133
177
|
import { useTemplateRef } from "vue";
|
|
134
178
|
import { DragActionHandler } from "../drag/DragActionHandler.js";
|
|
179
|
+
import LayoutDragEdgeHandle from "../components/LayoutDragEdgeHandle.vue";
|
|
180
|
+
import LayoutDragEdgeVisible from "../components/LayoutDragEdgeVisible.vue";
|
|
181
|
+
import LayoutIntersectionVisible from "../components/LayoutIntersectionVisible.vue";
|
|
182
|
+
import LayoutWindow from "../components/LayoutWindow.vue";
|
|
135
183
|
const winId = ref(void 0);
|
|
136
184
|
const win = computed(() => winId.value !== void 0 ? app.layout.windows[winId.value] : void 0);
|
|
137
|
-
const layoutComponent =
|
|
185
|
+
const layoutComponent = ref(void 0);
|
|
138
186
|
const frames = computed(() => {
|
|
139
187
|
if (!win.value) return;
|
|
140
188
|
return Object.values(win.value.frames);
|
|
@@ -185,15 +233,6 @@ function handleUncollapse(frameId) {
|
|
|
185
233
|
applyFrameChanges(win.value, changes);
|
|
186
234
|
DragActionHandler.debugState("uncollapse", "after", dragState.value, {}, void 0);
|
|
187
235
|
}
|
|
188
|
-
const textHints = computed(() => {
|
|
189
|
-
const isDragging = dragState.value?.isDragging;
|
|
190
|
-
const textHints2 = dragActionHandler.value?.textHints ?? { actions: [], errors: [] };
|
|
191
|
-
return [
|
|
192
|
-
...!isDragging ? [{ classes: "", text: "Drag from an edge to create a new frame." }] : [],
|
|
193
|
-
...textHints2.errors.map((_) => ({ classes: "text-red-500", text: _ })),
|
|
194
|
-
...textHints2.actions.map((_) => ({ text: _ }))
|
|
195
|
-
];
|
|
196
|
-
});
|
|
197
236
|
const collapsedDocks = computed(() => {
|
|
198
237
|
const sides = {};
|
|
199
238
|
for (const frame of Object.values(win.value?.frames ?? {})) {
|
|
@@ -204,4 +243,13 @@ const collapsedDocks = computed(() => {
|
|
|
204
243
|
return sides;
|
|
205
244
|
});
|
|
206
245
|
const dragActionHandler = computed(() => layoutComponent.value?.dragActionHandler);
|
|
246
|
+
const textHints = computed(() => {
|
|
247
|
+
const isDragging = dragState.value?.isDragging;
|
|
248
|
+
const textHints2 = dragActionHandler.value?.textHints ?? { actions: [], errors: [] };
|
|
249
|
+
return [
|
|
250
|
+
...!isDragging ? [{ classes: "", text: "Drag from an edge to create a new frame." }] : [],
|
|
251
|
+
...textHints2.errors.map((_) => ({ classes: "text-red-500", text: _ })),
|
|
252
|
+
...textHints2.actions.map((_) => ({ text: _ }))
|
|
253
|
+
];
|
|
254
|
+
});
|
|
207
255
|
</script>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</template>
|
|
10
10
|
<template #popover>
|
|
11
11
|
<div class="flex flex-col gap-2 rounded-md w-full`">
|
|
12
|
-
<label class="text-xs">Collapse Size (
|
|
12
|
+
<label class="text-xs">Collapse Size (px):</label>
|
|
13
13
|
<input
|
|
14
14
|
type="number"
|
|
15
15
|
class="w-full min-w-0 border border-neutral-300 dark:border-neutral-700 rounded px-1 py-0.5 text-xs bg-neutral-100 dark:bg-neutral-800"
|
|
@@ -42,7 +42,9 @@
|
|
|
42
42
|
import WDarkModeSwitcher from "@witchcraft/ui/components/WDarkModeSwitcher";
|
|
43
43
|
import WButton from "@witchcraft/ui/components/WButton";
|
|
44
44
|
import WPopover from "@witchcraft/ui/components/WPopover";
|
|
45
|
-
import
|
|
45
|
+
import WCheckbox from "@witchcraft/ui/components/WCheckbox";
|
|
46
|
+
import WSimpleInput from "@witchcraft/ui/components/WSimpleInput";
|
|
47
|
+
import { copyToClipboard } from "@alanscodelog/utils/copyToClipboard";
|
|
46
48
|
import { ref, watch } from "vue";
|
|
47
49
|
import { applyFrameChanges } from "../layout/applyFrameChanges.js";
|
|
48
50
|
import { getFrameUncollapseInfo } from "../layout/getFrameUncollapseInfo.js";
|
|
@@ -56,9 +58,9 @@ const props = defineProps({
|
|
|
56
58
|
dragActionHandler: { type: Object, required: false }
|
|
57
59
|
});
|
|
58
60
|
const showDevActions = ref(false);
|
|
59
|
-
const collapseSizeValue = ref(
|
|
61
|
+
const collapseSizeValue = ref(settings.collapseSizePx.width);
|
|
60
62
|
function handleCollapseSizeChange(value) {
|
|
61
|
-
settings.
|
|
63
|
+
settings.collapseSizePx = value;
|
|
62
64
|
collapseSizeValue.value = value;
|
|
63
65
|
}
|
|
64
66
|
function uncollapseAll() {
|
|
@@ -95,7 +97,7 @@ function copyState() {
|
|
|
95
97
|
}
|
|
96
98
|
}
|
|
97
99
|
const state = JSON.stringify(clone, null, 2);
|
|
98
|
-
|
|
100
|
+
copyToClipboard(state);
|
|
99
101
|
}
|
|
100
102
|
const debugKey = ref(import.meta.dev ? "state.win.frames" : "false");
|
|
101
103
|
watch(debugKey, () => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>@witchcraft/layout Vue Demo</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="app"></div>
|
|
10
|
+
<script type="module" src="./main.ts"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import "tailwindcss";@import "../../../playground/.nuxt/witchcraft-ui.css";@import "../../../playground/.nuxt/witchcraft-layout.css";
|
|
1
|
+
@import "tailwindcss";@import "../../../playground/.nuxt/witchcraft-ui.css";@import "../../../playground/.nuxt/witchcraft-layout.css";@source "../../../src/runtime/demo";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { ActionDragChangeResult, DragState, IDragAction } from "./types.js";
|
|
2
1
|
import { getCloseFrameInfo } from "../layout/getCloseFrameInfo.js";
|
|
3
|
-
import type { CloseDeco } from "../types/index.js";
|
|
2
|
+
import type { ActionDragChangeResult, CloseDeco, DragState, IDragAction } from "../types/index.js";
|
|
4
3
|
import type { KnownError } from "../utils/KnownError.js";
|
|
5
4
|
export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError>;
|
|
6
5
|
export declare class CloseAction implements IDragAction {
|
|
@@ -53,7 +53,7 @@ export class CloseAction {
|
|
|
53
53
|
force,
|
|
54
54
|
shapes: [
|
|
55
55
|
{
|
|
56
|
-
type: "
|
|
56
|
+
type: "rect",
|
|
57
57
|
data: { x: _.x, y: _.y, width: _.width, height: _.height },
|
|
58
58
|
attrs: {
|
|
59
59
|
class: force ? `deco-close-force-frame bg-orange-500/50` : `deco-close-frame bg-orange-500/20`
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type RecordFromArray } from "@alanscodelog/utils";
|
|
2
|
-
import type { DragChangeHandler, DragChangeResult, DragState, IDragAction } from "
|
|
3
|
-
import type { LayoutShape } from "../types/index.js";
|
|
2
|
+
import type { DragChangeHandler, DragChangeResult, DragState, Edge, IDragAction, LayoutFrame, LayoutShape } from "../types/index.js";
|
|
4
3
|
/**
|
|
5
4
|
* Handles the lifecycle of a drag actions {@link IDragAction} and provides additional hooks.
|
|
6
5
|
*
|
|
@@ -41,14 +40,17 @@ export declare class DragActionHandler<TRawDragActions extends IDragAction[], TD
|
|
|
41
40
|
* Default onDragChange handler for when no action can handle the request.
|
|
42
41
|
*
|
|
43
42
|
* Should return true to allow the edges to be moved, or false to prevent it.
|
|
43
|
+
*
|
|
44
|
+
* The default prevents movement when the edge is a window edge and when the edge is touching a collapsed frame.
|
|
44
45
|
*/
|
|
45
46
|
defaultOnDragChange?: DragChangeHandler);
|
|
46
47
|
eventHandler(e: KeyboardEvent | PointerEvent, state: DragState, forceRecalculateEdges: () => void): undefined;
|
|
47
48
|
onDragChange<T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: DragState, forceRecalculateEdges: () => void, cancel: (e: PointerEvent | KeyboardEvent | undefined, state: DragState) => void): DragChangeResult;
|
|
48
49
|
setTextHints(type: "start" | "move" | "end"): void;
|
|
50
|
+
annotateEdges(edges: Edge[], frames: LayoutFrame[]): void;
|
|
49
51
|
onDragApply(state: DragState, forceRecalculateEdges: () => void): boolean;
|
|
50
52
|
cancel(e: PointerEvent | KeyboardEvent | undefined, state: DragState): void;
|
|
51
53
|
static debugState(pluginName: string, type: "before" | "after" | string, state: DragState, pluginState?: Record<string, any>,
|
|
52
|
-
/** Object key to filter the state by, e.g. state.win.frames. If
|
|
54
|
+
/** Object key to filter the state by, e.g. state.win.frames. If false is ignored. The idea is you pass this.debug and users can set this.debug to a string to filter. */
|
|
53
55
|
key?: string | boolean): void;
|
|
54
56
|
}
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { get } from "@alanscodelog/utils";
|
|
2
|
+
import { isWindowEdge } from "../helpers/isWindowEdge.js";
|
|
3
|
+
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js";
|
|
4
|
+
import { LAYOUT_ERROR } from "../types/index.js";
|
|
5
|
+
import { KnownError } from "../utils/KnownError.js";
|
|
2
6
|
export class DragActionHandler {
|
|
3
7
|
activeAction;
|
|
4
8
|
actions;
|
|
5
9
|
eventCanceller = void 0;
|
|
6
10
|
boundCancel;
|
|
7
|
-
defaultOnDragChange = (type, _e, state, _forceRecalculateEdges, _cancel) =>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
defaultOnDragChange = (type, _e, state, _forceRecalculateEdges, _cancel) => {
|
|
12
|
+
const isTouchingCollapsedFrameEdge = type === "move" && state.isDragging === "edge" && state.touchingFramesArrays.some(
|
|
13
|
+
(frames) => (
|
|
14
|
+
// we check with a falsy check on PURPOSE, frames collapsed to 0 aren't an issue, they are ignored anyways
|
|
15
|
+
Object.values(frames).some((f) => f.collapsed)
|
|
16
|
+
)
|
|
17
|
+
);
|
|
18
|
+
return {
|
|
19
|
+
updateEdges: type === "move" ? !(state.isDraggingFromWindowEdge || isTouchingCollapsedFrameEdge) : true,
|
|
20
|
+
shapes: []
|
|
21
|
+
};
|
|
22
|
+
};
|
|
11
23
|
hooks;
|
|
12
24
|
/** All action shapes merged into a single array. If using vue you can set this to a reactive array for reactivity. */
|
|
13
25
|
shapes = [];
|
|
@@ -84,6 +96,28 @@ export class DragActionHandler {
|
|
|
84
96
|
this.textHints.errors.push(...res?.errors ?? []);
|
|
85
97
|
}
|
|
86
98
|
}
|
|
99
|
+
annotateEdges(edges, frames) {
|
|
100
|
+
for (const edge of edges) {
|
|
101
|
+
if (edge.error) continue;
|
|
102
|
+
for (const action of Object.values(this.actions)) {
|
|
103
|
+
action.annotateEdge?.(edge, frames);
|
|
104
|
+
if (edge.error) break;
|
|
105
|
+
}
|
|
106
|
+
if (!edge.error && !isWindowEdge(edge)) {
|
|
107
|
+
const touching = findFramesTouchingEdge(edge, frames);
|
|
108
|
+
if (touching) {
|
|
109
|
+
const collapsedFrame = touching.find((f) => f.frame.collapsed);
|
|
110
|
+
if (collapsedFrame) {
|
|
111
|
+
edge.error = new KnownError(
|
|
112
|
+
LAYOUT_ERROR.CANT_RESIZE_COLLAPSED_FRAME,
|
|
113
|
+
"Cannot Move: Can't Resize Collapsed Frame",
|
|
114
|
+
{ frame: collapsedFrame.frame }
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
87
121
|
onDragApply(state, forceRecalculateEdges) {
|
|
88
122
|
if (this.activeAction) {
|
|
89
123
|
const res = this.actions[this.activeAction].onDragApply(state, forceRecalculateEdges);
|
|
@@ -102,11 +136,11 @@ export class DragActionHandler {
|
|
|
102
136
|
this.hooks.onEnd?.({ cancelled: true, applied: false });
|
|
103
137
|
}
|
|
104
138
|
static debugState(pluginName, type, state, pluginState = {}, key) {
|
|
139
|
+
if (key === false) return;
|
|
105
140
|
let res = { state, pluginState };
|
|
106
|
-
let pickedRes = {};
|
|
107
141
|
if (typeof key === "string" && key !== "") {
|
|
108
|
-
pickedRes = {};
|
|
109
142
|
const paths = key.split(",").map((_) => _.trim()).filter((_) => _);
|
|
143
|
+
const pickedRes = {};
|
|
110
144
|
for (const path of paths) {
|
|
111
145
|
pickedRes[path] = get(res, path.split("."));
|
|
112
146
|
}
|
|
@@ -58,23 +58,22 @@ export class FrameDragAction {
|
|
|
58
58
|
return this.textHints;
|
|
59
59
|
}
|
|
60
60
|
getDecos(matchedZone, state, result) {
|
|
61
|
-
let decos = [];
|
|
62
61
|
const isError = result instanceof Error;
|
|
63
62
|
const frame = state.dragHoveredFrame;
|
|
64
63
|
if (!matchedZone || !frame) {
|
|
65
|
-
|
|
66
|
-
this.modifyDecos(
|
|
67
|
-
return
|
|
64
|
+
const decos2 = [];
|
|
65
|
+
this.modifyDecos(decos2);
|
|
66
|
+
return decos2;
|
|
68
67
|
}
|
|
69
68
|
const clipPath = createZoneSideClipPath(matchedZone, settings.zoneSizes);
|
|
70
69
|
const classes = isError ? `deco-frame-drag deco-frame-drag-error deco-frame-drag-${matchedZone.type}-${matchedZone.side} bg-red-500/50` : `deco-frame-drag deco-frame-drag-${matchedZone.type}-${matchedZone.side} bg-blue-500/50`;
|
|
71
|
-
decos = [{
|
|
70
|
+
const decos = [{
|
|
72
71
|
id: frame.id,
|
|
73
72
|
type: "drop",
|
|
74
73
|
position: matchedZone.side ?? "center",
|
|
75
74
|
shapes: [
|
|
76
75
|
{
|
|
77
|
-
type: "
|
|
76
|
+
type: "rect",
|
|
78
77
|
data: matchedZone,
|
|
79
78
|
attrs: clipPath ? { class: classes, style: `clip-path:${clipPath}` } : { class: classes }
|
|
80
79
|
}
|
|
@@ -105,7 +104,7 @@ export class FrameDragAction {
|
|
|
105
104
|
this.state.lastReturn = getFrameSwapInfo(win, draggingFrameId, dragHoveredFrame.id);
|
|
106
105
|
if (!(this.state.lastReturn instanceof Error)) this.state.lastReturn.info = "swap";
|
|
107
106
|
}
|
|
108
|
-
} else if (matchedZone.type === "window") {
|
|
107
|
+
} else if (matchedZone.type === "window" && dragHoveredFrame && !dragHoveredFrame.docked) {
|
|
109
108
|
this.state.lastReturn = getFrameDockInfo(win, draggingFrameId, matchedZone.side);
|
|
110
109
|
if (!(this.state.lastReturn instanceof Error)) this.state.lastReturn.info = "dock";
|
|
111
110
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { ActionDragChangeResult, DragState, IDragAction } from "./types.js";
|
|
2
1
|
import { getFrameSplitInfo } from "../layout/getFrameSplitInfo.js";
|
|
3
|
-
import type { Point, SplitDeco } from "../types/index.js";
|
|
2
|
+
import type { ActionDragChangeResult, DragState, IDragAction, Point, SplitDeco } from "../types/index.js";
|
|
4
3
|
import type { KnownError } from "../utils/KnownError.js";
|
|
5
4
|
export type SplitInfo = Exclude<ReturnType<typeof getFrameSplitInfo>, KnownError>;
|
|
6
5
|
export declare class SplitAction implements IDragAction {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { LayoutWindow, Point, Size } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* See also {@link createDebugLabeler} for customizing the labeling function, for
|
|
4
|
+
* example to debug the pixel sizes instead of position/size:
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* consoleDebugWindow(clone, 50, createDebugLabeler({
|
|
8
|
+
* showPxSize: true,
|
|
9
|
+
* showSize: false,
|
|
10
|
+
* showPos: false,
|
|
11
|
+
* getWin: () => clone
|
|
12
|
+
* }))
|
|
13
|
+
*
|
|
14
|
+
* @experimental
|
|
15
|
+
*/
|
|
16
|
+
export declare function consoleDebugWindow(win: LayoutWindow, targetWidth?: number, labelFunc?: (f: LayoutWindow["frames"][string]) => string): void;
|
|
17
|
+
type Border = {
|
|
18
|
+
horizontal: string;
|
|
19
|
+
vertical: string;
|
|
20
|
+
topLeft: string;
|
|
21
|
+
topRight: string;
|
|
22
|
+
bottomLeft: string;
|
|
23
|
+
bottomRight: string;
|
|
24
|
+
cross: string;
|
|
25
|
+
fill: string;
|
|
26
|
+
labelBg: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function boxesToText<T extends Size & Point & {
|
|
29
|
+
id?: string;
|
|
30
|
+
}>(boxes: T[], targetWidth?: number, { border, heightScale, labelFunc }?: {
|
|
31
|
+
border?: Partial<Border>;
|
|
32
|
+
heightScale?: number;
|
|
33
|
+
labelFunc?: (box: T) => string;
|
|
34
|
+
}): string | Error;
|
|
35
|
+
export declare function createDebugLabeler({ showPxSize, showCollapsed, showDocked, showSize, showPos, getWin }?: {
|
|
36
|
+
showPxSize?: boolean;
|
|
37
|
+
showCollapsed?: boolean;
|
|
38
|
+
showDocked?: boolean;
|
|
39
|
+
showSize?: boolean;
|
|
40
|
+
showPos?: boolean;
|
|
41
|
+
getWin?: (f: LayoutWindow["frames"][string]) => Pick<LayoutWindow, "pxWidth" | "pxHeight">;
|
|
42
|
+
}): (f: LayoutWindow["frames"][string]) => string;
|
|
43
|
+
export {};
|