@witchcraft/layout 0.1.2 → 0.2.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 +27 -24
- package/dist/module.json +1 -1
- package/dist/runtime/components/FrameDragHandle.d.vue.ts +15 -0
- package/dist/runtime/components/FrameDragHandle.vue +28 -0
- package/dist/runtime/components/FrameDragHandle.vue.d.ts +15 -0
- package/dist/runtime/components/LayoutDecos.d.vue.ts +2 -4
- package/dist/runtime/components/LayoutDecos.vue +10 -29
- package/dist/runtime/components/LayoutDecos.vue.d.ts +2 -4
- package/dist/runtime/components/LayoutEdges.d.vue.ts +3 -3
- package/dist/runtime/components/LayoutEdges.vue +9 -10
- package/dist/runtime/components/LayoutEdges.vue.d.ts +3 -3
- package/dist/runtime/components/LayoutFrame.d.vue.ts +1 -1
- package/dist/runtime/components/LayoutFrame.vue +1 -4
- package/dist/runtime/components/LayoutFrame.vue.d.ts +1 -1
- package/dist/runtime/components/LayoutShapeSquare.d.vue.ts +3 -1
- package/dist/runtime/components/LayoutShapeSquare.vue +3 -5
- package/dist/runtime/components/LayoutShapeSquare.vue.d.ts +3 -1
- package/dist/runtime/components/LayoutWindow.d.vue.ts +26 -12
- package/dist/runtime/components/LayoutWindow.vue +95 -84
- package/dist/runtime/components/LayoutWindow.vue.d.ts +26 -12
- package/dist/runtime/composables/useFrames.d.ts +15 -13
- package/dist/runtime/composables/useFrames.js +59 -39
- package/dist/runtime/demo/App.vue +116 -30
- package/dist/runtime/demo/DemoControls.d.vue.ts +4 -1
- package/dist/runtime/demo/DemoControls.vue +98 -4
- package/dist/runtime/demo/DemoControls.vue.d.ts +4 -1
- package/dist/runtime/drag/CloseAction.d.ts +26 -5
- package/dist/runtime/drag/CloseAction.js +87 -40
- package/dist/runtime/drag/DragActionHandler.d.ts +20 -8
- package/dist/runtime/drag/DragActionHandler.js +47 -12
- package/dist/runtime/drag/FrameDragAction.d.ts +45 -0
- package/dist/runtime/drag/FrameDragAction.js +143 -0
- package/dist/runtime/drag/SplitAction.d.ts +32 -11
- package/dist/runtime/drag/SplitAction.js +82 -24
- package/dist/runtime/drag/createDefaultHandlers.d.ts +9 -0
- package/dist/runtime/drag/createDefaultHandlers.js +10 -0
- package/dist/runtime/drag/defaultDragActions.d.ts +9 -0
- package/dist/runtime/drag/defaultDragActions.js +10 -0
- package/dist/runtime/drag/types.d.ts +82 -13
- package/dist/runtime/drag/types.js +1 -0
- package/dist/runtime/helpers/createZoneSideClipPath.d.ts +12 -0
- package/dist/runtime/helpers/createZoneSideClipPath.js +17 -0
- package/dist/runtime/helpers/doEdgesOverlap.d.ts +3 -1
- package/dist/runtime/helpers/doEdgesOverlap.js +5 -5
- package/dist/runtime/helpers/getDockBoundaries.d.ts +19 -0
- package/dist/runtime/helpers/getDockBoundaries.js +14 -0
- package/dist/runtime/helpers/getEdgeLength.d.ts +2 -0
- package/dist/runtime/helpers/getEdgeLength.js +5 -0
- package/dist/runtime/helpers/getIntersections.js +2 -2
- package/dist/runtime/helpers/getIntersectionsCss.js +2 -2
- package/dist/runtime/helpers/getMoveEdgeInfo.js +2 -2
- package/dist/runtime/helpers/getResizeLimit.js +2 -2
- package/dist/runtime/helpers/getShapeSquareCss.js +2 -2
- package/dist/runtime/helpers/getVisualEdgeCss.js +2 -2
- package/dist/runtime/helpers/getVisualEdges.d.ts +1 -1
- package/dist/runtime/helpers/getVisualEdges.js +4 -3
- package/dist/runtime/helpers/index.d.ts +4 -0
- package/dist/runtime/helpers/index.js +4 -0
- package/dist/runtime/helpers/isEdgeEqual.js +2 -4
- package/dist/runtime/helpers/isWindowEdge.js +2 -2
- package/dist/runtime/helpers/isWindowEdgePoint.js +2 -2
- package/dist/runtime/helpers/moveEdge.js +2 -2
- package/dist/runtime/helpers/numberToScaledPercent.d.ts +1 -1
- package/dist/runtime/helpers/numberToScaledPercent.js +2 -2
- package/dist/runtime/helpers/numberToScaledSize.js +2 -2
- package/dist/runtime/helpers/rotateFrames.d.ts +7 -0
- package/dist/runtime/helpers/rotateFrames.js +36 -0
- package/dist/runtime/helpers/scaledPointToPx.d.ts +13 -0
- package/dist/runtime/helpers/scaledPointToPx.js +7 -0
- package/dist/runtime/helpers/toWindowCoord.js +2 -2
- package/dist/runtime/layout/applyFrameChanges.d.ts +10 -0
- package/dist/runtime/layout/applyFrameChanges.js +29 -0
- package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +6 -1
- package/dist/runtime/layout/createSplitDecoFromDrag.js +4 -4
- package/dist/runtime/layout/createSplitDecoShapes.d.ts +7 -0
- package/dist/runtime/layout/{createSplitDecoEdge.js → createSplitDecoShapes.js} +6 -3
- package/dist/runtime/layout/debugFrame.js +2 -1
- package/dist/runtime/layout/findSafeSplitEdge.js +2 -2
- package/dist/runtime/layout/frameCreate.js +2 -2
- package/dist/runtime/layout/getCloseFrameInfo.d.ts +7 -6
- package/dist/runtime/layout/getCloseFrameInfo.js +10 -3
- package/dist/runtime/layout/getDragZones.d.ts +8 -0
- package/dist/runtime/layout/getDragZones.js +32 -0
- package/dist/runtime/layout/getFillEmptySpaceInfo.d.ts +65 -0
- package/dist/runtime/layout/getFillEmptySpaceInfo.js +69 -0
- package/dist/runtime/layout/getFrameCollapseInfo.d.ts +13 -0
- package/dist/runtime/layout/getFrameCollapseInfo.js +93 -0
- package/dist/runtime/layout/getFrameDockInfo.d.ts +9 -0
- package/dist/runtime/layout/getFrameDockInfo.js +82 -0
- package/dist/runtime/layout/getFrameDragZones.d.ts +16 -0
- package/dist/runtime/layout/getFrameDragZones.js +74 -0
- package/dist/runtime/layout/getFrameRearrangeInfo.d.ts +139 -0
- package/dist/runtime/layout/getFrameRearrangeInfo.js +87 -0
- package/dist/runtime/layout/getFrameSplitInfo.d.ts +7 -5
- package/dist/runtime/layout/getFrameSplitInfo.js +10 -3
- package/dist/runtime/layout/getFrameSwapInfo.d.ts +9 -0
- package/dist/runtime/layout/getFrameSwapInfo.js +27 -0
- package/dist/runtime/layout/getFrameTo.js +2 -2
- package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +12 -0
- package/dist/runtime/layout/getFrameUncollapseInfo.js +88 -0
- package/dist/runtime/layout/getFrameUndockInfo.d.ts +13 -0
- package/dist/runtime/layout/getFrameUndockInfo.js +51 -0
- package/dist/runtime/layout/getFramesRedistributeInfo.d.ts +29 -0
- package/dist/runtime/layout/getFramesRedistributeInfo.js +53 -0
- package/dist/runtime/layout/getWindowDragZones.d.ts +6 -0
- package/dist/runtime/layout/getWindowDragZones.js +49 -0
- package/dist/runtime/layout/index.d.ts +14 -5
- package/dist/runtime/layout/index.js +14 -5
- package/dist/runtime/layout/isPointInRect.d.ts +7 -0
- package/dist/runtime/layout/{isPointInFrame.js → isPointInRect.js} +1 -1
- package/dist/runtime/layout/resizeFrame.js +2 -2
- package/dist/runtime/settings.d.ts +41 -16
- package/dist/runtime/settings.js +95 -53
- package/dist/runtime/types/index.d.ts +324 -55
- package/dist/runtime/types/index.js +54 -20
- package/package.json +28 -29
- package/src/runtime/components/FrameDragHandle.vue +30 -0
- package/src/runtime/components/LayoutDecos.vue +12 -36
- package/src/runtime/components/LayoutEdges.vue +27 -22
- package/src/runtime/components/LayoutFrame.vue +6 -5
- package/src/runtime/components/LayoutShapeSquare.vue +11 -5
- package/src/runtime/components/LayoutWindow.vue +110 -101
- package/src/runtime/composables/useFrames.ts +80 -50
- package/src/runtime/demo/App.vue +126 -36
- package/src/runtime/demo/DemoControls.vue +115 -6
- package/src/runtime/drag/CloseAction.ts +106 -44
- package/src/runtime/drag/DragActionHandler.ts +71 -20
- package/src/runtime/drag/FrameDragAction.ts +202 -0
- package/src/runtime/drag/SplitAction.ts +106 -34
- package/src/runtime/drag/createDefaultHandlers.ts +19 -0
- package/src/runtime/drag/defaultDragActions.ts +19 -0
- package/src/runtime/drag/types.ts +90 -20
- package/src/runtime/helpers/createZoneSideClipPath.ts +41 -0
- package/src/runtime/helpers/doEdgesOverlap.ts +11 -5
- package/src/runtime/helpers/getDockBoundaries.ts +36 -0
- package/src/runtime/helpers/getEdgeLength.ts +10 -0
- package/src/runtime/helpers/getIntersections.ts +2 -2
- package/src/runtime/helpers/getIntersectionsCss.ts +2 -2
- package/src/runtime/helpers/getMoveEdgeInfo.ts +2 -2
- package/src/runtime/helpers/getResizeLimit.ts +2 -2
- package/src/runtime/helpers/getShapeSquareCss.ts +2 -2
- package/src/runtime/helpers/getVisualEdgeCss.ts +2 -2
- package/src/runtime/helpers/getVisualEdges.ts +5 -4
- package/src/runtime/helpers/index.ts +4 -0
- package/src/runtime/helpers/isEdgeEqual.ts +2 -4
- package/src/runtime/helpers/isWindowEdge.ts +2 -2
- package/src/runtime/helpers/isWindowEdgePoint.ts +2 -2
- package/src/runtime/helpers/moveEdge.ts +2 -2
- package/src/runtime/helpers/numberToScaledPercent.ts +3 -3
- package/src/runtime/helpers/numberToScaledSize.ts +2 -2
- package/src/runtime/helpers/rotateFrames.ts +45 -0
- package/src/runtime/helpers/scaledPointToPx.ts +13 -0
- package/src/runtime/helpers/toWindowCoord.ts +2 -2
- package/src/runtime/layout/applyFrameChanges.ts +39 -0
- package/src/runtime/layout/createSplitDecoFromDrag.ts +12 -6
- package/src/runtime/layout/{createSplitDecoEdge.ts → createSplitDecoShapes.ts} +17 -7
- package/src/runtime/layout/debugFrame.ts +1 -1
- package/src/runtime/layout/findSafeSplitEdge.ts +3 -3
- package/src/runtime/layout/frameCreate.ts +2 -2
- package/src/runtime/layout/getCloseFrameInfo.ts +21 -8
- package/src/runtime/layout/getDragZones.ts +48 -0
- package/src/runtime/layout/getFillEmptySpaceInfo.ts +177 -0
- package/src/runtime/layout/getFrameCollapseInfo.ts +164 -0
- package/src/runtime/layout/getFrameDockInfo.ts +126 -0
- package/src/runtime/layout/getFrameDragZones.ts +100 -0
- package/src/runtime/layout/getFrameRearrangeInfo.ts +261 -0
- package/src/runtime/layout/getFrameSplitInfo.ts +21 -8
- package/src/runtime/layout/getFrameSwapInfo.ts +45 -0
- package/src/runtime/layout/getFrameTo.ts +2 -2
- package/src/runtime/layout/getFrameUncollapseInfo.ts +160 -0
- package/src/runtime/layout/getFrameUndockInfo.ts +97 -0
- package/src/runtime/layout/getFramesRedistributeInfo.ts +98 -0
- package/src/runtime/layout/getWindowDragZones.ts +59 -0
- package/src/runtime/layout/index.ts +14 -5
- package/src/runtime/layout/isPointInRect.ts +7 -0
- package/src/runtime/layout/resizeFrame.ts +2 -2
- package/src/runtime/settings.ts +69 -49
- package/src/runtime/types/index.ts +143 -28
- package/dist/runtime/layout/closeFrame.d.ts +0 -5
- package/dist/runtime/layout/closeFrame.js +0 -13
- package/dist/runtime/layout/closeFrames.d.ts +0 -2
- package/dist/runtime/layout/closeFrames.js +0 -8
- package/dist/runtime/layout/createSplitDecoEdge.d.ts +0 -2
- package/dist/runtime/layout/frameSplit.d.ts +0 -16
- package/dist/runtime/layout/frameSplit.js +0 -9
- package/dist/runtime/layout/isPointInFrame.d.ts +0 -2
- package/src/runtime/layout/closeFrame.ts +0 -33
- package/src/runtime/layout/closeFrames.ts +0 -14
- package/src/runtime/layout/frameSplit.ts +0 -31
- package/src/runtime/layout/isPointInFrame.ts +0 -7
|
@@ -1,57 +1,92 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<!-- overflow hidden is because the borders inside will make it overflow -->
|
|
3
|
-
<div
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
<div
|
|
4
|
+
:class="twMerge(
|
|
5
|
+
`
|
|
6
|
+
layout-wrapper
|
|
7
|
+
flex
|
|
8
|
+
flex-col
|
|
9
|
+
`,
|
|
8
10
|
isDragging && `dragging cursor-pointer`,
|
|
9
11
|
requestType && `request-${requestType}`,
|
|
10
12
|
($attrs as any).class
|
|
11
13
|
)"
|
|
12
|
-
|
|
13
|
-
v-bind="{...$attrs, class: undefined}"
|
|
14
|
+
v-bind="{ ...$attrs, class: undefined }"
|
|
14
15
|
>
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
<!-- we need the size withot borders for correct px calculations -->
|
|
17
|
+
<div class="
|
|
18
|
+
layout-window
|
|
19
|
+
relative
|
|
20
|
+
overflow-hidden
|
|
21
|
+
flex-1
|
|
22
|
+
" ref="windowEl">
|
|
23
|
+
<template v-if="windowEl && win">
|
|
24
|
+
<LayoutFrameComponent
|
|
25
|
+
:frame="frame"
|
|
26
|
+
:is-active-frame="frame.id === win.activeFrame"
|
|
27
|
+
v-for="frame of frames"
|
|
28
|
+
:key="frame.id"
|
|
29
|
+
v-bind="frameProps"
|
|
30
|
+
@focus="windowSetActiveFrame(win, frame.id)"
|
|
31
|
+
>
|
|
32
|
+
<slot :name="`frame-${frame.id}`" v-bind="{frame}"/>
|
|
33
|
+
</LayoutFrameComponent>
|
|
34
|
+
<LayoutEdgesComponent
|
|
35
|
+
:win="win"
|
|
36
|
+
:active-frame="win.activeFrame ? frames[win.activeFrame] : undefined"
|
|
37
|
+
:edges="visualEdges"
|
|
38
|
+
:intersections="intersections"
|
|
39
|
+
:dragging-edge="draggingEdges.length === 1 ? draggingEdges[0] : undefined"
|
|
40
|
+
:dragging-intersection="draggingIntersection"
|
|
41
|
+
v-bind="edgesProps"
|
|
42
|
+
@drag-start="dragStart"
|
|
43
|
+
/>
|
|
44
|
+
<LayoutDecosComponent
|
|
45
|
+
:shapes="shapes"
|
|
46
|
+
/>
|
|
47
|
+
<slot name="extra-decos"/>
|
|
48
|
+
</template>
|
|
49
|
+
</div>
|
|
50
|
+
<Teleport
|
|
51
|
+
v-if="isDragging === 'frame' && frameDragFrameId && dragPoint"
|
|
52
|
+
:to="ghostTeleportTo"
|
|
53
|
+
defer
|
|
54
|
+
>
|
|
55
|
+
<div
|
|
56
|
+
class="fixed z-[9999] pointer-events-none"
|
|
57
|
+
:style="{
|
|
58
|
+
left: (dragPoint.x / settings.maxInt * win.pxWidth + win.pxX) + 'px',
|
|
59
|
+
top: (dragPoint.y / settings.maxInt * win.pxHeight + win.pxY) + 'px',
|
|
60
|
+
width: frames[frameDragFrameId]
|
|
61
|
+
? (frames[frameDragFrameId].width / settings.maxInt * win.pxWidth) + 'px'
|
|
62
|
+
: undefined,
|
|
63
|
+
height: frames[frameDragFrameId]
|
|
64
|
+
? (frames[frameDragFrameId].height / settings.maxInt * win.pxHeight) + 'px'
|
|
65
|
+
: undefined
|
|
66
|
+
}"
|
|
22
67
|
>
|
|
23
|
-
<slot
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
v-bind="edgesProps"
|
|
33
|
-
@drag-start="dragStart"
|
|
34
|
-
/>
|
|
35
|
-
<LayoutDecosComponent
|
|
36
|
-
:frames="frames"
|
|
37
|
-
:split-decos="splitDecos"
|
|
38
|
-
:close-decos="closeDecos"
|
|
39
|
-
/>
|
|
40
|
-
<slot name="extra-decos"/>
|
|
41
|
-
</template>
|
|
42
|
-
<Teleport v-if="instructionsTeleportTo && filteredUsageInstructions.length > 0" defer :to="instructionsTeleportTo">
|
|
68
|
+
<slot
|
|
69
|
+
:id="frameDragFrameId"
|
|
70
|
+
:name="`frame-drag-ghost`"
|
|
71
|
+
>
|
|
72
|
+
<div class="frame-drag-ghost border border-neutral-500 bg-white/50 w-10 h-10"/>
|
|
73
|
+
</slot>
|
|
74
|
+
</div>
|
|
75
|
+
</Teleport>
|
|
76
|
+
<Teleport v-if="textHintsTeleportTo && textHints.length > 0" :to="textHintsTeleportTo" defer>
|
|
43
77
|
<span aria-live="polite">
|
|
44
78
|
<span
|
|
45
|
-
class="
|
|
79
|
+
:class="twMerge(`
|
|
80
|
+
text-hint
|
|
46
81
|
after:content-['┃']
|
|
47
82
|
last:after:content-none
|
|
48
83
|
after:mx-1
|
|
49
|
-
after:text-
|
|
50
|
-
"
|
|
51
|
-
v-for="instruction of
|
|
52
|
-
:key="instruction"
|
|
84
|
+
after:text-neutral-500
|
|
85
|
+
`, instruction.classes)"
|
|
86
|
+
v-for="instruction of textHints"
|
|
87
|
+
:key="instruction.text"
|
|
53
88
|
>
|
|
54
|
-
{{ instruction }}
|
|
89
|
+
{{ instruction.text }}
|
|
55
90
|
</span>
|
|
56
91
|
</span>
|
|
57
92
|
</Teleport>
|
|
@@ -60,32 +95,31 @@
|
|
|
60
95
|
<script lang="ts" setup>
|
|
61
96
|
import { useGlobalResizeObserver } from "@witchcraft/ui/composables/useGlobalResizeObserver"
|
|
62
97
|
import { twMerge } from "@witchcraft/ui/utils/twMerge"
|
|
63
|
-
import { computed, ref,useAttrs,watch } from "vue"
|
|
64
|
-
import { type HTMLAttributes } from "vue"
|
|
98
|
+
import { computed, provide, reactive, ref, useAttrs, watch } from "vue"
|
|
65
99
|
|
|
66
100
|
import LayoutDecosComponent from "./LayoutDecos.vue"
|
|
67
101
|
import LayoutEdgesComponent from "./LayoutEdges.vue"
|
|
68
102
|
import LayoutFrameComponent from "./LayoutFrame.vue"
|
|
69
103
|
|
|
70
104
|
import { useFrames } from "../composables/useFrames.js"
|
|
71
|
-
import {
|
|
105
|
+
import { createDefaultHandlers } from "../drag/createDefaultHandlers.js"
|
|
72
106
|
import { DragActionHandler } from "../drag/DragActionHandler"
|
|
73
|
-
import {
|
|
74
|
-
import { type DragState, type IDragAction } from "../drag/types.js"
|
|
107
|
+
import { dragContextInjectionKey, type DragState, type IDragAction } from "../drag/types.js"
|
|
75
108
|
import { updateWindowWithEvent } from "../helpers/updateWindowSizeWithEvent.js"
|
|
76
109
|
import { windowSetActiveFrame } from "../layout/windowSetActiveFrame.js"
|
|
77
|
-
import
|
|
110
|
+
import type { LayoutEdgesProps, LayoutFrameProps, LayoutWindow } from "../types/index.js"
|
|
111
|
+
import { settings } from "../settings.js"
|
|
78
112
|
|
|
79
113
|
|
|
80
114
|
const $attrs = useAttrs()
|
|
81
115
|
const win = defineModel<LayoutWindow>("win", { required: true })
|
|
82
116
|
|
|
83
117
|
const props = withDefaults(defineProps<{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
/** Custom drag action handlers. Falls back to default split/close/frame handlers if not provided. */
|
|
119
|
+
actionHandlers?: IDragAction[]
|
|
120
|
+
textHints?: {text:string, classes?:string}[]
|
|
121
|
+
textHintsTeleportTo: string | undefined
|
|
122
|
+
ghostTeleportTo?: string
|
|
89
123
|
/**
|
|
90
124
|
* You might need to temporarily disable updating the window size while transitioning, depending on your layout.
|
|
91
125
|
*
|
|
@@ -94,61 +128,28 @@ const props = withDefaults(defineProps<{
|
|
|
94
128
|
* When this is turned back on again, it will trigger an update. You can also trigger updates manually with the exposed updateWindowSize function.
|
|
95
129
|
*/
|
|
96
130
|
allowWindowSizeUpdate?: boolean
|
|
97
|
-
frameProps?: Partial<Omit<LayoutFrameProps, "frame" | "isActiveFrame" | "onFocus"
|
|
98
|
-
edgesProps?: Partial<Omit<LayoutEdgesProps, "edges" | "intersections" | "win"
|
|
131
|
+
frameProps?: Partial<Omit<LayoutFrameProps, "frame" | "isActiveFrame" | "onFocus">>
|
|
132
|
+
edgesProps?: Partial<Omit<LayoutEdgesProps, "edges" | "intersections" | "win">>,
|
|
99
133
|
}>(), {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
allowWindowSizeUpdate: true,
|
|
134
|
+
actionHandlers: undefined,
|
|
135
|
+
textHints: () => [],
|
|
136
|
+
textHintsTeleportTo: undefined,
|
|
137
|
+
ghostTeleportTo: "#root",
|
|
138
|
+
allowWindowSizeUpdate: true
|
|
106
139
|
})
|
|
107
140
|
const emit = defineEmits<{
|
|
108
141
|
(e: "isShowingDrag", value: boolean): void
|
|
109
142
|
(e: "dragState", value: DragState): void
|
|
110
143
|
}>()
|
|
111
144
|
|
|
112
|
-
const filteredUsageInstructions = computed(() => Object.values(props.usageInstructions).filter(_ => _ !== undefined).map(_ => _))
|
|
113
|
-
|
|
114
|
-
const splitKeyHandler = props.splitKeyHandler ?? ((e: PointerEvent | KeyboardEvent, state: DragState) =>
|
|
115
|
-
e.altKey || state.isDraggingFromWindowEdge)
|
|
116
|
-
const closeKeyHandler = props.closeKeyHandler ?? ((e: PointerEvent | KeyboardEvent) => {
|
|
117
|
-
if (e.ctrlKey && e.shiftKey) {
|
|
118
|
-
return "force"
|
|
119
|
-
}
|
|
120
|
-
if (e.shiftKey) return true
|
|
121
|
-
return false
|
|
122
|
-
})
|
|
123
|
-
|
|
124
145
|
|
|
125
146
|
const windowEl = ref<HTMLElement | null>(null)
|
|
126
147
|
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
const closeDecos = ref<CloseDeco[]>([])
|
|
130
|
-
const splitDecos = ref<SplitDeco[]>([])
|
|
131
|
-
const requestType = ref<"split" | "close" | undefined | string>()
|
|
148
|
+
const requestType = ref<string | undefined | string>()
|
|
132
149
|
|
|
133
150
|
const dragActionHandler = new DragActionHandler(
|
|
134
|
-
(
|
|
135
|
-
type: "start" | "move" | "end",
|
|
136
|
-
_e: PointerEvent | KeyboardEvent | undefined,
|
|
137
|
-
state: DragState
|
|
138
|
-
) => type === "move" ? !state.isDraggingFromWindowEdge : undefined,
|
|
139
151
|
[
|
|
140
|
-
|
|
141
|
-
splitKeyHandler,
|
|
142
|
-
((decos: SplitDeco[]) => splitDecos.value = decos),
|
|
143
|
-
{
|
|
144
|
-
onStart: () => showDragging.value = false,
|
|
145
|
-
onCancel: () => showDragging.value = true,
|
|
146
|
-
}),
|
|
147
|
-
new CloseAction(
|
|
148
|
-
closeKeyHandler,
|
|
149
|
-
((decos: CloseDeco[]) => closeDecos.value = decos),
|
|
150
|
-
),
|
|
151
|
-
...props.additionalDragActions
|
|
152
|
+
...(props.actionHandlers ?? createDefaultHandlers()),
|
|
152
153
|
],
|
|
153
154
|
{
|
|
154
155
|
onEvent: (e, cancel) => {
|
|
@@ -163,12 +164,21 @@ const dragActionHandler = new DragActionHandler(
|
|
|
163
164
|
onEnd: () => {
|
|
164
165
|
requestType.value = undefined
|
|
165
166
|
showDragging.value = true
|
|
166
|
-
}
|
|
167
|
+
},
|
|
167
168
|
}
|
|
168
169
|
)
|
|
170
|
+
dragActionHandler.shapes = reactive([])
|
|
171
|
+
dragActionHandler.textHints = reactive({ actions: [], errors: [] })
|
|
172
|
+
const shapes = dragActionHandler.shapes
|
|
173
|
+
|
|
174
|
+
const dragContext = useFrames(
|
|
175
|
+
win,
|
|
176
|
+
dragActionHandler
|
|
177
|
+
)
|
|
169
178
|
|
|
170
179
|
const {
|
|
171
180
|
dragStart,
|
|
181
|
+
dragPoint,
|
|
172
182
|
visualEdges,
|
|
173
183
|
isDragging,
|
|
174
184
|
draggingEdges,
|
|
@@ -176,25 +186,24 @@ const {
|
|
|
176
186
|
frames,
|
|
177
187
|
intersections,
|
|
178
188
|
state,
|
|
179
|
-
|
|
180
|
-
win,
|
|
189
|
+
frameDragFrameId,
|
|
181
190
|
showDragging,
|
|
182
|
-
|
|
183
|
-
)
|
|
191
|
+
} = dragContext
|
|
184
192
|
|
|
193
|
+
provide(dragContextInjectionKey, dragContext)
|
|
185
194
|
|
|
186
195
|
function getWindowOffset() {
|
|
187
196
|
const windowElRect = windowEl.value!.getBoundingClientRect()
|
|
188
197
|
return {
|
|
189
198
|
pxX: Math.floor(windowElRect.x),
|
|
190
|
-
pxY: Math.floor(windowElRect.y)
|
|
199
|
+
pxY: Math.floor(windowElRect.y)
|
|
191
200
|
}
|
|
192
201
|
}
|
|
193
202
|
function getWindowSize() {
|
|
194
203
|
const windowElRect = windowEl.value!.getBoundingClientRect()
|
|
195
204
|
return {
|
|
196
205
|
pxWidth: Math.floor(windowElRect.width),
|
|
197
|
-
pxHeight: Math.floor(windowElRect.height)
|
|
206
|
+
pxHeight: Math.floor(windowElRect.height)
|
|
198
207
|
}
|
|
199
208
|
}
|
|
200
209
|
function updateWindowSize() {
|
|
@@ -217,7 +226,7 @@ defineExpose({
|
|
|
217
226
|
state,
|
|
218
227
|
win,
|
|
219
228
|
updateWindowSize,
|
|
229
|
+
dragActionHandler
|
|
220
230
|
})
|
|
221
|
-
|
|
222
231
|
</script>
|
|
223
232
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { debounce } from "@alanscodelog/utils/debounce"
|
|
2
2
|
import { keys } from "@alanscodelog/utils/keys"
|
|
3
3
|
import type { Ref } from "vue"
|
|
4
|
-
import { computed, onBeforeUnmount, onMounted, ref,
|
|
4
|
+
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
|
|
5
5
|
|
|
6
6
|
import { DragDirectionStore } from "../drag/DragDirectionStore.js"
|
|
7
|
-
import type { DragChangeHandler, DragState } from "../drag/types.js"
|
|
7
|
+
import type { DragChangeHandler, DragChangeResult, DragState, EdgeDragStartData, FrameDragStartData } from "../drag/types.js"
|
|
8
8
|
import { cloneFrame } from "../helpers/cloneFrame.js"
|
|
9
9
|
import { getIntersections } from "../helpers/getIntersections.js"
|
|
10
10
|
import { getVisualEdges } from "../helpers/getVisualEdges.js"
|
|
@@ -12,21 +12,21 @@ import { isWindowEdge } from "../helpers/isWindowEdge.js"
|
|
|
12
12
|
import { moveEdge } from "../helpers/moveEdge.js"
|
|
13
13
|
import { toWindowCoord } from "../helpers/toWindowCoord.js"
|
|
14
14
|
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
|
|
15
|
-
import {
|
|
16
|
-
import type { Direction, Edge, IntersectionEntry, LayoutFrame, LayoutWindow, Orientation, Point } from "../types/index.js"
|
|
15
|
+
import { isPointInRect } from "../layout/isPointInRect.js"
|
|
16
|
+
import type { Direction, Edge, FrameId, IntersectionEntry, LayoutFrame, LayoutWindow, Orientation, Point } from "../types/index.js"
|
|
17
17
|
|
|
18
18
|
export function useFrames(
|
|
19
19
|
win: Ref<LayoutWindow>,
|
|
20
|
-
/** Whether to show merged the moved frames while dragging. */
|
|
21
|
-
showDragging: Ref<boolean>,
|
|
22
20
|
handler: {
|
|
23
21
|
eventHandler: (e: KeyboardEvent, state: DragState, forceRecalculateEdges: () => void) => void
|
|
24
22
|
/**
|
|
25
|
-
* Called when the drag coordinates change (during any event). Should return true to allow the edges to be moved, or false to prevent it.
|
|
23
|
+
* 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.
|
|
24
|
+
*
|
|
25
|
+
* Can return anything for the end event as it's ignored.
|
|
26
26
|
*
|
|
27
27
|
* Can be used to save some context/info to later apply safely during onDragApply.
|
|
28
28
|
*/
|
|
29
|
-
onDragChange: DragChangeHandler
|
|
29
|
+
onDragChange: (...args: Parameters<DragChangeHandler>) => DragChangeResult
|
|
30
30
|
/**
|
|
31
31
|
* Called when drag will be applied. If dragEnd was called with apply false, it will not be called.
|
|
32
32
|
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
@@ -50,7 +50,8 @@ export function useFrames(
|
|
|
50
50
|
|
|
51
51
|
const touchingFramesArrays = computed(() => touchingFrames.value.map(entry => Object.values(entry)))
|
|
52
52
|
|
|
53
|
-
const isDragging = ref(false)
|
|
53
|
+
const isDragging = ref<false | "frame" | "edge">(false)
|
|
54
|
+
const showDragging = ref(false)
|
|
54
55
|
const dragPoint = ref<Point | undefined>()
|
|
55
56
|
|
|
56
57
|
const dragDirections = ref<Record<Orientation, Direction | undefined>>({} as any)
|
|
@@ -58,6 +59,8 @@ export function useFrames(
|
|
|
58
59
|
const draggingIntersection = ref<IntersectionEntry | undefined>(undefined)
|
|
59
60
|
const isDraggingFromWindowEdge = ref<boolean>(false)
|
|
60
61
|
|
|
62
|
+
const frameDragFrameId = ref<FrameId | undefined>()
|
|
63
|
+
|
|
61
64
|
const frames = computed(() =>
|
|
62
65
|
isDragging.value && showDragging.value
|
|
63
66
|
? { ...win.value.frames, ...allTouchingFrames.value }
|
|
@@ -67,7 +70,7 @@ export function useFrames(
|
|
|
67
70
|
const dragHoveredFrame = computed(() => {
|
|
68
71
|
if (isDragging.value) {
|
|
69
72
|
for (const id of keys(frames.value)) {
|
|
70
|
-
if (
|
|
73
|
+
if (isPointInRect(frames.value[id], dragPoint.value!)) {
|
|
71
74
|
return frames.value[id]
|
|
72
75
|
}
|
|
73
76
|
}
|
|
@@ -83,12 +86,14 @@ export function useFrames(
|
|
|
83
86
|
visualEdges.value = getVisualEdges(f, { includeWindowEdges: true })
|
|
84
87
|
}, 50, {}) as any
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
watch([isDragging, frames], () => {
|
|
87
90
|
// let request animation force recalc
|
|
88
91
|
if (isDragging.value) return
|
|
89
92
|
// otherwise use more performant debounced version
|
|
90
93
|
debounceGetDraggableEdges(Object.values(frames.value))
|
|
91
|
-
})
|
|
94
|
+
}, { deep: true })
|
|
95
|
+
debounceGetDraggableEdges(Object.values(frames.value))
|
|
96
|
+
|
|
92
97
|
function forceRecalculateEdges(): void {
|
|
93
98
|
visualEdges.value = getVisualEdges(Object.values(frames.value), { includeWindowEdges: true })
|
|
94
99
|
}
|
|
@@ -101,6 +106,8 @@ export function useFrames(
|
|
|
101
106
|
dragDirections: dragDirections.value,
|
|
102
107
|
dragPoint: dragPoint.value,
|
|
103
108
|
isDragging: isDragging.value,
|
|
109
|
+
showDragging: showDragging.value,
|
|
110
|
+
draggingFrameId: frameDragFrameId.value,
|
|
104
111
|
draggingEdges: draggingEdges.value,
|
|
105
112
|
draggingIntersection: draggingIntersection.value,
|
|
106
113
|
visualEdges: visualEdges.value,
|
|
@@ -121,11 +128,18 @@ export function useFrames(
|
|
|
121
128
|
isDragging.value = false
|
|
122
129
|
dragPoint.value = undefined
|
|
123
130
|
touchingFrames.value = []
|
|
131
|
+
frameDragFrameId.value = undefined
|
|
124
132
|
dragDirStore.reset()
|
|
133
|
+
showDragging.value = false
|
|
125
134
|
forceRecalculateEdges()
|
|
126
135
|
}
|
|
127
136
|
|
|
128
|
-
function dragStart
|
|
137
|
+
function dragStart<T extends "edge" | "frame">(
|
|
138
|
+
e: PointerEvent,
|
|
139
|
+
type: T,
|
|
140
|
+
// someday this will work
|
|
141
|
+
data: T extends "edge" ? EdgeDragStartData : FrameDragStartData
|
|
142
|
+
): void {
|
|
129
143
|
controller = new AbortController()
|
|
130
144
|
controller.signal.addEventListener("abort", () => resetState())
|
|
131
145
|
|
|
@@ -135,42 +149,50 @@ export function useFrames(
|
|
|
135
149
|
|
|
136
150
|
const point = toWindowCoord(win.value, e)
|
|
137
151
|
dragPoint.value = point
|
|
152
|
+
dragDirStore.update(point)
|
|
138
153
|
|
|
139
|
-
isDragging.value =
|
|
154
|
+
isDragging.value = type
|
|
155
|
+
showDragging.value = true
|
|
140
156
|
|
|
141
|
-
|
|
157
|
+
if (type === "frame") {
|
|
158
|
+
frameDragFrameId.value = (data as FrameDragStartData).frameId
|
|
159
|
+
} else {
|
|
160
|
+
const { edge, intersection } = data as EdgeDragStartData
|
|
161
|
+
draggingIntersection.value = intersection
|
|
142
162
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
163
|
+
draggingEdges.value = edge
|
|
164
|
+
? [edge]
|
|
165
|
+
: [
|
|
166
|
+
...(draggingIntersection.value?.sharedEdges.horizontal ?? []),
|
|
167
|
+
...(draggingIntersection.value?.sharedEdges.vertical ?? [])
|
|
168
|
+
]
|
|
149
169
|
|
|
150
|
-
dragDirStore.update(point)
|
|
151
|
-
isDraggingFromWindowEdge.value = draggingEdges.value.some(_ => isWindowEdge(_))
|
|
152
170
|
|
|
153
|
-
|
|
171
|
+
isDraggingFromWindowEdge.value = draggingEdges.value.some(_ => isWindowEdge(_))
|
|
154
172
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
173
|
+
const framesArray = Object.values(win.value.frames)
|
|
174
|
+
|
|
175
|
+
touchingFrames.value = []
|
|
176
|
+
// all frames in touchingFrames must be clones
|
|
177
|
+
// BUT they must be the same clone even if they are referenced by multiple dragging edges
|
|
178
|
+
const clones = new Map<string, LayoutFrame>()
|
|
179
|
+
for (let i = 0; i < draggingEdges.value.length; i++) {
|
|
180
|
+
const draggingEdge = draggingEdges.value[i]
|
|
181
|
+
touchingFrames.value[i] = {}
|
|
182
|
+
for (const { frame } of findFramesTouchingEdge(draggingEdge, framesArray)) {
|
|
183
|
+
if (!clones.has(frame.id)) {
|
|
184
|
+
const clone = cloneFrame(frame)
|
|
185
|
+
touchingFrames.value[i][frame.id] = clone
|
|
186
|
+
clones.set(frame.id, clone)
|
|
187
|
+
} else {
|
|
188
|
+
touchingFrames.value[i][frame.id] = clones.get(frame.id)!
|
|
189
|
+
}
|
|
169
190
|
}
|
|
170
191
|
}
|
|
171
192
|
}
|
|
172
193
|
|
|
173
|
-
handler.onDragChange("start", e, state.value, forceRecalculateEdges, cancel)
|
|
194
|
+
const res = handler.onDragChange("start", e, state.value, forceRecalculateEdges, cancel)
|
|
195
|
+
showDragging.value = res.showDragging ?? true
|
|
174
196
|
}
|
|
175
197
|
|
|
176
198
|
function dragMove(e: PointerEvent): void {
|
|
@@ -179,18 +201,23 @@ export function useFrames(
|
|
|
179
201
|
const didChange = dragDirStore.update(point)
|
|
180
202
|
dragPoint.value = point
|
|
181
203
|
if (!didChange) return
|
|
182
|
-
const
|
|
204
|
+
const res = handler.onDragChange("move", e, state.value, forceRecalculateEdges, cancel)
|
|
183
205
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
206
|
+
|
|
207
|
+
showDragging.value = res.showDragging ?? true
|
|
208
|
+
if (!res.updateEdges) return
|
|
209
|
+
|
|
210
|
+
if (isDragging.value === "edge") {
|
|
211
|
+
requestAnimationFrame(() => {
|
|
212
|
+
for (let i = 0; i < draggingEdges.value.length; i++) {
|
|
213
|
+
const draggingEdge = draggingEdges.value[i]
|
|
214
|
+
if (draggingEdge) {
|
|
215
|
+
moveEdge(touchingFramesArrays.value[i], draggingEdge, point)
|
|
216
|
+
}
|
|
190
217
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
218
|
+
forceRecalculateEdges()
|
|
219
|
+
})
|
|
220
|
+
}
|
|
194
221
|
}
|
|
195
222
|
|
|
196
223
|
function dragEnd(e?: PointerEvent, { apply = true }: { apply?: boolean } = {}): void {
|
|
@@ -233,6 +260,7 @@ export function useFrames(
|
|
|
233
260
|
dragStart,
|
|
234
261
|
dragEnd,
|
|
235
262
|
cancel,
|
|
263
|
+
dragMove,
|
|
236
264
|
dragDirections,
|
|
237
265
|
dragPoint,
|
|
238
266
|
isDragging,
|
|
@@ -246,6 +274,8 @@ export function useFrames(
|
|
|
246
274
|
intersections,
|
|
247
275
|
isDraggingFromWindowEdge,
|
|
248
276
|
forceRecalculateEdges,
|
|
249
|
-
state
|
|
277
|
+
state,
|
|
278
|
+
showDragging,
|
|
279
|
+
frameDragFrameId
|
|
250
280
|
}
|
|
251
281
|
}
|