fix(dialogs): находки код-ревью #600 r1 — сегмент без разрыва слов, радиус без блокировки Save, свидетель дефекта №5

M1. Подпись сегмента больше не рвётся посреди слова: колонка `.hpf-seg label`
не сжимается ниже самого длинного слова (`min-width: fit-content`, для
браузеров без него — прежний `0` строкой выше), слова переносятся только по
пробелам (`overflow-wrap: normal`), не поместившийся сегмент переносится на
вторую строку целыми кнопками (`flex-wrap`). Новый свидетель
demo/smoke_dialog_segments_i18n.mjs — четыре диалога × en/ru/de/fr: у каждой
подписи число строк (по Range текстового узла: span — flex-элемент, у блока
один прямоугольник даже при переносе) не больше числа слов, текст внутри
кнопки. На разметке r1 краснеет на en/ru/fr комнаты («Temperature» в 2
строки, «По температуре» в 3). Мутант form-kit-segment-breaks-words
возвращает прежние две строки CSS. ACCEPTANCE.md — строка про подписи
сегмента переписана.

M2. Glow radius — не условие Save: как на dev, нечисло или неположительное
значение при сохранении молча становится общим радиусом. Удалены
glowRadiusValid, MarkerProblem marker.error_glow_radius, ключ в четырёх
локалях словаря settings, aria-invalid у поля; смок device_settings_form
утверждает обратное прежнему (badRadiusDoesNotBlockSave,
zeroRadiusKeepsSaveEnabled) и проверяет «Review N fields» на привязке в
create-режиме. Changelog EN/RU и USER-GUIDE ru/en больше не называют радиус
среди ошибок; таблица устройства говорит про молчаливый общий радиус.

