@ahrowe/ui 0.28.0 → 0.29.1
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.
- package/dist/esm/common/accordion/accordion.mjs.map +1 -1
- package/dist/esm/common/accordion/accordion.module.mjs +1 -1
- package/dist/esm/common/accordion/accordion.module.mjs.map +1 -1
- package/dist/esm/common/accordion/accordion.plain.module.mjs +1 -1
- package/dist/esm/common/accordion/accordion.plain.module.mjs.map +1 -1
- package/dist/esm/common/accordion/accordion.primary.module.mjs +1 -1
- package/dist/esm/common/accordion/accordion.primary.module.mjs.map +1 -1
- package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -1
- package/dist/esm/common/actionButtons/actionButtons.module.mjs +1 -1
- package/dist/esm/common/actionButtons/actionButtons.module.mjs.map +1 -1
- package/dist/esm/common/actionIcon/actionIcon.mjs.map +1 -1
- package/dist/esm/common/actionIcon/actionIcon.module.mjs +1 -1
- package/dist/esm/common/actionIcon/actionIcon.module.mjs.map +1 -1
- package/dist/esm/common/alert/alert.mjs.map +1 -1
- package/dist/esm/common/alert/alert.module.mjs +1 -1
- package/dist/esm/common/animatedIcon/animatedIcon.mjs.map +1 -1
- package/dist/esm/common/animatedIcon/animatedIcon.module.mjs +1 -1
- package/dist/esm/common/animatedIcon/animatedIcon.module.mjs.map +1 -1
- package/dist/esm/common/animatedLogo/animatedLogo.mjs.map +1 -1
- package/dist/esm/common/animatedLogo/animatedLogo.module.mjs +1 -1
- package/dist/esm/common/animatedText/animatedText.mjs +1 -1
- package/dist/esm/common/animatedText/animatedText.mjs.map +1 -1
- package/dist/esm/common/animatedText/animatedText.module.mjs +1 -1
- package/dist/esm/common/animatedText/animatedText.module.mjs.map +1 -1
- package/dist/esm/common/avatar/avatar.mjs.map +1 -1
- package/dist/esm/common/avatar/avatar.module.mjs +1 -1
- package/dist/esm/common/avatar/avatar.module.mjs.map +1 -1
- package/dist/esm/common/avatar/avatarGroup.mjs.map +1 -1
- package/dist/esm/common/badge/badge.mjs.map +1 -1
- package/dist/esm/common/badge/badge.module.mjs +1 -1
- package/dist/esm/common/badge/badge.module.mjs.map +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.module.mjs +1 -1
- package/dist/esm/common/button/button.mjs.map +1 -1
- package/dist/esm/common/button/button.module.mjs +1 -1
- package/dist/esm/common/button/button.module.mjs.map +1 -1
- package/dist/esm/common/buttonGroup/buttonGroup.mjs.map +1 -1
- package/dist/esm/common/buttonGroup/buttonGroup.module.mjs +1 -1
- package/dist/esm/common/buttonGroup/buttonGroup.module.mjs.map +1 -1
- package/dist/esm/common/card/Card.mjs +1 -1
- package/dist/esm/common/card/Card.mjs.map +1 -1
- package/dist/esm/common/card/CardActions.mjs.map +1 -1
- package/dist/esm/common/card/CardHeader.mjs.map +1 -1
- package/dist/esm/common/card/card.module.mjs +1 -1
- package/dist/esm/common/card/card.module.mjs.map +1 -1
- package/dist/esm/common/carousel/carousel.mjs +1 -1
- package/dist/esm/common/carousel/carousel.mjs.map +1 -1
- package/dist/esm/common/carousel/carousel.module.mjs +1 -1
- package/dist/esm/common/carousel/carousel.module.mjs.map +1 -1
- package/dist/esm/common/checkbox/checkbox.mjs.map +1 -1
- package/dist/esm/common/checkbox/checkbox.module.mjs +1 -1
- package/dist/esm/common/checkbox/checkbox.module.mjs.map +1 -1
- package/dist/esm/common/chip/chip.mjs +1 -1
- package/dist/esm/common/chip/chip.mjs.map +1 -1
- package/dist/esm/common/chip/chip.module.mjs +1 -1
- package/dist/esm/common/chip/chip.module.mjs.map +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
- package/dist/esm/common/colorPicker/colorPicker.module.mjs +1 -1
- package/dist/esm/common/colorPicker/colorPicker.module.mjs.map +1 -1
- package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
- package/dist/esm/common/configProvider/useComponentDefaults.mjs.map +1 -1
- package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs.map +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.module.mjs.map +1 -1
- package/dist/esm/common/datePicker/dateFunctions.mjs.map +1 -1
- package/dist/esm/common/datePicker/datePicker.mjs +1 -1
- package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
- package/dist/esm/common/datePicker/datePicker.module.mjs +1 -1
- package/dist/esm/common/divider/divider.mjs.map +1 -1
- package/dist/esm/common/divider/divider.module.mjs +1 -1
- package/dist/esm/common/drawer/drawer.mjs.map +1 -1
- package/dist/esm/common/drawer/drawer.module.mjs +1 -1
- package/dist/esm/common/drawer/drawer.module.mjs.map +1 -1
- package/dist/esm/common/dropZone/dropZone.mjs +1 -1
- package/dist/esm/common/dropZone/dropZone.mjs.map +1 -1
- package/dist/esm/common/dropZone/dropZone.module.mjs +1 -1
- package/dist/esm/common/dropZone/dropZone.module.mjs.map +1 -1
- package/dist/esm/common/dropdown/dropdown.mjs +1 -1
- package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
- package/dist/esm/common/dropdown/dropdown.module.mjs +1 -1
- package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
- package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
- package/dist/esm/common/emptyState/emptyState.module.mjs +1 -1
- package/dist/esm/common/errorBoundary/errorBoundary.mjs.map +1 -1
- package/dist/esm/common/errorBoundary/errorBoundary.module.mjs +1 -1
- package/dist/esm/common/errorBoundary/errorBoundary.module.mjs.map +1 -1
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -1
- package/dist/esm/common/fab/components/fabBase/fabBase.module.mjs +1 -1
- package/dist/esm/common/fab/fab.mjs.map +1 -1
- package/dist/esm/common/fab/fab.module.mjs +1 -1
- package/dist/esm/common/fab/fab.module.mjs.map +1 -1
- package/dist/esm/common/flip/flip.mjs +1 -1
- package/dist/esm/common/flip/flip.mjs.map +1 -1
- package/dist/esm/common/flip/flip.module.mjs +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.mjs +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.module.mjs +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +1 -1
- package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +1 -1
- package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.faces.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.geometry.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.graph.mjs +1 -1
- package/dist/esm/common/floorPlan/floorPlan.graph.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.hit.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.json.mjs +1 -1
- package/dist/esm/common/floorPlan/floorPlan.json.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.mesh.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.path.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.plan.mjs +1 -1
- package/dist/esm/common/floorPlan/floorPlan.plan.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.rooms.mjs +1 -1
- package/dist/esm/common/floorPlan/floorPlan.rooms.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.snap.mjs.map +1 -1
- package/dist/esm/common/floorPlan/floorPlan.triangulate.mjs +1 -1
- package/dist/esm/common/floorPlan/floorPlan.triangulate.mjs.map +1 -1
- package/dist/esm/common/floorPlan/legacySvg.mjs.map +1 -1
- package/dist/esm/common/hooks/useAnchorTracking.mjs +1 -1
- package/dist/esm/common/hooks/useAnchorTracking.mjs.map +1 -1
- package/dist/esm/common/hooks/useCoarsePointer.mjs +1 -1
- package/dist/esm/common/hooks/useFocusBoundary.mjs.map +1 -1
- package/dist/esm/common/hooks/useMediaQuery.mjs +1 -1
- package/dist/esm/common/hooks/useMediaQuery.mjs.map +1 -1
- package/dist/esm/common/hooks/useOverlay.mjs.map +1 -1
- package/dist/esm/common/hooks/useSheet.mjs +1 -1
- package/dist/esm/common/hooks/useSheet.mjs.map +1 -1
- package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
- package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
- package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
- package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
- package/dist/esm/common/iconPicker/iconPicker.module.mjs +1 -1
- package/dist/esm/common/idleManager/idleManager.mjs.map +1 -1
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +1 -1
- package/dist/esm/common/infiniteBlock/infiniteBlock.module.mjs +1 -1
- package/dist/esm/common/input/input.mjs +1 -1
- package/dist/esm/common/input/input.mjs.map +1 -1
- package/dist/esm/common/input/input.module.mjs +1 -1
- package/dist/esm/common/input/input.module.mjs.map +1 -1
- package/dist/esm/common/input/input.types.mjs.map +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.module.mjs +1 -1
- package/dist/esm/common/inputDropdown/inputDropdown.module.mjs.map +1 -1
- package/dist/esm/common/interactableDiv/interactableDiv.mjs +1 -1
- package/dist/esm/common/interactableDiv/interactableDiv.mjs.map +1 -1
- package/dist/esm/common/interactableDiv/interactableDiv.module.mjs +1 -1
- package/dist/esm/common/kanbanBoard/KanbanBoard.mjs +1 -1
- package/dist/esm/common/kanbanBoard/KanbanBoard.mjs.map +1 -1
- package/dist/esm/common/kanbanBoard/KanbanColumn.mjs +1 -1
- package/dist/esm/common/kanbanBoard/KanbanColumn.mjs.map +1 -1
- package/dist/esm/common/kanbanBoard/KanbanItem.mjs.map +1 -1
- package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs +1 -1
- package/dist/esm/common/kanbanBoard/kanbanBoard.module.mjs.map +1 -1
- package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs +1 -1
- package/dist/esm/common/kanbanBoard/kanbanBoard.utils.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs +1 -1
- package/dist/esm/common/klipyPicker/components/gifPreview/gifPreview.module.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/components/gifView/gifView.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs +1 -1
- package/dist/esm/common/klipyPicker/components/gifView/gifView.module.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/klipyPicker.module.mjs +1 -1
- package/dist/esm/common/loading/iconLoading/iconLoading.mjs.map +1 -1
- package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs +1 -1
- package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs.map +1 -1
- package/dist/esm/common/loading/spinnerLoading/spinnerLoading.mjs.map +1 -1
- package/dist/esm/common/loading/spinnerLoading/spinnerLoading.module.mjs +1 -1
- package/dist/esm/common/modal/modal.mjs.map +1 -1
- package/dist/esm/common/modal/modal.module.mjs +1 -1
- package/dist/esm/common/modal/modal.module.mjs.map +1 -1
- package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
- package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
- package/dist/esm/common/multiSelect/multiSelect.module.mjs +1 -1
- package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -1
- package/dist/esm/common/numberInput/numberInput.mjs +1 -1
- package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
- package/dist/esm/common/numberInput/numberInput.module.mjs +1 -1
- package/dist/esm/common/numberInput/numberInput.module.mjs.map +1 -1
- package/dist/esm/common/numberInput/useStepRepeat.mjs +1 -1
- package/dist/esm/common/numberInput/useStepRepeat.mjs.map +1 -1
- package/dist/esm/common/optionPicker/optionPicker.mjs +1 -1
- package/dist/esm/common/optionPicker/optionPicker.mjs.map +1 -1
- package/dist/esm/common/optionPicker/optionPicker.module.mjs +1 -1
- package/dist/esm/common/optionPicker/optionPicker.module.mjs.map +1 -1
- package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
- package/dist/esm/common/otpInput/otpInput.module.mjs +1 -1
- package/dist/esm/common/otpInput/otpInput.module.mjs.map +1 -1
- package/dist/esm/common/overscroll/overscroll.mjs.map +1 -1
- package/dist/esm/common/overscroll/overscroll.module.mjs +1 -1
- package/dist/esm/common/pagination/pagination.mjs.map +1 -1
- package/dist/esm/common/pagination/pagination.module.mjs +1 -1
- package/dist/esm/common/pagination/pagination.module.mjs.map +1 -1
- package/dist/esm/common/planCanvas/planCanvas.mjs +1 -1
- package/dist/esm/common/planCanvas/planCanvas.mjs.map +1 -1
- package/dist/esm/common/planCanvas/planCanvas.module.mjs +1 -1
- package/dist/esm/common/planCanvas/planCanvas.module.mjs.map +1 -1
- package/dist/esm/common/popover/popover.mjs +1 -1
- package/dist/esm/common/popover/popover.mjs.map +1 -1
- package/dist/esm/common/popover/popover.module.mjs +1 -1
- package/dist/esm/common/popover/popover.module.mjs.map +1 -1
- package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
- package/dist/esm/common/progressBar/progressBar.mjs +1 -1
- package/dist/esm/common/progressBar/progressBar.mjs.map +1 -1
- package/dist/esm/common/progressBar/progressBar.module.mjs +1 -1
- package/dist/esm/common/progressBar/progressBar.module.mjs.map +1 -1
- package/dist/esm/common/radioGroup/radioGroup.mjs +1 -1
- package/dist/esm/common/radioGroup/radioGroup.mjs.map +1 -1
- package/dist/esm/common/radioGroup/radioGroup.module.mjs +1 -1
- package/dist/esm/common/radioGroup/radioGroup.module.mjs.map +1 -1
- package/dist/esm/common/rating/rating.mjs +1 -1
- package/dist/esm/common/rating/rating.mjs.map +1 -1
- package/dist/esm/common/rating/rating.module.mjs +1 -1
- package/dist/esm/common/revealLens/revealLens.mjs.map +1 -1
- package/dist/esm/common/revealLens/revealLens.module.mjs +1 -1
- package/dist/esm/common/revealLens/revealLens.module.mjs.map +1 -1
- package/dist/esm/common/ripple/ripple.mjs.map +1 -1
- package/dist/esm/common/ripple/ripple.module.mjs +1 -1
- package/dist/esm/common/ripple/ripple.module.mjs.map +1 -1
- package/dist/esm/common/roomDrawer/roomDrawer.mjs +1 -1
- package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
- package/dist/esm/common/roomDrawer/roomDrawer.module.mjs +1 -1
- package/dist/esm/common/roomDrawer/roomDrawer.module.mjs.map +1 -1
- package/dist/esm/common/roomDrawer/usePlanHistory.mjs.map +1 -1
- package/dist/esm/common/roomViewer/roomViewer.mjs +1 -1
- package/dist/esm/common/roomViewer/roomViewer.mjs.map +1 -1
- package/dist/esm/common/roomViewer/roomViewer.module.mjs +1 -1
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.mjs.map +1 -1
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.module.mjs +1 -1
- package/dist/esm/common/scrollbarProvider/scrollbarProvider.module.mjs.map +1 -1
- package/dist/esm/common/searchInput/searchInput.mjs.map +1 -1
- package/dist/esm/common/searchInput/searchInput.module.mjs +1 -1
- package/dist/esm/common/sectionHeader/sectionHeader.mjs.map +1 -1
- package/dist/esm/common/sectionHeader/sectionHeader.module.mjs +1 -1
- package/dist/esm/common/sectionHeader/sectionHeader.module.mjs.map +1 -1
- package/dist/esm/common/skeleton/skeleton.mjs.map +1 -1
- package/dist/esm/common/skeleton/skeleton.module.mjs +1 -1
- package/dist/esm/common/slider/slider.mjs +1 -1
- package/dist/esm/common/slider/slider.mjs.map +1 -1
- package/dist/esm/common/slider/slider.module.mjs +1 -1
- package/dist/esm/common/slider/slider.module.mjs.map +1 -1
- package/dist/esm/common/splitButton/splitButton.mjs.map +1 -1
- package/dist/esm/common/splitButton/splitButton.module.mjs +1 -1
- package/dist/esm/common/stepper/stepper.mjs.map +1 -1
- package/dist/esm/common/stepper/stepper.module.mjs +1 -1
- package/dist/esm/common/stepper/stepper.module.mjs.map +1 -1
- package/dist/esm/common/sticky/sticky.mjs.map +1 -1
- package/dist/esm/common/sticky/sticky.module.mjs +1 -1
- package/dist/esm/common/sticky/stickyStack.mjs.map +1 -1
- package/dist/esm/common/styles/sheet.module.mjs +1 -1
- package/dist/esm/common/styles/sheet.module.mjs.map +1 -1
- package/dist/esm/common/switch/switch.mjs.map +1 -1
- package/dist/esm/common/switch/switch.module.mjs +1 -1
- package/dist/esm/common/tabHeader/tabHeader.mjs.map +1 -1
- package/dist/esm/common/tabHeader/tabHeader.module.mjs +1 -1
- package/dist/esm/common/tabHeader/tabHeader.module.mjs.map +1 -1
- package/dist/esm/common/themeProvider/defaultTheme.mjs.map +1 -1
- package/dist/esm/common/themeProvider/theme.module.mjs +1 -1
- package/dist/esm/common/themeProvider/themeProvider.mjs +1 -1
- package/dist/esm/common/themeProvider/themeProvider.mjs.map +1 -1
- package/dist/esm/common/themeProvider/useTheme.mjs.map +1 -1
- package/dist/esm/common/tilt/tilt.mjs.map +1 -1
- package/dist/esm/common/tilt/tilt.module.mjs +1 -1
- package/dist/esm/common/tiltGroup/tiltGroup.mjs.map +1 -1
- package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs +1 -1
- package/dist/esm/common/timeInput/components/clockDial/clockDial.mjs.map +1 -1
- package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs +1 -1
- package/dist/esm/common/timeInput/components/clockDial/clockDial.module.mjs.map +1 -1
- package/dist/esm/common/timeInput/timeFunctions.mjs +1 -1
- package/dist/esm/common/timeInput/timeFunctions.mjs.map +1 -1
- package/dist/esm/common/timeInput/timeInput.mjs +1 -1
- package/dist/esm/common/timeInput/timeInput.mjs.map +1 -1
- package/dist/esm/common/timeInput/timeInput.module.mjs +1 -1
- package/dist/esm/common/timeInput/timeInput.module.mjs.map +1 -1
- package/dist/esm/common/timeline/timeline.mjs.map +1 -1
- package/dist/esm/common/timeline/timeline.module.mjs +1 -1
- package/dist/esm/common/timeline/timeline.module.mjs.map +1 -1
- package/dist/esm/common/timer/timer.chime.mjs.map +1 -1
- package/dist/esm/common/timer/timer.mjs +1 -1
- package/dist/esm/common/timer/timer.mjs.map +1 -1
- package/dist/esm/common/timer/timer.module.mjs +1 -1
- package/dist/esm/common/timer/timer.module.mjs.map +1 -1
- package/dist/esm/common/toast/toast.mjs.map +1 -1
- package/dist/esm/common/toast/toast.module.mjs +1 -1
- package/dist/esm/common/toast/toast.module.mjs.map +1 -1
- package/dist/esm/common/toast/toastProvider.mjs.map +1 -1
- package/dist/esm/common/tooltip/tooltip.mjs.map +1 -1
- package/dist/esm/common/tooltip/tooltip.module.mjs +1 -1
- package/dist/esm/common/tooltip/tooltip.module.mjs.map +1 -1
- package/dist/esm/common/tree/flattenTree.mjs.map +1 -1
- package/dist/esm/common/tree/tree.mjs +1 -1
- package/dist/esm/common/tree/tree.mjs.map +1 -1
- package/dist/esm/common/tree/tree.module.mjs +1 -1
- package/dist/esm/common/utils/activationKey.mjs +2 -0
- package/dist/esm/common/utils/activationKey.mjs.map +1 -0
- package/dist/esm/common/utils/renderIcon.mjs +1 -1
- package/dist/esm/common/utils/renderIcon.mjs.map +1 -1
- package/dist/esm/common/virtualList/useColumns.mjs +1 -1
- package/dist/esm/common/virtualList/useColumns.mjs.map +1 -1
- package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
- package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
- package/dist/esm/common/virtualList/useSelection.mjs.map +1 -1
- package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
- package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualList.module.mjs +1 -1
- package/dist/esm/common/virtualList/virtualList.module.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualList.utils.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualRow.mjs +1 -1
- package/dist/esm/common/virtualList/virtualRow.mjs.map +1 -1
- package/dist/esm/common/wizard/wizard.mjs +1 -1
- package/dist/esm/common/wizard/wizard.mjs.map +1 -1
- package/dist/esm/common/wizard/wizard.module.mjs +1 -1
- package/dist/esm/services/formValidation/FormValidatorGroupWithForm.mjs.map +1 -1
- package/dist/esm/services/formValidation/index.mjs +1 -1
- package/dist/esm/services/formValidation/useFormValidatorGroup.mjs.map +1 -1
- package/dist/esm/services/formValidation/validatableComponent.mjs.map +1 -1
- package/dist/esm/services/klipy.mjs.map +1 -1
- package/dist/esm/services/localization.mjs.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/{package/common → common}/actionButtons/actionButtons.d.ts +1 -1
- package/dist/types/{package/common → common}/animatedIcon/animatedIcon.d.ts +1 -1
- package/dist/types/common/card/Card.d.ts +4 -0
- package/dist/types/{package/common → common}/card/CardActions.d.ts +2 -1
- package/dist/types/common/card/CardContent.d.ts +4 -0
- package/dist/types/{package/common → common}/card/CardHeader.d.ts +2 -1
- package/dist/types/common/card/CardMedia.d.ts +4 -0
- package/dist/types/common/carousel/carousel.d.ts +4 -0
- package/dist/types/common/chip/chip.d.ts +4 -0
- package/dist/types/{package/common → common}/configProvider/configProvider.d.ts +1 -1
- package/dist/types/{package/common → common}/datePicker/components/datePickerMonth/datePickerMonth.d.ts +1 -1
- package/dist/types/{package/common → common}/datePicker/datePicker.d.ts +1 -1
- package/dist/types/{package/common → common}/drawer/drawer.d.ts +1 -1
- package/dist/types/{package/common → common}/dropZone/dropZone.d.ts +2 -1
- package/dist/types/common/dropdown/dropdown.d.ts +4 -0
- package/dist/types/{package/common → common}/fab/components/fabBase/fabBase.d.ts +1 -1
- package/dist/types/{package/common → common}/fab/fab.d.ts +1 -1
- package/dist/types/{package/common → common}/floatingMenu/floatingMenu.d.ts +1 -1
- package/dist/types/{package/common → common}/floatingMenu/useFloatingPosition.d.ts +1 -1
- package/dist/types/{package/common → common}/hooks/useOverlay.d.ts +1 -1
- package/dist/types/{package/common → common}/iconPicker/iconPicker.d.ts +2 -1
- package/dist/types/{package/common → common}/idleManager/idleManager.d.ts +1 -1
- package/dist/types/{package/common → common}/infiniteBlock/infiniteBlock.d.ts +2 -1
- package/dist/types/common/input/input.d.ts +4 -0
- package/dist/types/{package/common → common}/inputDropdown/inputDropdown.d.ts +2 -1
- package/dist/types/{package/common → common}/kanbanBoard/KanbanBoard.d.ts +1 -1
- package/dist/types/{package/common → common}/kanbanBoard/KanbanColumn.d.ts +1 -1
- package/dist/types/{package/common → common}/kanbanBoard/KanbanItem.d.ts +1 -1
- package/dist/types/{package/common → common}/loading/iconLoading/iconLoading.d.ts +2 -1
- package/dist/types/common/modal/modal.d.ts +3 -0
- package/dist/types/{package/common → common}/overscroll/overscroll.d.ts +1 -1
- package/dist/types/common/popover/popover.d.ts +3 -0
- package/dist/types/{package/common → common}/scrollbarProvider/scrollbarProvider.d.ts +1 -1
- package/dist/types/{package/common → common}/sheetBackdrop/sheetBackdrop.d.ts +1 -1
- package/dist/types/common/slider/slider.d.ts +3 -0
- package/dist/types/{package/common → common}/slider/slider.types.d.ts +35 -10
- package/dist/types/{package/common → common}/splitButton/splitButton.d.ts +1 -1
- package/dist/types/{package/common → common}/stepper/stepper.d.ts +2 -1
- package/dist/types/{package/common → common}/sticky/sticky.d.ts +2 -1
- package/dist/types/{package/common → common}/tabHeader/tabHeader.d.ts +2 -1
- package/dist/types/common/textarea/textarea.d.ts +3 -0
- package/dist/types/{package/common → common}/themeProvider/theme.types.d.ts +30 -0
- package/dist/types/{package/common → common}/themeProvider/themeProvider.d.ts +1 -1
- package/dist/types/{package/common → common}/timeInput/components/clockDial/clockDial.d.ts +2 -1
- package/dist/types/{package/common → common}/timeInput/timeInput.d.ts +2 -1
- package/dist/types/{package/common → common}/timeline/timeline.d.ts +2 -1
- package/dist/types/{package/common → common}/toast/index.d.ts +1 -1
- package/dist/types/{package/common → common}/toast/toast.d.ts +2 -1
- package/dist/types/{package/common → common}/toast/toastProvider.d.ts +2 -2
- package/dist/types/{package/common → common}/tooltip/tooltip.d.ts +2 -1
- package/dist/types/common/utils/activationKey.d.ts +9 -0
- package/dist/types/{package/common → common}/virtualList/virtualRow.d.ts +1 -1
- package/dist/types/{package/common → common}/wizard/wizard.d.ts +2 -1
- package/dist/types/{package/services → services}/formValidation/index.d.ts +1 -1
- package/docs/Flip.md +1 -1
- package/docs/RoomDrawer.md +13 -5
- package/docs/RoomViewer.md +4 -0
- package/docs/Slider.md +34 -4
- package/package.json +73 -69
- package/dist/types/package/common/card/Card.d.ts +0 -3
- package/dist/types/package/common/card/CardContent.d.ts +0 -3
- package/dist/types/package/common/card/CardMedia.d.ts +0 -3
- package/dist/types/package/common/carousel/carousel.d.ts +0 -3
- package/dist/types/package/common/chip/chip.d.ts +0 -3
- package/dist/types/package/common/dropdown/dropdown.d.ts +0 -3
- package/dist/types/package/common/input/input.d.ts +0 -3
- package/dist/types/package/common/modal/modal.d.ts +0 -3
- package/dist/types/package/common/popover/popover.d.ts +0 -3
- package/dist/types/package/common/slider/slider.d.ts +0 -3
- package/dist/types/package/common/textarea/textarea.d.ts +0 -2
- /package/dist/types/{package/common → common}/accordion/accordion.d.ts +0 -0
- /package/dist/types/{package/common → common}/accordion/accordion.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/accordion/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/actionButtons/actionButtons.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/actionButtons/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/actionIcon/actionIcon.d.ts +0 -0
- /package/dist/types/{package/common → common}/actionIcon/actionIcon.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/actionIcon/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/alert/alert.d.ts +0 -0
- /package/dist/types/{package/common → common}/alert/alert.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/alert/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedIcon/animatedIcon.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedIcon/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedLogo/animatedLogo.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedLogo/animatedLogo.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedLogo/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedText/animatedText.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedText/animatedText.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/animatedText/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/avatar/avatar.d.ts +0 -0
- /package/dist/types/{package/common → common}/avatar/avatar.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/avatar/avatarGroup.d.ts +0 -0
- /package/dist/types/{package/common → common}/avatar/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/badge/badge.d.ts +0 -0
- /package/dist/types/{package/common → common}/badge/badge.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/badge/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/bodyEnd/bodyEnd.d.ts +0 -0
- /package/dist/types/{package/common → common}/bodyEnd/bodyEnd.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/bodyEnd/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/breadcrumb/breadcrumb.d.ts +0 -0
- /package/dist/types/{package/common → common}/breadcrumb/breadcrumb.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/breadcrumb/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/button/button.d.ts +0 -0
- /package/dist/types/{package/common → common}/button/button.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/button/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/buttonGroup/buttonGroup.d.ts +0 -0
- /package/dist/types/{package/common → common}/buttonGroup/buttonGroup.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/buttonGroup/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/card/card.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/card/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/carousel/carousel.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/carousel/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/checkbox/checkbox.d.ts +0 -0
- /package/dist/types/{package/common → common}/checkbox/checkbox.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/checkbox/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/chip/chip.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/chip/chipContainer.d.ts +0 -0
- /package/dist/types/{package/common → common}/chip/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/colorPicker/colorPicker.d.ts +0 -0
- /package/dist/types/{package/common → common}/colorPicker/colorPicker.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/colorPicker/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/configProvider/configProvider.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/configProvider/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/configProvider/useComponentDefaults.d.ts +0 -0
- /package/dist/types/{package/common → common}/configProvider/usePresentationDefault.d.ts +0 -0
- /package/dist/types/{package/common → common}/confirmModal/confirmModal.d.ts +0 -0
- /package/dist/types/{package/common → common}/confirmModal/confirmModal.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/confirmModal/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/datePicker/components/datePickerMonth/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/datePicker/dateFunctions.d.ts +0 -0
- /package/dist/types/{package/common → common}/datePicker/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/divider/divider.d.ts +0 -0
- /package/dist/types/{package/common → common}/divider/divider.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/divider/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/drawer/drawer.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/drawer/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/dropZone/dropZone.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/dropZone/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/dropdown/dropdown.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/dropdown/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/emptyState/emptyState.d.ts +0 -0
- /package/dist/types/{package/common → common}/emptyState/emptyState.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/emptyState/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/errorBoundary/errorBoundary.d.ts +0 -0
- /package/dist/types/{package/common → common}/errorBoundary/errorBoundary.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/errorBoundary/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/fab/components/fabBase/fabBase.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/fab/components/fabBase/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/fab/fab.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/fab/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/flip/flip.d.ts +0 -0
- /package/dist/types/{package/common → common}/flip/flip.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/flip/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/floatingMenu/floatingMenu.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/floatingMenu/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.faces.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.fixtures.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.geometry.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.graph.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.hit.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.json.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.mesh.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.path.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.plan.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.rooms.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.snap.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.triangulate.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/floorPlan.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/floorPlan/legacySvg.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useAnchorTracking.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useCoarsePointer.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useFocusBoundary.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useMediaQuery.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useSheet.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useSwipeDismiss.d.ts +0 -0
- /package/dist/types/{package/common → common}/hooks/useVisualViewportSize.d.ts +0 -0
- /package/dist/types/{package/common → common}/iconPicker/iconPicker.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/iconPicker/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/idleManager/idleManager.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/idleManager/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/infiniteBlock/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/infiniteBlock/infiniteBlock.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/input/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/input/input.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/inputDropdown/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/inputDropdown/inputDropdown.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/interactableDiv/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/interactableDiv/interactableDiv.d.ts +0 -0
- /package/dist/types/{package/common → common}/kanbanBoard/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/kanbanBoard/kanbanBoard.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/kanbanBoard/kanbanBoard.utils.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/components/gifPreview/gifPreview.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/components/gifPreview/gifPreview.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/components/gifPreview/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/components/gifView/gifView.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/components/gifView/gifView.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/components/gifView/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/klipyPicker.d.ts +0 -0
- /package/dist/types/{package/common → common}/klipyPicker/klipyPicker.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/loading/iconLoading/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/loading/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/loading/spinnerLoading/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/loading/spinnerLoading/spinnerLoading.d.ts +0 -0
- /package/dist/types/{package/common → common}/modal/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/modal/modal.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/multiSelect/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/multiSelect/multiSelect.d.ts +0 -0
- /package/dist/types/{package/common → common}/multiSelect/multiSelect.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/numberInput/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/numberInput/numberInput.d.ts +0 -0
- /package/dist/types/{package/common → common}/numberInput/numberInput.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/numberInput/useStepRepeat.d.ts +0 -0
- /package/dist/types/{package/common → common}/optionPicker/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/optionPicker/optionPicker.d.ts +0 -0
- /package/dist/types/{package/common → common}/optionPicker/optionPicker.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/otpInput/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/otpInput/otpInput.d.ts +0 -0
- /package/dist/types/{package/common → common}/otpInput/otpInput.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/overscroll/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/overscroll/overscroll.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/pagination/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/pagination/pagination.d.ts +0 -0
- /package/dist/types/{package/common → common}/pagination/pagination.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/planCanvas/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/planCanvas/planCanvas.d.ts +0 -0
- /package/dist/types/{package/common → common}/planCanvas/planCanvas.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/popover/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/popover/popover.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/popover/usePopoverPosition.d.ts +0 -0
- /package/dist/types/{package/common → common}/progressBar/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/progressBar/progressBar.d.ts +0 -0
- /package/dist/types/{package/common → common}/progressBar/progressBar.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/radioGroup/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/radioGroup/radioGroup.d.ts +0 -0
- /package/dist/types/{package/common → common}/radioGroup/radioGroup.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/rating/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/rating/rating.d.ts +0 -0
- /package/dist/types/{package/common → common}/rating/rating.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/revealLens/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/revealLens/revealLens.d.ts +0 -0
- /package/dist/types/{package/common → common}/revealLens/revealLens.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/ripple/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/ripple/ripple.d.ts +0 -0
- /package/dist/types/{package/common → common}/ripple/ripple.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomDrawer/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomDrawer/roomDrawer.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomDrawer/roomDrawer.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomDrawer/usePlanHistory.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomViewer/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomViewer/roomViewer.d.ts +0 -0
- /package/dist/types/{package/common → common}/roomViewer/roomViewer.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/scrollbarProvider/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/searchInput/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/searchInput/searchInput.d.ts +0 -0
- /package/dist/types/{package/common → common}/searchInput/searchInput.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/sectionHeader/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/sectionHeader/sectionHeader.d.ts +0 -0
- /package/dist/types/{package/common → common}/sectionHeader/sectionHeader.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/sheetBackdrop/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/sheetBackdrop/sheetBackdrop.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/skeleton/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/skeleton/skeleton.d.ts +0 -0
- /package/dist/types/{package/common → common}/skeleton/skeleton.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/slider/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/splitButton/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/splitButton/splitButton.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/stepper/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/stepper/stepper.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/sticky/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/sticky/sticky.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/sticky/stickyStack.d.ts +0 -0
- /package/dist/types/{package/common → common}/switch/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/switch/switch.d.ts +0 -0
- /package/dist/types/{package/common → common}/switch/switch.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/tabHeader/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/tabHeader/tabHeader.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/textarea/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/textarea/textarea.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/themeProvider/defaultTheme.d.ts +0 -0
- /package/dist/types/{package/common → common}/themeProvider/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/themeProvider/useTheme.d.ts +0 -0
- /package/dist/types/{package/common → common}/tilt/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/tilt/tilt.d.ts +0 -0
- /package/dist/types/{package/common → common}/tilt/tilt.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/tilt/tiltMath.d.ts +0 -0
- /package/dist/types/{package/common → common}/tiltGroup/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/tiltGroup/tiltGroup.d.ts +0 -0
- /package/dist/types/{package/common → common}/tiltGroup/tiltGroup.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeInput/components/clockDial/clockDial.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeInput/components/clockDial/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeInput/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeInput/timeFunctions.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeInput/timeInput.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeline/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/timeline/timeline.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/timer/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/timer/timer.chime.d.ts +0 -0
- /package/dist/types/{package/common → common}/timer/timer.d.ts +0 -0
- /package/dist/types/{package/common → common}/timer/timer.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/toast/toast.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/toast/toastService.d.ts +0 -0
- /package/dist/types/{package/common → common}/tooltip/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/tooltip/tooltip.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/tree/flattenTree.d.ts +0 -0
- /package/dist/types/{package/common → common}/tree/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/tree/tree.d.ts +0 -0
- /package/dist/types/{package/common → common}/tree/tree.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/types/actions.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/types/baseProps.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/types/icon.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/types/slots.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/utils/renderIcon.d.ts +0 -0
- /package/dist/types/{package/common → common}/utils/scrollAncestors.d.ts +0 -0
- /package/dist/types/{package/common → common}/utils/visualViewport.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/useColumns.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/useRowDrag.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/useSelection.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/useVirtualWindow.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/virtualList.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/virtualList.types.d.ts +0 -0
- /package/dist/types/{package/common → common}/virtualList/virtualList.utils.d.ts +0 -0
- /package/dist/types/{package/common → common}/wizard/index.d.ts +0 -0
- /package/dist/types/{package/common → common}/wizard/wizard.types.d.ts +0 -0
- /package/dist/types/{package/hooks → hooks}/useWindowSize.d.ts +0 -0
- /package/dist/types/{package/index.d.ts → index.d.ts} +0 -0
- /package/dist/types/{package/services → services}/formValidation/FormValidatorGroupWithForm.d.ts +0 -0
- /package/dist/types/{package/services → services}/formValidation/useFormValidatorGroup.d.ts +0 -0
- /package/dist/types/{package/services → services}/formValidation/validatableComponent.d.ts +0 -0
- /package/dist/types/{package/services → services}/klipy.d.ts +0 -0
- /package/dist/types/{package/services → services}/localization.d.ts +0 -0
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import n from"../bodyEnd/bodyEnd.mjs";import r from"./floatingMenu.module.mjs";import i from"../styles/sheet.module.mjs";import a from"../sheetBackdrop/sheetBackdrop.mjs";import{useFloatingPosition as o}from"./useFloatingPosition.mjs";import{tabbablesIn as s,useFocusBoundary as c}from"../hooks/useFocusBoundary.mjs";import{Align as l,Presentation as u}from"./floatingMenu.types.mjs";import d from"../hooks/useSheet.mjs";import{useOverlay as f}from"../hooks/useOverlay.mjs";import{useEffect as p,useRef as m,useState as h}from"react";import g from"classnames";import{jsx as _,jsxs as v}from"react/jsx-runtime";function y(e){return e.charAt(0).toUpperCase()+e.slice(1)}function b(b){let{align:x=l.Left,children:S=null,content:C=null,isOpen:w=!1,onOpenChange:T=()=>{},dontCloseOnChildClick:E=!1,presentation:D,className:O,style:k,classNames:A,styles:j,...M}=e(`FloatingMenu`,b),N=m(null),P=m(null),F=m(null),I=m(T),[L,R]=h(10),z=m(!1);function B(){z.current=!0}p(()=>{I.current=T});function V(){if(w){E||T(!1);return}let e=F.current?.getBoundingClientRect();R(e?.width??10),T(!0)}let H=t(),{isSheet:
|
|
1
|
+
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import n from"../bodyEnd/bodyEnd.mjs";import r from"./floatingMenu.module.mjs";import i from"../styles/sheet.module.mjs";import a from"../sheetBackdrop/sheetBackdrop.mjs";import{useFloatingPosition as o}from"./useFloatingPosition.mjs";import{tabbablesIn as s,useFocusBoundary as c}from"../hooks/useFocusBoundary.mjs";import{Align as l,Presentation as u}from"./floatingMenu.types.mjs";import d from"../hooks/useSheet.mjs";import{useOverlay as f}from"../hooks/useOverlay.mjs";import{useEffect as p,useRef as m,useState as h}from"react";import g from"classnames";import{jsx as _,jsxs as v}from"react/jsx-runtime";function y(e){return e.charAt(0).toUpperCase()+e.slice(1)}function b(b){let{align:x=l.Left,children:S=null,content:C=null,isOpen:w=!1,onOpenChange:T=()=>{},dontCloseOnChildClick:E=!1,presentation:D,className:O,style:k,classNames:A,styles:j,...M}=e(`FloatingMenu`,b),N=m(null),P=m(null),F=m(null),I=m(T),[L,R]=h(10),z=m(!1);function B(){z.current=!0}p(()=>{I.current=T});function V(){if(w){E||T(!1);return}let e=F.current?.getBoundingClientRect();R(e?.width??10),T(!0)}let H=t(),U=D??H??u.Default,{isSheet:W,sheetStyle:G}=d(U);o({isOpen:w&&!W,triggerRef:F,anchorRef:P,panelRef:N,flipClassName:r.floatingMenuAnimFlip}),p(()=>{if(!w)return;function e(e){let t=N.current,n=F.current;if(!t||!n)return;let r=e.target;if(n===r||n.contains(r))return;let i=z.current;z.current=!1,(!(i||t===r||t.contains(r))||!E)&&I.current(!1)}return window.addEventListener(`mouseup`,e),()=>window.removeEventListener(`mouseup`,e)},[w,E]);let{restoreFocusToTrigger:K,focusAfterTrigger:q}=c({triggerRef:F,contentRef:N});f({isActive:w,containerRef:N,onEscape:()=>{N.current?.contains(document.activeElement)&&K(),I.current(!1)},trapFocus:!1,lockScroll:W});function J(e){if(e.key!==`Tab`)return;let t=s(N.current);if(t.length===0)return;let n=document.activeElement;!e.shiftKey&&n===t[t.length-1]?(e.preventDefault(),q(),I.current(!1)):e.shiftKey&&n===t[0]&&(e.preventDefault(),K(),I.current(!1))}return v(`div`,{...M,className:g(r.floatingMenu,O,A?.root),style:{...k,...j?.root},children:[_(`div`,{className:g(r.floatingMenuContent,A?.trigger),style:j?.trigger,ref:F,onClick:V,children:S}),w&&v(n,{children:[W&&_(a,{onClose:()=>I.current(!1),className:A?.backdrop,style:j?.backdrop}),v(`div`,{ref:P,className:g(W?i.sheet:r.floatingMenuAnim,A?.menu),style:{...W?G:{width:`${L}px`},...j?.menu},children:[!W&&_(`div`,{className:g(r.floatingMenuContainerFlag,r[`floatingMenuContainerFlagAlign${y(x)}`])}),_(`div`,{ref:N,className:g(r.floatingMenuContainer,W?i.sheetPanel:[r.floatingMenuContainerAnchored,r[`floatingMenuContainerAlign${y(x)}`]],A?.menuContainer),style:j?.menuContainer,onMouseUpCapture:B,onKeyDown:J,children:C})]})]})]})}export{b as default};
|
|
2
2
|
//# sourceMappingURL=floatingMenu.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floatingMenu.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './floatingMenu.module.pcss';\nimport sheetStyles from '../styles/sheet.module.pcss';\nimport SheetBackdrop from '../sheetBackdrop';\nimport { useFloatingPosition } from './useFloatingPosition';\nimport { useFocusBoundary, tabbablesIn } from '../hooks/useFocusBoundary';\nimport { useSheet } from '../hooks/useSheet';\nimport { useOverlay } from '../hooks/useOverlay';\nimport { useComponentDefaults, usePresentationDefault } from '../configProvider';\nimport { Align, Presentation, FloatingMenuProps } from './floatingMenu.types';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction FloatingMenu(props: FloatingMenuProps) {\n const {\n align = Align.Left,\n children = null,\n content = null,\n isOpen = false,\n onOpenChange = () => {},\n dontCloseOnChildClick = false,\n presentation: presentationProp,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('FloatingMenu', props);\n const menuContainerRef = useRef<HTMLDivElement>(null);\n const menuAnimRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const onOpenChangeRef = useRef(onOpenChange);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const contentInteractedRef = useRef(false);\n function handleContentMouseUp() {\n contentInteractedRef.current = true;\n }\n\n useEffect(() => { onOpenChangeRef.current = onOpenChange; });\n\n function handleTriggerClick() {\n if (isOpen) {\n if (!dontCloseOnChildClick) onOpenChange(false);\n return;\n }\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n onOpenChange(true);\n }\n\n // Explicit prop → this component's global default → the app-wide one → anchored.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation ?? Presentation.Default;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n // A sheet isn't anchored to anything, so there's nothing to track, flip or clamp.\n useFloatingPosition({\n isOpen: isOpen && !isSheet,\n triggerRef,\n anchorRef: menuAnimRef,\n panelRef: menuContainerRef,\n flipClassName: styles.floatingMenuAnimFlip,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n function onMouseUp(event: MouseEvent) {\n const menuElem = menuContainerRef.current;\n const triggerElem = triggerRef.current;\n if (!menuElem || !triggerElem) return;\n\n const target = event.target as Node;\n if (triggerElem === target || triggerElem.contains(target)) return;\n\n const contentInteracted = contentInteractedRef.current;\n contentInteractedRef.current = false;\n const clickedInMenu = contentInteracted || menuElem === target || menuElem.contains(target);\n\n if (!clickedInMenu || !dontCloseOnChildClick) {\n onOpenChangeRef.current(false);\n }\n }\n\n window.addEventListener('mouseup', onMouseUp);\n return () => window.removeEventListener('mouseup', onMouseUp);\n }, [isOpen, dontCloseOnChildClick]);\n\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({\n triggerRef,\n contentRef: menuContainerRef,\n });\n\n // Registered for as long as the menu is open, not just as a sheet: this is what puts it on the\n // overlay stack, so an enclosing Modal knows something sits above it. Without that, the modal\n // stays topmost and its focus trap drags focus out of this menu — which lives outside the\n // modal's panel, in the portal — and Escape closes the modal instead of just this menu.\n // Focus is deliberately not trapped: the menu doesn't take focus on open (see\n // `handleMenuKeyDown`), so there'd be nothing inside to trap.\n useOverlay({\n isActive: isOpen,\n containerRef: menuContainerRef,\n onEscape: () => {\n if (menuContainerRef.current?.contains(document.activeElement)) restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n },\n trapFocus: false,\n lockScroll: isSheet,\n });\n\n // The menu is portaled to the end of the DOM, so Tab never flows into it naturally. When\n // `content` has real focusable elements, close on Tab out of either end and continue focus as\n // if the menu sat right after the trigger. Escape is handled by `useOverlay` above instead, so\n // that it works from the trigger too and closes only the innermost open layer.\n // Unlike Popover, this doesn't also auto-focus the\n // first element on open, content here ranges from menus to live controls like ColorPicker's\n // hue slider, where grabbing focus on open would let a stray arrow-key press nudge a value the\n // user never interacted with. Auto-focus-on-open is still worth doing per-consumer (e.g.\n // SplitButton focuses its first enabled action), just not assumed generically here.\n function handleMenuKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'Tab') return;\n const focusables = tabbablesIn(menuContainerRef.current);\n if (focusables.length === 0) return;\n const active = document.activeElement;\n if (!event.shiftKey && active === focusables[focusables.length - 1]) {\n event.preventDefault();\n focusAfterTrigger();\n onOpenChangeRef.current(false);\n } else if (event.shiftKey && active === focusables[0]) {\n event.preventDefault();\n restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n }\n }\n\n return (\n <div {...rest} className={cx(styles.floatingMenu, className, classNames?.root)} style={{ ...style, ...slotStyles?.root }}>\n <div\n className={cx(styles.floatingMenuContent, classNames?.trigger)}\n style={slotStyles?.trigger}\n ref={triggerRef}\n onClick={handleTriggerClick}\n >\n {children}\n </div>\n {isOpen && (\n <BodyEnd>\n {isSheet && (\n <SheetBackdrop\n onClose={() => onOpenChangeRef.current(false)}\n className={classNames?.backdrop}\n style={slotStyles?.backdrop}\n />\n )}\n <div\n ref={menuAnimRef}\n className={cx(isSheet ? sheetStyles.sheet : styles.floatingMenuAnim, classNames?.menu)}\n style={{\n // A sheet spans the screen; only an anchored menu takes the trigger's width.\n ...(isSheet ? sheetStyle : { width: `${triggerWidth}px` }),\n ...slotStyles?.menu,\n }}\n >\n {!isSheet && (\n <div className={cx(\n styles.floatingMenuContainerFlag,\n styles[`floatingMenuContainerFlagAlign${capitalize(align)}`],\n )} />\n )}\n <div\n ref={menuContainerRef}\n className={cx(\n styles.floatingMenuContainer,\n isSheet ? sheetStyles.sheetPanel : [\n styles.floatingMenuContainerAnchored,\n styles[`floatingMenuContainerAlign${capitalize(align)}`],\n ],\n classNames?.menuContainer,\n )}\n style={slotStyles?.menuContainer}\n onMouseUpCapture={handleContentMouseUp}\n onKeyDown={handleMenuKeyDown}\n >\n {content}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n\nexport default FloatingMenu;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"floatingMenu.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './floatingMenu.module.pcss';\nimport sheetStyles from '../styles/sheet.module.pcss';\nimport SheetBackdrop from '../sheetBackdrop';\nimport { useFloatingPosition } from './useFloatingPosition';\nimport { useFocusBoundary, tabbablesIn } from '../hooks/useFocusBoundary';\nimport { useSheet } from '../hooks/useSheet';\nimport { useOverlay } from '../hooks/useOverlay';\nimport { useComponentDefaults, usePresentationDefault } from '../configProvider';\nimport { Align, Presentation, FloatingMenuProps } from './floatingMenu.types';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction FloatingMenu(props: FloatingMenuProps) {\n const {\n align = Align.Left,\n children = null,\n content = null,\n isOpen = false,\n onOpenChange = () => {},\n dontCloseOnChildClick = false,\n presentation: presentationProp,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('FloatingMenu', props);\n const menuContainerRef = useRef<HTMLDivElement>(null);\n const menuAnimRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const onOpenChangeRef = useRef(onOpenChange);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const contentInteractedRef = useRef(false);\n function handleContentMouseUp() {\n contentInteractedRef.current = true;\n }\n\n useEffect(() => {\n onOpenChangeRef.current = onOpenChange;\n });\n\n function handleTriggerClick() {\n if (isOpen) {\n if (!dontCloseOnChildClick) onOpenChange(false);\n return;\n }\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n onOpenChange(true);\n }\n\n // Explicit prop → this component's global default → the app-wide one → anchored.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation ?? Presentation.Default;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n // A sheet isn't anchored to anything, so there's nothing to track, flip or clamp.\n useFloatingPosition({\n isOpen: isOpen && !isSheet,\n triggerRef,\n anchorRef: menuAnimRef,\n panelRef: menuContainerRef,\n flipClassName: styles.floatingMenuAnimFlip,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n function onMouseUp(event: MouseEvent) {\n const menuElem = menuContainerRef.current;\n const triggerElem = triggerRef.current;\n if (!menuElem || !triggerElem) return;\n\n const target = event.target as Node;\n if (triggerElem === target || triggerElem.contains(target)) return;\n\n const contentInteracted = contentInteractedRef.current;\n contentInteractedRef.current = false;\n const clickedInMenu = contentInteracted || menuElem === target || menuElem.contains(target);\n\n if (!clickedInMenu || !dontCloseOnChildClick) {\n onOpenChangeRef.current(false);\n }\n }\n\n window.addEventListener('mouseup', onMouseUp);\n return () => window.removeEventListener('mouseup', onMouseUp);\n }, [isOpen, dontCloseOnChildClick]);\n\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({\n triggerRef,\n contentRef: menuContainerRef,\n });\n\n // Registered for as long as the menu is open, not just as a sheet: this is what puts it on the\n // overlay stack, so an enclosing Modal knows something sits above it. Without that, the modal\n // stays topmost and its focus trap drags focus out of this menu — which lives outside the\n // modal's panel, in the portal — and Escape closes the modal instead of just this menu.\n // Focus is deliberately not trapped: the menu doesn't take focus on open (see\n // `handleMenuKeyDown`), so there'd be nothing inside to trap.\n useOverlay({\n isActive: isOpen,\n containerRef: menuContainerRef,\n onEscape: () => {\n if (menuContainerRef.current?.contains(document.activeElement)) restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n },\n trapFocus: false,\n lockScroll: isSheet,\n });\n\n // The menu is portaled to the end of the DOM, so Tab never flows into it naturally. When\n // `content` has real focusable elements, close on Tab out of either end and continue focus as\n // if the menu sat right after the trigger. Escape is handled by `useOverlay` above instead, so\n // that it works from the trigger too and closes only the innermost open layer.\n // Unlike Popover, this doesn't also auto-focus the\n // first element on open, content here ranges from menus to live controls like ColorPicker's\n // hue slider, where grabbing focus on open would let a stray arrow-key press nudge a value the\n // user never interacted with. Auto-focus-on-open is still worth doing per-consumer (e.g.\n // SplitButton focuses its first enabled action), just not assumed generically here.\n function handleMenuKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'Tab') return;\n const focusables = tabbablesIn(menuContainerRef.current);\n if (focusables.length === 0) return;\n const active = document.activeElement;\n if (!event.shiftKey && active === focusables[focusables.length - 1]) {\n event.preventDefault();\n focusAfterTrigger();\n onOpenChangeRef.current(false);\n } else if (event.shiftKey && active === focusables[0]) {\n event.preventDefault();\n restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n }\n }\n\n return (\n <div\n {...rest}\n className={cx(styles.floatingMenu, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <div\n className={cx(styles.floatingMenuContent, classNames?.trigger)}\n style={slotStyles?.trigger}\n ref={triggerRef}\n onClick={handleTriggerClick}\n >\n {children}\n </div>\n {isOpen && (\n <BodyEnd>\n {isSheet && (\n <SheetBackdrop\n onClose={() => onOpenChangeRef.current(false)}\n className={classNames?.backdrop}\n style={slotStyles?.backdrop}\n />\n )}\n <div\n ref={menuAnimRef}\n className={cx(isSheet ? sheetStyles.sheet : styles.floatingMenuAnim, classNames?.menu)}\n style={{\n // A sheet spans the screen; only an anchored menu takes the trigger's width.\n ...(isSheet ? sheetStyle : { width: `${triggerWidth}px` }),\n ...slotStyles?.menu,\n }}\n >\n {!isSheet && (\n <div\n className={cx(\n styles.floatingMenuContainerFlag,\n styles[`floatingMenuContainerFlagAlign${capitalize(align)}`],\n )}\n />\n )}\n <div\n ref={menuContainerRef}\n className={cx(\n styles.floatingMenuContainer,\n isSheet\n ? sheetStyles.sheetPanel\n : [styles.floatingMenuContainerAnchored, styles[`floatingMenuContainerAlign${capitalize(align)}`]],\n classNames?.menuContainer,\n )}\n style={slotStyles?.menuContainer}\n onMouseUpCapture={handleContentMouseUp}\n onKeyDown={handleMenuKeyDown}\n >\n {content}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n\nexport default FloatingMenu;\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e={floatingMenu
|
|
1
|
+
var e=`floatingMenu_E1XCy`,t=`floatingMenu-content_AmxkA`,n=`floatingMenu-container_w7k-Y`,r=`floatingMenu-container-anchored_-8CHY`,i=`floatingMenu-anim-flip_a4-Ri`,a=`floatingMenu-container-align-left_InKnZ`,o=`floatingMenu-container-align-right_a9OoS`,s=`floatingMenu-container-align-center_-8bGT`,c=`floatingMenu-container-flag_VdKHr`,l=`floatingMenu-container-flag-align-right_vxrRN`,u=`floatingMenu-container-flag-align-left_a2Vv-`,d=`floatingMenu-container-flag-align-center_SmaaY`,f=`floatingMenu-anim_5KB-f`,p=`showMenu_AprCh`,m={floatingMenu:e,"floatingMenu-content":`floatingMenu-content_AmxkA`,floatingMenuContent:t,"floatingMenu-container":`floatingMenu-container_w7k-Y`,floatingMenuContainer:n,"floatingMenu-container-anchored":`floatingMenu-container-anchored_-8CHY`,floatingMenuContainerAnchored:r,"floatingMenu-anim-flip":`floatingMenu-anim-flip_a4-Ri`,floatingMenuAnimFlip:i,"floatingMenu-container-align-left":`floatingMenu-container-align-left_InKnZ`,floatingMenuContainerAlignLeft:a,"floatingMenu-container-align-right":`floatingMenu-container-align-right_a9OoS`,floatingMenuContainerAlignRight:o,"floatingMenu-container-align-center":`floatingMenu-container-align-center_-8bGT`,floatingMenuContainerAlignCenter:s,"floatingMenu-container-flag":`floatingMenu-container-flag_VdKHr`,floatingMenuContainerFlag:c,"floatingMenu-container-flag-align-right":`floatingMenu-container-flag-align-right_vxrRN`,floatingMenuContainerFlagAlignRight:l,"floatingMenu-container-flag-align-left":`floatingMenu-container-flag-align-left_a2Vv-`,floatingMenuContainerFlagAlignLeft:u,"floatingMenu-container-flag-align-center":`floatingMenu-container-flag-align-center_SmaaY`,floatingMenuContainerFlagAlignCenter:d,"floatingMenu-anim":`floatingMenu-anim_5KB-f`,floatingMenuAnim:f,showMenu:p};export{m as default,e as floatingMenu,f as floatingMenuAnim,i as floatingMenuAnimFlip,n as floatingMenuContainer,s as floatingMenuContainerAlignCenter,a as floatingMenuContainerAlignLeft,o as floatingMenuContainerAlignRight,r as floatingMenuContainerAnchored,c as floatingMenuContainerFlag,d as floatingMenuContainerFlagAlignCenter,u as floatingMenuContainerFlagAlignLeft,l as floatingMenuContainerFlagAlignRight,t as floatingMenuContent,p as showMenu};
|
|
2
2
|
//# sourceMappingURL=floatingMenu.module.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floatingMenu.module.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.module.pcss"],"sourcesContent":[".floatingMenu {\n position: relative;\n\n &-content {\n display: flex;\n align-items: stretch;\n height: 100%;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-container {\n color: var(--text-color);\n font-family: var(--default-font);\n font-size: var(--default-font-size);\n box-shadow: var(--card-shadow);\n background: var(--background-modal);\n padding: 8px;\n border-radius: calc(var(--default-border-radius) + 4px);\n\n /* Positioning lives here rather than on `&-container` itself, so that sheet presentation\n can leave it off instead of having to override it. */\n &-anchored {\n position: absolute;\n margin-top: 10px;\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 10px;\n }\n }\n\n &-align {\n &-left {\n left:
|
|
1
|
+
{"version":3,"file":"floatingMenu.module.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.module.pcss"],"sourcesContent":[".floatingMenu {\n position: relative;\n\n &-content {\n display: flex;\n align-items: stretch;\n height: 100%;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-container {\n color: var(--text-color);\n font-family: var(--default-font);\n font-size: var(--default-font-size);\n box-shadow: var(--card-shadow);\n background: var(--background-modal);\n padding: 8px;\n border-radius: calc(var(--default-border-radius) + 4px);\n\n /* Positioning lives here rather than on `&-container` itself, so that sheet presentation\n can leave it off instead of having to override it. */\n &-anchored {\n position: absolute;\n margin-top: 10px;\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 10px;\n }\n }\n\n &-align {\n &-left {\n left: 0;\n }\n\n &-right {\n right: 0;\n }\n\n &-center {\n left: 50%;\n transform: translateX(-50%);\n }\n }\n\n &-flag {\n box-shadow: var(--card-shadow);\n background: var(--background-modal);\n height: 10px;\n width: 10px;\n position: absolute;\n margin-top: 5px;\n transform: rotate(45deg);\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 5px;\n }\n\n &-align-right {\n right: 8px;\n }\n\n &-align-left {\n left: 8px;\n }\n\n &-align-center {\n left: 50%;\n transform: translateX(-50%) rotate(45deg);\n }\n }\n }\n\n &-anim {\n transform: scale(0.7);\n opacity: 0.7;\n animation: showMenu 0.1s forwards;\n position: fixed;\n z-index: 1;\n }\n\n @keyframes showMenu {\n to {\n transform: scale(1);\n opacity: 1;\n }\n }\n}\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floatingMenu.types.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from
|
|
1
|
+
{"version":3,"file":"floatingMenu.types.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** How a surface is presented on screen. */\nexport enum Presentation {\n /** Wherever the component normally puts it: anchored to its trigger, or centred for a Modal. */\n Default = 'default',\n /** Pinned to the bottom of the screen, full width up to a maximum. */\n Sheet = 'sheet',\n /** A sheet on touch devices with a small screen, anchored everywhere else. */\n Auto = 'auto',\n}\n\nexport enum Align {\n Left = 'left',\n Right = 'right',\n Center = 'center',\n}\n\nexport type FloatingMenuSlots = 'root' | 'trigger' | 'menu' | 'menuContainer' | 'backdrop';\n\nexport interface FloatingMenuProps extends Omit<HtmlProps, 'content'> {\n align?: Align;\n children?: ReactNode;\n content?: ReactNode;\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n dontCloseOnChildClick?: boolean;\n /** Where the menu opens: anchored to the trigger (`Default`), pinned to the bottom of the\n * screen, or the latter only on a small touch screen. */\n presentation?: Presentation;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<FloatingMenuSlots>;\n styles?: SlotStyles<FloatingMenuSlots>;\n}\n"],"mappings":"AAIA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,MAAA,QAEA,EAAA,KAAA,QACF,EAAA,CAAA,CAAA,EAEY,EAAL,SAAA,EAAA,OACL,GAAA,KAAA,OACA,EAAA,MAAA,QACA,EAAA,OAAA,UACF,EAAA,CAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { type RefObject } from 'react';\nimport { isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\nimport { useAnchorTracking } from '../hooks/useAnchorTracking';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: flips above the\n * trigger when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * `useAnchorTracking` supplies the lifecycle around this: mount wait, ancestor resolution, and\n * re-running on scroll, viewport resize and panel size changes.\n */\nexport function useFloatingPosition({
|
|
1
|
+
{"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { type RefObject } from 'react';\nimport { isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\nimport { useAnchorTracking } from '../hooks/useAnchorTracking';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: flips above the\n * trigger when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * `useAnchorTracking` supplies the lifecycle around this: mount wait, ancestor resolution, and\n * re-running on scroll, viewport resize and panel size changes.\n */\nexport function useFloatingPosition({\n isOpen,\n triggerRef,\n anchorRef,\n panelRef,\n flipClassName,\n placement = 'bottom',\n}: UseFloatingPositionArgs) {\n useAnchorTracking({\n isOpen,\n triggerRef,\n elementRefs: [anchorRef],\n // Both, since they're the same element for a panel-as-anchor consumer (Dropdown) but not for\n // a zero-height wrapper whose content sits inside it (FloatingMenu).\n resizeRefs: [anchorRef, panelRef],\n deps: [anchorRef, panelRef, flipClassName, placement],\n\n update: (trigger, ancestors) => {\n const anchor = anchorRef.current;\n if (!anchor) return;\n\n const rect = trigger.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n // The visible area, not the full layout viewport — shrinks on mobile when a keyboard is\n // open, so flip/clamp react to what's actually on screen instead of the keyboard hiding\n // a panel that \"fit\" against the unshrunk layout viewport.\n const vv = getVisualViewportRect();\n const spaceBelow = vv.top + vv.height - rect.bottom;\n const spaceAbove = rect.top - vv.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor.style.top = `${renderAbove ? rect.top - anchor.offsetHeight : rect.bottom}px`;\n anchor.style.left = `${rect.left}px`;\n\n // Horizontal clamp: shift the anchor so the panel stays within the viewport, since\n // `align` CSS only positions it relative to the anchor's own box. Use offsetWidth/\n // offsetLeft (untransformed layout geometry), not getBoundingClientRect — both this\n // anchor and Dropdown's animate in via a CSS `transform: scale(...)`, which\n // getBoundingClientRect reflects but the box-model offsets don't, so measuring via\n // the transformed rect would under- or over-correct while that entrance animation runs.\n const panelForClamp = panelRef.current;\n if (panelForClamp) {\n const relativeLeft = panelForClamp === anchor ? 0 : panelForClamp.offsetLeft;\n const panelLeft = rect.left + relativeLeft;\n const panelRight = panelLeft + panelForClamp.offsetWidth;\n const overflowRight = panelRight - (vv.left + vv.width - EDGE_MARGIN);\n const overflowLeft = vv.left + EDGE_MARGIN - panelLeft;\n if (overflowRight > 0) {\n anchor.style.left = `${rect.left - overflowRight}px`;\n } else if (overflowLeft > 0) {\n anchor.style.left = `${rect.left + overflowLeft}px`;\n }\n }\n\n anchor.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n },\n\n teardown: () => {\n // Positioning is written as inline styles, which outrank any class the popup might switch\n // to while it stays mounted — a popup turning into a bottom sheet (`useSheet`) would keep\n // the coordinates computed for its anchored self. Hand the element back as we found it.\n const anchor = anchorRef.current;\n if (!anchor) return;\n anchor.style.top = '';\n anchor.style.left = '';\n anchor.style.visibility = '';\n anchor.classList.remove(flipClassName);\n },\n });\n}\n"],"mappings":"4MAoBA,IAAM,EAAc,EAcpB,SAAgB,EAAoB,CAClC,SACA,aACA,YACA,WACA,gBACA,YAAY,UACc,CAC1B,EAAkB,CAChB,SACA,aACA,YAAa,CAAC,CAAS,EAGvB,WAAY,CAAC,EAAW,CAAQ,EAChC,KAAM,CAAC,EAAW,EAAU,EAAe,CAAS,EAEpD,QAAS,EAAS,IAAc,CAC9B,IAAM,EAAS,EAAU,QACzB,GAAI,CAAC,EAAQ,OAEb,IAAM,EAAO,EAAQ,sBAAsB,EACrC,EAAc,EAAS,SAAS,cAAgB,EAIhD,EAAK,EAAsB,EAC3B,EAAa,EAAG,IAAM,EAAG,OAAS,EAAK,OACvC,EAAa,EAAK,IAAM,EAAG,IAC3B,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAO,UAAU,OAAO,EAAe,CAAI,EAK3C,EAAO,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAO,aAAe,EAAK,OAAO,IACjF,EAAO,MAAM,KAAO,GAAG,EAAK,KAAK,IAQjC,IAAM,EAAgB,EAAS,QAC/B,GAAI,EAAe,CACjB,IAAM,EAAe,IAAkB,EAAS,EAAI,EAAc,WAC5D,EAAY,EAAK,KAAO,EAExB,EADa,EAAY,EAAc,aACT,EAAG,KAAO,EAAG,MAAQ,GACnD,EAAe,EAAG,KAAO,EAAc,EACzC,EAAgB,EAClB,EAAO,MAAM,KAAO,GAAG,EAAK,KAAO,EAAc,IACxC,EAAe,IACxB,EAAO,MAAM,KAAO,GAAG,EAAK,KAAO,EAAa,IAEpD,CAEA,EAAO,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,EAChF,EAEA,aAAgB,CAId,IAAM,EAAS,EAAU,QACpB,IACL,EAAO,MAAM,IAAM,GACnB,EAAO,MAAM,KAAO,GACpB,EAAO,MAAM,WAAa,GAC1B,EAAO,UAAU,OAAO,CAAa,EACvC,CACF,CAAC,CACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floorPlan.faces.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.faces.ts"],"sourcesContent":["/**\n * Planar face extraction: turns the wall graph into the enclosed rooms it forms.\n *\n * Each wall becomes two darts (directed half-edges), wall `i` owning darts `2i` and\n * `2i + 1`, so `twin(d) === d ^ 1` with no lookup. The darts leaving each node are\n * sorted by angle, and the face walk is:\n *\n * next(d) = the cyclic PREDECESSOR of twin(d) in the sorted ring at head(d)\n *\n * Because the shoelace sum runs on the same raw coordinates as the angular sort, the\n * rule needs no orientation convention: bounded faces come out with POSITIVE signed\n * area and each connected component's outer boundary comes out negative, whichever way\n * you read the y axis.\n *\n * A dangling wall (one endpoint of degree 1) is handled by the rule itself: a\n * one-element ring's cyclic predecessor is itself, so the walk goes out along the spur\n * and straight back. Both of its darts land in the same cycle, no extra face appears,\n * and the face gains a zero-width slit that contributes nothing to area, fill or\n * point-in-polygon.\n */\n\nimport {\n EPS_AREA,\n MIN_WALL_LENGTH,\n areaCentroid,\n dist,\n perimeter as ringPerimeter,\n pointInRing,\n representativePoint,\n signedArea,\n} from './floorPlan.geometry';\nimport type { PlanFace, PlanFloor, PlanNode, PlanPoint, PlanWall } from './floorPlan.types';\n\ninterface Dart {\n wallId: string;\n from: string;\n to: string;\n}\n\ninterface DartGraph {\n darts: Dart[];\n /** Node id to its outgoing dart indices, sorted by angle ascending. */\n outgoing: Map<string, number[]>;\n /** Dart index to its position within its own outgoing ring. */\n ringIndex: Int32Array;\n nodeOf: (id: string) => PlanNode;\n}\n\n/** Walls that are safe to traverse: real nodes at both ends, and long enough to have an angle. */\nfunction usableWalls(floor: PlanFloor): PlanWall[] {\n return Object.values(floor.walls).filter((w) => {\n if (w.a === w.b) return false;\n const a = floor.nodes[w.a];\n const b = floor.nodes[w.b];\n if (!a || !b) return false;\n return dist(a, b) >= MIN_WALL_LENGTH;\n });\n}\n\nfunction buildDartGraph(floor: PlanFloor): DartGraph {\n const walls = usableWalls(floor);\n const darts: Dart[] = new Array(walls.length * 2);\n\n for (let i = 0; i < walls.length; i++) {\n const w = walls[i];\n darts[2 * i] = { wallId: w.id, from: w.a, to: w.b };\n darts[2 * i + 1] = { wallId: w.id, from: w.b, to: w.a };\n }\n\n const nodeOf = (id: string): PlanNode => floor.nodes[id];\n\n const outgoing = new Map<string, number[]>();\n for (let d = 0; d < darts.length; d++) {\n const list = outgoing.get(darts[d].from);\n if (list) list.push(d);\n else outgoing.set(darts[d].from, [d]);\n }\n\n const angleOf = (d: number): number => {\n const from = nodeOf(darts[d].from);\n const to = nodeOf(darts[d].to);\n return Math.atan2(to.y - from.y, to.x - from.x);\n };\n\n for (const ring of outgoing.values()) {\n ring.sort((x, y) => {\n const ax = angleOf(x);\n const ay = angleOf(y);\n if (ax !== ay) return ax - ay;\n // Deterministic tie-break. A genuine tie means two walls leave this node in the\n // same direction, which validatePlan reports as OverlappingWalls: the sort stays\n // stable so the walk cannot hang, but the resulting face is still wrong.\n const wx = darts[x].wallId;\n const wy = darts[y].wallId;\n if (wx !== wy) return wx < wy ? -1 : 1;\n return x - y;\n });\n }\n\n const ringIndex = new Int32Array(darts.length);\n for (const ring of outgoing.values()) {\n for (let i = 0; i < ring.length; i++) ringIndex[ring[i]] = i;\n }\n\n return { darts, outgoing, ringIndex, nodeOf };\n}\n\nfunction nextDart(g: DartGraph, d: number): number {\n const ring = g.outgoing.get(g.darts[d].to);\n /* c8 ignore next -- head() always has the twin in its ring by construction */\n if (!ring || ring.length === 0) return d ^ 1;\n const i = g.ringIndex[d ^ 1];\n return ring[(i - 1 + ring.length) % ring.length];\n}\n\n/** Every dart belongs to exactly one cycle. */\nfunction walkCycles(g: DartGraph): number[][] {\n const visited = new Uint8Array(g.darts.length);\n const cycles: number[][] = [];\n\n for (let d0 = 0; d0 < g.darts.length; d0++) {\n if (visited[d0]) continue;\n const cycle: number[] = [];\n let d = d0;\n let guard = 0;\n do {\n visited[d] = 1;\n cycle.push(d);\n d = nextDart(g, d);\n // Only reachable if the dart permutation is corrupt (duplicate walls producing\n // an exact angular tie). Bail rather than spin.\n if (++guard > g.darts.length + 1) break;\n } while (d !== d0 && !visited[d]);\n cycles.push(cycle);\n }\n\n return cycles;\n}\n\n/** Union-find over node ids, joined by each wall. */\nfunction connectedComponents(g: DartGraph): Map<string, string> {\n const parent = new Map<string, string>();\n const find = (x: string): string => {\n let root = x;\n while (parent.get(root) !== root) root = parent.get(root) ?? root;\n let cur = x;\n while (parent.get(cur) !== root) {\n const nxt = parent.get(cur) ?? root;\n parent.set(cur, root);\n cur = nxt;\n }\n return root;\n };\n\n for (const nodeId of g.outgoing.keys()) parent.set(nodeId, nodeId);\n for (let d = 0; d < g.darts.length; d += 2) {\n const ra = find(g.darts[d].from);\n const rb = find(g.darts[d].to);\n if (ra !== rb) parent.set(ra, rb);\n }\n\n const out = new Map<string, string>();\n for (const nodeId of g.outgoing.keys()) out.set(nodeId, find(nodeId));\n return out;\n}\n\nfunction cycleRing(g: DartGraph, cycle: number[]): PlanPoint[] {\n return cycle.map((d) => {\n const n = g.nodeOf(g.darts[d].from);\n return { x: n.x, y: n.y };\n });\n}\n\n/**\n * A face id derived from the boundary itself, so it stays stable across derives for as\n * long as the geometry is unchanged.\n */\nfunction faceId(g: DartGraph, cycle: number[]): string {\n let best = '';\n for (const d of cycle) {\n const key = `${g.darts[d].wallId}>${g.darts[d].from}`;\n if (best === '' || key < best) best = key;\n }\n return `f:${best}`;\n}\n\n/**\n * Extracts every enclosed face from the wall graph, with nested components attached as\n * holes.\n *\n * Returned faces are positively wound (visually clockwise in SVG space) and their\n * `area` already has holes subtracted.\n */\nexport function deriveFaces(floor: PlanFloor): PlanFace[] {\n const g = buildDartGraph(floor);\n if (g.darts.length === 0) return [];\n\n const componentOf = connectedComponents(g);\n const cycles = walkCycles(g);\n\n interface Candidate {\n face: PlanFace;\n component: string;\n outerArea: number;\n }\n\n const candidates: Candidate[] = [];\n /** One outer (negatively wound) cycle per connected component. */\n const outerRings = new Map<string, PlanPoint[]>();\n\n for (const cycle of cycles) {\n const ring = cycleRing(g, cycle);\n const area = signedArea(ring);\n const component = componentOf.get(g.darts[cycle[0]].from) ?? '';\n\n if (area > EPS_AREA) {\n candidates.push({\n face: {\n id: faceId(g, cycle),\n outer: ring,\n holes: [],\n area,\n perimeter: ringPerimeter(ring),\n wallIds: cycle.map((d) => g.darts[d].wallId),\n nodeIds: cycle.map((d) => g.darts[d].from),\n },\n component,\n outerArea: area,\n });\n } else if (area < -EPS_AREA) {\n // This component's outer boundary. Kept at its negative winding, which is what\n // `PlanFace.holes` promises: opposite to the parent's positively wound `outer`.\n outerRings.set(component, ring);\n }\n // |area| <= EPS_AREA encloses nothing: a tree component or an isolated stub.\n }\n\n // Attach each component's outer boundary as a hole in the smallest face from a\n // different component that encloses it. Smallest-containing-area is what makes\n // arbitrary nesting depth work: with A > B > C, C's ring goes to B, never to A.\n for (const [component, ring] of outerRings) {\n const ringArea = Math.abs(signedArea(ring));\n if (ringArea <= EPS_AREA) continue;\n // An interior probe rather than a vertex, so two components that happen to touch\n // do not produce an on-boundary coin flip.\n const probe = representativePoint(ring);\n let parent: Candidate | null = null;\n for (const cand of candidates) {\n if (cand.component === component) continue;\n // The probe test alone is not sufficient: with one component nested inside\n // another, the OUTER component's probe also falls inside the inner component's\n // face, which would attach the big room as a hole of the small one. A face can\n // only enclose a ring smaller than itself.\n if (cand.outerArea <= ringArea) continue;\n if (!pointInRing(probe, cand.face.outer)) continue;\n if (!parent || cand.outerArea < parent.outerArea) parent = cand;\n }\n // No parent simply means this is a top-level component.\n if (parent) parent.face.holes.push(ring);\n }\n\n for (const cand of candidates) {\n let area = cand.outerArea;\n for (const hole of cand.face.holes) area -= Math.abs(signedArea(hole));\n cand.face.area = area;\n }\n\n return candidates.map((c) => c.face);\n}\n\n/**\n * Euler's formula per connected component: `V - E + F === 2C`, counting every cycle as\n * a face, including each component's own outer boundary.\n *\n * Note it is `2C`, not the `1 + C` of a single connected embedding. The dart walk\n * cannot bridge between disconnected components, so the region between two of them is\n * produced once per component rather than once in total.\n *\n * Exported for tests and dev assertions: it is the cheapest whole-graph check that the\n * dart permutation is intact.\n */\nexport function eulerCheck(floor: PlanFloor): {\n v: number;\n e: number;\n f: number;\n c: number;\n holds: boolean;\n} {\n const g = buildDartGraph(floor);\n const componentOf = connectedComponents(g);\n const v = g.outgoing.size;\n const e = g.darts.length / 2;\n const f = walkCycles(g).length;\n const c = new Set(componentOf.values()).size;\n return { v, e, f, c, holds: v - e + f === 2 * c };\n}\n\n/** Test/diagnostic helper: how many cycles each dart appears in. Must be all 1s. */\nexport function dartCycleCounts(floor: PlanFloor): number[] {\n const g = buildDartGraph(floor);\n const counts = new Array<number>(g.darts.length).fill(0);\n for (const cycle of walkCycles(g)) for (const d of cycle) counts[d] += 1;\n return counts;\n}\n\n/** Degree of each node, by id. Used by wall-path chaining and by validation. */\nexport function nodeDegrees(floor: PlanFloor): Map<string, number> {\n const degrees = new Map<string, number>();\n for (const w of usableWalls(floor)) {\n degrees.set(w.a, (degrees.get(w.a) ?? 0) + 1);\n degrees.set(w.b, (degrees.get(w.b) ?? 0) + 1);\n }\n return degrees;\n}\n\nexport { areaCentroid };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"floorPlan.faces.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.faces.ts"],"sourcesContent":["/**\n * Planar face extraction: turns the wall graph into the enclosed rooms it forms.\n *\n * Each wall becomes two darts (directed half-edges), wall `i` owning darts `2i` and\n * `2i + 1`, so `twin(d) === d ^ 1` with no lookup. The darts leaving each node are\n * sorted by angle, and the face walk is:\n *\n * next(d) = the cyclic PREDECESSOR of twin(d) in the sorted ring at head(d)\n *\n * Because the shoelace sum runs on the same raw coordinates as the angular sort, the\n * rule needs no orientation convention: bounded faces come out with POSITIVE signed\n * area and each connected component's outer boundary comes out negative, whichever way\n * you read the y axis.\n *\n * A dangling wall (one endpoint of degree 1) is handled by the rule itself: a\n * one-element ring's cyclic predecessor is itself, so the walk goes out along the spur\n * and straight back. Both of its darts land in the same cycle, no extra face appears,\n * and the face gains a zero-width slit that contributes nothing to area, fill or\n * point-in-polygon.\n */\n\nimport {\n EPS_AREA,\n MIN_WALL_LENGTH,\n areaCentroid,\n dist,\n perimeter as ringPerimeter,\n pointInRing,\n representativePoint,\n signedArea,\n} from './floorPlan.geometry';\nimport type { PlanFace, PlanFloor, PlanNode, PlanPoint, PlanWall } from './floorPlan.types';\n\ninterface Dart {\n wallId: string;\n from: string;\n to: string;\n}\n\ninterface DartGraph {\n darts: Dart[];\n /** Node id to its outgoing dart indices, sorted by angle ascending. */\n outgoing: Map<string, number[]>;\n /** Dart index to its position within its own outgoing ring. */\n ringIndex: Int32Array;\n nodeOf: (id: string) => PlanNode;\n}\n\n/** Walls that are safe to traverse: real nodes at both ends, and long enough to have an angle. */\nfunction usableWalls(floor: PlanFloor): PlanWall[] {\n return Object.values(floor.walls).filter((w) => {\n if (w.a === w.b) return false;\n const a = floor.nodes[w.a];\n const b = floor.nodes[w.b];\n if (!a || !b) return false;\n return dist(a, b) >= MIN_WALL_LENGTH;\n });\n}\n\nfunction buildDartGraph(floor: PlanFloor): DartGraph {\n const walls = usableWalls(floor);\n const darts: Dart[] = new Array(walls.length * 2);\n\n for (let i = 0; i < walls.length; i++) {\n const w = walls[i];\n darts[2 * i] = { wallId: w.id, from: w.a, to: w.b };\n darts[2 * i + 1] = { wallId: w.id, from: w.b, to: w.a };\n }\n\n const nodeOf = (id: string): PlanNode => floor.nodes[id];\n\n const outgoing = new Map<string, number[]>();\n for (let d = 0; d < darts.length; d++) {\n const list = outgoing.get(darts[d].from);\n if (list) list.push(d);\n else outgoing.set(darts[d].from, [d]);\n }\n\n const angleOf = (d: number): number => {\n const from = nodeOf(darts[d].from);\n const to = nodeOf(darts[d].to);\n return Math.atan2(to.y - from.y, to.x - from.x);\n };\n\n for (const ring of outgoing.values()) {\n ring.sort((x, y) => {\n const ax = angleOf(x);\n const ay = angleOf(y);\n if (ax !== ay) return ax - ay;\n // Deterministic tie-break. A genuine tie means two walls leave this node in the\n // same direction, which validatePlan reports as OverlappingWalls: the sort stays\n // stable so the walk cannot hang, but the resulting face is still wrong.\n const wx = darts[x].wallId;\n const wy = darts[y].wallId;\n if (wx !== wy) return wx < wy ? -1 : 1;\n return x - y;\n });\n }\n\n const ringIndex = new Int32Array(darts.length);\n for (const ring of outgoing.values()) {\n for (let i = 0; i < ring.length; i++) ringIndex[ring[i]] = i;\n }\n\n return { darts, outgoing, ringIndex, nodeOf };\n}\n\nfunction nextDart(g: DartGraph, d: number): number {\n const ring = g.outgoing.get(g.darts[d].to);\n /* c8 ignore next -- head() always has the twin in its ring by construction */\n if (!ring || ring.length === 0) return d ^ 1;\n const i = g.ringIndex[d ^ 1];\n return ring[(i - 1 + ring.length) % ring.length];\n}\n\n/** Every dart belongs to exactly one cycle. */\nfunction walkCycles(g: DartGraph): number[][] {\n const visited = new Uint8Array(g.darts.length);\n const cycles: number[][] = [];\n\n for (let d0 = 0; d0 < g.darts.length; d0++) {\n if (visited[d0]) continue;\n const cycle: number[] = [];\n let d = d0;\n let guard = 0;\n do {\n visited[d] = 1;\n cycle.push(d);\n d = nextDart(g, d);\n // Only reachable if the dart permutation is corrupt (duplicate walls producing\n // an exact angular tie). Bail rather than spin.\n if (++guard > g.darts.length + 1) break;\n } while (d !== d0 && !visited[d]);\n cycles.push(cycle);\n }\n\n return cycles;\n}\n\n/** Union-find over node ids, joined by each wall. */\nfunction connectedComponents(g: DartGraph): Map<string, string> {\n const parent = new Map<string, string>();\n const find = (x: string): string => {\n let root = x;\n while (parent.get(root) !== root) root = parent.get(root) ?? root;\n let cur = x;\n while (parent.get(cur) !== root) {\n const nxt = parent.get(cur) ?? root;\n parent.set(cur, root);\n cur = nxt;\n }\n return root;\n };\n\n for (const nodeId of g.outgoing.keys()) parent.set(nodeId, nodeId);\n for (let d = 0; d < g.darts.length; d += 2) {\n const ra = find(g.darts[d].from);\n const rb = find(g.darts[d].to);\n if (ra !== rb) parent.set(ra, rb);\n }\n\n const out = new Map<string, string>();\n for (const nodeId of g.outgoing.keys()) out.set(nodeId, find(nodeId));\n return out;\n}\n\nfunction cycleRing(g: DartGraph, cycle: number[]): PlanPoint[] {\n return cycle.map((d) => {\n const n = g.nodeOf(g.darts[d].from);\n return { x: n.x, y: n.y };\n });\n}\n\n/**\n * A face id derived from the boundary itself, so it stays stable across derives for as\n * long as the geometry is unchanged.\n */\nfunction faceId(g: DartGraph, cycle: number[]): string {\n let best = '';\n for (const d of cycle) {\n const key = `${g.darts[d].wallId}>${g.darts[d].from}`;\n if (best === '' || key < best) best = key;\n }\n return `f:${best}`;\n}\n\n/**\n * Extracts every enclosed face from the wall graph, with nested components attached as\n * holes.\n *\n * Returned faces are positively wound (visually clockwise in SVG space) and their\n * `area` already has holes subtracted.\n */\nexport function deriveFaces(floor: PlanFloor): PlanFace[] {\n const g = buildDartGraph(floor);\n if (g.darts.length === 0) return [];\n\n const componentOf = connectedComponents(g);\n const cycles = walkCycles(g);\n\n interface Candidate {\n face: PlanFace;\n component: string;\n outerArea: number;\n }\n\n const candidates: Candidate[] = [];\n /** One outer (negatively wound) cycle per connected component. */\n const outerRings = new Map<string, PlanPoint[]>();\n\n for (const cycle of cycles) {\n const ring = cycleRing(g, cycle);\n const area = signedArea(ring);\n const component = componentOf.get(g.darts[cycle[0]].from) ?? '';\n\n if (area > EPS_AREA) {\n candidates.push({\n face: {\n id: faceId(g, cycle),\n outer: ring,\n holes: [],\n area,\n perimeter: ringPerimeter(ring),\n wallIds: cycle.map((d) => g.darts[d].wallId),\n nodeIds: cycle.map((d) => g.darts[d].from),\n },\n component,\n outerArea: area,\n });\n } else if (area < -EPS_AREA) {\n // This component's outer boundary. Kept at its negative winding, which is what\n // `PlanFace.holes` promises: opposite to the parent's positively wound `outer`.\n outerRings.set(component, ring);\n }\n // |area| <= EPS_AREA encloses nothing: a tree component or an isolated stub.\n }\n\n // Attach each component's outer boundary as a hole in the smallest face from a\n // different component that encloses it. Smallest-containing-area is what makes\n // arbitrary nesting depth work: with A > B > C, C's ring goes to B, never to A.\n for (const [component, ring] of outerRings) {\n const ringArea = Math.abs(signedArea(ring));\n if (ringArea <= EPS_AREA) continue;\n // An interior probe rather than a vertex, so two components that happen to touch\n // do not produce an on-boundary coin flip.\n const probe = representativePoint(ring);\n let parent: Candidate | null = null;\n for (const cand of candidates) {\n if (cand.component === component) continue;\n // The probe test alone is not sufficient: with one component nested inside\n // another, the OUTER component's probe also falls inside the inner component's\n // face, which would attach the big room as a hole of the small one. A face can\n // only enclose a ring smaller than itself.\n if (cand.outerArea <= ringArea) continue;\n if (!pointInRing(probe, cand.face.outer)) continue;\n if (!parent || cand.outerArea < parent.outerArea) parent = cand;\n }\n // No parent simply means this is a top-level component.\n if (parent) parent.face.holes.push(ring);\n }\n\n for (const cand of candidates) {\n let area = cand.outerArea;\n for (const hole of cand.face.holes) area -= Math.abs(signedArea(hole));\n cand.face.area = area;\n }\n\n return candidates.map((c) => c.face);\n}\n\n/**\n * Euler's formula per connected component: `V - E + F === 2C`, counting every cycle as\n * a face, including each component's own outer boundary.\n *\n * Note it is `2C`, not the `1 + C` of a single connected embedding. The dart walk\n * cannot bridge between disconnected components, so the region between two of them is\n * produced once per component rather than once in total.\n *\n * Exported for tests and dev assertions: it is the cheapest whole-graph check that the\n * dart permutation is intact.\n */\nexport function eulerCheck(floor: PlanFloor): {\n v: number;\n e: number;\n f: number;\n c: number;\n holds: boolean;\n} {\n const g = buildDartGraph(floor);\n const componentOf = connectedComponents(g);\n const v = g.outgoing.size;\n const e = g.darts.length / 2;\n const f = walkCycles(g).length;\n const c = new Set(componentOf.values()).size;\n return { v, e, f, c, holds: v - e + f === 2 * c };\n}\n\n/** Test/diagnostic helper: how many cycles each dart appears in. Must be all 1s. */\nexport function dartCycleCounts(floor: PlanFloor): number[] {\n const g = buildDartGraph(floor);\n const counts = new Array<number>(g.darts.length).fill(0);\n for (const cycle of walkCycles(g)) for (const d of cycle) counts[d] += 1;\n return counts;\n}\n\n/** Degree of each node, by id. Used by wall-path chaining and by validation. */\nexport function nodeDegrees(floor: PlanFloor): Map<string, number> {\n const degrees = new Map<string, number>();\n for (const w of usableWalls(floor)) {\n degrees.set(w.a, (degrees.get(w.a) ?? 0) + 1);\n degrees.set(w.b, (degrees.get(w.b) ?? 0) + 1);\n }\n return degrees;\n}\n\nexport { areaCentroid };\n"],"mappings":"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"}
|
|
@@ -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=a(typeof i==`number`?{x:s.x+(d.x-s.x)*i,y:s.y+(d.y-s.y)*i}:i,s,d),m=r(s,p);if(m<10)return{floor:t,result:{nodeId:o.a,wallIds:null,droppedOpeningIds:[]},issues:[]};if(f-m<10)return{floor:t,result:{nodeId:o.b,wallIds:null,droppedOpeningIds:[]},issues:[]};let h=l(t),g=c(`n`);h.nodes[g]={id:g,x:p.x,y:p.y};let _=c(`w`),v=c(`w`),y={thickness:o.thickness,type:o.type,height:o.height,baseHeight:o.baseHeight};h.walls[_]={...y,id:_,a:o.a,b:g},h.walls[v]={...y,id:v,a:g,b:o.b},delete h.walls[n];let b=[],x=[];for(let r of Object.values(t.openings)){if(r.wallId!==n)continue;let t=r.offset<=m,i=t?_:v,a=t?m:f-m,o=t?r.offset:r.offset-m,s=Math.min(r.width,a-2,o*2,(a-o)*2);if(s<100){delete h.openings[r.id],b.push(r.id),x.push(u(e.OpeningDropped,`An opening was removed: the wall it sat on became too short for it.`,{openingIds:[r.id],wallIds:[n]}));continue}h.openings[r.id]={...r,wallId:i,offset:o,width:s}}return{floor:h,result:{nodeId:g,wallIds:[_,v],droppedOpeningIds:b},issues:x}}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>=.999999999&&(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,w as mergeNodes,k as moveNode,c as newId,P as removeOpening,O as removeWall,j as scalePlan,y as splitWall,A as transformPlan,N as updateOpening,F as validatePlan,d as wallLength,D as weldShortWalls};
|
|
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};
|
|
2
2
|
//# sourceMappingURL=floorPlan.graph.mjs.map
|