@issuegraph/editor 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 (143) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +238 -0
  3. package/dist/audit/findings.d.ts +225 -0
  4. package/dist/audit/findings.d.ts.map +1 -0
  5. package/dist/audit/findings.js +348 -0
  6. package/dist/audit/findings.js.map +1 -0
  7. package/dist/audit/styles.d.ts +37 -0
  8. package/dist/audit/styles.d.ts.map +1 -0
  9. package/dist/audit/styles.js +72 -0
  10. package/dist/audit/styles.js.map +1 -0
  11. package/dist/audit/surface.d.ts +155 -0
  12. package/dist/audit/surface.d.ts.map +1 -0
  13. package/dist/audit/surface.js +202 -0
  14. package/dist/audit/surface.js.map +1 -0
  15. package/dist/create/draft.d.ts +119 -0
  16. package/dist/create/draft.d.ts.map +1 -0
  17. package/dist/create/draft.js +114 -0
  18. package/dist/create/draft.js.map +1 -0
  19. package/dist/create/keys.d.ts +225 -0
  20. package/dist/create/keys.d.ts.map +1 -0
  21. package/dist/create/keys.js +228 -0
  22. package/dist/create/keys.js.map +1 -0
  23. package/dist/create/placement.d.ts +69 -0
  24. package/dist/create/placement.d.ts.map +1 -0
  25. package/dist/create/placement.js +76 -0
  26. package/dist/create/placement.js.map +1 -0
  27. package/dist/firstpass/batch.d.ts +190 -0
  28. package/dist/firstpass/batch.d.ts.map +1 -0
  29. package/dist/firstpass/batch.js +143 -0
  30. package/dist/firstpass/batch.js.map +1 -0
  31. package/dist/firstpass/candidates.d.ts +128 -0
  32. package/dist/firstpass/candidates.d.ts.map +1 -0
  33. package/dist/firstpass/candidates.js +39 -0
  34. package/dist/firstpass/candidates.js.map +1 -0
  35. package/dist/firstpass/keys.d.ts +90 -0
  36. package/dist/firstpass/keys.d.ts.map +1 -0
  37. package/dist/firstpass/keys.js +112 -0
  38. package/dist/firstpass/keys.js.map +1 -0
  39. package/dist/firstpass/queue.d.ts +183 -0
  40. package/dist/firstpass/queue.d.ts.map +1 -0
  41. package/dist/firstpass/queue.js +159 -0
  42. package/dist/firstpass/queue.js.map +1 -0
  43. package/dist/firstpass/render.d.ts +100 -0
  44. package/dist/firstpass/render.d.ts.map +1 -0
  45. package/dist/firstpass/render.js +216 -0
  46. package/dist/firstpass/render.js.map +1 -0
  47. package/dist/firstpass/styles.d.ts +36 -0
  48. package/dist/firstpass/styles.d.ts.map +1 -0
  49. package/dist/firstpass/styles.js +148 -0
  50. package/dist/firstpass/styles.js.map +1 -0
  51. package/dist/firstpass/view.d.ts +82 -0
  52. package/dist/firstpass/view.d.ts.map +1 -0
  53. package/dist/firstpass/view.js +60 -0
  54. package/dist/firstpass/view.js.map +1 -0
  55. package/dist/firstpass/words.d.ts +105 -0
  56. package/dist/firstpass/words.d.ts.map +1 -0
  57. package/dist/firstpass/words.js +28 -0
  58. package/dist/firstpass/words.js.map +1 -0
  59. package/dist/index.d.ts +150 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +147 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/overlay/grammar.d.ts +259 -0
  64. package/dist/overlay/grammar.d.ts.map +1 -0
  65. package/dist/overlay/grammar.js +223 -0
  66. package/dist/overlay/grammar.js.map +1 -0
  67. package/dist/overlay/render.d.ts +125 -0
  68. package/dist/overlay/render.d.ts.map +1 -0
  69. package/dist/overlay/render.js +439 -0
  70. package/dist/overlay/render.js.map +1 -0
  71. package/dist/overlay/styles.d.ts +41 -0
  72. package/dist/overlay/styles.d.ts.map +1 -0
  73. package/dist/overlay/styles.js +124 -0
  74. package/dist/overlay/styles.js.map +1 -0
  75. package/dist/picker/render.d.ts +80 -0
  76. package/dist/picker/render.d.ts.map +1 -0
  77. package/dist/picker/render.js +112 -0
  78. package/dist/picker/render.js.map +1 -0
  79. package/dist/picker/styles.d.ts +26 -0
  80. package/dist/picker/styles.d.ts.map +1 -0
  81. package/dist/picker/styles.js +116 -0
  82. package/dist/picker/styles.js.map +1 -0
  83. package/dist/picker/view.d.ts +135 -0
  84. package/dist/picker/view.d.ts.map +1 -0
  85. package/dist/picker/view.js +117 -0
  86. package/dist/picker/view.js.map +1 -0
  87. package/dist/picker/words.d.ts +53 -0
  88. package/dist/picker/words.d.ts.map +1 -0
  89. package/dist/picker/words.js +28 -0
  90. package/dist/picker/words.js.map +1 -0
  91. package/dist/reevaluate/render.d.ts +77 -0
  92. package/dist/reevaluate/render.d.ts.map +1 -0
  93. package/dist/reevaluate/render.js +211 -0
  94. package/dist/reevaluate/render.js.map +1 -0
  95. package/dist/reevaluate/styles.d.ts +24 -0
  96. package/dist/reevaluate/styles.d.ts.map +1 -0
  97. package/dist/reevaluate/styles.js +182 -0
  98. package/dist/reevaluate/styles.js.map +1 -0
  99. package/dist/reevaluate/view.d.ts +102 -0
  100. package/dist/reevaluate/view.d.ts.map +1 -0
  101. package/dist/reevaluate/view.js +111 -0
  102. package/dist/reevaluate/view.js.map +1 -0
  103. package/dist/reevaluate/words.d.ts +54 -0
  104. package/dist/reevaluate/words.d.ts.map +1 -0
  105. package/dist/reevaluate/words.js +29 -0
  106. package/dist/reevaluate/words.js.map +1 -0
  107. package/dist/scale/commands.d.ts +60 -0
  108. package/dist/scale/commands.d.ts.map +1 -0
  109. package/dist/scale/commands.js +49 -0
  110. package/dist/scale/commands.js.map +1 -0
  111. package/dist/scale/ladder.d.ts +141 -0
  112. package/dist/scale/ladder.d.ts.map +1 -0
  113. package/dist/scale/ladder.js +243 -0
  114. package/dist/scale/ladder.js.map +1 -0
  115. package/dist/scale/render.d.ts +85 -0
  116. package/dist/scale/render.d.ts.map +1 -0
  117. package/dist/scale/render.js +194 -0
  118. package/dist/scale/render.js.map +1 -0
  119. package/dist/scale/styles.d.ts +21 -0
  120. package/dist/scale/styles.d.ts.map +1 -0
  121. package/dist/scale/styles.js +105 -0
  122. package/dist/scale/styles.js.map +1 -0
  123. package/dist/workspace/inspector.d.ts +117 -0
  124. package/dist/workspace/inspector.d.ts.map +1 -0
  125. package/dist/workspace/inspector.js +140 -0
  126. package/dist/workspace/inspector.js.map +1 -0
  127. package/dist/workspace/rail.d.ts +122 -0
  128. package/dist/workspace/rail.d.ts.map +1 -0
  129. package/dist/workspace/rail.js +216 -0
  130. package/dist/workspace/rail.js.map +1 -0
  131. package/dist/workspace/render.d.ts +139 -0
  132. package/dist/workspace/render.d.ts.map +1 -0
  133. package/dist/workspace/render.js +366 -0
  134. package/dist/workspace/render.js.map +1 -0
  135. package/dist/workspace/selection.d.ts +92 -0
  136. package/dist/workspace/selection.d.ts.map +1 -0
  137. package/dist/workspace/selection.js +83 -0
  138. package/dist/workspace/selection.js.map +1 -0
  139. package/dist/workspace/styles.d.ts +39 -0
  140. package/dist/workspace/styles.d.ts.map +1 -0
  141. package/dist/workspace/styles.js +313 -0
  142. package/dist/workspace/styles.js.map +1 -0
  143. package/package.json +58 -0
