@issuegraph/viewer 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 (67) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +156 -0
  3. package/dist/clusters.d.ts +34 -0
  4. package/dist/clusters.d.ts.map +1 -0
  5. package/dist/clusters.js +195 -0
  6. package/dist/clusters.js.map +1 -0
  7. package/dist/document.d.ts +190 -0
  8. package/dist/document.d.ts.map +1 -0
  9. package/dist/document.js +308 -0
  10. package/dist/document.js.map +1 -0
  11. package/dist/element.d.ts +95 -0
  12. package/dist/element.d.ts.map +1 -0
  13. package/dist/element.js +174 -0
  14. package/dist/element.js.map +1 -0
  15. package/dist/index.d.ts +40 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +33 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/layout.d.ts +122 -0
  20. package/dist/layout.d.ts.map +1 -0
  21. package/dist/layout.js +297 -0
  22. package/dist/layout.js.map +1 -0
  23. package/dist/mount.d.ts +64 -0
  24. package/dist/mount.d.ts.map +1 -0
  25. package/dist/mount.js +402 -0
  26. package/dist/mount.js.map +1 -0
  27. package/dist/navigation.d.ts +56 -0
  28. package/dist/navigation.d.ts.map +1 -0
  29. package/dist/navigation.js +121 -0
  30. package/dist/navigation.js.map +1 -0
  31. package/dist/parts.d.ts +89 -0
  32. package/dist/parts.d.ts.map +1 -0
  33. package/dist/parts.js +214 -0
  34. package/dist/parts.js.map +1 -0
  35. package/dist/projections/graph.d.ts +30 -0
  36. package/dist/projections/graph.d.ts.map +1 -0
  37. package/dist/projections/graph.js +644 -0
  38. package/dist/projections/graph.js.map +1 -0
  39. package/dist/projections/linear.d.ts +35 -0
  40. package/dist/projections/linear.d.ts.map +1 -0
  41. package/dist/projections/linear.js +157 -0
  42. package/dist/projections/linear.js.map +1 -0
  43. package/dist/projections/tree.d.ts +17 -0
  44. package/dist/projections/tree.d.ts.map +1 -0
  45. package/dist/projections/tree.js +209 -0
  46. package/dist/projections/tree.js.map +1 -0
  47. package/dist/render.d.ts +35 -0
  48. package/dist/render.d.ts.map +1 -0
  49. package/dist/render.js +45 -0
  50. package/dist/render.js.map +1 -0
  51. package/dist/scene.d.ts +94 -0
  52. package/dist/scene.d.ts.map +1 -0
  53. package/dist/scene.js +48 -0
  54. package/dist/scene.js.map +1 -0
  55. package/dist/styles.d.ts +17 -0
  56. package/dist/styles.d.ts.map +1 -0
  57. package/dist/styles.js +389 -0
  58. package/dist/styles.js.map +1 -0
  59. package/dist/theme.d.ts +71 -0
  60. package/dist/theme.d.ts.map +1 -0
  61. package/dist/theme.js +169 -0
  62. package/dist/theme.js.map +1 -0
  63. package/dist/vocabulary.d.ts +107 -0
  64. package/dist/vocabulary.d.ts.map +1 -0
  65. package/dist/vocabulary.js +98 -0
  66. package/dist/vocabulary.js.map +1 -0
  67. package/package.json +56 -0
