` has only list items as direct children —
+ * TipTap's default extra `` host broke the list semantics for
+ * screen readers. The wrapper flattens away via display:contents. */
function TaskItemView({ node, updateAttributes, editor }: NodeViewProps): React.JSX.Element {
+ const { t } = useTranslation('tasks');
const checked = Boolean(node.attrs.checked);
return (
-
+
@@ -34,7 +42,13 @@ export const TaskItem = Node.create({
parseHTML: () => taskItemSpec.parseDOM,
renderHTML: ({ node }) => taskItemSpec.toDOM!(node),
addNodeView() {
- return ReactNodeViewRenderer(TaskItemView);
+ return ReactNodeViewRenderer(TaskItemView, {
+ as: 'li',
+ attrs: ({ node }) => ({
+ 'data-type': 'task_item',
+ 'data-checked': String(node.attrs.checked === true),
+ }),
+ });
},
addKeyboardShortcuts() {
return {
diff --git a/apps/web/src/graph/ForceGraph.tsx b/apps/web/src/graph/ForceGraph.tsx
index e464dfc..925eaa2 100644
--- a/apps/web/src/graph/ForceGraph.tsx
+++ b/apps/web/src/graph/ForceGraph.tsx
@@ -14,6 +14,7 @@ import {
type SimulationNodeDatum,
} from 'd3-force';
import { useEffect, useRef, useState } from 'react';
+import { useTranslation } from 'react-i18next';
/**
* Self-contained SVG force graph (issue #112). Only `d3-force` is bundled —
@@ -92,6 +93,7 @@ export function ForceGraph({
onNodeClick?: (id: string) => void;
settings?: ForceGraphSettings;
}): React.JSX.Element {
+ const { t } = useTranslation('graph');
const [view, setView] = useState({ k: 1, tx: 0, ty: 0 });
/** Last known positions — read by React renders, written by sim ticks. */
const positionsRef = useRef(new Map());
@@ -272,6 +274,7 @@ export function ForceGraph({
className="force-graph"
viewBox={`${-width / 2} ${-height / 2} ${width} ${height}`}
role="img"
+ aria-label={t('svgLabel', { nodes: nodes.length, edges: edges.length })}
onWheel={onWheel}
onPointerDown={onPointerDown}
onPointerMove={onPointerMove}
diff --git a/apps/web/src/styles/base.css b/apps/web/src/styles/base.css
index 4d0024a..fbfad2d 100644
--- a/apps/web/src/styles/base.css
+++ b/apps/web/src/styles/base.css
@@ -1701,15 +1701,19 @@ ul[data-type='task_list'] li {
robust form. `:first-of-type`/`:last-of-type` (NOT `:first-child`) because
the ``/`