fix v1.18.1: the drawing ruler badge was invisible — .stage.markup hides .devlayer

The v1.18.0 measure label was rendered inside .devlayer, which markup mode hides
entirely (display:none) so icons don't obstruct drawing. Moved it to its own
.measurelayer. Verified visually on a real segment (3.60 m).
This commit is contained in:
Matysh
2026-07-16 06:53:31 +03:00
parent 18a0d279a7
commit 4593d96955
9 changed files with 37 additions and 12 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ PLANS_DIR = "houseplan/plans" # relative to the HA configuration directory
FILES_URL = "/houseplan_files/files" FILES_URL = "/houseplan_files/files"
FILES_DIR = "houseplan/files" FILES_DIR = "houseplan/files"
CONF_ADMIN_ONLY = "admin_only" CONF_ADMIN_ONLY = "admin_only"
VERSION = "1.18.0" VERSION = "1.18.1"
DEFAULT_CONFIG: dict = { DEFAULT_CONFIG: dict = {
"spaces": [], "spaces": [],
@@ -239,6 +239,11 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
z-index: 1; z-index: 1;
} }
.roomlabel:active { cursor: grabbing; } .roomlabel:active { cursor: grabbing; }
.measurelayer {
position: absolute;
inset: 0;
pointer-events: none;
}
.measurelabel { .measurelabel {
position: absolute; position: absolute;
transform: translate(12px, -150%); transform: translate(12px, -150%);
@@ -1126,8 +1131,8 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
<div class="devlayer" style="--icon-size:${(r*i[2]/n.w).toFixed(3)}cqw"> <div class="devlayer" style="--icon-size:${(r*i[2]/n.w).toFixed(3)}cqw">
${s.map(t=>this._renderDevice(t,n))} ${s.map(t=>this._renderDevice(t,n))}
${a.showNames&&!this._markup?e.rooms.map(t=>this._renderRoomLabel(t,e,n,a)):K} ${a.showNames&&!this._markup?e.rooms.map(t=>this._renderRoomLabel(t,e,n,a)):K}
${this._markup&&"draw"===this._tool&&this._path.length&&this._cursorPt&&!this._contourClosed?this._renderMeasureLabel(n):K}
</div> </div>
${this._markup&&"draw"===this._tool&&this._path.length&&this._cursorPt&&!this._contourClosed?j`<div class="measurelayer">${this._renderMeasureLabel(n)}</div>`:K}
</div> </div>
${this._zoom>1?j`<div class="zoombadge">${Math.round(100*this._zoom)}%</div>`:K} ${this._zoom>1?j`<div class="zoombadge">${Math.round(100*this._zoom)}%</div>`:K}
</div> </div>
@@ -1428,4 +1433,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
</button> </button>
</div> </div>
</div> </div>
</div>`}}ue.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},_markup:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},ue.styles=Vt,customElements.get("houseplan-card")||customElements.define("houseplan-card",ue),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.18.0 ","background:#3ea6ff;color:#04121f;font-weight:700",""); </div>`}}ue.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},_markup:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},ue.styles=Vt,customElements.get("houseplan-card")||customElements.define("houseplan-card",ue),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.18.1 ","background:#3ea6ff;color:#04121f;font-weight:700","");
+1 -1
View File
@@ -16,5 +16,5 @@
"issue_tracker": "https://github.com/Matysh/houseplan-card/issues", "issue_tracker": "https://github.com/Matysh/houseplan-card/issues",
"requirements": [], "requirements": [],
"single_config_entry": true, "single_config_entry": true,
"version": "1.18.0" "version": "1.18.1"
} }
+7 -2
View File
@@ -239,6 +239,11 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
z-index: 1; z-index: 1;
} }
.roomlabel:active { cursor: grabbing; } .roomlabel:active { cursor: grabbing; }
.measurelayer {
position: absolute;
inset: 0;
pointer-events: none;
}
.measurelabel { .measurelabel {
position: absolute; position: absolute;
transform: translate(12px, -150%); transform: translate(12px, -150%);
@@ -1126,8 +1131,8 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
<div class="devlayer" style="--icon-size:${(r*i[2]/n.w).toFixed(3)}cqw"> <div class="devlayer" style="--icon-size:${(r*i[2]/n.w).toFixed(3)}cqw">
${s.map(t=>this._renderDevice(t,n))} ${s.map(t=>this._renderDevice(t,n))}
${a.showNames&&!this._markup?e.rooms.map(t=>this._renderRoomLabel(t,e,n,a)):K} ${a.showNames&&!this._markup?e.rooms.map(t=>this._renderRoomLabel(t,e,n,a)):K}
${this._markup&&"draw"===this._tool&&this._path.length&&this._cursorPt&&!this._contourClosed?this._renderMeasureLabel(n):K}
</div> </div>
${this._markup&&"draw"===this._tool&&this._path.length&&this._cursorPt&&!this._contourClosed?j`<div class="measurelayer">${this._renderMeasureLabel(n)}</div>`:K}
</div> </div>
${this._zoom>1?j`<div class="zoombadge">${Math.round(100*this._zoom)}%</div>`:K} ${this._zoom>1?j`<div class="zoombadge">${Math.round(100*this._zoom)}%</div>`:K}
</div> </div>
@@ -1428,4 +1433,4 @@ const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow
</button> </button>
</div> </div>
</div> </div>
</div>`}}ue.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},_markup:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},ue.styles=Vt,customElements.get("houseplan-card")||customElements.define("houseplan-card",ue),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.18.0 ","background:#3ea6ff;color:#04121f;font-weight:700",""); </div>`}}ue.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},_markup:{state:!0},_tool:{state:!0},_path:{state:!0},_cursorPt:{state:!0},_areaSel:{state:!0},_nameSel:{state:!0},_roomDialog:{state:!0},_spaceDialog:{state:!0},_infoCard:{state:!0},_rulesDialog:{state:!0},_importDialog:{state:!0},_markerDialog:{state:!0},_zoom:{state:!0},_view:{state:!0}},ue.styles=Vt,customElements.get("houseplan-card")||customElements.define("houseplan-card",ue),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.18.1 ","background:#3ea6ff;color:#04121f;font-weight:700","");
+10
View File
@@ -1,5 +1,15 @@
# Changelog # Changelog
## v1.18.1 — 2026-07-16 (fix: the drawing ruler was invisible)
- Fix on top of v1.18.0: the length badge never showed up while drawing. It was rendered
inside `.devlayer`, and `.stage.markup .devlayer { display: none }` hides that whole layer
in markup mode (so icons do not get in the way) — the badge was in the DOM but invisible.
It now lives in its own `.measurelayer` (absolute, `pointer-events: none`), which markup
mode does not hide. Verified visually on a real drawn segment ("3.60 m" on screen).
- Testing lesson (see docs/TESTING.md): asserting on `textContent` is not enough — a DOM
query passes on elements hidden by an ancestor. Check `offsetParent`/rect or look at a
screenshot.
## v1.18.0 — 2026-07-14 (live measurements while drawing rooms + per-space scale) ## v1.18.0 — 2026-07-14 (live measurements while drawing rooms + per-space scale)
- **Ruler while drawing.** In room-markup "draw" mode, a badge follows the cursor showing the - **Ruler while drawing.** In room-markup "draw" mode, a badge follows the cursor showing the
length of the current segment (last placed vertex → cursor). Units come from the HA unit length of the current segment (last placed vertex → cursor). Units come from the HA unit
+1 -1
View File
@@ -13,7 +13,7 @@
| Item | State | | Item | State |
|---|---| |---|---|
| Version | **v1.18.0** everywhere (manifest, const.py, package.json, CARD_VERSION) | | Version | **v1.18.1** everywhere (manifest, const.py, package.json, CARD_VERSION) |
| GitHub | https://github.com/Matysh/houseplan-card — branch `main`, releases v1.9.3…v1.11.2 | | GitHub | https://github.com/Matysh/houseplan-card — branch `main`, releases v1.9.3…v1.11.2 |
| CI | `.github/workflows/validate.yml` (hacs + hassfest + frontend + backend) — **fully green** since v1.11.1; `release.yml` auto-attaches the card bundle (needs `permissions: contents: write`, fixed) | | CI | `.github/workflows/validate.yml` (hacs + hassfest + frontend + backend) — **fully green** since v1.11.1; `release.yml` auto-attaches the card bundle (needs `permissions: contents: write`, fixed) |
| HACS | Works as custom repository (id 1290210112 on the home instance). **Inclusion PR: https://github.com/hacs/default/pull/9004** (queue ≈2 months as of 2026-07). Lesson: #8995 was auto-closed by hacs-bot — the PR body MUST be their exact template with every checkbox ticked and all 3 links (release, HACS action run, hassfest run); a custom body gets closed without discussion | | HACS | Works as custom repository (id 1290210112 on the home instance). **Inclusion PR: https://github.com/hacs/default/pull/9004** (queue ≈2 months as of 2026-07). Lesson: #8995 was auto-closed by hacs-bot — the PR body MUST be their exact template with every checkbox ticked and all 3 links (release, HACS action run, hassfest run); a custom body gets closed without discussion |
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "houseplan-card", "name": "houseplan-card",
"version": "1.18.0", "version": "1.18.1",
"description": "Interactive house plan Lovelace card for Home Assistant", "description": "Interactive house plan Lovelace card for Home Assistant",
"license": "MIT", "license": "MIT",
"type": "module", "type": "module",
+4 -4
View File
@@ -27,7 +27,7 @@ import './space-card';
import { cardStyles } from './styles'; import { cardStyles } from './styles';
import { langOf, t, type I18nKey } from './i18n'; import { langOf, t, type I18nKey } from './i18n';
const CARD_VERSION = '1.18.0'; const CARD_VERSION = '1.18.1';
const LS_KEY = 'houseplan_card_layout_v1'; 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_CFG = 'houseplan_card_cfg_v1'; // cache of the server config+layout for instant rendering
const LS_ZOOM = 'houseplan_card_zoom_v1'; const LS_ZOOM = 'houseplan_card_zoom_v1';
@@ -2025,10 +2025,10 @@ class HouseplanCard extends LitElement {
${disp.showNames && !this._markup ${disp.showNames && !this._markup
? space.rooms.map((r) => this._renderRoomLabel(r, space, view, disp)) ? space.rooms.map((r) => this._renderRoomLabel(r, space, view, disp))
: nothing} : nothing}
${this._markup && this._tool === 'draw' && this._path.length && this._cursorPt && !this._contourClosed
? this._renderMeasureLabel(view)
: nothing}
</div> </div>
${this._markup && this._tool === 'draw' && this._path.length && this._cursorPt && !this._contourClosed
? html`<div class="measurelayer">${this._renderMeasureLabel(view)}</div>`
: nothing}
</div> </div>
${this._zoom > 1 ${this._zoom > 1
? html`<div class="zoombadge">${Math.round(this._zoom * 100)}%</div>` ? html`<div class="zoombadge">${Math.round(this._zoom * 100)}%</div>`
+5
View File
@@ -236,6 +236,11 @@ export const cardStyles = css`
z-index: 1; z-index: 1;
} }
.roomlabel:active { cursor: grabbing; } .roomlabel:active { cursor: grabbing; }
.measurelayer {
position: absolute;
inset: 0;
pointer-events: none;
}
.measurelabel { .measurelabel {
position: absolute; position: absolute;
transform: translate(12px, -150%); transform: translate(12px, -150%);