fix: улучшить доступность View (#565)

Issue: #565
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-14 07:06:16 +00:00
committed by claude[bot]
parent 6103e7de68
commit 6aca447fa0
73 changed files with 927 additions and 530 deletions
+24
View File
@@ -3,6 +3,7 @@ import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import {
activitySourceSignature,
deviceAccessibleLabel,
deviceA11yState,
markerLqiBand,
markerLqiColor,
@@ -55,6 +56,29 @@ const options = {
showSignal: true,
};
test('#565 accessible device label removes only whole repeated segments', () => {
assert.equal(deviceAccessibleLabel([
'Sink leak sensor', ' Alarm ', 'alarm', '', null, false,
'LQI 117', 'medium signal',
]), 'Sink leak sensor, Alarm, LQI 117, medium signal');
assert.equal(deviceAccessibleLabel([
'Alarm sensor', 'Alarm', 'Alarm active', 'LQI 117', 'LQI 117, medium signal',
]), 'Alarm sensor, Alarm, Alarm active, LQI 117, LQI 117, medium signal');
assert.equal(deviceAccessibleLabel([
' Door sensor ', 'Open', 'Recent opening', 'OPEN',
]), 'Door sensor, Open, Recent opening');
for (const language of ['en', 'ru', 'de', 'fr']) {
const dictionary = JSON.parse(readFileSync(
new URL(`../src/i18n/${language}.json`, import.meta.url), 'utf8',
));
const alarm = dictionary['marker.state_a11y_alarm'];
assert.equal(alarm, dictionary['marker.pulse_a11y_alarm']);
assert.equal(deviceAccessibleLabel(['Leak sensor', alarm, alarm]).split(', ').length, 2,
`${language}: alarm is spoken once`);
}
});
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',
+25
View File
@@ -0,0 +1,25 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
const source = (path) => readFileSync(new URL(`../${path}`, import.meta.url), 'utf8');
test('#565 View keeps native space buttons and exposes one current page', () => {
const card = source('src/houseplan-card.ts');
assert.match(card, /<nav class="tabs" aria-label=\$\{this\._t\('nav\.spaces'\)\}/);
assert.match(card, /aria-current=\$\{this\._space === s\.id \? 'page' : nothing\}/);
assert.doesNotMatch(card, /role="tablist"|role="tab"/);
});
test('#565 keyboard tooltip has explicit focus ownership and room labels stay untouched', () => {
const card = source('src/houseplan-card.ts');
const hover = source('src/live-hover.ts');
const staticCard = source('src/space-render.ts');
assert.match(card, /@focus=\$\{\(e: FocusEvent\) => this\._showDeviceFocusTip\(e, d\)\}/);
assert.match(card, /@focusout=\$\{\(\) => this\._hideDeviceFocusTip\(d\.id\)\}/);
assert.match(hover, /!target\?\.matches\(':focus-visible'\)/);
assert.match(hover, /marker\?\.matches\(':focus-visible'\)/);
assert.match(card, /style="left:\$\{left\}%;top:\$\{top\}%;color:\$\{disp\.color\};opacity:\$\{op\};--rl-scale:/);
assert.match(staticCard, /style="left:\$\{left\}%;top:\$\{top\}%;color:\$\{disp\.color\};opacity:\$\{op\}"/);
assert.doesNotMatch(staticCard, /_showDeviceFocusTip|@focus=/);
});