audit pass 7: ARIA, focus management, and label fixes
CSS: - Add :focus-visible to sortable th, breadcrumb links, list links, cmd-item, combobox-option, typeahead-item, sidebar-sub-link, split-divider, stat-card - Fix .lt-skip-link:focus to also include :focus-visible for spec compliance JS: - Mobile nav: add focus trap (_trapFocus), save/restore trigger focus, fix aria-hidden="false" to removeAttribute pattern, add document.contains guard - Combobox: add aria-activedescendant on _moveFocus; add unique IDs to options; clear aria-activedescendant on close; wrap querySelectorAll in Array.from - Typeahead: add aria-activedescendant on _moveFocus; add unique IDs to items; add aria-busy during async search; clear aria-activedescendant on select; wrap querySelectorAll in Array.from - Command palette: add unique IDs to items; set/clear aria-activedescendant on move and mouseenter; clear on close - Lightbox: add document.contains guard on focus setTimeout - Stats filter: add Enter/Space keyboard handler for role="button" cards HTML: - Stat cards: add role="button" tabindex="0" aria-label (interactive divs) - Advanced filter selects: add id/for associations to all 3 label+select pairs - Accordion SVG icons: add aria-hidden="true" (decorative) - Range input: add aria-label, aria-valuemin/max/now - Wizard form controls: add id/for to all 4 label+input/select pairs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -276,29 +276,29 @@
|
||||
data-filter-key / data-filter-val → wired by lt.statsFilter
|
||||
========================================================== -->
|
||||
<div class="lt-stats-grid">
|
||||
<div class="lt-stat-card active" data-filter-key="status" data-filter-val="Open">
|
||||
<span class="lt-stat-icon">📋</span>
|
||||
<div class="lt-stat-card active" role="button" tabindex="0" data-filter-key="status" data-filter-val="Open" aria-label="Open tickets: 42">
|
||||
<span class="lt-stat-icon" aria-hidden="true">📋</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">42</span>
|
||||
<span class="lt-stat-label">Open</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-stat-card" data-filter-key="priority" data-filter-val="1">
|
||||
<span class="lt-stat-icon">🔴</span>
|
||||
<div class="lt-stat-card" role="button" tabindex="0" data-filter-key="priority" data-filter-val="1" aria-label="Critical tickets: 3">
|
||||
<span class="lt-stat-icon" aria-hidden="true">🔴</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">3</span>
|
||||
<span class="lt-stat-label">Critical</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-stat-card" data-filter-key="assigned_to" data-filter-val="0">
|
||||
<span class="lt-stat-icon">👤</span>
|
||||
<div class="lt-stat-card" role="button" tabindex="0" data-filter-key="assigned_to" data-filter-val="0" aria-label="Unassigned tickets: 11">
|
||||
<span class="lt-stat-icon" aria-hidden="true">👤</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">11</span>
|
||||
<span class="lt-stat-label">Unassigned</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lt-stat-card" data-filter-key="created" data-filter-val="today">
|
||||
<span class="lt-stat-icon">📅</span>
|
||||
<div class="lt-stat-card" role="button" tabindex="0" data-filter-key="created" data-filter-val="today" aria-label="Today's tickets: 7">
|
||||
<span class="lt-stat-icon" aria-hidden="true">📅</span>
|
||||
<div class="lt-stat-info">
|
||||
<span class="lt-stat-value">7</span>
|
||||
<span class="lt-stat-label">Today</span>
|
||||
@@ -392,8 +392,8 @@
|
||||
<div class="lt-dropdown-panel" id="adv-filter-panel" aria-hidden="true">
|
||||
<div style="padding:0.75rem;display:grid;gap:0.5rem;width:clamp(200px,60vw,260px)">
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" style="font-size:0.75rem">Status</label>
|
||||
<select class="lt-select" style="font-size:0.8rem">
|
||||
<label class="lt-label" style="font-size:0.75rem" for="adv-filter-status">Status</label>
|
||||
<select id="adv-filter-status" class="lt-select" style="font-size:0.8rem">
|
||||
<option value="">All</option>
|
||||
<option>Open</option>
|
||||
<option>In Progress</option>
|
||||
@@ -402,8 +402,8 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" style="font-size:0.75rem">Priority</label>
|
||||
<select class="lt-select" style="font-size:0.8rem">
|
||||
<label class="lt-label" style="font-size:0.75rem" for="adv-filter-priority">Priority</label>
|
||||
<select id="adv-filter-priority" class="lt-select" style="font-size:0.8rem">
|
||||
<option value="">All</option>
|
||||
<option>P1 Critical</option>
|
||||
<option>P2 High</option>
|
||||
@@ -412,8 +412,8 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="lt-form-group" style="margin:0">
|
||||
<label class="lt-label" style="font-size:0.75rem">Assignee</label>
|
||||
<select class="lt-select" style="font-size:0.8rem">
|
||||
<label class="lt-label" style="font-size:0.75rem" for="adv-filter-assignee">Assignee</label>
|
||||
<select id="adv-filter-assignee" class="lt-select" style="font-size:0.8rem">
|
||||
<option value="">Anyone</option>
|
||||
<option>Unassigned</option>
|
||||
<option>jdoe</option>
|
||||
@@ -878,21 +878,21 @@
|
||||
<div class="lt-accordion">
|
||||
<button class="lt-accordion-header" aria-expanded="false" aria-controls="acc-body-1" data-accordion>
|
||||
SYSTEM OVERVIEW
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 1l4 4 4-4"/></svg>
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M1 1l4 4 4-4"/></svg>
|
||||
</button>
|
||||
<div class="lt-accordion-body" id="acc-body-1"><div class="lt-accordion-content">Node running at 72% CPU. 12 active processes. Last restart: 3d ago.</div></div>
|
||||
</div>
|
||||
<div class="lt-accordion">
|
||||
<button class="lt-accordion-header" aria-expanded="false" aria-controls="acc-body-2" data-accordion>
|
||||
NETWORK CONFIG
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 1l4 4 4-4"/></svg>
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M1 1l4 4 4-4"/></svg>
|
||||
</button>
|
||||
<div class="lt-accordion-body" id="acc-body-2"><div class="lt-accordion-content">eth0: 10.0.0.7 — MTU 1500 — RX 4.2 GB — TX 1.1 GB</div></div>
|
||||
</div>
|
||||
<div class="lt-accordion">
|
||||
<button class="lt-accordion-header" aria-expanded="false" aria-controls="acc-body-3" data-accordion>
|
||||
FIREWALL RULES
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M1 1l4 4 4-4"/></svg>
|
||||
<svg class="lt-accordion-icon" viewBox="0 0 10 6" fill="none" stroke="currentColor" stroke-width="1.5" aria-hidden="true"><path d="M1 1l4 4 4-4"/></svg>
|
||||
</button>
|
||||
<div class="lt-accordion-body" id="acc-body-3"><div class="lt-accordion-content">22/tcp ALLOW — 80/tcp ALLOW — 443/tcp ALLOW — */* DENY</div></div>
|
||||
</div>
|
||||
@@ -949,7 +949,7 @@
|
||||
<span class="lt-range-label">Refresh Interval (s)</span>
|
||||
<span class="lt-range-value">30</span>
|
||||
</div>
|
||||
<input type="range" class="lt-range" min="5" max="60" value="30">
|
||||
<input type="range" class="lt-range" min="5" max="60" value="30" aria-label="Refresh Interval in seconds" aria-valuemin="5" aria-valuemax="60" aria-valuenow="30">
|
||||
</div>
|
||||
<div class="lt-tags">
|
||||
<span class="lt-tag lt-tag--orange">CRITICAL</span>
|
||||
@@ -1420,13 +1420,13 @@
|
||||
<!-- Steps -->
|
||||
<div data-wizard-step="1" class="is-active">
|
||||
<div class="lt-grid lt-grid-2" style="gap:1rem;margin-top:1rem">
|
||||
<div class="lt-form-group"><label class="lt-label">Ticket Title</label><input type="text" name="title" class="lt-input lt-w-full" placeholder="Brief description…"></div>
|
||||
<div class="lt-form-group"><label class="lt-label">Priority</label><select name="priority" class="lt-select lt-w-full"><option value="p1">P1 Critical</option><option value="p2">P2 High</option><option value="p3" selected>P3 Medium</option><option value="p4">P4 Low</option></select></div>
|
||||
<div class="lt-form-group"><label class="lt-label" for="wizard-title">Ticket Title</label><input id="wizard-title" type="text" name="title" class="lt-input lt-w-full" placeholder="Brief description…"></div>
|
||||
<div class="lt-form-group"><label class="lt-label" for="wizard-priority">Priority</label><select id="wizard-priority" name="priority" class="lt-select lt-w-full"><option value="p1">P1 Critical</option><option value="p2">P2 High</option><option value="p3" selected>P3 Medium</option><option value="p4">P4 Low</option></select></div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-wizard-step="2" aria-hidden="true">
|
||||
<div class="lt-form-group" style="margin-top:1rem"><label class="lt-label">Assign To</label><input type="text" name="assignee" class="lt-input lt-w-full" placeholder="Username…"></div>
|
||||
<div class="lt-form-group"><label class="lt-label">Due Date</label><input type="date" name="due" class="lt-input"></div>
|
||||
<div class="lt-form-group" style="margin-top:1rem"><label class="lt-label" for="wizard-assignee">Assign To</label><input id="wizard-assignee" type="text" name="assignee" class="lt-input lt-w-full" placeholder="Username…"></div>
|
||||
<div class="lt-form-group"><label class="lt-label" for="wizard-due">Due Date</label><input id="wizard-due" type="date" name="due" class="lt-input"></div>
|
||||
</div>
|
||||
<div data-wizard-step="3" aria-hidden="true">
|
||||
<div class="lt-empty-state lt-empty-state--sm"><div class="lt-empty-state-icon">✅</div><div class="lt-empty-state-title">Review & Submit</div><div class="lt-empty-state-body">Check the details above and click Submit when ready.</div></div>
|
||||
|
||||
Reference in New Issue
Block a user