perf(iso): ускорить точный граничный поиск (#585)

Issue: #585
User-Visible: no
This commit is contained in:
Claude
2026-09-20 01:51:19 +03:00
parent 3c2ab9b764
commit e793993c66
49 changed files with 739 additions and 606 deletions
@@ -1,309 +1,309 @@
{ {
"schema": 1, "schema": 1,
"fingerprint": "88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9", "fingerprint": "f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786",
"entry": "houseplan-card.js", "entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js", "panelEntry": "houseplan-panel.js",
"initialViewFiles": [ "initialViewFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-card.js" "houseplan-card.js"
], ],
"initialViewGzipBytes": 291517, "initialViewGzipBytes": 291531,
"initialPanelFiles": [ "initialPanelFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-panel.js" "houseplan-panel.js"
], ],
"initialPanelGzipBytes": 293039, "initialPanelGzipBytes": 293054,
"initialPanelOnlyFiles": [ "initialPanelOnlyFiles": [
"houseplan-panel.js" "houseplan-panel.js"
], ],
"initialPanelOnlyGzipBytes": 2324, "initialPanelOnlyGzipBytes": 2327,
"lazyFiles": [ "lazyFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/de-qGelgWw2.js", "houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-fzEJ3Sy_.js", "houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/fr-Dy8iiwy_.js", "houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js", "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js", "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js", "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js", "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-eMxHYpi-.js", "houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js", "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js", "houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js" "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
], ],
"lazyGzipBytes": 441076, "lazyGzipBytes": 441788,
"lazyEditorFiles": [ "lazyEditorFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/editor-fzEJ3Sy_.js", "houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js" "houseplan-assets/zigbee-topology-C-kzak0j.js"
], ],
"lazyEditorGzipBytes": 222197, "lazyEditorGzipBytes": 222205,
"lazyOnboardingFiles": [ "lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js" "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js"
], ],
"lazyOnboardingGzipBytes": 13918, "lazyOnboardingGzipBytes": 13919,
"lazyLocaleFiles": [ "lazyLocaleFiles": [
"houseplan-assets/de-qGelgWw2.js", "houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/fr-Dy8iiwy_.js" "houseplan-assets/fr-a1RH1L3D.js"
], ],
"lazyLocaleGzipBytes": 56352, "lazyLocaleGzipBytes": 56366,
"lazyIsometricFiles": [ "lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-DhtLxqcj.js" "houseplan-assets/iso-scene-render-DJ5weuvD.js"
], ],
"lazyIsometricGzipBytes": 16792, "lazyIsometricGzipBytes": 17468,
"lazyFurnitureArtFiles": [ "lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js" "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js"
], ],
"lazyFurnitureArtGzipBytes": 16944, "lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [ "lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/pdf-export-eMxHYpi-.js" "houseplan-assets/pdf-export-CekmWtl5.js"
], ],
"lazyPdfGzipBytes": 126817, "lazyPdfGzipBytes": 126814,
"files": [ "files": [
{ {
"path": "houseplan-assets/backdrop-pick-Pc0BlKD3.js", "path": "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"sha256": "a17a0059314b4275a5560c5235afe05c93ee0590ec5797b6eb9e793b34904820", "sha256": "900db7fb5992afbe29bc233852026cdec275236b153e7ddac0c0dda39e6bf271",
"rawBytes": 19959, "rawBytes": 19959,
"gzipBytes": 6883, "gzipBytes": 6883,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/de-qGelgWw2.js", "path": "houseplan-assets/de-DNwtZhVG.js",
"sha256": "5734db4624e6770a5f56defbe2626d2e5082fa662c93048c6214f51056080d57", "sha256": "42b5b3aae036198a6000575bfad2ab4a6887cf1577aaee89e46807d811a4b41c",
"rawBytes": 93989, "rawBytes": 93989,
"gzipBytes": 28441, "gzipBytes": 28448,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/editor-fzEJ3Sy_.js", "path": "houseplan-assets/editor-BMFNgL2p.js",
"sha256": "3fae1734402588dd4a0526ce2fcc568aa7d9ebfd95ba039407e2605d0bd035f0", "sha256": "19c12c4e6b3852fc10c27e4bda3e18dc5447ea437d6ad51b07f63a8ef9ebe448",
"rawBytes": 3833, "rawBytes": 3833,
"gzipBytes": 1583, "gzipBytes": 1585,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/form-kit.styles-BW84Z22H.js", "path": "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"sha256": "e24b9470e6f4fa894d108f27c31e6a6919e61971d7ba7271eb96fe6f53eea589", "sha256": "64145e5cfe224a062c9f30c3a2b13566915da2f34f9d01a2132b239d7a89943f",
"rawBytes": 3615, "rawBytes": 3615,
"gzipBytes": 1233, "gzipBytes": 1235,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/fr-Dy8iiwy_.js", "path": "houseplan-assets/fr-a1RH1L3D.js",
"sha256": "77c85c92191fbaf644d15aaced93611c37f3459c86ea8136acabb1c35269e119", "sha256": "404653aacaf79acdbe7e357c6427acf1cee8448b516bce2b7613a45cf31a9ab7",
"rawBytes": 96460, "rawBytes": 96460,
"gzipBytes": 27911, "gzipBytes": 27918,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "path": "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"sha256": "1df63e447d66a02eb7039337ef16198f3b457d78c23622e1f33a90c6d1f0bc1f", "sha256": "4713caf365b8e228e88a0220a77f4603f6045431d57b768fcbbe6b4cc27de1d2",
"rawBytes": 52033, "rawBytes": 52033,
"gzipBytes": 16944, "gzipBytes": 16940,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/houseplan-card-CdCQB6rW.js", "path": "houseplan-assets/houseplan-card-DrP8_MdR.js",
"sha256": "17d647662295c586c4ea81e8c8a3c194afe776da43e75830666dae882f001b52", "sha256": "dc471e9ada8f0113de4e5acb7743e3377f7c8274fa19e7a7d9363385a161222d",
"rawBytes": 1035518, "rawBytes": 1035518,
"gzipBytes": 290715, "gzipBytes": 290727,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [ "dynamicImports": [
"houseplan-assets/de-qGelgWw2.js", "houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-fzEJ3Sy_.js", "houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/fr-Dy8iiwy_.js", "houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js", "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js", "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js", "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js", "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-eMxHYpi-.js", "houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js" "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
] ]
}, },
{ {
"path": "houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "path": "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"sha256": "16af54e5252363307e7a1384305096395836362a9a34d77d837503fb41bd43bd", "sha256": "a9975e514b2ab69a61beeb4b6fb99ae7ca965ab849c730861edf6b330173a4b1",
"rawBytes": 689688, "rawBytes": 689688,
"gzipBytes": 188130, "gzipBytes": 188131,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js" "houseplan-assets/zigbee-topology-C-kzak0j.js"
], ],
"dynamicImports": [ "dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js" "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
] ]
}, },
{ {
"path": "houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js", "path": "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"sha256": "229bbb57e3928c39f46e40824ebdfaa2ba87fe5af6c4a3e9187773c9709185ab", "sha256": "208379c3485b77ef3a681ac46de8e74a02faa8ab51bf7dec3bb6001b99266fe3",
"rawBytes": 28289, "rawBytes": 28289,
"gzipBytes": 7035, "gzipBytes": 7036,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js", "path": "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"sha256": "e6ce493c3b1a44eb654188d4d148e5dabe237fa1edd6694f3bbce99b2105fd49", "sha256": "4ecedcacf6021d94b060d0978e17059bf4bd031cb0db7b603ce645160c89c26a",
"rawBytes": 10759, "rawBytes": 10759,
"gzipBytes": 3684, "gzipBytes": 3689,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js", "houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js" "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/iso-scene-render-DhtLxqcj.js", "path": "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"sha256": "4dd8c9fa88224e480f3c50d89c2c3b073f74dd1bed6cfeb6196f301aade77ded", "sha256": "e96e245dc9c2cff1c1d7408393f2440ac26e2f3694d7f37b2b8f76efe8b15ca3",
"rawBytes": 50012, "rawBytes": 51348,
"gzipBytes": 16792, "gzipBytes": 17468,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/live-interaction-runtime-bgXukYTl.js", "path": "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"sha256": "b623081e5e869c80bc73a9173eb072cb3686b06244105fbbafa2b7a03da374d3", "sha256": "d2980077723e8b35da04f327f07d8d404207f3ddb057c7306a52a5525c182879",
"rawBytes": 8216, "rawBytes": 8216,
"gzipBytes": 3207, "gzipBytes": 3209,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/pdf-export-eMxHYpi-.js", "path": "houseplan-assets/pdf-export-CekmWtl5.js",
"sha256": "43581b2fd6d3b12389e6fda98d36ff4250a0a4fe59f9e52668937e3307f95cbb", "sha256": "a4d5a8dc54c4615b8e7806ecdd1fc6b940c82d76b8c84fa30b9680afeed047c0",
"rawBytes": 236247, "rawBytes": 236247,
"gzipBytes": 109873, "gzipBytes": 109874,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/summary-panel-editor-f3elPcdE.js", "path": "houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"sha256": "727df14b390c264979ad8c07ca57d994a8c0c3caa73bc6e7f793745f3adc85d1", "sha256": "0337b078d59d0b6281809fae10f0a353cd0d706c1f71ce42350081fc5c3cd7ec",
"rawBytes": 14862, "rawBytes": 14862,
"gzipBytes": 3425, "gzipBytes": 3426,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js" "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/summary-panel-metrics-CzwbD9VU.js", "path": "houseplan-assets/summary-panel-metrics-BZroKqza.js",
"sha256": "fabd124197786f937775ede672afd5c5c72bab82b997cb5ccf84324d9d872de9", "sha256": "abaaf95c3717ccbd1b01181767e6198b25b5d8b50b2ed12dc88c67c860e28be5",
"rawBytes": 2611, "rawBytes": 2611,
"gzipBytes": 1306, "gzipBytes": 1309,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js", "path": "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"sha256": "4b6fe585ffe7ac0d299691195754879f645507176e1c2365a85cb13655edb17c", "sha256": "7a3fb4366d86299ee5b81b4cfd4f8232989ea6064c98437c439deb0359107747",
"rawBytes": 72733, "rawBytes": 72733,
"gzipBytes": 20173, "gzipBytes": 20176,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [ "dynamicImports": [
"houseplan-assets/summary-panel-editor-f3elPcdE.js", "houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"houseplan-assets/summary-panel-metrics-CzwbD9VU.js" "houseplan-assets/summary-panel-metrics-BZroKqza.js"
] ]
}, },
{ {
"path": "houseplan-assets/zigbee-topology-Km5WY9re.js", "path": "houseplan-assets/zigbee-topology-C-kzak0j.js",
"sha256": "ca81df585fa1aeb2568dc373e5533f3b0b6a88ed5f11083e022f1316595fd079", "sha256": "080ae360ef3f1640ef0a16cf787cc7984687dff4e9a159a5076531b8894f46a4",
"rawBytes": 18962, "rawBytes": 18962,
"gzipBytes": 7424, "gzipBytes": 7431,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js", "path": "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js",
"sha256": "53f5b9b40e8d868ab187aff1b66b410cb526ed1ae7132c55005fc0d929fc7058", "sha256": "1788037ba347b556f50bcadee7e9ce2ac54d66370426ffcd694713b0edb66f6f",
"rawBytes": 3942, "rawBytes": 3942,
"gzipBytes": 1763, "gzipBytes": 1765,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js" "houseplan-assets/zigbee-topology-C-kzak0j.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-card.js", "path": "houseplan-card.js",
"sha256": "eaaf069917dd00f4b4f73e114304cdbb289cf9a0e5fc1b49205741f0ae9b40c1", "sha256": "8155cac3c10cc2682c573aa678551714efe70c93e6e80b532bbf45d7cf5618f1",
"rawBytes": 1205, "rawBytes": 1205,
"gzipBytes": 802, "gzipBytes": 804,
"isEntry": true, "isEntry": true,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-panel.js", "path": "houseplan-panel.js",
"sha256": "6df398c5faa4791f14e9a0358e584c58972cc159c717e32f8f0ffdcbf9dcf0f4", "sha256": "d89caea13550eb2aae4736804bff3a77e4dd649a0c5c5e787542da0350836b37",
"rawBytes": 6165, "rawBytes": 6165,
"gzipBytes": 2324, "gzipBytes": 2327,
"isEntry": true, "isEntry": true,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
} }
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-CdCQB6rW.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-DrP8_MdR.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass} .hass=${this.hass}
.data=${this._formData} .data=${this._formData}
.schema=${e} .schema=${e}
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g}; globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g};
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-CdCQB6rW.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-Pc0BlKD3.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l} globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-DrP8_MdR.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-2rRBIPzi.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
.text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans"> .text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans">
${s.map(s=>{return o` ${s.map(s=>{return o`
<div class="savedplan ${s.url===t.planUrl?"cur":""}"> <div class="savedplan ${s.url===t.planUrl?"cur":""}">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{c as a,A as e}from"./houseplan-card-CdCQB6rW.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-ClIYcGcH.js";import"./form-kit.styles-BW84Z22H.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show"> globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{c as a,A as e}from"./houseplan-card-DrP8_MdR.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-rHMkdk8Q.js";import"./form-kit.styles-1SWKbgIc.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong> <span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span> <small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox" <input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as c,b2 as l,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-DrP8_MdR.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,d="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*h(c,l,d=_){try{let u=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function p(e,t,n=_){const i=h(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{h as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as l,b2 as c,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-CdCQB6rW.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,l="entity"===r?e.registry.entities?.[s]:null,c="device"===r?s:l?.device_id,d="device"===r?a?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===r&&n.liveEntities.has(s))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(l,c,d=_){try{let u=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(l,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{n as t,b as n}from"./zigbee-topology-Km5WY9re.js";import{aR as e}from"./houseplan-card-CdCQB6rW.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot}; globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{n as t,b as n}from"./zigbee-topology-C-kzak0j.js";import{aR as e}from"./houseplan-card-DrP8_MdR.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";try{await import("./houseplan-assets/houseplan-card-CdCQB6rW.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)} globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";try{await import("./houseplan-assets/houseplan-card-DrP8_MdR.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
File diff suppressed because one or more lines are too long
+141 -141
View File
@@ -1,309 +1,309 @@
{ {
"schema": 1, "schema": 1,
"fingerprint": "88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9", "fingerprint": "f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786",
"entry": "houseplan-card.js", "entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js", "panelEntry": "houseplan-panel.js",
"initialViewFiles": [ "initialViewFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-card.js" "houseplan-card.js"
], ],
"initialViewGzipBytes": 291517, "initialViewGzipBytes": 291531,
"initialPanelFiles": [ "initialPanelFiles": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-panel.js" "houseplan-panel.js"
], ],
"initialPanelGzipBytes": 293039, "initialPanelGzipBytes": 293054,
"initialPanelOnlyFiles": [ "initialPanelOnlyFiles": [
"houseplan-panel.js" "houseplan-panel.js"
], ],
"initialPanelOnlyGzipBytes": 2324, "initialPanelOnlyGzipBytes": 2327,
"lazyFiles": [ "lazyFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/de-qGelgWw2.js", "houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-fzEJ3Sy_.js", "houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/fr-Dy8iiwy_.js", "houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js", "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js", "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js", "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js", "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-eMxHYpi-.js", "houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js", "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js", "houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js" "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
], ],
"lazyGzipBytes": 441076, "lazyGzipBytes": 441788,
"lazyEditorFiles": [ "lazyEditorFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/editor-fzEJ3Sy_.js", "houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js" "houseplan-assets/zigbee-topology-C-kzak0j.js"
], ],
"lazyEditorGzipBytes": 222197, "lazyEditorGzipBytes": 222205,
"lazyOnboardingFiles": [ "lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js" "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js"
], ],
"lazyOnboardingGzipBytes": 13918, "lazyOnboardingGzipBytes": 13919,
"lazyLocaleFiles": [ "lazyLocaleFiles": [
"houseplan-assets/de-qGelgWw2.js", "houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/fr-Dy8iiwy_.js" "houseplan-assets/fr-a1RH1L3D.js"
], ],
"lazyLocaleGzipBytes": 56352, "lazyLocaleGzipBytes": 56366,
"lazyIsometricFiles": [ "lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-DhtLxqcj.js" "houseplan-assets/iso-scene-render-DJ5weuvD.js"
], ],
"lazyIsometricGzipBytes": 16792, "lazyIsometricGzipBytes": 17468,
"lazyFurnitureArtFiles": [ "lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js" "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js"
], ],
"lazyFurnitureArtGzipBytes": 16944, "lazyFurnitureArtGzipBytes": 16940,
"lazyPdfFiles": [ "lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/pdf-export-eMxHYpi-.js" "houseplan-assets/pdf-export-CekmWtl5.js"
], ],
"lazyPdfGzipBytes": 126817, "lazyPdfGzipBytes": 126814,
"files": [ "files": [
{ {
"path": "houseplan-assets/backdrop-pick-Pc0BlKD3.js", "path": "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"sha256": "a17a0059314b4275a5560c5235afe05c93ee0590ec5797b6eb9e793b34904820", "sha256": "900db7fb5992afbe29bc233852026cdec275236b153e7ddac0c0dda39e6bf271",
"rawBytes": 19959, "rawBytes": 19959,
"gzipBytes": 6883, "gzipBytes": 6883,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/de-qGelgWw2.js", "path": "houseplan-assets/de-DNwtZhVG.js",
"sha256": "5734db4624e6770a5f56defbe2626d2e5082fa662c93048c6214f51056080d57", "sha256": "42b5b3aae036198a6000575bfad2ab4a6887cf1577aaee89e46807d811a4b41c",
"rawBytes": 93989, "rawBytes": 93989,
"gzipBytes": 28441, "gzipBytes": 28448,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/editor-fzEJ3Sy_.js", "path": "houseplan-assets/editor-BMFNgL2p.js",
"sha256": "3fae1734402588dd4a0526ce2fcc568aa7d9ebfd95ba039407e2605d0bd035f0", "sha256": "19c12c4e6b3852fc10c27e4bda3e18dc5447ea437d6ad51b07f63a8ef9ebe448",
"rawBytes": 3833, "rawBytes": 3833,
"gzipBytes": 1583, "gzipBytes": 1585,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/form-kit.styles-BW84Z22H.js", "path": "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"sha256": "e24b9470e6f4fa894d108f27c31e6a6919e61971d7ba7271eb96fe6f53eea589", "sha256": "64145e5cfe224a062c9f30c3a2b13566915da2f34f9d01a2132b239d7a89943f",
"rawBytes": 3615, "rawBytes": 3615,
"gzipBytes": 1233, "gzipBytes": 1235,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/fr-Dy8iiwy_.js", "path": "houseplan-assets/fr-a1RH1L3D.js",
"sha256": "77c85c92191fbaf644d15aaced93611c37f3459c86ea8136acabb1c35269e119", "sha256": "404653aacaf79acdbe7e357c6427acf1cee8448b516bce2b7613a45cf31a9ab7",
"rawBytes": 96460, "rawBytes": 96460,
"gzipBytes": 27911, "gzipBytes": 27918,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "path": "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"sha256": "1df63e447d66a02eb7039337ef16198f3b457d78c23622e1f33a90c6d1f0bc1f", "sha256": "4713caf365b8e228e88a0220a77f4603f6045431d57b768fcbbe6b4cc27de1d2",
"rawBytes": 52033, "rawBytes": 52033,
"gzipBytes": 16944, "gzipBytes": 16940,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/houseplan-card-CdCQB6rW.js", "path": "houseplan-assets/houseplan-card-DrP8_MdR.js",
"sha256": "17d647662295c586c4ea81e8c8a3c194afe776da43e75830666dae882f001b52", "sha256": "dc471e9ada8f0113de4e5acb7743e3377f7c8274fa19e7a7d9363385a161222d",
"rawBytes": 1035518, "rawBytes": 1035518,
"gzipBytes": 290715, "gzipBytes": 290727,
"isEntry": false, "isEntry": false,
"imports": [], "imports": [],
"dynamicImports": [ "dynamicImports": [
"houseplan-assets/de-qGelgWw2.js", "houseplan-assets/de-DNwtZhVG.js",
"houseplan-assets/editor-fzEJ3Sy_.js", "houseplan-assets/editor-BMFNgL2p.js",
"houseplan-assets/fr-Dy8iiwy_.js", "houseplan-assets/fr-a1RH1L3D.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js", "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js", "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"houseplan-assets/iso-scene-render-DhtLxqcj.js", "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"houseplan-assets/live-interaction-runtime-bgXukYTl.js", "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"houseplan-assets/pdf-export-eMxHYpi-.js", "houseplan-assets/pdf-export-CekmWtl5.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js" "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
] ]
}, },
{ {
"path": "houseplan-assets/houseplan-editor-runtime-C7V34E2J.js", "path": "houseplan-assets/houseplan-editor-runtime-DzQJJ1M6.js",
"sha256": "16af54e5252363307e7a1384305096395836362a9a34d77d837503fb41bd43bd", "sha256": "a9975e514b2ab69a61beeb4b6fb99ae7ca965ab849c730861edf6b330173a4b1",
"rawBytes": 689688, "rawBytes": 689688,
"gzipBytes": 188130, "gzipBytes": 188131,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js" "houseplan-assets/zigbee-topology-C-kzak0j.js"
], ],
"dynamicImports": [ "dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js" "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
] ]
}, },
{ {
"path": "houseplan-assets/houseplan-onboarding-runtime-BEe4SZTb.js", "path": "houseplan-assets/houseplan-onboarding-runtime-DiKx8hzZ.js",
"sha256": "229bbb57e3928c39f46e40824ebdfaa2ba87fe5af6c4a3e9187773c9709185ab", "sha256": "208379c3485b77ef3a681ac46de8e74a02faa8ab51bf7dec3bb6001b99266fe3",
"rawBytes": 28289, "rawBytes": 28289,
"gzipBytes": 7035, "gzipBytes": 7036,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/backdrop-pick-Pc0BlKD3.js", "houseplan-assets/backdrop-pick-2rRBIPzi.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/hp-zigbee-topology-overlay-eqgElxaW.js", "path": "houseplan-assets/hp-zigbee-topology-overlay-uix5BXJ6.js",
"sha256": "e6ce493c3b1a44eb654188d4d148e5dabe237fa1edd6694f3bbce99b2105fd49", "sha256": "4ecedcacf6021d94b060d0978e17059bf4bd031cb0db7b603ce645160c89c26a",
"rawBytes": 10759, "rawBytes": 10759,
"gzipBytes": 3684, "gzipBytes": 3689,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js", "houseplan-assets/zigbee-topology-C-kzak0j.js",
"houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js" "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/iso-scene-render-DhtLxqcj.js", "path": "houseplan-assets/iso-scene-render-DJ5weuvD.js",
"sha256": "4dd8c9fa88224e480f3c50d89c2c3b073f74dd1bed6cfeb6196f301aade77ded", "sha256": "e96e245dc9c2cff1c1d7408393f2440ac26e2f3694d7f37b2b8f76efe8b15ca3",
"rawBytes": 50012, "rawBytes": 51348,
"gzipBytes": 16792, "gzipBytes": 17468,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/live-interaction-runtime-bgXukYTl.js", "path": "houseplan-assets/live-interaction-runtime-BsDaP7YB.js",
"sha256": "b623081e5e869c80bc73a9173eb072cb3686b06244105fbbafa2b7a03da374d3", "sha256": "d2980077723e8b35da04f327f07d8d404207f3ddb057c7306a52a5525c182879",
"rawBytes": 8216, "rawBytes": 8216,
"gzipBytes": 3207, "gzipBytes": 3209,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/pdf-export-eMxHYpi-.js", "path": "houseplan-assets/pdf-export-CekmWtl5.js",
"sha256": "43581b2fd6d3b12389e6fda98d36ff4250a0a4fe59f9e52668937e3307f95cbb", "sha256": "a4d5a8dc54c4615b8e7806ecdd1fc6b940c82d76b8c84fa30b9680afeed047c0",
"rawBytes": 236247, "rawBytes": 236247,
"gzipBytes": 109873, "gzipBytes": 109874,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/furniture-plan-art.generated-q2BImG4G.js", "houseplan-assets/furniture-plan-art.generated-CJAWlM4T.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/summary-panel-editor-f3elPcdE.js", "path": "houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"sha256": "727df14b390c264979ad8c07ca57d994a8c0c3caa73bc6e7f793745f3adc85d1", "sha256": "0337b078d59d0b6281809fae10f0a353cd0d706c1f71ce42350081fc5c3cd7ec",
"rawBytes": 14862, "rawBytes": 14862,
"gzipBytes": 3425, "gzipBytes": 3426,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js" "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/summary-panel-metrics-CzwbD9VU.js", "path": "houseplan-assets/summary-panel-metrics-BZroKqza.js",
"sha256": "fabd124197786f937775ede672afd5c5c72bab82b997cb5ccf84324d9d872de9", "sha256": "abaaf95c3717ccbd1b01181767e6198b25b5d8b50b2ed12dc88c67c860e28be5",
"rawBytes": 2611, "rawBytes": 2611,
"gzipBytes": 1306, "gzipBytes": 1309,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/summary-panel-runtime-loaded-ClIYcGcH.js", "path": "houseplan-assets/summary-panel-runtime-loaded-rHMkdk8Q.js",
"sha256": "4b6fe585ffe7ac0d299691195754879f645507176e1c2365a85cb13655edb17c", "sha256": "7a3fb4366d86299ee5b81b4cfd4f8232989ea6064c98437c439deb0359107747",
"rawBytes": 72733, "rawBytes": 72733,
"gzipBytes": 20173, "gzipBytes": 20176,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/form-kit.styles-BW84Z22H.js", "houseplan-assets/form-kit.styles-1SWKbgIc.js",
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [ "dynamicImports": [
"houseplan-assets/summary-panel-editor-f3elPcdE.js", "houseplan-assets/summary-panel-editor-D0YwKCWJ.js",
"houseplan-assets/summary-panel-metrics-CzwbD9VU.js" "houseplan-assets/summary-panel-metrics-BZroKqza.js"
] ]
}, },
{ {
"path": "houseplan-assets/zigbee-topology-Km5WY9re.js", "path": "houseplan-assets/zigbee-topology-C-kzak0j.js",
"sha256": "ca81df585fa1aeb2568dc373e5533f3b0b6a88ed5f11083e022f1316595fd079", "sha256": "080ae360ef3f1640ef0a16cf787cc7984687dff4e9a159a5076531b8894f46a4",
"rawBytes": 18962, "rawBytes": 18962,
"gzipBytes": 7424, "gzipBytes": 7431,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-assets/zigbee-topology-runtime-DLvqrPjc.js", "path": "houseplan-assets/zigbee-topology-runtime-CveXz_VE.js",
"sha256": "53f5b9b40e8d868ab187aff1b66b410cb526ed1ae7132c55005fc0d929fc7058", "sha256": "1788037ba347b556f50bcadee7e9ce2ac54d66370426ffcd694713b0edb66f6f",
"rawBytes": 3942, "rawBytes": 3942,
"gzipBytes": 1763, "gzipBytes": 1765,
"isEntry": false, "isEntry": false,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js", "houseplan-assets/houseplan-card-DrP8_MdR.js",
"houseplan-assets/zigbee-topology-Km5WY9re.js" "houseplan-assets/zigbee-topology-C-kzak0j.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-card.js", "path": "houseplan-card.js",
"sha256": "eaaf069917dd00f4b4f73e114304cdbb289cf9a0e5fc1b49205741f0ae9b40c1", "sha256": "8155cac3c10cc2682c573aa678551714efe70c93e6e80b532bbf45d7cf5618f1",
"rawBytes": 1205, "rawBytes": 1205,
"gzipBytes": 802, "gzipBytes": 804,
"isEntry": true, "isEntry": true,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
}, },
{ {
"path": "houseplan-panel.js", "path": "houseplan-panel.js",
"sha256": "6df398c5faa4791f14e9a0358e584c58972cc159c717e32f8f0ffdcbf9dcf0f4", "sha256": "d89caea13550eb2aae4736804bff3a77e4dd649a0c5c5e787542da0350836b37",
"rawBytes": 6165, "rawBytes": 6165,
"gzipBytes": 2324, "gzipBytes": 2327,
"isEntry": true, "isEntry": true,
"imports": [ "imports": [
"houseplan-assets/houseplan-card-CdCQB6rW.js" "houseplan-assets/houseplan-card-DrP8_MdR.js"
], ],
"dynamicImports": [] "dynamicImports": []
} }
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-CdCQB6rW.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{aI as e,l as o,aL as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-DrP8_MdR.js";class h extends e{constructor(){super(...arguments),this._spaces=null,this._spacesLoading=!1,this._spacesAuthoritative=!1}setConfig(e){this._config=e}async _loadSpaces(){if(!this._spaces&&!this._spacesLoading&&this.hass){this._spacesLoading=!0;try{const e=await this.hass.callWS({type:"houseplan/config/get"});this._spaces=(e?.config?.spaces||[]).map(e=>({value:e.id,label:e.title||e.id})),this._spacesAuthoritative=!0}catch{this._spaces=[],this._spacesAuthoritative=!1}finally{this._spacesLoading=!1}}}get _lang(){return o(this.hass,this._config?.language)}get _floorToken(){const e=this._config?.floor;return"number"==typeof e?`__houseplan_yaml_floor_index__:${String(e)}`:null}get _formData(){const e={...this._config},o=this._floorToken;return o?e.floor=o:Object.prototype.hasOwnProperty.call(e,"floor")||(e.floor=""),e}get _schema(){const e=this._spaces||[],o=this._lang,a=[{value:"",label:t(o,"editor.floor_none")}],i=this._floorToken;i&&a.push({value:i,label:t(o,"editor.floor_index",{index:String(this._config?.floor)})});const l="string"==typeof this._config?.floor?this._config.floor:"";l&&!e.some(e=>e.value===l)&&a.push({value:l,label:l}),a.push(...e);const n="string"==typeof this._config?.default_floor?this._config.default_floor:"",r=[...e];return n&&!e.some(e=>e.value===n)&&r.unshift({value:n,label:n}),[{name:"title",selector:{text:{}}},{name:"floor",selector:{select:{mode:"dropdown",options:a}}},e.length?{name:"default_floor",selector:{select:{mode:"dropdown",options:r}}}:{name:"default_floor",selector:{text:{}}},{name:"language",selector:{select:{mode:"dropdown",options:s(t(o,"editor.lang_auto"),this._config?.language)}}},{name:"icon_size",selector:{number:{min:1,max:6,step:.1,mode:"box"}}},{name:"show_temperature",selector:{boolean:{}}},{name:"live_states",selector:{boolean:{}}},{name:"show_signal",selector:{boolean:{}}},{name:"kiosk",selector:{boolean:{}}},{name:"cycle",selector:{number:{min:0,max:3600,step:5,mode:"box"}}}]}render(){if(!this.hass||!this._config)return a;const e=i(this,l,o(this.hass,this._config.language));if("cold"===e)return n();if("warm"===e)return r;this._loadSpaces();const s=this._lang,h={title:t(s,"editor.title"),floor:t(s,"editor.floor"),default_floor:t(s,"editor.default_floor"),language:t(s,"editor.language"),icon_size:t(s,"editor.icon_size"),show_temperature:t(s,"editor.show_temperature"),live_states:t(s,"editor.live_states"),show_signal:t(s,"editor.show_signal"),kiosk:t(s,"editor.kiosk"),cycle:t(s,"editor.cycle")},f=this._schema,_=function(e,o,t){if(!t||null===o)return null;const s="string"==typeof e?.default_floor?e.default_floor:"";return!s||o.some(e=>e.value===s)?null:s}(this._config,this._spaces,this._spacesAuthoritative),d=e=>c`<ha-form
.hass=${this.hass} .hass=${this.hass}
.data=${this._formData} .data=${this._formData}
.schema=${e} .schema=${e}
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g}; globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";const n={form:".summary-editor",prefix:"summary",cards:[".summary-general",".summary-blocks-card"],footer:".summary-editor-footer",tokens:{surface:"--summary-editor-surface",line:"--summary-editor-line",accent:"--summary-editor-accent"}},e={form:".hpf-form",prefix:"hpf",cards:[".hpf-card"],footer:".hpf-footer",tokens:{surface:"--hpf-surface",line:"--hpf-line",accent:"--hpf-accent"}};function r({cards:n,tokens:e}){return` ${n.join(",\n ")} {\n min-width: 0;\n padding: 14px;\n border: 1px solid var(${e.line});\n border-radius: 11px;\n background: var(${e.surface});\n }`}function i({form:n,footer:e,tokens:r}){return` ${n} input:focus-visible,\n ${n} select:focus-visible,\n ${n} button:focus-visible,\n ${e} button:focus-visible {\n outline: 2px solid var(${r.accent});\n outline-offset: 2px;\n }`}function t({form:n}){return` ${n} button:disabled,\n ${n} input:disabled,\n ${n} select:disabled { opacity: .4; cursor: default; }`}function o({form:n,prefix:e}){return` ${n} .${e}-switch {\n display: flex;\n min-width: 0;\n min-height: 54px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin: 0;\n color: var(--primary-text-color);\n cursor: pointer;\n }`}function a({prefix:n}){return` .${n}-switch-caption { display: grid; min-width: 0; gap: 3px; }\n .${n}-switch-caption strong { font-size: .875rem; font-weight: 600; overflow-wrap: anywhere; }\n .${n}-switch-caption small { font-size: .8125rem; color: var(--secondary-text-color); overflow-wrap: anywhere; }`}function s(n,{withSwitch:e=!0}={}){return`${function(n,e){const s=e?`\n${o(n)}\n${a(n)}`:"";return`${r(n)}\n${i(n)}\n${t(n)}${s}`}(n,e)}\n${function(n){const{form:e,prefix:r,tokens:i}=n;return` ${e} { display: grid; gap: 12px; }\n .${r}-head {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n margin: 0 0 10px;\n }\n .${r}-head h3 { margin: 0; font-size: 1rem; line-height: 1.3; font-weight: 600; }\n .${r}-row {\n display: flex;\n min-width: 0;\n min-height: 44px;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n }\n .${r}-row > .${r}-label { min-width: 0; overflow-wrap: anywhere; }\n .${r}-seg {\n display: flex;\n min-width: 0;\n border: 1px solid var(${i.line});\n border-radius: 9px;\n overflow: hidden;\n }\n .${r}-seg label {\n display: flex;\n min-width: 0;\n min-height: 44px;\n flex: 1 1 0;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 0 12px;\n cursor: pointer;\n text-align: center;\n }\n .${r}-seg label + label { border-left: 1px solid var(${i.line}); }\n .${r}-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }\n .${r}-seg label:has(input:checked) {\n background: var(${i.accent});\n color: var(--text-primary-color, #fff);\n }\n .${r}-seg label:has(input:focus-visible) {\n outline: 2px solid var(${i.accent});\n outline-offset: -2px;\n }\n .${r}-color { display: flex; min-width: 0; align-items: center; gap: 12px; }\n .${r}-color hp-color-opacity { flex: 0 0 auto; }`}(n)}\n`}const c=" hp-dialog .hpf-form {\n --hpf-surface: var(--card-background-color, #fff);\n --hpf-line: var(--hp-line, var(--divider-color, #dce5e7));\n --hpf-accent: var(--hp-accent, var(--primary-color));\n }\n";export{e as C,n as S,r as a,i as b,c,t as d,o as e,s as f,a as g};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-CdCQB6rW.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-Pc0BlKD3.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l} globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{l as t,bw as s,A as e,aL as a,c as o,g as l,cK as i,ar as h,am as c,au as n,cL as r,cQ as p,cM as d,cN as _,cO as u,cP as g,cR as m,cS as b,al as $,ao as f,ap as v,as as y,at as w,aq as D}from"./houseplan-card-DrP8_MdR.js";import{c as k,e as S,r as C,a as M}from"./backdrop-pick-2rRBIPzi.js";const F=1e3,x=t=>{if(!t.trim())return null;const s=Number(t.replace(",","."));return Number.isFinite(s)?s:null},T="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";class L{constructor(t){this.host=t,this._toggleServerPlans=async()=>{const t=this.host._spaceDialog;if(t)if(t.pickSaved)this.host._spaceDialog={...t,pickSaved:!1};else{this.host._spaceDialog={...t,pickSaved:!0,savedBusy:!0};try{const t=await this.host.hass.callWS({type:"houseplan/plans/list"}),s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:t?.plans||[],savedBusy:!1})}catch(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,saved:[],savedBusy:!1}),this.host._showToast(this.host._t("toast.plans_list_failed",{err:this.host._errText(t)}))}}}}_help(l){const i=`${l}.aria`,h=t(this.host.hass,this.host._config?.language);return s(h,l)&&s(h,i)?o`<hp-help data-help-key=${l}
.text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans"> .text=${a(h,l)} .ariaLabel=${a(h,i)}></hp-help>`:e}_openSpaceDialog(t,s){if(!this.host._serverStorage||!this.host._serverCfg)return void this.host._showToast(this.host._t("toast.integration_missing"));if("edit"===t){const e=this.host._serverCfg.spaces.find(t=>t.id===s);if(!e)return;const a=l(e),o=e.settings?.custom_fill&&"object"==typeof e.settings.custom_fill?i(e.settings.custom_fill):null,p="none"===a.fill?{...o||h,a:0}:o;return void(this.host._spaceDialog={mode:t,spaceId:s,title:e.title,planUrl:e.plan_url||null,planFile:null,source:e.plan_url?"file":"draw",showBorders:a.showBorders,showNames:a.showNames,zeroWallStyle:r(e),displayTouched:!0,hideDecor:a.hideDecor,hideOpenings:a.hideOpenings,roomColor:a.color,roomOpacity:a.opacity,fillMode:"none"===a.fill?"custom":a.fill,customFill:p,glowEnabled:a.glow,bgColor:a.bgColor,bgMode:"static"===e.settings?.bg_mode||"daynight"===e.settings?.bg_mode?e.settings.bg_mode:null,northDeg:n({},e.settings),sunRays:"boolean"==typeof e.settings?.sun_rays?e.settings.sun_rays:null,tempMin:a.tempMin,tempMax:a.tempMax,showLqi:a.showLqi??this.host._config?.show_signal??!0,cardFontScale:a.cardFontScale,labelTemp:a.labelTemp,labelHum:a.labelHum,labelLqi:a.labelLqi,labelLight:a.labelLight,cellCm:Number(e.cell_cm)>0?Number(e.cell_cm):5,cellCmInput:c(Number(e.cell_cm)>0?Number(e.cell_cm):5,this.host._imperial),cellCmTouched:!1,busy:!1})}const e=p(this.host._imperial);this.host._spaceDialog={mode:t,title:"",planUrl:null,planFile:null,...m(),hideDecor:!1,hideOpenings:!1,zeroWallStyle:"dashed",roomColor:g,roomOpacity:u,fillMode:"custom",customFill:{...h,a:0},glowEnabled:!0,bgColor:null,bgMode:"daynight",northDeg:null,sunRays:null,tempMin:_,tempMax:d,showLqi:this.host._config?.show_signal??!0,cardFontScale:1,labelTemp:!1,labelHum:!1,labelLqi:!1,labelLight:!1,cellCm:e,cellCmInput:c(e,this.host._imperial),cellCmTouched:!1,busy:!1}}async _pickPlanFile(t){const s=t.target,e=s.files?.[0];if(!e||!this.host._spaceDialog)return;s.value="";const a=await k(e);if("reject"===a.kind)return void this.host._showToast(this.host._t("toast.plan_formats"));if("guard"===a.kind)return void(this.host._backdropGuard=a.state);const o=await S(e,a.ext,e.name);this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:o})}_renderBackdropGuard(){return C(this.host,t=>{this.host._spaceDialog&&(this.host._spaceDialog={...this.host._spaceDialog,planFile:t})},()=>{this.host._backdropGuard=null},this.host.hass)??e}_useServerPlan(t){const s=this.host._spaceDialog;s&&(this.host._spaceDialog={...s,planUrl:t,planFile:null,pickSaved:!1,savedAspect:void 0},this.host._aspectJob=this._readPlanAspect(t))}async _readPlanAspect(t){for(let s=0;s<40;s++){const s=this.host._display(t);if(s){const e=await new Promise(t=>{const e=new Image;e.onload=()=>t(e.naturalWidth&&e.naturalHeight?e.naturalWidth/e.naturalHeight:0),e.onerror=()=>t(0),e.src=s}),a=this.host._spaceDialog;return a&&a.planUrl===t&&Number.isFinite(e)&&e>0?(this.host._spaceDialog={...a,savedAspect:e},e):0}if(await new Promise(t=>setTimeout(t,150)),this.host._spaceDialog?.planUrl!==t)return 0}return 0}async _deleteServerPlan(t){const s=this.host._spaceDialog,e=s?.saved?.find(s=>s.name===t);if(!s||!e||e.used_by.length||e.url===s.planUrl)return;const a=await this.host._confirmDanger({key:"delete-plan",kind:"destructive",title:this.host._t("confirm.delete_plan_title"),message:this.host._t("confirm.delete_plan_body"),objectName:t,confirmLabel:this.host._t("btn.delete"),cancelLabel:this.host._t("btn.cancel")}),o=this.host._spaceDialog,l=o?.saved?.find(s=>s.name===t);if(a&&o&&l&&l.url===e.url&&l.modified===e.modified&&!l.used_by.length&&l.url!==o.planUrl)try{await this.host.hass.callWS({type:"houseplan/plans/delete",name:t});const s=this.host._spaceDialog;s?.saved&&(this.host._spaceDialog={...s,saved:s.saved.filter(s=>s.name!==t)})}catch(t){this.host._showToast(this.host._t("toast.plan_delete_failed",{err:this.host._errText(t)}))}}_renderServerPlans(t){if(t.savedBusy)return o`<div class="savedplans muted">${this.host._t("space.loading")}</div>`;const s=t.saved||[];if(!s.length)return o`<div class="savedplans muted">${this.host._t("space.no_saved")}</div>`;return o`<div class="savedplans">
${s.map(s=>{return o` ${s.map(s=>{return o`
<div class="savedplan ${s.url===t.planUrl?"cur":""}"> <div class="savedplan ${s.url===t.planUrl?"cur":""}">
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{c as a,A as e}from"./houseplan-card-CdCQB6rW.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-ClIYcGcH.js";import"./form-kit.styles-BW84Z22H.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show"> globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{c as a,A as e}from"./houseplan-card-DrP8_MdR.js";import{s,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-rHMkdk8Q.js";import"./form-kit.styles-1SWKbgIc.js";const m=m=>{const{host:c,dialog:d,problems:n,t:b}=m,y=n.find(a=>"error"===a.kind),$=d.localShow!==d.baseLocalShow||!d.localOnly&&!s(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(e=>e.path===a),h=a=>a?b(`summary.problem.${a.code}`):"",k=()=>m.close(),g=a`<label class="summary-switch" for="summary-local-show">
<span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong> <span class="summary-switch-caption"><strong>${b("summary.show_local")}</strong>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span> <small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox" <input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -0,0 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as c,b2 as l,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-DrP8_MdR.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,c="entity"===r?e.registry.entities?.[s]:null,l="device"===r?s:c?.device_id,d="device"===r?a?.area_id:c?.area_id||l&&e.registry.devices?.[l]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;l&&e.registry.devices?.[l]&&e.spaceIds.has(f)&&(!n.devices.has(l)||"entity"===r&&n.liveEntities.has(s))&&t.add(l)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=c(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:l(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*h(c,l,d=_){try{let u=0;for(const f of l){const l=c.spaces.find(e=>String(e?.id)===f.id);if(!l)continue;const m=e(l,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function p(e,t,n=_){const i=h(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function b(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{h as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,b as summarySystemValue,p as totalCleanFloorAreaM2};
@@ -1 +0,0 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{ed as e,J as t,b4 as n,H as i,aa as o,a8 as r,bU as s,bT as a,b3 as l,b2 as c,b5 as d,ee as u,ef as f,bW as m,eg as g}from"./houseplan-card-CdCQB6rW.js";function v(e){if(!e.registry.authoritative)return null;const t=new Set,n=d(e.markers);for(const i of Object.values(e.registry.devices||{}))i?.id&&"service"!==i.entry_type&&!n.devices.has(i.id)&&i.area_id&&e.areaToSpace[i.area_id]&&t.add(i.id);for(const i of e.markers||[]){if(i.removed||"virtual"===i.binding)continue;const o=String(i.binding||"").indexOf(":");if(o<1)continue;const r=i.binding.slice(0,o),s=i.binding.slice(o+1),a="device"===r?e.registry.devices?.[s]:null,l="entity"===r?e.registry.entities?.[s]:null,c="device"===r?s:l?.device_id,d="device"===r?a?.area_id:l?.area_id||c&&e.registry.devices?.[c]?.area_id,u="string"==typeof i.room_id&&i.room_id.length>0&&null===i.area?"":i.area||d||"",f=u&&e.areaToSpace[u]||i.space||e.firstSpaceId;c&&e.registry.devices?.[c]&&e.spaceIds.has(f)&&(!n.devices.has(c)||"entity"===r&&n.liveEntities.has(s))&&t.add(c)}return t}function y(e,t){return e?.length?t?.length?g(e,t):e:t}function _(e,t){const n=l(e.rooms,t.walls,t.openCuts,[],i,t.cellCm,o,r);return{roomGeom:"ok"===n.status||"degraded-extra"===n.status?n.roomGeom:void 0,multiWallNodes:c(e.rooms,t.walls,t.openCuts,i,t.cellCm,o,r)}}function*b(l,c,d=_){try{let u=0;for(const f of c){const c=l.spaces.find(e=>String(e?.id)===f.id);if(!c)continue;const m=e(c,f),g=d(f,m);let v=null;for(const e of f.rooms){if(!e.id)continue;const a=t(e);if(!a)continue;const l=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||a;v=y(v,s(l,m.physicalBodies)),yield}const _=m.cellCm/o;u+=a(v)*_*_/1e4}return u}catch{return null}}function h(e,t,n=_){const i=b(e,t,n);let o=i.next();for(;!o.done;)o=i.next();return o.value}function p(e,t,n,i){if("system"!==e.type)return null;if("device_count"===e.key)return null===t.deviceCount?null:String(t.deviceCount);if("total_area"===e.key)return null===t.areaM2?null:m(t.areaM2,"mi"===n?.config?.unit_system?.length);try{return new Intl.DateTimeFormat(i||void 0,{dateStyle:"short",timeStyle:"short",timeZone:n?.config?.time_zone||void 0}).format(t.now)}catch{return t.now.toLocaleString()}}function S(e,t){const n=e?.states?.[t];if(!n)return null;const i=u(e,t);return i?f(i,String(n.attributes?.unit_of_measurement||"")):null}export{b as cleanFloorAreaSteps,v as representedHaDeviceIds,_ as spaceWallGeometry,S as summaryEntityValue,p as summarySystemValue,h as totalCleanFloorAreaM2};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";import{n as t,b as n}from"./zigbee-topology-Km5WY9re.js";import{aR as e}from"./houseplan-card-CdCQB6rW.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot}; globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";import{n as t,b as n}from"./zigbee-topology-C-kzak0j.js";import{aR as e}from"./houseplan-card-DrP8_MdR.js";const o=new WeakMap;function i(t){const n=function(t){const n=t?.connection||t;return!n||"object"!=typeof n&&"function"!=typeof n?null:n}(t);if(!n)return null;let e=o.get(n);return e||(e={revision:0,topologies:[],states:{},listeners:new Set,inflight:new Map},o.set(n,e)),e}function r(t,n,e){t.states={...t.states,[n]:e},function(t){t.revision++;for(const n of t.listeners)n()}(t)}function s(t){const n=t?.code;if("permission"===n||"unsupported"===n||"timeout"===n||"invalid_topic"===n||"invalid_payload"===n)return n;const e=String(t?.message||"").toLowerCase();return e.includes("unauthor")||e.includes("permission")?"permission":e.includes("unknown_command")||e.includes("not found")?"unsupported":"provider"}function a(t){return Object.assign(new Error(t),{code:t})}function c(t,n,e){const o=t.inflight.get(n);if(o)return o;r(t,n,{phase:"loading"});const i=e().then(n=>{if(!n.nodes.length&&n.warnings.some(t=>"invalid_payload"===t.code))throw a("invalid_payload");!function(t,n){t.topologies=[...t.topologies.filter(t=>!(t.provider===n.provider&&t.instanceId===n.instanceId)),n],r(t,"zha"===n.provider?"zha":`z2m:${n.instanceId}`,{phase:"ready",obtainedAt:n.obtainedAt,partial:n.warnings.length>0})}(t,n)}).catch(e=>{r(t,n,{phase:"error",error:s(e)})}).finally(()=>t.inflight.delete(n));return t.inflight.set(n,i),i}function l(t){const n=i(t);return n?{revision:n.revision,topologies:n.topologies,states:n.states}:{revision:0,topologies:[],states:{}}}function u(t,n){const e=i(t);return e?(e.listeners.add(n),()=>e.listeners.delete(n)):()=>{}}function f(t){if(!0!==t?.user?.is_admin)throw a("permission")}function p(n){const e=i(n);return e?c(e,"zha",async()=>{if(f(n),"function"!=typeof n?.callWS)throw a("unsupported");return t(await n.callWS({type:"zha/devices"}))}):Promise.resolve()}function d(t){return null!==t&&"object"==typeof t?t:null}function h(t){const n=d(t),e=n?.payload??t;if("string"!=typeof e)return e;try{return JSON.parse(e)}catch{return null}}async function g(t,n){let e;try{return await Promise.race([t,new Promise((t,o)=>{e=globalThis.setTimeout(()=>o(a("timeout")),Math.max(1,n))})])}finally{void 0!==e&&globalThis.clearTimeout(e)}}function m(t,o,r=15e4){const s=i(t);if(!s)return Promise.resolve();const l=e(o);return c(s,`z2m:${l||String(o)}`,async()=>{if(f(t),!l)throw a("invalid_topic");const e=t.connection,o=e?.subscribeMessage;if("function"!=typeof o||"function"!=typeof t?.callService)throw a("unsupported");const i=function(){const t=globalThis.crypto;return"function"==typeof t?.randomUUID?`houseplan-${t.randomUUID()}`:`houseplan-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`}(),s=Date.now()+Math.max(1,r);let c=!1,u=null,p=null,m=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,m=n}),b=[];try{const r=await o.call(e,t=>{!0===d(t)?.retain&&h(t)&&u?.()},{type:"mqtt/subscribe",topic:`${l}/bridge/info`});"function"==typeof r&&b.push(r);const f=await o.call(e,t=>{if(!0===d(t)?.retain)return;const n=h(t);null!==n?n&&function(t){const n=d(t),e=n?.transaction??d(n?.data)?.transaction;return"string"==typeof e||"number"==typeof e?String(e):null}(n)===i&&p?.(n):c&&m?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await g(y,Math.min(4e3,Math.max(1,s-Date.now()))),c=!0,await t.callService("mqtt","publish",{topic:`${l}/bridge/request/networkmap`,payload:JSON.stringify({type:"raw",routes:!1,transaction:i}),qos:0,retain:!1});const v=await g(w,s-Date.now()),_=d(v)?.status;if(_&&"ok"!==_)throw a("provider");return n(v,l)}finally{for(const t of b)try{t()}catch{}}})}export{p as readZhaTopology,m as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
+1 -1
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="88da84dd09fee5495b5072706209ec23fcdbe5a196bca2dae5df8592f958faa9";try{await import("./houseplan-assets/houseplan-card-CdCQB6rW.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)} globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="f75fcd3764d3a1a73710cfa9cac88454a450e0d29e090f3339b5f5d853594786";try{await import("./houseplan-assets/houseplan-card-DrP8_MdR.js")}catch(e){if(!customElements.get("houseplan-card")){const l=String(navigator.language||"en").toLowerCase();const m=l.startsWith("ru")?"House Plan обновился — перезагрузите страницу (Ctrl+F5).":l.startsWith("de")?"House Plan wurde aktualisiert — bitte laden Sie die Seite neu (Strg+F5).":l.startsWith("fr")?"House Plan a été mis à jour — veuillez recharger la page (Ctrl+F5).":"House Plan was updated — please reload the page (Ctrl+F5).";customElements.define("houseplan-card",class extends HTMLElement{setConfig(){}getCardSize(){return 1}connectedCallback(){this.style.cssText="display:block;box-sizing:border-box;padding:16px;border:1px solid var(--divider-color,#e0e0e0);border-radius:var(--ha-card-border-radius,12px);background:var(--card-background-color,#fff);color:var(--primary-text-color,#212121);font:14px/1.4 var(--paper-font-body1_-_font-family,sans-serif)";this.textContent=m}})}console.error("[houseplan] stale houseplan-card.js: the implementation chunk is unavailable",e)}
+1 -1
View File
File diff suppressed because one or more lines are too long
+287 -180
View File
@@ -117,6 +117,8 @@ export interface IsoOverlayCollisionItem {
placement: IsoOverlayPlacement; placement: IsoOverlayPlacement;
/** Axis-aligned screen-facing half-size in scene units. */ /** Axis-aligned screen-facing half-size in scene units. */
screenHalfSize: PlanPoint; screenHalfSize: PlanPoint;
/** Previous exact result as an upper bound; every nearer event is still checked. */
nudgeHintCss?: ScenePoint;
} }
export interface IsoOverlayCollisionInput { export interface IsoOverlayCollisionInput {
@@ -201,15 +203,18 @@ function validRoom(room: IsoOverlayRoom): boolean {
&& roomArea(room) > EPS; && roomArea(room) > EPS;
} }
function pointStrictlyInRoom(point: PlanPoint, room: IsoOverlayRoom): boolean { function pointStrictlyInValidatedRoom(point: PlanPoint, room: IsoOverlayRoom): boolean {
if (!validRoom(room) || pointOnRing(point, room.outer) || !pointInRing(point, room.outer)) if (pointOnRing(point, room.outer) || !pointInRing(point, room.outer)) return false;
return false;
for (const hole of room.holes || []) { for (const hole of room.holes || []) {
if (pointOnRing(point, hole) || pointInRing(point, hole)) return false; if (pointOnRing(point, hole) || pointInRing(point, hole)) return false;
} }
return true; return true;
} }
function pointStrictlyInRoom(point: PlanPoint, room: IsoOverlayRoom): boolean {
return validRoom(room) && pointStrictlyInValidatedRoom(point, room);
}
function roomBoundaryDistance(point: PlanPoint, room: IsoOverlayRoom): number { function roomBoundaryDistance(point: PlanPoint, room: IsoOverlayRoom): number {
let distance = Infinity; let distance = Infinity;
for (const ring of [room.outer, ...(room.holes || [])]) { for (const ring of [room.outer, ...(room.holes || [])]) {
@@ -364,6 +369,20 @@ function ringBounds(ring: readonly (readonly number[])[]): Bounds | null {
return [minX, minY, maxX, maxY]; return [minX, minY, maxX, maxY];
} }
function axisAlignedRoomBox(room: IsoOverlayRoom): Bounds | null {
if (room.outer.length !== 4 || (room.holes?.length || 0) !== 0) return null;
const bounds = ringBounds(room.outer);
if (!bounds) return null;
const corners = new Set(room.outer.map((point) => {
const x = Math.abs(point[0] - bounds[0]) <= EPS ? 0
: Math.abs(point[0] - bounds[2]) <= EPS ? 1 : -1;
const y = Math.abs(point[1] - bounds[1]) <= EPS ? 0
: Math.abs(point[1] - bounds[3]) <= EPS ? 1 : -1;
return x < 0 || y < 0 ? '' : `${x}:${y}`;
}));
return corners.size === 4 && !corners.has('') ? bounds : null;
}
function silhouetteBounds(silhouette: IsoWallSilhouette, cache: boolean): Bounds | null { function silhouetteBounds(silhouette: IsoWallSilhouette, cache: boolean): Bounds | null {
if (!cache) return ringBounds(silhouette.outer); if (!cache) return ringBounds(silhouette.outer);
if (silhouetteBoundsCache.has(silhouette)) return silhouetteBoundsCache.get(silhouette) ?? null; if (silhouetteBoundsCache.has(silhouette)) return silhouetteBoundsCache.get(silhouette) ?? null;
@@ -419,6 +438,12 @@ function validSilhouette(silhouette: IsoWallSilhouette): boolean {
/** A straight nudge must never cut through a concavity or an island hole. */ /** A straight nudge must never cut through a concavity or an island hole. */
function segmentStrictlyInRoom(start: PlanPoint, end: PlanPoint, room: IsoOverlayRoom): boolean { function segmentStrictlyInRoom(start: PlanPoint, end: PlanPoint, room: IsoOverlayRoom): boolean {
if (!pointStrictlyInRoom(start, room) || !pointStrictlyInRoom(end, room)) return false; if (!pointStrictlyInRoom(start, room) || !pointStrictlyInRoom(end, room)) return false;
return segmentBetweenStrictRoomPoints(start, end, room);
}
function segmentBetweenStrictRoomPoints(
start: PlanPoint, end: PlanPoint, room: IsoOverlayRoom,
): boolean {
for (const ring of [room.outer, ...(room.holes || [])]) { for (const ring of [room.outer, ...(room.holes || [])]) {
for (let index = 0; index < ring.length; index++) { for (let index = 0; index < ring.length; index++) {
if (segmentsIntersect(start, end, ring[index], ring[(index + 1) % ring.length])) if (segmentsIntersect(start, end, ring[index], ring[(index + 1) % ring.length]))
@@ -640,9 +665,22 @@ const ISO_OVERLAY_GROUP_CELL_CSS_PX = 64;
/** Candidate displacement together with its stable distance ordering. */ /** Candidate displacement together with its stable distance ordering. */
interface GroupOffset { readonly offset: ScenePoint; readonly distance: number } interface GroupOffset { readonly offset: ScenePoint; readonly distance: number }
type BoundaryCandidateMap = Map<string, ScenePoint>; type BoundaryCandidateMap = {
readonly points: Map<number | string, ScenePoint>;
readonly pending: ScenePoint[];
};
function boundaryCandidateKey(x: number, y: number): string { function createBoundaryCandidates(): BoundaryCandidateMap {
return { points: new Map(), pending: [] };
}
function boundaryCandidateKey(x: number, y: number): number | string {
// Production is bounded by 48 CSS px. Keep that hot path on V8's numeric
// Map representation; the string fallback preserves the helper's general
// finite-input contract without admitting packed-key collisions.
if (Number.isInteger(x) && Number.isInteger(y)
&& x >= -32768 && x <= 32767 && y >= -32768 && y <= 32767)
return (x + 32768) * 65536 + y + 32768;
return `${x}:${y}`; return `${x}:${y}`;
} }
@@ -664,7 +702,11 @@ function addBoundaryCandidate(
if (candidateX * candidateX + candidateY * candidateY > maxNudge * maxNudge + EPS) if (candidateX * candidateX + candidateY * candidateY > maxNudge * maxNudge + EPS)
continue; continue;
const key = boundaryCandidateKey(candidateX, candidateY); const key = boundaryCandidateKey(candidateX, candidateY);
if (!candidates.has(key)) candidates.set(key, [candidateX, candidateY]); if (!candidates.points.has(key)) {
const point: ScenePoint = [candidateX, candidateY];
candidates.points.set(key, point);
candidates.pending.push(point);
}
} }
} }
} }
@@ -695,23 +737,26 @@ function clipBoundarySegment(
]; ];
} }
function addBoundaryRectangleEvents( function addBoundaryRectangle(
candidates: BoundaryCandidateMap, rectangles: readonly Bounds[], maxNudge: number, candidates: BoundaryCandidateMap, bounds: Bounds, maxNudge: number,
): void {
addBoundaryCandidate(candidates,
[bounds[0], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[bounds[2], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[1]], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[3]], maxNudge);
}
function addBoundaryRectangleIntersections(
candidates: BoundaryCandidateMap, left: Bounds, right: Bounds, maxNudge: number,
): void { ): void {
for (const bounds of rectangles) {
addBoundaryCandidate(candidates,
[bounds[0], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[bounds[2], Math.max(bounds[1], Math.min(0, bounds[3]))], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[1]], maxNudge);
addBoundaryCandidate(candidates,
[Math.max(bounds[0], Math.min(0, bounds[2])), bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[1]], maxNudge);
addBoundaryCandidate(candidates, [bounds[2], bounds[3]], maxNudge);
addBoundaryCandidate(candidates, [bounds[0], bounds[3]], maxNudge);
}
// Only intersections of FINITE rectangle edges are critical. Combining // Only intersections of FINITE rectangle edges are critical. Combining
// every X with every unrelated Y forms an artificial O(n²) interior grid; // every X with every unrelated Y forms an artificial O(n²) interior grid;
// on the 200-device benchmark it produced almost five thousand candidates // on the 200-device benchmark it produced almost five thousand candidates
@@ -725,10 +770,19 @@ function addBoundaryRectangleEvents(
} }
} }
}; };
addIntersections(left, right);
addIntersections(right, left);
}
function addBoundaryRectangleEvents(
candidates: BoundaryCandidateMap, rectangles: readonly Bounds[], maxNudge: number,
): void {
for (const bounds of rectangles) addBoundaryRectangle(candidates, bounds, maxNudge);
for (let left = 0; left < rectangles.length; left++) { for (let left = 0; left < rectangles.length; left++) {
for (let right = left + 1; right < rectangles.length; right++) { for (let right = left + 1; right < rectangles.length; right++) {
addIntersections(rectangles[left], rectangles[right]); addBoundaryRectangleIntersections(
addIntersections(rectangles[right], rectangles[left]); candidates, rectangles[left], rectangles[right], maxNudge,
);
} }
} }
} }
@@ -743,7 +797,7 @@ export function buildIsoOverlayBoundaryCandidates(
): readonly ScenePoint[] { ): readonly ScenePoint[] {
if (!(maxNudge >= 0) || !Number.isFinite(maxNudge)) if (!(maxNudge >= 0) || !Number.isFinite(maxNudge))
throw new Error('invalid isometric overlay boundary input'); throw new Error('invalid isometric overlay boundary input');
const candidates: BoundaryCandidateMap = new Map(); const candidates = createBoundaryCandidates();
addBoundaryRectangleEvents(candidates, rectangles, maxNudge); addBoundaryRectangleEvents(candidates, rectangles, maxNudge);
return Object.freeze(sortedBoundaryCandidates(candidates).map(({ offset }) => return Object.freeze(sortedBoundaryCandidates(candidates).map(({ offset }) =>
Object.freeze(offset) as ScenePoint)); Object.freeze(offset) as ScenePoint));
@@ -780,55 +834,57 @@ function addCriticalBoundaryRectangle(
type BoundarySegment = readonly [start: ScenePoint, end: ScenePoint]; type BoundarySegment = readonly [start: ScenePoint, end: ScenePoint];
function addBoundarySegmentRectangleIntersections( function addBoundarySegmentRectangleIntersection(
candidates: BoundaryCandidateMap, segment: BoundarySegment, candidates: BoundaryCandidateMap, segment: BoundarySegment,
rectangles: readonly Bounds[], maxNudge: number, bounds: Bounds, maxNudge: number,
): void { ): void {
const [start, end] = segment; const [start, end] = segment;
const dx = end[0] - start[0], dy = end[1] - start[1]; const dx = end[0] - start[0], dy = end[1] - start[1];
for (const bounds of rectangles) { if (Math.abs(dx) > EPS) {
if (Math.abs(dx) > EPS) { for (const x of [bounds[0], bounds[2]]) {
for (const x of [bounds[0], bounds[2]]) { const ratio = (x - start[0]) / dx;
const ratio = (x - start[0]) / dx; if (ratio < -EPS || ratio > 1 + EPS) continue;
if (ratio < -EPS || ratio > 1 + EPS) continue; const y = start[1] + dy * ratio;
const y = start[1] + dy * ratio; if (y >= bounds[1] - EPS && y <= bounds[3] + EPS)
if (y >= bounds[1] - EPS && y <= bounds[3] + EPS) addBoundaryCandidate(candidates, [x, y], maxNudge);
addBoundaryCandidate(candidates, [x, y], maxNudge);
}
} }
if (Math.abs(dy) > EPS) { }
for (const y of [bounds[1], bounds[3]]) { if (Math.abs(dy) > EPS) {
const ratio = (y - start[1]) / dy; for (const y of [bounds[1], bounds[3]]) {
if (ratio < -EPS || ratio > 1 + EPS) continue; const ratio = (y - start[1]) / dy;
const x = start[0] + dx * ratio; if (ratio < -EPS || ratio > 1 + EPS) continue;
if (x >= bounds[0] - EPS && x <= bounds[2] + EPS) const x = start[0] + dx * ratio;
addBoundaryCandidate(candidates, [x, y], maxNudge); if (x >= bounds[0] - EPS && x <= bounds[2] + EPS)
} addBoundaryCandidate(candidates, [x, y], maxNudge);
} }
} }
} }
function addBoundaryLineIntersections( function addBoundarySegmentRectangleIntersections(
candidates: BoundaryCandidateMap, segments: readonly BoundarySegment[], maxNudge: number, candidates: BoundaryCandidateMap, segment: BoundarySegment,
rectangles: readonly Bounds[], maxNudge: number,
): void { ): void {
for (let left = 0; left < segments.length; left++) { for (const bounds of rectangles)
const [a, b] = segments[left]; addBoundarySegmentRectangleIntersection(candidates, segment, bounds, maxNudge);
const ab: ScenePoint = [b[0] - a[0], b[1] - a[1]]; }
for (let right = left + 1; right < segments.length; right++) {
const [c, d] = segments[right]; function addBoundaryLineIntersection(
const cd: ScenePoint = [d[0] - c[0], d[1] - c[1]]; candidates: BoundaryCandidateMap, left: BoundarySegment,
const denominator = ab[0] * cd[1] - ab[1] * cd[0]; right: BoundarySegment, maxNudge: number,
if (Math.abs(denominator) <= EPS) continue; ): void {
const ac: ScenePoint = [c[0] - a[0], c[1] - a[1]]; const [a, b] = left, [c, d] = right;
const ratio = (ac[0] * cd[1] - ac[1] * cd[0]) / denominator; const ab: ScenePoint = [b[0] - a[0], b[1] - a[1]];
const otherRatio = (ac[0] * ab[1] - ac[1] * ab[0]) / denominator; const cd: ScenePoint = [d[0] - c[0], d[1] - c[1]];
if (ratio < -EPS || ratio > 1 + EPS const denominator = ab[0] * cd[1] - ab[1] * cd[0];
|| otherRatio < -EPS || otherRatio > 1 + EPS) continue; if (Math.abs(denominator) <= EPS) return;
const point: ScenePoint = [a[0] + ab[0] * ratio, a[1] + ab[1] * ratio]; const ac: ScenePoint = [c[0] - a[0], c[1] - a[1]];
if (Math.hypot(point[0], point[1]) <= maxNudge + 2) const ratio = (ac[0] * cd[1] - ac[1] * cd[0]) / denominator;
addBoundaryCandidate(candidates, point, maxNudge); const otherRatio = (ac[0] * ab[1] - ac[1] * ab[0]) / denominator;
} if (ratio < -EPS || ratio > 1 + EPS
} || otherRatio < -EPS || otherRatio > 1 + EPS) return;
const point: ScenePoint = [a[0] + ab[0] * ratio, a[1] + ab[1] * ratio];
if (Math.hypot(point[0], point[1]) <= maxNudge + 2)
addBoundaryCandidate(candidates, point, maxNudge);
} }
/** /**
@@ -837,11 +893,20 @@ function addBoundaryLineIntersections(
* the straight part of the Minkowski boundary; the final polygon predicate * the straight part of the Minkowski boundary; the final polygon predicate
* still decides legality around vertices and concavities. * still decides legality around vertices and concavities.
*/ */
function addExpandedWallBoundarySegments( type WallBoundaryEdge = {
candidates: BoundaryCandidateMap, wall: IsoWallSilhouette, readonly tangent: ScenePoint;
footprint: readonly ScenePoint[], gapUnits: number, unitsPerPixel: number, readonly normal: ScenePoint;
maxNudge: number, rectangles: readonly Bounds[], segments?: BoundarySegment[], readonly tangentMin: number;
): void { readonly tangentMax: number;
readonly normalOffset: number;
};
const wallBoundaryEdgeCache = new WeakMap<IsoWallSilhouette, readonly WallBoundaryEdge[]>();
function wallBoundaryEdges(wall: IsoWallSilhouette): readonly WallBoundaryEdge[] {
const cached = wallBoundaryEdgeCache.get(wall);
if (cached) return cached;
const result: WallBoundaryEdge[] = [];
for (const ring of [wall.outer, ...(wall.holes || [])]) { for (const ring of [wall.outer, ...(wall.holes || [])]) {
for (let index = 0; index < ring.length; index++) { for (let index = 0; index < ring.length; index++) {
const wallStart = ring[index], wallEnd = ring[(index + 1) % ring.length]; const wallStart = ring[index], wallEnd = ring[(index + 1) % ring.length];
@@ -850,20 +915,43 @@ function addExpandedWallBoundarySegments(
if (edgeLength <= EPS) continue; if (edgeLength <= EPS) continue;
const tangent: ScenePoint = [edgeX / edgeLength, edgeY / edgeLength]; const tangent: ScenePoint = [edgeX / edgeLength, edgeY / edgeLength];
const normal: ScenePoint = [-tangent[1], tangent[0]]; const normal: ScenePoint = [-tangent[1], tangent[0]];
const tangentStart = wallStart[0] * tangent[0] + wallStart[1] * tangent[1];
const tangentEnd = wallEnd[0] * tangent[0] + wallEnd[1] * tangent[1];
result.push({
tangent, normal,
tangentMin: Math.min(tangentStart, tangentEnd),
tangentMax: Math.max(tangentStart, tangentEnd),
normalOffset: wallStart[0] * normal[0] + wallStart[1] * normal[1],
});
}
}
wallBoundaryEdgeCache.set(wall, result);
return result;
}
function addExpandedWallBoundarySegments(
candidates: BoundaryCandidateMap, wall: IsoWallSilhouette,
footprint: readonly ScenePoint[], gapUnits: number, unitsPerPixel: number,
maxNudge: number, rectangles: readonly Bounds[], segments?: BoundarySegment[],
): void {
for (const edge of wallBoundaryEdges(wall)) {
const { tangent, normal } = edge;
const dot = (point: readonly number[], axis: ScenePoint): number => const dot = (point: readonly number[], axis: ScenePoint): number =>
point[0] * axis[0] + point[1] * axis[1]; point[0] * axis[0] + point[1] * axis[1];
const wallTangentStart = dot(wallStart, tangent); let footprintTangentMin = Infinity, footprintTangentMax = -Infinity;
const wallTangentEnd = dot(wallEnd, tangent); let footprintNormalMin = Infinity, footprintNormalMax = -Infinity;
const wallTangentMin = Math.min(wallTangentStart, wallTangentEnd); for (const point of footprint) {
const wallTangentMax = Math.max(wallTangentStart, wallTangentEnd); const tangentOffset = dot(point, tangent), normalOffset = dot(point, normal);
const wallNormal = dot(wallStart, normal); footprintTangentMin = Math.min(footprintTangentMin, tangentOffset);
const footprintTangents = footprint.map((point) => dot(point, tangent)); footprintTangentMax = Math.max(footprintTangentMax, tangentOffset);
const footprintNormals = footprint.map((point) => dot(point, normal)); footprintNormalMin = Math.min(footprintNormalMin, normalOffset);
const tangentMin = wallTangentMin - Math.max(...footprintTangents) - gapUnits; footprintNormalMax = Math.max(footprintNormalMax, normalOffset);
const tangentMax = wallTangentMax - Math.min(...footprintTangents) + gapUnits; }
const tangentMin = edge.tangentMin - footprintTangentMax - gapUnits;
const tangentMax = edge.tangentMax - footprintTangentMin + gapUnits;
const normalOffsets = [ const normalOffsets = [
wallNormal - gapUnits - Math.max(...footprintNormals), edge.normalOffset - gapUnits - footprintNormalMax,
wallNormal + gapUnits - Math.min(...footprintNormals), edge.normalOffset + gapUnits - footprintNormalMin,
]; ];
for (const normalOffset of normalOffsets) { for (const normalOffset of normalOffsets) {
const toPoint = (tangentOffset: number): ScenePoint => [ const toPoint = (tangentOffset: number): ScenePoint => [
@@ -880,7 +968,6 @@ function addExpandedWallBoundarySegments(
candidates, clipped, rectangles, maxNudge, candidates, clipped, rectangles, maxNudge,
); );
} }
}
} }
} }
@@ -902,31 +989,12 @@ function addBoundaryCircle(
} }
function sortedBoundaryCandidates(candidates: BoundaryCandidateMap): GroupOffset[] { function sortedBoundaryCandidates(candidates: BoundaryCandidateMap): GroupOffset[] {
return [...candidates.values()].map((offset) => ({ return [...candidates.points.values()].map((offset) => ({
offset, distance: Math.hypot(offset[0], offset[1]), offset, distance: Math.hypot(offset[0], offset[1]),
})).sort((a, b) => a.distance - b.distance })).sort((a, b) => a.distance - b.distance
|| a.offset[1] - b.offset[1] || a.offset[0] - b.offset[0]); || a.offset[1] - b.offset[1] || a.offset[0] - b.offset[0]);
} }
/**
* Snap a continuous boundary event back to the exact integer-pixel result.
* The bounded 9x9 neighbourhood replaces the old complete 7,238-point disk.
*/
function localRefinementOffsets(
around: ScenePoint, maxNudge: number, reach = 4,
): readonly GroupOffset[] {
const offsets: GroupOffset[] = [];
for (let y = Math.floor(around[1] - reach); y <= Math.ceil(around[1] + reach); y++) {
for (let x = Math.floor(around[0] - reach); x <= Math.ceil(around[0] + reach); x++) {
const distance = Math.hypot(x, y);
if (distance <= maxNudge + EPS) offsets.push({ offset: [x, y], distance });
}
}
offsets.sort((a, b) => a.distance - b.distance
|| a.offset[1] - b.offset[1] || a.offset[0] - b.offset[0]);
return offsets;
}
function overlayRootBounds( function overlayRootBounds(
item: IsoOverlayCollisionItem, center: ScenePoint, item: IsoOverlayCollisionItem, center: ScenePoint,
): Bounds { ): Bounds {
@@ -1024,14 +1092,29 @@ export function resolveIsoOverlayCollisions(
const gapUnits = safetyGap * unitsPerPixel; const gapUnits = safetyGap * unitsPerPixel;
const cellUnits = ISO_OVERLAY_GROUP_CELL_CSS_PX * unitsPerPixel; const cellUnits = ISO_OVERLAY_GROUP_CELL_CSS_PX * unitsPerPixel;
const rooms = new Map(input.rooms.filter(validRoom).map((room) => [room.id, room])); const rooms = new Map(input.rooms.filter(validRoom).map((room) => [room.id, room]));
const roomBounds = new Map([...rooms].map(([id, room]) => [
id, ringBounds(room.outer as readonly ScenePoint[]),
]));
const axisAlignedRoomBoxes = new Map([...rooms].flatMap(([id, room]) => {
const bounds = axisAlignedRoomBox(room);
return bounds ? [[id, bounds] as const] : [];
}));
const wallsValid = input.wallSilhouettes.every(validSilhouette); const wallsValid = input.wallSilhouettes.every(validSilhouette);
const wallRows = input.wallSilhouettes.map((wall) => ({
wall, bounds: silhouetteBounds(wall, true),
}));
const accepted: AcceptedOverlay[] = []; const accepted: AcceptedOverlay[] = [];
const cells = new Map<string, number[]>(); const cells = new Map<number | string, number[]>();
const placements = new Map<string, IsoOverlayPlacement>(); const placements = new Map<string, IsoOverlayPlacement>();
const residualPairs: Array<readonly [string, string]> = []; const residualPairs: Array<readonly [string, string]> = [];
const stableItems = [...input.items].sort((a, b) => const stableItems = [...input.items].sort((a, b) =>
a.placement.nudgeDistanceCss - b.placement.nudgeDistanceCss a.placement.nudgeDistanceCss - b.placement.nudgeDistanceCss
|| isoOverlayCollisionKey(a.kind, a.id).localeCompare(isoOverlayCollisionKey(b.kind, b.id))); || isoOverlayCollisionKey(a.kind, a.id).localeCompare(isoOverlayCollisionKey(b.kind, b.id)));
const rot = camera.rotDeg * Math.PI / 180;
const tilt = camera.tiltDeg * Math.PI / 180;
const inverseX = 1 / camera.xyScale;
const inverseY = 1 / (camera.xyScale * Math.cos(tilt));
const cosRot = Math.cos(rot), sinRot = Math.sin(rot);
const cellRange = (bounds: Bounds): readonly [number, number, number, number] => [ const cellRange = (bounds: Bounds): readonly [number, number, number, number] => [
Math.floor(bounds[0] / cellUnits), Math.floor(bounds[1] / cellUnits), Math.floor(bounds[0] / cellUnits), Math.floor(bounds[1] / cellUnits),
@@ -1042,7 +1125,7 @@ export function resolveIsoOverlayCollisions(
const result = new Set<number>(); const result = new Set<number>();
for (let y = minY; y <= maxY; y++) { for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) { for (let x = minX; x <= maxX; x++) {
for (const index of cells.get(`${x}:${y}`) || []) result.add(index); for (const index of cells.get(boundaryCandidateKey(x, y)) || []) result.add(index);
} }
} }
return [...result].sort((a, b) => a - b); return [...result].sort((a, b) => a - b);
@@ -1052,7 +1135,7 @@ export function resolveIsoOverlayCollisions(
const [minX, minY, maxX, maxY] = cellRange(value.bounds); const [minX, minY, maxX, maxY] = cellRange(value.bounds);
for (let y = minY; y <= maxY; y++) { for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) { for (let x = minX; x <= maxX; x++) {
const key = `${x}:${y}`; const key = boundaryCandidateKey(x, y);
const list = cells.get(key) || []; const list = cells.get(key) || [];
list.push(index); list.push(index);
cells.set(key, list); cells.set(key, list);
@@ -1072,16 +1155,15 @@ export function resolveIsoOverlayCollisions(
] as ScenePoint); ] as ScenePoint);
const ownerRoom = base.owner ? rooms.get(base.owner.id) || null : null; const ownerRoom = base.owner ? rooms.get(base.owner.id) || null : null;
const currentPlan = raisedSceneToPlan(base.visualScene, visualOffset, camera); const currentPlan = raisedSceneToPlan(base.visualScene, visualOffset, camera);
const baseFootprintBounds = ringBounds(baseFootprint);
const wallCandidates = wallsValid && baseFootprint.length const wallCandidates = wallsValid && baseFootprint.length
? input.wallSilhouettes.filter((wall) => { ? wallRows.filter(({ bounds: wallBounds }) => {
const wallBounds = silhouetteBounds(wall, true);
if (!wallBounds) return false; if (!wallBounds) return false;
const radius = maxNudge * unitsPerPixel; const radius = maxNudge * unitsPerPixel;
const footprintBounds = ringBounds(baseFootprint); return !!baseFootprintBounds && boundsNear(expandedBounds(baseFootprintBounds, radius),
return !!footprintBounds && boundsNear(expandedBounds(footprintBounds, radius),
wallBounds, gapUnits); wallBounds, gapUnits);
}) })
: input.wallSilhouettes; : wallRows;
/** /**
* Дешёвая половина кандидата: где он окажется и с кем столкнётся. * Дешёвая половина кандидата: где он окажется и с кем столкнётся.
@@ -1147,8 +1229,16 @@ export function resolveIsoOverlayCollisions(
* съедала 8.5 из 9.6 секунд группового прохода. Подавляющее большинство * съедала 8.5 из 9.6 секунд группового прохода. Подавляющее большинство
* этих точек лежит ВНЕ комнаты — узнать это можно сравнением четырёх чисел, * этих точек лежит ВНЕ комнаты — узнать это можно сравнением четырёх чисел,
* а не обходом колец полигона и силуэтов стен. * а не обходом колец полигона и силуэтов стен.
*/ */
const ownerBox = ownerRoom ? ringBounds(ownerRoom.outer as readonly ScenePoint[]) : null; const ownerBox = ownerRoom ? roomBounds.get(ownerRoom.id) || null : null;
const ownerAxisBox = ownerRoom ? axisAlignedRoomBoxes.get(ownerRoom.id) || null : null;
const currentStrictlyInOwner = !!ownerRoom
&& (ownerAxisBox
? currentPlan[0] > ownerAxisBox[0] + EPS
&& currentPlan[0] < ownerAxisBox[2] - EPS
&& currentPlan[1] > ownerAxisBox[1] + EPS
&& currentPlan[1] < ownerAxisBox[3] - EPS
: pointStrictlyInValidatedRoom(currentPlan, ownerRoom));
/** /**
* Широкая фаза по стенам — то, чего требовал §6.4 ТЗ и чего не было. * Широкая фаза по стенам — то, чего требовал §6.4 ТЗ и чего не было.
@@ -1159,14 +1249,14 @@ export function resolveIsoOverlayCollisions(
* Стены раскладываются по тем же ячейкам, что и принятые оверлеи, и каждый * Стены раскладываются по тем же ячейкам, что и принятые оверлеи, и каждый
* кандидат смотрит только свои ячейки. * кандидат смотрит только свои ячейки.
*/ */
const wallCells = new Map<string, number[]>(); const wallCells = new Map<number | string, number[]>();
for (let index = 0; index < wallCandidates.length; index++) { for (let index = 0; index < wallCandidates.length; index++) {
const wallBounds = silhouetteBounds(wallCandidates[index], true); const wallBounds = wallCandidates[index].bounds;
if (!wallBounds) continue; if (!wallBounds) continue;
const [minX, minY, maxX, maxY] = cellRange(expandedBounds(wallBounds, gapUnits)); const [minX, minY, maxX, maxY] = cellRange(expandedBounds(wallBounds, gapUnits));
for (let y = minY; y <= maxY; y++) { for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) { for (let x = minX; x <= maxX; x++) {
const key = `${x}:${y}`; const key = boundaryCandidateKey(x, y);
const list = wallCells.get(key) || []; const list = wallCells.get(key) || [];
list.push(index); list.push(index);
wallCells.set(key, list); wallCells.set(key, list);
@@ -1177,52 +1267,79 @@ export function resolveIsoOverlayCollisions(
// стоит дороже самой проверки. // стоит дороже самой проверки.
const wallSeen = new Int32Array(wallCandidates.length); const wallSeen = new Int32Array(wallCandidates.length);
let wallSeenGeneration = 0; let wallSeenGeneration = 0;
const wallsNear = (bounds: Bounds): number[] => { const translatedFootprint = baseFootprint.map(() => [0, 0] as [number, number]);
const [minX, minY, maxX, maxY] = cellRange(expandedBounds(bounds, gapUnits)); const footprintAt = (offset: ScenePoint): readonly ScenePoint[] => {
const result: number[] = []; for (let index = 0; index < baseFootprint.length; index++) {
translatedFootprint[index][0] = baseFootprint[index][0] + offset[0];
translatedFootprint[index][1] = baseFootprint[index][1] + offset[1];
}
return translatedFootprint;
};
const firstWallNear = (
bounds: Bounds, footprint: () => readonly ScenePoint[],
): number | undefined => {
const minX = Math.floor((bounds[0] - gapUnits) / cellUnits);
const minY = Math.floor((bounds[1] - gapUnits) / cellUnits);
const maxX = Math.floor((bounds[2] + gapUnits) / cellUnits);
const maxY = Math.floor((bounds[3] + gapUnits) / cellUnits);
wallSeenGeneration += 1; wallSeenGeneration += 1;
for (let y = minY; y <= maxY; y++) { for (let y = minY; y <= maxY; y++) {
for (let x = minX; x <= maxX; x++) { for (let x = minX; x <= maxX; x++) {
for (const index of wallCells.get(`${x}:${y}`) || []) { for (const index of wallCells.get(boundaryCandidateKey(x, y)) || []) {
if (wallSeen[index] === wallSeenGeneration) continue; if (wallSeen[index] === wallSeenGeneration) continue;
wallSeen[index] = wallSeenGeneration; wallSeen[index] = wallSeenGeneration;
result.push(index); if (footprintNearSilhouette(
footprint(), bounds, wallCandidates[index].wall, gapUnits, true,
)) return index;
} }
} }
} }
return result; return undefined;
}; };
const INSPECTION_ALLOWED = -2;
const INSPECTION_ROOM = -1;
const inspectCandidate = (shape: { const inspectCandidate = (shape: {
offsetScene: ScenePoint; sameAsBase: boolean; visualScene: ScenePoint; offsetScene: ScenePoint; sameAsBase: boolean; visualScene: ScenePoint;
}): { allowed: boolean; walls: readonly number[]; room: boolean } => { }): number => {
if (shape.sameAsBase) return { allowed: true, walls: [], room: false }; if (shape.sameAsBase) return INSPECTION_ALLOWED;
if (!wallsValid || !ownerRoom) return { allowed: false, walls: [], room: true }; if (!wallsValid || !ownerRoom) return INSPECTION_ROOM;
const plan = raisedSceneToPlan(shape.visualScene, visualOffset, camera); const sceneDx = shape.visualScene[0] - base.visualScene[0];
if (ownerBox && (plan[0] < ownerBox[0] || plan[0] > ownerBox[2] const sceneDy = shape.visualScene[1] - base.visualScene[1];
|| plan[1] < ownerBox[1] || plan[1] > ownerBox[3])) const rx = sceneDx * inverseX, ry = sceneDy * inverseY;
return { allowed: false, walls: [], room: true }; const planX = currentPlan[0] + rx * cosRot + ry * sinRot;
if (!pointStrictlyInRoom(plan, ownerRoom)) const planY = currentPlan[1] - rx * sinRot + ry * cosRot;
return { allowed: false, walls: [], room: true }; if (ownerBox && (planX < ownerBox[0] || planX > ownerBox[2]
if (pointStrictlyInRoom(currentPlan, ownerRoom) || planY < ownerBox[1] || planY > ownerBox[3]))
&& !segmentStrictlyInRoom(currentPlan, plan, ownerRoom)) return INSPECTION_ROOM;
return { allowed: false, walls: [], room: true }; if (ownerAxisBox) {
const footprint = baseFootprint.map((point) => [ if (!(planX > ownerAxisBox[0] + EPS && planX < ownerAxisBox[2] - EPS
point[0] + shape.offsetScene[0], point[1] + shape.offsetScene[1], && planY > ownerAxisBox[1] + EPS && planY < ownerAxisBox[3] - EPS))
] as ScenePoint); return INSPECTION_ROOM;
const footprintBounds = ringBounds(footprint); } else {
if (!footprintBounds) return { allowed: false, walls: [], room: true }; const plan: PlanPoint = [planX, planY];
const wall = wallsNear(footprintBounds).find((index) => if (!pointStrictlyInValidatedRoom(plan, ownerRoom))
footprintNearSilhouette( return INSPECTION_ROOM;
footprint, footprintBounds, wallCandidates[index], gapUnits, true, if (currentStrictlyInOwner
)); && !segmentBetweenStrictRoomPoints(currentPlan, plan, ownerRoom))
return wall === undefined return INSPECTION_ROOM;
? { allowed: true, walls: [], room: false } }
: { allowed: false, walls: [wall], room: false }; if (!baseFootprintBounds) return INSPECTION_ROOM;
const footprintBounds: Bounds = [
baseFootprintBounds[0] + shape.offsetScene[0],
baseFootprintBounds[1] + shape.offsetScene[1],
baseFootprintBounds[2] + shape.offsetScene[0],
baseFootprintBounds[3] + shape.offsetScene[1],
];
let footprint: readonly ScenePoint[] | null = null;
const wall = firstWallNear(
footprintBounds, () => footprint ||= footprintAt(shape.offsetScene),
);
return wall === undefined ? INSPECTION_ALLOWED : wall;
}; };
const candidateAllowed = (shape: { const candidateAllowed = (shape: {
offsetScene: ScenePoint; sameAsBase: boolean; visualScene: ScenePoint; offsetScene: ScenePoint; sameAsBase: boolean; visualScene: ScenePoint;
}): boolean => inspectCandidate(shape).allowed; }): boolean => inspectCandidate(shape) === INSPECTION_ALLOWED;
const candidate = (offsetCss: ScenePoint): { const candidate = (offsetCss: ScenePoint): {
placement: IsoOverlayPlacement; placement: IsoOverlayPlacement;
@@ -1238,8 +1355,13 @@ export function resolveIsoOverlayCollisions(
}; };
}; };
let best = candidate(baseOffsetCss); const baseCandidate = candidate(baseOffsetCss);
let best = baseCandidate;
if (!best || best.conflicts.length) { if (!best || best.conflicts.length) {
const hinted = item.nudgeHintCss ? candidate(item.nudgeHintCss) : null;
if (hinted && !hinted.conflicts.length) best = hinted;
}
if (!baseCandidate || baseCandidate.conflicts.length) {
/** /**
* A nearest free point must touch the boundary of the forbidden union. * A nearest free point must touch the boundary of the forbidden union.
* Enumerate those one-dimensional boundaries instead of the 7238 points * Enumerate those one-dimensional boundaries instead of the 7238 points
@@ -1247,12 +1369,12 @@ export function resolveIsoOverlayCollisions(
* preserve the old integer result even when a legal slit is narrower * preserve the old integer result even when a legal slit is narrower
* than the former 4 px coarse grid. * than the former 4 px coarse grid.
*/ */
const boundaryCandidates: BoundaryCandidateMap = new Map(); const boundaryCandidates = createBoundaryCandidates();
const overlayBoundaryRectangles: Bounds[] = []; const overlayBoundaryRectangles: Bounds[] = [];
const boundaryRectangles: Bounds[] = []; const boundaryRectangles: Bounds[] = [];
const boundarySegments: BoundarySegment[] = []; const boundarySegments: BoundarySegment[] = [];
const expandedOverlayBoundaries = new Set<number>(); const expandedOverlayBoundaries = new Set<number>();
const encounteredOverlayBoundaries = new Set<number>(best?.conflicts || []); const encounteredOverlayBoundaries = new Set<number>(baseCandidate?.conflicts || []);
const addOverlayBoundary = (index: number): void => { const addOverlayBoundary = (index: number): void => {
if (expandedOverlayBoundaries.has(index)) return; if (expandedOverlayBoundaries.has(index)) return;
expandedOverlayBoundaries.add(index); expandedOverlayBoundaries.add(index);
@@ -1271,15 +1393,13 @@ export function resolveIsoOverlayCollisions(
boundaryRectangles.push(rectangle); boundaryRectangles.push(rectangle);
}; };
const footprintBounds = ringBounds(baseFootprint); const footprintBounds = baseFootprintBounds;
const expandedWalls = new Set<number>(); const expandedWalls = new Set<number>();
const pendingWalls = new Set<number>(); const pendingWalls = new Set<number>();
const evaluated = new Set<string>();
const addWallBoundary = (index: number): void => { const addWallBoundary = (index: number): void => {
if (expandedWalls.has(index) || !footprintBounds) return; if (expandedWalls.has(index) || !footprintBounds) return;
expandedWalls.add(index); expandedWalls.add(index);
const wall = wallCandidates[index]; const { wall, bounds: wallBounds } = wallCandidates[index];
const wallBounds = silhouetteBounds(wall, true);
if (wallBounds) { if (wallBounds) {
const expandedWallBounds: Bounds = [ const expandedWallBounds: Bounds = [
(wallBounds[0] - gapUnits - footprintBounds[2]) / unitsPerPixel, (wallBounds[0] - gapUnits - footprintBounds[2]) / unitsPerPixel,
@@ -1333,24 +1453,26 @@ export function resolveIsoOverlayCollisions(
boundaryCandidates, [boundaryRectangles[index]], maxNudge, boundaryCandidates, [boundaryRectangles[index]], maxNudge,
); );
for (let previous = 0; previous < index; previous++) for (let previous = 0; previous < index; previous++)
addBoundaryRectangleEvents(boundaryCandidates, [ addBoundaryRectangleIntersections(
boundaryRectangles[previous], boundaryRectangles[index], boundaryCandidates, boundaryRectangles[previous],
], maxNudge); boundaryRectangles[index], maxNudge,
);
} }
// Concave silhouettes and the safety-gap rounding meet where finite // Concave silhouettes and the safety-gap rounding meet where finite
// boundary segments cross. Exact polygons still make the final call. // boundary segments cross. Exact polygons still make the final call.
for (let index = processedSegments; index < boundarySegments.length; index++) { for (let index = processedSegments; index < boundarySegments.length; index++) {
for (let previous = 0; previous < index; previous++) for (let previous = 0; previous < index; previous++)
addBoundaryLineIntersections(boundaryCandidates, [ addBoundaryLineIntersection(
boundarySegments[previous], boundarySegments[index], boundaryCandidates, boundarySegments[previous],
], maxNudge); boundarySegments[index], maxNudge,
);
} }
for (let index = processedOverlayRectangles; for (let index = processedOverlayRectangles;
index < overlayBoundaryRectangles.length; index++) { index < overlayBoundaryRectangles.length; index++) {
for (let segment = 0; segment < processedSegments; segment++) for (let segment = 0; segment < processedSegments; segment++)
addBoundarySegmentRectangleIntersections( addBoundarySegmentRectangleIntersection(
boundaryCandidates, boundarySegments[segment], boundaryCandidates, boundarySegments[segment],
[overlayBoundaryRectangles[index]], maxNudge, overlayBoundaryRectangles[index], maxNudge,
); );
} }
for (let index = processedSegments; index < boundarySegments.length; index++) for (let index = processedSegments; index < boundarySegments.length; index++)
@@ -1364,9 +1486,8 @@ export function resolveIsoOverlayCollisions(
}; };
const evaluateNewCandidates = (): void => { const evaluateNewCandidates = (): void => {
const entries = [...boundaryCandidates.entries()] const entries = boundaryCandidates.pending.splice(0)
.filter(([key]) => !evaluated.has(key)) .map((offset) => ({
.map(([, offset]) => ({
offset, distance: Math.hypot(offset[0], offset[1]), offset, distance: Math.hypot(offset[0], offset[1]),
})) }))
.sort((a, b) => a.distance - b.distance .sort((a, b) => a.distance - b.distance
@@ -1379,9 +1500,6 @@ export function resolveIsoOverlayCollisions(
? best.placement.nudgeDistanceCss : Infinity; ? best.placement.nudgeDistanceCss : Infinity;
if (entry.distance > maxNudge + EPS || entry.distance > bestFreeDistance + EPS) break; if (entry.distance > maxNudge + EPS || entry.distance > bestFreeDistance + EPS) break;
const offset = entry.offset; const offset = entry.offset;
const key = boundaryCandidateKey(offset[0], offset[1]);
if (evaluated.has(key)) continue;
evaluated.add(key);
if (Math.abs(offset[0] - baseOffsetCss[0]) <= EPS if (Math.abs(offset[0] - baseOffsetCss[0]) <= EPS
&& Math.abs(offset[1] - baseOffsetCss[1]) <= EPS) continue; && Math.abs(offset[1] - baseOffsetCss[1]) <= EPS) continue;
const shape = candidateShape(offset); const shape = candidateShape(offset);
@@ -1394,8 +1512,9 @@ export function resolveIsoOverlayCollisions(
|| best.conflicts.length && shape.penalty < best.penalty - EPS; || best.conflicts.length && shape.penalty < best.penalty - EPS;
if (!canWin) continue; if (!canWin) continue;
const inspection = inspectCandidate(shape); const inspection = inspectCandidate(shape);
if (!inspection.allowed) { if (inspection !== INSPECTION_ALLOWED) {
for (const wallIndex of inspection.walls) { if (inspection >= 0) {
const wallIndex = inspection;
if (expandedWalls.has(wallIndex)) continue; if (expandedWalls.has(wallIndex)) continue;
const witness = { const witness = {
index: wallIndex, index: wallIndex,
@@ -1461,18 +1580,6 @@ export function resolveIsoOverlayCollisions(
refreshBoundaryEvents(); refreshBoundaryEvents();
evaluateNewCandidates(); evaluateNewCandidates();
} }
if (best && !best.conflicts.length) {
const around = best.placement.nudgeCss;
for (const entry of localRefinementOffsets(around, maxNudge)) {
if (entry.distance >= best.placement.nudgeDistanceCss - EPS) break;
const shape = candidateShape(entry.offset);
if (!shape || shape.conflicts.length || !candidateAllowed(shape)) continue;
best = {
placement: placementAtGroupOffset(base, entry.offset, unitsPerPixel, false),
bounds: shape.bounds, conflicts: shape.conflicts, penalty: shape.penalty,
};
}
}
} }
if (!best) { if (!best) {
const placement = placementAtGroupOffset(base, baseOffsetCss, unitsPerPixel, true); const placement = placementAtGroupOffset(base, baseOffsetCss, unitsPerPixel, true);
+24 -6
View File
@@ -974,13 +974,31 @@ export function buildIsoOverlayRenderScene(input: IsoOverlaySceneInput): IsoOver
if (previous?.collisionSignature === collisionSignature if (previous?.collisionSignature === collisionSignature
&& samePlacementMap(previous.rooms, roomPlacements)) return previous; && samePlacementMap(previous.rooms, roomPlacements)) return previous;
const previousEntries = new Map(previous?.entries.map((entry) => [
`${entry.kind}\u0000${entry.id}`, entry,
]) || []);
const collision = mode === 'live' ? resolveIsoOverlayCollisions({ const collision = mode === 'live' ? resolveIsoOverlayCollisions({
items: entries.flatMap((entry) => entry.kind === 'room-label' ? [] : [{ items: entries.flatMap((entry) => {
id: entry.id, if (entry.kind === 'room-label') return [];
kind: entry.kind, const before = previousEntries.get(`${entry.kind}\u0000${entry.id}`);
placement: entry.placement, const sameShape = !!before
screenHalfSize: entry.screenHalfSize, && before.screenHalfSize[0] === entry.screenHalfSize[0]
}]), && before.screenHalfSize[1] === entry.screenHalfSize[1]
&& before.placement.floorAnchor[0] === entry.placement.floorAnchor[0]
&& before.placement.floorAnchor[1] === entry.placement.floorAnchor[1]
&& (before.placement.owner?.id || '') === (entry.placement.owner?.id || '');
return [{
id: entry.id,
kind: entry.kind,
placement: entry.placement,
screenHalfSize: entry.screenHalfSize,
...(sameShape ? { nudgeHintCss: [
before!.placement.nudgeScene[0] / unitsPerPixel,
before!.placement.nudgeScene[1] / unitsPerPixel,
] as ScenePoint } : {}),
}];
}),
rooms, rooms,
wallSilhouettes: input.wallSilhouettes, wallSilhouettes: input.wallSilhouettes,
sceneUnitsPerCssPixel: unitsPerPixel, sceneUnitsPerCssPixel: unitsPerPixel,
+8
View File
@@ -97,6 +97,14 @@ test('group collision separates a solvable dense set independently of input orde
} }
assert.deepEqual(normal.placements.get(keys[0]).visualScene, [100, 100], assert.deepEqual(normal.placements.get(keys[0]).visualScene, [100, 100],
'the stable first item stays at its zero-deviation anchor'); 'the stable first item stays at its zero-deviation anchor');
const hintedItems = [make('a'), make('b'), make('lock')].map((item) => ({
...item,
nudgeHintCss: normal.placements.get(isoOverlayCollisionKey(item.kind, item.id)).nudgeCss,
}));
const hinted = solve(hintedItems);
for (const key of keys) assert.deepEqual(hinted.placements.get(key), normal.placements.get(key),
'a previous exact placement is only an upper bound and cannot change the nearest result');
}); });
test('group collision finds a legal one-pixel slit between the coarse nodes', () => { test('group collision finds a legal one-pixel slit between the coarse nodes', () => {