@scalewing/react 1.37.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 (117) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +91 -1
  3. package/dist/accessible-name.d.ts +13 -0
  4. package/dist/accessible-name.js +1 -0
  5. package/dist/chart-axis.d.ts +61 -0
  6. package/dist/chart-axis.js +83 -0
  7. package/dist/chart-dates.d.ts +6 -0
  8. package/dist/chart-dates.js +15 -0
  9. package/dist/chart-metrics.d.ts +40 -0
  10. package/dist/chart-metrics.js +48 -0
  11. package/dist/chart-scale.d.ts +48 -0
  12. package/dist/chart-scale.js +116 -0
  13. package/dist/chart-table-rows.d.ts +8 -0
  14. package/dist/chart-table-rows.js +1 -0
  15. package/dist/column-chart-bars.d.ts +38 -0
  16. package/dist/column-chart-bars.js +82 -0
  17. package/dist/column-chart-callouts.d.ts +48 -0
  18. package/dist/column-chart-callouts.js +54 -0
  19. package/dist/column-chart-input.d.ts +40 -0
  20. package/dist/column-chart-input.js +60 -0
  21. package/dist/column-chart-layout.d.ts +63 -0
  22. package/dist/column-chart-layout.js +97 -0
  23. package/dist/components/BarChart.d.ts +1 -1
  24. package/dist/components/BarChart.js +1 -1
  25. package/dist/components/ChartLegend.d.ts +38 -0
  26. package/dist/components/ChartLegend.js +32 -0
  27. package/dist/components/ColumnChart.d.ts +72 -0
  28. package/dist/components/ColumnChart.js +71 -0
  29. package/dist/components/DataBar.d.ts +48 -0
  30. package/dist/components/DataBar.js +28 -0
  31. package/dist/components/LineChart.d.ts +83 -0
  32. package/dist/components/LineChart.js +77 -0
  33. package/dist/components/Pagination.d.ts +34 -0
  34. package/dist/components/Pagination.js +27 -0
  35. package/dist/components/ScrollRegion.d.ts +9 -5
  36. package/dist/components/ScrollRegion.js +8 -6
  37. package/dist/components/SectionNav.d.ts +2 -8
  38. package/dist/components/SegmentedControl.d.ts +2 -8
  39. package/dist/components/Table.d.ts +48 -4
  40. package/dist/components/Table.js +9 -3
  41. package/dist/components/Tabs.d.ts +2 -9
  42. package/dist/components/chart/ChartTable.d.ts +16 -0
  43. package/dist/components/chart/ChartTable.js +12 -0
  44. package/dist/components/chart/ChartValueAxis.d.ts +14 -0
  45. package/dist/components/chart/ChartValueAxis.js +11 -0
  46. package/dist/components/chart/use-chart-width.d.ts +8 -0
  47. package/dist/components/chart/use-chart-width.js +34 -0
  48. package/dist/components/column-chart/ChartCalloutList.d.ts +16 -0
  49. package/dist/components/column-chart/ChartCalloutList.js +13 -0
  50. package/dist/components/column-chart/ColumnChartDrawing.d.ts +17 -0
  51. package/dist/components/column-chart/ColumnChartDrawing.js +18 -0
  52. package/dist/components/line-chart/LineChartDrawing.d.ts +17 -0
  53. package/dist/components/line-chart/LineChartDrawing.js +16 -0
  54. package/dist/components/table/TableRow.d.ts +8 -2
  55. package/dist/components/table/TableRow.js +1 -1
  56. package/dist/components/table/table-max-height.d.ts +20 -0
  57. package/dist/components/table/table-max-height.js +23 -0
  58. package/dist/components/use-scroll-overflow.d.ts +10 -8
  59. package/dist/components/use-scroll-overflow.js +23 -10
  60. package/dist/css/chart-marks.d.ts +10 -0
  61. package/dist/css/chart-marks.js +15 -0
  62. package/dist/css/chart-tones.d.ts +68 -0
  63. package/dist/css/chart-tones.js +130 -0
  64. package/dist/css/chevron.d.ts +6 -3
  65. package/dist/css/chevron.js +9 -4
  66. package/dist/css/{css-chart.d.ts → css-bar-chart.d.ts} +2 -2
  67. package/dist/css/{css-chart.js → css-bar-chart.js} +2 -2
  68. package/dist/css/css-chart-legend.d.ts +5 -0
  69. package/dist/css/css-chart-legend.js +102 -0
  70. package/dist/css/css-chart-plot.d.ts +2 -0
  71. package/dist/css/css-chart-plot.js +170 -0
  72. package/dist/css/css-components.js +20 -2
  73. package/dist/css/css-data-bar.d.ts +11 -0
  74. package/dist/css/css-data-bar.js +91 -0
  75. package/dist/css/css-line-chart.d.ts +2 -0
  76. package/dist/css/css-line-chart.js +31 -0
  77. package/dist/css/css-pagination.d.ts +2 -0
  78. package/dist/css/css-pagination.js +63 -0
  79. package/dist/css/css-scroll-region.d.ts +1 -0
  80. package/dist/css/css-scroll-region.js +10 -5
  81. package/dist/css/css-table-bounded-edges.d.ts +1 -0
  82. package/dist/css/css-table-bounded-edges.js +132 -0
  83. package/dist/css/css-table-bounded.d.ts +2 -0
  84. package/dist/css/css-table-bounded.js +73 -0
  85. package/dist/css/css-table-ledger.d.ts +5 -2
  86. package/dist/css/css-table-ledger.js +5 -2
  87. package/dist/css/css-table-metrics.d.ts +14 -0
  88. package/dist/css/css-table-metrics.js +13 -0
  89. package/dist/css/css-table-sort.js +2 -1
  90. package/dist/css/css-table-total-row.d.ts +2 -0
  91. package/dist/css/css-table-total-row.js +29 -0
  92. package/dist/css/css-table.js +14 -3
  93. package/dist/css/stylesheet.js +14 -2
  94. package/dist/data-bar-geometry.d.ts +24 -0
  95. package/dist/data-bar-geometry.js +41 -0
  96. package/dist/index.d.ts +6 -1
  97. package/dist/index.js +5 -0
  98. package/dist/is-one-of.d.ts +5 -0
  99. package/dist/is-one-of.js +7 -0
  100. package/dist/line-chart-input.d.ts +39 -0
  101. package/dist/line-chart-input.js +70 -0
  102. package/dist/line-chart-layout.d.ts +68 -0
  103. package/dist/line-chart-layout.js +99 -0
  104. package/dist/line-chart-markers.d.ts +29 -0
  105. package/dist/line-chart-markers.js +57 -0
  106. package/dist/line-chart-path.d.ts +18 -0
  107. package/dist/line-chart-path.js +33 -0
  108. package/dist/line-chart-points.d.ts +6 -0
  109. package/dist/line-chart-points.js +8 -0
  110. package/dist/line-chart-table.d.ts +15 -0
  111. package/dist/line-chart-table.js +29 -0
  112. package/dist/pagination-pages.d.ts +13 -0
  113. package/dist/pagination-pages.js +22 -0
  114. package/dist/scroll-overflow.d.ts +12 -0
  115. package/dist/scroll-overflow.js +31 -7
  116. package/dist/styles.css +442 -0
  117. 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
