(frontend) convert to figure/figcaption structure if caption exists

ensure  html structure by using figure/figcaption when captions are present

Signed-off-by: Cyril <c.gromoff@gmail.com>
This commit is contained in:
Cyril
2025-09-23 13:02:28 +02:00
parent cc4bed6f8e
commit 6cc42636e5
2 changed files with 69 additions and 6 deletions

View File

@@ -1,4 +1,3 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
@@ -21,6 +20,7 @@ and this project adheres to
- ♿ add document visible in list and openable via enter key #1365
- ♿ add pdf outline property to enable bookmarks display #1368
- ♿ hide decorative icons from assistive tech with aria-hidden #1404
- ♿ fix rgaa 1.9.1: convert to figure/figcaption structure #1426
- ♿ remove redundant aria-label to avoid over-accessibility #1420
- ♿ remove redundant aria-label on hidden icons and update tests #1432
- ♿ improve semantic structure and aria roles of leftpanel #1431
@@ -39,7 +39,6 @@ and this project adheres to
- ♿(frontend) improve accessibility:
- ♿improve NVDA navigation in DocShareModal #1396
## [3.7.0] - 2025-09-12
### Added

View File

@@ -10,6 +10,7 @@ import {
imageRender,
imageToExternalHTML,
} from '@blocknote/core';
import { t } from 'i18next';
type ImageBlockConfig = typeof imageBlockConfig;
@@ -25,10 +26,73 @@ export const accessibleImageRender = (
const dom = imageRenderComputed.dom;
const imgSelector = dom.querySelector('img');
imgSelector?.setAttribute('alt', '');
imgSelector?.setAttribute('role', 'presentation');
imgSelector?.setAttribute('aria-hidden', 'true');
imgSelector?.setAttribute('tabindex', '-1');
const withCaption =
block.props.caption && dom.querySelector('.bn-file-caption');
const accessibleImageWithCaption = () => {
imgSelector?.setAttribute('alt', block.props.caption);
imgSelector?.removeAttribute('aria-hidden');
imgSelector?.setAttribute('tabindex', '0');
// Fix RGAA 1.9.1: Convert to figure/figcaption structure if caption exists
const captionElement = dom.querySelector('.bn-file-caption');
if (captionElement) {
const figureElement = document.createElement('figure');
// Copy all attributes from the original div
figureElement.className = dom.className;
const styleAttr = dom.getAttribute('style');
if (styleAttr) {
figureElement.setAttribute('style', styleAttr);
}
figureElement.style.setProperty('margin', '0');
Array.from(dom.children).forEach((child) => {
figureElement.appendChild(child.cloneNode(true));
});
// Replace the <p> caption with <figcaption>
const figcaptionElement = document.createElement('figcaption');
const originalCaption = figureElement.querySelector('.bn-file-caption');
if (originalCaption) {
figcaptionElement.className = originalCaption.className;
figcaptionElement.textContent = originalCaption.textContent;
originalCaption.parentNode?.replaceChild(
figcaptionElement,
originalCaption,
);
// Add explicit role and aria-label for better screen reader support
figureElement.setAttribute('role', 'img');
figureElement.setAttribute(
'aria-label',
t(`Image: {{title}}`, { title: figcaptionElement.textContent }),
);
}
// Return the figure element as the new dom
return {
...imageRenderComputed,
dom: figureElement,
};
}
};
const accessibleImage = () => {
imgSelector?.setAttribute('alt', '');
imgSelector?.setAttribute('role', 'presentation');
imgSelector?.setAttribute('aria-hidden', 'true');
imgSelector?.setAttribute('tabindex', '-1');
};
// Set accessibility attributes for the image
const result = withCaption ? accessibleImageWithCaption() : accessibleImage();
// Return the result if accessibleImageWithCaption created a figure, otherwise return original
if (result) {
return result;
}
return {
...imageRenderComputed,