@witchcraft/layout 0.1.2 → 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 (190) 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 +9 -10
  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 +1 -4
  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 +3 -5
  17. package/dist/runtime/components/LayoutShapeSquare.vue.d.ts +3 -1
  18. package/dist/runtime/components/LayoutWindow.d.vue.ts +26 -12
  19. package/dist/runtime/components/LayoutWindow.vue +95 -84
  20. package/dist/runtime/components/LayoutWindow.vue.d.ts +26 -12
  21. package/dist/runtime/composables/useFrames.d.ts +15 -13
  22. package/dist/runtime/composables/useFrames.js +59 -39
  23. package/dist/runtime/demo/App.vue +116 -30
  24. package/dist/runtime/demo/DemoControls.d.vue.ts +4 -1
  25. package/dist/runtime/demo/DemoControls.vue +98 -4
  26. package/dist/runtime/demo/DemoControls.vue.d.ts +4 -1
  27. package/dist/runtime/drag/CloseAction.d.ts +26 -5
  28. package/dist/runtime/drag/CloseAction.js +87 -40
  29. package/dist/runtime/drag/DragActionHandler.d.ts +20 -8
  30. package/dist/runtime/drag/DragActionHandler.js +47 -12
  31. package/dist/runtime/drag/FrameDragAction.d.ts +45 -0
  32. package/dist/runtime/drag/FrameDragAction.js +143 -0
  33. package/dist/runtime/drag/SplitAction.d.ts +32 -11
  34. package/dist/runtime/drag/SplitAction.js +82 -24
  35. package/dist/runtime/drag/createDefaultHandlers.d.ts +9 -0
  36. package/dist/runtime/drag/createDefaultHandlers.js +10 -0
  37. package/dist/runtime/drag/defaultDragActions.d.ts +9 -0
  38. package/dist/runtime/drag/defaultDragActions.js +10 -0
  39. package/dist/runtime/drag/types.d.ts +82 -13
  40. package/dist/runtime/drag/types.js +1 -0
  41. package/dist/runtime/helpers/createZoneSideClipPath.d.ts +12 -0
  42. package/dist/runtime/helpers/createZoneSideClipPath.js +17 -0
  43. package/dist/runtime/helpers/doEdgesOverlap.d.ts +3 -1
  44. package/dist/runtime/helpers/doEdgesOverlap.js +5 -5
  45. package/dist/runtime/helpers/getDockBoundaries.d.ts +19 -0
  46. package/dist/runtime/helpers/getDockBoundaries.js +14 -0
  47. package/dist/runtime/helpers/getEdgeLength.d.ts +2 -0
  48. package/dist/runtime/helpers/getEdgeLength.js +5 -0
  49. package/dist/runtime/helpers/getIntersections.js +2 -2
  50. package/dist/runtime/helpers/getIntersectionsCss.js +2 -2
  51. package/dist/runtime/helpers/getMoveEdgeInfo.js +2 -2
  52. package/dist/runtime/helpers/getResizeLimit.js +2 -2
  53. package/dist/runtime/helpers/getShapeSquareCss.js +2 -2
  54. package/dist/runtime/helpers/getVisualEdgeCss.js +2 -2
  55. package/dist/runtime/helpers/getVisualEdges.d.ts +1 -1
  56. package/dist/runtime/helpers/getVisualEdges.js +4 -3
  57. package/dist/runtime/helpers/index.d.ts +4 -0
  58. package/dist/runtime/helpers/index.js +4 -0
  59. package/dist/runtime/helpers/isEdgeEqual.js +2 -4
  60. package/dist/runtime/helpers/isWindowEdge.js +2 -2
  61. package/dist/runtime/helpers/isWindowEdgePoint.js +2 -2
  62. package/dist/runtime/helpers/moveEdge.js +2 -2
  63. package/dist/runtime/helpers/numberToScaledPercent.d.ts +1 -1
  64. package/dist/runtime/helpers/numberToScaledPercent.js +2 -2
  65. package/dist/runtime/helpers/numberToScaledSize.js +2 -2
  66. package/dist/runtime/helpers/rotateFrames.d.ts +7 -0
  67. package/dist/runtime/helpers/rotateFrames.js +36 -0
  68. package/dist/runtime/helpers/scaledPointToPx.d.ts +13 -0
  69. package/dist/runtime/helpers/scaledPointToPx.js +7 -0
  70. package/dist/runtime/helpers/toWindowCoord.js +2 -2
  71. package/dist/runtime/layout/applyFrameChanges.d.ts +10 -0
  72. package/dist/runtime/layout/applyFrameChanges.js +29 -0
  73. package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +6 -1
  74. package/dist/runtime/layout/createSplitDecoFromDrag.js +4 -4
  75. package/dist/runtime/layout/createSplitDecoShapes.d.ts +7 -0
  76. package/dist/runtime/layout/{createSplitDecoEdge.js → createSplitDecoShapes.js} +6 -3
  77. package/dist/runtime/layout/debugFrame.js +2 -1
  78. package/dist/runtime/layout/findSafeSplitEdge.js +2 -2
  79. package/dist/runtime/layout/frameCreate.js +2 -2
  80. package/dist/runtime/layout/getCloseFrameInfo.d.ts +7 -6
  81. package/dist/runtime/layout/getCloseFrameInfo.js +10 -3
  82. package/dist/runtime/layout/getDragZones.d.ts +8 -0
  83. package/dist/runtime/layout/getDragZones.js +32 -0
  84. package/dist/runtime/layout/getFillEmptySpaceInfo.d.ts +65 -0
  85. package/dist/runtime/layout/getFillEmptySpaceInfo.js +69 -0
  86. package/dist/runtime/layout/getFrameCollapseInfo.d.ts +13 -0
  87. package/dist/runtime/layout/getFrameCollapseInfo.js +93 -0
  88. package/dist/runtime/layout/getFrameDockInfo.d.ts +9 -0
  89. package/dist/runtime/layout/getFrameDockInfo.js +82 -0
  90. package/dist/runtime/layout/getFrameDragZones.d.ts +16 -0
  91. package/dist/runtime/layout/getFrameDragZones.js +74 -0
  92. package/dist/runtime/layout/getFrameRearrangeInfo.d.ts +139 -0
  93. package/dist/runtime/layout/getFrameRearrangeInfo.js +87 -0
  94. package/dist/runtime/layout/getFrameSplitInfo.d.ts +7 -5
  95. package/dist/runtime/layout/getFrameSplitInfo.js +10 -3
  96. package/dist/runtime/layout/getFrameSwapInfo.d.ts +9 -0
  97. package/dist/runtime/layout/getFrameSwapInfo.js +27 -0
  98. package/dist/runtime/layout/getFrameTo.js +2 -2
  99. package/dist/runtime/layout/getFrameUncollapseInfo.d.ts +12 -0
  100. package/dist/runtime/layout/getFrameUncollapseInfo.js +88 -0
  101. package/dist/runtime/layout/getFrameUndockInfo.d.ts +13 -0
  102. package/dist/runtime/layout/getFrameUndockInfo.js +51 -0
  103. package/dist/runtime/layout/getFramesRedistributeInfo.d.ts +29 -0
  104. package/dist/runtime/layout/getFramesRedistributeInfo.js +53 -0
  105. package/dist/runtime/layout/getWindowDragZones.d.ts +6 -0
  106. package/dist/runtime/layout/getWindowDragZones.js +49 -0
  107. package/dist/runtime/layout/index.d.ts +14 -5
  108. package/dist/runtime/layout/index.js +14 -5
  109. package/dist/runtime/layout/isPointInRect.d.ts +7 -0
  110. package/dist/runtime/layout/{isPointInFrame.js → isPointInRect.js} +1 -1
  111. package/dist/runtime/layout/resizeFrame.js +2 -2
  112. package/dist/runtime/settings.d.ts +41 -16
  113. package/dist/runtime/settings.js +95 -53
  114. package/dist/runtime/types/index.d.ts +324 -55
  115. package/dist/runtime/types/index.js +54 -20
  116. package/package.json +28 -29
  117. package/src/runtime/components/FrameDragHandle.vue +30 -0
  118. package/src/runtime/components/LayoutDecos.vue +12 -36
  119. package/src/runtime/components/LayoutEdges.vue +27 -22
  120. package/src/runtime/components/LayoutFrame.vue +6 -5
  121. package/src/runtime/components/LayoutShapeSquare.vue +11 -5
  122. package/src/runtime/components/LayoutWindow.vue +110 -101
  123. package/src/runtime/composables/useFrames.ts +80 -50
  124. package/src/runtime/demo/App.vue +126 -36
  125. package/src/runtime/demo/DemoControls.vue +115 -6
  126. package/src/runtime/drag/CloseAction.ts +106 -44
  127. package/src/runtime/drag/DragActionHandler.ts +71 -20
  128. package/src/runtime/drag/FrameDragAction.ts +202 -0
  129. package/src/runtime/drag/SplitAction.ts +106 -34
  130. package/src/runtime/drag/createDefaultHandlers.ts +19 -0
  131. package/src/runtime/drag/defaultDragActions.ts +19 -0
  132. package/src/runtime/drag/types.ts +90 -20
  133. package/src/runtime/helpers/createZoneSideClipPath.ts +41 -0
  134. package/src/runtime/helpers/doEdgesOverlap.ts +11 -5
  135. package/src/runtime/helpers/getDockBoundaries.ts +36 -0
  136. package/src/runtime/helpers/getEdgeLength.ts +10 -0
  137. package/src/runtime/helpers/getIntersections.ts +2 -2
  138. package/src/runtime/helpers/getIntersectionsCss.ts +2 -2
  139. package/src/runtime/helpers/getMoveEdgeInfo.ts +2 -2
  140. package/src/runtime/helpers/getResizeLimit.ts +2 -2
  141. package/src/runtime/helpers/getShapeSquareCss.ts +2 -2
  142. package/src/runtime/helpers/getVisualEdgeCss.ts +2 -2
  143. package/src/runtime/helpers/getVisualEdges.ts +5 -4
  144. package/src/runtime/helpers/index.ts +4 -0
  145. package/src/runtime/helpers/isEdgeEqual.ts +2 -4
  146. package/src/runtime/helpers/isWindowEdge.ts +2 -2
  147. package/src/runtime/helpers/isWindowEdgePoint.ts +2 -2
  148. package/src/runtime/helpers/moveEdge.ts +2 -2
  149. package/src/runtime/helpers/numberToScaledPercent.ts +3 -3
  150. package/src/runtime/helpers/numberToScaledSize.ts +2 -2
  151. package/src/runtime/helpers/rotateFrames.ts +45 -0
  152. package/src/runtime/helpers/scaledPointToPx.ts +13 -0
  153. package/src/runtime/helpers/toWindowCoord.ts +2 -2
  154. package/src/runtime/layout/applyFrameChanges.ts +39 -0
  155. package/src/runtime/layout/createSplitDecoFromDrag.ts +12 -6
  156. package/src/runtime/layout/{createSplitDecoEdge.ts → createSplitDecoShapes.ts} +17 -7
  157. package/src/runtime/layout/debugFrame.ts +1 -1
  158. package/src/runtime/layout/findSafeSplitEdge.ts +3 -3
  159. package/src/runtime/layout/frameCreate.ts +2 -2
  160. package/src/runtime/layout/getCloseFrameInfo.ts +21 -8
  161. package/src/runtime/layout/getDragZones.ts +48 -0
  162. package/src/runtime/layout/getFillEmptySpaceInfo.ts +177 -0
  163. package/src/runtime/layout/getFrameCollapseInfo.ts +164 -0
  164. package/src/runtime/layout/getFrameDockInfo.ts +126 -0
  165. package/src/runtime/layout/getFrameDragZones.ts +100 -0
  166. package/src/runtime/layout/getFrameRearrangeInfo.ts +261 -0
  167. package/src/runtime/layout/getFrameSplitInfo.ts +21 -8
  168. package/src/runtime/layout/getFrameSwapInfo.ts +45 -0
  169. package/src/runtime/layout/getFrameTo.ts +2 -2
  170. package/src/runtime/layout/getFrameUncollapseInfo.ts +160 -0
  171. package/src/runtime/layout/getFrameUndockInfo.ts +97 -0
  172. package/src/runtime/layout/getFramesRedistributeInfo.ts +98 -0
  173. package/src/runtime/layout/getWindowDragZones.ts +59 -0
  174. package/src/runtime/layout/index.ts +14 -5
  175. package/src/runtime/layout/isPointInRect.ts +7 -0
  176. package/src/runtime/layout/resizeFrame.ts +2 -2
  177. package/src/runtime/settings.ts +69 -49
  178. package/src/runtime/types/index.ts +143 -28
  179. package/dist/runtime/layout/closeFrame.d.ts +0 -5
  180. package/dist/runtime/layout/closeFrame.js +0 -13
  181. package/dist/runtime/layout/closeFrames.d.ts +0 -2
  182. package/dist/runtime/layout/closeFrames.js +0 -8
  183. package/dist/runtime/layout/createSplitDecoEdge.d.ts +0 -2
  184. package/dist/runtime/layout/frameSplit.d.ts +0 -16
  185. package/dist/runtime/layout/frameSplit.js +0 -9
  186. package/dist/runtime/layout/isPointInFrame.d.ts +0 -2
  187. package/src/runtime/layout/closeFrame.ts +0 -33
  188. package/src/runtime/layout/closeFrames.ts +0 -14
  189. package/src/runtime/layout/frameSplit.ts +0 -31
  190. 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.2",
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.0-beta.3"
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.0-beta.3",
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
-
@@ -11,9 +11,9 @@
11
11
  `,
12
12
  ($attrs as any).class
13
13
  )"
14
- v-bind="{...$attrs, class: undefined}"
14
+ v-bind="{ ...$attrs, class: undefined }"
15
15
  />
16
-
16
+
17
17
  <template
18
18
  v-for="css, i of cssDragEdges"
19
19
  :key="i"
@@ -26,9 +26,9 @@
26
26
  hover:cursor-pointer
27
27
  [&:hover+.edge]:bg-blue-500/50
28
28
  `)"
