From 46ebd253f34cc081b25b0ab1f23a7c7fefac08cb Mon Sep 17 00:00:00 2001 From: Josh Knapp Date: Sun, 12 Jul 2026 14:50:50 -0700 Subject: [PATCH] a11y: keyboard-operable editor chrome + topbar aria-labels Clickable
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) --- craft/src/panels/left/LayersPanel.tsx | 6 +-- craft/src/panels/left/PagesPanel.tsx | 3 +- craft/src/panels/topbar/TemplateModal.tsx | 3 +- craft/src/panels/topbar/TopBar.tsx | 16 ++++--- craft/src/ui/AssetPicker.tsx | 3 +- craft/src/utils/a11y.test.ts | 51 +++++++++++++++++++++++ craft/src/utils/a11y.ts | 30 +++++++++++++ 7 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 craft/src/utils/a11y.test.ts create mode 100644 craft/src/utils/a11y.ts diff --git a/craft/src/panels/left/LayersPanel.tsx b/craft/src/panels/left/LayersPanel.tsx index fe776a7..68d41f3 100644 --- a/craft/src/panels/left/LayersPanel.tsx +++ b/craft/src/panels/left/LayersPanel.tsx @@ -1,5 +1,6 @@ import React, { useCallback } from 'react'; import { useEditor } from '@craftjs/core'; +import { clickableProps } from '../../utils/a11y'; interface LayerNodeProps { nodeId: string; @@ -17,8 +18,7 @@ const LayerNode: React.FC = ({ nodeId, depth }) => { }; }); - const handleClick = useCallback((e: React.MouseEvent) => { - e.stopPropagation(); + const handleActivate = useCallback(() => { actions.selectNode(nodeId); }, [actions, nodeId]); @@ -38,7 +38,7 @@ const LayerNode: React.FC = ({ nodeId, depth }) => { return (
{ const { @@ -286,7 +287,7 @@ export const PagesPanel: React.FC = () => { ) : ( /* Normal page item */
switchPage(page.id)} + {...clickableProps(() => switchPage(page.id))} style={{ display: 'flex', alignItems: 'center', diff --git a/craft/src/panels/topbar/TemplateModal.tsx b/craft/src/panels/topbar/TemplateModal.tsx index 53c3e52..0577843 100644 --- a/craft/src/panels/topbar/TemplateModal.tsx +++ b/craft/src/panels/topbar/TemplateModal.tsx @@ -9,6 +9,7 @@ import { TemplateCategory, } from '../../templates'; import { componentResolver } from '../../components/resolver'; +import { clickableProps } from '../../utils/a11y'; // --------------------------------------------------------------------------- // Types @@ -392,7 +393,7 @@ const TemplateCard: React.FC<{ return (
setHovered(true)} onMouseLeave={() => setHovered(false)} style={{ diff --git a/craft/src/panels/topbar/TopBar.tsx b/craft/src/panels/topbar/TopBar.tsx index 31c4994..a66cd6c 100644 --- a/craft/src/panels/topbar/TopBar.tsx +++ b/craft/src/panels/topbar/TopBar.tsx @@ -123,7 +123,7 @@ export const TopBar: React.FC = ({ device, onDeviceChange }) => {