@scalewing/react 1.37.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +39 -1
  3. package/dist/accessible-name.d.ts +13 -0
  4. package/dist/accessible-name.js +1 -0
  5. package/dist/components/DataBar.d.ts +48 -0
  6. package/dist/components/DataBar.js +28 -0
  7. package/dist/components/Pagination.d.ts +34 -0
  8. package/dist/components/Pagination.js +27 -0
  9. package/dist/components/ScrollRegion.d.ts +9 -5
  10. package/dist/components/ScrollRegion.js +8 -6
  11. package/dist/components/SectionNav.d.ts +2 -8
  12. package/dist/components/SegmentedControl.d.ts +2 -8
  13. package/dist/components/Table.d.ts +48 -4
  14. package/dist/components/Table.js +9 -3
  15. package/dist/components/Tabs.d.ts +2 -9
  16. package/dist/components/table/TableRow.d.ts +8 -2
  17. package/dist/components/table/TableRow.js +1 -1
  18. package/dist/components/table/table-max-height.d.ts +20 -0
  19. package/dist/components/table/table-max-height.js +23 -0
  20. package/dist/components/use-scroll-overflow.d.ts +10 -8
  21. package/dist/components/use-scroll-overflow.js +23 -10
  22. package/dist/css/chevron.d.ts +6 -3
  23. package/dist/css/chevron.js +9 -4
  24. package/dist/css/css-components.js +6 -0
  25. package/dist/css/css-data-bar.d.ts +16 -0
  26. package/dist/css/css-data-bar.js +107 -0
  27. package/dist/css/css-pagination.d.ts +2 -0
  28. package/dist/css/css-pagination.js +63 -0
  29. package/dist/css/css-scroll-region.d.ts +1 -0
  30. package/dist/css/css-scroll-region.js +10 -5
  31. package/dist/css/css-table-bounded-edges.d.ts +1 -0
  32. package/dist/css/css-table-bounded-edges.js +132 -0
  33. package/dist/css/css-table-bounded.d.ts +2 -0
  34. package/dist/css/css-table-bounded.js +73 -0
  35. package/dist/css/css-table-ledger.d.ts +5 -2
  36. package/dist/css/css-table-ledger.js +5 -2
  37. package/dist/css/css-table-metrics.d.ts +14 -0
  38. package/dist/css/css-table-metrics.js +13 -0
  39. package/dist/css/css-table-sort.js +2 -1
  40. package/dist/css/css-table-total-row.d.ts +2 -0
  41. package/dist/css/css-table-total-row.js +29 -0
  42. package/dist/css/css-table.js +14 -3
  43. package/dist/css/stylesheet.js +4 -0
  44. package/dist/data-bar-geometry.d.ts +24 -0
  45. package/dist/data-bar-geometry.js +41 -0
  46. package/dist/index.d.ts +3 -1
  47. package/dist/index.js +2 -0
  48. package/dist/pagination-pages.d.ts +13 -0
  49. package/dist/pagination-pages.js +22 -0
  50. package/dist/scroll-overflow.d.ts +12 -0
  51. package/dist/scroll-overflow.js +31 -7
  52. package/dist/styles.css +223 -0
  53. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ /*
2
+ * A total row mid-table (`TableRow variant="total"`), such as a subtotal
3
+ * the rows above add up to before the table goes on: its cells at weight
4
+ * 600 under the footer's heavier rule, 2 px in the border colour across
5
+ * its top, as a `TableFooter` total is drawn. The rule is the cells' own
6
+ * top border, which the collapsed-border model resolves over the row
7
+ * above's 1 px one, so forced colours keep it (in `CanvasText`) and no
8
+ * pseudo-element is taken from a selected row's bar or a sub row's guide.
9
+ * The row takes no fill: on the subtle fill, accent text (a link or an
10
+ * accent-toned figure) falls under 4.5:1 in several palettes, as the
11
+ * selected row's note in `css-table.ts` found. A total row belongs in the
12
+ * body: a pinned header cell draws its rules on its pseudo-elements
13
+ * instead, and a `TableFooter` already draws the total at the table's
14
+ * end. A cell's `tone` keeps its colour; a struck total row mutes and
15
+ * strikes it as any struck row.
16
+ */
17
+ export function cssTableTotalRowClasses() {
18
+ return `.sw-table .sw-table-row-total > :is(th, td) {
19
+ border-top: 2px solid var(--sw-color-border);
20
+ font-weight: 600;
21
+ }
22
+
23
+ @media (forced-colors: active) {
24
+ .sw-table .sw-table-row-total > :is(th, td) { border-top-color: CanvasText; }
25
+ }`;
26
+ }
27
+ export function tableTotalRowClassCatalog() {
28
+ return ['sw-table-row-total'];
29
+ }
@@ -1,13 +1,18 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
2
  import { scrollRegionRules } from './css-scroll-region.js';