@@ -0,0 +1,243 @@
1
+ /**
2
+ * The scale ladder — which of the three canvas tiers applies, and the route out
3
+ * of the two that refuse.
4
+ *
5
+ * The list scales; the graph does not, and that is fine because they answer
6
+ * different questions. The order rail is complete at any size — "what gets
7
+ * worked next" is answerable for every issue in the document — while the canvas
8
+ * is a LOCAL instrument answering "what surrounds this issue". So past its
9
+ * budget the canvas refuses rather than thinning, and this module is what makes
10
+ * that refusal actionable.
11
+ *
12
+ * ## Why this is layer 2 rather than more of layer 1
13
+ *
14
+ * `@issuegraph/viewer` already decides the same three tiers and already draws a
15
+ * refusal — deliberately an INFORMATIONAL one. Its own source says why: that
16
+ * package does not narrow, it renders exactly what it is given, so a control it
17
+ * published could never complete the action it advertised. Narrowing is the
18
+ * host's, and the editor is the host. What lands here is only the half layer 1
19
+ * refused to own: a component the reader can actually choose, a search that
20
+ * reaches one, and a chip that opens the issues the canvas leaves out.
21
+ *
22
+ * ## What this module deliberately does not compute
23
+ *
24
+ * Components, blocking counts, cycle flags and chain depth all come from
25
+ * `clustersOf` in the viewer. A second pass out here would be a mirror whose
26
+ * input space drifts from the canvas it is describing — the exact failure the
27
+ * package split exists to prevent — and the two would eventually disagree about
28
+ * whether a component contains a cycle while both were rendered on one screen.
29
+ */
30
+ import { CLUSTER_ONLY_BUDGET, GRAPH_NODE_BUDGET, clustersOf, normalizeDocument, } from '@issuegraph/viewer';
31
+ import { INITIAL_SCALE_STATE } from "./commands.js";
32
+ /**
33
+ * The ladder, as the design's table rather than as branches — and pinned to the
34
+ * viewer's exported budgets rather than restating their numbers, so the tier
35
+ * and the canvas cannot disagree about what "past budget" means.
36
+ */
37
+ const CLUSTERS_ONLY = { tier: 'clusters', ceiling: Number.POSITIVE_INFINITY };
38
+ const TIERS = [
39
+ { tier: 'direct', ceiling: GRAPH_NODE_BUDGET },
40
+ { tier: 'capsules', ceiling: CLUSTER_ONLY_BUDGET },
41
+ CLUSTERS_ONLY,
42
+ ];
43
+ /** How many capsules the cluster-only tier lists before it says it stopped. */
44
+ const CAPSULE_LIMIT = 12;
45
+ /** How many search matches are listed before the search says it stopped. */
46
+ const MATCH_LIMIT = 20;
47
+ function tierFor(nodeCount) {
48
+ // The last step's ceiling is infinite, so the fallback is unreachable — it
49
+ // stays because a total function must not depend on a reader noticing that.
50
+ return TIERS.find((step) => nodeCount <= step.ceiling) ?? CLUSTERS_ONLY;
51
+ }
52
+ /** The keys carrying at least one relationship: exactly what the canvas draws. */
53
+ function relatedKeys(document) {
54
+ const keys = new Set();
55
+ for (const issue of document.issues) {
56
+ if ((document.edgesOf.get(issue.key) ?? []).length > 0)
57
+ keys.add(issue.key);
58
+ }
59
+ return keys;
60
+ }
61
+ /**
62
+ * The document restricted to `keep`.
63
+ *
64
+ * IT NARROWS THE NORMALIZED DOCUMENT, NEVER THE RAW INPUT, and that is a
65
+ * correctness rule rather than a convenience. Two things go wrong otherwise.
66
+ *
67
+ * The canvas is handed straight to `renderViewer`, which normalizes whatever it
68
+ * is given — so raw values re-derive every diagnostic this function already
69
+ * collected about them, and a host surfacing diagnostics sees each one twice.
70
+ * Worse, `keep` is built from the NORMALIZED document: normalization drops a
71
+ * duplicate key and strips a url whose scheme the viewer will not link, so
72
+ * filtering the raw input against a normalized key set can hand the canvas an
73
+ * issue the ladder never counted — the ladder and the canvas disagreeing about
74
+ * the node count, which is the one thing this module promises they cannot do.
75
+ *
76
+ * A SLOT SURVIVES ONLY IF EVERY MEMBER DOES. A together unit is one position
77
+ * with several members, and half a unit is not a smaller unit — it is a
78
+ * different claim about what gets worked together. Members of one unit are
79
+ * joined by a `together-with` edge, so they are always in the same component
80
+ * and a focus never splits one; the rule is written for the isolated-exclusion
81
+ * pass, where a unit could otherwise lose a member that happens to be edge-free.
82
+ */
83
+ function narrow(input, keep) {
84
+ return {
85
+ issues: input.issues.filter((issue) => keep.has(issue.key)),
86
+ edges: input.edges.filter((edge) => keep.has(edge.from) && keep.has(edge.to)),
87
+ order: {
88
+ slots: input.order.slots.filter((slot) => slot.members.every((member) => keep.has(member))),
89
+ excluded: input.order.excluded.filter((exclusion) => keep.has(exclusion.key)),
90
+ },
91
+ };
92
+ }
93
+ /**
94
+ * A capsule, or `null` for a component with no members.
95
+ *
96
+ * NULL RATHER THAN AN EMPTY LEAD. `''` would render a control reading "Focus "
97
+ * that focuses nothing — an affordance that cannot complete its own action,
98
+ * which is the exact class the viewer's refusal spent four rounds removing.
99
+ * `clustersOf` never returns one today; this is what keeps that from becoming a
100
+ * silent contract.
101
+ */
102
+ function capsuleOf(cluster) {
103
+ // `members` is already in the viewer's deterministic order, so the first is a
104
+ // stable handle rather than whichever member the walk happened to reach first.
105
+ const lead = cluster.members[0];
106
+ if (lead === undefined)
107
+ return null;
108
+ return {
109
+ lead,
110
+ size: cluster.members.length,
111
+ blockedByEdges: cluster.blockedByEdges,
112
+ chainDepth: cluster.chainDepth,
113
+ hasCycle: cluster.hasCycle,
114
+ members: cluster.members,
115
+ };
116
+ }
117
+ /** Why the canvas declined, in the reader's terms. One sentence, three cases. */
118
+ function reasonFor(tier, nodeCount, focused) {
119
+ if (focused) {
120
+ return `The component you focused is ${String(nodeCount)} issues, itself past this canvas's budget of ${String(GRAPH_NODE_BUDGET)}, so it is not drawing them.`;
121
+ }
122
+ if (tier === 'clusters') {
123
+ return `${String(nodeCount)} related issues is far past this canvas's budget of ${String(GRAPH_NODE_BUDGET)} — past the cluster-only budget of ${String(CLUSTER_ONLY_BUDGET)} as well — so it is listing components and leading with search.`;
124
+ }
125
+ return `${String(nodeCount)} related issues is past this canvas's budget of ${String(GRAPH_NODE_BUDGET)}, so it is not drawing them.`;
126
+ }
127
+ function refusalFor(tier, nodeCount, focused, hasCapsules) {
128
+ if (tier === 'direct')
129
+ return null;
130
+ // ALWAYS AT LEAST TWO. Search reaches a component whatever the tier, and the
131
+ // order rail is complete at any size — so a refusal is never a dead end, and
132
+ // the emptiness of this list is not something a caller has to defend against.
133
+ const routes = [];
134
+ if (hasCapsules) {
135
+ routes.push({ kind: 'focus-cluster', label: 'Focus one component to draw it on its own.' });
136
+ }
137
+ if (focused) {
138
+ routes.push({ kind: 'clear-focus', label: 'Return to every component.' });
139
+ }
140
+ routes.push({
141
+ kind: 'search',
142
+ label: 'Search for an issue to focus the component around it.',
143
+ });
144
+ routes.push({
145
+ kind: 'order-rail',
146
+ label: 'The order list is complete at any size — nothing about the sequence is refused here.',
147
+ });
148
+ return {
149
+ reason: reasonFor(tier, nodeCount, focused),
150
+ nodeCount,
151
+ budget: GRAPH_NODE_BUDGET,
152
+ routes,
153
+ };
154
+ }
155
+ function searchFor(query, document, leadOf) {
156
+ const needle = query.trim().toLowerCase();
157
+ if (needle === '')
158
+ return { query, matches: [], omitted: 0 };
159
+ const found = [];
160
+ for (const issue of document.issues) {
161
+ // ONLY ISSUES THAT SIT IN A COMPONENT. This search exists to focus one, and
162
+ // an issue with no relationship has none to focus — offering it would be a
163
+ // match that cannot be acted on. The issues it leaves out are the ones the
164
+ // isolated chip is for, which is why the chip is not optional chrome.
165
+ const lead = leadOf.get(issue.key);
166
+ if (lead === undefined)
167
+ continue;
168
+ if (!issue.key.toLowerCase().includes(needle) &&
169
+ !issue.title.toLowerCase().includes(needle)) {
170
+ continue;
171
+ }
172
+ found.push({ key: issue.key, title: issue.title, lead });
173
+ }
174
+ return {
175
+ query,
176
+ matches: found.slice(0, MATCH_LIMIT),
177
+ omitted: Math.max(0, found.length - MATCH_LIMIT),
178
+ };
179
+ }
180
+ /**
181
+ * Resolve one document and one reader position into a ladder.
182
+ *
183
+ * Pure and total: no global is read, nothing is fetched, and a `focus` naming a
184
+ * key this document does not place in any component produces a diagnostic and
185
+ * every component, rather than a silently unnarrowed canvas that looks focused.
186
+ */
187
+ export function scaleLadder(input, state = INITIAL_SCALE_STATE) {
188
+ const { document, diagnostics: normalizeDiagnostics } = normalizeDocument(input);
189
+ const diagnostics = [...normalizeDiagnostics];
190
+ const related = relatedKeys(document);
191
+ const clusters = clustersOf(document);
192
+ const leadOf = new Map();
193
+ for (const cluster of clusters) {
194
+ const lead = cluster.members[0];
195
+ if (lead === undefined)
196
+ continue;
197
+ for (const member of cluster.members)
198
+ leadOf.set(member, lead);
199
+ }
200
+ const requested = state.focus;
201
+ const focusedCluster = requested === null
202
+ ? null
203
+ : (clusters.find((cluster) => cluster.members.includes(requested)) ?? null);
204
+ if (requested !== null && focusedCluster === null) {
205
+ diagnostics.push(`focus ${requested} is in no component of this document; showing every component instead`);
206
+ }
207
+ const keep = focusedCluster === null ? related : new Set(focusedCluster.members);
208
+ const canvas = narrow(document, keep);
209
+ const nodeCount = keep.size;
210
+ const { tier } = tierFor(nodeCount);
211
+ // NO CAPSULES WHILE ONE COMPONENT IS FOCUSED. The reader is already inside a
212
+ // component; listing every other one under a refusal about THIS one would
213
+ // read as an offer to focus what is already focused.
214
+ const listable = focusedCluster === null ? clusters : [];
215
+ const shown = tier === 'clusters' ? listable.slice(0, CAPSULE_LIMIT) : listable;
216
+ const capsules = tier === 'direct'
217
+ ? []
218
+ : shown.map(capsuleOf).filter((capsule) => capsule !== null);
219
+ const isolatedIssues = document.issues.filter((issue) => !related.has(issue.key));
220
+ const isolated = {
221
+ count: isolatedIssues.length,
222
+ label: `${String(isolatedIssues.length)} isolated ${isolatedIssues.length === 1 ? 'issue' : 'issues'}, with no relationship to draw`,
223
+ open: state.isolatedOpen,
224
+ issues: state.isolatedOpen ? isolatedIssues : [],
225
+ };
226
+ return {
227
+ tier,
228
+ nodeCount,
229
+ budgets: { node: GRAPH_NODE_BUDGET, clusterOnly: CLUSTER_ONLY_BUDGET },
230
+ focus: focusedCluster === null ? null : requested,
231
+ refusal: refusalFor(tier, nodeCount, focusedCluster !== null, capsules.length > 0),
232
+ capsules,
233
+ // COUNTED AGAINST WHAT WAS LISTED, not against what was sliced. A component
234
+ // dropped for having no members is as absent from the list as one past the
235
+ // limit, and reporting only the slice would under-count it.
236
+ capsulesOmitted: tier === 'direct' ? 0 : listable.length - capsules.length,
237
+ isolated,
238
+ search: tier === 'direct' ? null : searchFor(state.query, document, leadOf),
239
+ canvas,
240
+ diagnostics,
241
+ };
242
+ }
243
+ //# sourceMappingURL=ladder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ladder.js","sourceRoot":"","sources":["../../src/scale/ladder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The ladder, as markup.
3
+ *
4
+ * Pure, like `renderViewer` and for the same reason that package gives: a
5
+ * rendering package whose output can only be inspected by mounting it cannot be
6
+ * tested at the level its correctness actually lives at. Everything below is
7
+ * reachable without a DOM.
8
+ *
9
+ * ## The command contract
10
+ *
11
+ * Every control this renders publishes what it does as data — `data-ig-command`
12
+ * names the {@link ScaleCommand} kind, `data-ig-target` carries the key a
13
+ * `focus` needs, and the search input carries its own query as its value. A
14
+ * host reads them, calls `scaleReducer`, and renders again.
15
+ *
16
+ * THAT INDIRECTION IS THE POINT, not a missing wire. The viewer learned this
17
+ * the expensive way: a control that cannot complete the action it advertises
18
+ * draws a finding every round, and the fix was to stop publishing one from a
19
+ * layer that could not narrow. Layer 2 CAN narrow, so it publishes the controls
20
+ * — but the narrowing still happens by re-rendering with new state, which means
21
+ * the dispatcher is whatever owns that state. Wiring the listeners and
22
+ * restoring focus across the redraw is a mount's job and lands with the
23
+ * workspace that owns one.
24
+ *
25
+ * ## What is drawn, and what is not
26
+ *
27
+ * The canvas is rendered through `@issuegraph/viewer` ONLY on the tier that
28
+ * draws one. Handing an over-budget document to the viewer would make it draw
29
+ * its own refusal beside this one — two refusals about one document, one of
30
+ * which has no routes.
31
+ */
32
+ import { type Theme, type ViewerDocument } from '@issuegraph/viewer';
33
+ import { type ScaleState } from './commands.ts';
34
+ import { type ScaleLadder } from './ladder.ts';
35
+ export interface ScaleLadderOptions {
36
+ readonly state?: ScaleState | undefined;
37
+ readonly theme?: Theme | undefined;
38
+ /** The selector the theme's custom properties are written onto. */
39
+ readonly themeSelector?: string | undefined;
40
+ /**
41
+ * The selected issue key, handed to the viewer as `aria-current`.
42
+ *
43
+ * ADDITIVE AND OPTIONAL, for the surface that assembles this beside a rail.
44
+ * A workspace holds ONE selection and every zone reads it, so a canvas that
45
+ * could not be told what is selected made the shared value disagree with
46
+ * itself between zones on every render — the rail marking a row current while
47
+ * the graph drew the same issue as ordinary.
48
+ *
49
+ * Reaches the viewer only on the tier that draws one; there is nothing to
50
+ * mark on a tier whose canvas is a refusal.
51
+ */
52
+ readonly selected?: string | null | undefined;
53
+ /**
54
+ * The selected EDGE's identity, drawn on the canvas as a selection halo.
55
+ *
56
+ * THE OTHER HALF OF `selected`, AND IT COULD NOT BE FOLDED INTO IT. A
57
+ * workspace holds one selection of one of two kinds, and the viewer's own
58
+ * `selected` renders `aria-current` on a NODE — so an edge identity handed to
59
+ * that option matches nothing, and the canvas drew the selected edge as
60
+ * ordinary while the inspector was filtered to it. One value, two zones, and
61
+ * the canvas was the zone that could not read it.
62
+ *
63
+ * THE LADDER APPLIES THE OVERLAY ITSELF rather than publishing its scene for
64
+ * a caller to decorate. Exposing the scene would have left two ways to obtain
65
+ * this canvas's markup — `result.markup`, and a re-render of the decorated
66
+ * scene — with the first silently wrong for an edge selection. A result with
67
+ * a stale field beside a correct one is worse than a narrower option.
68
+ *
69
+ * Resolved against `ladder.canvas`, which is what this canvas actually draws:
70
+ * a narrowed tier, or a refusal that draws no canvas at all, renders as
71
+ * nothing selected rather than as a halo on a line that is not there.
72
+ */
73
+ readonly selectedEdge?: string | null | undefined;
74
+ }
75
+ export interface ScaleLadderResult {
76
+ readonly ladder: ScaleLadder;
77
+ /** The canvas, when there is one, followed by the ladder's own chrome. */
78
+ readonly markup: string;
79
+ /** The viewer's stylesheet, the theme, and the chrome's own. Install all. */
80
+ readonly styles: string;
81
+ readonly diagnostics: readonly string[];
82
+ }
83
+ /** Render one document at one reader position. */
84
+ export declare function renderScaleLadder(input: ViewerDocument, options?: ScaleLadderOptions): ScaleLadderResult;
85
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/scale/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAEL,KAAK,KAAK,EACV,KAAK,cAAc,EAOpB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EAEL,KAAK,WAAW,EAIjB,MAAM,aAAa,CAAC;AAGrB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IACnC,mEAAmE;IACnE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACnD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAyHD,kDAAkD;AAClD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAsFnB"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * The ladder, as markup.
3
+ *
4
+ * Pure, like `renderViewer` and for the same reason that package gives: a
5
+ * rendering package whose output can only be inspected by mounting it cannot be
6
+ * tested at the level its correctness actually lives at. Everything below is
7
+ * reachable without a DOM.
8
+ *
9
+ * ## The command contract
10
+ *
11
+ * Every control this renders publishes what it does as data — `data-ig-command`
12
+ * names the {@link ScaleCommand} kind, `data-ig-target` carries the key a
13
+ * `focus` needs, and the search input carries its own query as its value. A
14
+ * host reads them, calls `scaleReducer`, and renders again.
15
+ *
16
+ * THAT INDIRECTION IS THE POINT, not a missing wire. The viewer learned this
17
+ * the expensive way: a control that cannot complete the action it advertises
18
+ * draws a finding every round, and the fix was to stop publishing one from a
19
+ * layer that could not narrow. Layer 2 CAN narrow, so it publishes the controls
20
+ * — but the narrowing still happens by re-rendering with new state, which means
21
+ * the dispatcher is whatever owns that state. Wiring the listeners and
22
+ * restoring focus across the redraw is a mount's job and lands with the
23
+ * workspace that owns one.
24
+ *
25
+ * ## What is drawn, and what is not
26
+ *
27
+ * The canvas is rendered through `@issuegraph/viewer` ONLY on the tier that
28
+ * draws one. Handing an over-budget document to the viewer would make it draw
29
+ * its own refusal beside this one — two refusals about one document, one of
30
+ * which has no routes.
31
+ */
32
+ import { element, renderMarkup, renderViewer, resolveTheme, themeCss, viewerStylesheet, } from '@issuegraph/viewer';
33
+ import { edgeIdentity } from '@issuegraph/core';
34
+ import { attachEdgeOverlays } from "../overlay/render.js";
35
+ import { edgeOverlayStylesheet } from "../overlay/styles.js";
36
+ import { INITIAL_SCALE_STATE } from "./commands.js";
37
+ import { scaleLadder, } from "./ladder.js";
38
+ import { scaleLadderStylesheet } from "./styles.js";
39
+ function refusalSpec(refusal, ladder) {
40
+ return element('section', { class: 'ig-refusal', role: 'note' }, [
41
+ element('p', {}, [refusal.reason]),
42
+ ladder.capsules.length === 0
43
+ ? null
44
+ : element('ol', { class: 'ig-list', 'aria-label': 'connected components' }, ladder.capsules.map((capsule) => element('li', { class: 'ig-capsule' }, [
45
+ element('button', {
46
+ type: 'button',
47
+ 'data-ig-command': 'focus',
48
+ 'data-ig-target': capsule.lead,
49
+ }, [`Focus ${capsule.lead}`]),
50
+ element('span', { class: 'ig-count' }, [`${String(capsule.size)} issues`]),
51
+ element('span', { class: 'ig-count' }, [
52
+ `${String(capsule.blockedByEdges)} blocking`,
53
+ ]),
54
+ element('span', { class: 'ig-count' }, [`depth ${String(capsule.chainDepth)}`]),
55
+ capsule.hasCycle
56
+ ? element('span', { class: 'ig-badge', 'data-edge': 'blocked-by' }, ['cycle'])
57
+ : null,
58
+ element('span', { class: 'ig-id' }, [capsule.members.slice(0, 3).join(', ')]),
59
+ ]))),
60
+ ladder.capsulesOmitted > 0
61
+ ? element('p', { class: 'ig-refusal-omitted' }, [
62
+ `${String(ladder.capsulesOmitted)} further ${ladder.capsulesOmitted === 1 ? 'component is' : 'components are'} not listed.`,
63
+ ])
64
+ : null,
65
+ element('ul', { class: 'ig-ladder-routes', 'aria-label': 'what to do next' }, refusal.routes.map((route) => element('li', { class: 'ig-refusal-next', 'data-route': route.kind }, [route.label]))),
66
+ ]);
67
+ }
68
+ function searchSpec(search) {
69
+ return element('div', { class: 'ig-ladder-search' }, [
70
+ // THE INPUT SITS INSIDE ITS LABEL, so the two are associated without an
71
+ // `id`. A fixed `id` is not a detail here: a host rendering two documents
72
+ // side by side would emit it twice, and a duplicated `id` makes `for`
73
+ // resolve to whichever came first — so one of the two search boxes would
74
+ // silently lose its label.
75
+ element('label', {}, [
76
+ 'Search to focus a component',
77
+ element('input', {
78
+ type: 'search',
79
+ 'data-ig-command': 'search',
80
+ value: search.query,
81
+ autocomplete: 'off',
82
+ }),
83
+ ]),
84
+ search.matches.length === 0
85
+ ? null
86
+ : element('ol', { class: 'ig-list', 'aria-label': 'search matches' }, search.matches.map((match) => element('li', { class: 'ig-ladder-match' }, [
87
+ element('button', { type: 'button', 'data-ig-command': 'focus', 'data-ig-target': match.lead }, [`Focus ${match.key}`]),
88
+ element('span', { class: 'ig-title' }, [match.title]),
89
+ ]))),
90
+ search.omitted > 0
91
+ ? element('p', { class: 'ig-refusal-omitted' }, [
92
+ `${String(search.omitted)} further ${search.omitted === 1 ? 'match is' : 'matches are'} not listed.`,
93
+ ])
94
+ : null,
95
+ ]);
96
+ }
97
+ function isolatedSpec(isolated) {
98
+ // NOTHING IS DRAWN FOR AN EMPTY SET. A chip reading "0 isolated issues" is a
99
+ // control that opens nothing, and the count IS the information these issues
100
+ // carry — so with no issues there is nothing to say.
101
+ if (isolated.count === 0)
102
+ return null;
103
+ return element('div', { class: 'ig-ladder-isolated' }, [
104
+ element('button', {
105
+ type: 'button',
106
+ class: 'ig-chip',
107
+ 'aria-expanded': isolated.open ? 'true' : 'false',
108
+ 'data-ig-command': isolated.open ? 'close-isolated' : 'open-isolated',
109
+ }, [isolated.label]),
110
+ // A LIST, NEVER A CANVAS. These issues have no relationship to draw, which
111
+ // is exactly why they were collapsed in the first place.
112
+ isolated.open
113
+ ? element('ol', { class: 'ig-isolated-list', 'aria-label': 'isolated issues' }, isolated.issues.map((issue) => element('li', {}, [
114
+ element('span', { class: 'ig-id' }, [issue.key]),
115
+ element('span', { class: 'ig-title' }, [issue.title]),
116
+ ])))
117
+ : null,
118
+ ]);
119
+ }
120
+ /** Render one document at one reader position. */
121
+ export function renderScaleLadder(input, options = {}) {
122
+ const state = options.state ?? INITIAL_SCALE_STATE;
123
+ const ladder = scaleLadder(input, state);
124
+ const theme = resolveTheme(options.theme);
125
+ const canvas = ladder.tier === 'direct'
126
+ ? renderViewer(ladder.canvas, { projection: 'graph', theme, selected: options.selected ?? null })
127
+ : null;
128
+ // THE SELECTION HALO, ATTACHED TO THE SCENE THE CANVAS JUST DREW.
129
+ //
130
+ // Resolved against `ladder.canvas.edges` — the document this canvas was
131
+ // rendered from — rather than against the caller's input. An identity that
132
+ // names an edge this tier does not draw resolves to nothing here, which is
133
+ // the same promise every other zone makes: a selection is a NAME, and a name
134
+ // that no longer resolves renders as nothing selected.
135
+ const selectedEdge = canvas === null || options.selectedEdge === null || options.selectedEdge === undefined
136
+ ? null
137
+ : (ladder.canvas.edges.find((edge) => edgeIdentity(edge.field, edge.from, edge.to) === options.selectedEdge) ?? null);
138
+ // `states: ['selected']` AND NOTHING ELSE, deliberately. The write states are
139
+ // the store's to report — this synthesises the one state that is not about a
140
+ // write, which is exactly how `EDGE_STATES` describes `selected`. An edge
141
+ // that is ALSO mid-write is overlaid by whoever holds those writes; the two
142
+ // compose, because `overlayFor` reads a list.
143
+ const selectedOverlay = selectedEdge === null
144
+ ? null
145
+ : {
146
+ id: edgeIdentity(selectedEdge.field, selectedEdge.from, selectedEdge.to),
147
+ kind: selectedEdge.field,
148
+ from: selectedEdge.from,
149
+ to: selectedEdge.to,
150
+ states: ['selected'],
151
+ writes: [],
152
+ };
153
+ // `unattached` IS DELIBERATELY NOT SURFACED HERE, and the reason is a fact
154
+ // about this call site rather than about the value.
155
+ //
156
+ // `attachEdgeOverlays` reports an overlay whose edge the scene did not draw
157
+ // because a caller can hand it edges from anywhere. This one hands it exactly
158
+ // one edge, found moments earlier IN `ladder.canvas` — the same document the
159
+ // scene beside it was rendered from — and layer 1 states that geometry cannot
160
+ // fail for a kept edge: `edgeGeometry` returns `null` only when "a caller
161
+ // built a layout from a different document than the edge came from".
162
+ //
163
+ // So the one state this would report is one the inputs cannot reach, and the
164
+ // near miss it looks like — the viewer refusing under a `direct` tier —
165
+ // already reports itself through `canvas.diagnostics`. A diagnostic string no
166
+ // test can make appear is a claim about behaviour nobody can check; the
167
+ // reasoning is worth more here than the branch.
168
+ const overlaid = canvas === null || selectedOverlay === null
169
+ ? null
170
+ : attachEdgeOverlays(canvas.scene, [selectedOverlay], { theme });
171
+ const chrome = element('section', { class: 'ig-ladder', 'data-tier': ladder.tier }, [
172
+ ladder.focus === null
173
+ ? null
174
+ : element('button', { type: 'button', class: 'ig-chip', 'data-ig-command': 'clear-focus' }, ['Return to every component']),
175
+ ladder.refusal === null ? null : refusalSpec(ladder.refusal, ladder),
176
+ ladder.search === null ? null : searchSpec(ladder.search),
177
+ isolatedSpec(ladder.isolated),
178
+ ]);
179
+ return {
180
+ ladder,
181
+ // SIBLINGS RATHER THAN A HAND-BUILT WRAPPER. Every byte here comes from
182
+ // `renderMarkup`, so no attribute value in this package is ever
183
+ // concatenated into markup by hand — which is the escaping surface a
184
+ // second, hand-rolled renderer would have introduced.
185
+ markup: `${overlaid === null ? (canvas?.markup ?? '') : renderMarkup(overlaid.scene.root)}${renderMarkup(chrome)}`,
186
+ // THE OVERLAY'S OWN SHEET TRAVELS WITH THE MARKUP THAT NEEDS IT. The halo
187
+ // is a class this package styles, so a canvas that can draw one and a
188
+ // stylesheet a caller has to remember separately is a mark that renders
189
+ // invisibly whenever the caller forgets.
190
+ styles: `${viewerStylesheet}\n${themeCss(theme, options.themeSelector ?? ':root')}\n${scaleLadderStylesheet}\n${edgeOverlayStylesheet}`,
191
+ diagnostics: [...ladder.diagnostics, ...(canvas?.diagnostics ?? [])],
192
+ };
193
+ }
194
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/scale/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The ladder chrome's structural stylesheet.
3
+ *
4
+ * Same contract as the viewer's, and for the same reason: it carries layout,
5
+ * weight and state, never a value. Every colour, length and font here is a
6
+ * `var(--ig-…)` the host's theme resolves, so a second theme keeps working on
7
+ * the surfaces layer 2 adds rather than only on layer 1's. `styles.test.ts`
8
+ * scans these bytes for a literal colour or a fixed length and for a token the
9
+ * theme does not define, so the rule is enforced rather than remembered.
10
+ *
11
+ * IT ADDS SELECTORS RATHER THAN REDEFINING THEM. The refusal, its capsules and
12
+ * their counts already have a look — this file styles only what layer 2
13
+ * introduces: the ladder container, the routes, the search box, the isolated
14
+ * chip and the list it opens.
15
+ *
16
+ * Shipped as a string for the same reason the viewer's is: an entry that
17
+ * imports CSS cannot be loaded by a bare Node runtime, and a string needs no
18
+ * bundler.
19
+ */
20
+ export declare const scaleLadderStylesheet = "\n.ig-ladder {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n line-height: var(--ig-line-height);\n color: var(--ig-text-body);\n}\n\n.ig-ladder-routes {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n color: var(--ig-text-muted);\n font-size: var(--ig-font-size-small);\n}\n\n.ig-ladder-search {\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-ladder-search input {\n background: var(--ig-surface);\n color: var(--ig-text);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-tight);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size);\n}\n\n.ig-ladder-search input:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-ladder-match {\n display: flex;\n gap: var(--ig-space-tight);\n align-items: baseline;\n}\n\n.ig-chip {\n align-self: flex-start;\n background: var(--ig-surface-2);\n color: var(--ig-text-body);\n border: var(--ig-stroke) solid var(--ig-line);\n border-radius: var(--ig-radius);\n padding: var(--ig-space-tight) var(--ig-space);\n font-family: var(--ig-font-ui);\n font-size: var(--ig-font-size-small);\n cursor: pointer;\n}\n\n.ig-chip:focus-visible {\n outline: var(--ig-focus-ring) solid var(--ig-focus);\n outline-offset: var(--ig-space-tight);\n}\n\n.ig-chip[aria-expanded='true'] {\n border-color: var(--ig-accent);\n color: var(--ig-text);\n}\n\n.ig-isolated-list {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--ig-space-tight);\n}\n\n.ig-isolated-list .ig-id {\n font-family: var(--ig-font-mono);\n color: var(--ig-text-muted);\n}\n";
21
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../src/scale/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,eAAO,MAAM,qBAAqB,23DAoFjC,CAAC"}