@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.
- package/LICENSE +201 -0
- package/README.md +156 -0
- package/dist/clusters.d.ts +34 -0
- package/dist/clusters.d.ts.map +1 -0
- package/dist/clusters.js +195 -0
- package/dist/clusters.js.map +1 -0
- package/dist/document.d.ts +190 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +308 -0
- package/dist/document.js.map +1 -0
- package/dist/element.d.ts +95 -0
- package/dist/element.d.ts.map +1 -0
- package/dist/element.js +174 -0
- package/dist/element.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +122 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +297 -0
- package/dist/layout.js.map +1 -0
- package/dist/mount.d.ts +64 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +402 -0
- package/dist/mount.js.map +1 -0
- package/dist/navigation.d.ts +56 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +121 -0
- package/dist/navigation.js.map +1 -0
- package/dist/parts.d.ts +89 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +214 -0
- package/dist/parts.js.map +1 -0
- package/dist/projections/graph.d.ts +30 -0
- package/dist/projections/graph.d.ts.map +1 -0
- package/dist/projections/graph.js +644 -0
- package/dist/projections/graph.js.map +1 -0
- package/dist/projections/linear.d.ts +35 -0
- package/dist/projections/linear.d.ts.map +1 -0
- package/dist/projections/linear.js +157 -0
- package/dist/projections/linear.js.map +1 -0
- package/dist/projections/tree.d.ts +17 -0
- package/dist/projections/tree.d.ts.map +1 -0
- package/dist/projections/tree.js +209 -0
- package/dist/projections/tree.js.map +1 -0
- package/dist/render.d.ts +35 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +45 -0
- package/dist/render.js.map +1 -0
- package/dist/scene.d.ts +94 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +48 -0
- package/dist/scene.js.map +1 -0
- package/dist/styles.d.ts +17 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +389 -0
- package/dist/styles.js.map +1 -0
- package/dist/theme.d.ts +71 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +169 -0
- package/dist/theme.js.map +1 -0
- package/dist/vocabulary.d.ts +107 -0
- package/dist/vocabulary.d.ts.map +1 -0
- package/dist/vocabulary.js +98 -0
- package/dist/vocabulary.js.map +1 -0
- package/package.json +56 -0
package/dist/parts.d.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pieces every projection draws the same way.
|
|
3
|
+
*
|
|
4
|
+
* Identity, provenance, holds, readiness stations and edge badges are one
|
|
5
|
+
* grammar, not three — the design's extensibility clause turns on that. Putting
|
|
6
|
+
* them here means a projection cannot invent a second spelling of "this issue
|
|
7
|
+
* is held", and a change to the grammar lands in every projection at once.
|
|
8
|
+
*/
|
|
9
|
+
import type { NormalizedDocument, RankProvenance, ViewerHold, ViewerIssue, ViewerSlot } from './document.ts';
|
|
10
|
+
import { type ElementSpec } from './element.ts';
|
|
11
|
+
/** How a readiness station is filled — the parallelism channel. */
|
|
12
|
+
export type StationFill = 'filled' | 'hollow' | 'dashed';
|
|
13
|
+
/**
|
|
14
|
+
* Filled = ready now. Hollow = ready once a named rank lands. Dashed = held.
|
|
15
|
+
*
|
|
16
|
+
* The hollow case needs the host to have told us the rank; without it a ready
|
|
17
|
+
* slot is simply ready, and inventing a pending state would claim a dependency
|
|
18
|
+
* nobody declared.
|
|
19
|
+
*/
|
|
20
|
+
export declare function stationFill(slot: ViewerSlot): StationFill;
|
|
21
|
+
export declare function station(fill: StationFill): ElementSpec;
|
|
22
|
+
/**
|
|
23
|
+
* The identity chip: the qualified reference, linked only when the host gave us
|
|
24
|
+
* a URL. The viewer never constructs one — knowing a tracker's URL shape is the
|
|
25
|
+
* kind of knowledge this layer exists not to have.
|
|
26
|
+
*/
|
|
27
|
+
export declare function identity(issue: ViewerIssue): ElementSpec;
|
|
28
|
+
/**
|
|
29
|
+
* The provenance line, in the three forms the design fixes: a matched ordering
|
|
30
|
+
* query, the declared tier, and an effective-priority promotion that names the
|
|
31
|
+
* dependent the urgency arrived through.
|
|
32
|
+
*/
|
|
33
|
+
export declare function provenanceLine(provenance: RankProvenance | undefined): ElementSpec | null;
|
|
34
|
+
/** One hold, rendered with the family it belongs to visible in the markup. */
|
|
35
|
+
export declare function holdLine(hold: ViewerHold): ElementSpec;
|
|
36
|
+
/**
|
|
37
|
+
* Every relationship touching a ROW, as badges in the format's own field order
|
|
38
|
+
* — so two rows with the same relationships always read identically.
|
|
39
|
+
*
|
|
40
|
+
* TAKES THE ROW'S WHOLE KEY SET, NOT ONE KEY, because a together unit is ONE
|
|
41
|
+
* row and its partners get no row of their own. Reading only the lead dropped
|
|
42
|
+
* every relationship a partner owned: a unit blocked through its partner
|
|
43
|
+
* rendered no blocking badge at all, so the order UI showed a held unit and
|
|
44
|
+
* silently withheld what was holding it. The keys are the row's identity, so
|
|
45
|
+
* `other` is whichever endpoint is OUTSIDE the set, and an edge internal to the
|
|
46
|
+
* unit still reads from its `from` end exactly as it did when the set was one
|
|
47
|
+
* key — a single-key row is unchanged by construction.
|
|
48
|
+
*/
|
|
49
|
+
export declare function edgeBadges(document: NormalizedDocument, keys: readonly string[]): ElementSpec | null;
|
|
50
|
+
/** The legend. Rendered once per scene so the grammar is readable cold. */
|
|
51
|
+
export declare function legend(): ElementSpec;
|
|
52
|
+
/**
|
|
53
|
+
* Every key a projection draws under some OTHER key's station, mapped to it.
|
|
54
|
+
*
|
|
55
|
+
* One rule for the linear and graph projections, which both render a together
|
|
56
|
+
* unit as a single row or node keyed by its lead. Written once because two
|
|
57
|
+
* copies of "which key stands in for which" is exactly how a projection's
|
|
58
|
+
* markup and its published `navigable` came to disagree in the first place.
|
|
59
|
+
*
|
|
60
|
+
* Only non-identity entries, so a lookup that misses means "represents itself"
|
|
61
|
+
* and no projection has to enumerate the keys that are already their own.
|
|
62
|
+
*/
|
|
63
|
+
export declare function stationsOf(document: NormalizedDocument): ReadonlyMap<string, string>;
|
|
64
|
+
/**
|
|
65
|
+
* The caller's options, with `selected` and `focused` named the way THIS
|
|
66
|
+
* projection names them.
|
|
67
|
+
*
|
|
68
|
+
* APPLIED BEFORE THE SCENE IS BUILT, and that is the whole point of it being
|
|
69
|
+
* here rather than only in `reconcile`. Reconciling afterwards fixed the state
|
|
70
|
+
* a handle reports and left the MARKUP built from the un-canonicalized key: the
|
|
71
|
+
* station's row was never marked `aria-current`, the roving tab stop stayed on
|
|
72
|
+
* whatever the fallback resolved to, and `renderViewer` — which never calls
|
|
73
|
+
* `reconcile` at all — was simply wrong. A viewer whose reported state and
|
|
74
|
+
* rendered DOM disagree is the defect, whichever half is right.
|
|
75
|
+
*
|
|
76
|
+
* The projection publishes the SAME map it canonicalized with, so `reconcile`
|
|
77
|
+
* cannot reach a different answer than the markup did.
|
|
78
|
+
*/
|
|
79
|
+
export declare function atStations<T extends {
|
|
80
|
+
selected?: string | null | undefined;
|
|
81
|
+
focused?: string | null | undefined;
|
|
82
|
+
}>(options: T, stations: ReadonlyMap<string, string>): T;
|
|
83
|
+
/** The title of a slot, naming every member — a together unit is one row. */
|
|
84
|
+
export declare function slotTitle(document: NormalizedDocument, slot: ViewerSlot): string;
|
|
85
|
+
/** A slot's accessible name: what it is, where it sits, and whether it is held. */
|
|
86
|
+
export declare function slotLabel(document: NormalizedDocument, slot: ViewerSlot): string;
|
|
87
|
+
/** The empty state. A container with nothing in it reads as a bug. */
|
|
88
|
+
export declare function emptyState(message: string): ElementSpec;
|
|
89
|
+
//# sourceMappingURL=parts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts.d.ts","sourceRoot":"","sources":["../src/parts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACV,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,EACX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,KAAK,WAAW,EAAW,MAAM,cAAc,CAAC;AAGzD,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAIzD;AAQD,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,CAOtD;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAgBxD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,IAAI,CAuBzF;AAED,8EAA8E;AAC9E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAEtD;AAoBD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,GAAG,IAAI,CA0BpG;AAED,2EAA2E;AAC3E,wBAAgB,MAAM,IAAI,WAAW,CAWpC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,kBAAkB,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAQpF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,EAChH,OAAO,EAAE,CAAC,EACV,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,CAAC,CAKH;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAIhF;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAGhF;AAED,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAEvD"}
|
package/dist/parts.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pieces every projection draws the same way.
|
|
3
|
+
*
|
|
4
|
+
* Identity, provenance, holds, readiness stations and edge badges are one
|
|
5
|
+
* grammar, not three — the design's extensibility clause turns on that. Putting
|
|
6
|
+
* them here means a projection cannot invent a second spelling of "this issue
|
|
7
|
+
* is held", and a change to the grammar lands in every projection at once.
|
|
8
|
+
*/
|
|
9
|
+
import { element } from "./element.js";
|
|
10
|
+
import { EDGE_ORDER, treatmentFor } from "./vocabulary.js";
|
|
11
|
+
/**
|
|
12
|
+
* Filled = ready now. Hollow = ready once a named rank lands. Dashed = held.
|
|
13
|
+
*
|
|
14
|
+
* The hollow case needs the host to have told us the rank; without it a ready
|
|
15
|
+
* slot is simply ready, and inventing a pending state would claim a dependency
|
|
16
|
+
* nobody declared.
|
|
17
|
+
*/
|
|
18
|
+
export function stationFill(slot) {
|
|
19
|
+
if (!slot.ready)
|
|
20
|
+
return 'dashed';
|
|
21
|
+
const after = slot.readyAfterRank;
|
|
22
|
+
return after === undefined || after === null ? 'filled' : 'hollow';
|
|
23
|
+
}
|
|
24
|
+
const STATION_LABEL = Object.freeze({
|
|
25
|
+
filled: 'ready now',
|
|
26
|
+
hollow: 'ready after an earlier rank',
|
|
27
|
+
dashed: 'held',
|
|
28
|
+
});
|
|
29
|
+
export function station(fill) {
|
|
30
|
+
return element('span', {
|
|
31
|
+
class: 'ig-station',
|
|
32
|
+
'data-fill': fill,
|
|
33
|
+
role: 'img',
|
|
34
|
+
'aria-label': STATION_LABEL[fill],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The identity chip: the qualified reference, linked only when the host gave us
|
|
39
|
+
* a URL. The viewer never constructs one — knowing a tracker's URL shape is the
|
|
40
|
+
* kind of knowledge this layer exists not to have.
|
|
41
|
+
*/
|
|
42
|
+
export function identity(issue) {
|
|
43
|
+
if (issue.url === undefined || issue.url === '') {
|
|
44
|
+
return element('span', { class: 'ig-id' }, [issue.key]);
|
|
45
|
+
}
|
|
46
|
+
return element('span', { class: 'ig-id' }, [
|
|
47
|
+
element('a', {
|
|
48
|
+
class: 'ig-link',
|
|
49
|
+
href: issue.url,
|
|
50
|
+
rel: 'noreferrer',
|
|
51
|
+
'aria-label': `open ${issue.key}`,
|
|
52
|
+
}, [`${issue.key} ↗`]),
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The provenance line, in the three forms the design fixes: a matched ordering
|
|
57
|
+
* query, the declared tier, and an effective-priority promotion that names the
|
|
58
|
+
* dependent the urgency arrived through.
|
|
59
|
+
*/
|
|
60
|
+
export function provenanceLine(provenance) {
|
|
61
|
+
if (provenance === undefined)
|
|
62
|
+
return null;
|
|
63
|
+
switch (provenance.kind) {
|
|
64
|
+
case 'matched-query':
|
|
65
|
+
return element('p', { class: 'ig-provenance' }, [
|
|
66
|
+
`matched ordered query ${String(provenance.index)} · `,
|
|
67
|
+
element('span', { class: 'ig-id' }, [provenance.label]),
|
|
68
|
+
]);
|
|
69
|
+
case 'declared-tier':
|
|
70
|
+
return element('p', { class: 'ig-provenance' }, [
|
|
71
|
+
`priority tier P${String(provenance.priority)}`,
|
|
72
|
+
]);
|
|
73
|
+
case 'promotion': {
|
|
74
|
+
const via = provenance.promotedBy.length === 0
|
|
75
|
+
? ''
|
|
76
|
+
: ` · inherited from ${provenance.promotedBy.join(', ')}`;
|
|
77
|
+
return element('p', { class: 'ig-provenance' }, [
|
|
78
|
+
element('span', { class: 'ig-id' }, [provenance.notation]),
|
|
79
|
+
`${via}`,
|
|
80
|
+
]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** One hold, rendered with the family it belongs to visible in the markup. */
|
|
85
|
+
export function holdLine(hold) {
|
|
86
|
+
return element('p', { class: 'ig-hold', 'data-family': hold.family }, [hold.reason]);
|
|
87
|
+
}
|
|
88
|
+
/** A badge naming one relationship, on all four channels at once. */
|
|
89
|
+
function edgeBadge(field, detail) {
|
|
90
|
+
const treatment = treatmentFor(field);
|
|
91
|
+
return element('span', {
|
|
92
|
+
class: 'ig-badge',
|
|
93
|
+
'data-edge': field,
|
|
94
|
+
title: `${treatment.label} ${detail}`,
|
|
95
|
+
'aria-label': `${treatment.label} ${detail}`,
|
|
96
|
+
}, [
|
|
97
|
+
element('span', { class: 'ig-glyph', 'aria-hidden': 'true' }, [treatment.glyph]),
|
|
98
|
+
element('span', {}, [detail]),
|
|
99
|
+
]);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Every relationship touching a ROW, as badges in the format's own field order
|
|
103
|
+
* — so two rows with the same relationships always read identically.
|
|
104
|
+
*
|
|
105
|
+
* TAKES THE ROW'S WHOLE KEY SET, NOT ONE KEY, because a together unit is ONE
|
|
106
|
+
* row and its partners get no row of their own. Reading only the lead dropped
|
|
107
|
+
* every relationship a partner owned: a unit blocked through its partner
|
|
108
|
+
* rendered no blocking badge at all, so the order UI showed a held unit and
|
|
109
|
+
* silently withheld what was holding it. The keys are the row's identity, so
|
|
110
|
+
* `other` is whichever endpoint is OUTSIDE the set, and an edge internal to the
|
|
111
|
+
* unit still reads from its `from` end exactly as it did when the set was one
|
|
112
|
+
* key — a single-key row is unchanged by construction.
|
|
113
|
+
*/
|
|
114
|
+
export function edgeBadges(document, keys) {
|
|
115
|
+
const mine = new Set(keys);
|
|
116
|
+
const badges = [];
|
|
117
|
+
// ONE EDGE, ONE BADGE. Both endpoints of an intra-unit edge are members, so
|
|
118
|
+
// it appears in two `edgesOf` entries and would otherwise render twice on the
|
|
119
|
+
// row that owns both ends.
|
|
120
|
+
const seen = new Set();
|
|
121
|
+
for (const field of EDGE_ORDER) {
|
|
122
|
+
for (const key of keys) {
|
|
123
|
+
for (const edge of document.edgesOf.get(key) ?? []) {
|
|
124
|
+
if (edge.field !== field)
|
|
125
|
+
continue;
|
|
126
|
+
const identity = `${edge.field}\u0000${edge.from}\u0000${edge.to}`;
|
|
127
|
+
if (seen.has(identity))
|
|
128
|
+
continue;
|
|
129
|
+
seen.add(identity);
|
|
130
|
+
const treatment = treatmentFor(field);
|
|
131
|
+
// A symmetric edge states one fact whichever end you read it from, so it
|
|
132
|
+
// is announced as one relationship rather than as two directions.
|
|
133
|
+
const outgoing = mine.has(edge.from);
|
|
134
|
+
const other = outgoing ? edge.to : edge.from;
|
|
135
|
+
const detail = treatment.symmetric || outgoing ? other : `${other} (incoming)`;
|
|
136
|
+
badges.push(edgeBadge(field, detail));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (badges.length === 0)
|
|
141
|
+
return null;
|
|
142
|
+
return element('span', { class: 'ig-badges' }, badges);
|
|
143
|
+
}
|
|
144
|
+
/** The legend. Rendered once per scene so the grammar is readable cold. */
|
|
145
|
+
export function legend() {
|
|
146
|
+
return element('fieldset', { class: 'ig-legend' }, [
|
|
147
|
+
element('legend', { class: 'ig-legend-caption' }, ['relationships']),
|
|
148
|
+
...EDGE_ORDER.map((field) => {
|
|
149
|
+
const treatment = treatmentFor(field);
|
|
150
|
+
return element('span', { class: 'ig-badge', 'data-edge': field }, [
|
|
151
|
+
element('span', { class: 'ig-glyph', 'aria-hidden': 'true' }, [treatment.glyph]),
|
|
152
|
+
element('span', {}, [treatment.label]),
|
|
153
|
+
]);
|
|
154
|
+
}),
|
|
155
|
+
]);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Every key a projection draws under some OTHER key's station, mapped to it.
|
|
159
|
+
*
|
|
160
|
+
* One rule for the linear and graph projections, which both render a together
|
|
161
|
+
* unit as a single row or node keyed by its lead. Written once because two
|
|
162
|
+
* copies of "which key stands in for which" is exactly how a projection's
|
|
163
|
+
* markup and its published `navigable` came to disagree in the first place.
|
|
164
|
+
*
|
|
165
|
+
* Only non-identity entries, so a lookup that misses means "represents itself"
|
|
166
|
+
* and no projection has to enumerate the keys that are already their own.
|
|
167
|
+
*/
|
|
168
|
+
export function stationsOf(document) {
|
|
169
|
+
const stations = new Map();
|
|
170
|
+
for (const slot of document.order.slots) {
|
|
171
|
+
for (const member of slot.members) {
|
|
172
|
+
if (member !== slot.lead)
|
|
173
|
+
stations.set(member, slot.lead);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return stations;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The caller's options, with `selected` and `focused` named the way THIS
|
|
180
|
+
* projection names them.
|
|
181
|
+
*
|
|
182
|
+
* APPLIED BEFORE THE SCENE IS BUILT, and that is the whole point of it being
|
|
183
|
+
* here rather than only in `reconcile`. Reconciling afterwards fixed the state
|
|
184
|
+
* a handle reports and left the MARKUP built from the un-canonicalized key: the
|
|
185
|
+
* station's row was never marked `aria-current`, the roving tab stop stayed on
|
|
186
|
+
* whatever the fallback resolved to, and `renderViewer` — which never calls
|
|
187
|
+
* `reconcile` at all — was simply wrong. A viewer whose reported state and
|
|
188
|
+
* rendered DOM disagree is the defect, whichever half is right.
|
|
189
|
+
*
|
|
190
|
+
* The projection publishes the SAME map it canonicalized with, so `reconcile`
|
|
191
|
+
* cannot reach a different answer than the markup did.
|
|
192
|
+
*/
|
|
193
|
+
export function atStations(options, stations) {
|
|
194
|
+
if (stations.size === 0)
|
|
195
|
+
return options;
|
|
196
|
+
const at = (key) => key === null || key === undefined ? key : (stations.get(key) ?? key);
|
|
197
|
+
return { ...options, selected: at(options.selected), focused: at(options.focused) };
|
|
198
|
+
}
|
|
199
|
+
/** The title of a slot, naming every member — a together unit is one row. */
|
|
200
|
+
export function slotTitle(document, slot) {
|
|
201
|
+
return slot.members
|
|
202
|
+
.map((member) => document.byKey.get(member)?.title ?? member)
|
|
203
|
+
.join(' · ');
|
|
204
|
+
}
|
|
205
|
+
/** A slot's accessible name: what it is, where it sits, and whether it is held. */
|
|
206
|
+
export function slotLabel(document, slot) {
|
|
207
|
+
const position = slot.rank === null ? 'held, no rank' : `rank ${String(slot.rank)}`;
|
|
208
|
+
return `${slotTitle(document, slot)} — ${slot.members.join(', ')} — ${position}`;
|
|
209
|
+
}
|
|
210
|
+
/** The empty state. A container with nothing in it reads as a bug. */
|
|
211
|
+
export function emptyState(message) {
|
|
212
|
+
return element('p', { class: 'ig-empty' }, [message]);
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=parts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts.js","sourceRoot":"","sources":["../src/parts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The graph projection: the ordered spine with gutters, and arcs for everything
|
|
3
|
+
* off it.
|
|
4
|
+
*
|
|
5
|
+
* Sequence is vertical position on the spine. Dependency is the arcs. Both
|
|
6
|
+
* readings work at once because they use different visual channels, which is
|
|
7
|
+
* the whole reason this shape was chosen over a force-directed or layered
|
|
8
|
+
* drawing — those make dependency legible and sequence a hunt, and their layout
|
|
9
|
+
* shifts between refreshes, which destroys trust in a panel whose job is to be
|
|
10
|
+
* authoritative.
|
|
11
|
+
*
|
|
12
|
+
* IT REFUSES RATHER THAN DEGRADES. The list scales; the canvas is a local
|
|
13
|
+
* instrument answering "what surrounds this issue", so past its budget it says
|
|
14
|
+
* so and offers the next move instead of drawing a hairball.
|
|
15
|
+
*/
|
|
16
|
+
import type { NormalizedDocument } from '../document.ts';
|
|
17
|
+
import { type Scene } from '../scene.ts';
|
|
18
|
+
import { type Theme } from '../theme.ts';
|
|
19
|
+
import { type SceneOptions } from './linear.ts';
|
|
20
|
+
/**
|
|
21
|
+
* The node budget, from the design's scale table. Above the first threshold the
|
|
22
|
+
* canvas shows component capsules; above the second, clusters only.
|
|
23
|
+
*/
|
|
24
|
+
export declare const GRAPH_NODE_BUDGET = 60;
|
|
25
|
+
export declare const CLUSTER_ONLY_BUDGET = 300;
|
|
26
|
+
export interface GraphOptions extends SceneOptions {
|
|
27
|
+
readonly theme?: Theme | undefined;
|
|
28
|
+
}
|
|
29
|
+
export declare function graphScene(document: NormalizedDocument, rawOptions?: GraphOptions): Scene;
|
|
30
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/projections/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,KAAK,EACV,kBAAkB,EAInB,MAAM,gBAAgB,CAAC;AAoBxB,OAAO,EAA0B,KAAK,KAAK,EAAmB,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,KAAK,KAAK,EAAgB,MAAM,aAAa,CAAC;AAEvD,OAAO,EAAE,KAAK,YAAY,EAA6B,MAAM,aAAa,CAAC;AAE3E;;;GAGG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;CACpC;AA4bD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,kBAAkB,EAAE,UAAU,GAAE,YAAiB,GAAG,KAAK,CA4Q7F"}
|