@graph-artifact/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/ThemeContext.d.ts +47 -0
  4. package/dist/ThemeContext.js +81 -0
  5. package/dist/components/DiagramCanvas.d.ts +8 -0
  6. package/dist/components/DiagramCanvas.js +19 -0
  7. package/dist/components/GraphCanvas.d.ts +9 -0
  8. package/dist/components/GraphCanvas.js +104 -0
  9. package/dist/components/NodeDetail.d.ts +9 -0
  10. package/dist/components/NodeDetail.js +127 -0
  11. package/dist/components/edges/RoutedEdge.d.ts +11 -0
  12. package/dist/components/edges/RoutedEdge.js +199 -0
  13. package/dist/components/nodes/ClassNode.d.ts +5 -0
  14. package/dist/components/nodes/ClassNode.js +62 -0
  15. package/dist/components/nodes/EntityNode.d.ts +5 -0
  16. package/dist/components/nodes/EntityNode.js +57 -0
  17. package/dist/components/nodes/FlowNode.d.ts +5 -0
  18. package/dist/components/nodes/FlowNode.js +144 -0
  19. package/dist/components/nodes/SequenceNodes.d.ts +33 -0
  20. package/dist/components/nodes/SequenceNodes.js +205 -0
  21. package/dist/components/nodes/StateNode.d.ts +5 -0
  22. package/dist/components/nodes/StateNode.js +71 -0
  23. package/dist/components/nodes/SubgraphNode.d.ts +5 -0
  24. package/dist/components/nodes/SubgraphNode.js +16 -0
  25. package/dist/config.d.ts +138 -0
  26. package/dist/config.js +165 -0
  27. package/dist/core.d.ts +12 -0
  28. package/dist/core.js +7 -0
  29. package/dist/diagrams/detect.d.ts +2 -0
  30. package/dist/diagrams/detect.js +8 -0
  31. package/dist/diagrams/plugins.d.ts +2 -0
  32. package/dist/diagrams/plugins.js +45 -0
  33. package/dist/diagrams/registry.d.ts +3 -0
  34. package/dist/diagrams/registry.js +13 -0
  35. package/dist/diagrams/types.d.ts +7 -0
  36. package/dist/diagrams/types.js +1 -0
  37. package/dist/index.d.ts +1 -0
  38. package/dist/index.js +3 -0
  39. package/dist/layout/dagre/index.d.ts +31 -0
  40. package/dist/layout/dagre/index.js +224 -0
  41. package/dist/layout/dagre/nodeSizing.d.ts +32 -0
  42. package/dist/layout/dagre/nodeSizing.js +202 -0
  43. package/dist/layout/edges/buildEdges.d.ts +18 -0
  44. package/dist/layout/edges/buildEdges.js +405 -0
  45. package/dist/layout/edges/classify.d.ts +13 -0
  46. package/dist/layout/edges/classify.js +36 -0
  47. package/dist/layout/edges/diamondHandles.d.ts +23 -0
  48. package/dist/layout/edges/diamondHandles.js +108 -0
  49. package/dist/layout/edges/index.d.ts +10 -0
  50. package/dist/layout/edges/index.js +8 -0
  51. package/dist/layout/edges/paths.d.ts +57 -0
  52. package/dist/layout/edges/paths.js +279 -0
  53. package/dist/layout/index.d.ts +59 -0
  54. package/dist/layout/index.js +131 -0
  55. package/dist/layout/intersect/circle.d.ts +2 -0
  56. package/dist/layout/intersect/circle.js +14 -0
  57. package/dist/layout/intersect/diamond.d.ts +9 -0
  58. package/dist/layout/intersect/diamond.js +21 -0
  59. package/dist/layout/intersect/index.d.ts +17 -0
  60. package/dist/layout/intersect/index.js +28 -0
  61. package/dist/layout/intersect/rect.d.ts +10 -0
  62. package/dist/layout/intersect/rect.js +31 -0
  63. package/dist/layout/intersect/rectRounded.d.ts +20 -0
  64. package/dist/layout/intersect/rectRounded.js +48 -0
  65. package/dist/layout/mindmapLayout.d.ts +13 -0
  66. package/dist/layout/mindmapLayout.js +299 -0
  67. package/dist/layout/sequenceLayout.d.ts +24 -0
  68. package/dist/layout/sequenceLayout.js +414 -0
  69. package/dist/layout/subgraph.d.ts +26 -0
  70. package/dist/layout/subgraph.js +63 -0
  71. package/dist/layout/types.d.ts +34 -0
  72. package/dist/layout/types.js +8 -0
  73. package/dist/parsers/classDiagram.d.ts +2 -0
  74. package/dist/parsers/classDiagram.js +105 -0
  75. package/dist/parsers/er.d.ts +2 -0
  76. package/dist/parsers/er.js +97 -0
  77. package/dist/parsers/flowchart.d.ts +2 -0
  78. package/dist/parsers/flowchart.js +191 -0
  79. package/dist/parsers/helpers.d.ts +4 -0
  80. package/dist/parsers/helpers.js +8 -0
  81. package/dist/parsers/index.d.ts +7 -0
  82. package/dist/parsers/index.js +19 -0
  83. package/dist/parsers/mindmap.d.ts +2 -0
  84. package/dist/parsers/mindmap.js +124 -0
  85. package/dist/parsers/sequence.d.ts +18 -0
  86. package/dist/parsers/sequence.js +196 -0
  87. package/dist/parsers/state.d.ts +2 -0
  88. package/dist/parsers/state.js +68 -0
  89. package/dist/react.d.ts +7 -0
  90. package/dist/react.js +9 -0
  91. package/dist/reactDefaults.d.ts +5 -0
  92. package/dist/reactDefaults.js +37 -0
  93. package/dist/renderMarkdown.d.ts +9 -0
  94. package/dist/renderMarkdown.js +103 -0
  95. package/dist/swagger.d.ts +113 -0
  96. package/dist/swagger.js +551 -0
  97. package/dist/theme/dark.d.ts +8 -0
  98. package/dist/theme/dark.js +190 -0
  99. package/dist/theme/index.d.ts +18 -0
  100. package/dist/theme/index.js +29 -0
  101. package/dist/theme/light.d.ts +8 -0
  102. package/dist/theme/light.js +190 -0
  103. package/dist/theme/types.d.ts +97 -0
  104. package/dist/theme/types.js +7 -0
  105. package/dist/types.d.ts +235 -0
  106. package/dist/types.js +1 -0
  107. package/package.json +74 -0
