@scalewing/react 1.39.0 → 1.41.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 +33 -0
- package/README.md +255 -5
- package/dist/calendar-labels.d.ts +2 -0
- package/dist/calendar-labels.js +7 -0
- package/dist/calendar-month.d.ts +6 -0
- package/dist/calendar-month.js +15 -0
- package/dist/components/BarChart.d.ts +20 -4
- package/dist/components/BarChart.js +13 -6
- package/dist/components/ButtonGroup.d.ts +8 -1
- package/dist/components/ButtonGroup.js +11 -2
- package/dist/components/DateField.d.ts +14 -2
- package/dist/components/DateField.js +14 -11
- package/dist/components/DateRangeButton.d.ts +65 -0
- package/dist/components/DateRangeButton.js +54 -0
- package/dist/components/DenominationGrid.d.ts +3 -2
- package/dist/components/DenominationGrid.js +21 -3
- package/dist/components/Dialog.d.ts +29 -13
- package/dist/components/Dialog.js +22 -20
- package/dist/components/Field.d.ts +13 -2
- package/dist/components/Field.js +14 -38
- package/dist/components/FilterChips.d.ts +7 -37
- package/dist/components/FilterChips.js +32 -24
- package/dist/components/ListGroup.d.ts +33 -0
- package/dist/components/ListGroup.js +19 -0
- package/dist/components/ListRow.d.ts +60 -0
- package/dist/components/ListRow.js +60 -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/SegmentedControl.d.ts +17 -1
- package/dist/components/SegmentedControl.js +11 -3
- package/dist/components/StatTile.d.ts +11 -4
- package/dist/components/StatTile.js +11 -4
- package/dist/components/Switch.d.ts +16 -1
- package/dist/components/Switch.js +17 -6
- package/dist/components/action-bar/ActionBarSummary.d.ts +10 -2
- package/dist/components/action-bar/ActionBarSummary.js +11 -2
- 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/date-field/CalendarDialog.js +9 -67
- package/dist/components/date-field/CalendarEntryButton.d.ts +24 -0
- package/dist/components/date-field/CalendarEntryButton.js +16 -0
- package/dist/components/date-field/CalendarHeader.js +2 -11
- package/dist/components/date-field/TypedEntry.d.ts +26 -0
- package/dist/components/date-field/TypedEntry.js +13 -0
- 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/denomination-grid/CountCell.d.ts +16 -0
- package/dist/components/denomination-grid/CountCell.js +14 -0
- package/dist/components/denomination-grid/DenominationStrip.d.ts +4 -1
- package/dist/components/denomination-grid/DenominationStrip.js +2 -2
- package/dist/components/denomination-grid/EntryCell.d.ts +3 -1
- package/dist/components/denomination-grid/EntryCell.js +2 -2
- package/dist/components/denomination-grid/StripRow.js +1 -10
- package/dist/components/denomination-grid/TransposedStrip.d.ts +17 -0
- package/dist/components/denomination-grid/TransposedStrip.js +43 -0
- package/dist/components/denomination-grid/types.d.ts +31 -0
- package/dist/components/denomination-grid/types.js +7 -1
- package/dist/components/denomination-grid/validate-options.d.ts +7 -0
- package/dist/components/denomination-grid/validate-options.js +27 -0
- package/dist/components/dialog/DialogFooter.d.ts +6 -5
- package/dist/components/dialog/DialogFooter.js +6 -6
- package/dist/components/dialog/validate.d.ts +24 -0
- package/dist/components/dialog/validate.js +23 -0
- package/dist/components/field/field-checks.d.ts +34 -0
- package/dist/components/field/field-checks.js +42 -0
- package/dist/components/filter-chips/FilterChip.d.ts +16 -0
- package/dist/components/filter-chips/FilterChip.js +20 -0
- package/dist/components/filter-chips/options.d.ts +75 -0
- package/dist/components/filter-chips/options.js +11 -0
- package/dist/components/filter-chips/validate.d.ts +9 -0
- package/dist/components/filter-chips/validate.js +48 -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 +22 -0
- package/dist/components/list/ListRowContent.js +11 -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-tones.d.ts +2 -0
- package/dist/css/chart-tones.js +5 -1
- package/dist/css/chevron.d.ts +6 -0
- package/dist/css/chevron.js +14 -0
- package/dist/css/css-bar-chart.d.ts +17 -2
- package/dist/css/css-bar-chart.js +38 -7
- package/dist/css/css-button-group-attached.d.ts +3 -0
- package/dist/css/css-button-group-attached.js +26 -5
- package/dist/css/css-button-group-track.js +1 -1
- package/dist/css/css-canvas-grouped.d.ts +17 -0
- package/dist/css/css-canvas-grouped.js +40 -0
- package/dist/css/css-checkbox.js +2 -2
- package/dist/css/css-components.js +15 -0
- package/dist/css/css-count-pill.d.ts +2 -0
- package/dist/css/css-count-pill.js +54 -0
- package/dist/css/css-date-field-calendar-entry.d.ts +11 -0
- package/dist/css/css-date-field-calendar-entry.js +50 -0
- package/dist/css/css-date-field.js +7 -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-denomination-grid.js +4 -0
- package/dist/css/css-denomination-transposed.d.ts +4 -0
- package/dist/css/css-denomination-transposed.js +178 -0
- package/dist/css/css-dialog-canvas.d.ts +3 -0
- package/dist/css/css-dialog-canvas.js +20 -0
- package/dist/css/css-dialog-frame.js +19 -2
- package/dist/css/css-dialog-grabber.d.ts +4 -0
- package/dist/css/css-dialog-grabber.js +56 -0
- package/dist/css/css-dialog.js +3 -2
- package/dist/css/css-document.js +3 -0
- package/dist/css/css-field-width.d.ts +12 -0
- package/dist/css/css-field-width.js +49 -0
- package/dist/css/css-field.js +4 -0
- package/dist/css/css-filter-chips-layout.d.ts +2 -0
- package/dist/css/css-filter-chips-layout.js +42 -0
- package/dist/css/css-filter-chips.js +4 -0
- package/dist/css/css-list-row.d.ts +8 -0
- package/dist/css/css-list-row.js +209 -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-segmented-sizing.d.ts +13 -0
- package/dist/css/css-segmented-sizing.js +66 -0
- package/dist/css/css-segmented.js +4 -0
- 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-switch.d.ts +6 -0
- package/dist/css/css-switch.js +39 -0
- 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.d.ts +1 -0
- package/dist/css/stacking.js +6 -3
- package/dist/css/stylesheet.js +10 -0
- package/dist/date-field-labels.d.ts +5 -0
- package/dist/date-field-labels.js +1 -0
- 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 +16 -9
- package/dist/index.js +14 -7
- package/dist/list-options.d.ts +71 -0
- package/dist/list-options.js +84 -0
- package/dist/styles.css +863 -41
- package/dist/theme/ThemeProvider.d.ts +11 -1
- package/dist/theme/ThemeProvider.js +4 -2
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type HTMLAttributes } from 'react';
|
|
2
|
-
import { type BarChartTone, barChartTones } from '../css/css-bar-chart.js';
|
|
3
|
-
export type { BarChartTone };
|
|
4
|
-
export { barChartTones };
|
|
2
|
+
import { type BarChartAppearance, barChartAppearances, type BarChartTone, barChartTones } from '../css/css-bar-chart.js';
|
|
3
|
+
export type { BarChartAppearance, BarChartTone };
|
|
4
|
+
export { barChartAppearances, barChartTones };
|
|
5
5
|
export type BarChartItem = {
|
|
6
6
|
label: string;
|
|
7
7
|
value: number;
|
|
@@ -9,7 +9,9 @@ export type BarChartItem = {
|
|
|
9
9
|
/**
|
|
10
10
|
* Colors the bar by what it means, in place of its sign's default (the
|
|
11
11
|
* accent, or danger for a negative value): such as `'warning'` for an
|
|
12
|
-
* overage
|
|
12
|
+
* overage, `'danger'` for a shortage and `'neutral'` (the muted grey)
|
|
13
|
+
* for a bar that is counted but not the point, such as the usual days
|
|
14
|
+
* beside the busiest ones. The color is a cue beside the
|
|
13
15
|
* value and its label, never the only sign of the meaning. An unknown tone
|
|
14
16
|
* throws a `RangeError`.
|
|
15
17
|
*/
|
|
@@ -33,6 +35,13 @@ export type BarChartProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
|
33
35
|
* alone tells a negative value.
|
|
34
36
|
*/
|
|
35
37
|
diverging?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* `track` (the default) draws each bar in a track with the value axis
|
|
40
|
+
* under the bars. `bare` draws the bars alone, with no track and no
|
|
41
|
+
* axis, for bars whose values are all written beside them. An unknown
|
|
42
|
+
* appearance throws a `RangeError`.
|
|
43
|
+
*/
|
|
44
|
+
appearance?: BarChartAppearance;
|
|
36
45
|
};
|
|
37
46
|
export declare const BarChart: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
38
47
|
'aria-label': string;
|
|
@@ -52,4 +61,11 @@ export declare const BarChart: import("react").ForwardRefExoticComponent<Omit<HT
|
|
|
52
61
|
* alone tells a negative value.
|
|
53
62
|
*/
|
|
54
63
|
diverging?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* `track` (the default) draws each bar in a track with the value axis
|
|
66
|
+
* under the bars. `bare` draws the bars alone, with no track and no
|
|
67
|
+
* axis, for bars whose values are all written beside them. An unknown
|
|
68
|
+
* appearance throws a `RangeError`.
|
|
69
|
+
*/
|
|
70
|
+
appearance?: BarChartAppearance;
|
|
55
71
|
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -2,21 +2,28 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { barChartFillRatio, barChartScaleMax, formatBarChartValue, } from '@scalewing/tokens';
|
|
3
3
|
import { forwardRef } from 'react';
|
|
4
4
|
import { cx } from '../class-names.js';
|
|
5
|
-
import { barChartTones } from '../css/css-bar-chart.js';
|
|
6
|
-
export { barChartTones };
|
|
5
|
+
import { barChartAppearances, barChartTones, } from '../css/css-bar-chart.js';
|
|
6
|
+
export { barChartAppearances, barChartTones };
|
|
7
7
|
/** The fill's classes: the sign's (which also shapes a diverging bar) and the tone's. */
|
|
8
8
|
function barChartFillClassName(item) {
|
|
9
9
|
if (item.tone !== undefined && !barChartTones.includes(item.tone))
|
|
10
10
|
throw new RangeError(`BarChart item tone must be one of ${barChartTones.join(', ')}; received ${String(item.tone)}`);
|
|
11
11
|
return cx('sw-bar-chart-fill', item.value < 0 && 'sw-bar-chart-fill-negative', item.tone && `sw-bar-chart-fill-${item.tone}`);
|
|
12
12
|
}
|
|
13
|
-
export const BarChart = forwardRef(function BarChart({ 'aria-label': ariaLabel, className, diverging = false, formatValue = formatBarChartValue, items, max, style, ...rest }, ref) {
|
|
13
|
+
export const BarChart = forwardRef(function BarChart({ 'aria-label': ariaLabel, appearance = 'track', className, diverging = false, formatValue = formatBarChartValue, items, max, style, ...rest }, ref) {
|
|
14
|
+
if (!barChartAppearances.includes(appearance))
|
|
15
|
+
throw new RangeError(`Unknown BarChart appearance: ${String(appearance)}`);
|
|
14
16
|
const scaleMax = barChartScaleMax(items.map((item) => item.value), max);
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
+
const bare = appearance === 'bare';
|
|
18
|
+
const axis = bare
|
|
19
|
+
? []
|
|
20
|
+
: diverging
|
|
21
|
+
? [-scaleMax, 0, scaleMax]
|
|
22
|
+
: [0, scaleMax];
|
|
23
|
+
return (_jsxs("div", { ref: ref, className: cx('sw-bar-chart', diverging && 'sw-bar-chart-diverging', bare && 'sw-bar-chart-bare', className), style: style, ...rest, children: [_jsx("ul", { "aria-label": ariaLabel, className: "sw-bar-chart-plot", children: items.map((item, index) => {
|
|
17
24
|
const ratio = barChartFillRatio(item.value, scaleMax);
|
|
18
25
|
return (_jsxs("li", { className: "sw-bar-chart-row", children: [_jsx("span", { className: "sw-bar-chart-label", children: item.label }), _jsx("span", { className: "sw-bar-chart-track", children: _jsx("span", { className: barChartFillClassName(item), style: {
|
|
19
26
|
'--sw-bar-fill': ratio,
|
|
20
27
|
} }) }), _jsx("span", { className: "sw-bar-chart-value", children: item.valueLabel ?? formatValue(item.value) })] }, `${item.label}-${index}`));
|
|
21
|
-
}) }), _jsxs("div", { "aria-hidden": "true", className: "sw-bar-chart-axis", children: [_jsx("span", {}), _jsx("span", { className: "sw-bar-chart-axis-track", children: axis.map((value) => (_jsx("span", { children: formatValue(value) }, value))) }), _jsx("span", {})] })] }));
|
|
28
|
+
}) }), bare ? null : (_jsxs("div", { "aria-hidden": "true", className: "sw-bar-chart-axis", children: [_jsx("span", {}), _jsx("span", { className: "sw-bar-chart-axis-track", children: axis.map((value) => (_jsx("span", { children: formatValue(value) }, value))) }), _jsx("span", {})] }))] }));
|
|
22
29
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Breakpoint } from '../css/breakpoints.js';
|
|
1
2
|
import { type ButtonGroupAppearance, buttonGroupAppearances } from '../css/css-button-group-track.js';
|
|
2
3
|
import { type BoxProps } from './Box.js';
|
|
3
4
|
export type ButtonGroupJustify = 'start' | 'end' | 'between';
|
|
@@ -19,6 +20,12 @@ export type ButtonGroupProps = BoxProps & {
|
|
|
19
20
|
* variant; `default` keeps each button's own fill and outline.
|
|
20
21
|
*/
|
|
21
22
|
appearance?: ButtonGroupAppearance;
|
|
23
|
+
/**
|
|
24
|
+
* Below this breakpoint (an `attached` group only) the group fills its
|
|
25
|
+
* column and its buttons share the width equally, such as ‹, a period and
|
|
26
|
+
* › across a phone. From it up the group sizes to its buttons.
|
|
27
|
+
*/
|
|
28
|
+
fullWidthBelow?: Breakpoint;
|
|
22
29
|
};
|
|
23
30
|
/**
|
|
24
31
|
* The action row of a form or dialog: buttons on one line, wrapping when
|
|
@@ -27,4 +34,4 @@ export type ButtonGroupProps = BoxProps & {
|
|
|
27
34
|
* (put the primary action last, as the row already does). It is a `group`,
|
|
28
35
|
* so an `aria-label` names the row for assistive tech.
|
|
29
36
|
*/
|
|
30
|
-
export declare function ButtonGroup({ appearance, attached, className, justify, ...rest }: ButtonGroupProps): import("react").JSX.Element;
|
|
37
|
+
export declare function ButtonGroup({ appearance, attached, className, fullWidthBelow, justify, ...rest }: ButtonGroupProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../class-names.js';
|
|
3
|
+
import { breakpoints } from '../css/breakpoints.js';
|
|
4
|
+
import { buttonGroupFullWidthClass } from '../css/css-button-group-attached.js';
|
|
3
5
|
import { buttonGroupAppearances, buttonGroupTrackClass, } from '../css/css-button-group-track.js';
|
|
4
6
|
import { Box } from './Box.js';
|
|
5
7
|
export { buttonGroupAppearances };
|
|
@@ -10,10 +12,17 @@ export { buttonGroupAppearances };
|
|
|
10
12
|
* (put the primary action last, as the row already does). It is a `group`,
|
|
11
13
|
* so an `aria-label` names the row for assistive tech.
|
|
12
14
|
*/
|
|
13
|
-
export function ButtonGroup({ appearance = 'default', attached = false, className, justify = 'end', ...rest }) {
|
|
15
|
+
export function ButtonGroup({ appearance = 'default', attached = false, className, fullWidthBelow, justify = 'end', ...rest }) {
|
|
14
16
|
if (!buttonGroupAppearances.includes(appearance))
|
|
15
17
|
throw new RangeError(`Unknown ButtonGroup appearance: ${String(appearance)}`);
|
|
16
18
|
if (appearance === 'track' && !attached)
|
|
17
19
|
throw new RangeError('ButtonGroup appearance="track" needs attached');
|
|
18
|
-
|
|
20
|
+
if (fullWidthBelow !== undefined) {
|
|
21
|
+
if (!breakpoints.includes(fullWidthBelow))
|
|
22
|
+
throw new RangeError(`Unknown ButtonGroup fullWidthBelow: ${String(fullWidthBelow)}`);
|
|
23
|
+
// An unattached group already stacks full width below md.
|
|
24
|
+
if (!attached)
|
|
25
|
+
throw new RangeError('ButtonGroup fullWidthBelow needs attached');
|
|
26
|
+
}
|
|
27
|
+
return (_jsx(Box, { className: cx('sw-button-group', `sw-button-group-${justify}`, attached && 'sw-button-group-attached', appearance === 'track' && buttonGroupTrackClass, fullWidthBelow && buttonGroupFullWidthClass(fullWidthBelow), className), role: "group", ...rest }));
|
|
19
28
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { type WeekStart } from '../calendar-month.js';
|
|
2
2
|
import { type DateFieldLabels } from '../date-field-labels.js';
|
|
3
|
+
import { type DateFieldEntry } from '../css/css-date-field-calendar-entry.js';
|
|
3
4
|
import { type RequiredMark } from './FieldLabelText.js';
|
|
4
|
-
export type { DateFieldLabels, WeekStart };
|
|
5
|
+
export type { DateFieldEntry, DateFieldLabels, WeekStart };
|
|
6
|
+
export { dateFieldEntries } from '../css/css-date-field-calendar-entry.js';
|
|
5
7
|
export type DateFieldProps = {
|
|
6
8
|
label: string;
|
|
7
9
|
/** Calendar date `YYYY-MM-DD`, or '' for no date. */
|
|
@@ -37,5 +39,15 @@ export type DateFieldProps = {
|
|
|
37
39
|
weekStartsOn?: WeekStart;
|
|
38
40
|
/** The control's own words; English by default. */
|
|
39
41
|
labels?: Partial<DateFieldLabels>;
|
|
42
|
+
/**
|
|
43
|
+
* `typed` (the default) is a text entry in the locale's order with a
|
|
44
|
+
* calendar button. `calendar` is one button showing the chosen day (or
|
|
45
|
+
* `labels.chooseDate`, such as "Choose a day", while empty) that opens
|
|
46
|
+
* the same calendar, for a form where a day is picked, never typed. It
|
|
47
|
+
* has no text to check, so validation and a required day stay with the
|
|
48
|
+
* consumer's `error`; while `required`, `labels.required` is said after
|
|
49
|
+
* its name.
|
|
50
|
+
*/
|
|
51
|
+
entry?: DateFieldEntry;
|
|
40
52
|
};
|
|
41
|
-
export declare function DateField({ label, value, onChange, min, max, today, disabled, required, requiredMark, description, error, locale, weekStartsOn, labels, }: DateFieldProps): import("react").JSX.Element;
|
|
53
|
+
export declare function DateField({ label, value, onChange, min, max, today, disabled, required, requiredMark, description, error, locale, weekStartsOn, labels, entry: entryKind, }: DateFieldProps): import("react").JSX.Element;
|
|
@@ -6,16 +6,19 @@ import { resolveDateFieldLabels, } from '../date-field-labels.js';
|
|
|
6
6
|
import { dateEntryPattern, dateEntryPlaceholder } from '../date-entry.js';
|
|
7
7
|
import { dateEntryValidity } from '../date-entry-validity.js';
|
|
8
8
|
import { assertDateBounds, isOutsideDateRange } from '../date-only.js';
|
|
9
|
+
import { assertDateFieldEntry, } from '../css/css-date-field-calendar-entry.js';
|
|
9
10
|
import { FieldErrorRegion } from './FieldErrorRegion.js';
|
|
10
11
|
import { assertRequiredMark, FieldLabelText, } from './FieldLabelText.js';
|
|
11
12
|
import { CalendarDialog } from './date-field/CalendarDialog.js';
|
|
12
|
-
import {
|
|
13
|
+
import { CalendarEntryButton } from './date-field/CalendarEntryButton.js';
|
|
14
|
+
import { TypedEntry } from './date-field/TypedEntry.js';
|
|
13
15
|
import { useCalendarPopup } from './date-field/use-calendar-popup.js';
|
|
14
16
|
import { useDateEntry } from './date-field/use-date-entry.js';
|
|
15
17
|
import { useLangLocale } from './date-field/use-lang-locale.js';
|
|
16
|
-
|
|
17
|
-
export function DateField({ label, value, onChange, min, max, today, disabled = false, required = false, requiredMark = 'visible', description, error, locale, weekStartsOn = 0, labels, }) {
|
|
18
|
+
export { dateFieldEntries } from '../css/css-date-field-calendar-entry.js';
|
|
19
|
+
export function DateField({ label, value, onChange, min, max, today, disabled = false, required = false, requiredMark = 'visible', description, error, locale, weekStartsOn = 0, labels, entry: entryKind = 'typed', }) {
|
|
18
20
|
assertRequiredMark(requiredMark);
|
|
21
|
+
assertDateFieldEntry(entryKind);
|
|
19
22
|
assertDateBounds(value, min, max);
|
|
20
23
|
assertWeekStart(weekStartsOn);
|
|
21
24
|
const words = resolveDateFieldLabels(labels);
|
|
@@ -45,7 +48,10 @@ export function DateField({ label, value, onChange, min, max, today, disabled =
|
|
|
45
48
|
const descriptionId = useId();
|
|
46
49
|
const entryErrorId = useId();
|
|
47
50
|
const errorId = useId();
|
|
51
|
+
const requiredId = useId();
|
|
52
|
+
const calendarEntry = entryKind === 'calendar';
|
|
48
53
|
const describedBy = [
|
|
54
|
+
calendarEntry && required ? requiredId : null,
|
|
49
55
|
description ? descriptionId : null,
|
|
50
56
|
entry.invalid ? entryErrorId : null,
|
|
51
57
|
error ? errorId : null,
|
|
@@ -53,12 +59,9 @@ export function DateField({ label, value, onChange, min, max, today, disabled =
|
|
|
53
59
|
.filter((id) => id !== null)
|
|
54
60
|
.join(' ');
|
|
55
61
|
const invalid = Boolean(error) || entry.invalid || isOutsideDateRange(value, min, max);
|
|
56
|
-
return (_jsxs("div", { className: "sw-date-field", ref: rootRef, children: [_jsx("label", { className: "sw-date-field-label", htmlFor: inputId, id: labelId, children: _jsx(FieldLabelText, { label: label, required: required, requiredMark: requiredMark }) }), _jsxs("div", { className: "sw-date-field-control", ref: controlRef, children: [_jsx(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
month: words.monthPlaceholder,
|
|
62
|
-
year: words.yearPlaceholder,
|
|
63
|
-
}), ref: inputRef, required: required, spellCheck: false, type: "text", value: entry.text }), _jsxs("button", { ...trigger, "aria-describedby": labelId, className: "sw-date-field-button", disabled: disabled, onClick: toggle, ref: buttonRef, tabIndex: tabStop, type: "button", children: [_jsx("span", { className: "sw-sr-only", children: words.chooseDate }), _jsx(DateFieldGlyph, { name: "calendar" })] })] }), description ? (_jsx("span", { className: "sw-date-field-description", id: descriptionId, children: description })) : null, _jsx(FieldErrorRegion, { className: "sw-date-field-error", id: entryErrorId, message: entry.invalid ? words.invalidEntry : undefined }), _jsx(FieldErrorRegion, { className: "sw-date-field-error", id: errorId, message: error }), shown ? (_jsx(CalendarDialog, { ...dialog, buttonRef: buttonRef, anchorRef: controlRef, labelId: labelId, labels: words, locale: resolvedLocale, max: max, min: min, required: required, value: value, weekStartsOn: weekStartsOn })) : null] }));
|
|
62
|
+
return (_jsxs("div", { className: "sw-date-field", ref: rootRef, children: [_jsx("label", { className: "sw-date-field-label", htmlFor: inputId, id: labelId, children: _jsx(FieldLabelText, { label: label, required: required, requiredMark: requiredMark }) }), calendarEntry ? (_jsxs("div", { className: "sw-date-field-control", ref: controlRef, children: [_jsx(CalendarEntryButton, { buttonRef: buttonRef, describedBy: describedBy || undefined, disabled: disabled, emptyText: words.chooseDate, id: inputId, invalid: invalid, labelId: labelId, locale: resolvedLocale, onPress: toggle, trigger: trigger, value: value }), required ? (_jsx("span", { hidden: true, id: requiredId, children: words.required })) : null] })) : (_jsx(TypedEntry, { buttonRef: buttonRef, controlRef: controlRef, describedBy: describedBy || undefined, disabled: disabled, entry: entry, id: inputId, inputRef: inputRef, invalid: invalid, labelId: labelId, onToggle: toggle, placeholder: dateEntryPlaceholder(pattern, {
|
|
63
|
+
day: words.dayPlaceholder,
|
|
64
|
+
month: words.monthPlaceholder,
|
|
65
|
+
year: words.yearPlaceholder,
|
|
66
|
+
}), required: required, toggleName: words.chooseDate, trigger: trigger })), description ? (_jsx("span", { className: "sw-date-field-description", id: descriptionId, children: description })) : null, _jsx(FieldErrorRegion, { className: "sw-date-field-error", id: entryErrorId, message: entry.invalid ? words.invalidEntry : undefined }), _jsx(FieldErrorRegion, { className: "sw-date-field-error", id: errorId, message: error }), shown ? (_jsx(CalendarDialog, { ...dialog, buttonRef: buttonRef, anchorRef: controlRef, labelId: labelId, labels: words, locale: resolvedLocale, max: max, min: min, required: required, value: value, weekStartsOn: weekStartsOn })) : null] }));
|
|
64
67
|
}
|
|
@@ -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
|
+
});
|
|
@@ -2,7 +2,8 @@ import { denominationGridFrames, denominationTotalEmphases } from '../css/css-de
|
|
|
2
2
|
import { denominationCellToneAppearances } from '../css/css-denomination-cell-tones.js';
|
|
3
3
|
import { denominationLabelAppearances } from '../css/css-denomination-label.js';
|
|
4
4
|
import { type DenominationGridProps } from './denomination-grid/types.js';
|
|
5
|
-
export type { DenominationCellToneAppearance, DenominationGridColumn, DenominationGridEntry, DenominationGridFrame, DenominationGridLayout, DenominationGridProps, DenominationGridRow, DenominationGridRowEmphasis, DenominationGridRowRole, DenominationGridTone, DenominationGridValueRow, DenominationLabelWidth, DenominationTotalEmphasis, } from './denomination-grid/types.js';
|
|
5
|
+
export type { DenominationCellToneAppearance, DenominationGridColumn, DenominationGridEntry, DenominationGridFrame, DenominationGridLayout, DenominationGridNegativeAppearance, DenominationGridProps, DenominationGridRow, DenominationGridRowEmphasis, DenominationGridRowRole, DenominationGridTone, DenominationGridValueRow, DenominationLabelWidth, DenominationTotalEmphasis, DenominationTransposeBreakpoint, } from './denomination-grid/types.js';
|
|
6
|
+
export { denominationNegativeAppearances, denominationTransposeBreakpoints, } from './denomination-grid/types.js';
|
|
6
7
|
export type { DenominationLabelAppearance } from '../css/css-denomination-label.js';
|
|
7
8
|
export { denominationCellToneAppearances, denominationGridFrames, denominationLabelAppearances, denominationTotalEmphases, };
|
|
8
|
-
export declare function DenominationGrid({ label, columns, rows, layout, subtotal, zeroLabel, totalLabel, rowRole, labelWidth, labelAppearance, frame, totalEmphasis, cellToneAppearance, }: DenominationGridProps): import("react").JSX.Element;
|
|
9
|
+
export declare function DenominationGrid({ label, columns, rows, layout, subtotal, zeroLabel, totalLabel, rowRole, labelWidth, labelAppearance, frame, totalEmphasis, cellToneAppearance, transposeBelow, countDigits, }: DenominationGridProps): import("react").JSX.Element;
|
|
@@ -1,25 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
3
|
import { cx } from '../class-names.js';
|
|
4
|
+
import { breakpointQuery } from '../css/breakpoints.js';
|
|
5
|
+
import { denominationCountDigitsClass } from '../css/css-denomination-transposed.js';
|
|
3
6
|
import { denominationLabelWidths } from '../css/css-denomination-aligned.js';
|
|
4
7
|
import { denominationGridFrames, denominationTotalEmphases, denominationTotalsStrongClass, } from '../css/css-denomination-appearance.js';
|
|
5
8
|
import { denominationCellToneAppearances, denominationCellTonesPillClass, } from '../css/css-denomination-cell-tones.js';
|
|
6
9
|
import { denominationLabelAppearances, denominationLabelsPlainClass, } from '../css/css-denomination-label.js';
|
|
7
10
|
import { DenominationStrip } from './denomination-grid/DenominationStrip.js';
|
|
8
11
|
import { DenominationTiles } from './denomination-grid/DenominationTiles.js';
|
|
12
|
+
import { TransposedStrip } from './denomination-grid/TransposedStrip.js';
|
|
9
13
|
import { assertDenominationGrid } from './denomination-grid/validate.js';
|
|
14
|
+
import { assertDenominationOptions } from './denomination-grid/validate-options.js';
|
|
10
15
|
import { assertDenominationValueRows } from './denomination-grid/validate-value-row.js';
|
|
16
|
+
import { useMediaQuery } from './use-media-query.js';
|
|
11
17
|
import { assertDenominationEntries, assertDenominationExtras, } from './denomination-grid/validate-entry.js';
|
|
18
|
+
export { denominationNegativeAppearances, denominationTransposeBreakpoints, } from './denomination-grid/types.js';
|
|
12
19
|
export { denominationCellToneAppearances, denominationGridFrames, denominationLabelAppearances, denominationTotalEmphases, };
|
|
13
20
|
/** Fails closed on a value outside a closed set, naming the prop. */
|
|
14
21
|
function assertOneOf(values, value, prop) {
|
|
15
22
|
if (!values.includes(value))
|
|
16
23
|
throw new RangeError(`Unknown ${prop}: ${String(value)}`);
|
|
17
24
|
}
|
|
18
|
-
export function DenominationGrid({ label, columns, rows, layout = 'strip', subtotal, zeroLabel = '—', totalLabel, rowRole = 'region', labelWidth, labelAppearance = 'tone', frame = 'none', totalEmphasis = 'default', cellToneAppearance = 'text', }) {
|
|
25
|
+
export function DenominationGrid({ label, columns, rows, layout = 'strip', subtotal, zeroLabel = '—', totalLabel, rowRole = 'region', labelWidth, labelAppearance = 'tone', frame = 'none', totalEmphasis = 'default', cellToneAppearance = 'text', transposeBelow, countDigits, }) {
|
|
19
26
|
assertDenominationGrid(label, columns, rows);
|
|
20
27
|
assertDenominationExtras(layout, columns, rows);
|
|
21
28
|
assertDenominationEntries(layout, columns, rows);
|
|
22
29
|
assertDenominationValueRows(layout, columns, rows);
|
|
30
|
+
assertDenominationOptions(layout, rows, transposeBelow, countDigits);
|
|
23
31
|
if (typeof zeroLabel !== 'string')
|
|
24
32
|
throw new RangeError('zeroLabel must be a string');
|
|
25
33
|
if (totalLabel !== undefined && !totalLabel.trim())
|
|
@@ -32,8 +40,18 @@ export function DenominationGrid({ label, columns, rows, layout = 'strip', subto
|
|
|
32
40
|
assertOneOf(denominationGridFrames, frame, 'frame');
|
|
33
41
|
assertOneOf(denominationTotalEmphases, totalEmphasis, 'totalEmphasis');
|
|
34
42
|
assertOneOf(denominationCellToneAppearances, cellToneAppearance, 'cellToneAppearance');
|
|
35
|
-
const appearanceClass = cx(labelAppearance === 'plain' && denominationLabelsPlainClass, totalEmphasis === 'strong' && denominationTotalsStrongClass, cellToneAppearance === 'pill' && denominationCellTonesPillClass);
|
|
43
|
+
const appearanceClass = cx(labelAppearance === 'plain' && denominationLabelsPlainClass, totalEmphasis === 'strong' && denominationTotalsStrongClass, cellToneAppearance === 'pill' && denominationCellTonesPillClass, countDigits !== undefined && denominationCountDigitsClass);
|
|
44
|
+
const countStyle = countDigits === undefined
|
|
45
|
+
? undefined
|
|
46
|
+
: { '--sw-denomination-count-digits': countDigits };
|
|
47
|
+
// Read on every render (hooks run in order); without transposeBelow the
|
|
48
|
+
// query never matches.
|
|
49
|
+
const transposed = useMediaQuery(transposeBelow === undefined
|
|
50
|
+
? 'not all'
|
|
51
|
+
: breakpointQuery('below', transposeBelow), false);
|
|
36
52
|
if (layout === 'tiles')
|
|
37
53
|
return (_jsx(DenominationTiles, { className: appearanceClass || undefined, columns: columns, label: label, rowRole: rowRole, rows: rows, subtotal: subtotal, zeroLabel: zeroLabel }));
|
|
38
|
-
|
|
54
|
+
if (transposeBelow !== undefined && transposed)
|
|
55
|
+
return (_jsx(TransposedStrip, { className: appearanceClass || undefined, columns: columns, label: label, rows: rows, style: countStyle, totalLabel: totalLabel, zeroLabel: zeroLabel }));
|
|
56
|
+
return (_jsx(DenominationStrip, { className: appearanceClass || undefined, countStyle: countStyle, columns: columns, framed: frame === 'table', label: label, labelWidth: labelWidth, rows: rows, totalLabel: totalLabel, zeroLabel: zeroLabel }));
|
|
39
57
|
}
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { type DialogHTMLAttributes, type ReactNode } from 'react';
|
|
2
2
|
import { type Breakpoint } from '../css/breakpoints.js';
|
|
3
3
|
import { type DialogAppearance, dialogAppearances } from '../css/css-dialog-banded.js';
|
|
4
|
+
import { type ThemeCanvas } from '../css/css-canvas-grouped.js';
|
|
4
5
|
import { type ActionBarSummary } from './action-bar/ActionBarSummary.js';
|
|
6
|
+
import { type DialogRole, type DialogSize, dialogSizes } from './dialog/validate.js';
|
|
5
7
|
export { dialogAppearances, type DialogAppearance };
|
|
6
|
-
export
|
|
7
|
-
/**
|
|
8
|
-
* `md` is the reading width (32rem) for a message or a short form; `lg`
|
|
9
|
-
* (56rem) holds a row of six fields or a data grid without folding it;
|
|
10
|
-
* `xl` (65rem) holds a grid of six count columns with its labels and total.
|
|
11
|
-
*/
|
|
12
|
-
export type DialogSize = (typeof dialogSizes)[number];
|
|
13
|
-
/** `alertdialog` for a dialog that interrupts to warn, such as an idle sign-out. */
|
|
14
|
-
export type DialogRole = 'dialog' | 'alertdialog';
|
|
8
|
+
export { dialogSizes, type DialogRole, type DialogSize };
|
|
15
9
|
/**
|
|
16
10
|
* The heading level of the dialog's title. It changes only the element (and
|
|
17
11
|
* so the outline a screen reader reads), never the title's look.
|
|
@@ -44,11 +38,19 @@ export type DialogProps = Omit<DialogHTMLAttributes<HTMLDialogElement>, 'onClose
|
|
|
44
38
|
* bottom edge at the full viewport width, its top corners rounded and its
|
|
45
39
|
* bottom corners square, a strip of backdrop left in view above it, and
|
|
46
40
|
* its bottom padding clearing `env(safe-area-inset-bottom)`. It slides up
|
|
47
|
-
* on open unless reduced motion is asked for. There is no drag
|
|
48
|
-
*
|
|
49
|
-
*
|
|
41
|
+
* on open unless reduced motion is asked for. There is no drag: it
|
|
42
|
+
* closes as any dialog does. From the breakpoint up it is the centered
|
|
43
|
+
* dialog, at its `size`.
|
|
50
44
|
*/
|
|
51
45
|
sheetBelow?: Breakpoint;
|
|
46
|
+
/**
|
|
47
|
+
* Draws a grabber, a short rounded bar centered at the top edge, while
|
|
48
|
+
* the dialog is a bottom sheet (below `sheetBelow`, which it needs). It
|
|
49
|
+
* only marks the sheet as one: it is hidden from assistive technology
|
|
50
|
+
* and does not drag. It stays at the top while the content scrolls.
|
|
51
|
+
* From the breakpoint up it is not drawn.
|
|
52
|
+
*/
|
|
53
|
+
sheetGrabber?: boolean;
|
|
52
54
|
/**
|
|
53
55
|
* The accessible name of a close button, such as "Close". When given, an
|
|
54
56
|
* icon-only ghost button ends the title row and asks `onClose`, like
|
|
@@ -74,6 +76,13 @@ export type DialogProps = Omit<DialogHTMLAttributes<HTMLDialogElement>, 'onClose
|
|
|
74
76
|
* polite live region: "Drawer +$1,000.00 vault −$1,000.00".
|
|
75
77
|
*/
|
|
76
78
|
summary?: ActionBarSummary;
|
|
79
|
+
/**
|
|
80
|
+
* One short line in the footer, after the summary and before the
|
|
81
|
+
* actions, in the same polite live region: plain words (muted, caption
|
|
82
|
+
* size), or a `Badge` and a short line in one `span`. Nothing
|
|
83
|
+
* (`undefined`, `null`, `false`, or blank words) leaves it out.
|
|
84
|
+
*/
|
|
85
|
+
status?: ReactNode;
|
|
77
86
|
/** `alertdialog` for a warning that interrupts. Default `dialog`. */
|
|
78
87
|
role?: DialogRole;
|
|
79
88
|
/**
|
|
@@ -82,6 +91,13 @@ export type DialogProps = Omit<DialogHTMLAttributes<HTMLDialogElement>, 'onClose
|
|
|
82
91
|
* quiet round fill; `glass` (the default) is one frosted panel.
|
|
83
92
|
*/
|
|
84
93
|
appearance?: DialogAppearance;
|
|
94
|
+
/**
|
|
95
|
+
* The dialog's fill. `grouped` puts its content on the grouped canvas
|
|
96
|
+
* (the quieter grey `ThemeProvider canvas="grouped"` paints), solid with
|
|
97
|
+
* no blur, so `Card`s inside stand apart; a banded title row and the
|
|
98
|
+
* footer stay on the surface. `default` keeps the appearance's fill.
|
|
99
|
+
*/
|
|
100
|
+
canvas?: ThemeCanvas;
|
|
85
101
|
children: ReactNode;
|
|
86
102
|
};
|
|
87
|
-
export declare function Dialog({ 'aria-describedby': describedBy, appearance, children, className, closeLabel, description, footer, icon, role, summary, onCancel, onClose, onKeyDown, onPointerDown, onSubmit, open, sheetBelow, size, title, titleLevel, ...rest }: DialogProps): import("react").JSX.Element;
|
|
103
|
+
export declare function Dialog({ 'aria-describedby': describedBy, appearance, canvas, children, className, closeLabel, description, footer, icon, role, summary, onCancel, onClose, onKeyDown, onPointerDown, onSubmit, open, sheetBelow, sheetGrabber, size, status, title, titleLevel, ...rest }: DialogProps): import("react").JSX.Element;
|
|
@@ -4,33 +4,35 @@ import { useId } from 'react';
|
|
|
4
4
|
import { cx } from '../class-names.js';
|
|
5
5
|
import { dialogSheetClass } from '../css/css-dialog.js';
|
|
6
6
|
import { dialogAppearances, dialogBandedClass, } from '../css/css-dialog-banded.js';
|
|
7
|
+
import { dialogCanvasClass } from '../css/css-dialog-canvas.js';
|
|
8
|
+
import { dialogGrabberClass, dialogHasGrabberClass, } from '../css/css-dialog-grabber.js';
|
|
7
9
|
import { spacingClassNames } from '../spacing-classes.js';
|
|
8
10
|
import { useDialogCloseRequests } from './dialog-close-requests.js';
|
|
9
|
-
import { assertActionBarSummary, } from './action-bar/ActionBarSummary.js';
|
|
10
11
|
import { DialogFooter } from './dialog/DialogFooter.js';
|
|
11
12
|
import { DialogTitle } from './dialog/DialogTitle.js';
|
|
13
|
+
import { assertDialogProps, dialogSizes, } from './dialog/validate.js';
|
|
12
14
|
import { Stack } from './Stack.js';
|
|
13
15
|
export { dialogAppearances };
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (summary)
|
|
27
|
-
assertActionBarSummary(summary);
|
|
28
|
-
}
|
|
29
|
-
export function Dialog({ 'aria-describedby': describedBy, appearance = 'glass', children, className, closeLabel, description, footer, icon, role, summary, onCancel, onClose, onKeyDown, onPointerDown, onSubmit, open, sheetBelow, size = 'md', title, titleLevel = 3, ...rest }) {
|
|
30
|
-
assertDialogProps(size, role, description, summary, appearance);
|
|
16
|
+
export { dialogSizes };
|
|
17
|
+
export function Dialog({ 'aria-describedby': describedBy, appearance = 'glass', canvas = 'default', children, className, closeLabel, description, footer, icon, role, summary, onCancel, onClose, onKeyDown, onPointerDown, onSubmit, open, sheetBelow, sheetGrabber = false, size = 'md', status, title, titleLevel = 3, ...rest }) {
|
|
18
|
+
assertDialogProps({
|
|
19
|
+
appearance,
|
|
20
|
+
canvas,
|
|
21
|
+
description,
|
|
22
|
+
role,
|
|
23
|
+
sheetBelow,
|
|
24
|
+
sheetGrabber,
|
|
25
|
+
size,
|
|
26
|
+
summary,
|
|
27
|
+
});
|
|
31
28
|
const titleId = useId();
|
|
32
29
|
const descriptionId = useId();
|
|
33
|
-
|
|
30
|
+
// Nothing, or blank words, leaves the line out, as in ActionBar.
|
|
31
|
+
const hasStatus = status !== undefined &&
|
|
32
|
+
status !== null &&
|
|
33
|
+
status !== false &&
|
|
34
|
+
!(typeof status === 'string' && !status.trim());
|
|
35
|
+
const hasFooter = Boolean(footer) || Boolean(summary) || hasStatus;
|
|
34
36
|
const { nodeRef, handlers } = useDialogCloseRequests({
|
|
35
37
|
open,
|
|
36
38
|
onClose,
|
|
@@ -39,5 +41,5 @@ export function Dialog({ 'aria-describedby': describedBy, appearance = 'glass',
|
|
|
39
41
|
onPointerDown,
|
|
40
42
|
onSubmit,
|
|
41
43
|
});
|
|
42
|
-
return (
|
|
44
|
+
return (_jsxs("dialog", { ...rest, ref: nodeRef, "aria-describedby": describedBy ?? (description ? descriptionId : undefined), "aria-labelledby": titleId, className: cx('sw-dialog', size !== 'md' && `sw-dialog-${size}`, sheetBelow && dialogSheetClass(sheetBelow), appearance === 'banded' && dialogBandedClass, canvas === 'grouped' && dialogCanvasClass, sheetGrabber && dialogHasGrabberClass, ...spacingClassNames({ padding: 5 }), className), role: role === 'alertdialog' ? 'alertdialog' : undefined, ...handlers, children: [sheetGrabber ? (_jsx("span", { "aria-hidden": "true", className: dialogGrabberClass })) : null, _jsxs(Stack, { gap: 4, children: [_jsx(DialogTitle, { banded: appearance === 'banded', closeLabel: closeLabel, description: description, descriptionId: descriptionId, icon: icon, id: titleId, level: titleLevel === 2 ? 2 : 3, onClose: onClose, title: title }), children, hasFooter ? (_jsx(DialogFooter, { status: hasStatus ? status : undefined, summary: summary, children: footer })) : null] })] }));
|
|
43
45
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type SpacingStep } from '@scalewing/tokens';
|
|
2
2
|
import { type ReactNode } from 'react';
|
|
3
3
|
import { type RequiredMark } from './FieldLabelText.js';
|
|
4
|
+
import { type FieldWidth } from '../css/css-field-width.js';
|
|
5
|
+
import { fieldVariants, type FieldVariant } from './field/field-checks.js';
|
|
4
6
|
export type FieldSize = 'xs' | 'md';
|
|
5
|
-
export
|
|
6
|
-
export type FieldVariant = (typeof fieldVariants)[number];
|
|
7
|
+
export { fieldVariants, type FieldVariant };
|
|
7
8
|
export type FieldProps = {
|
|
8
9
|
children: ReactNode;
|
|
9
10
|
gap?: SpacingStep;
|
|
@@ -60,5 +61,15 @@ export type FieldProps = {
|
|
|
60
61
|
clearLabel?: string;
|
|
61
62
|
/** Called by a search field's clear button; the consumer empties the value. */
|
|
62
63
|
onClear?: () => void;
|
|
64
|
+
/**
|
|
65
|
+
* Caps the control's width at a Table column size (`xs` 4rem, `sm` 6rem,
|
|
66
|
+
* `md` 8rem, `lg` 12rem, `xl` 16rem), at the start of the column and
|
|
67
|
+
* never wider than it, so a short value such as a rate or a count does
|
|
68
|
+
* not stretch across a form. The label and messages keep the column's
|
|
69
|
+
* width. Left out, the control fills the column. It needs one native
|
|
70
|
+
* text input, select or textarea child (a `TypeError` otherwise); an
|
|
71
|
+
* unknown width throws a `RangeError`.
|
|
72
|
+
*/
|
|
73
|
+
width?: FieldWidth;
|
|
63
74
|
};
|
|
64
75
|
export declare function Field(props: FieldProps): import("react").JSX.Element;
|