@scalewing/react 1.38.0 → 1.39.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +53 -1
  3. package/dist/chart-axis.d.ts +61 -0
  4. package/dist/chart-axis.js +83 -0
  5. package/dist/chart-dates.d.ts +6 -0
  6. package/dist/chart-dates.js +15 -0
  7. package/dist/chart-metrics.d.ts +40 -0
  8. package/dist/chart-metrics.js +48 -0
  9. package/dist/chart-scale.d.ts +48 -0
  10. package/dist/chart-scale.js +116 -0
  11. package/dist/chart-table-rows.d.ts +8 -0
  12. package/dist/chart-table-rows.js +1 -0
  13. package/dist/column-chart-bars.d.ts +38 -0
  14. package/dist/column-chart-bars.js +82 -0
  15. package/dist/column-chart-callouts.d.ts +48 -0
  16. package/dist/column-chart-callouts.js +54 -0
  17. package/dist/column-chart-input.d.ts +40 -0
  18. package/dist/column-chart-input.js +60 -0
  19. package/dist/column-chart-layout.d.ts +63 -0
  20. package/dist/column-chart-layout.js +97 -0
  21. package/dist/components/BarChart.d.ts +1 -1
  22. package/dist/components/BarChart.js +1 -1
  23. package/dist/components/ChartLegend.d.ts +38 -0
  24. package/dist/components/ChartLegend.js +32 -0
  25. package/dist/components/ColumnChart.d.ts +72 -0
  26. package/dist/components/ColumnChart.js +71 -0
  27. package/dist/components/DataBar.d.ts +6 -6
  28. package/dist/components/LineChart.d.ts +83 -0
  29. package/dist/components/LineChart.js +77 -0
  30. package/dist/components/chart/ChartTable.d.ts +16 -0
  31. package/dist/components/chart/ChartTable.js +12 -0
  32. package/dist/components/chart/ChartValueAxis.d.ts +14 -0
  33. package/dist/components/chart/ChartValueAxis.js +11 -0
  34. package/dist/components/chart/use-chart-width.d.ts +8 -0
  35. package/dist/components/chart/use-chart-width.js +34 -0
  36. package/dist/components/column-chart/ChartCalloutList.d.ts +16 -0
  37. package/dist/components/column-chart/ChartCalloutList.js +13 -0
  38. package/dist/components/column-chart/ColumnChartDrawing.d.ts +17 -0
  39. package/dist/components/column-chart/ColumnChartDrawing.js +18 -0
  40. package/dist/components/line-chart/LineChartDrawing.d.ts +17 -0
  41. package/dist/components/line-chart/LineChartDrawing.js +16 -0
  42. package/dist/css/chart-marks.d.ts +10 -0
  43. package/dist/css/chart-marks.js +15 -0
  44. package/dist/css/chart-tones.d.ts +68 -0
  45. package/dist/css/chart-tones.js +130 -0
  46. package/dist/css/{css-chart.d.ts → css-bar-chart.d.ts} +2 -2
  47. package/dist/css/{css-chart.js → css-bar-chart.js} +2 -2
  48. package/dist/css/css-chart-legend.d.ts +5 -0
  49. package/dist/css/css-chart-legend.js +102 -0
  50. package/dist/css/css-chart-plot.d.ts +2 -0
  51. package/dist/css/css-chart-plot.js +170 -0
  52. package/dist/css/css-components.js +14 -2
  53. package/dist/css/css-data-bar.d.ts +4 -9
  54. package/dist/css/css-data-bar.js +15 -31
  55. package/dist/css/css-line-chart.d.ts +2 -0
  56. package/dist/css/css-line-chart.js +31 -0
  57. package/dist/css/stylesheet.js +10 -2
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.js +3 -0
  60. package/dist/is-one-of.d.ts +5 -0
  61. package/dist/is-one-of.js +7 -0
  62. package/dist/line-chart-input.d.ts +39 -0
  63. package/dist/line-chart-input.js +70 -0
  64. package/dist/line-chart-layout.d.ts +68 -0
  65. package/dist/line-chart-layout.js +99 -0
  66. package/dist/line-chart-markers.d.ts +29 -0
  67. package/dist/line-chart-markers.js +57 -0
  68. package/dist/line-chart-path.d.ts +18 -0
  69. package/dist/line-chart-path.js +33 -0
  70. package/dist/line-chart-points.d.ts +6 -0
  71. package/dist/line-chart-points.js +8 -0
  72. package/dist/line-chart-table.d.ts +15 -0
  73. package/dist/line-chart-table.js +29 -0
  74. package/dist/styles.css +219 -0
  75. package/package.json +1 -1
