#5237 making styles take preceedence and adding test

This commit is contained in:
Knut Sveidqvist
2024-06-18 11:15:59 +02:00
parent a6f3316ddb
commit 83f2663f68
7 changed files with 203 additions and 64 deletions

View File

@@ -110,6 +110,7 @@ strikethrough
stringifying stringifying
struct struct
STYLECLASS STYLECLASS
STYLEDEF
STYLEOPTS STYLEOPTS
subcomponent subcomponent
subcomponents subcomponents

View File

@@ -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(

View File

@@ -75,12 +75,127 @@
</style> </style>
</head> </head>
<body> <body>
<pre id="diagram" class="mermaid"> <h4>Case 1</h4>
flowchart LR <div class="flex">
<pre id="diagram" class="mermaid">
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',

View File

@@ -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()); stateDiagram.parser.yy.extract(stateDiagram.parser.yy.getRootDocV2());
const data4Layout = stateDiagram.parser.yy.getData();
// const styleClasses = stateDb.getClasses(); expect(data4Layout.nodes[0].cssStyles).toEqual(['background:#bbb']);
// expect(styleClasses.get('exampleClass').styles.length).toEqual(1); });
// expect(styleClasses.get('exampleClass').styles[0]).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('has handles multiple ids', function () { it('can define multiple attributes separated by commas', function () {
stateDiagram.parser.parse(` stateDiagram.parser.parse(`stateDiagram-v2
stateDiagram-v2 id1
style id1,id2 background:#bbb;`); 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',
]);
expect(data4Layout.nodes[1].cssStyles).toEqual([
'background:#bbb',
'font-weight:bold',
'font-style:italic',
]);
}); });
// 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');
// });
}); });
}); });
}); });

View File

@@ -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;
} }
}); });

View File

@@ -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?

View File

@@ -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,
}, },