@scalewing/react 1.7.0 → 1.8.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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # @scalewing/react
2
2
 
3
+ ## 1.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7d46059: A `DenominationGrid` `strip` wider than its container now scrolls sideways
8
+ inside its own region instead of widening the page (for example an
9
+ eleven-column strip on a 390 px phone, or a six-column strip inside an
10
+ outlined card inside another card). The region is a keyboard-focusable
11
+ `group` named after the grid's `label`, like `Table`'s scroll wrapper, and
12
+ the row labels and the header corner above them stay pinned at the start
13
+ while the counts scroll under them, so each column head stays over its
14
+ counts. The pinned label draws its tone stripe as its own box, so the stripe
15
+ moves with it in every browser.
16
+
17
+ Reduce Transparency now takes effect on every glass surface it lists: the
18
+ fallback block is emitted after all component rules, where before most glass
19
+ rules (app header, sticky table head, dialog, toast and others) came after it
20
+ and kept their blur. The block lists glass surfaces only: the filled
21
+ secondary button left it, so it keeps its own fill and text colors.
22
+
23
+ New generated classes: `.sw-denomination-scroll` (the scroll region) and
24
+ `.sw-denomination-label-body` (the icon, label, and phone total inside the
25
+ row label cell). `Table` and the strip now share one generated scroll-region
26
+ rule; `.sw-table-wrap` output is unchanged. No prop changes. See
27
+ `docs/requests/teisoro-denomination-grid.md`.
28
+
3
29
  ## 1.7.0
4
30
 
5
31
  ### Minor Changes
package/README.md CHANGED
@@ -87,7 +87,7 @@ Every `Box`-based component (`Box`, `Stack`, `Inline`, `Card`, `Grid`, …) take
87
87
 
88
88
  Values outside the catalog throw a `RangeError`. There is no per-breakpoint span and no arbitrary column template.
89
89
 
90
- `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 moves under the label on a phone. The `tiles` layout stacks the column label, the count, and an optional `subtotal` string per column. The primitive does no arithmetic and no currency formatting; tones reuse the Badge vocabulary. Invalid columns, rows, or cells throw.
90
+ `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 moves under the label on a phone. 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; the page never scrolls sideways. The `tiles` layout stacks the column label, the count, and an optional `subtotal` string per column. The primitive does no arithmetic and no currency formatting; tones reuse the Badge vocabulary. Invalid columns, rows, or cells throw.
91
91
 
92
92
  `FilterChips` presents a long, wrapping single-choice filter set. Provide a localized group `label`, controlled `value`, `onChange`, and options with stable values and localized labels. An optional non-negative integer `count` renders as a tabular chicklet after the label and is part of the option's accessible name; a zero count quiets the chip until it is selected. Native radios provide arrow and Space navigation; disabled options are skipped.
93
93
 
@@ -0,0 +1,15 @@
1
+ import { type ReactNode } from 'react';
2
+ type ScrollRegionProps = {
3
+ children: ReactNode;
4
+ className: string;
5
+ 'aria-label'?: string;
6
+ 'aria-labelledby'?: string;
7
+ };
8
+ /**
9
+ * Private wrapper that scrolls wide content inside its own box (see
10
+ * `scrollRegionRules`). It is a keyboard stop named after its content, so a
11
+ * wide table with no focusable cell can still be scrolled sideways from the
12
+ * keyboard and is announced as one group.
13
+ */
14
+ export declare function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, }: ScrollRegionProps): import("react").JSX.Element;
15
+ export {};
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * Private wrapper that scrolls wide content inside its own box (see
4
+ * `scrollRegionRules`). It is a keyboard stop named after its content, so a
5
+ * wide table with no focusable cell can still be scrolled sideways from the
6
+ * keyboard and is announced as one group.
7
+ */
8
+ export function ScrollRegion({ children, className, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, }) {
9
+ return (_jsx("div", { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className: className, role: "group", tabIndex: 0, children: children }));
10
+ }
@@ -4,11 +4,7 @@ export type TableProps = HTMLAttributes<HTMLTableElement> & {
4
4
  density?: TableDensity;
5
5
  stickyHeader?: boolean;
6
6
  };
