@scalewing/react 1.12.0 → 1.14.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.
@@ -1,6 +1,4 @@
1
- import { buttonVariants, trackInset, typographyVariants, } from '@scalewing/tokens';
2
- import { scrollRegionRules } from './css-scroll-region.js';
3
- import { zIndex } from './stacking.js';
1
+ import { buttonVariants, typographyVariants } from '@scalewing/tokens';
4
2
  export const badgeTones = [
5
3
  'neutral',
6
4
  'accent',
@@ -10,8 +8,6 @@ export const badgeTones = [
10
8
  ];
11
9
  export const badgeSizes = ['sm', 'md'];
12
10
  const caption = typographyVariants.caption;
13
- const data = typographyVariants.data;
14
- const body = typographyVariants.body;
15
11
  export function badgeClassNames(tone, size = 'md') {
16
12
  return ['sw-badge', `sw-badge-${tone}`, `sw-badge-${size}`];
17
13
  }
@@ -83,171 +79,12 @@ export function cssDataClasses() {
83
79
  color: var(--sw-color-warning);
84
80
  }
85
81
 
86
- ${badgeOnFilledButtonRules()}
87
-
88
- .sw-segmented {
89
- background: var(--sw-glass-fill);
90
- border: 1px solid var(--sw-glass-border);
91
- border-radius: var(--sw-radius-pill);
92
- box-sizing: border-box;
93
- display: inline-flex;
94
- gap: ${trackInset}px;
95
- padding: ${trackInset}px;
96
- }
97
-
98
- .sw-segmented-item {
99
- appearance: none;
100
- background: transparent;
101
- border: 0;
102
- border-radius: var(--sw-radius-pill);
103
- color: var(--sw-color-muted);
104
- cursor: pointer;
105
- font-family: var(--sw-font-sans);
106
- font-size: ${data.fontSize}px;
107
- font-weight: 600;
108
- letter-spacing: ${data.letterSpacing}px;
109
- line-height: ${data.lineHeight}px;
110
- min-height: var(--sw-control-xs-min-height);
111
- padding-inline: var(--sw-control-xs-padding-inline);
112
- }
113
-
114
- .sw-segmented-item:focus-visible {
115
- outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
116
- outline-offset: var(--sw-focus-ring-offset);
117
- }
118
-
119
- .sw-segmented-item-selected {
120
- background: var(--sw-color-surface);
121
- color: var(--sw-color-text);
122
- }
123
-
124
- .sw-segmented-filled {
125
- display: grid;
126
- grid-auto-columns: minmax(0, 1fr);
127
- grid-auto-flow: column;
128
- }
129
-
130
- .sw-segmented-filled .sw-segmented-item {
131
- align-items: center;
132
- color: var(--sw-color-text);
133
- display: inline-flex;
134
- font-size: ${body.fontSize}px;
135
- justify-content: center;
136
- letter-spacing: ${body.letterSpacing}px;
137
- line-height: ${body.lineHeight}px;
138
- min-height: var(--sw-control-md-min-height);
139
- min-width: 0;
140
- padding-inline: var(--sw-control-md-padding-inline);
141
- }
142
-
143
- .sw-segmented-filled .sw-segmented-item-selected {
144
- background: var(--sw-color-accent);
145
- color: var(--sw-color-onAccent);
146
- }
147
-
148
- .sw-segmented-disabled {
149
- opacity: var(--sw-disabled-opacity);
150
- }
151
-
152
- .sw-segmented-item:disabled {
153
- cursor: not-allowed;
154
- }
155
-
156
- ${scrollRegionRules('.sw-table-wrap')}
157
-
158
- .sw-table {
159
- border-collapse: collapse;
160
- width: 100%;
161
- }
162
-
163
- .sw-table th,
164
- .sw-table td {
165
- border-bottom: 1px solid var(--sw-color-border);
166
- padding: var(--sw-space-2) var(--sw-space-3);
167
- text-align: start;
168
- vertical-align: middle;
169
- }
170
-
171
- .sw-table th {
172
- color: var(--sw-color-muted);
173
- font-family: var(--sw-font-sans);
174
- font-size: ${caption.fontSize}px;
175
- font-weight: 600;
176
- letter-spacing: ${caption.letterSpacing}px;
177
- line-height: ${caption.lineHeight}px;
178
- }
179
-
180
- /* Descendant form outranks .sw-table th / .sw-table td, which set text-align: start. */
181
- .sw-table .sw-table-end {
182
- text-align: end;
183
- }
184
-
185
- .sw-table .sw-table-numeric {
186
- font-variant-numeric: tabular-nums;
187
- text-align: end;
188
- }
189
-
190
- .sw-table-clip {
191
- max-width: 0;
192
- overflow: hidden;
193
- }
194
-
195
- .sw-table-sticky thead th {
196
- background: var(--sw-glass-fill);
197
- backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
198
- -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
199
- position: sticky;
200
- top: 0;
201
- ${zIndex('stickyCell')}
202
- }
203
-
204
- .sw-table-compact th,
205
- .sw-table-compact td {
206
- padding: var(--sw-space-1) var(--sw-space-2);
207
- }
208
-
209
- .sw-table-row-selected > :first-child {
210
- padding-inline-start: var(--sw-space-5);
211
- position: relative;
212
- }
213
-
214
- .sw-table-compact .sw-table-row-selected > :first-child {
215
- padding-inline-start: var(--sw-space-4);
216
- }
217
-
218
- .sw-table-row-selected > :first-child::before {
219
- background: var(--sw-color-accent);
220
- border-radius: var(--sw-radius-pill);
221
- content: '';
222
- height: var(--sw-space-2);
223
- inset-block-start: 50%;
224
- inset-inline-start: var(--sw-space-2);
225
- position: absolute;
226
- transform: translateY(-50%);
227
- width: var(--sw-space-2);
228
- }
229
-
230
- .sw-table-compact .sw-table-row-selected > :first-child::before {
231
- inset-inline-start: var(--sw-space-1);
232
- }`;
82
+ ${badgeOnFilledButtonRules()}`;
233
83
  }
