@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
@@ -0,0 +1,158 @@
1
+ import type { DragState, IDragAction } from "./types.js"
2
+
3
+ import { dirToOrientation } from "../helpers/dirToOrientation.js"
4
+ import { getEdgeOrientation } from "../helpers/getEdgeOrientation.js"
5
+ import { oppositeSide } from "../helpers/oppositeSide.js"
6
+ import { closeFrames } from "../layout/closeFrames.js"
7
+ import { findFramesTouchingEdge } from "../layout/findFramesTouchingEdge.js"
8
+ import { getCloseFrameInfo } from "../layout/getCloseFrameInfo.js"
9
+ import type { CloseDeco } from "../types/index.js"
10
+ import type { KnownError } from "../utils/KnownError.js"
11
+
12
+ export type CloseInfo = Exclude<ReturnType<typeof getCloseFrameInfo>, KnownError>
13
+
14
+ export class CloseAction implements IDragAction {
15
+ name = "close" as const
16
+
17
+ state: {
18
+ allowed: true
19
+ force: boolean
20
+ res: CloseInfo
21
+ cacheKey: string | undefined
22
+ } | {
23
+ allowed: false
24
+ force: boolean
25
+ res: CloseInfo | undefined
26
+ cacheKey: string | undefined
27
+ } = {} as any // this is initialized by this.reset()
28
+
29
+ handleEvent: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean | "force"
30
+ updateCloseDecos: (decos: CloseDeco[]) => void
31
+ hooks: {
32
+ onStart?: (active: boolean) => void
33
+ onCancel?: () => void
34
+ onError?: (e: KnownError) => void
35
+ }
36
+
37
+ constructor(
38
+ handleEvent: CloseAction["handleEvent"],
39
+ updateCloseDecos: CloseAction["updateCloseDecos"],
40
+ hooks: CloseAction["hooks"] = {}
41
+ ) {
42
+ this.handleEvent = handleEvent
43
+ this.updateCloseDecos = updateCloseDecos
44
+ this.hooks = hooks
45
+ this.reset()
46
+ }
47
+
48
+ reset(): void {
49
+ this.state = {
50
+ allowed: false,
51
+ force: false,
52
+ res: undefined,
53
+ cacheKey: undefined
54
+ }
55
+ this.updateCloseDecos([])
56
+ }
57
+
58
+ updateDecos(state: DragState): void {
59
+ const {
60
+ isDragging
61
+ } = state
62
+ if (isDragging && this.state.allowed && this.state.res) {
63
+ const { force } = this.state
64
+ const decos = this.state.res.deletedFrames.map(_ => ({ id: _.id, type: "close" as const, force }))
65
+ this.updateCloseDecos(decos)
66
+ } else {
67
+ this.updateCloseDecos([])
68
+ }
69
+ }
70
+
71
+ canHandleRequest(e: PointerEvent | KeyboardEvent, state: DragState): boolean {
72
+ const { draggingEdges } = state
73
+ if (draggingEdges.length !== 1) return false
74
+ const res = this.handleEvent(e, state)
75
+ if (res === "force") {
76
+ this.state.force = true
77
+ } else {
78
+ this.state.force = false
79
+ }
80
+ if (res) {
81
+ this.hooks.onStart?.(true)
82
+ return true
83
+ }
84
+ this.reset()
85
+ return false
86
+ }
87
+
88
+ onDragChange(
89
+ _type: "start" | "end" | "move",
90
+ _e: PointerEvent | undefined,
91
+ state: DragState
92
+ ): boolean {
93
+ const {
94
+ touchingFramesArrays,
95
+ dragDirections,
96
+ isDragging,
97
+ draggingEdges,
98
+ visualEdges,
99
+ frames,
100
+ isDraggingFromWindowEdge
101
+ } = state
102
+ const oppositeOrientation = oppositeSide(getEdgeOrientation(draggingEdges[0]))
103
+ let ok = false
104
+ if (isDragging && draggingEdges.length === 1) {
105
+ const res = findFramesTouchingEdge(
106
+ draggingEdges[0],
107
+ touchingFramesArrays[0],
108
+ {
109
+ // referencePoint: dragPoint.value, // if force pick smallest frame?
110
+ searchDirections: [dragDirections[oppositeOrientation]!]
111
+ }
112
+ )
113
+ if (res.length > 0) {
114
+ const orientation = dirToOrientation(dragDirections[oppositeOrientation]!)
115
+ const sizeKey = orientation === "horizontal" ? "width" : "height"
116
+ const smallestFrameSize = Math.min(...res.map(_ => _.frame[sizeKey]))
117
+ const frame = res.find(_ => _.frame[sizeKey] === smallestFrameSize)!.frame!
118
+ const cacheKey = `${frame.id}-${dragDirections[oppositeOrientation]!}`
119
+ if (this.state.allowed) {
120
+ if (this.state.cacheKey === cacheKey) {
121
+ this.updateDecos(state)
122
+ return true
123
+ }
124
+ }
125
+ const closeInfo = getCloseFrameInfo(Object.values(frames), visualEdges, frame, dragDirections[oppositeOrientation]!, "dir", this.state.force)
126
+ if (!(closeInfo instanceof Error)) {
127
+ this.state.allowed = true
128
+ this.state.res = closeInfo
129
+ this.state.cacheKey = cacheKey
130
+ ok = true
131
+ } else {
132
+ this.hooks.onError?.(closeInfo)
133
+ }
134
+ }
135
+ }
136
+ this.updateDecos(state)
137
+ if (!ok) {
138
+ this.state.allowed = false
139
+ }
140
+ return !isDraggingFromWindowEdge
141
+ }
142
+
143
+ onDragApply(state: DragState): boolean {
144
+ if (this.state.res) {
145
+ const { deletedFrames, modifiedFrames } = this.state.res
146
+ const win = state.win
147
+ closeFrames(win, deletedFrames, modifiedFrames)
148
+ this.reset()
149
+ return true
150
+ }
151
+ return false
152
+ }
153
+
154
+ cancel(): void {
155
+ this.reset()
156
+ this.hooks.onCancel?.()
157
+ }
158
+ }
@@ -0,0 +1,146 @@
1
+ import type { RecordFromArray } from "@alanscodelog/utils"
2
+
3
+ import type { DragChangeHandler, DragState, IDragAction } from "./types.js"
4
+
5
+ /**
6
+ * Handles the lifecycle of a drag actions {@link IDragAction} and provides additional hooks.
7
+ *
8
+ * The first action instance that can handle the request is passed control of the event handlers until the request changes.
9
+ */
10
+ export class DragActionHandler<
11
+ TRawDragActions extends IDragAction[],
12
+ TDragActions extends RecordFromArray<TRawDragActions, "name"> = RecordFromArray<TRawDragActions, "name">
13
+ > {
14
+ activeAction?: keyof TDragActions
15
+
16
+ actions: TDragActions
17
+
18
+ eventCanceller: (() => void) | undefined = undefined
19
+
20
+ boundCancel: () => void
21
+
22
+ defaultOnDragChange: DragChangeHandler
23
+ hooks: {
24
+ /** Called while dragging during dragChange events. You can use this to update the dragging edges. */
25
+ onRecalculate?: () => void
26
+ /**
27
+ * Called before searching for a matching action. Useful for re-initializing state.
28
+ *
29
+ * Is passed a `cancel` function if you want to cancel the current drag action.
30
+ */
31
+ onEvent?: (e: PointerEvent | KeyboardEvent | undefined, cancel: () => void) => void
32
+ /** Called when the action requested changes. */
33
+ onRequestChange?: (type: keyof TDragActions | undefined) => void
34
+ /** Called when the drag action ends either because it was completed or cancelled. */
35
+ onEnd?: (context: { cancelled: boolean, applied: boolean }) => void
36
+ }
37
+
38
+ constructor(
39
+ /**
40
+ * Default onDragChange handler for when no action can handle the request.
41
+ *
42
+ * Should return true to allow the edges to be moved, or false to prevent it.
43
+ */
44
+ defaultOnDragChange: DragChangeHandler,
45
+ actions: TRawDragActions,
46
+ hooks: DragActionHandler<TRawDragActions, TDragActions>["hooks"] = {}
47
+ ) {
48
+ this.defaultOnDragChange = defaultOnDragChange
49
+ this.hooks = hooks
50
+ this.actions = {} as any
51
+ for (const action of actions) {
52
+ (this.actions as any)[action.name] = action
53
+ }
54
+ this.boundCancel = this.cancel.bind(this)
55
+ }
56
+
57
+ eventHandler(
58
+ e: KeyboardEvent | PointerEvent,
59
+ state: DragState,
60
+ forceRecalculateEdges: () => void
61
+ ) {
62
+ if (state.isDragging) {
63
+ e.preventDefault()
64
+ }
65
+ let cancelled = false
66
+ this.hooks.onEvent?.(e, () => {
67
+ cancelled = true
68
+ this.cancel()
69
+ })
70
+ if (cancelled) return
71
+
72
+ let found = false
73
+ const oldActiveAction = this.activeAction
74
+ for (const action of Object.values<TRawDragActions[number]>(this.actions)) {
75
+ if (action.canHandleRequest(e, state, forceRecalculateEdges)) {
76
+ // if (this.activeAction !== action.name) {
77
+ // }
78
+ found = true
79
+ this.activeAction = action.name
80
+ break
81
+ }
82
+ }
83
+
84
+ if (!found) {
85
+ this.activeAction = undefined
86
+ }
87
+
88
+ if (oldActiveAction !== this.activeAction) {
89
+ if (oldActiveAction) {
90
+ this.actions[oldActiveAction]!.cancel()
91
+ }
92
+ this.hooks.onRequestChange?.(this.activeAction)
93
+ }
94
+
95
+ if (state.isDragging) {
96
+ forceRecalculateEdges()
97
+ this.hooks.onRecalculate?.()
98
+ }
99
+ return undefined
100
+ }
101
+
102
+ onDragChange<T extends "start" | "move" | "end">(
103
+ type: T,
104
+ e: T extends "end" ? PointerEvent | undefined : PointerEvent,
105
+ state: DragState,
106
+ forceRecalculateEdges: () => void,
107
+ cancel?: () => void
108
+ ): boolean | undefined {
109
+ if (type === "start") {
110
+ this.eventCanceller = cancel
111
+ state.isDragging = true
112
+ this.eventHandler(e!, state, forceRecalculateEdges)
113
+ }
114
+ if (type === "end") {
115
+ state.isDragging = false
116
+ this.activeAction = undefined
117
+ }
118
+
119
+ if (this.activeAction) {
120
+ return this.actions[this.activeAction]!.onDragChange(type, e, state, forceRecalculateEdges, this.boundCancel)
121
+ }
122
+ return this.defaultOnDragChange(type, e, state, forceRecalculateEdges, this.boundCancel)
123
+ }
124
+
125
+ onDragApply(
126
+ state: DragState,
127
+ forceRecalculateEdges: () => void
128
+ ): boolean {
129
+ if (this.activeAction) {
130
+ const res = this.actions[this.activeAction]!.onDragApply(state, forceRecalculateEdges)
131
+ this.hooks.onEnd?.({ cancelled: false, applied: res })
132
+ return false
133
+ }
134
+ this.hooks.onEnd?.({ cancelled: false, applied: false })
135
+ return true
136
+ }
137
+
138
+ cancel(): void {
139
+ if (this.activeAction) {
140
+ this.actions[this.activeAction].cancel()
141
+ }
142
+ this.activeAction = undefined
143
+ this.eventCanceller?.()
144
+ this.hooks.onEnd?.({ cancelled: true, applied: false })
145
+ }
146
+ }
@@ -0,0 +1,63 @@
1
+ import type { Direction, Orientation, Point } from "../types/index.js"
2
+
3
+ export class DragDirectionStore {
4
+ hooks: {
5
+ onUpdate: (directions: Record<Orientation, Direction | undefined>) => void
6
+ }
7
+
8
+ constructor(
9
+ hooks: DragDirectionStore["hooks"]
10
+ ) {
11
+ this.hooks = hooks
12
+ }
13
+
14
+ lastPoint: Point | undefined
15
+
16
+ dragDirection: Record<Orientation, Direction | undefined> = {} as any
17
+
18
+ lesser: { x: Direction, y: Direction } = {
19
+ x: "left",
20
+ y: "up"
21
+ }
22
+
23
+ greater: { x: Direction, y: Direction } = {
24
+ x: "right",
25
+ y: "down"
26
+ }
27
+
28
+ reset(): void {
29
+ this.lastPoint = undefined
30
+ this.dragDirection = {} as any
31
+ }
32
+
33
+ update(point: Point): boolean {
34
+ // eslint-disable-next-line @typescript-eslint/naming-convention
35
+ const newXDirection = this.getDragDirection("x", point)
36
+ // eslint-disable-next-line @typescript-eslint/naming-convention
37
+ const newYDirection = this.getDragDirection("y", point)
38
+ let changed = false
39
+ if (newXDirection) {
40
+ this.dragDirection.horizontal = newXDirection
41
+ }
42
+ if (newYDirection) {
43
+ this.dragDirection.vertical = newYDirection
44
+ }
45
+
46
+ if (this.lastPoint?.x !== point.x || this.lastPoint?.y !== point.y) {
47
+ this.lastPoint = point
48
+ changed = true
49
+ }
50
+
51
+ if (!changed) return false
52
+ this.hooks.onUpdate(this.dragDirection)
53
+ return true
54
+ }
55
+
56
+ getDragDirection(coord: "x" | "y", point: Point): Direction | false {
57
+ if (!this.lastPoint) return false
58
+ const diff = point[coord] - this.lastPoint![coord]
59
+ if (diff > 0) return this.greater[coord]
60
+ if (diff < 0) return this.lesser[coord]
61
+ return false
62
+ }
63
+ }
@@ -0,0 +1,147 @@
1
+ import type { DragState, IDragAction } from "./types.js"
2
+
3
+ import { getEdgeOrientation } from "../helpers/getEdgeOrientation.js"
4
+ import { oppositeSide } from "../helpers/oppositeSide.js"
5
+ import { createSplitDecoFromDrag } from "../layout/createSplitDecoFromDrag.js"
6
+ import { frameSplit } from "../layout/frameSplit.js"
7
+ import { getFrameSplitInfo } from "../layout/getFrameSplitInfo.js"
8
+ import type { SplitDeco } from "../types/index.js"
9
+ import type { KnownError } from "../utils/KnownError.js"
10
+
11
+ export type SplitInfo = Exclude<ReturnType<typeof getFrameSplitInfo>, KnownError>
12
+ export class SplitAction implements IDragAction {
13
+ name = "split" as const
14
+
15
+ state: {
16
+ allowed: false
17
+ res: SplitInfo | undefined
18
+ cacheKey: string | undefined
19
+ } | {
20
+ allowed: true
21
+ res: SplitInfo
22
+ cacheKey: string | undefined
23
+ } = {} as any // this is initialized by `this.reset()`
24
+
25
+ handleEvent: (e: PointerEvent | KeyboardEvent, state: DragState) => boolean
26
+ updateSplitDecos: (decos: SplitDeco[]) => void
27
+ hooks: {
28
+ onStart?: () => void
29
+ onCancel?: () => void
30
+ onError?: (e: KnownError) => void
31
+ }
32
+
33
+ constructor(
34
+ handleEvent: SplitAction["handleEvent"],
35
+ updateSplitDecos: SplitAction["updateSplitDecos"],
36
+ hooks: SplitAction["hooks"] = {}
37
+ ) {
38
+ this.handleEvent = handleEvent
39
+ this.updateSplitDecos = updateSplitDecos
40
+ this.hooks = hooks
41
+ this.reset()
42
+ }
43
+
44
+ reset(): void {
45
+ this.state = {
46
+ allowed: false,
47
+ res: undefined,
48
+ cacheKey: undefined
49
+ }
50
+ this.updateSplitDecos([])
51
+ }
52
+
53
+ updateDecos(state: DragState): void {
54
+ const {
55
+ win,
56
+ isDragging,
57
+ dragHoveredFrame,
58
+ dragDirections,
59
+ draggingEdges,
60
+ dragPoint
61
+ } = state
62
+ if (isDragging && this.state.allowed && dragHoveredFrame && draggingEdges.length === 1) {
63
+ const oppositeOrientation = oppositeSide(getEdgeOrientation(draggingEdges[0]))
64
+ const deco = createSplitDecoFromDrag(
65
+ win.frames,
66
+ dragHoveredFrame,
67
+ dragDirections[oppositeOrientation]!,
68
+ dragPoint!
69
+ )
70
+ this.updateSplitDecos([deco])
71
+ } else {
72
+ this.updateSplitDecos([])
73
+ }
74
+ }
75
+
76
+ canHandleRequest(e: PointerEvent | KeyboardEvent, state: DragState): boolean {
77
+ const { draggingEdges } = state
78
+ if (draggingEdges.length !== 1) return false
79
+ if (this.handleEvent(e, state)) {
80
+ this.hooks.onStart?.()
81
+ return true
82
+ }
83
+ this.reset()
84
+ return false
85
+ }
86
+
87
+ calculateSplitRequest(state: DragState): boolean {
88
+ const {
89
+ dragHoveredFrame,
90
+ dragDirections,
91
+ draggingEdges,
92
+ dragPoint
93
+ } = state
94
+ const oppositeOrientation = oppositeSide(getEdgeOrientation(draggingEdges[0]))
95
+ const canSplit = getFrameSplitInfo(
96
+ dragHoveredFrame!,
97
+ dragDirections[oppositeOrientation]!,
98
+ dragPoint!
99
+ )
100
+ if (!(canSplit instanceof Error)) {
101
+ this.state.allowed = true
102
+ this.state.res = canSplit
103
+ this.state.cacheKey = dragHoveredFrame?.id
104
+ return true
105
+ } else {
106
+ this.hooks.onError?.(canSplit)
107
+ return false
108
+ }
109
+ }
110
+
111
+ onDragChange(
112
+ _type: "start" | "end" | "move",
113
+ _e: PointerEvent | undefined,
114
+ state: DragState
115
+ ): true {
116
+ const { dragHoveredFrame } = state
117
+ let ok = false
118
+ if (dragHoveredFrame) {
119
+ if (this.state.cacheKey === dragHoveredFrame.id) {
120
+ this.updateDecos(state)
121
+ return true
122
+ }
123
+ ok = this.calculateSplitRequest(state)
124
+ }
125
+ this.updateDecos(state)
126
+ if (!ok) {
127
+ this.state.allowed = false
128
+ }
129
+ return true
130
+ }
131
+
132
+ onDragApply(state: DragState): boolean {
133
+ if (this.state.res) {
134
+ // this only caches once per frame hovered over
135
+ // so the drag position is outdated
136
+ this.calculateSplitRequest(state)
137
+ frameSplit(state.win, this.state.res!)
138
+ }
139
+ this.reset()
140
+ return true
141
+ }
142
+
143
+ cancel(): void {
144
+ this.reset()
145
+ this.hooks.onCancel?.()
146
+ }
147
+ }
@@ -0,0 +1,107 @@
1
+ import type { Direction, Edge, IntersectionEntry, LayoutFrame, LayoutWindow, Orientation, Point } from "../types/index.js"
2
+
3
+ export type DragState = {
4
+ /** The current directions in the corresponding orientations that the user is dragging in. */
5
+ dragDirections: Record<Orientation, Direction | undefined>
6
+ /** The curren point (in scaled window coordinates) the user is dragging at. */
7
+ dragPoint?: Point
8
+ /** Whether the user is currently dragging. Is true during all drag events. */
9
+ isDragging: boolean
10
+ /**
11
+ * The edges that are currently being dragged. There are multiple edges if they drag an intersection since what's actually happening is we're just dragging the closest horizontal and vertical edges.
12
+ */
13
+ draggingEdges: Edge[]
14
+ /**
15
+ * The intersection that is currently being dragged.
16
+ */
17
+ draggingIntersection?: IntersectionEntry
18
+ /** The "visual" edges that can be displayed for dragging. See {@link getVisualEdges} */
19
+ visualEdges: Edge[]
20
+ /**
21
+ * The frames touching the currently dragged edges. Each entry corresponds to the frames touching the corresponding dragging edge.
22
+ *
23
+ * So you can use the index in draggingEdges to get the corresponding frames.
24
+ */
25
+ touchingFrames: Record<string, LayoutFrame>[]
26
+ /**
27
+ * Same as touchingFrames, but with the frames in an array.
28
+ */
29
+ touchingFramesArrays: LayoutFrame[][]
30
+ /**
31
+ * All the frames, with/without the currently dragged frames depending on if `showDragging` is true.
32
+ */
33
+ frames: Record<string, LayoutFrame>
34
+ /**
35
+ * The frame that is currently being hovered over (according to whether `dragPoint` in in the frame or not).
36
+ */
37
+ dragHoveredFrame: LayoutFrame | undefined
38
+ /**
39
+ * A list of corner intersections. Frames can also be dragged by these.
40
+ */
41
+ intersections: IntersectionEntry[]
42
+ /**
43
+ * Whether the drag was initiated from a point along the window edge.
44
+ */
45
+ isDraggingFromWindowEdge: boolean
46
+ win: LayoutWindow
47
+ }
48
+
49
+ /**
50
+ * Note that the return type only affects the `move` event but is also typed as `boolean` for other events for ease of use.
51
+ */
52
+ export interface DragChangeHandler {
53
+ <T extends "start" | "move" | "end">(
54
+ type: T,
55
+ e: T extends "end" ? PointerEvent | undefined : PointerEvent,
56
+ state: DragState,
57
+ forceRecalculateEdges: () => void,
58
+ cancel: () => void
59
+ ): boolean | undefined
60
+ }
61
+
62
+ /**
63
+ * A drag action describes when and how to handle a drag event.
64
+ *
65
+ * For example, there are the default split/close actions that can be triggered in certain situations. This could be when holding down a modifier or key, or some other condition (e.g. the user is dragging a specific edge).
66
+ *
67
+ * Each action should handle it's configuration and saving/caching any state it needs. See {@link SplitAction} and {@link CloseAction} for examples.
68
+ */
69
+ // eslint-disable-next-line @typescript-eslint/naming-convention
70
+ export interface IDragAction {
71
+ /** A unique name for your action. */
72
+ name: string
73
+ /**
74
+ * Called when the drag coordinates change (during any event). Should return true to allow the edges to be moved, or false to prevent it.
75
+ *
76
+ * Can be used to save some context/info to later apply safely during onDragApply.
77
+ */
78
+
79
+ onDragChange: DragChangeHandler
80
+ /**
81
+ *
82
+ * Is called after `onDragChange("end")` with the same event. Might not be called if the request was cancelled.
83
+ *
84
+ * You should apply your action if possible and return whether it was applied.
85
+ *
86
+ * This is also a good place to reset your state.
87
+ */
88
+ onDragApply: (state: DragState, forceRecalculateEdges: () => void) => boolean
89
+ /**
90
+ * Should return true if it should handle the "request"/event (e.g. some modifier is being pressed => user is requesting x action).
91
+ *
92
+ * The user is not necessarily dragging at this point, though they might also change actions mid drag. So it does not necessarily mean the event is allowed.
93
+ *
94
+ * Here is where you should initiate your state. Don't allow the action by default unless it can always be allowed.
95
+ */
96
+ canHandleRequest(
97
+ e: KeyboardEvent | PointerEvent,
98
+ state: DragState,
99
+ forceRecalculateEdges: () => void
100
+ ): boolean
101
+ /**
102
+ * Called when a user cancels the drag action.
103
+ *
104
+ * You should reset your state here.
105
+ */
106
+ cancel(): void
107
+ }
@@ -0,0 +1,9 @@
1
+ import type { Intersections, Point } from "../types/index.js"
2
+
3
+ export function addPointsToIntersection(intersections: Intersections, points: Point[]): void {
4
+ for (const point of points) {
5
+ intersections[point.x] ??= {}
6
+ intersections[point.x][point.y] ??= 0
7
+ intersections[point.x][point.y]++
8
+ }
9
+ }
@@ -0,0 +1,11 @@
1
+ import { getEdgeOrientation } from "./getEdgeOrientation.js"
2
+
3
+ import type { Edge } from "../types/index.js"
4
+
5
+ export function assertEdgeSorted(edge: Edge): void {
6
+ const dir = getEdgeOrientation(edge)
7
+ if ((dir === "horizontal" && edge.startX > edge.endX)
8
+ || (dir === "vertical" && edge.startY > edge.endY)) {
9
+ throw new Error("Edge start/end is revered.")
10
+ }
11
+ }
@@ -0,0 +1,13 @@
1
+ import { LAYOUT_ERROR } from "../types/index.js"
2
+ import { KnownError } from "../utils/KnownError.js"
3
+
4
+ export function assertItemIn<
5
+ T extends Record<string, any>
6
+ >(entries: T, id: keyof T | string | undefined): asserts id is keyof T {
7
+ if (id === undefined || entries[id] === undefined) {
8
+ const message = id === undefined
9
+ ? `Id cannot be undefined.`
10
+ : `Could not find item by that id (${id as string | undefined}).`
11
+ throw new KnownError(LAYOUT_ERROR.INVALID_ID, message, { id: id as string | undefined })
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ import { LAYOUT_ERROR } from "../types/index.js"
2
+ import { KnownError } from "../utils/KnownError.js"
3
+
4
+ // don't try to be clever with type, we don't want it to narrow to never since we still want to be able to assign a new
5
+
6
+ export function assertItemNotIn(entries: Record<string, any>, id: string | undefined): void {
7
+ if (id !== undefined && entries[id] !== undefined) {
8
+ throw new KnownError(LAYOUT_ERROR.ID_ALREADY_EXISTS, `Item with id ${id as string} already exists`, { id })
9
+ }
10
+ }
@@ -0,0 +1,9 @@
1
+ import type { Layout } from "../types/index.js"
2
+ import { LAYOUT_ERROR } from "../types/index.js"
3
+ import { KnownError } from "../utils/KnownError.js"
4
+
5
+ export function assertLayoutHasActiveWindow(layout: Layout): asserts layout is Omit<Layout, "activeWindow"> & { activeWindow: NonNullable<Layout["activeWindow"]> } {
6
+ if (layout.activeWindow === undefined) {
7
+ throw new KnownError(LAYOUT_ERROR.NO_ACTIVE_WINDOW, "Layout has not active window.", {})
8
+ }
9
+ }
@@ -0,0 +1,16 @@
1
+ import { assertValidWinAndFrameIds } from "./assertValidWinAndFrameIds.js"
2
+
3
+ import type {
4
+ Layout,
5
+ LayoutFrame,
6
+ LayoutWindow
7
+ } from "../types/index.js"
8
+
9
+ export function assertValidWinAndFrame(
10
+ layout: Layout,
11
+ win?: LayoutWindow,
12
+ frame?: LayoutFrame
13
+ ): { win: LayoutWindow, frame: LayoutFrame } {
14
+ assertValidWinAndFrameIds(layout.windows, win?.id, frame?.id)
15
+ return { win: win!, frame: frame! }
16
+ }