Upstream mermaid-js/mermaid state of the touched files before f69fecf786
This commit is contained in:
commit
1312d198a1
1 file changed
+298
@@ -0,0 +1,298 @@
|
|||||||
|
// import khroma from 'khroma';
|
||||||
|
import * as khroma from 'khroma';
|
||||||
|
import { getIconStyles } from '../globalStyles.js';
|
||||||
|
import { colorSlotCount, hasPalette, isColorTheme, safeLook } from '../common/colorThemeGate.js';
|
||||||
|
|
||||||
|
/** Returns the styles given options */
|
||||||
|
export interface FlowChartStyleOptions {
|
||||||
|
arrowheadColor: string;
|
||||||
|
border2: string;
|
||||||
|
clusterBkg: string;
|
||||||
|
clusterBorder: string;
|
||||||
|
edgeLabelBackground: string;
|
||||||
|
fontFamily: string;
|
||||||
|
lineColor: string;
|
||||||
|
mainBkg: string;
|
||||||
|
nodeBorder: string;
|
||||||
|
nodeTextColor: string;
|
||||||
|
tertiaryColor: string;
|
||||||
|
textColor: string;
|
||||||
|
titleColor: string;
|
||||||
|
strokeWidth: string;
|
||||||
|
theme?: string;
|
||||||
|
look?: string;
|
||||||
|
THEME_COLOR_LIMIT?: number;
|
||||||
|
borderColorArray?: string[];
|
||||||
|
bkgColorArray?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cycling per-subgraph colour. Only the containers are painted -- the nodes inside keep
|
||||||
|
* the uniform look, because a flowchart node is a step in a flow rather than a distinct
|
||||||
|
* participant, and node colour is already how `classDef` / `style` carry meaning.
|
||||||
|
*
|
||||||
|
* Emits both the `rect` (classic/neo) and `path` (handDrawn) forms since the container is
|
||||||
|
* a plain rect in one look and a roughjs path pair in the other. `.collapsed-group` is
|
||||||
|
* the same container drawn as a compact node by `collapsedGroup.ts` — it is a container,
|
||||||
|
* not one of the flow's steps, so it takes the palette too; without it a collapsed
|
||||||
|
* subgraph rendered uncoloured beside tinted siblings.
|
||||||
|
*
|
||||||
|
* Not `!important`: `clusters.js` and `collapsedGroup.ts` both put user styles in an
|
||||||
|
* inline `style` attribute, which has to keep winning over the theme palette. The
|
||||||
|
* collapsed form's own colours are presentation attributes (`fill=` / `stroke=`), which
|
||||||
|
* these rules correctly outrank while still losing to that inline style.
|
||||||
|
*
|
||||||
|
* Lanes are excluded by `:not(.swimlane)` and ruled separately below: a lane is two
|
||||||
|
* rectangles, and the generic `path` rule would paint the hachure roughjs emits for its
|
||||||
|
* unfilled body. Here, not in `swimlanes/styles.ts`, so `layout: swimlane` is covered too.
|
||||||
|
*/
|
||||||
|
const genColor = (options: FlowChartStyleOptions) => {
|
||||||
|
const { theme, bkgColorArray, borderColorArray } = options;
|
||||||
|
if (!isColorTheme(theme, borderColorArray)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const look = safeLook(options.look);
|
||||||
|
const hasBkgColors = hasPalette(bkgColorArray);
|
||||||
|
let sections = '';
|
||||||
|
|
||||||
|
for (let i = 0; i < colorSlotCount(options.THEME_COLOR_LIMIT, borderColorArray); i++) {
|
||||||
|
const borderColor = borderColorArray![i % borderColorArray!.length];
|
||||||
|
const fill = hasBkgColors ? `fill: ${bkgColorArray[i % bkgColorArray.length]};` : '';
|
||||||
|
const slot = `[data-look="${look}"][data-color-id="color-${i}"]`;
|
||||||
|
/* A collapsed subgraph is drawn by `collapsedGroup.ts` through `getNodeClasses`, which
|
||||||
|
* returns `rough-node` instead of `node` for the handDrawn look -- so a `.node`-only
|
||||||
|
* selector leaves handDrawn collapsed containers uncoloured beside their tinted
|
||||||
|
* siblings. Clusters are unaffected: `clusters.js` sets the `cluster` class directly.
|
||||||
|
*
|
||||||
|
* Each descendant has to be appended to *both* prefixes separately. Writing
|
||||||
|
* `${slot}.node, ${slot}.rough-node .thing` would attach the descendant to the last
|
||||||
|
* item of the list only, silently matching nothing under the classic look.
|
||||||
|
*/
|
||||||
|
const collapsedRule = (suffix: string) =>
|
||||||
|
`${slot}.node ${suffix}, ${slot}.rough-node ${suffix}`;
|
||||||
|
/* Both halves of a lane. Each carries the whole prefix separately, as above. */
|
||||||
|
const laneRule = (suffix: string) =>
|
||||||
|
`${slot}.swimlane.cluster .swimlane-title${suffix}, ${slot}.swimlane.cluster .swimlane-body${suffix}`;
|
||||||
|
sections += `
|
||||||
|
|
||||||
|
${slot}.cluster:not(.swimlane) rect {
|
||||||
|
stroke: ${borderColor};
|
||||||
|
${fill}
|
||||||
|
}
|
||||||
|
|
||||||
|
${slot}.cluster:not(.swimlane) path {
|
||||||
|
stroke: ${borderColor};
|
||||||
|
${fill}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lane, classic and neo. */
|
||||||
|
${slot}.swimlane.cluster rect.swimlane-title,
|
||||||
|
${slot}.swimlane.cluster rect.swimlane-body {
|
||||||
|
stroke: ${borderColor};
|
||||||
|
${fill}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lane, handDrawn: roughjs emits the hachure fill first, then the outline. */
|
||||||
|
${laneRule(' path:nth-of-type(2)')} {
|
||||||
|
stroke: ${borderColor};
|
||||||
|
}
|
||||||
|
${
|
||||||
|
hasBkgColors
|
||||||
|
? `
|
||||||
|
/* A roughjs fill is drawn as lines, so the lane fill is a stroke here. */
|
||||||
|
${laneRule(' path:first-of-type')} {
|
||||||
|
stroke: ${bkgColorArray[i % bkgColorArray.length]};
|
||||||
|
}
|
||||||
|
`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
${collapsedRule('.collapsed-group')},
|
||||||
|
${collapsedRule('.collapsed-group path')} {
|
||||||
|
stroke: ${borderColor};
|
||||||
|
${fill}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The ellipsis dots and the separator take clusterBorder further down, so without
|
||||||
|
these the container is palette-coloured while its own markers are not. */
|
||||||
|
${collapsedRule('.collapsed-indicator')} {
|
||||||
|
fill: ${borderColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
${collapsedRule('.collapsed-separator')} {
|
||||||
|
stroke: ${borderColor};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return sections;
|
||||||
|
};
|
||||||
|
|
||||||
|
const fade = (color: string, opacity: number) => {
|
||||||
|
// @ts-ignore TODO: incorrect types from khroma
|
||||||
|
const channel = khroma.channel;
|
||||||
|
|
||||||
|
const r = channel(color, 'r');
|
||||||
|
const g = channel(color, 'g');
|
||||||
|
const b = channel(color, 'b');
|
||||||
|
|
||||||
|
// @ts-ignore incorrect types from khroma
|
||||||
|
return khroma.rgba(r, g, b, opacity);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStyles = (options: FlowChartStyleOptions) =>
|
||||||
|
`${genColor(options)}
|
||||||
|
.label {
|
||||||
|
font-family: ${options.fontFamily};
|
||||||
|
color: ${options.nodeTextColor || options.textColor};
|
||||||
|
}
|
||||||
|
.cluster-label text {
|
||||||
|
fill: ${options.titleColor};
|
||||||
|
}
|
||||||
|
.cluster-label span {
|
||||||
|
color: ${options.titleColor};
|
||||||
|
}
|
||||||
|
.cluster-label span p {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label text,span {
|
||||||
|
fill: ${options.nodeTextColor || options.textColor};
|
||||||
|
color: ${options.nodeTextColor || options.textColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
.node rect,
|
||||||
|
.node circle,
|
||||||
|
.node ellipse,
|
||||||
|
.node polygon,
|
||||||
|
.node path {
|
||||||
|
fill: ${options.mainBkg};
|
||||||
|
stroke: ${options.nodeBorder};
|
||||||
|
stroke-width: ${options.strokeWidth ?? 1}px;
|
||||||
|
}
|
||||||
|
.rough-node .label text , .node .label text, .image-shape .label, .icon-shape .label {
|
||||||
|
text-anchor: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node .katex path {
|
||||||
|
fill: #000;
|
||||||
|
stroke: #000;
|
||||||
|
stroke-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rough-node .label,.node .label, .image-shape .label, .icon-shape .label {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.node.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.root .anchor path {
|
||||||
|
fill: ${options.lineColor} !important;
|
||||||
|
stroke-width: 0;
|
||||||
|
stroke: ${options.lineColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowheadPath {
|
||||||
|
fill: ${options.arrowheadColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
.edgePaths .path {
|
||||||
|
stroke: ${options.lineColor};
|
||||||
|
stroke-width: ${options.strokeWidth ?? 2}px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flowchart-link {
|
||||||
|
stroke: ${options.lineColor};
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edgeLabel {
|
||||||
|
background-color: ${options.edgeLabelBackground};
|
||||||
|
p {
|
||||||
|
background-color: ${options.edgeLabelBackground};
|
||||||
|
}
|
||||||
|
rect {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: ${options.edgeLabelBackground};
|
||||||
|
fill: ${options.edgeLabelBackground};
|
||||||
|
}
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For html labels only */
|
||||||
|
.labelBkg {
|
||||||
|
background-color: ${fade(options.edgeLabelBackground, 0.5)};
|
||||||
|
// background-color:
|
||||||
|
}
|
||||||
|
|
||||||
|
.cluster rect {
|
||||||
|
fill: ${options.clusterBkg};
|
||||||
|
stroke: ${options.clusterBorder};
|
||||||
|
stroke-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cluster text {
|
||||||
|
fill: ${options.titleColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
.cluster span {
|
||||||
|
color: ${options.titleColor};
|
||||||
|
}
|
||||||
|
/* .cluster div {
|
||||||
|
color: ${options.titleColor};
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* Collapsed subgraph node (@{ view: collapsed }) */
|
||||||
|
.node .collapsed-indicator {
|
||||||
|
fill: ${options.clusterBorder};
|
||||||
|
stroke: none;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.node .collapsed-separator {
|
||||||
|
stroke: ${options.clusterBorder};
|
||||||
|
stroke-width: 0.75px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.mermaidTooltip {
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
max-width: 200px;
|
||||||
|
padding: 2px;
|
||||||
|
font-family: ${options.fontFamily};
|
||||||
|
font-size: 12px;
|
||||||
|
background: ${options.tertiaryColor};
|
||||||
|
border: 1px solid ${options.border2};
|
||||||
|
border-radius: 2px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flowchartTitleText {
|
||||||
|
text-anchor: middle;
|
||||||
|
font-size: 18px;
|
||||||
|
fill: ${options.textColor};
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.text {
|
||||||
|
fill: none;
|
||||||
|
stroke-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shape, .image-shape {
|
||||||
|
background-color: ${options.edgeLabelBackground};
|
||||||
|
p {
|
||||||
|
background-color: ${options.edgeLabelBackground};
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
.label rect {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: ${options.edgeLabelBackground};
|
||||||
|
fill: ${options.edgeLabelBackground};
|
||||||
|
}
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
${getIconStyles()}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default getStyles;
|
||||||
Reference in new issue
Block a user