@witchcraft/layout 0.4.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@witchcraft/layout",
3
3
  "configKey": "witchcraftLayout",
4
- "version": "0.4.2",
4
+ "version": "0.4.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -7,7 +7,7 @@
7
7
  z-20
8
8
  bg-accent-500
9
9
  cursor-pointer
10
- [&.request-split]:hidden
10
+ [.request-split_&]:hidden
11
11
  `,
12
12
  $attrs.class
13
13
  )"
@@ -7,8 +7,7 @@
7
7
  drag-edge
8
8
  z-20
9
9
  hover:cursor-pointer
10
-
11
- [&.request-split]:hidden
10
+ [.request-split_&]:hidden
12
11
  `,
13
12
  edge.error && `
14
13
  drag-edge-errored
@@ -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;
@@ -744,6 +744,7 @@ export declare function useFrames(win: Ref<LayoutWindow>, handler: {
744
744
  x: number;
745
745
  y: number;
746
746
  } | undefined;
747
+ dragDistance: number;
747
748
  isDragging: false | "edge" | "frame";
748
749
  showDragging: boolean;
749
750
  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;
@@ -40,6 +41,8 @@ export declare class CloseAction implements IDragAction {
40
41
  modifyDecos?: CloseAction["modifyDecos"], hooks?: CloseAction["hooks"], config?: {
41
42
  debug?: boolean | string;
42
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;
43
46
  });
44
47
  reset(): void;
45
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() {
@@ -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
  };
@@ -32,6 +33,8 @@ export declare class FrameDragAction implements IDragAction {
32
33
  /** Modify the created decos before they are rendered. */
33
34
  modifyDecos?: FrameDragAction["modifyDecos"], hooks?: FrameDragAction["hooks"], config?: {
34
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;
35
38
  });
36
39
  reset(): void;
37
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() {
@@ -92,6 +94,9 @@ export class FrameDragAction {
92
94
  return false;
93
95
  }
94
96
  onDragChange(_type, _e, state) {
97
+ if (state.dragDistance <= this.minDragDistance) {
98
+ return { updateEdges: false, shapes: [], showDragging: false };
99
+ }
95
100
  const { win, draggingFrameId, dragHoveredFrame } = state;
96
101
  const matchedZone = getDragZones(state, settings.zoneSizes);
97
102
  if (!matchedZone) {
@@ -5,6 +5,7 @@ export type SplitInfo = Exclude<ReturnType<typeof getFrameSplitInfo>, KnownError
5
5
  export type DragChangeType = "start" | "move" | "end";
6
6
  export declare class SplitAction implements IDragAction {
7
7
  name: "split";
8
+ minDragDistance: number;
8
9
  state: {
9
10
  allowed: true;
10
11
  res: SplitInfo;
@@ -37,6 +38,8 @@ export declare class SplitAction implements IDragAction {
37
38
  modifyDecos?: SplitAction["modifyDecos"], hooks?: SplitAction["hooks"], config?: {
38
39
  debug?: boolean | string;
39
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;
40
43
  });
41
44
  reset(): void;
42
45
  getDecos(state: DragState): SplitDeco[];
@@ -6,6 +6,7 @@ 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;
@@ -24,6 +25,7 @@ export class SplitAction {
24
25
  this.hooks = hooks;
25
26
  this.reset();
26
27
  if (config?.debug) this.debug = true;
28
+ if (config?.minDragDistance !== void 0) this.minDragDistance = config.minDragDistance;
27
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
  }
@@ -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;
@@ -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) {
@@ -8,7 +8,7 @@ export class Settings {
8
8
  resetToDefaults() {
9
9
  this.scale = 3;
10
10
  this.snapPoint = 0.5;
11
- this.minSize = 5;
11
+ this.minSize = 3;
12
12
  this.collapseSizePx = 15;
13
13
  this.maxPerpendicularLength = 20;
14
14
  this.zoneSizes = { frameEdgePx: 40, windowEdgePx: 20 };
@@ -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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@witchcraft/layout",
3
3
  "description": "Headless layout manager.",
4
- "version": "0.4.2",
4
+ "version": "0.4.3",
5
5
  "main": "./dist/runtime/index.js",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -6,7 +6,7 @@
6
6
  z-20
7
7
  bg-accent-500
8
8
  cursor-pointer
9
- [&.request-split]:hidden
9
+ [.request-split_&]:hidden
10
10
  `,