@@ -0,0 +1,71 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatBarChartValue } from '@scalewing/tokens';
4
+ import { forwardRef, useImperativeHandle, useRef, } from 'react';
5
+ import { cx } from '../class-names.js';
6
+ import { columnChartModes, } from '../column-chart-bars.js';
7
+ import { assertColumnChartInput, } from '../column-chart-input.js';
8
+ import { columnChartLayout } from '../column-chart-layout.js';
9
+ import { ChartTable } from './chart/ChartTable.js';
10
+ import { useChartWidth } from './chart/use-chart-width.js';
11
+ import { ChartCalloutList } from './column-chart/ChartCalloutList.js';
12
+ import { ColumnChartDrawing } from './column-chart/ColumnChartDrawing.js';
13
+ export { columnChartModes };
14
+ const noCallouts = [];
15
+ /**
16
+ * Columns for each category (a week, a month), stacked or grouped by
17
+ * series, with an optional line on its own right-hand scale whose zero
18
+ * and grid lines are level with the columns', the current period boxed
19
+ * and callouts pinned above their columns. It fills its container's width
20
+ * and is laid out for it: a narrow chart labels fewer categories and lists
21
+ * its callouts under the plot, never scrolling sideways. The drawing is
22
+ * hidden from assistive technology; a visually hidden table named by
23
+ * `label` carries every figure, and the callouts stay a list. Put it on
24
+ * the surface (a `Card`) with a `ChartLegend` above it naming each series
25
+ * (`bar` in its tone), the line (`line`, `accent`) and the box (`box`,
26
+ * `accent`). Input it cannot draw throws a `RangeError`.
27
+ */
28
+ export const ColumnChart = forwardRef(function ColumnChart({ callouts = noCallouts, categories, className, formatTick, formatValue = formatBarChartValue, highlight, label, line, mode = 'stacked', series, ...rest }, ref) {
29
+ assertColumnChartInput({
30
+ label,
31
+ categories,
32
+ series,
33
+ mode,
34
+ line,
35
+ highlight,
36
+ callouts,
37
+ });
38
+ const box = useRef(null);
39
+ useImperativeHandle(ref, () => box.current, []);
40
+ const width = useChartWidth(box);
41
+ const lastLineValue = line?.values.at(-1);
42
+ const layout = columnChartLayout({
43
+ width,
44
+ categories,
45
+ series: series.map((s) => s.values),
46
+ mode,
47
+ line: line
48
+ ? {
49
+ values: line.values,
50
+ endLabel: line.endLabel === false || lastLineValue === undefined
51
+ ? null
52
+ : formatValue(lastLineValue),
53
+ }
54
+ : null,
55
+ highlight: highlight ?? null,
56
+ callouts,
57
+ formatTick: formatTick ?? formatValue,
58
+ });
59
+ return (_jsxs("div", { ref: box, className: cx('sw-chart', className), ...rest, children: [_jsx(ColumnChartDrawing, { calloutTones: callouts.map((callout) => callout.tone), layout: layout, tones: series.map((s) => s.tone) }), _jsx(ChartTable, { caption: label, columns: [
60
+ ...series.map((s) => s.label),
61
+ ...(line ? [line.label] : []),
62
+ ], rows: categories.map((category, index) => ({
63
+ key: `${category}-${index}`,
64
+ header: category,
65
+ cells: [
66
+ ...series.map((s) => formatValue(s.values[index])),
67
+ ...(line ? [formatValue(line.values[index])] : []),
68
+ ],
69
+ current: index === highlight,
70
+ })) }), _jsx(ChartCalloutList, { callouts: callouts, visible: layout.compact })] }));
71
+ });
@@ -13,9 +13,9 @@ export type DataBarProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'a
13
13
  max: number;
14
14
  /**
15
15
  * What the bar means (default `neutral`): `success` for money in,
16
- * `muted` for money out (an outflow is not an error, so there is no
17
- * danger tone), `strong` for a subtotal and `accent` for a counted or
18
- * recorded figure.
16
+ * `muted` for money out (an outflow is not an error, so it is never
17
+ * danger), `strong` for a subtotal, `accent` for a counted or recorded
18
+ * figure and `danger` for a shortage, never for cash leaving.
19
19
  */
20
20
  tone?: DataBarTone;
21
21
  };
@@ -40,9 +40,9 @@ export declare const DataBar: import("react").ForwardRefExoticComponent<Omit<HTM
40
40
  max: number;
41
41
  /**
42
42
  * What the bar means (default `neutral`): `success` for money in,
43
- * `muted` for money out (an outflow is not an error, so there is no
44
- * danger tone), `strong` for a subtotal and `accent` for a counted or
45
- * recorded figure.
43
+ * `muted` for money out (an outflow is not an error, so it is never
44
+ * danger), `strong` for a subtotal, `accent` for a counted or recorded
45
+ * figure and `danger` for a shortage, never for cash leaving.
46
46
  */
47
47
  tone?: DataBarTone;
48
48
  } & import("react").RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,83 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ import { type ChartStrokeTone } from '../css/chart-tones.js';
