@ahrowe/ui 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/common/actionButtons/actionButtons.mjs +1 -1
- package/dist/esm/common/actionButtons/actionButtons.mjs.map +1 -1
- package/dist/esm/common/alert/alert.mjs +1 -1
- package/dist/esm/common/alert/alert.mjs.map +1 -1
- package/dist/esm/common/alert/alert.types.mjs.map +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
- package/dist/esm/common/breadcrumb/breadcrumb.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/card.types.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/chip/chip.mjs +1 -1
- package/dist/esm/common/chip/chip.mjs.map +1 -1
- package/dist/esm/common/chip/chip.types.mjs.map +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs +1 -1
- package/dist/esm/common/colorPicker/colorPicker.mjs.map +1 -1
- package/dist/esm/common/configProvider/useLabels.mjs +2 -0
- package/dist/esm/common/configProvider/useLabels.mjs.map +1 -0
- package/dist/esm/common/confirmModal/confirmModal.mjs +1 -1
- package/dist/esm/common/confirmModal/confirmModal.mjs.map +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.mjs +1 -1
- package/dist/esm/common/datePicker/components/datePickerMonth/datePickerMonth.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/drawer/drawer.mjs +1 -1
- package/dist/esm/common/drawer/drawer.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/emptyState/emptyState.mjs +1 -1
- package/dist/esm/common/emptyState/emptyState.mjs.map +1 -1
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs +1 -1
- package/dist/esm/common/fab/components/fabBase/fabBase.mjs.map +1 -1
- package/dist/esm/common/fab/fab.mjs +1 -1
- package/dist/esm/common/fab/fab.mjs.map +1 -1
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs +1 -1
- package/dist/esm/common/infiniteBlock/infiniteBlock.mjs.map +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.types.mjs.map +1 -1
- package/dist/esm/common/klipyPicker/klipyPicker.mjs +1 -1
- package/dist/esm/common/klipyPicker/klipyPicker.mjs.map +1 -1
- package/dist/esm/common/modal/modal.mjs +1 -1
- package/dist/esm/common/modal/modal.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/numberInput/numberInput.mjs +1 -1
- package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
- package/dist/esm/common/otpInput/otpInput.mjs +1 -1
- package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
- package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
- package/dist/esm/common/pagination/pagination.mjs +1 -1
- package/dist/esm/common/pagination/pagination.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/roomDrawer/roomDrawer.mjs +1 -1
- package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
- package/dist/esm/common/searchInput/searchInput.mjs +1 -1
- package/dist/esm/common/searchInput/searchInput.mjs.map +1 -1
- package/dist/esm/common/splitButton/splitButton.mjs +1 -1
- package/dist/esm/common/splitButton/splitButton.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/toast/toast.mjs +1 -1
- package/dist/esm/common/toast/toast.mjs.map +1 -1
- package/dist/esm/common/toast/toastProvider.mjs +1 -1
- package/dist/esm/common/toast/toastProvider.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/virtualList/virtualList.mjs +1 -1
- package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
- package/dist/esm/common/virtualList/virtualListHeader.mjs +1 -1
- package/dist/esm/common/virtualList/virtualListHeader.mjs.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/types/common/actionButtons/actionButtons.types.d.ts +9 -2
- package/dist/types/common/alert/alert.types.d.ts +7 -0
- package/dist/types/common/breadcrumb/breadcrumb.types.d.ts +7 -0
- package/dist/types/common/card/card.types.d.ts +6 -1
- package/dist/types/common/carousel/carousel.types.d.ts +13 -0
- package/dist/types/common/chip/chip.types.d.ts +13 -2
- package/dist/types/common/colorPicker/colorPicker.d.ts +1 -1
- package/dist/types/common/colorPicker/colorPicker.types.d.ts +13 -1
- package/dist/types/common/configProvider/configProvider.types.d.ts +26 -1
- package/dist/types/common/configProvider/index.d.ts +1 -0
- package/dist/types/common/configProvider/useLabels.d.ts +22 -0
- package/dist/types/common/confirmModal/confirmModal.types.d.ts +13 -4
- package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.d.ts +2 -14
- package/dist/types/common/datePicker/components/datePickerMonth/datePickerMonth.types.d.ts +23 -0
- package/dist/types/common/datePicker/datePicker.d.ts +1 -22
- package/dist/types/common/datePicker/datePicker.types.d.ts +60 -0
- package/dist/types/common/datePicker/index.d.ts +1 -0
- package/dist/types/common/drawer/drawer.d.ts +1 -1
- package/dist/types/common/drawer/drawer.types.d.ts +7 -1
- package/dist/types/common/dropdown/dropdown.types.d.ts +6 -6
- package/dist/types/common/emptyState/emptyState.d.ts +1 -1
- package/dist/types/common/emptyState/emptyState.types.d.ts +13 -1
- package/dist/types/common/fab/components/fabBase/fabBase.d.ts +1 -1
- package/dist/types/common/fab/components/fabBase/fabBase.types.d.ts +3 -1
- package/dist/types/common/fab/fab.d.ts +1 -1
- package/dist/types/common/fab/fab.types.d.ts +6 -1
- package/dist/types/common/infiniteBlock/infiniteBlock.d.ts +1 -1
- package/dist/types/common/infiniteBlock/infiniteBlock.types.d.ts +2 -0
- package/dist/types/common/input/input.types.d.ts +13 -0
- package/dist/types/common/klipyPicker/klipyPicker.d.ts +1 -1
- package/dist/types/common/klipyPicker/klipyPicker.types.d.ts +7 -0
- package/dist/types/common/modal/modal.types.d.ts +7 -0
- package/dist/types/common/multiSelect/multiSelect.types.d.ts +13 -6
- package/dist/types/common/numberInput/numberInput.types.d.ts +15 -2
- package/dist/types/common/otpInput/otpInput.types.d.ts +9 -0
- package/dist/types/common/pagination/pagination.types.d.ts +15 -0
- package/dist/types/common/progressBar/progressBar.d.ts +1 -1
- package/dist/types/common/progressBar/progressBar.types.d.ts +6 -1
- package/dist/types/common/roomDrawer/roomDrawer.types.d.ts +6 -0
- package/dist/types/common/searchInput/searchInput.d.ts +1 -1
- package/dist/types/common/searchInput/searchInput.types.d.ts +13 -1
- package/dist/types/common/splitButton/splitButton.types.d.ts +7 -0
- package/dist/types/common/timer/timer.types.d.ts +7 -0
- package/dist/types/common/toast/toast.d.ts +4 -2
- package/dist/types/common/toast/toast.types.d.ts +11 -1
- package/dist/types/common/toast/toastProvider.d.ts +1 -1
- package/dist/types/common/tree/tree.types.d.ts +7 -2
- package/dist/types/common/virtualList/virtualList.types.d.ts +15 -6
- package/dist/types/common/virtualList/virtualListHeader.d.ts +3 -3
- package/docs/ActionButtons.md +7 -6
- package/docs/Alert.md +2 -0
- package/docs/Breadcrumb.md +2 -0
- package/docs/Card.md +2 -0
- package/docs/Carousel.md +2 -0
- package/docs/Chip.md +5 -1
- package/docs/ColorPicker.md +4 -0
- package/docs/ConfigProvider.md +23 -0
- package/docs/ConfirmModal.md +7 -5
- package/docs/DatePicker.md +6 -1
- package/docs/Drawer.md +2 -0
- package/docs/Dropdown.md +2 -0
- package/docs/EmptyState.md +4 -0
- package/docs/Fab.md +2 -0
- package/docs/FormValidatorGroup.md +1 -1
- package/docs/Input.md +2 -0
- package/docs/KlipyPicker.md +2 -0
- package/docs/Modal.md +2 -0
- package/docs/MultiSelect.md +7 -5
- package/docs/NumberInput.md +8 -2
- package/docs/OtpInput.md +2 -0
- package/docs/Pagination.md +2 -0
- package/docs/ProgressBar.md +2 -0
- package/docs/RoomDrawer.md +2 -0
- package/docs/SearchInput.md +4 -0
- package/docs/SplitButton.md +2 -0
- package/docs/Timer.md +2 -0
- package/docs/Toast.md +2 -0
- package/docs/Tree.md +3 -1
- package/docs/VirtualList.md +3 -2
- package/docs/Wizard.md +1 -2
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../tooltip/tooltip.mjs";import{OtpInputCharset as
|
|
1
|
+
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import n from"../tooltip/tooltip.mjs";import{OtpInputCharset as r}from"./otpInput.types.mjs";import i from"./otpInput.module.mjs";import{useEffect as a,useRef as o,useState as s}from"react";import c from"classnames";import{jsx as l,jsxs as u}from"react/jsx-runtime";var d=/[0-9]/g,f=/[a-zA-Z0-9]/g,p={field:`One-time code`,digit:(e,t)=>`Digit ${e} of ${t}`};function m(e,t){let n=t===r.Alphanumeric?f:d;return(e.match(n)||[]).join(``)}function h(d){let{length:f=6,value:h,onChange:g=()=>{},onComplete:_=()=>{},formValidator:v=null,charset:y=r.Numeric,masked:b=!1,groupAfter:x=[],label:S=``,isValid:C=!0,errorMessage:w=``,isRequired:T=!1,clearOnError:E=!1,clearErrorDelay:D=900,disabled:O=!1,autoFocus:k=!1,className:A=``,style:j,classNames:M,styles:N,labels:P,...F}=e(`OtpInput`,d),I=t(`OtpInput`,P,p),L=(v?v.value:h)??``,[,R]=s(0),[z,B]=s(!1),[V,H]=s(!1),[U,W]=s(!1),G=o([]),K=o(!1);a(()=>{if(!v)return;v.validate();let e=()=>R(e=>e+1);return v.registerOnUpdateListener(e),()=>v.removeOnUpdateListener(e)},[v]),a(()=>{if(!k)return;let e=Math.min(L.length,f-1);G.current[e]?.focus()},[]);let q=v?v.touched&&v.hasError():!C||!!w,J=v?v.getCurrentErrorMessage():w||``;a(()=>{let e=q&&!K.current;if(K.current=q,!e)return;B(!0);let t=window.setTimeout(()=>B(!1),400),n=E?window.setTimeout(()=>{Y(``),G.current[0]?.focus()},D):null;return()=>{window.clearTimeout(t),n!=null&&window.clearTimeout(n)}},[q,E,D]);function Y(e){let t=L.length===f,n=m(e,y).slice(0,f);v&&v.set(n),g?.(n),n.length===f&&!t&&_?.(n)}function X(e,t){let n=L.split(``);n[e]=t,Y(n.join(``))}function Z(e,t){if(O)return;if(t===``){X(e,``);return}let n=m(t,y);if(!n)return;let r=Math.min(e,L.length);if(t.length>1){Q(r,n);return}X(r,n),r<f-1?G.current[r+1]?.focus():G.current[r]?.blur()}function Q(e,t){let n=m(t,y);if(!n)return;let r=L.padEnd(f,` `).split(``),i=e;for(let e of n){if(i>=f)break;r[i]=e,i+=1}Y(r.join(``).trimEnd());let a=Math.min(i,f-1);G.current[a]?.focus(),i>=f&&G.current[f-1]?.blur()}function $(e,t){if(O)return;let n=t.clipboardData.getData(`text`);n&&(t.preventDefault(),Q(Math.min(e,L.length),n))}function ee(e,t){if(!O){if(t.key.length===1&&!t.ctrlKey&&!t.metaKey&&!t.altKey){let n=m(t.key,y);if(n&&L[e]===n){t.preventDefault(),X(e,n),e<f-1?G.current[e+1]?.focus():G.current[e]?.blur();return}}if(t.key===`Backspace`){if(L[e]){X(e,``);return}e>0&&(t.preventDefault(),X(e-1,``),G.current[e-1]?.focus());return}if(t.key===`Delete`){L[e]&&X(e,``);return}if(t.key===`ArrowLeft`&&e>0){t.preventDefault(),G.current[e-1]?.focus();return}t.key===`ArrowRight`&&e<f-1&&(t.preventDefault(),G.current[e+1]?.focus())}}function te(e){e.target.select()}function ne(){H(!0)}function re(e){e.currentTarget.contains(e.relatedTarget)||(H(!1),v&&(v.touched=!0))}return u(`div`,{...F,className:c(i.otpInput,O&&i.otpInputDisabled,A),style:j,children:[S&&u(`div`,{className:c(i.otpInputLabel,M?.label),style:N?.label,children:[S,T&&l(`span`,{className:i.otpInputRequiredMark,children:` *`})]}),l(`div`,{role:`group`,"aria-label":S||I.field,className:c(i.otpInputBoxes,z&&i.otpInputBoxesShake,M?.inputs),style:N?.inputs,onFocus:ne,onBlur:re,onMouseEnter:()=>W(!0),onMouseLeave:()=>W(!1),children:Array.from({length:f},(e,t)=>{let n=L[t]||``;return u(`div`,{className:i.otpInputBoxWrapper,children:[l(`input`,{ref:e=>{G.current[t]=e},type:b?`password`:`text`,inputMode:y===r.Numeric?`numeric`:`text`,pattern:y===r.Numeric?`[0-9]*`:void 0,autoComplete:t===0?`one-time-code`:`off`,maxLength:1,disabled:O,value:n,"aria-label":I.digit(t+1,f),"aria-invalid":q||void 0,className:c(i.otpInputBox,q&&i.otpInputBoxError,n&&i.otpInputBoxFilled,M?.input),style:N?.input,onChange:e=>Z(t,e.target.value),onKeyDown:e=>ee(t,e),onPaste:e=>$(t,e),onFocus:te}),x.includes(t+1)&&t<f-1&&l(`span`,{className:c(i.otpInputSeparator,M?.separator),style:N?.separator})]},t)})}),l(n,{variant:`error`,message:J,isVisible:q&&(V||U)})]})}export{h as default};
|
|
2
2
|
//# sourceMappingURL=otpInput.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otpInput.mjs","names":[],"sources":["../../../../package/common/otpInput/otpInput.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\nimport Tooltip from 'components/common/tooltip';\nimport { useComponentDefaults } from '../configProvider';\n\nimport { OtpInputCharset, type OtpInputProps } from './otpInput.types';\nimport styles from './otpInput.module.pcss';\n\nconst NUMERIC_RE = /[0-9]/g;\nconst ALPHANUMERIC_RE = /[a-zA-Z0-9]/g;\n\nfunction filterChars(raw: string, charset: OtpInputCharset): string {\n const re = charset === OtpInputCharset.Alphanumeric ? ALPHANUMERIC_RE : NUMERIC_RE;\n return (raw.match(re) || []).join('');\n}\n\nfunction OtpInput(props: OtpInputProps): ReactElement {\n const {\n length = 6,\n value,\n onChange = () => {},\n onComplete = () => {},\n formValidator = null,\n charset = OtpInputCharset.Numeric,\n masked = false,\n groupAfter = [],\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n clearOnError = false,\n clearErrorDelay = 900,\n disabled = false,\n autoFocus = false,\n className = '',\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('OtpInput', props);\n\n const currentValue = (formValidator ? (formValidator.value as string) : value) ?? '';\n const [, forceUpdate] = useState(0);\n const [isShaking, setIsShaking] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const inputRefs = useRef<Array<HTMLInputElement | null>>([]);\n const wasErrorRef = useRef(false);\n\n useEffect(() => {\n if (!formValidator) return;\n formValidator.validate();\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator]);\n\n useEffect(() => {\n if (!autoFocus) return;\n const firstEmpty = Math.min(currentValue.length, length - 1);\n inputRefs.current[firstEmpty]?.focus();\n // Only run once, on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const showError = formValidator ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n const displayedErrorMessage = formValidator ? formValidator.getCurrentErrorMessage() : errorMessage || '';\n\n useEffect(() => {\n const justErrored = showError && !wasErrorRef.current;\n wasErrorRef.current = showError;\n if (!justErrored) return;\n\n setIsShaking(true);\n const shakeTimeoutId = window.setTimeout(() => setIsShaking(false), 400);\n const clearTimeoutId = clearOnError\n ? window.setTimeout(() => {\n commit('');\n inputRefs.current[0]?.focus();\n }, clearErrorDelay)\n : null;\n\n return () => {\n window.clearTimeout(shakeTimeoutId);\n if (clearTimeoutId != null) window.clearTimeout(clearTimeoutId);\n };\n // Only re-evaluate on an actual error-state or config change, not on every value/render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [showError, clearOnError, clearErrorDelay]);\n\n function commit(next: string) {\n const wasComplete = currentValue.length === length;\n const clipped = filterChars(next, charset).slice(0, length);\n if (formValidator) {\n formValidator.set(clipped);\n }\n onChange?.(clipped);\n // Only fire once per genuinely new completion (going from partial to full), not on every\n // keystroke made while correcting an already-full code.\n if (clipped.length === length && !wasComplete) {\n onComplete?.(clipped);\n }\n }\n\n function setCharAt(index: number, char: string) {\n const chars = currentValue.split('');\n chars[index] = char;\n commit(chars.join(''));\n }\n\n function handleChange(index: number, rawInput: string) {\n if (disabled) return;\n if (rawInput === '') {\n // Box was cleared (e.g. select + delete) — Backspace itself is handled in onKeyDown.\n setCharAt(index, '');\n return;\n }\n\n const filtered = filterChars(rawInput, charset);\n if (!filtered) {\n // Typed an invalid/disallowed character — the controlled `value` re-render discards it.\n return;\n }\n\n // Clicking straight into a box past the contiguous filled prefix (skipping ahead of\n // empty boxes) fills the next expected slot instead, rather than leaving a gap before it\n // that setCharAt/distributeFrom can't represent in a plain string and would silently collapse.\n const targetIndex = Math.min(index, currentValue.length);\n\n if (rawInput.length > 1) {\n // Mobile autofill / SMS suggestions can drop the whole code into one box, bypassing maxLength.\n distributeFrom(targetIndex, filtered);\n return;\n }\n\n setCharAt(targetIndex, filtered);\n if (targetIndex < length - 1) {\n inputRefs.current[targetIndex + 1]?.focus();\n } else {\n inputRefs.current[targetIndex]?.blur();\n }\n }\n\n function distributeFrom(startIndex: number, chars: string) {\n const clean = filterChars(chars, charset);\n if (!clean) return;\n const existing = currentValue.padEnd(length, ' ').split('');\n let cursor = startIndex;\n for (const char of clean) {\n if (cursor >= length) break;\n existing[cursor] = char;\n cursor += 1;\n }\n commit(existing.join('').trimEnd());\n const nextFocus = Math.min(cursor, length - 1);\n inputRefs.current[nextFocus]?.focus();\n if (cursor >= length) {\n inputRefs.current[length - 1]?.blur();\n }\n }\n\n function handlePaste(index: number, event: React.ClipboardEvent<HTMLInputElement>) {\n if (disabled) return;\n const pasted = event.clipboardData.getData('text');\n if (!pasted) return;\n event.preventDefault();\n // Same clamp as handleChange — pasting into a box past the filled prefix starts at the\n // next expected slot instead of leaving an unrepresentable gap before it.\n distributeFrom(Math.min(index, currentValue.length), pasted);\n }\n\n function handleKeyDown(index: number, event: React.KeyboardEvent<HTMLInputElement>) {\n if (disabled) return;\n\n // React's controlled-input onChange never fires when the resulting value is identical to\n // what's already rendered (its value tracker sees no change) — so retyping the exact digit\n // already in a box would otherwise silently do nothing. keydown always fires, so handle that\n // one case here and skip the native edit entirely.\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {\n const typed = filterChars(event.key, charset);\n if (typed && currentValue[index] === typed) {\n event.preventDefault();\n setCharAt(index, typed);\n if (index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n } else {\n inputRefs.current[index]?.blur();\n }\n return;\n }\n }\n\n if (event.key === 'Backspace') {\n if (currentValue[index]) {\n setCharAt(index, '');\n return;\n }\n if (index > 0) {\n event.preventDefault();\n setCharAt(index - 1, '');\n inputRefs.current[index - 1]?.focus();\n }\n return;\n }\n if (event.key === 'Delete') {\n if (currentValue[index]) setCharAt(index, '');\n return;\n }\n if (event.key === 'ArrowLeft' && index > 0) {\n event.preventDefault();\n inputRefs.current[index - 1]?.focus();\n return;\n }\n if (event.key === 'ArrowRight' && index < length - 1) {\n event.preventDefault();\n inputRefs.current[index + 1]?.focus();\n }\n }\n\n function handleFocus(event: React.FocusEvent<HTMLInputElement>) {\n event.target.select();\n }\n\n function handleGroupFocus() {\n setIsFocused(true);\n }\n\n function handleGroupBlur(event: React.FocusEvent<HTMLDivElement>) {\n // Auto-advance moves focus between boxes constantly while typing — only treat this as\n // leaving the group once focus actually lands outside it, not on the next box.\n if (event.currentTarget.contains(event.relatedTarget as Node | null)) return;\n setIsFocused(false);\n if (formValidator) formValidator.touched = true;\n }\n\n return (\n <div {...rest} className={cx(styles.otpInput, disabled && styles.otpInputDisabled, className)} style={style}>\n {label && (\n <div className={cx(styles.otpInputLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n {isRequired && <span className={styles.otpInputRequiredMark}> *</span>}\n </div>\n )}\n <div\n role='group'\n aria-label={label || 'One-time code'}\n className={cx(styles.otpInputBoxes, isShaking && styles.otpInputBoxesShake, classNames?.inputs)}\n style={slotStyles?.inputs}\n onFocus={handleGroupFocus}\n onBlur={handleGroupBlur}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {Array.from({ length }, (_, index) => {\n const char = currentValue[index] || '';\n return (\n <div key={index} className={styles.otpInputBoxWrapper}>\n <input\n ref={(el) => {\n inputRefs.current[index] = el;\n }}\n type={masked ? 'password' : 'text'}\n inputMode={charset === OtpInputCharset.Numeric ? 'numeric' : 'text'}\n pattern={charset === OtpInputCharset.Numeric ? '[0-9]*' : undefined}\n autoComplete={index === 0 ? 'one-time-code' : 'off'}\n maxLength={1}\n disabled={disabled}\n value={char}\n aria-label={`Digit ${index + 1} of ${length}`}\n aria-invalid={showError || undefined}\n className={cx(\n styles.otpInputBox,\n showError && styles.otpInputBoxError,\n char && styles.otpInputBoxFilled,\n classNames?.input,\n )}\n style={slotStyles?.input}\n onChange={(e) => handleChange(index, e.target.value)}\n onKeyDown={(e) => handleKeyDown(index, e)}\n onPaste={(e) => handlePaste(index, e)}\n onFocus={handleFocus}\n />\n {groupAfter.includes(index + 1) && index < length - 1 && (\n <span className={cx(styles.otpInputSeparator, classNames?.separator)} style={slotStyles?.separator} />\n )}\n </div>\n );\n })}\n </div>\n <Tooltip variant='error' message={displayedErrorMessage} isVisible={showError && (isFocused || isHovered)} />\n </div>\n );\n}\n\nexport default OtpInput;\n"],"mappings":"4VAQA,IAAM,EAAa,SACb,EAAkB,eAExB,SAAS,EAAY,EAAa,EAAkC,CAClE,IAAM,EAAK,IAAY,EAAgB,aAAe,EAAkB,EACxE,OAAQ,EAAI,MAAM,CAAE,GAAK,CAAC,EAAA,CAAG,KAAK,EAAE,CACtC,CAEA,SAAS,EAAS,EAAoC,CACpD,GAAM,CACJ,SAAS,EACT,QACA,eAAiB,CAAC,EAClB,iBAAmB,CAAC,EACpB,gBAAgB,KAChB,UAAU,EAAgB,QAC1B,SAAS,GACT,aAAa,CAAC,EACd,QAAQ,GACR,UAAU,GACV,eAAe,GACf,aAAa,GACb,eAAe,GACf,kBAAkB,IAClB,WAAW,GACX,YAAY,GACZ,YAAY,GACZ,QACA,aACA,OAAQ,EACR,GAAG,GACD,EAAqB,WAAY,CAAK,EAEpC,GAAgB,EAAiB,EAAc,MAAmB,IAAU,GAC5E,EAAG,GAAe,EAAS,CAAC,EAC5B,CAAC,EAAW,GAAgB,EAAS,EAAK,EAC1C,CAAC,EAAW,GAAgB,EAAS,EAAK,EAC1C,CAAC,EAAW,GAAgB,EAAS,EAAK,EAC1C,EAAY,EAAuC,CAAC,CAAC,EACrD,EAAc,EAAO,EAAK,EAEhC,MAAgB,CACd,GAAI,CAAC,EAAe,OACpB,EAAc,SAAS,EACvB,IAAM,MAAiB,EAAa,GAAM,EAAI,CAAC,EAE/C,OADA,EAAc,yBAAyB,CAAQ,MAClC,EAAc,uBAAuB,CAAQ,CAC5D,EAAG,CAAC,CAAa,CAAC,EAElB,MAAgB,CACd,GAAI,CAAC,EAAW,OAChB,IAAM,EAAa,KAAK,IAAI,EAAa,OAAQ,EAAS,CAAC,EAC3D,EAAU,QAAQ,EAAW,EAAE,MAAM,CAGvC,EAAG,CAAC,CAAC,EAEL,IAAM,EAAY,EAAgB,EAAc,SAAW,EAAc,SAAS,EAAI,CAAC,GAAW,CAAC,CAAC,EAC9F,EAAwB,EAAgB,EAAc,uBAAuB,EAAI,GAAgB,GAEvG,MAAgB,CACd,IAAM,EAAc,GAAa,CAAC,EAAY,QAE9C,GADA,EAAY,QAAU,EAClB,CAAC,EAAa,OAElB,EAAa,EAAI,EACjB,IAAM,EAAiB,OAAO,eAAiB,EAAa,EAAK,EAAG,GAAG,EACjE,EAAiB,EACnB,OAAO,eAAiB,CACtB,EAAO,EAAE,EACT,EAAU,QAAQ,EAAE,EAAE,MAAM,CAC9B,EAAG,CAAe,EAClB,KAEJ,UAAa,CACX,OAAO,aAAa,CAAc,EAC9B,GAAkB,MAAM,OAAO,aAAa,CAAc,CAChE,CAGF,EAAG,CAAC,EAAW,EAAc,CAAe,CAAC,EAE7C,SAAS,EAAO,EAAc,CAC5B,IAAM,EAAc,EAAa,SAAW,EACtC,EAAU,EAAY,EAAM,CAAO,CAAC,CAAC,MAAM,EAAG,CAAM,EACtD,GACF,EAAc,IAAI,CAAO,EAE3B,IAAW,CAAO,EAGd,EAAQ,SAAW,GAAU,CAAC,GAChC,IAAa,CAAO,CAExB,CAEA,SAAS,EAAU,EAAe,EAAc,CAC9C,IAAM,EAAQ,EAAa,MAAM,EAAE,EACnC,EAAM,GAAS,EACf,EAAO,EAAM,KAAK,EAAE,CAAC,CACvB,CAEA,SAAS,EAAa,EAAe,EAAkB,CACrD,GAAI,EAAU,OACd,GAAI,IAAa,GAAI,CAEnB,EAAU,EAAO,EAAE,EACnB,MACF,CAEA,IAAM,EAAW,EAAY,EAAU,CAAO,EAC9C,GAAI,CAAC,EAEH,OAMF,IAAM,EAAc,KAAK,IAAI,EAAO,EAAa,MAAM,EAEvD,GAAI,EAAS,OAAS,EAAG,CAEvB,EAAe,EAAa,CAAQ,EACpC,MACF,CAEA,EAAU,EAAa,CAAQ,EAC3B,EAAc,EAAS,EACzB,EAAU,QAAQ,EAAc,EAAE,EAAE,MAAM,EAE1C,EAAU,QAAQ,EAAY,EAAE,KAAK,CAEzC,CAEA,SAAS,EAAe,EAAoB,EAAe,CACzD,IAAM,EAAQ,EAAY,EAAO,CAAO,EACxC,GAAI,CAAC,EAAO,OACZ,IAAM,EAAW,EAAa,OAAO,EAAQ,GAAG,CAAC,CAAC,MAAM,EAAE,EACtD,EAAS,EACb,IAAK,IAAM,KAAQ,EAAO,CACxB,GAAI,GAAU,EAAQ,MACtB,EAAS,GAAU,EACnB,GAAU,CACZ,CACA,EAAO,EAAS,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,EAClC,IAAM,EAAY,KAAK,IAAI,EAAQ,EAAS,CAAC,EAC7C,EAAU,QAAQ,EAAU,EAAE,MAAM,EAChC,GAAU,GACZ,EAAU,QAAQ,EAAS,EAAE,EAAE,KAAK,CAExC,CAEA,SAAS,EAAY,EAAe,EAA+C,CACjF,GAAI,EAAU,OACd,IAAM,EAAS,EAAM,cAAc,QAAQ,MAAM,EAC5C,IACL,EAAM,eAAe,EAGrB,EAAe,KAAK,IAAI,EAAO,EAAa,MAAM,EAAG,CAAM,EAC7D,CAEA,SAAS,EAAc,EAAe,EAA8C,CAC9E,MAMJ,IAAI,EAAM,IAAI,SAAW,GAAK,CAAC,EAAM,SAAW,CAAC,EAAM,SAAW,CAAC,EAAM,OAAQ,CAC/E,IAAM,EAAQ,EAAY,EAAM,IAAK,CAAO,EAC5C,GAAI,GAAS,EAAa,KAAW,EAAO,CAC1C,EAAM,eAAe,EACrB,EAAU,EAAO,CAAK,EAClB,EAAQ,EAAS,EACnB,EAAU,QAAQ,EAAQ,EAAE,EAAE,MAAM,EAEpC,EAAU,QAAQ,EAAM,EAAE,KAAK,EAEjC,MACF,CACF,CAEA,GAAI,EAAM,MAAQ,YAAa,CAC7B,GAAI,EAAa,GAAQ,CACvB,EAAU,EAAO,EAAE,EACnB,MACF,CACI,EAAQ,IACV,EAAM,eAAe,EACrB,EAAU,EAAQ,EAAG,EAAE,EACvB,EAAU,QAAQ,EAAQ,EAAE,EAAE,MAAM,GAEtC,MACF,CACA,GAAI,EAAM,MAAQ,SAAU,CACtB,EAAa,IAAQ,EAAU,EAAO,EAAE,EAC5C,MACF,CACA,GAAI,EAAM,MAAQ,aAAe,EAAQ,EAAG,CAC1C,EAAM,eAAe,EACrB,EAAU,QAAQ,EAAQ,EAAE,EAAE,MAAM,EACpC,MACF,CACI,EAAM,MAAQ,cAAgB,EAAQ,EAAS,IACjD,EAAM,eAAe,EACrB,EAAU,QAAQ,EAAQ,EAAE,EAAE,MAAM,EAzBtC,CA2BF,CAEA,SAAS,EAAY,EAA2C,CAC9D,EAAM,OAAO,OAAO,CACtB,CAEA,SAAS,GAAmB,CAC1B,EAAa,EAAI,CACnB,CAEA,SAAS,EAAgB,EAAyC,CAG5D,EAAM,cAAc,SAAS,EAAM,aAA4B,IACnE,EAAa,EAAK,EACd,IAAe,EAAc,QAAU,IAC7C,CAEA,OACE,EAAC,MAAD,CAAK,GAAI,EAAM,UAAW,EAAG,EAAO,SAAU,GAAY,EAAO,iBAAkB,CAAS,EAAU,QAAtG,SAAA,CACG,GACC,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,cAAe,GAAY,KAAK,EAAG,MAAO,GAAY,MAAhF,SAAA,CACG,EACA,GAAc,EAAC,OAAD,CAAM,UAAW,EAAO,qBAAsB,SAAA,IAAQ,CAAA,CAClE,IAEP,EAAC,MAAD,CACE,KAAK,QACL,aAAY,GAAS,gBACrB,UAAW,EAAG,EAAO,cAAe,GAAa,EAAO,mBAAoB,GAAY,MAAM,EAC9F,MAAO,GAAY,OACnB,QAAS,EACT,OAAQ,EACR,iBAAoB,EAAa,EAAI,EACrC,iBAAoB,EAAa,EAAK,EAErC,SAAA,MAAM,KAAK,CAAE,QAAO,GAAI,EAAG,IAAU,CACpC,IAAM,EAAO,EAAa,IAAU,GACpC,OACE,EAAC,MAAD,CAAiB,UAAW,EAAO,mBAAnC,SAAA,CACE,EAAC,QAAD,CACE,IAAM,GAAO,CACX,EAAU,QAAQ,GAAS,CAC7B,EACA,KAAM,EAAS,WAAa,OAC5B,UAAW,IAAY,EAAgB,QAAU,UAAY,OAC7D,QAAS,IAAY,EAAgB,QAAU,SAAW,IAAA,GAC1D,aAAc,IAAU,EAAI,gBAAkB,MAC9C,UAAW,EACD,WACV,MAAO,EACP,aAAY,SAAS,EAAQ,EAAE,MAAM,IACrC,eAAc,GAAa,IAAA,GAC3B,UAAW,EACT,EAAO,YACP,GAAa,EAAO,iBACpB,GAAQ,EAAO,kBACf,GAAY,KACd,EACA,MAAO,GAAY,MACnB,SAAW,GAAM,EAAa,EAAO,EAAE,OAAO,KAAK,EACnD,UAAY,GAAM,EAAc,EAAO,CAAC,EACxC,QAAU,GAAM,EAAY,EAAO,CAAC,EACpC,QAAS,CACV,CAAA,EACA,EAAW,SAAS,EAAQ,CAAC,GAAK,EAAQ,EAAS,GAClD,EAAC,OAAD,CAAM,UAAW,EAAG,EAAO,kBAAmB,GAAY,SAAS,EAAG,MAAO,GAAY,SAAY,CAAA,CAEpG,CA7BK,EAAA,CA6BL,CAET,CAAC,CACE,CAAA,EACL,EAAC,EAAD,CAAS,QAAQ,QAAQ,QAAS,EAAuB,UAAW,IAAc,GAAa,EAAa,CAAA,CACzG,GAET"}
|
|
1
|
+
{"version":3,"file":"otpInput.mjs","names":[],"sources":["../../../../package/common/otpInput/otpInput.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\nimport Tooltip from 'components/common/tooltip';\nimport { useComponentDefaults, useLabels } from '../configProvider';\n\nimport { OtpInputCharset, type OtpInputLabels, type OtpInputProps } from './otpInput.types';\nimport styles from './otpInput.module.pcss';\n\nconst NUMERIC_RE = /[0-9]/g;\nconst ALPHANUMERIC_RE = /[a-zA-Z0-9]/g;\n\nconst DEFAULT_LABELS: Required<OtpInputLabels> = {\n field: 'One-time code',\n digit: (position, length) => `Digit ${position} of ${length}`,\n};\n\nfunction filterChars(raw: string, charset: OtpInputCharset): string {\n const re = charset === OtpInputCharset.Alphanumeric ? ALPHANUMERIC_RE : NUMERIC_RE;\n return (raw.match(re) || []).join('');\n}\n\nfunction OtpInput(props: OtpInputProps): ReactElement {\n const {\n length = 6,\n value,\n onChange = () => {},\n onComplete = () => {},\n formValidator = null,\n charset = OtpInputCharset.Numeric,\n masked = false,\n groupAfter = [],\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n clearOnError = false,\n clearErrorDelay = 900,\n disabled = false,\n autoFocus = false,\n className = '',\n style,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n } = useComponentDefaults('OtpInput', props);\n const text = useLabels('OtpInput', labels, DEFAULT_LABELS);\n\n const currentValue = (formValidator ? (formValidator.value as string) : value) ?? '';\n const [, forceUpdate] = useState(0);\n const [isShaking, setIsShaking] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const inputRefs = useRef<Array<HTMLInputElement | null>>([]);\n const wasErrorRef = useRef(false);\n\n useEffect(() => {\n if (!formValidator) return;\n formValidator.validate();\n const listener = () => forceUpdate((n) => n + 1);\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator]);\n\n useEffect(() => {\n if (!autoFocus) return;\n const firstEmpty = Math.min(currentValue.length, length - 1);\n inputRefs.current[firstEmpty]?.focus();\n // Only run once, on mount.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const showError = formValidator ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n const displayedErrorMessage = formValidator ? formValidator.getCurrentErrorMessage() : errorMessage || '';\n\n useEffect(() => {\n const justErrored = showError && !wasErrorRef.current;\n wasErrorRef.current = showError;\n if (!justErrored) return;\n\n setIsShaking(true);\n const shakeTimeoutId = window.setTimeout(() => setIsShaking(false), 400);\n const clearTimeoutId = clearOnError\n ? window.setTimeout(() => {\n commit('');\n inputRefs.current[0]?.focus();\n }, clearErrorDelay)\n : null;\n\n return () => {\n window.clearTimeout(shakeTimeoutId);\n if (clearTimeoutId != null) window.clearTimeout(clearTimeoutId);\n };\n // Only re-evaluate on an actual error-state or config change, not on every value/render.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [showError, clearOnError, clearErrorDelay]);\n\n function commit(next: string) {\n const wasComplete = currentValue.length === length;\n const clipped = filterChars(next, charset).slice(0, length);\n if (formValidator) {\n formValidator.set(clipped);\n }\n onChange?.(clipped);\n // Only fire once per genuinely new completion (going from partial to full), not on every\n // keystroke made while correcting an already-full code.\n if (clipped.length === length && !wasComplete) {\n onComplete?.(clipped);\n }\n }\n\n function setCharAt(index: number, char: string) {\n const chars = currentValue.split('');\n chars[index] = char;\n commit(chars.join(''));\n }\n\n function handleChange(index: number, rawInput: string) {\n if (disabled) return;\n if (rawInput === '') {\n // Box was cleared (e.g. select + delete) — Backspace itself is handled in onKeyDown.\n setCharAt(index, '');\n return;\n }\n\n const filtered = filterChars(rawInput, charset);\n if (!filtered) {\n // Typed an invalid/disallowed character — the controlled `value` re-render discards it.\n return;\n }\n\n // Clicking straight into a box past the contiguous filled prefix (skipping ahead of\n // empty boxes) fills the next expected slot instead, rather than leaving a gap before it\n // that setCharAt/distributeFrom can't represent in a plain string and would silently collapse.\n const targetIndex = Math.min(index, currentValue.length);\n\n if (rawInput.length > 1) {\n // Mobile autofill / SMS suggestions can drop the whole code into one box, bypassing maxLength.\n distributeFrom(targetIndex, filtered);\n return;\n }\n\n setCharAt(targetIndex, filtered);\n if (targetIndex < length - 1) {\n inputRefs.current[targetIndex + 1]?.focus();\n } else {\n inputRefs.current[targetIndex]?.blur();\n }\n }\n\n function distributeFrom(startIndex: number, chars: string) {\n const clean = filterChars(chars, charset);\n if (!clean) return;\n const existing = currentValue.padEnd(length, ' ').split('');\n let cursor = startIndex;\n for (const char of clean) {\n if (cursor >= length) break;\n existing[cursor] = char;\n cursor += 1;\n }\n commit(existing.join('').trimEnd());\n const nextFocus = Math.min(cursor, length - 1);\n inputRefs.current[nextFocus]?.focus();\n if (cursor >= length) {\n inputRefs.current[length - 1]?.blur();\n }\n }\n\n function handlePaste(index: number, event: React.ClipboardEvent<HTMLInputElement>) {\n if (disabled) return;\n const pasted = event.clipboardData.getData('text');\n if (!pasted) return;\n event.preventDefault();\n // Same clamp as handleChange — pasting into a box past the filled prefix starts at the\n // next expected slot instead of leaving an unrepresentable gap before it.\n distributeFrom(Math.min(index, currentValue.length), pasted);\n }\n\n function handleKeyDown(index: number, event: React.KeyboardEvent<HTMLInputElement>) {\n if (disabled) return;\n\n // React's controlled-input onChange never fires when the resulting value is identical to\n // what's already rendered (its value tracker sees no change) — so retyping the exact digit\n // already in a box would otherwise silently do nothing. keydown always fires, so handle that\n // one case here and skip the native edit entirely.\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {\n const typed = filterChars(event.key, charset);\n if (typed && currentValue[index] === typed) {\n event.preventDefault();\n setCharAt(index, typed);\n if (index < length - 1) {\n inputRefs.current[index + 1]?.focus();\n } else {\n inputRefs.current[index]?.blur();\n }\n return;\n }\n }\n\n if (event.key === 'Backspace') {\n if (currentValue[index]) {\n setCharAt(index, '');\n return;\n }\n if (index > 0) {\n event.preventDefault();\n setCharAt(index - 1, '');\n inputRefs.current[index - 1]?.focus();\n }\n return;\n }\n if (event.key === 'Delete') {\n if (currentValue[index]) setCharAt(index, '');\n return;\n }\n if (event.key === 'ArrowLeft' && index > 0) {\n event.preventDefault();\n inputRefs.current[index - 1]?.focus();\n return;\n }\n if (event.key === 'ArrowRight' && index < length - 1) {\n event.preventDefault();\n inputRefs.current[index + 1]?.focus();\n }\n }\n\n function handleFocus(event: React.FocusEvent<HTMLInputElement>) {\n event.target.select();\n }\n\n function handleGroupFocus() {\n setIsFocused(true);\n }\n\n function handleGroupBlur(event: React.FocusEvent<HTMLDivElement>) {\n // Auto-advance moves focus between boxes constantly while typing — only treat this as\n // leaving the group once focus actually lands outside it, not on the next box.\n if (event.currentTarget.contains(event.relatedTarget as Node | null)) return;\n setIsFocused(false);\n if (formValidator) formValidator.touched = true;\n }\n\n return (\n <div {...rest} className={cx(styles.otpInput, disabled && styles.otpInputDisabled, className)} style={style}>\n {label && (\n <div className={cx(styles.otpInputLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n {isRequired && <span className={styles.otpInputRequiredMark}> *</span>}\n </div>\n )}\n <div\n role='group'\n aria-label={label || text.field}\n className={cx(styles.otpInputBoxes, isShaking && styles.otpInputBoxesShake, classNames?.inputs)}\n style={slotStyles?.inputs}\n onFocus={handleGroupFocus}\n onBlur={handleGroupBlur}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n {Array.from({ length }, (_, index) => {\n const char = currentValue[index] || '';\n return (\n <div key={index} className={styles.otpInputBoxWrapper}>\n <input\n ref={(el) => {\n inputRefs.current[index] = el;\n }}\n type={masked ? 'password' : 'text'}\n inputMode={charset === OtpInputCharset.Numeric ? 'numeric' : 'text'}\n pattern={charset === OtpInputCharset.Numeric ? '[0-9]*' : undefined}\n autoComplete={index === 0 ? 'one-time-code' : 'off'}\n maxLength={1}\n disabled={disabled}\n value={char}\n aria-label={text.digit(index + 1, length)}\n aria-invalid={showError || undefined}\n className={cx(\n styles.otpInputBox,\n showError && styles.otpInputBoxError,\n char && styles.otpInputBoxFilled,\n classNames?.input,\n )}\n style={slotStyles?.input}\n onChange={(e) => handleChange(index, e.target.value)}\n onKeyDown={(e) => handleKeyDown(index, e)}\n onPaste={(e) => handlePaste(index, e)}\n onFocus={handleFocus}\n />\n {groupAfter.includes(index + 1) && index < length - 1 && (\n <span className={cx(styles.otpInputSeparator, classNames?.separator)} style={slotStyles?.separator} />\n )}\n </div>\n );\n })}\n </div>\n <Tooltip variant='error' message={displayedErrorMessage} isVisible={showError && (isFocused || isHovered)} />\n </div>\n );\n}\n\nexport default OtpInput;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"otpInput.types.mjs","names":[],"sources":["../../../../package/common/otpInput/otpInput.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { FormValidator } from 'services/formValidation';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport type OtpInputSlots = 'root' | 'label' | 'inputs' | 'input' | 'separator';\n\nexport enum OtpInputCharset {\n /** Digits only (0-9). Shows a numeric mobile keyboard. */\n Numeric = 'numeric',\n /** Letters and digits. */\n Alphanumeric = 'alphanumeric',\n}\n\nexport interface OtpInputProps extends Omit<HtmlProps, 'onChange'> {\n /** Number of character boxes. Default 6. */\n length?: number;\n /** Current code as a plain string, e.g. \"123456\". */\n value?: string;\n /** Fired on every change with the full current code (may be shorter than `length`). */\n onChange?: ((value: string) => void) | null;\n /** Fired once, when the code reaches `length` characters. */\n onComplete?: ((value: string) => void) | null;\n formValidator?: FormValidator | null;\n\n /** Restricts which characters can be typed and picks the mobile keyboard. Default `numeric`. */\n charset?: OtpInputCharset;\n /** Render each box's value as a dot, like a password field. */\n masked?: boolean;\n /** Draw a small gap after these 1-based box indices, e.g. `[3]` to split 6 boxes into 3+3. */\n groupAfter?: number[];\n\n label?: string;\n isValid?: boolean;\n /** Shown in an error Tooltip on focus/hover once `isValid` is `false` (or, with a\n * `formValidator`, once it's touched and has an error). Persists until the value changes\n * `isValid`/`formValidator`'s error state itself — see `clearOnError` to auto-dismiss it. */\n errorMessage?: string;\n isRequired?: boolean;\n /** When an error newly appears (`isValid`/`formValidator` turning invalid), clear every box and\n * refocus the first one after `clearErrorDelay`, so the next attempt starts clean instead of the\n * user editing individual wrong digits (and re-triggering `onComplete` on every keystroke while\n * the code stays at full length). Default `false`. */\n clearOnError?: boolean;\n /** Delay in ms before `clearOnError` clears the boxes, so the wrong code and error message are\n * still visible for a moment first. Default `900`. */\n clearErrorDelay?: number;\n disabled?: boolean;\n /** Focuses the first empty box (or the first box) on mount. */\n autoFocus?: boolean;\n\n className?: string;\n style?: React.CSSProperties;\n classNames?: SlotClassNames<OtpInputSlots>;\n styles?: SlotStyles<OtpInputSlots>;\n}\n"],"mappings":"AAMA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,aAAA,gBACF,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"otpInput.types.mjs","names":[],"sources":["../../../../package/common/otpInput/otpInput.types.ts"],"sourcesContent":["import type React from 'react';\nimport type { FormValidator } from 'services/formValidation';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport type OtpInputSlots = 'root' | 'label' | 'inputs' | 'input' | 'separator';\n\nexport enum OtpInputCharset {\n /** Digits only (0-9). Shows a numeric mobile keyboard. */\n Numeric = 'numeric',\n /** Letters and digits. */\n Alphanumeric = 'alphanumeric',\n}\n\n/** Text OtpInput renders of its own, for translating it. */\nexport interface OtpInputLabels {\n /** The group of boxes, used when no `label` is given. */\n field?: string;\n /** One box, given its 1-based position and how many there are. */\n digit?: (position: number, length: number) => string;\n}\n\nexport interface OtpInputProps extends Omit<HtmlProps, 'onChange'> {\n /** Number of character boxes. Default 6. */\n length?: number;\n /** Current code as a plain string, e.g. \"123456\". */\n value?: string;\n /** Fired on every change with the full current code (may be shorter than `length`). */\n onChange?: ((value: string) => void) | null;\n /** Fired once, when the code reaches `length` characters. */\n onComplete?: ((value: string) => void) | null;\n formValidator?: FormValidator | null;\n\n /** Restricts which characters can be typed and picks the mobile keyboard. Default `numeric`. */\n charset?: OtpInputCharset;\n /** Render each box's value as a dot, like a password field. */\n masked?: boolean;\n /** Draw a small gap after these 1-based box indices, e.g. `[3]` to split 6 boxes into 3+3. */\n groupAfter?: number[];\n\n label?: string;\n isValid?: boolean;\n /** Shown in an error Tooltip on focus/hover once `isValid` is `false` (or, with a\n * `formValidator`, once it's touched and has an error). Persists until the value changes\n * `isValid`/`formValidator`'s error state itself — see `clearOnError` to auto-dismiss it. */\n errorMessage?: string;\n isRequired?: boolean;\n /** When an error newly appears (`isValid`/`formValidator` turning invalid), clear every box and\n * refocus the first one after `clearErrorDelay`, so the next attempt starts clean instead of the\n * user editing individual wrong digits (and re-triggering `onComplete` on every keystroke while\n * the code stays at full length). Default `false`. */\n clearOnError?: boolean;\n /** Delay in ms before `clearOnError` clears the boxes, so the wrong code and error message are\n * still visible for a moment first. Default `900`. */\n clearErrorDelay?: number;\n disabled?: boolean;\n /** Focuses the first empty box (or the first box) on mount. */\n autoFocus?: boolean;\n\n className?: string;\n style?: React.CSSProperties;\n classNames?: SlotClassNames<OtpInputSlots>;\n styles?: SlotStyles<OtpInputSlots>;\n /** Overrides the text OtpInput renders of its own. Merged per key. */\n labels?: OtpInputLabels;\n}\n"],"mappings":"AAMA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,aAAA,gBACF,EAAA,CAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{
|
|
1
|
+
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import r from"./pagination.module.mjs";import{useState as i}from"react";import a from"classnames";import{faAnglesLeft as o,faAnglesRight as s,faChevronLeft as c,faChevronRight as l}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var f=`dots`,p={goToPage:e=>`Go to page ${e}`,first:`Go to first page`,previous:`Go to previous page`,next:`Go to next page`,last:`Go to last page`};function m(e,t){return t<e?[]:Array.from({length:t-e+1},(t,n)=>e+n)}function h(e,t){return Math.max(1,Math.min(t,Math.round(e)))}function g(e,t,n,r){if(n*2+r*2+3>=t)return m(1,t);let i=m(1,r),a=m(t-r+1,t),o=i.length>0?[f]:[],s=a.length>0?[f]:[],c=Math.max(e-n,r+1),l=Math.min(e+n,t-r),u=c>r+2,d=l<t-r-1;return!u&&d?[...m(1,r+n*2+2),...s,...a]:u&&!d?[...i,...o,...m(t-r-n*2-1,t)]:[...i,...o,...m(c,l),...s,...a]}function _(m){let{total:_,page:v,defaultPage:y=1,onChange:b=()=>{},siblings:x=1,boundaries:S=1,showControls:C=!0,showEdges:w=!1,disabled:T=!1,previousIcon:E=c,nextIcon:D=l,firstIcon:O=o,lastIcon:k=s,"aria-label":A=`Pagination`,className:j,style:M,classNames:N,styles:P,labels:F,...I}=e(`Pagination`,m),L=t(`Pagination`,F,p),R=v!==void 0,[z,B]=i(y),V=h(R?v:z,_);if(_<1)return null;function H(e){let t=h(e,_);t!==V&&(R||B(t),b(t))}let U=a(r.paginationControl,N?.control);function W(e,t,r,i,a){return u(`button`,{type:`button`,className:U,style:P?.control,"aria-label":t,disabled:T||a,onClick:()=>H(i),children:n(r)},e)}let G=V<=1,K=V>=_;return d(`nav`,{...I,"aria-label":A,className:a(r.pagination,N?.root,j),style:{...M,...P?.root},children:[w&&W(`first`,L.first,O,1,G),C&&W(`previous`,L.previous,E,V-1,G),g(V,_,x,S).map((e,t)=>e===f?u(`span`,{"aria-hidden":`true`,className:a(r.paginationEllipsis,N?.ellipsis),style:P?.ellipsis,children:`…`},`dots-${t}`):u(`button`,{type:`button`,className:a(r.paginationItem,e===V&&r.paginationItemActive,N?.item),style:P?.item,"aria-label":L.goToPage(e),"aria-current":e===V?`page`:void 0,disabled:T,onClick:()=>H(e),children:e},e)),C&&W(`next`,L.next,D,V+1,K),w&&W(`last`,L.last,k,_,K)]})}export{_ as default};
|
|
2
2
|
//# sourceMappingURL=pagination.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.mjs","names":[],"sources":["../../../../package/common/pagination/pagination.tsx"],"sourcesContent":["import { useState } from 'react';\nimport type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faAnglesLeft, faAnglesRight, faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport { useComponentDefaults } from '../configProvider';\nimport type { IconContent } from '../types/icon.types';\nimport { renderIcon } from '../utils/renderIcon';\nimport type { PaginationProps } from './pagination.types';\n\nimport styles from './pagination.module.pcss';\n\nconst DOTS = 'dots';\n\ntype PaginationEntry = number | typeof DOTS;\n\nfunction range(start: number, end: number): number[] {\n if (end < start) return [];\n return Array.from({ length: end - start + 1 }, (_, index) => start + index);\n}\n\nfunction clampPage(page: number, total: number): number {\n return Math.max(1, Math.min(total, Math.round(page)));\n}\n\nfunction getEntries(page: number, total: number, siblings: number, boundaries: number): PaginationEntry[] {\n const maxEntries = siblings * 2 + boundaries * 2 + 3;\n if (maxEntries >= total) return range(1, total);\n\n const leftBoundary = range(1, boundaries);\n const rightBoundary = range(total - boundaries + 1, total);\n const leftGap: PaginationEntry[] = leftBoundary.length > 0 ? [DOTS] : [];\n const rightGap: PaginationEntry[] = rightBoundary.length > 0 ? [DOTS] : [];\n\n const leftSibling = Math.max(page - siblings, boundaries + 1);\n const rightSibling = Math.min(page + siblings, total - boundaries);\n\n const hasLeftDots = leftSibling > boundaries + 2;\n const hasRightDots = rightSibling < total - boundaries - 1;\n\n if (!hasLeftDots && hasRightDots) {\n return [...range(1, boundaries + siblings * 2 + 2), ...rightGap, ...rightBoundary];\n }\n\n if (hasLeftDots && !hasRightDots) {\n return [...leftBoundary, ...leftGap, ...range(total - boundaries - siblings * 2 - 1, total)];\n }\n\n return [...leftBoundary, ...leftGap, ...range(leftSibling, rightSibling), ...rightGap, ...rightBoundary];\n}\n\nfunction Pagination(props: PaginationProps): ReactElement | null {\n const {\n total,\n page: controlledPage,\n defaultPage = 1,\n onChange = () => {},\n siblings = 1,\n boundaries = 1,\n showControls = true,\n showEdges = false,\n disabled = false,\n previousIcon = faChevronLeft,\n nextIcon = faChevronRight,\n firstIcon = faAnglesLeft,\n lastIcon = faAnglesRight,\n 'aria-label': ariaLabel = 'Pagination',\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Pagination', props);\n\n const isControlled = controlledPage !== undefined;\n const [internalPage, setInternalPage] = useState(defaultPage);\n const page = clampPage(isControlled ? controlledPage! : internalPage, total);\n\n if (total < 1) return null;\n\n function goTo(next: number) {\n const clamped = clampPage(next, total);\n if (clamped === page) return;\n if (!isControlled) setInternalPage(clamped);\n onChange(clamped);\n }\n\n const controlClassName = cx(styles.paginationControl, classNames?.control);\n\n function renderControl(key: string, label: string, icon: IconContent, target: number, isDisabled: boolean) {\n return (\n <button\n key={key}\n type='button'\n className={controlClassName}\n style={slotStyles?.control}\n aria-label={label}\n disabled={disabled || isDisabled}\n onClick={() => goTo(target)}\n >\n {renderIcon(icon)}\n </button>\n );\n }\n\n const isFirst = page <= 1;\n const isLast = page >= total;\n\n return (\n <nav\n {...rest}\n aria-label={ariaLabel}\n className={cx(styles.pagination, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {showEdges && renderControl('first',
|
|
1
|
+
{"version":3,"file":"pagination.mjs","names":[],"sources":["../../../../package/common/pagination/pagination.tsx"],"sourcesContent":["import { useState } from 'react';\nimport type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faAnglesLeft, faAnglesRight, faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport type { IconContent } from '../types/icon.types';\nimport { renderIcon } from '../utils/renderIcon';\nimport type { PaginationLabels, PaginationProps } from './pagination.types';\n\nimport styles from './pagination.module.pcss';\n\nconst DOTS = 'dots';\n\ntype PaginationEntry = number | typeof DOTS;\n\nconst DEFAULT_LABELS: Required<PaginationLabels> = {\n goToPage: (page) => `Go to page ${page}`,\n first: 'Go to first page',\n previous: 'Go to previous page',\n next: 'Go to next page',\n last: 'Go to last page',\n};\n\nfunction range(start: number, end: number): number[] {\n if (end < start) return [];\n return Array.from({ length: end - start + 1 }, (_, index) => start + index);\n}\n\nfunction clampPage(page: number, total: number): number {\n return Math.max(1, Math.min(total, Math.round(page)));\n}\n\nfunction getEntries(page: number, total: number, siblings: number, boundaries: number): PaginationEntry[] {\n const maxEntries = siblings * 2 + boundaries * 2 + 3;\n if (maxEntries >= total) return range(1, total);\n\n const leftBoundary = range(1, boundaries);\n const rightBoundary = range(total - boundaries + 1, total);\n const leftGap: PaginationEntry[] = leftBoundary.length > 0 ? [DOTS] : [];\n const rightGap: PaginationEntry[] = rightBoundary.length > 0 ? [DOTS] : [];\n\n const leftSibling = Math.max(page - siblings, boundaries + 1);\n const rightSibling = Math.min(page + siblings, total - boundaries);\n\n const hasLeftDots = leftSibling > boundaries + 2;\n const hasRightDots = rightSibling < total - boundaries - 1;\n\n if (!hasLeftDots && hasRightDots) {\n return [...range(1, boundaries + siblings * 2 + 2), ...rightGap, ...rightBoundary];\n }\n\n if (hasLeftDots && !hasRightDots) {\n return [...leftBoundary, ...leftGap, ...range(total - boundaries - siblings * 2 - 1, total)];\n }\n\n return [...leftBoundary, ...leftGap, ...range(leftSibling, rightSibling), ...rightGap, ...rightBoundary];\n}\n\nfunction Pagination(props: PaginationProps): ReactElement | null {\n const {\n total,\n page: controlledPage,\n defaultPage = 1,\n onChange = () => {},\n siblings = 1,\n boundaries = 1,\n showControls = true,\n showEdges = false,\n disabled = false,\n previousIcon = faChevronLeft,\n nextIcon = faChevronRight,\n firstIcon = faAnglesLeft,\n lastIcon = faAnglesRight,\n 'aria-label': ariaLabel = 'Pagination',\n className,\n style,\n classNames,\n styles: slotStyles,\n labels,\n ...rest\n } = useComponentDefaults('Pagination', props);\n const text = useLabels('Pagination', labels, DEFAULT_LABELS);\n\n const isControlled = controlledPage !== undefined;\n const [internalPage, setInternalPage] = useState(defaultPage);\n const page = clampPage(isControlled ? controlledPage! : internalPage, total);\n\n if (total < 1) return null;\n\n function goTo(next: number) {\n const clamped = clampPage(next, total);\n if (clamped === page) return;\n if (!isControlled) setInternalPage(clamped);\n onChange(clamped);\n }\n\n const controlClassName = cx(styles.paginationControl, classNames?.control);\n\n function renderControl(key: string, label: string, icon: IconContent, target: number, isDisabled: boolean) {\n return (\n <button\n key={key}\n type='button'\n className={controlClassName}\n style={slotStyles?.control}\n aria-label={label}\n disabled={disabled || isDisabled}\n onClick={() => goTo(target)}\n >\n {renderIcon(icon)}\n </button>\n );\n }\n\n const isFirst = page <= 1;\n const isLast = page >= total;\n\n return (\n <nav\n {...rest}\n aria-label={ariaLabel}\n className={cx(styles.pagination, classNames?.root, className)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {showEdges && renderControl('first', text.first, firstIcon, 1, isFirst)}\n {showControls && renderControl('previous', text.previous, previousIcon, page - 1, isFirst)}\n\n {getEntries(page, total, siblings, boundaries).map((entry, index) =>\n entry === DOTS ? (\n <span\n key={`dots-${index}`}\n aria-hidden='true'\n className={cx(styles.paginationEllipsis, classNames?.ellipsis)}\n style={slotStyles?.ellipsis}\n >\n …\n </span>\n ) : (\n <button\n key={entry}\n type='button'\n className={cx(styles.paginationItem, entry === page && styles.paginationItemActive, classNames?.item)}\n style={slotStyles?.item}\n aria-label={text.goToPage(entry)}\n aria-current={entry === page ? 'page' : undefined}\n disabled={disabled}\n onClick={() => goTo(entry)}\n >\n {entry}\n </button>\n ),\n )}\n\n {showControls && renderControl('next', text.next, nextIcon, page + 1, isLast)}\n {showEdges && renderControl('last', text.last, lastIcon, total, isLast)}\n </nav>\n );\n}\n\nexport default Pagination;\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"./progressBar.module.mjs";import t from"classnames";import{jsx as n}from"react/jsx-runtime";function r(e){let t=e.replace(`#`,``),n=parseInt(t.substring(0,2),16),r=parseInt(t.substring(2,4),16),i=parseInt(t.substring(4,6),16);return(.299*n+.587*r+.114*i)/255>.5?`#000000`:`#ffffff`}function i({className:i=void 0,total:a=100,progress:o=0,style:s=void 0,...
|
|
1
|
+
import e from"./progressBar.module.mjs";import t from"classnames";import{jsx as n}from"react/jsx-runtime";function r(e){let t=e.replace(`#`,``),n=parseInt(t.substring(0,2),16),r=parseInt(t.substring(2,4),16),i=parseInt(t.substring(4,6),16);return(.299*n+.587*r+.114*i)/255>.5?`#000000`:`#ffffff`}function i({className:i=void 0,total:a=100,progress:o=0,style:s=void 0,classNames:c,styles:l,...u}){function d(){let i=[];return Array.isArray(o)?i.push(...o):typeof o==`object`?i.push(o):i.push({amount:o}),i.map((o,s)=>{let u=a?o.amount/a*100:0;return n(`div`,{className:t(e.progressBarFill,s===i.length-1&&e.progressBarFillEnd,o.class,c?.fill),style:{width:`${u}%`,background:o.color||void 0,...l?.fill},title:o.label?`${o.label}: ${o.amount}`:void 0,children:o.label&&n(`div`,{className:t(e.progressBarLabel,c?.label),style:{...o.color?{color:r(o.color)}:{},...l?.label},children:o.label})},s)})}return n(`div`,{...u,className:t(e.progressBar,i,c?.root),style:{...s,...l?.root},children:d()})}export{i as default,r as getContrastColor};
|
|
2
2
|
//# sourceMappingURL=progressBar.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progressBar.mjs","names":[],"sources":["../../../../package/common/progressBar/progressBar.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { Progress, ProgressBarProps } from './progressBar.types';\n\nimport styles from './progressBar.module.pcss';\n\nexport function getContrastColor(hexColor: string): string {\n const hex = hexColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n\n const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luminance > 0.5 ? '#000000' : '#ffffff';\n}\n\nfunction ProgressBar({\n className = undefined,\n total = 100,\n progress = 0,\n style = undefined,\n ...rest\n}: ProgressBarProps): ReactElement {\n function renderProgressBars() {\n const progressArray: Progress[] = [];\n\n if (Array.isArray(progress)) progressArray.push(...progress);\n else if (typeof progress === 'object') progressArray.push(progress);\n else progressArray.push({ amount: progress });\n\n return progressArray.map((prog, index) => {\n const widthPercentage = !total ? 0 : (prog.amount / total) * 100;\n\n return (\n <div\n key={index}\n className={cx(\n styles.progressBarFill,\n index === progressArray.length - 1 && styles.progressBarFillEnd,\n prog.class,\n )}\n style={{\n width: `${widthPercentage}%`,\n background: prog.color || undefined,\n ...
|
|
1
|
+
{"version":3,"file":"progressBar.mjs","names":[],"sources":["../../../../package/common/progressBar/progressBar.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { Progress, ProgressBarProps } from './progressBar.types';\n\nimport styles from './progressBar.module.pcss';\n\nexport function getContrastColor(hexColor: string): string {\n const hex = hexColor.replace('#', '');\n const r = parseInt(hex.substring(0, 2), 16);\n const g = parseInt(hex.substring(2, 4), 16);\n const b = parseInt(hex.substring(4, 6), 16);\n\n const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;\n return luminance > 0.5 ? '#000000' : '#ffffff';\n}\n\nfunction ProgressBar({\n className = undefined,\n total = 100,\n progress = 0,\n style = undefined,\n classNames,\n styles: slotStyles,\n ...rest\n}: ProgressBarProps): ReactElement {\n function renderProgressBars() {\n const progressArray: Progress[] = [];\n\n if (Array.isArray(progress)) progressArray.push(...progress);\n else if (typeof progress === 'object') progressArray.push(progress);\n else progressArray.push({ amount: progress });\n\n return progressArray.map((prog, index) => {\n const widthPercentage = !total ? 0 : (prog.amount / total) * 100;\n\n return (\n <div\n key={index}\n className={cx(\n styles.progressBarFill,\n index === progressArray.length - 1 && styles.progressBarFillEnd,\n prog.class,\n classNames?.fill,\n )}\n style={{\n width: `${widthPercentage}%`,\n background: prog.color || undefined,\n ...slotStyles?.fill,\n }}\n title={prog.label ? `${prog.label}: ${prog.amount}` : undefined}\n >\n {prog.label && (\n <div\n className={cx(styles.progressBarLabel, classNames?.label)}\n style={{ ...(prog.color ? { color: getContrastColor(prog.color) } : {}), ...slotStyles?.label }}\n >\n {prog.label}\n </div>\n )}\n </div>\n );\n });\n }\n\n return (\n <div\n {...rest}\n className={cx(styles.progressBar, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {renderProgressBars()}\n </div>\n );\n}\n\nexport default ProgressBar;\n"],"mappings":"0GAMA,SAAgB,EAAiB,EAA0B,CACzD,IAAM,EAAM,EAAS,QAAQ,IAAK,EAAE,EAC9B,EAAI,SAAS,EAAI,UAAU,EAAG,CAAC,EAAG,EAAE,EACpC,EAAI,SAAS,EAAI,UAAU,EAAG,CAAC,EAAG,EAAE,EACpC,EAAI,SAAS,EAAI,UAAU,EAAG,CAAC,EAAG,EAAE,EAG1C,OADmB,KAAQ,EAAI,KAAQ,EAAI,KAAQ,GAAK,IACrC,GAAM,UAAY,SACvC,CAEA,SAAS,EAAY,CACnB,YAAY,IAAA,GACZ,QAAQ,IACR,WAAW,EACX,QAAQ,IAAA,GACR,aACA,OAAQ,EACR,GAAG,GAC8B,CACjC,SAAS,GAAqB,CAC5B,IAAM,EAA4B,CAAC,EAMnC,OAJI,MAAM,QAAQ,CAAQ,EAAG,EAAc,KAAK,GAAG,CAAQ,EAClD,OAAO,GAAa,SAAU,EAAc,KAAK,CAAQ,EAC7D,EAAc,KAAK,CAAE,OAAQ,CAAS,CAAC,EAErC,EAAc,KAAK,EAAM,IAAU,CACxC,IAAM,EAAmB,EAAa,EAAK,OAAS,EAAS,IAA5B,EAEjC,OACE,EAAC,MAAD,CAEE,UAAW,EACT,EAAO,gBACP,IAAU,EAAc,OAAS,GAAK,EAAO,mBAC7C,EAAK,MACL,GAAY,IACd,EACA,MAAO,CACL,MAAO,GAAG,EAAgB,GAC1B,WAAY,EAAK,OAAS,IAAA,GAC1B,GAAG,GAAY,IACjB,EACA,MAAO,EAAK,MAAQ,GAAG,EAAK,MAAM,IAAI,EAAK,SAAW,IAAA,GAErD,SAAA,EAAK,OACJ,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,iBAAkB,GAAY,KAAK,EACxD,MAAO,CAAE,GAAI,EAAK,MAAQ,CAAE,MAAO,EAAiB,EAAK,KAAK,CAAE,EAAI,CAAC,EAAI,GAAG,GAAY,KAAM,EAE7F,SAAA,EAAK,KACH,CAAA,CAEJ,EAtBE,CAsBF,CAET,CAAC,CACH,CAEA,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,YAAa,EAAW,GAAY,IAAI,EAC7D,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,IAAK,EAEtC,SAAA,EAAmB,CACjB,CAAA,CAET"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{renderIcon as t}from"../utils/renderIcon.mjs";import n from"../actionIcon/actionIcon.mjs";import r from"../hooks/useCoarsePointer.mjs";import i from"../input/input.mjs";import{OpeningKind as a,WallType as o}from"../floorPlan/floorPlan.types.mjs";import{pointToSegment as s}from"../floorPlan/floorPlan.geometry.mjs";import{DEFAULT_WALL_ATTRS as c,addOpening as l,addRect as ee,addWall as u,detachWall as te,dissolveNode as ne,mergeNodes as re,moveNode as ie,removeOpening as ae,removeWall as oe,splitWall as se,updateOpening as ce,weldShortWalls as le}from"../floorPlan/floorPlan.graph.mjs";import{addFloor as ue,duplicateFloor as de,emptyFloorPlan as fe,floorBelow as pe,floorBounds as me,floorIndex as he,getFloor as ge,moveFloor as _e,removeFloor as ve,renameFloor as ye,setFloor as be,setFloorHeight as xe}from"../floorPlan/floorPlan.plan.mjs";import{commitDerivation as Se,derivePlan as Ce}from"../floorPlan/floorPlan.rooms.mjs";import{HIT_PX as we,HIT_PX_COARSE as Te,hitTest as Ee,selectionsEqual as De,worldTolerances as d}from"../floorPlan/floorPlan.hit.mjs";import{SnapKind as f,clientToWorld as Oe,resolveSnap as ke}from"../floorPlan/floorPlan.snap.mjs";import{planFromJson as Ae,planToJson as je}from"../floorPlan/floorPlan.json.mjs";import Me from"../numberInput/index.mjs";import Ne from"../planCanvas/planCanvas.mjs";import{usePlanHistory as Pe}from"./usePlanHistory.mjs";import p from"./roomDrawer.module.mjs";import{forwardRef as Fe,useCallback as m,useEffect as h,useImperativeHandle as Ie,useMemo as Le,useRef as g,useState as _}from"react";import v from"classnames";import{faAngleDown as Re,faAngleUp as ze,faArrowPointer as Be,faArrowRotateLeft as Ve,faArrowRotateRight as He,faBorderAll as Ue,faClone as We,faDoorOpen as Ge,faDownload as Ke,faDraftingCompass as qe,faExpand as Je,faLayerGroup as Ye,faMagnet as Xe,faMagnifyingGlassMinus as Ze,faMagnifyingGlassPlus as Qe,faMinus as $e,faPlus as et,faRulerCombined as tt,faSquare as nt,faTrash as rt,faUpload as it,faWindowMaximize as at}from"@fortawesome/free-solid-svg-icons";import{Fragment as ot,jsx as y,jsxs as b}from"react/jsx-runtime";var st=[`select`,`wall`,`rect`,`door`,`window`,`archway`,`measure`],ct={v:`select`,w:`wall`,r:`rect`,d:`door`,n:`window`,a:`archway`,m:`measure`},lt={door:a.Door,window:a.Window,archway:a.Archway},ut={[a.Door]:`Door`,[a.Window]:`Window`,[a.Archway]:`Archway`,[a.Gap]:`Gap`},dt={[a.Door]:{width:900,sill:0,head:2100},[a.Window]:{width:1200,sill:900,head:2100},[a.Archway]:{width:1200,sill:0,head:2100},[a.Gap]:{width:1e3,sill:0,head:2500}},ft=1,pt=4,mt=[];function ht(e){return e>=1e3?`${(e/1e3).toFixed(2)} m`:`${Math.round(e)} mm`}function gt(e){let t=e/1e6;return`${t.toFixed(+(t<10))} m²`}function _t(e){let t=e*180/Math.PI;return t=(t%360+360)%360,t>180&&(t-=360),`${Math.abs(t)<.05?0:Math.round(t*10)/10}°`}var x=Fe(function(a,Fe){let{value:x,defaultValue:vt,onChange:S,onChangeEnd:yt,floorId:bt,defaultFloorId:xt,onFloorChange:St,showFloorBar:Ct=!0,showUnderlay:wt=!0,tool:Tt,defaultTool:Et=`select`,onToolChange:Dt,tools:Ot=st,selection:kt,defaultSelection:At,onSelectionChange:jt,multiSelect:Mt=!0,onHoverChange:Nt,view:Pt,defaultView:Ft,onViewChange:It,minZoom:Lt=.005,maxZoom:Rt=2,fitOnMount:zt=!0,gridSize:C=100,showGrid:Bt=!0,snap:Vt=!0,angleLock:Ht=!1,constrainAngle:Ut=45,showSnapGuides:Wt=!0,wallThickness:Gt=c.thickness,wallHeight:Kt,openingDefaults:qt,showMeasurements:Jt=!0,formatLength:Yt=ht,formatArea:Xt=gt,showToolbar:Zt=!0,showInspector:Qt=!0,showHint:$t=!0,showHistoryControls:en=!0,showFileControls:tn=!0,fileName:nn,onImport:rn,historyMode:an=`internal`,historyLimit:on=50,onHistoryChange:sn,readOnly:cn=!1,disabled:w=!1,canvasHeight:ln=`420px`,getRoomColor:un,renderRoomLabel:dn,labels:T,icons:E,"aria-label":fn,className:pn,style:mn,classNames:D,styles:O,...hn}=e(`RoomDrawer`,a),gn=r(),k=gn?Te:we,_n=g(null),vn=g(null),yn=g(null),bn=g(null),A=g({kind:`none`}),xn=g(new Map),Sn=g(null),Cn=g(!1),wn=g(!1),Tn=g(!1),En=Le(()=>vt??x??fe(),[]),j=Pe(En,on),Dn=x!==void 0,M=Dn?x:j.present;h(()=>{if(Dn&&x){if(x===bn.current){j.replace(x);return}j.commit(x,`external`)}},[x,Dn]);let[On,kn]=_(xt),An=bt??On??M.floors[0]?.id,N=Le(()=>ge(M,An)??ge(M)??fe().floors[0],[M,An]),[jn,Mn]=_(wt);h(()=>Mn(wt),[wt]);let Nn=Le(()=>jn?pe(M,N.id):null,[jn,M,N.id]),Pn=m(e=>{e!==N.id&&(bt===void 0&&kn(e),St?.(e))},[N.id,bt,St]),P=Le(()=>Ce(N),[N]).rooms,[Fn,In]=_(Et),F=Tt??Fn,Ln=m(e=>{Tt===void 0&&In(e),Dt?.(e)},[Tt,Dt]),[Rn,zn]=_(At??mt),I=kt===void 0?Rn:kt,L=g(I);L.current=I;let R=m(e=>{let t=e===null?mt:Array.isArray(e)?e:[e];L.current=t,kt===void 0&&zn(t),jt?.([...t])},[kt,jt]),Bn=m(e=>{let t=L.current,n=t.filter(t=>t.type!==e.type||t.id!==e.id);R(n.length===t.length?[...t,e]:n)},[R]),z=I.length===1?I[0]:null,Vn=m(e=>{let t=new Set;for(let n of e)if(n.type===`node`)t.add(n.id);else if(n.type===`wall`){let e=N.walls[n.id];e&&(t.add(e.a),t.add(e.b))}else if(n.type===`room`){let e=P.find(e=>e.roomId===n.id);for(let n of e?.nodeIds??[])t.add(n)}return t},[N.walls,P]),Hn=Le(()=>Vn(I),[Vn,I]),[Un,Wn]=_(null),[Gn,Kn]=_(Ft??{x:0,y:0,zoom:.05}),B=Pt??Gn,V=m(e=>{Pt===void 0&&Kn(e),It?.(e)},[Pt,It]),[H,qn]=_({width:800,height:420}),[U,Jn]=_([]),[W,Yn]=_(null),[Xn,Zn]=_(Vt),[Qn,$n]=_(Ht);h(()=>Zn(Vt),[Vt]),h(()=>$n(Ht),[Ht]);let[er,tr]=_(Bt);h(()=>tr(Bt),[Bt]);let nr=g(null),[G,rr]=_(null),[K,ir]=_([]),ar=g(0),[or,sr]=_(null),cr=g(null),lr=m(e=>{let t=d(k,B.zoom);for(let n=K.length-1;n>=0;n--){let r=K[n];if(Math.hypot(e.x-r.a.x,e.y-r.a.y)<=t.node)return{id:r.id,end:`a`};if(Math.hypot(e.x-r.b.x,e.y-r.b.y)<=t.node)return{id:r.id,end:`b`}}for(let n=K.length-1;n>=0;n--){let r=K[n];if(s(e,r.a,r.b).dist<=t.wall)return{id:r.id}}return null},[K,k,B.zoom]),[ur,dr]=_(null),q=!cn&&!w,fr=Le(()=>{if(U.length<2)return;let e=U[U.length-2],t=U[U.length-1];return Math.atan2(t.y-e.y,t.x-e.x)},[U]);h(()=>{let e=vn.current;if(!e)return;let t=new ResizeObserver(()=>{let t=e.getBoundingClientRect();t.width>0&&t.height>0&&qn({width:Math.round(t.width),height:Math.round(t.height)})});t.observe(e);let n=e.getBoundingClientRect();return n.width>0&&n.height>0&&qn({width:Math.round(n.width),height:Math.round(n.height)}),()=>t.disconnect()},[]);let pr=m((e,t)=>{let n=vn.current?.getBoundingClientRect()??{left:0,top:0};return Oe(e,t,n,B)},[B]),J=m(e=>({x:(e.x-B.x)*B.zoom,y:(e.y-B.y)*B.zoom}),[B]),Y=m((e,t,n,r,i)=>{let a=Xn!==wn.current,o=Qn!==Tn.current,s=ke(e,{floor:N,pxToWorld:B.zoom>0?1/B.zoom:1,origin:t,referenceAngle:r,excludeNodeIds:n,excludeWallIds:i,options:{enabled:a?[f.Node,f.Intersection,f.Wall,f.Angle,f.Extension,f.Alignment,f.Grid]:[],gridSize:C,angleStepDeg:o?Ut:0,toleranceScreenPx:gn?16:10}});return nr.current=s,s},[N,B.zoom,Xn,Qn,C,Ut,gn]),mr=m(e=>{let t=Object.values(N.walls).filter(t=>t.a===e||t.b===e),n=new Set(t.map(e=>e.id)),r=N.nodes[e];if(!r)return{excludeWallIds:n};let i={x:r.x,y:r.y},a,o=t[0];if(o){let t=o.a===e?o.b:o.a,n=N.nodes[t];n&&(a=Math.atan2(n.y-r.y,n.x-r.x))}return{origin:i,referenceAngle:a,excludeWallIds:n}},[N]),hr=m((e={})=>{let t=e.padding??24,n=me(N);if(!n||n.width<=0||n.height<=0){V({x:-1e3,y:-1e3,zoom:.05});return}let r=Math.min((H.width-t*2)/n.width,(H.height-t*2)/n.height),i=Math.max(Lt,Math.min(Rt,r));V({x:n.minX-(H.width/i-n.width)/2,y:n.minY-(H.height/i-n.height)/2,zoom:i})},[N,H.width,H.height,Lt,Rt,V]),gr=g(!1);h(()=>{zt&&!gr.current&&Object.keys(N.nodes).length!==0&&(H.width<=1||(gr.current=!0,hr()))},[zt,N,H.width,hr]);let _r=m((e,t,n,r=[],i={})=>{if(e===N)return M;let a=be(M,e);bn.current=a,n?i.push===!1?j.replace(a):j.commit(a,t,r):j.updateGesture(a);let o={reason:t,committed:n,targetIds:r};return S?.(a,o),n&&yt?.(a,o),a},[N,M,j,S,yt]),X=m((e,t,n=[],r={})=>{let i=Se(le(e).floor).floor;return _r(i,t,!0,n,r)},[_r]);h(()=>{sn?.({canUndo:j.canUndo,canRedo:j.canRedo})},[j.canUndo,j.canRedo,sn]);let vr=Le(()=>z?.type===`room`?P.find(e=>e.roomId===z.id)??null:null,[z,P]),Z=z?.type===`wall`?N.walls[z.id]:void 0,yr=z?.type===`opening`?N.openings[z.id]:void 0,br=Le(()=>{if(!Z)return null;let e=N.nodes[Z.a],t=N.nodes[Z.b];return!e||!t?null:{x:(e.x+t.x)/2,y:(e.y+t.y)/2}},[Z,N.nodes]),xr=m(()=>{if(!q||!Z)return;let e=se(N,Z.id,.5);e.result.wallIds&&(X(e.floor,`edit-wall`,[e.result.nodeId]),R({type:`node`,id:e.result.nodeId}))},[q,Z,N,X,R]),Sr=m((e,t,n=new Set)=>{if(e.type===`wall`)return{floor:oe(t,e.id).floor};if(e.type===`opening`)return{floor:ae(t,e.id).floor};if(e.type===`node`){let n=ne(t,e.id,{force:!0});if(n.result)return{floor:n.floor,reselect:{type:`wall`,id:n.result.wallId}};let r=t;for(let n of Object.values(t.walls))(n.a===e.id||n.b===e.id)&&(r=oe(r,n.id,{dissolveCollinear:!1}).floor);return{floor:r}}let r=P.find(t=>t.roomId===e.id);if(!r)return{floor:t};let i=new Set;for(let t of P)if(t.roomId!==e.id&&!(t.roomId&&n.has(t.roomId)))for(let e of t.wallIds)i.add(e);let a=t;for(let e of new Set(r.wallIds))i.has(e)||(a=oe(a,e,{dissolveCollinear:!1}).floor);let o={...a.rooms};return delete o[e.id],{floor:{...a,rooms:o}}},[P]),Cr=m(()=>{let e=L.current;if(!q||e.length===0)return;let t={room:0,opening:1,wall:2,node:3},n=[...e].sort((e,n)=>t[e.type]-t[n.type]),r=new Set(n.filter(e=>e.type===`room`).map(e=>e.id)),i=N,a;for(let e of n){let t=Sr(e,i,r);i=t.floor,n.length===1&&(a=t.reselect)}i!==N&&(X(i,`delete`,n.map(e=>e.id)),R(a??null))},[q,N,Sr,X,R]),wr=m(()=>{Jn(e=>e.length===0?e:[]),rr(null)},[]);h(()=>{wr()},[F,wr]);let Tr=m(e=>{if(w)return;if(_n.current?.focus(),dr(null),xn.current.set(e.pointerId,{x:e.clientX,y:e.clientY}),e.currentTarget.setPointerCapture?.(e.pointerId),xn.current.size===2){let[e,t]=[...xn.current.values()];A.current.kind!==`none`&&A.current.kind!==`pan`&&j.cancelGesture(),A.current={kind:`pinch`,startDist:Math.hypot(t.x-e.x,t.y-e.y),startView:B,startMid:{x:(e.x+t.x)/2,y:(e.y+t.y)/2}};return}if(xn.current.size>2)return;if(Sn.current={client:{x:e.clientX,y:e.clientY},moved:!1},e.button===1||Cn.current){A.current={kind:`pan`,startClient:{x:e.clientX,y:e.clientY},startView:B};return}if(e.button!==0)return;let t=pr(e.clientX,e.clientY);if(!q){let e=Ee(N,P,t,d(k,B.zoom));R(e);return}if(F===`rect`){let e=Y(t).point;A.current={kind:`rect`,start:e,current:e},j.beginGesture();return}if(F===`measure`){let e=lr(t);if(e){let n=K.find(t=>t.id===e.id);A.current=e.end?{kind:`measureEnd`,id:e.id,end:e.end}:{kind:`measureMove`,id:e.id,startWorld:t,origA:n.a,origB:n.b};return}let n=Y(t).point;A.current={kind:`measure`,start:n,current:n};return}if(F===`wall`){let e=U[U.length-1],n=Y(t,e,void 0,fr).point;if(U.length===0){Jn([n]);return}let r=U[U.length-1],i=u(N,r,n,{thickness:Gt,type:o.Interior,height:Kt},d(k,B.zoom).node);i.result.wallIds.length>0&&X(i.floor,`draw-wall`,i.result.wallIds),U.length>=2&&Math.hypot(n.x-U[0].x,n.y-U[0].y)<d(k,B.zoom).node?wr():Jn(e=>[...e,n]);return}let n=lt[F];if(n){let e=d(k,B.zoom),r=Ee(N,P,t,e,{accept:[`wall`]});if(r?.type!==`wall`)return;let i=N.walls[r.id],a=N.nodes[i.a],o=N.nodes[i.b],s=Math.hypot(o.x-a.x,o.y-a.y),c=((t.x-a.x)*(o.x-a.x)+(t.y-a.y)*(o.y-a.y))/(s*s||1),ee={...dt[n],...qt?.[n]},u=l(N,{wallId:i.id,kind:n,offset:Math.min(Math.max(c,0),1)*s,width:ee.width,sill:ee.sill,head:ee.head});u.result.openingId&&(X(u.floor,`add-opening`,[u.result.openingId]),R({type:`opening`,id:u.result.openingId}));return}let r=d(k,B.zoom);if(br&&z?.type===`wall`&&Math.hypot(t.x-br.x,t.y-br.y)<=r.node){j.beginGesture(),A.current={kind:`wallSplit`,wallId:z.id,at:br};return}let i=Ee(N,P,t,r),a=Mt&&(e.ctrlKey||e.metaKey);if(!i){a||R(null),A.current=Mt?{kind:`marquee`,start:t,current:t,additive:a,base:L.current}:{kind:`none`};return}if((e.ctrlKey||e.metaKey)&&i.type===`wall`&&N.walls[i.id]){let e=N.walls[i.id];a||R(i),j.beginGesture(),A.current={kind:`wall`,wallId:i.id,startWorld:t,origA:{...N.nodes[e.a]},origB:{...N.nodes[e.b]},moved:!1,detach:!0,toggle:a};return}if(a){Bn(i),A.current={kind:`none`};return}if(L.current.some(e=>e.type===i.type&&e.id===i.id)||R(i),j.beginGesture(),L.current.length>1){let e=[...Vn(L.current)],n={};for(let t of e){let e=N.nodes[t];e&&(n[t]={x:e.x,y:e.y})}A.current={kind:`room`,nodeIds:e,startWorld:t,orig:n,moved:!1};return}if(i.type===`node`)A.current={kind:`node`,nodeId:i.id,moved:!1,...mr(i.id)};else if(i.type===`wall`){let e=N.walls[i.id];A.current={kind:`wall`,wallId:i.id,startWorld:t,origA:{...N.nodes[e.a]},origB:{...N.nodes[e.b]},moved:!1}}else if(i.type===`opening`)A.current={kind:`opening`,openingId:i.id,moved:!1};else{let e=P.find(e=>e.roomId===i.id),n=e?[...new Set(e.nodeIds)]:[],r={};for(let e of n){let t=N.nodes[e];t&&(r[e]={x:t.x,y:t.y})}A.current={kind:`room`,nodeIds:n,startWorld:t,orig:r,moved:!1}}},[w,q,B,F,N,P,k,pr,Y,U,Gt,Kt,qt,X,R,br,z,fr,mr,Vn,Mt,Bn,j,wr,lr,K]),Er=m(e=>{if(w)return;xn.current.has(e.pointerId)&&xn.current.set(e.pointerId,{x:e.clientX,y:e.clientY});let t=A.current;if(t.kind===`pinch`&&xn.current.size>=2){let[e,n]=[...xn.current.values()],r=Math.hypot(n.x-e.x,n.y-e.y);if(t.startDist<=0)return;let i=Math.max(Lt,Math.min(Rt,t.startView.zoom*(r/t.startDist))),a=vn.current?.getBoundingClientRect()??{left:0,top:0},o={x:(e.x+n.x)/2,y:(e.y+n.y)/2},s=Oe(t.startMid.x,t.startMid.y,a,t.startView);V({x:s.x-(o.x-a.left)/i,y:s.y-(o.y-a.top)/i,zoom:i});return}if(Sn.current){let t=e.clientX-Sn.current.client.x,n=e.clientY-Sn.current.client.y;Math.hypot(t,n)>pt&&(Sn.current.moved=!0)}if(t.kind===`pan`){V({x:t.startView.x-(e.clientX-t.startClient.x)/t.startView.zoom,y:t.startView.y-(e.clientY-t.startClient.y)/t.startView.zoom,zoom:t.startView.zoom});return}let n=pr(e.clientX,e.clientY);if(Yn(n),t.kind===`none`){if(!q)return;if(F===`wall`&&U.length>0){let e=Y(n,U[U.length-1],void 0,fr);Yn(e.point),rr(e);return}if(F===`select`){let e=Ee(N,P,n,d(k,B.zoom));De(e,Un)||(Wn(e),Nt?.(e))}F===`measure`&&sr(lr(n)?.id??null);return}if(Sn.current?.moved){if(t.kind===`measureEnd`){let e=Y(n).point;ir(n=>n.map(n=>n.id===t.id?{...n,[t.end]:e}:n)),Yn(e);return}if(t.kind===`measureMove`){let e=n.x-t.startWorld.x,r=n.y-t.startWorld.y;ir(n=>n.map(n=>n.id===t.id?{...n,a:{x:t.origA.x+e,y:t.origA.y+r},b:{x:t.origB.x+e,y:t.origB.y+r}}:n));return}if(t.kind===`rect`||t.kind===`measure`){A.current={...t,current:Y(n).point},Yn(Y(n).point);return}if(t.kind===`marquee`){A.current={...t,current:n},Yn(n);return}if(t.kind===`wallSplit`){let e=se(N,t.wallId,t.at);if(!e.result.wallIds){A.current={kind:`none`};return}let r=e.result.nodeId,i=N.walls[t.wallId],a=i?e.floor.nodes[i.a]:void 0,o=i?e.floor.nodes[i.b]:void 0,s={origin:a?{x:a.x,y:a.y}:void 0,referenceAngle:a&&o?Math.atan2(o.y-a.y,o.x-a.x):void 0,excludeWallIds:new Set(e.result.wallIds)},c=Y(n,s.origin,new Set([r]),s.referenceAngle,s.excludeWallIds).point;A.current={kind:`node`,nodeId:r,moved:!0,...s},R({type:`node`,id:r}),rr(nr.current),_r(ie(e.floor,r,c).floor,`move-node`,!1,[r]);return}if(t.kind===`node`){let e=Y(n,t.origin,new Set([t.nodeId]),t.referenceAngle,t.excludeWallIds).point;rr(nr.current),A.current={...t,moved:!0},_r(ie(N,t.nodeId,e).floor,`move-node`,!1,[t.nodeId]);return}if(t.kind===`wall`){let e=N.walls[t.wallId];if(!e)return;let r=t.origB.x-t.origA.x,i=t.origB.y-t.origA.y,a=Math.hypot(r,i);if(a<1e-6)return;let o={x:-i/a,y:r/a},s=(n.x-t.startWorld.x)*o.x+(n.y-t.startWorld.y)*o.y,c=Vt!==wn.current&&C>0?C:1,l=Math.round(s/c)*c,ee=Math.max(c,10);if(t.detach){if(Math.abs(l)<ee)return;let e=te(N,t.wallId,{x:o.x*l,y:o.y*l});if(!e.result)return;A.current={...t,detach:!1,toggle:!1,detachedSign:Math.sign(l),moved:!0},R({type:`wall`,id:t.wallId}),_r(e.floor,`move-wall`,!1,[t.wallId]);return}let u=ie(N,e.a,{x:t.origA.x+o.x*l,y:t.origA.y+o.y*l}).floor;u=ie(u,e.b,{x:t.origB.x+o.x*l,y:t.origB.y+o.y*l}).floor,t.detachedSign&&Math.abs(l)<10?(u=le(u).floor,A.current={...t,detachedSign:void 0,moved:!0}):A.current={...t,moved:!0},_r(u,`move-wall`,!1,[t.wallId]);return}if(t.kind===`opening`){let e=N.openings[t.openingId];if(!e)return;let r=N.walls[e.wallId],i=N.nodes[r.a],a=N.nodes[r.b],o=Math.hypot(a.x-i.x,a.y-i.y),s=((n.x-i.x)*(a.x-i.x)+(n.y-i.y)*(a.y-i.y))/(o*o||1);A.current={...t,moved:!0},_r(ce(N,t.openingId,{offset:Math.min(Math.max(s,0),1)*o}).floor,`move-opening`,!1,[t.openingId]);return}if(t.kind===`room`){let e=n.x-t.startWorld.x,r=n.y-t.startWorld.y,i=Vt!==wn.current&&C>0?C:1,a=Math.round(e/i)*i,o=Math.round(r/i)*i,s=N;for(let e of t.nodeIds){let n=t.orig[e];n&&(s=ie(s,e,{x:n.x+a,y:n.y+o}).floor)}A.current={...t,moved:!0},_r(s,`move-room`,!1,t.nodeIds)}}},[w,q,F,N,P,Un,k,B.zoom,Lt,Rt,C,Vt,pr,Y,_r,V,R,U,fr,Nt,lr]),Dr=m((e,t)=>{xn.current.delete(e.pointerId);let n=A.current;A.current={kind:`none`};let r=Sn.current?.moved??!1;if(Sn.current=null,rr(null),n.kind===`none`||n.kind===`pan`||n.kind===`pinch`)return;if(n.kind===`marquee`){if(t||!r){t&&R([...n.base]);return}let e=Math.min(n.start.x,n.current.x),i=Math.max(n.start.x,n.current.x),a=Math.min(n.start.y,n.current.y),o=Math.max(n.start.y,n.current.y),s=[];for(let t of Object.values(N.nodes))t.x>=e&&t.x<=i&&t.y>=a&&t.y<=o&&s.push({type:`node`,id:t.id});if(n.additive){let e=new Set(n.base.map(e=>`${e.type}:${e.id}`));R([...n.base,...s.filter(t=>!e.has(`${t.type}:${t.id}`))])}else R(s);return}if(t){let e=j.cancelGesture();e&&S?.(e,{reason:`external`,committed:!1,targetIds:[]});return}if(n.kind===`measureEnd`||n.kind===`measureMove`)return;if(n.kind===`measure`){let e=Math.hypot(n.current.x-n.start.x,n.current.y-n.start.y);r&&e>ft&&(ar.current+=1,ir(e=>[...e,{id:ar.current,a:n.start,b:n.current}]));return}if(n.kind===`rect`){if(!r){j.cancelGesture();return}let e=ee(N,n.start,n.current,{thickness:Gt,type:o.Interior,height:Kt},d(k,B.zoom).node);if(e.result.wallIds.length===0){j.cancelGesture();return}let t=j.endGesture();X(e.floor,`draw-rect`,e.result.wallIds,{push:!t});return}if(!r){j.cancelGesture(),n.kind===`wall`&&n.toggle&&Bn({type:`wall`,id:n.wallId});return}if(n.kind===`node`){let e=N.nodes[n.nodeId];if(e){let t=d(k,B.zoom).node,r=Object.values(N.nodes).find(r=>r.id!==n.nodeId&&Math.hypot(r.x-e.x,r.y-e.y)<=t);if(r){let e=j.endGesture();X(re(N,r.id,n.nodeId).floor,`move-node`,[r.id],{push:!e}),R({type:`node`,id:r.id});return}}}let i=j.endGesture(),a=n.kind===`wall`?`move-wall`:n.kind===`opening`?`move-opening`:n.kind===`room`?`move-room`:`move-node`;X(N,a,[],{push:!i})},[N,j,k,B.zoom,Gt,Kt,X,R,Bn,S]);h(()=>{let e=vn.current;if(!e||w)return;function t(t){t.preventDefault();let n=e.getBoundingClientRect(),r=Math.exp(-t.deltaY*.002);V((()=>{let e=Or.current,i=Math.max(Lt,Math.min(Rt,e.zoom*r)),a=Oe(t.clientX,t.clientY,n,e);return{x:a.x-(t.clientX-n.left)/i,y:a.y-(t.clientY-n.top)/i,zoom:i}})())}return e.addEventListener(`wheel`,t,{passive:!1}),()=>e.removeEventListener(`wheel`,t)},[w,Lt,Rt,V]);let Or=g(B);Or.current=B;let kr=m(e=>{let t=Math.max(Lt,Math.min(Rt,B.zoom*e)),n={x:B.x+H.width/2/B.zoom,y:B.y+H.height/2/B.zoom};V({x:n.x-H.width/2/t,y:n.y-H.height/2/t,zoom:t})},[B,H,Lt,Rt,V]),Ar=m(()=>{if(an===`none`)return;let e=j.undo();e&&(bn.current=e,S?.(e,{reason:`undo`,committed:!0,targetIds:[]}),yt?.(e,{reason:`undo`,committed:!0,targetIds:[]}))},[an,j,S,yt]),jr=m(()=>{if(an===`none`)return;let e=j.redo();e&&(bn.current=e,S?.(e,{reason:`redo`,committed:!0,targetIds:[]}),yt?.(e,{reason:`redo`,committed:!0,targetIds:[]}))},[an,j,S,yt]),Mr=m(()=>{let e=P.filter(e=>e.roomId).map(e=>({type:`room`,id:e.roomId}));if(e.length>0){R(e);return}R(Object.keys(N.nodes).map(e=>({type:`node`,id:e})))},[P,N.nodes,R]),Nr=m((e,t)=>{if(!q||Hn.size===0)return;let n=C>0?C:100,r=Tn.current?n*10:n,i=N;for(let n of Hn){let a=i.nodes[n];a&&(i=ie(i,n,{x:a.x+e*r,y:a.y+t*r}).floor)}X(i,`nudge`,[...Hn])},[q,Hn,N,C,X]),Pr=m(e=>{if(w)return;let t=e.target;if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){e.key===`Escape`&&t.blur();return}if(e.key===`Shift`&&(Tn.current=!0),e.key===`Alt`&&(wn.current=!0),e.key===` `&&!Cn.current){Cn.current=!0,e.preventDefault();return}let n=e.metaKey||e.ctrlKey;if(n&&e.key.toLowerCase()===`z`){e.preventDefault(),e.shiftKey?jr():Ar();return}if(n&&e.key.toLowerCase()===`a`){e.preventDefault(),Mt&&Mr();return}if(n&&e.key.toLowerCase()===`y`){e.preventDefault(),jr();return}if(e.key===`Escape`){U.length>0?wr():K.length>0?ir([]):R(null);return}if(e.key===`Enter`&&F===`wall`){wr();return}if(e.key===`Delete`||e.key===`Backspace`){if(e.preventDefault(),F===`measure`){or!==null&&(ir(e=>e.filter(e=>e.id!==or)),sr(null));return}Cr();return}if(e.key===`+`||e.key===`=`){kr(1.25);return}if(e.key===`-`){kr(1/1.25);return}if(e.key===`0`){hr();return}if(e.key.startsWith(`Arrow`)){e.preventDefault();let t={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[e.key];t&&Nr(t[0],t[1]);return}let r=e.key.toLowerCase();if(r===`s`){Zn(e=>!e);return}if(r===`l`){$n(e=>!e);return}if(r===`g`){tr(e=>!e);return}let i=ct[e.key.toLowerCase()];i&&q&&Ot.includes(i)&&(Ln(i),wr())},[w,q,Ot,F,U,K.length,or,jr,Ar,R,wr,Cr,kr,hr,Nr,Ln,Mt,Mr]),Q=m((e,t,n)=>{bn.current=e,n?.resetHistory?(j.clearHistory(),j.replace(e)):j.commit(e,t);let r={reason:t,committed:!0,targetIds:[]};S?.(e,r),yt?.(e,r)},[j,S,yt]),Fr=m((e={})=>{let{plan:t,floor:n}=ue(M,{...e,index:he(M,N.id)+1});return Q(t,`add-floor`),Pn(n.id),n.id},[M,N.id,Q,Pn]),Ir=m(()=>{let{plan:e,floor:t}=de(M,N.id);return t?(Q(e,`duplicate-floor`),Pn(t.id),t.id):null},[M,N.id,Q,Pn]),Lr=m(e=>{let t=e??N.id,n=ve(M,t);if(n!==M&&(Q(n,`remove-floor`),t===N.id)){let e=he(M,t);Pn(n.floors[Math.max(0,e-1)].id)}},[M,N.id,Q,Pn]),Rr=m((e,t)=>{let n=_e(M,e,t);n!==M&&Q(n,`move-floor`)},[M,Q]),zr=m((e,t)=>{let n=xe(M,e,t);n!==M&&Q(n,`edit-floor`)},[M,Q]),Br=m((e,t)=>{let n=ye(M,e,t);n!==M&&Q(n,`rename-floor`)},[M,Q]),Vr=m(e=>{let t=(e??nn??M.name??``).trim()||`floor-plan`,n=URL.createObjectURL(new Blob([je(M)],{type:`application/json`})),r=document.createElement(`a`);r.href=n,r.download=t.endsWith(`.json`)?t:`${t}.json`,r.click(),setTimeout(()=>URL.revokeObjectURL(n),0)},[nn,M]),Hr=m(e=>{let t=Ae(e);return t.plan&&Q(t.plan,`import`),dr(t.plan&&t.issues.length===0?null:t.issues),rn?.(t),t},[rn,Q]),Ur=m(e=>{e.text().then(e=>Hr(e)).catch(e=>{let t=[`Could not read that file: ${e.message}`];dr(t),rn?.({plan:null,issues:t})})},[Hr,rn]),Wr=m(()=>ir([]),[]),Gr=m(e=>{e.key===`Shift`&&(Tn.current=!1),e.key===`Alt`&&(wn.current=!1),e.key===` `&&(Cn.current=!1)},[]);Ie(Fe,()=>({getPlan:()=>M,setPlan:(e,t)=>Q(e,`import`,t),clear:()=>Q(fe(),`clear`),getFloorId:()=>N.id,setFloorId:Pn,addFloor:e=>Fr(e),duplicateFloor:Ir,removeFloor:Lr,renameFloor:Br,moveFloor:Rr,setFloorHeight:zr,clearMeasurements:Wr,download:Vr,loadJson:Hr,undo:Ar,redo:jr,canUndo:()=>an!==`none`&&j.canUndo,canRedo:()=>an!==`none`&&j.canRedo,clearHistory:j.clearHistory,getSelection:()=>[...L.current],select:R,addToSelection:e=>{let t=Array.isArray(e)?e:[e],n=new Set(L.current.map(e=>`${e.type}:${e.id}`));R([...L.current,...t.filter(e=>!n.has(`${e.type}:${e.id}`))])},toggleSelection:Bn,selectAll:Mr,deleteSelection:Cr,getView:()=>B,setView:V,zoomBy:kr,fitToContent:hr,toWorld:pr,toScreen:J,getSvgElement:()=>yn.current}),[M,j,Q,N,Pn,Fr,Ir,Lr,Br,Rr,zr,Wr,Vr,Hr,Ar,jr,an,R,Bn,Mr,Cr,B,V,kr,hr,pr,J]);let $=A.current,Kr=Le(()=>{if(!q)return null;let e=[],t=[...K,...$.kind===`measure`?[{id:-1,a:$.start,b:$.current}]:[]];for(let n of t){let t=J(n.a),r=J(n.b),i=Math.hypot(n.b.x-n.a.x,n.b.y-n.a.y);if(i<ft)continue;let a=Math.atan2(n.b.y-n.a.y,n.b.x-n.a.x),o=-Math.sin(a)*5,s=Math.cos(a)*5,c={x:(t.x+r.x)/2,y:(t.y+r.y)/2};if(e.push(b(`g`,{className:v(p.roomDrawerMeasureLine,or===n.id&&p.roomDrawerMeasureLineHovered,D?.measureLine),children:[y(`line`,{x1:t.x,y1:t.y,x2:r.x,y2:r.y}),y(`line`,{x1:t.x-o,y1:t.y-s,x2:t.x+o,y2:t.y+s}),y(`line`,{x1:r.x-o,y1:r.y-s,x2:r.x+o,y2:r.y+s})]},`measure-${n.id}`)),F===`measure`&&n.id>=0)for(let[i,a]of[[`a`,t],[`b`,r]])e.push(y(`circle`,{className:p.roomDrawerMeasureGrip,cx:a.x,cy:a.y,r:4},`measure-grip-${n.id}-${i}`));e.push(y(`text`,{className:v(p.roomDrawerMeasure,D?.measureLine),x:c.x,y:c.y-8,textAnchor:`middle`,children:`${Yt(i)} · ${_t(a)}`},`measure-label-${n.id}`))}if(Wt&&G&&(G.guides.forEach((t,n)=>{let r=J(t.a),i=J(t.b);e.push(y(`line`,{className:v(p.roomDrawerGuide,t.kind===f.Angle&&p.roomDrawerGuideAngle),x1:r.x,y1:r.y,x2:i.x,y2:i.y},`guide-${n}`))}),G.kind!==f.None&&G.kind!==f.Grid)){let t=J(G.point);e.push(y(`rect`,{className:p.roomDrawerSnapMarker,x:t.x-4,y:t.y-4,width:8,height:8},`snap-marker`))}if($.kind===`rect`){let t=J($.start),n=J($.current),r=Math.min(t.x,n.x),i=Math.min(t.y,n.y),a=Math.max(t.x,n.x),o=Math.max(t.y,n.y);e.push(y(`rect`,{className:p.roomDrawerPreview,x:r,y:i,width:a-r,height:o-i},`rect-preview`));let s=Math.abs($.current.x-$.start.x),c=Math.abs($.current.y-$.start.y);Jt&&(s>0||c>0)&&(e.push(y(`text`,{className:p.roomDrawerMeasure,x:(r+a)/2,y:i-8,textAnchor:`middle`,children:Yt(s)},`rect-width`),y(`text`,{className:p.roomDrawerMeasure,x:r-8,y:(i+o)/2,textAnchor:`end`,dominantBaseline:`central`,children:Yt(c)},`rect-height`)),s>0&&c>0&&e.push(y(`text`,{className:v(p.roomDrawerMeasure,p.roomDrawerMeasureSecondary),x:(r+a)/2,y:(i+o)/2,textAnchor:`middle`,dominantBaseline:`central`,children:Xt(s*c)},`rect-area`)))}if(F===`wall`&&U.length>0){let t=[...U,W].filter(Boolean).map(J);if(e.push(y(`polyline`,{className:p.roomDrawerPreview,points:t.map(e=>`${e.x},${e.y}`).join(` `),fill:`none`},`chain`)),t.forEach((t,n)=>{e.push(y(`circle`,{className:p.roomDrawerHandle,cx:t.x,cy:t.y,r:4},`chain-dot-${n}`))}),Jt&&W&&U.length>0){let t=U[U.length-1],n=Math.hypot(W.x-t.x,W.y-t.y),r=J({x:(t.x+W.x)/2,y:(t.y+W.y)/2}),i=G?.kind===f.Angle;e.push(y(`text`,{className:v(p.roomDrawerMeasure,i&&p.roomDrawerMeasureLocked),x:r.x,y:r.y-8,textAnchor:`middle`,children:`${Yt(n)} · ${_t(G?.angleRelativeTo===`reference`&&fr!==void 0?Math.atan2(W.y-t.y,W.x-t.x)-fr:Math.atan2(W.y-t.y,W.x-t.x))}${G?.angleRelativeTo===`reference`?` rel`:``}`},`chain-len`))}}let n=new Set(I.filter(e=>e.type===`node`).map(e=>e.id));for(let t of Hn){let r=N.nodes[t];if(!r)continue;let i=J(r);e.push(y(`circle`,{className:v(p.roomDrawerHandle,n.has(t)&&p.roomDrawerHandleActive),cx:i.x,cy:i.y,r:5},`handle-${t}`))}if($.kind===`marquee`&&Sn.current?.moved){let t=J($.start),n=J($.current);e.push(y(`rect`,{className:p.roomDrawerMarquee,x:Math.min(t.x,n.x),y:Math.min(t.y,n.y),width:Math.abs(n.x-t.x),height:Math.abs(n.y-t.y)},`marquee`))}if(br&&$.kind!==`node`){let t=J(br);e.push(y(`circle`,{className:p.roomDrawerMidHandle,cx:t.x,cy:t.y,r:4},`midpoint`))}if(Jt&&$.kind===`room`&&$.moved){let t=new Set($.nodeIds),n=$.nodeIds.find(e=>N.nodes[e]&&$.orig[e]);if(n){let t=N.nodes[n],r=$.orig[n],i=t.x-r.x,a=t.y-r.y,o=z?.type===`room`?P.find(e=>e.roomId===z.id):void 0,s=J(o?o.anchor:t);e.push(y(`text`,{className:v(p.roomDrawerMeasure,p.roomDrawerMeasureOffset),x:s.x,y:s.y-26,textAnchor:`middle`,children:`${Yt(Math.hypot(i,a))} · ${_t(Math.atan2(a,i))}`},`room-offset`))}for(let n of Object.values(N.walls)){if(t.has(n.a)===t.has(n.b))continue;let r=N.nodes[n.a],i=N.nodes[n.b];if(!r||!i)continue;let a=t.has(n.a)?r:i,o=t.has(n.a)?i:r,s=J({x:(r.x+i.x)/2,y:(r.y+i.y)/2});e.push(y(`text`,{className:v(p.roomDrawerMeasure,p.roomDrawerMeasureSecondary),x:s.x,y:s.y-8,textAnchor:`middle`,children:`${Yt(Math.hypot(o.x-a.x,o.y-a.y))} · ${_t(Math.atan2(o.y-a.y,o.x-a.x))}`},`room-stretch-${n.id}`))}}if(Jt&&(z?.type===`node`||z?.type===`wall`)){let t=[],n=new Set,r=(e,r,i)=>{if(n.has(e))return;let a=N.walls[e];a&&(n.add(e),t.push({wall:a,from:r,primary:i}))};if(z.type===`node`)for(let e of Object.values(N.walls))(e.a===z.id||e.b===z.id)&&r(e.id,z.id,!0);else{let e=N.walls[z.id];if(e){r(e.id,e.a,!0);for(let t of Object.values(N.walls))if(t.id!==e.id)for(let n of[e.a,e.b])(t.a===n||t.b===n)&&r(t.id,n,!1)}}let i=G?.kind===f.Angle&&$.kind!==`none`;for(let{wall:n,from:r,primary:a}of t){let t=N.nodes[n.a],o=N.nodes[n.b];if(!t||!o)continue;let s=n.a===r?t:o,c=n.a===r?o:t,l=J({x:(t.x+o.x)/2,y:(t.y+o.y)/2});e.push(y(`text`,{className:v(p.roomDrawerMeasure,!a&&p.roomDrawerMeasureSecondary,a&&i&&p.roomDrawerMeasureLocked),x:l.x,y:l.y-8,textAnchor:`middle`,children:`${Yt(Math.hypot(c.x-s.x,c.y-s.y))} · ${_t(Math.atan2(c.y-s.y,c.x-s.x))}`},`measure-${n.id}`))}}return y(ot,{children:e})},[q,$,F,U,W,I,N,P,z,Hn,br,Jt,Wt,G,fr,Yt,Xt,K,or,D?.measureLine,J]),qr={select:{icon:Be,label:T?.select??`Select and edit`,key:`V`},wall:{icon:$e,label:T?.wall??`Draw walls`,key:`W`},rect:{icon:nt,label:T?.rect??`Draw a room`,key:`R`},door:{icon:Ge,label:T?.door??`Add a door`,key:`D`},window:{icon:at,label:T?.window??`Add a window`,key:`N`},archway:{icon:Je,label:T?.archway??`Add an archway`,key:`A`},measure:{icon:tt,label:T?.measure??`Measure`,key:`M`}},Jr=q?F===`wall`?T?.hintWall??`Click to place corners · Shift for a fixed angle, L to latch it · Click the first corner or press Enter to close`:F===`rect`?T?.hintRect??`Drag to draw a room`:F===`measure`?T?.hintMeasure??`Drag to measure · Drag an end or the line to adjust it · Delete removes one, Escape clears them`:lt[F]?T?.hintOpening??`Click a wall to cut an opening into it`:T?.hintSelect??(Mt?`Drag a corner to reshape · Drag a wall to push it, and the room next door moves with it · Ctrl-click or drag a box to select several · Delete to remove`:`Drag a corner to reshape · Drag a wall to push it, and the room next door moves with it · Drag the dot on a selected wall to add a corner · Delete to remove`):``,Yr=I.length===0?T?.selectedFloor??`Floor`:I.length>1?(T?.selectedCount??`{count} selected`).replace(`{count}`,String(I.length)):yr?T?.selectedOpening??ut[yr.kind]:Z?T?.selectedWall??`Wall`:z?.type===`room`?T?.selectedRoom??`Room`:T?.selectedCorner??`Corner`,Xr=q?Ot:[];return b(`div`,{...hn,ref:_n,className:v(p.roomDrawer,w&&p.roomDrawerDisabled,pn,D?.root),style:{...mn,...O?.root},role:`application`,"aria-label":fn??`Floor plan editor`,tabIndex:w?-1:0,onKeyDown:Pr,onKeyUp:Gr,children:[Zt&&b(`div`,{className:v(p.roomDrawerToolbar,D?.toolbar),style:O?.toolbar,role:`toolbar`,"aria-label":`Drawing tools`,children:[Xr.map(e=>{let n=qr[e];return y(`button`,{type:`button`,className:v(p.roomDrawerToolButton,e===F&&p.roomDrawerToolButtonActive,D?.toolButton),style:O?.toolButton,title:`${n.label} (${n.key})`,"aria-label":n.label,"aria-pressed":e===F,onClick:()=>{Ln(e),wr()},children:t(E?.[e]??n.icon,{className:v(p.roomDrawerToolIcon,D?.toolIcon),style:O?.toolIcon})},e)}),Xr.length>0&&y(`span`,{className:p.roomDrawerToolbarSeparator}),q&&b(ot,{children:[[{on:Xn,toggle:()=>Zn(e=>!e),icon:E?.snap??Xe,label:T?.snap??`Snap to grid and geometry`,key:`S`},{on:Qn,toggle:()=>$n(e=>!e),icon:E?.angleLock??qe,label:T?.angleLock??`Lock to ${Ut}° angles`,key:`L`},{on:er,toggle:()=>tr(e=>!e),icon:E?.grid??Ue,label:T?.grid??`Show grid`,key:`G`},...pe(M,N.id)?[{on:jn,toggle:()=>Mn(e=>!e),icon:E?.underlay??Ye,label:T?.underlay??`Show the floor below`,key:`B`}]:[]].map(e=>y(`button`,{type:`button`,className:v(p.roomDrawerToolButton,e.on&&p.roomDrawerToolButtonOn,D?.toolButton),style:O?.toolButton,title:`${e.label} (${e.key})`,"aria-label":e.label,"aria-pressed":e.on,onClick:e.toggle,children:t(e.icon,{className:v(p.roomDrawerToolIcon,D?.toolIcon),style:O?.toolIcon})},e.key)),y(`span`,{className:p.roomDrawerToolbarSeparator})]}),en&&an!==`none`&&q&&b(ot,{children:[y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.undo??`Undo`,"aria-label":T?.undo??`Undo`,disabled:!j.canUndo,onClick:Ar,children:t(E?.undo??Ve)}),y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.redo??`Redo`,"aria-label":T?.redo??`Redo`,disabled:!j.canRedo,onClick:jr,children:t(E?.redo??He)}),y(`span`,{className:p.roomDrawerToolbarSeparator})]}),tn&&b(ot,{children:[y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.download??`Download plan`,"aria-label":T?.download??`Download plan`,onClick:()=>Vr(),children:t(E?.download??Ke)}),q&&y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.upload??`Open a plan file`,"aria-label":T?.upload??`Open a plan file`,onClick:()=>cr.current?.click(),children:t(E?.upload??it)}),y(`span`,{className:p.roomDrawerToolbarSeparator})]}),b(`div`,{className:v(p.roomDrawerViewControls,D?.viewControls),style:O?.viewControls,children:[y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.zoomOut??`Zoom out`,"aria-label":T?.zoomOut??`Zoom out`,onClick:()=>kr(1/1.25),children:t(E?.zoomOut??Ze)}),b(`button`,{type:`button`,className:v(p.roomDrawerZoomLabel,D?.zoomLabel),style:O?.zoomLabel,title:T?.fit??`Fit to content`,onClick:()=>hr(),children:[Math.round(B.zoom*1e3)/10,`%`]}),y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.zoomIn??`Zoom in`,"aria-label":T?.zoomIn??`Zoom in`,onClick:()=>kr(1.25),children:t(E?.zoomIn??Qe)})]})]}),Ct&&M.floors.length>0&&b(`div`,{className:v(p.roomDrawerFloorBar,D?.floorBar),style:O?.floorBar,role:`tablist`,"aria-label":T?.selectedFloor??`Floor`,children:[[...M.floors].reverse().map(e=>y(`button`,{type:`button`,role:`tab`,className:v(p.roomDrawerFloorTab,e.id===N.id&&p.roomDrawerFloorTabActive,D?.floorTab),style:O?.floorTab,"aria-selected":e.id===N.id,onClick:()=>Pn(e.id),children:e.label},e.id)),q&&y(`button`,{type:`button`,className:v(p.roomDrawerFloorTab,p.roomDrawerFloorTabAdd),title:T?.addFloor??`Add a floor above`,"aria-label":T?.addFloor??`Add a floor above`,onClick:()=>Fr(),children:t(E?.addFloor??et)})]}),y(`div`,{ref:vn,className:v(p.roomDrawerCanvasWrapper,q&&F!==`select`&&p.roomDrawerCanvasWrapperDrawing,D?.canvasWrapper),style:{height:ln,...O?.canvasWrapper},onPointerDown:Tr,onPointerMove:Er,onPointerUp:e=>Dr(e,!1),onPointerCancel:e=>Dr(e,!0),children:y(Ne,{ref:yn,floor:N,underlay:Nn,rooms:P,view:B,size:H,selection:I,hovered:Un,interactiveRooms:!1,showGrid:er,gridSize:C,showRoomLabels:!0,formatArea:Xt,getRoomColor:un,renderRoomLabel:dn,overlay:Kr,classNames:D,styles:O})}),Qt&&q&&b(`div`,{className:v(p.roomDrawerInspector,D?.inspector),style:O?.inspector,children:[y(`span`,{className:v(p.roomDrawerInspectorKind,I.length===0&&p.roomDrawerInspectorKindEmpty,D?.inspectorLabel),children:Yr}),I.length===0&&b(ot,{children:[y(i,{className:v(p.roomDrawerInspectorName,D?.inspectorField),style:O?.inspectorField,label:T?.floorName??`Floor name`,value:N.label,onChange:e=>Br(N.id,e)}),y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.floorHeight??`Height (mm)`,title:`Storey height. The floors above move to sit on top of it.`,value:N.height,decimalScale:0,min:500,step:100,showArrows:!0,onChange:e=>{e!==void 0&&zr(N.id,e)}}),M.floors.length>1&&b(ot,{children:[y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,title:T?.moveFloorUp??`Move this floor up`,"aria-label":T?.moveFloorUp??`Move this floor up`,disabled:he(M,N.id)>=M.floors.length-1,onClick:()=>Rr(N.id,he(M,N.id)+1),children:t(E?.moveFloorUp??ze)}),y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,title:T?.moveFloorDown??`Move this floor down`,"aria-label":T?.moveFloorDown??`Move this floor down`,disabled:he(M,N.id)<=0,onClick:()=>Rr(N.id,he(M,N.id)-1),children:t(E?.moveFloorDown??Re)})]}),y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,title:T?.duplicateFloor??`Copy this floor to a new one above`,onClick:()=>Ir(),children:t(E?.duplicateFloor??We)}),M.floors.length>1&&y(n,{className:p.roomDrawerInspectorDelete,icon:E?.delete??rt,title:T?.deleteFloor??`Delete this floor`,onClick:()=>Lr()})]}),vr?.meta&&b(ot,{children:[y(i,{className:v(p.roomDrawerInspectorName,D?.inspectorField),style:O?.inspectorField,label:T?.roomName??`Room name`,value:vr.meta.name,onChange:e=>{let t=vr.meta;X({...N,rooms:{...N.rooms,[t.id]:{...t,name:e}}},`edit-room`,[t.id])}}),y(`span`,{className:v(p.roomDrawerInspectorLabel,D?.inspectorLabel),children:Xt(vr.area)})]}),Z&&y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,onClick:xr,title:T?.addCorner??`Add a corner to this wall`,children:T?.addCorner??`Add corner`}),Z&&y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.thickness??`Thickness (mm)`,value:Z.thickness,decimalScale:0,min:10,showArrows:!0,step:10,onChange:e=>{e!==void 0&&X({...N,walls:{...N.walls,[Z.id]:{...Z,thickness:e}}},`edit-wall`,[Z.id])}}),yr&&b(ot,{children:[y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.width??`Width (mm)`,value:yr.width,decimalScale:0,min:100,step:50,showArrows:!0,onChange:e=>{e!==void 0&&X(ce(N,yr.id,{width:e}).floor,`edit-opening`,[yr.id])}}),y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.sill??`Sill (mm)`,title:`How far above the floor the opening starts. Stored for a 3D view; it does not change the plan.`,showArrows:!0,value:yr.sill,decimalScale:0,min:0,step:50,onChange:e=>{e!==void 0&&X(ce(N,yr.id,{sill:e}).floor,`edit-opening`,[yr.id])}})]}),I.length>0&&y(n,{className:p.roomDrawerInspectorDelete,icon:E?.delete??rt,title:T?.deleteSelection??`Delete selection`,onClick:Cr})]}),tn&&q&&y(`input`,{ref:cr,type:`file`,accept:`application/json,.json`,className:p.roomDrawerFileInput,tabIndex:-1,"aria-hidden":`true`,onChange:e=>{let t=e.target.files?.[0];e.target.value=``,t&&Ur(t)}}),$t&&(ur!==null||Jr)&&y(`div`,{className:v(p.roomDrawerHint,ur!==null&&p.roomDrawerHintReport,D?.hint),style:O?.hint,role:ur===null?void 0:`status`,children:ur===null?Jr:ur.length===0?T?.importFailed??`That file could not be read as a floor plan`:ur.join(` · `)})]})});export{x as default};
|
|
1
|
+
import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{renderIcon as t}from"../utils/renderIcon.mjs";import n from"../actionIcon/actionIcon.mjs";import r from"../hooks/useCoarsePointer.mjs";import i from"../input/input.mjs";import{OpeningKind as a,WallType as o}from"../floorPlan/floorPlan.types.mjs";import{pointToSegment as s}from"../floorPlan/floorPlan.geometry.mjs";import{DEFAULT_WALL_ATTRS as c,addOpening as l,addRect as ee,addWall as u,detachWall as te,dissolveNode as ne,mergeNodes as re,moveNode as ie,removeOpening as ae,removeWall as oe,splitWall as se,updateOpening as ce,weldShortWalls as le}from"../floorPlan/floorPlan.graph.mjs";import{addFloor as ue,duplicateFloor as de,emptyFloorPlan as fe,floorBelow as pe,floorBounds as me,floorIndex as he,getFloor as ge,moveFloor as _e,removeFloor as ve,renameFloor as ye,setFloor as be,setFloorHeight as xe}from"../floorPlan/floorPlan.plan.mjs";import{commitDerivation as Se,derivePlan as Ce}from"../floorPlan/floorPlan.rooms.mjs";import{HIT_PX as we,HIT_PX_COARSE as Te,hitTest as Ee,selectionsEqual as De,worldTolerances as d}from"../floorPlan/floorPlan.hit.mjs";import{SnapKind as f,clientToWorld as Oe,resolveSnap as ke}from"../floorPlan/floorPlan.snap.mjs";import{planFromJson as Ae,planToJson as je}from"../floorPlan/floorPlan.json.mjs";import Me from"../numberInput/index.mjs";import Ne from"../planCanvas/planCanvas.mjs";import{usePlanHistory as Pe}from"./usePlanHistory.mjs";import p from"./roomDrawer.module.mjs";import{forwardRef as Fe,useCallback as m,useEffect as h,useImperativeHandle as Ie,useMemo as Le,useRef as g,useState as _}from"react";import v from"classnames";import{faAngleDown as Re,faAngleUp as ze,faArrowPointer as Be,faArrowRotateLeft as Ve,faArrowRotateRight as He,faBorderAll as Ue,faClone as We,faDoorOpen as Ge,faDownload as Ke,faDraftingCompass as qe,faExpand as Je,faLayerGroup as Ye,faMagnet as Xe,faMagnifyingGlassMinus as Ze,faMagnifyingGlassPlus as Qe,faMinus as $e,faPlus as et,faRulerCombined as tt,faSquare as nt,faTrash as rt,faUpload as it,faWindowMaximize as at}from"@fortawesome/free-solid-svg-icons";import{Fragment as ot,jsx as y,jsxs as b}from"react/jsx-runtime";var st=[`select`,`wall`,`rect`,`door`,`window`,`archway`,`measure`],ct={v:`select`,w:`wall`,r:`rect`,d:`door`,n:`window`,a:`archway`,m:`measure`},lt={door:a.Door,window:a.Window,archway:a.Archway},ut={[a.Door]:`Door`,[a.Window]:`Window`,[a.Archway]:`Archway`,[a.Gap]:`Gap`},dt={[a.Door]:{width:900,sill:0,head:2100},[a.Window]:{width:1200,sill:900,head:2100},[a.Archway]:{width:1200,sill:0,head:2100},[a.Gap]:{width:1e3,sill:0,head:2500}},ft=1,pt=4,mt=[];function ht(e){return e>=1e3?`${(e/1e3).toFixed(2)} m`:`${Math.round(e)} mm`}function gt(e){let t=e/1e6;return`${t.toFixed(+(t<10))} m²`}function _t(e){let t=e*180/Math.PI;return t=(t%360+360)%360,t>180&&(t-=360),`${Math.abs(t)<.05?0:Math.round(t*10)/10}°`}var x=Fe(function(a,Fe){let{value:x,defaultValue:vt,onChange:S,onChangeEnd:yt,floorId:bt,defaultFloorId:xt,onFloorChange:St,showFloorBar:Ct=!0,showUnderlay:wt=!0,tool:Tt,defaultTool:Et=`select`,onToolChange:Dt,tools:Ot=st,selection:kt,defaultSelection:At,onSelectionChange:jt,multiSelect:Mt=!0,onHoverChange:Nt,view:Pt,defaultView:Ft,onViewChange:It,minZoom:Lt=.005,maxZoom:Rt=2,fitOnMount:zt=!0,gridSize:C=100,showGrid:Bt=!0,snap:Vt=!0,angleLock:Ht=!1,constrainAngle:Ut=45,showSnapGuides:Wt=!0,wallThickness:Gt=c.thickness,wallHeight:Kt,openingDefaults:qt,showMeasurements:Jt=!0,formatLength:Yt=ht,formatArea:Xt=gt,showToolbar:Zt=!0,showInspector:Qt=!0,showHint:$t=!0,showHistoryControls:en=!0,showFileControls:tn=!0,fileName:nn,onImport:rn,historyMode:an=`internal`,historyLimit:on=50,onHistoryChange:sn,readOnly:cn=!1,disabled:w=!1,canvasHeight:ln=`420px`,getRoomColor:un,renderRoomLabel:dn,labels:T,icons:E,"aria-label":fn,className:pn,style:mn,classNames:D,styles:O,...hn}=e(`RoomDrawer`,a),gn=r(),k=gn?Te:we,_n=g(null),vn=g(null),yn=g(null),bn=g(null),A=g({kind:`none`}),xn=g(new Map),Sn=g(null),Cn=g(!1),wn=g(!1),Tn=g(!1),En=Le(()=>vt??x??fe(),[]),j=Pe(En,on),Dn=x!==void 0,M=Dn?x:j.present;h(()=>{if(Dn&&x){if(x===bn.current){j.replace(x);return}j.commit(x,`external`)}},[x,Dn]);let[On,kn]=_(xt),An=bt??On??M.floors[0]?.id,N=Le(()=>ge(M,An)??ge(M)??fe().floors[0],[M,An]),[jn,Mn]=_(wt);h(()=>Mn(wt),[wt]);let Nn=Le(()=>jn?pe(M,N.id):null,[jn,M,N.id]),Pn=m(e=>{e!==N.id&&(bt===void 0&&kn(e),St?.(e))},[N.id,bt,St]),P=Le(()=>Ce(N),[N]).rooms,[Fn,In]=_(Et),F=Tt??Fn,Ln=m(e=>{Tt===void 0&&In(e),Dt?.(e)},[Tt,Dt]),[Rn,zn]=_(At??mt),I=kt===void 0?Rn:kt,L=g(I);L.current=I;let R=m(e=>{let t=e===null?mt:Array.isArray(e)?e:[e];L.current=t,kt===void 0&&zn(t),jt?.([...t])},[kt,jt]),Bn=m(e=>{let t=L.current,n=t.filter(t=>t.type!==e.type||t.id!==e.id);R(n.length===t.length?[...t,e]:n)},[R]),z=I.length===1?I[0]:null,Vn=m(e=>{let t=new Set;for(let n of e)if(n.type===`node`)t.add(n.id);else if(n.type===`wall`){let e=N.walls[n.id];e&&(t.add(e.a),t.add(e.b))}else if(n.type===`room`){let e=P.find(e=>e.roomId===n.id);for(let n of e?.nodeIds??[])t.add(n)}return t},[N.walls,P]),Hn=Le(()=>Vn(I),[Vn,I]),[Un,Wn]=_(null),[Gn,Kn]=_(Ft??{x:0,y:0,zoom:.05}),B=Pt??Gn,V=m(e=>{Pt===void 0&&Kn(e),It?.(e)},[Pt,It]),[H,qn]=_({width:800,height:420}),[U,Jn]=_([]),[W,Yn]=_(null),[Xn,Zn]=_(Vt),[Qn,$n]=_(Ht);h(()=>Zn(Vt),[Vt]),h(()=>$n(Ht),[Ht]);let[er,tr]=_(Bt);h(()=>tr(Bt),[Bt]);let nr=g(null),[G,rr]=_(null),[K,ir]=_([]),ar=g(0),[or,sr]=_(null),cr=g(null),lr=m(e=>{let t=d(k,B.zoom);for(let n=K.length-1;n>=0;n--){let r=K[n];if(Math.hypot(e.x-r.a.x,e.y-r.a.y)<=t.node)return{id:r.id,end:`a`};if(Math.hypot(e.x-r.b.x,e.y-r.b.y)<=t.node)return{id:r.id,end:`b`}}for(let n=K.length-1;n>=0;n--){let r=K[n];if(s(e,r.a,r.b).dist<=t.wall)return{id:r.id}}return null},[K,k,B.zoom]),[ur,dr]=_(null),q=!cn&&!w,fr=Le(()=>{if(U.length<2)return;let e=U[U.length-2],t=U[U.length-1];return Math.atan2(t.y-e.y,t.x-e.x)},[U]);h(()=>{let e=vn.current;if(!e)return;let t=new ResizeObserver(()=>{let t=e.getBoundingClientRect();t.width>0&&t.height>0&&qn({width:Math.round(t.width),height:Math.round(t.height)})});t.observe(e);let n=e.getBoundingClientRect();return n.width>0&&n.height>0&&qn({width:Math.round(n.width),height:Math.round(n.height)}),()=>t.disconnect()},[]);let pr=m((e,t)=>{let n=vn.current?.getBoundingClientRect()??{left:0,top:0};return Oe(e,t,n,B)},[B]),J=m(e=>({x:(e.x-B.x)*B.zoom,y:(e.y-B.y)*B.zoom}),[B]),Y=m((e,t,n,r,i)=>{let a=Xn!==wn.current,o=Qn!==Tn.current,s=ke(e,{floor:N,pxToWorld:B.zoom>0?1/B.zoom:1,origin:t,referenceAngle:r,excludeNodeIds:n,excludeWallIds:i,options:{enabled:a?[f.Node,f.Intersection,f.Wall,f.Angle,f.Extension,f.Alignment,f.Grid]:[],gridSize:C,angleStepDeg:o?Ut:0,toleranceScreenPx:gn?16:10}});return nr.current=s,s},[N,B.zoom,Xn,Qn,C,Ut,gn]),mr=m(e=>{let t=Object.values(N.walls).filter(t=>t.a===e||t.b===e),n=new Set(t.map(e=>e.id)),r=N.nodes[e];if(!r)return{excludeWallIds:n};let i={x:r.x,y:r.y},a,o=t[0];if(o){let t=o.a===e?o.b:o.a,n=N.nodes[t];n&&(a=Math.atan2(n.y-r.y,n.x-r.x))}return{origin:i,referenceAngle:a,excludeWallIds:n}},[N]),hr=m((e={})=>{let t=e.padding??24,n=me(N);if(!n||n.width<=0||n.height<=0){V({x:-1e3,y:-1e3,zoom:.05});return}let r=Math.min((H.width-t*2)/n.width,(H.height-t*2)/n.height),i=Math.max(Lt,Math.min(Rt,r));V({x:n.minX-(H.width/i-n.width)/2,y:n.minY-(H.height/i-n.height)/2,zoom:i})},[N,H.width,H.height,Lt,Rt,V]),gr=g(!1);h(()=>{zt&&!gr.current&&Object.keys(N.nodes).length!==0&&(H.width<=1||(gr.current=!0,hr()))},[zt,N,H.width,hr]);let _r=m((e,t,n,r=[],i={})=>{if(e===N)return M;let a=be(M,e);bn.current=a,n?i.push===!1?j.replace(a):j.commit(a,t,r):j.updateGesture(a);let o={reason:t,committed:n,targetIds:r};return S?.(a,o),n&&yt?.(a,o),a},[N,M,j,S,yt]),X=m((e,t,n=[],r={})=>{let i=Se(le(e).floor).floor;return _r(i,t,!0,n,r)},[_r]);h(()=>{sn?.({canUndo:j.canUndo,canRedo:j.canRedo})},[j.canUndo,j.canRedo,sn]);let vr=Le(()=>z?.type===`room`?P.find(e=>e.roomId===z.id)??null:null,[z,P]),Z=z?.type===`wall`?N.walls[z.id]:void 0,yr=z?.type===`opening`?N.openings[z.id]:void 0,br=Le(()=>{if(!Z)return null;let e=N.nodes[Z.a],t=N.nodes[Z.b];return!e||!t?null:{x:(e.x+t.x)/2,y:(e.y+t.y)/2}},[Z,N.nodes]),xr=m(()=>{if(!q||!Z)return;let e=se(N,Z.id,.5);e.result.wallIds&&(X(e.floor,`edit-wall`,[e.result.nodeId]),R({type:`node`,id:e.result.nodeId}))},[q,Z,N,X,R]),Sr=m((e,t,n=new Set)=>{if(e.type===`wall`)return{floor:oe(t,e.id).floor};if(e.type===`opening`)return{floor:ae(t,e.id).floor};if(e.type===`node`){let n=ne(t,e.id,{force:!0});if(n.result)return{floor:n.floor,reselect:{type:`wall`,id:n.result.wallId}};let r=t;for(let n of Object.values(t.walls))(n.a===e.id||n.b===e.id)&&(r=oe(r,n.id,{dissolveCollinear:!1}).floor);return{floor:r}}let r=P.find(t=>t.roomId===e.id);if(!r)return{floor:t};let i=new Set;for(let t of P)if(t.roomId!==e.id&&!(t.roomId&&n.has(t.roomId)))for(let e of t.wallIds)i.add(e);let a=t;for(let e of new Set(r.wallIds))i.has(e)||(a=oe(a,e,{dissolveCollinear:!1}).floor);let o={...a.rooms};return delete o[e.id],{floor:{...a,rooms:o}}},[P]),Cr=m(()=>{let e=L.current;if(!q||e.length===0)return;let t={room:0,opening:1,wall:2,node:3},n=[...e].sort((e,n)=>t[e.type]-t[n.type]),r=new Set(n.filter(e=>e.type===`room`).map(e=>e.id)),i=N,a;for(let e of n){let t=Sr(e,i,r);i=t.floor,n.length===1&&(a=t.reselect)}i!==N&&(X(i,`delete`,n.map(e=>e.id)),R(a??null))},[q,N,Sr,X,R]),wr=m(()=>{Jn(e=>e.length===0?e:[]),rr(null)},[]);h(()=>{wr()},[F,wr]);let Tr=m(e=>{if(w)return;if(_n.current?.focus(),dr(null),xn.current.set(e.pointerId,{x:e.clientX,y:e.clientY}),e.currentTarget.setPointerCapture?.(e.pointerId),xn.current.size===2){let[e,t]=[...xn.current.values()];A.current.kind!==`none`&&A.current.kind!==`pan`&&j.cancelGesture(),A.current={kind:`pinch`,startDist:Math.hypot(t.x-e.x,t.y-e.y),startView:B,startMid:{x:(e.x+t.x)/2,y:(e.y+t.y)/2}};return}if(xn.current.size>2)return;if(Sn.current={client:{x:e.clientX,y:e.clientY},moved:!1},e.button===1||Cn.current){A.current={kind:`pan`,startClient:{x:e.clientX,y:e.clientY},startView:B};return}if(e.button!==0)return;let t=pr(e.clientX,e.clientY);if(!q){let e=Ee(N,P,t,d(k,B.zoom));R(e);return}if(F===`rect`){let e=Y(t).point;A.current={kind:`rect`,start:e,current:e},j.beginGesture();return}if(F===`measure`){let e=lr(t);if(e){let n=K.find(t=>t.id===e.id);A.current=e.end?{kind:`measureEnd`,id:e.id,end:e.end}:{kind:`measureMove`,id:e.id,startWorld:t,origA:n.a,origB:n.b};return}let n=Y(t).point;A.current={kind:`measure`,start:n,current:n};return}if(F===`wall`){let e=U[U.length-1],n=Y(t,e,void 0,fr).point;if(U.length===0){Jn([n]);return}let r=U[U.length-1],i=u(N,r,n,{thickness:Gt,type:o.Interior,height:Kt},d(k,B.zoom).node);i.result.wallIds.length>0&&X(i.floor,`draw-wall`,i.result.wallIds),U.length>=2&&Math.hypot(n.x-U[0].x,n.y-U[0].y)<d(k,B.zoom).node?wr():Jn(e=>[...e,n]);return}let n=lt[F];if(n){let e=d(k,B.zoom),r=Ee(N,P,t,e,{accept:[`wall`]});if(r?.type!==`wall`)return;let i=N.walls[r.id],a=N.nodes[i.a],o=N.nodes[i.b],s=Math.hypot(o.x-a.x,o.y-a.y),c=((t.x-a.x)*(o.x-a.x)+(t.y-a.y)*(o.y-a.y))/(s*s||1),ee={...dt[n],...qt?.[n]},u=l(N,{wallId:i.id,kind:n,offset:Math.min(Math.max(c,0),1)*s,width:ee.width,sill:ee.sill,head:ee.head});u.result.openingId&&(X(u.floor,`add-opening`,[u.result.openingId]),R({type:`opening`,id:u.result.openingId}));return}let r=d(k,B.zoom);if(br&&z?.type===`wall`&&Math.hypot(t.x-br.x,t.y-br.y)<=r.node){j.beginGesture(),A.current={kind:`wallSplit`,wallId:z.id,at:br};return}let i=Ee(N,P,t,r),a=Mt&&(e.ctrlKey||e.metaKey);if(!i){a||R(null),A.current=Mt?{kind:`marquee`,start:t,current:t,additive:a,base:L.current}:{kind:`none`};return}if((e.ctrlKey||e.metaKey)&&i.type===`wall`&&N.walls[i.id]){let e=N.walls[i.id];a||R(i),j.beginGesture(),A.current={kind:`wall`,wallId:i.id,startWorld:t,origA:{...N.nodes[e.a]},origB:{...N.nodes[e.b]},moved:!1,detach:!0,toggle:a};return}if(a){Bn(i),A.current={kind:`none`};return}if(L.current.some(e=>e.type===i.type&&e.id===i.id)||R(i),j.beginGesture(),L.current.length>1){let e=[...Vn(L.current)],n={};for(let t of e){let e=N.nodes[t];e&&(n[t]={x:e.x,y:e.y})}A.current={kind:`room`,nodeIds:e,startWorld:t,orig:n,moved:!1};return}if(i.type===`node`)A.current={kind:`node`,nodeId:i.id,moved:!1,...mr(i.id)};else if(i.type===`wall`){let e=N.walls[i.id];A.current={kind:`wall`,wallId:i.id,startWorld:t,origA:{...N.nodes[e.a]},origB:{...N.nodes[e.b]},moved:!1}}else if(i.type===`opening`)A.current={kind:`opening`,openingId:i.id,moved:!1};else{let e=P.find(e=>e.roomId===i.id),n=e?[...new Set(e.nodeIds)]:[],r={};for(let e of n){let t=N.nodes[e];t&&(r[e]={x:t.x,y:t.y})}A.current={kind:`room`,nodeIds:n,startWorld:t,orig:r,moved:!1}}},[w,q,B,F,N,P,k,pr,Y,U,Gt,Kt,qt,X,R,br,z,fr,mr,Vn,Mt,Bn,j,wr,lr,K]),Er=m(e=>{if(w)return;xn.current.has(e.pointerId)&&xn.current.set(e.pointerId,{x:e.clientX,y:e.clientY});let t=A.current;if(t.kind===`pinch`&&xn.current.size>=2){let[e,n]=[...xn.current.values()],r=Math.hypot(n.x-e.x,n.y-e.y);if(t.startDist<=0)return;let i=Math.max(Lt,Math.min(Rt,t.startView.zoom*(r/t.startDist))),a=vn.current?.getBoundingClientRect()??{left:0,top:0},o={x:(e.x+n.x)/2,y:(e.y+n.y)/2},s=Oe(t.startMid.x,t.startMid.y,a,t.startView);V({x:s.x-(o.x-a.left)/i,y:s.y-(o.y-a.top)/i,zoom:i});return}if(Sn.current){let t=e.clientX-Sn.current.client.x,n=e.clientY-Sn.current.client.y;Math.hypot(t,n)>pt&&(Sn.current.moved=!0)}if(t.kind===`pan`){V({x:t.startView.x-(e.clientX-t.startClient.x)/t.startView.zoom,y:t.startView.y-(e.clientY-t.startClient.y)/t.startView.zoom,zoom:t.startView.zoom});return}let n=pr(e.clientX,e.clientY);if(Yn(n),t.kind===`none`){if(!q)return;if(F===`wall`&&U.length>0){let e=Y(n,U[U.length-1],void 0,fr);Yn(e.point),rr(e);return}if(F===`select`){let e=Ee(N,P,n,d(k,B.zoom));De(e,Un)||(Wn(e),Nt?.(e))}F===`measure`&&sr(lr(n)?.id??null);return}if(Sn.current?.moved){if(t.kind===`measureEnd`){let e=Y(n).point;ir(n=>n.map(n=>n.id===t.id?{...n,[t.end]:e}:n)),Yn(e);return}if(t.kind===`measureMove`){let e=n.x-t.startWorld.x,r=n.y-t.startWorld.y;ir(n=>n.map(n=>n.id===t.id?{...n,a:{x:t.origA.x+e,y:t.origA.y+r},b:{x:t.origB.x+e,y:t.origB.y+r}}:n));return}if(t.kind===`rect`||t.kind===`measure`){A.current={...t,current:Y(n).point},Yn(Y(n).point);return}if(t.kind===`marquee`){A.current={...t,current:n},Yn(n);return}if(t.kind===`wallSplit`){let e=se(N,t.wallId,t.at);if(!e.result.wallIds){A.current={kind:`none`};return}let r=e.result.nodeId,i=N.walls[t.wallId],a=i?e.floor.nodes[i.a]:void 0,o=i?e.floor.nodes[i.b]:void 0,s={origin:a?{x:a.x,y:a.y}:void 0,referenceAngle:a&&o?Math.atan2(o.y-a.y,o.x-a.x):void 0,excludeWallIds:new Set(e.result.wallIds)},c=Y(n,s.origin,new Set([r]),s.referenceAngle,s.excludeWallIds).point;A.current={kind:`node`,nodeId:r,moved:!0,...s},R({type:`node`,id:r}),rr(nr.current),_r(ie(e.floor,r,c).floor,`move-node`,!1,[r]);return}if(t.kind===`node`){let e=Y(n,t.origin,new Set([t.nodeId]),t.referenceAngle,t.excludeWallIds).point;rr(nr.current),A.current={...t,moved:!0},_r(ie(N,t.nodeId,e).floor,`move-node`,!1,[t.nodeId]);return}if(t.kind===`wall`){let e=N.walls[t.wallId];if(!e)return;let r=t.origB.x-t.origA.x,i=t.origB.y-t.origA.y,a=Math.hypot(r,i);if(a<1e-6)return;let o={x:-i/a,y:r/a},s=(n.x-t.startWorld.x)*o.x+(n.y-t.startWorld.y)*o.y,c=Vt!==wn.current&&C>0?C:1,l=Math.round(s/c)*c,ee=Math.max(c,10);if(t.detach){if(Math.abs(l)<ee)return;let e=te(N,t.wallId,{x:o.x*l,y:o.y*l});if(!e.result)return;A.current={...t,detach:!1,toggle:!1,detachedSign:Math.sign(l),moved:!0},R({type:`wall`,id:t.wallId}),_r(e.floor,`move-wall`,!1,[t.wallId]);return}let u=ie(N,e.a,{x:t.origA.x+o.x*l,y:t.origA.y+o.y*l}).floor;u=ie(u,e.b,{x:t.origB.x+o.x*l,y:t.origB.y+o.y*l}).floor,t.detachedSign&&Math.abs(l)<10?(u=le(u).floor,A.current={...t,detachedSign:void 0,moved:!0}):A.current={...t,moved:!0},_r(u,`move-wall`,!1,[t.wallId]);return}if(t.kind===`opening`){let e=N.openings[t.openingId];if(!e)return;let r=N.walls[e.wallId],i=N.nodes[r.a],a=N.nodes[r.b],o=Math.hypot(a.x-i.x,a.y-i.y),s=((n.x-i.x)*(a.x-i.x)+(n.y-i.y)*(a.y-i.y))/(o*o||1);A.current={...t,moved:!0},_r(ce(N,t.openingId,{offset:Math.min(Math.max(s,0),1)*o}).floor,`move-opening`,!1,[t.openingId]);return}if(t.kind===`room`){let e=n.x-t.startWorld.x,r=n.y-t.startWorld.y,i=Vt!==wn.current&&C>0?C:1,a=Math.round(e/i)*i,o=Math.round(r/i)*i,s=N;for(let e of t.nodeIds){let n=t.orig[e];n&&(s=ie(s,e,{x:n.x+a,y:n.y+o}).floor)}A.current={...t,moved:!0},_r(s,`move-room`,!1,t.nodeIds)}}},[w,q,F,N,P,Un,k,B.zoom,Lt,Rt,C,Vt,pr,Y,_r,V,R,U,fr,Nt,lr]),Dr=m((e,t)=>{xn.current.delete(e.pointerId);let n=A.current;A.current={kind:`none`};let r=Sn.current?.moved??!1;if(Sn.current=null,rr(null),n.kind===`none`||n.kind===`pan`||n.kind===`pinch`)return;if(n.kind===`marquee`){if(t||!r){t&&R([...n.base]);return}let e=Math.min(n.start.x,n.current.x),i=Math.max(n.start.x,n.current.x),a=Math.min(n.start.y,n.current.y),o=Math.max(n.start.y,n.current.y),s=[];for(let t of Object.values(N.nodes))t.x>=e&&t.x<=i&&t.y>=a&&t.y<=o&&s.push({type:`node`,id:t.id});if(n.additive){let e=new Set(n.base.map(e=>`${e.type}:${e.id}`));R([...n.base,...s.filter(t=>!e.has(`${t.type}:${t.id}`))])}else R(s);return}if(t){let e=j.cancelGesture();e&&S?.(e,{reason:`external`,committed:!1,targetIds:[]});return}if(n.kind===`measureEnd`||n.kind===`measureMove`)return;if(n.kind===`measure`){let e=Math.hypot(n.current.x-n.start.x,n.current.y-n.start.y);r&&e>ft&&(ar.current+=1,ir(e=>[...e,{id:ar.current,a:n.start,b:n.current}]));return}if(n.kind===`rect`){if(!r){j.cancelGesture();return}let e=ee(N,n.start,n.current,{thickness:Gt,type:o.Interior,height:Kt},d(k,B.zoom).node);if(e.result.wallIds.length===0){j.cancelGesture();return}let t=j.endGesture();X(e.floor,`draw-rect`,e.result.wallIds,{push:!t});return}if(!r){j.cancelGesture(),n.kind===`wall`&&n.toggle&&Bn({type:`wall`,id:n.wallId});return}if(n.kind===`node`){let e=N.nodes[n.nodeId];if(e){let t=d(k,B.zoom).node,r=Object.values(N.nodes).find(r=>r.id!==n.nodeId&&Math.hypot(r.x-e.x,r.y-e.y)<=t);if(r){let e=j.endGesture();X(re(N,r.id,n.nodeId).floor,`move-node`,[r.id],{push:!e}),R({type:`node`,id:r.id});return}}}let i=j.endGesture(),a=n.kind===`wall`?`move-wall`:n.kind===`opening`?`move-opening`:n.kind===`room`?`move-room`:`move-node`;X(N,a,[],{push:!i})},[N,j,k,B.zoom,Gt,Kt,X,R,Bn,S]);h(()=>{let e=vn.current;if(!e||w)return;function t(t){t.preventDefault();let n=e.getBoundingClientRect(),r=Math.exp(-t.deltaY*.002);V((()=>{let e=Or.current,i=Math.max(Lt,Math.min(Rt,e.zoom*r)),a=Oe(t.clientX,t.clientY,n,e);return{x:a.x-(t.clientX-n.left)/i,y:a.y-(t.clientY-n.top)/i,zoom:i}})())}return e.addEventListener(`wheel`,t,{passive:!1}),()=>e.removeEventListener(`wheel`,t)},[w,Lt,Rt,V]);let Or=g(B);Or.current=B;let kr=m(e=>{let t=Math.max(Lt,Math.min(Rt,B.zoom*e)),n={x:B.x+H.width/2/B.zoom,y:B.y+H.height/2/B.zoom};V({x:n.x-H.width/2/t,y:n.y-H.height/2/t,zoom:t})},[B,H,Lt,Rt,V]),Ar=m(()=>{if(an===`none`)return;let e=j.undo();e&&(bn.current=e,S?.(e,{reason:`undo`,committed:!0,targetIds:[]}),yt?.(e,{reason:`undo`,committed:!0,targetIds:[]}))},[an,j,S,yt]),jr=m(()=>{if(an===`none`)return;let e=j.redo();e&&(bn.current=e,S?.(e,{reason:`redo`,committed:!0,targetIds:[]}),yt?.(e,{reason:`redo`,committed:!0,targetIds:[]}))},[an,j,S,yt]),Mr=m(()=>{let e=P.filter(e=>e.roomId).map(e=>({type:`room`,id:e.roomId}));if(e.length>0){R(e);return}R(Object.keys(N.nodes).map(e=>({type:`node`,id:e})))},[P,N.nodes,R]),Nr=m((e,t)=>{if(!q||Hn.size===0)return;let n=C>0?C:100,r=Tn.current?n*10:n,i=N;for(let n of Hn){let a=i.nodes[n];a&&(i=ie(i,n,{x:a.x+e*r,y:a.y+t*r}).floor)}X(i,`nudge`,[...Hn])},[q,Hn,N,C,X]),Pr=m(e=>{if(w)return;let t=e.target;if(t instanceof HTMLInputElement||t instanceof HTMLTextAreaElement){e.key===`Escape`&&t.blur();return}if(e.key===`Shift`&&(Tn.current=!0),e.key===`Alt`&&(wn.current=!0),e.key===` `&&!Cn.current){Cn.current=!0,e.preventDefault();return}let n=e.metaKey||e.ctrlKey;if(n&&e.key.toLowerCase()===`z`){e.preventDefault(),e.shiftKey?jr():Ar();return}if(n&&e.key.toLowerCase()===`a`){e.preventDefault(),Mt&&Mr();return}if(n&&e.key.toLowerCase()===`y`){e.preventDefault(),jr();return}if(e.key===`Escape`){U.length>0?wr():K.length>0?ir([]):R(null);return}if(e.key===`Enter`&&F===`wall`){wr();return}if(e.key===`Delete`||e.key===`Backspace`){if(e.preventDefault(),F===`measure`){or!==null&&(ir(e=>e.filter(e=>e.id!==or)),sr(null));return}Cr();return}if(e.key===`+`||e.key===`=`){kr(1.25);return}if(e.key===`-`){kr(1/1.25);return}if(e.key===`0`){hr();return}if(e.key.startsWith(`Arrow`)){e.preventDefault();let t={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[e.key];t&&Nr(t[0],t[1]);return}let r=e.key.toLowerCase();if(r===`s`){Zn(e=>!e);return}if(r===`l`){$n(e=>!e);return}if(r===`g`){tr(e=>!e);return}let i=ct[e.key.toLowerCase()];i&&q&&Ot.includes(i)&&(Ln(i),wr())},[w,q,Ot,F,U,K.length,or,jr,Ar,R,wr,Cr,kr,hr,Nr,Ln,Mt,Mr]),Q=m((e,t,n)=>{bn.current=e,n?.resetHistory?(j.clearHistory(),j.replace(e)):j.commit(e,t);let r={reason:t,committed:!0,targetIds:[]};S?.(e,r),yt?.(e,r)},[j,S,yt]),Fr=m((e={})=>{let{plan:t,floor:n}=ue(M,{...e,index:he(M,N.id)+1});return Q(t,`add-floor`),Pn(n.id),n.id},[M,N.id,Q,Pn]),Ir=m(()=>{let{plan:e,floor:t}=de(M,N.id);return t?(Q(e,`duplicate-floor`),Pn(t.id),t.id):null},[M,N.id,Q,Pn]),Lr=m(e=>{let t=e??N.id,n=ve(M,t);if(n!==M&&(Q(n,`remove-floor`),t===N.id)){let e=he(M,t);Pn(n.floors[Math.max(0,e-1)].id)}},[M,N.id,Q,Pn]),Rr=m((e,t)=>{let n=_e(M,e,t);n!==M&&Q(n,`move-floor`)},[M,Q]),zr=m((e,t)=>{let n=xe(M,e,t);n!==M&&Q(n,`edit-floor`)},[M,Q]),Br=m((e,t)=>{let n=ye(M,e,t);n!==M&&Q(n,`rename-floor`)},[M,Q]),Vr=m(e=>{let t=(e??nn??M.name??``).trim()||`floor-plan`,n=URL.createObjectURL(new Blob([je(M)],{type:`application/json`})),r=document.createElement(`a`);r.href=n,r.download=t.endsWith(`.json`)?t:`${t}.json`,r.click(),setTimeout(()=>URL.revokeObjectURL(n),0)},[nn,M]),Hr=m(e=>{let t=Ae(e);return t.plan&&Q(t.plan,`import`),dr(t.plan&&t.issues.length===0?null:t.issues),rn?.(t),t},[rn,Q]),Ur=m(e=>{e.text().then(e=>Hr(e)).catch(e=>{let t=[`Could not read that file: ${e.message}`];dr(t),rn?.({plan:null,issues:t})})},[Hr,rn]),Wr=m(()=>ir([]),[]),Gr=m(e=>{e.key===`Shift`&&(Tn.current=!1),e.key===`Alt`&&(wn.current=!1),e.key===` `&&(Cn.current=!1)},[]);Ie(Fe,()=>({getPlan:()=>M,setPlan:(e,t)=>Q(e,`import`,t),clear:()=>Q(fe(),`clear`),getFloorId:()=>N.id,setFloorId:Pn,addFloor:e=>Fr(e),duplicateFloor:Ir,removeFloor:Lr,renameFloor:Br,moveFloor:Rr,setFloorHeight:zr,clearMeasurements:Wr,download:Vr,loadJson:Hr,undo:Ar,redo:jr,canUndo:()=>an!==`none`&&j.canUndo,canRedo:()=>an!==`none`&&j.canRedo,clearHistory:j.clearHistory,getSelection:()=>[...L.current],select:R,addToSelection:e=>{let t=Array.isArray(e)?e:[e],n=new Set(L.current.map(e=>`${e.type}:${e.id}`));R([...L.current,...t.filter(e=>!n.has(`${e.type}:${e.id}`))])},toggleSelection:Bn,selectAll:Mr,deleteSelection:Cr,getView:()=>B,setView:V,zoomBy:kr,fitToContent:hr,toWorld:pr,toScreen:J,getSvgElement:()=>yn.current}),[M,j,Q,N,Pn,Fr,Ir,Lr,Br,Rr,zr,Wr,Vr,Hr,Ar,jr,an,R,Bn,Mr,Cr,B,V,kr,hr,pr,J]);let $=A.current,Kr=Le(()=>{if(!q)return null;let e=[],t=[...K,...$.kind===`measure`?[{id:-1,a:$.start,b:$.current}]:[]];for(let n of t){let t=J(n.a),r=J(n.b),i=Math.hypot(n.b.x-n.a.x,n.b.y-n.a.y);if(i<ft)continue;let a=Math.atan2(n.b.y-n.a.y,n.b.x-n.a.x),o=-Math.sin(a)*5,s=Math.cos(a)*5,c={x:(t.x+r.x)/2,y:(t.y+r.y)/2};if(e.push(b(`g`,{className:v(p.roomDrawerMeasureLine,or===n.id&&p.roomDrawerMeasureLineHovered,D?.measureLine),children:[y(`line`,{x1:t.x,y1:t.y,x2:r.x,y2:r.y}),y(`line`,{x1:t.x-o,y1:t.y-s,x2:t.x+o,y2:t.y+s}),y(`line`,{x1:r.x-o,y1:r.y-s,x2:r.x+o,y2:r.y+s})]},`measure-${n.id}`)),F===`measure`&&n.id>=0)for(let[i,a]of[[`a`,t],[`b`,r]])e.push(y(`circle`,{className:p.roomDrawerMeasureGrip,cx:a.x,cy:a.y,r:4},`measure-grip-${n.id}-${i}`));e.push(y(`text`,{className:v(p.roomDrawerMeasure,D?.measureLine),x:c.x,y:c.y-8,textAnchor:`middle`,children:`${Yt(i)} · ${_t(a)}`},`measure-label-${n.id}`))}if(Wt&&G&&(G.guides.forEach((t,n)=>{let r=J(t.a),i=J(t.b);e.push(y(`line`,{className:v(p.roomDrawerGuide,t.kind===f.Angle&&p.roomDrawerGuideAngle),x1:r.x,y1:r.y,x2:i.x,y2:i.y},`guide-${n}`))}),G.kind!==f.None&&G.kind!==f.Grid)){let t=J(G.point);e.push(y(`rect`,{className:p.roomDrawerSnapMarker,x:t.x-4,y:t.y-4,width:8,height:8},`snap-marker`))}if($.kind===`rect`){let t=J($.start),n=J($.current),r=Math.min(t.x,n.x),i=Math.min(t.y,n.y),a=Math.max(t.x,n.x),o=Math.max(t.y,n.y);e.push(y(`rect`,{className:p.roomDrawerPreview,x:r,y:i,width:a-r,height:o-i},`rect-preview`));let s=Math.abs($.current.x-$.start.x),c=Math.abs($.current.y-$.start.y);Jt&&(s>0||c>0)&&(e.push(y(`text`,{className:p.roomDrawerMeasure,x:(r+a)/2,y:i-8,textAnchor:`middle`,children:Yt(s)},`rect-width`),y(`text`,{className:p.roomDrawerMeasure,x:r-8,y:(i+o)/2,textAnchor:`end`,dominantBaseline:`central`,children:Yt(c)},`rect-height`)),s>0&&c>0&&e.push(y(`text`,{className:v(p.roomDrawerMeasure,p.roomDrawerMeasureSecondary),x:(r+a)/2,y:(i+o)/2,textAnchor:`middle`,dominantBaseline:`central`,children:Xt(s*c)},`rect-area`)))}if(F===`wall`&&U.length>0){let t=[...U,W].filter(Boolean).map(J);if(e.push(y(`polyline`,{className:p.roomDrawerPreview,points:t.map(e=>`${e.x},${e.y}`).join(` `),fill:`none`},`chain`)),t.forEach((t,n)=>{e.push(y(`circle`,{className:p.roomDrawerHandle,cx:t.x,cy:t.y,r:4},`chain-dot-${n}`))}),Jt&&W&&U.length>0){let t=U[U.length-1],n=Math.hypot(W.x-t.x,W.y-t.y),r=J({x:(t.x+W.x)/2,y:(t.y+W.y)/2}),i=G?.kind===f.Angle;e.push(y(`text`,{className:v(p.roomDrawerMeasure,i&&p.roomDrawerMeasureLocked),x:r.x,y:r.y-8,textAnchor:`middle`,children:`${Yt(n)} · ${_t(G?.angleRelativeTo===`reference`&&fr!==void 0?Math.atan2(W.y-t.y,W.x-t.x)-fr:Math.atan2(W.y-t.y,W.x-t.x))}${G?.angleRelativeTo===`reference`?` rel`:``}`},`chain-len`))}}let n=new Set(I.filter(e=>e.type===`node`).map(e=>e.id));for(let t of Hn){let r=N.nodes[t];if(!r)continue;let i=J(r);e.push(y(`circle`,{className:v(p.roomDrawerHandle,n.has(t)&&p.roomDrawerHandleActive),cx:i.x,cy:i.y,r:5},`handle-${t}`))}if($.kind===`marquee`&&Sn.current?.moved){let t=J($.start),n=J($.current);e.push(y(`rect`,{className:p.roomDrawerMarquee,x:Math.min(t.x,n.x),y:Math.min(t.y,n.y),width:Math.abs(n.x-t.x),height:Math.abs(n.y-t.y)},`marquee`))}if(br&&$.kind!==`node`){let t=J(br);e.push(y(`circle`,{className:p.roomDrawerMidHandle,cx:t.x,cy:t.y,r:4},`midpoint`))}if(Jt&&$.kind===`room`&&$.moved){let t=new Set($.nodeIds),n=$.nodeIds.find(e=>N.nodes[e]&&$.orig[e]);if(n){let t=N.nodes[n],r=$.orig[n],i=t.x-r.x,a=t.y-r.y,o=z?.type===`room`?P.find(e=>e.roomId===z.id):void 0,s=J(o?o.anchor:t);e.push(y(`text`,{className:v(p.roomDrawerMeasure,p.roomDrawerMeasureOffset),x:s.x,y:s.y-26,textAnchor:`middle`,children:`${Yt(Math.hypot(i,a))} · ${_t(Math.atan2(a,i))}`},`room-offset`))}for(let n of Object.values(N.walls)){if(t.has(n.a)===t.has(n.b))continue;let r=N.nodes[n.a],i=N.nodes[n.b];if(!r||!i)continue;let a=t.has(n.a)?r:i,o=t.has(n.a)?i:r,s=J({x:(r.x+i.x)/2,y:(r.y+i.y)/2});e.push(y(`text`,{className:v(p.roomDrawerMeasure,p.roomDrawerMeasureSecondary),x:s.x,y:s.y-8,textAnchor:`middle`,children:`${Yt(Math.hypot(o.x-a.x,o.y-a.y))} · ${_t(Math.atan2(o.y-a.y,o.x-a.x))}`},`room-stretch-${n.id}`))}}if(Jt&&(z?.type===`node`||z?.type===`wall`)){let t=[],n=new Set,r=(e,r,i)=>{if(n.has(e))return;let a=N.walls[e];a&&(n.add(e),t.push({wall:a,from:r,primary:i}))};if(z.type===`node`)for(let e of Object.values(N.walls))(e.a===z.id||e.b===z.id)&&r(e.id,z.id,!0);else{let e=N.walls[z.id];if(e){r(e.id,e.a,!0);for(let t of Object.values(N.walls))if(t.id!==e.id)for(let n of[e.a,e.b])(t.a===n||t.b===n)&&r(t.id,n,!1)}}let i=G?.kind===f.Angle&&$.kind!==`none`;for(let{wall:n,from:r,primary:a}of t){let t=N.nodes[n.a],o=N.nodes[n.b];if(!t||!o)continue;let s=n.a===r?t:o,c=n.a===r?o:t,l=J({x:(t.x+o.x)/2,y:(t.y+o.y)/2});e.push(y(`text`,{className:v(p.roomDrawerMeasure,!a&&p.roomDrawerMeasureSecondary,a&&i&&p.roomDrawerMeasureLocked),x:l.x,y:l.y-8,textAnchor:`middle`,children:`${Yt(Math.hypot(c.x-s.x,c.y-s.y))} · ${_t(Math.atan2(c.y-s.y,c.x-s.x))}`},`measure-${n.id}`))}}return y(ot,{children:e})},[q,$,F,U,W,I,N,P,z,Hn,br,Jt,Wt,G,fr,Yt,Xt,K,or,D?.measureLine,J]),qr={select:{icon:Be,label:T?.select??`Select and edit`,key:`V`},wall:{icon:$e,label:T?.wall??`Draw walls`,key:`W`},rect:{icon:nt,label:T?.rect??`Draw a room`,key:`R`},door:{icon:Ge,label:T?.door??`Add a door`,key:`D`},window:{icon:at,label:T?.window??`Add a window`,key:`N`},archway:{icon:Je,label:T?.archway??`Add an archway`,key:`A`},measure:{icon:tt,label:T?.measure??`Measure`,key:`M`}},Jr=q?F===`wall`?T?.hintWall??`Click to place corners · Shift for a fixed angle, L to latch it · Click the first corner or press Enter to close`:F===`rect`?T?.hintRect??`Drag to draw a room`:F===`measure`?T?.hintMeasure??`Drag to measure · Drag an end or the line to adjust it · Delete removes one, Escape clears them`:lt[F]?T?.hintOpening??`Click a wall to cut an opening into it`:T?.hintSelect??(Mt?`Drag a corner to reshape · Drag a wall to push it, and the room next door moves with it · Ctrl-click or drag a box to select several · Delete to remove`:`Drag a corner to reshape · Drag a wall to push it, and the room next door moves with it · Drag the dot on a selected wall to add a corner · Delete to remove`):``,Yr=I.length===0?T?.selectedFloor??`Floor`:I.length>1?(T?.selectedCount??`{count} selected`).replace(`{count}`,String(I.length)):yr?T?.selectedOpening??ut[yr.kind]:Z?T?.selectedWall??`Wall`:z?.type===`room`?T?.selectedRoom??`Room`:T?.selectedCorner??`Corner`,Xr=q?Ot:[];return b(`div`,{...hn,ref:_n,className:v(p.roomDrawer,w&&p.roomDrawerDisabled,pn,D?.root),style:{...mn,...O?.root},role:`application`,"aria-label":fn??`Floor plan editor`,tabIndex:w?-1:0,onKeyDown:Pr,onKeyUp:Gr,children:[Zt&&b(`div`,{className:v(p.roomDrawerToolbar,D?.toolbar),style:O?.toolbar,role:`toolbar`,"aria-label":T?.tools??`Drawing tools`,children:[Xr.map(e=>{let n=qr[e];return y(`button`,{type:`button`,className:v(p.roomDrawerToolButton,e===F&&p.roomDrawerToolButtonActive,D?.toolButton),style:O?.toolButton,title:`${n.label} (${n.key})`,"aria-label":n.label,"aria-pressed":e===F,onClick:()=>{Ln(e),wr()},children:t(E?.[e]??n.icon,{className:v(p.roomDrawerToolIcon,D?.toolIcon),style:O?.toolIcon})},e)}),Xr.length>0&&y(`span`,{className:p.roomDrawerToolbarSeparator}),q&&b(ot,{children:[[{on:Xn,toggle:()=>Zn(e=>!e),icon:E?.snap??Xe,label:T?.snap??`Snap to grid and geometry`,key:`S`},{on:Qn,toggle:()=>$n(e=>!e),icon:E?.angleLock??qe,label:T?.angleLock??`Lock to ${Ut}° angles`,key:`L`},{on:er,toggle:()=>tr(e=>!e),icon:E?.grid??Ue,label:T?.grid??`Show grid`,key:`G`},...pe(M,N.id)?[{on:jn,toggle:()=>Mn(e=>!e),icon:E?.underlay??Ye,label:T?.underlay??`Show the floor below`,key:`B`}]:[]].map(e=>y(`button`,{type:`button`,className:v(p.roomDrawerToolButton,e.on&&p.roomDrawerToolButtonOn,D?.toolButton),style:O?.toolButton,title:`${e.label} (${e.key})`,"aria-label":e.label,"aria-pressed":e.on,onClick:e.toggle,children:t(e.icon,{className:v(p.roomDrawerToolIcon,D?.toolIcon),style:O?.toolIcon})},e.key)),y(`span`,{className:p.roomDrawerToolbarSeparator})]}),en&&an!==`none`&&q&&b(ot,{children:[y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.undo??`Undo`,"aria-label":T?.undo??`Undo`,disabled:!j.canUndo,onClick:Ar,children:t(E?.undo??Ve)}),y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.redo??`Redo`,"aria-label":T?.redo??`Redo`,disabled:!j.canRedo,onClick:jr,children:t(E?.redo??He)}),y(`span`,{className:p.roomDrawerToolbarSeparator})]}),tn&&b(ot,{children:[y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.download??`Download plan`,"aria-label":T?.download??`Download plan`,onClick:()=>Vr(),children:t(E?.download??Ke)}),q&&y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.upload??`Open a plan file`,"aria-label":T?.upload??`Open a plan file`,onClick:()=>cr.current?.click(),children:t(E?.upload??it)}),y(`span`,{className:p.roomDrawerToolbarSeparator})]}),b(`div`,{className:v(p.roomDrawerViewControls,D?.viewControls),style:O?.viewControls,children:[y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.zoomOut??`Zoom out`,"aria-label":T?.zoomOut??`Zoom out`,onClick:()=>kr(1/1.25),children:t(E?.zoomOut??Ze)}),b(`button`,{type:`button`,className:v(p.roomDrawerZoomLabel,D?.zoomLabel),style:O?.zoomLabel,title:T?.fit??`Fit to content`,onClick:()=>hr(),children:[Math.round(B.zoom*1e3)/10,`%`]}),y(`button`,{type:`button`,className:v(p.roomDrawerViewButton,D?.viewButton),style:O?.viewButton,title:T?.zoomIn??`Zoom in`,"aria-label":T?.zoomIn??`Zoom in`,onClick:()=>kr(1.25),children:t(E?.zoomIn??Qe)})]})]}),Ct&&M.floors.length>0&&b(`div`,{className:v(p.roomDrawerFloorBar,D?.floorBar),style:O?.floorBar,role:`tablist`,"aria-label":T?.selectedFloor??`Floor`,children:[[...M.floors].reverse().map(e=>y(`button`,{type:`button`,role:`tab`,className:v(p.roomDrawerFloorTab,e.id===N.id&&p.roomDrawerFloorTabActive,D?.floorTab),style:O?.floorTab,"aria-selected":e.id===N.id,onClick:()=>Pn(e.id),children:e.label},e.id)),q&&y(`button`,{type:`button`,className:v(p.roomDrawerFloorTab,p.roomDrawerFloorTabAdd),title:T?.addFloor??`Add a floor above`,"aria-label":T?.addFloor??`Add a floor above`,onClick:()=>Fr(),children:t(E?.addFloor??et)})]}),y(`div`,{ref:vn,className:v(p.roomDrawerCanvasWrapper,q&&F!==`select`&&p.roomDrawerCanvasWrapperDrawing,D?.canvasWrapper),style:{height:ln,...O?.canvasWrapper},onPointerDown:Tr,onPointerMove:Er,onPointerUp:e=>Dr(e,!1),onPointerCancel:e=>Dr(e,!0),children:y(Ne,{ref:yn,floor:N,underlay:Nn,rooms:P,view:B,size:H,selection:I,hovered:Un,interactiveRooms:!1,showGrid:er,gridSize:C,showRoomLabels:!0,formatArea:Xt,getRoomColor:un,renderRoomLabel:dn,overlay:Kr,classNames:D,styles:O})}),Qt&&q&&b(`div`,{className:v(p.roomDrawerInspector,D?.inspector),style:O?.inspector,children:[y(`span`,{className:v(p.roomDrawerInspectorKind,I.length===0&&p.roomDrawerInspectorKindEmpty,D?.inspectorLabel),children:Yr}),I.length===0&&b(ot,{children:[y(i,{className:v(p.roomDrawerInspectorName,D?.inspectorField),style:O?.inspectorField,label:T?.floorName??`Floor name`,value:N.label,onChange:e=>Br(N.id,e)}),y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.floorHeight??`Height (mm)`,title:T?.storeyHeightHint??`Storey height. The floors above move to sit on top of it.`,value:N.height,decimalScale:0,min:500,step:100,showArrows:!0,onChange:e=>{e!==void 0&&zr(N.id,e)}}),M.floors.length>1&&b(ot,{children:[y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,title:T?.moveFloorUp??`Move this floor up`,"aria-label":T?.moveFloorUp??`Move this floor up`,disabled:he(M,N.id)>=M.floors.length-1,onClick:()=>Rr(N.id,he(M,N.id)+1),children:t(E?.moveFloorUp??ze)}),y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,title:T?.moveFloorDown??`Move this floor down`,"aria-label":T?.moveFloorDown??`Move this floor down`,disabled:he(M,N.id)<=0,onClick:()=>Rr(N.id,he(M,N.id)-1),children:t(E?.moveFloorDown??Re)})]}),y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,title:T?.duplicateFloor??`Copy this floor to a new one above`,onClick:()=>Ir(),children:t(E?.duplicateFloor??We)}),M.floors.length>1&&y(n,{className:p.roomDrawerInspectorDelete,icon:E?.delete??rt,title:T?.deleteFloor??`Delete this floor`,onClick:()=>Lr()})]}),vr?.meta&&b(ot,{children:[y(i,{className:v(p.roomDrawerInspectorName,D?.inspectorField),style:O?.inspectorField,label:T?.roomName??`Room name`,value:vr.meta.name,onChange:e=>{let t=vr.meta;X({...N,rooms:{...N.rooms,[t.id]:{...t,name:e}}},`edit-room`,[t.id])}}),y(`span`,{className:v(p.roomDrawerInspectorLabel,D?.inspectorLabel),children:Xt(vr.area)})]}),Z&&y(`button`,{type:`button`,className:v(p.roomDrawerInspectorAction,D?.inspectorField),style:O?.inspectorField,onClick:xr,title:T?.addCorner??`Add a corner to this wall`,children:T?.addCorner??`Add corner`}),Z&&y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.thickness??`Thickness (mm)`,value:Z.thickness,decimalScale:0,min:10,showArrows:!0,step:10,onChange:e=>{e!==void 0&&X({...N,walls:{...N.walls,[Z.id]:{...Z,thickness:e}}},`edit-wall`,[Z.id])}}),yr&&b(ot,{children:[y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.width??`Width (mm)`,value:yr.width,decimalScale:0,min:100,step:50,showArrows:!0,onChange:e=>{e!==void 0&&X(ce(N,yr.id,{width:e}).floor,`edit-opening`,[yr.id])}}),y(Me,{className:v(p.roomDrawerInspectorField,D?.inspectorField),style:O?.inspectorField,label:T?.sill??`Sill (mm)`,title:T?.sillHeightHint??`How far above the floor the opening starts. Stored for a 3D view; it does not change the plan.`,showArrows:!0,value:yr.sill,decimalScale:0,min:0,step:50,onChange:e=>{e!==void 0&&X(ce(N,yr.id,{sill:e}).floor,`edit-opening`,[yr.id])}})]}),I.length>0&&y(n,{className:p.roomDrawerInspectorDelete,icon:E?.delete??rt,title:T?.deleteSelection??`Delete selection`,onClick:Cr})]}),tn&&q&&y(`input`,{ref:cr,type:`file`,accept:`application/json,.json`,className:p.roomDrawerFileInput,tabIndex:-1,"aria-hidden":`true`,onChange:e=>{let t=e.target.files?.[0];e.target.value=``,t&&Ur(t)}}),$t&&(ur!==null||Jr)&&y(`div`,{className:v(p.roomDrawerHint,ur!==null&&p.roomDrawerHintReport,D?.hint),style:O?.hint,role:ur===null?void 0:`status`,children:ur===null?Jr:ur.length===0?T?.importFailed??`That file could not be read as a floor plan`:ur.join(` · `)})]})});export{x as default};
|
|
2
2
|
//# sourceMappingURL=roomDrawer.mjs.map
|