@witchcraft/layout 0.4.3 → 0.5.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.
Files changed (126) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/FrameDragHandle.vue +3 -3
  3. package/dist/runtime/components/LayoutDragEdgeGrabbed.vue +3 -3
  4. package/dist/runtime/components/LayoutDragEdgeHandle.d.vue.ts +2 -2
  5. package/dist/runtime/components/LayoutDragEdgeHandle.vue +2 -2
  6. package/dist/runtime/components/LayoutDragEdgeHandle.vue.d.ts +2 -2
  7. package/dist/runtime/components/LayoutDragEdges.vue +5 -5
  8. package/dist/runtime/components/LayoutEdgesActiveFrame.vue +2 -2
  9. package/dist/runtime/components/LayoutFrame.vue +2 -2
  10. package/dist/runtime/components/LayoutIntersectionHandle.d.vue.ts +2 -2
  11. package/dist/runtime/components/LayoutIntersectionHandle.vue +2 -2
  12. package/dist/runtime/components/LayoutIntersectionHandle.vue.d.ts +2 -2
  13. package/dist/runtime/components/LayoutIntersections.vue +4 -4
  14. package/dist/runtime/components/LayoutWindow.d.vue.ts +54 -45
  15. package/dist/runtime/components/LayoutWindow.vue +29 -29
  16. package/dist/runtime/components/LayoutWindow.vue.d.ts +54 -45
  17. package/dist/runtime/composables/useFrames.d.ts +142 -129
  18. package/dist/runtime/composables/useFrames.js +122 -94
  19. package/dist/runtime/demo/App.vue +16 -16
  20. package/dist/runtime/demo/DemoControls.d.vue.ts +2 -2
  21. package/dist/runtime/demo/DemoControls.vue +4 -4
  22. package/dist/runtime/demo/DemoControls.vue.d.ts +2 -2
  23. package/dist/runtime/demo/tailwind.css +1 -1
  24. package/dist/runtime/helpers/createZoneSideClipPath.d.ts +2 -2
  25. package/dist/runtime/helpers/findEdgesTouchingWindow.d.ts +7 -0
  26. package/dist/runtime/helpers/findEdgesTouchingWindow.js +20 -0
  27. package/dist/runtime/helpers/{findFrameDraggableEdges.d.ts → findFrameMoveableEdges.d.ts} +2 -2
  28. package/dist/runtime/helpers/{findFrameDraggableEdges.js → findFrameMoveableEdges.js} +3 -3
  29. package/dist/runtime/helpers/{findDraggableEdge.d.ts → findMoveableEdge.d.ts} +1 -1
  30. package/dist/runtime/helpers/{findDraggableEdge.js → findMoveableEdge.js} +1 -1
  31. package/dist/runtime/helpers/index.d.ts +10 -3
  32. package/dist/runtime/helpers/index.js +10 -3
  33. package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +1 -1
  34. package/dist/runtime/layout/createSplitDecoFromDrag.js +2 -2
  35. package/dist/runtime/layout/debugFrame.js +5 -1
  36. package/dist/runtime/layout/findSafeSplitEdge.d.ts +1 -1
  37. package/dist/runtime/layout/findSafeSplitEdge.js +2 -2
  38. package/dist/runtime/layout/getCloseFrameInfo.js +4 -4
  39. package/dist/runtime/layout/getFrameCollapseInfo.d.ts +1 -1
  40. package/dist/runtime/layout/getFrameCollapseInfo.js +9 -29
  41. package/dist/runtime/layout/getFrameDockInfo.d.ts +1 -1
  42. package/dist/runtime/layout/getFrameDockInfo.js +61 -44
  43. package/dist/runtime/layout/getFrameExpandInfo.d.ts +11 -0
  44. package/dist/runtime/layout/getFrameExpandInfo.js +49 -0
  45. package/dist/runtime/layout/getFrameRearrangeInfo.d.ts +2 -2
  46. package/dist/runtime/layout/getFrameRearrangeInfo.js +8 -8
  47. package/dist/runtime/layout/getFrameShrinkInfo.d.ts +14 -0
  48. package/dist/runtime/layout/getFrameShrinkInfo.js +48 -0
  49. package/dist/runtime/layout/getFrameSplitInfo.d.ts +1 -1
  50. package/dist/runtime/layout/getFrameSplitInfo.js +2 -2
  51. package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +1 -1
  52. package/dist/runtime/layout/getFrameUncollapseInfo.js +6 -20
  53. package/dist/runtime/layout/{getFrameDragZones.d.ts → getFrameZones.d.ts} +3 -3
  54. package/dist/runtime/layout/{getFrameDragZones.js → getFrameZones.js} +1 -1
  55. package/dist/runtime/layout/getUpdateWindowSizeInfo.js +10 -12
  56. package/dist/runtime/layout/{getWindowDragZones.d.ts → getWindowZones.d.ts} +1 -1
  57. package/dist/runtime/layout/{getWindowDragZones.js → getWindowZones.js} +1 -1
  58. package/dist/runtime/layout/getZones.d.ts +8 -0
  59. package/dist/runtime/layout/getZones.js +32 -0
  60. package/dist/runtime/layout/index.d.ts +6 -3
  61. package/dist/runtime/layout/index.js +6 -3
  62. package/dist/runtime/{drag/DragActionHandler.d.ts → move/ActionHandler.d.ts} +18 -18
  63. package/dist/runtime/{drag/DragActionHandler.js → move/ActionHandler.js} +19 -19
  64. package/dist/runtime/{drag → move}/CloseAction.d.ts +8 -8
  65. package/dist/runtime/{drag → move}/CloseAction.js +29 -26
  66. package/dist/runtime/{drag → move}/FrameDragAction.d.ts +8 -8
  67. package/dist/runtime/{drag → move}/FrameDragAction.js +23 -21
  68. package/dist/runtime/{drag/DragDirectionStore.d.ts → move/MoveDirectionStore.d.ts} +4 -4
  69. package/dist/runtime/{drag/DragDirectionStore.js → move/MoveDirectionStore.js} +9 -9
  70. package/dist/runtime/{drag → move}/SplitAction.d.ts +9 -9
  71. package/dist/runtime/{drag → move}/SplitAction.js +46 -43
  72. package/dist/runtime/{drag → move}/createDefaultHandlers.d.ts +2 -2
  73. package/dist/runtime/types/index.d.ts +242 -158
  74. package/dist/runtime/types/index.js +4 -3
  75. package/dist/runtime/types/vue.d.ts +25 -18
  76. package/dist/runtime/types/vue.js +1 -1
  77. package/package.json +3 -2
  78. package/src/runtime/components/FrameDragHandle.vue +3 -3
  79. package/src/runtime/components/LayoutDragEdgeGrabbed.vue +3 -3
  80. package/src/runtime/components/LayoutDragEdgeHandle.vue +4 -4
  81. package/src/runtime/components/LayoutDragEdges.vue +5 -5
  82. package/src/runtime/components/LayoutEdgesActiveFrame.vue +2 -2
  83. package/src/runtime/components/LayoutFrame.vue +2 -2
  84. package/src/runtime/components/LayoutIntersectionHandle.vue +4 -4
  85. package/src/runtime/components/LayoutIntersections.vue +4 -4
  86. package/src/runtime/components/LayoutWindow.vue +35 -35
  87. package/src/runtime/composables/useFrames.ts +141 -121
  88. package/src/runtime/demo/App.vue +18 -18
  89. package/src/runtime/demo/DemoControls.vue +5 -5
  90. package/src/runtime/demo/tailwind.css +4 -0
  91. package/src/runtime/helpers/createZoneSideClipPath.ts +2 -2
  92. package/src/runtime/helpers/findEdgesTouchingWindow.ts +30 -0
  93. package/src/runtime/helpers/{findFrameDraggableEdges.ts → findFrameMoveableEdges.ts} +4 -4
  94. package/src/runtime/helpers/{findDraggableEdge.ts → findMoveableEdge.ts} +1 -1
  95. package/src/runtime/helpers/index.ts +10 -3
  96. package/src/runtime/layout/createSplitDecoFromDrag.ts +2 -2
  97. package/src/runtime/layout/debugFrame.ts +6 -1
  98. package/src/runtime/layout/findSafeSplitEdge.ts +4 -4
  99. package/src/runtime/layout/getCloseFrameInfo.ts +4 -4
  100. package/src/runtime/layout/getFrameCollapseInfo.ts +12 -41
  101. package/src/runtime/layout/getFrameDockInfo.ts +77 -57
  102. package/src/runtime/layout/getFrameExpandInfo.ts +84 -0
  103. package/src/runtime/layout/getFrameRearrangeInfo.ts +10 -10
  104. package/src/runtime/layout/getFrameShrinkInfo.ts +87 -0
  105. package/src/runtime/layout/getFrameSplitInfo.ts +5 -5
  106. package/src/runtime/layout/getFrameUncollapseInfo.ts +8 -30
  107. package/src/runtime/layout/{getFrameDragZones.ts → getFrameZones.ts} +4 -4
  108. package/src/runtime/layout/getUpdateWindowSizeInfo.ts +16 -22
  109. package/src/runtime/layout/{getWindowDragZones.ts → getWindowZones.ts} +1 -1
  110. package/src/runtime/layout/getZones.ts +48 -0
  111. package/src/runtime/layout/index.ts +6 -3
  112. package/src/runtime/{drag/DragActionHandler.ts → move/ActionHandler.ts} +44 -42
  113. package/src/runtime/{drag → move}/CloseAction.ts +39 -36
  114. package/src/runtime/{drag → move}/FrameDragAction.ts +36 -35
  115. package/src/runtime/{drag/DragDirectionStore.ts → move/MoveDirectionStore.ts} +10 -10
  116. package/src/runtime/{drag → move}/SplitAction.ts +56 -53
  117. package/src/runtime/{drag/defaultDragActions.ts → move/createDefaultHandlers.ts} +2 -2
  118. package/src/runtime/types/index.ts +104 -55
  119. package/src/runtime/types/vue.ts +18 -16
  120. package/dist/runtime/drag/defaultDragActions.d.ts +0 -9
  121. package/dist/runtime/drag/defaultDragActions.js +0 -10
  122. package/dist/runtime/layout/getDragZones.d.ts +0 -8
  123. package/dist/runtime/layout/getDragZones.js +0 -32
  124. package/src/runtime/drag/createDefaultHandlers.ts +0 -20
  125. package/src/runtime/layout/getDragZones.ts +0 -48
  126. /package/dist/runtime/{drag → move}/createDefaultHandlers.js +0 -0
