mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-15 14:29:25 +02:00
feat: adding more accessibility tooling
This commit is contained in:
45
demos/er.html
Normal file
45
demos/er.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Mermaid Quick Test Page</title>
|
||||||
|
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=">
|
||||||
|
<style>
|
||||||
|
div.mermaid {
|
||||||
|
/* font-family: 'trebuchet ms', verdana, arial; */
|
||||||
|
font-family: 'Courier New', Courier, monospace !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="mermaid">
|
||||||
|
erDiagram
|
||||||
|
title This is a title
|
||||||
|
accDescription Test a description
|
||||||
|
CUSTOMER ||--o{ ORDER : places
|
||||||
|
ORDER ||--|{ LINE-ITEM : contains
|
||||||
|
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="./mermaid.js"></script>
|
||||||
|
<script>
|
||||||
|
mermaid.initialize({
|
||||||
|
theme: 'forest',
|
||||||
|
// themeCSS: '.node rect { fill: red; }',
|
||||||
|
logLevel: 3,
|
||||||
|
securityLevel: 'loose',
|
||||||
|
flowchart: { curve: 'basis' },
|
||||||
|
gantt: { axisFormat: '%m/%d/%Y' },
|
||||||
|
sequence: { actorMargin: 50 },
|
||||||
|
// sequenceDiagram: { actorMargin: 300 } // deprecated
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@@ -230,6 +230,8 @@
|
|||||||
<h3>flowchart</h3>
|
<h3>flowchart</h3>
|
||||||
<div class="mermaid">
|
<div class="mermaid">
|
||||||
flowchart TD
|
flowchart TD
|
||||||
|
title Christmas
|
||||||
|
accDescription Get money
|
||||||
A[Christmas] -->|Get money| B(Go shopping)
|
A[Christmas] -->|Get money| B(Go shopping)
|
||||||
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
|
B --> C{Let me thinksssssx<br/>sssssssssssssssssssuuu<br />tttsssssssssssssssssssssss}
|
||||||
C -->|One| D[Laptop]
|
C -->|One| D[Laptop]
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
<div class="mermaid">
|
<div class="mermaid">
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
|
title: FancySequenceDiagram
|
||||||
accDescription Test a description
|
accDescription Test a description
|
||||||
participant Alice
|
participant Alice
|
||||||
participant Bob
|
participant Bob
|
||||||
|
11
launch.json
Normal file
11
launch.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "attach",
|
||||||
|
"name": "Attach",
|
||||||
|
"port": 9229
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@@ -9,15 +9,16 @@
|
|||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
export default function addSVGAccessibilityFields(yy_parser, svg, id) {
|
export default function addSVGAccessibilityFields(yy_parser, svg, id) {
|
||||||
|
if (typeof svg.insert == 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let title_string = yy_parser.getTitle();
|
let title_string = yy_parser.getTitle();
|
||||||
let description = yy_parser.getAccDescription();
|
let description = yy_parser.getAccDescription();
|
||||||
svg.attr('role', 'img').attr('aria-labelledby', 'chart-title-' + id + ' chart-desc-' + id);
|
svg.attr('role', 'img').attr('aria-labelledby', 'chart-title-' + id + ' chart-desc-' + id);
|
||||||
|
|
||||||
svg
|
svg
|
||||||
.insert('desc', ':first-child')
|
.insert('desc', ':first-child')
|
||||||
.attr('id', 'chart-desc-' + id)
|
.attr('id', 'chart-desc-' + id)
|
||||||
.text(description);
|
.text(description);
|
||||||
|
|
||||||
svg
|
svg
|
||||||
.insert('title', ':first-child')
|
.insert('title', ':first-child')
|
||||||
.attr('id', 'chart-title-' + id)
|
.attr('id', 'chart-title-' + id)
|
||||||
|
@@ -5,6 +5,7 @@ import * as configApi from '../../config';
|
|||||||
let entities = {};
|
let entities = {};
|
||||||
let relationships = [];
|
let relationships = [];
|
||||||
let title = '';
|
let title = '';
|
||||||
|
let description = '';
|
||||||
|
|
||||||
const Cardinality = {
|
const Cardinality = {
|
||||||
ZERO_OR_ONE: 'ZERO_OR_ONE',
|
ZERO_OR_ONE: 'ZERO_OR_ONE',
|
||||||
@@ -75,6 +76,14 @@ const getTitle = function () {
|
|||||||
return title;
|
return title;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setAccDescription = function (txt) {
|
||||||
|
description = txt;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAccDescription = function () {
|
||||||
|
return description;
|
||||||
|
};
|
||||||
|
|
||||||
const clear = function () {
|
const clear = function () {
|
||||||
entities = {};
|
entities = {};
|
||||||
relationships = [];
|
relationships = [];
|
||||||
@@ -94,4 +103,6 @@ export default {
|
|||||||
clear,
|
clear,
|
||||||
setTitle,
|
setTitle,
|
||||||
getTitle,
|
getTitle,
|
||||||
|
setAccDescription,
|
||||||
|
getAccDescription,
|
||||||
};
|
};
|
||||||
|
@@ -7,6 +7,7 @@ import { getConfig } from '../../config';
|
|||||||
import { log } from '../../logger';
|
import { log } from '../../logger';
|
||||||
import erMarkers from './erMarkers';
|
import erMarkers from './erMarkers';
|
||||||
import { configureSvgSize } from '../../utils';
|
import { configureSvgSize } from '../../utils';
|
||||||
|
import addSVGAccessibilityFields from '../../accessibility';
|
||||||
|
|
||||||
const conf = {};
|
const conf = {};
|
||||||
|
|
||||||
@@ -637,6 +638,8 @@ export const draw = function (text, id) {
|
|||||||
configureSvgSize(svg, height, width, conf.useMaxWidth);
|
configureSvgSize(svg, height, width, conf.useMaxWidth);
|
||||||
|
|
||||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||||
|
|
||||||
|
addSVGAccessibilityFields(parser.yy, svg, id);
|
||||||
}; // draw
|
}; // draw
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@@ -2,8 +2,14 @@
|
|||||||
|
|
||||||
%options case-insensitive
|
%options case-insensitive
|
||||||
%x open_directive type_directive arg_directive block
|
%x open_directive type_directive arg_directive block
|
||||||
|
%x title
|
||||||
|
%x accDescription
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
title { this.begin("title");return 'title'; }
|
||||||
|
<title>(?!\n|;|#)*[^\n]* { this.popState(); return "title_value"; }
|
||||||
|
accDescription { this.begin("accDescription");return 'accDescription'; }
|
||||||
|
<accDescription>(?!\n|;|#)*[^\n]* { this.popState(); return "description_value"; }
|
||||||
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
|
\%\%\{ { this.begin('open_directive'); return 'open_directive'; }
|
||||||
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
|
<open_directive>((?:(?!\}\%\%)[^:.])*) { this.begin('type_directive'); return 'type_directive'; }
|
||||||
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
|
<type_directive>":" { this.popState(); this.begin('arg_directive'); return ':'; }
|
||||||
@@ -84,6 +90,8 @@ statement
|
|||||||
}
|
}
|
||||||
| entityName BLOCK_START BLOCK_STOP { yy.addEntity($1); }
|
| entityName BLOCK_START BLOCK_STOP { yy.addEntity($1); }
|
||||||
| entityName { yy.addEntity($1); }
|
| entityName { yy.addEntity($1); }
|
||||||
|
| title title_value { $$=$2.trim();yy.setTitle($$); }
|
||||||
|
| accDescription description_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
entityName
|
entityName
|
||||||
|
@@ -181,6 +181,17 @@ describe('when parsing ER diagram it...', function () {
|
|||||||
expect(Object.keys(erDb.getEntities()).length).toBe(1);
|
expect(Object.keys(erDb.getEntities()).length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow for a title and acc description', function () {
|
||||||
|
const teacherRole = 'is teacher of';
|
||||||
|
const line1 = `TEACHER }o--o{ STUDENT : "${teacherRole}"`;
|
||||||
|
|
||||||
|
erDiagram.parser.parse(
|
||||||
|
`erDiagram\ntitle graph title\n accDescription this graph is about stuff\n${line1}`
|
||||||
|
);
|
||||||
|
expect(erDb.getTitle()).toBe('graph title');
|
||||||
|
expect(erDb.getAccDescription()).toBe('this graph is about stuff');
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow more than one relationship between the same two entities', function () {
|
it('should allow more than one relationship between the same two entities', function () {
|
||||||
const line1 = 'CAR ||--o{ PERSON : "insured for"';
|
const line1 = 'CAR ||--o{ PERSON : "insured for"';
|
||||||
const line2 = 'CAR }o--|| PERSON : "owned by"';
|
const line2 = 'CAR }o--|| PERSON : "owned by"';
|
||||||
|
@@ -56,7 +56,8 @@
|
|||||||
"note" return 'note';
|
"note" return 'note';
|
||||||
"activate" { this.begin('ID'); return 'activate'; }
|
"activate" { this.begin('ID'); return 'activate'; }
|
||||||
"deactivate" { this.begin('ID'); return 'deactivate'; }
|
"deactivate" { this.begin('ID'); return 'deactivate'; }
|
||||||
"title" return 'title';
|
"title"\s[^#\n;]+ return 'title';
|
||||||
|
"title:"\s[^#\n;]+ return 'legacy_title';
|
||||||
"accDescription"\s[^#\n;]+ return 'accDescription';
|
"accDescription"\s[^#\n;]+ return 'accDescription';
|
||||||
"sequenceDiagram" return 'SD';
|
"sequenceDiagram" return 'SD';
|
||||||
"autonumber" return 'autonumber';
|
"autonumber" return 'autonumber';
|
||||||
@@ -122,7 +123,8 @@ statement
|
|||||||
| link_statement 'NEWLINE'
|
| link_statement 'NEWLINE'
|
||||||
| properties_statement 'NEWLINE'
|
| properties_statement 'NEWLINE'
|
||||||
| details_statement 'NEWLINE'
|
| details_statement 'NEWLINE'
|
||||||
| title text2 'NEWLINE' {$$=[{type:'setTitle', text:$2}]}
|
| title {yy.setTitle($1.substring(6));$$=$1.substring(6);}
|
||||||
|
| legacy_title {yy.setTitle($1.substring(7));$$=$1.substring(7);}
|
||||||
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
|
| accDescription {yy.setAccDescription($1.substring(15));$$=$1.substring(15);}
|
||||||
| 'loop' restOfLine document end
|
| 'loop' restOfLine document end
|
||||||
{
|
{
|
||||||
|
@@ -9,7 +9,6 @@ let messages = [];
|
|||||||
const notes = [];
|
const notes = [];
|
||||||
let title = '';
|
let title = '';
|
||||||
let description = '';
|
let description = '';
|
||||||
let titleWrapped = false;
|
|
||||||
let sequenceNumbersEnabled = false;
|
let sequenceNumbersEnabled = false;
|
||||||
let wrapEnabled = false;
|
let wrapEnabled = false;
|
||||||
|
|
||||||
@@ -123,9 +122,6 @@ export const getActorKeys = function () {
|
|||||||
export const getTitle = function () {
|
export const getTitle = function () {
|
||||||
return title;
|
return title;
|
||||||
};
|
};
|
||||||
export const getTitleWrapped = function () {
|
|
||||||
return titleWrapped;
|
|
||||||
};
|
|
||||||
export const enableSequenceNumbers = function () {
|
export const enableSequenceNumbers = function () {
|
||||||
sequenceNumbersEnabled = true;
|
sequenceNumbersEnabled = true;
|
||||||
};
|
};
|
||||||
@@ -324,9 +320,9 @@ export const getActorProperty = function (actor, key) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setTitle = function (titleWrap) {
|
export const setTitle = function (txt) {
|
||||||
title = titleWrap.text;
|
let sanitizedText = sanitizeText(txt, configApi.getConfig());
|
||||||
titleWrapped = (titleWrap.wrap === undefined && autoWrap()) || !!titleWrap.wrap;
|
title = sanitizedText;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const apply = function (param) {
|
export const apply = function (param) {
|
||||||
@@ -410,7 +406,8 @@ export const apply = function (param) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setAccDescription = function (description_lex) {
|
const setAccDescription = function (description_lex) {
|
||||||
description = description_lex;
|
let sanitizedText = sanitizeText(description_lex, configApi.getConfig());
|
||||||
|
description = sanitizedText;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAccDescription = function () {
|
const getAccDescription = function () {
|
||||||
@@ -436,7 +433,6 @@ export default {
|
|||||||
getTitle,
|
getTitle,
|
||||||
parseDirective,
|
parseDirective,
|
||||||
getConfig: () => configApi.getConfig().sequence,
|
getConfig: () => configApi.getConfig().sequence,
|
||||||
getTitleWrapped,
|
|
||||||
clear,
|
clear,
|
||||||
parseMessage,
|
parseMessage,
|
||||||
LINETYPE,
|
LINETYPE,
|
||||||
|
@@ -60,7 +60,7 @@ Bob-->Alice: I am good thanks!`;
|
|||||||
mermaidAPI.parse(str);
|
mermaidAPI.parse(str);
|
||||||
expect(parser.yy.showSequenceNumbers()).toBe(true);
|
expect(parser.yy.showSequenceNumbers()).toBe(true);
|
||||||
});
|
});
|
||||||
it('it should handle a sequenceDiagram definition with a title', function () {
|
it('it should handle a sequenceDiagram definition with a title:', function () {
|
||||||
const str = `
|
const str = `
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
title: Diagram Title
|
title: Diagram Title
|
||||||
@@ -82,10 +82,34 @@ Bob-->Alice: I am good thanks!`;
|
|||||||
expect(messages[2].from).toBe('Bob');
|
expect(messages[2].from).toBe('Bob');
|
||||||
expect(title).toBe('Diagram Title');
|
expect(title).toBe('Diagram Title');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('it should handle a sequenceDiagram definition with a title without a :', function () {
|
||||||
|
const str = `
|
||||||
|
sequenceDiagram
|
||||||
|
title Diagram Title
|
||||||
|
Alice->Bob:Hello Bob, how are you?
|
||||||
|
Note right of Bob: Bob thinks
|
||||||
|
Bob-->Alice: I am good thanks!`;
|
||||||
|
|
||||||
|
mermaidAPI.parse(str);
|
||||||
|
const actors = parser.yy.getActors();
|
||||||
|
expect(actors.Alice.description).toBe('Alice');
|
||||||
|
actors.Bob.description = 'Bob';
|
||||||
|
|
||||||
|
expect(parser.yy.getAccDescription()).toBe('');
|
||||||
|
const messages = parser.yy.getMessages();
|
||||||
|
const title = parser.yy.getTitle();
|
||||||
|
|
||||||
|
expect(messages.length).toBe(3);
|
||||||
|
expect(messages[0].from).toBe('Alice');
|
||||||
|
expect(messages[2].from).toBe('Bob');
|
||||||
|
expect(title).toBe('Diagram Title');
|
||||||
|
});
|
||||||
|
|
||||||
it('it should handle a sequenceDiagram definition with a accDescription', function () {
|
it('it should handle a sequenceDiagram definition with a accDescription', function () {
|
||||||
const str = `
|
const str = `
|
||||||
sequenceDiagram
|
sequenceDiagram
|
||||||
accDescription: Accessibility Description
|
accDescription Accessibility Description
|
||||||
Alice->Bob:Hello Bob, how are you?
|
Alice->Bob:Hello Bob, how are you?
|
||||||
Note right of Bob: Bob thinks
|
Note right of Bob: Bob thinks
|
||||||
Bob-->Alice: I am good thanks!`;
|
Bob-->Alice: I am good thanks!`;
|
||||||
@@ -1609,6 +1633,7 @@ participant Alice
|
|||||||
|
|
||||||
renderer.bounds.init();
|
renderer.bounds.init();
|
||||||
mermaidAPI.parse(str);
|
mermaidAPI.parse(str);
|
||||||
|
|
||||||
renderer.draw(str, 'tst');
|
renderer.draw(str, 'tst');
|
||||||
|
|
||||||
const { bounds, models } = renderer.bounds.getBounds();
|
const { bounds, models } = renderer.bounds.getBounds();
|
||||||
|
Reference in New Issue
Block a user