@witchcraft/layout 0.1.3 → 0.2.0

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.
Files changed (189) hide show
  1. package/README.md +27 -24
  2. package/dist/module.json +1 -1
  3. package/dist/runtime/components/FrameDragHandle.d.vue.ts +15 -0
  4. package/dist/runtime/components/FrameDragHandle.vue +28 -0
  5. package/dist/runtime/components/FrameDragHandle.vue.d.ts +15 -0
  6. package/dist/runtime/components/LayoutDecos.d.vue.ts +2 -4
  7. package/dist/runtime/components/LayoutDecos.vue +10 -29
  8. package/dist/runtime/components/LayoutDecos.vue.d.ts +2 -4
  9. package/dist/runtime/components/LayoutEdges.d.vue.ts +3 -3
  10. package/dist/runtime/components/LayoutEdges.vue +8 -8
  11. package/dist/runtime/components/LayoutEdges.vue.d.ts +3 -3
  12. package/dist/runtime/components/LayoutFrame.d.vue.ts +1 -1
  13. package/dist/runtime/components/LayoutFrame.vue +0 -1
  14. package/dist/runtime/components/LayoutFrame.vue.d.ts +1 -1
  15. package/dist/runtime/components/LayoutShapeSquare.d.vue.ts +3 -1
  16. package/dist/runtime/components/LayoutShapeSquare.vue.d.ts +3 -1
  17. package/dist/runtime/components/LayoutWindow.d.vue.ts +26 -12
  18. package/dist/runtime/components/LayoutWindow.vue +95 -84
  19. package/dist/runtime/components/LayoutWindow.vue.d.ts +26 -12
  20. package/dist/runtime/composables/useFrames.d.ts +15 -13
  21. package/dist/runtime/composables/useFrames.js +59 -39
  22. package/dist/runtime/demo/App.vue +116 -30
  23. package/dist/runtime/demo/DemoControls.d.vue.ts +4 -1
  24. package/dist/runtime/demo/DemoControls.vue +98 -4
  25. package/dist/runtime/demo/DemoControls.vue.d.ts +4 -1
  26. package/dist/runtime/drag/CloseAction.d.ts +26 -5
  27. package/dist/runtime/drag/CloseAction.js +87 -40
  28. package/dist/runtime/drag/DragActionHandler.d.ts +20 -8
  29. package/dist/runtime/drag/DragActionHandler.js +47 -12
  30. package/dist/runtime/drag/FrameDragAction.d.ts +45 -0
  31. package/dist/runtime/drag/FrameDragAction.js +143 -0
  32. package/dist/runtime/drag/SplitAction.d.ts +32 -11
  33. package/dist/runtime/drag/SplitAction.js +82 -24
  34. package/dist/runtime/drag/createDefaultHandlers.d.ts +9 -0
  35. package/dist/runtime/drag/createDefaultHandlers.js +10 -0
  36. package/dist/runtime/drag/defaultDragActions.d.ts +9 -0
  37. package/dist/runtime/drag/defaultDragActions.js +10 -0
  38. package/dist/runtime/drag/types.d.ts +82 -13
  39. package/dist/runtime/drag/types.js +1 -0
  40. package/dist/runtime/helpers/createZoneSideClipPath.d.ts +12 -0
  41. package/dist/runtime/helpers/createZoneSideClipPath.js +17 -0
  42. package/dist/runtime/helpers/doEdgesOverlap.d.ts +3 -1
  43. package/dist/runtime/helpers/doEdgesOverlap.js +5 -5
  44. package/dist/runtime/helpers/getDockBoundaries.d.ts +19 -0
  45. package/dist/runtime/helpers/getDockBoundaries.js +14 -0
  46. package/dist/runtime/helpers/getEdgeLength.d.ts +2 -0
  47. package/dist/runtime/helpers/getEdgeLength.js +5 -0
  48. package/dist/runtime/helpers/getIntersections.js +2 -2
  49. package/dist/runtime/helpers/getIntersectionsCss.js +2 -2
  50. package/dist/runtime/helpers/getMoveEdgeInfo.js +2 -2
  51. package/dist/runtime/helpers/getResizeLimit.js +2 -2
  52. package/dist/runtime/helpers/getShapeSquareCss.js +2 -2
  53. package/dist/runtime/helpers/getVisualEdgeCss.js +2 -2
  54. package/dist/runtime/helpers/getVisualEdges.d.ts +1 -1
  55. package/dist/runtime/helpers/getVisualEdges.js +4 -3
  56. package/dist/runtime/helpers/index.d.ts +4 -0
  57. package/dist/runtime/helpers/index.js +4 -0
  58. package/dist/runtime/helpers/isEdgeEqual.js +2 -4
  59. package/dist/runtime/helpers/isWindowEdge.js +2 -2
  60. package/dist/runtime/helpers/isWindowEdgePoint.js +2 -2
  61. package/dist/runtime/helpers/moveEdge.js +2 -2
  62. package/dist/runtime/helpers/numberToScaledPercent.d.ts +1 -1
  63. package/dist/runtime/helpers/numberToScaledPercent.js +2 -2
  64. package/dist/runtime/helpers/numberToScaledSize.js +2 -2
  65. package/dist/runtime/helpers/rotateFrames.d.ts +7 -0
  66. package/dist/runtime/helpers/rotateFrames.js +36 -0
  67. package/dist/runtime/helpers/scaledPointToPx.d.ts +13 -0
  68. package/dist/runtime/helpers/scaledPointToPx.js +7 -0
  69. package/dist/runtime/helpers/toWindowCoord.js +2 -2
  70. package/dist/runtime/layout/applyFrameChanges.d.ts +10 -0
  71. package/dist/runtime/layout/applyFrameChanges.js +29 -0
  72. package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +6 -1
  73. package/dist/runtime/layout/createSplitDecoFromDrag.js +4 -4
  74. package/dist/runtime/layout/createSplitDecoShapes.d.ts +7 -0
  75. package/dist/runtime/layout/{createSplitDecoEdge.js → createSplitDecoShapes.js} +6 -3
  76. package/dist/runtime/layout/debugFrame.js +2 -1
  77. package/dist/runtime/layout/findSafeSplitEdge.js +2 -2
  78. package/dist/runtime/layout/frameCreate.js +2 -2
  79. package/dist/runtime/layout/getCloseFrameInfo.d.ts +7 -6
  80. package/dist/runtime/layout/getCloseFrameInfo.js +10 -3
  81. package/dist/runtime/layout/getDragZones.d.ts +8 -0
  82. package/dist/runtime/layout/getDragZones.js +32 -0
  83. package/dist/runtime/layout/getFillEmptySpaceInfo.d.ts +65 -0
  84. package/dist/runtime/layout/getFillEmptySpaceInfo.js +69 -0
  85. package/dist/runtime/layout/getFrameCollapseInfo.d.ts +13 -0
  86. package/dist/runtime/layout/getFrameCollapseInfo.js +93 -0
  87. package/dist/runtime/layout/getFrameDockInfo.d.ts +9 -0
  88. package/dist/runtime/layout/getFrameDockInfo.js +82 -0
  89. package/dist/runtime/layout/getFrameDragZones.d.ts +16 -0
  90. package/dist/runtime/layout/getFrameDragZones.js +74 -0
  91. package/dist/runtime/layout/getFrameRearrangeInfo.d.ts +139 -0
  92. package/dist/runtime/layout/getFrameRearrangeInfo.js +87 -0
  93. package/dist/runtime/layout/getFrameSplitInfo.d.ts +7 -5
  94. package/dist/runtime/layout/getFrameSplitInfo.js +10 -3
  95. package/dist/runtime/layout/getFrameSwapInfo.d.ts +9 -0
  96. package/dist/runtime/layout/getFrameSwapInfo.js +27 -0
  97. package/dist/runtime/layout/getFrameTo.js +2 -2
  98. package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +12 -0
  99. package/dist/runtime/layout/getFrameUncollapseInfo.js +88 -0
  100. package/dist/runtime/layout/getFrameUndockInfo.d.ts +13 -0
  101. package/dist/runtime/layout/getFrameUndockInfo.js +51 -0
  102. package/dist/runtime/layout/getFramesRedistributeInfo.d.ts +29 -0
  103. package/dist/runtime/layout/getFramesRedistributeInfo.js +53 -0
  104. package/dist/runtime/layout/getWindowDragZones.d.ts +6 -0
  105. package/dist/runtime/layout/getWindowDragZones.js +49 -0
  106. package/dist/runtime/layout/index.d.ts +14 -5
  107. package/dist/runtime/layout/index.js +14 -5
  108. package/dist/runtime/layout/isPointInRect.d.ts +7 -0
  109. package/dist/runtime/layout/{isPointInFrame.js → isPointInRect.js} +1 -1
  110. package/dist/runtime/layout/resizeFrame.js +2 -2
  111. package/dist/runtime/settings.d.ts +41 -16
  112. package/dist/runtime/settings.js +95 -53
  113. package/dist/runtime/types/index.d.ts +324 -54
  114. package/dist/runtime/types/index.js +54 -20
  115. package/package.json +28 -29
  116. package/src/runtime/components/FrameDragHandle.vue +30 -0
  117. package/src/runtime/components/LayoutDecos.vue +12 -36
  118. package/src/runtime/components/LayoutEdges.vue +27 -23
  119. package/src/runtime/components/LayoutFrame.vue +6 -5
  120. package/src/runtime/components/LayoutShapeSquare.vue +9 -3
  121. package/src/runtime/components/LayoutWindow.vue +110 -101
  122. package/src/runtime/composables/useFrames.ts +80 -50
  123. package/src/runtime/demo/App.vue +126 -36
  124. package/src/runtime/demo/DemoControls.vue +115 -6
  125. package/src/runtime/drag/CloseAction.ts +106 -44
  126. package/src/runtime/drag/DragActionHandler.ts +71 -20
  127. package/src/runtime/drag/FrameDragAction.ts +202 -0
  128. package/src/runtime/drag/SplitAction.ts +106 -34
  129. package/src/runtime/drag/createDefaultHandlers.ts +19 -0
  130. package/src/runtime/drag/defaultDragActions.ts +19 -0
  131. package/src/runtime/drag/types.ts +90 -20
  132. package/src/runtime/helpers/createZoneSideClipPath.ts +41 -0
  133. package/src/runtime/helpers/doEdgesOverlap.ts +11 -5
  134. package/src/runtime/helpers/getDockBoundaries.ts +36 -0
  135. package/src/runtime/helpers/getEdgeLength.ts +10 -0
  136. package/src/runtime/helpers/getIntersections.ts +2 -2
  137. package/src/runtime/helpers/getIntersectionsCss.ts +2 -2
  138. package/src/runtime/helpers/getMoveEdgeInfo.ts +2 -2
  139. package/src/runtime/helpers/getResizeLimit.ts +2 -2
  140. package/src/runtime/helpers/getShapeSquareCss.ts +2 -2
  141. package/src/runtime/helpers/getVisualEdgeCss.ts +2 -2
  142. package/src/runtime/helpers/getVisualEdges.ts +5 -4
  143. package/src/runtime/helpers/index.ts +4 -0
  144. package/src/runtime/helpers/isEdgeEqual.ts +2 -4
  145. package/src/runtime/helpers/isWindowEdge.ts +2 -2
  146. package/src/runtime/helpers/isWindowEdgePoint.ts +2 -2
  147. package/src/runtime/helpers/moveEdge.ts +2 -2
  148. package/src/runtime/helpers/numberToScaledPercent.ts +3 -3
  149. package/src/runtime/helpers/numberToScaledSize.ts +2 -2
  150. package/src/runtime/helpers/rotateFrames.ts +45 -0
  151. package/src/runtime/helpers/scaledPointToPx.ts +13 -0
  152. package/src/runtime/helpers/toWindowCoord.ts +2 -2
  153. package/src/runtime/layout/applyFrameChanges.ts +39 -0
  154. package/src/runtime/layout/createSplitDecoFromDrag.ts +12 -6
  155. package/src/runtime/layout/{createSplitDecoEdge.ts → createSplitDecoShapes.ts} +17 -7
  156. package/src/runtime/layout/debugFrame.ts +1 -1
  157. package/src/runtime/layout/findSafeSplitEdge.ts +3 -3
  158. package/src/runtime/layout/frameCreate.ts +2 -2
  159. package/src/runtime/layout/getCloseFrameInfo.ts +21 -8
  160. package/src/runtime/layout/getDragZones.ts +48 -0
  161. package/src/runtime/layout/getFillEmptySpaceInfo.ts +177 -0
  162. package/src/runtime/layout/getFrameCollapseInfo.ts +164 -0
  163. package/src/runtime/layout/getFrameDockInfo.ts +126 -0
  164. package/src/runtime/layout/getFrameDragZones.ts +100 -0
  165. package/src/runtime/layout/getFrameRearrangeInfo.ts +261 -0
  166. package/src/runtime/layout/getFrameSplitInfo.ts +21 -8
  167. package/src/runtime/layout/getFrameSwapInfo.ts +45 -0
  168. package/src/runtime/layout/getFrameTo.ts +2 -2
  169. package/src/runtime/layout/getFrameUncollapseInfo.ts +160 -0
  170. package/src/runtime/layout/getFrameUndockInfo.ts +97 -0
  171. package/src/runtime/layout/getFramesRedistributeInfo.ts +98 -0
  172. package/src/runtime/layout/getWindowDragZones.ts +59 -0
  173. package/src/runtime/layout/index.ts +14 -5
  174. package/src/runtime/layout/isPointInRect.ts +7 -0
  175. package/src/runtime/layout/resizeFrame.ts +2 -2
  176. package/src/runtime/settings.ts +69 -49
  177. package/src/runtime/types/index.ts +143 -28
  178. package/dist/runtime/layout/closeFrame.d.ts +0 -5
  179. package/dist/runtime/layout/closeFrame.js +0 -13
  180. package/dist/runtime/layout/closeFrames.d.ts +0 -2
  181. package/dist/runtime/layout/closeFrames.js +0 -8
  182. package/dist/runtime/layout/createSplitDecoEdge.d.ts +0 -2
  183. package/dist/runtime/layout/frameSplit.d.ts +0 -16
  184. package/dist/runtime/layout/frameSplit.js +0 -9
  185. package/dist/runtime/layout/isPointInFrame.d.ts +0 -2
  186. package/src/runtime/layout/closeFrame.ts +0 -33
  187. package/src/runtime/layout/closeFrames.ts +0 -14
  188. package/src/runtime/layout/frameSplit.ts +0 -31
  189. package/src/runtime/layout/isPointInFrame.ts +0 -7
