@ahrowe/ui 0.29.0 → 0.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../ripple/ripple.mjs";import n from"../interactableDiv/index.mjs";import{CardStyleType as r}from"./card.types.mjs";import i from"./card.module.mjs";import{useRef as a}from"react";import o from"classnames";import{jsx as s}from"react/jsx-runtime";var c={elevated:i.cardStyleElevated,outlined:i.cardStyleOutlined,filled:i.cardStyleFilled};function l(l){let{className:u=void 0,children:d=null,styleType:f=r.Elevated,onClick:p=void 0,tabIndex:m=null,hoverEffect:h=void 0,style:g=void 0,autoGap:_=!0,clip:v=!1,onKeyDown:y,...b}=e(`Card`,l),x=!!p,S=a(null);function C(e){x&&(e.key===`Enter`||e.key===` `)&&S.current?.addRipple(),y?.(e)}return s(n,{...b,className:o(i.card,c[f],v&&i.cardClip,x&&i.cardInteractable,(x&&h!==!1||h)&&i.cardHover,u),onClick:p,onKeyDown:C,tabIndex:m??(x?0:null),style:g,children:s(t,{ref:S,disabled:!x,className:o(i.cardPadding,_&&i.cardGaps),style:{borderRadius:`inherit`},children:d})})}export{l as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../ripple/ripple.mjs";import{isSelfActivation as n}from"../utils/activationKey.mjs";import r from"../interactableDiv/index.mjs";import{CardStyleType as i}from"./card.types.mjs";import a from"./card.module.mjs";import{useRef as o}from"react";import s from"classnames";import{jsx as c}from"react/jsx-runtime";var l={elevated:a.cardStyleElevated,outlined:a.cardStyleOutlined,filled:a.cardStyleFilled};function u(u){let{className:d=void 0,children:f=null,styleType:p=i.Elevated,onClick:m=void 0,tabIndex:h=null,hoverEffect:g=void 0,style:_=void 0,autoGap:v=!0,clip:y=!1,onKeyDown:b,...x}=e(`Card`,u),S=!!m,C=o(null);function w(e){S&&n(e)&&C.current?.addRipple(),b?.(e)}return c(r,{...x,className:s(a.card,l[p],y&&a.cardClip,S&&a.cardInteractable,(S&&g!==!1||g)&&a.cardHover,d),onClick:m,onKeyDown:w,tabIndex:h??(S?0:null),style:_,children:c(t,{ref:C,disabled:!S,className:s(a.cardPadding,v&&a.cardGaps),style:{borderRadius:`inherit`},children:f})})}export{u as default};
2
2
  //# sourceMappingURL=Card.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"Card.mjs","names":[],"sources":["../../../../package/common/card/Card.tsx"],"sourcesContent":["import cx from 'classnames';\nimport React, { useRef } from 'react';\n\nimport { CardStyleType, type CardProps } from './card.types';\nimport styles from './card.module.pcss';\nimport InteractableDiv from '../interactableDiv';\nimport Ripple from '../ripple';\nimport type { RippleHandle } from '../ripple';\nimport { useComponentDefaults } from '../configProvider';\n\nconst CLASS_BY_STYLE: Record<CardStyleType, string> = {\n elevated: styles.cardStyleElevated,\n outlined: styles.cardStyleOutlined,\n filled: styles.cardStyleFilled,\n};\n\nfunction Card(props: CardProps) {\n const {\n className = undefined,\n children = null,\n styleType = CardStyleType.Elevated,\n onClick = undefined,\n tabIndex = null,\n hoverEffect = undefined,\n style = undefined,\n autoGap = true,\n clip = false,\n onKeyDown: onKeyDownProp,\n ...rest\n } = useComponentDefaults('Card', props);\n const isInteractable = !!onClick;\n\n const rippleRef = useRef<RippleHandle>(null);\n\n // Keyboard activation calls onClick directly without dispatching a DOM click, so Ripple's own\n // listener never sees it.\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n if (isInteractable && (event.key === 'Enter' || event.key === ' ')) rippleRef.current?.addRipple();\n onKeyDownProp?.(event);\n }\n\n return (\n <InteractableDiv\n {...rest}\n className={cx(\n styles.card,\n CLASS_BY_STYLE[styleType],\n clip && styles.cardClip,\n isInteractable && styles.cardInteractable,\n ((isInteractable && hoverEffect !== false) || hoverEffect) && styles.cardHover,\n className,\n )}\n onClick={onClick}\n onKeyDown={handleKeyDown}\n tabIndex={tabIndex ?? (isInteractable ? 0 : null)}\n style={style}\n >\n <Ripple\n ref={rippleRef}\n disabled={!isInteractable}\n className={cx(styles.cardPadding, autoGap && styles.cardGaps)}\n style={{ borderRadius: 'inherit' }}\n >\n {children}\n </Ripple>\n </InteractableDiv>\n );\n}\n\nexport default Card;\n"],"mappings":"qVAUA,IAAM,EAAgD,CACpD,SAAU,EAAO,kBACjB,SAAU,EAAO,kBACjB,OAAQ,EAAO,eACjB,EAEA,SAAS,EAAK,EAAkB,CAC9B,GAAM,CACJ,YAAY,IAAA,GACZ,WAAW,KACX,YAAY,EAAc,SAC1B,UAAU,IAAA,GACV,WAAW,KACX,cAAc,IAAA,GACd,QAAQ,IAAA,GACR,UAAU,GACV,OAAO,GACP,UAAW,EACX,GAAG,GACD,EAAqB,OAAQ,CAAK,EAChC,EAAiB,CAAC,CAAC,EAEnB,EAAY,EAAqB,IAAI,EAI3C,SAAS,EAAc,EAA4C,CAC7D,IAAmB,EAAM,MAAQ,SAAW,EAAM,MAAQ,MAAM,EAAU,SAAS,UAAU,EACjG,IAAgB,CAAK,CACvB,CAEA,OACE,EAAC,EAAD,CACE,GAAI,EACJ,UAAW,EACT,EAAO,KACP,EAAe,GACf,GAAQ,EAAO,SACf,GAAkB,EAAO,kBACvB,GAAkB,IAAgB,IAAU,IAAgB,EAAO,UACrE,CACF,EACS,UACT,UAAW,EACX,SAAU,IAAa,EAAiB,EAAI,MACrC,QAEP,SAAA,EAAC,EAAD,CACE,IAAK,EACL,SAAU,CAAC,EACX,UAAW,EAAG,EAAO,YAAa,GAAW,EAAO,QAAQ,EAC5D,MAAO,CAAE,aAAc,SAAU,EAEhC,UACK,CAAA,CACO,CAAA,CAErB"}
