@scalewing/react 1.40.0 → 1.41.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 +24 -0
- package/README.md +154 -6
- package/dist/calendar-labels.d.ts +2 -0
- package/dist/calendar-labels.js +7 -0
- package/dist/components/BarChart.d.ts +20 -4
- package/dist/components/BarChart.js +13 -6
- package/dist/components/ButtonGroup.d.ts +8 -1
- package/dist/components/ButtonGroup.js +11 -2
- package/dist/components/DateField.d.ts +14 -2
- package/dist/components/DateField.js +14 -11
- package/dist/components/DenominationGrid.d.ts +3 -2
- package/dist/components/DenominationGrid.js +21 -3
- package/dist/components/Dialog.d.ts +29 -13
- package/dist/components/Dialog.js +22 -20
- package/dist/components/Field.d.ts +13 -2
- package/dist/components/Field.js +14 -38
- package/dist/components/FilterChips.d.ts +7 -37
- package/dist/components/FilterChips.js +32 -24
- package/dist/components/ListRow.d.ts +11 -2
- package/dist/components/ListRow.js +3 -2
- package/dist/components/SegmentedControl.d.ts +17 -1
- package/dist/components/SegmentedControl.js +11 -3
- package/dist/components/Switch.d.ts +16 -1
- package/dist/components/Switch.js +17 -6
- package/dist/components/action-bar/ActionBarSummary.d.ts +10 -2
- package/dist/components/action-bar/ActionBarSummary.js +11 -2
- package/dist/components/date-field/CalendarEntryButton.d.ts +24 -0
- package/dist/components/date-field/CalendarEntryButton.js +16 -0
- package/dist/components/date-field/TypedEntry.d.ts +26 -0
- package/dist/components/date-field/TypedEntry.js +13 -0
- package/dist/components/denomination-grid/CountCell.d.ts +16 -0
- package/dist/components/denomination-grid/CountCell.js +14 -0
- package/dist/components/denomination-grid/DenominationStrip.d.ts +4 -1
- package/dist/components/denomination-grid/DenominationStrip.js +2 -2
- package/dist/components/denomination-grid/EntryCell.d.ts +3 -1
- package/dist/components/denomination-grid/EntryCell.js +2 -2
- package/dist/components/denomination-grid/StripRow.js +1 -10
- package/dist/components/denomination-grid/TransposedStrip.d.ts +17 -0
- package/dist/components/denomination-grid/TransposedStrip.js +43 -0
- package/dist/components/denomination-grid/types.d.ts +31 -0
- package/dist/components/denomination-grid/types.js +7 -1
- package/dist/components/denomination-grid/validate-options.d.ts +7 -0
- package/dist/components/denomination-grid/validate-options.js +27 -0
- package/dist/components/dialog/DialogFooter.d.ts +6 -5
- package/dist/components/dialog/DialogFooter.js +6 -6
- package/dist/components/dialog/validate.d.ts +24 -0
- package/dist/components/dialog/validate.js +23 -0
- package/dist/components/field/field-checks.d.ts +34 -0
- package/dist/components/field/field-checks.js +42 -0
- package/dist/components/filter-chips/FilterChip.d.ts +16 -0
- package/dist/components/filter-chips/FilterChip.js +20 -0
- package/dist/components/filter-chips/options.d.ts +75 -0
- package/dist/components/filter-chips/options.js +11 -0
- package/dist/components/filter-chips/validate.d.ts +9 -0
- package/dist/components/filter-chips/validate.js +48 -0
- package/dist/components/list/ListRowContent.d.ts +3 -1
- package/dist/components/list/ListRowContent.js +3 -2
- package/dist/css/chart-tones.d.ts +2 -0
- package/dist/css/chart-tones.js +5 -1
- package/dist/css/css-bar-chart.d.ts +17 -2
- package/dist/css/css-bar-chart.js +38 -7
- package/dist/css/css-button-group-attached.d.ts +3 -0
- package/dist/css/css-button-group-attached.js +18 -1
- package/dist/css/css-canvas-grouped.d.ts +17 -0
- package/dist/css/css-canvas-grouped.js +40 -0
- package/dist/css/css-components.js +6 -0
- package/dist/css/css-date-field-calendar-entry.d.ts +11 -0
- package/dist/css/css-date-field-calendar-entry.js +50 -0
- package/dist/css/css-date-field.js +4 -0
- package/dist/css/css-denomination-grid.js +4 -0
- package/dist/css/css-denomination-transposed.d.ts +4 -0
- package/dist/css/css-denomination-transposed.js +178 -0
- package/dist/css/css-dialog-canvas.d.ts +3 -0
- package/dist/css/css-dialog-canvas.js +20 -0
- package/dist/css/css-dialog-frame.js +19 -2
- package/dist/css/css-dialog-grabber.d.ts +4 -0
- package/dist/css/css-dialog-grabber.js +56 -0
- package/dist/css/css-dialog.js +3 -2
- package/dist/css/css-document.js +3 -0
- package/dist/css/css-field-width.d.ts +12 -0
- package/dist/css/css-field-width.js +49 -0
- package/dist/css/css-field.js +4 -0
- package/dist/css/css-filter-chips-layout.d.ts +2 -0
- package/dist/css/css-filter-chips-layout.js +42 -0
- package/dist/css/css-filter-chips.js +4 -0
- package/dist/css/css-list-row.d.ts +6 -0
- package/dist/css/css-list-row.js +19 -3
- package/dist/css/css-segmented-sizing.d.ts +13 -0
- package/dist/css/css-segmented-sizing.js +66 -0
- package/dist/css/css-segmented.js +4 -0
- package/dist/css/css-switch.d.ts +6 -0
- package/dist/css/css-switch.js +39 -0
- package/dist/css/stacking.d.ts +1 -0
- package/dist/css/stacking.js +4 -1
- package/dist/css/stylesheet.js +4 -0
- package/dist/date-field-labels.d.ts +5 -0
- package/dist/date-field-labels.js +1 -0
- package/dist/index.d.ts +10 -8
- package/dist/index.js +8 -6
- package/dist/list-options.d.ts +8 -7
- package/dist/list-options.js +15 -8
- package/dist/styles.css +343 -2
- package/dist/theme/ThemeProvider.d.ts +11 -1
- package/dist/theme/ThemeProvider.js +4 -2
- package/package.json +1 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DateField's calendar entry: one neutral Button showing the chosen day (or
|
|
3
|
+
* the words that ask for one) after the calendar glyph, shaped as a field's
|
|
4
|
+
* control rather than a pill, sized to its words on one line at the
|
|
5
|
+
* column's start, the danger edge while the field is invalid.
|
|
6
|
+
*/
|
|
7
|
+
export const dateFieldEntries = ['typed', 'calendar'];
|
|
8
|
+
export function assertDateFieldEntry(entry) {
|
|
9
|
+
if (!dateFieldEntries.includes(entry))
|
|
10
|
+
throw new RangeError(`Unknown DateField entry: ${String(entry)}`);
|
|
11
|
+
}
|
|
12
|
+
const entry = '.sw-button.sw-date-field-calendar-entry';
|
|
13
|
+
export function cssDateFieldCalendarEntryClasses() {
|
|
14
|
+
return `${entry} {
|
|
15
|
+
align-self: flex-start;
|
|
16
|
+
border-radius: var(--sw-radius-sm);
|
|
17
|
+
flex: none;
|
|
18
|
+
justify-content: flex-start;
|
|
19
|
+
max-width: 100%;
|
|
20
|
+
text-align: start;
|
|
21
|
+
white-space: nowrap;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* A long day or word in a narrow column ends in an ellipsis; the name keeps it whole. */
|
|
25
|
+
.sw-date-field-calendar-entry-text {
|
|
26
|
+
min-width: 0;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
text-overflow: ellipsis;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
${entry} .sw-date-field-glyph {
|
|
32
|
+
height: var(--sw-space-4);
|
|
33
|
+
width: var(--sw-space-4);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
${entry}.sw-date-field-calendar-entry-invalid {
|
|
37
|
+
border-color: var(--sw-color-danger);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@media (forced-colors: active) {
|
|
41
|
+
${entry}.sw-date-field-calendar-entry-invalid { border-color: Mark; }
|
|
42
|
+
}`;
|
|
43
|
+
}
|
|
44
|
+
export function dateFieldCalendarEntryClassCatalog() {
|
|
45
|
+
return [
|
|
46
|
+
'sw-date-field-calendar-entry',
|
|
47
|
+
'sw-date-field-calendar-entry-text',
|
|
48
|
+
'sw-date-field-calendar-entry-invalid',
|
|
49
|
+
];
|
|
50
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { disabledControlForcedColors, disabledControlSurface, } from './css-document.js';
|
|
3
|
+
import { cssDateFieldCalendarEntryClasses, dateFieldCalendarEntryClassCatalog, } from './css-date-field-calendar-entry.js';
|
|
3
4
|
import { zIndex } from './stacking.js';
|
|
4
5
|
import { quietFill } from './quiet-fill.js';
|
|
5
6
|
import { rangeBand, rangeBandHover } from './range-band.js';
|
|
@@ -334,12 +335,15 @@ function adaptiveRules() {
|
|
|
334
335
|
export function cssDateFieldClasses() {
|
|
335
336
|
return `${fieldRules()}
|
|
336
337
|
|
|
338
|
+
${cssDateFieldCalendarEntryClasses()}
|
|
339
|
+
|
|
337
340
|
${calendarRules()}
|
|
338
341
|
|
|
339
342
|
${adaptiveRules()}`;
|
|
340
343
|
}
|
|
341
344
|
export function dateFieldClassCatalog() {
|
|
342
345
|
return [
|
|
346
|
+
...dateFieldCalendarEntryClassCatalog(),
|
|
343
347
|
'sw-date-field',
|
|
344
348
|
'sw-date-field-label',
|
|
345
349
|
'sw-date-field-control',
|
|
@@ -6,6 +6,7 @@ import { cssDenominationLabelClasses, denominationLabelClassCatalog, } from './c
|
|
|
6
6
|
import { cssDenominationAlignedClasses, denominationAlignedClassCatalog, } from './css-denomination-aligned.js';
|
|
7
7
|
import { cssDenominationEntryClasses, denominationEntryClassCatalog, } from './css-denomination-entry.js';
|
|
8
8
|
import { cssDenominationValueRowClasses, denominationValueRowClassCatalog, } from './css-denomination-value-row.js';
|
|
9
|
+
import { cssDenominationTransposedClasses, denominationTransposedClassCatalog, } from './css-denomination-transposed.js';
|
|
9
10
|
import { cssDenominationCellToneClasses, denominationCellToneClassCatalog, } from './css-denomination-cell-tones.js';
|
|
10
11
|
import { pinnedStartShadeRules, scrollRegionRules, } from './css-scroll-region.js';
|
|
11
12
|
import { visuallyHiddenDeclarations } from './css-utilities.js';
|
|
@@ -263,6 +264,8 @@ ${cssDenominationAppearanceClasses()}
|
|
|
263
264
|
|
|
264
265
|
${cssDenominationValueRowClasses()}
|
|
265
266
|
|
|
267
|
+
${cssDenominationTransposedClasses()}
|
|
268
|
+
|
|
266
269
|
@media (forced-colors: active) {
|
|
267
270
|
.sw-denomination-label { border-inline-start-color: CanvasText; color: CanvasText; }
|
|
268
271
|
.sw-denomination-strip .sw-denomination-label::before { background: CanvasText; forced-color-adjust: none; }
|
|
@@ -307,5 +310,6 @@ export function denominationGridClassCatalog() {
|
|
|
307
310
|
...denominationLabelClassCatalog(),
|
|
308
311
|
...denominationAppearanceClassCatalog(),
|
|
309
312
|
...denominationValueRowClassCatalog(),
|
|
313
|
+
...denominationTransposedClassCatalog(),
|
|
310
314
|
];
|
|
311
315
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** A grid whose entry counts keep room for `--sw-denomination-count-digits` digits. */
|
|
2
|
+
export declare const denominationCountDigitsClass = "sw-denomination-count-digits";
|
|
3
|
+
export declare function cssDenominationTransposedClasses(): string;
|
|
4
|
+
export declare function denominationTransposedClassCatalog(): string[];
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { pinnedStartShadeRules } from './css-scroll-region.js';
|
|
3
|
+
import { zIndex } from './stacking.js';
|
|
4
|
+
const body = typographyVariants.body;
|
|
5
|
+
const data = typographyVariants.data;
|
|
6
|
+
const label = typographyVariants.label;
|
|
7
|
+
/** A grid whose entry counts keep room for `--sw-denomination-count-digits` digits. */
|
|
8
|
+
export const denominationCountDigitsClass = 'sw-denomination-count-digits';
|
|
9
|
+
const transposed = '.sw-denomination-transposed';
|
|
10
|
+
/*
|
|
11
|
+
* A transposed strip, for a phone: a row per denomination under a
|
|
12
|
+
* hairline, each grid row's head on one line (the region scrolls rather
|
|
13
|
+
* than break a head word by word), the denomination column pinned with the
|
|
14
|
+
* strip's start shade,
|
|
15
|
+
* its label in the text colour at label size, then each grid row's counts
|
|
16
|
+
* (end-aligned, centred over steppers as in the strip) and its value line on
|
|
17
|
+
* the subtle fill, centred; the totals in a last row in each row's tone. A
|
|
18
|
+
* quiet grid row's heads and cells take the subtle fill; a disabled one's
|
|
19
|
+
* heads, read-only counts (toned ones too), values and total fade, its
|
|
20
|
+
* steppers disabled by the Stepper.
|
|
21
|
+
*/
|
|
22
|
+
function transposedRules() {
|
|
23
|
+
return `${transposed} {
|
|
24
|
+
border-collapse: collapse;
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
${transposed} th,
|
|
29
|
+
${transposed} td {
|
|
30
|
+
padding: var(--sw-space-1) var(--sw-space-2);
|
|
31
|
+
vertical-align: middle;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
${transposed} tbody tr,
|
|
35
|
+
${transposed} tfoot tr {
|
|
36
|
+
border-top: 1px solid var(--sw-color-border);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
${transposed} .sw-denomination-transposed-head {
|
|
40
|
+
vertical-align: bottom;
|
|
41
|
+
white-space: nowrap;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
${transposed} .sw-denomination-label-line {
|
|
45
|
+
justify-content: flex-end;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.sw-denomination-transposed-label {
|
|
49
|
+
color: var(--sw-color-text);
|
|
50
|
+
font-size: ${label.fontSize}px;
|
|
51
|
+
font-weight: ${label.fontWeight};
|
|
52
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
53
|
+
line-height: ${label.lineHeight}px;
|
|
54
|
+
text-align: start;
|
|
55
|
+
white-space: nowrap;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
${transposed} td.sw-denomination-entry {
|
|
59
|
+
padding: var(--sw-space-1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.sw-denomination-transposed-entry .sw-denomination-transposed-head,
|
|
63
|
+
.sw-denomination-transposed-entry .sw-denomination-cell {
|
|
64
|
+
text-align: center;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.sw-denomination-transposed-entry .sw-denomination-label-line {
|
|
68
|
+
justify-content: center;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.sw-denomination-transposed-value {
|
|
72
|
+
background: var(--sw-color-subtle);
|
|
73
|
+
font-size: ${label.fontSize}px;
|
|
74
|
+
font-variant-numeric: tabular-nums;
|
|
75
|
+
font-weight: ${data.fontWeight};
|
|
76
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
77
|
+
line-height: ${label.lineHeight}px;
|
|
78
|
+
text-align: center;
|
|
79
|
+
white-space: nowrap;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.sw-denomination-transposed-total {
|
|
83
|
+
color: var(--sw-denomination-tone);
|
|
84
|
+
font-size: ${data.fontSize}px;
|
|
85
|
+
font-variant-numeric: tabular-nums;
|
|
86
|
+
font-weight: 600;
|
|
87
|
+
letter-spacing: ${data.letterSpacing}px;
|
|
88
|
+
line-height: ${data.lineHeight}px;
|
|
89
|
+
text-align: end;
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.sw-denomination-transposed-entry .sw-denomination-transposed-total {
|
|
94
|
+
text-align: center;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* The denomination column and its corner stay in view, as the strip's labels do. */
|
|
98
|
+
${transposed} .sw-denomination-transposed-label,
|
|
99
|
+
${transposed} :is(thead, tfoot) .sw-denomination-corner:first-child {
|
|
100
|
+
background: var(--sw-glass-fill);
|
|
101
|
+
backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
102
|
+
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
103
|
+
inset-inline-start: 0;
|
|
104
|
+
position: sticky;
|
|
105
|
+
${zIndex('stickyCell')}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
${pinnedStartShadeRules('.sw-denomination-scroll-transposed', [
|
|
109
|
+
'.sw-denomination-transposed-label',
|
|
110
|
+
])}
|
|
111
|
+
|
|
112
|
+
.sw-denomination-transposed-quiet {
|
|
113
|
+
background: var(--sw-color-subtle);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* Over a toned count's full strength (three classes, emitted later). */
|
|
117
|
+
.sw-denomination-grid${transposed} .sw-denomination-transposed-disabled:is(.sw-denomination-cell, .sw-denomination-transposed-value, .sw-denomination-transposed-total, .sw-denomination-transposed-head) {
|
|
118
|
+
opacity: var(--sw-disabled-opacity);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@media (forced-colors: active) {
|
|
122
|
+
.sw-denomination-transposed-value,
|
|
123
|
+
.sw-denomination-transposed-quiet { background: Canvas; }
|
|
124
|
+
.sw-denomination-transposed-label,
|
|
125
|
+
.sw-denomination-transposed-value,
|
|
126
|
+
.sw-denomination-transposed-total { color: CanvasText; }
|
|
127
|
+
}`;
|
|
128
|
+
}
|
|
129
|
+
/*
|
|
130
|
+
* The count's last options. A signed count's success colour reads from the
|
|
131
|
+
* cell too, so a transposed column (no row element) keeps it; a plain
|
|
132
|
+
* negative count is the text colour (cash out by design, never red). An
|
|
133
|
+
* entry count with room for more digits sets its track in the input's own
|
|
134
|
+
* type, so a digit's width (1ch) there is the input's, and keeps that many
|
|
135
|
+
* digits, its padding and its two hairlines before the strip scrolls.
|
|
136
|
+
*/
|
|
137
|
+
function countRules() {
|
|
138
|
+
return `.sw-denomination-cell-signed.sw-denomination-cell-positive {
|
|
139
|
+
color: var(--sw-color-success);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.sw-denomination-cell-negative.sw-denomination-cell-plain {
|
|
143
|
+
color: var(--sw-color-text);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.${denominationCountDigitsClass} .sw-denomination-entry .sw-stepper-full .sw-stepper-track {
|
|
147
|
+
font-size: ${body.fontSize}px;
|
|
148
|
+
font-variant-numeric: tabular-nums;
|
|
149
|
+
font-weight: ${label.fontWeight};
|
|
150
|
+
grid-template-columns: var(--sw-space-6) minmax(calc(var(--sw-denomination-count-digits) * 1ch + 2 * var(--sw-space-1) + 2px), 1fr) var(--sw-space-6);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@media (forced-colors: active) {
|
|
154
|
+
.sw-denomination-cell-signed.sw-denomination-cell-positive,
|
|
155
|
+
.sw-denomination-cell-negative.sw-denomination-cell-plain { color: CanvasText; }
|
|
156
|
+
}`;
|
|
157
|
+
}
|
|
158
|
+
export function cssDenominationTransposedClasses() {
|
|
159
|
+
return `${transposedRules()}
|
|
160
|
+
|
|
161
|
+
${countRules()}`;
|
|
162
|
+
}
|
|
163
|
+
export function denominationTransposedClassCatalog() {
|
|
164
|
+
return [
|
|
165
|
+
'sw-denomination-transposed',
|
|
166
|
+
'sw-denomination-transposed-entry',
|
|
167
|
+
'sw-denomination-scroll-transposed',
|
|
168
|
+
'sw-denomination-transposed-head',
|
|
169
|
+
'sw-denomination-transposed-label',
|
|
170
|
+
'sw-denomination-transposed-value',
|
|
171
|
+
'sw-denomination-transposed-total',
|
|
172
|
+
'sw-denomination-transposed-quiet',
|
|
173
|
+
'sw-denomination-transposed-disabled',
|
|
174
|
+
'sw-denomination-cell-signed',
|
|
175
|
+
'sw-denomination-cell-plain',
|
|
176
|
+
denominationCountDigitsClass,
|
|
177
|
+
];
|
|
178
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { groupedCanvasFill } from './css-canvas-grouped.js';
|
|
2
|
+
export const dialogCanvasClass = 'sw-dialog-canvas-grouped';
|
|
3
|
+
/*
|
|
4
|
+
* A dialog on the grouped canvas: its fill is the grouped canvas grey, solid
|
|
5
|
+
* with no blur, so Cards inside it stand apart as they do on a grouped page.
|
|
6
|
+
* The selector carries two classes so it wins over the glass and banded
|
|
7
|
+
* fills at any order. A banded title row and the pinned footer keep their
|
|
8
|
+
* own surface, so they stay bands over the grey. Forced colours paint the
|
|
9
|
+
* system canvas as they do any dialog.
|
|
10
|
+
*/
|
|
11
|
+
export function cssDialogCanvasClasses() {
|
|
12
|
+
return `.sw-dialog.${dialogCanvasClass} {
|
|
13
|
+
backdrop-filter: none;
|
|
14
|
+
-webkit-backdrop-filter: none;
|
|
15
|
+
background: ${groupedCanvasFill};
|
|
16
|
+
}`;
|
|
17
|
+
}
|
|
18
|
+
export function dialogCanvasClassCatalog() {
|
|
19
|
+
return [dialogCanvasClass];
|
|
20
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
const caption = typographyVariants.caption;
|
|
1
3
|
/*
|
|
2
4
|
* The dialog's frame beyond its title: a consumer icon before the title, a
|
|
3
5
|
* muted description under it, and a footer pinned to the bottom edge.
|
|
@@ -42,13 +44,27 @@ export function cssDialogFrameClasses() {
|
|
|
42
44
|
|
|
43
45
|
.sw-dialog-footer-status {
|
|
44
46
|
align-items: center;
|
|
47
|
+
column-gap: var(--sw-space-2);
|
|
45
48
|
display: flex;
|
|
46
49
|
flex: 1 1 auto;
|
|
50
|
+
flex-wrap: wrap;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* The status line: muted caption words beside the actions. Its children
|
|
55
|
+
sit on one row and wrap as one phrase. */
|
|
56
|
+
.sw-dialog-footer-note {
|
|
57
|
+
color: var(--sw-color-muted);
|
|
58
|
+
font-family: var(--sw-font-sans);
|
|
59
|
+
font-size: ${caption.fontSize}px;
|
|
60
|
+
line-height: ${caption.lineHeight}px;
|
|
47
61
|
min-width: 0;
|
|
62
|
+
overflow-wrap: anywhere;
|
|
48
63
|
}
|
|
49
64
|
|
|
50
|
-
/* With no
|
|
51
|
-
is still announced, but it takes no room in
|
|
65
|
+
/* With no figure and no status line the live region stays in the
|
|
66
|
+
dialog, so a first figure is still announced, but it takes no room in
|
|
67
|
+
the footer. */
|
|
52
68
|
.sw-dialog-footer-status:empty {
|
|
53
69
|
clip-path: inset(50%);
|
|
54
70
|
height: 1px;
|
|
@@ -78,6 +94,7 @@ export function dialogFrameClassCatalog() {
|
|
|
78
94
|
'sw-dialog-description',
|
|
79
95
|
'sw-dialog-footer',
|
|
80
96
|
'sw-dialog-footer-status',
|
|
97
|
+
'sw-dialog-footer-note',
|
|
81
98
|
'sw-dialog-footer-actions',
|
|
82
99
|
];
|
|
83
100
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { breakpointQuery, breakpoints } from './breakpoints.js';
|
|
2
|
+
import { dialogSheetClass } from './css-dialog.js';
|
|
3
|
+
import { dialogBandedClass } from './css-dialog-banded.js';
|
|
4
|
+
import { zIndex } from './stacking.js';
|
|
5
|
+
export const dialogGrabberClass = 'sw-dialog-grabber';
|
|
6
|
+
export const dialogHasGrabberClass = 'sw-dialog-has-grabber';
|
|
7
|
+
/* How far the grabber sits from the sheet's top edge. */
|
|
8
|
+
const inset = 'var(--sw-space-2)';
|
|
9
|
+
/*
|
|
10
|
+
* A bottom sheet's grabber: a space-6 by space-1 bar on the muted colour at
|
|
11
|
+
* 40 %, centered a space-2 step under the top edge. Its margins add up to
|
|
12
|
+
* nothing (up into the dialog's space-5 padding to the space-2 inset, its
|
|
13
|
+
* space-1 height, then a space-3 step down), so the title keeps its place
|
|
14
|
+
* a space-3 under the bar. It is sticky at that inset while the content
|
|
15
|
+
* scrolls (sticky insets count from the padding edge, so it steps back
|
|
16
|
+
* past the space-5 padding) and sits over a banded title band, whose top padding grows to space-5 to keep the space-3
|
|
17
|
+
* step under the bar. Drawn only below the sheet's breakpoint; forced colours
|
|
18
|
+
* draw it in the text colour (inside the same breakpoint, at the same
|
|
19
|
+
* specificity, so the override wins).
|
|
20
|
+
*/
|
|
21
|
+
function sheetGrabberRules() {
|
|
22
|
+
return breakpoints
|
|
23
|
+
.map((breakpoint) => {
|
|
24
|
+
const sheet = `.${dialogSheetClass(breakpoint)}`;
|
|
25
|
+
return `@media ${breakpointQuery('below', breakpoint)} {
|
|
26
|
+
${sheet} .${dialogGrabberClass} {
|
|
27
|
+
background: color-mix(in srgb, var(--sw-color-muted) 40%, transparent);
|
|
28
|
+
border-radius: var(--sw-radius-pill);
|
|
29
|
+
display: block;
|
|
30
|
+
height: var(--sw-space-1);
|
|
31
|
+
margin: calc(${inset} - var(--sw-space-5)) auto var(--sw-space-3);
|
|
32
|
+
position: sticky;
|
|
33
|
+
top: calc(${inset} - var(--sw-space-5));
|
|
34
|
+
width: var(--sw-space-6);
|
|
35
|
+
${zIndex('sheetGrabber')}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
${sheet}.${dialogBandedClass}.${dialogHasGrabberClass} .sw-dialog-header {
|
|
39
|
+
padding-top: var(--sw-space-5);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@media (forced-colors: active) {
|
|
43
|
+
${sheet} .${dialogGrabberClass} { background: CanvasText; forced-color-adjust: none; }
|
|
44
|
+
}
|
|
45
|
+
}`;
|
|
46
|
+
})
|
|
47
|
+
.join('\n\n');
|
|
48
|
+
}
|
|
49
|
+
export function cssDialogGrabberClasses() {
|
|
50
|
+
return `.${dialogGrabberClass} { display: none; }
|
|
51
|
+
|
|
52
|
+
${sheetGrabberRules()}`;
|
|
53
|
+
}
|
|
54
|
+
export function dialogGrabberClassCatalog() {
|
|
55
|
+
return [dialogGrabberClass, dialogHasGrabberClass];
|
|
56
|
+
}
|
package/dist/css/css-dialog.js
CHANGED
|
@@ -16,8 +16,9 @@ export function dialogSheetClass(sheetBelow) {
|
|
|
16
16
|
* shows above it), and padding that clears the safe areas. A pinned
|
|
17
17
|
* footer steps past that padding so its surface reaches the bottom edge,
|
|
18
18
|
* and pads itself clear of the home indicator. Emitted after
|
|
19
|
-
* `sw-dialog-lg` and `sw-dialog-xl` so it wins at equal specificity.
|
|
20
|
-
* grabber
|
|
19
|
+
* `sw-dialog-lg` and `sw-dialog-xl` so it wins at equal specificity. A
|
|
20
|
+
* grabber is opt-in (css-dialog-grabber.ts) and marks the sheet only: there
|
|
21
|
+
* is no drag gesture.
|
|
21
22
|
*/
|
|
22
23
|
function sheetRules() {
|
|
23
24
|
return breakpoints
|
package/dist/css/css-document.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { cssBoxLinkClasses } from './css-box-link.js';
|
|
3
|
+
import { cssCanvasGroupedRules } from './css-canvas-grouped.js';
|
|
3
4
|
const body = typographyVariants.body;
|
|
4
5
|
/** The native controls that take typed text: the canvas's text controls. */
|
|
5
6
|
export const typedInputs = [
|
|
@@ -84,6 +85,8 @@ body {
|
|
|
84
85
|
color-scheme: dark;
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
${cssCanvasGroupedRules()}
|
|
89
|
+
|
|
87
90
|
[data-theme] a {
|
|
88
91
|
color: var(--sw-color-accent);
|
|
89
92
|
text-decoration: none;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type TableColumnSize } from './css-table-layout.js';
|
|
2
|
+
/**
|
|
3
|
+
* The widths a field's control can be capped at: the Table column sizes
|
|
4
|
+
* (`xs` 4rem to `xl` 16rem), so a short value such as a rate or a count
|
|
5
|
+
* sits in a box its own size instead of across the form's column.
|
|
6
|
+
*/
|
|
7
|
+
export type FieldWidth = TableColumnSize;
|
|
8
|
+
export declare const fieldWidths: FieldWidth[];
|
|
9
|
+
export declare function fieldWidthClass(width: FieldWidth): string;
|
|
10
|
+
export declare function assertFieldWidth(width: unknown): void;
|
|
11
|
+
export declare function cssFieldWidthClasses(): string;
|
|
12
|
+
export declare function fieldWidthClassCatalog(): string[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { typedInputs } from './css-document.js';
|
|
2
|
+
import { tableColumnSizes } from './css-table-layout.js';
|
|
3
|
+
export const fieldWidths = Object.keys(tableColumnSizes);
|
|
4
|
+
export function fieldWidthClass(width) {
|
|
5
|
+
return `sw-field-width-${width}`;
|
|
6
|
+
}
|
|
7
|
+
export function assertFieldWidth(width) {
|
|
8
|
+
if (width !== undefined && !fieldWidths.includes(width))
|
|
9
|
+
throw new RangeError(`Unknown Field width: ${String(width)}`);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The field's own control: a native text control or select, or the frame
|
|
13
|
+
* round an adorned or search input. A checkbox, radio, range, colour or
|
|
14
|
+
* file input keeps its own size.
|
|
15
|
+
*/
|
|
16
|
+
const control = `:is(${typedInputs}, select, .sw-field-adorned, .sw-field-search)`;
|
|
17
|
+
/*
|
|
18
|
+
* A sized field keeps its label, description and error at the column's
|
|
19
|
+
* width and caps only its control, at the start of the column, never wider
|
|
20
|
+
* than the column on a narrow screen. Every capped control measures its
|
|
21
|
+
* border box, and a resized textarea stays inside the column. A select
|
|
22
|
+
* is a content box in the canvas (its height leaves out its two
|
|
23
|
+
* hairlines), so a sized one states the whole control height instead, at
|
|
24
|
+
* md or xs.
|
|
25
|
+
*/
|
|
26
|
+
export function cssFieldWidthClasses() {
|
|
27
|
+
const widths = Object.entries(tableColumnSizes)
|
|
28
|
+
.map(([size, rem]) => `.${fieldWidthClass(size)} { --sw-field-width: ${rem}rem; }`)
|
|
29
|
+
.join('\n');
|
|
30
|
+
return `${widths}
|
|
31
|
+
|
|
32
|
+
.sw-field-sized > ${control} {
|
|
33
|
+
align-self: flex-start;
|
|
34
|
+
box-sizing: border-box;
|
|
35
|
+
inline-size: min(100%, var(--sw-field-width));
|
|
36
|
+
max-inline-size: 100%;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-theme] .sw-field-sized > select {
|
|
40
|
+
height: var(--sw-control-md-min-height);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
[data-theme] .sw-field-xs.sw-field-sized > select {
|
|
44
|
+
height: var(--sw-control-xs-min-height);
|
|
45
|
+
}`;
|
|
46
|
+
}
|
|
47
|
+
export function fieldWidthClassCatalog() {
|
|
48
|
+
return ['sw-field-sized', ...fieldWidths.map(fieldWidthClass)];
|
|
49
|
+
}
|
package/dist/css/css-field.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { controlSurface, disabledControlForcedColors, disabledControlSurface, } from './css-document.js';
|
|
3
3
|
import { cssFieldChangedClasses } from './css-field-changed.js';
|
|
4
|
+
import { cssFieldWidthClasses, fieldWidthClassCatalog, } from './css-field-width.js';
|
|
4
5
|
import { cssFieldSearchClasses, fieldSearchClassCatalog, } from './css-field-search.js';
|
|
5
6
|
const caption = typographyVariants.caption;
|
|
6
7
|
/*
|
|
@@ -88,6 +89,8 @@ ${cssFieldSearchClasses()}
|
|
|
88
89
|
|
|
89
90
|
${cssFieldChangedClasses()}
|
|
90
91
|
|
|
92
|
+
${cssFieldWidthClasses()}
|
|
93
|
+
|
|
91
94
|
@media (forced-colors: active) {
|
|
92
95
|
[data-theme] .sw-field-invalid :is(input, select, textarea),
|
|
93
96
|
.sw-field-invalid .sw-field-adorned { border-color: Mark; }
|
|
@@ -110,5 +113,6 @@ export function fieldClassCatalog() {
|
|
|
110
113
|
'sw-field-prefix',
|
|
111
114
|
'sw-field-suffix',
|
|
112
115
|
...fieldSearchClassCatalog(),
|
|
116
|
+
...fieldWidthClassCatalog(),
|
|
113
117
|
];
|
|
114
118
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The chips' opt-in layouts.
|
|
3
|
+
*
|
|
4
|
+
* An inline count is set in the chip's own words, at tabular figures, after
|
|
5
|
+
* a middle dot ("Open · 3"); a chosen chip keeps it in its own ink.
|
|
6
|
+
*
|
|
7
|
+
* Chips that scroll keep one row and scroll sideways inside their own box
|
|
8
|
+
* (never the page) when they do not fit, each chip at its words' width on
|
|
9
|
+
* one line (no wrapping, which overrides the wrapping row's
|
|
10
|
+
* `overflow-wrap: anywhere`). The box is padded by the focus ring's reach and pulled back by
|
|
11
|
+
* the same amount, so a focused chip's ring is not clipped and the chips
|
|
12
|
+
* stay where a wrapped row puts them. A focused chip past the edge is
|
|
13
|
+
* scrolled into view by the browser. The scrollbar stays, thin, so a
|
|
14
|
+
* pointer without a sideways wheel can still reach the last chip.
|
|
15
|
+
*/
|
|
16
|
+
const ringReach = 'calc(var(--sw-focus-ring-width) + var(--sw-focus-ring-offset))';
|
|
17
|
+
export function cssFilterChipsLayoutClasses() {
|
|
18
|
+
return `.sw-filter-chip-count-inline {
|
|
19
|
+
font-variant-numeric: tabular-nums;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.sw-filter-chips-scroll .sw-filter-chips-options {
|
|
23
|
+
flex-wrap: nowrap;
|
|
24
|
+
margin: calc(-1 * ${ringReach});
|
|
25
|
+
overflow-x: auto;
|
|
26
|
+
overscroll-behavior-x: contain;
|
|
27
|
+
padding: ${ringReach};
|
|
28
|
+
scrollbar-width: thin;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.sw-filter-chips-scroll .sw-filter-chip {
|
|
32
|
+
flex: none;
|
|
33
|
+
max-width: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.sw-filter-chips-scroll .sw-filter-chip-face {
|
|
37
|
+
white-space: nowrap;
|
|
38
|
+
}`;
|
|
39
|
+
}
|
|
40
|
+
export function filterChipsLayoutClassCatalog() {
|
|
41
|
+
return ['sw-filter-chip-count-inline', 'sw-filter-chips-scroll'];
|
|
42
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { cssFilterChipsLayoutClasses, filterChipsLayoutClassCatalog, } from './css-filter-chips-layout.js';
|
|
2
3
|
const label = typographyVariants.label;
|
|
3
4
|
const data = typographyVariants.data;
|
|
4
5
|
const caption = typographyVariants.caption;
|
|
@@ -123,6 +124,8 @@ export function cssFilterChipsClasses() {
|
|
|
123
124
|
border-color: var(--sw-color-danger);
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
${cssFilterChipsLayoutClasses()}
|
|
128
|
+
|
|
126
129
|
@media (forced-colors: active) {
|
|
127
130
|
.sw-filter-chip-face { background: Canvas; border-color: CanvasText; color: CanvasText; }
|
|
128
131
|
.sw-filter-chips-error { color: Mark; }
|
|
@@ -144,5 +147,6 @@ export function filterChipsClassCatalog() {
|
|
|
144
147
|
'sw-filter-chip-count',
|
|
145
148
|
'sw-filter-chip-quiet',
|
|
146
149
|
'sw-filter-chips-error',
|
|
150
|
+
...filterChipsLayoutClassCatalog(),
|
|
147
151
|
];
|
|
148
152
|
}
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The colours a row's value can take: a table cell's, and `warning`, for a
|
|
3
|
+
* figure that needs a look but is not wrong yet.
|
|
4
|
+
*/
|
|
5
|
+
export declare const listRowValueTones: readonly ["success", "danger", "muted", "accent", "warning"];
|
|
6
|
+
export type ListRowValueTone = (typeof listRowValueTones)[number];
|
|
1
7
|
export declare function cssListRowClasses(): string;
|
|
2
8
|
export declare function listRowClassCatalog(): string[];
|
package/dist/css/css-list-row.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { checkStrokeIn, chevronStrokeIn } from './chevron.js';
|
|
3
|
-
import {
|
|
3
|
+
import { chartColorMix, chartInkMixes } from './chart-tones.js';
|
|
4
|
+
import { tableCellTones } from './css-table-ledger.js';
|
|
4
5
|
import { quietFill } from './quiet-fill.js';
|
|
5
6
|
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
6
7
|
const label = typographyVariants.label;
|
|
@@ -81,8 +82,22 @@ function rowRules() {
|
|
|
81
82
|
}
|
|
82
83
|
}`;
|
|
83
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* The colours a row's value can take: a table cell's, and `warning`, for a
|
|
87
|
+
* figure that needs a look but is not wrong yet.
|
|
88
|
+
*/
|
|
89
|
+
export const listRowValueTones = [...tableCellTones, 'warning'];
|
|
90
|
+
/*
|
|
91
|
+
* A warning value is the warning colour's ink, moved halfway to the text
|
|
92
|
+
* colour as a chart's warning words are: the warning colour alone falls
|
|
93
|
+
* under 4.5:1 on the surface in some palettes. Forced colours draw it as
|
|
94
|
+
* text, as every tone.
|
|
95
|
+
*/
|
|
96
|
+
function warningValueRule() {
|
|
97
|
+
return `.sw-list-row-value-warning { color: ${chartColorMix(chartInkMixes.warning)}; }`;
|
|
98
|
+
}
|
|
84
99
|
function partRules() {
|
|
85
|
-
const tones =
|
|
100
|
+
const tones = tableCellTones
|
|
86
101
|
.map((tone) => `.sw-list-row-value-${tone} { color: var(--sw-color-${tone}); }`)
|
|
87
102
|
.join('\n');
|
|
88
103
|
return `.sw-list-row-leading {
|
|
@@ -132,7 +147,8 @@ function partRules() {
|
|
|
132
147
|
|
|
133
148
|
.sw-list-row-value { font-weight: ${label.fontWeight}; }
|
|
134
149
|
|
|
135
|
-
${tones}
|
|
150
|
+
${tones}
|
|
151
|
+
${warningValueRule()}`;
|
|
136
152
|
}
|
|
137
153
|
/*
|
|
138
154
|
* The chevron is the stroke Accordion and the menus share, pointing to the
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Breakpoint } from './breakpoints.js';
|
|
2
|
+
/** The class that stretches a SegmentedControl's field below a breakpoint. */
|
|
3
|
+
export declare function segmentedFullWidthClass(breakpoint: Breakpoint): string;
|
|
4
|
+
/**
|
|
5
|
+
* `md` (the default) is each track's own segment padding; `sm` pads every
|
|
6
|
+
* segment a step less and keeps its label on one line, ending in an
|
|
7
|
+
* ellipsis past its share, so a few segments fit a phone's card.
|
|
8
|
+
*/
|
|
9
|
+
export declare const segmentedSizes: readonly ["md", "sm"];
|
|
10
|
+
export type SegmentedSize = (typeof segmentedSizes)[number];
|
|
11
|
+
export declare const segmentedSmClass = "sw-segmented-sm";
|
|
12
|
+
export declare function cssSegmentedSizingClasses(): string;
|
|
13
|
+
export declare function segmentedSizingClassCatalog(): string[];
|