+ });
@@ -0,0 +1,48 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ import { type DataBarTone, dataBarTones } from '../css/css-data-bar.js';
3
+ export type { DataBarTone };
4
+ export { dataBarTones };
5
+ export type DataBarProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'aria-hidden'> & {
6
+ /** One end of the range, in the domain's units. */
7
+ from: number;
8
+ /** The other end; the bar runs between the two whichever is larger. */
9
+ to: number;
10
+ /** The domain's least value, at the track's inline start. */
11
+ min: number;
12
+ /** The domain's greatest value, at the track's inline end. */
13
+ max: number;
14
+ /**
15
+ * What the bar means (default `neutral`): `success` for money in,
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
+ */
20
+ tone?: DataBarTone;
21
+ };
22
+ /**
23
+ * A horizontal range bar for a table cell or a list row: a bar from `from`
24
+ * to `to` on a track whose domain runs from `min` to `max`, such as where a
25
+ * statement's line leaves the running total, or a day's difference on a
26
+ * domain from below zero to above it, which draws a zero line. It is
27
+ * decorative (`aria-hidden`): the figure is the cell's own text, so keep
28
+ * the value beside it. Values past the domain are clamped to it;
29
+ * non-finite numbers, a `min` not under `max` or an unknown tone throw a
30
+ * `RangeError`.
31
+ */
32
+ export declare const DataBar: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLSpanElement>, "children" | "aria-hidden"> & {
33
+ /** One end of the range, in the domain's units. */
34
+ from: number;
35
+ /** The other end; the bar runs between the two whichever is larger. */
36
+ to: number;
37
+ /** The domain's least value, at the track's inline start. */
38
+ min: number;
39
+ /** The domain's greatest value, at the track's inline end. */
40
+ max: number;
41
+ /**
42
+ * What the bar means (default `neutral`): `success` for money in,
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
+ */
47
+ tone?: DataBarTone;
48
+ } & import("react").RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ import { cx } from '../class-names.js';
4
+ import { dataBarTones } from '../css/css-data-bar.js';
5
+ import { dataBarGeometry } from '../data-bar-geometry.js';
6
+ export { dataBarTones };
7
+ /**
8
+ * A horizontal range bar for a table cell or a list row: a bar from `from`
9
+ * to `to` on a track whose domain runs from `min` to `max`, such as where a
10
+ * statement's line leaves the running total, or a day's difference on a
11
+ * domain from below zero to above it, which draws a zero line. It is
12
+ * decorative (`aria-hidden`): the figure is the cell's own text, so keep
13
+ * the value beside it. Values past the domain are clamped to it;
14
+ * non-finite numbers, a `min` not under `max` or an unknown tone throw a
15
+ * `RangeError`.
16
+ */
17
+ export const DataBar = forwardRef(function DataBar({ className, from, max, min, style, to, tone = 'neutral', ...rest }, ref) {
18
+ if (!dataBarTones.includes(tone))
19
+ throw new RangeError(`DataBar tone must be one of ${dataBarTones.join(', ')}; received ${String(tone)}`);
20
+ const { start, size, zero, zeroEnd } = dataBarGeometry(from, to, min, max);
21
+ return (_jsx("span", { ref: ref, className: cx('sw-data-bar', `sw-data-bar-${tone}`, zero !== null && 'sw-data-bar-diverging', zeroEnd !== null && `sw-data-bar-zero-${zeroEnd}`, className), style: {
22
+ ...style,
23
+ ...(zero === null ? {} : { '--sw-data-bar-zero': zero }),
24
+ }, ...rest, "aria-hidden": "true", children: _jsx("span", { className: "sw-data-bar-fill", style: {
25
+ '--sw-data-bar-start': start,
26
+ '--sw-data-bar-size': size,
27
+ } }) }));
28
+ });
@@ -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,34 @@
1
+ import { type HTMLAttributes } from 'react';
2
+ import { type AccessibleName } from '../accessible-name.js';
3
+ /** The steps' accessible names, in the product's words. */
4
+ export type PaginationLabels = {
5
+ /** Names the step to the page before, such as "Previous page". */
6
+ previous: string;
7
+ /** Names the step to the page after, such as "Next page". */
8
+ next: string;
9
+ };
10
+ export type PaginationProps = Omit<HTMLAttributes<HTMLElement>, 'children' | 'aria-label' | 'aria-labelledby'> & AccessibleName & {
11
+ /** The page shown, from 1. */
12
+ page: number;
13
+ /** How many pages there are, from 1. */
14
+ pageCount: number;
15
+ /** Called with the page a step goes to; never past either end. */
16
+ onPageChange: (page: number) => void;
17
+ /**
18
+ * What the page shows, in the product's words, such as "1–25 of 130
19
+ * changes". It is announced politely when it changes.
20
+ */
21
+ rangeLabel: string;
22
+ labels: PaginationLabels;
23
+ };
24
+ /**
25
+ * Previous and next steps through a list shown a page at a time, beside
26
+ * the consumer's words for what the page shows, in a navigation landmark
27
+ * named by `aria-label` or `aria-labelledby`. Each step is an icon-only
28
+ * neutral Button named by `labels`. At either end its step looks disabled
29
+ * (`aria-disabled`) but stays a Tab stop, so focus is never dropped when
30
+ * the last page is reached, and a press there does nothing. Invalid pages
31
+ * or an empty step label (`labels.previous` or `labels.next`) throw a
32
+ * `RangeError`.
33
+ */
34
+ export declare const Pagination: import("react").ForwardRefExoticComponent<PaginationProps & import("react").RefAttributes<HTMLElement>>;
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from 'react';
3
+ import { cx } from '../class-names.js';
4
+ import { assertPaginationLabels, assertPaginationPages, paginationStep, } from '../pagination-pages.js';
5
+ import { Button } from './Button.js';
6
+ /**
7
+ * Previous and next steps through a list shown a page at a time, beside
8
+ * the consumer's words for what the page shows, in a navigation landmark
9
+ * named by `aria-label` or `aria-labelledby`. Each step is an icon-only
10
+ * neutral Button named by `labels`. At either end its step looks disabled
11
+ * (`aria-disabled`) but stays a Tab stop, so focus is never dropped when
12
+ * the last page is reached, and a press there does nothing. Invalid pages
13
+ * or an empty step label (`labels.previous` or `labels.next`) throw a
14
+ * `RangeError`.
15
+ */
16
+ export const Pagination = forwardRef(function Pagination({ className, labels, onPageChange, page, pageCount, rangeLabel, ...rest }, ref) {
17
+ assertPaginationPages(page, pageCount);
18
+ assertPaginationLabels(labels);
19
+ const step = (direction) => {
20
+ const target = paginationStep(page, pageCount, direction);
21
+ return (_jsx(Button, { "aria-disabled": target === null || undefined, "aria-label": labels[direction], className: "sw-pagination-step", disabledAppearance: "neutral", onPress: () => {
22
+ if (target !== null)
23
+ onPageChange(target);
24
+ }, size: "sm", variant: "neutral", children: _jsx("span", { "aria-hidden": "true", className: `sw-pagination-glyph sw-pagination-glyph-${direction}` }) }));
25
+ };
26
+ return (_jsxs("nav", { ref: ref, className: cx('sw-pagination', className), ...rest, children: [_jsx("span", { "aria-atomic": "true", "aria-live": "polite", className: "sw-pagination-range", children: rangeLabel }), _jsxs("span", { className: "sw-pagination-steps", children: [step('previous'), step('next')] })] }));
27
+ });
@@ -1,4 +1,4 @@
1
- import { type ReactNode } from 'react';
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
2
  type ScrollRegionProps = {
3
3
  children: ReactNode;
4
4
  className: string;
@@ -6,6 +6,8 @@ type ScrollRegionProps = {
6
6
  'aria-labelledby'?: string;
7
7
  /** Adds `sw-scroll-fits` once measured with content that fits its width. */
8
8
  markFits?: boolean;
9
+ /** Generated custom properties only, such as a bounded table's row count. */
10
+ style?: CSSProperties;
9
11
  };
10
12
  /**
11
13
  * Private wrapper that scrolls wide content inside its own box (see
@@ -14,9 +16,11 @@ type ScrollRegionProps = {
14
16
  * keyboard and is announced as one group. While content is scrolled out past
15
17
  * an inline edge, that edge draws a shade (`sw-scroll-more-start`,
16
18
  * `sw-scroll-more-end`), so a phone, whose scrollbars hide, still shows that
17
- * the table goes on. With `markFits`, a measured region whose content fits
18
- * its width carries `sw-scroll-fits`, so a table with a sticky footer can
19
- * stop being a scroll box and pin its header and footer to the page.
19
+ * the table goes on. A region of bounded height that scrolls its rows marks
20
+ * its top and bottom the same way (`sw-scroll-more-top`,
21
+ * `sw-scroll-more-bottom`). With `markFits`, a measured region whose content
22
+ * fits its width carries `sw-scroll-fits`, so a table with a sticky footer
23
+ * can stop being a scroll box and pin its header and footer to the page.
20
24
  */
21
- export declare function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits, }: ScrollRegionProps): import("react").JSX.Element;
25
+ export declare function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits, style, }: ScrollRegionProps): import("react").JSX.Element;
22
26
  export {};
