Skip to content

Commit 5f08285

Browse files
shail-mehtashail-mehtajoedolsonellatrix
authored andcommitted
Replaces the title attributes used by revision inline diff annotations with aria-describedby (#80440)
* Replace revision diff attributes with * Check Unit test * Check Unit test * Apply Feedback Changes Co-authored-by: shail-mehta <shailu25@git.wordpress.org> Co-authored-by: joedolson <joedolson@git.wordpress.org> Co-authored-by: ellatrix <ellatrix@git.wordpress.org>
1 parent 63bdeed commit 5f08285

4 files changed

Lines changed: 94 additions & 23 deletions

File tree

packages/editor/src/components/post-revisions-preview/block-diff.js

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { __, _n, sprintf } from '@wordpress/i18n';
2929
* Internal dependencies
3030
*/
3131
import { unlock } from '../../lock-unlock';
32+
import { DIFF_DESCRIPTION_IDS } from './diff-format-types';
3233

3334
const { parseRawBlock } = unlock( blocksPrivateApis );
3435

@@ -562,7 +563,9 @@ function applyRichTextDiff( currentRichText, previousRichText ) {
562563
removedSlice,
563564
{
564565
type: 'revision/diff-removed',
565-
attributes: { title: __( 'Removed' ) },
566+
attributes: {
567+
'aria-describedby': DIFF_DESCRIPTION_IDS.removed,
568+
},
566569
},
567570
0,
568571
part.value.length
@@ -580,7 +583,9 @@ function applyRichTextDiff( currentRichText, previousRichText ) {
580583
addedSlice,
581584
{
582585
type: 'revision/diff-added',
583-
attributes: { title: __( 'Added' ) },
586+
attributes: {
587+
'aria-describedby': DIFF_DESCRIPTION_IDS.added,
588+
},
584589
},
585590
0,
586591
part.value.length
@@ -619,26 +624,40 @@ function applyRichTextDiff( currentRichText, previousRichText ) {
619624
);
620625

621626
if ( rangeFormatChanged ) {
622-
// Get type and description of what changed
623-
const { type, description } = describeFormatChange(
627+
// Get type of what changed. `description` (e.g. "2
628+
// formats changed") is no longer used for the
629+
// accessible name: aria-describedby must point to a
630+
// static element already in the document, so we
631+
// reference one of a fixed set of shared hidden
632+
// descriptions instead of building one per instance.
633+
const { type } = describeFormatChange(
624634
currentFormats,
625635
previousFormats,
626636
currentIdx + rangeStart,
627637
previousIdx + rangeStart
628638
);
629639

630-
// Map change type to format type for styling
640+
// Map change type to format type for styling, and
641+
// the id of its shared hidden description element.
631642
const formatType = {
632643
added: 'revision/diff-format-added',
633644
removed: 'revision/diff-format-removed',
634645
changed: 'revision/diff-format-changed',
635646
}[ type ];
636647

648+
const descriptionId = {
649+
added: DIFF_DESCRIPTION_IDS.formatAdded,
650+
removed: DIFF_DESCRIPTION_IDS.formatRemoved,
651+
changed: DIFF_DESCRIPTION_IDS.formatChanged,
652+
}[ type ];
653+
637654
const marked = applyFormat(
638655
rangeSlice,
639656
{
640657
type: formatType,
641-
attributes: { title: description },
658+
attributes: {
659+
'aria-describedby': descriptionId,
660+
},
642661
},
643662
0,
644663
i - rangeStart

packages/editor/src/components/post-revisions-preview/diff-format-types.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44
import { __ } from '@wordpress/i18n';
55
import { registerFormatType, unregisterFormatType } from '@wordpress/rich-text';
66

7+
/**
8+
* IDs of the visually-hidden description elements rendered into the
9+
* revisions canvas (see revisions-canvas.js). Diff formats reference
10+
* these via `aria-describedby` instead of a `title` attribute, since
11+
* `title` is inconsistently announced by screen readers in
12+
* low-verbosity modes.
13+
*/
14+
export const DIFF_DESCRIPTION_IDS = {
15+
removed: 'revision-diff-removed-desc',
16+
added: 'revision-diff-added-desc',
17+
formatAdded: 'revision-diff-format-added-desc',
18+
formatRemoved: 'revision-diff-format-removed-desc',
19+
formatChanged: 'revision-diff-format-changed-desc',
20+
};
21+
722
const DIFF_FORMAT_TYPES = [
823
{
924
name: 'revision/diff-removed',
@@ -20,19 +35,19 @@ const DIFF_FORMAT_TYPES = [
2035
{
2136
name: 'revision/diff-format-added',
2237
title: __( 'Format added' ),
23-
tagName: 'span',
38+
tagName: 'mark',
2439
className: 'revision-diff-format-added',
2540
},
2641
{
2742
name: 'revision/diff-format-removed',
2843
title: __( 'Format removed' ),
29-
tagName: 'span',
44+
tagName: 'mark',
3045
className: 'revision-diff-format-removed',
3146
},
3247
{
3348
name: 'revision/diff-format-changed',
3449
title: __( 'Format changed' ),
35-
tagName: 'span',
50+
tagName: 'mark',
3651
className: 'revision-diff-format-changed',
3752
},
3853
];
@@ -41,7 +56,7 @@ export function registerDiffFormatTypes() {
4156
for ( const formatType of DIFF_FORMAT_TYPES ) {
4257
registerFormatType( formatType.name, {
4358
...formatType,
44-
attributes: { title: 'title' },
59+
attributes: { 'aria-describedby': 'aria-describedby' },
4560
edit: () => null,
4661
} );
4762
}

packages/editor/src/components/post-revisions-preview/revisions-canvas.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
1111
import { useSelect } from '@wordpress/data';
1212
import { useEffect } from '@wordpress/element';
1313
import { addFilter } from '@wordpress/hooks';
14+
import { __ } from '@wordpress/i18n';
15+
import { VisuallyHidden } from '@wordpress/ui';
1416

1517
/**
1618
* Internal dependencies
@@ -21,6 +23,7 @@ import VisualEditor from '../visual-editor';
2123
import {
2224
registerDiffFormatTypes,
2325
unregisterDiffFormatTypes,
26+
DIFF_DESCRIPTION_IDS,
2427
} from './diff-format-types';
2528
import { useDiffMarkers } from './diff-markers';
2629

@@ -78,6 +81,14 @@ const REVISION_DIFF_STYLES = `
7881
background-color: color-mix(in srgb, currentColor 5%, #00a32a 15%);
7982
text-decoration: none;
8083
}
84+
/* Reset UA <mark> styles so format markers keep the same look as before. */
85+
mark.revision-diff-format-added,
86+
mark.revision-diff-format-removed,
87+
mark.revision-diff-format-changed {
88+
background: transparent;
89+
color: inherit;
90+
padding: 0;
91+
}
8192
.revision-diff-format-added {
8293
text-decoration: underline wavy color-mix(in srgb, currentColor 30%, #00a32a 70%);
8394
text-decoration-thickness: 2px;
@@ -136,10 +147,36 @@ function DiffStyleOverrides( { showDiff } ) {
136147
return null;
137148
}
138149

150+
/**
151+
* Visually hidden descriptions that diff marks (<del>, <ins>, <mark>)
152+
* reference via `aria-describedby`. They must be rendered inside the
153+
* canvas iframe because `aria-describedby` cannot reference an element
154+
* across a document/iframe boundary. This is more reliable than `title`,
155+
* which some screen readers ignore in low-verbosity modes.
156+
*/
157+
function DiffDescriptions() {
158+
return (
159+
<VisuallyHidden>
160+
<span id={ DIFF_DESCRIPTION_IDS.removed }>{ __( 'Removed' ) }</span>
161+
<span id={ DIFF_DESCRIPTION_IDS.added }>{ __( 'Added' ) }</span>
162+
<span id={ DIFF_DESCRIPTION_IDS.formatAdded }>
163+
{ __( 'Format added' ) }
164+
</span>
165+
<span id={ DIFF_DESCRIPTION_IDS.formatRemoved }>
166+
{ __( 'Format removed' ) }
167+
</span>
168+
<span id={ DIFF_DESCRIPTION_IDS.formatChanged }>
169+
{ __( 'Format changed' ) }
170+
</span>
171+
</VisuallyHidden>
172+
);
173+
}
174+
139175
function CanvasContent( { showDiff } ) {
140176
const [ contentRef, diffMarkers ] = useDiffMarkers();
141177
return (
142178
<>
179+
{ showDiff && <DiffDescriptions /> }
143180
<VisualEditor contentRef={ contentRef } />
144181
{ showDiff && diffMarkers }
145182
</>

packages/editor/src/components/post-revisions-preview/test/block-diff.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ describe( 'diffRevisionContent', () => {
230230
attributes: {
231231
// Inline diff: "existing" → "modified"
232232
content:
233-
'This is some <del title="Removed" class="revision-diff-removed">existing</del><ins title="Added" class="revision-diff-added">modified</ins> content',
233+
'This is some <del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">existing</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">modified</ins> content',
234234
__revisionDiffStatus: {
235235
status: 'modified',
236236
},
@@ -427,7 +427,7 @@ describe( 'diffRevisionContent', () => {
427427
name: 'core/paragraph',
428428
attributes: {
429429
content:
430-
'Second block content<ins title="Added" class="revision-diff-added"> modified</ins>',
430+
'Second block content<ins aria-describedby="revision-diff-added-desc" class="revision-diff-added"> modified</ins>',
431431
__revisionDiffStatus: {
432432
status: 'modified',
433433
},
@@ -523,7 +523,7 @@ describe( 'diffRevisionContent', () => {
523523
name: 'core/paragraph',
524524
attributes: {
525525
content:
526-
'Original tail content sentence<ins title="Added" class="revision-diff-added"> rewritten</ins>',
526+
'Original tail content sentence<ins aria-describedby="revision-diff-added-desc" class="revision-diff-added"> rewritten</ins>',
527527
__revisionDiffStatus: { status: 'modified' },
528528
},
529529
},
@@ -800,7 +800,7 @@ describe( 'diffRevisionContent', () => {
800800
attributes: {
801801
// B→D modification with inline diff
802802
content:
803-
'<del title="Removed" class="revision-diff-removed">B</del><ins title="Added" class="revision-diff-added">D</ins>',
803+
'<del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">B</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">D</ins>',
804804
__revisionDiffStatus: {
805805
status: 'modified',
806806
},
@@ -859,7 +859,7 @@ describe( 'diffRevisionContent', () => {
859859
attributes: {
860860
// jumps→leaps modification with inline diff
861861
content:
862-
'The quick brown fox <del title="Removed" class="revision-diff-removed">jumps</del><ins title="Added" class="revision-diff-added">leaps</ins> over the lazy dog',
862+
'The quick brown fox <del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">jumps</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">leaps</ins> over the lazy dog',
863863
__revisionDiffStatus: {
864864
status: 'modified',
865865
},
@@ -1056,7 +1056,7 @@ describe( 'diffRevisionContent', () => {
10561056
name: 'core/paragraph',
10571057
attributes: {
10581058
content:
1059-
'Hello <strong><span title="1 format added" class="revision-diff-format-added">world</span></strong>',
1059+
'Hello <strong><mark aria-describedby="revision-diff-format-added-desc" class="revision-diff-format-added">world</mark></strong>',
10601060
__revisionDiffStatus: {
10611061
status: 'modified',
10621062
},
@@ -1084,7 +1084,7 @@ describe( 'diffRevisionContent', () => {
10841084
name: 'core/paragraph',
10851085
attributes: {
10861086
content:
1087-
'Hello <strong><del title="Removed" class="revision-diff-removed">world</del><ins title="Added" class="revision-diff-added">everyone</ins></strong>',
1087+
'Hello <strong><del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">world</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">everyone</ins></strong>',
10881088
__revisionDiffStatus: {
10891089
status: 'modified',
10901090
},
@@ -1136,7 +1136,7 @@ describe( 'diffRevisionContent', () => {
11361136
name: 'core/paragraph',
11371137
attributes: {
11381138
content:
1139-
'Visit <a href="https://new-site.com"><span title="1 format changed" class="revision-diff-format-changed">our site</span></a> today',
1139+
'Visit <a href="https://new-site.com"><mark aria-describedby="revision-diff-format-changed-desc" class="revision-diff-format-changed">our site</mark></a> today',
11401140
__revisionDiffStatus: {
11411141
status: 'modified',
11421142
},
@@ -1166,7 +1166,7 @@ describe( 'diffRevisionContent', () => {
11661166
name: 'core/paragraph',
11671167
attributes: {
11681168
content:
1169-
'Visit <a href="https://example.com"><del title="Removed" class="revision-diff-removed">our</del><ins title="Added" class="revision-diff-added">the</ins> <del title="Removed" class="revision-diff-removed">site</del><ins title="Added" class="revision-diff-added">website</ins></a> today',
1169+
'Visit <a href="https://example.com"><del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">our</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">the</ins> <del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">site</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">website</ins></a> today',
11701170
__revisionDiffStatus: {
11711171
status: 'modified',
11721172
},
@@ -1216,7 +1216,7 @@ describe( 'diffRevisionContent', () => {
12161216
name: 'core/paragraph',
12171217
attributes: {
12181218
content:
1219-
'<span title="1 format removed" class="revision-diff-format-removed">Bold</span> and <span title="1 format removed" class="revision-diff-format-removed">italic</span> text',
1219+
'<mark aria-describedby="revision-diff-format-removed-desc" class="revision-diff-format-removed">Bold</mark> and <mark aria-describedby="revision-diff-format-removed-desc" class="revision-diff-format-removed">italic</mark> text',
12201220
__revisionDiffStatus: {
12211221
status: 'modified',
12221222
},
@@ -1244,7 +1244,7 @@ describe( 'diffRevisionContent', () => {
12441244
name: 'core/paragraph',
12451245
attributes: {
12461246
content:
1247-
'Hello <em><span title="1 format added, 1 format removed" class="revision-diff-format-changed">world</span></em>',
1247+
'Hello <em><mark aria-describedby="revision-diff-format-changed-desc" class="revision-diff-format-changed">world</mark></em>',
12481248
__revisionDiffStatus: {
12491249
status: 'modified',
12501250
},
@@ -1291,7 +1291,7 @@ describe( 'diffRevisionContent', () => {
12911291
name: 'core/paragraph',
12921292
attributes: {
12931293
content:
1294-
'<del title="Removed" class="revision-diff-removed">Hello</del><ins title="Added" class="revision-diff-added">Goodbye</ins> <strong>world</strong>!',
1294+
'<del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">Hello</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">Goodbye</ins> <strong>world</strong>!',
12951295
__revisionDiffStatus: {
12961296
status: 'modified',
12971297
},
@@ -1329,7 +1329,7 @@ describe( 'diffRevisionContent', () => {
13291329
name: 'core/paragraph',
13301330
attributes: {
13311331
content:
1332-
'<del title="Removed" class="revision-diff-removed">Hello</del><ins title="Added" class="revision-diff-added">Goodbye</ins> <strong><del title="Removed" class="revision-diff-removed">world</del><ins title="Added" class="revision-diff-added">everyone</ins></strong>',
1332+
'<del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">Hello</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">Goodbye</ins> <strong><del aria-describedby="revision-diff-removed-desc" class="revision-diff-removed">world</del><ins aria-describedby="revision-diff-added-desc" class="revision-diff-added">everyone</ins></strong>',
13331333
__revisionDiffStatus: {
13341334
status: 'modified',
13351335
},

0 commit comments

Comments
 (0)