7
- /**
8
- * The scroll wrapper is a keyboard stop named after the table, so a wide
9
- * table with no focusable cell can still be scrolled sideways from the
10
- * keyboard and is announced as one group.
11
- */
7
+ /** A wide table scrolls inside its own `ScrollRegion`, named after the table. */
12
8
  export declare const Table: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLTableElement> & {
13
9
  density?: TableDensity;
14
10
  stickyHeader?: boolean;
@@ -1,13 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, } from 'react';
3
3
  import { cx } from '../class-names.js';
4
- /**
5
- * The scroll wrapper is a keyboard stop named after the table, so a wide
6
- * table with no focusable cell can still be scrolled sideways from the
7
- * keyboard and is announced as one group.
8
- */
4
+ import { ScrollRegion } from './ScrollRegion.js';
5
+ /** A wide table scrolls inside its own `ScrollRegion`, named after the table. */
9
6
  export const Table = forwardRef(function Table({ children, className, density = 'comfortable', stickyHeader = true, ...rest }, ref) {
10
- return (_jsx("div", { "aria-label": rest['aria-label'], "aria-labelledby": rest['aria-labelledby'], className: "sw-table-wrap", role: "group", tabIndex: 0, children: _jsx("table", { ref: ref, className: cx('sw-table', density === 'compact' && 'sw-table-compact', stickyHeader && 'sw-table-sticky', className), ...rest, children: children }) }));
7
+ return (_jsx(ScrollRegion, { "aria-label": rest['aria-label'], "aria-labelledby": rest['aria-labelledby'], className: "sw-table-wrap", children: _jsx("table", { ref: ref, className: cx('sw-table', density === 'compact' && 'sw-table-compact', stickyHeader && 'sw-table-sticky', className), ...rest, children: children }) }));
11
8
  });
12
9
  export const TableHeader = forwardRef(function TableHeader({ className, ...rest }, ref) {
13
10
  return _jsx("thead", { ref: ref, className: className, ...rest });
@@ -1,10 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { cx } from '../../class-names.js';
3
3
  import { denominationCellView } from '../../denomination-cells.js';
4
+ import { ScrollRegion } from '../ScrollRegion.js';
4
5
  export function DenominationStrip({ label, columns, rows, zeroLabel, }) {
5
6
  const hasTotals = rows.some((row) => row.total !== undefined);
6
- return (_jsxs("table", { className: "sw-denomination-grid sw-denomination-strip", children: [_jsx("caption", { className: "sw-sr-only", children: label }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("td", { className: "sw-denomination-corner" }), columns.map((column) => (_jsx("th", { className: "sw-denomination-head", scope: "col", children: column.label }, column.key))), hasTotals ? _jsx("td", { className: "sw-denomination-corner" }) : null] }) }), _jsx("tbody", { children: rows.map((row) => (_jsxs("tr", { className: cx('sw-denomination-row', `sw-denomination-row-${row.tone ?? 'neutral'}`, row.signed && 'sw-denomination-row-signed'), children: [_jsxs("th", { className: "sw-denomination-label", scope: "row", children: [row.icon ? (_jsx("span", { "aria-hidden": "true", className: "sw-denomination-icon", children: row.icon })) : null, _jsx("span", { className: "sw-denomination-label-text", children: row.label }), row.total !== undefined ? (_jsx("span", { "aria-hidden": "true", className: "sw-denomination-total-inline", children: row.total })) : null] }), columns.map((column, index) => {
7
- const view = denominationCellView(row.cells[index] ?? null, row.signed ?? false, zeroLabel);
8
- return (_jsx("td", { className: `sw-denomination-cell sw-denomination-cell-${view.state}`, children: view.text }, column.key));
9
- }), hasTotals ? (_jsx("td", { className: "sw-denomination-total", children: row.total ?? '' })) : null] }, row.id))) })] }));
7
+ return (_jsx(ScrollRegion, { "aria-label": label, className: "sw-denomination-scroll", children: _jsxs("table", { className: "sw-denomination-grid sw-denomination-strip", children: [_jsx("caption", { className: "sw-sr-only", children: label }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("td", { className: "sw-denomination-corner" }), columns.map((column) => (_jsx("th", { className: "sw-denomination-head", scope: "col", children: column.label }, column.key))), hasTotals ? _jsx("td", { className: "sw-denomination-corner" }) : null] }) }), _jsx("tbody", { children: rows.map((row) => (_jsxs("tr", { className: cx('sw-denomination-row', `sw-denomination-row-${row.tone ?? 'neutral'}`, row.signed && 'sw-denomination-row-signed'), children: [_jsx("th", { className: "sw-denomination-label", scope: "row", children: _jsxs("span", { className: "sw-denomination-label-body", children: [row.icon ? (_jsx("span", { "aria-hidden": "true", className: "sw-denomination-icon", children: row.icon })) : null, _jsx("span", { className: "sw-denomination-label-text", children: row.label }), row.total !== undefined ? (_jsx("span", { "aria-hidden": "true", className: "sw-denomination-total-inline", children: row.total })) : null] }) }), columns.map((column, index) => {
8
+ const view = denominationCellView(row.cells[index] ?? null, row.signed ?? false, zeroLabel);
9
+ return (_jsx("td", { className: `sw-denomination-cell sw-denomination-cell-${view.state}`, children: view.text }, column.key));
10
+ }), hasTotals ? (_jsx("td", { className: "sw-denomination-total", children: row.total ?? '' })) : null] }, row.id))) })] }) }));
10
11
  }
