@ahrowe/ui 0.34.0 → 0.36.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 (1172) hide show
  1. package/README.md +158 -68
  2. package/dist/cjs-types/common/accordion/accordion.d.ts +4 -0
  3. package/dist/cjs-types/common/accordion/accordion.types.d.ts +21 -0
  4. package/dist/cjs-types/common/accordion/index.d.ts +2 -0
  5. package/dist/cjs-types/common/actionButtons/actionButtons.d.ts +2 -0
  6. package/dist/cjs-types/common/actionButtons/actionButtons.types.d.ts +34 -0
  7. package/dist/cjs-types/common/actionButtons/index.d.ts +2 -0
  8. package/dist/cjs-types/common/actionIcon/actionIcon.d.ts +4 -0
  9. package/dist/cjs-types/common/actionIcon/actionIcon.types.d.ts +15 -0
  10. package/dist/cjs-types/common/actionIcon/index.d.ts +2 -0
  11. package/dist/cjs-types/common/alert/alert.d.ts +4 -0
  12. package/dist/cjs-types/common/alert/alert.types.d.ts +30 -0
  13. package/dist/cjs-types/common/alert/index.d.ts +2 -0
  14. package/dist/cjs-types/common/animatedIcon/animatedIcon.d.ts +3 -0
  15. package/dist/cjs-types/common/animatedIcon/animatedIcon.types.d.ts +25 -0
  16. package/dist/cjs-types/common/animatedIcon/index.d.ts +2 -0
  17. package/dist/cjs-types/common/animatedLogo/animatedLogo.d.ts +4 -0
  18. package/dist/cjs-types/common/animatedLogo/animatedLogo.types.d.ts +35 -0
  19. package/dist/cjs-types/common/animatedLogo/index.d.ts +2 -0
  20. package/dist/cjs-types/common/animatedText/animatedText.d.ts +4 -0
  21. package/dist/cjs-types/common/animatedText/animatedText.types.d.ts +65 -0
  22. package/dist/cjs-types/common/animatedText/index.d.ts +2 -0
  23. package/dist/cjs-types/common/avatar/avatar.d.ts +4 -0
  24. package/dist/cjs-types/common/avatar/avatar.types.d.ts +26 -0
  25. package/dist/cjs-types/common/avatar/avatarGroup.d.ts +4 -0
  26. package/dist/cjs-types/common/avatar/index.d.ts +3 -0
  27. package/dist/cjs-types/common/badge/badge.d.ts +4 -0
  28. package/dist/cjs-types/common/badge/badge.types.d.ts +31 -0
  29. package/dist/cjs-types/common/badge/index.d.ts +2 -0
  30. package/dist/cjs-types/common/bodyEnd/bodyEnd.d.ts +4 -0
  31. package/dist/cjs-types/common/bodyEnd/bodyEnd.types.d.ts +4 -0
  32. package/dist/cjs-types/common/bodyEnd/index.d.ts +2 -0
  33. package/dist/cjs-types/common/breadcrumb/breadcrumb.d.ts +4 -0
  34. package/dist/cjs-types/common/breadcrumb/breadcrumb.types.d.ts +33 -0
  35. package/dist/cjs-types/common/breadcrumb/index.d.ts +2 -0
  36. package/dist/cjs-types/common/button/button.d.ts +9 -0
  37. package/dist/cjs-types/common/button/button.types.d.ts +42 -0
  38. package/dist/cjs-types/common/button/index.d.ts +2 -0
  39. package/dist/cjs-types/common/buttonGroup/buttonGroup.d.ts +4 -0
  40. package/dist/cjs-types/common/buttonGroup/buttonGroup.types.d.ts +12 -0
  41. package/dist/cjs-types/common/buttonGroup/index.d.ts +2 -0
  42. package/dist/cjs-types/common/card/Card.d.ts +4 -0
  43. package/dist/cjs-types/common/card/CardActions.d.ts +4 -0
  44. package/dist/cjs-types/common/card/CardContent.d.ts +4 -0
  45. package/dist/cjs-types/common/card/CardHeader.d.ts +4 -0
  46. package/dist/cjs-types/common/card/CardMedia.d.ts +4 -0
  47. package/dist/cjs-types/common/card/card.types.d.ts +55 -0
  48. package/dist/cjs-types/common/card/index.d.ts +6 -0
  49. package/dist/cjs-types/common/carousel/carousel.d.ts +4 -0
  50. package/dist/cjs-types/common/carousel/carousel.types.d.ts +35 -0
  51. package/dist/cjs-types/common/carousel/index.d.ts +2 -0
  52. package/dist/cjs-types/common/checkbox/checkbox.d.ts +4 -0
  53. package/dist/cjs-types/common/checkbox/checkbox.types.d.ts +27 -0
  54. package/dist/cjs-types/common/checkbox/index.d.ts +2 -0
  55. package/dist/cjs-types/common/chip/chip.d.ts +4 -0
  56. package/dist/cjs-types/common/chip/chip.types.d.ts +35 -0
  57. package/dist/cjs-types/common/chip/chipContainer.d.ts +4 -0
  58. package/dist/cjs-types/common/chip/index.d.ts +3 -0
  59. package/dist/cjs-types/common/colorPicker/colorPicker.d.ts +4 -0
  60. package/dist/cjs-types/common/colorPicker/colorPicker.types.d.ts +25 -0
  61. package/dist/cjs-types/common/colorPicker/index.d.ts +2 -0
  62. package/dist/cjs-types/common/colorPicker/toHex.d.ts +11 -0
  63. package/dist/cjs-types/common/configProvider/configProvider.d.ts +13 -0
  64. package/dist/cjs-types/common/configProvider/configProvider.types.d.ts +133 -0
  65. package/dist/cjs-types/common/configProvider/index.d.ts +6 -0
  66. package/dist/cjs-types/common/configProvider/presentation.types.d.ts +14 -0
  67. package/dist/cjs-types/common/configProvider/useComponentDefaults.d.ts +17 -0
  68. package/dist/cjs-types/common/configProvider/useLabels.d.ts +22 -0
  69. package/dist/cjs-types/common/configProvider/usePresentationDefault.d.ts +8 -0
  70. package/dist/cjs-types/common/confirmModal/confirmModal.d.ts +4 -0
  71. package/dist/cjs-types/common/confirmModal/confirmModal.types.d.ts +24 -0
  72. package/dist/cjs-types/common/confirmModal/index.d.ts +2 -0
  73. package/dist/cjs-types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +2 -0
  74. package/dist/cjs-types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +23 -0
  75. package/dist/cjs-types/common/datePicker/components/datePickerMonth/index.d.ts +1 -0
  76. package/dist/cjs-types/common/datePicker/dateFunctions.d.ts +44 -0
  77. package/dist/cjs-types/common/datePicker/datePicker.d.ts +3 -0
  78. package/dist/cjs-types/common/datePicker/datePicker.types.d.ts +60 -0
  79. package/dist/cjs-types/common/datePicker/index.d.ts +2 -0
  80. package/dist/cjs-types/common/divider/divider.d.ts +4 -0
  81. package/dist/cjs-types/common/divider/divider.types.d.ts +21 -0
  82. package/dist/cjs-types/common/divider/index.d.ts +2 -0
  83. package/dist/cjs-types/common/drawer/drawer.d.ts +4 -0
  84. package/dist/cjs-types/common/drawer/drawer.types.d.ts +15 -0
  85. package/dist/cjs-types/common/drawer/index.d.ts +2 -0
  86. package/dist/cjs-types/common/dropZone/dropZone.d.ts +4 -0
  87. package/dist/cjs-types/common/dropZone/dropZone.types.d.ts +90 -0
  88. package/dist/cjs-types/common/dropZone/index.d.ts +2 -0
  89. package/dist/cjs-types/common/dropdown/dropdown.d.ts +4 -0
  90. package/dist/cjs-types/common/dropdown/dropdown.types.d.ts +47 -0
  91. package/dist/cjs-types/common/dropdown/index.d.ts +2 -0
  92. package/dist/cjs-types/common/emptyState/emptyState.d.ts +3 -0
  93. package/dist/cjs-types/common/emptyState/emptyState.types.d.ts +20 -0
  94. package/dist/cjs-types/common/emptyState/index.d.ts +2 -0
  95. package/dist/cjs-types/common/errorBoundary/errorBoundary.d.ts +14 -0
  96. package/dist/cjs-types/common/errorBoundary/errorBoundary.types.d.ts +57 -0
  97. package/dist/cjs-types/common/errorBoundary/index.d.ts +2 -0
  98. package/dist/cjs-types/common/fab/components/fabBase/fabBase.d.ts +3 -0
  99. package/dist/cjs-types/common/fab/components/fabBase/fabBase.types.d.ts +12 -0
  100. package/dist/cjs-types/common/fab/components/fabBase/index.d.ts +1 -0
  101. package/dist/cjs-types/common/fab/fab.d.ts +3 -0
  102. package/dist/cjs-types/common/fab/fab.types.d.ts +22 -0
  103. package/dist/cjs-types/common/fab/index.d.ts +2 -0
  104. package/dist/cjs-types/common/flip/flip.d.ts +3 -0
  105. package/dist/cjs-types/common/flip/flip.types.d.ts +44 -0
  106. package/dist/cjs-types/common/flip/index.d.ts +2 -0
  107. package/dist/cjs-types/common/floorPlan/floorPlan.faces.d.ts +33 -0
  108. package/dist/cjs-types/common/floorPlan/floorPlan.fixtures.d.ts +35 -0
  109. package/dist/cjs-types/common/floorPlan/floorPlan.geometry.d.ts +111 -0
  110. package/dist/cjs-types/common/floorPlan/floorPlan.graph.d.ts +184 -0
  111. package/dist/cjs-types/common/floorPlan/floorPlan.hit.d.ts +26 -0
  112. package/dist/cjs-types/common/floorPlan/floorPlan.json.d.ts +23 -0
  113. package/dist/cjs-types/common/floorPlan/floorPlan.mesh.d.ts +36 -0
  114. package/dist/cjs-types/common/floorPlan/floorPlan.path.d.ts +59 -0
  115. package/dist/cjs-types/common/floorPlan/floorPlan.plan.d.ts +98 -0
  116. package/dist/cjs-types/common/floorPlan/floorPlan.rooms.d.ts +47 -0
  117. package/dist/cjs-types/common/floorPlan/floorPlan.snap.d.ts +101 -0
  118. package/dist/cjs-types/common/floorPlan/floorPlan.triangulate.d.ts +11 -0
  119. package/dist/cjs-types/common/floorPlan/floorPlan.types.d.ts +276 -0
  120. package/dist/cjs-types/common/floorPlan/index.d.ts +30 -0
  121. package/dist/cjs-types/common/floorPlan/legacySvg.d.ts +27 -0
  122. package/dist/cjs-types/common/hooks/useAnchorTracking.d.ts +40 -0
  123. package/dist/cjs-types/common/hooks/useCoarsePointer.d.ts +3 -0
  124. package/dist/cjs-types/common/hooks/useFocusBoundary.d.ts +20 -0
  125. package/dist/cjs-types/common/hooks/useMediaQuery.d.ts +9 -0
  126. package/dist/cjs-types/common/hooks/useOverlay.d.ts +26 -0
  127. package/dist/cjs-types/common/hooks/useScrollEdges.d.ts +18 -0
  128. package/dist/cjs-types/common/hooks/useSheet.d.ts +19 -0
  129. package/dist/cjs-types/common/hooks/useSwipeDismiss.d.ts +33 -0
  130. package/dist/cjs-types/common/hooks/useVisualViewportSize.d.ts +13 -0
  131. package/dist/cjs-types/common/iconPicker/iconPicker.d.ts +3 -0
  132. package/dist/cjs-types/common/iconPicker/iconPicker.types.d.ts +23 -0
  133. package/dist/cjs-types/common/iconPicker/index.d.ts +2 -0
  134. package/dist/cjs-types/common/idleManager/idleManager.d.ts +3 -0
  135. package/dist/cjs-types/common/idleManager/idleManager.types.d.ts +8 -0
  136. package/dist/cjs-types/common/idleManager/index.d.ts +2 -0
  137. package/dist/cjs-types/common/infiniteBlock/useInfiniteScroll.d.ts +5 -0
  138. package/dist/cjs-types/common/input/index.d.ts +2 -0
  139. package/dist/cjs-types/common/input/input.d.ts +4 -0
  140. package/dist/cjs-types/common/input/input.types.d.ts +84 -0
  141. package/dist/cjs-types/common/inputDropdown/index.d.ts +2 -0
  142. package/dist/cjs-types/common/inputDropdown/inputDropdown.d.ts +3 -0
  143. package/dist/cjs-types/common/inputDropdown/inputDropdown.types.d.ts +36 -0
  144. package/dist/cjs-types/common/interactableDiv/index.d.ts +2 -0
  145. package/dist/cjs-types/common/interactableDiv/interactableDiv.d.ts +8 -0
  146. package/dist/cjs-types/common/kanbanBoard/KanbanBoard.d.ts +3 -0
  147. package/dist/cjs-types/common/kanbanBoard/KanbanColumn.d.ts +45 -0
  148. package/dist/cjs-types/common/kanbanBoard/KanbanItem.d.ts +3 -0
  149. package/dist/cjs-types/common/kanbanBoard/index.d.ts +3 -0
  150. package/dist/cjs-types/common/kanbanBoard/kanbanBoard.types.d.ts +129 -0
  151. package/dist/cjs-types/common/kanbanBoard/kanbanBoard.utils.d.ts +60 -0
  152. package/dist/cjs-types/common/klipyPicker/components/gifPreview/gifPreview.d.ts +3 -0
  153. package/dist/cjs-types/common/klipyPicker/components/gifPreview/gifPreview.types.d.ts +7 -0
  154. package/dist/cjs-types/common/klipyPicker/components/gifPreview/index.d.ts +1 -0
  155. package/dist/cjs-types/common/klipyPicker/components/gifView/gifView.d.ts +3 -0
  156. package/dist/cjs-types/common/klipyPicker/components/gifView/gifView.types.d.ts +4 -0
  157. package/dist/cjs-types/common/klipyPicker/components/gifView/index.d.ts +1 -0
  158. package/dist/cjs-types/common/klipyPicker/index.d.ts +2 -0
  159. package/dist/cjs-types/common/klipyPicker/klipyPicker.d.ts +3 -0
  160. package/dist/cjs-types/common/klipyPicker/klipyPicker.types.d.ts +15 -0
  161. package/dist/cjs-types/common/loading/iconLoading/iconLoading.d.ts +5 -0
  162. package/dist/cjs-types/common/loading/iconLoading/index.d.ts +2 -0
  163. package/dist/cjs-types/common/loading/index.d.ts +2 -0
  164. package/dist/cjs-types/common/loading/spinnerLoading/index.d.ts +2 -0
  165. package/dist/cjs-types/common/loading/spinnerLoading/spinnerLoading.d.ts +6 -0
  166. package/dist/cjs-types/common/maskedInput/index.d.ts +2 -0
  167. package/dist/cjs-types/common/maskedInput/mask.d.ts +48 -0
  168. package/dist/cjs-types/common/maskedInput/maskedInput.d.ts +13 -0
  169. package/dist/cjs-types/common/maskedInput/maskedInput.types.d.ts +38 -0
  170. package/dist/cjs-types/common/menu/index.d.ts +2 -0
  171. package/dist/cjs-types/common/menu/menu.d.ts +14 -0
  172. package/dist/cjs-types/common/menu/menu.types.d.ts +55 -0
  173. package/dist/cjs-types/common/modal/index.d.ts +2 -0
  174. package/dist/cjs-types/common/modal/modal.d.ts +3 -0
  175. package/dist/cjs-types/common/modal/modal.types.d.ts +31 -0
  176. package/dist/cjs-types/common/multiSelect/index.d.ts +2 -0
  177. package/dist/cjs-types/common/multiSelect/multiSelect.d.ts +4 -0
  178. package/dist/cjs-types/common/multiSelect/multiSelect.types.d.ts +69 -0
  179. package/dist/cjs-types/common/numberInput/index.d.ts +3 -0
  180. package/dist/cjs-types/common/numberInput/numberInput.d.ts +5 -0
  181. package/dist/cjs-types/common/numberInput/numberInput.types.d.ts +76 -0
  182. package/dist/cjs-types/common/numberInput/useStepRepeat.d.ts +17 -0
  183. package/dist/cjs-types/common/optionPicker/index.d.ts +2 -0
  184. package/dist/cjs-types/common/optionPicker/optionPicker.d.ts +4 -0
  185. package/dist/cjs-types/common/optionPicker/optionPicker.types.d.ts +16 -0
  186. package/dist/cjs-types/common/otpInput/index.d.ts +2 -0
  187. package/dist/cjs-types/common/otpInput/otpInput.d.ts +4 -0
  188. package/dist/cjs-types/common/otpInput/otpInput.types.d.ts +60 -0
  189. package/dist/cjs-types/common/overscroll/index.d.ts +2 -0
  190. package/dist/cjs-types/common/overscroll/overscroll.d.ts +2 -0
  191. package/dist/cjs-types/common/overscroll/overscroll.types.d.ts +14 -0
  192. package/dist/cjs-types/common/pagination/index.d.ts +2 -0
  193. package/dist/cjs-types/common/pagination/pagination.d.ts +4 -0
  194. package/dist/cjs-types/common/pagination/pagination.types.d.ts +45 -0
  195. package/dist/cjs-types/common/planCanvas/index.d.ts +2 -0
  196. package/dist/cjs-types/common/planCanvas/planCanvas.d.ts +7 -0
  197. package/dist/cjs-types/common/planCanvas/planCanvas.types.d.ts +64 -0
  198. package/dist/cjs-types/common/popover/index.d.ts +2 -0
  199. package/dist/cjs-types/common/popover/popover.d.ts +3 -0
  200. package/dist/cjs-types/common/popover/popover.types.d.ts +94 -0
  201. package/dist/cjs-types/common/popover/usePopoverPosition.d.ts +44 -0
  202. package/dist/cjs-types/common/progressBar/index.d.ts +2 -0
  203. package/dist/cjs-types/common/progressBar/progressBar.d.ts +5 -0
  204. package/dist/cjs-types/common/progressBar/progressBar.types.d.ts +18 -0
  205. package/dist/cjs-types/common/radioGroup/index.d.ts +2 -0
  206. package/dist/cjs-types/common/radioGroup/radioGroup.d.ts +4 -0
  207. package/dist/cjs-types/common/radioGroup/radioGroup.types.d.ts +45 -0
  208. package/dist/cjs-types/common/rating/index.d.ts +2 -0
  209. package/dist/cjs-types/common/rating/rating.d.ts +4 -0
  210. package/dist/cjs-types/common/rating/rating.types.d.ts +19 -0
  211. package/dist/cjs-types/common/revealLens/index.d.ts +2 -0
  212. package/dist/cjs-types/common/revealLens/revealLens.d.ts +4 -0
  213. package/dist/cjs-types/common/revealLens/revealLens.types.d.ts +24 -0
  214. package/dist/cjs-types/common/ripple/index.d.ts +2 -0
  215. package/dist/cjs-types/common/ripple/ripple.d.ts +5 -0
  216. package/dist/cjs-types/common/ripple/ripple.types.d.ts +16 -0
  217. package/dist/cjs-types/common/roomDrawer/index.d.ts +2 -0
  218. package/dist/cjs-types/common/roomDrawer/roomDrawer.d.ts +3 -0
  219. package/dist/cjs-types/common/roomDrawer/roomDrawer.types.d.ts +308 -0
  220. package/dist/cjs-types/common/roomDrawer/usePlanHistory.d.ts +24 -0
  221. package/dist/cjs-types/common/roomViewer/index.d.ts +2 -0
  222. package/dist/cjs-types/common/roomViewer/roomViewer.d.ts +10 -0
  223. package/dist/cjs-types/common/roomViewer/roomViewer.types.d.ts +91 -0
  224. package/dist/cjs-types/common/scrollFade/index.d.ts +2 -0
  225. package/dist/cjs-types/common/scrollFade/scrollFade.d.ts +4 -0
  226. package/dist/cjs-types/common/scrollFade/scrollFade.types.d.ts +20 -0
  227. package/dist/cjs-types/common/scrollbarProvider/index.d.ts +2 -0
  228. package/dist/cjs-types/common/scrollbarProvider/scrollbarProvider.d.ts +7 -0
  229. package/dist/cjs-types/common/searchInput/index.d.ts +2 -0
  230. package/dist/cjs-types/common/searchInput/searchInput.d.ts +3 -0
  231. package/dist/cjs-types/common/searchInput/searchInput.types.d.ts +28 -0
  232. package/dist/cjs-types/common/sectionHeader/index.d.ts +2 -0
  233. package/dist/cjs-types/common/sectionHeader/sectionHeader.d.ts +4 -0
  234. package/dist/cjs-types/common/sectionHeader/sectionHeader.types.d.ts +27 -0
  235. package/dist/cjs-types/common/sheetBackdrop/index.d.ts +2 -0
  236. package/dist/cjs-types/common/sheetBackdrop/sheetBackdrop.d.ts +16 -0
  237. package/dist/cjs-types/common/sheetBackdrop/sheetBackdrop.types.d.ts +7 -0
  238. package/dist/cjs-types/common/skeleton/index.d.ts +2 -0
  239. package/dist/cjs-types/common/skeleton/skeleton.d.ts +4 -0
  240. package/dist/cjs-types/common/skeleton/skeleton.types.d.ts +22 -0
  241. package/dist/cjs-types/common/slider/index.d.ts +2 -0
  242. package/dist/cjs-types/common/slider/slider.d.ts +3 -0
  243. package/dist/cjs-types/common/slider/slider.types.d.ts +68 -0
  244. package/dist/cjs-types/common/splitButton/index.d.ts +2 -0
  245. package/dist/cjs-types/common/splitButton/splitButton.d.ts +3 -0
  246. package/dist/cjs-types/common/splitButton/splitButton.types.d.ts +35 -0
  247. package/dist/cjs-types/common/stepper/index.d.ts +2 -0
  248. package/dist/cjs-types/common/stepper/stepper.d.ts +3 -0
  249. package/dist/cjs-types/common/stepper/stepper.types.d.ts +77 -0
  250. package/dist/cjs-types/common/sticky/index.d.ts +1 -0
  251. package/dist/cjs-types/common/sticky/sticky.d.ts +3 -0
  252. package/dist/cjs-types/common/sticky/sticky.types.d.ts +22 -0
  253. package/dist/cjs-types/common/sticky/stickyStack.d.ts +46 -0
  254. package/dist/cjs-types/common/switch/index.d.ts +2 -0
  255. package/dist/cjs-types/common/switch/switch.d.ts +4 -0
  256. package/dist/cjs-types/common/switch/switch.types.d.ts +21 -0
  257. package/dist/cjs-types/common/tabHeader/index.d.ts +2 -0
  258. package/dist/cjs-types/common/tabHeader/tabHeader.d.ts +4 -0
  259. package/dist/cjs-types/common/tabHeader/tabHeader.types.d.ts +20 -0
  260. package/dist/cjs-types/common/textarea/index.d.ts +2 -0
  261. package/dist/cjs-types/common/textarea/textarea.d.ts +3 -0
  262. package/dist/cjs-types/common/textarea/textarea.types.d.ts +2 -0
  263. package/dist/cjs-types/common/themeProvider/defaultTheme.d.ts +7 -0
  264. package/dist/cjs-types/common/themeProvider/index.d.ts +4 -0
  265. package/dist/cjs-types/common/themeProvider/lightTheme.d.ts +13 -0
  266. package/dist/cjs-types/common/themeProvider/theme.types.d.ts +272 -0
  267. package/dist/cjs-types/common/themeProvider/themeProvider.d.ts +38 -0
  268. package/dist/cjs-types/common/themeProvider/themeVariablesContext.d.ts +11 -0
  269. package/dist/cjs-types/common/themeProvider/useTheme.d.ts +4 -0
  270. package/dist/cjs-types/common/tilt/index.d.ts +4 -0
  271. package/dist/cjs-types/common/tilt/tilt.d.ts +3 -0
  272. package/dist/cjs-types/common/tilt/tilt.types.d.ts +40 -0
  273. package/dist/cjs-types/common/tilt/tiltMath.d.ts +24 -0
  274. package/dist/cjs-types/common/tiltGroup/index.d.ts +3 -0
  275. package/dist/cjs-types/common/tiltGroup/tiltGroup.d.ts +6 -0
  276. package/dist/cjs-types/common/tiltGroup/tiltGroup.types.d.ts +16 -0
  277. package/dist/cjs-types/common/timeInput/components/clockDial/clockDial.d.ts +3 -0
  278. package/dist/cjs-types/common/timeInput/components/clockDial/clockDial.types.d.ts +24 -0
  279. package/dist/cjs-types/common/timeInput/components/clockDial/index.d.ts +1 -0
  280. package/dist/cjs-types/common/timeInput/index.d.ts +1 -0
  281. package/dist/cjs-types/common/timeInput/timeFunctions.d.ts +36 -0
  282. package/dist/cjs-types/common/timeInput/timeInput.d.ts +3 -0
  283. package/dist/cjs-types/common/timeInput/timeInput.types.d.ts +44 -0
  284. package/dist/cjs-types/common/timeline/index.d.ts +2 -0
  285. package/dist/cjs-types/common/timeline/timeline.d.ts +3 -0
  286. package/dist/cjs-types/common/timeline/timeline.types.d.ts +51 -0
  287. package/dist/cjs-types/common/timer/index.d.ts +2 -0
  288. package/dist/cjs-types/common/timer/timer.chime.d.ts +1 -0
  289. package/dist/cjs-types/common/timer/timer.d.ts +3 -0
  290. package/dist/cjs-types/common/timer/timer.types.d.ts +110 -0
  291. package/dist/cjs-types/common/toast/index.d.ts +3 -0
  292. package/dist/cjs-types/common/toast/toast.d.ts +11 -0
  293. package/dist/cjs-types/common/toast/toast.types.d.ts +50 -0
  294. package/dist/cjs-types/common/toast/toastProvider.d.ts +8 -0
  295. package/dist/cjs-types/common/toast/toastService.d.ts +7 -0
  296. package/dist/cjs-types/common/tooltip/index.d.ts +2 -0
  297. package/dist/cjs-types/common/tooltip/tooltip.d.ts +3 -0
  298. package/dist/cjs-types/common/tooltip/tooltip.types.d.ts +17 -0
  299. package/dist/cjs-types/common/tree/flattenTree.d.ts +3 -0
  300. package/dist/cjs-types/common/tree/index.d.ts +3 -0
  301. package/dist/cjs-types/common/tree/tree.d.ts +4 -0
  302. package/dist/cjs-types/common/tree/tree.types.d.ts +67 -0
  303. package/dist/cjs-types/common/types/actions.types.d.ts +7 -0
  304. package/dist/cjs-types/common/types/baseProps.types.d.ts +29 -0
  305. package/dist/cjs-types/common/types/icon.types.d.ts +17 -0
  306. package/dist/cjs-types/common/types/slots.types.d.ts +4 -0
  307. package/dist/cjs-types/common/utils/activationKey.d.ts +9 -0
  308. package/dist/cjs-types/common/utils/interactiveTarget.d.ts +7 -0
  309. package/dist/cjs-types/common/utils/listNavigation.d.ts +49 -0
  310. package/dist/cjs-types/common/utils/mergeRefs.d.ts +12 -0
  311. package/dist/cjs-types/common/utils/renderIcon.d.ts +29 -0
  312. package/dist/cjs-types/common/utils/scrollAncestors.d.ts +2 -0
  313. package/dist/cjs-types/common/utils/visualViewport.d.ts +7 -0
  314. package/dist/cjs-types/common/virtualList/index.d.ts +2 -0
  315. package/dist/cjs-types/common/virtualList/useColumnResize.d.ts +59 -0
  316. package/dist/cjs-types/common/virtualList/useColumns.d.ts +52 -0
  317. package/dist/cjs-types/common/virtualList/useHeaderNavigation.d.ts +22 -0
  318. package/dist/cjs-types/common/virtualList/useRowDrag.d.ts +58 -0
  319. package/dist/cjs-types/common/virtualList/useRowNavigation.d.ts +50 -0
  320. package/dist/cjs-types/common/virtualList/useSelection.d.ts +24 -0
  321. package/dist/cjs-types/common/virtualList/useSorting.d.ts +26 -0
  322. package/dist/cjs-types/common/virtualList/useVirtualWindow.d.ts +36 -0
  323. package/dist/cjs-types/common/virtualList/virtualList.d.ts +5 -0
  324. package/dist/cjs-types/common/virtualList/virtualList.types.d.ts +317 -0
  325. package/dist/cjs-types/common/virtualList/virtualList.utils.d.ts +126 -0
  326. package/dist/cjs-types/common/virtualList/virtualListHeader.d.ts +35 -0
  327. package/dist/cjs-types/common/virtualList/virtualRow.d.ts +62 -0
  328. package/dist/cjs-types/common/wizard/index.d.ts +1 -0
  329. package/dist/cjs-types/common/wizard/wizard.d.ts +3 -0
  330. package/dist/cjs-types/common/wizard/wizard.types.d.ts +12 -0
  331. package/dist/cjs-types/hooks/useWindowSize.d.ts +6 -0
  332. package/dist/cjs-types/index.d.ts +154 -0
  333. package/dist/cjs-types/package.json +3 -0
  334. package/dist/cjs-types/services/formValidation/FormValidatorGroupWithForm.d.ts +18 -0
  335. package/dist/cjs-types/services/formValidation/index.d.ts +5 -0
  336. package/dist/cjs-types/services/formValidation/useFormValidatorGroup.d.ts +10 -0
  337. package/dist/cjs-types/services/formValidation/validatableComponent.d.ts +36 -0
  338. package/dist/cjs-types/services/klipy.d.ts +36 -0
  339. package/dist/cjs-types/services/localization.d.ts +3 -0
  340. package/dist/esm/common/accordion/accordion.mjs +1 -1
  341. package/dist/esm/common/accordion/accordion.mjs.map +1 -1
  342. package/dist/esm/common/accordion/accordion.module.mjs +1 -1
  343. package/dist/esm/common/accordion/accordion.module.mjs.map +1 -1
  344. package/dist/esm/common/accordion/accordion.plain.module.mjs +1 -1
  345. package/dist/esm/common/accordion/accordion.plain.module.mjs.map +1 -1
  346. package/dist/esm/common/accordion/accordion.primary.module.mjs +1 -1
  347. package/dist/esm/common/accordion/accordion.primary.module.mjs.map +1 -1
  348. package/dist/esm/common/accordion/accordion.types.mjs +1 -1
  349. package/dist/esm/common/accordion/accordion.types.mjs.map +1 -1
  350. package/dist/esm/common/actionButtons/actionButtons.mjs +1 -1
  351. package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -1
  352. package/dist/esm/common/actionButtons/actionButtons.module.mjs +1 -1
  353. package/dist/esm/common/actionIcon/actionIcon.mjs +1 -1
  354. package/dist/esm/common/actionIcon/actionIcon.mjs.map +1 -1
  355. package/dist/esm/common/actionIcon/actionIcon.module.mjs +1 -1
  356. package/dist/esm/common/alert/alert.mjs +1 -1
  357. package/dist/esm/common/alert/alert.mjs.map +1 -1
  358. package/dist/esm/common/alert/alert.module.mjs +1 -1
  359. package/dist/esm/common/alert/alert.types.mjs +1 -1
  360. package/dist/esm/common/alert/alert.types.mjs.map +1 -1
  361. package/dist/esm/common/animatedIcon/animatedIcon.mjs +1 -1
  362. package/dist/esm/common/animatedIcon/animatedIcon.mjs.map +1 -1
  363. package/dist/esm/common/animatedIcon/animatedIcon.module.mjs +1 -1
  364. package/dist/esm/common/animatedLogo/animatedLogo.mjs +1 -1
  365. package/dist/esm/common/animatedLogo/animatedLogo.mjs.map +1 -1
  366. package/dist/esm/common/animatedLogo/animatedLogo.module.mjs +1 -1
  367. package/dist/esm/common/animatedText/animatedText.mjs +1 -1
  368. package/dist/esm/common/animatedText/animatedText.mjs.map +1 -1
  369. package/dist/esm/common/animatedText/animatedText.module.mjs +1 -1
  370. package/dist/esm/common/animatedText/animatedText.types.mjs +1 -1
  371. package/dist/esm/common/animatedText/animatedText.types.mjs.map +1 -1
  372. package/dist/esm/common/avatar/avatar.mjs +1 -1
  373. package/dist/esm/common/avatar/avatar.mjs.map +1 -1
  374. package/dist/esm/common/avatar/avatar.module.mjs +1 -1
  375. package/dist/esm/common/avatar/avatarGroup.mjs +1 -1
  376. package/dist/esm/common/avatar/avatarGroup.mjs.map +1 -1
  377. package/dist/esm/common/badge/badge.mjs +1 -1
  378. package/dist/esm/common/badge/badge.mjs.map +1 -1
  379. package/dist/esm/common/badge/badge.module.mjs +1 -1
  380. package/dist/esm/common/badge/badge.types.mjs +1 -1
  381. package/dist/esm/common/badge/badge.types.mjs.map +1 -1
  382. package/dist/esm/common/bodyEnd/bodyEnd.mjs +1 -1
  383. package/dist/esm/common/bodyEnd/bodyEnd.mjs.map +1 -1
  384. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  385. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  386. package/dist/esm/common/breadcrumb/breadcrumb.module.mjs +1 -1
  387. package/dist/esm/common/button/button.mjs +1 -1
  388. package/dist/esm/common/button/button.mjs.map +1 -1
  389. package/dist/esm/common/button/button.module.mjs +1 -1
  390. package/dist/esm/common/button/button.types.mjs +1 -1
  391. package/dist/esm/common/button/button.types.mjs.map +1 -1
  392. package/dist/esm/common/buttonGroup/buttonGroup.mjs +1 -1
  393. package/dist/esm/common/buttonGroup/buttonGroup.mjs.map +1 -1
  394. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs +1 -1
  395. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs +1 -1
  396. package/dist/esm/common/buttonGroup/buttonGroup.types.mjs.map +1 -1
  397. package/dist/esm/common/card/Card.mjs +1 -1
  398. package/dist/esm/common/card/Card.mjs.map +1 -1
  399. package/dist/esm/common/card/CardActions.mjs +1 -1
  400. package/dist/esm/common/card/CardActions.mjs.map +1 -1
  401. package/dist/esm/common/card/CardContent.mjs +1 -1
  402. package/dist/esm/common/card/CardContent.mjs.map +1 -1
  403. package/dist/esm/common/card/CardHeader.mjs +1 -1
  404. package/dist/esm/common/card/CardHeader.mjs.map +1 -1
  405. package/dist/esm/common/card/CardMedia.mjs +1 -1
  406. package/dist/esm/common/card/CardMedia.mjs.map +1 -1
  407. package/dist/esm/common/card/card.module.mjs +1 -1
  408. package/dist/esm/common/card/card.module.mjs.map +1 -1
  409. package/dist/esm/common/card/card.types.mjs +1 -1
  410. package/dist/esm/common/card/card.types.mjs.map +1 -1
  411. package/dist/esm/common/carousel/carousel.mjs +1 -1
  412. package/dist/esm/common/carousel/carousel.mjs.map +1 -1
  413. package/dist/esm/common/carousel/carousel.module.mjs +1 -1
  414. package/dist/esm/common/carousel/carousel.module.mjs.map +1 -1
  415. package/dist/esm/common/checkbox/checkbox.mjs +1 -1
  416. package/dist/esm/common/checkbox/checkbox.mjs.map +1 -1
  417. package/dist/esm/common/checkbox/checkbox.module.mjs +1 -1
  418. package/dist/esm/common/checkbox/checkbox.module.mjs.map +1 -1
  419. package/dist/esm/common/chip/chip.mjs +1 -1
  420. package/dist/esm/common/chip/chip.mjs.map +1 -1
  421. package/dist/esm/common/chip/chip.module.mjs +1 -1
  422. package/dist/esm/common/chip/chip.types.mjs +1 -1
  423. package/dist/esm/common/chip/chip.types.mjs.map +1 -1
  424. package/dist/esm/common/chip/chipContainer.mjs +1 -1
  425. package/dist/esm/common/chip/chipContainer.mjs.map +1 -1
  426. package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
  427. package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
  428. package/dist/esm/common/colorPicker/colorPicker.module.mjs +1 -1
  429. package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -1
  430. package/dist/esm/common/colorPicker/toHex.mjs +1 -1
  431. package/dist/esm/common/colorPicker/toHex.mjs.map +1 -1
  432. package/dist/esm/common/configProvider/configProvider.mjs +1 -1
  433. package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
  434. package/dist/esm/common/configProvider/presentation.types.mjs +1 -1
  435. package/dist/esm/common/configProvider/presentation.types.mjs.map +1 -1
  436. package/dist/esm/common/configProvider/useComponentDefaults.mjs +1 -1
  437. package/dist/esm/common/configProvider/useComponentDefaults.mjs.map +1 -1
  438. package/dist/esm/common/configProvider/useLabels.mjs +1 -1
  439. package/dist/esm/common/configProvider/useLabels.mjs.map +1 -1
  440. package/dist/esm/common/configProvider/usePresentationDefault.mjs +1 -1
  441. package/dist/esm/common/configProvider/usePresentationDefault.mjs.map +1 -1
  442. package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
  443. package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
  444. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
  445. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
  446. package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs +1 -1
  447. package/dist/esm/common/datePicker/dateFunctions.mjs +1 -1
  448. package/dist/esm/common/datePicker/dateFunctions.mjs.map +1 -1
  449. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  450. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  451. package/dist/esm/common/datePicker/datePicker.module.mjs +1 -1
  452. package/dist/esm/common/divider/divider.mjs +1 -1
  453. package/dist/esm/common/divider/divider.mjs.map +1 -1
  454. package/dist/esm/common/divider/divider.module.mjs +1 -1
  455. package/dist/esm/common/divider/divider.types.mjs +1 -1
  456. package/dist/esm/common/divider/divider.types.mjs.map +1 -1
  457. package/dist/esm/common/drawer/drawer.mjs +1 -1
  458. package/dist/esm/common/drawer/drawer.mjs.map +1 -1
  459. package/dist/esm/common/drawer/drawer.module.mjs +1 -1
  460. package/dist/esm/common/drawer/drawer.module.mjs.map +1 -1
  461. package/dist/esm/common/dropZone/dropZone.mjs +1 -1
  462. package/dist/esm/common/dropZone/dropZone.mjs.map +1 -1
  463. package/dist/esm/common/dropZone/dropZone.module.mjs +1 -1
  464. package/dist/esm/common/dropZone/dropZone.types.mjs +1 -1
  465. package/dist/esm/common/dropZone/dropZone.types.mjs.map +1 -1
  466. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  467. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  468. package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
  469. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  470. package/dist/esm/common/emptyState/emptyState.mjs +1 -1
  471. package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
  472. package/dist/esm/common/emptyState/emptyState.module.mjs +1 -1
  473. package/dist/esm/common/errorBoundary/errorBoundary.mjs +1 -1
  474. package/dist/esm/common/errorBoundary/errorBoundary.mjs.map +1 -1
  475. package/dist/esm/common/errorBoundary/errorBoundary.module.mjs +1 -1
  476. package/dist/esm/common/fab/components/fabBase/fabBase.mjs +1 -1
  477. package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -1
  478. package/dist/esm/common/fab/components/fabBase/fabBase.module.mjs +1 -1
  479. package/dist/esm/common/fab/fab.mjs +1 -1
  480. package/dist/esm/common/fab/fab.mjs.map +1 -1
  481. package/dist/esm/common/fab/fab.module.mjs +1 -1
  482. package/dist/esm/common/fab/fab.module.mjs.map +1 -1
  483. package/dist/esm/common/flip/flip.mjs +1 -1
  484. package/dist/esm/common/flip/flip.mjs.map +1 -1
  485. package/dist/esm/common/flip/flip.module.mjs +1 -1
  486. package/dist/esm/common/floorPlan/floorPlan.faces.mjs +1 -1
  487. package/dist/esm/common/floorPlan/floorPlan.faces.mjs.map +1 -1
  488. package/dist/esm/common/floorPlan/floorPlan.geometry.mjs +1 -1
  489. package/dist/esm/common/floorPlan/floorPlan.geometry.mjs.map +1 -1
  490. package/dist/esm/common/floorPlan/floorPlan.graph.mjs +1 -1
  491. package/dist/esm/common/floorPlan/floorPlan.graph.mjs.map +1 -1
  492. package/dist/esm/common/floorPlan/floorPlan.hit.mjs +1 -1
  493. package/dist/esm/common/floorPlan/floorPlan.hit.mjs.map +1 -1
  494. package/dist/esm/common/floorPlan/floorPlan.json.mjs +1 -1
  495. package/dist/esm/common/floorPlan/floorPlan.json.mjs.map +1 -1
  496. package/dist/esm/common/floorPlan/floorPlan.mesh.mjs +1 -1
  497. package/dist/esm/common/floorPlan/floorPlan.mesh.mjs.map +1 -1
  498. package/dist/esm/common/floorPlan/floorPlan.path.mjs +1 -1
  499. package/dist/esm/common/floorPlan/floorPlan.path.mjs.map +1 -1
  500. package/dist/esm/common/floorPlan/floorPlan.plan.mjs +1 -1
  501. package/dist/esm/common/floorPlan/floorPlan.plan.mjs.map +1 -1
  502. package/dist/esm/common/floorPlan/floorPlan.rooms.mjs +1 -1
  503. package/dist/esm/common/floorPlan/floorPlan.rooms.mjs.map +1 -1
  504. package/dist/esm/common/floorPlan/floorPlan.snap.mjs +1 -1
  505. package/dist/esm/common/floorPlan/floorPlan.snap.mjs.map +1 -1
  506. package/dist/esm/common/floorPlan/floorPlan.triangulate.mjs +1 -1
  507. package/dist/esm/common/floorPlan/floorPlan.triangulate.mjs.map +1 -1
  508. package/dist/esm/common/floorPlan/floorPlan.types.mjs +1 -1
  509. package/dist/esm/common/floorPlan/floorPlan.types.mjs.map +1 -1
  510. package/dist/esm/common/floorPlan/legacySvg.mjs +1 -1
  511. package/dist/esm/common/floorPlan/legacySvg.mjs.map +1 -1
  512. package/dist/esm/common/hooks/useAnchorTracking.mjs +1 -1
  513. package/dist/esm/common/hooks/useAnchorTracking.mjs.map +1 -1
  514. package/dist/esm/common/hooks/useCoarsePointer.mjs +1 -1
  515. package/dist/esm/common/hooks/useCoarsePointer.mjs.map +1 -1
  516. package/dist/esm/common/hooks/useFocusBoundary.mjs +1 -1
  517. package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -1
  518. package/dist/esm/common/hooks/useMediaQuery.mjs +1 -1
  519. package/dist/esm/common/hooks/useMediaQuery.mjs.map +1 -1
  520. package/dist/esm/common/hooks/useOverlay.mjs +1 -1
  521. package/dist/esm/common/hooks/useOverlay.mjs.map +1 -1
  522. package/dist/esm/common/hooks/useScrollEdges.mjs +2 -0
  523. package/dist/esm/common/hooks/useScrollEdges.mjs.map +1 -0
  524. package/dist/esm/common/hooks/useSheet.mjs +1 -1
  525. package/dist/esm/common/hooks/useSheet.mjs.map +1 -1
  526. package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
  527. package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
  528. package/dist/esm/common/hooks/useVisualViewportSize.mjs +1 -1
  529. package/dist/esm/common/hooks/useVisualViewportSize.mjs.map +1 -1
  530. package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
  531. package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
  532. package/dist/esm/common/iconPicker/iconPicker.module.mjs +1 -1
  533. package/dist/esm/common/idleManager/idleManager.mjs +1 -1
  534. package/dist/esm/common/idleManager/idleManager.mjs.map +1 -1
  535. package/dist/esm/common/infiniteBlock/useInfiniteScroll.mjs +2 -0
  536. package/dist/esm/common/infiniteBlock/useInfiniteScroll.mjs.map +1 -0
  537. package/dist/esm/common/input/input.mjs +1 -1
  538. package/dist/esm/common/input/input.mjs.map +1 -1
  539. package/dist/esm/common/input/input.module.mjs +1 -1
  540. package/dist/esm/common/input/input.module.mjs.map +1 -1
  541. package/dist/esm/common/input/input.types.mjs +1 -1
  542. package/dist/esm/common/input/input.types.mjs.map +1 -1
  543. package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
  544. package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
  545. package/dist/esm/common/inputDropdown/inputDropdown.module.mjs +1 -1
  546. package/dist/esm/common/interactableDiv/index.mjs +1 -1
  547. package/dist/esm/common/interactableDiv/index.mjs.map +1 -1
  548. package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
  549. package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
  550. package/dist/esm/common/interactableDiv/interactableDiv.module.mjs +1 -1
  551. package/dist/esm/common/kanbanBoard/KanbanBoard.mjs +1 -1
  552. package/dist/esm/common/kanbanBoard/KanbanBoard.mjs.map +1 -1
  553. package/dist/esm/common/kanbanBoard/KanbanColumn.mjs +1 -1
  554. package/dist/esm/common/kanbanBoard/KanbanColumn.mjs.map +1 -1
  555. package/dist/esm/common/kanbanBoard/KanbanItem.mjs +1 -1
  556. package/dist/esm/common/kanbanBoard/KanbanItem.mjs.map +1 -1
  557. package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs +1 -1
  558. package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs +1 -1
  559. package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs.map +1 -1
  560. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs +1 -1
  561. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs.map +1 -1
  562. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs +1 -1
  563. package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs.map +1 -1
  564. package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs +1 -1
  565. package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs.map +1 -1
  566. package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs +1 -1
  567. package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs.map +1 -1
  568. package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
  569. package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
  570. package/dist/esm/common/klipyPicker/klipyPicker.module.mjs +1 -1
  571. package/dist/esm/common/loading/iconLoading/iconLoading.mjs +1 -1
  572. package/dist/esm/common/loading/iconLoading/iconLoading.mjs.map +1 -1
  573. package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs +1 -1
  574. package/dist/esm/common/loading/iconLoading/index.mjs +1 -1
  575. package/dist/esm/common/loading/iconLoading/index.mjs.map +1 -1
  576. package/dist/esm/common/loading/spinnerLoading/index.mjs +1 -1
  577. package/dist/esm/common/loading/spinnerLoading/index.mjs.map +1 -1
  578. package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs +1 -1
  579. package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs.map +1 -1
  580. package/dist/esm/common/loading/spinnerLoading/spinnerLoading.module.mjs +1 -1
  581. package/dist/esm/common/maskedInput/mask.mjs +2 -0
  582. package/dist/esm/common/maskedInput/mask.mjs.map +1 -0
  583. package/dist/esm/common/maskedInput/maskedInput.mjs +2 -0
  584. package/dist/esm/common/maskedInput/maskedInput.mjs.map +1 -0
  585. package/dist/esm/common/menu/menu.mjs +1 -1
  586. package/dist/esm/common/menu/menu.mjs.map +1 -1
  587. package/dist/esm/common/menu/menu.module.mjs +1 -1
  588. package/dist/esm/common/menu/menu.types.mjs +1 -1
  589. package/dist/esm/common/menu/menu.types.mjs.map +1 -1
  590. package/dist/esm/common/modal/modal.mjs +1 -1
  591. package/dist/esm/common/modal/modal.mjs.map +1 -1
  592. package/dist/esm/common/modal/modal.module.mjs +1 -1
  593. package/dist/esm/common/modal/modal.module.mjs.map +1 -1
  594. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  595. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  596. package/dist/esm/common/multiSelect/multiSelect.module.mjs +1 -1
  597. package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -1
  598. package/dist/esm/common/numberInput/index.mjs +1 -1
  599. package/dist/esm/common/numberInput/index.mjs.map +1 -1
  600. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  601. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  602. package/dist/esm/common/numberInput/numberInput.module.mjs +1 -1
  603. package/dist/esm/common/numberInput/useStepRepeat.mjs +1 -1
  604. package/dist/esm/common/numberInput/useStepRepeat.mjs.map +1 -1
  605. package/dist/esm/common/optionPicker/optionPicker.mjs +1 -1
  606. package/dist/esm/common/optionPicker/optionPicker.mjs.map +1 -1
  607. package/dist/esm/common/optionPicker/optionPicker.module.mjs +1 -1
  608. package/dist/esm/common/otpInput/otpInput.mjs +1 -1
  609. package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
  610. package/dist/esm/common/otpInput/otpInput.module.mjs +1 -1
  611. package/dist/esm/common/otpInput/otpInput.types.mjs +1 -1
  612. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  613. package/dist/esm/common/overscroll/overscroll.mjs +1 -1
  614. package/dist/esm/common/overscroll/overscroll.mjs.map +1 -1
  615. package/dist/esm/common/overscroll/overscroll.module.mjs +1 -1
  616. package/dist/esm/common/pagination/pagination.mjs +1 -1
  617. package/dist/esm/common/pagination/pagination.mjs.map +1 -1
  618. package/dist/esm/common/pagination/pagination.module.mjs +1 -1
  619. package/dist/esm/common/planCanvas/planCanvas.mjs +1 -1
  620. package/dist/esm/common/planCanvas/planCanvas.mjs.map +1 -1
  621. package/dist/esm/common/planCanvas/planCanvas.module.mjs +1 -1
  622. package/dist/esm/common/popover/popover.mjs +1 -1
  623. package/dist/esm/common/popover/popover.mjs.map +1 -1
  624. package/dist/esm/common/popover/popover.module.mjs +1 -1
  625. package/dist/esm/common/popover/popover.types.mjs +1 -1
  626. package/dist/esm/common/popover/popover.types.mjs.map +1 -1
  627. package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
  628. package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
  629. package/dist/esm/common/progressBar/progressBar.mjs +1 -1
  630. package/dist/esm/common/progressBar/progressBar.mjs.map +1 -1
  631. package/dist/esm/common/progressBar/progressBar.module.mjs +1 -1
  632. package/dist/esm/common/progressBar/progressBar.module.mjs.map +1 -1
  633. package/dist/esm/common/radioGroup/radioGroup.mjs +1 -1
  634. package/dist/esm/common/radioGroup/radioGroup.mjs.map +1 -1
  635. package/dist/esm/common/radioGroup/radioGroup.module.mjs +1 -1
  636. package/dist/esm/common/radioGroup/radioGroup.module.mjs.map +1 -1
  637. package/dist/esm/common/radioGroup/radioGroup.types.mjs +1 -1
  638. package/dist/esm/common/radioGroup/radioGroup.types.mjs.map +1 -1
  639. package/dist/esm/common/rating/rating.mjs +1 -1
  640. package/dist/esm/common/rating/rating.mjs.map +1 -1
  641. package/dist/esm/common/rating/rating.module.mjs +1 -1
  642. package/dist/esm/common/rating/rating.module.mjs.map +1 -1
  643. package/dist/esm/common/revealLens/revealLens.mjs +1 -1
  644. package/dist/esm/common/revealLens/revealLens.mjs.map +1 -1
  645. package/dist/esm/common/revealLens/revealLens.module.mjs +1 -1
  646. package/dist/esm/common/ripple/ripple.mjs +1 -1
  647. package/dist/esm/common/ripple/ripple.mjs.map +1 -1
  648. package/dist/esm/common/ripple/ripple.module.mjs +1 -1
  649. package/dist/esm/common/ripple/ripple.module.mjs.map +1 -1
  650. package/dist/esm/common/roomDrawer/roomDrawer.mjs +1 -1
  651. package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
  652. package/dist/esm/common/roomDrawer/roomDrawer.module.mjs +1 -1
  653. package/dist/esm/common/roomDrawer/usePlanHistory.mjs +1 -1
  654. package/dist/esm/common/roomDrawer/usePlanHistory.mjs.map +1 -1
  655. package/dist/esm/common/roomViewer/roomViewer.mjs +1 -1
  656. package/dist/esm/common/roomViewer/roomViewer.mjs.map +1 -1
  657. package/dist/esm/common/roomViewer/roomViewer.module.mjs +1 -1
  658. package/dist/esm/common/scrollFade/scrollFade.mjs +2 -0
  659. package/dist/esm/common/scrollFade/scrollFade.mjs.map +1 -0
  660. package/dist/esm/common/scrollFade/scrollFade.module.mjs +2 -0
  661. package/dist/esm/common/scrollFade/scrollFade.module.mjs.map +1 -0
  662. package/dist/esm/common/scrollFade/scrollFade.types.mjs +2 -0
  663. package/dist/esm/common/scrollFade/scrollFade.types.mjs.map +1 -0
  664. package/dist/esm/common/scrollbarProvider/index.mjs +1 -1
  665. package/dist/esm/common/scrollbarProvider/index.mjs.map +1 -1
  666. package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs +1 -1
  667. package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs.map +1 -1
  668. package/dist/esm/common/scrollbarProvider/scrollbarProvider.module.mjs +1 -1
  669. package/dist/esm/common/searchInput/searchInput.mjs +1 -1
  670. package/dist/esm/common/searchInput/searchInput.mjs.map +1 -1
  671. package/dist/esm/common/searchInput/searchInput.module.mjs +1 -1
  672. package/dist/esm/common/sectionHeader/sectionHeader.mjs +1 -1
  673. package/dist/esm/common/sectionHeader/sectionHeader.mjs.map +1 -1
  674. package/dist/esm/common/sectionHeader/sectionHeader.module.mjs +1 -1
  675. package/dist/esm/common/sectionHeader/sectionHeader.types.mjs +1 -1
  676. package/dist/esm/common/sectionHeader/sectionHeader.types.mjs.map +1 -1
  677. package/dist/esm/common/sheetBackdrop/sheetBackdrop.mjs +1 -1
  678. package/dist/esm/common/sheetBackdrop/sheetBackdrop.mjs.map +1 -1
  679. package/dist/esm/common/skeleton/skeleton.mjs +1 -1
  680. package/dist/esm/common/skeleton/skeleton.mjs.map +1 -1
  681. package/dist/esm/common/skeleton/skeleton.module.mjs +1 -1
  682. package/dist/esm/common/skeleton/skeleton.types.mjs +1 -1
  683. package/dist/esm/common/skeleton/skeleton.types.mjs.map +1 -1
  684. package/dist/esm/common/slider/slider.mjs +1 -1
  685. package/dist/esm/common/slider/slider.mjs.map +1 -1
  686. package/dist/esm/common/slider/slider.module.mjs +1 -1
  687. package/dist/esm/common/splitButton/splitButton.mjs +1 -1
  688. package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
  689. package/dist/esm/common/splitButton/splitButton.module.mjs +1 -1
  690. package/dist/esm/common/stepper/stepper.mjs +1 -1
  691. package/dist/esm/common/stepper/stepper.mjs.map +1 -1
  692. package/dist/esm/common/stepper/stepper.module.mjs +1 -1
  693. package/dist/esm/common/stepper/stepper.types.mjs +1 -1
  694. package/dist/esm/common/stepper/stepper.types.mjs.map +1 -1
  695. package/dist/esm/common/sticky/sticky.mjs +1 -1
  696. package/dist/esm/common/sticky/sticky.mjs.map +1 -1
  697. package/dist/esm/common/sticky/sticky.module.mjs +1 -1
  698. package/dist/esm/common/sticky/stickyStack.mjs +1 -1
  699. package/dist/esm/common/sticky/stickyStack.mjs.map +1 -1
  700. package/dist/esm/common/styles/scrollFade.module.mjs +2 -0
  701. package/dist/esm/common/styles/scrollFade.module.mjs.map +1 -0
  702. package/dist/esm/common/styles/sheet.module.mjs +1 -1
  703. package/dist/esm/common/styles/sheet.module.mjs.map +1 -1
  704. package/dist/esm/common/switch/switch.mjs +1 -1
  705. package/dist/esm/common/switch/switch.mjs.map +1 -1
  706. package/dist/esm/common/switch/switch.module.mjs +1 -1
  707. package/dist/esm/common/switch/switch.module.mjs.map +1 -1
  708. package/dist/esm/common/tabHeader/tabHeader.mjs +1 -1
  709. package/dist/esm/common/tabHeader/tabHeader.mjs.map +1 -1
  710. package/dist/esm/common/tabHeader/tabHeader.module.mjs +1 -1
  711. package/dist/esm/common/textarea/textarea.mjs +1 -1
  712. package/dist/esm/common/textarea/textarea.mjs.map +1 -1
  713. package/dist/esm/common/themeProvider/defaultTheme.mjs +1 -1
  714. package/dist/esm/common/themeProvider/defaultTheme.mjs.map +1 -1
  715. package/dist/esm/common/themeProvider/lightTheme.mjs +2 -0
  716. package/dist/esm/common/themeProvider/lightTheme.mjs.map +1 -0
  717. package/dist/esm/common/themeProvider/theme.module.mjs +1 -1
  718. package/dist/esm/common/themeProvider/themeProvider.mjs +1 -1
  719. package/dist/esm/common/themeProvider/themeProvider.mjs.map +1 -1
  720. package/dist/esm/common/themeProvider/themeVariablesContext.mjs +1 -1
  721. package/dist/esm/common/themeProvider/themeVariablesContext.mjs.map +1 -1
  722. package/dist/esm/common/themeProvider/useTheme.mjs +1 -1
  723. package/dist/esm/common/themeProvider/useTheme.mjs.map +1 -1
  724. package/dist/esm/common/tilt/tilt.mjs +1 -1
  725. package/dist/esm/common/tilt/tilt.mjs.map +1 -1
  726. package/dist/esm/common/tilt/tilt.module.mjs +1 -1
  727. package/dist/esm/common/tilt/tiltMath.mjs +1 -1
  728. package/dist/esm/common/tilt/tiltMath.mjs.map +1 -1
  729. package/dist/esm/common/tiltGroup/tiltGroup.mjs +1 -1
  730. package/dist/esm/common/tiltGroup/tiltGroup.mjs.map +1 -1
  731. package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs +1 -1
  732. package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs.map +1 -1
  733. package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs +1 -1
  734. package/dist/esm/common/timeInput/timeFunctions.mjs +1 -1
  735. package/dist/esm/common/timeInput/timeFunctions.mjs.map +1 -1
  736. package/dist/esm/common/timeInput/timeInput.mjs +1 -1
  737. package/dist/esm/common/timeInput/timeInput.mjs.map +1 -1
  738. package/dist/esm/common/timeInput/timeInput.module.mjs +1 -1
  739. package/dist/esm/common/timeline/timeline.mjs +1 -1
  740. package/dist/esm/common/timeline/timeline.mjs.map +1 -1
  741. package/dist/esm/common/timeline/timeline.module.mjs +1 -1
  742. package/dist/esm/common/timeline/timeline.types.mjs +1 -1
  743. package/dist/esm/common/timeline/timeline.types.mjs.map +1 -1
  744. package/dist/esm/common/timer/timer.chime.mjs +1 -1
  745. package/dist/esm/common/timer/timer.chime.mjs.map +1 -1
  746. package/dist/esm/common/timer/timer.mjs +1 -1
  747. package/dist/esm/common/timer/timer.mjs.map +1 -1
  748. package/dist/esm/common/timer/timer.module.mjs +1 -1
  749. package/dist/esm/common/toast/toast.mjs +1 -1
  750. package/dist/esm/common/toast/toast.mjs.map +1 -1
  751. package/dist/esm/common/toast/toast.module.mjs +1 -1
  752. package/dist/esm/common/toast/toast.module.mjs.map +1 -1
  753. package/dist/esm/common/toast/toastProvider.mjs +1 -1
  754. package/dist/esm/common/toast/toastProvider.mjs.map +1 -1
  755. package/dist/esm/common/toast/toastService.mjs +1 -1
  756. package/dist/esm/common/toast/toastService.mjs.map +1 -1
  757. package/dist/esm/common/tooltip/tooltip.mjs +1 -1
  758. package/dist/esm/common/tooltip/tooltip.mjs.map +1 -1
  759. package/dist/esm/common/tooltip/tooltip.module.mjs +1 -1
  760. package/dist/esm/common/tree/flattenTree.mjs +1 -1
  761. package/dist/esm/common/tree/flattenTree.mjs.map +1 -1
  762. package/dist/esm/common/tree/tree.mjs +1 -1
  763. package/dist/esm/common/tree/tree.mjs.map +1 -1
  764. package/dist/esm/common/tree/tree.module.mjs +1 -1
  765. package/dist/esm/common/tree/tree.module.mjs.map +1 -1
  766. package/dist/esm/common/utils/activationKey.mjs +1 -1
  767. package/dist/esm/common/utils/activationKey.mjs.map +1 -1
  768. package/dist/esm/common/utils/interactiveTarget.mjs +2 -0
  769. package/dist/esm/common/utils/interactiveTarget.mjs.map +1 -0
  770. package/dist/esm/common/utils/listNavigation.mjs +2 -0
  771. package/dist/esm/common/utils/listNavigation.mjs.map +1 -0
  772. package/dist/esm/common/utils/mergeRefs.mjs +2 -0
  773. package/dist/esm/common/utils/mergeRefs.mjs.map +1 -0
  774. package/dist/esm/common/utils/renderIcon.mjs +1 -1
  775. package/dist/esm/common/utils/renderIcon.mjs.map +1 -1
  776. package/dist/esm/common/utils/scrollAncestors.mjs +1 -1
  777. package/dist/esm/common/utils/scrollAncestors.mjs.map +1 -1
  778. package/dist/esm/common/utils/visualViewport.mjs +1 -1
  779. package/dist/esm/common/utils/visualViewport.mjs.map +1 -1
  780. package/dist/esm/common/virtualList/useColumnResize.mjs +1 -1
  781. package/dist/esm/common/virtualList/useColumnResize.mjs.map +1 -1
  782. package/dist/esm/common/virtualList/useColumns.mjs +1 -1
  783. package/dist/esm/common/virtualList/useColumns.mjs.map +1 -1
  784. package/dist/esm/common/virtualList/useHeaderNavigation.mjs +1 -1
  785. package/dist/esm/common/virtualList/useHeaderNavigation.mjs.map +1 -1
  786. package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
  787. package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
  788. package/dist/esm/common/virtualList/useRowNavigation.mjs +1 -1
  789. package/dist/esm/common/virtualList/useRowNavigation.mjs.map +1 -1
  790. package/dist/esm/common/virtualList/useSelection.mjs +1 -1
  791. package/dist/esm/common/virtualList/useSelection.mjs.map +1 -1
  792. package/dist/esm/common/virtualList/useSorting.mjs +1 -1
  793. package/dist/esm/common/virtualList/useSorting.mjs.map +1 -1
  794. package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
  795. package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
  796. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  797. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  798. package/dist/esm/common/virtualList/virtualList.module.mjs +1 -1
  799. package/dist/esm/common/virtualList/virtualList.utils.mjs +1 -1
  800. package/dist/esm/common/virtualList/virtualList.utils.mjs.map +1 -1
  801. package/dist/esm/common/virtualList/virtualListHeader.mjs +1 -1
  802. package/dist/esm/common/virtualList/virtualListHeader.mjs.map +1 -1
  803. package/dist/esm/common/virtualList/virtualRow.mjs +1 -1
  804. package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -1
  805. package/dist/esm/common/wizard/wizard.mjs +1 -1
  806. package/dist/esm/common/wizard/wizard.mjs.map +1 -1
  807. package/dist/esm/common/wizard/wizard.module.mjs +1 -1
  808. package/dist/esm/common/wizard/wizard.module.mjs.map +1 -1
  809. package/dist/esm/hooks/useWindowSize.mjs +1 -1
  810. package/dist/esm/hooks/useWindowSize.mjs.map +1 -1
  811. package/dist/esm/index.mjs +1 -1
  812. package/dist/esm/og.png +0 -0
  813. package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs +1 -1
  814. package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs.map +1 -1
  815. package/dist/esm/services/formValidation/index.mjs +1 -1
  816. package/dist/esm/services/formValidation/useFormValidatorGroup.mjs +1 -1
  817. package/dist/esm/services/formValidation/useFormValidatorGroup.mjs.map +1 -1
  818. package/dist/esm/services/formValidation/validatableComponent.mjs +1 -1
  819. package/dist/esm/services/formValidation/validatableComponent.mjs.map +1 -1
  820. package/dist/esm/services/klipy.mjs +1 -1
  821. package/dist/esm/services/klipy.mjs.map +1 -1
  822. package/dist/esm/services/localization.mjs +1 -1
  823. package/dist/esm/services/localization.mjs.map +1 -1
  824. package/dist/index.cjs +3 -3
  825. package/dist/index.cjs.map +1 -1
  826. package/dist/mcp.js +21432 -56
  827. package/dist/og.png +0 -0
  828. package/dist/style.css +1 -1
  829. package/dist/types/common/accordion/accordion.d.ts +1 -1
  830. package/dist/types/common/accordion/accordion.types.d.ts +1 -1
  831. package/dist/types/common/accordion/index.d.ts +2 -2
  832. package/dist/types/common/actionButtons/actionButtons.d.ts +1 -1
  833. package/dist/types/common/actionButtons/actionButtons.types.d.ts +3 -3
  834. package/dist/types/common/actionButtons/index.d.ts +2 -2
  835. package/dist/types/common/actionIcon/actionIcon.d.ts +1 -1
  836. package/dist/types/common/actionIcon/actionIcon.types.d.ts +5 -3
  837. package/dist/types/common/actionIcon/index.d.ts +2 -2
  838. package/dist/types/common/alert/alert.d.ts +1 -1
  839. package/dist/types/common/alert/alert.types.d.ts +2 -2
  840. package/dist/types/common/alert/index.d.ts +2 -2
  841. package/dist/types/common/animatedIcon/animatedIcon.d.ts +1 -1
  842. package/dist/types/common/animatedIcon/animatedIcon.types.d.ts +1 -1
  843. package/dist/types/common/animatedIcon/index.d.ts +2 -2
  844. package/dist/types/common/animatedLogo/animatedLogo.d.ts +1 -1
  845. package/dist/types/common/animatedLogo/animatedLogo.types.d.ts +1 -1
  846. package/dist/types/common/animatedLogo/index.d.ts +2 -2
  847. package/dist/types/common/animatedText/animatedText.d.ts +1 -1
  848. package/dist/types/common/animatedText/animatedText.types.d.ts +1 -1
  849. package/dist/types/common/animatedText/index.d.ts +2 -2
  850. package/dist/types/common/avatar/avatar.d.ts +1 -1
  851. package/dist/types/common/avatar/avatar.types.d.ts +2 -2
  852. package/dist/types/common/avatar/avatarGroup.d.ts +1 -1
  853. package/dist/types/common/avatar/index.d.ts +3 -3
  854. package/dist/types/common/badge/badge.d.ts +1 -1
  855. package/dist/types/common/badge/badge.types.d.ts +1 -1
  856. package/dist/types/common/badge/index.d.ts +2 -2
  857. package/dist/types/common/bodyEnd/bodyEnd.d.ts +1 -1
  858. package/dist/types/common/bodyEnd/index.d.ts +2 -2
  859. package/dist/types/common/breadcrumb/breadcrumb.d.ts +1 -1
  860. package/dist/types/common/breadcrumb/breadcrumb.types.d.ts +2 -2
  861. package/dist/types/common/breadcrumb/index.d.ts +2 -2
  862. package/dist/types/common/button/button.d.ts +1 -1
  863. package/dist/types/common/button/button.types.d.ts +2 -2
  864. package/dist/types/common/button/index.d.ts +2 -2
  865. package/dist/types/common/buttonGroup/buttonGroup.d.ts +1 -1
  866. package/dist/types/common/buttonGroup/buttonGroup.types.d.ts +1 -1
  867. package/dist/types/common/buttonGroup/index.d.ts +2 -2
  868. package/dist/types/common/card/Card.d.ts +1 -1
  869. package/dist/types/common/card/CardActions.d.ts +1 -1
  870. package/dist/types/common/card/CardContent.d.ts +1 -1
  871. package/dist/types/common/card/CardHeader.d.ts +1 -1
  872. package/dist/types/common/card/CardMedia.d.ts +1 -1
  873. package/dist/types/common/card/card.types.d.ts +6 -4
  874. package/dist/types/common/card/index.d.ts +6 -6
  875. package/dist/types/common/carousel/carousel.d.ts +1 -1
  876. package/dist/types/common/carousel/carousel.types.d.ts +1 -1
  877. package/dist/types/common/carousel/index.d.ts +2 -2
  878. package/dist/types/common/checkbox/checkbox.d.ts +1 -1
  879. package/dist/types/common/checkbox/checkbox.types.d.ts +5 -3
  880. package/dist/types/common/checkbox/index.d.ts +2 -2
  881. package/dist/types/common/chip/chip.d.ts +1 -1
  882. package/dist/types/common/chip/chip.types.d.ts +1 -1
  883. package/dist/types/common/chip/chipContainer.d.ts +1 -1
  884. package/dist/types/common/chip/index.d.ts +3 -3
  885. package/dist/types/common/colorPicker/colorPicker.d.ts +1 -1
  886. package/dist/types/common/colorPicker/colorPicker.types.d.ts +5 -1
  887. package/dist/types/common/colorPicker/index.d.ts +2 -2
  888. package/dist/types/common/configProvider/configProvider.d.ts +2 -2
  889. package/dist/types/common/configProvider/configProvider.types.d.ts +47 -43
  890. package/dist/types/common/configProvider/index.d.ts +6 -6
  891. package/dist/types/common/configProvider/useComponentDefaults.d.ts +1 -1
  892. package/dist/types/common/configProvider/useLabels.d.ts +1 -1
  893. package/dist/types/common/configProvider/usePresentationDefault.d.ts +1 -1
  894. package/dist/types/common/confirmModal/confirmModal.d.ts +1 -1
  895. package/dist/types/common/confirmModal/confirmModal.types.d.ts +2 -2
  896. package/dist/types/common/confirmModal/index.d.ts +2 -2
  897. package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +1 -1
  898. package/dist/types/common/datePicker/components/datePickerMonth/index.d.ts +1 -1
  899. package/dist/types/common/datePicker/datePicker.d.ts +1 -1
  900. package/dist/types/common/datePicker/datePicker.types.d.ts +2 -2
  901. package/dist/types/common/datePicker/index.d.ts +2 -2
  902. package/dist/types/common/divider/divider.d.ts +1 -1
  903. package/dist/types/common/divider/divider.types.d.ts +1 -1
  904. package/dist/types/common/divider/index.d.ts +2 -2
  905. package/dist/types/common/drawer/drawer.d.ts +1 -1
  906. package/dist/types/common/drawer/drawer.types.d.ts +1 -1
  907. package/dist/types/common/drawer/index.d.ts +2 -2
  908. package/dist/types/common/dropZone/dropZone.d.ts +1 -1
  909. package/dist/types/common/dropZone/dropZone.types.d.ts +1 -1
  910. package/dist/types/common/dropZone/index.d.ts +2 -2
  911. package/dist/types/common/dropdown/dropdown.d.ts +1 -1
  912. package/dist/types/common/dropdown/dropdown.types.d.ts +3 -3
  913. package/dist/types/common/dropdown/index.d.ts +2 -2
  914. package/dist/types/common/emptyState/emptyState.d.ts +1 -1
  915. package/dist/types/common/emptyState/emptyState.types.d.ts +2 -2
  916. package/dist/types/common/emptyState/index.d.ts +2 -2
  917. package/dist/types/common/errorBoundary/errorBoundary.d.ts +1 -1
  918. package/dist/types/common/errorBoundary/errorBoundary.types.d.ts +1 -1
  919. package/dist/types/common/errorBoundary/index.d.ts +2 -2
  920. package/dist/types/common/fab/components/fabBase/fabBase.d.ts +1 -1
  921. package/dist/types/common/fab/components/fabBase/fabBase.types.d.ts +1 -1
  922. package/dist/types/common/fab/components/fabBase/index.d.ts +1 -1
  923. package/dist/types/common/fab/fab.d.ts +1 -1
  924. package/dist/types/common/fab/fab.types.d.ts +2 -2
  925. package/dist/types/common/fab/index.d.ts +2 -2
  926. package/dist/types/common/flip/flip.d.ts +2 -2
  927. package/dist/types/common/flip/flip.types.d.ts +4 -2
  928. package/dist/types/common/flip/index.d.ts +2 -2
  929. package/dist/types/common/floorPlan/floorPlan.faces.d.ts +2 -2
  930. package/dist/types/common/floorPlan/floorPlan.fixtures.d.ts +1 -1
  931. package/dist/types/common/floorPlan/floorPlan.geometry.d.ts +1 -1
  932. package/dist/types/common/floorPlan/floorPlan.graph.d.ts +1 -1
  933. package/dist/types/common/floorPlan/floorPlan.hit.d.ts +1 -1
  934. package/dist/types/common/floorPlan/floorPlan.json.d.ts +1 -1
  935. package/dist/types/common/floorPlan/floorPlan.mesh.d.ts +1 -1
  936. package/dist/types/common/floorPlan/floorPlan.path.d.ts +1 -1
  937. package/dist/types/common/floorPlan/floorPlan.plan.d.ts +1 -1
  938. package/dist/types/common/floorPlan/floorPlan.rooms.d.ts +1 -1
  939. package/dist/types/common/floorPlan/floorPlan.snap.d.ts +1 -1
  940. package/dist/types/common/floorPlan/floorPlan.triangulate.d.ts +1 -1
  941. package/dist/types/common/floorPlan/index.d.ts +22 -22
  942. package/dist/types/common/floorPlan/legacySvg.d.ts +2 -2
  943. package/dist/types/common/hooks/useScrollEdges.d.ts +18 -0
  944. package/dist/types/common/hooks/useSheet.d.ts +1 -1
  945. package/dist/types/common/iconPicker/iconPicker.d.ts +1 -1
  946. package/dist/types/common/iconPicker/iconPicker.types.d.ts +2 -2
  947. package/dist/types/common/iconPicker/index.d.ts +2 -1
  948. package/dist/types/common/idleManager/idleManager.d.ts +1 -1
  949. package/dist/types/common/idleManager/index.d.ts +2 -1
  950. package/dist/types/common/infiniteBlock/useInfiniteScroll.d.ts +5 -0
  951. package/dist/types/common/input/index.d.ts +2 -2
  952. package/dist/types/common/input/input.d.ts +1 -1
  953. package/dist/types/common/input/input.types.d.ts +7 -2
  954. package/dist/types/common/inputDropdown/index.d.ts +2 -1
  955. package/dist/types/common/inputDropdown/inputDropdown.d.ts +1 -1
  956. package/dist/types/common/inputDropdown/inputDropdown.types.d.ts +2 -2
  957. package/dist/types/common/interactableDiv/index.d.ts +1 -1
  958. package/dist/types/common/interactableDiv/interactableDiv.d.ts +4 -3
  959. package/dist/types/common/kanbanBoard/KanbanBoard.d.ts +1 -1
  960. package/dist/types/common/kanbanBoard/KanbanColumn.d.ts +1 -1
  961. package/dist/types/common/kanbanBoard/KanbanItem.d.ts +1 -1
  962. package/dist/types/common/kanbanBoard/index.d.ts +3 -3
  963. package/dist/types/common/kanbanBoard/kanbanBoard.types.d.ts +1 -1
  964. package/dist/types/common/kanbanBoard/kanbanBoard.utils.d.ts +1 -1
  965. package/dist/types/common/klipyPicker/components/gifPreview/gifPreview.d.ts +1 -1
  966. package/dist/types/common/klipyPicker/components/gifPreview/gifPreview.types.d.ts +1 -1
  967. package/dist/types/common/klipyPicker/components/gifPreview/index.d.ts +1 -1
  968. package/dist/types/common/klipyPicker/components/gifView/gifView.d.ts +1 -1
  969. package/dist/types/common/klipyPicker/components/gifView/index.d.ts +1 -1
  970. package/dist/types/common/klipyPicker/index.d.ts +2 -2
  971. package/dist/types/common/klipyPicker/klipyPicker.d.ts +1 -1
  972. package/dist/types/common/klipyPicker/klipyPicker.types.d.ts +1 -1
  973. package/dist/types/common/loading/index.d.ts +2 -2
  974. package/dist/types/common/loading/spinnerLoading/index.d.ts +1 -1
  975. package/dist/types/common/loading/spinnerLoading/spinnerLoading.d.ts +0 -5
  976. package/dist/types/common/maskedInput/index.d.ts +2 -0
  977. package/dist/types/common/maskedInput/mask.d.ts +48 -0
  978. package/dist/types/common/maskedInput/maskedInput.d.ts +13 -0
  979. package/dist/types/common/maskedInput/maskedInput.types.d.ts +38 -0
  980. package/dist/types/common/menu/index.d.ts +2 -2
  981. package/dist/types/common/menu/menu.d.ts +1 -1
  982. package/dist/types/common/menu/menu.types.d.ts +4 -4
  983. package/dist/types/common/modal/index.d.ts +2 -2
  984. package/dist/types/common/modal/modal.d.ts +1 -1
  985. package/dist/types/common/modal/modal.types.d.ts +6 -3
  986. package/dist/types/common/multiSelect/index.d.ts +2 -2
  987. package/dist/types/common/multiSelect/multiSelect.d.ts +1 -1
  988. package/dist/types/common/multiSelect/multiSelect.types.d.ts +3 -3
  989. package/dist/types/common/numberInput/index.d.ts +2 -2
  990. package/dist/types/common/numberInput/numberInput.d.ts +2 -2
  991. package/dist/types/common/numberInput/numberInput.types.d.ts +4 -2
  992. package/dist/types/common/optionPicker/index.d.ts +2 -2
  993. package/dist/types/common/optionPicker/optionPicker.d.ts +1 -1
  994. package/dist/types/common/optionPicker/optionPicker.types.d.ts +1 -1
  995. package/dist/types/common/otpInput/index.d.ts +2 -2
  996. package/dist/types/common/otpInput/otpInput.d.ts +1 -1
  997. package/dist/types/common/otpInput/otpInput.types.d.ts +4 -2
  998. package/dist/types/common/overscroll/index.d.ts +2 -2
  999. package/dist/types/common/overscroll/overscroll.d.ts +1 -1
  1000. package/dist/types/common/pagination/index.d.ts +2 -2
  1001. package/dist/types/common/pagination/pagination.d.ts +1 -1
  1002. package/dist/types/common/pagination/pagination.types.d.ts +2 -2
  1003. package/dist/types/common/planCanvas/index.d.ts +2 -2
  1004. package/dist/types/common/planCanvas/planCanvas.d.ts +2 -2
  1005. package/dist/types/common/planCanvas/planCanvas.types.d.ts +5 -3
  1006. package/dist/types/common/popover/index.d.ts +2 -2
  1007. package/dist/types/common/popover/popover.d.ts +1 -1
  1008. package/dist/types/common/popover/popover.types.d.ts +2 -2
  1009. package/dist/types/common/popover/usePopoverPosition.d.ts +1 -1
  1010. package/dist/types/common/progressBar/index.d.ts +2 -2
  1011. package/dist/types/common/progressBar/progressBar.d.ts +1 -1
  1012. package/dist/types/common/progressBar/progressBar.types.d.ts +1 -1
  1013. package/dist/types/common/radioGroup/index.d.ts +2 -2
  1014. package/dist/types/common/radioGroup/radioGroup.d.ts +1 -1
  1015. package/dist/types/common/radioGroup/radioGroup.types.d.ts +3 -3
  1016. package/dist/types/common/rating/index.d.ts +2 -2
  1017. package/dist/types/common/rating/rating.d.ts +1 -1
  1018. package/dist/types/common/rating/rating.types.d.ts +2 -2
  1019. package/dist/types/common/revealLens/index.d.ts +2 -2
  1020. package/dist/types/common/revealLens/revealLens.d.ts +1 -1
  1021. package/dist/types/common/revealLens/revealLens.types.d.ts +1 -1
  1022. package/dist/types/common/ripple/index.d.ts +2 -2
  1023. package/dist/types/common/ripple/ripple.d.ts +2 -2
  1024. package/dist/types/common/ripple/ripple.types.d.ts +2 -1
  1025. package/dist/types/common/roomDrawer/index.d.ts +2 -2
  1026. package/dist/types/common/roomDrawer/roomDrawer.d.ts +2 -2
  1027. package/dist/types/common/roomDrawer/roomDrawer.types.d.ts +6 -4
  1028. package/dist/types/common/roomDrawer/usePlanHistory.d.ts +2 -2
  1029. package/dist/types/common/roomViewer/index.d.ts +2 -2
  1030. package/dist/types/common/roomViewer/roomViewer.d.ts +2 -2
  1031. package/dist/types/common/roomViewer/roomViewer.types.d.ts +6 -4
  1032. package/dist/types/common/scrollFade/index.d.ts +2 -0
  1033. package/dist/types/common/scrollFade/scrollFade.d.ts +4 -0
  1034. package/dist/types/common/scrollFade/scrollFade.types.d.ts +20 -0
  1035. package/dist/types/common/scrollbarProvider/index.d.ts +1 -1
  1036. package/dist/types/common/searchInput/index.d.ts +2 -2
  1037. package/dist/types/common/searchInput/searchInput.d.ts +2 -2
  1038. package/dist/types/common/searchInput/searchInput.types.d.ts +4 -1
  1039. package/dist/types/common/sectionHeader/index.d.ts +2 -2
  1040. package/dist/types/common/sectionHeader/sectionHeader.d.ts +1 -1
  1041. package/dist/types/common/sectionHeader/sectionHeader.types.d.ts +3 -3
  1042. package/dist/types/common/sheetBackdrop/index.d.ts +2 -2
  1043. package/dist/types/common/sheetBackdrop/sheetBackdrop.d.ts +1 -1
  1044. package/dist/types/common/skeleton/index.d.ts +2 -2
  1045. package/dist/types/common/skeleton/skeleton.d.ts +1 -1
  1046. package/dist/types/common/skeleton/skeleton.types.d.ts +1 -1
  1047. package/dist/types/common/slider/index.d.ts +2 -2
  1048. package/dist/types/common/slider/slider.d.ts +1 -1
  1049. package/dist/types/common/slider/slider.types.d.ts +2 -2
  1050. package/dist/types/common/splitButton/index.d.ts +2 -2
  1051. package/dist/types/common/splitButton/splitButton.d.ts +1 -1
  1052. package/dist/types/common/splitButton/splitButton.types.d.ts +4 -4
  1053. package/dist/types/common/stepper/index.d.ts +2 -2
  1054. package/dist/types/common/stepper/stepper.d.ts +1 -1
  1055. package/dist/types/common/stepper/stepper.types.d.ts +2 -2
  1056. package/dist/types/common/sticky/index.d.ts +1 -1
  1057. package/dist/types/common/sticky/sticky.d.ts +1 -1
  1058. package/dist/types/common/sticky/sticky.types.d.ts +1 -1
  1059. package/dist/types/common/switch/index.d.ts +2 -2
  1060. package/dist/types/common/switch/switch.d.ts +1 -1
  1061. package/dist/types/common/switch/switch.types.d.ts +5 -3
  1062. package/dist/types/common/tabHeader/index.d.ts +2 -2
  1063. package/dist/types/common/tabHeader/tabHeader.d.ts +1 -1
  1064. package/dist/types/common/tabHeader/tabHeader.types.d.ts +2 -2
  1065. package/dist/types/common/textarea/index.d.ts +2 -2
  1066. package/dist/types/common/textarea/textarea.d.ts +1 -1
  1067. package/dist/types/common/textarea/textarea.types.d.ts +1 -1
  1068. package/dist/types/common/themeProvider/defaultTheme.d.ts +1 -1
  1069. package/dist/types/common/themeProvider/index.d.ts +4 -3
  1070. package/dist/types/common/themeProvider/lightTheme.d.ts +13 -0
  1071. package/dist/types/common/themeProvider/theme.types.d.ts +28 -0
  1072. package/dist/types/common/themeProvider/themeProvider.d.ts +1 -1
  1073. package/dist/types/common/tilt/index.d.ts +4 -4
  1074. package/dist/types/common/tilt/tilt.d.ts +2 -2
  1075. package/dist/types/common/tilt/tilt.types.d.ts +5 -3
  1076. package/dist/types/common/tiltGroup/index.d.ts +3 -3
  1077. package/dist/types/common/tiltGroup/tiltGroup.d.ts +1 -1
  1078. package/dist/types/common/tiltGroup/tiltGroup.types.d.ts +1 -1
  1079. package/dist/types/common/timeInput/components/clockDial/clockDial.d.ts +1 -1
  1080. package/dist/types/common/timeInput/components/clockDial/clockDial.types.d.ts +3 -3
  1081. package/dist/types/common/timeInput/components/clockDial/index.d.ts +1 -1
  1082. package/dist/types/common/timeInput/index.d.ts +1 -1
  1083. package/dist/types/common/timeInput/timeInput.d.ts +1 -1
  1084. package/dist/types/common/timeInput/timeInput.types.d.ts +2 -2
  1085. package/dist/types/common/timeline/index.d.ts +2 -2
  1086. package/dist/types/common/timeline/timeline.d.ts +1 -1
  1087. package/dist/types/common/timeline/timeline.types.d.ts +2 -2
  1088. package/dist/types/common/timer/index.d.ts +2 -2
  1089. package/dist/types/common/timer/timer.d.ts +2 -2
  1090. package/dist/types/common/timer/timer.types.d.ts +5 -3
  1091. package/dist/types/common/toast/index.d.ts +3 -3
  1092. package/dist/types/common/toast/toast.d.ts +1 -1
  1093. package/dist/types/common/toast/toast.types.d.ts +1 -1
  1094. package/dist/types/common/toast/toastProvider.d.ts +1 -1
  1095. package/dist/types/common/toast/toastService.d.ts +1 -1
  1096. package/dist/types/common/tooltip/index.d.ts +2 -2
  1097. package/dist/types/common/tooltip/tooltip.d.ts +2 -2
  1098. package/dist/types/common/tooltip/tooltip.types.d.ts +7 -0
  1099. package/dist/types/common/tree/flattenTree.d.ts +1 -1
  1100. package/dist/types/common/tree/index.d.ts +3 -3
  1101. package/dist/types/common/tree/tree.d.ts +1 -1
  1102. package/dist/types/common/tree/tree.types.d.ts +2 -2
  1103. package/dist/types/common/types/actions.types.d.ts +1 -1
  1104. package/dist/types/common/types/baseProps.types.d.ts +6 -0
  1105. package/dist/types/common/types/slots.types.d.ts +1 -1
  1106. package/dist/types/common/utils/interactiveTarget.d.ts +7 -0
  1107. package/dist/types/common/utils/listNavigation.d.ts +49 -0
  1108. package/dist/types/common/utils/mergeRefs.d.ts +12 -0
  1109. package/dist/types/common/utils/renderIcon.d.ts +1 -1
  1110. package/dist/types/common/virtualList/index.d.ts +2 -2
  1111. package/dist/types/common/virtualList/useColumnResize.d.ts +1 -1
  1112. package/dist/types/common/virtualList/useColumns.d.ts +1 -1
  1113. package/dist/types/common/virtualList/useRowDrag.d.ts +1 -1
  1114. package/dist/types/common/virtualList/useRowNavigation.d.ts +1 -1
  1115. package/dist/types/common/virtualList/useSorting.d.ts +1 -1
  1116. package/dist/types/common/virtualList/useVirtualWindow.d.ts +1 -1
  1117. package/dist/types/common/virtualList/virtualList.d.ts +3 -5
  1118. package/dist/types/common/virtualList/virtualList.types.d.ts +4 -2
  1119. package/dist/types/common/virtualList/virtualList.utils.d.ts +1 -1
  1120. package/dist/types/common/virtualList/virtualListHeader.d.ts +4 -4
  1121. package/dist/types/common/virtualList/virtualRow.d.ts +1 -1
  1122. package/dist/types/common/wizard/index.d.ts +1 -1
  1123. package/dist/types/common/wizard/wizard.d.ts +1 -1
  1124. package/dist/types/common/wizard/wizard.types.d.ts +1 -1
  1125. package/dist/types/index.d.ts +153 -153
  1126. package/dist/types/services/formValidation/index.d.ts +3 -3
  1127. package/dist/types/services/formValidation/useFormValidatorGroup.d.ts +1 -1
  1128. package/docs/Accordion.md +9 -0
  1129. package/docs/ActionIcon.md +3 -0
  1130. package/docs/CLAUDE.md +123 -193
  1131. package/docs/Card.md +2 -1
  1132. package/docs/Checkbox.md +1 -0
  1133. package/docs/ColorPicker.md +12 -2
  1134. package/docs/Divider.md +2 -0
  1135. package/docs/Dropdown.md +20 -0
  1136. package/docs/IdleManager.md +38 -8
  1137. package/docs/Input.md +1 -0
  1138. package/docs/InputDropdown.md +11 -0
  1139. package/docs/InteractableDiv.md +7 -1
  1140. package/docs/KlipyPicker.md +2 -2
  1141. package/docs/Loading.md +3 -1
  1142. package/docs/Menu.md +2 -0
  1143. package/docs/Modal.md +34 -10
  1144. package/docs/MultiSelect.md +2 -2
  1145. package/docs/NumberInput.md +1 -0
  1146. package/docs/OtpInput.md +1 -0
  1147. package/docs/Pagination.md +1 -1
  1148. package/docs/Popover.md +2 -0
  1149. package/docs/RadioGroup.md +1 -1
  1150. package/docs/Rating.md +2 -0
  1151. package/docs/Ripple.md +3 -0
  1152. package/docs/RoomViewer.md +3 -5
  1153. package/docs/ScrollFade.md +77 -0
  1154. package/docs/ScrollbarProvider.md +2 -0
  1155. package/docs/SearchInput.md +1 -0
  1156. package/docs/Slider.md +1 -1
  1157. package/docs/Switch.md +1 -0
  1158. package/docs/Textarea.md +1 -0
  1159. package/docs/ThemeProvider.md +30 -1
  1160. package/docs/Timer.md +1 -1
  1161. package/docs/Tooltip.md +23 -1
  1162. package/docs/Wizard.md +1 -1
  1163. package/package.json +39 -16
  1164. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +0 -2
  1165. package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +0 -1
  1166. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs +0 -2
  1167. package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs.map +0 -1
  1168. package/dist/types/common/infiniteBlock/index.d.ts +0 -1
  1169. package/dist/types/common/infiniteBlock/infiniteBlock.d.ts +0 -4
  1170. package/dist/types/common/infiniteBlock/infiniteBlock.types.d.ts +0 -13
  1171. package/docs/Icon.md +0 -27
  1172. package/docs/InfiniteBlock.md +0 -23
@@ -1 +1 @@
1
- {"version":3,"file":"floorPlan.geometry.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.geometry.ts"],"sourcesContent":["/**\n * Pure vector and polygon primitives. Nothing here knows about the plan model.\n *\n * All lengths are millimetres (see floorPlan.types.ts).\n */\n\nimport type { PlanPoint } from './floorPlan.types';\n\n// ─── Model-integrity epsilons ──────────────────────────────────────────────────\n// These are FIXED millimetre values describing when the model itself is degenerate.\n// They are a separate family from the user-intent tolerances in floorPlan.snap.ts,\n// which are screen pixels converted through the current zoom. Conflating the two\n// gives you either a model that accumulates 0.2mm walls, or snapping that stops\n// working when zoomed in.\n\n/** Shortest wall the graph will accept. Keeps zero-length walls out entirely. */\nexport const MIN_WALL_LENGTH = 10;\n/** Two points closer than this are the same point. */\nexport const EPS_COINCIDENT = 1;\n/** A ring with |area| below this encloses nothing (0.0001 m²). */\nexport const EPS_AREA = 100;\n/** Angular tolerance for \"these two walls are collinear\", in radians. */\nexport const EPS_ANGLE = 1e-4;\n/** Narrowest scanline span that counts as room interior rather than a slit. */\nexport const EPS_SPAN = 2;\n/** Narrowest opening worth keeping when a wall shortens under it. */\nexport const MIN_OPENING_WIDTH = 100;\n\n// ─── Vectors ───────────────────────────────────────────────────────────────────\n\nexport function dist(a: PlanPoint, b: PlanPoint): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n\nexport function distSq(a: PlanPoint, b: PlanPoint): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return dx * dx + dy * dy;\n}\n\n/** Cross product of ab and ac. Positive when c is clockwise of b in SVG's y-down space. */\nexport function cross(a: PlanPoint, b: PlanPoint, c: PlanPoint): number {\n return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);\n}\n\nexport function lerp(a: PlanPoint, b: PlanPoint, t: number): PlanPoint {\n return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };\n}\n\n/** Unit vector from a to b, or null when they are coincident. */\nexport function direction(a: PlanPoint, b: PlanPoint): PlanPoint | null {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len = Math.hypot(dx, dy);\n if (len < 1e-9) return null;\n return { x: dx / len, y: dy / len };\n}\n\n/** Left-hand normal of the direction from a to b, or null when coincident. */\nexport function normal(a: PlanPoint, b: PlanPoint): PlanPoint | null {\n const d = direction(a, b);\n return d ? { x: -d.y, y: d.x } : null;\n}\n\n// ─── Point / segment ───────────────────────────────────────────────────────────\n\n/**\n * Distance from p to segment ab, plus the clamped parameter t of the closest point.\n * `t` is clamped to [0, 1], so the closest point is always on the segment.\n */\nexport function pointToSegment(\n p: PlanPoint,\n a: PlanPoint,\n b: PlanPoint,\n): { dist: number; t: number; point: PlanPoint } {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) return { dist: dist(p, a), t: 0, point: { x: a.x, y: a.y } };\n const raw = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;\n const t = raw < 0 ? 0 : raw > 1 ? 1 : raw;\n const point = { x: a.x + t * dx, y: a.y + t * dy };\n return { dist: dist(p, point), t, point };\n}\n\n/**\n * Exact projection of p onto segment ab, clamped to the segment.\n *\n * Used after a fuzzy hit tolerance has decided that p belongs to this segment: intent\n * is allowed to be approximate, the stored model never is.\n */\nexport function projectOnSegment(p: PlanPoint, a: PlanPoint, b: PlanPoint): PlanPoint {\n return pointToSegment(p, a, b).point;\n}\n\nexport type SegmentIntersectionKind =\n /** The segments cross strictly inside both. */\n | 'proper'\n /** They are parallel and do not touch. */\n | 'none'\n /** They lie on the same line and overlap over a non-zero length. */\n | 'collinearOverlap'\n /** They lie on the same line but do not overlap. */\n | 'collinearDisjoint'\n /** An endpoint of one lies on the other, or they share an endpoint. */\n | 'touch';\n\nexport interface SegmentIntersection {\n kind: SegmentIntersectionKind;\n /** Parameter along ab, for 'proper' and 'touch'. */\n t?: number;\n /** Parameter along cd, for 'proper' and 'touch'. */\n s?: number;\n point?: PlanPoint;\n}\n\n/**\n * Classifies how segments ab and cd meet.\n *\n * `eps` is a millimetre distance tolerance, not a parameter tolerance, so the result\n * does not change with segment length.\n */\nexport function segmentIntersection(\n a: PlanPoint,\n b: PlanPoint,\n c: PlanPoint,\n d: PlanPoint,\n eps = EPS_COINCIDENT,\n): SegmentIntersection {\n const abLen = dist(a, b);\n const cdLen = dist(c, d);\n if (abLen < 1e-9 || cdLen < 1e-9) return { kind: 'none' };\n\n const rx = b.x - a.x;\n const ry = b.y - a.y;\n const sx = d.x - c.x;\n const sy = d.y - c.y;\n const denom = rx * sy - ry * sx;\n\n // Perpendicular distance of c and d from line ab, used to tell parallel from collinear.\n const distC = Math.abs(cross(a, b, c)) / abLen;\n const distD = Math.abs(cross(a, b, d)) / abLen;\n\n if (Math.abs(denom) < 1e-12 || (distC < eps && distD < eps)) {\n if (distC >= eps || distD >= eps) return { kind: 'none' };\n // Collinear: compare parameters along ab.\n const len2 = rx * rx + ry * ry;\n const tc = ((c.x - a.x) * rx + (c.y - a.y) * ry) / len2;\n const td = ((d.x - a.x) * rx + (d.y - a.y) * ry) / len2;\n const lo = Math.min(tc, td);\n const hi = Math.max(tc, td);\n const epsT = eps / abLen;\n if (hi < epsT || lo > 1 - epsT) return { kind: 'collinearDisjoint' };\n if (Math.min(hi, 1) - Math.max(lo, 0) < epsT) return { kind: 'collinearDisjoint' };\n return { kind: 'collinearOverlap' };\n }\n\n const t = ((c.x - a.x) * sy - (c.y - a.y) * sx) / denom;\n const s = ((c.x - a.x) * ry - (c.y - a.y) * rx) / denom;\n const epsT = eps / abLen;\n const epsS = eps / cdLen;\n\n if (t < -epsT || t > 1 + epsT || s < -epsS || s > 1 + epsS) return { kind: 'none' };\n\n const point = { x: a.x + t * rx, y: a.y + t * ry };\n const atAbEnd = t <= epsT || t >= 1 - epsT;\n const atCdEnd = s <= epsS || s >= 1 - epsS;\n if (atAbEnd || atCdEnd) return { kind: 'touch', t, s, point };\n return { kind: 'proper', t, s, point };\n}\n\n// ─── Rings ─────────────────────────────────────────────────────────────────────\n\n/**\n * Shoelace area of a closed ring (first vertex not repeated).\n *\n * Positive means visually clockwise in SVG's y-down space. See `PlanFace.outer`.\n */\nexport function signedArea(ring: readonly PlanPoint[]): number {\n const n = ring.length;\n if (n < 3) return 0;\n let sum = 0;\n for (let i = 0, j = n - 1; i < n; j = i++) {\n sum += ring[j].x * ring[i].y - ring[i].x * ring[j].y;\n }\n return sum / 2;\n}\n\nexport function perimeter(ring: readonly PlanPoint[]): number {\n const n = ring.length;\n if (n < 2) return 0;\n let sum = 0;\n for (let i = 0, j = n - 1; i < n; j = i++) sum += dist(ring[j], ring[i]);\n return sum;\n}\n\n/**\n * Area-weighted centroid of a ring.\n *\n * Deliberately not the vertex mean: a dangling wall adds an out-and-back vertex pair\n * that skews the mean but contributes nothing to the area moment. Falls back to the\n * vertex mean only for a degenerate (zero-area) ring.\n */\nexport function areaCentroid(ring: readonly PlanPoint[]): PlanPoint {\n const n = ring.length;\n if (n === 0) return { x: 0, y: 0 };\n if (n < 3) {\n return {\n x: ring.reduce((s, p) => s + p.x, 0) / n,\n y: ring.reduce((s, p) => s + p.y, 0) / n,\n };\n }\n let a = 0;\n let cx = 0;\n let cy = 0;\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const f = ring[j].x * ring[i].y - ring[i].x * ring[j].y;\n a += f;\n cx += (ring[j].x + ring[i].x) * f;\n cy += (ring[j].y + ring[i].y) * f;\n }\n if (Math.abs(a) < 1e-9) {\n return {\n x: ring.reduce((s, p) => s + p.x, 0) / n,\n y: ring.reduce((s, p) => s + p.y, 0) / n,\n };\n }\n return { x: cx / (3 * a), y: cy / (3 * a) };\n}\n\n/** Ray-casting point-in-ring test. Points exactly on an edge are unspecified. */\nexport function pointInRing(p: PlanPoint, ring: readonly PlanPoint[]): boolean {\n let inside = false;\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {\n const xi = ring[i].x;\n const yi = ring[i].y;\n const xj = ring[j].x;\n const yj = ring[j].y;\n if (yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/** Inside `outer` and outside every hole. */\nexport function pointInRings(\n p: PlanPoint,\n outer: readonly PlanPoint[],\n holes: readonly (readonly PlanPoint[])[] = [],\n): boolean {\n if (!pointInRing(p, outer)) return false;\n for (const hole of holes) if (pointInRing(p, hole)) return false;\n return true;\n}\n\n/**\n * A point guaranteed to lie strictly inside the ring set, placed somewhere visually\n * central where possible.\n *\n * The area centroid is preferred, but it is not guaranteed to be inside a concave\n * polygon (an L-shaped room's centroid can land in the notch), so a scanline fallback\n * picks the widest interior span across several horizontal lines. The EPS_SPAN test on\n * that span is what stops an anchor landing inside the zero-width slit that a dangling\n * wall leaves in a face.\n */\nexport function representativePoint(\n outer: readonly PlanPoint[],\n holes: readonly (readonly PlanPoint[])[] = [],\n): PlanPoint {\n if (outer.length === 0) return { x: 0, y: 0 };\n\n const centre = areaCentroid(outer);\n if (pointInRings(centre, outer, holes)) return centre;\n\n let ymin = Infinity;\n let ymax = -Infinity;\n for (const p of outer) {\n if (p.y < ymin) ymin = p.y;\n if (p.y > ymax) ymax = p.y;\n }\n if (!Number.isFinite(ymin) || ymax - ymin < 1e-9) return centre;\n\n const rings: readonly (readonly PlanPoint[])[] = [outer, ...holes];\n let best: { point: PlanPoint; width: number } | null = null;\n\n const SAMPLES = 7;\n for (let k = 1; k <= SAMPLES; k++) {\n const y = ymin + ((ymax - ymin) * k) / (SAMPLES + 1);\n const xs: number[] = [];\n // One crossing list across ALL rings, so even-odd pairing yields interior spans\n // directly. Running the scanline per ring would not compose with holes.\n for (const ring of rings) {\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {\n const p = ring[j];\n const q = ring[i];\n if (p.y > y !== q.y > y) {\n xs.push(p.x + ((y - p.y) * (q.x - p.x)) / (q.y - p.y));\n }\n }\n }\n xs.sort((m, n) => m - n);\n for (let i = 0; i + 1 < xs.length; i += 2) {\n const width = xs[i + 1] - xs[i];\n if (width > EPS_SPAN && (!best || width > best.width)) {\n best = { point: { x: (xs[i] + xs[i + 1]) / 2, y }, width };\n }\n }\n }\n\n return best ? best.point : centre;\n}\n\n/**\n * Removes out-and-back spurs (`... P, Q, P ...`) from a ring, repeatedly until none\n * remain.\n *\n * A face containing a dangling wall is a valid fill but is not a simple polygon, which\n * breaks polygon offsetting and makes some triangulators emit zero-area triangles. Run\n * this before triangulating a floor slab; keep the raw ring for the 2D fill, where the\n * slit is harmless and `wallIds` alignment matters.\n */\nexport function stripSpurs(ring: readonly PlanPoint[]): PlanPoint[] {\n let out = ring.slice();\n let changed = true;\n while (changed && out.length > 3) {\n changed = false;\n const next: PlanPoint[] = [];\n const n = out.length;\n for (let i = 0; i < n; i++) {\n const prev = out[(i - 1 + n) % n];\n const nextPt = out[(i + 1) % n];\n // The middle of an out-and-back is the vertex whose neighbours coincide.\n if (dist(prev, nextPt) < EPS_COINCIDENT) {\n changed = true;\n continue;\n }\n next.push(out[i]);\n }\n if (changed) {\n // Drop the now-duplicated turning point left behind by each removed spur tip.\n out = next.filter((p, i) => dist(p, next[(i + 1) % next.length]) >= EPS_COINCIDENT);\n }\n }\n return out;\n}\n\nexport function rectToPoints(x: number, y: number, w: number, h: number): PlanPoint[] {\n return [\n { x, y },\n { x: x + w, y },\n { x: x + w, y: y + h },\n { x, y: y + h },\n ];\n}\n\nexport function boundsOf(points: readonly PlanPoint[]): {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n} | null {\n if (points.length === 0) return null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { minX, minY, maxX, maxY };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"floorPlan.geometry.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.geometry.ts"],"sourcesContent":["/**\n * Pure vector and polygon primitives. Nothing here knows about the plan model.\n *\n * All lengths are millimetres (see floorPlan.types.ts).\n */\n\nimport type { PlanPoint } from './floorPlan.types';\n\n// ─── Model-integrity epsilons ──────────────────────────────────────────────────\n// These are FIXED millimetre values describing when the model itself is degenerate.\n// They are a separate family from the user-intent tolerances in floorPlan.snap.ts,\n// which are screen pixels converted through the current zoom. Conflating the two\n// gives you either a model that accumulates 0.2mm walls, or snapping that stops\n// working when zoomed in.\n\n/** Shortest wall the graph will accept. Keeps zero-length walls out entirely. */\nexport const MIN_WALL_LENGTH = 10;\n/** Two points closer than this are the same point. */\nexport const EPS_COINCIDENT = 1;\n/** A ring with |area| below this encloses nothing (0.0001 m²). */\nexport const EPS_AREA = 100;\n/** Angular tolerance for \"these two walls are collinear\", in radians. */\nexport const EPS_ANGLE = 1e-4;\n/** Narrowest scanline span that counts as room interior rather than a slit. */\nexport const EPS_SPAN = 2;\n/** Narrowest opening worth keeping when a wall shortens under it. */\nexport const MIN_OPENING_WIDTH = 100;\n\n// ─── Vectors ───────────────────────────────────────────────────────────────────\n\nexport function dist(a: PlanPoint, b: PlanPoint): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n\nexport function distSq(a: PlanPoint, b: PlanPoint): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return dx * dx + dy * dy;\n}\n\n/** Cross product of ab and ac. Positive when c is clockwise of b in SVG's y-down space. */\nexport function cross(a: PlanPoint, b: PlanPoint, c: PlanPoint): number {\n return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);\n}\n\nexport function lerp(a: PlanPoint, b: PlanPoint, t: number): PlanPoint {\n return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };\n}\n\n/** Unit vector from a to b, or null when they are coincident. */\nexport function direction(a: PlanPoint, b: PlanPoint): PlanPoint | null {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len = Math.hypot(dx, dy);\n if (len < 1e-9) return null;\n return { x: dx / len, y: dy / len };\n}\n\n/** Left-hand normal of the direction from a to b, or null when coincident. */\nexport function normal(a: PlanPoint, b: PlanPoint): PlanPoint | null {\n const d = direction(a, b);\n return d ? { x: -d.y, y: d.x } : null;\n}\n\n// ─── Point / segment ───────────────────────────────────────────────────────────\n\n/**\n * Distance from p to segment ab, plus the clamped parameter t of the closest point.\n * `t` is clamped to [0, 1], so the closest point is always on the segment.\n */\nexport function pointToSegment(\n p: PlanPoint,\n a: PlanPoint,\n b: PlanPoint,\n): { dist: number; t: number; point: PlanPoint } {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) return { dist: dist(p, a), t: 0, point: { x: a.x, y: a.y } };\n const raw = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;\n const t = raw < 0 ? 0 : raw > 1 ? 1 : raw;\n const point = { x: a.x + t * dx, y: a.y + t * dy };\n return { dist: dist(p, point), t, point };\n}\n\n/**\n * Exact projection of p onto segment ab, clamped to the segment.\n *\n * Used after a fuzzy hit tolerance has decided that p belongs to this segment: intent\n * is allowed to be approximate, the stored model never is.\n */\nexport function projectOnSegment(p: PlanPoint, a: PlanPoint, b: PlanPoint): PlanPoint {\n return pointToSegment(p, a, b).point;\n}\n\nexport type SegmentIntersectionKind =\n /** The segments cross strictly inside both. */\n | 'proper'\n /** They are parallel and do not touch. */\n | 'none'\n /** They lie on the same line and overlap over a non-zero length. */\n | 'collinearOverlap'\n /** They lie on the same line but do not overlap. */\n | 'collinearDisjoint'\n /** An endpoint of one lies on the other, or they share an endpoint. */\n | 'touch';\n\nexport interface SegmentIntersection {\n kind: SegmentIntersectionKind;\n /** Parameter along ab, for 'proper' and 'touch'. */\n t?: number;\n /** Parameter along cd, for 'proper' and 'touch'. */\n s?: number;\n point?: PlanPoint;\n}\n\n/**\n * Classifies how segments ab and cd meet.\n *\n * `eps` is a millimetre distance tolerance, not a parameter tolerance, so the result\n * does not change with segment length.\n */\nexport function segmentIntersection(\n a: PlanPoint,\n b: PlanPoint,\n c: PlanPoint,\n d: PlanPoint,\n eps = EPS_COINCIDENT,\n): SegmentIntersection {\n const abLen = dist(a, b);\n const cdLen = dist(c, d);\n if (abLen < 1e-9 || cdLen < 1e-9) return { kind: 'none' };\n\n const rx = b.x - a.x;\n const ry = b.y - a.y;\n const sx = d.x - c.x;\n const sy = d.y - c.y;\n const denom = rx * sy - ry * sx;\n\n // Perpendicular distance of c and d from line ab, used to tell parallel from collinear.\n const distC = Math.abs(cross(a, b, c)) / abLen;\n const distD = Math.abs(cross(a, b, d)) / abLen;\n\n if (Math.abs(denom) < 1e-12 || (distC < eps && distD < eps)) {\n if (distC >= eps || distD >= eps) return { kind: 'none' };\n // Collinear: compare parameters along ab.\n const len2 = rx * rx + ry * ry;\n const tc = ((c.x - a.x) * rx + (c.y - a.y) * ry) / len2;\n const td = ((d.x - a.x) * rx + (d.y - a.y) * ry) / len2;\n const lo = Math.min(tc, td);\n const hi = Math.max(tc, td);\n const epsT = eps / abLen;\n if (hi < epsT || lo > 1 - epsT) return { kind: 'collinearDisjoint' };\n if (Math.min(hi, 1) - Math.max(lo, 0) < epsT) return { kind: 'collinearDisjoint' };\n return { kind: 'collinearOverlap' };\n }\n\n const t = ((c.x - a.x) * sy - (c.y - a.y) * sx) / denom;\n const s = ((c.x - a.x) * ry - (c.y - a.y) * rx) / denom;\n const epsT = eps / abLen;\n const epsS = eps / cdLen;\n\n if (t < -epsT || t > 1 + epsT || s < -epsS || s > 1 + epsS) return { kind: 'none' };\n\n const point = { x: a.x + t * rx, y: a.y + t * ry };\n const atAbEnd = t <= epsT || t >= 1 - epsT;\n const atCdEnd = s <= epsS || s >= 1 - epsS;\n if (atAbEnd || atCdEnd) return { kind: 'touch', t, s, point };\n return { kind: 'proper', t, s, point };\n}\n\n// ─── Rings ─────────────────────────────────────────────────────────────────────\n\n/**\n * Shoelace area of a closed ring (first vertex not repeated).\n *\n * Positive means visually clockwise in SVG's y-down space. See `PlanFace.outer`.\n */\nexport function signedArea(ring: readonly PlanPoint[]): number {\n const n = ring.length;\n if (n < 3) return 0;\n let sum = 0;\n for (let i = 0, j = n - 1; i < n; j = i++) {\n sum += ring[j].x * ring[i].y - ring[i].x * ring[j].y;\n }\n return sum / 2;\n}\n\nexport function perimeter(ring: readonly PlanPoint[]): number {\n const n = ring.length;\n if (n < 2) return 0;\n let sum = 0;\n for (let i = 0, j = n - 1; i < n; j = i++) sum += dist(ring[j], ring[i]);\n return sum;\n}\n\n/**\n * Area-weighted centroid of a ring.\n *\n * Deliberately not the vertex mean: a dangling wall adds an out-and-back vertex pair\n * that skews the mean but contributes nothing to the area moment. Falls back to the\n * vertex mean only for a degenerate (zero-area) ring.\n */\nexport function areaCentroid(ring: readonly PlanPoint[]): PlanPoint {\n const n = ring.length;\n if (n === 0) return { x: 0, y: 0 };\n if (n < 3) {\n return {\n x: ring.reduce((s, p) => s + p.x, 0) / n,\n y: ring.reduce((s, p) => s + p.y, 0) / n,\n };\n }\n let a = 0;\n let cx = 0;\n let cy = 0;\n for (let i = 0, j = n - 1; i < n; j = i++) {\n const f = ring[j].x * ring[i].y - ring[i].x * ring[j].y;\n a += f;\n cx += (ring[j].x + ring[i].x) * f;\n cy += (ring[j].y + ring[i].y) * f;\n }\n if (Math.abs(a) < 1e-9) {\n return {\n x: ring.reduce((s, p) => s + p.x, 0) / n,\n y: ring.reduce((s, p) => s + p.y, 0) / n,\n };\n }\n return { x: cx / (3 * a), y: cy / (3 * a) };\n}\n\n/** Ray-casting point-in-ring test. Points exactly on an edge are unspecified. */\nexport function pointInRing(p: PlanPoint, ring: readonly PlanPoint[]): boolean {\n let inside = false;\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {\n const xi = ring[i].x;\n const yi = ring[i].y;\n const xj = ring[j].x;\n const yj = ring[j].y;\n if (yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/** Inside `outer` and outside every hole. */\nexport function pointInRings(\n p: PlanPoint,\n outer: readonly PlanPoint[],\n holes: readonly (readonly PlanPoint[])[] = [],\n): boolean {\n if (!pointInRing(p, outer)) return false;\n for (const hole of holes) if (pointInRing(p, hole)) return false;\n return true;\n}\n\n/**\n * A point guaranteed to lie strictly inside the ring set, placed somewhere visually\n * central where possible.\n *\n * The area centroid is preferred, but it is not guaranteed to be inside a concave\n * polygon (an L-shaped room's centroid can land in the notch), so a scanline fallback\n * picks the widest interior span across several horizontal lines. The EPS_SPAN test on\n * that span is what stops an anchor landing inside the zero-width slit that a dangling\n * wall leaves in a face.\n */\nexport function representativePoint(\n outer: readonly PlanPoint[],\n holes: readonly (readonly PlanPoint[])[] = [],\n): PlanPoint {\n if (outer.length === 0) return { x: 0, y: 0 };\n\n const centre = areaCentroid(outer);\n if (pointInRings(centre, outer, holes)) return centre;\n\n let ymin = Infinity;\n let ymax = -Infinity;\n for (const p of outer) {\n if (p.y < ymin) ymin = p.y;\n if (p.y > ymax) ymax = p.y;\n }\n if (!Number.isFinite(ymin) || ymax - ymin < 1e-9) return centre;\n\n const rings: readonly (readonly PlanPoint[])[] = [outer, ...holes];\n let best: { point: PlanPoint; width: number } | null = null;\n\n const SAMPLES = 7;\n for (let k = 1; k <= SAMPLES; k++) {\n const y = ymin + ((ymax - ymin) * k) / (SAMPLES + 1);\n const xs: number[] = [];\n // One crossing list across ALL rings, so even-odd pairing yields interior spans\n // directly. Running the scanline per ring would not compose with holes.\n for (const ring of rings) {\n for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {\n const p = ring[j];\n const q = ring[i];\n if (p.y > y !== q.y > y) {\n xs.push(p.x + ((y - p.y) * (q.x - p.x)) / (q.y - p.y));\n }\n }\n }\n xs.sort((m, n) => m - n);\n for (let i = 0; i + 1 < xs.length; i += 2) {\n const width = xs[i + 1] - xs[i];\n if (width > EPS_SPAN && (!best || width > best.width)) {\n best = { point: { x: (xs[i] + xs[i + 1]) / 2, y }, width };\n }\n }\n }\n\n return best ? best.point : centre;\n}\n\n/**\n * Removes out-and-back spurs (`... P, Q, P ...`) from a ring, repeatedly until none\n * remain.\n *\n * A face containing a dangling wall is a valid fill but is not a simple polygon, which\n * breaks polygon offsetting and makes some triangulators emit zero-area triangles. Run\n * this before triangulating a floor slab; keep the raw ring for the 2D fill, where the\n * slit is harmless and `wallIds` alignment matters.\n */\nexport function stripSpurs(ring: readonly PlanPoint[]): PlanPoint[] {\n let out = ring.slice();\n let changed = true;\n while (changed && out.length > 3) {\n changed = false;\n const next: PlanPoint[] = [];\n const n = out.length;\n for (let i = 0; i < n; i++) {\n const prev = out[(i - 1 + n) % n];\n const nextPt = out[(i + 1) % n];\n // The middle of an out-and-back is the vertex whose neighbours coincide.\n if (dist(prev, nextPt) < EPS_COINCIDENT) {\n changed = true;\n continue;\n }\n next.push(out[i]);\n }\n if (changed) {\n // Drop the now-duplicated turning point left behind by each removed spur tip.\n out = next.filter((p, i) => dist(p, next[(i + 1) % next.length]) >= EPS_COINCIDENT);\n }\n }\n return out;\n}\n\nexport function rectToPoints(x: number, y: number, w: number, h: number): PlanPoint[] {\n return [\n { x, y },\n { x: x + w, y },\n { x: x + w, y: y + h },\n { x, y: y + h },\n ];\n}\n\nexport function boundsOf(points: readonly PlanPoint[]): {\n minX: number;\n minY: number;\n maxX: number;\n maxY: number;\n} | null {\n if (points.length === 0) return null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of points) {\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x > maxX) maxX = p.x;\n if (p.y > maxY) maxY = p.y;\n }\n return { minX, minY, maxX, maxY };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{PlanIssueKind as e,WallType as t}from"./floorPlan.types.mjs";import{cross as n,dist as r,pointToSegment as i,projectOnSegment as a,segmentIntersection as o}from"./floorPlan.geometry.mjs";var s=0;function c(e){return s+=1,`${e}_${typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID().slice(0,8):Math.random().toString(36).slice(2,10)}${s.toString(36)}`}function l(e){return{...e,nodes:{...e.nodes},walls:{...e.walls},openings:{...e.openings},rooms:{...e.rooms}}}function u(e,t,n={}){return{kind:e,message:t,...n}}function d(e,t){let n=e.nodes[t.a],i=e.nodes[t.b];return!n||!i?0:r(n,i)}function f(e,t){return Object.values(e.walls).filter(e=>e.a===t||e.b===t)}function p(e,t,n){for(let r of Object.values(e.walls))if(r.a===t&&r.b===n||r.a===n&&r.b===t)return r;return null}var m=250;function h(e,t){return`${Math.round(e/m)}|${Math.round(t/m)}`}function g(e){let t=new Map;for(let n of Object.values(e.nodes)){let e=h(n.x,n.y),r=t.get(e);r?r.push(n):t.set(e,[n])}return t}function _(e,t,n){let i=g(e),a=Math.round(t.x/m),o=Math.round(t.y/m),s=null,c=n,l=Math.max(1,Math.ceil(n/m));for(let e=-l;e<=l;e++)for(let n=-l;n<=l;n++)for(let l of i.get(`${a+e}|${o+n}`)??[]){let e=r(t,l);e<=c&&(s=l,c=e)}return s}function v(e,t,n,r){let a=null;for(let o of Object.values(e.walls)){if(r?.has(o.id))continue;let s=e.nodes[o.a],c=e.nodes[o.b];if(!s||!c)continue;let l=i(t,s,c);l.dist<=n&&(!a||l.dist<a.dist)&&(a={wall:o,t:l.t,point:l.point,dist:l.dist})}return a}function y(t,n,i){let o=t.walls[n];if(!o)return{floor:t,result:{nodeId:``,wallIds:null,droppedOpeningIds:[]},issues:[]};let s=t.nodes[o.a],d=t.nodes[o.b];if(!s||!d)return{floor:t,result:{nodeId:``,wallIds:null,droppedOpeningIds:[]},issues:[]};let f=r(s,d),p=typeof i==`number`?{x:s.x+(d.x-s.x)*i,y:s.y+(d.y-s.y)*i}:i,m=a(p,s,d),h=r(s,m);if(h<10)return{floor:t,result:{nodeId:o.a,wallIds:null,droppedOpeningIds:[]},issues:[]};if(f-h<10)return{floor:t,result:{nodeId:o.b,wallIds:null,droppedOpeningIds:[]},issues:[]};let g=l(t),_=c(`n`);g.nodes[_]={id:_,x:m.x,y:m.y};let v=c(`w`),y=c(`w`),b={thickness:o.thickness,type:o.type,height:o.height,baseHeight:o.baseHeight};g.walls[v]={...b,id:v,a:o.a,b:_},g.walls[y]={...b,id:y,a:_,b:o.b},delete g.walls[n];let x=[],S=[];for(let r of Object.values(t.openings)){if(r.wallId!==n)continue;let t=r.offset<=h,i=t?v:y,a=t?h:f-h,o=t?r.offset:r.offset-h,s=Math.min(r.width,a-2,o*2,(a-o)*2);if(s<100){delete g.openings[r.id],x.push(r.id),S.push(u(e.OpeningDropped,`An opening was removed: the wall it sat on became too short for it.`,{openingIds:[r.id],wallIds:[n]}));continue}g.openings[r.id]={...r,wallId:i,offset:o,width:s}}return{floor:g,result:{nodeId:_,wallIds:[v,y],droppedOpeningIds:x},issues:S}}function b(e,t,n){let r=_(e,t,n);if(r)return{floor:e,result:{nodeId:r.id,createdNode:!1,splitWallId:null},issues:[]};let i=v(e,t,n);if(i){let t=y(e,i.wall.id,i.point);if(t.result.nodeId)return{floor:t.floor,result:{nodeId:t.result.nodeId,createdNode:t.result.wallIds!==null,splitWallId:t.result.wallIds?i.wall.id:null},issues:t.issues}}let a=l(e),o=c(`n`);return a.nodes[o]={id:o,x:t.x,y:t.y},{floor:a,result:{nodeId:o,createdNode:!0,splitWallId:null},issues:[]}}var x={thickness:200,type:t.Interior};function S(t,n,a,s=x,l=1){let d=[];if(r(n,a)<10)return{floor:t,result:{wallIds:[],nodeIds:[]},issues:d};let f=b(t,n,l),m=f.floor;d.push(...f.issues);let h=b(m,a,l);m=h.floor,d.push(...h.issues);let g=f.result.nodeId,_=h.result.nodeId;if(g===_)return{floor:t,result:{wallIds:[],nodeIds:[]},issues:d};let v=m.nodes[g],S=m.nodes[_],C=r(v,S);if(C<10)return{floor:t,result:{wallIds:[],nodeIds:[]},issues:d};let w=[{t:0,nodeId:g},{t:1,nodeId:_}],T=new Map,E=[],D=e=>i(e,v,S).t;for(let e of Object.values(m.walls)){let t=m.nodes[e.a],n=m.nodes[e.b];if(!t||!n)continue;let r=o(v,S,t,n,l);if(r.kind===`collinearOverlap`){let e=D(t),r=D(n);E.push([Math.min(e,r),Math.max(e,r)]);for(let[i,a]of[[t,e],[n,r]])a*C>10&&(1-a)*C>10&&w.push({t:a,nodeId:i.id});continue}if(r.kind===`proper`&&r.t!==void 0&&r.s!==void 0){let t=T.get(e.id);t?t.push(r.s):T.set(e.id,[r.s]),w.push({t:r.t,nodeId:null,pending:{wallId:e.id,s:r.s}});continue}if(r.kind===`touch`&&r.t!==void 0&&r.s!==void 0){let e=r.s<=.5?t:n,a=D(e);i(e,v,S).dist<=l&&a*C>10&&(1-a)*C>10&&w.push({t:a,nodeId:e.id})}}for(let e of Object.values(m.nodes)){if(e.id===g||e.id===_)continue;let t=i(e,v,S);t.dist>l||t.t*C<=10||(1-t.t)*C<=10||w.push({t:t.t,nodeId:e.id})}for(let[e,n]of T){let r=[...n].sort((e,t)=>t-e),i=e,a=new Set(r);for(let n of r){let r=m.walls[i];if(!r)break;let o=m.nodes[r.a],s=m.nodes[r.b];if(!o||!s)break;let c=t.walls[e],l=m.nodes[c?.a??r.a]??o,u=m.nodes[c?.b??r.b]??s,f={x:l.x+(u.x-l.x)*n,y:l.y+(u.y-l.y)*n},p=y(m,i,f);m=p.floor,d.push(...p.issues),a.delete(n);for(let t of w)t.pending&&t.pending.wallId===e&&t.pending.s===n&&(t.nodeId=p.result.nodeId,t.pending=void 0);if(p.result.wallIds){let[e,t]=p.result.wallIds,r=Math.max(...a,-1);i=r>=0&&r>n?t:e}}}let O=w.filter(e=>!!e.nodeId);O.sort((e,t)=>e.t-t.t);let k=[];for(let e of O){let t=k[k.length-1];if(!t){k.push(e);continue}if(t.nodeId!==e.nodeId){if((e.t-t.t)*C<10){e.t>=1-1e-9&&(k[k.length-1]=e);continue}k.push(e)}}let A=[];for(let e=0;e+1<k.length;e++){let t=k[e],n=k[e+1],i=(t.t+n.t)/2;if(E.some(([e,t])=>i>e+1e-9&&i<t-1e-9)||p(m,t.nodeId,n.nodeId))continue;let a=m.nodes[t.nodeId],o=m.nodes[n.nodeId];if(!a||!o||r(a,o)<10)continue;let l=c(`w`);m={...m,walls:{...m.walls,[l]:{...s,id:l,a:t.nodeId,b:n.nodeId}}},A.push(l)}return A.length===0&&E.length>0&&d.push(u(e.DuplicateWall,`A wall already covers that span, so nothing was added.`)),{floor:m,result:{wallIds:A,nodeIds:k.map(e=>e.nodeId)},issues:d}}function C(e,t,n,r=x,i=1){let a=Math.min(t.x,n.x),o=Math.max(t.x,n.x),s=Math.min(t.y,n.y),c=Math.max(t.y,n.y);if(o-a<10||c-s<10)return{floor:e,result:{wallIds:[]},issues:[]};let l=[{x:a,y:s},{x:o,y:s},{x:o,y:c},{x:a,y:c}],u=e,d=[],f=[];for(let e=0;e<4;e++){let t=S(u,l[e],l[(e+1)%4],r,i);u=t.floor,d.push(...t.result.wallIds),f.push(...t.issues)}return{floor:u,result:{wallIds:d},issues:f}}function w(t,n,r){if(n===r||!t.nodes[n]||!t.nodes[r])return{floor:t,result:{removedWallIds:[]},issues:[]};let i=l(t),a=[],o=[];for(let e of Object.values(i.walls))e.a===r&&(i.walls[e.id]={...i.walls[e.id],a:n}),e.b===r&&(i.walls[e.id]={...i.walls[e.id],b:n});for(let e of Object.values(i.walls))if(e.a===e.b){delete i.walls[e.id],a.push(e.id);for(let t of Object.values(i.openings))t.wallId===e.id&&delete i.openings[t.id]}let s=new Map;for(let t of Object.values(i.walls)){let n=t.a<t.b?`${t.a}|${t.b}`:`${t.b}|${t.a}`,r=s.get(n);if(!r){s.set(n,t);continue}let c=t.thickness>=r.thickness?t:r,l=c===t?r:t;for(let e of Object.values(i.openings))e.wallId===l.id&&(i.openings[e.id]={...e,wallId:c.id});delete i.walls[l.id],a.push(l.id),s.set(n,c),o.push(u(e.DuplicateWall,`Two walls became the same wall and were merged.`,{wallIds:[c.id,l.id]}))}return delete i.nodes[r],{floor:i,result:{removedWallIds:a},issues:o}}function T(t,i,a={}){let{force:o=!1}=a,s=t.nodes[i];if(!s)return{floor:t,result:null,issues:[]};let p=f(t,i);if(p.length!==2)return{floor:t,result:null,issues:[]};let[m,h]=p,g=m.thickness===h.thickness&&m.type===h.type&&m.height===h.height&&m.baseHeight===h.baseHeight;if(!g&&!o)return{floor:t,result:null,issues:[]};let _=m.a===i?m.b:m.a,v=h.a===i?h.b:h.a;if(_===v)return{floor:t,result:null,issues:[]};let y=t.nodes[_],b=t.nodes[v];if(!y||!b)return{floor:t,result:null,issues:[]};let x=r(y,b);if(x<10||!o&&Math.abs(n(y,b,s))/x>Math.max(1,x*1e-4))return{floor:t,result:null,issues:[]};let S=!g&&m.thickness<h.thickness?h:m,C=l(t),w=c(`w`);C.walls[w]={id:w,a:_,b:v,thickness:S.thickness,type:S.type,height:S.height,baseHeight:S.baseHeight};let T=r(y,s),E=r(s,b),D=T+E>0?x/(T+E):1,O=[];for(let n of Object.values(t.openings)){if(n.wallId!==m.id&&n.wallId!==h.id)continue;let r=n.wallId===m.id,a=r?m:h,o=a.a===i,s=d(t,a),c=o?n.offset:s-n.offset,l=(r?T-c:T+c)*D,f=Math.min(n.width*D,x-2);if(f<100){O.push(u(e.OpeningDropped,`An opening was removed: the wall it sat on became too short for it.`,{openingIds:[n.id],wallIds:[a.id]})),delete C.openings[n.id];continue}C.openings[n.id]={...n,wallId:w,width:f,offset:Math.min(Math.max(l,f/2),x-f/2)}}return delete C.walls[m.id],delete C.walls[h.id],delete C.nodes[i],{floor:C,result:{wallId:w},issues:O}}function E(e,t,n){let r=e.walls[t];if(!r||r.a===r.b||Math.hypot(n.x,n.y)<10)return{floor:e,result:null,issues:[]};let i=[r.a,r.b],a=[r.a,r.b],o=[null,null],s=[],c=[],u=e;i.forEach((i,s)=>{let c=e.nodes[i];if(!c)return;let d={x:c.x+n.x,y:c.y+n.y},p=f(e,i).filter(e=>e.id!==t);if(p.length===0){let e=l(u);e.nodes[i]={...e.nodes[i],x:d.x,y:d.y},u=e;return}let m=b(u,d,1);u=m.floor,a[s]=m.result.nodeId,o[s]=p.length===1?p[0]:r});let d=l(u);d.walls[t]={...d.walls[t],a:a[0],b:a[1]},u=d,i.forEach((e,t)=>{let n=o[t],r=u.nodes[e],i=u.nodes[a[t]];if(!n||!r||!i)return;let l=S(u,r,i,{thickness:n.thickness,type:n.type,height:n.height,baseHeight:n.baseHeight});u=l.floor,s.push(...l.result.wallIds),c.push(...l.issues)});let p=[];return i.forEach((e,t)=>{if(a[t]===e)return;let n=T(u,e);n.result&&(u=n.floor,p.push(e),c.push(...n.issues))}),{floor:u,result:{nodeIds:a,connectorIds:s,dissolvedNodeIds:p},issues:c}}function D(e,t=10){let n=e,i=[],a=[];for(let o=Object.keys(e.walls).length;o>0;o--){let e=Object.values(n.walls).find(e=>{if(e.a===e.b)return!1;let i=n.nodes[e.a],a=n.nodes[e.b];return i&&a&&r(i,a)<t});if(!e)break;let o=f(n,e.b).length>f(n,e.a).length?e.b:e.a,s=w(n,o,o===e.a?e.b:e.a);if(s.floor===n)break;n=s.floor,i.push(e.id),a.push(...s.issues)}return{floor:n,result:{weldedWallIds:i},issues:a}}function O(e,t,n={}){let{pruneOrphanNodes:r=!0,dissolveCollinear:i=!0}=n,a=e.walls[t];if(!a)return{floor:e,result:{removedNodeIds:[],dissolvedWallIds:[]},issues:[]};let o=l(e);delete o.walls[t];for(let e of Object.values(o.openings))e.wallId===t&&delete o.openings[e.id];let s=[],c=[],u=[];for(let e of[a.a,a.b]){let t=f(o,e).length;if(t===0&&r)delete o.nodes[e],s.push(e);else if(t===2&&i){let t=T(o,e);t.result&&(o=t.floor,c.push(t.result.wallId),s.push(e),u.push(...t.issues))}}return{floor:o,result:{removedNodeIds:s,dissolvedWallIds:c},issues:u}}function k(e,t,n){let r=e.nodes[t];if(!r)return{floor:e,result:void 0,issues:[]};let i=l(e);return i.nodes[t]={...r,x:n.x,y:n.y},{floor:i,result:void 0,issues:[]}}function A(e,t,n){let r=l(e);for(let i of Object.values(e.nodes))r.nodes[i.id]={...i,x:i.x+t,y:i.y+n};for(let i of Object.values(e.rooms))r.rooms[i.id]={...i,anchor:{x:i.anchor.x+t,y:i.anchor.y+n}};return r}function j(e,t){let n=l(e);for(let r of Object.values(e.nodes))n.nodes[r.id]={...r,x:r.x*t,y:r.y*t};for(let r of Object.values(e.walls))n.walls[r.id]={...r,thickness:r.thickness*t,height:r.height===void 0?void 0:r.height*t,baseHeight:r.baseHeight===void 0?void 0:r.baseHeight*t};for(let r of Object.values(e.openings))n.openings[r.id]={...r,offset:r.offset*t,width:r.width*t,sill:r.sill*t,head:r.head*t};for(let r of Object.values(e.rooms))n.rooms[r.id]={...r,anchor:{x:r.anchor.x*t,y:r.anchor.y*t},area:r.area*t*t};return n}function M(t,n){let r=t.walls[n.wallId];if(!r)return{floor:t,result:{openingId:null},issues:[]};let i=d(t,r),a=Math.min(n.width,i-2);if(a<100)return{floor:t,result:{openingId:null},issues:[u(e.OpeningDropped,`That wall is too short for an opening.`,{wallIds:[r.id]})]};let o=Math.min(Math.max(n.offset,a/2),i-a/2),s=l(t),f=c(`o`);return s.openings[f]={...n,id:f,offset:o,width:a},{floor:s,result:{openingId:f},issues:[]}}function N(e,t,n){let r=e.openings[t];if(!r)return{floor:e,result:void 0,issues:[]};let i=e.walls[r.wallId];if(!i)return{floor:e,result:void 0,issues:[]};let a=d(e,i),o={...r,...n},s=Math.min(Math.max(o.width,100),Math.max(a-2,100)),c=Math.min(Math.max(o.offset,s/2),Math.max(a-s/2,s/2)),u=l(e);return u.openings[t]={...o,width:s,offset:c},{floor:u,result:void 0,issues:[]}}function P(e,t){if(!e.openings[t])return{floor:e,result:void 0,issues:[]};let n=l(e);return delete n.openings[t],{floor:n,result:void 0,issues:[]}}function F(t){let n=[],a=Object.values(t.walls);for(let i of a){let a=t.nodes[i.a],o=t.nodes[i.b];if(i.a===i.b){n.push(u(e.SelfLoopWall,`A wall starts and ends at the same node.`,{wallIds:[i.id]}));continue}if(!a||!o){n.push(u(e.ZeroLengthWall,`A wall references a missing node.`,{wallIds:[i.id]}));continue}r(a,o)<10&&n.push(u(e.ZeroLengthWall,`A wall is shorter than the minimum length.`,{wallIds:[i.id]}))}let s=new Map;for(let t of a){let r=t.a<t.b?`${t.a}|${t.b}`:`${t.b}|${t.a}`,i=s.get(r);i?n.push(u(e.DuplicateWall,`Two walls connect the same pair of nodes.`,{wallIds:[i,t.id]})):s.set(r,t.id)}let c=Object.values(t.nodes);for(let t=0;t<c.length;t++)for(let i=t+1;i<c.length;i++)r(c[t],c[i])<1&&n.push(u(e.CoincidentNodes,`Two nodes occupy the same position.`,{nodeIds:[c[t].id,c[i].id]}));for(let r=0;r<a.length;r++)for(let i=r+1;i<a.length;i++){let s=a[r],c=a[i],l=t.nodes[s.a],d=t.nodes[s.b],f=t.nodes[c.a],p=t.nodes[c.b];if(!l||!d||!f||!p)continue;let m=o(l,d,f,p);m.kind===`proper`?n.push(u(e.UnsplitCrossing,`Two walls cross with no node at the intersection.`,{wallIds:[s.id,c.id]})):m.kind===`collinearOverlap`&&n.push(u(e.OverlappingWalls,`Two walls overlap along the same line.`,{wallIds:[s.id,c.id]}))}for(let r of a){let a=t.nodes[r.a],o=t.nodes[r.b];if(a&&o)for(let t of c){if(t.id===r.a||t.id===r.b)continue;let s=i(t,a,o);s.dist<1&&s.t>0&&s.t<1&&n.push(u(e.UnsplitNodeOnWall,`A node sits on a wall that was never split there.`,{wallIds:[r.id],nodeIds:[t.id]}))}}for(let r of Object.values(t.openings))t.walls[r.wallId]||n.push(u(e.DanglingOpening,`An opening references a wall that no longer exists.`,{openingIds:[r.id]}));let l=new Set;for(let e of a)l.add(e.a),l.add(e.b);for(let t of c)l.has(t.id)||n.push(u(e.OrphanNode,`A node has no walls.`,{nodeIds:[t.id]}));return n}function I(t){let n=[],i=D(t),a=l(i.floor);for(let t of i.result.weldedWallIds)n.push(u(e.ZeroLengthWall,`Welded the two ends of a wall with no length.`,{wallIds:[t]}));for(let t of Object.values(a.walls)){let i=a.nodes[t.a],o=a.nodes[t.b];(t.a===t.b||!i||!o||r(i,o)<10)&&(delete a.walls[t.id],n.push(u(e.ZeroLengthWall,`Removed a degenerate wall.`,{wallIds:[t.id]})))}let o=new Map;for(let t of Object.values(a.walls)){let r=t.a<t.b?`${t.a}|${t.b}`:`${t.b}|${t.a}`,i=o.get(r);if(!i){o.set(r,t);continue}let s=t.thickness>=i.thickness?t:i,c=s===t?i:t;for(let e of Object.values(a.openings))e.wallId===c.id&&(a.openings[e.id]={...e,wallId:s.id});delete a.walls[c.id],o.set(r,s),n.push(u(e.DuplicateWall,`Removed a duplicate wall.`,{wallIds:[c.id]}))}for(let t of Object.values(a.openings))a.walls[t.wallId]||(delete a.openings[t.id],n.push(u(e.DanglingOpening,`Removed an opening with no wall.`,{openingIds:[t.id]})));let s=new Set;for(let e of Object.values(a.walls))s.add(e.a),s.add(e.b);for(let t of Object.values(a.nodes))s.has(t.id)||(delete a.nodes[t.id],n.push(u(e.OrphanNode,`Removed a node with no walls.`,{nodeIds:[t.id]})));return{floor:a,result:n,issues:n}}export{x as DEFAULT_WALL_ATTRS,M as addOpening,C as addRect,S as addWall,I as cleanupPlan,E as detachWall,T as dissolveNode,_ as findNodeNear,p as findWallBetween,v as findWallNear,w as mergeNodes,k as moveNode,c as newId,P as removeOpening,O as removeWall,b as resolveNodeAt,j as scalePlan,y as splitWall,A as transformPlan,N as updateOpening,F as validatePlan,d as wallLength,f as wallsAtNode,D as weldShortWalls};
1
+ "use client";import{PlanIssueKind as e,WallType as t}from"./floorPlan.types.mjs";import{cross as n,dist as r,pointToSegment as i,projectOnSegment as a,segmentIntersection as o}from"./floorPlan.geometry.mjs";var s=0;function c(e){return s+=1,`${e}_${typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID().slice(0,8):Math.random().toString(36).slice(2,10)}${s.toString(36)}`}function l(e){return{...e,nodes:{...e.nodes},walls:{...e.walls},openings:{...e.openings},rooms:{...e.rooms}}}function u(e,t,n={}){return{kind:e,message:t,...n}}function d(e,t){let n=e.nodes[t.a],i=e.nodes[t.b];return!n||!i?0:r(n,i)}function f(e,t){return Object.values(e.walls).filter(e=>e.a===t||e.b===t)}function p(e,t,n){for(let r of Object.values(e.walls))if(r.a===t&&r.b===n||r.a===n&&r.b===t)return r;return null}var m=250;function h(e,t){return`${Math.round(e/m)}|${Math.round(t/m)}`}function g(e){let t=new Map;for(let n of Object.values(e.nodes)){let e=h(n.x,n.y),r=t.get(e);r?r.push(n):t.set(e,[n])}return t}function _(e,t,n){let i=g(e),a=Math.round(t.x/m),o=Math.round(t.y/m),s=null,c=n,l=Math.max(1,Math.ceil(n/m));for(let e=-l;e<=l;e++)for(let n=-l;n<=l;n++)for(let l of i.get(`${a+e}|${o+n}`)??[]){let e=r(t,l);e<=c&&(s=l,c=e)}return s}function v(e,t,n,r){let a=null;for(let o of Object.values(e.walls)){if(r?.has(o.id))continue;let s=e.nodes[o.a],c=e.nodes[o.b];if(!s||!c)continue;let l=i(t,s,c);l.dist<=n&&(!a||l.dist<a.dist)&&(a={wall:o,t:l.t,point:l.point,dist:l.dist})}return a}function y(t,n,i){let o=t.walls[n];if(!o)return{floor:t,result:{nodeId:``,wallIds:null,droppedOpeningIds:[]},issues:[]};let s=t.nodes[o.a],d=t.nodes[o.b];if(!s||!d)return{floor:t,result:{nodeId:``,wallIds:null,droppedOpeningIds:[]},issues:[]};let f=r(s,d),p=typeof i==`number`?{x:s.x+(d.x-s.x)*i,y:s.y+(d.y-s.y)*i}:i,m=a(p,s,d),h=r(s,m);if(h<10)return{floor:t,result:{nodeId:o.a,wallIds:null,droppedOpeningIds:[]},issues:[]};if(f-h<10)return{floor:t,result:{nodeId:o.b,wallIds:null,droppedOpeningIds:[]},issues:[]};let g=l(t),_=c(`n`);g.nodes[_]={id:_,x:m.x,y:m.y};let v=c(`w`),y=c(`w`),b={thickness:o.thickness,type:o.type,height:o.height,baseHeight:o.baseHeight};g.walls[v]={...b,id:v,a:o.a,b:_},g.walls[y]={...b,id:y,a:_,b:o.b},delete g.walls[n];let x=[],S=[];for(let r of Object.values(t.openings)){if(r.wallId!==n)continue;let t=r.offset<=h,i=t?v:y,a=t?h:f-h,o=t?r.offset:r.offset-h,s=Math.min(r.width,a-2,o*2,(a-o)*2);if(s<100){delete g.openings[r.id],x.push(r.id),S.push(u(e.OpeningDropped,`An opening was removed: the wall it sat on became too short for it.`,{openingIds:[r.id],wallIds:[n]}));continue}g.openings[r.id]={...r,wallId:i,offset:o,width:s}}return{floor:g,result:{nodeId:_,wallIds:[v,y],droppedOpeningIds:x},issues:S}}function b(e,t,n){let r=_(e,t,n);if(r)return{floor:e,result:{nodeId:r.id,createdNode:!1,splitWallId:null},issues:[]};let i=v(e,t,n);if(i){let t=y(e,i.wall.id,i.point);if(t.result.nodeId)return{floor:t.floor,result:{nodeId:t.result.nodeId,createdNode:t.result.wallIds!==null,splitWallId:t.result.wallIds?i.wall.id:null},issues:t.issues}}let a=l(e),o=c(`n`);return a.nodes[o]={id:o,x:t.x,y:t.y},{floor:a,result:{nodeId:o,createdNode:!0,splitWallId:null},issues:[]}}var x={thickness:200,type:t.Interior};function S(t,n,a,s=x,l=1){let d=[];if(r(n,a)<10)return{floor:t,result:{wallIds:[],nodeIds:[]},issues:d};let f=b(t,n,l),m=f.floor;d.push(...f.issues);let h=b(m,a,l);m=h.floor,d.push(...h.issues);let g=f.result.nodeId,_=h.result.nodeId;if(g===_)return{floor:t,result:{wallIds:[],nodeIds:[]},issues:d};let v=m.nodes[g],S=m.nodes[_],C=r(v,S);if(C<10)return{floor:t,result:{wallIds:[],nodeIds:[]},issues:d};let w=[{t:0,nodeId:g},{t:1,nodeId:_}],T=new Map,E=[],D=e=>i(e,v,S).t;for(let e of Object.values(m.walls)){let t=m.nodes[e.a],n=m.nodes[e.b];if(!t||!n)continue;let r=o(v,S,t,n,l);if(r.kind===`collinearOverlap`){let e=D(t),r=D(n);E.push([Math.min(e,r),Math.max(e,r)]);for(let[i,a]of[[t,e],[n,r]])a*C>10&&(1-a)*C>10&&w.push({t:a,nodeId:i.id});continue}if(r.kind===`proper`&&r.t!==void 0&&r.s!==void 0){let t=T.get(e.id);t?t.push(r.s):T.set(e.id,[r.s]),w.push({t:r.t,nodeId:null,pending:{wallId:e.id,s:r.s}});continue}if(r.kind===`touch`&&r.t!==void 0&&r.s!==void 0){let e=r.s<=.5?t:n,a=D(e);i(e,v,S).dist<=l&&a*C>10&&(1-a)*C>10&&w.push({t:a,nodeId:e.id})}}for(let e of Object.values(m.nodes)){if(e.id===g||e.id===_)continue;let t=i(e,v,S);t.dist>l||t.t*C<=10||(1-t.t)*C<=10||w.push({t:t.t,nodeId:e.id})}for(let[e,n]of T){let r=[...n].sort((e,t)=>t-e),i=e,a=new Set(r);for(let n of r){let r=m.walls[i];if(!r)break;let o=m.nodes[r.a],s=m.nodes[r.b];if(!o||!s)break;let c=t.walls[e],l=m.nodes[c?.a??r.a]??o,u=m.nodes[c?.b??r.b]??s,f={x:l.x+(u.x-l.x)*n,y:l.y+(u.y-l.y)*n},p=y(m,i,f);m=p.floor,d.push(...p.issues),a.delete(n);for(let t of w)t.pending&&t.pending.wallId===e&&t.pending.s===n&&(t.nodeId=p.result.nodeId,t.pending=void 0);if(p.result.wallIds){let[e,t]=p.result.wallIds,r=Math.max(...a,-1);i=r>=0&&r>n?t:e}}}let O=w.filter(e=>!!e.nodeId);O.sort((e,t)=>e.t-t.t);let k=[];for(let e of O){let t=k[k.length-1];if(!t){k.push(e);continue}if(t.nodeId!==e.nodeId){if((e.t-t.t)*C<10){e.t>=1-1e-9&&(k[k.length-1]=e);continue}k.push(e)}}let A=[];for(let e=0;e+1<k.length;e++){let t=k[e],n=k[e+1],i=(t.t+n.t)/2;if(E.some(([e,t])=>i>e+1e-9&&i<t-1e-9)||p(m,t.nodeId,n.nodeId))continue;let a=m.nodes[t.nodeId],o=m.nodes[n.nodeId];if(!a||!o||r(a,o)<10)continue;let l=c(`w`);m={...m,walls:{...m.walls,[l]:{...s,id:l,a:t.nodeId,b:n.nodeId}}},A.push(l)}return A.length===0&&E.length>0&&d.push(u(e.DuplicateWall,`A wall already covers that span, so nothing was added.`)),{floor:m,result:{wallIds:A,nodeIds:k.map(e=>e.nodeId)},issues:d}}function C(e,t,n,r=x,i=1){let a=Math.min(t.x,n.x),o=Math.max(t.x,n.x),s=Math.min(t.y,n.y),c=Math.max(t.y,n.y);if(o-a<10||c-s<10)return{floor:e,result:{wallIds:[]},issues:[]};let l=[{x:a,y:s},{x:o,y:s},{x:o,y:c},{x:a,y:c}],u=e,d=[],f=[];for(let e=0;e<4;e++){let t=S(u,l[e],l[(e+1)%4],r,i);u=t.floor,d.push(...t.result.wallIds),f.push(...t.issues)}return{floor:u,result:{wallIds:d},issues:f}}function w(t,n,r){if(n===r||!t.nodes[n]||!t.nodes[r])return{floor:t,result:{removedWallIds:[]},issues:[]};let i=l(t),a=[],o=[];for(let e of Object.values(i.walls))e.a===r&&(i.walls[e.id]={...i.walls[e.id],a:n}),e.b===r&&(i.walls[e.id]={...i.walls[e.id],b:n});for(let e of Object.values(i.walls))if(e.a===e.b){delete i.walls[e.id],a.push(e.id);for(let t of Object.values(i.openings))t.wallId===e.id&&delete i.openings[t.id]}let s=new Map;for(let t of Object.values(i.walls)){let n=t.a<t.b?`${t.a}|${t.b}`:`${t.b}|${t.a}`,r=s.get(n);if(!r){s.set(n,t);continue}let c=t.thickness>=r.thickness?t:r,l=c===t?r:t;for(let e of Object.values(i.openings))e.wallId===l.id&&(i.openings[e.id]={...e,wallId:c.id});delete i.walls[l.id],a.push(l.id),s.set(n,c),o.push(u(e.DuplicateWall,`Two walls became the same wall and were merged.`,{wallIds:[c.id,l.id]}))}return delete i.nodes[r],{floor:i,result:{removedWallIds:a},issues:o}}function T(t,i,a={}){let{force:o=!1}=a,s=t.nodes[i];if(!s)return{floor:t,result:null,issues:[]};let p=f(t,i);if(p.length!==2)return{floor:t,result:null,issues:[]};let[m,h]=p,g=m.thickness===h.thickness&&m.type===h.type&&m.height===h.height&&m.baseHeight===h.baseHeight;if(!g&&!o)return{floor:t,result:null,issues:[]};let _=m.a===i?m.b:m.a,v=h.a===i?h.b:h.a;if(_===v)return{floor:t,result:null,issues:[]};let y=t.nodes[_],b=t.nodes[v];if(!y||!b)return{floor:t,result:null,issues:[]};let x=r(y,b);if(x<10||!o&&Math.abs(n(y,b,s))/x>Math.max(1,x*1e-4))return{floor:t,result:null,issues:[]};let S=!g&&m.thickness<h.thickness?h:m,C=l(t),w=c(`w`);C.walls[w]={id:w,a:_,b:v,thickness:S.thickness,type:S.type,height:S.height,baseHeight:S.baseHeight};let T=r(y,s),E=r(s,b),D=T+E>0?x/(T+E):1,O=[];for(let n of Object.values(t.openings)){if(n.wallId!==m.id&&n.wallId!==h.id)continue;let r=n.wallId===m.id,a=r?m:h,o=a.a===i,s=d(t,a),c=o?n.offset:s-n.offset,l=(r?T-c:T+c)*D,f=Math.min(n.width*D,x-2);if(f<100){O.push(u(e.OpeningDropped,`An opening was removed: the wall it sat on became too short for it.`,{openingIds:[n.id],wallIds:[a.id]})),delete C.openings[n.id];continue}C.openings[n.id]={...n,wallId:w,width:f,offset:Math.min(Math.max(l,f/2),x-f/2)}}return delete C.walls[m.id],delete C.walls[h.id],delete C.nodes[i],{floor:C,result:{wallId:w},issues:O}}function E(e,t,n){let r=e.walls[t];if(!r||r.a===r.b||Math.hypot(n.x,n.y)<10)return{floor:e,result:null,issues:[]};let i=[r.a,r.b],a=[r.a,r.b],o=[null,null],s=[],c=[],u=e;i.forEach((i,s)=>{let c=e.nodes[i];if(!c)return;let d={x:c.x+n.x,y:c.y+n.y},p=f(e,i).filter(e=>e.id!==t);if(p.length===0){let e=l(u);e.nodes[i]={...e.nodes[i],x:d.x,y:d.y},u=e;return}let m=b(u,d,1);u=m.floor,a[s]=m.result.nodeId,o[s]=p.length===1?p[0]:r});let d=l(u);d.walls[t]={...d.walls[t],a:a[0],b:a[1]},u=d,i.forEach((e,t)=>{let n=o[t],r=u.nodes[e],i=u.nodes[a[t]];if(!n||!r||!i)return;let l=S(u,r,i,{thickness:n.thickness,type:n.type,height:n.height,baseHeight:n.baseHeight});u=l.floor,s.push(...l.result.wallIds),c.push(...l.issues)});let p=[];return i.forEach((e,t)=>{if(a[t]===e)return;let n=T(u,e);n.result&&(u=n.floor,p.push(e),c.push(...n.issues))}),{floor:u,result:{nodeIds:a,connectorIds:s,dissolvedNodeIds:p},issues:c}}function D(e,t=10){let n=e,i=[],a=[];for(let o=Object.keys(e.walls).length;o>0;o--){let e=Object.values(n.walls).find(e=>{if(e.a===e.b)return!1;let i=n.nodes[e.a],a=n.nodes[e.b];return i&&a&&r(i,a)<t});if(!e)break;let o=f(n,e.b).length>f(n,e.a).length?e.b:e.a,s=w(n,o,o===e.a?e.b:e.a);if(s.floor===n)break;n=s.floor,i.push(e.id),a.push(...s.issues)}return{floor:n,result:{weldedWallIds:i},issues:a}}function O(e,t,n={}){let{pruneOrphanNodes:r=!0,dissolveCollinear:i=!0}=n,a=e.walls[t];if(!a)return{floor:e,result:{removedNodeIds:[],dissolvedWallIds:[]},issues:[]};let o=l(e);delete o.walls[t];for(let e of Object.values(o.openings))e.wallId===t&&delete o.openings[e.id];let s=[],c=[],u=[];for(let e of[a.a,a.b]){let t=f(o,e).length;if(t===0&&r)delete o.nodes[e],s.push(e);else if(t===2&&i){let t=T(o,e);t.result&&(o=t.floor,c.push(t.result.wallId),s.push(e),u.push(...t.issues))}}return{floor:o,result:{removedNodeIds:s,dissolvedWallIds:c},issues:u}}function k(e,t,n){let r=e.nodes[t];if(!r)return{floor:e,result:void 0,issues:[]};let i=l(e);return i.nodes[t]={...r,x:n.x,y:n.y},{floor:i,result:void 0,issues:[]}}function A(e,t,n){let r=l(e);for(let i of Object.values(e.nodes))r.nodes[i.id]={...i,x:i.x+t,y:i.y+n};for(let i of Object.values(e.rooms))r.rooms[i.id]={...i,anchor:{x:i.anchor.x+t,y:i.anchor.y+n}};return r}function j(e,t){let n=l(e);for(let r of Object.values(e.nodes))n.nodes[r.id]={...r,x:r.x*t,y:r.y*t};for(let r of Object.values(e.walls))n.walls[r.id]={...r,thickness:r.thickness*t,height:r.height===void 0?void 0:r.height*t,baseHeight:r.baseHeight===void 0?void 0:r.baseHeight*t};for(let r of Object.values(e.openings))n.openings[r.id]={...r,offset:r.offset*t,width:r.width*t,sill:r.sill*t,head:r.head*t};for(let r of Object.values(e.rooms))n.rooms[r.id]={...r,anchor:{x:r.anchor.x*t,y:r.anchor.y*t},area:r.area*t*t};return n}function M(t,n){let r=t.walls[n.wallId];if(!r)return{floor:t,result:{openingId:null},issues:[]};let i=d(t,r),a=Math.min(n.width,i-2);if(a<100)return{floor:t,result:{openingId:null},issues:[u(e.OpeningDropped,`That wall is too short for an opening.`,{wallIds:[r.id]})]};let o=Math.min(Math.max(n.offset,a/2),i-a/2),s=l(t),f=c(`o`);return s.openings[f]={...n,id:f,offset:o,width:a},{floor:s,result:{openingId:f},issues:[]}}function N(e,t,n){let r=e.openings[t];if(!r)return{floor:e,result:void 0,issues:[]};let i=e.walls[r.wallId];if(!i)return{floor:e,result:void 0,issues:[]};let a=d(e,i),o={...r,...n},s=Math.min(Math.max(o.width,100),Math.max(a-2,100)),c=Math.min(Math.max(o.offset,s/2),Math.max(a-s/2,s/2)),u=l(e);return u.openings[t]={...o,width:s,offset:c},{floor:u,result:void 0,issues:[]}}function P(e,t){if(!e.openings[t])return{floor:e,result:void 0,issues:[]};let n=l(e);return delete n.openings[t],{floor:n,result:void 0,issues:[]}}function F(t){let n=[],a=Object.values(t.walls);for(let i of a){let a=t.nodes[i.a],o=t.nodes[i.b];if(i.a===i.b){n.push(u(e.SelfLoopWall,`A wall starts and ends at the same node.`,{wallIds:[i.id]}));continue}if(!a||!o){n.push(u(e.ZeroLengthWall,`A wall references a missing node.`,{wallIds:[i.id]}));continue}r(a,o)<10&&n.push(u(e.ZeroLengthWall,`A wall is shorter than the minimum length.`,{wallIds:[i.id]}))}let s=new Map;for(let t of a){let r=t.a<t.b?`${t.a}|${t.b}`:`${t.b}|${t.a}`,i=s.get(r);i?n.push(u(e.DuplicateWall,`Two walls connect the same pair of nodes.`,{wallIds:[i,t.id]})):s.set(r,t.id)}let c=Object.values(t.nodes);for(let t=0;t<c.length;t++)for(let i=t+1;i<c.length;i++)r(c[t],c[i])<1&&n.push(u(e.CoincidentNodes,`Two nodes occupy the same position.`,{nodeIds:[c[t].id,c[i].id]}));for(let r=0;r<a.length;r++)for(let i=r+1;i<a.length;i++){let s=a[r],c=a[i],l=t.nodes[s.a],d=t.nodes[s.b],f=t.nodes[c.a],p=t.nodes[c.b];if(!l||!d||!f||!p)continue;let m=o(l,d,f,p);m.kind===`proper`?n.push(u(e.UnsplitCrossing,`Two walls cross with no node at the intersection.`,{wallIds:[s.id,c.id]})):m.kind===`collinearOverlap`&&n.push(u(e.OverlappingWalls,`Two walls overlap along the same line.`,{wallIds:[s.id,c.id]}))}for(let r of a){let a=t.nodes[r.a],o=t.nodes[r.b];if(a&&o)for(let t of c){if(t.id===r.a||t.id===r.b)continue;let s=i(t,a,o);s.dist<1&&s.t>0&&s.t<1&&n.push(u(e.UnsplitNodeOnWall,`A node sits on a wall that was never split there.`,{wallIds:[r.id],nodeIds:[t.id]}))}}for(let r of Object.values(t.openings))t.walls[r.wallId]||n.push(u(e.DanglingOpening,`An opening references a wall that no longer exists.`,{openingIds:[r.id]}));let l=new Set;for(let e of a)l.add(e.a),l.add(e.b);for(let t of c)l.has(t.id)||n.push(u(e.OrphanNode,`A node has no walls.`,{nodeIds:[t.id]}));return n}function I(t){let n=[],i=D(t),a=l(i.floor);for(let t of i.result.weldedWallIds)n.push(u(e.ZeroLengthWall,`Welded the two ends of a wall with no length.`,{wallIds:[t]}));for(let t of Object.values(a.walls)){let i=a.nodes[t.a],o=a.nodes[t.b];(t.a===t.b||!i||!o||r(i,o)<10)&&(delete a.walls[t.id],n.push(u(e.ZeroLengthWall,`Removed a degenerate wall.`,{wallIds:[t.id]})))}let o=new Map;for(let t of Object.values(a.walls)){let r=t.a<t.b?`${t.a}|${t.b}`:`${t.b}|${t.a}`,i=o.get(r);if(!i){o.set(r,t);continue}let s=t.thickness>=i.thickness?t:i,c=s===t?i:t;for(let e of Object.values(a.openings))e.wallId===c.id&&(a.openings[e.id]={...e,wallId:s.id});delete a.walls[c.id],o.set(r,s),n.push(u(e.DuplicateWall,`Removed a duplicate wall.`,{wallIds:[c.id]}))}for(let t of Object.values(a.openings))a.walls[t.wallId]||(delete a.openings[t.id],n.push(u(e.DanglingOpening,`Removed an opening with no wall.`,{openingIds:[t.id]})));let s=new Set;for(let e of Object.values(a.walls))s.add(e.a),s.add(e.b);for(let t of Object.values(a.nodes))s.has(t.id)||(delete a.nodes[t.id],n.push(u(e.OrphanNode,`Removed a node with no walls.`,{nodeIds:[t.id]})));return{floor:a,result:n,issues:n}}export{x as DEFAULT_WALL_ATTRS,M as addOpening,C as addRect,S as addWall,I as cleanupPlan,E as detachWall,T as dissolveNode,_ as findNodeNear,p as findWallBetween,v as findWallNear,w as mergeNodes,k as moveNode,c as newId,P as removeOpening,O as removeWall,b as resolveNodeAt,j as scalePlan,y as splitWall,A as transformPlan,N as updateOpening,F as validatePlan,d as wallLength,f as wallsAtNode,D as weldShortWalls};
2
2
  //# sourceMappingURL=floorPlan.graph.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"floorPlan.graph.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.graph.ts"],"sourcesContent":["/**\n * Graph maintenance: the operations that keep the wall graph a valid planar embedding\n * while the user draws.\n *\n * The invariant every function here protects: no two walls may cross without a node at\n * the intersection, and no node may lie on a wall's interior without that wall being\n * split there. Break either and the face walk silently merges two rooms into one\n * figure-eight face, with no error anywhere.\n *\n * Every operation is pure and returns a new floor, for direct use as React state.\n */\n\nimport {\n EPS_ANGLE,\n EPS_COINCIDENT,\n MIN_OPENING_WIDTH,\n MIN_WALL_LENGTH,\n cross,\n dist,\n pointToSegment,\n projectOnSegment,\n segmentIntersection,\n} from './floorPlan.geometry';\nimport { PlanIssueKind, WallType } from './floorPlan.types';\nimport type { PlanEdit, PlanFloor, PlanIssue, PlanNode, PlanOpening, PlanPoint, PlanWall } from './floorPlan.types';\n\n// ─── Ids ───────────────────────────────────────────────────────────────────────\n\nlet idSeq = 0;\n\n/**\n * Ids are deliberately non-numeric strings, so `Record` iteration keeps insertion\n * order (JavaScript reorders integer-like keys), which is what makes derivation\n * reproducible.\n */\nexport function newId(prefix: string): string {\n idSeq += 1;\n const rand =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID().slice(0, 8)\n : Math.random().toString(36).slice(2, 10);\n return `${prefix}_${rand}${idSeq.toString(36)}`;\n}\n\n/** Test-only: makes generated ids reproducible within a single test. */\nexport function __resetIdSeq(): void {\n idSeq = 0;\n}\n\n// ─── Internals ─────────────────────────────────────────────────────────────────\n\nfunction cloneFloor(floor: PlanFloor): PlanFloor {\n return {\n ...floor,\n nodes: { ...floor.nodes },\n walls: { ...floor.walls },\n openings: { ...floor.openings },\n rooms: { ...floor.rooms },\n };\n}\n\nfunction issue(kind: PlanIssueKind, message: string, extra: Partial<PlanIssue> = {}): PlanIssue {\n return { kind, message, ...extra };\n}\n\nfunction wallLength(floor: PlanFloor, wall: PlanWall): number {\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) return 0;\n return dist(a, b);\n}\n\nfunction wallsAtNode(floor: PlanFloor, nodeId: string): PlanWall[] {\n return Object.values(floor.walls).filter((w) => w.a === nodeId || w.b === nodeId);\n}\n\nfunction findWallBetween(floor: PlanFloor, a: string, b: string): PlanWall | null {\n for (const w of Object.values(floor.walls)) {\n if ((w.a === a && w.b === b) || (w.a === b && w.b === a)) return w;\n }\n return null;\n}\n\n// ─── Node spatial hash ─────────────────────────────────────────────────────────\n\n/**\n * Bucket size for the node hash, in millimetres. Any lookup checks the 3x3\n * neighbourhood, so this only has to exceed the largest snap tolerance in world units.\n */\nconst HASH_CELL = 250;\n\nfunction hashKey(x: number, y: number): string {\n return `${Math.round(x / HASH_CELL)}|${Math.round(y / HASH_CELL)}`;\n}\n\nfunction buildNodeHash(floor: PlanFloor): Map<string, PlanNode[]> {\n const map = new Map<string, PlanNode[]>();\n for (const node of Object.values(floor.nodes)) {\n const key = hashKey(node.x, node.y);\n const list = map.get(key);\n if (list) list.push(node);\n else map.set(key, [node]);\n }\n return map;\n}\n\n/** Nearest existing node within `tol`, using the spatial hash. */\nexport function findNodeNear(floor: PlanFloor, p: PlanPoint, tol: number): PlanNode | null {\n const hash = buildNodeHash(floor);\n const cx = Math.round(p.x / HASH_CELL);\n const cy = Math.round(p.y / HASH_CELL);\n let best: PlanNode | null = null;\n let bestDist = tol;\n const span = Math.max(1, Math.ceil(tol / HASH_CELL));\n for (let dx = -span; dx <= span; dx++) {\n for (let dy = -span; dy <= span; dy++) {\n for (const node of hash.get(`${cx + dx}|${cy + dy}`) ?? []) {\n const d = dist(p, node);\n if (d <= bestDist) {\n best = node;\n bestDist = d;\n }\n }\n }\n }\n return best;\n}\n\n/** Nearest wall whose centreline passes within `tol` of `p`. */\nexport function findWallNear(\n floor: PlanFloor,\n p: PlanPoint,\n tol: number,\n exclude?: ReadonlySet<string>,\n): { wall: PlanWall; t: number; point: PlanPoint; dist: number } | null {\n let best: { wall: PlanWall; t: number; point: PlanPoint; dist: number } | null = null;\n for (const wall of Object.values(floor.walls)) {\n if (exclude?.has(wall.id)) continue;\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) continue;\n const r = pointToSegment(p, a, b);\n if (r.dist <= tol && (!best || r.dist < best.dist)) {\n best = { wall, t: r.t, point: r.point, dist: r.dist };\n }\n }\n return best;\n}\n\n// ─── splitWall ─────────────────────────────────────────────────────────────────\n\nexport interface SplitWallResult {\n nodeId: string;\n wallIds: [string, string] | null;\n droppedOpeningIds: string[];\n}\n\n/**\n * Splits a wall at a point or parameter, returning the node at the cut.\n *\n * Refuses to cut within `MIN_WALL_LENGTH` of either end, returning that endpoint's\n * existing node instead. That single rule is what keeps zero-length walls out of the\n * graph entirely, which in turn is what stops the angular sort from being fed a\n * direction-less dart.\n */\nexport function splitWall(floor: PlanFloor, wallId: string, at: PlanPoint | number): PlanEdit<SplitWallResult> {\n const wall = floor.walls[wallId];\n if (!wall) {\n return { floor, result: { nodeId: '', wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) {\n return { floor, result: { nodeId: '', wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n\n const len = dist(a, b);\n const point = typeof at === 'number' ? { x: a.x + (b.x - a.x) * at, y: a.y + (b.y - a.y) * at } : at;\n // Project exactly, so the two children stay perfectly collinear and dissolveNode can\n // undo the split cleanly later.\n const exact = projectOnSegment(point, a, b);\n const fromA = dist(a, exact);\n\n if (fromA < MIN_WALL_LENGTH) {\n return { floor, result: { nodeId: wall.a, wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n if (len - fromA < MIN_WALL_LENGTH) {\n return { floor, result: { nodeId: wall.b, wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n\n const next = cloneFloor(floor);\n const nodeId = newId('n');\n next.nodes[nodeId] = { id: nodeId, x: exact.x, y: exact.y };\n\n const firstId = newId('w');\n const secondId = newId('w');\n const base = { thickness: wall.thickness, type: wall.type, height: wall.height, baseHeight: wall.baseHeight };\n next.walls[firstId] = { ...base, id: firstId, a: wall.a, b: nodeId };\n next.walls[secondId] = { ...base, id: secondId, a: nodeId, b: wall.b };\n delete next.walls[wallId];\n\n // Reassign openings by the side their CENTRE falls on. An opening straddling the cut\n // is a genuine conflict: move it wholly into that child and clamp it, or drop it and\n // say so. Silently deleting a window is not acceptable.\n const droppedOpeningIds: string[] = [];\n const issues: PlanIssue[] = [];\n for (const opening of Object.values(floor.openings)) {\n if (opening.wallId !== wallId) continue;\n const intoFirst = opening.offset <= fromA;\n const childId = intoFirst ? firstId : secondId;\n const childLen = intoFirst ? fromA : len - fromA;\n const offset = intoFirst ? opening.offset : opening.offset - fromA;\n\n const maxWidth = Math.min(opening.width, childLen - 2, offset * 2, (childLen - offset) * 2);\n if (maxWidth < MIN_OPENING_WIDTH) {\n delete next.openings[opening.id];\n droppedOpeningIds.push(opening.id);\n issues.push(\n issue(PlanIssueKind.OpeningDropped, 'An opening was removed: the wall it sat on became too short for it.', {\n openingIds: [opening.id],\n wallIds: [wallId],\n }),\n );\n continue;\n }\n next.openings[opening.id] = { ...opening, wallId: childId, offset, width: maxWidth };\n }\n\n return { floor: next, result: { nodeId, wallIds: [firstId, secondId], droppedOpeningIds }, issues };\n}\n\n// ─── resolveNodeAt ─────────────────────────────────────────────────────────────\n\nexport interface ResolveNodeResult {\n nodeId: string;\n createdNode: boolean;\n splitWallId: string | null;\n}\n\n/**\n * Returns the node to use at `p`: an existing one within `tol`, a new one created by\n * splitting a wall that passes under `p`, or a brand new free-standing node.\n */\nexport function resolveNodeAt(floor: PlanFloor, p: PlanPoint, tol: number): PlanEdit<ResolveNodeResult> {\n const existing = findNodeNear(floor, p, tol);\n if (existing) {\n return { floor, result: { nodeId: existing.id, createdNode: false, splitWallId: null }, issues: [] };\n }\n\n const onWall = findWallNear(floor, p, tol);\n if (onWall) {\n const split = splitWall(floor, onWall.wall.id, onWall.point);\n if (split.result.nodeId) {\n return {\n floor: split.floor,\n result: {\n nodeId: split.result.nodeId,\n createdNode: split.result.wallIds !== null,\n splitWallId: split.result.wallIds ? onWall.wall.id : null,\n },\n issues: split.issues,\n };\n }\n }\n\n const next = cloneFloor(floor);\n const nodeId = newId('n');\n next.nodes[nodeId] = { id: nodeId, x: p.x, y: p.y };\n return { floor: next, result: { nodeId, createdNode: true, splitWallId: null }, issues: [] };\n}\n\n// ─── addWall ───────────────────────────────────────────────────────────────────\n\nexport type WallAttrs = Pick<PlanWall, 'thickness' | 'type'> & Partial<Pick<PlanWall, 'height' | 'baseHeight'>>;\n\nexport const DEFAULT_WALL_ATTRS: WallAttrs = { thickness: 200, type: WallType.Interior };\n\ninterface Cut {\n t: number;\n nodeId: string | null;\n /** Set while the node does not exist yet because its wall has not been split. */\n pending?: { wallId: string; s: number };\n}\n\n/**\n * Adds a wall from `a` to `b`, splitting anything it crosses so the graph stays planar.\n *\n * Collect-then-apply, in two phases: the naive version splits walls while iterating\n * over walls, which both invalidates the iteration and reparameterises the very\n * segments it is about to test.\n */\nexport function addWall(\n floor: PlanFloor,\n a: PlanPoint,\n b: PlanPoint,\n attrs: WallAttrs = DEFAULT_WALL_ATTRS,\n tol: number = EPS_COINCIDENT,\n): PlanEdit<{ wallIds: string[]; nodeIds: string[] }> {\n const issues: PlanIssue[] = [];\n if (dist(a, b) < MIN_WALL_LENGTH) {\n return { floor, result: { wallIds: [], nodeIds: [] }, issues };\n }\n\n // 1. Endpoints. Each may reuse a node, split a wall, or create a node.\n const startEdit = resolveNodeAt(floor, a, tol);\n let work = startEdit.floor;\n issues.push(...startEdit.issues);\n const endEdit = resolveNodeAt(work, b, tol);\n work = endEdit.floor;\n issues.push(...endEdit.issues);\n\n const na = startEdit.result.nodeId;\n const nb = endEdit.result.nodeId;\n if (na === nb) return { floor, result: { wallIds: [], nodeIds: [] }, issues };\n\n const A = work.nodes[na];\n const B = work.nodes[nb];\n const len = dist(A, B);\n if (len < MIN_WALL_LENGTH) return { floor, result: { wallIds: [], nodeIds: [] }, issues };\n\n // 2. COLLECT. Nothing is mutated in this phase.\n const cuts: Cut[] = [\n { t: 0, nodeId: na },\n { t: 1, nodeId: nb },\n ];\n const splits = new Map<string, number[]>();\n const overlaps: Array<[number, number]> = [];\n\n const paramAlong = (p: PlanPoint): number => pointToSegment(p, A, B).t;\n\n for (const wall of Object.values(work.walls)) {\n const wa = work.nodes[wall.a];\n const wb = work.nodes[wall.b];\n if (!wa || !wb) continue;\n\n const hit = segmentIntersection(A, B, wa, wb, tol);\n\n if (hit.kind === 'collinearOverlap') {\n const t0 = paramAlong(wa);\n const t1 = paramAlong(wb);\n overlaps.push([Math.min(t0, t1), Math.max(t0, t1)]);\n // Endpoints of the overlapping wall that fall strictly inside AB still need cuts,\n // or the new wall would run straight past them.\n for (const [node, t] of [\n [wa, t0],\n [wb, t1],\n ] as const) {\n if (t * len > MIN_WALL_LENGTH && (1 - t) * len > MIN_WALL_LENGTH) {\n cuts.push({ t, nodeId: node.id });\n }\n }\n continue;\n }\n\n if (hit.kind === 'proper' && hit.t !== undefined && hit.s !== undefined) {\n const list = splits.get(wall.id);\n if (list) list.push(hit.s);\n else splits.set(wall.id, [hit.s]);\n cuts.push({ t: hit.t, nodeId: null, pending: { wallId: wall.id, s: hit.s } });\n continue;\n }\n\n if (hit.kind === 'touch' && hit.t !== undefined && hit.s !== undefined) {\n // A T junction where one of the wall's own endpoints sits on AB: reuse it.\n const atWallStart = hit.s <= 0.5;\n const endpoint = atWallStart ? wa : wb;\n const tOnAb = paramAlong(endpoint);\n if (\n pointToSegment(endpoint, A, B).dist <= tol &&\n tOnAb * len > MIN_WALL_LENGTH &&\n (1 - tOnAb) * len > MIN_WALL_LENGTH\n ) {\n cuts.push({ t: tOnAb, nodeId: endpoint.id });\n }\n }\n }\n\n // 3. Nodes lying on AB that no crossing test found. NOT redundant with step 2: a node\n // whose incident walls all run away from AB is invisible to every crossing test, yet\n // failing to cut AB there leaves a node on a wall interior, which silently merges the\n // two rooms either side of it.\n for (const node of Object.values(work.nodes)) {\n if (node.id === na || node.id === nb) continue;\n const r = pointToSegment(node, A, B);\n if (r.dist > tol) continue;\n if (r.t * len <= MIN_WALL_LENGTH || (1 - r.t) * len <= MIN_WALL_LENGTH) continue;\n cuts.push({ t: r.t, nodeId: node.id });\n }\n\n // 4. APPLY splits, per wall, in DESCENDING parameter order so that earlier\n // parameters stay valid as later ones are consumed.\n for (const [wallId, params] of splits) {\n const sorted = [...params].sort((x, y) => y - x);\n let currentWallId = wallId;\n const remaining = new Set(sorted);\n for (const s of sorted) {\n const target = work.walls[currentWallId];\n if (!target) break;\n const wa = work.nodes[target.a];\n const wb = work.nodes[target.b];\n if (!wa || !wb) break;\n // Re-project onto the wall as it stands now, rather than reusing the original\n // parameter, which the previous split may have reparameterised.\n const original = floor.walls[wallId];\n const oa = work.nodes[original?.a ?? target.a] ?? wa;\n const ob = work.nodes[original?.b ?? target.b] ?? wb;\n const worldPoint = { x: oa.x + (ob.x - oa.x) * s, y: oa.y + (ob.y - oa.y) * s };\n const edit = splitWall(work, currentWallId, worldPoint);\n work = edit.floor;\n issues.push(...edit.issues);\n remaining.delete(s);\n for (const cut of cuts) {\n if (cut.pending && cut.pending.wallId === wallId && cut.pending.s === s) {\n cut.nodeId = edit.result.nodeId;\n cut.pending = undefined;\n }\n }\n // Continue splitting whichever child still holds the remaining parameters.\n if (edit.result.wallIds) {\n const [first, second] = edit.result.wallIds;\n const nextS = Math.max(...[...remaining], -1);\n currentWallId = nextS >= 0 && nextS > s ? second : first;\n }\n }\n }\n\n // 5. Chain the cuts into walls.\n const resolved = cuts.filter((c): c is Cut & { nodeId: string } => Boolean(c.nodeId));\n resolved.sort((x, y) => x.t - y.t);\n\n const chain: Array<Cut & { nodeId: string }> = [];\n for (const cut of resolved) {\n const last = chain[chain.length - 1];\n if (!last) {\n chain.push(cut);\n continue;\n }\n if (last.nodeId === cut.nodeId) continue;\n if ((cut.t - last.t) * len < MIN_WALL_LENGTH) {\n // Too close to be a separate wall. Prefer whichever end is an endpoint of AB.\n if (cut.t >= 1 - 1e-9) chain[chain.length - 1] = cut;\n continue;\n }\n chain.push(cut);\n }\n\n const createdWallIds: string[] = [];\n for (let i = 0; i + 1 < chain.length; i++) {\n const from = chain[i];\n const to = chain[i + 1];\n const midT = (from.t + to.t) / 2;\n if (overlaps.some(([lo, hi]) => midT > lo + 1e-9 && midT < hi - 1e-9)) {\n // Already walled. Do not create a duplicate, and do not rewrite the existing\n // wall's attributes from a stroke that was aimed elsewhere.\n continue;\n }\n if (findWallBetween(work, from.nodeId, to.nodeId)) continue;\n const wa = work.nodes[from.nodeId];\n const wb = work.nodes[to.nodeId];\n if (!wa || !wb || dist(wa, wb) < MIN_WALL_LENGTH) continue;\n\n const id = newId('w');\n work = { ...work, walls: { ...work.walls, [id]: { ...attrs, id, a: from.nodeId, b: to.nodeId } } };\n createdWallIds.push(id);\n }\n\n if (createdWallIds.length === 0 && overlaps.length > 0) {\n issues.push(issue(PlanIssueKind.DuplicateWall, 'A wall already covers that span, so nothing was added.'));\n }\n\n return {\n floor: work,\n result: { wallIds: createdWallIds, nodeIds: chain.map((c) => c.nodeId) },\n issues,\n };\n}\n\n/** Draws the four walls of an axis-aligned rectangle, welding onto anything already there. */\nexport function addRect(\n floor: PlanFloor,\n corner: PlanPoint,\n opposite: PlanPoint,\n attrs: WallAttrs = DEFAULT_WALL_ATTRS,\n tol: number = EPS_COINCIDENT,\n): PlanEdit<{ wallIds: string[] }> {\n const x0 = Math.min(corner.x, opposite.x);\n const x1 = Math.max(corner.x, opposite.x);\n const y0 = Math.min(corner.y, opposite.y);\n const y1 = Math.max(corner.y, opposite.y);\n if (x1 - x0 < MIN_WALL_LENGTH || y1 - y0 < MIN_WALL_LENGTH) {\n return { floor, result: { wallIds: [] }, issues: [] };\n }\n\n const corners: PlanPoint[] = [\n { x: x0, y: y0 },\n { x: x1, y: y0 },\n { x: x1, y: y1 },\n { x: x0, y: y1 },\n ];\n\n let work = floor;\n const wallIds: string[] = [];\n const issues: PlanIssue[] = [];\n for (let i = 0; i < 4; i++) {\n const edit = addWall(work, corners[i], corners[(i + 1) % 4], attrs, tol);\n work = edit.floor;\n wallIds.push(...edit.result.wallIds);\n issues.push(...edit.issues);\n }\n return { floor: work, result: { wallIds }, issues };\n}\n\n// ─── mergeNodes ────────────────────────────────────────────────────────────────\n\n/**\n * Merges `removeId` into `keepId`, as when a node is dragged onto another.\n *\n * Order matters, and step 3 is mandatory rather than cosmetic: a duplicate wall between\n * the same pair of nodes is exactly the identical-angle degeneracy that corrupts the\n * face walk's angular sort.\n */\nexport function mergeNodes(floor: PlanFloor, keepId: string, removeId: string): PlanEdit<{ removedWallIds: string[] }> {\n if (keepId === removeId || !floor.nodes[keepId] || !floor.nodes[removeId]) {\n return { floor, result: { removedWallIds: [] }, issues: [] };\n }\n\n const next = cloneFloor(floor);\n const removedWallIds: string[] = [];\n const issues: PlanIssue[] = [];\n\n // 1. Rewire.\n for (const wall of Object.values(next.walls)) {\n if (wall.a === removeId) next.walls[wall.id] = { ...next.walls[wall.id], a: keepId };\n if (wall.b === removeId) next.walls[wall.id] = { ...next.walls[wall.id], b: keepId };\n }\n\n // 2. Drop self-loops, and their openings with them.\n for (const wall of Object.values(next.walls)) {\n if (wall.a !== wall.b) continue;\n delete next.walls[wall.id];\n removedWallIds.push(wall.id);\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === wall.id) delete next.openings[opening.id];\n }\n }\n\n // 3. Deduplicate walls that now share the same unordered node pair.\n const seen = new Map<string, PlanWall>();\n for (const wall of Object.values(next.walls)) {\n const key = wall.a < wall.b ? `${wall.a}|${wall.b}` : `${wall.b}|${wall.a}`;\n const prior = seen.get(key);\n if (!prior) {\n seen.set(key, wall);\n continue;\n }\n // Keep the thicker wall, and carry both walls' openings onto it.\n const keep = wall.thickness >= prior.thickness ? wall : prior;\n const drop = keep === wall ? prior : wall;\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === drop.id) {\n next.openings[opening.id] = { ...opening, wallId: keep.id };\n }\n }\n delete next.walls[drop.id];\n removedWallIds.push(drop.id);\n seen.set(key, keep);\n issues.push(\n issue(PlanIssueKind.DuplicateWall, 'Two walls became the same wall and were merged.', {\n wallIds: [keep.id, drop.id],\n }),\n );\n }\n\n // 4. Drop the now-unreferenced node.\n delete next.nodes[removeId];\n\n return { floor: next, result: { removedWallIds }, issues };\n}\n\n// ─── dissolveNode ──────────────────────────────────────────────────────────────\n\nexport interface DissolveNodeOptions {\n /**\n * Rejoin the two walls even when the corner is bent or the walls differ in\n * construction, taking the thicker wall's attributes and rescaling openings onto the\n * shorter merged wall.\n *\n * This is \"delete this corner\" as a user means it. The default, unforced behaviour is\n * the stricter one used by cleanup and by `removeWall`, where dissolving must not\n * change the drawing's geometry at all.\n */\n force?: boolean;\n}\n\n/**\n * Merges the two walls meeting at a degree-2 node back into one, the natural inverse of\n * `splitWall`.\n *\n * Returns `null` unless the node is genuinely a seam: degree exactly 2, both walls\n * identical in construction, and the turn within `EPS_ANGLE` of straight. Pass\n * `{ force: true }` to rejoin a bent corner as well. Never call it mid-drag: it destroys\n * node ids the user may be holding.\n */\nexport function dissolveNode(\n floor: PlanFloor,\n nodeId: string,\n options: DissolveNodeOptions = {},\n): PlanEdit<{ wallId: string } | null> {\n const { force = false } = options;\n const node = floor.nodes[nodeId];\n if (!node) return { floor, result: null, issues: [] };\n\n const incident = wallsAtNode(floor, nodeId);\n if (incident.length !== 2) return { floor, result: null, issues: [] };\n\n const [w1, w2] = incident;\n const sameConstruction =\n w1.thickness === w2.thickness && w1.type === w2.type && w1.height === w2.height && w1.baseHeight === w2.baseHeight;\n if (!sameConstruction && !force) return { floor, result: null, issues: [] };\n\n const far1 = w1.a === nodeId ? w1.b : w1.a;\n const far2 = w2.a === nodeId ? w2.b : w2.a;\n if (far1 === far2) return { floor, result: null, issues: [] };\n\n const p1 = floor.nodes[far1];\n const p2 = floor.nodes[far2];\n if (!p1 || !p2) return { floor, result: null, issues: [] };\n\n const span = dist(p1, p2);\n if (span < MIN_WALL_LENGTH) return { floor, result: null, issues: [] };\n\n if (!force) {\n // Straightness by perpendicular offset rather than raw angle, so the tolerance stays\n // meaningful at any wall length.\n const offset = Math.abs(cross(p1, p2, node)) / span;\n if (offset > Math.max(EPS_COINCIDENT, span * EPS_ANGLE)) {\n return { floor, result: null, issues: [] };\n }\n }\n\n // Forced over a bent corner, the survivor is the thicker of the two, since that is the\n // one whose construction the rest of the plan is more likely to depend on.\n const keep = !sameConstruction && w1.thickness < w2.thickness ? w2 : w1;\n\n const next = cloneFloor(floor);\n const id = newId('w');\n next.walls[id] = {\n id,\n a: far1,\n b: far2,\n thickness: keep.thickness,\n type: keep.type,\n height: keep.height,\n baseHeight: keep.baseHeight,\n };\n\n // Re-express every opening's offset against the merged wall's direction (far1 -> far2).\n const len1 = dist(p1, node);\n const len2 = dist(node, p2);\n // Cutting a bent corner shortens the run, so positions are scaled along it rather than\n // carried over, which would push an opening off the end of its own wall.\n const scale = len1 + len2 > 0 ? span / (len1 + len2) : 1;\n const issues: PlanIssue[] = [];\n\n for (const opening of Object.values(floor.openings)) {\n if (opening.wallId !== w1.id && opening.wallId !== w2.id) continue;\n const onFirst = opening.wallId === w1.id;\n const wall = onFirst ? w1 : w2;\n const startsAtNode = wall.a === nodeId;\n const lenOfWall = wallLength(floor, wall);\n // Distance from the seam, then from the merged wall's own start.\n const fromSeam = startsAtNode ? opening.offset : lenOfWall - opening.offset;\n const alongOriginal = onFirst ? len1 - fromSeam : len1 + fromSeam;\n const offsetOnMerged = alongOriginal * scale;\n\n const width = Math.min(opening.width * scale, span - 2);\n if (width < MIN_OPENING_WIDTH) {\n issues.push(\n issue(PlanIssueKind.OpeningDropped, 'An opening was removed: the wall it sat on became too short for it.', {\n openingIds: [opening.id],\n wallIds: [wall.id],\n }),\n );\n delete next.openings[opening.id];\n continue;\n }\n\n next.openings[opening.id] = {\n ...opening,\n wallId: id,\n width,\n offset: Math.min(Math.max(offsetOnMerged, width / 2), span - width / 2),\n };\n }\n\n delete next.walls[w1.id];\n delete next.walls[w2.id];\n delete next.nodes[nodeId];\n\n return { floor: next, result: { wallId: id }, issues };\n}\n\n// ─── detachWall ────────────────────────────────────────────────────────────────\n\nexport interface DetachWallResult {\n /** The wall's end nodes after the detach, in `[a, b]` order. */\n nodeIds: [string, string];\n /** Connecting walls minted where an end was shared with a neighbour. */\n connectorIds: string[];\n /** Ends that became a straight seam once the wall left, and were dissolved away. */\n dissolvedNodeIds: string[];\n}\n\n/**\n * Pulls a wall off the nodes it shares with its neighbours and moves it by `delta`,\n * leaving a connecting wall behind at each end that was shared.\n *\n * This is the extrude half of dragging a wall. A plain drag moves the shared end nodes,\n * so everything meeting the wall follows it; here the neighbours keep their ends and\n * only the new connectors grow, which is what you want when a partition joins the wall\n * halfway along and should stay put.\n *\n * A free end is only moved: there is nothing there to detach from, and a connector would\n * be zero length. For the same reason `delta` must be at least `MIN_WALL_LENGTH` long —\n * below that the caller should `moveNode` both ends instead.\n *\n * The connector continues whatever was already at the corner (its thickness, type and\n * heights) when exactly one wall was, so pulling a wall off a plain corner redraws\n * exactly as a plain drag would: the seam that leaves behind is straight and is\n * dissolved before returning. At a junction there is no single wall to continue, so the\n * connector takes the dragged wall's own construction.\n */\nexport function detachWall(floor: PlanFloor, wallId: string, delta: PlanPoint): PlanEdit<DetachWallResult | null> {\n const wall = floor.walls[wallId];\n if (!wall || wall.a === wall.b) return { floor, result: null, issues: [] };\n if (Math.hypot(delta.x, delta.y) < MIN_WALL_LENGTH) return { floor, result: null, issues: [] };\n\n const ends: [string, string] = [wall.a, wall.b];\n const nodeIds: [string, string] = [wall.a, wall.b];\n const sources: (PlanWall | null)[] = [null, null];\n const connectorIds: string[] = [];\n const issues: PlanIssue[] = [];\n let out = floor;\n\n // 1. Give the wall its own ends. `resolveNodeAt` rather than a bare node, because the\n // new end often lands in the middle of another wall — the usual case is pushing the\n // shared wall of two rooms sideways, where each end slides along the wall above and\n // below it — and only a split keeps a node off a wall's interior.\n ends.forEach((nodeId, index) => {\n const origin = floor.nodes[nodeId];\n if (!origin) return;\n const to = { x: origin.x + delta.x, y: origin.y + delta.y };\n const others = wallsAtNode(floor, nodeId).filter((w) => w.id !== wallId);\n\n if (others.length === 0) {\n // A free end has nothing to detach from, and a connector there would be a wall\n // between a node and itself.\n const next = cloneFloor(out);\n next.nodes[nodeId] = { ...next.nodes[nodeId], x: to.x, y: to.y };\n out = next;\n return;\n }\n\n const edit = resolveNodeAt(out, to, EPS_COINCIDENT);\n out = edit.floor;\n nodeIds[index] = edit.result.nodeId;\n // The connector continues whatever was already at this corner, so pulling a wall off\n // a plain corner redraws exactly as a plain drag would. At a junction there is no\n // single wall to continue, so it takes the dragged wall's own construction.\n sources[index] = others.length === 1 ? others[0] : wall;\n });\n\n // 2. Move the wall onto them. Its openings ride along untouched: a detach is a pure\n // translation, so the wall keeps its id, its direction and its length.\n const moved = cloneFloor(out);\n moved.walls[wallId] = { ...moved.walls[wallId], a: nodeIds[0], b: nodeIds[1] };\n out = moved;\n\n // 3. Bridge each end back to where it came from, unless a wall already runs there.\n ends.forEach((nodeId, index) => {\n const source = sources[index];\n const from = out.nodes[nodeId];\n const to = out.nodes[nodeIds[index]];\n if (!source || !from || !to) return;\n const edit = addWall(out, from, to, {\n thickness: source.thickness,\n type: source.type,\n height: source.height,\n baseHeight: source.baseHeight,\n });\n out = edit.floor;\n connectorIds.push(...edit.result.wallIds);\n issues.push(...edit.issues);\n });\n\n // 4. An end that was a plain corner is now a straight seam. Dissolving it is what\n // makes detaching a wall with nothing attached to it a no-op on the drawing.\n const dissolvedNodeIds: string[] = [];\n ends.forEach((nodeId, index) => {\n if (nodeIds[index] === nodeId) return;\n const edit = dissolveNode(out, nodeId);\n if (!edit.result) return;\n out = edit.floor;\n dissolvedNodeIds.push(nodeId);\n issues.push(...edit.issues);\n });\n\n return { floor: out, result: { nodeIds, connectorIds, dissolvedNodeIds }, issues };\n}\n\n// ─── weldShortWalls ────────────────────────────────────────────────────────────\n\n/**\n * Collapses every wall shorter than `minLength` by merging its two ends together.\n *\n * Squashing a wall to nothing is the one thing a drag can do that the model forbids, and\n * it is easy to do by accident: pushing a wall back onto the line it was detached from,\n * or dragging a corner past the one next to it. Deleting the short wall is the wrong\n * repair — it leaves two nodes sitting on the same point with the plan split between\n * them, which reads as two corners stacked on top of each other and derives as two\n * rooms. Merging is lossless, since the two ends are within `minLength` of each other by\n * definition.\n *\n * The end with more walls on it survives, so the corner that was already there keeps its\n * position and the one that arrived is the one that gives way.\n */\nexport function weldShortWalls(\n floor: PlanFloor,\n minLength: number = MIN_WALL_LENGTH,\n): PlanEdit<{ weldedWallIds: string[] }> {\n let out = floor;\n const weldedWallIds: string[] = [];\n const issues: PlanIssue[] = [];\n\n // Re-scan rather than iterate: one weld moves nodes, so it can shorten another wall to\n // nothing in turn. Bounded by the wall count, since every pass removes at least one.\n for (let guard = Object.keys(floor.walls).length; guard > 0; guard--) {\n const short = Object.values(out.walls).find((w) => {\n if (w.a === w.b) return false;\n const a = out.nodes[w.a];\n const b = out.nodes[w.b];\n return a && b && dist(a, b) < minLength;\n });\n if (!short) break;\n\n const keep = wallsAtNode(out, short.b).length > wallsAtNode(out, short.a).length ? short.b : short.a;\n const edit = mergeNodes(out, keep, keep === short.a ? short.b : short.a);\n if (edit.floor === out) break;\n out = edit.floor;\n weldedWallIds.push(short.id);\n issues.push(...edit.issues);\n }\n\n return { floor: out, result: { weldedWallIds }, issues };\n}\n\n// ─── removeWall / moveNode ─────────────────────────────────────────────────────\n\nexport function removeWall(\n floor: PlanFloor,\n wallId: string,\n opts: { pruneOrphanNodes?: boolean; dissolveCollinear?: boolean } = {},\n): PlanEdit<{ removedNodeIds: string[]; dissolvedWallIds: string[] }> {\n const { pruneOrphanNodes = true, dissolveCollinear = true } = opts;\n const wall = floor.walls[wallId];\n if (!wall) return { floor, result: { removedNodeIds: [], dissolvedWallIds: [] }, issues: [] };\n\n let next = cloneFloor(floor);\n delete next.walls[wallId];\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === wallId) delete next.openings[opening.id];\n }\n\n const removedNodeIds: string[] = [];\n const dissolvedWallIds: string[] = [];\n const issues: PlanIssue[] = [];\n\n for (const endpoint of [wall.a, wall.b]) {\n const degree = wallsAtNode(next, endpoint).length;\n if (degree === 0 && pruneOrphanNodes) {\n delete next.nodes[endpoint];\n removedNodeIds.push(endpoint);\n } else if (degree === 2 && dissolveCollinear) {\n // The natural inverse of the split that created this seam.\n const edit = dissolveNode(next, endpoint);\n if (edit.result) {\n next = edit.floor;\n dissolvedWallIds.push(edit.result.wallId);\n removedNodeIds.push(endpoint);\n issues.push(...edit.issues);\n }\n }\n }\n\n return { floor: next, result: { removedNodeIds, dissolvedWallIds }, issues };\n}\n\nexport function moveNode(floor: PlanFloor, nodeId: string, to: PlanPoint): PlanEdit {\n const node = floor.nodes[nodeId];\n if (!node) return { floor, result: undefined, issues: [] };\n const next = cloneFloor(floor);\n next.nodes[nodeId] = { ...node, x: to.x, y: to.y };\n return { floor: next, result: undefined, issues: [] };\n}\n\n/**\n * Translates every node, and every room anchor with it.\n *\n * Room matching does not depend on this (it is primarily wall-id based), but a plan\n * that is dragged and then saved without a derive should still have sane anchors.\n */\nexport function transformPlan(floor: PlanFloor, dx: number, dy: number): PlanFloor {\n const next = cloneFloor(floor);\n for (const node of Object.values(floor.nodes)) {\n next.nodes[node.id] = { ...node, x: node.x + dx, y: node.y + dy };\n }\n for (const room of Object.values(floor.rooms)) {\n next.rooms[room.id] = { ...room, anchor: { x: room.anchor.x + dx, y: room.anchor.y + dy } };\n }\n return next;\n}\n\n/**\n * Multiplies every coordinate and dimension by `factor`.\n *\n * The one place a scale factor belongs: converting a unitless legacy plan into the\n * module's millimetre invariant, once, at the import boundary. The caller picks the\n * factor, because nothing in the old data says what it should be.\n */\nexport function scalePlan(floor: PlanFloor, factor: number): PlanFloor {\n const next = cloneFloor(floor);\n for (const node of Object.values(floor.nodes)) {\n next.nodes[node.id] = { ...node, x: node.x * factor, y: node.y * factor };\n }\n for (const wall of Object.values(floor.walls)) {\n next.walls[wall.id] = {\n ...wall,\n thickness: wall.thickness * factor,\n height: wall.height === undefined ? undefined : wall.height * factor,\n baseHeight: wall.baseHeight === undefined ? undefined : wall.baseHeight * factor,\n };\n }\n for (const opening of Object.values(floor.openings)) {\n next.openings[opening.id] = {\n ...opening,\n offset: opening.offset * factor,\n width: opening.width * factor,\n sill: opening.sill * factor,\n head: opening.head * factor,\n };\n }\n for (const room of Object.values(floor.rooms)) {\n next.rooms[room.id] = {\n ...room,\n anchor: { x: room.anchor.x * factor, y: room.anchor.y * factor },\n area: room.area * factor * factor,\n };\n }\n return next;\n}\n\n// ─── Openings ──────────────────────────────────────────────────────────────────\n\nexport function addOpening(floor: PlanFloor, opening: Omit<PlanOpening, 'id'>): PlanEdit<{ openingId: string | null }> {\n const wall = floor.walls[opening.wallId];\n if (!wall) return { floor, result: { openingId: null }, issues: [] };\n\n const len = wallLength(floor, wall);\n const width = Math.min(opening.width, len - 2);\n if (width < MIN_OPENING_WIDTH) {\n return {\n floor,\n result: { openingId: null },\n issues: [\n issue(PlanIssueKind.OpeningDropped, 'That wall is too short for an opening.', {\n wallIds: [wall.id],\n }),\n ],\n };\n }\n\n const offset = Math.min(Math.max(opening.offset, width / 2), len - width / 2);\n const next = cloneFloor(floor);\n const id = newId('o');\n next.openings[id] = { ...opening, id, offset, width };\n return { floor: next, result: { openingId: id }, issues: [] };\n}\n\nexport function updateOpening(\n floor: PlanFloor,\n openingId: string,\n patch: Partial<Omit<PlanOpening, 'id' | 'wallId'>>,\n): PlanEdit {\n const opening = floor.openings[openingId];\n if (!opening) return { floor, result: undefined, issues: [] };\n const wall = floor.walls[opening.wallId];\n if (!wall) return { floor, result: undefined, issues: [] };\n\n const len = wallLength(floor, wall);\n const merged = { ...opening, ...patch };\n const width = Math.min(Math.max(merged.width, MIN_OPENING_WIDTH), Math.max(len - 2, MIN_OPENING_WIDTH));\n const offset = Math.min(Math.max(merged.offset, width / 2), Math.max(len - width / 2, width / 2));\n\n const next = cloneFloor(floor);\n next.openings[openingId] = { ...merged, width, offset };\n return { floor: next, result: undefined, issues: [] };\n}\n\nexport function removeOpening(floor: PlanFloor, openingId: string): PlanEdit {\n if (!floor.openings[openingId]) return { floor, result: undefined, issues: [] };\n const next = cloneFloor(floor);\n delete next.openings[openingId];\n return { floor: next, result: undefined, issues: [] };\n}\n\n// ─── Validation and cleanup ────────────────────────────────────────────────────\n\n/**\n * Reports every way the graph currently violates the planar invariant.\n *\n * O(W²), so run it in tests and in development, not on every keystroke.\n */\nexport function validatePlan(floor: PlanFloor): PlanIssue[] {\n const issues: PlanIssue[] = [];\n const walls = Object.values(floor.walls);\n\n for (const wall of walls) {\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (wall.a === wall.b) {\n issues.push(\n issue(PlanIssueKind.SelfLoopWall, 'A wall starts and ends at the same node.', { wallIds: [wall.id] }),\n );\n continue;\n }\n if (!a || !b) {\n issues.push(issue(PlanIssueKind.ZeroLengthWall, 'A wall references a missing node.', { wallIds: [wall.id] }));\n continue;\n }\n if (dist(a, b) < MIN_WALL_LENGTH) {\n issues.push(\n issue(PlanIssueKind.ZeroLengthWall, 'A wall is shorter than the minimum length.', { wallIds: [wall.id] }),\n );\n }\n }\n\n const pairSeen = new Map<string, string>();\n for (const wall of walls) {\n const key = wall.a < wall.b ? `${wall.a}|${wall.b}` : `${wall.b}|${wall.a}`;\n const prior = pairSeen.get(key);\n if (prior) {\n issues.push(\n issue(PlanIssueKind.DuplicateWall, 'Two walls connect the same pair of nodes.', {\n wallIds: [prior, wall.id],\n }),\n );\n } else {\n pairSeen.set(key, wall.id);\n }\n }\n\n const nodes = Object.values(floor.nodes);\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i + 1; j < nodes.length; j++) {\n if (dist(nodes[i], nodes[j]) < EPS_COINCIDENT) {\n issues.push(\n issue(PlanIssueKind.CoincidentNodes, 'Two nodes occupy the same position.', {\n nodeIds: [nodes[i].id, nodes[j].id],\n }),\n );\n }\n }\n }\n\n for (let i = 0; i < walls.length; i++) {\n for (let j = i + 1; j < walls.length; j++) {\n const w1 = walls[i];\n const w2 = walls[j];\n const a = floor.nodes[w1.a];\n const b = floor.nodes[w1.b];\n const c = floor.nodes[w2.a];\n const d = floor.nodes[w2.b];\n if (!a || !b || !c || !d) continue;\n const hit = segmentIntersection(a, b, c, d);\n if (hit.kind === 'proper') {\n issues.push(\n issue(PlanIssueKind.UnsplitCrossing, 'Two walls cross with no node at the intersection.', {\n wallIds: [w1.id, w2.id],\n }),\n );\n } else if (hit.kind === 'collinearOverlap') {\n issues.push(\n issue(PlanIssueKind.OverlappingWalls, 'Two walls overlap along the same line.', {\n wallIds: [w1.id, w2.id],\n }),\n );\n }\n }\n }\n\n for (const wall of walls) {\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) continue;\n for (const node of nodes) {\n if (node.id === wall.a || node.id === wall.b) continue;\n const r = pointToSegment(node, a, b);\n if (r.dist < EPS_COINCIDENT && r.t > 0 && r.t < 1) {\n issues.push(\n issue(PlanIssueKind.UnsplitNodeOnWall, 'A node sits on a wall that was never split there.', {\n wallIds: [wall.id],\n nodeIds: [node.id],\n }),\n );\n }\n }\n }\n\n for (const opening of Object.values(floor.openings)) {\n if (!floor.walls[opening.wallId]) {\n issues.push(\n issue(PlanIssueKind.DanglingOpening, 'An opening references a wall that no longer exists.', {\n openingIds: [opening.id],\n }),\n );\n }\n }\n\n const referenced = new Set<string>();\n for (const wall of walls) {\n referenced.add(wall.a);\n referenced.add(wall.b);\n }\n for (const node of nodes) {\n if (!referenced.has(node.id)) {\n issues.push(issue(PlanIssueKind.OrphanNode, 'A node has no walls.', { nodeIds: [node.id] }));\n }\n }\n\n return issues;\n}\n\n/**\n * Removes what validation can safely remove: degenerate walls, orphan nodes, dangling\n * openings, and duplicate walls. Idempotent.\n *\n * Deliberately does not touch unsplit crossings: fixing one changes the room structure,\n * which is the user's call, not a cleanup pass's.\n */\nexport function cleanupPlan(floor: PlanFloor): PlanEdit<PlanIssue[]> {\n const fixed: PlanIssue[] = [];\n\n // Welding comes first, and is why the sweep below only ever sees walls that are\n // degenerate for some other reason: a wall squashed to nothing has two perfectly good\n // ends, and deleting it would leave them stacked on the same point.\n const welded = weldShortWalls(floor);\n const next = cloneFloor(welded.floor);\n for (const wallId of welded.result.weldedWallIds) {\n fixed.push(\n issue(PlanIssueKind.ZeroLengthWall, 'Welded the two ends of a wall with no length.', {\n wallIds: [wallId],\n }),\n );\n }\n\n for (const wall of Object.values(next.walls)) {\n const a = next.nodes[wall.a];\n const b = next.nodes[wall.b];\n if (wall.a === wall.b || !a || !b || dist(a, b) < MIN_WALL_LENGTH) {\n delete next.walls[wall.id];\n fixed.push(issue(PlanIssueKind.ZeroLengthWall, 'Removed a degenerate wall.', { wallIds: [wall.id] }));\n }\n }\n\n const pairSeen = new Map<string, PlanWall>();\n for (const wall of Object.values(next.walls)) {\n const key = wall.a < wall.b ? `${wall.a}|${wall.b}` : `${wall.b}|${wall.a}`;\n const prior = pairSeen.get(key);\n if (!prior) {\n pairSeen.set(key, wall);\n continue;\n }\n const keep = wall.thickness >= prior.thickness ? wall : prior;\n const drop = keep === wall ? prior : wall;\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === drop.id) next.openings[opening.id] = { ...opening, wallId: keep.id };\n }\n delete next.walls[drop.id];\n pairSeen.set(key, keep);\n fixed.push(issue(PlanIssueKind.DuplicateWall, 'Removed a duplicate wall.', { wallIds: [drop.id] }));\n }\n\n for (const opening of Object.values(next.openings)) {\n if (!next.walls[opening.wallId]) {\n delete next.openings[opening.id];\n fixed.push(\n issue(PlanIssueKind.DanglingOpening, 'Removed an opening with no wall.', {\n openingIds: [opening.id],\n }),\n );\n }\n }\n\n // One pass to count degrees, rather than scanning every wall per node: the naive form\n // is O(nodes x walls), which is the dominant cost on a large plan.\n const referenced = new Set<string>();\n for (const wall of Object.values(next.walls)) {\n referenced.add(wall.a);\n referenced.add(wall.b);\n }\n for (const node of Object.values(next.nodes)) {\n if (!referenced.has(node.id)) {\n delete next.nodes[node.id];\n fixed.push(issue(PlanIssueKind.OrphanNode, 'Removed a node with no walls.', { nodeIds: [node.id] }));\n }\n }\n\n return { floor: next, result: fixed, issues: fixed };\n}\n\nexport { wallLength, wallsAtNode, findWallBetween };\n"],"mappings":"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"}
1
+ {"version":3,"file":"floorPlan.graph.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.graph.ts"],"sourcesContent":["/**\n * Graph maintenance: the operations that keep the wall graph a valid planar embedding\n * while the user draws.\n *\n * The invariant every function here protects: no two walls may cross without a node at\n * the intersection, and no node may lie on a wall's interior without that wall being\n * split there. Break either and the face walk silently merges two rooms into one\n * figure-eight face, with no error anywhere.\n *\n * Every operation is pure and returns a new floor, for direct use as React state.\n */\n\nimport {\n EPS_ANGLE,\n EPS_COINCIDENT,\n MIN_OPENING_WIDTH,\n MIN_WALL_LENGTH,\n cross,\n dist,\n pointToSegment,\n projectOnSegment,\n segmentIntersection,\n} from './floorPlan.geometry';\nimport { PlanIssueKind, WallType } from './floorPlan.types';\nimport type { PlanEdit, PlanFloor, PlanIssue, PlanNode, PlanOpening, PlanPoint, PlanWall } from './floorPlan.types';\n\n// ─── Ids ───────────────────────────────────────────────────────────────────────\n\nlet idSeq = 0;\n\n/**\n * Ids are deliberately non-numeric strings, so `Record` iteration keeps insertion\n * order (JavaScript reorders integer-like keys), which is what makes derivation\n * reproducible.\n */\nexport function newId(prefix: string): string {\n idSeq += 1;\n const rand =\n typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function'\n ? crypto.randomUUID().slice(0, 8)\n : Math.random().toString(36).slice(2, 10);\n return `${prefix}_${rand}${idSeq.toString(36)}`;\n}\n\n/** Test-only: makes generated ids reproducible within a single test. */\nexport function __resetIdSeq(): void {\n idSeq = 0;\n}\n\n// ─── Internals ─────────────────────────────────────────────────────────────────\n\nfunction cloneFloor(floor: PlanFloor): PlanFloor {\n return {\n ...floor,\n nodes: { ...floor.nodes },\n walls: { ...floor.walls },\n openings: { ...floor.openings },\n rooms: { ...floor.rooms },\n };\n}\n\nfunction issue(kind: PlanIssueKind, message: string, extra: Partial<PlanIssue> = {}): PlanIssue {\n return { kind, message, ...extra };\n}\n\nfunction wallLength(floor: PlanFloor, wall: PlanWall): number {\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) return 0;\n return dist(a, b);\n}\n\nfunction wallsAtNode(floor: PlanFloor, nodeId: string): PlanWall[] {\n return Object.values(floor.walls).filter((w) => w.a === nodeId || w.b === nodeId);\n}\n\nfunction findWallBetween(floor: PlanFloor, a: string, b: string): PlanWall | null {\n for (const w of Object.values(floor.walls)) {\n if ((w.a === a && w.b === b) || (w.a === b && w.b === a)) return w;\n }\n return null;\n}\n\n// ─── Node spatial hash ─────────────────────────────────────────────────────────\n\n/**\n * Bucket size for the node hash, in millimetres. Any lookup checks the 3x3\n * neighbourhood, so this only has to exceed the largest snap tolerance in world units.\n */\nconst HASH_CELL = 250;\n\nfunction hashKey(x: number, y: number): string {\n return `${Math.round(x / HASH_CELL)}|${Math.round(y / HASH_CELL)}`;\n}\n\nfunction buildNodeHash(floor: PlanFloor): Map<string, PlanNode[]> {\n const map = new Map<string, PlanNode[]>();\n for (const node of Object.values(floor.nodes)) {\n const key = hashKey(node.x, node.y);\n const list = map.get(key);\n if (list) list.push(node);\n else map.set(key, [node]);\n }\n return map;\n}\n\n/** Nearest existing node within `tol`, using the spatial hash. */\nexport function findNodeNear(floor: PlanFloor, p: PlanPoint, tol: number): PlanNode | null {\n const hash = buildNodeHash(floor);\n const cx = Math.round(p.x / HASH_CELL);\n const cy = Math.round(p.y / HASH_CELL);\n let best: PlanNode | null = null;\n let bestDist = tol;\n const span = Math.max(1, Math.ceil(tol / HASH_CELL));\n for (let dx = -span; dx <= span; dx++) {\n for (let dy = -span; dy <= span; dy++) {\n for (const node of hash.get(`${cx + dx}|${cy + dy}`) ?? []) {\n const d = dist(p, node);\n if (d <= bestDist) {\n best = node;\n bestDist = d;\n }\n }\n }\n }\n return best;\n}\n\n/** Nearest wall whose centreline passes within `tol` of `p`. */\nexport function findWallNear(\n floor: PlanFloor,\n p: PlanPoint,\n tol: number,\n exclude?: ReadonlySet<string>,\n): { wall: PlanWall; t: number; point: PlanPoint; dist: number } | null {\n let best: { wall: PlanWall; t: number; point: PlanPoint; dist: number } | null = null;\n for (const wall of Object.values(floor.walls)) {\n if (exclude?.has(wall.id)) continue;\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) continue;\n const r = pointToSegment(p, a, b);\n if (r.dist <= tol && (!best || r.dist < best.dist)) {\n best = { wall, t: r.t, point: r.point, dist: r.dist };\n }\n }\n return best;\n}\n\n// ─── splitWall ─────────────────────────────────────────────────────────────────\n\nexport interface SplitWallResult {\n nodeId: string;\n wallIds: [string, string] | null;\n droppedOpeningIds: string[];\n}\n\n/**\n * Splits a wall at a point or parameter, returning the node at the cut.\n *\n * Refuses to cut within `MIN_WALL_LENGTH` of either end, returning that endpoint's\n * existing node instead. That single rule is what keeps zero-length walls out of the\n * graph entirely, which in turn is what stops the angular sort from being fed a\n * direction-less dart.\n */\nexport function splitWall(floor: PlanFloor, wallId: string, at: PlanPoint | number): PlanEdit<SplitWallResult> {\n const wall = floor.walls[wallId];\n if (!wall) {\n return { floor, result: { nodeId: '', wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) {\n return { floor, result: { nodeId: '', wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n\n const len = dist(a, b);\n const point = typeof at === 'number' ? { x: a.x + (b.x - a.x) * at, y: a.y + (b.y - a.y) * at } : at;\n // Project exactly, so the two children stay perfectly collinear and dissolveNode can\n // undo the split cleanly later.\n const exact = projectOnSegment(point, a, b);\n const fromA = dist(a, exact);\n\n if (fromA < MIN_WALL_LENGTH) {\n return { floor, result: { nodeId: wall.a, wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n if (len - fromA < MIN_WALL_LENGTH) {\n return { floor, result: { nodeId: wall.b, wallIds: null, droppedOpeningIds: [] }, issues: [] };\n }\n\n const next = cloneFloor(floor);\n const nodeId = newId('n');\n next.nodes[nodeId] = { id: nodeId, x: exact.x, y: exact.y };\n\n const firstId = newId('w');\n const secondId = newId('w');\n const base = { thickness: wall.thickness, type: wall.type, height: wall.height, baseHeight: wall.baseHeight };\n next.walls[firstId] = { ...base, id: firstId, a: wall.a, b: nodeId };\n next.walls[secondId] = { ...base, id: secondId, a: nodeId, b: wall.b };\n delete next.walls[wallId];\n\n // Reassign openings by the side their CENTRE falls on. An opening straddling the cut\n // is a genuine conflict: move it wholly into that child and clamp it, or drop it and\n // say so. Silently deleting a window is not acceptable.\n const droppedOpeningIds: string[] = [];\n const issues: PlanIssue[] = [];\n for (const opening of Object.values(floor.openings)) {\n if (opening.wallId !== wallId) continue;\n const intoFirst = opening.offset <= fromA;\n const childId = intoFirst ? firstId : secondId;\n const childLen = intoFirst ? fromA : len - fromA;\n const offset = intoFirst ? opening.offset : opening.offset - fromA;\n\n const maxWidth = Math.min(opening.width, childLen - 2, offset * 2, (childLen - offset) * 2);\n if (maxWidth < MIN_OPENING_WIDTH) {\n delete next.openings[opening.id];\n droppedOpeningIds.push(opening.id);\n issues.push(\n issue(PlanIssueKind.OpeningDropped, 'An opening was removed: the wall it sat on became too short for it.', {\n openingIds: [opening.id],\n wallIds: [wallId],\n }),\n );\n continue;\n }\n next.openings[opening.id] = { ...opening, wallId: childId, offset, width: maxWidth };\n }\n\n return { floor: next, result: { nodeId, wallIds: [firstId, secondId], droppedOpeningIds }, issues };\n}\n\n// ─── resolveNodeAt ─────────────────────────────────────────────────────────────\n\nexport interface ResolveNodeResult {\n nodeId: string;\n createdNode: boolean;\n splitWallId: string | null;\n}\n\n/**\n * Returns the node to use at `p`: an existing one within `tol`, a new one created by\n * splitting a wall that passes under `p`, or a brand new free-standing node.\n */\nexport function resolveNodeAt(floor: PlanFloor, p: PlanPoint, tol: number): PlanEdit<ResolveNodeResult> {\n const existing = findNodeNear(floor, p, tol);\n if (existing) {\n return { floor, result: { nodeId: existing.id, createdNode: false, splitWallId: null }, issues: [] };\n }\n\n const onWall = findWallNear(floor, p, tol);\n if (onWall) {\n const split = splitWall(floor, onWall.wall.id, onWall.point);\n if (split.result.nodeId) {\n return {\n floor: split.floor,\n result: {\n nodeId: split.result.nodeId,\n createdNode: split.result.wallIds !== null,\n splitWallId: split.result.wallIds ? onWall.wall.id : null,\n },\n issues: split.issues,\n };\n }\n }\n\n const next = cloneFloor(floor);\n const nodeId = newId('n');\n next.nodes[nodeId] = { id: nodeId, x: p.x, y: p.y };\n return { floor: next, result: { nodeId, createdNode: true, splitWallId: null }, issues: [] };\n}\n\n// ─── addWall ───────────────────────────────────────────────────────────────────\n\nexport type WallAttrs = Pick<PlanWall, 'thickness' | 'type'> & Partial<Pick<PlanWall, 'height' | 'baseHeight'>>;\n\nexport const DEFAULT_WALL_ATTRS: WallAttrs = { thickness: 200, type: WallType.Interior };\n\ninterface Cut {\n t: number;\n nodeId: string | null;\n /** Set while the node does not exist yet because its wall has not been split. */\n pending?: { wallId: string; s: number };\n}\n\n/**\n * Adds a wall from `a` to `b`, splitting anything it crosses so the graph stays planar.\n *\n * Collect-then-apply, in two phases: the naive version splits walls while iterating\n * over walls, which both invalidates the iteration and reparameterises the very\n * segments it is about to test.\n */\nexport function addWall(\n floor: PlanFloor,\n a: PlanPoint,\n b: PlanPoint,\n attrs: WallAttrs = DEFAULT_WALL_ATTRS,\n tol: number = EPS_COINCIDENT,\n): PlanEdit<{ wallIds: string[]; nodeIds: string[] }> {\n const issues: PlanIssue[] = [];\n if (dist(a, b) < MIN_WALL_LENGTH) {\n return { floor, result: { wallIds: [], nodeIds: [] }, issues };\n }\n\n // 1. Endpoints. Each may reuse a node, split a wall, or create a node.\n const startEdit = resolveNodeAt(floor, a, tol);\n let work = startEdit.floor;\n issues.push(...startEdit.issues);\n const endEdit = resolveNodeAt(work, b, tol);\n work = endEdit.floor;\n issues.push(...endEdit.issues);\n\n const na = startEdit.result.nodeId;\n const nb = endEdit.result.nodeId;\n if (na === nb) return { floor, result: { wallIds: [], nodeIds: [] }, issues };\n\n const A = work.nodes[na];\n const B = work.nodes[nb];\n const len = dist(A, B);\n if (len < MIN_WALL_LENGTH) return { floor, result: { wallIds: [], nodeIds: [] }, issues };\n\n // 2. COLLECT. Nothing is mutated in this phase.\n const cuts: Cut[] = [\n { t: 0, nodeId: na },\n { t: 1, nodeId: nb },\n ];\n const splits = new Map<string, number[]>();\n const overlaps: Array<[number, number]> = [];\n\n const paramAlong = (p: PlanPoint): number => pointToSegment(p, A, B).t;\n\n for (const wall of Object.values(work.walls)) {\n const wa = work.nodes[wall.a];\n const wb = work.nodes[wall.b];\n if (!wa || !wb) continue;\n\n const hit = segmentIntersection(A, B, wa, wb, tol);\n\n if (hit.kind === 'collinearOverlap') {\n const t0 = paramAlong(wa);\n const t1 = paramAlong(wb);\n overlaps.push([Math.min(t0, t1), Math.max(t0, t1)]);\n // Endpoints of the overlapping wall that fall strictly inside AB still need cuts,\n // or the new wall would run straight past them.\n for (const [node, t] of [\n [wa, t0],\n [wb, t1],\n ] as const) {\n if (t * len > MIN_WALL_LENGTH && (1 - t) * len > MIN_WALL_LENGTH) {\n cuts.push({ t, nodeId: node.id });\n }\n }\n continue;\n }\n\n if (hit.kind === 'proper' && hit.t !== undefined && hit.s !== undefined) {\n const list = splits.get(wall.id);\n if (list) list.push(hit.s);\n else splits.set(wall.id, [hit.s]);\n cuts.push({ t: hit.t, nodeId: null, pending: { wallId: wall.id, s: hit.s } });\n continue;\n }\n\n if (hit.kind === 'touch' && hit.t !== undefined && hit.s !== undefined) {\n // A T junction where one of the wall's own endpoints sits on AB: reuse it.\n const atWallStart = hit.s <= 0.5;\n const endpoint = atWallStart ? wa : wb;\n const tOnAb = paramAlong(endpoint);\n if (\n pointToSegment(endpoint, A, B).dist <= tol &&\n tOnAb * len > MIN_WALL_LENGTH &&\n (1 - tOnAb) * len > MIN_WALL_LENGTH\n ) {\n cuts.push({ t: tOnAb, nodeId: endpoint.id });\n }\n }\n }\n\n // 3. Nodes lying on AB that no crossing test found. NOT redundant with step 2: a node\n // whose incident walls all run away from AB is invisible to every crossing test, yet\n // failing to cut AB there leaves a node on a wall interior, which silently merges the\n // two rooms either side of it.\n for (const node of Object.values(work.nodes)) {\n if (node.id === na || node.id === nb) continue;\n const r = pointToSegment(node, A, B);\n if (r.dist > tol) continue;\n if (r.t * len <= MIN_WALL_LENGTH || (1 - r.t) * len <= MIN_WALL_LENGTH) continue;\n cuts.push({ t: r.t, nodeId: node.id });\n }\n\n // 4. APPLY splits, per wall, in DESCENDING parameter order so that earlier\n // parameters stay valid as later ones are consumed.\n for (const [wallId, params] of splits) {\n const sorted = [...params].sort((x, y) => y - x);\n let currentWallId = wallId;\n const remaining = new Set(sorted);\n for (const s of sorted) {\n const target = work.walls[currentWallId];\n if (!target) break;\n const wa = work.nodes[target.a];\n const wb = work.nodes[target.b];\n if (!wa || !wb) break;\n // Re-project onto the wall as it stands now, rather than reusing the original\n // parameter, which the previous split may have reparameterised.\n const original = floor.walls[wallId];\n const oa = work.nodes[original?.a ?? target.a] ?? wa;\n const ob = work.nodes[original?.b ?? target.b] ?? wb;\n const worldPoint = { x: oa.x + (ob.x - oa.x) * s, y: oa.y + (ob.y - oa.y) * s };\n const edit = splitWall(work, currentWallId, worldPoint);\n work = edit.floor;\n issues.push(...edit.issues);\n remaining.delete(s);\n for (const cut of cuts) {\n if (cut.pending && cut.pending.wallId === wallId && cut.pending.s === s) {\n cut.nodeId = edit.result.nodeId;\n cut.pending = undefined;\n }\n }\n // Continue splitting whichever child still holds the remaining parameters.\n if (edit.result.wallIds) {\n const [first, second] = edit.result.wallIds;\n const nextS = Math.max(...[...remaining], -1);\n currentWallId = nextS >= 0 && nextS > s ? second : first;\n }\n }\n }\n\n // 5. Chain the cuts into walls.\n const resolved = cuts.filter((c): c is Cut & { nodeId: string } => Boolean(c.nodeId));\n resolved.sort((x, y) => x.t - y.t);\n\n const chain: Array<Cut & { nodeId: string }> = [];\n for (const cut of resolved) {\n const last = chain[chain.length - 1];\n if (!last) {\n chain.push(cut);\n continue;\n }\n if (last.nodeId === cut.nodeId) continue;\n if ((cut.t - last.t) * len < MIN_WALL_LENGTH) {\n // Too close to be a separate wall. Prefer whichever end is an endpoint of AB.\n if (cut.t >= 1 - 1e-9) chain[chain.length - 1] = cut;\n continue;\n }\n chain.push(cut);\n }\n\n const createdWallIds: string[] = [];\n for (let i = 0; i + 1 < chain.length; i++) {\n const from = chain[i];\n const to = chain[i + 1];\n const midT = (from.t + to.t) / 2;\n if (overlaps.some(([lo, hi]) => midT > lo + 1e-9 && midT < hi - 1e-9)) {\n // Already walled. Do not create a duplicate, and do not rewrite the existing\n // wall's attributes from a stroke that was aimed elsewhere.\n continue;\n }\n if (findWallBetween(work, from.nodeId, to.nodeId)) continue;\n const wa = work.nodes[from.nodeId];\n const wb = work.nodes[to.nodeId];\n if (!wa || !wb || dist(wa, wb) < MIN_WALL_LENGTH) continue;\n\n const id = newId('w');\n work = { ...work, walls: { ...work.walls, [id]: { ...attrs, id, a: from.nodeId, b: to.nodeId } } };\n createdWallIds.push(id);\n }\n\n if (createdWallIds.length === 0 && overlaps.length > 0) {\n issues.push(issue(PlanIssueKind.DuplicateWall, 'A wall already covers that span, so nothing was added.'));\n }\n\n return {\n floor: work,\n result: { wallIds: createdWallIds, nodeIds: chain.map((c) => c.nodeId) },\n issues,\n };\n}\n\n/** Draws the four walls of an axis-aligned rectangle, welding onto anything already there. */\nexport function addRect(\n floor: PlanFloor,\n corner: PlanPoint,\n opposite: PlanPoint,\n attrs: WallAttrs = DEFAULT_WALL_ATTRS,\n tol: number = EPS_COINCIDENT,\n): PlanEdit<{ wallIds: string[] }> {\n const x0 = Math.min(corner.x, opposite.x);\n const x1 = Math.max(corner.x, opposite.x);\n const y0 = Math.min(corner.y, opposite.y);\n const y1 = Math.max(corner.y, opposite.y);\n if (x1 - x0 < MIN_WALL_LENGTH || y1 - y0 < MIN_WALL_LENGTH) {\n return { floor, result: { wallIds: [] }, issues: [] };\n }\n\n const corners: PlanPoint[] = [\n { x: x0, y: y0 },\n { x: x1, y: y0 },\n { x: x1, y: y1 },\n { x: x0, y: y1 },\n ];\n\n let work = floor;\n const wallIds: string[] = [];\n const issues: PlanIssue[] = [];\n for (let i = 0; i < 4; i++) {\n const edit = addWall(work, corners[i], corners[(i + 1) % 4], attrs, tol);\n work = edit.floor;\n wallIds.push(...edit.result.wallIds);\n issues.push(...edit.issues);\n }\n return { floor: work, result: { wallIds }, issues };\n}\n\n// ─── mergeNodes ────────────────────────────────────────────────────────────────\n\n/**\n * Merges `removeId` into `keepId`, as when a node is dragged onto another.\n *\n * Order matters, and step 3 is mandatory rather than cosmetic: a duplicate wall between\n * the same pair of nodes is exactly the identical-angle degeneracy that corrupts the\n * face walk's angular sort.\n */\nexport function mergeNodes(floor: PlanFloor, keepId: string, removeId: string): PlanEdit<{ removedWallIds: string[] }> {\n if (keepId === removeId || !floor.nodes[keepId] || !floor.nodes[removeId]) {\n return { floor, result: { removedWallIds: [] }, issues: [] };\n }\n\n const next = cloneFloor(floor);\n const removedWallIds: string[] = [];\n const issues: PlanIssue[] = [];\n\n // 1. Rewire.\n for (const wall of Object.values(next.walls)) {\n if (wall.a === removeId) next.walls[wall.id] = { ...next.walls[wall.id], a: keepId };\n if (wall.b === removeId) next.walls[wall.id] = { ...next.walls[wall.id], b: keepId };\n }\n\n // 2. Drop self-loops, and their openings with them.\n for (const wall of Object.values(next.walls)) {\n if (wall.a !== wall.b) continue;\n delete next.walls[wall.id];\n removedWallIds.push(wall.id);\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === wall.id) delete next.openings[opening.id];\n }\n }\n\n // 3. Deduplicate walls that now share the same unordered node pair.\n const seen = new Map<string, PlanWall>();\n for (const wall of Object.values(next.walls)) {\n const key = wall.a < wall.b ? `${wall.a}|${wall.b}` : `${wall.b}|${wall.a}`;\n const prior = seen.get(key);\n if (!prior) {\n seen.set(key, wall);\n continue;\n }\n // Keep the thicker wall, and carry both walls' openings onto it.\n const keep = wall.thickness >= prior.thickness ? wall : prior;\n const drop = keep === wall ? prior : wall;\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === drop.id) {\n next.openings[opening.id] = { ...opening, wallId: keep.id };\n }\n }\n delete next.walls[drop.id];\n removedWallIds.push(drop.id);\n seen.set(key, keep);\n issues.push(\n issue(PlanIssueKind.DuplicateWall, 'Two walls became the same wall and were merged.', {\n wallIds: [keep.id, drop.id],\n }),\n );\n }\n\n // 4. Drop the now-unreferenced node.\n delete next.nodes[removeId];\n\n return { floor: next, result: { removedWallIds }, issues };\n}\n\n// ─── dissolveNode ──────────────────────────────────────────────────────────────\n\nexport interface DissolveNodeOptions {\n /**\n * Rejoin the two walls even when the corner is bent or the walls differ in\n * construction, taking the thicker wall's attributes and rescaling openings onto the\n * shorter merged wall.\n *\n * This is \"delete this corner\" as a user means it. The default, unforced behaviour is\n * the stricter one used by cleanup and by `removeWall`, where dissolving must not\n * change the drawing's geometry at all.\n */\n force?: boolean;\n}\n\n/**\n * Merges the two walls meeting at a degree-2 node back into one, the natural inverse of\n * `splitWall`.\n *\n * Returns `null` unless the node is genuinely a seam: degree exactly 2, both walls\n * identical in construction, and the turn within `EPS_ANGLE` of straight. Pass\n * `{ force: true }` to rejoin a bent corner as well. Never call it mid-drag: it destroys\n * node ids the user may be holding.\n */\nexport function dissolveNode(\n floor: PlanFloor,\n nodeId: string,\n options: DissolveNodeOptions = {},\n): PlanEdit<{ wallId: string } | null> {\n const { force = false } = options;\n const node = floor.nodes[nodeId];\n if (!node) return { floor, result: null, issues: [] };\n\n const incident = wallsAtNode(floor, nodeId);\n if (incident.length !== 2) return { floor, result: null, issues: [] };\n\n const [w1, w2] = incident;\n const sameConstruction =\n w1.thickness === w2.thickness && w1.type === w2.type && w1.height === w2.height && w1.baseHeight === w2.baseHeight;\n if (!sameConstruction && !force) return { floor, result: null, issues: [] };\n\n const far1 = w1.a === nodeId ? w1.b : w1.a;\n const far2 = w2.a === nodeId ? w2.b : w2.a;\n if (far1 === far2) return { floor, result: null, issues: [] };\n\n const p1 = floor.nodes[far1];\n const p2 = floor.nodes[far2];\n if (!p1 || !p2) return { floor, result: null, issues: [] };\n\n const span = dist(p1, p2);\n if (span < MIN_WALL_LENGTH) return { floor, result: null, issues: [] };\n\n if (!force) {\n // Straightness by perpendicular offset rather than raw angle, so the tolerance stays\n // meaningful at any wall length.\n const offset = Math.abs(cross(p1, p2, node)) / span;\n if (offset > Math.max(EPS_COINCIDENT, span * EPS_ANGLE)) {\n return { floor, result: null, issues: [] };\n }\n }\n\n // Forced over a bent corner, the survivor is the thicker of the two, since that is the\n // one whose construction the rest of the plan is more likely to depend on.\n const keep = !sameConstruction && w1.thickness < w2.thickness ? w2 : w1;\n\n const next = cloneFloor(floor);\n const id = newId('w');\n next.walls[id] = {\n id,\n a: far1,\n b: far2,\n thickness: keep.thickness,\n type: keep.type,\n height: keep.height,\n baseHeight: keep.baseHeight,\n };\n\n // Re-express every opening's offset against the merged wall's direction (far1 -> far2).\n const len1 = dist(p1, node);\n const len2 = dist(node, p2);\n // Cutting a bent corner shortens the run, so positions are scaled along it rather than\n // carried over, which would push an opening off the end of its own wall.\n const scale = len1 + len2 > 0 ? span / (len1 + len2) : 1;\n const issues: PlanIssue[] = [];\n\n for (const opening of Object.values(floor.openings)) {\n if (opening.wallId !== w1.id && opening.wallId !== w2.id) continue;\n const onFirst = opening.wallId === w1.id;\n const wall = onFirst ? w1 : w2;\n const startsAtNode = wall.a === nodeId;\n const lenOfWall = wallLength(floor, wall);\n // Distance from the seam, then from the merged wall's own start.\n const fromSeam = startsAtNode ? opening.offset : lenOfWall - opening.offset;\n const alongOriginal = onFirst ? len1 - fromSeam : len1 + fromSeam;\n const offsetOnMerged = alongOriginal * scale;\n\n const width = Math.min(opening.width * scale, span - 2);\n if (width < MIN_OPENING_WIDTH) {\n issues.push(\n issue(PlanIssueKind.OpeningDropped, 'An opening was removed: the wall it sat on became too short for it.', {\n openingIds: [opening.id],\n wallIds: [wall.id],\n }),\n );\n delete next.openings[opening.id];\n continue;\n }\n\n next.openings[opening.id] = {\n ...opening,\n wallId: id,\n width,\n offset: Math.min(Math.max(offsetOnMerged, width / 2), span - width / 2),\n };\n }\n\n delete next.walls[w1.id];\n delete next.walls[w2.id];\n delete next.nodes[nodeId];\n\n return { floor: next, result: { wallId: id }, issues };\n}\n\n// ─── detachWall ────────────────────────────────────────────────────────────────\n\nexport interface DetachWallResult {\n /** The wall's end nodes after the detach, in `[a, b]` order. */\n nodeIds: [string, string];\n /** Connecting walls minted where an end was shared with a neighbour. */\n connectorIds: string[];\n /** Ends that became a straight seam once the wall left, and were dissolved away. */\n dissolvedNodeIds: string[];\n}\n\n/**\n * Pulls a wall off the nodes it shares with its neighbours and moves it by `delta`,\n * leaving a connecting wall behind at each end that was shared.\n *\n * This is the extrude half of dragging a wall. A plain drag moves the shared end nodes,\n * so everything meeting the wall follows it; here the neighbours keep their ends and\n * only the new connectors grow, which is what you want when a partition joins the wall\n * halfway along and should stay put.\n *\n * A free end is only moved: there is nothing there to detach from, and a connector would\n * be zero length. For the same reason `delta` must be at least `MIN_WALL_LENGTH` long —\n * below that the caller should `moveNode` both ends instead.\n *\n * The connector continues whatever was already at the corner (its thickness, type and\n * heights) when exactly one wall was, so pulling a wall off a plain corner redraws\n * exactly as a plain drag would: the seam that leaves behind is straight and is\n * dissolved before returning. At a junction there is no single wall to continue, so the\n * connector takes the dragged wall's own construction.\n */\nexport function detachWall(floor: PlanFloor, wallId: string, delta: PlanPoint): PlanEdit<DetachWallResult | null> {\n const wall = floor.walls[wallId];\n if (!wall || wall.a === wall.b) return { floor, result: null, issues: [] };\n if (Math.hypot(delta.x, delta.y) < MIN_WALL_LENGTH) return { floor, result: null, issues: [] };\n\n const ends: [string, string] = [wall.a, wall.b];\n const nodeIds: [string, string] = [wall.a, wall.b];\n const sources: (PlanWall | null)[] = [null, null];\n const connectorIds: string[] = [];\n const issues: PlanIssue[] = [];\n let out = floor;\n\n // 1. Give the wall its own ends. `resolveNodeAt` rather than a bare node, because the\n // new end often lands in the middle of another wall — the usual case is pushing the\n // shared wall of two rooms sideways, where each end slides along the wall above and\n // below it — and only a split keeps a node off a wall's interior.\n ends.forEach((nodeId, index) => {\n const origin = floor.nodes[nodeId];\n if (!origin) return;\n const to = { x: origin.x + delta.x, y: origin.y + delta.y };\n const others = wallsAtNode(floor, nodeId).filter((w) => w.id !== wallId);\n\n if (others.length === 0) {\n // A free end has nothing to detach from, and a connector there would be a wall\n // between a node and itself.\n const next = cloneFloor(out);\n next.nodes[nodeId] = { ...next.nodes[nodeId], x: to.x, y: to.y };\n out = next;\n return;\n }\n\n const edit = resolveNodeAt(out, to, EPS_COINCIDENT);\n out = edit.floor;\n nodeIds[index] = edit.result.nodeId;\n // The connector continues whatever was already at this corner, so pulling a wall off\n // a plain corner redraws exactly as a plain drag would. At a junction there is no\n // single wall to continue, so it takes the dragged wall's own construction.\n sources[index] = others.length === 1 ? others[0] : wall;\n });\n\n // 2. Move the wall onto them. Its openings ride along untouched: a detach is a pure\n // translation, so the wall keeps its id, its direction and its length.\n const moved = cloneFloor(out);\n moved.walls[wallId] = { ...moved.walls[wallId], a: nodeIds[0], b: nodeIds[1] };\n out = moved;\n\n // 3. Bridge each end back to where it came from, unless a wall already runs there.\n ends.forEach((nodeId, index) => {\n const source = sources[index];\n const from = out.nodes[nodeId];\n const to = out.nodes[nodeIds[index]];\n if (!source || !from || !to) return;\n const edit = addWall(out, from, to, {\n thickness: source.thickness,\n type: source.type,\n height: source.height,\n baseHeight: source.baseHeight,\n });\n out = edit.floor;\n connectorIds.push(...edit.result.wallIds);\n issues.push(...edit.issues);\n });\n\n // 4. An end that was a plain corner is now a straight seam. Dissolving it is what\n // makes detaching a wall with nothing attached to it a no-op on the drawing.\n const dissolvedNodeIds: string[] = [];\n ends.forEach((nodeId, index) => {\n if (nodeIds[index] === nodeId) return;\n const edit = dissolveNode(out, nodeId);\n if (!edit.result) return;\n out = edit.floor;\n dissolvedNodeIds.push(nodeId);\n issues.push(...edit.issues);\n });\n\n return { floor: out, result: { nodeIds, connectorIds, dissolvedNodeIds }, issues };\n}\n\n// ─── weldShortWalls ────────────────────────────────────────────────────────────\n\n/**\n * Collapses every wall shorter than `minLength` by merging its two ends together.\n *\n * Squashing a wall to nothing is the one thing a drag can do that the model forbids, and\n * it is easy to do by accident: pushing a wall back onto the line it was detached from,\n * or dragging a corner past the one next to it. Deleting the short wall is the wrong\n * repair — it leaves two nodes sitting on the same point with the plan split between\n * them, which reads as two corners stacked on top of each other and derives as two\n * rooms. Merging is lossless, since the two ends are within `minLength` of each other by\n * definition.\n *\n * The end with more walls on it survives, so the corner that was already there keeps its\n * position and the one that arrived is the one that gives way.\n */\nexport function weldShortWalls(\n floor: PlanFloor,\n minLength: number = MIN_WALL_LENGTH,\n): PlanEdit<{ weldedWallIds: string[] }> {\n let out = floor;\n const weldedWallIds: string[] = [];\n const issues: PlanIssue[] = [];\n\n // Re-scan rather than iterate: one weld moves nodes, so it can shorten another wall to\n // nothing in turn. Bounded by the wall count, since every pass removes at least one.\n for (let guard = Object.keys(floor.walls).length; guard > 0; guard--) {\n const short = Object.values(out.walls).find((w) => {\n if (w.a === w.b) return false;\n const a = out.nodes[w.a];\n const b = out.nodes[w.b];\n return a && b && dist(a, b) < minLength;\n });\n if (!short) break;\n\n const keep = wallsAtNode(out, short.b).length > wallsAtNode(out, short.a).length ? short.b : short.a;\n const edit = mergeNodes(out, keep, keep === short.a ? short.b : short.a);\n if (edit.floor === out) break;\n out = edit.floor;\n weldedWallIds.push(short.id);\n issues.push(...edit.issues);\n }\n\n return { floor: out, result: { weldedWallIds }, issues };\n}\n\n// ─── removeWall / moveNode ─────────────────────────────────────────────────────\n\nexport function removeWall(\n floor: PlanFloor,\n wallId: string,\n opts: { pruneOrphanNodes?: boolean; dissolveCollinear?: boolean } = {},\n): PlanEdit<{ removedNodeIds: string[]; dissolvedWallIds: string[] }> {\n const { pruneOrphanNodes = true, dissolveCollinear = true } = opts;\n const wall = floor.walls[wallId];\n if (!wall) return { floor, result: { removedNodeIds: [], dissolvedWallIds: [] }, issues: [] };\n\n let next = cloneFloor(floor);\n delete next.walls[wallId];\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === wallId) delete next.openings[opening.id];\n }\n\n const removedNodeIds: string[] = [];\n const dissolvedWallIds: string[] = [];\n const issues: PlanIssue[] = [];\n\n for (const endpoint of [wall.a, wall.b]) {\n const degree = wallsAtNode(next, endpoint).length;\n if (degree === 0 && pruneOrphanNodes) {\n delete next.nodes[endpoint];\n removedNodeIds.push(endpoint);\n } else if (degree === 2 && dissolveCollinear) {\n // The natural inverse of the split that created this seam.\n const edit = dissolveNode(next, endpoint);\n if (edit.result) {\n next = edit.floor;\n dissolvedWallIds.push(edit.result.wallId);\n removedNodeIds.push(endpoint);\n issues.push(...edit.issues);\n }\n }\n }\n\n return { floor: next, result: { removedNodeIds, dissolvedWallIds }, issues };\n}\n\nexport function moveNode(floor: PlanFloor, nodeId: string, to: PlanPoint): PlanEdit {\n const node = floor.nodes[nodeId];\n if (!node) return { floor, result: undefined, issues: [] };\n const next = cloneFloor(floor);\n next.nodes[nodeId] = { ...node, x: to.x, y: to.y };\n return { floor: next, result: undefined, issues: [] };\n}\n\n/**\n * Translates every node, and every room anchor with it.\n *\n * Room matching does not depend on this (it is primarily wall-id based), but a plan\n * that is dragged and then saved without a derive should still have sane anchors.\n */\nexport function transformPlan(floor: PlanFloor, dx: number, dy: number): PlanFloor {\n const next = cloneFloor(floor);\n for (const node of Object.values(floor.nodes)) {\n next.nodes[node.id] = { ...node, x: node.x + dx, y: node.y + dy };\n }\n for (const room of Object.values(floor.rooms)) {\n next.rooms[room.id] = { ...room, anchor: { x: room.anchor.x + dx, y: room.anchor.y + dy } };\n }\n return next;\n}\n\n/**\n * Multiplies every coordinate and dimension by `factor`.\n *\n * The one place a scale factor belongs: converting a unitless legacy plan into the\n * module's millimetre invariant, once, at the import boundary. The caller picks the\n * factor, because nothing in the old data says what it should be.\n */\nexport function scalePlan(floor: PlanFloor, factor: number): PlanFloor {\n const next = cloneFloor(floor);\n for (const node of Object.values(floor.nodes)) {\n next.nodes[node.id] = { ...node, x: node.x * factor, y: node.y * factor };\n }\n for (const wall of Object.values(floor.walls)) {\n next.walls[wall.id] = {\n ...wall,\n thickness: wall.thickness * factor,\n height: wall.height === undefined ? undefined : wall.height * factor,\n baseHeight: wall.baseHeight === undefined ? undefined : wall.baseHeight * factor,\n };\n }\n for (const opening of Object.values(floor.openings)) {\n next.openings[opening.id] = {\n ...opening,\n offset: opening.offset * factor,\n width: opening.width * factor,\n sill: opening.sill * factor,\n head: opening.head * factor,\n };\n }\n for (const room of Object.values(floor.rooms)) {\n next.rooms[room.id] = {\n ...room,\n anchor: { x: room.anchor.x * factor, y: room.anchor.y * factor },\n area: room.area * factor * factor,\n };\n }\n return next;\n}\n\n// ─── Openings ──────────────────────────────────────────────────────────────────\n\nexport function addOpening(floor: PlanFloor, opening: Omit<PlanOpening, 'id'>): PlanEdit<{ openingId: string | null }> {\n const wall = floor.walls[opening.wallId];\n if (!wall) return { floor, result: { openingId: null }, issues: [] };\n\n const len = wallLength(floor, wall);\n const width = Math.min(opening.width, len - 2);\n if (width < MIN_OPENING_WIDTH) {\n return {\n floor,\n result: { openingId: null },\n issues: [\n issue(PlanIssueKind.OpeningDropped, 'That wall is too short for an opening.', {\n wallIds: [wall.id],\n }),\n ],\n };\n }\n\n const offset = Math.min(Math.max(opening.offset, width / 2), len - width / 2);\n const next = cloneFloor(floor);\n const id = newId('o');\n next.openings[id] = { ...opening, id, offset, width };\n return { floor: next, result: { openingId: id }, issues: [] };\n}\n\nexport function updateOpening(\n floor: PlanFloor,\n openingId: string,\n patch: Partial<Omit<PlanOpening, 'id' | 'wallId'>>,\n): PlanEdit {\n const opening = floor.openings[openingId];\n if (!opening) return { floor, result: undefined, issues: [] };\n const wall = floor.walls[opening.wallId];\n if (!wall) return { floor, result: undefined, issues: [] };\n\n const len = wallLength(floor, wall);\n const merged = { ...opening, ...patch };\n const width = Math.min(Math.max(merged.width, MIN_OPENING_WIDTH), Math.max(len - 2, MIN_OPENING_WIDTH));\n const offset = Math.min(Math.max(merged.offset, width / 2), Math.max(len - width / 2, width / 2));\n\n const next = cloneFloor(floor);\n next.openings[openingId] = { ...merged, width, offset };\n return { floor: next, result: undefined, issues: [] };\n}\n\nexport function removeOpening(floor: PlanFloor, openingId: string): PlanEdit {\n if (!floor.openings[openingId]) return { floor, result: undefined, issues: [] };\n const next = cloneFloor(floor);\n delete next.openings[openingId];\n return { floor: next, result: undefined, issues: [] };\n}\n\n// ─── Validation and cleanup ────────────────────────────────────────────────────\n\n/**\n * Reports every way the graph currently violates the planar invariant.\n *\n * O(W²), so run it in tests and in development, not on every keystroke.\n */\nexport function validatePlan(floor: PlanFloor): PlanIssue[] {\n const issues: PlanIssue[] = [];\n const walls = Object.values(floor.walls);\n\n for (const wall of walls) {\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (wall.a === wall.b) {\n issues.push(\n issue(PlanIssueKind.SelfLoopWall, 'A wall starts and ends at the same node.', { wallIds: [wall.id] }),\n );\n continue;\n }\n if (!a || !b) {\n issues.push(issue(PlanIssueKind.ZeroLengthWall, 'A wall references a missing node.', { wallIds: [wall.id] }));\n continue;\n }\n if (dist(a, b) < MIN_WALL_LENGTH) {\n issues.push(\n issue(PlanIssueKind.ZeroLengthWall, 'A wall is shorter than the minimum length.', { wallIds: [wall.id] }),\n );\n }\n }\n\n const pairSeen = new Map<string, string>();\n for (const wall of walls) {\n const key = wall.a < wall.b ? `${wall.a}|${wall.b}` : `${wall.b}|${wall.a}`;\n const prior = pairSeen.get(key);\n if (prior) {\n issues.push(\n issue(PlanIssueKind.DuplicateWall, 'Two walls connect the same pair of nodes.', {\n wallIds: [prior, wall.id],\n }),\n );\n } else {\n pairSeen.set(key, wall.id);\n }\n }\n\n const nodes = Object.values(floor.nodes);\n for (let i = 0; i < nodes.length; i++) {\n for (let j = i + 1; j < nodes.length; j++) {\n if (dist(nodes[i], nodes[j]) < EPS_COINCIDENT) {\n issues.push(\n issue(PlanIssueKind.CoincidentNodes, 'Two nodes occupy the same position.', {\n nodeIds: [nodes[i].id, nodes[j].id],\n }),\n );\n }\n }\n }\n\n for (let i = 0; i < walls.length; i++) {\n for (let j = i + 1; j < walls.length; j++) {\n const w1 = walls[i];\n const w2 = walls[j];\n const a = floor.nodes[w1.a];\n const b = floor.nodes[w1.b];\n const c = floor.nodes[w2.a];\n const d = floor.nodes[w2.b];\n if (!a || !b || !c || !d) continue;\n const hit = segmentIntersection(a, b, c, d);\n if (hit.kind === 'proper') {\n issues.push(\n issue(PlanIssueKind.UnsplitCrossing, 'Two walls cross with no node at the intersection.', {\n wallIds: [w1.id, w2.id],\n }),\n );\n } else if (hit.kind === 'collinearOverlap') {\n issues.push(\n issue(PlanIssueKind.OverlappingWalls, 'Two walls overlap along the same line.', {\n wallIds: [w1.id, w2.id],\n }),\n );\n }\n }\n }\n\n for (const wall of walls) {\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) continue;\n for (const node of nodes) {\n if (node.id === wall.a || node.id === wall.b) continue;\n const r = pointToSegment(node, a, b);\n if (r.dist < EPS_COINCIDENT && r.t > 0 && r.t < 1) {\n issues.push(\n issue(PlanIssueKind.UnsplitNodeOnWall, 'A node sits on a wall that was never split there.', {\n wallIds: [wall.id],\n nodeIds: [node.id],\n }),\n );\n }\n }\n }\n\n for (const opening of Object.values(floor.openings)) {\n if (!floor.walls[opening.wallId]) {\n issues.push(\n issue(PlanIssueKind.DanglingOpening, 'An opening references a wall that no longer exists.', {\n openingIds: [opening.id],\n }),\n );\n }\n }\n\n const referenced = new Set<string>();\n for (const wall of walls) {\n referenced.add(wall.a);\n referenced.add(wall.b);\n }\n for (const node of nodes) {\n if (!referenced.has(node.id)) {\n issues.push(issue(PlanIssueKind.OrphanNode, 'A node has no walls.', { nodeIds: [node.id] }));\n }\n }\n\n return issues;\n}\n\n/**\n * Removes what validation can safely remove: degenerate walls, orphan nodes, dangling\n * openings, and duplicate walls. Idempotent.\n *\n * Deliberately does not touch unsplit crossings: fixing one changes the room structure,\n * which is the user's call, not a cleanup pass's.\n */\nexport function cleanupPlan(floor: PlanFloor): PlanEdit<PlanIssue[]> {\n const fixed: PlanIssue[] = [];\n\n // Welding comes first, and is why the sweep below only ever sees walls that are\n // degenerate for some other reason: a wall squashed to nothing has two perfectly good\n // ends, and deleting it would leave them stacked on the same point.\n const welded = weldShortWalls(floor);\n const next = cloneFloor(welded.floor);\n for (const wallId of welded.result.weldedWallIds) {\n fixed.push(\n issue(PlanIssueKind.ZeroLengthWall, 'Welded the two ends of a wall with no length.', {\n wallIds: [wallId],\n }),\n );\n }\n\n for (const wall of Object.values(next.walls)) {\n const a = next.nodes[wall.a];\n const b = next.nodes[wall.b];\n if (wall.a === wall.b || !a || !b || dist(a, b) < MIN_WALL_LENGTH) {\n delete next.walls[wall.id];\n fixed.push(issue(PlanIssueKind.ZeroLengthWall, 'Removed a degenerate wall.', { wallIds: [wall.id] }));\n }\n }\n\n const pairSeen = new Map<string, PlanWall>();\n for (const wall of Object.values(next.walls)) {\n const key = wall.a < wall.b ? `${wall.a}|${wall.b}` : `${wall.b}|${wall.a}`;\n const prior = pairSeen.get(key);\n if (!prior) {\n pairSeen.set(key, wall);\n continue;\n }\n const keep = wall.thickness >= prior.thickness ? wall : prior;\n const drop = keep === wall ? prior : wall;\n for (const opening of Object.values(next.openings)) {\n if (opening.wallId === drop.id) next.openings[opening.id] = { ...opening, wallId: keep.id };\n }\n delete next.walls[drop.id];\n pairSeen.set(key, keep);\n fixed.push(issue(PlanIssueKind.DuplicateWall, 'Removed a duplicate wall.', { wallIds: [drop.id] }));\n }\n\n for (const opening of Object.values(next.openings)) {\n if (!next.walls[opening.wallId]) {\n delete next.openings[opening.id];\n fixed.push(\n issue(PlanIssueKind.DanglingOpening, 'Removed an opening with no wall.', {\n openingIds: [opening.id],\n }),\n );\n }\n }\n\n // One pass to count degrees, rather than scanning every wall per node: the naive form\n // is O(nodes x walls), which is the dominant cost on a large plan.\n const referenced = new Set<string>();\n for (const wall of Object.values(next.walls)) {\n referenced.add(wall.a);\n referenced.add(wall.b);\n }\n for (const node of Object.values(next.nodes)) {\n if (!referenced.has(node.id)) {\n delete next.nodes[node.id];\n fixed.push(issue(PlanIssueKind.OrphanNode, 'Removed a node with no walls.', { nodeIds: [node.id] }));\n }\n }\n\n return { floor: next, result: fixed, issues: fixed };\n}\n\nexport { wallLength, wallsAtNode, findWallBetween };\n"],"mappings":"+MA4BA,IAAI,EAAQ,EAOZ,SAAgB,EAAM,EAAwB,CAM5C,MALA,IAAS,EAKF,GAAG,EAAO,GAHf,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WAC1D,OAAO,WAAW,CAAC,CAAC,MAAM,EAAG,CAAC,EAC9B,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAG,EAAE,IACjB,EAAM,SAAS,EAAE,GAC9C,CASA,SAAS,EAAW,EAA6B,CAC/C,MAAO,CACL,GAAG,EACH,MAAO,CAAE,GAAG,EAAM,KAAM,EACxB,MAAO,CAAE,GAAG,EAAM,KAAM,EACxB,SAAU,CAAE,GAAG,EAAM,QAAS,EAC9B,MAAO,CAAE,GAAG,EAAM,KAAM,CAC1B,CACF,CAEA,SAAS,EAAM,EAAqB,EAAiB,EAA4B,CAAC,EAAc,CAC9F,MAAO,CAAE,OAAM,UAAS,GAAG,CAAM,CACnC,CAEA,SAAS,EAAW,EAAkB,EAAwB,CAC5D,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GAE3B,MADI,CAAC,GAAK,CAAC,EAAU,EACd,EAAK,EAAG,CAAC,CAClB,CAEA,SAAS,EAAY,EAAkB,EAA4B,CACjE,OAAO,OAAO,OAAO,EAAM,KAAK,CAAC,CAAC,OAAQ,GAAM,EAAE,IAAM,GAAU,EAAE,IAAM,CAAM,CAClF,CAEA,SAAS,EAAgB,EAAkB,EAAW,EAA4B,CAChF,IAAK,IAAM,KAAK,OAAO,OAAO,EAAM,KAAK,EACvC,GAAK,EAAE,IAAM,GAAK,EAAE,IAAM,GAAO,EAAE,IAAM,GAAK,EAAE,IAAM,EAAI,OAAO,EAEnE,OAAO,IACT,CAQA,IAAM,EAAY,IAElB,SAAS,EAAQ,EAAW,EAAmB,CAC7C,MAAO,GAAG,KAAK,MAAM,EAAI,CAAS,EAAE,GAAG,KAAK,MAAM,EAAI,CAAS,GACjE,CAEA,SAAS,EAAc,EAA2C,CAChE,IAAM,EAAM,IAAI,IAChB,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAAG,CAC7C,IAAM,EAAM,EAAQ,EAAK,EAAG,EAAK,CAAC,EAC5B,EAAO,EAAI,IAAI,CAAG,EACpB,EAAM,EAAK,KAAK,CAAI,EACnB,EAAI,IAAI,EAAK,CAAC,CAAI,CAAC,CAC1B,CACA,OAAO,CACT,CAGA,SAAgB,EAAa,EAAkB,EAAc,EAA8B,CACzF,IAAM,EAAO,EAAc,CAAK,EAC1B,EAAK,KAAK,MAAM,EAAE,EAAI,CAAS,EAC/B,EAAK,KAAK,MAAM,EAAE,EAAI,CAAS,EACjC,EAAwB,KACxB,EAAW,EACT,EAAO,KAAK,IAAI,EAAG,KAAK,KAAK,EAAM,CAAS,CAAC,EACnD,IAAK,IAAI,EAAK,CAAC,EAAM,GAAM,EAAM,IAC/B,IAAK,IAAI,EAAK,CAAC,EAAM,GAAM,EAAM,IAC/B,IAAK,IAAM,KAAQ,EAAK,IAAI,GAAG,EAAK,EAAG,GAAG,EAAK,GAAI,GAAK,CAAC,EAAG,CAC1D,IAAM,EAAI,EAAK,EAAG,CAAI,EAClB,GAAK,IACP,EAAO,EACP,EAAW,EAEf,CAGJ,OAAO,CACT,CAGA,SAAgB,EACd,EACA,EACA,EACA,EACsE,CACtE,IAAI,EAA6E,KACjF,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAAG,CAC7C,GAAI,GAAS,IAAI,EAAK,EAAE,EAAG,SAC3B,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GAC3B,GAAI,CAAC,GAAK,CAAC,EAAG,SACd,IAAM,EAAI,EAAe,EAAG,EAAG,CAAC,EAC5B,EAAE,MAAQ,IAAQ,CAAC,GAAQ,EAAE,KAAO,EAAK,QAC3C,EAAO,CAAE,OAAM,EAAG,EAAE,EAAG,MAAO,EAAE,MAAO,KAAM,EAAE,IAAK,EAExD,CACA,OAAO,CACT,CAkBA,SAAgB,EAAU,EAAkB,EAAgB,EAAmD,CAC7G,IAAM,EAAO,EAAM,MAAM,GACzB,GAAI,CAAC,EACH,MAAO,CAAE,QAAO,OAAQ,CAAE,OAAQ,GAAI,QAAS,KAAM,kBAAmB,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAE3F,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GAC3B,GAAI,CAAC,GAAK,CAAC,EACT,MAAO,CAAE,QAAO,OAAQ,CAAE,OAAQ,GAAI,QAAS,KAAM,kBAAmB,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAG3F,IAAM,EAAM,EAAK,EAAG,CAAC,EACf,EAAQ,OAAO,GAAO,SAAW,CAAE,EAAG,EAAE,GAAK,EAAE,EAAI,EAAE,GAAK,EAAI,EAAG,EAAE,GAAK,EAAE,EAAI,EAAE,GAAK,CAAG,EAAI,EAG5F,EAAQ,EAAiB,EAAO,EAAG,CAAC,EACpC,EAAQ,EAAK,EAAG,CAAK,EAE3B,GAAI,EAAA,GACF,MAAO,CAAE,QAAO,OAAQ,CAAE,OAAQ,EAAK,EAAG,QAAS,KAAM,kBAAmB,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAE/F,GAAI,EAAM,EAAA,GACR,MAAO,CAAE,QAAO,OAAQ,CAAE,OAAQ,EAAK,EAAG,QAAS,KAAM,kBAAmB,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAG/F,IAAM,EAAO,EAAW,CAAK,EACvB,EAAS,EAAM,GAAG,EACxB,EAAK,MAAM,GAAU,CAAE,GAAI,EAAQ,EAAG,EAAM,EAAG,EAAG,EAAM,CAAE,EAE1D,IAAM,EAAU,EAAM,GAAG,EACnB,EAAW,EAAM,GAAG,EACpB,EAAO,CAAE,UAAW,EAAK,UAAW,KAAM,EAAK,KAAM,OAAQ,EAAK,OAAQ,WAAY,EAAK,UAAW,EAC5G,EAAK,MAAM,GAAW,CAAE,GAAG,EAAM,GAAI,EAAS,EAAG,EAAK,EAAG,EAAG,CAAO,EACnE,EAAK,MAAM,GAAY,CAAE,GAAG,EAAM,GAAI,EAAU,EAAG,EAAQ,EAAG,EAAK,CAAE,EACrE,OAAO,EAAK,MAAM,GAKlB,IAAM,EAA8B,CAAC,EAC/B,EAAsB,CAAC,EAC7B,IAAK,IAAM,KAAW,OAAO,OAAO,EAAM,QAAQ,EAAG,CACnD,GAAI,EAAQ,SAAW,EAAQ,SAC/B,IAAM,EAAY,EAAQ,QAAU,EAC9B,EAAU,EAAY,EAAU,EAChC,EAAW,EAAY,EAAQ,EAAM,EACrC,EAAS,EAAY,EAAQ,OAAS,EAAQ,OAAS,EAEvD,EAAW,KAAK,IAAI,EAAQ,MAAO,EAAW,EAAG,EAAS,GAAI,EAAW,GAAU,CAAC,EAC1F,GAAI,EAAA,IAA8B,CAChC,OAAO,EAAK,SAAS,EAAQ,IAC7B,EAAkB,KAAK,EAAQ,EAAE,EACjC,EAAO,KACL,EAAM,EAAc,eAAgB,sEAAuE,CACzG,WAAY,CAAC,EAAQ,EAAE,EACvB,QAAS,CAAC,CAAM,CAClB,CAAC,CACH,EACA,QACF,CACA,EAAK,SAAS,EAAQ,IAAM,CAAE,GAAG,EAAS,OAAQ,EAAS,SAAQ,MAAO,CAAS,CACrF,CAEA,MAAO,CAAE,MAAO,EAAM,OAAQ,CAAE,SAAQ,QAAS,CAAC,EAAS,CAAQ,EAAG,mBAAkB,EAAG,QAAO,CACpG,CAcA,SAAgB,EAAc,EAAkB,EAAc,EAA0C,CACtG,IAAM,EAAW,EAAa,EAAO,EAAG,CAAG,EAC3C,GAAI,EACF,MAAO,CAAE,QAAO,OAAQ,CAAE,OAAQ,EAAS,GAAI,YAAa,GAAO,YAAa,IAAK,EAAG,OAAQ,CAAC,CAAE,EAGrG,IAAM,EAAS,EAAa,EAAO,EAAG,CAAG,EACzC,GAAI,EAAQ,CACV,IAAM,EAAQ,EAAU,EAAO,EAAO,KAAK,GAAI,EAAO,KAAK,EAC3D,GAAI,EAAM,OAAO,OACf,MAAO,CACL,MAAO,EAAM,MACb,OAAQ,CACN,OAAQ,EAAM,OAAO,OACrB,YAAa,EAAM,OAAO,UAAY,KACtC,YAAa,EAAM,OAAO,QAAU,EAAO,KAAK,GAAK,IACvD,EACA,OAAQ,EAAM,MAChB,CAEJ,CAEA,IAAM,EAAO,EAAW,CAAK,EACvB,EAAS,EAAM,GAAG,EAExB,MADA,GAAK,MAAM,GAAU,CAAE,GAAI,EAAQ,EAAG,EAAE,EAAG,EAAG,EAAE,CAAE,EAC3C,CAAE,MAAO,EAAM,OAAQ,CAAE,SAAQ,YAAa,GAAM,YAAa,IAAK,EAAG,OAAQ,CAAC,CAAE,CAC7F,CAMA,IAAa,EAAgC,CAAE,UAAW,IAAK,KAAM,EAAS,QAAS,EAgBvF,SAAgB,EACd,EACA,EACA,EACA,EAAmB,EACnB,EAAA,EACoD,CACpD,IAAM,EAAsB,CAAC,EAC7B,GAAI,EAAK,EAAG,CAAC,EAAA,GACX,MAAO,CAAE,QAAO,OAAQ,CAAE,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,EAAG,QAAO,EAI/D,IAAM,EAAY,EAAc,EAAO,EAAG,CAAG,EACzC,EAAO,EAAU,MACrB,EAAO,KAAK,GAAG,EAAU,MAAM,EAC/B,IAAM,EAAU,EAAc,EAAM,EAAG,CAAG,EAC1C,EAAO,EAAQ,MACf,EAAO,KAAK,GAAG,EAAQ,MAAM,EAE7B,IAAM,EAAK,EAAU,OAAO,OACtB,EAAK,EAAQ,OAAO,OAC1B,GAAI,IAAO,EAAI,MAAO,CAAE,QAAO,OAAQ,CAAE,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,EAAG,QAAO,EAE5E,IAAM,EAAI,EAAK,MAAM,GACf,EAAI,EAAK,MAAM,GACf,EAAM,EAAK,EAAG,CAAC,EACrB,GAAI,EAAA,GAAuB,MAAO,CAAE,QAAO,OAAQ,CAAE,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,EAAG,QAAO,EAGxF,IAAM,EAAc,CAClB,CAAE,EAAG,EAAG,OAAQ,CAAG,EACnB,CAAE,EAAG,EAAG,OAAQ,CAAG,CACrB,EACM,EAAS,IAAI,IACb,EAAoC,CAAC,EAErC,EAAc,GAAyB,EAAe,EAAG,EAAG,CAAC,CAAC,CAAC,EAErE,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EAAG,CAC5C,IAAM,EAAK,EAAK,MAAM,EAAK,GACrB,EAAK,EAAK,MAAM,EAAK,GAC3B,GAAI,CAAC,GAAM,CAAC,EAAI,SAEhB,IAAM,EAAM,EAAoB,EAAG,EAAG,EAAI,EAAI,CAAG,EAEjD,GAAI,EAAI,OAAS,mBAAoB,CACnC,IAAM,EAAK,EAAW,CAAE,EAClB,EAAK,EAAW,CAAE,EACxB,EAAS,KAAK,CAAC,KAAK,IAAI,EAAI,CAAE,EAAG,KAAK,IAAI,EAAI,CAAE,CAAC,CAAC,EAGlD,IAAK,GAAM,CAAC,EAAM,IAAM,CACtB,CAAC,EAAI,CAAE,EACP,CAAC,EAAI,CAAE,CACT,EACM,EAAI,EAAA,KAA0B,EAAI,GAAK,EAAA,IACzC,EAAK,KAAK,CAAE,IAAG,OAAQ,EAAK,EAAG,CAAC,EAGpC,QACF,CAEA,GAAI,EAAI,OAAS,UAAY,EAAI,IAAM,IAAA,IAAa,EAAI,IAAM,IAAA,GAAW,CACvE,IAAM,EAAO,EAAO,IAAI,EAAK,EAAE,EAC3B,EAAM,EAAK,KAAK,EAAI,CAAC,EACpB,EAAO,IAAI,EAAK,GAAI,CAAC,EAAI,CAAC,CAAC,EAChC,EAAK,KAAK,CAAE,EAAG,EAAI,EAAG,OAAQ,KAAM,QAAS,CAAE,OAAQ,EAAK,GAAI,EAAG,EAAI,CAAE,CAAE,CAAC,EAC5E,QACF,CAEA,GAAI,EAAI,OAAS,SAAW,EAAI,IAAM,IAAA,IAAa,EAAI,IAAM,IAAA,GAAW,CAGtE,IAAM,EADc,EAAI,GAAK,GACE,EAAK,EAC9B,EAAQ,EAAW,CAAQ,EAE/B,EAAe,EAAU,EAAG,CAAC,CAAC,CAAC,MAAQ,GACvC,EAAQ,EAAA,KACP,EAAI,GAAS,EAAA,IAEd,EAAK,KAAK,CAAE,EAAG,EAAO,OAAQ,EAAS,EAAG,CAAC,CAE/C,CACF,CAMA,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EAAG,CAC5C,GAAI,EAAK,KAAO,GAAM,EAAK,KAAO,EAAI,SACtC,IAAM,EAAI,EAAe,EAAM,EAAG,CAAC,EAC/B,EAAE,KAAO,GACT,EAAE,EAAI,GAAA,KAA2B,EAAI,EAAE,GAAK,GAAA,IAChD,EAAK,KAAK,CAAE,EAAG,EAAE,EAAG,OAAQ,EAAK,EAAG,CAAC,CACvC,CAIA,IAAK,GAAM,CAAC,EAAQ,KAAW,EAAQ,CACrC,IAAM,EAAS,CAAC,GAAG,CAAM,CAAC,CAAC,MAAM,EAAG,IAAM,EAAI,CAAC,EAC3C,EAAgB,EACd,EAAY,IAAI,IAAI,CAAM,EAChC,IAAK,IAAM,KAAK,EAAQ,CACtB,IAAM,EAAS,EAAK,MAAM,GAC1B,GAAI,CAAC,EAAQ,MACb,IAAM,EAAK,EAAK,MAAM,EAAO,GACvB,EAAK,EAAK,MAAM,EAAO,GAC7B,GAAI,CAAC,GAAM,CAAC,EAAI,MAGhB,IAAM,EAAW,EAAM,MAAM,GACvB,EAAK,EAAK,MAAM,GAAU,GAAK,EAAO,IAAM,EAC5C,EAAK,EAAK,MAAM,GAAU,GAAK,EAAO,IAAM,EAC5C,EAAa,CAAE,EAAG,EAAG,GAAK,EAAG,EAAI,EAAG,GAAK,EAAG,EAAG,EAAG,GAAK,EAAG,EAAI,EAAG,GAAK,CAAE,EACxE,EAAO,EAAU,EAAM,EAAe,CAAU,EACtD,EAAO,EAAK,MACZ,EAAO,KAAK,GAAG,EAAK,MAAM,EAC1B,EAAU,OAAO,CAAC,EAClB,IAAK,IAAM,KAAO,EACZ,EAAI,SAAW,EAAI,QAAQ,SAAW,GAAU,EAAI,QAAQ,IAAM,IACpE,EAAI,OAAS,EAAK,OAAO,OACzB,EAAI,QAAU,IAAA,IAIlB,GAAI,EAAK,OAAO,QAAS,CACvB,GAAM,CAAC,EAAO,GAAU,EAAK,OAAO,QAC9B,EAAQ,KAAK,IAAQ,GAAG,EAAY,EAAE,EAC5C,EAAgB,GAAS,GAAK,EAAQ,EAAI,EAAS,CACrD,CACF,CACF,CAGA,IAAM,EAAW,EAAK,OAAQ,GAAqC,EAAQ,EAAE,MAAO,EACpF,EAAS,MAAM,EAAG,IAAM,EAAE,EAAI,EAAE,CAAC,EAEjC,IAAM,EAAyC,CAAC,EAChD,IAAK,IAAM,KAAO,EAAU,CAC1B,IAAM,EAAO,EAAM,EAAM,OAAS,GAClC,GAAI,CAAC,EAAM,CACT,EAAM,KAAK,CAAG,EACd,QACF,CACI,KAAK,SAAW,EAAI,OACxB,KAAK,EAAI,EAAI,EAAK,GAAK,EAAA,GAAuB,CAExC,EAAI,GAAK,EAAI,OAAM,EAAM,EAAM,OAAS,GAAK,GACjD,QACF,CACA,EAAM,KAAK,CAAG,CADd,CAEF,CAEA,IAAM,EAA2B,CAAC,EAClC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAI,EAAM,OAAQ,IAAK,CACzC,IAAM,EAAO,EAAM,GACb,EAAK,EAAM,EAAI,GACf,GAAQ,EAAK,EAAI,EAAG,GAAK,EAM/B,GALI,EAAS,MAAM,CAAC,EAAI,KAAQ,EAAO,EAAK,MAAQ,EAAO,EAAK,IAAI,GAKhE,EAAgB,EAAM,EAAK,OAAQ,EAAG,MAAM,EAAG,SACnD,IAAM,EAAK,EAAK,MAAM,EAAK,QACrB,EAAK,EAAK,MAAM,EAAG,QACzB,GAAI,CAAC,GAAM,CAAC,GAAM,EAAK,EAAI,CAAE,EAAA,GAAqB,SAElD,IAAM,EAAK,EAAM,GAAG,EACpB,EAAO,CAAE,GAAG,EAAM,MAAO,CAAE,GAAG,EAAK,OAAQ,GAAK,CAAE,GAAG,EAAO,KAAI,EAAG,EAAK,OAAQ,EAAG,EAAG,MAAO,CAAE,CAAE,EACjG,EAAe,KAAK,CAAE,CACxB,CAMA,OAJI,EAAe,SAAW,GAAK,EAAS,OAAS,GACnD,EAAO,KAAK,EAAM,EAAc,cAAe,wDAAwD,CAAC,EAGnG,CACL,MAAO,EACP,OAAQ,CAAE,QAAS,EAAgB,QAAS,EAAM,IAAK,GAAM,EAAE,MAAM,CAAE,EACvE,QACF,CACF,CAGA,SAAgB,EACd,EACA,EACA,EACA,EAAmB,EACnB,EAAA,EACiC,CACjC,IAAM,EAAK,KAAK,IAAI,EAAO,EAAG,EAAS,CAAC,EAClC,EAAK,KAAK,IAAI,EAAO,EAAG,EAAS,CAAC,EAClC,EAAK,KAAK,IAAI,EAAO,EAAG,EAAS,CAAC,EAClC,EAAK,KAAK,IAAI,EAAO,EAAG,EAAS,CAAC,EACxC,GAAI,EAAK,EAAA,IAAwB,EAAK,EAAA,GACpC,MAAO,CAAE,QAAO,OAAQ,CAAE,QAAS,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAGtD,IAAM,EAAuB,CAC3B,CAAE,EAAG,EAAI,EAAG,CAAG,EACf,CAAE,EAAG,EAAI,EAAG,CAAG,EACf,CAAE,EAAG,EAAI,EAAG,CAAG,EACf,CAAE,EAAG,EAAI,EAAG,CAAG,CACjB,EAEI,EAAO,EACL,EAAoB,CAAC,EACrB,EAAsB,CAAC,EAC7B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAG,IAAK,CAC1B,IAAM,EAAO,EAAQ,EAAM,EAAQ,GAAI,GAAS,EAAI,GAAK,GAAI,EAAO,CAAG,EACvE,EAAO,EAAK,MACZ,EAAQ,KAAK,GAAG,EAAK,OAAO,OAAO,EACnC,EAAO,KAAK,GAAG,EAAK,MAAM,CAC5B,CACA,MAAO,CAAE,MAAO,EAAM,OAAQ,CAAE,SAAQ,EAAG,QAAO,CACpD,CAWA,SAAgB,EAAW,EAAkB,EAAgB,EAA0D,CACrH,GAAI,IAAW,GAAY,CAAC,EAAM,MAAM,IAAW,CAAC,EAAM,MAAM,GAC9D,MAAO,CAAE,QAAO,OAAQ,CAAE,eAAgB,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAG7D,IAAM,EAAO,EAAW,CAAK,EACvB,EAA2B,CAAC,EAC5B,EAAsB,CAAC,EAG7B,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EACrC,EAAK,IAAM,IAAU,EAAK,MAAM,EAAK,IAAM,CAAE,GAAG,EAAK,MAAM,EAAK,IAAK,EAAG,CAAO,GAC/E,EAAK,IAAM,IAAU,EAAK,MAAM,EAAK,IAAM,CAAE,GAAG,EAAK,MAAM,EAAK,IAAK,EAAG,CAAO,GAIrF,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EACrC,KAAK,IAAM,EAAK,EAEpB,CADA,OAAO,EAAK,MAAM,EAAK,IACvB,EAAe,KAAK,EAAK,EAAE,EAC3B,IAAK,IAAM,KAAW,OAAO,OAAO,EAAK,QAAQ,EAC3C,EAAQ,SAAW,EAAK,IAAI,OAAO,EAAK,SAAS,EAAQ,GAFpC,CAO7B,IAAM,EAAO,IAAI,IACjB,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EAAG,CAC5C,IAAM,EAAM,EAAK,EAAI,EAAK,EAAI,GAAG,EAAK,EAAE,GAAG,EAAK,IAAM,GAAG,EAAK,EAAE,GAAG,EAAK,IAClE,EAAQ,EAAK,IAAI,CAAG,EAC1B,GAAI,CAAC,EAAO,CACV,EAAK,IAAI,EAAK,CAAI,EAClB,QACF,CAEA,IAAM,EAAO,EAAK,WAAa,EAAM,UAAY,EAAO,EAClD,EAAO,IAAS,EAAO,EAAQ,EACrC,IAAK,IAAM,KAAW,OAAO,OAAO,EAAK,QAAQ,EAC3C,EAAQ,SAAW,EAAK,KAC1B,EAAK,SAAS,EAAQ,IAAM,CAAE,GAAG,EAAS,OAAQ,EAAK,EAAG,GAG9D,OAAO,EAAK,MAAM,EAAK,IACvB,EAAe,KAAK,EAAK,EAAE,EAC3B,EAAK,IAAI,EAAK,CAAI,EAClB,EAAO,KACL,EAAM,EAAc,cAAe,kDAAmD,CACpF,QAAS,CAAC,EAAK,GAAI,EAAK,EAAE,CAC5B,CAAC,CACH,CACF,CAKA,OAFA,OAAO,EAAK,MAAM,GAEX,CAAE,MAAO,EAAM,OAAQ,CAAE,gBAAe,EAAG,QAAO,CAC3D,CA0BA,SAAgB,EACd,EACA,EACA,EAA+B,CAAC,EACK,CACrC,GAAM,CAAE,QAAQ,IAAU,EACpB,EAAO,EAAM,MAAM,GACzB,GAAI,CAAC,EAAM,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAEpD,IAAM,EAAW,EAAY,EAAO,CAAM,EAC1C,GAAI,EAAS,SAAW,EAAG,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAEpE,GAAM,CAAC,EAAI,GAAM,EACX,EACJ,EAAG,YAAc,EAAG,WAAa,EAAG,OAAS,EAAG,MAAQ,EAAG,SAAW,EAAG,QAAU,EAAG,aAAe,EAAG,WAC1G,GAAI,CAAC,GAAoB,CAAC,EAAO,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAE1E,IAAM,EAAO,EAAG,IAAM,EAAS,EAAG,EAAI,EAAG,EACnC,EAAO,EAAG,IAAM,EAAS,EAAG,EAAI,EAAG,EACzC,GAAI,IAAS,EAAM,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAE5D,IAAM,EAAK,EAAM,MAAM,GACjB,EAAK,EAAM,MAAM,GACvB,GAAI,CAAC,GAAM,CAAC,EAAI,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAEzD,IAAM,EAAO,EAAK,EAAI,CAAE,EAGxB,GAFI,EAAA,IAEA,CAAC,GAGY,KAAK,IAAI,EAAM,EAAI,EAAI,CAAI,CAAC,EAAI,EAClC,KAAK,IAAA,EAAoB,EAAA,IAAgB,EACpD,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAM7C,IAAM,EAAO,CAAC,GAAoB,EAAG,UAAY,EAAG,UAAY,EAAK,EAE/D,EAAO,EAAW,CAAK,EACvB,EAAK,EAAM,GAAG,EACpB,EAAK,MAAM,GAAM,CACf,KACA,EAAG,EACH,EAAG,EACH,UAAW,EAAK,UAChB,KAAM,EAAK,KACX,OAAQ,EAAK,OACb,WAAY,EAAK,UACnB,EAGA,IAAM,EAAO,EAAK,EAAI,CAAI,EACpB,EAAO,EAAK,EAAM,CAAE,EAGpB,EAAQ,EAAO,EAAO,EAAI,GAAQ,EAAO,GAAQ,EACjD,EAAsB,CAAC,EAE7B,IAAK,IAAM,KAAW,OAAO,OAAO,EAAM,QAAQ,EAAG,CACnD,GAAI,EAAQ,SAAW,EAAG,IAAM,EAAQ,SAAW,EAAG,GAAI,SAC1D,IAAM,EAAU,EAAQ,SAAW,EAAG,GAChC,EAAO,EAAU,EAAK,EACtB,EAAe,EAAK,IAAM,EAC1B,EAAY,EAAW,EAAO,CAAI,EAElC,EAAW,EAAe,EAAQ,OAAS,EAAY,EAAQ,OAE/D,GADgB,EAAU,EAAO,EAAW,EAAO,GAClB,EAEjC,EAAQ,KAAK,IAAI,EAAQ,MAAQ,EAAO,EAAO,CAAC,EACtD,GAAI,EAAA,IAA2B,CAC7B,EAAO,KACL,EAAM,EAAc,eAAgB,sEAAuE,CACzG,WAAY,CAAC,EAAQ,EAAE,EACvB,QAAS,CAAC,EAAK,EAAE,CACnB,CAAC,CACH,EACA,OAAO,EAAK,SAAS,EAAQ,IAC7B,QACF,CAEA,EAAK,SAAS,EAAQ,IAAM,CAC1B,GAAG,EACH,OAAQ,EACR,QACA,OAAQ,KAAK,IAAI,KAAK,IAAI,EAAgB,EAAQ,CAAC,EAAG,EAAO,EAAQ,CAAC,CACxE,CACF,CAMA,OAJA,OAAO,EAAK,MAAM,EAAG,IACrB,OAAO,EAAK,MAAM,EAAG,IACrB,OAAO,EAAK,MAAM,GAEX,CAAE,MAAO,EAAM,OAAQ,CAAE,OAAQ,CAAG,EAAG,QAAO,CACvD,CAgCA,SAAgB,EAAW,EAAkB,EAAgB,EAAqD,CAChH,IAAM,EAAO,EAAM,MAAM,GAEzB,GADI,CAAC,GAAQ,EAAK,IAAM,EAAK,GACzB,KAAK,MAAM,EAAM,EAAG,EAAM,CAAC,EAAA,GAAqB,MAAO,CAAE,QAAO,OAAQ,KAAM,OAAQ,CAAC,CAAE,EAE7F,IAAM,EAAyB,CAAC,EAAK,EAAG,EAAK,CAAC,EACxC,EAA4B,CAAC,EAAK,EAAG,EAAK,CAAC,EAC3C,EAA+B,CAAC,KAAM,IAAI,EAC1C,EAAyB,CAAC,EAC1B,EAAsB,CAAC,EACzB,EAAM,EAMV,EAAK,SAAS,EAAQ,IAAU,CAC9B,IAAM,EAAS,EAAM,MAAM,GAC3B,GAAI,CAAC,EAAQ,OACb,IAAM,EAAK,CAAE,EAAG,EAAO,EAAI,EAAM,EAAG,EAAG,EAAO,EAAI,EAAM,CAAE,EACpD,EAAS,EAAY,EAAO,CAAM,CAAC,CAAC,OAAQ,GAAM,EAAE,KAAO,CAAM,EAEvE,GAAI,EAAO,SAAW,EAAG,CAGvB,IAAM,EAAO,EAAW,CAAG,EAC3B,EAAK,MAAM,GAAU,CAAE,GAAG,EAAK,MAAM,GAAS,EAAG,EAAG,EAAG,EAAG,EAAG,CAAE,EAC/D,EAAM,EACN,MACF,CAEA,IAAM,EAAO,EAAc,EAAK,EAAA,CAAkB,EAClD,EAAM,EAAK,MACX,EAAQ,GAAS,EAAK,OAAO,OAI7B,EAAQ,GAAS,EAAO,SAAW,EAAI,EAAO,GAAK,CACrD,CAAC,EAID,IAAM,EAAQ,EAAW,CAAG,EAC5B,EAAM,MAAM,GAAU,CAAE,GAAG,EAAM,MAAM,GAAS,EAAG,EAAQ,GAAI,EAAG,EAAQ,EAAG,EAC7E,EAAM,EAGN,EAAK,SAAS,EAAQ,IAAU,CAC9B,IAAM,EAAS,EAAQ,GACjB,EAAO,EAAI,MAAM,GACjB,EAAK,EAAI,MAAM,EAAQ,IAC7B,GAAI,CAAC,GAAU,CAAC,GAAQ,CAAC,EAAI,OAC7B,IAAM,EAAO,EAAQ,EAAK,EAAM,EAAI,CAClC,UAAW,EAAO,UAClB,KAAM,EAAO,KACb,OAAQ,EAAO,OACf,WAAY,EAAO,UACrB,CAAC,EACD,EAAM,EAAK,MACX,EAAa,KAAK,GAAG,EAAK,OAAO,OAAO,EACxC,EAAO,KAAK,GAAG,EAAK,MAAM,CAC5B,CAAC,EAID,IAAM,EAA6B,CAAC,EAUpC,OATA,EAAK,SAAS,EAAQ,IAAU,CAC9B,GAAI,EAAQ,KAAW,EAAQ,OAC/B,IAAM,EAAO,EAAa,EAAK,CAAM,EAChC,EAAK,SACV,EAAM,EAAK,MACX,EAAiB,KAAK,CAAM,EAC5B,EAAO,KAAK,GAAG,EAAK,MAAM,EAC5B,CAAC,EAEM,CAAE,MAAO,EAAK,OAAQ,CAAE,UAAS,eAAc,kBAAiB,EAAG,QAAO,CACnF,CAkBA,SAAgB,EACd,EACA,EAAA,GACuC,CACvC,IAAI,EAAM,EACJ,EAA0B,CAAC,EAC3B,EAAsB,CAAC,EAI7B,IAAK,IAAI,EAAQ,OAAO,KAAK,EAAM,KAAK,CAAC,CAAC,OAAQ,EAAQ,EAAG,IAAS,CACpE,IAAM,EAAQ,OAAO,OAAO,EAAI,KAAK,CAAC,CAAC,KAAM,GAAM,CACjD,GAAI,EAAE,IAAM,EAAE,EAAG,MAAO,GACxB,IAAM,EAAI,EAAI,MAAM,EAAE,GAChB,EAAI,EAAI,MAAM,EAAE,GACtB,OAAO,GAAK,GAAK,EAAK,EAAG,CAAC,EAAI,CAChC,CAAC,EACD,GAAI,CAAC,EAAO,MAEZ,IAAM,EAAO,EAAY,EAAK,EAAM,CAAC,CAAC,CAAC,OAAS,EAAY,EAAK,EAAM,CAAC,CAAC,CAAC,OAAS,EAAM,EAAI,EAAM,EAC7F,EAAO,EAAW,EAAK,EAAM,IAAS,EAAM,EAAI,EAAM,EAAI,EAAM,CAAC,EACvE,GAAI,EAAK,QAAU,EAAK,MACxB,EAAM,EAAK,MACX,EAAc,KAAK,EAAM,EAAE,EAC3B,EAAO,KAAK,GAAG,EAAK,MAAM,CAC5B,CAEA,MAAO,CAAE,MAAO,EAAK,OAAQ,CAAE,eAAc,EAAG,QAAO,CACzD,CAIA,SAAgB,EACd,EACA,EACA,EAAoE,CAAC,EACD,CACpE,GAAM,CAAE,mBAAmB,GAAM,oBAAoB,IAAS,EACxD,EAAO,EAAM,MAAM,GACzB,GAAI,CAAC,EAAM,MAAO,CAAE,QAAO,OAAQ,CAAE,eAAgB,CAAC,EAAG,iBAAkB,CAAC,CAAE,EAAG,OAAQ,CAAC,CAAE,EAE5F,IAAI,EAAO,EAAW,CAAK,EAC3B,OAAO,EAAK,MAAM,GAClB,IAAK,IAAM,KAAW,OAAO,OAAO,EAAK,QAAQ,EAC3C,EAAQ,SAAW,GAAQ,OAAO,EAAK,SAAS,EAAQ,IAG9D,IAAM,EAA2B,CAAC,EAC5B,EAA6B,CAAC,EAC9B,EAAsB,CAAC,EAE7B,IAAK,IAAM,IAAY,CAAC,EAAK,EAAG,EAAK,CAAC,EAAG,CACvC,IAAM,EAAS,EAAY,EAAM,CAAQ,CAAC,CAAC,OAC3C,GAAI,IAAW,GAAK,EAClB,OAAO,EAAK,MAAM,GAClB,EAAe,KAAK,CAAQ,OACvB,GAAI,IAAW,GAAK,EAAmB,CAE5C,IAAM,EAAO,EAAa,EAAM,CAAQ,EACpC,EAAK,SACP,EAAO,EAAK,MACZ,EAAiB,KAAK,EAAK,OAAO,MAAM,EACxC,EAAe,KAAK,CAAQ,EAC5B,EAAO,KAAK,GAAG,EAAK,MAAM,EAE9B,CACF,CAEA,MAAO,CAAE,MAAO,EAAM,OAAQ,CAAE,iBAAgB,kBAAiB,EAAG,QAAO,CAC7E,CAEA,SAAgB,EAAS,EAAkB,EAAgB,EAAyB,CAClF,IAAM,EAAO,EAAM,MAAM,GACzB,GAAI,CAAC,EAAM,MAAO,CAAE,QAAO,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,EACzD,IAAM,EAAO,EAAW,CAAK,EAE7B,MADA,GAAK,MAAM,GAAU,CAAE,GAAG,EAAM,EAAG,EAAG,EAAG,EAAG,EAAG,CAAE,EAC1C,CAAE,MAAO,EAAM,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,CACtD,CAQA,SAAgB,EAAc,EAAkB,EAAY,EAAuB,CACjF,IAAM,EAAO,EAAW,CAAK,EAC7B,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAC1C,EAAK,MAAM,EAAK,IAAM,CAAE,GAAG,EAAM,EAAG,EAAK,EAAI,EAAI,EAAG,EAAK,EAAI,CAAG,EAElE,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAC1C,EAAK,MAAM,EAAK,IAAM,CAAE,GAAG,EAAM,OAAQ,CAAE,EAAG,EAAK,OAAO,EAAI,EAAI,EAAG,EAAK,OAAO,EAAI,CAAG,CAAE,EAE5F,OAAO,CACT,CASA,SAAgB,EAAU,EAAkB,EAA2B,CACrE,IAAM,EAAO,EAAW,CAAK,EAC7B,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAC1C,EAAK,MAAM,EAAK,IAAM,CAAE,GAAG,EAAM,EAAG,EAAK,EAAI,EAAQ,EAAG,EAAK,EAAI,CAAO,EAE1E,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAC1C,EAAK,MAAM,EAAK,IAAM,CACpB,GAAG,EACH,UAAW,EAAK,UAAY,EAC5B,OAAQ,EAAK,SAAW,IAAA,GAAY,IAAA,GAAY,EAAK,OAAS,EAC9D,WAAY,EAAK,aAAe,IAAA,GAAY,IAAA,GAAY,EAAK,WAAa,CAC5E,EAEF,IAAK,IAAM,KAAW,OAAO,OAAO,EAAM,QAAQ,EAChD,EAAK,SAAS,EAAQ,IAAM,CAC1B,GAAG,EACH,OAAQ,EAAQ,OAAS,EACzB,MAAO,EAAQ,MAAQ,EACvB,KAAM,EAAQ,KAAO,EACrB,KAAM,EAAQ,KAAO,CACvB,EAEF,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAC1C,EAAK,MAAM,EAAK,IAAM,CACpB,GAAG,EACH,OAAQ,CAAE,EAAG,EAAK,OAAO,EAAI,EAAQ,EAAG,EAAK,OAAO,EAAI,CAAO,EAC/D,KAAM,EAAK,KAAO,EAAS,CAC7B,EAEF,OAAO,CACT,CAIA,SAAgB,EAAW,EAAkB,EAA0E,CACrH,IAAM,EAAO,EAAM,MAAM,EAAQ,QACjC,GAAI,CAAC,EAAM,MAAO,CAAE,QAAO,OAAQ,CAAE,UAAW,IAAK,EAAG,OAAQ,CAAC,CAAE,EAEnE,IAAM,EAAM,EAAW,EAAO,CAAI,EAC5B,EAAQ,KAAK,IAAI,EAAQ,MAAO,EAAM,CAAC,EAC7C,GAAI,EAAA,IACF,MAAO,CACL,QACA,OAAQ,CAAE,UAAW,IAAK,EAC1B,OAAQ,CACN,EAAM,EAAc,eAAgB,yCAA0C,CAC5E,QAAS,CAAC,EAAK,EAAE,CACnB,CAAC,CACH,CACF,EAGF,IAAM,EAAS,KAAK,IAAI,KAAK,IAAI,EAAQ,OAAQ,EAAQ,CAAC,EAAG,EAAM,EAAQ,CAAC,EACtE,EAAO,EAAW,CAAK,EACvB,EAAK,EAAM,GAAG,EAEpB,MADA,GAAK,SAAS,GAAM,CAAE,GAAG,EAAS,KAAI,SAAQ,OAAM,EAC7C,CAAE,MAAO,EAAM,OAAQ,CAAE,UAAW,CAAG,EAAG,OAAQ,CAAC,CAAE,CAC9D,CAEA,SAAgB,EACd,EACA,EACA,EACU,CACV,IAAM,EAAU,EAAM,SAAS,GAC/B,GAAI,CAAC,EAAS,MAAO,CAAE,QAAO,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,EAC5D,IAAM,EAAO,EAAM,MAAM,EAAQ,QACjC,GAAI,CAAC,EAAM,MAAO,CAAE,QAAO,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,EAEzD,IAAM,EAAM,EAAW,EAAO,CAAI,EAC5B,EAAS,CAAE,GAAG,EAAS,GAAG,CAAM,EAChC,EAAQ,KAAK,IAAI,KAAK,IAAI,EAAO,MAAA,GAAwB,EAAG,KAAK,IAAI,EAAM,EAAA,GAAoB,CAAC,EAChG,EAAS,KAAK,IAAI,KAAK,IAAI,EAAO,OAAQ,EAAQ,CAAC,EAAG,KAAK,IAAI,EAAM,EAAQ,EAAG,EAAQ,CAAC,CAAC,EAE1F,EAAO,EAAW,CAAK,EAE7B,MADA,GAAK,SAAS,GAAa,CAAE,GAAG,EAAQ,QAAO,QAAO,EAC/C,CAAE,MAAO,EAAM,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,CACtD,CAEA,SAAgB,EAAc,EAAkB,EAA6B,CAC3E,GAAI,CAAC,EAAM,SAAS,GAAY,MAAO,CAAE,QAAO,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,EAC9E,IAAM,EAAO,EAAW,CAAK,EAE7B,OADA,OAAO,EAAK,SAAS,GACd,CAAE,MAAO,EAAM,OAAQ,IAAA,GAAW,OAAQ,CAAC,CAAE,CACtD,CASA,SAAgB,EAAa,EAA+B,CAC1D,IAAM,EAAsB,CAAC,EACvB,EAAQ,OAAO,OAAO,EAAM,KAAK,EAEvC,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GAC3B,GAAI,EAAK,IAAM,EAAK,EAAG,CACrB,EAAO,KACL,EAAM,EAAc,aAAc,2CAA4C,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CACtG,EACA,QACF,CACA,GAAI,CAAC,GAAK,CAAC,EAAG,CACZ,EAAO,KAAK,EAAM,EAAc,eAAgB,oCAAqC,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CAAC,EAC5G,QACF,CACI,EAAK,EAAG,CAAC,EAAA,IACX,EAAO,KACL,EAAM,EAAc,eAAgB,6CAA8C,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CAC1G,CAEJ,CAEA,IAAM,EAAW,IAAI,IACrB,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAM,EAAK,EAAI,EAAK,EAAI,GAAG,EAAK,EAAE,GAAG,EAAK,IAAM,GAAG,EAAK,EAAE,GAAG,EAAK,IAClE,EAAQ,EAAS,IAAI,CAAG,EAC1B,EACF,EAAO,KACL,EAAM,EAAc,cAAe,4CAA6C,CAC9E,QAAS,CAAC,EAAO,EAAK,EAAE,CAC1B,CAAC,CACH,EAEA,EAAS,IAAI,EAAK,EAAK,EAAE,CAE7B,CAEA,IAAM,EAAQ,OAAO,OAAO,EAAM,KAAK,EACvC,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,IAAK,IAAI,EAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,EAAK,EAAM,GAAI,EAAM,EAAE,EAAA,GACzB,EAAO,KACL,EAAM,EAAc,gBAAiB,sCAAuC,CAC1E,QAAS,CAAC,EAAM,EAAE,CAAC,GAAI,EAAM,EAAE,CAAC,EAAE,CACpC,CAAC,CACH,EAKN,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,IAAK,IAAI,EAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACzC,IAAM,EAAK,EAAM,GACX,EAAK,EAAM,GACX,EAAI,EAAM,MAAM,EAAG,GACnB,EAAI,EAAM,MAAM,EAAG,GACnB,EAAI,EAAM,MAAM,EAAG,GACnB,EAAI,EAAM,MAAM,EAAG,GACzB,GAAI,CAAC,GAAK,CAAC,GAAK,CAAC,GAAK,CAAC,EAAG,SAC1B,IAAM,EAAM,EAAoB,EAAG,EAAG,EAAG,CAAC,EACtC,EAAI,OAAS,SACf,EAAO,KACL,EAAM,EAAc,gBAAiB,oDAAqD,CACxF,QAAS,CAAC,EAAG,GAAI,EAAG,EAAE,CACxB,CAAC,CACH,EACS,EAAI,OAAS,oBACtB,EAAO,KACL,EAAM,EAAc,iBAAkB,yCAA0C,CAC9E,QAAS,CAAC,EAAG,GAAI,EAAG,EAAE,CACxB,CAAC,CACH,CAEJ,CAGF,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GACvB,GAAC,GAAM,EACX,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,EAAK,KAAO,EAAK,GAAK,EAAK,KAAO,EAAK,EAAG,SAC9C,IAAM,EAAI,EAAe,EAAM,EAAG,CAAC,EAC/B,EAAE,KAAA,GAAyB,EAAE,EAAI,GAAK,EAAE,EAAI,GAC9C,EAAO,KACL,EAAM,EAAc,kBAAmB,oDAAqD,CAC1F,QAAS,CAAC,EAAK,EAAE,EACjB,QAAS,CAAC,EAAK,EAAE,CACnB,CAAC,CACH,CAEJ,CACF,CAEA,IAAK,IAAM,KAAW,OAAO,OAAO,EAAM,QAAQ,EAC3C,EAAM,MAAM,EAAQ,SACvB,EAAO,KACL,EAAM,EAAc,gBAAiB,sDAAuD,CAC1F,WAAY,CAAC,EAAQ,EAAE,CACzB,CAAC,CACH,EAIJ,IAAM,EAAa,IAAI,IACvB,IAAK,IAAM,KAAQ,EACjB,EAAW,IAAI,EAAK,CAAC,EACrB,EAAW,IAAI,EAAK,CAAC,EAEvB,IAAK,IAAM,KAAQ,EACZ,EAAW,IAAI,EAAK,EAAE,GACzB,EAAO,KAAK,EAAM,EAAc,WAAY,uBAAwB,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CAAC,EAI/F,OAAO,CACT,CASA,SAAgB,EAAY,EAAyC,CACnE,IAAM,EAAqB,CAAC,EAKtB,EAAS,EAAe,CAAK,EAC7B,EAAO,EAAW,EAAO,KAAK,EACpC,IAAK,IAAM,KAAU,EAAO,OAAO,cACjC,EAAM,KACJ,EAAM,EAAc,eAAgB,gDAAiD,CACnF,QAAS,CAAC,CAAM,CAClB,CAAC,CACH,EAGF,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EAAG,CAC5C,IAAM,EAAI,EAAK,MAAM,EAAK,GACpB,EAAI,EAAK,MAAM,EAAK,IACtB,EAAK,IAAM,EAAK,GAAK,CAAC,GAAK,CAAC,GAAK,EAAK,EAAG,CAAC,EAAA,MAC5C,OAAO,EAAK,MAAM,EAAK,IACvB,EAAM,KAAK,EAAM,EAAc,eAAgB,6BAA8B,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CAAC,EAExG,CAEA,IAAM,EAAW,IAAI,IACrB,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EAAG,CAC5C,IAAM,EAAM,EAAK,EAAI,EAAK,EAAI,GAAG,EAAK,EAAE,GAAG,EAAK,IAAM,GAAG,EAAK,EAAE,GAAG,EAAK,IAClE,EAAQ,EAAS,IAAI,CAAG,EAC9B,GAAI,CAAC,EAAO,CACV,EAAS,IAAI,EAAK,CAAI,EACtB,QACF,CACA,IAAM,EAAO,EAAK,WAAa,EAAM,UAAY,EAAO,EAClD,EAAO,IAAS,EAAO,EAAQ,EACrC,IAAK,IAAM,KAAW,OAAO,OAAO,EAAK,QAAQ,EAC3C,EAAQ,SAAW,EAAK,KAAI,EAAK,SAAS,EAAQ,IAAM,CAAE,GAAG,EAAS,OAAQ,EAAK,EAAG,GAE5F,OAAO,EAAK,MAAM,EAAK,IACvB,EAAS,IAAI,EAAK,CAAI,EACtB,EAAM,KAAK,EAAM,EAAc,cAAe,4BAA6B,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CAAC,CACpG,CAEA,IAAK,IAAM,KAAW,OAAO,OAAO,EAAK,QAAQ,EAC1C,EAAK,MAAM,EAAQ,UACtB,OAAO,EAAK,SAAS,EAAQ,IAC7B,EAAM,KACJ,EAAM,EAAc,gBAAiB,mCAAoC,CACvE,WAAY,CAAC,EAAQ,EAAE,CACzB,CAAC,CACH,GAMJ,IAAM,EAAa,IAAI,IACvB,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EACzC,EAAW,IAAI,EAAK,CAAC,EACrB,EAAW,IAAI,EAAK,CAAC,EAEvB,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAK,KAAK,EACpC,EAAW,IAAI,EAAK,EAAE,IACzB,OAAO,EAAK,MAAM,EAAK,IACvB,EAAM,KAAK,EAAM,EAAc,WAAY,gCAAiC,CAAE,QAAS,CAAC,EAAK,EAAE,CAAE,CAAC,CAAC,GAIvG,MAAO,CAAE,MAAO,EAAM,OAAQ,EAAO,OAAQ,CAAM,CACrD"}
@@ -1,2 +1,2 @@
1
- import{dist as e,pointToSegment as t}from"./floorPlan.geometry.mjs";import{roomAtPoint as n}from"./floorPlan.rooms.mjs";import{openingGeometry as r}from"./floorPlan.path.mjs";var i={node:10,opening:9,wall:8},a={node:18,opening:16,wall:14};function o(e,t){let n=t>0?t:1;return{node:e.node/n,opening:e.opening/n,wall:e.wall/n}}function s(i,a,o,s,c={}){let l=e=>!c.accept||c.accept.includes(e),u=e=>c.excludeIds?.has(e)??!1;if(l(`node`)){let t=null;for(let n of Object.values(i.nodes)){if(u(n.id))continue;let r=e(o,n);r<=s.node&&(!t||r<t.d)&&(t={id:n.id,d:r})}if(t)return{type:`node`,id:t.id}}if(l(`opening`)){let e=null;for(let n of Object.values(i.openings)){if(u(n.id))continue;let a=r(i,n);if(!a)continue;let c=t(o,a.p1,a.p2).dist;c<=s.opening&&(!e||c<e.d)&&(e={id:n.id,d:c})}if(e)return{type:`opening`,id:e.id}}if(l(`wall`)){let e=null;for(let n of Object.values(i.walls)){if(u(n.id))continue;let r=i.nodes[n.a],a=i.nodes[n.b];if(!r||!a)continue;let c=Math.max(s.wall,n.thickness/2),l=t(o,r,a).dist;l<=c&&(!e||l<e.d)&&(e={id:n.id,d:l})}if(e)return{type:`wall`,id:e.id}}if(l(`room`)){let e=n(a,o);if(e?.roomId&&!u(e.roomId))return{type:`room`,id:e.roomId}}return null}function c(e,t){return e===t?!0:!e||!t?!1:e.type===t.type&&e.id===t.id}export{i as HIT_PX,a as HIT_PX_COARSE,s as hitTest,c as selectionsEqual,o as worldTolerances};
1
+ "use client";import{dist as e,pointToSegment as t}from"./floorPlan.geometry.mjs";import{roomAtPoint as n}from"./floorPlan.rooms.mjs";import{openingGeometry as r}from"./floorPlan.path.mjs";var i={node:10,opening:9,wall:8},a={node:18,opening:16,wall:14};function o(e,t){let n=t>0?t:1;return{node:e.node/n,opening:e.opening/n,wall:e.wall/n}}function s(i,a,o,s,c={}){let l=e=>!c.accept||c.accept.includes(e),u=e=>c.excludeIds?.has(e)??!1;if(l(`node`)){let t=null;for(let n of Object.values(i.nodes)){if(u(n.id))continue;let r=e(o,n);r<=s.node&&(!t||r<t.d)&&(t={id:n.id,d:r})}if(t)return{type:`node`,id:t.id}}if(l(`opening`)){let e=null;for(let n of Object.values(i.openings)){if(u(n.id))continue;let a=r(i,n);if(!a)continue;let c=t(o,a.p1,a.p2).dist;c<=s.opening&&(!e||c<e.d)&&(e={id:n.id,d:c})}if(e)return{type:`opening`,id:e.id}}if(l(`wall`)){let e=null;for(let n of Object.values(i.walls)){if(u(n.id))continue;let r=i.nodes[n.a],a=i.nodes[n.b];if(!r||!a)continue;let c=Math.max(s.wall,n.thickness/2),l=t(o,r,a).dist;l<=c&&(!e||l<e.d)&&(e={id:n.id,d:l})}if(e)return{type:`wall`,id:e.id}}if(l(`room`)){let e=n(a,o);if(e?.roomId&&!u(e.roomId))return{type:`room`,id:e.roomId}}return null}function c(e,t){return e===t?!0:!e||!t?!1:e.type===t.type&&e.id===t.id}export{i as HIT_PX,a as HIT_PX_COARSE,s as hitTest,c as selectionsEqual,o as worldTolerances};
2
2
  //# sourceMappingURL=floorPlan.hit.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"floorPlan.hit.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.hit.ts"],"sourcesContent":["/**\n * Hit testing against a derived plan.\n *\n * Tolerances arrive in WORLD units and are expected to have been converted from screen\n * pixels by the caller (`HIT_PX / view.zoom`), so a handle stays the same size on screen\n * at any zoom level.\n */\n\nimport { dist, pointToSegment } from './floorPlan.geometry';\nimport { openingGeometry } from './floorPlan.path';\nimport { roomAtPoint } from './floorPlan.rooms';\nimport type { DerivedRoom, PlanFloor, PlanPoint, PlanSelection } from './floorPlan.types';\n\nexport interface HitTolerances {\n node: number;\n opening: number;\n wall: number;\n}\n\n/** Screen-pixel hit radii, divided by `view.zoom` to get world tolerances. */\nexport const HIT_PX: HitTolerances = { node: 10, opening: 9, wall: 8 };\n/** Wider targets for touch, where there is no pixel-accurate pointer. */\nexport const HIT_PX_COARSE: HitTolerances = { node: 18, opening: 16, wall: 14 };\n\nexport function worldTolerances(px: HitTolerances, zoom: number): HitTolerances {\n const safeZoom = zoom > 0 ? zoom : 1;\n return { node: px.node / safeZoom, opening: px.opening / safeZoom, wall: px.wall / safeZoom };\n}\n\nexport interface HitTestOptions {\n /** Restricts what can be hit. Defaults to everything. */\n accept?: Array<PlanSelection['type']>;\n excludeIds?: ReadonlySet<string>;\n}\n\n/**\n * Finds what is under `point`, in priority order: node handle, opening, wall, then room\n * fill.\n *\n * The order is what makes editing feel right. A node sits on top of the walls that meet\n * there, and an opening sits on top of the wall it cuts, so the smaller, more specific\n * target always wins over the larger one underneath it.\n */\nexport function hitTest(\n floor: PlanFloor,\n rooms: DerivedRoom[],\n point: PlanPoint,\n tolerances: HitTolerances,\n options: HitTestOptions = {},\n): PlanSelection | null {\n const accepts = (type: PlanSelection['type']) => !options.accept || options.accept.includes(type);\n const excluded = (id: string) => options.excludeIds?.has(id) ?? false;\n\n if (accepts('node')) {\n let best: { id: string; d: number } | null = null;\n for (const node of Object.values(floor.nodes)) {\n if (excluded(node.id)) continue;\n const d = dist(point, node);\n if (d <= tolerances.node && (!best || d < best.d)) best = { id: node.id, d };\n }\n if (best) return { type: 'node', id: best.id };\n }\n\n if (accepts('opening')) {\n let best: { id: string; d: number } | null = null;\n for (const opening of Object.values(floor.openings)) {\n if (excluded(opening.id)) continue;\n const geo = openingGeometry(floor, opening);\n if (!geo) continue;\n const d = pointToSegment(point, geo.p1, geo.p2).dist;\n if (d <= tolerances.opening && (!best || d < best.d)) best = { id: opening.id, d };\n }\n if (best) return { type: 'opening', id: best.id };\n }\n\n if (accepts('wall')) {\n let best: { id: string; d: number } | null = null;\n for (const wall of Object.values(floor.walls)) {\n if (excluded(wall.id)) continue;\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) continue;\n // Half the wall's own thickness, so a thick wall is grabbable across its body\n // rather than only along its centreline.\n const reach = Math.max(tolerances.wall, wall.thickness / 2);\n const d = pointToSegment(point, a, b).dist;\n if (d <= reach && (!best || d < best.d)) best = { id: wall.id, d };\n }\n if (best) return { type: 'wall', id: best.id };\n }\n\n if (accepts('room')) {\n const room = roomAtPoint(rooms, point);\n if (room?.roomId && !excluded(room.roomId)) return { type: 'room', id: room.roomId };\n }\n\n return null;\n}\n\nexport function selectionsEqual(a: PlanSelection | null, b: PlanSelection | null): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n return a.type === b.type && a.id === b.id;\n}\n"],"mappings":"+KAoBA,IAAa,EAAwB,CAAE,KAAM,GAAI,QAAS,EAAG,KAAM,CAAE,EAExD,EAA+B,CAAE,KAAM,GAAI,QAAS,GAAI,KAAM,EAAG,EAE9E,SAAgB,EAAgB,EAAmB,EAA6B,CAC9E,IAAM,EAAW,EAAO,EAAI,EAAO,EACnC,MAAO,CAAE,KAAM,EAAG,KAAO,EAAU,QAAS,EAAG,QAAU,EAAU,KAAM,EAAG,KAAO,CAAS,CAC9F,CAgBA,SAAgB,EACd,EACA,EACA,EACA,EACA,EAA0B,CAAC,EACL,CACtB,IAAM,EAAW,GAAgC,CAAC,EAAQ,QAAU,EAAQ,OAAO,SAAS,CAAI,EAC1F,EAAY,GAAe,EAAQ,YAAY,IAAI,CAAE,GAAK,GAEhE,GAAI,EAAQ,MAAM,EAAG,CACnB,IAAI,EAAyC,KAC7C,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAAG,CAC7C,GAAI,EAAS,EAAK,EAAE,EAAG,SACvB,IAAM,EAAI,EAAK,EAAO,CAAI,EACtB,GAAK,EAAW,OAAS,CAAC,GAAQ,EAAI,EAAK,KAAI,EAAO,CAAE,GAAI,EAAK,GAAI,GAAE,EAC7E,CACA,GAAI,EAAM,MAAO,CAAE,KAAM,OAAQ,GAAI,EAAK,EAAG,CAC/C,CAEA,GAAI,EAAQ,SAAS,EAAG,CACtB,IAAI,EAAyC,KAC7C,IAAK,IAAM,KAAW,OAAO,OAAO,EAAM,QAAQ,EAAG,CACnD,GAAI,EAAS,EAAQ,EAAE,EAAG,SAC1B,IAAM,EAAM,EAAgB,EAAO,CAAO,EAC1C,GAAI,CAAC,EAAK,SACV,IAAM,EAAI,EAAe,EAAO,EAAI,GAAI,EAAI,EAAE,CAAC,CAAC,KAC5C,GAAK,EAAW,UAAY,CAAC,GAAQ,EAAI,EAAK,KAAI,EAAO,CAAE,GAAI,EAAQ,GAAI,GAAE,EACnF,CACA,GAAI,EAAM,MAAO,CAAE,KAAM,UAAW,GAAI,EAAK,EAAG,CAClD,CAEA,GAAI,EAAQ,MAAM,EAAG,CACnB,IAAI,EAAyC,KAC7C,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAAG,CAC7C,GAAI,EAAS,EAAK,EAAE,EAAG,SACvB,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GAC3B,GAAI,CAAC,GAAK,CAAC,EAAG,SAGd,IAAM,EAAQ,KAAK,IAAI,EAAW,KAAM,EAAK,UAAY,CAAC,EACpD,EAAI,EAAe,EAAO,EAAG,CAAC,CAAC,CAAC,KAClC,GAAK,IAAU,CAAC,GAAQ,EAAI,EAAK,KAAI,EAAO,CAAE,GAAI,EAAK,GAAI,GAAE,EACnE,CACA,GAAI,EAAM,MAAO,CAAE,KAAM,OAAQ,GAAI,EAAK,EAAG,CAC/C,CAEA,GAAI,EAAQ,MAAM,EAAG,CACnB,IAAM,EAAO,EAAY,EAAO,CAAK,EACrC,GAAI,GAAM,QAAU,CAAC,EAAS,EAAK,MAAM,EAAG,MAAO,CAAE,KAAM,OAAQ,GAAI,EAAK,MAAO,CACrF,CAEA,OAAO,IACT,CAEA,SAAgB,EAAgB,EAAyB,EAAkC,CAGzF,OAFI,IAAM,EAAU,GAChB,CAAC,GAAK,CAAC,EAAU,GACd,EAAE,OAAS,EAAE,MAAQ,EAAE,KAAO,EAAE,EACzC"}
1
+ {"version":3,"file":"floorPlan.hit.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.hit.ts"],"sourcesContent":["/**\n * Hit testing against a derived plan.\n *\n * Tolerances arrive in WORLD units and are expected to have been converted from screen\n * pixels by the caller (`HIT_PX / view.zoom`), so a handle stays the same size on screen\n * at any zoom level.\n */\n\nimport { dist, pointToSegment } from './floorPlan.geometry';\nimport { openingGeometry } from './floorPlan.path';\nimport { roomAtPoint } from './floorPlan.rooms';\nimport type { DerivedRoom, PlanFloor, PlanPoint, PlanSelection } from './floorPlan.types';\n\nexport interface HitTolerances {\n node: number;\n opening: number;\n wall: number;\n}\n\n/** Screen-pixel hit radii, divided by `view.zoom` to get world tolerances. */\nexport const HIT_PX: HitTolerances = { node: 10, opening: 9, wall: 8 };\n/** Wider targets for touch, where there is no pixel-accurate pointer. */\nexport const HIT_PX_COARSE: HitTolerances = { node: 18, opening: 16, wall: 14 };\n\nexport function worldTolerances(px: HitTolerances, zoom: number): HitTolerances {\n const safeZoom = zoom > 0 ? zoom : 1;\n return { node: px.node / safeZoom, opening: px.opening / safeZoom, wall: px.wall / safeZoom };\n}\n\nexport interface HitTestOptions {\n /** Restricts what can be hit. Defaults to everything. */\n accept?: Array<PlanSelection['type']>;\n excludeIds?: ReadonlySet<string>;\n}\n\n/**\n * Finds what is under `point`, in priority order: node handle, opening, wall, then room\n * fill.\n *\n * The order is what makes editing feel right. A node sits on top of the walls that meet\n * there, and an opening sits on top of the wall it cuts, so the smaller, more specific\n * target always wins over the larger one underneath it.\n */\nexport function hitTest(\n floor: PlanFloor,\n rooms: DerivedRoom[],\n point: PlanPoint,\n tolerances: HitTolerances,\n options: HitTestOptions = {},\n): PlanSelection | null {\n const accepts = (type: PlanSelection['type']) => !options.accept || options.accept.includes(type);\n const excluded = (id: string) => options.excludeIds?.has(id) ?? false;\n\n if (accepts('node')) {\n let best: { id: string; d: number } | null = null;\n for (const node of Object.values(floor.nodes)) {\n if (excluded(node.id)) continue;\n const d = dist(point, node);\n if (d <= tolerances.node && (!best || d < best.d)) best = { id: node.id, d };\n }\n if (best) return { type: 'node', id: best.id };\n }\n\n if (accepts('opening')) {\n let best: { id: string; d: number } | null = null;\n for (const opening of Object.values(floor.openings)) {\n if (excluded(opening.id)) continue;\n const geo = openingGeometry(floor, opening);\n if (!geo) continue;\n const d = pointToSegment(point, geo.p1, geo.p2).dist;\n if (d <= tolerances.opening && (!best || d < best.d)) best = { id: opening.id, d };\n }\n if (best) return { type: 'opening', id: best.id };\n }\n\n if (accepts('wall')) {\n let best: { id: string; d: number } | null = null;\n for (const wall of Object.values(floor.walls)) {\n if (excluded(wall.id)) continue;\n const a = floor.nodes[wall.a];\n const b = floor.nodes[wall.b];\n if (!a || !b) continue;\n // Half the wall's own thickness, so a thick wall is grabbable across its body\n // rather than only along its centreline.\n const reach = Math.max(tolerances.wall, wall.thickness / 2);\n const d = pointToSegment(point, a, b).dist;\n if (d <= reach && (!best || d < best.d)) best = { id: wall.id, d };\n }\n if (best) return { type: 'wall', id: best.id };\n }\n\n if (accepts('room')) {\n const room = roomAtPoint(rooms, point);\n if (room?.roomId && !excluded(room.roomId)) return { type: 'room', id: room.roomId };\n }\n\n return null;\n}\n\nexport function selectionsEqual(a: PlanSelection | null, b: PlanSelection | null): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n return a.type === b.type && a.id === b.id;\n}\n"],"mappings":"4LAoBA,IAAa,EAAwB,CAAE,KAAM,GAAI,QAAS,EAAG,KAAM,CAAE,EAExD,EAA+B,CAAE,KAAM,GAAI,QAAS,GAAI,KAAM,EAAG,EAE9E,SAAgB,EAAgB,EAAmB,EAA6B,CAC9E,IAAM,EAAW,EAAO,EAAI,EAAO,EACnC,MAAO,CAAE,KAAM,EAAG,KAAO,EAAU,QAAS,EAAG,QAAU,EAAU,KAAM,EAAG,KAAO,CAAS,CAC9F,CAgBA,SAAgB,EACd,EACA,EACA,EACA,EACA,EAA0B,CAAC,EACL,CACtB,IAAM,EAAW,GAAgC,CAAC,EAAQ,QAAU,EAAQ,OAAO,SAAS,CAAI,EAC1F,EAAY,GAAe,EAAQ,YAAY,IAAI,CAAE,GAAK,GAEhE,GAAI,EAAQ,MAAM,EAAG,CACnB,IAAI,EAAyC,KAC7C,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAAG,CAC7C,GAAI,EAAS,EAAK,EAAE,EAAG,SACvB,IAAM,EAAI,EAAK,EAAO,CAAI,EACtB,GAAK,EAAW,OAAS,CAAC,GAAQ,EAAI,EAAK,KAAI,EAAO,CAAE,GAAI,EAAK,GAAI,GAAE,EAC7E,CACA,GAAI,EAAM,MAAO,CAAE,KAAM,OAAQ,GAAI,EAAK,EAAG,CAC/C,CAEA,GAAI,EAAQ,SAAS,EAAG,CACtB,IAAI,EAAyC,KAC7C,IAAK,IAAM,KAAW,OAAO,OAAO,EAAM,QAAQ,EAAG,CACnD,GAAI,EAAS,EAAQ,EAAE,EAAG,SAC1B,IAAM,EAAM,EAAgB,EAAO,CAAO,EAC1C,GAAI,CAAC,EAAK,SACV,IAAM,EAAI,EAAe,EAAO,EAAI,GAAI,EAAI,EAAE,CAAC,CAAC,KAC5C,GAAK,EAAW,UAAY,CAAC,GAAQ,EAAI,EAAK,KAAI,EAAO,CAAE,GAAI,EAAQ,GAAI,GAAE,EACnF,CACA,GAAI,EAAM,MAAO,CAAE,KAAM,UAAW,GAAI,EAAK,EAAG,CAClD,CAEA,GAAI,EAAQ,MAAM,EAAG,CACnB,IAAI,EAAyC,KAC7C,IAAK,IAAM,KAAQ,OAAO,OAAO,EAAM,KAAK,EAAG,CAC7C,GAAI,EAAS,EAAK,EAAE,EAAG,SACvB,IAAM,EAAI,EAAM,MAAM,EAAK,GACrB,EAAI,EAAM,MAAM,EAAK,GAC3B,GAAI,CAAC,GAAK,CAAC,EAAG,SAGd,IAAM,EAAQ,KAAK,IAAI,EAAW,KAAM,EAAK,UAAY,CAAC,EACpD,EAAI,EAAe,EAAO,EAAG,CAAC,CAAC,CAAC,KAClC,GAAK,IAAU,CAAC,GAAQ,EAAI,EAAK,KAAI,EAAO,CAAE,GAAI,EAAK,GAAI,GAAE,EACnE,CACA,GAAI,EAAM,MAAO,CAAE,KAAM,OAAQ,GAAI,EAAK,EAAG,CAC/C,CAEA,GAAI,EAAQ,MAAM,EAAG,CACnB,IAAM,EAAO,EAAY,EAAO,CAAK,EACrC,GAAI,GAAM,QAAU,CAAC,EAAS,EAAK,MAAM,EAAG,MAAO,CAAE,KAAM,OAAQ,GAAI,EAAK,MAAO,CACrF,CAEA,OAAO,IACT,CAEA,SAAgB,EAAgB,EAAyB,EAAkC,CAGzF,OAFI,IAAM,EAAU,GAChB,CAAC,GAAK,CAAC,EAAU,GACd,EAAE,OAAS,EAAE,MAAQ,EAAE,KAAO,EAAE,EACzC"}
@@ -1,2 +1,2 @@
1
- import{DoorSwing as e,OpeningKind as t,PlanUnitSystem as n,WallType as r}from"./floorPlan.types.mjs";import{cleanupPlan as i,newId as a}from"./floorPlan.graph.mjs";import{emptyFloor as o}from"./floorPlan.plan.mjs";var s=1;function c(e,t={}){return JSON.stringify(e,null,t.pretty===!1?void 0:2)}function l(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function u(e,t){let n=typeof e==`string`?Number(e):e;return typeof n==`number`&&Number.isFinite(n)?n:t}function d(e,t){return typeof e==`string`?e:t}function f(e,t){return typeof e==`boolean`?e:t}function p(e,t,n){return typeof e==`string`&&t.includes(e)?e:n}function m(e,t){return l(e)?{x:u(e.x,t.x),y:u(e.y,t.y)}:t}function h(e){return Array.isArray(e)?e:l(e)?Object.values(e):[]}function g(e){let t={};for(let n of e)t[n.id]=n;return t}function _(n,a,s){let c=`floor ${a+1}`,_=l(n)?n:{};l(n)||s.push(`${c} was not an object, so it was read as empty`);let v=o();v.id=d(_.id,v.id),v.label=d(_.label,v.label),v.elevation=u(_.elevation,0),v.height=u(_.height,v.height);let y=[];for(let e of h(_.nodes))l(e)&&typeof e.id==`string`&&y.push({id:e.id,x:u(e.x,0),y:u(e.y,0)});v.nodes=g(y);let b=[],x=0;for(let e of h(_.walls)){if(!l(e)||typeof e.id!=`string`)continue;let t=d(e.a,``),n=d(e.b,``);if(!v.nodes[t]||!v.nodes[n]||t===n){x+=1;continue}b.push({id:e.id,a:t,b:n,thickness:Math.max(1,u(e.thickness,100)),height:e.height===void 0?void 0:u(e.height,0),baseHeight:e.baseHeight===void 0?void 0:u(e.baseHeight,0),type:p(e.type,Object.values(r),r.Interior)})}v.walls=g(b),x>0&&s.push(`${c}: dropped ${x} wall(s) whose corners were missing`);let S=[],C=0;for(let n of h(_.openings)){if(!l(n)||typeof n.id!=`string`)continue;let r=d(n.wallId,``);if(!v.walls[r]){C+=1;continue}S.push({id:n.id,wallId:r,kind:p(n.kind,Object.values(t),t.Door),offset:u(n.offset,0),width:Math.max(1,u(n.width,800)),sill:u(n.sill,0),head:u(n.head,2100),swing:n.swing===void 0?void 0:p(n.swing,Object.values(e),e.StartLeft)})}v.openings=g(S),C>0&&s.push(`${c}: dropped ${C} opening(s) with no wall to sit in`);let w=[];for(let e of h(_.rooms))l(e)&&typeof e.id==`string`&&w.push({id:e.id,name:d(e.name,``),colour:typeof e.colour==`string`?e.colour:void 0,usage:typeof e.usage==`string`?e.usage:void 0,anchor:m(e.anchor,{x:0,y:0}),anchorPinned:f(e.anchorPinned,!1),seq:u(e.seq,w.length),wallIds:Array.isArray(e.wallIds)?e.wallIds.filter(e=>typeof e==`string`&&!!v.walls[e]):[],area:u(e.area,0)});v.rooms=g(w);let T=i(v);return T.result.length>0&&s.push(`${c}: repaired ${T.result.length} inconsistency(ies) in the geometry`),T.floor}function v(e){let t=[],r;try{r=JSON.parse(e)}catch(e){return{plan:null,issues:[`Not valid JSON: ${e.message}`]}}if(!l(r))return{plan:null,issues:[`Not a floor plan: expected an object`]};if(r.version!==void 0&&r.version!==1)return{plan:null,issues:[`Plan format version ${String(r.version)} is not supported (this build reads version 1)`]};r.version===void 0&&t.push(`No format version, read as version 1`);let i=Array.isArray(r.floors)?r.floors:[];if(i.length===0){if(r.floors!==void 0)t.push(`No floors in the file, started an empty one`);else return{plan:null,issues:["Not a floor plan: no `floors`"]}}let o=(i.length>0?i:[void 0]).map((e,n)=>_(e,n,t));return{plan:{id:d(r.id,a(`plan`)),name:typeof r.name==`string`?r.name:void 0,version:1,unitSystem:p(r.unitSystem,Object.values(n),n.Metric),floors:o,revision:u(r.revision,0)+1},issues:t}}export{s as PLAN_FORMAT_VERSION,v as planFromJson,c as planToJson};
1
+ "use client";import{DoorSwing as e,OpeningKind as t,PlanUnitSystem as n,WallType as r}from"./floorPlan.types.mjs";import{cleanupPlan as i,newId as a}from"./floorPlan.graph.mjs";import{emptyFloor as o}from"./floorPlan.plan.mjs";var s=1;function c(e,t={}){return JSON.stringify(e,null,t.pretty===!1?void 0:2)}function l(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function u(e,t){let n=typeof e==`string`?Number(e):e;return typeof n==`number`&&Number.isFinite(n)?n:t}function d(e,t){return typeof e==`string`?e:t}function f(e,t){return typeof e==`boolean`?e:t}function p(e,t,n){return typeof e==`string`&&t.includes(e)?e:n}function m(e,t){return l(e)?{x:u(e.x,t.x),y:u(e.y,t.y)}:t}function h(e){return Array.isArray(e)?e:l(e)?Object.values(e):[]}function g(e){let t={};for(let n of e)t[n.id]=n;return t}function _(n,a,s){let c=`floor ${a+1}`,_=l(n)?n:{};l(n)||s.push(`${c} was not an object, so it was read as empty`);let v=o();v.id=d(_.id,v.id),v.label=d(_.label,v.label),v.elevation=u(_.elevation,0),v.height=u(_.height,v.height);let y=[];for(let e of h(_.nodes))l(e)&&typeof e.id==`string`&&y.push({id:e.id,x:u(e.x,0),y:u(e.y,0)});v.nodes=g(y);let b=[],x=0;for(let e of h(_.walls)){if(!l(e)||typeof e.id!=`string`)continue;let t=d(e.a,``),n=d(e.b,``);if(!v.nodes[t]||!v.nodes[n]||t===n){x+=1;continue}b.push({id:e.id,a:t,b:n,thickness:Math.max(1,u(e.thickness,100)),height:e.height===void 0?void 0:u(e.height,0),baseHeight:e.baseHeight===void 0?void 0:u(e.baseHeight,0),type:p(e.type,Object.values(r),r.Interior)})}v.walls=g(b),x>0&&s.push(`${c}: dropped ${x} wall(s) whose corners were missing`);let S=[],C=0;for(let n of h(_.openings)){if(!l(n)||typeof n.id!=`string`)continue;let r=d(n.wallId,``);if(!v.walls[r]){C+=1;continue}S.push({id:n.id,wallId:r,kind:p(n.kind,Object.values(t),t.Door),offset:u(n.offset,0),width:Math.max(1,u(n.width,800)),sill:u(n.sill,0),head:u(n.head,2100),swing:n.swing===void 0?void 0:p(n.swing,Object.values(e),e.StartLeft)})}v.openings=g(S),C>0&&s.push(`${c}: dropped ${C} opening(s) with no wall to sit in`);let w=[];for(let e of h(_.rooms))l(e)&&typeof e.id==`string`&&w.push({id:e.id,name:d(e.name,``),colour:typeof e.colour==`string`?e.colour:void 0,usage:typeof e.usage==`string`?e.usage:void 0,anchor:m(e.anchor,{x:0,y:0}),anchorPinned:f(e.anchorPinned,!1),seq:u(e.seq,w.length),wallIds:Array.isArray(e.wallIds)?e.wallIds.filter(e=>typeof e==`string`&&!!v.walls[e]):[],area:u(e.area,0)});v.rooms=g(w);let T=i(v);return T.result.length>0&&s.push(`${c}: repaired ${T.result.length} inconsistency(ies) in the geometry`),T.floor}function v(e){let t=[],r;try{r=JSON.parse(e)}catch(e){return{plan:null,issues:[`Not valid JSON: ${e.message}`]}}if(!l(r))return{plan:null,issues:[`Not a floor plan: expected an object`]};if(r.version!==void 0&&r.version!==1)return{plan:null,issues:[`Plan format version ${String(r.version)} is not supported (this build reads version 1)`]};r.version===void 0&&t.push(`No format version, read as version 1`);let i=Array.isArray(r.floors)?r.floors:[];if(i.length===0){if(r.floors!==void 0)t.push(`No floors in the file, started an empty one`);else return{plan:null,issues:["Not a floor plan: no `floors`"]}}let o=(i.length>0?i:[void 0]).map((e,n)=>_(e,n,t));return{plan:{id:d(r.id,a(`plan`)),name:typeof r.name==`string`?r.name:void 0,version:1,unitSystem:p(r.unitSystem,Object.values(n),n.Metric),floors:o,revision:u(r.revision,0)+1},issues:t}}export{s as PLAN_FORMAT_VERSION,v as planFromJson,c as planToJson};
2
2
  //# sourceMappingURL=floorPlan.json.mjs.map