@scalewing/react 1.30.0 → 1.32.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 +43 -0
- package/README.md +23 -5
- package/dist/components/ActionMenu.d.ts +10 -1
- package/dist/components/ActionMenu.js +7 -2
- package/dist/components/AppHeader.d.ts +9 -1
- package/dist/components/AppHeader.js +6 -2
- package/dist/components/Box.d.ts +10 -2
- package/dist/components/Button.d.ts +27 -2
- package/dist/components/Button.js +5 -3
- package/dist/components/ButtonGroup.d.ts +9 -1
- package/dist/components/ButtonGroup.js +8 -2
- package/dist/components/Combobox.d.ts +14 -0
- package/dist/components/Combobox.js +125 -0
- package/dist/components/DateField.d.ts +9 -1
- package/dist/components/DateField.js +4 -3
- package/dist/components/DenominationGrid.d.ts +5 -3
- package/dist/components/DenominationGrid.js +21 -11
- package/dist/components/Dialog.d.ts +9 -1
- package/dist/components/Dialog.js +8 -4
- package/dist/components/Field.d.ts +25 -0
- package/dist/components/Field.js +56 -6
- package/dist/components/FieldLabelText.d.ts +21 -3
- package/dist/components/FieldLabelText.js +16 -4
- package/dist/components/FilterChips.d.ts +9 -1
- package/dist/components/FilterChips.js +4 -2
- package/dist/components/Nav.d.ts +14 -2
- package/dist/components/Nav.js +6 -2
- package/dist/components/SegmentedControl.d.ts +5 -2
- package/dist/components/SegmentedControl.js +2 -1
- package/dist/components/Select.d.ts +9 -1
- package/dist/components/Select.js +4 -3
- package/dist/components/Stepper.d.ts +13 -0
- package/dist/components/Stepper.js +8 -2
- package/dist/components/combobox/ComboboxPopup.d.ts +25 -0
- package/dist/components/combobox/ComboboxPopup.js +68 -0
- package/dist/components/combobox/entries.d.ts +18 -0
- package/dist/components/combobox/entries.js +34 -0
- package/dist/components/combobox/types.d.ts +71 -0
- package/dist/components/combobox/types.js +1 -0
- package/dist/components/combobox/validate.d.ts +3 -0
- package/dist/components/combobox/validate.js +44 -0
- package/dist/components/denomination-grid/DenominationStrip.d.ts +4 -2
- package/dist/components/denomination-grid/DenominationStrip.js +3 -2
- package/dist/components/denomination-grid/DenominationTiles.d.ts +1 -1
- package/dist/components/denomination-grid/EntryCell.js +1 -1
- package/dist/components/denomination-grid/StripRow.js +5 -2
- package/dist/components/denomination-grid/types.d.ts +35 -1
- package/dist/components/dialog/DialogTitle.d.ts +5 -3
- package/dist/components/dialog/DialogTitle.js +4 -4
- package/dist/components/field/SearchFrame.d.ts +16 -0
- package/dist/components/field/SearchFrame.js +32 -0
- package/dist/css/css-action-menu-trigger.d.ts +11 -0
- package/dist/css/css-action-menu-trigger.js +66 -0
- package/dist/css/css-action-menu.js +7 -2
- package/dist/css/css-app-header-bar.d.ts +10 -0
- package/dist/css/css-app-header-bar.js +26 -0
- package/dist/css/css-box-border.d.ts +6 -1
- package/dist/css/css-box-border.js +8 -4
- package/dist/css/css-button-group-attached.js +5 -2
- package/dist/css/css-button-group-track.d.ts +11 -0
- package/dist/css/css-button-group-track.js +48 -0
- package/dist/css/css-button.d.ts +19 -2
- package/dist/css/css-button.js +31 -1
- package/dist/css/css-chrome.js +14 -1
- package/dist/css/css-combobox.d.ts +2 -0
- package/dist/css/css-combobox.js +136 -0
- package/dist/css/css-components.js +6 -0
- package/dist/css/css-data.js +3 -2
- package/dist/css/css-date-field.js +2 -1
- package/dist/css/css-denomination-appearance.d.ts +21 -0
- package/dist/css/css-denomination-appearance.js +114 -0
- package/dist/css/css-denomination-cell-tones.d.ts +8 -0
- package/dist/css/css-denomination-cell-tones.js +20 -1
- package/dist/css/css-denomination-grid.js +4 -0
- package/dist/css/css-dialog-banded.d.ts +11 -0
- package/dist/css/css-dialog-banded.js +84 -0
- package/dist/css/css-field-search.d.ts +2 -0
- package/dist/css/css-field-search.js +118 -0
- package/dist/css/css-field.js +4 -0
- package/dist/css/css-multi-select.js +2 -1
- package/dist/css/css-nav-words.d.ts +13 -0
- package/dist/css/css-nav-words.js +51 -0
- package/dist/css/css-notice.d.ts +4 -11
- package/dist/css/css-notice.js +6 -22
- package/dist/css/css-segmented-raised.d.ts +3 -0
- package/dist/css/css-segmented-raised.js +72 -0
- package/dist/css/css-segmented.js +9 -3
- package/dist/css/css-select.js +2 -1
- package/dist/css/css-split.js +2 -1
- package/dist/css/css-stepper.js +7 -0
- package/dist/css/quiet-fill.d.ts +7 -0
- package/dist/css/quiet-fill.js +7 -0
- package/dist/css/stacking.js +6 -2
- package/dist/css/stylesheet.js +4 -0
- package/dist/css/tone-tint.d.ts +21 -0
- package/dist/css/tone-tint.js +23 -0
- package/dist/index.d.ts +13 -10
- package/dist/index.js +11 -8
- package/dist/styles.css +505 -12
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { chevronStroke } from './chevron.js';
|
|
3
|
+
import { actionMenuTriggerClassCatalog, cssActionMenuTriggerClasses, } from './css-action-menu-trigger.js';
|
|
3
4
|
import { zIndex } from './stacking.js';
|
|
4
5
|
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
6
|
+
import { quietFill } from './quiet-fill.js';
|
|
5
7
|
const caption = typographyVariants.caption;
|
|
6
8
|
const label = typographyVariants.label;
|
|
7
9
|
export function cssActionMenuClasses() {
|
|
@@ -103,7 +105,7 @@ export function cssActionMenuClasses() {
|
|
|
103
105
|
|
|
104
106
|
.sw-action-menu-item:hover,
|
|
105
107
|
.sw-action-menu-item:focus-visible {
|
|
106
|
-
background:
|
|
108
|
+
background: ${quietFill};
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
.sw-action-menu-item:disabled {
|
|
@@ -162,7 +164,9 @@ export function cssActionMenuClasses() {
|
|
|
162
164
|
.sw-action-menu-item {
|
|
163
165
|
min-height: ${touchTarget};
|
|
164
166
|
}
|
|
165
|
-
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
${cssActionMenuTriggerClasses()}`;
|
|
166
170
|
}
|
|
167
171
|
export function actionMenuClassCatalog() {
|
|
168
172
|
return [
|
|
@@ -176,5 +180,6 @@ export function actionMenuClassCatalog() {
|
|
|
176
180
|
'sw-action-menu-detail',
|
|
177
181
|
'sw-action-menu-chevron',
|
|
178
182
|
'sw-action-menu-separator',
|
|
183
|
+
...actionMenuTriggerClassCatalog(),
|
|
179
184
|
];
|
|
180
185
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const appHeaderAppearances: readonly ["glass", "bar"];
|
|
2
|
+
/**
|
|
3
|
+
* How an AppHeader is drawn: `glass` (the default) is a rounded frosted
|
|
4
|
+
* card; `bar` is a full-width band of the solid surface with a hairline
|
|
5
|
+
* under it and no rounding, set against the page's edges.
|
|
6
|
+
*/
|
|
7
|
+
export type AppHeaderAppearance = (typeof appHeaderAppearances)[number];
|
|
8
|
+
export declare const appHeaderBarClass = "sw-app-header-bar";
|
|
9
|
+
export declare function cssAppHeaderBarClasses(): string;
|
|
10
|
+
export declare function appHeaderBarClassCatalog(): string[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const appHeaderAppearances = ['glass', 'bar'];
|
|
2
|
+
export const appHeaderBarClass = 'sw-app-header-bar';
|
|
3
|
+
const bar = `.${appHeaderBarClass}`;
|
|
4
|
+
/*
|
|
5
|
+
* A bar header: the surface with no blur or specular line, no radius, and
|
|
6
|
+
* the border hairline under it only. One class, emitted after the glass
|
|
7
|
+
* header, so it wins by order; the Box border classes are emitted later
|
|
8
|
+
* still, so a Box `border` prop on the header wins over it, as on any
|
|
9
|
+
* Box-based frame. Reduce Transparency sets the same surface. Forced
|
|
10
|
+
* colors keep the hairline.
|
|
11
|
+
*/
|
|
12
|
+
export function cssAppHeaderBarClasses() {
|
|
13
|
+
return `${bar} {
|
|
14
|
+
backdrop-filter: none;
|
|
15
|
+
-webkit-backdrop-filter: none;
|
|
16
|
+
background: var(--sw-color-surface);
|
|
17
|
+
border-color: var(--sw-color-border);
|
|
18
|
+
border-radius: 0;
|
|
19
|
+
border-style: solid;
|
|
20
|
+
border-width: 0 0 1px;
|
|
21
|
+
box-shadow: none;
|
|
22
|
+
}`;
|
|
23
|
+
}
|
|
24
|
+
export function appHeaderBarClassCatalog() {
|
|
25
|
+
return [appHeaderBarClass];
|
|
26
|
+
}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `true` (solid) or `'dashed'` draws the hairline all round; `'bottom'`
|
|
3
|
+
* draws it under the box only, for a full-width bar such as a header or a
|
|
4
|
+
* section's sub-navigation.
|
|
5
|
+
*/
|
|
6
|
+
export type BoxBorderValue = boolean | 'dashed' | 'bottom';
|
|
2
7
|
/** The generated class for a Box `border` prop, or none for `false`. */
|
|
3
8
|
export declare function boxBorderClass(border: BoxBorderValue | undefined): string | undefined;
|
|
4
9
|
export declare function cssBoxBorderClasses(): string;
|
|
@@ -6,8 +6,11 @@ function borderClass(style) {
|
|
|
6
6
|
export function boxBorderClass(border) {
|
|
7
7
|
if (!border)
|
|
8
8
|
return undefined;
|
|
9
|
+
if (border === 'bottom')
|
|
10
|
+
return bottomBorderClass;
|
|
9
11
|
return borderClass(border === 'dashed' ? 'dashed' : 'solid');
|
|
10
12
|
}
|
|
13
|
+
const bottomBorderClass = 'sw-border-bottom';
|
|
11
14
|
/*
|
|
12
15
|
* A Box `border` is a token hairline. These rules are emitted after every
|
|
13
16
|
* component rule so that, at equal specificity, the prop still wins over a
|
|
@@ -15,10 +18,11 @@ export function boxBorderClass(border) {
|
|
|
15
18
|
* forced colors the system border color replaces the token and the style stays.
|
|
16
19
|
*/
|
|
17
20
|
export function cssBoxBorderClasses() {
|
|
18
|
-
return
|
|
19
|
-
.map((style) => `.${borderClass(style)} { border: 1px ${style} var(--sw-color-border); }`)
|
|
20
|
-
|
|
21
|
+
return [
|
|
22
|
+
...borderStyles.map((style) => `.${borderClass(style)} { border: 1px ${style} var(--sw-color-border); }`),
|
|
23
|
+
`.${bottomBorderClass} { border-width: 0 0 1px; border-style: solid; border-color: var(--sw-color-border); }`,
|
|
24
|
+
].join('\n');
|
|
21
25
|
}
|
|
22
26
|
export function boxBorderClassCatalog() {
|
|
23
|
-
return borderStyles.map(borderClass);
|
|
27
|
+
return [...borderStyles.map(borderClass), bottomBorderClass];
|
|
24
28
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { breakpointQuery } from './breakpoints.js';
|
|
2
|
+
import { buttonGroupTrackClassCatalog, cssButtonGroupTrackClasses, } from './css-button-group-track.js';
|
|
2
3
|
import { joinedZIndex } from './stacking.js';
|
|
3
4
|
/*
|
|
4
5
|
* An attached ButtonGroup is one joined control, such as Previous, Today
|
|
@@ -63,8 +64,10 @@ ${group} > .sw-button:focus-visible {
|
|
|
63
64
|
@media ${breakpointQuery('below', 'md')} {
|
|
64
65
|
${group} { align-items: stretch; flex-direction: row; }
|
|
65
66
|
${group} > * { width: auto; }
|
|
66
|
-
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
${cssButtonGroupTrackClasses()}`;
|
|
67
70
|
}
|
|
68
71
|
export function buttonGroupAttachedClassCatalog() {
|
|
69
|
-
return ['sw-button-group-attached'];
|
|
72
|
+
return ['sw-button-group-attached', ...buttonGroupTrackClassCatalog()];
|
|
70
73
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const buttonGroupAppearances: readonly ["default", "track"];
|
|
2
|
+
/**
|
|
3
|
+
* How an attached ButtonGroup is drawn: `default` keeps each button's own
|
|
4
|
+
* fill and outline, joined; `track` sets the buttons as words on one
|
|
5
|
+
* quiet grey track, a hairline between them, such as Previous, Today and
|
|
6
|
+
* Next above a day.
|
|
7
|
+
*/
|
|
8
|
+
export type ButtonGroupAppearance = (typeof buttonGroupAppearances)[number];
|
|
9
|
+
export declare const buttonGroupTrackClass = "sw-button-group-track";
|
|
10
|
+
export declare function cssButtonGroupTrackClasses(): string;
|
|
11
|
+
export declare function buttonGroupTrackClassCatalog(): string[];
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { quietFill } from './quiet-fill.js';
|
|
2
|
+
export const buttonGroupAppearances = ['default', 'track'];
|
|
3
|
+
export const buttonGroupTrackClass = 'sw-button-group-track';
|
|
4
|
+
const track = `.sw-button-group.sw-button-group-attached.${buttonGroupTrackClass}`;
|
|
5
|
+
/*
|
|
6
|
+
* The track: the attached group takes the quiet fill and the sm radius
|
|
7
|
+
* (its buttons' outer corners already are), and every button in it loses
|
|
8
|
+
* its own fill and outline to take its words in the text color. The
|
|
9
|
+
* divider between two buttons is a border hairline at full height, after
|
|
10
|
+
* the attached group's tinted divider (one more class, so it wins at the
|
|
11
|
+
* same place); it is the second button's start border, so the one before
|
|
12
|
+
* a disabled button fades with it. The divider is the canvas hairline
|
|
13
|
+
* (about 1.2:1 on the track, as the board draws it; fainter on a dark
|
|
14
|
+
* card). A pressed button keeps its ring and a focused one its outline,
|
|
15
|
+
* over the track. A disabled button fades, `disabledAppearance="neutral"`
|
|
16
|
+
* included (its muted words would read as enabled ones here). Forced
|
|
17
|
+
* colors outline the track, keep every border and draw a pressed button's
|
|
18
|
+
* border in Highlight. A track is for equal-weight navigation: every
|
|
19
|
+
* variant's meaning goes, so keep a primary or destructive action out of it.
|
|
20
|
+
*/
|
|
21
|
+
export function cssButtonGroupTrackClasses() {
|
|
22
|
+
return `${track} {
|
|
23
|
+
background: ${quietFill};
|
|
24
|
+
border-radius: var(--sw-radius-sm);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
${track} > .sw-button {
|
|
28
|
+
background: transparent;
|
|
29
|
+
border-color: transparent;
|
|
30
|
+
color: var(--sw-color-text);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
${track} > .sw-button + .sw-button {
|
|
34
|
+
border-inline-start-color: var(--sw-color-border);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
${track} > .sw-button:disabled {
|
|
38
|
+
opacity: var(--sw-disabled-opacity);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@media (forced-colors: active) {
|
|
42
|
+
${track} { outline: 1px solid CanvasText; }
|
|
43
|
+
${track} > .sw-button[aria-pressed='true'] { border-color: Highlight; }
|
|
44
|
+
}`;
|
|
45
|
+
}
|
|
46
|
+
export function buttonGroupTrackClassCatalog() {
|
|
47
|
+
return [buttonGroupTrackClass];
|
|
48
|
+
}
|
package/dist/css/css-button.d.ts
CHANGED
|
@@ -1,7 +1,24 @@
|
|
|
1
|
-
import { type ButtonSize
|
|
1
|
+
import { type ButtonSize } from '@scalewing/tokens';
|
|
2
|
+
/**
|
|
3
|
+
* The web Button's variants: the shared tiers from `@scalewing/tokens`, plus
|
|
4
|
+
* `neutral`, a quiet grey fill in the text color for an action beside the
|
|
5
|
+
* primary that should not draw the eye (a Cancel on a sheet). Native has no
|
|
6
|
+
* `neutral` yet.
|
|
7
|
+
*/
|
|
8
|
+
export declare const webButtonVariants: readonly ["primary", "secondary", "tertiary", "ghost", "danger", "neutral"];
|
|
9
|
+
export type WebButtonVariant = (typeof webButtonVariants)[number];
|
|
10
|
+
export declare const buttonDisabledAppearances: readonly ["faded", "neutral"];
|
|
11
|
+
/**
|
|
12
|
+
* How a disabled button looks: `faded` (the default) fades the variant as
|
|
13
|
+
* any disabled control; `neutral` draws a filled button on the quiet grey
|
|
14
|
+
* fill with muted words, whatever its variant (a ghost button, which has
|
|
15
|
+
* no fill, still fades).
|
|
16
|
+
*/
|
|
17
|
+
export type ButtonDisabledAppearance = (typeof buttonDisabledAppearances)[number];
|
|
2
18
|
export declare function buttonClassNames(options: {
|
|
3
19
|
size: ButtonSize;
|
|
4
|
-
variant:
|
|
20
|
+
variant: WebButtonVariant;
|
|
21
|
+
disabledAppearance?: ButtonDisabledAppearance;
|
|
5
22
|
}): string[];
|
|
6
23
|
export declare const pressedRingGap = 2;
|
|
7
24
|
export declare const pressedRingWidth = 4;
|
package/dist/css/css-button.js
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { buttonSizes, buttonVariants, controlScale, typographyVariants, } from '@scalewing/tokens';
|
|
2
2
|
import { breakpointQuery } from './breakpoints.js';
|
|
3
3
|
import { buttonGroupAttachedClassCatalog, cssButtonGroupAttachedClasses, } from './css-button-group-attached.js';
|
|
4
|
+
import { quietFill } from './quiet-fill.js';
|
|
4
5
|
const label = typographyVariants.label;
|
|
6
|
+
/**
|
|
7
|
+
* The web Button's variants: the shared tiers from `@scalewing/tokens`, plus
|
|
8
|
+
* `neutral`, a quiet grey fill in the text color for an action beside the
|
|
9
|
+
* primary that should not draw the eye (a Cancel on a sheet). Native has no
|
|
10
|
+
* `neutral` yet.
|
|
11
|
+
*/
|
|
12
|
+
export const webButtonVariants = [...buttonVariants, 'neutral'];
|
|
13
|
+
export const buttonDisabledAppearances = ['faded', 'neutral'];
|
|
5
14
|
export function buttonClassNames(options) {
|
|
6
15
|
return [
|
|
7
16
|
'sw-button',
|
|
8
17
|
`sw-button-${options.variant}`,
|
|
9
18
|
`sw-button-${options.size}`,
|
|
19
|
+
...(options.disabledAppearance === 'neutral'
|
|
20
|
+
? ['sw-button-disabled-neutral']
|
|
21
|
+
: []),
|
|
10
22
|
];
|
|
11
23
|
}
|
|
12
24
|
function variantRules() {
|
|
@@ -16,8 +28,24 @@ function variantRules() {
|
|
|
16
28
|
`.sw-button-tertiary { background: var(--sw-color-tertiary); border-color: transparent; color: var(--sw-color-onTertiary); }`,
|
|
17
29
|
`.sw-button-ghost { background: transparent; border-color: transparent; color: var(--sw-color-accent); }`,
|
|
18
30
|
`.sw-button-danger { background: var(--sw-color-danger); border-color: transparent; color: var(--sw-color-onDanger); }`,
|
|
31
|
+
`.sw-button-neutral { background: ${quietFill}; border-color: transparent; color: var(--sw-color-text); }`,
|
|
19
32
|
].join('\n');
|
|
20
33
|
}
|
|
34
|
+
/*
|
|
35
|
+
* A neutral disabled button: the quiet fill with its words in the muted
|
|
36
|
+
* color at 48 %, about #AEAEAE on the grey (a disabled control needs no
|
|
37
|
+
* contrast, and the faded words say it cannot be pressed), at full
|
|
38
|
+
* opacity so no accent shows through.
|
|
39
|
+
* Forced colors draw it as any disabled button.
|
|
40
|
+
*/
|
|
41
|
+
function disabledNeutralRules() {
|
|
42
|
+
return `.sw-button-disabled-neutral:disabled:not(.sw-button-ghost) {
|
|
43
|
+
background: ${quietFill};
|
|
44
|
+
border-color: transparent;
|
|
45
|
+
color: color-mix(in srgb, var(--sw-color-muted) 48%, transparent);
|
|
46
|
+
opacity: 1;
|
|
47
|
+
}`;
|
|
48
|
+
}
|
|
21
49
|
/*
|
|
22
50
|
* A toggle button's pressed state is an accent ring drawn outside the fill,
|
|
23
51
|
* past a 2 px gap in the page background: the ring meets the background on
|
|
@@ -92,6 +120,7 @@ export function cssButtonClasses() {
|
|
|
92
120
|
}
|
|
93
121
|
|
|
94
122
|
${variantRules()}
|
|
123
|
+
${disabledNeutralRules()}
|
|
95
124
|
${pressedRules()}
|
|
96
125
|
${sizeRules()}
|
|
97
126
|
${groupRules()}
|
|
@@ -118,7 +147,8 @@ function groupRules() {
|
|
|
118
147
|
export function buttonClassCatalog() {
|
|
119
148
|
return [
|
|
120
149
|
'sw-button',
|
|
121
|
-
...
|
|
150
|
+
...webButtonVariants.map((variant) => `sw-button-${variant}`),
|
|
151
|
+
'sw-button-disabled-neutral',
|
|
122
152
|
...buttonSizes.map((size) => `sw-button-${size}`),
|
|
123
153
|
'sw-button-group',
|
|
124
154
|
...buttonGroupJustifies.map((name) => `sw-button-group-${name}`),
|
package/dist/css/css-chrome.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { appHeaderBarClassCatalog, cssAppHeaderBarClasses, } from './css-app-header-bar.js';
|
|
3
|
+
import { cssNavWordsClasses, navWordsClassCatalog } from './css-nav-words.js';
|
|
2
4
|
import { zIndex } from './stacking.js';
|
|
3
5
|
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
4
6
|
const caption = typographyVariants.caption;
|
|
@@ -13,6 +15,8 @@ export function cssChromeClasses() {
|
|
|
13
15
|
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
14
16
|
}
|
|
15
17
|
|
|
18
|
+
${cssAppHeaderBarClasses()}
|
|
19
|
+
|
|
16
20
|
.sw-app-header-sticky {
|
|
17
21
|
position: sticky;
|
|
18
22
|
top: 0;
|
|
@@ -49,6 +53,8 @@ export function cssChromeClasses() {
|
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
|
|
56
|
+
${cssNavWordsClasses()}
|
|
57
|
+
|
|
52
58
|
.sw-field-xs :is(select, input, textarea) {
|
|
53
59
|
font-size: ${caption.fontSize}px;
|
|
54
60
|
letter-spacing: ${caption.letterSpacing}px;
|
|
@@ -68,5 +74,12 @@ export function cssChromeClasses() {
|
|
|
68
74
|
}`;
|
|
69
75
|
}
|
|
70
76
|
export function chromeClassCatalog() {
|
|
71
|
-
return [
|
|
77
|
+
return [
|
|
78
|
+
'sw-app-header',
|
|
79
|
+
'sw-app-header-sticky',
|
|
80
|
+
...appHeaderBarClassCatalog(),
|
|
81
|
+
'sw-nav',
|
|
82
|
+
...navWordsClassCatalog(),
|
|
83
|
+
'sw-field-xs',
|
|
84
|
+
];
|
|
72
85
|
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { zIndex } from './stacking.js';
|
|
3
|
+
import { quietFill } from './quiet-fill.js';
|
|
4
|
+
const caption = typographyVariants.caption;
|
|
5
|
+
const label = typographyVariants.label;
|
|
6
|
+
/*
|
|
7
|
+
* The combobox input is a Field's input. Its list is a glass popover on
|
|
8
|
+
* the popup layer (as Select's list), at least as wide as the input: a
|
|
9
|
+
* caption heading per group, then options at the md control height with
|
|
10
|
+
* the label, a badge and a muted description on one wrapping line. The
|
|
11
|
+
* active option (the one aria-activedescendant names) takes the soft
|
|
12
|
+
* muted fill; a hairline parts each option from the one before it, as
|
|
13
|
+
* the boards draw it; a disabled option is muted and not pressable; the action
|
|
14
|
+
* ends the list in the accent colour over a hairline. The empty text and
|
|
15
|
+
* the note are muted captions under the list.
|
|
16
|
+
*/
|
|
17
|
+
export function cssComboboxClasses() {
|
|
18
|
+
return `.sw-combobox {
|
|
19
|
+
max-width: 100%;
|
|
20
|
+
min-width: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.sw-combobox-popup {
|
|
24
|
+
background: var(--sw-glass-fill);
|
|
25
|
+
border: 1px solid var(--sw-glass-border);
|
|
26
|
+
border-radius: var(--sw-radius-sm);
|
|
27
|
+
box-shadow: var(--sw-elevation-sm), inset 0 1px 0 var(--sw-glass-specular);
|
|
28
|
+
backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
29
|
+
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
30
|
+
box-sizing: border-box;
|
|
31
|
+
color: var(--sw-color-text);
|
|
32
|
+
inset: auto;
|
|
33
|
+
margin: 0;
|
|
34
|
+
max-height: min(var(--sw-select-max), calc(100% - var(--sw-space-2) - var(--sw-space-2)));
|
|
35
|
+
max-width: calc(100% - var(--sw-space-2) - var(--sw-space-2));
|
|
36
|
+
overflow: auto;
|
|
37
|
+
padding: var(--sw-space-1);
|
|
38
|
+
position: fixed;
|
|
39
|
+
${zIndex('popup')}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.sw-combobox-heading {
|
|
43
|
+
color: var(--sw-color-muted);
|
|
44
|
+
font-family: var(--sw-font-sans);
|
|
45
|
+
font-size: ${caption.fontSize}px;
|
|
46
|
+
font-weight: ${label.fontWeight};
|
|
47
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
48
|
+
line-height: ${caption.lineHeight}px;
|
|
49
|
+
padding: var(--sw-space-2) var(--sw-space-3) var(--sw-space-1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.sw-combobox-option {
|
|
53
|
+
align-items: center;
|
|
54
|
+
border-radius: var(--sw-radius-sm);
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
column-gap: var(--sw-space-2);
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-wrap: wrap;
|
|
60
|
+
font-family: var(--sw-font-sans);
|
|
61
|
+
font-size: ${label.fontSize}px;
|
|
62
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
63
|
+
line-height: ${label.lineHeight}px;
|
|
64
|
+
min-height: var(--sw-control-md-min-height);
|
|
65
|
+
overflow-wrap: anywhere;
|
|
66
|
+
padding: var(--sw-space-1) var(--sw-space-3);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.sw-combobox-option + .sw-combobox-option {
|
|
70
|
+
border-top: 1px solid var(--sw-color-border);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.sw-combobox-label {
|
|
74
|
+
font-weight: ${label.fontWeight};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.sw-combobox-description {
|
|
78
|
+
color: var(--sw-color-muted);
|
|
79
|
+
font-size: ${caption.fontSize}px;
|
|
80
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
81
|
+
line-height: ${caption.lineHeight}px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sw-combobox-option[aria-selected='true'] {
|
|
85
|
+
background: ${quietFill};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.sw-combobox-option[aria-disabled='true'] {
|
|
89
|
+
cursor: not-allowed;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.sw-combobox-option[aria-disabled='true'] .sw-combobox-label {
|
|
93
|
+
color: var(--sw-color-muted);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.sw-combobox-action {
|
|
97
|
+
border-top: 1px solid var(--sw-color-border);
|
|
98
|
+
color: var(--sw-color-accent);
|
|
99
|
+
margin-top: var(--sw-space-1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.sw-combobox-empty,
|
|
103
|
+
.sw-combobox-note {
|
|
104
|
+
color: var(--sw-color-muted);
|
|
105
|
+
font-family: var(--sw-font-sans);
|
|
106
|
+
font-size: ${caption.fontSize}px;
|
|
107
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
108
|
+
line-height: ${caption.lineHeight}px;
|
|
109
|
+
padding: var(--sw-space-2) var(--sw-space-3);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@media (forced-colors: active) {
|
|
113
|
+
.sw-combobox-popup { border-color: CanvasText; }
|
|
114
|
+
.sw-combobox-option[aria-selected='true'] { background: Highlight; color: HighlightText; forced-color-adjust: none; }
|
|
115
|
+
.sw-combobox-option[aria-selected='true'] .sw-combobox-description { color: HighlightText; }
|
|
116
|
+
.sw-combobox-option[aria-selected='true'] .sw-badge { forced-color-adjust: auto; }
|
|
117
|
+
.sw-combobox-option[aria-disabled='true'] .sw-combobox-label { color: GrayText; }
|
|
118
|
+
.sw-combobox-option[aria-selected='true'][aria-disabled='true'] .sw-combobox-label { color: HighlightText; }
|
|
119
|
+
.sw-combobox-option + .sw-combobox-option { border-color: CanvasText; }
|
|
120
|
+
.sw-combobox-action { border-color: CanvasText; }
|
|
121
|
+
}`;
|
|
122
|
+
}
|
|
123
|
+
export function comboboxClassCatalog() {
|
|
124
|
+
return [
|
|
125
|
+
'sw-combobox',
|
|
126
|
+
'sw-combobox-popup',
|
|
127
|
+
'sw-combobox-list',
|
|
128
|
+
'sw-combobox-heading',
|
|
129
|
+
'sw-combobox-option',
|
|
130
|
+
'sw-combobox-label',
|
|
131
|
+
'sw-combobox-description',
|
|
132
|
+
'sw-combobox-action',
|
|
133
|
+
'sw-combobox-empty',
|
|
134
|
+
'sw-combobox-note',
|
|
135
|
+
];
|
|
136
|
+
}
|
|
@@ -13,7 +13,9 @@ import { cssSegmentedClasses } from './css-segmented.js';
|
|
|
13
13
|
import { cssTableClasses } from './css-table.js';
|
|
14
14
|
import { cssDateFieldClasses } from './css-date-field.js';
|
|
15
15
|
import { cssDialogClasses } from './css-dialog.js';
|
|
16
|
+
import { cssDialogBandedClasses } from './css-dialog-banded.js';
|
|
16
17
|
import { cssDialogFrameClasses } from './css-dialog-frame.js';
|
|
18
|
+
import { cssComboboxClasses } from './css-combobox.js';
|
|
17
19
|
import { cssSelectClasses } from './css-select.js';
|
|
18
20
|
import { cssMultiSelectClasses } from './css-multi-select.js';
|
|
19
21
|
import { cssSplitClasses } from './css-split.js';
|
|
@@ -64,6 +66,7 @@ function reducedTransparencyRules() {
|
|
|
64
66
|
.sw-select-list,
|
|
65
67
|
.sw-action-menu-list,
|
|
66
68
|
.sw-multi-select-panel,
|
|
69
|
+
.sw-combobox-popup,
|
|
67
70
|
.sw-date-field-calendar,
|
|
68
71
|
.sw-toast {
|
|
69
72
|
background: var(--sw-color-surface);
|
|
@@ -142,12 +145,15 @@ ${cssDialogClasses()}
|
|
|
142
145
|
|
|
143
146
|
${cssDialogFrameClasses()}
|
|
144
147
|
|
|
148
|
+
${cssDialogBandedClasses()}
|
|
149
|
+
|
|
145
150
|
${cssAccordionClasses()}
|
|
146
151
|
|
|
147
152
|
${cssSelectClasses()}
|
|
148
153
|
|
|
149
154
|
${cssActionMenuClasses()}
|
|
150
155
|
|
|
156
|
+
${cssComboboxClasses()}
|
|
151
157
|
${cssMultiSelectClasses()}
|
|
152
158
|
|
|
153
159
|
${cssActionBarClasses()}
|
package/dist/css/css-data.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { webButtonVariants } from './css-button.js';
|
|
2
3
|
export const badgeTones = [
|
|
3
4
|
'neutral',
|
|
4
5
|
'accent',
|
|
@@ -20,7 +21,7 @@ export function badgeClassNames(tone, size = 'md') {
|
|
|
20
21
|
* button has no fill.
|
|
21
22
|
*/
|
|
22
23
|
function badgeOnFilledButtonRules() {
|
|
23
|
-
const filled =
|
|
24
|
+
const filled = webButtonVariants
|
|
24
25
|
.filter((variant) => variant !== 'ghost')
|
|
25
26
|
.map((variant) => `.sw-button-${variant}`)
|
|
26
27
|
.join(', ');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
2
|
import { disabledControlForcedColors, disabledControlSurface, } from './css-document.js';
|
|
3
3
|
import { zIndex } from './stacking.js';
|
|
4
|
+
import { quietFill } from './quiet-fill.js';
|
|
4
5
|
const body = typographyVariants.body;
|
|
5
6
|
const label = typographyVariants.label;
|
|
6
7
|
const caption = typographyVariants.caption;
|
|
@@ -226,7 +227,7 @@ function calendarRules() {
|
|
|
226
227
|
|
|
227
228
|
.sw-date-field-step:hover:not([aria-disabled='true']),
|
|
228
229
|
.sw-date-field-day:hover:not([aria-disabled='true']) {
|
|
229
|
-
background:
|
|
230
|
+
background: ${quietFill};
|
|
230
231
|
}
|
|
231
232
|
|
|
232
233
|
/*
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const denominationGridFrames: readonly ["none", "table"];
|
|
2
|
+
/**
|
|
3
|
+
* How a strip sits on the page: `none` (the default) is open rows on the
|
|
4
|
+
* page's own surface; `table` is a framed table: the surface inside a
|
|
5
|
+
* hairline with rounded corners, the heading row on the subtle fill, a
|
|
6
|
+
* rule between columns, and the counts at label size, centred under
|
|
7
|
+
* their heads.
|
|
8
|
+
*/
|
|
9
|
+
export type DenominationGridFrame = (typeof denominationGridFrames)[number];
|
|
10
|
+
export declare const denominationTotalEmphases: readonly ["default", "strong"];
|
|
11
|
+
/**
|
|
12
|
+
* How the row totals read: `default` is data type in the row's tone (a
|
|
13
|
+
* neutral row's muted); `strong` is label type in bold, a neutral row's in
|
|
14
|
+
* the text color and a toned row's in its tone.
|
|
15
|
+
*/
|
|
16
|
+
export type DenominationTotalEmphasis = (typeof denominationTotalEmphases)[number];
|
|
17
|
+
export declare const denominationFramedClass = "sw-denomination-framed";
|
|
18
|
+
export declare const denominationScrollFramedClass = "sw-denomination-scroll-framed";
|
|
19
|
+
export declare const denominationTotalsStrongClass = "sw-denomination-totals-strong";
|
|
20
|
+
export declare function cssDenominationAppearanceClasses(): string;
|
|
21
|
+
export declare function denominationAppearanceClassCatalog(): string[];
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { breakpointQuery } from './breakpoints.js';
|
|
3
|
+
const label = typographyVariants.label;
|
|
4
|
+
export const denominationGridFrames = ['none', 'table'];
|
|
5
|
+
export const denominationTotalEmphases = ['default', 'strong'];
|
|
6
|
+
export const denominationFramedClass = 'sw-denomination-framed';
|
|
7
|
+
export const denominationScrollFramedClass = 'sw-denomination-scroll-framed';
|
|
8
|
+
export const denominationTotalsStrongClass = 'sw-denomination-totals-strong';
|
|
9
|
+
const framed = `.sw-denomination-strip.${denominationFramedClass}`;
|
|
10
|
+
const strong = `.${denominationTotalsStrongClass}`;
|
|
11
|
+
/*
|
|
12
|
+
* A framed strip. The frame is the scroll region's border, so it stays put
|
|
13
|
+
* while a wide strip scrolls inside it and its shades still draw on the
|
|
14
|
+
* region's own shadow. The cells pad a space-3 step across (space-2 below
|
|
15
|
+
* md) and the body cells a space-4 step down, so a read-only row is about
|
|
16
|
+
* as tall as an entry row; the cell padding is zero-specificity past the
|
|
17
|
+
* frame class, so an entry cell keeps its own space-1 padding and, below
|
|
18
|
+
* md, the collapsed total column is collapsed again. The row labels pad
|
|
19
|
+
* the same step whatever their appearance. The pinned label sits on the
|
|
20
|
+
* surface at the same low specificity, so a quiet row's label keeps the
|
|
21
|
+
* subtle fill; the pinned corner takes the heading row's fill. The column
|
|
22
|
+
* rule is a border on every cell after a row's first, so forced colours
|
|
23
|
+
* keep it and RTL mirrors it; the collapsed total column draws none.
|
|
24
|
+
* Emitted after the grid's own rules, its label appearances and its
|
|
25
|
+
* narrow-screen padding, so it wins at every width.
|
|
26
|
+
*/
|
|
27
|
+
function frameRules() {
|
|
28
|
+
return `.${denominationScrollFramedClass} {
|
|
29
|
+
background: var(--sw-color-surface);
|
|
30
|
+
border: 1px solid var(--sw-color-border);
|
|
31
|
+
border-radius: var(--sw-radius-sm);
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
${framed} :where(th, td) {
|
|
36
|
+
padding: var(--sw-space-4) var(--sw-space-3);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
${framed} thead :where(th, td),
|
|
40
|
+
${framed} thead .sw-denomination-corner:first-child {
|
|
41
|
+
background: var(--sw-color-subtle);
|
|
42
|
+
padding-block: var(--sw-space-2);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
${framed} :is(th, td) + :is(th, td) {
|
|
46
|
+
border-inline-start: 1px solid var(--sw-color-border);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
${framed} :where(.sw-denomination-label) {
|
|
50
|
+
backdrop-filter: none;
|
|
51
|
+
-webkit-backdrop-filter: none;
|
|
52
|
+
background: var(--sw-color-surface);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
${framed} .sw-denomination-label {
|
|
56
|
+
padding-inline: var(--sw-space-3);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
${framed} .sw-denomination-head:not(.sw-denomination-total-head),
|
|
60
|
+
${framed} .sw-denomination-cell {
|
|
61
|
+
text-align: center;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
${framed} .sw-denomination-cell {
|
|
65
|
+
font-size: ${label.fontSize}px;
|
|
66
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
67
|
+
line-height: ${label.lineHeight}px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media ${breakpointQuery('below', 'md')} {
|
|
71
|
+
${framed} :where(th, td),
|
|
72
|
+
${framed} .sw-denomination-label { padding-inline: var(--sw-space-2); }
|
|
73
|
+
${framed} .sw-denomination-total,
|
|
74
|
+
${framed} .sw-denomination-total-head { border-inline-start: 0; padding: 0; }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (forced-colors: active) {
|
|
78
|
+
.${denominationScrollFramedClass},
|
|
79
|
+
${framed} :is(th, td) + :is(th, td) { border-color: CanvasText; }
|
|
80
|
+
}`;
|
|
81
|
+
}
|
|
82
|
+
/*
|
|
83
|
+
* Strong totals: label type in bold, a neutral row's in the text color
|
|
84
|
+
* (its tone is the muted color) and a toned row's left in its tone, under
|
|
85
|
+
* the label on a phone too. One class more specific than the plain
|
|
86
|
+
* labels' inline total, so a neutral row's total is the text color there.
|
|
87
|
+
*/
|
|
88
|
+
function totalRules() {
|
|
89
|
+
return `${strong} .sw-denomination-total {
|
|
90
|
+
font-size: ${label.fontSize}px;
|
|
91
|
+
font-weight: 700;
|
|
92
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
93
|
+
line-height: ${label.lineHeight}px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
${strong} .sw-denomination-total-inline { font-weight: 700; }
|
|
97
|
+
|
|
98
|
+
${strong} .sw-denomination-row-neutral .sw-denomination-total,
|
|
99
|
+
${strong} .sw-denomination-row-neutral .sw-denomination-total-inline {
|
|
100
|
+
color: var(--sw-color-text);
|
|
101
|
+
}`;
|
|
102
|
+
}
|
|
103
|
+
export function cssDenominationAppearanceClasses() {
|
|
104
|
+
return `${frameRules()}
|
|
105
|
+
|
|
106
|
+
${totalRules()}`;
|
|
107
|
+
}
|
|
108
|
+
export function denominationAppearanceClassCatalog() {
|
|
109
|
+
return [
|
|
110
|
+
denominationScrollFramedClass,
|
|
111
|
+
denominationFramedClass,
|
|
112
|
+
denominationTotalsStrongClass,
|
|
113
|
+
];
|
|
114
|
+
}
|