29
- @pointerdown="emit('dragStart', $event, {edge:edges[i]})"
29
+ @pointerdown="emit('dragStart', $event, 'edge', { edge: edges[i] })"
30
30
  />
31
- <LayoutShapeSquare
31
+ <LayoutShapeSquare
32
32
  :css="css.thin"
33
33
  :class="twMerge(`
34
34
  pointer-events-none
@@ -47,7 +47,10 @@
47
47
  v-for="css, i of cssDragEdge"
48
48
  :key="i"
49
49
  />
50
- <template v-for="css, i of cssDragIntersections" :key="i">
50
+ <template
51
+ v-for="css, i of cssDragIntersections"
52
+ :key="i"
53
+ >
51
54
  <LayoutShapeSquare
52
55
  :css="css.thick"
53
56
  :class="twMerge(`
@@ -56,9 +59,9 @@
56
59
  rounded-full
57
60
  hover:cursor-pointer
58
61
  [&:hover+.intersection]:bg-blue-500/50
59
- `,
62
+ `
60
63
  )"
61
- @pointerdown="emit('dragStart', $event, { intersection:wantedIntersections[i]})"
64
+ @pointerdown="emit('dragStart', $event, 'edge', { intersection: wantedIntersections[i] })"
62
65
  />
63
66
  <LayoutShapeSquare
