schematex 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 (181) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +379 -0
  3. package/dist/chunk-2MQWZ2XY.cjs +453 -0
  4. package/dist/chunk-2MQWZ2XY.cjs.map +1 -0
  5. package/dist/chunk-2UKC6ZCY.cjs +1803 -0
  6. package/dist/chunk-2UKC6ZCY.cjs.map +1 -0
  7. package/dist/chunk-34X3ZJ6E.cjs +783 -0
  8. package/dist/chunk-34X3ZJ6E.cjs.map +1 -0
  9. package/dist/chunk-3FTUWAXK.cjs +1220 -0
  10. package/dist/chunk-3FTUWAXK.cjs.map +1 -0
  11. package/dist/chunk-3J7TFUOC.js +745 -0
  12. package/dist/chunk-3J7TFUOC.js.map +1 -0
  13. package/dist/chunk-47ZC6EMJ.js +1009 -0
  14. package/dist/chunk-47ZC6EMJ.js.map +1 -0
  15. package/dist/chunk-4DBRNOPA.cjs +750 -0
  16. package/dist/chunk-4DBRNOPA.cjs.map +1 -0
  17. package/dist/chunk-4G7ZIBHN.js +778 -0
  18. package/dist/chunk-4G7ZIBHN.js.map +1 -0
  19. package/dist/chunk-5C7DPDHQ.js +1321 -0
  20. package/dist/chunk-5C7DPDHQ.js.map +1 -0
  21. package/dist/chunk-ADOXGKAK.js +1251 -0
  22. package/dist/chunk-ADOXGKAK.js.map +1 -0
  23. package/dist/chunk-BE5HNDA5.cjs +874 -0
  24. package/dist/chunk-BE5HNDA5.cjs.map +1 -0
  25. package/dist/chunk-CZRM7LT7.js +889 -0
  26. package/dist/chunk-CZRM7LT7.js.map +1 -0
  27. package/dist/chunk-D4JTSPOL.js +1795 -0
  28. package/dist/chunk-D4JTSPOL.js.map +1 -0
  29. package/dist/chunk-DS47NTWZ.cjs +1034 -0
  30. package/dist/chunk-DS47NTWZ.cjs.map +1 -0
  31. package/dist/chunk-FDLZEKEB.js +449 -0
  32. package/dist/chunk-FDLZEKEB.js.map +1 -0
  33. package/dist/chunk-FGPTCDUT.cjs +1851 -0
  34. package/dist/chunk-FGPTCDUT.cjs.map +1 -0
  35. package/dist/chunk-HDKDQAEQ.cjs +86 -0
  36. package/dist/chunk-HDKDQAEQ.cjs.map +1 -0
  37. package/dist/chunk-IX554O5K.js +346 -0
  38. package/dist/chunk-IX554O5K.js.map +1 -0
  39. package/dist/chunk-KLJEK547.js +71 -0
  40. package/dist/chunk-KLJEK547.js.map +1 -0
  41. package/dist/chunk-LMFSHK45.js +1028 -0
  42. package/dist/chunk-LMFSHK45.js.map +1 -0
  43. package/dist/chunk-MDICUK6F.cjs +1258 -0
  44. package/dist/chunk-MDICUK6F.cjs.map +1 -0
  45. package/dist/chunk-N7KOXOMX.cjs +363 -0
  46. package/dist/chunk-N7KOXOMX.cjs.map +1 -0
  47. package/dist/chunk-NYCIK4SU.cjs +775 -0
  48. package/dist/chunk-NYCIK4SU.cjs.map +1 -0
  49. package/dist/chunk-PDPHRZZT.js +770 -0
  50. package/dist/chunk-PDPHRZZT.js.map +1 -0
  51. package/dist/chunk-ROFLJ74T.js +1212 -0
  52. package/dist/chunk-ROFLJ74T.js.map +1 -0
  53. package/dist/chunk-S6BK5DB6.cjs +845 -0
  54. package/dist/chunk-S6BK5DB6.cjs.map +1 -0
  55. package/dist/chunk-U4I37IBN.js +874 -0
  56. package/dist/chunk-U4I37IBN.js.map +1 -0
  57. package/dist/chunk-U5GGE6PJ.js +839 -0
  58. package/dist/chunk-U5GGE6PJ.js.map +1 -0
  59. package/dist/chunk-UHLYS3W5.cjs +1015 -0
  60. package/dist/chunk-UHLYS3W5.cjs.map +1 -0
  61. package/dist/chunk-URSKIHSY.cjs +881 -0
  62. package/dist/chunk-URSKIHSY.cjs.map +1 -0
  63. package/dist/chunk-V6WO7RK7.cjs +1056 -0
  64. package/dist/chunk-V6WO7RK7.cjs.map +1 -0
  65. package/dist/chunk-VFQCTXOX.js +869 -0
  66. package/dist/chunk-VFQCTXOX.js.map +1 -0
  67. package/dist/chunk-XQ52ICHU.cjs +895 -0
  68. package/dist/chunk-XQ52ICHU.cjs.map +1 -0
  69. package/dist/chunk-XX4BKS7Y.js +1051 -0
  70. package/dist/chunk-XX4BKS7Y.js.map +1 -0
  71. package/dist/chunk-XXU36667.js +1844 -0
  72. package/dist/chunk-XXU36667.js.map +1 -0
  73. package/dist/chunk-ZX7QKZK2.cjs +1326 -0
  74. package/dist/chunk-ZX7QKZK2.cjs.map +1 -0
  75. package/dist/diagrams/blockdiagram/index.cjs +25 -0
  76. package/dist/diagrams/blockdiagram/index.cjs.map +1 -0
  77. package/dist/diagrams/blockdiagram/index.d.cts +67 -0
  78. package/dist/diagrams/blockdiagram/index.d.ts +67 -0
  79. package/dist/diagrams/blockdiagram/index.js +4 -0
  80. package/dist/diagrams/blockdiagram/index.js.map +1 -0
  81. package/dist/diagrams/circuit/index.cjs +34 -0
  82. package/dist/diagrams/circuit/index.cjs.map +1 -0
  83. package/dist/diagrams/circuit/index.d.cts +138 -0
  84. package/dist/diagrams/circuit/index.d.ts +138 -0
  85. package/dist/diagrams/circuit/index.js +5 -0
  86. package/dist/diagrams/circuit/index.js.map +1 -0
  87. package/dist/diagrams/ecomap/index.cjs +30 -0
  88. package/dist/diagrams/ecomap/index.cjs.map +1 -0
  89. package/dist/diagrams/ecomap/index.d.cts +15 -0
  90. package/dist/diagrams/ecomap/index.d.ts +15 -0
  91. package/dist/diagrams/ecomap/index.js +5 -0
  92. package/dist/diagrams/ecomap/index.js.map +1 -0
  93. package/dist/diagrams/entity/index.cjs +26 -0
  94. package/dist/diagrams/entity/index.cjs.map +1 -0
  95. package/dist/diagrams/entity/index.d.cts +54 -0
  96. package/dist/diagrams/entity/index.d.ts +54 -0
  97. package/dist/diagrams/entity/index.js +5 -0
  98. package/dist/diagrams/entity/index.js.map +1 -0
  99. package/dist/diagrams/fishbone/index.cjs +34 -0
  100. package/dist/diagrams/fishbone/index.cjs.map +1 -0
  101. package/dist/diagrams/fishbone/index.d.cts +185 -0
  102. package/dist/diagrams/fishbone/index.d.ts +185 -0
  103. package/dist/diagrams/fishbone/index.js +5 -0
  104. package/dist/diagrams/fishbone/index.js.map +1 -0
  105. package/dist/diagrams/flowchart/index.cjs +34 -0
  106. package/dist/diagrams/flowchart/index.cjs.map +1 -0
  107. package/dist/diagrams/flowchart/index.d.cts +2 -0
  108. package/dist/diagrams/flowchart/index.d.ts +2 -0
  109. package/dist/diagrams/flowchart/index.js +5 -0
  110. package/dist/diagrams/flowchart/index.js.map +1 -0
  111. package/dist/diagrams/genogram/index.cjs +38 -0
  112. package/dist/diagrams/genogram/index.cjs.map +1 -0
  113. package/dist/diagrams/genogram/index.d.cts +20 -0
  114. package/dist/diagrams/genogram/index.d.ts +20 -0
  115. package/dist/diagrams/genogram/index.js +5 -0
  116. package/dist/diagrams/genogram/index.js.map +1 -0
  117. package/dist/diagrams/ladder/index.cjs +26 -0
  118. package/dist/diagrams/ladder/index.cjs.map +1 -0
  119. package/dist/diagrams/ladder/index.d.cts +49 -0
  120. package/dist/diagrams/ladder/index.d.ts +49 -0
  121. package/dist/diagrams/ladder/index.js +5 -0
  122. package/dist/diagrams/ladder/index.js.map +1 -0
  123. package/dist/diagrams/logic/index.cjs +26 -0
  124. package/dist/diagrams/logic/index.cjs.map +1 -0
  125. package/dist/diagrams/logic/index.d.cts +73 -0
  126. package/dist/diagrams/logic/index.d.ts +73 -0
  127. package/dist/diagrams/logic/index.js +5 -0
  128. package/dist/diagrams/logic/index.js.map +1 -0
  129. package/dist/diagrams/orgchart/index.cjs +30 -0
  130. package/dist/diagrams/orgchart/index.cjs.map +1 -0
  131. package/dist/diagrams/orgchart/index.d.cts +100 -0
  132. package/dist/diagrams/orgchart/index.d.ts +100 -0
  133. package/dist/diagrams/orgchart/index.js +5 -0
  134. package/dist/diagrams/orgchart/index.js.map +1 -0
  135. package/dist/diagrams/pedigree/index.cjs +30 -0
  136. package/dist/diagrams/pedigree/index.cjs.map +1 -0
  137. package/dist/diagrams/pedigree/index.d.cts +15 -0
  138. package/dist/diagrams/pedigree/index.d.ts +15 -0
  139. package/dist/diagrams/pedigree/index.js +5 -0
  140. package/dist/diagrams/pedigree/index.js.map +1 -0
  141. package/dist/diagrams/phylo/index.cjs +30 -0
  142. package/dist/diagrams/phylo/index.cjs.map +1 -0
  143. package/dist/diagrams/phylo/index.d.cts +32 -0
  144. package/dist/diagrams/phylo/index.d.ts +32 -0
  145. package/dist/diagrams/phylo/index.js +5 -0
  146. package/dist/diagrams/phylo/index.js.map +1 -0
  147. package/dist/diagrams/sld/index.cjs +26 -0
  148. package/dist/diagrams/sld/index.cjs.map +1 -0
  149. package/dist/diagrams/sld/index.d.cts +58 -0
  150. package/dist/diagrams/sld/index.d.ts +58 -0
  151. package/dist/diagrams/sld/index.js +5 -0
  152. package/dist/diagrams/sld/index.js.map +1 -0
  153. package/dist/diagrams/sociogram/index.cjs +26 -0
  154. package/dist/diagrams/sociogram/index.cjs.map +1 -0
  155. package/dist/diagrams/sociogram/index.d.cts +76 -0
  156. package/dist/diagrams/sociogram/index.d.ts +76 -0
  157. package/dist/diagrams/sociogram/index.js +5 -0
  158. package/dist/diagrams/sociogram/index.js.map +1 -0
  159. package/dist/diagrams/timing/index.cjs +21 -0
  160. package/dist/diagrams/timing/index.cjs.map +1 -0
  161. package/dist/diagrams/timing/index.d.cts +9 -0
  162. package/dist/diagrams/timing/index.d.ts +9 -0
  163. package/dist/diagrams/timing/index.js +4 -0
  164. package/dist/diagrams/timing/index.js.map +1 -0
  165. package/dist/diagrams/venn/index.cjs +38 -0
  166. package/dist/diagrams/venn/index.cjs.map +1 -0
  167. package/dist/diagrams/venn/index.d.cts +69 -0
  168. package/dist/diagrams/venn/index.d.ts +69 -0
  169. package/dist/diagrams/venn/index.js +5 -0
  170. package/dist/diagrams/venn/index.js.map +1 -0
  171. package/dist/index-BSlza1YY.d.ts +150 -0
  172. package/dist/index-BXefHVce.d.cts +150 -0
  173. package/dist/index.cjs +2033 -0
  174. package/dist/index.cjs.map +1 -0
  175. package/dist/index.d.cts +29 -0
  176. package/dist/index.d.ts +29 -0
  177. package/dist/index.js +1944 -0
  178. package/dist/index.js.map +1 -0
  179. package/dist/types-DqfcYkcY.d.cts +741 -0
  180. package/dist/types-DqfcYkcY.d.ts +741 -0
  181. package/package.json +163 -0
