mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-16 13:59:54 +02:00
Add support for classes
This commit is contained in:
@@ -37,6 +37,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
|
|
||||||
"{" return 'STRUCT_START';
|
"{" return 'STRUCT_START';
|
||||||
"}" return 'STRUCT_STOP';
|
"}" return 'STRUCT_STOP';
|
||||||
|
":"{3} return 'STYLE_SEPARATOR';
|
||||||
":" return 'COLONSEP';
|
":" return 'COLONSEP';
|
||||||
|
|
||||||
"id" return 'ID';
|
"id" return 'ID';
|
||||||
@@ -77,13 +78,16 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
<style>\w+ return 'ALPHA';
|
<style>\w+ return 'ALPHA';
|
||||||
<style>":" return 'COLON';
|
<style>":" return 'COLON';
|
||||||
<style>";" return 'SEMICOLON';
|
<style>";" return 'SEMICOLON';
|
||||||
<style>"," return 'COMMA';
|
|
||||||
<style>"%" return 'PERCENT';
|
<style>"%" return 'PERCENT';
|
||||||
<style>"-" return 'MINUS';
|
<style>"-" return 'MINUS';
|
||||||
<style>"#" return 'BRKT';
|
<style>"#" return 'BRKT';
|
||||||
<style>" " /* skip spaces */
|
<style>" " /* skip spaces */
|
||||||
|
<style>["] { this.begin("string"); }
|
||||||
<style>\n { this.popState(); }
|
<style>\n { this.popState(); }
|
||||||
|
|
||||||
|
"classDef" { this.begin("style"); return 'CLASSDEF'; }
|
||||||
|
"class" { this.begin("style"); return 'CLASS'; }
|
||||||
|
|
||||||
"<-" return 'END_ARROW_L';
|
"<-" return 'END_ARROW_L';
|
||||||
"->" {return 'END_ARROW_R';}
|
"->" {return 'END_ARROW_R';}
|
||||||
"-" {return 'LINE';}
|
"-" {return 'LINE';}
|
||||||
@@ -92,10 +96,11 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
|
|||||||
<string>["] { this.popState(); }
|
<string>["] { this.popState(); }
|
||||||
<string>[^"]* { return "qString"; }
|
<string>[^"]* { return "qString"; }
|
||||||
|
|
||||||
[\w][^\r\n\{\<\>\-\=]* { yytext = yytext.trim(); return 'unqString';}
|
[\w][^:,\r\n\{\<\>\-\=]* { yytext = yytext.trim(); return 'unqString';}
|
||||||
|
|
||||||
<*>\w+ return 'ALPHA';
|
<*>\w+ return 'ALPHA';
|
||||||
<*>[0-9]+ return 'NUM';
|
<*>[0-9]+ return 'NUM';
|
||||||
|
<*>"," return 'COMMA';
|
||||||
|
|
||||||
/lex
|
/lex
|
||||||
|
|
||||||
@@ -122,6 +127,8 @@ diagram
|
|||||||
| directive diagram
|
| directive diagram
|
||||||
| direction diagram
|
| direction diagram
|
||||||
| styleStatement diagram
|
| styleStatement diagram
|
||||||
|
| classDefStatement diagram
|
||||||
|
| classStatement diagram
|
||||||
| NEWLINE diagram
|
| NEWLINE diagram
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -137,8 +144,9 @@ direction
|
|||||||
;
|
;
|
||||||
|
|
||||||
requirementDef
|
requirementDef
|
||||||
: requirementType requirementName STRUCT_START NEWLINE requirementBody
|
: requirementType requirementName STRUCT_START NEWLINE requirementBody { yy.addRequirement($2, $1) }
|
||||||
{ yy.addRequirement($2, $1) };
|
| requirementType requirementName STYLE_SEPARATOR idList STRUCT_START NEWLINE requirementBody { yy.addRequirement($2, $1); yy.setClass([$2], $4); }
|
||||||
|
;
|
||||||
|
|
||||||
requirementBody
|
requirementBody
|
||||||
: ID COLONSEP id NEWLINE requirementBody
|
: ID COLONSEP id NEWLINE requirementBody
|
||||||
@@ -182,8 +190,9 @@ verifyType
|
|||||||
{ $$=yy.VerifyType.VERIFY_TEST;};
|
{ $$=yy.VerifyType.VERIFY_TEST;};
|
||||||
|
|
||||||
elementDef
|
elementDef
|
||||||
: ELEMENT elementName STRUCT_START NEWLINE elementBody
|
: ELEMENT elementName STRUCT_START NEWLINE elementBody { yy.addElement($2) }
|
||||||
{ yy.addElement($2) };
|
| ELEMENT elementName STYLE_SEPARATOR idList STRUCT_START NEWLINE elementBody { yy.addElement($2); yy.setClass([$2], $4); }
|
||||||
|
;
|
||||||
|
|
||||||
elementBody
|
elementBody
|
||||||
: TYPE COLONSEP type NEWLINE elementBody
|
: TYPE COLONSEP type NEWLINE elementBody
|
||||||
@@ -215,8 +224,24 @@ relationship
|
|||||||
| TRACES
|
| TRACES
|
||||||
{ $$=yy.Relationships.TRACES;};
|
{ $$=yy.Relationships.TRACES;};
|
||||||
|
|
||||||
|
classDefStatement
|
||||||
|
: CLASSDEF idList stylesOpt {$$ = $CLASSDEF;yy.defineClass($idList,$stylesOpt);}
|
||||||
|
;
|
||||||
|
|
||||||
|
classStatement
|
||||||
|
: CLASS idList idList {yy.setClass($2, $3);}
|
||||||
|
| id STYLE_SEPARATOR idList {yy.setClass([$1], $3);}
|
||||||
|
;
|
||||||
|
|
||||||
|
idList
|
||||||
|
: ALPHA { $$ = [$ALPHA]; }
|
||||||
|
| idList COMMA ALPHA = { $$ = $idList.concat([$ALPHA]); }
|
||||||
|
| id { $$ = [$id]; }
|
||||||
|
| idList COMMA id = { $$ = $idList.concat([$id]); }
|
||||||
|
;
|
||||||
|
|
||||||
styleStatement
|
styleStatement
|
||||||
: STYLE ALPHA stylesOpt {$$ = $STYLE;yy.setCssStyle($2,$stylesOpt);}
|
: STYLE idList stylesOpt {$$ = $STYLE;yy.setCssStyle($2,$stylesOpt);}
|
||||||
;
|
;
|
||||||
|
|
||||||
stylesOpt
|
stylesOpt
|
||||||
|
@@ -16,6 +16,7 @@ import type {
|
|||||||
Relation,
|
Relation,
|
||||||
RelationshipType,
|
RelationshipType,
|
||||||
Requirement,
|
Requirement,
|
||||||
|
RequirementClass,
|
||||||
RequirementType,
|
RequirementType,
|
||||||
RiskLevel,
|
RiskLevel,
|
||||||
VerifyType,
|
VerifyType,
|
||||||
@@ -67,6 +68,7 @@ const getInitialRequirement = (): Requirement => ({
|
|||||||
name: '',
|
name: '',
|
||||||
type: RequirementType.REQUIREMENT as RequirementType,
|
type: RequirementType.REQUIREMENT as RequirementType,
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
|
classes: ['default'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const getInitialElement = (): Element => ({
|
const getInitialElement = (): Element => ({
|
||||||
@@ -74,6 +76,7 @@ const getInitialElement = (): Element => ({
|
|||||||
type: '',
|
type: '',
|
||||||
docRef: '',
|
docRef: '',
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
|
classes: ['default'],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update initial declarations
|
// Update initial declarations
|
||||||
@@ -82,6 +85,7 @@ let latestRequirement: Requirement = getInitialRequirement();
|
|||||||
let requirements = new Map<string, Requirement>();
|
let requirements = new Map<string, Requirement>();
|
||||||
let latestElement: Element = getInitialElement();
|
let latestElement: Element = getInitialElement();
|
||||||
let elements = new Map<string, Element>();
|
let elements = new Map<string, Element>();
|
||||||
|
let classes = new Map<string, RequirementClass>();
|
||||||
|
|
||||||
// Add reset functions
|
// Add reset functions
|
||||||
const resetLatestRequirement = () => {
|
const resetLatestRequirement = () => {
|
||||||
@@ -102,6 +106,7 @@ const addRequirement = (name: string, type: RequirementType) => {
|
|||||||
risk: latestRequirement.risk,
|
risk: latestRequirement.risk,
|
||||||
verifyMethod: latestRequirement.verifyMethod,
|
verifyMethod: latestRequirement.verifyMethod,
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
|
classes: ['default'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
resetLatestRequirement();
|
resetLatestRequirement();
|
||||||
@@ -142,6 +147,7 @@ const addElement = (name: string) => {
|
|||||||
type: latestElement.type,
|
type: latestElement.type,
|
||||||
docRef: latestElement.docRef,
|
docRef: latestElement.docRef,
|
||||||
cssStyles: [],
|
cssStyles: [],
|
||||||
|
classes: ['default'],
|
||||||
});
|
});
|
||||||
log.info('Added new element: ', name);
|
log.info('Added new element: ', name);
|
||||||
}
|
}
|
||||||
@@ -180,29 +186,84 @@ const clear = () => {
|
|||||||
requirements = new Map();
|
requirements = new Map();
|
||||||
resetLatestElement();
|
resetLatestElement();
|
||||||
elements = new Map();
|
elements = new Map();
|
||||||
|
classes = new Map();
|
||||||
commonClear();
|
commonClear();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setCssStyle = function (id: string, styles: string[]) {
|
export const setCssStyle = function (ids: string[], styles: string[]) {
|
||||||
const node = requirements.get(id) ?? elements.get(id);
|
for (const id of ids) {
|
||||||
if (!styles || !node) {
|
const node = requirements.get(id) ?? elements.get(id);
|
||||||
return;
|
if (!styles || !node) {
|
||||||
}
|
return;
|
||||||
for (const s of styles) {
|
}
|
||||||
if (s.includes(',')) {
|
for (const s of styles) {
|
||||||
node.cssStyles.push(...s.split(','));
|
if (s.includes(',')) {
|
||||||
} else {
|
node.cssStyles.push(...s.split(','));
|
||||||
node.cssStyles.push(s);
|
} else {
|
||||||
|
node.cssStyles.push(s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setClass = function (ids: string[], classNames: string[]) {
|
||||||
|
for (const id of ids) {
|
||||||
|
const node = requirements.get(id) ?? elements.get(id);
|
||||||
|
if (node) {
|
||||||
|
for (const _class of classNames) {
|
||||||
|
node.classes.push(_class);
|
||||||
|
const styles = classes.get(_class)?.styles;
|
||||||
|
if (styles) {
|
||||||
|
node.cssStyles.push(...styles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defineClass = function (ids: string[], style: string[]) {
|
||||||
|
for (const id of ids) {
|
||||||
|
let styleClass = classes.get(id);
|
||||||
|
if (styleClass === undefined) {
|
||||||
|
styleClass = { id, styles: [], textStyles: [] };
|
||||||
|
classes.set(id, styleClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (style) {
|
||||||
|
style.forEach(function (s) {
|
||||||
|
if (/color/.exec(s)) {
|
||||||
|
const newStyle = s.replace('fill', 'bgFill'); // .replace('color', 'fill');
|
||||||
|
styleClass.textStyles.push(newStyle);
|
||||||
|
}
|
||||||
|
styleClass.styles.push(s);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
requirements.forEach((value) => {
|
||||||
|
if (value.classes.includes(id)) {
|
||||||
|
value.cssStyles.push(...style.flatMap((s) => s.split(',')));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
elements.forEach((value) => {
|
||||||
|
if (value.classes.includes(id)) {
|
||||||
|
value.cssStyles.push(...style.flatMap((s) => s.split(',')));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getClasses = () => {
|
||||||
|
return classes;
|
||||||
|
};
|
||||||
|
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
const nodes: Node[] = [];
|
const nodes: Node[] = [];
|
||||||
const edges: Edge[] = [];
|
const edges: Edge[] = [];
|
||||||
for (const requirement of requirements.values()) {
|
for (const requirement of requirements.values()) {
|
||||||
const node = requirement as unknown as Node;
|
const node = requirement as unknown as Node;
|
||||||
|
node.cssStyles = requirement.cssStyles;
|
||||||
|
node.cssClasses = requirement.classes.join(' ');
|
||||||
node.shape = 'requirementBox';
|
node.shape = 'requirementBox';
|
||||||
node.look = config.look;
|
node.look = config.look;
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
@@ -213,6 +274,8 @@ const getData = () => {
|
|||||||
node.shape = 'requirementBox';
|
node.shape = 'requirementBox';
|
||||||
node.look = config.look;
|
node.look = config.look;
|
||||||
node.id = element.name;
|
node.id = element.name;
|
||||||
|
node.cssStyles = element.cssStyles;
|
||||||
|
node.cssClasses = element.classes.join(' ');
|
||||||
|
|
||||||
nodes.push(node);
|
nodes.push(node);
|
||||||
}
|
}
|
||||||
@@ -270,5 +333,8 @@ export default {
|
|||||||
getRelationships,
|
getRelationships,
|
||||||
clear,
|
clear,
|
||||||
setCssStyle,
|
setCssStyle,
|
||||||
|
setClass,
|
||||||
|
defineClass,
|
||||||
|
getClasses,
|
||||||
getData,
|
getData,
|
||||||
};
|
};
|
||||||
|
@@ -18,6 +18,7 @@ export interface Requirement {
|
|||||||
risk: RiskLevel;
|
risk: RiskLevel;
|
||||||
verifyMethod: VerifyType;
|
verifyMethod: VerifyType;
|
||||||
cssStyles: string[];
|
cssStyles: string[];
|
||||||
|
classes: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RelationshipType =
|
export type RelationshipType =
|
||||||
@@ -40,4 +41,11 @@ export interface Element {
|
|||||||
type: string;
|
type: string;
|
||||||
docRef: string;
|
docRef: string;
|
||||||
cssStyles: string[];
|
cssStyles: string[];
|
||||||
|
classes: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RequirementClass {
|
||||||
|
id: string;
|
||||||
|
styles: string[];
|
||||||
|
textStyles: string[];
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { updateNodeBounds } from './util.js';
|
import { getNodeClasses, updateNodeBounds } from './util.js';
|
||||||
import intersect from '../intersect/index.js';
|
import intersect from '../intersect/index.js';
|
||||||
import type { Node } from '../../types.js';
|
import type { Node } from '../../types.js';
|
||||||
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
import { styles2String, userNodeOverrides } from './handDrawnShapeStyles.js';
|
||||||
@@ -22,11 +22,12 @@ export async function requirementBox<T extends SVGGraphicsElement>(
|
|||||||
const PADDING = 20;
|
const PADDING = 20;
|
||||||
const GAP = 20;
|
const GAP = 20;
|
||||||
const isRequirementNode = 'verifyMethod' in node;
|
const isRequirementNode = 'verifyMethod' in node;
|
||||||
|
const classes = getNodeClasses(node);
|
||||||
|
|
||||||
// Add outer g element
|
// Add outer g element
|
||||||
const shapeSvg = parent
|
const shapeSvg = parent
|
||||||
.insert('g')
|
.insert('g')
|
||||||
.attr('class', '')
|
.attr('class', classes)
|
||||||
.attr('id', node.domId ?? node.id);
|
.attr('id', node.domId ?? node.id);
|
||||||
|
|
||||||
let typeHeight;
|
let typeHeight;
|
||||||
|
Reference in New Issue
Block a user