@witchcraft/layout 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/composables/useFrames.d.ts +6 -4
- package/dist/runtime/composables/useFrames.js +8 -4
- package/dist/runtime/move/ActionHandler.d.ts +11 -11
- package/dist/runtime/move/ActionHandler.js +23 -20
- package/dist/runtime/move/CloseAction.d.ts +3 -2
- package/dist/runtime/move/CloseAction.js +9 -8
- package/dist/runtime/move/FrameDragAction.d.ts +3 -2
- package/dist/runtime/move/FrameDragAction.js +6 -7
- package/dist/runtime/move/SplitAction.d.ts +3 -2
- package/dist/runtime/move/SplitAction.js +14 -8
- package/dist/runtime/types/index.d.ts +49 -36
- package/dist/runtime/types/vue.d.ts +5 -3
- package/package.json +1 -1
- package/src/module.ts +1 -1
- package/src/runtime/composables/useFrames.ts +16 -10
- package/src/runtime/move/ActionHandler.ts +40 -36
- package/src/runtime/move/CloseAction.ts +12 -10
- package/src/runtime/move/FrameDragAction.ts +9 -9
- package/src/runtime/move/SplitAction.ts +17 -10
- package/src/runtime/types/index.ts +63 -39
- package/src/runtime/types/vue.ts +3 -3
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -20,7 +20,7 @@ const module$1 = defineNuxtModule({
|
|
|
20
20
|
getContents: () => [
|
|
21
21
|
`@source "${resolve("runtime/components")}";`,
|
|
22
22
|
// the drag actions handlers and utils they use add some styles
|
|
23
|
-
`@source "${resolve("runtime/
|
|
23
|
+
`@source "${resolve("runtime/move")}";`,
|
|
24
24
|
`@source "${resolve("runtime/utils/createSplitDecoShapes")}";`
|
|
25
25
|
].join("\n")
|
|
26
26
|
});
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Ref } from "vue";
|
|
2
|
-
import type {
|
|
3
|
-
export declare function useFrames(win: Ref<LayoutWindow>, handler:
|
|
2
|
+
import type { EdgeMoveStartData, FrameMoveStartData, IActionHandler, IntersectionEntry, LayoutFrame, LayoutWindow } from "../types/index.js";
|
|
3
|
+
export declare function useFrames(win: Ref<LayoutWindow>, handler: IActionHandler): {
|
|
4
4
|
moveStart: <T extends "edge" | "frame">(e: PointerEvent, type: T, data: T extends "edge" ? EdgeMoveStartData : FrameMoveStartData, { moveEvent, endEvent, context }?: {
|
|
5
5
|
moveEvent?: string;
|
|
6
6
|
endEvent?: string;
|
|
7
7
|
context?: Record<string, unknown>;
|
|
8
8
|
}) => Promise<any>;
|
|
9
|
-
moveEnd: (e?: PointerEvent, { apply }?:
|
|
9
|
+
moveEnd: (e?: PointerEvent, { apply }?: {
|
|
10
|
+
apply?: boolean;
|
|
11
|
+
}) => void;
|
|
10
12
|
cancel: () => void;
|
|
11
13
|
onMove: (e: PointerEvent) => void;
|
|
12
14
|
moveDirections: Ref<{
|
|
@@ -1049,5 +1051,5 @@ export declare function useFrames(win: Ref<LayoutWindow>, handler: ActionHandler
|
|
|
1049
1051
|
}>;
|
|
1050
1052
|
showMoving: Ref<boolean, boolean>;
|
|
1051
1053
|
movingFrameId: Ref<string | undefined, string | undefined>;
|
|
1052
|
-
actionHandler:
|
|
1054
|
+
actionHandler: IActionHandler;
|
|
1053
1055
|
};
|
|
@@ -102,6 +102,7 @@ export function useFrames(win, handler) {
|
|
|
102
102
|
moveDirStore.reset();
|
|
103
103
|
showMoving.value = false;
|
|
104
104
|
forceRecalculateEdges();
|
|
105
|
+
handler.onMoveEnded();
|
|
105
106
|
}
|
|
106
107
|
function moveStart(e, type, data, {
|
|
107
108
|
moveEvent = "pointermove",
|
|
@@ -169,10 +170,13 @@ export function useFrames(win, handler) {
|
|
|
169
170
|
);
|
|
170
171
|
}
|
|
171
172
|
if (!didChange) return;
|
|
172
|
-
|
|
173
|
+
onMoveChange(e, "move", point);
|
|
174
|
+
}
|
|
175
|
+
function onMoveChange(e, type, point) {
|
|
176
|
+
const res = handler.onMoveChange(type, e, state.value, forceRecalculateEdges, cancel, type === "end" ? void 0 : resolve);
|
|
173
177
|
showMoving.value = res.showMoving ?? true;
|
|
174
178
|
if (!res.updateEdges) return;
|
|
175
|
-
if (isMoving.value === "edge") {
|
|
179
|
+
if (isMoving.value === "edge" && point) {
|
|
176
180
|
requestAnimationFrame(() => {
|
|
177
181
|
for (let i = 0; i < movingEdges.value.length; i++) {
|
|
178
182
|
const movingEdge = movingEdges.value[i];
|
|
@@ -189,16 +193,16 @@ export function useFrames(win, handler) {
|
|
|
189
193
|
const point = toWindowCoord(win.value, e);
|
|
190
194
|
movePoint.value = point;
|
|
191
195
|
}
|
|
196
|
+
onMoveChange(e, "end", movePoint.value);
|
|
192
197
|
if (apply) {
|
|
193
198
|
const applyResult = handler.onMoveApply(state.value, forceRecalculateEdges);
|
|
194
199
|
moveResult = applyResult.result;
|
|
195
|
-
if (applyResult.
|
|
200
|
+
if (applyResult.updateEdges) {
|
|
196
201
|
for (const frame of touchingFramesArrays.value.flat()) {
|
|
197
202
|
win.value.frames[frame.id] = frame;
|
|
198
203
|
}
|
|
199
204
|
}
|
|
200
205
|
}
|
|
201
|
-
handler.onMoveChange("end", e, state.value, forceRecalculateEdges, void 0, void 0);
|
|
202
206
|
controller?.abort();
|
|
203
207
|
}
|
|
204
208
|
function cancel() {
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { type RecordFromArray } from "@alanscodelog/utils";
|
|
2
|
-
import type { ActionHandlerApplyResult, Edge, IAction, LayoutFrame, LayoutShape,
|
|
2
|
+
import type { ActionHandlerApplyResult, ActionResolve, Edge, IAction, IActionHandler, LayoutFrame, LayoutShape, MoveChangeResult, MoveState } from "../types/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Handles the lifecycle of a drag actions {@link IAction} and provides additional hooks.
|
|
5
5
|
*
|
|
6
6
|
* The first action instance that can handle the request is passed control of the event handlers until the request changes.
|
|
7
7
|
*/
|
|
8
|
-
export declare class ActionHandler<TRawActions extends IAction[], TActions extends RecordFromArray<TRawActions, "name"> = RecordFromArray<TRawActions, "name">> {
|
|
8
|
+
export declare class ActionHandler<TRawActions extends IAction[], TActions extends RecordFromArray<TRawActions, "name"> = RecordFromArray<TRawActions, "name">> implements IActionHandler {
|
|
9
9
|
activeAction?: keyof TActions;
|
|
10
10
|
actions: TActions;
|
|
11
11
|
eventCanceller: ((e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void) | undefined;
|
|
12
12
|
boundCancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void;
|
|
13
|
-
defaultOnMoveChange:
|
|
13
|
+
defaultOnMoveChange: IAction["onMoveChange"];
|
|
14
14
|
hooks: {
|
|
15
15
|
/** Called while dragging during dragChange events. You can use this to update the dragging edges. */
|
|
16
16
|
onRecalculate?: () => void;
|
|
@@ -25,7 +25,8 @@ export declare class ActionHandler<TRawActions extends IAction[], TActions exten
|
|
|
25
25
|
/** Called when the drag action ends either because it was completed or cancelled. */
|
|
26
26
|
onEnd?: (context: {
|
|
27
27
|
cancelled: boolean;
|
|
28
|
-
|
|
28
|
+
wasApplied: boolean;
|
|
29
|
+
result?: any;
|
|
29
30
|
}) => void;
|
|
30
31
|
};
|
|
31
32
|
/** All action shapes merged into a single array. If using vue you can set this to a reactive array for reactivity. */
|
|
@@ -37,19 +38,18 @@ export declare class ActionHandler<TRawActions extends IAction[], TActions exten
|
|
|
37
38
|
};
|
|
38
39
|
constructor(actions: TRawActions, hooks?: ActionHandler<TRawActions, TActions>["hooks"],
|
|
39
40
|
/**
|
|
40
|
-
* Default onMoveChange handler for when no action can handle the request.
|
|
41
|
-
*
|
|
42
|
-
* Should return true to allow the edges to be moved, or false to prevent it.
|
|
41
|
+
* Default onMoveChange handler for when no action can handle the request. See {@link IAction.onMoveChange}.
|
|
43
42
|
*
|
|
44
43
|
* The default prevents movement when the edge is a window edge and when the edge is touching a collapsed frame.
|
|
45
44
|
*/
|
|
46
|
-
defaultOnMoveChange?:
|
|
45
|
+
defaultOnMoveChange?: IAction["onMoveChange"]);
|
|
47
46
|
eventHandler(e: KeyboardEvent | PointerEvent, state: MoveState, forceRecalculateEdges: () => void): undefined;
|
|
48
|
-
onMoveChange<T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: MoveState, forceRecalculateEdges: () => void, cancel:
|
|
49
|
-
setTextHints(type: "start" | "move" | "end"): void;
|
|
50
|
-
annotateEdges(edges: Edge[], frames: LayoutFrame[]): void;
|
|
47
|
+
onMoveChange<T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: MoveState, forceRecalculateEdges: () => void, cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void, resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)): MoveChangeResult;
|
|
51
48
|
onMoveApply(state: MoveState, forceRecalculateEdges: () => void): ActionHandlerApplyResult;
|
|
49
|
+
onMoveEnded(): void;
|
|
52
50
|
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void;
|
|
51
|
+
setTextHints(type: "start" | "move" | "end"): void;
|
|
52
|
+
annotateEdges(edges: Edge[], frames: LayoutFrame[]): void;
|
|
53
53
|
static debugState(pluginName: string, type: "before" | "after" | string, state: MoveState, pluginState?: Record<string, any>,
|
|
54
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. */
|
|
55
55
|
key?: string | boolean): void;
|
|
@@ -82,11 +82,31 @@ export class ActionHandler {
|
|
|
82
82
|
this.setTextHints(type);
|
|
83
83
|
const res = this.defaultOnMoveChange(type, e, state, forceRecalculateEdges, this.boundCancel, resolve);
|
|
84
84
|
this.shapes.splice(0, this.shapes.length, ...res.shapes);
|
|
85
|
-
if (type === "end") {
|
|
86
|
-
this.activeAction = void 0;
|
|
87
|
-
}
|
|
88
85
|
return res;
|
|
89
86
|
}
|
|
87
|
+
onMoveApply(state, forceRecalculateEdges) {
|
|
88
|
+
if (this.activeAction) {
|
|
89
|
+
const res = this.actions[this.activeAction].onMoveApply(state, forceRecalculateEdges);
|
|
90
|
+
this.hooks.onEnd?.({ cancelled: false, wasApplied: res.wasApplied, result: res.result });
|
|
91
|
+
return res;
|
|
92
|
+
}
|
|
93
|
+
this.hooks.onEnd?.({ cancelled: false, wasApplied: false });
|
|
94
|
+
return { updateEdges: true, result: void 0 };
|
|
95
|
+
}
|
|
96
|
+
onMoveEnded() {
|
|
97
|
+
if (this.activeAction) {
|
|
98
|
+
this.actions[this.activeAction].onMoveEnded();
|
|
99
|
+
}
|
|
100
|
+
this.activeAction = void 0;
|
|
101
|
+
}
|
|
102
|
+
cancel(e, state) {
|
|
103
|
+
if (this.activeAction) {
|
|
104
|
+
this.actions[this.activeAction].cancel(e, state);
|
|
105
|
+
}
|
|
106
|
+
this.activeAction = void 0;
|
|
107
|
+
this.eventCanceller?.(e, state);
|
|
108
|
+
this.hooks.onEnd?.({ cancelled: true, wasApplied: false });
|
|
109
|
+
}
|
|
90
110
|
setTextHints(type) {
|
|
91
111
|
this.textHints.actions = [];
|
|
92
112
|
this.textHints.errors = [];
|
|
@@ -118,23 +138,6 @@ export class ActionHandler {
|
|
|
118
138
|
}
|
|
119
139
|
}
|
|
120
140
|
}
|
|
121
|
-
onMoveApply(state, forceRecalculateEdges) {
|
|
122
|
-
if (this.activeAction) {
|
|
123
|
-
const res = this.actions[this.activeAction].onMoveApply(state, forceRecalculateEdges);
|
|
124
|
-
this.hooks.onEnd?.({ cancelled: false, applied: res });
|
|
125
|
-
return { apply: res, result: void 0 };
|
|
126
|
-
}
|
|
127
|
-
this.hooks.onEnd?.({ cancelled: false, applied: false });
|
|
128
|
-
return { apply: true, result: void 0 };
|
|
129
|
-
}
|
|
130
|
-
cancel(e, state) {
|
|
131
|
-
if (this.activeAction) {
|
|
132
|
-
this.actions[this.activeAction].cancel(e, state);
|
|
133
|
-
}
|
|
134
|
-
this.activeAction = void 0;
|
|
135
|
-
this.eventCanceller?.(e, state);
|
|
136
|
-
this.hooks.onEnd?.({ cancelled: true, applied: false });
|
|
137
|
-
}
|
|
138
141
|
static debugState(pluginName, type, state, pluginState = {}, key) {
|
|
139
142
|
if (key === false) return;
|
|
140
143
|
let res = { state, pluginState };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getCloseFrameInfo } from "../layout/getCloseFrameInfo.js";
|
|
2
|
-
import type { ActionChangeResult, CloseDeco, IAction, MoveState } from "../types/index.js";
|
|
2
|
+
import type { ActionApplyResult, ActionChangeResult, CloseDeco, IAction, MoveState } from "../types/index.js";
|
|
3
3
|
import type { KnownError } from "../utils/KnownError.js";
|
|
4
4
|
export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError>;
|
|
5
5
|
export declare class CloseAction implements IAction {
|
|
@@ -53,6 +53,7 @@ export declare class CloseAction implements IAction {
|
|
|
53
53
|
};
|
|
54
54
|
canHandleRequest(e: PointerEvent | KeyboardEvent, state: MoveState): boolean;
|
|
55
55
|
onMoveChange(type: "start" | "end" | "move", _e: PointerEvent | undefined, state: MoveState): ActionChangeResult;
|
|
56
|
-
onMoveApply(state: MoveState):
|
|
56
|
+
onMoveApply(state: MoveState): ActionApplyResult;
|
|
57
57
|
cancel(): void;
|
|
58
|
+
onMoveEnded(): void;
|
|
58
59
|
}
|
|
@@ -99,10 +99,6 @@ export class CloseAction {
|
|
|
99
99
|
return false;
|
|
100
100
|
}
|
|
101
101
|
onMoveChange(type, _e, state) {
|
|
102
|
-
if (type === "end") {
|
|
103
|
-
this.reset();
|
|
104
|
-
return { shapes: [] };
|
|
105
|
-
}
|
|
106
102
|
if (state.moveDistance <= this.minDragDistance) {
|
|
107
103
|
return { updateEdges: false, shapes: [] };
|
|
108
104
|
}
|
|
@@ -152,7 +148,10 @@ export class CloseAction {
|
|
|
152
148
|
}
|
|
153
149
|
}
|
|
154
150
|
const decos = this._getDecos(state);
|
|
155
|
-
this.state.lastReturn = {
|
|
151
|
+
this.state.lastReturn = {
|
|
152
|
+
updateEdges: !isMovingFromWindowEdge,
|
|
153
|
+
shapes: type === "end" ? [] : decos.flatMap((_) => _.shapes)
|
|
154
|
+
};
|
|
156
155
|
return this.state.lastReturn;
|
|
157
156
|
}
|
|
158
157
|
onMoveApply(state) {
|
|
@@ -165,12 +164,14 @@ export class CloseAction {
|
|
|
165
164
|
if (this.debug) {
|
|
166
165
|
ActionHandler.debugState(this.name, "after", state, this.state, this.debug);
|
|
167
166
|
}
|
|
168
|
-
return true;
|
|
167
|
+
return { updateEdges: false, wasApplied: true };
|
|
169
168
|
}
|
|
170
|
-
return false;
|
|
169
|
+
return { updateEdges: true, wasApplied: false };
|
|
171
170
|
}
|
|
172
171
|
cancel() {
|
|
173
|
-
this.reset();
|
|
174
172
|
this.hooks.onCancel?.();
|
|
175
173
|
}
|
|
174
|
+
onMoveEnded() {
|
|
175
|
+
this.reset();
|
|
176
|
+
}
|
|
176
177
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionChangeResult, FrameDeco, IAction, LayoutChange, MoveState, Zone } from "../types/index.js";
|
|
1
|
+
import type { ActionApplyResult, ActionChangeResult, FrameDeco, IAction, LayoutChange, MoveState, Zone } from "../types/index.js";
|
|
2
2
|
import type { KnownError } from "../utils/KnownError.js";
|
|
3
3
|
export declare class FrameDragAction implements IAction {
|
|
4
4
|
name: "frameDrag";
|
|
@@ -45,6 +45,7 @@ export declare class FrameDragAction implements IAction {
|
|
|
45
45
|
getDecos(matchedZone: Zone | undefined, state: MoveState, result: LayoutChange<"split" | "swap" | "rearrange" | "dock"> | KnownError | undefined): FrameDeco[];
|
|
46
46
|
canHandleRequest(e: PointerEvent | KeyboardEvent, state: MoveState): boolean;
|
|
47
47
|
onMoveChange<T extends "start" | "move" | "end">(type: T, _e: PointerEvent | undefined, state: MoveState): ActionChangeResult;
|
|
48
|
-
onMoveApply(state: MoveState):
|
|
48
|
+
onMoveApply(state: MoveState): ActionApplyResult;
|
|
49
|
+
onMoveEnded(): void;
|
|
49
50
|
cancel(): void;
|
|
50
51
|
}
|
|
@@ -94,10 +94,6 @@ export class FrameDragAction {
|
|
|
94
94
|
return false;
|
|
95
95
|
}
|
|
96
96
|
onMoveChange(type, _e, state) {
|
|
97
|
-
if (type === "end") {
|
|
98
|
-
this.reset();
|
|
99
|
-
return { shapes: [] };
|
|
100
|
-
}
|
|
101
97
|
if (state.moveDistance <= this.minDragDistance) {
|
|
102
98
|
return { updateEdges: false, shapes: [], showMoving: false };
|
|
103
99
|
}
|
|
@@ -119,7 +115,7 @@ export class FrameDragAction {
|
|
|
119
115
|
this.setTextHints(this.state.lastReturn);
|
|
120
116
|
const decos = this.getDecos(matchedZone, state, this.state.lastReturn);
|
|
121
117
|
return {
|
|
122
|
-
shapes: decos.flatMap((_) => _.shapes),
|
|
118
|
+
shapes: type === "end" ? [] : decos.flatMap((_) => _.shapes),
|
|
123
119
|
updateEdges: false,
|
|
124
120
|
showMoving: false
|
|
125
121
|
};
|
|
@@ -127,7 +123,7 @@ export class FrameDragAction {
|
|
|
127
123
|
onMoveApply(state) {
|
|
128
124
|
const result = this.state.lastReturn;
|
|
129
125
|
if (!result || !state.moveHoveredFrame || !state.movingFrameId) {
|
|
130
|
-
return
|
|
126
|
+
return { updateEdges: false, wasApplied: false };
|
|
131
127
|
}
|
|
132
128
|
if (result instanceof Error) {
|
|
133
129
|
this.hooks.onError?.(result);
|
|
@@ -140,7 +136,10 @@ export class FrameDragAction {
|
|
|
140
136
|
ActionHandler.debugState(this.name, "after", state, this.state, this.debug);
|
|
141
137
|
}
|
|
142
138
|
}
|
|
143
|
-
return true;
|
|
139
|
+
return { updateEdges: false, wasApplied: true };
|
|
140
|
+
}
|
|
141
|
+
onMoveEnded() {
|
|
142
|
+
this.reset();
|
|
144
143
|
}
|
|
145
144
|
cancel() {
|
|
146
145
|
this.reset();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getFrameSplitInfo } from "../layout/getFrameSplitInfo.js";
|
|
2
|
-
import type { ActionChangeResult, IAction, MoveState, Point, SplitDeco } from "../types/index.js";
|
|
2
|
+
import type { ActionApplyResult, ActionChangeResult, IAction, MoveState, Point, SplitDeco } from "../types/index.js";
|
|
3
3
|
import type { KnownError } from "../utils/KnownError.js";
|
|
4
4
|
export type SplitInfo = Exclude<ReturnType<typeof getFrameSplitInfo>, KnownError>;
|
|
5
5
|
export type DragChangeType = "start" | "move" | "end";
|
|
@@ -51,6 +51,7 @@ export declare class SplitAction implements IAction {
|
|
|
51
51
|
};
|
|
52
52
|
calculateSplitRequest(state: MoveState): boolean;
|
|
53
53
|
onMoveChange(type: "start" | "end" | "move", _e: PointerEvent | undefined, state: MoveState): ActionChangeResult;
|
|
54
|
-
onMoveApply(state: MoveState):
|
|
54
|
+
onMoveApply(state: MoveState): ActionApplyResult;
|
|
55
|
+
onMoveEnded(): void;
|
|
55
56
|
cancel(): void;
|
|
56
57
|
}
|
|
@@ -119,10 +119,6 @@ export class SplitAction {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
onMoveChange(type, _e, state) {
|
|
122
|
-
if (type === "end") {
|
|
123
|
-
this.reset();
|
|
124
|
-
return { shapes: [] };
|
|
125
|
-
}
|
|
126
122
|
const { moveHoveredFrame, moveDistance } = state;
|
|
127
123
|
if (moveDistance <= this.minDragDistance) {
|
|
128
124
|
return { updateEdges: false, shapes: [], showMoving: false };
|
|
@@ -147,11 +143,19 @@ export class SplitAction {
|
|
|
147
143
|
},
|
|
148
144
|
attrs: { class: "deco-split-error bg-red-500/50" }
|
|
149
145
|
};
|
|
150
|
-
this.state.lastReturn = {
|
|
146
|
+
this.state.lastReturn = {
|
|
147
|
+
updateEdges: true,
|
|
148
|
+
shapes: type === "end" ? [] : [errorDeco],
|
|
149
|
+
showMoving: false
|
|
150
|
+
};
|
|
151
151
|
return this.state.lastReturn;
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
|
-
this.state.lastReturn = {
|
|
154
|
+
this.state.lastReturn = {
|
|
155
|
+
updateEdges: false,
|
|
156
|
+
shapes: type === "end" ? [] : decos.flatMap((_) => _.shapes),
|
|
157
|
+
showMoving: false
|
|
158
|
+
};
|
|
155
159
|
return this.state.lastReturn;
|
|
156
160
|
}
|
|
157
161
|
onMoveApply(state) {
|
|
@@ -167,10 +171,12 @@ export class SplitAction {
|
|
|
167
171
|
}
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
|
-
return true;
|
|
174
|
+
return { updateEdges: false, wasApplied: true };
|
|
171
175
|
}
|
|
172
|
-
|
|
176
|
+
onMoveEnded() {
|
|
173
177
|
this.reset();
|
|
178
|
+
}
|
|
179
|
+
cancel() {
|
|
174
180
|
this.hooks.onCancel?.();
|
|
175
181
|
}
|
|
176
182
|
}
|
|
@@ -1889,7 +1889,7 @@ export type MoveState = {
|
|
|
1889
1889
|
*/
|
|
1890
1890
|
intersections: IntersectionEntry[];
|
|
1891
1891
|
/**
|
|
1892
|
-
* Whether the
|
|
1892
|
+
* Whether the move was initiated from a point along the window edge.
|
|
1893
1893
|
*/
|
|
1894
1894
|
isMovingFromWindowEdge: boolean;
|
|
1895
1895
|
/** Custom context passed to moveStart, available to action handlers via state.eventContext. */
|
|
@@ -1897,7 +1897,7 @@ export type MoveState = {
|
|
|
1897
1897
|
win: LayoutWindow;
|
|
1898
1898
|
};
|
|
1899
1899
|
export interface ActionChangeResult {
|
|
1900
|
-
/** Whether the
|
|
1900
|
+
/** Whether the move should update the edges. Defaults to false. */
|
|
1901
1901
|
updateEdges?: boolean;
|
|
1902
1902
|
/** Deco shapes produced by this action during this drag step. */
|
|
1903
1903
|
shapes: LayoutShape[];
|
|
@@ -1905,25 +1905,6 @@ export interface ActionChangeResult {
|
|
|
1905
1905
|
showMoving?: boolean;
|
|
1906
1906
|
}
|
|
1907
1907
|
export type MoveChangeResult = Omit<ActionChangeResult, "shapes">;
|
|
1908
|
-
/**
|
|
1909
|
-
* Called when the drag coordinates change (during any event).
|
|
1910
|
-
*
|
|
1911
|
-
* Should return `{ allowed: true/false, shapes: LayoutShape[] }` to control whether the action is allowed and edges update and what deco shapes to render.
|
|
1912
|
-
*
|
|
1913
|
-
* Note that the allowed return type only affect the `move` event but is also typed as `boolean` for other events for ease of use.
|
|
1914
|
-
*
|
|
1915
|
-
* Use also to cleanup your action when type is "end".
|
|
1916
|
-
*
|
|
1917
|
-
* See also {@link ActionHandler.onMoveChange} to understand it's lifecycle as it is the extended version of.
|
|
1918
|
-
*/
|
|
1919
|
-
export type MoveChangeHandler = <T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: MoveState, forceRecalculateEdges: () => void,
|
|
1920
|
-
/** Calls moveEnd with apply: false */
|
|
1921
|
-
cancel: T extends "end" ? undefined : (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
1922
|
-
/** Saves result to resolve moveStart promise with then calls moveEnd with given apply. */
|
|
1923
|
-
resolve: T extends "end" ? undefined : ({ apply, result }: {
|
|
1924
|
-
apply: boolean;
|
|
1925
|
-
result: any;
|
|
1926
|
-
}) => void) => ActionChangeResult;
|
|
1927
1908
|
/**
|
|
1928
1909
|
* A drag action describes when and how to handle a drag event.
|
|
1929
1910
|
*
|
|
@@ -1934,18 +1915,30 @@ resolve: T extends "end" ? undefined : ({ apply, result }: {
|
|
|
1934
1915
|
export interface IAction {
|
|
1935
1916
|
/** A unique name for your action. */
|
|
1936
1917
|
name: string;
|
|
1937
|
-
onMoveChange: MoveChangeHandler;
|
|
1938
1918
|
/**
|
|
1919
|
+
* Called when the drag coordinates change (during any event).
|
|
1939
1920
|
*
|
|
1940
|
-
*
|
|
1921
|
+
* Should return `{ allowed: true/false, shapes: LayoutShape[] }` to control whether the action is allowed and edges update and what deco shapes to render.
|
|
1941
1922
|
*
|
|
1942
|
-
*
|
|
1923
|
+
* Note that the allowed return type only affect the `move` event but is also typed as `boolean` for other events for ease of use.
|
|
1943
1924
|
*
|
|
1944
|
-
*
|
|
1925
|
+
* Use also to cleanup your action when type is "end".
|
|
1926
|
+
*
|
|
1927
|
+
* See also {@link ActionHandler.onMoveChange} to understand it's lifecycle as it is the extended version of.
|
|
1928
|
+
*/
|
|
1929
|
+
onMoveChange: <T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: MoveState, forceRecalculateEdges: () => void,
|
|
1930
|
+
/** Calls moveEnd with updateEdges: false. This can technically be called from "end", it should still work. */
|
|
1931
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
1932
|
+
/** Saves result to resolve moveStart promise with then calls moveEnd with given apply. Not available during "end" event. It's designed for resolving from other external evente (e.g. key events). */
|
|
1933
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)) => ActionChangeResult;
|
|
1934
|
+
/**
|
|
1935
|
+
* Is called after `onMoveChange("end")` with the same event. Will not be called if the request was cancelled.
|
|
1936
|
+
*
|
|
1937
|
+
* You should apply your action if possible and return whether it was applied `wasApplied` as well as `updateEdges` and `result` (optional), see {@link ActionHandler.onMoveApply}, which this is the extended version of.
|
|
1945
1938
|
*
|
|
1946
|
-
*
|
|
1939
|
+
* Do not reset state here, use onMoveChange ("end").
|
|
1947
1940
|
*/
|
|
1948
|
-
onMoveApply: (state: MoveState, forceRecalculateEdges: () => void) =>
|
|
1941
|
+
onMoveApply: (state: MoveState, forceRecalculateEdges: () => void) => ActionApplyResult;
|
|
1949
1942
|
/**
|
|
1950
1943
|
* Should return true if it should handle the "request"/event (e.g. some modifier is being pressed => user is requesting x action).
|
|
1951
1944
|
*
|
|
@@ -1977,6 +1970,10 @@ export interface IAction {
|
|
|
1977
1970
|
/** Error texts/hints to display when the action produces an error. */
|
|
1978
1971
|
errors?: string[];
|
|
1979
1972
|
};
|
|
1973
|
+
/**
|
|
1974
|
+
* Called when an action is cancelled. Call action specific onCancel hooks here.
|
|
1975
|
+
*/
|
|
1976
|
+
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void;
|
|
1980
1977
|
/**
|
|
1981
1978
|
* Called after visual edges are recalculated, once per edge. Action handlers can annotate edges with error info here ({@link Edge.error}).
|
|
1982
1979
|
*
|
|
@@ -2006,35 +2003,51 @@ export type FrameMoveStartData = {
|
|
|
2006
2003
|
frameId: FrameId;
|
|
2007
2004
|
};
|
|
2008
2005
|
export type ActionHandlerApplyResult = {
|
|
2009
|
-
|
|
2006
|
+
updateEdges: boolean;
|
|
2007
|
+
/** Value to resolve the drag promise with. Ignored if `updateEdges` is false. */
|
|
2008
|
+
result?: any;
|
|
2009
|
+
};
|
|
2010
|
+
export type ActionApplyResult = ActionHandlerApplyResult & {
|
|
2011
|
+
wasApplied: boolean;
|
|
2012
|
+
};
|
|
2013
|
+
export type ActionResolve = {
|
|
2010
2014
|
apply: boolean;
|
|
2011
|
-
|
|
2012
|
-
result: any;
|
|
2015
|
+
result?: any;
|
|
2013
2016
|
};
|
|
2014
2017
|
/**
|
|
2015
2018
|
* Handler interface for drag actions.
|
|
2016
2019
|
*/
|
|
2017
|
-
export interface
|
|
2020
|
+
export interface IActionHandler {
|
|
2018
2021
|
eventHandler: (e: KeyboardEvent, state: MoveState, forceRecalculateEdges: () => void) => void;
|
|
2019
2022
|
/**
|
|
2020
|
-
* 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.
|
|
2023
|
+
* Called when the drag coordinates change (during any event). Should return updateEdges true to allow the edges to be updated/moved, or false to prevent it. See also {@link MoveChangeHandler} for the built in action handler.
|
|
2021
2024
|
*
|
|
2022
2025
|
* Can be used to save some context/info to later apply safely during onMoveApply.
|
|
2023
2026
|
*
|
|
2024
2027
|
* The call order is:
|
|
2025
2028
|
* - onMoveChange("start", ...)
|
|
2026
2029
|
* - onMoveChange("move", ...)
|
|
2030
|
+
* - onMoveChange("end", ...)
|
|
2027
2031
|
* - onMoveApply(...) (IF moveEnd was called with apply: true, otherwise this is skipped)
|
|
2028
|
-
*
|
|
2032
|
+
* - If anything calls cancel or resolve they call onMoveApply (cancel with apply: false, resolve with whatever apply value you gave it).
|
|
2033
|
+
* - onMoveEnded() // do cleanup here
|
|
2034
|
+
*
|
|
2035
|
+
* Note also that resolve just resolves the promise value (after onMoveApply("end") and before onMoveEnded()). Depending on what you're doing you might still have to apply the result, remember onMoveApply will still be called if you do `resolve({ apply:true })`.
|
|
2029
2036
|
*/
|
|
2030
|
-
onMoveChange
|
|
2037
|
+
onMoveChange<T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: MoveState, forceRecalculateEdges: () => void,
|
|
2038
|
+
/** Calls moveEnd with apply: false. This can technically be called from "end", it should still work. */
|
|
2039
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
2040
|
+
/** Saves result to resolve moveStart promise with then calls moveEnd with given apply. Not available during "end" event. It's designed for resolving from other external evente (e.g. key events). */
|
|
2041
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)): MoveChangeResult;
|
|
2031
2042
|
/**
|
|
2032
2043
|
* Called when drag will be applied. If moveEnd was called with apply false, it will not be called.
|
|
2033
|
-
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
2044
|
+
* Return `{updateEdges: false`} to not apply the regular drag end changes (i.e. return false to reset to the position before dragging). Optionally return a `result` value to resolve the promise with.
|
|
2034
2045
|
*
|
|
2035
|
-
* Do not use for resetting handler state, use
|
|
2046
|
+
* Do not use for resetting handler state, use onMoveEnded for that.
|
|
2036
2047
|
*/
|
|
2037
2048
|
onMoveApply: (state: MoveState, forceRecalculateEdges: () => void) => ActionHandlerApplyResult;
|
|
2049
|
+
/** For doing cleanup */
|
|
2050
|
+
onMoveEnded: () => void;
|
|
2038
2051
|
/**
|
|
2039
2052
|
* Called after visual edges are recalculated. Action handlers can annotate edges with error info.
|
|
2040
2053
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey, Ref } from "vue";
|
|
2
|
-
import type {
|
|
2
|
+
import type { Direction, Edge, FrameId, IActionHandler, IntersectionEntry, LayoutFrame, LayoutShape, LayoutWindow, MoveState, Orientation, Point } from "./index.js";
|
|
3
3
|
export type LayoutContext = ComputedRef<{
|
|
4
4
|
/** The owning window, needed so we can correctly scale coordinates. */
|
|
5
5
|
win: LayoutWindow;
|
|
@@ -8,7 +8,7 @@ export type LayoutContext = ComputedRef<{
|
|
|
8
8
|
}>;
|
|
9
9
|
export declare const layoutContextInjectionKey: InjectionKey<LayoutContext>;
|
|
10
10
|
export interface UseFramesContext {
|
|
11
|
-
actionHandler:
|
|
11
|
+
actionHandler: IActionHandler;
|
|
12
12
|
moveStart: {
|
|
13
13
|
(e: PointerEvent, type: "edge", data: {
|
|
14
14
|
edge?: Edge;
|
|
@@ -27,7 +27,9 @@ export interface UseFramesContext {
|
|
|
27
27
|
}): Promise<any>;
|
|
28
28
|
};
|
|
29
29
|
onMove: (e: PointerEvent) => void;
|
|
30
|
-
moveEnd: (e?: PointerEvent, options?:
|
|
30
|
+
moveEnd: (e?: PointerEvent, options?: {
|
|
31
|
+
apply?: boolean;
|
|
32
|
+
}) => void;
|
|
31
33
|
cancel: () => void;
|
|
32
34
|
moveDirections: Ref<Record<Orientation, Direction | undefined>>;
|
|
33
35
|
movePoint: Ref<Point | undefined>;
|
package/package.json
CHANGED
package/src/module.ts
CHANGED
|
@@ -38,7 +38,7 @@ export default defineNuxtModule<ModuleOptions>({
|
|
|
38
38
|
getContents: () => [
|
|
39
39
|
`@source "${resolve("runtime/components")}";`,
|
|
40
40
|
// the drag actions handlers and utils they use add some styles
|
|
41
|
-
`@source "${resolve("runtime/
|
|
41
|
+
`@source "${resolve("runtime/move")}";`,
|
|
42
42
|
`@source "${resolve("runtime/utils/createSplitDecoShapes")}";`
|
|
43
43
|
].join("\n")
|
|
44
44
|
})
|
|
@@ -12,11 +12,11 @@ import { toWindowCoord } from "../helpers/toWindowCoord.js"
|
|
|
12
12
|
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
|
|
13
13
|
import { isPointInRect } from "../layout/isPointInRect.js"
|
|
14
14
|
import { MoveDirectionStore } from "../move/MoveDirectionStore.js"
|
|
15
|
-
import type {
|
|
15
|
+
import type { ActionResolve, Direction, Edge, EdgeMoveStartData, FrameId, FrameMoveStartData, IActionHandler, IntersectionEntry, LayoutFrame, LayoutWindow, MoveState, Orientation, Point } from "../types/index.js"
|
|
16
16
|
|
|
17
17
|
export function useFrames(
|
|
18
18
|
win: Ref<LayoutWindow>,
|
|
19
|
-
handler:
|
|
19
|
+
handler: IActionHandler
|
|
20
20
|
) {
|
|
21
21
|
const movingEdges = ref<Edge[]>([])
|
|
22
22
|
|
|
@@ -134,6 +134,7 @@ export function useFrames(
|
|
|
134
134
|
moveDirStore.reset()
|
|
135
135
|
showMoving.value = false
|
|
136
136
|
forceRecalculateEdges()
|
|
137
|
+
handler.onMoveEnded()
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
function moveStart<T extends "edge" | "frame">(
|
|
@@ -231,13 +232,17 @@ export function useFrames(
|
|
|
231
232
|
)
|
|
232
233
|
}
|
|
233
234
|
if (!didChange) return
|
|
234
|
-
|
|
235
|
+
onMoveChange(e, "move", point)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function onMoveChange(e: PointerEvent | undefined, type: "move" | "end", point: Point | undefined) {
|
|
239
|
+
const res = handler.onMoveChange(type, e, state.value, forceRecalculateEdges, cancel, type === "end" ? undefined : resolve)
|
|
235
240
|
|
|
236
241
|
|
|
237
242
|
showMoving.value = res.showMoving ?? true
|
|
238
243
|
if (!res.updateEdges) return
|
|
239
244
|
|
|
240
|
-
if (isMoving.value === "edge") {
|
|
245
|
+
if (isMoving.value === "edge" && point) {
|
|
241
246
|
requestAnimationFrame(() => {
|
|
242
247
|
for (let i = 0; i < movingEdges.value.length; i++) {
|
|
243
248
|
const movingEdge = movingEdges.value[i]
|
|
@@ -250,33 +255,34 @@ export function useFrames(
|
|
|
250
255
|
}
|
|
251
256
|
}
|
|
252
257
|
|
|
253
|
-
function moveEnd(e?: PointerEvent, { apply = true }:
|
|
258
|
+
function moveEnd(e?: PointerEvent, { apply = true }: { apply?: boolean } = {}) {
|
|
254
259
|
if (e) {
|
|
255
260
|
const point = toWindowCoord(win.value, e)
|
|
256
261
|
movePoint.value = point
|
|
257
262
|
}
|
|
258
263
|
|
|
264
|
+
onMoveChange(e, "end", movePoint.value)
|
|
265
|
+
|
|
259
266
|
if (apply) {
|
|
260
267
|
const applyResult = handler.onMoveApply(state.value, forceRecalculateEdges)
|
|
261
268
|
moveResult = applyResult.result
|
|
262
|
-
if (applyResult.
|
|
269
|
+
if (applyResult.updateEdges) {
|
|
263
270
|
for (const frame of touchingFramesArrays.value.flat()) {
|
|
264
271
|
win!.value.frames[frame.id] = frame
|
|
265
272
|
}
|
|
266
273
|
}
|
|
267
274
|
}
|
|
268
275
|
|
|
269
|
-
handler.onMoveChange("end", e, state.value, forceRecalculateEdges, undefined, undefined)
|
|
270
|
-
|
|
271
276
|
// this can get called from elsewhere
|
|
272
|
-
// also takes care of cleanup
|
|
277
|
+
// also takes care of cleanup, resolving promise, and calling onMoveEnded
|
|
273
278
|
controller?.abort()
|
|
274
279
|
}
|
|
275
280
|
|
|
276
281
|
function cancel(): void {
|
|
277
282
|
moveEnd(undefined, { apply: false })
|
|
278
283
|
}
|
|
279
|
-
|
|
284
|
+
// we use apply not updateEdges, updateEdges needs to be returned by onMoveApply
|
|
285
|
+
function resolve({ apply, result: value }: ActionResolve): void {
|
|
280
286
|
moveResult = value
|
|
281
287
|
moveEnd(undefined, { apply })
|
|
282
288
|
}
|
|
@@ -2,7 +2,7 @@ import { get, type RecordFromArray } from "@alanscodelog/utils"
|
|
|
2
2
|
|
|
3
3
|
import { isWindowEdge } from "../helpers/isWindowEdge.js"
|
|
4
4
|
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
|
|
5
|
-
import type { ActionHandlerApplyResult, Edge, IAction, LayoutFrame, LayoutShape,
|
|
5
|
+
import type { ActionHandlerApplyResult, ActionResolve, Edge, IAction, IActionHandler, LayoutFrame, LayoutShape, MoveChangeResult, MoveState } from "../types/index.js"
|
|
6
6
|
import { LAYOUT_ERROR } from "../types/index.js"
|
|
7
7
|
import { KnownError } from "../utils/KnownError.js"
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ import { KnownError } from "../utils/KnownError.js"
|
|
|
14
14
|
export class ActionHandler<
|
|
15
15
|
TRawActions extends IAction[],
|
|
16
16
|
TActions extends RecordFromArray<TRawActions, "name"> = RecordFromArray<TRawActions, "name">
|
|
17
|
-
> {
|
|
17
|
+
> implements IActionHandler {
|
|
18
18
|
activeAction?: keyof TActions
|
|
19
19
|
|
|
20
20
|
actions: TActions
|
|
@@ -23,7 +23,7 @@ export class ActionHandler<
|
|
|
23
23
|
|
|
24
24
|
boundCancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void
|
|
25
25
|
|
|
26
|
-
defaultOnMoveChange:
|
|
26
|
+
defaultOnMoveChange: IAction["onMoveChange"] = (type, _e, state, _forceRecalculateEdges, _cancel) => {
|
|
27
27
|
const isTouchingCollapsedFrameEdge = type === "move"
|
|
28
28
|
&& state.isMoving === "edge"
|
|
29
29
|
&& state.touchingFramesArrays.some(frames =>
|
|
@@ -48,7 +48,7 @@ export class ActionHandler<
|
|
|
48
48
|
/** Called when the action requested changes. */
|
|
49
49
|
onRequestChange?: (type: keyof TActions | undefined) => void
|
|
50
50
|
/** Called when the drag action ends either because it was completed or cancelled. */
|
|
51
|
-
onEnd?: (context: { cancelled: boolean,
|
|
51
|
+
onEnd?: (context: { cancelled: boolean, wasApplied: boolean, result?: any }) => void
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/** All action shapes merged into a single array. If using vue you can set this to a reactive array for reactivity. */
|
|
@@ -61,13 +61,11 @@ export class ActionHandler<
|
|
|
61
61
|
actions: TRawActions,
|
|
62
62
|
hooks: ActionHandler<TRawActions, TActions>["hooks"] = {},
|
|
63
63
|
/**
|
|
64
|
-
* Default onMoveChange handler for when no action can handle the request.
|
|
65
|
-
*
|
|
66
|
-
* Should return true to allow the edges to be moved, or false to prevent it.
|
|
64
|
+
* Default onMoveChange handler for when no action can handle the request. See {@link IAction.onMoveChange}.
|
|
67
65
|
*
|
|
68
66
|
* The default prevents movement when the edge is a window edge and when the edge is touching a collapsed frame.
|
|
69
67
|
*/
|
|
70
|
-
defaultOnMoveChange?:
|
|
68
|
+
defaultOnMoveChange?: IAction["onMoveChange"]
|
|
71
69
|
) {
|
|
72
70
|
if (defaultOnMoveChange) this.defaultOnMoveChange = defaultOnMoveChange
|
|
73
71
|
this.hooks = hooks
|
|
@@ -128,8 +126,8 @@ export class ActionHandler<
|
|
|
128
126
|
e: T extends "end" ? PointerEvent | undefined : PointerEvent,
|
|
129
127
|
state: MoveState,
|
|
130
128
|
forceRecalculateEdges: () => void,
|
|
131
|
-
cancel:
|
|
132
|
-
resolve: T extends "end" ? undefined : (opts:
|
|
129
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
130
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)
|
|
133
131
|
): MoveChangeResult {
|
|
134
132
|
if (type === "start") {
|
|
135
133
|
this.eventCanceller = cancel
|
|
@@ -137,7 +135,7 @@ export class ActionHandler<
|
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
if (this.activeAction) {
|
|
140
|
-
const res = this.actions[this.activeAction]!.onMoveChange(type, e, state, forceRecalculateEdges, this.boundCancel as any, resolve
|
|
138
|
+
const res = this.actions[this.activeAction]!.onMoveChange(type, e, state, forceRecalculateEdges, this.boundCancel as any, resolve)
|
|
141
139
|
// in case it's a vue reactive array
|
|
142
140
|
this.shapes.splice(0, this.shapes.length, ...res.shapes)
|
|
143
141
|
this.setTextHints(type)
|
|
@@ -147,12 +145,40 @@ export class ActionHandler<
|
|
|
147
145
|
const res = this.defaultOnMoveChange(type, e, state, forceRecalculateEdges, this.boundCancel as any, resolve as any)
|
|
148
146
|
this.shapes.splice(0, this.shapes.length, ...res.shapes)
|
|
149
147
|
|
|
150
|
-
if (type === "end") {
|
|
151
|
-
this.activeAction = undefined
|
|
152
|
-
}
|
|
153
148
|
return res
|
|
154
149
|
}
|
|
155
150
|
|
|
151
|
+
onMoveApply(
|
|
152
|
+
state: MoveState,
|
|
153
|
+
forceRecalculateEdges: () => void
|
|
154
|
+
): ActionHandlerApplyResult {
|
|
155
|
+
if (this.activeAction) {
|
|
156
|
+
const res = this.actions[this.activeAction]!.onMoveApply(state, forceRecalculateEdges)
|
|
157
|
+
this.hooks.onEnd?.({ cancelled: false, wasApplied: res.wasApplied, result: res.result })
|
|
158
|
+
return res
|
|
159
|
+
}
|
|
160
|
+
this.hooks.onEnd?.({ cancelled: false, wasApplied: false })
|
|
161
|
+
return { updateEdges: true, result: undefined }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
onMoveEnded() {
|
|
165
|
+
if (this.activeAction) {
|
|
166
|
+
this.actions[this.activeAction]!.onMoveEnded()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.activeAction = undefined
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void {
|
|
173
|
+
if (this.activeAction) {
|
|
174
|
+
this.actions[this.activeAction].cancel(e, state)
|
|
175
|
+
}
|
|
176
|
+
this.activeAction = undefined
|
|
177
|
+
this.eventCanceller?.(e, state)
|
|
178
|
+
this.hooks.onEnd?.({ cancelled: true, wasApplied: false })
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
156
182
|
setTextHints(type: "start" | "move" | "end") {
|
|
157
183
|
// again in case it's a vue reactive object
|
|
158
184
|
this.textHints.actions = []
|
|
@@ -190,28 +216,6 @@ export class ActionHandler<
|
|
|
190
216
|
}
|
|
191
217
|
}
|
|
192
218
|
|
|
193
|
-
onMoveApply(
|
|
194
|
-
state: MoveState,
|
|
195
|
-
forceRecalculateEdges: () => void
|
|
196
|
-
): ActionHandlerApplyResult {
|
|
197
|
-
if (this.activeAction) {
|
|
198
|
-
const res = this.actions[this.activeAction]!.onMoveApply(state, forceRecalculateEdges)
|
|
199
|
-
this.hooks.onEnd?.({ cancelled: false, applied: res })
|
|
200
|
-
return { apply: res, result: undefined }
|
|
201
|
-
}
|
|
202
|
-
this.hooks.onEnd?.({ cancelled: false, applied: false })
|
|
203
|
-
return { apply: true, result: undefined }
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void {
|
|
207
|
-
if (this.activeAction) {
|
|
208
|
-
this.actions[this.activeAction].cancel(e, state)
|
|
209
|
-
}
|
|
210
|
-
this.activeAction = undefined
|
|
211
|
-
this.eventCanceller?.(e, state)
|
|
212
|
-
this.hooks.onEnd?.({ cancelled: true, applied: false })
|
|
213
|
-
}
|
|
214
|
-
|
|
215
219
|
static debugState(
|
|
216
220
|
pluginName: string,
|
|
217
221
|
type: "before" | "after" | string,
|
|
@@ -6,7 +6,7 @@ import { oppositeSide } from "../helpers/oppositeSide.js"
|
|
|
6
6
|
import { applyFrameChanges } from "../layout/applyFrameChanges.js"
|
|
7
7
|
import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
|
|
8
8
|
import { getCloseFrameInfo } from "../layout/getCloseFrameInfo.js"
|
|
9
|
-
import type { ActionChangeResult, CloseDeco, IAction, MoveState } from "../types/index.js"
|
|
9
|
+
import type { ActionApplyResult, ActionChangeResult, CloseDeco, IAction, MoveState } from "../types/index.js"
|
|
10
10
|
import type { KnownError } from "../utils/KnownError.js"
|
|
11
11
|
|
|
12
12
|
export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError>
|
|
@@ -155,10 +155,6 @@ export class CloseAction implements IAction {
|
|
|
155
155
|
_e: PointerEvent | undefined,
|
|
156
156
|
state: MoveState
|
|
157
157
|
): ActionChangeResult {
|
|
158
|
-
if (type === "end") {
|
|
159
|
-
this.reset()
|
|
160
|
-
return { shapes: [] }
|
|
161
|
-
}
|
|
162
158
|
if (state.moveDistance <= this.minDragDistance) {
|
|
163
159
|
return { updateEdges: false, shapes: [] }
|
|
164
160
|
}
|
|
@@ -209,23 +205,29 @@ export class CloseAction implements IAction {
|
|
|
209
205
|
}
|
|
210
206
|
}
|
|
211
207
|
const decos = this._getDecos(state)
|
|
212
|
-
this.state.lastReturn = {
|
|
208
|
+
this.state.lastReturn = {
|
|
209
|
+
updateEdges: !isMovingFromWindowEdge,
|
|
210
|
+
shapes: type === "end" ? [] : decos.flatMap(_ => _.shapes)
|
|
211
|
+
}
|
|
213
212
|
return this.state.lastReturn
|
|
214
213
|
}
|
|
215
214
|
|
|
216
|
-
onMoveApply(state: MoveState):
|
|
215
|
+
onMoveApply(state: MoveState): ActionApplyResult {
|
|
217
216
|
if (this.state.res) {
|
|
218
217
|
const win = state.win
|
|
219
218
|
if (this.debug) { ActionHandler.debugState(this.name, "before", state, this.state, this.debug) }
|
|
220
219
|
applyFrameChanges(win, this.state.res)
|
|
221
220
|
if (this.debug) { ActionHandler.debugState(this.name, "after", state, this.state, this.debug) }
|
|
222
|
-
return true
|
|
221
|
+
return { updateEdges: false, wasApplied: true }
|
|
223
222
|
}
|
|
224
|
-
return false
|
|
223
|
+
return { updateEdges: true, wasApplied: false }
|
|
225
224
|
}
|
|
226
225
|
|
|
227
226
|
cancel(): void {
|
|
228
|
-
this.reset()
|
|
229
227
|
this.hooks.onCancel?.()
|
|
230
228
|
}
|
|
229
|
+
|
|
230
|
+
onMoveEnded() {
|
|
231
|
+
this.reset()
|
|
232
|
+
}
|
|
231
233
|
}
|
|
@@ -7,7 +7,7 @@ import { getFrameRearrangeInfo } from "../layout/getFrameRearrangeInfo.js"
|
|
|
7
7
|
import { getFrameSwapInfo } from "../layout/getFrameSwapInfo.js"
|
|
8
8
|
import { getZones } from "../layout/getZones.js"
|
|
9
9
|
import { settings } from "../settings.js"
|
|
10
|
-
import type { ActionChangeResult, FrameDeco, IAction, LayoutChange, MoveState, Zone } from "../types/index.js"
|
|
10
|
+
import type { ActionApplyResult, ActionChangeResult, FrameDeco, IAction, LayoutChange, MoveState, Zone } from "../types/index.js"
|
|
11
11
|
import type { KnownError } from "../utils/KnownError.js"
|
|
12
12
|
|
|
13
13
|
|
|
@@ -155,10 +155,6 @@ export class FrameDragAction implements IAction {
|
|
|
155
155
|
_e: PointerEvent | undefined,
|
|
156
156
|
state: MoveState
|
|
157
157
|
): ActionChangeResult {
|
|
158
|
-
if (type === "end") {
|
|
159
|
-
this.reset()
|
|
160
|
-
return { shapes: [] }
|
|
161
|
-
}
|
|
162
158
|
if (state.moveDistance <= this.minDragDistance) {
|
|
163
159
|
return { updateEdges: false, shapes: [], showMoving: false }
|
|
164
160
|
}
|
|
@@ -185,16 +181,16 @@ export class FrameDragAction implements IAction {
|
|
|
185
181
|
const decos = this.getDecos(matchedZone, state, this.state.lastReturn)
|
|
186
182
|
|
|
187
183
|
return {
|
|
188
|
-
shapes: decos.flatMap(_ => _.shapes),
|
|
184
|
+
shapes: type === "end" ? [] : decos.flatMap(_ => _.shapes),
|
|
189
185
|
updateEdges: false,
|
|
190
186
|
showMoving: false
|
|
191
187
|
}
|
|
192
188
|
}
|
|
193
189
|
|
|
194
|
-
onMoveApply(state: MoveState):
|
|
190
|
+
onMoveApply(state: MoveState): ActionApplyResult {
|
|
195
191
|
const result = this.state.lastReturn
|
|
196
192
|
if (!result || !state.moveHoveredFrame || !state.movingFrameId) {
|
|
197
|
-
return
|
|
193
|
+
return { updateEdges: false, wasApplied: false }
|
|
198
194
|
}
|
|
199
195
|
|
|
200
196
|
if (result instanceof Error) {
|
|
@@ -205,7 +201,11 @@ export class FrameDragAction implements IAction {
|
|
|
205
201
|
if (this.debug) { ActionHandler.debugState(this.name, "after", state, this.state, this.debug) }
|
|
206
202
|
}
|
|
207
203
|
|
|
208
|
-
return true
|
|
204
|
+
return { updateEdges: false, wasApplied: true }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
onMoveEnded() {
|
|
208
|
+
this.reset()
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
cancel(): void {
|
|
@@ -5,7 +5,7 @@ import { oppositeSide } from "../helpers/oppositeSide.js"
|
|
|
5
5
|
import { applyFrameChanges } from "../layout/applyFrameChanges.js"
|
|
6
6
|
import { createSplitDecoFromDrag } from "../layout/createSplitDecoFromDrag.js"
|
|
7
7
|
import { getFrameSplitInfo } from "../layout/getFrameSplitInfo.js"
|
|
8
|
-
import type { ActionChangeResult, IAction, LayoutShape, MoveState, Point, SplitDeco } from "../types/index.js"
|
|
8
|
+
import type { ActionApplyResult, ActionChangeResult, IAction, LayoutShape, MoveState, Point, SplitDeco } from "../types/index.js"
|
|
9
9
|
import type { KnownError } from "../utils/KnownError.js"
|
|
10
10
|
|
|
11
11
|
export type SplitInfo = Exclude<ReturnType<typeof getFrameSplitInfo>, KnownError>
|
|
@@ -178,10 +178,6 @@ export class SplitAction implements IAction {
|
|
|
178
178
|
_e: PointerEvent | undefined,
|
|
179
179
|
state: MoveState
|
|
180
180
|
): ActionChangeResult {
|
|
181
|
-
if (type === "end") {
|
|
182
|
-
this.reset()
|
|
183
|
-
return { shapes: [] }
|
|
184
|
-
}
|
|
185
181
|
const { moveHoveredFrame, moveDistance } = state
|
|
186
182
|
if (moveDistance <= this.minDragDistance) {
|
|
187
183
|
return { updateEdges: false, shapes: [], showMoving: false }
|
|
@@ -207,15 +203,23 @@ export class SplitAction implements IAction {
|
|
|
207
203
|
},
|
|
208
204
|
attrs: { class: "deco-split-error bg-red-500/50" }
|
|
209
205
|
}
|
|
210
|
-
this.state.lastReturn = {
|
|
206
|
+
this.state.lastReturn = {
|
|
207
|
+
updateEdges: true,
|
|
208
|
+
shapes: type === "end" ? [] : [errorDeco],
|
|
209
|
+
showMoving: false
|
|
210
|
+
}
|
|
211
211
|
return this.state.lastReturn
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
|
-
this.state.lastReturn = {
|
|
214
|
+
this.state.lastReturn = {
|
|
215
|
+
updateEdges: false,
|
|
216
|
+
shapes: type === "end" ? [] : decos.flatMap(_ => _.shapes),
|
|
217
|
+
showMoving: false
|
|
218
|
+
}
|
|
215
219
|
return this.state.lastReturn
|
|
216
220
|
}
|
|
217
221
|
|
|
218
|
-
onMoveApply(state: MoveState):
|
|
222
|
+
onMoveApply(state: MoveState): ActionApplyResult {
|
|
219
223
|
if (this.state.res && state.moveHoveredFrame) {
|
|
220
224
|
// this only caches once per frame hovered over
|
|
221
225
|
// so the drag position is outdated, we must recalculate
|
|
@@ -226,11 +230,14 @@ export class SplitAction implements IAction {
|
|
|
226
230
|
if (this.debug) { ActionHandler.debugState(this.name, "after", state, this.state, this.debug) }
|
|
227
231
|
}
|
|
228
232
|
}
|
|
229
|
-
return true
|
|
233
|
+
return { updateEdges: false, wasApplied: true }
|
|
230
234
|
}
|
|
231
235
|
|
|
232
|
-
|
|
236
|
+
onMoveEnded() {
|
|
233
237
|
this.reset()
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
cancel(): void {
|
|
234
241
|
this.hooks.onCancel?.()
|
|
235
242
|
}
|
|
236
243
|
}
|
|
@@ -487,7 +487,7 @@ export type MoveState = {
|
|
|
487
487
|
*/
|
|
488
488
|
intersections: IntersectionEntry[]
|
|
489
489
|
/**
|
|
490
|
-
* Whether the
|
|
490
|
+
* Whether the move was initiated from a point along the window edge.
|
|
491
491
|
*/
|
|
492
492
|
isMovingFromWindowEdge: boolean
|
|
493
493
|
/** Custom context passed to moveStart, available to action handlers via state.eventContext. */
|
|
@@ -497,7 +497,7 @@ export type MoveState = {
|
|
|
497
497
|
|
|
498
498
|
|
|
499
499
|
export interface ActionChangeResult {
|
|
500
|
-
/** Whether the
|
|
500
|
+
/** Whether the move should update the edges. Defaults to false. */
|
|
501
501
|
updateEdges?: boolean
|
|
502
502
|
/** Deco shapes produced by this action during this drag step. */
|
|
503
503
|
shapes: LayoutShape[]
|
|
@@ -506,27 +506,6 @@ export interface ActionChangeResult {
|
|
|
506
506
|
}
|
|
507
507
|
export type MoveChangeResult = Omit<ActionChangeResult, "shapes">
|
|
508
508
|
|
|
509
|
-
/**
|
|
510
|
-
* Called when the drag coordinates change (during any event).
|
|
511
|
-
*
|
|
512
|
-
* Should return `{ allowed: true/false, shapes: LayoutShape[] }` to control whether the action is allowed and edges update and what deco shapes to render.
|
|
513
|
-
*
|
|
514
|
-
* Note that the allowed return type only affect the `move` event but is also typed as `boolean` for other events for ease of use.
|
|
515
|
-
*
|
|
516
|
-
* Use also to cleanup your action when type is "end".
|
|
517
|
-
*
|
|
518
|
-
* See also {@link ActionHandler.onMoveChange} to understand it's lifecycle as it is the extended version of.
|
|
519
|
-
*/
|
|
520
|
-
export type MoveChangeHandler = <T extends "start" | "move" | "end">(
|
|
521
|
-
type: T,
|
|
522
|
-
e: T extends "end" ? PointerEvent | undefined : PointerEvent,
|
|
523
|
-
state: MoveState,
|
|
524
|
-
forceRecalculateEdges: () => void,
|
|
525
|
-
/** Calls moveEnd with apply: false */
|
|
526
|
-
cancel: T extends "end" ? undefined : (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
527
|
-
/** Saves result to resolve moveStart promise with then calls moveEnd with given apply. */
|
|
528
|
-
resolve: T extends "end" ? undefined : ({ apply, result }: { apply: boolean, result: any }) => void
|
|
529
|
-
) => ActionChangeResult
|
|
530
509
|
|
|
531
510
|
/**
|
|
532
511
|
* A drag action describes when and how to handle a drag event.
|
|
@@ -539,18 +518,35 @@ export type MoveChangeHandler = <T extends "start" | "move" | "end">(
|
|
|
539
518
|
export interface IAction {
|
|
540
519
|
/** A unique name for your action. */
|
|
541
520
|
name: string
|
|
542
|
-
onMoveChange: MoveChangeHandler
|
|
543
521
|
/**
|
|
522
|
+
* Called when the drag coordinates change (during any event).
|
|
544
523
|
*
|
|
545
|
-
*
|
|
524
|
+
* Should return `{ allowed: true/false, shapes: LayoutShape[] }` to control whether the action is allowed and edges update and what deco shapes to render.
|
|
546
525
|
*
|
|
547
|
-
*
|
|
526
|
+
* Note that the allowed return type only affect the `move` event but is also typed as `boolean` for other events for ease of use.
|
|
548
527
|
*
|
|
549
|
-
*
|
|
528
|
+
* Use also to cleanup your action when type is "end".
|
|
550
529
|
*
|
|
551
|
-
* See also {@link ActionHandler.
|
|
530
|
+
* See also {@link ActionHandler.onMoveChange} to understand it's lifecycle as it is the extended version of.
|
|
552
531
|
*/
|
|
553
|
-
|
|
532
|
+
onMoveChange: <T extends "start" | "move" | "end">(
|
|
533
|
+
type: T,
|
|
534
|
+
e: T extends "end" ? PointerEvent | undefined : PointerEvent,
|
|
535
|
+
state: MoveState,
|
|
536
|
+
forceRecalculateEdges: () => void,
|
|
537
|
+
/** Calls moveEnd with updateEdges: false. This can technically be called from "end", it should still work. */
|
|
538
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
539
|
+
/** Saves result to resolve moveStart promise with then calls moveEnd with given apply. Not available during "end" event. It's designed for resolving from other external evente (e.g. key events). */
|
|
540
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)
|
|
541
|
+
) => ActionChangeResult
|
|
542
|
+
/**
|
|
543
|
+
* Is called after `onMoveChange("end")` with the same event. Will not be called if the request was cancelled.
|
|
544
|
+
*
|
|
545
|
+
* You should apply your action if possible and return whether it was applied `wasApplied` as well as `updateEdges` and `result` (optional), see {@link ActionHandler.onMoveApply}, which this is the extended version of.
|
|
546
|
+
*
|
|
547
|
+
* Do not reset state here, use onMoveChange ("end").
|
|
548
|
+
*/
|
|
549
|
+
onMoveApply: (state: MoveState, forceRecalculateEdges: () => void) => ActionApplyResult
|
|
554
550
|
/**
|
|
555
551
|
* Should return true if it should handle the "request"/event (e.g. some modifier is being pressed => user is requesting x action).
|
|
556
552
|
*
|
|
@@ -587,6 +583,11 @@ export interface IAction {
|
|
|
587
583
|
/** Error texts/hints to display when the action produces an error. */
|
|
588
584
|
errors?: string[]
|
|
589
585
|
}
|
|
586
|
+
/**
|
|
587
|
+
* Called when an action is cancelled. Call action specific onCancel hooks here.
|
|
588
|
+
*/
|
|
589
|
+
// note: internally this is done by the actionhandler wrapping the given cancel function for an event
|
|
590
|
+
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void
|
|
590
591
|
/**
|
|
591
592
|
* Called after visual edges are recalculated, once per edge. Action handlers can annotate edges with error info here ({@link Edge.error}).
|
|
592
593
|
*
|
|
@@ -612,39 +613,62 @@ export type EdgeMoveStartData = { edge?: Edge, intersection?: IntersectionEntry
|
|
|
612
613
|
export type FrameMoveStartData = { frameId: FrameId }
|
|
613
614
|
|
|
614
615
|
export type ActionHandlerApplyResult = {
|
|
615
|
-
/** Whether
|
|
616
|
-
|
|
617
|
-
/** Value to resolve the drag promise with. Ignored if `
|
|
618
|
-
result
|
|
616
|
+
// /** Whether the move should update the edges. Defaults to false which resets to the position before moving started.*/
|
|
617
|
+
updateEdges: boolean
|
|
618
|
+
/** Value to resolve the drag promise with. Ignored if `updateEdges` is false. */
|
|
619
|
+
result?: any
|
|
619
620
|
}
|
|
620
621
|
|
|
622
|
+
export type ActionApplyResult = ActionHandlerApplyResult & { wasApplied: boolean }
|
|
623
|
+
|
|
624
|
+
export type ActionResolve = { apply: boolean, result?: any }
|
|
625
|
+
|
|
621
626
|
/**
|
|
622
627
|
* Handler interface for drag actions.
|
|
623
628
|
*/
|
|
624
|
-
|
|
629
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
630
|
+
export interface IActionHandler {
|
|
625
631
|
eventHandler: (e: KeyboardEvent, state: MoveState, forceRecalculateEdges: () => void) => void
|
|
632
|
+
|
|
626
633
|
/**
|
|
627
|
-
* 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.
|
|
634
|
+
* Called when the drag coordinates change (during any event). Should return updateEdges true to allow the edges to be updated/moved, or false to prevent it. See also {@link MoveChangeHandler} for the built in action handler.
|
|
628
635
|
*
|
|
629
636
|
* Can be used to save some context/info to later apply safely during onMoveApply.
|
|
630
637
|
*
|
|
631
638
|
* The call order is:
|
|
632
639
|
* - onMoveChange("start", ...)
|
|
633
640
|
* - onMoveChange("move", ...)
|
|
641
|
+
* - onMoveChange("end", ...)
|
|
634
642
|
* - onMoveApply(...) (IF moveEnd was called with apply: true, otherwise this is skipped)
|
|
635
|
-
*
|
|
643
|
+
* - If anything calls cancel or resolve they call onMoveApply (cancel with apply: false, resolve with whatever apply value you gave it).
|
|
644
|
+
* - onMoveEnded() // do cleanup here
|
|
645
|
+
*
|
|
646
|
+
* Note also that resolve just resolves the promise value (after onMoveApply("end") and before onMoveEnded()). Depending on what you're doing you might still have to apply the result, remember onMoveApply will still be called if you do `resolve({ apply:true })`.
|
|
636
647
|
*/
|
|
637
|
-
onMoveChange
|
|
648
|
+
onMoveChange<T extends "start" | "move" | "end">(
|
|
649
|
+
type: T,
|
|
650
|
+
e: T extends "end" ? PointerEvent | undefined : PointerEvent,
|
|
651
|
+
state: MoveState,
|
|
652
|
+
forceRecalculateEdges: () => void,
|
|
653
|
+
/** Calls moveEnd with apply: false. This can technically be called from "end", it should still work. */
|
|
654
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
655
|
+
/** Saves result to resolve moveStart promise with then calls moveEnd with given apply. Not available during "end" event. It's designed for resolving from other external evente (e.g. key events). */
|
|
656
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)
|
|
657
|
+
): MoveChangeResult
|
|
638
658
|
/**
|
|
639
659
|
* Called when drag will be applied. If moveEnd was called with apply false, it will not be called.
|
|
640
|
-
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
660
|
+
* Return `{updateEdges: false`} to not apply the regular drag end changes (i.e. return false to reset to the position before dragging). Optionally return a `result` value to resolve the promise with.
|
|
641
661
|
*
|
|
642
|
-
* Do not use for resetting handler state, use
|
|
662
|
+
* Do not use for resetting handler state, use onMoveEnded for that.
|
|
643
663
|
*/
|
|
644
664
|
onMoveApply: (
|
|
645
665
|
state: MoveState,
|
|
646
666
|
forceRecalculateEdges: () => void
|
|
647
667
|
) => ActionHandlerApplyResult
|
|
668
|
+
|
|
669
|
+
/** For doing cleanup */
|
|
670
|
+
onMoveEnded: () => void
|
|
671
|
+
|
|
648
672
|
/**
|
|
649
673
|
* Called after visual edges are recalculated. Action handlers can annotate edges with error info.
|
|
650
674
|
*/
|
package/src/runtime/types/vue.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ComputedRef, InjectionKey, Ref } from "vue"
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line no-restricted-imports
|
|
4
|
-
import type {
|
|
4
|
+
import type { Direction, Edge, FrameId, IActionHandler, IntersectionEntry, LayoutFrame, LayoutShape, LayoutWindow, MoveState, Orientation, Point } from "./index.js"
|
|
5
5
|
|
|
6
6
|
export type LayoutContext = ComputedRef<
|
|
7
7
|
& {
|
|
@@ -15,13 +15,13 @@ export type LayoutContext = ComputedRef<
|
|
|
15
15
|
export const layoutContextInjectionKey = Symbol.for("@witchcraft/layout:context") as InjectionKey<LayoutContext>
|
|
16
16
|
|
|
17
17
|
export interface UseFramesContext {
|
|
18
|
-
actionHandler:
|
|
18
|
+
actionHandler: IActionHandler
|
|
19
19
|
moveStart: {
|
|
20
20
|
(e: PointerEvent, type: "edge", data: { edge?: Edge, intersection?: IntersectionEntry }, opts?: { moveEvent?: string, endEvent?: string, context?: Record<string, unknown> }): Promise<any>
|
|
21
21
|
(e: PointerEvent, type: "frame", data: { frameId: FrameId }, opts?: { moveEvent?: string, endEvent?: string, context?: Record<string, unknown> }): Promise<any>
|
|
22
22
|
}
|
|
23
23
|
onMove: (e: PointerEvent) => void
|
|
24
|
-
moveEnd: (e?: PointerEvent, options?:
|
|
24
|
+
moveEnd: (e?: PointerEvent, options?: { apply?: boolean }) => void
|
|
25
25
|
cancel: () => void
|
|
26
26
|
moveDirections: Ref<Record<Orientation, Direction | undefined>>
|
|
27
27
|
movePoint: Ref<Point | undefined>
|