@miragon/team-topologies-renderer 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 (74) hide show
  1. package/dist/Modeler.d.ts +14 -0
  2. package/dist/Modeler.d.ts.map +1 -0
  3. package/dist/NavigatedViewer.d.ts +7 -0
  4. package/dist/NavigatedViewer.d.ts.map +1 -0
  5. package/dist/TtBaseViewer.d.ts +49 -0
  6. package/dist/TtBaseViewer.d.ts.map +1 -0
  7. package/dist/Viewer.d.ts +7 -0
  8. package/dist/Viewer.d.ts.map +1 -0
  9. package/dist/behaviors/TtFlatModelBehavior.d.ts +8 -0
  10. package/dist/behaviors/TtFlatModelBehavior.d.ts.map +1 -0
  11. package/dist/behaviors/index.d.ts +5 -0
  12. package/dist/behaviors/index.d.ts.map +1 -0
  13. package/dist/context-pad/TtContextPadProvider.d.ts +13 -0
  14. package/dist/context-pad/TtContextPadProvider.d.ts.map +1 -0
  15. package/dist/context-pad/index.d.ts +5 -0
  16. package/dist/context-pad/index.d.ts.map +1 -0
  17. package/dist/draw/TeamTopologiesRenderer.d.ts +16 -0
  18. package/dist/draw/TeamTopologiesRenderer.d.ts.map +1 -0
  19. package/dist/draw/icons.d.ts +10 -0
  20. package/dist/draw/icons.d.ts.map +1 -0
  21. package/dist/draw/index.d.ts +5 -0
  22. package/dist/draw/index.d.ts.map +1 -0
  23. package/dist/draw/palette-icons.d.ts +5 -0
  24. package/dist/draw/palette-icons.d.ts.map +1 -0
  25. package/dist/draw/styles.d.ts +20 -0
  26. package/dist/draw/styles.d.ts.map +1 -0
  27. package/dist/index.d.ts +21 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +852 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/io/TtExporter.d.ts +11 -0
  32. package/dist/io/TtExporter.d.ts.map +1 -0
  33. package/dist/io/TtImporter.d.ts +20 -0
  34. package/dist/io/TtImporter.d.ts.map +1 -0
  35. package/dist/io/index.d.ts +9 -0
  36. package/dist/io/index.d.ts.map +1 -0
  37. package/dist/io/saveSvg.d.ts +6 -0
  38. package/dist/io/saveSvg.d.ts.map +1 -0
  39. package/dist/io/types.d.ts +11 -0
  40. package/dist/io/types.d.ts.map +1 -0
  41. package/dist/keyboard/TtKeyboard.d.ts +9 -0
  42. package/dist/keyboard/TtKeyboard.d.ts.map +1 -0
  43. package/dist/keyboard/index.d.ts +5 -0
  44. package/dist/keyboard/index.d.ts.map +1 -0
  45. package/dist/label-editing/TtLabelEditing.d.ts +14 -0
  46. package/dist/label-editing/TtLabelEditing.d.ts.map +1 -0
  47. package/dist/label-editing/index.d.ts +5 -0
  48. package/dist/label-editing/index.d.ts.map +1 -0
  49. package/dist/model/TtElementFactory.d.ts +15 -0
  50. package/dist/model/TtElementFactory.d.ts.map +1 -0
  51. package/dist/model/di-types.d.ts +29 -0
  52. package/dist/model/di-types.d.ts.map +1 -0
  53. package/dist/model/index.d.ts +6 -0
  54. package/dist/model/index.d.ts.map +1 -0
  55. package/dist/modeling/TtModeling.d.ts +17 -0
  56. package/dist/modeling/TtModeling.d.ts.map +1 -0
  57. package/dist/modeling/cmd/UpdatePropertiesHandler.d.ts +13 -0
  58. package/dist/modeling/cmd/UpdatePropertiesHandler.d.ts.map +1 -0
  59. package/dist/modeling/index.d.ts +5 -0
  60. package/dist/modeling/index.d.ts.map +1 -0
  61. package/dist/palette/TtPaletteProvider.d.ts +12 -0
  62. package/dist/palette/TtPaletteProvider.d.ts.map +1 -0
  63. package/dist/palette/index.d.ts +5 -0
  64. package/dist/palette/index.d.ts.map +1 -0
  65. package/dist/rules/TtRules.d.ts +8 -0
  66. package/dist/rules/TtRules.d.ts.map +1 -0
  67. package/dist/rules/index.d.ts +5 -0
  68. package/dist/rules/index.d.ts.map +1 -0
  69. package/dist/team-topologies.css +1 -0
  70. package/dist/zorder/TtZOrder.d.ts +13 -0
  71. package/dist/zorder/TtZOrder.d.ts.map +1 -0
  72. package/dist/zorder/index.d.ts +5 -0
  73. package/dist/zorder/index.d.ts.map +1 -0
  74. package/package.json +51 -0
