@cyoda/workflow-viewer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +26 -0
- package/dist/index.cjs +941 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +57 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +913 -0
- package/dist/index.js.map +1 -0
- package/dist/theme/index.cjs +213 -0
- package/dist/theme/index.cjs.map +1 -0
- package/dist/theme/index.d.cts +176 -0
- package/dist/theme/index.d.ts +176 -0
- package/dist/theme/index.js +178 -0
- package/dist/theme/index.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { StateNode, TransitionEdge, TransitionSummary } from '@cyoda/workflow-graph';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Design tokens for the Cyoda workflow viewer.
|
|
5
|
+
*
|
|
6
|
+
* Palette values match the existing Cyoda Launchpad workflow diagram at
|
|
7
|
+
* `cyoda-launchpad/src/lib/workflow-diagram/cyoda/CyodaWorkflowDiagram.tsx`.
|
|
8
|
+
* Changes here should be coordinated with that renderer so the website and
|
|
9
|
+
* editor remain visually identical.
|
|
10
|
+
*/
|
|
11
|
+
interface RolePaletteEntry {
|
|
12
|
+
fill: string;
|
|
13
|
+
border: string;
|
|
14
|
+
meta: string;
|
|
15
|
+
title: string;
|
|
16
|
+
}
|
|
17
|
+
interface TerminalPaletteEntry extends RolePaletteEntry {
|
|
18
|
+
innerRing: string;
|
|
19
|
+
}
|
|
20
|
+
interface NodePalette {
|
|
21
|
+
default: RolePaletteEntry;
|
|
22
|
+
initial: RolePaletteEntry;
|
|
23
|
+
terminal: TerminalPaletteEntry;
|
|
24
|
+
manualReview: RolePaletteEntry;
|
|
25
|
+
processing: RolePaletteEntry;
|
|
26
|
+
}
|
|
27
|
+
interface EdgePalette {
|
|
28
|
+
automated: string;
|
|
29
|
+
manual: string;
|
|
30
|
+
conditional: string;
|
|
31
|
+
processing: string;
|
|
32
|
+
terminal: string;
|
|
33
|
+
loop: string;
|
|
34
|
+
disabled: string;
|
|
35
|
+
arrowhead: string;
|
|
36
|
+
}
|
|
37
|
+
interface BadgePaletteEntry {
|
|
38
|
+
fill: string;
|
|
39
|
+
border: string;
|
|
40
|
+
}
|
|
41
|
+
interface BadgePalette {
|
|
42
|
+
manual: BadgePaletteEntry;
|
|
43
|
+
processor: BadgePaletteEntry;
|
|
44
|
+
criterion: BadgePaletteEntry;
|
|
45
|
+
disabled: BadgePaletteEntry;
|
|
46
|
+
text: string;
|
|
47
|
+
}
|
|
48
|
+
interface EdgeLabelPalette {
|
|
49
|
+
fill: string;
|
|
50
|
+
border: string;
|
|
51
|
+
text: string;
|
|
52
|
+
}
|
|
53
|
+
interface NeutralPalette {
|
|
54
|
+
white: string;
|
|
55
|
+
white95: string;
|
|
56
|
+
white75: string;
|
|
57
|
+
slate200: string;
|
|
58
|
+
slate300: string;
|
|
59
|
+
slate500: string;
|
|
60
|
+
slate600: string;
|
|
61
|
+
slate900: string;
|
|
62
|
+
}
|
|
63
|
+
interface WorkflowPalette {
|
|
64
|
+
neutrals: NeutralPalette;
|
|
65
|
+
node: NodePalette;
|
|
66
|
+
edge: EdgePalette;
|
|
67
|
+
edgeLabel: EdgeLabelPalette;
|
|
68
|
+
badge: BadgePalette;
|
|
69
|
+
}
|
|
70
|
+
declare const workflowPalette: WorkflowPalette;
|
|
71
|
+
declare const typography: {
|
|
72
|
+
fontFamily: string;
|
|
73
|
+
monoFamily: string;
|
|
74
|
+
stateCategory: {
|
|
75
|
+
size: number;
|
|
76
|
+
weight: number;
|
|
77
|
+
tracking: string;
|
|
78
|
+
};
|
|
79
|
+
stateTitle: {
|
|
80
|
+
size: number;
|
|
81
|
+
weight: number;
|
|
82
|
+
tracking: string;
|
|
83
|
+
};
|
|
84
|
+
edgeLabel: {
|
|
85
|
+
size: number;
|
|
86
|
+
weight: number;
|
|
87
|
+
tracking: string;
|
|
88
|
+
};
|
|
89
|
+
badge: {
|
|
90
|
+
size: number;
|
|
91
|
+
weight: number;
|
|
92
|
+
tracking: string;
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
declare const geometry: {
|
|
96
|
+
node: {
|
|
97
|
+
width: number;
|
|
98
|
+
height: number;
|
|
99
|
+
radius: number;
|
|
100
|
+
strokeWidth: number;
|
|
101
|
+
terminalInset: number;
|
|
102
|
+
terminalInnerRadius: number;
|
|
103
|
+
};
|
|
104
|
+
edge: {
|
|
105
|
+
strokeWidth: number;
|
|
106
|
+
loopStrokeWidth: number;
|
|
107
|
+
arrowheadSize: number;
|
|
108
|
+
};
|
|
109
|
+
labelPill: {
|
|
110
|
+
paddingX: number;
|
|
111
|
+
paddingY: number;
|
|
112
|
+
radius: number;
|
|
113
|
+
shadowOpacity: number;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Category label shown in the small uppercase header line above the state
|
|
119
|
+
* title. Derived from projection data (role + visual category).
|
|
120
|
+
*
|
|
121
|
+
* Reused by the editor shell so the website viewer and editor canvas display
|
|
122
|
+
* identical headers.
|
|
123
|
+
*/
|
|
124
|
+
declare function roleCategoryLabel(node: StateNode): string;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Select the edge stroke color ("lane") for a transition edge.
|
|
128
|
+
*
|
|
129
|
+
* Order of precedence (mirrors the Launchpad renderer):
|
|
130
|
+
* 1. Disabled transitions → disabled lane.
|
|
131
|
+
* 2. Loopback (self or back-edge) → loop lane.
|
|
132
|
+
* 3. Target is a terminal state → terminal lane (set by caller via
|
|
133
|
+
* `targetIsTerminal` since the edge itself doesn't know).
|
|
134
|
+
* 4. Processor-bearing transition → processing lane.
|
|
135
|
+
* 5. Manual transition → manual lane.
|
|
136
|
+
* 6. Has a criterion (non-group) → conditional lane.
|
|
137
|
+
* 7. Default → automated lane.
|
|
138
|
+
*/
|
|
139
|
+
declare function laneColor(edge: TransitionEdge, opts: {
|
|
140
|
+
targetIsTerminal: boolean;
|
|
141
|
+
}): string;
|
|
142
|
+
/**
|
|
143
|
+
* Whether the stroke should be rendered dashed (spec §24: dashed-vs-solid
|
|
144
|
+
* carries meaning, colour alone never does).
|
|
145
|
+
*/
|
|
146
|
+
declare function laneIsDashed(edge: TransitionEdge): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* SVG `strokeDasharray` value for an edge.
|
|
149
|
+
* - Disabled: tight "3 2" — visually reads as "greyed out / inactive".
|
|
150
|
+
* - Loopback (non-disabled): "6 4" — looser, still dashed.
|
|
151
|
+
* - Otherwise: undefined (solid).
|
|
152
|
+
*/
|
|
153
|
+
declare function laneDashArray(edge: TransitionEdge): string | undefined;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Select the palette entry for a state node.
|
|
157
|
+
* initial-terminal prefers terminal styling (with initial accent applied
|
|
158
|
+
* separately by the renderer — e.g. a secondary border ring).
|
|
159
|
+
*/
|
|
160
|
+
declare function paletteFor(node: StateNode): RolePaletteEntry | TerminalPaletteEntry;
|
|
161
|
+
|
|
162
|
+
interface BadgeDescriptor {
|
|
163
|
+
key: "manual" | "processor" | "criterion" | "disabled" | "execution";
|
|
164
|
+
label: string;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Translate a transition summary + flags into the ordered list of badges the
|
|
168
|
+
* edge chip should render. Mirrors §10 chip summaries + the visual design
|
|
169
|
+
* section of the implementation plan.
|
|
170
|
+
*/
|
|
171
|
+
declare function badgesFor(summary: TransitionSummary, flags: {
|
|
172
|
+
manual: boolean;
|
|
173
|
+
disabled: boolean;
|
|
174
|
+
}): BadgeDescriptor[];
|
|
175
|
+
|
|
176
|
+
export { type BadgeDescriptor, type BadgePalette, type BadgePaletteEntry, type EdgeLabelPalette, type EdgePalette, type NeutralPalette, type NodePalette, type RolePaletteEntry, type TerminalPaletteEntry, type WorkflowPalette, badgesFor, geometry, laneColor, laneDashArray, laneIsDashed, paletteFor, roleCategoryLabel, typography, workflowPalette };
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// src/theme/tokens.ts
|
|
2
|
+
var workflowPalette = {
|
|
3
|
+
neutrals: {
|
|
4
|
+
white: "#FFFFFF",
|
|
5
|
+
white95: "#FFFFFFF2",
|
|
6
|
+
white75: "#FFFFFFBF",
|
|
7
|
+
slate200: "#E2E8F0",
|
|
8
|
+
slate300: "#CBD5E1",
|
|
9
|
+
slate500: "#64748B",
|
|
10
|
+
slate600: "#475569",
|
|
11
|
+
slate900: "#0F172A"
|
|
12
|
+
},
|
|
13
|
+
node: {
|
|
14
|
+
default: {
|
|
15
|
+
fill: "#F0FDFA",
|
|
16
|
+
border: "#2DD4BF",
|
|
17
|
+
meta: "#0F766E",
|
|
18
|
+
title: "#0F172A"
|
|
19
|
+
},
|
|
20
|
+
initial: {
|
|
21
|
+
fill: "#D1FAE5",
|
|
22
|
+
border: "#059669",
|
|
23
|
+
meta: "#047857",
|
|
24
|
+
title: "#022C22"
|
|
25
|
+
},
|
|
26
|
+
terminal: {
|
|
27
|
+
fill: "#FFF1F2",
|
|
28
|
+
border: "#FDA4AF",
|
|
29
|
+
meta: "#BE123C",
|
|
30
|
+
title: "#4C0519",
|
|
31
|
+
innerRing: "#FFFFFFBF"
|
|
32
|
+
},
|
|
33
|
+
manualReview: {
|
|
34
|
+
fill: "#F5F3FF",
|
|
35
|
+
border: "#C4B5FD",
|
|
36
|
+
meta: "#6D28D9",
|
|
37
|
+
title: "#2E1065"
|
|
38
|
+
},
|
|
39
|
+
processing: {
|
|
40
|
+
fill: "#F0F9FF",
|
|
41
|
+
border: "#7DD3FC",
|
|
42
|
+
meta: "#0369A1",
|
|
43
|
+
title: "#082F49"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
edge: {
|
|
47
|
+
automated: "#64748B",
|
|
48
|
+
manual: "#8B5CF6",
|
|
49
|
+
conditional: "#F59E0B",
|
|
50
|
+
processing: "#0EA5E9",
|
|
51
|
+
terminal: "#FB7185",
|
|
52
|
+
loop: "#14B8A6",
|
|
53
|
+
disabled: "#CBD5E1",
|
|
54
|
+
arrowhead: "#64748B"
|
|
55
|
+
},
|
|
56
|
+
edgeLabel: {
|
|
57
|
+
fill: "#FFFFFFF2",
|
|
58
|
+
border: "#E2E8F0",
|
|
59
|
+
text: "#475569"
|
|
60
|
+
},
|
|
61
|
+
badge: {
|
|
62
|
+
manual: { fill: "#F5F3FF", border: "#DDD6FE" },
|
|
63
|
+
processor: { fill: "#F0F9FF", border: "#BAE6FD" },
|
|
64
|
+
criterion: { fill: "#FFFBEB", border: "#FDE68A" },
|
|
65
|
+
disabled: { fill: "#F8FAFC", border: "#E2E8F0" },
|
|
66
|
+
text: "#475569"
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
var typography = {
|
|
70
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", system-ui, sans-serif',
|
|
71
|
+
monoFamily: 'ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace',
|
|
72
|
+
stateCategory: { size: 10, weight: 700, tracking: "0.12em" },
|
|
73
|
+
stateTitle: { size: 14, weight: 700, tracking: "0.01em" },
|
|
74
|
+
edgeLabel: { size: 9, weight: 700, tracking: "0.04em" },
|
|
75
|
+
badge: { size: 8, weight: 600, tracking: "0.04em" }
|
|
76
|
+
};
|
|
77
|
+
var geometry = {
|
|
78
|
+
node: {
|
|
79
|
+
width: 144,
|
|
80
|
+
height: 72,
|
|
81
|
+
radius: 8,
|
|
82
|
+
strokeWidth: 1.5,
|
|
83
|
+
terminalInset: 3,
|
|
84
|
+
terminalInnerRadius: 6
|
|
85
|
+
},
|
|
86
|
+
edge: {
|
|
87
|
+
strokeWidth: 1.8,
|
|
88
|
+
loopStrokeWidth: 1.6,
|
|
89
|
+
arrowheadSize: 6
|
|
90
|
+
},
|
|
91
|
+
labelPill: {
|
|
92
|
+
paddingX: 6,
|
|
93
|
+
paddingY: 3,
|
|
94
|
+
radius: 6,
|
|
95
|
+
shadowOpacity: 0.08
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// src/theme/role-label.ts
|
|
100
|
+
function roleCategoryLabel(node) {
|
|
101
|
+
if (node.role === "initial" || node.role === "initial-terminal") return "INITIAL";
|
|
102
|
+
if (node.role === "terminal") return "TERMINAL";
|
|
103
|
+
if (node.category === "MANUAL_REVIEW") return "MANUAL REVIEW";
|
|
104
|
+
if (node.category === "PROCESSING_STATE") return "PROCESSING STATE";
|
|
105
|
+
return "STATE";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/theme/lane.ts
|
|
109
|
+
function laneColor(edge, opts) {
|
|
110
|
+
const e = workflowPalette.edge;
|
|
111
|
+
if (edge.disabled) return e.disabled;
|
|
112
|
+
if (edge.isLoopback) return e.loop;
|
|
113
|
+
if (opts.targetIsTerminal) return e.terminal;
|
|
114
|
+
if (edge.summary.processor && edge.summary.processor.kind !== "none") {
|
|
115
|
+
return e.processing;
|
|
116
|
+
}
|
|
117
|
+
if (edge.manual) return e.manual;
|
|
118
|
+
if (edge.summary.criterion) return e.conditional;
|
|
119
|
+
return e.automated;
|
|
120
|
+
}
|
|
121
|
+
function laneIsDashed(edge) {
|
|
122
|
+
return edge.disabled || edge.isLoopback;
|
|
123
|
+
}
|
|
124
|
+
function laneDashArray(edge) {
|
|
125
|
+
if (edge.disabled) return "3 2";
|
|
126
|
+
if (edge.isLoopback) return "6 4";
|
|
127
|
+
return void 0;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/theme/node-palette.ts
|
|
131
|
+
function paletteFor(node) {
|
|
132
|
+
const p = workflowPalette.node;
|
|
133
|
+
if (node.role === "terminal" || node.role === "initial-terminal") return p.terminal;
|
|
134
|
+
if (node.role === "initial") return p.initial;
|
|
135
|
+
if (node.category === "MANUAL_REVIEW") return p.manualReview;
|
|
136
|
+
if (node.category === "PROCESSING_STATE") return p.processing;
|
|
137
|
+
return p.default;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/theme/badges.ts
|
|
141
|
+
function badgesFor(summary, flags) {
|
|
142
|
+
const out = [];
|
|
143
|
+
if (flags.manual) out.push({ key: "manual", label: "Manual" });
|
|
144
|
+
if (summary.processor) {
|
|
145
|
+
if (summary.processor.kind === "single") {
|
|
146
|
+
out.push({ key: "processor", label: summary.processor.name });
|
|
147
|
+
} else if (summary.processor.kind === "multiple") {
|
|
148
|
+
out.push({ key: "processor", label: `${summary.processor.count} processors` });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (summary.criterion) {
|
|
152
|
+
const c = summary.criterion;
|
|
153
|
+
if (c.kind === "group") {
|
|
154
|
+
out.push({ key: "criterion", label: `${c.operator} \xB7 ${c.count}` });
|
|
155
|
+
} else {
|
|
156
|
+
out.push({ key: "criterion", label: "Criterion" });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (summary.execution?.kind === "sync") {
|
|
160
|
+
out.push({ key: "execution", label: "SYNC" });
|
|
161
|
+
} else if (summary.execution?.kind === "asyncSameTx") {
|
|
162
|
+
out.push({ key: "execution", label: "ASYNC_SAME_TX" });
|
|
163
|
+
}
|
|
164
|
+
if (flags.disabled) out.push({ key: "disabled", label: "Disabled" });
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
export {
|
|
168
|
+
badgesFor,
|
|
169
|
+
geometry,
|
|
170
|
+
laneColor,
|
|
171
|
+
laneDashArray,
|
|
172
|
+
laneIsDashed,
|
|
173
|
+
paletteFor,
|
|
174
|
+
roleCategoryLabel,
|
|
175
|
+
typography,
|
|
176
|
+
workflowPalette
|
|
177
|
+
};
|
|
178
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/theme/tokens.ts","../../src/theme/role-label.ts","../../src/theme/lane.ts","../../src/theme/node-palette.ts","../../src/theme/badges.ts"],"sourcesContent":["/**\n * Design tokens for the Cyoda workflow viewer.\n *\n * Palette values match the existing Cyoda Launchpad workflow diagram at\n * `cyoda-launchpad/src/lib/workflow-diagram/cyoda/CyodaWorkflowDiagram.tsx`.\n * Changes here should be coordinated with that renderer so the website and\n * editor remain visually identical.\n */\n\nexport interface RolePaletteEntry {\n fill: string;\n border: string;\n meta: string;\n title: string;\n}\n\nexport interface TerminalPaletteEntry extends RolePaletteEntry {\n innerRing: string;\n}\n\nexport interface NodePalette {\n default: RolePaletteEntry;\n initial: RolePaletteEntry;\n terminal: TerminalPaletteEntry;\n manualReview: RolePaletteEntry;\n processing: RolePaletteEntry;\n}\n\nexport interface EdgePalette {\n automated: string;\n manual: string;\n conditional: string;\n processing: string;\n terminal: string;\n loop: string;\n disabled: string;\n arrowhead: string;\n}\n\nexport interface BadgePaletteEntry {\n fill: string;\n border: string;\n}\n\nexport interface BadgePalette {\n manual: BadgePaletteEntry;\n processor: BadgePaletteEntry;\n criterion: BadgePaletteEntry;\n disabled: BadgePaletteEntry;\n text: string;\n}\n\nexport interface EdgeLabelPalette {\n fill: string;\n border: string;\n text: string;\n}\n\nexport interface NeutralPalette {\n white: string;\n white95: string;\n white75: string;\n slate200: string;\n slate300: string;\n slate500: string;\n slate600: string;\n slate900: string;\n}\n\nexport interface WorkflowPalette {\n neutrals: NeutralPalette;\n node: NodePalette;\n edge: EdgePalette;\n edgeLabel: EdgeLabelPalette;\n badge: BadgePalette;\n}\n\nexport const workflowPalette: WorkflowPalette = {\n neutrals: {\n white: \"#FFFFFF\",\n white95: \"#FFFFFFF2\",\n white75: \"#FFFFFFBF\",\n slate200: \"#E2E8F0\",\n slate300: \"#CBD5E1\",\n slate500: \"#64748B\",\n slate600: \"#475569\",\n slate900: \"#0F172A\",\n },\n node: {\n default: {\n fill: \"#F0FDFA\",\n border: \"#2DD4BF\",\n meta: \"#0F766E\",\n title: \"#0F172A\",\n },\n initial: {\n fill: \"#D1FAE5\",\n border: \"#059669\",\n meta: \"#047857\",\n title: \"#022C22\",\n },\n terminal: {\n fill: \"#FFF1F2\",\n border: \"#FDA4AF\",\n meta: \"#BE123C\",\n title: \"#4C0519\",\n innerRing: \"#FFFFFFBF\",\n },\n manualReview: {\n fill: \"#F5F3FF\",\n border: \"#C4B5FD\",\n meta: \"#6D28D9\",\n title: \"#2E1065\",\n },\n processing: {\n fill: \"#F0F9FF\",\n border: \"#7DD3FC\",\n meta: \"#0369A1\",\n title: \"#082F49\",\n },\n },\n edge: {\n automated: \"#64748B\",\n manual: \"#8B5CF6\",\n conditional: \"#F59E0B\",\n processing: \"#0EA5E9\",\n terminal: \"#FB7185\",\n loop: \"#14B8A6\",\n disabled: \"#CBD5E1\",\n arrowhead: \"#64748B\",\n },\n edgeLabel: {\n fill: \"#FFFFFFF2\",\n border: \"#E2E8F0\",\n text: \"#475569\",\n },\n badge: {\n manual: { fill: \"#F5F3FF\", border: \"#DDD6FE\" },\n processor: { fill: \"#F0F9FF\", border: \"#BAE6FD\" },\n criterion: { fill: \"#FFFBEB\", border: \"#FDE68A\" },\n disabled: { fill: \"#F8FAFC\", border: \"#E2E8F0\" },\n text: \"#475569\",\n },\n};\n\nexport const typography = {\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Inter\", system-ui, sans-serif',\n monoFamily: 'ui-monospace, \"SF Mono\", \"Cascadia Code\", Menlo, monospace',\n stateCategory: { size: 10, weight: 700, tracking: \"0.12em\" },\n stateTitle: { size: 14, weight: 700, tracking: \"0.01em\" },\n edgeLabel: { size: 9, weight: 700, tracking: \"0.04em\" },\n badge: { size: 8, weight: 600, tracking: \"0.04em\" },\n};\n\nexport const geometry = {\n node: {\n width: 144,\n height: 72,\n radius: 8,\n strokeWidth: 1.5,\n terminalInset: 3,\n terminalInnerRadius: 6,\n },\n edge: {\n strokeWidth: 1.8,\n loopStrokeWidth: 1.6,\n arrowheadSize: 6,\n },\n labelPill: {\n paddingX: 6,\n paddingY: 3,\n radius: 6,\n shadowOpacity: 0.08,\n },\n};\n","import type { StateNode } from \"@cyoda/workflow-graph\";\n\n/**\n * Category label shown in the small uppercase header line above the state\n * title. Derived from projection data (role + visual category).\n *\n * Reused by the editor shell so the website viewer and editor canvas display\n * identical headers.\n */\nexport function roleCategoryLabel(node: StateNode): string {\n if (node.role === \"initial\" || node.role === \"initial-terminal\") return \"INITIAL\";\n if (node.role === \"terminal\") return \"TERMINAL\";\n if (node.category === \"MANUAL_REVIEW\") return \"MANUAL REVIEW\";\n if (node.category === \"PROCESSING_STATE\") return \"PROCESSING STATE\";\n return \"STATE\";\n}\n","import type { TransitionEdge } from \"@cyoda/workflow-graph\";\nimport { workflowPalette } from \"./tokens.js\";\n\n/**\n * Select the edge stroke color (\"lane\") for a transition edge.\n *\n * Order of precedence (mirrors the Launchpad renderer):\n * 1. Disabled transitions → disabled lane.\n * 2. Loopback (self or back-edge) → loop lane.\n * 3. Target is a terminal state → terminal lane (set by caller via\n * `targetIsTerminal` since the edge itself doesn't know).\n * 4. Processor-bearing transition → processing lane.\n * 5. Manual transition → manual lane.\n * 6. Has a criterion (non-group) → conditional lane.\n * 7. Default → automated lane.\n */\nexport function laneColor(\n edge: TransitionEdge,\n opts: { targetIsTerminal: boolean },\n): string {\n const e = workflowPalette.edge;\n if (edge.disabled) return e.disabled;\n if (edge.isLoopback) return e.loop;\n if (opts.targetIsTerminal) return e.terminal;\n if (edge.summary.processor && edge.summary.processor.kind !== \"none\") {\n return e.processing;\n }\n if (edge.manual) return e.manual;\n if (edge.summary.criterion) return e.conditional;\n return e.automated;\n}\n\n/**\n * Whether the stroke should be rendered dashed (spec §24: dashed-vs-solid\n * carries meaning, colour alone never does).\n */\nexport function laneIsDashed(edge: TransitionEdge): boolean {\n return edge.disabled || edge.isLoopback;\n}\n\n/**\n * SVG `strokeDasharray` value for an edge.\n * - Disabled: tight \"3 2\" — visually reads as \"greyed out / inactive\".\n * - Loopback (non-disabled): \"6 4\" — looser, still dashed.\n * - Otherwise: undefined (solid).\n */\nexport function laneDashArray(edge: TransitionEdge): string | undefined {\n if (edge.disabled) return \"3 2\";\n if (edge.isLoopback) return \"6 4\";\n return undefined;\n}\n","import type { StateNode } from \"@cyoda/workflow-graph\";\nimport { workflowPalette, type RolePaletteEntry, type TerminalPaletteEntry } from \"./tokens.js\";\n\n/**\n * Select the palette entry for a state node.\n * initial-terminal prefers terminal styling (with initial accent applied\n * separately by the renderer — e.g. a secondary border ring).\n */\nexport function paletteFor(\n node: StateNode,\n): RolePaletteEntry | TerminalPaletteEntry {\n const p = workflowPalette.node;\n if (node.role === \"terminal\" || node.role === \"initial-terminal\") return p.terminal;\n if (node.role === \"initial\") return p.initial;\n if (node.category === \"MANUAL_REVIEW\") return p.manualReview;\n if (node.category === \"PROCESSING_STATE\") return p.processing;\n return p.default;\n}\n","import type { TransitionSummary } from \"@cyoda/workflow-graph\";\n\nexport interface BadgeDescriptor {\n key: \"manual\" | \"processor\" | \"criterion\" | \"disabled\" | \"execution\";\n label: string;\n}\n\n/**\n * Translate a transition summary + flags into the ordered list of badges the\n * edge chip should render. Mirrors §10 chip summaries + the visual design\n * section of the implementation plan.\n */\nexport function badgesFor(\n summary: TransitionSummary,\n flags: { manual: boolean; disabled: boolean },\n): BadgeDescriptor[] {\n const out: BadgeDescriptor[] = [];\n\n if (flags.manual) out.push({ key: \"manual\", label: \"Manual\" });\n\n if (summary.processor) {\n if (summary.processor.kind === \"single\") {\n out.push({ key: \"processor\", label: summary.processor.name });\n } else if (summary.processor.kind === \"multiple\") {\n out.push({ key: \"processor\", label: `${summary.processor.count} processors` });\n }\n }\n\n if (summary.criterion) {\n const c = summary.criterion;\n if (c.kind === \"group\") {\n out.push({ key: \"criterion\", label: `${c.operator} · ${c.count}` });\n } else {\n out.push({ key: \"criterion\", label: \"Criterion\" });\n }\n }\n\n if (summary.execution?.kind === \"sync\") {\n out.push({ key: \"execution\", label: \"SYNC\" });\n } else if (summary.execution?.kind === \"asyncSameTx\") {\n out.push({ key: \"execution\", label: \"ASYNC_SAME_TX\" });\n }\n\n if (flags.disabled) out.push({ key: \"disabled\", label: \"Disabled\" });\n\n return out;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cyoda/workflow-viewer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Slim read-only SVG renderer for Cyoda workflows.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/Cyoda-platform/cyoda-workflow-editor.git",
|
|
14
|
+
"directory": "packages/workflow-viewer"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/Cyoda-platform/cyoda-workflow-editor#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/Cyoda-platform/cyoda-workflow-editor/issues"
|
|
19
|
+
},
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.cjs"
|
|
25
|
+
},
|
|
26
|
+
"./theme": {
|
|
27
|
+
"types": "./dist/theme/index.d.ts",
|
|
28
|
+
"import": "./dist/theme/index.js",
|
|
29
|
+
"require": "./dist/theme/index.cjs"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist",
|
|
34
|
+
"README.md",
|
|
35
|
+
"LICENSE"
|
|
36
|
+
],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public",
|
|
39
|
+
"provenance": true
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@cyoda/workflow-core": "0.1.0",
|
|
43
|
+
"@cyoda/workflow-graph": "0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"react": "^18.3.1",
|
|
47
|
+
"react-dom": "^18.3.1"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@testing-library/react": "^14.2.0",
|
|
51
|
+
"@types/react": "^18.2.66",
|
|
52
|
+
"@types/react-dom": "^18.2.22",
|
|
53
|
+
"jsdom": "^24.0.0",
|
|
54
|
+
"react": "^18.3.1",
|
|
55
|
+
"react-dom": "^18.3.1"
|
|
56
|
+
},
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup",
|
|
59
|
+
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"test:watch": "vitest"
|
|
62
|
+
}
|
|
63
|
+
}
|