@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.
- package/CHANGELOG.md +24 -0
- package/README.md +154 -6
- package/dist/calendar-labels.d.ts +2 -0
- package/dist/calendar-labels.js +7 -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/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/ListRow.d.ts +11 -2
- package/dist/components/ListRow.js +3 -2
- package/dist/components/SegmentedControl.d.ts +17 -1
- package/dist/components/SegmentedControl.js +11 -3
- 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/CalendarEntryButton.d.ts +24 -0
- package/dist/components/date-field/CalendarEntryButton.js +16 -0
- package/dist/components/date-field/TypedEntry.d.ts +26 -0
- package/dist/components/date-field/TypedEntry.js +13 -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/list/ListRowContent.d.ts +3 -1
- package/dist/components/list/ListRowContent.js +3 -2
- package/dist/css/chart-tones.d.ts +2 -0
- package/dist/css/chart-tones.js +5 -1
- 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 +18 -1
- package/dist/css/css-canvas-grouped.d.ts +17 -0
- package/dist/css/css-canvas-grouped.js +40 -0
- package/dist/css/css-components.js +6 -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 +4 -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 +6 -0
- package/dist/css/css-list-row.js +19 -3
- 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-switch.d.ts +6 -0
- package/dist/css/css-switch.js +39 -0
- package/dist/css/stacking.d.ts +1 -0
- package/dist/css/stacking.js +4 -1
- package/dist/css/stylesheet.js +4 -0
- package/dist/date-field-labels.d.ts +5 -0
- package/dist/date-field-labels.js +1 -0
- package/dist/index.d.ts +10 -8
- package/dist/index.js +8 -6
- package/dist/list-options.d.ts +8 -7
- package/dist/list-options.js +15 -8
- package/dist/styles.css +343 -2
- package/dist/theme/ThemeProvider.d.ts +11 -1
- package/dist/theme/ThemeProvider.js +4 -2
- 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 {
|
|
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
|
}
|
|
@@ -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;
|
package/dist/components/Field.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 ||
|
|
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
|
|
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
|
|
2
|
-
export type FilterChipOption
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
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 {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
/**
|
|
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 {};
|