234
84
  export function dataClassCatalog() {
235
85
  return [
236
86
  'sw-badge',
237
87
  ...badgeTones.map((tone) => `sw-badge-${tone}`),
238
88
  ...badgeSizes.map((size) => `sw-badge-${size}`),
239
- 'sw-segmented',
240
- 'sw-segmented-item',
241
- 'sw-segmented-item-selected',
242
- 'sw-segmented-filled',
243
- 'sw-segmented-disabled',
244
- 'sw-table-wrap',
245
- 'sw-table',
246
- 'sw-table-end',
247
- 'sw-table-numeric',
248
- 'sw-table-clip',
249
- 'sw-table-sticky',
250
- 'sw-table-compact',
251
- 'sw-table-row-selected',
252
89
  ];
253
90
  }
@@ -1,4 +1,5 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
+ import { disabledControlForcedColors, disabledControlSurface, } from './css-document.js';
2
3
  import { zIndex } from './stacking.js';
3
4
  const body = typographyVariants.body;
4
5
  const label = typographyVariants.label;
@@ -19,12 +20,11 @@ function fieldRules() {
19
20
  width: max-content;
20
21
  }
21
22
 
23
+ /* The label inherits the canvas's body type, as Field's does; the label
24
+ words inside it are a Text label span. The same line box gives the same
25
+ gap to the entry as a Field beside it. */
22
26
  .sw-date-field-label {
23
27
  color: var(--sw-color-text);
24
- font-family: var(--sw-font-sans);
25
- font-size: ${label.fontSize}px;
26
- font-weight: ${label.fontWeight};
27
- line-height: ${label.lineHeight}px;
28
28
  }
29
29
 