3
+ import { tableCellPadding, tableRuleWidth } from './css-table-metrics.js';
4
+ import { cssTableBoundedClasses, tableBoundedClassCatalog, } from './css-table-bounded.js';
3
5
  import { cssTableLayoutClasses, tableLayoutClassCatalog, } from './css-table-layout.js';
4
6
  import { cssTableLedgerClasses, tableLedgerClassCatalog, } from './css-table-ledger.js';
5
7
  import { cssTableFooterClasses, tableFooterClassCatalog, } from './css-table-footer.js';
6
8
  import { cssTablePagePinClasses, tablePagePinClassCatalog, } from './css-table-page-pin.js';
9
+ import { cssTableTotalRowClasses, tableTotalRowClassCatalog, } from './css-table-total-row.js';
7
10
  import { cssTablePressClasses, tablePressClassCatalog, } from './css-table-press.js';
8
11
  import { cssTableStickyHeaderClasses, tableStickyHeaderClassCatalog, } from './css-table-sticky-header.js';
9
12
  import { cssTableSortClasses, tableSortClassCatalog, } from './css-table-sort.js';
10
13
  const caption = typographyVariants.caption;
14
+ const comfortable = tableCellPadding.comfortable;
15
+ const compact = tableCellPadding.compact;
11
16
  /*
12
17
  * A selected row is marked by an accent bar at its inline start and nothing
13
18
  * else: no fill, so text, muted text and accent text (ghost buttons, links)
@@ -45,8 +50,8 @@ export function cssTableClasses() {
45
50
 
46
51
  .sw-table th,
47
52
  .sw-table td {
48
- border-bottom: 1px solid var(--sw-color-border);
49
- padding: var(--sw-space-2) var(--sw-space-3);
53
+ border-bottom: ${tableRuleWidth} solid var(--sw-color-border);
54
+ padding: ${comfortable.block} ${comfortable.inline};
50
55
  text-align: start;
51
56
  vertical-align: middle;
52
57
  }
@@ -79,7 +84,7 @@ ${cssTableStickyHeaderClasses()}
79
84
 
80
85
  .sw-table-compact th,
81
86
  .sw-table-compact td {
82
- padding: var(--sw-space-1) var(--sw-space-2);
87
+ padding: ${compact.block} ${compact.inline};
83
88
  }
84
89
 
85
90
  ${cssTableLayoutClasses()}
@@ -88,10 +93,14 @@ ${cssTableSortClasses()}
88
93
 
89
94
  ${cssTableLedgerClasses()}
90
95
 
96
+ ${cssTableTotalRowClasses()}
97
+
91
98
  ${cssTableFooterClasses()}
92
99
 
93
100
  ${cssTablePagePinClasses()}
94
101
 
102
+ ${cssTableBoundedClasses()}
103
+
95
104
  ${cssTablePressClasses()}
96
105
 
97
106
  ${selectedRowRules()}`;
@@ -109,8 +118,10 @@ export function tableClassCatalog() {
109
118
  ...tableLayoutClassCatalog(),
110
119
  ...tableSortClassCatalog(),
111
120
  ...tableLedgerClassCatalog(),
121
+ ...tableTotalRowClassCatalog(),
112
122
  ...tableFooterClassCatalog(),
113
123
  ...tablePagePinClassCatalog(),
124
+ ...tableBoundedClassCatalog(),
114
125
  ...tablePressClassCatalog(),
115
126
  ];
116
127
  }
@@ -31,6 +31,8 @@ import { boxLinkClassCatalog } from './css-box-link.js';
31
31
  import { cssComponentClasses } from './css-components.js';
32
32
  import { buttonClassCatalog } from './css-button.js';
33
33
  import { chartClassCatalog } from './css-chart.js';
34
+ import { dataBarClassCatalog } from './css-data-bar.js';
35
+ import { paginationClassCatalog } from './css-pagination.js';
34
36
  import { dataClassCatalog } from './css-data.js';
35
37
  import { segmentedClassCatalog } from './css-segmented.js';
36
38
  import { tableClassCatalog } from './css-table.js';
@@ -69,6 +71,8 @@ export function utilityClassCatalog() {
69
71
  ...tableClassCatalog(),
70
72
  ...scrollRegionClassCatalog(),
71
73
  ...chartClassCatalog(),
74
+ ...dataBarClassCatalog(),
75
+ ...paginationClassCatalog(),
72
76
  ...chromeClassCatalog(),
73
77
  ...sectionNavClassCatalog(),
74
78
  ...dialogClassCatalog(),
@@ -0,0 +1,24 @@
1
+ /** Where a range bar sits on its track, as shares of the track (0 to 1). */
2
+ export type DataBarGeometry = {
3
+ /** The bar's inline start, from the track's start. */
4
+ start: number;
5
+ /** The bar's length. */
6
+ size: number;
7
+ /** Where zero falls, when the domain runs from below zero to above it. */
8
+ zero: number | null;
9
+ /**
10
+ * Which end of the bar meets the zero line on such a domain: `start`
11
+ * for a bar from zero toward the domain's end (a positive value), `end`
12
+ * for one from below zero up to it, `null` when neither end is zero.
13
+ */
14
+ zeroEnd: 'start' | 'end' | null;
15
+ };
16
+ /**
17
+ * Places the range from `from` to `to` on a track whose domain runs from
18
+ * `min` to `max`: the bar starts at the smaller end and runs to the larger,
19
+ * each clamped to the domain, so a value just past it from rounding stays
20
+ * on the track. A domain from below zero to above it has a zero line, and
21
+ * the bar says which of its ends meets it.
22
+ * Non-finite numbers, or a `min` not under `max`, throw a `RangeError`.
23
+ */
24
+ export declare function dataBarGeometry(from: number, to: number, min: number, max: number): DataBarGeometry;
@@ -0,0 +1,41 @@
1
+ function assertFinite(name, value) {
2
+ if (typeof value !== 'number' || !Number.isFinite(value))
3
+ throw new RangeError(`DataBar ${name} must be a finite number: ${String(value)}`);
4
+ }
5
+ function share(value, min, span) {
6
+ return (Math.min(Math.max(value, min), min + span) - min) / span;
7
+ }
8
+ /**
9
+ * Places the range from `from` to `to` on a track whose domain runs from
10
+ * `min` to `max`: the bar starts at the smaller end and runs to the larger,
11
+ * each clamped to the domain, so a value just past it from rounding stays
12
+ * on the track. A domain from below zero to above it has a zero line, and
13
+ * the bar says which of its ends meets it.
14
+ * Non-finite numbers, or a `min` not under `max`, throw a `RangeError`.
15
+ */
16
+ export function dataBarGeometry(from, to, min, max) {
17
+ assertFinite('from', from);
18
+ assertFinite('to', to);
19
+ assertFinite('min', min);
20
+ assertFinite('max', max);
21
+ if (min >= max)
22
+ throw new RangeError(`DataBar min must be under max: min ${min}, max ${max}`);
23
+ const span = max - min;
24
+ const low = Math.min(from, to);
25
+ const high = Math.max(from, to);
26
+ const start = share(low, min, span);
27
+ const end = share(high, min, span);
28
+ const diverging = min < 0 && max > 0;
29
+ return {
30
+ start,
31
+ size: end - start,
32
+ zero: diverging ? share(0, min, span) : null,
33
+ zeroEnd: !diverging || low === high
34
+ ? null
35
+ : low === 0
36
+ ? 'start'
37
+ : high === 0
38
+ ? 'end'
39
+ : null,
40
+ };
41
+ }
package/dist/index.d.ts CHANGED
@@ -16,6 +16,8 @@ export { RadioGroup, type RadioGroupOption, type RadioGroupProps, } from './comp
16
16
  export { AppHeader, appHeaderAppearances, type AppHeaderAppearance, type AppHeaderProps, } from './components/AppHeader.js';
