a11y: keyboard-operable editor chrome + topbar aria-labels
Clickable <div> rows/tiles (page list, layer tree, template cards, asset picker grid) now expose role="button", a tab stop, and Enter/Space activation via a shared clickableProps() helper, matching their existing onClick behavior. TopBar icon-only controls (device switcher, undo/redo, save, publish, templates, code, preview, back) gain aria-label alongside their existing title tooltips. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -123,7 +123,7 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange }) => {
|
||||
<nav className="topbar">
|
||||
<div className="topbar-left">
|
||||
{isWHP && (
|
||||
<a href={whpConfig!.backUrl} className="topbar-btn back-btn">
|
||||
<a href={whpConfig!.backUrl} className="topbar-btn back-btn" aria-label="Back to Panel">
|
||||
<i className="fa fa-arrow-left" /> Back to Panel
|
||||
</a>
|
||||
)}
|
||||
@@ -141,6 +141,8 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange }) => {
|
||||
className={`device-btn ${device === d ? 'active' : ''}`}
|
||||
onClick={() => onDeviceChange(d)}
|
||||
title={d.charAt(0).toUpperCase() + d.slice(1)}
|
||||
aria-label={d.charAt(0).toUpperCase() + d.slice(1)}
|
||||
aria-pressed={device === d}
|
||||
>
|
||||
<i className={`fa ${d === 'desktop' ? 'fa-desktop' : d === 'tablet' ? 'fa-tablet' : 'fa-mobile'}`} />
|
||||
</button>
|
||||
@@ -149,20 +151,20 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange }) => {
|
||||
</div>
|
||||
|
||||
<div className="topbar-right">
|
||||
<button className="topbar-btn" onClick={() => actions.history.undo()} disabled={!canUndo} title="Undo">
|
||||
<button className="topbar-btn" onClick={() => actions.history.undo()} disabled={!canUndo} title="Undo" aria-label="Undo">
|
||||
<i className="fa fa-undo" />
|
||||
</button>
|
||||
<button className="topbar-btn" onClick={() => actions.history.redo()} disabled={!canRedo} title="Redo">
|
||||
<button className="topbar-btn" onClick={() => actions.history.redo()} disabled={!canRedo} title="Redo" aria-label="Redo">
|
||||
<i className="fa fa-repeat" />
|
||||
</button>
|
||||
<span className="topbar-divider" />
|
||||
<button className="topbar-btn" title="Templates" onClick={() => setTemplateModalOpen(true)}>
|
||||
<button className="topbar-btn" title="Templates" aria-label="Templates" onClick={() => setTemplateModalOpen(true)}>
|
||||
<i className="fa fa-th-large" /> Templates
|
||||
</button>
|
||||
<button className="topbar-btn" title="Custom Head Code" onClick={() => setHeadCodeModalOpen(true)}>
|
||||
<button className="topbar-btn" title="Custom Head Code" aria-label="Custom Head Code" onClick={() => setHeadCodeModalOpen(true)}>
|
||||
<i className="fa fa-code" /> Code
|
||||
</button>
|
||||
<button className="topbar-btn" title="Preview" onClick={() => {
|
||||
<button className="topbar-btn" title="Preview" aria-label="Preview" onClick={() => {
|
||||
try {
|
||||
const serialized = query.serialize();
|
||||
import('../../utils/html-export').then(({ exportToHtml, exportBodyHtml }) => {
|
||||
@@ -255,6 +257,7 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange }) => {
|
||||
onClick={handleSave}
|
||||
disabled={saveStatus === 'saving'}
|
||||
title="Save Draft"
|
||||
aria-label="Save Draft"
|
||||
>
|
||||
{saveStatus === 'saving' ? (
|
||||
<><i className="fa fa-spinner fa-spin" /> Saving...</>
|
||||
@@ -269,6 +272,7 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange }) => {
|
||||
onClick={handlePublish}
|
||||
disabled={publishStatus === 'publishing' || saveStatus === 'saving'}
|
||||
title="Publish to live site"
|
||||
aria-label="Publish to live site"
|
||||
>
|
||||
{publishStatus === 'publishing' ? (
|
||||
<><i className="fa fa-spinner fa-spin" /> Publishing...</>
|
||||
|
||||
Reference in New Issue
Block a user