@ahrowe/ui 0.26.0 → 0.27.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"floorPlan.triangulate.mjs","names":[],"sources":["../../../../package/common/floorPlan/floorPlan.triangulate.ts"],"sourcesContent":["/**\n * Ear clipping for simple polygons, with holes bridged into the outer ring first.\n *\n * Written out rather than pulled in: a floor slab is the only thing in this package that\n * needs a triangulator, and a dependency is a poor trade for one file.\n *\n * The rooms this runs on come from face extraction, so they are already closed, already\n * consistently wound, and free of self-intersections. That is what makes plain ear\n * clipping enough: it is O(n²) and it cannot cope with a self-intersecting ring, and\n * neither limit matters for a room with a few dozen corners.\n */\n\nimport { signedArea, stripSpurs } from './floorPlan.geometry';\nimport type { PlanPoint } from './floorPlan.types';\n\nconst EPS = 1e-9;\n\nfunction area2(a: PlanPoint, b: PlanPoint, c: PlanPoint): number {\n return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);\n}\n\nfunction samePoint(a: PlanPoint, b: PlanPoint): boolean {\n return Math.abs(a.x - b.x) < EPS && Math.abs(a.y - b.y) < EPS;\n}\n\n/** Inclusive of the edges: a vertex lying on one would still leave a sliver behind. */\nfunction inTriangle(p: PlanPoint, a: PlanPoint, b: PlanPoint, c: PlanPoint): boolean {\n const d1 = area2(p, a, b);\n const d2 = area2(p, b, c);\n const d3 = area2(p, c, a);\n const neg = d1 < -EPS || d2 < -EPS || d3 < -EPS;\n const pos = d1 > EPS || d2 > EPS || d3 > EPS;\n return !(neg && pos);\n}\n\n/**\n * Joins each hole to the outer ring with a pair of coincident edges, leaving one ring\n * that ear clipping can take. The bridge runs from the hole's rightmost vertex to a\n * visible vertex of the outer ring, which is the standard construction: going rightwards\n * from the extreme point of a hole must leave it, so the first outer edge hit is visible\n * from it.\n */\nfunction bridgeHoles(outer: PlanPoint[], holes: PlanPoint[][]): PlanPoint[] {\n let ring = outer.slice();\n\n // Rightmost hole first: bridging it cannot cross a hole further right.\n const queue = holes\n .filter((h) => h.length >= 3)\n .map((h) => ({ ring: h, index: h.reduce((best, p, i) => (p.x > h[best].x ? i : best), 0) }))\n .sort((a, b) => b.ring[b.index].x - a.ring[a.index].x);\n\n for (const hole of queue) {\n const from = hole.ring[hole.index];\n\n // The outer vertex to bridge to: the one that is visible and, among those, closest.\n let best = -1;\n let bestDist = Infinity;\n for (let i = 0; i < ring.length; i++) {\n if (ring[i].x < from.x) continue; // must lie to the right, or the bridge doubles back\n const d = (ring[i].x - from.x) ** 2 + (ring[i].y - from.y) ** 2;\n if (d < bestDist && visible(from, ring[i], ring, hole.ring)) {\n bestDist = d;\n best = i;\n }\n }\n // Nothing to the right was visible, so fall back to the nearest vertex anywhere. The\n // ring stays closed either way; at worst the slab gains a seam nobody can see.\n if (best < 0) {\n for (let i = 0; i < ring.length; i++) {\n const d = (ring[i].x - from.x) ** 2 + (ring[i].y - from.y) ** 2;\n if (d < bestDist) {\n bestDist = d;\n best = i;\n }\n }\n }\n\n // Walk the hole from its bridge vertex, then come back along the bridge.\n const woven: PlanPoint[] = [];\n for (let k = 0; k <= hole.ring.length; k++) {\n woven.push(hole.ring[(hole.index + k) % hole.ring.length]);\n }\n ring = [...ring.slice(0, best + 1), ...woven, ...ring.slice(best)];\n }\n\n return ring;\n}\n\n/** Whether the segment from `a` to `b` crosses any edge of the rings it has to avoid. */\nfunction visible(a: PlanPoint, b: PlanPoint, ring: PlanPoint[], hole: PlanPoint[]): boolean {\n for (const poly of [ring, hole]) {\n for (let i = 0; i < poly.length; i++) {\n const p = poly[i];\n const q = poly[(i + 1) % poly.length];\n if (p === a || q === a || p === b || q === b) continue;\n const d1 = area2(a, b, p);\n const d2 = area2(a, b, q);\n const d3 = area2(p, q, a);\n const d4 = area2(p, q, b);\n if (d1 * d2 < 0 && d3 * d4 < 0) return false;\n }\n }\n return true;\n}\n\n/**\n * Triangulates a ring and its holes into index triples over the returned vertex list.\n *\n * The vertices come back as well as the indices because bridging a hole duplicates the\n * two vertices it joins, so the caller cannot simply index into what it passed in.\n */\nexport function triangulate(\n outer: readonly PlanPoint[],\n holes: readonly (readonly PlanPoint[])[] = [],\n): { vertices: PlanPoint[]; indices: number[] } {\n // A dangling wall inside a room puts the same vertex in the ring twice, which is not a\n // simple polygon and would stall ear clipping on a zero-area ear.\n const cleanOuter = stripSpurs(outer);\n if (cleanOuter.length < 3) return { vertices: [], indices: [] };\n\n const ring = bridgeHoles(\n cleanOuter,\n holes.map((h) => stripSpurs(h)).filter((h) => h.length >= 3),\n );\n\n // Ear clipping wants a counter-clockwise ring under the usual maths convention.\n const vertices = signedArea(ring) < 0 ? ring.slice().reverse() : ring.slice();\n\n const live = vertices.map((_, i) => i);\n const indices: number[] = [];\n let guard = live.length * live.length;\n\n while (live.length > 3 && guard-- > 0) {\n let clipped = false;\n for (let i = 0; i < live.length; i++) {\n const ai = live[(i + live.length - 1) % live.length];\n const bi = live[i];\n const ci = live[(i + 1) % live.length];\n const a = vertices[ai];\n const b = vertices[bi];\n const c = vertices[ci];\n if (area2(a, b, c) <= EPS) continue; // reflex or degenerate: not an ear\n\n let blocked = false;\n for (const vi of live) {\n if (vi === ai || vi === bi || vi === ci) continue;\n const v = vertices[vi];\n // Bridging a hole duplicates the two vertices it joins, so a candidate can sit\n // exactly on a corner of the ear. Counting that as \"inside\" blocks every ear in\n // the ring and the triangulation comes back empty.\n if (samePoint(v, a) || samePoint(v, b) || samePoint(v, c)) continue;\n if (inTriangle(v, a, b, c)) {\n blocked = true;\n break;\n }\n }\n if (blocked) continue;\n\n indices.push(ai, bi, ci);\n live.splice(i, 1);\n clipped = true;\n break;\n }\n // No ear found: the ring is degenerate in a way this cannot reduce further. Stopping\n // beats spinning, and the caller gets whatever was triangulated so far.\n if (!clipped) break;\n }\n if (live.length === 3) indices.push(live[0], live[1], live[2]);\n\n return { vertices, indices };\n}\n"],"mappings":"sEAeA,IAAM,EAAM,KAEZ,SAAS,EAAM,EAAc,EAAc,EAAsB,CAC/D,OAAQ,EAAE,EAAI,EAAE,IAAM,EAAE,EAAI,EAAE,IAAM,EAAE,EAAI,EAAE,IAAM,EAAE,EAAI,EAAE,EAC5D,CAEA,SAAS,EAAU,EAAc,EAAuB,CACtD,OAAO,KAAK,IAAI,EAAE,EAAI,EAAE,CAAC,EAAI,GAAO,KAAK,IAAI,EAAE,EAAI,EAAE,CAAC,EAAI,CAC5D,CAGA,SAAS,EAAW,EAAc,EAAc,EAAc,EAAuB,CACnF,IAAM,EAAK,EAAM,EAAG,EAAG,CAAC,EAClB,EAAK,EAAM,EAAG,EAAG,CAAC,EAClB,EAAK,EAAM,EAAG,EAAG,CAAC,EAGxB,MAAO,GAFK,EAAK,OAAQ,EAAK,OAAQ,EAAK,SAC/B,EAAK,GAAO,EAAK,GAAO,EAAK,GAE3C,CASA,SAAS,EAAY,EAAoB,EAAmC,CAC1E,IAAI,EAAO,EAAM,MAAM,EAGjB,EAAQ,EACX,OAAQ,GAAM,EAAE,QAAU,CAAC,EAC3B,IAAK,IAAO,CAAE,KAAM,EAAG,MAAO,EAAE,QAAQ,EAAM,EAAG,IAAO,EAAE,EAAI,EAAE,GAAM,EAAI,EAAI,EAAO,CAAC,CAAE,EAAE,EAC1F,MAAM,EAAG,IAAM,EAAE,KAAK,EAAE,OAAO,EAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAEvD,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAO,EAAK,KAAK,EAAK,OAGxB,EAAO,GACP,EAAW,IACf,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,EAAK,GAAG,EAAI,EAAK,EAAG,SACxB,IAAM,GAAK,EAAK,GAAG,EAAI,EAAK,IAAM,GAAK,EAAK,GAAG,EAAI,EAAK,IAAM,EAC1D,EAAI,GAAY,EAAQ,EAAM,EAAK,GAAI,EAAM,EAAK,IAAI,IACxD,EAAW,EACX,EAAO,EAEX,CAGA,GAAI,EAAO,EACT,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,GAAK,EAAK,GAAG,EAAI,EAAK,IAAM,GAAK,EAAK,GAAG,EAAI,EAAK,IAAM,EAC1D,EAAI,IACN,EAAW,EACX,EAAO,EAEX,CAIF,IAAM,EAAqB,CAAC,EAC5B,IAAK,IAAI,EAAI,EAAG,GAAK,EAAK,KAAK,OAAQ,IACrC,EAAM,KAAK,EAAK,MAAM,EAAK,MAAQ,GAAK,EAAK,KAAK,OAAO,EAE3D,EAAO,CAAC,GAAG,EAAK,MAAM,EAAG,EAAO,CAAC,EAAG,GAAG,EAAO,GAAG,EAAK,MAAM,CAAI,CAAC,CACnE,CAEA,OAAO,CACT,CAGA,SAAS,EAAQ,EAAc,EAAc,EAAmB,EAA4B,CAC1F,IAAK,IAAM,IAAQ,CAAC,EAAM,CAAI,EAC5B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAI,EAAK,GACT,EAAI,GAAM,EAAI,GAAK,EAAK,QAC9B,GAAI,IAAM,GAAK,IAAM,GAAK,IAAM,GAAK,IAAM,EAAG,SAC9C,IAAM,EAAK,EAAM,EAAG,EAAG,CAAC,EAClB,EAAK,EAAM,EAAG,EAAG,CAAC,EAClB,EAAK,EAAM,EAAG,EAAG,CAAC,EAClB,EAAK,EAAM,EAAG,EAAG,CAAC,EACxB,GAAI,EAAK,EAAK,GAAK,EAAK,EAAK,EAAG,MAAO,EACzC,CAEF,MAAO,EACT,CAQA,SAAgB,EACd,EACA,EAA2C,CAAC,EACE,CAG9C,IAAM,EAAa,EAAW,CAAK,EACnC,GAAI,EAAW,OAAS,EAAG,MAAO,CAAE,SAAU,CAAC,EAAG,QAAS,CAAC,CAAE,EAE9D,IAAM,EAAO,EACX,EACA,EAAM,IAAK,GAAM,EAAW,CAAC,CAAC,EAAE,OAAQ,GAAM,EAAE,QAAU,CAAC,CAC7D,EAGM,EAAW,EAAW,CAAI,EAAI,EAAI,EAAK,MAAM,EAAE,QAAQ,EAAI,EAAK,MAAM,EAEtE,EAAO,EAAS,KAAK,EAAG,IAAM,CAAC,EAC/B,EAAoB,CAAC,EACvB,EAAQ,EAAK,OAAS,EAAK,OAE/B,KAAO,EAAK,OAAS,GAAK,KAAU,GAAG,CACrC,IAAI,EAAU,GACd,IAAK,IAAI,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,IAAM,EAAK,GAAM,EAAI,EAAK,OAAS,GAAK,EAAK,QACvC,EAAK,EAAK,GACV,EAAK,GAAM,EAAI,GAAK,EAAK,QACzB,EAAI,EAAS,GACb,EAAI,EAAS,GACb,EAAI,EAAS,GACnB,GAAI,EAAM,EAAG,EAAG,CAAC,GAAK,EAAK,SAE3B,IAAI,EAAU,GACd,IAAK,IAAM,KAAM,EAAM,CACrB,GAAI,IAAO,GAAM,IAAO,GAAM,IAAO,EAAI,SACzC,IAAM,EAAI,EAAS,GAIf,OAAU,EAAG,CAAC,GAAK,EAAU,EAAG,CAAC,GAAK,EAAU,EAAG,CAAC,IACpD,EAAW,EAAG,EAAG,EAAG,CAAC,EAAG,CAC1B,EAAU,GACV,KACF,CACF,CACI,MAIJ,CAFA,EAAQ,KAAK,EAAI,EAAI,CAAE,EACvB,EAAK,OAAO,EAAG,CAAC,EAChB,EAAU,GACV,KADU,CAEZ,CAGA,GAAI,CAAC,EAAS,KAChB,CAGA,OAFI,EAAK,SAAW,GAAG,EAAQ,KAAK,EAAK,GAAI,EAAK,GAAI,EAAK,EAAE,EAEtD,CAAE,WAAU,SAAQ,CAC7B"}
@@ -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 ee,addRect as te,addWall as ne,dissolveNode as re,mergeNodes as ie,moveNode as ae,removeOpening as oe,removeWall as se,splitWall as ce,updateOpening 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 l}from"../floorPlan/floorPlan.hit.mjs";import{SnapKind as u,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 d from"./roomDrawer.module.mjs";import{forwardRef as Fe,useCallback as f,useEffect as p,useImperativeHandle as Ie,useMemo as m,useRef as h,useState as g}from"react";import _ from"classnames";import{faAngleDown as Le,faAngleUp as Re,faArrowPointer as ze,faArrowRotateLeft as Be,faArrowRotateRight as Ve,faBorderAll as He,faClone as Ue,faDoorOpen as We,faDownload as Ge,faDraftingCompass as Ke,faExpand as qe,faLayerGroup as Je,faMagnet as Ye,faMagnifyingGlassMinus as Xe,faMagnifyingGlassPlus as Ze,faMinus as Qe,faPlus as $e,faRulerCombined as et,faSquare as tt,faTrash as nt,faUpload as rt,faWindowMaximize as it}from"@fortawesome/free-solid-svg-icons";import{Fragment as at,jsx as v,jsxs as y}from"react/jsx-runtime";var ot=[`select`,`wall`,`rect`,`door`,`window`,`archway`,`measure`],st={v:`select`,w:`wall`,r:`rect`,d:`door`,n:`window`,a:`archway`,m:`measure`},ct={door:a.Door,window:a.Window,archway:a.Archway},lt={[a.Door]:`Door`,[a.Window]:`Window`,[a.Archway]:`Archway`,[a.Gap]:`Gap`},ut={[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}},dt=1,ft=4,pt=[];function mt(e){return e>=1e3?`${(e/1e3).toFixed(2)} m`:`${Math.round(e)} mm`}function ht(e){let t=e/1e6;return`${t.toFixed(+(t<10))} m²`}function gt(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:_t,onChange:x,onChangeEnd:vt,floorId:yt,defaultFloorId:bt,onFloorChange:xt,showFloorBar:St=!0,showUnderlay:Ct=!0,tool:wt,defaultTool:Tt=`select`,onToolChange:Et,tools:Dt=ot,selection:Ot,defaultSelection:kt,onSelectionChange:At,multiSelect:jt=!0,onHoverChange:Mt,view:Nt,defaultView:Pt,onViewChange:Ft,minZoom:It=.005,maxZoom:Lt=2,fitOnMount:Rt=!0,gridSize:S=100,showGrid:zt=!0,snap:Bt=!0,angleLock:Vt=!1,constrainAngle:Ht=45,showSnapGuides:Ut=!0,wallThickness:Wt=c.thickness,wallHeight:Gt,openingDefaults:Kt,showMeasurements:qt=!0,formatLength:Jt=mt,formatArea:Yt=ht,showToolbar:Xt=!0,showInspector:Zt=!0,showHint:Qt=!0,showHistoryControls:$t=!0,showFileControls:en=!0,fileName:tn,onImport:nn,historyMode:rn=`internal`,historyLimit:an=50,onHistoryChange:on,readOnly:sn=!1,disabled:C=!1,canvasHeight:cn=`420px`,getRoomColor:ln,renderRoomLabel:un,labels:w,icons:T,"aria-label":dn,className:fn,style:pn,classNames:E,styles:D,...mn}=e(`RoomDrawer`,a),hn=r(),O=hn?Te:we,gn=h(null),_n=h(null),vn=h(null),yn=h(null),k=h({kind:`none`}),bn=h(new Map),xn=h(null),Sn=h(!1),Cn=h(!1),wn=h(!1),A=Pe(m(()=>_t??b??fe(),[]),an),Tn=b!==void 0,j=Tn?b:A.present;p(()=>{if(!(!Tn||!b)){if(b===yn.current){A.replace(b);return}A.commit(b,`external`)}},[b,Tn]);let[En,Dn]=g(bt),On=yt??En??j.floors[0]?.id,M=m(()=>ge(j,On)??ge(j)??fe().floors[0],[j,On]),[kn,An]=g(Ct);p(()=>An(Ct),[Ct]);let jn=m(()=>kn?pe(j,M.id):null,[kn,j,M.id]),N=f(e=>{e!==M.id&&(yt===void 0&&Dn(e),xt?.(e))},[M.id,yt,xt]),P=m(()=>Ce(M),[M]).rooms,[Mn,Nn]=g(Tt),F=wt??Mn,Pn=f(e=>{wt===void 0&&Nn(e),Et?.(e)},[wt,Et]),[Fn,In]=g(kt??pt),I=Ot===void 0?Fn:Ot,L=h(I);L.current=I;let R=f(e=>{let t=e===null?pt:Array.isArray(e)?e:[e];L.current=t,Ot===void 0&&In(t),At?.([...t])},[Ot,At]),Ln=f(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,Rn=f(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=M.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},[M.walls,P]),zn=m(()=>Rn(I),[Rn,I]),[Bn,Vn]=g(null),[Hn,Un]=g(Pt??{x:0,y:0,zoom:.05}),B=Nt??Hn,V=f(e=>{Nt===void 0&&Un(e),Ft?.(e)},[Nt,Ft]),[H,Wn]=g({width:800,height:420}),[U,Gn]=g([]),[W,Kn]=g(null),[qn,Jn]=g(Bt),[Yn,Xn]=g(Vt);p(()=>Jn(Bt),[Bt]),p(()=>Xn(Vt),[Vt]);let[Zn,Qn]=g(zt);p(()=>Qn(zt),[zt]);let $n=h(null),[G,er]=g(null),[K,tr]=g([]),nr=h(0),[rr,ir]=g(null),ar=h(null),or=f(e=>{let t=l(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]),[sr,cr]=g(null),q=!sn&&!C,lr=m(()=>{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]);p(()=>{let e=_n.current;if(!e)return;let t=new ResizeObserver(()=>{let t=e.getBoundingClientRect();t.width>0&&t.height>0&&Wn({width:Math.round(t.width),height:Math.round(t.height)})});t.observe(e);let n=e.getBoundingClientRect();return n.width>0&&n.height>0&&Wn({width:Math.round(n.width),height:Math.round(n.height)}),()=>t.disconnect()},[]);let ur=f((e,t)=>Oe(e,t,_n.current?.getBoundingClientRect()??{left:0,top:0},B),[B]),J=f(e=>({x:(e.x-B.x)*B.zoom,y:(e.y-B.y)*B.zoom}),[B]),Y=f((e,t,n,r,i)=>{let a=qn!==Cn.current,o=Yn!==wn.current,s=ke(e,{floor:M,pxToWorld:B.zoom>0?1/B.zoom:1,origin:t,referenceAngle:r,excludeNodeIds:n,excludeWallIds:i,options:{enabled:a?[u.Node,u.Intersection,u.Wall,u.Angle,u.Extension,u.Alignment,u.Grid]:[],gridSize:S,angleStepDeg:o?Ht:0,toleranceScreenPx:hn?16:10}});return $n.current=s,s},[M,B.zoom,qn,Yn,S,Ht,hn]),dr=f(e=>{let t=Object.values(M.walls).filter(t=>t.a===e||t.b===e),n=new Set(t.map(e=>e.id)),r=M.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=M.nodes[t];n&&(a=Math.atan2(n.y-r.y,n.x-r.x))}return{origin:i,referenceAngle:a,excludeWallIds:n}},[M]),fr=f((e={})=>{let t=e.padding??24,n=me(M);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(It,Math.min(Lt,r));V({x:n.minX-(H.width/i-n.width)/2,y:n.minY-(H.height/i-n.height)/2,zoom:i})},[M,H.width,H.height,It,Lt,V]),pr=h(!1);p(()=>{!Rt||pr.current||Object.keys(M.nodes).length!==0&&(H.width<=1||(pr.current=!0,fr()))},[Rt,M,H.width,fr]);let mr=f((e,t,n,r=[],i={})=>{if(e===M)return j;let a=be(j,e);yn.current=a,n?i.push===!1?A.replace(a):A.commit(a,t,r):A.updateGesture(a);let o={reason:t,committed:n,targetIds:r};return x?.(a,o),n&&vt?.(a,o),a},[M,j,A,x,vt]),X=f((e,t,n=[],r={})=>{let i=Se(e).floor;return mr(i,t,!0,n,r)},[mr]);p(()=>{on?.({canUndo:A.canUndo,canRedo:A.canRedo})},[A.canUndo,A.canRedo,on]);let hr=m(()=>z?.type===`room`?P.find(e=>e.roomId===z.id)??null:null,[z,P]),Z=z?.type===`wall`?M.walls[z.id]:void 0,gr=z?.type===`opening`?M.openings[z.id]:void 0,_r=m(()=>{if(!Z)return null;let e=M.nodes[Z.a],t=M.nodes[Z.b];return!e||!t?null:{x:(e.x+t.x)/2,y:(e.y+t.y)/2}},[Z,M.nodes]),vr=f(()=>{if(!q||!Z)return;let e=ce(M,Z.id,.5);e.result.wallIds&&(X(e.floor,`edit-wall`,[e.result.nodeId]),R({type:`node`,id:e.result.nodeId}))},[q,Z,M,X,R]),yr=f((e,t,n=new Set)=>{if(e.type===`wall`)return{floor:se(t,e.id).floor};if(e.type===`opening`)return{floor:oe(t,e.id).floor};if(e.type===`node`){let n=re(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=se(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=se(a,e,{dissolveCollinear:!1}).floor);let o={...a.rooms};return delete o[e.id],{floor:{...a,rooms:o}}},[P]),br=f(()=>{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=M,a;for(let e of n){let t=yr(e,i,r);i=t.floor,n.length===1&&(a=t.reselect)}i!==M&&(X(i,`delete`,n.map(e=>e.id)),R(a??null))},[q,M,yr,X,R]),xr=f(()=>{Gn([])},[]),Sr=f(e=>{if(C)return;if(gn.current?.focus(),cr(null),bn.current.set(e.pointerId,{x:e.clientX,y:e.clientY}),e.currentTarget.setPointerCapture?.(e.pointerId),bn.current.size===2){let[e,t]=[...bn.current.values()];k.current.kind!==`none`&&k.current.kind!==`pan`&&A.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(bn.current.size>2)return;if(xn.current={client:{x:e.clientX,y:e.clientY},moved:!1},e.button===1||Sn.current){k.current={kind:`pan`,startClient:{x:e.clientX,y:e.clientY},startView:B};return}if(e.button!==0)return;let t=ur(e.clientX,e.clientY);if(!q){R(Ee(M,P,t,l(O,B.zoom)));return}if(F===`rect`){let e=Y(t).point;k.current={kind:`rect`,start:e,current:e},A.beginGesture();return}if(F===`measure`){let e=or(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,lr).point;if(U.length===0){Gn([n]);return}let r=U[U.length-1],i=ne(M,r,n,{thickness:Wt,type:o.Interior,height:Gt},l(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)<l(O,B.zoom).node?xr():Gn(e=>[...e,n]);return}let n=ct[F];if(n){let e=Ee(M,P,t,l(O,B.zoom),{accept:[`wall`]});if(e?.type!==`wall`)return;let r=M.walls[e.id],i=M.nodes[r.a],a=M.nodes[r.b],o=Math.hypot(a.x-i.x,a.y-i.y),s=((t.x-i.x)*(a.x-i.x)+(t.y-i.y)*(a.y-i.y))/(o*o||1),c={...ut[n],...Kt?.[n]},te=ee(M,{wallId:r.id,kind:n,offset:Math.min(Math.max(s,0),1)*o,width:c.width,sill:c.sill,head:c.head});te.result.openingId&&(X(te.floor,`add-opening`,[te.result.openingId]),R({type:`opening`,id:te.result.openingId}));return}let r=l(O,B.zoom);if(_r&&z?.type===`wall`&&Math.hypot(t.x-_r.x,t.y-_r.y)<=r.node){A.beginGesture(),k.current={kind:`wallSplit`,wallId:z.id,at:_r};return}let i=Ee(M,P,t,r),a=jt&&(e.ctrlKey||e.metaKey);if(!i){a||R(null),k.current=jt?{kind:`marquee`,start:t,current:t,additive:a,base:L.current}:{kind:`none`};return}if(a){Ln(i),k.current={kind:`none`};return}if(L.current.some(e=>e.type===i.type&&e.id===i.id)||R(i),A.beginGesture(),L.current.length>1){let e=[...Rn(L.current)],n={};for(let t of e){let e=M.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,...dr(i.id)};else if(i.type===`wall`){let e=M.walls[i.id];k.current={kind:`wall`,wallId:i.id,startWorld:t,origA:{...M.nodes[e.a]},origB:{...M.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=M.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,M,P,O,ur,Y,U,Wt,Gt,Kt,X,R,_r,z,lr,dr,Rn,jt,Ln,A,xr,or,K]),Cr=f(e=>{if(C)return;bn.current.has(e.pointerId)&&bn.current.set(e.pointerId,{x:e.clientX,y:e.clientY});let t=k.current;if(t.kind===`pinch`&&bn.current.size>=2){let[e,n]=[...bn.current.values()],r=Math.hypot(n.x-e.x,n.y-e.y);if(t.startDist<=0)return;let i=Math.max(It,Math.min(Lt,t.startView.zoom*(r/t.startDist))),a=_n.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(xn.current){let t=e.clientX-xn.current.client.x,n=e.clientY-xn.current.client.y;Math.hypot(t,n)>ft&&(xn.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=ur(e.clientX,e.clientY);if(Kn(n),t.kind===`none`){if(!q)return;if(F===`wall`&&U.length>0){let e=Y(n,U[U.length-1],void 0,lr);Kn(e.point),er(e);return}if(F===`select`){let e=Ee(M,P,n,l(O,B.zoom));De(e,Bn)||(Vn(e),Mt?.(e))}F===`measure`&&ir(or(n)?.id??null);return}if(xn.current?.moved){if(t.kind===`measureEnd`){let e=Y(n).point;tr(n=>n.map(n=>n.id===t.id?{...n,[t.end]:e}:n)),Kn(e);return}if(t.kind===`measureMove`){let e=n.x-t.startWorld.x,r=n.y-t.startWorld.y;tr(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},Kn(Y(n).point);return}if(t.kind===`marquee`){k.current={...t,current:n},Kn(n);return}if(t.kind===`wallSplit`){let e=ce(M,t.wallId,t.at);if(!e.result.wallIds){k.current={kind:`none`};return}let r=e.result.nodeId,i=M.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}),er($n.current),mr(ae(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;er($n.current),k.current={...t,moved:!0},mr(ae(M,t.nodeId,e).floor,`move-node`,!1,[t.nodeId]);return}if(t.kind===`wall`){let e=M.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=Bt!==Cn.current&&S>0?S:1,ee=Math.round(s/c)*c,te=ae(M,e.a,{x:t.origA.x+o.x*ee,y:t.origA.y+o.y*ee}).floor;te=ae(te,e.b,{x:t.origB.x+o.x*ee,y:t.origB.y+o.y*ee}).floor,k.current={...t,moved:!0},mr(te,`move-wall`,!1,[t.wallId]);return}if(t.kind===`opening`){let e=M.openings[t.openingId];if(!e)return;let r=M.walls[e.wallId],i=M.nodes[r.a],a=M.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},mr(le(M,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=Bt!==Cn.current&&S>0?S:1,a=Math.round(e/i)*i,o=Math.round(r/i)*i,s=M;for(let e of t.nodeIds){let n=t.orig[e];n&&(s=ae(s,e,{x:n.x+a,y:n.y+o}).floor)}k.current={...t,moved:!0},mr(s,`move-room`,!1,t.nodeIds)}}},[C,q,F,M,P,Bn,O,B.zoom,It,Lt,S,Bt,ur,Y,mr,V,R,U,lr,Mt,or]),wr=f((e,t)=>{bn.current.delete(e.pointerId);let n=k.current;k.current={kind:`none`};let r=xn.current?.moved??!1;if(xn.current=null,er(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(M.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=A.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>dt&&(nr.current+=1,tr(e=>[...e,{id:nr.current,a:n.start,b:n.current}]));return}if(n.kind===`rect`){if(!r){A.cancelGesture();return}let e=te(M,n.start,n.current,{thickness:Wt,type:o.Interior,height:Gt},l(O,B.zoom).node);if(e.result.wallIds.length===0){A.cancelGesture();return}let t=A.endGesture();X(e.floor,`draw-rect`,e.result.wallIds,{push:!t});return}if(!r){A.cancelGesture();return}if(n.kind===`node`){let e=M.nodes[n.nodeId];if(e){let t=l(O,B.zoom).node,r=Object.values(M.nodes).find(r=>r.id!==n.nodeId&&Math.hypot(r.x-e.x,r.y-e.y)<=t);if(r){let e=A.endGesture();X(ie(M,r.id,n.nodeId).floor,`move-node`,[r.id],{push:!e}),R({type:`node`,id:r.id});return}}}let i=A.endGesture();X(M,n.kind===`wall`?`move-wall`:n.kind===`opening`?`move-opening`:n.kind===`room`?`move-room`:`move-node`,[],{push:!i})},[M,A,O,B.zoom,Wt,Gt,X,R,x]);p(()=>{let e=_n.current;if(!e||C)return;function t(t){t.preventDefault();let n=e.getBoundingClientRect(),r=Math.exp(-t.deltaY*.002);V((()=>{let e=Tr.current,i=Math.max(It,Math.min(Lt,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,It,Lt,V]);let Tr=h(B);Tr.current=B;let Er=f(e=>{let t=Math.max(It,Math.min(Lt,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,It,Lt,V]),Dr=f(()=>{if(rn===`none`)return;let e=A.undo();e&&(yn.current=e,x?.(e,{reason:`undo`,committed:!0,targetIds:[]}),vt?.(e,{reason:`undo`,committed:!0,targetIds:[]}))},[rn,A,x,vt]),Or=f(()=>{if(rn===`none`)return;let e=A.redo();e&&(yn.current=e,x?.(e,{reason:`redo`,committed:!0,targetIds:[]}),vt?.(e,{reason:`redo`,committed:!0,targetIds:[]}))},[rn,A,x,vt]),kr=f(()=>{let e=P.filter(e=>e.roomId).map(e=>({type:`room`,id:e.roomId}));if(e.length>0){R(e);return}R(Object.keys(M.nodes).map(e=>({type:`node`,id:e})))},[P,M.nodes,R]),Ar=f((e,t)=>{if(!q||zn.size===0)return;let n=S>0?S:100,r=wn.current?n*10:n,i=M;for(let n of zn){let a=i.nodes[n];a&&(i=ae(i,n,{x:a.x+e*r,y:a.y+t*r}).floor)}X(i,`nudge`,[...zn])},[q,zn,M,S,X]),jr=f(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`&&(wn.current=!0),e.key===`Alt`&&(Cn.current=!0),e.key===` `&&!Sn.current){Sn.current=!0,e.preventDefault();return}let n=e.metaKey||e.ctrlKey;if(n&&e.key.toLowerCase()===`z`){e.preventDefault(),e.shiftKey?Or():Dr();return}if(n&&e.key.toLowerCase()===`a`){e.preventDefault(),jt&&kr();return}if(n&&e.key.toLowerCase()===`y`){e.preventDefault(),Or();return}if(e.key===`Escape`){U.length>0?xr():K.length>0?tr([]):R(null);return}if(e.key===`Enter`&&F===`wall`){xr();return}if(e.key===`Delete`||e.key===`Backspace`){if(e.preventDefault(),F===`measure`){rr!==null&&(tr(e=>e.filter(e=>e.id!==rr)),ir(null));return}br();return}if(e.key===`+`||e.key===`=`){Er(1.25);return}if(e.key===`-`){Er(1/1.25);return}if(e.key===`0`){fr();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&&Ar(t[0],t[1]);return}let r=e.key.toLowerCase();if(r===`s`){Jn(e=>!e);return}if(r===`l`){Xn(e=>!e);return}if(r===`g`){Qn(e=>!e);return}let i=st[e.key.toLowerCase()];i&&q&&Dt.includes(i)&&(Pn(i),xr())},[C,q,Dt,F,U,K.length,rr,Or,Dr,R,xr,br,Er,fr,Ar,Pn,jt,kr]),Q=f((e,t,n)=>{yn.current=e,n?.resetHistory?(A.clearHistory(),A.replace(e)):A.commit(e,t);let r={reason:t,committed:!0,targetIds:[]};x?.(e,r),vt?.(e,r)},[A,x,vt]),Mr=f((e={})=>{let{plan:t,floor:n}=ue(j,{...e,index:he(j,M.id)+1});return Q(t,`add-floor`),N(n.id),n.id},[j,M.id,Q,N]),Nr=f(()=>{let{plan:e,floor:t}=de(j,M.id);return t?(Q(e,`duplicate-floor`),N(t.id),t.id):null},[j,M.id,Q,N]),Pr=f(e=>{let t=e??M.id,n=ve(j,t);if(n!==j&&(Q(n,`remove-floor`),t===M.id)){let e=he(j,t);N(n.floors[Math.max(0,e-1)].id)}},[j,M.id,Q,N]),Fr=f((e,t)=>{let n=_e(j,e,t);n!==j&&Q(n,`move-floor`)},[j,Q]),Ir=f((e,t)=>{let n=xe(j,e,t);n!==j&&Q(n,`edit-floor`)},[j,Q]),Lr=f((e,t)=>{let n=ye(j,e,t);n!==j&&Q(n,`rename-floor`)},[j,Q]),Rr=f(e=>{let t=(e??tn??j.name??``).trim()||`floor-plan`,n=URL.createObjectURL(new Blob([je(j)],{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)},[tn,j]),zr=f(e=>{let t=Ae(e);return t.plan&&Q(t.plan,`import`),cr(t.plan&&t.issues.length===0?null:t.issues),nn?.(t),t},[nn,Q]),Br=f(e=>{e.text().then(e=>zr(e)).catch(e=>{let t=[`Could not read that file: ${e.message}`];cr(t),nn?.({plan:null,issues:t})})},[zr,nn]),Vr=f(()=>tr([]),[]),Hr=f(e=>{e.key===`Shift`&&(wn.current=!1),e.key===`Alt`&&(Cn.current=!1),e.key===` `&&(Sn.current=!1)},[]);Ie(Fe,()=>({getPlan:()=>j,setPlan:(e,t)=>Q(e,`import`,t),clear:()=>Q(fe(),`clear`),getFloorId:()=>M.id,setFloorId:N,addFloor:e=>Mr(e),duplicateFloor:Nr,removeFloor:Pr,renameFloor:Lr,moveFloor:Fr,setFloorHeight:Ir,clearMeasurements:Vr,download:Rr,loadJson:zr,undo:Dr,redo:Or,canUndo:()=>rn!==`none`&&A.canUndo,canRedo:()=>rn!==`none`&&A.canRedo,clearHistory:A.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:Ln,selectAll:kr,deleteSelection:br,getView:()=>B,setView:V,zoomBy:Er,fitToContent:fr,toWorld:ur,toScreen:J,getSvgElement:()=>vn.current}),[j,A,Q,M,N,Mr,Nr,Pr,Lr,Fr,Ir,Vr,Rr,zr,Dr,Or,rn,R,Ln,kr,br,B,V,Er,fr,ur,J]);let $=k.current,Ur=m(()=>{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<dt)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:_(d.roomDrawerMeasureLine,rr===n.id&&d.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:d.roomDrawerMeasureGrip,cx:a.x,cy:a.y,r:4},`measure-grip-${n.id}-${i}`));e.push(v(`text`,{className:_(d.roomDrawerMeasure,E?.measureLine),x:c.x,y:c.y-8,textAnchor:`middle`,children:`${Jt(i)} · ${gt(a)}`},`measure-label-${n.id}`))}if(Ut&&G&&(G.guides.forEach((t,n)=>{let r=J(t.a),i=J(t.b);e.push(v(`line`,{className:_(d.roomDrawerGuide,t.kind===u.Angle&&d.roomDrawerGuideAngle),x1:r.x,y1:r.y,x2:i.x,y2:i.y},`guide-${n}`))}),G.kind!==u.None&&G.kind!==u.Grid)){let t=J(G.point);e.push(v(`rect`,{className:d.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:d.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);qt&&(s>0||c>0)&&(e.push(v(`text`,{className:d.roomDrawerMeasure,x:(r+a)/2,y:i-8,textAnchor:`middle`,children:Jt(s)},`rect-width`),v(`text`,{className:d.roomDrawerMeasure,x:r-8,y:(i+o)/2,textAnchor:`end`,dominantBaseline:`central`,children:Jt(c)},`rect-height`)),s>0&&c>0&&e.push(v(`text`,{className:_(d.roomDrawerMeasure,d.roomDrawerMeasureSecondary),x:(r+a)/2,y:(i+o)/2,textAnchor:`middle`,dominantBaseline:`central`,children:Yt(s*c)},`rect-area`)))}if(F===`wall`&&U.length>0){let t=[...U,W].filter(Boolean).map(J);if(e.push(v(`polyline`,{className:d.roomDrawerPreview,points:t.map(e=>`${e.x},${e.y}`).join(` `),fill:`none`},`chain`)),t.forEach((t,n)=>{e.push(v(`circle`,{className:d.roomDrawerHandle,cx:t.x,cy:t.y,r:4},`chain-dot-${n}`))}),qt&&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===u.Angle;e.push(v(`text`,{className:_(d.roomDrawerMeasure,i&&d.roomDrawerMeasureLocked),x:r.x,y:r.y-8,textAnchor:`middle`,children:`${Jt(n)} · ${gt(G?.angleRelativeTo===`reference`&&lr!==void 0?Math.atan2(W.y-t.y,W.x-t.x)-lr: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 zn){let r=M.nodes[t];if(!r)continue;let i=J(r);e.push(v(`circle`,{className:_(d.roomDrawerHandle,n.has(t)&&d.roomDrawerHandleActive),cx:i.x,cy:i.y,r:5},`handle-${t}`))}if($.kind===`marquee`&&xn.current?.moved){let t=J($.start),n=J($.current);e.push(v(`rect`,{className:d.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(_r&&$.kind!==`node`){let t=J(_r);e.push(v(`circle`,{className:d.roomDrawerMidHandle,cx:t.x,cy:t.y,r:4},`midpoint`))}if(qt&&$.kind===`room`&&$.moved){let t=new Set($.nodeIds),n=$.nodeIds.find(e=>M.nodes[e]&&$.orig[e]);if(n){let t=M.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:_(d.roomDrawerMeasure,d.roomDrawerMeasureOffset),x:s.x,y:s.y-26,textAnchor:`middle`,children:`${Jt(Math.hypot(i,a))} · ${gt(Math.atan2(a,i))}`},`room-offset`))}for(let n of Object.values(M.walls)){if(t.has(n.a)===t.has(n.b))continue;let r=M.nodes[n.a],i=M.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:_(d.roomDrawerMeasure,d.roomDrawerMeasureSecondary),x:s.x,y:s.y-8,textAnchor:`middle`,children:`${Jt(Math.hypot(o.x-a.x,o.y-a.y))} · ${gt(Math.atan2(o.y-a.y,o.x-a.x))}`},`room-stretch-${n.id}`))}}if(qt&&(z?.type===`node`||z?.type===`wall`)){let t=[],n=new Set,r=(e,r,i)=>{if(n.has(e))return;let a=M.walls[e];a&&(n.add(e),t.push({wall:a,from:r,primary:i}))};if(z.type===`node`)for(let e of Object.values(M.walls))(e.a===z.id||e.b===z.id)&&r(e.id,z.id,!0);else{let e=M.walls[z.id];if(e){r(e.id,e.a,!0);for(let t of Object.values(M.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===u.Angle&&$.kind!==`none`;for(let{wall:n,from:r,primary:a}of t){let t=M.nodes[n.a],o=M.nodes[n.b];if(!t||!o)continue;let s=n.a===r?t:o,c=n.a===r?o:t,ee=J({x:(t.x+o.x)/2,y:(t.y+o.y)/2});e.push(v(`text`,{className:_(d.roomDrawerMeasure,!a&&d.roomDrawerMeasureSecondary,a&&i&&d.roomDrawerMeasureLocked),x:ee.x,y:ee.y-8,textAnchor:`middle`,children:`${Jt(Math.hypot(c.x-s.x,c.y-s.y))} · ${gt(Math.atan2(c.y-s.y,c.x-s.x))}`},`measure-${n.id}`))}}return v(at,{children:e})},[q,$,F,U,W,I,M,P,z,zn,_r,qt,Ut,G,lr,Jt,Yt,K,rr,E?.measureLine,J]),Wr={select:{icon:ze,label:w?.select??`Select and edit`,key:`V`},wall:{icon:Qe,label:w?.wall??`Draw walls`,key:`W`},rect:{icon:tt,label:w?.rect??`Draw a room`,key:`R`},door:{icon:We,label:w?.door??`Add a door`,key:`D`},window:{icon:it,label:w?.window??`Add a window`,key:`N`},archway:{icon:qe,label:w?.archway??`Add an archway`,key:`A`},measure:{icon:et,label:w?.measure??`Measure`,key:`M`}},Gr=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`:ct[F]?w?.hintOpening??`Click a wall to cut an opening into it`:w?.hintSelect??(jt?`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`):``,Kr=I.length===0?w?.selectedFloor??`Floor`:I.length>1?(w?.selectedCount??`{count} selected`).replace(`{count}`,String(I.length)):gr?w?.selectedOpening??lt[gr.kind]:Z?w?.selectedWall??`Wall`:z?.type===`room`?w?.selectedRoom??`Room`:w?.selectedCorner??`Corner`,qr=q?Dt:[];return y(`div`,{...mn,ref:gn,className:_(d.roomDrawer,C&&d.roomDrawerDisabled,fn,E?.root),style:{...pn,...D?.root},role:`application`,"aria-label":dn??`Floor plan editor`,tabIndex:C?-1:0,onKeyDown:jr,onKeyUp:Hr,children:[Xt&&y(`div`,{className:_(d.roomDrawerToolbar,E?.toolbar),style:D?.toolbar,role:`toolbar`,"aria-label":`Drawing tools`,children:[qr.map(e=>{let n=Wr[e];return v(`button`,{type:`button`,className:_(d.roomDrawerToolButton,e===F&&d.roomDrawerToolButtonActive,E?.toolButton),style:D?.toolButton,title:`${n.label} (${n.key})`,"aria-label":n.label,"aria-pressed":e===F,onClick:()=>{Pn(e),xr()},children:t(T?.[e]??n.icon,{className:_(d.roomDrawerToolIcon,E?.toolIcon),style:D?.toolIcon})},e)}),qr.length>0&&v(`span`,{className:d.roomDrawerToolbarSeparator}),q&&y(at,{children:[[{on:qn,toggle:()=>Jn(e=>!e),icon:T?.snap??Ye,label:w?.snap??`Snap to grid and geometry`,key:`S`},{on:Yn,toggle:()=>Xn(e=>!e),icon:T?.angleLock??Ke,label:w?.angleLock??`Lock to ${Ht}° angles`,key:`L`},{on:Zn,toggle:()=>Qn(e=>!e),icon:T?.grid??He,label:w?.grid??`Show grid`,key:`G`},...pe(j,M.id)?[{on:kn,toggle:()=>An(e=>!e),icon:T?.underlay??Je,label:w?.underlay??`Show the floor below`,key:`B`}]:[]].map(e=>v(`button`,{type:`button`,className:_(d.roomDrawerToolButton,e.on&&d.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:_(d.roomDrawerToolIcon,E?.toolIcon),style:D?.toolIcon})},e.key)),v(`span`,{className:d.roomDrawerToolbarSeparator})]}),$t&&rn!==`none`&&q&&y(at,{children:[v(`button`,{type:`button`,className:_(d.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.undo??`Undo`,"aria-label":w?.undo??`Undo`,disabled:!A.canUndo,onClick:Dr,children:t(T?.undo??Be)}),v(`button`,{type:`button`,className:_(d.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.redo??`Redo`,"aria-label":w?.redo??`Redo`,disabled:!A.canRedo,onClick:Or,children:t(T?.redo??Ve)}),v(`span`,{className:d.roomDrawerToolbarSeparator})]}),en&&y(at,{children:[v(`button`,{type:`button`,className:_(d.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.download??`Download plan`,"aria-label":w?.download??`Download plan`,onClick:()=>Rr(),children:t(T?.download??Ge)}),q&&v(`button`,{type:`button`,className:_(d.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.upload??`Open a plan file`,"aria-label":w?.upload??`Open a plan file`,onClick:()=>ar.current?.click(),children:t(T?.upload??rt)}),v(`span`,{className:d.roomDrawerToolbarSeparator})]}),y(`div`,{className:_(d.roomDrawerViewControls,E?.viewControls),style:D?.viewControls,children:[v(`button`,{type:`button`,className:_(d.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.zoomOut??`Zoom out`,"aria-label":w?.zoomOut??`Zoom out`,onClick:()=>Er(1/1.25),children:t(T?.zoomOut??Xe)}),y(`button`,{type:`button`,className:_(d.roomDrawerZoomLabel,E?.zoomLabel),style:D?.zoomLabel,title:w?.fit??`Fit to content`,onClick:()=>fr(),children:[Math.round(B.zoom*1e3)/10,`%`]}),v(`button`,{type:`button`,className:_(d.roomDrawerViewButton,E?.viewButton),style:D?.viewButton,title:w?.zoomIn??`Zoom in`,"aria-label":w?.zoomIn??`Zoom in`,onClick:()=>Er(1.25),children:t(T?.zoomIn??Ze)})]})]}),St&&j.floors.length>0&&y(`div`,{className:_(d.roomDrawerFloorBar,E?.floorBar),style:D?.floorBar,role:`tablist`,"aria-label":w?.selectedFloor??`Floor`,children:[[...j.floors].reverse().map(e=>v(`button`,{type:`button`,role:`tab`,className:_(d.roomDrawerFloorTab,e.id===M.id&&d.roomDrawerFloorTabActive,E?.floorTab),style:D?.floorTab,"aria-selected":e.id===M.id,onClick:()=>N(e.id),children:e.label},e.id)),q&&v(`button`,{type:`button`,className:_(d.roomDrawerFloorTab,d.roomDrawerFloorTabAdd),title:w?.addFloor??`Add a floor above`,"aria-label":w?.addFloor??`Add a floor above`,onClick:()=>Mr(),children:t(T?.addFloor??$e)})]}),v(`div`,{ref:_n,className:_(d.roomDrawerCanvasWrapper,q&&F!==`select`&&d.roomDrawerCanvasWrapperDrawing,E?.canvasWrapper),style:{height:cn,...D?.canvasWrapper},onPointerDown:Sr,onPointerMove:Cr,onPointerUp:e=>wr(e,!1),onPointerCancel:e=>wr(e,!0),children:v(Ne,{ref:vn,floor:M,underlay:jn,rooms:P,view:B,size:H,selection:I,hovered:Bn,interactiveRooms:!1,showGrid:Zn,gridSize:S,showRoomLabels:!0,formatArea:Yt,getRoomColor:ln,renderRoomLabel:un,overlay:Ur,classNames:E,styles:D})}),Zt&&q&&y(`div`,{className:_(d.roomDrawerInspector,E?.inspector),style:D?.inspector,children:[v(`span`,{className:_(d.roomDrawerInspectorKind,I.length===0&&d.roomDrawerInspectorKindEmpty,E?.inspectorLabel),children:Kr}),I.length===0&&y(at,{children:[v(i,{className:_(d.roomDrawerInspectorName,E?.inspectorField),style:D?.inspectorField,label:w?.floorName??`Floor name`,value:M.label,onChange:e=>Lr(M.id,e)}),v(Me,{className:_(d.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:M.height,decimalScale:0,min:500,step:100,showArrows:!0,onChange:e=>{e!==void 0&&Ir(M.id,e)}}),j.floors.length>1&&y(at,{children:[v(`button`,{type:`button`,className:_(d.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,title:w?.moveFloorUp??`Move this floor up`,"aria-label":w?.moveFloorUp??`Move this floor up`,disabled:he(j,M.id)>=j.floors.length-1,onClick:()=>Fr(M.id,he(j,M.id)+1),children:t(T?.moveFloorUp??Re)}),v(`button`,{type:`button`,className:_(d.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,title:w?.moveFloorDown??`Move this floor down`,"aria-label":w?.moveFloorDown??`Move this floor down`,disabled:he(j,M.id)<=0,onClick:()=>Fr(M.id,he(j,M.id)-1),children:t(T?.moveFloorDown??Le)})]}),v(`button`,{type:`button`,className:_(d.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,title:w?.duplicateFloor??`Copy this floor to a new one above`,onClick:()=>Nr(),children:t(T?.duplicateFloor??Ue)}),j.floors.length>1&&v(n,{className:d.roomDrawerInspectorDelete,icon:T?.delete??nt,title:w?.deleteFloor??`Delete this floor`,onClick:()=>Pr()})]}),hr?.meta&&y(at,{children:[v(i,{className:_(d.roomDrawerInspectorName,E?.inspectorField),style:D?.inspectorField,label:w?.roomName??`Room name`,value:hr.meta.name,onChange:e=>{let t=hr.meta;X({...M,rooms:{...M.rooms,[t.id]:{...t,name:e}}},`edit-room`,[t.id])}}),v(`span`,{className:_(d.roomDrawerInspectorLabel,E?.inspectorLabel),children:Yt(hr.area)})]}),Z&&v(`button`,{type:`button`,className:_(d.roomDrawerInspectorAction,E?.inspectorField),style:D?.inspectorField,onClick:vr,title:w?.addCorner??`Add a corner to this wall`,children:w?.addCorner??`Add corner`}),Z&&v(Me,{className:_(d.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({...M,walls:{...M.walls,[Z.id]:{...Z,thickness:e}}},`edit-wall`,[Z.id])}}),gr&&y(at,{children:[v(Me,{className:_(d.roomDrawerInspectorField,E?.inspectorField),style:D?.inspectorField,label:w?.width??`Width (mm)`,value:gr.width,decimalScale:0,min:100,step:50,showArrows:!0,onChange:e=>{e!==void 0&&X(le(M,gr.id,{width:e}).floor,`edit-opening`,[gr.id])}}),v(Me,{className:_(d.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:gr.sill,decimalScale:0,min:0,step:50,onChange:e=>{e!==void 0&&X(le(M,gr.id,{sill:e}).floor,`edit-opening`,[gr.id])}})]}),I.length>0&&v(n,{className:d.roomDrawerInspectorDelete,icon:T?.delete??nt,title:w?.deleteSelection??`Delete selection`,onClick:br})]}),en&&q&&v(`input`,{ref:ar,type:`file`,accept:`application/json,.json`,className:d.roomDrawerFileInput,tabIndex:-1,"aria-hidden":`true`,onChange:e=>{let t=e.target.files?.[0];e.target.value=``,t&&Br(t)}}),Qt&&(sr!==null||Gr)&&v(`div`,{className:_(d.roomDrawerHint,sr!==null&&d.roomDrawerHintReport,E?.hint),style:D?.hint,role:sr===null?void 0:`status`,children:sr===null?Gr:sr.length===0?w?.importFailed??`That file could not be read as a floor plan`:sr.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 te,detachWall as ne,dissolveNode as re,mergeNodes as ie,moveNode as ae,removeOpening as oe,removeWall as se,splitWall as ce,updateOpening as le,weldShortWalls as ue}from"../floorPlan/floorPlan.graph.mjs";import{addFloor as de,duplicateFloor as fe,emptyFloorPlan as pe,floorBelow as me,floorBounds as he,floorIndex as ge,getFloor as _e,moveFloor as ve,removeFloor as ye,renameFloor as be,setFloor as xe,setFloorHeight as Se}from"../floorPlan/floorPlan.plan.mjs";import{commitDerivation as Ce,derivePlan as we}from"../floorPlan/floorPlan.rooms.mjs";import{HIT_PX as Te,HIT_PX_COARSE as Ee,hitTest as De,selectionsEqual as Oe,worldTolerances as u}from"../floorPlan/floorPlan.hit.mjs";import{SnapKind as d,clientToWorld as ke,resolveSnap as Ae}from"../floorPlan/floorPlan.snap.mjs";import{planFromJson as je,planToJson as Me}from"../floorPlan/floorPlan.json.mjs";import Ne from"../numberInput/index.mjs";import Pe from"../planCanvas/planCanvas.mjs";import{usePlanHistory as Fe}from"./usePlanHistory.mjs";import f from"./roomDrawer.module.mjs";import{forwardRef as Ie,useCallback as p,useEffect as Le,useImperativeHandle as Re,useMemo as ze,useRef as m,useState as h}from"react";import g from"classnames";import{faAngleDown as Be,faAngleUp as Ve,faArrowPointer as He,faArrowRotateLeft as Ue,faArrowRotateRight as We,faBorderAll as Ge,faClone as Ke,faDoorOpen as qe,faDownload as Je,faDraftingCompass as Ye,faExpand as Xe,faLayerGroup as Ze,faMagnet as Qe,faMagnifyingGlassMinus as $e,faMagnifyingGlassPlus as et,faMinus as tt,faPlus as nt,faRulerCombined as rt,faSquare as it,faTrash as at,faUpload as ot,faWindowMaximize as st}from"@fortawesome/free-solid-svg-icons";import{Fragment as ct,jsx as _,jsxs as v}from"react/jsx-runtime";var lt=[`select`,`wall`,`rect`,`door`,`window`,`archway`,`measure`],ut={v:`select`,w:`wall`,r:`rect`,d:`door`,n:`window`,a:`archway`,m:`measure`},dt={door:a.Door,window:a.Window,archway:a.Archway},ft={[a.Door]:`Door`,[a.Window]:`Window`,[a.Archway]:`Archway`,[a.Gap]:`Gap`},pt={[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}},mt=1,ht=4,gt=[];function _t(e){return e>=1e3?`${(e/1e3).toFixed(2)} m`:`${Math.round(e)} mm`}function vt(e){let t=e/1e6;return`${t.toFixed(+(t<10))} m²`}function yt(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 y=Ie(function(a,Ie){let{value:y,defaultValue:bt,onChange:b,onChangeEnd:xt,floorId:St,defaultFloorId:Ct,onFloorChange:wt,showFloorBar:Tt=!0,showUnderlay:Et=!0,tool:Dt,defaultTool:Ot=`select`,onToolChange:kt,tools:At=lt,selection:jt,defaultSelection:Mt,onSelectionChange:Nt,multiSelect:Pt=!0,onHoverChange:Ft,view:It,defaultView:Lt,onViewChange:Rt,minZoom:zt=.005,maxZoom:Bt=2,fitOnMount:Vt=!0,gridSize:x=100,showGrid:Ht=!0,snap:Ut=!0,angleLock:Wt=!1,constrainAngle:Gt=45,showSnapGuides:Kt=!0,wallThickness:qt=c.thickness,wallHeight:Jt,openingDefaults:Yt,showMeasurements:Xt=!0,formatLength:Zt=_t,formatArea:Qt=vt,showToolbar:$t=!0,showInspector:en=!0,showHint:tn=!0,showHistoryControls:nn=!0,showFileControls:rn=!0,fileName:an,onImport:on,historyMode:sn=`internal`,historyLimit:cn=50,onHistoryChange:ln,readOnly:un=!1,disabled:S=!1,canvasHeight:dn=`420px`,getRoomColor:fn,renderRoomLabel:pn,labels:C,icons:w,"aria-label":mn,className:hn,style:gn,classNames:T,styles:E,..._n}=e(`RoomDrawer`,a),vn=r(),D=vn?Ee:Te,yn=m(null),bn=m(null),xn=m(null),Sn=m(null),O=m({kind:`none`}),k=m(new Map),A=m(null),Cn=m(!1),wn=m(!1),Tn=m(!1),j=Fe(ze(()=>bt??y??pe(),[]),cn),En=y!==void 0,M=En?y:j.present;Le(()=>{if(!(!En||!y)){if(y===Sn.current){j.replace(y);return}j.commit(y,`external`)}},[y,En]);let[Dn,On]=h(Ct),kn=St??Dn??M.floors[0]?.id,N=ze(()=>_e(M,kn)??_e(M)??pe().floors[0],[M,kn]),[An,jn]=h(Et);Le(()=>jn(Et),[Et]);let Mn=ze(()=>An?me(M,N.id):null,[An,M,N.id]),Nn=p(e=>{e!==N.id&&(St===void 0&&On(e),wt?.(e))},[N.id,St,wt]),P=ze(()=>we(N),[N]).rooms,[Pn,Fn]=h(Ot),F=Dt??Pn,In=p(e=>{Dt===void 0&&Fn(e),kt?.(e)},[Dt,kt]),[Ln,Rn]=h(Mt??gt),I=jt===void 0?Ln:jt,L=m(I);L.current=I;let R=p(e=>{let t=e===null?gt:Array.isArray(e)?e:[e];L.current=t,jt===void 0&&Rn(t),Nt?.([...t])},[jt,Nt]),zn=p(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,Bn=p(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]),Vn=ze(()=>Bn(I),[Bn,I]),[Hn,Un]=h(null),[Wn,Gn]=h(Lt??{x:0,y:0,zoom:.05}),B=It??Wn,V=p(e=>{It===void 0&&Gn(e),Rt?.(e)},[It,Rt]),[H,Kn]=h({width:800,height:420}),[U,qn]=h([]),[W,Jn]=h(null),[Yn,Xn]=h(Ut),[Zn,Qn]=h(Wt);Le(()=>Xn(Ut),[Ut]),Le(()=>Qn(Wt),[Wt]);let[$n,er]=h(Ht);Le(()=>er(Ht),[Ht]);let tr=m(null),[G,nr]=h(null),[K,rr]=h([]),ir=m(0),[ar,or]=h(null),sr=m(null),cr=p(e=>{let t=u(D,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,D,B.zoom]),[lr,ur]=h(null),q=!un&&!S,dr=ze(()=>{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]);Le(()=>{let e=bn.current;if(!e)return;let t=new ResizeObserver(()=>{let t=e.getBoundingClientRect();t.width>0&&t.height>0&&Kn({width:Math.round(t.width),height:Math.round(t.height)})});t.observe(e);let n=e.getBoundingClientRect();return n.width>0&&n.height>0&&Kn({width:Math.round(n.width),height:Math.round(n.height)}),()=>t.disconnect()},[]);let fr=p((e,t)=>ke(e,t,bn.current?.getBoundingClientRect()??{left:0,top:0},B),[B]),J=p(e=>({x:(e.x-B.x)*B.zoom,y:(e.y-B.y)*B.zoom}),[B]),Y=p((e,t,n,r,i)=>{let a=Yn!==wn.current,o=Zn!==Tn.current,s=Ae(e,{floor:N,pxToWorld:B.zoom>0?1/B.zoom:1,origin:t,referenceAngle:r,excludeNodeIds:n,excludeWallIds:i,options:{enabled:a?[d.Node,d.Intersection,d.Wall,d.Angle,d.Extension,d.Alignment,d.Grid]:[],gridSize:x,angleStepDeg:o?Gt:0,toleranceScreenPx:vn?16:10}});return tr.current=s,s},[N,B.zoom,Yn,Zn,x,Gt,vn]),pr=p(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]),mr=p((e={})=>{let t=e.padding??24,n=he(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(zt,Math.min(Bt,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,zt,Bt,V]),hr=m(!1);Le(()=>{!Vt||hr.current||Object.keys(N.nodes).length!==0&&(H.width<=1||(hr.current=!0,mr()))},[Vt,N,H.width,mr]);let gr=p((e,t,n,r=[],i={})=>{if(e===N)return M;let a=xe(M,e);Sn.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 b?.(a,o),n&&xt?.(a,o),a},[N,M,j,b,xt]),X=p((e,t,n=[],r={})=>{let i=Ce(ue(e).floor).floor;return gr(i,t,!0,n,r)},[gr]);Le(()=>{ln?.({canUndo:j.canUndo,canRedo:j.canRedo})},[j.canUndo,j.canRedo,ln]);let _r=ze(()=>z?.type===`room`?P.find(e=>e.roomId===z.id)??null:null,[z,P]),Z=z?.type===`wall`?N.walls[z.id]:void 0,vr=z?.type===`opening`?N.openings[z.id]:void 0,yr=ze(()=>{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]),br=p(()=>{if(!q||!Z)return;let e=ce(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]),xr=p((e,t,n=new Set)=>{if(e.type===`wall`)return{floor:se(t,e.id).floor};if(e.type===`opening`)return{floor:oe(t,e.id).floor};if(e.type===`node`){let n=re(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=se(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=se(a,e,{dissolveCollinear:!1}).floor);let o={...a.rooms};return delete o[e.id],{floor:{...a,rooms:o}}},[P]),Sr=p(()=>{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=xr(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,xr,X,R]),Cr=p(()=>{qn([])},[]),wr=p(e=>{if(S)return;if(yn.current?.focus(),ur(null),k.current.set(e.pointerId,{x:e.clientX,y:e.clientY}),e.currentTarget.setPointerCapture?.(e.pointerId),k.current.size===2){let[e,t]=[...k.current.values()];O.current.kind!==`none`&&O.current.kind!==`pan`&&j.cancelGesture(),O.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(k.current.size>2)return;if(A.current={client:{x:e.clientX,y:e.clientY},moved:!1},e.button===1||Cn.current){O.current={kind:`pan`,startClient:{x:e.clientX,y:e.clientY},startView:B};return}if(e.button!==0)return;let t=fr(e.clientX,e.clientY);if(!q){R(De(N,P,t,u(D,B.zoom)));return}if(F===`rect`){let e=Y(t).point;O.current={kind:`rect`,start:e,current:e},j.beginGesture();return}if(F===`measure`){let e=cr(t);if(e){let n=K.find(t=>t.id===e.id);O.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;O.current={kind:`measure`,start:n,current:n};return}if(F===`wall`){let e=U[U.length-1],n=Y(t,e,void 0,dr).point;if(U.length===0){qn([n]);return}let r=U[U.length-1],i=te(N,r,n,{thickness:qt,type:o.Interior,height:Jt},u(D,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)<u(D,B.zoom).node?Cr():qn(e=>[...e,n]);return}let n=dt[F];if(n){let e=De(N,P,t,u(D,B.zoom),{accept:[`wall`]});if(e?.type!==`wall`)return;let r=N.walls[e.id],i=N.nodes[r.a],a=N.nodes[r.b],o=Math.hypot(a.x-i.x,a.y-i.y),s=((t.x-i.x)*(a.x-i.x)+(t.y-i.y)*(a.y-i.y))/(o*o||1),c={...pt[n],...Yt?.[n]},ee=l(N,{wallId:r.id,kind:n,offset:Math.min(Math.max(s,0),1)*o,width:c.width,sill:c.sill,head:c.head});ee.result.openingId&&(X(ee.floor,`add-opening`,[ee.result.openingId]),R({type:`opening`,id:ee.result.openingId}));return}let r=u(D,B.zoom);if(yr&&z?.type===`wall`&&Math.hypot(t.x-yr.x,t.y-yr.y)<=r.node){j.beginGesture(),O.current={kind:`wallSplit`,wallId:z.id,at:yr};return}let i=De(N,P,t,r),a=Pt&&(e.ctrlKey||e.metaKey);if(!i){a||R(null),O.current=Pt?{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(),O.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){zn(i),O.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=[...Bn(L.current)],n={};for(let t of e){let e=N.nodes[t];e&&(n[t]={x:e.x,y:e.y})}O.current={kind:`room`,nodeIds:e,startWorld:t,orig:n,moved:!1};return}if(i.type===`node`)O.current={kind:`node`,nodeId:i.id,moved:!1,...pr(i.id)};else if(i.type===`wall`){let e=N.walls[i.id];O.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`)O.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})}O.current={kind:`room`,nodeIds:n,startWorld:t,orig:r,moved:!1}}},[S,q,B,F,N,P,D,fr,Y,U,qt,Jt,Yt,X,R,yr,z,dr,pr,Bn,Pt,zn,j,Cr,cr,K]),Tr=p(e=>{if(S)return;k.current.has(e.pointerId)&&k.current.set(e.pointerId,{x:e.clientX,y:e.clientY});let t=O.current;if(t.kind===`pinch`&&k.current.size>=2){let[e,n]=[...k.current.values()],r=Math.hypot(n.x-e.x,n.y-e.y);if(t.startDist<=0)return;let i=Math.max(zt,Math.min(Bt,t.startView.zoom*(r/t.startDist))),a=bn.current?.getBoundingClientRect()??{left:0,top:0},o={x:(e.x+n.x)/2,y:(e.y+n.y)/2},s=ke(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(A.current){let t=e.clientX-A.current.client.x,n=e.clientY-A.current.client.y;Math.hypot(t,n)>ht&&(A.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=fr(e.clientX,e.clientY);if(Jn(n),t.kind===`none`){if(!q)return;if(F===`wall`&&U.length>0){let e=Y(n,U[U.length-1],void 0,dr);Jn(e.point),nr(e);return}if(F===`select`){let e=De(N,P,n,u(D,B.zoom));Oe(e,Hn)||(Un(e),Ft?.(e))}F===`measure`&&or(cr(n)?.id??null);return}if(A.current?.moved){if(t.kind===`measureEnd`){let e=Y(n).point;rr(n=>n.map(n=>n.id===t.id?{...n,[t.end]:e}:n)),Jn(e);return}if(t.kind===`measureMove`){let e=n.x-t.startWorld.x,r=n.y-t.startWorld.y;rr(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`){O.current={...t,current:Y(n).point},Jn(Y(n).point);return}if(t.kind===`marquee`){O.current={...t,current:n},Jn(n);return}if(t.kind===`wallSplit`){let e=ce(N,t.wallId,t.at);if(!e.result.wallIds){O.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;O.current={kind:`node`,nodeId:r,moved:!0,...s},R({type:`node`,id:r}),nr(tr.current),gr(ae(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;nr(tr.current),O.current={...t,moved:!0},gr(ae(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=Ut!==wn.current&&x>0?x:1,l=Math.round(s/c)*c,ee=Math.max(c,10);if(t.detach){if(Math.abs(l)<ee)return;let e=ne(N,t.wallId,{x:o.x*l,y:o.y*l});if(!e.result)return;O.current={...t,detach:!1,toggle:!1,detachedSign:Math.sign(l),moved:!0},R({type:`wall`,id:t.wallId}),gr(e.floor,`move-wall`,!1,[t.wallId]);return}let te=ae(N,e.a,{x:t.origA.x+o.x*l,y:t.origA.y+o.y*l}).floor;te=ae(te,e.b,{x:t.origB.x+o.x*l,y:t.origB.y+o.y*l}).floor,t.detachedSign&&Math.abs(l)<10?(te=ue(te).floor,O.current={...t,detachedSign:void 0,moved:!0}):O.current={...t,moved:!0},gr(te,`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);O.current={...t,moved:!0},gr(le(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=Ut!==wn.current&&x>0?x: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=ae(s,e,{x:n.x+a,y:n.y+o}).floor)}O.current={...t,moved:!0},gr(s,`move-room`,!1,t.nodeIds)}}},[S,q,F,N,P,Hn,D,B.zoom,zt,Bt,x,Ut,fr,Y,gr,V,R,U,dr,Ft,cr]),Er=p((e,t)=>{k.current.delete(e.pointerId);let n=O.current;O.current={kind:`none`};let r=A.current?.moved??!1;if(A.current=null,nr(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&&b?.(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>mt&&(ir.current+=1,rr(e=>[...e,{id:ir.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:qt,type:o.Interior,height:Jt},u(D,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&&zn({type:`wall`,id:n.wallId});return}if(n.kind===`node`){let e=N.nodes[n.nodeId];if(e){let t=u(D,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(ie(N,r.id,n.nodeId).floor,`move-node`,[r.id],{push:!e}),R({type:`node`,id:r.id});return}}}let i=j.endGesture();X(N,n.kind===`wall`?`move-wall`:n.kind===`opening`?`move-opening`:n.kind===`room`?`move-room`:`move-node`,[],{push:!i})},[N,j,D,B.zoom,qt,Jt,X,R,zn,b]);Le(()=>{let e=bn.current;if(!e||S)return;function t(t){t.preventDefault();let n=e.getBoundingClientRect(),r=Math.exp(-t.deltaY*.002);V((()=>{let e=Dr.current,i=Math.max(zt,Math.min(Bt,e.zoom*r)),a=ke(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)},[S,zt,Bt,V]);let Dr=m(B);Dr.current=B;let Or=p(e=>{let t=Math.max(zt,Math.min(Bt,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,zt,Bt,V]),kr=p(()=>{if(sn===`none`)return;let e=j.undo();e&&(Sn.current=e,b?.(e,{reason:`undo`,committed:!0,targetIds:[]}),xt?.(e,{reason:`undo`,committed:!0,targetIds:[]}))},[sn,j,b,xt]),Ar=p(()=>{if(sn===`none`)return;let e=j.redo();e&&(Sn.current=e,b?.(e,{reason:`redo`,committed:!0,targetIds:[]}),xt?.(e,{reason:`redo`,committed:!0,targetIds:[]}))},[sn,j,b,xt]),jr=p(()=>{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]),Mr=p((e,t)=>{if(!q||Vn.size===0)return;let n=x>0?x:100,r=Tn.current?n*10:n,i=N;for(let n of Vn){let a=i.nodes[n];a&&(i=ae(i,n,{x:a.x+e*r,y:a.y+t*r}).floor)}X(i,`nudge`,[...Vn])},[q,Vn,N,x,X]),Nr=p(e=>{if(S)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?Ar():kr();return}if(n&&e.key.toLowerCase()===`a`){e.preventDefault(),Pt&&jr();return}if(n&&e.key.toLowerCase()===`y`){e.preventDefault(),Ar();return}if(e.key===`Escape`){U.length>0?Cr():K.length>0?rr([]):R(null);return}if(e.key===`Enter`&&F===`wall`){Cr();return}if(e.key===`Delete`||e.key===`Backspace`){if(e.preventDefault(),F===`measure`){ar!==null&&(rr(e=>e.filter(e=>e.id!==ar)),or(null));return}Sr();return}if(e.key===`+`||e.key===`=`){Or(1.25);return}if(e.key===`-`){Or(1/1.25);return}if(e.key===`0`){mr();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&&Mr(t[0],t[1]);return}let r=e.key.toLowerCase();if(r===`s`){Xn(e=>!e);return}if(r===`l`){Qn(e=>!e);return}if(r===`g`){er(e=>!e);return}let i=ut[e.key.toLowerCase()];i&&q&&At.includes(i)&&(In(i),Cr())},[S,q,At,F,U,K.length,ar,Ar,kr,R,Cr,Sr,Or,mr,Mr,In,Pt,jr]),Q=p((e,t,n)=>{Sn.current=e,n?.resetHistory?(j.clearHistory(),j.replace(e)):j.commit(e,t);let r={reason:t,committed:!0,targetIds:[]};b?.(e,r),xt?.(e,r)},[j,b,xt]),Pr=p((e={})=>{let{plan:t,floor:n}=de(M,{...e,index:ge(M,N.id)+1});return Q(t,`add-floor`),Nn(n.id),n.id},[M,N.id,Q,Nn]),Fr=p(()=>{let{plan:e,floor:t}=fe(M,N.id);return t?(Q(e,`duplicate-floor`),Nn(t.id),t.id):null},[M,N.id,Q,Nn]),Ir=p(e=>{let t=e??N.id,n=ye(M,t);if(n!==M&&(Q(n,`remove-floor`),t===N.id)){let e=ge(M,t);Nn(n.floors[Math.max(0,e-1)].id)}},[M,N.id,Q,Nn]),Lr=p((e,t)=>{let n=ve(M,e,t);n!==M&&Q(n,`move-floor`)},[M,Q]),Rr=p((e,t)=>{let n=Se(M,e,t);n!==M&&Q(n,`edit-floor`)},[M,Q]),zr=p((e,t)=>{let n=be(M,e,t);n!==M&&Q(n,`rename-floor`)},[M,Q]),Br=p(e=>{let t=(e??an??M.name??``).trim()||`floor-plan`,n=URL.createObjectURL(new Blob([Me(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)},[an,M]),Vr=p(e=>{let t=je(e);return t.plan&&Q(t.plan,`import`),ur(t.plan&&t.issues.length===0?null:t.issues),on?.(t),t},[on,Q]),Hr=p(e=>{e.text().then(e=>Vr(e)).catch(e=>{let t=[`Could not read that file: ${e.message}`];ur(t),on?.({plan:null,issues:t})})},[Vr,on]),Ur=p(()=>rr([]),[]),Wr=p(e=>{e.key===`Shift`&&(Tn.current=!1),e.key===`Alt`&&(wn.current=!1),e.key===` `&&(Cn.current=!1)},[]);Re(Ie,()=>({getPlan:()=>M,setPlan:(e,t)=>Q(e,`import`,t),clear:()=>Q(pe(),`clear`),getFloorId:()=>N.id,setFloorId:Nn,addFloor:e=>Pr(e),duplicateFloor:Fr,removeFloor:Ir,renameFloor:zr,moveFloor:Lr,setFloorHeight:Rr,clearMeasurements:Ur,download:Br,loadJson:Vr,undo:kr,redo:Ar,canUndo:()=>sn!==`none`&&j.canUndo,canRedo:()=>sn!==`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:zn,selectAll:jr,deleteSelection:Sr,getView:()=>B,setView:V,zoomBy:Or,fitToContent:mr,toWorld:fr,toScreen:J,getSvgElement:()=>xn.current}),[M,j,Q,N,Nn,Pr,Fr,Ir,zr,Lr,Rr,Ur,Br,Vr,kr,Ar,sn,R,zn,jr,Sr,B,V,Or,mr,fr,J]);let $=O.current,Gr=ze(()=>{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<mt)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(v(`g`,{className:g(f.roomDrawerMeasureLine,ar===n.id&&f.roomDrawerMeasureLineHovered,T?.measureLine),children:[_(`line`,{x1:t.x,y1:t.y,x2:r.x,y2:r.y}),_(`line`,{x1:t.x-o,y1:t.y-s,x2:t.x+o,y2:t.y+s}),_(`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(_(`circle`,{className:f.roomDrawerMeasureGrip,cx:a.x,cy:a.y,r:4},`measure-grip-${n.id}-${i}`));e.push(_(`text`,{className:g(f.roomDrawerMeasure,T?.measureLine),x:c.x,y:c.y-8,textAnchor:`middle`,children:`${Zt(i)} · ${yt(a)}`},`measure-label-${n.id}`))}if(Kt&&G&&(G.guides.forEach((t,n)=>{let r=J(t.a),i=J(t.b);e.push(_(`line`,{className:g(f.roomDrawerGuide,t.kind===d.Angle&&f.roomDrawerGuideAngle),x1:r.x,y1:r.y,x2:i.x,y2:i.y},`guide-${n}`))}),G.kind!==d.None&&G.kind!==d.Grid)){let t=J(G.point);e.push(_(`rect`,{className:f.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(_(`rect`,{className:f.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);Xt&&(s>0||c>0)&&(e.push(_(`text`,{className:f.roomDrawerMeasure,x:(r+a)/2,y:i-8,textAnchor:`middle`,children:Zt(s)},`rect-width`),_(`text`,{className:f.roomDrawerMeasure,x:r-8,y:(i+o)/2,textAnchor:`end`,dominantBaseline:`central`,children:Zt(c)},`rect-height`)),s>0&&c>0&&e.push(_(`text`,{className:g(f.roomDrawerMeasure,f.roomDrawerMeasureSecondary),x:(r+a)/2,y:(i+o)/2,textAnchor:`middle`,dominantBaseline:`central`,children:Qt(s*c)},`rect-area`)))}if(F===`wall`&&U.length>0){let t=[...U,W].filter(Boolean).map(J);if(e.push(_(`polyline`,{className:f.roomDrawerPreview,points:t.map(e=>`${e.x},${e.y}`).join(` `),fill:`none`},`chain`)),t.forEach((t,n)=>{e.push(_(`circle`,{className:f.roomDrawerHandle,cx:t.x,cy:t.y,r:4},`chain-dot-${n}`))}),Xt&&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===d.Angle;e.push(_(`text`,{className:g(f.roomDrawerMeasure,i&&f.roomDrawerMeasureLocked),x:r.x,y:r.y-8,textAnchor:`middle`,children:`${Zt(n)} · ${yt(G?.angleRelativeTo===`reference`&&dr!==void 0?Math.atan2(W.y-t.y,W.x-t.x)-dr: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 Vn){let r=N.nodes[t];if(!r)continue;let i=J(r);e.push(_(`circle`,{className:g(f.roomDrawerHandle,n.has(t)&&f.roomDrawerHandleActive),cx:i.x,cy:i.y,r:5},`handle-${t}`))}if($.kind===`marquee`&&A.current?.moved){let t=J($.start),n=J($.current);e.push(_(`rect`,{className:f.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(yr&&$.kind!==`node`){let t=J(yr);e.push(_(`circle`,{className:f.roomDrawerMidHandle,cx:t.x,cy:t.y,r:4},`midpoint`))}if(Xt&&$.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(_(`text`,{className:g(f.roomDrawerMeasure,f.roomDrawerMeasureOffset),x:s.x,y:s.y-26,textAnchor:`middle`,children:`${Zt(Math.hypot(i,a))} · ${yt(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(_(`text`,{className:g(f.roomDrawerMeasure,f.roomDrawerMeasureSecondary),x:s.x,y:s.y-8,textAnchor:`middle`,children:`${Zt(Math.hypot(o.x-a.x,o.y-a.y))} · ${yt(Math.atan2(o.y-a.y,o.x-a.x))}`},`room-stretch-${n.id}`))}}if(Xt&&(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===d.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(_(`text`,{className:g(f.roomDrawerMeasure,!a&&f.roomDrawerMeasureSecondary,a&&i&&f.roomDrawerMeasureLocked),x:l.x,y:l.y-8,textAnchor:`middle`,children:`${Zt(Math.hypot(c.x-s.x,c.y-s.y))} · ${yt(Math.atan2(c.y-s.y,c.x-s.x))}`},`measure-${n.id}`))}}return _(ct,{children:e})},[q,$,F,U,W,I,N,P,z,Vn,yr,Xt,Kt,G,dr,Zt,Qt,K,ar,T?.measureLine,J]),Kr={select:{icon:He,label:C?.select??`Select and edit`,key:`V`},wall:{icon:tt,label:C?.wall??`Draw walls`,key:`W`},rect:{icon:it,label:C?.rect??`Draw a room`,key:`R`},door:{icon:qe,label:C?.door??`Add a door`,key:`D`},window:{icon:st,label:C?.window??`Add a window`,key:`N`},archway:{icon:Xe,label:C?.archway??`Add an archway`,key:`A`},measure:{icon:rt,label:C?.measure??`Measure`,key:`M`}},qr=q?F===`wall`?C?.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`?C?.hintRect??`Drag to draw a room`:F===`measure`?C?.hintMeasure??`Drag to measure · Drag an end or the line to adjust it · Delete removes one, Escape clears them`:dt[F]?C?.hintOpening??`Click a wall to cut an opening into it`:C?.hintSelect??(Pt?`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`):``,Jr=I.length===0?C?.selectedFloor??`Floor`:I.length>1?(C?.selectedCount??`{count} selected`).replace(`{count}`,String(I.length)):vr?C?.selectedOpening??ft[vr.kind]:Z?C?.selectedWall??`Wall`:z?.type===`room`?C?.selectedRoom??`Room`:C?.selectedCorner??`Corner`,Yr=q?At:[];return v(`div`,{..._n,ref:yn,className:g(f.roomDrawer,S&&f.roomDrawerDisabled,hn,T?.root),style:{...gn,...E?.root},role:`application`,"aria-label":mn??`Floor plan editor`,tabIndex:S?-1:0,onKeyDown:Nr,onKeyUp:Wr,children:[$t&&v(`div`,{className:g(f.roomDrawerToolbar,T?.toolbar),style:E?.toolbar,role:`toolbar`,"aria-label":`Drawing tools`,children:[Yr.map(e=>{let n=Kr[e];return _(`button`,{type:`button`,className:g(f.roomDrawerToolButton,e===F&&f.roomDrawerToolButtonActive,T?.toolButton),style:E?.toolButton,title:`${n.label} (${n.key})`,"aria-label":n.label,"aria-pressed":e===F,onClick:()=>{In(e),Cr()},children:t(w?.[e]??n.icon,{className:g(f.roomDrawerToolIcon,T?.toolIcon),style:E?.toolIcon})},e)}),Yr.length>0&&_(`span`,{className:f.roomDrawerToolbarSeparator}),q&&v(ct,{children:[[{on:Yn,toggle:()=>Xn(e=>!e),icon:w?.snap??Qe,label:C?.snap??`Snap to grid and geometry`,key:`S`},{on:Zn,toggle:()=>Qn(e=>!e),icon:w?.angleLock??Ye,label:C?.angleLock??`Lock to ${Gt}° angles`,key:`L`},{on:$n,toggle:()=>er(e=>!e),icon:w?.grid??Ge,label:C?.grid??`Show grid`,key:`G`},...me(M,N.id)?[{on:An,toggle:()=>jn(e=>!e),icon:w?.underlay??Ze,label:C?.underlay??`Show the floor below`,key:`B`}]:[]].map(e=>_(`button`,{type:`button`,className:g(f.roomDrawerToolButton,e.on&&f.roomDrawerToolButtonOn,T?.toolButton),style:E?.toolButton,title:`${e.label} (${e.key})`,"aria-label":e.label,"aria-pressed":e.on,onClick:e.toggle,children:t(e.icon,{className:g(f.roomDrawerToolIcon,T?.toolIcon),style:E?.toolIcon})},e.key)),_(`span`,{className:f.roomDrawerToolbarSeparator})]}),nn&&sn!==`none`&&q&&v(ct,{children:[_(`button`,{type:`button`,className:g(f.roomDrawerViewButton,T?.viewButton),style:E?.viewButton,title:C?.undo??`Undo`,"aria-label":C?.undo??`Undo`,disabled:!j.canUndo,onClick:kr,children:t(w?.undo??Ue)}),_(`button`,{type:`button`,className:g(f.roomDrawerViewButton,T?.viewButton),style:E?.viewButton,title:C?.redo??`Redo`,"aria-label":C?.redo??`Redo`,disabled:!j.canRedo,onClick:Ar,children:t(w?.redo??We)}),_(`span`,{className:f.roomDrawerToolbarSeparator})]}),rn&&v(ct,{children:[_(`button`,{type:`button`,className:g(f.roomDrawerViewButton,T?.viewButton),style:E?.viewButton,title:C?.download??`Download plan`,"aria-label":C?.download??`Download plan`,onClick:()=>Br(),children:t(w?.download??Je)}),q&&_(`button`,{type:`button`,className:g(f.roomDrawerViewButton,T?.viewButton),style:E?.viewButton,title:C?.upload??`Open a plan file`,"aria-label":C?.upload??`Open a plan file`,onClick:()=>sr.current?.click(),children:t(w?.upload??ot)}),_(`span`,{className:f.roomDrawerToolbarSeparator})]}),v(`div`,{className:g(f.roomDrawerViewControls,T?.viewControls),style:E?.viewControls,children:[_(`button`,{type:`button`,className:g(f.roomDrawerViewButton,T?.viewButton),style:E?.viewButton,title:C?.zoomOut??`Zoom out`,"aria-label":C?.zoomOut??`Zoom out`,onClick:()=>Or(1/1.25),children:t(w?.zoomOut??$e)}),v(`button`,{type:`button`,className:g(f.roomDrawerZoomLabel,T?.zoomLabel),style:E?.zoomLabel,title:C?.fit??`Fit to content`,onClick:()=>mr(),children:[Math.round(B.zoom*1e3)/10,`%`]}),_(`button`,{type:`button`,className:g(f.roomDrawerViewButton,T?.viewButton),style:E?.viewButton,title:C?.zoomIn??`Zoom in`,"aria-label":C?.zoomIn??`Zoom in`,onClick:()=>Or(1.25),children:t(w?.zoomIn??et)})]})]}),Tt&&M.floors.length>0&&v(`div`,{className:g(f.roomDrawerFloorBar,T?.floorBar),style:E?.floorBar,role:`tablist`,"aria-label":C?.selectedFloor??`Floor`,children:[[...M.floors].reverse().map(e=>_(`button`,{type:`button`,role:`tab`,className:g(f.roomDrawerFloorTab,e.id===N.id&&f.roomDrawerFloorTabActive,T?.floorTab),style:E?.floorTab,"aria-selected":e.id===N.id,onClick:()=>Nn(e.id),children:e.label},e.id)),q&&_(`button`,{type:`button`,className:g(f.roomDrawerFloorTab,f.roomDrawerFloorTabAdd),title:C?.addFloor??`Add a floor above`,"aria-label":C?.addFloor??`Add a floor above`,onClick:()=>Pr(),children:t(w?.addFloor??nt)})]}),_(`div`,{ref:bn,className:g(f.roomDrawerCanvasWrapper,q&&F!==`select`&&f.roomDrawerCanvasWrapperDrawing,T?.canvasWrapper),style:{height:dn,...E?.canvasWrapper},onPointerDown:wr,onPointerMove:Tr,onPointerUp:e=>Er(e,!1),onPointerCancel:e=>Er(e,!0),children:_(Pe,{ref:xn,floor:N,underlay:Mn,rooms:P,view:B,size:H,selection:I,hovered:Hn,interactiveRooms:!1,showGrid:$n,gridSize:x,showRoomLabels:!0,formatArea:Qt,getRoomColor:fn,renderRoomLabel:pn,overlay:Gr,classNames:T,styles:E})}),en&&q&&v(`div`,{className:g(f.roomDrawerInspector,T?.inspector),style:E?.inspector,children:[_(`span`,{className:g(f.roomDrawerInspectorKind,I.length===0&&f.roomDrawerInspectorKindEmpty,T?.inspectorLabel),children:Jr}),I.length===0&&v(ct,{children:[_(i,{className:g(f.roomDrawerInspectorName,T?.inspectorField),style:E?.inspectorField,label:C?.floorName??`Floor name`,value:N.label,onChange:e=>zr(N.id,e)}),_(Ne,{className:g(f.roomDrawerInspectorField,T?.inspectorField),style:E?.inspectorField,label:C?.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&&Rr(N.id,e)}}),M.floors.length>1&&v(ct,{children:[_(`button`,{type:`button`,className:g(f.roomDrawerInspectorAction,T?.inspectorField),style:E?.inspectorField,title:C?.moveFloorUp??`Move this floor up`,"aria-label":C?.moveFloorUp??`Move this floor up`,disabled:ge(M,N.id)>=M.floors.length-1,onClick:()=>Lr(N.id,ge(M,N.id)+1),children:t(w?.moveFloorUp??Ve)}),_(`button`,{type:`button`,className:g(f.roomDrawerInspectorAction,T?.inspectorField),style:E?.inspectorField,title:C?.moveFloorDown??`Move this floor down`,"aria-label":C?.moveFloorDown??`Move this floor down`,disabled:ge(M,N.id)<=0,onClick:()=>Lr(N.id,ge(M,N.id)-1),children:t(w?.moveFloorDown??Be)})]}),_(`button`,{type:`button`,className:g(f.roomDrawerInspectorAction,T?.inspectorField),style:E?.inspectorField,title:C?.duplicateFloor??`Copy this floor to a new one above`,onClick:()=>Fr(),children:t(w?.duplicateFloor??Ke)}),M.floors.length>1&&_(n,{className:f.roomDrawerInspectorDelete,icon:w?.delete??at,title:C?.deleteFloor??`Delete this floor`,onClick:()=>Ir()})]}),_r?.meta&&v(ct,{children:[_(i,{className:g(f.roomDrawerInspectorName,T?.inspectorField),style:E?.inspectorField,label:C?.roomName??`Room name`,value:_r.meta.name,onChange:e=>{let t=_r.meta;X({...N,rooms:{...N.rooms,[t.id]:{...t,name:e}}},`edit-room`,[t.id])}}),_(`span`,{className:g(f.roomDrawerInspectorLabel,T?.inspectorLabel),children:Qt(_r.area)})]}),Z&&_(`button`,{type:`button`,className:g(f.roomDrawerInspectorAction,T?.inspectorField),style:E?.inspectorField,onClick:br,title:C?.addCorner??`Add a corner to this wall`,children:C?.addCorner??`Add corner`}),Z&&_(Ne,{className:g(f.roomDrawerInspectorField,T?.inspectorField),style:E?.inspectorField,label:C?.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])}}),vr&&v(ct,{children:[_(Ne,{className:g(f.roomDrawerInspectorField,T?.inspectorField),style:E?.inspectorField,label:C?.width??`Width (mm)`,value:vr.width,decimalScale:0,min:100,step:50,showArrows:!0,onChange:e=>{e!==void 0&&X(le(N,vr.id,{width:e}).floor,`edit-opening`,[vr.id])}}),_(Ne,{className:g(f.roomDrawerInspectorField,T?.inspectorField),style:E?.inspectorField,label:C?.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:vr.sill,decimalScale:0,min:0,step:50,onChange:e=>{e!==void 0&&X(le(N,vr.id,{sill:e}).floor,`edit-opening`,[vr.id])}})]}),I.length>0&&_(n,{className:f.roomDrawerInspectorDelete,icon:w?.delete??at,title:C?.deleteSelection??`Delete selection`,onClick:Sr})]}),rn&&q&&_(`input`,{ref:sr,type:`file`,accept:`application/json,.json`,className:f.roomDrawerFileInput,tabIndex:-1,"aria-hidden":`true`,onChange:e=>{let t=e.target.files?.[0];e.target.value=``,t&&Hr(t)}}),tn&&(lr!==null||qr)&&_(`div`,{className:g(f.roomDrawerHint,lr!==null&&f.roomDrawerHintReport,T?.hint),style:E?.hint,role:lr===null?void 0:`status`,children:lr===null?qr:lr.length===0?C?.importFailed??`That file could not be read as a floor plan`:lr.join(` · `)})]})});export{y as default};
2
2
  //# sourceMappingURL=roomDrawer.mjs.map