@nanisoft/prism-ui 0.15.0 → 0.16.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/.tsbuildinfo +1 -1
- package/dist/blocks/data-table-01/data-table.d.ts +10 -0
- package/dist/blocks/data-table-01/data-table.d.ts.map +1 -1
- package/dist/blocks/data-table-01/data-table.js +2 -1
- package/dist/blocks/page-header-01/page-header.d.ts +7 -0
- package/dist/blocks/page-header-01/page-header.d.ts.map +1 -1
- package/dist/blocks/page-header-01/page-header.js +9 -1
- package/dist/blocks/run-console-01/run-console.d.ts.map +1 -1
- package/dist/blocks/run-console-01/run-console.js +2 -1
- package/dist/blocks/site-footer/site-footer.d.ts +16 -0
- package/dist/blocks/site-footer/site-footer.d.ts.map +1 -1
- package/dist/blocks/site-footer/site-footer.js +17 -1
- package/dist/blocks/stack-grid-01/stack-grid.d.ts +13 -0
- package/dist/blocks/stack-grid-01/stack-grid.d.ts.map +1 -1
- package/dist/blocks/stack-grid-01/stack-grid.js +14 -1
- package/dist/components/ui/diagram.d.ts +38 -7
- package/dist/components/ui/diagram.d.ts.map +1 -1
- package/dist/components/ui/diagram.js +134 -52
- package/dist/components/ui/fact-list.d.ts +17 -0
- package/dist/components/ui/fact-list.d.ts.map +1 -1
- package/dist/components/ui/fact-list.js +18 -1
- package/dist/components/ui/prose.d.ts +11 -0
- package/dist/components/ui/prose.d.ts.map +1 -1
- package/dist/components/ui/prose.js +12 -1
- package/dist/components/ui/pulse-graph.d.ts +36 -4
- package/dist/components/ui/pulse-graph.d.ts.map +1 -1
- package/dist/components/ui/pulse-graph.js +174 -60
- package/dist/components/ui/section.d.ts +33 -31
- package/dist/components/ui/section.d.ts.map +1 -1
- package/dist/components/ui/section.js +33 -31
- package/dist/lib/figure.d.ts +149 -0
- package/dist/lib/figure.d.ts.map +1 -0
- package/dist/lib/figure.js +242 -0
- package/dist/live/run-stream-01/run-stream.d.ts.map +1 -1
- package/dist/live/run-stream-01/run-stream.js +2 -1
- package/dist/pages/blog-post-page/index.d.ts +36 -15
- package/dist/pages/blog-post-page/index.d.ts.map +1 -1
- package/dist/pages/blog-post-page/index.js +35 -10
- package/dist/pages/docs-shell/docs-shell.d.ts +120 -18
- package/dist/pages/docs-shell/docs-shell.d.ts.map +1 -1
- package/dist/pages/docs-shell/docs-shell.js +208 -24
- package/dist/pages/error-page/index.d.ts.map +1 -1
- package/dist/pages/error-page/index.js +7 -3
- package/dist/pages/not-found-page/index.d.ts.map +1 -1
- package/dist/pages/not-found-page/index.js +4 -3
- package/dist/styles.css +107 -12
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { INK_CLEARANCE, LABEL_DESCENT, fitPoints, strokeBetween, } from '../../lib/figure.js';
|
|
2
3
|
import { cn } from '../../lib/utils.js';
|
|
3
4
|
/**
|
|
4
5
|
* The canvas the graph draws into, in its own user units.
|
|
@@ -7,18 +8,49 @@ import { cn } from '../../lib/utils.js';
|
|
|
7
8
|
* the reason `Diagram` gives: type inside a scaled SVG is sized in the SVG's
|
|
8
9
|
* own user units, so a viewBox derived from a caller's coordinates would make
|
|
9
10
|
* the label size a function of how large a number the caller happened to use.
|
|
11
|
+
*
|
|
12
|
+
* **A fixed canvas fixes the ratio, and the ratio was the half of the argument
|
|
13
|
+
* that was missing.** Every label's rendered size is its size in user units times
|
|
14
|
+
* the rendered width over this number, so a drawing that is right at a desktop
|
|
15
|
+
* width shrinks with its container until it says nothing. In the 356 pixels a
|
|
16
|
+
* phone leaves a PulseGraph, a stage name came to 7.23 pixels and a node's note
|
|
17
|
+
* to 5.56, which is a picture of a shape with nothing written on it. The canvas
|
|
18
|
+
* is still the right answer and it is what keeps a label a constant rather than a
|
|
19
|
+
* function of the caller's arithmetic; what it does not do is set a floor, and
|
|
20
|
+
* `LEGIBLE_MIN_WIDTH` is that floor. `DESIGN.md` states the rule under The figure
|
|
21
|
+
* floor.
|
|
10
22
|
*/
|
|
11
23
|
const CANVAS_WIDTH = 640;
|
|
12
24
|
const CANVAS_HEIGHT = 360;
|
|
25
|
+
/**
|
|
26
|
+
* The width below which the drawing stops being legible, as a spacing multiple.
|
|
27
|
+
*
|
|
28
|
+
* The floor is `CANVAS_WIDTH` itself, so the rule is one sentence: the drawing is
|
|
29
|
+
* never rendered narrower than its own coordinate space, one user unit is
|
|
30
|
+
* therefore never less than one pixel, and the smallest label in it is
|
|
31
|
+
* `NODE_NOTE_SIZE`, which is the size `--text-xs` resolves to. So no label this
|
|
32
|
+
* drawing sets is smaller than `text-xs`, and at the floor the smallest is
|
|
33
|
+
* exactly it.
|
|
34
|
+
*
|
|
35
|
+
* **A container narrower than the floor scrolls rather than shrinking, and that
|
|
36
|
+
* is the answer this repository already gives a table and a board.** A table that
|
|
37
|
+
* restacks has stopped being a table, and a graph whose stage names are seven
|
|
38
|
+
* pixels tall has stopped being a graph: it is the shape with nothing written on
|
|
39
|
+
* it a reader can read. So the drawing holds its size and the container moves
|
|
40
|
+
* under it, which is what `Table` does with seven columns and what `Gantt01`
|
|
41
|
+
* does with a schedule of names and bars.
|
|
42
|
+
*
|
|
43
|
+
* `160` is `CANVAS_WIDTH` as a multiple of the authored spacing base, which is
|
|
44
|
+
* how a width nobody held a separate decision for is written.
|
|
45
|
+
*/
|
|
46
|
+
const LEGIBLE_MIN_WIDTH = 'min-w-160';
|
|
13
47
|
/**
|
|
14
48
|
* The band left empty around the fitted points, in user units.
|
|
15
49
|
*
|
|
16
|
-
*
|
|
17
|
-
* pulse graph is read as a sequence running left to
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* collide with. Reserving it once here is cheaper than every caller learning
|
|
21
|
-
* where not to put a node.
|
|
50
|
+
* The same band `Diagram` keeps on its top and its two sides, and the foot
|
|
51
|
+
* carries more than that: a pulse graph is read as a sequence running left to
|
|
52
|
+
* right, so the band below the fitted area holds the rail, and a lane whose mark
|
|
53
|
+
* lands low puts its note in the gap `RAIL_BAND` left rather than under the rail.
|
|
22
54
|
*/
|
|
23
55
|
const PADDING = 56;
|
|
24
56
|
/** The node mark's radius. A circle, so no corner radius for the pack to move. */
|
|
@@ -29,14 +61,29 @@ const NODE_RADIUS = 6;
|
|
|
29
61
|
* The authored type scale is in `rem` and cannot be used inside a viewBox, where
|
|
30
62
|
* a font size is a coordinate and not a length on the page. These are geometry,
|
|
31
63
|
* the one thing Tailwind stays authoritative for.
|
|
64
|
+
*
|
|
65
|
+
* The note is twelve user units, which is what `--text-xs` resolves to, so at
|
|
66
|
+
* `LEGIBLE_MIN_WIDTH` it renders at exactly that step and never below it. It was
|
|
67
|
+
* ten, and ten is not a step this system sets interface type at, so a note was the
|
|
68
|
+
* smallest type the whole package emitted anywhere, a figure included. The name is
|
|
69
|
+
* one unit larger, which is the same hierarchy the two have always drawn.
|
|
32
70
|
*/
|
|
33
71
|
const NODE_NAME_SIZE = 13;
|
|
34
72
|
const NODE_NAME_OFFSET = 22;
|
|
35
|
-
const NODE_NOTE_SIZE =
|
|
36
|
-
|
|
73
|
+
const NODE_NOTE_SIZE = 12;
|
|
74
|
+
/**
|
|
75
|
+
* The note's baseline, measured down from the mark's centre.
|
|
76
|
+
*
|
|
77
|
+
* The name's baseline, then the note's own size, then a line of leading, so the
|
|
78
|
+
* second line sits under the first rather than on it. It is the deepest any node
|
|
79
|
+
* draws, and the rail band below is measured from it.
|
|
80
|
+
*/
|
|
81
|
+
const NODE_NOTE_OFFSET = NODE_NAME_OFFSET + NODE_NOTE_SIZE + 5;
|
|
82
|
+
/** The deepest ink a node draws below its mark's centre, in user units. */
|
|
83
|
+
const NODE_NOTE_DEPTH = NODE_NOTE_OFFSET + LABEL_DESCENT * NODE_NOTE_SIZE;
|
|
37
84
|
/**
|
|
38
85
|
* The rail the marker rides, in user units, measured from the bottom of the
|
|
39
|
-
*
|
|
86
|
+
* canvas.
|
|
40
87
|
*
|
|
41
88
|
* It is a separate element from the edges because it is a different claim: the
|
|
42
89
|
* edges say what connects to what, and the rail says there is an order. A graph
|
|
@@ -46,28 +93,64 @@ const NODE_NOTE_OFFSET = 35;
|
|
|
46
93
|
const RAIL_OFFSET = 74;
|
|
47
94
|
const RAIL_THICKNESS = 1.5;
|
|
48
95
|
/**
|
|
49
|
-
* The
|
|
50
|
-
* the leftover shared out evenly.
|
|
96
|
+
* The band the rail reserves at the foot of the canvas, in user units.
|
|
51
97
|
*
|
|
52
|
-
*
|
|
53
|
-
* the
|
|
98
|
+
* It is the rail's own distance up from the bottom, then half its thickness, then
|
|
99
|
+
* the clearance the drawing keeps between two pieces of ink, then the deepest ink
|
|
100
|
+
* a node draws below its mark. The fitted area stops above the whole of it, so a
|
|
101
|
+
* lane whose mark lands on the bottom of that area puts its note in the gap this
|
|
102
|
+
* band left rather than on the rail's own stroke. It is arithmetic rather than a
|
|
103
|
+
* number because every term in it has its own reason, and retuning the rail or the
|
|
104
|
+
* type moves the fit with it rather than leaving the band behind.
|
|
54
105
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
106
|
+
const RAIL_BAND = RAIL_OFFSET + RAIL_THICKNESS / 2 + INK_CLEARANCE + NODE_NOTE_DEPTH;
|
|
107
|
+
/**
|
|
108
|
+
* The labels this drawing prints under one node, which are what a stroke leaving it
|
|
109
|
+
* has to be trimmed against.
|
|
110
|
+
*
|
|
111
|
+
* Each label is its own obstacle rather than one box enclosing both, and that is the
|
|
112
|
+
* whole of the trim rule as it applies here: a node's name and note are both below
|
|
113
|
+
* its mark, so an edge leaving sideways runs along the mark's centre line and never
|
|
114
|
+
* enters either of them, while an edge leaving downward enters both. The arithmetic
|
|
115
|
+
* is `lib/figure`, which is where the shared answer lives; what is left here is the
|
|
116
|
+
* two labels this drawing prints and where it prints them.
|
|
117
|
+
*/
|
|
118
|
+
function nodeLabels(node) {
|
|
119
|
+
const labels = [{ text: node.name, size: NODE_NAME_SIZE, offset: NODE_NAME_OFFSET }];
|
|
120
|
+
if (node.note !== undefined) {
|
|
121
|
+
labels.push({ text: node.note, size: NODE_NOTE_SIZE, offset: NODE_NOTE_OFFSET });
|
|
122
|
+
}
|
|
123
|
+
return labels;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The head a carrying edge grows, at the end of the stroke a reader can see.
|
|
127
|
+
*
|
|
128
|
+
* The head is part of the stroke rather than part of the target mark, so it is
|
|
129
|
+
* placed at the stroke's own end and not at an inset from the mark's centre. A
|
|
130
|
+
* head measured from the centre would sit inside the clearance the stroke stops at
|
|
131
|
+
* and the two would read as two marks with a gap between them rather than as one
|
|
132
|
+
* arrow. Measured from the stroke's own end the tip is one ink clearance from the
|
|
133
|
+
* mark it points at, which is the same gap every other end of every other connector
|
|
134
|
+
* on the rail keeps.
|
|
135
|
+
*
|
|
136
|
+
* This is the one piece of the drawing that earns its place by being static. An
|
|
137
|
+
* edge that carries something has to say so to a reader who has turned every
|
|
138
|
+
* animation off, and a dashed overlay read as direction only while the dashes
|
|
139
|
+
* were moving, so the claim vanished for exactly the reader who most needed it.
|
|
140
|
+
* A head does not move, so it does not need a cycle, and it is legible in a
|
|
141
|
+
* printed page. The rail's travelling marker is then free to be pure atmosphere
|
|
142
|
+
* rather than the only thing carrying the meaning.
|
|
143
|
+
*/
|
|
144
|
+
function flowHead(line) {
|
|
145
|
+
const dx = line.to.x - line.from.x;
|
|
146
|
+
const dy = line.to.y - line.from.y;
|
|
147
|
+
const length = Math.hypot(dx, dy);
|
|
148
|
+
if (length === 0)
|
|
149
|
+
return null;
|
|
150
|
+
const ux = dx / length;
|
|
151
|
+
const uy = dy / length;
|
|
152
|
+
const head = 5;
|
|
153
|
+
return (_jsx("path", { "data-slot": "pulse-graph-flow", d: `M ${line.to.x - uy * head} ${line.to.y + ux * head} L ${line.to.x} ${line.to.y} L ${line.to.x + uy * head} ${line.to.y - ux * head}`, strokeWidth: 1.5, fill: "none", className: "stroke-brand-ink" }));
|
|
71
154
|
}
|
|
72
155
|
/**
|
|
73
156
|
* The lanes present, in ascending order.
|
|
@@ -159,19 +242,40 @@ function stagger(lane) {
|
|
|
159
242
|
* sentence is what a screen reader gets. Pass `decorative` when that sentence
|
|
160
243
|
* already says what the drawing shows.
|
|
161
244
|
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
245
|
+
* **No stroke crosses a label, and every connector still reaches the marks it
|
|
246
|
+
* joins.** An edge used to run from one mark's centre to the other, and a node's
|
|
247
|
+
* name is printed under its mark, so every edge heading downward struck through the
|
|
248
|
+
* name of the node it left. Each label a node prints is now its own obstacle rather
|
|
249
|
+
* than part of one box enclosing the whole node, and an edge is trimmed only against
|
|
250
|
+
* the labels it would actually enter. That direction is the whole of the rule: a
|
|
251
|
+
* name and a note both sit below their mark, so an edge leaving sideways runs along
|
|
252
|
+
* the mark's centre line and clears both, and it stops at the mark's own edge with
|
|
253
|
+
* the ink clearance between. Backing every edge off the widest label at its node
|
|
254
|
+
* instead detached all five connectors on a six-stage rail from the circles they
|
|
255
|
+
* connect, which is a drawing of a shape with no relations on it. The Component
|
|
256
|
+
* cannot know that two labels will not collide with one another, which is the
|
|
257
|
+
* caller's positions to settle, and it does know every mark's radius, both label
|
|
258
|
+
* offsets and every label's own width, because a monospaced label's width is its
|
|
259
|
+
* character count. The rail is held to
|
|
260
|
+
* the same clearance rather than to a fixed distance from the canvas bottom,
|
|
261
|
+
* because a note is the deepest ink a node draws and a lane whose mark lands low
|
|
262
|
+
* put it under the rail. `test/pulse-graph.test.tsx` asserts both halves as
|
|
263
|
+
* geometry rather than the presence of a class name.
|
|
264
|
+
*
|
|
265
|
+
* **No label is drawn below `text-xs`.** The drawing is wrapped in a container
|
|
266
|
+
* that scrolls sideways, and the drawing itself holds a floor of its own
|
|
267
|
+
* coordinate space, so a phone sees the whole graph at a legible size rather than
|
|
268
|
+
* the whole graph at six pixels. That is the same bargain `Table` strikes with
|
|
269
|
+
* seven columns, and it is a bargain rather than an accident because the
|
|
270
|
+
* alternative is a picture of a shape with nothing written on it.
|
|
271
|
+
*
|
|
272
|
+
* Positions are the caller's, and two labels crossing one another is still the
|
|
273
|
+
* caller's to settle. A relation naming a node that is not in `nodes` is dropped
|
|
274
|
+
* and counted on the element.
|
|
165
275
|
*/
|
|
166
276
|
function PulseGraph({ nodes, relations = [], label, decorative = false, className, }) {
|
|
167
|
-
const place = fit(nodes);
|
|
168
277
|
const byId = new Map(nodes.map((node) => [node.id, node]));
|
|
169
278
|
const lanes = lanesOf(nodes);
|
|
170
|
-
const drawn = relations.flatMap((relation) => {
|
|
171
|
-
const from = byId.get(relation.from);
|
|
172
|
-
const to = byId.get(relation.to);
|
|
173
|
-
return from && to ? [{ relation, from: place(from), to: place(to) }] : [];
|
|
174
|
-
});
|
|
175
279
|
/**
|
|
176
280
|
* The rail's two ends, taken from the lanes that exist rather than from the
|
|
177
281
|
* canvas. A rail as wide as the canvas regardless of where the nodes are would
|
|
@@ -179,6 +283,27 @@ function PulseGraph({ nodes, relations = [], label, decorative = false, classNam
|
|
|
179
283
|
* about a caller's data that the caller did not make.
|
|
180
284
|
*/
|
|
181
285
|
const railNodes = nodes.filter((node) => node.lane !== undefined);
|
|
286
|
+
// A lane's note is the deepest ink a node draws, and the rail sits below the
|
|
287
|
+
// fitted area, so the fit stops above the band the rail reserves. A field has
|
|
288
|
+
// no rail, nothing reserves the foot, and the fit is the same band the top and
|
|
289
|
+
// the two sides get.
|
|
290
|
+
const place = fitPoints(nodes, {
|
|
291
|
+
width: CANVAS_WIDTH,
|
|
292
|
+
height: CANVAS_HEIGHT,
|
|
293
|
+
padding: PADDING,
|
|
294
|
+
bottom: railNodes.length ? CANVAS_HEIGHT - RAIL_BAND : undefined,
|
|
295
|
+
});
|
|
296
|
+
const drawn = relations.flatMap((relation) => {
|
|
297
|
+
const from = byId.get(relation.from);
|
|
298
|
+
const to = byId.get(relation.to);
|
|
299
|
+
if (!from || !to)
|
|
300
|
+
return [];
|
|
301
|
+
// Each end carries its mark's centre and the labels printed under it, because
|
|
302
|
+
// a stroke is trimmed against the labels it would enter and the two are not the
|
|
303
|
+
// same thing.
|
|
304
|
+
const end = (node) => ({ at: place(node), labels: nodeLabels(node) });
|
|
305
|
+
return [{ relation, from: end(from), to: end(to) }];
|
|
306
|
+
});
|
|
182
307
|
const railAt = railNodes.length
|
|
183
308
|
? {
|
|
184
309
|
x0: Math.min(...railNodes.map((node) => place(node).x)) - NODE_RADIUS - 10,
|
|
@@ -186,27 +311,16 @@ function PulseGraph({ nodes, relations = [], label, decorative = false, classNam
|
|
|
186
311
|
}
|
|
187
312
|
: null;
|
|
188
313
|
const railY = CANVAS_HEIGHT - RAIL_OFFSET;
|
|
189
|
-
return (
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const ux = dx / length;
|
|
201
|
-
const uy = dy / length;
|
|
202
|
-
const hx = to.x - ux * inset;
|
|
203
|
-
const hy = to.y - uy * inset;
|
|
204
|
-
const head = 5;
|
|
205
|
-
return (_jsx("path", { "data-slot": "pulse-graph-flow", d: `M ${hx - uy * head} ${hy + ux * head} L ${hx} ${hy} L ${hx + uy * head} ${hy - ux * head}`, strokeWidth: 1.5, fill: "none", className: "stroke-brand-ink" }));
|
|
206
|
-
})()
|
|
207
|
-
: null] }, `${relation.from}-${relation.to}`))), nodes.map((node) => {
|
|
208
|
-
const at = place(node);
|
|
209
|
-
return (_jsxs("g", { "data-slot": "pulse-graph-node", "data-node": node.id, "data-emphasis": node.emphasis || undefined, "data-lane": node.lane, children: [node.emphasis ? (_jsx("circle", { "data-slot": "pulse-graph-halo", cx: at.x, cy: at.y, r: NODE_RADIUS, strokeWidth: 0, className: cn('fill-brand-ink/25', 'prism-ambient-pulse', stagger(node.lane ?? 0)) })) : null, _jsx("circle", { cx: at.x, cy: at.y, r: NODE_RADIUS, strokeWidth: node.emphasis ? 2 : 1, className: cn(node.emphasis ? 'fill-accent stroke-brand-ink' : 'fill-card stroke-border') }), _jsx("text", { x: at.x, y: at.y + NODE_NAME_OFFSET, fontSize: NODE_NAME_SIZE, textAnchor: "middle", className: "fill-foreground font-mono", children: node.name }), node.note ? (_jsx("text", { x: at.x, y: at.y + NODE_NOTE_OFFSET, fontSize: NODE_NOTE_SIZE, textAnchor: "middle", className: "fill-muted-foreground font-mono", children: node.note })) : null] }, node.id));
|
|
210
|
-
})] }));
|
|
314
|
+
return (
|
|
315
|
+
// The sideways region, for the reason `LEGIBLE_MIN_WIDTH` states: the drawing
|
|
316
|
+
// holds a legible floor and a container narrower than it moves under the
|
|
317
|
+
// drawing rather than the drawing shrinking below what it says.
|
|
318
|
+
_jsx("div", { "data-slot": "pulse-graph-container", className: "w-full overflow-x-auto", children: _jsxs("svg", { "data-slot": "pulse-graph", "data-unresolved-relations": relations.length - drawn.length, "data-lanes": lanes.length, viewBox: `0 0 ${CANVAS_WIDTH} ${CANVAS_HEIGHT}`, xmlns: "http://www.w3.org/2000/svg", role: decorative ? undefined : 'img', "aria-label": decorative ? undefined : label, "aria-hidden": decorative || undefined, className: cn('h-auto w-full', LEGIBLE_MIN_WIDTH, className), children: [railAt ? (_jsxs("g", { "data-slot": "pulse-graph-rail", children: [_jsx("line", { "data-slot": "pulse-graph-rail-line", x1: railAt.x0, y1: railY, x2: railAt.x1, y2: railY, strokeWidth: RAIL_THICKNESS, className: "stroke-border" }), _jsx("g", { "data-slot": "pulse-graph-marker", className: "prism-ambient-travel prism-ambient-delay-1", style: { '--ambient-travel-distance': `${railAt.x1 - railAt.x0}px` }, children: _jsx("rect", { x: railAt.x0 - 2.5, y: railY - 2.5, width: 5, height: 5, rx: 2.5, className: "fill-brand-ink" }) })] })) : null, drawn.map(({ relation, from, to }) => {
|
|
319
|
+
const line = strokeBetween(from.at, to.at, NODE_RADIUS, from.labels, to.labels);
|
|
320
|
+
return (_jsxs("g", { "data-slot": "pulse-graph-relation", "data-relation": `${relation.from}-${relation.to}`, "data-carries": relation.carries || undefined, children: [_jsx("line", { x1: line.from.x, y1: line.from.y, x2: line.to.x, y2: line.to.y, strokeWidth: 1, strokeDasharray: relation.indirect ? '4 4' : undefined, className: "stroke-muted-foreground/50 fill-none" }), relation.carries ? flowHead(line) : null] }, `${relation.from}-${relation.to}`));
|
|
321
|
+
}), nodes.map((node) => {
|
|
322
|
+
const at = place(node);
|
|
323
|
+
return (_jsxs("g", { "data-slot": "pulse-graph-node", "data-node": node.id, "data-emphasis": node.emphasis || undefined, "data-lane": node.lane, children: [node.emphasis ? (_jsx("circle", { "data-slot": "pulse-graph-halo", cx: at.x, cy: at.y, r: NODE_RADIUS, strokeWidth: 0, className: cn('fill-brand-ink/25', 'prism-ambient-pulse', stagger(node.lane ?? 0)) })) : null, _jsx("circle", { cx: at.x, cy: at.y, r: NODE_RADIUS, strokeWidth: node.emphasis ? 2 : 1, className: cn(node.emphasis ? 'fill-accent stroke-brand-ink' : 'fill-card stroke-border') }), _jsx("text", { x: at.x, y: at.y + NODE_NAME_OFFSET, fontSize: NODE_NAME_SIZE, textAnchor: "middle", className: "fill-foreground font-mono", children: node.name }), node.note ? (_jsx("text", { "data-slot": "pulse-graph-node-note", x: at.x, y: at.y + NODE_NOTE_OFFSET, fontSize: NODE_NOTE_SIZE, textAnchor: "middle", className: "fill-muted-foreground font-mono", children: node.note })) : null] }, node.id));
|
|
324
|
+
})] }) }));
|
|
211
325
|
}
|
|
212
326
|
export { PulseGraph };
|
|
@@ -102,45 +102,47 @@ export declare function headingSizeClass(level: HeadingLevel): string;
|
|
|
102
102
|
*
|
|
103
103
|
* | level | step | authored value | at `sm` | authored value |
|
|
104
104
|
* | --- | --- | --- | --- | --- |
|
|
105
|
-
* | `h1` | `text-
|
|
106
|
-
* | `h2` | `text-
|
|
107
|
-
* | `h3` | `text-
|
|
108
|
-
* | `h4` | `text-
|
|
109
|
-
* | `h5` | `text-
|
|
105
|
+
* | `h1` | `text-5xl` | 3rem / 1 | `sm:text-6xl` | 3.75rem / 1 |
|
|
106
|
+
* | `h2` | `text-4xl` | 2.25rem / 1.111 | `sm:text-5xl` | 3rem / 1 |
|
|
107
|
+
* | `h3` | `text-3xl` | 1.875rem / 1.2 | `sm:text-4xl` | 2.25rem / 1.111 |
|
|
108
|
+
* | `h4` | `text-2xl` | 1.5rem / 1.333 | `sm:text-3xl` | 1.875rem / 1.2 |
|
|
109
|
+
* | `h5` | `text-xl` | 1.25rem / 1.4 | `sm:text-2xl` | 1.5rem / 1.333 |
|
|
110
110
|
* | `h6` | `text-lg` | 1.125rem / 1.556 | `sm:text-xl` | 1.25rem / 1.4 |
|
|
111
111
|
*
|
|
112
|
-
* **`h1` is Display and
|
|
113
|
-
* gives it: a page's own heading is the largest thing on the
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
112
|
+
* **`h1` is Display and Display is the ceiling of the scale**, because that is
|
|
113
|
+
* the role `DESIGN.md` gives it: a page's own heading is the largest thing on the
|
|
114
|
+
* page. The two steps above `4xl` are authored rather than invented here, and they
|
|
115
|
+
* are authored as a pair rather than as one step, because every rung of this table
|
|
116
|
+
* is a pair: a base step and one step up at `sm`. A single new step would have made
|
|
117
|
+
* Display the one heading in the system that does not grow, which is a smaller
|
|
118
|
+
* defect than the one this table was written to remove and is still a defect.
|
|
119
|
+
* `5xl` is `4xl` times four thirds, which is the first gap in the group wider than
|
|
120
|
+
* any gap it already had, and `6xl` is `5xl` times five fourths. Nothing in the
|
|
121
|
+
* system goes above `6xl`, and no heading level steps above Display.
|
|
117
122
|
*
|
|
118
123
|
* **`h2` is one step below it, and `h2` is what almost every Block renders**,
|
|
119
124
|
* because a Block is composed under a heading the document already owns. That is
|
|
120
|
-
* the whole of
|
|
121
|
-
*
|
|
125
|
+
* the whole of what a consumer sees: a section title moves from 1.5rem to
|
|
126
|
+
* 2.25rem, and above `sm` from 1.875rem to 3rem.
|
|
122
127
|
*
|
|
123
|
-
* **The floor is `
|
|
128
|
+
* **The floor is `h6`, and the floor is `text-lg`.** `lg` is the deepest authored
|
|
124
129
|
* step that is not smaller than Body, and Body is 400 at 1.125rem, so a heading
|
|
125
130
|
* that stepped one further would render smaller than the copy it introduces and
|
|
126
|
-
* read as a caption rather than as a heading.
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* `text-balance` at every step,
|
|
132
|
-
* copy where size no longer can.
|
|
131
|
+
* read as a caption rather than as a heading. The table has six rows and the scale
|
|
132
|
+
* has exactly six steps at or above Body, so the ladder lands on the floor rather
|
|
133
|
+
* than running off the bottom of it: every level now holds a step of its own, where
|
|
134
|
+
* before `h4` through `h6` shared one. `childLevel()` clamps at `h6` for the same
|
|
135
|
+
* reason the table stops there. A heading at the floor is still a heading: it keeps
|
|
136
|
+
* `font-semibold`, keeps `tracking-tight`, and keeps `text-balance` at every step,
|
|
137
|
+
* so weight and tracking tell it apart from body copy where size no longer can.
|
|
133
138
|
*
|
|
134
139
|
* So a consumer gets the hierarchy by passing the level it was already passing,
|
|
135
140
|
* and a Block moved from an `h2` section into an `h3` one carries its size with
|
|
136
141
|
* it, which is what `headingLevel` was introduced to do.
|
|
137
142
|
*
|
|
138
|
-
* **`Prose`
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* This Component was the second answer, and it was the one every catalogue Item
|
|
142
|
-
* used, which is why the disagreement was visible on every product page and not
|
|
143
|
-
* on a documentation page.
|
|
143
|
+
* **`Prose` walks this ladder from one rung down**, because its measure is the
|
|
144
|
+
* reading measure rather than the page column and the Display step does not fit a
|
|
145
|
+
* 42rem column. See `Prose`.
|
|
144
146
|
*/
|
|
145
147
|
export declare function SectionHeading({ index, eyebrow, title, as: Heading, description, align, id, className, }: {
|
|
146
148
|
/**
|
|
@@ -168,11 +170,11 @@ export declare function SectionHeading({ index, eyebrow, title, as: Heading, des
|
|
|
168
170
|
* entry point.
|
|
169
171
|
*
|
|
170
172
|
* It also picks the size, and there is no prop for the size. The table is in
|
|
171
|
-
* this Component's JSDoc above: `h1` at
|
|
172
|
-
* 1.
|
|
173
|
-
* step above `sm`. Passing a deeper level is
|
|
174
|
-
* as well as an outline one, which is the
|
|
175
|
-
* deeper should read as one level deeper.
|
|
173
|
+
* this Component's JSDoc above: `h1` at 3rem, `h2` at 2.25rem, `h3` at
|
|
174
|
+
* 1.875rem, `h4` at 1.5rem, `h5` at 1.25rem and `h6` at 1.125rem, each
|
|
175
|
+
* stepping up one authored step above `sm`. Passing a deeper level is
|
|
176
|
+
* therefore a typographic decision as well as an outline one, which is the
|
|
177
|
+
* point: a Block composed one level deeper should read as one level deeper.
|
|
176
178
|
*/
|
|
177
179
|
as?: HeadingLevel;
|
|
178
180
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../../src/components/ui/section.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,EACtB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,+BAWjC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAKlE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAG5D;AAoBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE5D;AAED
|
|
1
|
+
{"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../../../src/components/ui/section.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGtC;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,EACtB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,+BAWjC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAKlE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,YAAY,CAG5D;AAoBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE5D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,OAAO,EACP,KAAK,EACL,EAAE,EAAE,OAAc,EAClB,WAAW,EACX,KAAgB,EAChB,EAAE,EACF,SAAS,GACV,EAAE;IACD;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,KAAK,EAAE,SAAS,CAAA;IAChB,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAA;IACzB;;;;;;;;;;;;OAYG;IACH,EAAE,CAAC,EAAE,YAAY,CAAA;IACjB;;;;;;;;;;;OAWG;IACH,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,+BAgCA"}
|
|
@@ -63,11 +63,11 @@ export function childLevel(level) {
|
|
|
63
63
|
* two copies in step.
|
|
64
64
|
*/
|
|
65
65
|
const HEADING_SIZE = {
|
|
66
|
-
h1: 'text-
|
|
67
|
-
h2: 'text-
|
|
68
|
-
h3: 'text-
|
|
69
|
-
h4: 'text-
|
|
70
|
-
h5: 'text-
|
|
66
|
+
h1: 'text-5xl sm:text-6xl',
|
|
67
|
+
h2: 'text-4xl sm:text-5xl',
|
|
68
|
+
h3: 'text-3xl sm:text-4xl',
|
|
69
|
+
h4: 'text-2xl sm:text-3xl',
|
|
70
|
+
h5: 'text-xl sm:text-2xl',
|
|
71
71
|
h6: 'text-lg sm:text-xl',
|
|
72
72
|
};
|
|
73
73
|
/**
|
|
@@ -113,45 +113,47 @@ export function headingSizeClass(level) {
|
|
|
113
113
|
*
|
|
114
114
|
* | level | step | authored value | at `sm` | authored value |
|
|
115
115
|
* | --- | --- | --- | --- | --- |
|
|
116
|
-
* | `h1` | `text-
|
|
117
|
-
* | `h2` | `text-
|
|
118
|
-
* | `h3` | `text-
|
|
119
|
-
* | `h4` | `text-
|
|
120
|
-
* | `h5` | `text-
|
|
116
|
+
* | `h1` | `text-5xl` | 3rem / 1 | `sm:text-6xl` | 3.75rem / 1 |
|
|
117
|
+
* | `h2` | `text-4xl` | 2.25rem / 1.111 | `sm:text-5xl` | 3rem / 1 |
|
|
118
|
+
* | `h3` | `text-3xl` | 1.875rem / 1.2 | `sm:text-4xl` | 2.25rem / 1.111 |
|
|
119
|
+
* | `h4` | `text-2xl` | 1.5rem / 1.333 | `sm:text-3xl` | 1.875rem / 1.2 |
|
|
120
|
+
* | `h5` | `text-xl` | 1.25rem / 1.4 | `sm:text-2xl` | 1.5rem / 1.333 |
|
|
121
121
|
* | `h6` | `text-lg` | 1.125rem / 1.556 | `sm:text-xl` | 1.25rem / 1.4 |
|
|
122
122
|
*
|
|
123
|
-
* **`h1` is Display and
|
|
124
|
-
* gives it: a page's own heading is the largest thing on the
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
123
|
+
* **`h1` is Display and Display is the ceiling of the scale**, because that is
|
|
124
|
+
* the role `DESIGN.md` gives it: a page's own heading is the largest thing on the
|
|
125
|
+
* page. The two steps above `4xl` are authored rather than invented here, and they
|
|
126
|
+
* are authored as a pair rather than as one step, because every rung of this table
|
|
127
|
+
* is a pair: a base step and one step up at `sm`. A single new step would have made
|
|
128
|
+
* Display the one heading in the system that does not grow, which is a smaller
|
|
129
|
+
* defect than the one this table was written to remove and is still a defect.
|
|
130
|
+
* `5xl` is `4xl` times four thirds, which is the first gap in the group wider than
|
|
131
|
+
* any gap it already had, and `6xl` is `5xl` times five fourths. Nothing in the
|
|
132
|
+
* system goes above `6xl`, and no heading level steps above Display.
|
|
128
133
|
*
|
|
129
134
|
* **`h2` is one step below it, and `h2` is what almost every Block renders**,
|
|
130
135
|
* because a Block is composed under a heading the document already owns. That is
|
|
131
|
-
* the whole of
|
|
132
|
-
*
|
|
136
|
+
* the whole of what a consumer sees: a section title moves from 1.5rem to
|
|
137
|
+
* 2.25rem, and above `sm` from 1.875rem to 3rem.
|
|
133
138
|
*
|
|
134
|
-
* **The floor is `
|
|
139
|
+
* **The floor is `h6`, and the floor is `text-lg`.** `lg` is the deepest authored
|
|
135
140
|
* step that is not smaller than Body, and Body is 400 at 1.125rem, so a heading
|
|
136
141
|
* that stepped one further would render smaller than the copy it introduces and
|
|
137
|
-
* read as a caption rather than as a heading.
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* `text-balance` at every step,
|
|
143
|
-
* copy where size no longer can.
|
|
142
|
+
* read as a caption rather than as a heading. The table has six rows and the scale
|
|
143
|
+
* has exactly six steps at or above Body, so the ladder lands on the floor rather
|
|
144
|
+
* than running off the bottom of it: every level now holds a step of its own, where
|
|
145
|
+
* before `h4` through `h6` shared one. `childLevel()` clamps at `h6` for the same
|
|
146
|
+
* reason the table stops there. A heading at the floor is still a heading: it keeps
|
|
147
|
+
* `font-semibold`, keeps `tracking-tight`, and keeps `text-balance` at every step,
|
|
148
|
+
* so weight and tracking tell it apart from body copy where size no longer can.
|
|
144
149
|
*
|
|
145
150
|
* So a consumer gets the hierarchy by passing the level it was already passing,
|
|
146
151
|
* and a Block moved from an `h2` section into an `h3` one carries its size with
|
|
147
152
|
* it, which is what `headingLevel` was introduced to do.
|
|
148
153
|
*
|
|
149
|
-
* **`Prose`
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
* This Component was the second answer, and it was the one every catalogue Item
|
|
153
|
-
* used, which is why the disagreement was visible on every product page and not
|
|
154
|
-
* on a documentation page.
|
|
154
|
+
* **`Prose` walks this ladder from one rung down**, because its measure is the
|
|
155
|
+
* reading measure rather than the page column and the Display step does not fit a
|
|
156
|
+
* 42rem column. See `Prose`.
|
|
155
157
|
*/
|
|
156
158
|
export function SectionHeading({ index, eyebrow, title, as: Heading = 'h2', description, align = 'center', id, className, }) {
|
|
157
159
|
return (_jsxs("div", { className: cn('flex flex-col gap-4', align === 'center' ? 'items-center text-center' : 'items-start text-left', className), children: [index ? (_jsx("span", { className: "text-muted-foreground font-mono text-xs font-normal tracking-normal", children: index })) : null, eyebrow ? (_jsx("span", { className: "text-muted-foreground text-sm font-medium tracking-wide uppercase", children: eyebrow })) : null, _jsx(Heading, { id: id, className: cn('font-semibold tracking-tight text-balance', headingSizeClass(Heading)), children: title }), description ? (_jsx("p", { className: "text-muted-foreground max-w-measure text-lg text-pretty", children: description })) : null] }));
|