@scalewing/react 1.40.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +154 -6
  3. package/dist/calendar-labels.d.ts +2 -0
  4. package/dist/calendar-labels.js +7 -0
  5. package/dist/components/BarChart.d.ts +20 -4
  6. package/dist/components/BarChart.js +13 -6
  7. package/dist/components/ButtonGroup.d.ts +8 -1
  8. package/dist/components/ButtonGroup.js +11 -2
  9. package/dist/components/DateField.d.ts +14 -2
  10. package/dist/components/DateField.js +14 -11
  11. package/dist/components/DenominationGrid.d.ts +3 -2
  12. package/dist/components/DenominationGrid.js +21 -3
  13. package/dist/components/Dialog.d.ts +29 -13
  14. package/dist/components/Dialog.js +22 -20
  15. package/dist/components/Field.d.ts +13 -2
  16. package/dist/components/Field.js +14 -38
  17. package/dist/components/FilterChips.d.ts +7 -37
  18. package/dist/components/FilterChips.js +32 -24
  19. package/dist/components/ListRow.d.ts +11 -2
  20. package/dist/components/ListRow.js +3 -2
  21. package/dist/components/SegmentedControl.d.ts +17 -1
  22. package/dist/components/SegmentedControl.js +11 -3
  23. package/dist/components/Switch.d.ts +16 -1
  24. package/dist/components/Switch.js +17 -6
  25. package/dist/components/action-bar/ActionBarSummary.d.ts +10 -2
  26. package/dist/components/action-bar/ActionBarSummary.js +11 -2
  27. package/dist/components/date-field/CalendarEntryButton.d.ts +24 -0
  28. package/dist/components/date-field/CalendarEntryButton.js +16 -0
  29. package/dist/components/date-field/TypedEntry.d.ts +26 -0
  30. package/dist/components/date-field/TypedEntry.js +13 -0
  31. package/dist/components/denomination-grid/CountCell.d.ts +16 -0
  32. package/dist/components/denomination-grid/CountCell.js +14 -0
  33. package/dist/components/denomination-grid/DenominationStrip.d.ts +4 -1
  34. package/dist/components/denomination-grid/DenominationStrip.js +2 -2
  35. package/dist/components/denomination-grid/EntryCell.d.ts +3 -1
  36. package/dist/components/denomination-grid/EntryCell.js +2 -2
  37. package/dist/components/denomination-grid/StripRow.js +1 -10
  38. package/dist/components/denomination-grid/TransposedStrip.d.ts +17 -0
  39. package/dist/components/denomination-grid/TransposedStrip.js +43 -0
  40. package/dist/components/denomination-grid/types.d.ts +31 -0
  41. package/dist/components/denomination-grid/types.js +7 -1
  42. package/dist/components/denomination-grid/validate-options.d.ts +7 -0
  43. package/dist/components/denomination-grid/validate-options.js +27 -0
  44. package/dist/components/dialog/DialogFooter.d.ts +6 -5
  45. package/dist/components/dialog/DialogFooter.js +6 -6
  46. package/dist/components/dialog/validate.d.ts +24 -0
  47. package/dist/components/dialog/validate.js +23 -0
  48. package/dist/components/field/field-checks.d.ts +34 -0
  49. package/dist/components/field/field-checks.js +42 -0
  50. package/dist/components/filter-chips/FilterChip.d.ts +16 -0
  51. package/dist/components/filter-chips/FilterChip.js +20 -0
  52. package/dist/components/filter-chips/options.d.ts +75 -0
  53. package/dist/components/filter-chips/options.js +11 -0
  54. package/dist/components/filter-chips/validate.d.ts +9 -0
  55. package/dist/components/filter-chips/validate.js +48 -0
  56. package/dist/components/list/ListRowContent.d.ts +3 -1
  57. package/dist/components/list/ListRowContent.js +3 -2
  58. package/dist/css/chart-tones.d.ts +2 -0
  59. package/dist/css/chart-tones.js +5 -1
  60. package/dist/css/css-bar-chart.d.ts +17 -2
  61. package/dist/css/css-bar-chart.js +38 -7
  62. package/dist/css/css-button-group-attached.d.ts +3 -0
  63. package/dist/css/css-button-group-attached.js +18 -1
  64. package/dist/css/css-canvas-grouped.d.ts +17 -0
  65. package/dist/css/css-canvas-grouped.js +40 -0
  66. package/dist/css/css-components.js +6 -0
  67. package/dist/css/css-date-field-calendar-entry.d.ts +11 -0
  68. package/dist/css/css-date-field-calendar-entry.js +50 -0
  69. package/dist/css/css-date-field.js +4 -0
  70. package/dist/css/css-denomination-grid.js +4 -0
  71. package/dist/css/css-denomination-transposed.d.ts +4 -0
  72. package/dist/css/css-denomination-transposed.js +178 -0
  73. package/dist/css/css-dialog-canvas.d.ts +3 -0
  74. package/dist/css/css-dialog-canvas.js +20 -0
  75. package/dist/css/css-dialog-frame.js +19 -2
  76. package/dist/css/css-dialog-grabber.d.ts +4 -0
  77. package/dist/css/css-dialog-grabber.js +56 -0
  78. package/dist/css/css-dialog.js +3 -2
  79. package/dist/css/css-document.js +3 -0
  80. package/dist/css/css-field-width.d.ts +12 -0
  81. package/dist/css/css-field-width.js +49 -0
  82. package/dist/css/css-field.js +4 -0
  83. package/dist/css/css-filter-chips-layout.d.ts +2 -0
  84. package/dist/css/css-filter-chips-layout.js +42 -0
  85. package/dist/css/css-filter-chips.js +4 -0
  86. package/dist/css/css-list-row.d.ts +6 -0
  87. package/dist/css/css-list-row.js +19 -3
  88. package/dist/css/css-segmented-sizing.d.ts +13 -0
  89. package/dist/css/css-segmented-sizing.js +66 -0
  90. package/dist/css/css-segmented.js +4 -0
  91. package/dist/css/css-switch.d.ts +6 -0
  92. package/dist/css/css-switch.js +39 -0
  93. package/dist/css/stacking.d.ts +1 -0
  94. package/dist/css/stacking.js +4 -1
  95. package/dist/css/stylesheet.js +4 -0
  96. package/dist/date-field-labels.d.ts +5 -0
  97. package/dist/date-field-labels.js +1 -0
  98. package/dist/index.d.ts +10 -8
  99. package/dist/index.js +8 -6
  100. package/dist/list-options.d.ts +8 -7
  101. package/dist/list-options.js +15 -8
  102. package/dist/styles.css +343 -2
  103. package/dist/theme/ThemeProvider.d.ts +11 -1
  104. package/dist/theme/ThemeProvider.js +4 -2
  105. package/package.json +1 -1
