adr-kit 0.9.0 → 0.11.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 (76) hide show
  1. package/README.md +23 -7
  2. package/README.zh.md +18 -6
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +18 -5
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/completion.d.ts.map +1 -1
  7. package/dist/commands/completion.js +4 -3
  8. package/dist/commands/completion.js.map +1 -1
  9. package/dist/commands/graph.d.ts +3 -0
  10. package/dist/commands/graph.d.ts.map +1 -1
  11. package/dist/commands/graph.js +39 -6
  12. package/dist/commands/graph.js.map +1 -1
  13. package/dist/commands/supersede.js +1 -1
  14. package/dist/commands/supersede.js.map +1 -1
  15. package/dist/commands/tree.d.ts +1 -1
  16. package/dist/commands/tree.d.ts.map +1 -1
  17. package/dist/commands/tree.js +4 -1
  18. package/dist/commands/tree.js.map +1 -1
  19. package/dist/core/adr.d.ts +1 -0
  20. package/dist/core/adr.d.ts.map +1 -1
  21. package/dist/core/adr.js.map +1 -1
  22. package/dist/core/canvas-view.d.ts +21 -0
  23. package/dist/core/canvas-view.d.ts.map +1 -0
  24. package/dist/core/canvas-view.js +316 -0
  25. package/dist/core/canvas-view.js.map +1 -0
  26. package/dist/core/deliberation-html.d.ts +4 -0
  27. package/dist/core/deliberation-html.d.ts.map +1 -0
  28. package/dist/core/deliberation-html.js +153 -0
  29. package/dist/core/deliberation-html.js.map +1 -0
  30. package/dist/core/deliberation-view.d.ts +4 -0
  31. package/dist/core/deliberation-view.d.ts.map +1 -0
  32. package/dist/core/deliberation-view.js +341 -0
  33. package/dist/core/deliberation-view.js.map +1 -0
  34. package/dist/core/deliberation.d.ts +39 -7
  35. package/dist/core/deliberation.d.ts.map +1 -1
  36. package/dist/core/deliberation.js +175 -35
  37. package/dist/core/deliberation.js.map +1 -1
  38. package/dist/core/graph-html.d.ts +8 -0
  39. package/dist/core/graph-html.d.ts.map +1 -0
  40. package/dist/core/graph-html.js +299 -0
  41. package/dist/core/graph-html.js.map +1 -0
  42. package/dist/core/graph-view.d.ts +3 -0
  43. package/dist/core/graph-view.d.ts.map +1 -0
  44. package/dist/core/graph-view.js +80 -0
  45. package/dist/core/graph-view.js.map +1 -0
  46. package/dist/core/graph.d.ts +4 -1
  47. package/dist/core/graph.d.ts.map +1 -1
  48. package/dist/core/graph.js +11 -2
  49. package/dist/core/graph.js.map +1 -1
  50. package/dist/core/relation-focus.d.ts +4 -0
  51. package/dist/core/relation-focus.d.ts.map +1 -0
  52. package/dist/core/relation-focus.js +89 -0
  53. package/dist/core/relation-focus.js.map +1 -0
  54. package/dist/core/repository.d.ts.map +1 -1
  55. package/dist/core/repository.js +6 -2
  56. package/dist/core/repository.js.map +1 -1
  57. package/dist/core/share.d.ts +30 -0
  58. package/dist/core/share.d.ts.map +1 -0
  59. package/dist/core/share.js +420 -0
  60. package/dist/core/share.js.map +1 -0
  61. package/dist/core/templates.d.ts +10 -3
  62. package/dist/core/templates.d.ts.map +1 -1
  63. package/dist/core/templates.js +12 -2
  64. package/dist/core/templates.js.map +1 -1
  65. package/dist/core/tool-integrations.d.ts.map +1 -1
  66. package/dist/core/tool-integrations.js +55 -5
  67. package/dist/core/tool-integrations.js.map +1 -1
  68. package/dist/core/validate.d.ts +1 -1
  69. package/dist/core/validate.d.ts.map +1 -1
  70. package/dist/core/validate.js +56 -15
  71. package/dist/core/validate.js.map +1 -1
  72. package/dist/core/view-text.d.ts +21 -0
  73. package/dist/core/view-text.d.ts.map +1 -0
  74. package/dist/core/view-text.js +92 -0
  75. package/dist/core/view-text.js.map +1 -0
  76. package/package.json +1 -1
