@scalewing/react 1.36.0 → 1.38.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 +15 -0
- package/README.md +41 -3
- package/dist/accessible-name.d.ts +13 -0
- package/dist/accessible-name.js +1 -0
- package/dist/components/DataBar.d.ts +48 -0
- package/dist/components/DataBar.js +28 -0
- package/dist/components/DenominationGrid.d.ts +1 -1
- package/dist/components/DenominationGrid.js +2 -0
- package/dist/components/Pagination.d.ts +34 -0
- package/dist/components/Pagination.js +27 -0
- package/dist/components/ScrollRegion.d.ts +9 -5
- package/dist/components/ScrollRegion.js +8 -6
- package/dist/components/SectionNav.d.ts +2 -8
- package/dist/components/SegmentedControl.d.ts +2 -8
- package/dist/components/Stepper.d.ts +5 -0
- package/dist/components/Stepper.js +4 -2
- package/dist/components/Table.d.ts +48 -4
- package/dist/components/Table.js +9 -3
- package/dist/components/Tabs.d.ts +2 -9
- package/dist/components/denomination-grid/DenominationStrip.js +3 -1
- 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.d.ts +8 -2
- package/dist/components/denomination-grid/StripRow.js +14 -5
- package/dist/components/denomination-grid/StripTotal.d.ts +11 -0
- package/dist/components/denomination-grid/StripTotal.js +12 -0
- package/dist/components/denomination-grid/StripValueRow.d.ts +25 -0
- package/dist/components/denomination-grid/StripValueRow.js +27 -0
- package/dist/components/denomination-grid/types.d.ts +19 -0
- package/dist/components/denomination-grid/validate-value-row.d.ts +6 -0
- package/dist/components/denomination-grid/validate-value-row.js +30 -0
- package/dist/components/table/TableRow.d.ts +8 -2
- package/dist/components/table/TableRow.js +1 -1
- package/dist/components/table/table-max-height.d.ts +20 -0
- package/dist/components/table/table-max-height.js +23 -0
- package/dist/components/use-scroll-overflow.d.ts +10 -8
- package/dist/components/use-scroll-overflow.js +23 -10
- package/dist/css/chevron.d.ts +6 -3
- package/dist/css/chevron.js +9 -4
- package/dist/css/css-components.js +6 -0
- package/dist/css/css-data-bar.d.ts +16 -0
- package/dist/css/css-data-bar.js +107 -0
- package/dist/css/css-denomination-grid.js +4 -0
- package/dist/css/css-denomination-value-row.d.ts +3 -0
- package/dist/css/css-denomination-value-row.js +54 -0
- package/dist/css/css-pagination.d.ts +2 -0
- package/dist/css/css-pagination.js +63 -0
- package/dist/css/css-scroll-region.d.ts +1 -0
- package/dist/css/css-scroll-region.js +10 -5
- package/dist/css/css-table-bounded-edges.d.ts +1 -0
- package/dist/css/css-table-bounded-edges.js +132 -0
- package/dist/css/css-table-bounded.d.ts +2 -0
- package/dist/css/css-table-bounded.js +73 -0
- package/dist/css/css-table-ledger.d.ts +5 -2
- package/dist/css/css-table-ledger.js +5 -2
- package/dist/css/css-table-metrics.d.ts +14 -0
- package/dist/css/css-table-metrics.js +13 -0
- package/dist/css/css-table-sort.js +2 -1
- package/dist/css/css-table-total-row.d.ts +2 -0
- package/dist/css/css-table-total-row.js +29 -0
- package/dist/css/css-table.js +14 -3
- package/dist/css/stylesheet.js +4 -0
- package/dist/data-bar-geometry.d.ts +24 -0
- package/dist/data-bar-geometry.js +41 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -0
- package/dist/pagination-pages.d.ts +13 -0
- package/dist/pagination-pages.js +22 -0
- package/dist/scroll-overflow.d.ts +12 -0
- package/dist/scroll-overflow.js +31 -7
- package/dist/styles.css +258 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @scalewing/react
|
|
2
2
|
|
|
3
|
+
## 1.38.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- ac063ea: `DataBar`: a decorative (`aria-hidden`) horizontal range bar for a table cell or a list row, from `from` to `to` on a track whose domain runs from `min` to `max`, such as where a statement's line leaves the running total. A domain from below zero to above it draws a zero line, so a column of differences diverges around it, the bar's end at zero square. `tone` (`DataBarTone`: `neutral`, `success`, `muted`, `strong`, `accent`; no danger tone, money out is `muted`) colours it from the semantic colours mixed into the surface. Values past the domain are clamped; non-finite numbers, a `min` not under `max` and an unknown tone throw a `RangeError`. The bar follows the writing direction and is drawn in the system text colour in forced colours. New exports `DataBar`, `DataBarProps`, `DataBarTone`, `dataBarTones`; new classes `sw-data-bar`, `sw-data-bar-fill`, `sw-data-bar-diverging`, `sw-data-bar-zero-start`, `sw-data-bar-zero-end` and `sw-data-bar-<tone>`; no new tokens, no new dependency. Request: `docs/requests/teisoro-data-bar.md`.
|
|
8
|
+
- b95f9ea: `Pagination`: previous and next steps through a list shown a page at a time, in a `nav` landmark named by `aria-label` or `aria-labelledby`. It shows the consumer's `rangeLabel` (such as "1–25 of 130 changes") at the inline start, a polite live region, and the steps at the end: icon-only neutral `sm` Buttons named by `labels` (`PaginationLabels`: `previous`, `next`), square, 44 px on a coarse pointer, with a private chevron mirrored right to left. `page` and `pageCount` count from 1 and `onPageChange` receives the page a step goes to. At either end a step is `aria-disabled` (the neutral grey) but stays a Tab stop, so focus is not dropped at the last page, and a press there does nothing. Invalid pages or an empty step label (`labels.previous` or `labels.next`) throw a `RangeError`. New exports `Pagination`, `PaginationProps`, `PaginationLabels`; new classes `sw-pagination`, `sw-pagination-range`, `sw-pagination-steps`, `sw-pagination-step`, `sw-pagination-glyph`, `sw-pagination-glyph-previous` and `sw-pagination-glyph-next`; no new tokens, no new dependency. Request: `docs/requests/teisoro-pagination.md`.
|
|
9
|
+
- 744ed13: `Table` `maxHeight` (opt-in): bounds a table's height by a row count, `{ rows: number }` (new type `TableMaxHeight`), and the rest of the rows scroll inside the table's own region. The region is as tall as that many single-line body rows plus the header row and the footer row when there is one, from the type and spacing tokens the cells are drawn with (compact density included; a sorting header as tall as its buttons, the 44 px touch target on a coarse pointer). The header pins to the region's top and a `TableFooter sticky` total to its bottom; the region stays a keyboard stop named after the table, and an edge with rows scrolled past it draws the scroll shade, cast from the pinned header or total, or from the region's own edge where nothing is pinned (none in forced colours). While the region has keyboard focus, the pinned header and total carry the part of its focus ring they cover. Printed, every row shows. Page pinning (`stickyHeader="page"`, a sticky footer in a table that fits) is unchanged for tables without `maxHeight`; with it, `stickyHeader` `'page'` or `false` throw a `RangeError`, as does a row count that is not a whole number from 1. New classes `sw-table-bounded`, `sw-scroll-more-top` and `sw-scroll-more-bottom`; no new tokens, no new dependency. Request: `docs/requests/teisoro-table-contained-scroll.md`.
|
|
10
|
+
- b638b5e: `TableRow` `variant="total"`: a total mid-table, such as a subtotal the rows above add up to before the table goes on. Its cells are at weight 600 under a 2 px rule across its top (the cells' own collapsed border, kept in forced colours), as a `TableFooter` total is drawn, with no fill, so accent text keeps the contrast it has on the table's own surface. `tableRowVariants` is now `['default', 'sub', 'total']`. New class `sw-table-row-total`; no new tokens, no new dependency. Request: `docs/requests/teisoro-table-row-total.md`.
|
|
11
|
+
|
|
12
|
+
## 1.37.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- a9e2447: `DenominationGrid` row `valueRow` (opt-in, strip layout): a line right under a row that gives each column's value, such as the money its count adds up to. It is its own table row on the subtle fill, named in the label column (`label`), each consumer-formatted value centred under its count in tabular figures (`null` or `''` blank), with the row's `total` moved onto it; each typed count is described by the value under it, which is no tab stop. `Stepper` gains `aria-describedby` (ids read before its error). The grid still does no arithmetic or currency formatting. New classes `sw-denomination-value-row` and `sw-denomination-value`; no new tokens, no new dependency. Request: `docs/requests/teisoro-denomination-value-row.md`.
|
|
17
|
+
|
|
3
18
|
## 1.36.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ActionBar,
|
|
11
11
|
ActionMenu,
|
|
12
12
|
BarChart,
|
|
13
|
+
DataBar,
|
|
13
14
|
Box,
|
|
14
15
|
Button,
|
|
15
16
|
CalendarButton,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
RadioGroup,
|
|
19
20
|
SectionNav,
|
|
20
21
|
Spinner,
|
|
22
|
+
Pagination,
|
|
21
23
|
Progress,
|
|
22
24
|
Tooltip,
|
|
23
25
|
InfoTip,
|
|
@@ -113,7 +115,7 @@ A disabled native text control (`<input>`, `<select>` or `<textarea>` on the can
|
|
|
113
115
|
</Field>
|
|
114
116
|
```
|
|
115
117
|
|
|
116
|
-
`Stepper` is a whole-number count changed with − and + or typed. The count is a native text input with `role="spinbutton"` and `inputmode="numeric"`, named by `label` (visible above it, or `labelVisuallyHidden` where table headers say it) and the one tab stop: ArrowUp and ArrowDown step it by `step` (default 1), Home goes to `min` and End to a finite `max` (a range below zero takes `inputmode="text"`, since a phone's numeric pad has no minus key). The − and + buttons are pointer targets outside the tab order, named by `decrementLabel` and `incrementLabel` (your copy), and a press on one leaves focus where it was; the count and both buttons sit in a `group` named by the label. − is disabled at `min` (default 0) and + at `max` (no upper bound when left out). `value` is a count or `null` for an empty box, which the buttons treat as `min` and `placeholder` can fill. Typed text is refused unless it is digits (with a leading minus when `min` is below zero), so `onChange` only receives a whole number or `null`; a typed count is reported as typed even outside the bounds, so say why in `error` (a polite message, `aria-invalid` and the danger border, as `Field`'s), and the buttons then move it back inside them. `changed` takes `Field`'s changed look; `readOnly` keeps the count focusable and hides the buttons in their own room; `disabled` stops all three. `limitAppearance="plain"` (default `"faded"`) keeps − at `min` and + at `max` in their usual look instead of faded, for a count sheet where a faded − reads as broken; they are still disabled, a disabled or read-only Stepper is unchanged, forced colors still grey them, and an unknown value throws a `RangeError`. The count is a few digits wide and keeps that width (`width="fixed"`), or fills its container (`width="full"`, for a table cell). Bounds that are not whole numbers, `min` above `max`, or a `step` that is not above zero throw a `RangeError`.
|
|
118
|
+
`Stepper` is a whole-number count changed with − and + or typed. The count is a native text input with `role="spinbutton"` and `inputmode="numeric"`, named by `label` (visible above it, or `labelVisuallyHidden` where table headers say it) and the one tab stop: ArrowUp and ArrowDown step it by `step` (default 1), Home goes to `min` and End to a finite `max` (a range below zero takes `inputmode="text"`, since a phone's numeric pad has no minus key). The − and + buttons are pointer targets outside the tab order, named by `decrementLabel` and `incrementLabel` (your copy), and a press on one leaves focus where it was; the count and both buttons sit in a `group` named by the label. − is disabled at `min` (default 0) and + at `max` (no upper bound when left out). `value` is a count or `null` for an empty box, which the buttons treat as `min` and `placeholder` can fill. Typed text is refused unless it is digits (with a leading minus when `min` is below zero), so `onChange` only receives a whole number or `null`; a typed count is reported as typed even outside the bounds, so say why in `error` (a polite message, `aria-invalid` and the danger border, as `Field`'s), and the buttons then move it back inside them. `aria-describedby` takes ids of elements that describe the count, such as the value it adds up to, read before an `error`'s message. `changed` takes `Field`'s changed look; `readOnly` keeps the count focusable and hides the buttons in their own room; `disabled` stops all three. `limitAppearance="plain"` (default `"faded"`) keeps − at `min` and + at `max` in their usual look instead of faded, for a count sheet where a faded − reads as broken; they are still disabled, a disabled or read-only Stepper is unchanged, forced colors still grey them, and an unknown value throws a `RangeError`. The count is a few digits wide and keeps that width (`width="fixed"`), or fills its container (`width="full"`, for a table cell). Bounds that are not whole numbers, `min` above `max`, or a `step` that is not above zero throw a `RangeError`.
|
|
117
119
|
|
|
118
120
|
```tsx
|
|
119
121
|
<Stepper
|
|
@@ -418,7 +420,7 @@ An option's optional `description` (a `ReactNode`) is secondary text for that op
|
|
|
418
420
|
|
|
419
421
|
A header `TableCell` (`as="th"`) with `sort` (`'ascending'`, `'descending'` or `'none'`) and `onSort` is its column's sort control: its children become a button in the header's own style with a chevron (before the name in a `numeric` or end-aligned column), and the cell carries `aria-sort` only while it is the sorted column. `sort` on a data cell, or one of the two without the other, throws a `TypeError`. `Table` `layout="fixed"` (default `auto`) sizes the columns from the header row alone, so a filter that hides a row moves no column, and `verticalAlign="top"` (default `middle`) starts every cell of a tall row on its first line. `TableCell` `width` is `min` (an auto table's column takes the least room its content allows, on one line; set it on each cell of the column) or a size, `xs` to `xl` (4, 6, 8, 12 and 16 rem); in a fixed table a column without a width shares what is left, so leave one column, such as a description, unsized. The HTML `width` attribute is not accepted. Unknown values throw a `RangeError`.
|
|
420
422
|
|
|
421
|
-
A ledger read across as well as down takes `Table` `columnRules` (a hairline at the inline start of every cell after a row's first, mirrored right to left) and `TableCell` `tone` (`success`, `danger`, `muted` or `accent`: the cell's text in the theme colour, as `Text color` uses it; never the only signal, so keep the sign or the words). `TableRow` `variant="sub"` (default `"default"`) sets a row under the one above, as a batch's items: its row header, a `TableCell as="th" scope="row"`, is indented a `space-6` step with a guide bar at the indent (a sub row without a row header is not indented). `TableRow` `struck` keeps a voided row on the record: the subtle fill and the text muted and struck through, toned cells included; it works with
|
|
423
|
+
A ledger read across as well as down takes `Table` `columnRules` (a hairline at the inline start of every cell after a row's first, mirrored right to left) and `TableCell` `tone` (`success`, `danger`, `muted` or `accent`: the cell's text in the theme colour, as `Text color` uses it; never the only signal, so keep the sign or the words). `TableRow` `variant="sub"` (default `"default"`) sets a row under the one above, as a batch's items: its row header, a `TableCell as="th" scope="row"`, is indented a `space-6` step with a guide bar at the indent (a sub row without a row header is not indented). `TableRow` `variant="total"` is a total mid-table, such as a subtotal the rows above add up to before the table goes on: its cells at weight 600 under a 2 px rule across its top (the cells' own collapsed top border, so forced colors keep it), as a `TableFooter` total is drawn, with no fill, so accent text in it keeps the contrast it has on the table's own surface. Name it with a row header and keep it in the body, after the rows it adds up (not the body's first row under a pinned header, whose rule would sit on its own); a cell's `tone` keeps its colour, and `struck` works on it. Its cells are all at weight 600, so a quiet link or a `TableCell onPress` action in it is no longer set apart by weight: keep a total row's name plain text (a `TableFooter` row is the same). `TableRow` `struck` keeps a voided row on the record: the subtle fill and the text muted and struck through, toned cells included; it works with any variant. A line-through is not read aloud, so say why in the row, such as a `Badge` "Voided": a Badge in a line of text is not struck, but one that is itself a flex item (a direct child of `Inline`) is, so put it in the title's line. A row header in the body or footer (`th scope="row"`) reads as body text. An unknown `tone` or `variant` throws a `RangeError`.
|
|
422
424
|
|
|
423
425
|
`Table` `stickyHeader` pins the header: the whole `TableHeader` as one group, every row in it (the column headings and any row under them, such as a running total) with all its cells, `th` and `td`, each row under the one above, on the glass with its row and column rules. `true` (default) pins it to the top of the table's own scroll region, `false` lets it scroll away, and `'page'` pins it to the page's top as the page scrolls. With `'page'`, while the table fits its width its region stops being a scroll box (`sw-table-sticky-page`), so the header stays in view under any sticky `AppHeader` (which covers it); a table wider than its region scrolls sideways in it and pins inside it. Use it for a long table whose last row, such as a non-sticky `TableFooter` total, should scroll with the rows. An unknown value throws a `RangeError`.
|
|
424
426
|
|
|
@@ -430,8 +432,44 @@ A ledger read across as well as down takes `Table` `columnRules` (a hairline at
|
|
|
430
432
|
|
|
431
433
|
`TableFooter` is the table's `tfoot`, for a total: its cells are set at weight 600 under a 2 px rule across its first row (drawn on each cell's `::before`, so forced colors keep it), and a `TableCell as="th" scope="row"` in it names the total. `sticky` pins the footer to the bottom edge on the header's glass (solid under Reduce Transparency, the system canvas in forced colors), on its own layer over the cells and the pinned header. While the table fits its width, a table with a sticky footer stops being a scroll box, so the footer pins to the page's bottom and the sticky header to its top as the page scrolls; a sticky `AppHeader` covers that header. A table wider than its region scrolls sideways in it and pins to the region instead. A sticky `ActionBar` covers a pinned footer, and so does a `Dialog`'s pinned footer, so do not pair them.
|
|
432
434
|
|
|
435
|
+
`Table` `maxHeight` (opt-in, `{ rows: number }`, type `TableMaxHeight`) bounds the table's height by a row count, and the rest of the rows scroll inside the table's own region: the region is as tall as that many single-line body rows plus the header row and, when there is one, the footer row (from the type and spacing tokens the cells are drawn with, compact density included, a sorting header as tall as its buttons and the 44 px touch target on a coarse pointer; rows of two lines or with controls, a second header or footer row, and a horizontal scrollbar that takes room show fewer at a time). The header pins to the region's top and a `TableFooter sticky` total to its bottom, so a total over every row stays in view while the rows scroll; a non-sticky footer scrolls with the rows. The region stays a keyboard stop named after the table, and while rows are scrolled out past its top or bottom that edge draws the scroll shade (`sw-scroll-more-top`, `sw-scroll-more-bottom`): cast from the pinned header's last row (a header cell spanning rows from an earlier row casts none) or total over the rows under it, or from the region's own edge where nothing is pinned; none in forced colors. While the region has keyboard focus, the pinned header and total carry the part of its focus ring they cover (their side parts on the first and last cells, so avoid `rowSpan` in a bounded table's header). Printed, every row shows. A bounded table never pins to the page, and without `maxHeight` the page pinning above is unchanged. `stickyHeader` `'page'` or `false` with it, a value that is not `{ rows }`, or a row count that is not a whole number from 1 throw a `RangeError`.
|
|
436
|
+
|
|
437
|
+
```tsx
|
|
438
|
+
<Table aria-label="Closeouts" maxHeight={{ rows: 12 }}>
|
|
439
|
+
<TableHeader>…</TableHeader>
|
|
440
|
+
<TableBody>…</TableBody>
|
|
441
|
+
<TableFooter sticky>…</TableFooter>
|
|
442
|
+
</Table>
|
|
443
|
+
```
|
|
444
|
+
|
|
433
445
|
`BarChart` `formatValue` writes the axis's values and each value without its own `valueLabel`, such as a currency. `diverging` puts zero in the middle of each track behind a hairline: a positive bar grows toward the inline end and a negative one toward the start, on one scale, and the axis reads minus the maximum, zero and the maximum. Without it every bar grows from the start. An item's `tone` (`BarChartTone`: `'accent'`, `'success'`, `'warning'` or `'danger'`, listed in the exported `barChartTones`) colors its bar by what it means in place of its sign's default (the accent, or danger for a negative value), such as a diverging chart's overage in `'warning'` and shortage in `'danger'`; a toned bar keeps its sign's place, every tone keeps 3:1 against the track, and an unknown tone throws a `RangeError`. Forced colors draw every bar in the system text color, so the value and its side of zero carry the meaning there.
|
|
434
446
|
|
|
447
|
+
`DataBar` is a horizontal range bar for a table cell or a list row: a bar from `from` to `to` (whichever is larger is its far end) on a track whose domain runs from `min` to `max`, such as where a statement's line leaves the running total. It fills its container's width, a spacing step 4 tall with no track fill, and its ends follow the writing direction. It is decorative (`aria-hidden`): the figure is the cell's own text, so keep the value beside it, and a cell holding both is named by the figure alone. `tone` (`DataBarTone`, listed in `dataBarTones`; default `'neutral'`) says what the bar is: `'neutral'` for where it started, `'success'` for what came in, `'muted'` for what went out (there is no danger tone: an outflow is not an error), `'strong'` for a subtotal and `'accent'` for what was counted or recorded. Each is a semantic colour mixed into the surface, 1.5:1 or more on it, the three greys 1.5:1 or more apart, in every palette and scheme. A domain from below zero to above it (`min < 0 < max`) draws a hairline at zero, so a column of differences diverges around it (`from={0} to={value}`), and the bar's end at zero is square. Values past the domain are clamped to it; non-finite numbers, a `min` not under `max`, or an unknown tone throw a `RangeError`. Forced colors draw the bar and the zero line in the system text color.
|
|
448
|
+
|
|
449
|
+
A bar in its own column reads as empty cells to assistive technology, which is fine while the figure's cell carries the value; a bar and its figure can also share one cell, side by side in a `Grid`.
|
|
450
|
+
|
|
451
|
+
```tsx
|
|
452
|
+
<TableCell numeric>
|
|
453
|
+
<Grid align="center" columns={2} gap={2}>
|
|
454
|
+
<DataBar from={0} to={-6} min={-10} max={10} tone="muted" />
|
|
455
|
+
<span>−6</span>
|
|
456
|
+
</Grid>
|
|
457
|
+
</TableCell>
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
`Pagination` steps through a list shown a page at a time, for a list with no total to keep in view (a list that adds up scrolls inside itself instead, with `Table` `maxHeight`). It is a `nav` landmark named by `aria-label` or `aria-labelledby` (one is required), holding the consumer's words for what the page shows (`rangeLabel`, such as "1–25 of 130 changes", in the muted caption at the inline start and announced politely when it changes) and the previous and next steps at the end: icon-only neutral `sm` Buttons, square, the 44 px touch target on a coarse pointer, named by `labels` (`PaginationLabels`: `previous`, `next`) with a private chevron glyph mirrored right to left. `page` (from 1) and `pageCount` place it; a step calls `onPageChange` with the page it goes to. At either end its step looks disabled (`aria-disabled`, the neutral grey) but stays a Tab stop, so focus is never dropped when the last page is reached, and a press there does nothing. Pages that are not whole numbers in range, or an empty step label (`labels.previous` or `labels.next`), throw a `RangeError`. The row wraps on a narrow column, the steps staying at the end.
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
<Pagination
|
|
464
|
+
aria-label="Change pages"
|
|
465
|
+
page={page}
|
|
466
|
+
pageCount={6}
|
|
467
|
+
onPageChange={setPage}
|
|
468
|
+
rangeLabel="1–25 of 130 changes"
|
|
469
|
+
labels={{ previous: 'Previous page', next: 'Next page' }}
|
|
470
|
+
/>
|
|
471
|
+
```
|
|
472
|
+
|
|
435
473
|
`Spinner` shows indeterminate loading in small, medium, or large sizes. Supply localized `label` for the one announced status in a loading region. Use `decorative` on additional indicators beside that status so screen readers do not hear the same message repeatedly. Reduced motion leaves a static accented ring.
|
|
436
474
|
|
|
437
475
|
`GlyphTile` is a small rounded square in a categorical colour with the consumer's glyph in white: the mark of a kind beside its name, such as a service in a list. `hue` is one of the `@scalewing/tokens` categorical colours (`green`, `blue`, `orange`, `purple`, `teal`, `rose`, or `neutral`); which kind takes which hue is yours. `size` is `sm` (24), `md` (28, the default) or `lg` (32); the glyph is drawn at spacing step 4 in white, which keeps 3:1 on every fill; pass the SVG (a Lucide component) as the tile's direct child, since only a direct-child SVG is sized. It is always `aria-hidden`, so put the kind's name in visible text beside it. An unknown `hue` or `size` throws a `RangeError`.
|
|
@@ -564,7 +602,7 @@ Values outside the catalog throw a `RangeError`. There is no per-breakpoint span
|
|
|
564
602
|
</Grid>
|
|
565
603
|
```
|
|
566
604
|
|
|
567
|
-
`DenominationGrid` shows integer counts per unit across a fixed set of columns. The `strip` layout is a captioned table: each row has a toned label with an icon slot, muted zero cells, optional signed deltas toned by sign, and an optional consumer-formatted `total` that shows under the label on a phone. Pass `totalLabel` (for example "Total") to name the total column: it renders a `th scope="col"` shown over the totals from `md` up and visually hidden below it, and without it the corner stays an empty cell as before (either way the column takes no width on a phone). `labelWidth` (`xs` to `xl`, the `Table` column sizes) lines a strip's columns up with every other strip of the same columns in a container of the same width, such as the cards of a feed: the row labels take that width and the count columns share the rest of the region equally, so no content moves a column. `labelAppearance="plain"` (default `"tone"`) sets every row label in the text color at label weight with no tone stripe, in both layouts, for a grid whose rows need no color to tell apart; a row's `tone` still colors its total, and an unknown value throws. Three more grid-level options match a framed count sheet, each off by default: `frame="table"` (default `"none"`) draws a strip as a framed table, its scroll region a surface inside a border hairline at the `sm` radius, the heading row on the subtle fill, a rule between columns, the counts at label size centred under their heads and the cells padded a space-3 step across (the tiles layout has no frame and ignores it); `totalEmphasis="strong"` (default `"default"`) sets the row totals in bold label type, a neutral row's in the text color and a toned row's in its tone, under the label on a phone too; and `cellToneAppearance="pill"` (default `"text"`) sets a `cellTones` count of a strip's read-only row on a rounded tint of its tone in the tone's ink (the `Notice` fill and words, 4.5:1 on the tint except where a palette's own `danger` is already under 4.5:1, harvest and mocha dark), outlined in forced colors; entry counts and tiles keep their tone border. With `zeroLabel=""` a toned zero or empty count shows nothing in either appearance, so tone only counts that are there. An unknown value of any of them throws a `RangeError`. `zeroLabel` (default `"—"`) is what a zero or empty read-only count shows; an empty string leaves those counts blank, so only the counts that are there stand out (it suits the strip, where the column header names each blank cell, better than tiles, where a blank tile is only its column's name), and a `zeroLabel` that is not a string throws. On a phone the total cell stays in the table, visually hidden, so a screen reader still reads each total in its row; the copy under the label is `aria-hidden`. A strip wider than its container scrolls sideways inside its own keyboard-focusable region, named after `label`, with the row labels pinned at the start and the same edge shade as `Table` while counts are scrolled out of view (the start shade is cast from the pinned labels' edge, since they cover the region's own); the page never scrolls sideways. The `tiles` layout stacks the column label, the count, and an optional `subtotal` string per column. Each tiles row shows its label line (icon, label and `total`) when the grid has several rows, or when a lone row has an icon or a `total`; a lone plain row is named by the grid's `label` alone. Every row is a region named by its `label`, except a lone plain row whose `label` is the grid's own: it has no name of its own, so assistive technology hears the grid's group once rather than a region repeating it. `rowRole="group"` (default `"region"`) keeps every named row's name but makes it a `group` instead of a landmark region, for a page with many grids (one per order card, say) whose rows would otherwise fill the landmark list; the strip ignores it, since its rows are table rows, and an unknown `rowRole` throws a `RangeError` in either layout. A row's icon and its label words stay on one line in both layouts (`sw-denomination-label-line`): a long label wraps its words beside the icon, never under it, and on a phone the strip's total goes on its own line under them. A row's `cellTones` (one Badge tone or `null` per column) tones a single count in place: the count is set in the tone over its signed or zero look, and in the tiles layout its tile's border takes the tone too, so a short bill turns red without leaving its row; `neutral` or `null` leaves a count as it is, a row's `tone` still colors only its label, and a `cellTones` that is not one known tone or `null` per column throws. The tone never says why on its own; put that in words beside the grid. Every negative count, signed or not and in either layout, is written with the typographic minus ("−1"), never a hyphen. The primitive does no arithmetic and no currency formatting; tones reuse the Badge vocabulary. Invalid columns, rows, or cells throw.
|
|
605
|
+
`DenominationGrid` shows integer counts per unit across a fixed set of columns. The `strip` layout is a captioned table: each row has a toned label with an icon slot, muted zero cells, optional signed deltas toned by sign, and an optional consumer-formatted `total` that shows under the label on a phone. Pass `totalLabel` (for example "Total") to name the total column: it renders a `th scope="col"` shown over the totals from `md` up and visually hidden below it, and without it the corner stays an empty cell as before (either way the column takes no width on a phone). `labelWidth` (`xs` to `xl`, the `Table` column sizes) lines a strip's columns up with every other strip of the same columns in a container of the same width, such as the cards of a feed: the row labels take that width and the count columns share the rest of the region equally, so no content moves a column. `labelAppearance="plain"` (default `"tone"`) sets every row label in the text color at label weight with no tone stripe, in both layouts, for a grid whose rows need no color to tell apart; a row's `tone` still colors its total, and an unknown value throws. Three more grid-level options match a framed count sheet, each off by default: `frame="table"` (default `"none"`) draws a strip as a framed table, its scroll region a surface inside a border hairline at the `sm` radius, the heading row on the subtle fill, a rule between columns, the counts at label size centred under their heads and the cells padded a space-3 step across (the tiles layout has no frame and ignores it); `totalEmphasis="strong"` (default `"default"`) sets the row totals in bold label type, a neutral row's in the text color and a toned row's in its tone, under the label on a phone too; and `cellToneAppearance="pill"` (default `"text"`) sets a `cellTones` count of a strip's read-only row on a rounded tint of its tone in the tone's ink (the `Notice` fill and words, 4.5:1 on the tint except where a palette's own `danger` is already under 4.5:1, harvest and mocha dark), outlined in forced colors; entry counts and tiles keep their tone border. A strip row's `valueRow` (`{ label, cells }`, opt-in) adds a line right under it that gives each column's value, such as the money its count adds up to: its own table row on the subtle fill, `label` (such as "Value") in the label column (named with the row's label, "Counted Value", for table navigation), each of `cells` (one consumer-formatted string or `null` per column; `null` or `''` leaves it blank) centred under its count at label size in tabular figures, and the row's `total` moved onto it (bold with `totalEmphasis="strong"`, under the line's name on a phone); the counts' own total cell stays empty. It keeps the row's tone and `disabled` (a disabled line fades its values). Each entry count with a value is described by it (`aria-describedby`, before an error), and the value is no tab stop. The grid still does no arithmetic. A `valueRow` in the tiles layout, a blank label, or cells that are not one string or `null` per column throw a `RangeError`. With `zeroLabel=""` a toned zero or empty count shows nothing in either appearance, so tone only counts that are there. An unknown value of any of them throws a `RangeError`. `zeroLabel` (default `"—"`) is what a zero or empty read-only count shows; an empty string leaves those counts blank, so only the counts that are there stand out (it suits the strip, where the column header names each blank cell, better than tiles, where a blank tile is only its column's name), and a `zeroLabel` that is not a string throws. On a phone the total cell stays in the table, visually hidden, so a screen reader still reads each total in its row; the copy under the label is `aria-hidden`. A strip wider than its container scrolls sideways inside its own keyboard-focusable region, named after `label`, with the row labels pinned at the start and the same edge shade as `Table` while counts are scrolled out of view (the start shade is cast from the pinned labels' edge, since they cover the region's own); the page never scrolls sideways. The `tiles` layout stacks the column label, the count, and an optional `subtotal` string per column. Each tiles row shows its label line (icon, label and `total`) when the grid has several rows, or when a lone row has an icon or a `total`; a lone plain row is named by the grid's `label` alone. Every row is a region named by its `label`, except a lone plain row whose `label` is the grid's own: it has no name of its own, so assistive technology hears the grid's group once rather than a region repeating it. `rowRole="group"` (default `"region"`) keeps every named row's name but makes it a `group` instead of a landmark region, for a page with many grids (one per order card, say) whose rows would otherwise fill the landmark list; the strip ignores it, since its rows are table rows, and an unknown `rowRole` throws a `RangeError` in either layout. A row's icon and its label words stay on one line in both layouts (`sw-denomination-label-line`): a long label wraps its words beside the icon, never under it, and on a phone the strip's total goes on its own line under them. A row's `cellTones` (one Badge tone or `null` per column) tones a single count in place: the count is set in the tone over its signed or zero look, and in the tiles layout its tile's border takes the tone too, so a short bill turns red without leaving its row; `neutral` or `null` leaves a count as it is, a row's `tone` still colors only its label, and a `cellTones` that is not one known tone or `null` per column throws. The tone never says why on its own; put that in words beside the grid. Every negative count, signed or not and in either layout, is written with the typographic minus ("−1"), never a hyphen. The primitive does no arithmetic and no currency formatting; tones reuse the Badge vocabulary. Invalid columns, rows, or cells throw.
|
|
568
606
|
|
|
569
607
|
A strip row with `entry` makes its counts editable: each column holds a `Stepper` (`width="full"`, its label hidden and named by the row label and the column's label and caption as its header reads, such as "Received $20" or "Counted $1 × 100") whose count is the row's `cells` entry (`null` is an empty box). `entry.onChange(columnKey, value)` reports a change; `entry.decrementLabel` and `entry.incrementLabel` name the buttons; `entry.max` caps each column (`null` for none), `entry.errors` puts a message under a column's count (`null` for none), and `entry.placeholder` fills an empty box. `entry.limitAppearance` is the Steppers' `limitAppearance`: `"plain"` keeps − at 0 (and + at a cap) unfaded. The minimum is 0. The grid still does no arithmetic, so recompute the row's `total` in `onChange`. A strip with an entry row centres its heads and read-only counts over the steppers, and each count keeps spacing step 8 of room, so a narrow strip scrolls in its region instead of crushing it. A `cellTones` tone on an entry count draws its border in the tone (danger for a difference); an `accent` tone, for a suggestion or a change, is the `Stepper`'s `changed` look (border and tint); a message in `entry.errors` wins. A row `caption` is a muted line under its label ("from the customer"), and a column `caption` a muted note after its label ("× 100"). Captions show in both layouts. In the strip, `emphasis="quiet"` sets a row on the subtle fill, for a row to compare against, and `disabled` fades a row that does not apply, disables its entry and marks it `aria-disabled`. Entry rows, quiet rows and disabled rows need the `strip` layout. An entry row's counts are zero or more and it is not `signed`; its label is its own among the entry rows, as each column's label and caption are, so every count has its own name. Breaking any of these, a cap or message list that is not one per column, a cap that is not a whole count of zero or more, blank button names or captions, an unknown `emphasis`, or a `disabled` that is not a boolean throws a `RangeError`.
|
|
570
608
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component's accessible name, given one way: `aria-label` with the words,
|
|
3
|
+
* or `aria-labelledby` with the id of an element that holds them, never both.
|
|
4
|
+
* Shared by the components whose name is required (a group, a list of tabs,
|
|
5
|
+
* a navigation landmark).
|
|
6
|
+
*/
|
|
7
|
+
export type AccessibleName = {
|
|
8
|
+
'aria-label': string;
|
|
9
|
+
'aria-labelledby'?: never;
|
|
10
|
+
} | {
|
|
11
|
+
'aria-label'?: never;
|
|
12
|
+
'aria-labelledby': string;
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
import { type DataBarTone, dataBarTones } from '../css/css-data-bar.js';
|
|
3
|
+
export type { DataBarTone };
|
|
4
|
+
export { dataBarTones };
|
|
5
|
+
export type DataBarProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'aria-hidden'> & {
|
|
6
|
+
/** One end of the range, in the domain's units. */
|
|
7
|
+
from: number;
|
|
8
|
+
/** The other end; the bar runs between the two whichever is larger. */
|
|
9
|
+
to: number;
|
|
10
|
+
/** The domain's least value, at the track's inline start. */
|
|
11
|
+
min: number;
|
|
12
|
+
/** The domain's greatest value, at the track's inline end. */
|
|
13
|
+
max: number;
|
|
14
|
+
/**
|
|
15
|
+
* What the bar means (default `neutral`): `success` for money in,
|
|
16
|
+
* `muted` for money out (an outflow is not an error, so there is no
|
|
17
|
+
* danger tone), `strong` for a subtotal and `accent` for a counted or
|
|
18
|
+
* recorded figure.
|
|
19
|
+
*/
|
|
20
|
+
tone?: DataBarTone;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* A horizontal range bar for a table cell or a list row: a bar from `from`
|
|
24
|
+
* to `to` on a track whose domain runs from `min` to `max`, such as where a
|
|
25
|
+
* statement's line leaves the running total, or a day's difference on a
|
|
26
|
+
* domain from below zero to above it, which draws a zero line. It is
|
|
27
|
+
* decorative (`aria-hidden`): the figure is the cell's own text, so keep
|
|
28
|
+
* the value beside it. Values past the domain are clamped to it;
|
|
29
|
+
* non-finite numbers, a `min` not under `max` or an unknown tone throw a
|
|
30
|
+
* `RangeError`.
|
|
31
|
+
*/
|
|
32
|
+
export declare const DataBar: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLSpanElement>, "children" | "aria-hidden"> & {
|
|
33
|
+
/** One end of the range, in the domain's units. */
|
|
34
|
+
from: number;
|
|
35
|
+
/** The other end; the bar runs between the two whichever is larger. */
|
|
36
|
+
to: number;
|
|
37
|
+
/** The domain's least value, at the track's inline start. */
|
|
38
|
+
min: number;
|
|
39
|
+
/** The domain's greatest value, at the track's inline end. */
|
|
40
|
+
max: number;
|
|
41
|
+
/**
|
|
42
|
+
* What the bar means (default `neutral`): `success` for money in,
|
|
43
|
+
* `muted` for money out (an outflow is not an error, so there is no
|
|
44
|
+
* danger tone), `strong` for a subtotal and `accent` for a counted or
|
|
45
|
+
* recorded figure.
|
|
46
|
+
*/
|
|
47
|
+
tone?: DataBarTone;
|
|
48
|
+
} & import("react").RefAttributes<HTMLSpanElement>>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cx } from '../class-names.js';
|
|
4
|
+
import { dataBarTones } from '../css/css-data-bar.js';
|
|
5
|
+
import { dataBarGeometry } from '../data-bar-geometry.js';
|
|
6
|
+
export { dataBarTones };
|
|
7
|
+
/**
|
|
8
|
+
* A horizontal range bar for a table cell or a list row: a bar from `from`
|
|
9
|
+
* to `to` on a track whose domain runs from `min` to `max`, such as where a
|
|
10
|
+
* statement's line leaves the running total, or a day's difference on a
|
|
11
|
+
* domain from below zero to above it, which draws a zero line. It is
|
|
12
|
+
* decorative (`aria-hidden`): the figure is the cell's own text, so keep
|
|
13
|
+
* the value beside it. Values past the domain are clamped to it;
|
|
14
|
+
* non-finite numbers, a `min` not under `max` or an unknown tone throw a
|
|
15
|
+
* `RangeError`.
|
|
16
|
+
*/
|
|
17
|
+
export const DataBar = forwardRef(function DataBar({ className, from, max, min, style, to, tone = 'neutral', ...rest }, ref) {
|
|
18
|
+
if (!dataBarTones.includes(tone))
|
|
19
|
+
throw new RangeError(`DataBar tone must be one of ${dataBarTones.join(', ')}; received ${String(tone)}`);
|
|
20
|
+
const { start, size, zero, zeroEnd } = dataBarGeometry(from, to, min, max);
|
|
21
|
+
return (_jsx("span", { ref: ref, className: cx('sw-data-bar', `sw-data-bar-${tone}`, zero !== null && 'sw-data-bar-diverging', zeroEnd !== null && `sw-data-bar-zero-${zeroEnd}`, className), style: {
|
|
22
|
+
...style,
|
|
23
|
+
...(zero === null ? {} : { '--sw-data-bar-zero': zero }),
|
|
24
|
+
}, ...rest, "aria-hidden": "true", children: _jsx("span", { className: "sw-data-bar-fill", style: {
|
|
25
|
+
'--sw-data-bar-start': start,
|
|
26
|
+
'--sw-data-bar-size': size,
|
|
27
|
+
} }) }));
|
|
28
|
+
});
|
|
@@ -2,7 +2,7 @@ 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, DenominationLabelWidth, DenominationTotalEmphasis, } 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';
|
|
6
6
|
export type { DenominationLabelAppearance } from '../css/css-denomination-label.js';
|
|
7
7
|
export { denominationCellToneAppearances, denominationGridFrames, denominationLabelAppearances, denominationTotalEmphases, };
|
|
8
8
|
export declare function DenominationGrid({ label, columns, rows, layout, subtotal, zeroLabel, totalLabel, rowRole, labelWidth, labelAppearance, frame, totalEmphasis, cellToneAppearance, }: DenominationGridProps): import("react").JSX.Element;
|
|
@@ -7,6 +7,7 @@ import { denominationLabelAppearances, denominationLabelsPlainClass, } from '../
|
|
|
7
7
|
import { DenominationStrip } from './denomination-grid/DenominationStrip.js';
|
|
8
8
|
import { DenominationTiles } from './denomination-grid/DenominationTiles.js';
|
|
9
9
|
import { assertDenominationGrid } from './denomination-grid/validate.js';
|
|
10
|
+
import { assertDenominationValueRows } from './denomination-grid/validate-value-row.js';
|
|
10
11
|
import { assertDenominationEntries, assertDenominationExtras, } from './denomination-grid/validate-entry.js';
|
|
11
12
|
export { denominationCellToneAppearances, denominationGridFrames, denominationLabelAppearances, denominationTotalEmphases, };
|
|
12
13
|
/** Fails closed on a value outside a closed set, naming the prop. */
|
|
@@ -18,6 +19,7 @@ export function DenominationGrid({ label, columns, rows, layout = 'strip', subto
|
|
|
18
19
|
assertDenominationGrid(label, columns, rows);
|
|
19
20
|
assertDenominationExtras(layout, columns, rows);
|
|
20
21
|
assertDenominationEntries(layout, columns, rows);
|
|
22
|
+
assertDenominationValueRows(layout, columns, rows);
|
|
21
23
|
if (typeof zeroLabel !== 'string')
|
|
22
24
|
throw new RangeError('zeroLabel must be a string');
|
|
23
25
|
if (totalLabel !== undefined && !totalLabel.trim())
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
import { type AccessibleName } from '../accessible-name.js';
|
|
3
|
+
/** The steps' accessible names, in the product's words. */
|
|
4
|
+
export type PaginationLabels = {
|
|
5
|
+
/** Names the step to the page before, such as "Previous page". */
|
|
6
|
+
previous: string;
|
|
7
|
+
/** Names the step to the page after, such as "Next page". */
|
|
8
|
+
next: string;
|
|
9
|
+
};
|
|
10
|
+
export type PaginationProps = Omit<HTMLAttributes<HTMLElement>, 'children' | 'aria-label' | 'aria-labelledby'> & AccessibleName & {
|
|
11
|
+
/** The page shown, from 1. */
|
|
12
|
+
page: number;
|
|
13
|
+
/** How many pages there are, from 1. */
|
|
14
|
+
pageCount: number;
|
|
15
|
+
/** Called with the page a step goes to; never past either end. */
|
|
16
|
+
onPageChange: (page: number) => void;
|
|
17
|
+
/**
|
|
18
|
+
* What the page shows, in the product's words, such as "1–25 of 130
|
|
19
|
+
* changes". It is announced politely when it changes.
|
|
20
|
+
*/
|
|
21
|
+
rangeLabel: string;
|
|
22
|
+
labels: PaginationLabels;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Previous and next steps through a list shown a page at a time, beside
|
|
26
|
+
* the consumer's words for what the page shows, in a navigation landmark
|
|
27
|
+
* named by `aria-label` or `aria-labelledby`. Each step is an icon-only
|
|
28
|
+
* neutral Button named by `labels`. At either end its step looks disabled
|
|
29
|
+
* (`aria-disabled`) but stays a Tab stop, so focus is never dropped when
|
|
30
|
+
* the last page is reached, and a press there does nothing. Invalid pages
|
|
31
|
+
* or an empty step label (`labels.previous` or `labels.next`) throw a
|
|
32
|
+
* `RangeError`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const Pagination: import("react").ForwardRefExoticComponent<PaginationProps & import("react").RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import { cx } from '../class-names.js';
|
|
4
|
+
import { assertPaginationLabels, assertPaginationPages, paginationStep, } from '../pagination-pages.js';
|
|
5
|
+
import { Button } from './Button.js';
|
|
6
|
+
/**
|
|
7
|
+
* Previous and next steps through a list shown a page at a time, beside
|
|
8
|
+
* the consumer's words for what the page shows, in a navigation landmark
|
|
9
|
+
* named by `aria-label` or `aria-labelledby`. Each step is an icon-only
|
|
10
|
+
* neutral Button named by `labels`. At either end its step looks disabled
|
|
11
|
+
* (`aria-disabled`) but stays a Tab stop, so focus is never dropped when
|
|
12
|
+
* the last page is reached, and a press there does nothing. Invalid pages
|
|
13
|
+
* or an empty step label (`labels.previous` or `labels.next`) throw a
|
|
14
|
+
* `RangeError`.
|
|
15
|
+
*/
|
|
16
|
+
export const Pagination = forwardRef(function Pagination({ className, labels, onPageChange, page, pageCount, rangeLabel, ...rest }, ref) {
|
|
17
|
+
assertPaginationPages(page, pageCount);
|
|
18
|
+
assertPaginationLabels(labels);
|
|
19
|
+
const step = (direction) => {
|
|
20
|
+
const target = paginationStep(page, pageCount, direction);
|
|
21
|
+
return (_jsx(Button, { "aria-disabled": target === null || undefined, "aria-label": labels[direction], className: "sw-pagination-step", disabledAppearance: "neutral", onPress: () => {
|
|
22
|
+
if (target !== null)
|
|
23
|
+
onPageChange(target);
|
|
24
|
+
}, size: "sm", variant: "neutral", children: _jsx("span", { "aria-hidden": "true", className: `sw-pagination-glyph sw-pagination-glyph-${direction}` }) }));
|
|
25
|
+
};
|
|
26
|
+
return (_jsxs("nav", { ref: ref, className: cx('sw-pagination', className), ...rest, children: [_jsx("span", { "aria-atomic": "true", "aria-live": "polite", className: "sw-pagination-range", children: rangeLabel }), _jsxs("span", { className: "sw-pagination-steps", children: [step('previous'), step('next')] })] }));
|
|
27
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { type CSSProperties, type ReactNode } from 'react';
|
|
2
2
|
type ScrollRegionProps = {
|
|
3
3
|
children: ReactNode;
|
|
4
4
|
className: string;
|
|
@@ -6,6 +6,8 @@ type ScrollRegionProps = {
|
|
|
6
6
|
'aria-labelledby'?: string;
|
|
7
7
|
/** Adds `sw-scroll-fits` once measured with content that fits its width. */
|
|
8
8
|
markFits?: boolean;
|
|
9
|
+
/** Generated custom properties only, such as a bounded table's row count. */
|
|
10
|
+
style?: CSSProperties;
|
|
9
11
|
};
|
|
10
12
|
/**
|
|
11
13
|
* Private wrapper that scrolls wide content inside its own box (see
|
|
@@ -14,9 +16,11 @@ type ScrollRegionProps = {
|
|
|
14
16
|
* keyboard and is announced as one group. While content is scrolled out past
|
|
15
17
|
* an inline edge, that edge draws a shade (`sw-scroll-more-start`,
|
|
16
18
|
* `sw-scroll-more-end`), so a phone, whose scrollbars hide, still shows that
|
|
17
|
-
* the table goes on.
|
|
18
|
-
* its
|
|
19
|
-
*
|
|
19
|
+
* the table goes on. A region of bounded height that scrolls its rows marks
|
|
20
|
+
* its top and bottom the same way (`sw-scroll-more-top`,
|
|
21
|
+
* `sw-scroll-more-bottom`). With `markFits`, a measured region whose content
|
|
22
|
+
* fits its width carries `sw-scroll-fits`, so a table with a sticky footer
|
|
23
|
+
* can stop being a scroll box and pin its header and footer to the page.
|
|
20
24
|
*/
|
|
21
|
-
export declare function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits, }: ScrollRegionProps): import("react").JSX.Element;
|
|
25
|
+
export declare function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits, style, }: ScrollRegionProps): import("react").JSX.Element;
|
|
22
26
|
export {};
|
|
@@ -10,16 +10,18 @@ import { useScrollOverflow } from './use-scroll-overflow.js';
|
|
|
10
10
|
* keyboard and is announced as one group. While content is scrolled out past
|
|
11
11
|
* an inline edge, that edge draws a shade (`sw-scroll-more-start`,
|
|
12
12
|
* `sw-scroll-more-end`), so a phone, whose scrollbars hide, still shows that
|
|
13
|
-
* the table goes on.
|
|
14
|
-
* its
|
|
15
|
-
*
|
|
13
|
+
* the table goes on. A region of bounded height that scrolls its rows marks
|
|
14
|
+
* its top and bottom the same way (`sw-scroll-more-top`,
|
|
15
|
+
* `sw-scroll-more-bottom`). With `markFits`, a measured region whose content
|
|
16
|
+
* fits its width carries `sw-scroll-fits`, so a table with a sticky footer
|
|
17
|
+
* can stop being a scroll box and pin its header and footer to the page.
|
|
16
18
|
*/
|
|
17
|
-
export function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits = false, }) {
|
|
19
|
+
export function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, markFits = false, style, }) {
|
|
18
20
|
const ref = useRef(null);
|
|
19
21
|
const overflow = useScrollOverflow(ref);
|
|
20
|
-
return (_jsx("div", { ref: ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className: cx(className, overflow.start && 'sw-scroll-more-start', overflow.end && 'sw-scroll-more-end', markFits &&
|
|
22
|
+
return (_jsx("div", { ref: ref, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className: cx(className, overflow.start && 'sw-scroll-more-start', overflow.end && 'sw-scroll-more-end', overflow.top && 'sw-scroll-more-top', overflow.bottom && 'sw-scroll-more-bottom', markFits &&
|
|
21
23
|
overflow.measured &&
|
|
22
24
|
!overflow.start &&
|
|
23
25
|
!overflow.end &&
|
|
24
|
-
'sw-scroll-fits'), role: "group", tabIndex: 0, children: children }));
|
|
26
|
+
'sw-scroll-fits'), role: "group", style: style, tabIndex: 0, children: children }));
|
|
25
27
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
+
import { type AccessibleName } from '../accessible-name.js';
|
|
2
3
|
import { type Breakpoint } from '../css/breakpoints.js';
|
|
3
4
|
import { type SectionNavAppearance } from '../css/css-section-nav-filled.js';
|
|
4
5
|
export type { SectionNavAppearance };
|
|
@@ -29,14 +30,7 @@ export type SectionNavItem = {
|
|
|
29
30
|
*/
|
|
30
31
|
countLabel?: string;
|
|
31
32
|
};
|
|
32
|
-
type
|
|
33
|
-
'aria-label': string;
|
|
34
|
-
'aria-labelledby'?: never;
|
|
35
|
-
} | {
|
|
36
|
-
'aria-label'?: never;
|
|
37
|
-
'aria-labelledby': string;
|
|
38
|
-
};
|
|
39
|
-
export type SectionNavProps = SectionNavLabel & {
|
|
33
|
+
export type SectionNavProps = AccessibleName & {
|
|
40
34
|
items: readonly SectionNavItem[];
|
|
41
35
|
/**
|
|
42
36
|
* Called for a plain press on an item (the main button, no modifier key),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
+
import { type AccessibleName } from '../accessible-name.js';
|
|
2
3
|
export type SegmentedItem = {
|
|
3
4
|
id: string;
|
|
4
5
|
label: ReactNode;
|
|
@@ -11,13 +12,6 @@ export type SegmentedItem = {
|
|
|
11
12
|
*/
|
|
12
13
|
icon?: ReactNode;
|
|
13
14
|
};
|
|
14
|
-
type SegmentedLabel = {
|
|
15
|
-
'aria-label': string;
|
|
16
|
-
'aria-labelledby'?: never;
|
|
17
|
-
} | {
|
|
18
|
-
'aria-label'?: never;
|
|
19
|
-
'aria-labelledby': string;
|
|
20
|
-
};
|
|
21
15
|
/**
|
|
22
16
|
* `compact` is the quiet chip track for a section switch; `filled` gives every
|
|
23
17
|
* segment the same width and paints the selected one in the accent, for a
|
|
@@ -40,7 +34,7 @@ type SegmentedChange = {
|
|
|
40
34
|
disabled: true;
|
|
41
35
|
onChange?: (id: string) => void;
|
|
42
36
|
};
|
|
43
|
-
export type SegmentedControlProps =
|
|
37
|
+
export type SegmentedControlProps = AccessibleName & SegmentedChange & {
|
|
44
38
|
items: readonly SegmentedItem[];
|
|
45
39
|
value: string;
|
|
46
40
|
variant?: SegmentedControlVariant;
|
|
@@ -38,6 +38,11 @@ export type StepperProps = {
|
|
|
38
38
|
readOnly?: boolean;
|
|
39
39
|
/** Says the count in words for assistive technology (`aria-valuetext`), such as "12 straps". */
|
|
40
40
|
valueText?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Ids of elements that describe the count, such as the value it adds up
|
|
43
|
+
* to; read before an `error`'s message.
|
|
44
|
+
*/
|
|
45
|
+
'aria-describedby'?: string;
|
|
41
46
|
/** Shown in an empty box, such as "0". */
|
|
42
47
|
placeholder?: string;
|
|
43
48
|
name?: string;
|
|
@@ -15,7 +15,7 @@ function keepFocus(event) {
|
|
|
15
15
|
* tab stop (the count, a spin button that ArrowUp and ArrowDown step), with
|
|
16
16
|
* the buttons as pointer targets beside it. − stops at `min`, + at `max`.
|
|
17
17
|
*/
|
|
18
|
-
export const Stepper = forwardRef(function Stepper({ label, labelVisuallyHidden = false, value, onChange, min = 0, max = Number.POSITIVE_INFINITY, step = 1, decrementLabel, incrementLabel, error, changed = false, disabled = false, readOnly = false, valueText, placeholder, name, width = 'fixed', limitAppearance = 'faded', }, ref) {
|
|
18
|
+
export const Stepper = forwardRef(function Stepper({ label, labelVisuallyHidden = false, value, onChange, min = 0, max = Number.POSITIVE_INFINITY, step = 1, decrementLabel, incrementLabel, error, changed = false, disabled = false, readOnly = false, valueText, 'aria-describedby': describedBy, placeholder, name, width = 'fixed', limitAppearance = 'faded', }, ref) {
|
|
19
19
|
const bounds = { min, max, step };
|
|
20
20
|
assertStepperBounds(bounds);
|
|
21
21
|
if (!stepperLimitAppearances.includes(limitAppearance))
|
|
@@ -76,7 +76,9 @@ export const Stepper = forwardRef(function Stepper({ label, labelVisuallyHidden
|
|
|
76
76
|
return (_jsxs("div", { className: cx('sw-stepper', width === 'full' && 'sw-stepper-full', invalid && 'sw-stepper-invalid', changed && !invalid && 'sw-stepper-changed', readOnly && 'sw-stepper-readonly', limitAppearance === 'plain' &&
|
|
77
77
|
!disabled &&
|
|
78
78
|
!readOnly &&
|
|
79
|
-
'sw-stepper-limit-plain'), children: [_jsx("label", { className: labelVisuallyHidden ? 'sw-sr-only' : undefined, htmlFor: inputId, id: labelId, children: _jsx(FieldLabelText, { label: label }) }), _jsxs("div", { "aria-labelledby": labelId, className: "sw-stepper-track", role: "group", children: [_jsx("button", { "aria-controls": inputId, "aria-label": decrementLabel, className: "sw-stepper-button", disabled: moves.down === null, onClick: () => move(moves.down), onMouseDown: keepFocus, tabIndex: -1, type: "button", children: _jsx("span", { "aria-hidden": "true", children: '−' }) }), _jsx("input", { ref: ref, "aria-describedby":
|
|
79
|
+
'sw-stepper-limit-plain'), children: [_jsx("label", { className: labelVisuallyHidden ? 'sw-sr-only' : undefined, htmlFor: inputId, id: labelId, children: _jsx(FieldLabelText, { label: label }) }), _jsxs("div", { "aria-labelledby": labelId, className: "sw-stepper-track", role: "group", children: [_jsx("button", { "aria-controls": inputId, "aria-label": decrementLabel, className: "sw-stepper-button", disabled: moves.down === null, onClick: () => move(moves.down), onMouseDown: keepFocus, tabIndex: -1, type: "button", children: _jsx("span", { "aria-hidden": "true", children: '−' }) }), _jsx("input", { ref: ref, "aria-describedby": [describedBy?.trim() || null, invalid ? errorId : null]
|
|
80
|
+
.filter((id) => id !== null)
|
|
81
|
+
.join(' ') || undefined, "aria-invalid": invalid || undefined, "aria-valuemax": Number.isFinite(max) ? max : undefined, "aria-valuemin": min, "aria-valuenow": value ?? undefined, "aria-valuetext": valueText, autoComplete: "off", className: "sw-stepper-input", disabled: disabled, id: inputId,
|
|
80
82
|
// iOS's numeric pad has no minus key, so a range below zero takes
|
|
81
83
|
// the text keyboard.
|
|
82
84
|
inputMode: allowsNegative ? 'text' : 'numeric', name: name, onBlur: () => setDraft(null), onChange: onType, onKeyDown: onKeyDown, placeholder: placeholder, readOnly: readOnly, role: "spinbutton", type: "text", value: text }), _jsx("button", { "aria-controls": inputId, "aria-label": incrementLabel, className: "sw-stepper-button", disabled: moves.up === null, onClick: () => move(moves.up), onMouseDown: keepFocus, tabIndex: -1, type: "button", children: _jsx("span", { "aria-hidden": "true", children: "+" }) })] }), _jsx(FieldErrorRegion, { className: "sw-field-error", id: errorId, message: error })] }));
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { type HTMLAttributes } from 'react';
|
|
2
2
|
import { type TableLayout, type TableStickyHeader, type TableVerticalAlign } from './table/table-layout.js';
|
|
3
|
+
import { type TableMaxHeight } from './table/table-max-height.js';
|
|
3
4
|
export { TableCell, type TableCellProps, type TableColumnWidth, type TableSort, } from './table/TableCell.js';
|
|
4
5
|
export { TableRow, type TableRowProps, type TableRowVariant, } from './table/TableRow.js';
|
|
5
6
|
export type { TableCellTone } from '../css/css-table-ledger.js';
|
|
6
7
|
export { tableCellTones, tableRowVariants } from '../css/css-table-ledger.js';
|
|
7
|
-
export type { TableLayout, TableStickyHeader, TableVerticalAlign };
|
|
8
|
+
export type { TableLayout, TableMaxHeight, TableStickyHeader, TableVerticalAlign, };
|
|
8
9
|
export type TableDensity = 'comfortable' | 'compact';
|
|
9
10
|
export type TableProps = HTMLAttributes<HTMLTableElement> & {
|
|
10
11
|
density?: TableDensity;
|
|
@@ -40,8 +41,30 @@ export type TableProps = HTMLAttributes<HTMLTableElement> & {
|
|
|
40
41
|
* after a row's first, for a ledger read across as well as down.
|
|
41
42
|
*/
|
|
42
43
|
columnRules?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Bounds the table's height, counted in rows (`{ rows: 12 }`): its region
|
|
46
|
+
* is as tall as that many single-line body rows plus the header row (a
|
|
47
|
+
* sorting header as tall as its buttons, the touch target on a coarse
|
|
48
|
+
* pointer) and, when there is one, the footer row, and the rest of the
|
|
49
|
+
* rows scroll inside it. Rows of two lines or with controls, a second
|
|
50
|
+
* header or footer row and a horizontal scrollbar that takes room show
|
|
51
|
+
* fewer rows. The header pins to the region's top and a sticky
|
|
52
|
+
* `TableFooter` total to its bottom, so a total over every row stays in
|
|
53
|
+
* view. The region is a keyboard stop named after the table, its focus
|
|
54
|
+
* ring drawn over the pinned rows too, and an edge with rows scrolled
|
|
55
|
+
* out past it draws a shade (cast from the pinned header's last row or
|
|
56
|
+
* the total when there is one). Printed, every row shows. It keeps its
|
|
57
|
+
* header pinned to the region, so `stickyHeader` `'page'` or `false`
|
|
58
|
+
* throw with it, as do a value that is not `{ rows }` and a row count
|
|
59
|
+
* that is not a whole number from 1. Without it (the default) the table
|
|
60
|
+
* is as tall as its rows.
|
|
61
|
+
*/
|
|
62
|
+
maxHeight?: TableMaxHeight;
|
|
43
63
|
};
|
|
44
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* A wide table scrolls inside its own `ScrollRegion`, named after the
|
|
66
|
+
* table; a bounded one (`maxHeight`) scrolls its rows in it too.
|
|
67
|
+
*/
|
|
45
68
|
export declare const Table: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLTableElement> & {
|
|
46
69
|
density?: TableDensity;
|
|
47
70
|
/**
|
|
@@ -76,6 +99,25 @@ export declare const Table: import("react").ForwardRefExoticComponent<HTMLAttrib
|
|
|
76
99
|
* after a row's first, for a ledger read across as well as down.
|
|
77
100
|
*/
|
|
78
101
|
columnRules?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Bounds the table's height, counted in rows (`{ rows: 12 }`): its region
|
|
104
|
+
* is as tall as that many single-line body rows plus the header row (a
|
|
105
|
+
* sorting header as tall as its buttons, the touch target on a coarse
|
|
106
|
+
* pointer) and, when there is one, the footer row, and the rest of the
|
|
107
|
+
* rows scroll inside it. Rows of two lines or with controls, a second
|
|
108
|
+
* header or footer row and a horizontal scrollbar that takes room show
|
|
109
|
+
* fewer rows. The header pins to the region's top and a sticky
|
|
110
|
+
* `TableFooter` total to its bottom, so a total over every row stays in
|
|
111
|
+
* view. The region is a keyboard stop named after the table, its focus
|
|
112
|
+
* ring drawn over the pinned rows too, and an edge with rows scrolled
|
|
113
|
+
* out past it draws a shade (cast from the pinned header's last row or
|
|
114
|
+
* the total when there is one). Printed, every row shows. It keeps its
|
|
115
|
+
* header pinned to the region, so `stickyHeader` `'page'` or `false`
|
|
116
|
+
* throw with it, as do a value that is not `{ rows }` and a row count
|
|
117
|
+
* that is not a whole number from 1. Without it (the default) the table
|
|
118
|
+
* is as tall as its rows.
|
|
119
|
+
*/
|
|
120
|
+
maxHeight?: TableMaxHeight;
|
|
79
121
|
} & import("react").RefAttributes<HTMLTableElement>>;
|
|
80
122
|
export type TableHeaderProps = HTMLAttributes<HTMLTableSectionElement>;
|
|
81
123
|
export declare const TableHeader: import("react").ForwardRefExoticComponent<TableHeaderProps & import("react").RefAttributes<HTMLTableSectionElement>>;
|
|
@@ -87,7 +129,8 @@ export type TableFooterProps = HTMLAttributes<HTMLTableSectionElement> & {
|
|
|
87
129
|
* scroll under it: to the page while the table fits its width (the
|
|
88
130
|
* sticky header then pins to the page's top too, under any sticky
|
|
89
131
|
* AppHeader, which covers it), or to the table's own region while the
|
|
90
|
-
* table scrolls sideways in it
|
|
132
|
+
* table scrolls sideways in it or is bounded (`Table maxHeight`), where
|
|
133
|
+
* it stays at the region's bottom. A sticky ActionBar covers a pinned
|
|
91
134
|
* footer, and so does a Dialog's pinned footer, so do not pair them.
|
|
92
135
|
*/
|
|
93
136
|
sticky?: boolean;
|
|
@@ -103,7 +146,8 @@ export declare const TableFooter: import("react").ForwardRefExoticComponent<HTML
|
|
|
103
146
|
* scroll under it: to the page while the table fits its width (the
|
|
104
147
|
* sticky header then pins to the page's top too, under any sticky
|
|
105
148
|
* AppHeader, which covers it), or to the table's own region while the
|
|
106
|
-
* table scrolls sideways in it
|
|
149
|
+
* table scrolls sideways in it or is bounded (`Table maxHeight`), where
|
|
150
|
+
* it stays at the region's bottom. A sticky ActionBar covers a pinned
|
|
107
151
|
* footer, and so does a Dialog's pinned footer, so do not pair them.
|
|
108
152
|
*/
|
|
109
153
|
sticky?: boolean;
|