@issuegraph/viewer 0.9.1 → 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.
- package/dist/clusters.d.ts +1 -1
- package/dist/clusters.d.ts.map +1 -1
- package/dist/clusters.js +13 -12
- package/dist/clusters.js.map +1 -1
- package/dist/document.d.ts +27 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +10 -2
- package/dist/document.js.map +1 -1
- package/dist/element.d.ts +10 -2
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +7 -2
- package/dist/layout.js.map +1 -1
- package/dist/mount.d.ts +2 -2
- package/dist/mount.d.ts.map +1 -1
- package/dist/mount.js +6 -0
- package/dist/mount.js.map +1 -1
- package/dist/parts.d.ts +0 -7
- package/dist/parts.d.ts.map +1 -1
- package/dist/parts.js +24 -42
- package/dist/parts.js.map +1 -1
- package/dist/projections/graph.d.ts +50 -2
- package/dist/projections/graph.d.ts.map +1 -1
- package/dist/projections/graph.js +140 -49
- package/dist/projections/graph.js.map +1 -1
- package/dist/projections/linear.d.ts +105 -15
- package/dist/projections/linear.d.ts.map +1 -1
- package/dist/projections/linear.js +132 -58
- package/dist/projections/linear.js.map +1 -1
- package/dist/projections/tree.d.ts.map +1 -1
- package/dist/projections/tree.js +17 -4
- package/dist/projections/tree.js.map +1 -1
- package/dist/render.d.ts +5 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js.map +1 -1
- package/dist/scene.d.ts +22 -0
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js.map +1 -1
- package/dist/skeleton.d.ts +63 -0
- package/dist/skeleton.d.ts.map +1 -0
- package/dist/skeleton.js +108 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +236 -69
- package/dist/styles.js.map +1 -1
- package/package.json +1 -1
package/dist/skeleton.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `renderViewerSkeleton` — what the viewer draws before there is a document.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the package draws it, and the host only styles it
|
|
5
|
+
*
|
|
6
|
+
* A viewer mounted before its data arrives had two choices and both were wrong.
|
|
7
|
+
* Rendered over an empty document it said "nothing is in the order", which is
|
|
8
|
+
* a claim about a backlog nobody has read yet. Held back by the host instead,
|
|
9
|
+
* the host drew its own placeholder — a guess at this package's layout that
|
|
10
|
+
* jumped when the real rows landed and that every host had to rewrite.
|
|
11
|
+
*
|
|
12
|
+
* So the SHAPE is this package's: the skeleton rows use the same `.ig-slot`
|
|
13
|
+
* geometry the order uses, so a placeholder row is exactly as tall as a real
|
|
14
|
+
* one at every density the container picks, and nothing moves on arrival. It
|
|
15
|
+
* is a pure function over no document, so a host can render it on the server
|
|
16
|
+
* — in a route's loading state — and the page-load placeholder, the
|
|
17
|
+
* waiting-for-data placeholder and the data all line up.
|
|
18
|
+
*
|
|
19
|
+
* The LOOK is the host's. Every placeholder is an `.ig-skeleton-block`,
|
|
20
|
+
* filled with `--ig-surface-2` and carrying no animation. This package ships
|
|
21
|
+
* no motion anywhere — the editor's sheet says why — so a host that wants its
|
|
22
|
+
* own pulse adds it to that one class, gated on its own reduced-motion rule,
|
|
23
|
+
* and the fill follows the host's theme like every other surface here.
|
|
24
|
+
*
|
|
25
|
+
* ## No word of its own
|
|
26
|
+
*
|
|
27
|
+
* The root is `aria-busy` always. It is a labelled `status` region only when
|
|
28
|
+
* the host supplies `label` — "Loading your issues" is a sentence in the
|
|
29
|
+
* host's language, and this package does not write one.
|
|
30
|
+
*/
|
|
31
|
+
import { element, renderMarkup } from "./element.js";
|
|
32
|
+
import { resolveTheme, themeCss } from "./theme.js";
|
|
33
|
+
import { viewerStylesheet } from "./styles.js";
|
|
34
|
+
const DEFAULT_ROWS = 8;
|
|
35
|
+
const DEFAULT_CARDS = 3;
|
|
36
|
+
/** Title widths cycle through a few lengths so the column reads as text, not as a bar chart. */
|
|
37
|
+
const TITLE_WIDTHS = ['0', '1', '2', '1'];
|
|
38
|
+
function block(shape, extra = {}) {
|
|
39
|
+
return element('span', { class: 'ig-skeleton-block', 'data-shape': shape, ...extra });
|
|
40
|
+
}
|
|
41
|
+
function headerSkeleton() {
|
|
42
|
+
return element('header', { class: 'ig-header' }, [
|
|
43
|
+
element('div', { class: 'ig-header-top' }, [block('label')]),
|
|
44
|
+
element('div', { class: 'ig-skeleton-chips' }, [block('chip'), block('chip'), block('chip')]),
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
function rowSkeleton(index) {
|
|
48
|
+
return element('li', { class: 'ig-slot ig-skeleton-row' }, [
|
|
49
|
+
// THE STATION ALONE IN THE RANK TRACK. A rank figure over it made the cell
|
|
50
|
+
// taller than a real row's, and the whole placeholder a few pixels a row
|
|
51
|
+
// too tall — the jump this file exists to prevent. Measured against the
|
|
52
|
+
// real rail at its dense density: 53 and 53.
|
|
53
|
+
element('div', { class: 'ig-rank-cell' }, [block('station')]),
|
|
54
|
+
element('div', { class: 'ig-row-body' }, [
|
|
55
|
+
// ONE WRAPPER FOR BOTH LINES, as the real row has, so the body's own gap
|
|
56
|
+
// is not spent between the title and the meta line a second time.
|
|
57
|
+
element('div', { class: 'ig-skeleton-lines' }, [
|
|
58
|
+
block('title', { 'data-width': TITLE_WIDTHS[index % TITLE_WIDTHS.length] ?? '0' }),
|
|
59
|
+
block('meta'),
|
|
60
|
+
]),
|
|
61
|
+
]),
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A spine card's placeholder: ONE filled block at the card's width and height,
|
|
66
|
+
* not an outlined card with bars inside. Solid rounded blocks are how a
|
|
67
|
+
* skeleton reads at a glance — the same shape host dashboards draw for their
|
|
68
|
+
* own cards — and it keeps every placeholder on the one hook a host styles.
|
|
69
|
+
*/
|
|
70
|
+
function cardSkeleton() {
|
|
71
|
+
return block('card');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The placeholder's root, as a spec — exported so a composing surface (the
|
|
75
|
+
* editor's workspace skeleton) can place it inside its own zones.
|
|
76
|
+
*/
|
|
77
|
+
export function skeletonSpec(options = {}) {
|
|
78
|
+
const projection = options.projection ?? 'linear';
|
|
79
|
+
const graph = projection === 'graph';
|
|
80
|
+
const count = Math.max(1, Math.floor(options.rows ?? (graph ? DEFAULT_CARDS : DEFAULT_ROWS)));
|
|
81
|
+
const body = graph
|
|
82
|
+
? element('div', { class: 'ig-skeleton-stage' }, Array.from({ length: count }, () => cardSkeleton()))
|
|
83
|
+
: element('ol', { class: 'ig-list' }, Array.from({ length: count }, (_, index) => rowSkeleton(index)));
|
|
84
|
+
return element('section', {
|
|
85
|
+
class: `ig-viewer ${graph ? 'ig-graph' : projection === 'tree' ? 'ig-tree-view' : 'ig-linear'}`,
|
|
86
|
+
'data-projection': projection,
|
|
87
|
+
'data-frame': options.frame === false ? 'none' : undefined,
|
|
88
|
+
'data-ig-loading': 'true',
|
|
89
|
+
'aria-busy': 'true',
|
|
90
|
+
role: options.label === undefined ? undefined : 'status',
|
|
91
|
+
'aria-label': options.label,
|
|
92
|
+
}, [
|
|
93
|
+
options.chrome === false || graph ? null : headerSkeleton(),
|
|
94
|
+
// THE PLACEHOLDERS SAY NOTHING. They are shapes, not content, and a
|
|
95
|
+
// screen reader walking eight empty list items learns only that there
|
|
96
|
+
// are eight of them — the region's busy state and label already say it.
|
|
97
|
+
element('div', { 'aria-hidden': 'true' }, [body]),
|
|
98
|
+
]);
|
|
99
|
+
}
|
|
100
|
+
/** Render the placeholder a host shows before the viewer has a document. Pure and total. */
|
|
101
|
+
export function renderViewerSkeleton(options = {}) {
|
|
102
|
+
const theme = resolveTheme(options.theme);
|
|
103
|
+
return {
|
|
104
|
+
markup: renderMarkup(skeletonSpec(options)),
|
|
105
|
+
styles: `${viewerStylesheet}\n${themeCss(theme, options.themeSelector ?? ':root')}`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=skeleton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skeleton.js","sourceRoot":"","sources":["../src/skeleton.ts"],"names":[],"mappings":"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"}
|
package/dist/styles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA+PH,eAAO,MAAM,gBAAgB,QAm+C5B,CAAC"}
|
package/dist/styles.js
CHANGED
|
@@ -169,18 +169,10 @@ ${scope} .ig-unit-count {
|
|
|
169
169
|
margin-right: var(--ig-space-tight);
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
/* THE FOOTER
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
its TITLE: it wrapped, and the excluded row carrying a canonical reference
|
|
177
|
-
ran to 73px while its siblings sat at 36. A footer row taller than a
|
|
178
|
-
ranked row inverts the whole point of the group.
|
|
179
|
-
|
|
180
|
-
THE DEFECT IS THE ONE ALREADY FIXED ON .ig-slot, ONE ROW KIND OVER: a
|
|
181
|
-
title with nothing stopping it wrapping takes the row with it. Fixed at
|
|
182
|
-
the class this time rather than at the site - the rail renders three row
|
|
183
|
-
kinds and the first pass governed two. */
|
|
172
|
+
/* THE FOOTER ROW'S TITLE STAYS ON ONE LINE, as a ranked row's does. The row
|
|
173
|
+
is taller than a ranked row now by design — its status and its reason are
|
|
174
|
+
what it exists to show — but a title that wraps still takes the row with it,
|
|
175
|
+
so the name ellipsizes and the reason below it carries the length. */
|
|
184
176
|
${scope} .ig-footer-row .ig-title {
|
|
185
177
|
line-height: var(--ig-row-title-line);
|
|
186
178
|
min-width: 0;
|
|
@@ -189,39 +181,7 @@ ${scope} .ig-footer-row .ig-title {
|
|
|
189
181
|
white-space: nowrap;
|
|
190
182
|
}
|
|
191
183
|
|
|
192
|
-
|
|
193
|
-
flex-wrap: nowrap;
|
|
194
|
-
min-width: 0;
|
|
195
|
-
overflow: hidden;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/* AND THE CHIPS LOSE THEIR CHROME HERE TOO, which is what actually makes a
|
|
199
|
-
footer entry ONE LINE. 16a draws it as "a label chip, a title and an
|
|
200
|
-
identity, on one line"; a bordered chip is padding plus stroke plus line
|
|
201
|
-
box, so a row carrying any relationship badge stood at 36px against 22px
|
|
202
|
-
for one carrying none - and the badge block, not the title, was the last
|
|
203
|
-
thing driving it.
|
|
204
|
-
|
|
205
|
-
MEASURED IN TWO PASSES, WHICH IS THE POINT. Stopping after the title fix
|
|
206
|
-
left the footer group at two heights and looked finished: the row that had
|
|
207
|
-
been 73px was down to 36 and matched its siblings, so the obvious check
|
|
208
|
-
passed. It was the SECOND measurement - why 22 and why 36 - that found the
|
|
209
|
-
badges. A class is not fixed until nothing in it varies for a reason you
|
|
210
|
-
have not named. */
|
|
211
|
-
${scope} .ig-footer-row .ig-badge {
|
|
212
|
-
background: none;
|
|
213
|
-
border: 0;
|
|
214
|
-
border-radius: 0;
|
|
215
|
-
padding: 0;
|
|
216
|
-
white-space: nowrap;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/* THE THIRD AND LAST MEMBER OF THE CLASS: the identity. An excluded row
|
|
220
|
-
carries TWO - its own, and the canonical it defers to ('455 -> 512') - and
|
|
221
|
-
the second wrapped, which is why that row alone stood at 30px when the
|
|
222
|
-
others reached 17. Same defect as the title and the chips, third element,
|
|
223
|
-
found by asking the same question a third time rather than by stopping at
|
|
224
|
-
the first uniform-looking answer. */
|
|
184
|
+
/* The identity never wraps mid-reference. */
|
|
225
185
|
${scope} .ig-footer-row .ig-id {
|
|
226
186
|
white-space: nowrap;
|
|
227
187
|
}
|
|
@@ -299,6 +259,19 @@ ${scope} .ig-slot[aria-expanded='true'] {
|
|
|
299
259
|
${scope} .ig-slot[aria-expanded='true'] .ig-provenance {
|
|
300
260
|
display: block;
|
|
301
261
|
}
|
|
262
|
+
|
|
263
|
+
/* THE QUERY CHIP COMES BACK WHERE ITS LINE GOES (#131). At this density the
|
|
264
|
+
provenance line is hidden, so the chip is the only mark on the row naming
|
|
265
|
+
WHICH ordered query placed it — and step 3 below keeps it for exactly that
|
|
266
|
+
reason. A row the reader opened draws the line again, and the chip leaves
|
|
267
|
+
with it: one fact, said once, at every density. */
|
|
268
|
+
${scope} .ig-slot .ig-badge[data-priority='query'] {
|
|
269
|
+
display: inline-flex;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
${scope} .ig-slot[aria-expanded='true'] .ig-badge[data-priority='query'] {
|
|
273
|
+
display: none;
|
|
274
|
+
}
|
|
302
275
|
`;
|
|
303
276
|
}
|
|
304
277
|
export const viewerStylesheet = `
|
|
@@ -314,6 +287,51 @@ export const viewerStylesheet = `
|
|
|
314
287
|
position: relative;
|
|
315
288
|
}
|
|
316
289
|
|
|
290
|
+
/* THE FRAME IS THE STANDALONE CASE'S, AND A CONTAINER CAN DECLINE IT.
|
|
291
|
+
Alone in a host's page the viewer is a card and draws its own edge. Composed
|
|
292
|
+
into a surface that already rules its own zones off, that edge lands beside
|
|
293
|
+
the container's and the seam reads as a doubled hairline — so the container
|
|
294
|
+
passes frame: false and takes responsibility for every line on the
|
|
295
|
+
surface. See SceneOptions.frame for why this is an option rather than a
|
|
296
|
+
host stylesheet unsetting the properties above. */
|
|
297
|
+
.ig-viewer[data-frame='none'] {
|
|
298
|
+
border: 0;
|
|
299
|
+
border-radius: 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* THE LEGEND DOCKS AGAINST THE CONTAINER'S SCROLLPORT, NOT THIS ROOT'S.
|
|
303
|
+
See SceneOptions.dockLegend for why only a container can ask for this.
|
|
304
|
+
|
|
305
|
+
THE overflow LINE IS THE WHOLE MECHANISM AND LOOKS LIKE A TIDY-UP. A sticky
|
|
306
|
+
element positions against its nearest SCROLLPORT, and an ancestor with
|
|
307
|
+
overflow: hidden is one — so with the root left as it is above, the legend
|
|
308
|
+
sticks to a box that never scrolls, which is the box it already sat at the
|
|
309
|
+
bottom of. Nothing moves, nothing errors, and the declaration below reads as
|
|
310
|
+
though it works. Lifting the clip hands the legend the container's scroller
|
|
311
|
+
instead, which is the only one that scrolls.
|
|
312
|
+
|
|
313
|
+
WHICH IS ALSO WHY THIS IS SAFE ONLY WITH THE FRAME DECLINED. The clip exists
|
|
314
|
+
so a drawn radius cuts its own corners; a root that has stopped clipping must
|
|
315
|
+
not be drawing one. The rule above and this one are written to be passed
|
|
316
|
+
together, and the workspace passes both.
|
|
317
|
+
|
|
318
|
+
NO z-index, DELIBERATELY. The legend is the root's last child, so it already
|
|
319
|
+
paints over the order it overlaps; a layer number here would be a claim about
|
|
320
|
+
a stacking order this package does not own. */
|
|
321
|
+
.ig-viewer[data-legend='docked'] {
|
|
322
|
+
overflow: visible;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* bottom: 0 IS A DEFAULT THE CONTAINER OVERRIDES, not a fixed position. A
|
|
326
|
+
container with something of its own already pinned to that edge — the
|
|
327
|
+
grooming workspace's rail footer — sets this element's bottom to clear it,
|
|
328
|
+
from a height it measures rather than from a number either package wrote
|
|
329
|
+
down and both would have to keep true. */
|
|
330
|
+
.ig-viewer[data-legend='docked'] > .ig-legend {
|
|
331
|
+
position: sticky;
|
|
332
|
+
bottom: 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
317
335
|
.ig-viewer *,
|
|
318
336
|
.ig-viewer *::before,
|
|
319
337
|
.ig-viewer *::after {
|
|
@@ -1045,6 +1063,20 @@ ${railDensity(".ig-viewer[data-density='dense']")}
|
|
|
1045
1063
|
padding: var(--ig-space-micro) var(--ig-space-tight);
|
|
1046
1064
|
}
|
|
1047
1065
|
|
|
1066
|
+
/* A MATCHED QUERY IS SAID ONCE ON A LIST ROW, BY ITS LINE (#131). The row's
|
|
1067
|
+
provenance line already reads "Picked by query 1 · label:P0", so a chip
|
|
1068
|
+
carrying "label:P0" above it printed the same label twice on every row a
|
|
1069
|
+
query placed — and no §16 frame draws that chip; §16h gives a row "a single
|
|
1070
|
+
provenance line". Hidden by CSS rather than dropped from the markup, for the
|
|
1071
|
+
reason the dense rail hides the line instead: the markup stays whole, and
|
|
1072
|
+
at the dense density, where the LINE is the one hidden, the rail block
|
|
1073
|
+
brings the chip back. A graph card is not an .ig-slot and draws no line, so
|
|
1074
|
+
its chip is untouched. A declared tier and a promotion keep their chips:
|
|
1075
|
+
those are the scanning read §16a draws beside the sentence. */
|
|
1076
|
+
.ig-slot .ig-badge[data-priority='query'] {
|
|
1077
|
+
display: none;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1048
1080
|
/* THE HUE IS A BORDER AND A FILL HERE, NOT A TEXT COLOUR — the theme holds the
|
|
1049
1081
|
edge hues to the 3:1 NON-TEXT bar, and says so where it defines them, so
|
|
1050
1082
|
painting badge LABELS with them contradicts the palette's own claim. It was
|
|
@@ -1188,57 +1220,83 @@ ${railDensity(".ig-viewer[data-density='dense']")}
|
|
|
1188
1220
|
|
|
1189
1221
|
/* ── the footer group: holds that earn no rank slot ────────────────────── */
|
|
1190
1222
|
|
|
1191
|
-
.
|
|
1192
|
-
|
|
1193
|
-
|
|
1223
|
+
/* NO RULE OF ITS OWN ON TOP. The last ranked row above already draws its
|
|
1224
|
+
bottom rule, and a second one here stacked on it as a doubled line. */
|
|
1225
|
+
/* THE PANEL HEADER'S LAYOUT, ONE LEVEL DOWN: a kicker and a count chip on one
|
|
1226
|
+
line, a sentence under them. The kicker and the chip are the header's own
|
|
1227
|
+
classes (see footerHead), so this rule only places them. */
|
|
1228
|
+
.ig-footer-head {
|
|
1229
|
+
display: flex;
|
|
1230
|
+
flex-direction: column;
|
|
1231
|
+
gap: var(--ig-space-tight);
|
|
1232
|
+
padding: var(--ig-row-padding-block-dense) var(--ig-space-wide);
|
|
1194
1233
|
}
|
|
1195
1234
|
|
|
1196
|
-
.ig-footer-
|
|
1235
|
+
.ig-footer-title-row {
|
|
1197
1236
|
align-items: center;
|
|
1198
1237
|
display: flex;
|
|
1199
1238
|
gap: var(--ig-space);
|
|
1200
|
-
justify-content: space-between;
|
|
1201
1239
|
}
|
|
1202
1240
|
|
|
1203
1241
|
.ig-footer-title {
|
|
1204
|
-
color: var(--ig-text-body);
|
|
1205
|
-
font-size: var(--ig-font-size-compact);
|
|
1206
1242
|
margin: 0;
|
|
1207
1243
|
}
|
|
1208
1244
|
|
|
1209
|
-
.ig-footer-
|
|
1245
|
+
.ig-footer-note {
|
|
1210
1246
|
color: var(--ig-text-muted);
|
|
1211
|
-
font-
|
|
1212
|
-
|
|
1247
|
+
font-size: var(--ig-font-size-compact);
|
|
1248
|
+
line-height: var(--ig-row-meta-line);
|
|
1249
|
+
margin: 0;
|
|
1213
1250
|
}
|
|
1214
1251
|
|
|
1215
|
-
/* ONE LINE EACH, and the frame is explicit about why: these are not facts
|
|
1216
|
-
about the work, so they earn no rank slot and no explanation block. A full
|
|
1217
|
-
row here — station, badges, provenance — was claiming the opposite. */
|
|
1218
1252
|
.ig-footer .ig-list {
|
|
1219
1253
|
display: flex;
|
|
1220
1254
|
flex-direction: column;
|
|
1221
|
-
gap: var(--ig-space-snug);
|
|
1222
|
-
margin-top: var(--ig-space);
|
|
1223
1255
|
}
|
|
1224
1256
|
|
|
1257
|
+
/* A RANKED ROW'S GRID, PADDING AND RULE, so the group is the rest of the same
|
|
1258
|
+
list rather than a panel of its own: the rank track holds the held station,
|
|
1259
|
+
and it lines up under the stations above because it is the same track.
|
|
1260
|
+
|
|
1261
|
+
ON THE PANEL'S OWN GROUND, NOT A SECOND SURFACE, and at full strength. The
|
|
1262
|
+
group used to sit on --ig-surface-2 with every row at 0.72 opacity, which
|
|
1263
|
+
read as disabled — on the rows whose whole purpose is "open me to see why". */
|
|
1225
1264
|
.ig-footer-row {
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1265
|
+
border-top: var(--ig-stroke) solid var(--ig-line);
|
|
1266
|
+
column-gap: var(--ig-space);
|
|
1267
|
+
cursor: pointer;
|
|
1268
|
+
display: grid;
|
|
1269
|
+
grid-template-columns: var(--ig-rank-column) 1fr;
|
|
1270
|
+
/* THE DENSE RANKED ROW'S PADDING, at every width: these rows carry three
|
|
1271
|
+
lines where a ranked row carries two, and the wider padding on top of that
|
|
1272
|
+
made each one twice the height of its neighbours above. */
|
|
1273
|
+
padding: var(--ig-row-padding-block-dense) var(--ig-space-wide);
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
.ig-footer-row:hover {
|
|
1277
|
+
background: color-mix(in srgb, var(--ig-text) var(--ig-tint-unit), transparent);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
/* THE RANKED ROW'S SELECTED BAND, and its fill: one selection, one look,
|
|
1281
|
+
whichever part of the list it was made in. */
|
|
1282
|
+
.ig-footer-row[aria-current='true'] {
|
|
1283
|
+
background: color-mix(in srgb, var(--ig-accent) var(--ig-tint-fill), transparent);
|
|
1284
|
+
box-shadow: inset var(--ig-band-rail) 0 0 var(--ig-accent);
|
|
1230
1285
|
}
|
|
1231
1286
|
|
|
1232
1287
|
.ig-footer-row .ig-title {
|
|
1233
|
-
|
|
1288
|
+
color: var(--ig-text-body);
|
|
1234
1289
|
}
|
|
1235
1290
|
|
|
1236
|
-
.ig-footer-row .ig-
|
|
1237
|
-
|
|
1291
|
+
.ig-footer-row[aria-current='true'] .ig-title {
|
|
1292
|
+
color: var(--ig-text);
|
|
1238
1293
|
}
|
|
1239
1294
|
|
|
1240
|
-
.ig-footer-
|
|
1241
|
-
|
|
1295
|
+
.ig-footer-why {
|
|
1296
|
+
color: var(--ig-text-muted);
|
|
1297
|
+
font-size: var(--ig-font-size-compact);
|
|
1298
|
+
line-height: var(--ig-row-meta-line);
|
|
1299
|
+
margin: 0;
|
|
1242
1300
|
}
|
|
1243
1301
|
|
|
1244
1302
|
/* ── the graph canvas ──────────────────────────────────────────────────── */
|
|
@@ -1573,6 +1631,94 @@ ${railDensity(".ig-viewer[data-density='dense']")}
|
|
|
1573
1631
|
padding: var(--ig-space-tight) 0;
|
|
1574
1632
|
}
|
|
1575
1633
|
|
|
1634
|
+
/* ── loading placeholder ───────────────────────────────────────────────── */
|
|
1635
|
+
|
|
1636
|
+
/* THE HOST'S HOOK, AND THE ONLY ONE. Every placeholder shape is one of these,
|
|
1637
|
+
filled with the second surface and holding still: this package ships no
|
|
1638
|
+
motion, and the fill already follows the host's theme. A host that wants a
|
|
1639
|
+
pulse animates this class under its own reduced-motion rule. */
|
|
1640
|
+
.ig-skeleton-block {
|
|
1641
|
+
background: var(--ig-surface-2);
|
|
1642
|
+
border-radius: var(--ig-radius);
|
|
1643
|
+
display: block;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
/* ON THE HEADER'S OWN GROUND the second surface is the ground, so the shapes
|
|
1647
|
+
there take the hairline colour instead, or they vanish into it. */
|
|
1648
|
+
.ig-header .ig-skeleton-block {
|
|
1649
|
+
background: var(--ig-line);
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
.ig-skeleton-block[data-shape='label'] {
|
|
1653
|
+
block-size: var(--ig-space);
|
|
1654
|
+
inline-size: calc(var(--ig-char-width) * 14);
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
.ig-skeleton-chips {
|
|
1658
|
+
display: flex;
|
|
1659
|
+
gap: var(--ig-space-snug);
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
.ig-skeleton-block[data-shape='chip'] {
|
|
1663
|
+
block-size: calc(var(--ig-space) * 2);
|
|
1664
|
+
border-radius: var(--ig-radius);
|
|
1665
|
+
inline-size: calc(var(--ig-char-width) * 9);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
.ig-skeleton-block[data-shape='station'] {
|
|
1669
|
+
block-size: var(--ig-space);
|
|
1670
|
+
border-radius: 50%;
|
|
1671
|
+
inline-size: var(--ig-space);
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
/* THE ROW'S OWN LINE HEIGHTS, so a placeholder row and a real row are the same
|
|
1675
|
+
height at every density the container picks. */
|
|
1676
|
+
.ig-skeleton-block[data-shape='title'] {
|
|
1677
|
+
block-size: var(--ig-row-title-line);
|
|
1678
|
+
inline-size: 68%;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1681
|
+
.ig-skeleton-block[data-shape='title'][data-width='1'] {
|
|
1682
|
+
inline-size: 54%;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
.ig-skeleton-block[data-shape='title'][data-width='2'] {
|
|
1686
|
+
inline-size: 82%;
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
.ig-skeleton-block[data-shape='meta'] {
|
|
1690
|
+
block-size: var(--ig-row-meta-line);
|
|
1691
|
+
inline-size: 36%;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
/* THE TWO LINES OF A ROW, stacked with no gap of their own: each block is its
|
|
1695
|
+
line's full height, which already carries the leading a real line has. */
|
|
1696
|
+
.ig-skeleton-lines {
|
|
1697
|
+
display: flex;
|
|
1698
|
+
flex-direction: column;
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
/* A placeholder row points at nothing, so it takes no pointer and no hover. */
|
|
1702
|
+
.ig-skeleton-row {
|
|
1703
|
+
pointer-events: none;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
.ig-skeleton-stage {
|
|
1707
|
+
align-items: center;
|
|
1708
|
+
display: flex;
|
|
1709
|
+
flex-direction: column;
|
|
1710
|
+
gap: var(--ig-space-wide);
|
|
1711
|
+
padding: var(--ig-space-wide);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
/* THE SPINE CARD'S OWN WIDTH, so the graph's placeholder sits where its cards
|
|
1715
|
+
will, as one solid block with the large radius the panel's cards use. */
|
|
1716
|
+
.ig-skeleton-block[data-shape='card'] {
|
|
1717
|
+
block-size: calc(var(--ig-station-box) * 4);
|
|
1718
|
+
border-radius: var(--ig-radius-large);
|
|
1719
|
+
inline-size: min(100%, var(--ig-spine-width));
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1576
1722
|
/* ── legend ────────────────────────────────────────────────────────────── */
|
|
1577
1723
|
|
|
1578
1724
|
/* A FOOTER BAR, WHERE §16b PUTS IT, and worded rather than glyph-only. It sits
|
|
@@ -1591,8 +1737,29 @@ ${railDensity(".ig-viewer[data-density='dense']")}
|
|
|
1591
1737
|
padding: var(--ig-space) var(--ig-space-wide);
|
|
1592
1738
|
}
|
|
1593
1739
|
|
|
1740
|
+
/* FLOATED SO THE BROWSER STOPS TREATING IT AS A RENDERED LEGEND, which is the
|
|
1741
|
+
only reason this declaration exists. HTML gives the first in-flow legend of a
|
|
1742
|
+
fieldset a layout nothing else in CSS has: it is lifted OUT of the fieldset's
|
|
1743
|
+
content box, painted across the top border with a notch cut through the rule
|
|
1744
|
+
either side of it, and the content box then starts below it. On this bar that
|
|
1745
|
+
drew the caption sitting on the rule, a gap of bare ground under the caption
|
|
1746
|
+
where the fieldset's own surface should have been, and a top rule broken in
|
|
1747
|
+
the middle — all three of which looked like a styling bug and none of which
|
|
1748
|
+
any rule here asked for.
|
|
1749
|
+
|
|
1750
|
+
The spec's own escape hatch is the float: a legend whose computed float is
|
|
1751
|
+
not none is not the rendered legend, and becomes an ordinary child. This bar
|
|
1752
|
+
is a flex container, where float does not apply to an item at all, so the
|
|
1753
|
+
caption simply lays out as the first item on the row — which is what the
|
|
1754
|
+
flex rule above, its muted uppercase micro type and its centred alignment
|
|
1755
|
+
were always written for.
|
|
1756
|
+
|
|
1757
|
+
IT IS LOAD-BEARING AND LOOKS DECORATIVE, which is why it is recorded here at
|
|
1758
|
+
this length: delete it and the notch, the gap and the broken rule all come
|
|
1759
|
+
back, with nothing else in this file changed. */
|
|
1594
1760
|
.ig-legend-caption {
|
|
1595
1761
|
color: var(--ig-text-muted);
|
|
1762
|
+
float: left;
|
|
1596
1763
|
font-family: var(--ig-font-mono);
|
|
1597
1764
|
font-size: var(--ig-font-size-pill);
|
|
1598
1765
|
letter-spacing: var(--ig-tracking-group);
|
package/dist/styles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO;EACP,KAAK;;;;;;;;;;EAUL,KAAK;;;;EAIL,KAAK;;;;;;;;;EASL,KAAK;;;;;;;;;;EAUL,KAAK;;;;;;;;;;;;;EAaL,KAAK;;;;;;;;EAQL,KAAK;;;;;;;;;;;;;;;;;;EAkBL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BL,KAAK;;;;EAIL,KAAK;EACL,KAAK;;;;;;;EAOL,KAAK
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO;EACP,KAAK;;;;;;;;;;EAUL,KAAK;;;;EAIL,KAAK;;;;;;;;;EASL,KAAK;;;;;;;;;;EAUL,KAAK;;;;;;;;;;;;;EAaL,KAAK;;;;;;;;EAQL,KAAK;;;;;;;;;;;;;;;;;;EAkBL,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BL,KAAK;;;;EAIL,KAAK;EACL,KAAK;;;;;;;EAOL,KAAK;;;;;;;;;;;EAWL,KAAK;;;;;;;;;EASL,KAAK;;;;;;;;;;;;EAYL,KAAK;;;;;EAKL,KAAK;;;;;EAKL,KAAK;;;;;;;EAOL,KAAK;;;;;;;;;;;;;;;;;;;;;;;EAuBL,KAAK;EACL,KAAK;EACL,KAAK;;;;;;;;;;;;;;;;EAgBL,KAAK;;;;EAIL,KAAK;;;;;;;;;EASL,KAAK;;;;EAIL,KAAK;;;CAGN,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmf9B,WAAW,CAAC,gCAAgC,CAAC;;;;;;;;;;;;;EAa7C,WAAW,CAAC,kCAAkC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAm+BhD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@issuegraph/viewer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Render an Issuegraph document as a work order — the ordered spine with readiness stations, the five edge treatments, and three projections. Rendering only: no fetching, no mutation, no auth, and every value themeable through CSS custom properties.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"issuegraph",
|