@@ -0,0 +1,316 @@
1
+ import { escapeHtml } from './view-text.js';
2
+ import { GITHUB_MARK_PATH, SHARE_BUTTON_HTML, SHARE_WATERMARK } from './share.js';
3
+ /** Derived from the credit line, so the link and the image cannot drift apart. */
4
+ const REPOSITORY_URL = 'https://github.com/' + SHARE_WATERMARK;
5
+ /**
6
+ * The GitHub mark beside the wordmark — the same glyph the shared image
7
+ * credits with, filled rather than stroked because it is a logo here, and it
8
+ * inherits the link's colour so hover reaches it too.
9
+ */
10
+ const BRAND_MARK = '<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true" focusable="false">'
11
+ + '<path d="' + GITHUB_MARK_PATH + '" fill="currentColor"/></svg>';
12
+ /** Shared compact shell for both offline viewers. */
13
+ export const CANVAS_STYLE = String.raw `
14
+ :root { font-family: Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; color: #233c36; background: #f6f8f5; }
15
+ * { box-sizing: border-box; }
16
+ body { margin: 0; }
17
+ main { position: relative; }
18
+ button, summary { font: inherit; color: inherit; cursor: pointer; }
19
+ button:focus-visible, summary:focus-visible, main:focus-visible, a:focus-visible { outline: 2px solid #7750a5; outline-offset: -2px; }
20
+ .viewer-bar { position: relative; z-index: 5; display: flex; align-items: center; gap: 16px; padding: 8px 16px; min-height: 52px; background: #fff; border-bottom: 1px solid #e1e7e1; }
21
+ .viewer-heading { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; }
22
+ .viewer-brand { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 650; white-space: nowrap; padding-right: 12px; border-right: 1px solid #dce4dc; color: inherit; text-decoration: none; }
23
+ .viewer-brand svg { display: block; }
24
+ .viewer-brand:hover { color: #294d3e; text-decoration: underline; text-decoration-color: #a6bcae; text-underline-offset: 2px; }
25
+ .viewer-heading h1 { margin: 0; min-width: 0; font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
26
+ .viewer-count { flex: none; font-size: 12px; color: #64756c; }
27
+ .viewer-sep { flex: none; width: 1px; height: 18px; background: #dce4dc; }
28
+ .viewer-actions { display: flex; align-items: center; gap: 10px; flex: none; }
29
+ /* The controls are icon buttons: square, and close enough together to read as
30
+ one cluster while the count and the divider keep their distance. */
31
+ .viewer-tools { display: flex; align-items: center; gap: 4px; }
32
+ .viewer-bar button, .viewer-info > summary { border: 0; border-radius: 7px; background: transparent; padding: 7px; font-size: 12px; line-height: 20px; white-space: nowrap; }
33
+ .viewer-bar button:hover, .viewer-info > summary:hover, .viewer-info[open] > summary { background: #edf3ef; }
34
+ .viewer-info > summary { list-style: none; }
35
+ .viewer-info > summary::-webkit-details-marker { display: none; }
36
+ /* Toolbar icons sit on their own line: an inline SVG adds the font's descender
37
+ space below it, which lifts the icon out of line with its neighbour. This
38
+ belongs to the shared shell, or one view aligns and the other does not. */
39
+ .viewer-bar button svg, .viewer-bar summary svg { display: block; }
40
+ .viewer-panel { position: absolute; right: 12px; top: calc(100% + 8px); width: min(360px, calc(100vw - 24px)); max-height: calc(100vh - 120px); max-height: calc(100dvh - 120px); overflow: auto; overscroll-behavior: contain; padding: 20px; background: #fff; border: 1px solid #dce4dc; border-radius: 12px; box-shadow: 0 12px 36px #233c3620; font-size: 12px; line-height: 1.6; }
41
+ .viewer-panel h2 { margin: 0 0 10px; font-size: 15px; overflow-wrap: anywhere; }
42
+ .viewer-panel p { margin: 10px 0; color: #64756c; }
43
+ .viewer-stats { display: flex; gap: 8px 16px; flex-wrap: wrap; margin: 16px 0 0; }
44
+ .viewer-stats strong { margin-right: 4px; }
45
+ .canvas-dock { position: absolute; z-index: 4; left: 0; right: 0; bottom: 0; display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 12px 16px; pointer-events: none; }
46
+ .canvas-dock > * { pointer-events: auto; }
47
+ /* Without the script there is no floating canvas: the dock sits at the end of the content. */
48
+ body:not(.interactive) main { padding-bottom: 84px; }
49
+ .canvas-legend { display: grid; gap: 6px; min-width: 0; max-width: min(620px, 100%); padding: 10px 12px; background: #ffffffe8; border: 1px solid #e1e7e1; border-radius: 10px; box-shadow: 0 4px 20px #294d3e0a; font-size: 11px; color: #55655c; }
50
+ .canvas-legend .legend { display: flex; flex-wrap: wrap; gap: 6px 16px; }
51
+ .canvas-legend .legend span { display: flex; align-items: center; gap: 8px; }
52
+ .viewer-panel .hint { border-top: 1px solid #e1e7e1; padding-top: 14px; margin: 16px 0 0; }
53
+ .controls { display: none; align-items: center; gap: 2px; padding: 5px; background: #fff; border: 1px solid #dce4dc; border-radius: 11px; box-shadow: 0 4px 20px #294d3e0a; }
54
+ .controls button { border: 0; background: none; font: inherit; color: inherit; cursor: pointer; padding: 6px 9px; border-radius: 7px; }
55
+ .controls button:hover { background: #edf3ef; }
56
+ .controls output { font: 11px monospace; min-width: 44px; text-align: center; }
57
+ .js-control { display: none; }
58
+ body.interactive { height: 100vh; height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
59
+ .interactive .viewer-bar { flex: none; }
60
+ .interactive main { flex: 1; min-width: 0; min-height: 0; overflow: hidden; touch-action: none; cursor: grab; user-select: none; }
61
+ .interactive #world { position: absolute; }
62
+ .interactive .js-control { display: block; }
63
+ .interactive .controls { display: flex; }
64
+ .interactive main.dragging { cursor: grabbing; }
65
+ @media (max-width: 760px) {
66
+ .viewer-bar { flex-wrap: wrap; gap: 4px 12px; padding: 6px 10px; }
67
+ .viewer-heading { flex-basis: 100%; min-height: 28px; }
68
+ .viewer-actions { width: 100%; justify-content: flex-end; }
69
+ .viewer-count { margin-right: auto; }
70
+ .viewer-panel { right: 10px; }
71
+ .canvas-legend { max-width: 100%; }
72
+ }
73
+ /* Below the count's breakpoint the row it sat on would hold two icons and
74
+ nothing else, so the bar goes back to one line and keeps its height for the
75
+ canvas. The brand gives up its room to the title, which needs it more. */
76
+ @media (max-width: 480px) {
77
+ .viewer-count, .viewer-sep, .viewer-brand { display: none; }
78
+ /* flex-basis 0, not auto: an auto basis measures the whole title, which no
79
+ row can hold, so the bar would wrap back into two lines. */
80
+ .viewer-heading { flex-basis: 0; }
81
+ .viewer-actions { width: auto; }
82
+ }
83
+ @media (pointer: coarse) {
84
+ .viewer-bar button, .viewer-info > summary { min-height: 44px; min-width: 44px; }
85
+ }
86
+ `;
87
+ /**
88
+ * The Info disclosure is icon-only: the word carried no information of its
89
+ * own, and the glyph is unambiguous. The label keeps it accessible, and the
90
+ * separator sets the read-only count apart from the controls.
91
+ */
92
+ const INFO_ICON = '<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false">'
93
+ + '<circle cx="8" cy="8" r="6.6" fill="none" stroke="currentColor" stroke-width="1.4"/>'
94
+ + '<circle cx="8" cy="5.1" r=".95" fill="currentColor"/>'
95
+ + '<path d="M8 7.4v4.2" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/></svg>';
96
+ /**
97
+ * The compact toolbar: brand, title, one headline count, and the controls —
98
+ * the Info disclosure and the Save-as-image camera, as one cluster. The canvas
99
+ * dock keeps the gesture controls. A statistic is listed only when its count is
100
+ * non-zero: a zero names something the view does not contain, which sends the
101
+ * reader looking for it.
102
+ */
103
+ export function canvasHeaderHTML(title, stats, description) {
104
+ const listed = stats.filter(([, value]) => value !== 0);
105
+ const first = listed[0];
106
+ return '<header class="viewer-bar">'
107
+ + '<div class="viewer-heading"><a class="viewer-brand" href="' + REPOSITORY_URL + '" target="_blank" rel="noopener noreferrer" title="' + SHARE_WATERMARK + ' on GitHub">' + BRAND_MARK + 'ADR Kit</a><h1>' + escapeHtml(title) + '</h1></div>'
108
+ + '<div class="viewer-actions"><span class="viewer-count">' + (first ? first[1] + ' ' + escapeHtml(first[0]) : '') + '</span>'
109
+ + '<span class="viewer-sep" aria-hidden="true"></span>'
110
+ + '<div class="viewer-tools">'
111
+ + '<details class="viewer-info"><summary aria-label="View information" title="View information">' + INFO_ICON + '</summary><section class="viewer-panel" aria-label="View information">'
112
+ + '<h2>' + escapeHtml(title) + '</h2><p>' + escapeHtml(description) + '</p>'
113
+ + '<div class="viewer-stats">' + listed.map(([label, value]) => '<span><strong>' + value + '</strong>' + escapeHtml(label) + '</span>').join('') + '</div>'
114
+ + '<p id="instructions" class="hint">' + CANVAS_HINT + '</p>'
115
+ + '</section></details>'
116
+ + SHARE_BUTTON_HTML
117
+ + '</div>'
118
+ + '</div></header>';
119
+ }
120
+ /**
121
+ * The canvas dock: the legend over the bottom-left corner, the zoom cluster
122
+ * over the bottom-right. Both float above the canvas, so the header can stay
123
+ * compact without hiding what the picture means. A view with nothing to key
124
+ * draws no legend panel rather than an empty one.
125
+ */
126
+ export function canvasDockHTML(legend, fitLabel) {
127
+ return '<div class="canvas-dock">'
128
+ + (legend === '' ? '' : '<section class="canvas-legend" aria-label="Legend"><div class="legend">' + legend + '</div></section>')
129
+ + canvasControlsHTML(fitLabel)
130
+ + '</div>';
131
+ }
132
+ /** Shared pan/zoom controller for the offline HTML views. */
133
+ export const CANVAS_SCRIPT = String.raw `
134
+
135
+ (() => {
136
+ const viewport = document.getElementById('viewport');
137
+ const world = document.getElementById('world');
138
+ if (!viewport || !world) return;
139
+ document.body.classList.add('interactive');
140
+ const info = document.querySelector('.viewer-info');
141
+ document.addEventListener('keydown', event => {
142
+ if (event.key === 'Escape' && info && info.open) {
143
+ info.open = false;
144
+ info.querySelector('summary').focus();
145
+ }
146
+ });
147
+ document.addEventListener('pointerdown', event => {
148
+ if (info && info.open && !info.contains(event.target)) info.open = false;
149
+ });
150
+ let scale = 1, tx = 0, ty = 0, frame = 0;
151
+
152
+ function paint() {
153
+ world.style.transform = 'translate(' + tx + 'px,' + ty + 'px) scale(' + scale + ')';
154
+ const zoom = document.getElementById('zoom');
155
+ if (zoom) zoom.value = Math.round(scale * 100) + '%';
156
+ }
157
+ /** Overview: the whole diagram inside the viewport, behind the Fit control. */
158
+ function fit() {
159
+ const width = world.offsetWidth, height = world.offsetHeight;
160
+ if (!width || !height) return;
161
+ // Fit above the dock so no card hides behind the legend panel.
162
+ const dock = viewport.querySelector('.canvas-dock');
163
+ const padY = 48 + (dock ? dock.offsetHeight : 0);
164
+ scale = Math.max(.01, Math.min(1, (viewport.clientWidth - 48) / width, (viewport.clientHeight - padY) / height));
165
+ tx = (viewport.clientWidth - width * scale) / 2;
166
+ ty = (viewport.clientHeight - height * scale) / 2;
167
+ paint();
168
+ }
169
+ /**
170
+ * The view a diagram opens in: readable first. Fit the width and never past
171
+ * 1:1, so a tall tree runs past the fold and pans instead of shrinking to a
172
+ * thumbnail whose text cannot be read. Fit is still the overview.
173
+ */
174
+ function fitWidth() {
175
+ const width = world.offsetWidth, height = world.offsetHeight;
176
+ if (!width || !height) return;
177
+ scale = Math.max(.01, Math.min(1, (viewport.clientWidth - 48) / width));
178
+ tx = (viewport.clientWidth - width * scale) / 2;
179
+ const dock = viewport.querySelector('.canvas-dock');
180
+ const room = viewport.clientHeight - 48 - (dock ? dock.offsetHeight : 0);
181
+ ty = height * scale <= room ? (viewport.clientHeight - height * scale) / 2 : 24;
182
+ paint();
183
+ }
184
+ function zoomAt(factor, clientX, clientY) {
185
+ const next = Math.max(Math.min(scale, .05), Math.min(2, scale * factor));
186
+ const rect = viewport.getBoundingClientRect();
187
+ const x = clientX === undefined ? viewport.clientWidth / 2 : clientX - rect.left;
188
+ const y = clientY === undefined ? viewport.clientHeight / 2 : clientY - rect.top;
189
+ tx = x - (x - tx) * next / scale;
190
+ ty = y - (y - ty) * next / scale;
191
+ scale = next;
192
+ paint();
193
+ }
194
+ function zoom(factor) { zoomAt(factor); }
195
+ function addPan(dx, dy) { tx += dx; ty += dy; paint(); }
196
+ function relayout() { if (typeof window.__adrCanvasLayout === 'function') window.__adrCanvasLayout(); }
197
+ function schedule() {
198
+ if (frame) return;
199
+ frame = requestAnimationFrame(() => { frame = 0; relayout(); });
200
+ }
201
+
202
+ const plus = document.getElementById('plus');
203
+ const minus = document.getElementById('minus');
204
+ const fitButton = document.getElementById('fit');
205
+ const reset = document.getElementById('reset');
206
+ if (plus) plus.addEventListener('click', () => zoom(1.2));
207
+ if (minus) minus.addEventListener('click', () => zoom(1 / 1.2));
208
+ if (fitButton) fitButton.addEventListener('click', fit);
209
+ if (reset) reset.addEventListener('click', () => zoom(1 / scale));
210
+
211
+ let drag = null;
212
+ let panned = false;
213
+ // A press that moves pans; a press that stays is a click. The slop
214
+ // threshold is what lets links live inside the canvas: pointer capture
215
+ // would retarget their click, so capture waits until the gesture has
216
+ // committed to being a pan.
217
+ const CLICK_SLOP = 4;
218
+ viewport.addEventListener('pointerdown', event => {
219
+ if (event.button !== 0) return;
220
+ // Real controls keep their native press behavior: with pointer capture
221
+ // their click would land on the viewport and never reach them.
222
+ if (event.target.closest('button, summary, input, select, textarea, .controls, .canvas-legend')) return;
223
+ panned = false;
224
+ drag = { x: event.clientX, y: event.clientY, id: event.pointerId, moved: false };
225
+ });
226
+ viewport.addEventListener('pointermove', event => {
227
+ if (!drag || drag.id !== event.pointerId) return;
228
+ if (!drag.moved) {
229
+ if (Math.abs(event.clientX - drag.x) + Math.abs(event.clientY - drag.y) < CLICK_SLOP) return;
230
+ drag.moved = true;
231
+ viewport.setPointerCapture(event.pointerId);
232
+ viewport.classList.add('dragging');
233
+ }
234
+ tx += event.clientX - drag.x;
235
+ ty += event.clientY - drag.y;
236
+ drag.x = event.clientX;
237
+ drag.y = event.clientY;
238
+ paint();
239
+ });
240
+ viewport.addEventListener('pointerup', event => {
241
+ panned = drag !== null && drag.moved && drag.id === event.pointerId;
242
+ drag = null;
243
+ viewport.classList.remove('dragging');
244
+ });
245
+ for (const name of ['pointercancel', 'lostpointercapture']) {
246
+ viewport.addEventListener(name, () => { drag = null; viewport.classList.remove('dragging'); });
247
+ }
248
+ // The pan must not also open the link it started on, and a native link
249
+ // drag would cancel the pointer gesture outright.
250
+ viewport.addEventListener('click', event => {
251
+ if (!panned) return;
252
+ panned = false;
253
+ event.preventDefault();
254
+ event.stopPropagation();
255
+ }, true);
256
+ viewport.addEventListener('dragstart', event => { if (drag) event.preventDefault(); });
257
+ // A trackpad pinch arrives as a ctrlKey wheel event; macOS also reports
258
+ // Command as metaKey. Either one zooms toward the pointer so the point under
259
+ // the cursor stays put (ADR 11), matching the on-screen hint. A plain wheel
260
+ // pans.
261
+ viewport.addEventListener('wheel', event => {
262
+ event.preventDefault();
263
+ if (event.ctrlKey || event.metaKey) {
264
+ zoomAt(Math.exp(-event.deltaY / 100), event.clientX, event.clientY);
265
+ return;
266
+ }
267
+ tx -= event.deltaX;
268
+ ty -= event.deltaY;
269
+ paint();
270
+ }, { passive: false });
271
+ viewport.addEventListener('keydown', event => {
272
+ if (event.target !== viewport) return;
273
+ const actions = {
274
+ ArrowLeft: () => { tx += 50; }, ArrowRight: () => { tx -= 50; },
275
+ ArrowUp: () => { ty += 50; }, ArrowDown: () => { ty -= 50; },
276
+ '+': () => zoom(1.2), '=': () => zoom(1.2), '-': () => zoom(1 / 1.2), '0': fit
277
+ };
278
+ if (actions[event.key]) { event.preventDefault(); actions[event.key](); paint(); }
279
+ });
280
+ viewport.addEventListener('focusin', event => {
281
+ if (!event.target.closest('.card, #world a')) return;
282
+ const target = event.target.getBoundingClientRect();
283
+ const view = viewport.getBoundingClientRect();
284
+ if (target.left < view.left || target.right > view.right || target.top < view.top || target.bottom > view.bottom) {
285
+ tx += view.left + view.width / 2 - (target.left + target.width / 2);
286
+ ty += view.top + view.height / 2 - (target.top + target.height / 2);
287
+ paint();
288
+ }
289
+ });
290
+ window.addEventListener('resize', () => { relayout(); fitWidth(); });
291
+
292
+ window.__adrCanvas = {
293
+ viewport, world,
294
+ get scale() { return scale; },
295
+ paint, fit, fitWidth, zoom, zoomAt, addPan, schedule, relayout
296
+ };
297
+
298
+ // Open in the readable view, from the shared controller that owns it: the
299
+ // map has no layout step of its own, so without this it would sit unfitted.
300
+ // The tree's cards are laid out by the script that follows this one, which
301
+ // fits again once they are measured.
302
+ relayout();
303
+ fitWidth();
304
+ })();
305
+ `;
306
+ export const CANVAS_HINT = 'Drag anywhere or scroll to pan · Pinch or Ctrl/⌘ + scroll to zoom at the pointer · Arrow keys move · + / − zoom · 0 fits';
307
+ function canvasControlsHTML(fitLabel) {
308
+ return '<div class="controls js-control">'
309
+ + '<button id="minus" aria-label="Zoom out">−</button>'
310
+ + '<output id="zoom" aria-label="Zoom level">100%</output>'
311
+ + '<button id="plus" aria-label="Zoom in">+</button>'
312
+ + '<button id="fit" aria-label="' + escapeHtml(fitLabel) + '">Fit</button>'
313
+ + '<button id="reset">1:1</button>'
314
+ + '</div>';
315
+ }
316
+ //# sourceMappingURL=canvas-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-view.js","sourceRoot":"","sources":["../../src/core/canvas-view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { DeliberationNode } from './deliberation.js';
2
+ /** Render semantic cards on the server; the embedded script only lays them out. */
3
+ export declare function renderCardTree(nodes: DeliberationNode[], title: string): string;
4
+ //# sourceMappingURL=deliberation-html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliberation-html.d.ts","sourceRoot":"","sources":["../../src/core/deliberation-html.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AA8C1D,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAyH/E"}
@@ -0,0 +1,153 @@
1
+ import { RELATION_STYLE, RELATION_SCRIPT } from './relation-focus.js';
2
+ import { isUnlockedQuestion } from './deliberation.js';
3
+ import { CANVAS_STYLE, CANVAS_SCRIPT, canvasHeaderHTML, canvasDockHTML } from './canvas-view.js';
4
+ import { TREE_STYLE, TREE_SCRIPT } from './deliberation-view.js';
5
+ import { SHARE_SCRIPT, SHARE_STYLE } from './share.js';
6
+ import { escapeHtml } from './view-text.js';
7
+ function kindOf(node) {
8
+ return node.type ?? (node.children.length > 0 ? 'question' : 'option');
9
+ }
10
+ /** Only option children can be answers; a settled follow-up is not an answer. */
11
+ function overridden(card) {
12
+ const chosen = card.options.filter(({ node }) => node.status === 'settled');
13
+ return card.kind === 'question' && chosen.length > 0
14
+ && card.options.some(({ node }) => node.recommended)
15
+ && !chosen.some(({ node }) => node.recommended);
16
+ }
17
+ function reason(node) {
18
+ return node.reason === undefined ? '' : `<p class="reason">${escapeHtml(node.reason)}</p>`;
19
+ }
20
+ /**
21
+ * The exception states, with the gloss the legend gives each one. `settled` is
22
+ * absent on purpose: it is what a node is when nothing else is said, so a chip
23
+ * would repeat the same word on every card.
24
+ */
25
+ const STATE_LEGEND = [
26
+ ['open', 'unresolved'],
27
+ ['rejected', 'not taken'],
28
+ ['unrecorded', 'no state marker'],
29
+ ];
30
+ /** Render semantic cards on the server; the embedded script only lays them out. */
31
+ export function renderCardTree(nodes, title) {
32
+ const cards = [];
33
+ let sequence = 0;
34
+ function collect(node, parent = '', anchor = '', depth = 0) {
35
+ const kind = depth === 0 && node.type === undefined ? 'root' : kindOf(node);
36
+ const card = { id: `n${++sequence}`, node, kind, parent, anchor, depth, options: [], children: [], unlocked: false };
37
+ cards.push(card);
38
+ for (const child of node.children) {
39
+ if (kind !== 'option' && kindOf(child) === 'option') {
40
+ const id = `n${++sequence}`;
41
+ card.options.push({ id, node: child });
42
+ for (const followup of child.children) {
43
+ card.children.push(collect(followup, card.id, id, depth + 1).id);
44
+ }
45
+ }
46
+ else {
47
+ card.children.push(collect(child, card.id, '', depth + 1).id);
48
+ }
49
+ }
50
+ return card;
51
+ }
52
+ // A session that settles several decisions records them as sibling roots,
53
+ // which the canvas would draw as unrelated islands. Group them under one
54
+ // presentational card; recorded roots keep their kind, depth, and content.
55
+ // The card carries only its label: no heading, no count, no state.
56
+ const virtual = nodes.length > 1
57
+ ? {
58
+ id: `n${++sequence}`,
59
+ node: { text: '', children: [] },
60
+ kind: 'virtual', parent: '', anchor: '', depth: 0, options: [], children: [], unlocked: false,
61
+ }
62
+ : undefined;
63
+ if (virtual !== undefined)
64
+ cards.push(virtual);
65
+ nodes.forEach((node) => {
66
+ const card = collect(node, virtual?.id ?? '');
67
+ virtual?.children.push(card.id);
68
+ });
69
+ // Whether each card's incoming edge is an unlocked one. The question is the
70
+ // outline's, not the drawing's: the node that raised this card is the option
71
+ // it anchors to, or the card it hangs off when it anchors to none. Asking it
72
+ // here lets the drawn edge and the legend read one answer.
73
+ const byId = new Map(cards.map((card) => [card.id, card]));
74
+ const optionNodes = new Map(cards.flatMap((card) => card.options.map(({ id, node }) => [id, node])));
75
+ for (const card of cards) {
76
+ const parent = byId.get(card.parent);
77
+ if (parent === undefined || card.kind === 'virtual')
78
+ continue;
79
+ const anchor = optionNodes.get(card.anchor);
80
+ card.unlocked = isUnlockedQuestion(card.node, anchor ?? parent.node, anchor === undefined && parent.kind === 'root');
81
+ }
82
+ let questionNumber = 0;
83
+ /** The states that actually draw a chip, so the legend keys only what it can point at. */
84
+ const chipped = new Set();
85
+ const markup = cards.map((card) => {
86
+ const { node, id, kind } = card;
87
+ const override = overridden(card);
88
+ const chosen = card.options.filter((option) => option.node.status === 'settled');
89
+ const other = card.options.filter((option) => option.node.status !== 'settled');
90
+ const status = node.status ?? 'unrecorded';
91
+ // Only an exception earns a chip; a settled node already reads as settled
92
+ // from its chosen answer, so the same word on every card would say nothing.
93
+ const chip = kind !== 'virtual' && status !== 'settled';
94
+ if (chip)
95
+ chipped.add(status);
96
+ const label = kind === 'question' ? `QUESTION ${String(++questionNumber).padStart(2, '0')}`
97
+ : kind === 'virtual' ? 'DELIBERATION' : kind.toUpperCase();
98
+ const stateChip = chip ? `<span class="state ${status}">${status}</span>` : '';
99
+ // A folded option writes its state as plain text, not as a chip, so it earns
100
+ // no legend key: the word is already readable and the pill is what needs one.
101
+ const optionMarkup = (option) => {
102
+ const selected = option.node.status === 'settled';
103
+ const state = option.node.status ?? 'unrecorded';
104
+ return `<div id="${option.id}" class="${selected ? 'answer' : 'alt'}" data-state="${state}">
105
+ <span class="badge">${selected ? '✓ Selected' : escapeHtml(state)}${option.node.recommended ? ' · Agent recommended' : ''}</span>
106
+ <p>${escapeHtml(option.node.text)}</p>${reason(option.node)}</div>`;
107
+ };
108
+ const heading = kind === 'virtual' ? '' : `<h2 id="${id}-title">${escapeHtml(node.text)}</h2>`;
109
+ const labelledBy = kind === 'virtual' ? '' : ` aria-labelledby="${id}-title"`;
110
+ const toggleLabel = kind === 'virtual' ? 'Toggle all decisions' : `Toggle follow-ups: ${escapeHtml(node.text)}`;
111
+ return `<article id="${id}" class="card ${kind}" data-parent="${card.parent}" data-anchor="${card.anchor}" data-state="${status}" data-unlocked="${card.unlocked}" style="--depth:${card.depth}"${labelledBy}${kind === 'virtual' ? '' : ' tabindex="0"'}>
112
+ <div class="cardhead"><div class="label"><span>${label}</span>${stateChip}</div>
113
+ ${heading}${reason(node)}
114
+ ${node.recommended ? '<p class="badge">Agent recommended</p>' : ''}
115
+ ${override ? '<p class="override">Human override · recommendation not taken</p>' : ''}</div>
116
+ ${chosen.map(optionMarkup).join('\n')}
117
+ ${other.length === 0 ? '' : `<details class="alts"><summary>${other.length} other option${other.length === 1 ? '' : 's'}${override ? ' · includes recommendation' : ''}</summary>${other.map(optionMarkup).join('\n')}</details>`}
118
+ ${card.children.length === 0 ? '' : `<button class="branch" aria-expanded="true" aria-controls="${card.children.join(' ')}" aria-label="${toggleLabel}">−</button>`}
119
+ </article>`;
120
+ }).join('\n');
121
+ const overrides = cards.filter(overridden).length;
122
+ const stats = [
123
+ ['questions', questionNumber],
124
+ ['options', cards.reduce((sum, card) => sum + card.options.length, 0)],
125
+ ['overrides', overrides],
126
+ ];
127
+ // The legend quotes what the picture draws: an entry for something no card
128
+ // shows sends the reader looking for it, so each one waits for its object.
129
+ // The edge keys carry a line sample in the stroke the view draws, because a
130
+ // dashed text dash looks like neither of the two edges it would be naming.
131
+ const legend = [
132
+ cards.some((card) => card.options.some(({ node }) => node.status === 'settled'))
133
+ ? '<span data-share-selector=".card:not([hidden]) .answer">✓ Selected answer</span>' : '',
134
+ cards.some((card) => card.parent !== '') ? '<span data-share-selector="#edges path[data-unlocked=false]"><i class="edge-key"></i>Raised by</span>' : '',
135
+ cards.some((card) => card.unlocked) ? '<span data-share-selector="#edges path[data-unlocked=true]"><i class="edge-key unlocked"></i>Unlocked question</span>' : '',
136
+ overrides === 0 ? '' : '<span class="override-key" data-share-selector=".card:not([hidden]) .override">● Human override</span>',
137
+ ...STATE_LEGEND
138
+ .filter(([state]) => chipped.has(state))
139
+ .map(([state, gloss]) => `<span data-share-selector=".card:not([hidden]) .cardhead .state.${state}"><span class="state ${state}">${state}</span>${gloss}</span>`),
140
+ ].filter(Boolean).join('');
141
+ return `<!doctype html>
142
+ <html lang="en">
143
+ <head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
144
+ <title>${escapeHtml(title)} — deliberation tree</title><style>${TREE_STYLE}${CANVAS_STYLE}${SHARE_STYLE}${RELATION_STYLE}</style></head>
145
+ <body>
146
+ ${canvasHeaderHTML(title, stats, 'Hover or focus a card to trace its ancestors and follow-ups. Escape clears the highlight.')}
147
+ <main id="viewport" tabindex="0" aria-label="Decision tree" aria-describedby="instructions"><div id="world"><svg id="edges" aria-hidden="true"></svg><div id="cards">${markup}</div></div>
148
+ ${canvasDockHTML(legend, 'Fit tree')}</main>
149
+ <noscript><p class="no-script">JavaScript is disabled. All cards are shown in outline order; expand other options to read their reasons.</p></noscript>
150
+ <script>${CANVAS_SCRIPT}${SHARE_SCRIPT}${TREE_SCRIPT}${RELATION_SCRIPT}</script>
151
+ </body></html>\n`;
152
+ }
153
+ //# sourceMappingURL=deliberation-html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliberation-html.js","sourceRoot":"","sources":["../../src/core/deliberation-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAc5C,SAAS,MAAM,CAAC,IAAsB;IACpC,OAAO,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,iFAAiF;AACjF,SAAS,UAAU,CAAC,IAAU;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;WAC/C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;WACjD,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,MAAM,CAAC,IAAsB;IACpC,OAAO,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;AAC7F,CAAC;AAED;;;;GAIG;AACH,MAAM,YAAY,GAA4B;IAC5C,CAAC,MAAM,EAAE,YAAY,CAAC;IACtB,CAAC,UAAU,EAAE,WAAW,CAAC;IACzB,CAAC,YAAY,EAAE,iBAAiB,CAAC;CAClC,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,KAAyB,EAAE,KAAa;IACrE,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,SAAS,OAAO,CAAC,IAAsB,EAAE,MAAM,GAAG,EAAE,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,CAAC;QAC1E,MAAM,IAAI,GAAG,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAS,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC3H,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClC,IAAI,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACpD,MAAM,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBACvC,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;oBACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACnE,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAChE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,0EAA0E;IAC1E,yEAAyE;IACzE,2EAA2E;IAC3E,mEAAmE;IACnE,MAAM,OAAO,GAAqB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChD,CAAC,CAAC;YACE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACpB,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;YAChC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK;SAC9F;QACH,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,OAAO,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/C,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IACH,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,2DAA2D;IAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,CAAU,CAAC,CAAC,CAAC,CAAC;IAC9G,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;YAAE,SAAS;QAC9D,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,GAAG,kBAAkB,CAChC,IAAI,CAAC,IAAI,EACT,MAAM,IAAI,MAAM,CAAC,IAAI,EACrB,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAC/C,CAAC;IACJ,CAAC;IACD,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,0FAA0F;IAC1F,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAChC,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QAChC,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QACjF,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC;QAC3C,0EAA0E;QAC1E,4EAA4E;QAC5E,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC;QACxD,IAAI,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,MAAM,CAAC,EAAE,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;YACzF,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAC7D,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,sBAAsB,MAAM,KAAK,MAAM,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,6EAA6E;QAC7E,8EAA8E;QAC9E,MAAM,YAAY,GAAG,CAAC,MAA+B,EAAU,EAAE;YAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC;YAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC;YACjD,OAAO,YAAY,MAAM,CAAC,EAAE,YAAY,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,iBAAiB,KAAK;8BACjE,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE;aACpH,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;QACxE,CAAC,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,WAAW,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QAC/F,MAAM,UAAU,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,EAAE,SAAS,CAAC;QAC9E,MAAM,WAAW,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,sBAAsB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChH,OAAO,gBAAgB,EAAE,iBAAiB,IAAI,kBAAkB,IAAI,CAAC,MAAM,kBAAkB,IAAI,CAAC,MAAM,iBAAiB,MAAM,oBAAoB,IAAI,CAAC,QAAQ,oBAAoB,IAAI,CAAC,KAAK,IAAI,UAAU,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe;uDACrM,KAAK,UAAU,SAAS;QACvE,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,wCAAwC,CAAC,CAAC,CAAC,EAAE;QAChE,QAAQ,CAAC,CAAC,CAAC,mEAAmE,CAAC,CAAC,CAAC,EAAE;QACnF,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACnC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kCAAkC,KAAK,CAAC,MAAM,gBAAgB,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,aAAa,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY;QAC/N,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,8DAA8D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,WAAW,cAAc;eAC1J,CAAC;IACd,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IAClD,MAAM,KAAK,GAA4B;QACrC,CAAC,WAAW,EAAE,cAAc,CAAC;QAC7B,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACtE,CAAC,WAAW,EAAE,SAAS,CAAC;KACzB,CAAC;IACF,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,MAAM,MAAM,GAAG;QACb,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;YAC9E,CAAC,CAAC,kFAAkF,CAAC,CAAC,CAAC,EAAE;QAC3F,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,uGAAuG,CAAC,CAAC,CAAC,EAAE;QACvJ,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,uHAAuH,CAAC,CAAC,CAAC,EAAE;QAClK,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,wGAAwG;QAC/H,GAAG,YAAY;aACZ,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;aACvC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,mEAAmE,KAAK,wBAAwB,KAAK,KAAK,KAAK,UAAU,KAAK,SAAS,CAAC;KACpK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3B,OAAO;;;SAGA,UAAU,CAAC,KAAK,CAAC,sCAAsC,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,cAAc;;EAEtH,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,2FAA2F,CAAC;uKAC0C,MAAM;EAC3K,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC;;UAE1B,aAAa,GAAG,YAAY,GAAG,WAAW,GAAG,eAAe;iBACrD,CAAC;AAClB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** Inline assets for the offline tree viewer. No network or runtime dependency. */
2
+ export declare const TREE_STYLE: string;
3
+ export declare const TREE_SCRIPT: string;
4
+ //# sourceMappingURL=deliberation-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deliberation-view.d.ts","sourceRoot":"","sources":["../../src/core/deliberation-view.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,eAAO,MAAM,UAAU,QA4NtB,CAAC;AAIF,eAAO,MAAM,WAAW,QAmHvB,CAAC"}