@@ -10,16 +10,18 @@ import { useScrollOverflow } from './use-scroll-overflow.js';
10
10
  * keyboard and is announced as one group. While content is scrolled out past
11
11
  * an inline edge, that edge draws a shade (`sw-scroll-more-start`,
12
12
  * `sw-scroll-more-end`), so a phone, whose scrollbars hide, still shows that
13
- * the table goes on. With `markFits`, a measured region whose content fits
14
- * its width carries `sw-scroll-fits`, so a table with a sticky footer can
15
- * stop being a scroll box and pin its header and footer to the page.
13
+ * the table goes on. A region of bounded height that scrolls its rows marks
14
+ * its top and bottom the same way (`sw-scroll-more-top`,
15
+ * `sw-scroll-more-bottom`). With `markFits`, a measured region whose content
16
+ * fits its width carries `sw-scroll-fits`, so a table with a sticky footer
17
+ * can stop being a scroll box and pin its header and footer to the page.
16
18
  */
17
- export function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits = false, }) {
19
+ export function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits = false, style, }) {
18
20
  const ref = useRef(null);
19
21
  const overflow = useScrollOverflow(ref);
20
- return (_jsx("div", { ref: ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className: cx(className, overflow.start && 'sw-scroll-more-start', overflow.end && 'sw-scroll-more-end', markFits &&
22
+ return (_jsx("div", { ref: ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className: cx(className, overflow.start && 'sw-scroll-more-start', overflow.end && 'sw-scroll-more-end', overflow.top && 'sw-scroll-more-top', overflow.bottom && 'sw-scroll-more-bottom', markFits &&
21
23
  overflow.measured &&
22
24
  !overflow.start &&
23
25
  !overflow.end &&
24
- 'sw-scroll-fits'), role: "group", tabIndex: 0, children: children }));
26
+ 'sw-scroll-fits'), role: "group", style: style, tabIndex: 0, children: children }));
25
27
  }
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type AccessibleName } from '../accessible-name.js';
2
3
  import { type Breakpoint } from '../css/breakpoints.js';