@@ -3,7 +3,6 @@ import { keys } from "@alanscodelog/utils/keys"
3
3
  import type { Ref } from "vue"
4
4
  import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"
5
5
 
6
- import { DragDirectionStore } from "../drag/DragDirectionStore.js"
7
6
  import { cloneFrame } from "../helpers/cloneFrame.js"
8
7
  import { getIntersections } from "../helpers/getIntersections.js"
9
8
  import { getVisualEdges } from "../helpers/getVisualEdges.js"
@@ -12,32 +11,14 @@ import { moveEdge } from "../helpers/moveEdge.js"
12
11
  import { toWindowCoord } from "../helpers/toWindowCoord.js"
13
12
  import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
14
13
  import { isPointInRect } from "../layout/isPointInRect.js"
15
- import type { Direction, DragChangeHandler, DragChangeResult, DragState, Edge, EdgeDragStartData, FrameDragStartData, FrameId, IntersectionEntry, LayoutFrame, LayoutWindow, Orientation, Point } from "../types/index.js"
14
+ import { MoveDirectionStore } from "../move/MoveDirectionStore.js"
15
+ import type { ActionHandler, ActionHandlerApplyResult, Direction, Edge, EdgeMoveStartData, FrameId, FrameMoveStartData, IntersectionEntry, LayoutFrame, LayoutWindow, MoveState, 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
- const draggingEdges = ref<Edge[]>([])
21
+ const movingEdges = ref<Edge[]>([])
41
22
 
42
23
  // each entry corresponds to the frames touching the corresponding dragging edge
43
24
  const touchingFrames = ref<Record<string, LayoutFrame>[]>([])
@@ -53,30 +34,31 @@ export function useFrames(
53
34
 
54
35
  const touchingFramesArrays = computed(() => touchingFrames.value.map(entry => Object.values(entry)))
55
36
 
56
- const isDragging = ref<false | "frame" | "edge">(false)
57
- const showDragging = ref(false)
58
- const dragPoint = ref<Point | undefined>()
37
+ const isMoving = ref<false | "frame" | "edge">(false)
38
+ const showMoving = ref(false)
39
+ const movePoint = ref<Point | undefined>()
59
40
 
60
- const dragDirections = ref<Record<Orientation, Direction | undefined>>({} as any)
41
+ const moveDirections = ref<Record<Orientation, Direction | undefined>>({} as any)
61
42
 
62
- let dragStartPoint: Point | undefined
63
- const dragDistance = ref(-1)
43
+ let moveStartPoint: Point | undefined
44
+ const moveDistance = ref(-1)
64
45
 
65
- const draggingIntersection = ref<IntersectionEntry | undefined>(undefined)
66
- const isDraggingFromWindowEdge = ref<boolean>(false)
46
+ const movingIntersection = ref<IntersectionEntry | undefined>(undefined)
47
+ const isMovingFromWindowEdge = ref<boolean>(false)
67
48
 
68
- const frameDragFrameId = ref<FrameId | undefined>()
49
+ const movingFrameId = ref<FrameId | undefined>()
50
+ const eventContext = ref<Record<string, unknown> | undefined>()
69
51
 
70
52
  const frames = computed(() =>
71
- isDragging.value && showDragging.value
53
+ isMoving.value && showMoving.value
72
54
  ? { ...win.value.frames, ...allTouchingFrames.value }
73
55
  : win.value.frames
74
56
  )
75
57
 
76
- const dragHoveredFrame = computed(() => {
77
- if (isDragging.value) {
58
+ const moveHoveredFrame = computed(() => {
59
+ if (isMoving.value) {
78
60
  for (const id of keys(frames.value)) {
79
- if (isPointInRect(frames.value[id], dragPoint.value!)) {
61
+ if (isPointInRect(frames.value[id], movePoint.value!)) {
80
62
  return frames.value[id]
81
63
  }
82
64
  }
@@ -88,100 +70,127 @@ export function useFrames(
88
70
  const intersections = computed(() => getIntersections(visualEdges.value))
89
71
  // avoid expensive calculation of edges when lots of frames are added/removed
90
72
  // all at once (e.g. by clicking on some command many times in a row)
91
- const debounceGetDraggableEdges = debounce((f: LayoutFrame[]) => {
73
+ const debounceGetMoveableEdges = debounce((f: LayoutFrame[]) => {
92
74
  visualEdges.value = getVisualEdges(f, { includeWindowEdges: true })
93
75
  handler.annotateEdges?.(visualEdges.value, f)
94
76
  }, 50, {}) as any
95
77
 
96
- watch([isDragging, frames], () => {
78
+ watch([isMoving, frames], () => {
97
79
  // let request animation force recalc
98
- if (isDragging.value) return
80
+ if (isMoving.value) return
99
81
  // otherwise use more performant debounced version
100
- debounceGetDraggableEdges(Object.values(frames.value))
82
+ debounceGetMoveableEdges(Object.values(frames.value))
101
83
  }, { deep: true })
102
- debounceGetDraggableEdges(Object.values(frames.value))
84
+ debounceGetMoveableEdges(Object.values(frames.value))
103
85
 
104
86
  function forceRecalculateEdges(): void {
105
87
  visualEdges.value = getVisualEdges(Object.values(frames.value), { includeWindowEdges: true })
106
88
  handler.annotateEdges?.(visualEdges.value, Object.values(frames.value))
107
89
  }
108
90
 
109
- const dragDirStore = new DragDirectionStore({
110
- onUpdate: dir => dragDirections.value = dir
91
+ const moveDirStore = new MoveDirectionStore({
92
+ onUpdate: dir => moveDirections.value = dir
111
93
  })
112
94
 
113
95
  const state = computed(() => ({
114
- dragDirections: dragDirections.value,
115
- dragPoint: dragPoint.value,
116
- dragDistance: dragDistance.value,
117
- isDragging: isDragging.value,
118
- showDragging: showDragging.value,
119
- draggingFrameId: frameDragFrameId.value,
120
- draggingEdges: draggingEdges.value,
121
- draggingIntersection: draggingIntersection.value,
96
+ moveDirections: moveDirections.value,
97
+ movePoint: movePoint.value,
98
+ moveDistance: moveDistance.value,
99
+ isMoving: isMoving.value,
100
+ showMoving: showMoving.value,
101
+ movingFrameId: movingFrameId.value,
102
+ movingEdges: movingEdges.value,
103
+ movingIntersection: movingIntersection.value,
122
104
  visualEdges: visualEdges.value,
123
105
  touchingFrames: touchingFrames.value,
124
106
  touchingFramesArrays: touchingFramesArrays.value,
125
107
  frames: frames.value,
126
- dragHoveredFrame: dragHoveredFrame.value,
108
+ moveHoveredFrame: moveHoveredFrame.value,
127
109
  intersections: intersections.value,
128
- isDraggingFromWindowEdge: isDraggingFromWindowEdge.value,
110
+ isMovingFromWindowEdge: isMovingFromWindowEdge.value,
111
+ eventContext: eventContext.value,
129
112
  win: win.value
130
- } satisfies DragState))
113
+ } satisfies MoveState))
131
114
 
132
115
  let controller: AbortController
116
+ let moveResolve: ((result: any) => void) | undefined
117
+ let moveResult: any
133
118
 
134
119
  function resetState(): void {
135
- dragStartPoint = undefined
120
+ moveStartPoint = undefined
121
+
122
+ moveResolve?.(moveResult)
123
+ moveResolve = undefined
124
+ moveResult = undefined
136
125
 
137
- draggingEdges.value = []
138
- draggingIntersection.value = undefined
139
- isDragging.value = false
140
- dragPoint.value = undefined
141
- dragDistance.value = -1
126
+ movingEdges.value = []
127
+ movingIntersection.value = undefined
128
+ isMoving.value = false
129
+ movePoint.value = undefined
130
+ moveDistance.value = -1
142
131
  touchingFrames.value = []
143
- frameDragFrameId.value = undefined
144
- dragDirStore.reset()
145
- showDragging.value = false
132
+ movingFrameId.value = undefined
133
+ eventContext.value = undefined
134
+ moveDirStore.reset()
135
+ showMoving.value = false
146
136
  forceRecalculateEdges()
147
137
  }
148
138
 
149
- function dragStart<T extends "edge" | "frame">(
139
+ function moveStart<T extends "edge" | "frame">(
150
140
  e: PointerEvent,
151
141
  type: T,
152
142
  // someday this will work
153
- data: T extends "edge" ? EdgeDragStartData : FrameDragStartData
154
- ): void {
143
+ data: T extends "edge" ? EdgeMoveStartData : FrameMoveStartData,
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
+ moveResolve = resolve
161
+ })
162
+
155
163
  controller = new AbortController()
156
164
  controller.signal.addEventListener("abort", () => resetState())
157
165
 
158
166
  e.preventDefault()
159
- window.addEventListener("pointermove", dragMove, { signal: controller.signal })
160
- window.addEventListener("pointerup", dragEnd, { signal: controller.signal })
167
+ window.addEventListener(moveEvent, onMove as EventListener, { signal: controller.signal })
168
+ window.addEventListener(endEvent, moveEnd as EventListener, { signal: controller.signal })
161
169
 
162
170
  const point = toWindowCoord(win.value, e)
163
- dragPoint.value = point
164
- dragStartPoint = { ...point }
165
- dragDirStore.update(point)
171
+ movePoint.value = point
172
+ moveStartPoint = { ...point }
173
+ moveDirStore.update(point)
174
+ eventContext.value = context
166
175
 
167
- isDragging.value = type
168
- showDragging.value = true
176
+ isMoving.value = type
177
+ showMoving.value = true
169
178
 
170
179
  if (type === "frame") {
171
- frameDragFrameId.value = (data as FrameDragStartData).frameId
180
+ movingFrameId.value = (data as FrameMoveStartData).frameId
172
181
  } else {
173
- const { edge, intersection } = data as EdgeDragStartData
174
- draggingIntersection.value = intersection
182
+ const { edge, intersection } = data as EdgeMoveStartData
183
+ movingIntersection.value = intersection
175
184
 
176
- draggingEdges.value = edge
177
- ? [edge]
185
+ movingEdges.value = edge
186
+ ? [edge!]
178
187
  : [
179
- ...(draggingIntersection.value?.sharedEdges.horizontal ?? []),
180
- ...(draggingIntersection.value?.sharedEdges.vertical ?? [])
188
+ ...(movingIntersection.value?.sharedEdges.horizontal ?? []),
189
+ ...(movingIntersection.value?.sharedEdges.vertical ?? [])
181
190
  ]
182
191
 
183
192
 
184
- isDraggingFromWindowEdge.value = draggingEdges.value.some(_ => isWindowEdge(_))
193
+ isMovingFromWindowEdge.value = movingEdges.value.some(_ => isWindowEdge(_))
185
194
 
186
195
  const framesArray = Object.values(win.value.frames)
187
196
 
@@ -189,10 +198,10 @@ export function useFrames(
189
198
  // all frames in touchingFrames must be clones
190
199
  // BUT they must be the same clone even if they are referenced by multiple dragging edges
191
200
  const clones = new Map<string, LayoutFrame>()
192
- for (let i = 0; i < draggingEdges.value.length; i++) {
193
- const draggingEdge = draggingEdges.value[i]
201
+ for (let i = 0; i < movingEdges.value.length; i++) {
202
+ const movingEdge = movingEdges.value[i]
194
203
  touchingFrames.value[i] = {}
195
- for (const { frame } of findFramesTouchingEdge(draggingEdge, framesArray)) {
204
+ for (const { frame } of findFramesTouchingEdge(movingEdge, framesArray)) {
196
205
  if (!clones.has(frame.id)) {
197
206
  const clone = cloneFrame(frame)
198
207
  touchingFrames.value[i][frame.id] = clone
@@ -204,35 +213,36 @@ export function useFrames(
204
213
  }
205
214
  }
206
215
 
207
- const res = handler.onDragChange("start", e, state.value, forceRecalculateEdges, cancel)
208
- showDragging.value = res.showDragging ?? true
216
+ const res = handler.onMoveChange("start", e, state.value, forceRecalculateEdges, cancel, resolve)
217
+ showMoving.value = res.showMoving ?? true
218
+ return promise
209
219
  }
210
220
 
211
- function dragMove(e: PointerEvent): void {
221
+ function onMove(e: PointerEvent): void {
212
222
  e.preventDefault()
213
223
  const point = toWindowCoord(win.value, e)
214
- const didChange = dragDirStore.update(point)
215
- dragPoint.value = point
224
+ const didChange = moveDirStore.update(point)
225
+ movePoint.value = point
216
226
  // at least one drag move has happened
217
- dragDistance.value = 0
218
- if (dragStartPoint) {
219
- dragDistance.value = Math.sqrt(
220
- Math.pow(point.x - dragStartPoint.x, 2) + Math.pow(point.y - dragStartPoint.y, 2)
227
+ moveDistance.value = 0
228
+ if (moveStartPoint) {
229
+ moveDistance.value = Math.sqrt(
230
+ Math.pow(point.x - moveStartPoint.x, 2) + Math.pow(point.y - moveStartPoint.y, 2)
221
231
  )
222
232
  }
223
233
  if (!didChange) return
224
- const res = handler.onDragChange("move", e, state.value, forceRecalculateEdges, cancel)
234
+ const res = handler.onMoveChange("move", e, state.value, forceRecalculateEdges, cancel, resolve)
225
235
 
226
236
 
227
- showDragging.value = res.showDragging ?? true
237
+ showMoving.value = res.showMoving ?? true
228
238
  if (!res.updateEdges) return
229
239
 
230
- if (isDragging.value === "edge") {
240
+ if (isMoving.value === "edge") {
231
241
  requestAnimationFrame(() => {
232
- for (let i = 0; i < draggingEdges.value.length; i++) {
233
- const draggingEdge = draggingEdges.value[i]
234
- if (draggingEdge) {
235
- moveEdge(touchingFramesArrays.value[i], draggingEdge, point)
242
+ for (let i = 0; i < movingEdges.value.length; i++) {
243
+ const movingEdge = movingEdges.value[i]
244
+ if (movingEdge) {
245
+ moveEdge(touchingFramesArrays.value[i], movingEdge, point)
236
246
  }
237
247
  }
238
248
  forceRecalculateEdges()
@@ -240,28 +250,37 @@ export function useFrames(
240
250
  }
241
251
  }
242
252
 
243
- function dragEnd(e?: PointerEvent, { apply = true }: { apply?: boolean } = {}): void {
253
+ function moveEnd(e?: PointerEvent, { apply = true }: Partial<Pick<ActionHandlerApplyResult, "apply">> = {}): void {
244
254
  if (e) {
245
255
  const point = toWindowCoord(win.value, e)
246
- dragPoint.value = point
256
+ movePoint.value = point
247
257
  }
248
258
 
249
- const doApply = apply && handler.onDragApply(state.value, forceRecalculateEdges)
250
- if (doApply) {
251
- for (const frame of touchingFramesArrays.value.flat()) {
252
- win!.value.frames[frame.id] = frame
259
+ if (apply) {
260
+ const applyResult = handler.onMoveApply(state.value, forceRecalculateEdges)
261
+ moveResult = applyResult.result
262
+ if (applyResult.apply) {
263
+ for (const frame of touchingFramesArrays.value.flat()) {
264
+ win!.value.frames[frame.id] = frame
265
+ }
253
266
  }
254
267
  }
255
268
 
256
- handler.onDragChange("end", e, state.value, forceRecalculateEdges, cancel)
269
+ handler.onMoveChange("end", e, state.value, forceRecalculateEdges, undefined, undefined)
257
270
 
258
271
  // this can get called from elsewhere
259
- // also takes care of cleanup
272
+ // also takes care of cleanup nd resolving promise
260
273
  controller?.abort()
261
274
  }
275
+
262
276
  function cancel(): void {
263
- dragEnd(undefined, { apply: false })
277
+ moveEnd(undefined, { apply: false })
264
278
  }
279
+ function resolve({ apply, result: value }: ActionHandlerApplyResult): void {
280
+ moveResult = value
281
+ moveEnd(undefined, { apply })
282
+ }
283
+
265
284
  const keydownController = new AbortController()
266
285
  const wrappedKeydownHandler = (e: KeyboardEvent): void => {
267
286
  handler.eventHandler(e, state.value, forceRecalculateEdges)
@@ -277,25 +296,26 @@ export function useFrames(
277
296
  })
278
297
 
279
298
  return {
280
- dragStart,
281
- dragEnd,
299
+ moveStart,
300
+ moveEnd,
282
301
  cancel,
283
- dragMove,
284
- dragDirections,
285
- dragPoint,
286
- isDragging,
287
- draggingEdges,
288
- draggingIntersection,
302
+ onMove,
303
+ moveDirections,
304
+ movePoint,
305
+ isMoving,
306
+ movingEdges,
307
+ movingIntersection,
289
308
  visualEdges,
290
309
  touchingFrames,
291
310
  touchingFramesArrays,
292
311
  frames,
293
- dragHoveredFrame,
312
+ moveHoveredFrame,
294
313
  intersections,
295
- isDraggingFromWindowEdge,
314
+ isMovingFromWindowEdge,
296
315
  forceRecalculateEdges,
297
316
  state,
298
- showDragging,
299
- frameDragFrameId
317
+ showMoving,
318
+ movingFrameId,
319
+ actionHandler: handler
300
320
  }
301
321
  }
@@ -10,7 +10,7 @@
10
10
  v-if="win"
11
11
  :frames="frames!"
12
12
  :win="win"
13
- :dragActionHandler="dragActionHandler"
13
+ :actionHandler="actionHandler"
14
14
  />
15
15
 
16
16
  <LayoutWindow
@@ -33,8 +33,8 @@
33
33
  :textHints="textHints"
34
34
  textHintsTeleportTo="#status-bar"
35
35
  v-model:win="win"
36
- @is-showing-drag="isShowingDrag = $event"
37
- @drag-state="dragState = $event"
36
+ @is-showing-move="isShowingMove = $event"
37
+ @move-state="moveState = $event"
38
38
  >
39
39
  <LayoutFrame class="
40
40
  flex
@@ -163,7 +163,7 @@ import LayoutIntersections from "../components/LayoutIntersections.vue"
163
163
  import LayoutEdgesActiveFrame from "../components/LayoutEdgesActiveFrame.vue"
164
164
  import LayoutDragEdges from "../components/LayoutDragEdges.vue"
165
165
  import LayoutIntersectionHandle from "../components/LayoutIntersectionHandle.vue"
166
- import type { DragState } from "../types/index.js"
166
+ import type { MoveState } from "../types/index.js"
167
167
  import { applyFrameChanges } from "../layout/applyFrameChanges.js"
168
168
  import { debugFrame } from "../layout/debugFrame.js"
169
169
  import { getFrameCollapseInfo } from "../layout/getFrameCollapseInfo.js"
@@ -179,7 +179,7 @@ import { settings } from "../settings.js"
179
179
  import type { EdgeSide, Layout, Pos, Size } from "../types/index.js"
180
180
  import { throwIfError } from "@alanscodelog/utils/throwIfError"
181
181
  import { useTemplateRef } from "vue"
182
- import { DragActionHandler } from "../drag/DragActionHandler.js"
182
+ import { ActionHandler } from "../move/ActionHandler.js"
183
183
  import LayoutDragEdgeHandle from "../components/LayoutDragEdgeHandle.vue"
184
184
  import LayoutDragEdgeVisible from "../components/LayoutDragEdgeVisible.vue"
185
185
  import LayoutIntersectionVisible from "../components/LayoutIntersectionVisible.vue"
@@ -228,30 +228,30 @@ function layoutInitialize(layout: Layout, { defaultPos, defaultSize }: {
228
228
  }
229
229
 
230
230
  // whether layout window is showing the edge beneath the mouse
231
- // as determined by the DragActionHandler in LayoutWindow
232
- const isShowingDrag = ref(false)
231
+ // as determined by the ActionHandler in LayoutWindow
232
+ const isShowingMove = ref(false)
233
233
  // drag state as returned by useFrames in LayoutWindow
234
- const dragState = ref<DragState | undefined>(undefined)
234
+ const moveState = ref<MoveState | undefined>(undefined)
235
235
 
236
236
  function handleUndock(frameId: string) {
237
237
  const changes = throwIfError(getFrameUndockInfo(win.value!, frameId))
238
- DragActionHandler.debugState("undock", "before", dragState.value!, {}, undefined)
238
+ ActionHandler.debugState("undock", "before", moveState.value!, {}, undefined)
239
239
  applyFrameChanges(win.value!, changes)
240
- DragActionHandler.debugState("undock", "after", dragState.value!, {}, undefined)
240
+ ActionHandler.debugState("undock", "after", moveState.value!, {}, undefined)
241
241
  }
242
242
 
243
243
  function handleCollapse(frameId: string) {
244
244
  const changes = throwIfError(getFrameCollapseInfo(win.value!, frameId))
245
- DragActionHandler.debugState("collapse", "before", dragState.value!, {}, undefined)
245
+ ActionHandler.debugState("collapse", "before", moveState.value!, {}, undefined)
246
246
  applyFrameChanges(win.value!, changes)
247
- DragActionHandler.debugState("collapse", "after", dragState.value!, {}, undefined)
247
+ ActionHandler.debugState("collapse", "after", moveState.value!, {}, undefined)
248
248
  }
249
249
 
250
250
  function handleUncollapse(frameId: string) {
251
251
  const changes = throwIfError(getFrameUncollapseInfo(win.value!, frameId))
252
- DragActionHandler.debugState("uncollapse", "before", dragState.value!, {}, undefined)
252
+ ActionHandler.debugState("uncollapse", "before", moveState.value!, {}, undefined)
253
253
  applyFrameChanges(win.value!, changes)
254
- DragActionHandler.debugState("uncollapse", "after", dragState.value!, {}, undefined)
254
+ ActionHandler.debugState("uncollapse", "after", moveState.value!, {}, undefined)
255
255
  }
256
256
 
257
257
  const collapsedDocks = computed(() => {
@@ -264,13 +264,13 @@ const collapsedDocks = computed(() => {
264
264
  return sides
265
265
  })
266
266
 
267
- const dragActionHandler = computed(() => layoutComponent.value?.dragActionHandler)
267
+ const actionHandler = computed(() => layoutComponent.value?.actionHandler)
268
268
 
269
269
  const textHints = computed(() => {
270
- const isDragging = dragState.value?.isDragging
271
- const textHints = dragActionHandler.value?.textHints ?? {actions:[], errors:[]}
270
+ const isMoving = moveState.value?.isMoving
271
+ const textHints = actionHandler.value?.textHints ?? {actions:[], errors:[]}
272
272
  return [
273
- ...(!isDragging ? [{classes:"", text:"Drag from an edge to create a new frame."}] : []),
273
+ ...(!isMoving ? [{classes:"", text:"Drag from an edge to create a new frame."}] : []),
274
274
  ...textHints.errors.map((_: string) => ({classes:"text-red-500", text:_})),
275
275
  ...textHints.actions.map((_: string) => ({ text:_})),
276
276
  ]
@@ -25,7 +25,7 @@
25
25
  <WButton class="flex-1" @click="copyState">Copy State</WButton>
26
26
  <WCheckbox v-model="renameFrames">Easy Ids</WCheckbox>
27
27
  </div>
28
- <label class="flex flex-col gap-2 text-sm" v-if="dragActionHandler">
28
+ <label class="flex flex-col gap-2 text-sm" v-if="actionHandler">
29
29
  <span>Plugin Debug Logs (true | debug path):</span>
30
30
  <WSimpleInput v-model="debugKey" />
31
31
  </label>
@@ -50,13 +50,13 @@ import { settings } from "../settings.js"
50
50
  import type { LayoutFrame, LayoutWindow } from "../types/index.js"
51
51
  import { throwIfError } from "@alanscodelog/utils/throwIfError";
52
52
  import { walk } from "@alanscodelog/utils/walk"
53
- import type { DragActionHandler } from "../drag/DragActionHandler.js"
53
+ import type { ActionHandler } from "../move/ActionHandler.js"
54
54
  import { rotateLayout } from "../helpers/rotateFrames.js"
55
55
 
56
56
  const props = defineProps<{
57
57
  win: LayoutWindow
58
58
  frames: LayoutFrame[],
59
- dragActionHandler?: DragActionHandler<any>
59
+ actionHandler?: ActionHandler<any>
60
60
  }>()
61
61
 
62
62
  const showDevActions = ref(false)
@@ -112,14 +112,14 @@ function copyState() {
112
112
 
113
113
  const debugKey = ref(import.meta.dev ? "state.win.frames" : "false")
114
114
  watch(debugKey, () => {
115
- if (!props.dragActionHandler) return
115
+ if (!props.actionHandler) return
116
116
  const value = debugKey.value === "true"
117
117
  ? true
118
118
  : debugKey.value === "false"
119
119
  ? false
120
120
  : debugKey.value
121
121
 
122
- for (const plugin of Object.values(props.dragActionHandler.actions)) {
122
+ for (const plugin of Object.values(props.actionHandler.actions)) {
123
123
  plugin.debug = value
124
124
  }
125
125
  })
@@ -5,3 +5,7 @@
5
5
 
6
6
  /* Only needed for the dev playground: the demo App.vue lives outside the Vite project root, so Tailwind's auto-scan doesn't find the [&.deco-...] classes it defines. */
7
7
  @source "../../../src/runtime/demo";
8
+
9
+ button {
10
+ cursor: pointer;
11
+ }
@@ -6,10 +6,10 @@
6
6
  * Accepts scaled coordinates.
7
7
  */
8
8
 
9
- import type { DragZone } from "../types/index.js"
9
+ import type { Zone } from "../types/index.js"
10
10
 
11
11
  export function createZoneSideClipPath(
12
- zone: DragZone,
12
+ zone: Zone,
13
13
  { frameEdgePx, windowEdgePx }: { frameEdgePx: number, windowEdgePx: number }
14
14
  ): string | undefined {
15
15
  const side = zone.side
@@ -0,0 +1,30 @@
1
+ import { settings } from "../settings.js"
2
+ import type { EdgeSide, LayoutFrame } from "../types/index.js"
3
+
4
+ /**
5
+ * Checks which window edges a frame touches and how.
6
+ *
7
+ * @returns Record mapping touched sides to `"full"` (spans the entire edge) or `"partial"` (touches but doesn't span fully). Only touched sides are included as keys.
8
+ */
9
+ export function findEdgesTouchingWindow(frame: LayoutFrame): Partial<Record<EdgeSide, "full" | "partial">> {
10
+ const maxInt = settings.maxInt
11
+ const result: Partial<Record<EdgeSide, "full" | "partial">> = {}
12
+
13
+ const spansVertical = frame.y === 0 && frame.y + frame.height === maxInt
14
+ const spansHorizontal = frame.x === 0 && frame.x + frame.width === maxInt
15
+
16
+ if (frame.x === 0) {
17
+ result.left = spansVertical ? "full" : "partial"
18
+ }
19
+ if (frame.x + frame.width === maxInt) {
20
+ result.right = spansVertical ? "full" : "partial"
21
+ }
22
+ if (frame.y === 0) {
23
+ result.top = spansHorizontal ? "full" : "partial"
24
+ }
25
+ if (frame.y + frame.height === maxInt) {
26
+ result.bottom = spansHorizontal ? "full" : "partial"
27
+ }
28
+
29
+ return result
30
+ }
@@ -1,4 +1,4 @@
1
- import { findDraggableEdge } from "./findDraggableEdge.js"
1
+ import { findMoveableEdge } from "./findMoveableEdge.js"
2
2
  import { frameToEdges } from "./frameToEdges.js"
3
3
  import { isWindowEdge } from "./isWindowEdge.js"
4
4
  import { sideToOrientation } from "./sideToOrientation.js"
@@ -8,10 +8,10 @@ import type {
8
8
  EdgeSide, LayoutFrame
9
9
  } from "../types/index.js"
10
10
 
11
- export function findFrameDraggableEdges(
11
+ export function findFrameMoveableEdges(
12
12
  frame: LayoutFrame,
13
13
  edges: Edge[],
14
- /** See {@link findDraggableEdge} */
14
+ /** See {@link findMoveableEdge} */
15
15
  exact: boolean = true,
16
16
  sides: EdgeSide[] = ["left", "right", "top", "bottom"]
17
17
  ): { edge: Edge, side: EdgeSide }[] | undefined {
@@ -23,7 +23,7 @@ export function findFrameDraggableEdges(
23
23
  const isWinEdge = isWindowEdge(edge, edgeDirection)
24
24
 
25
25
  if (isWinEdge) continue
26
- const maybeEdge = findDraggableEdge(edge, edges, exact, edgeDirection)
26
+ const maybeEdge = findMoveableEdge(edge, edges, exact, edgeDirection)
27
27
 
28
28
  if (maybeEdge) res.push({ edge: maybeEdge, side })
29
29
  }
@@ -4,7 +4,7 @@ import { isEdgeEqual } from "./isEdgeEqual.js"
4
4
 
5
5
  import type { Edge, Orientation } from "../types/index.js"
6
6
 
7
- export function findDraggableEdge(
7
+ export function findMoveableEdge(
8
8
  edge: Edge,
9
9
  edges: Edge[],
10
10
  /** Whether the edge must match exactly and does not "contain/touch" another frame. */