@scalewing/react 1.38.0 → 1.40.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/CHANGELOG.md +18 -0
- package/README.md +155 -1
- package/dist/calendar-month.d.ts +6 -0
- package/dist/calendar-month.js +15 -0
- package/dist/chart-axis.d.ts +61 -0
- package/dist/chart-axis.js +83 -0
- package/dist/chart-dates.d.ts +6 -0
- package/dist/chart-dates.js +15 -0
- package/dist/chart-metrics.d.ts +40 -0
- package/dist/chart-metrics.js +48 -0
- package/dist/chart-scale.d.ts +48 -0
- package/dist/chart-scale.js +116 -0
- package/dist/chart-table-rows.d.ts +8 -0
- package/dist/chart-table-rows.js +1 -0
- package/dist/column-chart-bars.d.ts +38 -0
- package/dist/column-chart-bars.js +82 -0
- package/dist/column-chart-callouts.d.ts +48 -0
- package/dist/column-chart-callouts.js +54 -0
- package/dist/column-chart-input.d.ts +40 -0
- package/dist/column-chart-input.js +60 -0
- package/dist/column-chart-layout.d.ts +63 -0
- package/dist/column-chart-layout.js +97 -0
- package/dist/components/BarChart.d.ts +1 -1
- package/dist/components/BarChart.js +1 -1
- package/dist/components/ChartLegend.d.ts +38 -0
- package/dist/components/ChartLegend.js +32 -0
- package/dist/components/ColumnChart.d.ts +72 -0
- package/dist/components/ColumnChart.js +71 -0
- package/dist/components/DataBar.d.ts +6 -6
- package/dist/components/DateRangeButton.d.ts +65 -0
- package/dist/components/DateRangeButton.js +54 -0
- package/dist/components/LineChart.d.ts +83 -0
- package/dist/components/LineChart.js +77 -0
- package/dist/components/ListGroup.d.ts +33 -0
- package/dist/components/ListGroup.js +19 -0
- package/dist/components/ListRow.d.ts +51 -0
- package/dist/components/ListRow.js +59 -0
- package/dist/components/NavCount.d.ts +21 -0
- package/dist/components/NavCount.js +23 -0
- package/dist/components/SectionNav.js +1 -8
- package/dist/components/StatTile.d.ts +11 -4
- package/dist/components/StatTile.js +11 -4
- package/dist/components/{date-field → calendar}/CalendarGrid.d.ts +17 -2
- package/dist/components/{date-field → calendar}/CalendarGrid.js +11 -3
- package/dist/components/calendar/CalendarPopover.d.ts +25 -0
- package/dist/components/calendar/CalendarPopover.js +22 -0
- package/dist/components/calendar/MonthStep.d.ts +16 -0
- package/dist/components/calendar/MonthStep.js +17 -0
- package/dist/components/calendar/use-grid-focus.d.ts +18 -0
- package/dist/components/calendar/use-grid-focus.js +35 -0
- package/dist/components/calendar/wrap-tab.d.ts +7 -0
- package/dist/components/calendar/wrap-tab.js +29 -0
- package/dist/components/chart/ChartTable.d.ts +16 -0
- package/dist/components/chart/ChartTable.js +12 -0
- package/dist/components/chart/ChartValueAxis.d.ts +14 -0
- package/dist/components/chart/ChartValueAxis.js +11 -0
- package/dist/components/chart/use-chart-width.d.ts +8 -0
- package/dist/components/chart/use-chart-width.js +34 -0
- package/dist/components/column-chart/ChartCalloutList.d.ts +16 -0
- package/dist/components/column-chart/ChartCalloutList.js +13 -0
- package/dist/components/column-chart/ColumnChartDrawing.d.ts +17 -0
- package/dist/components/column-chart/ColumnChartDrawing.js +18 -0
- package/dist/components/date-field/CalendarDialog.js +9 -67
- package/dist/components/date-field/CalendarHeader.js +2 -11
- package/dist/components/date-range/DateRangePopover.d.ts +7 -0
- package/dist/components/date-range/DateRangePopover.js +17 -0
- package/dist/components/date-range/DateRangeSheet.d.ts +7 -0
- package/dist/components/date-range/DateRangeSheet.js +15 -0
- package/dist/components/date-range/RangeMonths.d.ts +28 -0
- package/dist/components/date-range/RangeMonths.js +50 -0
- package/dist/components/date-range/RangePresets.d.ts +16 -0
- package/dist/components/date-range/RangePresets.js +10 -0
- package/dist/components/date-range/RangeSummary.d.ts +15 -0
- package/dist/components/date-range/RangeSummary.js +11 -0
- package/dist/components/date-range/range-panel-props.d.ts +31 -0
- package/dist/components/date-range/range-panel-props.js +1 -0
- package/dist/components/date-range/use-range-popup.d.ts +21 -0
- package/dist/components/date-range/use-range-popup.js +53 -0
- package/dist/components/line-chart/LineChartDrawing.d.ts +17 -0
- package/dist/components/line-chart/LineChartDrawing.js +16 -0
- package/dist/components/link-press.d.ts +7 -0
- package/dist/components/link-press.js +13 -0
- package/dist/components/list/ListRowAccessoryMark.d.ts +5 -0
- package/dist/components/list/ListRowAccessoryMark.js +7 -0
- package/dist/components/list/ListRowContent.d.ts +20 -0
- package/dist/components/list/ListRowContent.js +10 -0
- package/dist/components/list/list-row-container.d.ts +5 -0
- package/dist/components/list/list-row-container.js +6 -0
- package/dist/components/use-media-query.d.ts +5 -0
- package/dist/components/use-media-query.js +18 -0
- package/dist/css/chart-marks.d.ts +10 -0
- package/dist/css/chart-marks.js +15 -0
- package/dist/css/chart-tones.d.ts +68 -0
- package/dist/css/chart-tones.js +130 -0
- package/dist/css/chevron.d.ts +6 -0
- package/dist/css/chevron.js +14 -0
- package/dist/css/{css-chart.d.ts → css-bar-chart.d.ts} +2 -2
- package/dist/css/{css-chart.js → css-bar-chart.js} +2 -2
- package/dist/css/css-button-group-attached.js +8 -4
- package/dist/css/css-button-group-track.js +1 -1
- package/dist/css/css-chart-legend.d.ts +5 -0
- package/dist/css/css-chart-legend.js +102 -0
- package/dist/css/css-chart-plot.d.ts +2 -0
- package/dist/css/css-chart-plot.js +170 -0
- package/dist/css/css-checkbox.js +2 -2
- package/dist/css/css-components.js +23 -2
- package/dist/css/css-count-pill.d.ts +2 -0
- package/dist/css/css-count-pill.js +54 -0
- package/dist/css/css-data-bar.d.ts +4 -9
- package/dist/css/css-data-bar.js +15 -31
- package/dist/css/css-date-field.js +3 -2
- package/dist/css/css-date-range-presets.d.ts +2 -0
- package/dist/css/css-date-range-presets.js +109 -0
- package/dist/css/css-date-range.d.ts +2 -0
- package/dist/css/css-date-range.js +197 -0
- package/dist/css/css-line-chart.d.ts +2 -0
- package/dist/css/css-line-chart.js +31 -0
- package/dist/css/css-list-row.d.ts +2 -0
- package/dist/css/css-list-row.js +193 -0
- package/dist/css/css-list.d.ts +3 -0
- package/dist/css/css-list.js +85 -0
- package/dist/css/css-scroll-region.d.ts +18 -0
- package/dist/css/css-scroll-region.js +41 -0
- package/dist/css/css-section-nav-filled.js +2 -25
- package/dist/css/css-stat-tile.d.ts +7 -0
- package/dist/css/css-stat-tile.js +16 -0
- package/dist/css/css-steps.js +2 -2
- package/dist/css/css-table-bounded-edges.js +4 -27
- package/dist/css/range-band.d.ts +2 -0
- package/dist/css/range-band.js +7 -0
- package/dist/css/stacking.js +2 -2
- package/dist/css/stylesheet.js +16 -2
- package/dist/date-range-draft.d.ts +26 -0
- package/dist/date-range-draft.js +36 -0
- package/dist/date-range-input.d.ts +26 -0
- package/dist/date-range-input.js +58 -0
- package/dist/date-range-labels.d.ts +22 -0
- package/dist/date-range-labels.js +26 -0
- package/dist/date-range-view.d.ts +12 -0
- package/dist/date-range-view.js +29 -0
- package/dist/date-range-words.d.ts +11 -0
- package/dist/date-range-words.js +40 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +9 -1
- package/dist/is-one-of.d.ts +5 -0
- package/dist/is-one-of.js +7 -0
- package/dist/line-chart-input.d.ts +39 -0
- package/dist/line-chart-input.js +70 -0
- package/dist/line-chart-layout.d.ts +68 -0
- package/dist/line-chart-layout.js +99 -0
- package/dist/line-chart-markers.d.ts +29 -0
- package/dist/line-chart-markers.js +57 -0
- package/dist/line-chart-path.d.ts +18 -0
- package/dist/line-chart-path.js +33 -0
- package/dist/line-chart-points.d.ts +6 -0
- package/dist/line-chart-points.js +8 -0
- package/dist/line-chart-table.d.ts +15 -0
- package/dist/line-chart-table.js +29 -0
- package/dist/list-options.d.ts +70 -0
- package/dist/list-options.js +77 -0
- package/dist/styles.css +726 -26
- package/package.json +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
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 { chartFillTones, chartStrokeTones, } from '../css/chart-tones.js';
|
|
5
|
+
import { chartLegendSwatches, } from '../css/css-chart-legend.js';
|
|
6
|
+
import { isOneOf } from '../is-one-of.js';
|
|
7
|
+
export { chartFillTones, chartLegendSwatches, chartStrokeTones };
|
|
8
|
+
/** Refuses empty words, and a swatch or a tone the item cannot draw. */
|
|
9
|
+
function assertLegendItem(item) {
|
|
10
|
+
if (typeof item.label !== 'string' || item.label.trim() === '')
|
|
11
|
+
throw new RangeError('ChartLegend item label must not be empty');
|
|
12
|
+
if (!isOneOf(chartLegendSwatches, item.swatch))
|
|
13
|
+
throw new RangeError(`ChartLegend swatch must be one of ${chartLegendSwatches.join(', ')}; received ${String(item.swatch)}`);
|
|
14
|
+
const tones = item.swatch === 'bar' ? chartFillTones : chartStrokeTones;
|
|
15
|
+
if (!isOneOf(tones, item.tone))
|
|
16
|
+
throw new RangeError(`ChartLegend ${item.swatch} tone must be one of ${tones.join(', ')}; received ${String(item.tone)}`);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A chart's key: a list of its marks, each a swatch and its words, in a
|
|
20
|
+
* wrapping row in the caption type. Put it above the chart it names, or
|
|
21
|
+
* above a statement's range bars. The swatches are decorative
|
|
22
|
+
* (`aria-hidden`), so each item reads as its words; the list keeps its
|
|
23
|
+
* list role where a style would drop it. Empty words, or a swatch or tone the
|
|
24
|
+
* item cannot draw, throw a `RangeError`.
|
|
25
|
+
*/
|
|
26
|
+
export const ChartLegend = forwardRef(function ChartLegend({ className, items, ...rest }, ref) {
|
|
27
|
+
for (const item of items)
|
|
28
|
+
assertLegendItem(item);
|
|
29
|
+
return (_jsx("ul", { ref: ref, className: cx('sw-chart-legend', className),
|
|
30
|
+
// A list styled without markers loses its role in Safari.
|
|
31
|
+
role: "list", ...rest, children: items.map((item, index) => (_jsxs("li", { className: cx('sw-chart-legend-item', `sw-chart-tone-${item.tone}`), children: [_jsx("span", { "aria-hidden": "true", className: cx('sw-chart-legend-swatch', `sw-chart-legend-${item.swatch}`) }), item.label] }, `${item.label}-${index}`))) }));
|
|
32
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
import { type ColumnChartMode, columnChartModes } from '../column-chart-bars.js';
|
|
3
|
+
import { type ColumnChartCallout, type ColumnChartLine, type ColumnChartSeries } from '../column-chart-input.js';
|
|
4
|
+
export type { ColumnChartCallout, ColumnChartLine, ColumnChartMode, ColumnChartSeries, };
|
|
5
|
+
export { columnChartModes };
|
|
6
|
+
export type ColumnChartProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
7
|
+
/** Names the chart: the caption of the table that carries its figures. */
|
|
8
|
+
label: string;
|
|
9
|
+
/** The columns' places, such as weeks, in order; each is a row's header. */
|
|
10
|
+
categories: readonly string[];
|
|
11
|
+
/** Each series: a value per category, drawn in a categorical hue. */
|
|
12
|
+
series: readonly ColumnChartSeries[];
|
|
13
|
+
/**
|
|
14
|
+
* `stacked` (the default) puts a category's columns on one another,
|
|
15
|
+
* positive values up from zero and negative ones down from it;
|
|
16
|
+
* `grouped` sets them side by side, each from zero.
|
|
17
|
+
*/
|
|
18
|
+
mode?: ColumnChartMode;
|
|
19
|
+
/** A line over the columns, such as a running total, on its own scale. */
|
|
20
|
+
line?: ColumnChartLine;
|
|
21
|
+
/** The index of the category to box, such as the current week. */
|
|
22
|
+
highlight?: number;
|
|
23
|
+
/** Words pinned above a category's column, with a leader down to it. */
|
|
24
|
+
callouts?: readonly ColumnChartCallout[];
|
|
25
|
+
/**
|
|
26
|
+
* Writes each figure in the table and the line's last value, such as a
|
|
27
|
+
* currency. Defaults to a plain number with at most one decimal.
|
|
28
|
+
*/
|
|
29
|
+
formatValue?: (value: number) => string;
|
|
30
|
+
/** Writes the axes' values, shorter if need be; defaults to `formatValue`. */
|
|
31
|
+
formatTick?: (value: number) => string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Columns for each category (a week, a month), stacked or grouped by
|
|
35
|
+
* series, with an optional line on its own right-hand scale whose zero
|
|
36
|
+
* and grid lines are level with the columns', the current period boxed
|
|
37
|
+
* and callouts pinned above their columns. It fills its container's width
|
|
38
|
+
* and is laid out for it: a narrow chart labels fewer categories and lists
|
|
39
|
+
* its callouts under the plot, never scrolling sideways. The drawing is
|
|
40
|
+
* hidden from assistive technology; a visually hidden table named by
|
|
41
|
+
* `label` carries every figure, and the callouts stay a list. Put it on
|
|
42
|
+
* the surface (a `Card`) with a `ChartLegend` above it naming each series
|
|
43
|
+
* (`bar` in its tone), the line (`line`, `accent`) and the box (`box`,
|
|
44
|
+
* `accent`). Input it cannot draw throws a `RangeError`.
|
|
45
|
+
*/
|
|
46
|
+
export declare const ColumnChart: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
47
|
+
/** Names the chart: the caption of the table that carries its figures. */
|
|
48
|
+
label: string;
|
|
49
|
+
/** The columns' places, such as weeks, in order; each is a row's header. */
|
|
50
|
+
categories: readonly string[];
|
|
51
|
+
/** Each series: a value per category, drawn in a categorical hue. */
|
|
52
|
+
series: readonly ColumnChartSeries[];
|
|
53
|
+
/**
|
|
54
|
+
* `stacked` (the default) puts a category's columns on one another,
|
|
55
|
+
* positive values up from zero and negative ones down from it;
|
|
56
|
+
* `grouped` sets them side by side, each from zero.
|
|
57
|
+
*/
|
|
58
|
+
mode?: ColumnChartMode;
|
|
59
|
+
/** A line over the columns, such as a running total, on its own scale. */
|
|
60
|
+
line?: ColumnChartLine;
|
|
61
|
+
/** The index of the category to box, such as the current week. */
|
|
62
|
+
highlight?: number;
|
|
63
|
+
/** Words pinned above a category's column, with a leader down to it. */
|
|
64
|
+
callouts?: readonly ColumnChartCallout[];
|
|
65
|
+
/**
|
|
66
|
+
* Writes each figure in the table and the line's last value, such as a
|
|
67
|
+
* currency. Defaults to a plain number with at most one decimal.
|
|
68
|
+
*/
|
|
69
|
+
formatValue?: (value: number) => string;
|
|
70
|
+
/** Writes the axes' values, shorter if need be; defaults to `formatValue`. */
|
|
71
|
+
formatTick?: (value: number) => string;
|
|
72
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -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
|
|
17
|
-
* danger
|
|
18
|
-
*
|
|
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
|
|
44
|
-
* danger
|
|
45
|
-
*
|
|
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,65 @@
|
|
|
1
|
+
import { type WeekStart } from '../calendar-month.js';
|
|
2
|
+
import { type DateRangePreset } from '../date-range-input.js';
|
|
3
|
+
import { type DateRangeButtonLabels } from '../date-range-labels.js';
|
|
4
|
+
import { type DateOnlyRange } from '../date-only.js';
|
|
5
|
+
import { type ButtonSize, type ButtonVariant } from './Button.js';
|
|
6
|
+
export type { DateRangeButtonLabels, DateRangePreset };
|
|
7
|
+
/** A span of calendar days `YYYY-MM-DD`, both ends included. */
|
|
8
|
+
export type DateRangeButtonValue = DateOnlyRange;
|
|
9
|
+
export type DateRangeButtonProps = {
|
|
10
|
+
/**
|
|
11
|
+
* What pressing it does, such as "Choose a period". The button's name is
|
|
12
|
+
* this label, `labels.nameSeparator`, then the range it shows; the
|
|
13
|
+
* popover and the sheet are named by it.
|
|
14
|
+
*/
|
|
15
|
+
label: string;
|
|
16
|
+
/**
|
|
17
|
+
* The range shown, `{ start, end }` as `YYYY-MM-DD`, start not after end.
|
|
18
|
+
* A range outside `min`/`max` or longer than `maxDays` stays the value.
|
|
19
|
+
*/
|
|
20
|
+
value: DateRangeButtonValue;
|
|
21
|
+
/** Receives a new range on Apply or a preset, never converted through UTC. */
|
|
22
|
+
onChange: (value: DateRangeButtonValue) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Ranges chosen in one press, such as "Last 7 days": a list beside the
|
|
25
|
+
* months (a row above the month on a phone). A press applies its range
|
|
26
|
+
* and closes. Each must lie inside `min`/`max` and `maxDays`.
|
|
27
|
+
*/
|
|
28
|
+
presets?: readonly DateRangePreset[];
|
|
29
|
+
min?: string;
|
|
30
|
+
/** The last day that can be picked, such as today. */
|
|
31
|
+
max?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The longest range, in days with both ends counted: once a first day is
|
|
34
|
+
* pressed, the days after this many are disabled.
|
|
35
|
+
*/
|
|
36
|
+
maxDays?: number;
|
|
37
|
+
/**
|
|
38
|
+
* The calendar's today `YYYY-MM-DD`, the day it marks. Defaults to the
|
|
39
|
+
* device's local date; pass the business's day when it keeps its own.
|
|
40
|
+
*/
|
|
41
|
+
today?: string;
|
|
42
|
+
disabled?: boolean;
|
|
43
|
+
/** The `<button>` element's id. */
|
|
44
|
+
id?: string;
|
|
45
|
+
/**
|
|
46
|
+
* BCP 47 tag for the dates and the calendar's month and weekday names.
|
|
47
|
+
* Defaults to the nearest `lang` attribute, then en-US.
|
|
48
|
+
*/
|
|
49
|
+
locale?: string;
|
|
50
|
+
/** First column of the calendar: 0 Sunday (default) or 1 Monday. */
|
|
51
|
+
weekStartsOn?: WeekStart;
|
|
52
|
+
/** The calendar's words; English by default. */
|
|
53
|
+
labels?: Partial<DateRangeButtonLabels>;
|
|
54
|
+
/** A Button size; a coarse pointer gets a 44 px target. */
|
|
55
|
+
size?: ButtonSize;
|
|
56
|
+
/** Default `neutral`, the quiet grey of a page's period controls. */
|
|
57
|
+
variant?: ButtonVariant;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* A button showing a range of days that opens a calendar to pick a first
|
|
61
|
+
* and a last day: from `md` up a popover with the presets and two months,
|
|
62
|
+
* below it a bottom sheet with one month. Apply gives the range; Cancel,
|
|
63
|
+
* Escape and a press outside keep the value. The ref reaches the `<button>`.
|
|
64
|
+
*/
|
|
65
|
+
export declare const DateRangeButton: import("react").ForwardRefExoticComponent<DateRangeButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useCallback } from 'react';
|
|
4
|
+
import { breakpointQuery } from '../css/breakpoints.js';
|
|
5
|
+
import { latestPick, rangeDayCount, sameRange } from '../date-range-draft.js';
|
|
6
|
+
import { assertDateRangeInput, } from '../date-range-input.js';
|
|
7
|
+
import { resolveDateRangeButtonLabels, } from '../date-range-labels.js';
|
|
8
|
+
import { formatRangeLong, formatRangeShort } from '../date-range-words.js';
|
|
9
|
+
import { todayDateOnly } from '../date-only.js';
|
|
10
|
+
import { Button } from './Button.js';
|
|
11
|
+
import { DateFieldGlyph } from './date-field/DateFieldGlyph.js';
|
|
12
|
+
import { useLangLocale } from './date-field/use-lang-locale.js';
|
|
13
|
+
import { DateRangePopover } from './date-range/DateRangePopover.js';
|
|
14
|
+
import { DateRangeSheet } from './date-range/DateRangeSheet.js';
|
|
15
|
+
import { useRangePopup } from './date-range/use-range-popup.js';
|
|
16
|
+
import { useMediaQuery } from './use-media-query.js';
|
|
17
|
+
/** Sets a forwarded ref, callback or object, to the same node. */
|
|
18
|
+
function setForwardedRef(ref, node) {
|
|
19
|
+
if (typeof ref === 'function')
|
|
20
|
+
ref(node);
|
|
21
|
+
else if (ref)
|
|
22
|
+
ref.current = node;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A button showing a range of days that opens a calendar to pick a first
|
|
26
|
+
* and a last day: from `md` up a popover with the presets and two months,
|
|
27
|
+
* below it a bottom sheet with one month. Apply gives the range; Cancel,
|
|
28
|
+
* Escape and a press outside keep the value. The ref reaches the `<button>`.
|
|
29
|
+
*/
|
|
30
|
+
export const DateRangeButton = forwardRef(function DateRangeButton({ label, value, onChange, presets = [], min, max, maxDays, today, disabled = false, id, locale, weekStartsOn = 0, labels, size = 'md', variant = 'neutral', }, ref) {
|
|
31
|
+
assertDateRangeInput({
|
|
32
|
+
label,
|
|
33
|
+
value,
|
|
34
|
+
presets,
|
|
35
|
+
min,
|
|
36
|
+
max,
|
|
37
|
+
maxDays,
|
|
38
|
+
today,
|
|
39
|
+
weekStartsOn,
|
|
40
|
+
});
|
|
41
|
+
const words = resolveDateRangeButtonLabels(labels);
|
|
42
|
+
const popup = useRangePopup(value, disabled, onChange);
|
|
43
|
+
const resolvedLocale = useLangLocale(locale, popup.buttonRef);
|
|
44
|
+
const wide = useMediaQuery(breakpointQuery('from', 'md'), true);
|
|
45
|
+
const { buttonRef } = popup;
|
|
46
|
+
const setButton = useCallback((node) => {
|
|
47
|
+
buttonRef.current = node;
|
|
48
|
+
setForwardedRef(ref, node);
|
|
49
|
+
}, [buttonRef, ref]);
|
|
50
|
+
const { range } = popup.draft;
|
|
51
|
+
const shown = formatRangeShort(value, resolvedLocale);
|
|
52
|
+
const Panel = wide ? DateRangePopover : DateRangeSheet;
|
|
53
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Button, { "aria-controls": popup.shown ? popup.id : undefined, "aria-expanded": popup.shown, "aria-haspopup": "dialog", className: "sw-date-range-button", disabled: disabled, id: id, onPress: popup.toggle, ref: setButton, size: size, variant: variant, children: [_jsx("span", { className: "sw-sr-only", children: `${label}${words.nameSeparator}${shown}` }), _jsx(DateFieldGlyph, { name: "calendar" }), _jsx("span", { "aria-hidden": "true", children: shown })] }), popup.shown ? (_jsx(Panel, { buttonRef: buttonRef, count: words.dayCount(rangeDayCount(range)), draft: popup.draft, id: popup.id, label: label, labels: words, latest: latestPick(popup.draft, max, maxDays), line: formatRangeLong(range, resolvedLocale), locale: resolvedLocale, max: max, min: min, onApply: () => popup.apply(range), onCancel: popup.cancel, onChoosePreset: (preset) => popup.apply(preset.range), onPress: popup.press, presets: presets, pressedPresetId: presets.find((preset) => sameRange(preset.range, range))?.id, today: today ?? todayDateOnly(), weekStartsOn: weekStartsOn })) : null] }));
|
|
54
|
+
});
|
|
@@ -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,33 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type ListGroupMaxHeight, type ListGroupVariant } from '../list-options.js';
|
|
3
|
+
export type ListGroupProps = {
|
|
4
|
+
/** `ListRow` elements; the group draws a hairline between each pair. */
|
|
5
|
+
children: ReactNode;
|
|
6
|
+
/** Names the list, such as its card's heading. Required with `maxHeight`. */
|
|
7
|
+
'aria-label'?: string;
|
|
8
|
+
'aria-labelledby'?: string;
|
|
9
|
+
/**
|
|
10
|
+
* `panel` (the default) is one bordered panel; `plain` draws no panel
|
|
11
|
+
* and a hairline above the first row too, for rows inside a Card.
|
|
12
|
+
*/
|
|
13
|
+
variant?: ListGroupVariant;
|
|
14
|
+
/**
|
|
15
|
+
* Bounds the list to a row count of its own region, `{ rows }` rows of a
|
|
16
|
+
* title and one detail line, where the rest scroll; the region is a named
|
|
17
|
+
* keyboard stop and shades an edge with more rows past it.
|
|
18
|
+
*/
|
|
19
|
+
maxHeight?: ListGroupMaxHeight;
|
|
20
|
+
/**
|
|
21
|
+
* Pinned under the rows, outside the scroll, under a hairline: a total
|
|
22
|
+
* the rows add up to, such as a `ListRow` with the count and the sum.
|
|
23
|
+
*/
|
|
24
|
+
footer?: ReactNode;
|
|
25
|
+
className?: string;
|
|
26
|
+
id?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Rows in one list (`ul`, its list role kept) with hairlines between them:
|
|
30
|
+
* a panel of its own, or plain rows inside a surface. The ref reaches the
|
|
31
|
+
* outer box.
|
|
32
|
+
*/
|
|
33
|
+
export declare const ListGroup: import("react").ForwardRefExoticComponent<ListGroupProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { cx } from '../class-names.js';
|
|
5
|
+
import { assertListGroup, listMaxHeightStyle, } from '../list-options.js';
|
|
6
|
+
import { ListRowContainer } from './list/list-row-container.js';
|
|
7
|
+
import { ScrollRegion } from './ScrollRegion.js';
|
|
8
|
+
/**
|
|
9
|
+
* Rows in one list (`ul`, its list role kept) with hairlines between them:
|
|
10
|
+
* a panel of its own, or plain rows inside a surface. The ref reaches the
|
|
11
|
+
* outer box.
|
|
12
|
+
*/
|
|
13
|
+
export const ListGroup = forwardRef(function ListGroup({ children, 'aria-label': label, 'aria-labelledby': labelledBy, variant = 'panel', maxHeight, footer, className, id, }, ref) {
|
|
14
|
+
assertListGroup({ label, labelledBy, variant, maxHeight });
|
|
15
|
+
const list = (_jsx("ul", { "aria-label": label, "aria-labelledby": labelledBy, className: "sw-list",
|
|
16
|
+
// A list styled without bullets loses its role in Safari.
|
|
17
|
+
role: "list", children: _jsx(ListRowContainer.Provider, { value: "li", children: children }) }));
|
|
18
|
+
return (_jsxs("div", { className: cx('sw-list-group', `sw-list-group-${variant}`, className), id: id, ref: ref, children: [maxHeight === undefined ? (list) : (_jsx(ScrollRegion, { "aria-label": label, "aria-labelledby": labelledBy, className: "sw-list-group-scroll", style: listMaxHeightStyle(maxHeight), children: list })), footer === undefined ? null : (_jsx("div", { className: "sw-list-group-footer", children: _jsx(ListRowContainer.Provider, { value: "div", children: footer }) }))] }));
|
|
19
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type ListRowTitleAppearance, type ListRowTone, type ListRowValueTone } from '../list-options.js';
|
|
3
|
+
export type ListRowProps = {
|
|
4
|
+
title: string;
|
|
5
|
+
/** A muted line under the title. */
|
|
6
|
+
detail?: string;
|
|
7
|
+
/** A figure or word at the row's end, such as "+$1.48". */
|
|
8
|
+
value?: string;
|
|
9
|
+
/** A muted line under the value, such as "checks $3,427". */
|
|
10
|
+
valueDetail?: string;
|
|
11
|
+
/** Colours the value only, as a table cell's tone; the words say why. */
|
|
12
|
+
valueTone?: ListRowValueTone;
|
|
13
|
+
/**
|
|
14
|
+
* A consumer mark at the row's start, such as a status dot or a Lucide
|
|
15
|
+
* glyph (ADR 0008). It is hidden from assistive technology, so the words
|
|
16
|
+
* must say what it means.
|
|
17
|
+
*/
|
|
18
|
+
leading?: ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* Makes the whole row a button (or, with `href`, a link's plain press
|
|
21
|
+
* for a client router) and adds the chevron.
|
|
22
|
+
*/
|
|
23
|
+
onPress?: () => void;
|
|
24
|
+
/** Makes the whole row a link to `href`, with the chevron. */
|
|
25
|
+
href?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Makes the row a choice: a check while true, nothing while false, and
|
|
28
|
+
* the state (`aria-pressed` on a button, `aria-current` on a link). Only
|
|
29
|
+
* on a row with `onPress` or `href`.
|
|
30
|
+
*/
|
|
31
|
+
selected?: boolean;
|
|
32
|
+
/** Dims the row and blocks presses; a link row drops its `href`. */
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
/** `danger` draws the title in the danger colour, for a row that ends something. */
|
|
35
|
+
tone?: ListRowTone;
|
|
36
|
+
/** `plain` sets the title at the body weight, for a list of plain statements. */
|
|
37
|
+
titleAppearance?: ListRowTitleAppearance;
|
|
38
|
+
/** `none` hides the chevron of a pressable row that acts in place. */
|
|
39
|
+
accessory?: 'chevron' | 'none';
|
|
40
|
+
/**
|
|
41
|
+
* Replaces a pressable row's name, which is its title and value; its
|
|
42
|
+
* detail lines are its description.
|
|
43
|
+
*/
|
|
44
|
+
'aria-label'?: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* One row of a `ListGroup`: it opens something (`onPress` or `href`, with
|
|
48
|
+
* a chevron, the whole row pressing), picks one option in place
|
|
49
|
+
* (`selected`), or only states something (neither).
|
|
50
|
+
*/
|
|
51
|
+
export declare function ListRow({ title, detail, value, valueDetail, valueTone, leading, onPress, href, selected, disabled, tone, titleAppearance, accessory, 'aria-label': ariaLabel, }: ListRowProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useContext, useId } from 'react';
|
|
4
|
+
import { cx } from '../class-names.js';
|
|
5
|
+
import { assertListRow, listRowAccessory, } from '../list-options.js';
|
|
6
|
+
import { tabStop } from '../tab-stop.js';
|
|
7
|
+
import { plainPress } from './link-press.js';
|
|
8
|
+
import { ListRowContent } from './list/ListRowContent.js';
|
|
9
|
+
import { ListRowContainer } from './list/list-row-container.js';
|
|
10
|
+
function ids(...parts) {
|
|
11
|
+
const joined = parts.filter(Boolean).join(' ');
|
|
12
|
+
return joined === '' ? undefined : joined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* One row of a `ListGroup`: it opens something (`onPress` or `href`, with
|
|
16
|
+
* a chevron, the whole row pressing), picks one option in place
|
|
17
|
+
* (`selected`), or only states something (neither).
|
|
18
|
+
*/
|
|
19
|
+
export function ListRow({ title, detail, value, valueDetail, valueTone, leading, onPress, href, selected, disabled = false, tone = 'default', titleAppearance = 'strong', accessory = 'chevron', 'aria-label': ariaLabel, }) {
|
|
20
|
+
const pressable = onPress !== undefined || href !== undefined;
|
|
21
|
+
assertListRow({
|
|
22
|
+
title,
|
|
23
|
+
tone,
|
|
24
|
+
titleAppearance,
|
|
25
|
+
valueTone,
|
|
26
|
+
accessory,
|
|
27
|
+
value,
|
|
28
|
+
valueDetail,
|
|
29
|
+
selected,
|
|
30
|
+
pressable,
|
|
31
|
+
});
|
|
32
|
+
const container = useContext(ListRowContainer);
|
|
33
|
+
const id = useId();
|
|
34
|
+
const kind = listRowAccessory({ pressable, selected, accessory });
|
|
35
|
+
const content = (_jsx(ListRowContent, { accessory: kind, detail: detail, id: id, leading: leading, title: title, titleAppearance: titleAppearance, tone: tone, value: value, valueDetail: valueDetail, valueTone: valueTone }));
|
|
36
|
+
const className = cx('sw-list-row', pressable && 'sw-list-row-pressable', disabled && 'sw-list-row-disabled');
|
|
37
|
+
const naming = {
|
|
38
|
+
'aria-label': ariaLabel,
|
|
39
|
+
'aria-labelledby': ariaLabel
|
|
40
|
+
? undefined
|
|
41
|
+
: ids(`${id}-title`, value !== undefined && `${id}-value`),
|
|
42
|
+
'aria-describedby': ids(Boolean(detail) && `${id}-detail`, Boolean(valueDetail) && `${id}-value-detail`),
|
|
43
|
+
};
|
|
44
|
+
let row;
|
|
45
|
+
if (href !== undefined)
|
|
46
|
+
row = (_jsx("a", { ...naming, "aria-current": selected ? 'true' : undefined, "aria-disabled": disabled || undefined, className: className, href: disabled ? undefined : href, onClick: onPress && !disabled
|
|
47
|
+
? (event) => {
|
|
48
|
+
if (!plainPress(event))
|
|
49
|
+
return;
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
onPress();
|
|
52
|
+
}
|
|
53
|
+
: undefined, role: disabled ? 'link' : undefined, tabIndex: disabled ? undefined : tabStop, children: content }));
|
|
54
|
+
else if (onPress !== undefined)
|
|
55
|
+
row = (_jsx("button", { ...naming, "aria-pressed": selected, className: className, disabled: disabled, onClick: onPress, tabIndex: tabStop, type: "button", children: content }));
|
|
56
|
+
else
|
|
57
|
+
row = (_jsx("div", { "aria-label": ariaLabel, className: className, role: ariaLabel ? 'group' : undefined, children: content }));
|
|
58
|
+
return container === 'li' ? (_jsx("li", { className: "sw-list-item", children: row })) : (_jsx("div", { className: "sw-list-item", children: row }));
|
|
59
|
+
}
|