@krizaka/charts 0.3.0 → 0.4.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/README.md +1 -1
- package/dist/actions-5VG352VZ.js +53 -0
- package/dist/actions-5VG352VZ.js.map +1 -0
- package/dist/bar.d.ts +3 -3
- package/dist/bar.js +7 -6
- package/dist/candlestick.d.ts +2 -2
- package/dist/candlestick.js +6 -5
- package/dist/card.d.ts +52 -0
- package/dist/card.js +19 -0
- package/dist/card.js.map +1 -0
- package/dist/{cartesian-BRhNQ3ib.d.ts → cartesian-CEY_wwe_.d.ts} +12 -2
- package/dist/chart.d.ts +2 -2
- package/dist/chart.js +5 -4
- package/dist/{chunk-BV4DBGN7.js → chunk-7W4T255Q.js} +4 -4
- package/dist/{chunk-W5ILLSPK.js → chunk-AGSSNMK5.js} +5 -5
- package/dist/{chunk-VKZZY2QD.js → chunk-FE4LUGAE.js} +5 -5
- package/dist/{chunk-ARARFMNE.js → chunk-FIQHMJZK.js} +5 -5
- package/dist/chunk-FIQHMJZK.js.map +1 -0
- package/dist/{chunk-ANUCSRUN.js → chunk-GD7TWEN3.js} +3 -3
- package/dist/chunk-GRRFPI27.js +89 -0
- package/dist/chunk-GRRFPI27.js.map +1 -0
- package/dist/{chunk-SLEJDQ3A.js → chunk-HH65IEUV.js} +3 -3
- package/dist/{chunk-OIRHLJBC.js → chunk-IJTI6VJD.js} +3 -3
- package/dist/{chunk-WVTIKOII.js → chunk-IURCLBUQ.js} +2 -2
- package/dist/{chunk-CVWSMUUB.js → chunk-JST4HJC3.js} +33 -15
- package/dist/chunk-JST4HJC3.js.map +1 -0
- package/dist/{chunk-IKQV3NSL.js → chunk-KERGFVSN.js} +3 -3
- package/dist/{chunk-XDDALY4C.js → chunk-KMQ7RANJ.js} +5 -5
- package/dist/{chunk-NCIQMRV3.js → chunk-LLUQEK5J.js} +5 -5
- package/dist/{chunk-AA5EWWYV.js → chunk-LZPZWBBY.js} +2 -2
- package/dist/{chunk-PBQV3B6O.js → chunk-MK2ZFUWM.js} +31 -16
- package/dist/chunk-MK2ZFUWM.js.map +1 -0
- package/dist/{chunk-CSSZLFLO.js → chunk-MRGMLDNS.js} +5 -5
- package/dist/{chunk-I3D7KUGN.js → chunk-NLTZWJLV.js} +3 -3
- package/dist/{chunk-PWMMXRMC.js → chunk-NV52AKHG.js} +3 -3
- package/dist/{chunk-MXLITIGU.js → chunk-NWJ5VDN7.js} +5 -5
- package/dist/{chunk-3CJHBJXA.js → chunk-OVASCEGF.js} +12 -73
- package/dist/chunk-OVASCEGF.js.map +1 -0
- package/dist/{chunk-EQLC2QVN.js → chunk-OZOAKP5F.js} +4 -4
- package/dist/chunk-OZOAKP5F.js.map +1 -0
- package/dist/{chunk-KNDHO67X.js → chunk-P2NK5L3B.js} +3 -3
- package/dist/{chunk-JTKR7ZWP.js → chunk-P6RS2L23.js} +140 -36
- package/dist/chunk-P6RS2L23.js.map +1 -0
- package/dist/{chunk-W5FX4TU3.js → chunk-PGD6SH5I.js} +30 -2
- package/dist/chunk-PGD6SH5I.js.map +1 -0
- package/dist/{chunk-4LBXEAGC.js → chunk-PWZHIGPO.js} +5 -5
- package/dist/{chunk-L2EKYWVI.js → chunk-VEOJNMPF.js} +3 -3
- package/dist/chunk-YHQFW2PR.js +71 -0
- package/dist/chunk-YHQFW2PR.js.map +1 -0
- package/dist/{chunk-C4MFZLJM.js → chunk-Z4T3JFNU.js} +2 -2
- package/dist/{chunk-EEP7PS2L.js → chunk-ZF7LVQTR.js} +3 -3
- package/dist/{context-BgYUymEO.d.ts → context-DNW7bJYw.d.ts} +19 -0
- package/dist/credits.d.ts +1 -1
- package/dist/credits.js +7 -6
- package/dist/earnings.d.ts +3 -3
- package/dist/earnings.js +8 -7
- package/dist/{frame-I7_xYGy5.d.ts → frame-B1HDNm7c.d.ts} +9 -5
- package/dist/funnel.d.ts +2 -2
- package/dist/funnel.js +6 -5
- package/dist/gauge.d.ts +2 -2
- package/dist/gauge.js +4 -3
- package/dist/geo.d.ts +2 -2
- package/dist/geo.js +5 -4
- package/dist/globe.d.ts +2 -2
- package/dist/globe.js +4 -3
- package/dist/goal.d.ts +2 -2
- package/dist/goal.js +5 -4
- package/dist/heatmap.d.ts +2 -2
- package/dist/heatmap.js +6 -5
- package/dist/index.d.ts +5 -3
- package/dist/index.js +45 -37
- package/dist/latency.d.ts +3 -3
- package/dist/latency.js +8 -7
- package/dist/line.d.ts +3 -3
- package/dist/line.js +7 -6
- package/dist/native.d.ts +19 -0
- package/dist/native.js +13 -1
- package/dist/native.js.map +1 -1
- package/dist/pie.d.ts +2 -2
- package/dist/pie.js +6 -5
- package/dist/provider.d.ts +2 -2
- package/dist/provider.js +4 -2
- package/dist/radar.d.ts +2 -2
- package/dist/radar.js +6 -5
- package/dist/sankey.d.ts +2 -2
- package/dist/sankey.js +6 -5
- package/dist/scatter.d.ts +2 -2
- package/dist/scatter.js +6 -5
- package/dist/sparkline.d.ts +2 -2
- package/dist/sparkline.js +6 -5
- package/dist/table-sheet-CQBIAV5N.js +36 -0
- package/dist/table-sheet-CQBIAV5N.js.map +1 -0
- package/dist/throughput.d.ts +3 -3
- package/dist/throughput.js +8 -7
- package/dist/ticker.d.ts +3 -3
- package/dist/ticker.js +8 -7
- package/dist/treemap.d.ts +2 -2
- package/dist/treemap.js +7 -6
- package/package.json +295 -53
- package/registry/area-chart.json +82 -12
- package/registry/bar-chart.json +82 -12
- package/registry/calendar-heatmap.json +46 -18
- package/registry/candlestick.json +46 -18
- package/registry/chart-card.json +235 -0
- package/registry/chart.json +40 -12
- package/registry/charts-provider.json +2 -2
- package/registry/earnings-chart.json +82 -12
- package/registry/examples/chart-card/before-after.d.ts +4 -0
- package/registry/examples/chart-card/before-after.js +22 -0
- package/registry/examples/chart-card/before-after.tsx +22 -0
- package/registry/examples/chart-card/jobs-activity.d.ts +4 -0
- package/registry/examples/chart-card/jobs-activity.js +20 -0
- package/registry/examples/chart-card/jobs-activity.tsx +20 -0
- package/registry/examples/chart-card/sparse-and-empty.d.ts +4 -0
- package/registry/examples/chart-card/sparse-and-empty.js +16 -0
- package/registry/examples/chart-card/sparse-and-empty.tsx +18 -0
- package/registry/examples/chart-card/usage-donut.d.ts +4 -0
- package/registry/examples/chart-card/usage-donut.js +18 -0
- package/registry/examples/chart-card/usage-donut.tsx +18 -0
- package/registry/examples/charts-provider/french-orazaka.js +1 -1
- package/registry/examples/charts-provider/french-orazaka.tsx +1 -1
- package/registry/examples/kpi-stat/dashboard-row.d.ts +4 -0
- package/registry/examples/kpi-stat/dashboard-row.js +19 -0
- package/registry/examples/kpi-stat/dashboard-row.tsx +17 -0
- package/registry/examples/kpi-stat/single.d.ts +4 -0
- package/registry/examples/kpi-stat/single.js +11 -0
- package/registry/examples/kpi-stat/single.tsx +6 -0
- package/registry/funnel.json +46 -18
- package/registry/gauge.json +42 -14
- package/registry/geo-map.json +46 -18
- package/registry/globe.json +40 -12
- package/registry/goal-progress.json +36 -8
- package/registry/heatmap.json +46 -18
- package/registry/index.json +49 -1
- package/registry/job-throughput.json +82 -12
- package/registry/kpi-stat.json +296 -0
- package/registry/latency-chart.json +82 -12
- package/registry/line-chart.json +82 -12
- package/registry/pie-chart.json +92 -36
- package/registry/price-ticker.json +82 -12
- package/registry/radar-chart.json +46 -18
- package/registry/sankey.json +46 -18
- package/registry/scatter-chart.json +46 -18
- package/registry/sparkline.json +38 -10
- package/registry/treemap.json +40 -12
- package/dist/chunk-3CJHBJXA.js.map +0 -1
- package/dist/chunk-ARARFMNE.js.map +0 -1
- package/dist/chunk-CVWSMUUB.js.map +0 -1
- package/dist/chunk-EQLC2QVN.js.map +0 -1
- package/dist/chunk-JTKR7ZWP.js.map +0 -1
- package/dist/chunk-PBQV3B6O.js.map +0 -1
- package/dist/chunk-W5FX4TU3.js.map +0 -1
- /package/dist/{chunk-BV4DBGN7.js.map → chunk-7W4T255Q.js.map} +0 -0
- /package/dist/{chunk-W5ILLSPK.js.map → chunk-AGSSNMK5.js.map} +0 -0
- /package/dist/{chunk-VKZZY2QD.js.map → chunk-FE4LUGAE.js.map} +0 -0
- /package/dist/{chunk-ANUCSRUN.js.map → chunk-GD7TWEN3.js.map} +0 -0
- /package/dist/{chunk-SLEJDQ3A.js.map → chunk-HH65IEUV.js.map} +0 -0
- /package/dist/{chunk-OIRHLJBC.js.map → chunk-IJTI6VJD.js.map} +0 -0
- /package/dist/{chunk-WVTIKOII.js.map → chunk-IURCLBUQ.js.map} +0 -0
- /package/dist/{chunk-IKQV3NSL.js.map → chunk-KERGFVSN.js.map} +0 -0
- /package/dist/{chunk-XDDALY4C.js.map → chunk-KMQ7RANJ.js.map} +0 -0
- /package/dist/{chunk-NCIQMRV3.js.map → chunk-LLUQEK5J.js.map} +0 -0
- /package/dist/{chunk-AA5EWWYV.js.map → chunk-LZPZWBBY.js.map} +0 -0
- /package/dist/{chunk-CSSZLFLO.js.map → chunk-MRGMLDNS.js.map} +0 -0
- /package/dist/{chunk-I3D7KUGN.js.map → chunk-NLTZWJLV.js.map} +0 -0
- /package/dist/{chunk-PWMMXRMC.js.map → chunk-NV52AKHG.js.map} +0 -0
- /package/dist/{chunk-MXLITIGU.js.map → chunk-NWJ5VDN7.js.map} +0 -0
- /package/dist/{chunk-KNDHO67X.js.map → chunk-P2NK5L3B.js.map} +0 -0
- /package/dist/{chunk-4LBXEAGC.js.map → chunk-PWZHIGPO.js.map} +0 -0
- /package/dist/{chunk-L2EKYWVI.js.map → chunk-VEOJNMPF.js.map} +0 -0
- /package/dist/{chunk-C4MFZLJM.js.map → chunk-Z4T3JFNU.js.map} +0 -0
- /package/dist/{chunk-EEP7PS2L.js.map → chunk-ZF7LVQTR.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cartesian/cartesian.tsx"],"sourcesContent":["\"use client\";\n// Line, area and bar charts: one cartesian engine in plain SVG (no chart library: a line chart weighs a few kB, not\n// the 180 kB of a general engine), drawn on the --kz-* roles and the palette's CSS variables — a theme switch repaints\n// it with no JavaScript. Thin marks (2 px lines, bars ≤ 24 px with a 4 px rounded data end, a 2 px gap between stacked\n// segments), recessive grid, round ticks, selective direct labels, thresholds and markers, a crosshair tooltip and\n// the keyboard.\nimport { type KeyboardEvent, type PointerEvent, type ReactNode, useMemo, useState } from \"react\";\n\nimport { extent, normalizeSeries, type Series, stack, type Table, tabulate } from \"../core/data\";\nimport { describeSeries } from \"../core/describe\";\nimport { categoryFormatter, shareFormatter, valueFormatter } from \"../core/format\";\nimport { type ChartKind, fill } from \"../core/labels\";\nimport { bandScale, linearScale, niceDomain, pointScale, thinLabels } from \"../core/scale\";\nimport { areaPath, barPath, type Curve, linePath, type Point, segments } from \"../core/shape\";\nimport type { Accessor, CategoryFormat, Datum, Marker, SeriesSpec, Threshold, ValueFormat } from \"../core/types\";\nimport { ChartFrame, type ChartFrameProps, useSettings } from \"../web/frame\";\nimport { colorOf, cx, Legend, Tooltip } from \"../web/parts\";\n\n/** What every cartesian chart takes: rows, the category field, the series, the formats, thresholds and markers. */\nexport interface CartesianProps<T extends Datum> extends ChartFrameProps {\n /** The rows, in the order of the x axis. */\n data: readonly T[];\n /** The field (or function) of the category: a month (`\"2026-04\"`), a day, a label. Default: the row's position. */\n x?: Accessor<T, unknown>;\n /** A single series: its field. Use `series` for several. */\n y?: Accessor<T, number | null | undefined>;\n /** The name of the single `y` series (legend, tooltip, table). Default: the field's name. */\n yLabel?: string;\n /** The series to draw, each with its field and its name; the palette follows their order. */\n series?: readonly SeriesSpec<T>[];\n /** How the values are written (axis, tooltip, table, summary). Default `\"number\"`. */\n format?: ValueFormat;\n /** How the categories are written. Default: dates by their precision (`2026-04` → `Apr 2026`), text as is. */\n xFormat?: CategoryFormat;\n /** The header of the categories in the data table (`Month`). */\n xLabel?: string;\n /** Horizontal lines at a value: a goal, a payout threshold. */\n thresholds?: readonly Threshold[];\n /** Vertical markers at a category: a launch, an incident. */\n markers?: readonly Marker[];\n /** Show the legend (from two series). Default true. */\n legend?: boolean;\n /** Start the value axis at zero. Default: true for bars and areas; for lines, unless the values sit far from zero. */\n zero?: boolean;\n /** Called with the row when a point or a bar is clicked (or Enter is pressed on it). */\n onSelect?: (datum: T, index: number) => void;\n}\n\nexport interface CartesianOptions {\n readonly kind: ChartKind;\n readonly mode: \"line\" | \"area\" | \"bar\";\n readonly curve?: Curve;\n readonly stacked?: boolean;\n readonly horizontal?: boolean;\n readonly dots?: boolean;\n readonly endLabels?: boolean;\n readonly valueLabels?: boolean;\n}\n\nconst M = { top: 12, bottom: 26, right: 14 };\n\nexport function Cartesian<T extends Datum>({ props, options }: { props: CartesianProps<T>; options: CartesianOptions }) {\n const { data, x, y, yLabel, series: seriesProp, format, xFormat, xLabel, thresholds = [], markers = [], legend = true, zero, onSelect } = props;\n const { kind, mode, stacked = false, horizontal = false } = options;\n const { locale, labels } = useSettings(props);\n\n const specs = useMemo(() => normalizeSeries(seriesProp, y, yLabel), [seriesProp, y, yLabel]);\n const table = useMemo(() => tabulate(data, x, specs), [data, x, specs]);\n const fmt = useMemo(() => {\n const category = categoryFormatter(xFormat, locale);\n return {\n value: valueFormatter(format, locale, labels.noValue),\n axis: valueFormatter(format, locale, labels.noValue, true),\n category,\n share: shareFormatter(locale),\n };\n }, [format, xFormat, locale, labels.noValue]);\n\n const isEmpty = table.series.length === 0 || table.series.every((s) => s.values.every((v) => v == null));\n const summary = useMemo(\n () => (isEmpty ? labels.empty : describeSeries(table, { kind, labels, value: fmt.value, category: fmt.category, share: fmt.share, thresholds })),\n [isEmpty, table, kind, labels, fmt, thresholds],\n );\n const tableModel = useMemo(\n () => ({\n columns: [xLabel ?? labels.category, ...table.series.map((s) => s.label)],\n rows: table.categories.map((c, i) => [fmt.category(c), ...table.series.map((s) => fmt.value(s.values[i]))]),\n }),\n [table, fmt, xLabel, labels.category],\n );\n\n const [active, setActive] = useState<number | null>(null);\n const [pointer, setPointer] = useState<{ x: number; y: number } | null>(null);\n const count = table.categories.length;\n\n const colors = table.series.map((s) => colorOf(s.color, s.slot));\n const legendNode = legend ? (\n <Legend items={table.series.map((s, i) => ({ label: s.label, color: colors[i]!, shape: mode === \"bar\" ? \"square\" : \"line\", dashed: s.dashed }))} />\n ) : null;\n\n const announce = active === null ? \"\" : `${fmt.category(table.categories[active])}: ${table.series.map((s) => `${s.label} ${fmt.value(s.values[active])}`).join(\", \")}`;\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (!count) return;\n const keys: Record<string, () => number | null> = {\n ArrowRight: () => Math.min(count - 1, (active ?? -1) + 1),\n ArrowDown: () => Math.min(count - 1, (active ?? -1) + 1),\n ArrowLeft: () => Math.max(0, (active ?? count) - 1),\n ArrowUp: () => Math.max(0, (active ?? count) - 1),\n Home: () => 0,\n End: () => count - 1,\n Escape: () => null,\n };\n if (event.key === \"Enter\" && active !== null && onSelect) {\n event.preventDefault();\n onSelect(data[active]!, active);\n return;\n }\n const next = keys[event.key];\n if (!next) return;\n event.preventDefault();\n setPointer(null);\n setActive(next());\n };\n\n return (\n <ChartFrame\n kind={kind}\n frame={props}\n table={tableModel}\n summary={summary}\n isEmpty={isEmpty}\n legend={legendNode}\n announcement={announce}\n active={active !== null}\n handlers={{\n onKeyDown,\n onBlur: () => setActive(null),\n onPointerLeave: () => {\n setActive(null);\n setPointer(null);\n },\n }}\n >\n {(width, height) => (\n <Plot\n table={table}\n width={width}\n height={height}\n options={options}\n fmt={fmt}\n colors={colors}\n thresholds={thresholds}\n markers={markers}\n zero={zero ?? (mode !== \"line\" || stacked)}\n autoZero={zero === undefined && mode === \"line\"}\n stacked={stacked}\n horizontal={horizontal}\n active={active}\n pointer={pointer}\n onPointer={(index, at) => {\n setActive(index);\n setPointer(at);\n }}\n onSelect={onSelect ? (i) => onSelect(data[i]!, i) : undefined}\n labels={{ thresholdTemplate: labels.summaryThreshold, total: labels.total }}\n />\n )}\n </ChartFrame>\n );\n}\n\ninterface PlotProps {\n table: Table;\n width: number;\n height: number;\n options: CartesianOptions;\n fmt: { value: (v: number | null | undefined) => string; axis: (v: number | null | undefined) => string; category: (c: unknown) => string };\n colors: string[];\n thresholds: readonly Threshold[];\n markers: readonly Marker[];\n zero: boolean;\n autoZero: boolean;\n stacked: boolean;\n horizontal: boolean;\n active: number | null;\n pointer: { x: number; y: number } | null;\n onPointer: (index: number | null, at: { x: number; y: number } | null) => void;\n onSelect?: (index: number) => void;\n labels: { thresholdTemplate: string; total: string };\n}\n\nfunction Plot({ table, width, height, options, fmt, colors, thresholds, markers, zero, autoZero, stacked, horizontal, active, pointer, onPointer, onSelect, labels }: PlotProps) {\n const { mode, curve = \"monotone\", dots, endLabels, valueLabels } = options;\n const series = table.series;\n const count = table.categories.length;\n\n // The value domain: the data, the thresholds, zero when asked (or when the data is near it), round ticks.\n let [lo, hi] = extent(series, stacked);\n for (const t of thresholds) {\n lo = Math.min(lo, t.value);\n hi = Math.max(hi, t.value);\n }\n const keepZero = zero || (autoZero && (lo <= 0 || lo < hi * 0.5));\n if (keepZero) {\n lo = Math.min(0, lo);\n hi = Math.max(0, hi);\n }\n const valueSpan = horizontal ? width : height;\n const nice = niceDomain(lo, hi, Math.max(2, Math.min(6, Math.round(valueSpan / 70))));\n const tickTexts = nice.ticks.map((t) => fmt.axis(t));\n const categoryTexts = table.categories.map((c) => fmt.category(c));\n\n const showEnd = mode !== \"bar\" && endLabels && series.length <= 3 && width >= 360;\n const endWidth = showEnd ? Math.max(...series.map((s) => textWidth(fmt.axis(lastValue(s))))) + 14 : 0;\n\n const left = horizontal ? Math.min(width * 0.35, Math.max(...categoryTexts.map(textWidth)) + 12) : Math.max(...tickTexts.map(textWidth)) + 10;\n const right = Math.max(M.right, endWidth, horizontal ? textWidth(tickTexts[tickTexts.length - 1] ?? \"\") / 2 + 4 : 0);\n const x0 = left;\n const x1 = Math.max(x0 + 10, width - right);\n const y0 = M.top + (markers.length ? 14 : 0);\n const y1 = Math.max(y0 + 10, height - M.bottom);\n\n const value = horizontal ? linearScale(nice.domain, [x0, x1], nice.ticks) : linearScale(nice.domain, [y1, y0], nice.ticks);\n const band = bandScale(count, horizontal ? [y0, y1] : [x0, x1], count > 24 ? 0.15 : 0.3);\n const point = mode === \"bar\" ? (i: number) => band(i) + band.bandwidth / 2 : pointScale(count, [x0, x1]);\n const centerOf = (i: number) => point(i);\n const base = value(Math.max(nice.domain[0], Math.min(nice.domain[1], 0)));\n\n // Which category labels fit: about one every 64 px along x, every 18 px along y.\n const labelIndexes = horizontal ? thinLabels(count, Math.floor((y1 - y0) / 18)) : thinLabels(count, Math.max(2, Math.floor((x1 - x0) / Math.max(64, Math.max(...categoryTexts.map(textWidth)) + 16))));\n\n const stacks = stacked ? stack(series) : null;\n\n const indexAt = (px: number, py: number) => {\n if (!count) return null;\n const along = horizontal ? py : px;\n if (mode === \"bar\") return Math.max(0, Math.min(count - 1, Math.floor((along - (horizontal ? y0 : x0)) / band.step)));\n const step = count > 1 ? (x1 - x0) / (count - 1) : 1;\n return Math.max(0, Math.min(count - 1, Math.round((px - x0) / step)));\n };\n\n const onMove = (event: PointerEvent<SVGSVGElement>) => {\n const box = event.currentTarget.getBoundingClientRect();\n const px = event.clientX - box.left;\n const py = event.clientY - box.top;\n onPointer(indexAt(px, py), { x: px, y: py });\n };\n\n const marks: ReactNode[] = [];\n if (mode === \"bar\") {\n const groups = stacked ? 1 : series.length;\n const thickness = Math.min(24, Math.max(2, (band.bandwidth - (groups - 1) * 2) / groups));\n const groupWidth = thickness * groups + (groups - 1) * 2;\n series.forEach((s, k) => {\n s.values.forEach((v, i) => {\n if (v == null && !stacked) return;\n const seg = stacks?.[k]?.[i];\n const from = seg ? seg.base : 0;\n const to = seg ? seg.top : (v ?? 0);\n if (from === to) return;\n const negative = to < from;\n const isTop = !stacked || series.slice(k + 1).every((other) => {\n const ov = other.values[i] ?? 0;\n return negative ? ov >= 0 : ov <= 0;\n });\n const offset = band(i) + (band.bandwidth - groupWidth) / 2 + (stacked ? 0 : k * (thickness + 2));\n const a = value(from);\n const b = value(to);\n // The 2 px surface gap between stacked segments: each segment gives up 2 px at its far end.\n const gap = stacked && !isTop ? 2 : 0;\n const radius = isTop ? 4 : 0;\n let d: string;\n if (horizontal) {\n const start = Math.min(a, b);\n const size = Math.abs(b - a) - gap;\n d = barPath(negative ? start + gap : start, offset, Math.max(0, size), thickness, radius, true, negative);\n } else {\n const top = Math.min(a, b);\n const size = Math.abs(b - a) - gap;\n d = barPath(offset, negative ? top : top + gap, thickness, Math.max(0, size), radius, false, negative);\n }\n marks.push(\n <path\n key={`${k}-${i}`}\n d={d}\n className={cx(\"kzc-mark\", horizontal ? \"kzc-enter-growx\" : \"kzc-enter-grow\")}\n data-negative={negative || undefined}\n data-dim={active !== null && active !== i ? \"\" : undefined}\n style={{ fill: colors[k], cursor: onSelect ? \"pointer\" : undefined }}\n onClick={onSelect ? () => onSelect(i) : undefined}\n />,\n );\n if (valueLabels && series.length === 1 && count <= 16 && v != null) {\n const tip = value(to);\n marks.push(\n horizontal ? (\n <text key={`l-${i}`} x={negative ? tip - 6 : tip + 6} y={offset + thickness / 2} dominantBaseline=\"central\" textAnchor={negative ? \"end\" : \"start\"} className=\"kzc-enter-fade\">\n {fmt.axis(v)}\n </text>\n ) : (\n <text key={`l-${i}`} x={offset + thickness / 2} y={negative ? tip + 14 : tip - 6} textAnchor=\"middle\" className=\"kzc-enter-fade\">\n {fmt.axis(v)}\n </text>\n ),\n );\n }\n });\n });\n } else {\n series.forEach((s, k) => {\n const pts = s.values.map((v, i) => {\n if (v == null) return null;\n const top = stacks ? stacks[k]![i]!.top : v;\n return [centerOf(i), value(top)] as Point;\n });\n for (const seg of segments(pts)) {\n if (mode === \"area\") {\n const baseLine = stacks && k > 0 ? seg.map(([px]) => [px, value(stacks[k]![Math.round(indexAtX(px, x0, x1, count))]!.base)] as Point) : base;\n marks.push(<path key={`a-${k}-${seg[0]![0]}`} d={areaPath(seg, baseLine, curve)} className=\"kzc-area kzc-enter-fade\" style={{ fill: colors[k], opacity: stacked ? 0.5 : undefined }} />);\n }\n marks.push(\n <path\n key={`l-${k}-${seg[0]![0]}`}\n d={linePath(seg, curve)}\n pathLength={s.dashed ? undefined : 1}\n className={cx(\"kzc-line kzc-mark\", s.dashed ? \"kzc-enter-fade\" : \"kzc-enter-line\")}\n strokeDasharray={s.dashed ? \"6 4\" : undefined}\n style={{ stroke: colors[k] }}\n />,\n );\n if (dots || seg.length === 1) {\n for (const [px, py] of seg) marks.push(<circle key={`d-${k}-${px}`} cx={px} cy={py} r={4} className=\"kzc-dot kzc-enter-fade\" style={{ fill: colors[k] }} />);\n }\n }\n if (showEnd) {\n const last = [...pts].reverse().find(Boolean);\n if (last) {\n marks.push(<circle key={`e-${k}`} cx={last[0]} cy={last[1]} r={4} className=\"kzc-dot kzc-enter-fade\" style={{ fill: colors[k] }} />);\n marks.push(\n <text key={`et-${k}`} x={last[0] + 9} y={last[1]} dominantBaseline=\"central\" className=\"kzc-strong kzc-enter-fade\">\n {fmt.axis(lastValue(s))}\n </text>,\n );\n }\n }\n });\n }\n\n // Thresholds: a dashed line in the tone, its label and value on the surface.\n const thresholdMarks = thresholds.map((t, i) => {\n const at = value(t.value);\n const text = fill(labels.thresholdTemplate, { label: t.label, value: fmt.value(t.value) });\n return horizontal ? (\n <g key={`t-${i}`} data-tone={t.tone ?? \"neutral\"}>\n <line x1={at} x2={at} y1={y0} y2={y1} className=\"kzc-threshold\" />\n <text x={at + 4} y={y0 + 10} className=\"kzc-threshold-label\">\n {text}\n </text>\n </g>\n ) : (\n <g key={`t-${i}`} data-tone={t.tone ?? \"neutral\"}>\n <line x1={x0} x2={x1} y1={at} y2={at} className=\"kzc-threshold\" />\n <text x={x1} y={at - 6} textAnchor=\"end\" className=\"kzc-threshold-label\">\n {text}\n </text>\n </g>\n );\n });\n\n const markerMarks = markers.map((m, i) => {\n const index = table.categories.findIndex((c) => sameCategory(c, m.x));\n if (index < 0) return null;\n const at = centerOf(index);\n return horizontal ? null : (\n <g key={`m-${i}`} data-tone={m.tone ?? \"neutral\"}>\n <line x1={at} x2={at} y1={y0 - 4} y2={y1} className=\"kzc-threshold\" />\n <text x={at} y={y0 - 8} textAnchor={at > (x0 + x1) / 2 ? \"end\" : \"start\"} className=\"kzc-threshold-label\">\n {m.label}\n </text>\n </g>\n );\n });\n\n const cursorAt = active !== null ? centerOf(active) : null;\n const tipRows = active !== null ? series.map((s, k) => ({ label: s.label, value: fmt.value(s.values[active]), color: colors[k], shape: mode === \"bar\" ? (\"square\" as const) : (\"line\" as const) })) : [];\n const stackTotal = active !== null && stacked && series.length > 1 ? series.reduce((sum, s) => sum + (s.values[active] ?? 0), 0) : null;\n const anchor =\n active === null\n ? null\n : pointer ?? (horizontal ? { x: value(Math.max(...series.map((s) => s.values[active] ?? 0))), y: cursorAt! } : { x: cursorAt!, y: Math.min(...series.map((s) => (s.values[active] == null ? y1 : value(s.values[active]!)))) });\n\n return (\n <>\n <svg className=\"kzc-svg\" width={width} height={height} viewBox={`0 0 ${width} ${height}`} aria-hidden onPointerMove={onMove}>\n {nice.ticks.map((t, i) =>\n horizontal ? (\n <g key={t}>\n <line x1={value(t)} x2={value(t)} y1={y0} y2={y1} className={t === 0 ? \"kzc-axis\" : \"kzc-grid\"} />\n <text x={value(t)} y={y1 + 16} textAnchor=\"middle\">\n {tickTexts[i]}\n </text>\n </g>\n ) : (\n <g key={t}>\n <line x1={x0} x2={x1} y1={value(t)} y2={value(t)} className={t === 0 ? \"kzc-axis\" : \"kzc-grid\"} />\n <text x={x0 - 8} y={value(t)} textAnchor=\"end\" dominantBaseline=\"central\">\n {tickTexts[i]}\n </text>\n </g>\n ),\n )}\n {labelIndexes.map((i) =>\n horizontal ? (\n <text key={i} x={x0 - 8} y={centerOf(i)} textAnchor=\"end\" dominantBaseline=\"central\">\n {clip(categoryTexts[i]!, left - 12)}\n </text>\n ) : (\n <text key={i} x={centerOf(i)} y={y1 + 17} textAnchor={mode !== \"bar\" && i === 0 ? \"start\" : mode !== \"bar\" && i === count - 1 ? \"end\" : \"middle\"}>\n {categoryTexts[i]}\n </text>\n ),\n )}\n {cursorAt !== null && mode !== \"bar\" && <line x1={cursorAt} x2={cursorAt} y1={y0} y2={y1} className=\"kzc-cursor\" />}\n {cursorAt !== null && mode === \"bar\" && (\n <rect\n x={horizontal ? x0 : band(active!) - (band.step - band.bandwidth) / 2}\n y={horizontal ? band(active!) - (band.step - band.bandwidth) / 2 : y0}\n width={horizontal ? x1 - x0 : band.step}\n height={horizontal ? band.step : y1 - y0}\n style={{ fill: \"var(--kz-surface-2)\", opacity: 0.6 }}\n />\n )}\n <g>{marks}</g>\n {thresholdMarks}\n {markerMarks}\n {active !== null &&\n mode !== \"bar\" &&\n series.map((s, k) => {\n const v = s.values[active];\n if (v == null) return null;\n const top = stacked ? stack(series)[k]![active]!.top : v;\n return <circle key={k} cx={cursorAt!} cy={value(top)} r={5} className=\"kzc-dot\" style={{ fill: colors[k] }} />;\n })}\n </svg>\n {active !== null && anchor && (\n <Tooltip\n x={anchor.x}\n y={anchor.y}\n width={width}\n title={categoryTexts[active]}\n rows={stackTotal !== null ? [...tipRows, { label: labels.total, value: fmt.value(stackTotal) }] : tipRows}\n />\n )}\n </>\n );\n}\n\nconst lastValue = (s: Series) => [...s.values].reverse().find((v) => v != null) ?? null;\n\n/** An estimate of a label's width at 11 px (no layout on the server): the margins are sized from it. */\nexport function textWidth(text: string): number {\n return Math.ceil(text.length * 6.4);\n}\n\nfunction clip(text: string, max: number): string {\n if (textWidth(text) <= max) return text;\n const chars = Math.max(3, Math.floor(max / 6.4) - 1);\n return `${text.slice(0, chars)}…`;\n}\n\nfunction indexAtX(px: number, x0: number, x1: number, count: number): number {\n return count > 1 ? ((px - x0) / (x1 - x0)) * (count - 1) : 0;\n}\n\nfunction sameCategory(a: unknown, b: unknown): boolean {\n if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();\n return a === b || String(a) === String(b);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gauge/gauge.tsx"],"sourcesContent":["\"use client\";\n// One value against its range: a 240° arc, the value written in the middle, an optional target tick and coloured\n// zones (a quota that turns to warning, then danger). Plain SVG; exposed as a `meter` (value, range and its words).\nimport { useMemo } from \"react\";\n\nimport { valueFormatter } from \"../core/format\";\nimport { fill } from \"../core/labels\";\nimport { polar, strokeArcPath } from \"../core/shape\";\nimport type { Threshold, Tone, ValueFormat } from \"../core/types\";\nimport { ChartFrame, type ChartFrameProps, useSettings } from \"../web/frame\";\nimport { colorOf } from \"../web/parts\";\n\nexport interface GaugeZone {\n /** The zone runs from the previous one's end (or `min`) to this value. */\n readonly to: number;\n readonly tone: Tone;\n /** Its name, in the summary and the table (“Over quota”). */\n readonly label?: string;\n}\n\nexport interface GaugeProps extends Omit<ChartFrameProps, \"dataTable\" | \"exportable\"> {\n /** The value. */\n/** The value. */\n value: number;\n /** The start of the range. Default 0. */\n/** The start of the range. Default 0. */\n min?: number;\n /** The end of the range. Default 100. */\n/** The end of the range. Default 100. */\n max?: number;\n /** How the value is written. */\n/** How the value and the range are written. */\n format?: ValueFormat;\n /** The words under the value (“of 50 000 credits”). */\n caption?: string;\n /** A tick on the arc: the objective. */\n target?: Threshold;\n /** Coloured zones along the arc: the value takes the tone of the zone it is in. */\n zones?: readonly GaugeZone[];\n /** The tone of the value without zones. Default `\"accent\"`. */\n/** The tone of the value without zones. Default `\"accent\"`. */\n tone?: Tone;\n}\n\nconst START = (-120 * Math.PI) / 180;\nconst END = (120 * Math.PI) / 180;\n\n/** One figure against its range — credits used of a plan, a challenge's progress, a load. */\nexport function Gauge(props: GaugeProps) {\n const { value, min = 0, max = 100, format, caption, target, zones = [], tone = \"accent\" } = props;\n const { locale, labels } = useSettings(props);\n const fmt = useMemo(() => valueFormatter(format, locale, labels.noValue), [format, locale, labels.noValue]);\n const clamped = Math.min(max, Math.max(min, value));\n const ratio = max > min ? (clamped - min) / (max - min) : 0;\n const zone = zones.find((z) => clamped <= z.to) ?? zones[zones.length - 1];\n const color = colorOf(zone?.tone ?? tone, 1);\n const text = fmt(value);\n const summary = [\n `${labels.kinds.gauge}: ${text} (${min === 0 ? \"\" : `${fmt(min)} – `}${fmt(max)})${zone?.label ? `, ${zone.label}` : \"\"}.`,\n target ? `${fill(labels.summaryThreshold, { label: target.label, value: fmt(target.value) })}.` : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n const table = { columns: [labels.category, labels.value], rows: [[props.title, text], [\"min\", fmt(min)], [\"max\", fmt(max)], ...(target ? [[target.label, fmt(target.value)]] : [])] };\n const at = (v: number) => START + ((Math.min(max, Math.max(min, v)) - min) / (max - min || 1)) * (END - START);\n\n return (\n <ChartFrame kind=\"gauge\" frame={{ ...props, dataTable: false }} defaultHeight={180} table={table} summary={summary} isEmpty={false} navigable={false}>\n {(width, height) => {\n // The arc spans 240°: its lowest points sit at half the radius below the centre, the range labels under them.\n const radius = Math.max(20, Math.min(width / 2 - 12, (height - 30) / 1.58));\n const cx = width / 2;\n const cy = 8 + radius;\n const stroke = Math.max(8, radius * 0.16);\n let from = min;\n return (\n <div role=\"meter\" aria-label={props.title} aria-valuemin={min} aria-valuemax={max} aria-valuenow={clamped} aria-valuetext={caption ? `${text} ${caption}` : text} style={{ height: \"100%\" }}>\n <svg className=\"kzc-svg\" width={width} height={height} viewBox={`0 0 ${width} ${height}`} aria-hidden>\n <path d={strokeArcPath(cx, cy, radius, START, END)} style={{ fill: \"none\", stroke: \"var(--kz-surface-3)\", strokeWidth: stroke, strokeLinecap: \"round\" }} />\n {zones.map((z, i) => {\n const d = strokeArcPath(cx, cy, radius + stroke / 2 + 4, at(from), at(z.to));\n from = z.to;\n return <path key={i} d={d} data-tone={z.tone} style={{ fill: \"none\", stroke: \"var(--kzc-tone)\", strokeWidth: 3, opacity: 0.7 }} />;\n })}\n {ratio > 0 && (\n <path d={strokeArcPath(cx, cy, radius, START, at(clamped))} pathLength={1} className=\"kzc-line kzc-enter-line\" style={{ stroke: color, strokeWidth: stroke }} />\n )}\n {target && (\n <g data-tone={target.tone ?? \"neutral\"}>\n <line\n x1={polar(cx, cy, radius - stroke, at(target.value))[0]}\n y1={polar(cx, cy, radius - stroke, at(target.value))[1]}\n x2={polar(cx, cy, radius + stroke, at(target.value))[0]}\n y2={polar(cx, cy, radius + stroke, at(target.value))[1]}\n style={{ stroke: \"var(--kzc-text)\", strokeWidth: 2, strokeLinecap: \"round\" }}\n />\n </g>\n )}\n <text x={cx} y={cy} textAnchor=\"middle\" dominantBaseline=\"central\" className=\"kzc-strong\" style={{ fontSize: Math.max(12, Math.min(32, radius / 2.6, (radius * 1.45) / (text.length * 0.58))) }}>\n {text}\n </text>\n {caption && (\n <text x={cx} y={cy + Math.max(16, radius / 3.2)} textAnchor=\"middle\" dominantBaseline=\"central\">\n {caption}\n </text>\n )}\n <text x={polar(cx, cy, radius, START)[0]} y={polar(cx, cy, radius, START)[1] + stroke + 6} textAnchor=\"middle\">\n {fmt(min)}\n </text>\n <text x={polar(cx, cy, radius, END)[0]} y={polar(cx, cy, radius, END)[1] + stroke + 6} textAnchor=\"middle\">\n {fmt(max)}\n </text>\n </svg>\n </div>\n );\n }}\n </ChartFrame>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/web/hooks.ts","../src/web/parts.tsx","../src/web/styles.tsx","../src/web/frame.tsx","../src/web/export.ts"],"sourcesContent":["\"use client\";\n// The browser facts a chart reacts to: its width (ResizeObserver), whether it is on screen (IntersectionObserver),\n// the reader's motion preference, the theme, and whether it runs in the browser at all (SSR renders a placeholder).\nimport { type RefObject, useEffect, useState, useSyncExternalStore } from \"react\";\n\n/** The element's content width, rounded; 0 until measured (on the server, before the first layout). */\nexport function useWidth(ref: RefObject<HTMLElement | null>): number {\n const [width, setWidth] = useState(0);\n useEffect(() => {\n const el = ref.current;\n if (!el) return undefined;\n const measure = () => setWidth(Math.round(el.getBoundingClientRect().width));\n measure();\n if (typeof ResizeObserver === \"undefined\") return undefined;\n // Coalesced to one frame: a drag of a window does not redraw the chart a hundred times.\n let frame = 0;\n const observer = new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(measure);\n });\n observer.observe(el);\n return () => {\n cancelAnimationFrame(frame);\n observer.disconnect();\n };\n }, [ref]);\n return width;\n}\n\n/**\n * Whether the element is on screen (with a margin): an entrance waits for it, a loop pauses outside it. `once` keeps\n * `true` after the first sight (entrances); otherwise it follows the element (loops). True where it cannot be known.\n */\nexport function useInView(ref: RefObject<HTMLElement | null>, { once = false, margin = \"120px\" } = {}): boolean {\n // Without IntersectionObserver (an old runtime, a test DOM), everything counts as on screen.\n const [inView, setInView] = useState(() => typeof window !== \"undefined\" && typeof IntersectionObserver === \"undefined\");\n useEffect(() => {\n const el = ref.current;\n if (!el || typeof IntersectionObserver === \"undefined\") return undefined;\n const observer = new IntersectionObserver(\n ([entry]) => {\n const visible = Boolean(entry?.isIntersecting);\n setInView(visible);\n if (visible && once) observer.disconnect();\n },\n { rootMargin: margin },\n );\n observer.observe(el);\n return () => observer.disconnect();\n }, [ref, once, margin]);\n return inView;\n}\n\nconst REDUCE = \"(prefers-reduced-motion: reduce)\";\nconst subscribeMotion = (notify: () => void) => {\n if (typeof matchMedia === \"undefined\") return () => {};\n const query = matchMedia(REDUCE);\n query.addEventListener(\"change\", notify);\n return () => query.removeEventListener(\"change\", notify);\n};\n\n/** Whether the reader asked for reduced motion (false on the server: the CSS guards the entrances anyway). */\nexport function useReducedMotion(): boolean {\n return useSyncExternalStore(\n subscribeMotion,\n () => typeof matchMedia !== \"undefined\" && matchMedia(REDUCE).matches,\n () => false,\n );\n}\n\n/** Increments on every theme change (`html` class, style or `data-theme`, and the OS scheme): canvas charts re-read their colours. */\nexport function useThemeVersion(): number {\n const [version, setVersion] = useState(0);\n useEffect(() => {\n const bump = () => setVersion((v) => v + 1);\n const observer = new MutationObserver(bump);\n observer.observe(document.documentElement, { attributes: true, attributeFilter: [\"class\", \"style\", \"data-theme\"] });\n observer.observe(document.body, { attributes: true, attributeFilter: [\"class\", \"style\", \"data-theme\"] });\n const query = typeof matchMedia === \"undefined\" ? null : matchMedia(\"(prefers-color-scheme: dark)\");\n query?.addEventListener(\"change\", bump);\n return () => {\n observer.disconnect();\n query?.removeEventListener(\"change\", bump);\n };\n }, []);\n return version;\n}\n\nconst noop = () => () => {};\n/** False during the server render and the hydration pass, true after: what only the browser can draw waits for it. */\nexport function useMounted(): boolean {\n return useSyncExternalStore(\n noop,\n () => true,\n () => false,\n );\n}\n","// The small pieces every chart shares: a series' colour, the legend and the tooltip (the surface of @krizaka/ui's\n// floating elements: raised surface, border, large shadow; text in the text roles, the colour on a key beside it).\nimport type { ReactNode } from \"react\";\n\nimport type { SeriesColor, Tone } from \"../core/types\";\n\n/** Joins class names, skipping the empty ones. */\nexport const cx = (...names: (string | false | null | undefined)[]) => names.filter(Boolean).join(\" \");\n\nconst TONES: Record<Tone, string> = {\n neutral: \"var(--kz-text-secondary)\",\n accent: \"var(--kz-accent)\",\n success: \"var(--kz-success)\",\n warning: \"var(--kz-warning)\",\n danger: \"var(--kz-danger)\",\n info: \"var(--kz-info)\",\n};\n\n/** The CSS colour of a series: its own (`color`), else its palette slot, `var(--kzc-<slot>)`. */\nexport function colorOf(color: SeriesColor | undefined, slot: number): string {\n if (color === undefined) return `var(--kzc-${((slot - 1) % 8) + 1})`;\n if (typeof color === \"number\") return `var(--kzc-${color})`;\n if (color in TONES) return TONES[color as Tone];\n return color;\n}\n\nexport interface LegendItem {\n readonly label: string;\n readonly color: string;\n readonly shape?: \"square\" | \"line\";\n readonly dashed?: boolean;\n}\n\n/** The legend: a key in the series' colour beside its name in the text colour. Shown from two series. */\nexport function Legend({ items }: { items: readonly LegendItem[] }) {\n if (items.length < 2) return null;\n return (\n <ul className=\"kzc-legend\" aria-hidden>\n {items.map((item) => (\n <li key={item.label}>\n <span\n className=\"kzc-key\"\n data-shape={item.shape}\n style={{ background: item.dashed ? `repeating-linear-gradient(90deg, ${item.color} 0 4px, transparent 4px 7px)` : item.color }}\n />\n {item.label}\n </li>\n ))}\n </ul>\n );\n}\n\nexport interface TooltipRow {\n readonly label: string;\n readonly value: string;\n readonly color?: string;\n readonly shape?: \"square\" | \"line\";\n}\n\nexport interface TooltipProps {\n /** Where the pointer or the active point is, in the plot's pixels. */\n readonly x: number;\n readonly y: number;\n /** The plot's width: the tooltip flips to the left of the point past the middle. */\n readonly width: number;\n readonly title?: string;\n readonly rows: readonly TooltipRow[];\n readonly note?: ReactNode;\n}\n\n/** The rich tooltip: a title (the category), one row per series (key, name, value), an optional note. */\nexport function Tooltip({ x, y, width, title, rows, note }: TooltipProps) {\n const flip = x > width / 2;\n return (\n <div className=\"kzc-tip\" aria-hidden style={{ left: flip ? x - 12 : x + 12, top: Math.max(0, y - 12), transform: flip ? \"translateX(-100%)\" : undefined }}>\n {title && <p className=\"kzc-tip-title\">{title}</p>}\n {rows.map((row, i) => (\n <p key={i} className=\"kzc-tip-row\">\n {row.color ? <span className=\"kzc-key\" data-shape={row.shape} style={{ background: row.color }} /> : <span />}\n <span>{row.label}</span>\n <b>{row.value}</b>\n </p>\n ))}\n {note && <p className=\"kzc-tip-note\">{note}</p>}\n </div>\n );\n}\n\n/**\n * The colour of step `i` of `n` of a sequential scale: the brand hue (slot 1) mixed into the surface in OKLab, from\n * 22 % (still distinct from the surface) to 100 % — the same steps as `sequential()` for the canvas engine.\n */\nexport const stepColor = (i: number, n: number) => `color-mix(in oklab, var(--kzc-1) ${Math.round(22 + (78 * i) / Math.max(1, n - 1))}%, var(--kz-surface-1))`;\n\n/** The legend of a sequential scale: its lowest value, the steps from near the surface to the full hue, its highest. */\nexport function RampLegend({ min, max, steps, write }: { min: number; max: number; steps: number; write: (v: number) => string }) {\n return (\n <div className=\"kzc-legend\" aria-hidden>\n <span>{write(min)}</span>\n <span style={{ display: \"inline-flex\", gap: 2 }}>\n {Array.from({ length: steps }, (_, i) => (\n <span key={i} className=\"kzc-key\" style={{ background: stepColor(i, steps), width: 14 }} />\n ))}\n </span>\n <span>{write(max)}</span>\n </div>\n );\n}\n","// The charts' own stylesheet: plain CSS with `kzc-` classes on the --kz-* roles, so a chart needs nothing but the\n// tokens an app already loads (no Tailwind source to declare, no CSS import). Rendered once per document through\n// React 19's stylesheet hoisting (`<style href precedence>`, deduplicated, server-rendered in <head>).\n//\n// The palette is `light-dark()`: it follows the `color-scheme` the tokens set (`:root`/`.theme-dark` dark,\n// `html.light`/`.theme-light` light) — a theme switch repaints every chart with no JavaScript. The brand's order comes\n// from a `.brand-<id>` ancestor or the chart's own `data-brand`.\nimport { HUES, ORDERS } from \"../core/palette\";\nimport type { BrandId } from \"../core/types\";\n\nconst slots = (brand: BrandId) =>\n ORDERS[brand].map((hue, i) => `--kzc-${i + 1}:light-dark(${HUES[hue].light},${HUES[hue].dark});`).join(\"\");\n\nconst PALETTE = [\n `[data-kzc]{${slots(\"krizaka\")}--kzc-low:light-dark(${HUES.blue.light},${HUES.blue.dark});--kzc-high:light-dark(${HUES.red.light},${HUES.red.dark});}`,\n ...([\"orazaka\", \"orochia\", \"krizaka\"] as const).map((brand) => `:where(.brand-${brand}) [data-kzc]{${slots(brand)}}`),\n ...([\"orazaka\", \"orochia\", \"krizaka\"] as const).map((brand) => `[data-kzc][data-brand=${brand}]{${slots(brand)}}`),\n].join(\"\");\n\nconst tone = (name: string, value: string) => `.kzc [data-tone=${name}]{--kzc-tone:${value}}`;\n\nexport const CSS = `${PALETTE}\n.kzc{--kzc-text:var(--kz-text-primary);--kzc-text-2:var(--kz-text-secondary);--kzc-text-3:var(--kz-text-muted);--kzc-grid:var(--kz-border-subtle);--kzc-axis:var(--kz-border-default);--kzc-surface:var(--kz-surface-1);--kzc-tone:var(--kz-text-secondary);margin:0;min-width:0;display:flex;flex-direction:column;gap:8px;color:var(--kzc-text);font-family:var(--kz-font-sans,system-ui,sans-serif);font-variant-numeric:tabular-nums}\n${tone(\"neutral\", \"var(--kz-text-secondary)\")}${tone(\"accent\", \"var(--kz-accent)\")}${tone(\"success\", \"var(--kz-success)\")}${tone(\"warning\", \"var(--kz-warning)\")}${tone(\"danger\", \"var(--kz-danger)\")}${tone(\"info\", \"var(--kz-info)\")}\n.kzc-head{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:4px 12px}\n.kzc-heading{display:flex;flex-direction:column;gap:2px;min-width:0}\n.kzc-title{margin:0;font-family:var(--kz-font-display,inherit);font-size:14px;font-weight:600;line-height:20px;color:var(--kzc-text)}\n.kzc-desc{margin:0;font-size:13px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-tools{display:flex;flex-wrap:wrap;gap:4px}\n.kzc-btn{appearance:none;display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 10px;border:1px solid var(--kz-border-default);border-radius:var(--kz-radius-md,8px);background:transparent;color:var(--kzc-text-2);font:inherit;font-size:12px;font-weight:500;cursor:pointer;transition:background-color .15s,color .15s}\n.kzc-btn:hover{background:var(--kz-surface-2);color:var(--kzc-text)}\n.kzc-btn:focus-visible,.kzc-plot:focus-visible{outline:2px solid var(--kz-ring);outline-offset:2px}\n.kzc-btn[aria-pressed=true]{background:var(--kz-surface-3);color:var(--kzc-text)}\n.kzc-plot{position:relative;width:100%;border-radius:var(--kz-radius-md,8px);outline:none}\n.kzc-plot svg{display:block;overflow:visible}\n.kzc-svg text{fill:var(--kzc-text-2);font-size:11px;font-family:inherit}\n.kzc-svg .kzc-strong{fill:var(--kzc-text);font-weight:600}\n.kzc-grid{stroke:var(--kzc-grid);stroke-width:1;shape-rendering:crispEdges}\n.kzc-axis{stroke:var(--kzc-axis);stroke-width:1;shape-rendering:crispEdges}\n.kzc-threshold{stroke:var(--kzc-tone);stroke-width:1.5;stroke-dasharray:6 4}\n.kzc-threshold-label{fill:var(--kzc-text)!important;font-weight:600;paint-order:stroke;stroke:var(--kzc-surface);stroke-width:3px;stroke-linejoin:round}\n.kzc-cursor{stroke:var(--kzc-axis);stroke-width:1}\n.kzc-line{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}\n.kzc-area{stroke:none;opacity:.14}\n.kzc-dot{stroke:var(--kzc-surface);stroke-width:2}\n.kzc-mark{transition:opacity .15s}\n.kzc[data-active] .kzc-mark[data-dim]{opacity:.35}\n.kzc-legend{display:flex;flex-wrap:wrap;gap:4px 14px;margin:0;padding:0;list-style:none;font-size:12px;color:var(--kzc-text-2)}\n.kzc-legend li{display:inline-flex;align-items:center;gap:6px}\n.kzc-key{width:10px;height:10px;border-radius:3px;flex:none}\n.kzc-key[data-shape=line]{height:3px;border-radius:2px;width:14px}\n.kzc-tip{position:absolute;z-index:2;pointer-events:none;min-width:140px;max-width:260px;padding:8px 10px;border:1px solid var(--kz-border-default);border-radius:var(--kz-radius-lg,10px);background:var(--kz-surface-2);color:var(--kzc-text);box-shadow:var(--kz-shadow-lg);font-size:12px;line-height:18px}\n.kzc-tip-title{margin:0 0 4px;font-weight:600;color:var(--kzc-text)}\n.kzc-tip-row{display:flex;align-items:center;gap:8px;margin:0}\n.kzc-tip-row span:nth-child(2){flex:1;color:var(--kzc-text-2)}\n.kzc-tip-row b{font-weight:600}\n.kzc-tip-note{margin:4px 0 0;color:var(--kzc-text-3)}\n.kzc-summary{margin:0;font-size:12px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-sr{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}\n.kzc-table-wrap{max-height:320px;overflow:auto;border:1px solid var(--kz-border-subtle);border-radius:var(--kz-radius-md,8px)}\n.kzc-table{width:100%;border-collapse:collapse;font-size:12px}\n.kzc-table caption{padding:8px 10px;text-align:left;font-weight:600;color:var(--kzc-text)}\n.kzc-table th,.kzc-table td{padding:6px 10px;border-top:1px solid var(--kz-border-subtle);text-align:right;white-space:nowrap}\n.kzc-table th[scope=row],.kzc-table thead th:first-child{text-align:left;font-weight:500;color:var(--kzc-text)}\n.kzc-table thead th{position:sticky;top:0;background:var(--kz-surface-1);color:var(--kzc-text-2);font-weight:500}\n.kzc-state{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:16px;text-align:center;font-size:13px;color:var(--kzc-text-2);border:1px dashed var(--kz-border-default);border-radius:var(--kz-radius-lg,10px)}\n.kzc-state[data-state=error]{color:var(--kz-danger-text,var(--kzc-text))}\n.kzc-skeleton{position:absolute;inset:0;display:flex;align-items:flex-end;gap:6%;padding:12px 4% 24px;border-radius:var(--kz-radius-lg,10px);overflow:hidden}\n.kzc-skeleton i{flex:1;border-radius:4px 4px 0 0;background:var(--kz-surface-2)}\n.kzc-live{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}\n.kzc-host{position:absolute;inset:0}\n.kzc-host>div{border-radius:inherit}\n.kzc-kpi{display:inline-flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;margin-top:4px}\n.kzc-kpi-value{font-family:var(--kz-font-display,inherit);font-size:24px;line-height:30px;font-weight:800;letter-spacing:-.01em;color:var(--kzc-text)}\n.kzc-kpi-label{font-size:13px;color:var(--kzc-text-2)}\n.kzc-kpi-delta{display:inline-flex;align-items:center;gap:4px;font-size:13px;font-weight:600;color:var(--kzc-text)}\n.kzc-kpi-delta svg{width:12px;height:12px;flex:none;color:var(--kzc-tone)}\n.kzc-meter{position:relative;height:10px;border-radius:999px;background:var(--kz-surface-3);overflow:hidden;--kzc-tone:var(--kz-accent)}\n.kzc-meter>i{position:absolute;inset:0 auto 0 0;border-radius:inherit;background:var(--kzc-tone);transition:width .6s var(--kz-ease,ease-out)}\n.kzc-meter[data-tone=warning]{--kzc-tone:var(--kz-warning)}.kzc-meter[data-tone=danger]{--kzc-tone:var(--kz-danger)}\n.kzc-row{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px;margin:0;font-size:12px;line-height:18px;color:var(--kzc-text-2)}\n.kzc-row b{font-weight:600;color:var(--kzc-text)}\n@media (prefers-reduced-motion:no-preference){\n.kzc-skeleton i{animation:kzc-pulse 1.6s ease-in-out infinite}\n.kzc[data-inview] .kzc-enter-line{stroke-dasharray:1;stroke-dashoffset:1;animation:kzc-draw .9s var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-fade{opacity:0;animation:kzc-fade .6s .3s var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-grow{transform:scaleY(0);transform-box:fill-box;transform-origin:bottom;animation:kzc-grow .6s var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-grow[data-negative]{transform-origin:top}\n.kzc[data-inview] .kzc-enter-growx{transform:scaleX(0);transform-box:fill-box;transform-origin:left;animation:kzc-growx .6s var(--kz-ease,ease-out) forwards}\n.kzc[data-inview] .kzc-enter-growx[data-negative]{transform-origin:right}\n.kzc[data-inview] .kzc-enter-pop{opacity:0;transform:scale(.92);transform-box:view-box;transform-origin:center;animation:kzc-pop .6s var(--kz-ease,ease-out) forwards}\n.kzc:not([data-inview]) .kzc-enter-line,.kzc:not([data-inview]) .kzc-enter-fade,.kzc:not([data-inview]) .kzc-enter-grow,.kzc:not([data-inview]) .kzc-enter-growx,.kzc:not([data-inview]) .kzc-enter-pop{visibility:hidden}\n.kzc[data-live] *{animation:none!important}\n.kzc[data-live] .kzc-enter-line{stroke-dasharray:none;stroke-dashoffset:0}\n.kzc[data-live] :is(.kzc-enter-fade,.kzc-enter-grow,.kzc-enter-growx,.kzc-enter-pop){opacity:1;transform:none;visibility:visible}\n}\n@keyframes kzc-draw{to{stroke-dashoffset:0}}\n@keyframes kzc-fade{to{opacity:1}}\n@keyframes kzc-grow{to{transform:scaleY(1)}}\n@keyframes kzc-growx{to{transform:scaleX(1)}}\n@keyframes kzc-pop{to{opacity:1;transform:none}}\n@keyframes kzc-pulse{50%{opacity:.5}}\n@media (forced-colors:active){.kzc-line{stroke:CanvasText}.kzc-key{forced-color-adjust:none}}\n`.replace(/\\n/g, \"\");\n\n/** The stylesheet, once per document (React 19 hoists and deduplicates it, on the server too). */\nexport function ChartStyles() {\n return (\n <style href=\"krizaka-charts\" precedence=\"default\">\n {CSS}\n </style>\n );\n}\n","\"use client\";\n// The frame every web chart is drawn in — where the \"better than the industry\" promises live, once for all of them:\n// - a title (the accessible name) and a description; a written summary (min, max, trend) read by screen readers, or\n// shown (`summary=\"visible\"`);\n// - the data table, always in the page for assistive technology (visually hidden), shown by \"Show data\";\n// - one tab stop on the plot (`role=\"group\"`, roledescription \"chart\"), the arrow keys walking its points, each one\n// announced in a polite live region;\n// - loading (a chart skeleton), empty and error states, at the chart's own height;\n// - responsive (ResizeObserver) and SSR without layout shift: the server renders the frame, the summary, the table and\n// a placeholder of the exact height; the browser draws once it knows the width;\n// - an entrance once on screen, none under reduced motion, none for live data;\n// - export to PNG, SVG and CSV.\nimport { type CSSProperties, type KeyboardEvent, type PointerEvent, type ReactNode, type RefObject, useCallback, useId, useMemo, useRef, useState } from \"react\";\n\nimport type { ChartKind, ChartLabels } from \"../core/labels\";\nimport { fill } from \"../core/labels\";\nimport type { BrandId, Locale } from \"../core/types\";\nimport { type ChartsSettings, useChartSettings } from \"./context\";\nimport { download, fileName, serializeSvg, svgToPng, toCsv } from \"./export\";\nimport { useInView, useMounted, useWidth } from \"./hooks\";\nimport { cx } from \"./parts\";\nimport { ChartStyles } from \"./styles\";\n\nexport type ExportFormat = \"png\" | \"svg\" | \"csv\";\n\n/** The props every web chart takes, on top of its data. */\nexport interface ChartFrameProps extends ChartsSettings {\n /** What the chart shows, in a few words: its accessible name, and its heading unless `hideTitle`. */\n title: string;\n /** A sentence under the title: the period, the unit, the source. */\n description?: ReactNode;\n /** Visually hide the title (it stays the chart's accessible name): a card that already has its heading. */\n hideTitle?: boolean;\n /** The height of the plot in pixels. Default 280 (a sparkline: 32). */\n height?: number;\n /** The data is on its way: a skeleton of the chart, announced once. */\n loading?: boolean;\n /** The data could not be loaded: `true` says the default words, a node says yours (a retry button…). */\n error?: boolean | ReactNode;\n /** What to show when there is nothing to draw (default: the `empty` label). An `EmptyState` of @krizaka/ui fits. */\n empty?: ReactNode;\n /** The written summary: read by screen readers only (`\"hidden\"`, default), or shown under the chart (`\"visible\"`). */\n summary?: \"hidden\" | \"visible\";\n /** Your own summary instead of the generated one (still read first by screen readers). */\n summaryText?: string;\n /** The \"Show data\" button (the table is in the page for screen readers either way). Default true. */\n dataTable?: boolean;\n /** Export buttons: `true` for PNG, SVG and CSV, or the formats you want. */\n exportable?: boolean | readonly ExportFormat[];\n /** Streaming data (a job queue, an auction): no entrance on updates, no announcement of every new point. */\n live?: boolean;\n /** The id of the figure. */\n id?: string;\n /** A class on the figure (layout: margins, grid placement). */\n className?: string;\n /** Inline style on the figure (layout only: colours come from the tokens). */\n style?: CSSProperties;\n}\n\nexport interface TableModel {\n /** The header of each column; the first one names the categories. */\n readonly columns: readonly string[];\n /** The rows, already written (formatted values). The first cell is the row's header. */\n readonly rows: readonly (readonly string[])[];\n}\n\nexport interface PlotHandlers {\n onKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;\n onPointerMove?: (event: PointerEvent<HTMLDivElement>) => void;\n onPointerLeave?: () => void;\n onBlur?: () => void;\n}\n\ninterface FrameInternals {\n readonly kind: ChartKind;\n readonly frame: ChartFrameProps;\n readonly defaultHeight?: number;\n readonly table: TableModel;\n readonly summary: string;\n readonly isEmpty: boolean;\n /** Draws the plot at the measured width (browser only). */\n readonly children: (width: number, height: number) => ReactNode;\n readonly legend?: ReactNode;\n readonly tooltip?: ReactNode;\n readonly announcement?: string;\n readonly handlers?: PlotHandlers;\n /** Whether the plot has points to walk with the keyboard. */\n readonly navigable?: boolean;\n /** A canvas engine exports its own image; the SVG charts are serialised. */\n readonly exportImage?: (format: \"png\" | \"svg\") => Promise<string | null> | string | null;\n /** Draw on the server too (a sparkline of a known width). */\n readonly ssrWidth?: number;\n /** Whether something is drawn on top of the plot (an active point): dims the other marks. */\n readonly active?: boolean;\n readonly plotRef?: RefObject<HTMLDivElement | null>;\n readonly compact?: boolean;\n /** Something the chart needs is still loading (the world's countries): `data-pending` until it is there. */\n readonly pending?: boolean;\n}\n\n/** The settings of a chart (`useChartSettings` re-exported for the charts). */\nexport function useSettings(frame: ChartFrameProps): { locale: Locale; brand?: BrandId; labels: ChartLabels } {\n return useChartSettings(frame);\n}\n\nexport function ChartFrame({\n kind,\n frame,\n defaultHeight = 280,\n table,\n summary,\n isEmpty,\n children,\n legend,\n tooltip,\n announcement,\n handlers,\n navigable = true,\n exportImage,\n ssrWidth,\n active,\n plotRef,\n compact,\n pending,\n}: FrameInternals) {\n const { title, description, hideTitle, height = defaultHeight, loading, error, empty, summaryText, dataTable = true, exportable, live, id, className, style } = frame;\n const { brand, labels } = useChartSettings(frame);\n const uid = useId();\n const ids = { title: `${uid}-t`, summary: `${uid}-s`, hint: `${uid}-h`, table: `${uid}-d` };\n const ownRef = useRef<HTMLDivElement | null>(null);\n const ref = plotRef ?? ownRef;\n const figureRef = useRef<HTMLElement | null>(null);\n const mounted = useMounted();\n const measured = useWidth(ref);\n const width = mounted ? measured : 0;\n const inView = useInView(figureRef, { once: true });\n const [showTable, setShowTable] = useState(false);\n\n const formats = useMemo<readonly ExportFormat[]>(() => (exportable === true ? [\"png\", \"svg\", \"csv\"] : exportable || []), [exportable]);\n const state = error ? \"error\" : loading ? \"loading\" : isEmpty ? \"empty\" : \"ready\";\n\n const doExport = useCallback(\n async (format: ExportFormat) => {\n if (format === \"csv\") {\n download(fileName(title, \"csv\"), new Blob([`\\uFEFF${toCsv([table.columns, ...table.rows])}`], { type: \"text/csv;charset=utf-8\" }));\n return;\n }\n if (exportImage) {\n const url = await exportImage(format);\n if (url) download(fileName(title, format), url);\n return;\n }\n const svg = ref.current?.querySelector<SVGSVGElement>(\"svg.kzc-svg\");\n if (!svg) return;\n const background = getComputedStyle(figureRef.current ?? document.body).getPropertyValue(\"--kz-surface-1\").trim() || \"#fff\";\n const surface = resolveColor(background, figureRef.current);\n const markup = serializeSvg(svg, surface);\n if (format === \"svg\") download(fileName(title, \"svg\"), new Blob([markup], { type: \"image/svg+xml\" }));\n else {\n const box = svg.getBoundingClientRect();\n download(fileName(title, \"png\"), await svgToPng(markup, box.width, box.height, surface));\n }\n },\n [exportImage, ref, table, title],\n );\n\n const drawWidth = width || ssrWidth || 0;\n let plot: ReactNode;\n if (state === \"loading\") {\n plot = (\n <div className=\"kzc-skeleton\" role=\"status\">\n <span className=\"kzc-sr\">{labels.loading}</span>\n {!compact && [0.55, 0.8, 0.45, 0.95, 0.7, 0.6].map((h, i) => <i key={i} aria-hidden style={{ height: `${h * 100}%` }} />)}\n </div>\n );\n } else if (state === \"error\") {\n plot = (\n <div className=\"kzc-state\" data-state=\"error\" role=\"alert\">\n {error === true ? labels.error : error}\n </div>\n );\n } else if (state === \"empty\") {\n plot = empty ?? (\n <div className=\"kzc-state\" data-state=\"empty\" role=\"status\">\n {labels.empty}\n </div>\n );\n } else if (drawWidth > 0) {\n plot = children(drawWidth, height);\n } else {\n // SSR and the first browser pass: a placeholder of the exact height (no layout shift), the data already in the table.\n plot = !compact && (\n <div className=\"kzc-skeleton\" aria-hidden>\n {[0.55, 0.8, 0.45, 0.95, 0.7, 0.6].map((h, i) => (\n <i key={i} style={{ height: `${h * 100}%` }} />\n ))}\n </div>\n );\n }\n\n const ready = state === \"ready\" && drawWidth > 0;\n return (\n <figure\n ref={figureRef}\n id={id}\n className={cx(\"kzc\", className)}\n style={style}\n data-kzc=\"\"\n data-kind={kind}\n data-state={state}\n data-brand={brand}\n data-inview={inView || undefined}\n data-live={live || undefined}\n data-active={active || undefined}\n data-pending={pending || (state === \"ready\" && drawWidth === 0) || undefined}\n aria-labelledby={ids.title}\n >\n <ChartStyles />\n {(\n <div className={!hideTitle || description || (!compact && (dataTable || formats.length > 0)) ? \"kzc-head\" : \"kzc-sr\"}>\n <div className=\"kzc-heading\">\n <p id={ids.title} className={hideTitle ? \"kzc-sr\" : \"kzc-title\"}>\n {title}\n </p>\n {description && <p className=\"kzc-desc\">{description}</p>}\n </div>\n {(dataTable || formats.length > 0) && !compact && state !== \"loading\" && state !== \"error\" && (\n <div className=\"kzc-tools\">\n {dataTable && !isEmpty && (\n <button type=\"button\" className=\"kzc-btn\" aria-expanded={showTable} aria-controls={ids.table} onClick={() => setShowTable((v) => !v)}>\n {showTable ? labels.hideData : labels.showData}\n </button>\n )}\n {!isEmpty &&\n formats.map((format) => (\n <button key={format} type=\"button\" className=\"kzc-btn\" onClick={() => void doExport(format)} aria-label={`${title} — ${format.toUpperCase()}`}>\n {format === \"png\" ? labels.exportPng : format === \"svg\" ? labels.exportSvg : labels.exportCsv}\n </button>\n ))}\n </div>\n )}\n </div>\n )}\n {legend}\n <div\n ref={ref}\n className=\"kzc-plot\"\n style={{ height }}\n {...(ready\n ? {\n role: \"group\",\n \"aria-roledescription\": labels.roleDescription,\n \"aria-labelledby\": ids.title,\n \"aria-describedby\": navigable ? `${ids.summary} ${ids.hint}` : ids.summary,\n tabIndex: navigable ? 0 : undefined,\n ...handlers,\n }\n : {})}\n >\n {plot}\n {ready && tooltip}\n </div>\n <p id={ids.summary} className={frame.summary === \"visible\" ? \"kzc-summary\" : \"kzc-sr\"}>\n {summaryText ?? summary}\n </p>\n {ready && navigable && (\n <span id={ids.hint} className=\"kzc-sr\">\n {labels.keyboardHint}\n </span>\n )}\n <div className=\"kzc-live\" aria-live=\"polite\" aria-atomic=\"true\">\n {live ? \"\" : announcement}\n </div>\n {!isEmpty && (\n <div id={ids.table} className={showTable ? \"kzc-table-wrap\" : \"kzc-sr\"}>\n <table className=\"kzc-table\">\n <caption>{fill(labels.tableCaption, { title })}</caption>\n <thead>\n <tr>\n {table.columns.map((column, i) => (\n <th key={i} scope=\"col\">\n {column}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {table.rows.map((row, r) => (\n <tr key={r}>\n {row.map((cell, c) =>\n c === 0 ? (\n <th key={c} scope=\"row\">\n {cell}\n </th>\n ) : (\n <td key={c}>{cell}</td>\n ),\n )}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )}\n </figure>\n );\n}\n\n/** A CSS colour (a `var(--…)`, `light-dark()`, `hsl()`…) as the browser resolves it on `scope`: `rgb(r, g, b)`. */\nexport function resolveColor(color: string, scope: Element | null): string {\n if (typeof document === \"undefined\") return color;\n const probe = document.createElement(\"span\");\n probe.style.color = color;\n probe.style.display = \"none\";\n (scope ?? document.body).appendChild(probe);\n const resolved = getComputedStyle(probe).color;\n probe.remove();\n return resolved || color;\n}\n","// Export a chart as a file: CSV (the data table, as the reader sees it), SVG (the drawing, its colours resolved — a\n// file has no --kz-* variables) and PNG (the SVG rasterised at twice the size).\n\n/** One CSV line per row; cells quoted when they hold a separator, a quote or a line break. */\nexport function toCsv(rows: readonly (readonly string[])[]): string {\n const cell = (value: string) => (/[\",\\n;]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value);\n return rows.map((row) => row.map(cell).join(\",\")).join(\"\\n\");\n}\n\n/** A file name from a title: `Earnings, last 6 months` → `earnings-last-6-months`. */\nexport function fileName(title: string | undefined, extension: string): string {\n const base =\n (title ?? \"chart\")\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\") || \"chart\";\n return `${base}.${extension}`;\n}\n\nexport function download(name: string, content: Blob | string): void {\n const url = typeof content === \"string\" ? content : URL.createObjectURL(content);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = name;\n link.click();\n if (typeof content !== \"string\") setTimeout(() => URL.revokeObjectURL(url), 1000);\n}\n\nconst PROPS = [\"fill\", \"stroke\", \"stroke-width\", \"stroke-dasharray\", \"opacity\", \"fill-opacity\", \"font-size\", \"font-weight\", \"font-family\"] as const;\n\n/** A standalone copy of a drawn SVG: every colour and text style the CSS gave it, written on the element. */\nexport function serializeSvg(svg: SVGSVGElement, background?: string): string {\n const clone = svg.cloneNode(true) as SVGSVGElement;\n const source = [svg, ...svg.querySelectorAll(\"*\")];\n const target = [clone, ...clone.querySelectorAll(\"*\")];\n source.forEach((el, i) => {\n const style = getComputedStyle(el);\n const out = target[i] as SVGElement;\n for (const prop of PROPS) {\n const value = style.getPropertyValue(prop);\n if (value) out.style.setProperty(prop, value);\n }\n // The entrance animation's dash would export a line half drawn.\n out.style.removeProperty(\"stroke-dasharray\");\n if (el.getAttribute(\"stroke-dasharray\")) out.style.setProperty(\"stroke-dasharray\", el.getAttribute(\"stroke-dasharray\")!);\n });\n clone.setAttribute(\"xmlns\", \"http://www.w3.org/2000/svg\");\n if (background) clone.style.setProperty(\"background\", background);\n return new XMLSerializer().serializeToString(clone);\n}\n\n/** The SVG drawn on a canvas at `scale` × its size, as a PNG data URL. */\nexport function svgToPng(markup: string, width: number, height: number, background: string, scale = 2): Promise<string> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n image.onload = () => {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width * scale;\n canvas.height = height * scale;\n const context = canvas.getContext(\"2d\");\n if (!context) return reject(new Error(\"No 2D canvas\"));\n context.fillStyle = background;\n context.fillRect(0, 0, canvas.width, canvas.height);\n context.drawImage(image, 0, 0, canvas.width, canvas.height);\n resolve(canvas.toDataURL(\"image/png\"));\n return undefined;\n };\n image.onerror = () => reject(new Error(\"The SVG could not be rasterised\"));\n image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(markup)}`;\n });\n}\n"],"mappings":"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","names":["jsx","useState","jsx","jsxs","useState"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pie/pie-chart.tsx"],"sourcesContent":["\"use client\";\n// Part of a whole: a pie, or a donut with the total in its hole. Plain SVG. The slices are sorted largest first and\n// folded into “Other” past `maxSlices` (a ninth hue is never invented); a 2 px surface gap separates them; the legend\n// carries each part's value and share, so the colour is never the only way to read it.\nimport { type KeyboardEvent, useMemo, useState } from \"react\";\n\nimport { read } from \"../core/data\";\nimport { describeParts } from \"../core/describe\";\nimport { shareFormatter, valueFormatter } from \"../core/format\";\nimport { arcPath, polar } from \"../core/shape\";\nimport type { Accessor, Datum, SeriesColor, ValueFormat } from \"../core/types\";\nimport { ChartFrame, type ChartFrameProps, useSettings } from \"../web/frame\";\nimport { colorOf, Tooltip } from \"../web/parts\";\n\nexport interface PieChartProps<T extends Datum> extends ChartFrameProps {\n /** One row per part. */\n data: readonly T[];\n /** The field (or function) naming the part. */\n label: Accessor<T, string>;\n /** The field (or function) of its amount (≥ 0). */\n value: Accessor<T, number>;\n /** A part's own colour (a slot, a tone or a CSS colour); default: the palette in order of size. */\n color?: Accessor<T, SeriesColor | undefined>;\n /** How the amounts are written. */\n format?: ValueFormat;\n /** A ring rather than a pie: the total (or `centerValue`) is written in its hole. */\n donut?: boolean;\n /** The words under the number in the hole of a donut (“Total credits”). */\n centerLabel?: string;\n /** The number in the hole, written already. Default: the total. */\n centerValue?: string;\n /** At most this many slices; the rest fold into one, named `otherLabel`. Default 6. */\n maxSlices?: number;\n /** The name of the folded slice. Default “Other”. */\n otherLabel?: string;\n /** Called with the row when a slice is clicked (or Enter is pressed on it). */\n onSelect?: (datum: T, index: number) => void;\n /** The header of the parts in the data table. */\n labelHeader?: string;\n /** The header of the amounts in the data table. */\n valueHeader?: string;\n}\n\ninterface Slice<T> {\n readonly label: string;\n readonly value: number;\n readonly color: string;\n readonly datum?: T;\n readonly index: number;\n}\n\nexport function PieChart<T extends Datum>(props: PieChartProps<T>) {\n const { data, label, value, color, format, donut = false, centerLabel, centerValue, maxSlices = 6, otherLabel = \"Other\", onSelect, labelHeader, valueHeader } = props;\n const { locale, labels } = useSettings(props);\n const fmt = useMemo(() => ({ value: valueFormatter(format, locale, labels.noValue), share: shareFormatter(locale) }), [format, locale, labels.noValue]);\n\n const slices = useMemo<Slice<T>[]>(() => {\n const rows = data\n .map((datum, index) => ({ datum, index, label: read(label, datum, index), value: Math.max(0, Number(read(value, datum, index)) || 0) }))\n .sort((a, b) => b.value - a.value);\n const kept = rows.length > maxSlices ? rows.slice(0, maxSlices - 1) : rows;\n const out: Slice<T>[] = kept.map((row, i) => ({ ...row, color: colorOf(color ? read(color, row.datum, row.index) : undefined, i + 1) }));\n if (rows.length > maxSlices) {\n const rest = rows.slice(maxSlices - 1).reduce((sum, row) => sum + row.value, 0);\n out.push({ label: otherLabel, value: rest, color: \"var(--kz-text-muted)\", index: -1 });\n }\n return out;\n }, [data, label, value, color, maxSlices, otherLabel]);\n\n const total = slices.reduce((sum, s) => sum + s.value, 0);\n const isEmpty = total <= 0;\n const kind = donut ? \"donut\" : \"pie\";\n const summary = useMemo(() => (isEmpty ? labels.empty : describeParts(kind, slices, { labels, value: fmt.value, share: fmt.share })), [isEmpty, kind, slices, labels, fmt]);\n const table = useMemo(\n () => ({\n columns: [labelHeader ?? labels.category, valueHeader ?? labels.value, \"%\"],\n rows: [...slices.map((s) => [s.label, fmt.value(s.value), fmt.share(total ? s.value / total : 0)]), [labels.total, fmt.value(total), fmt.share(1)]],\n }),\n [slices, fmt, total, labels, labelHeader, valueHeader],\n );\n\n const [active, setActive] = useState<number | null>(null);\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const n = slices.length;\n const moves: Record<string, () => number | null> = {\n ArrowRight: () => ((active ?? -1) + 1) % n,\n ArrowDown: () => ((active ?? -1) + 1) % n,\n ArrowLeft: () => ((active ?? 0) - 1 + n) % n,\n ArrowUp: () => ((active ?? 0) - 1 + n) % n,\n Home: () => 0,\n End: () => n - 1,\n Escape: () => null,\n };\n if (event.key === \"Enter\" && active !== null && onSelect) {\n const slice = slices[active]!;\n if (slice.datum) onSelect(slice.datum, slice.index);\n return;\n }\n const move = moves[event.key];\n if (!move) return;\n event.preventDefault();\n setActive(move());\n };\n const say = (s: Slice<T>) => `${s.label}: ${fmt.value(s.value)} (${fmt.share(total ? s.value / total : 0)})`;\n\n const legend = (\n <ul className=\"kzc-legend\" aria-hidden>\n {slices.map((s) => (\n <li key={s.label}>\n <span className=\"kzc-key\" style={{ background: s.color }} />\n {s.label} · {fmt.share(total ? s.value / total : 0)}\n </li>\n ))}\n </ul>\n );\n\n return (\n <ChartFrame\n kind={kind}\n frame={props}\n defaultHeight={240}\n table={table}\n summary={summary}\n isEmpty={isEmpty}\n legend={isEmpty ? null : legend}\n announcement={active === null ? \"\" : say(slices[active]!)}\n active={active !== null}\n handlers={{ onKeyDown, onBlur: () => setActive(null), onPointerLeave: () => setActive(null) }}\n >\n {(width, height) => {\n const radius = Math.max(10, Math.min(width, height) / 2 - 6);\n const inner = donut ? radius * 0.64 : 0;\n const cx = width / 2;\n const cy = height / 2;\n let angle = 0;\n const arcs = slices.map((s, i) => {\n const sweep = total ? (s.value / total) * Math.PI * 2 : 0;\n const start = angle;\n angle += sweep;\n return { s, i, start, end: angle };\n });\n const current = active !== null ? arcs[active] : null;\n const mid = current ? (current.start + current.end) / 2 : 0;\n const [tx, ty] = current ? polar(cx, cy, (radius + inner) / 2 + (donut ? 0 : radius * 0.2), mid) : [0, 0];\n return (\n <>\n <svg className=\"kzc-svg\" width={width} height={height} viewBox={`0 0 ${width} ${height}`} aria-hidden>\n <g className=\"kzc-enter-pop\">\n {arcs.map(({ s, i, start, end }) => {\n const lift = active === i ? 4 : 0;\n const [dx, dy] = lift ? polar(0, 0, lift, (start + end) / 2) : [0, 0];\n return (\n <path\n key={s.label}\n d={arcPath(cx + dx, cy + dy, inner, radius, start, end)}\n className=\"kzc-mark\"\n data-dim={active !== null && active !== i ? \"\" : undefined}\n style={{ fill: s.color, stroke: \"var(--kzc-surface)\", strokeWidth: slices.length > 1 ? 2 : 0, strokeLinejoin: \"round\", cursor: onSelect ? \"pointer\" : undefined }}\n onPointerEnter={() => setActive(i)}\n onClick={onSelect && s.datum ? () => onSelect(s.datum!, s.index) : undefined}\n />\n );\n })}\n </g>\n {donut && (\n <g className=\"kzc-enter-fade\">\n <text x={cx} y={cy - (centerLabel ? 6 : 0)} textAnchor=\"middle\" dominantBaseline=\"central\" className=\"kzc-strong\" style={{ fontSize: Math.max(14, Math.min(26, inner / 3)) }}>\n {centerValue ?? fmt.value(total)}\n </text>\n {centerLabel && (\n <text x={cx} y={cy + Math.max(12, Math.min(20, inner / 4))} textAnchor=\"middle\" dominantBaseline=\"central\">\n {centerLabel}\n </text>\n )}\n </g>\n )}\n </svg>\n {current && <Tooltip x={tx} y={ty} width={width} title={current.s.label} rows={[{ label: fmt.share(total ? current.s.value / total : 0), value: fmt.value(current.s.value), color: current.s.color }]} />}\n </>\n );\n }}\n </ChartFrame>\n );\n}\n\n/** A pie with a hole: the total (or `centerValue`) and `centerLabel` in it. */\nexport function DonutChart<T extends Datum>(props: Omit<PieChartProps<T>, \"donut\">) {\n return <PieChart {...props} donut />;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/data.ts"],"sourcesContent":["// From the app's rows to what a chart draws: the categories (x) and, per series, one value per category. Missing\n// values stay `null` (a gap), never a zero.\nimport type { Accessor, Datum, SeriesColor, SeriesSpec, SeriesSummary } from \"./types\";\n\n/** Reads a field or calls the accessor. */\nexport function read<T, V>(accessor: Accessor<T, V>, datum: T, index: number): V {\n return typeof accessor === \"function\" ? accessor(datum, index) : (datum[accessor as keyof T] as V);\n}\n\nexport interface Series {\n readonly id: string;\n readonly label: string;\n readonly values: readonly (number | null)[];\n readonly color?: SeriesColor;\n readonly dashed?: boolean;\n /** Its palette slot (1–8), in the order the series were given: a series keeps its colour whatever is filtered. */\n readonly slot: number;\n}\n\nexport interface Table {\n readonly categories: readonly unknown[];\n readonly series: readonly Series[];\n}\n\nconst toNumber = (value: unknown): number | null => (typeof value === \"number\" && Number.isFinite(value) ? value : null);\n\n/** `series`, or a single series from `y` and `label`. */\nexport function normalizeSeries<T extends Datum>(series: readonly SeriesSpec<T>[] | undefined, y: Accessor<T, number | null | undefined> | undefined, label: string | undefined): readonly SeriesSpec<T>[] {\n if (series?.length) return series;\n if (y !== undefined) return [{ key: y, label: label ?? (typeof y === \"string\" ? y : \"\") }];\n return [];\n}\n\n/** The categories and the series' values, row by row. */\nexport function tabulate<T extends Datum>(data: readonly T[], x: Accessor<T, unknown> | undefined, series: readonly SeriesSpec<T>[]): Table {\n return {\n categories: data.map((datum, i) => (x === undefined ? i + 1 : read(x, datum, i))),\n series: series.map((spec, s) => ({\n id: typeof spec.key === \"string\" ? spec.key : `series-${s}`,\n label: spec.label,\n values: data.map((datum, i) => toNumber(read(spec.key, datum, i))),\n color: spec.color,\n dashed: spec.dashed,\n slot: (s % 8) + 1,\n })),\n };\n}\n\n/** The smallest and largest value of the series, `stacked` summing them per category (positives and negatives apart). */\nexport function extent(series: readonly Series[], stacked = false): [number, number] {\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n const count = series[0]?.values.length ?? 0;\n if (stacked) {\n for (let i = 0; i < count; i += 1) {\n let pos = 0;\n let neg = 0;\n for (const s of series) {\n const v = s.values[i] ?? 0;\n if (v >= 0) pos += v;\n else neg += v;\n }\n min = Math.min(min, neg);\n max = Math.max(max, pos);\n }\n } else {\n for (const s of series) {\n for (const v of s.values) {\n if (v == null) continue;\n min = Math.min(min, v);\n max = Math.max(max, v);\n }\n }\n }\n if (min === Number.POSITIVE_INFINITY) return [0, 0];\n return [min, max];\n}\n\n/** Per category and series, the base and top of a stacked mark (positives up, negatives down). */\nexport function stack(series: readonly Series[]): { base: number; top: number }[][] {\n const count = series[0]?.values.length ?? 0;\n const out = series.map(() => [] as { base: number; top: number }[]);\n for (let i = 0; i < count; i += 1) {\n let pos = 0;\n let neg = 0;\n series.forEach((s, k) => {\n const v = s.values[i] ?? 0;\n if (v >= 0) {\n out[k]!.push({ base: pos, top: pos + v });\n pos += v;\n } else {\n out[k]!.push({ base: neg, top: neg + v });\n neg += v;\n }\n });\n }\n return out;\n}\n\n/** What a series says: its extremes, its first and last values, its total and its trend (±1 % is flat). */\nexport function summarize(series: Series, categories: readonly unknown[], writeCategory: (c: unknown) => string): SeriesSummary {\n let min: SeriesSummary[\"min\"] = null;\n let max: SeriesSummary[\"max\"] = null;\n let first: number | null = null;\n let last: number | null = null;\n let total = 0;\n let count = 0;\n series.values.forEach((v, i) => {\n if (v == null) return;\n count += 1;\n total += v;\n if (first === null) first = v;\n last = v;\n if (!min || v < min.value) min = { value: v, category: writeCategory(categories[i]) };\n if (!max || v > max.value) max = { value: v, category: writeCategory(categories[i]) };\n });\n const change = first !== null && last !== null && first !== 0 && count > 1 ? (last as number) / first - 1 : null;\n const trend = count < 2 || change === null ? (count < 2 ? \"none\" : last! > first! ? \"up\" : last! < first! ? \"down\" : \"flat\") : Math.abs(change) < 0.01 ? \"flat\" : change > 0 ? \"up\" : \"down\";\n return { label: series.label, count, min, max, first, last, total, change, trend };\n}\n"],"mappings":"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","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|