@ahrowe/ui 0.25.2 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/esm/common/floorPlan/floorPlan.faces.mjs +2 -0
  2. package/dist/esm/common/floorPlan/floorPlan.faces.mjs.map +1 -0
  3. package/dist/esm/common/floorPlan/floorPlan.geometry.mjs +2 -0
  4. package/dist/esm/common/floorPlan/floorPlan.geometry.mjs.map +1 -0
  5. package/dist/esm/common/floorPlan/floorPlan.graph.mjs +2 -0
  6. package/dist/esm/common/floorPlan/floorPlan.graph.mjs.map +1 -0
  7. package/dist/esm/common/floorPlan/floorPlan.hit.mjs +2 -0
  8. package/dist/esm/common/floorPlan/floorPlan.hit.mjs.map +1 -0
  9. package/dist/esm/common/floorPlan/floorPlan.json.mjs +2 -0
  10. package/dist/esm/common/floorPlan/floorPlan.json.mjs.map +1 -0
  11. package/dist/esm/common/floorPlan/floorPlan.path.mjs +2 -0
  12. package/dist/esm/common/floorPlan/floorPlan.path.mjs.map +1 -0
  13. package/dist/esm/common/floorPlan/floorPlan.plan.mjs +2 -0
  14. package/dist/esm/common/floorPlan/floorPlan.plan.mjs.map +1 -0
  15. package/dist/esm/common/floorPlan/floorPlan.rooms.mjs +2 -0
  16. package/dist/esm/common/floorPlan/floorPlan.rooms.mjs.map +1 -0
  17. package/dist/esm/common/floorPlan/floorPlan.snap.mjs +2 -0
  18. package/dist/esm/common/floorPlan/floorPlan.snap.mjs.map +1 -0
  19. package/dist/esm/common/floorPlan/floorPlan.types.mjs +2 -0
  20. package/dist/esm/common/floorPlan/floorPlan.types.mjs.map +1 -0
  21. package/dist/esm/common/floorPlan/legacySvg.mjs +2 -0
  22. package/dist/esm/common/floorPlan/legacySvg.mjs.map +1 -0
  23. package/dist/esm/common/planCanvas/planCanvas.mjs +2 -0
  24. package/dist/esm/common/planCanvas/planCanvas.mjs.map +1 -0
  25. package/dist/esm/common/planCanvas/planCanvas.module.mjs +2 -0
  26. package/dist/esm/common/planCanvas/planCanvas.module.mjs.map +1 -0
  27. package/dist/esm/common/roomDrawer/roomDrawer.mjs +1 -1
  28. package/dist/esm/common/roomDrawer/roomDrawer.mjs.map +1 -1
  29. package/dist/esm/common/roomDrawer/roomDrawer.module.mjs +1 -1
  30. package/dist/esm/common/roomDrawer/roomDrawer.module.mjs.map +1 -1
  31. package/dist/esm/common/roomDrawer/usePlanHistory.mjs +2 -0
  32. package/dist/esm/common/roomDrawer/usePlanHistory.mjs.map +1 -0
  33. package/dist/esm/common/roomViewer/roomViewer.mjs +1 -1
  34. package/dist/esm/common/roomViewer/roomViewer.mjs.map +1 -1
  35. package/dist/esm/common/roomViewer/roomViewer.module.mjs +1 -1
  36. package/dist/esm/common/roomViewer/roomViewer.module.mjs.map +1 -1
  37. package/dist/esm/index.mjs +1 -1
  38. package/dist/index.cjs +3 -7
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/style.css +1 -1
  41. package/dist/types/package/common/configProvider/configProvider.types.d.ts +4 -0
  42. package/dist/types/package/common/floorPlan/floorPlan.faces.d.ts +33 -0
  43. package/dist/types/package/common/floorPlan/floorPlan.fixtures.d.ts +35 -0
  44. package/dist/types/package/common/floorPlan/floorPlan.geometry.d.ts +111 -0
  45. package/dist/types/package/common/floorPlan/floorPlan.graph.d.ts +139 -0
  46. package/dist/types/package/common/floorPlan/floorPlan.hit.d.ts +26 -0
  47. package/dist/types/package/common/floorPlan/floorPlan.json.d.ts +23 -0
  48. package/dist/types/package/common/floorPlan/floorPlan.path.d.ts +59 -0
  49. package/dist/types/package/common/floorPlan/floorPlan.plan.d.ts +98 -0
  50. package/dist/types/package/common/floorPlan/floorPlan.rooms.d.ts +47 -0
  51. package/dist/types/package/common/floorPlan/floorPlan.snap.d.ts +101 -0
  52. package/dist/types/package/common/floorPlan/floorPlan.types.d.ts +276 -0
  53. package/dist/types/package/common/floorPlan/index.d.ts +28 -0
  54. package/dist/types/package/common/floorPlan/legacySvg.d.ts +27 -0
  55. package/dist/types/package/common/planCanvas/index.d.ts +2 -0
  56. package/dist/types/package/common/planCanvas/planCanvas.d.ts +7 -0
  57. package/dist/types/package/common/planCanvas/planCanvas.types.d.ts +62 -0
  58. package/dist/types/package/common/roomDrawer/roomDrawer.d.ts +3 -3
  59. package/dist/types/package/common/roomDrawer/roomDrawer.types.d.ts +295 -15
  60. package/dist/types/package/common/roomDrawer/usePlanHistory.d.ts +24 -0
  61. package/dist/types/package/common/roomViewer/index.d.ts +1 -0
  62. package/dist/types/package/common/roomViewer/roomViewer.d.ts +9 -2
  63. package/dist/types/package/common/roomViewer/roomViewer.types.d.ts +88 -9
  64. package/dist/types/package/index.d.ts +1 -0
  65. package/docs/CLAUDE.md +1 -0
  66. package/docs/ConfigProvider.md +1 -0
  67. package/docs/FloorPlan.md +214 -0
  68. package/docs/RoomDrawer.md +330 -30
  69. package/docs/RoomViewer.md +80 -27
  70. package/package.json +1 -1
  71. package/dist/esm/common/roomDrawer/roomDrawer.utils.mjs +0 -6
  72. package/dist/esm/common/roomDrawer/roomDrawer.utils.mjs.map +0 -1
  73. package/dist/types/package/common/roomDrawer/roomDrawer.utils.d.ts +0 -32
  74. package/docs/room-drawing-analysis.md +0 -337
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePlanHistory.mjs","names":[],"sources":["../../../../package/common/roomDrawer/usePlanHistory.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nimport type { FloorPlan } from '../floorPlan';\nimport type { RoomDrawerChangeReason } from './roomDrawer.types';\n\n/**\n * Undo/redo over plan snapshots.\n *\n * Snapshots rather than command objects: every mutator already returns a fresh\n * immutable plan with structural sharing, so a snapshot costs a handful of pointers.\n * Commands would mean writing and testing an inverse for each of fifteen operations,\n * and an `addWall` that split three other walls on its way has no cheap inverse at all.\n *\n * The gesture API is what keeps a 200-move drag to ONE entry: `begin` stashes the plan\n * as it was, `update` replaces the present without pushing, and `end` pushes that single\n * stashed snapshot. A gesture that was aborted, or that ended where it started, pushes\n * nothing.\n */\n\n/** Discrete edits of the same kind on the same target merge if they land within this. */\nconst MERGE_WINDOW_MS = 500;\n\nexport interface PlanHistory {\n present: FloorPlan;\n canUndo: boolean;\n canRedo: boolean;\n\n /** Stashes the current plan as the snapshot a later `endGesture` would restore to. */\n beginGesture: () => void;\n /** Replaces the present mid-gesture. Pushes nothing. */\n updateGesture: (plan: FloorPlan) => void;\n /** Pushes the stashed snapshot, if the gesture actually changed anything. */\n endGesture: () => boolean;\n /** Discards the gesture and restores the stashed snapshot. */\n cancelGesture: () => FloorPlan | null;\n\n /** A discrete edit: pushes and replaces atomically. */\n commit: (plan: FloorPlan, reason: RoomDrawerChangeReason, targetIds?: string[]) => void;\n /** Replaces the present without touching history, for an externally driven value. */\n replace: (plan: FloorPlan) => void;\n\n undo: () => FloorPlan | null;\n redo: () => FloorPlan | null;\n clearHistory: () => void;\n isGestureActive: () => boolean;\n}\n\nexport function usePlanHistory(initial: FloorPlan, limit = 50): PlanHistory {\n const [present, setPresent] = useState<FloorPlan>(initial);\n const pastRef = useRef<FloorPlan[]>([]);\n const futureRef = useRef<FloorPlan[]>([]);\n const gestureStartRef = useRef<FloorPlan | null>(null);\n const presentRef = useRef<FloorPlan>(initial);\n const lastCommitRef = useRef<{ reason: string; targets: string; at: number } | null>(null);\n const [, forceCounter] = useState(0);\n\n const setBoth = useCallback((plan: FloorPlan) => {\n presentRef.current = plan;\n setPresent(plan);\n }, []);\n\n const push = useCallback(\n (snapshot: FloorPlan) => {\n pastRef.current = [...pastRef.current, snapshot].slice(-limit);\n futureRef.current = [];\n },\n [limit],\n );\n\n const beginGesture = useCallback(() => {\n gestureStartRef.current = presentRef.current;\n }, []);\n\n const updateGesture = useCallback(\n (plan: FloorPlan) => {\n setBoth(plan);\n },\n [setBoth],\n );\n\n const endGesture = useCallback(() => {\n const start = gestureStartRef.current;\n gestureStartRef.current = null;\n if (!start || start === presentRef.current) return false;\n push(start);\n lastCommitRef.current = null;\n forceCounter((n) => n + 1);\n return true;\n }, [push]);\n\n const cancelGesture = useCallback(() => {\n const start = gestureStartRef.current;\n gestureStartRef.current = null;\n if (!start) return null;\n setBoth(start);\n return start;\n }, [setBoth]);\n\n const commit = useCallback(\n (plan: FloorPlan, reason: RoomDrawerChangeReason, targetIds: string[] = []) => {\n if (plan === presentRef.current) return;\n const targets = targetIds.join(',');\n const now = Date.now();\n const last = lastCommitRef.current;\n // Typing a room name would otherwise flood the stack with one entry per keystroke.\n const mergeable =\n last !== null &&\n last.reason === reason &&\n last.targets === targets &&\n now - last.at < MERGE_WINDOW_MS &&\n pastRef.current.length > 0;\n\n if (!mergeable) push(presentRef.current);\n else futureRef.current = [];\n\n lastCommitRef.current = { reason, targets, at: now };\n setBoth(plan);\n forceCounter((n) => n + 1);\n },\n [push, setBoth],\n );\n\n const replace = useCallback(\n (plan: FloorPlan) => {\n setBoth(plan);\n },\n [setBoth],\n );\n\n const undo = useCallback(() => {\n const past = pastRef.current;\n if (past.length === 0) return null;\n const previous = past[past.length - 1];\n pastRef.current = past.slice(0, -1);\n futureRef.current = [presentRef.current, ...futureRef.current];\n lastCommitRef.current = null;\n setBoth(previous);\n forceCounter((n) => n + 1);\n return previous;\n }, [setBoth]);\n\n const redo = useCallback(() => {\n const future = futureRef.current;\n if (future.length === 0) return null;\n const next = future[0];\n futureRef.current = future.slice(1);\n pastRef.current = [...pastRef.current, presentRef.current].slice(-limit);\n lastCommitRef.current = null;\n setBoth(next);\n forceCounter((n) => n + 1);\n return next;\n }, [limit, setBoth]);\n\n const clearHistory = useCallback(() => {\n pastRef.current = [];\n futureRef.current = [];\n lastCommitRef.current = null;\n forceCounter((n) => n + 1);\n }, []);\n\n const isGestureActive = useCallback(() => gestureStartRef.current !== null, []);\n\n return {\n present,\n canUndo: pastRef.current.length > 0,\n canRedo: futureRef.current.length > 0,\n beginGesture,\n updateGesture,\n endGesture,\n cancelGesture,\n commit,\n replace,\n undo,\n redo,\n clearHistory,\n isGestureActive,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"./roomViewer.module.mjs";import{useEffect as t,useRef as n,useState as r}from"react";import i from"classnames";import{FontAwesomeIcon as a}from"@fortawesome/react-fontawesome";import{faChevronLeft as o,faChevronRight as s,faLayerGroup as c}from"@fortawesome/free-solid-svg-icons";import{jsx as l,jsxs as u}from"react/jsx-runtime";function d({data:d=[]}){let f=n(null),[,p]=r(null),[m,h]=r(0),[g,_]=r(!0);t(()=>{let e=new AbortController;p(null);let t=f.current;return m>d.length-1||!t?(_(!1),()=>e.abort()):(t.querySelectorAll(`[id^="room"]`).forEach(n=>{n.addEventListener(`click`,()=>v(n.id,t),{signal:e.signal})}),_(!1),()=>e.abort())},[d,m]);function v(t,n){let r=t.substring(4);p(i=>{if(r===i)return i;let[a]=n.querySelectorAll(`[id="use"]`);a?.setAttribute(`href`,`#${t}`);let[o]=n.querySelectorAll(`[id="${t}"]`);if(i){let[t]=n.querySelectorAll(`[id="room${i}"]`);if(t){t.classList.remove(e.roomViewerSelected,e.roomViewerTint);let[n]=t.querySelectorAll(`[id="background"]`);n&&n.classList.remove(e.roomViewerTint)}}if(o){o.classList.add(e.roomViewerSelected);let[t]=o.querySelectorAll(`[id="background"]`);(t??o).classList.add(e.roomViewerTint)}return r})}function y(e){h(t=>{let n=t+e;return n<0||n>d.length-1?t:n})}let b=d[m]?.data??null;return u(`div`,{className:e.roomViewer,ref:f,children:[l(`h3`,{className:e.roomViewerHeader,children:d[m]?.label??``}),l(`div`,{className:i(e.roomViewerContainer,g&&e.roomViewerContainerLoading),children:b},m),d.length>1&&u(`div`,{className:e.roomViewerActions,children:[l(a,{icon:o,onClick:()=>y(-1)}),l(a,{icon:c}),l(a,{icon:s,onClick:()=>y(1)})]})]})}export{d as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{renderIcon as t}from"../utils/renderIcon.mjs";import{floorBounds as n,getFloor as r}from"../floorPlan/floorPlan.plan.mjs";import{derivePlan as i}from"../floorPlan/floorPlan.rooms.mjs";import{clientToWorld as a}from"../floorPlan/floorPlan.snap.mjs";import o from"../planCanvas/planCanvas.mjs";import s from"./roomViewer.module.mjs";import{forwardRef as c,useCallback as l,useEffect as u,useId as ee,useImperativeHandle as te,useMemo as d,useRef as f,useState as p}from"react";import m from"classnames";import{faExpand as ne,faMagnifyingGlassMinus as re,faMagnifyingGlassPlus as ie}from"@fortawesome/free-solid-svg-icons";import{jsx as h,jsxs as g}from"react/jsx-runtime";var _=.002,v=4,ae=4;function oe(e){let t=e/1e6;return`${t<10?t.toFixed(1):Math.round(t)} m²`}var se=c(function(c,se){let{plan:y,activeFloorId:b,defaultActiveFloorId:ce,onFloorChange:le,selectedRoomId:x,defaultSelectedRoomId:ue=null,onSelect:de,hoveredRoomId:S,onHoverChange:C,view:w,defaultView:fe,onViewChange:T,interactive:E=!0,pannable:D=!0,fitOnMount:pe=!0,showFloorBar:me=!0,showViewControls:he=!0,showGrid:ge=!1,showRoomLabels:_e=!0,showOpeningSymbols:ve=!0,getRoomColor:ye,renderRoomLabel:be,getRoomLabel:xe,formatArea:O=oe,height:Se=360,emptyState:Ce,labels:k,icons:A,className:we,style:Te,classNames:j,styles:M,"aria-label":N,...Ee}=e(`RoomViewer`,c),P=f(null),F=f(null),De=ee().replace(/:/g,``),I=y?.floors??[],[Oe,ke]=p(ce),L=b??Oe??I[0]?.id,R=d(()=>y?r(y,L)??r(y):null,[y,L]),z=l(e=>{b===void 0&&ke(e),le?.(e)},[b,le]),B=d(()=>R?i(R).rooms:[],[R]),[Ae,je]=p(ue),V=x===void 0?Ae:x,[Me,Ne]=p(null),H=S===void 0?Me:S,U=l(e=>{x===void 0&&je(e);let t=e?B.find(t=>t.roomId===e)??null:null;de?.(e,t,R?.id??``)},[x,B,de,R?.id]),Pe=l(e=>{S===void 0&&Ne(e),C?.(e)},[S,C]),Fe=(()=>{let e=V?B.find(e=>e.roomId===V):void 0;if(!e)return k?.noRoomSelected??`No room selected`;let t=e.meta?.name||`Unnamed room`;return(k?.selectedRoom??`{name} selected, {area}`).replace(`{name}`,t).replace(`{area}`,O(e.area))})(),[Ie,Le]=p(fe??{x:0,y:0,zoom:.05}),W=w??Ie,G=f(W);G.current=W;let K=l(e=>{w===void 0&&Le(e),T?.(e)},[w,T]),q=f(!1),[J,Re]=p({width:800,height:360});u(()=>{let e=P.current;if(!e)return;let t=()=>{let t=e.getBoundingClientRect();t.width>0&&t.height>0&&Re({width:Math.round(t.width),height:Math.round(t.height)})},n=new ResizeObserver(t);return n.observe(e),t(),()=>n.disconnect()},[]);let Y=l((e={})=>{let t=e.padding??24,r=R?n(R):null;if(!r||r.width<=0||r.height<=0){K({x:-1e3,y:-1e3,zoom:.05});return}let i=Math.max(_,Math.min(v,Math.min((J.width-t*2)/r.width,(J.height-t*2)/r.height)));K({x:r.minX-(J.width/i-r.width)/2,y:r.minY-(J.height/i-r.height)/2,zoom:i})},[R,J.width,J.height,K]);u(()=>{!pe||q.current||!R||J.width<=0||Object.keys(R.nodes).length===0||Y()},[pe,R,J.width,J.height,Y]);let X=l((e,t)=>{q.current=!0;let n=G.current,r=Math.max(_,Math.min(v,n.zoom*e));if(r===n.zoom)return;let i=t?.x??J.width/2,a=t?.y??J.height/2;K({x:n.x+i/n.zoom-i/r,y:n.y+a/n.zoom-a/r,zoom:r})},[K,J.width,J.height]),Z=f(new Map),Q=f(null),$=f(null),ze=l(e=>{if(D){if(Z.current.set(e.pointerId,{x:e.clientX,y:e.clientY}),Z.current.size===2){let[e,t]=[...Z.current.values()];$.current={dist:Math.hypot(t.x-e.x,t.y-e.y),view:G.current,mid:{x:(e.x+t.x)/2,y:(e.y+t.y)/2}},Q.current=null;return}Q.current={startClient:{x:e.clientX,y:e.clientY},startView:G.current,moved:!1}}},[D]),Be=l(e=>{Z.current.has(e.pointerId)&&Z.current.set(e.pointerId,{x:e.clientX,y:e.clientY});let t=$.current;if(t&&Z.current.size>=2){let[e,n]=[...Z.current.values()],r=Math.hypot(n.x-e.x,n.y-e.y);if(t.dist<=0)return;let i=Math.max(_,Math.min(v,t.view.zoom*(r/t.dist))),o=P.current?.getBoundingClientRect()??{left:0,top:0},s={x:(e.x+n.x)/2,y:(e.y+n.y)/2};q.current=!0;let c=a(t.mid.x,t.mid.y,o,t.view);K({x:c.x-(s.x-o.left)/i,y:c.y-(s.y-o.top)/i,zoom:i});return}let n=Q.current;if(!n)return;let r=e.clientX-n.startClient.x,i=e.clientY-n.startClient.y;!n.moved&&Math.hypot(r,i)<=ae||(n.moved||e.currentTarget.setPointerCapture?.(e.pointerId),n.moved=!0,q.current=!0,K({x:n.startView.x-r/n.startView.zoom,y:n.startView.y-i/n.startView.zoom,zoom:n.startView.zoom}))},[K]),Ve=l(e=>{Z.current.delete(e.pointerId),Z.current.size<2&&($.current=null),Q.current=null},[]);u(()=>{let e=P.current;if(!e||!D)return;let t=t=>{t.preventDefault();let n=e.getBoundingClientRect();X(t.deltaY<0?1.1:1/1.1,{x:t.clientX-n.left,y:t.clientY-n.top})};return e.addEventListener(`wheel`,t,{passive:!1}),()=>e.removeEventListener(`wheel`,t)},[D,X]),te(se,()=>({fitToContent:Y,getView:()=>G.current,setView:K,zoomBy:e=>X(e),select:U,getFloorId:()=>R?.id??null,setFloorId:z,getSvgElement:()=>F.current}),[Y,K,X,U,R?.id,z]);let He=d(()=>V?[{type:`room`,id:V}]:[],[V]),Ue=d(()=>H?{type:`room`,id:H}:null,[H]),We=!R||Object.keys(R.walls).length===0;return g(`div`,{...Ee,className:m(s.roomViewer,we,j?.root),style:{...Te,...M?.root},"aria-label":N??`Floor plan`,children:[me&&I.length>1&&h(`div`,{className:m(s.roomViewerFloorBar,j?.floorBar),style:M?.floorBar,role:`tablist`,"aria-label":k?.floors??`Floors`,children:[...I].reverse().map(e=>h(`button`,{type:`button`,role:`tab`,className:m(s.roomViewerFloorTab,e.id===R?.id&&s.roomViewerFloorTabActive,j?.floorTab),style:M?.floorTab,"aria-selected":e.id===R?.id,onClick:()=>z(e.id),children:e.label},e.id))}),g(`div`,{ref:P,className:m(s.roomViewerCanvasWrapper,D&&s.roomViewerCanvasWrapperPannable,j?.canvasWrapper),style:{height:Se,...M?.canvasWrapper},onPointerDown:ze,onPointerMove:Be,onPointerUp:Ve,onPointerCancel:Ve,children:[We?h(`div`,{className:m(s.roomViewerEmpty,j?.empty),style:M?.empty,children:Ce??k?.empty??`Nothing to show`}):h(o,{ref:F,floor:R,rooms:B,view:W,size:J,selection:He,hovered:Ue,interactiveRooms:E,showGrid:ge,showRoomLabels:_e,showOpeningSymbols:ve,getRoomColor:ye,renderRoomLabel:be,getRoomLabel:xe,formatArea:O,onRoomActivate:E?e=>U(e):void 0,onBackgroundActivate:E?()=>U(null):void 0,onHoverChange:E?e=>Pe(e?.type===`room`?e.id:null):void 0,classNames:{canvas:j?.canvas,grid:j?.grid,rooms:j?.rooms,roomFill:j?.roomFill,roomLabel:j?.roomLabel,walls:j?.walls,wallBody:j?.wallBody,openings:j?.openings,opening:j?.opening},styles:{canvas:M?.canvas,grid:M?.grid,rooms:M?.rooms,roomFill:M?.roomFill,roomLabel:M?.roomLabel,walls:M?.walls,wallBody:M?.wallBody,openings:M?.openings,opening:M?.opening},"aria-label":N??`Floor plan`}),he&&!We&&g(`div`,{className:m(s.roomViewerViewControls,j?.viewControls),style:M?.viewControls,children:[h(`button`,{type:`button`,className:m(s.roomViewerViewButton,j?.viewButton),style:M?.viewButton,title:k?.zoomOut??`Zoom out`,"aria-label":k?.zoomOut??`Zoom out`,onClick:()=>X(1/1.2),children:t(A?.zoomOut??re)}),h(`button`,{type:`button`,className:m(s.roomViewerViewButton,j?.viewButton),style:M?.viewButton,title:k?.fit??`Fit to view`,"aria-label":k?.fit??`Fit to view`,onClick:()=>{q.current=!1,Y()},children:t(A?.fit??ne)}),h(`button`,{type:`button`,className:m(s.roomViewerViewButton,j?.viewButton),style:M?.viewButton,title:k?.zoomIn??`Zoom in`,"aria-label":k?.zoomIn??`Zoom in`,onClick:()=>X(1.2),children:t(A?.zoomIn??ie)})]})]}),h(`div`,{id:De,className:s.roomViewerLive,role:`status`,"aria-live":`polite`,children:Fe})]})});export{se as default};
2
2
  //# sourceMappingURL=roomViewer.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"roomViewer.mjs","names":[],"sources":["../../../../package/common/roomViewer/roomViewer.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport {\n faChevronLeft as leftIcon,\n faChevronRight as rightIcon,\n faLayerGroup as layerIcon,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport styles from './roomViewer.module.pcss';\nimport type { RoomViewerProps } from './roomViewer.types';\n\nfunction RoomViewer({ data = [] }: RoomViewerProps) {\n const roomViewerRef = useRef<HTMLDivElement>(null);\n\n const [, setSelectedRoomId] = useState<string | null>(null);\n const [selectedDataId, setSelectedDataId] = useState(0);\n const [isLoading, setIsLoading] = useState(true);\n\n useEffect(() => {\n const abortController = new AbortController();\n\n setSelectedRoomId(null);\n\n const container = roomViewerRef.current;\n\n if (selectedDataId > data.length - 1 || !container) {\n setIsLoading(false);\n return () => abortController.abort();\n }\n\n // useEffect fires after the DOM has been committed, so the SVG rendered\n // from data[selectedDataId].data is already in the container here.\n const rooms = container.querySelectorAll<Element>('[id^=\"room\"]');\n rooms.forEach((element) => {\n element.addEventListener(\n 'click',\n () => onRoomClicked(element.id, container),\n { signal: abortController.signal }\n );\n });\n setIsLoading(false);\n\n return () => abortController.abort();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [data, selectedDataId]);\n\n function onRoomClicked(roomId: string, container: Element) {\n const pureRoomId = roomId.substring(4);\n\n setSelectedRoomId((prevSelectedRoomId) => {\n if (pureRoomId === prevSelectedRoomId) return prevSelectedRoomId;\n\n const [use] = container.querySelectorAll<Element>('[id=\"use\"]');\n use?.setAttribute('href', `#${roomId}`);\n\n const [room] = container.querySelectorAll<Element>(`[id=\"${roomId}\"]`);\n\n if (prevSelectedRoomId) {\n const [prevRoom] = container.querySelectorAll<Element>(`[id=\"room${prevSelectedRoomId}\"]`);\n if (prevRoom) {\n prevRoom.classList.remove(styles.roomViewerSelected, styles.roomViewerTint);\n const [prevBackground] = prevRoom.querySelectorAll<Element>('[id=\"background\"]');\n if (prevBackground) prevBackground.classList.remove(styles.roomViewerTint);\n }\n }\n\n if (room) {\n room.classList.add(styles.roomViewerSelected);\n const [background] = room.querySelectorAll<Element>('[id=\"background\"]');\n (background ?? room).classList.add(styles.roomViewerTint);\n }\n\n return pureRoomId;\n });\n }\n\n function addToCurrentFloor(change: number) {\n setSelectedDataId((prev) => {\n const next = prev + change;\n if (next < 0 || next > data.length - 1) return prev;\n return next;\n });\n }\n\n const svgData = data[selectedDataId]?.data ?? null;\n\n return (\n <div className={styles.roomViewer} ref={roomViewerRef}>\n <h3 className={styles.roomViewerHeader}>{data[selectedDataId]?.label ?? ''}</h3>\n <div\n key={selectedDataId}\n className={cx(styles.roomViewerContainer, isLoading && styles.roomViewerContainerLoading)}\n >\n {svgData}\n </div>\n {data.length > 1 && (\n <div className={styles.roomViewerActions}>\n <FontAwesomeIcon icon={leftIcon} onClick={() => addToCurrentFloor(-1)} />\n <FontAwesomeIcon icon={layerIcon} />\n <FontAwesomeIcon icon={rightIcon} onClick={() => addToCurrentFloor(1)} />\n </div>\n )}\n </div>\n );\n}\n\nexport default RoomViewer;\n"],"mappings":"wVAYA,SAAS,EAAW,CAAE,OAAO,CAAC,GAAsB,CAClD,IAAM,EAAgB,EAAuB,IAAI,EAE3C,EAAG,GAAqB,EAAwB,IAAI,EACpD,CAAC,EAAgB,GAAqB,EAAS,CAAC,EAChD,CAAC,EAAW,GAAgB,EAAS,EAAI,EAE/C,MAAgB,CACd,IAAM,EAAkB,IAAI,gBAE5B,EAAkB,IAAI,EAEtB,IAAM,EAAY,EAAc,QAmBhC,OAjBI,EAAiB,EAAK,OAAS,GAAK,CAAC,GACvC,EAAa,EAAK,MACL,EAAgB,MAAM,IAMrC,EADwB,iBAA0B,cAClD,EAAM,QAAS,GAAY,CACzB,EAAQ,iBACN,YACM,EAAc,EAAQ,GAAI,CAAS,EACzC,CAAE,OAAQ,EAAgB,MAAO,CACnC,CACF,CAAC,EACD,EAAa,EAAK,MAEL,EAAgB,MAAM,EAErC,EAAG,CAAC,EAAM,CAAc,CAAC,EAEzB,SAAS,EAAc,EAAgB,EAAoB,CACzD,IAAM,EAAa,EAAO,UAAU,CAAC,EAErC,EAAmB,GAAuB,CACxC,GAAI,IAAe,EAAoB,OAAO,EAE9C,GAAM,CAAC,GAAO,EAAU,iBAA0B,YAAY,EAC9D,GAAK,aAAa,OAAQ,IAAI,GAAQ,EAEtC,GAAM,CAAC,GAAQ,EAAU,iBAA0B,QAAQ,EAAO,GAAG,EAErE,GAAI,EAAoB,CACtB,GAAM,CAAC,GAAY,EAAU,iBAA0B,YAAY,EAAmB,GAAG,EACzF,GAAI,EAAU,CACZ,EAAS,UAAU,OAAO,EAAO,mBAAoB,EAAO,cAAc,EAC1E,GAAM,CAAC,GAAkB,EAAS,iBAA0B,mBAAmB,EAC3E,GAAgB,EAAe,UAAU,OAAO,EAAO,cAAc,CAC3E,CACF,CAEA,GAAI,EAAM,CACR,EAAK,UAAU,IAAI,EAAO,kBAAkB,EAC5C,GAAM,CAAC,GAAc,EAAK,iBAA0B,mBAAmB,GACtE,GAAc,GAAM,UAAU,IAAI,EAAO,cAAc,CAC1D,CAEA,OAAO,CACT,CAAC,CACH,CAEA,SAAS,EAAkB,EAAgB,CACzC,EAAmB,GAAS,CAC1B,IAAM,EAAO,EAAO,EAEpB,OADI,EAAO,GAAK,EAAO,EAAK,OAAS,EAAU,EACxC,CACT,CAAC,CACH,CAEA,IAAM,EAAU,EAAK,IAAiB,MAAQ,KAE9C,OACE,EAAC,MAAD,CAAK,UAAW,EAAO,WAAY,IAAK,WAAxC,CACE,EAAC,KAAD,CAAI,UAAW,EAAO,0BAAmB,EAAK,IAAiB,OAAS,EAAO,CAAA,EAC/E,EAAC,MAAD,CAEE,UAAW,EAAG,EAAO,oBAAqB,GAAa,EAAO,0BAA0B,WAEvF,CACE,EAJE,CAIF,EACJ,EAAK,OAAS,GACb,EAAC,MAAD,CAAK,UAAW,EAAO,2BAAvB,CACE,EAAC,EAAD,CAAiB,KAAM,EAAU,YAAe,EAAkB,EAAE,CAAI,CAAA,EACxE,EAAC,EAAD,CAAiB,KAAM,CAAY,CAAA,EACnC,EAAC,EAAD,CAAiB,KAAM,EAAW,YAAe,EAAkB,CAAC,CAAI,CAAA,CACrE,GAEJ,GAET"}
1
+ {"version":3,"file":"roomViewer.mjs","names":[],"sources":["../../../../package/common/roomViewer/roomViewer.tsx"],"sourcesContent":["import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useId,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport type { PointerEvent as ReactPointerEvent } from 'react';\nimport cx from 'classnames';\nimport {\n faExpand,\n faMagnifyingGlassMinus,\n faMagnifyingGlassPlus,\n} from '@fortawesome/free-solid-svg-icons';\n\nimport { useComponentDefaults } from '../configProvider';\nimport {\n clientToWorld,\n derivePlan,\n floorBounds,\n getFloor,\n type PlanFloor,\n type PlanSelection,\n type PlanView,\n} from '../floorPlan';\nimport PlanCanvas from '../planCanvas';\nimport { renderIcon } from '../utils/renderIcon';\nimport type { RoomViewerHandle, RoomViewerProps } from './roomViewer.types';\nimport styles from './roomViewer.module.pcss';\n\nconst MIN_ZOOM = 0.002;\nconst MAX_ZOOM = 4;\n/** Past this many pixels a press is a pan rather than a click on a room. */\nconst PAN_THRESHOLD_PX = 4;\n\nfunction formatAreaDefault(areaMm2: number): string {\n const m2 = areaMm2 / 1e6;\n return `${m2 < 10 ? m2.toFixed(1) : Math.round(m2)} m²`;\n}\n\n/**\n * Read-only view of a floor plan.\n *\n * It renders the same `planCanvas` the drawer does, from the same `FloorPlan`, so the\n * two cannot drift apart. Selection and hover are React state rather than classes pushed\n * onto DOM nodes, which is what lets them be controlled from outside.\n */\nconst RoomViewer = forwardRef<RoomViewerHandle, RoomViewerProps>(function RoomViewer(props, ref) {\n const {\n plan,\n activeFloorId,\n defaultActiveFloorId,\n onFloorChange,\n selectedRoomId,\n defaultSelectedRoomId = null,\n onSelect,\n hoveredRoomId,\n onHoverChange,\n view,\n defaultView,\n onViewChange,\n interactive = true,\n pannable = true,\n fitOnMount = true,\n showFloorBar = true,\n showViewControls = true,\n showGrid = false,\n showRoomLabels = true,\n showOpeningSymbols = true,\n getRoomColor,\n renderRoomLabel,\n getRoomLabel,\n formatArea = formatAreaDefault,\n height = 360,\n emptyState,\n labels,\n icons,\n className,\n style,\n classNames,\n styles: slotStyles,\n 'aria-label': ariaLabel,\n ...rest\n } = useComponentDefaults('RoomViewer', props);\n\n const wrapperRef = useRef<HTMLDivElement>(null);\n const svgRef = useRef<SVGSVGElement>(null);\n const liveId = useId().replace(/:/g, '');\n\n const floors = plan?.floors ?? [];\n\n // ─── Floor ────────────────────────────────────────────────────────────────────\n\n const [floorIdState, setFloorIdState] = useState<string | undefined>(defaultActiveFloorId);\n const currentFloorId = (activeFloorId ?? floorIdState) ?? floors[0]?.id;\n const floor: PlanFloor | null = useMemo(\n () => (plan ? (getFloor(plan, currentFloorId) ?? getFloor(plan)) : null),\n [plan, currentFloorId],\n );\n\n const selectFloor = useCallback(\n (nextId: string) => {\n if (activeFloorId === undefined) setFloorIdState(nextId);\n onFloorChange?.(nextId);\n },\n [activeFloorId, onFloorChange],\n );\n\n const rooms = useMemo(() => (floor ? derivePlan(floor).rooms : []), [floor]);\n\n // ─── Selection and hover ──────────────────────────────────────────────────────\n\n const [selectedState, setSelectedState] = useState<string | null>(defaultSelectedRoomId);\n const selected = selectedRoomId !== undefined ? selectedRoomId : selectedState;\n\n const [hoveredState, setHoveredState] = useState<string | null>(null);\n const hovered = hoveredRoomId !== undefined ? hoveredRoomId : hoveredState;\n\n const selectRoom = useCallback(\n (roomId: string | null) => {\n if (selectedRoomId === undefined) setSelectedState(roomId);\n const room = roomId ? (rooms.find((r) => r.roomId === roomId) ?? null) : null;\n onSelect?.(roomId, room, floor?.id ?? '');\n },\n [selectedRoomId, rooms, onSelect, floor?.id],\n );\n\n const setHovered = useCallback(\n (roomId: string | null) => {\n if (hoveredRoomId === undefined) setHoveredState(roomId);\n onHoverChange?.(roomId);\n },\n [hoveredRoomId, onHoverChange],\n );\n\n // A selection made by clicking a shape is silent to a screen reader, so it is\n // announced separately rather than relying on focus landing somewhere useful.\n const announcement = (() => {\n const room = selected ? rooms.find((r) => r.roomId === selected) : undefined;\n if (!room) return labels?.noRoomSelected ?? 'No room selected';\n const name = room.meta?.name || 'Unnamed room';\n return (labels?.selectedRoom ?? '{name} selected, {area}')\n .replace('{name}', name)\n .replace('{area}', formatArea(room.area));\n })();\n\n // ─── View ─────────────────────────────────────────────────────────────────────\n\n const [viewState, setViewState] = useState<PlanView>(defaultView ?? { x: 0, y: 0, zoom: 0.05 });\n const currentView = view ?? viewState;\n const viewRef = useRef(currentView);\n viewRef.current = currentView;\n\n const applyView = useCallback(\n (next: PlanView) => {\n if (view === undefined) setViewState(next);\n onViewChange?.(next);\n },\n [view, onViewChange],\n );\n\n const userMovedRef = useRef(false);\n const [size, setSize] = useState({ width: 800, height: 360 });\n useEffect(() => {\n const element = wrapperRef.current;\n if (!element) return;\n const measure = () => {\n const rect = element.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n setSize({ width: Math.round(rect.width), height: Math.round(rect.height) });\n }\n };\n const observer = new ResizeObserver(measure);\n observer.observe(element);\n measure();\n return () => observer.disconnect();\n }, []);\n\n const fitToContent = useCallback(\n (options: { padding?: number } = {}) => {\n const padding = options.padding ?? 24;\n const bounds = floor ? floorBounds(floor) : null;\n if (!bounds || bounds.width <= 0 || bounds.height <= 0) {\n applyView({ x: -1000, y: -1000, zoom: 0.05 });\n return;\n }\n const zoom = Math.max(\n MIN_ZOOM,\n Math.min(\n MAX_ZOOM,\n Math.min(\n (size.width - padding * 2) / bounds.width,\n (size.height - padding * 2) / bounds.height,\n ),\n ),\n );\n applyView({\n x: bounds.minX - (size.width / zoom - bounds.width) / 2,\n y: bounds.minY - (size.height / zoom - bounds.height) / 2,\n zoom,\n });\n },\n [floor, size.width, size.height, applyView],\n );\n\n /**\n * Refit on anything that changes what \"fitted\" means — the floor, and the canvas size,\n * which is not known until the element has been measured. The moment the viewer pans or\n * zooms, the view is theirs and we stop touching it.\n */\n useEffect(() => {\n if (!fitOnMount || userMovedRef.current) return;\n if (!floor || size.width <= 0 || Object.keys(floor.nodes).length === 0) return;\n fitToContent();\n }, [fitOnMount, floor, size.width, size.height, fitToContent]);\n\n const zoomBy = useCallback(\n (factor: number, centre?: { x: number; y: number }) => {\n userMovedRef.current = true;\n const v = viewRef.current;\n const next = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, v.zoom * factor));\n if (next === v.zoom) return;\n const cx0 = centre?.x ?? size.width / 2;\n const cy0 = centre?.y ?? size.height / 2;\n // Keep the world point under the cursor where it is.\n applyView({\n x: v.x + cx0 / v.zoom - cx0 / next,\n y: v.y + cy0 / v.zoom - cy0 / next,\n zoom: next,\n });\n },\n [applyView, size.width, size.height],\n );\n\n // ─── Pan and pinch ────────────────────────────────────────────────────────────\n\n const pointersRef = useRef(new Map<number, { x: number; y: number }>());\n const panRef = useRef<{ startClient: { x: number; y: number }; startView: PlanView; moved: boolean } | null>(null);\n const pinchRef = useRef<{ dist: number; view: PlanView; mid: { x: number; y: number } } | null>(null);\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n if (!pannable) return;\n pointersRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY });\n // Deliberately NOT capturing the pointer yet. While a capture is active the click\n // is dispatched to the capturing element instead of the shape under the cursor, so\n // capturing here would mean a room could never be clicked. The capture is taken in\n // the move handler, once the press has actually turned into a pan.\n if (pointersRef.current.size === 2) {\n const [p1, p2] = [...pointersRef.current.values()];\n pinchRef.current = {\n dist: Math.hypot(p2.x - p1.x, p2.y - p1.y),\n view: viewRef.current,\n mid: { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 },\n };\n panRef.current = null;\n return;\n }\n panRef.current = {\n startClient: { x: event.clientX, y: event.clientY },\n startView: viewRef.current,\n moved: false,\n };\n },\n [pannable],\n );\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n if (pointersRef.current.has(event.pointerId)) {\n pointersRef.current.set(event.pointerId, { x: event.clientX, y: event.clientY });\n }\n\n const pinch = pinchRef.current;\n if (pinch && pointersRef.current.size >= 2) {\n const [p1, p2] = [...pointersRef.current.values()];\n const now = Math.hypot(p2.x - p1.x, p2.y - p1.y);\n if (pinch.dist <= 0) return;\n const zoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, pinch.view.zoom * (now / pinch.dist)));\n const rect = wrapperRef.current?.getBoundingClientRect() ?? { left: 0, top: 0 };\n const mid = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };\n userMovedRef.current = true;\n const worldMid = clientToWorld(pinch.mid.x, pinch.mid.y, rect, pinch.view);\n applyView({\n x: worldMid.x - (mid.x - rect.left) / zoom,\n y: worldMid.y - (mid.y - rect.top) / zoom,\n zoom,\n });\n return;\n }\n\n const pan = panRef.current;\n if (!pan) return;\n const dx = event.clientX - pan.startClient.x;\n const dy = event.clientY - pan.startClient.y;\n if (!pan.moved && Math.hypot(dx, dy) <= PAN_THRESHOLD_PX) return;\n if (!pan.moved) {\n (event.currentTarget as HTMLElement).setPointerCapture?.(event.pointerId);\n }\n pan.moved = true;\n userMovedRef.current = true;\n applyView({\n x: pan.startView.x - dx / pan.startView.zoom,\n y: pan.startView.y - dy / pan.startView.zoom,\n zoom: pan.startView.zoom,\n });\n },\n [applyView],\n );\n\n const handlePointerUp = useCallback((event: ReactPointerEvent<HTMLDivElement>) => {\n pointersRef.current.delete(event.pointerId);\n if (pointersRef.current.size < 2) pinchRef.current = null;\n panRef.current = null;\n }, []);\n\n // React's onWheel is passive, so it cannot preventDefault and the page scrolls instead.\n useEffect(() => {\n const element = wrapperRef.current;\n if (!element || !pannable) return;\n const onWheel = (event: WheelEvent) => {\n event.preventDefault();\n const rect = element.getBoundingClientRect();\n zoomBy(event.deltaY < 0 ? 1.1 : 1 / 1.1, {\n x: event.clientX - rect.left,\n y: event.clientY - rect.top,\n });\n };\n element.addEventListener('wheel', onWheel, { passive: false });\n return () => element.removeEventListener('wheel', onWheel);\n }, [pannable, zoomBy]);\n\n // ─── Handle ───────────────────────────────────────────────────────────────────\n\n useImperativeHandle(\n ref,\n () => ({\n fitToContent,\n getView: () => viewRef.current,\n setView: applyView,\n zoomBy: (factor: number) => zoomBy(factor),\n select: selectRoom,\n getFloorId: () => floor?.id ?? null,\n setFloorId: selectFloor,\n getSvgElement: () => svgRef.current,\n }),\n [fitToContent, applyView, zoomBy, selectRoom, floor?.id, selectFloor],\n );\n\n // ─── Render ───────────────────────────────────────────────────────────────────\n\n const selection: readonly PlanSelection[] = useMemo(\n () => (selected ? [{ type: 'room', id: selected } as PlanSelection] : []),\n [selected],\n );\n const hoveredSelection: PlanSelection | null = useMemo(\n () => (hovered ? { type: 'room', id: hovered } : null),\n [hovered],\n );\n\n const isEmpty = !floor || Object.keys(floor.walls).length === 0;\n\n return (\n <div\n {...rest}\n className={cx(styles.roomViewer, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n aria-label={ariaLabel ?? 'Floor plan'}\n >\n {showFloorBar && floors.length > 1 && (\n <div\n className={cx(styles.roomViewerFloorBar, classNames?.floorBar)}\n style={slotStyles?.floorBar}\n role=\"tablist\"\n aria-label={labels?.floors ?? 'Floors'}\n >\n {/* Top storey first, the way a building reads in section. */}\n {[...floors].reverse().map((f) => (\n <button\n key={f.id}\n type=\"button\"\n role=\"tab\"\n className={cx(\n styles.roomViewerFloorTab,\n f.id === floor?.id && styles.roomViewerFloorTabActive,\n classNames?.floorTab,\n )}\n style={slotStyles?.floorTab}\n aria-selected={f.id === floor?.id}\n onClick={() => selectFloor(f.id)}\n >\n {f.label}\n </button>\n ))}\n </div>\n )}\n\n <div\n ref={wrapperRef}\n className={cx(\n styles.roomViewerCanvasWrapper,\n pannable && styles.roomViewerCanvasWrapperPannable,\n classNames?.canvasWrapper,\n )}\n style={{ height, ...slotStyles?.canvasWrapper }}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n >\n {isEmpty ? (\n <div className={cx(styles.roomViewerEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {emptyState ?? labels?.empty ?? 'Nothing to show'}\n </div>\n ) : (\n <PlanCanvas\n ref={svgRef}\n floor={floor}\n rooms={rooms}\n view={currentView}\n size={size}\n selection={selection}\n hovered={hoveredSelection}\n interactiveRooms={interactive}\n showGrid={showGrid}\n showRoomLabels={showRoomLabels}\n showOpeningSymbols={showOpeningSymbols}\n getRoomColor={getRoomColor}\n renderRoomLabel={renderRoomLabel}\n getRoomLabel={getRoomLabel}\n formatArea={formatArea}\n onRoomActivate={interactive ? (roomId) => selectRoom(roomId) : undefined}\n onBackgroundActivate={interactive ? () => selectRoom(null) : undefined}\n onHoverChange={\n interactive ? (target) => setHovered(target?.type === 'room' ? target.id : null) : undefined\n }\n classNames={{\n canvas: classNames?.canvas,\n grid: classNames?.grid,\n rooms: classNames?.rooms,\n roomFill: classNames?.roomFill,\n roomLabel: classNames?.roomLabel,\n walls: classNames?.walls,\n wallBody: classNames?.wallBody,\n openings: classNames?.openings,\n opening: classNames?.opening,\n }}\n styles={{\n canvas: slotStyles?.canvas,\n grid: slotStyles?.grid,\n rooms: slotStyles?.rooms,\n roomFill: slotStyles?.roomFill,\n roomLabel: slotStyles?.roomLabel,\n walls: slotStyles?.walls,\n wallBody: slotStyles?.wallBody,\n openings: slotStyles?.openings,\n opening: slotStyles?.opening,\n }}\n aria-label={ariaLabel ?? 'Floor plan'}\n />\n )}\n\n {showViewControls && !isEmpty && (\n <div\n className={cx(styles.roomViewerViewControls, classNames?.viewControls)}\n style={slotStyles?.viewControls}\n >\n <button\n type=\"button\"\n className={cx(styles.roomViewerViewButton, classNames?.viewButton)}\n style={slotStyles?.viewButton}\n title={labels?.zoomOut ?? 'Zoom out'}\n aria-label={labels?.zoomOut ?? 'Zoom out'}\n onClick={() => zoomBy(1 / 1.2)}\n >\n {renderIcon(icons?.zoomOut ?? faMagnifyingGlassMinus)}\n </button>\n <button\n type=\"button\"\n className={cx(styles.roomViewerViewButton, classNames?.viewButton)}\n style={slotStyles?.viewButton}\n title={labels?.fit ?? 'Fit to view'}\n aria-label={labels?.fit ?? 'Fit to view'}\n onClick={() => {\n userMovedRef.current = false;\n fitToContent();\n }}\n >\n {renderIcon(icons?.fit ?? faExpand)}\n </button>\n <button\n type=\"button\"\n className={cx(styles.roomViewerViewButton, classNames?.viewButton)}\n style={slotStyles?.viewButton}\n title={labels?.zoomIn ?? 'Zoom in'}\n aria-label={labels?.zoomIn ?? 'Zoom in'}\n onClick={() => zoomBy(1.2)}\n >\n {renderIcon(icons?.zoomIn ?? faMagnifyingGlassPlus)}\n </button>\n </div>\n )}\n </div>\n\n <div id={liveId} className={styles.roomViewerLive} role=\"status\" aria-live=\"polite\">\n {announcement}\n </div>\n </div>\n );\n});\n\nexport default RoomViewer;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e={"roomViewer-containerLoading":`roomViewer-containerLoading_BL3M-`,roomViewerContainerLoading:`roomViewer-containerLoading_BL3M-`,"roomViewer-container":`roomViewer-container_YlmB8`,roomViewerContainer:`roomViewer-container_YlmB8`,"roomViewer-active":`roomViewer-active_gG6wf`,roomViewerActive:`roomViewer-active_gG6wf`,"roomViewer-selected":`roomViewer-selected_CpdMj`,roomViewerSelected:`roomViewer-selected_CpdMj`,"roomViewer-tint":`roomViewer-tint_O9JrM`,roomViewerTint:`roomViewer-tint_O9JrM`,"roomViewer-actions":`roomViewer-actions_4cA74`,roomViewerActions:`roomViewer-actions_4cA74`,"roomViewer-header":`roomViewer-header_XEHCO`,roomViewerHeader:`roomViewer-header_XEHCO`};export{e as default};
1
+ var e={roomViewer:`roomViewer_JtBDo`,"roomViewer-floorBar":`roomViewer-floorBar_Svfsf`,roomViewerFloorBar:`roomViewer-floorBar_Svfsf`,"roomViewer-floorTab":`roomViewer-floorTab_eH3Nl`,roomViewerFloorTab:`roomViewer-floorTab_eH3Nl`,"roomViewer-floorTab-active":`roomViewer-floorTab-active_3ZQv9`,roomViewerFloorTabActive:`roomViewer-floorTab-active_3ZQv9`,"roomViewer-canvasWrapper":`roomViewer-canvasWrapper_UopaD`,roomViewerCanvasWrapper:`roomViewer-canvasWrapper_UopaD`,"roomViewer-canvasWrapper-pannable":`roomViewer-canvasWrapper-pannable_-Knr7`,roomViewerCanvasWrapperPannable:`roomViewer-canvasWrapper-pannable_-Knr7`,"roomViewer-viewControls":`roomViewer-viewControls_XNVTI`,roomViewerViewControls:`roomViewer-viewControls_XNVTI`,"roomViewer-viewButton":`roomViewer-viewButton_Q-o9G`,roomViewerViewButton:`roomViewer-viewButton_Q-o9G`,"roomViewer-empty":`roomViewer-empty_LL-4L`,roomViewerEmpty:`roomViewer-empty_LL-4L`,"roomViewer-live":`roomViewer-live_WSwUx`,roomViewerLive:`roomViewer-live_WSwUx`};export{e as default};
2
2
  //# sourceMappingURL=roomViewer.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"roomViewer.module.mjs","names":[],"sources":["../../../../package/common/roomViewer/roomViewer.module.pcss"],"sourcesContent":[".roomViewer{\n &-container{\n &Loading {\n opacity: 0.4;\n pointer-events: none;\n }\n\n svg{\n stroke-width: 1px;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-opacity: 1;\n path {\n stroke: var(--primary-color);\n fill: transparent;\n }\n path[id=\"background\"] {\n stroke: none;\n fill: transparent;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n *[id^=\"room\"] {\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n text{\n fill: var(--text-color);\n stroke: none;\n font-size: 5px;\n }\n }\n }\n\n &-active{\n stroke: #18f810 !important;\n fill: #20f81013 !important;\n path {\n stroke: #18f810 !important;\n fill: none !important;\n }\n path[id=\"background\"] {\n stroke: none !important;\n fill: #20f81013 !important;\n }\n }\n\n &-selected {\n stroke: #18f810 !important;\n path {\n stroke: #18f810 !important;\n fill: none !important;\n }\n path[id=\"background\"] {\n stroke: none !important;\n fill: #20f81013 !important;\n }\n\n text{\n stroke: none;\n fill: var(--text-color);\n }\n }\n\n &-tint {\n fill: #20f81013 !important;\n\n path{\n fill: #20f81013 !important;\n }\n\n text{\n stroke: none;\n fill: none;\n }\n }\n\n &-actions{\n display: flex;\n width: 100%;\n justify-content: center;\n gap: 8px;\n font-size: 16px;\n\n svg{\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n &-header{\n margin-bottom: 4px;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"roomViewer.module.mjs","names":[],"sources":["../../../../package/common/roomViewer/roomViewer.module.pcss"],"sourcesContent":[".roomViewer {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-s, 8px);\n\n /* Storeys, top first, the way a building reads in section. */\n &-floorBar {\n display: flex;\n align-items: center;\n gap: 2px;\n flex-wrap: wrap;\n padding: var(--spacing-xs, 4px);\n background: var(--background-accent);\n border: 1px solid var(--border-color);\n border-radius: var(--default-border-radius);\n }\n\n &-floorTab {\n height: 28px;\n padding: 0 10px;\n border: 1px solid transparent;\n border-radius: var(--default-border-radius);\n background: transparent;\n color: var(--text-dark);\n font-size: 12px;\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &:hover {\n background: var(--background-accent-light);\n }\n\n &:focus-visible {\n outline: none;\n border-color: var(--focus-border-color, var(--primary-color));\n }\n\n &-active {\n background: var(--primary-color);\n border-color: var(--primary-color);\n color: var(--text-on-primary);\n font-weight: 600;\n\n &:hover {\n background: var(--primary-color);\n }\n }\n }\n\n &-canvasWrapper {\n position: relative;\n overflow: hidden;\n border: 1px solid var(--border-color);\n border-radius: var(--default-border-radius);\n background: var(--background);\n\n &-pannable {\n /* Without this the browser claims the gesture and pointermove stops firing. */\n touch-action: none;\n cursor: grab;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n &-viewControls {\n position: absolute;\n right: var(--spacing-s, 8px);\n bottom: var(--spacing-s, 8px);\n display: flex;\n gap: 2px;\n padding: 2px;\n background: var(--background-accent);\n border: 1px solid var(--border-color);\n border-radius: var(--default-border-radius);\n }\n\n &-viewButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid transparent;\n border-radius: var(--default-border-radius);\n background: transparent;\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &:hover {\n background: var(--background-accent-light);\n }\n\n &:focus-visible {\n outline: none;\n border-color: var(--focus-border-color, var(--primary-color));\n }\n }\n\n &-empty {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-dark);\n font-size: 13px;\n }\n\n /* Announces the selection to a screen reader. A room selected by clicking its shape is\n otherwise silent, and there is nowhere useful for focus to land. */\n &-live {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n }\n}\n"],"mappings":""}
@@ -1 +1 @@
1
- import{AccordionStyleType as e}from"./common/accordion/accordion.types.mjs";import t from"./common/configProvider/configProvider.mjs";import{useComponentDefaults as n}from"./common/configProvider/useComponentDefaults.mjs";import{usePresentationDefault as r}from"./common/configProvider/usePresentationDefault.mjs";import i from"./common/accordion/accordion.mjs";import a from"./common/loading/spinnerLoading/index.mjs";import{ButtonSize as o,ButtonStyleType as s,ButtonType as c}from"./common/button/button.types.mjs";import l from"./common/ripple/ripple.mjs";import u from"./common/button/button.mjs";import d from"./common/actionButtons/actionButtons.mjs";import f from"./common/interactableDiv/index.mjs";import p from"./common/actionIcon/actionIcon.mjs";import{AlertStyleType as m}from"./common/alert/alert.types.mjs";import h from"./common/alert/alert.mjs";import g from"./common/animatedLogo/animatedLogo.mjs";import{AnimatedTextUnit as _,AnimatedTextVariant as v}from"./common/animatedText/animatedText.types.mjs";import y from"./common/animatedText/animatedText.mjs";import{BadgePosition as b,BadgeStyleType as x}from"./common/badge/badge.types.mjs";import S from"./common/badge/badge.mjs";import C from"./common/avatar/avatar.mjs";import w from"./common/avatar/avatarGroup.mjs";import T from"./common/bodyEnd/bodyEnd.mjs";import{Align as E,Presentation as D}from"./common/floatingMenu/floatingMenu.types.mjs";import O from"./common/floatingMenu/floatingMenu.mjs";import k from"./common/breadcrumb/breadcrumb.mjs";import{ButtonGroupOrientation as A}from"./common/buttonGroup/buttonGroup.types.mjs";import j from"./common/buttonGroup/buttonGroup.mjs";import{CardStyleType as M}from"./common/card/card.types.mjs";import N from"./common/card/Card.mjs";import P from"./common/card/CardHeader.mjs";import F from"./common/card/CardMedia.mjs";import I from"./common/card/CardContent.mjs";import L from"./common/card/CardActions.mjs";import R from"./common/carousel/carousel.mjs";import z from"./common/checkbox/checkbox.mjs";import{ChipStyleType as B}from"./common/chip/chip.types.mjs";import V from"./common/chip/chip.mjs";import H from"./common/chip/chipContainer.mjs";import U from"./common/tooltip/tooltip.mjs";import{InputIconPosition as W,InputType as G}from"./common/input/input.types.mjs";import K from"./common/input/input.mjs";import q from"./common/colorPicker/colorPicker.mjs";import J from"./common/modal/modal.mjs";import Y from"./common/confirmModal/confirmModal.mjs";import{getLocale as X,mapLocale as Z,setLocale as Q}from"./services/localization.mjs";import $ from"./common/infiniteBlock/infiniteBlock.mjs";import ee from"./common/dropdown/dropdown.mjs";import te from"./common/datePicker/datePicker.mjs";import{DividerOrientation as ne,DividerTextPosition as re}from"./common/divider/divider.types.mjs";import ie from"./common/divider/divider.mjs";import ae from"./common/drawer/drawer.mjs";import{DropZoneReturnType as oe,DropZoneStatus as se}from"./common/dropZone/dropZone.types.mjs";import ce from"./common/dropZone/dropZone.mjs";import le from"./common/emptyState/emptyState.mjs";import{showToast as ue}from"./common/toast/toastService.mjs";import de from"./common/toast/toastProvider.mjs";import fe from"./common/errorBoundary/errorBoundary.mjs";import pe from"./common/fab/fab.mjs";import me from"./common/flip/flip.mjs";import he from"./common/iconPicker/iconPicker.mjs";import ge from"./common/idleManager/idleManager.mjs";import _e from"./common/inputDropdown/inputDropdown.mjs";import ve from"./common/kanbanBoard/KanbanColumn.mjs";import ye from"./common/kanbanBoard/KanbanBoard.mjs";import be from"./common/searchInput/searchInput.mjs";import xe from"./common/klipyPicker/klipyPicker.mjs";import Se from"./common/loading/iconLoading/index.mjs";import Ce from"./common/numberInput/index.mjs";import we from"./common/optionPicker/optionPicker.mjs";import{OtpInputCharset as Te}from"./common/otpInput/otpInput.types.mjs";import Ee from"./common/otpInput/otpInput.mjs";import De from"./common/overscroll/overscroll.mjs";import{PopoverAlign as Oe,PopoverPlacement as ke,PopoverTrigger as Ae}from"./common/popover/popover.types.mjs";import je from"./common/popover/popover.mjs";import Me from"./common/progressBar/progressBar.mjs";import{RadioGroupOrientation as Ne}from"./common/radioGroup/radioGroup.types.mjs";import Pe from"./common/radioGroup/radioGroup.mjs";import Fe from"./common/rating/rating.mjs";import Ie from"./common/revealLens/revealLens.mjs";import Le from"./common/roomDrawer/roomDrawer.mjs";import Re from"./common/roomViewer/roomViewer.mjs";import ze from"./common/scrollbarProvider/index.mjs";import{SectionHeaderSize as Be}from"./common/sectionHeader/sectionHeader.types.mjs";import Ve from"./common/sectionHeader/sectionHeader.mjs";import{SkeletonAnimation as He,SkeletonVariant as Ue}from"./common/skeleton/skeleton.types.mjs";import We from"./common/skeleton/skeleton.mjs";import Ge from"./common/slider/slider.mjs";import Ke from"./common/splitButton/splitButton.mjs";import{StepperAlignment as qe,StepperCollapse as Je,StepperLabelPlacement as Ye,StepperStyleType as Xe}from"./common/stepper/stepper.types.mjs";import Ze from"./common/stepper/stepper.mjs";import Qe from"./common/sticky/sticky.mjs";import $e from"./common/switch/switch.mjs";import et from"./common/tabHeader/tabHeader.mjs";import tt from"./common/textarea/textarea.mjs";import{defaultTheme as nt}from"./common/themeProvider/defaultTheme.mjs";import rt from"./common/themeProvider/themeProvider.mjs";import{useTheme as it}from"./common/themeProvider/useTheme.mjs";import at,{TiltGroupContext as ot,useTiltGroup as st}from"./common/tiltGroup/tiltGroup.mjs";import{defaultTiltEasing as ct}from"./common/tilt/tiltMath.mjs";import lt from"./common/tilt/tilt.mjs";import ut from"./common/timeInput/timeInput.mjs";import{TimelineAlignment as dt,TimelineItemStatus as ft}from"./common/timeline/timeline.types.mjs";import pt from"./common/timeline/timeline.mjs";import mt from"./common/timer/timer.mjs";import ht from"./common/virtualList/virtualList.mjs";import gt from"./common/wizard/wizard.mjs";import _t from"./services/formValidation/FormValidatorGroupWithForm.mjs";import vt from"./services/formValidation/validatableComponent.mjs";import{useFormValidatorGroup as yt}from"./services/formValidation/useFormValidatorGroup.mjs";import{FormValidator as bt,Validators as xt,useFormValidator as St}from"./services/formValidation/index.mjs";import{hasEightPasswordChars as Ct,hasOnePasswordDigit as wt,hasOnePasswordLetter as Tt,isBic as Et,isDate as Dt,isEmail as Ot,isISODate as kt,isNumber as At,isPassword as jt,isURL as Mt}from"@ahrowe/form-validation";export{i as Accordion,e as AccordionStyleType,d as ActionButtons,p as ActionIcon,h as Alert,m as AlertStyleType,E as Align,g as AnimatedLogo,y as AnimatedText,_ as AnimatedTextUnit,v as AnimatedTextVariant,C as Avatar,w as AvatarGroup,S as Badge,b as BadgePosition,x as BadgeStyleType,T as BodyEnd,k as Breadcrumb,u as Button,j as ButtonGroup,A as ButtonGroupOrientation,o as ButtonSize,s as ButtonStyleType,c as ButtonType,N as Card,L as CardActions,I as CardContent,P as CardHeader,F as CardMedia,M as CardStyleType,R as Carousel,z as Checkbox,V as Chip,H as ChipContainer,B as ChipStyleType,q as ColorPicker,t as ConfigProvider,Y as ConfirmModal,te as DatePicker,ie as Divider,ne as DividerOrientation,re as DividerTextPosition,ae as Drawer,ce as DropZone,oe as DropZoneReturnType,se as DropZoneStatus,ee as Dropdown,le as EmptyState,fe as ErrorBoundary,pe as Fab,me as Flip,O as FloatingMenu,bt as FormValidator,_t as FormValidatorGroup,Se as IconLoading,he as IconPicker,ge as IdleManager,$ as InfiniteBlock,K as Input,_e as InputDropdown,W as InputIconPosition,G as InputType,f as InteractableDiv,ye as KanbanBoard,ve as KanbanColumn,xe as KlipyPicker,J as Modal,Ce as NumberInput,we as OptionPicker,Ee as OtpInput,Te as OtpInputCharset,De as Overscroll,je as Popover,Oe as PopoverAlign,ke as PopoverPlacement,Ae as PopoverTrigger,D as Presentation,Me as ProgressBar,Pe as RadioGroup,Ne as RadioGroupOrientation,Fe as Rating,Ie as RevealLens,l as Ripple,Le as RoomDrawer,Re as RoomViewer,ze as ScrollbarProvider,be as SearchInput,Ve as SectionHeader,Be as SectionHeaderSize,We as Skeleton,He as SkeletonAnimation,Ue as SkeletonVariant,Ge as Slider,a as SpinnerLoading,Ke as SplitButton,Ze as Stepper,qe as StepperAlignment,Je as StepperCollapse,Ye as StepperLabelPlacement,Xe as StepperStyleType,Qe as Sticky,$e as Switch,et as TabHeader,tt as Textarea,rt as ThemeProvider,lt as Tilt,at as TiltGroup,ot as TiltGroupContext,ut as TimeInput,pt as Timeline,dt as TimelineAlignment,ft as TimelineItemStatus,mt as Timer,de as ToastProvider,U as Tooltip,vt as ValidatableComponent,xt as Validators,ht as VirtualList,gt as Wizard,nt as defaultTheme,ct as defaultTiltEasing,X as getLocale,Ct as hasEightPasswordChars,wt as hasOnePasswordDigit,Tt as hasOnePasswordLetter,Et as isBic,Dt as isDate,Ot as isEmail,kt as isISODate,At as isNumber,jt as isPassword,Mt as isURL,Z as mapLocale,Q as setLocale,ue as showToast,n as useComponentDefaults,St as useFormValidator,yt as useFormValidatorGroup,r as usePresentationDefault,it as useTheme,st as useTiltGroup};
1
+ import{AccordionStyleType as e}from"./common/accordion/accordion.types.mjs";import t from"./common/configProvider/configProvider.mjs";import{useComponentDefaults as n}from"./common/configProvider/useComponentDefaults.mjs";import{usePresentationDefault as r}from"./common/configProvider/usePresentationDefault.mjs";import i from"./common/accordion/accordion.mjs";import a from"./common/loading/spinnerLoading/index.mjs";import{ButtonSize as o,ButtonStyleType as s,ButtonType as c}from"./common/button/button.types.mjs";import l from"./common/ripple/ripple.mjs";import u from"./common/button/button.mjs";import d from"./common/actionButtons/actionButtons.mjs";import f from"./common/interactableDiv/index.mjs";import p from"./common/actionIcon/actionIcon.mjs";import{AlertStyleType as m}from"./common/alert/alert.types.mjs";import h from"./common/alert/alert.mjs";import g from"./common/animatedLogo/animatedLogo.mjs";import{AnimatedTextUnit as _,AnimatedTextVariant as v}from"./common/animatedText/animatedText.types.mjs";import y from"./common/animatedText/animatedText.mjs";import{BadgePosition as b,BadgeStyleType as x}from"./common/badge/badge.types.mjs";import S from"./common/badge/badge.mjs";import C from"./common/avatar/avatar.mjs";import w from"./common/avatar/avatarGroup.mjs";import T from"./common/bodyEnd/bodyEnd.mjs";import{Align as E,Presentation as D}from"./common/floatingMenu/floatingMenu.types.mjs";import O from"./common/floatingMenu/floatingMenu.mjs";import k from"./common/breadcrumb/breadcrumb.mjs";import{ButtonGroupOrientation as A}from"./common/buttonGroup/buttonGroup.types.mjs";import j from"./common/buttonGroup/buttonGroup.mjs";import{CardStyleType as M}from"./common/card/card.types.mjs";import N from"./common/card/Card.mjs";import P from"./common/card/CardHeader.mjs";import F from"./common/card/CardMedia.mjs";import I from"./common/card/CardContent.mjs";import L from"./common/card/CardActions.mjs";import R from"./common/carousel/carousel.mjs";import z from"./common/checkbox/checkbox.mjs";import{ChipStyleType as B}from"./common/chip/chip.types.mjs";import V from"./common/chip/chip.mjs";import H from"./common/chip/chipContainer.mjs";import U from"./common/tooltip/tooltip.mjs";import{InputIconPosition as W,InputType as G}from"./common/input/input.types.mjs";import K from"./common/input/input.mjs";import q from"./common/colorPicker/colorPicker.mjs";import J from"./common/modal/modal.mjs";import Y from"./common/confirmModal/confirmModal.mjs";import{getLocale as X,mapLocale as Z,setLocale as Q}from"./services/localization.mjs";import $ from"./common/infiniteBlock/infiniteBlock.mjs";import ee from"./common/dropdown/dropdown.mjs";import te from"./common/datePicker/datePicker.mjs";import{DividerOrientation as ne,DividerTextPosition as re}from"./common/divider/divider.types.mjs";import ie from"./common/divider/divider.mjs";import ae from"./common/drawer/drawer.mjs";import{DropZoneReturnType as oe,DropZoneStatus as se}from"./common/dropZone/dropZone.types.mjs";import ce from"./common/dropZone/dropZone.mjs";import le from"./common/emptyState/emptyState.mjs";import{showToast as ue}from"./common/toast/toastService.mjs";import de from"./common/toast/toastProvider.mjs";import fe from"./common/errorBoundary/errorBoundary.mjs";import pe from"./common/fab/fab.mjs";import me from"./common/flip/flip.mjs";import{DoorSwing as he,OpeningKind as ge,PlanIssueKind as _e,PlanUnitSystem as ve,WallType as ye}from"./common/floorPlan/floorPlan.types.mjs";import{MIN_OPENING_WIDTH as be,MIN_WALL_LENGTH as xe}from"./common/floorPlan/floorPlan.geometry.mjs";import{DEFAULT_WALL_ATTRS as Se,addOpening as Ce,addRect as we,addWall as Te,cleanupPlan as Ee,dissolveNode as De,mergeNodes as Oe,moveNode as ke,removeOpening as Ae,removeWall as je,scalePlan as Me,splitWall as Ne,transformPlan as Pe,updateOpening as Fe,validatePlan as Ie,wallLength as Le}from"./common/floorPlan/floorPlan.graph.mjs";import{MIN_FLOOR_HEIGHT as Re,addFloor as ze,duplicateFloor as Be,emptyFloor as Ve,emptyFloorPlan as He,floorBelow as Ue,floorBounds as We,floorIndex as Ge,getFloor as Ke,moveFloor as qe,removeFloor as Je,renameFloor as Ye,setFloor as Xe,setFloorHeight as Ze,updateFloor as Qe}from"./common/floorPlan/floorPlan.plan.mjs";import{deriveFaces as $e,nodeDegrees as et}from"./common/floorPlan/floorPlan.faces.mjs";import{commitDerivation as tt,derivePlan as nt,pruneUnmatchedRooms as rt,roomAtPoint as it}from"./common/floorPlan/floorPlan.rooms.mjs";import{buildWallPaths as at,openingGeometry as ot,wallCentrelineSpans as st}from"./common/floorPlan/floorPlan.path.mjs";import{HIT_PX as ct,HIT_PX_COARSE as lt,hitTest as ut,selectionsEqual as dt,worldTolerances as ft}from"./common/floorPlan/floorPlan.hit.mjs";import{DEFAULT_SNAP_OPTIONS as pt,SnapKind as mt,clientToWorld as ht,resolveSnap as gt,screenScale as _t}from"./common/floorPlan/floorPlan.snap.mjs";import{PLAN_FORMAT_VERSION as vt,planFromJson as yt,planToJson as bt}from"./common/floorPlan/floorPlan.json.mjs";import{planFromLegacySvg as xt}from"./common/floorPlan/legacySvg.mjs";import St from"./common/iconPicker/iconPicker.mjs";import Ct from"./common/idleManager/idleManager.mjs";import wt from"./common/inputDropdown/inputDropdown.mjs";import Tt from"./common/kanbanBoard/KanbanColumn.mjs";import Et from"./common/kanbanBoard/KanbanBoard.mjs";import Dt from"./common/searchInput/searchInput.mjs";import Ot from"./common/klipyPicker/klipyPicker.mjs";import kt from"./common/loading/iconLoading/index.mjs";import At from"./common/numberInput/index.mjs";import jt from"./common/optionPicker/optionPicker.mjs";import{OtpInputCharset as Mt}from"./common/otpInput/otpInput.types.mjs";import Nt from"./common/otpInput/otpInput.mjs";import Pt from"./common/overscroll/overscroll.mjs";import{PopoverAlign as Ft,PopoverPlacement as It,PopoverTrigger as Lt}from"./common/popover/popover.types.mjs";import Rt from"./common/popover/popover.mjs";import zt from"./common/progressBar/progressBar.mjs";import{RadioGroupOrientation as Bt}from"./common/radioGroup/radioGroup.types.mjs";import Vt from"./common/radioGroup/radioGroup.mjs";import Ht from"./common/rating/rating.mjs";import Ut from"./common/revealLens/revealLens.mjs";import Wt from"./common/roomDrawer/roomDrawer.mjs";import Gt from"./common/roomViewer/roomViewer.mjs";import Kt from"./common/scrollbarProvider/index.mjs";import{SectionHeaderSize as qt}from"./common/sectionHeader/sectionHeader.types.mjs";import Jt from"./common/sectionHeader/sectionHeader.mjs";import{SkeletonAnimation as Yt,SkeletonVariant as Xt}from"./common/skeleton/skeleton.types.mjs";import Zt from"./common/skeleton/skeleton.mjs";import Qt from"./common/slider/slider.mjs";import $t from"./common/splitButton/splitButton.mjs";import{StepperAlignment as en,StepperCollapse as tn,StepperLabelPlacement as nn,StepperStyleType as rn}from"./common/stepper/stepper.types.mjs";import an from"./common/stepper/stepper.mjs";import on from"./common/sticky/sticky.mjs";import sn from"./common/switch/switch.mjs";import cn from"./common/tabHeader/tabHeader.mjs";import ln from"./common/textarea/textarea.mjs";import{defaultTheme as un}from"./common/themeProvider/defaultTheme.mjs";import dn from"./common/themeProvider/themeProvider.mjs";import{useTheme as fn}from"./common/themeProvider/useTheme.mjs";import pn,{TiltGroupContext as mn,useTiltGroup as hn}from"./common/tiltGroup/tiltGroup.mjs";import{defaultTiltEasing as gn}from"./common/tilt/tiltMath.mjs";import _n from"./common/tilt/tilt.mjs";import vn from"./common/timeInput/timeInput.mjs";import{TimelineAlignment as yn,TimelineItemStatus as bn}from"./common/timeline/timeline.types.mjs";import xn from"./common/timeline/timeline.mjs";import Sn from"./common/timer/timer.mjs";import Cn from"./common/virtualList/virtualList.mjs";import wn from"./common/wizard/wizard.mjs";import Tn from"./services/formValidation/FormValidatorGroupWithForm.mjs";import En from"./services/formValidation/validatableComponent.mjs";import{useFormValidatorGroup as Dn}from"./services/formValidation/useFormValidatorGroup.mjs";import{FormValidator as On,Validators as kn,useFormValidator as An}from"./services/formValidation/index.mjs";import{hasEightPasswordChars as jn,hasOnePasswordDigit as Mn,hasOnePasswordLetter as Nn,isBic as Pn,isDate as Fn,isEmail as In,isISODate as Ln,isNumber as Rn,isPassword as zn,isURL as Bn}from"@ahrowe/form-validation";export{i as Accordion,e as AccordionStyleType,d as ActionButtons,p as ActionIcon,h as Alert,m as AlertStyleType,E as Align,g as AnimatedLogo,y as AnimatedText,_ as AnimatedTextUnit,v as AnimatedTextVariant,C as Avatar,w as AvatarGroup,S as Badge,b as BadgePosition,x as BadgeStyleType,T as BodyEnd,k as Breadcrumb,u as Button,j as ButtonGroup,A as ButtonGroupOrientation,o as ButtonSize,s as ButtonStyleType,c as ButtonType,N as Card,L as CardActions,I as CardContent,P as CardHeader,F as CardMedia,M as CardStyleType,R as Carousel,z as Checkbox,V as Chip,H as ChipContainer,B as ChipStyleType,q as ColorPicker,t as ConfigProvider,Y as ConfirmModal,pt as DEFAULT_SNAP_OPTIONS,Se as DEFAULT_WALL_ATTRS,te as DatePicker,ie as Divider,ne as DividerOrientation,re as DividerTextPosition,he as DoorSwing,ae as Drawer,ce as DropZone,oe as DropZoneReturnType,se as DropZoneStatus,ee as Dropdown,le as EmptyState,fe as ErrorBoundary,pe as Fab,me as Flip,O as FloatingMenu,On as FormValidator,Tn as FormValidatorGroup,ct as HIT_PX,lt as HIT_PX_COARSE,kt as IconLoading,St as IconPicker,Ct as IdleManager,$ as InfiniteBlock,K as Input,wt as InputDropdown,W as InputIconPosition,G as InputType,f as InteractableDiv,Et as KanbanBoard,Tt as KanbanColumn,Ot as KlipyPicker,Re as MIN_FLOOR_HEIGHT,be as MIN_OPENING_WIDTH,xe as MIN_WALL_LENGTH,J as Modal,At as NumberInput,ge as OpeningKind,jt as OptionPicker,Nt as OtpInput,Mt as OtpInputCharset,Pt as Overscroll,vt as PLAN_FORMAT_VERSION,_e as PlanIssueKind,ve as PlanUnitSystem,Rt as Popover,Ft as PopoverAlign,It as PopoverPlacement,Lt as PopoverTrigger,D as Presentation,zt as ProgressBar,Vt as RadioGroup,Bt as RadioGroupOrientation,Ht as Rating,Ut as RevealLens,l as Ripple,Wt as RoomDrawer,Gt as RoomViewer,Kt as ScrollbarProvider,Dt as SearchInput,Jt as SectionHeader,qt as SectionHeaderSize,Zt as Skeleton,Yt as SkeletonAnimation,Xt as SkeletonVariant,Qt as Slider,mt as SnapKind,a as SpinnerLoading,$t as SplitButton,an as Stepper,en as StepperAlignment,tn as StepperCollapse,nn as StepperLabelPlacement,rn as StepperStyleType,on as Sticky,sn as Switch,cn as TabHeader,ln as Textarea,dn as ThemeProvider,_n as Tilt,pn as TiltGroup,mn as TiltGroupContext,vn as TimeInput,xn as Timeline,yn as TimelineAlignment,bn as TimelineItemStatus,Sn as Timer,de as ToastProvider,U as Tooltip,En as ValidatableComponent,kn as Validators,Cn as VirtualList,ye as WallType,wn as Wizard,ze as addFloor,Ce as addOpening,we as addRect,Te as addWall,at as buildWallPaths,Ee as cleanupPlan,ht as clientToWorld,tt as commitDerivation,un as defaultTheme,gn as defaultTiltEasing,$e as deriveFaces,nt as derivePlan,De as dissolveNode,Be as duplicateFloor,Ve as emptyFloor,He as emptyFloorPlan,Ue as floorBelow,We as floorBounds,Ge as floorIndex,Ke as getFloor,X as getLocale,jn as hasEightPasswordChars,Mn as hasOnePasswordDigit,Nn as hasOnePasswordLetter,ut as hitTest,Pn as isBic,Fn as isDate,In as isEmail,Ln as isISODate,Rn as isNumber,zn as isPassword,Bn as isURL,Z as mapLocale,Oe as mergeNodes,qe as moveFloor,ke as moveNode,et as nodeDegrees,ot as openingGeometry,yt as planFromJson,xt as planFromLegacySvg,bt as planToJson,rt as pruneUnmatchedRooms,Je as removeFloor,Ae as removeOpening,je as removeWall,Ye as renameFloor,gt as resolveSnap,it as roomAtPoint,Me as scalePlan,_t as screenScale,dt as selectionsEqual,Xe as setFloor,Ze as setFloorHeight,Q as setLocale,ue as showToast,Ne as splitWall,Pe as transformPlan,Qe as updateFloor,Fe as updateOpening,n as useComponentDefaults,An as useFormValidator,Dn as useFormValidatorGroup,r as usePresentationDefault,fn as useTheme,hn as useTiltGroup,Ie as validatePlan,st as wallCentrelineSpans,Le as wallLength,ft as worldTolerances};