@@ -0,0 +1,174 @@
1
+ /**
2
+ * One description of rendered structure, and the two renderers that consume it.
3
+ *
4
+ * A projection returns an {@link ElementSpec} tree. {@link renderMarkup} turns
5
+ * it into a string — server rendering, and every test in this package that
6
+ * asserts what is drawn. {@link materialize} builds the same tree out of real
7
+ * nodes for {@link ../mount.ts mountViewer}.
8
+ *
9
+ * THE POINT IS THAT THEY CANNOT DISAGREE. The obvious alternative — build
10
+ * markup, then set `innerHTML` — makes the string path and the node path one
11
+ * implementation but leaves the package unable to render without a parser; the
12
+ * other obvious alternative, writing the DOM path separately, makes them two
13
+ * implementations that drift. One spec with two total walks over it is the only
14
+ * arrangement where a test on the markup is evidence about the nodes.
15
+ *
16
+ * Nothing here reaches a global. {@link materialize} takes the document it
17
+ * builds into, which is what keeps this module importable on a runtime that has
18
+ * no DOM at all.
19
+ */
20
+ export const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
21
+ /**
22
+ * HTML elements that may not carry children and must not be given a closing
23
+ * tag. An empty non-void element still renders `<div></div>`, because
24
+ * `<div/>` is not self-closing in HTML and browsers nest whatever follows it.
25
+ */
26
+ const VOID_HTML_TAGS = new Set([
27
+ 'area',
28
+ 'base',
29
+ 'br',
30
+ 'col',
31
+ 'embed',
32
+ 'hr',
33
+ 'img',
34
+ 'input',
35
+ 'link',
36
+ 'meta',
37
+ 'source',
38
+ 'track',
39
+ 'wbr',
40
+ ]);
41
+ function escapeText(value) {
42
+ return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
43
+ }
44
+ function escapeAttr(value) {
45
+ return escapeText(value).replace(/"/g, '&quot;');
46
+ }
47
+ function isSpec(child) {
48
+ return typeof child !== 'string';
49
+ }
50
+ function renderAttrs(attrs) {
51
+ if (attrs === undefined)
52
+ return '';
53
+ const parts = [];
54
+ for (const [name, value] of Object.entries(attrs)) {
55
+ if (value === undefined || value === null || value === false)
56
+ continue;
57
+ if (value === true) {
58
+ parts.push(` ${name}`);
59
+ continue;
60
+ }
61
+ parts.push(` ${name}="${escapeAttr(typeof value === 'number' ? String(value) : value)}"`);
62
+ }
63
+ return parts.join('');
64
+ }
65
+ /**
66
+ * Render a spec tree to markup.
67
+ *
68
+ * Pure and deterministic: attribute order follows the spec's own key order, so
69
+ * the same tree always produces the same bytes. That is what makes a
70
+ * two-themes-one-markup assertion possible.
71
+ *
72
+ * ITERATIVE, LIKE EVERY OTHER WALK IN THIS PACKAGE. A recursive renderer costs
73
+ * one call frame per level of nesting, and the tree projection's depth is the
74
+ * host's `decomposed-from` chain — which nothing bounds. `renderViewer`
75
+ * documents itself as TOTAL, so a document that makes it throw falsifies the
76
+ * claim whatever the depth was. This was the third stack-depth finding on this
77
+ * package; making the traversal iterative removes the class rather than
78
+ * capping the input, which would have invented a product rule the design does
79
+ * not have.
80
+ */
81
+ export function renderMarkup(spec, inheritedNs) {
82
+ const out = [];
83
+ const stack = [{ kind: 'open', spec, ns: inheritedNs }];
84
+ while (stack.length > 0) {
85
+ const frame = stack.pop();
86
+ if (frame.kind === 'close') {
87
+ out.push(`</${frame.tag}>`);
88
+ continue;
89
+ }
90
+ if (frame.kind === 'text') {
91
+ out.push(escapeText(frame.text));
92
+ continue;
93
+ }
94
+ const ns = frame.spec.ns ?? frame.ns;
95
+ const open = `<${frame.spec.tag}${renderAttrs(frame.spec.attrs)}`;
96
+ const children = frame.spec.children ?? [];
97
+ if (children.length === 0) {
98
+ out.push(ns === 'svg' || VOID_HTML_TAGS.has(frame.spec.tag)
99
+ ? `${open} />`
100
+ : `${open}></${frame.spec.tag}>`);
101
+ continue;
102
+ }
103
+ out.push(`${open}>`);
104
+ stack.push({ kind: 'close', tag: frame.spec.tag });
105
+ // Pushed in reverse so they pop in document order.
106
+ for (let index = children.length - 1; index >= 0; index -= 1) {
107
+ const child = children[index];
108
+ stack.push(isSpec(child) ? { kind: 'open', spec: child, ns } : { kind: 'text', text: child });
109
+ }
110
+ }
111
+ return out.join('');
112
+ }
113
+ /**
114
+ * Build a spec tree as nodes in the supplied document.
115
+ *
116
+ * Attributes follow `renderMarkup`'s rules exactly — same omissions, same
117
+ * number coercion, same bare-attribute handling for `true` — because the two
118
+ * walks are only useful as one grammar.
119
+ */
120
+ export function materialize(doc, spec, options = {}) {
121
+ // Iterative for the reason `renderMarkup` is: the two walks are only useful
122
+ // as one grammar, so they have to share the depth behaviour too.
123
+ const stack = [{ kind: 'element', spec, ns: options.ns, parent: null }];
124
+ let root = null;
125
+ while (stack.length > 0) {
126
+ const frame = stack.pop();
127
+ if (frame.kind === 'text') {
128
+ frame.parent.appendChild(doc.createTextNode(frame.text));
129
+ continue;
130
+ }
131
+ const ns = frame.spec.ns ?? frame.ns;
132
+ const built = ns === 'svg'
133
+ ? doc.createElementNS(SVG_NAMESPACE, frame.spec.tag)
134
+ : doc.createElement(frame.spec.tag);
135
+ if (frame.spec.attrs !== undefined) {
136
+ for (const [name, value] of Object.entries(frame.spec.attrs)) {
137
+ if (value === undefined || value === null || value === false)
138
+ continue;
139
+ built.setAttribute(name, value === true ? '' : String(value));
140
+ }
141
+ }
142
+ options.onElement?.(frame.spec, built);
143
+ // Appended on the way DOWN, so a node is in place before its own children
144
+ // are popped. That is what keeps sibling order right without holding the
145
+ // parent's frame open, which is the whole point of dropping the recursion.
146
+ if (frame.parent === null)
147
+ root = built;
148
+ else
149
+ frame.parent.appendChild(built);
150
+ const children = frame.spec.children ?? [];
151
+ // Pushed in reverse so they pop in document order.
152
+ for (let index = children.length - 1; index >= 0; index -= 1) {
153
+ const child = children[index];
154
+ stack.push(isSpec(child)
155
+ ? { kind: 'element', spec: child, ns, parent: built }
156
+ : { kind: 'text', text: child, parent: built });
157
+ }
158
+ }
159
+ // The seed frame always builds an element, so this is set by the first pass.
160
+ return root;
161
+ }
162
+ /** A spec, with `undefined` children dropped — the common conditional-child case. */
163
+ export function element(tag, attrs, children = []) {
164
+ return {
165
+ tag,
166
+ attrs,
167
+ children: children.filter((child) => child !== null && child !== undefined && child !== false),
168
+ };
169
+ }
170
+ /** The same, in the SVG namespace. */
171
+ export function svg(tag, attrs, children = []) {
172
+ return { ...element(tag, attrs, children), ns: 'svg' };
173
+ }
174
+ //# sourceMappingURL=element.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element.js","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `@issuegraph/viewer` — render an Issuegraph document as a work order.
3
+ *
4
+ * The innermost layer of the Issuegraph UI, and the whole of its contract:
5
+ *
6
+ * in {issues, edges, order} + a projection choice
7
+ * out onSelect, onHover
8
+ * never fetching, mutation, auth, persistence, or a host's vocabulary
9
+ *
10
+ * It owns the node, edge and badge grammar, the layout maths and the readiness
11
+ * stations. It derives no order — `@issuegraph/derive` does that, and a second
12
+ * implementation here would be a mirror whose input space drifts.
13
+ *
14
+ * Two entry points: {@link renderViewer} is pure and returns markup plus
15
+ * styles, which is what server rendering and every test in this package use;
16
+ * {@link mountViewer} builds the same tree as nodes and wires the two callbacks.
17
+ *
18
+ * THE SURFACE IS WHAT A CONSUMER CALLS, and no more. Internals stay internal
19
+ * because a published package can add an export later and can never take one
20
+ * back.
21
+ *
22
+ * @see https://github.com/autnmy/issuegraph/blob/main/SPEC.md
23
+ */
24
+ export type { HoldFamily, NormalizeResult, NormalizedDocument, RankProvenance, ViewerDocument, ViewerEdge, ViewerExclusion, ViewerHold, ViewerIssue, ViewerOrder, ViewerSlot, } from './document.ts';
25
+ export { normalizeDocument } from './document.ts';
26
+ export type { Projection, Scene } from './scene.ts';
27
+ export { KEY_ATTRIBUTE } from './scene.ts';
28
+ export type { RenderOptions, RenderResult } from './render.ts';
29
+ export { renderViewer } from './render.ts';
30
+ export type { MountElement, MountEvent, MountOptions, ViewerHandle, } from './mount.ts';
31
+ export { mountViewer } from './mount.ts';
32
+ export type { NavigationCommand, NavigationResult, NavigationState } from './navigation.ts';
33
+ export { initialNavigationState, navigate, reconcile } from './navigation.ts';
34
+ export type { ColorToken, MetricToken, Theme, ThemeOverride, TypeToken, } from './theme.ts';
35
+ export { COLOR_TOKENS, METRIC_TOKENS, THEME_TOKENS, TYPE_TOKENS, defaultTheme, extendTheme, themeCss, } from './theme.ts';
36
+ export { viewerStylesheet } from './styles.ts';
37
+ export type { EdgeDash, EdgeTerminal, EdgeTreatment, OrderingEffect } from './vocabulary.ts';
38
+ export { EDGE_TREATMENTS, dashArrayFor, treatmentFor } from './vocabulary.ts';
39
+ export { CLUSTER_ONLY_BUDGET, GRAPH_NODE_BUDGET } from './projections/graph.ts';
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,YAAY,EACV,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,cAAc,EACd,UAAU,EACV,eAAe,EACf,UAAU,EACV,WAAW,EACX,WAAW,EACX,UAAU,GACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,YAAY,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,YAAY,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,YAAY,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,YAAY,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC5F,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE9E,YAAY,EACV,UAAU,EACV,WAAW,EACX,KAAK,EACL,aAAa,EACb,SAAS,GACV,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE9E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `@issuegraph/viewer` — render an Issuegraph document as a work order.
3
+ *
4
+ * The innermost layer of the Issuegraph UI, and the whole of its contract:
5
+ *
6
+ * in {issues, edges, order} + a projection choice
7
+ * out onSelect, onHover
8
+ * never fetching, mutation, auth, persistence, or a host's vocabulary
9
+ *
10
+ * It owns the node, edge and badge grammar, the layout maths and the readiness
11
+ * stations. It derives no order — `@issuegraph/derive` does that, and a second
12
+ * implementation here would be a mirror whose input space drifts.
13
+ *
14
+ * Two entry points: {@link renderViewer} is pure and returns markup plus
15
+ * styles, which is what server rendering and every test in this package use;
16
+ * {@link mountViewer} builds the same tree as nodes and wires the two callbacks.
17
+ *
18
+ * THE SURFACE IS WHAT A CONSUMER CALLS, and no more. Internals stay internal
19
+ * because a published package can add an export later and can never take one
20
+ * back.
21
+ *
22
+ * @see https://github.com/autnmy/issuegraph/blob/main/SPEC.md
23
+ */
24
+ export { normalizeDocument } from "./document.js";
25
+ export { KEY_ATTRIBUTE } from "./scene.js";
26
+ export { renderViewer } from "./render.js";
27
+ export { mountViewer } from "./mount.js";
28
+ export { initialNavigationState, navigate, reconcile } from "./navigation.js";
29
+ export { COLOR_TOKENS, METRIC_TOKENS, THEME_TOKENS, TYPE_TOKENS, defaultTheme, extendTheme, themeCss, } from "./theme.js";
30
+ export { viewerStylesheet } from "./styles.js";
31
+ export { EDGE_TREATMENTS, dashArrayFor, treatmentFor } from "./vocabulary.js";
32
+ export { CLUSTER_ONLY_BUDGET, GRAPH_NODE_BUDGET } from "./projections/graph.js";
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAeH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAG3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQ3C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAS9E,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,WAAW,EACX,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE9E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Graph geometry, computed — never eyeballed.
3
+ *
4
+ * Three columns, three jobs: the LEFT GUTTER holds open issues outside the
5
+ * order that explain a hold, the CENTRE SPINE is the work order itself, and the
6
+ * RIGHT GUTTER holds issues the order never works. Sequence is vertical
7
+ * position on the spine; dependency is everything off it.
8
+ *
9
+ * Two rules carry most of the weight, and both come from the design's
10
+ * implementation note rather than from taste:
11
+ *
12
+ * - **Every edge endpoint is derived from a node's computed bounds.** An edge
13
+ * terminates ON a bound, never at a remembered offset, so a node that
14
+ * changes size moves its edges with it.
15
+ * - **Arcs stay out of the occupied x-ranges** and out of the station band.
16
+ * The colour-blind-safety claim rests on four redundant channels, and the
17
+ * terminal marker is the one that separates `decomposed-from` from
18
+ * `duplicate-of` — a marker hidden under an opaque card silently drops the
19
+ * encoding to three.
20
+ *
21
+ * Deterministic by construction: no measurement, no randomness, no clock. The
22
+ * same document always produces the same coordinates, which is what lets a
23
+ * panel whose job is to be authoritative be trusted between refreshes.
24
+ */
25
+ import type { NormalizedDocument, ViewerEdge } from './document.ts';
26
+ import type { Theme } from './theme.ts';
27
+ /**
28
+ * Custom properties carrying LAYOUT OUTPUT rather than theme input.
29
+ *
30
+ * A theme token is a value a host chooses; these are values this module
31
+ * COMPUTES and writes onto individual elements, so the rail can sit on the node
32
+ * it names without either side hard-coding a coordinate. They are declared here
33
+ * so `styles.test.ts` can tell the two kinds apart — a `var()` naming neither a
34
+ * theme token nor one of these is still a defect, and still fails.
35
+ */
36
+ export declare const LAYOUT_PROPERTIES: readonly string[];
37
+ /** Which column a node sits in. */
38
+ export type Column = 'left' | 'spine' | 'right';
39
+ export interface NodeBox {
40
+ readonly key: string;
41
+ readonly column: Column;
42
+ readonly x: number;
43
+ readonly y: number;
44
+ readonly width: number;
45
+ readonly height: number;
46
+ /** The slot this node belongs to, when it is on the spine. */
47
+ readonly rank: number | null;
48
+ readonly held: boolean;
49
+ }
50
+ export interface Point {
51
+ readonly x: number;
52
+ readonly y: number;
53
+ }
54
+ export interface GraphLayout {
55
+ readonly width: number;
56
+ readonly height: number;
57
+ readonly nodes: ReadonlyMap<string, NodeBox>;
58
+ /** Spine keys in RANK order — the order navigation walks. */
59
+ readonly spineOrder: readonly string[];
60
+ /** Slot lead -> the members drawn under it, in document order. */
61
+ readonly slotMembers: ReadonlyMap<string, readonly string[]>;
62
+ /** The free vertical channels arcs route through. */
63
+ readonly leftChannel: number;
64
+ readonly rightChannel: number;
65
+ }
66
+ /**
67
+ * A node's width follows its own contents rather than the column, so an edge
68
+ * terminating on its bound lands where the reader sees the box end. Clamped to
69
+ * the column so the channels stay free.
70
+ */
71
+ /**
72
+ * The label as it fits the box the layout gave it.
73
+ *
74
+ * `boxWidth` CLAMPS to the column, so a title longer than the column gets a box
75
+ * narrower than its text — and an SVG `<text>` neither wraps nor clips, so the
76
+ * overflow ran straight across the routing channel and the neighbouring nodes,
77
+ * hiding the edges and labels the graph exists to show. Long issue titles are
78
+ * ordinary, so this was the common case rather than an edge one.
79
+ *
80
+ * IT MEASURES WITH THE SAME METRIC `boxWidth` SIZES WITH, which is the whole
81
+ * reason this belongs beside it rather than in the projection. Both read
82
+ * `--ig-char-width`, so the renderer's idea of what fits and the layout's cannot
83
+ * disagree — a separate estimate in the drawing code would be a second opinion
84
+ * about the same question, and the two would drift.
85
+ *
86
+ * THE ELLIPSIS IS THIS PACKAGE'S OWN TREATMENT, not a new convention: the rail's
87
+ * HTML rows already resolve an over-long title with `text-overflow: ellipsis`,
88
+ * so a canvas label that simply stopped mid-word would make the two surfaces
89
+ * disagree about what a truncated title looks like.
90
+ *
91
+ * NOTHING IS LOST TO A READER — the full title stays in the node's accessible
92
+ * name and its `<title>`, so this shortens what is DRAWN and never what is
93
+ * available.
94
+ */
95
+ export declare function fitLabel(theme: Theme, label: string, width: number): string;
96
+ /** Lay a document out. Pure: coordinates depend only on the document and the theme. */
97
+ export declare function layoutGraph(document: NormalizedDocument, theme: Theme): GraphLayout;
98
+ export interface EdgeGeometry {
99
+ /** The SVG path. Always a quadratic through one of the free channels. */
100
+ readonly d: string;
101
+ readonly start: Point;
102
+ readonly end: Point;
103
+ /** Radians. Orients the terminal marker along the path's own tangent. */
104
+ readonly endAngle: number;
105
+ }
106
+ /**
107
+ * The geometry for one edge, derived entirely from the two boxes' bounds.
108
+ *
109
+ * Returns `null` when either end has no box — which `normalizeDocument` has
110
+ * already made impossible for a kept edge, so a `null` here means a caller
111
+ * built a layout from a different document than the edge came from. Refusing is
112
+ * better than drawing at coordinates nobody computed.
113
+ */
114
+ export declare function edgeGeometry(layout: GraphLayout, edge: ViewerEdge): EdgeGeometry | null;
115
+ /** The box enclosing a together unit's members, padded clear of their bounds. */
116
+ export declare function enclosureBounds(layout: GraphLayout, members: readonly string[], theme: Theme): {
117
+ x: number;
118
+ y: number;
119
+ width: number;
120
+ height: number;
121
+ } | null;
122
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../src/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAe,KAAK,EAAE,MAAM,YAAY,CAAC;AAErD;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAO7C,CAAC;AAEH,mCAAmC;AACnC,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,kEAAkE;IAClE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IAC7D,qDAAqD;IACrD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAMD;;;;GAIG;AACH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS3E;AA8DD,uFAAuF;AACvF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,kBAAkB,EAAE,KAAK,EAAE,KAAK,GAAG,WAAW,CA8EnF;AAED,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC;IACpB,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AA2CD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,UAAU,GACf,YAAY,GAAG,IAAI,CAyBrB;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAC7B,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,KAAK,EAAE,KAAK,GACX;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWhE"}