mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
File diff suppressed because one or more lines are too long
@@ -37,6 +37,11 @@ const res = await page.evaluate(async () => {
|
||||
await c.updateComplete;
|
||||
const preview = sr().querySelector('hp-device-preview');
|
||||
await preview?.updateComplete;
|
||||
preview?.dispatchEvent(new PointerEvent('pointerover', {
|
||||
pointerType: 'mouse', bubbles: true, composed: true,
|
||||
}));
|
||||
const previewHoverGatePropagates = c.hasAttribute('data-pointer-hover')
|
||||
&& preview?.hasAttribute('data-pointer-hover');
|
||||
const previewFace = face(preview?.renderRoot?.querySelector('.dev'));
|
||||
const providerShown = /demo/i.test(preview?.renderRoot?.querySelector('.previewfacts')?.textContent || '');
|
||||
|
||||
@@ -168,6 +173,7 @@ const res = await page.evaluate(async () => {
|
||||
|
||||
return {
|
||||
allFacesPresent: !!planFace && !!previewFace && !!staticFace,
|
||||
previewHoverGatePropagates,
|
||||
planPreviewEqual: JSON.stringify(planFace) === JSON.stringify(previewFace),
|
||||
planStaticEqual: JSON.stringify(planFace) === JSON.stringify(staticFace),
|
||||
providerShown,
|
||||
|
||||
+2
-2
@@ -239,7 +239,7 @@ const res = await page.evaluate(async () => {
|
||||
const poolBeforeHover = sr().querySelector('.glow-pool');
|
||||
const gradientBeforeHover = sr().querySelector('radialGradient[id^="hp-glow-"]');
|
||||
const roomEl = sr().querySelector('.room');
|
||||
roomEl?.dispatchEvent(new MouseEvent('mouseenter'));
|
||||
roomEl?.dispatchEvent(new PointerEvent('pointerenter', { pointerType: 'mouse' }));
|
||||
await c.updateComplete;
|
||||
const hoverFill = sr().querySelector('.room-hover-fill');
|
||||
const hoverFillLayer = sr().querySelector('.room-hover-fill-layer');
|
||||
@@ -263,7 +263,7 @@ const res = await page.evaluate(async () => {
|
||||
// late outline must follow it; absence is not a layer-order failure.
|
||||
&& (!wallLayer
|
||||
|| !!(wallLayer.compareDocumentPosition(hoverOutlineLayer) & Node.DOCUMENT_POSITION_FOLLOWING));
|
||||
roomEl?.dispatchEvent(new MouseEvent('mouseleave'));
|
||||
roomEl?.dispatchEvent(new PointerEvent('pointerleave', { pointerType: 'mouse' }));
|
||||
await c.updateComplete;
|
||||
return out;
|
||||
});
|
||||
|
||||
@@ -45,15 +45,15 @@ const res = await page.evaluate(async () => {
|
||||
const lbl = [...sr().querySelectorAll('.roomlabel')].find((l) => l.textContent.includes(model.name));
|
||||
out.cardShowsSource = lbl ? lbl.textContent.includes('30.2°') : false;
|
||||
const modelIndex = c._spaceModel().rooms.findIndex((r) => r.id === editedId);
|
||||
[...sr().querySelectorAll('.room')][modelIndex].dispatchEvent(new MouseEvent('mousemove', {
|
||||
bubbles: true, composed: true, clientX: 200, clientY: 200,
|
||||
[...sr().querySelectorAll('.room')][modelIndex].dispatchEvent(new PointerEvent('pointermove', {
|
||||
pointerType: 'mouse', bubbles: true, composed: true, clientX: 200, clientY: 200,
|
||||
}));
|
||||
await c.updateComplete;
|
||||
out.tooltipShowsHumiditySource = c._tip?.hum === 47
|
||||
&& (sr().querySelector('.tip')?.textContent || '').includes(`${c._t('tip.hum_avg')} 47%`);
|
||||
model.settings = { ...model.settings, hum_source: 'entity:sensor.missing_room_hum' };
|
||||
[...sr().querySelectorAll('.room')][modelIndex].dispatchEvent(new MouseEvent('mousemove', {
|
||||
bubbles: true, composed: true, clientX: 210, clientY: 210,
|
||||
[...sr().querySelectorAll('.room')][modelIndex].dispatchEvent(new PointerEvent('pointermove', {
|
||||
pointerType: 'mouse', bubbles: true, composed: true, clientX: 210, clientY: 210,
|
||||
}));
|
||||
await c.updateComplete;
|
||||
out.invalidHumiditySourceIsOmitted = c._tip?.hum == null
|
||||
|
||||
+21
-8
@@ -41,7 +41,9 @@ const res = await page.evaluate(async () => {
|
||||
// тултип комнаты: площадь и агрегаты температуры/влажности в стабильном порядке
|
||||
const rooms = [...sr().querySelectorAll('.room')];
|
||||
const room = rooms[0];
|
||||
room.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, composed: true, clientX: 200, clientY: 200 }));
|
||||
room.dispatchEvent(new PointerEvent('pointermove', {
|
||||
pointerType: 'mouse', bubbles: true, composed: true, clientX: 200, clientY: 200,
|
||||
}));
|
||||
await c.updateComplete;
|
||||
out.tipTemp = c._tip?.temp;
|
||||
out.tipHum = c._tip?.hum;
|
||||
@@ -60,26 +62,37 @@ const res = await page.evaluate(async () => {
|
||||
out.tipHasAreaLine = (sr().querySelector('.tip')?.textContent || '').includes(expectedArea);
|
||||
|
||||
// Комната без источника влажности не получает пустую строку.
|
||||
rooms[1].dispatchEvent(new MouseEvent('mousemove', { bubbles: true, composed: true, clientX: 210, clientY: 210 }));
|
||||
rooms[1].dispatchEvent(new PointerEvent('pointermove', {
|
||||
pointerType: 'mouse', bubbles: true, composed: true, clientX: 210, clientY: 210,
|
||||
}));
|
||||
await c.updateComplete;
|
||||
out.noHumidityOmitted = c._tip?.hum == null
|
||||
&& !(sr().querySelector('.tip')?.textContent || '').includes('средняя влажность');
|
||||
|
||||
// Общий device tooltip остаётся без room humidity.
|
||||
sr().querySelector('.dev').dispatchEvent(new MouseEvent('mousemove', {
|
||||
bubbles: true, composed: true, clientX: 220, clientY: 220,
|
||||
sr().querySelector('.dev').dispatchEvent(new PointerEvent('pointermove', {
|
||||
pointerType: 'mouse', bubbles: true, composed: true, clientX: 220, clientY: 220,
|
||||
}));
|
||||
await c.updateComplete;
|
||||
out.deviceTooltipHasNoHumidity = c._tip?.hum == null
|
||||
&& !(sr().querySelector('.tip')?.textContent || '').includes('средняя влажность');
|
||||
|
||||
// После первого touch/pen hover-подсказки по-прежнему не создаются.
|
||||
c.constructor._touchSeen = true;
|
||||
// Touch/pen input never creates hover-only tooltips.
|
||||
room.dispatchEvent(new PointerEvent('pointerdown', {
|
||||
pointerType: 'touch', pointerId: 91, bubbles: true, composed: true,
|
||||
clientX: 230, clientY: 230,
|
||||
}));
|
||||
c._tip = null;
|
||||
room.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, composed: true, clientX: 230, clientY: 230 }));
|
||||
room.dispatchEvent(new PointerEvent('pointermove', {
|
||||
pointerType: 'touch', pointerId: 91, bubbles: true, composed: true,
|
||||
clientX: 230, clientY: 230,
|
||||
}));
|
||||
await c.updateComplete;
|
||||
out.noHoverSuppressesTooltip = c._tip === null;
|
||||
c.constructor._touchSeen = false;
|
||||
room.dispatchEvent(new PointerEvent('pointerup', {
|
||||
pointerType: 'touch', pointerId: 91, bubbles: true, composed: true,
|
||||
clientX: 230, clientY: 230,
|
||||
}));
|
||||
// диалог: радио заливки, компактные поля, ширина
|
||||
c._openSpaceDialog('edit', 'f1'); await c.updateComplete;
|
||||
out.fillRadios = sr().querySelectorAll('input[name="fillmode"]').length;
|
||||
|
||||
File diff suppressed because one or more lines are too long
Vendored
+24
-24
File diff suppressed because one or more lines are too long
+3
-2
@@ -6,8 +6,9 @@
|
||||
shrinking the 44×44 px interaction floor, and wide Text markers keep uniform
|
||||
capsule insets. A real toggle/run dispatch gives a smooth 5% press response
|
||||
for 200 ms (with a reduced-motion alternative). Touch and pen no longer leave
|
||||
room, marker or shared-control hover stuck; a real mouse restores hover on
|
||||
hybrid hardware without reloading ([#212](https://github.com/Matysh/houseplan-card/issues/212)).
|
||||
room, marker, Device preview or shared-control hover stuck; a real mouse
|
||||
restores hover on hybrid hardware without reloading
|
||||
([#212](https://github.com/Matysh/houseplan-card/issues/212)).
|
||||
|
||||
## v1.65.0-beta.7 — 2026-08-20
|
||||
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
без уменьшения области нажатия 44×44 px; широкий Text-маркер получил ровные
|
||||
отступы капсулы. Реальная отправка toggle/run-команды даёт плавный отклик
|
||||
уменьшением на 5% за 0,2 с с отдельным вариантом для reduced motion. Касание
|
||||
пальцем или пером больше не оставляет hover комнаты, маркера и общих контролов
|
||||
«прилипшим», а настоящая мышь возвращает hover на гибридном устройстве без
|
||||
перезагрузки ([#212](https://github.com/Matysh/houseplan-card/issues/212)).
|
||||
пальцем или пером больше не оставляет hover комнаты, маркера, Device preview
|
||||
и общих контролов «прилипшим», а настоящая мышь возвращает hover на гибридном
|
||||
устройстве без перезагрузки
|
||||
([#212](https://github.com/Matysh/houseplan-card/issues/212)).
|
||||
|
||||
## v1.65.0-beta.7 — 2026-08-20
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 1,
|
||||
"fixture": "synthetic-only",
|
||||
"sourceFingerprint": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceFingerprint": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"captureScriptSha256": "34f2219790d46efd8250e7a1bd829cb8fc0b0547e1260635fefa52407551b41b",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "8780c6f05a9f2af55b97512dfa8d277bb77ab9ae0dafb50640cc3237028055dc"
|
||||
},
|
||||
"view-touch": {
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "5e41c81ded9eb67deea49840c260eaaa404cab61abf014a1a275586dafe66e53"
|
||||
},
|
||||
"space-create": {
|
||||
@@ -35,7 +35,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "c53db2e5c642a5549c13f3c93a5b359fed69bdb2621bf71a243a877ffcb95e6b"
|
||||
},
|
||||
"room-contour-close": {
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "2f13ea645af306eee9cc7c52699c928377b72f412b08c1a3db6beb848ace1b51"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
@@ -57,7 +57,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "a6c526fede11bc3503fd2384bd4a3f6afa008f481c5c47578f06cae6c81c6f9b"
|
||||
},
|
||||
"device-editor": {
|
||||
@@ -68,7 +68,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "bfba4647c04bdf4b46dc9cea3b42e349b3ea67007bb38e16880983dbee14653e"
|
||||
},
|
||||
"device-display-preview": {
|
||||
@@ -79,7 +79,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "8cdfe00ead5558d013265617104997fdd138337322aa82f6a3e1d15eeb36cf5e"
|
||||
},
|
||||
"background-editor": {
|
||||
@@ -90,7 +90,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "d7cfe70551d9260169df8efd832e32ed7df99c7f60b55d1fd4a8322bd4c47175"
|
||||
},
|
||||
"room-card": {
|
||||
@@ -101,7 +101,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "ab29f6fdb31d3117e935a93a237105d42a5103687ac892ef426a4887ae7960c4"
|
||||
},
|
||||
"device-info": {
|
||||
@@ -112,7 +112,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "040ec09a494568481fd2a4853a4dd8183c7950152dc9674d0a458a323f8bdf21",
|
||||
"sourceSha256": "d7e3504b796d334b3d6646bcf34f7effb2d465add3e9ddabeb23b696f9e271a9",
|
||||
"imageSha256": "30bf3f2a1311fc2bffeac6359773925fea22150df2845015c630e009016f095f"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,6 +484,7 @@ const LS_ZOOM = 'houseplan_card_zoom_v1';
|
||||
const LS_NAV = 'houseplan_card_nav_v1'; // last space only; editor sessions never survive page navigation
|
||||
const LS_KIOSK = 'houseplan_card_kiosk_v1'; // per-SCREEN size multipliers (each wall tablet differs)
|
||||
const LS_VIEW = 'houseplan_card_view_v1'; // presentation preference per space, Labs-only
|
||||
const POINTER_HOVER_TARGET_SELECTOR = 'hp-dialog, hp-help, hp-color-opacity, hp-device-preview';
|
||||
const NORM_W = 1000; // side of the render space — the canvas is square (v1.48.0)
|
||||
/** Short semantic-event / direct-terminal-transition window. Event uses
|
||||
three sequential 1.1 s waves; motion cool-down itself never animates. */
|
||||
@@ -5849,7 +5850,7 @@ class HouseplanCard extends LitElement {
|
||||
private _syncPointerHoverTargets(): void {
|
||||
const enabled = this._pointerModality.hoverEnabled;
|
||||
for (const target of this.renderRoot.querySelectorAll<HTMLElement>(
|
||||
'hp-dialog, hp-help, hp-color-opacity',
|
||||
POINTER_HOVER_TARGET_SELECTOR,
|
||||
)) {
|
||||
target.toggleAttribute('data-pointer-hover', enabled);
|
||||
}
|
||||
@@ -5859,11 +5860,11 @@ class HouseplanCard extends LitElement {
|
||||
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
||||
const element = node as HTMLElement;
|
||||
const enabled = this._pointerModality.hoverEnabled;
|
||||
if (element.matches('hp-dialog, hp-help, hp-color-opacity')) {
|
||||
if (element.matches(POINTER_HOVER_TARGET_SELECTOR)) {
|
||||
element.toggleAttribute('data-pointer-hover', enabled);
|
||||
}
|
||||
for (const target of element.querySelectorAll<HTMLElement>(
|
||||
'hp-dialog, hp-help, hp-color-opacity',
|
||||
POINTER_HOVER_TARGET_SELECTOR,
|
||||
)) {
|
||||
target.toggleAttribute('data-pointer-hover', enabled);
|
||||
}
|
||||
|
||||
@@ -41,8 +41,20 @@ test('issue 212 removes the global touch latch and gates every shared hover sele
|
||||
assert.doesNotMatch(card, /private static _touchSeen/);
|
||||
assert.match(card, /PointerModalityController/);
|
||||
assert.match(card, /_clearTransientHover/);
|
||||
assert.match(
|
||||
card,
|
||||
/POINTER_HOVER_TARGET_SELECTOR\s*=\s*'[^']*hp-device-preview[^']*'/,
|
||||
'device preview must receive the card-owned pointer hover gate',
|
||||
);
|
||||
|
||||
for (const name of ['styles.ts', 'hp-dialog.ts', 'hp-help.ts', 'hp-color-opacity.ts', 'space-card.ts']) {
|
||||
for (const name of [
|
||||
'styles.ts',
|
||||
'hp-dialog.ts',
|
||||
'hp-help.ts',
|
||||
'hp-color-opacity.ts',
|
||||
'hp-device-preview.ts',
|
||||
'space-card.ts',
|
||||
]) {
|
||||
const text = source(name);
|
||||
const selectors = [...text.matchAll(/(^|\})([^{}]+)\{/gm)].map((match) => match[2]);
|
||||
const naked = selectors.flatMap((selector) => selector.split(','))
|
||||
|
||||
Reference in New Issue
Block a user