64
67
  :css="css.thin"
@@ -68,14 +71,15 @@
68
71
  rounded-full
69
72
  pointer-events-none
70
73
  `,
71
- css.thin._shifted && `w-[7px] h-[7px]`,
74
+ css.thin._shifted && `w-[7px] h-[7px]`
72
75
  )"
73
76
  />
74
77
  </template>
75
78
  </template>
79
+
76
80
  <script lang="ts" setup>
77
81
  import { twMerge } from "@witchcraft/ui/utils/twMerge"
78
- import { computed,useAttrs } from "vue"
82
+ import { computed, useAttrs } from "vue"
79
83
 
80
84
  import LayoutShapeSquare from "./LayoutShapeSquare.vue"
81
85
 
@@ -83,25 +87,27 @@ import { getIntersectionsCss } from "../helpers/getIntersectionsCss.js"
83
87
  import { getShapeSquareCss } from "../helpers/getShapeSquareCss.js"
84
88
  import { getVisualEdgesCss } from "../helpers/getVisualEdgesCss.js"
85
89
  import { isEdgeEqual } from "../helpers/isEdgeEqual.js"
86
- import {
87
- type Edge,
88
- type EdgeCss,
89
- type IntersectionEntry,
90
- type LayoutEdgesProps,
90
+ import type {
91
+ Edge,
92
+ EdgeCss,
93
+ IntersectionEntry,
94
+ LayoutEdgesProps
91
95
  } from "../types/index.js"
96
+
92
97
  const $attrs = useAttrs()
93
98
 
94
99
  defineOptions({
95
- inheritAttrs: false,
100
+ inheritAttrs: false
96
101
  })
97
102
 
98
103
  const emit = defineEmits<{
99
- dragStart: [e: PointerEvent, { edge?: Edge, intersection?: IntersectionEntry }]
104
+ dragStart: [e: PointerEvent, type:"edge", opts:{ edge?: Edge, intersection?: IntersectionEntry }]
100
105
  }>()
106
+
101
107
  const props = withDefaults(defineProps<LayoutEdgesProps>(), {
102
108
  activeFrame: undefined,
103
109
  draggingEdge: undefined,
104
- draggingIntersection: undefined,
110
+ draggingIntersection: undefined
105
111
  })
106
112
 
107
113
 
@@ -119,12 +125,12 @@ const cssDragEdges = computed(() => {
119
125
  : props.edges,
120
126
  {
121
127
  edgeWidth: `var(--layoutHandleWidth, 8px)`,
122
- padLongAxis: `var(--layoutEdgeWidth, 2px)`,
128
+ padLongAxis: `var(--layoutEdgeWidth, 2px)`
123
129
  }
124
130
  )
125
131
  const thinEdges = getVisualEdgesCss(props.edges, {
126
132
  edgeWidth: `var(--layoutEdgeWidth, 2px)`,
127
- padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`,
133
+ padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`
128
134
  })
129
135
  const edges: { thin: EdgeCss, thick: EdgeCss }[] = []
130
136
  for (let i = 0; i < thickEdges.length; i++) {
@@ -137,7 +143,7 @@ const cssDragEdge = computed(() => {
137
143
  if (!props.draggingEdge) return []
138
144
  return getVisualEdgesCss([props.draggingEdge], {
139
145
  edgeWidth: `var(--layoutEdgeWidth, 2px)`,
140
- padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`,
146
+ padLongAxis: `(var(--layoutEdgeWidth, 2px) + var(--layoutExtraDragEdgePadding, 0px))`
141
147
  })
