@scalewing/react 1.47.0 → 1.49.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 +82 -0
- package/README.md +215 -6
- 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 +4 -3
- package/dist/components/AppShell.js +24 -7
- 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/EmptyState.d.ts +23 -0
- package/dist/components/EmptyState.js +40 -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/Grid.d.ts +11 -3
- package/dist/components/Grid.js +13 -4
- package/dist/components/Hero.d.ts +26 -0
- package/dist/components/Hero.js +23 -0
- 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/Stepper.d.ts +11 -1
- package/dist/components/Stepper.js +10 -8
- package/dist/components/Text.js +3 -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/types.d.ts +36 -1
- package/dist/components/app-shell/validate.d.ts +4 -3
- package/dist/components/app-shell/validate.js +21 -3
- 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/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/stepper/StepperCountFrame.d.ts +15 -0
- package/dist/components/stepper/StepperCountFrame.js +25 -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-page-bar.d.ts +3 -0
- package/dist/css/css-app-shell-page-bar.js +81 -0
- package/dist/css/css-app-shell.js +6 -1
- 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 +30 -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 +2 -2
- package/dist/css/css-count-pill.js +11 -3
- package/dist/css/css-empty-state.d.ts +2 -0
- package/dist/css/css-empty-state.js +77 -0
- 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-grid-span.js +5 -2
- package/dist/css/css-grid.d.ts +13 -0
- package/dist/css/css-grid.js +17 -1
- package/dist/css/css-hero.d.ts +2 -0
- package/dist/css/css-hero.js +62 -0
- 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/css-stepper-unit.d.ts +9 -0
- package/dist/css/css-stepper-unit.js +102 -0
- package/dist/css/css-stepper.js +5 -1
- package/dist/css/stacking.js +7 -4
- package/dist/css/stylesheet.js +20 -0
- package/dist/index.d.ts +18 -2
- package/dist/index.js +13 -1
- package/dist/stepper-count.d.ts +8 -0
- package/dist/stepper-count.js +17 -0
- package/dist/styles.css +2202 -702
- package/package.json +2 -2
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { breakpointQuery } from './breakpoints.js';
|
|
3
|
+
import { chevronStrokeIn } from './chevron.js';
|
|
4
|
+
import { quietFill } from './quiet-fill.js';
|
|
5
|
+
import { touchTarget } from './touch-target.js';
|
|
6
|
+
const caption = typographyVariants.caption;
|
|
7
|
+
const label = typographyVariants.label;
|
|
8
|
+
export const fixtureCenterKinds = ['time', 'score'];
|
|
9
|
+
const belowMd = breakpointQuery('below', 'md');
|
|
10
|
+
/*
|
|
11
|
+
* The run: one grid whose columns are the home side, the centre, the away
|
|
12
|
+
* side, the end (details and status) and the chevron. Each item and its
|
|
13
|
+
* row are subgrids of it, so every row's centre and end line up down the
|
|
14
|
+
* run. The space between the columns is the centre's, the end's and the
|
|
15
|
+
* chevron's own margin, so a run with no end or chevron keeps no gap for
|
|
16
|
+
* them.
|
|
17
|
+
*/
|
|
18
|
+
function listRules() {
|
|
19
|
+
return `.sw-fixture-group {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.sw-fixture-group-title {
|
|
25
|
+
color: var(--sw-color-muted);
|
|
26
|
+
font-family: var(--sw-font-sans);
|
|
27
|
+
font-size: ${caption.fontSize}px;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
30
|
+
line-height: ${caption.lineHeight}px;
|
|
31
|
+
padding-block: var(--sw-space-2) var(--sw-space-1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.sw-fixture-list {
|
|
35
|
+
display: grid;
|
|
36
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto auto;
|
|
37
|
+
list-style: none;
|
|
38
|
+
margin: 0;
|
|
39
|
+
padding: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.sw-fixture-item,
|
|
43
|
+
.sw-fixture-row {
|
|
44
|
+
display: grid;
|
|
45
|
+
grid-column: 1 / -1;
|
|
46
|
+
grid-template-columns: subgrid;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sw-fixture-item {
|
|
50
|
+
border-top: 1px solid var(--sw-color-border);
|
|
51
|
+
}`;
|
|
52
|
+
}
|
|
53
|
+
/*
|
|
54
|
+
* A row: the md control height (44 px), its parts centred on one line a
|
|
55
|
+
* space-3 apart; a link or button row is the whole target, the text
|
|
56
|
+
* colour, the quiet fill on hover and an inset accent ring, with the
|
|
57
|
+
* shared chevron at the end. The sides' names are label type at weight 500
|
|
58
|
+
* and wrap; the home side ends at the centre (its mark nearest it), the
|
|
59
|
+
* away side starts from it, mirrored in right-to-left.
|
|
60
|
+
*/
|
|
61
|
+
function rowRules() {
|
|
62
|
+
return `.sw-fixture-row {
|
|
63
|
+
align-items: center;
|
|
64
|
+
appearance: none;
|
|
65
|
+
background: transparent;
|
|
66
|
+
border: 0;
|
|
67
|
+
box-sizing: border-box;
|
|
68
|
+
color: var(--sw-color-text);
|
|
69
|
+
font-family: var(--sw-font-sans);
|
|
70
|
+
font-size: ${label.fontSize}px;
|
|
71
|
+
letter-spacing: ${label.letterSpacing}px;
|
|
72
|
+
line-height: ${label.lineHeight}px;
|
|
73
|
+
margin: 0;
|
|
74
|
+
min-height: ${touchTarget};
|
|
75
|
+
padding: var(--sw-space-2);
|
|
76
|
+
row-gap: var(--sw-space-1);
|
|
77
|
+
text-align: start;
|
|
78
|
+
text-decoration: none;
|
|
79
|
+
width: 100%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.sw-fixture-row-pressable { cursor: pointer; }
|
|
83
|
+
|
|
84
|
+
@media (hover: hover) {
|
|
85
|
+
.sw-fixture-row-pressable:hover { background: ${quietFill}; }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.sw-fixture-row-pressable:focus { outline: none; }
|
|
89
|
+
|
|
90
|
+
.sw-fixture-row-pressable:focus-visible {
|
|
91
|
+
outline: var(--sw-focus-ring-width) solid var(--sw-color-accent);
|
|
92
|
+
outline-offset: calc(-1 * var(--sw-focus-ring-width));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
[data-theme] a.sw-fixture-row,
|
|
96
|
+
[data-theme] a.sw-fixture-row:hover {
|
|
97
|
+
color: var(--sw-color-text);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
[data-theme] a.sw-fixture-row:focus-visible {
|
|
101
|
+
outline-offset: calc(-1 * var(--sw-focus-ring-width));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.sw-fixture-team {
|
|
105
|
+
align-items: center;
|
|
106
|
+
display: flex;
|
|
107
|
+
gap: var(--sw-space-2);
|
|
108
|
+
min-width: 0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.sw-fixture-team-home {
|
|
112
|
+
grid-column: 1;
|
|
113
|
+
justify-content: flex-end;
|
|
114
|
+
text-align: end;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.sw-fixture-team-away {
|
|
118
|
+
grid-column: 3;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.sw-fixture-name {
|
|
122
|
+
font-weight: 500;
|
|
123
|
+
min-width: 0;
|
|
124
|
+
overflow-wrap: anywhere;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.sw-fixture-mark {
|
|
128
|
+
display: inline-flex;
|
|
129
|
+
flex: none;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.sw-fixture-center {
|
|
133
|
+
font-variant-numeric: tabular-nums;
|
|
134
|
+
grid-column: 2;
|
|
135
|
+
margin-inline: var(--sw-space-3);
|
|
136
|
+
justify-self: center;
|
|
137
|
+
white-space: nowrap;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.sw-fixture-center-time {
|
|
141
|
+
background: var(--sw-color-subtle);
|
|
142
|
+
border-radius: var(--sw-radius-sm);
|
|
143
|
+
font-size: ${caption.fontSize}px;
|
|
144
|
+
font-weight: 600;
|
|
145
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
146
|
+
line-height: ${caption.lineHeight}px;
|
|
147
|
+
padding: calc(var(--sw-space-1) / 2) var(--sw-space-2);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.sw-fixture-center-score {
|
|
151
|
+
font-weight: 700;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.sw-fixture-end {
|
|
155
|
+
align-items: center;
|
|
156
|
+
color: var(--sw-color-muted);
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
font-size: ${caption.fontSize}px;
|
|
160
|
+
gap: var(--sw-space-2);
|
|
161
|
+
grid-column: 4;
|
|
162
|
+
justify-content: flex-end;
|
|
163
|
+
letter-spacing: ${caption.letterSpacing}px;
|
|
164
|
+
margin-inline-start: var(--sw-space-3);
|
|
165
|
+
line-height: ${caption.lineHeight}px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.sw-fixture-chevron {
|
|
169
|
+
${chevronStrokeIn('var(--sw-color-muted)')}
|
|
170
|
+
grid-column: 5;
|
|
171
|
+
justify-self: end;
|
|
172
|
+
margin-inline: var(--sw-space-3) var(--sw-space-1);
|
|
173
|
+
transform: rotate(-45deg);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.sw-fixture-chevron:dir(rtl) { transform: rotate(135deg); }
|
|
177
|
+
|
|
178
|
+
@media (forced-colors: active) {
|
|
179
|
+
.sw-fixture-row-pressable:hover {
|
|
180
|
+
outline: var(--sw-focus-ring-width) solid Highlight;
|
|
181
|
+
outline-offset: calc(-1 * var(--sw-focus-ring-width));
|
|
182
|
+
}
|
|
183
|
+
.sw-fixture-center-time { border: 1px solid CanvasText; }
|
|
184
|
+
.sw-fixture-chevron { border-color: CanvasText; }
|
|
185
|
+
}`;
|
|
186
|
+
}
|
|
187
|
+
/*
|
|
188
|
+
* Below `md`: three columns and the chevron, the end on a second line
|
|
189
|
+
* from the start. After the row rules, so it wins over their placement.
|
|
190
|
+
*/
|
|
191
|
+
function narrowRules() {
|
|
192
|
+
return `@media ${belowMd} {
|
|
193
|
+
.sw-fixture-list {
|
|
194
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.sw-fixture-end {
|
|
198
|
+
grid-column: 1 / 4;
|
|
199
|
+
grid-row: 2;
|
|
200
|
+
justify-content: flex-start;
|
|
201
|
+
margin-inline-start: 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.sw-fixture-chevron {
|
|
205
|
+
grid-column: 4;
|
|
206
|
+
grid-row: 1 / span 2;
|
|
207
|
+
}
|
|
208
|
+
}`;
|
|
209
|
+
}
|
|
210
|
+
/*
|
|
211
|
+
* Without subgrid (Chrome before 117, Safari before 16): each row is its
|
|
212
|
+
* own grid of the same columns, so a row still reads in order and the
|
|
213
|
+
* centres sit near the middle, but they do not line up down the run.
|
|
214
|
+
*/
|
|
215
|
+
function fallbackRules() {
|
|
216
|
+
return `@supports not (grid-template-columns: subgrid) {
|
|
217
|
+
.sw-fixture-item {
|
|
218
|
+
display: block;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.sw-fixture-row {
|
|
222
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto auto;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
@media ${belowMd} {
|
|
226
|
+
.sw-fixture-row {
|
|
227
|
+
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}`;
|
|
231
|
+
}
|
|
232
|
+
/* FixtureGroup and FixtureRow (see components/FixtureRow.tsx). */
|
|
233
|
+
export function cssFixtureClasses() {
|
|
234
|
+
return `${listRules()}
|
|
235
|
+
|
|
236
|
+
${rowRules()}
|
|
237
|
+
|
|
238
|
+
${narrowRules()}
|
|
239
|
+
|
|
240
|
+
${fallbackRules()}`;
|
|
241
|
+
}
|
|
242
|
+
export function fixtureClassCatalog() {
|
|
243
|
+
return [
|
|
244
|
+
'sw-fixture-group',
|
|
245
|
+
'sw-fixture-group-title',
|
|
246
|
+
'sw-fixture-list',
|
|
247
|
+
'sw-fixture-item',
|
|
248
|
+
'sw-fixture-row',
|
|
249
|
+
'sw-fixture-row-pressable',
|
|
250
|
+
'sw-fixture-team',
|
|
251
|
+
'sw-fixture-team-home',
|
|
252
|
+
'sw-fixture-team-away',
|
|
253
|
+
'sw-fixture-name',
|
|
254
|
+
'sw-fixture-mark',
|
|
255
|
+
'sw-fixture-center',
|
|
256
|
+
...fixtureCenterKinds.map((kind) => `sw-fixture-center-${kind}`),
|
|
257
|
+
'sw-fixture-end',
|
|
258
|
+
'sw-fixture-chevron',
|
|
259
|
+
];
|
|
260
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export declare const glyphTileSizes: readonly ["sm", "md", "lg"];
|
|
2
2
|
/** `sm` 24, `md` 28 (the xs control height), `lg` 32. */
|
|
3
3
|
export type GlyphTileSize = (typeof glyphTileSizes)[number];
|
|
4
|
+
/** The most letters a tile holds, such as a three-letter crest ("NSL"). */
|
|
5
|
+
export declare const glyphTileLetterLimit = 3;
|
|
4
6
|
export declare function cssGlyphTileClasses(): string;
|
|
5
7
|
export declare function glyphTileClassCatalog(): string[];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { categoricalColorKeys } from '@scalewing/tokens';
|
|
2
2
|
export const glyphTileSizes = ['sm', 'md', 'lg'];
|
|
3
|
+
/** The most letters a tile holds, such as a three-letter crest ("NSL"). */
|
|
4
|
+
export const glyphTileLetterLimit = 3;
|
|
3
5
|
const tileSide = {
|
|
4
6
|
sm: 'var(--sw-space-5)',
|
|
5
7
|
md: 'var(--sw-control-xs-min-height)',
|
|
@@ -12,7 +14,7 @@ function hueRules() {
|
|
|
12
14
|
}
|
|
13
15
|
function sizeRules() {
|
|
14
16
|
return Object.entries(tileSide)
|
|
15
|
-
.map(([size, side]) => `.sw-glyph-tile-${size} { height: ${side}; width: ${side}; }`)
|
|
17
|
+
.map(([size, side]) => `.sw-glyph-tile-${size} { --sw-glyph-tile-side: ${side}; height: ${side}; width: ${side}; }`)
|
|
16
18
|
.join('\n');
|
|
17
19
|
}
|
|
18
20
|
/*
|
|
@@ -40,6 +42,28 @@ export function cssGlyphTileClasses() {
|
|
|
40
42
|
width: var(--sw-space-4);
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
/*
|
|
46
|
+
* Letters in place of a glyph: one line, centred, weight 600, the line as
|
|
47
|
+
* tall as the letters, sized from the tile's side rather than the text
|
|
48
|
+
* round it, so they fit at every size: one letter at half the side, two
|
|
49
|
+
* at 0.42 of it, three at a third, tightened a little, so even a wide
|
|
50
|
+
* trio ("WMW") fits inside the smallest tile.
|
|
51
|
+
*/
|
|
52
|
+
.sw-glyph-tile-text {
|
|
53
|
+
font-weight: 600;
|
|
54
|
+
line-height: 1;
|
|
55
|
+
white-space: nowrap;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.sw-glyph-tile-text-1 { font-size: calc(var(--sw-glyph-tile-side) / 2); }
|
|
59
|
+
|
|
60
|
+
.sw-glyph-tile-text-2 { font-size: calc(var(--sw-glyph-tile-side) * 0.42); }
|
|
61
|
+
|
|
62
|
+
.sw-glyph-tile-text-3 {
|
|
63
|
+
font-size: calc(var(--sw-glyph-tile-side) / 3);
|
|
64
|
+
letter-spacing: -0.02em;
|
|
65
|
+
}
|
|
66
|
+
|
|
43
67
|
${hueRules()}
|
|
44
68
|
|
|
45
69
|
${sizeRules()}
|
|
@@ -53,5 +77,9 @@ export function glyphTileClassCatalog() {
|
|
|
53
77
|
'sw-glyph-tile',
|
|
54
78
|
...categoricalColorKeys.map((key) => `sw-glyph-tile-${key}`),
|
|
55
79
|
...glyphTileSizes.map((size) => `sw-glyph-tile-${size}`),
|
|
80
|
+
'sw-glyph-tile-text',
|
|
81
|
+
'sw-glyph-tile-text-1',
|
|
82
|
+
'sw-glyph-tile-text-2',
|
|
83
|
+
'sw-glyph-tile-text-3',
|
|
56
84
|
];
|
|
57
85
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { breakpointQuery, breakpoints } from './breakpoints.js';
|
|
2
|
-
import { gridColumnCounts, gridColumnsBelowClass, gridColumnsClass, } from './css-grid.js';
|
|
2
|
+
import { gridColumnCounts, gridColumnsBelowClass, gridColumnsClass, gridFitClass, gridFits, } from './css-grid.js';
|
|
3
3
|
export const gridColumnSpans = gridColumnCounts;
|
|
4
4
|
export function gridSpanClass(span) {
|
|
5
5
|
return `sw-grid-span-${span}`;
|
|
@@ -21,6 +21,9 @@ function widerSpans(columns) {
|
|
|
21
21
|
export function cssGridSpanClasses() {
|
|
22
22
|
const spans = gridColumnSpans.map((span) => spanRule(`.${gridSpanClass(span)}`, span));
|
|
23
23
|
const caps = gridColumnCounts.flatMap((columns) => widerSpans(columns).map((span) => capRule(gridColumnsClass(columns), columns, span)));
|
|
24
|
+
// A fitted grid's column count follows its width, so a span there would
|
|
25
|
+
// add implicit columns: its children each take one column.
|
|
26
|
+
const fitted = gridFits.flatMap((fit) => widerSpans(1).map((span) => `:where(.${gridFitClass(fit)}) > .${gridSpanClass(span)} { grid-column: auto; }`));
|
|
24
27
|
// Below a breakpoint every span wider than one is restated for the phone
|
|
25
28
|
// column count, which also undoes a desktop cap when that count is larger.
|
|
26
29
|
const below = breakpoints.map((breakpoint) => `@media ${breakpointQuery('below', breakpoint)} {
|
|
@@ -28,7 +31,7 @@ ${gridColumnCounts
|
|
|
28
31
|
.flatMap((columns) => widerSpans(1).map((span) => ` ${capRule(gridColumnsBelowClass(breakpoint, columns), columns, span)}`))
|
|
29
32
|
.join('\n')}
|
|
30
33
|
}`);
|
|
31
|
-
return [...spans, ...caps, ...below].join('\n');
|
|
34
|
+
return [...spans, ...caps, ...fitted, ...below].join('\n');
|
|
32
35
|
}
|
|
33
36
|
export function gridSpanClassCatalog() {
|
|
34
37
|
return gridColumnSpans.map((span) => gridSpanClass(span));
|
package/dist/css/css-grid.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { type Breakpoint } from './breakpoints.js';
|
|
2
2
|
export declare const gridColumnCounts: readonly [1, 2, 3, 4, 6];
|
|
3
3
|
export type GridColumns = (typeof gridColumnCounts)[number];
|
|
4
|
+
/**
|
|
5
|
+
* A fitted grid's narrowest column: as many columns as fit the grid's width
|
|
6
|
+
* at this minimum, each stretched to share the row, and one column when
|
|
7
|
+
* the grid is narrower than the minimum.
|
|
8
|
+
*/
|
|
9
|
+
export declare const gridFitWidths: {
|
|
10
|
+
readonly narrow: "15rem";
|
|
11
|
+
readonly medium: "16.25rem";
|
|
12
|
+
readonly wide: "18.75rem";
|
|
13
|
+
};
|
|
14
|
+
export type GridFit = keyof typeof gridFitWidths;
|
|
15
|
+
export declare const gridFits: GridFit[];
|
|
16
|
+
export declare function gridFitClass(fit: GridFit): string;
|
|
4
17
|
export declare function gridColumnsClass(columns: GridColumns): string;
|
|
5
18
|
export declare function gridColumnsBelowClass(breakpoint: Breakpoint, columns: GridColumns): string;
|
|
6
19
|
export declare function cssGridClasses(): string;
|
package/dist/css/css-grid.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { breakpointQuery, breakpoints, } from './breakpoints.js';
|
|
2
2
|
export const gridColumnCounts = [1, 2, 3, 4, 6];
|
|
3
|
+
/**
|
|
4
|
+
* A fitted grid's narrowest column: as many columns as fit the grid's width
|
|
5
|
+
* at this minimum, each stretched to share the row, and one column when
|
|
6
|
+
* the grid is narrower than the minimum.
|
|
7
|
+
*/
|
|
8
|
+
export const gridFitWidths = {
|
|
9
|
+
narrow: '15rem',
|
|
10
|
+
medium: '16.25rem',
|
|
11
|
+
wide: '18.75rem',
|
|
12
|
+
};
|
|
13
|
+
export const gridFits = Object.keys(gridFitWidths);
|
|
14
|
+
export function gridFitClass(fit) {
|
|
15
|
+
return `sw-grid-fit-${fit}`;
|
|
16
|
+
}
|
|
3
17
|
export function gridColumnsClass(columns) {
|
|
4
18
|
return `sw-grid-cols-${columns}`;
|
|
5
19
|
}
|
|
@@ -20,12 +34,14 @@ ${gridColumnCounts
|
|
|
20
34
|
.map((count) => columnsRule(gridColumnsBelowClass(breakpoint, count), count))
|
|
21
35
|
.join('\n')}
|
|
22
36
|
}`);
|
|
23
|
-
|
|
37
|
+
const fitted = gridFits.map((fit) => `.${gridFitClass(fit)} { grid-template-columns: repeat(auto-fit, minmax(min(100%, ${gridFitWidths[fit]}), 1fr)); }`);
|
|
38
|
+
return [base, ...columns, ...below, ...fitted].join('\n');
|
|
24
39
|
}
|
|
25
40
|
export function gridClassCatalog() {
|
|
26
41
|
return [
|
|
27
42
|
'sw-grid',
|
|
28
43
|
...gridColumnCounts.map((count) => gridColumnsClass(count)),
|
|
29
44
|
...breakpoints.flatMap((breakpoint) => gridColumnCounts.map((count) => gridColumnsBelowClass(breakpoint, count))),
|
|
45
|
+
...gridFits.map(gridFitClass),
|
|
30
46
|
];
|
|
31
47
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { breakpointQuery } from './breakpoints.js';
|
|
2
|
+
/*
|
|
3
|
+
* A public page's opening: the words in one column (an eyebrow, the hero
|
|
4
|
+
* title, the lead and the actions) and an optional picture beside them.
|
|
5
|
+
* From `md` the picture keeps its own width at the row's end and the words
|
|
6
|
+
* take the rest; below `md` the picture sits centred under the words and
|
|
7
|
+
* the actions stack to the full width, as a phone's thumb expects. With no
|
|
8
|
+
* picture the words keep the reading width, so a long title or lead does
|
|
9
|
+
* not run the page's full width. The actions sit one spacing step further
|
|
10
|
+
* from the lead than the text's gap, so the buttons read as their own row.
|
|
11
|
+
*/
|
|
12
|
+
export function cssHeroClasses() {
|
|
13
|
+
return `.sw-hero {
|
|
14
|
+
align-items: center;
|
|
15
|
+
display: grid;
|
|
16
|
+
gap: var(--sw-space-8);
|
|
17
|
+
min-width: 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.sw-hero-text {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
gap: var(--sw-space-4);
|
|
24
|
+
min-width: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.sw-hero:not(.sw-hero-with-media) .sw-hero-text {
|
|
28
|
+
max-width: var(--sw-reading-max);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.sw-hero-actions {
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-wrap: wrap;
|
|
34
|
+
gap: var(--sw-space-3);
|
|
35
|
+
padding-top: var(--sw-space-1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.sw-hero-media {
|
|
39
|
+
justify-self: center;
|
|
40
|
+
max-width: 100%;
|
|
41
|
+
min-width: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media ${breakpointQuery('from', 'md')} {
|
|
45
|
+
.sw-hero-text { gap: var(--sw-space-5); }
|
|
46
|
+
.sw-hero-with-media { grid-template-columns: minmax(0, 1fr) auto; }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@media ${breakpointQuery('below', 'md')} {
|
|
50
|
+
.sw-hero { gap: var(--sw-space-6); }
|
|
51
|
+
.sw-hero-actions { align-items: stretch; flex-direction: column; }
|
|
52
|
+
}`;
|
|
53
|
+
}
|
|
54
|
+
export function heroClassCatalog() {
|
|
55
|
+
return [
|
|
56
|
+
'sw-hero',
|
|
57
|
+
'sw-hero-with-media',
|
|
58
|
+
'sw-hero-text',
|
|
59
|
+
'sw-hero-actions',
|
|
60
|
+
'sw-hero-media',
|
|
61
|
+
];
|
|
62
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { typographyVariants } from '@scalewing/tokens';
|
|
2
|
+
import { breakpointQuery } from './breakpoints.js';
|
|
3
|
+
import { coarsePointerQuery, touchTarget } from './touch-target.js';
|
|
4
|
+
const label = typographyVariants.label;
|
|
5
|
+
const caption = typographyVariants.caption;
|
|
6
|
+
/** The font declarations of a typography variant, weight included or not. */
|
|
7
|
+
function type(variant, weight = variant.fontWeight) {
|
|
8
|
+
return `font-size: ${variant.fontSize}px;
|
|
9
|
+
font-weight: ${weight};
|
|
10
|
+
letter-spacing: ${variant.letterSpacing}px;
|
|
11
|
+
line-height: ${variant.lineHeight}px;`;
|
|
12
|
+
}
|
|
13
|
+
/*
|
|
14
|
+
* The footer sits on the inverse band (`Band tone="inverse"`), which
|
|
15
|
+
* re-scopes the theme's words, muted words and hairline, so these rules
|
|
16
|
+
* read the ordinary variables. Group labels are the band's words at label
|
|
17
|
+
* weight; links are its muted words in label size, no underline (a list
|
|
18
|
+
* of links in a named `nav`), the band's words with an underline on hover
|
|
19
|
+
* and focus, and the current page in the band's words at label weight. The
|
|
20
|
+
* link rules match the band's running-text link rule's specificity and
|
|
21
|
+
* win by coming after it (`cssSiteFooterClasses` follows `cssBandClasses`;
|
|
22
|
+
* a test holds the order).
|
|
23
|
+
* Below `md` the brand spans two columns of groups; from `md` the brand
|
|
24
|
+
* and the groups share one wrapping row, spread apart.
|
|
25
|
+
*/
|
|
26
|
+
export function cssSiteFooterClasses() {
|
|
27
|
+
return `.sw-site-footer-top {
|
|
28
|
+
display: grid;
|
|
29
|
+
gap: var(--sw-space-6) var(--sw-space-5);
|
|
30
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.sw-site-footer-brand {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
gap: var(--sw-space-3);
|
|
37
|
+
grid-column: 1 / -1;
|
|
38
|
+
max-width: 20rem;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.sw-site-footer-brand > :first-child {
|
|
42
|
+
align-self: flex-start;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.sw-site-footer-tagline {
|
|
46
|
+
color: var(--sw-color-muted);
|
|
47
|
+
margin: 0;
|
|
48
|
+
${type(label, 400)}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.sw-site-footer-group {
|
|
52
|
+
display: flex;
|
|
53
|
+
flex-direction: column;
|
|
54
|
+
gap: var(--sw-space-3);
|
|
55
|
+
min-width: 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.sw-site-footer-label {
|
|
59
|
+
color: var(--sw-color-text);
|
|
60
|
+
margin: 0;
|
|
61
|
+
${type(caption, 600)}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.sw-site-footer-links {
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
gap: var(--sw-space-2);
|
|
68
|
+
list-style: none;
|
|
69
|
+
margin: 0;
|
|
70
|
+
padding: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[data-theme] .sw-band-inverse a.sw-site-footer-link {
|
|
74
|
+
color: var(--sw-color-muted);
|
|
75
|
+
display: inline-flex;
|
|
76
|
+
${type(label, 400)}
|
|
77
|
+
overflow-wrap: anywhere;
|
|
78
|
+
text-decoration-color: transparent;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
[data-theme] .sw-band-inverse a.sw-site-footer-link:is(:hover, :focus-visible) {
|
|
82
|
+
color: var(--sw-color-text);
|
|
83
|
+
text-decoration-color: currentColor;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-theme] .sw-band-inverse a.sw-site-footer-link[aria-current='page'] {
|
|
87
|
+
color: var(--sw-color-text);
|
|
88
|
+
font-weight: ${label.fontWeight};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.sw-site-footer-bottom {
|
|
92
|
+
align-items: center;
|
|
93
|
+
border-top: 1px solid var(--sw-color-border);
|
|
94
|
+
color: var(--sw-color-muted);
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-wrap: wrap;
|
|
97
|
+
gap: var(--sw-space-3);
|
|
98
|
+
justify-content: space-between;
|
|
99
|
+
margin-top: var(--sw-space-6);
|
|
100
|
+
padding-top: var(--sw-space-4);
|
|
101
|
+
${type(caption)}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.sw-site-footer-end {
|
|
105
|
+
margin-inline-start: auto;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@media ${breakpointQuery('from', 'md')} {
|
|
109
|
+
.sw-site-footer-top {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-wrap: wrap;
|
|
112
|
+
gap: var(--sw-space-6) var(--sw-space-8);
|
|
113
|
+
justify-content: space-between;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@media ${coarsePointerQuery} {
|
|
118
|
+
[data-theme] .sw-band-inverse a.sw-site-footer-link {
|
|
119
|
+
align-items: center;
|
|
120
|
+
min-height: ${touchTarget};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.sw-site-footer-links {
|
|
124
|
+
gap: 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@media (forced-colors: active) {
|
|
129
|
+
[data-theme] .sw-band-inverse a.sw-site-footer-link {
|
|
130
|
+
color: LinkText;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.sw-site-footer-bottom {
|
|
134
|
+
border-top-color: CanvasText;
|
|
135
|
+
}
|
|
136
|
+
}`;
|
|
137
|
+
}
|
|
138
|
+
export function siteFooterClassCatalog() {
|
|
139
|
+
return [
|
|
140
|
+
'sw-site-footer',
|
|
141
|
+
'sw-site-footer-top',
|
|
142
|
+
'sw-site-footer-brand',
|
|
143
|
+
'sw-site-footer-tagline',
|
|
144
|
+
'sw-site-footer-group',
|
|
145
|
+
'sw-site-footer-label',
|
|
146
|
+
'sw-site-footer-links',
|
|
147
|
+
'sw-site-footer-link',
|
|
148
|
+
'sw-site-footer-bottom',
|
|
149
|
+
'sw-site-footer-legal',
|
|
150
|
+
'sw-site-footer-end',
|
|
151
|
+
];
|
|
152
|
+
}
|