3
+ import { type LineChartMarker, type LineChartPeriod, type LineChartPoint } from '../line-chart-input.js';
4
+ import { type LineChartCurve, lineChartCurves } from '../line-chart-path.js';
5
+ export type { LineChartCurve, LineChartMarker, LineChartPeriod, LineChartPoint, };
6
+ export { lineChartCurves };
7
+ export type LineChartProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
8
+ /** Names the chart: the caption of the table that carries its figures. */
9
+ label: string;
10
+ /** Heads the table's value column; defaults to `label`. */
11
+ valueLabel?: string;
12
+ /** The values by date (`YYYY-MM-DD`), in date order. */
13
+ points: readonly LineChartPoint[];
14
+ /**
15
+ * `linear` (the default) joins each point to the next; `step` holds a
16
+ * value until the next date, as a balance that changes on a day does.
17
+ */
18
+ curve?: LineChartCurve;
19
+ /** Fills the area between the line and zero with a tint of its tone. */
20
+ area?: boolean;
21
+ /** The line's stroke tone (default `accent`). */
22
+ tone?: ChartStrokeTone;
23
+ /** Downward triangles on the line at some of its dates, with words. */
24
+ markers?: readonly LineChartMarker[];
25
+ /** Heads the table's column of marker words; required with markers. */
26
+ markersLabel?: string;
27
+ /** The dates labelled on the time axis; the first and last by default. */
28
+ ticks?: readonly string[];
29
+ /** A period to box, such as the current week. */
30
+ highlight?: LineChartPeriod;
31
+ /** Writes the last value beside the plot's end (default `true`). */
32
+ endLabel?: boolean;
33
+ /** Writes each figure in the table and the last value. */
34
+ formatValue?: (value: number) => string;
35
+ /** Writes the value axis; defaults to `formatValue`. */
36
+ formatTick?: (value: number) => string;
37
+ /** Writes a date for the time axis and the table; the date itself by default. */
38
+ formatDate?: (date: string) => string;
39
+ };
40
+ /**
41
+ * A value over time: a line through its points by date, straight or in
42
+ * steps, optionally over a tinted area, with markers on chosen dates, a
43
+ * boxed period and its last value beside the plot. It fills its
44
+ * container's width and is laid out for it, labelling fewer dates when
45
+ * they would meet, never scrolling sideways. The drawing is hidden from
46
+ * assistive technology; a visually hidden table named by `label` carries
47
+ * every date, value and marker. Pair it with a `ChartLegend` (`line` in its
48
+ * tone, `marker` in each marker's, `box` in `accent`), on the surface.
49
+ * Input it cannot draw throws a `RangeError`.
50
+ */
51
+ export declare const LineChart: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
52
+ /** Names the chart: the caption of the table that carries its figures. */
53
+ label: string;
54
+ /** Heads the table's value column; defaults to `label`. */
55
+ valueLabel?: string;
56
+ /** The values by date (`YYYY-MM-DD`), in date order. */
57
+ points: readonly LineChartPoint[];
58
+ /**
59
+ * `linear` (the default) joins each point to the next; `step` holds a
60
+ * value until the next date, as a balance that changes on a day does.
61
+ */
62
+ curve?: LineChartCurve;
63
+ /** Fills the area between the line and zero with a tint of its tone. */
64
+ area?: boolean;
65
+ /** The line's stroke tone (default `accent`). */
66
+ tone?: ChartStrokeTone;
67
+ /** Downward triangles on the line at some of its dates, with words. */
68
+ markers?: readonly LineChartMarker[];
69
+ /** Heads the table's column of marker words; required with markers. */
70
+ markersLabel?: string;
71
+ /** The dates labelled on the time axis; the first and last by default. */
72
+ ticks?: readonly string[];
73
+ /** A period to box, such as the current week. */
74
+ highlight?: LineChartPeriod;
75
+ /** Writes the last value beside the plot's end (default `true`). */
76
+ endLabel?: boolean;
77
+ /** Writes each figure in the table and the last value. */
78
+ formatValue?: (value: number) => string;
79
+ /** Writes the value axis; defaults to `formatValue`. */
80
+ formatTick?: (value: number) => string;
81
+ /** Writes a date for the time axis and the table; the date itself by default. */
82
+ formatDate?: (date: string) => string;
83
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,77 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatBarChartValue } from '@scalewing/tokens';
4
+ import { forwardRef, useImperativeHandle, useRef, } from 'react';
5
+ import { cx } from '../class-names.js';
6
+ import { assertLineChartInput, lineChartDay, } from '../line-chart-input.js';
7
+ import { lineChartLayout } from '../line-chart-layout.js';
8
+ import { lineChartRows } from '../line-chart-table.js';
9
+ import { lineChartCurves } from '../line-chart-path.js';
10
+ import { ChartTable } from './chart/ChartTable.js';
11
+ import { useChartWidth } from './chart/use-chart-width.js';
12
+ import { LineChartDrawing } from './line-chart/LineChartDrawing.js';
13
+ export { lineChartCurves };
14
+ const none = [];
15
+ const sameDate = (date) => date;
16
+ /**
17
+ * A value over time: a line through its points by date, straight or in
18
+ * steps, optionally over a tinted area, with markers on chosen dates, a
19
+ * boxed period and its last value beside the plot. It fills its
20
+ * container's width and is laid out for it, labelling fewer dates when
21
+ * they would meet, never scrolling sideways. The drawing is hidden from
22
+ * assistive technology; a visually hidden table named by `label` carries
23
+ * every date, value and marker. Pair it with a `ChartLegend` (`line` in its
24
+ * tone, `marker` in each marker's, `box` in `accent`), on the surface.
25
+ * Input it cannot draw throws a `RangeError`.
26
+ */
27
+ export const LineChart = forwardRef(function LineChart({ area = false, className, curve = 'linear', endLabel = true, formatDate = sameDate, formatTick, formatValue = formatBarChartValue, highlight, label, markers = none, markersLabel, points, ticks, tone = 'accent', valueLabel, ...rest }, ref) {
28
+ assertLineChartInput({
29
+ label,
30
+ valueLabel,
31
+ points,
32
+ curve,
33
+ tone,
34
+ markers,
35
+ markersLabel,
36
+ ticks,
37
+ highlight,
38
+ });
39
+ const box = useRef(null);
40
+ useImperativeHandle(ref, () => box.current, []);
41
+ const width = useChartWidth(box);
42
+ const lastPoint = points.at(-1);
43
+ const tickDates = ticks ??
44
+ [...new Set([points[0]?.x, lastPoint?.x])].filter((date) => date !== undefined);
45
+ const layout = lineChartLayout({
46
+ width,
47
+ points: points.map((p) => ({ day: lineChartDay('x', p.x), y: p.y })),
48
+ curve,
49
+ area,
50
+ markers: markers.map((m) => ({
51
+ day: lineChartDay('x', m.x),
52
+ label: m.label,
53
+ })),
54
+ ticks: tickDates.map((date) => ({
55
+ day: lineChartDay('tick', date),
56
+ text: formatDate(date),
57
+ })),
58
+ highlight: highlight
59
+ ? {
60
+ from: lineChartDay('from', highlight.from),
61
+ to: lineChartDay('to', highlight.to),
62
+ }
63
+ : null,
64
+ endLabel: endLabel && lastPoint ? formatValue(lastPoint.y) : null,
65
+ formatTick: formatTick ?? formatValue,
66
+ });
67
+ return (_jsxs("div", { ref: box, className: cx('sw-chart', className), ...rest, children: [_jsx(LineChartDrawing, { layout: layout, markerTones: markers.map((m) => m.tone), tone: tone }), _jsx(ChartTable, { caption: label, columns: [
68
+ valueLabel ?? label,
69
+ ...(markers.length > 0 ? [markersLabel] : []),
70
+ ], rows: lineChartRows({
71
+ formatDate,
72
+ formatValue,
73
+ highlight,
74
+ markers,
75
+ points,
76
+ }) })] }));
77
+ });
@@ -0,0 +1,16 @@
1
+ import { type ChartTableRow } from '../../chart-table-rows.js';
2
+ export type ChartTableProps = {
3
+ caption: string;
4
+ /** The columns' headers, after the rows' own header column. */
5
+ columns: readonly string[];
6
+ rows: readonly ChartTableRow[];
7
+ };
8
+ /**
9
+ * Every figure a chart draws, as a table kept for assistive technology and
10
+ * not drawn: it sits in a `sw-sr-only` box, because a table is never
11
+ * narrower than its contents and would widen the page. Its caption is the
12
+ * chart's name, with a header per column and per row, and the boxed
13
+ * period's row marked current. The drawing itself is hidden, so this is
14
+ * what a screen reader reads.
15
+ */
16
+ export declare function ChartTable({ caption, columns, rows }: ChartTableProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Every figure a chart draws, as a table kept for assistive technology and
4
+ * not drawn: it sits in a `sw-sr-only` box, because a table is never
5
+ * narrower than its contents and would widen the page. Its caption is the
6
+ * chart's name, with a header per column and per row, and the boxed
7
+ * period's row marked current. The drawing itself is hidden, so this is
8
+ * what a screen reader reads.
9
+ */
10
+ export function ChartTable({ caption, columns, rows }) {
11
+ return (_jsx("div", { className: "sw-sr-only", children: _jsxs("table", { children: [_jsx("caption", { children: caption }), columns.length > 0 ? (_jsx("thead", { children: _jsxs("tr", { children: [_jsx("td", {}), columns.map((column, index) => (_jsx("th", { scope: "col", children: column }, `${column}-${index}`)))] }) })) : null, _jsx("tbody", { children: rows.map((row) => (_jsxs("tr", { "aria-current": row.current ? 'true' : undefined, children: [_jsx("th", { scope: "row", children: row.header }), row.cells.map((cell, index) => (_jsx("td", { children: cell }, index)))] }, row.key))) })] }) }));
12
+ }
@@ -0,0 +1,14 @@
1
+ import { type ChartPlot, type ChartTick } from '../../chart-axis.js';
2
+ export type ChartValueAxisProps = {
3
+ plot: ChartPlot;
4
+ ticks: readonly ChartTick[];
5
+ /** The side its words sit on: the plot's start, or its end for a line's own scale. */
6
+ side: 'start' | 'end';
7
+ /** Draws the grid lines across the plot (the start axis does). */
8
+ grid?: boolean;
9
+ };
10
+ /**
11
+ * A value axis inside a chart's SVG: a grid line at each tick across the
12
+ * plot, the zero line set apart, and each tick's words beside the plot.
13
+ */
14
+ export declare function ChartValueAxis({ grid, plot, side, ticks, }: ChartValueAxisProps): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { chartGap } from '../../chart-metrics.js';
3
+ import { cx } from '../../class-names.js';
4
+ /**
5
+ * A value axis inside a chart's SVG: a grid line at each tick across the
6
+ * plot, the zero line set apart, and each tick's words beside the plot.
7
+ */
8
+ export function ChartValueAxis({ grid = false, plot, side, ticks, }) {
9
+ const x = side === 'start' ? plot.left - chartGap : plot.right + chartGap;
10
+ return (_jsx("g", { children: ticks.map((tick) => (_jsxs("g", { children: [grid ? (_jsx("line", { className: tick.value === 0 ? 'sw-chart-zero' : 'sw-chart-grid', x1: plot.left, x2: plot.right, y1: tick.y, y2: tick.y })) : null, _jsx("text", { className: cx('sw-chart-tick', side === 'end' && 'sw-chart-tick-line'), dominantBaseline: "central", textAnchor: side === 'start' ? 'end' : 'start', x: x, y: tick.y, children: tick.label })] }, tick.value))) }));
11
+ }
@@ -0,0 +1,8 @@
1
+ import { type RefObject } from 'react';
2
+ /**
3
+ * Follows the width a chart is given, so its drawing is laid out in its
4
+ * own pixels: on mount, before the first paint, and whenever its box
5
+ * changes size. On the server it reports `chartFallbackWidth`, and a browser with
6
+ * no ResizeObserver measures on window resizes instead.
7
+ */
8
+ export declare function useChartWidth(ref: RefObject<HTMLElement | null>): number;
@@ -0,0 +1,34 @@
1
+ 'use client';
2
+ import { useLayoutEffect, useState } from 'react';
3
+ import { chartFallbackWidth } from '../../chart-metrics.js';
4
+ /**
5
+ * Follows the width a chart is given, so its drawing is laid out in its
6
+ * own pixels: on mount, before the first paint, and whenever its box
7
+ * changes size. On the server it reports `chartFallbackWidth`, and a browser with
8
+ * no ResizeObserver measures on window resizes instead.
9
+ */
10
+ export function useChartWidth(ref) {
11
+ const [width, setWidth] = useState(chartFallbackWidth);
12
+ // Before paint, so a phone never shows the wide layout first.
13
+ useLayoutEffect(() => {
14
+ const box = ref.current;
15
+ if (!box)
16
+ return;
17
+ function measure() {
18
+ if (!box)
19
+ return;
20
+ const next = Math.round(box.getBoundingClientRect().width);
21
+ if (next > 0)
22
+ setWidth(next);
23
+ }
24
+ measure();
25
+ if (typeof ResizeObserver === 'undefined') {
26
+ window.addEventListener('resize', measure);
27
+ return () => window.removeEventListener('resize', measure);
28
+ }
29
+ const observer = new ResizeObserver(measure);
30
+ observer.observe(box);
31
+ return () => observer.disconnect();
32
+ }, [ref]);
33
+ return width;
34
+ }
@@ -0,0 +1,16 @@
1
+ import { type CategoricalColor } from '@scalewing/tokens';
2
+ export type ChartCalloutListProps = {
3
+ callouts: readonly {
4
+ text: string;
5
+ tone?: CategoricalColor;
6
+ }[];
7
+ /** Shows the list under the plot; otherwise it is kept for assistive technology only. */
8
+ visible: boolean;
9
+ };
10
+ /**
11
+ * A chart's callouts as a list of their words, each after a dot in its
12
+ * hue: shown under the plot on a compact chart, where they no longer fit
13
+ * above it, and otherwise kept for assistive technology (`sw-sr-only`)
14
+ * while the drawing pins them above their columns.
15
+ */
16
+ export declare function ChartCalloutList({ callouts, visible }: ChartCalloutListProps): import("react").JSX.Element | null;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from '../../class-names.js';
3
+ /**
4
+ * A chart's callouts as a list of their words, each after a dot in its
5
+ * hue: shown under the plot on a compact chart, where they no longer fit
6
+ * above it, and otherwise kept for assistive technology (`sw-sr-only`)
7
+ * while the drawing pins them above their columns.
8
+ */
9
+ export function ChartCalloutList({ callouts, visible }) {
10
+ if (callouts.length === 0)
11
+ return null;
12
+ return (_jsx("ul", { className: cx('sw-chart-callouts', !visible && 'sw-sr-only'), role: "list", children: callouts.map((callout, index) => (_jsxs("li", { className: cx('sw-chart-callout', callout.tone && `sw-chart-tone-${callout.tone}`), children: [_jsx("span", { "aria-hidden": "true", className: "sw-chart-callout-dot" }), callout.text] }, `${callout.text}-${index}`))) }));
13
+ }
@@ -0,0 +1,17 @@
1
+ import { type CategoricalColor } from '@scalewing/tokens';
2
+ import { type ColumnChartLayout } from '../../column-chart-layout.js';
3
+ export type ColumnChartDrawingProps = {
4
+ layout: ColumnChartLayout;
5
+ /** Each series' hue, in series order. */
6
+ tones: readonly CategoricalColor[];
7
+ /** Each callout's hue, in callout order. */
8
+ calloutTones: readonly (CategoricalColor | undefined)[];
9
+ };
10
+ /**
11
+ * A column chart's picture, hidden from assistive technology (the table
12
+ * beside it carries every figure): the grid and value axes, the boxed
13
+ * period, the columns, the line and its last value, the category labels
14
+ * and the callouts with their leaders. It is laid out in its own pixels,
15
+ * left to right whatever the writing direction, as a time axis reads.
16
+ */
17
+ export declare function ColumnChartDrawing({ calloutTones, layout, tones, }: ColumnChartDrawingProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { chartBoxRadius, chartColumnRadius, chartDotRadius, } from '../../chart-metrics.js';
3
+ import { cx } from '../../class-names.js';
4
+ import { ChartValueAxis } from '../chart/ChartValueAxis.js';
5
+ function toneClass(tone) {
6
+ return tone ? `sw-chart-tone-${tone}` : undefined;
7
+ }
8
+ /**
9
+ * A column chart's picture, hidden from assistive technology (the table
10
+ * beside it carries every figure): the grid and value axes, the boxed
11
+ * period, the columns, the line and its last value, the category labels
12
+ * and the callouts with their leaders. It is laid out in its own pixels,
13
+ * left to right whatever the writing direction, as a time axis reads.
14
+ */
15
+ export function ColumnChartDrawing({ calloutTones, layout, tones, }) {
16
+ const { plot } = layout;
17
+ return (_jsxs("svg", { "aria-hidden": "true", className: "sw-chart-svg", direction: "ltr", focusable: "false", height: layout.height, viewBox: `0 0 ${layout.width} ${layout.height}`, width: layout.width, children: [_jsx(ChartValueAxis, { grid: true, plot: plot, side: "start", ticks: layout.ticks }), layout.highlight ? (_jsx("rect", { className: "sw-chart-highlight sw-chart-tone-accent", height: layout.highlight.height, rx: chartBoxRadius, width: layout.highlight.width, x: layout.highlight.x, y: layout.highlight.y })) : null, layout.columns.map((column) => (_jsx("rect", { className: cx('sw-chart-column', toneClass(tones[column.series])), height: column.height, rx: Math.min(chartColumnRadius, column.width / 2, column.height / 2), width: column.width, x: column.x, y: column.y }, `${column.series}-${column.category}`))), layout.line ? (_jsxs("g", { className: "sw-chart-tone-accent", children: [_jsx("polyline", { className: "sw-chart-line", points: layout.line.points.map((p) => `${p.x},${p.y}`).join(' ') }), _jsx(ChartValueAxis, { plot: plot, side: "end", ticks: layout.lineTicks }), layout.line.end || layout.line.points.length === 1 ? (_jsx("circle", { className: "sw-chart-dot", cx: layout.line.points.at(-1).x, cy: layout.line.points.at(-1).y, r: chartDotRadius })) : null, layout.line.end ? (_jsx("text", { className: "sw-chart-end-label", dominantBaseline: "central", x: layout.line.end.x, y: layout.line.end.y, children: layout.line.end.text })) : null] })) : null, layout.categoryLabels.map((label) => (_jsx("text", { className: "sw-chart-category", textAnchor: "middle", x: label.x, y: label.y, children: label.text }, label.index))), layout.callouts.map((callout) => (_jsxs("g", { className: toneClass(calloutTones[callout.order]), children: [_jsx("line", { className: "sw-chart-leader", x1: callout.x, x2: callout.x, y1: callout.leaderStart, y2: callout.leaderEnd }), _jsx("text", { className: "sw-chart-callout-text", textAnchor: callout.anchor, x: callout.textX, y: callout.textY, children: callout.text })] }, callout.order)))] }));
18
+ }
@@ -0,0 +1,17 @@
1
+ import { type ChartStrokeTone } from '../../css/chart-tones.js';
2
+ import { type LineChartLayout } from '../../line-chart-layout.js';
3
+ export type LineChartDrawingProps = {
4
+ layout: LineChartLayout;
5
+ tone: ChartStrokeTone;
6
+ /** Each marker's tone, in marker order. */
7
+ markerTones: readonly ChartStrokeTone[];
8
+ };
9
+ /**
10
+ * A line chart's picture, hidden from assistive technology (the table
11
+ * beside it carries every figure): the grid and value axis, the boxed
12
+ * period, the area and line in the line's tone with a dot and words at its
13
+ * last value, the date labels, and each marker's triangle and words in its
14
+ * own tone. It is laid out in its own pixels, left to right whatever the
15
+ * writing direction, as a time axis reads.
16
+ */
17
+ export declare function LineChartDrawing({ layout, markerTones, tone, }: LineChartDrawingProps): import("react").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { chartBoxRadius, chartDotRadius } from '../../chart-metrics.js';
3
+ import { svgPoints } from '../../line-chart-path.js';
4
+ import { ChartValueAxis } from '../chart/ChartValueAxis.js';
5
+ /**
6
+ * A line chart's picture, hidden from assistive technology (the table
7
+ * beside it carries every figure): the grid and value axis, the boxed
8
+ * period, the area and line in the line's tone with a dot and words at its
9
+ * last value, the date labels, and each marker's triangle and words in its
10
+ * own tone. It is laid out in its own pixels, left to right whatever the
11
+ * writing direction, as a time axis reads.
12
+ */
13
+ export function LineChartDrawing({ layout, markerTones, tone, }) {
14
+ const { last, plot } = layout;
15
+ return (_jsxs("svg", { "aria-hidden": "true", className: "sw-chart-svg", direction: "ltr", focusable: "false", height: layout.height, viewBox: `0 0 ${layout.width} ${layout.height}`, width: layout.width, children: [_jsx(ChartValueAxis, { grid: true, plot: plot, side: "start", ticks: layout.ticks }), layout.highlight ? (_jsx("rect", { className: "sw-chart-highlight sw-chart-tone-accent", height: layout.highlight.height, rx: chartBoxRadius, width: layout.highlight.width, x: layout.highlight.x, y: layout.highlight.y })) : null, _jsxs("g", { className: `sw-chart-tone-${tone}`, children: [layout.area.length > 0 ? (_jsx("polygon", { className: "sw-chart-area", points: svgPoints(layout.area) })) : null, _jsx("polyline", { className: "sw-chart-line", points: svgPoints(layout.path) }), last && (layout.end || layout.path.length === 1) ? (_jsx("circle", { className: "sw-chart-dot", cx: last.x, cy: last.y, r: chartDotRadius })) : null, layout.end ? (_jsx("text", { className: "sw-chart-end-label", dominantBaseline: "central", x: layout.end.x, y: layout.end.y, children: layout.end.text })) : null] }), layout.markers.map((marker) => (_jsxs("g", { className: `sw-chart-tone-${markerTones[marker.order]}`, children: [_jsx("polygon", { className: "sw-chart-marker", points: marker.triangle }), marker.labelShown ? (_jsx("text", { className: "sw-chart-marker-label", textAnchor: "middle", x: marker.labelX, y: marker.labelY, children: marker.label })) : null] }, marker.order))), layout.dateLabels.map((label) => (_jsx("text", { className: "sw-chart-category", textAnchor: "middle", x: label.x, y: label.y, children: label.text }, label.day)))] }));
16
+ }
@@ -0,0 +1,10 @@
1
+ /** A line's thickness (a chart's line and a legend's line swatch), in px. */
2
+ export declare const chartLineWidth = 2;
3
+ /** A hairline: a grid line, a leader, the boxed period's dashed edge. */
4
+ export declare const chartHairline = 1;
5
+ /** The boxed period's dashes: 3 px drawn, 3 px left out. */
6
+ export declare const chartBoxDash = "3 3";
7
+ /** A callout's leader: finer dashes, 2 px drawn, 2 px left out. */
8
+ export declare const chartLeaderDash = "2 2";
9
+ /** The gap between grouped columns side by side, at most. */
10
+ export declare const chartColumnGap = 2;
@@ -0,0 +1,15 @@
1
+ /*
2
+ * The sizes every chart's marks share, so a legend swatch is drawn at the
3
+ * size of the mark it names. They are geometry, not theme values: the
4
+ * colours come from `chart-tones.ts` and the type from the caption variant.
5
+ */
6
+ /** A line's thickness (a chart's line and a legend's line swatch), in px. */
7
+ export const chartLineWidth = 2;
8
+ /** A hairline: a grid line, a leader, the boxed period's dashed edge. */
9
+ export const chartHairline = 1;
10
+ /** The boxed period's dashes: 3 px drawn, 3 px left out. */
11
+ export const chartBoxDash = '3 3';
12
+ /** A callout's leader: finer dashes, 2 px drawn, 2 px left out. */
13
+ export const chartLeaderDash = '2 2';
14
+ /** The gap between grouped columns side by side, at most. */
15
+ export const chartColumnGap = chartLineWidth;
@@ -0,0 +1,68 @@
1
+ import { type CategoricalColor } from '@scalewing/tokens';
2
+ /** Where a mark's colour comes from: a semantic or a categorical colour. */
3
+ export type ChartColorSource = {
4
+ semantic: 'accent' | 'success' | 'warning' | 'danger' | 'muted' | 'text';
5
+ } | {
6
+ categorical: CategoricalColor;
7
+ };
8
+ /**
9
+ * A colour mixed into the surface or toward the text colour by a share of
10
+ * its own (1 is the colour unmixed).
11
+ */
12
+ export type ChartColorMix = ChartColorSource & {
13
+ share: number;
14
+ into: 'surface' | 'text';
15
+ };
16
+ /**
17
+ * The statement tones a range bar's fill takes (see DataBar). `danger` is
18
+ * for a shortage, never for cash leaving: an outflow is `muted`.
19
+ */
20
+ export declare const statementFillTones: readonly ["neutral", "success", "muted", "strong", "accent", "danger"];
21
+ /**
22
+ * Every fill tone: the categorical colours (a chart's series), then the
23
+ * statement tones a range bar adds. `neutral` is in both and is one grey.
24
+ */
25
+ export declare const chartFillTones: readonly ("danger" | "muted" | "accent" | "success" | CategoricalColor | "strong")[];
26
+ export type ChartFillTone = CategoricalColor | (typeof statementFillTones)[number];
27
+ /** The tones a line, a marker or the boxed period is drawn in. */
28
+ export declare const chartStrokeTones: readonly ["accent", "success", "warning", "danger", "neutral"];
29
+ export type ChartStrokeTone = (typeof chartStrokeTones)[number];
30
+ /** Every tone a chart or a legend swatch can take. */
31
+ export type ChartTone = ChartFillTone | ChartStrokeTone;
32
+ export declare const chartTones: readonly ChartTone[];
33
+ /**
34
+ * How much of a categorical colour a column's fill mixes into the surface:
35
+ * a lighter fill, so a line drawn over the columns stands apart, that
36
+ * keeps 1.5:1 on the surface in every palette and scheme.
37
+ */
38
+ export declare const categoricalFillShare = 0.72;
39
+ /**
40
+ * How much of the danger colour its fill mixes into the surface (a
41
+ * shortage's range bar, never cash leaving): a light red, at 1.5:1 or more
42
+ * on the surface in every palette and scheme, as every other fill.
43
+ */
44
+ export declare const dangerFillShare = 0.4;
45
+ /** Each fill tone's colour, mixed into the surface. */
46
+ export declare const chartFillMixes: Record<ChartFillTone, ChartColorMix>;
47
+ /** Each stroke tone's colour: a semantic colour, or muted for neutral. */
48
+ export declare const chartStrokeColors: Record<ChartStrokeTone, ChartColorSource>;
49
+ /**
50
+ * How much of a line's stroke the area under it takes, over transparency:
51
+ * a quiet tint behind the line, decorative (the line carries the values).
52
+ */
53
+ export declare const chartAreaShare = 0.12;
54
+ /** How much of a hue's colour its words keep, moved toward the text colour. */
55
+ export declare const categoricalInkShare = 0.3;
56
+ /** How much of a semantic colour its words keep, moved toward the text colour. */
57
+ export declare const semanticInkShare = 0.5;
58
+ /** The tones whose words are drawn beside a mark: a series' and a stroke's. */
59
+ export declare const chartInkTones: readonly ["green", "blue", "orange", "purple", "teal", "rose", "accent", "success", "warning", "danger", "neutral"];
60
+ export type ChartInkTone = (typeof chartInkTones)[number];
61
+ /** The words beside a mark: its tone moved toward the text colour. */
62
+ export declare const chartInkMixes: Record<ChartInkTone, ChartColorMix>;
63
+ /** A mix as CSS: the colour alone when unmixed. */
64
+ export declare function chartColorMix(mix: ChartColorMix): string;
65
+ /** A fill tone's colour. */
66
+ export declare function chartFill(tone: ChartFillTone): string;
67
+ export declare function cssChartToneClasses(): string;
68
+ export declare function chartToneClassCatalog(): string[];