@scalewing/react 1.46.0 → 1.48.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 +74 -0
- package/README.md +228 -4
- package/dist/app-shell.test-support.d.ts +5 -0
- package/dist/app-shell.test-support.js +45 -0
- package/dist/command-palette.test-support.d.ts +21 -0
- package/dist/command-palette.test-support.js +55 -0
- package/dist/components/AppHeader.d.ts +3 -0
- package/dist/components/AppShell.d.ts +13 -0
- package/dist/components/AppShell.js +65 -0
- package/dist/components/Band.d.ts +30 -0
- package/dist/components/Band.js +23 -0
- package/dist/components/ButtonLink.d.ts +33 -0
- package/dist/components/ButtonLink.js +27 -0
- package/dist/components/CommandPalette.d.ts +12 -0
- package/dist/components/CommandPalette.js +143 -0
- package/dist/components/CommandPaletteTrigger.d.ts +9 -0
- package/dist/components/CommandPaletteTrigger.js +16 -0
- package/dist/components/ContextSwitcher.d.ts +12 -0
- package/dist/components/ContextSwitcher.js +62 -0
- package/dist/components/FixtureGroup.d.ts +9 -0
- package/dist/components/FixtureGroup.js +16 -0
- package/dist/components/FixtureRow.d.ts +10 -0
- package/dist/components/FixtureRow.js +46 -0
- package/dist/components/GlyphTile.d.ts +9 -3
- package/dist/components/GlyphTile.js +15 -4
- package/dist/components/NavCount.d.ts +12 -5
- package/dist/components/NavCount.js +9 -4
- package/dist/components/SectionNav.d.ts +2 -1
- package/dist/components/SectionNav.js +3 -19
- package/dist/components/SiteFooter.d.ts +12 -0
- package/dist/components/SiteFooter.js +23 -0
- package/dist/components/SiteHeader.d.ts +14 -0
- package/dist/components/SiteHeader.js +24 -0
- package/dist/components/Skeleton.d.ts +22 -0
- package/dist/components/Skeleton.js +30 -0
- package/dist/components/app-shell/AppShellBar.d.ts +23 -0
- package/dist/components/app-shell/AppShellBar.js +25 -0
- package/dist/components/app-shell/AppShellDrawer.d.ts +24 -0
- package/dist/components/app-shell/AppShellDrawer.js +17 -0
- package/dist/components/app-shell/AppShellLink.d.ts +14 -0
- package/dist/components/app-shell/AppShellLink.js +27 -0
- package/dist/components/app-shell/AppShellNav.d.ts +15 -0
- package/dist/components/app-shell/AppShellNav.js +29 -0
- package/dist/components/app-shell/AppShellSidebar.d.ts +18 -0
- package/dist/components/app-shell/AppShellSidebar.js +18 -0
- package/dist/components/app-shell/types.d.ts +122 -0
- package/dist/components/app-shell/types.js +1 -0
- package/dist/components/app-shell/validate.d.ts +7 -0
- package/dist/components/app-shell/validate.js +70 -0
- package/dist/components/command-palette/PaletteList.d.ts +20 -0
- package/dist/components/command-palette/PaletteList.js +21 -0
- package/dist/components/command-palette/shortcut.d.ts +19 -0
- package/dist/components/command-palette/shortcut.js +75 -0
- package/dist/components/command-palette/types.d.ts +72 -0
- package/dist/components/command-palette/types.js +2 -0
- package/dist/components/command-palette/validate.d.ts +10 -0
- package/dist/components/command-palette/validate.js +50 -0
- package/dist/components/context-switcher/SwitcherOption.d.ts +17 -0
- package/dist/components/context-switcher/SwitcherOption.js +20 -0
- package/dist/components/context-switcher/SwitcherPopup.d.ts +31 -0
- package/dist/components/context-switcher/SwitcherPopup.js +111 -0
- package/dist/components/context-switcher/options.d.ts +33 -0
- package/dist/components/context-switcher/options.js +60 -0
- package/dist/components/context-switcher/types.d.ts +96 -0
- package/dist/components/context-switcher/types.js +1 -0
- package/dist/components/context-switcher/use-switcher-list.d.ts +29 -0
- package/dist/components/context-switcher/use-switcher-list.js +93 -0
- package/dist/components/context-switcher/validate.d.ts +8 -0
- package/dist/components/context-switcher/validate.js +94 -0
- package/dist/components/fixture/fixture-list-context.d.ts +4 -0
- package/dist/components/fixture/fixture-list-context.js +9 -0
- package/dist/components/fixture/types.d.ts +50 -0
- package/dist/components/fixture/types.js +1 -0
- package/dist/components/fixture/validate.d.ts +8 -0
- package/dist/components/fixture/validate.js +36 -0
- package/dist/components/nav-items.d.ts +21 -0
- package/dist/components/nav-items.js +26 -0
- package/dist/components/site-footer/types.d.ts +31 -0
- package/dist/components/site-footer/types.js +1 -0
- package/dist/components/site-footer/validate.d.ts +7 -0
- package/dist/components/site-footer/validate.js +22 -0
- package/dist/components/site-header/SiteHeaderLinks.d.ts +7 -0
- package/dist/components/site-header/SiteHeaderLinks.js +7 -0
- package/dist/components/site-header/types.d.ts +38 -0
- package/dist/components/site-header/types.js +1 -0
- package/dist/components/site-header/use-menu-dismiss.d.ts +8 -0
- package/dist/components/site-header/use-menu-dismiss.js +62 -0
- package/dist/components/site-header/validate.d.ts +7 -0
- package/dist/components/site-header/validate.js +17 -0
- package/dist/components/use-element-height.d.ts +10 -0
- package/dist/components/use-element-height.js +35 -0
- package/dist/context-switcher.test-support.d.ts +9 -0
- package/dist/context-switcher.test-support.js +41 -0
- package/dist/css/css-app-shell-drawer.d.ts +2 -0
- package/dist/css/css-app-shell-drawer.js +91 -0
- package/dist/css/css-app-shell-nav.d.ts +3 -0
- package/dist/css/css-app-shell-nav.js +167 -0
- package/dist/css/css-app-shell-page-bar.d.ts +3 -0
- package/dist/css/css-app-shell-page-bar.js +81 -0
- package/dist/css/css-app-shell.d.ts +4 -0
- package/dist/css/css-app-shell.js +155 -0
- package/dist/css/css-band.d.ts +10 -0
- package/dist/css/css-band.js +101 -0
- package/dist/css/css-button-link.d.ts +3 -0
- package/dist/css/css-button-link.js +48 -0
- package/dist/css/css-command-palette-key.d.ts +1 -0
- package/dist/css/css-command-palette-key.js +33 -0
- package/dist/css/css-command-palette-trigger.d.ts +2 -0
- package/dist/css/css-command-palette-trigger.js +88 -0
- package/dist/css/css-command-palette.d.ts +2 -0
- package/dist/css/css-command-palette.js +209 -0
- package/dist/css/css-components.js +27 -0
- package/dist/css/css-context-switcher-trigger.d.ts +15 -0
- package/dist/css/css-context-switcher-trigger.js +175 -0
- package/dist/css/css-context-switcher.d.ts +4 -0
- package/dist/css/css-context-switcher.js +219 -0
- package/dist/css/css-count-pill.d.ts +7 -0
- package/dist/css/css-count-pill.js +50 -12
- package/dist/css/css-fixture.d.ts +5 -0
- package/dist/css/css-fixture.js +260 -0
- package/dist/css/css-glyph-tile.d.ts +2 -0
- package/dist/css/css-glyph-tile.js +29 -1
- package/dist/css/css-site-footer.d.ts +2 -0
- package/dist/css/css-site-footer.js +152 -0
- package/dist/css/css-site-header.d.ts +2 -0
- package/dist/css/css-site-header.js +262 -0
- package/dist/css/css-skeleton.d.ts +10 -0
- package/dist/css/css-skeleton.js +110 -0
- package/dist/css/stacking.js +7 -4
- package/dist/css/stylesheet.js +18 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +11 -0
- package/dist/styles.css +2122 -512
- package/package.json +2 -2
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { cssChartToneClasses } from './chart-tones.js';
|
|
2
2
|
import { cssActionBarClasses } from './css-action-bar.js';
|
|
3
3
|
import { cssActionMenuClasses } from './css-action-menu.js';
|
|
4
|
+
import { cssCommandPaletteClasses } from './css-command-palette.js';
|
|
5
|
+
import { cssContextSwitcherClasses } from './css-context-switcher.js';
|
|
4
6
|
import { cssAccordionClasses } from './css-accordion.js';
|
|
5
7
|
import { cssButtonClasses } from './css-button.js';
|
|
8
|
+
import { cssButtonLinkClasses } from './css-button-link.js';
|
|
6
9
|
import { cssCalendarButtonClasses } from './css-calendar-button.js';
|
|
7
10
|
import { cssDateRangeClasses } from './css-date-range.js';
|
|
8
11
|
import { cssFileFieldClasses } from './css-file-field.js';
|
|
9
12
|
import { cssArticleClasses } from './css-article.js';
|
|
10
13
|
import { cssDocumentViewerClasses } from './css-document-viewer.js';
|
|
14
|
+
import { cssFixtureClasses } from './css-fixture.js';
|
|
11
15
|
import { cssListClasses } from './css-list.js';
|
|
12
16
|
import { cssMarkdownClasses } from './css-markdown.js';
|
|
13
17
|
import { cssCountPillClasses } from './css-count-pill.js';
|
|
@@ -21,6 +25,7 @@ import { cssCheckboxClasses } from './css-checkbox.js';
|
|
|
21
25
|
import { cssRadioGroupClasses } from './css-radio-group.js';
|
|
22
26
|
import { cssChromeClasses } from './css-chrome.js';
|
|
23
27
|
import { cssSectionNavClasses } from './css-section-nav.js';
|
|
28
|
+
import { cssAppShellClasses } from './css-app-shell.js';
|
|
24
29
|
import { cssDataClasses } from './css-data.js';
|
|
25
30
|
import { cssSegmentedClasses } from './css-segmented.js';
|
|
26
31
|
import { cssTableClasses } from './css-table.js';
|
|
@@ -37,6 +42,7 @@ import { cssSplitClasses } from './css-split.js';
|
|
|
37
42
|
import { cssSwitchClasses } from './css-switch.js';
|
|
38
43
|
import { cssTextClasses } from './css-text.js';
|
|
39
44
|
import { cssFontMonoClasses } from './css-font-mono.js';
|
|
45
|
+
import { cssSkeletonClasses } from './css-skeleton.js';
|
|
40
46
|
import { cssSpinnerClasses } from './css-spinner.js';
|
|
41
47
|
import { cssProgressClasses } from './css-progress.js';
|
|
42
48
|
import { cssNoticeClasses } from './css-notice.js';
|
|
@@ -44,6 +50,9 @@ import { cssGlyphTileClasses } from './css-glyph-tile.js';
|
|
|
44
50
|
import { cssTooltipClasses } from './css-tooltip.js';
|
|
45
51
|
import { cssInfoTipClasses } from './css-info-tip.js';
|
|
46
52
|
import { cssSeparatorClasses } from './css-separator.js';
|
|
53
|
+
import { cssBandClasses } from './css-band.js';
|
|
54
|
+
import { cssSiteFooterClasses } from './css-site-footer.js';
|
|
55
|
+
import { cssSiteHeaderClasses } from './css-site-header.js';
|
|
47
56
|
import { cssStatTileClasses } from './css-stat-tile.js';
|
|
48
57
|
import { cssDescriptionListClasses } from './css-description-list.js';
|
|
49
58
|
import { cssTabsClasses } from './css-tabs.js';
|
|
@@ -139,6 +148,8 @@ ${cssFontMonoClasses()}
|
|
|
139
148
|
|
|
140
149
|
${cssButtonClasses()}
|
|
141
150
|
|
|
151
|
+
${cssButtonLinkClasses()}
|
|
152
|
+
|
|
142
153
|
${cssCheckboxClasses()}
|
|
143
154
|
|
|
144
155
|
${cssRadioGroupClasses()}
|
|
@@ -157,6 +168,8 @@ ${cssDateRangeClasses()}
|
|
|
157
168
|
|
|
158
169
|
${cssListClasses()}
|
|
159
170
|
|
|
171
|
+
${cssFixtureClasses()}
|
|
172
|
+
|
|
160
173
|
${cssFileFieldClasses()}
|
|
161
174
|
|
|
162
175
|
${cssArticleClasses()}
|
|
@@ -185,6 +198,14 @@ ${cssChromeClasses()}
|
|
|
185
198
|
|
|
186
199
|
${cssSectionNavClasses()}
|
|
187
200
|
|
|
201
|
+
${cssBandClasses()}
|
|
202
|
+
|
|
203
|
+
${cssSiteFooterClasses()}
|
|
204
|
+
|
|
205
|
+
${cssSiteHeaderClasses()}
|
|
206
|
+
|
|
207
|
+
${cssAppShellClasses()}
|
|
208
|
+
|
|
188
209
|
${cssDialogClasses()}
|
|
189
210
|
|
|
190
211
|
${cssDialogFrameClasses()}
|
|
@@ -201,6 +222,10 @@ ${cssSelectClasses()}
|
|
|
201
222
|
|
|
202
223
|
${cssActionMenuClasses()}
|
|
203
224
|
|
|
225
|
+
${cssContextSwitcherClasses()}
|
|
226
|
+
|
|
227
|
+
${cssCommandPaletteClasses()}
|
|
228
|
+
|
|
204
229
|
${cssComboboxClasses()}
|
|
205
230
|
${cssMultiSelectClasses()}
|
|
206
231
|
|
|
@@ -210,6 +235,8 @@ ${cssSwitchClasses()}
|
|
|
210
235
|
|
|
211
236
|
${cssSpinnerClasses()}
|
|
212
237
|
|
|
238
|
+
${cssSkeletonClasses()}
|
|
239
|
+
|
|
213
240
|
${cssProgressClasses()}
|
|
214
241
|
|
|
215
242
|
${cssNoticeClasses()}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const contextSwitcherTriggerAppearances: readonly ["framed", "text", "pill", "icon"];
|
|
2
|
+
/**
|
|
3
|
+
* How a ContextSwitcher's trigger looks: `framed` (the default) is the
|
|
4
|
+
* outlined control; `text` is its content and a chevron with no fill until
|
|
5
|
+
* hovered or open; `pill` is a rounded outlined pill at label weight;
|
|
6
|
+
* `icon` is a glyph alone in a round quiet button with no chevron.
|
|
7
|
+
*/
|
|
8
|
+
export type ContextSwitcherTriggerAppearance = (typeof contextSwitcherTriggerAppearances)[number];
|
|
9
|
+
export declare const contextSwitcherWidths: readonly ["content", "full"];
|
|
10
|
+
/** `full` makes the trigger fill its column, such as a sidebar's top. */
|
|
11
|
+
export type ContextSwitcherWidth = (typeof contextSwitcherWidths)[number];
|
|
12
|
+
/** The modifier class of an appearance, such as `sw-context-switcher-trigger-pill`. */
|
|
13
|
+
export declare function contextSwitcherTriggerClass(appearance: ContextSwitcherTriggerAppearance): string;
|
|
14
|
+
export declare function cssContextSwitcherTriggerClasses(): string;
|
|
15
|
+
export declare function contextSwitcherTriggerClassCatalog(): string[];
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { chevronStroke } from './chevron.js';
|
|
3
|
+
import { quietFill } from './quiet-fill.js';
|
|
4
|
+
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
5
|
+
const label = typographyVariants.label;
|
|
6
|
+
export const contextSwitcherTriggerAppearances = [
|
|
7
|
+
'framed',
|
|
8
|
+
'text',
|
|
9
|
+
'pill',
|
|
10
|
+
'icon',
|
|
11
|
+
];
|
|
12
|
+
export const contextSwitcherWidths = ['content', 'full'];
|
|
13
|
+
/** The modifier class of an appearance, such as `sw-context-switcher-trigger-pill`. */
|
|
14
|
+
export function contextSwitcherTriggerClass(appearance) {
|
|
15
|
+
return `sw-context-switcher-trigger-${appearance}`;
|
|
16
|
+
}
|
|
17
|
+
const trigger = '.sw-context-switcher-trigger';
|
|
18
|
+
const framed = `${trigger}.${contextSwitcherTriggerClass('framed')}`;
|
|
19
|
+
const pill = `${trigger}.${contextSwitcherTriggerClass('pill')}`;
|
|
20
|
+
const icon = `${trigger}.${contextSwitcherTriggerClass('icon')}`;
|
|
21
|
+
/*
|
|
22
|
+
* Every trigger: a real button in label type in the text colour, its
|
|
23
|
+
* content (a mark and words, which may be two lines) taking the free space
|
|
24
|
+
* at the inline start, then the shared muted chevron pointing down; the sm
|
|
25
|
+
* control height, the 44 px target on a coarse pointer. A transparent
|
|
26
|
+
* border is kept for forced colours. The quiet fill shows while open and
|
|
27
|
+
* under a hovering pointer, so the open state is seen as well as read.
|
|
28
|
+
*/
|
|
29
|
+
function baseRules() {
|
|
30
|
+
return `.sw-context-switcher {
|
|
31
|
+
display: inline-flex;
|
|
32
|
+
max-width: 100%;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.sw-context-switcher-full {
|
|
36
|
+
display: flex;
|
|
37
|
+
width: 100%;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
${trigger} {
|
|
41
|
+
align-items: center;
|
|
42
|
+
appearance: none;
|
|
43
|
+
background: transparent;
|
|
44
|
+
border: 1px solid transparent;
|
|
45
|
+
border-radius: var(--sw-radius-sm);
|
|
46
|
+
box-sizing: border-box;
|
|
47
|
+
color: var(--sw-color-text);
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
font-family: var(--sw-font-sans);
|
|
51
|
+
font-size: ${label.fontSize}px;
|
|
52
|
+
font-weight: 500;
|
|
53
|
+
gap: var(--sw-space-2);
|
|
54
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
55
|
+
line-height: ${label.lineHeight}px;
|
|
56
|
+
margin: 0;
|
|
57
|
+
max-width: 100%;
|
|
58
|
+
min-height: var(--sw-control-sm-min-height);
|
|
59
|
+
padding-block: var(--sw-space-1);
|
|
60
|
+
padding-inline: var(--sw-space-3) var(--sw-space-2);
|
|
61
|
+
text-align: start;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.sw-context-switcher-full ${trigger} {
|
|
65
|
+
width: 100%;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.sw-context-switcher-trigger-content {
|
|
69
|
+
align-items: center;
|
|
70
|
+
display: flex;
|
|
71
|
+
flex: 1 1 auto;
|
|
72
|
+
gap: var(--sw-space-2);
|
|
73
|
+
min-width: 0;
|
|
74
|
+
overflow-wrap: anywhere;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
${trigger}:not(.${contextSwitcherTriggerClass('icon')})::after {
|
|
78
|
+
${chevronStroke}
|
|
79
|
+
content: '';
|
|
80
|
+
flex: none;
|
|
81
|
+
transform: translateY(-25%) rotate(45deg);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
${trigger}[aria-expanded='true'] {
|
|
85
|
+
background: ${quietFill};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@media (hover: hover) {
|
|
89
|
+
${trigger}:hover {
|
|
90
|
+
background: ${quietFill};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
${trigger}:focus-visible {
|
|
95
|
+
outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
|
|
96
|
+
outline-offset: var(--sw-focus-ring-offset);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@media ${coarsePointerQuery} {
|
|
100
|
+
${trigger} { min-height: ${touchTarget}; }
|
|
101
|
+
}`;
|
|
102
|
+
}
|
|
103
|
+
/*
|
|
104
|
+
* The appearances: `framed` the field's glass fill inside the border
|
|
105
|
+
* hairline; `pill` the same hairline on the surface, fully rounded, at
|
|
106
|
+
* label weight; `icon` a round button as wide as it is tall, the glyph
|
|
107
|
+
* centred and muted, no chevron. Two classes, so each outranks the base.
|
|
108
|
+
*/
|
|
109
|
+
function appearanceRules() {
|
|
110
|
+
return `${framed} {
|
|
111
|
+
background: var(--sw-glass-fill);
|
|
112
|
+
border-color: var(--sw-color-border);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
${pill} {
|
|
116
|
+
background: var(--sw-color-surface);
|
|
117
|
+
border-color: var(--sw-color-border);
|
|
118
|
+
border-radius: var(--sw-radius-pill);
|
|
119
|
+
font-weight: ${label.fontWeight};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
${framed}[aria-expanded='true'],
|
|
123
|
+
${pill}[aria-expanded='true'] {
|
|
124
|
+
background: ${quietFill};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@media (hover: hover) {
|
|
128
|
+
${framed}:hover,
|
|
129
|
+
${pill}:hover {
|
|
130
|
+
background: ${quietFill};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
${icon} {
|
|
135
|
+
border-radius: var(--sw-radius-pill);
|
|
136
|
+
color: var(--sw-color-muted);
|
|
137
|
+
justify-content: center;
|
|
138
|
+
min-width: var(--sw-control-sm-min-height);
|
|
139
|
+
padding: 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
${icon} .sw-context-switcher-trigger-content {
|
|
143
|
+
flex: none;
|
|
144
|
+
justify-content: center;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
${icon}[aria-expanded='true'] {
|
|
148
|
+
color: var(--sw-color-text);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@media ${coarsePointerQuery} {
|
|
152
|
+
${icon} { min-width: ${touchTarget}; }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@media (forced-colors: active) {
|
|
156
|
+
${trigger}::after { border-color: CanvasText; }
|
|
157
|
+
${trigger}[aria-expanded='true'] { border-color: Highlight; }
|
|
158
|
+
${icon} { color: ButtonText; }
|
|
159
|
+
}`;
|
|
160
|
+
}
|
|
161
|
+
/* ContextSwitcher's trigger (see components/ContextSwitcher.tsx). */
|
|
162
|
+
export function cssContextSwitcherTriggerClasses() {
|
|
163
|
+
return `${baseRules()}
|
|
164
|
+
|
|
165
|
+
${appearanceRules()}`;
|
|
166
|
+
}
|
|
167
|
+
export function contextSwitcherTriggerClassCatalog() {
|
|
168
|
+
return [
|
|
169
|
+
'sw-context-switcher',
|
|
170
|
+
'sw-context-switcher-full',
|
|
171
|
+
'sw-context-switcher-trigger',
|
|
172
|
+
'sw-context-switcher-trigger-content',
|
|
173
|
+
...contextSwitcherTriggerAppearances.map(contextSwitcherTriggerClass),
|
|
174
|
+
];
|
|
175
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** The trigger's width, set on the open popup so it is never narrower. */
|
|
2
|
+
export declare const contextSwitcherTriggerWidthVariable = "--sw-context-switcher-trigger-width";
|
|
3
|
+
export declare function cssContextSwitcherClasses(): string;
|
|
4
|
+
export declare function contextSwitcherClassCatalog(): string[];
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { checkStrokeIn } from './chevron.js';
|
|
3
|
+
import { contextSwitcherTriggerClassCatalog, cssContextSwitcherTriggerClasses, } from './css-context-switcher-trigger.js';
|
|
4
|
+
import { quietFill } from './quiet-fill.js';
|
|
5
|
+
import { zIndex } from './stacking.js';
|
|
6
|
+
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
7
|
+
const caption = typographyVariants.caption;
|
|
8
|
+
const label = typographyVariants.label;
|
|
9
|
+
/* The popup's least width, a named geometry of this control. */
|
|
10
|
+
const popupMinWidth = '15rem';
|
|
11
|
+
/** The trigger's width, set on the open popup so it is never narrower. */
|
|
12
|
+
export const contextSwitcherTriggerWidthVariable = '--sw-context-switcher-trigger-width';
|
|
13
|
+
const viewportCap = 'calc(100% - var(--sw-space-2) - var(--sw-space-2))';
|
|
14
|
+
/*
|
|
15
|
+
* The popup: a glass panel on the top layer beside the trigger (placed by
|
|
16
|
+
* script, as the menus are), at least 15rem and as wide as the trigger
|
|
17
|
+
* (its width set by the component), capped by the dialog width (or the
|
|
18
|
+
* trigger's, when wider) and the viewport. A column: the filter field,
|
|
19
|
+
* the listbox (the only part that scrolls), the empty words, the footer.
|
|
20
|
+
*/
|
|
21
|
+
function popupRules() {
|
|
22
|
+
return `.sw-context-switcher-popup {
|
|
23
|
+
background: var(--sw-glass-fill);
|
|
24
|
+
border: 1px solid var(--sw-glass-border);
|
|
25
|
+
border-radius: var(--sw-radius-sm);
|
|
26
|
+
box-shadow: var(--sw-elevation-sm), inset 0 1px 0 var(--sw-glass-specular);
|
|
27
|
+
backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
28
|
+
-webkit-backdrop-filter: blur(var(--sw-glass-blur)) saturate(var(--sw-glass-saturate));
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
color: var(--sw-color-text);
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: var(--sw-space-1);
|
|
34
|
+
inset: auto;
|
|
35
|
+
margin: 0;
|
|
36
|
+
max-height: ${viewportCap};
|
|
37
|
+
max-width: min(max(var(--sw-dialog-max), var(${contextSwitcherTriggerWidthVariable}, 0px)), ${viewportCap});
|
|
38
|
+
min-width: min(max(${popupMinWidth}, var(${contextSwitcherTriggerWidthVariable}, 0px)), ${viewportCap});
|
|
39
|
+
padding: var(--sw-space-1);
|
|
40
|
+
position: fixed;
|
|
41
|
+
width: max-content;
|
|
42
|
+
${zIndex('popup')}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.sw-context-switcher-filter {
|
|
46
|
+
box-sizing: border-box;
|
|
47
|
+
flex: none;
|
|
48
|
+
margin: var(--sw-space-1);
|
|
49
|
+
width: calc(100% - var(--sw-space-2));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.sw-context-switcher-list {
|
|
53
|
+
flex: 1 1 auto;
|
|
54
|
+
max-height: var(--sw-select-max);
|
|
55
|
+
min-height: 0;
|
|
56
|
+
overflow-y: auto;
|
|
57
|
+
overscroll-behavior: contain;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.sw-context-switcher-list:focus {
|
|
61
|
+
outline: none;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.sw-context-switcher-heading {
|
|
65
|
+
color: var(--sw-color-muted);
|
|
66
|
+
font-family: var(--sw-font-sans);
|
|
67
|
+
font-size: ${caption.fontSize}px;
|
|
68
|
+
font-weight: 600;
|
|
69
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
70
|
+
line-height: ${caption.lineHeight}px;
|
|
71
|
+
padding: var(--sw-space-2) var(--sw-space-2) var(--sw-space-1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.sw-context-switcher-empty {
|
|
75
|
+
color: var(--sw-color-muted);
|
|
76
|
+
font-family: var(--sw-font-sans);
|
|
77
|
+
font-size: ${caption.fontSize}px;
|
|
78
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
79
|
+
line-height: ${caption.lineHeight}px;
|
|
80
|
+
margin: 0;
|
|
81
|
+
padding: var(--sw-space-2);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.sw-context-switcher-footer {
|
|
85
|
+
border-top: 1px solid var(--sw-color-border);
|
|
86
|
+
display: flex;
|
|
87
|
+
flex: none;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
gap: var(--sw-space-1);
|
|
90
|
+
padding-top: var(--sw-space-1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.sw-context-switcher-action-icon {
|
|
94
|
+
display: inline-flex;
|
|
95
|
+
flex: none;
|
|
96
|
+
}`;
|
|
97
|
+
}
|
|
98
|
+
/*
|
|
99
|
+
* An option: the mark, the label over its muted detail, then the badge,
|
|
100
|
+
* the count pill and the current one's check at the inline end. The sm
|
|
101
|
+
* control height (44 px on a coarse pointer). The active row (the arrow
|
|
102
|
+
* keys' or the pointer's) takes the quiet fill, and an accent ring while
|
|
103
|
+
* the list itself has visible focus; the current one is at label weight
|
|
104
|
+
* with the accent check. Forced colours draw the active row in Highlight.
|
|
105
|
+
*/
|
|
106
|
+
function optionRules() {
|
|
107
|
+
return `.sw-context-switcher-option {
|
|
108
|
+
align-items: center;
|
|
109
|
+
border-radius: var(--sw-radius-sm);
|
|
110
|
+
box-sizing: border-box;
|
|
111
|
+
cursor: pointer;
|
|
112
|
+
display: flex;
|
|
113
|
+
font-family: var(--sw-font-sans);
|
|
114
|
+
font-size: ${label.fontSize}px;
|
|
115
|
+
gap: var(--sw-space-2);
|
|
116
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
117
|
+
line-height: ${label.lineHeight}px;
|
|
118
|
+
min-height: var(--sw-control-sm-min-height);
|
|
119
|
+
overflow-wrap: anywhere;
|
|
120
|
+
padding: var(--sw-space-1) var(--sw-space-2);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.sw-context-switcher-option[data-active='true'] {
|
|
124
|
+
background: ${quietFill};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* On the quiet fill the muted detail moves toward the text colour, keeping 4.5:1. */
|
|
128
|
+
.sw-context-switcher-option[data-active='true'] .sw-context-switcher-detail {
|
|
129
|
+
color: color-mix(in srgb, var(--sw-color-muted) 70%, var(--sw-color-text));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.sw-context-switcher-list:focus-visible .sw-context-switcher-option[data-active='true'] {
|
|
133
|
+
outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
|
|
134
|
+
outline-offset: calc(-1 * var(--sw-focus-ring-width));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.sw-context-switcher-icon {
|
|
138
|
+
display: inline-flex;
|
|
139
|
+
flex: none;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.sw-context-switcher-words {
|
|
143
|
+
display: flex;
|
|
144
|
+
flex: 1 1 auto;
|
|
145
|
+
flex-direction: column;
|
|
146
|
+
min-width: 0;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.sw-context-switcher-option[aria-selected='true'] .sw-context-switcher-label {
|
|
150
|
+
font-weight: ${label.fontWeight};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.sw-context-switcher-detail {
|
|
154
|
+
color: var(--sw-color-muted);
|
|
155
|
+
font-size: ${caption.fontSize}px;
|
|
156
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
157
|
+
line-height: ${caption.lineHeight}px;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.sw-context-switcher-count {
|
|
161
|
+
flex: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.sw-context-switcher-check {
|
|
165
|
+
${checkStrokeIn('var(--sw-color-accent)')}
|
|
166
|
+
box-sizing: border-box;
|
|
167
|
+
flex: none;
|
|
168
|
+
height: var(--sw-space-3);
|
|
169
|
+
margin-inline: var(--sw-space-1);
|
|
170
|
+
transform: rotate(45deg);
|
|
171
|
+
width: var(--sw-space-2);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@media ${coarsePointerQuery} {
|
|
175
|
+
.sw-context-switcher-option { min-height: ${touchTarget}; }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@media (forced-colors: active) {
|
|
179
|
+
.sw-context-switcher-popup { border-color: CanvasText; }
|
|
180
|
+
.sw-context-switcher-option[data-active='true'] { background: Highlight; color: HighlightText; forced-color-adjust: none; }
|
|
181
|
+
.sw-context-switcher-option[data-active='true'] .sw-context-switcher-detail { color: HighlightText; }
|
|
182
|
+
.sw-context-switcher-option[data-active='true'] .sw-badge,
|
|
183
|
+
.sw-context-switcher-option[data-active='true'] .sw-context-switcher-count { forced-color-adjust: auto; }
|
|
184
|
+
.sw-context-switcher-check { border-color: CanvasText; }
|
|
185
|
+
.sw-context-switcher-option[data-active='true'] .sw-context-switcher-check { border-color: HighlightText; }
|
|
186
|
+
.sw-context-switcher-footer { border-color: CanvasText; }
|
|
187
|
+
}`;
|
|
188
|
+
}
|
|
189
|
+
/*
|
|
190
|
+
* ContextSwitcher (see components/ContextSwitcher.tsx): the trigger is
|
|
191
|
+
* `css-context-switcher-trigger.ts`; its count joins the shared pill
|
|
192
|
+
* (`css-count-pill.ts`).
|
|
193
|
+
*/
|
|
194
|
+
export function cssContextSwitcherClasses() {
|
|
195
|
+
return `${cssContextSwitcherTriggerClasses()}
|
|
196
|
+
|
|
197
|
+
${popupRules()}
|
|
198
|
+
|
|
199
|
+
${optionRules()}`;
|
|
200
|
+
}
|
|
201
|
+
export function contextSwitcherClassCatalog() {
|
|
202
|
+
return [
|
|
203
|
+
...contextSwitcherTriggerClassCatalog(),
|
|
204
|
+
'sw-context-switcher-popup',
|
|
205
|
+
'sw-context-switcher-filter',
|
|
206
|
+
'sw-context-switcher-list',
|
|
207
|
+
'sw-context-switcher-heading',
|
|
208
|
+
'sw-context-switcher-option',
|
|
209
|
+
'sw-context-switcher-icon',
|
|
210
|
+
'sw-context-switcher-words',
|
|
211
|
+
'sw-context-switcher-label',
|
|
212
|
+
'sw-context-switcher-detail',
|
|
213
|
+
'sw-context-switcher-check',
|
|
214
|
+
'sw-context-switcher-empty',
|
|
215
|
+
'sw-context-switcher-footer',
|
|
216
|
+
'sw-context-switcher-action-icon',
|
|
217
|
+
// sw-context-switcher-count is the shared pill's (css-count-pill.ts).
|
|
218
|
+
];
|
|
219
|
+
}
|
|
@@ -1,2 +1,9 @@
|
|
|
1
|
+
/** The pills that take a tone modifier: all but SectionNav's. */
|
|
2
|
+
declare const tonedPills: readonly ["sw-nav-count", "sw-app-shell-count", "sw-context-switcher-count"];
|
|
3
|
+
/** The tones other than the pill's own danger. */
|
|
4
|
+
declare const pillTones: readonly ["accent", "warning"];
|
|
5
|
+
/** A toned pill's modifier class, such as `sw-nav-count-warning`. */
|
|
6
|
+
export declare function countToneClass(pill: (typeof tonedPills)[number], tone: (typeof pillTones)[number]): string;
|
|
1
7
|
export declare function cssCountPillClasses(): string;
|
|
2
8
|
export declare function countPillClassCatalog(): string[];
|
|
9
|
+
export {};
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { toneTintFill, toneTintInk } from './tone-tint.js';
|
|
2
3
|
const caption = typographyVariants.caption;
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The counts drawn as the pill: SectionNav's, a Nav word's, AppShell's and
|
|
6
|
+
* a ContextSwitcher option's.
|
|
7
|
+
*/
|
|
8
|
+
const pills = [
|
|
9
|
+
'sw-section-nav-count',
|
|
10
|
+
'sw-nav-count',
|
|
11
|
+
'sw-app-shell-count',
|
|
12
|
+
'sw-context-switcher-count',
|
|
13
|
+
];
|
|
14
|
+
/** The pills that take a tone modifier: all but SectionNav's. */
|
|
15
|
+
const tonedPills = [
|
|
16
|
+
'sw-nav-count',
|
|
17
|
+
'sw-app-shell-count',
|
|
18
|
+
'sw-context-switcher-count',
|
|
19
|
+
];
|
|
20
|
+
/** The tones other than the pill's own danger. */
|
|
21
|
+
const pillTones = ['accent', 'warning'];
|
|
22
|
+
/** A toned pill's modifier class, such as `sw-nav-count-warning`. */
|
|
23
|
+
export function countToneClass(pill, tone) {
|
|
24
|
+
return `${pill}-${tone}`;
|
|
25
|
+
}
|
|
26
|
+
function tonedSelector(tone) {
|
|
27
|
+
return tonedPills
|
|
28
|
+
.map((pill) => `[data-theme] .${pill}.${countToneClass(pill, tone)}`)
|
|
29
|
+
.join(',\n');
|
|
30
|
+
}
|
|
7
31
|
/*
|
|
8
32
|
* A count after a destination's words (a number waiting there, such as
|
|
9
33
|
* tasks to do) is a filled pill: the danger colour with its on-colour
|
|
10
34
|
* figures (4.5:1 in every palette, as a danger Button's label), caption
|
|
11
35
|
* size at weight 700, a space-5 less space-1 (20) high and at least as
|
|
12
|
-
* wide. Forced colours draw its edge. SectionNav's item count
|
|
13
|
-
* NavCount share it, so an area's count reads
|
|
36
|
+
* wide. Forced colours draw its edge. SectionNav's item count, Nav's
|
|
37
|
+
* NavCount and AppShell's item count share it, so an area's count reads
|
|
38
|
+
* the same in each.
|
|
14
39
|
*/
|
|
15
40
|
export function cssCountPillClasses() {
|
|
16
41
|
const selector = pills.map((name) => `[data-theme] .${name}`).join(',\n');
|
|
@@ -33,16 +58,26 @@ export function cssCountPillClasses() {
|
|
|
33
58
|
}
|
|
34
59
|
|
|
35
60
|
/*
|
|
36
|
-
*
|
|
37
|
-
* was added since the person last looked),
|
|
38
|
-
* on-colour figures (4.5:1 in every palette, as
|
|
39
|
-
*
|
|
61
|
+
* \`tone="accent"\` (NavCount, an AppShell item's \`countTone\`): a count that
|
|
62
|
+
* is news, not work waiting (what was added since the person last looked),
|
|
63
|
+
* is the accent fill with its on-colour figures (4.5:1 in every palette, as
|
|
64
|
+
* a primary Button's label). \`tone="warning"\`: work that needs the person
|
|
65
|
+
* but is not urgent is amber, the warning tint with the warning ink (a
|
|
66
|
+
* warning Notice's, 4.5:1 on the tint in every palette) inside the warning
|
|
67
|
+
* edge a warning Badge draws. One class more specific than the pill, so
|
|
68
|
+
* each wins in any order.
|
|
40
69
|
*/
|
|
41
|
-
|
|
70
|
+
${tonedSelector('accent')} {
|
|
42
71
|
background: var(--sw-color-accent);
|
|
43
72
|
color: var(--sw-color-onAccent);
|
|
44
73
|
}
|
|
45
74
|
|
|
75
|
+
${tonedSelector('warning')} {
|
|
76
|
+
background: ${toneTintFill('warning')};
|
|
77
|
+
border: 1px solid var(--sw-color-warning);
|
|
78
|
+
color: ${toneTintInk('warning')};
|
|
79
|
+
}
|
|
80
|
+
|
|
46
81
|
/*
|
|
47
82
|
* A Nav link holding a count lays out as SectionNav's link does: the words
|
|
48
83
|
* and the pill centred on one line a space-2 apart (the space text node
|
|
@@ -63,5 +98,8 @@ export function cssCountPillClasses() {
|
|
|
63
98
|
}`;
|
|
64
99
|
}
|
|
65
100
|
export function countPillClassCatalog() {
|
|
66
|
-
return [
|
|
101
|
+
return [
|
|
102
|
+
...pills,
|
|
103
|
+
...tonedPills.flatMap((pill) => pillTones.map((tone) => countToneClass(pill, tone))),
|
|
104
|
+
];
|
|
67
105
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const fixtureCenterKinds: readonly ["time", "score"];
|
|
2
|
+
/** `time` is a kickoff time in a grey chip; `score` is bold figures. */
|
|
3
|
+
export type FixtureCenterKind = (typeof fixtureCenterKinds)[number];
|
|
4
|
+
export declare function cssFixtureClasses(): string;
|
|
5
|
+
export declare function fixtureClassCatalog(): string[];
|