@cyoda/workflow-viewer 0.1.0 → 0.2.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/README.md +60 -9
- package/dist/index.cjs +146 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -6
- package/dist/index.d.ts +27 -6
- package/dist/index.js +147 -64
- package/dist/index.js.map +1 -1
- package/dist/theme/index.cjs +3 -10
- package/dist/theme/index.cjs.map +1 -1
- package/dist/theme/index.d.cts +1 -2
- package/dist/theme/index.d.ts +1 -2
- package/dist/theme/index.js +3 -10
- package/dist/theme/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/WorkflowViewer.tsx","../src/theme/tokens.ts","../src/layout.ts","../src/hooks/usePanZoom.ts","../src/theme/lane.ts","../src/components/EdgePath.tsx","../src/components/Defs.tsx","../src/components/StartMarker.tsx","../src/theme/role-label.ts","../src/theme/node-palette.ts","../src/theme/badges.ts","../src/components/StateNode.tsx","../src/components/EdgeLabel.tsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport type {\n GraphDocument,\n GraphEdge,\n GraphNode,\n StateNode,\n TransitionEdge,\n} from \"@cyoda/workflow-graph\";\nimport { simpleLayout, type LayoutResult, type NodePosition } from \"../layout.js\";\nimport { usePanZoom } from \"../hooks/usePanZoom.js\";\nimport { Defs } from \"./Defs.js\";\nimport { StartMarker } from \"./StartMarker.js\";\nimport { StateNodeView } from \"./StateNode.js\";\nimport { EdgePath, computeEdgeGeometry } from \"./EdgePath.js\";\nimport { EdgeLabel } from \"./EdgeLabel.js\";\nimport { workflowPalette } from \"../theme/tokens.js\";\n\nexport interface WorkflowViewerProps {\n graph: GraphDocument;\n /** Optional pre-computed layout (e.g. from @cyoda/workflow-layout). */\n layout?: LayoutResult;\n width?: number | string;\n height?: number | string;\n selectedId?: string;\n onSelectionChange?: (id: string | null) => void;\n className?: string;\n}\n\n/**\n * Slim read-only SVG renderer. Renders workflow state nodes, transitions,\n * and edge-label chips using the theme tokens. No editing affordances.\n */\nexport function WorkflowViewer({\n graph,\n layout,\n width = \"100%\",\n height = \"100%\",\n selectedId,\n onSelectionChange,\n className,\n}: WorkflowViewerProps) {\n const effectiveLayout = useMemo(\n () => layout ?? simpleLayout(graph),\n [graph, layout],\n );\n const pan = usePanZoom();\n const [internalSelection, setInternalSelection] = useState<string | null>(null);\n const [hovered, setHovered] = useState<string | null>(null);\n const selection = selectedId ?? internalSelection;\n\n const stateNodes = useMemo(\n () => graph.nodes.filter((n): n is StateNode => n.kind === \"state\"),\n [graph.nodes],\n );\n const stateById = useMemo(() => {\n const m = new Map<string, StateNode>();\n for (const n of stateNodes) m.set(n.id, n);\n return m;\n }, [stateNodes]);\n\n const transitionEdges = useMemo(\n () => graph.edges.filter((e): e is TransitionEdge => e.kind === \"transition\"),\n [graph.edges],\n );\n\n const highlightSet = useMemo(\n () => computeHighlightSet(hovered ?? selection, graph.nodes, graph.edges),\n [hovered, selection, graph.nodes, graph.edges],\n );\n\n const anythingFocused = highlightSet !== null;\n\n const handleSelect = (id: string) => {\n setInternalSelection(id);\n onSelectionChange?.(id);\n };\n\n const handleBackgroundClick = () => {\n setInternalSelection(null);\n onSelectionChange?.(null);\n };\n\n return (\n <svg\n width={width}\n height={height}\n viewBox={`0 0 ${effectiveLayout.width} ${effectiveLayout.height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n onClick={handleBackgroundClick}\n onWheel={pan.onWheel}\n onMouseDown={pan.onMouseDown}\n onMouseMove={pan.onMouseMove}\n onMouseUp={pan.onMouseUp}\n onMouseLeave={pan.onMouseUp}\n className={className}\n style={{\n background: workflowPalette.neutrals.white,\n fontFamily: \"inherit\",\n userSelect: \"none\",\n }}\n data-testid=\"workflow-viewer\"\n >\n <Defs />\n <g\n transform={`translate(${pan.transform.x}, ${pan.transform.y}) scale(${pan.transform.scale})`}\n >\n {/* Edges first so they render behind nodes. */}\n {transitionEdges.map((edge) => {\n const source = effectiveLayout.positions.get(edge.sourceId);\n const target = effectiveLayout.positions.get(edge.targetId);\n if (!source || !target) return null;\n const targetNode = stateById.get(edge.targetId);\n const route = effectiveLayout.edges?.get(edge.id);\n const isEdgeSelected = selection === edge.id;\n const isHighlighted = highlightSet?.has(edge.id) ?? false;\n const isDimmed = anythingFocused && !isHighlighted;\n return (\n <EdgePath\n key={edge.id}\n edge={edge}\n source={source}\n target={target}\n route={route}\n targetIsTerminal={\n targetNode?.role === \"terminal\" ||\n targetNode?.role === \"initial-terminal\"\n }\n highlighted={isHighlighted}\n dimmed={isDimmed}\n selected={isEdgeSelected}\n onSelect={handleSelect}\n onHoverEnter={setHovered}\n onHoverLeave={() => setHovered(null)}\n />\n );\n })}\n\n {/* Edge labels on top of edges. */}\n {transitionEdges.map((edge) => {\n const source = effectiveLayout.positions.get(edge.sourceId);\n const target = effectiveLayout.positions.get(edge.targetId);\n if (!source || !target) return null;\n const route = effectiveLayout.edges?.get(edge.id);\n const labelPos = route\n ? { midX: route.labelX, midY: route.labelY }\n : computeEdgeGeometry(edge, source, target);\n const isHighlighted = highlightSet?.has(edge.id) ?? false;\n const isDimmed = anythingFocused && !isHighlighted;\n return (\n <EdgeLabel\n key={`label-${edge.id}`}\n edge={edge}\n x={labelPos.midX}\n y={labelPos.midY}\n width={route?.labelWidth}\n height={route?.labelHeight}\n dimmed={isDimmed}\n />\n );\n })}\n\n {/* Nodes on top. */}\n {graph.nodes.map((node) => renderNode(node, effectiveLayout, {\n selection,\n highlightSet,\n anythingFocused,\n onSelect: handleSelect,\n onHoverEnter: setHovered,\n onHoverLeave: () => setHovered(null),\n }))}\n </g>\n </svg>\n );\n}\n\ninterface RenderCtx {\n selection: string | null;\n highlightSet: Set<string> | null;\n anythingFocused: boolean;\n onSelect: (id: string) => void;\n onHoverEnter: (id: string) => void;\n onHoverLeave: () => void;\n}\n\nfunction renderNode(\n node: GraphNode,\n layout: LayoutResult,\n ctx: RenderCtx,\n) {\n const pos = layout.positions.get(node.id);\n if (!pos) return null;\n if (node.kind === \"startMarker\") {\n return <StartMarker key={node.id} position={smallPositionForMarker(pos)} />;\n }\n const isHighlighted = ctx.highlightSet?.has(node.id) ?? false;\n const isDimmed = ctx.anythingFocused && !isHighlighted;\n return (\n <StateNodeView\n key={node.id}\n node={node}\n position={pos}\n selected={ctx.selection === node.id}\n highlighted={isHighlighted}\n dimmed={isDimmed}\n onSelect={ctx.onSelect}\n onHoverEnter={ctx.onHoverEnter}\n onHoverLeave={ctx.onHoverLeave}\n />\n );\n}\n\nfunction smallPositionForMarker(pos: NodePosition): NodePosition {\n // Shrink the marker to a small badge centred at the node slot.\n const size = 16;\n return {\n id: pos.id,\n x: pos.x + pos.width / 2 - size / 2,\n y: pos.y + pos.height / 2 - size / 2,\n width: size,\n height: size,\n };\n}\n\n/**\n * Compute the set of node/edge IDs to highlight when `focusedId` is hovered\n * or selected. Returns `null` when nothing is focused (all nodes+edges shown\n * at full opacity).\n */\nfunction computeHighlightSet(\n focusedId: string | null,\n nodes: GraphNode[],\n edges: GraphEdge[],\n): Set<string> | null {\n if (!focusedId) return null;\n\n const set = new Set<string>();\n set.add(focusedId);\n\n const node = nodes.find((n) => n.id === focusedId);\n if (node) {\n for (const e of edges) {\n if (e.kind !== \"transition\") continue;\n if (e.sourceId === focusedId || e.targetId === focusedId) {\n set.add(e.id);\n set.add(e.sourceId);\n set.add(e.targetId);\n }\n }\n return set;\n }\n\n const edge = edges.find((e) => e.id === focusedId);\n if (edge && edge.kind === \"transition\") {\n set.add(edge.sourceId);\n set.add(edge.targetId);\n }\n return set;\n}\n","/**\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 { GraphDocument, GraphNode } from \"@cyoda/workflow-graph\";\nimport { geometry } from \"./theme/tokens.js\";\n\nexport interface NodePosition {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface EdgeWaypoint {\n x: number;\n y: number;\n}\n\nexport interface EdgeRoute {\n id: string;\n /** Full polyline from source attach point to target attach point. */\n points: EdgeWaypoint[];\n labelX: number;\n labelY: number;\n labelWidth?: number;\n labelHeight?: number;\n}\n\nexport interface LayoutResult {\n positions: Map<string, NodePosition>;\n /** Optional pre-computed polyline routes (e.g. from ELK). */\n edges?: Map<string, EdgeRoute>;\n width: number;\n height: number;\n}\n\n/**\n * Simple deterministic fallback layout used by the viewer when no ELK-computed\n * layout is provided. Groups nodes by workflow and arranges each workflow's\n * states in a BFS-layered top-to-bottom flow.\n *\n * The editor and the website both prefer ELK output (Phase 4). This layout is\n * a dependency-free default so the viewer package can render in isolation.\n */\nexport function simpleLayout(graph: GraphDocument): LayoutResult {\n const { width: nodeW, height: nodeH } = geometry.node;\n const hGap = 48;\n const vGap = 48;\n\n const positions = new Map<string, NodePosition>();\n const nodesByWorkflow = groupByWorkflow(graph.nodes);\n\n let yCursor = 24;\n let maxWidth = 0;\n\n for (const wfNodes of nodesByWorkflow.values()) {\n const layers = layerByBFS(wfNodes, graph);\n let y = yCursor;\n for (const layer of layers) {\n const layerWidth = layer.length * nodeW + (layer.length - 1) * hGap;\n maxWidth = Math.max(maxWidth, layerWidth + 48);\n let x = Math.max(24, (maxWidth - layerWidth) / 2);\n for (const node of layer) {\n positions.set(node.id, { id: node.id, x, y, width: nodeW, height: nodeH });\n x += nodeW + hGap;\n }\n y += nodeH + vGap;\n }\n yCursor = y + vGap;\n }\n\n return { positions, width: maxWidth + 24, height: yCursor };\n}\n\nfunction groupByWorkflow(nodes: GraphNode[]): Map<string, GraphNode[]> {\n const out = new Map<string, GraphNode[]>();\n for (const n of nodes) {\n const wf = \"workflow\" in n ? n.workflow : \"\";\n const list = out.get(wf) ?? [];\n list.push(n);\n out.set(wf, list);\n }\n return out;\n}\n\nfunction layerByBFS(nodes: GraphNode[], graph: GraphDocument): GraphNode[][] {\n const stateNodes: GraphNode[] = nodes.filter((n) => n.kind === \"state\");\n const markers: GraphNode[] = nodes.filter((n) => n.kind === \"startMarker\");\n if (stateNodes.length === 0) return markers.length > 0 ? [markers] : [];\n\n // Build adjacency from transition edges (skip loopbacks for layering).\n const adj = new Map<string, Set<string>>();\n const indeg = new Map<string, number>();\n for (const n of stateNodes) {\n adj.set(n.id, new Set());\n indeg.set(n.id, 0);\n }\n for (const e of graph.edges) {\n if (e.kind !== \"transition\" || e.isLoopback) continue;\n if (!adj.has(e.sourceId) || !adj.has(e.targetId)) continue;\n const set = adj.get(e.sourceId)!;\n if (!set.has(e.targetId)) {\n set.add(e.targetId);\n indeg.set(e.targetId, (indeg.get(e.targetId) ?? 0) + 1);\n }\n }\n\n const layers: GraphNode[][] = [];\n if (markers.length > 0) layers.push(markers);\n\n // Topological layering: sources first, then successors.\n const byId = new Map(stateNodes.map((n) => [n.id, n] as const));\n let frontier = stateNodes.filter((n) => (indeg.get(n.id) ?? 0) === 0);\n const placed = new Set<string>();\n while (frontier.length > 0) {\n layers.push(frontier);\n const next: GraphNode[] = [];\n for (const n of frontier) {\n placed.add(n.id);\n for (const succ of adj.get(n.id) ?? []) {\n const remaining = (indeg.get(succ) ?? 0) - 1;\n indeg.set(succ, remaining);\n if (remaining === 0 && !placed.has(succ)) {\n const node = byId.get(succ);\n if (node) next.push(node);\n }\n }\n }\n frontier = next;\n }\n\n // Any unplaced (cycle participants not reachable via in-degree-0) — drop\n // into a trailing layer so they still render.\n const remaining = stateNodes.filter((n) => !placed.has(n.id));\n if (remaining.length > 0) layers.push(remaining);\n return layers;\n}\n","import { useCallback, useRef, useState } from \"react\";\n\nexport interface ViewportTransform {\n x: number;\n y: number;\n scale: number;\n}\n\nexport interface PanZoomHandlers {\n transform: ViewportTransform;\n onWheel: (e: React.WheelEvent<SVGSVGElement>) => void;\n onMouseDown: (e: React.MouseEvent<SVGSVGElement>) => void;\n onMouseMove: (e: React.MouseEvent<SVGSVGElement>) => void;\n onMouseUp: (e: React.MouseEvent<SVGSVGElement>) => void;\n reset: () => void;\n setTransform: (t: ViewportTransform) => void;\n}\n\nconst MIN_SCALE = 0.25;\nconst MAX_SCALE = 4;\nconst ZOOM_STEP = 1.1;\n\n/**\n * Minimal pan + zoom state for a single SVG `<g>` transform. No inertia, no\n * trackpad-gesture normalisation — deferred to when we adopt react-zoom-pan\n * or a similar library.\n */\nexport function usePanZoom(initial?: Partial<ViewportTransform>): PanZoomHandlers {\n const [transform, setTransform] = useState<ViewportTransform>({\n x: initial?.x ?? 0,\n y: initial?.y ?? 0,\n scale: initial?.scale ?? 1,\n });\n const dragStart = useRef<{ x: number; y: number; vx: number; vy: number } | null>(null);\n\n const onWheel = useCallback((e: React.WheelEvent<SVGSVGElement>) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n const delta = e.deltaY > 0 ? 1 / ZOOM_STEP : ZOOM_STEP;\n setTransform((t) => {\n const nextScale = clamp(t.scale * delta, MIN_SCALE, MAX_SCALE);\n const ratio = nextScale / t.scale;\n const rect = (e.currentTarget as SVGSVGElement).getBoundingClientRect();\n const px = e.clientX - rect.left;\n const py = e.clientY - rect.top;\n return {\n scale: nextScale,\n x: px - (px - t.x) * ratio,\n y: py - (py - t.y) * ratio,\n };\n });\n }, []);\n\n const onMouseDown = useCallback((e: React.MouseEvent<SVGSVGElement>) => {\n if (e.button !== 0) return;\n dragStart.current = { x: e.clientX, y: e.clientY, vx: transform.x, vy: transform.y };\n }, [transform.x, transform.y]);\n\n const onMouseMove = useCallback((e: React.MouseEvent<SVGSVGElement>) => {\n if (!dragStart.current) return;\n const dx = e.clientX - dragStart.current.x;\n const dy = e.clientY - dragStart.current.y;\n setTransform((t) => ({ ...t, x: dragStart.current!.vx + dx, y: dragStart.current!.vy + dy }));\n }, []);\n\n const onMouseUp = useCallback(() => {\n dragStart.current = null;\n }, []);\n\n const reset = useCallback(() => {\n setTransform({ x: 0, y: 0, scale: 1 });\n }, []);\n\n return { transform, onWheel, onMouseDown, onMouseMove, onMouseUp, reset, setTransform };\n}\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n));\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 { TransitionEdge } from \"@cyoda/workflow-graph\";\nimport { laneColor, laneDashArray } from \"../theme/lane.js\";\nimport { geometry, workflowPalette } from \"../theme/tokens.js\";\nimport type { EdgeRoute, NodePosition } from \"../layout.js\";\n\ninterface Props {\n edge: TransitionEdge;\n source: NodePosition;\n target: NodePosition;\n /** Pre-computed polyline from the layout engine (ELK). Overrides center-to-center heuristic. */\n route?: EdgeRoute;\n targetIsTerminal: boolean;\n highlighted: boolean;\n dimmed: boolean;\n selected: boolean;\n onSelect: (id: string) => void;\n onHoverEnter: (id: string) => void;\n onHoverLeave: () => void;\n}\n\nexport interface EdgeGeometry {\n d: string;\n midX: number;\n midY: number;\n}\n\n/**\n * Convert a polyline to an SVG path `d` string.\n */\nexport function polylineToPath(points: { x: number; y: number }[]): string {\n if (points.length === 0) return \"\";\n const [first, ...rest] = points;\n let d = `M ${first!.x} ${first!.y}`;\n for (const p of rest) d += ` L ${p.x} ${p.y}`;\n return d;\n}\n\n/**\n * Compute a simple orthogonal-ish path between two node centres. Self-loops\n * are rendered as a right-side arc; parallel siblings are offset laterally\n * based on parallelIndex to avoid overlap.\n */\nexport function computeEdgeGeometry(\n edge: TransitionEdge,\n source: NodePosition,\n target: NodePosition,\n): EdgeGeometry {\n const sx = source.x + source.width / 2;\n const sy = source.y + source.height / 2;\n const tx = target.x + target.width / 2;\n const ty = target.y + target.height / 2;\n\n if (edge.isSelf) {\n const rightX = source.x + source.width;\n const topY = source.y + source.height / 3;\n const bottomY = source.y + (source.height * 2) / 3;\n const loopX = rightX + 28;\n const d = `M ${rightX} ${topY} C ${loopX} ${topY}, ${loopX} ${bottomY}, ${rightX} ${bottomY}`;\n return { d, midX: loopX, midY: (topY + bottomY) / 2 };\n }\n\n // Lateral offset for parallel edges: stagger by parallelIndex around the\n // midpoint. 0 → centred, 1 → +offset, 2 → -offset, etc.\n const offsetStep = 18;\n const half = Math.floor(edge.parallelGroupSize / 2);\n const signed = edge.parallelIndex - half;\n const offset = signed * offsetStep;\n\n const mx = (sx + tx) / 2 + offset;\n const my = (sy + ty) / 2;\n\n // Simple cubic curve so parallel siblings don't overlap.\n const d = `M ${sx} ${sy} Q ${mx} ${my}, ${tx} ${ty}`;\n return { d, midX: mx, midY: my };\n}\n\nexport function EdgePath({\n edge,\n source,\n target,\n route,\n targetIsTerminal,\n highlighted,\n dimmed,\n selected,\n onSelect,\n onHoverEnter,\n onHoverLeave,\n}: Props) {\n const color = laneColor(edge, { targetIsTerminal });\n const dash = laneDashArray(edge);\n const d =\n route && route.points.length >= 2\n ? polylineToPath(route.points)\n : computeEdgeGeometry(edge, source, target).d;\n\n const strokeWidth =\n selected || highlighted\n ? geometry.edge.strokeWidth + 0.8\n : edge.isLoopback\n ? geometry.edge.loopStrokeWidth\n : geometry.edge.strokeWidth;\n const opacity = dimmed ? 0.25 : 1;\n // Manual transitions get a thin ghost stroke on top of the main stroke —\n // strengthens the manual-vs-auto visual cue without changing semantics.\n const isManualSolid = edge.manual && !edge.disabled && !edge.isLoopback;\n\n return (\n <g\n opacity={opacity}\n onClick={(e) => {\n e.stopPropagation();\n onSelect(edge.id);\n }}\n onMouseEnter={() => onHoverEnter(edge.id)}\n onMouseLeave={onHoverLeave}\n style={{ cursor: \"pointer\" }}\n data-testid={`edge-${edge.id}`}\n >\n {/* Transparent fat stroke to widen the hit-area. */}\n <path d={d} fill=\"none\" stroke=\"transparent\" strokeWidth={12} />\n <path\n d={d}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeDasharray={dash}\n markerEnd={`url(#wf-arrow-${colorKey(color)})`}\n />\n {isManualSolid && (\n <path\n d={d}\n fill=\"none\"\n stroke={workflowPalette.neutrals.white}\n strokeWidth={0.6}\n pointerEvents=\"none\"\n />\n )}\n </g>\n );\n}\n\n/**\n * Lane colours keyed so we can reuse one marker per lane. Must be a valid\n * fragment identifier.\n */\nexport function colorKey(color: string): string {\n return color.replace(\"#\", \"\").toLowerCase();\n}\n\n/**\n * The set of lane colours we need arrowhead markers for. Emitted once per\n * SVG instance from `WorkflowViewer`.\n */\nexport const laneColorSet: string[] = Object.values(workflowPalette.edge);\n","import { geometry, workflowPalette } from \"../theme/tokens.js\";\nimport { colorKey, laneColorSet } from \"./EdgePath.js\";\n\n/**\n * Shared SVG `<defs>` — arrowhead markers (one per lane colour) and the two\n * drop-shadow filters used by nodes and label chips.\n */\nexport function Defs() {\n const size = geometry.edge.arrowheadSize;\n // Sharper 2:1 triangle: width (tip-to-base) = 2*size, base thickness = size,\n // so the base runs vertically from (0, size/2) to (0, 3*size/2) and the tip\n // sits at (2*size, size). refX is pushed close to the tip so the arrow kisses\n // the node edge, not floats away from it.\n const unique = Array.from(new Set(laneColorSet));\n return (\n <defs>\n {unique.map((color) => (\n <marker\n key={color}\n id={`wf-arrow-${colorKey(color)}`}\n viewBox={`0 0 ${size * 2} ${size * 2}`}\n refX={size * 1.85}\n refY={size}\n markerWidth={size}\n markerHeight={size}\n orient=\"auto-start-reverse\"\n >\n <path\n d={`M 0 ${size / 2} L ${size * 2} ${size} L 0 ${size * 1.5} z`}\n fill={color}\n />\n </marker>\n ))}\n <filter id=\"wf-node-shadow\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"140%\">\n <feDropShadow\n dx={0}\n dy={2}\n stdDeviation={2}\n floodColor={workflowPalette.neutrals.slate900}\n floodOpacity={0.08}\n />\n </filter>\n <filter\n id=\"wf-node-shadow-strong\"\n x=\"-10%\"\n y=\"-10%\"\n width=\"120%\"\n height=\"140%\"\n >\n <feDropShadow\n dx={0}\n dy={3}\n stdDeviation={3}\n floodColor={workflowPalette.neutrals.slate900}\n floodOpacity={0.18}\n />\n </filter>\n <filter id=\"wf-label-shadow\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"140%\">\n <feDropShadow\n dx={0}\n dy={1}\n stdDeviation={1.2}\n floodColor={workflowPalette.neutrals.slate900}\n floodOpacity={geometry.labelPill.shadowOpacity}\n />\n </filter>\n </defs>\n );\n}\n","import { workflowPalette } from \"../theme/tokens.js\";\nimport type { NodePosition } from \"../layout.js\";\n\ninterface Props {\n position: NodePosition;\n}\n\n/**\n * Non-interactive start marker node (spec §10.5). Rendered as a small filled\n * circle above the initial state.\n */\nexport function StartMarker({ position }: Props) {\n const cx = position.x + position.width / 2;\n const cy = position.y + position.height / 2;\n const r = Math.min(position.width, position.height) / 3;\n return (\n <g aria-hidden=\"true\">\n <circle\n cx={cx}\n cy={cy}\n r={r}\n fill={workflowPalette.node.initial.border}\n stroke={workflowPalette.node.initial.meta}\n strokeWidth={1.5}\n />\n </g>\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 { 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","import type { StateNode as StateNodeData } from \"@cyoda/workflow-graph\";\nimport { paletteFor, roleCategoryLabel } from \"../theme/index.js\";\nimport { geometry, typography, workflowPalette } from \"../theme/tokens.js\";\nimport type { NodePosition } from \"../layout.js\";\n\ninterface Props {\n node: StateNodeData;\n position: NodePosition;\n selected: boolean;\n highlighted: boolean;\n dimmed: boolean;\n onSelect: (id: string) => void;\n onHoverEnter: (id: string) => void;\n onHoverLeave: () => void;\n}\n\nexport function StateNodeView({\n node,\n position,\n selected,\n highlighted,\n dimmed,\n onSelect,\n onHoverEnter,\n onHoverLeave,\n}: Props) {\n const palette = paletteFor(node);\n const { radius, strokeWidth, terminalInset, terminalInnerRadius } = geometry.node;\n const { width, height } = position;\n const isTerminal = node.role === \"terminal\" || node.role === \"initial-terminal\";\n const isInitialTerminal = node.role === \"initial-terminal\";\n const category = roleCategoryLabel(node);\n\n const opacity = dimmed ? 0.35 : 1;\n const outerStroke = selected\n ? workflowPalette.neutrals.slate900\n : palette.border;\n const outerStrokeWidth = selected ? strokeWidth + 1 : strokeWidth;\n\n return (\n <g\n transform={`translate(${position.x}, ${position.y})`}\n opacity={opacity}\n onClick={(e) => {\n e.stopPropagation();\n onSelect(node.id);\n }}\n onMouseEnter={() => onHoverEnter(node.id)}\n onMouseLeave={onHoverLeave}\n style={{ cursor: \"pointer\" }}\n data-testid={`state-node-${node.stateCode}`}\n aria-label={`${category} ${node.stateCode}`}\n role=\"button\"\n tabIndex={0}\n >\n <rect\n x={0}\n y={0}\n width={width}\n height={height}\n rx={radius}\n ry={radius}\n fill={palette.fill}\n stroke={outerStroke}\n strokeWidth={outerStrokeWidth}\n filter={highlighted || selected ? \"url(#wf-node-shadow-strong)\" : \"url(#wf-node-shadow)\"}\n />\n {isTerminal && (\n <rect\n x={terminalInset}\n y={terminalInset}\n width={width - terminalInset * 2}\n height={height - terminalInset * 2}\n rx={terminalInnerRadius}\n ry={terminalInnerRadius}\n fill=\"none\"\n stroke={\n \"innerRing\" in palette\n ? palette.innerRing\n : workflowPalette.neutrals.white75\n }\n strokeWidth={1}\n />\n )}\n {isInitialTerminal && (\n <rect\n x={terminalInset}\n y={terminalInset}\n width={width - terminalInset * 2}\n height={height - terminalInset * 2}\n rx={terminalInnerRadius}\n ry={terminalInnerRadius}\n fill=\"none\"\n stroke={workflowPalette.node.initial.border}\n strokeWidth={1}\n strokeDasharray=\"3 3\"\n />\n )}\n <text\n x={width / 2}\n y={height / 2 - 8}\n textAnchor=\"middle\"\n fill={palette.meta}\n fontFamily={typography.fontFamily}\n fontSize={typography.stateCategory.size}\n fontWeight={typography.stateCategory.weight}\n letterSpacing={typography.stateCategory.tracking}\n >\n {category}\n </text>\n <text\n x={width / 2}\n y={height / 2 + 12}\n textAnchor=\"middle\"\n fill={palette.title}\n fontFamily={typography.monoFamily}\n fontSize={typography.stateTitle.size}\n fontWeight={typography.stateTitle.weight}\n letterSpacing={typography.stateTitle.tracking}\n >\n {truncate(node.stateCode, 18)}\n </text>\n </g>\n );\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return `${s.slice(0, max - 1)}…`;\n}\n","import type { TransitionEdge } from \"@cyoda/workflow-graph\";\nimport { badgesFor, type BadgeDescriptor } from \"../theme/badges.js\";\nimport { geometry, typography, workflowPalette } from \"../theme/tokens.js\";\n\ninterface Props {\n edge: TransitionEdge;\n x: number;\n y: number;\n width?: number;\n height?: number;\n dimmed: boolean;\n}\n\nconst BADGE_HEIGHT = 14;\nconst BADGE_GAP = 4;\nconst LABEL_PADDING_X = geometry.labelPill.paddingX;\nconst LABEL_PADDING_Y = geometry.labelPill.paddingY;\nconst BADGE_TEXT_PADDING_X = 6;\n\n/**\n * Estimate label width in SVG units. Rough heuristic: avg glyph width ≈\n * fontSize * 0.58 for the sans/mono stack at these sizes. Good enough until\n * we measure via getBBox.\n */\nfunction estimateWidth(text: string, fontSize: number): number {\n return Math.ceil(text.length * fontSize * 0.58);\n}\n\nexport function EdgeLabel({ edge, x, y, width, height, dimmed }: Props) {\n const title = edge.summary.display;\n const badges = badgesFor(edge.summary, {\n manual: edge.manual,\n disabled: edge.disabled,\n });\n\n const titleW = estimateWidth(title, typography.edgeLabel.size);\n\n const badgeWidths = badges.map(\n (b) => estimateWidth(b.label, typography.badge.size) + BADGE_TEXT_PADDING_X * 2,\n );\n const badgesTotalW =\n badgeWidths.reduce((a, b) => a + b, 0) +\n Math.max(0, badges.length - 1) * BADGE_GAP;\n\n const pillW = width ?? Math.max(titleW, badgesTotalW) + LABEL_PADDING_X * 2;\n const hasBadges = badges.length > 0;\n const pillH = height ??\n typography.edgeLabel.size +\n LABEL_PADDING_Y * 2 +\n (hasBadges ? BADGE_HEIGHT + BADGE_GAP : 0);\n\n const pillX = x - pillW / 2;\n const pillY = y - pillH / 2;\n const titleY = pillY + LABEL_PADDING_Y + typography.edgeLabel.size - 2;\n const badgeY = titleY + BADGE_GAP + 2;\n\n const opacity = dimmed ? 0.4 : 1;\n\n return (\n <g opacity={opacity} pointerEvents=\"none\">\n <rect\n x={pillX}\n y={pillY}\n width={pillW}\n height={pillH}\n rx={geometry.labelPill.radius}\n ry={geometry.labelPill.radius}\n fill={workflowPalette.edgeLabel.fill}\n stroke={workflowPalette.edgeLabel.border}\n strokeWidth={1}\n filter=\"url(#wf-label-shadow)\"\n />\n <text\n x={x}\n y={titleY}\n textAnchor=\"middle\"\n fill={workflowPalette.edgeLabel.text}\n fontFamily={typography.fontFamily}\n fontSize={typography.edgeLabel.size}\n fontWeight={typography.edgeLabel.weight}\n letterSpacing={typography.edgeLabel.tracking}\n >\n {title}\n </text>\n {hasBadges && renderBadges(badges, badgeWidths, pillX, pillW, badgeY)}\n </g>\n );\n}\n\nfunction renderBadges(\n badges: BadgeDescriptor[],\n widths: number[],\n pillX: number,\n pillW: number,\n y: number,\n) {\n const totalW =\n widths.reduce((a, b) => a + b, 0) +\n Math.max(0, badges.length - 1) * BADGE_GAP;\n let cursor = pillX + (pillW - totalW) / 2;\n return (\n <g>\n {badges.map((b, i) => {\n const w = widths[i]!;\n const slot = pickBadgePalette(b.key);\n const node = (\n <g key={`${b.key}-${i}`}>\n <rect\n x={cursor}\n y={y}\n width={w}\n height={BADGE_HEIGHT}\n rx={BADGE_HEIGHT / 2}\n ry={BADGE_HEIGHT / 2}\n fill={slot.fill}\n stroke={slot.border}\n strokeWidth={1}\n />\n <text\n x={cursor + w / 2}\n y={y + BADGE_HEIGHT - 4}\n textAnchor=\"middle\"\n fill={workflowPalette.badge.text}\n fontFamily={typography.fontFamily}\n fontSize={typography.badge.size}\n fontWeight={typography.badge.weight}\n letterSpacing={typography.badge.tracking}\n >\n {b.label}\n </text>\n </g>\n );\n cursor += w + BADGE_GAP;\n return node;\n })}\n </g>\n );\n}\n\nfunction pickBadgePalette(key: BadgeDescriptor[\"key\"]) {\n switch (key) {\n case \"manual\":\n return workflowPalette.badge.manual;\n case \"processor\":\n return workflowPalette.badge.processor;\n case \"criterion\":\n return workflowPalette.badge.criterion;\n case \"execution\":\n return workflowPalette.badge.processor;\n case \"disabled\":\n return workflowPalette.badge.disabled;\n }\n}\n"],"mappings":"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","names":["useState","remaining","d","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/WorkflowViewer.tsx","../src/theme/tokens.ts","../src/layout.ts","../src/hooks/usePanZoom.ts","../src/theme/lane.ts","../src/components/EdgePath.tsx","../src/components/Defs.tsx","../src/components/StartMarker.tsx","../src/theme/role-label.ts","../src/theme/node-palette.ts","../src/theme/badges.ts","../src/components/StateNode.tsx","../src/components/EdgeLabel.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport type { WorkflowEditorDocument } from \"@cyoda/workflow-core\";\nimport type {\n GraphDocument,\n GraphNode,\n StateNode,\n TransitionEdge,\n WorkflowInspection,\n} from \"@cyoda/workflow-graph\";\nimport { computeHighlightSet, inspectGraphFocus, projectToGraph } from \"@cyoda/workflow-graph\";\nimport { simpleLayout, nudgeLabels, type LayoutResult, type NodePosition } from \"../layout.js\";\nimport { usePanZoom } from \"../hooks/usePanZoom.js\";\nimport { Defs } from \"./Defs.js\";\nimport { StartMarker } from \"./StartMarker.js\";\nimport { StateNodeView } from \"./StateNode.js\";\nimport { EdgePath, computeEdgeGeometry } from \"./EdgePath.js\";\nimport { EdgeLabel } from \"./EdgeLabel.js\";\nimport { workflowPalette } from \"../theme/tokens.js\";\n\nexport interface WorkflowViewerProps {\n graph?: GraphDocument;\n document?: WorkflowEditorDocument;\n /**\n * Product layout preset, or a pre-computed graph layout for existing\n * advanced callers. Passing a LayoutResult remains supported.\n */\n layout?: WorkflowViewerLayout | LayoutResult;\n width?: number | string;\n height?: number | string;\n selectedId?: string;\n onSelectionChange?: (id: string | null) => void;\n surface?: WorkflowViewerSurface;\n layoutMode?: WorkflowViewerLayout;\n /** Alias for hosts that need both a pre-computed `layout` and a product preset. */\n viewerLayout?: WorkflowViewerLayout;\n interaction?: WorkflowViewerInteraction;\n /**\n * Receives lightweight adjacent-state/transition inspection for hover-path.\n * TODO: add pathProvider support for explicit STP or representative paths.\n */\n onInspect?: (inspection: WorkflowInspection | null) => void;\n /** Render the synthetic start-marker badge produced by graph projection. */\n showStartMarker?: boolean;\n className?: string;\n}\n\nexport type WorkflowViewerSurface = \"website\" | \"ops-console\";\nexport type WorkflowViewerLayout = \"embedded\" | \"fullWidth\";\nexport type WorkflowViewerInteraction =\n | \"none\"\n | \"select\"\n | \"hover-highlight\"\n | \"hover-path\";\n\n/**\n * Slim read-only SVG renderer. Renders workflow state nodes, transitions,\n * and edge-label chips using the theme tokens. No editing affordances.\n */\nexport function WorkflowViewer({\n graph: graphInput,\n document,\n layout,\n width = \"100%\",\n height = \"100%\",\n selectedId,\n onSelectionChange,\n surface = \"website\",\n layoutMode,\n viewerLayout,\n interaction = \"hover-highlight\",\n onInspect,\n showStartMarker = false,\n className,\n}: WorkflowViewerProps) {\n const graph = useMemo(() => {\n if (graphInput) return graphInput;\n if (document) return projectToGraph(document);\n throw new Error(\"WorkflowViewer requires either graph or document.\");\n }, [graphInput, document]);\n const visibleGraph = useMemo<GraphDocument>(() => {\n if (showStartMarker) return graph;\n return {\n ...graph,\n nodes: graph.nodes.filter((node) => node.kind !== \"startMarker\"),\n edges: graph.edges.filter((edge) => edge.kind !== \"startMarker\"),\n };\n }, [graph, showStartMarker]);\n const graphLayout = typeof layout === \"string\" ? undefined : layout;\n const productLayout = viewerLayout ??\n layoutMode ??\n (typeof layout === \"string\" ? layout : undefined) ??\n \"embedded\";\n const effectiveLayout = useMemo(\n () => normalizeLayoutForVisibleGraph(graphLayout, visibleGraph) ?? simpleLayout(visibleGraph),\n [graphLayout, visibleGraph],\n );\n const pan = usePanZoom();\n const [internalSelection, setInternalSelection] = useState<string | null>(null);\n const [hovered, setHovered] = useState<string | null>(null);\n const selection = selectedId ?? internalSelection;\n\n const stateNodes = useMemo(\n () => visibleGraph.nodes.filter((n): n is StateNode => n.kind === \"state\"),\n [visibleGraph.nodes],\n );\n const stateById = useMemo(() => {\n const m = new Map<string, StateNode>();\n for (const n of stateNodes) m.set(n.id, n);\n return m;\n }, [stateNodes]);\n\n const transitionEdges = useMemo(\n () => visibleGraph.edges.filter((e): e is TransitionEdge => e.kind === \"transition\"),\n [visibleGraph.edges],\n );\n\n // Dev-mode hint when the fallback renderer is used on a branching graph.\n useEffect(() => {\n if (process.env.NODE_ENV === \"production\" || graphLayout) return;\n const sourceCounts = new Map<string, number>();\n for (const e of graph.edges) {\n if (e.kind !== \"transition\") continue;\n sourceCounts.set(e.sourceId, (sourceCounts.get(e.sourceId) ?? 0) + 1);\n }\n if ([...sourceCounts.values()].some((n) => n > 1)) {\n console.warn(\n \"[WorkflowViewer] Rendering without an ELK layout — branching graphs may not look polished. \" +\n \"Pass a layout from `layoutGraph()` (@cyoda/workflow-layout) for best results.\",\n );\n }\n }, [graphLayout, visibleGraph.edges]);\n\n // Pre-compute fallback label positions with collision avoidance.\n // Only used when effectiveLayout has no .edges (the ELK path already provides label coords).\n const fallbackLabelPositions = useMemo(() => {\n if (effectiveLayout.edges) return null;\n const CHAR_W = 6.5;\n const PILL_H = 24;\n const items = transitionEdges.flatMap((edge) => {\n const source = effectiveLayout.positions.get(edge.sourceId);\n const target = effectiveLayout.positions.get(edge.targetId);\n if (!source || !target) return [];\n const { midX, midY } = computeEdgeGeometry(edge, source, target);\n const pillW = Math.max(40, edge.summary.display.length * CHAR_W + 12);\n return [{ id: edge.id, midX, midY, pillW, pillH: PILL_H }];\n });\n return nudgeLabels(items);\n }, [effectiveLayout, transitionEdges]);\n\n const focusId = hovered ?? selection;\n const highlightSet = useMemo(() => {\n if (interaction === \"none\") return null;\n if (interaction === \"select\") {\n return computeHighlightSet(selection, visibleGraph.nodes, visibleGraph.edges);\n }\n return computeHighlightSet(focusId, visibleGraph.nodes, visibleGraph.edges);\n }, [interaction, focusId, selection, visibleGraph.nodes, visibleGraph.edges]);\n\n const anythingFocused = highlightSet !== null;\n\n const handleSelect = (id: string) => {\n if (interaction === \"none\") return;\n setInternalSelection(id);\n onSelectionChange?.(id);\n };\n\n const handleBackgroundClick = () => {\n if (interaction === \"none\") return;\n setInternalSelection(null);\n onSelectionChange?.(null);\n };\n\n const handleHoverEnter = (id: string) => {\n if (interaction === \"hover-highlight\" || interaction === \"hover-path\") {\n setHovered(id);\n }\n if (interaction === \"hover-path\") {\n onInspect?.(inspectGraphFocus(visibleGraph, id));\n }\n };\n\n const handleHoverLeave = () => {\n if (interaction === \"hover-highlight\" || interaction === \"hover-path\") {\n setHovered(null);\n }\n if (interaction === \"hover-path\") {\n onInspect?.(null);\n }\n };\n\n return (\n <svg\n width={width}\n height={height}\n viewBox={`0 0 ${effectiveLayout.width} ${effectiveLayout.height}`}\n preserveAspectRatio=\"xMidYMid meet\"\n onClick={handleBackgroundClick}\n onWheel={pan.onWheel}\n onMouseDown={pan.onMouseDown}\n onMouseMove={pan.onMouseMove}\n onMouseUp={pan.onMouseUp}\n onMouseLeave={pan.onMouseUp}\n className={className}\n style={{\n background: workflowPalette.neutrals.white,\n fontFamily: \"inherit\",\n userSelect: \"none\",\n ...(productLayout === \"fullWidth\" ? { display: \"block\", width: \"100%\", height: \"100%\" } : null),\n }}\n data-surface={surface}\n data-layout={productLayout}\n data-interaction={interaction}\n data-testid=\"workflow-viewer\"\n >\n <Defs />\n <g\n transform={`translate(${pan.transform.x}, ${pan.transform.y}) scale(${pan.transform.scale})`}\n >\n {/* Edges first so they render behind nodes. */}\n {transitionEdges.map((edge) => {\n const source = effectiveLayout.positions.get(edge.sourceId);\n const target = effectiveLayout.positions.get(edge.targetId);\n if (!source || !target) return null;\n const targetNode = stateById.get(edge.targetId);\n const route = effectiveLayout.edges?.get(edge.id);\n const isEdgeSelected = selection === edge.id;\n const isHighlighted = highlightSet?.has(edge.id) ?? false;\n const isDimmed = anythingFocused && !isHighlighted;\n return (\n <EdgePath\n key={edge.id}\n edge={edge}\n source={source}\n target={target}\n route={route}\n targetIsTerminal={\n targetNode?.role === \"terminal\" ||\n targetNode?.role === \"initial-terminal\"\n }\n highlighted={isHighlighted}\n dimmed={isDimmed}\n selected={isEdgeSelected}\n onSelect={handleSelect}\n onHoverEnter={handleHoverEnter}\n onHoverLeave={handleHoverLeave}\n />\n );\n })}\n\n {/* Edge labels on top of edges. */}\n {transitionEdges.map((edge) => {\n const source = effectiveLayout.positions.get(edge.sourceId);\n const target = effectiveLayout.positions.get(edge.targetId);\n if (!source || !target) return null;\n const route = effectiveLayout.edges?.get(edge.id);\n // ELK path: use pre-placed label coords from the route.\n // Fallback path: use nudge-adjusted positions (collision-free).\n const labelPos = route\n ? { midX: route.labelX, midY: route.labelY }\n : (fallbackLabelPositions?.get(edge.id) ?? computeEdgeGeometry(edge, source, target));\n const isHighlighted = highlightSet?.has(edge.id) ?? false;\n const isDimmed = anythingFocused && !isHighlighted;\n return (\n <EdgeLabel\n key={`label-${edge.id}`}\n edge={edge}\n x={labelPos.midX}\n y={labelPos.midY}\n width={route?.labelWidth}\n height={route?.labelHeight}\n dimmed={isDimmed}\n />\n );\n })}\n\n {/* Nodes on top. */}\n {visibleGraph.nodes.map((node) => renderNode(node, effectiveLayout, {\n selection,\n highlightSet,\n anythingFocused,\n onSelect: handleSelect,\n onHoverEnter: handleHoverEnter,\n onHoverLeave: handleHoverLeave,\n }))}\n </g>\n </svg>\n );\n}\n\nfunction normalizeLayoutForVisibleGraph(\n layout: LayoutResult | undefined,\n graph: GraphDocument,\n): LayoutResult | undefined {\n if (!layout) return undefined;\n const visibleNodeIds = new Set(graph.nodes.map((node) => node.id));\n const positions = new Map(\n Array.from(layout.positions.entries()).filter(([nodeId]) => visibleNodeIds.has(nodeId)),\n );\n const visibleEdgeIds = new Set(graph.edges.map((edge) => edge.id));\n const edges = layout.edges\n ? new Map(Array.from(layout.edges.entries()).filter(([edgeId]) => visibleEdgeIds.has(edgeId)))\n : undefined;\n return {\n ...layout,\n positions,\n edges,\n width: computeLayoutBound(positions, \"x\"),\n height: computeLayoutBound(positions, \"y\"),\n };\n}\n\nfunction computeLayoutBound(\n positions: Map<string, NodePosition>,\n axis: \"x\" | \"y\",\n): number {\n let max = 0;\n for (const position of positions.values()) {\n const bound = axis === \"x\"\n ? position.x + position.width\n : position.y + position.height;\n if (bound > max) max = bound;\n }\n return Math.max(max + 24, 72);\n}\n\ninterface RenderCtx {\n selection: string | null;\n highlightSet: Set<string> | null;\n anythingFocused: boolean;\n onSelect: (id: string) => void;\n onHoverEnter: (id: string) => void;\n onHoverLeave: () => void;\n}\n\nfunction renderNode(\n node: GraphNode,\n layout: LayoutResult,\n ctx: RenderCtx,\n) {\n const pos = layout.positions.get(node.id);\n if (!pos) return null;\n if (node.kind === \"startMarker\") {\n return <StartMarker key={node.id} position={smallPositionForMarker(pos)} />;\n }\n const isHighlighted = ctx.highlightSet?.has(node.id) ?? false;\n const isDimmed = ctx.anythingFocused && !isHighlighted;\n return (\n <StateNodeView\n key={node.id}\n node={node}\n position={pos}\n selected={ctx.selection === node.id}\n highlighted={isHighlighted}\n dimmed={isDimmed}\n onSelect={ctx.onSelect}\n onHoverEnter={ctx.onHoverEnter}\n onHoverLeave={ctx.onHoverLeave}\n />\n );\n}\n\nfunction smallPositionForMarker(pos: NodePosition): NodePosition {\n // Shrink the marker to a small badge centred at the node slot.\n const size = 16;\n return {\n id: pos.id,\n x: pos.x + pos.width / 2 - size / 2,\n y: pos.y + pos.height / 2 - size / 2,\n width: size,\n height: size,\n };\n}\n\n/**\n * Compute the set of node/edge IDs to highlight when `focusedId` is hovered\n * or selected. Returns `null` when nothing is focused (all nodes+edges shown\n * at full opacity).\n */\n","/**\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 { GraphDocument, GraphNode } from \"@cyoda/workflow-graph\";\nimport { geometry } from \"./theme/tokens.js\";\n\nexport interface NodePosition {\n id: string;\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport interface EdgeWaypoint {\n x: number;\n y: number;\n}\n\nexport interface EdgeRoute {\n id: string;\n /** Full polyline from source attach point to target attach point. */\n points: EdgeWaypoint[];\n labelX: number;\n labelY: number;\n labelWidth?: number;\n labelHeight?: number;\n}\n\nexport interface LayoutResult {\n positions: Map<string, NodePosition>;\n /** Optional pre-computed polyline routes (e.g. from ELK). */\n edges?: Map<string, EdgeRoute>;\n width: number;\n height: number;\n}\n\n/**\n * Simple deterministic fallback layout used by the viewer when no ELK-computed\n * layout is provided. Groups nodes by workflow and arranges each workflow's\n * states in a BFS-layered top-to-bottom flow.\n *\n * The editor and the website both prefer ELK output (Phase 4). This layout is\n * a dependency-free default so the viewer package can render in isolation.\n */\nexport function simpleLayout(graph: GraphDocument): LayoutResult {\n const { width: nodeW, height: nodeH } = geometry.node;\n const hGap = 48;\n const vGap = 48;\n\n const positions = new Map<string, NodePosition>();\n const nodesByWorkflow = groupByWorkflow(graph.nodes);\n\n let yCursor = 24;\n let maxWidth = 0;\n\n for (const wfNodes of nodesByWorkflow.values()) {\n const layers = layerByBFS(wfNodes, graph);\n let y = yCursor;\n for (const layer of layers) {\n const layerWidth = layer.length * nodeW + (layer.length - 1) * hGap;\n maxWidth = Math.max(maxWidth, layerWidth + 48);\n let x = Math.max(24, (maxWidth - layerWidth) / 2);\n for (const node of layer) {\n positions.set(node.id, { id: node.id, x, y, width: nodeW, height: nodeH });\n x += nodeW + hGap;\n }\n y += nodeH + vGap;\n }\n yCursor = y + vGap;\n }\n\n return { positions, width: maxWidth + 24, height: yCursor };\n}\n\n/**\n * Greedy label de-overlap pass for fallback (non-ELK) rendering.\n *\n * Takes a list of edges with their tentative label centres and estimated pill\n * dimensions, then nudges any overlapping label downward so pills do not stack.\n * Only applies in the fallback path; ELK already does this via its own label\n * placement algorithm.\n *\n * Returns a Map<edgeId, { midX, midY }> with adjusted centres.\n */\nexport function nudgeLabels(\n items: Array<{ id: string; midX: number; midY: number; pillW: number; pillH: number }>,\n): Map<string, { midX: number; midY: number }> {\n // Sort by x then y so we process left-to-right, top-to-bottom.\n const sorted = [...items].sort((a, b) => a.midX - b.midX || a.midY - b.midY);\n const placed: Array<{ x: number; y: number; w: number; h: number }> = [];\n const result = new Map<string, { midX: number; midY: number }>();\n\n for (const item of sorted) {\n const { midX } = item;\n let { midY } = item;\n const halfW = item.pillW / 2;\n const halfH = item.pillH / 2;\n\n // Nudge downward until no overlap with already-placed labels.\n let attempts = 0;\n while (attempts < 20) {\n const overlaps = placed.some(\n (p) =>\n midX + halfW > p.x - p.w / 2 &&\n midX - halfW < p.x + p.w / 2 &&\n midY + halfH > p.y - p.h / 2 &&\n midY - halfH < p.y + p.h / 2,\n );\n if (!overlaps) break;\n midY += item.pillH + 4;\n attempts++;\n }\n\n placed.push({ x: midX, y: midY, w: item.pillW, h: item.pillH });\n result.set(item.id, { midX, midY });\n }\n\n return result;\n}\n\nfunction groupByWorkflow(nodes: GraphNode[]): Map<string, GraphNode[]> {\n const out = new Map<string, GraphNode[]>();\n for (const n of nodes) {\n const wf = \"workflow\" in n ? n.workflow : \"\";\n const list = out.get(wf) ?? [];\n list.push(n);\n out.set(wf, list);\n }\n return out;\n}\n\nfunction layerByBFS(nodes: GraphNode[], graph: GraphDocument): GraphNode[][] {\n const stateNodes: GraphNode[] = nodes.filter((n) => n.kind === \"state\");\n const markers: GraphNode[] = nodes.filter((n) => n.kind === \"startMarker\");\n if (stateNodes.length === 0) return markers.length > 0 ? [markers] : [];\n\n // Build adjacency from transition edges (skip loopbacks for layering).\n const adj = new Map<string, Set<string>>();\n const indeg = new Map<string, number>();\n for (const n of stateNodes) {\n adj.set(n.id, new Set());\n indeg.set(n.id, 0);\n }\n for (const e of graph.edges) {\n if (e.kind !== \"transition\" || e.isLoopback) continue;\n if (!adj.has(e.sourceId) || !adj.has(e.targetId)) continue;\n const set = adj.get(e.sourceId)!;\n if (!set.has(e.targetId)) {\n set.add(e.targetId);\n indeg.set(e.targetId, (indeg.get(e.targetId) ?? 0) + 1);\n }\n }\n\n const layers: GraphNode[][] = [];\n if (markers.length > 0) layers.push(markers);\n\n // Topological layering: sources first, then successors.\n const byId = new Map(stateNodes.map((n) => [n.id, n] as const));\n let frontier = stateNodes.filter((n) => (indeg.get(n.id) ?? 0) === 0);\n const placed = new Set<string>();\n while (frontier.length > 0) {\n layers.push(frontier);\n const next: GraphNode[] = [];\n for (const n of frontier) {\n placed.add(n.id);\n for (const succ of adj.get(n.id) ?? []) {\n const remaining = (indeg.get(succ) ?? 0) - 1;\n indeg.set(succ, remaining);\n if (remaining === 0 && !placed.has(succ)) {\n const node = byId.get(succ);\n if (node) next.push(node);\n }\n }\n }\n frontier = next;\n }\n\n // Any unplaced (cycle participants not reachable via in-degree-0) — drop\n // into a trailing layer so they still render.\n const remaining = stateNodes.filter((n) => !placed.has(n.id));\n if (remaining.length > 0) layers.push(remaining);\n return layers;\n}\n","import { useCallback, useRef, useState } from \"react\";\n\nexport interface ViewportTransform {\n x: number;\n y: number;\n scale: number;\n}\n\nexport interface PanZoomHandlers {\n transform: ViewportTransform;\n onWheel: (e: React.WheelEvent<SVGSVGElement>) => void;\n onMouseDown: (e: React.MouseEvent<SVGSVGElement>) => void;\n onMouseMove: (e: React.MouseEvent<SVGSVGElement>) => void;\n onMouseUp: (e: React.MouseEvent<SVGSVGElement>) => void;\n reset: () => void;\n setTransform: (t: ViewportTransform) => void;\n}\n\nconst MIN_SCALE = 0.25;\nconst MAX_SCALE = 4;\nconst ZOOM_STEP = 1.1;\n\n/**\n * Minimal pan + zoom state for a single SVG `<g>` transform. No inertia, no\n * trackpad-gesture normalisation — deferred to when we adopt react-zoom-pan\n * or a similar library.\n */\nexport function usePanZoom(initial?: Partial<ViewportTransform>): PanZoomHandlers {\n const [transform, setTransform] = useState<ViewportTransform>({\n x: initial?.x ?? 0,\n y: initial?.y ?? 0,\n scale: initial?.scale ?? 1,\n });\n const dragStart = useRef<{ x: number; y: number; vx: number; vy: number } | null>(null);\n\n const onWheel = useCallback((e: React.WheelEvent<SVGSVGElement>) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n const delta = e.deltaY > 0 ? 1 / ZOOM_STEP : ZOOM_STEP;\n setTransform((t) => {\n const nextScale = clamp(t.scale * delta, MIN_SCALE, MAX_SCALE);\n const ratio = nextScale / t.scale;\n const rect = (e.currentTarget as SVGSVGElement).getBoundingClientRect();\n const px = e.clientX - rect.left;\n const py = e.clientY - rect.top;\n return {\n scale: nextScale,\n x: px - (px - t.x) * ratio,\n y: py - (py - t.y) * ratio,\n };\n });\n }, []);\n\n const onMouseDown = useCallback((e: React.MouseEvent<SVGSVGElement>) => {\n if (e.button !== 0) return;\n dragStart.current = { x: e.clientX, y: e.clientY, vx: transform.x, vy: transform.y };\n }, [transform.x, transform.y]);\n\n const onMouseMove = useCallback((e: React.MouseEvent<SVGSVGElement>) => {\n if (!dragStart.current) return;\n const dx = e.clientX - dragStart.current.x;\n const dy = e.clientY - dragStart.current.y;\n setTransform((t) => ({ ...t, x: dragStart.current!.vx + dx, y: dragStart.current!.vy + dy }));\n }, []);\n\n const onMouseUp = useCallback(() => {\n dragStart.current = null;\n }, []);\n\n const reset = useCallback(() => {\n setTransform({ x: 0, y: 0, scale: 1 });\n }, []);\n\n return { transform, onWheel, onMouseDown, onMouseMove, onMouseUp, reset, setTransform };\n}\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, n));\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.manual;\n}\n\n/**\n * SVG `strokeDasharray` value for an edge.\n * - Manual: dotted \"2 4\".\n * - Otherwise: undefined (solid).\n */\nexport function laneDashArray(edge: TransitionEdge): string | undefined {\n if (edge.manual) return \"2 4\";\n return undefined;\n}\n","import type { TransitionEdge } from \"@cyoda/workflow-graph\";\nimport { laneColor, laneDashArray } from \"../theme/lane.js\";\nimport { geometry, workflowPalette } from \"../theme/tokens.js\";\nimport type { EdgeRoute, NodePosition } from \"../layout.js\";\n\ninterface Props {\n edge: TransitionEdge;\n source: NodePosition;\n target: NodePosition;\n /** Pre-computed polyline from the layout engine (ELK). Overrides center-to-center heuristic. */\n route?: EdgeRoute;\n targetIsTerminal: boolean;\n highlighted: boolean;\n dimmed: boolean;\n selected: boolean;\n onSelect: (id: string) => void;\n onHoverEnter: (id: string) => void;\n onHoverLeave: () => void;\n}\n\nexport interface EdgeGeometry {\n d: string;\n midX: number;\n midY: number;\n}\n\n/**\n * Convert a polyline to an SVG path `d` string.\n */\nexport function polylineToPath(points: { x: number; y: number }[]): string {\n if (points.length === 0) return \"\";\n const [first, ...rest] = points;\n let d = `M ${first!.x} ${first!.y}`;\n for (const p of rest) d += ` L ${p.x} ${p.y}`;\n return d;\n}\n\n/**\n * Compute a simple orthogonal-ish path between two node centres. Self-loops\n * are rendered as a right-side arc; parallel siblings are offset laterally\n * based on parallelIndex to avoid overlap.\n */\nexport function computeEdgeGeometry(\n edge: TransitionEdge,\n source: NodePosition,\n target: NodePosition,\n): EdgeGeometry {\n // Default ports: source exits from bottom-centre, target enters at top-centre.\n // simpleLayout always produces top-down BFS layers so this avoids the arrowhead\n // landing under the target node (which happens when both ends are at node centre).\n const sx = source.x + source.width / 2;\n const sy = source.y + source.height;\n const tx = target.x + target.width / 2;\n const ty = target.y;\n\n if (edge.isSelf) {\n const rightX = source.x + source.width;\n const topY = source.y + source.height / 3;\n const bottomY = source.y + (source.height * 2) / 3;\n const loopX = rightX + 28;\n const d = `M ${rightX} ${topY} C ${loopX} ${topY}, ${loopX} ${bottomY}, ${rightX} ${bottomY}`;\n return { d, midX: loopX, midY: (topY + bottomY) / 2 };\n }\n\n // Lateral offset for parallel edges: stagger by parallelIndex around the\n // midpoint. 0 → centred, 1 → +offset, 2 → -offset, etc.\n const offsetStep = 18;\n const half = Math.floor(edge.parallelGroupSize / 2);\n const signed = edge.parallelIndex - half;\n const offset = signed * offsetStep;\n\n const mx = (sx + tx) / 2 + offset;\n const my = (sy + ty) / 2;\n\n // Simple cubic curve so parallel siblings don't overlap.\n const d = `M ${sx} ${sy} Q ${mx} ${my}, ${tx} ${ty}`;\n return { d, midX: mx, midY: my };\n}\n\nexport function EdgePath({\n edge,\n source,\n target,\n route,\n targetIsTerminal,\n highlighted,\n dimmed,\n selected,\n onSelect,\n onHoverEnter,\n onHoverLeave,\n}: Props) {\n const color = laneColor(edge, { targetIsTerminal });\n const dash = laneDashArray(edge);\n const d =\n route && route.points.length >= 2\n ? polylineToPath(route.points)\n : computeEdgeGeometry(edge, source, target).d;\n\n const strokeWidth =\n selected || highlighted\n ? geometry.edge.strokeWidth + 0.8\n : edge.isLoopback\n ? geometry.edge.loopStrokeWidth\n : geometry.edge.strokeWidth;\n const opacity = dimmed ? 0.25 : 1;\n\n return (\n <g\n opacity={opacity}\n onClick={(e) => {\n e.stopPropagation();\n onSelect(edge.id);\n }}\n onMouseEnter={() => onHoverEnter(edge.id)}\n onMouseLeave={onHoverLeave}\n style={{ cursor: \"pointer\" }}\n data-testid={`edge-${edge.id}`}\n >\n {/* Transparent fat stroke to widen the hit-area. */}\n <path d={d} fill=\"none\" stroke=\"transparent\" strokeWidth={12} />\n <path\n d={d}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeDasharray={dash}\n markerEnd={`url(#wf-arrow-${colorKey(color)})`}\n />\n </g>\n );\n}\n\n/**\n * Lane colours keyed so we can reuse one marker per lane. Must be a valid\n * fragment identifier.\n */\nexport function colorKey(color: string): string {\n return color.replace(\"#\", \"\").toLowerCase();\n}\n\n/**\n * The set of lane colours we need arrowhead markers for. Emitted once per\n * SVG instance from `WorkflowViewer`.\n */\nexport const laneColorSet: string[] = Object.values(workflowPalette.edge);\n","import { geometry, workflowPalette } from \"../theme/tokens.js\";\nimport { colorKey, laneColorSet } from \"./EdgePath.js\";\n\n/**\n * Shared SVG `<defs>` — arrowhead markers (one per lane colour) and the two\n * drop-shadow filters used by nodes and label chips.\n */\nexport function Defs() {\n const size = geometry.edge.arrowheadSize;\n // Sharper 2:1 triangle: width (tip-to-base) = 2*size, base thickness = size,\n // so the base runs vertically from (0, size/2) to (0, 3*size/2) and the tip\n // sits at (2*size, size). refX is pushed close to the tip so the arrow kisses\n // the node edge, not floats away from it.\n const unique = Array.from(new Set(laneColorSet));\n return (\n <defs>\n {unique.map((color) => (\n <marker\n key={color}\n id={`wf-arrow-${colorKey(color)}`}\n viewBox={`0 0 ${size * 2} ${size * 2}`}\n refX={size * 1.85}\n refY={size}\n markerWidth={size}\n markerHeight={size}\n orient=\"auto-start-reverse\"\n >\n <path\n d={`M 0 ${size / 2} L ${size * 2} ${size} L 0 ${size * 1.5} z`}\n fill={color}\n />\n </marker>\n ))}\n <filter id=\"wf-node-shadow\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"140%\">\n <feDropShadow\n dx={0}\n dy={2}\n stdDeviation={2}\n floodColor={workflowPalette.neutrals.slate900}\n floodOpacity={0.08}\n />\n </filter>\n <filter\n id=\"wf-node-shadow-strong\"\n x=\"-10%\"\n y=\"-10%\"\n width=\"120%\"\n height=\"140%\"\n >\n <feDropShadow\n dx={0}\n dy={3}\n stdDeviation={3}\n floodColor={workflowPalette.neutrals.slate900}\n floodOpacity={0.18}\n />\n </filter>\n <filter id=\"wf-label-shadow\" x=\"-10%\" y=\"-10%\" width=\"120%\" height=\"140%\">\n <feDropShadow\n dx={0}\n dy={1}\n stdDeviation={1.2}\n floodColor={workflowPalette.neutrals.slate900}\n floodOpacity={geometry.labelPill.shadowOpacity}\n />\n </filter>\n </defs>\n );\n}\n","import { workflowPalette } from \"../theme/tokens.js\";\nimport type { NodePosition } from \"../layout.js\";\n\ninterface Props {\n position: NodePosition;\n}\n\n/**\n * Non-interactive start marker node (spec §10.5). Rendered as a small filled\n * circle above the initial state.\n */\nexport function StartMarker({ position }: Props) {\n const cx = position.x + position.width / 2;\n const cy = position.y + position.height / 2;\n const r = Math.min(position.width, position.height) / 3;\n return (\n <g aria-hidden=\"true\">\n <circle\n data-testid=\"start-marker\"\n cx={cx}\n cy={cy}\n r={r}\n fill={workflowPalette.node.initial.border}\n stroke={workflowPalette.node.initial.meta}\n strokeWidth={1.5}\n />\n </g>\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\";\n return \"STATE\";\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 // Manual badge removed – hidden from display\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 // Execution badges (SYNC, ASYNC_SAME_TX) removed – hidden from display\n\n if (flags.disabled) out.push({ key: \"disabled\", label: \"Disabled\" });\n\n return out;\n}\n","import type { StateNode as StateNodeData } from \"@cyoda/workflow-graph\";\nimport { paletteFor, roleCategoryLabel } from \"../theme/index.js\";\nimport { geometry, typography, workflowPalette } from \"../theme/tokens.js\";\nimport type { NodePosition } from \"../layout.js\";\n\ninterface Props {\n node: StateNodeData;\n position: NodePosition;\n selected: boolean;\n highlighted: boolean;\n dimmed: boolean;\n onSelect: (id: string) => void;\n onHoverEnter: (id: string) => void;\n onHoverLeave: () => void;\n}\n\nexport function StateNodeView({\n node,\n position,\n selected,\n highlighted,\n dimmed,\n onSelect,\n onHoverEnter,\n onHoverLeave,\n}: Props) {\n const palette = paletteFor(node);\n const { radius, strokeWidth, terminalInset, terminalInnerRadius } = geometry.node;\n const { width, height } = position;\n const isTerminal = node.role === \"terminal\" || node.role === \"initial-terminal\";\n const isInitialTerminal = node.role === \"initial-terminal\";\n const category = roleCategoryLabel(node);\n\n const opacity = dimmed ? 0.35 : 1;\n const outerStroke = selected\n ? workflowPalette.neutrals.slate900\n : palette.border;\n const outerStrokeWidth = selected ? strokeWidth + 1 : strokeWidth;\n\n return (\n <g\n transform={`translate(${position.x}, ${position.y})`}\n opacity={opacity}\n onClick={(e) => {\n e.stopPropagation();\n onSelect(node.id);\n }}\n onMouseEnter={() => onHoverEnter(node.id)}\n onMouseLeave={onHoverLeave}\n style={{ cursor: \"pointer\" }}\n data-testid={`state-node-${node.stateCode}`}\n aria-label={`${category} ${node.stateCode}`}\n role=\"button\"\n tabIndex={0}\n >\n <rect\n x={0}\n y={0}\n width={width}\n height={height}\n rx={radius}\n ry={radius}\n fill={palette.fill}\n stroke={outerStroke}\n strokeWidth={outerStrokeWidth}\n filter={highlighted || selected ? \"url(#wf-node-shadow-strong)\" : \"url(#wf-node-shadow)\"}\n />\n {isTerminal && (\n <rect\n x={terminalInset}\n y={terminalInset}\n width={width - terminalInset * 2}\n height={height - terminalInset * 2}\n rx={terminalInnerRadius}\n ry={terminalInnerRadius}\n fill=\"none\"\n stroke={\n \"innerRing\" in palette\n ? palette.innerRing\n : workflowPalette.neutrals.white75\n }\n strokeWidth={1}\n />\n )}\n {isInitialTerminal && (\n <rect\n x={terminalInset}\n y={terminalInset}\n width={width - terminalInset * 2}\n height={height - terminalInset * 2}\n rx={terminalInnerRadius}\n ry={terminalInnerRadius}\n fill=\"none\"\n stroke={workflowPalette.node.initial.border}\n strokeWidth={1}\n strokeDasharray=\"3 3\"\n />\n )}\n <text\n x={width / 2}\n y={height / 2 - 8}\n textAnchor=\"middle\"\n fill={palette.meta}\n fontFamily={typography.fontFamily}\n fontSize={typography.stateCategory.size}\n fontWeight={typography.stateCategory.weight}\n letterSpacing={typography.stateCategory.tracking}\n >\n {category}\n </text>\n <text\n x={width / 2}\n y={height / 2 + 12}\n textAnchor=\"middle\"\n fill={palette.title}\n fontFamily={typography.monoFamily}\n fontSize={typography.stateTitle.size}\n fontWeight={typography.stateTitle.weight}\n letterSpacing={typography.stateTitle.tracking}\n >\n {truncate(node.stateCode, 18)}\n </text>\n </g>\n );\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return `${s.slice(0, max - 1)}…`;\n}\n","import type { TransitionEdge } from \"@cyoda/workflow-graph\";\nimport { badgesFor, type BadgeDescriptor } from \"../theme/badges.js\";\nimport { geometry, typography, workflowPalette } from \"../theme/tokens.js\";\n\ninterface Props {\n edge: TransitionEdge;\n x: number;\n y: number;\n width?: number;\n height?: number;\n dimmed: boolean;\n}\n\nconst BADGE_HEIGHT = 14;\nconst BADGE_GAP = 4;\nconst LABEL_PADDING_X = geometry.labelPill.paddingX;\nconst LABEL_PADDING_Y = geometry.labelPill.paddingY;\nconst BADGE_TEXT_PADDING_X = 6;\n\n/**\n * Estimate label width in SVG units. Rough heuristic: avg glyph width ≈\n * fontSize * 0.58 for the sans/mono stack at these sizes. Good enough until\n * we measure via getBBox.\n */\nfunction estimateWidth(text: string, fontSize: number): number {\n return Math.ceil(text.length * fontSize * 0.58);\n}\n\nexport function EdgeLabel({ edge, x, y, width, height, dimmed }: Props) {\n const title = edge.summary.display;\n const badges = badgesFor(edge.summary, {\n manual: edge.manual,\n disabled: edge.disabled,\n });\n\n const titleW = estimateWidth(title, typography.edgeLabel.size);\n\n const badgeWidths = badges.map(\n (b) => estimateWidth(b.label, typography.badge.size) + BADGE_TEXT_PADDING_X * 2,\n );\n const badgesTotalW =\n badgeWidths.reduce((a, b) => a + b, 0) +\n Math.max(0, badges.length - 1) * BADGE_GAP;\n\n const pillW = width ?? Math.max(titleW, badgesTotalW) + LABEL_PADDING_X * 2;\n const hasBadges = badges.length > 0;\n const pillH = height ??\n typography.edgeLabel.size +\n LABEL_PADDING_Y * 2 +\n (hasBadges ? BADGE_HEIGHT + BADGE_GAP : 0);\n\n const pillX = x - pillW / 2;\n const pillY = y - pillH / 2;\n const titleY = pillY + LABEL_PADDING_Y + typography.edgeLabel.size - 2;\n const badgeY = titleY + BADGE_GAP + 2;\n\n const opacity = dimmed ? 0.4 : 1;\n\n return (\n <g opacity={opacity} pointerEvents=\"none\">\n <rect\n x={pillX}\n y={pillY}\n width={pillW}\n height={pillH}\n rx={geometry.labelPill.radius}\n ry={geometry.labelPill.radius}\n fill={workflowPalette.edgeLabel.fill}\n stroke={workflowPalette.edgeLabel.border}\n strokeWidth={1}\n filter=\"url(#wf-label-shadow)\"\n />\n <text\n x={x}\n y={titleY}\n textAnchor=\"middle\"\n fill={workflowPalette.edgeLabel.text}\n fontFamily={typography.fontFamily}\n fontSize={typography.edgeLabel.size}\n fontWeight={typography.edgeLabel.weight}\n letterSpacing={typography.edgeLabel.tracking}\n >\n {title}\n </text>\n {hasBadges && renderBadges(badges, badgeWidths, pillX, pillW, badgeY)}\n </g>\n );\n}\n\nfunction renderBadges(\n badges: BadgeDescriptor[],\n widths: number[],\n pillX: number,\n pillW: number,\n y: number,\n) {\n const totalW =\n widths.reduce((a, b) => a + b, 0) +\n Math.max(0, badges.length - 1) * BADGE_GAP;\n let cursor = pillX + (pillW - totalW) / 2;\n return (\n <g>\n {badges.map((b, i) => {\n const w = widths[i]!;\n const slot = pickBadgePalette(b.key);\n const node = (\n <g key={`${b.key}-${i}`}>\n <rect\n x={cursor}\n y={y}\n width={w}\n height={BADGE_HEIGHT}\n rx={BADGE_HEIGHT / 2}\n ry={BADGE_HEIGHT / 2}\n fill={slot.fill}\n stroke={slot.border}\n strokeWidth={1}\n />\n <text\n x={cursor + w / 2}\n y={y + BADGE_HEIGHT - 4}\n textAnchor=\"middle\"\n fill={workflowPalette.badge.text}\n fontFamily={typography.fontFamily}\n fontSize={typography.badge.size}\n fontWeight={typography.badge.weight}\n letterSpacing={typography.badge.tracking}\n >\n {b.label}\n </text>\n </g>\n );\n cursor += w + BADGE_GAP;\n return node;\n })}\n </g>\n );\n}\n\nfunction pickBadgePalette(key: BadgeDescriptor[\"key\"]) {\n switch (key) {\n case \"manual\":\n return workflowPalette.badge.manual;\n case \"processor\":\n return workflowPalette.badge.processor;\n case \"criterion\":\n return workflowPalette.badge.criterion;\n case \"execution\":\n return workflowPalette.badge.processor;\n case \"disabled\":\n return workflowPalette.badge.disabled;\n }\n}\n"],"mappings":"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","names":["useState","remaining","d","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState"]}
|
package/dist/theme/index.cjs
CHANGED
|
@@ -135,7 +135,7 @@ function roleCategoryLabel(node) {
|
|
|
135
135
|
if (node.role === "initial" || node.role === "initial-terminal") return "INITIAL";
|
|
136
136
|
if (node.role === "terminal") return "TERMINAL";
|
|
137
137
|
if (node.category === "MANUAL_REVIEW") return "MANUAL REVIEW";
|
|
138
|
-
if (node.category === "PROCESSING_STATE") return "PROCESSING
|
|
138
|
+
if (node.category === "PROCESSING_STATE") return "PROCESSING";
|
|
139
139
|
return "STATE";
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -153,11 +153,10 @@ function laneColor(edge, opts) {
|
|
|
153
153
|
return e.automated;
|
|
154
154
|
}
|
|
155
155
|
function laneIsDashed(edge) {
|
|
156
|
-
return edge.
|
|
156
|
+
return edge.manual;
|
|
157
157
|
}
|
|
158
158
|
function laneDashArray(edge) {
|
|
159
|
-
if (edge.
|
|
160
|
-
if (edge.isLoopback) return "6 4";
|
|
159
|
+
if (edge.manual) return "2 4";
|
|
161
160
|
return void 0;
|
|
162
161
|
}
|
|
163
162
|
|
|
@@ -174,7 +173,6 @@ function paletteFor(node) {
|
|
|
174
173
|
// src/theme/badges.ts
|
|
175
174
|
function badgesFor(summary, flags) {
|
|
176
175
|
const out = [];
|
|
177
|
-
if (flags.manual) out.push({ key: "manual", label: "Manual" });
|
|
178
176
|
if (summary.processor) {
|
|
179
177
|
if (summary.processor.kind === "single") {
|
|
180
178
|
out.push({ key: "processor", label: summary.processor.name });
|
|
@@ -190,11 +188,6 @@ function badgesFor(summary, flags) {
|
|
|
190
188
|
out.push({ key: "criterion", label: "Criterion" });
|
|
191
189
|
}
|
|
192
190
|
}
|
|
193
|
-
if (summary.execution?.kind === "sync") {
|
|
194
|
-
out.push({ key: "execution", label: "SYNC" });
|
|
195
|
-
} else if (summary.execution?.kind === "asyncSameTx") {
|
|
196
|
-
out.push({ key: "execution", label: "ASYNC_SAME_TX" });
|
|
197
|
-
}
|
|
198
191
|
if (flags.disabled) out.push({ key: "disabled", label: "Disabled" });
|
|
199
192
|
return out;
|
|
200
193
|
}
|
package/dist/theme/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/theme/index.ts","../../src/theme/tokens.ts","../../src/theme/role-label.ts","../../src/theme/lane.ts","../../src/theme/node-palette.ts","../../src/theme/badges.ts"],"sourcesContent":["export {\n workflowPalette,\n typography,\n geometry,\n} from \"./tokens.js\";\nexport type {\n BadgePalette,\n BadgePaletteEntry,\n EdgeLabelPalette,\n EdgePalette,\n NeutralPalette,\n NodePalette,\n RolePaletteEntry,\n TerminalPaletteEntry,\n WorkflowPalette,\n} from \"./tokens.js\";\nexport { roleCategoryLabel } from \"./role-label.js\";\nexport { laneColor, laneIsDashed, laneDashArray } from \"./lane.js\";\nexport { paletteFor } from \"./node-palette.js\";\nexport { badgesFor } from \"./badges.js\";\nexport type { BadgeDescriptor } from \"./badges.js\";\n","/**\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC6EO,IAAM,kBAAmC;AAAA,EAC9C,UAAU;AAAA,IACR,OAAO;AAAA,IACP,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,SAAS;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW;AAAA,IACb;AAAA,IACA,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,IACA,YAAY;AAAA,MACV,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,MAAM;AAAA,IACJ,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,WAAW;AAAA,EACb;AAAA,EACA,WAAW;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,EACR;AAAA,EACA,OAAO;AAAA,IACL,QAAQ,EAAE,MAAM,WAAW,QAAQ,UAAU;AAAA,IAC7C,WAAW,EAAE,MAAM,WAAW,QAAQ,UAAU;AAAA,IAChD,WAAW,EAAE,MAAM,WAAW,QAAQ,UAAU;AAAA,IAChD,UAAU,EAAE,MAAM,WAAW,QAAQ,UAAU;AAAA,IAC/C,MAAM;AAAA,EACR;AACF;AAEO,IAAM,aAAa;AAAA,EACxB,YACE;AAAA,EACF,YAAY;AAAA,EACZ,eAAe,EAAE,MAAM,IAAI,QAAQ,KAAK,UAAU,SAAS;AAAA,EAC3D,YAAY,EAAE,MAAM,IAAI,QAAQ,KAAK,UAAU,SAAS;AAAA,EACxD,WAAW,EAAE,MAAM,GAAG,QAAQ,KAAK,UAAU,SAAS;AAAA,EACtD,OAAO,EAAE,MAAM,GAAG,QAAQ,KAAK,UAAU,SAAS;AACpD;AAEO,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,qBAAqB;AAAA,EACvB;AAAA,EACA,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,eAAe;AAAA,EACjB;AAAA,EACA,WAAW;AAAA,IACT,UAAU;AAAA,IACV,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,eAAe;AAAA,EACjB;AACF;;;ACtKO,SAAS,kBAAkB,MAAyB;AACzD,MAAI,KAAK,SAAS,aAAa,KAAK,SAAS,mBAAoB,QAAO;AACxE,MAAI,KAAK,SAAS,WAAY,QAAO;AACrC,MAAI,KAAK,aAAa,gBAAiB,QAAO;AAC9C,MAAI,KAAK,aAAa,mBAAoB,QAAO;AACjD,SAAO;AACT;;;ACCO,SAAS,UACd,MACA,MACQ;AACR,QAAM,IAAI,gBAAgB;AAC1B,MAAI,KAAK,SAAU,QAAO,EAAE;AAC5B,MAAI,KAAK,WAAY,QAAO,EAAE;AAC9B,MAAI,KAAK,iBAAkB,QAAO,EAAE;AACpC,MAAI,KAAK,QAAQ,aAAa,KAAK,QAAQ,UAAU,SAAS,QAAQ;AACpE,WAAO,EAAE;AAAA,EACX;AACA,MAAI,KAAK,OAAQ,QAAO,EAAE;AAC1B,MAAI,KAAK,QAAQ,UAAW,QAAO,EAAE;AACrC,SAAO,EAAE;AACX;AAMO,SAAS,aAAa,MAA+B;AAC1D,SAAO,KAAK,YAAY,KAAK;AAC/B;AAQO,SAAS,cAAc,MAA0C;AACtE,MAAI,KAAK,SAAU,QAAO;AAC1B,MAAI,KAAK,WAAY,QAAO;AAC5B,SAAO;AACT;;;AC1CO,SAAS,WACd,MACyC;AACzC,QAAM,IAAI,gBAAgB;AAC1B,MAAI,KAAK,SAAS,cAAc,KAAK,SAAS,mBAAoB,QAAO,EAAE;AAC3E,MAAI,KAAK,SAAS,UAAW,QAAO,EAAE;AACtC,MAAI,KAAK,aAAa,gBAAiB,QAAO,EAAE;AAChD,MAAI,KAAK,aAAa,mBAAoB,QAAO,EAAE;AACnD,SAAO,EAAE;AACX;;;ACLO,SAAS,UACd,SACA,OACmB;AACnB,QAAM,MAAyB,CAAC;AAEhC,MAAI,MAAM,OAAQ,KAAI,KAAK,EAAE,KAAK,UAAU,OAAO,SAAS,CAAC;AAE7D,MAAI,QAAQ,WAAW;AACrB,QAAI,QAAQ,UAAU,SAAS,UAAU;AACvC,UAAI,KAAK,EAAE,KAAK,aAAa,OAAO,QAAQ,UAAU,KAAK,CAAC;AAAA,IAC9D,WAAW,QAAQ,UAAU,SAAS,YAAY;AAChD,UAAI,KAAK,EAAE,KAAK,aAAa,OAAO,GAAG,QAAQ,UAAU,KAAK,cAAc,CAAC;AAAA,IAC/E;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW;AACrB,UAAM,IAAI,QAAQ;AAClB,QAAI,EAAE,SAAS,SAAS;AACtB,UAAI,KAAK,EAAE,KAAK,aAAa,OAAO,GAAG,EAAE,QAAQ,SAAM,EAAE,KAAK,GAAG,CAAC;AAAA,IACpE,OAAO;AACL,UAAI,KAAK,EAAE,KAAK,aAAa,OAAO,YAAY,CAAC;AAAA,IACnD;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,SAAS,QAAQ;AACtC,QAAI,KAAK,EAAE,KAAK,aAAa,OAAO,OAAO,CAAC;AAAA,EAC9C,WAAW,QAAQ,WAAW,SAAS,eAAe;AACpD,QAAI,KAAK,EAAE,KAAK,aAAa,OAAO,gBAAgB,CAAC;AAAA,EACvD;AAEA,MAAI,MAAM,SAAU,KAAI,KAAK,EAAE,KAAK,YAAY,OAAO,WAAW,CAAC;AAEnE,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/theme/index.ts","../../src/theme/tokens.ts","../../src/theme/role-label.ts","../../src/theme/lane.ts","../../src/theme/node-palette.ts","../../src/theme/badges.ts"],"sourcesContent":["export {\n workflowPalette,\n typography,\n geometry,\n} from \"./tokens.js\";\nexport type {\n BadgePalette,\n BadgePaletteEntry,\n EdgeLabelPalette,\n EdgePalette,\n NeutralPalette,\n NodePalette,\n RolePaletteEntry,\n TerminalPaletteEntry,\n WorkflowPalette,\n} from \"./tokens.js\";\nexport { roleCategoryLabel } from \"./role-label.js\";\nexport { laneColor, laneIsDashed, laneDashArray } from \"./lane.js\";\nexport { paletteFor } from \"./node-palette.js\";\nexport { badgesFor } from \"./badges.js\";\nexport type { BadgeDescriptor } from \"./badges.js\";\n","/**\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\";\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.manual;\n}\n\n/**\n * SVG `strokeDasharray` value for an edge.\n * - Manual: dotted \"2 4\".\n * - Otherwise: undefined (solid).\n */\nexport function laneDashArray(edge: TransitionEdge): string | undefined {\n if (edge.manual) return \"2 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 // Manual badge removed – hidden from display\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 // Execution badges (SYNC, ASYNC_SAME_TX) removed – hidden from display\n\n if (flags.disabled) out.push({ key: \"disabled\", label: \"Disabled\" });\n\n return out;\n}\n"],"mappings":"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","names":[]}
|
package/dist/theme/index.d.cts
CHANGED
|
@@ -146,8 +146,7 @@ declare function laneColor(edge: TransitionEdge, opts: {
|
|
|
146
146
|
declare function laneIsDashed(edge: TransitionEdge): boolean;
|
|
147
147
|
/**
|
|
148
148
|
* SVG `strokeDasharray` value for an edge.
|
|
149
|
-
* -
|
|
150
|
-
* - Loopback (non-disabled): "6 4" — looser, still dashed.
|
|
149
|
+
* - Manual: dotted "2 4".
|
|
151
150
|
* - Otherwise: undefined (solid).
|
|
152
151
|
*/
|
|
153
152
|
declare function laneDashArray(edge: TransitionEdge): string | undefined;
|
package/dist/theme/index.d.ts
CHANGED
|
@@ -146,8 +146,7 @@ declare function laneColor(edge: TransitionEdge, opts: {
|
|
|
146
146
|
declare function laneIsDashed(edge: TransitionEdge): boolean;
|
|
147
147
|
/**
|
|
148
148
|
* SVG `strokeDasharray` value for an edge.
|
|
149
|
-
* -
|
|
150
|
-
* - Loopback (non-disabled): "6 4" — looser, still dashed.
|
|
149
|
+
* - Manual: dotted "2 4".
|
|
151
150
|
* - Otherwise: undefined (solid).
|
|
152
151
|
*/
|
|
153
152
|
declare function laneDashArray(edge: TransitionEdge): string | undefined;
|
package/dist/theme/index.js
CHANGED
|
@@ -101,7 +101,7 @@ function roleCategoryLabel(node) {
|
|
|
101
101
|
if (node.role === "initial" || node.role === "initial-terminal") return "INITIAL";
|
|
102
102
|
if (node.role === "terminal") return "TERMINAL";
|
|
103
103
|
if (node.category === "MANUAL_REVIEW") return "MANUAL REVIEW";
|
|
104
|
-
if (node.category === "PROCESSING_STATE") return "PROCESSING
|
|
104
|
+
if (node.category === "PROCESSING_STATE") return "PROCESSING";
|
|
105
105
|
return "STATE";
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -119,11 +119,10 @@ function laneColor(edge, opts) {
|
|
|
119
119
|
return e.automated;
|
|
120
120
|
}
|
|
121
121
|
function laneIsDashed(edge) {
|
|
122
|
-
return edge.
|
|
122
|
+
return edge.manual;
|
|
123
123
|
}
|
|
124
124
|
function laneDashArray(edge) {
|
|
125
|
-
if (edge.
|
|
126
|
-
if (edge.isLoopback) return "6 4";
|
|
125
|
+
if (edge.manual) return "2 4";
|
|
127
126
|
return void 0;
|
|
128
127
|
}
|
|
129
128
|
|
|
@@ -140,7 +139,6 @@ function paletteFor(node) {
|
|
|
140
139
|
// src/theme/badges.ts
|
|
141
140
|
function badgesFor(summary, flags) {
|
|
142
141
|
const out = [];
|
|
143
|
-
if (flags.manual) out.push({ key: "manual", label: "Manual" });
|
|
144
142
|
if (summary.processor) {
|
|
145
143
|
if (summary.processor.kind === "single") {
|
|
146
144
|
out.push({ key: "processor", label: summary.processor.name });
|
|
@@ -156,11 +154,6 @@ function badgesFor(summary, flags) {
|
|
|
156
154
|
out.push({ key: "criterion", label: "Criterion" });
|
|
157
155
|
}
|
|
158
156
|
}
|
|
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
157
|
if (flags.disabled) out.push({ key: "disabled", label: "Disabled" });
|
|
165
158
|
return out;
|
|
166
159
|
}
|
package/dist/theme/index.js.map
CHANGED
|
@@ -1 +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":[]}
|
|
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\";\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.manual;\n}\n\n/**\n * SVG `strokeDasharray` value for an edge.\n * - Manual: dotted \"2 4\".\n * - Otherwise: undefined (solid).\n */\nexport function laneDashArray(edge: TransitionEdge): string | undefined {\n if (edge.manual) return \"2 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 // Manual badge removed – hidden from display\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 // Execution badges (SYNC, ASYNC_SAME_TX) removed – hidden from display\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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyoda/workflow-viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Slim read-only SVG renderer for Cyoda workflows.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"provenance": true
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@cyoda/workflow-core": "0.
|
|
43
|
-
"@cyoda/workflow-graph": "0.
|
|
42
|
+
"@cyoda/workflow-core": "0.2.0",
|
|
43
|
+
"@cyoda/workflow-graph": "0.2.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"react": "^18.3.1",
|