fix: polish device marker geometry and input

Issue: #213
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-08-20 11:00:22 +03:00
parent c749d68a4d
commit 0e5ee030fe
37 changed files with 1760 additions and 951 deletions
+1
View File
@@ -102,6 +102,7 @@ test('Text and Double use one shared shell and deterministic full-text fitting',
: Array.isArray(value) ? value.map(flatten).join('') : String(value ?? '');
const markup = flatten(root);
assert.match(markup, /device-shell/);
assert.match(markup, /device-shell-frame/);
assert.match(markup, /device-core/);
assert.match(markup, /device-sections/);
assert.match(markup, /band-/);
+16
View File
@@ -0,0 +1,16 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import {
DEFAULT_DEVICE_BASE_SIZE,
DEVICE_PREVIEW_BASE_PX,
effectiveDeviceBaseSize,
} from '../test-build/device-marker-geometry.js';
test('issue 213 resolves compatibility size units once at the surface boundary', () => {
assert.equal(DEFAULT_DEVICE_BASE_SIZE, 2.25);
assert.equal(DEVICE_PREVIEW_BASE_PX, 48.6);
assert.equal(effectiveDeviceBaseSize(2.5), 2.25);
assert.equal(effectiveDeviceBaseSize(4), 3.6);
assert.equal(effectiveDeviceBaseSize(5) / effectiveDeviceBaseSize(2.5), 2);
assert.equal(effectiveDeviceBaseSize(Number.NaN), 2.25);
});
+26 -4
View File
@@ -4,18 +4,40 @@ import { readFileSync } from 'node:fs';
const source = (name) => readFileSync(new URL(`../src/${name}`, import.meta.url), 'utf8');
test('issue 212 applies one visual 0.9 factor without shrinking the hit target', () => {
test('issue 213 resolves the effective base before the face without a late visual factor', () => {
const styles = source('styles.ts');
assert.match(styles, /--device-visual-factor:\s*0\.9\s*;/);
assert.doesNotMatch(styles, /--device-visual-factor/);
assert.match(
styles,
/--dev-size:\s*calc\([^;]*var\(--device-visual-factor,\s*0\.9\)[^;]*\);/,
/--dev-size:\s*calc\(\s*var\(--device-base-size,\s*2\.25cqw\)\s*\*\s*var\(--dev-scale,\s*1\)\s*\)/,
);
assert.match(styles, /width:\s*max\(44px,\s*var\(--device-shell-size\)\)/);
assert.match(
styles,
/--puck-size:\s*calc\([^;]*var\(--device-visual-factor,\s*0\.9\)[^;]*\);/,
/--puck-size:\s*calc\(\s*var\(--device-base-size,\s*2\.25cqw\)\s*\*\s*0\.8\s*\)/,
);
assert.match(styles, /--mdc-icon-size:\s*calc\([^;]*var\(--dev-size[^;]*\*\s*0\.55\)/);
});
test('issue 213 gives the visual shell a shared-centre frame that owns capsule input', () => {
const styles = source('styles.ts');
const face = source('device-face.ts');
assert.match(face, /class="device-shell-frame"/);
assert.match(styles, /\.device-shell-frame\s*\{[\s\S]*inset:\s*calc\(var\(--device-shell-inset\)\s*\/\s*-1\)/);
assert.match(styles, /\.device-shell-frame\s*\{[\s\S]*pointer-events:\s*auto/);
assert.match(styles, /\.device-shell\s*\{[\s\S]*padding:\s*0/);
});
test('issue 213 projects opening locks through the compact package layers', () => {
const styles = source('styles.ts');
const card = source('houseplan-card.ts');
assert.match(styles, /--oplock-size:\s*calc\(var\(--icon-size,\s*2\.5cqw\)\s*\*\s*0\.62\)/);
assert.match(styles, /--oplock-core-size:\s*calc\(var\(--oplock-size\)\s*\/\s*1\.26875\)/);
assert.match(styles, /\.oplock ha-icon\s*\{[\s\S]*--mdc-icon-size:[^;]*\*\s*0\.55/);
assert.match(styles, /\.oplock\.unlocked\s*\{[\s\S]*--oplock-core-bg:\s*#F0A00C/);
assert.doesNotMatch(styles, /\.oplock\.locked\s*\{[^}]*#66d17a/i);
assert.match(card, /class="oplock \$\{deviceThemeClass\(this\._renderPlanHass\)\}/);
assert.match(card, /class="oplock-shell"[\s\S]*class="oplock-core"/);
});
test('issue 212 Text value uses a stadium radius based on height', () => {
+5 -4
View File
@@ -51,13 +51,14 @@ const options = {
showSignal: true,
};
test('marker LQI is categorical without changing the room-fill gradient', () => {
test('marker LQI keeps semantic bands while its colour uses the continuous gradient', () => {
assert.deepEqual([0, 40, 41, 179, 180].map(markerLqiBand), [
'low', 'low', 'mid', 'mid', 'high',
]);
assert.deepEqual([40, 41, 179, 180].map(markerLqiColor), [
'#F0410C', '#F0A00C', '#F0A00C', '#1DC21D',
]);
for (const lqi of [0, 40, 41, 110, 179, 180, 255]) {
assert.equal(markerLqiColor(lqi), lqiColor(lqi));
}
assert.notEqual(markerLqiColor(41), markerLqiColor(42));
assert.equal(lqiColor(110), 'hsl(60, 85%, 55%)');
});