@witchcraft/layout 1.0.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 (336) hide show
  1. package/README.md +474 -0
  2. package/dist/module.d.mts +14 -0
  3. package/dist/module.json +9 -0
  4. package/dist/module.mjs +26 -0
  5. package/dist/runtime/components/LayoutDecos.d.vue.ts +0 -0
  6. package/dist/runtime/components/LayoutDecos.vue +54 -0
  7. package/dist/runtime/components/LayoutDecos.vue.d.ts +0 -0
  8. package/dist/runtime/components/LayoutEdges.d.vue.ts +0 -0
  9. package/dist/runtime/components/LayoutEdges.vue +145 -0
  10. package/dist/runtime/components/LayoutEdges.vue.d.ts +0 -0
  11. package/dist/runtime/components/LayoutFrame.d.vue.ts +0 -0
  12. package/dist/runtime/components/LayoutFrame.vue +41 -0
  13. package/dist/runtime/components/LayoutFrame.vue.d.ts +0 -0
  14. package/dist/runtime/components/LayoutShapeSquare.d.vue.ts +0 -0
  15. package/dist/runtime/components/LayoutShapeSquare.vue +36 -0
  16. package/dist/runtime/components/LayoutShapeSquare.vue.d.ts +0 -0
  17. package/dist/runtime/components/LayoutWindow.d.vue.ts +0 -0
  18. package/dist/runtime/components/LayoutWindow.vue +183 -0
  19. package/dist/runtime/components/LayoutWindow.vue.d.ts +0 -0
  20. package/dist/runtime/composables/useFrames.d.ts +0 -0
  21. package/dist/runtime/composables/useFrames.js +184 -0
  22. package/dist/runtime/demo/App.d.vue.ts +0 -0
  23. package/dist/runtime/demo/App.vue +123 -0
  24. package/dist/runtime/demo/App.vue.d.ts +0 -0
  25. package/dist/runtime/demo/DemoControls.d.vue.ts +0 -0
  26. package/dist/runtime/demo/DemoControls.vue +14 -0
  27. package/dist/runtime/demo/DemoControls.vue.d.ts +0 -0
  28. package/dist/runtime/demo/README.md +1 -0
  29. package/dist/runtime/demo/main.d.ts +0 -0
  30. package/dist/runtime/demo/main.js +4 -0
  31. package/dist/runtime/demo/sharedLayoutInstance.d.ts +0 -0
  32. package/dist/runtime/demo/sharedLayoutInstance.js +5 -0
  33. package/dist/runtime/demo/tailwind.css +1 -0
  34. package/dist/runtime/drag/CloseAction.d.ts +0 -0
  35. package/dist/runtime/drag/CloseAction.js +121 -0
  36. package/dist/runtime/drag/DragActionHandler.d.ts +0 -0
  37. package/dist/runtime/drag/DragActionHandler.js +83 -0
  38. package/dist/runtime/drag/DragDirectionStore.d.ts +0 -0
  39. package/dist/runtime/drag/DragDirectionStore.js +45 -0
  40. package/dist/runtime/drag/SplitAction.d.ts +0 -0
  41. package/dist/runtime/drag/SplitAction.js +110 -0
  42. package/dist/runtime/drag/types.d.ts +0 -0
  43. package/dist/runtime/drag/types.js +0 -0
  44. package/dist/runtime/helpers/addPointsToIntersection.d.ts +0 -0
  45. package/dist/runtime/helpers/addPointsToIntersection.js +7 -0
  46. package/dist/runtime/helpers/assertEdgeSorted.d.ts +0 -0
  47. package/dist/runtime/helpers/assertEdgeSorted.js +7 -0
  48. package/dist/runtime/helpers/assertItemIn.d.ts +0 -0
  49. package/dist/runtime/helpers/assertItemIn.js +8 -0
  50. package/dist/runtime/helpers/assertItemNotIn.d.ts +0 -0
  51. package/dist/runtime/helpers/assertItemNotIn.js +7 -0
  52. package/dist/runtime/helpers/assertLayoutHasActiveWindow.d.ts +0 -0
  53. package/dist/runtime/helpers/assertLayoutHasActiveWindow.js +7 -0
  54. package/dist/runtime/helpers/assertValidWinAndFrame.d.ts +0 -0
  55. package/dist/runtime/helpers/assertValidWinAndFrame.js +5 -0
  56. package/dist/runtime/helpers/assertValidWinAndFrameIds.d.ts +0 -0
  57. package/dist/runtime/helpers/assertValidWinAndFrameIds.js +6 -0
  58. package/dist/runtime/helpers/assertWindowHasActiveFrame.d.ts +0 -0
  59. package/dist/runtime/helpers/assertWindowHasActiveFrame.js +7 -0
  60. package/dist/runtime/helpers/clampNumber.d.ts +0 -0
  61. package/dist/runtime/helpers/clampNumber.js +3 -0
  62. package/dist/runtime/helpers/cloneFrame.d.ts +0 -0
  63. package/dist/runtime/helpers/cloneFrame.js +3 -0
  64. package/dist/runtime/helpers/cloneFrames.d.ts +0 -0
  65. package/dist/runtime/helpers/cloneFrames.js +16 -0
  66. package/dist/runtime/helpers/containsEdge.d.ts +0 -0
  67. package/dist/runtime/helpers/containsEdge.js +13 -0
  68. package/dist/runtime/helpers/convertLayoutWindowToWorkspace.d.ts +0 -0
  69. package/dist/runtime/helpers/convertLayoutWindowToWorkspace.js +10 -0
  70. package/dist/runtime/helpers/copySize.d.ts +0 -0
  71. package/dist/runtime/helpers/copySize.js +5 -0
  72. package/dist/runtime/helpers/createEdge.d.ts +0 -0
  73. package/dist/runtime/helpers/createEdge.js +13 -0
  74. package/dist/runtime/helpers/dirToOrientation.d.ts +0 -0
  75. package/dist/runtime/helpers/dirToOrientation.js +10 -0
  76. package/dist/runtime/helpers/dirToSide.d.ts +0 -0
  77. package/dist/runtime/helpers/dirToSide.js +5 -0
  78. package/dist/runtime/helpers/doEdgesOverlap.d.ts +0 -0
  79. package/dist/runtime/helpers/doEdgesOverlap.js +22 -0
  80. package/dist/runtime/helpers/doesEdgeContinueEdge.d.ts +0 -0
  81. package/dist/runtime/helpers/doesEdgeContinueEdge.js +17 -0
  82. package/dist/runtime/helpers/edgeToPoints.d.ts +0 -0
  83. package/dist/runtime/helpers/edgeToPoints.js +3 -0
  84. package/dist/runtime/helpers/findDraggableEdge.d.ts +0 -0
  85. package/dist/runtime/helpers/findDraggableEdge.js +13 -0
  86. package/dist/runtime/helpers/findFrameDraggableEdges.d.ts +0 -0
  87. package/dist/runtime/helpers/findFrameDraggableEdges.js +18 -0
  88. package/dist/runtime/helpers/frameToEdges.d.ts +0 -0
  89. package/dist/runtime/helpers/frameToEdges.js +21 -0
  90. package/dist/runtime/helpers/frameToPoints.d.ts +0 -0
  91. package/dist/runtime/helpers/frameToPoints.js +7 -0
  92. package/dist/runtime/helpers/getEdgeOrientation.d.ts +0 -0
  93. package/dist/runtime/helpers/getEdgeOrientation.js +4 -0
  94. package/dist/runtime/helpers/getEdgeSharedDirection.d.ts +0 -0
  95. package/dist/runtime/helpers/getEdgeSharedDirection.js +7 -0
  96. package/dist/runtime/helpers/getEdgeSide.d.ts +0 -0
  97. package/dist/runtime/helpers/getEdgeSide.js +16 -0
  98. package/dist/runtime/helpers/getFrameById.d.ts +0 -0
  99. package/dist/runtime/helpers/getFrameById.js +5 -0
  100. package/dist/runtime/helpers/getFrameConstant.d.ts +0 -0
  101. package/dist/runtime/helpers/getFrameConstant.js +15 -0
  102. package/dist/runtime/helpers/getIntersections.d.ts +0 -0
  103. package/dist/runtime/helpers/getIntersections.js +63 -0
  104. package/dist/runtime/helpers/getIntersectionsCss.d.ts +0 -0
  105. package/dist/runtime/helpers/getIntersectionsCss.js +56 -0
  106. package/dist/runtime/helpers/getMoveEdgeInfo.d.ts +0 -0
  107. package/dist/runtime/helpers/getMoveEdgeInfo.js +42 -0
  108. package/dist/runtime/helpers/getResizeLimit.d.ts +0 -0
  109. package/dist/runtime/helpers/getResizeLimit.js +39 -0
  110. package/dist/runtime/helpers/getShapeSquareCss.d.ts +0 -0
  111. package/dist/runtime/helpers/getShapeSquareCss.js +17 -0
  112. package/dist/runtime/helpers/getSideTouching.d.ts +0 -0
  113. package/dist/runtime/helpers/getSideTouching.js +7 -0
  114. package/dist/runtime/helpers/getVisualEdgeCss.d.ts +0 -0
  115. package/dist/runtime/helpers/getVisualEdgeCss.js +40 -0
  116. package/dist/runtime/helpers/getVisualEdges.d.ts +0 -0
  117. package/dist/runtime/helpers/getVisualEdges.js +89 -0
  118. package/dist/runtime/helpers/getVisualEdgesCss.d.ts +0 -0
  119. package/dist/runtime/helpers/getVisualEdgesCss.js +4 -0
  120. package/dist/runtime/helpers/getWinAndFrameById.d.ts +0 -0
  121. package/dist/runtime/helpers/getWinAndFrameById.js +14 -0
  122. package/dist/runtime/helpers/getWinByFrameUuid.d.ts +0 -0
  123. package/dist/runtime/helpers/getWinByFrameUuid.js +13 -0
  124. package/dist/runtime/helpers/getWinById.d.ts +0 -0
  125. package/dist/runtime/helpers/getWinById.js +5 -0
  126. package/dist/runtime/helpers/getWindowConstant.d.ts +0 -0
  127. package/dist/runtime/helpers/getWindowConstant.js +14 -0
  128. package/dist/runtime/helpers/inRange.d.ts +0 -0
  129. package/dist/runtime/helpers/inRange.js +3 -0
  130. package/dist/runtime/helpers/index.d.ts +0 -0
  131. package/dist/runtime/helpers/index.js +62 -0
  132. package/dist/runtime/helpers/isEdgeEqual.d.ts +0 -0
  133. package/dist/runtime/helpers/isEdgeEqual.js +11 -0
  134. package/dist/runtime/helpers/isEdgeParallel.d.ts +0 -0
  135. package/dist/runtime/helpers/isEdgeParallel.js +7 -0
  136. package/dist/runtime/helpers/isPointEqual.d.ts +0 -0
  137. package/dist/runtime/helpers/isPointEqual.js +3 -0
  138. package/dist/runtime/helpers/isSizeAboveMin.d.ts +0 -0
  139. package/dist/runtime/helpers/isSizeAboveMin.js +3 -0
  140. package/dist/runtime/helpers/isSizeEqual.d.ts +0 -0
  141. package/dist/runtime/helpers/isSizeEqual.js +3 -0
  142. package/dist/runtime/helpers/isWindowEdge.d.ts +0 -0
  143. package/dist/runtime/helpers/isWindowEdge.js +7 -0
  144. package/dist/runtime/helpers/isWindowEdgePoint.d.ts +0 -0
  145. package/dist/runtime/helpers/isWindowEdgePoint.js +5 -0
  146. package/dist/runtime/helpers/moveEdge.d.ts +0 -0
  147. package/dist/runtime/helpers/moveEdge.js +8 -0
  148. package/dist/runtime/helpers/numberToScaledPercent.d.ts +0 -0
  149. package/dist/runtime/helpers/numberToScaledPercent.js +5 -0
  150. package/dist/runtime/helpers/numberToScaledSize.d.ts +0 -0
  151. package/dist/runtime/helpers/numberToScaledSize.js +19 -0
  152. package/dist/runtime/helpers/oppositeSide.d.ts +0 -0
  153. package/dist/runtime/helpers/oppositeSide.js +30 -0
  154. package/dist/runtime/helpers/resizeByEdge.d.ts +0 -0
  155. package/dist/runtime/helpers/resizeByEdge.js +29 -0
  156. package/dist/runtime/helpers/sideToDirection.d.ts +0 -0
  157. package/dist/runtime/helpers/sideToDirection.js +11 -0
  158. package/dist/runtime/helpers/sideToOrientation.d.ts +0 -0
  159. package/dist/runtime/helpers/sideToOrientation.js +10 -0
  160. package/dist/runtime/helpers/splitEdge.d.ts +0 -0
  161. package/dist/runtime/helpers/splitEdge.js +20 -0
  162. package/dist/runtime/helpers/toCoord.d.ts +0 -0
  163. package/dist/runtime/helpers/toCoord.js +10 -0
  164. package/dist/runtime/helpers/toId.d.ts +0 -0
  165. package/dist/runtime/helpers/toId.js +4 -0
  166. package/dist/runtime/helpers/toWindowCoord.d.ts +0 -0
  167. package/dist/runtime/helpers/toWindowCoord.js +14 -0
  168. package/dist/runtime/helpers/unionEdges.d.ts +0 -0
  169. package/dist/runtime/helpers/unionEdges.js +8 -0
  170. package/dist/runtime/helpers/updateWindowSizeWithEvent.d.ts +0 -0
  171. package/dist/runtime/helpers/updateWindowSizeWithEvent.js +8 -0
  172. package/dist/runtime/index.d.ts +0 -0
  173. package/dist/runtime/index.js +5 -0
  174. package/dist/runtime/layout/closeFrame.d.ts +0 -0
  175. package/dist/runtime/layout/closeFrame.js +13 -0
  176. package/dist/runtime/layout/closeFrames.d.ts +0 -0
  177. package/dist/runtime/layout/closeFrames.js +8 -0
  178. package/dist/runtime/layout/createSplitDecoEdge.d.ts +0 -0
  179. package/dist/runtime/layout/createSplitDecoEdge.js +24 -0
  180. package/dist/runtime/layout/createSplitDecoFromDrag.d.ts +0 -0
  181. package/dist/runtime/layout/createSplitDecoFromDrag.js +14 -0
  182. package/dist/runtime/layout/debugFrame.d.ts +0 -0
  183. package/dist/runtime/layout/debugFrame.js +4 -0
  184. package/dist/runtime/layout/findFramesTouchingEdge.d.ts +0 -0
  185. package/dist/runtime/layout/findFramesTouchingEdge.js +33 -0
  186. package/dist/runtime/layout/findSafeSplitEdge.d.ts +0 -0
  187. package/dist/runtime/layout/findSafeSplitEdge.js +20 -0
  188. package/dist/runtime/layout/findVisualEdge.d.ts +0 -0
  189. package/dist/runtime/layout/findVisualEdge.js +9 -0
  190. package/dist/runtime/layout/frameCreate.d.ts +0 -0
  191. package/dist/runtime/layout/frameCreate.js +13 -0
  192. package/dist/runtime/layout/frameSplit.d.ts +0 -0
  193. package/dist/runtime/layout/frameSplit.js +9 -0
  194. package/dist/runtime/layout/getCloseFrameInfo.d.ts +0 -0
  195. package/dist/runtime/layout/getCloseFrameInfo.js +103 -0
  196. package/dist/runtime/layout/getFrameSplitInfo.d.ts +0 -0
  197. package/dist/runtime/layout/getFrameSplitInfo.js +40 -0
  198. package/dist/runtime/layout/getFrameTo.d.ts +0 -0
  199. package/dist/runtime/layout/getFrameTo.js +47 -0
  200. package/dist/runtime/layout/index.d.ts +0 -0
  201. package/dist/runtime/layout/index.js +22 -0
  202. package/dist/runtime/layout/isPointInFrame.d.ts +0 -0
  203. package/dist/runtime/layout/isPointInFrame.js +4 -0
  204. package/dist/runtime/layout/layoutAddWindow.d.ts +0 -0
  205. package/dist/runtime/layout/layoutAddWindow.js +4 -0
  206. package/dist/runtime/layout/layoutCreate.d.ts +0 -0
  207. package/dist/runtime/layout/layoutCreate.js +7 -0
  208. package/dist/runtime/layout/layoutRemoveWindow.d.ts +0 -0
  209. package/dist/runtime/layout/layoutRemoveWindow.js +5 -0
  210. package/dist/runtime/layout/resizeFrame.d.ts +0 -0
  211. package/dist/runtime/layout/resizeFrame.js +69 -0
  212. package/dist/runtime/layout/windowAddFrame.d.ts +0 -0
  213. package/dist/runtime/layout/windowAddFrame.js +4 -0
  214. package/dist/runtime/layout/windowCreate.d.ts +0 -0
  215. package/dist/runtime/layout/windowCreate.js +13 -0
  216. package/dist/runtime/layout/windowRemoveFrame.d.ts +0 -0
  217. package/dist/runtime/layout/windowRemoveFrame.js +5 -0
  218. package/dist/runtime/layout/windowSetActiveFrame.d.ts +0 -0
  219. package/dist/runtime/layout/windowSetActiveFrame.js +5 -0
  220. package/dist/runtime/settings.d.ts +0 -0
  221. package/dist/runtime/settings.js +54 -0
  222. package/dist/runtime/types/index.d.ts +0 -0
  223. package/dist/runtime/types/index.js +120 -0
  224. package/dist/runtime/utils/KnownError.d.ts +0 -0
  225. package/dist/runtime/utils/KnownError.js +9 -0
  226. package/dist/types.d.mts +5 -0
  227. package/package.json +153 -0
  228. package/src/module.ts +43 -0
  229. package/src/runtime/components/LayoutDecos.vue +62 -0
  230. package/src/runtime/components/LayoutEdges.vue +172 -0
  231. package/src/runtime/components/LayoutFrame.vue +47 -0
  232. package/src/runtime/components/LayoutShapeSquare.vue +38 -0
  233. package/src/runtime/components/LayoutWindow.vue +223 -0
  234. package/src/runtime/composables/useFrames.ts +251 -0
  235. package/src/runtime/demo/App.vue +140 -0
  236. package/src/runtime/demo/DemoControls.vue +17 -0
  237. package/src/runtime/demo/README.md +1 -0
  238. package/src/runtime/demo/main.ts +9 -0
  239. package/src/runtime/demo/sharedLayoutInstance.ts +7 -0
  240. package/src/runtime/demo/tailwind.css +4 -0
  241. package/src/runtime/drag/CloseAction.ts +158 -0
  242. package/src/runtime/drag/DragActionHandler.ts +146 -0
  243. package/src/runtime/drag/DragDirectionStore.ts +63 -0
  244. package/src/runtime/drag/SplitAction.ts +147 -0
  245. package/src/runtime/drag/types.ts +107 -0
  246. package/src/runtime/helpers/addPointsToIntersection.ts +9 -0
  247. package/src/runtime/helpers/assertEdgeSorted.ts +11 -0
  248. package/src/runtime/helpers/assertItemIn.ts +13 -0
  249. package/src/runtime/helpers/assertItemNotIn.ts +10 -0
  250. package/src/runtime/helpers/assertLayoutHasActiveWindow.ts +9 -0
  251. package/src/runtime/helpers/assertValidWinAndFrame.ts +16 -0
  252. package/src/runtime/helpers/assertValidWinAndFrameIds.ts +9 -0
  253. package/src/runtime/helpers/assertWindowHasActiveFrame.ts +9 -0
  254. package/src/runtime/helpers/clampNumber.ts +9 -0
  255. package/src/runtime/helpers/cloneFrame.ts +5 -0
  256. package/src/runtime/helpers/cloneFrames.ts +20 -0
  257. package/src/runtime/helpers/containsEdge.ts +16 -0
  258. package/src/runtime/helpers/convertLayoutWindowToWorkspace.ts +18 -0
  259. package/src/runtime/helpers/copySize.ts +7 -0
  260. package/src/runtime/helpers/createEdge.ts +19 -0
  261. package/src/runtime/helpers/dirToOrientation.ts +12 -0
  262. package/src/runtime/helpers/dirToSide.ts +7 -0
  263. package/src/runtime/helpers/doEdgesOverlap.ts +25 -0
  264. package/src/runtime/helpers/doesEdgeContinueEdge.ts +20 -0
  265. package/src/runtime/helpers/edgeToPoints.ts +5 -0
  266. package/src/runtime/helpers/findDraggableEdge.ts +24 -0
  267. package/src/runtime/helpers/findFrameDraggableEdges.ts +32 -0
  268. package/src/runtime/helpers/frameToEdges.ts +32 -0
  269. package/src/runtime/helpers/frameToPoints.ts +14 -0
  270. package/src/runtime/helpers/getEdgeOrientation.ts +6 -0
  271. package/src/runtime/helpers/getEdgeSharedDirection.ts +10 -0
  272. package/src/runtime/helpers/getEdgeSide.ts +27 -0
  273. package/src/runtime/helpers/getFrameById.ts +15 -0
  274. package/src/runtime/helpers/getFrameConstant.ts +22 -0
  275. package/src/runtime/helpers/getIntersections.ts +87 -0
  276. package/src/runtime/helpers/getIntersectionsCss.ts +65 -0
  277. package/src/runtime/helpers/getMoveEdgeInfo.ts +69 -0
  278. package/src/runtime/helpers/getResizeLimit.ts +60 -0
  279. package/src/runtime/helpers/getShapeSquareCss.ts +28 -0
  280. package/src/runtime/helpers/getSideTouching.ts +9 -0
  281. package/src/runtime/helpers/getVisualEdgeCss.ts +53 -0
  282. package/src/runtime/helpers/getVisualEdges.ts +155 -0
  283. package/src/runtime/helpers/getVisualEdgesCss.ts +13 -0
  284. package/src/runtime/helpers/getWinAndFrameById.ts +28 -0
  285. package/src/runtime/helpers/getWinByFrameUuid.ts +19 -0
  286. package/src/runtime/helpers/getWinById.ts +12 -0
  287. package/src/runtime/helpers/getWindowConstant.ts +21 -0
  288. package/src/runtime/helpers/inRange.ts +5 -0
  289. package/src/runtime/helpers/index.ts +64 -0
  290. package/src/runtime/helpers/isEdgeEqual.ts +14 -0
  291. package/src/runtime/helpers/isEdgeParallel.ts +10 -0
  292. package/src/runtime/helpers/isPointEqual.ts +5 -0
  293. package/src/runtime/helpers/isSizeAboveMin.ts +8 -0
  294. package/src/runtime/helpers/isSizeEqual.ts +5 -0
  295. package/src/runtime/helpers/isWindowEdge.ts +11 -0
  296. package/src/runtime/helpers/isWindowEdgePoint.ts +8 -0
  297. package/src/runtime/helpers/moveEdge.ts +21 -0
  298. package/src/runtime/helpers/numberToScaledPercent.ts +19 -0
  299. package/src/runtime/helpers/numberToScaledSize.ts +28 -0
  300. package/src/runtime/helpers/oppositeSide.ts +45 -0
  301. package/src/runtime/helpers/resizeByEdge.ts +45 -0
  302. package/src/runtime/helpers/sideToDirection.ts +15 -0
  303. package/src/runtime/helpers/sideToOrientation.ts +12 -0
  304. package/src/runtime/helpers/splitEdge.ts +23 -0
  305. package/src/runtime/helpers/toCoord.ts +13 -0
  306. package/src/runtime/helpers/toId.ts +9 -0
  307. package/src/runtime/helpers/toWindowCoord.ts +23 -0
  308. package/src/runtime/helpers/unionEdges.ts +11 -0
  309. package/src/runtime/helpers/updateWindowSizeWithEvent.ts +10 -0
  310. package/src/runtime/index.ts +5 -0
  311. package/src/runtime/layout/closeFrame.ts +33 -0
  312. package/src/runtime/layout/closeFrames.ts +14 -0
  313. package/src/runtime/layout/createSplitDecoEdge.ts +34 -0
  314. package/src/runtime/layout/createSplitDecoFromDrag.ts +24 -0
  315. package/src/runtime/layout/debugFrame.ts +6 -0
  316. package/src/runtime/layout/findFramesTouchingEdge.ts +92 -0
  317. package/src/runtime/layout/findSafeSplitEdge.ts +39 -0
  318. package/src/runtime/layout/findVisualEdge.ts +11 -0
  319. package/src/runtime/layout/frameCreate.ts +23 -0
  320. package/src/runtime/layout/frameSplit.ts +31 -0
  321. package/src/runtime/layout/getCloseFrameInfo.ts +193 -0
  322. package/src/runtime/layout/getFrameSplitInfo.ts +65 -0
  323. package/src/runtime/layout/getFrameTo.ts +65 -0
  324. package/src/runtime/layout/index.ts +24 -0
  325. package/src/runtime/layout/isPointInFrame.ts +7 -0
  326. package/src/runtime/layout/layoutAddWindow.ts +6 -0
  327. package/src/runtime/layout/layoutCreate.ts +12 -0
  328. package/src/runtime/layout/layoutRemoveWindow.ts +7 -0
  329. package/src/runtime/layout/resizeFrame.ts +106 -0
  330. package/src/runtime/layout/windowAddFrame.ts +10 -0
  331. package/src/runtime/layout/windowCreate.ts +18 -0
  332. package/src/runtime/layout/windowRemoveFrame.ts +7 -0
  333. package/src/runtime/layout/windowSetActiveFrame.ts +7 -0
  334. package/src/runtime/settings.ts +63 -0
  335. package/src/runtime/types/index.ts +293 -0
  336. package/src/runtime/utils/KnownError.ts +24 -0
