@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.
- package/CHANGELOG.md +35 -0
- package/README.md +50 -5
- package/dist/components/DateField.js +3 -2
- package/dist/components/Field.js +3 -3
- package/dist/components/FieldLabelText.d.ts +13 -0
- package/dist/components/FieldLabelText.js +12 -0
- package/dist/components/RadioGroup.d.ts +7 -0
- package/dist/components/RadioGroup.js +1 -1
- package/dist/components/SegmentedControl.d.ts +8 -0
- package/dist/components/SegmentedControl.js +16 -11
- package/dist/components/Select.d.ts +13 -1
- package/dist/components/Select.js +4 -4
- package/dist/components/denomination-grid/DenominationTiles.js +20 -8
- package/dist/css/css-button.d.ts +1 -0
- package/dist/css/css-button.js +13 -4
- package/dist/css/css-components.js +6 -0
- package/dist/css/css-data.js +2 -165
- package/dist/css/css-date-field.js +12 -5
- package/dist/css/css-document.d.ts +2 -0
- package/dist/css/css-document.js +35 -0
- package/dist/css/css-field.js +12 -2
- package/dist/css/css-radio-group.js +9 -0
- package/dist/css/css-segmented.d.ts +2 -0
- package/dist/css/css-segmented.js +127 -0
- package/dist/css/css-select.js +33 -0
- package/dist/css/css-table.d.ts +2 -0
- package/dist/css/css-table.js +99 -0
- package/dist/css/stylesheet.js +4 -0
- package/dist/index.d.ts +1 -1
- package/dist/styles.css +136 -20
- package/package.json +1 -1
package/dist/css/css-data.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { buttonVariants,
|
|
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
|
-
|
|
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;
|
package/dist/css/css-document.js
CHANGED
|
@@ -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
|
}
|
package/dist/css/css-field.js
CHANGED
|
@@ -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,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
|
+
}
|
package/dist/css/css-select.js
CHANGED
|
@@ -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,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
|
+
}
|
package/dist/css/stylesheet.js
CHANGED
|
@@ -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';
|