3
4
  import { type SectionNavAppearance } from '../css/css-section-nav-filled.js';
4
5
  export type { SectionNavAppearance };
@@ -29,14 +30,7 @@ export type SectionNavItem = {
29
30
  */
30
31
  countLabel?: string;
31
32
  };
32
- type SectionNavLabel = {
33
- 'aria-label': string;
34
- 'aria-labelledby'?: never;
35
- } | {
36
- 'aria-label'?: never;
37
- 'aria-labelledby': string;
38
- };
39
- export type SectionNavProps = SectionNavLabel & {
33
+ export type SectionNavProps = AccessibleName & {
40
34
  items: readonly SectionNavItem[];
41
35
  /**
42
36
  * Called for a plain press on an item (the main button, no modifier key),
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type AccessibleName } from '../accessible-name.js';
2
3
  export type SegmentedItem = {
3
4
  id: string;
4
5
  label: ReactNode;
@@ -11,13 +12,6 @@ export type SegmentedItem = {
11
12
  */
12
13
  icon?: ReactNode;
13
14
  };
14
- type SegmentedLabel = {
15
- 'aria-label': string;
16
- 'aria-labelledby'?: never;
17
- } | {
18
- 'aria-label'?: never;
19
- 'aria-labelledby': string;
20
- };
21
15
  /**
22
16
  * `compact` is the quiet chip track for a section switch; `filled` gives every
23
17
  * segment the same width and paints the selected one in the accent, for a
@@ -40,7 +34,7 @@ type SegmentedChange = {
40
34
  disabled: true;
41
35
  onChange?: (id: string) => void;
42
36
  };
43
- export type SegmentedControlProps = SegmentedLabel & SegmentedChange & {
37
+ export type SegmentedControlProps = AccessibleName & SegmentedChange & {
44
38
  items: readonly SegmentedItem[];
45
39
  value: string;
46
40
  variant?: SegmentedControlVariant;
@@ -1,10 +1,11 @@
1
1
  import { type HTMLAttributes } from 'react';
2
2
  import { type TableLayout, type TableStickyHeader, type TableVerticalAlign } from './table/table-layout.js';
3
+ import { type TableMaxHeight } from './table/table-max-height.js';
3
4
  export { TableCell, type TableCellProps, type TableColumnWidth, type TableSort, } from './table/TableCell.js';
4
5
  export { TableRow, type TableRowProps, type TableRowVariant, } from './table/TableRow.js';
5
6
  export type { TableCellTone } from '../css/css-table-ledger.js';
6
7
  export { tableCellTones, tableRowVariants } from '../css/css-table-ledger.js';
7
- export type { TableLayout, TableStickyHeader, TableVerticalAlign };
8
+ export type { TableLayout, TableMaxHeight, TableStickyHeader, TableVerticalAlign, };
8
9
  export type TableDensity = 'comfortable' | 'compact';
9
10
  export type TableProps = HTMLAttributes<HTMLTableElement> & {
10
11
  density?: TableDensity;
@@ -40,8 +41,30 @@ export type TableProps = HTMLAttributes<HTMLTableElement> & {
40
41
  * after a row's first, for a ledger read across as well as down.
41
42
  */
42
43
  columnRules?: boolean;
44
+ /**
45
+ * Bounds the table's height, counted in rows (`{ rows: 12 }`): its region
46
+ * is as tall as that many single-line body rows plus the header row (a
47
+ * sorting header as tall as its buttons, the touch target on a coarse
48
+ * pointer) and, when there is one, the footer row, and the rest of the
49
+ * rows scroll inside it. Rows of two lines or with controls, a second
50
+ * header or footer row and a horizontal scrollbar that takes room show
51
+ * fewer rows. The header pins to the region's top and a sticky
52
+ * `TableFooter` total to its bottom, so a total over every row stays in
53
+ * view. The region is a keyboard stop named after the table, its focus
54
+ * ring drawn over the pinned rows too, and an edge with rows scrolled
55
+ * out past it draws a shade (cast from the pinned header's last row or
56
+ * the total when there is one). Printed, every row shows. It keeps its
57
+ * header pinned to the region, so `stickyHeader` `'page'` or `false`
58
+ * throw with it, as do a value that is not `{ rows }` and a row count
59
+ * that is not a whole number from 1. Without it (the default) the table
60
+ * is as tall as its rows.
61
+ */
62
+ maxHeight?: TableMaxHeight;
43
63
  };
