@stealthscale/component-screen 0.0.1 → 0.2.1
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/README.md +211 -54
- package/dist/cyclonedx/bom.json +1 -1
- package/dist/index.d.ts +327 -444
- package/dist/index.js +2246 -1905
- package/dist/recipe-DRMsitrw.js +283 -0
- package/dist/{recipe-CRJrRAI8.js → recipe-sZAQY6Kq.js} +467 -456
- package/dist/root-DDwipXru.d.ts +327 -0
- package/dist/root-qEh4u7y5.js +1182 -0
- package/dist/shell.d.ts +42 -0
- package/dist/shell.js +166 -0
- package/dist/theme.js +4 -3
- package/package.json +57 -41
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { i as NARROW$1, n as FOLDING } from "./recipe-DRMsitrw.js";
|
|
2
|
+
import { CONTROL_INSET_END, CONTROL_INSET_START, axis, below, cornerVariants, defineSlotRecipe, dense, divider, interactive, motion, onSlot, onSlots, paletteVariants, sizeVariants, surface, truncate } from "@stealthscale/theme/authoring";
|
|
2
3
|
//#region src/action-bar/recipe.ts
|
|
3
4
|
/**
|
|
4
5
|
* Styles the action bar, a panel fixed to the bottom of the window with the actions for what a
|
|
@@ -9,8 +10,9 @@ import { CONTROL_INSET_END, CONTROL_INSET_START, axis, below, cornerVariants, de
|
|
|
9
10
|
* recipe passes its variants from an ancestor. The positioner spans the window inside the inset
|
|
10
11
|
* and takes no pointer events, so the page around the bar remains pressable. The toolbar inside
|
|
11
12
|
* the bar is as wide as the bar, which is at least `sizes.2xl`, 672px. The toolbar folds when it
|
|
12
|
-
* is narrower than the `sm` breakpoint, 640px
|
|
13
|
-
* the
|
|
13
|
+
* is narrower than the `sm` breakpoint, 640px, and while its controls need more room than the
|
|
14
|
+
* window leaves the bar. The minimum width makes it fold on the width of the window and not on
|
|
15
|
+
* the width of its folded content. The recipe has no `palette` axis,
|
|
14
16
|
* because the bar reads the neutral `bg.panel`, and no `effect` axis, because the bar is not a
|
|
15
17
|
* control.
|
|
16
18
|
*/
|
|
@@ -37,7 +39,7 @@ const ALIGNED = {
|
|
|
37
39
|
/**
|
|
38
40
|
* Defines the action bar recipe, which places the bar in the middle of the bottom edge by default.
|
|
39
41
|
*/
|
|
40
|
-
const recipe$
|
|
42
|
+
const recipe$7 = defineSlotRecipe({
|
|
41
43
|
base: {
|
|
42
44
|
closeTrigger: { flexShrink: "0" },
|
|
43
45
|
content: {
|
|
@@ -85,6 +87,98 @@ const recipe$8 = defineSlotRecipe({
|
|
|
85
87
|
placement: onSlot("positioner", axis(PLACEMENTS, (placement) => ({ justifyContent: ALIGNED[placement] }))()) }
|
|
86
88
|
});
|
|
87
89
|
//#endregion
|
|
90
|
+
//#region src/resize/widths.ts
|
|
91
|
+
/**
|
|
92
|
+
* Attribute an element has while a drag inside it resizes a panel or a column.
|
|
93
|
+
*/
|
|
94
|
+
const RESIZING = "data-resizing";
|
|
95
|
+
/**
|
|
96
|
+
* Returns the CSS length of a width a person resized an element to: the width, and never wider than
|
|
97
|
+
* its limit, so a width stored on a wide screen fits a narrow one.
|
|
98
|
+
*
|
|
99
|
+
* @param width - The width, in pixels.
|
|
100
|
+
* @param max - The widest width, in pixels. Half the window where left out.
|
|
101
|
+
* @returns The length, such as `min(320px, 50vw)`.
|
|
102
|
+
*/
|
|
103
|
+
function lengthOf(width, max) {
|
|
104
|
+
const limit = max === void 0 ? "50vw" : `${String(max)}px`;
|
|
105
|
+
return `min(${String(width)}px, ${limit})`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Returns a width held between the bounds.
|
|
109
|
+
*
|
|
110
|
+
* @param width - The width asked for.
|
|
111
|
+
* @param bounds - The narrowest and the widest width.
|
|
112
|
+
* @returns The width, raised to the narrowest or lowered to the widest.
|
|
113
|
+
*/
|
|
114
|
+
function clamped(width, { max, min }) {
|
|
115
|
+
return Math.min(Math.max(width, min), max);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns 1 where the pointer moving to the physical right widens the element, and -1 where it
|
|
119
|
+
* narrows it.
|
|
120
|
+
*
|
|
121
|
+
* @param edge - Side of the page the element is on.
|
|
122
|
+
* @param rtl - Whether the page reads right to left.
|
|
123
|
+
*/
|
|
124
|
+
function growthOf(edge, rtl) {
|
|
125
|
+
return edge === "start" === !rtl ? 1 : -1;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Returns the width a key moves the element to.
|
|
129
|
+
*
|
|
130
|
+
* @param key - The key pressed, as `KeyboardEvent.key` spells it.
|
|
131
|
+
* @param shift - Whether Shift is held.
|
|
132
|
+
* @param width - The element's width now.
|
|
133
|
+
* @param scale - The narrowest and the widest width, and the direction the width grows in.
|
|
134
|
+
* @returns The new width, or undefined for a key that resizes nothing.
|
|
135
|
+
*/
|
|
136
|
+
function keyedWidth(key, shift, width, scale) {
|
|
137
|
+
const step = (shift ? 50 : 10) * scale.growth;
|
|
138
|
+
if (key === "ArrowRight") return clamped(width + step, scale);
|
|
139
|
+
if (key === "ArrowLeft") return clamped(width - step, scale);
|
|
140
|
+
if (key === "Home") return scale.min;
|
|
141
|
+
if (key === "End") return scale.max;
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
//#region src/resize/strip.ts
|
|
145
|
+
/**
|
|
146
|
+
* Styles the strip on the edge of a panel or a column that a person presses, drags or focuses.
|
|
147
|
+
*
|
|
148
|
+
* @remarks
|
|
149
|
+
* The strip is 24px wide and transparent, with a line down its middle under the pointer, on
|
|
150
|
+
* keyboard focus and while a drag inside its holder runs. A separator, the strip of an element a
|
|
151
|
+
* person resizes, takes the column resize cursor. The strip is hidden under a coarse pointer,
|
|
152
|
+
* where a finger presses the menu button instead. The module imports no React, because the theme
|
|
153
|
+
* plugin evaluates the recipes that read it in Node.
|
|
154
|
+
*/
|
|
155
|
+
/**
|
|
156
|
+
* Styles the strip, with its placement left to the recipe that reads it.
|
|
157
|
+
*/
|
|
158
|
+
const STRIP$3 = {
|
|
159
|
+
...interactive(),
|
|
160
|
+
_after: {
|
|
161
|
+
background: "transparent",
|
|
162
|
+
content: "\"\"",
|
|
163
|
+
inlineSize: "{borderWidths.indicator}",
|
|
164
|
+
insetBlock: "0",
|
|
165
|
+
insetInlineStart: "calc(50% - {borderWidths.indicator} / 2)",
|
|
166
|
+
position: "absolute"
|
|
167
|
+
},
|
|
168
|
+
_focusVisible: { _after: { background: "colorPalette.focusRing" } },
|
|
169
|
+
_hover: { _after: { background: "border.emphasized" } },
|
|
170
|
+
_touch: { display: "none" },
|
|
171
|
+
"&[role=separator]": { cursor: "resizeColumn" },
|
|
172
|
+
[`[${RESIZING}] &`]: { _after: { background: "border.emphasized" } },
|
|
173
|
+
appearance: "none",
|
|
174
|
+
background: "transparent",
|
|
175
|
+
borderWidth: "0",
|
|
176
|
+
colorPalette: "neutral",
|
|
177
|
+
inlineSize: "6",
|
|
178
|
+
padding: "0",
|
|
179
|
+
zIndex: "docked"
|
|
180
|
+
};
|
|
181
|
+
//#endregion
|
|
88
182
|
//#region src/app-shell/metrics.ts
|
|
89
183
|
/**
|
|
90
184
|
* Names the custom properties and attributes the app shell reads, and defines the style objects
|
|
@@ -115,10 +209,24 @@ const PANEL_RAIL = "--app-shell-panel-rail";
|
|
|
115
209
|
*/
|
|
116
210
|
const STICKY_OFFSET$1 = "--app-shell-sticky-offset";
|
|
117
211
|
/**
|
|
118
|
-
* Custom property on the root with the height of every pinned bar
|
|
212
|
+
* Custom property on the root with the height of every pinned bar, the bars in a pane included,
|
|
213
|
+
* which a page's sticky bands stick under.
|
|
119
214
|
*/
|
|
120
215
|
const STICKY_TOP$1 = "--app-shell-sticky-top";
|
|
121
216
|
/**
|
|
217
|
+
* Custom property on the root with the height of the pinned bars above the body, which a panel
|
|
218
|
+
* that sticks under them reads.
|
|
219
|
+
*
|
|
220
|
+
* @remarks
|
|
221
|
+
* A bar in a pane is beside the panels and not above them, so a panel sticks under the root's
|
|
222
|
+
* own bars alone.
|
|
223
|
+
*/
|
|
224
|
+
const PANEL_TOP = "--app-shell-panel-top";
|
|
225
|
+
/**
|
|
226
|
+
* Custom property on the root with the height of the pinned bars in a pane.
|
|
227
|
+
*/
|
|
228
|
+
const PANE_TOP = "--app-shell-pane-top";
|
|
229
|
+
/**
|
|
122
230
|
* Custom property an ancestor sets to the height of the shell's window.
|
|
123
231
|
*
|
|
124
232
|
* @remarks
|
|
@@ -140,14 +248,15 @@ const WINDOW = `var(${WINDOW_HEIGHT}, 100dvh)`;
|
|
|
140
248
|
*/
|
|
141
249
|
const SETTLED = "data-settled";
|
|
142
250
|
/**
|
|
143
|
-
* Styles the transition of a moving part, with no motion under reduced motion
|
|
144
|
-
*
|
|
251
|
+
* Styles the transition of a moving part, with no motion under reduced motion, before the root has
|
|
252
|
+
* settled, or while a person drags a panel's width.
|
|
145
253
|
*/
|
|
146
254
|
const MOVING = {
|
|
147
255
|
_motionReduce: { transitionDuration: "0s" },
|
|
148
256
|
transitionDuration: "move",
|
|
149
257
|
transitionTimingFunction: "move",
|
|
150
|
-
[`.${CLASS$5}__root:not([${SETTLED}]) &`]: { transitionDuration: "0s" }
|
|
258
|
+
[`.${CLASS$5}__root:not([${SETTLED}]) &`]: { transitionDuration: "0s" },
|
|
259
|
+
[`.${CLASS$5}__root[${RESIZING}] &`]: { transitionDuration: "0s" }
|
|
151
260
|
};
|
|
152
261
|
/**
|
|
153
262
|
* Width of a panel over the page: its open width, and never closer than a rail's width to the far
|
|
@@ -236,16 +345,16 @@ const PINNED = {
|
|
|
236
345
|
zIndex: "sticky"
|
|
237
346
|
};
|
|
238
347
|
/**
|
|
239
|
-
* Styles a panel in the body while the window scrolls: stuck under the pinned bars and as
|
|
240
|
-
* the height they leave.
|
|
348
|
+
* Styles a panel in the body while the window scrolls: stuck under the root's pinned bars and as
|
|
349
|
+
* tall as the height they leave.
|
|
241
350
|
*
|
|
242
351
|
* @remarks
|
|
243
352
|
* The rule selects a panel beside the page only, because the window-scroll look is a variant and
|
|
244
353
|
* applies over the base, where a sheet is fixed and a panel under the page is static.
|
|
245
354
|
*/
|
|
246
355
|
const STUCK$1 = { ["&:not([data-overlaid], [data-stacked])"]: {
|
|
247
|
-
blockSize: `calc(${WINDOW} - var(${
|
|
248
|
-
insetBlockStart: `var(${
|
|
356
|
+
blockSize: `calc(${WINDOW} - var(${PANEL_TOP}, 0px))`,
|
|
357
|
+
insetBlockStart: `var(${PANEL_TOP}, 0px)`,
|
|
249
358
|
position: "sticky"
|
|
250
359
|
} };
|
|
251
360
|
/**
|
|
@@ -294,38 +403,18 @@ const COLUMN = {
|
|
|
294
403
|
}
|
|
295
404
|
};
|
|
296
405
|
/**
|
|
297
|
-
* Styles the rail:
|
|
298
|
-
* its middle under the pointer and on keyboard focus.
|
|
406
|
+
* Styles the rail: the 24px strip centred on the edge between a panel and the page.
|
|
299
407
|
*
|
|
300
408
|
* @remarks
|
|
301
409
|
* The negative margins take the strip's width back from the row, so the strip overlaps the panel
|
|
302
|
-
* and the page by 12px each and moves neither.
|
|
303
|
-
* a finger presses the menu button instead.
|
|
410
|
+
* and the page by 12px each and moves neither.
|
|
304
411
|
*/
|
|
305
412
|
const RAIL = {
|
|
306
|
-
...
|
|
307
|
-
_after: {
|
|
308
|
-
background: "transparent",
|
|
309
|
-
content: "\"\"",
|
|
310
|
-
inlineSize: "{borderWidths.indicator}",
|
|
311
|
-
insetBlock: "0",
|
|
312
|
-
insetInlineStart: "calc(50% - {borderWidths.indicator} / 2)",
|
|
313
|
-
position: "absolute"
|
|
314
|
-
},
|
|
315
|
-
_focusVisible: { _after: { background: "colorPalette.focusRing" } },
|
|
316
|
-
_hover: { _after: { background: "border.emphasized" } },
|
|
317
|
-
_touch: { display: "none" },
|
|
413
|
+
...STRIP$3,
|
|
318
414
|
alignSelf: "stretch",
|
|
319
|
-
appearance: "none",
|
|
320
|
-
background: "transparent",
|
|
321
|
-
borderWidth: "0",
|
|
322
|
-
colorPalette: "neutral",
|
|
323
415
|
flexShrink: "0",
|
|
324
|
-
inlineSize: "6",
|
|
325
416
|
marginInline: "calc({sizes.6} / -2)",
|
|
326
|
-
|
|
327
|
-
position: "relative",
|
|
328
|
-
zIndex: "docked"
|
|
417
|
+
position: "relative"
|
|
329
418
|
};
|
|
330
419
|
//#endregion
|
|
331
420
|
//#region src/app-shell/recipe.ts
|
|
@@ -334,29 +423,36 @@ const RAIL = {
|
|
|
334
423
|
* and a panel on either side of the page in the body.
|
|
335
424
|
*
|
|
336
425
|
* @remarks
|
|
337
|
-
* The recipe has
|
|
426
|
+
* The recipe has nineteen slots. The body, the main region, a panel's content and a band that
|
|
338
427
|
* scrolls are the primitives package's scroll areas, so every bar in the shell is the theme's:
|
|
339
428
|
* `bodyViewport` and `row` are the body's viewport and content, `mainViewport` is the `main`
|
|
340
429
|
* element, `column` is the content of the main region and of a panel, and `scroller` is the root
|
|
341
|
-
* of a band that scrolls. A
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
* the
|
|
354
|
-
*
|
|
430
|
+
* of a band that scrolls. A pane is a column in the row between the panels, with bars above and
|
|
431
|
+
* below the main region, so the panels run the full height beside the bars. A part that is left
|
|
432
|
+
* out takes no room. Every part is a container: the recipe sets the layout, the scrolling, the
|
|
433
|
+
* motion, the hairlines between regions and the grounds, and the application styles the rest
|
|
434
|
+
* through a theme. The plain look fills no region, so the shell shows the ground it is placed
|
|
435
|
+
* on. The backdrop, a sheet and a pinned bar are filled, because the page is visible under each.
|
|
436
|
+
* A sheet is raised by a shadow. A panel in the body is a track whose width moves between its
|
|
437
|
+
* open and closed widths, and its content keeps the open width, so the track clips the content
|
|
438
|
+
* instead of reflowing it. A panel over the page is fixed to the window with a backdrop behind
|
|
439
|
+
* it. The open and closed widths are the theme's `sizes.sidebar`, `sizes.aside` and `sizes.rail`
|
|
440
|
+
* unless a panel states its own. The window's height is `100dvh` unless an ancestor sets
|
|
441
|
+
* `WINDOW_HEIGHT`, so a shell staged in a box of a fixed height fills the box. The header and
|
|
442
|
+
* the footer pad their content by the middle gap, the status bar pads its row of entries by the
|
|
443
|
+
* smallest gap above and below and the middle gap at the sides, and takes no room while every
|
|
444
|
+
* entry renders nothing. A section pads by the large gap. The recipe has no `palette` and no
|
|
445
|
+
* `effect` axis, because the parts are containers and the components inside them offer their
|
|
446
|
+
* own.
|
|
355
447
|
*/
|
|
356
448
|
/**
|
|
357
449
|
* Styles a plain, divided shell that scrolls its page.
|
|
450
|
+
*
|
|
451
|
+
* @remarks
|
|
452
|
+
* `staticCss` lists every value of `content`, `scroll` and `variant`. A product's frame states
|
|
453
|
+
* them as data, and the compiler emits a variant only where a source states it as a literal.
|
|
358
454
|
*/
|
|
359
|
-
const recipe$
|
|
455
|
+
const recipe$6 = defineSlotRecipe({
|
|
360
456
|
base: {
|
|
361
457
|
aside: {
|
|
362
458
|
...PANEL,
|
|
@@ -412,10 +508,12 @@ const recipe$7 = defineSlotRecipe({
|
|
|
412
508
|
"&[data-sticky]": {
|
|
413
509
|
...PINNED,
|
|
414
510
|
insetBlockStart: `var(${STICKY_OFFSET$1}, 0px)`
|
|
415
|
-
}
|
|
511
|
+
},
|
|
512
|
+
[`.${CLASS$5}__pane > &`]: { "&[data-sticky]": { insetBlockStart: `calc(var(${PANEL_TOP}, 0px) + var(${STICKY_OFFSET$1}, 0px))` } }
|
|
416
513
|
},
|
|
417
514
|
main: {
|
|
418
515
|
flex: "1",
|
|
516
|
+
minBlockSize: "0",
|
|
419
517
|
minInlineSize: "0"
|
|
420
518
|
},
|
|
421
519
|
navbar: {
|
|
@@ -431,16 +529,28 @@ const recipe$7 = defineSlotRecipe({
|
|
|
431
529
|
insetInlineStart: "0"
|
|
432
530
|
}
|
|
433
531
|
},
|
|
532
|
+
pane: {
|
|
533
|
+
display: "flex",
|
|
534
|
+
flex: "1",
|
|
535
|
+
flexDirection: "column",
|
|
536
|
+
minBlockSize: "0",
|
|
537
|
+
minInlineSize: "0"
|
|
538
|
+
},
|
|
434
539
|
rail: RAIL,
|
|
435
540
|
root: {
|
|
436
541
|
display: "flex",
|
|
437
542
|
flexDirection: "column",
|
|
438
|
-
inlineSize: "100%"
|
|
543
|
+
inlineSize: "100%",
|
|
544
|
+
[STICKY_TOP$1]: `calc(var(${PANEL_TOP}, 0px) + var(${PANE_TOP}, 0px))`,
|
|
545
|
+
[`&[${RESIZING}]`]: {
|
|
546
|
+
cursor: "resizeColumn",
|
|
547
|
+
userSelect: "none"
|
|
548
|
+
}
|
|
439
549
|
},
|
|
440
550
|
row: {
|
|
441
551
|
display: "flex",
|
|
442
552
|
"&:has(> [data-stacked])": { flexWrap: "wrap" },
|
|
443
|
-
[`&:has(> [data-stacked]) > .${CLASS$5}__main`]: { flexBasis: "100%" }
|
|
553
|
+
[`&:has(> [data-stacked]) > :is(.${CLASS$5}__main, .${CLASS$5}__pane)`]: { flexBasis: "100%" }
|
|
444
554
|
},
|
|
445
555
|
scroller: SCROLLER,
|
|
446
556
|
section: SECTION,
|
|
@@ -452,12 +562,14 @@ const recipe$7 = defineSlotRecipe({
|
|
|
452
562
|
flexWrap: "wrap",
|
|
453
563
|
paddingBlock: dense("{spacing.gap.xs}"),
|
|
454
564
|
paddingInline: dense("{spacing.gap.md}"),
|
|
455
|
-
rowGap: dense("{spacing.gap.xs}")
|
|
565
|
+
rowGap: dense("{spacing.gap.xs}"),
|
|
566
|
+
"&:empty": { display: "none" }
|
|
456
567
|
},
|
|
457
568
|
trigger: { flexShrink: "0" }
|
|
458
569
|
},
|
|
459
570
|
className: CLASS$5,
|
|
460
571
|
defaultVariants: {
|
|
572
|
+
content: "fluid",
|
|
461
573
|
divided: true,
|
|
462
574
|
scroll: "page",
|
|
463
575
|
variant: "plain"
|
|
@@ -470,6 +582,7 @@ const recipe$7 = defineSlotRecipe({
|
|
|
470
582
|
"bodyViewport",
|
|
471
583
|
"row",
|
|
472
584
|
"navbar",
|
|
585
|
+
"pane",
|
|
473
586
|
"main",
|
|
474
587
|
"mainViewport",
|
|
475
588
|
"aside",
|
|
@@ -483,7 +596,27 @@ const recipe$7 = defineSlotRecipe({
|
|
|
483
596
|
"rail",
|
|
484
597
|
"backdrop"
|
|
485
598
|
],
|
|
599
|
+
staticCss: [{
|
|
600
|
+
content: ["constrained", "fluid"],
|
|
601
|
+
scroll: ["page", "window"],
|
|
602
|
+
variant: [
|
|
603
|
+
"floating",
|
|
604
|
+
"inset",
|
|
605
|
+
"plain"
|
|
606
|
+
]
|
|
607
|
+
}],
|
|
486
608
|
variants: {
|
|
609
|
+
/**
|
|
610
|
+
* Width of the page in the main region: the whole region, or at most the theme's wide page
|
|
611
|
+
* measure, centred in the region.
|
|
612
|
+
*/
|
|
613
|
+
content: {
|
|
614
|
+
constrained: { column: { [`.${CLASS$5}__mainViewport > &`]: {
|
|
615
|
+
marginInline: "auto",
|
|
616
|
+
maxInlineSize: "{sizes.page.wide}"
|
|
617
|
+
} } },
|
|
618
|
+
fluid: { column: { [`.${CLASS$5}__mainViewport > &`]: { maxInlineSize: "none" } } }
|
|
619
|
+
},
|
|
487
620
|
/**
|
|
488
621
|
* Whether a hairline separates each bar and each panel from the page.
|
|
489
622
|
*
|
|
@@ -529,7 +662,7 @@ const recipe$7 = defineSlotRecipe({
|
|
|
529
662
|
[`&:has(> .${CLASS$5}__row > [data-stacked])`]: { overflow: "auto" },
|
|
530
663
|
overflow: "visible"
|
|
531
664
|
},
|
|
532
|
-
mainViewport: { [`.${CLASS$5}__row:has(> [data-stacked]) > .${CLASS$5}__main > &`]: { overflow: "visible" } },
|
|
665
|
+
mainViewport: { [`.${CLASS$5}__row:has(> [data-stacked]) > :is(.${CLASS$5}__main, .${CLASS$5}__pane > .${CLASS$5}__main) > &`]: { overflow: "visible" } },
|
|
533
666
|
root: { blockSize: WINDOW },
|
|
534
667
|
row: {
|
|
535
668
|
"&:has(> [data-stacked])": { blockSize: "auto" },
|
|
@@ -552,7 +685,9 @@ const recipe$7 = defineSlotRecipe({
|
|
|
552
685
|
* `plain` fills nothing, so every region shows the ground the shell is placed on: the page's
|
|
553
686
|
* `bg` in an application, or a staging box's own fill. A sidebar in a panel paints its own
|
|
554
687
|
* ground. `inset` gives the main region `surface()`, the panel ground with a hairline and a
|
|
555
|
-
* shadow, over a `bg.subtle` root
|
|
688
|
+
* shadow, over a `bg.subtle` root, and gives it to the pane instead where the main region is
|
|
689
|
+
* in one, so the bars in the pane are on the card too. `floating` gives each panel's content
|
|
690
|
+
* `surface()` instead.
|
|
556
691
|
*/
|
|
557
692
|
variant: {
|
|
558
693
|
floating: {
|
|
@@ -565,7 +700,11 @@ const recipe$7 = defineSlotRecipe({
|
|
|
565
700
|
root: { background: "bg.subtle" }
|
|
566
701
|
},
|
|
567
702
|
inset: {
|
|
568
|
-
main: {
|
|
703
|
+
main: { [`&:not(.${CLASS$5}__pane > *)`]: {
|
|
704
|
+
...surface(),
|
|
705
|
+
margin: dense("{spacing.gap.xs}")
|
|
706
|
+
} },
|
|
707
|
+
pane: {
|
|
569
708
|
...surface(),
|
|
570
709
|
margin: dense("{spacing.gap.xs}")
|
|
571
710
|
},
|
|
@@ -604,7 +743,7 @@ const CLASS$4 = "floating-panel";
|
|
|
604
743
|
/**
|
|
605
744
|
* Width of a resize trigger's strip, and the side of a corner's square.
|
|
606
745
|
*/
|
|
607
|
-
const STRIP$
|
|
746
|
+
const STRIP$2 = "{sizes.2}";
|
|
608
747
|
/**
|
|
609
748
|
* Stacking level of the positioner: the banner level of the z-index scale plus the panel's place in
|
|
610
749
|
* the stack of open panels, which the machine writes as `--z-index`.
|
|
@@ -617,15 +756,16 @@ const RING_OFFSET = "--scroll-area-ring-offset";
|
|
|
617
756
|
/**
|
|
618
757
|
* Defines the floating panel recipe.
|
|
619
758
|
*/
|
|
620
|
-
const recipe$
|
|
759
|
+
const recipe$5 = defineSlotRecipe({
|
|
621
760
|
base: {
|
|
622
761
|
body: {
|
|
623
|
-
|
|
624
|
-
|
|
762
|
+
textStyle: "body.sm",
|
|
763
|
+
padding: dense("{spacing.inset.sm}")
|
|
625
764
|
},
|
|
626
765
|
closeTrigger: { flexShrink: "0" },
|
|
627
766
|
content: {
|
|
628
767
|
...motion("scale-fade.in", "scale-fade.out"),
|
|
768
|
+
focusVisibleRing: "outside",
|
|
629
769
|
background: "bg.panel",
|
|
630
770
|
borderColor: "transparent",
|
|
631
771
|
borderRadius: "l3",
|
|
@@ -636,7 +776,6 @@ const recipe$6 = defineSlotRecipe({
|
|
|
636
776
|
display: "flex",
|
|
637
777
|
flexDirection: "column",
|
|
638
778
|
focusRingColor: "colorPalette.focusRing",
|
|
639
|
-
focusVisibleRing: "outside",
|
|
640
779
|
position: "relative"
|
|
641
780
|
},
|
|
642
781
|
control: {
|
|
@@ -677,11 +816,11 @@ const recipe$6 = defineSlotRecipe({
|
|
|
677
816
|
},
|
|
678
817
|
positioner: { zIndex: LAYERED },
|
|
679
818
|
resizeTrigger: {
|
|
680
|
-
"&:is([data-axis=e], [data-axis=w])": { inlineSize: STRIP$
|
|
681
|
-
"&:is([data-axis=n], [data-axis=s])": { blockSize: STRIP$
|
|
819
|
+
"&:is([data-axis=e], [data-axis=w])": { inlineSize: STRIP$2 },
|
|
820
|
+
"&:is([data-axis=n], [data-axis=s])": { blockSize: STRIP$2 },
|
|
682
821
|
"&:is([data-axis=ne], [data-axis=nw], [data-axis=se], [data-axis=sw])": {
|
|
683
|
-
blockSize: STRIP$
|
|
684
|
-
inlineSize: STRIP$
|
|
822
|
+
blockSize: STRIP$2,
|
|
823
|
+
inlineSize: STRIP$2
|
|
685
824
|
},
|
|
686
825
|
"&[data-disabled]": { display: "none" },
|
|
687
826
|
zIndex: "docked"
|
|
@@ -690,8 +829,8 @@ const recipe$6 = defineSlotRecipe({
|
|
|
690
829
|
scroller: {
|
|
691
830
|
"&[hidden]": { display: "none" },
|
|
692
831
|
flex: "1",
|
|
693
|
-
marginBlockEnd: STRIP$
|
|
694
|
-
marginInlineEnd: STRIP$
|
|
832
|
+
marginBlockEnd: STRIP$2,
|
|
833
|
+
marginInlineEnd: STRIP$2,
|
|
695
834
|
minBlockSize: "0",
|
|
696
835
|
[RING_OFFSET]: "calc({borderWidths.ring} * -1)"
|
|
697
836
|
},
|
|
@@ -701,8 +840,8 @@ const recipe$6 = defineSlotRecipe({
|
|
|
701
840
|
},
|
|
702
841
|
title: {
|
|
703
842
|
...truncate(),
|
|
704
|
-
|
|
705
|
-
|
|
843
|
+
textStyle: "label.md",
|
|
844
|
+
fontWeight: "semibold"
|
|
706
845
|
},
|
|
707
846
|
trigger: {
|
|
708
847
|
...interactive(),
|
|
@@ -730,58 +869,11 @@ const recipe$6 = defineSlotRecipe({
|
|
|
730
869
|
]
|
|
731
870
|
});
|
|
732
871
|
//#endregion
|
|
733
|
-
//#region src/folding/folding.ts
|
|
734
|
-
/**
|
|
735
|
-
* Styles an action that folds to its icon while its row is narrow, for the page, the toolbar and
|
|
736
|
-
* the section.
|
|
737
|
-
*
|
|
738
|
-
* @remarks
|
|
739
|
-
* A secondary action shows its icon alone, and its words remain for a screen reader. A tertiary
|
|
740
|
-
* action renders nothing on a narrow row and runs from the row's menu, which the action registers
|
|
741
|
-
* with. The row measures its own width, so a row beside an open sidebar folds on its own width
|
|
742
|
-
* and the caller does not write a breakpoint.
|
|
743
|
-
*/
|
|
744
|
-
/**
|
|
745
|
-
* Attribute an action sets on itself while its own row is narrow.
|
|
746
|
-
*
|
|
747
|
-
* @remarks
|
|
748
|
-
* The action reads the state from its row's context, so a narrow ancestor folds no action of a
|
|
749
|
-
* wider row inside it. A bar fixed to the window is wider than the page around it in the
|
|
750
|
-
* document.
|
|
751
|
-
*/
|
|
752
|
-
const NARROW$2 = "data-narrow";
|
|
753
|
-
/**
|
|
754
|
-
* Attribute an action sets to its priority.
|
|
755
|
-
*
|
|
756
|
-
* @remarks
|
|
757
|
-
* The priority is an attribute and not an axis, because a slot recipe resolves its variants once,
|
|
758
|
-
* at the root, and each action in a row folds on its own priority.
|
|
759
|
-
*/
|
|
760
|
-
const PRIORITY = "data-priority";
|
|
761
|
-
/**
|
|
762
|
-
* Styles an action by its priority while its row is narrow.
|
|
763
|
-
*
|
|
764
|
-
* @remarks
|
|
765
|
-
* Every action keeps its words on one line at every width, because a wrapped control would make
|
|
766
|
-
* the row taller. A secondary action hides its element children other than its icon with
|
|
767
|
-
* `srOnly`, so it keeps its accessible name, and renders as a square around its icon. Its words
|
|
768
|
-
* must be in an element, because a CSS selector cannot select a bare text node. A primary action
|
|
769
|
-
* is unchanged.
|
|
770
|
-
*/
|
|
771
|
-
const FOLDING = {
|
|
772
|
-
[`&[${PRIORITY}=secondary]`]: { [`&[${NARROW$2}]`]: {
|
|
773
|
-
"& > :not(svg)": { srOnly: true },
|
|
774
|
-
aspectRatio: "square",
|
|
775
|
-
justifyContent: "center",
|
|
776
|
-
paddingInline: "0"
|
|
777
|
-
} },
|
|
778
|
-
whiteSpace: "nowrap"
|
|
779
|
-
};
|
|
780
|
-
//#endregion
|
|
781
872
|
//#region src/page/metrics.ts
|
|
782
873
|
/**
|
|
783
|
-
* Computes the rules the page recipe writes
|
|
784
|
-
* picker opens and the title's heading
|
|
874
|
+
* Computes the rules the page recipe writes at each of its sizes: the padding and gaps of the
|
|
875
|
+
* bands, the tabs in the navigation band, the panel the tab picker opens and the title's heading
|
|
876
|
+
* role.
|
|
785
877
|
*
|
|
786
878
|
* @remarks
|
|
787
879
|
* The module is separate from the recipe so the recipe is under the 300-line limit. It imports no
|
|
@@ -804,14 +896,35 @@ const TABS = "tabs";
|
|
|
804
896
|
*/
|
|
805
897
|
const COMMAND = "command";
|
|
806
898
|
/**
|
|
807
|
-
* Selects the
|
|
899
|
+
* Selects the strip of tabs in the navigation band: the tabs' root, or the `Page.Tabs` slot where
|
|
900
|
+
* the tabs' root contains the panels too and the band contains the list alone.
|
|
808
901
|
*/
|
|
809
|
-
const
|
|
902
|
+
const STRIP$1 = `:is(.${TABS}__root, .${CLASS$3}__tabs)`;
|
|
903
|
+
/**
|
|
904
|
+
* Selects the strip of tabs as a child of the navigation band.
|
|
905
|
+
*/
|
|
906
|
+
const TABS_IN_NAV = `& > ${STRIP$1}`;
|
|
810
907
|
/**
|
|
811
908
|
* Selects every tab of a strip in the navigation band.
|
|
812
909
|
*/
|
|
813
910
|
const TAB_IN_NAV = `& .${TABS}__trigger`;
|
|
814
911
|
/**
|
|
912
|
+
* Sizes the page offers, which a section in the page reads too.
|
|
913
|
+
*/
|
|
914
|
+
const STEPS = [
|
|
915
|
+
"sm",
|
|
916
|
+
"md",
|
|
917
|
+
"lg"
|
|
918
|
+
];
|
|
919
|
+
/**
|
|
920
|
+
* Selects a band followed by the navigation, which then has the hairline.
|
|
921
|
+
*/
|
|
922
|
+
const BEFORE_NAV = `&:has(+ .${CLASS$3}__nav)`;
|
|
923
|
+
/**
|
|
924
|
+
* Selects a navigation band with a strip of tabs, which is flush with the band's hairline.
|
|
925
|
+
*/
|
|
926
|
+
const WITH_TABS = `&:has(> ${STRIP$1})`;
|
|
927
|
+
/**
|
|
815
928
|
* Tab height and inline inset per page size: a medium or large page's tabs are 48px tall and inset
|
|
816
929
|
* by the `md` inset, a small page's 44px and the `sm` inset.
|
|
817
930
|
*/
|
|
@@ -877,18 +990,65 @@ const NARROW_TITLE = `.${CLASS$3}__root[data-narrow] > .${CLASS$3}__header > &`;
|
|
|
877
990
|
*/
|
|
878
991
|
const TITLES = {
|
|
879
992
|
lg: {
|
|
880
|
-
|
|
881
|
-
textStyle: "heading.
|
|
993
|
+
textStyle: "heading.xl",
|
|
994
|
+
[NARROW_TITLE]: { textStyle: "heading.lg" }
|
|
882
995
|
},
|
|
883
996
|
md: {
|
|
884
|
-
|
|
885
|
-
textStyle: "heading.
|
|
997
|
+
textStyle: "heading.lg",
|
|
998
|
+
[NARROW_TITLE]: { textStyle: "heading.md" }
|
|
886
999
|
},
|
|
887
1000
|
sm: {
|
|
888
|
-
|
|
889
|
-
textStyle: "heading.
|
|
1001
|
+
textStyle: "heading.md",
|
|
1002
|
+
[NARROW_TITLE]: { textStyle: "heading.sm" }
|
|
890
1003
|
}
|
|
891
1004
|
};
|
|
1005
|
+
/**
|
|
1006
|
+
* Rules the recipe's `size` axis writes on each slot it sizes, at the page's three sizes.
|
|
1007
|
+
*/
|
|
1008
|
+
const SIZES = onSlots({
|
|
1009
|
+
actions: sizeVariants((size) => ({ gap: dense(`{spacing.gap.${size}}`) }), STEPS),
|
|
1010
|
+
aside: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1011
|
+
banner: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1012
|
+
body: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1013
|
+
context: sizeVariants((size) => ({
|
|
1014
|
+
textStyle: `body.${below(size)}`,
|
|
1015
|
+
gap: dense(`{spacing.gap.${size}}`),
|
|
1016
|
+
marginBlockEnd: size === "lg" ? "{spacing.1}" : "{spacing.0.5}"
|
|
1017
|
+
}), STEPS),
|
|
1018
|
+
description: {
|
|
1019
|
+
lg: { textStyle: "body.md" },
|
|
1020
|
+
md: { textStyle: "body.md" },
|
|
1021
|
+
sm: { textStyle: "body.sm" }
|
|
1022
|
+
},
|
|
1023
|
+
footer: sizeVariants((size) => ({
|
|
1024
|
+
gap: dense(`{spacing.gap.${size}}`),
|
|
1025
|
+
paddingBlock: dense(`{spacing.inset.${size}}`)
|
|
1026
|
+
}), STEPS),
|
|
1027
|
+
header: sizeVariants((size) => ({
|
|
1028
|
+
[BEFORE_NAV]: { paddingBlockEnd: dense(`{spacing.gap.${size}}`) },
|
|
1029
|
+
paddingBlock: dense(`{spacing.inset.${size}}`)
|
|
1030
|
+
}), STEPS),
|
|
1031
|
+
meta: sizeVariants((size) => ({
|
|
1032
|
+
gap: dense(`{spacing.gap.${size}}`),
|
|
1033
|
+
marginInlineStart: dense(`{spacing.gap.${size}}`)
|
|
1034
|
+
}), STEPS),
|
|
1035
|
+
nav: sizeVariants((size) => ({
|
|
1036
|
+
...tabbed(size),
|
|
1037
|
+
paddingBlock: dense(`{spacing.gap.${size}}`),
|
|
1038
|
+
[WITH_TABS]: { paddingBlock: "0" }
|
|
1039
|
+
}), STEPS),
|
|
1040
|
+
palette: sizeVariants(() => FLAT_PALETTE, STEPS),
|
|
1041
|
+
sidebar: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1042
|
+
title: TITLES,
|
|
1043
|
+
toolbar: sizeVariants((size) => ({
|
|
1044
|
+
gap: dense(`{spacing.gap.${size}}`),
|
|
1045
|
+
paddingBlock: dense(`{spacing.gap.${size}}`)
|
|
1046
|
+
}), STEPS),
|
|
1047
|
+
trail: sizeVariants((size) => ({
|
|
1048
|
+
textStyle: `body.${below(size)}`,
|
|
1049
|
+
gap: dense(`{spacing.gap.${below(size)}}`)
|
|
1050
|
+
}), STEPS)
|
|
1051
|
+
});
|
|
892
1052
|
//#endregion
|
|
893
1053
|
//#region src/page/recipe.ts
|
|
894
1054
|
/**
|
|
@@ -906,9 +1066,12 @@ const TITLES = {
|
|
|
906
1066
|
* `folded` below the `sm` breakpoint. From the `lg` breakpoint of the window, a page with an
|
|
907
1067
|
* aside becomes a grid with the aside beside the body, because a rail beside the text needs the
|
|
908
1068
|
* window's width. Below it the aside stacks under the body, or leaves the page with
|
|
909
|
-
* `folds="hide"`. A
|
|
910
|
-
*
|
|
911
|
-
*
|
|
1069
|
+
* `folds="hide"`. A page at least as wide as the `md` breakpoint, by its own measurement, becomes
|
|
1070
|
+
* a grid with its sidebar at the start of the body's row, and a narrower page renders the
|
|
1071
|
+
* sidebar's picker as a band above the body. A sticky aside keeps to the top of its row, under
|
|
1072
|
+
* the shell's sticky bars, and so does a sticky sidebar. The recipe has no `palette` axis,
|
|
1073
|
+
* because a page is layout on the page's surface, and no `effect` axis, because a page is not a
|
|
1074
|
+
* control.
|
|
912
1075
|
*/
|
|
913
1076
|
/**
|
|
914
1077
|
* Custom property the root sets to the room at the page's inline edges.
|
|
@@ -949,10 +1112,15 @@ const STICKY_OFFSET = "--page-sticky-offset";
|
|
|
949
1112
|
*/
|
|
950
1113
|
const STICKY_TOP = "--page-sticky-top";
|
|
951
1114
|
/**
|
|
952
|
-
* Custom property a sticky aside takes, set to the height of the area that scrolls the
|
|
1115
|
+
* Custom property a sticky aside or sidebar takes, set to the height of the area that scrolls the
|
|
1116
|
+
* page.
|
|
953
1117
|
*/
|
|
954
1118
|
const SCROLLPORT = "--page-scrollport";
|
|
955
1119
|
/**
|
|
1120
|
+
* Custom property the sidebar sets to the width a person resized it to.
|
|
1121
|
+
*/
|
|
1122
|
+
const SIDEBAR_SIZE = "--page-sidebar-size";
|
|
1123
|
+
/**
|
|
956
1124
|
* Room a focus ring takes outside an element: its offset and its width.
|
|
957
1125
|
*/
|
|
958
1126
|
const RING_ROOM = "calc(var(--focus-ring-offset, 0px) + var(--focus-ring-width, 0px))";
|
|
@@ -973,23 +1141,41 @@ const STUCK = {
|
|
|
973
1141
|
zIndex: "sticky"
|
|
974
1142
|
};
|
|
975
1143
|
/**
|
|
1144
|
+
* Styles a column that sticks to the top of its row, under the shell's sticky bars and the page's
|
|
1145
|
+
* sticky bands, a gap below them.
|
|
1146
|
+
*/
|
|
1147
|
+
const STICKY_COLUMN = {
|
|
1148
|
+
alignSelf: "start",
|
|
1149
|
+
insetBlockStart: `calc(var(${SHELL_TOP}, 0px) + var(${STICKY_TOP}, 0px) + {spacing.gap.xl})`,
|
|
1150
|
+
position: "sticky"
|
|
1151
|
+
};
|
|
1152
|
+
/**
|
|
1153
|
+
* Caps a sticky column at the height of the area that scrolls the page, less the sticky bars and
|
|
1154
|
+
* bands above it and a gap at each end, as a flex column that its scroll area fills.
|
|
1155
|
+
*/
|
|
1156
|
+
const CAPPED_COLUMN = {
|
|
1157
|
+
display: "flex",
|
|
1158
|
+
flexDirection: "column",
|
|
1159
|
+
maxBlockSize: `calc(var(${SCROLLPORT}, 100dvh) - var(${SHELL_TOP}, 0px) - var(${STICKY_TOP}, 0px) - {spacing.gap.xl} * 2)`
|
|
1160
|
+
};
|
|
1161
|
+
/**
|
|
976
1162
|
* Styles a row that centres its items, wraps and shrinks.
|
|
977
1163
|
*/
|
|
978
|
-
const ROW$
|
|
1164
|
+
const ROW$1 = {
|
|
979
1165
|
alignItems: "center",
|
|
980
1166
|
display: "flex",
|
|
981
1167
|
flexWrap: "wrap",
|
|
982
1168
|
minInlineSize: "0"
|
|
983
1169
|
};
|
|
984
1170
|
/**
|
|
985
|
-
* Selects a band followed by the navigation, which then has the hairline.
|
|
986
|
-
*/
|
|
987
|
-
const BEFORE_NAV = `&:has(+ .${CLASS$3}__nav)`;
|
|
988
|
-
/**
|
|
989
1171
|
* Selects a root with an aside, which lays its bands out as a grid from the `lg` breakpoint.
|
|
990
1172
|
*/
|
|
991
1173
|
const WITH_ASIDE = `&:has(> .${CLASS$3}__aside)`;
|
|
992
1174
|
/**
|
|
1175
|
+
* Selects a root with a sidebar beside its body, which lays its bands out as a grid.
|
|
1176
|
+
*/
|
|
1177
|
+
const WITH_SIDEBAR = `&:has(> .${CLASS$3}__sidebar[data-beside])`;
|
|
1178
|
+
/**
|
|
993
1179
|
* Selects a toolbar in the navigation band.
|
|
994
1180
|
*/
|
|
995
1181
|
const TOOLBAR_IN_NAV = `& > .toolbar__root`;
|
|
@@ -1004,38 +1190,47 @@ const STRIP_IN_NAV = `& .${CLASS$3}__tabs[data-orientation]`;
|
|
|
1004
1190
|
* @remarks
|
|
1005
1191
|
* The body's row takes the remaining height and every other row takes its content's height,
|
|
1006
1192
|
* because the root is at least as tall as the shell's main region and a grid shares spare height
|
|
1007
|
-
* between its `auto` rows.
|
|
1193
|
+
* between its `auto` rows. The sidebar's row holds the picker a narrow page renders in the
|
|
1194
|
+
* sidebar's place, and takes no height without one.
|
|
1008
1195
|
*/
|
|
1009
1196
|
const BESIDE = {
|
|
1010
1197
|
columnGap: dense("{spacing.gap.xl}"),
|
|
1011
1198
|
display: "grid",
|
|
1012
|
-
gridTemplateAreas: "\"banner banner\" \"header header\" \"nav nav\" \"toolbar toolbar\" \"body aside\" \"footer footer\"",
|
|
1199
|
+
gridTemplateAreas: "\"banner banner\" \"header header\" \"nav nav\" \"toolbar toolbar\" \"sidebar sidebar\" \"body aside\" \"footer footer\"",
|
|
1013
1200
|
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
1014
|
-
gridTemplateRows: "auto auto auto auto 1fr auto"
|
|
1201
|
+
gridTemplateRows: "auto auto auto auto auto 1fr auto"
|
|
1015
1202
|
};
|
|
1016
1203
|
/**
|
|
1017
|
-
*
|
|
1204
|
+
* Styles the grid of a page with a sidebar beside its body: every band across, the sidebar at the
|
|
1205
|
+
* start, and an aside under the body.
|
|
1018
1206
|
*/
|
|
1019
|
-
const
|
|
1020
|
-
"
|
|
1021
|
-
"
|
|
1022
|
-
"
|
|
1023
|
-
|
|
1207
|
+
const SIDEBAR_BESIDE = {
|
|
1208
|
+
columnGap: dense("{spacing.gap.xl}"),
|
|
1209
|
+
display: "grid",
|
|
1210
|
+
gridTemplateAreas: "\"banner banner\" \"header header\" \"nav nav\" \"toolbar toolbar\" \"sidebar body\" \"sidebar aside\" \"footer footer\"",
|
|
1211
|
+
gridTemplateColumns: "auto minmax(0, 1fr)",
|
|
1212
|
+
gridTemplateRows: "auto auto auto auto 1fr auto auto"
|
|
1213
|
+
};
|
|
1024
1214
|
/**
|
|
1025
|
-
*
|
|
1215
|
+
* Styles the grid of a page with a sidebar beside its body and an aside beside it from the `lg`
|
|
1216
|
+
* breakpoint: the sidebar, the body and the aside in one row.
|
|
1026
1217
|
*/
|
|
1027
|
-
const
|
|
1218
|
+
const SIDEBAR_AND_ASIDE = {
|
|
1219
|
+
gridTemplateAreas: "\"banner banner banner\" \"header header header\" \"nav nav nav\" \"toolbar toolbar toolbar\" \"sidebar body aside\" \"footer footer footer\"",
|
|
1220
|
+
gridTemplateColumns: "auto minmax(0, 1fr) auto",
|
|
1221
|
+
gridTemplateRows: "auto auto auto auto 1fr auto"
|
|
1222
|
+
};
|
|
1028
1223
|
/**
|
|
1029
1224
|
* Defines the page recipe: a full-width page at size `md` by default.
|
|
1030
1225
|
*/
|
|
1031
|
-
const recipe$
|
|
1226
|
+
const recipe$4 = defineSlotRecipe({
|
|
1032
1227
|
base: {
|
|
1033
1228
|
action: {
|
|
1034
1229
|
...FOLDING,
|
|
1035
1230
|
flexShrink: "0"
|
|
1036
1231
|
},
|
|
1037
1232
|
actions: {
|
|
1038
|
-
...ROW$
|
|
1233
|
+
...ROW$1,
|
|
1039
1234
|
flexWrap: "nowrap",
|
|
1040
1235
|
gridArea: "actions",
|
|
1041
1236
|
justifySelf: "end",
|
|
@@ -1052,14 +1247,8 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1052
1247
|
aside: {
|
|
1053
1248
|
"&[data-folds=hide]": { lgDown: { display: "none" } },
|
|
1054
1249
|
"&[data-sticky]": {
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
lg: {
|
|
1058
|
-
display: "flex",
|
|
1059
|
-
flexDirection: "column",
|
|
1060
|
-
maxBlockSize: `calc(var(${SCROLLPORT}, 100dvh) - var(${SHELL_TOP}, 0px) - var(${STICKY_TOP}, 0px) - {spacing.gap.xl} * 2)`
|
|
1061
|
-
},
|
|
1062
|
-
position: "sticky"
|
|
1250
|
+
...STICKY_COLUMN,
|
|
1251
|
+
lg: CAPPED_COLUMN
|
|
1063
1252
|
},
|
|
1064
1253
|
gridArea: "aside",
|
|
1065
1254
|
lg: { paddingInlineStart: "0" },
|
|
@@ -1089,7 +1278,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1089
1278
|
minBlockSize: "0"
|
|
1090
1279
|
},
|
|
1091
1280
|
context: {
|
|
1092
|
-
...ROW$
|
|
1281
|
+
...ROW$1,
|
|
1093
1282
|
gridArea: "context",
|
|
1094
1283
|
minInlineSize: "0"
|
|
1095
1284
|
},
|
|
@@ -1107,7 +1296,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1107
1296
|
*/
|
|
1108
1297
|
footer: {
|
|
1109
1298
|
...BAND$1,
|
|
1110
|
-
...ROW$
|
|
1299
|
+
...ROW$1,
|
|
1111
1300
|
"&[data-sticky]": {
|
|
1112
1301
|
...STUCK,
|
|
1113
1302
|
insetBlockEnd: "0",
|
|
@@ -1139,7 +1328,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1139
1328
|
marginInlineEnd: dense("{spacing.gap.lg}")
|
|
1140
1329
|
},
|
|
1141
1330
|
meta: {
|
|
1142
|
-
...ROW$
|
|
1331
|
+
...ROW$1,
|
|
1143
1332
|
gridArea: "meta"
|
|
1144
1333
|
},
|
|
1145
1334
|
nav: {
|
|
@@ -1172,14 +1361,64 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1172
1361
|
minInlineSize: "0"
|
|
1173
1362
|
},
|
|
1174
1363
|
root: {
|
|
1364
|
+
[`&[${RESIZING}]`]: {
|
|
1365
|
+
cursor: "resizeColumn",
|
|
1366
|
+
userSelect: "none"
|
|
1367
|
+
},
|
|
1175
1368
|
display: "flex",
|
|
1176
1369
|
flexDirection: "column",
|
|
1177
1370
|
flexGrow: "1",
|
|
1178
1371
|
inlineSize: "100%",
|
|
1179
1372
|
minBlockSize: "100%",
|
|
1180
1373
|
minInlineSize: "0",
|
|
1181
|
-
[WITH_ASIDE]: { lg: BESIDE }
|
|
1374
|
+
[WITH_ASIDE]: { lg: BESIDE },
|
|
1375
|
+
[WITH_SIDEBAR]: {
|
|
1376
|
+
...SIDEBAR_BESIDE,
|
|
1377
|
+
[WITH_ASIDE]: { lg: SIDEBAR_AND_ASIDE }
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
/**
|
|
1381
|
+
* The sidebar: a column beside the body on a page as wide as the `md` breakpoint, and a band
|
|
1382
|
+
* with the picker on a narrower page.
|
|
1383
|
+
*
|
|
1384
|
+
* @remarks
|
|
1385
|
+
* Beside the body the column starts at the gutter, so the fills of its rows start where the
|
|
1386
|
+
* title starts. The column is as wide as the theme's sidebar unless a person resized it. A
|
|
1387
|
+
* sticky sidebar keeps to the top of its row and is at most as tall as the room under the
|
|
1388
|
+
* sticky bands, as a sticky aside is. The handle is centred on the column's end edge, in the
|
|
1389
|
+
* gap before the body.
|
|
1390
|
+
*/
|
|
1391
|
+
sidebar: {
|
|
1392
|
+
...BAND$1,
|
|
1393
|
+
"&[data-beside]": {
|
|
1394
|
+
"&[data-sticky]": {
|
|
1395
|
+
...STICKY_COLUMN,
|
|
1396
|
+
...CAPPED_COLUMN
|
|
1397
|
+
},
|
|
1398
|
+
inlineSize: `var(${SIDEBAR_SIZE}, {sizes.sidebar})`,
|
|
1399
|
+
paddingInlineEnd: "0",
|
|
1400
|
+
position: "relative"
|
|
1401
|
+
},
|
|
1402
|
+
gridArea: "sidebar"
|
|
1403
|
+
},
|
|
1404
|
+
/**
|
|
1405
|
+
* The padding of a sticky sidebar's scroll area, the room a focus ring takes at its edges.
|
|
1406
|
+
*/
|
|
1407
|
+
sidebarContent: { padding: RING_ROOM },
|
|
1408
|
+
/**
|
|
1409
|
+
* The strip on a resizable sidebar's end edge, centred on the edge.
|
|
1410
|
+
*/
|
|
1411
|
+
sidebarHandle: {
|
|
1412
|
+
...STRIP$3,
|
|
1413
|
+
insetBlock: "0",
|
|
1414
|
+
insetInlineEnd: "calc({sizes.6} / -2)",
|
|
1415
|
+
position: "absolute"
|
|
1182
1416
|
},
|
|
1417
|
+
/**
|
|
1418
|
+
* A sticky sidebar's scroll area, pulled out on every side by the room its content's padding
|
|
1419
|
+
* takes, so the content keeps its place.
|
|
1420
|
+
*/
|
|
1421
|
+
sidebarScroller: { margin: `calc(${RING_ROOM} * -1)` },
|
|
1183
1422
|
title: {
|
|
1184
1423
|
gridArea: "title",
|
|
1185
1424
|
minInlineSize: "0",
|
|
@@ -1187,7 +1426,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1187
1426
|
},
|
|
1188
1427
|
toolbar: {
|
|
1189
1428
|
...BAND$1,
|
|
1190
|
-
...ROW$
|
|
1429
|
+
...ROW$1,
|
|
1191
1430
|
"&[data-sticky]": STUCK,
|
|
1192
1431
|
gridArea: "toolbar"
|
|
1193
1432
|
},
|
|
@@ -1250,6 +1489,10 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1250
1489
|
"picker",
|
|
1251
1490
|
"palette",
|
|
1252
1491
|
"toolbar",
|
|
1492
|
+
"sidebar",
|
|
1493
|
+
"sidebarScroller",
|
|
1494
|
+
"sidebarContent",
|
|
1495
|
+
"sidebarHandle",
|
|
1253
1496
|
"body",
|
|
1254
1497
|
"aside",
|
|
1255
1498
|
"asideScroller",
|
|
@@ -1333,49 +1576,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1333
1576
|
* The page offers three sizes, because larger steps belong to a display heading. A section in
|
|
1334
1577
|
* the page reads this size too.
|
|
1335
1578
|
*/
|
|
1336
|
-
size:
|
|
1337
|
-
actions: sizeVariants((size) => ({ gap: dense(`{spacing.gap.${size}}`) }), STEPS),
|
|
1338
|
-
aside: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1339
|
-
banner: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1340
|
-
body: sizeVariants((size) => ({ paddingBlock: dense(`{spacing.inset.${size}}`) }), STEPS),
|
|
1341
|
-
context: sizeVariants((size) => ({
|
|
1342
|
-
gap: dense(`{spacing.gap.${size}}`),
|
|
1343
|
-
marginBlockEnd: size === "lg" ? "{spacing.1}" : "{spacing.0.5}",
|
|
1344
|
-
textStyle: `body.${below(size)}`
|
|
1345
|
-
}), STEPS),
|
|
1346
|
-
description: {
|
|
1347
|
-
lg: { textStyle: "body.md" },
|
|
1348
|
-
md: { textStyle: "body.md" },
|
|
1349
|
-
sm: { textStyle: "body.sm" }
|
|
1350
|
-
},
|
|
1351
|
-
footer: sizeVariants((size) => ({
|
|
1352
|
-
gap: dense(`{spacing.gap.${size}}`),
|
|
1353
|
-
paddingBlock: dense(`{spacing.inset.${size}}`)
|
|
1354
|
-
}), STEPS),
|
|
1355
|
-
header: sizeVariants((size) => ({
|
|
1356
|
-
[BEFORE_NAV]: { paddingBlockEnd: dense(`{spacing.gap.${size}}`) },
|
|
1357
|
-
paddingBlock: dense(`{spacing.inset.${size}}`)
|
|
1358
|
-
}), STEPS),
|
|
1359
|
-
meta: sizeVariants((size) => ({
|
|
1360
|
-
gap: dense(`{spacing.gap.${size}}`),
|
|
1361
|
-
marginInlineStart: dense(`{spacing.gap.${size}}`)
|
|
1362
|
-
}), STEPS),
|
|
1363
|
-
nav: sizeVariants((size) => ({
|
|
1364
|
-
...tabbed(size),
|
|
1365
|
-
paddingBlock: dense(`{spacing.gap.${size}}`),
|
|
1366
|
-
[WITH_TABS]: { paddingBlock: "0" }
|
|
1367
|
-
}), STEPS),
|
|
1368
|
-
palette: sizeVariants(() => FLAT_PALETTE, STEPS),
|
|
1369
|
-
title: TITLES,
|
|
1370
|
-
toolbar: sizeVariants((size) => ({
|
|
1371
|
-
gap: dense(`{spacing.gap.${size}}`),
|
|
1372
|
-
paddingBlock: dense(`{spacing.gap.${size}}`)
|
|
1373
|
-
}), STEPS),
|
|
1374
|
-
trail: sizeVariants((size) => ({
|
|
1375
|
-
gap: dense(`{spacing.gap.${below(size)}}`),
|
|
1376
|
-
textStyle: `body.${below(size)}`
|
|
1377
|
-
}), STEPS)
|
|
1378
|
-
})
|
|
1579
|
+
size: SIZES
|
|
1379
1580
|
}
|
|
1380
1581
|
});
|
|
1381
1582
|
//#endregion
|
|
@@ -1413,7 +1614,7 @@ const AFTER = `.${CLASS$2}__root + &`;
|
|
|
1413
1614
|
/**
|
|
1414
1615
|
* Selects a band of a narrow section.
|
|
1415
1616
|
*/
|
|
1416
|
-
const NARROW
|
|
1617
|
+
const NARROW = `.${CLASS$2}__root[data-narrow] > &`;
|
|
1417
1618
|
/**
|
|
1418
1619
|
* Selects the actions of a narrow section.
|
|
1419
1620
|
*/
|
|
@@ -1457,7 +1658,7 @@ const SPACED = {
|
|
|
1457
1658
|
/**
|
|
1458
1659
|
* Styles a row that centres its items, wraps and shrinks.
|
|
1459
1660
|
*/
|
|
1460
|
-
const ROW
|
|
1661
|
+
const ROW = {
|
|
1461
1662
|
alignItems: "center",
|
|
1462
1663
|
display: "flex",
|
|
1463
1664
|
flexWrap: "wrap",
|
|
@@ -1466,14 +1667,14 @@ const ROW$1 = {
|
|
|
1466
1667
|
/**
|
|
1467
1668
|
* Defines the section recipe: a plain section at size `md` by default.
|
|
1468
1669
|
*/
|
|
1469
|
-
const recipe$
|
|
1670
|
+
const recipe$3 = defineSlotRecipe({
|
|
1470
1671
|
base: {
|
|
1471
1672
|
action: {
|
|
1472
1673
|
...FOLDING,
|
|
1473
1674
|
flexShrink: "0"
|
|
1474
1675
|
},
|
|
1475
1676
|
actions: {
|
|
1476
|
-
...ROW
|
|
1677
|
+
...ROW,
|
|
1477
1678
|
flexWrap: "nowrap",
|
|
1478
1679
|
gridArea: "actions",
|
|
1479
1680
|
justifySelf: "end",
|
|
@@ -1488,7 +1689,7 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1488
1689
|
minInlineSize: "0"
|
|
1489
1690
|
},
|
|
1490
1691
|
footer: {
|
|
1491
|
-
...ROW
|
|
1692
|
+
...ROW,
|
|
1492
1693
|
"& > :last-child:not(:first-child)": { marginInlineStart: "auto" },
|
|
1493
1694
|
justifyContent: "space-between"
|
|
1494
1695
|
},
|
|
@@ -1599,7 +1800,7 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1599
1800
|
}
|
|
1600
1801
|
},
|
|
1601
1802
|
header: {
|
|
1602
|
-
[NARROW
|
|
1803
|
+
[NARROW]: { marginBlockEnd: `var(${BANDS})` },
|
|
1603
1804
|
padding: "0"
|
|
1604
1805
|
},
|
|
1605
1806
|
root: {
|
|
@@ -1644,8 +1845,8 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1644
1845
|
"lg"
|
|
1645
1846
|
]),
|
|
1646
1847
|
description: sizeVariants((size) => ({
|
|
1647
|
-
|
|
1648
|
-
|
|
1848
|
+
textStyle: `body.${below(size)}`,
|
|
1849
|
+
marginBlockStart: size === "lg" ? "{spacing.1}" : "{spacing.0.5}"
|
|
1649
1850
|
}), [
|
|
1650
1851
|
"sm",
|
|
1651
1852
|
"md",
|
|
@@ -1722,7 +1923,7 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1722
1923
|
/**
|
|
1723
1924
|
* Selects a part inside a sidebar collapsed to a rail.
|
|
1724
1925
|
*/
|
|
1725
|
-
const ICONIC
|
|
1926
|
+
const ICONIC = "[data-iconic] &";
|
|
1726
1927
|
/**
|
|
1727
1928
|
* Selects the children of a band that fold to an icon by themselves: a search, a nav block, a
|
|
1728
1929
|
* navigation list and a switcher.
|
|
@@ -1750,7 +1951,7 @@ const BANDED = {
|
|
|
1750
1951
|
display: "flex",
|
|
1751
1952
|
flexDirection: "column",
|
|
1752
1953
|
flexShrink: "0",
|
|
1753
|
-
[ICONIC
|
|
1954
|
+
[ICONIC]: {
|
|
1754
1955
|
alignItems: "center",
|
|
1755
1956
|
[WORDS]: { srOnly: true }
|
|
1756
1957
|
},
|
|
@@ -1810,16 +2011,21 @@ function squared(size) {
|
|
|
1810
2011
|
*/
|
|
1811
2012
|
function banded(size) {
|
|
1812
2013
|
return {
|
|
2014
|
+
textStyle: `label.${below(size)}`,
|
|
1813
2015
|
gap: dense(`{spacing.gap.${below(size)}}`),
|
|
1814
2016
|
[LINES]: { marginInline: marked(size) },
|
|
1815
|
-
padding: dense(`{spacing.gap.${size}}`)
|
|
1816
|
-
textStyle: `label.${below(size)}`
|
|
2017
|
+
padding: dense(`{spacing.gap.${size}}`)
|
|
1817
2018
|
};
|
|
1818
2019
|
}
|
|
1819
2020
|
/**
|
|
1820
2021
|
* Styles a plain sidebar at the middle size.
|
|
2022
|
+
*
|
|
2023
|
+
* @remarks
|
|
2024
|
+
* `staticCss` lists every size and every look. A sidebar in a panel over the page renders at `lg`
|
|
2025
|
+
* whatever its `size`, a product's frame states the size and the look as data, and the compiler
|
|
2026
|
+
* emits a variant only where a source states it as a literal.
|
|
1821
2027
|
*/
|
|
1822
|
-
const recipe$
|
|
2028
|
+
const recipe$2 = defineSlotRecipe({
|
|
1823
2029
|
base: {
|
|
1824
2030
|
content: {
|
|
1825
2031
|
display: "flex",
|
|
@@ -1827,7 +2033,7 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1827
2033
|
},
|
|
1828
2034
|
empty: {
|
|
1829
2035
|
color: "fg.muted",
|
|
1830
|
-
[ICONIC
|
|
2036
|
+
[ICONIC]: { display: "none" },
|
|
1831
2037
|
textAlign: "center"
|
|
1832
2038
|
},
|
|
1833
2039
|
footer: BANDED,
|
|
@@ -1855,7 +2061,7 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1855
2061
|
display: "flex",
|
|
1856
2062
|
flexShrink: "0",
|
|
1857
2063
|
gridColumn: "2 / 3",
|
|
1858
|
-
[ICONIC
|
|
2064
|
+
[ICONIC]: { display: "none" },
|
|
1859
2065
|
justifyContent: "center",
|
|
1860
2066
|
padding: "0"
|
|
1861
2067
|
},
|
|
@@ -1866,18 +2072,18 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1866
2072
|
display: "flex",
|
|
1867
2073
|
fontWeight: "medium",
|
|
1868
2074
|
gridColumn: "1 / 2",
|
|
1869
|
-
[ICONIC
|
|
2075
|
+
[ICONIC]: { srOnly: true },
|
|
1870
2076
|
textTransform: "uppercase"
|
|
1871
2077
|
},
|
|
1872
2078
|
navLabel: {
|
|
1873
2079
|
...truncate(),
|
|
2080
|
+
textStyle: "label.xs",
|
|
1874
2081
|
alignItems: "center",
|
|
1875
2082
|
color: "fg.subtle",
|
|
1876
2083
|
display: "flex",
|
|
1877
2084
|
fontWeight: "medium",
|
|
1878
2085
|
gridColumn: "1 / 2",
|
|
1879
|
-
[ICONIC
|
|
1880
|
-
textStyle: "label.xs",
|
|
2086
|
+
[ICONIC]: { srOnly: true },
|
|
1881
2087
|
textTransform: "uppercase"
|
|
1882
2088
|
},
|
|
1883
2089
|
root: {
|
|
@@ -1892,7 +2098,7 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1892
2098
|
minBlockSize: "0"
|
|
1893
2099
|
},
|
|
1894
2100
|
search: {
|
|
1895
|
-
[ICONIC
|
|
2101
|
+
[ICONIC]: {
|
|
1896
2102
|
display: "flex",
|
|
1897
2103
|
justifyContent: "center"
|
|
1898
2104
|
},
|
|
@@ -1921,6 +2127,19 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1921
2127
|
"empty",
|
|
1922
2128
|
"separator"
|
|
1923
2129
|
],
|
|
2130
|
+
staticCss: [{
|
|
2131
|
+
size: [
|
|
2132
|
+
"sm",
|
|
2133
|
+
"md",
|
|
2134
|
+
"lg"
|
|
2135
|
+
],
|
|
2136
|
+
variant: [
|
|
2137
|
+
"outline",
|
|
2138
|
+
"plain",
|
|
2139
|
+
"subtle",
|
|
2140
|
+
"surface"
|
|
2141
|
+
]
|
|
2142
|
+
}],
|
|
1924
2143
|
variants: {
|
|
1925
2144
|
size: onSlots({
|
|
1926
2145
|
/**
|
|
@@ -1938,8 +2157,8 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1938
2157
|
"lg"
|
|
1939
2158
|
]),
|
|
1940
2159
|
empty: sizeVariants((size) => ({
|
|
1941
|
-
|
|
1942
|
-
|
|
2160
|
+
textStyle: `body.${size}`,
|
|
2161
|
+
padding: dense(`{spacing.inset.${size}}`)
|
|
1943
2162
|
}), [
|
|
1944
2163
|
"sm",
|
|
1945
2164
|
"md",
|
|
@@ -1978,10 +2197,10 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1978
2197
|
"lg"
|
|
1979
2198
|
]),
|
|
1980
2199
|
navHeading: sizeVariants((size) => ({
|
|
2200
|
+
textStyle: "label.xs",
|
|
1981
2201
|
marginBlockEnd: `calc(${dense(`{spacing.gap.${size}}`)} * -0.5)`,
|
|
1982
2202
|
paddingBlock: dense("{spacing.gap.xs}"),
|
|
1983
|
-
paddingInline: marked(size)
|
|
1984
|
-
textStyle: "label.xs"
|
|
2203
|
+
paddingInline: marked(size)
|
|
1985
2204
|
}), [
|
|
1986
2205
|
"sm",
|
|
1987
2206
|
"md",
|
|
@@ -2095,7 +2314,7 @@ const PILLED = `&:has(> .${CLASS$1}__resizeTriggerIndicator)`;
|
|
|
2095
2314
|
/**
|
|
2096
2315
|
* Defines the splitter recipe, in the primary palette by default.
|
|
2097
2316
|
*/
|
|
2098
|
-
const recipe$
|
|
2317
|
+
const recipe$1 = defineSlotRecipe({
|
|
2099
2318
|
base: {
|
|
2100
2319
|
panel: {
|
|
2101
2320
|
display: "flex",
|
|
@@ -2104,6 +2323,7 @@ const recipe$2 = defineSlotRecipe({
|
|
|
2104
2323
|
minInlineSize: "0"
|
|
2105
2324
|
},
|
|
2106
2325
|
resizeTrigger: {
|
|
2326
|
+
focusVisibleRing: "outside",
|
|
2107
2327
|
_touch: {
|
|
2108
2328
|
_before: {
|
|
2109
2329
|
content: "\"\"",
|
|
@@ -2129,7 +2349,6 @@ const recipe$2 = defineSlotRecipe({
|
|
|
2129
2349
|
marginBlock: `calc(${STRIP} * -0.5)`
|
|
2130
2350
|
},
|
|
2131
2351
|
focusRingColor: "colorPalette.focusRing",
|
|
2132
|
-
focusVisibleRing: "outside",
|
|
2133
2352
|
justifyItems: "center",
|
|
2134
2353
|
[PILLED]: { _focusVisible: { outlineStyle: "none" } },
|
|
2135
2354
|
position: "relative",
|
|
@@ -2228,224 +2447,6 @@ const recipe$2 = defineSlotRecipe({
|
|
|
2228
2447
|
palette: onSlot("root", paletteVariants()) }
|
|
2229
2448
|
});
|
|
2230
2449
|
//#endregion
|
|
2231
|
-
//#region src/switcher/recipe.ts
|
|
2232
|
-
/**
|
|
2233
|
-
* Declares the switcher's slot recipe, which styles the control that shows the current workspace,
|
|
2234
|
-
* project or environment and opens the menu of the others.
|
|
2235
|
-
*
|
|
2236
|
-
* @remarks
|
|
2237
|
-
* The recipe has six slots. The root slot is the trigger, and the mark, the label, the name, the
|
|
2238
|
-
* detail and the indicator are inside it. `Switcher.Root` is the disclosure package's menu, so
|
|
2239
|
-
* the menu's recipe styles the panel and its rows. The trigger takes the button's looks and
|
|
2240
|
-
* palettes from the same layer styles, so an outlined switcher has the button's light edge. The
|
|
2241
|
-
* mark is a square in the palette's muted fill for an initial, an icon or an avatar. The name and
|
|
2242
|
-
* the detail truncate to keep the control at one height. A pair of chevrons marks a control that
|
|
2243
|
-
* switches and not a direction, so the indicator does not rotate while the menu is open. In a
|
|
2244
|
-
* sidebar closed to icons the control is its mark alone, square, and in a narrow toolbar a
|
|
2245
|
-
* switcher with a mark hides its name. The words remain in the accessible name in both.
|
|
2246
|
-
*/
|
|
2247
|
-
/**
|
|
2248
|
-
* Selects a part of a switcher drawn as its mark alone, in a sidebar closed to icons.
|
|
2249
|
-
*/
|
|
2250
|
-
const ICONIC = ".switcher__root[data-iconic] &";
|
|
2251
|
-
/**
|
|
2252
|
-
* Selects a part of a switcher with a mark in a toolbar too narrow for the name. A switcher
|
|
2253
|
-
* without a mark keeps its name, because the name is the only content that identifies it.
|
|
2254
|
-
*/
|
|
2255
|
-
const NARROW = ".switcher__root[data-narrow]:has(.switcher__mark) &";
|
|
2256
|
-
/**
|
|
2257
|
-
* Custom property the size axis sets to the height of a button at the switcher's size.
|
|
2258
|
-
*/
|
|
2259
|
-
const HEIGHT = "--switcher-height";
|
|
2260
|
-
/**
|
|
2261
|
-
* Styles a control that is one line as wide as its words: in a toolbar and on its own.
|
|
2262
|
-
*
|
|
2263
|
-
* @remarks
|
|
2264
|
-
* `inlineSize: fit` keeps the control as wide as its words, because a flex container fills its
|
|
2265
|
-
* line otherwise. The detail is hidden, because the control is one line tall. The control is at
|
|
2266
|
-
* least as tall as a button of its size, so it lines up with the buttons in a toolbar: 36px at
|
|
2267
|
-
* `sm` and 40px at `md`.
|
|
2268
|
-
*/
|
|
2269
|
-
const INLINE = {
|
|
2270
|
-
detail: { display: "none" },
|
|
2271
|
-
root: {
|
|
2272
|
-
inlineSize: "fit",
|
|
2273
|
-
minBlockSize: `var(${HEIGHT})`
|
|
2274
|
-
}
|
|
2275
|
-
};
|
|
2276
|
-
/**
|
|
2277
|
-
* Styles the control in a sidebar: a row as wide as the column, and the mark alone on a rail.
|
|
2278
|
-
*
|
|
2279
|
-
* @remarks
|
|
2280
|
-
* On a rail the control has no padding and no edge, so it is the mark's square, as tall as the
|
|
2281
|
-
* rows under it: 32px at `md`.
|
|
2282
|
-
*/
|
|
2283
|
-
const ROW = { root: {
|
|
2284
|
-
"&[data-iconic]": {
|
|
2285
|
-
alignSelf: "center",
|
|
2286
|
-
aspectRatio: "square",
|
|
2287
|
-
borderWidth: "0",
|
|
2288
|
-
inlineSize: "auto",
|
|
2289
|
-
justifyContent: "center",
|
|
2290
|
-
padding: "0"
|
|
2291
|
-
},
|
|
2292
|
-
inlineSize: "full"
|
|
2293
|
-
} };
|
|
2294
|
-
/**
|
|
2295
|
-
* Styles a ghost switcher at the middle size, alone.
|
|
2296
|
-
*/
|
|
2297
|
-
const recipe$1 = defineSlotRecipe({
|
|
2298
|
-
base: {
|
|
2299
|
-
detail: {
|
|
2300
|
-
...truncate(),
|
|
2301
|
-
color: "fg.subtle",
|
|
2302
|
-
textStyle: "caption"
|
|
2303
|
-
},
|
|
2304
|
-
indicator: {
|
|
2305
|
-
_open: { rotate: "0deg" },
|
|
2306
|
-
alignItems: "center",
|
|
2307
|
-
color: "fg.subtle",
|
|
2308
|
-
display: "inline-flex",
|
|
2309
|
-
flexShrink: "0",
|
|
2310
|
-
[ICONIC]: { display: "none" },
|
|
2311
|
-
justifyContent: "center",
|
|
2312
|
-
marginInlineStart: "auto",
|
|
2313
|
-
transitionDuration: "press",
|
|
2314
|
-
transitionProperty: "common",
|
|
2315
|
-
transitionTimingFunction: "press"
|
|
2316
|
-
},
|
|
2317
|
-
label: {
|
|
2318
|
-
display: "flex",
|
|
2319
|
-
flex: "1",
|
|
2320
|
-
flexDirection: "column",
|
|
2321
|
-
[ICONIC]: { srOnly: true },
|
|
2322
|
-
minInlineSize: "0",
|
|
2323
|
-
[NARROW]: { srOnly: true },
|
|
2324
|
-
textAlign: "start"
|
|
2325
|
-
},
|
|
2326
|
-
mark: {
|
|
2327
|
-
alignItems: "center",
|
|
2328
|
-
background: "colorPalette.muted",
|
|
2329
|
-
borderRadius: "l1",
|
|
2330
|
-
color: "colorPalette.fg",
|
|
2331
|
-
display: "inline-flex",
|
|
2332
|
-
flexShrink: "0",
|
|
2333
|
-
fontWeight: "semibold",
|
|
2334
|
-
justifyContent: "center",
|
|
2335
|
-
lineHeight: "tight",
|
|
2336
|
-
overflow: "clip"
|
|
2337
|
-
},
|
|
2338
|
-
name: {
|
|
2339
|
-
...truncate(),
|
|
2340
|
-
fontWeight: "medium"
|
|
2341
|
-
},
|
|
2342
|
-
root: {
|
|
2343
|
-
...interactive(),
|
|
2344
|
-
alignItems: "center",
|
|
2345
|
-
appearance: "none",
|
|
2346
|
-
borderColor: "transparent",
|
|
2347
|
-
borderWidth: "control",
|
|
2348
|
-
colorPalette: "neutral",
|
|
2349
|
-
display: "flex",
|
|
2350
|
-
minInlineSize: "0"
|
|
2351
|
-
}
|
|
2352
|
-
},
|
|
2353
|
-
className: "switcher",
|
|
2354
|
-
compoundVariants: [{
|
|
2355
|
-
css: { mark: {
|
|
2356
|
-
boxSize: dense("{sizes.icon.lg}"),
|
|
2357
|
-
fontSize: "xs"
|
|
2358
|
-
} },
|
|
2359
|
-
name: "marked",
|
|
2360
|
-
placement: ["alone", "toolbar"]
|
|
2361
|
-
}, (
|
|
2362
|
-
/**
|
|
2363
|
-
* Sets the detail and the indicator in the trigger's own ink on the solid look, where the
|
|
2364
|
-
* page's subtle ink is not read against the fill.
|
|
2365
|
-
*/
|
|
2366
|
-
{
|
|
2367
|
-
css: {
|
|
2368
|
-
detail: { color: "inherit" },
|
|
2369
|
-
indicator: { color: "inherit" }
|
|
2370
|
-
},
|
|
2371
|
-
name: "inked",
|
|
2372
|
-
variant: "solid"
|
|
2373
|
-
})],
|
|
2374
|
-
defaultVariants: {
|
|
2375
|
-
placement: "alone",
|
|
2376
|
-
size: "md",
|
|
2377
|
-
variant: "ghost"
|
|
2378
|
-
},
|
|
2379
|
-
jsx: [/^Switcher(\.\w+)?$/u],
|
|
2380
|
-
slots: [
|
|
2381
|
-
"root",
|
|
2382
|
-
"mark",
|
|
2383
|
-
"label",
|
|
2384
|
-
"name",
|
|
2385
|
-
"detail",
|
|
2386
|
-
"indicator"
|
|
2387
|
-
],
|
|
2388
|
-
variants: {
|
|
2389
|
-
/**
|
|
2390
|
-
* The palette of the look and the mark.
|
|
2391
|
-
*/
|
|
2392
|
-
palette: onSlot("root", paletteVariants()),
|
|
2393
|
-
/**
|
|
2394
|
-
* Where the control is placed, which sets its width and its lines.
|
|
2395
|
-
*
|
|
2396
|
-
* @remarks
|
|
2397
|
-
* `Switcher.Root` reads the placement from the sidebar or the toolbar around it unless a
|
|
2398
|
-
* caller states one. The `marked` compound sizes the mark to `icon.lg` on one line, because
|
|
2399
|
-
* the size axis sizes it for a sidebar and a compound applies over an axis.
|
|
2400
|
-
*/
|
|
2401
|
-
placement: {
|
|
2402
|
-
alone: INLINE,
|
|
2403
|
-
sidebar: ROW,
|
|
2404
|
-
toolbar: INLINE
|
|
2405
|
-
},
|
|
2406
|
-
size: onSlots({
|
|
2407
|
-
indicator: sizeVariants((size) => ({ boxSize: dense(`{sizes.icon.${below(size)}}`) }), [
|
|
2408
|
-
"sm",
|
|
2409
|
-
"md",
|
|
2410
|
-
"lg"
|
|
2411
|
-
]),
|
|
2412
|
-
mark: sizeVariants((size) => ({
|
|
2413
|
-
boxSize: dense(`{sizes.control.${below(below(size))}}`),
|
|
2414
|
-
fontSize: below(size)
|
|
2415
|
-
}), [
|
|
2416
|
-
"sm",
|
|
2417
|
-
"md",
|
|
2418
|
-
"lg"
|
|
2419
|
-
]),
|
|
2420
|
-
name: sizeVariants((size) => ({ textStyle: `body.${below(size)}` }), [
|
|
2421
|
-
"sm",
|
|
2422
|
-
"md",
|
|
2423
|
-
"lg"
|
|
2424
|
-
]),
|
|
2425
|
-
root: sizeVariants((size) => ({
|
|
2426
|
-
borderRadius: "l2",
|
|
2427
|
-
gap: dense(`{spacing.gap.${size}}`),
|
|
2428
|
-
[HEIGHT]: dense(`{sizes.control.${size}}`),
|
|
2429
|
-
paddingBlock: dense(`{spacing.gap.${below(size)}}`),
|
|
2430
|
-
paddingInline: dense(`{spacing.gap.${size}}`),
|
|
2431
|
-
textStyle: `body.${below(size)}`
|
|
2432
|
-
}), [
|
|
2433
|
-
"sm",
|
|
2434
|
-
"md",
|
|
2435
|
-
"lg"
|
|
2436
|
-
])
|
|
2437
|
-
}),
|
|
2438
|
-
/**
|
|
2439
|
-
* The button's six looks, each one of the theme's layer styles.
|
|
2440
|
-
*
|
|
2441
|
-
* @remarks
|
|
2442
|
-
* `ghost`, the default, has no fill at rest, so a switcher at the head of a sidebar shows the
|
|
2443
|
-
* sidebar's own ground and fills under a pointer.
|
|
2444
|
-
*/
|
|
2445
|
-
variant: onSlot("root", lookVariants())
|
|
2446
|
-
}
|
|
2447
|
-
});
|
|
2448
|
-
//#endregion
|
|
2449
2450
|
//#region src/toolbar/recipe.ts
|
|
2450
2451
|
/**
|
|
2451
2452
|
* Recipe for a toolbar: a row of controls with a start, a centre and an end band, and a search.
|
|
@@ -2460,9 +2461,11 @@ const recipe$1 = defineSlotRecipe({
|
|
|
2460
2461
|
* percentage width gives a band no content width, so the search states an inline size. An opened
|
|
2461
2462
|
* search covers the whole row, the padding and the edge of an outline or surface row included,
|
|
2462
2463
|
* and the root hides its other children while it is open, so the row needs no fill of its own on
|
|
2463
|
-
* any surface. The
|
|
2464
|
-
*
|
|
2465
|
-
* row
|
|
2464
|
+
* any surface. The title is semibold and leaves twice the gap after it, so the control after it
|
|
2465
|
+
* reads as the first of the row's controls and not as part of the title. A narrow row folds
|
|
2466
|
+
* those controls, and its title leaves the row's gap alone. The recipe has no
|
|
2467
|
+
* `palette` axis, because the controls in the row set their own palettes, and no `effect` axis,
|
|
2468
|
+
* because the row is not a control.
|
|
2466
2469
|
*/
|
|
2467
2470
|
/**
|
|
2468
2471
|
* Custom property the root sets to the gap between controls, which every band reads.
|
|
@@ -2548,6 +2551,13 @@ const recipe = defineSlotRecipe({
|
|
|
2548
2551
|
start: {
|
|
2549
2552
|
...BAND,
|
|
2550
2553
|
flexShrink: "0"
|
|
2554
|
+
},
|
|
2555
|
+
title: {
|
|
2556
|
+
...BAND,
|
|
2557
|
+
[`&[${NARROW$1}]`]: { marginInlineEnd: "0" },
|
|
2558
|
+
flexShrink: "0",
|
|
2559
|
+
fontWeight: "semibold",
|
|
2560
|
+
marginInlineEnd: `calc(var(${GAP}) * 2)`
|
|
2551
2561
|
}
|
|
2552
2562
|
},
|
|
2553
2563
|
className: CLASS,
|
|
@@ -2565,7 +2575,8 @@ const recipe = defineSlotRecipe({
|
|
|
2565
2575
|
"action",
|
|
2566
2576
|
"group",
|
|
2567
2577
|
"separator",
|
|
2568
|
-
"search"
|
|
2578
|
+
"search",
|
|
2579
|
+
"title"
|
|
2569
2580
|
],
|
|
2570
2581
|
variants: {
|
|
2571
2582
|
/**
|
|
@@ -2609,4 +2620,4 @@ const recipe = defineSlotRecipe({
|
|
|
2609
2620
|
}
|
|
2610
2621
|
});
|
|
2611
2622
|
//#endregion
|
|
2612
|
-
export { STICKY_OFFSET$1 as _,
|
|
2623
|
+
export { lengthOf as C, keyedWidth as S, STICKY_OFFSET$1 as _, SCROLLPORT as a, clamped as b, STICKY_TOP as c, recipe$6 as d, PANEL_RAIL as f, SETTLED as g, PANE_TOP as h, recipe$3 as i, recipe$4 as l, PANEL_TOP as m, recipe$1 as n, SIDEBAR_SIZE as o, PANEL_SIZE as p, recipe$2 as r, STICKY_OFFSET as s, recipe as t, recipe$5 as u, WINDOW_HEIGHT as v, recipe$7 as w, growthOf as x, RESIZING as y };
|