From 37b39e7a1eef2e457b2895716e1c03a836b81a30 Mon Sep 17 00:00:00 2001 From: Matysh Date: Wed, 22 Jul 2026 12:19:15 +0300 Subject: [PATCH] fix v1.31.2: merge/split room pick highlight visible again - .room.picked moved after .room.outlined: equal specificity, source order silently killed the amber highlight in markup (gotcha x4, documented inline) - smoke_merge_highlight.mjs (waits out the 0.12s transition before reading computed colors); TESTING/CHANGELOG same-commit --- custom_components/houseplan/const.py | 2 +- .../houseplan/frontend/houseplan-card.js | 11 +++++---- custom_components/houseplan/manifest.json | 2 +- demo/smoke_merge_highlight.mjs | 24 +++++++++++++++++++ demo/srv/assets/houseplan-card.js | 11 +++++---- dist/houseplan-card.js | 11 +++++---- docs/CHANGELOG.md | 7 ++++++ docs/TESTING.md | 3 +++ package.json | 2 +- src/houseplan-card.ts | 2 +- src/styles.ts | 9 +++---- 11 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 demo/smoke_merge_highlight.mjs diff --git a/custom_components/houseplan/const.py b/custom_components/houseplan/const.py index 02bf7a4..d5dd1ea 100755 --- a/custom_components/houseplan/const.py +++ b/custom_components/houseplan/const.py @@ -11,7 +11,7 @@ PLANS_DIR = "houseplan/plans" # relative to the HA configuration directory FILES_URL = "/houseplan_files/files" FILES_DIR = "houseplan/files" CONF_ADMIN_ONLY = "admin_only" -VERSION = "1.31.1" +VERSION = "1.31.2" DEFAULT_CONFIG: dict = { "spaces": [], diff --git a/custom_components/houseplan/frontend/houseplan-card.js b/custom_components/houseplan/frontend/houseplan-card.js index 2233f7e..b02d280 100755 --- a/custom_components/houseplan/frontend/houseplan-card.js +++ b/custom_components/houseplan/frontend/houseplan-card.js @@ -506,15 +506,16 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow @media (max-width: 720px) { .modetab .ml { display: none; } } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ .room.picked { stroke: #ffc14d; stroke-width: 3; fill: rgba(255, 193, 77, 0.25); } - .room.outlined { - stroke: rgba(62, 166, 255, 0.55); - fill: rgba(62, 166, 255, 0.06); - } .griddot { fill: var(--hp-accent); opacity: 0.75; @@ -1969,4 +1970,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow - `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.31.1 ","background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.31.2 ","background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/custom_components/houseplan/manifest.json b/custom_components/houseplan/manifest.json index a9bd043..bb833d8 100755 --- a/custom_components/houseplan/manifest.json +++ b/custom_components/houseplan/manifest.json @@ -16,5 +16,5 @@ "issue_tracker": "https://github.com/Matysh/houseplan-card/issues", "requirements": [], "single_config_entry": true, - "version": "1.31.1" + "version": "1.31.2" } diff --git a/demo/smoke_merge_highlight.mjs b/demo/smoke_merge_highlight.mjs new file mode 100644 index 0000000..4bd26f5 --- /dev/null +++ b/demo/smoke_merge_highlight.mjs @@ -0,0 +1,24 @@ +import { launch } from './serve.mjs'; +const { page, browser } = await launch(); +const res = await page.evaluate(async () => { + const out = {}; + const c = window.__card; + const sr = () => c.shadowRoot || c.renderRoot; + c._setMode('plan'); c._tool = 'merge'; await c.updateComplete; + const room = c._spaceModel().rooms.find((r) => r.name); + c._mergeSel = room.id; c.requestUpdate(); await c.updateComplete; + await new Promise((r) => setTimeout(r, 250)); // дождаться transition 0.12s + const el = [...sr().querySelectorAll('.room')].find((e) => e.classList.contains('picked')); + out.pickedRendered = !!el; + const cs = el ? getComputedStyle(el) : null; + out.amberStroke = cs ? cs.stroke.includes('255, 193, 77') : null; + out.amberFill = cs ? cs.fill.includes('255, 193, 77') : null; + // split-выбор подсвечивается так же + c._mergeSel = null; c._tool = 'split'; c._splitSel = { roomId: room.id }; c.requestUpdate(); await c.updateComplete; + await new Promise((r) => setTimeout(r, 250)); + const el2 = [...sr().querySelectorAll('.room')].find((e) => e.classList.contains('picked')); + out.splitPicked = !!el2 && getComputedStyle(el2).stroke.includes('255, 193, 77'); + return out; +}); +console.log(JSON.stringify(res)); +await browser.close(); diff --git a/demo/srv/assets/houseplan-card.js b/demo/srv/assets/houseplan-card.js index 2233f7e..b02d280 100755 --- a/demo/srv/assets/houseplan-card.js +++ b/demo/srv/assets/houseplan-card.js @@ -506,15 +506,16 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow @media (max-width: 720px) { .modetab .ml { display: none; } } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ .room.picked { stroke: #ffc14d; stroke-width: 3; fill: rgba(255, 193, 77, 0.25); } - .room.outlined { - stroke: rgba(62, 166, 255, 0.55); - fill: rgba(62, 166, 255, 0.06); - } .griddot { fill: var(--hp-accent); opacity: 0.75; @@ -1969,4 +1970,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow - `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.31.1 ","background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.31.2 ","background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/dist/houseplan-card.js b/dist/houseplan-card.js index 2233f7e..b02d280 100755 --- a/dist/houseplan-card.js +++ b/dist/houseplan-card.js @@ -506,15 +506,16 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow @media (max-width: 720px) { .modetab .ml { display: none; } } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ .room.picked { stroke: #ffc14d; stroke-width: 3; fill: rgba(255, 193, 77, 0.25); } - .room.outlined { - stroke: rgba(62, 166, 255, 0.55); - fill: rgba(62, 166, 255, 0.06); - } .griddot { fill: var(--hp-accent); opacity: 0.75; @@ -1969,4 +1970,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow - `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.31.1 ","background:#3ea6ff;color:#04121f;font-weight:700",""); + `}}Ii.properties={hass:{attribute:!1},_config:{state:!0},_space:{state:!0},_layout:{state:!0},_devices:{state:!0},_tip:{state:!0},_selId:{state:!0},_toast:{state:!0},_serverCfg:{state:!0},_mode:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_mergeSel:{state:!0},_openingDialog:{state:!0},_openingInfo:{state:!0},_mergeDialog:{state:!0},_splitSel:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_settingsDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},Ii.styles=mi,customElements.get("houseplan-card")||customElements.define("houseplan-card",Ii),window.customCards=window.customCards||[],window.customCards.find(t=>"houseplan-card"===t.type)||window.customCards.push({type:"houseplan-card",name:"House Plan Card",description:"Interactive house plan: spaces, rooms and devices with live states and drag layout."}),console.info("%c HOUSEPLAN-CARD %c v1.31.2 ","background:#3ea6ff;color:#04121f;font-weight:700",""); diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 302feee..59689eb 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## v1.31.2 — 2026-07-22 +- Plan editor: the room picked with the **Merge** tool (and the room selected + for **Split**) is highlighted amber again. The `.outlined` markup style, + added later in the stylesheet, was silently overriding the `.picked` + highlight at equal specificity (source-order gotcha #4 — rule order fixed + and documented in the stylesheet). + ## v1.31.1 — 2026-07-22 - Plan editor: interacting with a room card (drag, corner-resize or a plain click) no longer leaks into the active markup tool — previously the click diff --git a/docs/TESTING.md b/docs/TESTING.md index ac07d6f..332c049 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -140,6 +140,9 @@ Run the *core flows* (marked ★ below) in each environment at least once per mi (explicit ripple color still wins); off/white lights unchanged [auto] - [ ] Alarm pulse (v1.27.0): leak/smoke/gas/CO/siren in 'on' pulse a red ring over any display mode; clears on 'off'; unavailable never alarms [auto]; reduced-motion static +- [ ] Merge/split pick highlight (v1.31.2): the first room clicked with the + Merge tool (and the split-selected room) gets an amber outline + fill; + visible over the blue markup outlines [auto] - [ ] Card vs tool conflict (v1.31.1): in the Plan editor, dragging/resizing or clicking a room card never feeds the active tool (no draw point, no delete-room confirm, no merge/split pick); clicks past the card work [auto] diff --git a/package.json b/package.json index 6734843..16734d7 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "houseplan-card", - "version": "1.31.1", + "version": "1.31.2", "description": "Interactive house plan Lovelace card for Home Assistant", "license": "MIT", "type": "module", diff --git a/src/houseplan-card.ts b/src/houseplan-card.ts index ddba2cf..6d0c45a 100755 --- a/src/houseplan-card.ts +++ b/src/houseplan-card.ts @@ -32,7 +32,7 @@ import './space-card'; import { cardStyles } from './styles'; import { langOf, t, type I18nKey } from './i18n'; -const CARD_VERSION = '1.31.1'; +const CARD_VERSION = '1.31.2'; const LS_KEY = 'houseplan_card_layout_v1'; const LS_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering const LS_ZOOM = 'houseplan_card_zoom_v1'; diff --git a/src/styles.ts b/src/styles.ts index 977b836..98ff408 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -503,15 +503,16 @@ export const cardStyles = css` @media (max-width: 720px) { .modetab .ml { display: none; } } + .room.outlined { + stroke: rgba(62, 166, 255, 0.55); + fill: rgba(62, 166, 255, 0.06); + } + /* AFTER .outlined: same specificity — source order decides (gotcha x4) */ .room.picked { stroke: #ffc14d; stroke-width: 3; fill: rgba(255, 193, 77, 0.25); } - .room.outlined { - stroke: rgba(62, 166, 255, 0.55); - fill: rgba(62, 166, 255, 0.06); - } .griddot { fill: var(--hp-accent); opacity: 0.75;