@witchcraft/layout 0.5.5 → 0.5.6

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/README.md CHANGED
@@ -79,6 +79,36 @@ declare module "@witchcraft/layout" {
79
79
  ```
80
80
  Note that `zFrameId` and `zWinId` are different as they also support constants (`zFrameIdConstants` and `zWindowIdConstants`).
81
81
 
82
+ #### Extending Move Types
83
+
84
+ You can also extend the move types. This is usually needed for creating custom actions.
85
+
86
+ Unlike frame types, this uses a pattern where you can extend as many times as you want so long as the key is prefixed with `LayoutMove` and the type satisfies `{ type: string, context: any, resolve: any, moveType: "edge" | "frame" | "other" }`.
87
+
88
+
89
+ ```ts
90
+
91
+ declare module "@witchcraft/layout" {
92
+ interface Register {
93
+ LayoutMovePicker: {
94
+ // used to discriminate the type
95
+ type: "picker",
96
+ // any other props to add to the context parameter of moveStart
97
+ // context ends up typed as { type: "picker", someState: string }
98
+ context: {
99
+ someState: string
100
+ }
101
+ // promise resolve value, for typing the return value of moveStart
102
+ resolve: string
103
+ // for typing the type parameter of moveStart so user picks supported types
104
+ moveType: "other",
105
+ }
106
+ }
107
+ }
108
+ ```
109
+
110
+ `moveStart`'s context parameter will now be type checked as `{someState: string, type: "picker"}` and the return value will be `Promise<string>`.
111
+
82
112
  ## Basics
83
113
 
84
114
  A layout is very simple, and looks like this:
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@witchcraft/layout",
3
3
  "configKey": "witchcraftLayout",
4
- "version": "0.5.5",
4
+ "version": "0.5.6",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "unknown"
@@ -44,7 +44,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
44
44
  y: number;
45
45
  } | undefined;
46
46
  moveDistance: number;
47
- isMoving: false | "edge" | "frame";
47
+ isMoving: false | "edge" | "frame" | "other";
48
48
  showMoving: boolean;
49
49
  movingFrameId: string | undefined;
50
50
  movingEdges: {
@@ -347,11 +347,19 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
347
347
  getUpdateWindowSizeInfo: typeof getUpdateWindowSizeInfo;
348
348
  actionHandler: ActionHandler<any, any>;
349
349
  moveContext: {
350
- moveStart: <T extends "edge" | "frame">(e: PointerEvent, type: T, data: T extends "edge" ? import("../types/index.js").EdgeMoveStartData : import("../types/index.js").FrameMoveStartData, { moveEvent, endEvent, context }?: {
350
+ moveStart: <T extends "edge" | "frame" | "other", TContextType extends keyof import("../types/index.js").ExtendedMoveTypes, TContext extends import("../types/index.js").ExtendedMoveTypes[TContextType], TContextReturn extends TContext extends {
351
+ resolve: infer R;
352
+ } ? R : never, TContextMoveType extends TContext extends {
353
+ moveType: infer M;
354
+ } ? M : never, TContextContext extends TContext extends {
355
+ context: infer C;
356
+ } ? C : never>(e: PointerEvent, type: TContextMoveType extends never ? T : TContextMoveType, data: T extends "edge" ? import("../types/index.js").EdgeMoveStartData : T extends "frame" ? import("../types/index.js").FrameMoveStartData : undefined, { moveEvent, endEvent, context }?: {
351
357
  moveEvent?: string;
352
358
  endEvent?: string;
353
- context?: Record<string, unknown>;
354
- }) => Promise<any>;
359
+ context?: {
360
+ type: TContextType;
361
+ } & TContextContext;
362
+ }) => TContext extends never ? Promise<void> : Promise<TContextReturn>;
355
363
  moveEnd: (e?: PointerEvent, { apply }?: {
356
364
  apply?: boolean;
357
365
  }) => void;
@@ -371,7 +379,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
371
379
  x: number;
372
380
  y: number;
373
381
  } | undefined>;
374
- isMoving: import("vue").Ref<false | "edge" | "frame", false | "edge" | "frame">;
382
+ isMoving: import("vue").Ref<false | "edge" | "frame" | "other", false | "edge" | "frame" | "other">;
375
383
  movingEdges: import("vue").Ref<{
376
384
  startX: number;
377
385
  startY: number;
@@ -1096,7 +1104,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
1096
1104
  y: number;
1097
1105
  } | undefined;
1098
1106
  moveDistance: number;
1099
- isMoving: false | "edge" | "frame";
1107
+ isMoving: false | "edge" | "frame" | "other";
1100
1108
  showMoving: boolean;
1101
1109
  movingFrameId: string | undefined;
1102
1110
  movingEdges: {
@@ -44,7 +44,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
44
44
  y: number;
45
45
  } | undefined;
46
46
  moveDistance: number;
47
- isMoving: false | "edge" | "frame";
47
+ isMoving: false | "edge" | "frame" | "other";
48
48
  showMoving: boolean;
49
49
  movingFrameId: string | undefined;
50
50
  movingEdges: {
@@ -347,11 +347,19 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
347
347
  getUpdateWindowSizeInfo: typeof getUpdateWindowSizeInfo;
348
348
  actionHandler: ActionHandler<any, any>;
349
349
  moveContext: {
350
- moveStart: <T extends "edge" | "frame">(e: PointerEvent, type: T, data: T extends "edge" ? import("../types/index.js").EdgeMoveStartData : import("../types/index.js").FrameMoveStartData, { moveEvent, endEvent, context }?: {
350
+ moveStart: <T extends "edge" | "frame" | "other", TContextType extends keyof import("../types/index.js").ExtendedMoveTypes, TContext extends import("../types/index.js").ExtendedMoveTypes[TContextType], TContextReturn extends TContext extends {
351
+ resolve: infer R;
352
+ } ? R : never, TContextMoveType extends TContext extends {
353
+ moveType: infer M;
354
+ } ? M : never, TContextContext extends TContext extends {
355
+ context: infer C;
356
+ } ? C : never>(e: PointerEvent, type: TContextMoveType extends never ? T : TContextMoveType, data: T extends "edge" ? import("../types/index.js").EdgeMoveStartData : T extends "frame" ? import("../types/index.js").FrameMoveStartData : undefined, { moveEvent, endEvent, context }?: {
351
357
  moveEvent?: string;
352
358
  endEvent?: string;
353
- context?: Record<string, unknown>;
354
- }) => Promise<any>;
359
+ context?: {
360
+ type: TContextType;
361
+ } & TContextContext;
362
+ }) => TContext extends never ? Promise<void> : Promise<TContextReturn>;
355
363
  moveEnd: (e?: PointerEvent, { apply }?: {
356
364
  apply?: boolean;
357
365
  }) => void;
@@ -371,7 +379,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
371
379
  x: number;
372
380
  y: number;
373
381
  } | undefined>;
374
- isMoving: import("vue").Ref<false | "edge" | "frame", false | "edge" | "frame">;
382
+ isMoving: import("vue").Ref<false | "edge" | "frame" | "other", false | "edge" | "frame" | "other">;
375
383
  movingEdges: import("vue").Ref<{
376
384
  startX: number;
377
385
  startY: number;
@@ -1096,7 +1104,7 @@ declare const __VLS_component: import("vue").DefineComponent<__VLS_PublicProps,
1096
1104
  y: number;
1097
1105
  } | undefined;
1098
1106
  moveDistance: number;
1099
- isMoving: false | "edge" | "frame";
1107
+ isMoving: false | "edge" | "frame" | "other";
1100
1108
  showMoving: boolean;
1101
1109
  movingFrameId: string | undefined;
1102
1110
  movingEdges: {
@@ -1,11 +1,19 @@
1
1
  import type { Ref } from "vue";
2
- import type { EdgeMoveStartData, FrameMoveStartData, IActionHandler, IntersectionEntry, LayoutFrame, LayoutWindow } from "../types/index.js";
2
+ import type { EdgeMoveStartData, ExtendedMoveTypes, FrameMoveStartData, IActionHandler, IntersectionEntry, LayoutFrame, LayoutWindow } from "../types/index.js";
3
3
  export declare function useFrames(win: Ref<LayoutWindow>, handler: IActionHandler): {
4
- moveStart: <T extends "edge" | "frame">(e: PointerEvent, type: T, data: T extends "edge" ? EdgeMoveStartData : FrameMoveStartData, { moveEvent, endEvent, context }?: {
4
+ moveStart: <T extends "edge" | "frame" | "other", TContextType extends keyof ExtendedMoveTypes, TContext extends ExtendedMoveTypes[TContextType], TContextReturn extends TContext extends {
5
+ resolve: infer R;
6
+ } ? R : never, TContextMoveType extends TContext extends {
7
+ moveType: infer M;
8
+ } ? M : never, TContextContext extends TContext extends {
9
+ context: infer C;
10
+ } ? C : never>(e: PointerEvent, type: TContextMoveType extends never ? T : TContextMoveType, data: T extends "edge" ? EdgeMoveStartData : T extends "frame" ? FrameMoveStartData : undefined, { moveEvent, endEvent, context }?: {
5
11
  moveEvent?: string;
6
12
  endEvent?: string;
7
- context?: Record<string, unknown>;
8
- }) => Promise<any>;
13
+ context?: {
14
+ type: TContextType;
15
+ } & TContextContext;
16
+ }) => TContext extends never ? Promise<void> : Promise<TContextReturn>;
9
17
  moveEnd: (e?: PointerEvent, { apply }?: {
10
18
  apply?: boolean;
11
19
  }) => void;
@@ -25,7 +33,7 @@ export declare function useFrames(win: Ref<LayoutWindow>, handler: IActionHandle
25
33
  x: number;
26
34
  y: number;
27
35
  } | undefined>;
28
- isMoving: Ref<false | "edge" | "frame", false | "edge" | "frame">;
36
+ isMoving: Ref<false | "edge" | "frame" | "other", false | "edge" | "frame" | "other">;
29
37
  movingEdges: Ref<{
30
38
  startX: number;
31
39
  startY: number;
@@ -750,7 +758,7 @@ export declare function useFrames(win: Ref<LayoutWindow>, handler: IActionHandle
750
758
  y: number;
751
759
  } | undefined;
752
760
  moveDistance: number;
753
- isMoving: false | "edge" | "frame";
761
+ isMoving: false | "edge" | "frame" | "other";
754
762
  showMoving: boolean;
755
763
  movingFrameId: string | undefined;
756
764
  movingEdges: {
@@ -129,7 +129,7 @@ export function useFrames(win, handler) {
129
129
  showMoving.value = true;
130
130
  if (type === "frame") {
131
131
  movingFrameId.value = data.frameId;
132
- } else {
132
+ } else if (type === "edge") {
133
133
  const { edge, intersection } = data;
134
134
  movingIntersection.value = intersection;
135
135
  movingEdges.value = edge ? [edge] : [
@@ -1,4 +1,5 @@
1
1
  import type { EnumLike } from "@alanscodelog/utils";
2
+ import type { Flatten, OrToAnd } from "@alanscodelog/utils/types";
2
3
  import { z } from "zod";
3
4
  import { KnownError } from "../utils/KnownError.js";
4
5
  export declare const zUuid: z.ZodUUID;
@@ -1843,6 +1844,12 @@ export type LayoutChange<TInfo = never> = {
1843
1844
  window?: Partial<LayoutWindow>;
1844
1845
  info?: TInfo;
1845
1846
  };
1847
+ export type ExtendedMoveTypes = Flatten<OrToAnd<keyof Register extends `LayoutMove${infer T}` ? Register extends Record<`LayoutMove${T}`, infer U> ? U extends {
1848
+ type: string;
1849
+ context: any;
1850
+ resolve: any;
1851
+ moveType: "edge" | "frame" | "other";
1852
+ } ? Record<U["type"], U> : never : never : never>>;
1846
1853
  export type MoveState = {
1847
1854
  /** The current directions in the corresponding orientations that the user is dragging in. */
1848
1855
  moveDirections: Record<Orientation, Direction | undefined>;
@@ -1850,8 +1857,12 @@ export type MoveState = {
1850
1857
  movePoint?: Point;
1851
1858
  /** Cumulative pixel distance the user has dragged from the initial click point. 0 on start, increases on each move. */
1852
1859
  moveDistance: number;
1853
- /** Whether the user is currently dragging and what type of drag. Is truthy string during all drag events. */
1854
- isMoving: boolean | "frame" | "edge";
1860
+ /**
1861
+ * Whether the user is currently moving and what type of move. Is truthy string during all move events. The actions decide what they need to set it to as "frame" and "edge" have custom behavior.
1862
+ *
1863
+ * Other is for actions that do things other than drag frames/edges which include built in behavior (e.g. frames get a frame dragging indicator at the cursor)
1864
+ */
1865
+ isMoving: boolean | "frame" | "edge" | "other";
1855
1866
  /** Whether to show the moved frames while dragging. */
1856
1867
  showMoving: boolean;
1857
1868
  /** The frame being dragged during a frame drag. Only set when isMoving is "frame". */
@@ -33,7 +33,7 @@ export interface UseFramesContext {
33
33
  cancel: () => void;
34
34
  moveDirections: Ref<Record<Orientation, Direction | undefined>>;
35
35
  movePoint: Ref<Point | undefined>;
36
- isMoving: Ref<false | "frame" | "edge">;
36
+ isMoving: Ref<false | "frame" | "edge" | "other">;
37
37
  movingEdges: Ref<Edge[]>;
38
38
  movingIntersection: Ref<IntersectionEntry | undefined>;
39
39
  visualEdges: Ref<Edge[]>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@witchcraft/layout",
3
3
  "description": "Headless layout manager.",
4
- "version": "0.5.5",
4
+ "version": "0.5.6",
5
5
  "main": "./dist/runtime/index.js",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -12,7 +12,23 @@ 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 { ActionResolve, Direction, Edge, EdgeMoveStartData, FrameId, FrameMoveStartData, IActionHandler, IntersectionEntry, LayoutFrame, LayoutWindow, MoveState, Orientation, Point } from "../types/index.js"
15
+ import type {
16
+ ActionResolve,
17
+ Direction,
18
+ Edge,
19
+ EdgeMoveStartData,
20
+ ExtendedMoveTypes,
21
+ FrameId,
22
+ FrameMoveStartData,
23
+ IActionHandler,
24
+ IntersectionEntry,
25
+ LayoutFrame,
26
+ LayoutWindow,
27
+ MoveState,
28
+ Orientation,
29
+ Point
30
+ } from "../types/index.js"
31
+
16
32
 
17
33
  export function useFrames(
18
34
  win: Ref<LayoutWindow>,
@@ -34,7 +50,7 @@ export function useFrames(
34
50
 
35
51
  const touchingFramesArrays = computed(() => touchingFrames.value.map(entry => Object.values(entry)))
36
52
 
37
- const isMoving = ref<false | "frame" | "edge">(false)
53
+ const isMoving = ref<false | "frame" | "edge" | "other">(false)
38
54
  const showMoving = ref(false)
39
55
  const movePoint = ref<Point | undefined>()
40
56
 
@@ -137,11 +153,18 @@ export function useFrames(
137
153
  handler.onMoveEnded()
138
154
  }
139
155
 
140
- function moveStart<T extends "edge" | "frame">(
156
+ function moveStart<
157
+ T extends "edge" | "frame" | "other",
158
+ TContextType extends keyof ExtendedMoveTypes,
159
+ TContext extends ExtendedMoveTypes[TContextType],
160
+ TContextReturn extends TContext extends { resolve: infer R } ? R : never,
161
+ TContextMoveType extends TContext extends { moveType: infer M } ? M : never,
162
+ TContextContext extends TContext extends { context: infer C } ? C : never
163
+ >(
141
164
  e: PointerEvent,
142
- type: T,
165
+ type: TContextMoveType extends never ? T : TContextMoveType,
143
166
  // someday this will work
144
- data: T extends "edge" ? EdgeMoveStartData : FrameMoveStartData,
167
+ data: T extends "edge" ? EdgeMoveStartData : T extends "frame" ? FrameMoveStartData : undefined,
145
168
  {
146
169
  moveEvent = "pointermove",
147
170
  endEvent = "pointerup",
@@ -149,9 +172,11 @@ export function useFrames(
149
172
  }: {
150
173
  moveEvent?: string
151
174
  endEvent?: string
152
- context?: Record<string, unknown>
175
+ context?: { type: TContextType } & TContextContext
153
176
  } = {}
154
- ): Promise<any> {
177
+ ): TContext extends never
178
+ ? Promise<void>
179
+ : Promise<TContextReturn> {
155
180
  // if already dragging, abort previous (resetState resolves the old promise)
156
181
  if (controller) {
157
182
  controller.abort()
@@ -174,12 +199,12 @@ export function useFrames(
174
199
  moveDirStore.update(point)
175
200
  eventContext.value = context
176
201
 
177
- isMoving.value = type
202
+ isMoving.value = type as any
178
203
  showMoving.value = true
179
204
 
180
205
  if (type === "frame") {
181
206
  movingFrameId.value = (data as FrameMoveStartData).frameId
182
- } else {
207
+ } else if (type === "edge") {
183
208
  const { edge, intersection } = data as EdgeMoveStartData
184
209
  movingIntersection.value = intersection
185
210
 
@@ -216,7 +241,7 @@ export function useFrames(
216
241
 
217
242
  const res = handler.onMoveChange("start", e, state.value, forceRecalculateEdges, cancel, resolve)
218
243
  showMoving.value = res.showMoving ?? true
219
- return promise
244
+ return promise as any
220
245
  }
221
246
 
222
247
  function onMove(e: PointerEvent): void {
@@ -1,5 +1,6 @@
1
1
  import type { EnumLike } from "@alanscodelog/utils"
2
2
  import { enumFromArray } from "@alanscodelog/utils/enumFromArray"
3
+ import type { Flatten, OrToAnd } from "@alanscodelog/utils/types"
3
4
  import { z } from "zod"
4
5
 
5
6
  import { KnownError } from "../utils/KnownError.js"
@@ -441,6 +442,22 @@ export type LayoutChange<TInfo = never> = {
441
442
  window?: Partial<LayoutWindow>
442
443
  info?: TInfo
443
444
  }
445
+
446
+
447
+ // #todo we also need to change how the normal types are extended to this pattern
448
+ export type ExtendedMoveTypes = Flatten<OrToAnd<keyof Register extends `LayoutMove${infer T}`
449
+ ? Register extends Record<`LayoutMove${T}`, infer U>
450
+ ? U extends {
451
+ type: string
452
+ context: any
453
+ resolve: any
454
+ moveType: "edge" | "frame" | "other"
455
+ }
456
+ ? Record<U["type"], U>
457
+ : never
458
+ : never
459
+ : never>>
460
+
444
461
  export type MoveState = {
445
462
  /** The current directions in the corresponding orientations that the user is dragging in. */
446
463
  moveDirections: Record<Orientation, Direction | undefined>
@@ -448,8 +465,12 @@ export type MoveState = {
448
465
  movePoint?: Point
449
466
  /** Cumulative pixel distance the user has dragged from the initial click point. 0 on start, increases on each move. */
450
467
  moveDistance: number
451
- /** Whether the user is currently dragging and what type of drag. Is truthy string during all drag events. */
452
- isMoving: boolean | "frame" | "edge"
468
+ /**
469
+ * Whether the user is currently moving and what type of move. Is truthy string during all move events. The actions decide what they need to set it to as "frame" and "edge" have custom behavior.
470
+ *
471
+ * Other is for actions that do things other than drag frames/edges which include built in behavior (e.g. frames get a frame dragging indicator at the cursor)
472
+ */
473
+ isMoving: boolean | "frame" | "edge" | "other"
453
474
  /** Whether to show the moved frames while dragging. */
454
475
  showMoving: boolean
455
476
  /** The frame being dragged during a frame drag. Only set when isMoving is "frame". */
@@ -25,7 +25,7 @@ export interface UseFramesContext {
25
25
  cancel: () => void
26
26
  moveDirections: Ref<Record<Orientation, Direction | undefined>>
27
27
  movePoint: Ref<Point | undefined>
28
- isMoving: Ref<false | "frame" | "edge">
28
+ isMoving: Ref<false | "frame" | "edge" | "other">
29
29
  movingEdges: Ref<Edge[]>
30
30
  movingIntersection: Ref<IntersectionEntry | undefined>
31
31
  visualEdges: Ref<Edge[]>
@@ -41,3 +41,4 @@ export interface UseFramesContext {
41
41
  }
42
42
 
43
43
  export const moveContextInjectionKey = Symbol.for("@witchcraft/layout:moveContext") as InjectionKey<UseFramesContext>
44
+