17
17
  export { Badge, type BadgeProps, type BadgeSize, type BadgeTone, badgeSizes, badgeTones, } from './components/Badge.js';
18
18
  export { BarChart, type BarChartItem, type BarChartProps, type BarChartTone, barChartTones, } from './components/BarChart.js';
19
+ export { DataBar, type DataBarProps, type DataBarTone, dataBarTones, } from './components/DataBar.js';
20
+ export { Pagination, type PaginationLabels, type PaginationProps, } from './components/Pagination.js';
19
21
  export { Button, type ButtonDisabledAppearance, type ButtonProps, type ButtonSize, type ButtonVariant, } from './components/Button.js';
20
22
  export { buttonDisabledAppearances, webButtonVariants, } from './css/css-button.js';
21
23
  export { Box, type BoxBorder, type BoxElement, type BoxLink, type BoxProps, } from './components/Box.js';
@@ -42,7 +44,7 @@ export { Select } from './components/Select.js';
42
44
  export type { SelectAction, SelectOption, SelectProps, SelectWidth, } from './components/Select.js';
43
45
  export { MultiSelect, type MultiSelectAlign, type MultiSelectOption, type MultiSelectProps, } from './components/MultiSelect.js';
44
46
  export { Stack, type Align, type Justify, type StackProps, } from './components/Stack.js';
