@witchcraft/layout 0.5.1 → 0.5.3
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 -3
- package/dist/runtime/move/ActionHandler.d.ts +10 -11
- package/dist/runtime/move/ActionHandler.js +17 -17
- package/dist/runtime/move/CloseAction.d.ts +2 -2
- package/dist/runtime/move/CloseAction.js +2 -2
- package/dist/runtime/move/FrameDragAction.d.ts +2 -2
- package/dist/runtime/move/FrameDragAction.js +2 -2
- package/dist/runtime/move/SplitAction.d.ts +2 -2
- package/dist/runtime/move/SplitAction.js +1 -1
- package/dist/runtime/types/index.d.ts +36 -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 +12 -6
- package/src/runtime/move/ActionHandler.ts +30 -31
- package/src/runtime/move/CloseAction.ts +4 -4
- package/src/runtime/move/FrameDragAction.ts +4 -4
- package/src/runtime/move/SplitAction.ts +3 -3
- package/src/runtime/types/index.ts +49 -38
- 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
|
};
|
|
@@ -197,7 +197,7 @@ export function useFrames(win, handler) {
|
|
|
197
197
|
if (apply) {
|
|
198
198
|
const applyResult = handler.onMoveApply(state.value, forceRecalculateEdges);
|
|
199
199
|
moveResult = applyResult.result;
|
|
200
|
-
if (applyResult.
|
|
200
|
+
if (applyResult.updateEdges) {
|
|
201
201
|
for (const frame of touchingFramesArrays.value.flat()) {
|
|
202
202
|
win.value.frames[frame.id] = frame;
|
|
203
203
|
}
|
|
@@ -208,9 +208,14 @@ export function useFrames(win, handler) {
|
|
|
208
208
|
function cancel() {
|
|
209
209
|
moveEnd(void 0, { apply: false });
|
|
210
210
|
}
|
|
211
|
-
function resolve({
|
|
211
|
+
function resolve({ updateEdges, result: value }) {
|
|
212
212
|
moveResult = value;
|
|
213
|
-
|
|
213
|
+
if (updateEdges) {
|
|
214
|
+
for (const frame of touchingFramesArrays.value.flat()) {
|
|
215
|
+
win.value.frames[frame.id] = frame;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
controller?.abort();
|
|
214
219
|
}
|
|
215
220
|
const keydownController = new AbortController();
|
|
216
221
|
const wrappedKeydownHandler = (e) => {
|
|
@@ -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,20 +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: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void, resolve: T extends "end" ? undefined : (opts:
|
|
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;
|
|
48
|
+
onMoveApply(state: MoveState, forceRecalculateEdges: () => void): ActionHandlerApplyResult;
|
|
49
49
|
onMoveEnded(): void;
|
|
50
|
+
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void;
|
|
50
51
|
setTextHints(type: "start" | "move" | "end"): void;
|
|
51
52
|
annotateEdges(edges: Edge[], frames: LayoutFrame[]): void;
|
|
52
|
-
onMoveApply(state: MoveState, forceRecalculateEdges: () => void): ActionHandlerApplyResult;
|
|
53
|
-
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void;
|
|
54
53
|
static debugState(pluginName: string, type: "before" | "after" | string, state: MoveState, pluginState?: Record<string, any>,
|
|
55
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. */
|
|
56
55
|
key?: string | boolean): void;
|
|
@@ -84,12 +84,29 @@ export class ActionHandler {
|
|
|
84
84
|
this.shapes.splice(0, this.shapes.length, ...res.shapes);
|
|
85
85
|
return res;
|
|
86
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
|
+
}
|
|
87
96
|
onMoveEnded() {
|
|
88
97
|
if (this.activeAction) {
|
|
89
98
|
this.actions[this.activeAction].onMoveEnded();
|
|
90
99
|
}
|
|
91
100
|
this.activeAction = void 0;
|
|
92
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
|
+
}
|
|
93
110
|
setTextHints(type) {
|
|
94
111
|
this.textHints.actions = [];
|
|
95
112
|
this.textHints.errors = [];
|
|
@@ -121,23 +138,6 @@ export class ActionHandler {
|
|
|
121
138
|
}
|
|
122
139
|
}
|
|
123
140
|
}
|
|
124
|
-
onMoveApply(state, forceRecalculateEdges) {
|
|
125
|
-
if (this.activeAction) {
|
|
126
|
-
const res = this.actions[this.activeAction].onMoveApply(state, forceRecalculateEdges);
|
|
127
|
-
this.hooks.onEnd?.({ cancelled: false, applied: res });
|
|
128
|
-
return { apply: !res, result: void 0 };
|
|
129
|
-
}
|
|
130
|
-
this.hooks.onEnd?.({ cancelled: false, applied: false });
|
|
131
|
-
return { apply: true, result: void 0 };
|
|
132
|
-
}
|
|
133
|
-
cancel(e, state) {
|
|
134
|
-
if (this.activeAction) {
|
|
135
|
-
this.actions[this.activeAction].cancel(e, state);
|
|
136
|
-
}
|
|
137
|
-
this.activeAction = void 0;
|
|
138
|
-
this.eventCanceller?.(e, state);
|
|
139
|
-
this.hooks.onEnd?.({ cancelled: true, applied: false });
|
|
140
|
-
}
|
|
141
141
|
static debugState(pluginName, type, state, pluginState = {}, key) {
|
|
142
142
|
if (key === false) return;
|
|
143
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,7 +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
58
|
onMoveEnded(): void;
|
|
59
59
|
}
|
|
@@ -164,9 +164,9 @@ export class CloseAction {
|
|
|
164
164
|
if (this.debug) {
|
|
165
165
|
ActionHandler.debugState(this.name, "after", state, this.state, this.debug);
|
|
166
166
|
}
|
|
167
|
-
return true;
|
|
167
|
+
return { updateEdges: false, wasApplied: true };
|
|
168
168
|
}
|
|
169
|
-
return false;
|
|
169
|
+
return { updateEdges: true, wasApplied: false };
|
|
170
170
|
}
|
|
171
171
|
cancel() {
|
|
172
172
|
this.hooks.onCancel?.();
|
|
@@ -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,7 +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
49
|
onMoveEnded(): void;
|
|
50
50
|
cancel(): void;
|
|
51
51
|
}
|
|
@@ -123,7 +123,7 @@ export class FrameDragAction {
|
|
|
123
123
|
onMoveApply(state) {
|
|
124
124
|
const result = this.state.lastReturn;
|
|
125
125
|
if (!result || !state.moveHoveredFrame || !state.movingFrameId) {
|
|
126
|
-
return
|
|
126
|
+
return { updateEdges: false, wasApplied: false };
|
|
127
127
|
}
|
|
128
128
|
if (result instanceof Error) {
|
|
129
129
|
this.hooks.onError?.(result);
|
|
@@ -136,7 +136,7 @@ export class FrameDragAction {
|
|
|
136
136
|
ActionHandler.debugState(this.name, "after", state, this.state, this.debug);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
return true;
|
|
139
|
+
return { updateEdges: false, wasApplied: true };
|
|
140
140
|
}
|
|
141
141
|
onMoveEnded() {
|
|
142
142
|
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,7 +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
55
|
onMoveEnded(): void;
|
|
56
56
|
cancel(): void;
|
|
57
57
|
}
|
|
@@ -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. This can technically be called from "end", it should still work. */
|
|
1921
|
-
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
1922
|
-
/** 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). */
|
|
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".
|
|
1945
1926
|
*
|
|
1946
|
-
* See also {@link ActionHandler.
|
|
1927
|
+
* See also {@link ActionHandler.onMoveChange} to understand it's lifecycle as it is the extended version of.
|
|
1947
1928
|
*/
|
|
1948
|
-
|
|
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, updates edges if you passed updateEdges then aborts the handler (only onMoveEnded will fire after) . 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.
|
|
1938
|
+
*
|
|
1939
|
+
* Do not reset state here, use onMoveChange ("end").
|
|
1940
|
+
*/
|
|
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
|
*
|
|
@@ -2010,18 +2003,21 @@ export type FrameMoveStartData = {
|
|
|
2010
2003
|
frameId: FrameId;
|
|
2011
2004
|
};
|
|
2012
2005
|
export type ActionHandlerApplyResult = {
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
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;
|
|
2017
2012
|
};
|
|
2013
|
+
export type ActionResolve = ActionHandlerApplyResult;
|
|
2018
2014
|
/**
|
|
2019
2015
|
* Handler interface for drag actions.
|
|
2020
2016
|
*/
|
|
2021
|
-
export interface
|
|
2017
|
+
export interface IActionHandler {
|
|
2022
2018
|
eventHandler: (e: KeyboardEvent, state: MoveState, forceRecalculateEdges: () => void) => void;
|
|
2023
2019
|
/**
|
|
2024
|
-
* 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. See also {@link MoveChangeHandler} for the built in action handler.
|
|
2020
|
+
* 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.
|
|
2025
2021
|
*
|
|
2026
2022
|
* Can be used to save some context/info to later apply safely during onMoveApply.
|
|
2027
2023
|
*
|
|
@@ -2030,12 +2026,16 @@ export interface ActionHandler {
|
|
|
2030
2026
|
* - onMoveChange("move", ...)
|
|
2031
2027
|
* - onMoveChange("end", ...)
|
|
2032
2028
|
* - onMoveApply(...) (IF moveEnd was called with apply: true, otherwise this is skipped)
|
|
2033
|
-
* - onMoveEnded() // do cleanup here
|
|
2029
|
+
* - onMoveEnded() // do cleanup here, always called at the very end
|
|
2034
2030
|
*/
|
|
2035
|
-
onMoveChange
|
|
2031
|
+
onMoveChange<T extends "start" | "move" | "end">(type: T, e: T extends "end" ? PointerEvent | undefined : PointerEvent, state: MoveState, forceRecalculateEdges: () => void,
|
|
2032
|
+
/** Calls moveEnd with apply: false. This can technically be called from "end", it should still work. */
|
|
2033
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
2034
|
+
/** Saves result to resolve moveStart promise, updates edges if you passed updateEdges then aborts the handler (only onMoveEnded will fire after) . Not available during "end" event. It's designed for resolving from other external evente (e.g. key events). */
|
|
2035
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)): MoveChangeResult;
|
|
2036
2036
|
/**
|
|
2037
2037
|
* Called when drag will be applied. If moveEnd was called with apply false, it will not be called.
|
|
2038
|
-
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
2038
|
+
* 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.
|
|
2039
2039
|
*
|
|
2040
2040
|
* Do not use for resetting handler state, use onMoveEnded for that.
|
|
2041
2041
|
*/
|
|
@@ -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
|
|
|
@@ -255,7 +255,7 @@ export function useFrames(
|
|
|
255
255
|
}
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
function moveEnd(e?: PointerEvent, { apply = true }:
|
|
258
|
+
function moveEnd(e?: PointerEvent, { apply = true }: { apply?: boolean } = {}) {
|
|
259
259
|
if (e) {
|
|
260
260
|
const point = toWindowCoord(win.value, e)
|
|
261
261
|
movePoint.value = point
|
|
@@ -266,7 +266,7 @@ export function useFrames(
|
|
|
266
266
|
if (apply) {
|
|
267
267
|
const applyResult = handler.onMoveApply(state.value, forceRecalculateEdges)
|
|
268
268
|
moveResult = applyResult.result
|
|
269
|
-
if (applyResult.
|
|
269
|
+
if (applyResult.updateEdges) {
|
|
270
270
|
for (const frame of touchingFramesArrays.value.flat()) {
|
|
271
271
|
win!.value.frames[frame.id] = frame
|
|
272
272
|
}
|
|
@@ -281,9 +281,15 @@ export function useFrames(
|
|
|
281
281
|
function cancel(): void {
|
|
282
282
|
moveEnd(undefined, { apply: false })
|
|
283
283
|
}
|
|
284
|
-
function resolve({
|
|
284
|
+
function resolve({ updateEdges, result: value }: ActionResolve): void {
|
|
285
285
|
moveResult = value
|
|
286
|
-
|
|
286
|
+
|
|
287
|
+
if (updateEdges) {
|
|
288
|
+
for (const frame of touchingFramesArrays.value.flat()) {
|
|
289
|
+
win!.value.frames[frame.id] = frame
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
controller?.abort()
|
|
287
293
|
}
|
|
288
294
|
|
|
289
295
|
const keydownController = new AbortController()
|
|
@@ -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
|
|
@@ -129,7 +127,7 @@ export class ActionHandler<
|
|
|
129
127
|
state: MoveState,
|
|
130
128
|
forceRecalculateEdges: () => void,
|
|
131
129
|
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
132
|
-
resolve: T extends "end" ? undefined : (opts:
|
|
130
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)
|
|
133
131
|
): MoveChangeResult {
|
|
134
132
|
if (type === "start") {
|
|
135
133
|
this.eventCanceller = cancel
|
|
@@ -150,6 +148,19 @@ export class ActionHandler<
|
|
|
150
148
|
return res
|
|
151
149
|
}
|
|
152
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
|
+
|
|
153
164
|
onMoveEnded() {
|
|
154
165
|
if (this.activeAction) {
|
|
155
166
|
this.actions[this.activeAction]!.onMoveEnded()
|
|
@@ -158,6 +169,16 @@ export class ActionHandler<
|
|
|
158
169
|
this.activeAction = undefined
|
|
159
170
|
}
|
|
160
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
|
+
|
|
161
182
|
setTextHints(type: "start" | "move" | "end") {
|
|
162
183
|
// again in case it's a vue reactive object
|
|
163
184
|
this.textHints.actions = []
|
|
@@ -195,28 +216,6 @@ export class ActionHandler<
|
|
|
195
216
|
}
|
|
196
217
|
}
|
|
197
218
|
|
|
198
|
-
onMoveApply(
|
|
199
|
-
state: MoveState,
|
|
200
|
-
forceRecalculateEdges: () => void
|
|
201
|
-
): ActionHandlerApplyResult {
|
|
202
|
-
if (this.activeAction) {
|
|
203
|
-
const res = this.actions[this.activeAction]!.onMoveApply(state, forceRecalculateEdges)
|
|
204
|
-
this.hooks.onEnd?.({ cancelled: false, applied: res })
|
|
205
|
-
return { apply: !res, result: undefined }
|
|
206
|
-
}
|
|
207
|
-
this.hooks.onEnd?.({ cancelled: false, applied: false })
|
|
208
|
-
return { apply: true, result: undefined }
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
cancel(e: PointerEvent | KeyboardEvent | undefined, state: MoveState): void {
|
|
212
|
-
if (this.activeAction) {
|
|
213
|
-
this.actions[this.activeAction].cancel(e, state)
|
|
214
|
-
}
|
|
215
|
-
this.activeAction = undefined
|
|
216
|
-
this.eventCanceller?.(e, state)
|
|
217
|
-
this.hooks.onEnd?.({ cancelled: true, applied: false })
|
|
218
|
-
}
|
|
219
|
-
|
|
220
219
|
static debugState(
|
|
221
220
|
pluginName: string,
|
|
222
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>
|
|
@@ -212,15 +212,15 @@ export class CloseAction implements IAction {
|
|
|
212
212
|
return this.state.lastReturn
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
onMoveApply(state: MoveState):
|
|
215
|
+
onMoveApply(state: MoveState): ActionApplyResult {
|
|
216
216
|
if (this.state.res) {
|
|
217
217
|
const win = state.win
|
|
218
218
|
if (this.debug) { ActionHandler.debugState(this.name, "before", state, this.state, this.debug) }
|
|
219
219
|
applyFrameChanges(win, this.state.res)
|
|
220
220
|
if (this.debug) { ActionHandler.debugState(this.name, "after", state, this.state, this.debug) }
|
|
221
|
-
return true
|
|
221
|
+
return { updateEdges: false, wasApplied: true }
|
|
222
222
|
}
|
|
223
|
-
return false
|
|
223
|
+
return { updateEdges: true, wasApplied: false }
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
cancel(): void {
|
|
@@ -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
|
|
|
@@ -187,10 +187,10 @@ export class FrameDragAction implements IAction {
|
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
|
|
190
|
-
onMoveApply(state: MoveState):
|
|
190
|
+
onMoveApply(state: MoveState): ActionApplyResult {
|
|
191
191
|
const result = this.state.lastReturn
|
|
192
192
|
if (!result || !state.moveHoveredFrame || !state.movingFrameId) {
|
|
193
|
-
return
|
|
193
|
+
return { updateEdges: false, wasApplied: false }
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
if (result instanceof Error) {
|
|
@@ -201,7 +201,7 @@ export class FrameDragAction implements IAction {
|
|
|
201
201
|
if (this.debug) { ActionHandler.debugState(this.name, "after", state, this.state, this.debug) }
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
return true
|
|
204
|
+
return { updateEdges: false, wasApplied: true }
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
onMoveEnded() {
|
|
@@ -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>
|
|
@@ -219,7 +219,7 @@ export class SplitAction implements IAction {
|
|
|
219
219
|
return this.state.lastReturn
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
onMoveApply(state: MoveState):
|
|
222
|
+
onMoveApply(state: MoveState): ActionApplyResult {
|
|
223
223
|
if (this.state.res && state.moveHoveredFrame) {
|
|
224
224
|
// this only caches once per frame hovered over
|
|
225
225
|
// so the drag position is outdated, we must recalculate
|
|
@@ -230,7 +230,7 @@ export class SplitAction implements IAction {
|
|
|
230
230
|
if (this.debug) { ActionHandler.debugState(this.name, "after", state, this.state, this.debug) }
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
|
-
return true
|
|
233
|
+
return { updateEdges: false, wasApplied: true }
|
|
234
234
|
}
|
|
235
235
|
|
|
236
236
|
onMoveEnded() {
|
|
@@ -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. This can technically be called from "end", it should still work. */
|
|
526
|
-
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
527
|
-
/** 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). */
|
|
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".
|
|
529
|
+
*
|
|
530
|
+
* See also {@link ActionHandler.onMoveChange} to understand it's lifecycle as it is the extended version of.
|
|
531
|
+
*/
|
|
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, updates edges if you passed updateEdges then aborts the handler (only onMoveEnded will fire after) . 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.
|
|
550
546
|
*
|
|
551
|
-
*
|
|
547
|
+
* Do not reset state here, use onMoveChange ("end").
|
|
552
548
|
*/
|
|
553
|
-
onMoveApply: (state: MoveState, forceRecalculateEdges: () => void) =>
|
|
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
|
*
|
|
@@ -617,19 +613,25 @@ export type EdgeMoveStartData = { edge?: Edge, intersection?: IntersectionEntry
|
|
|
617
613
|
export type FrameMoveStartData = { frameId: FrameId }
|
|
618
614
|
|
|
619
615
|
export type ActionHandlerApplyResult = {
|
|
620
|
-
/** Whether
|
|
621
|
-
|
|
622
|
-
/** Value to resolve the drag promise with. Ignored if `
|
|
623
|
-
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
|
|
624
620
|
}
|
|
625
621
|
|
|
622
|
+
export type ActionApplyResult = ActionHandlerApplyResult & { wasApplied: boolean }
|
|
623
|
+
|
|
624
|
+
export type ActionResolve = ActionHandlerApplyResult
|
|
625
|
+
|
|
626
626
|
/**
|
|
627
627
|
* Handler interface for drag actions.
|
|
628
628
|
*/
|
|
629
|
-
|
|
629
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
630
|
+
export interface IActionHandler {
|
|
630
631
|
eventHandler: (e: KeyboardEvent, state: MoveState, forceRecalculateEdges: () => void) => void
|
|
632
|
+
|
|
631
633
|
/**
|
|
632
|
-
* 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. See also {@link MoveChangeHandler} for the built in action handler.
|
|
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.
|
|
633
635
|
*
|
|
634
636
|
* Can be used to save some context/info to later apply safely during onMoveApply.
|
|
635
637
|
*
|
|
@@ -638,12 +640,21 @@ export interface ActionHandler {
|
|
|
638
640
|
* - onMoveChange("move", ...)
|
|
639
641
|
* - onMoveChange("end", ...)
|
|
640
642
|
* - onMoveApply(...) (IF moveEnd was called with apply: true, otherwise this is skipped)
|
|
641
|
-
* - onMoveEnded() // do cleanup here
|
|
643
|
+
* - onMoveEnded() // do cleanup here, always called at the very end
|
|
642
644
|
*/
|
|
643
|
-
onMoveChange
|
|
645
|
+
onMoveChange<T extends "start" | "move" | "end">(
|
|
646
|
+
type: T,
|
|
647
|
+
e: T extends "end" ? PointerEvent | undefined : PointerEvent,
|
|
648
|
+
state: MoveState,
|
|
649
|
+
forceRecalculateEdges: () => void,
|
|
650
|
+
/** Calls moveEnd with apply: false. This can technically be called from "end", it should still work. */
|
|
651
|
+
cancel: (e: PointerEvent | KeyboardEvent | undefined, state: MoveState) => void,
|
|
652
|
+
/** Saves result to resolve moveStart promise, updates edges if you passed updateEdges then aborts the handler (only onMoveEnded will fire after) . Not available during "end" event. It's designed for resolving from other external evente (e.g. key events). */
|
|
653
|
+
resolve: T extends "end" ? undefined : ((opts: ActionResolve) => void)
|
|
654
|
+
): MoveChangeResult
|
|
644
655
|
/**
|
|
645
656
|
* Called when drag will be applied. If moveEnd was called with apply false, it will not be called.
|
|
646
|
-
* Return false to not apply the regular drag end changes (i.e. return false to reset to the position before dragging).
|
|
657
|
+
* 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.
|
|
647
658
|
*
|
|
648
659
|
* Do not use for resetting handler state, use onMoveEnded for that.
|
|
649
660
|
*/
|
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>
|