11
11
  ($attrs as any).class
12
12
  )"
@@ -7,8 +7,7 @@
7
7
  drag-edge
8
8
  z-20
9
9
  hover:cursor-pointer
10
-
11
- [&.request-split]:hidden
10
+ [.request-split_&]:hidden
12
11
  `,
13
12
  edge.error && `
14
13
  drag-edge-errored
@@ -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
@@ -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
 
@@ -151,6 +155,9 @@ export class CloseAction implements IDragAction {
151
155
  _e: PointerEvent | undefined,
152
156
  state: DragState
153
157
  ): ActionDragChangeResult {
158
+ if (state.dragDistance <= this.minDragDistance) {
159
+ return { updateEdges: false, shapes: [] }
160
+ }
154
161
  const {
155
162
  touchingFramesArrays,
156
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
  } = {
@@ -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
  }
@@ -149,6 +155,9 @@ export class FrameDragAction 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: [], showDragging: false }
160
+ }
152
161
  const { win, draggingFrameId, dragHoveredFrame } = state
153
162
  const matchedZone = getDragZones(state, settings.zoneSizes)
154
163
 
@@ -16,6 +16,7 @@ export type DragChangeType = "start" | "move" | "end"
16
16
 
17
17
  export class SplitAction implements IDragAction {
18
18
  name = "split" as const
19
+ minDragDistance = 5
19
20
 
20
21
  state: {
21
22
  allowed: true
@@ -57,6 +58,8 @@ export class SplitAction implements IDragAction {
57
58
  config?: {
58
59
  debug?: boolean | string
59
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
60
63
  }
61
64
  ) {
62
65
  if (handleEvent !== undefined) this.handleEvent = handleEvent
@@ -65,6 +68,7 @@ export class SplitAction implements IDragAction {
65
68
  this.hooks = hooks
66
69
  this.reset()
67
70
  if (config?.debug) this.debug = true
71
+ if (config?.minDragDistance !== undefined) this.minDragDistance = config.minDragDistance
68
72
  if (config?.splitHints?.actions) this.splitHints.actions = config.splitHints.actions
69
73
  if (config?.splitHints?.transformError) this.splitHints.transformError = config.splitHints.transformError
70
74
  }
@@ -106,7 +110,8 @@ export class SplitAction implements IDragAction {
106
110
  canHandleRequest(e: PointerEvent | KeyboardEvent, state: DragState): boolean {
107
111
  const { draggingEdges } = state
108
112
  if (draggingEdges.length !== 1) return false
109
- this.setTextHints(state.isDragging === "edge" ? true : undefined)
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)
110
115
  if (this.handleEvent(e, state)) {
111
116
  this.hooks.onStart?.()
112
117
  return true
@@ -154,7 +159,7 @@ export class SplitAction implements IDragAction {
154
159
  dragDirections[oppositeOrientation]!,
155
160
  dragPoint!
156
161
  )
157
- this.setTextHints(canSplit)
162
+ this.setTextHints(state.isDragging === "edge" && !state.isDraggingFromWindowEdge ? canSplit : undefined)
158
163
  if (!(canSplit instanceof Error)) {
159
164
  this.state.allowed = true
160
165
  this.state.res = canSplit
@@ -173,7 +178,10 @@ export class SplitAction implements IDragAction {
173
178
  _e: PointerEvent | undefined,
174
179
  state: DragState
175
180
  ): ActionDragChangeResult {
176
- const { dragHoveredFrame } = state
181
+ const { dragHoveredFrame, dragDistance } = state
182
+ if (dragDistance <= this.minDragDistance) {
183
+ return { updateEdges: false, shapes: [], showDragging: false }
184
+ }
177
185
  let ok = false
178
186
  if (dragHoveredFrame) {
179
187
  if (this.state.lastPoint?.x === state.dragPoint?.x && this.state.lastPoint?.y === state.dragPoint?.y && this.state.lastReturn) {
@@ -11,7 +11,7 @@ export class Settings {
11
11
  resetToDefaults() {
12
12
  this.scale = 3
13
13
  this.snapPoint = 0.5
14
- this.minSize = 5
14
+ this.minSize = 3
15
15
  this.collapseSizePx = 15
16
16
  this.maxPerpendicularLength = 20
17
17
  this.zoneSizes = { frameEdgePx: 40, windowEdgePx: 20 }
@@ -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. */