30
30
  .sw-date-field-control {
@@ -71,7 +71,11 @@ ${input}[aria-invalid='true'] {
71
71
  border-color: var(--sw-color-danger);
72
72
  }
73
73
 
74
- ${input}:disabled,
74
+ /* The entry looks locked as every text control does; its button fades as buttons do. */
75
+ ${input}:disabled {
76
+ ${disabledControlSurface}
77
+ }
78
+
75
79
  .sw-date-field-button:disabled {
76
80
  cursor: not-allowed;
77
81
  opacity: var(--sw-disabled-opacity);
@@ -270,6 +274,9 @@ function adaptiveRules() {
270
274
 
271
275
  @media (forced-colors: active) {
272
276
  ${input}[aria-invalid='true'] { border-color: CanvasText; }
277
+ ${input}:disabled {
278
+ ${disabledControlForcedColors}
279
+ }
273
280
  .sw-date-field-calendar { border-color: CanvasText; }
274
281
  .sw-date-field-day[aria-current='date'] { border-color: CanvasText; }
275
282
  .sw-date-field-day[aria-selected='true'] {
@@ -1,3 +1,5 @@
1
1
  /** The frame every native text control draws: fill, hairline border, radius. */
2
2
  export declare const controlSurface = "background-color: var(--sw-glass-fill);\n border: 1px solid var(--sw-color-border);\n border-radius: var(--sw-radius-sm);\n color: inherit;\n font-family: inherit;\n font-size: inherit;\n padding-inline: var(--sw-control-md-padding-inline);";
3
+ export declare const disabledControlSurface = "background-color: var(--sw-color-subtle);\n border-style: dashed;\n cursor: not-allowed;\n opacity: 1;\n -webkit-text-fill-color: currentColor;";
4
+ export declare const disabledControlForcedColors = "border-color: GrayText;\n color: GrayText;\n -webkit-text-fill-color: GrayText;";
3
5
  export declare function cssDocumentCanvas(): string;
@@ -18,6 +18,22 @@ export const controlSurface = `background-color: var(--sw-glass-fill);
18
18
  font-family: inherit;
19
19
  font-size: inherit;
20
20
  padding-inline: var(--sw-control-md-padding-inline);`;
21
+ /*
22
+ * A disabled text control keeps its value in the text color, so a locked
23
+ * value stays readable (4.5:1 or more on the subtle fill in every palette),
24
+ * and says it is locked with the quiet subtle fill and a dashed hairline
25
+ * instead of the opacity buttons use. WebKit fades a disabled entry's text
26
+ * with its own fill color and opacity, so both are set back.
27
+ */
28
+ export const disabledControlSurface = `background-color: var(--sw-color-subtle);
29
+ border-style: dashed;
30
+ cursor: not-allowed;
31
+ opacity: 1;
32
+ -webkit-text-fill-color: currentColor;`;
33
+ /* Forced colors keep the dashed border; the system's disabled color draws it. */
34
+ export const disabledControlForcedColors = `border-color: GrayText;
35
+ color: GrayText;
36
+ -webkit-text-fill-color: GrayText;`;
21
37
  export function cssDocumentCanvas() {
22
38
  return `html,
23
39
  body {
@@ -99,5 +115,24 @@ body {
99
115
  [data-theme] select:focus-visible {
100
116
  outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
101
117
  outline-offset: var(--sw-focus-ring-offset);
118
+ }
119
+
120
+ /* The browser's placeholder gray is one fixed #757575 (2.3:1 on a dark
121
+ field); muted is tuned per palette and scheme. */
122
+ [data-theme] :is(${typedInputs})::placeholder {
123
+ color: var(--sw-color-muted);
124
+ opacity: 1;
125
+ }
126
+
127
+ [data-theme] :is(${typedInputs}):disabled,
128
+ [data-theme] select:disabled {
129
+ ${disabledControlSurface}
130
+ }
131
+
132
+ @media (forced-colors: active) {
133
+ [data-theme] :is(${typedInputs}):disabled,
134
+ [data-theme] select:disabled {
135
+ ${disabledControlForcedColors}
136
+ }
102
137
  }`;
103
138
  }
@@ -1,5 +1,5 @@
1
1
  import { typographyVariants } from '@scalewing/tokens';
2
- import { controlSurface } from './css-document.js';
2
+ import { controlSurface, disabledControlForcedColors, disabledControlSurface, } from './css-document.js';
3
3
  const caption = typographyVariants.caption;
4
4
  /*
5
5
  * A prefix or suffix sits inside the control frame: the wrapper draws the
@@ -51,7 +51,14 @@ function adornmentRules() {
51
51
  padding-inline: var(--sw-control-xs-padding-inline);
52
52
  }
53
53
 
54
- .sw-field-invalid .sw-field-adorned { border-color: var(--sw-color-danger); }`;
54
+ .sw-field-invalid .sw-field-adorned { border-color: var(--sw-color-danger); }
55
+
56
+ /* The frame draws the surface, so it carries the disabled look for its input. */
57
+ .sw-field-adorned:has(> input:disabled) {
58
+ ${disabledControlSurface}
59
+ }
60
+
61
+ [data-theme] .sw-field-adorned > input:disabled { background: transparent; }`;
55
62
  }
56
63
  export function cssFieldClasses() {
57
64
  return `.sw-field-required { color: var(--sw-color-danger); }
@@ -79,6 +86,9 @@ ${adornmentRules()}
79
86
  [data-theme] .sw-field-invalid :is(input, select, textarea),
80
87
  .sw-field-invalid .sw-field-adorned { border-color: Mark; }
81
88
  .sw-field-prefix, .sw-field-suffix { color: CanvasText; }
89
+ .sw-field-adorned:has(> input:disabled) {
90
+ ${disabledControlForcedColors}
91
+ }
82
92
  .sw-field-error, .sw-field-required { color: Mark; }
83
93
  }`;
84
94
  }
@@ -101,6 +101,14 @@ export function cssRadioGroupClasses() {
101
101
  opacity: var(--sw-disabled-opacity);
102
102
  }
103
103
 
104
+ /* A consumer glyph beside the label, in the label's color and the option's gap. */
105
+ .sw-radio-group-icon {
106
+ align-items: center;
107
+ color: var(--sw-color-text);
108
+ display: inline-flex;
109
+ flex: none;
110
+ }
111
+
104
112
  .sw-radio-group-text {
105
113
  color: var(--sw-color-text);
106
114
  font-family: var(--sw-font-sans);
@@ -142,6 +150,7 @@ export function radioGroupClassCatalog() {
142
150
  'sw-radio-group-control',
143
151
  'sw-radio-group-input',
144
152
  'sw-radio-group-mark',
153
+ 'sw-radio-group-icon',
145
154
  'sw-radio-group-text',
146
155
  'sw-radio-group-description',
147
156
  'sw-radio-group-error',
@@ -0,0 +1,2 @@
1
+ export declare function cssSegmentedClasses(): string;
2
+ export declare function segmentedClassCatalog(): string[];
@@ -0,0 +1,127 @@
1
+ import { trackInset, typographyVariants } from '@scalewing/tokens';
2
+ const body = typographyVariants.body;
3
+ const data = typographyVariants.data;
4
+ /*
5
+ * The control and its error message. The wrapper takes the track's place in
6
+ * the layout: inline beside text and stretched in a Stack (compact), block
7
+ * wide and stretched (filled), and the track fills it. The message has
8
+ * inline-size containment, so its length never widens the field by itself;
9
+ * while it has text the field is at least 24ch wide, capped at its
10
+ * container (the percentage resolves against the Stack or Inline, not the
11
+ * field), so a short track does not squeeze the message into a column. In
12
+ * a Stack that changes nothing; in an Inline the field grows and the row
13
+ * moves, while the track keeps its labels' width.
14
+ */
15
+ function fieldRules() {
16
+ return `.sw-segmented-field {
17
+ display: inline-flex;
18
+ flex-direction: column;
19
+ gap: var(--sw-space-1);
20
+ }
21
+
22
+ .sw-segmented-field-filled {
23
+ display: flex;
24
+ }
25
+
26
+ .sw-segmented-field > .sw-field-error {
27
+ contain: inline-size;
28
+ }
29
+
30
+ .sw-segmented-field:has(> .sw-field-error:not(:empty)) {
31
+ min-inline-size: min(100%, 24ch);
32
+ }
33
+
34
+ .sw-inline > .sw-segmented-field > .sw-segmented {
35
+ align-self: flex-start;
36
+ }
37
+
38
+ .sw-segmented[aria-invalid='true'] {
39
+ border-color: var(--sw-color-danger);
40
+ }
41
+
42
+ @media (forced-colors: active) {
43
+ .sw-segmented[aria-invalid='true'] { border-color: Mark; }
44
+ }`;
45
+ }
46
+ export function cssSegmentedClasses() {
47
+ return `${fieldRules()}
48
+
49
+ .sw-segmented {
50
+ background: var(--sw-glass-fill);
51
+ border: 1px solid var(--sw-glass-border);
52
+ border-radius: var(--sw-radius-pill);
53
+ box-sizing: border-box;
54
+ display: inline-flex;
55
+ gap: ${trackInset}px;
56
+ padding: ${trackInset}px;
57
+ }
58
+
59
+ .sw-segmented-item {
60
+ appearance: none;
61
+ background: transparent;
62
+ border: 0;
63
+ border-radius: var(--sw-radius-pill);
64
+ color: var(--sw-color-muted);
65
+ cursor: pointer;
66
+ font-family: var(--sw-font-sans);
67
+ font-size: ${data.fontSize}px;
68
+ font-weight: 600;
69
+ letter-spacing: ${data.letterSpacing}px;
70
+ line-height: ${data.lineHeight}px;
71
+ min-height: var(--sw-control-xs-min-height);
72
+ padding-inline: var(--sw-control-xs-padding-inline);
73
+ }
74
+
75
+ .sw-segmented-item:focus-visible {
76
+ outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
77
+ outline-offset: var(--sw-focus-ring-offset);
78
+ }
79
+
80
+ .sw-segmented-item-selected {
81
+ background: var(--sw-color-surface);
82
+ color: var(--sw-color-text);
83
+ }
84
+
85
+ .sw-segmented-filled {
86
+ display: grid;
87
+ grid-auto-columns: minmax(0, 1fr);
88
+ grid-auto-flow: column;
89
+ }
90
+
91
+ .sw-segmented-filled .sw-segmented-item {
92
+ align-items: center;
93
+ color: var(--sw-color-text);
94
+ display: inline-flex;
95
+ font-size: ${body.fontSize}px;
96
+ justify-content: center;
97
+ letter-spacing: ${body.letterSpacing}px;
98
+ line-height: ${body.lineHeight}px;
99
+ min-height: var(--sw-control-md-min-height);
100
+ min-width: 0;
101
+ padding-inline: var(--sw-control-md-padding-inline);
102
+ }
103
+
104
+ .sw-segmented-filled .sw-segmented-item-selected {
105
+ background: var(--sw-color-accent);
106
+ color: var(--sw-color-onAccent);
107
+ }
108
+
109
+ .sw-segmented-disabled {
110
+ opacity: var(--sw-disabled-opacity);
111
+ }
112
+
113
+ .sw-segmented-item:disabled {
114
+ cursor: not-allowed;
115
+ }`;
116
+ }
117
+ export function segmentedClassCatalog() {
118
+ return [
119
+ 'sw-segmented-field',
120
+ 'sw-segmented-field-filled',
121
+ 'sw-segmented',
122
+ 'sw-segmented-item',
123
+ 'sw-segmented-item-selected',
124
+ 'sw-segmented-filled',
125
+ 'sw-segmented-disabled',
126
+ ];
127
+ }
@@ -9,6 +9,25 @@ export function cssSelectClasses() {
9
9
  width: max-content;
10
10
  }
11
11
 
12
+ /*
13
+ * width="full": the field and its trigger fill the container's inline size.
14
+ * The value still takes the free space and ellipsizes, and the chevron stays
15
+ * last, at the inline end. In an Inline row the field takes only the space
16
+ * its siblings leave, so a Button beside it keeps its label on one line.
17
+ */
18
+ .sw-select-full {
19
+ width: 100%;
20
+ }
21
+
22
+ .sw-inline > .sw-select-full {
23
+ flex: 1 1 0;
24
+ min-width: 0;
25
+ }
26
+
27
+ .sw-select-full .sw-select-trigger {
28
+ width: 100%;
29
+ }
30
+
12
31
  .sw-select-control {
13
32
  position: relative;
14
33
  }
@@ -125,6 +144,15 @@ export function cssSelectClasses() {
125
144
  ${zIndex('popup')}
126
145
  }
127
146
 
147
+ /*
148
+ * A full-width field's open list is exactly the trigger's width (min-width
149
+ * already beats the dialog-max cap), so it never runs past a phone's edge;
150
+ * a long option wraps inside it, even a single long word.
151
+ */
152
+ .sw-select-full .sw-select-list {
153
+ width: 100%;
154
+ }
155
+
128
156
  .sw-select-option {
129
157
  border-radius: var(--sw-radius-sm);
130
158
  box-sizing: border-box;
@@ -135,6 +163,10 @@ export function cssSelectClasses() {
135
163
  padding-inline: var(--sw-control-xs-padding-inline);
136
164
  }
137
165
 
166
+ .sw-select-full .sw-select-option {
167
+ overflow-wrap: anywhere;
168
+ }
169
+
138
170
  .sw-select-option[aria-selected='true'] {
139
171
  font-weight: ${label.fontWeight};
140
172
  }
@@ -159,6 +191,7 @@ export function selectClassCatalog() {
159
191
  return [
160
192
  'sw-select',
161
193
  'sw-select-xs',
194
+ 'sw-select-full',
162
195
  'sw-select-control',
163
196
  'sw-select-trigger',
164
197
  'sw-select-value',
@@ -0,0 +1,2 @@
1
+ export declare function cssTableClasses(): string;
2
+ export declare function tableClassCatalog(): string[];
@@ -0,0 +1,99 @@
1
+ import { typographyVariants } from '@scalewing/tokens';
2
+ import { scrollRegionRules } from './css-scroll-region.js';
3
+ import { zIndex } from './stacking.js';
4
+ const caption = typographyVariants.caption;
5
+ /*
6
+ * A selected row is marked by an accent bar at its inline start and nothing
7
+ * else: no fill, so text, muted text and accent text (ghost buttons, links)
8
+ * keep the contrast they have on the table's own surface. (A subtle tint
9
+ * dropped accent text under 4.5:1 in several palettes.) The bar is the first
10
+ * cell's ::before, absolutely placed in the cell's own padding, so it takes
11
+ * no layout space and no column moves when a row is picked. It is a border,
12
+ * not a fill, so forced colors keep it, drawn in the system highlight.
13
+ */
14
+ function selectedRowRules() {
15
+ return `.sw-table-row-selected > :first-child {
16
+ position: relative;
17
+ }
18
+
19
+ .sw-table-row-selected > :first-child::before {
20
+ border-inline-start: var(--sw-space-1) solid var(--sw-color-accent);
21
+ content: '';
22
+ inset-block: 0;
23
+ inset-inline-start: 0;
24
+ pointer-events: none;
25
+ position: absolute;
26
+ }
27
+
28
+ @media (forced-colors: active) {
29
+ .sw-table-row-selected > :first-child::before { border-color: Highlight; }
30
+ }`;
31
+ }
32
+ export function cssTableClasses() {
33
+ return `${scrollRegionRules('.sw-table-wrap')}
34
+
35
+ .sw-table {
36
+ border-collapse: collapse;
37
+ width: 100%;
38
+ }
39
+
40
+ .sw-table th,
41
+ .sw-table td {
42
+ border-bottom: 1px solid var(--sw-color-border);
43
+ padding: var(--sw-space-2) var(--sw-space-3);
44
+ text-align: start;
45
+ vertical-align: middle;
46
+ }
47
+
48
+ .sw-table th {
49
+ color: var(--sw-color-muted);
50
+ font-family: var(--sw-font-sans);
51
+ font-size: ${caption.fontSize}px;
52
+ font-weight: 600;
53
+ letter-spacing: ${caption.letterSpacing}px;
54
+ line-height: ${caption.lineHeight}px;
55
+ }
56
+
57
+ /* Descendant form outranks .sw-table th / .sw-table td, which set text-align: start. */
58
+ .sw-table .sw-table-end {
59
+ text-align: end;
60
+ }
61
+
62
+ .sw-table .sw-table-numeric {
63
+ font-variant-numeric: tabular-nums;
64
+ text-align: end;
65
+ }
66
+
67
+ .sw-table-clip {
68
+ max-width: 0;
69
+ overflow: hidden;
70
+ }
71
+
72
+ .sw-table-sticky thead th {
73
+ background: var(--sw-glass-fill);
74
+ backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
75
+ -webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
76
+ position: sticky;
77
+ top: 0;
78
+ ${zIndex('stickyCell')}
79
+ }
80
+
81
+ .sw-table-compact th,
82
+ .sw-table-compact td {
83
+ padding: var(--sw-space-1) var(--sw-space-2);
84
+ }
85
+
86
+ ${selectedRowRules()}`;
87
+ }
88
+ export function tableClassCatalog() {
89
+ return [
90
+ 'sw-table-wrap',
91
+ 'sw-table',
92
+ 'sw-table-end',
93
+ 'sw-table-numeric',
94
+ 'sw-table-clip',
95
+ 'sw-table-sticky',
96
+ 'sw-table-compact',
97
+ 'sw-table-row-selected',
98
+ ];
99
+ }
@@ -24,6 +24,8 @@ import { cssComponentClasses } from './css-components.js';
24
24
  import { buttonClassCatalog } from './css-button.js';
25
25
  import { chartClassCatalog } from './css-chart.js';
26
26
  import { dataClassCatalog } from './css-data.js';
27
+ import { segmentedClassCatalog } from './css-segmented.js';
28
+ import { tableClassCatalog } from './css-table.js';
27
29
  import { chromeClassCatalog } from './css-chrome.js';
28
30
  import { dialogClassCatalog } from './css-dialog.js';
29
31
  import { selectClassCatalog } from './css-select.js';
@@ -49,6 +51,8 @@ export function utilityClassCatalog() {
49
51
  ...Object.keys(typographyVariants).map((name) => `sw-text-${name}`),
50
52
  ...buttonClassCatalog(),
51
53
  ...dataClassCatalog(),
54
+ ...segmentedClassCatalog(),
55
+ ...tableClassCatalog(),
52
56
  ...chartClassCatalog(),
53
57
  ...chromeClassCatalog(),
54
58
  ...dialogClassCatalog(),
package/dist/index.d.ts CHANGED
@@ -29,7 +29,7 @@ export type { SplitProps } from './components/Split.js';
29
29
  export { Nav, type NavProps } from './components/Nav.js';
30
30
  export { SegmentedControl, type SegmentedControlProps, type SegmentedControlVariant, type SegmentedItem, } from './components/SegmentedControl.js';
31
31
  export { Select } from './components/Select.js';
32
- export type { SelectAction, SelectOption, SelectProps, } from './components/Select.js';
32
+ export type { SelectAction, SelectOption, SelectProps, SelectWidth, } from './components/Select.js';
33
33
  export { Stack, type Align, type Justify, type StackProps, } from './components/Stack.js';
34
34
  export { Table, TableBody, TableCell, TableHeader, TableRow, type TableBodyProps, type TableCellProps, type TableDensity, type TableHeaderProps, type TableProps, type TableRowProps, } from './components/Table.js';
35
35
  export { Text, type TextAlign, type TextElement, type TextProps, } from './components/Text.js';