@@ -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 { DateFieldGlyph } from './date-field/DateFieldGlyph.js';
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
- import { tabStop } from '../tab-stop.js';
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("input", { "aria-describedby": describedBy || undefined, "aria-invalid": invalid, autoComplete: "off", className: "sw-date-field-input", disabled: disabled, id: inputId, onBlur: entry.check, onChange: (event) => entry.change(event.currentTarget.value), onKeyDown: (event) => {
57
- if (event.key === 'Enter')
58
- entry.check();
59
- }, placeholder: dateEntryPlaceholder(pattern, {
60
- day: words.dayPlaceholder,
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
  }
@@ -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
- return (_jsx(DenominationStrip, { className: appearanceClass || undefined, columns: columns, framed: frame === 'table', label: label, labelWidth: labelWidth, rows: rows, totalLabel: totalLabel, zeroLabel: zeroLabel }));
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 declare const dialogSizes: readonly ["md", "lg", "xl"];
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 grabber
48
- * (and no drag): it closes as any dialog does. From the breakpoint up it
49
- * is the centered dialog, at its `size`.
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 const dialogSizes = ['md', 'lg', 'xl'];
15
- const dialogRoles = ['dialog', 'alertdialog'];
16
- function assertDialogProps(size, role, description, summary, appearance) {
17
- if (!dialogSizes.includes(size))
18
- throw new RangeError(`Unknown Dialog size: ${String(size)}`);
19
- if (!dialogAppearances.includes(appearance))
20
- throw new RangeError(`Unknown Dialog appearance: ${String(appearance)}`);
21
- if (role !== undefined && !dialogRoles.includes(role))
22
- throw new RangeError(`Unknown Dialog role: ${String(role)}`);
23
- if (description !== undefined &&
24
- (typeof description !== 'string' || !description.trim()))
25
- throw new RangeError('Dialog description must not be empty');
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
- const hasFooter = Boolean(footer) || Boolean(summary);
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 (_jsx("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, ...spacingClassNames({ padding: 5 }), className), role: role === 'alertdialog' ? 'alertdialog' : undefined, ...handlers, children: _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, { summary: summary, children: footer })) : null] }) }));
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 declare const fieldVariants: readonly ["outlined", "search"];
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;
@@ -4,45 +4,14 @@ import { cloneElement, isValidElement, useId, } from 'react';
4
4
  import { adornedControlAria, FieldAdornment, } from './FieldAdornment.js';
5
5
  import { FieldErrorRegion } from './FieldErrorRegion.js';
6
6
  import { assertRequiredMark, FieldLabelText, } from './FieldLabelText.js';
7
+ import { fieldWidthClass } from '../css/css-field-width.js';
7
8
  import { SearchFrame } from './field/SearchFrame.js';
9
+ import { assertFieldProps, fieldVariants, passesInvalid, } from './field/field-checks.js';
8
10
  import { Stack } from './Stack.js';
9
- export const fieldVariants = ['outlined', 'search'];
10
- function assertSearch(props, child) {
11
- const { variant = 'outlined' } = props;
12
- if (!fieldVariants.includes(variant))
13
- throw new RangeError(`Unknown Field variant: ${String(variant)}`);
14
- if (variant !== 'search') {
15
- if (props.leading !== undefined ||
16
- props.clearLabel !== undefined ||
17
- props.onClear !== undefined)
18
- throw new TypeError('Field leading, clearLabel and onClear are for variant="search"');
19
- return;
20
- }
21
- if (!props.clearLabel?.trim())
22
- throw new RangeError('A search Field needs a nonempty clearLabel');
23
- if (typeof props.onClear !== 'function')
24
- throw new TypeError('A search Field needs onClear');
25
- if (props.prefix || props.suffix)
26
- throw new TypeError('A search Field takes leading, not prefix or suffix');
27
- if (!isValidElement(child) || child.type !== 'input')
28
- throw new TypeError('A search Field needs one native input child');
29
- if (child.props.value === undefined)
30
- throw new TypeError('A search Field needs a controlled input: pass value (and onChange)');
31
- }
32
- /**
33
- * `invalid` was passed, even as `false`, but not as `undefined` (a wrapper
34
- * forwarding an optional prop passes nothing): such a field needs one native
35
- * control from its first render, so a form learns it on the happy path
36
- * instead of on its first failed submit. `error` keeps its older rule (it
37
- * requires the control only while it holds a message), so a composed
38
- * child beside `error={undefined}` still renders.
39
- */
40
- function passesInvalid(props) {
41
- return props.invalid !== undefined || props.changed !== undefined;
42
- }
11
+ export { fieldVariants };
43
12
  export function Field(props) {
44
- const { children, gap = 1, label, labelVisuallyHidden = false, size = 'md', description, error, invalid = false, changed = false, required = false, requiredMark = 'visible', prefix, suffix, variant = 'outlined', leading, clearLabel = '', onClear, } = props;
45
- assertSearch(props, children);
13
+ const { children, gap = 1, label, labelVisuallyHidden = false, size = 'md', description, error, invalid = false, changed = false, required = false, requiredMark = 'visible', prefix, suffix, variant = 'outlined', leading, clearLabel = '', onClear, width, } = props;
14
+ assertFieldProps(props, children);
46
15
  const search = variant === 'search';
47
16
  const controlId = useId();
48
17
  const descriptionId = useId();
@@ -54,13 +23,20 @@ export function Field(props) {
54
23
  const message = error || description;
55
24
  const marksInvalid = Boolean(error) || invalid;
56
25
  const adorned = Boolean(prefix || suffix);
57
- const needsControl = Boolean(message || marksInvalid || passesInvalid(props) || required || adorned);
26
+ const needsControl = Boolean(message ||
27
+ marksInvalid ||
28
+ passesInvalid(props) ||
29
+ required ||
30
+ adorned ||
31
+ Boolean(width));
58
32
  const className = [
59
33
  'sw-field',
60
34
  size === 'xs' && 'sw-field-xs',
61
35
  marksInvalid && 'sw-field-invalid',
62
36
  search && 'sw-field-search-field',
63
37
  changed && !marksInvalid && 'sw-field-changed',
38
+ width && 'sw-field-sized',
39
+ width && fieldWidthClass(width),
64
40
  ]
65
41
  .filter(Boolean)
66
42
  .join(' ');
@@ -71,7 +47,7 @@ export function Field(props) {
71
47
  typeof children.type !== 'string' ||
72
48
  !['input', 'select', 'textarea'].includes(children.type)) {
73
49
  if (needsControl)
74
- throw new TypeError('Field validation and adornments require one native input, select, or textarea child');
50
+ throw new TypeError('Field validation, adornments and width require one native input, select, or textarea child');
75
51
  return (_jsxs(Stack, { as: "label", className: className, gap: labelHidden ? 0 : gap, children: [labelText, children] }));
76
52
  }
77
53
  if (adorned && children.type !== 'input')
@@ -1,37 +1,7 @@
1
- import { type RequiredMark } from './FieldLabelText.js';
2
- export type FilterChipOption = {
3
- value: string;
4
- label: string;
5
- count?: number;
6
- disabled?: boolean;
7
- };
8
- export type FilterChipsProps = {
9
- label: string;
10
- /** The chosen option's value, or `''` while nothing is chosen yet. */
11
- value: string;
12
- onChange: (value: string) => void;
13
- options: readonly FilterChipOption[];
14
- /**
15
- * A choice must be made, such as a reason: each radio is `required` and
16
- * the label shows the required mark (hidden from assistive technology,
17
- * which reads the radios' own state).
18
- */
19
- required?: boolean;
20
- /**
21
- * `hidden` leaves out the label's " *" while the control stays required
22
- * (and announced so); `visible` (default) draws it.
23
- * When hidden, say in visible text which fields must be filled; a
24
- * placeholder alone is not enough.
25
- */
26
- requiredMark?: RequiredMark;
27
- /**
28
- * A message under the chips, such as "Pick a reason": a polite live
29
- * region linked to the group by `aria-describedby`; the group is marked
30
- * invalid and every chip takes the danger edge. An empty string is no
31
- * error.
32
- */
33
- error?: string;
34
- /** More ids that describe the group, such as a hint beside it. */
35
- 'aria-describedby'?: string;
36
- };
37
- export declare function FilterChips({ label, value, onChange, options, required, requiredMark, error, 'aria-describedby': describedByProp, }: FilterChipsProps): import("react").JSX.Element;
1
+ import { type FilterChipsProps } from './filter-chips/options.js';
2
+ export { filterChipCountAppearances, filterChipsOverflows, type FilterChipCountAppearance, type FilterChipOption, type FilterChipsOverflow, type FilterChipsProps, } from './filter-chips/options.js';
3
+ /**
4
+ * A labelled row of chips: one choice (radios), or several at once
5
+ * (`multiple`, checkboxes), each chip optionally counted.
6
+ */
7
+ export declare function FilterChips(props: FilterChipsProps): import("react").JSX.Element;
@@ -1,35 +1,43 @@
1
1
  'use client';
2
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useId } from 'react';
4
4
  import { cx } from '../class-names.js';
5
+ import { radioTabStopValue } from '../tab-stop.js';
5
6
  import { FieldErrorRegion } from './FieldErrorRegion.js';
6
- import { assertRequiredMark, showsRequiredMark, } from './FieldLabelText.js';
7
- import { radioTabStopValue, tabStop } from '../tab-stop.js';
8
- function isCount(count) {
9
- return count === undefined || (Number.isInteger(count) && count >= 0);
7
+ import { showsRequiredMark } from './FieldLabelText.js';
8
+ import { FilterChip } from './filter-chips/FilterChip.js';
9
+ import { assertFilterChips } from './filter-chips/validate.js';
10
+ export { filterChipCountAppearances, filterChipsOverflows, } from './filter-chips/options.js';
11
+ /** The values a change leaves on, in the options' order. */
12
+ function toggled(options, chosen, value, checked) {
13
+ return options
14
+ .map((option) => option.value)
15
+ .filter((each) => (each === value ? checked : chosen.includes(each)));
10
16
  }
11
- export function FilterChips({ label, value, onChange, options, required = false, requiredMark = 'visible', error, 'aria-describedby': describedByProp, }) {
17
+ /**
18
+ * A labelled row of chips: one choice (radios), or several at once
19
+ * (`multiple`, checkboxes), each chip optionally counted.
20
+ */
21
+ export function FilterChips(props) {
22
+ const { label, options, labelVisuallyHidden = false, requiredMark = 'visible', countAppearance = 'figure', overflow = 'wrap', error, 'aria-describedby': describedByProp, } = props;
12
23
  const name = useId();
13
24
  const errorId = useId();
25
+ assertFilterChips(props);
26
+ const required = props.multiple ? false : (props.required ?? false);
14
27
  const describedBy = [describedByProp?.trim() || null, error ? errorId : null]
15
28
  .filter((id) => id !== null)
16
29
  .join(' ');
17
- const values = options.map((option) => option.value);
18
- if (!label.trim())
19
- throw new RangeError('label must not be empty');
20
- assertRequiredMark(requiredMark);
21
- if (options.length === 0 ||
22
- options.some((option) => !option.value.trim() || !option.label.trim()))
23
- throw new RangeError('options must have nonempty values and labels');
24
- if (new Set(values).size !== values.length)
25
- throw new RangeError('options must have unique values');
26
- if (value !== '' && !values.includes(value))
27
- throw new RangeError('value must match an option or be empty');
28
- if (options.some((option) => !isCount(option.count)))
29
- throw new RangeError('count must be a non-negative integer');
30
- const entry = radioTabStopValue(options, value);
31
- return (_jsxs("fieldset", { "aria-describedby": describedBy || undefined, "aria-invalid": error ? true : undefined, className: "sw-filter-chips", children: [_jsxs("legend", { className: "sw-filter-chips-legend", children: [label, showsRequiredMark(required, requiredMark) ? (_jsxs("span", { "aria-hidden": "true", className: "sw-field-required", children: [' ', "*"] })) : null] }), _jsx("span", { className: "sw-filter-chips-options", children: options.map((option) => (_jsxs("label", { className: cx('sw-filter-chip', option.count === 0 && 'sw-filter-chip-quiet'), children: [_jsx("input", { checked: option.value === value, className: "sw-filter-chip-input", disabled: option.disabled, name: name, onChange: (event) => {
32
- if (event.currentTarget.checked && !option.disabled)
33
- onChange(option.value);
34
- }, required: required, tabIndex: option.value === entry ? tabStop : undefined, type: "radio", value: option.value }), _jsxs("span", { className: "sw-filter-chip-face", children: [option.label, option.count === undefined ? null : (_jsxs(_Fragment, { children: [' ', _jsx("span", { className: "sw-filter-chip-count", children: option.count })] }))] })] }, option.value))) }), _jsx(FieldErrorRegion, { className: "sw-filter-chips-error", id: errorId, message: error })] }));
30
+ const entry = props.multiple
31
+ ? undefined
32
+ : radioTabStopValue(options, props.value);
33
+ function isChecked(value) {
34
+ return props.multiple ? props.value.includes(value) : props.value === value;
35
+ }
36
+ function change(value, checked) {
37
+ if (props.multiple)
38
+ props.onChange(toggled(options, props.value, value, checked));
39
+ else if (checked)
40
+ props.onChange(value);
41
+ }
42
+ return (_jsxs("fieldset", { "aria-describedby": describedBy || undefined, "aria-invalid": error ? true : undefined, className: cx('sw-filter-chips', overflow === 'scroll' && 'sw-filter-chips-scroll'), children: [_jsxs("legend", { className: cx('sw-filter-chips-legend', labelVisuallyHidden && 'sw-sr-only'), children: [label, showsRequiredMark(required, requiredMark) ? (_jsxs("span", { "aria-hidden": "true", className: "sw-field-required", children: [' ', "*"] })) : null] }), _jsx("span", { className: "sw-filter-chips-options", children: options.map((option) => (_jsx(FilterChip, { checked: isChecked(option.value), countAppearance: countAppearance, name: name, onCheckedChange: (checked) => change(option.value, checked), option: option, required: required, tabStopHere: props.multiple ? true : option.value === entry, type: props.multiple ? 'checkbox' : 'radio' }, option.value))) }), _jsx(FieldErrorRegion, { className: "sw-filter-chips-error", id: errorId, message: error })] }));
35
43
  }
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type BadgeTone } from '../css/css-data.js';
2
3
  import { type ListRowTitleAppearance, type ListRowTone, type ListRowValueTone } from '../list-options.js';
3
4
  export type ListRowProps = {
4
5
  title: string;
@@ -8,8 +9,16 @@ export type ListRowProps = {
8
9
  value?: string;
9
10
  /** A muted line under the value, such as "checks $3,427". */
10
11
  valueDetail?: string;
11
- /** Colours the value only, as a table cell's tone; the words say why. */
12
+ /**
13
+ * Colours the value only, as a table cell's tone, or `warning` for a
14
+ * figure that needs a look; the words say why.
15
+ */
12
16
  valueTone?: ListRowValueTone;
17
+ /**
18
+ * Draws the value as a `Badge` in this tone, such as a status ("Open",
19
+ * "Blocked") at the row's end. Not with `valueTone`.
20
+ */
21
+ valueBadge?: BadgeTone;
13
22
  /**
14
23
  * A consumer mark at the row's start, such as a status dot or a Lucide
15
24
  * glyph (ADR 0008). It is hidden from assistive technology, so the words
@@ -48,4 +57,4 @@ export type ListRowProps = {
48
57
  * a chevron, the whole row pressing), picks one option in place
49
58
  * (`selected`), or only states something (neither).
50
59
  */
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;
60
+ export declare function ListRow({ title, detail, value, valueDetail, valueTone, valueBadge, leading, onPress, href, selected, disabled, tone, titleAppearance, accessory, 'aria-label': ariaLabel, }: ListRowProps): import("react").JSX.Element;
@@ -16,7 +16,7 @@ function ids(...parts) {
16
16
  * a chevron, the whole row pressing), picks one option in place
17
17
  * (`selected`), or only states something (neither).
18
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, }) {
19
+ export function ListRow({ title, detail, value, valueDetail, valueTone, valueBadge, leading, onPress, href, selected, disabled = false, tone = 'default', titleAppearance = 'strong', accessory = 'chevron', 'aria-label': ariaLabel, }) {
20
20
  const pressable = onPress !== undefined || href !== undefined;
21
21
  assertListRow({
22
22
  title,
@@ -26,13 +26,14 @@ export function ListRow({ title, detail, value, valueDetail, valueTone, leading,
26
26
  accessory,
27
27
  value,
28
28
  valueDetail,
29
+ valueBadge,
29
30
  selected,
30
31
  pressable,
31
32
  });
32
33
  const container = useContext(ListRowContainer);
33
34
  const id = useId();
34
35
  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 content = (_jsx(ListRowContent, { accessory: kind, detail: detail, id: id, leading: leading, title: title, titleAppearance: titleAppearance, tone: tone, value: value, valueBadge: valueBadge, valueDetail: valueDetail, valueTone: valueTone }));
36
37
  const className = cx('sw-list-row', pressable && 'sw-list-row-pressable', disabled && 'sw-list-row-disabled');
37
38
  const naming = {
38
39
  'aria-label': ariaLabel,
@@ -1,5 +1,8 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import { type AccessibleName } from '../accessible-name.js';
3
+ import { type Breakpoint } from '../css/breakpoints.js';
4
+ import { type SegmentedSize, segmentedSizes } from '../css/css-segmented-sizing.js';
5
+ export { segmentedSizes, type SegmentedSize };
3
6
  export type SegmentedItem = {
4
7
  id: string;
5
8
  label: ReactNode;
@@ -46,6 +49,19 @@ export type SegmentedControlProps = AccessibleName & SegmentedChange & {
46
49
  error?: string;
47
50
  /** Sets `aria-required` on the group; the visible mark belongs to the element that labels it. */
48
51
  required?: boolean;
52
+ /**
53
+ * Below this breakpoint the control fills its column and its segments
54
+ * share the width equally, whatever the variant, such as a period
55
+ * switch across a phone. From it up it keeps its own width.
56
+ */
57
+ fullWidthBelow?: Breakpoint;
58
+ /**
59
+ * `sm` pads every segment a step less and keeps each label on one line
60
+ * (ending in an ellipsis past its share; its name keeps the whole
61
+ * label), so three or four segments with counts fit a phone's card.
62
+ * Keep the labels short enough to fit: the hidden part cannot be read.
63
+ * `md` (the default) is the variant's own padding.
64
+ */
65
+ size?: SegmentedSize;
49
66
  };
50
67
  export declare const SegmentedControl: import("react").ForwardRefExoticComponent<SegmentedControlProps & import("react").RefAttributes<HTMLDivElement>>;
51
- export {};