package/README.md ADDED
@@ -0,0 +1,474 @@
1
+ [![Docs](https://github.com/witchcraftjs/layout/workflows/Docs/badge.svg)](https://github.com/witchcraftjs/layout/actions/workflows/docs.yml)
2
+ [![Release](https://github.com/witchcraftjs/layout/actions/workflows/release.yml/badge.svg)](https://github.com/witchcraftjs/layout/actions/workflows/release.yml)
3
+ [![NPM Version (with latest tag)](https://img.shields.io/npm/v/%40alanscodelog%2FREPONAME/latest)](https://www.npmjs.com/package/@witchcraft/layout/v/latest)
4
+ # [Docs](https://witchcraftjs.github.io/layout)
5
+ # [Demo](https://witchcraftjs.github.io/layout/demo)
6
+
7
+ # @witchcraft/layout
8
+
9
+ A headless layout manager for managing frames in an app.
10
+
11
+ While it's headless, it does provide ready made nuxt/vue components, but it's pretty easy to re-create these if you need them.
12
+
13
+ The structure of the library might seem a bit odd. It's not written with classes at all, but uses plain objects and many small utility functions to manipulate them. This makes the objects easily de/serializable and extendable. Basic zod types are included for validating them.
14
+
15
+ # Usage
16
+
17
+ ## Base Types
18
+
19
+ While some base types are provided, it's required you define what's inside a frame.
20
+
21
+ This can be done using types:
22
+ ```ts [global.d.ts]
23
+ // you don't need to extend from LayoutFrame, it's done automatically
24
+ type ContentA = {
25
+ type: "contentA"
26
+ content: {
27
+ id?: string
28
+ }
29
+ }
30
+ type ContentB = {
31
+ type: "contentB"
32
+ content: {
33
+ someOtherKey?: string
34
+ }
35
+ }
36
+ declare module "@witchcraft/layout" {
37
+ interface Register {
38
+ ExtendedLayoutFrame: ContentA | ContentB
39
+ }
40
+ }
41
+ export {}
42
+
43
+ ```
44
+
45
+ Or if using zod, you can do something like this. Note that you will need to create/extend `zLayoutWindow/Frame` or use `zLayoutWindow/FramePassthrough` to allow for extra properties. All zod types have been made `strict` where possible as it's easy to accidentally use the wrong type and loose properties silently otherwise.
46
+
47
+ ```ts
48
+ import { zLayoutFramePassthrough, layoutCreate } from "@witchcraft/layout"
49
+ import { z } from "zod"
50
+
51
+ // we remove the id to set the discriminated union, then add it back,
52
+ // otherwise this doesn't work
53
+ export const zAppFrame = z.discriminatedUnion("type", [
54
+ zLayoutFramePassthrough.extend({
55
+ type: z.literal("contentA"),
56
+ content: z.object({
57
+ id: z.optional(z.uuid()),
58
+ }),
59
+ }),
60
+ zLayoutFramePassthrough.extend({
61
+ type: z.literal("contentB"),
62
+ content: z.object({
63
+ someOtherKey: z.optional(z.uuid()),
64
+ }),
65
+ }),
66
+ ]).and(z.object({
67
+ id: z.uuid(),
68
+ }))
69
+
70
+ declare module "@witchcraft/layout" {
71
+ interface Register {
72
+ // Register the type
73
+ ExtendedLayoutFrame: z.infer<typeof zAppFrame>
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## Basics
79
+
80
+ A layout is very simple, and looks like this:
81
+ ```ts
82
+ {
83
+ activeWindow: string,
84
+ windows: {
85
+ [id: string]: {
86
+ activeFrame: string,
87
+ pxWidth: number,
88
+ pxHeight: number,
89
+ pxX: number,
90
+ pxY: number,
91
+ frames: {
92
+ [id: string]: {
93
+ id: string,
94
+ x: number,
95
+ y: number,
96
+ width: number,
97
+ height: number,
98
+ }
99
+ }
100
+ }
101
+ }
102
+ }
103
+ ```
104
+ NOTE: While the "container" for frames is called a window, it does not refer to the actual window, but the element holding the frames (which could only take up a part of the real window) and it's size/pos are in pixels as opposed to the frames which use percentages.
105
+
106
+ Frame positions are in *scaled* percentage ints. That is, instead of 100%, the value is `100 * 10^SCALE`. `SCALE` is 3 by default, so 100% is 100000.
107
+
108
+ This is done like this to make it easy to keep the dimensions rounded to x decimal points (in this case 3, `100%` => `100000` => `100.000%`). You could not use any decimal points but movements will be choppy.
109
+
110
+ `SCALE` is a global setting. See configuration below.
111
+
112
+ ## Configuration
113
+
114
+ There are a few variables that need to be used nearly everywhere such as `SCALE` and `SNAP_PERCENT_{X/Y}`.
115
+
116
+ While all function that need them, can also be called with params to override them, it's much easier to just manage them globally.
117
+
118
+ They are exported from `/settings.js` and stored in a variable called `globalOptions` which you can modify, but helpers are provided for getting/setting the information we actually want to extract using these variables, `maxInt`, `margin`, `snapPoint`.
119
+
120
+ ```ts
121
+ import {
122
+ globalOptions,
123
+ getMaxInt,
124
+ // this is called snapPoint because it's type looks like a point
125
+ // but it's more like it describes snap steps / distance in x/y
126
+ getSnapPoint,
127
+ setScale,
128
+ setSnapAmount
129
+ } from "@witchcraft-layout/settings.js"
130
+
131
+ // the function checks the max number is safe to use (using `isSafeInteger`)
132
+ // 3 decimal points of precision
133
+ setScale(3)
134
+ // snap to 1%
135
+ setSnapPercentage(1)
136
+ // snap x/y differently
137
+ setSnapPercentage({ x: 1, y: 2 })
138
+ setMarginPercentage(1)
139
+
140
+ // like doing const maxInt = globalOptions.maxInt
141
+ const maxInt = getMaxInt() // 100000
142
+ const snapAmountPoint = getSnapPoint() // { x: 1000, y: 1000 }
143
+ const marginSize = getMarginSize() // { width: 1000, height: 1000 }
144
+ ```
145
+ **NOTE: If you are saving layouts, if you change the snap or the margins to a bigger value, old layouts will become "invalid".** The should still load and you should be able to close frames, but it's not guaranteed they'll function correctly.
146
+
147
+ There are utilities for converting between non-scaled and scaled values if you need to:
148
+
149
+ ```ts
150
+ import {
151
+ numberToScaledSize,
152
+ numverToScaledPercent
153
+ } from "@witchcraft-layout/helpers/numberToScaledSize.js"
154
+
155
+ /* -----------
156
+ * | * |
157
+ * -----------
158
+ * | ^100px
159
+ * ^ 50px
160
+ * // returns 50 / 100 * scale or 50000 (50%)
161
+ */
162
+
163
+ const scaledPercent = numberToScaledPercent(someCoord, boundingBoxMax, scale) // scale is optional and will use the global scale
164
+ ```
165
+
166
+ ## Creating a Layout
167
+
168
+ Using vue as an example, in some file, preferably some sort of store like pinia, you can do something like this:
169
+ ```ts
170
+ import {reactive} from "vue"
171
+
172
+ // this does not have any windows/frames
173
+ // you will need to add them if you want them to exist on init
174
+ export const layout = ref(layoutCreate())
175
+ ```
176
+
177
+ Then in the page with the layout, initialize it and add a component to handle the rendering. One is included for vue, but it's pretty simple.
178
+
179
+ It uses a flat structure insides like so, so edges are always on top of frames, and decorations (drag/drop) are always on top of edges:
180
+ ```
181
+ - LayoutWindow
182
+ - LayoutFrame
183
+ - [Slot] (`frame-${frame.id}`)
184
+ - LayoutEdges (Edge type)
185
+ - LayoutDecos
186
+ ```
187
+
188
+ Edges and Decos are very simple and there are various utilies like `getVisualEdgesCss` and `getShapeSquareCss` to create the css needed to display them. They can both be handled as squares making it easy to reuse a single component to render them.
189
+
190
+ This has the benefit for edges, that the grabable area can be easily adjusted and bigger than the displayed edge.
191
+
192
+ ## Dragging
193
+
194
+ Then you will need to add dragging. This is not implemented by default (except for vue) as the state and rendering of a layout being dragged like this is almost always tightly coupled with whatever framework you're using and how you've structured your app. What I've figured out how to separate such as the `DragDirectionStore` and the drag action handlers is in `/drag`.
195
+
196
+ The default vue component implements some complex, optimized behavior (see the `useFrames` composable) if you want to see an example.
197
+
198
+ But basic dragging can be added as follows:
199
+
200
+ Add a `pointerdown` handler to all the edges.
201
+
202
+ You can then use `toWindowCoord` to translate the event coordinates into a point.
203
+
204
+ Before using it, you should be sure the window's coordinates are updated as this requires knowing the x/y px offset and the window dimensions.
205
+
206
+ ```ts
207
+ const point = toWindowCoord(win, e, snapPoint) // snapPoint is optional, it uses the global settings
208
+ ```
209
+
210
+ One drag starts, I suggest making a copy of the original positions in case you need to cancel the drag. This can be further optimized by only cloning and modifying the touching frames and overlaying them over the unmoved edges to render them. See [Overlayed Frames Technique](#overlayed-frames-technique) below.
211
+
212
+ You can use the `DragDirectionStore `to help keep track of which direction the user is dragging.
213
+
214
+ Minus framework specific details, the drag handlers might look something like this:
215
+ ```ts
216
+ // i suggest against a barrel import if not using all features, but this is for demo purposes
217
+ import {
218
+ DragDirectionStore,
219
+ getEdgeDirection,
220
+ moveEdge,
221
+ cloneFrame,
222
+ getVisualEdges,
223
+ toWindowCoord
224
+ findFramesTouchingEdge
225
+ type Point, type Edge, type LayoutFrame, type LayoutWindow
226
+ } from "@witchcraft-layout"
227
+
228
+ // const frames = getFramesFromYourStore()
229
+
230
+ // can be reused
231
+ const dragDirStore = new DragDirectionStore()
232
+
233
+ let dragPoint: Point | undefined
234
+ let draggingEdge: Edge | undefined
235
+ let isDragging = false
236
+ let clonedFrames: Record<string, LayoutFrame> = {}
237
+ let touchingFrames: Record<string, LayoutFrame> = {}
238
+
239
+ // this is what you can render by transforming it into css using getVisualEdgesCss
240
+ let visualEdges: Edge[] = []
241
+
242
+ // updates the edges, it doesn't have to be done with every event
243
+ // if the cursor hasn't moved. The dragDirStore can tell you if it did.
244
+ function forceRecalculateEdges() {
245
+ visualEdges = getVisualEdges(Object.values(frames.value), false)
246
+ }
247
+
248
+ // just makes it easier to remove the temporary window listeners
249
+ let controller: AbortController
250
+
251
+ // assuming something like this for each edge
252
+ // edgeEl.addEventListener("pointerdown", (e) => dragStartHandler(e, edge))
253
+ // you could even pass the point here already, and have handlers that look like ({edge, point}) => {...})
254
+
255
+ const dragStartHandler = function(e:PointerEvent, edge:Edge) {
256
+ controller = new AbortController()
257
+ window.addEventListener("pointermove", dragMoveHandler, { signal: controller.signal })
258
+ window.addEventListener("pointerup", dragEndHandler, { signal: controller.signal })
259
+ e.preventDefault()
260
+
261
+ const point = toWindowCoord(win, e)
262
+
263
+ dragPoint = point
264
+ dragDirStore.setOrientation(getEdgeDirection(edge))
265
+ dragDirStore.update(point, dragDirection)
266
+
267
+ draggingEdge = edge
268
+ isDragging = true
269
+ touchingFrames = findFramesTouchingEdge(edge, Object.values(win.frames)) ?? []
270
+ for (const frame of Object.values(win.frames)) {
271
+ clonedFrames[frame.id] = cloneFrame(frame)
272
+ }
273
+ }
274
+
275
+ const dragMoveHandler = function(e:PointerEvent, edge:Edge) {
276
+ e.preventDefault()
277
+ const point = toWindowCoord(win, e, snapPoint)
278
+
279
+ const didChange = dragDirStore.update(point, dragDirection)
280
+ dragPoint = point
281
+ if (!didChange) return
282
+
283
+ requestAnimationFrame(() => {
284
+ if (isDragging) {
285
+ moveEdge(win, touchingFrames, draggingEdge, point, 20)
286
+ }
287
+ forceRecalculateEdges()
288
+ })
289
+ }
290
+
291
+ const dragEndHandler = function(e:PointerEvent, edge:Edge) {
292
+ e.preventDefault()
293
+ controller.abort() // remove the temporary listeners
294
+ const point = toWindowCoord(win, e, snapPoint)
295
+
296
+ const didChange = dragDirStore.update(point, dragDirection)
297
+ dragPoint = point
298
+ isDragging = false
299
+ draggingEdge = undefined
300
+
301
+ touchingFrames = {}
302
+ dragDirStore.reset()
303
+ dragPoint = undefined
304
+ const apply = // determine if user wants to apply the drag
305
+ if (!apply) {
306
+ for (const frame of Object.values(clonedFrames)) {
307
+ win.frames[frame.id] = frame
308
+ }
309
+ }
310
+ }
311
+ ```
312
+ ### Drag Actions
313
+
314
+ A drag action describes when and how to handle a drag event, to, for example, split/close a frame when dragging with a certain modifier.
315
+
316
+ Customizable `SplitAction` and `CloseAction` actions are provided.
317
+
318
+ It requires implementing the some of the variables `useFrames` returns (i.e. using the overlayed frames technique) for your framework. You can see an example of how to use it in the `LayoutWindows.vue` component.
319
+
320
+ ### Overlayed Frames Technique
321
+
322
+ If you will be using drag actions or something like it, you'll probably want to handle the frame state by overlaying the changed state as needed. This makes two things possible:
323
+
324
+ - Actions can hide the new state. For example, when splitting, we don't want the edges to move from their original position.
325
+ - Actions can be easily cancelled.
326
+
327
+ To do this, at the start of the drag, you can clone all the touching frames (they will be the only ones that ever move) using `findFramesTouchingEdge` and `cloneFrames`.
328
+
329
+ ```ts
330
+ const touchingFrames = {}
331
+ for (const _ of touching) touchingFrames.value[_.frame.id] = cloneFrame(_.frame)
332
+ ```
333
+
334
+ You can then just get the overlayed frames like this where you need them.
335
+ ```ts
336
+ const overlayedFrames = {
337
+ ...win.value.frames,
338
+ ...touchingFrames.value
339
+ }
340
+ ```
341
+ If your framework has something like vue's computed you should use that and you can use a condition to "toggle" the overlay on/off.
342
+ ```ts
343
+ showDraggging
344
+ ? { ...win.value.frames, ...touchingFrames.value }
345
+ : win.value.frames
346
+ ```
347
+
348
+ You should then calculate all visualEdges based off of these frames.
349
+
350
+ ```ts
351
+ function recalculateEdges() {
352
+ visualEdges = getVisualEdges(Object.values(frames.value), {
353
+ // careful using this, you should handle this with a drag action
354
+ // don't let it actually change the edges or you'll end up with an
355
+ // invalid layout
356
+ includeWindowEdges: true,
357
+ })
358
+ }
359
+ ```
360
+
361
+ You can use `DragDirectionStore` in your events to check if anything actually changed.
362
+
363
+
364
+ If it did, you should move the edges in touchingFrames in your drag move handler and update your edges.
365
+
366
+ ```ts
367
+ requestAnimationFrame(() => {
368
+ moveEdge(touchingFramesArray.value, draggingEdge.value, point)
369
+ recalculateEdges()
370
+ })
371
+ ```
372
+
373
+
374
+ # Vue Only Extras
375
+
376
+ ## LayoutWindow
377
+
378
+ This is the main component that can render and handle dragging.
379
+
380
+ The component takes care of updating the size/pos of the window on mount.
381
+
382
+ It also includes basic styles for the edges and decos.
383
+
384
+ The order and styles classes look like this:
385
+
386
+ - `.frame` - frames come first so that edges can be rendered on top of them when needed.
387
+
388
+ Edges are stacked in this order.
389
+
390
+ - `.active-frame-edge` (active frame - rendered as single div)
391
+ - `.drag-edge` (thicker edge for attaching pointer events) + sibling .edge
392
+ - It looks like `.drag-edge .edge .drag-edge .edge` and so on.
393
+ - `.edge` is not shown by default, instead frames are padded to let the background show through since that way we can support having rounded corners inside the frames.
394
+ - This is you can target the edge style on the drag-edge's hover: `.drag-edge:hover+.edge`
395
+ - `.grabbed-edge` (the grabbed drag edge if any) - prefer this over drag-edge:hover for css that should remain visible when dragging to avoid flickering when the mouse moves slightly off the edge
396
+ - `.intersection` (intersections)
397
+
398
+ **ALL edges except `active-frame-edge` are rendered as individual divs, so set the background color instead of the border.**
399
+
400
+ This is done like this for several reasons:
401
+ - Edges can be shared by frames, only the active edges are guaranteed to equal some frame's edges. And we need to know the full edge that is being dragged to implement dragging.
402
+ - The css/logic is simpler, edges can be any width without affecting the layout. We just transform translate them to be exactly centered over their position and then just pad the frames the correct amount.
403
+
404
+ Decos:
405
+
406
+ - Close:
407
+ - `.deco-close-frame` (close frame preview)
408
+ - `.deco-close-force-frame` (close frame preview when force is on)
409
+ - Split:
410
+ - `.deco-split-new-frame` (new frame preview)
411
+ - `.deco-split-edge` (edge preview)
412
+
413
+ State classes (so you can do stuff like `.request-split .drag-edge`)
414
+ - `.dragging`
415
+ - `.request-split`
416
+ - `.request-close`
417
+
418
+ Several css variables are provided to help with sizing:
419
+ - `--layoutHandleWidth`
420
+ - `--layoutEdgeWidth`
421
+ - `--layoutSplitEdgeWidth`
422
+ - `--layoutIntersectionWidth`
423
+
424
+ ```vue
425
+ <template>
426
+
427
+ <LayoutWindow
428
+ v-if="win"
429
+ class="flex-1 w-full
430
+ // hide drag/grabbed edge when splitting (let only split edge show)
431
+ [&.request-split_.grabbed-edge]:hidden
432
+ [&.request-split_.drag-edge]:hidden
433
+ "
434
+ style="--layoutSplitEdgeWidth:2px;"
435
+ :win="win"
436
+ >
437
+ <template #[`frame-${f.id}`] v-for="f in frames" :key="f.id">
438
+ <ContentFrame
439
+ :frame="f"
440
+ :get-component="getComponent"
441
+ />
442
+ </template>
443
+ </LayoutWindow>
444
+ </template>
445
+
446
+ <script setup lang="ts">
447
+ const {
448
+ layout,
449
+ activeWindow: win,
450
+ activeFrame,
451
+ frames
452
+ } = storeToRefs(useLayoutStore())
453
+
454
+ function getComponent(type: string | undefined) {
455
+ if (type === "contentA") {
456
+ return yourContentAComponent
457
+ }
458
+ }
459
+
460
+ </script>
461
+ ```
462
+ ## Nuxt w/ Tailwind
463
+
464
+ The nuxt module creates a `witchcraft-layout.css` file with the proper source imports for the components folder. You just have to import it in your tailwind css file. Note that this requires `@witchcraft/ui` be installed and setup in a similar way also.
465
+
466
+ ```css [~/assets/css/tailwind.css]
467
+ @import "tailwindcss";
468
+ // or
469
+ @import "tailwindcss" source("path/to/src");
470
+ @import "../../../.nuxt/witchcraft-ui.css";
471
+ @import "../../../.nuxt/witchcraft-layout.css";
472
+ ```
473
+
474
+
@@ -0,0 +1,14 @@
1
+ import * as _nuxt_schema from '@nuxt/schema';
2
+ export * from '../dist/runtime/index.js';
3
+
4
+ declare module "@nuxt/schema" {
5
+ interface PublicRuntimeConfig {
6
+ }
7
+ }
8
+ interface ModuleOptions {
9
+ debug?: boolean;
10
+ }
11
+ declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
12
+
13
+ export { _default as default };
14
+ export type { ModuleOptions };
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@witchcraft/layout",
3
+ "configKey": "witchcraftLayout",
4
+ "version": "1.0.0",
5
+ "builder": {
6
+ "@nuxt/module-builder": "1.0.2",
7
+ "unbuild": "unknown"
8
+ }
9
+ }
@@ -0,0 +1,26 @@
1
+ import { defineNuxtModule, createResolver, addComponentsDir, addTemplate } from '@nuxt/kit';
2
+ export * from '../dist/runtime/index.js';
3
+
4
+ const module = defineNuxtModule({
5
+ meta: {
6
+ name: "@witchcraft/layout",
7
+ configKey: "witchcraftLayout"
8
+ },
9
+ defaults: {
10
+ debug: false
11
+ },
12
+ async setup(_options, nuxt) {
13
+ const { resolve } = createResolver(import.meta.url);
14
+ addComponentsDir({
15
+ path: resolve("runtime/components")
16
+ });
17
+ addTemplate({
18
+ filename: "witchcraft-layout.css",
19
+ write: true,
20
+ getContents: () => `@source "${resolve("runtime/components")}";`
21
+ });
22
+ nuxt.options.alias["#witchcraft-layout"] = resolve("runtime");
23
+ }
24
+ });
25
+
26
+ export { module as default };
File without changes
@@ -0,0 +1,54 @@
1
+ <template>
2
+ <!-- <div -->
3
+ <!-- v-bind="$attrs" -->
4
+ <!-- class="decos" -->
5
+ <!-- > -->
6
+ <template
7
+ v-for="(deco) of splitDecos"
8
+ :key="deco.id"
9
+ >
10
+ <LayoutShapeSquare
11
+ class="
12
+ deco-split-new-frame
13
+ bg-blue-500/50
14
+ "
15
+ :css="getShapeSquareCss(deco.shapes.newFrame, `var(--layoutEdgeWidth,2px)`)"
16
+ />
17
+ <LayoutShapeSquare
18
+ class="
19
+ deco-split-edge
20
+ bg-red-500
21
+ "
22
+ :css="getVisualEdgeCss(deco.shapes.edge, { padLongAxis: `var(--layoutEdgeWidth,2px)` })"
23
+ />
24
+ </template>
25
+ <template
26
+ v-for="deco of closeDecos"
27
+ :key="deco.id"
28
+ >
29
+ <LayoutShapeSquare
30
+ :class="`
31
+ ${deco.force ? 'deco-close-force-frame' : 'deco-close-frame'}
32
+ bg-red-500/50
33
+ `"
34
+ :css="getShapeSquareCss(frames[deco.id], `var(--layoutEdgeWidth,2px)`)"
35
+ />
36
+ </template>
37
+ <!-- </div> -->
38
+ </template>
39
+
40
+ <script setup>
41
+ import { twMerge } from "@witchcraft/ui/utils/twMerge";
42
+ import { computed, inject, ref, useAttrs } from "vue";
43
+ import LayoutShapeSquare from "./LayoutShapeSquare.vue";
44
+ import { dirToOrientation } from "../helpers/dirToOrientation.js";
45
+ import { getShapeSquareCss } from "../helpers/getShapeSquareCss";
46
+ import { getVisualEdgeCss } from "../helpers/getVisualEdgeCss";
47
+ import {} from "../types/index.js";
48
+ const $attrs = useAttrs();
49
+ const props = defineProps({
50
+ frames: { type: Object, required: true },
51
+ splitDecos: { type: Array, required: true },
52
+ closeDecos: { type: Array, required: true }
53
+ });
54
+ </script>
File without changes
File without changes