45
- export { Table, TableBody, TableCell, TableFooter, TableHeader, TableRow, tableCellTones, tableRowVariants, type TableBodyProps, type TableCellProps, type TableCellTone, type TableColumnWidth, type TableDensity, type TableFooterProps, type TableHeaderProps, type TableLayout, type TableProps, type TableRowProps, type TableRowVariant, type TableSort, type TableStickyHeader, type TableVerticalAlign, } from './components/Table.js';
47
+ export { Table, TableBody, TableCell, TableFooter, TableHeader, TableRow, tableCellTones, tableRowVariants, type TableBodyProps, type TableCellProps, type TableCellTone, type TableColumnWidth, type TableDensity, type TableFooterProps, type TableHeaderProps, type TableLayout, type TableMaxHeight, type TableProps, type TableRowProps, type TableRowVariant, type TableSort, type TableStickyHeader, type TableVerticalAlign, } from './components/Table.js';
46
48
  export { Text, type TextAlign, type TextElement, type TextProps, } from './components/Text.js';
47
49
  export { ThemeProvider, useTheme, type ThemeProviderProps, } from './theme/ThemeProvider.js';
48
50
  export { utilityClassCatalog } from './css/stylesheet.js';
package/dist/index.js CHANGED
@@ -15,6 +15,8 @@ export { RadioGroup, } from './components/RadioGroup.js';
15
15
  export { AppHeader, appHeaderAppearances, } from './components/AppHeader.js';
16
16
  export { Badge, badgeSizes, badgeTones, } from './components/Badge.js';
17
17
  export { BarChart, barChartTones, } from './components/BarChart.js';
18
+ export { DataBar, dataBarTones, } from './components/DataBar.js';
19
+ export { Pagination, } from './components/Pagination.js';
18
20
  export { Button, } from './components/Button.js';
19
21
  export { buttonDisabledAppearances, webButtonVariants, } from './css/css-button.js';
20
22
  export { Box, } from './components/Box.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Checks a pager's place: `pageCount` a whole number from 1 and `page` a
3
+ * whole number from 1 to `pageCount`. Pages count from 1, as people read
4
+ * them. Anything else throws a `RangeError`.
5
+ */
6
+ export declare function assertPaginationPages(page: number, pageCount: number): void;
7
+ /** The page a step goes to, or `null` at the end it cannot pass. */
8
+ export declare function paginationStep(page: number, pageCount: number, direction: 'previous' | 'next'): number | null;
9
+ /** The steps' names, one per step, each a word or two (not blank). */
10
+ export declare function assertPaginationLabels(labels: {
11
+ previous: string;
12
+ next: string;
13
+ }): void;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Checks a pager's place: `pageCount` a whole number from 1 and `page` a
3
+ * whole number from 1 to `pageCount`. Pages count from 1, as people read
4
+ * them. Anything else throws a `RangeError`.
5
+ */
6
+ export function assertPaginationPages(page, pageCount) {
7
+ if (!Number.isInteger(pageCount) || pageCount < 1)
8
+ throw new RangeError(`Pagination pageCount must be a whole number from 1: ${String(pageCount)}`);
9
+ if (!Number.isInteger(page) || page < 1 || page > pageCount)
10
+ throw new RangeError(`Pagination page must be a whole number from 1 to ${pageCount}: ${String(page)}`);
11
+ }
12
+ /** The page a step goes to, or `null` at the end it cannot pass. */
13
+ export function paginationStep(page, pageCount, direction) {
14
+ const target = direction === 'previous' ? page - 1 : page + 1;
15
+ return target < 1 || target > pageCount ? null : target;
16
+ }
17
+ /** The steps' names, one per step, each a word or two (not blank). */
18
+ export function assertPaginationLabels(labels) {
19
+ for (const key of ['previous', 'next'])
20
+ if (typeof labels?.[key] !== 'string' || labels[key].trim() === '')
21
+ throw new RangeError(`Pagination labels.${key} must be a word or two`);
22
+ }
@@ -3,7 +3,13 @@ export type ScrollOverflow = {
3
3
  start: boolean;
4
4
  end: boolean;
5
5
  };
6
+ /** Which block edges of a scroll box have content scrolled out past them. */
7
+ export type BlockScrollOverflow = {
8
+ top: boolean;
9
+ bottom: boolean;
10
+ };
6
11
  export declare const noScrollOverflow: ScrollOverflow;
