mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-21 09:16:41 +02:00
#5237 making styles take preceedence and adding test
This commit is contained in:
@@ -110,6 +110,7 @@ strikethrough
|
|||||||
stringifying
|
stringifying
|
||||||
struct
|
struct
|
||||||
STYLECLASS
|
STYLECLASS
|
||||||
|
STYLEDEF
|
||||||
STYLEOPTS
|
STYLEOPTS
|
||||||
subcomponent
|
subcomponent
|
||||||
subcomponents
|
subcomponents
|
||||||
|
@@ -558,6 +558,29 @@ stateDiagram-v2
|
|||||||
{ logLevel: 0, fontFamily: 'courier' }
|
{ logLevel: 0, fontFamily: 'courier' }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
it(' can have styles applied ', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
AState
|
||||||
|
style AState fill:#636,border:1px solid red,color:white;
|
||||||
|
`,
|
||||||
|
{ logLevel: 0, fontFamily: 'courier' }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
it(' should let styles take preceedence over classes', () => {
|
||||||
|
imgSnapshotTest(
|
||||||
|
`
|
||||||
|
stateDiagram-v2
|
||||||
|
AState: Should NOT be white
|
||||||
|
BState
|
||||||
|
classDef exampleStyleClass fill:#fff,color: blue;
|
||||||
|
class AState,BState exampleStyleClass
|
||||||
|
style AState fill:#636,border:1px solid red,color:white;
|
||||||
|
`,
|
||||||
|
{ logLevel: 0, fontFamily: 'courier' }
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
it('1433: should render a simple state diagram with a title', () => {
|
it('1433: should render a simple state diagram with a title', () => {
|
||||||
imgSnapshotTest(
|
imgSnapshotTest(
|
||||||
|
@@ -75,12 +75,127 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<h4>Case 1</h4>
|
||||||
|
<div class="flex">
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid">
|
||||||
flowchart LR
|
stateDiagram-v2
|
||||||
|
AState: Should NOT be white
|
||||||
|
BState
|
||||||
|
classDef exampleStyleClass fill:#fff,color: blue;
|
||||||
|
class AState,BState exampleStyleClass
|
||||||
|
style AState fill:#636,border:1px solid red,color:white;
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid">
|
||||||
|
%%{init: {"look": "classic"} }%%
|
||||||
|
stateDiagram-v2
|
||||||
|
AState: Should NOT be white
|
||||||
|
BState
|
||||||
|
classDef exampleStyleClass fill:#fff,color: blue;
|
||||||
|
class AState,BState exampleStyleClass
|
||||||
|
style AState fill:#636,border:1px solid red,color:white;
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram-v2
|
||||||
|
|
||||||
Apa --AA--> C
|
classDef exampleStyleClass background:#bbb,border:1px solid red;
|
||||||
</pre
|
a --> b
|
||||||
>
|
class a exampleStyleClass
|
||||||
|
%% a:::exampleStyleClass
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram
|
||||||
|
direction TB
|
||||||
|
|
||||||
|
accTitle: This is the accessible title
|
||||||
|
accDescr: This is an accessible description
|
||||||
|
|
||||||
|
classDef notMoving fill:white
|
||||||
|
classDef movement font-style:italic;
|
||||||
|
classDef badBadEvent fill:#f00,color:white,font-weight:bold,stroke-width:2px,stroke:yellow
|
||||||
|
|
||||||
|
[*] --> Still:::notMoving
|
||||||
|
Still --> [*]
|
||||||
|
Still --> Moving:::movement
|
||||||
|
Moving --> Still
|
||||||
|
Moving --> Crash:::movement
|
||||||
|
Crash:::badBadEvent --> [*]
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram-v2
|
||||||
|
MyState
|
||||||
|
note left of MyState : I am a leftie
|
||||||
|
note right of MyState : I am a rightie
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram
|
||||||
|
%% direction LR
|
||||||
|
|
||||||
|
state C0 {
|
||||||
|
A0 --> B0
|
||||||
|
}
|
||||||
|
|
||||||
|
C0 --> Apa0
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram
|
||||||
|
direction LR
|
||||||
|
|
||||||
|
|
||||||
|
state C1 {
|
||||||
|
A1 --> B1
|
||||||
|
}
|
||||||
|
|
||||||
|
C1 --> Apa1
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
<h4>Case 2</h4>
|
||||||
|
<div class="flex">
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram
|
||||||
|
direction LR
|
||||||
|
state Gorilla0 {
|
||||||
|
state Apa0 {
|
||||||
|
A0 --> B0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Apa --> Gorilla0:Label
|
||||||
|
A0 --> C0
|
||||||
|
%% C1: "`This is C`"
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram
|
||||||
|
direction LR
|
||||||
|
state Apa1 {
|
||||||
|
A1
|
||||||
|
}
|
||||||
|
|
||||||
|
Apa11 --> Apa1
|
||||||
|
A1 --> C1
|
||||||
|
%% C1: "`This is C`"
|
||||||
|
</pre>
|
||||||
|
<pre id="diagram" class="mermaid2">
|
||||||
|
stateDiagram
|
||||||
|
[*] --> Level1
|
||||||
|
|
||||||
|
state Level1 {
|
||||||
|
[*] --> Level2
|
||||||
|
|
||||||
|
state Level2 {
|
||||||
|
[*] --> level2
|
||||||
|
level2 --> Level3
|
||||||
|
|
||||||
|
state Level3 {
|
||||||
|
[*] --> level3
|
||||||
|
level3 --> [*]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid2">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph Apa["Apa"]
|
subgraph Apa["Apa"]
|
||||||
@@ -127,20 +242,7 @@ Apa --> C
|
|||||||
A --> B & C["C"]
|
A --> B & C["C"]
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid">
|
|
||||||
stateDiagram
|
|
||||||
direction LR
|
|
||||||
state Gorilla0 {
|
|
||||||
state Apa0 {
|
|
||||||
A0 --> B0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Apa0 --> C0
|
|
||||||
A0 --> C0
|
|
||||||
C1: "`This is C`"
|
|
||||||
</pre
|
|
||||||
>
|
|
||||||
<pre id="diagram" class="mermaid2">
|
<pre id="diagram" class="mermaid2">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
subgraph Gorilla
|
subgraph Gorilla
|
||||||
@@ -180,7 +282,7 @@ stateDiagram
|
|||||||
|
|
||||||
</pre
|
</pre
|
||||||
>
|
>
|
||||||
<pre id="diagram" class="mermaid">
|
<pre id="diagram" class="mermaid2">
|
||||||
flowchart LR
|
flowchart LR
|
||||||
Apa --Hello--> C
|
Apa --Hello--> C
|
||||||
|
|
||||||
@@ -318,7 +420,7 @@ stateDiagram-v2
|
|||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
// theme: 'base',
|
// theme: 'base',
|
||||||
// handdrawnSeed: 12,
|
// handdrawnSeed: 12,
|
||||||
// look: 'handdrawn',
|
look: 'handdrawn',
|
||||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||||
// layout: 'dagre',
|
// layout: 'dagre',
|
||||||
// layout: 'elk',
|
// layout: 'elk',
|
||||||
|
@@ -221,41 +221,46 @@ describe('ClassDefs and classes when parsing a State diagram', () => {
|
|||||||
describe('style statement for a state (style)', () => {
|
describe('style statement for a state (style)', () => {
|
||||||
describe('defining (style)', () => {
|
describe('defining (style)', () => {
|
||||||
it('has "style" as a keyword, an id, and can set a css style attribute', function () {
|
it('has "style" as a keyword, an id, and can set a css style attribute', function () {
|
||||||
stateDiagram.parser.parse(`
|
stateDiagram.parser.parse(`stateDiagram-v2
|
||||||
stateDiagram-v2
|
id1
|
||||||
style id1 background:#bbb;`);
|
style id1 background:#bbb`);
|
||||||
|
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
|
||||||
|
const data4Layout = stateDiagram.parser.yy.getData();
|
||||||
|
|
||||||
|
expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']);
|
||||||
|
});
|
||||||
|
it('has "style" as a keyword, an id, and can set a css style attribute', function () {
|
||||||
|
stateDiagram.parser.parse(`stateDiagram-v2
|
||||||
|
id1
|
||||||
|
id2
|
||||||
|
style id1,id2 background:#bbb`);
|
||||||
|
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
|
||||||
|
const data4Layout = stateDiagram.parser.yy.getData();
|
||||||
|
|
||||||
|
expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']);
|
||||||
|
expect(data4Layout.nodes[1].cssStyles).toEqual(['background:#bbb']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can define multiple attributes separated by commas', function () {
|
||||||
|
stateDiagram.parser.parse(`stateDiagram-v2
|
||||||
|
id1
|
||||||
|
id2
|
||||||
|
style id1,id2 background:#bbb, font-weight:bold, font-style:italic;`);
|
||||||
|
|
||||||
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
|
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
|
||||||
|
const data4Layout = stateDiagram.parser.yy.getData();
|
||||||
|
|
||||||
// const styleClasses = stateDb.getClasses();
|
expect(data4Layout.nodes[0].cssStyles).toEqual([
|
||||||
// expect(styleClasses.get('exampleClass').styles.length).toEqual(1);
|
'background:#bbb',
|
||||||
// expect(styleClasses.get('exampleClass').styles[0]).toEqual('background:#bbb');
|
'font-weight:bold',
|
||||||
});
|
'font-style:italic',
|
||||||
|
]);
|
||||||
it('has handles multiple ids', function () {
|
expect(data4Layout.nodes[1].cssStyles).toEqual([
|
||||||
stateDiagram.parser.parse(`
|
'background:#bbb',
|
||||||
stateDiagram-v2
|
'font-weight:bold',
|
||||||
style id1,id2 background:#bbb;`);
|
'font-style:italic',
|
||||||
|
]);
|
||||||
stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
|
});
|
||||||
|
|
||||||
// const styleClasses = stateDb.getClasses();
|
|
||||||
// expect(styleClasses.get('exampleClass').styles.length).toEqual(1);
|
|
||||||
// expect(styleClasses.get('exampleClass').styles[0]).toEqual('background:#bbb');
|
|
||||||
});
|
|
||||||
|
|
||||||
// it('can define multiple attributes separated by commas', function () {
|
|
||||||
// stateDiagram.parser.parse(
|
|
||||||
// 'stateDiagram-v2\n classDef exampleClass background:#bbb, font-weight:bold, font-style:italic;'
|
|
||||||
// );
|
|
||||||
// stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
|
|
||||||
|
|
||||||
// const styleClasses = stateDb.getClasses();
|
|
||||||
// expect(styleClasses.get('exampleClass').styles.length).toEqual(3);
|
|
||||||
// expect(styleClasses.get('exampleClass').styles[0]).toEqual('background:#bbb');
|
|
||||||
// expect(styleClasses.get('exampleClass').styles[1]).toEqual('font-weight:bold');
|
|
||||||
// expect(styleClasses.get('exampleClass').styles[2]).toEqual('font-style:italic');
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -202,13 +202,13 @@ const extract = (_doc) => {
|
|||||||
ids.forEach((id) => {
|
ids.forEach((id) => {
|
||||||
const state = getState(id);
|
const state = getState(id);
|
||||||
if (state !== undefined) {
|
if (state !== undefined) {
|
||||||
state.styles = styles;
|
state.styles = styles.map((s) => s.replace(/;/g, '')?.trim());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STMT_APPLYCLASS:
|
case STMT_APPLYCLASS:
|
||||||
setStyle(item.id.trim(), item.styleClass);
|
setCssClass(item.id.trim(), item.styleClass);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -198,7 +198,16 @@ export const createText = (
|
|||||||
} = {},
|
} = {},
|
||||||
config: MermaidConfig
|
config: MermaidConfig
|
||||||
) => {
|
) => {
|
||||||
log.info('createText', text, style, isTitle, classes, useHtmlLabels, isNode, addSvgBackground);
|
log.info(
|
||||||
|
'IPI createText',
|
||||||
|
text,
|
||||||
|
style,
|
||||||
|
isTitle,
|
||||||
|
classes,
|
||||||
|
useHtmlLabels,
|
||||||
|
isNode,
|
||||||
|
addSvgBackground
|
||||||
|
);
|
||||||
if (useHtmlLabels) {
|
if (useHtmlLabels) {
|
||||||
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
// TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that?
|
||||||
|
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
import { getConfig } from '$root/diagram-api/diagramAPI.js';
|
||||||
import type { Node } from '$root/rendering-util/types.d.ts';
|
import type { Node } from '$root/rendering-util/types.d.ts';
|
||||||
import styles from '../../../../dist/diagrams/packet/styles';
|
|
||||||
|
|
||||||
// Striped fill like start or fork nodes in state diagrams
|
// Striped fill like start or fork nodes in state diagrams
|
||||||
export const solidStateFill = (color: string) => {
|
export const solidStateFill = (color: string) => {
|
||||||
@@ -22,31 +21,33 @@ export const compileStyles = (node: Node) => {
|
|||||||
// node.cssStyles is an array of styles directly set on the node
|
// node.cssStyles is an array of styles directly set on the node
|
||||||
|
|
||||||
// concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates
|
// concat the arrays and remove duplicates such that the values from node.cssStyles are used if there are duplicates
|
||||||
return [...(node.cssCompiledStyles || []), ...(node.cssStyles || [])];
|
const stylesMap = styles2Map([...(node.cssCompiledStyles || []), ...(node.cssStyles || [])]);
|
||||||
|
return { stylesMap, stylesArray: [...stylesMap] };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const styles2Map = (styles: string[]) => {
|
export const styles2Map = (styles: string[]) => {
|
||||||
const styleMap = new Map();
|
const styleMap = new Map<string, string>();
|
||||||
styles.forEach((style) => {
|
styles.forEach((style) => {
|
||||||
const [key, value] = style.split(':');
|
const [key, value] = style.split(':');
|
||||||
styleMap.set(key.trim(), value.trim());
|
styleMap.set(key.trim(), value?.trim());
|
||||||
});
|
});
|
||||||
return styleMap;
|
return styleMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const styles2String = (node: Node) => {
|
export const styles2String = (node: Node) => {
|
||||||
const styles = compileStyles(node);
|
const { stylesArray } = compileStyles(node);
|
||||||
const labelStyles: string[] = [];
|
const labelStyles: string[] = [];
|
||||||
const nodeStyles: string[] = [];
|
const nodeStyles: string[] = [];
|
||||||
|
|
||||||
styles.forEach((style) => {
|
stylesArray.forEach((style) => {
|
||||||
const [key, value] = style.split(':');
|
const key = style[0];
|
||||||
if (key === 'color') {
|
if (key === 'color') {
|
||||||
labelStyles.push(style);
|
labelStyles.push(style.join(':') + ' !important');
|
||||||
} else {
|
} else {
|
||||||
nodeStyles.push(style);
|
nodeStyles.push(style.join(':') + ' !important');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return { labelStyles: labelStyles.join(';'), nodeStyles: nodeStyles.join(';') };
|
return { labelStyles: labelStyles.join(';'), nodeStyles: nodeStyles.join(';') };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,18 +56,16 @@ export const styles2String = (node: Node) => {
|
|||||||
export const userNodeOverrides = (node: Node, options: any) => {
|
export const userNodeOverrides = (node: Node, options: any) => {
|
||||||
const { themeVariables, handdrawnSeed } = getConfig();
|
const { themeVariables, handdrawnSeed } = getConfig();
|
||||||
const { nodeBorder, mainBkg } = themeVariables;
|
const { nodeBorder, mainBkg } = themeVariables;
|
||||||
const styles = compileStyles(node);
|
const { stylesArray: styles, stylesMap } = compileStyles(node);
|
||||||
|
|
||||||
// index the style array to a map object
|
// index the style array to a map object
|
||||||
const styleMap = styles2Map(styles);
|
|
||||||
|
|
||||||
const result = Object.assign(
|
const result = Object.assign(
|
||||||
{
|
{
|
||||||
roughness: 0.7,
|
roughness: 0.7,
|
||||||
fill: styleMap.get('fill') || mainBkg,
|
fill: stylesMap.get('fill') || mainBkg,
|
||||||
fillStyle: 'hachure', // solid fill
|
fillStyle: 'hachure', // solid fill
|
||||||
fillWeight: 3.5,
|
fillWeight: 3.5,
|
||||||
stroke: styleMap.get('stroke') || nodeBorder,
|
stroke: stylesMap.get('stroke') || nodeBorder,
|
||||||
seed: handdrawnSeed,
|
seed: handdrawnSeed,
|
||||||
strokeWidth: 1.3,
|
strokeWidth: 1.3,
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user