44
- /** A wide table scrolls inside its own `ScrollRegion`, named after the table. */
64
+ /**
65
+ * A wide table scrolls inside its own `ScrollRegion`, named after the
66
+ * table; a bounded one (`maxHeight`) scrolls its rows in it too.
67
+ */
45
68
  export declare const Table: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLTableElement> & {
46
69
  density?: TableDensity;
47
70
  /**
@@ -76,6 +99,25 @@ export declare const Table: import("react").ForwardRefExoticComponent<HTMLAttrib
76
99
  * after a row's first, for a ledger read across as well as down.
77
100
  */
78
101
  columnRules?: boolean;
102
+ /**
103
+ * Bounds the table's height, counted in rows (`{ rows: 12 }`): its region
104
+ * is as tall as that many single-line body rows plus the header row (a
105
+ * sorting header as tall as its buttons, the touch target on a coarse
106
+ * pointer) and, when there is one, the footer row, and the rest of the
107
+ * rows scroll inside it. Rows of two lines or with controls, a second
108
+ * header or footer row and a horizontal scrollbar that takes room show
109
+ * fewer rows. The header pins to the region's top and a sticky
110
+ * `TableFooter` total to its bottom, so a total over every row stays in
111
+ * view. The region is a keyboard stop named after the table, its focus
112
+ * ring drawn over the pinned rows too, and an edge with rows scrolled
113
+ * out past it draws a shade (cast from the pinned header's last row or
114
+ * the total when there is one). Printed, every row shows. It keeps its
115
+ * header pinned to the region, so `stickyHeader` `'page'` or `false`
116
+ * throw with it, as do a value that is not `{ rows }` and a row count
117
+ * that is not a whole number from 1. Without it (the default) the table
118
+ * is as tall as its rows.
119
+ */
120
+ maxHeight?: TableMaxHeight;
79
121
  } & import("react").RefAttributes<HTMLTableElement>>;
