@witchcraft/layout 0.4.1 → 0.4.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/runtime/components/LayoutDragEdgeGrabbed.vue +1 -1
- package/dist/runtime/components/LayoutDragEdgeHandle.vue +1 -2
- package/dist/runtime/components/LayoutDragEdges.d.vue.ts +2 -2
- package/dist/runtime/components/LayoutDragEdges.vue +1 -1
- package/dist/runtime/components/LayoutDragEdges.vue.d.ts +2 -2
- package/dist/runtime/components/LayoutIntersections.vue +1 -0
- package/dist/runtime/components/LayoutWindow.d.vue.ts +3 -0
- package/dist/runtime/components/LayoutWindow.vue +3 -2
- package/dist/runtime/components/LayoutWindow.vue.d.ts +3 -0
- package/dist/runtime/composables/useFrames.d.ts +1 -0
- package/dist/runtime/composables/useFrames.js +12 -0
- package/dist/runtime/drag/CloseAction.d.ts +6 -1
- package/dist/runtime/drag/CloseAction.js +6 -1
- package/dist/runtime/drag/FrameDragAction.d.ts +10 -5
- package/dist/runtime/drag/FrameDragAction.js +6 -2
- package/dist/runtime/drag/SplitAction.d.ts +5 -1
- package/dist/runtime/drag/SplitAction.js +11 -6
- package/dist/runtime/settings.js +1 -1
- package/dist/runtime/types/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/runtime/components/LayoutDragEdgeGrabbed.vue +1 -1
- package/src/runtime/components/LayoutDragEdgeHandle.vue +1 -2
- package/src/runtime/components/LayoutDragEdges.vue +1 -1
- package/src/runtime/components/LayoutIntersections.vue +1 -0
- package/src/runtime/components/LayoutWindow.vue +6 -4
- package/src/runtime/composables/useFrames.ts +15 -0
- package/src/runtime/drag/CloseAction.ts +11 -2
- package/src/runtime/drag/FrameDragAction.ts +15 -3
- package/src/runtime/drag/SplitAction.ts +20 -7
- package/src/runtime/settings.ts +1 -1
- package/src/runtime/types/index.ts +2 -0
package/dist/module.json
CHANGED
|
@@ -2,14 +2,14 @@ declare var __VLS_1: {
|
|
|
2
2
|
css: any;
|
|
3
3
|
edge: any;
|
|
4
4
|
onPointerDown: any;
|
|
5
|
-
},
|
|
5
|
+
}, __VLS_6: {
|
|
6
6
|
css: any;
|
|
7
7
|
edge: any;
|
|
8
8
|
};
|
|
9
9
|
type __VLS_Slots = {} & {
|
|
10
10
|
handle?: (props: typeof __VLS_1) => any;
|
|
11
11
|
} & {
|
|
12
|
-
indicator?: (props: typeof
|
|
12
|
+
indicator?: (props: typeof __VLS_6) => any;
|
|
13
13
|
};
|
|
14
14
|
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
15
15
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
@@ -2,14 +2,14 @@ declare var __VLS_1: {
|
|
|
2
2
|
css: any;
|
|
3
3
|
edge: any;
|
|
4
4
|
onPointerDown: any;
|
|
5
|
-
},
|
|
5
|
+
}, __VLS_6: {
|
|
6
6
|
css: any;
|
|
7
7
|
edge: any;
|
|
8
8
|
};
|
|
9
9
|
type __VLS_Slots = {} & {
|
|
10
10
|
handle?: (props: typeof __VLS_1) => any;
|
|
11
11
|
} & {
|
|
12
|
-
indicator?: (props: typeof
|
|
12
|
+
indicator?: (props: typeof __VLS_6) => any;
|
|
13
13
|
};
|
|
14
14
|
declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
15
15
|
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
@@ -3,6 +3,8 @@ import { type DragState, type IDragAction } from "../types/index.js";
|
|
|
3
3
|
import { getUpdateWindowSizeInfo } from "../layout/getUpdateWindowSizeInfo.js";
|
|
4
4
|
import { type LayoutWindow } from "../types/index.js";
|
|
5
5
|
type __VLS_Props = {
|
|
6
|
+
/** If you really need it, you can provide your own drag action handler, note the actionHandler's prop will no longer have any effect.*/
|
|
7
|
+
dragActionHandler?: DragActionHandler<any, any>;
|
|
6
8
|
/** Custom drag action handlers. Falls back to default split/close/frame handlers if not provided. */
|
|
7
9
|
actionHandlers?: IDragAction[];
|
|
8
10
|
textHints?: {
|
|
@@ -41,6 +43,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
|
|
|
41
43
|
x: number;
|
|
42
44
|
y: number;
|
|
43
45
|
} | undefined;
|
|
46
|
+
dragDistance: number;
|
|
44
47
|
isDragging: false | "edge" | "frame";
|
|
45
48
|
showDragging: boolean;
|
|
46
49
|
draggingFrameId: string | undefined;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
flex
|
|
8
8
|
flex-col
|
|
9
9
|
`,
|
|
10
|
-
isDragging && `dragging cursor-pointer`,
|
|
10
|
+
isDragging && `dragging cursor-pointer user-select-none`,
|
|
11
11
|
requestType && `request-${requestType}`,
|
|
12
12
|
$attrs.class
|
|
13
13
|
)"
|
|
@@ -82,6 +82,7 @@ import { applyFrameChanges } from "../layout/applyFrameChanges.js";
|
|
|
82
82
|
const $attrs = useAttrs();
|
|
83
83
|
const win = defineModel("win", { type: Object, ...{ required: true } });
|
|
84
84
|
const props = defineProps({
|
|
85
|
+
dragActionHandler: { type: Object, required: false },
|
|
85
86
|
actionHandlers: { type: Array, required: false, default: void 0 },
|
|
86
87
|
textHints: { type: Array, required: false, default: () => [] },
|
|
87
88
|
textHintsTeleportTo: { type: null, required: true, default: void 0 },
|
|
@@ -91,7 +92,7 @@ const props = defineProps({
|
|
|
91
92
|
const emit = defineEmits(["isShowingDrag", "dragState"]);
|
|
92
93
|
const windowEl = ref(null);
|
|
93
94
|
const requestType = ref();
|
|
94
|
-
const dragActionHandler = new DragActionHandler(
|
|
95
|
+
const dragActionHandler = props.dragActionHandler ?? new DragActionHandler(
|
|
95
96
|
[
|
|
96
97
|
...props.actionHandlers ?? createDefaultHandlers()
|
|
97
98
|
],
|
|
@@ -3,6 +3,8 @@ import { type DragState, type IDragAction } from "../types/index.js";
|
|
|
3
3
|
import { getUpdateWindowSizeInfo } from "../layout/getUpdateWindowSizeInfo.js";
|
|
4
4
|
import { type LayoutWindow } from "../types/index.js";
|
|
5
5
|
type __VLS_Props = {
|
|
6
|
+
/** If you really need it, you can provide your own drag action handler, note the actionHandler's prop will no longer have any effect.*/
|
|
7
|
+
dragActionHandler?: DragActionHandler<any, any>;
|
|
6
8
|
/** Custom drag action handlers. Falls back to default split/close/frame handlers if not provided. */
|
|
7
9
|
actionHandlers?: IDragAction[];
|
|
8
10
|
textHints?: {
|
|
@@ -41,6 +43,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
|
|
|
41
43
|
x: number;
|
|
42
44
|
y: number;
|
|
43
45
|
} | undefined;
|
|
46
|
+
dragDistance: number;
|
|
44
47
|
isDragging: false | "edge" | "frame";
|
|
45
48
|
showDragging: boolean;
|
|
46
49
|
draggingFrameId: string | undefined;
|
|
@@ -27,6 +27,8 @@ export function useFrames(win, handler) {
|
|
|
27
27
|
const showDragging = ref(false);
|
|
28
28
|
const dragPoint = ref();
|
|
29
29
|
const dragDirections = ref({});
|
|
30
|
+
let dragStartPoint;
|
|
31
|
+
const dragDistance = ref(-1);
|
|
30
32
|
const draggingIntersection = ref(void 0);
|
|
31
33
|
const isDraggingFromWindowEdge = ref(false);
|
|
32
34
|
const frameDragFrameId = ref();
|
|
@@ -64,6 +66,7 @@ export function useFrames(win, handler) {
|
|
|
64
66
|
const state = computed(() => ({
|
|
65
67
|
dragDirections: dragDirections.value,
|
|
66
68
|
dragPoint: dragPoint.value,
|
|
69
|
+
dragDistance: dragDistance.value,
|
|
67
70
|
isDragging: isDragging.value,
|
|
68
71
|
showDragging: showDragging.value,
|
|
69
72
|
draggingFrameId: frameDragFrameId.value,
|
|
@@ -80,10 +83,12 @@ export function useFrames(win, handler) {
|
|
|
80
83
|
}));
|
|
81
84
|
let controller;
|
|
82
85
|
function resetState() {
|
|
86
|
+
dragStartPoint = void 0;
|
|
83
87
|
draggingEdges.value = [];
|
|
84
88
|
draggingIntersection.value = void 0;
|
|
85
89
|
isDragging.value = false;
|
|
86
90
|
dragPoint.value = void 0;
|
|
91
|
+
dragDistance.value = -1;
|
|
87
92
|
touchingFrames.value = [];
|
|
88
93
|
frameDragFrameId.value = void 0;
|
|
89
94
|
dragDirStore.reset();
|
|
@@ -98,6 +103,7 @@ export function useFrames(win, handler) {
|
|
|
98
103
|
window.addEventListener("pointerup", dragEnd, { signal: controller.signal });
|
|
99
104
|
const point = toWindowCoord(win.value, e);
|
|
100
105
|
dragPoint.value = point;
|
|
106
|
+
dragStartPoint = { ...point };
|
|
101
107
|
dragDirStore.update(point);
|
|
102
108
|
isDragging.value = type;
|
|
103
109
|
showDragging.value = true;
|
|
@@ -136,6 +142,12 @@ export function useFrames(win, handler) {
|
|
|
136
142
|
const point = toWindowCoord(win.value, e);
|
|
137
143
|
const didChange = dragDirStore.update(point);
|
|
138
144
|
dragPoint.value = point;
|
|
145
|
+
dragDistance.value = 0;
|
|
146
|
+
if (dragStartPoint) {
|
|
147
|
+
dragDistance.value = Math.sqrt(
|
|
148
|
+
Math.pow(point.x - dragStartPoint.x, 2) + Math.pow(point.y - dragStartPoint.y, 2)
|
|
149
|
+
);
|
|
150
|
+
}
|
|
139
151
|
if (!didChange) return;
|
|
140
152
|
const res = handler.onDragChange("move", e, state.value, forceRecalculateEdges, cancel);
|
|
141
153
|
showDragging.value = res.showDragging ?? true;
|
|
@@ -4,6 +4,7 @@ import type { KnownError } from "../utils/KnownError.js";
|
|
|
4
4
|
export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError>;
|
|
5
5
|
export declare class CloseAction implements IDragAction {
|
|
6
6
|
name: "close";
|
|
7
|
+
minDragDistance: number;
|
|
7
8
|
state: {
|
|
8
9
|
allowed: true;
|
|
9
10
|
force: boolean;
|
|
@@ -23,7 +24,9 @@ export declare class CloseAction implements IDragAction {
|
|
|
23
24
|
errors: string[];
|
|
24
25
|
};
|
|
25
26
|
closeHints: {
|
|
26
|
-
actions: string[]
|
|
27
|
+
actions: string[] | ((state: {
|
|
28
|
+
force: boolean;
|
|
29
|
+
}) => string[]);
|
|
27
30
|
transformError: (e: KnownError) => string;
|
|
28
31
|
};
|
|
29
32
|
handleEvent: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean | "force";
|
|
@@ -38,6 +41,8 @@ export declare class CloseAction implements IDragAction {
|
|
|
38
41
|
modifyDecos?: CloseAction["modifyDecos"], hooks?: CloseAction["hooks"], config?: {
|
|
39
42
|
debug?: boolean | string;
|
|
40
43
|
closeHints?: Partial<CloseAction["closeHints"]>;
|
|
44
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
45
|
+
minDragDistance?: number;
|
|
41
46
|
});
|
|
42
47
|
reset(): void;
|
|
43
48
|
private _getDecos;
|
|
@@ -7,6 +7,7 @@ import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js";
|
|
|
7
7
|
import { getCloseFrameInfo } from "../layout/getCloseFrameInfo.js";
|
|
8
8
|
export class CloseAction {
|
|
9
9
|
name = "close";
|
|
10
|
+
minDragDistance = 5;
|
|
10
11
|
state = {};
|
|
11
12
|
// this is initialized by this.reset()
|
|
12
13
|
debug = false;
|
|
@@ -30,6 +31,7 @@ export class CloseAction {
|
|
|
30
31
|
if (modifyDecos !== void 0) this.modifyDecos = modifyDecos;
|
|
31
32
|
this.hooks = hooks;
|
|
32
33
|
if (config?.debug) this.debug = true;
|
|
34
|
+
if (config?.minDragDistance !== void 0) this.minDragDistance = config.minDragDistance;
|
|
33
35
|
this.reset();
|
|
34
36
|
}
|
|
35
37
|
reset() {
|
|
@@ -73,7 +75,7 @@ export class CloseAction {
|
|
|
73
75
|
this.textHints.actions = [];
|
|
74
76
|
this.textHints.errors = [this.closeHints.transformError(result)];
|
|
75
77
|
} else {
|
|
76
|
-
this.textHints.actions = this.closeHints.actions;
|
|
78
|
+
this.textHints.actions = typeof this.closeHints.actions === "function" ? this.closeHints.actions({ force: this.state.force }) : this.closeHints.actions;
|
|
77
79
|
this.textHints.errors = [];
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -97,6 +99,9 @@ export class CloseAction {
|
|
|
97
99
|
return false;
|
|
98
100
|
}
|
|
99
101
|
onDragChange(_type, _e, state) {
|
|
102
|
+
if (state.dragDistance <= this.minDragDistance) {
|
|
103
|
+
return { updateEdges: false, shapes: [] };
|
|
104
|
+
}
|
|
100
105
|
const {
|
|
101
106
|
touchingFramesArrays,
|
|
102
107
|
dragDirections,
|
|
@@ -2,6 +2,7 @@ import type { ActionDragChangeResult, DragState, DragZone, FrameDragDeco, IDragA
|
|
|
2
2
|
import type { KnownError } from "../utils/KnownError.js";
|
|
3
3
|
export declare class FrameDragAction implements IDragAction {
|
|
4
4
|
name: "frameDrag";
|
|
5
|
+
minDragDistance: number;
|
|
5
6
|
state: {
|
|
6
7
|
lastReturn?: LayoutChange<"split" | "swap" | "rearrange" | "dock"> | KnownError;
|
|
7
8
|
};
|
|
@@ -13,11 +14,13 @@ export declare class FrameDragAction implements IDragAction {
|
|
|
13
14
|
handleEvent: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean;
|
|
14
15
|
dragHints: {
|
|
15
16
|
actions: {
|
|
16
|
-
split
|
|
17
|
-
swap
|
|
18
|
-
rearrange
|
|
19
|
-
dock
|
|
20
|
-
}
|
|
17
|
+
split?: string;
|
|
18
|
+
swap?: string;
|
|
19
|
+
rearrange?: string;
|
|
20
|
+
dock?: string;
|
|
21
|
+
} | ((state: {
|
|
22
|
+
type: "split" | "swap" | "rearrange" | "dock";
|
|
23
|
+
}) => string[]);
|
|
21
24
|
transformError: (e: KnownError) => string;
|
|
22
25
|
};
|
|
23
26
|
modifyDecos: (shapes: FrameDragDeco[]) => void;
|
|
@@ -30,6 +33,8 @@ export declare class FrameDragAction implements IDragAction {
|
|
|
30
33
|
/** Modify the created decos before they are rendered. */
|
|
31
34
|
modifyDecos?: FrameDragAction["modifyDecos"], hooks?: FrameDragAction["hooks"], config?: {
|
|
32
35
|
debug?: boolean | string;
|
|
36
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
37
|
+
minDragDistance?: number;
|
|
33
38
|
});
|
|
34
39
|
reset(): void;
|
|
35
40
|
setTextHints(result: LayoutChange<"split" | "swap" | "rearrange" | "dock"> | KnownError | undefined): void;
|
|
@@ -8,6 +8,7 @@ import { getFrameSwapInfo } from "../layout/getFrameSwapInfo.js";
|
|
|
8
8
|
import { settings } from "../settings.js";
|
|
9
9
|
export class FrameDragAction {
|
|
10
10
|
name = "frameDrag";
|
|
11
|
+
minDragDistance = 5;
|
|
11
12
|
state = {
|
|
12
13
|
lastReturn: void 0
|
|
13
14
|
};
|
|
@@ -31,6 +32,7 @@ export class FrameDragAction {
|
|
|
31
32
|
if (modifyDecos !== void 0) this.modifyDecos = modifyDecos;
|
|
32
33
|
this.hooks = hooks;
|
|
33
34
|
if (config?.debug) this.debug = true;
|
|
35
|
+
if (config?.minDragDistance !== void 0) this.minDragDistance = config.minDragDistance;
|
|
34
36
|
this.reset();
|
|
35
37
|
}
|
|
36
38
|
reset() {
|
|
@@ -46,8 +48,7 @@ export class FrameDragAction {
|
|
|
46
48
|
this.textHints.actions = [];
|
|
47
49
|
this.textHints.errors = [this.dragHints.transformError(result)];
|
|
48
50
|
} else {
|
|
49
|
-
|
|
50
|
-
this.textHints.actions = [text];
|
|
51
|
+
this.textHints.actions = typeof this.dragHints.actions === "function" ? this.dragHints.actions({ type: result.info }) : this.dragHints.actions[result.info] !== void 0 ? [this.dragHints.actions[result.info]] : [];
|
|
51
52
|
this.textHints.errors = [];
|
|
52
53
|
}
|
|
53
54
|
}
|
|
@@ -93,6 +94,9 @@ export class FrameDragAction {
|
|
|
93
94
|
return false;
|
|
94
95
|
}
|
|
95
96
|
onDragChange(_type, _e, state) {
|
|
97
|
+
if (state.dragDistance <= this.minDragDistance) {
|
|
98
|
+
return { updateEdges: false, shapes: [], showDragging: false };
|
|
99
|
+
}
|
|
96
100
|
const { win, draggingFrameId, dragHoveredFrame } = state;
|
|
97
101
|
const matchedZone = getDragZones(state, settings.zoneSizes);
|
|
98
102
|
if (!matchedZone) {
|
|
@@ -2,8 +2,10 @@ import { getFrameSplitInfo } from "../layout/getFrameSplitInfo.js";
|
|
|
2
2
|
import type { ActionDragChangeResult, DragState, IDragAction, 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
|
+
export type DragChangeType = "start" | "move" | "end";
|
|
5
6
|
export declare class SplitAction implements IDragAction {
|
|
6
7
|
name: "split";
|
|
8
|
+
minDragDistance: number;
|
|
7
9
|
state: {
|
|
8
10
|
allowed: true;
|
|
9
11
|
res: SplitInfo;
|
|
@@ -21,7 +23,7 @@ export declare class SplitAction implements IDragAction {
|
|
|
21
23
|
errors: string[];
|
|
22
24
|
};
|
|
23
25
|
splitHints: {
|
|
24
|
-
|
|
26
|
+
actions: string[] | ((type: DragChangeType) => string[]);
|
|
25
27
|
transformError: (e: KnownError) => string;
|
|
26
28
|
};
|
|
27
29
|
handleEvent: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean;
|
|
@@ -36,6 +38,8 @@ export declare class SplitAction implements IDragAction {
|
|
|
36
38
|
modifyDecos?: SplitAction["modifyDecos"], hooks?: SplitAction["hooks"], config?: {
|
|
37
39
|
debug?: boolean | string;
|
|
38
40
|
splitHints?: Partial<SplitAction["splitHints"]>;
|
|
41
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
42
|
+
minDragDistance?: number;
|
|
39
43
|
});
|
|
40
44
|
reset(): void;
|
|
41
45
|
getDecos(state: DragState): SplitDeco[];
|
|
@@ -6,12 +6,13 @@ import { createSplitDecoFromDrag } from "../layout/createSplitDecoFromDrag.js";
|
|
|
6
6
|
import { getFrameSplitInfo } from "../layout/getFrameSplitInfo.js";
|
|
7
7
|
export class SplitAction {
|
|
8
8
|
name = "split";
|
|
9
|
+
minDragDistance = 5;
|
|
9
10
|
state = {};
|
|
10
11
|
// this is initialized by `this.reset()`
|
|
11
12
|
debug = false;
|
|
12
13
|
textHints = { actions: [], errors: [] };
|
|
13
14
|
splitHints = {
|
|
14
|
-
|
|
15
|
+
actions: ["Hold Alt to Split"],
|
|
15
16
|
transformError: (e) => e.message
|
|
16
17
|
};
|
|
17
18
|
handleEvent = (e, state) => e.altKey || state.isDraggingFromWindowEdge;
|
|
@@ -24,7 +25,8 @@ export class SplitAction {
|
|
|
24
25
|
this.hooks = hooks;
|
|
25
26
|
this.reset();
|
|
26
27
|
if (config?.debug) this.debug = true;
|
|
27
|
-
if (config?.
|
|
28
|
+
if (config?.minDragDistance !== void 0) this.minDragDistance = config.minDragDistance;
|
|
29
|
+
if (config?.splitHints?.actions) this.splitHints.actions = config.splitHints.actions;
|
|
28
30
|
if (config?.splitHints?.transformError) this.splitHints.transformError = config.splitHints.transformError;
|
|
29
31
|
}
|
|
30
32
|
reset() {
|
|
@@ -62,7 +64,7 @@ export class SplitAction {
|
|
|
62
64
|
canHandleRequest(e, state) {
|
|
63
65
|
const { draggingEdges } = state;
|
|
64
66
|
if (draggingEdges.length !== 1) return false;
|
|
65
|
-
this.setTextHints(state.isDragging === "edge" ? true : void 0);
|
|
67
|
+
this.setTextHints(state.isDragging === "edge" && !state.isDraggingFromWindowEdge ? true : void 0);
|
|
66
68
|
if (this.handleEvent(e, state)) {
|
|
67
69
|
this.hooks.onStart?.();
|
|
68
70
|
return true;
|
|
@@ -78,7 +80,7 @@ export class SplitAction {
|
|
|
78
80
|
this.textHints.actions = [];
|
|
79
81
|
this.textHints.errors = [this.splitHints.transformError(result)];
|
|
80
82
|
} else {
|
|
81
|
-
this.textHints.actions =
|
|
83
|
+
this.textHints.actions = typeof this.splitHints.actions === "function" ? this.splitHints.actions("move") : this.splitHints.actions;
|
|
82
84
|
this.textHints.errors = [];
|
|
83
85
|
}
|
|
84
86
|
}
|
|
@@ -103,7 +105,7 @@ export class SplitAction {
|
|
|
103
105
|
dragDirections[oppositeOrientation],
|
|
104
106
|
dragPoint
|
|
105
107
|
);
|
|
106
|
-
this.setTextHints(canSplit);
|
|
108
|
+
this.setTextHints(state.isDragging === "edge" && !state.isDraggingFromWindowEdge ? canSplit : void 0);
|
|
107
109
|
if (!(canSplit instanceof Error)) {
|
|
108
110
|
this.state.allowed = true;
|
|
109
111
|
this.state.res = canSplit;
|
|
@@ -117,7 +119,10 @@ export class SplitAction {
|
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
onDragChange(_type, _e, state) {
|
|
120
|
-
const { dragHoveredFrame } = state;
|
|
122
|
+
const { dragHoveredFrame, dragDistance } = state;
|
|
123
|
+
if (dragDistance <= this.minDragDistance) {
|
|
124
|
+
return { updateEdges: false, shapes: [], showDragging: false };
|
|
125
|
+
}
|
|
121
126
|
let ok = false;
|
|
122
127
|
if (dragHoveredFrame) {
|
|
123
128
|
if (this.state.lastPoint?.x === state.dragPoint?.x && this.state.lastPoint?.y === state.dragPoint?.y && this.state.lastReturn) {
|
package/dist/runtime/settings.js
CHANGED
|
@@ -1808,6 +1808,8 @@ export type DragState = {
|
|
|
1808
1808
|
dragDirections: Record<Orientation, Direction | undefined>;
|
|
1809
1809
|
/** The curren point (in scaled window coordinates) the user is dragging at. */
|
|
1810
1810
|
dragPoint?: Point;
|
|
1811
|
+
/** Cumulative pixel distance the user has dragged from the initial click point. 0 on start, increases on each move. */
|
|
1812
|
+
dragDistance: number;
|
|
1811
1813
|
/** Whether the user is currently dragging and what type of drag. Is truthy string during all drag events. */
|
|
1812
1814
|
isDragging: boolean | "frame" | "edge";
|
|
1813
1815
|
/** Whether to show the moved frames while dragging. */
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
flex
|
|
8
8
|
flex-col
|
|
9
9
|
`,
|
|
10
|
-
isDragging && `dragging cursor-pointer`,
|
|
10
|
+
isDragging && `dragging cursor-pointer user-select-none`,
|
|
11
11
|
requestType && `request-${requestType}`,
|
|
12
12
|
($attrs as any).class
|
|
13
13
|
)"
|
|
@@ -90,6 +90,8 @@ const $attrs = useAttrs()
|
|
|
90
90
|
const win = defineModel<LayoutWindow>("win", { required: true })
|
|
91
91
|
|
|
92
92
|
const props = withDefaults(defineProps<{
|
|
93
|
+
/** If you really need it, you can provide your own drag action handler, note the actionHandler's prop will no longer have any effect.*/
|
|
94
|
+
dragActionHandler?: DragActionHandler<any, any>
|
|
93
95
|
/** Custom drag action handlers. Falls back to default split/close/frame handlers if not provided. */
|
|
94
96
|
actionHandlers?: IDragAction[]
|
|
95
97
|
textHints?: {text:string, classes?:string}[]
|
|
@@ -120,9 +122,9 @@ const windowEl = ref<HTMLElement | null>(null)
|
|
|
120
122
|
|
|
121
123
|
const requestType = ref<string | undefined | string>()
|
|
122
124
|
|
|
123
|
-
const dragActionHandler = new DragActionHandler(
|
|
125
|
+
const dragActionHandler = props.dragActionHandler ?? new DragActionHandler(
|
|
124
126
|
[
|
|
125
|
-
...(props.actionHandlers ?? createDefaultHandlers())
|
|
127
|
+
...(props.actionHandlers ?? createDefaultHandlers())
|
|
126
128
|
],
|
|
127
129
|
{
|
|
128
130
|
onEvent: (e, cancel) => {
|
|
@@ -132,7 +134,7 @@ const dragActionHandler = new DragActionHandler(
|
|
|
132
134
|
}
|
|
133
135
|
},
|
|
134
136
|
onRequestChange: type => {
|
|
135
|
-
requestType.value = type
|
|
137
|
+
requestType.value = type as any
|
|
136
138
|
},
|
|
137
139
|
onEnd: () => {
|
|
138
140
|
requestType.value = undefined
|
|
@@ -59,6 +59,9 @@ export function useFrames(
|
|
|
59
59
|
|
|
60
60
|
const dragDirections = ref<Record<Orientation, Direction | undefined>>({} as any)
|
|
61
61
|
|
|
62
|
+
let dragStartPoint: Point | undefined
|
|
63
|
+
const dragDistance = ref(-1)
|
|
64
|
+
|
|
62
65
|
const draggingIntersection = ref<IntersectionEntry | undefined>(undefined)
|
|
63
66
|
const isDraggingFromWindowEdge = ref<boolean>(false)
|
|
64
67
|
|
|
@@ -110,6 +113,7 @@ export function useFrames(
|
|
|
110
113
|
const state = computed(() => ({
|
|
111
114
|
dragDirections: dragDirections.value,
|
|
112
115
|
dragPoint: dragPoint.value,
|
|
116
|
+
dragDistance: dragDistance.value,
|
|
113
117
|
isDragging: isDragging.value,
|
|
114
118
|
showDragging: showDragging.value,
|
|
115
119
|
draggingFrameId: frameDragFrameId.value,
|
|
@@ -128,10 +132,13 @@ export function useFrames(
|
|
|
128
132
|
let controller: AbortController
|
|
129
133
|
|
|
130
134
|
function resetState(): void {
|
|
135
|
+
dragStartPoint = undefined
|
|
136
|
+
|
|
131
137
|
draggingEdges.value = []
|
|
132
138
|
draggingIntersection.value = undefined
|
|
133
139
|
isDragging.value = false
|
|
134
140
|
dragPoint.value = undefined
|
|
141
|
+
dragDistance.value = -1
|
|
135
142
|
touchingFrames.value = []
|
|
136
143
|
frameDragFrameId.value = undefined
|
|
137
144
|
dragDirStore.reset()
|
|
@@ -154,6 +161,7 @@ export function useFrames(
|
|
|
154
161
|
|
|
155
162
|
const point = toWindowCoord(win.value, e)
|
|
156
163
|
dragPoint.value = point
|
|
164
|
+
dragStartPoint = { ...point }
|
|
157
165
|
dragDirStore.update(point)
|
|
158
166
|
|
|
159
167
|
isDragging.value = type
|
|
@@ -205,6 +213,13 @@ export function useFrames(
|
|
|
205
213
|
const point = toWindowCoord(win.value, e)
|
|
206
214
|
const didChange = dragDirStore.update(point)
|
|
207
215
|
dragPoint.value = point
|
|
216
|
+
// at least one drag move has happened
|
|
217
|
+
dragDistance.value = 0
|
|
218
|
+
if (dragStartPoint) {
|
|
219
|
+
dragDistance.value = Math.sqrt(
|
|
220
|
+
Math.pow(point.x - dragStartPoint.x, 2) + Math.pow(point.y - dragStartPoint.y, 2)
|
|
221
|
+
)
|
|
222
|
+
}
|
|
208
223
|
if (!didChange) return
|
|
209
224
|
const res = handler.onDragChange("move", e, state.value, forceRecalculateEdges, cancel)
|
|
210
225
|
|
|
@@ -13,6 +13,7 @@ export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError
|
|
|
13
13
|
|
|
14
14
|
export class CloseAction implements IDragAction {
|
|
15
15
|
name = "close" as const
|
|
16
|
+
minDragDistance = 5
|
|
16
17
|
|
|
17
18
|
state: {
|
|
18
19
|
allowed: true
|
|
@@ -32,7 +33,7 @@ export class CloseAction implements IDragAction {
|
|
|
32
33
|
textHints: { actions: string[], errors: string[] } = { actions: [], errors: [] }
|
|
33
34
|
|
|
34
35
|
closeHints: {
|
|
35
|
-
actions: string[]
|
|
36
|
+
actions: string[] | ((state: { force: boolean }) => string[])
|
|
36
37
|
transformError: (e: KnownError) => string
|
|
37
38
|
} = {
|
|
38
39
|
actions: ["Hold Shift to Close", "Hold Ctrl+Shift to Force Close"],
|
|
@@ -62,12 +63,15 @@ export class CloseAction implements IDragAction {
|
|
|
62
63
|
config?: {
|
|
63
64
|
debug?: boolean | string
|
|
64
65
|
closeHints?: Partial<CloseAction["closeHints"]>
|
|
66
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
67
|
+
minDragDistance?: number
|
|
65
68
|
}
|
|
66
69
|
) {
|
|
67
70
|
if (handleEvent !== undefined) this.handleEvent = handleEvent
|
|
68
71
|
if (modifyDecos !== undefined) this.modifyDecos = modifyDecos
|
|
69
72
|
this.hooks = hooks
|
|
70
73
|
if (config?.debug) this.debug = true
|
|
74
|
+
if (config?.minDragDistance !== undefined) this.minDragDistance = config.minDragDistance
|
|
71
75
|
this.reset()
|
|
72
76
|
}
|
|
73
77
|
|
|
@@ -116,7 +120,9 @@ export class CloseAction implements IDragAction {
|
|
|
116
120
|
this.textHints.actions = []
|
|
117
121
|
this.textHints.errors = [this.closeHints.transformError(result)]
|
|
118
122
|
} else {
|
|
119
|
-
this.textHints.actions = this.closeHints.actions
|
|
123
|
+
this.textHints.actions = typeof this.closeHints.actions === "function"
|
|
124
|
+
? this.closeHints.actions({ force: this.state.force })
|
|
125
|
+
: this.closeHints.actions
|
|
120
126
|
this.textHints.errors = []
|
|
121
127
|
}
|
|
122
128
|
}
|
|
@@ -149,6 +155,9 @@ export class CloseAction implements IDragAction {
|
|
|
149
155
|
_e: PointerEvent | undefined,
|
|
150
156
|
state: DragState
|
|
151
157
|
): ActionDragChangeResult {
|
|
158
|
+
if (state.dragDistance <= this.minDragDistance) {
|
|
159
|
+
return { updateEdges: false, shapes: [] }
|
|
160
|
+
}
|
|
152
161
|
const {
|
|
153
162
|
touchingFramesArrays,
|
|
154
163
|
dragDirections,
|
|
@@ -13,6 +13,9 @@ import type { KnownError } from "../utils/KnownError.js"
|
|
|
13
13
|
|
|
14
14
|
export class FrameDragAction implements IDragAction {
|
|
15
15
|
name = "frameDrag" as const
|
|
16
|
+
|
|
17
|
+
minDragDistance = 5
|
|
18
|
+
|
|
16
19
|
state: {
|
|
17
20
|
lastReturn?: LayoutChange<"split" | "swap" | "rearrange" | "dock"> | KnownError
|
|
18
21
|
} = {
|
|
@@ -26,7 +29,7 @@ export class FrameDragAction implements IDragAction {
|
|
|
26
29
|
= (_e: PointerEvent | KeyboardEvent, state: DragState) => state.isDragging === "frame"
|
|
27
30
|
|
|
28
31
|
dragHints: {
|
|
29
|
-
actions: { split
|
|
32
|
+
actions: { split?: string, swap?: string, rearrange?: string, dock?: string } | ((state: { type: "split" | "swap" | "rearrange" | "dock" }) => string[])
|
|
30
33
|
transformError: (e: KnownError) => string
|
|
31
34
|
} = {
|
|
32
35
|
actions: {
|
|
@@ -52,12 +55,15 @@ export class FrameDragAction implements IDragAction {
|
|
|
52
55
|
hooks: FrameDragAction["hooks"] = {},
|
|
53
56
|
config?: {
|
|
54
57
|
debug?: boolean | string
|
|
58
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
59
|
+
minDragDistance?: number
|
|
55
60
|
}
|
|
56
61
|
) {
|
|
57
62
|
if (handleEvent !== undefined) this.handleEvent = handleEvent
|
|
58
63
|
if (modifyDecos !== undefined) this.modifyDecos = modifyDecos
|
|
59
64
|
this.hooks = hooks
|
|
60
65
|
if (config?.debug) this.debug = true
|
|
66
|
+
if (config?.minDragDistance !== undefined) this.minDragDistance = config.minDragDistance
|
|
61
67
|
|
|
62
68
|
this.reset()
|
|
63
69
|
}
|
|
@@ -76,8 +82,11 @@ export class FrameDragAction implements IDragAction {
|
|
|
76
82
|
this.textHints.actions = []
|
|
77
83
|
this.textHints.errors = [this.dragHints.transformError(result)]
|
|
78
84
|
} else {
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
this.textHints.actions = typeof this.dragHints.actions === "function"
|
|
86
|
+
? this.dragHints.actions({ type: result.info })
|
|
87
|
+
: this.dragHints.actions[result.info] !== undefined
|
|
88
|
+
? [this.dragHints.actions[result.info]!]
|
|
89
|
+
: []
|
|
81
90
|
this.textHints.errors = []
|
|
82
91
|
}
|
|
83
92
|
}
|
|
@@ -146,6 +155,9 @@ export class FrameDragAction implements IDragAction {
|
|
|
146
155
|
_e: PointerEvent | undefined,
|
|
147
156
|
state: DragState
|
|
148
157
|
): ActionDragChangeResult {
|
|
158
|
+
if (state.dragDistance <= this.minDragDistance) {
|
|
159
|
+
return { updateEdges: false, shapes: [], showDragging: false }
|
|
160
|
+
}
|
|
149
161
|
const { win, draggingFrameId, dragHoveredFrame } = state
|
|
150
162
|
const matchedZone = getDragZones(state, settings.zoneSizes)
|
|
151
163
|
|
|
@@ -12,8 +12,11 @@ export type SplitInfo = Exclude<ReturnType<typeof getFrameSplitInfo>, KnownError
|
|
|
12
12
|
|
|
13
13
|
// note that we dont annotateEdges because is possible to forexample drag from a window edge to a frame that can be split, moving over a collapsed frame that was sharing the edge but can't be split
|
|
14
14
|
|
|
15
|
+
export type DragChangeType = "start" | "move" | "end"
|
|
16
|
+
|
|
15
17
|
export class SplitAction implements IDragAction {
|
|
16
18
|
name = "split" as const
|
|
19
|
+
minDragDistance = 5
|
|
17
20
|
|
|
18
21
|
state: {
|
|
19
22
|
allowed: true
|
|
@@ -30,10 +33,10 @@ export class SplitAction implements IDragAction {
|
|
|
30
33
|
debug: boolean | string = false
|
|
31
34
|
textHints: { actions: string[], errors: string[] } = { actions: [], errors: [] }
|
|
32
35
|
splitHints: {
|
|
33
|
-
|
|
36
|
+
actions: string[] | ((type: DragChangeType) => string[])
|
|
34
37
|
transformError: (e: KnownError) => string
|
|
35
38
|
} = {
|
|
36
|
-
|
|
39
|
+
actions: ["Hold Alt to Split"],
|
|
37
40
|
transformError: e => e.message
|
|
38
41
|
}
|
|
39
42
|
|
|
@@ -55,6 +58,8 @@ export class SplitAction implements IDragAction {
|
|
|
55
58
|
config?: {
|
|
56
59
|
debug?: boolean | string
|
|
57
60
|
splitHints?: Partial<SplitAction["splitHints"]>
|
|
61
|
+
/** Minimum pixel distance the user must drag before the action is allowed (decos shown and action applied). Defaults to 5. */
|
|
62
|
+
minDragDistance?: number
|
|
58
63
|
}
|
|
59
64
|
) {
|
|
60
65
|
if (handleEvent !== undefined) this.handleEvent = handleEvent
|
|
@@ -63,7 +68,8 @@ export class SplitAction implements IDragAction {
|
|
|
63
68
|
this.hooks = hooks
|
|
64
69
|
this.reset()
|
|
65
70
|
if (config?.debug) this.debug = true
|
|
66
|
-
if (config?.
|
|
71
|
+
if (config?.minDragDistance !== undefined) this.minDragDistance = config.minDragDistance
|
|
72
|
+
if (config?.splitHints?.actions) this.splitHints.actions = config.splitHints.actions
|
|
67
73
|
if (config?.splitHints?.transformError) this.splitHints.transformError = config.splitHints.transformError
|
|
68
74
|
}
|
|
69
75
|
|
|
@@ -104,7 +110,8 @@ export class SplitAction implements IDragAction {
|
|
|
104
110
|
canHandleRequest(e: PointerEvent | KeyboardEvent, state: DragState): boolean {
|
|
105
111
|
const { draggingEdges } = state
|
|
106
112
|
if (draggingEdges.length !== 1) return false
|
|
107
|
-
|
|
113
|
+
// hint should not be shown when dragging from window edge but we should still handle the event
|
|
114
|
+
this.setTextHints(state.isDragging === "edge" && !state.isDraggingFromWindowEdge ? true : undefined)
|
|
108
115
|
if (this.handleEvent(e, state)) {
|
|
109
116
|
this.hooks.onStart?.()
|
|
110
117
|
return true
|
|
@@ -121,7 +128,10 @@ export class SplitAction implements IDragAction {
|
|
|
121
128
|
this.textHints.actions = []
|
|
122
129
|
this.textHints.errors = [this.splitHints.transformError(result)]
|
|
123
130
|
} else {
|
|
124
|
-
this.textHints.actions =
|
|
131
|
+
this.textHints.actions = typeof this.splitHints.actions === "function"
|
|
132
|
+
? this.splitHints.actions("move")
|
|
133
|
+
: this.splitHints.actions
|
|
134
|
+
|
|
125
135
|
this.textHints.errors = []
|
|
126
136
|
}
|
|
127
137
|
}
|
|
@@ -149,7 +159,7 @@ export class SplitAction implements IDragAction {
|
|
|
149
159
|
dragDirections[oppositeOrientation]!,
|
|
150
160
|
dragPoint!
|
|
151
161
|
)
|
|
152
|
-
this.setTextHints(canSplit)
|
|
162
|
+
this.setTextHints(state.isDragging === "edge" && !state.isDraggingFromWindowEdge ? canSplit : undefined)
|
|
153
163
|
if (!(canSplit instanceof Error)) {
|
|
154
164
|
this.state.allowed = true
|
|
155
165
|
this.state.res = canSplit
|
|
@@ -168,7 +178,10 @@ export class SplitAction implements IDragAction {
|
|
|
168
178
|
_e: PointerEvent | undefined,
|
|
169
179
|
state: DragState
|
|
170
180
|
): ActionDragChangeResult {
|
|
171
|
-
const { dragHoveredFrame } = state
|
|
181
|
+
const { dragHoveredFrame, dragDistance } = state
|
|
182
|
+
if (dragDistance <= this.minDragDistance) {
|
|
183
|
+
return { updateEdges: false, shapes: [], showDragging: false }
|
|
184
|
+
}
|
|
172
185
|
let ok = false
|
|
173
186
|
if (dragHoveredFrame) {
|
|
174
187
|
if (this.state.lastPoint?.x === state.dragPoint?.x && this.state.lastPoint?.y === state.dragPoint?.y && this.state.lastReturn) {
|
package/src/runtime/settings.ts
CHANGED
|
@@ -442,6 +442,8 @@ export type DragState = {
|
|
|
442
442
|
dragDirections: Record<Orientation, Direction | undefined>
|
|
443
443
|
/** The curren point (in scaled window coordinates) the user is dragging at. */
|
|
444
444
|
dragPoint?: Point
|
|
445
|
+
/** Cumulative pixel distance the user has dragged from the initial click point. 0 on start, increases on each move. */
|
|
446
|
+
dragDistance: number
|
|
445
447
|
/** Whether the user is currently dragging and what type of drag. Is truthy string during all drag events. */
|
|
446
448
|
isDragging: boolean | "frame" | "edge"
|
|
447
449
|
/** Whether to show the moved frames while dragging. */
|