mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-01-28 07:03:17 +08:00
refactor accessibility
- remove @ts-ignore comments - rename vitest test and describe title - remove unnecessary types, e.i, `null` and `number` - clean `addSVGa11yTitleDescription` and `setA11yDiagramInfo` functions
This commit is contained in:
parent
d9db2edf5a
commit
228bafa909
@ -1,27 +1,24 @@
|
|||||||
import { MockedD3 } from './tests/MockedD3.js';
|
import { MockedD3 } from './tests/MockedD3.js';
|
||||||
import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js';
|
import { setA11yDiagramInfo, addSVGa11yTitleDescription } from './accessibility.js';
|
||||||
import { D3Element } from './mermaidAPI.js';
|
import type { D3Element } from './mermaidAPI.js';
|
||||||
|
|
||||||
describe('accessibility', () => {
|
describe('accessibility', () => {
|
||||||
const fauxSvgNode = new MockedD3();
|
const fauxSvgNode: MockedD3 = new MockedD3();
|
||||||
|
|
||||||
describe('setA11yDiagramInfo', () => {
|
describe('setA11yDiagramInfo', () => {
|
||||||
it('sets the svg element role to "graphics-document document"', () => {
|
it('should set svg element role to "graphics-document document"', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
||||||
expect(svgAttrSpy).toHaveBeenCalledWith('role', 'graphics-document document');
|
expect(svgAttrSpy).toHaveBeenCalledWith('role', 'graphics-document document');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets the aria-roledescription to the diagram type', () => {
|
it('should set aria-roledescription to the diagram type', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
setA11yDiagramInfo(fauxSvgNode, 'flowchart');
|
||||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-roledescription', 'flowchart');
|
expect(svgAttrSpy).toHaveBeenCalledWith('aria-roledescription', 'flowchart');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not set the aria-roledescription if the diagram type is empty', () => {
|
it('should not set aria-roledescription if the diagram type is empty', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
setA11yDiagramInfo(fauxSvgNode, '');
|
setA11yDiagramInfo(fauxSvgNode, '');
|
||||||
expect(svgAttrSpy).toHaveBeenCalledTimes(1);
|
expect(svgAttrSpy).toHaveBeenCalledTimes(1);
|
||||||
@ -32,8 +29,8 @@ describe('accessibility', () => {
|
|||||||
describe('addSVGa11yTitleDescription', () => {
|
describe('addSVGa11yTitleDescription', () => {
|
||||||
const givenId = 'theBaseId';
|
const givenId = 'theBaseId';
|
||||||
|
|
||||||
describe('with the given svg d3 object:', () => {
|
describe('with svg d3 object', () => {
|
||||||
it('does nothing if there is no insert defined', () => {
|
it('should do nothing if there is no insert defined', () => {
|
||||||
const noInsertSvg = {
|
const noInsertSvg = {
|
||||||
attr: vi.fn(),
|
attr: vi.fn(),
|
||||||
};
|
};
|
||||||
@ -42,26 +39,25 @@ describe('accessibility', () => {
|
|||||||
expect(noInsertAttrSpy).not.toHaveBeenCalled();
|
expect(noInsertAttrSpy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ----------------
|
// convenience functions to DRY up the spec
|
||||||
// Convenience functions to DRY up the spec
|
|
||||||
|
|
||||||
function expectAriaLabelledByIsTitleId(
|
function expectAriaLabelledByItTitleId(
|
||||||
svgD3Node: D3Element,
|
svgD3Node: D3Element,
|
||||||
title: string | null | undefined,
|
title: string | undefined,
|
||||||
desc: string | null | undefined,
|
desc: string | undefined,
|
||||||
givenId: string
|
givenId: string
|
||||||
) {
|
): void {
|
||||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-labelledby', `chart-title-${givenId}`);
|
expect(svgAttrSpy).toHaveBeenCalledWith('aria-labelledby', `chart-title-${givenId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function expectAriaDescribedByIsDescId(
|
function expectAriaDescribedByItDescId(
|
||||||
svgD3Node: D3Element,
|
svgD3Node: D3Element,
|
||||||
title: string | null | undefined,
|
title: string | undefined,
|
||||||
desc: string | null | undefined,
|
desc: string | undefined,
|
||||||
givenId: string
|
givenId: string
|
||||||
) {
|
): void {
|
||||||
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
const svgAttrSpy = vi.spyOn(svgD3Node, 'attr').mockReturnValue(svgD3Node);
|
||||||
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
addSVGa11yTitleDescription(svgD3Node, title, desc, givenId);
|
||||||
expect(svgAttrSpy).toHaveBeenCalledWith('aria-describedby', `chart-desc-${givenId}`);
|
expect(svgAttrSpy).toHaveBeenCalledWith('aria-describedby', `chart-desc-${givenId}`);
|
||||||
@ -69,154 +65,148 @@ describe('accessibility', () => {
|
|||||||
|
|
||||||
function a11yTitleTagInserted(
|
function a11yTitleTagInserted(
|
||||||
svgD3Node: D3Element,
|
svgD3Node: D3Element,
|
||||||
title: string | null | undefined,
|
title: string | undefined,
|
||||||
desc: string | null | undefined,
|
desc: string | undefined,
|
||||||
givenId: string,
|
givenId: string,
|
||||||
callNumber: number
|
callNumber: number
|
||||||
) {
|
): void {
|
||||||
a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'title', title);
|
a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'title', title);
|
||||||
}
|
}
|
||||||
|
|
||||||
function a11yDescTagInserted(
|
function a11yDescTagInserted(
|
||||||
svgD3Node: D3Element,
|
svgD3Node: D3Element,
|
||||||
title: string | null | undefined,
|
title: string | undefined,
|
||||||
desc: string | null | undefined,
|
desc: string | undefined,
|
||||||
givenId: string,
|
givenId: string,
|
||||||
callNumber: number
|
callNumber: number
|
||||||
) {
|
): void {
|
||||||
a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'desc', desc);
|
a11yTagInserted(svgD3Node, title, desc, givenId, callNumber, 'desc', desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
function a11yTagInserted(
|
function a11yTagInserted(
|
||||||
svgD3Node: D3Element,
|
_svgD3Node: D3Element,
|
||||||
title: string | null | undefined,
|
title: string | undefined,
|
||||||
desc: string | null | undefined,
|
desc: string | undefined,
|
||||||
givenId: string,
|
givenId: string,
|
||||||
callNumber: number,
|
callNumber: number,
|
||||||
expectedPrefix: string,
|
expectedPrefix: string,
|
||||||
expectedText: string | null | undefined
|
expectedText: string | undefined
|
||||||
) {
|
): void {
|
||||||
const fauxInsertedD3 = new MockedD3();
|
const fauxInsertedD3: MockedD3 = new MockedD3();
|
||||||
const svgInsertSpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxInsertedD3);
|
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxInsertedD3);
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const titleAttrSpy = vi.spyOn(fauxInsertedD3, 'attr').mockReturnValue(fauxInsertedD3);
|
const titleAttrSpy = vi.spyOn(fauxInsertedD3, 'attr').mockReturnValue(fauxInsertedD3);
|
||||||
const titleTextSpy = vi.spyOn(fauxInsertedD3, 'text');
|
const titleTextSpy = vi.spyOn(fauxInsertedD3, 'text');
|
||||||
|
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, title, desc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, title, desc, givenId);
|
||||||
expect(svgInsertSpy).toHaveBeenCalledWith(expectedPrefix, ':first-child');
|
expect(svginsertpy).toHaveBeenCalledWith(expectedPrefix, ':first-child');
|
||||||
expect(titleAttrSpy).toHaveBeenCalledWith('id', `chart-${expectedPrefix}-${givenId}`);
|
expect(titleAttrSpy).toHaveBeenCalledWith('id', `chart-${expectedPrefix}-${givenId}`);
|
||||||
expect(titleTextSpy).toHaveBeenNthCalledWith(callNumber, expectedText);
|
expect(titleTextSpy).toHaveBeenNthCalledWith(callNumber, expectedText);
|
||||||
}
|
}
|
||||||
// ----------------
|
|
||||||
|
|
||||||
describe('given an a11y title', () => {
|
describe('with a11y title', () => {
|
||||||
const a11yTitle = 'a11y title';
|
const a11yTitle = 'a11y title';
|
||||||
|
|
||||||
describe('given an a11y description', () => {
|
describe('with a11y description', () => {
|
||||||
const a11yDesc = 'a11y description';
|
const a11yDesc = 'a11y description';
|
||||||
|
|
||||||
it('sets aria-labelledby to the title id inserted as a child', () => {
|
it('shold set aria-labelledby to the title id inserted as a child', () => {
|
||||||
expectAriaLabelledByIsTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
expectAriaLabelledByItTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets aria-describedby to the description id inserted as a child', () => {
|
it('should set aria-describedby to the description id inserted as a child', () => {
|
||||||
expectAriaDescribedByIsDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
expectAriaDescribedByItDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts a title tag as the first child with the text set to the accTitle given', () => {
|
it('should insert title tag as the first child with the text set to the accTitle given', () => {
|
||||||
a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 2);
|
a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts a desc tag as the 2nd child with the text set to accDescription given', () => {
|
it('should insert desc tag as the 2nd child with the text set to accDescription given', () => {
|
||||||
a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe(`no a11y description`, () => {
|
describe(`without a11y description`, () => {
|
||||||
const a11yDesc = undefined;
|
const a11yDesc = undefined;
|
||||||
|
|
||||||
it('sets aria-labelledby to the title id inserted as a child', () => {
|
it('should set aria-labelledby to the title id inserted as a child', () => {
|
||||||
expectAriaLabelledByIsTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
expectAriaLabelledByItTitleId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no aria-describedby is set', () => {
|
it('should not set aria-describedby', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
|
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts a title tag as the first child with the text set to the accTitle given', () => {
|
it('should insert title tag as the first child with the text set to the accTitle given', () => {
|
||||||
a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
a11yTitleTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no description tag is inserted', () => {
|
it('should not insert description tag', () => {
|
||||||
const fauxTitle = new MockedD3();
|
const fauxTitle: MockedD3 = new MockedD3();
|
||||||
const svgInsertSpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgInsertSpy).not.toHaveBeenCalledWith('desc', ':first-child');
|
expect(svginsertpy).not.toHaveBeenCalledWith('desc', ':first-child');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('no a11y title', () => {
|
describe('without a11y title', () => {
|
||||||
const a11yTitle = undefined;
|
const a11yTitle = undefined;
|
||||||
|
|
||||||
describe('given an a11y description', () => {
|
describe('with a11y description', () => {
|
||||||
const a11yDesc = 'a11y description';
|
const a11yDesc = 'a11y description';
|
||||||
|
|
||||||
it('no aria-labelledby is set', () => {
|
it('should not set aria-labelledby', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
|
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no title tag inserted', () => {
|
it('should not insert title tag', () => {
|
||||||
const fauxTitle = new MockedD3();
|
const fauxTitle: MockedD3 = new MockedD3();
|
||||||
const svgInsertSpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgInsertSpy).not.toHaveBeenCalledWith('title', ':first-child');
|
expect(svginsertpy).not.toHaveBeenCalledWith('title', ':first-child');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets aria-describedby to the description id inserted as a child', () => {
|
it('should set aria-describedby to the description id inserted as a child', () => {
|
||||||
expectAriaDescribedByIsDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
expectAriaDescribedByItDescId(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('inserts a desc tag as the 2nd child with the text set to accDescription given', () => {
|
it('should insert desc tag as the 2nd child with the text set to accDescription given', () => {
|
||||||
a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
a11yDescTagInserted(fauxSvgNode, a11yTitle, a11yDesc, givenId, 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('no a11y description', () => {
|
describe('without a11y description', () => {
|
||||||
const a11yDesc = undefined;
|
const a11yDesc = undefined;
|
||||||
|
|
||||||
it('no aria-labelledby is set', () => {
|
it('should not set aria-labelledby', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
|
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-labelledby', expect.anything());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no aria-describedby is set', () => {
|
it('should not set aria-describedby', () => {
|
||||||
// @ts-ignore Required to easily handle the d3 select types
|
|
||||||
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
const svgAttrSpy = vi.spyOn(fauxSvgNode, 'attr').mockReturnValue(fauxSvgNode);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
|
expect(svgAttrSpy).not.toHaveBeenCalledWith('aria-describedby', expect.anything());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no title tag inserted', () => {
|
it('should not insert title tag', () => {
|
||||||
const fauxTitle = new MockedD3();
|
const fauxTitle: MockedD3 = new MockedD3();
|
||||||
const svgInsertSpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxTitle);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgInsertSpy).not.toHaveBeenCalledWith('title', ':first-child');
|
expect(svginsertpy).not.toHaveBeenCalledWith('title', ':first-child');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('no description tag inserted', () => {
|
it('should not insert description tag', () => {
|
||||||
const fauxDesc = new MockedD3();
|
const fauxDesc: MockedD3 = new MockedD3();
|
||||||
const svgInsertSpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxDesc);
|
const svginsertpy = vi.spyOn(fauxSvgNode, 'insert').mockReturnValue(fauxDesc);
|
||||||
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
addSVGa11yTitleDescription(fauxSvgNode, a11yTitle, a11yDesc, givenId);
|
||||||
expect(svgInsertSpy).not.toHaveBeenCalledWith('desc', ':first-child');
|
expect(svginsertpy).not.toHaveBeenCalledWith('desc', ':first-child');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* Accessibility (a11y) functions, types, helpers
|
* Accessibility (a11y) functions, types, helpers.
|
||||||
|
*
|
||||||
* @see https://www.w3.org/WAI/
|
* @see https://www.w3.org/WAI/
|
||||||
* @see https://www.w3.org/TR/wai-aria-1.1/
|
* @see https://www.w3.org/TR/wai-aria-1.1/
|
||||||
* @see https://www.w3.org/TR/svg-aam-1.0/
|
* @see https://www.w3.org/TR/svg-aam-1.0/
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
import { D3Element } from './mermaidAPI.js';
|
import type { D3Element } from './mermaidAPI.js';
|
||||||
|
|
||||||
import isEmpty from 'lodash-es/isEmpty.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SVG element role:
|
* SVG element role:
|
||||||
@ -21,50 +19,47 @@ import isEmpty from 'lodash-es/isEmpty.js';
|
|||||||
const SVG_ROLE = 'graphics-document document';
|
const SVG_ROLE = 'graphics-document document';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add role and aria-roledescription to the svg element
|
* Add role and aria-roledescription to the svg element.
|
||||||
*
|
*
|
||||||
* @param svg - d3 object that contains the SVG HTML element
|
* @param svg - d3 object that contains the SVG HTML element
|
||||||
* @param diagramType - diagram name for to the aria-roledescription
|
* @param diagramType - diagram name for to the aria-roledescription
|
||||||
*/
|
*/
|
||||||
export function setA11yDiagramInfo(svg: D3Element, diagramType: string | null | undefined) {
|
export function setA11yDiagramInfo(svg: D3Element, diagramType: string) {
|
||||||
svg.attr('role', SVG_ROLE);
|
svg.attr('role', SVG_ROLE);
|
||||||
if (!isEmpty(diagramType)) {
|
if (diagramType !== '') {
|
||||||
svg.attr('aria-roledescription', diagramType);
|
svg.attr('aria-roledescription', diagramType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an accessible title and/or description element to a chart.
|
* Add an accessible title and/or description element to a chart.
|
||||||
* The title is usually not displayed and the description is never displayed.
|
* The title is usually not displayed and the description is never displayed.
|
||||||
*
|
*
|
||||||
* The following charts display their title as a visual and accessibility element: gantt
|
* The following charts display their title as a visual and accessibility element: gantt.
|
||||||
*
|
*
|
||||||
* @param svg - d3 node to insert the a11y title and desc info
|
* @param svg - d3 node to insert the a11y title and desc info
|
||||||
* @param a11yTitle - a11y title. null and undefined are meaningful: means to skip it
|
* @param a11yTitle - a11y title. undefined or empty strings mean to skip them
|
||||||
* @param a11yDesc - a11y description. null and undefined are meaningful: means to skip it
|
* @param a11yDesc - a11y description. undefined or empty strings mean to skip them
|
||||||
* @param baseId - id used to construct the a11y title and description id
|
* @param baseId - id used to construct the a11y title and description id
|
||||||
*/
|
*/
|
||||||
export function addSVGa11yTitleDescription(
|
export function addSVGa11yTitleDescription(
|
||||||
svg: D3Element,
|
svg: D3Element,
|
||||||
a11yTitle: string | null | undefined,
|
a11yTitle: string | undefined,
|
||||||
a11yDesc: string | null | undefined,
|
a11yDesc: string | undefined,
|
||||||
baseId: string
|
baseId: string
|
||||||
) {
|
): void {
|
||||||
if (svg.insert === undefined) {
|
if (svg.insert === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a11yTitle || a11yDesc) {
|
|
||||||
if (a11yDesc) {
|
if (a11yDesc) {
|
||||||
const descId = 'chart-desc-' + baseId;
|
const descId = `chart-desc-${baseId}`;
|
||||||
svg.attr('aria-describedby', descId);
|
svg.attr('aria-describedby', descId);
|
||||||
svg.insert('desc', ':first-child').attr('id', descId).text(a11yDesc);
|
svg.insert('desc', ':first-child').attr('id', descId).text(a11yDesc);
|
||||||
}
|
}
|
||||||
if (a11yTitle) {
|
if (a11yTitle) {
|
||||||
const titleId = 'chart-title-' + baseId;
|
const titleId = `chart-title-${baseId}`;
|
||||||
svg.attr('aria-labelledby', titleId);
|
svg.attr('aria-labelledby', titleId);
|
||||||
svg.insert('title', ':first-child').attr('id', titleId).text(a11yTitle);
|
svg.insert('title', ':first-child').attr('id', titleId).text(a11yTitle);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import type {} from '@vitest/spy/dist/index.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a mocked/stubbed version of the d3 Selection type. Each of the main functions are all
|
* This is a mocked/stubbed version of the d3 Selection type. Each of the main functions are all
|
||||||
* mocked (via vi.fn()) so you can track if they have been called, etc.
|
* mocked (via vi.fn()) so you can track if they have been called, etc.
|
||||||
@ -7,9 +5,8 @@ import type {} from '@vitest/spy/dist/index.js';
|
|||||||
* Note that node() returns a HTML Element with tag 'svg'. It is an empty element (no innerHTML, no children, etc).
|
* Note that node() returns a HTML Element with tag 'svg'. It is an empty element (no innerHTML, no children, etc).
|
||||||
* This potentially allows testing of mermaidAPI render().
|
* This potentially allows testing of mermaidAPI render().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class MockedD3 {
|
export class MockedD3 {
|
||||||
public attribs = new Map<string, string | null>();
|
public attribs = new Map<string, string>();
|
||||||
public id: string | undefined = '';
|
public id: string | undefined = '';
|
||||||
_children: MockedD3[] = [];
|
_children: MockedD3[] = [];
|
||||||
|
|
||||||
@ -72,9 +69,9 @@ export class MockedD3 {
|
|||||||
return newMock;
|
return newMock;
|
||||||
};
|
};
|
||||||
|
|
||||||
attr(attrName: string): null | undefined | string | number;
|
attr(attrName: string): undefined | string;
|
||||||
// attr(attrName: string, attrValue: string): MockedD3;
|
attr(attrName: string, attrValue: string): MockedD3;
|
||||||
attr(attrName: string, attrValue?: string): null | undefined | string | number | MockedD3 {
|
attr(attrName: string, attrValue?: string): undefined | string | MockedD3 {
|
||||||
if (arguments.length === 1) {
|
if (arguments.length === 1) {
|
||||||
return this.attribs.get(attrName);
|
return this.attribs.get(attrName);
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user