@scalewing/react 1.21.0 → 1.22.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 +23 -0
- package/README.md +46 -4
- package/dist/components/ActionMenu.d.ts +13 -1
- package/dist/components/ActionMenu.js +2 -2
- package/dist/components/BarChart.d.ts +28 -0
- package/dist/components/BarChart.js +5 -4
- package/dist/components/CalendarButton.d.ts +10 -0
- package/dist/components/CalendarButton.js +4 -3
- package/dist/components/DenominationGrid.d.ts +2 -2
- package/dist/components/DenominationGrid.js +5 -2
- package/dist/components/Field.d.ts +9 -0
- package/dist/components/Field.js +3 -2
- package/dist/components/SectionNav.d.ts +44 -0
- package/dist/components/SectionNav.js +48 -0
- package/dist/components/Table.d.ts +38 -13
- package/dist/components/Table.js +7 -12
- package/dist/components/Tabs.d.ts +3 -1
- package/dist/components/Tabs.js +8 -2
- package/dist/components/Tooltip.js +19 -3
- package/dist/components/action-menu/ActionMenuList.d.ts +3 -2
- package/dist/components/action-menu/ActionMenuList.js +16 -4
- package/dist/components/date-field/CalendarDialog.d.ts +4 -1
- package/dist/components/date-field/CalendarDialog.js +2 -2
- package/dist/components/date-field/CalendarGrid.d.ts +4 -1
- package/dist/components/date-field/CalendarGrid.js +11 -3
- package/dist/components/denomination-grid/DenominationStrip.d.ts +2 -2
- package/dist/components/denomination-grid/DenominationStrip.js +17 -6
- package/dist/components/denomination-grid/types.d.ts +15 -2
- package/dist/components/table/TableCell.d.ts +42 -0
- package/dist/components/table/TableCell.js +27 -0
- package/dist/components/table/table-layout.d.ts +10 -0
- package/dist/components/table/table-layout.js +14 -0
- package/dist/components/tooltip/tooltip-open.d.ts +8 -0
- package/dist/components/tooltip/tooltip-open.js +60 -0
- package/dist/components/tooltip/use-tooltip-placement.d.ts +11 -0
- package/dist/components/tooltip/use-tooltip-placement.js +46 -0
- package/dist/components/use-anchored-popover.d.ts +2 -0
- package/dist/components/use-anchored-popover.js +2 -1
- package/dist/css/css-action-menu.js +24 -0
- package/dist/css/css-chart.js +45 -1
- package/dist/css/css-components.js +3 -0
- package/dist/css/css-date-field.js +47 -1
- package/dist/css/css-denomination-aligned.d.ts +7 -0
- package/dist/css/css-denomination-aligned.js +68 -0
- package/dist/css/css-denomination-grid.js +7 -1
- package/dist/css/css-field.js +14 -0
- package/dist/css/css-scroll-region.d.ts +8 -0
- package/dist/css/css-scroll-region.js +9 -3
- package/dist/css/css-section-nav.d.ts +4 -0
- package/dist/css/css-section-nav.js +120 -0
- package/dist/css/css-table-layout.d.ts +20 -0
- package/dist/css/css-table-layout.js +59 -0
- package/dist/css/css-table-sort.d.ts +2 -0
- package/dist/css/css-table-sort.js +105 -0
- package/dist/css/css-table.js +8 -0
- package/dist/css/css-tabs.d.ts +6 -1
- package/dist/css/css-tabs.js +9 -1
- package/dist/css/css-tooltip.js +7 -4
- package/dist/css/stylesheet.js +2 -0
- package/dist/date-only.d.ts +12 -0
- package/dist/date-only.js +24 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -0
- package/dist/styles.css +363 -6
- package/package.json +1 -1
|
@@ -13,7 +13,8 @@ function layoutViewport() {
|
|
|
13
13
|
height: root.clientHeight || window.innerHeight,
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
/** Places a fixed (or top-layer) `node` beside `anchor`, inside the viewport. */
|
|
17
|
+
export function placePopover(node, anchor, { align = 'start', flipInline = false }) {
|
|
17
18
|
const position = anchoredPosition(anchor.getBoundingClientRect(), { width: node.offsetWidth, height: node.offsetHeight }, layoutViewport(), {
|
|
18
19
|
gap: spacingScale[1],
|
|
19
20
|
inset: spacingScale[2],
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { zIndex } from './stacking.js';
|
|
3
3
|
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
4
|
+
const caption = typographyVariants.caption;
|
|
4
5
|
const label = typographyVariants.label;
|
|
5
6
|
export function cssActionMenuClasses() {
|
|
6
7
|
return `.sw-action-menu {
|
|
@@ -56,6 +57,27 @@ export function cssActionMenuClasses() {
|
|
|
56
57
|
${zIndex('popup')}
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
/* Each child of the header is a line of its own: a name, then a role. */
|
|
61
|
+
.sw-action-menu-header {
|
|
62
|
+
border-bottom: 1px solid var(--sw-color-border);
|
|
63
|
+
color: var(--sw-color-muted);
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
gap: var(--sw-space-1);
|
|
67
|
+
font-family: var(--sw-font-sans);
|
|
68
|
+
font-size: ${caption.fontSize}px;
|
|
69
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
70
|
+
line-height: ${caption.lineHeight}px;
|
|
71
|
+
margin-bottom: var(--sw-space-1);
|
|
72
|
+
/* The commands' inline padding, so the header's words line up with theirs. */
|
|
73
|
+
padding: var(--sw-space-1) var(--sw-control-xs-padding-inline) var(--sw-space-2);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* With a header, the commands are the menu inside the popover. */
|
|
77
|
+
.sw-action-menu-items {
|
|
78
|
+
display: block;
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
.sw-action-menu-item {
|
|
60
82
|
align-items: center;
|
|
61
83
|
appearance: none;
|
|
@@ -109,6 +131,8 @@ export function actionMenuClassCatalog() {
|
|
|
109
131
|
'sw-action-menu',
|
|
110
132
|
'sw-action-menu-trigger',
|
|
111
133
|
'sw-action-menu-list',
|
|
134
|
+
'sw-action-menu-header',
|
|
135
|
+
'sw-action-menu-items',
|
|
112
136
|
'sw-action-menu-item',
|
|
113
137
|
'sw-action-menu-item-danger',
|
|
114
138
|
];
|
package/dist/css/css-chart.js
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
const caption = typographyVariants.caption;
|
|
3
3
|
const data = typographyVariants.data;
|
|
4
|
+
/*
|
|
5
|
+
* A diverging chart puts zero in the middle of each track, marked by a
|
|
6
|
+
* hairline: a positive bar starts there and grows toward the inline end, a
|
|
7
|
+
* negative one ends there and grows toward the start, each at most half the
|
|
8
|
+
* track. The fill keeps its share of the scale (`--sw-bar-fill`), so a
|
|
9
|
+
* bar is half as long as in the magnitude layout, on the same scale. The
|
|
10
|
+
* end at zero is square, so the bars meet the hairline.
|
|
11
|
+
*/
|
|
12
|
+
function divergingRules() {
|
|
13
|
+
return `.sw-bar-chart-diverging .sw-bar-chart-track {
|
|
14
|
+
position: relative;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.sw-bar-chart-diverging .sw-bar-chart-track::before {
|
|
18
|
+
background: var(--sw-color-border);
|
|
19
|
+
content: '';
|
|
20
|
+
inset-block: 0;
|
|
21
|
+
inset-inline-start: 50%;
|
|
22
|
+
position: absolute;
|
|
23
|
+
width: 1px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.sw-bar-chart-diverging .sw-bar-chart-fill {
|
|
27
|
+
border-end-start-radius: 0;
|
|
28
|
+
border-start-start-radius: 0;
|
|
29
|
+
margin-inline-start: 50%;
|
|
30
|
+
width: calc(var(--sw-bar-fill, 0) * 50%);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.sw-bar-chart-diverging .sw-bar-chart-fill-negative {
|
|
34
|
+
border-end-end-radius: 0;
|
|
35
|
+
border-end-start-radius: inherit;
|
|
36
|
+
border-start-end-radius: 0;
|
|
37
|
+
border-start-start-radius: inherit;
|
|
38
|
+
margin-inline-start: calc(50% - var(--sw-bar-fill, 0) * 50%);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@media (forced-colors: active) {
|
|
42
|
+
.sw-bar-chart-diverging .sw-bar-chart-track::before { background: CanvasText; }
|
|
43
|
+
}`;
|
|
44
|
+
}
|
|
4
45
|
export function cssChartClasses() {
|
|
5
46
|
return `.sw-bar-chart {
|
|
6
47
|
display: grid;
|
|
@@ -80,7 +121,9 @@ export function cssChartClasses() {
|
|
|
80
121
|
.sw-bar-chart-axis-track {
|
|
81
122
|
display: flex;
|
|
82
123
|
justify-content: space-between;
|
|
83
|
-
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
${divergingRules()}`;
|
|
84
127
|
}
|
|
85
128
|
export function chartClassCatalog() {
|
|
86
129
|
return [
|
|
@@ -94,5 +137,6 @@ export function chartClassCatalog() {
|
|
|
94
137
|
'sw-bar-chart-fill-negative',
|
|
95
138
|
'sw-bar-chart-value',
|
|
96
139
|
'sw-bar-chart-axis-track',
|
|
140
|
+
'sw-bar-chart-diverging',
|
|
97
141
|
];
|
|
98
142
|
}
|
|
@@ -7,6 +7,7 @@ import { cssChartClasses } from './css-chart.js';
|
|
|
7
7
|
import { cssCheckboxClasses } from './css-checkbox.js';
|
|
8
8
|
import { cssRadioGroupClasses } from './css-radio-group.js';
|
|
9
9
|
import { cssChromeClasses } from './css-chrome.js';
|
|
10
|
+
import { cssSectionNavClasses } from './css-section-nav.js';
|
|
10
11
|
import { cssDataClasses } from './css-data.js';
|
|
11
12
|
import { cssSegmentedClasses } from './css-segmented.js';
|
|
12
13
|
import { cssTableClasses } from './css-table.js';
|
|
@@ -123,6 +124,8 @@ ${cssChartClasses()}
|
|
|
123
124
|
|
|
124
125
|
${cssChromeClasses()}
|
|
125
126
|
|
|
127
|
+
${cssSectionNavClasses()}
|
|
128
|
+
|
|
126
129
|
${cssDialogClasses()}
|
|
127
130
|
|
|
128
131
|
${cssAccordionClasses()}
|
|
@@ -229,16 +229,51 @@ function calendarRules() {
|
|
|
229
229
|
background: color-mix(in srgb, var(--sw-color-muted) 16%, transparent);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
+
/*
|
|
233
|
+
* A range's days are one band in each week row: square-cornered, the accent
|
|
234
|
+
* at 16 % over the calendar's glass, rounded at the range's start and end.
|
|
235
|
+
* accentSubtle is mixed against the surface, not the glass, and fades to
|
|
236
|
+
* nothing where the accent is near AA, so the band would vanish in most
|
|
237
|
+
* dark palettes. Every number on the band is in the text colour, which
|
|
238
|
+
* keeps 4.5:1 on it in every palette (muted and accent do not); a
|
|
239
|
+
* neighbouring month's day and today are marked by the band and today's
|
|
240
|
+
* accent ring (3:1 or more on the band). The selected day sits on top.
|
|
241
|
+
*/
|
|
242
|
+
.sw-date-field-day-in-range {
|
|
243
|
+
background: color-mix(in srgb, var(--sw-color-accent) 16%, transparent);
|
|
244
|
+
border-radius: 0;
|
|
245
|
+
color: var(--sw-color-text);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.sw-date-field-day-range-start {
|
|
249
|
+
border-end-start-radius: var(--sw-radius-pill);
|
|
250
|
+
border-start-start-radius: var(--sw-radius-pill);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.sw-date-field-day-range-end {
|
|
254
|
+
border-end-end-radius: var(--sw-radius-pill);
|
|
255
|
+
border-start-end-radius: var(--sw-radius-pill);
|
|
256
|
+
}
|
|
257
|
+
|
|
232
258
|
.sw-date-field-day[aria-current='date'] {
|
|
233
259
|
border-color: var(--sw-color-accent);
|
|
234
260
|
color: var(--sw-color-accent);
|
|
235
261
|
font-weight: ${label.fontWeight};
|
|
236
262
|
}
|
|
237
263
|
|
|
264
|
+
.sw-date-field-day-in-range[aria-current='date'] {
|
|
265
|
+
color: var(--sw-color-text);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.sw-date-field-day-in-range:hover:not([aria-disabled='true']) {
|
|
269
|
+
background: color-mix(in srgb, var(--sw-color-accent) 24%, transparent);
|
|
270
|
+
}
|
|
271
|
+
|
|
238
272
|
.sw-date-field-day[aria-selected='true'],
|
|
239
273
|
.sw-date-field-day[aria-selected='true']:hover {
|
|
240
274
|
background: var(--sw-color-accent);
|
|
241
275
|
border-color: var(--sw-color-accent);
|
|
276
|
+
border-radius: var(--sw-radius-pill);
|
|
242
277
|
color: var(--sw-color-onAccent);
|
|
243
278
|
font-weight: ${label.fontWeight};
|
|
244
279
|
}
|
|
@@ -279,7 +314,15 @@ function adaptiveRules() {
|
|
|
279
314
|
}
|
|
280
315
|
.sw-date-field-calendar { border-color: CanvasText; }
|
|
281
316
|
.sw-date-field-day[aria-current='date'] { border-color: CanvasText; }
|
|
282
|
-
.sw-date-field-day
|
|
317
|
+
.sw-date-field-day-in-range,
|
|
318
|
+
.sw-date-field-day-in-range:hover:not([aria-disabled='true']),
|
|
319
|
+
.sw-date-field-day-in-range[aria-current='date'] {
|
|
320
|
+
background: Mark;
|
|
321
|
+
color: MarkText;
|
|
322
|
+
forced-color-adjust: none;
|
|
323
|
+
}
|
|
324
|
+
.sw-date-field-day[aria-selected='true'],
|
|
325
|
+
.sw-date-field-day[aria-selected='true']:hover {
|
|
283
326
|
background: Highlight;
|
|
284
327
|
color: HighlightText;
|
|
285
328
|
forced-color-adjust: none;
|
|
@@ -311,6 +354,9 @@ export function dateFieldClassCatalog() {
|
|
|
311
354
|
'sw-date-field-grid',
|
|
312
355
|
'sw-date-field-day',
|
|
313
356
|
'sw-date-field-day-outside',
|
|
357
|
+
'sw-date-field-day-in-range',
|
|
358
|
+
'sw-date-field-day-range-start',
|
|
359
|
+
'sw-date-field-day-range-end',
|
|
314
360
|
'sw-date-field-footer',
|
|
315
361
|
];
|
|
316
362
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type TableColumnSize } from './css-table-layout.js';
|
|
2
|
+
/** The row-label widths a strip lines up at: the Table column sizes. */
|
|
3
|
+
export type DenominationLabelWidth = TableColumnSize;
|
|
4
|
+
export declare const denominationLabelWidths: DenominationLabelWidth[];
|
|
5
|
+
export declare function denominationLabelWidthClass(width: DenominationLabelWidth): string;
|
|
6
|
+
export declare function cssDenominationAlignedClasses(): string;
|
|
7
|
+
export declare function denominationAlignedClassCatalog(): string[];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { breakpointQuery } from './breakpoints.js';
|
|
2
|
+
import { tableColumnSizes } from './css-table-layout.js';
|
|
3
|
+
export const denominationLabelWidths = Object.keys(tableColumnSizes);
|
|
4
|
+
export function denominationLabelWidthClass(width) {
|
|
5
|
+
return `sw-denomination-label-${width}`;
|
|
6
|
+
}
|
|
7
|
+
/*
|
|
8
|
+
* A strip with a label width lines its columns up with every other strip
|
|
9
|
+
* of the same columns in a container of the same width, such as the cards
|
|
10
|
+
* of a feed: the label column is that width, and the count columns (and the
|
|
11
|
+
* total column from md up, where it is drawn) share the rest of the scroll
|
|
12
|
+
* region's width equally, measured from the region itself (a container, so
|
|
13
|
+
* 100cqi is its width) rather than from the cells' content. Every column is
|
|
14
|
+
* sized, so the browser has no spare width to share by content. A count
|
|
15
|
+
* wider than its share widens its column, and the strip then scrolls as a
|
|
16
|
+
* plain one does. The component sets the column count and whether there is
|
|
17
|
+
* a total column (`--sw-denomination-columns`, `--sw-denomination-total`);
|
|
18
|
+
* below md the total column collapses, so it takes no share.
|
|
19
|
+
*/
|
|
20
|
+
export function cssDenominationAlignedClasses() {
|
|
21
|
+
const widths = Object.entries(tableColumnSizes)
|
|
22
|
+
.map(([size, rem]) => `.${denominationLabelWidthClass(size)} { --sw-denomination-label-width: ${rem}rem; }`)
|
|
23
|
+
.join('\n');
|
|
24
|
+
const strip = '.sw-denomination-strip-aligned';
|
|
25
|
+
return `.sw-denomination-scroll-aligned {
|
|
26
|
+
container-type: inline-size;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
${widths}
|
|
30
|
+
|
|
31
|
+
${strip} {
|
|
32
|
+
--sw-denomination-total-shown: 1;
|
|
33
|
+
--sw-denomination-share: calc(
|
|
34
|
+
(100cqi - var(--sw-denomination-label-width)) /
|
|
35
|
+
(var(--sw-denomination-columns) + var(--sw-denomination-total) * var(--sw-denomination-total-shown))
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
${strip} th,
|
|
40
|
+
${strip} td {
|
|
41
|
+
box-sizing: border-box;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
${strip} .sw-denomination-label,
|
|
45
|
+
${strip} thead .sw-denomination-corner:first-child {
|
|
46
|
+
width: var(--sw-denomination-label-width);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
${strip} .sw-denomination-cell,
|
|
50
|
+
${strip} .sw-denomination-head:not(.sw-denomination-total-head),
|
|
51
|
+
${strip} .sw-denomination-total,
|
|
52
|
+
${strip} .sw-denomination-total-head {
|
|
53
|
+
width: var(--sw-denomination-share);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@media ${breakpointQuery('below', 'md')} {
|
|
57
|
+
${strip} { --sw-denomination-total-shown: 0; }
|
|
58
|
+
${strip} .sw-denomination-total,
|
|
59
|
+
${strip} .sw-denomination-total-head { width: 0; }
|
|
60
|
+
}`;
|
|
61
|
+
}
|
|
62
|
+
export function denominationAlignedClassCatalog() {
|
|
63
|
+
return [
|
|
64
|
+
'sw-denomination-scroll-aligned',
|
|
65
|
+
'sw-denomination-strip-aligned',
|
|
66
|
+
...denominationLabelWidths.map(denominationLabelWidthClass),
|
|
67
|
+
];
|
|
68
|
+
}
|
|
@@ -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 { cssDenominationAlignedClasses, denominationAlignedClassCatalog, } from './css-denomination-aligned.js';
|
|
4
5
|
import { cssDenominationCellToneClasses, denominationCellToneClassCatalog, } from './css-denomination-cell-tones.js';
|
|
5
6
|
import { pinnedStartShadeRules, scrollRegionRules, } from './css-scroll-region.js';
|
|
6
7
|
import { visuallyHiddenDeclarations } from './css-utilities.js';
|
|
@@ -235,7 +236,8 @@ ${pinnedStartShadeRules('.sw-denomination-scroll', [
|
|
|
235
236
|
@media ${breakpointQuery('below', 'md')} {
|
|
236
237
|
.sw-denomination-strip .sw-denomination-total,
|
|
237
238
|
.sw-denomination-strip .sw-denomination-total-head { padding: 0; position: relative; }
|
|
238
|
-
.sw-denomination-total-value
|
|
239
|
+
.sw-denomination-total-value,
|
|
240
|
+
.sw-denomination-total-label { ${visuallyHiddenDeclarations} }
|
|
239
241
|
.sw-denomination-total-inline { display: block; }
|
|
240
242
|
.sw-denomination-label-body { flex-direction: column; align-items: flex-start; gap: var(--sw-space-1); }
|
|
241
243
|
.sw-denomination-strip .sw-denomination-label-line { gap: var(--sw-space-1); }
|
|
@@ -247,6 +249,8 @@ ${pinnedStartShadeRules('.sw-denomination-scroll', [
|
|
|
247
249
|
|
|
248
250
|
${cssDenominationCellToneClasses()}
|
|
249
251
|
|
|
252
|
+
${cssDenominationAlignedClasses()}
|
|
253
|
+
|
|
250
254
|
@media (forced-colors: active) {
|
|
251
255
|
.sw-denomination-label { border-inline-start-color: CanvasText; color: CanvasText; }
|
|
252
256
|
.sw-denomination-strip .sw-denomination-label::before { background: CanvasText; forced-color-adjust: none; }
|
|
@@ -279,11 +283,13 @@ export function denominationGridClassCatalog() {
|
|
|
279
283
|
'sw-denomination-total',
|
|
280
284
|
'sw-denomination-total-inline',
|
|
281
285
|
'sw-denomination-total-head',
|
|
286
|
+
'sw-denomination-total-label',
|
|
282
287
|
'sw-denomination-total-value',
|
|
283
288
|
'sw-denomination-tiles',
|
|
284
289
|
'sw-denomination-tile-list',
|
|
285
290
|
'sw-denomination-tile',
|
|
286
291
|
'sw-denomination-subtotal',
|
|
287
292
|
...denominationCellToneClassCatalog(),
|
|
293
|
+
...denominationAlignedClassCatalog(),
|
|
288
294
|
];
|
|
289
295
|
}
|
package/dist/css/css-field.js
CHANGED
|
@@ -80,11 +80,24 @@ export function cssFieldClasses() {
|
|
|
80
80
|
border-color: var(--sw-color-danger);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
/*
|
|
84
|
+
* A changed value: the accent border, a hairline thicker through an inset
|
|
85
|
+
* shadow so nothing moves, on the control or on an adorned frame (whose
|
|
86
|
+
* input draws no border of its own).
|
|
87
|
+
*/
|
|
88
|
+
[data-theme] .sw-field-changed > :is(input, select, textarea),
|
|
89
|
+
.sw-field-changed .sw-field-adorned {
|
|
90
|
+
border-color: var(--sw-color-accent);
|
|
91
|
+
box-shadow: inset 0 0 0 1px var(--sw-color-accent);
|
|
92
|
+
}
|
|
93
|
+
|
|
83
94
|
${adornmentRules()}
|
|
84
95
|
|
|
85
96
|
@media (forced-colors: active) {
|
|
86
97
|
[data-theme] .sw-field-invalid :is(input, select, textarea),
|
|
87
98
|
.sw-field-invalid .sw-field-adorned { border-color: Mark; }
|
|
99
|
+
[data-theme] .sw-field-changed > :is(input, select, textarea),
|
|
100
|
+
.sw-field-changed .sw-field-adorned { border-color: Highlight; box-shadow: inset 0 0 0 1px Highlight; }
|
|
88
101
|
.sw-field-prefix, .sw-field-suffix { color: CanvasText; }
|
|
89
102
|
.sw-field-adorned:has(> input:disabled) {
|
|
90
103
|
${disabledControlForcedColors}
|
|
@@ -99,6 +112,7 @@ export function fieldClassCatalog() {
|
|
|
99
112
|
'sw-field-description',
|
|
100
113
|
'sw-field-error',
|
|
101
114
|
'sw-field-invalid',
|
|
115
|
+
'sw-field-changed',
|
|
102
116
|
'sw-field-adorned',
|
|
103
117
|
'sw-field-prefix',
|
|
104
118
|
'sw-field-suffix',
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shade each inline edge of `selector` draws while `useScrollOverflow`
|
|
3
|
+
* marks it (`sw-scroll-more-start`, `sw-scroll-more-end`). The start edge is
|
|
4
|
+
* the left in a left-to-right box and the right in RTL. A box that scrolls
|
|
5
|
+
* itself (a `Tabs` strip) takes these alone; a scroll region takes them
|
|
6
|
+
* through `scrollRegionRules`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function scrollShadeRules(selector: string): string;
|
|
1
9
|
/**
|
|
2
10
|
* A scroll region is a full-width box that scrolls its own content when the
|
|
3
11
|
* content is wider (or taller) than the box, so a wide table never widens the
|
|
@@ -12,8 +12,14 @@ function edgeShade(side) {
|
|
|
12
12
|
const offset = side === 'left' ? 'var(--sw-space-6)' : 'calc(-1 * var(--sw-space-6))';
|
|
13
13
|
return `inset ${offset} 0 var(--sw-space-5) calc(-1 * var(--sw-space-5)) ${shadeColor}`;
|
|
14
14
|
}
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The shade each inline edge of `selector` draws while `useScrollOverflow`
|
|
17
|
+
* marks it (`sw-scroll-more-start`, `sw-scroll-more-end`). The start edge is
|
|
18
|
+
* the left in a left-to-right box and the right in RTL. A box that scrolls
|
|
19
|
+
* itself (a `Tabs` strip) takes these alone; a scroll region takes them
|
|
20
|
+
* through `scrollRegionRules`.
|
|
21
|
+
*/
|
|
22
|
+
export function scrollShadeRules(selector) {
|
|
17
23
|
const more = (edge) => `${selector}.sw-scroll-more-${edge}`;
|
|
18
24
|
const both = `${more('start')}.sw-scroll-more-end`;
|
|
19
25
|
return [
|
|
@@ -47,7 +53,7 @@ ${selector}:focus-visible {
|
|
|
47
53
|
outline-offset: calc(-1 * var(--sw-focus-ring-width));
|
|
48
54
|
}
|
|
49
55
|
|
|
50
|
-
${
|
|
56
|
+
${scrollShadeRules(selector)}`;
|
|
51
57
|
}
|
|
52
58
|
export function scrollRegionClassCatalog() {
|
|
53
59
|
return ['sw-scroll-more-start', 'sw-scroll-more-end'];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { breakpointQuery, breakpoints, } from './breakpoints.js';
|
|
3
|
+
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
4
|
+
const label = typographyVariants.label;
|
|
5
|
+
export function sectionNavVerticalClass(breakpoint) {
|
|
6
|
+
return `sw-section-nav-vertical-from-${breakpoint}`;
|
|
7
|
+
}
|
|
8
|
+
/*
|
|
9
|
+
* From the breakpoint up the row becomes a side list: one item per line,
|
|
10
|
+
* the full width of its column, the current one marked by an accent bar at
|
|
11
|
+
* its inline start instead of the underline.
|
|
12
|
+
*/
|
|
13
|
+
function verticalRules() {
|
|
14
|
+
return breakpoints
|
|
15
|
+
.map((breakpoint) => {
|
|
16
|
+
const nav = `.${sectionNavVerticalClass(breakpoint)}`;
|
|
17
|
+
return `@media ${breakpointQuery('from', breakpoint)} {
|
|
18
|
+
${nav} .sw-section-nav-list {
|
|
19
|
+
border-bottom: 0;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: var(--sw-space-1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
${nav} .sw-section-nav-link {
|
|
25
|
+
border-bottom: 0;
|
|
26
|
+
border-inline-start: 2px solid transparent;
|
|
27
|
+
border-radius: 0 var(--sw-radius-sm) var(--sw-radius-sm) 0;
|
|
28
|
+
margin-bottom: 0;
|
|
29
|
+
width: 100%;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
${nav} .sw-section-nav-link:dir(rtl) {
|
|
33
|
+
border-radius: var(--sw-radius-sm) 0 0 var(--sw-radius-sm);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
${nav} .sw-section-nav-link[aria-current] {
|
|
37
|
+
border-inline-start-color: var(--sw-color-accent);
|
|
38
|
+
}
|
|
39
|
+
}`;
|
|
40
|
+
})
|
|
41
|
+
.join('\n\n');
|
|
42
|
+
}
|
|
43
|
+
/*
|
|
44
|
+
* A section navigation is quieter than a workspace's: label-size words in
|
|
45
|
+
* the muted color with no fill, the current item in the text color over an
|
|
46
|
+
* accent underline on the row's hairline (as a tab strip marks its tab),
|
|
47
|
+
* and a soft fill on hover. A link that is the current page or holds it is
|
|
48
|
+
* marked the same way. A coarse pointer gets the 44 px target. The link
|
|
49
|
+
* rules start at the canvas (`[data-theme]`) to outrank its accent links.
|
|
50
|
+
*/
|
|
51
|
+
export function cssSectionNavClasses() {
|
|
52
|
+
return `.sw-section-nav-list {
|
|
53
|
+
border-bottom: 1px solid var(--sw-color-border);
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-wrap: wrap;
|
|
56
|
+
gap: var(--sw-space-1) var(--sw-space-2);
|
|
57
|
+
list-style: none;
|
|
58
|
+
margin: 0;
|
|
59
|
+
padding: 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[data-theme] .sw-section-nav-link {
|
|
63
|
+
align-items: center;
|
|
64
|
+
border-bottom: 2px solid transparent;
|
|
65
|
+
border-radius: var(--sw-radius-sm) var(--sw-radius-sm) 0 0;
|
|
66
|
+
box-sizing: border-box;
|
|
67
|
+
color: var(--sw-color-muted);
|
|
68
|
+
display: inline-flex;
|
|
69
|
+
font-family: var(--sw-font-sans);
|
|
70
|
+
font-size: ${label.fontSize}px;
|
|
71
|
+
font-weight: ${label.fontWeight};
|
|
72
|
+
gap: var(--sw-space-2);
|
|
73
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
74
|
+
line-height: ${label.lineHeight}px;
|
|
75
|
+
margin-bottom: -1px;
|
|
76
|
+
min-height: var(--sw-control-sm-min-height);
|
|
77
|
+
padding-inline: var(--sw-control-xs-padding-inline);
|
|
78
|
+
text-decoration: none;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
[data-theme] .sw-section-nav-link:hover {
|
|
82
|
+
background: color-mix(in srgb, var(--sw-color-muted) 12%, transparent);
|
|
83
|
+
color: var(--sw-color-text);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-theme] .sw-section-nav-link:focus-visible {
|
|
87
|
+
outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
|
|
88
|
+
outline-offset: calc(-1 * var(--sw-focus-ring-width));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
[data-theme] .sw-section-nav-link[aria-current] {
|
|
92
|
+
border-bottom-color: var(--sw-color-accent);
|
|
93
|
+
color: var(--sw-color-text);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.sw-section-nav-icon {
|
|
97
|
+
display: inline-flex;
|
|
98
|
+
flex: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
${verticalRules()}
|
|
102
|
+
|
|
103
|
+
@media ${coarsePointerQuery} {
|
|
104
|
+
[data-theme] .sw-section-nav-link { min-height: ${touchTarget}; }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@media (forced-colors: active) {
|
|
108
|
+
[data-theme] .sw-section-nav-link { color: LinkText; }
|
|
109
|
+
[data-theme] .sw-section-nav-link[aria-current] { border-color: Highlight; color: CanvasText; }
|
|
110
|
+
}`;
|
|
111
|
+
}
|
|
112
|
+
export function sectionNavClassCatalog() {
|
|
113
|
+
return [
|
|
114
|
+
'sw-section-nav',
|
|
115
|
+
'sw-section-nav-list',
|
|
116
|
+
'sw-section-nav-link',
|
|
117
|
+
'sw-section-nav-icon',
|
|
118
|
+
...breakpoints.map(sectionNavVerticalClass),
|
|
119
|
+
];
|
|
120
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sized column widths, in rem so a header in caption type and a cell in
|
|
3
|
+
* body type agree: `xs` holds a count or a short code, `sm` a short date or
|
|
4
|
+
* an amount, `md` a date with its year, `lg` a date and a time, `xl` a name
|
|
5
|
+
* or a short phrase. A cell's padding is outside the width.
|
|
6
|
+
*/
|
|
7
|
+
export declare const tableColumnSizes: {
|
|
8
|
+
readonly xs: 4;
|
|
9
|
+
readonly sm: 6;
|
|
10
|
+
readonly md: 8;
|
|
11
|
+
readonly lg: 12;
|
|
12
|
+
readonly xl: 16;
|
|
13
|
+
};
|
|
14
|
+
export type TableColumnSize = keyof typeof tableColumnSizes;
|
|
15
|
+
/** A column's width: shrink to its content on one line, or a size. */
|
|
16
|
+
export type TableColumnWidth = 'min' | TableColumnSize;
|
|
17
|
+
export declare const tableColumnWidths: readonly TableColumnWidth[];
|
|
18
|
+
export declare function tableColumnWidthClass(width: TableColumnWidth): string;
|
|
19
|
+
export declare function cssTableLayoutClasses(): string;
|
|
20
|
+
export declare function tableLayoutClassCatalog(): string[];
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sized column widths, in rem so a header in caption type and a cell in
|
|
3
|
+
* body type agree: `xs` holds a count or a short code, `sm` a short date or
|
|
4
|
+
* an amount, `md` a date with its year, `lg` a date and a time, `xl` a name
|
|
5
|
+
* or a short phrase. A cell's padding is outside the width.
|
|
6
|
+
*/
|
|
7
|
+
export const tableColumnSizes = {
|
|
8
|
+
xs: 4,
|
|
9
|
+
sm: 6,
|
|
10
|
+
md: 8,
|
|
11
|
+
lg: 12,
|
|
12
|
+
xl: 16,
|
|
13
|
+
};
|
|
14
|
+
export const tableColumnWidths = [
|
|
15
|
+
'min',
|
|
16
|
+
...Object.keys(tableColumnSizes),
|
|
17
|
+
];
|
|
18
|
+
export function tableColumnWidthClass(width) {
|
|
19
|
+
return `sw-table-col-${width}`;
|
|
20
|
+
}
|
|
21
|
+
/*
|
|
22
|
+
* A fixed table sizes its columns from the header row only, so a filter
|
|
23
|
+
* that hides a row moves no column. `min` is the one-percent idiom: an auto
|
|
24
|
+
* table gives the column the least room its content allows, on one line; a
|
|
25
|
+
* fixed table never measures content, so there `min` is no width at all
|
|
26
|
+
* and the column shares what is left. `top` starts every cell of a tall row
|
|
27
|
+
* on its first line.
|
|
28
|
+
*/
|
|
29
|
+
export function cssTableLayoutClasses() {
|
|
30
|
+
const sizes = Object.entries(tableColumnSizes)
|
|
31
|
+
.map(([size, rem]) => `.sw-table .${tableColumnWidthClass(size)} { width: ${rem}rem; }`)
|
|
32
|
+
.join('\n');
|
|
33
|
+
return `.sw-table-fixed {
|
|
34
|
+
table-layout: fixed;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.sw-table .sw-table-col-min {
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
width: 1%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.sw-table-fixed .sw-table-col-min {
|
|
43
|
+
width: auto;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
${sizes}
|
|
47
|
+
|
|
48
|
+
.sw-table.sw-table-top th,
|
|
49
|
+
.sw-table.sw-table-top td {
|
|
50
|
+
vertical-align: top;
|
|
51
|
+
}`;
|
|
52
|
+
}
|
|
53
|
+
export function tableLayoutClassCatalog() {
|
|
54
|
+
return [
|
|
55
|
+
'sw-table-fixed',
|
|
56
|
+
'sw-table-top',
|
|
57
|
+
...tableColumnWidths.map(tableColumnWidthClass),
|
|
58
|
+
];
|
|
59
|
+
}
|