@@ -0,0 +1,1009 @@
1
+ import { resolveBaseTheme } from './chunk-IX554O5K.js';
2
+ import { title, desc, el, text, path, rect, group, svgRoot, escapeXml, circle } from './chunk-KLJEK547.js';
3
+
4
+ // src/diagrams/orgchart/parser.ts
5
+ var OrgchartParseError = class extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "OrgchartParseError";
9
+ }
10
+ };
11
+ var ROLE_ICONS = {
12
+ ceo: "CEO",
13
+ cto: "CTO",
14
+ cfo: "CFO",
15
+ coo: "COO",
16
+ cmo: "CMO",
17
+ cpo: "CPO",
18
+ vp: "VP",
19
+ engineer: "Engineer",
20
+ engineering: "Engineer",
21
+ designer: "Designer",
22
+ design: "Designer",
23
+ sales: "Sales",
24
+ hr: "HR",
25
+ legal: "Legal",
26
+ ops: "Ops",
27
+ operations: "Ops",
28
+ marketing: "Marketing",
29
+ product: "Product",
30
+ data: "Data",
31
+ advisor: "Advisor",
32
+ intern: "Intern",
33
+ vacant: "Vacant"
34
+ };
35
+ var NODE_KIND_KEYWORDS = /* @__PURE__ */ new Set([
36
+ "person",
37
+ "role",
38
+ "open",
39
+ "draft",
40
+ "tbh",
41
+ "advisor",
42
+ "external"
43
+ ]);
44
+ function stripComment(line) {
45
+ let out = "";
46
+ let inQuote = false;
47
+ for (const ch of line) {
48
+ if (ch === '"') inQuote = !inQuote;
49
+ if ((ch === "#" || ch === "/" && out.endsWith("/")) && !inQuote) {
50
+ if (ch === "/") return out.slice(0, -1);
51
+ return out;
52
+ }
53
+ out += ch;
54
+ }
55
+ return out;
56
+ }
57
+ function stripQuotes(v) {
58
+ const t = v.trim();
59
+ if (t.length >= 2 && t.startsWith('"') && t.endsWith('"')) return t.slice(1, -1);
60
+ return t;
61
+ }
62
+ function splitTopLevelCommas(inside) {
63
+ const parts = [];
64
+ let cur = "";
65
+ let inQuote = false;
66
+ for (const ch of inside) {
67
+ if (ch === '"') inQuote = !inQuote;
68
+ if (ch === "," && !inQuote) {
69
+ parts.push(cur);
70
+ cur = "";
71
+ } else {
72
+ cur += ch;
73
+ }
74
+ }
75
+ if (cur.trim()) parts.push(cur);
76
+ return parts;
77
+ }
78
+ function parseProps(inside) {
79
+ const out = {};
80
+ for (const p of splitTopLevelCommas(inside)) {
81
+ const s = p.trim();
82
+ if (!s) continue;
83
+ const colon = s.indexOf(":");
84
+ if (colon < 0) {
85
+ out[s.toLowerCase()] = "true";
86
+ continue;
87
+ }
88
+ const k = s.slice(0, colon).trim().toLowerCase();
89
+ const v = s.slice(colon + 1).trim();
90
+ out[k] = stripQuotes(v);
91
+ }
92
+ return out;
93
+ }
94
+ function tokenizeLines(text2) {
95
+ const result = [];
96
+ for (const raw of text2.split("\n")) {
97
+ const stripped = stripComment(raw.replace(/\r$/, ""));
98
+ if (!stripped.trim()) continue;
99
+ const match = stripped.match(/^(\s*)(.*)$/);
100
+ if (!match) continue;
101
+ const indent = match[1].replace(/\t/g, " ").length;
102
+ result.push({ indent, text: match[2].trim() });
103
+ }
104
+ return result;
105
+ }
106
+ function parseNodeLine(line) {
107
+ let kind = "person";
108
+ let rest = line;
109
+ const firstSp = line.indexOf(" ");
110
+ if (firstSp > 0) {
111
+ const first = line.slice(0, firstSp).toLowerCase();
112
+ if (NODE_KIND_KEYWORDS.has(first)) {
113
+ if (first === "role" || first === "open") kind = "role";
114
+ else if (first === "draft" || first === "tbh") kind = "draft";
115
+ else if (first === "advisor" || first === "external") kind = "advisor";
116
+ else kind = "person";
117
+ rest = line.slice(firstSp + 1).trim();
118
+ }
119
+ }
120
+ const colonIdx = rest.indexOf(":");
121
+ if (colonIdx < 0) return null;
122
+ const id = rest.slice(0, colonIdx).trim();
123
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(id)) return null;
124
+ let tail = rest.slice(colonIdx + 1).trim();
125
+ let props = {};
126
+ const propsMatch = tail.match(/\[([^\]]*)\]\s*$/);
127
+ if (propsMatch) {
128
+ props = parseProps(propsMatch[1]);
129
+ tail = tail.slice(0, tail.length - propsMatch[0].length).trim();
130
+ }
131
+ const fields = [];
132
+ let cur = "";
133
+ let inQuote = false;
134
+ for (const ch of tail) {
135
+ if (ch === '"') inQuote = !inQuote;
136
+ if (ch === "|" && !inQuote) {
137
+ fields.push(cur.trim());
138
+ cur = "";
139
+ } else {
140
+ cur += ch;
141
+ }
142
+ }
143
+ if (cur.trim()) fields.push(cur.trim());
144
+ if (fields.length > 0) fields[0] = stripQuotes(fields[0]);
145
+ return { kind, id, fields, props };
146
+ }
147
+ function resolveRole(raw) {
148
+ if (!raw) return void 0;
149
+ const key = raw.trim().toLowerCase();
150
+ return ROLE_ICONS[key];
151
+ }
152
+ var EDGE_OPS = [
153
+ { token: "-.->", kind: "matrix" },
154
+ { token: "->", kind: "report" }
155
+ ];
156
+ function findEdgeToken(line, token) {
157
+ let inQuote = false;
158
+ for (let i = 0; i < line.length; i++) {
159
+ const ch = line[i];
160
+ if (ch === '"') inQuote = !inQuote;
161
+ if (!inQuote && line.startsWith(token, i)) return i;
162
+ }
163
+ return -1;
164
+ }
165
+ function parseOrgchart(text2) {
166
+ const rawLines = tokenizeLines(text2);
167
+ let title2;
168
+ let direction = "TD";
169
+ let layout = "tree";
170
+ const nodes = [];
171
+ const nodeMap = /* @__PURE__ */ new Map();
172
+ const edges = [];
173
+ const indentStack = [];
174
+ for (const rl of rawLines) {
175
+ const line = rl.text;
176
+ if (/^orgchart\b/i.test(line)) {
177
+ const m = line.match(/"([^"]*)"/);
178
+ if (m) title2 = m[1];
179
+ continue;
180
+ }
181
+ if (/^config\b/i.test(line)) {
182
+ const m = line.match(/^config\s*:\s*(\w+)\s*=\s*"?([^"\n]+?)"?\s*$/i);
183
+ if (m) {
184
+ const key = m[1].toLowerCase();
185
+ const val = m[2].trim();
186
+ if (key === "direction") {
187
+ direction = val.toUpperCase() === "LR" ? "LR" : "TD";
188
+ } else if (key === "layout") {
189
+ const v = val.toLowerCase();
190
+ if (v === "list" || v === "directory" || v === "compact") layout = "list";
191
+ else layout = "tree";
192
+ }
193
+ }
194
+ continue;
195
+ }
196
+ let edgeHandled = false;
197
+ for (const { token, kind } of EDGE_OPS) {
198
+ const idx = findEdgeToken(line, token);
199
+ if (idx < 0) continue;
200
+ const left = line.slice(0, idx).trim();
201
+ let rest = line.slice(idx + token.length).trim();
202
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(left)) break;
203
+ let props = {};
204
+ const propsMatch = rest.match(/\[([^\]]*)\]\s*$/);
205
+ if (propsMatch) {
206
+ props = parseProps(propsMatch[1]);
207
+ rest = rest.slice(0, rest.length - propsMatch[0].length).trim();
208
+ }
209
+ const to = rest.split(/\s+/)[0];
210
+ if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(to)) break;
211
+ const edge = { from: left, to, kind };
212
+ if (props.label) edge.label = props.label;
213
+ edges.push(edge);
214
+ edgeHandled = true;
215
+ break;
216
+ }
217
+ if (edgeHandled) continue;
218
+ const parsed = parseNodeLine(line);
219
+ if (!parsed) {
220
+ throw new OrgchartParseError(`Cannot parse line: ${line}`);
221
+ }
222
+ if (nodeMap.has(parsed.id)) {
223
+ throw new OrgchartParseError(`Duplicate node id "${parsed.id}"`);
224
+ }
225
+ const node = {
226
+ id: parsed.id,
227
+ name: parsed.fields[0] ?? parsed.id,
228
+ title: parsed.fields[1] || void 0,
229
+ department: parsed.fields[2] || void 0,
230
+ info: parsed.fields[3] || void 0,
231
+ kind: parsed.kind,
232
+ matrix: []
233
+ };
234
+ const p = parsed.props;
235
+ if (p.role) node.role = resolveRole(p.role);
236
+ if (p.icon) node.role = resolveRole(p.icon) ?? node.role;
237
+ if (p.open === "true") {
238
+ node.open = true;
239
+ node.kind = "role";
240
+ }
241
+ if (p.draft === "true" || p.tbh === "true") {
242
+ node.draft = true;
243
+ node.kind = "draft";
244
+ }
245
+ if (p.external === "true") {
246
+ node.external = true;
247
+ if (node.kind === "person") node.kind = "advisor";
248
+ }
249
+ if (p["assistant-of"]) node.assistantOf = p["assistant-of"];
250
+ if (p.reports) node.parent = p.reports;
251
+ if (p.matrix) {
252
+ node.matrix = p.matrix.split(/[\s,]+/).filter(Boolean);
253
+ }
254
+ if (p.department) node.department = p.department;
255
+ if (p["avatar-color"] || p.avatarcolor) {
256
+ node.avatarColor = p["avatar-color"] ?? p.avatarcolor;
257
+ }
258
+ if (p.gender) {
259
+ const g = p.gender.toLowerCase();
260
+ if (g === "male" || g === "m") node.gender = "male";
261
+ else if (g === "female" || g === "f") node.gender = "female";
262
+ }
263
+ if (!node.info) {
264
+ node.info = p.note ?? p.email ?? p.phone ?? p.location ?? void 0;
265
+ }
266
+ if (p.status) {
267
+ const s = p.status.toLowerCase();
268
+ if (s === "new" || s === "leaving" || s === "on-leave") node.status = s;
269
+ }
270
+ if (node.kind === "role" && node.open === void 0 && !p.draft) node.open = true;
271
+ if (node.kind === "role" && !node.role) node.role = "Vacant";
272
+ while (indentStack.length > 0 && indentStack[indentStack.length - 1].indent >= rl.indent) {
273
+ indentStack.pop();
274
+ }
275
+ if (!node.parent && indentStack.length > 0) {
276
+ node.parent = indentStack[indentStack.length - 1].id;
277
+ }
278
+ indentStack.push({ indent: rl.indent, id: node.id });
279
+ for (const m of node.matrix) {
280
+ edges.push({ from: m, to: node.id, kind: "matrix" });
281
+ }
282
+ nodes.push(node);
283
+ nodeMap.set(node.id, node);
284
+ }
285
+ for (const n of nodes) {
286
+ if (n.parent && !n.assistantOf) {
287
+ const exists = edges.some(
288
+ (e) => e.kind === "report" && e.from === n.parent && e.to === n.id
289
+ );
290
+ if (!exists) edges.push({ from: n.parent, to: n.id, kind: "report" });
291
+ }
292
+ }
293
+ for (const e of edges) {
294
+ if (!nodeMap.has(e.from)) {
295
+ throw new OrgchartParseError(`Edge references unknown node "${e.from}"`);
296
+ }
297
+ if (!nodeMap.has(e.to)) {
298
+ throw new OrgchartParseError(`Edge references unknown node "${e.to}"`);
299
+ }
300
+ }
301
+ if (nodes.length === 0) {
302
+ throw new OrgchartParseError("Orgchart has no nodes");
303
+ }
304
+ return {
305
+ type: "orgchart",
306
+ title: title2,
307
+ direction,
308
+ layout,
309
+ nodes,
310
+ edges
311
+ };
312
+ }
313
+
314
+ // src/diagrams/orgchart/layout.ts
315
+ var CARD_W = 240;
316
+ var CARD_H = 76;
317
+ var TIER_GAP = 44;
318
+ var SIB_GAP = 20;
319
+ var PADDING = 30;
320
+ var ASSISTANT_GAP = 32;
321
+ function hashString(s) {
322
+ let h = 0;
323
+ for (let i = 0; i < s.length; i++) {
324
+ h = h * 31 + s.charCodeAt(i) | 0;
325
+ }
326
+ return Math.abs(h);
327
+ }
328
+ function hexToRgb(hex) {
329
+ const h = hex.replace("#", "").padEnd(6, "0");
330
+ return {
331
+ r: parseInt(h.slice(0, 2), 16),
332
+ g: parseInt(h.slice(2, 4), 16),
333
+ b: parseInt(h.slice(4, 6), 16)
334
+ };
335
+ }
336
+ function rgbToHex(r, g, b) {
337
+ const c = (v) => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2, "0");
338
+ return `#${c(r)}${c(g)}${c(b)}`;
339
+ }
340
+ function tint(hex, weight) {
341
+ const { r, g, b } = hexToRgb(hex);
342
+ return rgbToHex(255 + (r - 255) * weight, 255 + (g - 255) * weight, 255 + (b - 255) * weight);
343
+ }
344
+ function shade(hex, weight) {
345
+ const { r, g, b } = hexToRgb(hex);
346
+ return rgbToHex(r * (1 - weight), g * (1 - weight), b * (1 - weight));
347
+ }
348
+ function computeInitials(name) {
349
+ const trimmed = name.trim();
350
+ if (!trimmed) return "?";
351
+ if (/[^\x00-\x7F]/.test(trimmed[0])) {
352
+ return Array.from(trimmed)[0];
353
+ }
354
+ const parts = trimmed.split(/\s+/);
355
+ if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
356
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
357
+ }
358
+ function layoutOrgchart(ast, palette) {
359
+ const hasInfo = ast.nodes.some((n) => !!n.info);
360
+ const cW = CARD_W;
361
+ const cH = hasInfo ? 92 : CARD_H;
362
+ const tierGap = TIER_GAP;
363
+ const sibGap = SIB_GAP;
364
+ const nodeById = /* @__PURE__ */ new Map();
365
+ for (const n of ast.nodes) nodeById.set(n.id, n);
366
+ const childrenMap = /* @__PURE__ */ new Map();
367
+ const parentMap = /* @__PURE__ */ new Map();
368
+ for (const n of ast.nodes) childrenMap.set(n.id, []);
369
+ for (const e of ast.edges) {
370
+ if (e.kind !== "report") continue;
371
+ childrenMap.get(e.from)?.push(e.to);
372
+ parentMap.set(e.to, e.from);
373
+ }
374
+ const roots = [];
375
+ for (const n of ast.nodes) {
376
+ if (!parentMap.has(n.id) && !n.assistantOf) roots.push(n);
377
+ }
378
+ const treeById = /* @__PURE__ */ new Map();
379
+ for (const n of ast.nodes) {
380
+ treeById.set(n.id, {
381
+ id: n.id,
382
+ node: n,
383
+ children: [],
384
+ assistants: [],
385
+ subtreeWidth: 0,
386
+ x: 0,
387
+ y: 0
388
+ });
389
+ }
390
+ for (const n of ast.nodes) {
391
+ const t = treeById.get(n.id);
392
+ for (const cid of childrenMap.get(n.id) ?? []) {
393
+ const c = nodeById.get(cid);
394
+ if (c.assistantOf === n.id) continue;
395
+ t.children.push(treeById.get(cid));
396
+ }
397
+ }
398
+ for (const n of ast.nodes) {
399
+ if (n.assistantOf) {
400
+ const parent = treeById.get(n.assistantOf);
401
+ if (parent) parent.assistants.push(treeById.get(n.id));
402
+ }
403
+ }
404
+ function computeWidth(t) {
405
+ if (t.children.length === 0) {
406
+ t.subtreeWidth = cW;
407
+ return t.subtreeWidth;
408
+ }
409
+ let sum = 0;
410
+ for (let i = 0; i < t.children.length; i++) {
411
+ sum += computeWidth(t.children[i]);
412
+ if (i < t.children.length - 1) sum += sibGap;
413
+ }
414
+ t.subtreeWidth = Math.max(cW, sum);
415
+ return t.subtreeWidth;
416
+ }
417
+ function assign(t, leftX, depth) {
418
+ const cx = leftX + t.subtreeWidth / 2;
419
+ t.x = cx;
420
+ t.y = PADDING + depth * (cH + tierGap);
421
+ if (t.children.length > 0) {
422
+ const childBlock = t.children.reduce(
423
+ (s, c, i) => s + c.subtreeWidth + (i > 0 ? sibGap : 0),
424
+ 0
425
+ );
426
+ let childLeft = cx - childBlock / 2;
427
+ for (const c of t.children) {
428
+ assign(c, childLeft, depth + 1);
429
+ childLeft += c.subtreeWidth + sibGap;
430
+ }
431
+ }
432
+ }
433
+ let curLeft = PADDING;
434
+ for (const r of roots) {
435
+ const rt = treeById.get(r.id);
436
+ computeWidth(rt);
437
+ assign(rt, curLeft, 0);
438
+ curLeft += rt.subtreeWidth + sibGap * 2;
439
+ }
440
+ for (const [, t] of treeById) {
441
+ for (let i = 0; i < t.assistants.length; i++) {
442
+ const a = t.assistants[i];
443
+ a.x = t.x + cW + ASSISTANT_GAP + i * (cW + sibGap);
444
+ a.y = t.y + cH * 0.3;
445
+ }
446
+ }
447
+ const deptIndex = /* @__PURE__ */ new Map();
448
+ for (const n of ast.nodes) {
449
+ if (n.department && !deptIndex.has(n.department)) {
450
+ deptIndex.set(n.department, deptIndex.size);
451
+ }
452
+ }
453
+ const nodes = [];
454
+ for (const n of ast.nodes) {
455
+ const t = treeById.get(n.id);
456
+ const deptColor = n.department ? palette[(deptIndex.get(n.department) ?? 0) % palette.length] : void 0;
457
+ const base = n.avatarColor ?? deptColor ?? palette[hashString(n.name) % palette.length];
458
+ const avatarBg = tint(base, 0.14);
459
+ const avatarFg = shade(base, 0.4);
460
+ nodes.push({
461
+ node: n,
462
+ x: t.x,
463
+ y: t.y,
464
+ width: cW,
465
+ height: cH,
466
+ deptColor,
467
+ avatarBg,
468
+ avatarFg,
469
+ initials: computeInitials(n.name)
470
+ });
471
+ }
472
+ let minX = Infinity;
473
+ for (const n of nodes) minX = Math.min(minX, n.x - n.width / 2);
474
+ const shift = PADDING - minX;
475
+ if (Math.abs(shift) > 0.5) {
476
+ for (const n of nodes) n.x += shift;
477
+ }
478
+ const nodeLayoutById = /* @__PURE__ */ new Map();
479
+ for (const n of nodes) nodeLayoutById.set(n.node.id, n);
480
+ const layoutEdges = [];
481
+ for (const e of ast.edges) {
482
+ const from = nodeLayoutById.get(e.from);
483
+ const to = nodeLayoutById.get(e.to);
484
+ if (!from || !to) continue;
485
+ if (e.kind === "report") {
486
+ if (to.node.assistantOf === from.node.id) {
487
+ const sx2 = from.x + from.width / 2;
488
+ const sy2 = from.y + from.height / 2;
489
+ const ex2 = to.x - to.width / 2;
490
+ const ey2 = to.y + to.height / 2;
491
+ layoutEdges.push({ edge: e, path: `M ${sx2} ${sy2} L ${ex2} ${ey2}` });
492
+ continue;
493
+ }
494
+ const sx = from.x;
495
+ const sy = from.y + from.height;
496
+ const ex = to.x;
497
+ const ey = to.y;
498
+ const midY = (sy + ey) / 2;
499
+ const path2 = Math.abs(sx - ex) < 0.5 ? `M ${sx} ${sy} L ${ex} ${ey}` : `M ${sx} ${sy} L ${sx} ${midY} L ${ex} ${midY} L ${ex} ${ey}`;
500
+ layoutEdges.push({ edge: e, path: path2 });
501
+ } else {
502
+ const sx = from.x;
503
+ const sy = from.y + from.height / 2;
504
+ const ex = to.x;
505
+ const ey = to.y + to.height / 2;
506
+ const midY = (sy + ey) / 2;
507
+ const path2 = `M ${sx} ${sy} C ${sx} ${midY}, ${ex} ${midY}, ${ex} ${ey}`;
508
+ const entry = { edge: e, path: path2 };
509
+ if (e.label) {
510
+ entry.labelX = (sx + ex) / 2;
511
+ entry.labelY = midY;
512
+ }
513
+ layoutEdges.push(entry);
514
+ }
515
+ }
516
+ let maxX = 0;
517
+ let maxY = 0;
518
+ for (const n of nodes) {
519
+ maxX = Math.max(maxX, n.x + n.width / 2);
520
+ maxY = Math.max(maxY, n.y + n.height);
521
+ }
522
+ const width = Math.max(400, maxX + PADDING);
523
+ const height = Math.max(200, maxY + PADDING);
524
+ return {
525
+ width,
526
+ height,
527
+ nodes,
528
+ edges: layoutEdges,
529
+ title: ast.title,
530
+ mode: "tree"
531
+ };
532
+ }
533
+ var LIST_ROW_H = 32;
534
+ var LIST_INDENT = 22;
535
+ var LIST_PAD = 20;
536
+ var LIST_PANEL_W = 820;
537
+ var LIST_GUIDE_X0 = 32;
538
+ function layoutOrgchartList(ast, palette) {
539
+ const nodeById = /* @__PURE__ */ new Map();
540
+ for (const n of ast.nodes) nodeById.set(n.id, n);
541
+ const childrenMap = /* @__PURE__ */ new Map();
542
+ const parentMap = /* @__PURE__ */ new Map();
543
+ for (const n of ast.nodes) childrenMap.set(n.id, []);
544
+ for (const e of ast.edges) {
545
+ if (e.kind !== "report") continue;
546
+ childrenMap.get(e.from)?.push(e.to);
547
+ parentMap.set(e.to, e.from);
548
+ }
549
+ const roots = [];
550
+ for (const n of ast.nodes) {
551
+ if (!parentMap.has(n.id) && !n.assistantOf) roots.push(n);
552
+ }
553
+ const subtreeSize = /* @__PURE__ */ new Map();
554
+ function computeSize(id) {
555
+ const cached = subtreeSize.get(id);
556
+ if (cached !== void 0) return cached;
557
+ const kids = childrenMap.get(id) ?? [];
558
+ let s = kids.length;
559
+ for (const k of kids) s += computeSize(k);
560
+ subtreeSize.set(id, s);
561
+ return s;
562
+ }
563
+ for (const n of ast.nodes) computeSize(n.id);
564
+ const deptIndex = /* @__PURE__ */ new Map();
565
+ for (const n of ast.nodes) {
566
+ if (n.department && !deptIndex.has(n.department)) {
567
+ deptIndex.set(n.department, deptIndex.size);
568
+ }
569
+ }
570
+ const nodes = [];
571
+ const guides = [];
572
+ let rowIdx = 0;
573
+ function visit(id, depth) {
574
+ const n = nodeById.get(id);
575
+ if (!n) return;
576
+ const y = LIST_PAD + rowIdx * LIST_ROW_H;
577
+ const x = LIST_GUIDE_X0 + depth * LIST_INDENT;
578
+ const deptColor = n.department ? palette[(deptIndex.get(n.department) ?? 0) % palette.length] : void 0;
579
+ const base = n.avatarColor ?? deptColor ?? palette[hashString(n.name) % palette.length];
580
+ const kids = childrenMap.get(id) ?? [];
581
+ const hasKids = kids.length > 0;
582
+ nodes.push({
583
+ node: n,
584
+ x,
585
+ y,
586
+ width: LIST_PANEL_W - x - LIST_PAD,
587
+ height: LIST_ROW_H,
588
+ deptColor,
589
+ avatarBg: tint(base, 0.14),
590
+ avatarFg: shade(base, 0.4),
591
+ initials: computeInitials(n.name),
592
+ depth,
593
+ subtreeSize: subtreeSize.get(id) ?? 0,
594
+ hasChildren: hasKids
595
+ });
596
+ rowIdx++;
597
+ for (const c of kids) visit(c, depth + 1);
598
+ }
599
+ for (const r of roots) visit(r.id, 0);
600
+ for (let i = 0; i < nodes.length; i++) {
601
+ const p = nodes[i];
602
+ if (!p.hasChildren) continue;
603
+ const pxLine = p.x + 10;
604
+ const pyStart = p.y + LIST_ROW_H / 2 + 6;
605
+ const directChildren = [];
606
+ for (let j = i + 1; j < nodes.length; j++) {
607
+ const q = nodes[j];
608
+ if ((q.depth ?? 0) <= (p.depth ?? 0)) break;
609
+ if ((q.depth ?? 0) === (p.depth ?? 0) + 1) directChildren.push(q);
610
+ }
611
+ if (directChildren.length === 0) continue;
612
+ const lastChild = directChildren[directChildren.length - 1];
613
+ const pyEnd = lastChild.y + LIST_ROW_H / 2;
614
+ guides.push(`M ${pxLine} ${pyStart} L ${pxLine} ${pyEnd}`);
615
+ for (const c of directChildren) {
616
+ const tickY = c.y + LIST_ROW_H / 2;
617
+ guides.push(`M ${pxLine} ${tickY} L ${c.x - 2} ${tickY}`);
618
+ }
619
+ }
620
+ const height = LIST_PAD * 2 + rowIdx * LIST_ROW_H;
621
+ return {
622
+ width: LIST_PANEL_W,
623
+ height,
624
+ nodes,
625
+ edges: [],
626
+ title: ast.title,
627
+ mode: "list",
628
+ guides
629
+ };
630
+ }
631
+
632
+ // src/diagrams/orgchart/renderer.ts
633
+ function buildCss(t) {
634
+ return `
635
+ .lt-org { background: ${t.bg}; font-family: system-ui, -apple-system, sans-serif; }
636
+ .lt-org-title { font: 500 16px sans-serif; fill: ${t.text}; }
637
+ .lt-org-card { fill: ${t.bg}; stroke: ${t.neutral}; stroke-width: 1; }
638
+ .lt-org-card-vacant { fill: ${t.bg}; stroke: ${t.warn}; stroke-width: 1; stroke-dasharray: 4,3; }
639
+ .lt-org-card-draft { fill: ${t.bg}; stroke: ${t.neutral}; stroke-width: 1; stroke-dasharray: 4,3; opacity: 0.7; }
640
+ .lt-org-card-external { fill: ${t.bg}; stroke: ${t.neutral}; stroke-width: 1; stroke-dasharray: 4,3; }
641
+ .lt-org-name { font: 500 14px sans-serif; fill: ${t.text}; }
642
+ .lt-org-title-text { font: 400 12px sans-serif; fill: ${t.textMuted}; }
643
+ .lt-org-info { font: 400 11px sans-serif; fill: ${t.textMuted}; }
644
+ .lt-org-dept { font: 500 10px sans-serif; }
645
+ .lt-org-avatar-text { font: 600 13px sans-serif; text-anchor: middle; }
646
+ .lt-org-edge { stroke: ${t.stroke}; stroke-width: 1.4; fill: none; }
647
+ .lt-org-edge-matrix { stroke: ${t.neutral}; stroke-width: 1.2; stroke-dasharray: 4,3; fill: none; }
648
+ .lt-org-edge-label-bg { fill: ${t.bg}; stroke: ${t.neutral}; stroke-width: 1; }
649
+ .lt-org-edge-label { font: 500 10px sans-serif; fill: ${t.textMuted}; text-anchor: middle; }
650
+ .lt-org-pill-bg { fill: ${t.bg}; stroke-width: 1; }
651
+ .lt-org-pill { font: 600 9px sans-serif; text-anchor: middle; letter-spacing: 0.4px; }
652
+ .lt-org-panel { fill: ${t.bg}; stroke: ${t.neutral}; stroke-width: 1; }
653
+ .lt-org-guide { stroke: ${t.neutral}; stroke-width: 1; fill: none; }
654
+ .lt-org-caret { font: 400 9px sans-serif; fill: ${t.textMuted}; }
655
+ .lt-org-row-name { font: 500 13px sans-serif; fill: ${t.text}; }
656
+ .lt-org-row-title { font: 400 12px sans-serif; fill: ${t.textMuted}; }
657
+ .lt-org-row-avatar-text { font: 600 10px sans-serif; text-anchor: middle; }
658
+ .lt-org-row-count { font: 400 11px sans-serif; fill: ${t.textMuted}; text-anchor: end; }
659
+ .lt-org-row-dept { font: 500 10px sans-serif; text-anchor: middle; }
660
+ `.trim();
661
+ }
662
+ function renderGenderGlyph(gender, fg) {
663
+ const f = `fill="${fg}"`;
664
+ if (gender === "male") {
665
+ return `<circle cx="0" cy="-7" r="5.5" ${f}/><path d="M -9 11 C -9 2 -5 0 0 0 C 5 0 9 2 9 11 Z" ${f}/>`;
666
+ }
667
+ return `<circle cx="0" cy="-7" r="5.5" ${f}/><path d="M -5 0 C -10 5 -11 10 -10 11 L 10 11 C 11 10 10 5 5 0 Z" ${f}/>`;
668
+ }
669
+ function renderRoleGlyph(role, fg) {
670
+ const stroke = `stroke="${fg}" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"`;
671
+ const fillWhite = `fill="${fg}"`;
672
+ switch (role) {
673
+ case "CEO":
674
+ case "VP":
675
+ return `<path d="M -10 4 L -10 -6 L -4 0 L 0 -8 L 4 0 L 10 -6 L 10 4 Z" ${fillWhite} stroke="none"/>`;
676
+ case "CTO":
677
+ case "Engineer":
678
+ return `<circle r="6" ${stroke}/><circle r="2" ${fillWhite} stroke="none"/><g ${stroke}><line x1="0" y1="-9" x2="0" y2="-7"/><line x1="0" y1="9" x2="0" y2="7"/><line x1="-9" y1="0" x2="-7" y2="0"/><line x1="9" y1="0" x2="7" y2="0"/><line x1="-6.4" y1="-6.4" x2="-5" y2="-5"/><line x1="6.4" y1="-6.4" x2="5" y2="-5"/><line x1="-6.4" y1="6.4" x2="-5" y2="5"/><line x1="6.4" y1="6.4" x2="5" y2="5"/></g>`;
679
+ case "CFO":
680
+ return `<text x="0" y="6" text-anchor="middle" font-size="18" font-weight="700" fill="${fg}">$</text>`;
681
+ case "COO":
682
+ case "Ops":
683
+ return `<g ${fillWhite}><circle cx="-6" cy="0" r="3" stroke="none"/><circle cx="6" cy="0" r="3" stroke="none"/><circle cx="0" cy="-5" r="3" stroke="none"/></g>`;
684
+ case "CMO":
685
+ case "Marketing":
686
+ return `<path d="M -8 -4 L 2 -7 L 2 7 L -8 4 Z" ${fillWhite} stroke="none"/><path d="M 2 -4 L 8 -6 L 8 6 L 2 4 Z" ${fillWhite} stroke="none"/>`;
687
+ case "CPO":
688
+ case "Product":
689
+ return `<path d="M 0 -8 C 5 -8 7 -4 7 0 C 7 3 4 4 4 6 L -4 6 C -4 4 -7 3 -7 0 C -7 -4 -5 -8 0 -8 Z" ${fillWhite} stroke="none"/><line x1="-3" y1="9" x2="3" y2="9" stroke="${fg}" stroke-width="1.5"/>`;
690
+ case "Designer":
691
+ return `<path d="M -7 7 L 7 -7 L 9 -5 L -5 9 Z" ${fillWhite} stroke="none"/>`;
692
+ case "Sales":
693
+ return `<rect x="-8" y="-4" width="16" height="10" rx="1" ${fillWhite} stroke="none"/><rect x="-4" y="-7" width="8" height="4" ${stroke}/>`;
694
+ case "HR":
695
+ return `<circle cx="-3" cy="-4" r="3" ${fillWhite} stroke="none"/><circle cx="4" cy="-3" r="2.5" ${fillWhite} stroke="none"/><path d="M -8 7 C -8 2 -2 2 -2 2 C -2 2 2 2 2 7 Z" ${fillWhite} stroke="none"/><path d="M 0 7 C 0 4 4 4 4 4 C 4 4 9 4 9 7 Z" ${fillWhite} stroke="none"/>`;
696
+ case "Legal":
697
+ return `<line x1="0" y1="-8" x2="0" y2="8" stroke="${fg}" stroke-width="1.6"/><line x1="-7" y1="-6" x2="7" y2="-6" stroke="${fg}" stroke-width="1.6"/><path d="M -9 0 L -5 -6 L -1 0 Z" ${fillWhite} stroke="none"/><path d="M 1 0 L 5 -6 L 9 0 Z" ${fillWhite} stroke="none"/>`;
698
+ case "Data":
699
+ return `<g ${fillWhite}><rect x="-8" y="0" width="4" height="7" stroke="none"/><rect x="-2" y="-4" width="4" height="11" stroke="none"/><rect x="4" y="-7" width="4" height="14" stroke="none"/></g>`;
700
+ case "Advisor":
701
+ return `<path d="M 0 -9 L 2.6 -2.7 L 9 -2 L 4 2.3 L 5.3 8.5 L 0 5 L -5.3 8.5 L -4 2.3 L -9 -2 L -2.6 -2.7 Z" ${fillWhite} stroke="none"/>`;
702
+ case "Intern":
703
+ return `<path d="M -10 -2 L 0 -7 L 10 -2 L 0 3 Z" ${fillWhite} stroke="none"/><path d="M -5 0 L -5 5 C -5 7 5 7 5 5 L 5 0" ${stroke}/>`;
704
+ case "Vacant":
705
+ return `<circle r="7" stroke="${fg}" stroke-width="1.4" fill="none" stroke-dasharray="3,2"/><text x="0" y="4" text-anchor="middle" font-size="12" font-weight="700" fill="${fg}">?</text>`;
706
+ default:
707
+ return "";
708
+ }
709
+ }
710
+ function renderAvatar(ln) {
711
+ const role = ln.node.role;
712
+ const cx = -ln.width / 2 + 14 + 18;
713
+ const cy = 0;
714
+ const r = 18;
715
+ const parts = [
716
+ circle({ cx, cy, r, fill: ln.avatarBg, stroke: "none" })
717
+ ];
718
+ if (role && role !== "Vacant") {
719
+ parts.push(
720
+ group({ transform: `translate(${cx}, ${cy})` }, [
721
+ renderRoleGlyph(role, ln.avatarFg)
722
+ ])
723
+ );
724
+ } else if (ln.node.open) {
725
+ parts.push(
726
+ group({ transform: `translate(${cx}, ${cy})` }, [
727
+ renderRoleGlyph("Vacant", ln.avatarFg)
728
+ ])
729
+ );
730
+ } else if (ln.node.gender) {
731
+ parts.push(
732
+ group({ transform: `translate(${cx}, ${cy})` }, [
733
+ renderGenderGlyph(ln.node.gender, ln.avatarFg)
734
+ ])
735
+ );
736
+ } else {
737
+ parts.push(
738
+ text(
739
+ { x: cx, y: cy + 5, class: "lt-org-avatar-text", fill: ln.avatarFg },
740
+ ln.initials
741
+ )
742
+ );
743
+ }
744
+ return group({}, parts);
745
+ }
746
+ function renderCardBody(ln, t) {
747
+ const n = ln.node;
748
+ const x = -ln.width / 2;
749
+ const y = -ln.height / 2;
750
+ let cardClass = "lt-org-card";
751
+ if (n.open) cardClass = "lt-org-card-vacant";
752
+ else if (n.draft) cardClass = "lt-org-card-draft";
753
+ else if (n.external) cardClass = "lt-org-card-external";
754
+ const parts = [];
755
+ parts.push(
756
+ rect({
757
+ x,
758
+ y,
759
+ width: ln.width,
760
+ height: ln.height,
761
+ rx: 10,
762
+ ry: 10,
763
+ class: cardClass
764
+ })
765
+ );
766
+ parts.push(renderAvatar(ln));
767
+ const textX = x + 14 + 36 + 12;
768
+ const hasTitle = !!n.title;
769
+ const hasInfo = !!n.info;
770
+ const displayName = n.open && !n.name ? "Open Role" : n.name;
771
+ const lineCount = 1 + (hasTitle ? 1 : 0) + (hasInfo ? 1 : 0);
772
+ const lineH = 16;
773
+ let nameY = -(lineCount - 1) * lineH / 2;
774
+ parts.push(text({ x: textX, y: nameY, class: "lt-org-name" }, displayName));
775
+ if (hasTitle) {
776
+ parts.push(text({ x: textX, y: nameY + lineH, class: "lt-org-title-text" }, n.title));
777
+ }
778
+ if (hasInfo) {
779
+ parts.push(
780
+ text(
781
+ { x: textX, y: nameY + lineH * (hasTitle ? 2 : 1), class: "lt-org-info" },
782
+ n.info
783
+ )
784
+ );
785
+ }
786
+ const pillLabel = n.open ? "HIRING" : n.status === "new" ? "NEW" : n.status === "leaving" ? "LEAVING" : n.status === "on-leave" ? "ON LEAVE" : void 0;
787
+ if (pillLabel) {
788
+ const pw = pillLabel.length * 5.8 + 10;
789
+ const ph = 14;
790
+ const px = ln.width / 2 - pw - 8;
791
+ const py = y + 8;
792
+ const pillFg = pillLabel === "HIRING" ? "#8a6d00" : pillLabel === "NEW" ? "#2b6a3a" : pillLabel === "LEAVING" ? "#8a3b1a" : t.textMuted;
793
+ const pillBg = pillLabel === "HIRING" ? "#fef3c7" : pillLabel === "NEW" ? "#dcfce7" : pillLabel === "LEAVING" ? "#fee4d8" : "#eeeeea";
794
+ parts.push(
795
+ rect({ x: px, y: py, width: pw, height: ph, rx: 3, fill: pillBg, stroke: "none" })
796
+ );
797
+ parts.push(
798
+ text(
799
+ { x: px + pw / 2, y: py + ph - 4, class: "lt-org-pill", fill: pillFg },
800
+ pillLabel
801
+ )
802
+ );
803
+ }
804
+ return group(
805
+ {
806
+ transform: `translate(${ln.x}, ${ln.y + ln.height / 2})`,
807
+ "data-person-id": n.id,
808
+ "data-department": n.department ?? "",
809
+ "data-role": n.role ?? ""
810
+ },
811
+ parts
812
+ );
813
+ }
814
+ function renderListRow(ln) {
815
+ const n = ln.node;
816
+ const rowCenterY = ln.y + ln.height / 2;
817
+ const caretX = ln.x;
818
+ const avatarCx = ln.x + 20;
819
+ const avatarR = 11;
820
+ const parts = [];
821
+ const caret = ln.hasChildren ? "\u25BC" : "\xB7";
822
+ parts.push(
823
+ text(
824
+ { x: caretX, y: rowCenterY + 3, class: "lt-org-caret" },
825
+ caret
826
+ )
827
+ );
828
+ parts.push(circle({ cx: avatarCx, cy: rowCenterY, r: avatarR, fill: ln.avatarBg, stroke: "none" }));
829
+ if (n.role && n.role !== "Vacant") {
830
+ parts.push(
831
+ group({ transform: `translate(${avatarCx}, ${rowCenterY}) scale(0.58)` }, [
832
+ renderRoleGlyph(n.role, ln.avatarFg)
833
+ ])
834
+ );
835
+ } else if (n.open) {
836
+ parts.push(
837
+ group({ transform: `translate(${avatarCx}, ${rowCenterY}) scale(0.58)` }, [
838
+ renderRoleGlyph("Vacant", ln.avatarFg)
839
+ ])
840
+ );
841
+ } else if (n.gender) {
842
+ parts.push(
843
+ group({ transform: `translate(${avatarCx}, ${rowCenterY}) scale(0.56)` }, [
844
+ renderGenderGlyph(n.gender, ln.avatarFg)
845
+ ])
846
+ );
847
+ } else {
848
+ parts.push(
849
+ text(
850
+ {
851
+ x: avatarCx,
852
+ y: rowCenterY + 3,
853
+ class: "lt-org-row-avatar-text",
854
+ fill: ln.avatarFg
855
+ },
856
+ ln.initials
857
+ )
858
+ );
859
+ }
860
+ const textY = rowCenterY + 4;
861
+ const nameX = avatarCx + avatarR + 10;
862
+ const displayName = n.open && !n.name ? "Open Role" : n.name;
863
+ parts.push(text({ x: nameX, y: textY, class: "lt-org-row-name" }, displayName));
864
+ if (n.title) {
865
+ const titleX = nameX + Math.max(80, displayName.length * 8 + 10);
866
+ parts.push(text({ x: titleX, y: textY, class: "lt-org-row-title" }, n.title));
867
+ }
868
+ const rightEdge = ln.x + ln.width;
869
+ let cursor = rightEdge;
870
+ if (ln.subtreeSize && ln.subtreeSize > 0) {
871
+ const countLabel = ln.depth === 0 ? `${ln.subtreeSize} reports` : `${ln.subtreeSize}`;
872
+ parts.push(
873
+ text(
874
+ { x: cursor, y: textY, class: "lt-org-row-count" },
875
+ countLabel
876
+ )
877
+ );
878
+ cursor -= Math.max(30, countLabel.length * 6.5) + 12;
879
+ }
880
+ if (n.department) {
881
+ const pw = n.department.length * 5.6 + 14;
882
+ const ph = 16;
883
+ const px = cursor - pw;
884
+ const py = rowCenterY - ph / 2;
885
+ parts.push(
886
+ rect({ x: px, y: py, width: pw, height: ph, rx: 3, fill: ln.avatarBg, stroke: "none" })
887
+ );
888
+ parts.push(
889
+ text(
890
+ {
891
+ x: px + pw / 2,
892
+ y: textY,
893
+ class: "lt-org-row-dept",
894
+ fill: ln.avatarFg
895
+ },
896
+ n.department
897
+ )
898
+ );
899
+ }
900
+ return group({ "data-person-id": n.id }, parts);
901
+ }
902
+ function renderOrgchartList(ast, layout, t) {
903
+ const titleOffset = ast.title ? 42 : 16;
904
+ const width = Math.ceil(layout.width);
905
+ const height = Math.ceil(layout.height + titleOffset);
906
+ const children = [];
907
+ children.push(title(ast.title ?? "Organizational Directory"));
908
+ children.push(
909
+ desc(
910
+ `Organizational directory with ${ast.nodes.length} people and ${ast.edges.length} reporting relationships`
911
+ )
912
+ );
913
+ children.push(el("style", {}, buildCss(t)));
914
+ if (ast.title) {
915
+ children.push(text({ x: 20, y: 24, class: "lt-org-title" }, ast.title));
916
+ }
917
+ const inner = [];
918
+ for (const g of layout.guides ?? []) {
919
+ inner.push(path({ d: g, class: "lt-org-guide" }));
920
+ }
921
+ for (const ln of layout.nodes) {
922
+ inner.push(renderListRow(ln));
923
+ }
924
+ children.push(group({ transform: `translate(0, ${titleOffset})` }, inner));
925
+ return svgRoot(
926
+ {
927
+ class: "lt-org",
928
+ role: "img",
929
+ "aria-label": escapeXml(ast.title ?? "Organizational directory"),
930
+ width,
931
+ height,
932
+ viewBox: `0 0 ${width} ${height}`
933
+ },
934
+ children
935
+ );
936
+ }
937
+ function renderOrgchart(ast, config) {
938
+ const t = resolveBaseTheme(config?.theme ?? "default");
939
+ if (ast.layout === "list") {
940
+ return renderOrgchartList(ast, layoutOrgchartList(ast, t.palette), t);
941
+ }
942
+ const layout = layoutOrgchart(ast, t.palette);
943
+ const titleOffset = ast.title ? 36 : 10;
944
+ const width = Math.ceil(layout.width);
945
+ const height = Math.ceil(layout.height + titleOffset);
946
+ const children = [];
947
+ children.push(title(ast.title ?? "Organizational Chart"));
948
+ children.push(
949
+ desc(
950
+ `Organizational chart with ${ast.nodes.length} people and ${ast.edges.length} relationships`
951
+ )
952
+ );
953
+ children.push(el("style", {}, buildCss(t)));
954
+ if (ast.title) {
955
+ children.push(text({ x: 20, y: 24, class: "lt-org-title" }, ast.title));
956
+ }
957
+ const inner = [];
958
+ for (const le of layout.edges) {
959
+ const cls = le.edge.kind === "matrix" ? "lt-org-edge-matrix" : "lt-org-edge";
960
+ inner.push(path({ d: le.path, class: cls }));
961
+ }
962
+ for (const le of layout.edges) {
963
+ if (le.edge.kind !== "matrix" || !le.edge.label || le.labelX === void 0) continue;
964
+ const w = le.edge.label.length * 6 + 12;
965
+ const h = 16;
966
+ const x = (le.labelX ?? 0) - w / 2;
967
+ const y = (le.labelY ?? 0) - h / 2;
968
+ inner.push(
969
+ rect({ x, y, width: w, height: h, rx: 3, class: "lt-org-edge-label-bg" })
970
+ );
971
+ inner.push(
972
+ text(
973
+ { x: le.labelX, y: (le.labelY ?? 0) + 4, class: "lt-org-edge-label" },
974
+ le.edge.label
975
+ )
976
+ );
977
+ }
978
+ for (const ln of layout.nodes) {
979
+ inner.push(renderCardBody(ln, t));
980
+ }
981
+ children.push(group({ transform: `translate(0, ${titleOffset})` }, inner));
982
+ return svgRoot(
983
+ {
984
+ class: "lt-org",
985
+ role: "img",
986
+ "aria-label": escapeXml(ast.title ?? "Organizational chart"),
987
+ width,
988
+ height,
989
+ viewBox: `0 0 ${width} ${height}`
990
+ },
991
+ children
992
+ );
993
+ }
994
+
995
+ // src/diagrams/orgchart/index.ts
996
+ var orgchart = {
997
+ type: "orgchart",
998
+ detect(text2) {
999
+ return /^\s*orgchart\b/i.test(text2);
1000
+ },
1001
+ render(text2, config) {
1002
+ const ast = parseOrgchart(text2);
1003
+ return renderOrgchart(ast, config);
1004
+ }
1005
+ };
1006
+
1007
+ export { OrgchartParseError, layoutOrgchart, orgchart, parseOrgchart, renderOrgchart };
1008
+ //# sourceMappingURL=chunk-47ZC6EMJ.js.map
1009
+ //# sourceMappingURL=chunk-47ZC6EMJ.js.map