@stealthscale/component-charts 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.
@@ -0,0 +1,1054 @@
1
+ import { below, defineRecipe, defineSlotRecipe, dense, onSlots, ratioVariants, sizeVariants } from "@stealthscale/theme/authoring";
2
+ //#region src/chart/placed.ts
3
+ /**
4
+ * Styles the lines, words and marks a chart places over its plot: a quadrant chart's dividing lines
5
+ * and names, the words beside a scatter's points, a timeline's markers, an annotation's words and
6
+ * the crosshair, and sizes a plot by its rows.
7
+ *
8
+ * @remarks
9
+ * The chart recipe spreads `PLACED` into its plot's styles and takes `ROWS_TALL` as its `rows`
10
+ * ratio. Each selector names the class its part renders with, so no rule applies to another
11
+ * chart's marks. The dividing lines are in the emphasized border ink and the quadrants' names in
12
+ * the label ink. A point's words are the ink inside a halo in the panel's color, and a marker's
13
+ * count is the black or white `contrast-color()` finds against the marker's color. An
14
+ * annotation's words are the label ink inside the same halo, and the crosshair takes the
15
+ * cursor's border ink.
16
+ */
17
+ /**
18
+ * Class a quadrant chart's two dividing lines take.
19
+ */
20
+ const DIVISION = "chart-division";
21
+ /**
22
+ * Selects the line of each of a quadrant chart's dividing lines.
23
+ */
24
+ const DIVISIONS = "& .chart-division .recharts-reference-line-line";
25
+ /**
26
+ * Class the name of a quadrant takes, written in its corner of the plot.
27
+ */
28
+ const QUADRANT = "chart-quadrant";
29
+ /**
30
+ * Selects the names of a quadrant chart's quadrants.
31
+ */
32
+ const QUADRANT_NAMES = "& .recharts-text.chart-quadrant";
33
+ /**
34
+ * Class the words beside a point take, such as a vendor's name on a quadrant chart.
35
+ */
36
+ const POINT_LABEL = "chart-point-label";
37
+ /**
38
+ * Selects the words beside the points of a scatter.
39
+ */
40
+ const POINT_LABELS = "& .recharts-text.chart-point-label";
41
+ /**
42
+ * Class a timeline's marker takes: a dot for one moment, or a pill with the count of a cluster.
43
+ */
44
+ const MARKER = "chart-marker";
45
+ /**
46
+ * Custom property of a timeline marker's color, which fills the dot or the pill and which the
47
+ * count's ink contrasts with.
48
+ */
49
+ const MARKER_FILL = "--chart-marker";
50
+ /**
51
+ * Selects the dot or the pill of every timeline marker.
52
+ */
53
+ const MARKER_SHAPES = "& .chart-marker > :is(circle, rect)";
54
+ /**
55
+ * Selects the count a timeline marker writes on its pill.
56
+ */
57
+ const MARKER_COUNTS = "& .chart-marker > text";
58
+ /**
59
+ * Selects a timeline marker the chart selects on a press.
60
+ */
61
+ const MARKER_PRESSES = "& .chart-marker[data-press]";
62
+ /**
63
+ * Class an annotation's mark takes: a moment's rule, a period's wash or a point's ring.
64
+ */
65
+ const ANNOTATION = "chart-annotation";
66
+ /**
67
+ * Class the words of an annotation take.
68
+ */
69
+ const ANNOTATION_LABEL = "chart-annotation-label";
70
+ /**
71
+ * Selects the words of every annotation.
72
+ */
73
+ const ANNOTATION_LABELS = "& .recharts-text.chart-annotation-label";
74
+ /**
75
+ * Class the crosshair's guide takes.
76
+ */
77
+ const CROSSHAIR = "chart-crosshair";
78
+ /**
79
+ * Selects the line of the crosshair's guide.
80
+ */
81
+ const CROSSHAIR_LINE = "& .chart-crosshair .recharts-reference-line-line";
82
+ /**
83
+ * Custom property of the number of rows a plot at the `rows` ratio is tall, such as a timeline's
84
+ * lanes.
85
+ */
86
+ const ROWS = "--chart-rows";
87
+ /**
88
+ * Sizes a plot by its rows: a row of `sizes.10` per row and `sizes.12` for the axis under them.
89
+ */
90
+ const ROWS_TALL = {
91
+ aspectRatio: "auto",
92
+ blockSize: "calc(var(--chart-rows, 1) * {sizes.10} + {sizes.12})"
93
+ };
94
+ /**
95
+ * Styles of the lines, words and marks a chart places over its plot, which the plot spreads.
96
+ */
97
+ const PLACED = {
98
+ [ANNOTATION_LABELS]: {
99
+ _highContrast: {
100
+ fill: "CanvasText",
101
+ stroke: "Canvas"
102
+ },
103
+ fill: "fg.muted",
104
+ paintOrder: "stroke",
105
+ pointerEvents: "none",
106
+ stroke: "bg.panel",
107
+ strokeLinejoin: "round",
108
+ strokeWidth: "ring",
109
+ textStyle: "body.xs"
110
+ },
111
+ [CROSSHAIR_LINE]: {
112
+ _highContrast: { stroke: "CanvasText" },
113
+ stroke: "border"
114
+ },
115
+ [DIVISIONS]: {
116
+ _highContrast: { stroke: "CanvasText" },
117
+ stroke: "border.emphasized"
118
+ },
119
+ [MARKER_COUNTS]: {
120
+ fill: "contrast-color(var(--chart-marker))",
121
+ fontWeight: "semibold",
122
+ pointerEvents: "none",
123
+ textStyle: "body.xs"
124
+ },
125
+ [MARKER_PRESSES]: { cursor: "button" },
126
+ [MARKER_SHAPES]: {
127
+ _highContrast: { stroke: "Canvas" },
128
+ fill: "var(--chart-marker)",
129
+ stroke: "bg.panel",
130
+ strokeWidth: "ring"
131
+ },
132
+ [POINT_LABELS]: {
133
+ _highContrast: {
134
+ fill: "CanvasText",
135
+ stroke: "Canvas"
136
+ },
137
+ fill: "fg",
138
+ paintOrder: "stroke",
139
+ pointerEvents: "none",
140
+ stroke: "bg.panel",
141
+ strokeLinejoin: "round",
142
+ strokeWidth: "ring",
143
+ textStyle: "body.xs"
144
+ },
145
+ [QUADRANT_NAMES]: {
146
+ _highContrast: { fill: "CanvasText" },
147
+ fill: "fg.muted",
148
+ fontWeight: "medium",
149
+ pointerEvents: "none",
150
+ textStyle: "body.xs"
151
+ }
152
+ };
153
+ //#endregion
154
+ //#region src/chart/recipe.ts
155
+ /**
156
+ * Styles a chart's figure and parts, and restyles the classes recharts writes on its SVG with the
157
+ * theme's tokens.
158
+ *
159
+ * @remarks
160
+ * Recharts writes its inks as presentation attributes: `#666` on tick labels, axis lines and tick
161
+ * marks, `#ccc` on grid lines, a polar radius axis and the cursor, `#fff` on dots, sectors and a
162
+ * funnel's trapezoids, `#808080` on a `Label`'s text. A CSS property applies over a presentation
163
+ * attribute, so the plot sets each from a role, and a `fill` or `stroke` a caller passes to an
164
+ * axis or a `Label` loses to it. Under forced colors neither Firefox nor Chromium replaces an SVG
165
+ * `fill` or `stroke`, so the series keep their colors, and the plot sets the ticks, the labels
166
+ * and the axis lines in `CanvasText` and the grid in `GrayText`. A bar's hairline edge in the
167
+ * panel's color parts the segments of a stack. A series the legend does not point at fades to the
168
+ * plot's `--chart-faded`. The band under the pointer and a hovered legend button fill with the
169
+ * neutral palette's `subtle`, which steps towards the ink in both modes, where a well such as
170
+ * `bg.muted` sinks below a dark panel. A pie's shares and a funnel's counts render in `fg` inside
171
+ * a halo in the panel's color, so they read on a mark of any color, and the pointer passes
172
+ * through them to the mark under them, which opens the tooltip. A treemap's tile hides a line of
173
+ * words it marks as wider than the tile, and a sunburst's gap takes no pointer and no edge. A
174
+ * flow, a sankey's band or a chord diagram's ribbon, rests at the backdrop opacity, lifts to the
175
+ * muted opacity while the tooltip is at the flow or at one of its nodes, and fades while the
176
+ * tooltip is at another mark, and so does the bar or the arc of a node the tooltip is not at. The
177
+ * tooltip's panel is transparent while it is empty, so a readout outside recharts' wrapper, such
178
+ * as a chord diagram's, shows only while it is at a mark and remains in the accessibility tree as
179
+ * a live region before it fills. A bar's target tick is the ink inside a halo in the panel's
180
+ * color, and the part of a bar's zones no zone covers fills like a track. A quadrant chart's
181
+ * dividing lines are in the emphasized border ink and its quadrants' names in the label ink. A
182
+ * point's words are the ink inside a halo in the panel's color, and a timeline marker's count is
183
+ * the black or white `contrast-color()` finds against the marker's color. The `rows` ratio sizes
184
+ * a plot by its rows, such as a timeline's lanes. The recipe has no `palette` or `effect` axis,
185
+ * because each series takes its own color and a chart is not a control.
186
+ */
187
+ /**
188
+ * Selects the tick labels of every cartesian and polar axis.
189
+ */
190
+ const TICKS = "& .recharts-text:is(.recharts-cartesian-axis-tick-value, .recharts-polar-angle-axis-tick-value, .recharts-polar-radius-axis-tick-value)";
191
+ /**
192
+ * Selects the tick labels of a polar radius axis, which recharts writes on the ring they label,
193
+ * over the rings and the polygons.
194
+ */
195
+ const RADII = "& .recharts-text.recharts-polar-radius-axis-tick-value";
196
+ /**
197
+ * Class a sector takes as a track: the rest of a gauge's dial past the reading, and the part of
198
+ * its range no zone covers.
199
+ */
200
+ const TRACK = "chart-track";
201
+ /**
202
+ * Selects a track: the rest of a radial bar's full turn behind its ring, and a gauge's track.
203
+ *
204
+ * @remarks
205
+ * The selector names the sector's class and the track's class. Its specificity of three classes
206
+ * applies its forced edge over the panel-colored edge of every sector, whose `:is()` counts a
207
+ * class and a type.
208
+ */
209
+ const TRACKS = "& .recharts-sector:is(.recharts-radial-bar-background-sector, .chart-track)";
210
+ /**
211
+ * Selects the line of every cartesian and polar axis and the tick marks along it.
212
+ */
213
+ const AXES = "& :is(.recharts-cartesian-axis-line, .recharts-cartesian-axis-tick-line, .recharts-polar-angle-axis-line, .recharts-polar-angle-axis-tick-line, .recharts-polar-radius-axis-line)";
214
+ /**
215
+ * Selects the text of recharts' `Label`, which a reference line or an axis renders.
216
+ */
217
+ const LABELS = "& .recharts-text.recharts-label";
218
+ /**
219
+ * Selects the lines of a cartesian grid, and the spokes and the ring paths of a polar one.
220
+ */
221
+ const GRID = "& :is(.recharts-cartesian-grid line, .recharts-polar-grid line, .recharts-polar-grid path)";
222
+ /**
223
+ * Selects the band a bar chart renders behind the hovered category.
224
+ */
225
+ const BAND = "& .recharts-rectangle.recharts-tooltip-cursor";
226
+ /**
227
+ * Selects the cursor line a line or area chart renders at the hovered category, and the cross a
228
+ * scatter renders at the hovered point.
229
+ */
230
+ const CURSOR = "& :is(.recharts-curve, .recharts-cross).recharts-tooltip-cursor";
231
+ /**
232
+ * Selects the white edges recharts renders around a dot, between a pie's sectors and between a
233
+ * funnel's stages, and a scatter's points, whose edge keeps overlapping points apart.
234
+ *
235
+ * @remarks
236
+ * A reference dot is left out, because recharts edges it in its own `stroke`, such as an
237
+ * annotation's ring in its palette's chart color. The exclusion is inside `:where()`, so the rule
238
+ * keeps the specificity the chart's other edge rules are written against.
239
+ */
240
+ const SEPARATED = "& :is(.recharts-active-dot circle, .recharts-dot:not(:where(.recharts-reference-dot-dot)), .recharts-sector, .recharts-symbols, .recharts-trapezoid)";
241
+ /**
242
+ * Selects every bar, whose edge parts the segments of a stack.
243
+ */
244
+ const BARS = "& .recharts-bar-rectangle path";
245
+ /**
246
+ * Class a trend line takes, whose line fades with the series it summarises.
247
+ */
248
+ const TREND = "chart-trend";
249
+ /**
250
+ * Class a treemap's tile takes, whose group takes its family's opacity.
251
+ */
252
+ const TILE = "chart-tile";
253
+ /**
254
+ * Class a sunburst's gap takes: the arc a ring leaves where a leaf ends above it.
255
+ */
256
+ const GAP = "chart-gap";
257
+ /**
258
+ * Selects a sunburst's gap, whose specificity applies over the panel-colored edge of every sector.
259
+ */
260
+ const GAPS = "& .recharts-sector.chart-gap";
261
+ /**
262
+ * Class a flow takes at the backdrop opacity: a sankey's band, a stroke without a fill, or a chord
263
+ * diagram's ribbon, a fill without a stroke.
264
+ */
265
+ const FLOW = "chart-flow";
266
+ /**
267
+ * Class a node takes: a sankey's bar or a chord diagram's arc, with its words.
268
+ */
269
+ const NODE = "chart-node";
270
+ /**
271
+ * Selects every flow of a sankey or a chord diagram.
272
+ */
273
+ const FLOWS = "& .chart-flow";
274
+ /**
275
+ * Selects the flow the tooltip is at, and every flow of the node it is at.
276
+ */
277
+ const LIT$1 = "& .chart-flow[data-trace=lit]";
278
+ /**
279
+ * Selects every other flow while the tooltip is at a mark.
280
+ */
281
+ const DIMMED = "& .chart-flow[data-trace=dimmed]";
282
+ /**
283
+ * Selects the bar of every node of a sankey.
284
+ */
285
+ const BARS_OF_NODES = "& .chart-node .recharts-rectangle";
286
+ /**
287
+ * Selects the bar or the arc of every node the tooltip is not at while it is at a mark.
288
+ */
289
+ const IDLE = "& .chart-node[data-trace=dimmed] :is(.recharts-rectangle, .recharts-sector)";
290
+ /**
291
+ * Attribute a treemap's tile writes on a line of words wider than the tile, and a node on a line
292
+ * of words that meets another node's, which the plot hides.
293
+ */
294
+ const OVERFLOW$1 = "data-overflow";
295
+ /**
296
+ * Selects a line of words a treemap's tile or a node marks as not fitting.
297
+ */
298
+ const OVERFLOWED = "& :is(.chart-tile, .chart-node) [data-overflow]";
299
+ /**
300
+ * Selects the painted paths of every line, area, bar, sector, polygon, point and trend line, and
301
+ * every treemap tile, which take a series' opacity.
302
+ */
303
+ const MARKS = "& :is(.recharts-line-curve, .recharts-area-area, .recharts-area-curve, .recharts-bar-rectangle path, .recharts-sector, .recharts-polygon, .recharts-symbols, .chart-trend .recharts-reference-line-line, .chart-tile)";
304
+ /**
305
+ * Class a `LabelList` gives each value it writes on a mark, a pie's share or a funnel's count,
306
+ * which recharts writes on the `text` in place of `recharts-label`.
307
+ */
308
+ const SHARE = "chart-share";
309
+ /**
310
+ * Selects the shares a pie writes on its slices and the counts a funnel writes on its stages.
311
+ */
312
+ const SHARES = "& .recharts-text.chart-share";
313
+ /**
314
+ * Class a waterfall's connectors take: the dashed lines from each bar to the next at the running
315
+ * total.
316
+ */
317
+ const CONNECTOR = "chart-connector";
318
+ /**
319
+ * Selects the line of every connector.
320
+ */
321
+ const CONNECTORS = "& .chart-connector .recharts-reference-line-line";
322
+ /**
323
+ * Class a box's whiskers and their caps take, in the chart and in its key.
324
+ */
325
+ const WHISKER = "chart-whisker";
326
+ /**
327
+ * Class a box's median line and a violin's median point take, in the chart and in its key.
328
+ */
329
+ const MEDIAN = "chart-median";
330
+ /**
331
+ * Class a violin's quartile bar takes, in the chart and in its key.
332
+ */
333
+ const QUARTILES = "chart-quartiles";
334
+ /**
335
+ * Class an outlier's point takes, in the chart and in its key.
336
+ */
337
+ const OUTLIER = "chart-outlier";
338
+ /**
339
+ * Class a bar's target tick takes, in the chart and in its key.
340
+ */
341
+ const TARGET = "chart-target";
342
+ /**
343
+ * Selects the part of a bar's zones no zone covers, a rectangle with the track's class.
344
+ */
345
+ const BAND_TRACKS = "& rect.chart-track";
346
+ /**
347
+ * Custom property of the opacity a series' marks take while the legend points at another series.
348
+ */
349
+ const FADED = "--chart-faded";
350
+ /**
351
+ * Defines the chart recipe: a figure whose plot is as wide as the figure and as tall as its ratio,
352
+ * by default the video ratio.
353
+ */
354
+ const recipe$2 = defineSlotRecipe({
355
+ base: {
356
+ caption: {
357
+ color: "fg.muted",
358
+ textStyle: "body.sm"
359
+ },
360
+ center: {
361
+ alignItems: "center",
362
+ display: "flex",
363
+ flexDirection: "column",
364
+ inset: "0",
365
+ justifyContent: "center",
366
+ pointerEvents: "none",
367
+ position: "absolute",
368
+ textAlign: "center"
369
+ },
370
+ centerLabel: {
371
+ color: "fg.muted",
372
+ textStyle: "body.xs"
373
+ },
374
+ centerValue: {
375
+ color: "fg",
376
+ fontVariantNumeric: "tabular-nums",
377
+ fontWeight: "semibold",
378
+ textStyle: "heading.md"
379
+ },
380
+ empty: {
381
+ alignItems: "center",
382
+ borderColor: "border",
383
+ borderRadius: "l2",
384
+ borderStyle: "dashed",
385
+ borderWidth: "hairline",
386
+ color: "fg.muted",
387
+ display: "flex",
388
+ inlineSize: "full",
389
+ justifyContent: "center",
390
+ padding: dense("{spacing.inset.md}"),
391
+ textAlign: "center",
392
+ textStyle: "body.sm"
393
+ },
394
+ glyph: {
395
+ "& > svg": {
396
+ blockSize: "full",
397
+ inlineSize: "full",
398
+ overflow: "visible"
399
+ },
400
+ boxSize: "icon.xs",
401
+ display: "inline-flex",
402
+ flexShrink: "0"
403
+ },
404
+ heading: {
405
+ color: "fg",
406
+ fontWeight: "medium"
407
+ },
408
+ item: {
409
+ _highContrast: { _hover: {
410
+ outlineColor: "CanvasText",
411
+ outlineStyle: "solid"
412
+ } },
413
+ _hover: { background: "neutral.subtle" },
414
+ "&[aria-pressed=false]": {
415
+ color: "fg.muted",
416
+ textDecorationLine: "line-through"
417
+ },
418
+ alignItems: "center",
419
+ background: "transparent",
420
+ borderRadius: "l1",
421
+ color: "fg",
422
+ cursor: "button",
423
+ display: "inline-flex",
424
+ focusRingColor: "border.focus",
425
+ focusVisibleRing: "outside",
426
+ gap: dense("{spacing.gap.sm}"),
427
+ ["&[aria-pressed=false] .color-swatch"]: { opacity: "0.4" },
428
+ minBlockSize: "6",
429
+ paddingInline: dense("{spacing.inset.xs}"),
430
+ textStyle: "body.sm"
431
+ },
432
+ key: {
433
+ alignItems: "center",
434
+ color: "fg.muted",
435
+ columnGap: dense("{spacing.gap.md}"),
436
+ display: "flex",
437
+ flexWrap: "wrap",
438
+ listStyle: "none",
439
+ margin: "0",
440
+ padding: "0",
441
+ rowGap: dense("{spacing.gap.xs}"),
442
+ textStyle: "body.sm"
443
+ },
444
+ keyItem: {
445
+ alignItems: "center",
446
+ display: "inline-flex",
447
+ gap: dense("{spacing.gap.sm}")
448
+ },
449
+ legend: {
450
+ alignItems: "center",
451
+ borderWidth: "0",
452
+ columnGap: dense("{spacing.gap.md}"),
453
+ display: "flex",
454
+ flexWrap: "wrap",
455
+ margin: "0",
456
+ minInlineSize: "0",
457
+ padding: "0",
458
+ rowGap: dense("{spacing.gap.xs}")
459
+ },
460
+ name: {
461
+ color: "fg.muted",
462
+ flex: "1"
463
+ },
464
+ plot: {
465
+ ...PLACED,
466
+ "& .recharts-surface": {
467
+ focusRingColor: "border.focus",
468
+ focusVisibleRing: "outside",
469
+ overflow: "visible"
470
+ },
471
+ [AXES]: {
472
+ _highContrast: { stroke: "CanvasText" },
473
+ stroke: "border"
474
+ },
475
+ [BAND]: { fill: "neutral.subtle" },
476
+ [BAND_TRACKS]: {
477
+ _highContrast: {
478
+ fill: "Canvas",
479
+ stroke: "GrayText"
480
+ },
481
+ fill: "neutral.subtle"
482
+ },
483
+ [BARS]: {
484
+ stroke: "bg.panel",
485
+ strokeWidth: "hairline"
486
+ },
487
+ [BARS_OF_NODES]: { transition: "opacity {durations.fast} {easings.out}" },
488
+ [CONNECTORS]: {
489
+ _highContrast: { stroke: "GrayText" },
490
+ stroke: "border.emphasized"
491
+ },
492
+ [CURSOR]: { stroke: "border" },
493
+ [DIMMED]: { opacity: "backdrop" },
494
+ [FADED]: "{opacity.backdrop}",
495
+ [FLOWS]: {
496
+ fillOpacity: "{opacity.backdrop}",
497
+ strokeOpacity: "{opacity.backdrop}",
498
+ transition: "fill-opacity {durations.fast} {easings.out}, stroke-opacity {durations.fast} {easings.out}, opacity {durations.fast} {easings.out}"
499
+ },
500
+ [GAPS]: {
501
+ pointerEvents: "none",
502
+ stroke: "none"
503
+ },
504
+ [GRID]: {
505
+ _highContrast: { stroke: "GrayText" },
506
+ stroke: "border.muted"
507
+ },
508
+ [IDLE]: { opacity: "muted" },
509
+ inlineSize: "full",
510
+ [LABELS]: {
511
+ _highContrast: { fill: "CanvasText" },
512
+ fill: "fg.muted",
513
+ textStyle: "body.xs"
514
+ },
515
+ [LIT$1]: {
516
+ fillOpacity: "{opacity.muted}",
517
+ strokeOpacity: "{opacity.muted}"
518
+ },
519
+ [MARKS]: { transition: "opacity {durations.fast} {easings.out}" },
520
+ minInlineSize: "0",
521
+ [OVERFLOWED]: { visibility: "hidden" },
522
+ position: "relative",
523
+ [RADII]: {
524
+ _highContrast: { stroke: "Canvas" },
525
+ dominantBaseline: "text-before-edge",
526
+ paintOrder: "stroke",
527
+ stroke: "bg.panel",
528
+ strokeLinejoin: "round",
529
+ strokeWidth: "ring"
530
+ },
531
+ [SEPARATED]: { stroke: "bg.panel" },
532
+ [SHARES]: {
533
+ _highContrast: {
534
+ fill: "CanvasText",
535
+ stroke: "Canvas"
536
+ },
537
+ fill: "fg",
538
+ fontWeight: "semibold",
539
+ paintOrder: "stroke",
540
+ pointerEvents: "none",
541
+ stroke: "bg.panel",
542
+ strokeLinejoin: "round",
543
+ strokeWidth: "ring",
544
+ textStyle: "body.xs"
545
+ },
546
+ [TICKS]: {
547
+ _highContrast: { fill: "CanvasText" },
548
+ fill: "fg.muted",
549
+ textStyle: "body.xs"
550
+ },
551
+ [TRACKS]: {
552
+ _highContrast: {
553
+ fill: "Canvas",
554
+ stroke: "GrayText"
555
+ },
556
+ fill: "neutral.subtle"
557
+ }
558
+ },
559
+ root: {
560
+ "& .chart-median": {
561
+ _highContrast: {
562
+ fill: "Canvas",
563
+ stroke: "CanvasText"
564
+ },
565
+ fill: "bg.panel",
566
+ stroke: "fg"
567
+ },
568
+ "& .chart-outlier": {
569
+ _highContrast: { fill: "Canvas" },
570
+ fill: "bg.panel"
571
+ },
572
+ "& .chart-quartiles": {
573
+ _highContrast: { fill: "CanvasText" },
574
+ fill: "fg"
575
+ },
576
+ "& .chart-target": {
577
+ _highContrast: {
578
+ fill: "CanvasText",
579
+ stroke: "Canvas"
580
+ },
581
+ fill: "fg",
582
+ paintOrder: "stroke",
583
+ stroke: "bg.panel",
584
+ strokeWidth: "ring"
585
+ },
586
+ "& .chart-whisker": {
587
+ _highContrast: { stroke: "CanvasText" },
588
+ stroke: "fg.muted"
589
+ },
590
+ display: "flex",
591
+ flexDirection: "column",
592
+ gap: dense("{spacing.gap.md}"),
593
+ inlineSize: "full",
594
+ minInlineSize: "0"
595
+ },
596
+ row: {
597
+ alignItems: "center",
598
+ display: "flex",
599
+ gap: dense("{spacing.gap.sm}")
600
+ },
601
+ tooltip: {
602
+ _empty: { opacity: "0" },
603
+ background: "bg.popover",
604
+ borderColor: "border",
605
+ borderRadius: "l2",
606
+ borderStyle: "solid",
607
+ borderWidth: "hairline",
608
+ boxShadow: "lg",
609
+ color: "fg",
610
+ display: "grid",
611
+ gap: dense("{spacing.gap.xs}"),
612
+ minInlineSize: "40",
613
+ padding: dense("{spacing.inset.sm}"),
614
+ textAlign: "start",
615
+ textStyle: "body.sm"
616
+ },
617
+ value: {
618
+ color: "fg",
619
+ fontVariantNumeric: "tabular-nums",
620
+ fontWeight: "medium"
621
+ }
622
+ },
623
+ className: "chart",
624
+ defaultVariants: { ratio: "video" },
625
+ jsx: [/^Chart(\.\w+)?$/u],
626
+ slots: [
627
+ "root",
628
+ "plot",
629
+ "center",
630
+ "centerValue",
631
+ "centerLabel",
632
+ "empty",
633
+ "caption",
634
+ "legend",
635
+ "item",
636
+ "key",
637
+ "keyItem",
638
+ "glyph",
639
+ "tooltip",
640
+ "heading",
641
+ "row",
642
+ "name",
643
+ "value"
644
+ ],
645
+ variants: {
646
+ /**
647
+ * Aspect ratio of the plot and of the empty state in its place, one of the theme's ratios, or
648
+ * `rows` for a plot as tall as its rows.
649
+ *
650
+ * @remarks
651
+ * Recharts measures the plot's box after the first render and renders nothing in a box 0
652
+ * pixels high. The ratio gives the box its height before that measurement. At `rows` the box
653
+ * is a row of `sizes.10` per row of `--chart-rows`, one unless stated, and `sizes.12` for the
654
+ * axis, so a timeline of four lanes is 208px tall at any width.
655
+ */
656
+ ratio: onSlots({
657
+ empty: {
658
+ ...ratioVariants(),
659
+ rows: ROWS_TALL
660
+ },
661
+ plot: {
662
+ ...ratioVariants(),
663
+ rows: ROWS_TALL
664
+ }
665
+ }) }
666
+ });
667
+ //#endregion
668
+ //#region src/heat/recipe.ts
669
+ /**
670
+ * Styles a heat grid, a table whose cells take a color from their values: the frame, the grid, its
671
+ * headings and cells, the readout over a cell, and the key under the grid.
672
+ *
673
+ * @remarks
674
+ * The cells are 2px apart on the panel, so each reads as one block of color. A cell takes its
675
+ * fill from `--heat-fill`, which the component sets from the value, and keeps it under forced
676
+ * colors, where neither engine would otherwise keep a background color. A value printed in a
677
+ * cell is black or white, whichever `contrast-color()` picks against the fill, which measured at
678
+ * least 4.56:1 on every fill of the ten themes in both modes and both engines. A cell without a
679
+ * value has no fill and a dashed edge, and a cell without a reading in a sparse grid has neither.
680
+ * The cell the readout shows takes an outline in the ink, inside its edge, and a cell with focus
681
+ * takes the focus ring outside it, over the gap. The headings of the row and the column the
682
+ * readout shows fill with the neutral palette's `subtle`. The row headings are sticky at the
683
+ * grid's start while it scrolls sideways, and their words and the corner's align to their end,
684
+ * beside the cells. Next to squares the row headings take no height of their own, so the rows are
685
+ * as far apart as the columns. A group's words start at its first column and are placed out of
686
+ * the table's layout, so a group never widens its columns, and they are transparent with
687
+ * `data-overflow`. The readout is placed above its cell at `--heat-x` and `--heat-y`, or below it
688
+ * with `data-side="bottom"`, and takes no pointer. The key aligns to the grid's end, and its bar
689
+ * runs the scale's colors from `--heat-ramp` from the reading start. The recipe has no `palette`
690
+ * or `effect` axis, because the values set the colors and a grid is not a control.
691
+ */
692
+ /**
693
+ * Sizes the grid offers.
694
+ */
695
+ const SIZES = [
696
+ "sm",
697
+ "md",
698
+ "lg"
699
+ ];
700
+ /**
701
+ * Attribute the cell the readout shows writes, which the recipe outlines.
702
+ */
703
+ const SHOWN = "data-readout";
704
+ /**
705
+ * Custom property of a cell's fill.
706
+ */
707
+ const FILL = "--heat-fill";
708
+ /**
709
+ * Custom property of the colors of the key's bar, from its start to its end.
710
+ */
711
+ const RAMP = "--heat-ramp";
712
+ /**
713
+ * Custom property of the readout's horizontal middle, from the frame's start.
714
+ */
715
+ const READOUT_X = "--heat-x";
716
+ /**
717
+ * Custom property of the edge of the cell the readout is placed against, from the frame's top.
718
+ */
719
+ const READOUT_Y = "--heat-y";
720
+ /**
721
+ * Attribute a heading writes while the readout shows a cell in its row or its column.
722
+ */
723
+ const LIT = "data-lit";
724
+ /**
725
+ * Attribute the readout writes while its cell is out of the scroll area's view, which hides it.
726
+ */
727
+ const CLIPPED = "data-clipped";
728
+ /**
729
+ * Attribute a group's words write while they are wider than the group, which hides them from sight.
730
+ */
731
+ const OVERFLOW = "data-overflow";
732
+ /**
733
+ * Room between two cells, which the table also leaves around its outer cells.
734
+ */
735
+ const SPACING = "{spacing.0.5}";
736
+ /**
737
+ * Custom property of a block cell's height and least width, which the size sets.
738
+ */
739
+ const BLOCK = "--heat-block";
740
+ /**
741
+ * Custom property of a square cell's side, which the size sets.
742
+ */
743
+ const SQUARE = "--heat-square";
744
+ /**
745
+ * Maps each size to the grid step of a block cell's height and least width.
746
+ */
747
+ const BLOCKS = {
748
+ lg: "11",
749
+ md: "8",
750
+ sm: "6"
751
+ };
752
+ /**
753
+ * Maps each size to the grid step of a square cell's side.
754
+ */
755
+ const SQUARES = {
756
+ lg: "6",
757
+ md: "3.5",
758
+ sm: "2.5"
759
+ };
760
+ /**
761
+ * Styles every cell: a fill from the value, a transparent edge a missing value dashes, the outline
762
+ * of the cell the readout shows and the focus ring.
763
+ */
764
+ const CELL = {
765
+ _focusVisible: { outlineOffset: "0" },
766
+ _highContrast: {
767
+ "&[data-state=missing]": { borderColor: "GrayText" },
768
+ [`&[${SHOWN}]`]: { outlineColor: "CanvasText" },
769
+ focusRingColor: "Highlight"
770
+ },
771
+ "&[data-state=missing]": {
772
+ borderColor: "border",
773
+ borderStyle: "dashed"
774
+ },
775
+ [`&[${SHOWN}]:not(:focus-visible)`]: {
776
+ outlineColor: "fg",
777
+ outlineOffset: "calc({borderWidths.indicator} * -1)",
778
+ outlineStyle: "solid",
779
+ outlineWidth: "indicator"
780
+ },
781
+ backgroundColor: `var(${FILL}, transparent)`,
782
+ borderColor: "transparent",
783
+ borderStyle: "solid",
784
+ borderWidth: "hairline",
785
+ focusRingColor: "border.focus",
786
+ focusVisibleRing: "outside",
787
+ forcedColorAdjust: "none",
788
+ padding: "0"
789
+ };
790
+ /**
791
+ * Styles a heading the readout lights: the neutral palette's `subtle` fill and the full ink.
792
+ */
793
+ const LIGHT = { [`&[${LIT}]`]: {
794
+ _highContrast: {
795
+ background: "Highlight",
796
+ color: "HighlightText",
797
+ forcedColorAdjust: "none"
798
+ },
799
+ background: "neutral.subtle",
800
+ color: "fg"
801
+ } };
802
+ /**
803
+ * Defines the heat recipe: a grid of block cells 2px apart at size `md` by default.
804
+ */
805
+ const recipe$1 = defineSlotRecipe({
806
+ base: {
807
+ bar: {
808
+ _rtl: { backgroundImage: `linear-gradient(to left, var(${RAMP}))` },
809
+ backgroundImage: `linear-gradient(to right, var(${RAMP}))`,
810
+ blockSize: "2",
811
+ borderColor: "border",
812
+ borderRadius: "l1",
813
+ borderStyle: "solid",
814
+ borderWidth: "hairline",
815
+ forcedColorAdjust: "none"
816
+ },
817
+ cell: {
818
+ ...CELL,
819
+ textAlign: "center",
820
+ verticalAlign: "middle",
821
+ whiteSpace: "nowrap"
822
+ },
823
+ columnHeading: {
824
+ ...LIGHT,
825
+ "&:first-child": {
826
+ background: "bg.panel",
827
+ insetInlineStart: "0",
828
+ position: "sticky",
829
+ textAlign: "end",
830
+ zIndex: "1"
831
+ },
832
+ color: "fg.muted",
833
+ fontWeight: "normal",
834
+ paddingBlock: "0",
835
+ paddingInline: dense("{spacing.gap.xs}"),
836
+ textAlign: "center",
837
+ verticalAlign: "bottom",
838
+ whiteSpace: "nowrap"
839
+ },
840
+ frame: {
841
+ display: "flex",
842
+ flexDirection: "column",
843
+ gap: dense("{spacing.gap.sm}"),
844
+ inlineSize: "fit",
845
+ maxInlineSize: "full",
846
+ minInlineSize: "0",
847
+ position: "relative"
848
+ },
849
+ grid: {
850
+ borderCollapse: "separate",
851
+ borderSpacing: SPACING
852
+ },
853
+ group: {
854
+ blockSize: "1lh",
855
+ color: "fg.muted",
856
+ fontWeight: "normal",
857
+ padding: "0",
858
+ position: "relative",
859
+ verticalAlign: "bottom"
860
+ },
861
+ groupLabel: {
862
+ [`&[${OVERFLOW}]`]: { opacity: "0" },
863
+ insetBlockEnd: "0",
864
+ insetInlineStart: "0",
865
+ pointerEvents: "none",
866
+ position: "absolute",
867
+ whiteSpace: "nowrap"
868
+ },
869
+ key: {
870
+ alignItems: "center",
871
+ alignSelf: "end",
872
+ color: "fg.muted",
873
+ columnGap: dense("{spacing.gap.sm}"),
874
+ display: "grid",
875
+ fontVariantNumeric: "tabular-nums",
876
+ gridTemplateColumns: "auto auto {sizes.40} auto",
877
+ inlineSize: "fit",
878
+ marginInlineEnd: SPACING,
879
+ rowGap: dense("{spacing.gap.xs}"),
880
+ textStyle: "body.xs"
881
+ },
882
+ keyLabel: {
883
+ color: "fg",
884
+ paddingInlineEnd: dense("{spacing.gap.xs}")
885
+ },
886
+ midpoint: {
887
+ gridColumn: "3",
888
+ gridRow: "2",
889
+ justifySelf: "center"
890
+ },
891
+ name: { srOnly: true },
892
+ readout: {
893
+ "&[data-side=bottom]": { translate: "-50% {spacing.gap.xs}" },
894
+ [`&[${CLIPPED}]`]: { visibility: "hidden" },
895
+ left: `var(${READOUT_X})`,
896
+ maxInlineSize: "full",
897
+ pointerEvents: "none",
898
+ position: "absolute",
899
+ top: `var(${READOUT_Y})`,
900
+ translate: "-50% calc(-100% - {spacing.gap.xs})",
901
+ zIndex: "docked"
902
+ },
903
+ rowHeading: {
904
+ ...LIGHT,
905
+ background: "bg.panel",
906
+ color: "fg.muted",
907
+ fontWeight: "normal",
908
+ insetInlineStart: "0",
909
+ paddingBlock: "0",
910
+ paddingInline: dense("{spacing.gap.xs}"),
911
+ position: "sticky",
912
+ textAlign: "end",
913
+ whiteSpace: "nowrap",
914
+ zIndex: "1"
915
+ },
916
+ value: {
917
+ color: `contrast-color(var(${FILL}))`,
918
+ fontVariantNumeric: "tabular-nums",
919
+ paddingInline: dense("{spacing.gap.xs}")
920
+ }
921
+ },
922
+ className: "heat",
923
+ compoundVariants: [{
924
+ css: { rowHeading: { lineHeight: "0" } },
925
+ name: "squared",
926
+ shape: "square"
927
+ }],
928
+ defaultVariants: {
929
+ shape: "block",
930
+ size: "md"
931
+ },
932
+ jsx: [/^Heatmap$/u],
933
+ slots: [
934
+ "frame",
935
+ "grid",
936
+ "group",
937
+ "groupLabel",
938
+ "columnHeading",
939
+ "rowHeading",
940
+ "cell",
941
+ "value",
942
+ "name",
943
+ "readout",
944
+ "key",
945
+ "keyLabel",
946
+ "bar",
947
+ "midpoint"
948
+ ],
949
+ variants: {
950
+ /**
951
+ * Shape of the cells: a block at least as wide as it is tall, which widens to a printed value,
952
+ * or a square with a 2px corner in every theme.
953
+ */
954
+ shape: {
955
+ block: { cell: {
956
+ blockSize: `var(${BLOCK})`,
957
+ minInlineSize: `var(${BLOCK})`
958
+ } },
959
+ square: { cell: {
960
+ borderRadius: "xs",
961
+ boxSize: `var(${SQUARE})`,
962
+ minInlineSize: `var(${SQUARE})`
963
+ } }
964
+ },
965
+ /**
966
+ * Size of the cells and of the words in the grid: a block 24, 32 or 44px tall, a square 10, 14
967
+ * or 24px, and the headings and values one text size smaller than the size. A large square is a
968
+ * pointer target of the 24px WCAG 2.5.8 asks for.
969
+ */
970
+ size: onSlots({
971
+ cell: sizeVariants((size) => ({
972
+ [BLOCK]: dense(`{sizes.${BLOCKS[size]}}`),
973
+ [SQUARE]: dense(`{sizes.${SQUARES[size]}}`)
974
+ }), SIZES),
975
+ columnHeading: sizeVariants((size) => ({ textStyle: `label.${below(size)}` }), SIZES),
976
+ group: sizeVariants((size) => ({ textStyle: `label.${below(size)}` }), SIZES),
977
+ rowHeading: sizeVariants((size) => ({ textStyle: `label.${below(size)}` }), SIZES),
978
+ value: sizeVariants((size) => ({ textStyle: `body.${below(size)}` }), SIZES)
979
+ })
980
+ }
981
+ });
982
+ //#endregion
983
+ //#region src/spark/recipe.ts
984
+ /**
985
+ * Styles a spark, a run of values the size of a word: the box recharts renders the run in, and the
986
+ * baseline across it.
987
+ *
988
+ * @remarks
989
+ * The box takes its size from the grid, four times as wide as it is tall: 64 by 16 pixels at
990
+ * `sm`, 96 by 24 at `md` and 128 by 32 at `lg`, times the density. `stretch` fills the
991
+ * container's width at the size's height. A baseline renders in the subtle ink, and in
992
+ * `CanvasText` under forced colors, where the run keeps its color because neither Firefox nor
993
+ * Chromium replaces an SVG `fill` or `stroke`. The recipe has no `palette` axis, because the run
994
+ * takes a palette through the component's `color`.
995
+ */
996
+ /**
997
+ * Selects the line of a baseline recharts renders across the run.
998
+ */
999
+ const BASELINE = "& .recharts-reference-line line";
1000
+ /**
1001
+ * Maps each size to the grid step of its height.
1002
+ */
1003
+ const HEIGHTS = {
1004
+ lg: "8",
1005
+ md: "6",
1006
+ sm: "4"
1007
+ };
1008
+ /**
1009
+ * Maps each size to the grid step of its width.
1010
+ */
1011
+ const WIDTHS = {
1012
+ lg: "32",
1013
+ md: "24",
1014
+ sm: "16"
1015
+ };
1016
+ /**
1017
+ * Defines the spark recipe: an inline box at the middle size.
1018
+ */
1019
+ const recipe = defineRecipe({
1020
+ base: {
1021
+ [BASELINE]: {
1022
+ _highContrast: { stroke: "CanvasText" },
1023
+ stroke: "fg.subtle"
1024
+ },
1025
+ display: "inline-flex",
1026
+ flexShrink: "0",
1027
+ verticalAlign: "middle"
1028
+ },
1029
+ className: "spark",
1030
+ defaultVariants: { size: "md" },
1031
+ jsx: [/^Spark(bar|line)$/u],
1032
+ variants: {
1033
+ /**
1034
+ * Box on the grid, four times as wide as it is tall.
1035
+ */
1036
+ size: sizeVariants((size) => ({
1037
+ blockSize: dense(`{sizes.${HEIGHTS[size]}}`),
1038
+ inlineSize: dense(`{sizes.${WIDTHS[size]}}`)
1039
+ }), [
1040
+ "sm",
1041
+ "md",
1042
+ "lg"
1043
+ ]),
1044
+ /**
1045
+ * Whether the box fills its container's width at the size's height.
1046
+ */
1047
+ stretch: { true: {
1048
+ display: "flex",
1049
+ inlineSize: "full"
1050
+ } }
1051
+ }
1052
+ });
1053
+ //#endregion
1054
+ export { DIVISION as A, TRACK as C, ANNOTATION as D, recipe$2 as E, ROWS as F, MARKER_FILL as M, POINT_LABEL as N, ANNOTATION_LABEL as O, QUADRANT as P, TILE as S, WHISKER as T, OUTLIER as _, OVERFLOW as a, SHARE as b, READOUT_Y as c, CONNECTOR as d, FADED as f, NODE as g, MEDIAN as h, LIT as i, MARKER as j, CROSSHAIR as k, SHOWN as l, GAP as m, CLIPPED as n, RAMP as o, FLOW as p, FILL as r, READOUT_X as s, recipe as t, recipe$1 as u, OVERFLOW$1 as v, TREND as w, TARGET as x, QUARTILES as y };