80
122
  export type TableHeaderProps = HTMLAttributes<HTMLTableSectionElement>;
81
123
  export declare const TableHeader: import("react").ForwardRefExoticComponent<TableHeaderProps & import("react").RefAttributes<HTMLTableSectionElement>>;
@@ -87,7 +129,8 @@ export type TableFooterProps = HTMLAttributes<HTMLTableSectionElement> & {
87
129
  * scroll under it: to the page while the table fits its width (the
88
130
  * sticky header then pins to the page's top too, under any sticky
89
131
  * AppHeader, which covers it), or to the table's own region while the
90
- * table scrolls sideways in it. A sticky ActionBar covers a pinned
132
+ * table scrolls sideways in it or is bounded (`Table maxHeight`), where
133
+ * it stays at the region's bottom. A sticky ActionBar covers a pinned
91
134
  * footer, and so does a Dialog's pinned footer, so do not pair them.
92
135
  */
93
136
  sticky?: boolean;
@@ -103,7 +146,8 @@ export declare const TableFooter: import("react").ForwardRefExoticComponent<HTML
103
146
  * scroll under it: to the page while the table fits its width (the
104
147
  * sticky header then pins to the page's top too, under any sticky
105
148
  * AppHeader, which covers it), or to the table's own region while the
106
- * table scrolls sideways in it. A sticky ActionBar covers a pinned
149
+ * table scrolls sideways in it or is bounded (`Table maxHeight`), where
150
+ * it stays at the region's bottom. A sticky ActionBar covers a pinned
107
151
  * footer, and so does a Dialog's pinned footer, so do not pair them.
108
152
  */
109
153
  sticky?: boolean;
@@ -3,15 +3,21 @@ import { forwardRef } from 'react';
3
3
  import { cx } from '../class-names.js';
4
4
  import { ScrollRegion } from './ScrollRegion.js';
5
5
  import { assertTableLayout, assertTableStickyHeader, assertTableVerticalAlign, } from './table/table-layout.js';
6
+ import { assertTableMaxHeight, tableMaxHeightStyle, } from './table/table-max-height.js';
6
7
  export { TableCell, } from './table/TableCell.js';
7
8
  export { TableRow, } from './table/TableRow.js';
8
9
  export { tableCellTones, tableRowVariants } from '../css/css-table-ledger.js';
9
- /** A wide table scrolls inside its own `ScrollRegion`, named after the table. */
10
- export const Table = forwardRef(function Table({ children, className, columnRules = false, density = 'comfortable', layout = 'auto', stickyHeader = true, verticalAlign = 'middle', ...rest }, ref) {
10
+ /**
11
+ * A wide table scrolls inside its own `ScrollRegion`, named after the
12
+ * table; a bounded one (`maxHeight`) scrolls its rows in it too.
13
+ */
14
+ export const Table = forwardRef(function Table({ children, className, columnRules = false, density = 'comfortable', layout = 'auto', maxHeight, stickyHeader = true, verticalAlign = 'middle', ...rest }, ref) {
11
15
  assertTableLayout(layout);
12
16
  assertTableStickyHeader(stickyHeader);
13
17
  assertTableVerticalAlign(verticalAlign);
14
- return (_jsx(ScrollRegion, { "aria-label": rest['aria-label'], "aria-labelledby": rest['aria-labelledby'], className: "sw-table-wrap", markFits: true, children: _jsx("table", { ref: ref, className: cx('sw-table', density === 'compact' && 'sw-table-compact', layout === 'fixed' && 'sw-table-fixed', stickyHeader !== false && 'sw-table-sticky', stickyHeader === 'page' && 'sw-table-sticky-page', verticalAlign === 'top' && 'sw-table-top', columnRules && 'sw-table-column-rules', className), ...rest, children: children }) }));
18
+ assertTableMaxHeight(maxHeight, stickyHeader);
19
+ const bounded = maxHeight !== undefined;
20
+ return (_jsx(ScrollRegion, { "aria-label": rest['aria-label'], "aria-labelledby": rest['aria-labelledby'], className: cx('sw-table-wrap', bounded && 'sw-table-bounded'), markFits: !bounded, style: tableMaxHeightStyle(maxHeight), children: _jsx("table", { ref: ref, className: cx('sw-table', density === 'compact' && 'sw-table-compact', layout === 'fixed' && 'sw-table-fixed', stickyHeader !== false && 'sw-table-sticky', stickyHeader === 'page' && 'sw-table-sticky-page', verticalAlign === 'top' && 'sw-table-top', columnRules && 'sw-table-column-rules', className), ...rest, children: children }) }));
15
21
  });
16
22
  export const TableHeader = forwardRef(function TableHeader({ className, ...rest }, ref) {
17
23
  return _jsx("thead", { ref: ref, className: className, ...rest });
@@ -1,16 +1,10 @@
1
1
  import { type HTMLAttributes, type ReactNode } from 'react';
2
+ import { type AccessibleName } from '../accessible-name.js';
2
3
  export type TabItem = {
3
4
  id: string;
4
5
  label: ReactNode;
5
6
  };
6
- type TabsLabel = {
7
- 'aria-label': string;
8
- 'aria-labelledby'?: never;
9
- } | {
10
- 'aria-label'?: never;
11
- 'aria-labelledby': string;
12
- };
13
- export type TabsProps = TabsLabel & {
7
+ export type TabsProps = AccessibleName & {
14
8
  /** Prefix for the tab and panel ids, so a `TabPanel` can point back at its tab. */
15
9
  id: string;
16
10
  items: readonly TabItem[];
@@ -58,4 +52,3 @@ export type TabPanelProps = Omit<HTMLAttributes<HTMLDivElement>, 'id'> & {
58
52
  };
59
53
  /** The content of one tab, labelled by its tab and hidden while another tab is current. */
60
54
  export declare function TabPanel({ children, className, id, tabsId, value, ...rest }: TabPanelProps): import("react").JSX.Element;
61
- export {};
@@ -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;