@@ -0,0 +1,205 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * SequenceNodes.tsx — React Flow node components for sequence diagrams.
4
+ *
5
+ * Node types:
6
+ * - sequenceParticipant: Clickable participant boxes at top/bottom
7
+ * - sequenceLifeline: Dashed vertical line behind messages
8
+ * - sequenceAnchor: Invisible 2px nodes at message endpoints (edges attach here)
9
+ * - sequenceNote: Styled note boxes spanning attached participants
10
+ * - sequenceBlock: Alt/loop/opt overlay rectangles
11
+ * - sequenceMessageLabel: Text label positioned above message edges
12
+ * - sequenceNumber: Numbered circle on the lifeline for autonumbering
13
+ */
14
+ import { memo } from 'react';
15
+ import { Handle, Position } from '@xyflow/react';
16
+ import { useTheme } from '../../ThemeContext.js';
17
+ const invisibleHandle = {
18
+ opacity: 0,
19
+ width: 1,
20
+ height: 1,
21
+ border: 'none',
22
+ background: 'transparent',
23
+ pointerEvents: 'none',
24
+ };
25
+ export const SequenceParticipantNode = memo(function SequenceParticipantNode({ data }) {
26
+ const theme = useTheme();
27
+ const label = String(data.label ?? '');
28
+ const participantType = String(data.participantType ?? 'participant');
29
+ const meta = data.meta;
30
+ const w = data.layoutWidth ?? 150;
31
+ const h = data.layoutHeight ?? 40;
32
+ if (participantType === 'actor') {
33
+ // Stick figure actor
34
+ const cx = w / 2;
35
+ return (_jsxs("div", { style: { width: w, height: h + 16, position: 'relative', cursor: 'pointer' }, children: [_jsxs("svg", { width: w, height: h + 16, viewBox: `0 0 ${w} ${h + 16}`, children: [_jsx("circle", { cx: cx, cy: 10, r: 8, fill: "none", stroke: theme.color.orange1, strokeWidth: 1.5 }), _jsx("line", { x1: cx, y1: 18, x2: cx, y2: 30, stroke: theme.color.orange1, strokeWidth: 1.5 }), _jsx("line", { x1: cx - 12, y1: 22, x2: cx + 12, y2: 22, stroke: theme.color.orange1, strokeWidth: 1.5 }), _jsx("line", { x1: cx, y1: 30, x2: cx - 8, y2: 40, stroke: theme.color.orange1, strokeWidth: 1.5 }), _jsx("line", { x1: cx, y1: 30, x2: cx + 8, y2: 40, stroke: theme.color.orange1, strokeWidth: 1.5 }), _jsx("text", { x: cx, y: h + 12, textAnchor: "middle", fill: theme.color.gray4, fontSize: 12, fontWeight: 600, fontFamily: theme.font.family, children: label })] }), _jsx(Handle, { type: "source", position: Position.Bottom, style: invisibleHandle }), _jsx(Handle, { type: "target", position: Position.Top, style: invisibleHandle })] }));
36
+ }
37
+ // Box participant
38
+ return (_jsxs("div", { style: {
39
+ width: w,
40
+ height: h,
41
+ backgroundColor: theme.color.orange1,
42
+ borderRadius: theme.radius.md,
43
+ display: 'flex',
44
+ alignItems: 'center',
45
+ justifyContent: 'center',
46
+ cursor: 'pointer',
47
+ fontFamily: theme.font.family,
48
+ boxShadow: meta ? `0 0 0 2px ${theme.color.orange2}` : undefined,
49
+ }, children: [_jsx("span", { style: {
50
+ color: theme.color.white,
51
+ fontSize: theme.font.size.sm,
52
+ fontWeight: theme.font.weight.bold,
53
+ textAlign: 'center',
54
+ whiteSpace: 'pre-wrap',
55
+ lineHeight: 1.2,
56
+ overflow: 'hidden',
57
+ padding: '0 4px',
58
+ }, children: label }), _jsx(Handle, { type: "source", position: Position.Bottom, style: invisibleHandle }), _jsx(Handle, { type: "target", position: Position.Top, style: invisibleHandle }), _jsx(Handle, { type: "source", id: "left", position: Position.Left, style: invisibleHandle }), _jsx(Handle, { type: "target", id: "left", position: Position.Left, style: invisibleHandle }), _jsx(Handle, { type: "source", id: "right", position: Position.Right, style: invisibleHandle }), _jsx(Handle, { type: "target", id: "right", position: Position.Right, style: invisibleHandle })] }));
59
+ });
60
+ // ─── Lifeline Node ─────────────────────────────────────────────────────────
61
+ export const SequenceLifelineNode = memo(function SequenceLifelineNode({ data }) {
62
+ const theme = useTheme();
63
+ const height = data.lifelineHeight ?? 200;
64
+ return (_jsx("div", { style: {
65
+ width: 2,
66
+ height,
67
+ pointerEvents: 'none',
68
+ }, children: _jsx("svg", { width: 2, height: height, style: { overflow: 'visible' }, children: _jsx("line", { x1: 1, y1: 0, x2: 1, y2: height, stroke: theme.color.gray2, strokeWidth: 1.5, strokeDasharray: "6,4" }) }) }));
69
+ });
70
+ // ─── Anchor Node ───────────────────────────────────────────────────────────
71
+ export const SequenceAnchorNode = memo(function SequenceAnchorNode() {
72
+ return (_jsxs("div", { style: { width: 2, height: 2, pointerEvents: 'none' }, children: [_jsx(Handle, { type: "source", position: Position.Right, style: invisibleHandle }), _jsx(Handle, { type: "target", position: Position.Left, style: invisibleHandle }), _jsx(Handle, { type: "source", id: "left", position: Position.Left, style: invisibleHandle }), _jsx(Handle, { type: "target", id: "right", position: Position.Right, style: invisibleHandle }), _jsx(Handle, { type: "source", id: "top", position: Position.Top, style: invisibleHandle }), _jsx(Handle, { type: "target", id: "bottom", position: Position.Bottom, style: invisibleHandle })] }));
73
+ });
74
+ // ─── Note Node ─────────────────────────────────────────────────────────────
75
+ export const SequenceNoteNode = memo(function SequenceNoteNode({ data }) {
76
+ const theme = useTheme();
77
+ const label = String(data.label ?? '');
78
+ const w = data.noteWidth ?? 140;
79
+ const h = data.noteHeight ?? 36;
80
+ const ns = theme.nodeStyles.sequence;
81
+ return (_jsx("div", { style: {
82
+ width: w,
83
+ backgroundColor: theme.color.darkBg3,
84
+ border: `${ns.note.borderWidth} solid ${theme.color.gray2}`,
85
+ borderRadius: theme.radius.sm,
86
+ display: 'flex',
87
+ alignItems: 'center',
88
+ justifyContent: 'center',
89
+ padding: `${ns.note.paddingY} ${theme.space[2]}`,
90
+ pointerEvents: 'none',
91
+ boxSizing: 'border-box',
92
+ }, children: _jsx("span", { style: {
93
+ color: theme.color.gray4,
94
+ fontSize: theme.font.size.sm,
95
+ fontFamily: theme.font.family,
96
+ textAlign: 'center',
97
+ lineHeight: theme.lineHeight.tight,
98
+ whiteSpace: 'pre-wrap',
99
+ wordBreak: 'break-word',
100
+ overflow: 'hidden',
101
+ }, children: label }) }));
102
+ });
103
+ // ─── Message Label Node ───────────────────────────────────────────────────
104
+ export const SequenceMessageLabelNode = memo(function SequenceMessageLabelNode({ data }) {
105
+ const theme = useTheme();
106
+ const label = String(data.label ?? '');
107
+ const w = data.labelWidth ?? 120;
108
+ return (_jsx("div", { style: {
109
+ width: w,
110
+ display: 'flex',
111
+ justifyContent: 'center',
112
+ pointerEvents: 'none',
113
+ }, children: _jsx("span", { style: {
114
+ color: theme.color.gray4,
115
+ fontSize: theme.font.size.sm,
116
+ fontFamily: theme.font.family,
117
+ fontWeight: theme.font.weight.medium,
118
+ textAlign: 'center',
119
+ whiteSpace: 'pre-wrap',
120
+ lineHeight: 1.3,
121
+ }, children: label }) }));
122
+ });
123
+ // ─── Number Circle Node ──────────────────────────────────────────────────
124
+ export const SequenceNumberNode = memo(function SequenceNumberNode({ data }) {
125
+ const theme = useTheme();
126
+ const num = data.number ?? 1;
127
+ const ns = theme.nodeStyles.sequence;
128
+ const size = ns.number.size;
129
+ return (_jsx("div", { style: {
130
+ width: size,
131
+ height: size,
132
+ borderRadius: '50%',
133
+ border: `${ns.number.borderWidth} solid ${theme.color.gray3}`,
134
+ backgroundColor: theme.color.darkBg2,
135
+ display: 'flex',
136
+ alignItems: 'center',
137
+ justifyContent: 'center',
138
+ pointerEvents: 'none',
139
+ }, children: _jsx("span", { style: {
140
+ color: theme.color.gray4,
141
+ fontSize: ns.number.fontSize,
142
+ fontFamily: theme.font.family,
143
+ fontWeight: theme.font.weight.semibold,
144
+ lineHeight: 1,
145
+ }, children: num }) }));
146
+ });
147
+ export const SequenceBlockNode = memo(function SequenceBlockNode({ data }) {
148
+ const theme = useTheme();
149
+ const ns = theme.nodeStyles.sequence;
150
+ const blockType = String(data.blockType ?? 'alt');
151
+ const blockLabel = String(data.blockLabel ?? '');
152
+ const w = data.blockWidth ?? 300;
153
+ const h = data.blockHeight ?? 100;
154
+ const sections = data.sections;
155
+ const messageY = data.messageY;
156
+ const blockStartY = data.blockStartY ?? 0;
157
+ return (_jsxs("div", { style: {
158
+ width: w,
159
+ height: h,
160
+ border: `${ns.block.borderWidth} dashed ${theme.color.gray2}`,
161
+ borderRadius: theme.radius.sm,
162
+ position: 'relative',
163
+ pointerEvents: 'none',
164
+ }, children: [_jsx("div", { style: {
165
+ position: 'absolute',
166
+ top: 0,
167
+ left: 0,
168
+ backgroundColor: theme.color.gray2,
169
+ borderRadius: `${theme.radius.sm} 0 ${theme.radius.sm} 0`,
170
+ padding: `2px ${theme.space[2]}`,
171
+ }, children: _jsx("span", { style: {
172
+ color: theme.color.gray4,
173
+ fontSize: theme.font.size.sm,
174
+ fontWeight: theme.font.weight.semibold,
175
+ fontFamily: theme.font.family,
176
+ }, children: blockType }) }), blockLabel && (_jsx("div", { style: {
177
+ position: 'absolute',
178
+ top: 2,
179
+ left: blockType.length * ns.block.labelCharWidth + ns.block.labelOffsetBase,
180
+ }, children: _jsxs("span", { style: {
181
+ color: theme.color.gray3,
182
+ fontSize: theme.font.size.sm,
183
+ fontFamily: theme.font.family,
184
+ fontStyle: 'italic',
185
+ }, children: ["[", blockLabel, "]"] }) })), sections && messageY && sections.map((section, i) => {
186
+ const sectionY = messageY[section.startIndex]
187
+ ? messageY[section.startIndex] - blockStartY - 25
188
+ : h / 2;
189
+ return (_jsx("div", { style: {
190
+ position: 'absolute',
191
+ top: sectionY,
192
+ left: 0,
193
+ width: '100%',
194
+ borderTop: `${ns.block.dividerWidth} dashed ${theme.color.gray2}`,
195
+ }, children: _jsxs("span", { style: {
196
+ position: 'absolute',
197
+ top: 2,
198
+ left: Number(theme.space[2].replace('px', '')),
199
+ color: theme.color.gray3,
200
+ fontSize: theme.font.size.sm,
201
+ fontFamily: theme.font.family,
202
+ fontStyle: 'italic',
203
+ }, children: ["[", section.label || 'else', "]"] }) }, i));
204
+ })] }));
205
+ });
@@ -0,0 +1,5 @@
1
+ interface Props {
2
+ data: Record<string, unknown>;
3
+ }
4
+ export declare const StateNode: import("react").NamedExoticComponent<Props>;
5
+ export {};
@@ -0,0 +1,71 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ import { Handle, Position } from '@xyflow/react';
4
+ import { useTheme } from '../../ThemeContext.js';
5
+ const invisibleHandle = {
6
+ opacity: 0,
7
+ width: 1,
8
+ height: 1,
9
+ border: 'none',
10
+ background: 'transparent',
11
+ pointerEvents: 'none',
12
+ };
13
+ function spreadPositions(count) {
14
+ const n = Math.max(1, count);
15
+ return Array.from({ length: n }, (_, i) => ((i + 1) / (n + 1)) * 100);
16
+ }
17
+ const SIDE_SLOTS = 5;
18
+ const sideSlotPositions = spreadPositions(SIDE_SLOTS); // [~17%, 33%, 50%, 67%, 83%]
19
+ function SideHandles({ side }) {
20
+ const position = side === 'left' ? Position.Left : Position.Right;
21
+ return (_jsxs(_Fragment, { children: [sideSlotPositions.map((pct, i) => (_jsx(Handle, { type: "target", id: `back-${side}-target-${i}`, position: position, style: { ...invisibleHandle, top: `${pct}%` } }, `${side}-t-${i}`))), sideSlotPositions.map((pct, i) => (_jsx(Handle, { type: "source", id: `back-${side}-source-${i}`, position: position, style: { ...invisibleHandle, top: `${pct}%` } }, `${side}-s-${i}`)))] }));
22
+ }
23
+ function StateHandles({ fwIn, fwOut }) {
24
+ const targetPositions = spreadPositions(fwIn);
25
+ const sourcePositions = spreadPositions(fwOut);
26
+ return (_jsxs(_Fragment, { children: [targetPositions.map((pct, i) => (_jsx(Handle, { type: "target", id: `fw-target-${i}`, position: Position.Top, style: { ...invisibleHandle, left: `${pct}%` } }, `ft-${i}`))), sourcePositions.map((pct, i) => (_jsx(Handle, { type: "source", id: `fw-source-${i}`, position: Position.Bottom, style: { ...invisibleHandle, left: `${pct}%` } }, `fs-${i}`))), _jsx(SideHandles, { side: "left" }), _jsx(SideHandles, { side: "right" }), _jsx(Handle, { type: "target", id: "lateral-target", position: Position.Left, style: invisibleHandle }), _jsx(Handle, { type: "source", id: "lateral-source", position: Position.Right, style: invisibleHandle })] }));
27
+ }
28
+ export const StateNode = memo(function StateNode({ data }) {
29
+ const theme = useTheme();
30
+ const label = String(data.label ?? '');
31
+ const shape = String(data.shape ?? 'round');
32
+ const ns = theme.nodeStyles.state;
33
+ const fwIn = Math.max(1, data.fwIn ?? 1);
34
+ const fwOut = Math.max(1, data.fwOut ?? 1);
35
+ const layoutWidth = data.layoutWidth;
36
+ const layoutHeight = data.layoutHeight;
37
+ // Start state: filled circle
38
+ if (shape === 'circle') {
39
+ return (_jsx("div", { style: {
40
+ width: layoutWidth, height: layoutHeight,
41
+ backgroundColor: theme.color.gray5, borderRadius: theme.radius.full,
42
+ }, children: _jsx(StateHandles, { fwIn: fwIn, fwOut: fwOut }) }));
43
+ }
44
+ // End state: bullseye (outer ring + inner filled dot).
45
+ // layoutWidth/layoutHeight include the border, so use box-sizing: border-box.
46
+ if (shape === 'doublecircle') {
47
+ const innerSize = layoutWidth - 16; // outer - padding(8) - border(3)*2
48
+ return (_jsxs("div", { style: {
49
+ width: layoutWidth, height: layoutHeight,
50
+ boxSizing: 'border-box',
51
+ borderRadius: theme.radius.full,
52
+ border: `${theme.borderWidth.md} solid ${theme.color.gray5}`,
53
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
54
+ }, children: [_jsx("div", { style: {
55
+ width: innerSize, height: innerSize,
56
+ backgroundColor: theme.color.gray5, borderRadius: theme.radius.full,
57
+ } }), _jsx(StateHandles, { fwIn: fwIn, fwOut: fwOut })] }));
58
+ }
59
+ return (_jsxs("div", { style: {
60
+ backgroundColor: theme.color.darkBg2, border: `${theme.borderWidth.sm} solid ${theme.color.gray2}`,
61
+ borderLeft: `${ns.rect.accentWidth} solid ${theme.color.orange1}`, borderRadius: theme.radius.pill,
62
+ padding: `${theme.space[3]} ${theme.space[6]}`,
63
+ width: layoutWidth, height: layoutHeight,
64
+ boxSizing: 'border-box',
65
+ fontFamily: theme.font.family, cursor: 'pointer',
66
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
67
+ }, children: [_jsx("div", { style: {
68
+ color: theme.color.gray5, fontSize: theme.font.size.lg, fontWeight: theme.font.weight.semibold,
69
+ textAlign: 'center', whiteSpace: 'nowrap',
70
+ }, children: label }), _jsx(StateHandles, { fwIn: fwIn, fwOut: fwOut })] }));
71
+ });
@@ -0,0 +1,5 @@
1
+ interface Props {
2
+ data: Record<string, unknown>;
3
+ }
4
+ export declare const SubgraphNode: import("react").NamedExoticComponent<Props>;
5
+ export {};
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { memo } from 'react';
3
+ import { useTheme } from '../../ThemeContext.js';
4
+ export const SubgraphNode = memo(function SubgraphNode({ data }) {
5
+ const theme = useTheme();
6
+ const label = String(data.label ?? '');
7
+ const ns = theme.nodeStyles.subgraph;
8
+ return (_jsx("div", { style: {
9
+ fontSize: theme.font.size.sm,
10
+ fontWeight: theme.font.weight.semibold,
11
+ fontFamily: theme.font.family,
12
+ color: theme.color.gray3,
13
+ padding: `${theme.space[1]} ${theme.space[2]}`,
14
+ pointerEvents: ns.pointerEvents,
15
+ }, children: label }));
16
+ });
@@ -0,0 +1,138 @@
1
+ /**
2
+ * config.ts — Single source of truth for the entire @graph-artifact/core package.
3
+ *
4
+ * Every configurable surface lives here: base theme selection, theme overrides,
5
+ * canvas behavior, layout tuning, node type registry, node children registry,
6
+ * and layout mappings.
7
+ *
8
+ * Consumers call `configure()` once at module load time. Every internal module
9
+ * reads from `getConfig()`. Nothing is hardcoded elsewhere.
10
+ */
11
+ import type { ThemeOverride, NodeComponent, NodeChildComponent } from './types.js';
12
+ export interface GraphConfig {
13
+ /** Which theme to use as the base token set ('dark', 'light', or any registered name) */
14
+ baseTheme: string;
15
+ /** Partial theme overrides — deep-merged on top of the base theme at runtime */
16
+ theme: ThemeOverride;
17
+ /** Dagre layout tuning */
18
+ layout: {
19
+ rankSep: number;
20
+ erRankSep: number;
21
+ stateRankSep: number;
22
+ nodeSep: number;
23
+ erNodeSep: number;
24
+ stateNodeSep: number;
25
+ subgraphPadding: number;
26
+ /** Numeric pixel sizes for dagre node dimension calculations.
27
+ * These are the SINGLE SOURCE OF TRUTH for node dimensions.
28
+ * Components receive these as layoutWidth/layoutHeight via node data. */
29
+ nodeSizing: {
30
+ charWidth: number;
31
+ common: {
32
+ minWidth: number;
33
+ maxWidth: number;
34
+ lineBaseHeight: number;
35
+ lineStepHeight: number;
36
+ };
37
+ er: {
38
+ width: number;
39
+ headerHeight: number;
40
+ rowHeight: number;
41
+ borderExtra: number;
42
+ };
43
+ class: {
44
+ width: number;
45
+ headerHeight: number;
46
+ rowHeight: number;
47
+ dividerGap: number;
48
+ };
49
+ state: {
50
+ circleSize: number;
51
+ doublecirclePad: number;
52
+ doublecircleBorder: number;
53
+ minWidth: number;
54
+ height: number;
55
+ padding: number;
56
+ borderExtra: number;
57
+ };
58
+ flow: {
59
+ diamondSize: number;
60
+ circleSize: number;
61
+ cylinderWidth: number;
62
+ cylinderHeight: number;
63
+ minWidth: number;
64
+ height: number;
65
+ padding: number;
66
+ };
67
+ };
68
+ sequence: {
69
+ participantWidth: number;
70
+ participantHeight: number;
71
+ participantGap: number;
72
+ baseMessageRowHeight: number;
73
+ selfMessageExtra: number;
74
+ labelLineHeight: number;
75
+ labelGapBelow: number;
76
+ topPadding: number;
77
+ leftPadding: number;
78
+ lifelineStartOffset: number;
79
+ bottomParticipantGap: number;
80
+ anchorWidth: number;
81
+ anchorHeight: number;
82
+ noteBaseHeight: number;
83
+ noteLineHeight: number;
84
+ noteOffsetX: number;
85
+ noteVerticalGap: number;
86
+ notePaddingInner: number;
87
+ blockPaddingX: number;
88
+ blockPaddingTop: number;
89
+ blockPaddingBottom: number;
90
+ numberCircleSize: number;
91
+ textCharWidthEstimate: number;
92
+ maxCollisionIterations: number;
93
+ };
94
+ };
95
+ /** React Flow canvas behavior */
96
+ canvas: {
97
+ minZoom: number;
98
+ maxZoom: number;
99
+ fitView: boolean;
100
+ showBackground: boolean;
101
+ showControls: boolean;
102
+ showMiniMap: boolean;
103
+ backgroundGap: number;
104
+ backgroundSize: number;
105
+ };
106
+ /** Node component registry — maps type names to React components */
107
+ nodeTypes: Record<string, NodeComponent>;
108
+ /** Custom node child components — rendered inside node bodies */
109
+ nodeChildren: Record<string, NodeChildComponent>;
110
+ /** Maps diagram types (e.g. 'flowchart') to node type names (e.g. 'flow') */
111
+ layoutMappings: Record<string, string>;
112
+ /** Product/app copy overrides for host-application messaging. */
113
+ library: {
114
+ nodeDetailEmptyHint: string;
115
+ };
116
+ }
117
+ export interface ConfigureOptions {
118
+ baseTheme?: string;
119
+ theme?: ThemeOverride;
120
+ layout?: Partial<GraphConfig['layout']>;
121
+ canvas?: Partial<GraphConfig['canvas']>;
122
+ nodeTypes?: Record<string, NodeComponent>;
123
+ nodeChildren?: Record<string, NodeChildComponent>;
124
+ layoutMappings?: Record<string, string>;
125
+ library?: Partial<GraphConfig['library']>;
126
+ }
127
+ /** Apply partial config overrides. Call once at module load time. */
128
+ export declare function configure(overrides: ConfigureOptions): void;
129
+ /** Read the current config. All internal modules use this. */
130
+ export declare function getConfig(): Readonly<GraphConfig>;
131
+ /** Restore all defaults. Useful for testing. */
132
+ export declare function resetConfig(): void;
133
+ export declare function registerNodeType(name: string, component: NodeComponent): void;
134
+ export declare function getNodeTypes(): Record<string, NodeComponent>;
135
+ export declare function registerNodeChild(name: string, component: NodeChildComponent): void;
136
+ export declare function getNodeChild(name: string): NodeChildComponent | undefined;
137
+ export declare function registerLayoutMapping(diagramType: string, nodeType: string): void;
138
+ export declare function getLayoutMapping(diagramType: string): string;
package/dist/config.js ADDED
@@ -0,0 +1,165 @@
1
+ /**
2
+ * config.ts — Single source of truth for the entire @graph-artifact/core package.
3
+ *
4
+ * Every configurable surface lives here: base theme selection, theme overrides,
5
+ * canvas behavior, layout tuning, node type registry, node children registry,
6
+ * and layout mappings.
7
+ *
8
+ * Consumers call `configure()` once at module load time. Every internal module
9
+ * reads from `getConfig()`. Nothing is hardcoded elsewhere.
10
+ */
11
+ // ─── Defaults ────────────────────────────────────────────────────────────────
12
+ function createDefaultConfig() {
13
+ return {
14
+ baseTheme: 'dark',
15
+ theme: {},
16
+ layout: {
17
+ rankSep: 30,
18
+ erRankSep: 60,
19
+ stateRankSep: 60,
20
+ nodeSep: 30,
21
+ erNodeSep: 80,
22
+ stateNodeSep: 40,
23
+ subgraphPadding: 16,
24
+ nodeSizing: {
25
+ charWidth: 9,
26
+ common: { minWidth: 120, maxWidth: 560, lineBaseHeight: 16, lineStepHeight: 18 },
27
+ er: { width: 220, headerHeight: 33, rowHeight: 23, borderExtra: 2 },
28
+ class: { width: 240, headerHeight: 33, rowHeight: 20, dividerGap: 17 },
29
+ state: {
30
+ circleSize: 28, doublecirclePad: 8, doublecircleBorder: 3,
31
+ minWidth: 100, height: 40, padding: 32, borderExtra: 6,
32
+ },
33
+ flow: {
34
+ diamondSize: 120, circleSize: 80, cylinderWidth: 120, cylinderHeight: 70,
35
+ minWidth: 120, height: 44, padding: 40,
36
+ },
37
+ },
38
+ sequence: {
39
+ participantWidth: 150,
40
+ participantHeight: 40,
41
+ participantGap: 60,
42
+ baseMessageRowHeight: 55,
43
+ selfMessageExtra: 30,
44
+ labelLineHeight: 16,
45
+ labelGapBelow: 6,
46
+ topPadding: 20,
47
+ leftPadding: 40,
48
+ lifelineStartOffset: 40,
49
+ bottomParticipantGap: 40,
50
+ anchorWidth: 2,
51
+ anchorHeight: 2,
52
+ noteBaseHeight: 36,
53
+ noteLineHeight: 16,
54
+ noteOffsetX: 10,
55
+ noteVerticalGap: 20,
56
+ notePaddingInner: 12,
57
+ blockPaddingX: 20,
58
+ blockPaddingTop: 30,
59
+ blockPaddingBottom: 15,
60
+ numberCircleSize: 22,
61
+ textCharWidthEstimate: 6,
62
+ maxCollisionIterations: 16,
63
+ },
64
+ },
65
+ canvas: {
66
+ minZoom: 0.1,
67
+ maxZoom: 2,
68
+ fitView: true,
69
+ showBackground: true,
70
+ showControls: true,
71
+ showMiniMap: true,
72
+ backgroundGap: 20,
73
+ backgroundSize: 1,
74
+ },
75
+ nodeTypes: {},
76
+ nodeChildren: {},
77
+ layoutMappings: {
78
+ flowchart: 'flow',
79
+ mindmap: 'flow',
80
+ state: 'state',
81
+ er: 'entity',
82
+ class: 'class',
83
+ sequence: 'sequence',
84
+ },
85
+ library: {
86
+ nodeDetailEmptyHint: 'Attach metadata in your host app to show rich notes here.',
87
+ },
88
+ };
89
+ }
90
+ // ─── Singleton ───────────────────────────────────────────────────────────────
91
+ let config = createDefaultConfig();
92
+ // ─── Public API ──────────────────────────────────────────────────────────────
93
+ /** Apply partial config overrides. Call once at module load time. */
94
+ export function configure(overrides) {
95
+ if (overrides.baseTheme !== undefined) {
96
+ config = { ...config, baseTheme: overrides.baseTheme };
97
+ }
98
+ if (overrides.theme) {
99
+ config = { ...config, theme: { ...config.theme, ...overrides.theme } };
100
+ }
101
+ if (overrides.layout) {
102
+ const { nodeSizing: nsOverride, ...flatLayout } = overrides.layout;
103
+ const mergedNs = nsOverride
104
+ ? {
105
+ ...config.layout.nodeSizing,
106
+ ...nsOverride,
107
+ common: { ...config.layout.nodeSizing.common, ...nsOverride.common },
108
+ er: { ...config.layout.nodeSizing.er, ...nsOverride.er },
109
+ class: { ...config.layout.nodeSizing.class, ...nsOverride.class },
110
+ state: { ...config.layout.nodeSizing.state, ...nsOverride.state },
111
+ flow: { ...config.layout.nodeSizing.flow, ...nsOverride.flow },
112
+ }
113
+ : config.layout.nodeSizing;
114
+ const mergedSequence = overrides.layout.sequence
115
+ ? { ...config.layout.sequence, ...overrides.layout.sequence }
116
+ : config.layout.sequence;
117
+ config = {
118
+ ...config,
119
+ layout: { ...config.layout, ...flatLayout, nodeSizing: mergedNs, sequence: mergedSequence },
120
+ };
121
+ }
122
+ if (overrides.canvas) {
123
+ config = { ...config, canvas: { ...config.canvas, ...overrides.canvas } };
124
+ }
125
+ if (overrides.nodeTypes) {
126
+ config = { ...config, nodeTypes: { ...config.nodeTypes, ...overrides.nodeTypes } };
127
+ }
128
+ if (overrides.nodeChildren) {
129
+ config = { ...config, nodeChildren: { ...config.nodeChildren, ...overrides.nodeChildren } };
130
+ }
131
+ if (overrides.layoutMappings) {
132
+ config = { ...config, layoutMappings: { ...config.layoutMappings, ...overrides.layoutMappings } };
133
+ }
134
+ if (overrides.library) {
135
+ config = { ...config, library: { ...config.library, ...overrides.library } };
136
+ }
137
+ }
138
+ /** Read the current config. All internal modules use this. */
139
+ export function getConfig() {
140
+ return config;
141
+ }
142
+ /** Restore all defaults. Useful for testing. */
143
+ export function resetConfig() {
144
+ config = createDefaultConfig();
145
+ }
146
+ // ─── Registry Convenience Functions ──────────────────────────────────────────
147
+ // These mutate the live config — same as calling configure() for a single entry.
148
+ export function registerNodeType(name, component) {
149
+ config.nodeTypes = { ...config.nodeTypes, [name]: component };
150
+ }
151
+ export function getNodeTypes() {
152
+ return config.nodeTypes;
153
+ }
154
+ export function registerNodeChild(name, component) {
155
+ config.nodeChildren = { ...config.nodeChildren, [name]: component };
156
+ }
157
+ export function getNodeChild(name) {
158
+ return config.nodeChildren[name];
159
+ }
160
+ export function registerLayoutMapping(diagramType, nodeType) {
161
+ config.layoutMappings = { ...config.layoutMappings, [diagramType]: nodeType };
162
+ }
163
+ export function getLayoutMapping(diagramType) {
164
+ return config.layoutMappings[diagramType] ?? 'flow';
165
+ }
package/dist/core.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export type { Diagram, NodeMetadata, ThemeOverride, ParsedGraph, ParsedDiagram, ParsedCustomDiagram, ParsedNode, ParsedEdge, ParsedSubgraph, EdgeType, DiagramType, GraphDiagramType, CustomDiagramType, Cardinality, DeepPartial, NodeComponent, NodeChildProps, NodeChildComponent, SequenceParticipant, SequenceMessage, SequenceArrowType, SequenceBlock, SequenceBlockType, SequenceNote, SequenceData, } from './types.js';
2
+ export { configure, getConfig, resetConfig, registerNodeType, getNodeTypes, registerNodeChild, getNodeChild, registerLayoutMapping, getLayoutMapping, } from './config.js';
3
+ export type { GraphConfig, ConfigureOptions } from './config.js';
4
+ export { registerTheme, getThemeTokens, getThemeNames } from './theme/index.js';
5
+ export type { ThemeTokens } from './theme/index.js';
6
+ export { layoutParsedGraph, layoutDiagram } from './layout/index.js';
7
+ export type { LayoutOptions, LayoutResult, GraphLayoutResult, CustomLayoutResult, } from './layout/index.js';
8
+ export { parseMermaid } from './parsers/index.js';
9
+ export { registerDiagramPlugin, getDiagramPlugins } from './diagrams/registry.js';
10
+ export type { DiagramPlugin } from './diagrams/types.js';
11
+ export { createSwaggerPlugin, generateSwaggerFocusedArtifact, generateSwaggerFocusedDiagram, parseSwaggerToGraphFocused, generateSwaggerDiagrams, generateSwaggerDiagram, parseSwaggerToGraph, } from './swagger.js';
12
+ export type { SwaggerDiagramBundle, SwaggerDiagramFlavor, SwaggerFocusedArtifact, SwaggerFocusRequest, SwaggerPlugin, SwaggerPluginConfig, SwaggerEndpointFocus, SwaggerDefinitionFocus, SwaggerGenerateOptions, SwaggerParseOptions, SwaggerPolicyOptions, } from './swagger.js';
package/dist/core.js ADDED
@@ -0,0 +1,7 @@
1
+ // Headless/public core entry (Node-safe: no React Flow CSS side-effects).
2
+ export { configure, getConfig, resetConfig, registerNodeType, getNodeTypes, registerNodeChild, getNodeChild, registerLayoutMapping, getLayoutMapping, } from './config.js';
3
+ export { registerTheme, getThemeTokens, getThemeNames } from './theme/index.js';
4
+ export { layoutParsedGraph, layoutDiagram } from './layout/index.js';
5
+ export { parseMermaid } from './parsers/index.js';
6
+ export { registerDiagramPlugin, getDiagramPlugins } from './diagrams/registry.js';
7
+ export { createSwaggerPlugin, generateSwaggerFocusedArtifact, generateSwaggerFocusedDiagram, parseSwaggerToGraphFocused, generateSwaggerDiagrams, generateSwaggerDiagram, parseSwaggerToGraph, } from './swagger.js';
@@ -0,0 +1,2 @@
1
+ import type { DiagramPlugin } from './types.js';
2
+ export declare function detectDiagramPlugin(syntax: string): DiagramPlugin | null;
@@ -0,0 +1,8 @@
1
+ import { getDiagramPlugins } from './registry.js';
2
+ export function detectDiagramPlugin(syntax) {
3
+ for (const plugin of getDiagramPlugins()) {
4
+ if (plugin.detect(syntax))
5
+ return plugin;
6
+ }
7
+ return null;
8
+ }
@@ -0,0 +1,2 @@
1
+ import type { DiagramPlugin } from './types.js';
2
+ export declare const builtinDiagramPlugins: DiagramPlugin[];