M3. Свидетель дефекта №5 (поповер «?» обрезается границей диалога комнаты):
demo/smoke_dialog_help_clipping.mjs — короткое окно 900×620, диалог комнаты
скроллится, «?» нижней карточки прижат к краю; подсказка выходит за край
скроллера и остаётся hit-test'ируемой во всех пяти точках (elementsFromPoint
сквозь теневые корни — обрезанная часть не hit-test'ится). Четыре ветки:
нативный <dialog> и ha-dialog × Popover API и портальный fallback; ветка
ha-dialog — заглушка с ловушками настоящей mwc-поверхности (transform +
overflow: hidden + собственный скроллер), portal вне поверхности проверен
явно. Настоящий ha-dialog (#505, загрузка колеса HA-frontend) — отдельная
диагностическая приёмка владельца; так и записано в ACCEPTANCE.md, где
появилась таблица AC8 «девять дефектов — свидетель на каждый».

M4. ACCEPTANCE.md: эталонов 13, а не 11 — одиннадцать из ТЗ (список AC10
унаследован от #598 без комнаты) плюс две room-temperature-dialog-*.

L1. USER-GUIDE.ru.md: испорченная строка таблицы настроек пространства
(хвост удалённой строки про декоративный слой) — убран; пояснение «в
редакторе подложки остаются видимыми» вернулось в строку «Видимые слои»;
строка про солнце говорит «слой Двери, окна и ворота выключен» вместо
«Скрыть проёмы включено».

Фикстуры листа диалогов набора пересняты (панель — байт в байт).

Бюджет: initial 289 852 / 290 900; lazy editor 242 989 / 243 900.

Гейты: typecheck, build, bundle:sync (три копии), npm test 2794 pass по
четырём частям, no-new-any, mutation-gate --check, check-inputs --coverage,
смоки: segments_i18n, help_clipping, четыре формы, config_parity,
help_affordance, room_settings, settings_dialog_cards.

Issue: #600
User-Visible: yes
This commit is contained in:
Claude
2026-09-20 16:37:31 +03:00
parent 32791fb336
commit 8dc60aec6e
62 changed files with 1066 additions and 823 deletions
@@ -1,312 +1,312 @@
{
"schema": 1,
"fingerprint": "c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",
"fingerprint": "54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 289829,
"initialViewGzipBytes": 289852,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 291350,
"initialPanelGzipBytes": 291374,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2323,
"initialPanelOnlyGzipBytes": 2325,
"lazyFiles": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/de-AkOtg0jq.js",
"houseplan-assets/editor-_VTHnoKH.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/fr-Ds3OdruH.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js",
"houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js",
"houseplan-assets/iso-scene-render-BfrsUAJf.js",
"houseplan-assets/live-interaction-runtime-CCfHOfT8.js",
"houseplan-assets/pdf-export-Bslsp3h0.js",
"houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js",
"houseplan-assets/zigbee-topology-runtime-BXasXMdL.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/de-DVCIKwC0.js",
"houseplan-assets/editor-C694OxAO.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/fr-DHxhbm5E.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js",
"houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js",
"houseplan-assets/iso-scene-render-fYqz_-Ot.js",
"houseplan-assets/live-interaction-runtime-XyTIhKAA.js",
"houseplan-assets/pdf-export-D3vmqIY6.js",
"houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js",
"houseplan-assets/zigbee-topology-runtime-d-S2Abll.js"
],
"lazyGzipBytes": 459663,
"lazyGzipBytes": 459551,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/editor-_VTHnoKH.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/editor-C694OxAO.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js"
],
"lazyEditorGzipBytes": 243125,
"lazyEditorGzipBytes": 242989,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js"
],
"lazyOnboardingGzipBytes": 33646,
"lazyOnboardingGzipBytes": 33577,
"lazyLocaleFiles": [
"houseplan-assets/de-AkOtg0jq.js",
"houseplan-assets/fr-Ds3OdruH.js"
"houseplan-assets/de-DVCIKwC0.js",
"houseplan-assets/fr-DHxhbm5E.js"
],
"lazyLocaleGzipBytes": 55372,
"lazyLocaleGzipBytes": 55383,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-BfrsUAJf.js"
"houseplan-assets/iso-scene-render-fYqz_-Ot.js"
],
"lazyIsometricGzipBytes": 17644,
"lazyIsometricGzipBytes": 17643,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js"
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js"
],
"lazyFurnitureArtGzipBytes": 16945,
"lazyFurnitureArtGzipBytes": 16942,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/pdf-export-Bslsp3h0.js"
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/pdf-export-D3vmqIY6.js"
],
"lazyPdfGzipBytes": 126819,
"lazyPdfGzipBytes": 126817,
"files": [
{
"path": "houseplan-assets/backdrop-pick-CtZfmF4H.js",
"sha256": "0318781a07d46ab4852f6ab7b0fdc44c180a1b0271935e031f9a9f885de62991",
"rawBytes": 74764,
"gzipBytes": 24114,
"path": "houseplan-assets/backdrop-pick-BJOCHJxe.js",
"sha256": "c24f2896a89f71e0a4147184f93b0e69e0c22eb705b772e644e9fc131ff879f4",
"rawBytes": 74375,
"gzipBytes": 24031,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-AkOtg0jq.js",
"sha256": "21cadc32b989295b913052353b5c8049b844474028e72162f8564698c0bdb9db",
"path": "houseplan-assets/de-DVCIKwC0.js",
"sha256": "6f716933e452260c6e7c0c40d7193e750b6fc443f162cca5cb814c734142dde5",
"rawBytes": 92513,
"gzipBytes": 27927,
"gzipBytes": 27933,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-_VTHnoKH.js",
"sha256": "881257f965ba340ab8367a3a0ffbfaf7e4509a38997c7b3b33281ff27b700907",
"path": "houseplan-assets/editor-C694OxAO.js",
"sha256": "f95242b8000cddf2fe1856a5518883c00a27a90c2983f228003db0189dffc1b4",
"rawBytes": 3833,
"gzipBytes": 1583,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-DcvCvE8g.js",
"sha256": "5068cd6f5bd37792a593096b142ea5e9b729b0f85a1cf4d3c5722f714ff64eb2",
"rawBytes": 23495,
"gzipBytes": 4704,
"path": "houseplan-assets/form-kit.styles-CKUQLdmn.js",
"sha256": "44a654e7c905948ab4bb363514532c13e67e3e54eee37e4af0ec8447f706fbc1",
"rawBytes": 23544,
"gzipBytes": 4716,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-Ds3OdruH.js",
"sha256": "395585192b0478200785d46cb37805871bd0726088ca776e0f95150af595633c",
"path": "houseplan-assets/fr-DHxhbm5E.js",
"sha256": "f603ade3217ebe9959225379598608583ec29ab654dc257f57ae894d85ca448f",
"rawBytes": 94824,
"gzipBytes": 27445,
"gzipBytes": 27450,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"sha256": "2f193022979145fe8544c3c498fb8f1e9b3690fa6500fcd70a6c4f34c8a13860",
"path": "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"sha256": "86d1074252f182c84d47285560a5b22c26724e21f21d03fbac4583973a9c11a7",
"rawBytes": 52033,
"gzipBytes": 16945,
"gzipBytes": 16942,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-BWAph8ZF.js",
"sha256": "ded6a4cd113062c60ed2086560b03f1cdba08884b0454c85f7140f5f51b284cb",
"path": "houseplan-assets/houseplan-card-9fMSy3y3.js",
"sha256": "e475fbae1c25540d2e349d4441bc963a4ff4181b8659fd491309dd1e578f716a",
"rawBytes": 1027208,
"gzipBytes": 289027,
"gzipBytes": 289049,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-AkOtg0jq.js",
"houseplan-assets/editor-_VTHnoKH.js",
"houseplan-assets/fr-Ds3OdruH.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js",
"houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js",
"houseplan-assets/iso-scene-render-BfrsUAJf.js",
"houseplan-assets/live-interaction-runtime-CCfHOfT8.js",
"houseplan-assets/pdf-export-Bslsp3h0.js",
"houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js"
"houseplan-assets/de-DVCIKwC0.js",
"houseplan-assets/editor-C694OxAO.js",
"houseplan-assets/fr-DHxhbm5E.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js",
"houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js",
"houseplan-assets/iso-scene-render-fYqz_-Ot.js",
"houseplan-assets/live-interaction-runtime-XyTIhKAA.js",
"houseplan-assets/pdf-export-D3vmqIY6.js",
"houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"sha256": "1af11a5d027eec8d8a0793eae9be1713b6387d3a15c239e83f8623f87877f8a1",
"rawBytes": 677599,
"gzipBytes": 188352,
"path": "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"sha256": "e84feb1cf320be8297982134d45a5adceaec5a50f95aaa884e6e53cae2664edd",
"rawBytes": 677390,
"gzipBytes": 188290,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-BXasXMdL.js"
"houseplan-assets/zigbee-topology-runtime-d-S2Abll.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js",
"sha256": "a30a515e61b632b90005e296b23d5cc52d3266c91ce29760fbb7358180956d1c",
"path": "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js",
"sha256": "64367a8743ea22c4a9a350456878b7006ba01a346cc89eabb786e3c1d944ad3a",
"rawBytes": 15667,
"gzipBytes": 4828,
"gzipBytes": 4830,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js",
"sha256": "780e78bbb5e04de2042497fdea47f44c31f8abeef03ad7cae3aeaf0e776f0db5",
"path": "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js",
"sha256": "b2fa73ad0fc3353630e380abe1f63f483113c7bfc5f1e634150c2f0e12b4e0cf",
"rawBytes": 10759,
"gzipBytes": 3684,
"gzipBytes": 3686,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js",
"houseplan-assets/zigbee-topology-runtime-BXasXMdL.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js",
"houseplan-assets/zigbee-topology-runtime-d-S2Abll.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-BfrsUAJf.js",
"sha256": "2806544f1906569d9613087eea4ca3b7017d0394147d6913f9e9998b8b4b456b",
"path": "houseplan-assets/iso-scene-render-fYqz_-Ot.js",
"sha256": "009a9217d1c522a5c2b6f9d5ea3450e2a77aafe52096d9c1d19902a18c6632f9",
"rawBytes": 51983,
"gzipBytes": 17644,
"gzipBytes": 17643,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-CCfHOfT8.js",
"sha256": "5b905320a37ded5bfb1b52a4095e6a5821644d4ce0031d2ba2374b1418be2239",
"path": "houseplan-assets/live-interaction-runtime-XyTIhKAA.js",
"sha256": "0fd38fd067699ea97f11565db7c4ae86c1bcc867041e7e3377408f40e741f03f",
"rawBytes": 8216,
"gzipBytes": 3205,
"gzipBytes": 3209,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-Bslsp3h0.js",
"sha256": "c7fc552565f6551b70366350399fbbe9bb849a588be6c293e6fb17602dabd0ae",
"path": "houseplan-assets/pdf-export-D3vmqIY6.js",
"sha256": "4c60cf0b34a17777c60c4849f1ee42841fb74b69466366adcf94cf97eec9ad2e",
"rawBytes": 236247,
"gzipBytes": 109874,
"gzipBytes": 109875,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-1TWzLmMH.js",
"sha256": "b6fad5dd728b4b6cfa4b4d54989a2d9d9dd9f37aba52301332a0bf3a4e69a66b",
"rawBytes": 14862,
"gzipBytes": 3424,
"path": "houseplan-assets/summary-panel-editor-CNT_mev4.js",
"sha256": "ef5dcf22a38fb5df834dcce277de7967303b8025167527483aab726dd30f3a2c",
"rawBytes": 14867,
"gzipBytes": 3427,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js"
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-CsJSnPHD.js",
"sha256": "a9c4d54e9e1d168a3dd48fd8f09d8470eafa3b9dbc825fe6f9dda5bcb34a7029",
"path": "houseplan-assets/summary-panel-metrics-BhoEMuKv.js",
"sha256": "0b4f1816c4069cc62f20dccaeeeceb82c139dee339782833e594e46aa768fe06",
"rawBytes": 2611,
"gzipBytes": 1306,
"gzipBytes": 1308,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js",
"sha256": "e3042c31f4e963a6c91fec76b05b1900e79360f60c246d8ce32291dd71201840",
"path": "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js",
"sha256": "95e65a1d327f9d2f90796b9ae7754e0d8a64c15e44a82cefe329dca8f6115689",
"rawBytes": 72733,
"gzipBytes": 20171,
"gzipBytes": 20172,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-1TWzLmMH.js",
"houseplan-assets/summary-panel-metrics-CsJSnPHD.js"
"houseplan-assets/summary-panel-editor-CNT_mev4.js",
"houseplan-assets/summary-panel-metrics-BhoEMuKv.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-D0gydI7H.js",
"sha256": "abe70ae6d783881bc6e8bdaac98a7372d1263f206103bf7110348f83f4a8dc2a",
"path": "houseplan-assets/zigbee-topology-CI6PJorK.js",
"sha256": "6e503b93a48deeda46368588fd4eebf7215aa4a2928e1162747da8b3ffe4b67a",
"rawBytes": 18962,
"gzipBytes": 7427,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js",
"sha256": "c7dd23a95592651b462f8ef86d073b4aa98b6fad4ce3395b5bbeb0679bf0c76d",
"path": "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js",
"sha256": "f6aad0abbf74532abc1c705d1268cce95048e7dbdc81a52a776a996c8b70f969",
"rawBytes": 3942,
"gzipBytes": 1760,
"gzipBytes": 1764,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "d5d8d4cbc7b0a71e4c6ba3f4cffb2fd412a9f8ce922200659ce96ee8f70d0bc0",
"sha256": "c796620c6d67c8fb18479291279eb410302ad541ed2b3679d59b780f74e8935b",
"rawBytes": 1205,
"gzipBytes": 802,
"gzipBytes": 803,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "a34d397053df4099bce9aca317cfa95619c4e031796d77a1da09c15aab69a132",
"sha256": "c134452d829194d8d630e5859f8142d345e15348a706d7a83d5d9328b0df3faa",
"rawBytes": 6165,
"gzipBytes": 2323,
"gzipBytes": 2325,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{az as e,l as o,aC as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-BWAph8ZF.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__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{az as e,l as o,aC as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-9fMSy3y3.js";class f 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,f={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")},h=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}
.data=${this._formData}
.schema=${e}
.computeLabel=${e=>h[e.name]||e.name}
.computeLabel=${e=>f[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(f.slice(0,3))}
${d(h.slice(0,3))}
${_?c`<div class="default-floor-error" role="alert"
style="color:var(--error-color,#db4437);margin:-4px 0 12px;overflow-wrap:anywhere">
${t(s,"editor.default_floor_missing",{id:_})}
</div>`:a}
${d(f.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h);
${d(h.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}f.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",f);
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__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{c as a,A as e}from"./houseplan-card-BWAph8ZF.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-BGIJeXIz.js";import"./form-kit.styles-DcvCvE8g.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__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{c as a,A as s}from"./houseplan-card-9fMSy3y3.js";import{s as e,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-CX2cplA1.js";import"./form-kit.styles-CKUQLdmn.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&&!e(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(s=>s.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>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -10,31 +10,31 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
dismiss-on-scrim aria-busy=${String(d.busy)}
@hp-close=${k}>
<div class="body summary-editor" @click=${()=>m.closeSource()}>
${d.localOnly?a`<p class="summary-local-hint">${b(d.localOnlyHint)}</p>`:e}
${d.localOnly?a`<p class="summary-local-hint">${b(d.localOnlyHint)}</p>`:s}
<section class="summary-general" aria-labelledby="summary-general-title">
<h3 id="summary-general-title">${b("summary.general_settings")}</h3>
<div class="summary-general-grid">
${d.localOnly?e:a`<div class="summary-field">
${d.localOnly?s:a`<div class="summary-field">
<label for="summary-panel-title">${b("summary.panel_title")}</label>
<input id="summary-panel-title" type="text" .value=${d.draft.title}
?disabled=${d.busy}
data-summary-error=${String(d.attempted&&"title"===y?.path)}
aria-invalid=${"error"===v("title")?.kind?"true":"false"}
@input=${a=>m.mutate(e=>{e.title=a.target.value})} />
${v("title")?a`<div class="summary-problem error">${h(v("title"))}</div>`:e}
@input=${a=>m.mutate(s=>{s.title=a.target.value})} />
${v("title")?a`<div class="summary-problem error">${h(v("title"))}</div>`:s}
</div>`}
${g}
${d.localOnly?e:a`<label class="summary-switch" for="summary-mobile-show">
${d.localOnly?s:a`<label class="summary-switch" for="summary-mobile-show">
<span class="summary-switch-caption"><strong>${b("summary.show_mobile")}</strong>
<small id="summary-mobile-show-hint">${b("summary.show_mobile_hint")}</small></span>
<input id="summary-mobile-show" data-summary-mobile-show type="checkbox"
.checked=${d.draft.show_on_mobile} ?disabled=${!d.localShow||d.busy}
aria-label=${b("summary.show_mobile")} aria-describedby="summary-mobile-show-hint"
@change=${a=>m.mutate(e=>{e.show_on_mobile=a.target.checked})} /></label>`}
@change=${a=>m.mutate(s=>{s.show_on_mobile=a.target.checked})} /></label>`}
</div>
${m.storageUnavailable?a`<div class="summary-problem warning">${b("summary.storage_unavailable")}</div>`:e}
${m.storageUnavailable?a`<div class="summary-problem warning">${b("summary.storage_unavailable")}</div>`:s}
</section>
${d.localOnly?e:a`
${d.localOnly?s:a`
<section class="summary-blocks-card" aria-labelledby="summary-blocks-title">
<header class="summary-blocks-heading">
<div><h3 id="summary-blocks-title">${b("summary.blocks")}</h3>
@@ -42,7 +42,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
<span class="summary-block-count">${b("summary.block_count").replace("{count}",String(d.draft.blocks.length)).replace("{limit}","10")}</span>
</header>
<div class="summary-editor-blocks">
${d.draft.blocks.map((s,t)=>{const u=`blocks.${t}`,n=v(`${u}.scope`);return a`<article class="summary-editor-block"
${d.draft.blocks.map((e,t)=>{const u=`blocks.${t}`,n=v(`${u}.scope`);return a`<article class="summary-editor-block"
@dragover=${a=>a.preventDefault()}
@drop=${a=>m.drop(a,`block:${t}`)}>
<div class="summary-block-head">
@@ -57,40 +57,40 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
?disabled=${t===d.draft.blocks.length-1||d.busy}
@click=${()=>m.mutate(a=>{a.blocks=r(a.blocks,t,t+1)})}>${l("down")}</button>
</div>
<input class="summary-block-title" type="text" .value=${s.title}
<input class="summary-block-title" type="text" .value=${e.title}
placeholder=${b("summary.block_title")} aria-label=${b("summary.block_title")}
?disabled=${d.busy}
data-summary-error=${String(d.attempted&&y?.path===`${u}.title`)}
aria-invalid=${"error"===v(`${u}.title`)?.kind?"true":"false"}
@input=${a=>m.mutate(e=>{e.blocks[t].title=a.target.value})} />
@input=${a=>m.mutate(s=>{s.blocks[t].title=a.target.value})} />
<button class="summary-icon-button summary-visibility" type="button"
?disabled=${d.busy} aria-pressed=${String(s.visible)}
title=${b(s.visible?"summary.hide_block":"summary.show_block")}
aria-label=${b(s.visible?"summary.hide_block":"summary.show_block")}
@click=${()=>m.mutate(a=>{a.blocks[t].visible=!a.blocks[t].visible})}>${l(s.visible?"eye":"eyeOff")}</button>
${v(`${u}.title`)?a`<div class="summary-problem error summary-block-title-error">${h(v(`${u}.title`))}</div>`:e}
?disabled=${d.busy} aria-pressed=${String(e.visible)}
title=${b(e.visible?"summary.hide_block":"summary.show_block")}
aria-label=${b(e.visible?"summary.hide_block":"summary.show_block")}
@click=${()=>m.mutate(a=>{a.blocks[t].visible=!a.blocks[t].visible})}>${l(e.visible?"eye":"eyeOff")}</button>
${v(`${u}.title`)?a`<div class="summary-problem error summary-block-title-error">${h(v(`${u}.title`))}</div>`:s}
<div class="summary-scope">
<select .value=${s.scope.type} ?disabled=${d.busy}
<select .value=${e.scope.type} ?disabled=${d.busy}
aria-label=${b("summary.scope")}
@change=${a=>m.mutate(e=>{e.blocks[t].scope="space"===a.target.value?{type:"space",space_id:c._space}:{type:"all"}})}>
<option value="all" ?selected=${"all"===s.scope.type}>${b("summary.scope_all")}</option>
<option value="space" ?selected=${"space"===s.scope.type}>${b("summary.scope_space")}</option>
@change=${a=>m.mutate(s=>{s.blocks[t].scope="space"===a.target.value?{type:"space",space_id:c._space}:{type:"all"}})}>
<option value="all" ?selected=${"all"===e.scope.type}>${b("summary.scope_all")}</option>
<option value="space" ?selected=${"space"===e.scope.type}>${b("summary.scope_space")}</option>
</select>
${"space"===s.scope.type?a`<select .value=${s.scope.space_id}
${"space"===e.scope.type?a`<select .value=${e.scope.space_id}
?disabled=${d.busy} aria-label=${b("summary.scope_space")}
data-summary-error=${String(d.attempted&&y?.path===`${u}.scope`)}
aria-invalid=${"error"===n?.kind?"true":"false"}
@change=${a=>m.mutate(e=>{const s=e.blocks[t].scope;"space"===s.type&&(s.space_id=a.target.value)})}>
${c._model.some(a=>a.id===s.scope.space_id)?e:a`<option value=${s.scope.space_id} selected>${s.scope.space_id}</option>`}
${c._model.map(e=>a`<option value=${e.id}
?selected=${e.id===s.scope.space_id}>${e.title}</option>`)}
</select>`:e}
@change=${a=>m.mutate(s=>{const e=s.blocks[t].scope;"space"===e.type&&(e.space_id=a.target.value)})}>
${c._model.some(a=>a.id===e.scope.space_id)?s:a`<option value=${e.scope.space_id} selected>${e.scope.space_id}</option>`}
${c._model.map(s=>a`<option value=${s.id}
?selected=${s.id===e.scope.space_id}>${s.title}</option>`)}
</select>`:s}
</div>
${n?a`<div class="summary-problem summary-scope-problem ${n.kind}">${h(n)}</div>`:e}
${n?a`<div class="summary-problem summary-scope-problem ${n.kind}">${h(n)}</div>`:s}
</div>
<div class="summary-block-body">
<div class="summary-editor-values">
${s.values.map((i,c)=>{const n=`${u}.values.${c}`,$=v(`${n}.source`),p=m.sourceToken(i.source),k=d.activeSource?.blockId===s.id&&d.activeSource.valueId===i.id,g="system"===i.source.type?b(`summary.system.${i.source.key}`):i.source.entity_id?m.entityIndex.labels.get(i.source.entity_id)||i.source.entity_id:b("summary.select_source"),_="system"===i.source.type?b("summary.system_source"):i.source.entity_id,f=k?o(m.entityIndex,d.entityFilter):null,w="entity"===i.source.type&&!!i.source.entity_id&&!m.entityIndex.labels.has(i.source.entity_id),S=`${s.id}\n${i.id}`;return a`<div class="summary-editor-value"
${e.values.map((i,c)=>{const n=`${u}.values.${c}`,$=v(`${n}.source`),p=m.sourceToken(i.source),k=d.activeSource?.blockId===e.id&&d.activeSource.valueId===i.id,g="system"===i.source.type?b(`summary.system.${i.source.key}`):i.source.entity_id?m.entityIndex.labels.get(i.source.entity_id)||i.source.entity_id:b("summary.select_source"),_="system"===i.source.type?b("summary.system_source"):i.source.entity_id,f=k?o(m.entityIndex,d.entityFilter):null,w="entity"===i.source.type&&!!i.source.entity_id&&!m.entityIndex.labels.has(i.source.entity_id),S=`${e.id}\n${i.id}`;return a`<div class="summary-editor-value"
@dragover=${a=>{a.preventDefault(),a.stopPropagation()}}
@drop=${a=>m.drop(a,`value:${t}:${c}`)}>
<span class="summary-drag" draggable=${String(!d.busy)} title=${b("summary.drag")}
@@ -101,7 +101,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
@click=${()=>m.mutate(a=>{a.blocks[t].values=r(a.blocks[t].values,c,c-1)})}>${l("up")}</button>
<button class="summary-icon-button" type="button" title=${b("summary.down")}
aria-label=${b("summary.down")}
?disabled=${c===s.values.length-1||d.busy}
?disabled=${c===e.values.length-1||d.busy}
@click=${()=>m.mutate(a=>{a.blocks[t].values=r(a.blocks[t].values,c,c+1)})}>${l("down")}</button>
</div>
<div class="summary-value-label">
@@ -109,8 +109,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
placeholder=${b("summary.value_name")} aria-label=${b("summary.value_name")}
data-summary-error=${String(d.attempted&&y?.path===`${n}.label`)}
aria-invalid=${"error"===v(`${n}.label`)?.kind?"true":"false"}
@input=${a=>m.mutate(e=>{e.blocks[t].values[c].label=a.target.value})} />
${v(`${n}.label`)?a`<div class="summary-problem error">${h(v(`${n}.label`))}</div>`:e}
@input=${a=>m.mutate(s=>{s.blocks[t].values[c].label=a.target.value})} />
${v(`${n}.label`)?a`<div class="summary-problem error">${h(v(`${n}.label`))}</div>`:s}
</div>
<div class="summary-source-field">
<button class="summary-source" type="button"
@@ -119,9 +119,9 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
data-summary-error=${String(d.attempted&&y?.path===`${n}.source`)}
aria-invalid=${"error"===$?.kind?"true":"false"}
aria-haspopup="listbox" aria-expanded=${k?"true":"false"}
@click=${a=>{a.stopPropagation(),k?m.closeSource():m.openSource(s.id,i.id)}}>
@click=${a=>{a.stopPropagation(),k?m.closeSource():m.openSource(e.id,i.id)}}>
<span class="summary-source-caption"><strong>${g}</strong>
${_?a`<small>${_}</small>`:e}</span>
${_?a`<small>${_}</small>`:s}</span>
${l("chevron")}
</button>
${k&&f?a`<div class="summary-source-picker"
@@ -135,39 +135,39 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
<div class="summary-source-results" role="listbox"
aria-label=${b("summary.select_source")}>
<div class="summary-source-group">${b("summary.system_group")}</div>
${["device_count","total_area","datetime"].map(e=>a`
${["device_count","total_area","datetime"].map(s=>a`
<button type="button" role="option"
?disabled=${d.busy}
aria-selected=${p===`system:${e}`?"true":"false"}
@click=${()=>m.setSource(s.id,i.id,`system:${e}`)}>
${b(`summary.system.${e}`)}
aria-selected=${p===`system:${s}`?"true":"false"}
@click=${()=>m.setSource(e.id,i.id,`system:${s}`)}>
${b(`summary.system.${s}`)}
</button>`)}
${w?a`<div class="summary-source-group">${b("summary.current_source")}</div>
<button type="button" role="option" class="broken" aria-selected="true"
?disabled=${d.busy}
@click=${()=>m.setSource(s.id,i.id,p)}>
@click=${()=>m.setSource(e.id,i.id,p)}>
${g}
</button>`:e}
</button>`:s}
<div class="summary-source-group">${b("summary.entities_group")}</div>
${f.entries.map(e=>a`<button type="button" role="option"
${f.entries.map(s=>a`<button type="button" role="option"
?disabled=${d.busy}
aria-selected=${p===`entity:${e.id}`?"true":"false"}
@click=${()=>m.setSource(s.id,i.id,`entity:${e.id}`)}>
<span>${e.label}</span><small>${e.id}</small>
aria-selected=${p===`entity:${s.id}`?"true":"false"}
@click=${()=>m.setSource(e.id,i.id,`entity:${s.id}`)}>
<span>${s.label}</span><small>${s.id}</small>
</button>`)}
${f.total?e:a`<div class="summary-empty">${b("summary.no_search_results")}</div>`}
${f.truncated?a`<div class="summary-refine">${b("summary.refine_search")}</div>`:e}
${f.total?s:a`<div class="summary-empty">${b("summary.no_search_results")}</div>`}
${f.truncated?a`<div class="summary-refine">${b("summary.refine_search")}</div>`:s}
</div>
</div>`:e}
${$?a`<div class="summary-problem ${$.kind}">${h($)}</div>`:e}
</div>`:s}
${$?a`<div class="summary-problem ${$.kind}">${h($)}</div>`:s}
</div>
<button class="summary-icon-button summary-value-remove" type="button"
title=${b("btn.delete")} aria-label=${b("btn.delete")} ?disabled=${d.busy}
@click=${()=>m.mutate(a=>{a.blocks[t].values.splice(c,1)})}>${l("close")}</button>
</div>`})}
<button class="summary-add summary-add-value" type="button"
?disabled=${s.values.length>=20||d.busy}
title=${s.values.length>=20?b("summary.limit_values"):""}
?disabled=${e.values.length>=20||d.busy}
title=${e.values.length>=20?b("summary.limit_values"):""}
@click=${()=>m.mutate(a=>{a.blocks[t].values.push(i())})}>
${l("plus")}${b("summary.add_value")}
</button>
@@ -186,11 +186,11 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
${l("plus")}${b("summary.add_block")}
</button>
</section>
${d.error?a`<div class="summary-problem error" role="alert">${d.error}</div>`:e}
${d.error?a`<div class="summary-problem error" role="alert">${d.error}</div>`:s}
${d.conflict?a`<button class="btn ghost summary-reload" type="button"
?disabled=${d.busy} @click=${()=>m.reload()}>
<ha-icon icon="mdi:reload"></ha-icon>${b("summary.reload_current")}
</button>`:e}
</button>`:s}
`}
</div>
<div class="row summary-editor-footer" slot="footer">
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{ed as e,K as t,aX as n,I as i,ab as o,a9 as r,bO as a,bN as s,aW as c,aV as l,aY as d,ee as u,ef as f,bQ as m,eg as g}from"./houseplan-card-BWAph8ZF.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),a=i.binding.slice(o+1),s="device"===r?e.registry.devices?.[a]:null,c="entity"===r?e.registry.entities?.[a]:null,l="device"===r?a:c?.device_id,d="device"===r?s?.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(a))&&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 s=t(e);if(!s)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||s;v=y(v,a(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=s(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};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{ed as e,J as t,aX as n,H as i,aa as o,a8 as r,bO as a,bN as s,aW as c,aV as l,aY as d,ee as u,ef as f,bQ as m,eg as g}from"./houseplan-card-9fMSy3y3.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),a=i.binding.slice(o+1),s="device"===r?e.registry.devices?.[a]:null,c="entity"===r?e.registry.entities?.[a]:null,l="device"===r?a:c?.device_id,d="device"===r?s?.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(a))&&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 s=t(e);if(!s)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||s;v=y(v,a(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=s(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 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{n as t,b as n}from"./zigbee-topology-D0gydI7H.js";import{aI as e}from"./houseplan-card-BWAph8ZF.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 m(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 g(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,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=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&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(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 m(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,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{n as t,b as n}from"./zigbee-topology-CI6PJorK.js";import{aI as e}from"./houseplan-card-9fMSy3y3.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 m(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 g(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,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=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&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(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 m(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,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";try{await import("./houseplan-assets/houseplan-card-BWAph8ZF.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__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";try{await import("./houseplan-assets/houseplan-card-9fMSy3y3.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
+10 -4
View File
@@ -98,13 +98,17 @@ const out = await page.evaluate(async () => {
input(q('#marker-glow-brightness'), '42'); await upd();
o.brightnessNumberWrites = c._markerDialog.glowBrightness === 42 && c._markerDialog.glowTouched === true;
o.radiusHintWhenEmpty = c._markerDialog.glowRadius === '' && !!q('#marker-glow-radius')?.closest('.hpf-field')?.querySelector('.hpf-hint');
// Ревью r1 M2: радиус — не условие Save. Нечисло или ноль, как на dev, при
// сохранении молча становится общим радиусом; поле не помечается ошибкой.
c._markerDialog = { ...c._markerDialog, glowRadius: 'x' }; await upd();
o.badRadiusBlocksSave = saveBtn().disabled === true && !!q('#marker-glow-radius[aria-invalid="true"]')
&& !!q('.hpf-card[data-card="light"] .hpf-error') && !!q('.hpf-status .hpf-link');
q('.hpf-status .hpf-link').click(); await upd();
o.reviewLinkFocusesRadius = (sr().activeElement ?? document.activeElement)?.id === 'marker-glow-radius';
o.badRadiusDoesNotBlockSave = saveBtn().disabled === false && !q('#marker-glow-radius[aria-invalid="true"]')
&& !q('.hpf-card[data-card="light"] .hpf-error') && !q('.hpf-status .hpf-link');
input(q('#marker-glow-radius'), '2.5'); await upd();
o.radiusWrites = c._markerDialog.glowRadius === '2.5' && saveBtn().disabled === false;
// «Review N fields» ведёт к первому ошибочному полю — здесь к привязке (create-режим ниже проверяет ссылку).
input(q('#marker-glow-radius'), '0'); await upd();
o.zeroRadiusKeepsSaveEnabled = saveBtn().disabled === false;
input(q('#marker-glow-radius'), ''); await upd();
// --- Appearance: иконка, display, бейдж, превью (Q3), размеры ----------------
o.iconFieldHasPreview = !!q('#marker-icon') && !!q('.hpf-iconfield .hpf-iconpreview ha-icon');
@@ -172,6 +176,8 @@ const out = await page.evaluate(async () => {
await pickSeg('bmode', 'ha');
o.createHaWithoutBindingIsAProblem = saveBtn().disabled === true && !!q('.hpf-status .hpf-link')
&& !!q('.hpf-card[data-card="basics"] .hpf-error') && q('#marker-binding').getAttribute('aria-expanded') === 'true';
q('.hpf-status .hpf-link').click(); await upd();
o.reviewLinkFocusesBinding = (sr().activeElement ?? document.activeElement)?.id === 'marker-binding';
await pickSeg('bmode', 'virtual');
o.createVirtualHasHint = c._markerDialog.binding === 'virtual' && saveBtn().disabled === false
&& !!q('input[name="bmode"]')?.closest('.hpf-field')?.querySelector('.hpf-hint');
+134
View File
@@ -0,0 +1,134 @@
// #600 AC8, дефект №5 («поповер «?» обрезается границей диалога комнаты»),
// ревью r1 M3: свидетель, что подсказка «?» в диалоге комнаты не режется ни
// скроллером диалога, ни поверхностью ha-dialog.
//
// Проверяется исполнением, а не чтением: подсказка открывается у карточки,
// прижатой к нижнему краю короткого окна (диалог скроллится), и каждый угол её
// прямоугольника hit-test'ом (elementsFromPoint сквозь теневые корни) попадает
// в саму подсказку — обрезанная часть элемента не hit-test'ится. Четыре
// комбинации: нативный <dialog> и ветка ha-dialog × Popover API и портальный
// fallback. Ветка ha-dialog берётся заглушкой с теми же ловушками, что у
// настоящей mwc-поверхности: transform на поверхности (ловит position: fixed) и
// overflow: hidden с собственным скроллером содержимого. Настоящий ha-dialog
// (#505) требует загрузки колеса HA-frontend — это отдельная приёмка владельца.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 900, height: 620 });
const out = await page.evaluate(async () => {
const o = {};
const c = window.__card;
const sr = () => c.shadowRoot || c.renderRoot;
const frame = () => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r)));
const upd = async () => { c.requestUpdate(); await c.updateComplete; await frame(); await new Promise((r) => setTimeout(r, 40)); };
const dlg = () => sr().querySelector('hp-dialog[data-kind="room"]');
const helpOf = (key) => dlg()?.querySelector(`hp-help[data-help-key="${key}"]`);
const surfaceOf = (key) => helpOf(key)?.shadowRoot?.querySelector('.tooltip')
|| dlg()?.shadowRoot?.querySelector('[data-hp-overlay="help"]')?.shadowRoot?.querySelector('.tooltip');
// hit-test сквозь теневые корни: есть ли в точке именно .tooltip
const tooltipAt = (x, y) => {
const seen = new Set();
const visit = (root) => {
for (const el of root.elementsFromPoint(x, y)) {
if (seen.has(el)) continue; seen.add(el);
if (el.classList?.contains('tooltip')) return true;
if (el.shadowRoot && visit(el.shadowRoot)) return true;
}
return false;
};
return visit(document);
};
const scroller = () => dlg()?.shadowRoot?.querySelector('.content')
|| dlg()?.shadowRoot?.querySelector('ha-dialog')?.shadowRoot?.querySelector('.content');
const probe = async (label, key) => {
const help = helpOf(key);
// прижать «?» к нижнему краю окна — там подсказка обязана уйти вверх, а не под срез
help.scrollIntoView({ block: 'end' });
await frame();
const trigger = help.shadowRoot.querySelector('.trigger');
trigger.click(); await frame(); await new Promise((r) => setTimeout(r, 60));
const surface = surfaceOf(key);
const r = surface?.getBoundingClientRect();
const inViewport = !!r && r.width > 40 && r.height > 20 && r.left >= 0 && r.top >= 0
&& r.right <= innerWidth && r.bottom <= innerHeight;
// 12 px от края: у подсказки скруглённые углы (radius 9), точка в 2 px от угла — за скруглением
const corners = r ? [[r.left + 12, r.top + 12], [r.right - 12, r.top + 12], [r.left + 12, r.bottom - 12], [r.right - 12, r.bottom - 12], [(r.left + r.right) / 2, (r.top + r.bottom) / 2]] : [];
const hits = corners.map(([x, y]) => tooltipAt(x, y));
o[`${label}_open`] = trigger.getAttribute('aria-expanded') === 'true' && !!surface;
o[`${label}_insideViewport`] = inViewport;
o[`${label}_notClipped`] = hits.length === 5 && hits.every(Boolean);
// подсказка стоит ВНЕ скроллера содержимого: её низ ниже или верх выше «?» так, что часть
// прямоугольника лежит за пределами видимой области скроллера — и всё равно hit-test'ится
const sc = scroller()?.getBoundingClientRect();
o[`${label}_crossesScrollerEdge`] = !!r && !!sc && (r.top < sc.top || r.bottom > sc.bottom);
trigger.click(); await frame();
};
const openRoom = async () => {
if (c._roomDialog) { c._roomDialogCancel(); await upd(); }
c._setMode('plan'); await upd();
c._openRoomEdit(c._curSpaceCfg.rooms[0]); await upd();
c._roomFill = 'temp'; await upd();
};
const withFallback = async (fn) => {
const show = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'showPopover');
const hide = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'hidePopover');
Object.defineProperty(HTMLElement.prototype, 'showPopover', { configurable: true, value: undefined });
Object.defineProperty(HTMLElement.prototype, 'hidePopover', { configurable: true, value: undefined });
try { await fn(); } finally {
if (show) Object.defineProperty(HTMLElement.prototype, 'showPopover', show); else delete HTMLElement.prototype.showPopover;
if (hide) Object.defineProperty(HTMLElement.prototype, 'hidePopover', hide); else delete HTMLElement.prototype.hidePopover;
}
};
// --- нативный <dialog> ------------------------------------------------------
await openRoom();
o.nativeBranch = !!dlg().shadowRoot.querySelector('dialog') && !dlg().shadowRoot.querySelector('ha-dialog');
o.dialogScrolls = scroller().scrollHeight > scroller().clientHeight + 10;
await probe('native_popover_sizes', 'room.sizes_section.help');
await probe('native_popover_fill', 'room.group_fill.help');
await withFallback(async () => {
await probe('native_fallback_sizes', 'room.sizes_section.help');
});
// доказательство содержательное только если подсказка реально вышла за край скроллера
o.native_tooltipLeavesScrollerAndStaysVisible = o.native_popover_sizes_crossesScrollerEdge === true
&& o.native_fallback_sizes_crossesScrollerEdge === true;
// --- ветка ha-dialog: заглушка с ловушками настоящей mwc-поверхности --------
customElements.define('ha-dialog', class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' }).innerHTML = `<style>
:host { position: fixed; inset: 0; z-index: 7; display: flex; align-items: center; justify-content: center; }
.scrim { position: absolute; inset: 0; background: rgba(0,0,0,.32); }
.surface { position: relative; display: flex; flex-direction: column; width: min(560px, 94vw); max-height: calc(100vh - 72px);
overflow: hidden; transform: scale(1); border-radius: 12px; background: var(--card-background-color, #fff); }
.head { flex: 0 0 auto; padding: 12px 16px; }
.content { flex: 1 1 auto; min-height: 0; overflow: auto; }
.foot { flex: 0 0 auto; }
</style><div class="scrim"></div><div class="surface"><div class="head"><slot name="headerTitle"></slot></div>
<div class="content"><slot></slot></div><div class="foot"><slot name="footer"></slot></div></div>`;
}
connectedCallback() { queueMicrotask(() => this.dispatchEvent(new CustomEvent('opened'))); }
set open(v) { this._open = v; } get open() { return this._open; }
});
c._roomDialogCancel(); await upd();
await openRoom();
o.haDialogBranch = !!dlg().shadowRoot.querySelector('ha-dialog') && !dlg().shadowRoot.querySelector('dialog');
o.haDialogPortalOutsideSurface = (() => {
const portal = dlg().shadowRoot.querySelector('.overlay-portal');
return !!portal && !dlg().shadowRoot.querySelector('ha-dialog').contains(portal);
})();
o.haDialogScrolls = scroller().scrollHeight > scroller().clientHeight + 10;
await probe('ha_popover_sizes', 'room.sizes_section.help');
await withFallback(async () => {
await probe('ha_fallback_sizes', 'room.sizes_section.help');
await probe('ha_fallback_fill', 'room.group_fill.help');
});
o.ha_tooltipLeavesScrollerAndStaysVisible = o.ha_popover_sizes_crossesScrollerEdge === true
&& o.ha_fallback_sizes_crossesScrollerEdge === true;
c._roomDialogCancel(); await upd();
return o;
});
checkAll(Object.fromEntries(Object.entries(out).filter(([k]) => !k.endsWith('_crossesScrollerEdge'))));
await finish(browser, out);
+71
View File
@@ -0,0 +1,71 @@
// #600 AC2/AC9, ревью r1 M1: подписи сегментов не рвутся посреди слова ни в
// одной из четырёх локалей ни в одном из четырёх диалогов. Смок на скролл
// контейнера этого не видел: слово ломалось внутри кнопки, scrollWidth не рос.
//
// Проверка: у текстового span'а каждого варианта число клиентских прямоугольников
// (строк) не больше числа слов — однословная подпись всегда в одну строку,
// многословная переносится только по пробелам; кнопка при этом не выходит за
// границы своего сегмента.
import { launch, checkAll, finish } from './serve.mjs';
const { page, browser } = await launch({ width: 1280, height: 900 });
const out = await page.evaluate(async () => {
const o = {};
const c = window.__card;
const sr = () => c.shadowRoot || c.renderRoot;
const upd = async () => { c.requestUpdate(); await c.updateComplete; await new Promise((r) => setTimeout(r, 40)); };
const spId = c._space;
const closeAll = async () => {
c._settingsDialog = null; c._spaceDialog = null; c._markerDialog = null; if (c._roomDialog) c._roomDialogCancel();
await upd();
};
const open = {
space: async () => { c._setMode('view'); c._openSpaceDialog('edit', spId); await upd(); c._spaceDialog = { ...c._spaceDialog, fillMode: 'temp', northMode: 'custom', northDeg: 35 }; await upd(); },
settings: async () => { c._openSettingsDialog(); await upd(); },
room: async () => {
c._setMode('plan'); await upd();
c._openRoomEdit(c._curSpaceCfg.rooms[0]); await upd();
c._roomFill = 'temp'; c._roomTempSrc = ''; c._roomSrcOpen = null; await upd();
},
marker: async () => {
c._setMode('devices'); await upd();
const d = c._devices.find((x) => x.id === 'd_light1') || c._devices.find((x) => x.bindingKind === 'device') || c._devices[0];
c._openMarkerDialog(d); await upd();
c._markerDialog = { ...c._markerDialog, lightRole: 'always', lightRoleTouched: true, glowMode: 'fixed', glowTouched: true, valueBadgeEnabled: true, valueBadgeTouched: true };
await upd();
},
};
const wordsOf = (text) => text.trim().split(/\s+/).filter(Boolean).length;
for (const lang of ['en', 'ru', 'de', 'fr']) {
c._config = { ...c._config, language: lang }; await upd();
for (const [kind, opener] of Object.entries(open)) {
await closeAll(); await opener();
const dlg = sr().querySelector(`hp-dialog[data-kind="${kind}"]`);
const labels = [...(dlg?.querySelectorAll('.hpf-seg label') || [])];
let broken = [];
let outside = [];
for (const label of labels) {
const span = [...label.querySelectorAll('span')].find((s) => !s.classList.contains('hpf-line'));
if (!span) continue;
// span — flex-элемент (блок), у блока один прямоугольник даже при переносе:
// строки считаются по текстовому узлу через Range.
const range = document.createRange(); range.selectNodeContents(span);
const lines = [...range.getClientRects()].filter((r) => r.width > 0 && r.height > 0).length;
if (lines > wordsOf(span.textContent)) broken.push(`${lang}/${kind}: «${span.textContent.trim()}» в ${lines} строк`);
const lb = label.getBoundingClientRect(); const sb = span.getBoundingClientRect();
if (sb.left < lb.left - 0.5 || sb.right > lb.right + 0.5) outside.push(`${lang}/${kind}: «${span.textContent.trim()}» шире кнопки`);
}
o[`${lang}_${kind}_hasSegments`] = labels.length >= 2;
o[`${lang}_${kind}_noMidWordBreak`] = broken.length === 0 || broken;
o[`${lang}_${kind}_labelsInsideButtons`] = outside.length === 0 || outside;
}
}
await closeAll();
c._config = { ...c._config, language: 'en' }; await upd();
return o;
});
const normalized = Object.fromEntries(Object.entries(out).map(([k, v]) => [k, v === true]));
checkAll(normalized);
await finish(browser, out);
+146 -146
View File
@@ -1,312 +1,312 @@
{
"schema": 1,
"fingerprint": "c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f",
"fingerprint": "54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32",
"entry": "houseplan-card.js",
"panelEntry": "houseplan-panel.js",
"initialViewFiles": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-card.js"
],
"initialViewGzipBytes": 289829,
"initialViewGzipBytes": 289852,
"initialPanelFiles": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-panel.js"
],
"initialPanelGzipBytes": 291350,
"initialPanelGzipBytes": 291374,
"initialPanelOnlyFiles": [
"houseplan-panel.js"
],
"initialPanelOnlyGzipBytes": 2323,
"initialPanelOnlyGzipBytes": 2325,
"lazyFiles": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/de-AkOtg0jq.js",
"houseplan-assets/editor-_VTHnoKH.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/fr-Ds3OdruH.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js",
"houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js",
"houseplan-assets/iso-scene-render-BfrsUAJf.js",
"houseplan-assets/live-interaction-runtime-CCfHOfT8.js",
"houseplan-assets/pdf-export-Bslsp3h0.js",
"houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js",
"houseplan-assets/zigbee-topology-runtime-BXasXMdL.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/de-DVCIKwC0.js",
"houseplan-assets/editor-C694OxAO.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/fr-DHxhbm5E.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js",
"houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js",
"houseplan-assets/iso-scene-render-fYqz_-Ot.js",
"houseplan-assets/live-interaction-runtime-XyTIhKAA.js",
"houseplan-assets/pdf-export-D3vmqIY6.js",
"houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js",
"houseplan-assets/zigbee-topology-runtime-d-S2Abll.js"
],
"lazyGzipBytes": 459663,
"lazyGzipBytes": 459551,
"lazyEditorFiles": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/editor-_VTHnoKH.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/editor-C694OxAO.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js"
],
"lazyEditorGzipBytes": 243125,
"lazyEditorGzipBytes": 242989,
"lazyOnboardingFiles": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js"
],
"lazyOnboardingGzipBytes": 33646,
"lazyOnboardingGzipBytes": 33577,
"lazyLocaleFiles": [
"houseplan-assets/de-AkOtg0jq.js",
"houseplan-assets/fr-Ds3OdruH.js"
"houseplan-assets/de-DVCIKwC0.js",
"houseplan-assets/fr-DHxhbm5E.js"
],
"lazyLocaleGzipBytes": 55372,
"lazyLocaleGzipBytes": 55383,
"lazyIsometricFiles": [
"houseplan-assets/iso-scene-render-BfrsUAJf.js"
"houseplan-assets/iso-scene-render-fYqz_-Ot.js"
],
"lazyIsometricGzipBytes": 17644,
"lazyIsometricGzipBytes": 17643,
"lazyFurnitureArtFiles": [
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js"
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js"
],
"lazyFurnitureArtGzipBytes": 16945,
"lazyFurnitureArtGzipBytes": 16942,
"lazyPdfFiles": [
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/pdf-export-Bslsp3h0.js"
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/pdf-export-D3vmqIY6.js"
],
"lazyPdfGzipBytes": 126819,
"lazyPdfGzipBytes": 126817,
"files": [
{
"path": "houseplan-assets/backdrop-pick-CtZfmF4H.js",
"sha256": "0318781a07d46ab4852f6ab7b0fdc44c180a1b0271935e031f9a9f885de62991",
"rawBytes": 74764,
"gzipBytes": 24114,
"path": "houseplan-assets/backdrop-pick-BJOCHJxe.js",
"sha256": "c24f2896a89f71e0a4147184f93b0e69e0c22eb705b772e644e9fc131ff879f4",
"rawBytes": 74375,
"gzipBytes": 24031,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/de-AkOtg0jq.js",
"sha256": "21cadc32b989295b913052353b5c8049b844474028e72162f8564698c0bdb9db",
"path": "houseplan-assets/de-DVCIKwC0.js",
"sha256": "6f716933e452260c6e7c0c40d7193e750b6fc443f162cca5cb814c734142dde5",
"rawBytes": 92513,
"gzipBytes": 27927,
"gzipBytes": 27933,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/editor-_VTHnoKH.js",
"sha256": "881257f965ba340ab8367a3a0ffbfaf7e4509a38997c7b3b33281ff27b700907",
"path": "houseplan-assets/editor-C694OxAO.js",
"sha256": "f95242b8000cddf2fe1856a5518883c00a27a90c2983f228003db0189dffc1b4",
"rawBytes": 3833,
"gzipBytes": 1583,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/form-kit.styles-DcvCvE8g.js",
"sha256": "5068cd6f5bd37792a593096b142ea5e9b729b0f85a1cf4d3c5722f714ff64eb2",
"rawBytes": 23495,
"gzipBytes": 4704,
"path": "houseplan-assets/form-kit.styles-CKUQLdmn.js",
"sha256": "44a654e7c905948ab4bb363514532c13e67e3e54eee37e4af0ec8447f706fbc1",
"rawBytes": 23544,
"gzipBytes": 4716,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/fr-Ds3OdruH.js",
"sha256": "395585192b0478200785d46cb37805871bd0726088ca776e0f95150af595633c",
"path": "houseplan-assets/fr-DHxhbm5E.js",
"sha256": "f603ade3217ebe9959225379598608583ec29ab654dc257f57ae894d85ca448f",
"rawBytes": 94824,
"gzipBytes": 27445,
"gzipBytes": 27450,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"sha256": "2f193022979145fe8544c3c498fb8f1e9b3690fa6500fcd70a6c4f34c8a13860",
"path": "houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"sha256": "86d1074252f182c84d47285560a5b22c26724e21f21d03fbac4583973a9c11a7",
"rawBytes": 52033,
"gzipBytes": 16945,
"gzipBytes": 16942,
"isEntry": false,
"imports": [],
"dynamicImports": []
},
{
"path": "houseplan-assets/houseplan-card-BWAph8ZF.js",
"sha256": "ded6a4cd113062c60ed2086560b03f1cdba08884b0454c85f7140f5f51b284cb",
"path": "houseplan-assets/houseplan-card-9fMSy3y3.js",
"sha256": "e475fbae1c25540d2e349d4441bc963a4ff4181b8659fd491309dd1e578f716a",
"rawBytes": 1027208,
"gzipBytes": 289027,
"gzipBytes": 289049,
"isEntry": false,
"imports": [],
"dynamicImports": [
"houseplan-assets/de-AkOtg0jq.js",
"houseplan-assets/editor-_VTHnoKH.js",
"houseplan-assets/fr-Ds3OdruH.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js",
"houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js",
"houseplan-assets/iso-scene-render-BfrsUAJf.js",
"houseplan-assets/live-interaction-runtime-CCfHOfT8.js",
"houseplan-assets/pdf-export-Bslsp3h0.js",
"houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js"
"houseplan-assets/de-DVCIKwC0.js",
"houseplan-assets/editor-C694OxAO.js",
"houseplan-assets/fr-DHxhbm5E.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js",
"houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js",
"houseplan-assets/iso-scene-render-fYqz_-Ot.js",
"houseplan-assets/live-interaction-runtime-XyTIhKAA.js",
"houseplan-assets/pdf-export-D3vmqIY6.js",
"houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js"
]
},
{
"path": "houseplan-assets/houseplan-editor-runtime-BlocE3XU.js",
"sha256": "1af11a5d027eec8d8a0793eae9be1713b6387d3a15c239e83f8623f87877f8a1",
"rawBytes": 677599,
"gzipBytes": 188352,
"path": "houseplan-assets/houseplan-editor-runtime-AzCVhtuX.js",
"sha256": "e84feb1cf320be8297982134d45a5adceaec5a50f95aaa884e6e53cae2664edd",
"rawBytes": 677390,
"gzipBytes": 188290,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js"
],
"dynamicImports": [
"houseplan-assets/zigbee-topology-runtime-BXasXMdL.js"
"houseplan-assets/zigbee-topology-runtime-d-S2Abll.js"
]
},
{
"path": "houseplan-assets/houseplan-onboarding-runtime-DYojoXE_.js",
"sha256": "a30a515e61b632b90005e296b23d5cc52d3266c91ce29760fbb7358180956d1c",
"path": "houseplan-assets/houseplan-onboarding-runtime-Dp2b84fm.js",
"sha256": "64367a8743ea22c4a9a350456878b7006ba01a346cc89eabb786e3c1d944ad3a",
"rawBytes": 15667,
"gzipBytes": 4828,
"gzipBytes": 4830,
"isEntry": false,
"imports": [
"houseplan-assets/backdrop-pick-CtZfmF4H.js",
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/backdrop-pick-BJOCHJxe.js",
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/hp-zigbee-topology-overlay-jGSF0zVB.js",
"sha256": "780e78bbb5e04de2042497fdea47f44c31f8abeef03ad7cae3aeaf0e776f0db5",
"path": "houseplan-assets/hp-zigbee-topology-overlay-CbSbT5WT.js",
"sha256": "b2fa73ad0fc3353630e380abe1f63f483113c7bfc5f1e634150c2f0e12b4e0cf",
"rawBytes": 10759,
"gzipBytes": 3684,
"gzipBytes": 3686,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js",
"houseplan-assets/zigbee-topology-runtime-BXasXMdL.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js",
"houseplan-assets/zigbee-topology-runtime-d-S2Abll.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/iso-scene-render-BfrsUAJf.js",
"sha256": "2806544f1906569d9613087eea4ca3b7017d0394147d6913f9e9998b8b4b456b",
"path": "houseplan-assets/iso-scene-render-fYqz_-Ot.js",
"sha256": "009a9217d1c522a5c2b6f9d5ea3450e2a77aafe52096d9c1d19902a18c6632f9",
"rawBytes": 51983,
"gzipBytes": 17644,
"gzipBytes": 17643,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/live-interaction-runtime-CCfHOfT8.js",
"sha256": "5b905320a37ded5bfb1b52a4095e6a5821644d4ce0031d2ba2374b1418be2239",
"path": "houseplan-assets/live-interaction-runtime-XyTIhKAA.js",
"sha256": "0fd38fd067699ea97f11565db7c4ae86c1bcc867041e7e3377408f40e741f03f",
"rawBytes": 8216,
"gzipBytes": 3205,
"gzipBytes": 3209,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/pdf-export-Bslsp3h0.js",
"sha256": "c7fc552565f6551b70366350399fbbe9bb849a588be6c293e6fb17602dabd0ae",
"path": "houseplan-assets/pdf-export-D3vmqIY6.js",
"sha256": "4c60cf0b34a17777c60c4849f1ee42841fb74b69466366adcf94cf97eec9ad2e",
"rawBytes": 236247,
"gzipBytes": 109874,
"gzipBytes": 109875,
"isEntry": false,
"imports": [
"houseplan-assets/furniture-plan-art.generated-Ck1wv9qF.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/furniture-plan-art.generated-DaxkO8ol.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-editor-1TWzLmMH.js",
"sha256": "b6fad5dd728b4b6cfa4b4d54989a2d9d9dd9f37aba52301332a0bf3a4e69a66b",
"rawBytes": 14862,
"gzipBytes": 3424,
"path": "houseplan-assets/summary-panel-editor-CNT_mev4.js",
"sha256": "ef5dcf22a38fb5df834dcce277de7967303b8025167527483aab726dd30f3a2c",
"rawBytes": 14867,
"gzipBytes": 3427,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js"
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-metrics-CsJSnPHD.js",
"sha256": "a9c4d54e9e1d168a3dd48fd8f09d8470eafa3b9dbc825fe6f9dda5bcb34a7029",
"path": "houseplan-assets/summary-panel-metrics-BhoEMuKv.js",
"sha256": "0b4f1816c4069cc62f20dccaeeeceb82c139dee339782833e594e46aa768fe06",
"rawBytes": 2611,
"gzipBytes": 1306,
"gzipBytes": 1308,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/summary-panel-runtime-loaded-BGIJeXIz.js",
"sha256": "e3042c31f4e963a6c91fec76b05b1900e79360f60c246d8ce32291dd71201840",
"path": "houseplan-assets/summary-panel-runtime-loaded-CX2cplA1.js",
"sha256": "95e65a1d327f9d2f90796b9ae7754e0d8a64c15e44a82cefe329dca8f6115689",
"rawBytes": 72733,
"gzipBytes": 20171,
"gzipBytes": 20172,
"isEntry": false,
"imports": [
"houseplan-assets/form-kit.styles-DcvCvE8g.js",
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/form-kit.styles-CKUQLdmn.js",
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": [
"houseplan-assets/summary-panel-editor-1TWzLmMH.js",
"houseplan-assets/summary-panel-metrics-CsJSnPHD.js"
"houseplan-assets/summary-panel-editor-CNT_mev4.js",
"houseplan-assets/summary-panel-metrics-BhoEMuKv.js"
]
},
{
"path": "houseplan-assets/zigbee-topology-D0gydI7H.js",
"sha256": "abe70ae6d783881bc6e8bdaac98a7372d1263f206103bf7110348f83f4a8dc2a",
"path": "houseplan-assets/zigbee-topology-CI6PJorK.js",
"sha256": "6e503b93a48deeda46368588fd4eebf7215aa4a2928e1162747da8b3ffe4b67a",
"rawBytes": 18962,
"gzipBytes": 7427,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-assets/zigbee-topology-runtime-BXasXMdL.js",
"sha256": "c7dd23a95592651b462f8ef86d073b4aa98b6fad4ce3395b5bbeb0679bf0c76d",
"path": "houseplan-assets/zigbee-topology-runtime-d-S2Abll.js",
"sha256": "f6aad0abbf74532abc1c705d1268cce95048e7dbdc81a52a776a996c8b70f969",
"rawBytes": 3942,
"gzipBytes": 1760,
"gzipBytes": 1764,
"isEntry": false,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js",
"houseplan-assets/zigbee-topology-D0gydI7H.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js",
"houseplan-assets/zigbee-topology-CI6PJorK.js"
],
"dynamicImports": []
},
{
"path": "houseplan-card.js",
"sha256": "d5d8d4cbc7b0a71e4c6ba3f4cffb2fd412a9f8ce922200659ce96ee8f70d0bc0",
"sha256": "c796620c6d67c8fb18479291279eb410302ad541ed2b3679d59b780f74e8935b",
"rawBytes": 1205,
"gzipBytes": 802,
"gzipBytes": 803,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
},
{
"path": "houseplan-panel.js",
"sha256": "a34d397053df4099bce9aca317cfa95619c4e031796d77a1da09c15aab69a132",
"sha256": "c134452d829194d8d630e5859f8142d345e15348a706d7a83d5d9328b0df3faa",
"rawBytes": 6165,
"gzipBytes": 2323,
"gzipBytes": 2325,
"isEntry": true,
"imports": [
"houseplan-assets/houseplan-card-BWAph8ZF.js"
"houseplan-assets/houseplan-card-9fMSy3y3.js"
],
"dynamicImports": []
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,14 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{az as e,l as o,aC as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-BWAph8ZF.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__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{az as e,l as o,aC as t,e7 as s,A as a,e8 as i,e9 as l,ea as n,E as r,c}from"./houseplan-card-9fMSy3y3.js";class f 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,f={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")},h=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}
.data=${this._formData}
.schema=${e}
.computeLabel=${e=>h[e.name]||e.name}
.computeLabel=${e=>f[e.name]||e.name}
@value-changed=${this._valueChanged}
></ha-form>`;return c`
${d(f.slice(0,3))}
${d(h.slice(0,3))}
${_?c`<div class="default-floor-error" role="alert"
style="color:var(--error-color,#db4437);margin:-4px 0 12px;overflow-wrap:anywhere">
${t(s,"editor.default_floor_missing",{id:_})}
</div>`:a}
${d(f.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}h.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",h);
${d(h.slice(3))}
`}_valueChanged(e){const o={...this._config,...e.detail.value};""===o.floor?delete o.floor:o.floor===this._floorToken&&(o.floor=this._config?.floor);const t=new Event("config-changed",{bubbles:!0,composed:!0});t.detail={config:o},this.dispatchEvent(t)}}f.properties={hass:{attribute:!1},_config:{state:!0},_spaces:{state:!0}},customElements.get("houseplan-card-editor")||customElements.define("houseplan-card-editor",f);
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
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__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{c as a,A as e}from"./houseplan-card-BWAph8ZF.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-BGIJeXIz.js";import"./form-kit.styles-DcvCvE8g.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__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{c as a,A as s}from"./houseplan-card-9fMSy3y3.js";import{s as e,n as t,a as l,m as r,b as o,c as i,d as u}from"./summary-panel-runtime-loaded-CX2cplA1.js";import"./form-kit.styles-CKUQLdmn.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&&!e(t(d.draft),d.base),p=$&&!d.busy&&!y,v=a=>n.find(s=>s.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>
<small id="summary-local-show-hint">${b("summary.show_local_hint")}</small></span>
<input id="summary-local-show" data-summary-local-show type="checkbox"
@@ -10,31 +10,31 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
dismiss-on-scrim aria-busy=${String(d.busy)}
@hp-close=${k}>
<div class="body summary-editor" @click=${()=>m.closeSource()}>
${d.localOnly?a`<p class="summary-local-hint">${b(d.localOnlyHint)}</p>`:e}
${d.localOnly?a`<p class="summary-local-hint">${b(d.localOnlyHint)}</p>`:s}
<section class="summary-general" aria-labelledby="summary-general-title">
<h3 id="summary-general-title">${b("summary.general_settings")}</h3>
<div class="summary-general-grid">
${d.localOnly?e:a`<div class="summary-field">
${d.localOnly?s:a`<div class="summary-field">
<label for="summary-panel-title">${b("summary.panel_title")}</label>
<input id="summary-panel-title" type="text" .value=${d.draft.title}
?disabled=${d.busy}
data-summary-error=${String(d.attempted&&"title"===y?.path)}
aria-invalid=${"error"===v("title")?.kind?"true":"false"}
@input=${a=>m.mutate(e=>{e.title=a.target.value})} />
${v("title")?a`<div class="summary-problem error">${h(v("title"))}</div>`:e}
@input=${a=>m.mutate(s=>{s.title=a.target.value})} />
${v("title")?a`<div class="summary-problem error">${h(v("title"))}</div>`:s}
</div>`}
${g}
${d.localOnly?e:a`<label class="summary-switch" for="summary-mobile-show">
${d.localOnly?s:a`<label class="summary-switch" for="summary-mobile-show">
<span class="summary-switch-caption"><strong>${b("summary.show_mobile")}</strong>
<small id="summary-mobile-show-hint">${b("summary.show_mobile_hint")}</small></span>
<input id="summary-mobile-show" data-summary-mobile-show type="checkbox"
.checked=${d.draft.show_on_mobile} ?disabled=${!d.localShow||d.busy}
aria-label=${b("summary.show_mobile")} aria-describedby="summary-mobile-show-hint"
@change=${a=>m.mutate(e=>{e.show_on_mobile=a.target.checked})} /></label>`}
@change=${a=>m.mutate(s=>{s.show_on_mobile=a.target.checked})} /></label>`}
</div>
${m.storageUnavailable?a`<div class="summary-problem warning">${b("summary.storage_unavailable")}</div>`:e}
${m.storageUnavailable?a`<div class="summary-problem warning">${b("summary.storage_unavailable")}</div>`:s}
</section>
${d.localOnly?e:a`
${d.localOnly?s:a`
<section class="summary-blocks-card" aria-labelledby="summary-blocks-title">
<header class="summary-blocks-heading">
<div><h3 id="summary-blocks-title">${b("summary.blocks")}</h3>
@@ -42,7 +42,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
<span class="summary-block-count">${b("summary.block_count").replace("{count}",String(d.draft.blocks.length)).replace("{limit}","10")}</span>
</header>
<div class="summary-editor-blocks">
${d.draft.blocks.map((s,t)=>{const u=`blocks.${t}`,n=v(`${u}.scope`);return a`<article class="summary-editor-block"
${d.draft.blocks.map((e,t)=>{const u=`blocks.${t}`,n=v(`${u}.scope`);return a`<article class="summary-editor-block"
@dragover=${a=>a.preventDefault()}
@drop=${a=>m.drop(a,`block:${t}`)}>
<div class="summary-block-head">
@@ -57,40 +57,40 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
?disabled=${t===d.draft.blocks.length-1||d.busy}
@click=${()=>m.mutate(a=>{a.blocks=r(a.blocks,t,t+1)})}>${l("down")}</button>
</div>
<input class="summary-block-title" type="text" .value=${s.title}
<input class="summary-block-title" type="text" .value=${e.title}
placeholder=${b("summary.block_title")} aria-label=${b("summary.block_title")}
?disabled=${d.busy}
data-summary-error=${String(d.attempted&&y?.path===`${u}.title`)}
aria-invalid=${"error"===v(`${u}.title`)?.kind?"true":"false"}
@input=${a=>m.mutate(e=>{e.blocks[t].title=a.target.value})} />
@input=${a=>m.mutate(s=>{s.blocks[t].title=a.target.value})} />
<button class="summary-icon-button summary-visibility" type="button"
?disabled=${d.busy} aria-pressed=${String(s.visible)}
title=${b(s.visible?"summary.hide_block":"summary.show_block")}
aria-label=${b(s.visible?"summary.hide_block":"summary.show_block")}
@click=${()=>m.mutate(a=>{a.blocks[t].visible=!a.blocks[t].visible})}>${l(s.visible?"eye":"eyeOff")}</button>
${v(`${u}.title`)?a`<div class="summary-problem error summary-block-title-error">${h(v(`${u}.title`))}</div>`:e}
?disabled=${d.busy} aria-pressed=${String(e.visible)}
title=${b(e.visible?"summary.hide_block":"summary.show_block")}
aria-label=${b(e.visible?"summary.hide_block":"summary.show_block")}
@click=${()=>m.mutate(a=>{a.blocks[t].visible=!a.blocks[t].visible})}>${l(e.visible?"eye":"eyeOff")}</button>
${v(`${u}.title`)?a`<div class="summary-problem error summary-block-title-error">${h(v(`${u}.title`))}</div>`:s}
<div class="summary-scope">
<select .value=${s.scope.type} ?disabled=${d.busy}
<select .value=${e.scope.type} ?disabled=${d.busy}
aria-label=${b("summary.scope")}
@change=${a=>m.mutate(e=>{e.blocks[t].scope="space"===a.target.value?{type:"space",space_id:c._space}:{type:"all"}})}>
<option value="all" ?selected=${"all"===s.scope.type}>${b("summary.scope_all")}</option>
<option value="space" ?selected=${"space"===s.scope.type}>${b("summary.scope_space")}</option>
@change=${a=>m.mutate(s=>{s.blocks[t].scope="space"===a.target.value?{type:"space",space_id:c._space}:{type:"all"}})}>
<option value="all" ?selected=${"all"===e.scope.type}>${b("summary.scope_all")}</option>
<option value="space" ?selected=${"space"===e.scope.type}>${b("summary.scope_space")}</option>
</select>
${"space"===s.scope.type?a`<select .value=${s.scope.space_id}
${"space"===e.scope.type?a`<select .value=${e.scope.space_id}
?disabled=${d.busy} aria-label=${b("summary.scope_space")}
data-summary-error=${String(d.attempted&&y?.path===`${u}.scope`)}
aria-invalid=${"error"===n?.kind?"true":"false"}
@change=${a=>m.mutate(e=>{const s=e.blocks[t].scope;"space"===s.type&&(s.space_id=a.target.value)})}>
${c._model.some(a=>a.id===s.scope.space_id)?e:a`<option value=${s.scope.space_id} selected>${s.scope.space_id}</option>`}
${c._model.map(e=>a`<option value=${e.id}
?selected=${e.id===s.scope.space_id}>${e.title}</option>`)}
</select>`:e}
@change=${a=>m.mutate(s=>{const e=s.blocks[t].scope;"space"===e.type&&(e.space_id=a.target.value)})}>
${c._model.some(a=>a.id===e.scope.space_id)?s:a`<option value=${e.scope.space_id} selected>${e.scope.space_id}</option>`}
${c._model.map(s=>a`<option value=${s.id}
?selected=${s.id===e.scope.space_id}>${s.title}</option>`)}
</select>`:s}
</div>
${n?a`<div class="summary-problem summary-scope-problem ${n.kind}">${h(n)}</div>`:e}
${n?a`<div class="summary-problem summary-scope-problem ${n.kind}">${h(n)}</div>`:s}
</div>
<div class="summary-block-body">
<div class="summary-editor-values">
${s.values.map((i,c)=>{const n=`${u}.values.${c}`,$=v(`${n}.source`),p=m.sourceToken(i.source),k=d.activeSource?.blockId===s.id&&d.activeSource.valueId===i.id,g="system"===i.source.type?b(`summary.system.${i.source.key}`):i.source.entity_id?m.entityIndex.labels.get(i.source.entity_id)||i.source.entity_id:b("summary.select_source"),_="system"===i.source.type?b("summary.system_source"):i.source.entity_id,f=k?o(m.entityIndex,d.entityFilter):null,w="entity"===i.source.type&&!!i.source.entity_id&&!m.entityIndex.labels.has(i.source.entity_id),S=`${s.id}\n${i.id}`;return a`<div class="summary-editor-value"
${e.values.map((i,c)=>{const n=`${u}.values.${c}`,$=v(`${n}.source`),p=m.sourceToken(i.source),k=d.activeSource?.blockId===e.id&&d.activeSource.valueId===i.id,g="system"===i.source.type?b(`summary.system.${i.source.key}`):i.source.entity_id?m.entityIndex.labels.get(i.source.entity_id)||i.source.entity_id:b("summary.select_source"),_="system"===i.source.type?b("summary.system_source"):i.source.entity_id,f=k?o(m.entityIndex,d.entityFilter):null,w="entity"===i.source.type&&!!i.source.entity_id&&!m.entityIndex.labels.has(i.source.entity_id),S=`${e.id}\n${i.id}`;return a`<div class="summary-editor-value"
@dragover=${a=>{a.preventDefault(),a.stopPropagation()}}
@drop=${a=>m.drop(a,`value:${t}:${c}`)}>
<span class="summary-drag" draggable=${String(!d.busy)} title=${b("summary.drag")}
@@ -101,7 +101,7 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
@click=${()=>m.mutate(a=>{a.blocks[t].values=r(a.blocks[t].values,c,c-1)})}>${l("up")}</button>
<button class="summary-icon-button" type="button" title=${b("summary.down")}
aria-label=${b("summary.down")}
?disabled=${c===s.values.length-1||d.busy}
?disabled=${c===e.values.length-1||d.busy}
@click=${()=>m.mutate(a=>{a.blocks[t].values=r(a.blocks[t].values,c,c+1)})}>${l("down")}</button>
</div>
<div class="summary-value-label">
@@ -109,8 +109,8 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
placeholder=${b("summary.value_name")} aria-label=${b("summary.value_name")}
data-summary-error=${String(d.attempted&&y?.path===`${n}.label`)}
aria-invalid=${"error"===v(`${n}.label`)?.kind?"true":"false"}
@input=${a=>m.mutate(e=>{e.blocks[t].values[c].label=a.target.value})} />
${v(`${n}.label`)?a`<div class="summary-problem error">${h(v(`${n}.label`))}</div>`:e}
@input=${a=>m.mutate(s=>{s.blocks[t].values[c].label=a.target.value})} />
${v(`${n}.label`)?a`<div class="summary-problem error">${h(v(`${n}.label`))}</div>`:s}
</div>
<div class="summary-source-field">
<button class="summary-source" type="button"
@@ -119,9 +119,9 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
data-summary-error=${String(d.attempted&&y?.path===`${n}.source`)}
aria-invalid=${"error"===$?.kind?"true":"false"}
aria-haspopup="listbox" aria-expanded=${k?"true":"false"}
@click=${a=>{a.stopPropagation(),k?m.closeSource():m.openSource(s.id,i.id)}}>
@click=${a=>{a.stopPropagation(),k?m.closeSource():m.openSource(e.id,i.id)}}>
<span class="summary-source-caption"><strong>${g}</strong>
${_?a`<small>${_}</small>`:e}</span>
${_?a`<small>${_}</small>`:s}</span>
${l("chevron")}
</button>
${k&&f?a`<div class="summary-source-picker"
@@ -135,39 +135,39 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
<div class="summary-source-results" role="listbox"
aria-label=${b("summary.select_source")}>
<div class="summary-source-group">${b("summary.system_group")}</div>
${["device_count","total_area","datetime"].map(e=>a`
${["device_count","total_area","datetime"].map(s=>a`
<button type="button" role="option"
?disabled=${d.busy}
aria-selected=${p===`system:${e}`?"true":"false"}
@click=${()=>m.setSource(s.id,i.id,`system:${e}`)}>
${b(`summary.system.${e}`)}
aria-selected=${p===`system:${s}`?"true":"false"}
@click=${()=>m.setSource(e.id,i.id,`system:${s}`)}>
${b(`summary.system.${s}`)}
</button>`)}
${w?a`<div class="summary-source-group">${b("summary.current_source")}</div>
<button type="button" role="option" class="broken" aria-selected="true"
?disabled=${d.busy}
@click=${()=>m.setSource(s.id,i.id,p)}>
@click=${()=>m.setSource(e.id,i.id,p)}>
${g}
</button>`:e}
</button>`:s}
<div class="summary-source-group">${b("summary.entities_group")}</div>
${f.entries.map(e=>a`<button type="button" role="option"
${f.entries.map(s=>a`<button type="button" role="option"
?disabled=${d.busy}
aria-selected=${p===`entity:${e.id}`?"true":"false"}
@click=${()=>m.setSource(s.id,i.id,`entity:${e.id}`)}>
<span>${e.label}</span><small>${e.id}</small>
aria-selected=${p===`entity:${s.id}`?"true":"false"}
@click=${()=>m.setSource(e.id,i.id,`entity:${s.id}`)}>
<span>${s.label}</span><small>${s.id}</small>
</button>`)}
${f.total?e:a`<div class="summary-empty">${b("summary.no_search_results")}</div>`}
${f.truncated?a`<div class="summary-refine">${b("summary.refine_search")}</div>`:e}
${f.total?s:a`<div class="summary-empty">${b("summary.no_search_results")}</div>`}
${f.truncated?a`<div class="summary-refine">${b("summary.refine_search")}</div>`:s}
</div>
</div>`:e}
${$?a`<div class="summary-problem ${$.kind}">${h($)}</div>`:e}
</div>`:s}
${$?a`<div class="summary-problem ${$.kind}">${h($)}</div>`:s}
</div>
<button class="summary-icon-button summary-value-remove" type="button"
title=${b("btn.delete")} aria-label=${b("btn.delete")} ?disabled=${d.busy}
@click=${()=>m.mutate(a=>{a.blocks[t].values.splice(c,1)})}>${l("close")}</button>
</div>`})}
<button class="summary-add summary-add-value" type="button"
?disabled=${s.values.length>=20||d.busy}
title=${s.values.length>=20?b("summary.limit_values"):""}
?disabled=${e.values.length>=20||d.busy}
title=${e.values.length>=20?b("summary.limit_values"):""}
@click=${()=>m.mutate(a=>{a.blocks[t].values.push(i())})}>
${l("plus")}${b("summary.add_value")}
</button>
@@ -186,11 +186,11 @@ globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc
${l("plus")}${b("summary.add_block")}
</button>
</section>
${d.error?a`<div class="summary-problem error" role="alert">${d.error}</div>`:e}
${d.error?a`<div class="summary-problem error" role="alert">${d.error}</div>`:s}
${d.conflict?a`<button class="btn ghost summary-reload" type="button"
?disabled=${d.busy} @click=${()=>m.reload()}>
<ha-icon icon="mdi:reload"></ha-icon>${b("summary.reload_current")}
</button>`:e}
</button>`:s}
`}
</div>
<div class="row summary-editor-footer" slot="footer">
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{ed as e,K as t,aX as n,I as i,ab as o,a9 as r,bO as a,bN as s,aW as c,aV as l,aY as d,ee as u,ef as f,bQ as m,eg as g}from"./houseplan-card-BWAph8ZF.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),a=i.binding.slice(o+1),s="device"===r?e.registry.devices?.[a]:null,c="entity"===r?e.registry.entities?.[a]:null,l="device"===r?a:c?.device_id,d="device"===r?s?.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(a))&&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 s=t(e);if(!s)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||s;v=y(v,a(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=s(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};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{ed as e,J as t,aX as n,H as i,aa as o,a8 as r,bO as a,bN as s,aW as c,aV as l,aY as d,ee as u,ef as f,bQ as m,eg as g}from"./houseplan-card-9fMSy3y3.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),a=i.binding.slice(o+1),s="device"===r?e.registry.devices?.[a]:null,c="entity"===r?e.registry.entities?.[a]:null,l="device"===r?a:c?.device_id,d="device"===r?s?.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(a))&&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 s=t(e);if(!s)continue;const c=n(f.rooms,e.id,m.walls,m.openCuts,i,m.cellCm,o,r,g.roomGeom,g.multiWallNodes)||s;v=y(v,a(c,m.physicalBodies)),yield}const _=m.cellCm/o;u+=s(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 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";import{n as t,b as n}from"./zigbee-topology-D0gydI7H.js";import{aI as e}from"./houseplan-card-BWAph8ZF.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 m(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 g(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,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=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&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(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 m(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,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";import{n as t,b as n}from"./zigbee-topology-CI6PJorK.js";import{aI as e}from"./houseplan-card-9fMSy3y3.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 m(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 g(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,g=null;const y=new Promise(t=>{u=t}),w=new Promise((t,n)=>{p=t,g=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&&g?.(a("invalid_payload"))},{type:"mqtt/subscribe",topic:`${l}/bridge/response/networkmap`});"function"==typeof f&&b.push(f),await m(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 m(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,g as refreshZ2mTopology,u as subscribeZigbeeTopology,l as zigbeeTopologyRuntimeSnapshot};
+1 -1
View File
@@ -1 +1 @@
globalThis.__HOUSEPLAN_BUILD_FINGERPRINT__="c6e9a7f9c0e3096b40b9ae51df9d052aeddc8359d008fd86a2e4cbef1aba717f";try{await import("./houseplan-assets/houseplan-card-BWAph8ZF.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__="54fcdd48a85ca3f133f7a631e38722f7eb58d88c475a1cfb768130946dffad32";try{await import("./houseplan-assets/houseplan-card-9fMSy3y3.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
+2 -2
View File
@@ -19,8 +19,8 @@
switch — turning it off opens a five-mode segment that starts at the space's
current mode; comfort bounds are two °C fields with a Cold / Comfort / Hot
legend. **Save** is enabled only when something changed, and closing a
dialog with unsaved changes asks first; broken values (an inverted or empty
bound, a north outside 0–359°, a missing binding, a non-positive glow radius)
dialog with unsaved changes asks first; broken values (an empty or
non-numeric bound, a north outside 0–359°, a missing binding)
are named under the field and a "Review N fields" link in the footer jumps
to the first one. The "Ask for confirmation" row is shown only for actions
that do something; the Zigbee links card no longer repeats its heading; the
+1 -2
View File
@@ -27,8 +27,7 @@
два поля °C с легендой «Холодно / Комфорт / Жарко». **Сохранить** активна
только при изменениях, закрытие с несохранёнными изменениями сначала
спрашивает; сломанные значения (пустая или нечисловая граница, север вне
0–359°, не выбранная привязка, неположительный радиус свечения) названы под
полем, а ссылка «Проверить N полей» в футере ведёт к первому. Строка
0–359°, не выбранная привязка) названы под полем, а ссылка «Проверить N полей» в футере ведёт к первому. Строка
«Спрашивать подтверждение» показывается только у действий; карточка «Связи
Zigbee» больше не повторяет заголовок; ленивый редактор загружается с простым
«Загрузка…». Все настройки, ключи и сохранённые значения прежние — переделаны
+3 -2
View File
@@ -463,7 +463,7 @@ elements:
changes". Closing a dialog with unsaved changes — by the close button,
**Cancel** or a click outside — asks first whether to discard them. An invalid
value — an empty or non-numeric temperature bound, a north outside 0–359°, a
missing binding, a non-positive glow radius — is named in red under the field,
missing binding — is named in red under the field,
and the **Review N fields** link in the footer jumps to the first one.
### Display settings
@@ -793,7 +793,8 @@ chosen, Save stays disabled and the reason is written under the field.
**Ask for confirmation** is shown only for actions that do something (toggle or
run). The light-source role and the glow mode are segments; with **Never** the
whole glow block is dimmed and explains why. The glow radius is a field with a
unit — empty means the general radius, and the hint names it. The dialog shows
unit — empty means the general radius, and the hint names it; a value that is
not a positive number is saved as the general radius too, as before. The dialog shows
binding provenance, exact next tap result, skipped targets and a live
presentation preview in a tinted **Display preview** block. Icon size and
rotation are two sliders with numbers. A saved missing source is shown as
+7 -7
View File
@@ -409,9 +409,9 @@ Zigbee2MQTT для каждого указанного базового топи
написано «Есть несохранённые изменения». Если закрыть диалог крестиком,
кнопкой **Отмена** или щелчком мимо него при несохранённых изменениях, House
Plan сначала спросит, сбросить ли их. Неверное значение — пустая или нечисловая
граница температуры, север вне 0–359°, не выбранная привязка, неположительный
радиус свечения — подписано под полем красным, а ссылка **Проверить N полей** в
футере ведёт к первому такому полю.
граница температуры, север вне 0–359°, не выбранная привязка — подписано под
полем красным, а ссылка **Проверить N полей** в футере ведёт к первому такому
полю.
<!-- docs-section: input -->
@@ -524,9 +524,9 @@ desktop: для точного рисования, Resize, модификато
| Масштаб | См или дюймов на клетку | Переводит сетку в реальные размеры и площади; новое пространство начинается с 1 см или 1 дюйма по системе единиц HA |
| Внешний вид | Всегда отображать границы комнат | Строка с тумблером: рисует контуры комнат в просмотре |
| Внешний вид | Стены нулевой толщины | Сегмент «Пунктирные / Сплошные» с образцом линии |
| Внешний вид | Видимые слои | Две строки с тумблерами: **Декоративный слой** и **Двери, окна и ворота**. Включено — видно; выключенный декоративный слой не рисует линии, фигуры, текст и мебель в просмотре, выключенные проёмы скрывают только их символы — свет, солнечные лучи и датчики продолжают работать |
| Внешний вид | Видимые слои | Две строки с тумблерами: **Декоративный слой** и **Двери, окна и ворота**. Включено — видно; выключенный декоративный слой не рисует линии, фигуры, текст и мебель в просмотре (в редакторе подложки они остаются видимыми), выключенные проёмы скрывают только их символы — свет, солнечные лучи и датчики продолжают работать |
| Карточки комнат | Показывать названия комнат | Рисует карточки комнат в Просмотре, киоске и статической карточке; при выключении не оставляет упрощённых подписей |
| Карточки комнат | Сигнал Zigbee рядом с устройствами | Переопределяет базовую настройку карточки для этого пространства |ожки они остаются видимыми |
| Карточки комнат | Сигнал Zigbee рядом с устройствами | Переопределяет базовую настройку карточки для этого пространства |
| Карточки комнат | Температура / влажность / сигнал / свет | Четыре плитки под тумблером названий добавляют показатели под названием комнаты; без названий плитки неактивны, а сообщение предлагает включить их |
| Карточки комнат | Размер шрифта карточек | Слайдер с числом и «Сбросить до 100%»: масштабирует все комнатные карточки пространства, 50–300%; ниже — образец карточки |
@@ -1071,7 +1071,7 @@ binding tombstone не вырезает её из живого устройст
| Использовать температуру climate | Добавляет `current_temperature` термостата/кондиционера в маркер и среднее назначенной ему комнаты |
| Скрыть / Показать | Кнопка слева в футере диалога. После сохранения убирает или возвращает значок; LQI и климатические данные скрытого устройства всё ещё могут участвовать в среднем назначенной комнаты |
| Удалить | Кнопка рядом со «Скрыть». Общий диалог House Plan называет устройство и объясняет последствия; после подтверждения устройство полностью исчезает с плана и позднее может быть добавлено заново |
| Радиус свечения | Поле с единицей; пустое — общий радиус, подсказка называет его. Локально переопределяет общий радиус, 0.1–100 м в хранилище |
| Радиус свечения | Поле с единицей; пустое — общий радиус, подсказка называет его; значение, не являющееся положительным числом, тоже сохраняется как общий радиус, как и раньше. Локально переопределяет общий радиус, 0.1–100 м в хранилище |
| Иконка | Ручная `mdi:*`; пусто — автоматический подбор. Автовариант показывается в поле как значок с именем `mdi:*`, но не сохраняется как ручная замена |
| Отображение | Иконка, иконка + активность или значение вместо иконки. Ниже сразу видны фактический результат, источник и интеграция |
| Размер и поворот иконки | Два слайдера с числами: масштаб маркера (×0.5–×3) и угол (шаг 5°) |
@@ -1731,7 +1731,7 @@ WebP и безопасный SVG; лимит 2 МиБ относится к со
| Толстая внешняя стена, режим «внутренние углы» | Луч начинается с комнатной стороны оконного тоннеля |
| Толстая внешняя стена, режим «внешние углы» | Луч начинается с фасадной стороны и проходит к комнате только внутри оконного тоннеля |
| Стена нулевой толщины | Оба режима выглядят одинаково |
| «Скрыть проёмы» включено | Символ окна скрыт, луч продолжает работать |
| Слой «Двери, окна и ворота» выключен | Символ окна скрыт, луч продолжает работать |
| Белый план | По бокам луча есть тонкая 1px тёмная кромка для читаемости |
| Любая погода, включая дождь и снег | Погода не влияет на лучи |
+20 -3
View File
@@ -25,8 +25,11 @@ Always и фиксированным свечением), раскрывает
из архива дизайнера (светлая тема, 1120 px при devicePixelRatio 2).
Это **диагностические** кадры, а не golden-базы: они не принимаются
`golden:accept` и не участвуют в `golden:verify`. Эталоны одиннадцати сцен живут
отдельно и закрываются AC10. PNG пережаты в палитру 256 цветов — для сравнения
`golden:accept` и не участвуют в `golden:verify`. Эталоны живут отдельно и
закрываются AC10: принято **13 сцен** (`ed2af1b1`) — одиннадцать из ТЗ (список
AC10 унаследован от #598, где диалог комнаты не менялся) плюс две
`room-temperature-dialog-{desktop-en,mobile-ru}`, потому что диалог комнаты в
скоупе #600. PNG пережаты в палитру 256 цветов — для сравнения
раскладки этого достаточно, а вес папки остаётся в полумегабайте.
## Статус по диалогам
@@ -66,7 +69,7 @@ Always и фиксированным свечением), раскрывает
|---|---|---|---|
| Образец карточки | убран (§6.1 «Font sizes») | под подсказкой размеров, на тинте | решение владельца Q2 |
| «?» у Basics | у поля Home Assistant area | у поля Home Assistant area (перенесён с заголовка карточки) | §6.1 |
| Подписи сегмента заливки | None · Zigbee · Lights · Temperature · Custom | None · Zigbee · Lights · Temperature · Custom (короткие ключи `room.fill_seg_*` для двух длинных) | §6.1 |
| Подписи сегмента заливки | None · Zigbee · Lights · Temperature · Custom, по одной строке на пункт | те же (короткие ключи `room.fill_seg_*` для двух длинных). Ревью r1 M1: «Temperature» рвалось посреди слова в пяти равных колонках — колонка сегмента больше не сжимается ниже самого длинного слова, слова переносятся только по пробелам, не поместившийся сегмент переносится на вторую строку целыми кнопками; свидетель — `smoke_dialog_segments_i18n` (четыре диалога × en/ru/de/fr) | §6.1, §3.1 «Сегмент» |
| Подписи источников | Temperature / Humidity | Temperature source / Humidity source (прежние ключи) | текст, не раскладка |
| Поле цвета «Свой цвет» | `input[type=color]` | плашка вокруг `hp-color-opacity` | Q5 |
| Кнопка выбора датчика | в потоке, панель с поиском | то же (`sourcePicker` набора) | §3.1 «Кнопка выбора источника» |
@@ -83,6 +86,20 @@ Always и фиксированным свечением), раскрывает
| Иконка | поле с превью, Clear, Pin в подсказке | то же; в HA — `ha-icon-picker` вместо текстового поля | §7.1 |
| Value badge | тумблер, Value, Position сегментом | то же; предупреждения бейджа — заметки и callout'ы | §7.1 |
## AC8: девять прямых дефектов выпущенного — свидетель на каждый
| № | Дефект (тело issue) | Чем закрыт | Свидетель |
|---|---|---|---|
| 1 | дублированный заголовок Zigbee links | карточка рисует заголовок и «?», `hp-zigbee-topology-settings` в режиме `embedded` своего не рисует | `smoke_general_settings_form` → `zigbeeHeadingOnce`; мутант `topology-embedded-draws-its-own-heading` |
| 2 | «Fill color» дважды в строке заливки пространства | плашка цвета с одной подписью поля (`colorRow` + `colorField`, у пикера `hide-label`) | `smoke_space_settings_form` → `hexIsPrinted`, `noNativeColorInputs`; `noLegacyMarkup` |
| 3 | семь `rhint`-абзацев в четырёх диалогах | пояснения — под «?» (`_help`/`shelp`), сообщения о состоянии — callout'ы (К5) | `noLegacyMarkup` в четырёх фокусных смоках (класс `.rhint` отсутствует); `test/i18n-dead-keys`; мутант `state-callout-hidden-under-help` |
| 4 | карточка внутри карточки (`fieldset` в Light and glow, Value badge) | плоские блоки `.hpf-block` с подзаголовком | `smoke_device_settings_form` → `noLegacyMarkup` (`fieldset`, `.markerlightgroup`), `badgeBlock`, `neverDisablesGlowBlock` |
| 5 | поповер «?» обрезается границей диалога комнаты | подсказка живёт в top layer (Popover API) либо в портале `.overlay-portal` **вне** поверхности диалога; тело формы без своего скроллера — резать нечем | **`smoke_dialog_help_clipping`**: короткое окно, «?» нижней карточки комнаты, подсказка выходит за край скроллера и остаётся hit-test'ируемой во всех точках; четыре ветки — нативный `<dialog>` и `ha-dialog` × Popover и fallback. Ветка `ha-dialog` — заглушка с ловушками настоящей mwc-поверхности (`transform` + `overflow: hidden` + свой скроллер); настоящий `ha-dialog` (#505, загрузка колеса HA-frontend) — отдельная диагностическая приёмка владельца, `demo/capture_summary_panel_505.mjs` как образец |
| 6 | белый инпут на тёмной теме у Glow radius | поле набора `.hpf-unit` на токенах темы | `pairs/device-dark.png`; `smoke_device_settings_form` |
| 7 | два скролла (тело формы и оболочка) | скроллер один — `.content` в `hp-dialog`; `.body` без `max-height`/`overflow` | фокусные смоки → `singleScroller` / `bodyHasNoOwnScroller` |
| 8 | пустое пространство внизу | `.body` без `max-height` и лишнего `padding-bottom` | те же; кадры `pairs/` |
| 9 | «Загружаем редактор…» | `editor.loading` → «Загрузка…» / «Loading…» | `src/i18n/*.json` |
## Принятые адаптации
Расхождения, которые **не** являются дефектом, потому что продиктованы
+17
View File
@@ -10496,6 +10496,23 @@ const MUTANT_DEFINITIONS = [
replace: " valueBadgePosition: position,\n valueBadgeTouched: false,",
}],
},
{
id: 'form-kit-segment-breaks-words',
guard: 'node demo/smoke_dialog_segments_i18n.mjs',
because: '#600 ревью r1 M1: пять равных колонок сегмента с overflow-wrap: anywhere рвали '
+ '«Temperature» посреди слова, и ни один смок этого не видел — scrollWidth контейнера не '
+ 'рос. Колонка не сжимается ниже самого длинного слова, слова переносятся только по '
+ 'пробелам; вернуть прежние две строки — вернуть дефект в четырёх локалях',
patches: [{
file: 'src/styles/form-kit.styles.ts',
find: ' min-width: fit-content;\n min-height: 38px;\n flex: 1 1 0;',
replace: ' min-height: 38px;\n flex: 1 1 0;',
}, {
file: 'src/styles/form-kit.styles.ts',
find: ' text-align: center;\n overflow-wrap: normal;\n }',
replace: ' text-align: center;\n overflow-wrap: anywhere;\n }',
}],
},
{
id: 'form-kit-segment-drops-radio-semantics',
guard: 'node --test test/form-kit.test.mjs',
+1 -3
View File
@@ -187,7 +187,6 @@ export function renderMarkerDialog(this: HouseplanEditorRuntime): TemplateResult
node?.focus();
};
const bindingProblem = problemFor('marker-binding');
const radiusProblem = problemFor('marker-glow-radius');
// ------------------------------------------------------------ Basics
const bindingBanner = bindingStatus?.kind === 'ha_disabled'
@@ -565,12 +564,11 @@ export function renderMarkerDialog(this: HouseplanEditorRuntime): TemplateResult
${glowValue}
${field({
label: t('marker.glow_radius_label'), htmlFor: 'marker-glow-radius', help: this._help('marker.glow_radius.help'),
error: radiusProblem ? st(radiusProblem.message) : undefined,
hint: d.glowRadius.trim() ? undefined : st('marker.glow_radius_empty_hint', { v: `${this.host._glowRadiusPlaceholder} ${unit}` }),
control: unitInput({
id: 'marker-glow-radius', unit, min: 0.5, step: 0.5, value: d.glowRadius,
placeholder: this.host._glowRadiusPlaceholder, ariaLabel: t('marker.glow_radius_label'),
disabled: glowSourceDisabled, invalid: !!radiusProblem,
disabled: glowSourceDisabled,
describedBy: glowSourceDisabled || passiveSource ? 'marker-glow-disabled-hint' : undefined,
onInput: (raw) => (this.host._markerDialog = { ...d, glowRadius: raw }),
}),
+6 -15
View File
@@ -6,7 +6,6 @@
* в отпечаток не входят. Флаги `*Touched` и `original*` входят: они меняются
* только действием человека, и это тоже изменение.
*/
import { strictNumber } from '../space-dialog';
import type { HouseplanEditorHostPort } from '../houseplan-editor-runtime';
import { dialogDirty, forgetDialogBaseline, rememberDialogBaseline, stableKey } from './dialog-baseline';
@@ -34,28 +33,20 @@ export function markerDirty(host: object, d: MarkerDialogDraft): boolean {
export interface MarkerProblem {
field: string;
message: 'marker.error_binding' | 'marker.error_glow_radius';
}
/** Радиус: пусто (общий радиус) либо положительное число — тем же парсером, что и запись. */
export function glowRadiusValid(raw: string): boolean {
if (!raw.trim()) return true;
const n = strictNumber(raw);
return n !== null && n > 0;
message: 'marker.error_binding';
}
/**
* Ошибки черновика (§7 референса): привязка обязательна в режиме HA (прежнее
* условие Save, теперь названное словами), радиус свечения — положительное число
* либо пусто (общий радиус).
* Ошибки черновика: привязка обязательна в режиме HA — прежнее условие Save,
* теперь названное словами под полем. Радиус свечения ошибкой **не является**
* (ревью #600 r1, M2): как и на `dev`, непустое нечисло или неположительное
* значение при сохранении молча становится «общим радиусом» (`null`), и К10
* закрытым списком других условий не называет.
*/
export function markerProblems(d: MarkerDialogDraft): MarkerProblem[] {
const problems: MarkerProblem[] = [];
if (d.bindingMode === 'ha' && (!d.binding || d.binding === 'virtual')) {
problems.push({ field: 'marker-binding', message: 'marker.error_binding' });
}
if (!glowRadiusValid(d.glowRadius)) {
problems.push({ field: 'marker-glow-radius', message: 'marker.error_glow_radius' });
}
return problems;
}
-1
View File
@@ -85,7 +85,6 @@
"marker.size.help.aria": "Hilfe: Symbolgröße und Drehung",
"marker.size_short": "Größe",
"marker.error_binding": "Wählen Sie ein Gerät oder eine Entität zum Verknüpfen.",
"marker.error_glow_radius": "Geben Sie einen Radius größer als 0 ein oder lassen Sie das Feld leer.",
"room.fill_seg_lqi": "Zigbee",
"room.fill_seg_custom": "Eigene"
}
-1
View File
@@ -85,7 +85,6 @@
"marker.size.help.aria": "Help: icon size and rotation",
"marker.size_short": "Size",
"marker.error_binding": "Choose a device or entity to bind.",
"marker.error_glow_radius": "Enter a radius greater than 0, or leave it empty.",
"room.fill_seg_lqi": "Zigbee",
"room.fill_seg_custom": "Custom"
}
-1
View File
@@ -85,7 +85,6 @@
"marker.size.help.aria": "Aide : taille et rotation de l’icône",
"marker.size_short": "Taille",
"marker.error_binding": "Choisissez un appareil ou une entité à lier.",
"marker.error_glow_radius": "Saisissez un rayon supérieur à 0 ou laissez le champ vide.",
"room.fill_seg_lqi": "Zigbee",
"room.fill_seg_custom": "Perso"
}
-1
View File
@@ -85,7 +85,6 @@
"marker.size.help.aria": "Справка: размер и поворот иконки",
"marker.size_short": "Размер",
"marker.error_binding": "Выберите устройство или сущность для привязки.",
"marker.error_glow_radius": "Введите радиус больше 0 или оставьте поле пустым.",
"room.fill_seg_lqi": "Zigbee",
"room.fill_seg_custom": "Свой цвет"
}
+10 -1
View File
@@ -144,6 +144,13 @@ function sharedCss(options: FormKitCssOptions, withSwitch: boolean): string {
* Числа — из §3.1 `SPEC.md` референса; цвета — через переменные темы HA, а не
* hex прототипа: тёмная тема обязательна. Всё здесь видит только ленивый
* редакторский граф — панель эти правила не получает (#597 К9).
*
* Сегмент (`-seg`): подпись варианта не рвётся посреди слова (ревью #600 r1,
* M1 — «Temperatur/e» в пяти колонках). Колонка не сжимается ниже самого
* длинного слова (`min-width: fit-content`; браузер без него берёт `0`
* строкой выше), слова переносятся только по пробелам (`overflow-wrap:
* normal`), а если варианты не помещаются в ряд — сегмент переносится на
* вторую строку целыми кнопками (`flex-wrap`), а не ломает текст.
*/
function extrasCss(options: FormKitCssOptions): string {
const { form, prefix, tokens } = options;
@@ -285,6 +292,7 @@ function extrasCss(options: FormKitCssOptions): string {
.${p}-toggle > input:disabled::before { opacity: .4; }
.${p}-seg {
display: flex;
flex-wrap: wrap;
min-width: 0;
gap: 3px;
padding: 3px;
@@ -296,6 +304,7 @@ function extrasCss(options: FormKitCssOptions): string {
position: relative;
display: flex;
min-width: 0;
min-width: fit-content;
min-height: 38px;
flex: 1 1 0;
align-items: center;
@@ -309,7 +318,7 @@ function extrasCss(options: FormKitCssOptions): string {
font-weight: 500;
cursor: pointer;
text-align: center;
overflow-wrap: anywhere;
overflow-wrap: normal;
}
.${p}-seg input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }
.${p}-seg label:has(input:checked) {
+3 -1
View File
@@ -166,6 +166,7 @@
.hpf-toggle > input:disabled::before { opacity: .4; }
.hpf-seg {
display: flex;
flex-wrap: wrap;
min-width: 0;
gap: 3px;
padding: 3px;
@@ -177,6 +178,7 @@
position: relative;
display: flex;
min-width: 0;
min-width: fit-content;
min-height: 38px;
flex: 1 1 0;
align-items: center;
@@ -190,7 +192,7 @@
font-weight: 500;
cursor: pointer;
text-align: center;
overflow-wrap: anywhere;
overflow-wrap: normal;
}
.hpf-seg input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }
.hpf-seg label:has(input:checked) {
+3 -1
View File
@@ -152,6 +152,7 @@
.hpf-toggle > input:disabled::before { opacity: .4; }
.hpf-seg {
display: flex;
flex-wrap: wrap;
min-width: 0;
gap: 3px;
padding: 3px;
@@ -163,6 +164,7 @@
position: relative;
display: flex;
min-width: 0;
min-width: fit-content;
min-height: 38px;
flex: 1 1 0;
align-items: center;
@@ -176,7 +178,7 @@
font-weight: 500;
cursor: pointer;
text-align: center;
overflow-wrap: anywhere;
overflow-wrap: normal;
}
.hpf-seg input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; pointer-events: none; }
.hpf-seg label:has(input:checked) {