compasso 0.3.0 → 0.4.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/dist/index.cjs CHANGED
@@ -1592,7 +1592,7 @@ function faultTreeIssues(input) {
1592
1592
  );
1593
1593
  }
1594
1594
  }
1595
- const GRAPH_BLOCKING = /* @__PURE__ */ new Set([
1595
+ const GRAPH_BLOCKING2 = /* @__PURE__ */ new Set([
1596
1596
  "duplicate-id",
1597
1597
  "unknown-input",
1598
1598
  "gate-on-non-intermediate",
@@ -1601,7 +1601,7 @@ function faultTreeIssues(input) {
1601
1601
  "inhibit-condition",
1602
1602
  "top-not-intermediate"
1603
1603
  ]);
1604
- if (!issues.some((i) => GRAPH_BLOCKING.has(i.code))) {
1604
+ if (!issues.some((i) => GRAPH_BLOCKING2.has(i.code))) {
1605
1605
  const gateOf = (eventId) => gates.find((g) => g.eventId === eventId);
1606
1606
  const reachable = /* @__PURE__ */ new Set();
1607
1607
  const queue = [input.topId];
@@ -2565,13 +2565,13 @@ function pedigreeIssues(input) {
2565
2565
  );
2566
2566
  }
2567
2567
  }
2568
- const GRAPH_BLOCKING = /* @__PURE__ */ new Set([
2568
+ const GRAPH_BLOCKING2 = /* @__PURE__ */ new Set([
2569
2569
  "duplicate-id",
2570
2570
  "unknown-partner",
2571
2571
  "unknown-sibship-mating",
2572
2572
  "unknown-child"
2573
2573
  ]);
2574
- if (!issues.some((i) => GRAPH_BLOCKING.has(i.code))) {
2574
+ if (!issues.some((i) => GRAPH_BLOCKING2.has(i.code))) {
2575
2575
  for (const s of sibships) {
2576
2576
  const mating = matingById.get(s.matingId);
2577
2577
  if (mating === void 0) continue;
@@ -3509,13 +3509,13 @@ function phyloIssues(input) {
3509
3509
  push("tip-with-children", `node ${n.id} is declared internal but has no children`);
3510
3510
  }
3511
3511
  }
3512
- const GRAPH_BLOCKING = /* @__PURE__ */ new Set([
3512
+ const GRAPH_BLOCKING2 = /* @__PURE__ */ new Set([
3513
3513
  "duplicate-id",
3514
3514
  "unknown-endpoint",
3515
3515
  "unknown-root",
3516
3516
  "multiple-parents"
3517
3517
  ]);
3518
- if (!issues.some((i) => GRAPH_BLOCKING.has(i.code))) {
3518
+ if (!issues.some((i) => GRAPH_BLOCKING2.has(i.code))) {
3519
3519
  const childrenOf = /* @__PURE__ */ new Map();
3520
3520
  for (const e of [...input.edges].sort((a, b) => a.id - b.id)) {
3521
3521
  const arr = childrenOf.get(e.parentId) ?? [];
@@ -3904,6 +3904,765 @@ function phyloSvg(input, opts = {}) {
3904
3904
  return { svg, layout };
3905
3905
  }
3906
3906
 
3907
+ // src/org-chart/types.ts
3908
+ var ORG_REPORT_KINDS = ["line", "assistant", "dotted"];
3909
+ var ORG_VACANCIES = ["filled", "vacant"];
3910
+
3911
+ // src/org-chart/labels.ts
3912
+ var ORG_CHART_TITLE_LABELS_EN = {
3913
+ reportKinds: { line: "Reports to", assistant: "Assistant to", dotted: "Dotted-line report to" },
3914
+ vacant: "(vacant)"
3915
+ };
3916
+ var ORG_CHART_SVG_LABELS_EN = {
3917
+ legend: { line: "Reports to", assistant: "Assistant", dotted: "Dotted-line / matrix", vacant: "Vacant position" },
3918
+ ariaLabel: "Organizational chart"
3919
+ };
3920
+
3921
+ // src/org-chart/validate.ts
3922
+ var ORG_MAX_MATRIX_EDGES_PER_NODE = 5;
3923
+ var OrgChartValidationError = class extends Error {
3924
+ issues;
3925
+ constructor(issues) {
3926
+ super(`invalid org chart: ${issues.map((i) => i.message).join("; ")}`);
3927
+ this.name = "OrgChartValidationError";
3928
+ this.issues = issues;
3929
+ }
3930
+ };
3931
+ function listIds2(ids) {
3932
+ if (ids.length === 1) return String(ids[0]);
3933
+ return `${ids.slice(0, -1).join(", ")} and ${ids[ids.length - 1]}`;
3934
+ }
3935
+ function sortIssues4(issues) {
3936
+ const unique = /* @__PURE__ */ new Map();
3937
+ for (const issue of issues) unique.set(`${issue.code} ${issue.message}`, issue);
3938
+ return [...unique.values()].sort(
3939
+ (a, b) => a.code !== b.code ? a.code < b.code ? -1 : 1 : a.message < b.message ? -1 : a.message > b.message ? 1 : 0
3940
+ );
3941
+ }
3942
+ var GRAPH_BLOCKING = /* @__PURE__ */ new Set([
3943
+ "duplicate-id",
3944
+ "unknown-manager",
3945
+ "unknown-report",
3946
+ "multiple-managers"
3947
+ ]);
3948
+ function orgChartIssues(input) {
3949
+ if (input.positions.length === 0 && input.reports.length === 0) return [];
3950
+ const issues = [];
3951
+ const push = (code, message) => {
3952
+ issues.push({ code, message });
3953
+ };
3954
+ const positionById = /* @__PURE__ */ new Map();
3955
+ const dupPositionIds = /* @__PURE__ */ new Set();
3956
+ for (const p of input.positions) {
3957
+ if (positionById.has(p.id)) dupPositionIds.add(p.id);
3958
+ else positionById.set(p.id, p);
3959
+ }
3960
+ for (const id of [...dupPositionIds].sort((a, b) => a - b)) {
3961
+ push("duplicate-id", `duplicate position id ${id}`);
3962
+ }
3963
+ const reportById = /* @__PURE__ */ new Map();
3964
+ const dupReportIds = /* @__PURE__ */ new Set();
3965
+ for (const r of input.reports) {
3966
+ if (reportById.has(r.id)) dupReportIds.add(r.id);
3967
+ else reportById.set(r.id, r);
3968
+ }
3969
+ for (const id of [...dupReportIds].sort((a, b) => a - b)) {
3970
+ push("duplicate-id", `duplicate report id ${id}`);
3971
+ }
3972
+ if (issues.length > 0) {
3973
+ return sortIssues4(issues);
3974
+ }
3975
+ const reports = [...reportById.values()].sort((a, b) => a.id - b.id);
3976
+ const solidParents = /* @__PURE__ */ new Map();
3977
+ const assistantReportEdge = /* @__PURE__ */ new Map();
3978
+ const solidManagedEdges = /* @__PURE__ */ new Map();
3979
+ const dottedDegree = /* @__PURE__ */ new Map();
3980
+ for (const r of reports) {
3981
+ const hasManager = positionById.has(r.managerId);
3982
+ const hasReport = positionById.has(r.reportId);
3983
+ if (!hasManager) {
3984
+ push("unknown-manager", `report ${r.id} managerId ${r.managerId} is not a declared position`);
3985
+ }
3986
+ if (!hasReport) {
3987
+ push("unknown-report", `report ${r.id} reportId ${r.reportId} is not a declared position`);
3988
+ }
3989
+ if (r.managerId === r.reportId) {
3990
+ push("self-report", `report ${r.id} has managerId === reportId (${r.managerId})`);
3991
+ }
3992
+ if (r.kind !== "dotted") {
3993
+ const arr = solidParents.get(r.reportId) ?? [];
3994
+ arr.push(r.id);
3995
+ solidParents.set(r.reportId, arr);
3996
+ const managed = solidManagedEdges.get(r.managerId) ?? [];
3997
+ managed.push(r.id);
3998
+ solidManagedEdges.set(r.managerId, managed);
3999
+ }
4000
+ if (r.kind === "assistant" && r.managerId !== r.reportId && !assistantReportEdge.has(r.reportId)) {
4001
+ assistantReportEdge.set(r.reportId, r.id);
4002
+ }
4003
+ if (r.kind === "dotted" && r.managerId !== r.reportId) {
4004
+ if (positionById.has(r.managerId)) dottedDegree.set(r.managerId, (dottedDegree.get(r.managerId) ?? 0) + 1);
4005
+ if (positionById.has(r.reportId)) dottedDegree.set(r.reportId, (dottedDegree.get(r.reportId) ?? 0) + 1);
4006
+ }
4007
+ }
4008
+ for (const [reportId, edgeIds] of [...solidParents.entries()].sort((a, b) => a[0] - b[0])) {
4009
+ if (edgeIds.length > 1) {
4010
+ push(
4011
+ "multiple-managers",
4012
+ `position ${reportId} is the report of solid edges ${listIds2(edgeIds.sort((a, b) => a - b))} \u2014 keep one solid line, make the rest kind "dotted"`
4013
+ );
4014
+ }
4015
+ }
4016
+ for (const [positionId, assistEdgeId] of [...assistantReportEdge.entries()].sort((a, b) => a[0] - b[0])) {
4017
+ const managed = solidManagedEdges.get(positionId);
4018
+ if (managed !== void 0 && managed.length > 0) {
4019
+ const firstManaged = Math.min(...managed);
4020
+ push(
4021
+ "assistant-has-reports",
4022
+ `position ${positionId} is an assistant (report of edge ${assistEdgeId}) but manages solid edge ${firstManaged} \u2014 assistants are leaves`
4023
+ );
4024
+ }
4025
+ }
4026
+ for (const [positionId, count] of [...dottedDegree.entries()].sort((a, b) => a[0] - b[0])) {
4027
+ if (count > ORG_MAX_MATRIX_EDGES_PER_NODE) {
4028
+ push(
4029
+ "too-many-matrix-edges",
4030
+ `position ${positionId} has ${count} dotted (matrix) connections \u2014 at most ${ORG_MAX_MATRIX_EDGES_PER_NODE} are supported per position`
4031
+ );
4032
+ }
4033
+ }
4034
+ if (!issues.some((i) => GRAPH_BLOCKING.has(i.code))) {
4035
+ const solidChildren = /* @__PURE__ */ new Map();
4036
+ for (const r of reports) {
4037
+ if (r.kind === "dotted") continue;
4038
+ if (r.managerId === r.reportId) continue;
4039
+ const arr = solidChildren.get(r.managerId) ?? [];
4040
+ arr.push(r.reportId);
4041
+ solidChildren.set(r.managerId, arr);
4042
+ }
4043
+ for (const arr of solidChildren.values()) arr.sort((a, b) => a - b);
4044
+ const color = /* @__PURE__ */ new Map();
4045
+ const seenCycles = /* @__PURE__ */ new Set();
4046
+ const dfs = (start) => {
4047
+ const stack = [{ id: start, nextChild: 0 }];
4048
+ color.set(start, 1);
4049
+ while (stack.length > 0) {
4050
+ const frame = stack[stack.length - 1];
4051
+ const children = solidChildren.get(frame.id) ?? [];
4052
+ if (frame.nextChild >= children.length) {
4053
+ color.set(frame.id, 2);
4054
+ stack.pop();
4055
+ continue;
4056
+ }
4057
+ const child = children[frame.nextChild];
4058
+ frame.nextChild += 1;
4059
+ const c = color.get(child) ?? 0;
4060
+ if (c === 1) {
4061
+ const from = stack.findIndex((f) => f.id === child);
4062
+ const cycle = stack.slice(from).map((f) => f.id);
4063
+ const minIdx = cycle.indexOf(Math.min(...cycle));
4064
+ const rotated = [...cycle.slice(minIdx), ...cycle.slice(0, minIdx)];
4065
+ const key = rotated.join(">");
4066
+ if (!seenCycles.has(key)) {
4067
+ seenCycles.add(key);
4068
+ push("cycle", `cycle: ${[...rotated, rotated[0]].join(" \u2192 ")}`);
4069
+ }
4070
+ } else if (c === 0) {
4071
+ color.set(child, 1);
4072
+ stack.push({ id: child, nextChild: 0 });
4073
+ }
4074
+ }
4075
+ };
4076
+ for (const p of [...positionById.values()].sort((a, b) => a.id - b.id)) {
4077
+ if ((color.get(p.id) ?? 0) === 0) dfs(p.id);
4078
+ }
4079
+ }
4080
+ return sortIssues4(issues);
4081
+ }
4082
+ function validateOrgChart(input) {
4083
+ const issues = orgChartIssues(input);
4084
+ if (issues.length > 0) throw new OrgChartValidationError(issues);
4085
+ }
4086
+
4087
+ // src/org-chart/layout.ts
4088
+ var ORG_LABEL_FONT = 12;
4089
+ var ORG_TITLE_FONT = 10;
4090
+ var ORG_LABEL_LINE_H = 14;
4091
+ var PADDING7 = 32;
4092
+ var ORG_SIBLING_GAP = 28;
4093
+ var ORG_TREE_GAP = 56;
4094
+ var ORG_CORRIDOR = 30;
4095
+ var ORG_MIN_BOX_W = 120;
4096
+ var ORG_BOX_PAD_X = 12;
4097
+ var ORG_BOX_PAD_Y = 9;
4098
+ var ORG_ASSIST_GAP = 24;
4099
+ var ORG_ASSIST_BAND_DROP = 14;
4100
+ var ORG_MATRIX_GUTTER_GAP = 28;
4101
+ var ORG_MATRIX_LANE_PITCH = 14;
4102
+ var ORG_MATRIX_ESCAPE_STEP = 2;
4103
+ var ORG_STEM_ID_BASE = 1e6;
4104
+ var ORG_BUS_ID_BASE = 2e6;
4105
+ var ORG_DROP_ID_BASE = 3e6;
4106
+ var ORG_ASSIST_ID_BASE = 4e6;
4107
+ var ORG_DOTTED_ID_BASE = 5e6;
4108
+ var round9 = (n) => Math.round(n * 100) / 100;
4109
+ var drawnLeftEdge = (cx, boxW) => round9(round9(cx) - round9(boxW) / 2);
4110
+ var drawnRightEdge = (cx, boxW) => drawnLeftEdge(cx, boxW) + round9(boxW);
4111
+ function packSubtree(node, gaps) {
4112
+ const { ownHalfL, ownHalfR, children } = node;
4113
+ if (children.length === 0) {
4114
+ return { halfL: ownHalfL, halfR: ownHalfR, offsets: [] };
4115
+ }
4116
+ const xs = [0];
4117
+ for (let i = 1; i < children.length; i++) {
4118
+ xs.push(xs[i - 1] + children[i - 1].halfR + gaps.siblingGap + children[i].halfL);
4119
+ }
4120
+ const first = children[0];
4121
+ const last = children[children.length - 1];
4122
+ const axis = (xs[0] + xs[xs.length - 1]) / 2;
4123
+ const offsets = xs.map((x) => x - axis);
4124
+ const halfL = Math.max(ownHalfL, axis - (xs[0] - first.halfL));
4125
+ const halfR = Math.max(ownHalfR, xs[xs.length - 1] + last.halfR - axis);
4126
+ return { halfL, halfR, offsets };
4127
+ }
4128
+ function measurePosition(position, maxLabelChars, vacantWord) {
4129
+ const nameLines = position.name === "" ? [] : wrapLabelBalanced(clampLabel(position.name, maxLabelChars), 2);
4130
+ const titleLines = position.title === null ? [] : wrapLabelBalanced(clampLabel(position.title, maxLabelChars), 2);
4131
+ const subtitleLines = position.subtitle === null ? [] : wrapLabelBalanced(clampLabel(position.subtitle, maxLabelChars), 1);
4132
+ const vacantMarker = position.vacancy === "vacant" ? vacantWord : null;
4133
+ let innerW = 0;
4134
+ for (const l of nameLines) innerW = Math.max(innerW, estimateTextWidth(l, ORG_LABEL_FONT));
4135
+ for (const l of titleLines) innerW = Math.max(innerW, estimateTextWidth(l, ORG_TITLE_FONT));
4136
+ for (const l of subtitleLines) innerW = Math.max(innerW, estimateTextWidth(l, ORG_TITLE_FONT));
4137
+ if (vacantMarker !== null) innerW = Math.max(innerW, estimateTextWidth(vacantMarker, ORG_TITLE_FONT));
4138
+ const boxW = Math.max(ORG_MIN_BOX_W, innerW + ORG_BOX_PAD_X * 2);
4139
+ const lineCount = nameLines.length + titleLines.length + subtitleLines.length + (vacantMarker !== null ? 1 : 0);
4140
+ const boxH = ORG_BOX_PAD_Y * 2 + lineCount * ORG_LABEL_LINE_H;
4141
+ return { boxW, boxH, nameLines, titleLines, subtitleLines, vacantMarker };
4142
+ }
4143
+ function positionTitle(position, vacantWord) {
4144
+ if (position.hover !== void 0) return position.hover;
4145
+ if (position.title !== null) {
4146
+ return position.name === "" ? position.title : `${position.name} \u2014 ${position.title}`;
4147
+ }
4148
+ if (position.name !== "") return position.name;
4149
+ return vacantWord;
4150
+ }
4151
+ function computeOrgChartLayout(input, opts = {}) {
4152
+ if (input.positions.length === 0 && input.reports.length === 0) {
4153
+ return { width: PADDING7 * 2, height: PADDING7 * 2, nodes: [], elements: [], rootPositionIds: [] };
4154
+ }
4155
+ validateOrgChart(input);
4156
+ const titleLabels = opts.titleLabels ?? ORG_CHART_TITLE_LABELS_EN;
4157
+ const vacantWord = titleLabels.vacant;
4158
+ const positionById = new Map(input.positions.map((p) => [p.id, p]));
4159
+ const reports = [...input.reports].sort((a, b) => a.id - b.id);
4160
+ const solidReports = reports.filter((r) => r.kind !== "dotted");
4161
+ const lineChildIds = /* @__PURE__ */ new Map();
4162
+ const assistChildIds = /* @__PURE__ */ new Map();
4163
+ const solidParentReportId = /* @__PURE__ */ new Set();
4164
+ for (const r of solidReports) {
4165
+ solidParentReportId.add(r.reportId);
4166
+ const bucket = r.kind === "assistant" ? assistChildIds : lineChildIds;
4167
+ const arr = bucket.get(r.managerId) ?? [];
4168
+ arr.push(r);
4169
+ bucket.set(r.managerId, arr);
4170
+ }
4171
+ for (const arr of lineChildIds.values()) arr.sort((a, b) => a.reportId - b.reportId);
4172
+ for (const arr of assistChildIds.values()) arr.sort((a, b) => a.reportId - b.reportId);
4173
+ const rootPositionIds = input.positions.map((p) => p.id).filter((id) => !solidParentReportId.has(id)).sort((a, b) => a - b);
4174
+ const newInst = (position, depth, assistReport) => {
4175
+ const m = measurePosition(position, opts.maxLabelChars, vacantWord);
4176
+ return {
4177
+ position,
4178
+ m,
4179
+ style: position.vacancy === "vacant" ? "dashed" : "solid",
4180
+ title: positionTitle(position, vacantWord),
4181
+ depth,
4182
+ lineChildren: [],
4183
+ assistants: [],
4184
+ ownHalfL: m.boxW / 2,
4185
+ ownHalfR: m.boxW / 2,
4186
+ spanL: 0,
4187
+ spanR: 0,
4188
+ offsets: [],
4189
+ cx: 0,
4190
+ assistReport,
4191
+ assistTop: 0
4192
+ };
4193
+ };
4194
+ const allInsts = [];
4195
+ const build = (positionId, depth, assistReport) => {
4196
+ const position = positionById.get(positionId);
4197
+ const inst = newInst(position, depth, assistReport);
4198
+ allInsts.push(inst);
4199
+ for (const r of assistChildIds.get(positionId) ?? []) {
4200
+ const a = build(r.reportId, depth + 1, r);
4201
+ inst.assistants.push({ inst: a, report: r });
4202
+ }
4203
+ for (const r of lineChildIds.get(positionId) ?? []) {
4204
+ inst.lineChildren.push(build(r.reportId, depth + 1, null));
4205
+ }
4206
+ return inst;
4207
+ };
4208
+ const roots = rootPositionIds.map((id) => build(id, 0, null));
4209
+ for (const inst of allInsts) {
4210
+ if (inst.assistants.length > 0) {
4211
+ const widest = inst.assistants.reduce((m, a) => Math.max(m, a.inst.m.boxW), 0);
4212
+ inst.ownHalfL = inst.m.boxW / 2 + ORG_ASSIST_GAP + widest;
4213
+ }
4214
+ }
4215
+ const gaps = { siblingGap: ORG_SIBLING_GAP };
4216
+ const pack = (inst) => {
4217
+ for (const c of inst.lineChildren) pack(c);
4218
+ const result = packSubtree(
4219
+ {
4220
+ ownHalfL: inst.ownHalfL,
4221
+ ownHalfR: inst.ownHalfR,
4222
+ children: inst.lineChildren.map((c) => ({ halfL: c.spanL, halfR: c.spanR }))
4223
+ },
4224
+ gaps
4225
+ );
4226
+ inst.spanL = result.halfL;
4227
+ inst.spanR = result.halfR;
4228
+ inst.offsets = result.offsets;
4229
+ };
4230
+ for (const root of roots) pack(root);
4231
+ let cursor = PADDING7;
4232
+ for (const root of roots) {
4233
+ root.cx = cursor + root.spanL;
4234
+ const placeX = (inst) => {
4235
+ inst.lineChildren.forEach((c, i) => {
4236
+ c.cx = inst.cx + inst.offsets[i];
4237
+ placeX(c);
4238
+ });
4239
+ };
4240
+ placeX(root);
4241
+ cursor = root.cx + root.spanR + ORG_TREE_GAP;
4242
+ }
4243
+ const canvasRight = roots.length === 0 ? PADDING7 : cursor - ORG_TREE_GAP;
4244
+ const rowInsts = [];
4245
+ for (const inst of allInsts) (rowInsts[inst.depth] ??= []).push(inst);
4246
+ const depthCount = rowInsts.length;
4247
+ const assistStackH = (inst) => {
4248
+ if (inst.assistants.length === 0) return 0;
4249
+ return inst.assistants.reduce((s, a) => s + a.inst.m.boxH + ORG_ASSIST_BAND_DROP, 0) + ORG_ASSIST_BAND_DROP;
4250
+ };
4251
+ const rowH = [];
4252
+ for (let d = 0; d < depthCount; d++) {
4253
+ const lineBoxes = (rowInsts[d] ?? []).filter((i) => i.assistReport === null);
4254
+ rowH.push(lineBoxes.reduce((m, i) => Math.max(m, i.m.boxH), 0));
4255
+ }
4256
+ const assistZone = [];
4257
+ for (let d = 0; d < depthCount; d++) {
4258
+ let tallest = 0;
4259
+ for (const inst of rowInsts[d] ?? []) tallest = Math.max(tallest, assistStackH(inst));
4260
+ assistZone.push(tallest);
4261
+ }
4262
+ const rowTop = [PADDING7];
4263
+ for (let d = 0; d < depthCount - 1; d++) {
4264
+ rowTop.push(rowTop[d] + rowH[d] + assistZone[d] + ORG_CORRIDOR);
4265
+ }
4266
+ const busY = (d) => rowTop[d + 1] - ORG_CORRIDOR / 2;
4267
+ const last = depthCount - 1;
4268
+ const height = Math.ceil(rowTop[last] + rowH[last] + assistZone[last] + PADDING7);
4269
+ const nodes = [];
4270
+ const elements = [];
4271
+ const reportTitle = (kind, label) => {
4272
+ const word = titleLabels.reportKinds[kind];
4273
+ return label !== null && label !== void 0 ? `${word} \xB7 ${label}` : word;
4274
+ };
4275
+ const pushNode = (inst) => {
4276
+ nodes.push({
4277
+ positionId: inst.position.id,
4278
+ cx: round9(inst.cx),
4279
+ top: round9(rowTop[inst.depth]),
4280
+ boxW: round9(inst.m.boxW),
4281
+ boxH: round9(inst.m.boxH),
4282
+ style: inst.style,
4283
+ nameLines: inst.m.nameLines,
4284
+ titleLines: inst.m.titleLines,
4285
+ subtitleLines: inst.m.subtitleLines,
4286
+ vacantMarker: inst.m.vacantMarker,
4287
+ isAssistant: inst.assistReport !== null,
4288
+ depth: inst.depth,
4289
+ title: inst.title
4290
+ });
4291
+ };
4292
+ const emit = (inst) => {
4293
+ const d = inst.depth;
4294
+ let bandY = rowTop[d] + rowH[d] + ORG_ASSIST_BAND_DROP;
4295
+ for (const { inst: a, report } of inst.assistants) {
4296
+ const assistRight = inst.cx - ORG_ASSIST_GAP;
4297
+ a.cx = assistRight - a.m.boxW / 2;
4298
+ const assistTop = bandY;
4299
+ a.assistTop = assistTop;
4300
+ const assistMidY = assistTop + a.m.boxH / 2;
4301
+ nodes.push({
4302
+ positionId: a.position.id,
4303
+ cx: round9(a.cx),
4304
+ top: round9(assistTop),
4305
+ boxW: round9(a.m.boxW),
4306
+ boxH: round9(a.m.boxH),
4307
+ style: a.style,
4308
+ nameLines: a.m.nameLines,
4309
+ titleLines: a.m.titleLines,
4310
+ subtitleLines: a.m.subtitleLines,
4311
+ vacantMarker: a.m.vacantMarker,
4312
+ isAssistant: true,
4313
+ depth: a.depth,
4314
+ title: a.title
4315
+ });
4316
+ elements.push({
4317
+ edgeId: ORG_ASSIST_ID_BASE + report.reportId,
4318
+ kind: "assist",
4319
+ points: [
4320
+ { x: round9(inst.cx), y: round9(assistMidY) },
4321
+ { x: drawnRightEdge(a.cx, a.m.boxW), y: round9(assistMidY) }
4322
+ ],
4323
+ dashed: false,
4324
+ title: reportTitle("assistant", report.label)
4325
+ });
4326
+ bandY += a.m.boxH + ORG_ASSIST_BAND_DROP;
4327
+ }
4328
+ pushNode(inst);
4329
+ if (inst.lineChildren.length === 0) return;
4330
+ const by = busY(d);
4331
+ const boxBottom = rowTop[d] + inst.m.boxH;
4332
+ elements.push({
4333
+ edgeId: ORG_STEM_ID_BASE + inst.position.id,
4334
+ kind: "stem",
4335
+ points: [
4336
+ { x: round9(inst.cx), y: round9(boxBottom) },
4337
+ { x: round9(inst.cx), y: round9(by) }
4338
+ ],
4339
+ dashed: false,
4340
+ title: reportTitle("line", null)
4341
+ });
4342
+ const childCxs = inst.lineChildren.map((c) => c.cx);
4343
+ if (inst.lineChildren.length > 1) {
4344
+ elements.push({
4345
+ edgeId: ORG_BUS_ID_BASE + inst.position.id,
4346
+ kind: "bus",
4347
+ points: [
4348
+ { x: round9(Math.min(...childCxs)), y: round9(by) },
4349
+ { x: round9(Math.max(...childCxs)), y: round9(by) }
4350
+ ],
4351
+ dashed: false,
4352
+ title: reportTitle("line", null)
4353
+ });
4354
+ }
4355
+ for (const c of inst.lineChildren) {
4356
+ elements.push({
4357
+ edgeId: ORG_DROP_ID_BASE + c.position.id,
4358
+ kind: "drop",
4359
+ points: [
4360
+ { x: round9(c.cx), y: round9(by) },
4361
+ { x: round9(c.cx), y: round9(rowTop[c.depth]) }
4362
+ ],
4363
+ dashed: false,
4364
+ title: reportTitle("line", null)
4365
+ });
4366
+ }
4367
+ for (const c of inst.lineChildren) emit(c);
4368
+ };
4369
+ for (const root of roots) emit(root);
4370
+ const instByPos = new Map(allInsts.map((i) => [i.position.id, i]));
4371
+ const escapeByPos = /* @__PURE__ */ new Map();
4372
+ for (const inst of allInsts) {
4373
+ const isAssist = inst.assistReport !== null;
4374
+ const boxTop = isAssist ? inst.assistTop : rowTop[inst.depth];
4375
+ const leftEdge = drawnLeftEdge(inst.cx, inst.m.boxW);
4376
+ const rightEdge = drawnRightEdge(inst.cx, inst.m.boxW);
4377
+ if (isAssist) {
4378
+ const managerInst = instByPos.get(inst.assistReport.managerId);
4379
+ escapeByPos.set(inst.position.id, {
4380
+ side: -1,
4381
+ boxEdge: leftEdge,
4382
+ escCol: managerInst.cx - managerInst.spanL,
4383
+ midY: boxTop + inst.m.boxH / 2,
4384
+ boxH: inst.m.boxH
4385
+ });
4386
+ } else {
4387
+ escapeByPos.set(inst.position.id, {
4388
+ side: 1,
4389
+ boxEdge: rightEdge,
4390
+ escCol: inst.cx + inst.spanR,
4391
+ midY: boxTop + inst.m.boxH / 2,
4392
+ boxH: inst.m.boxH
4393
+ });
4394
+ }
4395
+ }
4396
+ const nodeById = new Map(nodes.map((n) => [n.positionId, n]));
4397
+ const dottedReports = reports.filter(
4398
+ (r) => r.kind === "dotted" && nodeById.has(r.managerId) && nodeById.has(r.reportId) && r.managerId !== r.reportId
4399
+ );
4400
+ let maxBoxBottom = PADDING7;
4401
+ for (const n of nodes) maxBoxBottom = Math.max(maxBoxBottom, n.top + n.boxH);
4402
+ let laneCount = 0;
4403
+ let channelLanes = 0;
4404
+ if (dottedReports.length > 0) {
4405
+ const laneOf = /* @__PURE__ */ new Map();
4406
+ laneCount = allocateLanes2(
4407
+ dottedReports.map((r) => {
4408
+ const rep = escapeByPos.get(r.reportId);
4409
+ const mgr = escapeByPos.get(r.managerId);
4410
+ return {
4411
+ lo: Math.min(rep.midY, mgr.midY),
4412
+ hi: Math.max(rep.midY, mgr.midY),
4413
+ set: (lane) => laneOf.set(r.id, lane)
4414
+ };
4415
+ })
4416
+ );
4417
+ channelLanes = dottedReports.length * 2;
4418
+ const channelTop = maxBoxBottom + ORG_MATRIX_GUTTER_GAP;
4419
+ const exitSlot = /* @__PURE__ */ new Map();
4420
+ const nextExitY = (posId, mid, boxH) => {
4421
+ const slot = exitSlot.get(posId) ?? 0;
4422
+ exitSlot.set(posId, slot + 1);
4423
+ if (slot === 0) return mid;
4424
+ const step = Math.min(6, Math.max(2, (boxH / 2 - 6) / Math.max(1, Math.ceil(slot / 2))));
4425
+ const sign = slot % 2 === 1 ? -1 : 1;
4426
+ return mid + sign * Math.ceil(slot / 2) * step;
4427
+ };
4428
+ const geoms = dottedReports.map((r, i) => {
4429
+ const rep = escapeByPos.get(r.reportId);
4430
+ const mgr = escapeByPos.get(r.managerId);
4431
+ return {
4432
+ r,
4433
+ i,
4434
+ repMidY: round9(nextExitY(r.reportId, rep.midY, rep.boxH)),
4435
+ mgrMidY: round9(nextExitY(r.managerId, mgr.midY, mgr.boxH)),
4436
+ repBoxEdge: round9(rep.boxEdge),
4437
+ mgrBoxEdge: round9(mgr.boxEdge),
4438
+ repChY: round9(channelTop + 2 * i * ORG_MATRIX_LANE_PITCH),
4439
+ mgrChY: round9(channelTop + (2 * i + 1) * ORG_MATRIX_LANE_PITCH),
4440
+ laneX: round9(canvasRight + ORG_MATRIX_GUTTER_GAP + laneOf.get(r.id) * ORG_MATRIX_LANE_PITCH),
4441
+ repEscX: 0,
4442
+ mgrEscX: 0
4443
+ };
4444
+ });
4445
+ const verts = [];
4446
+ for (const g of geoms) {
4447
+ const rep = escapeByPos.get(g.r.reportId);
4448
+ const mgr = escapeByPos.get(g.r.managerId);
4449
+ verts.push({
4450
+ escCol: rep.escCol,
4451
+ side: rep.side,
4452
+ lo: Math.min(g.repMidY, g.repChY),
4453
+ hi: Math.max(g.repMidY, g.repChY),
4454
+ assign: (x) => g.repEscX = x
4455
+ });
4456
+ verts.push({
4457
+ escCol: mgr.escCol,
4458
+ side: mgr.side,
4459
+ lo: Math.min(g.mgrMidY, g.mgrChY),
4460
+ hi: Math.max(g.mgrMidY, g.mgrChY),
4461
+ assign: (x) => g.mgrEscX = x
4462
+ });
4463
+ }
4464
+ const VERT_EPS = 0.01;
4465
+ const ordered = verts.map((v, idx) => ({ v, key: geoms[Math.floor(idx / 2)].r.id * 2 + idx % 2 })).sort((a, b) => a.key - b.key).map((e) => e.v);
4466
+ const placed = [];
4467
+ const yOverlap = (aLo, aHi, bLo, bHi) => Math.min(aHi, bHi) - Math.max(aLo, bLo) > VERT_EPS;
4468
+ for (const v of ordered) {
4469
+ let band = v.side === 1 ? Math.max(canvasRight - v.escCol, ORG_MATRIX_GUTTER_GAP) : v.escCol;
4470
+ for (const n of nodes) {
4471
+ const bLeft = n.cx - n.boxW / 2;
4472
+ const bRight = n.cx + n.boxW / 2;
4473
+ if (n.top + n.boxH <= v.lo + VERT_EPS || n.top >= v.hi - VERT_EPS) continue;
4474
+ if (v.side === 1 && bLeft > v.escCol + VERT_EPS) band = Math.min(band, bLeft - v.escCol);
4475
+ else if (v.side === -1 && bRight < v.escCol - VERT_EPS) band = Math.min(band, v.escCol - bRight);
4476
+ }
4477
+ let lane = 0;
4478
+ let candidate = round9(v.escCol);
4479
+ while (placed.some((p) => Math.abs(p.x - candidate) < VERT_EPS && yOverlap(p.lo, p.hi, v.lo, v.hi))) {
4480
+ lane += 1;
4481
+ candidate = round9(v.escCol + v.side * lane * ORG_MATRIX_ESCAPE_STEP);
4482
+ }
4483
+ if (lane > 0 && lane * ORG_MATRIX_ESCAPE_STEP >= band - VERT_EPS) {
4484
+ throw new Error(
4485
+ `org-chart: escape-column-overflow \u2014 escape vertical nudged ${lane * ORG_MATRIX_ESCAPE_STEP}px from its base column exceeds the ${round9(band)}px box-free band`
4486
+ );
4487
+ }
4488
+ placed.push({ x: candidate, lo: v.lo, hi: v.hi });
4489
+ v.assign(candidate);
4490
+ }
4491
+ for (const g of geoms) {
4492
+ elements.push({
4493
+ edgeId: ORG_DOTTED_ID_BASE + g.r.id,
4494
+ kind: "dotted",
4495
+ points: collapseDegenerate([
4496
+ { x: g.repBoxEdge, y: g.repMidY },
4497
+ // out the report box's edge
4498
+ { x: g.repEscX, y: g.repMidY },
4499
+ // → box-free escape column (in own gutter lane)
4500
+ { x: g.repEscX, y: g.repChY },
4501
+ // → down into the bottom traverse channel
4502
+ { x: g.laneX, y: g.repChY },
4503
+ // → across (below all boxes) to the right gutter lane
4504
+ { x: g.laneX, y: g.mgrChY },
4505
+ // → down the right gutter (right of every box)
4506
+ { x: g.mgrEscX, y: g.mgrChY },
4507
+ // → back across (below all boxes) to the manager column
4508
+ { x: g.mgrEscX, y: g.mgrMidY },
4509
+ // → up the box-free escape column
4510
+ { x: g.mgrBoxEdge, y: g.mgrMidY }
4511
+ // → into the manager box's edge
4512
+ ]),
4513
+ dashed: true,
4514
+ title: reportTitle("dotted", g.r.label)
4515
+ });
4516
+ }
4517
+ }
4518
+ const width = dottedReports.length > 0 ? Math.ceil(canvasRight + ORG_MATRIX_GUTTER_GAP + (laneCount - 1) * ORG_MATRIX_LANE_PITCH + ORG_MATRIX_GUTTER_GAP + PADDING7) : Math.ceil(canvasRight + PADDING7);
4519
+ const finalHeight = channelLanes > 0 ? Math.ceil(maxBoxBottom + ORG_MATRIX_GUTTER_GAP + (channelLanes - 1) * ORG_MATRIX_LANE_PITCH + PADDING7) : height;
4520
+ return { width, height: finalHeight, nodes, elements, rootPositionIds };
4521
+ }
4522
+ function collapseDegenerate(points) {
4523
+ const out = [];
4524
+ for (const p of points) {
4525
+ const prev = out[out.length - 1];
4526
+ if (prev === void 0 || prev.x !== p.x || prev.y !== p.y) out.push(p);
4527
+ }
4528
+ return out;
4529
+ }
4530
+ function allocateLanes2(items) {
4531
+ const lanes = [];
4532
+ for (const it of items) {
4533
+ let chosen = -1;
4534
+ for (let l = 0; l < lanes.length; l++) {
4535
+ if (lanes[l].every((o) => it.hi <= o.lo || it.lo >= o.hi)) {
4536
+ chosen = l;
4537
+ break;
4538
+ }
4539
+ }
4540
+ if (chosen === -1) {
4541
+ chosen = lanes.length;
4542
+ lanes.push([]);
4543
+ }
4544
+ lanes[chosen].push({ lo: it.lo, hi: it.hi });
4545
+ it.set(chosen);
4546
+ }
4547
+ return lanes.length;
4548
+ }
4549
+
4550
+ // src/org-chart/svg.ts
4551
+ var GLYPH_STROKE5 = "#52525b";
4552
+ var LABEL_FILL6 = "#3f3f46";
4553
+ var EDGE_INK7 = "#71717a";
4554
+ var GLYPH_ATTRS3 = `fill="transparent" stroke="${GLYPH_STROKE5}" stroke-width="2"`;
4555
+ var VACANT_DASH = `stroke-dasharray="6,4"`;
4556
+ var DOTTED = EDGE_STROKE.distant;
4557
+ var round10 = (n) => Math.round(n * 100) / 100;
4558
+ var ORG_BOX_PAD_Y2 = 9;
4559
+ function boxSvg(n) {
4560
+ const left = round10(n.cx - n.boxW / 2);
4561
+ const pieces = [`<title>${xmlEscape(n.title)}</title>`];
4562
+ if (n.style === "dashed") {
4563
+ pieces.push(
4564
+ `<rect x="${left}" y="${n.top}" width="${n.boxW}" height="${n.boxH}" rx="2" ${GLYPH_ATTRS3} ${VACANT_DASH}/>`
4565
+ );
4566
+ const ix = round10(left + 3);
4567
+ const iy = round10(n.top + 3);
4568
+ const iw = round10(n.boxW - 6);
4569
+ const ih = round10(n.boxH - 6);
4570
+ pieces.push(`<rect x="${ix}" y="${iy}" width="${iw}" height="${ih}" rx="2" ${GLYPH_ATTRS3} ${VACANT_DASH}/>`);
4571
+ } else {
4572
+ pieces.push(`<rect x="${left}" y="${n.top}" width="${n.boxW}" height="${n.boxH}" rx="2" ${GLYPH_ATTRS3}/>`);
4573
+ }
4574
+ let lineIndex = 0;
4575
+ const firstBaseline = (i) => round10(n.top + ORG_BOX_PAD_Y2 + ORG_LABEL_LINE_H / 2 + i * ORG_LABEL_LINE_H + ORG_LABEL_FONT * 0.32);
4576
+ const textBlock = (lines, font) => {
4577
+ if (lines.length === 0) return "";
4578
+ const tspans = lines.map((line, i) => `<tspan x="${n.cx}" y="${firstBaseline(lineIndex + i)}">${xmlEscape(line)}</tspan>`).join("");
4579
+ lineIndex += lines.length;
4580
+ return `<text text-anchor="middle" font-family="${FONT_FAMILY}" font-size="${font}" fill="${LABEL_FILL6}">${tspans}</text>`;
4581
+ };
4582
+ pieces.push(textBlock(n.nameLines, ORG_LABEL_FONT));
4583
+ pieces.push(textBlock(n.titleLines, ORG_TITLE_FONT));
4584
+ pieces.push(textBlock(n.subtitleLines, ORG_TITLE_FONT));
4585
+ if (n.vacantMarker !== null) pieces.push(textBlock([n.vacantMarker], ORG_TITLE_FONT));
4586
+ return `<g data-node-id="p${n.positionId}">${pieces.filter((p) => p !== "").join("")}</g>`;
4587
+ }
4588
+ function elementSvg5(el) {
4589
+ const head = `<g data-edge-id="${el.edgeId}"><title>${xmlEscape(el.title)}</title>`;
4590
+ if (el.dashed) {
4591
+ const dash = DOTTED.dash === null ? "" : ` stroke-dasharray="${DOTTED.dash[0]},${DOTTED.dash[1]}"`;
4592
+ return head + `<path d="${pathData(el.points)}" fill="none" stroke="${EDGE_INK7}" stroke-width="${DOTTED.width}" stroke-opacity="${DOTTED.opacity}"${dash}/></g>`;
4593
+ }
4594
+ if (el.points.length === 2) {
4595
+ const a = el.points[0];
4596
+ const b = el.points[1];
4597
+ return head + `<line x1="${a.x}" y1="${a.y}" x2="${b.x}" y2="${b.y}" stroke="${EDGE_INK7}" stroke-width="1.5" stroke-opacity="0.75"/></g>`;
4598
+ }
4599
+ return head + `<path d="${pathData(el.points)}" fill="none" stroke="${EDGE_INK7}" stroke-width="1.5" stroke-opacity="0.75"/></g>`;
4600
+ }
4601
+ var MINI_ATTRS3 = `fill="transparent" stroke="${GLYPH_STROKE5}" stroke-width="1.5"`;
4602
+ function lineSwatch(x, y) {
4603
+ const x1 = round10(x + 2);
4604
+ const x2 = round10(x + LEGEND_SWATCH_W - 2);
4605
+ return `<line x1="${x1}" y1="${y}" x2="${x2}" y2="${y}" stroke="${EDGE_INK7}" stroke-width="1.5" stroke-opacity="0.75"/>`;
4606
+ }
4607
+ function assistantSwatch(x, y) {
4608
+ const stemX = round10(x + LEGEND_SWATCH_W - 4);
4609
+ const boxX = round10(x + 1);
4610
+ return `<line x1="${stemX}" y1="${round10(y - 4)}" x2="${stemX}" y2="${y}" stroke="${EDGE_INK7}" stroke-width="1.5" stroke-opacity="0.75"/><line x1="${stemX}" y1="${y}" x2="${round10(boxX + 8)}" y2="${y}" stroke="${EDGE_INK7}" stroke-width="1.5" stroke-opacity="0.75"/><rect x="${boxX}" y="${round10(y - 3.5)}" width="8" height="7" rx="1" ${MINI_ATTRS3}/>`;
4611
+ }
4612
+ function dottedSwatch(x, y) {
4613
+ const x1 = round10(x + 2);
4614
+ const x2 = round10(x + LEGEND_SWATCH_W - 2);
4615
+ const dash = DOTTED.dash === null ? "" : ` stroke-dasharray="${DOTTED.dash[0]},${DOTTED.dash[1]}"`;
4616
+ return `<line x1="${x1}" y1="${y}" x2="${x2}" y2="${y}" stroke="${EDGE_INK7}" stroke-width="${DOTTED.width}" stroke-opacity="${DOTTED.opacity}"${dash}/>`;
4617
+ }
4618
+ function vacantSwatch(x, y) {
4619
+ const cx = round10(x + LEGEND_SWATCH_W / 2);
4620
+ const bx = round10(cx - 8);
4621
+ const by = round10(y - 5);
4622
+ return `<rect x="${bx}" y="${by}" width="16" height="10" rx="1" ${MINI_ATTRS3} stroke-dasharray="3,2"/><rect x="${round10(bx + 2)}" y="${round10(by + 2)}" width="12" height="6" rx="1" ${MINI_ATTRS3} stroke-dasharray="3,2"/>`;
4623
+ }
4624
+ function orgChartLayoutSvg(layout, opts = {}) {
4625
+ const labels = opts.labels ?? ORG_CHART_SVG_LABELS_EN;
4626
+ const parts = [];
4627
+ for (const el of layout.elements) parts.push(elementSvg5(el));
4628
+ for (const n of layout.nodes) parts.push(boxSvg(n));
4629
+ let width = layout.width;
4630
+ let height = layout.height;
4631
+ if (opts.legend !== false && layout.nodes.length > 0) {
4632
+ const hasSolid = layout.elements.some((e) => e.kind === "stem" || e.kind === "bus" || e.kind === "drop");
4633
+ const hasAssistant = layout.nodes.some((n) => n.isAssistant);
4634
+ const hasDotted = layout.elements.some((e) => e.kind === "dotted");
4635
+ const hasVacant = layout.nodes.some((n) => n.style === "dashed");
4636
+ const entries = [];
4637
+ if (hasSolid) entries.push({ swatch: lineSwatch, label: labels.legend.line });
4638
+ if (hasAssistant) entries.push({ swatch: assistantSwatch, label: labels.legend.assistant });
4639
+ if (hasDotted) entries.push({ swatch: dottedSwatch, label: labels.legend.dotted });
4640
+ if (hasVacant) entries.push({ swatch: vacantSwatch, label: labels.legend.vacant });
4641
+ const block = legendBlock(entries, layout.height);
4642
+ if (block.svg !== "") {
4643
+ parts.push(block.svg);
4644
+ width = Math.max(width, block.width);
4645
+ height = block.height;
4646
+ }
4647
+ }
4648
+ const w = Math.ceil(width);
4649
+ const h = Math.ceil(height);
4650
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}" width="${w}" height="${h}" role="img" aria-label="${xmlEscape(labels.ariaLabel)}">` + parts.join("") + `</svg>`;
4651
+ }
4652
+
4653
+ // src/org-chart/render.ts
4654
+ function orgChartSvg(input, opts = {}) {
4655
+ const layout = computeOrgChartLayout(input, {
4656
+ ...opts.maxLabelChars !== void 0 ? { maxLabelChars: opts.maxLabelChars } : {},
4657
+ ...opts.titleLabels !== void 0 ? { titleLabels: opts.titleLabels } : {}
4658
+ });
4659
+ const svg = orgChartLayoutSvg(layout, {
4660
+ ...opts.legend === false ? { legend: false } : {},
4661
+ ...opts.svgLabels !== void 0 ? { labels: opts.svgLabels } : {}
4662
+ });
4663
+ return { svg, layout };
4664
+ }
4665
+
3907
4666
  exports.CHAR_W = CHAR_W;
3908
4667
  exports.CODE_FONT = CODE_FONT;
3909
4668
  exports.ECOMAP_LABELS_EN = ECOMAP_LABELS_EN;
@@ -3938,6 +4697,20 @@ exports.LEGEND_SWATCH_W = LEGEND_SWATCH_W;
3938
4697
  exports.LIFE_STATUSES = LIFE_STATUSES;
3939
4698
  exports.MAX_CONDITIONS_PER_INDIVIDUAL = MAX_CONDITIONS_PER_INDIVIDUAL;
3940
4699
  exports.NODE_SIZE = NODE_SIZE;
4700
+ exports.ORG_ASSIST_ID_BASE = ORG_ASSIST_ID_BASE;
4701
+ exports.ORG_BUS_ID_BASE = ORG_BUS_ID_BASE;
4702
+ exports.ORG_CHART_SVG_LABELS_EN = ORG_CHART_SVG_LABELS_EN;
4703
+ exports.ORG_CHART_TITLE_LABELS_EN = ORG_CHART_TITLE_LABELS_EN;
4704
+ exports.ORG_DOTTED_ID_BASE = ORG_DOTTED_ID_BASE;
4705
+ exports.ORG_DROP_ID_BASE = ORG_DROP_ID_BASE;
4706
+ exports.ORG_LABEL_FONT = ORG_LABEL_FONT;
4707
+ exports.ORG_LABEL_LINE_H = ORG_LABEL_LINE_H;
4708
+ exports.ORG_MAX_MATRIX_EDGES_PER_NODE = ORG_MAX_MATRIX_EDGES_PER_NODE;
4709
+ exports.ORG_REPORT_KINDS = ORG_REPORT_KINDS;
4710
+ exports.ORG_STEM_ID_BASE = ORG_STEM_ID_BASE;
4711
+ exports.ORG_TITLE_FONT = ORG_TITLE_FONT;
4712
+ exports.ORG_VACANCIES = ORG_VACANCIES;
4713
+ exports.OrgChartValidationError = OrgChartValidationError;
3941
4714
  exports.PARENT_REL_ID_BASE = PARENT_REL_ID_BASE;
3942
4715
  exports.PEDIGREE_SVG_LABELS_EN = PEDIGREE_SVG_LABELS_EN;
3943
4716
  exports.PEDIGREE_TITLE_LABELS_EN = PEDIGREE_TITLE_LABELS_EN;
@@ -3974,6 +4747,7 @@ exports.clampLabel = clampLabel;
3974
4747
  exports.classifyRelationshipType = classifyRelationshipType;
3975
4748
  exports.computeFaultTreeLayout = computeFaultTreeLayout;
3976
4749
  exports.computeGenogramLayout = computeGenogramLayout;
4750
+ exports.computeOrgChartLayout = computeOrgChartLayout;
3977
4751
  exports.computePedigreeLayout = computePedigreeLayout;
3978
4752
  exports.computePhyloLayout = computePhyloLayout;
3979
4753
  exports.ecomapSvg = ecomapSvg;
@@ -3988,6 +4762,10 @@ exports.latestUnionPerPair = latestUnionPerPair;
3988
4762
  exports.legendBlock = legendBlock;
3989
4763
  exports.niceScaleStep = niceScaleStep;
3990
4764
  exports.normalizeText = normalizeText;
4765
+ exports.orgChartIssues = orgChartIssues;
4766
+ exports.orgChartLayoutSvg = orgChartLayoutSvg;
4767
+ exports.orgChartSvg = orgChartSvg;
4768
+ exports.packSubtree = packSubtree;
3991
4769
  exports.pathData = pathData;
3992
4770
  exports.pedigreeIssues = pedigreeIssues;
3993
4771
  exports.pedigreeLayoutSvg = pedigreeLayoutSvg;
@@ -3999,6 +4777,7 @@ exports.qualityLineStyle = qualityLineStyle;
3999
4777
  exports.relationshipTypeTokens = relationshipTypeTokens;
4000
4778
  exports.romanNumeral = romanNumeral;
4001
4779
  exports.validateFaultTree = validateFaultTree;
4780
+ exports.validateOrgChart = validateOrgChart;
4002
4781
  exports.validatePedigree = validatePedigree;
4003
4782
  exports.validatePhylo = validatePhylo;
4004
4783
  exports.wrapLabel = wrapLabel;