@@ -1,13 +1,13 @@
1
1
  import { enumFromArray } from "@alanscodelog/utils/enumFromArray";
2
2
  import { z } from "zod";
3
3
  export * from "../drag/types.js";
4
- import { getMaxInt } from "../settings.js";
4
+ import { settings } from "../settings.js";
5
5
  export const zUuid = z.uuid();
6
6
  export const zWindowIdConstants = z.enum(["ACTIVE"]);
7
7
  export const zWinId = z.uuid().or(zWindowIdConstants);
8
8
  export const zFrameIdConstants = z.enum(["ACTIVE"]);
9
9
  export const zFrameId = z.uuid().or(zFrameIdConstants);
10
- export const zScaledIntPercentage = z.number().int().min(0).max(getMaxInt()).nonnegative();
10
+ export const zScaledIntPercentage = z.number().int().min(0).max(settings.maxInt).nonnegative();
11
11
  const zPx = z.number().int().nonnegative();
12
12
  export const zPos = z.object({
13
13
  x: zScaledIntPercentage,
@@ -41,9 +41,11 @@ export const zSide = z.enum(["top", "bottom", "left", "right"]);
41
41
  export const zOrientation = z.enum(["horizontal", "vertical"]);
42
42
  export const zExtendedSide = z.union([zSide, zOrientation]);
43
43
  export const zBaseSquare = zSize.extend(zPos.shape);
44
- export const zLayoutFrame = z.looseObject({
45
- id: z.uuid()
46
- }).extend(zBaseSquare.shape);
44
+ export const zLayoutFrame = zBaseSquare.extend({
45
+ id: z.uuid(),
46
+ docked: zSide.optional(),
47
+ collapsed: z.union([z.literal(false), z.number()]).optional()
48
+ }).loose();
47
49
  export const zLayoutFrameLoose = zLayoutFrame.loose();
48
50
  const baseLayoutWindow = z.object({
49
51
  id: z.uuid(),
@@ -52,7 +54,24 @@ const baseLayoutWindow = z.object({
52
54
  }).extend(zPxSize.shape).extend(zPxPos.shape);
53
55
  export const zLayoutWindow = baseLayoutWindow;
54
56
  export const zLayoutWindowLoose = baseLayoutWindow.loose();
55
- const baseWorkspace = zLayoutWindow.pick({ activeFrame: true, frames: true });
57
+ const baseWorkspace = baseLayoutWindow.pick({ activeFrame: true, frames: true }).superRefine((data, ctx) => {
58
+ for (const [frameId, frame] of Object.entries(data.frames ?? {})) {
59
+ if (frame.docked === void 0) continue;
60
+ const edge = frame.docked;
61
+ if (edge === "left" && frame.x !== 0) {
62
+ ctx.addIssue({ code: "custom", message: `Docked frame ${frameId} on left edge must have x=0`, path: ["frames", frameId, "x"] });
63
+ }
64
+ if (edge === "right" && frame.x + frame.width !== settings.maxInt) {
65
+ ctx.addIssue({ code: "custom", message: `Docked frame ${frameId} on right edge must have x+width=maxInt`, path: ["frames", frameId, "x"] });
66
+ }
67
+ if (edge === "top" && frame.y !== 0) {
68
+ ctx.addIssue({ code: "custom", message: `Docked frame ${frameId} on top edge must have y=0`, path: ["frames", frameId, "y"] });
69
+ }
70
+ if (edge === "bottom" && frame.y + frame.height !== settings.maxInt) {
71
+ ctx.addIssue({ code: "custom", message: `Docked frame ${frameId} on bottom edge must have y+height=maxInt`, path: ["frames", frameId, "y"] });
72
+ }
73
+ }
74
+ });
56
75
  export const zWorkspace = baseWorkspace.strict();
57
76
  export const zWorkspaceLoose = zWorkspace.loose();
58
77
  const baseLayout = z.object({
@@ -68,32 +87,34 @@ export const zInitializedLayout = zLayout.required({
68
87
  }
69
88
  return zLayoutWindow.safeParse(layout.windows[layout.activeWindow]).success;
70
89
  }, { message: "An initialized layout's active window must exist and be valid." });
71
- export const zSplitDecoShapes = z.object({
72
- edge: zEdge,
73
- newFrame: zBaseSquare
74
- }).strict();
75
- export const zSplitDeco = z.object({
90
+ const zLayoutShape = z.discriminatedUnion("type", [
91
+ z.object({ type: z.literal("square"), data: zBaseSquare, attrs: z.record(z.string(), z.string()).optional() }),
92
+ z.object({ type: z.literal("edge"), data: zEdge, attrs: z.record(z.string(), z.string()).optional() })
93
+ ]);
94
+ const zBaseDeco = z.object({
95
+ shapes: z.array(zLayoutShape).default([])
96
+ });
97
+ export const zSplitDeco = zBaseDeco.extend({
76
98
  id: z.uuid(),
77
99
  type: z.literal("split"),
78
100
  position: zScaledIntPercentage,
79
- direction: zDirection,
80
- shapes: zSplitDecoShapes
81
- }).strict();
101
+ direction: zDirection
102
+ });
82
103
  export const zRawSplitDeco = zSplitDeco.omit({ shapes: true });
83
- const zCloseDeco = z.object({
104
+ const zCloseDeco = zBaseDeco.extend({
84
105
  id: z.uuid(),
85
106
  type: z.literal("close"),
86
107
  force: z.boolean().optional()
87
- }).strict();
88
- const zDropDeco = z.object({
108
+ });
109
+ const zFrameDragDeco = zBaseDeco.extend({
89
110
  id: z.uuid(),
90
111
  type: z.literal("drop"),
91
112
  position: zSide.or(z.enum(["center"]))
92
- }).strict();
113
+ });
93
114
  export const zDeco = z.union([
94
115
  zSplitDeco,
95
116
  zCloseDeco,
96
- zDropDeco
117
+ zFrameDragDeco
97
118
  ]);
98
119
  export const LAYOUT_ERROR = enumFromArray([
99
120
  "INVALID_ID",
@@ -105,7 +126,20 @@ export const LAYOUT_ERROR = enumFromArray([
105
126
  "CANT_CLOSE_NEARBY_FRAMES_TOO_SMALL",
106
127
  "CANT_CLOSE_SINGLE_FRAME",
107
128
  "CANT_SPLIT_FRAME_TOO_SMALL",
108
- "CANT_CLOSE_WITHOUT_FORCE"
129
+ "CANT_CLOSE_WITHOUT_FORCE",
130
+ "CANT_SWAP_WITH_SELF",
131
+ "CANT_REARRANGE_TO_SAME_RELATIVE_POSITION",
132
+ "CANT_REARRANGE_WITH_DOCKED_EDGES",
133
+ "CANT_REARRANGE_DOCKED_WITH_NON_DOCKED",
134
+ "CANT_SPLIT_DOCKED_FRAME",
135
+ "NO_SPACE_TO_REDISTRIBUTE",
136
+ "REDISTRIBUTE_OUT_OF_BOUNDS",
137
+ "FRAME_ALREADY_DOCKED_ON_SIDE",
138
+ "CANT_LEAVE_NO_UNDOCKED_FRAMES",
139
+ "CANT_UNDOCK_COLLAPSED_FRAME",
140
+ "CANT_COLLAPSE_NOT_DOCKED",
141
+ "CANT_UNCOLLAPSE_NOT_COLLAPSED",
142
+ "NO_FILL_CANDIDATES"
109
143
  ]);
110
144
  export const zWindowCreate = zLayoutWindowLoose.partial({ id: true, pxWidth: true, pxHeight: true, pxX: true, pxY: true }).extend({ frames: zLayoutWindow.shape.frames.optional() });
111
145
  export const zLayoutCreate = baseLayout.loose().extend({
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@witchcraft/layout",
3
3
  "description": "Headless layout manager.",
4
- "version": "0.1.3",
4
+ "version": "0.2.0",
5
5
  "main": "./dist/runtime/index.js",
6
6
  "type": "module",
7
7
  "sideEffects": false,
@@ -29,12 +29,12 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@alanscodelog/utils": "^6.2.0",
32
- "@iconify/json": "^2.2.383",
33
- "es-toolkit": "^1.39.10"
32
+ "@iconify/json": "^2.2.474",
33
+ "es-toolkit": "^1.46.1"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@witchcraft/nuxt-utils": "^0.3.6",
37
- "@witchcraft/ui": "^0.4.1"
37
+ "@witchcraft/ui": "^0.4.4"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@witchcraft/ui": {
@@ -46,43 +46,43 @@
46
46
  },
47
47
  "devDependencies": {
48
48
  "@alanscodelog/commitlint-config": "^3.1.2",
49
- "@alanscodelog/eslint-config": "^6.3.0",
49
+ "@alanscodelog/eslint-config": "^6.3.1",
50
50
  "@alanscodelog/semantic-release-config": "^6.0.2",
51
51
  "@alanscodelog/tsconfigs": "^6.3.0",
52
- "@alanscodelog/vite-config": "^0.0.6",
52
+ "@alanscodelog/vite-config": "^0.0.7",
53
53
  "@commitlint/cli": "^19.8.1",
54
- "@nuxt/eslint-config": "^1.9.0",
55
- "@nuxt/kit": "^4.1.2",
54
+ "@nuxt/eslint-config": "^1.15.2",
55
+ "@nuxt/kit": "^4.4.6",
56
56
  "@nuxt/module-builder": "^1.0.2",
57
- "@nuxt/schema": "^4.1.2",
57
+ "@nuxt/schema": "^4.4.6",
58
58
  "@nuxt/types": "^2.18.1",
59
- "@tailwindcss/vite": "^4.1.12",
60
- "@types/node": "^24.3.3",
61
- "@vitejs/plugin-vue": "^6.0.1",
62
- "@vitest/coverage-c8": "^0.33.0",
59
+ "@tailwindcss/vite": "^4.3.0",
60
+ "@types/node": "^24.12.4",
61
+ "@vitejs/plugin-vue": "^6.0.7",
62
+ "@vitest/coverage-v8": "^4.1.0",
63
63
  "@witchcraft/nuxt-utils": "^0.3.6",
64
- "@witchcraft/ui": "^0.4.1",
64
+ "@witchcraft/ui": "^0.4.4",
65
65
  "concurrently": "^9.2.1",
66
- "cross-env": "^10.0.0",
66
+ "cross-env": "^10.1.0",
67
67
  "fast-glob": "^3.3.3",
68
68
  "http-server": "^14.1.1",
69
69
  "husky": "^9.1.7",
70
70
  "indexit": "2.1.0-beta.3",
71
71
  "madge": "^8.0.0",
72
- "nuxt": "^4.2.1",
72
+ "nuxt": "^4.4.6",
73
73
  "onchange": "^7.1.0",
74
- "semantic-release": "^24.2.8",
75
- "tailwindcss": "^4.1.12",
76
- "typedoc": "0.28.12",
77
- "typescript": "^5.8.3",
78
- "unplugin-icons": "^22.3.0",
79
- "unplugin-vue-components": "^29.0.0",
80
- "uuid": "^13.0.0",
81
- "vite": "^7.1.5",
74
+ "semantic-release": "^24.2.9",
75
+ "tailwindcss": "^4.3.0",
76
+ "typedoc": "0.28.19",
77
+ "typescript": "^5.9.3",
78
+ "unplugin-icons": "^22.5.0",
79
+ "unplugin-vue-components": "^29.2.0",
80
+ "uuid": "^13.0.2",
81
+ "vite": "^7.3.3",
82
82
  "vitest": "^3.2.4",
83
- "vue": "^3.5.20",
83
+ "vue": "^3.5.34",
84
84
  "vue-tsc": "^2.2.12",
85
- "zod": "^4.1.8"
85
+ "zod": "^4.4.3"
86
86
  },
87
87
  "author": "Alan <alanscodelog@gmail.com>",
88
88
  "repository": "https://github.com/witchcraftjs/layout",
@@ -132,15 +132,14 @@
132
132
  "dev:vite": "vite --mode development --config vite.dev.config.ts",
133
133
  "//dev": "The module needs to be build, not stubbed, for vite's dev to work.",
134
134
  "dev": "pnpm dev:vite",
135
- "lint:eslint": "eslint \"{src,tests,bin}/**/*.{cjs,js,ts}\" \"*.{cjs,js,ts}\" --max-warnings=3 --report-unused-disable-directives",
135
+ "lint:eslint": "eslint \"{src,tests,bin}/**/*.{cjs,js,ts}\" \"*.{cjs,js,ts}\" --max-warnings=0 --report-unused-disable-directives",
136
136
  "lint:commits": "commitlint --from-last-tag --to HEAD --verbose",
137
137
  "lint:imports": "echo disabled madge --circular --extensions ts ./src",
138
138
  "lint": "pnpm lint:eslint && pnpm lint:types && pnpm lint:commits && pnpm lint:imports",
139
139
  "lint:types": "vue-tsc --noEmit",
140
140
  "coverage": "vitest --coverage",
141
141
  "coverage:dev": "vitest --watch --coverage",
142
- "test": "echo no tests yet",
143
- "test:watch": "vitest --watch",
142
+ "test": "vitest",
144
143
  "doc": "typedoc",
145
144
  "doc:watch": "onchange -i \"src/**/*.ts\" \"typedoc.config.js\" -- pnpm doc",
146
145
  "doc:serve": "http-server docs --port=5001",
@@ -0,0 +1,30 @@
1
+ <template>
2
+ <div
3
+ class="cursor-grabbing"
4
+ @pointerdown="handlePointerDown"
5
+ >
6
+ <slot/>
7
+ </div>
8
+ </template>
9
+ <script lang="ts" setup>
10
+ import { inject, onBeforeUnmount } from "vue"
11
+ import { dragContextInjectionKey } from "../drag/types.js";
12
+
13
+ const props = defineProps<{
14
+ frameId: string
15
+ }>()
16
+
17
+
18
+ const dragContext = inject(dragContextInjectionKey)
19
+ if (!dragContext) {
20
+ throw new Error("FrameDragHandle must be used inside a LayoutWindow and drag context returned by useFrames must be injected.")
21
+ }
22
+ function handlePointerDown(e: PointerEvent): void {
23
+ e.preventDefault()
24
+ e.stopPropagation()
25
+ dragContext!.dragStart( e,"frame", {frameId: props.frameId})
26
+ }
27
+ onBeforeUnmount(() => {
28
+ dragContext.cancel()
29
+ })
30
+ </script>
@@ -1,52 +1,28 @@
1
1
  <template>
2
2
  <template
3
- v-for="(deco) of splitDecos"
4
- :key="deco.id"
3
+ v-for="(shape, i) of shapes"
4
+ :key="`${shape.type}-${i}`"
5
5
  >
6
6
  <LayoutShapeSquare
7
- class="
8
- deco-split-new-frame
9
- bg-blue-500/50
10
- "
11
- :css="getShapeSquareCss( deco.shapes.newFrame, `var(--layoutEdgeWidth,2px)`)"
7
+ v-if="shape.type === 'square'"
8
+ :css="getShapeSquareCss(shape.data, `var(--layoutEdgeWidth,2px)`)"
9
+ v-bind="shape.attrs ?? {}"
12
10
  />
13
11
  <LayoutShapeSquare
14
- class="
15
- deco-split-edge
16
- bg-red-500
17
- "
18
- :css="getVisualEdgeCss(deco.shapes.edge, {padLongAxis:`var(--layoutEdgeWidth,2px)`})"
19
- />
20
- </template>
21
- <template
22
- v-for="deco of closeDecos"
23
- :key="deco.id"
24
- >
25
- <LayoutShapeSquare
26
- :class="`
27
- ${deco.force ? 'deco-close-force-frame' : 'deco-close-frame'}
28
- bg-red-500/50
29
- `"
30
- :css="getShapeSquareCss( frames[deco.id], `var(--layoutEdgeWidth,2px)`)"
12
+ v-else-if="shape.type === 'edge'"
13
+ :css="getVisualEdgeCss(shape.data, { padLongAxis: 'var(--layoutEdgeWidth,2px)' })"
14
+ v-bind="shape.attrs ?? {}"
31
15
  />
32
16
  </template>
33
17
  </template>
34
18
  <script lang="ts" setup>
35
-
36
19
  import LayoutShapeSquare from "./LayoutShapeSquare.vue"
37
20
 
38
21
  import { getShapeSquareCss } from "../helpers/getShapeSquareCss"
39
22
  import { getVisualEdgeCss } from "../helpers/getVisualEdgeCss"
40
- import { type CloseDeco, type LayoutFrames, type Size, type SplitDeco } from "../types/index.js"
41
-
42
-
43
- const props = withDefaults(defineProps<{
44
- frames: LayoutFrames
45
- splitDecos: SplitDeco[]
46
- closeDecos: CloseDeco[]
47
- } >(),{
48
- })
49
-
23
+ import type { LayoutShape } from "../types/index.js"
50
24
 
25
+ defineProps<{
26
+ shapes: LayoutShape[]
27
+ }>()
51
28
  </script>
52
-
@@ -8,13 +8,12 @@
8
8
  z-0
9
9
  border-blue-500
10
10
  border
11
- rounded-md
12
11
  `,
13
12
  ($attrs as any).class
14
13
  )"
15
- v-bind="{...$attrs, class: undefined}"
14
+ v-bind="{ ...$attrs, class: undefined }"
16
15
  />
17
-
16
+
18
17
  <template
19
18
  v-for="css, i of cssDragEdges"
20
19
  :key="i"
@@ -27,9 +26,9 @@
27
26
  hover:cursor-pointer
28
27
  [&:hover+.edge]:bg-blue-500/50
29
28
  `)"
30
- @pointerdown="emit('dragStart', $event, {edge:edges[i]})"
29
+ @pointerdown="emit('dragStart', $event, 'edge', { edge: edges[i] })"
31
30
  />
32
- <LayoutShapeSquare
31
+ <LayoutShapeSquare
33
32
  :css="css.thin"
34
33
  :class="twMerge(`
35
34
  pointer-events-none
@@ -48,7 +47,10 @@
48
47
  v-for="css, i of cssDragEdge"
49
48
  :key="i"
50
49
  />
51
- <template v-for="css, i of cssDragIntersections" :key="i">
50
+ <template
51
+ v-for="css, i of cssDragIntersections"
52
+ :key="i"
53
+ >
52
54
  <LayoutShapeSquare
53
55
  :css="css.thick"
54
56
  :class="twMerge(`
@@ -57,9 +59,9 @@
57
59
  rounded-full
58
60
  hover:cursor-pointer
59
61
  [&:hover+.intersection]:bg-blue-500/50
60
- `,
62
+ `
61
63
  )"
62
- @pointerdown="emit('dragStart', $event, { intersection:wantedIntersections[i]})"
64
+ @pointerdown="emit('dragStart', $event, 'edge', { intersection: wantedIntersections[i] })"
63
65
  />
64
66
  <LayoutShapeSquare
65
67
  :css="css.thin"
@@ -69,14 +71,15 @@
69
71
  rounded-full
70
72
  pointer-events-none
71
73
  `,
72
- css.thin._shifted && `w-[7px] h-[7px]`,
74
+ css.thin._shifted && `w-[7px] h-[7px]`
73
75
  )"
74
76
  />
75
77
  </template>
76
78
  </template>
79
+
77
80
  <script lang="ts" setup>
78
81
  import { twMerge } from "@witchcraft/ui/utils/twMerge"
79
- import { computed,useAttrs } from "vue"
82
+ import { computed, useAttrs } from "vue"
80
83
 
81
84
  import LayoutShapeSquare from "./LayoutShapeSquare.vue"
82
85
 
@@ -84,25 +87,27 @@ import { getIntersectionsCss } from "../helpers/getIntersectionsCss.js"
84
87
  import { getShapeSquareCss } from "../helpers/getShapeSquareCss.js"
85
88
  import { getVisualEdgesCss } from "../helpers/getVisualEdgesCss.js"
86
89
  import { isEdgeEqual } from "../helpers/isEdgeEqual.js"
87
- import {
88
- type Edge,
89
- type EdgeCss,
90
- type IntersectionEntry,
91
- type LayoutEdgesProps,
90
+ import type {
91
+ Edge,
92
+ EdgeCss,
93
+ IntersectionEntry,
94
+ LayoutEdgesProps
92
95
  } from "../types/index.js"
96
+
93
97
  const $attrs = useAttrs()
94
98
 
95
99
  defineOptions({
96
- inheritAttrs: false,
100
+ inheritAttrs: false
97
101
  })
98
102
 
99
103
  const emit = defineEmits<{
100
- dragStart: [e: PointerEvent, { edge?: Edge, intersection?: IntersectionEntry }]
104
+ dragStart: [e: PointerEvent, type:"edge", opts:{ edge?: Edge, intersection?: IntersectionEntry }]
101
105
  }>()
106
+
102
107
  const props = withDefaults(defineProps<LayoutEdgesProps>(), {
103
108
  activeFrame: undefined,
104
109
  draggingEdge: undefined,
105
- draggingIntersection: undefined,
110
+ draggingIntersection: undefined
106
111
  })
107
112
 
108
113
 
@@ -120,12 +125,12 @@ const cssDragEdges = computed(() => {
120
125
  : props.edges,
121
126
  {
122
127
  edgeWidth: `var(--layoutHandleWidth, 8px)`,
123
- padLongAxis: `var(--layoutEdgeWidth, 2px)`,
128
+ padLongAxis: `var(--layoutEdgeWidth, 2px)`
124
129
  }
125
130
  )
126
131
  const thinEdges = getVisualEdgesCss(props.edges, {
127
132
  edgeWidth: `var(--layoutEdgeWidth, 2px)`,
128
- padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`,
133
+ padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`
129
134
  })
130
135
  const edges: { thin: EdgeCss, thick: EdgeCss }[] = []
131
136
  for (let i = 0; i < thickEdges.length; i++) {
@@ -138,7 +143,7 @@ const cssDragEdge = computed(() => {
138
143
  if (!props.draggingEdge) return []
139
144
  return getVisualEdgesCss([props.draggingEdge], {
140
145
  edgeWidth: `var(--layoutEdgeWidth, 2px)`,
141
- padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`,
146
+ padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`
142
147
  })
143
148
  })
144
149
 
@@ -152,7 +157,7 @@ const cssDragIntersections = computed(() => {
152
157
  thin: ReturnType<typeof getIntersectionsCss>[number]
153
158
  }[] = []
154
159
  const thick = getIntersectionsCss(wantedIntersections.value, {
155
- intersectionWidth: `var(--layoutIntersectionWidth, 15px)`,
160
+ intersectionWidth: `var(--layoutIntersectionWidth, 15px)`
156
161
  })
157
162
  const thin = getIntersectionsCss(wantedIntersections.value, {
158
163
  })
@@ -161,6 +166,5 @@ const cssDragIntersections = computed(() => {
161
166
  }
162
167
  return intersections
163
168
  })
164
-
165
169
  </script>
166
170
 
@@ -10,7 +10,7 @@
10
10
  `,
11
11
  ($attrs as any).class
12
12
  )"
13
- v-bind="{...$attrs, class: undefined}"
13
+ v-bind="{ ...$attrs, class: undefined }"
14
14
  @focus="emit('focus')"
15
15
  >
16
16
  <slot>
@@ -21,20 +21,22 @@
21
21
  </slot>
22
22
  </LayoutShapeSquare>
23
23
  </template>
24
+
24
25
  <script lang="ts" setup>
25
26
  import { twMerge } from "@witchcraft/ui/utils/twMerge"
26
27
  import { useAttrs } from "vue"
28
+
27
29
  const $attrs = useAttrs()
28
30
 
29
31
  defineOptions({
30
- inheritAttrs: false,
32
+ inheritAttrs: false
31
33
  })
32
34
 
33
35
  import LayoutShapeSquare from "./LayoutShapeSquare.vue"
34
36
 
35
37
  import { getShapeSquareCss } from "../helpers/getShapeSquareCss"
36
38
  import { debugFrame } from "../layout/debugFrame.js"
37
- import { type LayoutFrameProps } from "../types/index.js"
39
+ import type { LayoutFrameProps } from "../types/index.js"
38
40
 
39
41
 
40
42
  const emit = defineEmits<{
@@ -42,6 +44,5 @@ const emit = defineEmits<{
42
44
  (e: "focus"): void
43
45
  }>()
44
46
 
45
- /* const props = */defineProps<LayoutFrameProps>(
46
- )
47
+ /* const props = */defineProps<LayoutFrameProps>()
47
48
  </script>
@@ -17,21 +17,27 @@
17
17
  css.translate && `[transform:var(--translate)]`,
18
18
  ($attrs as any).class
19
19
  )"
20
- v-bind="{...$attrs, class: undefined}"
20
+ v-bind="{ ...$attrs, class: undefined }"
21
21
  >
22
22
  <slot/>
23
23
  </div>
24
24
  </template>
25
+
25
26
  <script setup lang="ts">
26
27
  import { twMerge } from "@witchcraft/ui/utils/twMerge"
27
28
  import { useAttrs } from "vue"
29
+ import type { HTMLAttributes } from "vue"
28
30
 
29
31
  import type { LayoutShapeSquareProps } from "../types/index.js"
32
+
30
33
  const $attrs = useAttrs()
31
34
 
32
35
  defineOptions({
33
- inheritAttrs: false,
36
+ inheritAttrs: false
34
37
  })
35
38
 
36
- const props = defineProps<LayoutShapeSquareProps>()
39
+ const props = defineProps<
40
+ & LayoutShapeSquareProps
41
+ & /** @vue-ignore */ HTMLAttributes
42
+ >()
37
43
  </script>