12
+ export declare const noBlockScrollOverflow: BlockScrollOverflow;
7
13
  /**
8
14
  * Reads a box's horizontal overflow from its scroll metrics. `scrollLeft` is
9
15
  * 0 at the inline start and grows toward the end in a left-to-right box; in
@@ -11,4 +17,10 @@ export declare const noScrollOverflow: ScrollOverflow;
11
17
  * the distance travelled is its magnitude in both.
12
18
  */
13
19
  export declare function scrollOverflow(scrollLeft: number, scrollWidth: number, clientWidth: number): ScrollOverflow;
20
+ /**
21
+ * Reads a box's vertical overflow from its scroll metrics: `scrollTop` is 0
22
+ * at the top and grows toward the bottom.
23
+ */
24
+ export declare function blockScrollOverflow(scrollTop: number, scrollHeight: number, clientHeight: number): BlockScrollOverflow;
14
25
  export declare function sameScrollOverflow(a: ScrollOverflow, b: ScrollOverflow): boolean;
26
+ export declare function sameBlockScrollOverflow(a: BlockScrollOverflow, b: BlockScrollOverflow): boolean;
@@ -1,10 +1,25 @@
1
1
  export const noScrollOverflow = { start: false, end: false };
2
+ export const noBlockScrollOverflow = {
3
+ top: false,
4
+ bottom: false,
5
+ };
2
6
  /**
3
7
  * Sub-pixel layout can leave a box a fraction of a pixel wider than its
4
8
  * content, or a scroll position a fraction short of its end; within this
5
9
  * many pixels an edge counts as reached.
6
10
  */
7
11
  const edgeTolerance = 1;
12
+ /**
13
+ * Whether one axis has content past its leading and its trailing edge, or
14
+ * `null` when the content fits that axis. `travelled` is how far the box
15
+ * has scrolled from its leading edge.
16
+ */
17
+ function axisOverflow(travelled, scrollSize, clientSize) {
18
+ const hidden = scrollSize - clientSize;
19
+ if (hidden <= edgeTolerance)
20
+ return null;
21
+ return [travelled > edgeTolerance, travelled < hidden - edgeTolerance];
22
+ }
8
23
  /**
9
24
  * Reads a box's horizontal overflow from its scroll metrics. `scrollLeft` is
10
25
  * 0 at the inline start and grows toward the end in a left-to-right box; in
@@ -12,15 +27,24 @@ const edgeTolerance = 1;
12
27
  * the distance travelled is its magnitude in both.
13
28
  */
14
29
  export function scrollOverflow(scrollLeft, scrollWidth, clientWidth) {
15
- const hidden = scrollWidth - clientWidth;
16
- if (hidden <= edgeTolerance)
30
+ const edges = axisOverflow(Math.abs(scrollLeft), scrollWidth, clientWidth);
31
+ if (edges === null)
17
32
  return noScrollOverflow;
18
- const travelled = Math.abs(scrollLeft);
19
- return {
20
- start: travelled > edgeTolerance,
21
- end: travelled < hidden - edgeTolerance,
22
- };
33
+ return { start: edges[0], end: edges[1] };
34
+ }
35
+ /**
36
+ * Reads a box's vertical overflow from its scroll metrics: `scrollTop` is 0
37
+ * at the top and grows toward the bottom.
38
+ */
39
+ export function blockScrollOverflow(scrollTop, scrollHeight, clientHeight) {
40
+ const edges = axisOverflow(scrollTop, scrollHeight, clientHeight);
41
+ if (edges === null)
42
+ return noBlockScrollOverflow;
43
+ return { top: edges[0], bottom: edges[1] };
23
44
  }
24
45
  export function sameScrollOverflow(a, b) {
25
46
  return a.start === b.start && a.end === b.end;
26
47
  }
48
+ export function sameBlockScrollOverflow(a, b) {
49
+ return a.top === b.top && a.bottom === b.bottom;
50
+ }
package/dist/styles.css CHANGED
@@ -1833,6 +1833,15 @@ body {
1833
1833
  .sw-table-row-sub > th[scope='row']::after { border-color: CanvasText; }
1834
1834
  }
1835
1835
 