1
+ {"version":3,"file":"Card.mjs","names":[],"sources":["../../../../package/common/card/Card.tsx"],"sourcesContent":["import cx from 'classnames';\nimport React, { useRef } from 'react';\n\nimport { CardStyleType, type CardProps } from './card.types';\nimport styles from './card.module.pcss';\nimport InteractableDiv from '../interactableDiv';\nimport Ripple from '../ripple';\nimport type { RippleHandle } from '../ripple';\nimport { useComponentDefaults } from '../configProvider';\nimport { isSelfActivation } from '../utils/activationKey';\n\nconst CLASS_BY_STYLE: Record<CardStyleType, string> = {\n elevated: styles.cardStyleElevated,\n outlined: styles.cardStyleOutlined,\n filled: styles.cardStyleFilled,\n};\n\nfunction Card(props: CardProps) {\n const {\n className = undefined,\n children = null,\n styleType = CardStyleType.Elevated,\n onClick = undefined,\n tabIndex = null,\n hoverEffect = undefined,\n style = undefined,\n autoGap = true,\n clip = false,\n onKeyDown: onKeyDownProp,\n ...rest\n } = useComponentDefaults('Card', props);\n const isInteractable = !!onClick;\n\n const rippleRef = useRef<RippleHandle>(null);\n\n // Keyboard activation calls onClick directly without dispatching a DOM click, so Ripple's own\n // listener never sees it.\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n if (isInteractable && isSelfActivation(event)) rippleRef.current?.addRipple();\n onKeyDownProp?.(event);\n }\n\n return (\n <InteractableDiv\n {...rest}\n className={cx(\n styles.card,\n CLASS_BY_STYLE[styleType],\n clip && styles.cardClip,\n isInteractable && styles.cardInteractable,\n ((isInteractable && hoverEffect !== false) || hoverEffect) && styles.cardHover,\n className,\n )}\n onClick={onClick}\n onKeyDown={handleKeyDown}\n tabIndex={tabIndex ?? (isInteractable ? 0 : null)}\n style={style}\n >\n <Ripple\n ref={rippleRef}\n disabled={!isInteractable}\n className={cx(styles.cardPadding, autoGap && styles.cardGaps)}\n style={{ borderRadius: 'inherit' }}\n >\n {children}\n </Ripple>\n </InteractableDiv>\n );\n}\n\nexport default Card;\n"],"mappings":"mZAWA,IAAM,EAAgD,CACpD,SAAU,EAAO,kBACjB,SAAU,EAAO,kBACjB,OAAQ,EAAO,eACjB,EAEA,SAAS,EAAK,EAAkB,CAC9B,GAAM,CACJ,YAAY,IAAA,GACZ,WAAW,KACX,YAAY,EAAc,SAC1B,UAAU,IAAA,GACV,WAAW,KACX,cAAc,IAAA,GACd,QAAQ,IAAA,GACR,UAAU,GACV,OAAO,GACP,UAAW,EACX,GAAG,GACD,EAAqB,OAAQ,CAAK,EAChC,EAAiB,CAAC,CAAC,EAEnB,EAAY,EAAqB,IAAI,EAI3C,SAAS,EAAc,EAA4C,CAC7D,GAAkB,EAAiB,CAAK,GAAG,EAAU,SAAS,UAAU,EAC5E,IAAgB,CAAK,CACvB,CAEA,OACE,EAAC,EAAD,CACE,GAAI,EACJ,UAAW,EACT,EAAO,KACP,EAAe,GACf,GAAQ,EAAO,SACf,GAAkB,EAAO,kBACvB,GAAkB,IAAgB,IAAU,IAAgB,EAAO,UACrE,CACF,EACS,UACT,UAAW,EACX,SAAU,IAAa,EAAiB,EAAI,MACrC,QAEP,SAAA,EAAC,EAAD,CACE,IAAK,EACL,SAAU,CAAC,EACX,UAAW,EAAG,EAAO,YAAa,GAAW,EAAO,QAAQ,EAC5D,MAAO,CAAE,aAAc,SAAU,EAEhC,UACK,CAAA,CACO,CAAA,CAErB"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../ripple/ripple.mjs";import n from"../interactableDiv/index.mjs";import r from"../actionIcon/actionIcon.mjs";import{ChipStyleType as i}from"./chip.types.mjs";import a from"./chip.module.mjs";import{useMemo as o,useRef as s}from"react";import c from"classnames";import{faXmarkCircle as l}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var f={default:a.chipStyleDefault,primary:a.chipStylePrimary,info:a.chipStyleInfo,warn:a.chipStyleWarn,error:a.chipStyleError};function p(p){let{className:m=``,thumbnail:h=``,text:g=``,styleType:_=i.Default,showRemoveIcon:v=!1,removeLabel:y=`Remove`,onClick:b,onRemove:x,...S}=e(`Chip`,p),C=s(null);function w(e){b&&(e.key===`Enter`||e.key===` `)&&C.current?.addRipple()}let T=o(()=>{if(typeof h==`string`&&h.startsWith(`http`))return h},[h]);return u(n,{...S,className:c(a.chip,f[_],b&&a.chipClickable,m),onClick:b,onKeyDown:w,children:u(t,{ref:C,disabled:!b,style:{borderRadius:`inherit`},children:d(`div`,{className:a.chipInner,children:[h&&u(`div`,{className:a.chipThumbnail,style:T?{backgroundImage:`url(${T})`}:{},children:!T&&h}),u(`div`,{className:a.chipText,children:g}),v&&u(r,{icon:l,"aria-label":y,onClick:e=>{e.stopPropagation(),x?.()}})]})})})}export{p as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../ripple/ripple.mjs";import{isSelfActivation as n}from"../utils/activationKey.mjs";import r from"../interactableDiv/index.mjs";import i from"../actionIcon/actionIcon.mjs";import{ChipStyleType as a}from"./chip.types.mjs";import o from"./chip.module.mjs";import{useMemo as s,useRef as c}from"react";import l from"classnames";import{faXmarkCircle as u}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var p={default:o.chipStyleDefault,primary:o.chipStylePrimary,info:o.chipStyleInfo,warn:o.chipStyleWarn,error:o.chipStyleError};function m(m){let{className:h=``,thumbnail:g=``,text:_=``,styleType:v=a.Default,showRemoveIcon:y=!1,removeLabel:b=`Remove`,onClick:x,onRemove:S,...C}=e(`Chip`,m),w=c(null);function T(e){x&&n(e)&&w.current?.addRipple()}let E=s(()=>{if(typeof g==`string`&&g.startsWith(`http`))return g},[g]);return d(r,{...C,className:l(o.chip,p[v],x&&o.chipClickable,h),onClick:x,onKeyDown:T,children:d(t,{ref:w,disabled:!x,style:{borderRadius:`inherit`},children:f(`div`,{className:o.chipInner,children:[g&&d(`div`,{className:o.chipThumbnail,style:E?{backgroundImage:`url(${E})`}:{},children:!E&&g}),d(`div`,{className:o.chipText,children:_}),y&&d(i,{icon:u,"aria-label":b,onClick:e=>{e.stopPropagation(),S?.()}})]})})})}export{m as default};
2
2
  //# sourceMappingURL=chip.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"chip.mjs","names":[],"sources":["../../../../package/common/chip/chip.tsx"],"sourcesContent":["import React, { useMemo, useRef } from 'react';\nimport { faXmarkCircle } from '@fortawesome/free-solid-svg-icons';\nimport cx from 'classnames';\n\nimport Ripple from '../ripple';\nimport type { RippleHandle } from '../ripple';\nimport InteractableDiv from '../interactableDiv';\nimport ActionIcon from '../actionIcon';\nimport { ChipStyleType, ChipProps } from './chip.types';\nimport { useComponentDefaults } from '../configProvider';\n\nimport styles from './chip.module.pcss';\n\nconst CLASS_BY_STYLE: Record<ChipStyleType, string> = {\n default: styles.chipStyleDefault,\n primary: styles.chipStylePrimary,\n info: styles.chipStyleInfo,\n warn: styles.chipStyleWarn,\n error: styles.chipStyleError,\n};\n\nfunction Chip(props: ChipProps) {\n const {\n className = '',\n thumbnail = '',\n text = '',\n styleType = ChipStyleType.Default,\n showRemoveIcon = false,\n removeLabel = 'Remove',\n onClick,\n onRemove,\n ...rest\n } = useComponentDefaults('Chip', props);\n const rippleRef = useRef<RippleHandle>(null);\n\n // Keyboard activation calls onClick directly without dispatching a DOM click, so Ripple's own\n // listener never sees it.\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n if (onClick && (event.key === 'Enter' || event.key === ' ')) rippleRef.current?.addRipple();\n }\n\n const thumbnailUrl = useMemo(() => {\n if (typeof thumbnail === 'string' && thumbnail.startsWith('http')) return thumbnail;\n return undefined;\n }, [thumbnail]);\n\n return (\n <InteractableDiv\n {...rest}\n className={cx(styles.chip, CLASS_BY_STYLE[styleType], onClick && styles.chipClickable, className)}\n onClick={onClick}\n onKeyDown={handleKeyDown}\n >\n <Ripple ref={rippleRef} disabled={!onClick} style={{ borderRadius: 'inherit' }}>\n <div className={styles.chipInner}>\n {thumbnail && (\n <div\n className={styles.chipThumbnail}\n style={thumbnailUrl ? { backgroundImage: `url(${thumbnailUrl})` } : {}}\n >\n {!thumbnailUrl && thumbnail}\n </div>\n )}\n <div className={styles.chipText}>{text}</div>\n {showRemoveIcon && (\n <ActionIcon\n icon={faXmarkCircle}\n aria-label={removeLabel}\n onClick={(e) => {\n e.stopPropagation();\n onRemove?.();\n }}\n />\n )}\n </div>\n </Ripple>\n </InteractableDiv>\n );\n}\n\nexport default Chip;\n"],"mappings":"0dAaA,IAAM,EAAgD,CACpD,QAAS,EAAO,iBAChB,QAAS,EAAO,iBAChB,KAAM,EAAO,cACb,KAAM,EAAO,cACb,MAAO,EAAO,cAChB,EAEA,SAAS,EAAK,EAAkB,CAC9B,GAAM,CACJ,YAAY,GACZ,YAAY,GACZ,OAAO,GACP,YAAY,EAAc,QAC1B,iBAAiB,GACjB,cAAc,SACd,UACA,WACA,GAAG,GACD,EAAqB,OAAQ,CAAK,EAChC,EAAY,EAAqB,IAAI,EAI3C,SAAS,EAAc,EAA4C,CAC7D,IAAY,EAAM,MAAQ,SAAW,EAAM,MAAQ,MAAM,EAAU,SAAS,UAAU,CAC5F,CAEA,IAAM,EAAe,MAAc,CACjC,GAAI,OAAO,GAAc,UAAY,EAAU,WAAW,MAAM,EAAG,OAAO,CAE5E,EAAG,CAAC,CAAS,CAAC,EAEd,OACE,EAAC,EAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,KAAM,EAAe,GAAY,GAAW,EAAO,cAAe,CAAS,EACvF,UACT,UAAW,EAEX,SAAA,EAAC,EAAD,CAAQ,IAAK,EAAW,SAAU,CAAC,EAAS,MAAO,CAAE,aAAc,SAAU,EAC3E,SAAA,EAAC,MAAD,CAAK,UAAW,EAAO,UAAvB,SAAA,CACG,GACC,EAAC,MAAD,CACE,UAAW,EAAO,cAClB,MAAO,EAAe,CAAE,gBAAiB,OAAO,EAAa,EAAG,EAAI,CAAC,EAEpE,SAAA,CAAC,GAAgB,CACf,CAAA,EAEP,EAAC,MAAD,CAAK,UAAW,EAAO,SAAW,SAAA,CAAU,CAAA,EAC3C,GACC,EAAC,EAAD,CACE,KAAM,EACN,aAAY,EACZ,QAAU,GAAM,CACd,EAAE,gBAAgB,EAClB,IAAW,CACb,CACD,CAAA,CAEA,GACC,CAAA,CACO,CAAA,CAErB"}
1
+ {"version":3,"file":"chip.mjs","names":[],"sources":["../../../../package/common/chip/chip.tsx"],"sourcesContent":["import React, { useMemo, useRef } from 'react';\nimport { faXmarkCircle } from '@fortawesome/free-solid-svg-icons';\nimport cx from 'classnames';\n\nimport Ripple from '../ripple';\nimport type { RippleHandle } from '../ripple';\nimport InteractableDiv from '../interactableDiv';\nimport ActionIcon from '../actionIcon';\nimport { ChipStyleType, ChipProps } from './chip.types';\nimport { useComponentDefaults } from '../configProvider';\nimport { isSelfActivation } from '../utils/activationKey';\n\nimport styles from './chip.module.pcss';\n\nconst CLASS_BY_STYLE: Record<ChipStyleType, string> = {\n default: styles.chipStyleDefault,\n primary: styles.chipStylePrimary,\n info: styles.chipStyleInfo,\n warn: styles.chipStyleWarn,\n error: styles.chipStyleError,\n};\n\nfunction Chip(props: ChipProps) {\n const {\n className = '',\n thumbnail = '',\n text = '',\n styleType = ChipStyleType.Default,\n showRemoveIcon = false,\n removeLabel = 'Remove',\n onClick,\n onRemove,\n ...rest\n } = useComponentDefaults('Chip', props);\n const rippleRef = useRef<RippleHandle>(null);\n\n // Keyboard activation calls onClick directly without dispatching a DOM click, so Ripple's own\n // listener never sees it.\n function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n if (onClick && isSelfActivation(event)) rippleRef.current?.addRipple();\n }\n\n const thumbnailUrl = useMemo(() => {\n if (typeof thumbnail === 'string' && thumbnail.startsWith('http')) return thumbnail;\n return undefined;\n }, [thumbnail]);\n\n return (\n <InteractableDiv\n {...rest}\n className={cx(styles.chip, CLASS_BY_STYLE[styleType], onClick && styles.chipClickable, className)}\n onClick={onClick}\n onKeyDown={handleKeyDown}\n >\n <Ripple ref={rippleRef} disabled={!onClick} style={{ borderRadius: 'inherit' }}>\n <div className={styles.chipInner}>\n {thumbnail && (\n <div\n className={styles.chipThumbnail}\n style={thumbnailUrl ? { backgroundImage: `url(${thumbnailUrl})` } : {}}\n >\n {!thumbnailUrl && thumbnail}\n </div>\n )}\n <div className={styles.chipText}>{text}</div>\n {showRemoveIcon && (\n <ActionIcon\n icon={faXmarkCircle}\n aria-label={removeLabel}\n onClick={(e) => {\n e.stopPropagation();\n onRemove?.();\n }}\n />\n )}\n </div>\n </Ripple>\n </InteractableDiv>\n );\n}\n\nexport default Chip;\n"],"mappings":"whBAcA,IAAM,EAAgD,CACpD,QAAS,EAAO,iBAChB,QAAS,EAAO,iBAChB,KAAM,EAAO,cACb,KAAM,EAAO,cACb,MAAO,EAAO,cAChB,EAEA,SAAS,EAAK,EAAkB,CAC9B,GAAM,CACJ,YAAY,GACZ,YAAY,GACZ,OAAO,GACP,YAAY,EAAc,QAC1B,iBAAiB,GACjB,cAAc,SACd,UACA,WACA,GAAG,GACD,EAAqB,OAAQ,CAAK,EAChC,EAAY,EAAqB,IAAI,EAI3C,SAAS,EAAc,EAA4C,CAC7D,GAAW,EAAiB,CAAK,GAAG,EAAU,SAAS,UAAU,CACvE,CAEA,IAAM,EAAe,MAAc,CACjC,GAAI,OAAO,GAAc,UAAY,EAAU,WAAW,MAAM,EAAG,OAAO,CAE5E,EAAG,CAAC,CAAS,CAAC,EAEd,OACE,EAAC,EAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,KAAM,EAAe,GAAY,GAAW,EAAO,cAAe,CAAS,EACvF,UACT,UAAW,EAEX,SAAA,EAAC,EAAD,CAAQ,IAAK,EAAW,SAAU,CAAC,EAAS,MAAO,CAAE,aAAc,SAAU,EAC3E,SAAA,EAAC,MAAD,CAAK,UAAW,EAAO,UAAvB,SAAA,CACG,GACC,EAAC,MAAD,CACE,UAAW,EAAO,cAClB,MAAO,EAAe,CAAE,gBAAiB,OAAO,EAAa,EAAG,EAAI,CAAC,EAEpE,SAAA,CAAC,GAAgB,CACf,CAAA,EAEP,EAAC,MAAD,CAAK,UAAW,EAAO,SAAW,SAAA,CAAU,CAAA,EAC3C,GACC,EAAC,EAAD,CACE,KAAM,EACN,aAAY,EACZ,QAAU,GAAM,CACd,EAAE,gBAAgB,EAClB,IAAW,CACb,CACD,CAAA,CAEA,GACC,CAAA,CACO,CAAA,CAErB"}
@@ -1,2 +1,2 @@
1
- import{DropZoneReturnType as e,DropZoneStatus as t}from"./dropZone.types.mjs";import n from"./dropZone.module.mjs";import{useCallback as r,useEffect as i,useId 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";function d(e,t){if(!t.length)return!0;let n=e.name.toLowerCase(),r=e.type.toLowerCase();return t.some(e=>{let t=e.trim().toLowerCase();return t?t.startsWith(`.`)?n.endsWith(t):t.endsWith(`/*`)?r.startsWith(t.slice(0,-1)):r===t:!1})}function f(t,n){return n===e.File?Promise.resolve({ok:!0,value:t}):new Promise(r=>{let i=new FileReader;i.onload=e=>{let n=e.target?.result;if(typeof n!=`string`){r({ok:!1});return}r({ok:!0,value:{name:t.name,size:t.size,type:t.type,lastModified:t.lastModified,data:n}})},i.onerror=()=>r({ok:!1}),n===e.Base64?i.readAsDataURL(t):i.readAsText(t)})}function p(e){return new Promise(t=>{if(e.isFile)e.file(e=>t([e]),()=>t([]));else if(e.isDirectory){let n=e.createReader(),r=[],i=()=>{n.readEntries(e=>{e.length?(r.push(...e),i()):Promise.all(r.map(p)).then(e=>t(e.flat()))},()=>t([]))};i()}else t([])})}function m(e,t){let n=e.items;if(n&&n.length){if(t&&typeof n[0].webkitGetAsEntry==`function`){let e=[];for(let t=0;t<n.length;t+=1)if(n[t].kind===`file`){let r=n[t].webkitGetAsEntry();r&&e.push(r)}if(e.length)return Promise.all(e.map(p)).then(e=>e.flat())}let e=[];for(let t=0;t<n.length;t+=1)if(n[t].kind===`file`){let r=n[t].getAsFile();r&&e.push(r)}return Promise.resolve(e)}return Promise.resolve(Array.from(e.files||[]))}function h({children:p,acceptedTypes:h=[],returnType:g=e.File,openPickerOnClick:_=!1,multiple:v=!0,maxFiles:y,maxSize:b,enablePaste:x=!1,allowDirectories:S=!0,capture:C,disabled:w=!1,unstyled:T=!1,showFileNames:E=!1,files:D,onFilesChanged:O,onReject:k,onStatusChanged:A,className:j,style:M,classNames:N,styles:P,...F}){let[I,L]=s(t.Idle),R=o(null),z=a(),B=o(I),V=o(0),H=o(0),U=o({acceptedTypes:h,returnType:g,multiple:v,maxFiles:y,maxSize:b,allowDirectories:S,disabled:w,onFilesChanged:O,onReject:k,onStatusChanged:A});i(()=>{U.current={acceptedTypes:h,returnType:g,multiple:v,maxFiles:y,maxSize:b,allowDirectories:S,disabled:w,onFilesChanged:O,onReject:k,onStatusChanged:A}});let W=r(e=>{B.current!==e&&(B.current=e,L(e),U.current.onStatusChanged?.(e))},[]),G=r(async e=>{let n=U.current,r=[],i=[];for(let t of e)d(t,n.acceptedTypes)?n.maxSize!=null&&t.size>n.maxSize?r.push({file:t,reason:`tooLarge`}):i.push(t):r.push({file:t,reason:`unacceptedType`});n.multiple||(i=i.slice(0,1)),n.maxFiles!=null&&i.length>n.maxFiles&&(i.slice(n.maxFiles).forEach(e=>r.push({file:e,reason:`tooMany`})),i=i.slice(0,n.maxFiles));let a=await Promise.all(i.map(e=>f(e,n.returnType))),o=[];a.forEach((e,t)=>{e.ok?o.push(e.value):r.push({file:i[t],reason:`readError`})}),r.length&&n.onReject?.(r),W(r.length&&!o.length?t.Error:t.Idle),o.length&&n.onFilesChanged?.(o)},[W]);i(()=>{let e=e=>!e||Array.from(e.types||[]).includes(`Files`),n=n=>{!U.current.disabled&&e(n.dataTransfer)&&(V.current+=1,(B.current===t.Idle||B.current===t.Error)&&W(t.Dragging))},r=()=>{V.current=Math.max(0,V.current-1),V.current===0&&B.current===t.Dragging&&W(t.Idle)},i=()=>{V.current=0,H.current=0,B.current===t.Dragging&&W(t.Idle)};return window.addEventListener(`dragenter`,n),window.addEventListener(`dragleave`,r),window.addEventListener(`drop`,i),()=>{window.removeEventListener(`dragenter`,n),window.removeEventListener(`dragleave`,r),window.removeEventListener(`drop`,i)}},[W]);let K=r(e=>{e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect=w?`none`:`copy`)},[w]),q=r(e=>{e.preventDefault(),e.stopPropagation(),!w&&(H.current+=1,W(t.Active))},[w,W]),J=r(e=>{e.preventDefault(),e.stopPropagation(),H.current=Math.max(0,H.current-1),H.current===0&&W(V.current>0?t.Dragging:t.Idle)},[W]),Y=r(e=>{if(e.preventDefault(),e.stopPropagation(),H.current=0,V.current=0,w||!e.dataTransfer){W(t.Idle);return}W(t.Idle),m(e.dataTransfer,U.current.allowDirectories).then(e=>{e.length&&G(e)})},[w,W,G]),X=r(()=>{!w&&_&&R.current?.click()},[w,_]),Z=r(e=>{let t=Array.from(e.target.files||[]);e.target.value=``,t.length&&G(t)},[G]),Q=r(e=>{if(!x||w)return;let t=Array.from(e.clipboardData?.files||[]);t.length&&(e.preventDefault(),G(t))},[x,w,G]),ee=r(e=>{_&&!w&&(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),X())},[_,w,X]),$=I===t.Dragging||I===t.Active,te={status:I,isDragging:$,isActive:I===t.Active,disabled:w},ne=h.length?h.join(`,`):void 0;return u(`div`,{...F,className:c(n.dropZone,_&&n.dropZoneClickable,w&&n.dropZoneDisabled,!T&&n.dropZoneDefault,!T&&I===t.Dragging&&n.dropZoneDragging,!T&&I===t.Active&&n.dropZoneActive,!T&&I===t.Error&&n.dropZoneError,N?.root,j),style:{...P?.root,...M},onDragEnter:q,onDragLeave:J,onDragOver:K,onDrop:Y,onClick:X,onKeyDown:ee,onPaste:x?Q:void 0,role:_?`button`:void 0,tabIndex:_&&!w?0:void 0,"aria-disabled":w||void 0,children:[l(`div`,{className:c(n.dropZoneContent,$&&n.dropZoneContentDragging,N?.content),style:P?.content,children:typeof p==`function`?p(te):p}),E&&D&&D.length>0&&l(`div`,{className:c(n.dropZoneFileList,N?.fileList),style:P?.fileList,children:D.map((e,t)=>l(`div`,{className:c(n.dropZoneFileItem,N?.fileItem),style:P?.fileItem,children:e.name},`${e.name}-${t}`))}),l(`input`,{ref:R,id:z,type:`file`,className:c(n.dropZoneInput,N?.input),style:P?.input,accept:ne,multiple:v,capture:C,disabled:w,onChange:Z,tabIndex:-1,"aria-hidden":`true`})]})}export{h as default};
1
+ import{isSelfActivation as e}from"../utils/activationKey.mjs";import{DropZoneReturnType as t,DropZoneStatus as n}from"./dropZone.types.mjs";import r from"./dropZone.module.mjs";import{useCallback as i,useEffect as a,useId as o,useRef as s,useState as c}from"react";import l from"classnames";import{jsx as u,jsxs as d}from"react/jsx-runtime";function f(e,t){if(!t.length)return!0;let n=e.name.toLowerCase(),r=e.type.toLowerCase();return t.some(e=>{let t=e.trim().toLowerCase();return t?t.startsWith(`.`)?n.endsWith(t):t.endsWith(`/*`)?r.startsWith(t.slice(0,-1)):r===t:!1})}function p(e,n){return n===t.File?Promise.resolve({ok:!0,value:e}):new Promise(r=>{let i=new FileReader;i.onload=t=>{let n=t.target?.result;if(typeof n!=`string`){r({ok:!1});return}r({ok:!0,value:{name:e.name,size:e.size,type:e.type,lastModified:e.lastModified,data:n}})},i.onerror=()=>r({ok:!1}),n===t.Base64?i.readAsDataURL(e):i.readAsText(e)})}function m(e){return new Promise(t=>{if(e.isFile)e.file(e=>t([e]),()=>t([]));else if(e.isDirectory){let n=e.createReader(),r=[],i=()=>{n.readEntries(e=>{e.length?(r.push(...e),i()):Promise.all(r.map(m)).then(e=>t(e.flat()))},()=>t([]))};i()}else t([])})}function h(e,t){let n=e.items;if(n&&n.length){if(t&&typeof n[0].webkitGetAsEntry==`function`){let e=[];for(let t=0;t<n.length;t+=1)if(n[t].kind===`file`){let r=n[t].webkitGetAsEntry();r&&e.push(r)}if(e.length)return Promise.all(e.map(m)).then(e=>e.flat())}let e=[];for(let t=0;t<n.length;t+=1)if(n[t].kind===`file`){let r=n[t].getAsFile();r&&e.push(r)}return Promise.resolve(e)}return Promise.resolve(Array.from(e.files||[]))}function g({children:m,acceptedTypes:g=[],returnType:_=t.File,openPickerOnClick:v=!1,multiple:y=!0,maxFiles:b,maxSize:x,enablePaste:S=!1,allowDirectories:C=!0,capture:w,disabled:T=!1,unstyled:E=!1,showFileNames:D=!1,files:O,onFilesChanged:k,onReject:A,onStatusChanged:j,className:M,style:N,classNames:P,styles:F,...I}){let[L,ee]=c(n.Idle),R=s(null),z=o(),B=s(L),V=s(0),H=s(0),U=s({acceptedTypes:g,returnType:_,multiple:y,maxFiles:b,maxSize:x,allowDirectories:C,disabled:T,onFilesChanged:k,onReject:A,onStatusChanged:j});a(()=>{U.current={acceptedTypes:g,returnType:_,multiple:y,maxFiles:b,maxSize:x,allowDirectories:C,disabled:T,onFilesChanged:k,onReject:A,onStatusChanged:j}});let W=i(e=>{B.current!==e&&(B.current=e,ee(e),U.current.onStatusChanged?.(e))},[]),G=i(async e=>{let t=U.current,r=[],i=[];for(let n of e)f(n,t.acceptedTypes)?t.maxSize!=null&&n.size>t.maxSize?r.push({file:n,reason:`tooLarge`}):i.push(n):r.push({file:n,reason:`unacceptedType`});t.multiple||(i=i.slice(0,1)),t.maxFiles!=null&&i.length>t.maxFiles&&(i.slice(t.maxFiles).forEach(e=>r.push({file:e,reason:`tooMany`})),i=i.slice(0,t.maxFiles));let a=await Promise.all(i.map(e=>p(e,t.returnType))),o=[];a.forEach((e,t)=>{e.ok?o.push(e.value):r.push({file:i[t],reason:`readError`})}),r.length&&t.onReject?.(r),W(r.length&&!o.length?n.Error:n.Idle),o.length&&t.onFilesChanged?.(o)},[W]);a(()=>{let e=e=>!e||Array.from(e.types||[]).includes(`Files`),t=t=>{!U.current.disabled&&e(t.dataTransfer)&&(V.current+=1,(B.current===n.Idle||B.current===n.Error)&&W(n.Dragging))},r=()=>{V.current=Math.max(0,V.current-1),V.current===0&&B.current===n.Dragging&&W(n.Idle)},i=()=>{V.current=0,H.current=0,B.current===n.Dragging&&W(n.Idle)};return window.addEventListener(`dragenter`,t),window.addEventListener(`dragleave`,r),window.addEventListener(`drop`,i),()=>{window.removeEventListener(`dragenter`,t),window.removeEventListener(`dragleave`,r),window.removeEventListener(`drop`,i)}},[W]);let K=i(e=>{e.preventDefault(),e.stopPropagation(),e.dataTransfer&&(e.dataTransfer.dropEffect=T?`none`:`copy`)},[T]),q=i(e=>{e.preventDefault(),e.stopPropagation(),!T&&(H.current+=1,W(n.Active))},[T,W]),J=i(e=>{e.preventDefault(),e.stopPropagation(),H.current=Math.max(0,H.current-1),H.current===0&&W(V.current>0?n.Dragging:n.Idle)},[W]),Y=i(e=>{if(e.preventDefault(),e.stopPropagation(),H.current=0,V.current=0,T||!e.dataTransfer){W(n.Idle);return}W(n.Idle),h(e.dataTransfer,U.current.allowDirectories).then(e=>{e.length&&G(e)})},[T,W,G]),X=i(()=>{!T&&v&&R.current?.click()},[T,v]),Z=i(e=>{let t=Array.from(e.target.files||[]);e.target.value=``,t.length&&G(t)},[G]),Q=i(e=>{if(!S||T)return;let t=Array.from(e.clipboardData?.files||[]);t.length&&(e.preventDefault(),G(t))},[S,T,G]),te=i(t=>{v&&!T&&e(t)&&(t.preventDefault(),X())},[v,T,X]),$=L===n.Dragging||L===n.Active,ne={status:L,isDragging:$,isActive:L===n.Active,disabled:T},re=g.length?g.join(`,`):void 0;return d(`div`,{...I,className:l(r.dropZone,v&&r.dropZoneClickable,T&&r.dropZoneDisabled,!E&&r.dropZoneDefault,!E&&L===n.Dragging&&r.dropZoneDragging,!E&&L===n.Active&&r.dropZoneActive,!E&&L===n.Error&&r.dropZoneError,P?.root,M),style:{...F?.root,...N},onDragEnter:q,onDragLeave:J,onDragOver:K,onDrop:Y,onClick:X,onKeyDown:te,onPaste:S?Q:void 0,role:v?`button`:void 0,tabIndex:v&&!T?0:void 0,"aria-disabled":T||void 0,children:[u(`div`,{className:l(r.dropZoneContent,$&&r.dropZoneContentDragging,P?.content),style:F?.content,children:typeof m==`function`?m(ne):m}),D&&O&&O.length>0&&u(`div`,{className:l(r.dropZoneFileList,P?.fileList),style:F?.fileList,children:O.map((e,t)=>u(`div`,{className:l(r.dropZoneFileItem,P?.fileItem),style:F?.fileItem,children:e.name},`${e.name}-${t}`))}),u(`input`,{ref:R,id:z,type:`file`,className:l(r.dropZoneInput,P?.input),style:F?.input,accept:re,multiple:y,capture:w,disabled:T,onChange:Z,tabIndex:-1,"aria-hidden":`true`})]})}export{g as default};
2
2
  //# sourceMappingURL=dropZone.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dropZone.mjs","names":[],"sources":["../../../../package/common/dropZone/dropZone.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport cx from 'classnames';\n\nimport {\n DropZoneProps,\n DropZoneReturnType,\n DropZoneStatus,\n DropZoneRejection,\n DropZoneRenderState,\n LoadedFile,\n} from './dropZone.types';\n\nimport styles from './dropZone.module.pcss';\n\n// ── Pure helpers ──────────────────────────────────────────────────────────────\n\n/** True when a file matches one of the accepted tokens (extension, mime, or wildcard). */\nfunction matchesAccepted(file: File, acceptedTypes: string[]): boolean {\n if (!acceptedTypes.length) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return acceptedTypes.some((raw) => {\n const accept = raw.trim().toLowerCase();\n if (!accept) return false;\n if (accept.startsWith('.')) return name.endsWith(accept); // extension\n if (accept.endsWith('/*')) return type.startsWith(accept.slice(0, -1)); // wildcard e.g. image/\n return type === accept; // exact mime type\n });\n}\n\ntype ReadResult = { ok: true; value: File | LoadedFile } | { ok: false };\n\n/** Read a single file into the requested return shape. Never rejects — failures resolve to `{ ok: false }`. */\nfunction readFile(file: File, returnType: DropZoneReturnType): Promise<ReadResult> {\n if (returnType === DropZoneReturnType.File) {\n return Promise.resolve({ ok: true, value: file });\n }\n return new Promise<ReadResult>((resolve) => {\n const reader = new FileReader();\n reader.onload = (event) => {\n const data = event.target?.result;\n if (typeof data !== 'string') {\n resolve({ ok: false });\n return;\n }\n resolve({\n ok: true,\n value: { name: file.name, size: file.size, type: file.type, lastModified: file.lastModified, data },\n });\n };\n reader.onerror = () => resolve({ ok: false });\n if (returnType === DropZoneReturnType.Base64) reader.readAsDataURL(file);\n else reader.readAsText(file);\n });\n}\n\n/** Recursively flatten a dropped file-system entry into a list of Files. */\nfunction readEntry(entry: FileSystemEntry): Promise<File[]> {\n return new Promise((resolve) => {\n if (entry.isFile) {\n (entry as FileSystemFileEntry).file(\n (file) => resolve([file]),\n () => resolve([]),\n );\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n const collected: FileSystemEntry[] = [];\n const readBatch = () => {\n // readEntries yields entries in chunks — keep calling until it returns empty.\n reader.readEntries(\n (batch) => {\n if (!batch.length) {\n Promise.all(collected.map(readEntry)).then((nested) => resolve(nested.flat()));\n } else {\n collected.push(...batch);\n readBatch();\n }\n },\n () => resolve([]),\n );\n };\n readBatch();\n } else {\n resolve([]);\n }\n });\n}\n\n/**\n * Extract Files from a drop's DataTransfer. `webkitGetAsEntry()` must be called\n * synchronously within the drop handler, so all entries are captured before any await.\n */\nfunction gatherFiles(dataTransfer: DataTransfer, allowDirectories: boolean): Promise<File[]> {\n const items = dataTransfer.items;\n if (items && items.length) {\n if (allowDirectories && typeof items[0].webkitGetAsEntry === 'function') {\n const entries: FileSystemEntry[] = [];\n for (let i = 0; i < items.length; i += 1) {\n if (items[i].kind === 'file') {\n const entry = items[i].webkitGetAsEntry();\n if (entry) entries.push(entry);\n }\n }\n if (entries.length) {\n return Promise.all(entries.map(readEntry)).then((nested) => nested.flat());\n }\n }\n const files: File[] = [];\n for (let i = 0; i < items.length; i += 1) {\n if (items[i].kind === 'file') {\n const file = items[i].getAsFile();\n if (file) files.push(file);\n }\n }\n return Promise.resolve(files);\n }\n return Promise.resolve(Array.from(dataTransfer.files || []));\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n\nfunction DropZone({\n children,\n acceptedTypes = [],\n returnType = DropZoneReturnType.File,\n openPickerOnClick = false,\n multiple = true,\n maxFiles,\n maxSize,\n enablePaste = false,\n allowDirectories = true,\n capture,\n disabled = false,\n unstyled = false,\n showFileNames = false,\n files,\n onFilesChanged,\n onReject,\n onStatusChanged,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: DropZoneProps) {\n const [status, setStatus] = useState<DropZoneStatus>(DropZoneStatus.Idle);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const inputId = useId();\n const statusRef = useRef(status);\n const windowDragDepth = useRef(0);\n const zoneDragDepth = useRef(0);\n\n // Latest props/callbacks, so the once-mounted window listeners never read stale values.\n const cfg = useRef({\n acceptedTypes,\n returnType,\n multiple,\n maxFiles,\n maxSize,\n allowDirectories,\n disabled,\n onFilesChanged,\n onReject,\n onStatusChanged,\n });\n useEffect(() => {\n cfg.current = {\n acceptedTypes,\n returnType,\n multiple,\n maxFiles,\n maxSize,\n allowDirectories,\n disabled,\n onFilesChanged,\n onReject,\n onStatusChanged,\n };\n });\n\n const changeStatus = useCallback((next: DropZoneStatus) => {\n if (statusRef.current === next) return;\n statusRef.current = next;\n setStatus(next);\n cfg.current.onStatusChanged?.(next);\n }, []);\n\n const processFiles = useCallback(\n async (incoming: File[]) => {\n const c = cfg.current;\n const rejections: DropZoneRejection[] = [];\n let accepted: File[] = [];\n\n for (const file of incoming) {\n if (!matchesAccepted(file, c.acceptedTypes)) {\n rejections.push({ file, reason: 'unacceptedType' });\n } else if (c.maxSize != null && file.size > c.maxSize) {\n rejections.push({ file, reason: 'tooLarge' });\n } else {\n accepted.push(file);\n }\n }\n\n if (!c.multiple) accepted = accepted.slice(0, 1);\n if (c.maxFiles != null && accepted.length > c.maxFiles) {\n accepted.slice(c.maxFiles).forEach((file) => rejections.push({ file, reason: 'tooMany' }));\n accepted = accepted.slice(0, c.maxFiles);\n }\n\n // Read in input order — Promise.all preserves index regardless of completion order.\n const results = await Promise.all(accepted.map((file) => readFile(file, c.returnType)));\n const loaded: (File | LoadedFile)[] = [];\n results.forEach((result, index) => {\n if (result.ok) loaded.push(result.value);\n else rejections.push({ file: accepted[index], reason: 'readError' });\n });\n\n if (rejections.length) c.onReject?.(rejections);\n changeStatus(rejections.length && !loaded.length ? DropZoneStatus.Error : DropZoneStatus.Idle);\n if (loaded.length) c.onFilesChanged?.(loaded);\n },\n [changeStatus],\n );\n\n // Window-level drag tracking via an enter/leave depth counter (robust against bubbling).\n useEffect(() => {\n const hasFiles = (dt: DataTransfer | null) => !dt || Array.from(dt.types || []).includes('Files');\n\n const onWindowDragEnter = (e: DragEvent) => {\n if (cfg.current.disabled || !hasFiles(e.dataTransfer)) return;\n windowDragDepth.current += 1;\n if (statusRef.current === DropZoneStatus.Idle || statusRef.current === DropZoneStatus.Error) {\n changeStatus(DropZoneStatus.Dragging);\n }\n };\n const onWindowDragLeave = () => {\n windowDragDepth.current = Math.max(0, windowDragDepth.current - 1);\n if (windowDragDepth.current === 0 && statusRef.current === DropZoneStatus.Dragging) {\n changeStatus(DropZoneStatus.Idle);\n }\n };\n const onWindowDrop = () => {\n windowDragDepth.current = 0;\n zoneDragDepth.current = 0;\n if (statusRef.current === DropZoneStatus.Dragging) changeStatus(DropZoneStatus.Idle);\n };\n\n window.addEventListener('dragenter', onWindowDragEnter);\n window.addEventListener('dragleave', onWindowDragLeave);\n window.addEventListener('drop', onWindowDrop);\n return () => {\n window.removeEventListener('dragenter', onWindowDragEnter);\n window.removeEventListener('dragleave', onWindowDragLeave);\n window.removeEventListener('drop', onWindowDrop);\n };\n }, [changeStatus]);\n\n const onDragOver = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer) e.dataTransfer.dropEffect = disabled ? 'none' : 'copy';\n },\n [disabled],\n );\n\n const onDragEnter = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (disabled) return;\n zoneDragDepth.current += 1;\n changeStatus(DropZoneStatus.Active);\n },\n [disabled, changeStatus],\n );\n\n const onDragLeave = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n zoneDragDepth.current = Math.max(0, zoneDragDepth.current - 1);\n if (zoneDragDepth.current === 0) {\n // Left the zone, but a drag may still be active elsewhere in the window.\n changeStatus(windowDragDepth.current > 0 ? DropZoneStatus.Dragging : DropZoneStatus.Idle);\n }\n },\n [changeStatus],\n );\n\n const onDrop = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n zoneDragDepth.current = 0;\n windowDragDepth.current = 0;\n if (disabled || !e.dataTransfer) {\n changeStatus(DropZoneStatus.Idle);\n return;\n }\n changeStatus(DropZoneStatus.Idle);\n // gatherFiles captures any directory entries synchronously before awaiting.\n gatherFiles(e.dataTransfer, cfg.current.allowDirectories).then((collected) => {\n if (collected.length) processFiles(collected);\n });\n },\n [disabled, changeStatus, processFiles],\n );\n\n const openPicker = useCallback(() => {\n if (disabled || !openPickerOnClick) return;\n inputRef.current?.click();\n }, [disabled, openPickerOnClick]);\n\n const onInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const selected = Array.from(e.target.files || []);\n // Reset so picking the same file again still fires onChange.\n e.target.value = '';\n if (selected.length) processFiles(selected);\n },\n [processFiles],\n );\n\n const onPaste = useCallback(\n (e: React.ClipboardEvent<HTMLDivElement>) => {\n if (!enablePaste || disabled) return;\n const pasted = Array.from(e.clipboardData?.files || []);\n if (pasted.length) {\n e.preventDefault();\n processFiles(pasted);\n }\n },\n [enablePaste, disabled, processFiles],\n );\n\n const onKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!openPickerOnClick || disabled) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n openPicker();\n }\n },\n [openPickerOnClick, disabled, openPicker],\n );\n\n const isDragging = status === DropZoneStatus.Dragging || status === DropZoneStatus.Active;\n const renderState: DropZoneRenderState = {\n status,\n isDragging,\n isActive: status === DropZoneStatus.Active,\n disabled,\n };\n\n const acceptAttr = acceptedTypes.length ? acceptedTypes.join(',') : undefined;\n\n return (\n <div\n {...rest}\n className={cx(\n styles.dropZone,\n openPickerOnClick && styles.dropZoneClickable,\n disabled && styles.dropZoneDisabled,\n !unstyled && styles.dropZoneDefault,\n !unstyled && status === DropZoneStatus.Dragging && styles.dropZoneDragging,\n !unstyled && status === DropZoneStatus.Active && styles.dropZoneActive,\n !unstyled && status === DropZoneStatus.Error && styles.dropZoneError,\n classNames?.root,\n className,\n )}\n style={{ ...slotStyles?.root, ...style }}\n onDragEnter={onDragEnter}\n onDragLeave={onDragLeave}\n onDragOver={onDragOver}\n onDrop={onDrop}\n onClick={openPicker}\n onKeyDown={onKeyDown}\n onPaste={enablePaste ? onPaste : undefined}\n role={openPickerOnClick ? 'button' : undefined}\n tabIndex={openPickerOnClick && !disabled ? 0 : undefined}\n aria-disabled={disabled || undefined}\n >\n <div\n className={cx(styles.dropZoneContent, isDragging && styles.dropZoneContentDragging, classNames?.content)}\n style={slotStyles?.content}\n >\n {typeof children === 'function' ? children(renderState) : children}\n </div>\n\n {showFileNames && files && files.length > 0 && (\n <div className={cx(styles.dropZoneFileList, classNames?.fileList)} style={slotStyles?.fileList}>\n {files.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className={cx(styles.dropZoneFileItem, classNames?.fileItem)}\n style={slotStyles?.fileItem}\n >\n {file.name}\n </div>\n ))}\n </div>\n )}\n\n <input\n ref={inputRef}\n id={inputId}\n type='file'\n className={cx(styles.dropZoneInput, classNames?.input)}\n style={slotStyles?.input}\n accept={acceptAttr}\n multiple={multiple}\n capture={capture}\n disabled={disabled}\n onChange={onInputChange}\n tabIndex={-1}\n aria-hidden='true'\n />\n </div>\n );\n}\n\nexport default DropZone;\n"],"mappings":"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"}
1
+ {"version":3,"file":"dropZone.mjs","names":[],"sources":["../../../../package/common/dropZone/dropZone.tsx"],"sourcesContent":["import React, { useCallback, useEffect, useId, useRef, useState } from 'react';\nimport cx from 'classnames';\n\nimport {\n DropZoneProps,\n DropZoneReturnType,\n DropZoneStatus,\n DropZoneRejection,\n DropZoneRenderState,\n LoadedFile,\n} from './dropZone.types';\n\nimport styles from './dropZone.module.pcss';\nimport { isSelfActivation } from '../utils/activationKey';\n\n// ── Pure helpers ──────────────────────────────────────────────────────────────\n\n/** True when a file matches one of the accepted tokens (extension, mime, or wildcard). */\nfunction matchesAccepted(file: File, acceptedTypes: string[]): boolean {\n if (!acceptedTypes.length) return true;\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return acceptedTypes.some((raw) => {\n const accept = raw.trim().toLowerCase();\n if (!accept) return false;\n if (accept.startsWith('.')) return name.endsWith(accept); // extension\n if (accept.endsWith('/*')) return type.startsWith(accept.slice(0, -1)); // wildcard e.g. image/\n return type === accept; // exact mime type\n });\n}\n\ntype ReadResult = { ok: true; value: File | LoadedFile } | { ok: false };\n\n/** Read a single file into the requested return shape. Never rejects — failures resolve to `{ ok: false }`. */\nfunction readFile(file: File, returnType: DropZoneReturnType): Promise<ReadResult> {\n if (returnType === DropZoneReturnType.File) {\n return Promise.resolve({ ok: true, value: file });\n }\n return new Promise<ReadResult>((resolve) => {\n const reader = new FileReader();\n reader.onload = (event) => {\n const data = event.target?.result;\n if (typeof data !== 'string') {\n resolve({ ok: false });\n return;\n }\n resolve({\n ok: true,\n value: { name: file.name, size: file.size, type: file.type, lastModified: file.lastModified, data },\n });\n };\n reader.onerror = () => resolve({ ok: false });\n if (returnType === DropZoneReturnType.Base64) reader.readAsDataURL(file);\n else reader.readAsText(file);\n });\n}\n\n/** Recursively flatten a dropped file-system entry into a list of Files. */\nfunction readEntry(entry: FileSystemEntry): Promise<File[]> {\n return new Promise((resolve) => {\n if (entry.isFile) {\n (entry as FileSystemFileEntry).file(\n (file) => resolve([file]),\n () => resolve([]),\n );\n } else if (entry.isDirectory) {\n const reader = (entry as FileSystemDirectoryEntry).createReader();\n const collected: FileSystemEntry[] = [];\n const readBatch = () => {\n // readEntries yields entries in chunks — keep calling until it returns empty.\n reader.readEntries(\n (batch) => {\n if (!batch.length) {\n Promise.all(collected.map(readEntry)).then((nested) => resolve(nested.flat()));\n } else {\n collected.push(...batch);\n readBatch();\n }\n },\n () => resolve([]),\n );\n };\n readBatch();\n } else {\n resolve([]);\n }\n });\n}\n\n/**\n * Extract Files from a drop's DataTransfer. `webkitGetAsEntry()` must be called\n * synchronously within the drop handler, so all entries are captured before any await.\n */\nfunction gatherFiles(dataTransfer: DataTransfer, allowDirectories: boolean): Promise<File[]> {\n const items = dataTransfer.items;\n if (items && items.length) {\n if (allowDirectories && typeof items[0].webkitGetAsEntry === 'function') {\n const entries: FileSystemEntry[] = [];\n for (let i = 0; i < items.length; i += 1) {\n if (items[i].kind === 'file') {\n const entry = items[i].webkitGetAsEntry();\n if (entry) entries.push(entry);\n }\n }\n if (entries.length) {\n return Promise.all(entries.map(readEntry)).then((nested) => nested.flat());\n }\n }\n const files: File[] = [];\n for (let i = 0; i < items.length; i += 1) {\n if (items[i].kind === 'file') {\n const file = items[i].getAsFile();\n if (file) files.push(file);\n }\n }\n return Promise.resolve(files);\n }\n return Promise.resolve(Array.from(dataTransfer.files || []));\n}\n\n// ── Component ───────────────────────────────────────────────────────────────\n\nfunction DropZone({\n children,\n acceptedTypes = [],\n returnType = DropZoneReturnType.File,\n openPickerOnClick = false,\n multiple = true,\n maxFiles,\n maxSize,\n enablePaste = false,\n allowDirectories = true,\n capture,\n disabled = false,\n unstyled = false,\n showFileNames = false,\n files,\n onFilesChanged,\n onReject,\n onStatusChanged,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: DropZoneProps) {\n const [status, setStatus] = useState<DropZoneStatus>(DropZoneStatus.Idle);\n\n const inputRef = useRef<HTMLInputElement>(null);\n const inputId = useId();\n const statusRef = useRef(status);\n const windowDragDepth = useRef(0);\n const zoneDragDepth = useRef(0);\n\n // Latest props/callbacks, so the once-mounted window listeners never read stale values.\n const cfg = useRef({\n acceptedTypes,\n returnType,\n multiple,\n maxFiles,\n maxSize,\n allowDirectories,\n disabled,\n onFilesChanged,\n onReject,\n onStatusChanged,\n });\n useEffect(() => {\n cfg.current = {\n acceptedTypes,\n returnType,\n multiple,\n maxFiles,\n maxSize,\n allowDirectories,\n disabled,\n onFilesChanged,\n onReject,\n onStatusChanged,\n };\n });\n\n const changeStatus = useCallback((next: DropZoneStatus) => {\n if (statusRef.current === next) return;\n statusRef.current = next;\n setStatus(next);\n cfg.current.onStatusChanged?.(next);\n }, []);\n\n const processFiles = useCallback(\n async (incoming: File[]) => {\n const c = cfg.current;\n const rejections: DropZoneRejection[] = [];\n let accepted: File[] = [];\n\n for (const file of incoming) {\n if (!matchesAccepted(file, c.acceptedTypes)) {\n rejections.push({ file, reason: 'unacceptedType' });\n } else if (c.maxSize != null && file.size > c.maxSize) {\n rejections.push({ file, reason: 'tooLarge' });\n } else {\n accepted.push(file);\n }\n }\n\n if (!c.multiple) accepted = accepted.slice(0, 1);\n if (c.maxFiles != null && accepted.length > c.maxFiles) {\n accepted.slice(c.maxFiles).forEach((file) => rejections.push({ file, reason: 'tooMany' }));\n accepted = accepted.slice(0, c.maxFiles);\n }\n\n // Read in input order — Promise.all preserves index regardless of completion order.\n const results = await Promise.all(accepted.map((file) => readFile(file, c.returnType)));\n const loaded: (File | LoadedFile)[] = [];\n results.forEach((result, index) => {\n if (result.ok) loaded.push(result.value);\n else rejections.push({ file: accepted[index], reason: 'readError' });\n });\n\n if (rejections.length) c.onReject?.(rejections);\n changeStatus(rejections.length && !loaded.length ? DropZoneStatus.Error : DropZoneStatus.Idle);\n if (loaded.length) c.onFilesChanged?.(loaded);\n },\n [changeStatus],\n );\n\n // Window-level drag tracking via an enter/leave depth counter (robust against bubbling).\n useEffect(() => {\n const hasFiles = (dt: DataTransfer | null) => !dt || Array.from(dt.types || []).includes('Files');\n\n const onWindowDragEnter = (e: DragEvent) => {\n if (cfg.current.disabled || !hasFiles(e.dataTransfer)) return;\n windowDragDepth.current += 1;\n if (statusRef.current === DropZoneStatus.Idle || statusRef.current === DropZoneStatus.Error) {\n changeStatus(DropZoneStatus.Dragging);\n }\n };\n const onWindowDragLeave = () => {\n windowDragDepth.current = Math.max(0, windowDragDepth.current - 1);\n if (windowDragDepth.current === 0 && statusRef.current === DropZoneStatus.Dragging) {\n changeStatus(DropZoneStatus.Idle);\n }\n };\n const onWindowDrop = () => {\n windowDragDepth.current = 0;\n zoneDragDepth.current = 0;\n if (statusRef.current === DropZoneStatus.Dragging) changeStatus(DropZoneStatus.Idle);\n };\n\n window.addEventListener('dragenter', onWindowDragEnter);\n window.addEventListener('dragleave', onWindowDragLeave);\n window.addEventListener('drop', onWindowDrop);\n return () => {\n window.removeEventListener('dragenter', onWindowDragEnter);\n window.removeEventListener('dragleave', onWindowDragLeave);\n window.removeEventListener('drop', onWindowDrop);\n };\n }, [changeStatus]);\n\n const onDragOver = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (e.dataTransfer) e.dataTransfer.dropEffect = disabled ? 'none' : 'copy';\n },\n [disabled],\n );\n\n const onDragEnter = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n if (disabled) return;\n zoneDragDepth.current += 1;\n changeStatus(DropZoneStatus.Active);\n },\n [disabled, changeStatus],\n );\n\n const onDragLeave = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n zoneDragDepth.current = Math.max(0, zoneDragDepth.current - 1);\n if (zoneDragDepth.current === 0) {\n // Left the zone, but a drag may still be active elsewhere in the window.\n changeStatus(windowDragDepth.current > 0 ? DropZoneStatus.Dragging : DropZoneStatus.Idle);\n }\n },\n [changeStatus],\n );\n\n const onDrop = useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n e.stopPropagation();\n zoneDragDepth.current = 0;\n windowDragDepth.current = 0;\n if (disabled || !e.dataTransfer) {\n changeStatus(DropZoneStatus.Idle);\n return;\n }\n changeStatus(DropZoneStatus.Idle);\n // gatherFiles captures any directory entries synchronously before awaiting.\n gatherFiles(e.dataTransfer, cfg.current.allowDirectories).then((collected) => {\n if (collected.length) processFiles(collected);\n });\n },\n [disabled, changeStatus, processFiles],\n );\n\n const openPicker = useCallback(() => {\n if (disabled || !openPickerOnClick) return;\n inputRef.current?.click();\n }, [disabled, openPickerOnClick]);\n\n const onInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const selected = Array.from(e.target.files || []);\n // Reset so picking the same file again still fires onChange.\n e.target.value = '';\n if (selected.length) processFiles(selected);\n },\n [processFiles],\n );\n\n const onPaste = useCallback(\n (e: React.ClipboardEvent<HTMLDivElement>) => {\n if (!enablePaste || disabled) return;\n const pasted = Array.from(e.clipboardData?.files || []);\n if (pasted.length) {\n e.preventDefault();\n processFiles(pasted);\n }\n },\n [enablePaste, disabled, processFiles],\n );\n\n const onKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!openPickerOnClick || disabled) return;\n if (!isSelfActivation(e)) return;\n e.preventDefault();\n openPicker();\n },\n [openPickerOnClick, disabled, openPicker],\n );\n\n const isDragging = status === DropZoneStatus.Dragging || status === DropZoneStatus.Active;\n const renderState: DropZoneRenderState = {\n status,\n isDragging,\n isActive: status === DropZoneStatus.Active,\n disabled,\n };\n\n const acceptAttr = acceptedTypes.length ? acceptedTypes.join(',') : undefined;\n\n return (\n <div\n {...rest}\n className={cx(\n styles.dropZone,\n openPickerOnClick && styles.dropZoneClickable,\n disabled && styles.dropZoneDisabled,\n !unstyled && styles.dropZoneDefault,\n !unstyled && status === DropZoneStatus.Dragging && styles.dropZoneDragging,\n !unstyled && status === DropZoneStatus.Active && styles.dropZoneActive,\n !unstyled && status === DropZoneStatus.Error && styles.dropZoneError,\n classNames?.root,\n className,\n )}\n style={{ ...slotStyles?.root, ...style }}\n onDragEnter={onDragEnter}\n onDragLeave={onDragLeave}\n onDragOver={onDragOver}\n onDrop={onDrop}\n onClick={openPicker}\n onKeyDown={onKeyDown}\n onPaste={enablePaste ? onPaste : undefined}\n role={openPickerOnClick ? 'button' : undefined}\n tabIndex={openPickerOnClick && !disabled ? 0 : undefined}\n aria-disabled={disabled || undefined}\n >\n <div\n className={cx(styles.dropZoneContent, isDragging && styles.dropZoneContentDragging, classNames?.content)}\n style={slotStyles?.content}\n >\n {typeof children === 'function' ? children(renderState) : children}\n </div>\n\n {showFileNames && files && files.length > 0 && (\n <div className={cx(styles.dropZoneFileList, classNames?.fileList)} style={slotStyles?.fileList}>\n {files.map((file, index) => (\n <div\n key={`${file.name}-${index}`}\n className={cx(styles.dropZoneFileItem, classNames?.fileItem)}\n style={slotStyles?.fileItem}\n >\n {file.name}\n </div>\n ))}\n </div>\n )}\n\n <input\n ref={inputRef}\n id={inputId}\n type='file'\n className={cx(styles.dropZoneInput, classNames?.input)}\n style={slotStyles?.input}\n accept={acceptAttr}\n multiple={multiple}\n capture={capture}\n disabled={disabled}\n onChange={onInputChange}\n tabIndex={-1}\n aria-hidden='true'\n />\n </div>\n );\n}\n\nexport default DropZone;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"./flip.module.mjs";import{forwardRef as n,useEffect as r,useImperativeHandle as i,useRef as a,useState as o}from"react";import s from"classnames";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u(){return typeof process<`u`&&!1}function d(){return typeof window<`u`&&window.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches===!0}var f=n(function(n,f){let{front:p,back:m,flipped:h,defaultFlipped:g=!1,flipOnClick:_=!1,flipAxis:v=`y`,reverse:y=!1,flipDuration:b=600,perspective:x=800,disabled:S=!1,onFlip:C,onFlipEnd:w,className:T,style:E,classNames:D,styles:O,...k}=e(`Flip`,n),A=h!==void 0,[j,M]=o(g),N=A?h:j;function P(e){A||M(e),C?.(e)}let F=()=>{_&&!S&&P(!N)},I=e=>{_&&!S&&(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),P(!N))},L=a(!1);r(()=>{if(!L.current){L.current=!0;return}d()&&w?.(N)},[N]);let R=e=>{e.target===e.currentTarget&&e.propertyName===`transform`&&w?.(N)};i(f,()=>({flip(){if(A){u()&&console.warn("Flip: flip() called on a controlled instance, update the `flipped` prop instead.");return}P(!N)},setFlipped(e){if(A){u()&&console.warn("Flip: setFlipped() called on a controlled instance, update the `flipped` prop instead.");return}P(e)},reset(){A||M(!1)}}));let z=y?-180:180,B=v===`x`&&N?z:0,V=v===`y`&&N?z:0,H=v===`x`?z:0,U=v===`y`?z:0;return c(`div`,{...k,className:s(t.flip,_&&t.flipClickable,T,D?.root),style:{...E,...O?.root},onClick:F,onKeyDown:_?I:void 0,role:_?`button`:void 0,tabIndex:_?0:void 0,"aria-pressed":_?N:void 0,children:c(`div`,{className:s(t.flipPerspective,D?.perspective),style:{perspective:x===`none`?`none`:`${x}px`,...O?.perspective},children:l(`div`,{className:s(t.flipSurface,D?.surface),style:{transform:`rotateX(${B}deg) rotateY(${V}deg)`,"--flip-duration":`${b}ms`,...O?.surface},"data-flipped":N,onTransitionEnd:R,children:[c(`div`,{className:s(t.flipFront,D?.front),style:O?.front,children:p}),c(`div`,{className:s(t.flipBack,D?.back),style:{transform:`rotateX(${H}deg) rotateY(${U}deg)`,...O?.back},children:m})]})})})});export{f as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{isSelfActivation as t}from"../utils/activationKey.mjs";import n from"./flip.module.mjs";import{forwardRef as r,useEffect as i,useImperativeHandle 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";function d(){return typeof process<`u`&&!1}function f(){return typeof window<`u`&&window.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches===!0}var p=r(function(r,p){let{front:m,back:h,flipped:g,defaultFlipped:_=!1,flipOnClick:v=!1,flipAxis:y=`y`,reverse:b=!1,flipDuration:x=600,perspective:S=800,disabled:C=!1,onFlip:w,onFlipEnd:T,className:E,style:D,classNames:O,styles:k,...A}=e(`Flip`,r),j=g!==void 0,[M,N]=s(_),P=j?g:M;function F(e){j||N(e),w?.(e)}let I=()=>{v&&!C&&F(!P)},L=e=>{v&&!C&&t(e)&&(e.preventDefault(),F(!P))},R=o(!1);i(()=>{if(!R.current){R.current=!0;return}f()&&T?.(P)},[P]);let z=e=>{e.target===e.currentTarget&&e.propertyName===`transform`&&T?.(P)};a(p,()=>({flip(){if(j){d()&&console.warn("Flip: flip() called on a controlled instance, update the `flipped` prop instead.");return}F(!P)},setFlipped(e){if(j){d()&&console.warn("Flip: setFlipped() called on a controlled instance, update the `flipped` prop instead.");return}F(e)},reset(){j||N(!1)}}));let B=b?-180:180,V=y===`x`&&P?B:0,H=y===`y`&&P?B:0,U=y===`x`?B:0,W=y===`y`?B:0;return l(`div`,{...A,className:c(n.flip,v&&n.flipClickable,E,O?.root),style:{...D,...k?.root},onClick:I,onKeyDown:v?L:void 0,role:v?`button`:void 0,tabIndex:v?0:void 0,"aria-pressed":v?P:void 0,children:l(`div`,{className:c(n.flipPerspective,O?.perspective),style:{perspective:S===`none`?`none`:`${S}px`,...k?.perspective},children:u(`div`,{className:c(n.flipSurface,O?.surface),style:{transform:`rotateX(${V}deg) rotateY(${H}deg)`,"--flip-duration":`${x}ms`,...k?.surface},"data-flipped":P,onTransitionEnd:z,children:[l(`div`,{className:c(n.flipFront,O?.front),style:k?.front,children:m}),l(`div`,{className:c(n.flipBack,O?.back),style:{transform:`rotateX(${U}deg) rotateY(${W}deg)`,...k?.back},children:h})]})})})});export{p as default};
2
2
  //# sourceMappingURL=flip.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"flip.mjs","names":[],"sources":["../../../../package/common/flip/flip.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from 'react';\nimport cx from 'classnames';\n\nimport { useComponentDefaults } from '../configProvider';\nimport type { FlipHandle, FlipProps } from './flip.types';\nimport styles from './flip.module.pcss';\n\n// Module-scoped ambient typing for the bundler-replaced NODE_ENV guard below. See bodyEnd.tsx.\ndeclare const process: { env: { NODE_ENV?: string } };\n\nfunction isDev(): boolean {\n return typeof process !== 'undefined' && process.env.NODE_ENV !== 'production';\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;\n}\n\nconst Flip = forwardRef<FlipHandle, FlipProps>(function Flip(props, ref) {\n const {\n front,\n back,\n flipped,\n defaultFlipped = false,\n flipOnClick = false,\n flipAxis = 'y',\n reverse = false,\n flipDuration = 600,\n perspective = 800,\n disabled = false,\n onFlip,\n onFlipEnd,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Flip', props);\n\n const isControlled = flipped !== undefined;\n const [internalFlipped, setInternalFlipped] = useState(defaultFlipped);\n const effectiveFlipped = isControlled ? flipped : internalFlipped;\n\n function doFlip(nextFlipped: boolean) {\n if (!isControlled) setInternalFlipped(nextFlipped);\n onFlip?.(nextFlipped);\n }\n\n const handleClick = () => {\n if (!flipOnClick || disabled) return;\n doFlip(!effectiveFlipped);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (!flipOnClick || disabled) return;\n if (event.key !== 'Enter' && event.key !== ' ') return;\n event.preventDefault();\n doFlip(!effectiveFlipped);\n };\n\n const mountedRef = useRef(false);\n useEffect(() => {\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n if (prefersReducedMotion()) onFlipEnd?.(effectiveFlipped);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [effectiveFlipped]);\n\n const handleTransitionEnd = (event: React.TransitionEvent<HTMLDivElement>) => {\n if (event.target !== event.currentTarget || event.propertyName !== 'transform') return;\n onFlipEnd?.(effectiveFlipped);\n };\n\n useImperativeHandle(ref, () => ({\n flip() {\n if (isControlled) {\n if (isDev()) {\n console.warn('Flip: flip() called on a controlled instance, update the `flipped` prop instead.');\n }\n return;\n }\n doFlip(!effectiveFlipped);\n },\n setFlipped(value: boolean) {\n if (isControlled) {\n if (isDev()) {\n console.warn('Flip: setFlipped() called on a controlled instance, update the `flipped` prop instead.');\n }\n return;\n }\n doFlip(value);\n },\n reset() {\n if (!isControlled) setInternalFlipped(false);\n },\n }));\n\n // `reverse` flips the rotation sign on the same hinge axis (+180deg vs -180deg), so adjacent\n // flips can sweep opposite ways without changing which edge they hinge on. The back face's\n // own static rotation (below) always uses this same sign, unconditionally: two rotations of\n // the same sign about the same axis (surface's + back's own) sum to +/-360deg, which is a full\n // turn back to a right-reading, forward-facing back, regardless of whether `reverse` is set.\n const turn = reverse ? -180 : 180;\n const flipOffsetX = flipAxis === 'x' && effectiveFlipped ? turn : 0;\n const flipOffsetY = flipAxis === 'y' && effectiveFlipped ? turn : 0;\n const backOffsetX = flipAxis === 'x' ? turn : 0;\n const backOffsetY = flipAxis === 'y' ? turn : 0;\n\n return (\n <div\n {...rest}\n className={cx(styles.flip, flipOnClick && styles.flipClickable, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n onClick={handleClick}\n onKeyDown={flipOnClick ? handleKeyDown : undefined}\n role={flipOnClick ? 'button' : undefined}\n tabIndex={flipOnClick ? 0 : undefined}\n aria-pressed={flipOnClick ? effectiveFlipped : undefined}\n >\n <div\n className={cx(styles.flipPerspective, classNames?.perspective)}\n style={{\n perspective: perspective === 'none' ? 'none' : `${perspective}px`,\n ...slotStyles?.perspective,\n }}\n >\n <div\n className={cx(styles.flipSurface, classNames?.surface)}\n style={\n {\n transform: `rotateX(${flipOffsetX}deg) rotateY(${flipOffsetY}deg)`,\n '--flip-duration': `${flipDuration}ms`,\n ...slotStyles?.surface,\n } as CSSProperties & Record<'--flip-duration', string>\n }\n data-flipped={effectiveFlipped}\n onTransitionEnd={handleTransitionEnd}\n >\n <div className={cx(styles.flipFront, classNames?.front)} style={slotStyles?.front}>\n {front}\n </div>\n <div\n className={cx(styles.flipBack, classNames?.back)}\n style={{\n transform: `rotateX(${backOffsetX}deg) rotateY(${backOffsetY}deg)`,\n ...slotStyles?.back,\n }}\n >\n {back}\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nexport default Flip;\n"],"mappings":"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"}
1
+ {"version":3,"file":"flip.mjs","names":[],"sources":["../../../../package/common/flip/flip.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from 'react';\nimport cx from 'classnames';\n\nimport { useComponentDefaults } from '../configProvider';\nimport type { FlipHandle, FlipProps } from './flip.types';\nimport styles from './flip.module.pcss';\nimport { isSelfActivation } from '../utils/activationKey';\n\n// Module-scoped ambient typing for the bundler-replaced NODE_ENV guard below. See bodyEnd.tsx.\ndeclare const process: { env: { NODE_ENV?: string } };\n\nfunction isDev(): boolean {\n return typeof process !== 'undefined' && process.env.NODE_ENV !== 'production';\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof window !== 'undefined' && window.matchMedia?.('(prefers-reduced-motion: reduce)').matches === true;\n}\n\nconst Flip = forwardRef<FlipHandle, FlipProps>(function Flip(props, ref) {\n const {\n front,\n back,\n flipped,\n defaultFlipped = false,\n flipOnClick = false,\n flipAxis = 'y',\n reverse = false,\n flipDuration = 600,\n perspective = 800,\n disabled = false,\n onFlip,\n onFlipEnd,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Flip', props);\n\n const isControlled = flipped !== undefined;\n const [internalFlipped, setInternalFlipped] = useState(defaultFlipped);\n const effectiveFlipped = isControlled ? flipped : internalFlipped;\n\n function doFlip(nextFlipped: boolean) {\n if (!isControlled) setInternalFlipped(nextFlipped);\n onFlip?.(nextFlipped);\n }\n\n const handleClick = () => {\n if (!flipOnClick || disabled) return;\n doFlip(!effectiveFlipped);\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (!flipOnClick || disabled) return;\n if (!isSelfActivation(event)) return;\n event.preventDefault();\n doFlip(!effectiveFlipped);\n };\n\n const mountedRef = useRef(false);\n useEffect(() => {\n if (!mountedRef.current) {\n mountedRef.current = true;\n return;\n }\n if (prefersReducedMotion()) onFlipEnd?.(effectiveFlipped);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [effectiveFlipped]);\n\n const handleTransitionEnd = (event: React.TransitionEvent<HTMLDivElement>) => {\n if (event.target !== event.currentTarget || event.propertyName !== 'transform') return;\n onFlipEnd?.(effectiveFlipped);\n };\n\n useImperativeHandle(ref, () => ({\n flip() {\n if (isControlled) {\n if (isDev()) {\n console.warn('Flip: flip() called on a controlled instance, update the `flipped` prop instead.');\n }\n return;\n }\n doFlip(!effectiveFlipped);\n },\n setFlipped(value: boolean) {\n if (isControlled) {\n if (isDev()) {\n console.warn('Flip: setFlipped() called on a controlled instance, update the `flipped` prop instead.');\n }\n return;\n }\n doFlip(value);\n },\n reset() {\n if (!isControlled) setInternalFlipped(false);\n },\n }));\n\n // `reverse` flips the rotation sign on the same hinge axis (+180deg vs -180deg), so adjacent\n // flips can sweep opposite ways without changing which edge they hinge on. The back face's\n // own static rotation (below) always uses this same sign, unconditionally: two rotations of\n // the same sign about the same axis (surface's + back's own) sum to +/-360deg, which is a full\n // turn back to a right-reading, forward-facing back, regardless of whether `reverse` is set.\n const turn = reverse ? -180 : 180;\n const flipOffsetX = flipAxis === 'x' && effectiveFlipped ? turn : 0;\n const flipOffsetY = flipAxis === 'y' && effectiveFlipped ? turn : 0;\n const backOffsetX = flipAxis === 'x' ? turn : 0;\n const backOffsetY = flipAxis === 'y' ? turn : 0;\n\n return (\n <div\n {...rest}\n className={cx(styles.flip, flipOnClick && styles.flipClickable, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n onClick={handleClick}\n onKeyDown={flipOnClick ? handleKeyDown : undefined}\n role={flipOnClick ? 'button' : undefined}\n tabIndex={flipOnClick ? 0 : undefined}\n aria-pressed={flipOnClick ? effectiveFlipped : undefined}\n >\n <div\n className={cx(styles.flipPerspective, classNames?.perspective)}\n style={{\n perspective: perspective === 'none' ? 'none' : `${perspective}px`,\n ...slotStyles?.perspective,\n }}\n >\n <div\n className={cx(styles.flipSurface, classNames?.surface)}\n style={\n {\n transform: `rotateX(${flipOffsetX}deg) rotateY(${flipOffsetY}deg)`,\n '--flip-duration': `${flipDuration}ms`,\n ...slotStyles?.surface,\n } as CSSProperties & Record<'--flip-duration', string>\n }\n data-flipped={effectiveFlipped}\n onTransitionEnd={handleTransitionEnd}\n >\n <div className={cx(styles.flipFront, classNames?.front)} style={slotStyles?.front}>\n {front}\n </div>\n <div\n className={cx(styles.flipBack, classNames?.back)}\n style={{\n transform: `rotateX(${backOffsetX}deg) rotateY(${backOffsetY}deg)`,\n ...slotStyles?.back,\n }}\n >\n {back}\n </div>\n </div>\n </div>\n </div>\n );\n});\n\nexport default Flip;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"./interactableDiv.module.mjs";import t,{useCallback as n}from"react";import r from"classnames";import{jsx as i}from"react/jsx-runtime";var a=t.forwardRef(({className:t,children:a,onClick:o,onKeyDown:s,tabIndex:c,...l},u)=>{let d=n(e=>{(e.key===`Enter`||e.key===` `)&&(e.key===` `&&e.preventDefault(),o?.(e)),s?.(e)},[o,s]);return i(`div`,{className:r(e.interactableDiv,t),onClick:o,tabIndex:c===void 0?o?0:void 0:c??void 0,role:o?`button`:void 0,onKeyDown:d,ref:u,...l,children:a})});a.displayName=`InteractableDiv`;export{a as default};
1
+ import e from"./interactableDiv.module.mjs";import{isSelfActivation as t}from"../utils/activationKey.mjs";import n,{useCallback as r}from"react";import i from"classnames";import{jsx as a}from"react/jsx-runtime";var o=n.forwardRef(({className:n,children:o,onClick:s,onKeyDown:c,tabIndex:l,...u},d)=>{let f=r(e=>{t(e)&&(e.key===` `&&e.preventDefault(),s?.(e)),c?.(e)},[s,c]);return a(`div`,{className:i(e.interactableDiv,n),onClick:s,tabIndex:l===void 0?s?0:void 0:l??void 0,role:s?`button`:void 0,onKeyDown:f,ref:d,...u,children:o})});o.displayName=`InteractableDiv`;export{o as default};
2
2
  //# sourceMappingURL=interactableDiv.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactableDiv.mjs","names":[],"sources":["../../../../package/common/interactableDiv/interactableDiv.tsx"],"sourcesContent":["import cx from 'classnames';\nimport React, { useCallback, type KeyboardEvent, type MouseEvent, type ReactElement } from 'react';\n\nimport styles from './interactableDiv.module.pcss';\nimport type { DataProps } from '../types/baseProps.types';\n\ninterface Properties extends DataProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'tabIndex'> {\n tabIndex?: number | null;\n}\n\nconst InteractableDiv = React.forwardRef<HTMLDivElement, Properties>(\n ({ className, children, onClick, onKeyDown, tabIndex, ...props }, ref): ReactElement => {\n const onKeyDownHandler = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n if (e.key === ' ') e.preventDefault();\n onClick?.(e as unknown as MouseEvent<HTMLDivElement>);\n }\n onKeyDown?.(e);\n },\n [onClick, onKeyDown],\n );\n\n // Compared to undefined rather than using ??, so an explicit null still means \"no tabindex\"\n // instead of falling through to the default.\n return (\n <div\n className={cx(styles.interactableDiv, className)}\n onClick={onClick}\n tabIndex={tabIndex === undefined ? (onClick ? 0 : undefined) : (tabIndex ?? undefined)}\n role={onClick ? 'button' : undefined}\n onKeyDown={onKeyDownHandler}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n },\n);\n\nInteractableDiv.displayName = 'InteractableDiv';\n\nexport default InteractableDiv;\n"],"mappings":"qJAUA,IAAM,EAAkB,EAAM,YAC3B,CAAE,YAAW,WAAU,UAAS,YAAW,WAAU,GAAG,GAAS,IAAsB,CACtF,IAAM,EAAmB,EACtB,GAAqC,EAChC,EAAE,MAAQ,SAAW,EAAE,MAAQ,OAC7B,EAAE,MAAQ,KAAK,EAAE,eAAe,EACpC,IAAU,CAA0C,GAEtD,IAAY,CAAC,CACf,EACA,CAAC,EAAS,CAAS,CACrB,EAIA,OACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,gBAAiB,CAAS,EACtC,UACT,SAAU,IAAa,IAAA,GAAa,EAAU,EAAI,IAAA,GAAc,GAAY,IAAA,GAC5E,KAAM,EAAU,SAAW,IAAA,GAC3B,UAAW,EACN,MACL,GAAI,EAEH,UACE,CAAA,CAET,CACF,EAEA,EAAgB,YAAc"}
1
+ {"version":3,"file":"interactableDiv.mjs","names":[],"sources":["../../../../package/common/interactableDiv/interactableDiv.tsx"],"sourcesContent":["import cx from 'classnames';\nimport React, { useCallback, type KeyboardEvent, type MouseEvent, type ReactElement } from 'react';\n\nimport styles from './interactableDiv.module.pcss';\nimport type { DataProps } from '../types/baseProps.types';\nimport { isSelfActivation } from '../utils/activationKey';\n\ninterface Properties extends DataProps, Omit<React.HTMLAttributes<HTMLDivElement>, 'tabIndex'> {\n tabIndex?: number | null;\n}\n\nconst InteractableDiv = React.forwardRef<HTMLDivElement, Properties>(\n ({ className, children, onClick, onKeyDown, tabIndex, ...props }, ref): ReactElement => {\n const onKeyDownHandler = useCallback(\n (e: KeyboardEvent<HTMLDivElement>) => {\n if (isSelfActivation(e)) {\n if (e.key === ' ') e.preventDefault();\n onClick?.(e as unknown as MouseEvent<HTMLDivElement>);\n }\n onKeyDown?.(e);\n },\n [onClick, onKeyDown],\n );\n\n // Compared to undefined rather than using ??, so an explicit null still means \"no tabindex\"\n // instead of falling through to the default.\n return (\n <div\n className={cx(styles.interactableDiv, className)}\n onClick={onClick}\n tabIndex={tabIndex === undefined ? (onClick ? 0 : undefined) : (tabIndex ?? undefined)}\n role={onClick ? 'button' : undefined}\n onKeyDown={onKeyDownHandler}\n ref={ref}\n {...props}\n >\n {children}\n </div>\n );\n },\n);\n\nInteractableDiv.displayName = 'InteractableDiv';\n\nexport default InteractableDiv;\n"],"mappings":"mNAWA,IAAM,EAAkB,EAAM,YAC3B,CAAE,YAAW,WAAU,UAAS,YAAW,WAAU,GAAG,GAAS,IAAsB,CACtF,IAAM,EAAmB,EACtB,GAAqC,CAChC,EAAiB,CAAC,IAChB,EAAE,MAAQ,KAAK,EAAE,eAAe,EACpC,IAAU,CAA0C,GAEtD,IAAY,CAAC,CACf,EACA,CAAC,EAAS,CAAS,CACrB,EAIA,OACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,gBAAiB,CAAS,EACtC,UACT,SAAU,IAAa,IAAA,GAAa,EAAU,EAAI,IAAA,GAAc,GAAY,IAAA,GAC5E,KAAM,EAAU,SAAW,IAAA,GAC3B,UAAW,EACN,MACL,GAAI,EAEH,UACE,CAAA,CAET,CACF,EAEA,EAAgB,YAAc"}
@@ -1,2 +1,2 @@
1
- var e=`planCanvas_7XTdG`,t=`planCanvas-screen_lk83X`,n=`planCanvas-underlay_rpzSl`,r=`planCanvas-grid_49CmH`,i=`planCanvas-rooms_UyjEC`,a=`planCanvas-roomFill_LXlOf`,o=`planCanvas-roomFill-interactive_JSU1E`,s=`planCanvas-roomFill-hovered_7ZXgf`,c=`planCanvas-roomLabel_GrzE3`,l=`planCanvas-roomName_kHAtD`,u=`planCanvas-roomArea_X1Tal`,d=`planCanvas-walls_G9vXB`,f=`planCanvas-wallOutline_eWEN-`,p=`planCanvas-wallFill_iKHyE`,m=`planCanvas-wallCaps_ZpLG4`,h=`planCanvas-roomEdgeCaps_5Y7lq`,g=`planCanvas-roomEdgeSelected_wQk6B`,_=`planCanvas-roomEdgeOutline_Y1ZwL`,v=`planCanvas-roomEdgeFill_Qr9p-`,y=`planCanvas-wallSelected_vFNw8`,b=`planCanvas-wallHovered_CFIAR`,x=`planCanvas-openings_1fyX4`,S=`planCanvas-opening-selected_Wgl4r`,C=`planCanvas-doorLeaf_1BEkI`,w=`planCanvas-doorSwing_QCc5i`,T=`planCanvas-windowPane_5q9oQ`,E=`planCanvas-opening-hovered_NGK0O`,D=`planCanvas-opening-hit_frRch`,O=`planCanvas-opening-hit-interactive_D4ZUY`,k=`planCanvas-opening-outline_HS2wY`,A=`planCanvas-jamb_e-I9r`,j=`planCanvas-jamb-highlighted_rWYxZ`,M=`planCanvas-selection_0a31R`,N={planCanvas:e,"planCanvas-screen":`planCanvas-screen_lk83X`,planCanvasScreen:t,"planCanvas-underlay":`planCanvas-underlay_rpzSl`,planCanvasUnderlay:n,"planCanvas-grid":`planCanvas-grid_49CmH`,planCanvasGrid:r,"planCanvas-rooms":`planCanvas-rooms_UyjEC`,planCanvasRooms:i,"planCanvas-roomFill":`planCanvas-roomFill_LXlOf`,planCanvasRoomFill:a,"planCanvas-roomFill-interactive":`planCanvas-roomFill-interactive_JSU1E`,planCanvasRoomFillInteractive:o,"planCanvas-roomFill-hovered":`planCanvas-roomFill-hovered_7ZXgf`,planCanvasRoomFillHovered:s,"planCanvas-roomLabel":`planCanvas-roomLabel_GrzE3`,planCanvasRoomLabel:c,"planCanvas-roomName":`planCanvas-roomName_kHAtD`,planCanvasRoomName:l,"planCanvas-roomArea":`planCanvas-roomArea_X1Tal`,planCanvasRoomArea:u,"planCanvas-walls":`planCanvas-walls_G9vXB`,planCanvasWalls:d,"planCanvas-wallOutline":`planCanvas-wallOutline_eWEN-`,planCanvasWallOutline:f,"planCanvas-wallFill":`planCanvas-wallFill_iKHyE`,planCanvasWallFill:p,"planCanvas-wallCaps":`planCanvas-wallCaps_ZpLG4`,planCanvasWallCaps:m,"planCanvas-roomEdgeCaps":`planCanvas-roomEdgeCaps_5Y7lq`,planCanvasRoomEdgeCaps:h,"planCanvas-roomEdgeSelected":`planCanvas-roomEdgeSelected_wQk6B`,planCanvasRoomEdgeSelected:g,"planCanvas-roomEdgeOutline":`planCanvas-roomEdgeOutline_Y1ZwL`,planCanvasRoomEdgeOutline:_,"planCanvas-roomEdgeFill":`planCanvas-roomEdgeFill_Qr9p-`,planCanvasRoomEdgeFill:v,"planCanvas-wallSelected":`planCanvas-wallSelected_vFNw8`,planCanvasWallSelected:y,"planCanvas-wallHovered":`planCanvas-wallHovered_CFIAR`,planCanvasWallHovered:b,"planCanvas-openings":`planCanvas-openings_1fyX4`,planCanvasOpenings:x,"planCanvas-opening-selected":`planCanvas-opening-selected_Wgl4r`,planCanvasOpeningSelected:S,"planCanvas-doorLeaf":`planCanvas-doorLeaf_1BEkI`,planCanvasDoorLeaf:C,"planCanvas-doorSwing":`planCanvas-doorSwing_QCc5i`,planCanvasDoorSwing:w,"planCanvas-windowPane":`planCanvas-windowPane_5q9oQ`,planCanvasWindowPane:T,"planCanvas-opening-hovered":`planCanvas-opening-hovered_NGK0O`,planCanvasOpeningHovered:E,"planCanvas-opening-hit":`planCanvas-opening-hit_frRch`,planCanvasOpeningHit:D,"planCanvas-opening-hit-interactive":`planCanvas-opening-hit-interactive_D4ZUY`,planCanvasOpeningHitInteractive:O,"planCanvas-opening-outline":`planCanvas-opening-outline_HS2wY`,planCanvasOpeningOutline:k,"planCanvas-jamb":`planCanvas-jamb_e-I9r`,planCanvasJamb:A,"planCanvas-jamb-highlighted":`planCanvas-jamb-highlighted_rWYxZ`,planCanvasJambHighlighted:j,"planCanvas-selection":`planCanvas-selection_0a31R`,planCanvasSelection:M};export{N as default,e as planCanvas,C as planCanvasDoorLeaf,w as planCanvasDoorSwing,r as planCanvasGrid,A as planCanvasJamb,j as planCanvasJambHighlighted,D as planCanvasOpeningHit,O as planCanvasOpeningHitInteractive,E as planCanvasOpeningHovered,k as planCanvasOpeningOutline,S as planCanvasOpeningSelected,x as planCanvasOpenings,u as planCanvasRoomArea,h as planCanvasRoomEdgeCaps,v as planCanvasRoomEdgeFill,_ as planCanvasRoomEdgeOutline,g as planCanvasRoomEdgeSelected,a as planCanvasRoomFill,s as planCanvasRoomFillHovered,o as planCanvasRoomFillInteractive,c as planCanvasRoomLabel,l as planCanvasRoomName,i as planCanvasRooms,t as planCanvasScreen,M as planCanvasSelection,n as planCanvasUnderlay,m as planCanvasWallCaps,p as planCanvasWallFill,b as planCanvasWallHovered,f as planCanvasWallOutline,y as planCanvasWallSelected,d as planCanvasWalls,T as planCanvasWindowPane};
1
+ var e=`planCanvas_7XTdG`,t=`planCanvas-screen_lk83X`,n=`planCanvas-underlay_rpzSl`,r=`planCanvas-grid_49CmH`,i=`planCanvas-rooms_UyjEC`,a=`planCanvas-roomFill_LXlOf`,o=`planCanvas-roomFill-interactive_JSU1E`,s=`planCanvas-roomFill-hovered_7ZXgf`,c=`planCanvas-roomLabel_GrzE3`,l=`planCanvas-roomName_kHAtD`,u=`planCanvas-roomArea_X1Tal`,d=`planCanvas-walls_G9vXB`,f=`planCanvas-wallOutline_eWEN-`,p=`planCanvas-wallFill_iKHyE`,m=`planCanvas-roomEdgeSelected_wQk6B`,h=`planCanvas-wallCaps_ZpLG4`,g=`planCanvas-roomEdgeCaps_5Y7lq`,_=`planCanvas-roomEdgeOutline_Y1ZwL`,v=`planCanvas-roomEdgeFill_Qr9p-`,y=`planCanvas-wallSelected_vFNw8`,b=`planCanvas-wallHovered_CFIAR`,x=`planCanvas-openings_1fyX4`,S=`planCanvas-opening-selected_Wgl4r`,C=`planCanvas-doorLeaf_1BEkI`,w=`planCanvas-doorSwing_QCc5i`,T=`planCanvas-windowPane_5q9oQ`,E=`planCanvas-opening-hovered_NGK0O`,D=`planCanvas-opening-hit_frRch`,O=`planCanvas-opening-hit-interactive_D4ZUY`,k=`planCanvas-opening-outline_HS2wY`,A=`planCanvas-jamb_e-I9r`,j=`planCanvas-jamb-highlighted_rWYxZ`,M=`planCanvas-selection_0a31R`,N={planCanvas:e,"planCanvas-screen":`planCanvas-screen_lk83X`,planCanvasScreen:t,"planCanvas-underlay":`planCanvas-underlay_rpzSl`,planCanvasUnderlay:n,"planCanvas-grid":`planCanvas-grid_49CmH`,planCanvasGrid:r,"planCanvas-rooms":`planCanvas-rooms_UyjEC`,planCanvasRooms:i,"planCanvas-roomFill":`planCanvas-roomFill_LXlOf`,planCanvasRoomFill:a,"planCanvas-roomFill-interactive":`planCanvas-roomFill-interactive_JSU1E`,planCanvasRoomFillInteractive:o,"planCanvas-roomFill-hovered":`planCanvas-roomFill-hovered_7ZXgf`,planCanvasRoomFillHovered:s,"planCanvas-roomLabel":`planCanvas-roomLabel_GrzE3`,planCanvasRoomLabel:c,"planCanvas-roomName":`planCanvas-roomName_kHAtD`,planCanvasRoomName:l,"planCanvas-roomArea":`planCanvas-roomArea_X1Tal`,planCanvasRoomArea:u,"planCanvas-walls":`planCanvas-walls_G9vXB`,planCanvasWalls:d,"planCanvas-wallOutline":`planCanvas-wallOutline_eWEN-`,planCanvasWallOutline:f,"planCanvas-wallFill":`planCanvas-wallFill_iKHyE`,planCanvasWallFill:p,"planCanvas-roomEdgeSelected":`planCanvas-roomEdgeSelected_wQk6B`,planCanvasRoomEdgeSelected:m,"planCanvas-wallCaps":`planCanvas-wallCaps_ZpLG4`,planCanvasWallCaps:h,"planCanvas-roomEdgeCaps":`planCanvas-roomEdgeCaps_5Y7lq`,planCanvasRoomEdgeCaps:g,"planCanvas-roomEdgeOutline":`planCanvas-roomEdgeOutline_Y1ZwL`,planCanvasRoomEdgeOutline:_,"planCanvas-roomEdgeFill":`planCanvas-roomEdgeFill_Qr9p-`,planCanvasRoomEdgeFill:v,"planCanvas-wallSelected":`planCanvas-wallSelected_vFNw8`,planCanvasWallSelected:y,"planCanvas-wallHovered":`planCanvas-wallHovered_CFIAR`,planCanvasWallHovered:b,"planCanvas-openings":`planCanvas-openings_1fyX4`,planCanvasOpenings:x,"planCanvas-opening-selected":`planCanvas-opening-selected_Wgl4r`,planCanvasOpeningSelected:S,"planCanvas-doorLeaf":`planCanvas-doorLeaf_1BEkI`,planCanvasDoorLeaf:C,"planCanvas-doorSwing":`planCanvas-doorSwing_QCc5i`,planCanvasDoorSwing:w,"planCanvas-windowPane":`planCanvas-windowPane_5q9oQ`,planCanvasWindowPane:T,"planCanvas-opening-hovered":`planCanvas-opening-hovered_NGK0O`,planCanvasOpeningHovered:E,"planCanvas-opening-hit":`planCanvas-opening-hit_frRch`,planCanvasOpeningHit:D,"planCanvas-opening-hit-interactive":`planCanvas-opening-hit-interactive_D4ZUY`,planCanvasOpeningHitInteractive:O,"planCanvas-opening-outline":`planCanvas-opening-outline_HS2wY`,planCanvasOpeningOutline:k,"planCanvas-jamb":`planCanvas-jamb_e-I9r`,planCanvasJamb:A,"planCanvas-jamb-highlighted":`planCanvas-jamb-highlighted_rWYxZ`,planCanvasJambHighlighted:j,"planCanvas-selection":`planCanvas-selection_0a31R`,planCanvasSelection:M};export{N as default,e as planCanvas,C as planCanvasDoorLeaf,w as planCanvasDoorSwing,r as planCanvasGrid,A as planCanvasJamb,j as planCanvasJambHighlighted,D as planCanvasOpeningHit,O as planCanvasOpeningHitInteractive,E as planCanvasOpeningHovered,k as planCanvasOpeningOutline,S as planCanvasOpeningSelected,x as planCanvasOpenings,u as planCanvasRoomArea,g as planCanvasRoomEdgeCaps,v as planCanvasRoomEdgeFill,_ as planCanvasRoomEdgeOutline,m as planCanvasRoomEdgeSelected,a as planCanvasRoomFill,s as planCanvasRoomFillHovered,o as planCanvasRoomFillInteractive,c as planCanvasRoomLabel,l as planCanvasRoomName,i as planCanvasRooms,t as planCanvasScreen,M as planCanvasSelection,n as planCanvasUnderlay,h as planCanvasWallCaps,p as planCanvasWallFill,b as planCanvasWallHovered,f as planCanvasWallOutline,y as planCanvasWallSelected,d as planCanvasWalls,T as planCanvasWindowPane};
2
2
  //# sourceMappingURL=planCanvas.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"planCanvas.module.mjs","names":[],"sources":["../../../../package/common/planCanvas/planCanvas.module.pcss"],"sourcesContent":["/**\n * Every colour comes from a theme variable. The wall fill/outline pair in particular\n * must stay two distinct surfaces, or the two-pass stroke has nothing to reveal.\n */\n\n.planCanvas {\n display: block;\n touch-action: none;\n user-select: none;\n background: var(--plan-canvas-background, var(--background));\n\n &-screen {\n pointer-events: none;\n }\n\n /* The storey below, for lining walls up between floors. Faint and dashed so it reads\n as a tracing under the drawing rather than as part of it, and never picks up a\n pointer: it is not this floor's geometry. */\n &-underlay {\n pointer-events: none;\n\n line {\n stroke: var(--plan-underlay-color, var(--text-dark));\n opacity: 0.28;\n stroke-dasharray: 6 5;\n stroke-linecap: round;\n vector-effect: non-scaling-stroke;\n }\n }\n\n &-grid {\n pointer-events: none;\n\n line {\n stroke: var(--plan-grid-color, var(--text-color));\n opacity: 0.1;\n }\n }\n\n /* ── Rooms ── */\n\n &-rooms {\n pointer-events: auto;\n }\n\n &-roomFill {\n fill: var(--plan-room-fill, var(--background-accent));\n stroke: none;\n transition:\n fill 0.12s ease-out,\n opacity 0.12s ease-out;\n\n &-interactive {\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &:focus-visible {\n outline: none;\n stroke: var(--focus-border-color, var(--primary-color));\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n }\n }\n\n /* Hover tints the floor, selection colours the walls: two channels, so both can be\n read at once. A fill answers \"which room\" instantly, where a shared wall is\n ambiguous between the rooms either side of it. */\n &-hovered {\n fill: var(--plan-room-fill-hover, var(--background-accent-light));\n }\n }\n\n &-roomLabel {\n pointer-events: none;\n }\n\n &-roomName {\n fill: var(--text-color);\n font-size: 13px;\n font-weight: 600;\n\n /* A halo, so a label stays legible over any room colour a consumer sets. */\n paint-order: stroke;\n stroke: var(--background);\n stroke-width: 3px;\n stroke-linejoin: round;\n }\n\n &-roomArea {\n fill: var(--text-dark);\n font-size: 11px;\n paint-order: stroke;\n stroke: var(--background);\n stroke-width: 3px;\n stroke-linejoin: round;\n }\n\n /* ── Walls ── */\n\n &-walls {\n pointer-events: none;\n }\n\n /*\n * A mitred corner runs to 1 / sin(angle / 2) times the stroke width, so an acute one\n * grows without bound and reads as a spike. 4 keeps a true point down to about 29\n * degrees and caps it at twice the wall thickness, which covers every angle a building\n * plausibly has; SVG bevels anything sharper.\n */\n &-wallOutline path {\n fill: none;\n stroke: var(--plan-wall-outline, var(--text-color));\n stroke-linecap: butt;\n stroke-linejoin: miter;\n stroke-miterlimit: var(--plan-wall-miter-limit, 4);\n }\n\n /* Must match the outline pass exactly: the two are the same shape, and the visible\n outline is what is left of the first after this one covers its middle. */\n &-wallFill path {\n fill: none;\n stroke: var(--plan-wall-fill, var(--text-dark));\n stroke-linecap: butt;\n stroke-linejoin: miter;\n stroke-miterlimit: var(--plan-wall-miter-limit, 4);\n }\n\n &-wallCaps line {\n stroke: var(--plan-wall-outline, var(--text-color));\n stroke-linecap: butt;\n }\n\n /* Drawn from the same geometry as the walls, so it inherits their corners and their\n gaps at doors. */\n &-roomEdgeCaps line {\n stroke: var(--plan-room-edge-selected, var(--primary-color));\n stroke-linecap: butt;\n }\n\n &-roomEdgeSelected path {\n fill: none;\n stroke-linecap: butt;\n stroke-linejoin: miter;\n stroke-miterlimit: var(--plan-wall-miter-limit, 4);\n }\n\n /* Edge darker than body, so the wall keeps the crisp outline every other wall has\n rather than turning into a flat slab, and reads as one highlighted object. */\n &-roomEdgeSelected {\n .planCanvas-roomEdgeOutline {\n stroke: var(--plan-room-edge-selected, var(--primary-color));\n }\n\n .planCanvas-roomEdgeFill {\n stroke: var(--plan-room-edge-selected-fill, var(--primary-lighter));\n }\n }\n\n &-wallSelected {\n stroke: var(--primary-color);\n opacity: 0.45;\n stroke-linecap: butt;\n }\n\n &-wallHovered {\n stroke: var(--primary-lighter);\n opacity: 0.35;\n stroke-linecap: butt;\n }\n\n /* ── Openings ── */\n\n &-openings {\n pointer-events: auto;\n }\n\n &-opening {\n /*\n * State lives on the group so the whole symbol responds, not just the box drawn round\n * it by `-outline`: a door reads as selected when its leaf and swing do, the way the\n * room fill does, rather than by acquiring a rectangle.\n */\n &-selected {\n .planCanvas-doorLeaf,\n .planCanvas-doorSwing,\n .planCanvas-windowPane {\n stroke: var(--primary-color);\n }\n\n .planCanvas-doorSwing {\n opacity: 0.9;\n }\n }\n\n &-hovered {\n .planCanvas-doorLeaf,\n .planCanvas-doorSwing,\n .planCanvas-windowPane {\n stroke: var(--primary-lighter, var(--primary-color));\n }\n }\n\n &-hit {\n fill: transparent;\n stroke: none;\n pointer-events: none;\n\n &-interactive {\n pointer-events: auto;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n &-outline {\n fill: none;\n stroke: var(--primary-color);\n stroke-width: 2;\n }\n }\n\n &-jamb {\n stroke: var(--plan-wall-outline, var(--text-color));\n stroke-linecap: butt;\n\n &-highlighted {\n stroke: var(--plan-room-edge-selected, var(--primary-color));\n }\n }\n\n &-doorLeaf {\n fill: none;\n stroke: var(--plan-door-color, var(--text-dark));\n stroke-linecap: butt;\n }\n\n &-doorSwing {\n fill: none;\n stroke: var(--plan-door-color, var(--text-dark));\n stroke-dasharray: 6 4;\n opacity: 0.6;\n }\n\n &-windowPane {\n stroke: var(--plan-window-color, var(--info-color));\n stroke-linecap: butt;\n }\n\n &-selection {\n pointer-events: none;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"planCanvas.module.mjs","names":[],"sources":["../../../../package/common/planCanvas/planCanvas.module.pcss"],"sourcesContent":["/**\n * Every colour comes from a theme variable. The wall fill/outline pair in particular\n * must stay two distinct surfaces, or the two-pass stroke has nothing to reveal.\n */\n\n.planCanvas {\n /*\n * The wall body and its edge, resolved once: the outline pass, the caps and the jamb\n * faces are the same edge of the same object and must not drift apart. Both mix towards\n * the canvas rather than sitting at the text colour, so a wall reads as mass on the\n * floor instead of as ink drawn over it. `--plan-wall-outline` and `--plan-wall-fill`\n * are still the knobs a consumer sets.\n */\n --plan-wall-edge-resolved: var(--plan-wall-outline, color-mix(in oklab, var(--text-color) 38%, var(--background)));\n --plan-wall-fill-resolved: var(--plan-wall-fill, color-mix(in oklab, var(--text-color) 58%, var(--background)));\n\n display: block;\n touch-action: none;\n user-select: none;\n background: var(--plan-canvas-background, var(--background));\n\n &-screen {\n pointer-events: none;\n }\n\n /* The storey below, for lining walls up between floors. Faint and dashed so it reads\n as a tracing under the drawing rather than as part of it, and never picks up a\n pointer: it is not this floor's geometry. */\n &-underlay {\n pointer-events: none;\n\n line {\n stroke: var(--plan-underlay-color, var(--text-dark));\n opacity: 0.28;\n stroke-dasharray: 6 5;\n stroke-linecap: round;\n vector-effect: non-scaling-stroke;\n }\n }\n\n &-grid {\n pointer-events: none;\n\n line {\n stroke: var(--plan-grid-color, var(--text-color));\n opacity: 0.1;\n }\n }\n\n /* ── Rooms ── */\n\n &-rooms {\n pointer-events: auto;\n }\n\n &-roomFill {\n fill: var(--plan-room-fill, var(--background-accent));\n stroke: none;\n transition:\n fill 0.12s ease-out,\n opacity 0.12s ease-out;\n\n &-interactive {\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &:focus-visible {\n outline: none;\n stroke: var(--focus-border-color, var(--primary-color));\n stroke-width: 2;\n vector-effect: non-scaling-stroke;\n }\n }\n\n /* Hover tints the floor, selection colours the walls: two channels, so both can be\n read at once. A fill answers \"which room\" instantly, where a shared wall is\n ambiguous between the rooms either side of it. */\n &-hovered {\n fill: var(--plan-room-fill-hover, var(--background-accent-light));\n }\n }\n\n &-roomLabel {\n pointer-events: none;\n }\n\n &-roomName {\n fill: var(--text-color);\n font-size: 13px;\n font-weight: 600;\n\n /* A halo, so a label stays legible over any room colour a consumer sets. */\n paint-order: stroke;\n stroke: var(--background);\n stroke-width: 3px;\n stroke-linejoin: round;\n }\n\n &-roomArea {\n fill: var(--text-dark);\n font-size: 11px;\n paint-order: stroke;\n stroke: var(--background);\n stroke-width: 3px;\n stroke-linejoin: round;\n }\n\n /* ── Walls ── */\n\n &-walls {\n pointer-events: none;\n }\n\n /*\n * Round joins, so the outer corners of the building come out softened and an acute\n * corner cannot fire a mitre spike out of the junction at all. `--plan-wall-join: miter`\n * restores the drafting corner, and `--plan-wall-miter-limit` then caps how far the\n * spike may run. The selection highlight shares the rule: it is drawn from the same\n * geometry over the same walls, so a different join would leave crescents showing.\n */\n &-wallOutline path,\n &-wallFill path,\n &-roomEdgeSelected path {\n fill: none;\n stroke-linecap: butt;\n stroke-linejoin: var(--plan-wall-join, round);\n stroke-miterlimit: var(--plan-wall-miter-limit, 4);\n }\n\n &-wallOutline path {\n stroke: var(--plan-wall-edge-resolved);\n }\n\n /* Must match the outline pass exactly: the two are the same shape, and the visible\n outline is what is left of the first after this one covers its middle. */\n &-wallFill path {\n stroke: var(--plan-wall-fill-resolved);\n }\n\n &-wallCaps line {\n stroke: var(--plan-wall-edge-resolved);\n stroke-linecap: butt;\n }\n\n /* Drawn from the same geometry as the walls, so it inherits their corners and their\n gaps at doors. */\n &-roomEdgeCaps line {\n stroke: var(--plan-room-edge-selected, var(--primary-color));\n stroke-linecap: butt;\n }\n\n /* Edge darker than body, so the wall keeps the crisp outline every other wall has\n rather than turning into a flat slab, and reads as one highlighted object. */\n &-roomEdgeSelected {\n .planCanvas-roomEdgeOutline {\n stroke: var(--plan-room-edge-selected, var(--primary-color));\n }\n\n .planCanvas-roomEdgeFill {\n stroke: var(--plan-room-edge-selected-fill, var(--primary-lighter));\n }\n }\n\n &-wallSelected {\n stroke: var(--primary-color);\n opacity: 0.45;\n stroke-linecap: butt;\n }\n\n &-wallHovered {\n stroke: var(--primary-lighter);\n opacity: 0.35;\n stroke-linecap: butt;\n }\n\n /* ── Openings ── */\n\n &-openings {\n pointer-events: auto;\n }\n\n &-opening {\n /*\n * State lives on the group so the whole symbol responds, not just the box drawn round\n * it by `-outline`: a door reads as selected when its leaf and swing do, the way the\n * room fill does, rather than by acquiring a rectangle.\n */\n &-selected {\n .planCanvas-doorLeaf,\n .planCanvas-doorSwing,\n .planCanvas-windowPane {\n stroke: var(--primary-color);\n }\n\n .planCanvas-doorSwing {\n opacity: 0.9;\n }\n }\n\n &-hovered {\n .planCanvas-doorLeaf,\n .planCanvas-doorSwing,\n .planCanvas-windowPane {\n stroke: var(--primary-lighter, var(--primary-color));\n }\n }\n\n &-hit {\n fill: transparent;\n stroke: none;\n pointer-events: none;\n\n &-interactive {\n pointer-events: auto;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n &-outline {\n fill: none;\n stroke: var(--primary-color);\n stroke-width: 2;\n }\n }\n\n /* The wall seen in section, so it takes the body colour rather than the edge one: at a\n doorway it is the only thing standing for the wall, and the edge tone disappears. */\n &-jamb {\n stroke: var(--plan-wall-fill-resolved);\n stroke-linecap: butt;\n\n &-highlighted {\n stroke: var(--plan-room-edge-selected, var(--primary-color));\n }\n }\n\n &-doorLeaf {\n fill: none;\n stroke: var(--plan-door-color, var(--text-dark));\n stroke-linecap: butt;\n }\n\n &-doorSwing {\n fill: none;\n stroke: var(--plan-door-color, var(--text-dark));\n stroke-dasharray: 6 4;\n opacity: 0.6;\n }\n\n &-windowPane {\n stroke: var(--plan-window-color, var(--info-color));\n stroke-linecap: butt;\n }\n\n &-selection {\n pointer-events: none;\n }\n}\n"],"mappings":""}
@@ -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 Ie,useImperativeHandle as Le,useMemo as Re,useRef as h,useState as g}from"react";import _ from"classnames";import{faAngleDown as ze,faAngleUp as Be,faArrowPointer as Ve,faArrowRotateLeft as He,faArrowRotateRight as Ue,faBorderAll as We,faClone as Ge,faDoorOpen as Ke,faDownload as qe,faDraftingCompass as Je,faExpand as Ye,faLayerGroup as Xe,faMagnet as Ze,faMagnifyingGlassMinus as Qe,faMagnifyingGlassPlus as $e,faMinus as et,faPlus as tt,faRulerCombined as nt,faSquare as rt,faTrash as it,faUpload as at,faWindowMaximize as ot}from"@fortawesome/free-solid-svg-icons";import{Fragment as st,jsx as v,jsxs as y}from"react/jsx-runtime";var ct=[`select`,`wall`,`rect`,`door`,`window`,`archway`,`measure`],lt={v:`select`,w:`wall`,r:`rect`,d:`door`,n:`window`,a:`archway`,m:`measure`},ut={door:a.Door,window:a.Window,archway:a.Archway},dt={[a.Door]:`Door`,[a.Window]:`Window`,[a.Archway]:`Archway`,[a.Gap]:`Gap`},ft={[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}},pt=1,mt=4,ht=[];function gt(e){return e>=1e3?`${(e/1e3).toFixed(2)} m`:`${Math.round(e)} mm`}function _t(e){let t=e/1e6;return`${t.toFixed(+(t<10))} m²`}function vt(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 b=Fe(function(a,Fe){let{value:b,defaultValue:yt,onChange:x,onChangeEnd:bt,floorId:xt,defaultFloorId:St,onFloorChange:Ct,showFloorBar:wt=!0,showUnderlay:Tt=!0,tool:Et,defaultTool:Dt=`select`,onToolChange:Ot,tools:kt=ct,selection:At,defaultSelection:jt,onSelectionChange:Mt,multiSelect:Nt=!0,onHoverChange:Pt,view:Ft,defaultView:It,onViewChange:Lt,minZoom:Rt=.005,maxZoom:zt=2,fitOnMount:Bt=!0,gridSize:S=100,showGrid:Vt=!0,snap:Ht=!0,angleLock:Ut=!1,constrainAngle:Wt=45,showSnapGuides:Gt=!0,wallThickness:Kt=c.thickness,wallHeight:qt,openingDefaults:Jt,showMeasurements:Yt=!0,formatLength:Xt=gt,formatArea:Zt=_t,showToolbar:Qt=!0,showInspector:$t=!0,showHint:en=!0,showHistoryControls:tn=!0,showFileControls:nn=!0,fileName:rn,onImport:an,historyMode:on=`internal`,historyLimit:sn=50,onHistoryChange:cn,readOnly:ln=!1,disabled:C=!1,canvasHeight:un=`420px`,getRoomColor:dn,renderRoomLabel:fn,labels:w,icons:T,"aria-label":pn,className:mn,style:hn,classNames:E,styles:D,...gn}=e(`RoomDrawer`,a),_n=r(),O=_n?Te:we,vn=h(null),yn=h(null),bn=h(null),xn=h(null),k=h({kind:`none`}),A=h(new Map),Sn=h(null),Cn=h(!1),wn=h(!1),Tn=h(!1),En=Re(()=>yt??b??fe(),[]),j=Pe(En,sn),Dn=b!==void 0,M=Dn?b:j.present;Ie(()=>{if(Dn&&b){if(b===xn.current){j.replace(b);return}j.commit(b,`external`)}},[b,Dn]);let[On,kn]=g(St),An=xt??On??M.floors[0]?.id,N=Re(()=>ge(M,An)??ge(M)??fe().floors[0],[M,An]),[jn,Mn]=g(Tt);Ie(()=>Mn(Tt),[Tt]);let Nn=Re(()=>jn?pe(M,N.id):null,[jn,M,N.id]),Pn=m(e=>{e!==N.id&&(xt===void 0&&kn(e),Ct?.(e))},[N.id,xt,Ct]),P=Re(()=>Ce(N),[N]).rooms,[Fn,In]=g(Dt),F=Et??Fn,Ln=m(e=>{Et===void 0&&In(e),Ot?.(e)},[Et,Ot]),[Rn,zn]=g(jt??ht),I=At===void 0?Rn:At,L=h(I);L.current=I;let R=m(e=>{let t=e===null?ht:Array.isArray(e)?e:[e];L.current=t,At===void 0&&zn(t),Mt?.([...t])},[At,Mt]),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=Re(()=>Vn(I),[Vn,I]),[Un,Wn]=g(null),[Gn,Kn]=g(It??{x:0,y:0,zoom:.05}),B=Ft??Gn,V=m(e=>{Ft===void 0&&Kn(e),Lt?.(e)},[Ft,Lt]),[H,qn]=g({width:800,height:420}),[U,Jn]=g([]),[W,Yn]=g(null),[Xn,Zn]=g(Ht),[Qn,$n]=g(Ut);Ie(()=>Zn(Ht),[Ht]),Ie(()=>$n(Ut),[Ut]);let[er,tr]=g(Vt);Ie(()=>tr(Vt),[Vt]);let nr=h(null),[G,rr]=g(null),[K,ir]=g([]),ar=h(0),[or,sr]=g(null),cr=h(null),lr=m(e=>{let t=d(O,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,O,B.zoom]),[ur,dr]=g(null),q=!ln&&!C,fr=Re(()=>{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]);Ie(()=>{let e=yn.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=yn.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:S,angleStepDeg:o?Wt:0,toleranceScreenPx:_n?16:10}});return nr.current=s,s},[N,B.zoom,Xn,Qn,S,Wt,_n]),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(Rt,Math.min(zt,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,Rt,zt,V]),gr=h(!1);Ie(()=>{Bt&&!gr.current&&Object.keys(N.nodes).length!==0&&(H.width<=1||(gr.current=!0,hr()))},[Bt,N,H.width,hr]);let _r=m((e,t,n,r=[],i={})=>{if(e===N)return M;let a=be(M,e);xn.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 x?.(a,o),n&&bt?.(a,o),a},[N,M,j,x,bt]),X=m((e,t,n=[],r={})=>{let i=Se(le(e).floor).floor;return _r(i,t,!0,n,r)},[_r]);Ie(()=>{cn?.({canUndo:j.canUndo,canRedo:j.canRedo})},[j.canUndo,j.canRedo,cn]);let vr=Re(()=>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=Re(()=>{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([])},[]),Tr=m(e=>{if(C)return;if(vn.current?.focus(),dr(null),A.current.set(e.pointerId,{x:e.clientX,y:e.clientY}),e.currentTarget.setPointerCapture?.(e.pointerId),A.current.size===2){let[e,t]=[...A.current.values()];k.current.kind!==`none`&&k.current.kind!==`pan`&&j.cancelGesture(),k.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(A.current.size>2)return;if(Sn.current={client:{x:e.clientX,y:e.clientY},moved:!1},e.button===1||Cn.current){k.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(O,B.zoom));R(e);return}if(F===`rect`){let e=Y(t).point;k.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);k.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;k.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:Kt,type:o.Interior,height:qt},d(O,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(O,B.zoom).node?wr():Jn(e=>[...e,n]);return}let n=ut[F];if(n){let e=d(O,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={...ft[n],...Jt?.[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(O,B.zoom);if(br&&z?.type===`wall`&&Math.hypot(t.x-br.x,t.y-br.y)<=r.node){j.beginGesture(),k.current={kind:`wallSplit`,wallId:z.id,at:br};return}let i=Ee(N,P,t,r),a=Nt&&(e.ctrlKey||e.metaKey);if(!i){a||R(null),k.current=Nt?{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(),k.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),k.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})}k.current={kind:`room`,nodeIds:e,startWorld:t,orig:n,moved:!1};return}if(i.type===`node`)k.current={kind:`node`,nodeId:i.id,moved:!1,...mr(i.id)};else if(i.type===`wall`){let e=N.walls[i.id];k.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`)k.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})}k.current={kind:`room`,nodeIds:n,startWorld:t,orig:r,moved:!1}}},[C,q,B,F,N,P,O,pr,Y,U,Kt,qt,Jt,X,R,br,z,fr,mr,Vn,Nt,Bn,j,wr,lr,K]),Er=m(e=>{if(C)return;A.current.has(e.pointerId)&&A.current.set(e.pointerId,{x:e.clientX,y:e.clientY});let t=k.current;if(t.kind===`pinch`&&A.current.size>=2){let[e,n]=[...A.current.values()],r=Math.hypot(n.x-e.x,n.y-e.y);if(t.startDist<=0)return;let i=Math.max(Rt,Math.min(zt,t.startView.zoom*(r/t.startDist))),a=yn.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)>mt&&(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(O,B.zoom));De(e,Un)||(Wn(e),Pt?.(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`){k.current={...t,current:Y(n).point},Yn(Y(n).point);return}if(t.kind===`marquee`){k.current={...t,current:n},Yn(n);return}if(t.kind===`wallSplit`){let e=se(N,t.wallId,t.at);if(!e.result.wallIds){k.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;k.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),k.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=Ht!==wn.current&&S>0?S: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;k.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,k.current={...t,detachedSign:void 0,moved:!0}):k.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);k.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=Ht!==wn.current&&S>0?S: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)}k.current={...t,moved:!0},_r(s,`move-room`,!1,t.nodeIds)}}},[C,q,F,N,P,Un,O,B.zoom,Rt,zt,S,Ht,pr,Y,_r,V,R,U,fr,Pt,lr]),Dr=m((e,t)=>{A.current.delete(e.pointerId);let n=k.current;k.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&&x?.(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>pt&&(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:Kt,type:o.Interior,height:qt},d(O,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(O,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,O,B.zoom,Kt,qt,X,R,Bn,x]);Ie(()=>{let e=yn.current;if(!e||C)return;function t(t){t.preventDefault();let n=e.getBoundingClientRect(),r=Math.exp(-t.deltaY*.002);V((()=>{let e=Or.current,i=Math.max(Rt,Math.min(zt,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)},[C,Rt,zt,V]);let Or=h(B);Or.current=B;let kr=m(e=>{let t=Math.max(Rt,Math.min(zt,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,Rt,zt,V]),Ar=m(()=>{if(on===`none`)return;let e=j.undo();e&&(xn.current=e,x?.(e,{reason:`undo`,committed:!0,targetIds:[]}),bt?.(e,{reason:`undo`,committed:!0,targetIds:[]}))},[on,j,x,bt]),jr=m(()=>{if(on===`none`)return;let e=j.redo();e&&(xn.current=e,x?.(e,{reason:`redo`,committed:!0,targetIds:[]}),bt?.(e,{reason:`redo`,committed:!0,targetIds:[]}))},[on,j,x,bt]),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=S>0?S: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,S,X]),Pr=m(e=>{if(C)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(),Nt&&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=lt[e.key.toLowerCase()];i&&q&&kt.includes(i)&&(Ln(i),wr())},[C,q,kt,F,U,K.length,or,jr,Ar,R,wr,Cr,kr,hr,Nr,Ln,Nt,Mr]),Q=m((e,t,n)=>{xn.current=e,n?.resetHistory?(j.clearHistory(),j.replace(e)):j.commit(e,t);let r={reason:t,committed:!0,targetIds:[]};x?.(e,r),bt?.(e,r)},[j,x,bt]),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??rn??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)},[rn,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),an?.(t),t},[an,Q]),Ur=m(e=>{e.text().then(e=>Hr(e)).catch(e=>{let t=[`Could not read that file: ${e.message}`];dr(t),an?.({plan:null,issues:t})})},[Hr,an]),Wr=m(()=>ir([]),[]),Gr=m(e=>{e.key===`Shift`&&(Tn.current=!1),e.key===`Alt`&&(wn.current=!1),e.key===` `&&(Cn.current=!1)},[]);Le(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:()=>on!==`none`&&j.canUndo,canRedo:()=>on!==`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:()=>bn.current}),[M,j,Q,N,Pn,Fr,Ir,Lr,Br,Rr,zr,Wr,Vr,Hr,Ar,jr,on,R,Bn,Mr,Cr,B,V,kr,hr,pr,J]);let $=k.current,Kr=Re(()=>{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<pt)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(y(`g`,{className:_(p.roomDrawerMeasureLine,or===n.id&&p.roomDrawerMeasureLineHovered,E?.measureLine),children:[v(`line`,{x1:t.x,y1:t.y,x2:r.x,y2:r.y}),v(`line`,{x1:t.x-o,y1:t.y-s,x2:t.x+o,y2:t.y+s}),v(`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(v(`circle`,{className:p.roomDrawerMeasureGrip,cx:a.x,cy:a.y,r:4},`measure-grip-${n.id}-${i}`));e.push(v(`text`,{className:_(p.roomDrawerMeasure,E?.measureLine),x:c.x,y:c.y-8,textAnchor:`middle`,children:`${Xt(i)} · ${vt(a)}`},`measure-label-${n.id}`))}if(Gt&&G&&(G.guides.forEach((t,n)=>{let r=J(t.a),i=J(t.b);e.push(v(`line`,{className:_(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(v(`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(v(`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);Yt&&(s>0||c>0)&&(e.push(v(`text`,{className:p.roomDrawerMeasure,x:(r+a)/2,y:i-8,textAnchor:`middle`,children:Xt(s)},`rect-width`),v(`text`,{className:p.roomDrawerMeasure,x:r-8,y:(i+o)/2,textAnchor:`end`,dominantBaseline:`central`,children:Xt(c)},`rect-height`)),s>0&&c>0&&e.push(v(`text`,{className:_(p.roomDrawerMeasure,p.roomDrawerMeasureSecondary),x:(r+a)/2,y:(i+o)/2,textAnchor:`middle`,dominantBaseline:`central`,children:Zt(s*c)},`rect-area`)))}if(F===`wall`&&U.length>0){let t=[...U,W].filter(Boolean).map(J);if(e.push(v(`polyline`,{className:p.roomDrawerPreview,points:t.map(e=>`${e.x},${e.y}`).join(` `),fill:`none`},`chain`)),t.forEach((t,n)=>{e.push(v(`circle`,{className:p.roomDrawerHandle,cx:t.x,cy:t.y,r:4},`chain-dot-${n}`))}),Yt&&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(v(`text`,{className:_(p.roomDrawerMeasure,i&&p.roomDrawerMeasureLocked),x:r.x,y:r.y-8,textAnchor:`middle`,children:`${Xt(n)} · ${vt(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(v(`circle`,{className:_(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(v(`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(v(`circle`,{className:p.roomDrawerMidHandle,cx:t.x,cy:t.y,r:4},`midpoint`))}if(Yt&&$.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(v(`text`,{className:_(p.roomDrawerMeasure,p.roomDrawerMeasureOffset),x:s.x,y:s.y-26,textAnchor:`middle`,children:`${Xt(Math.hypot(i,a))} · ${vt(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(v(`text`,{className:_(p.roomDrawerMeasure,p.roomDrawerMeasureSecondary),x:s.x,y:s.y-8,textAnchor:`middle`,children:`${Xt(Math.hypot(o.x-a.x,o.y-a.y))} · ${vt(Math.atan2(o.y-a.y,o.x-a.x))}`},`room-stretch-${n.id}`))}}if(Yt&&(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(v(`text`,{className:_(p.roomDrawerMeasure,!a&&p.roomDrawerMeasureSecondary,a&&i&&p.roomDrawerMeasureLocked),x:l.x,y:l.y-8,textAnchor:`middle`,children:`${Xt(Math.hypot(c.x-s.x,c.y-s.y))} · ${vt(Math.atan2(c.y-s.y,c.x-s.x))}`},`measure-${n.id}`))}}return v(st,{children:e})},[q,$,F,U,W,I,N,P,z,Hn,br,Yt,Gt,G,fr,Xt,Zt,K,or,E?.measureLine,J]),qr={select:{icon:Ve,label:w?.select??`Select and edit`,key:`V`},wall:{icon:et,label:w?.wall??`Draw walls`,key:`W`},rect:{icon:rt,label:w?.rect??`Draw a room`,key:`R`},door:{icon:Ke,label:w?.door??`Add a door`,key:`D`},window:{icon:ot,label:w?.window??`Add a window`,key:`N`},archway:{icon:Ye,label:w?.archway??`Add an archway`,key:`A`},measure:{icon:nt,label:w?.measure??`Measure`,key:`M`}},Jr=q?F===`wall`?w?.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`?w?.hintRect??`Drag to draw a room`:F===`measure`?w?.hintMeasure??`Drag to measure · Drag an end or the line to adjust it · Delete removes one, Escape clears them`:ut[F]?w?.hintOpening??`Click a wall to cut an opening into it`:w?.hintSelect??(Nt?`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?w?.selectedFloor??`Floor`:I.length>1?(w?.selectedCount??`{count} selected`).replace(`{count}`,String(I.length)):yr?w?.selectedOpening??dt[yr.kind]:Z?w?.selectedWall??`Wall`:z?.type===`room`?w?.selectedRoom??`Room`:w?.selectedCorner??`Corner`,Xr=q?kt:[];return y(`div`,{...gn,ref:vn,className:_(p.roomDrawer,C&&p.roomDrawerDisabled,mn,E?.root),style:{...hn,...D?.root},role:`application`,"aria-label":pn??`Floor plan editor`,tabIndex:C?-1:0,onKeyDown:Pr,onKeyUp:Gr,children:[Qt&&y(`div`,{className:_(p.roomDrawerToolbar,E?.toolbar),style:D?.toolbar,role:`toolbar`,"aria-label":`Drawing tools`,children:[Xr.map(e=>{let n=qr[e];return v(`button`,{type:`button`,className:_(p.roomDrawerToolButton,e===F&&p.roomDrawerToolButtonActive,E?.toolButton),style:D?.toolButton,title:`${n.label} (${n.key})`,"aria-label":n.label,"aria-pressed":e===F,onClick:()=>{Ln(e),wr()},children:t(T?.[e]??n.icon,{className:_(p.roomDrawerToolIcon,E?.toolIcon),style:D?.toolIcon})},e)}),Xr.length>0&&v(`span`,{className:p.roomDrawerToolbarSeparator}),q&&y(st,{children:[[{on:Xn,toggle:()=>Zn(e=>!e),icon:T?.snap??Ze,label:w?.snap??`Snap to grid and geometry`,key:`S`},{on:Qn,toggle:()=>$n(e=>!e),icon:T?.angleLock??Je,label:w?.angleLock??`Lock to ${Wt}° angles`,key:`L`},{on:er,toggle:()=>tr(e=>!e),icon:T?.grid??We,label:w?.grid??`Show grid`,key:`G`},...pe(M,N.id)?[{on:jn,toggle:()=>Mn(e=>!e),icon:T?.underlay??Xe,label:w?.underlay??`Show the floor below`,key:`B`}]:[]].map(e=>v(`button`,{type:`button`,className:_(p.roomDrawerToolButton,e.on&&p.roomDrawerToolButtonOn,E?.toolButton),style:D?.toolButton,title:`${e.label} (${e.key})`,"aria-label":e.label,"aria-pressed":e.on,onClick:e.toggle,children:t(e.icon,{className:_(p.roomDrawerToolIcon,E?.toolIcon),style:D?.toolIcon})},e.key)),v(`span`,{className:p.roomDrawerToolbarSeparator})]}),tn&&on!==`none`&&q&&y(st,{children:[v(`button`,{type:`button`,className:_(p.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.undo??`Undo`,"aria-label":w?.undo??`Undo`,disabled:!j.canUndo,onClick:Ar,children:t(T?.undo??He)}),v(`button`,{type:`button`,className:_(p.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.redo??`Redo`,"aria-label":w?.redo??`Redo`,disabled:!j.canRedo,onClick:jr,children:t(T?.redo??Ue)}),v(`span`,{className:p.roomDrawerToolbarSeparator})]}),nn&&y(st,{children:[v(`button`,{type:`button`,className:_(p.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.download??`Download plan`,"aria-label":w?.download??`Download plan`,onClick:()=>Vr(),children:t(T?.download??qe)}),q&&v(`button`,{type:`button`,className:_(p.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.upload??`Open a plan file`,"aria-label":w?.upload??`Open a plan file`,onClick:()=>cr.current?.click(),children:t(T?.upload??at)}),v(`span`,{className:p.roomDrawerToolbarSeparator})]}),y(`div`,{className:_(p.roomDrawerViewControls,E?.viewControls),style:D?.viewControls,children:[v(`button`,{type:`button`,className:_(p.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.zoomOut??`Zoom out`,"aria-label":w?.zoomOut??`Zoom out`,onClick:()=>kr(1/1.25),children:t(T?.zoomOut??Qe)}),y(`button`,{type:`button`,className:_(p.roomDrawerZoomLabel,E?.zoomLabel),style:D?.zoomLabel,title:w?.fit??`Fit to content`,onClick:()=>hr(),children:[Math.round(B.zoom*1e3)/10,`%`]}),v(`button`,{type:`button`,className:_(p.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.zoomIn??`Zoom in`,"aria-label":w?.zoomIn??`Zoom in`,onClick:()=>kr(1.25),children:t(T?.zoomIn??$e)})]})]}),wt&&M.floors.length>0&&y(`div`,{className:_(p.roomDrawerFloorBar,E?.floorBar),style:D?.floorBar,role:`tablist`,"aria-label":w?.selectedFloor??`Floor`,children:[[...M.floors].reverse().map(e=>v(`button`,{type:`button`,role:`tab`,className:_(p.roomDrawerFloorTab,e.id===N.id&&p.roomDrawerFloorTabActive,E?.floorTab),style:D?.floorTab,"aria-selected":e.id===N.id,onClick:()=>Pn(e.id),children:e.label},e.id)),q&&v(`button`,{type:`button`,className:_(p.roomDrawerFloorTab,p.roomDrawerFloorTabAdd),title:w?.addFloor??`Add a floor above`,"aria-label":w?.addFloor??`Add a floor above`,onClick:()=>Fr(),children:t(T?.addFloor??tt)})]}),v(`div`,{ref:yn,className:_(p.roomDrawerCanvasWrapper,q&&F!==`select`&&p.roomDrawerCanvasWrapperDrawing,E?.canvasWrapper),style:{height:un,...D?.canvasWrapper},onPointerDown:Tr,onPointerMove:Er,onPointerUp:e=>Dr(e,!1),onPointerCancel:e=>Dr(e,!0),children:v(Ne,{ref:bn,floor:N,underlay:Nn,rooms:P,view:B,size:H,selection:I,hovered:Un,interactiveRooms:!1,showGrid:er,gridSize:S,showRoomLabels:!0,formatArea:Zt,getRoomColor:dn,renderRoomLabel:fn,overlay:Kr,classNames:E,styles:D})}),$t&&q&&y(`div`,{className:_(p.roomDrawerInspector,E?.inspector),style:D?.inspector,children:[v(`span`,{className:_(p.roomDrawerInspectorKind,I.length===0&&p.roomDrawerInspectorKindEmpty,E?.inspectorLabel),children:Yr}),I.length===0&&y(st,{children:[v(i,{className:_(p.roomDrawerInspectorName,E?.inspectorField),style:D?.inspectorField,label:w?.floorName??`Floor name`,value:N.label,onChange:e=>Br(N.id,e)}),v(Me,{className:_(p.roomDrawerInspectorField,E?.inspectorField),style:D?.inspectorField,label:w?.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&&y(st,{children:[v(`button`,{type:`button`,className:_(p.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,title:w?.moveFloorUp??`Move this floor up`,"aria-label":w?.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(T?.moveFloorUp??Be)}),v(`button`,{type:`button`,className:_(p.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,title:w?.moveFloorDown??`Move this floor down`,"aria-label":w?.moveFloorDown??`Move this floor down`,disabled:he(M,N.id)<=0,onClick:()=>Rr(N.id,he(M,N.id)-1),children:t(T?.moveFloorDown??ze)})]}),v(`button`,{type:`button`,className:_(p.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,title:w?.duplicateFloor??`Copy this floor to a new one above`,onClick:()=>Ir(),children:t(T?.duplicateFloor??Ge)}),M.floors.length>1&&v(n,{className:p.roomDrawerInspectorDelete,icon:T?.delete??it,title:w?.deleteFloor??`Delete this floor`,onClick:()=>Lr()})]}),vr?.meta&&y(st,{children:[v(i,{className:_(p.roomDrawerInspectorName,E?.inspectorField),style:D?.inspectorField,label:w?.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])}}),v(`span`,{className:_(p.roomDrawerInspectorLabel,E?.inspectorLabel),children:Zt(vr.area)})]}),Z&&v(`button`,{type:`button`,className:_(p.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,onClick:xr,title:w?.addCorner??`Add a corner to this wall`,children:w?.addCorner??`Add corner`}),Z&&v(Me,{className:_(p.roomDrawerInspectorField,E?.inspectorField),style:D?.inspectorField,label:w?.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&&y(st,{children:[v(Me,{className:_(p.roomDrawerInspectorField,E?.inspectorField),style:D?.inspectorField,label:w?.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])}}),v(Me,{className:_(p.roomDrawerInspectorField,E?.inspectorField),style:D?.inspectorField,label:w?.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&&v(n,{className:p.roomDrawerInspectorDelete,icon:T?.delete??it,title:w?.deleteSelection??`Delete selection`,onClick:Cr})]}),nn&&q&&v(`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)}}),en&&(ur!==null||Jr)&&v(`div`,{className:_(p.roomDrawerHint,ur!==null&&p.roomDrawerHintReport,E?.hint),style:D?.hint,role:ur===null?void 0:`status`,children:ur===null?Jr:ur.length===0?w?.importFailed??`That file could not be read as a floor plan`:ur.join(` · `)})]})});export{b 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":`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};
2
2
  //# sourceMappingURL=roomDrawer.mjs.map