142
148
  })
143
149
 
@@ -151,7 +157,7 @@ const cssDragIntersections = computed(() => {
151
157
  thin: ReturnType<typeof getIntersectionsCss>[number]
152
158
  }[] = []
153
159
  const thick = getIntersectionsCss(wantedIntersections.value, {
154
- intersectionWidth: `var(--layoutIntersectionWidth, 15px)`,
160
+ intersectionWidth: `var(--layoutIntersectionWidth, 15px)`
155
161
  })
156
162
  const thin = getIntersectionsCss(wantedIntersections.value, {
157
163
  })
@@ -160,6 +166,5 @@ const cssDragIntersections = computed(() => {
160
166
  }
161
167
  return intersections
162
168
  })
163
-
164
169
  </script>
165
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>
@@ -1,12 +1,12 @@
1
1
  <template>
2
2
  <div
3
- :style="`
3
+ :style="[`
4
4
  --posX:${css.x};
5
5
  --posY:${css.y};
6
6
  --width:${css.width};
7
7
  --height:${css.height};
8
8
  ${css.translate ? `--translate:${css.translate}`: ``}
9
- ` + style"
9
+ `, $attrs.style]"
10
10
  :class="twMerge(`
11
11
  absolute
12
12
  w-[var(--width)]
@@ -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>