package/dist/index.js ADDED
@@ -0,0 +1,852 @@
1
+ import B from "diagram-js/lib/Diagram";
2
+ import { TEAM_TYPE_SPECS as T, newId as L, INTERACTION_MODE_SPECS as S, FLOW_SPEC as w, dashArray as x, DOCUMENT_VERSION as K, ALL_TEAM_SPECS as U, ALL_INTERACTION_SPECS as V } from "@miragon/team-topologies-schema-model";
3
+ import G from "diagram-js/lib/draw/BaseRenderer";
4
+ import { attr as g, create as y, append as _ } from "tiny-svg";
5
+ import H from "diagram-js/lib/features/selection";
6
+ import Y from "diagram-js/lib/navigation/zoomscroll";
7
+ import X from "diagram-js/lib/navigation/movecanvas";
8
+ import W from "diagram-js/lib/features/modeling";
9
+ import Z from "diagram-js/lib/features/move";
10
+ import q from "diagram-js/lib/features/outline";
11
+ import J from "diagram-js/lib/features/resize";
12
+ import Q from "diagram-js/lib/features/rules";
13
+ import tt from "diagram-js/lib/features/rules/RuleProvider";
14
+ import et from "diagram-js/lib/command/CommandInterceptor";
15
+ import it from "diagram-js/lib/features/palette";
16
+ import nt from "diagram-js/lib/features/create";
17
+ import ot from "diagram-js/lib/features/context-pad";
18
+ function R(r) {
19
+ return typeof r == "object" && r !== null ? r.ttKind : void 0;
20
+ }
21
+ function $(r) {
22
+ return typeof R(r) == "string";
23
+ }
24
+ function I(r) {
25
+ return R(r) === "team";
26
+ }
27
+ function C(r) {
28
+ return R(r) === "interaction";
29
+ }
30
+ function O(r) {
31
+ return R(r) === "flow";
32
+ }
33
+ const k = 40;
34
+ function rt(r, t) {
35
+ const e = r.getContainer().querySelector("svg");
36
+ if (!e) throw new Error("No SVG found in the canvas container.");
37
+ let o = 1 / 0, n = 1 / 0, s = -1 / 0, a = -1 / 0;
38
+ for (const b of t.getAll()) {
39
+ if (!$(b)) continue;
40
+ const d = b;
41
+ o = Math.min(o, d.x), n = Math.min(n, d.y), s = Math.max(s, d.x + d.width), a = Math.max(a, d.y + d.height);
42
+ }
43
+ Number.isFinite(o) || (o = 0, n = 0, s = 100, a = 100);
44
+ const c = o - k, h = n - k, l = s - o + k * 2, m = a - n + k * 2, u = e.cloneNode(!0);
45
+ u.setAttribute("xmlns", "http://www.w3.org/2000/svg"), u.setAttribute("viewBox", `${c} ${h} ${l} ${m}`), u.setAttribute("width", String(Math.round(l))), u.setAttribute("height", String(Math.round(m)));
46
+ const f = u.querySelector(".viewport");
47
+ return f && f.removeAttribute("transform"), { svg: `<?xml version="1.0" encoding="utf-8"?>
48
+ ` + new XMLSerializer().serializeToString(u) };
49
+ }
50
+ const M = "tt-root";
51
+ function z(r) {
52
+ return typeof r == "number" ? `${r}px` : r;
53
+ }
54
+ class st {
55
+ _diagram;
56
+ _container;
57
+ _options;
58
+ constructor(t = {}) {
59
+ this._options = t, this._container = this._createContainer(t);
60
+ }
61
+ _createContainer(t) {
62
+ const i = t.container ?? document.createElement("div");
63
+ return i.classList.add("tt-djs-container"), i.style.width = z(t.width ?? "100%"), i.style.height = z(t.height ?? (t.container ? "100%" : "600px")), i;
64
+ }
65
+ _ensureDiagram() {
66
+ if (!this._diagram) {
67
+ const t = [...this._getModules(), ...this._options.additionalModules ?? []];
68
+ this._diagram = new B({ canvas: { container: this._container }, modules: t });
69
+ }
70
+ return this._diagram;
71
+ }
72
+ /** Resolve a diagram-js service from the didi injector. */
73
+ get(t) {
74
+ return this._ensureDiagram().get(t);
75
+ }
76
+ on(t, i, e = 1e3) {
77
+ this.get("eventBus").on(t, e, i);
78
+ }
79
+ off(t, i) {
80
+ this.get("eventBus").off(t, i);
81
+ }
82
+ /** Load a document into the canvas (replaces existing content). */
83
+ importDocument(t) {
84
+ const i = this._ensureDiagram(), e = i.get("eventBus"), o = i.get("ttImporter");
85
+ o.clear();
86
+ const n = o.import(t);
87
+ return this._fit(), e.fire("import.done", { warnings: n }), { warnings: n };
88
+ }
89
+ /** Current canvas state as a canonical document. */
90
+ exportDocument() {
91
+ return this.get("ttExporter").export();
92
+ }
93
+ /** Update diagram-level metadata (title / flow-of-change) on the root. */
94
+ setMeta(t) {
95
+ const i = this.get("canvas");
96
+ let e;
97
+ try {
98
+ e = i.getRootElement();
99
+ } catch {
100
+ return;
101
+ }
102
+ if (!e || e.id !== M) return;
103
+ const o = e.businessObject ?? { title: "Untitled team topology" };
104
+ e.businessObject = { ...o, ...t };
105
+ }
106
+ /** Read diagram-level metadata (title / flow-of-change) from the root. */
107
+ getMeta() {
108
+ try {
109
+ return this.get("canvas").getRootElement().businessObject;
110
+ } catch {
111
+ return;
112
+ }
113
+ }
114
+ /** Standalone, self-contained SVG snapshot. */
115
+ saveSVG() {
116
+ return rt(this.get("canvas"), this.get("elementRegistry"));
117
+ }
118
+ /** Fit the content into the viewport, leaving room at the top for the palette. */
119
+ _fit(t = 84, i = 56) {
120
+ const e = this.get("canvas"), o = this.get("elementRegistry");
121
+ let n = 1 / 0, s = 1 / 0, a = -1 / 0, c = -1 / 0;
122
+ for (const b of o.getAll()) {
123
+ const d = b;
124
+ typeof d.x != "number" || typeof d.y != "number" || typeof d.width != "number" || typeof d.height != "number" || (n = Math.min(n, d.x), s = Math.min(s, d.y), a = Math.max(a, d.x + d.width), c = Math.max(c, d.y + d.height));
125
+ }
126
+ if (!Number.isFinite(n)) return;
127
+ const h = this._container.getBoundingClientRect(), l = h.width, m = h.height, u = Math.max(a - n, 1), f = Math.max(c - s, 1);
128
+ if (!l || !m) {
129
+ e.zoom("fit-viewport");
130
+ return;
131
+ }
132
+ const p = Math.min((l - 2 * i) / u, (m - t - i) / f, 1.25);
133
+ e.viewbox({
134
+ x: n + u / 2 - l / 2 / p,
135
+ y: s - t / p,
136
+ width: l / p,
137
+ height: m / p
138
+ });
139
+ }
140
+ /** Attach the container into `target`. */
141
+ attachTo(t) {
142
+ t.appendChild(this._container), this.get("canvas").resized();
143
+ }
144
+ /** Detach the container from the DOM, preserving state. */
145
+ detach() {
146
+ this._container.remove();
147
+ }
148
+ clear() {
149
+ this._ensureDiagram().clear();
150
+ }
151
+ destroy() {
152
+ this._diagram && (this._diagram.destroy(), this._diagram = void 0), this._container.remove();
153
+ }
154
+ get container() {
155
+ return this._container;
156
+ }
157
+ }
158
+ class at {
159
+ constructor(t) {
160
+ this.elementFactory = t;
161
+ }
162
+ static $inject = ["elementFactory"];
163
+ // --- from canonical document elements (import) -------------------------
164
+ createTeam(t) {
165
+ return this.elementFactory.createShape({
166
+ id: t.id,
167
+ x: t.position.x,
168
+ y: t.position.y,
169
+ width: t.size.width,
170
+ height: t.size.height,
171
+ ttKind: "team",
172
+ teamType: t.type,
173
+ ttLabel: t.label,
174
+ ...t.description ? { description: t.description } : {},
175
+ ...t.fill ? { fill: t.fill } : {},
176
+ ...t.stroke ? { stroke: t.stroke } : {}
177
+ });
178
+ }
179
+ createInteraction(t) {
180
+ return this.elementFactory.createShape({
181
+ id: t.id,
182
+ x: t.position.x,
183
+ y: t.position.y,
184
+ width: t.size.width,
185
+ height: t.size.height,
186
+ ttKind: "interaction",
187
+ mode: t.mode,
188
+ ...t.label ? { ttLabel: t.label } : {},
189
+ ...t.fill ? { fill: t.fill } : {},
190
+ ...t.stroke ? { stroke: t.stroke } : {}
191
+ });
192
+ }
193
+ createFlow(t) {
194
+ return this.elementFactory.createShape({
195
+ id: t.id,
196
+ x: t.position.x,
197
+ y: t.position.y,
198
+ width: t.size.width,
199
+ height: t.size.height,
200
+ ttKind: "flow",
201
+ ...t.label ? { ttLabel: t.label } : {}
202
+ });
203
+ }
204
+ // --- fresh, not-yet-placed shapes (palette / context-pad create) -------
205
+ //
206
+ // These set an explicit model-style id (`team_…`/`int_…`/`flow_…`, matching
207
+ // the model package's factory). We must NOT fall back to diagram-js' own
208
+ // auto-id: its counter starts at `shape_12` and is not advanced past ids that
209
+ // come in via import, so a re-imported `shape_N` (an element created in a
210
+ // previous session, then autosaved) collides with the next palette create —
211
+ // the first placement after a reload then throws "element already exists".
212
+ createNewTeam(t, i) {
213
+ const e = T[t];
214
+ return this.elementFactory.createShape({
215
+ id: L("team"),
216
+ width: e.defaultSize.width,
217
+ height: e.defaultSize.height,
218
+ ttKind: "team",
219
+ teamType: t,
220
+ ttLabel: i ?? e.label
221
+ });
222
+ }
223
+ createNewInteraction(t) {
224
+ const i = S[t];
225
+ return this.elementFactory.createShape({
226
+ id: L("int"),
227
+ width: i.defaultSize.width,
228
+ height: i.defaultSize.height,
229
+ ttKind: "interaction",
230
+ mode: t
231
+ });
232
+ }
233
+ createNewFlow() {
234
+ return this.elementFactory.createShape({
235
+ id: L("flow"),
236
+ width: w.defaultSize.width,
237
+ height: w.defaultSize.height,
238
+ ttKind: "flow",
239
+ ttLabel: w.label
240
+ });
241
+ }
242
+ }
243
+ const ct = {
244
+ ttElementFactory: ["type", at]
245
+ }, lt = 1500, dt = "#1f2430", ht = "#525a6b", E = {
246
+ /**
247
+ * Set directly as the `font-family` attribute on every SVG <text> (canvas
248
+ * labels and therefore the SVG export too) — not inherited from a CSS
249
+ * container. Falls back to system sans when the host doesn't provide Inter.
250
+ */
251
+ family: "'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif",
252
+ label: 13.5,
253
+ small: 11
254
+ };
255
+ class ut extends G {
256
+ static $inject = ["eventBus"];
257
+ constructor(t) {
258
+ super(t, lt);
259
+ }
260
+ canRender(t) {
261
+ return $(t);
262
+ }
263
+ drawShape(t, i) {
264
+ if (I(i)) return this.drawTeam(t, i);
265
+ if (C(i)) return this.drawInteraction(t, i);
266
+ if (O(i)) return this.drawFlow(t, i);
267
+ const e = g(y("rect"), {
268
+ width: i.width,
269
+ height: i.height,
270
+ fill: "#eee"
271
+ });
272
+ return _(t, e), e;
273
+ }
274
+ getShapePath(t) {
275
+ const { x: i, y: e, width: o, height: n } = t;
276
+ return `M${i},${e}l${o},0l0,${n}l${-o},0z`;
277
+ }
278
+ // --- teams ---------------------------------------------------------------
279
+ drawTeam(t, i) {
280
+ const e = T[i.teamType] ?? T["stream-aligned"], o = Math.max(i.width, 1), n = Math.max(i.height, 1), s = e.strokeWidth, a = x(e.strokeStyle, s), c = this.teamOutline(e.shape, o, n, s, {
281
+ fill: i.fill ?? e.fill,
282
+ stroke: i.stroke ?? e.stroke,
283
+ "stroke-width": s,
284
+ ...a ? { "stroke-dasharray": a } : {},
285
+ "stroke-linejoin": "round"
286
+ });
287
+ return _(t, c), this.appendLabel(t, i.ttLabel ?? "", o, n, { "font-weight": "640" }), c;
288
+ }
289
+ teamOutline(t, i, e, o, n) {
290
+ const s = o / 2, a = i - o, c = e - o;
291
+ if (t === "octagon") {
292
+ const l = Math.min(a, c) * 0.29;
293
+ return g(y("polygon"), { points: mt(s, a, c, l), ...n });
294
+ }
295
+ const h = t === "rect" ? 4 : Math.min(20, c / 2, a / 2);
296
+ return g(y("rect"), { x: s, y: s, width: a, height: c, rx: h, ry: h, ...n });
297
+ }
298
+ // --- interactions --------------------------------------------------------
299
+ drawInteraction(t, i) {
300
+ const e = S[i.mode] ?? S.collaboration, o = Math.max(i.width, 1), n = Math.max(i.height, 1), s = 2, a = s / 2, c = {
301
+ fill: i.fill ?? e.fill,
302
+ "fill-opacity": e.opacity,
303
+ stroke: i.stroke ?? e.stroke,
304
+ "stroke-width": s,
305
+ "stroke-dasharray": x(e.strokeStyle, s) || "6 4",
306
+ "stroke-linejoin": "round"
307
+ };
308
+ let h;
309
+ if (e.shape === "circle")
310
+ h = g(y("ellipse"), {
311
+ cx: o / 2,
312
+ cy: n / 2,
313
+ rx: (o - s) / 2,
314
+ ry: (n - s) / 2,
315
+ ...c
316
+ });
317
+ else if (e.shape === "triangle") {
318
+ const l = `${o / 2},${a} ${o - a},${n - a} ${a},${n - a}`;
319
+ h = g(y("polygon"), { points: l, ...c });
320
+ } else {
321
+ const l = Math.min(o * 0.26, n * 0.85), m = `${a + l},${a} ${o - a},${a} ${o - a - l},${n - a} ${a},${n - a}`;
322
+ h = g(y("polygon"), { points: m, ...c });
323
+ }
324
+ return _(t, h), i.ttLabel && this.appendLabel(t, i.ttLabel, o, n, {
325
+ "font-size": E.small,
326
+ "font-weight": "600"
327
+ }), h;
328
+ }
329
+ // --- flow of change ------------------------------------------------------
330
+ drawFlow(t, i) {
331
+ const e = Math.max(i.width, 1), o = Math.max(i.height, 1), n = w.strokeWidth, s = n / 2, a = Math.min(e * 0.16, o * 1.1), c = o * 0.5, h = (o - c) / 2, l = h + c, m = [
332
+ [s, h],
333
+ [e - a, h],
334
+ [e - a, s],
335
+ [e - s, o / 2],
336
+ [e - a, o - s],
337
+ [e - a, l],
338
+ [s, l]
339
+ ].map((f) => f.join(",")).join(" "), u = g(y("polygon"), {
340
+ points: m,
341
+ fill: "none",
342
+ stroke: w.stroke,
343
+ "stroke-width": n,
344
+ "stroke-dasharray": x(w.strokeStyle, n) || "6 4",
345
+ "stroke-linejoin": "round"
346
+ });
347
+ return _(t, u), i.ttLabel && this.appendLabel(t, i.ttLabel, e - a, o, {
348
+ "font-size": E.small,
349
+ "font-weight": "650",
350
+ "letter-spacing": "0.06em",
351
+ fill: ht
352
+ }), u;
353
+ }
354
+ // --- shared label rendering (wrapped, centred, no halo) ------------------
355
+ appendLabel(t, i, e, o, n) {
356
+ const s = typeof n["font-size"] == "number" ? n["font-size"] : E.label, a = ft(i, e - 20, s), c = s * 1.2, h = o / 2 - (a.length - 1) * c / 2;
357
+ a.forEach((l, m) => {
358
+ const u = g(y("text"), {
359
+ x: e / 2,
360
+ y: h + m * c,
361
+ "font-family": E.family,
362
+ "font-size": s,
363
+ fill: dt,
364
+ "text-anchor": "middle",
365
+ "dominant-baseline": "central",
366
+ ...n
367
+ });
368
+ u.textContent = l, _(t, u);
369
+ });
370
+ }
371
+ }
372
+ function mt(r, t, i, e) {
373
+ return [
374
+ [r + e, r],
375
+ [r + t - e, r],
376
+ [r + t, r + e],
377
+ [r + t, r + i - e],
378
+ [r + t - e, r + i],
379
+ [r + e, r + i],
380
+ [r, r + i - e],
381
+ [r, r + e]
382
+ ].map((o) => o.join(",")).join(" ");
383
+ }
384
+ function ft(r, t, i) {
385
+ const e = Math.max(4, Math.floor(t / (i * 0.58))), o = r.split(/\s+/).filter(Boolean);
386
+ if (o.length === 0) return [];
387
+ const n = [];
388
+ let s = "";
389
+ for (const a of o) {
390
+ const c = s ? `${s} ${a}` : a;
391
+ c.length > e && s ? (n.push(s), s = a) : s = c;
392
+ }
393
+ return s && n.push(s), n;
394
+ }
395
+ const pt = {
396
+ __init__: ["ttRenderer"],
397
+ ttRenderer: ["type", ut]
398
+ };
399
+ class gt {
400
+ constructor(t, i, e, o, n) {
401
+ this.canvas = t, this.elementFactory = i, this.factory = e, this.eventBus = o, this.elementRegistry = n;
402
+ }
403
+ static $inject = ["canvas", "elementFactory", "ttElementFactory", "eventBus", "elementRegistry"];
404
+ import(t) {
405
+ const i = [];
406
+ this.eventBus.fire("import.render.start", { document: t });
407
+ let e;
408
+ try {
409
+ e = this.canvas.getRootElement();
410
+ } catch {
411
+ e = void 0;
412
+ }
413
+ let o;
414
+ e && e.id === M ? o = e : (o = this.elementFactory.createRoot({ id: M }), this.canvas.setRootElement(o)), o.businessObject = { title: t.title };
415
+ for (const n of t.flows)
416
+ this.canvas.addShape(this.factory.createFlow(n), o);
417
+ for (const n of t.nodes)
418
+ this.canvas.addShape(this.factory.createTeam(n), o);
419
+ for (const n of t.interactions)
420
+ this.canvas.addShape(this.factory.createInteraction(n), o);
421
+ return this.eventBus.fire("import.render.done", { warnings: i }), i;
422
+ }
423
+ /** Removes every element (for re-import). */
424
+ clear() {
425
+ for (const t of [...this.elementRegistry.getAll()])
426
+ if (t.id !== M)
427
+ try {
428
+ this.canvas.removeShape(t.id);
429
+ } catch {
430
+ }
431
+ }
432
+ }
433
+ class yt {
434
+ constructor(t, i) {
435
+ this.elementRegistry = t, this.canvas = i;
436
+ }
437
+ static $inject = ["elementRegistry", "canvas"];
438
+ export() {
439
+ let t;
440
+ try {
441
+ t = this.canvas.getRootElement().businessObject;
442
+ } catch {
443
+ t = void 0;
444
+ }
445
+ const i = [], e = [], o = [];
446
+ for (const n of this.elementRegistry.getAll()) {
447
+ if (n.id === M) continue;
448
+ const s = n, a = { x: s.x, y: s.y }, c = { width: s.width, height: s.height };
449
+ I(n) ? i.push({
450
+ id: n.id,
451
+ type: n.teamType,
452
+ label: n.ttLabel ?? "",
453
+ position: a,
454
+ size: c,
455
+ ...n.description ? { description: n.description } : {},
456
+ ...n.fill ? { fill: n.fill } : {},
457
+ ...n.stroke ? { stroke: n.stroke } : {}
458
+ }) : C(n) ? e.push({
459
+ id: n.id,
460
+ mode: n.mode,
461
+ position: a,
462
+ size: c,
463
+ ...n.ttLabel ? { label: n.ttLabel } : {},
464
+ ...n.fill ? { fill: n.fill } : {},
465
+ ...n.stroke ? { stroke: n.stroke } : {}
466
+ }) : O(n) && o.push({
467
+ id: n.id,
468
+ position: a,
469
+ size: c,
470
+ ...n.ttLabel ? { label: n.ttLabel } : {}
471
+ });
472
+ }
473
+ return {
474
+ version: K,
475
+ title: t?.title ?? "Untitled team topology",
476
+ nodes: i,
477
+ interactions: e,
478
+ flows: o
479
+ };
480
+ }
481
+ }
482
+ const vt = {
483
+ ttImporter: ["type", gt],
484
+ ttExporter: ["type", yt]
485
+ };
486
+ class wt extends st {
487
+ _getModules() {
488
+ return [ct, pt, vt];
489
+ }
490
+ }
491
+ class bt extends wt {
492
+ _getModules() {
493
+ return [...super._getModules(), H, Y, X];
494
+ }
495
+ }
496
+ function F(r, t, i) {
497
+ i === void 0 ? delete r[t] : r[t] = i;
498
+ }
499
+ class _t {
500
+ execute(t) {
501
+ const { element: i, properties: e } = t, o = i, n = {};
502
+ for (const s of Object.keys(e))
503
+ n[s] = o[s], F(o, s, e[s]);
504
+ return t.oldProperties = n, [i];
505
+ }
506
+ revert(t) {
507
+ const { element: i, oldProperties: e } = t, o = i;
508
+ if (e)
509
+ for (const n of Object.keys(e)) F(o, n, e[n]);
510
+ return [i];
511
+ }
512
+ }
513
+ const N = "element.updateProperties";
514
+ class xt {
515
+ constructor(t) {
516
+ this.commandStack = t, t.registerHandler(N, _t);
517
+ }
518
+ static $inject = ["commandStack"];
519
+ updateProperties(t, i) {
520
+ this.commandStack.execute(N, { element: t, properties: i });
521
+ }
522
+ /** Rename / relabel any element. */
523
+ updateLabel(t, i) {
524
+ this.updateProperties(t, { ttLabel: i || void 0 });
525
+ }
526
+ setTeamType(t, i) {
527
+ this.updateProperties(t, { teamType: i });
528
+ }
529
+ setInteractionMode(t, i) {
530
+ this.updateProperties(t, { mode: i });
531
+ }
532
+ /** Set or clear per-element colour overrides (`undefined` reverts to default). */
533
+ setColors(t, i, e) {
534
+ this.updateProperties(t, { fill: i, stroke: e });
535
+ }
536
+ setDescription(t, i) {
537
+ this.updateProperties(t, { description: i });
538
+ }
539
+ }
540
+ const Mt = {
541
+ __init__: ["ttModeling"],
542
+ ttModeling: ["type", xt]
543
+ };
544
+ class $t extends tt {
545
+ static $inject = ["eventBus"];
546
+ constructor(t) {
547
+ super(t);
548
+ }
549
+ init() {
550
+ this.addRule(
551
+ ["shape.move", "elements.move"],
552
+ (t) => t.target && t.target.parent ? null : !0
553
+ ), this.addRule("shape.create", () => !0), this.addRule("shape.resize", () => !0);
554
+ }
555
+ }
556
+ const kt = {
557
+ __depends__: [Q],
558
+ __init__: ["ttRules"],
559
+ ttRules: ["type", $t]
560
+ };
561
+ class Et extends et {
562
+ static $inject = ["eventBus", "canvas"];
563
+ constructor(t, i) {
564
+ super(t), this.preExecute(
565
+ ["shape.create", "elements.create"],
566
+ (e) => {
567
+ e.parent = i.getRootElement();
568
+ },
569
+ !0
570
+ );
571
+ }
572
+ }
573
+ const Tt = {
574
+ __init__: ["ttFlatModelBehavior"],
575
+ ttFlatModelBehavior: ["type", Et]
576
+ };
577
+ function v(r) {
578
+ return `<svg class="tt-palette-svg" width="24" height="24" viewBox="0 0 26 26" aria-hidden="true">${r}</svg>`;
579
+ }
580
+ function St(r) {
581
+ const t = T[r], i = x(t.strokeStyle, 1.5), e = `fill="${t.fill}" stroke="${t.stroke}" stroke-width="1.5"` + (i ? ` stroke-dasharray="${i}"` : "");
582
+ switch (t.shape) {
583
+ case "octagon":
584
+ return v(`<polygon points="8,3 18,3 23,8 23,18 18,23 8,23 3,18 3,8" ${e}/>`);
585
+ case "rounded-rect-vertical":
586
+ return v(`<rect x="8" y="3" width="10" height="20" rx="4" ${e}/>`);
587
+ case "rect":
588
+ return v(`<rect x="3" y="7" width="20" height="12" rx="1.5" ${e}/>`);
589
+ default:
590
+ return v(`<rect x="3" y="8" width="20" height="10" rx="5" ${e}/>`);
591
+ }
592
+ }
593
+ function Rt() {
594
+ return v(
595
+ '<g fill="none" stroke="#6b6459" stroke-width="1.5" stroke-linejoin="round" stroke-dasharray="3 2"><polygon points="3,9 16,9 16,5 23,13 16,21 16,17 3,17"/></g>'
596
+ );
597
+ }
598
+ function Lt(r) {
599
+ const t = S[r], i = x(t.strokeStyle, 1.5), e = `fill="${t.fill}" fill-opacity="${t.opacity}" stroke="${t.stroke}" stroke-width="1.5"` + (i ? ` stroke-dasharray="${i}"` : "");
600
+ switch (t.shape) {
601
+ case "circle":
602
+ return v(`<circle cx="13" cy="13" r="9" ${e}/>`);
603
+ case "triangle":
604
+ return v(`<polygon points="5,6 22,13 5,20" ${e}/>`);
605
+ default:
606
+ return v(`<polygon points="9,6 23,6 17,20 3,20" ${e}/>`);
607
+ }
608
+ }
609
+ const Pt = "tt-1-teams", It = "tt-2-modes", Ct = "tt-3-flow";
610
+ function P(r, t) {
611
+ return `<div class="entry tt-palette-entry" draggable="true" title="${t}">${r}</div>`;
612
+ }
613
+ class Ot {
614
+ constructor(t, i, e) {
615
+ this.create = i, this.factory = e, t.registerProvider(this);
616
+ }
617
+ static $inject = ["palette", "create", "ttElementFactory"];
618
+ getPaletteEntries() {
619
+ const t = {};
620
+ for (const e of U) {
621
+ const o = (n) => this.create.start(
622
+ n,
623
+ this.factory.createNewTeam(e.type, e.label)
624
+ );
625
+ t[`team.${e.type}`] = {
626
+ group: Pt,
627
+ title: `${e.label} team — ${e.description}`,
628
+ html: P(St(e.type), `${e.label} team — ${e.description}`),
629
+ action: { dragstart: o, click: o }
630
+ };
631
+ }
632
+ for (const e of V) {
633
+ const o = (n) => this.create.start(
634
+ n,
635
+ this.factory.createNewInteraction(e.mode)
636
+ );
637
+ t[`mode.${e.mode}`] = {
638
+ group: It,
639
+ title: `${e.label} — ${e.description} (place over the teams it relates to)`,
640
+ html: P(Lt(e.mode), `${e.label} — ${e.description}`),
641
+ action: { dragstart: o, click: o }
642
+ };
643
+ }
644
+ const i = (e) => this.create.start(e, this.factory.createNewFlow());
645
+ return t.flow = {
646
+ group: Ct,
647
+ title: `${w.label} — the implied left-to-right flow`,
648
+ html: P(Rt(), w.label),
649
+ action: { dragstart: i, click: i }
650
+ }, t;
651
+ }
652
+ }
653
+ const zt = {
654
+ __depends__: [it, nt],
655
+ __init__: ["ttPaletteProvider"],
656
+ ttPaletteProvider: ["type", Ot]
657
+ }, Ft = "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z", Nt = "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z";
658
+ function jt(r, t = 18) {
659
+ return `<svg width="${t}" height="${t}" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="${r}"/></svg>`;
660
+ }
661
+ function j(r, t) {
662
+ return `<div class="entry tt-cp-entry" title="${t}">${jt(r)}</div>`;
663
+ }
664
+ class Dt {
665
+ constructor(t, i, e) {
666
+ this.modeling = i, this.labelEditing = e, t.registerProvider(this);
667
+ }
668
+ static $inject = ["contextPad", "modeling", "ttLabelEditing"];
669
+ getContextPadEntries(t) {
670
+ return $(t) ? {
671
+ "edit-label": {
672
+ group: "edit",
673
+ title: "Rename",
674
+ html: j(Ft, "Rename"),
675
+ action: { click: () => this.labelEditing.activate(t) }
676
+ },
677
+ delete: {
678
+ group: "edit",
679
+ title: "Delete",
680
+ html: j(Nt, "Delete"),
681
+ action: { click: () => this.modeling.removeElements([t]) }
682
+ }
683
+ } : {};
684
+ }
685
+ }
686
+ const At = {
687
+ __depends__: [ot],
688
+ __init__: ["ttContextPadProvider"],
689
+ ttContextPadProvider: ["type", Dt]
690
+ };
691
+ class Bt {
692
+ constructor(t, i, e) {
693
+ this.canvas = i, this.modeling = e, t.on("element.dblclick", (o) => {
694
+ $(o.element) && this.activate(o.element);
695
+ }), t.on(
696
+ ["element.mousedown", "drag.init", "canvas.viewbox.changing"],
697
+ () => this.active?.commit()
698
+ );
699
+ }
700
+ static $inject = ["eventBus", "canvas", "ttModeling"];
701
+ active = null;
702
+ activate(t) {
703
+ this.active?.commit();
704
+ const i = this.canvas.getContainer(), e = this.canvas.zoom(), o = this.canvas.viewbox(), n = t.x + t.width / 2, s = t.y + t.height / 2, a = 170, c = (n - o.x) * e - a / 2, h = (s - o.y) * e - 14, l = document.createElement("input");
705
+ l.type = "text", l.className = "tt-label-input", l.value = t.ttLabel ?? "", l.style.position = "absolute", l.style.left = `${c}px`, l.style.top = `${h}px`, l.style.width = `${a}px`, i.appendChild(l), l.focus(), l.select();
706
+ let m = !1;
707
+ const u = () => {
708
+ m || (m = !0, l.removeEventListener("keydown", p), l.removeEventListener("blur", b), l.remove(), this.active = null);
709
+ }, f = () => {
710
+ if (m) return;
711
+ const d = l.value.trim(), A = d !== (t.ttLabel ?? "");
712
+ u(), A && this.modeling.updateLabel(t, d);
713
+ }, p = (d) => {
714
+ d.key === "Enter" ? (d.preventDefault(), f()) : d.key === "Escape" && (d.preventDefault(), u());
715
+ }, b = () => f();
716
+ l.addEventListener("keydown", p), l.addEventListener("blur", b), this.active = { commit: f, cleanup: u };
717
+ }
718
+ cancel() {
719
+ this.active?.cleanup();
720
+ }
721
+ }
722
+ const Kt = {
723
+ __init__: ["ttLabelEditing"],
724
+ ttLabelEditing: ["type", Bt]
725
+ };
726
+ function Ut(r) {
727
+ const t = r;
728
+ return t ? t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.tagName === "SELECT" || t.isContentEditable : !1;
729
+ }
730
+ class Vt {
731
+ static $inject = ["canvas", "commandStack", "selection", "modeling"];
732
+ constructor(t, i, e, o) {
733
+ (t.getContainer().ownerDocument ?? document).addEventListener("keydown", (s) => {
734
+ if (Ut(s.target)) return;
735
+ const a = s.ctrlKey || s.metaKey, c = s.key.toLowerCase();
736
+ if (a && c === "z" && !s.shiftKey)
737
+ s.preventDefault(), i.canUndo() && i.undo();
738
+ else if (a && c === "z" && s.shiftKey || a && c === "y")
739
+ s.preventDefault(), i.canRedo() && i.redo();
740
+ else if (c === "delete" || c === "backspace") {
741
+ const h = e.get();
742
+ h.length && (s.preventDefault(), o.removeElements([...h]));
743
+ }
744
+ });
745
+ }
746
+ }
747
+ const Gt = {
748
+ __init__: ["ttKeyboard"],
749
+ ttKeyboard: ["type", Vt]
750
+ };
751
+ function D(r) {
752
+ return O(r) ? 0 : I(r) ? r.teamType === "enabling" ? 3 : r.teamType === "complicated-subsystem" ? 2 : 1 : C(r) ? 4 : 1;
753
+ }
754
+ class Ht {
755
+ constructor(t, i, e) {
756
+ this.canvas = i, this.elementRegistry = e, t.on("import.render.start", () => {
757
+ this.importing = !0;
758
+ }), t.on("import.render.done", () => {
759
+ this.importing = !1, this.reorder();
760
+ }), t.on("commandStack.changed", () => {
761
+ this.importing || this.reorder();
762
+ });
763
+ }
764
+ static $inject = ["eventBus", "canvas", "elementRegistry"];
765
+ importing = !1;
766
+ /** Re-append each element's graphics group in ascending tier order (back → front). */
767
+ reorder() {
768
+ const t = this.elementRegistry.getAll().filter($).sort(
769
+ (i, e) => D(i) - D(e)
770
+ );
771
+ for (const i of t) {
772
+ const o = this.canvas.getGraphics(i)?.parentNode, n = o?.parentNode;
773
+ o && n && n.appendChild(o);
774
+ }
775
+ }
776
+ }
777
+ const Yt = {
778
+ __init__: ["ttZOrder"],
779
+ ttZOrder: ["type", Ht]
780
+ };
781
+ class he extends bt {
782
+ _getModules() {
783
+ return [
784
+ ...super._getModules(),
785
+ // diagram-js stock
786
+ W,
787
+ Z,
788
+ q,
789
+ J,
790
+ // Team Topologies editor
791
+ Mt,
792
+ kt,
793
+ Tt,
794
+ zt,
795
+ At,
796
+ Kt,
797
+ Gt,
798
+ Yt
799
+ ];
800
+ }
801
+ undo() {
802
+ this.get("commandStack").undo();
803
+ }
804
+ redo() {
805
+ this.get("commandStack").redo();
806
+ }
807
+ canUndo() {
808
+ return this.get("commandStack").canUndo();
809
+ }
810
+ canRedo() {
811
+ return this.get("commandStack").canRedo();
812
+ }
813
+ }
814
+ export {
815
+ he as Modeler,
816
+ bt as NavigatedViewer,
817
+ M as ROOT_ID,
818
+ ut as TeamTopologiesRenderer,
819
+ st as TtBaseViewer,
820
+ Dt as TtContextPadProvider,
821
+ at as TtElementFactory,
822
+ yt as TtExporter,
823
+ Et as TtFlatModelBehavior,
824
+ gt as TtImporter,
825
+ Vt as TtKeyboard,
826
+ Bt as TtLabelEditing,
827
+ xt as TtModeling,
828
+ Ot as TtPaletteProvider,
829
+ $t as TtRules,
830
+ Ht as TtZOrder,
831
+ wt as Viewer,
832
+ Rt as flowIconSvg,
833
+ Lt as interactionIconSvg,
834
+ vt as ioModule,
835
+ $ as isTtElement,
836
+ O as isTtFlow,
837
+ C as isTtInteraction,
838
+ I as isTtTeam,
839
+ rt as saveSVG,
840
+ St as teamIconSvg,
841
+ Tt as ttBehaviorsModule,
842
+ At as ttContextPadModule,
843
+ pt as ttDrawModule,
844
+ Gt as ttKeyboardModule,
845
+ Kt as ttLabelEditingModule,
846
+ ct as ttModelModule,
847
+ Mt as ttModelingModule,
848
+ zt as ttPaletteModule,
849
+ kt as ttRulesModule,
850
+ Yt as ttZOrderModule
851
+ };
852
+ //# sourceMappingURL=index.js.map