1836
+ .sw-table .sw-table-row-total > :is(th, td) {
1837
+ border-top: 2px solid var(--sw-color-border);
1838
+ font-weight: 600;
1839
+ }
1840
+
1841
+ @media (forced-colors: active) {
1842
+ .sw-table .sw-table-row-total > :is(th, td) { border-top-color: CanvasText; }
1843
+ }
1844
+
1836
1845
  .sw-table tfoot :is(th, td) {
1837
1846
  font-weight: 600;
1838
1847
  position: relative;
@@ -1868,6 +1877,121 @@ body {
1868
1877
  overflow: visible;
1869
1878
  }
1870
1879
 
1880
+ .sw-table-bounded {
1881
+ --sw-table-cell-pad: var(--sw-space-2);
1882
+ --sw-table-head-block: 0px;
1883
+ --sw-table-foot-rows: 0;
1884
+ max-height: calc((var(--sw-table-max-rows) + var(--sw-table-foot-rows)) * (25px + 2 * var(--sw-table-cell-pad) + 1px) + var(--sw-table-head-block));
1885
+ }
1886
+
1887
+ .sw-table-bounded:has(> .sw-table-compact) {
1888
+ --sw-table-cell-pad: var(--sw-space-1);
1889
+ }
1890
+
1891
+ .sw-table-bounded:has(> .sw-table > thead) {
1892
+ --sw-table-head-block: calc(18px + 2 * var(--sw-table-cell-pad));
1893
+ }
1894
+
1895
+ .sw-table-bounded:has(> .sw-table > thead .sw-table-sort) {
1896
+ --sw-table-head-block: calc(max(18px, var(--sw-control-xs-min-height)) + 2 * var(--sw-table-cell-pad));
1897
+ }
1898
+
1899
+ @media (pointer: coarse) {
1900
+ .sw-table-bounded:has(> .sw-table > thead .sw-table-sort) {
1901
+ --sw-table-head-block: calc(max(18px, var(--sw-control-md-min-height)) + 2 * var(--sw-table-cell-pad));
1902
+ }
1903
+ }
1904
+
1905
+ .sw-table-bounded:has(> .sw-table > tfoot) {
1906
+ --sw-table-foot-rows: 1;
1907
+ }
1908
+
1909
+ @media print {
1910
+ .sw-table-bounded { max-height: none; }
1911
+ }
1912
+
1913
+ .sw-table-bounded.sw-scroll-more-top > .sw-table-sticky > thead > tr:last-child > :is(th, td)::before {
1914
+ background: linear-gradient(to bottom, color-mix(in srgb, var(--sw-color-text) 28%, transparent), transparent);
1915
+ border-bottom: 0;
1916
+ border-top: 1px solid var(--sw-color-border);
1917
+ box-sizing: border-box;
1918
+ height: var(--sw-space-5);
1919
+ inset-block-end: auto;
1920
+ inset-block-start: calc(100% - 1px);
1921
+ }
1922
+
1923
+ .sw-table-bounded.sw-scroll-more-bottom > .sw-table > .sw-table-footer-sticky > tr:first-child > :is(th, td)::before {
1924
+ background: linear-gradient(to top, color-mix(in srgb, var(--sw-color-text) 28%, transparent), transparent);
1925
+ border-bottom: 2px solid var(--sw-color-border);
1926
+ border-top: 0;
1927
+ box-sizing: border-box;
1928
+ height: var(--sw-space-5);
1929
+ inset-block-end: calc(100% - 1px);
1930
+ inset-block-start: auto;
1931
+ }
1932
+
1933
+ .sw-table-bounded.sw-scroll-more-top:not(:has(> .sw-table > thead)),
1934
+ .sw-table-bounded.sw-scroll-more-bottom:not(:has(> .sw-table > .sw-table-footer-sticky)) {
1935
+ background-repeat: no-repeat;
1936
+ background-size: 100% var(--sw-space-5);
1937
+ }
1938
+
1939
+ .sw-table-bounded.sw-scroll-more-top:not(:has(> .sw-table > thead)) {
1940
+ background-image: linear-gradient(to bottom, color-mix(in srgb, var(--sw-color-text) 28%, transparent), transparent);
1941
+ background-position: top;
1942
+ }
1943
+
1944
+ .sw-table-bounded.sw-scroll-more-bottom:not(:has(> .sw-table > .sw-table-footer-sticky)) {
1945
+ background-image: linear-gradient(to top, color-mix(in srgb, var(--sw-color-text) 28%, transparent), transparent);
1946
+ background-position: bottom;
1947
+ }
1948
+
1949
+ .sw-table-bounded.sw-scroll-more-top.sw-scroll-more-bottom:not(:has(> .sw-table > thead)):not(:has(> .sw-table > .sw-table-footer-sticky)) {
1950
+ background-image: linear-gradient(to bottom, color-mix(in srgb, var(--sw-color-text) 28%, transparent), transparent), linear-gradient(to top, color-mix(in srgb, var(--sw-color-text) 28%, transparent), transparent);
1951
+ background-position: top, bottom;
1952
+ }
1953
+
1954
+ @media (forced-colors: active) {
1955
+ .sw-table-bounded.sw-scroll-more-top > .sw-table-sticky > thead > tr:last-child > :is(th, td)::before,
1956
+ .sw-table-bounded.sw-scroll-more-bottom > .sw-table > .sw-table-footer-sticky > tr:first-child > :is(th, td)::before { background: none; border-color: CanvasText; }
1957
+ .sw-table-bounded.sw-scroll-more-top:not(:has(> .sw-table > thead)),
1958
+ .sw-table-bounded.sw-scroll-more-bottom:not(:has(> .sw-table > .sw-table-footer-sticky)),
1959
+ .sw-table-bounded.sw-scroll-more-top.sw-scroll-more-bottom:not(:has(> .sw-table > thead)):not(:has(> .sw-table > .sw-table-footer-sticky)) { background-image: none; }
1960
+ }
1961
+
1962
+ .sw-table-bounded:focus-visible > .sw-table-sticky > thead > tr > :is(th, td),
1963
+ .sw-table-bounded:focus-visible > .sw-table > .sw-table-footer-sticky > tr > :is(th, td) {
1964
+ box-shadow: var(--sw-table-ring-block, 0 0 transparent), var(--sw-table-ring-start, 0 0 transparent), var(--sw-table-ring-end, 0 0 transparent);
1965
+ }
1966
+
1967
+ .sw-table-bounded:focus-visible > .sw-table-sticky > thead > tr:first-child > :is(th, td) {
1968
+ --sw-table-ring-block: inset 0 var(--sw-focus-ring-width) 0 0 var(--sw-color-accent);
1969
+ }
1970
+
1971
+ .sw-table-bounded:focus-visible > .sw-table > .sw-table-footer-sticky > tr:last-child > :is(th, td) {
1972
+ --sw-table-ring-block: inset 0 calc(-1 * var(--sw-focus-ring-width)) 0 0 var(--sw-color-accent);
1973
+ }
1974
+
1975
+ .sw-table-bounded:focus-visible > .sw-table-sticky > thead > tr > :first-child,
1976
+ .sw-table-bounded:focus-visible > .sw-table > .sw-table-footer-sticky > tr > :first-child {
1977
+ --sw-table-ring-start: inset var(--sw-focus-ring-width) 0 0 0 var(--sw-color-accent);
1978
+ }
1979
+
1980
+ .sw-table-bounded:focus-visible > .sw-table-sticky > thead > tr > :last-child,
1981
+ .sw-table-bounded:focus-visible > .sw-table > .sw-table-footer-sticky > tr > :last-child {
1982
+ --sw-table-ring-end: inset calc(-1 * var(--sw-focus-ring-width)) 0 0 0 var(--sw-color-accent);
1983
+ }
1984
+
1985
+ .sw-table-bounded:focus-visible > .sw-table-sticky > thead > tr > :first-child:dir(rtl),
1986
+ .sw-table-bounded:focus-visible > .sw-table > .sw-table-footer-sticky > tr > :first-child:dir(rtl) {
1987
+ --sw-table-ring-start: inset calc(-1 * var(--sw-focus-ring-width)) 0 0 0 var(--sw-color-accent);
1988
+ }
1989
+
1990
+ .sw-table-bounded:focus-visible > .sw-table-sticky > thead > tr > :last-child:dir(rtl),
1991
+ .sw-table-bounded:focus-visible > .sw-table > .sw-table-footer-sticky > tr > :last-child:dir(rtl) {
1992
+ --sw-table-ring-end: inset var(--sw-focus-ring-width) 0 0 0 var(--sw-color-accent);
1993
+ }
1994
+
1871
1995
  .sw-table-row-press {
1872
1996
  cursor: pointer;
1873
1997
  }
@@ -2405,6 +2529,105 @@ body {
2405
2529
  .sw-bar-chart-fill { background: CanvasText; }
2406
2530
  }
2407
2531
 
2532
+ .sw-data-bar {
2533
+ display: block;
2534
+ height: var(--sw-space-4);
2535
+ min-width: var(--sw-space-6);
2536
+ position: relative;
2537
+ width: 100%;
2538
+ }
2539
+
2540
+ .sw-data-bar-fill {
2541
+ border-radius: calc(var(--sw-radius-sm) / 2);
2542
+ inset-block: 0;
2543
+ inset-inline-start: calc(var(--sw-data-bar-start, 0) * 100%);
2544
+ position: absolute;
2545
+ width: calc(var(--sw-data-bar-size, 0) * 100%);
2546
+ }
2547
+
2548
+ .sw-data-bar-neutral > .sw-data-bar-fill { background: color-mix(in srgb, var(--sw-color-muted) 65%, var(--sw-color-surface)); }
2549
+ .sw-data-bar-success > .sw-data-bar-fill { background: color-mix(in srgb, var(--sw-color-success) 55%, var(--sw-color-surface)); }
2550
+ .sw-data-bar-muted > .sw-data-bar-fill { background: color-mix(in srgb, var(--sw-color-muted) 35%, var(--sw-color-surface)); }
2551
+ .sw-data-bar-strong > .sw-data-bar-fill { background: color-mix(in srgb, var(--sw-color-text) 85%, var(--sw-color-surface)); }
2552
+ .sw-data-bar-accent > .sw-data-bar-fill { background: var(--sw-color-accent); }
2553
+
2554
+ .sw-data-bar-diverging::before {
2555
+ background: var(--sw-color-border);
2556
+ content: '';
2557
+ inset-block: calc(-1 * var(--sw-space-1));
2558
+ inset-inline-start: calc(var(--sw-data-bar-zero, 0) * 100%);
2559
+ /* Centred on zero, mirrored right to left. */
2560
+ margin-inline-start: -0.5px;
2561
+ position: absolute;
2562
+ width: 1px;
2563
+ }
2564
+
2565
+ .sw-data-bar-zero-start > .sw-data-bar-fill {
2566
+ border-end-start-radius: 0;
2567
+ border-start-start-radius: 0;
2568
+ }
2569
+
2570
+ .sw-data-bar-zero-end > .sw-data-bar-fill {
2571
+ border-end-end-radius: 0;
2572
+ border-start-end-radius: 0;
2573
+ }
2574
+
2575
+ @media (forced-colors: active) {
2576
+ .sw-data-bar > .sw-data-bar-fill,
2577
+ .sw-data-bar-diverging::before { background: CanvasText; }
2578
+ }
2579
+
2580
+ .sw-pagination {
2581
+ align-items: center;
2582
+ display: flex;
2583
+ flex-wrap: wrap;
2584
+ gap: var(--sw-space-2) var(--sw-space-3);
2585
+ }
2586
+
2587
+ .sw-pagination-range {
2588
+ color: var(--sw-color-muted);
2589
+ font-family: var(--sw-font-sans);
2590
+ font-size: 13px;
2591
+ font-variant-numeric: tabular-nums;
2592
+ letter-spacing: -0.08px;
2593
+ line-height: 18px;
2594
+ }
2595
+
2596
+ .sw-pagination-steps {
2597
+ display: flex;
2598
+ gap: var(--sw-space-2);
2599
+ margin-inline-start: auto;
2600
+ }
2601
+
2602
+ .sw-button.sw-pagination-step {
2603
+ flex: none;
2604
+ padding-inline: 0;
2605
+ }
2606
+
2607
+ .sw-button-xs.sw-pagination-step { min-width: var(--sw-control-xs-min-height); }
2608
+ .sw-button-sm.sw-pagination-step { min-width: var(--sw-control-sm-min-height); }
2609
+ .sw-button-md.sw-pagination-step { min-width: var(--sw-control-md-min-height); }
2610
+
2611
+ @media (pointer: coarse) {
2612
+ .sw-button.sw-pagination-step {
2613
+ min-height: var(--sw-control-md-min-height);
2614
+ min-width: var(--sw-control-md-min-height);
2615
+ }
2616
+ }
2617
+
2618
+ .sw-pagination-glyph {
2619
+ border-bottom: 2px solid currentColor;
2620
+ border-right: 2px solid currentColor;
2621
+ box-sizing: border-box;
2622
+ height: var(--sw-space-2);
2623
+ width: var(--sw-space-2);
2624
+ display: block;
2625
+ }
2626
+
2627
+ .sw-pagination-glyph-previous { transform: translateX(25%) rotate(135deg); }
2628
+ .sw-pagination-glyph-next { transform: translateX(-25%) rotate(-45deg); }
2629
+ .sw-pagination-glyph:dir(rtl) { scale: -1 1; }
2630
+
2408
2631
  .sw-app-header {
2409
2632
  background: var(--sw-glass-fill);
2410
2633
  border: 1px solid var(--sw-glass-border);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalewing/react",
3
- "version": "1.37.0",
3
+ "version": "1.38.0",
4
4
  "description": "Scalewing DOM components and package-owned CSS utilities.",
5
5
  "type": "module",
6
6
  "license": "MIT",