@@ -26,6 +26,32 @@ import { cssGridSpanClasses } from './css-grid-span.js';
26
26
  import { cssDenominationGridClasses } from './css-denomination-grid.js';
27
27
  import { cssFieldClasses } from './css-field.js';
28
28
  import { cssToastClasses } from './css-toast.js';
29
+ /*
30
+ * Reduce Transparency swaps every glass surface for the solid surface. It is
31
+ * emitted after every component rule: at equal specificity the later rule wins,
32
+ * so a glass rule emitted after this block would keep its blur.
33
+ */
34
+ function reducedTransparencyRules() {
35
+ return `@media (prefers-reduced-transparency: reduce) {
36
+ .sw-card-glass,
37
+ .sw-app-header,
38
+ .sw-badge-neutral,
39
+ .sw-segmented,
40
+ .sw-table-sticky thead th,
41
+ .sw-denomination-strip .sw-denomination-label,
42
+ .sw-denomination-strip thead .sw-denomination-corner:first-child,
43
+ .sw-bar-chart-track,
44
+ .sw-dialog,
45
+ .sw-accordion,
46
+ .sw-select-list,
47
+ .sw-action-menu-list,
48
+ .sw-toast {
49
+ background: var(--sw-color-surface);
50
+ backdrop-filter: none;
51
+ -webkit-backdrop-filter: none;
52
+ }
53
+ }`;
54
+ }
29
55
  function textVariantRules() {
30
56
  return Object.entries(typographyVariants)
31
57
  .map(([name, variant]) => {
@@ -79,25 +105,6 @@ export function cssComponentClasses() {
79
105
  background: var(--sw-color-subtle);
80
106
  }
81
107
 
82
- @media (prefers-reduced-transparency: reduce) {
83
- .sw-card-glass,
84
- .sw-app-header,
85
- .sw-button-secondary,
86
- .sw-badge-neutral,
87
- .sw-segmented,
88
- .sw-table-sticky thead th,
89
- .sw-bar-chart-track,
90
- .sw-dialog,
91
- .sw-accordion,
92
- .sw-select-list,
93
- .sw-action-menu-list,
94
- .sw-toast {
95
- background: var(--sw-color-surface);
96
- backdrop-filter: none;
97
- -webkit-backdrop-filter: none;
98
- }
99
- }
100
-
101
108
  .sw-text-align-start { text-align: start; }
102
109
  .sw-text-align-center { text-align: center; }
103
110
  .sw-text-align-end { text-align: end; }
@@ -164,5 +171,7 @@ ${cssSplitClasses()}
164
171
 
165
172
  ${cssToastClasses()}
166
173
 
167
- ${cssResponsiveClasses()}`;
174
+ ${cssResponsiveClasses()}
175
+
176
+ ${reducedTransparencyRules()}`;
168
177
  }
@@ -1,4 +1,5 @@
1
1
  import { trackInset, typographyVariants } from '@scalewing/tokens';
2
+ import { scrollRegionRules } from './css-scroll-region.js';
2
3
  export const badgeTones = [
3
4
  'neutral',
4
5
  'accent',
@@ -134,15 +135,7 @@ export function cssDataClasses() {
134
135
  cursor: not-allowed;
135
136
  }
136
137
 
137
- .sw-table-wrap {
138
- overflow: auto;
139
- width: 100%;
140
- }
141
-
142
- .sw-table-wrap:focus-visible {
143
- outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
144
- outline-offset: calc(-1 * var(--sw-focus-ring-width));
145
- }
138
+ ${scrollRegionRules('.sw-table-wrap')}
146
139
 
147
140
  .sw-table {
148
141
  border-collapse: collapse;
@@ -1,6 +1,7 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
2
  import { breakpointQuery } from './breakpoints.js';
3
3
  import { badgeTones } from './css-data.js';
4
+ import { scrollRegionRules } from './css-scroll-region.js';
4
5
  const caption = typographyVariants.caption;
5
6
  const data = typographyVariants.data;
6
7
  const label = typographyVariants.label;
@@ -20,6 +21,8 @@ export function cssDenominationGridClasses() {
20
21
 
21
22
  ${toneRules()}
22
23
 
24
+ ${scrollRegionRules('.sw-denomination-scroll')}
25
+
23
26
  .sw-denomination-strip {
24
27
  border-collapse: collapse;
25
28
  width: 100%;
@@ -49,20 +52,56 @@ ${toneRules()}
49
52
  }
50
53
 
51
54
  .sw-denomination-label {
52
- align-items: center;
53
55
  border-inline-start: var(--sw-space-1) solid var(--sw-denomination-tone);
54
56
  color: var(--sw-denomination-tone);
55
- display: flex;
56
- flex-wrap: wrap;
57
57
  font-size: ${label.fontSize}px;
58
58
  font-weight: ${label.fontWeight};
59
- gap: var(--sw-space-2);
60
59
  letter-spacing: ${label.letterSpacing}px;
61
60
  line-height: ${label.lineHeight}px;
62
61
  min-width: 0;
63
62
  text-align: start;
64
63
  }
65
64
 
65
+ .sw-denomination-tiles .sw-denomination-label,
66
+ .sw-denomination-label-body {
67
+ align-items: center;
68
+ display: flex;
69
+ flex-wrap: wrap;
70
+ gap: var(--sw-space-2);
71
+ }
72
+
73
+ /*
74
+ * The row labels and the header corner above them stay in view while a wide
75
+ * strip scrolls under them, so each column head stays over its counts.
76
+ */
77
+ .sw-denomination-strip .sw-denomination-label,
78
+ .sw-denomination-strip thead .sw-denomination-corner:first-child {
79
+ background: var(--sw-glass-fill);
80
+ backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
81
+ -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
82
+ inset-inline-start: 0;
83
+ position: sticky;
84
+ z-index: 1;
85
+ }
86
+
87
+ /*
88
+ * A collapsed-table border does not travel with a sticky cell in every
89
+ * browser, so the pinned label draws its tone stripe as its own box.
90
+ */
91
+ .sw-denomination-strip .sw-denomination-label {
92
+ border-inline-start: 0;
93
+ padding-inline-start: calc(var(--sw-space-2) + var(--sw-space-1));
94
+ }
95
+
96
+ .sw-denomination-strip .sw-denomination-label::before {
97
+ background: var(--sw-denomination-tone);
98
+ content: '';
99
+ inset-block: 0;
100
+ inset-inline-start: 0;
101
+ position: absolute;
102
+ width: var(--sw-space-1);
103
+ }
104
+
66
105
  .sw-denomination-icon {
67
106
  display: inline-flex;
68
107
  flex: none;
@@ -172,14 +211,16 @@ ${toneRules()}
172
211
  @media ${breakpointQuery('below', 'md')} {
173
212
  .sw-denomination-strip .sw-denomination-total { display: none; }
174
213
  .sw-denomination-total-inline { display: block; }
175
- .sw-denomination-strip .sw-denomination-label { flex-direction: column; align-items: flex-start; gap: var(--sw-space-1); }
214
+ .sw-denomination-label-body { flex-direction: column; align-items: flex-start; gap: var(--sw-space-1); }
176
215
  .sw-denomination-strip th,
177
216
  .sw-denomination-strip td { padding: var(--sw-space-1); }
217
+ .sw-denomination-strip .sw-denomination-label { padding-inline-start: calc(var(--sw-space-1) * 2); }
178
218
  .sw-denomination-tile-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
179
219
  }
180
220
 
181
221
  @media (forced-colors: active) {
182
222
  .sw-denomination-label { border-inline-start-color: CanvasText; color: CanvasText; }
223
+ .sw-denomination-strip .sw-denomination-label::before { background: CanvasText; forced-color-adjust: none; }
183
224
  .sw-denomination-cell-zero { color: GrayText; opacity: 1; }
184
225
  .sw-denomination-cell-negative,
185
226
  .sw-denomination-row-signed .sw-denomination-cell-positive,
@@ -190,6 +231,7 @@ ${toneRules()}
190
231
  export function denominationGridClassCatalog() {
191
232
  return [
192
233
  'sw-denomination-grid',
234
+ 'sw-denomination-scroll',
193
235
  ...badgeTones.map((tone) => `sw-denomination-row-${tone}`),
194
236
  'sw-denomination-strip',
195
237
  'sw-denomination-head',
@@ -197,6 +239,7 @@ export function denominationGridClassCatalog() {
197
239
  'sw-denomination-row',
198
240
  'sw-denomination-row-signed',
199
241
  'sw-denomination-label',
242
+ 'sw-denomination-label-body',
200
243
  'sw-denomination-label-text',
201
244
  'sw-denomination-icon',
202
245
  'sw-denomination-cell',
@@ -0,0 +1,8 @@
1
+ /**
2
+ * A scroll region is a full-width box that scrolls its own content when the
3
+ * content is wider (or taller) than the box, so a wide table never widens the
4
+ * page. It is a keyboard stop, so its focus ring is drawn inside its edge
5
+ * where an ancestor's clipping cannot hide it. Table and the DenominationGrid
6
+ * strip share it.
7
+ */
8
+ export declare function scrollRegionRules(selector: string): string;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A scroll region is a full-width box that scrolls its own content when the
3
+ * content is wider (or taller) than the box, so a wide table never widens the
4
+ * page. It is a keyboard stop, so its focus ring is drawn inside its edge
5
+ * where an ancestor's clipping cannot hide it. Table and the DenominationGrid
6
+ * strip share it.
7
+ */
8
+ export function scrollRegionRules(selector) {
9
+ return `${selector} {
10
+ overflow: auto;
11
+ width: 100%;
12
+ }
13
+
14
+ ${selector}:focus-visible {
15
+ outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
16
+ outline-offset: calc(-1 * var(--sw-focus-ring-width));
17
+ }`;
18
+ }
package/dist/styles.css CHANGED
@@ -756,25 +756,6 @@ body {
756
756
  background: var(--sw-color-subtle);
757
757
  }
758
758
 
759
- @media (prefers-reduced-transparency: reduce) {
760
- .sw-card-glass,
761
- .sw-app-header,
762
- .sw-button-secondary,
763
- .sw-badge-neutral,
764
- .sw-segmented,
765
- .sw-table-sticky thead th,
766
- .sw-bar-chart-track,
767
- .sw-dialog,
768
- .sw-accordion,
769
- .sw-select-list,
770
- .sw-action-menu-list,
771
- .sw-toast {
772
- background: var(--sw-color-surface);
773
- backdrop-filter: none;
774
- -webkit-backdrop-filter: none;
775
- }
776
- }
777
-
778
759
  .sw-text-align-start { text-align: start; }
779
760
  .sw-text-align-center { text-align: center; }
780
761
  .sw-text-align-end { text-align: end; }
@@ -2274,6 +2255,16 @@ body {
2274
2255
  .sw-denomination-row-danger { --sw-denomination-tone: var(--sw-color-danger); }
2275
2256
  .sw-denomination-row-warning { --sw-denomination-tone: var(--sw-color-warning); }
2276
2257
 
2258
+ .sw-denomination-scroll {
2259
+ overflow: auto;
2260
+ width: 100%;
2261
+ }
2262
+
2263
+ .sw-denomination-scroll:focus-visible {
2264
+ outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
2265
+ outline-offset: calc(-1 * var(--sw-focus-ring-width));
2266
+ }
2267
+
2277
2268
  .sw-denomination-strip {
2278
2269
  border-collapse: collapse;
2279
2270
  width: 100%;
@@ -2303,20 +2294,56 @@ body {
2303
2294
  }
2304
2295
 
2305
2296
  .sw-denomination-label {
2306
- align-items: center;
2307
2297
  border-inline-start: var(--sw-space-1) solid var(--sw-denomination-tone);
2308
2298
  color: var(--sw-denomination-tone);
2309
- display: flex;
2310
- flex-wrap: wrap;
2311
2299
  font-size: 15px;
2312
2300
  font-weight: 600;
2313
- gap: var(--sw-space-2);
2314
2301
  letter-spacing: -0.2px;
2315
2302
  line-height: 20px;
2316
2303
  min-width: 0;
2317
2304
  text-align: start;
2318
2305
  }
2319
2306
 
2307
+ .sw-denomination-tiles .sw-denomination-label,
2308
+ .sw-denomination-label-body {
2309
+ align-items: center;
2310
+ display: flex;
2311
+ flex-wrap: wrap;
2312
+ gap: var(--sw-space-2);
2313
+ }
2314
+
2315
+ /*
2316
+ * The row labels and the header corner above them stay in view while a wide
2317
+ * strip scrolls under them, so each column head stays over its counts.
2318
+ */
2319
+ .sw-denomination-strip .sw-denomination-label,
2320
+ .sw-denomination-strip thead .sw-denomination-corner:first-child {
2321
+ background: var(--sw-glass-fill);
2322
+ backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
2323
+ -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
2324
+ inset-inline-start: 0;
2325
+ position: sticky;
2326
+ z-index: 1;
2327
+ }
2328
+
2329
+ /*
2330
+ * A collapsed-table border does not travel with a sticky cell in every
2331
+ * browser, so the pinned label draws its tone stripe as its own box.
2332
+ */
2333
+ .sw-denomination-strip .sw-denomination-label {
2334
+ border-inline-start: 0;
2335
+ padding-inline-start: calc(var(--sw-space-2) + var(--sw-space-1));
2336
+ }
2337
+
2338
+ .sw-denomination-strip .sw-denomination-label::before {
2339
+ background: var(--sw-denomination-tone);
2340
+ content: '';
2341
+ inset-block: 0;
2342
+ inset-inline-start: 0;
2343
+ position: absolute;
2344
+ width: var(--sw-space-1);
2345
+ }
2346
+
2320
2347
  .sw-denomination-icon {
2321
2348
  display: inline-flex;
2322
2349
  flex: none;
@@ -2426,14 +2453,16 @@ body {
2426
2453
  @media not all and (min-width: 48rem) {
2427
2454
  .sw-denomination-strip .sw-denomination-total { display: none; }
2428
2455
  .sw-denomination-total-inline { display: block; }
2429
- .sw-denomination-strip .sw-denomination-label { flex-direction: column; align-items: flex-start; gap: var(--sw-space-1); }
2456
+ .sw-denomination-label-body { flex-direction: column; align-items: flex-start; gap: var(--sw-space-1); }
2430
2457
  .sw-denomination-strip th,
2431
2458
  .sw-denomination-strip td { padding: var(--sw-space-1); }
2459
+ .sw-denomination-strip .sw-denomination-label { padding-inline-start: calc(var(--sw-space-1) * 2); }
2432
2460
  .sw-denomination-tile-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
2433
2461
  }
2434
2462
 
2435
2463
  @media (forced-colors: active) {
2436
2464
  .sw-denomination-label { border-inline-start-color: CanvasText; color: CanvasText; }
2465
+ .sw-denomination-strip .sw-denomination-label::before { background: CanvasText; forced-color-adjust: none; }
2437
2466
  .sw-denomination-cell-zero { color: GrayText; opacity: 1; }
2438
2467
  .sw-denomination-cell-negative,
2439
2468
  .sw-denomination-row-signed .sw-denomination-cell-positive,
@@ -2620,3 +2649,23 @@ body {
2620
2649
  @media not all and (min-width: 48rem) {
2621
2650
  .sw-hide-below-md { display: none; }
2622
2651
  }
2652
+
2653
+ @media (prefers-reduced-transparency: reduce) {
2654
+ .sw-card-glass,
2655
+ .sw-app-header,
2656
+ .sw-badge-neutral,
2657
+ .sw-segmented,
2658
+ .sw-table-sticky thead th,
2659
+ .sw-denomination-strip .sw-denomination-label,
2660
+ .sw-denomination-strip thead .sw-denomination-corner:first-child,
2661
+ .sw-bar-chart-track,
2662
+ .sw-dialog,
2663
+ .sw-accordion,
2664
+ .sw-select-list,
2665
+ .sw-action-menu-list,
2666
+ .sw-toast {
2667
+ background: var(--sw-color-surface);
2668
+ backdrop-filter: none;
2669
+ -webkit-backdrop-filter: none;
2670
+ }
2671
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scalewing/react",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Scalewing DOM components and package-owned CSS utilities.",
5
5
  "type": "module",
6
6
  "license": "MIT",