@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.
Files changed (162) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +155 -1
  3. package/dist/calendar-month.d.ts +6 -0
  4. package/dist/calendar-month.js +15 -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 +6 -6
  30. package/dist/components/DateRangeButton.d.ts +65 -0
  31. package/dist/components/DateRangeButton.js +54 -0
  32. package/dist/components/LineChart.d.ts +83 -0
  33. package/dist/components/LineChart.js +77 -0
  34. package/dist/components/ListGroup.d.ts +33 -0
  35. package/dist/components/ListGroup.js +19 -0
  36. package/dist/components/ListRow.d.ts +51 -0
  37. package/dist/components/ListRow.js +59 -0
  38. package/dist/components/NavCount.d.ts +21 -0
  39. package/dist/components/NavCount.js +23 -0
  40. package/dist/components/SectionNav.js +1 -8
  41. package/dist/components/StatTile.d.ts +11 -4
  42. package/dist/components/StatTile.js +11 -4
  43. package/dist/components/{date-field → calendar}/CalendarGrid.d.ts +17 -2
  44. package/dist/components/{date-field → calendar}/CalendarGrid.js +11 -3
  45. package/dist/components/calendar/CalendarPopover.d.ts +25 -0
  46. package/dist/components/calendar/CalendarPopover.js +22 -0
  47. package/dist/components/calendar/MonthStep.d.ts +16 -0
  48. package/dist/components/calendar/MonthStep.js +17 -0
  49. package/dist/components/calendar/use-grid-focus.d.ts +18 -0
  50. package/dist/components/calendar/use-grid-focus.js +35 -0
  51. package/dist/components/calendar/wrap-tab.d.ts +7 -0
  52. package/dist/components/calendar/wrap-tab.js +29 -0
  53. package/dist/components/chart/ChartTable.d.ts +16 -0
  54. package/dist/components/chart/ChartTable.js +12 -0
  55. package/dist/components/chart/ChartValueAxis.d.ts +14 -0
  56. package/dist/components/chart/ChartValueAxis.js +11 -0
  57. package/dist/components/chart/use-chart-width.d.ts +8 -0
  58. package/dist/components/chart/use-chart-width.js +34 -0
  59. package/dist/components/column-chart/ChartCalloutList.d.ts +16 -0
  60. package/dist/components/column-chart/ChartCalloutList.js +13 -0
  61. package/dist/components/column-chart/ColumnChartDrawing.d.ts +17 -0
  62. package/dist/components/column-chart/ColumnChartDrawing.js +18 -0
  63. package/dist/components/date-field/CalendarDialog.js +9 -67
  64. package/dist/components/date-field/CalendarHeader.js +2 -11
  65. package/dist/components/date-range/DateRangePopover.d.ts +7 -0
  66. package/dist/components/date-range/DateRangePopover.js +17 -0
  67. package/dist/components/date-range/DateRangeSheet.d.ts +7 -0
  68. package/dist/components/date-range/DateRangeSheet.js +15 -0
  69. package/dist/components/date-range/RangeMonths.d.ts +28 -0
  70. package/dist/components/date-range/RangeMonths.js +50 -0
  71. package/dist/components/date-range/RangePresets.d.ts +16 -0
  72. package/dist/components/date-range/RangePresets.js +10 -0
  73. package/dist/components/date-range/RangeSummary.d.ts +15 -0
  74. package/dist/components/date-range/RangeSummary.js +11 -0
  75. package/dist/components/date-range/range-panel-props.d.ts +31 -0
  76. package/dist/components/date-range/range-panel-props.js +1 -0
  77. package/dist/components/date-range/use-range-popup.d.ts +21 -0
  78. package/dist/components/date-range/use-range-popup.js +53 -0
  79. package/dist/components/line-chart/LineChartDrawing.d.ts +17 -0
  80. package/dist/components/line-chart/LineChartDrawing.js +16 -0
  81. package/dist/components/link-press.d.ts +7 -0
  82. package/dist/components/link-press.js +13 -0
  83. package/dist/components/list/ListRowAccessoryMark.d.ts +5 -0
  84. package/dist/components/list/ListRowAccessoryMark.js +7 -0
  85. package/dist/components/list/ListRowContent.d.ts +20 -0
  86. package/dist/components/list/ListRowContent.js +10 -0
  87. package/dist/components/list/list-row-container.d.ts +5 -0
  88. package/dist/components/list/list-row-container.js +6 -0
  89. package/dist/components/use-media-query.d.ts +5 -0
  90. package/dist/components/use-media-query.js +18 -0
  91. package/dist/css/chart-marks.d.ts +10 -0
  92. package/dist/css/chart-marks.js +15 -0
  93. package/dist/css/chart-tones.d.ts +68 -0
  94. package/dist/css/chart-tones.js +130 -0
  95. package/dist/css/chevron.d.ts +6 -0
  96. package/dist/css/chevron.js +14 -0
  97. package/dist/css/{css-chart.d.ts → css-bar-chart.d.ts} +2 -2
  98. package/dist/css/{css-chart.js → css-bar-chart.js} +2 -2
  99. package/dist/css/css-button-group-attached.js +8 -4
  100. package/dist/css/css-button-group-track.js +1 -1
  101. package/dist/css/css-chart-legend.d.ts +5 -0
  102. package/dist/css/css-chart-legend.js +102 -0
  103. package/dist/css/css-chart-plot.d.ts +2 -0
  104. package/dist/css/css-chart-plot.js +170 -0
  105. package/dist/css/css-checkbox.js +2 -2
  106. package/dist/css/css-components.js +23 -2
  107. package/dist/css/css-count-pill.d.ts +2 -0
  108. package/dist/css/css-count-pill.js +54 -0
  109. package/dist/css/css-data-bar.d.ts +4 -9
  110. package/dist/css/css-data-bar.js +15 -31
  111. package/dist/css/css-date-field.js +3 -2
  112. package/dist/css/css-date-range-presets.d.ts +2 -0
  113. package/dist/css/css-date-range-presets.js +109 -0
  114. package/dist/css/css-date-range.d.ts +2 -0
  115. package/dist/css/css-date-range.js +197 -0
  116. package/dist/css/css-line-chart.d.ts +2 -0
  117. package/dist/css/css-line-chart.js +31 -0
  118. package/dist/css/css-list-row.d.ts +2 -0
  119. package/dist/css/css-list-row.js +193 -0
  120. package/dist/css/css-list.d.ts +3 -0
  121. package/dist/css/css-list.js +85 -0
  122. package/dist/css/css-scroll-region.d.ts +18 -0
  123. package/dist/css/css-scroll-region.js +41 -0
  124. package/dist/css/css-section-nav-filled.js +2 -25
  125. package/dist/css/css-stat-tile.d.ts +7 -0
  126. package/dist/css/css-stat-tile.js +16 -0
  127. package/dist/css/css-steps.js +2 -2
  128. package/dist/css/css-table-bounded-edges.js +4 -27
  129. package/dist/css/range-band.d.ts +2 -0
  130. package/dist/css/range-band.js +7 -0
  131. package/dist/css/stacking.js +2 -2
  132. package/dist/css/stylesheet.js +16 -2
  133. package/dist/date-range-draft.d.ts +26 -0
  134. package/dist/date-range-draft.js +36 -0
  135. package/dist/date-range-input.d.ts +26 -0
  136. package/dist/date-range-input.js +58 -0
  137. package/dist/date-range-labels.d.ts +22 -0
  138. package/dist/date-range-labels.js +26 -0
  139. package/dist/date-range-view.d.ts +12 -0
  140. package/dist/date-range-view.js +29 -0
  141. package/dist/date-range-words.d.ts +11 -0
  142. package/dist/date-range-words.js +40 -0
  143. package/dist/index.d.ts +9 -1
  144. package/dist/index.js +9 -1
  145. package/dist/is-one-of.d.ts +5 -0
  146. package/dist/is-one-of.js +7 -0
  147. package/dist/line-chart-input.d.ts +39 -0
  148. package/dist/line-chart-input.js +70 -0
  149. package/dist/line-chart-layout.d.ts +68 -0
  150. package/dist/line-chart-layout.js +99 -0
  151. package/dist/line-chart-markers.d.ts +29 -0
  152. package/dist/line-chart-markers.js +57 -0
  153. package/dist/line-chart-path.d.ts +18 -0
  154. package/dist/line-chart-path.js +33 -0
  155. package/dist/line-chart-points.d.ts +6 -0
  156. package/dist/line-chart-points.js +8 -0
  157. package/dist/line-chart-table.d.ts +15 -0
  158. package/dist/line-chart-table.js +29 -0
  159. package/dist/list-options.d.ts +70 -0
  160. package/dist/list-options.js +77 -0
  161. package/dist/styles.css +726 -26
  162. 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 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,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
+ }