@stealthscale/component-screen 0.0.1 → 0.2.2
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-CRJrRAI8.js → recipe-BWmweBfv.js} +469 -456
- package/dist/recipe-DRMsitrw.js +283 -0
- 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,13 @@ 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. `staticCss` lists `folded`, because the root sets it from its measured width, so an
|
|
1075
|
+
* application's stylesheet compiler does not read the value.
|
|
912
1076
|
*/
|
|
913
1077
|
/**
|
|
914
1078
|
* Custom property the root sets to the room at the page's inline edges.
|
|
@@ -949,10 +1113,15 @@ const STICKY_OFFSET = "--page-sticky-offset";
|
|
|
949
1113
|
*/
|
|
950
1114
|
const STICKY_TOP = "--page-sticky-top";
|
|
951
1115
|
/**
|
|
952
|
-
* Custom property a sticky aside takes, set to the height of the area that scrolls the
|
|
1116
|
+
* Custom property a sticky aside or sidebar takes, set to the height of the area that scrolls the
|
|
1117
|
+
* page.
|
|
953
1118
|
*/
|
|
954
1119
|
const SCROLLPORT = "--page-scrollport";
|
|
955
1120
|
/**
|
|
1121
|
+
* Custom property the sidebar sets to the width a person resized it to.
|
|
1122
|
+
*/
|
|
1123
|
+
const SIDEBAR_SIZE = "--page-sidebar-size";
|
|
1124
|
+
/**
|
|
956
1125
|
* Room a focus ring takes outside an element: its offset and its width.
|
|
957
1126
|
*/
|
|
958
1127
|
const RING_ROOM = "calc(var(--focus-ring-offset, 0px) + var(--focus-ring-width, 0px))";
|
|
@@ -973,23 +1142,41 @@ const STUCK = {
|
|
|
973
1142
|
zIndex: "sticky"
|
|
974
1143
|
};
|
|
975
1144
|
/**
|
|
1145
|
+
* Styles a column that sticks to the top of its row, under the shell's sticky bars and the page's
|
|
1146
|
+
* sticky bands, a gap below them.
|
|
1147
|
+
*/
|
|
1148
|
+
const STICKY_COLUMN = {
|
|
1149
|
+
alignSelf: "start",
|
|
1150
|
+
insetBlockStart: `calc(var(${SHELL_TOP}, 0px) + var(${STICKY_TOP}, 0px) + {spacing.gap.xl})`,
|
|
1151
|
+
position: "sticky"
|
|
1152
|
+
};
|
|
1153
|
+
/**
|
|
1154
|
+
* Caps a sticky column at the height of the area that scrolls the page, less the sticky bars and
|
|
1155
|
+
* bands above it and a gap at each end, as a flex column that its scroll area fills.
|
|
1156
|
+
*/
|
|
1157
|
+
const CAPPED_COLUMN = {
|
|
1158
|
+
display: "flex",
|
|
1159
|
+
flexDirection: "column",
|
|
1160
|
+
maxBlockSize: `calc(var(${SCROLLPORT}, 100dvh) - var(${SHELL_TOP}, 0px) - var(${STICKY_TOP}, 0px) - {spacing.gap.xl} * 2)`
|
|
1161
|
+
};
|
|
1162
|
+
/**
|
|
976
1163
|
* Styles a row that centres its items, wraps and shrinks.
|
|
977
1164
|
*/
|
|
978
|
-
const ROW$
|
|
1165
|
+
const ROW$1 = {
|
|
979
1166
|
alignItems: "center",
|
|
980
1167
|
display: "flex",
|
|
981
1168
|
flexWrap: "wrap",
|
|
982
1169
|
minInlineSize: "0"
|
|
983
1170
|
};
|
|
984
1171
|
/**
|
|
985
|
-
* Selects a band followed by the navigation, which then has the hairline.
|
|
986
|
-
*/
|
|
987
|
-
const BEFORE_NAV = `&:has(+ .${CLASS$3}__nav)`;
|
|
988
|
-
/**
|
|
989
1172
|
* Selects a root with an aside, which lays its bands out as a grid from the `lg` breakpoint.
|
|
990
1173
|
*/
|
|
991
1174
|
const WITH_ASIDE = `&:has(> .${CLASS$3}__aside)`;
|
|
992
1175
|
/**
|
|
1176
|
+
* Selects a root with a sidebar beside its body, which lays its bands out as a grid.
|
|
1177
|
+
*/
|
|
1178
|
+
const WITH_SIDEBAR = `&:has(> .${CLASS$3}__sidebar[data-beside])`;
|
|
1179
|
+
/**
|
|
993
1180
|
* Selects a toolbar in the navigation band.
|
|
994
1181
|
*/
|
|
995
1182
|
const TOOLBAR_IN_NAV = `& > .toolbar__root`;
|
|
@@ -1004,38 +1191,47 @@ const STRIP_IN_NAV = `& .${CLASS$3}__tabs[data-orientation]`;
|
|
|
1004
1191
|
* @remarks
|
|
1005
1192
|
* The body's row takes the remaining height and every other row takes its content's height,
|
|
1006
1193
|
* 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.
|
|
1194
|
+
* between its `auto` rows. The sidebar's row holds the picker a narrow page renders in the
|
|
1195
|
+
* sidebar's place, and takes no height without one.
|
|
1008
1196
|
*/
|
|
1009
1197
|
const BESIDE = {
|
|
1010
1198
|
columnGap: dense("{spacing.gap.xl}"),
|
|
1011
1199
|
display: "grid",
|
|
1012
|
-
gridTemplateAreas: "\"banner banner\" \"header header\" \"nav nav\" \"toolbar toolbar\" \"body aside\" \"footer footer\"",
|
|
1200
|
+
gridTemplateAreas: "\"banner banner\" \"header header\" \"nav nav\" \"toolbar toolbar\" \"sidebar sidebar\" \"body aside\" \"footer footer\"",
|
|
1013
1201
|
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
1014
|
-
gridTemplateRows: "auto auto auto auto 1fr auto"
|
|
1202
|
+
gridTemplateRows: "auto auto auto auto auto 1fr auto"
|
|
1015
1203
|
};
|
|
1016
1204
|
/**
|
|
1017
|
-
*
|
|
1205
|
+
* Styles the grid of a page with a sidebar beside its body: every band across, the sidebar at the
|
|
1206
|
+
* start, and an aside under the body.
|
|
1018
1207
|
*/
|
|
1019
|
-
const
|
|
1020
|
-
"
|
|
1021
|
-
"
|
|
1022
|
-
"
|
|
1023
|
-
|
|
1208
|
+
const SIDEBAR_BESIDE = {
|
|
1209
|
+
columnGap: dense("{spacing.gap.xl}"),
|
|
1210
|
+
display: "grid",
|
|
1211
|
+
gridTemplateAreas: "\"banner banner\" \"header header\" \"nav nav\" \"toolbar toolbar\" \"sidebar body\" \"sidebar aside\" \"footer footer\"",
|
|
1212
|
+
gridTemplateColumns: "auto minmax(0, 1fr)",
|
|
1213
|
+
gridTemplateRows: "auto auto auto auto 1fr auto auto"
|
|
1214
|
+
};
|
|
1024
1215
|
/**
|
|
1025
|
-
*
|
|
1216
|
+
* Styles the grid of a page with a sidebar beside its body and an aside beside it from the `lg`
|
|
1217
|
+
* breakpoint: the sidebar, the body and the aside in one row.
|
|
1026
1218
|
*/
|
|
1027
|
-
const
|
|
1219
|
+
const SIDEBAR_AND_ASIDE = {
|
|
1220
|
+
gridTemplateAreas: "\"banner banner banner\" \"header header header\" \"nav nav nav\" \"toolbar toolbar toolbar\" \"sidebar body aside\" \"footer footer footer\"",
|
|
1221
|
+
gridTemplateColumns: "auto minmax(0, 1fr) auto",
|
|
1222
|
+
gridTemplateRows: "auto auto auto auto 1fr auto"
|
|
1223
|
+
};
|
|
1028
1224
|
/**
|
|
1029
1225
|
* Defines the page recipe: a full-width page at size `md` by default.
|
|
1030
1226
|
*/
|
|
1031
|
-
const recipe$
|
|
1227
|
+
const recipe$4 = defineSlotRecipe({
|
|
1032
1228
|
base: {
|
|
1033
1229
|
action: {
|
|
1034
1230
|
...FOLDING,
|
|
1035
1231
|
flexShrink: "0"
|
|
1036
1232
|
},
|
|
1037
1233
|
actions: {
|
|
1038
|
-
...ROW$
|
|
1234
|
+
...ROW$1,
|
|
1039
1235
|
flexWrap: "nowrap",
|
|
1040
1236
|
gridArea: "actions",
|
|
1041
1237
|
justifySelf: "end",
|
|
@@ -1052,14 +1248,8 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1052
1248
|
aside: {
|
|
1053
1249
|
"&[data-folds=hide]": { lgDown: { display: "none" } },
|
|
1054
1250
|
"&[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"
|
|
1251
|
+
...STICKY_COLUMN,
|
|
1252
|
+
lg: CAPPED_COLUMN
|
|
1063
1253
|
},
|
|
1064
1254
|
gridArea: "aside",
|
|
1065
1255
|
lg: { paddingInlineStart: "0" },
|
|
@@ -1089,7 +1279,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1089
1279
|
minBlockSize: "0"
|
|
1090
1280
|
},
|
|
1091
1281
|
context: {
|
|
1092
|
-
...ROW$
|
|
1282
|
+
...ROW$1,
|
|
1093
1283
|
gridArea: "context",
|
|
1094
1284
|
minInlineSize: "0"
|
|
1095
1285
|
},
|
|
@@ -1107,7 +1297,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1107
1297
|
*/
|
|
1108
1298
|
footer: {
|
|
1109
1299
|
...BAND$1,
|
|
1110
|
-
...ROW$
|
|
1300
|
+
...ROW$1,
|
|
1111
1301
|
"&[data-sticky]": {
|
|
1112
1302
|
...STUCK,
|
|
1113
1303
|
insetBlockEnd: "0",
|
|
@@ -1139,7 +1329,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1139
1329
|
marginInlineEnd: dense("{spacing.gap.lg}")
|
|
1140
1330
|
},
|
|
1141
1331
|
meta: {
|
|
1142
|
-
...ROW$
|
|
1332
|
+
...ROW$1,
|
|
1143
1333
|
gridArea: "meta"
|
|
1144
1334
|
},
|
|
1145
1335
|
nav: {
|
|
@@ -1172,14 +1362,64 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1172
1362
|
minInlineSize: "0"
|
|
1173
1363
|
},
|
|
1174
1364
|
root: {
|
|
1365
|
+
[`&[${RESIZING}]`]: {
|
|
1366
|
+
cursor: "resizeColumn",
|
|
1367
|
+
userSelect: "none"
|
|
1368
|
+
},
|
|
1175
1369
|
display: "flex",
|
|
1176
1370
|
flexDirection: "column",
|
|
1177
1371
|
flexGrow: "1",
|
|
1178
1372
|
inlineSize: "100%",
|
|
1179
1373
|
minBlockSize: "100%",
|
|
1180
1374
|
minInlineSize: "0",
|
|
1181
|
-
[WITH_ASIDE]: { lg: BESIDE }
|
|
1375
|
+
[WITH_ASIDE]: { lg: BESIDE },
|
|
1376
|
+
[WITH_SIDEBAR]: {
|
|
1377
|
+
...SIDEBAR_BESIDE,
|
|
1378
|
+
[WITH_ASIDE]: { lg: SIDEBAR_AND_ASIDE }
|
|
1379
|
+
}
|
|
1380
|
+
},
|
|
1381
|
+
/**
|
|
1382
|
+
* The sidebar: a column beside the body on a page as wide as the `md` breakpoint, and a band
|
|
1383
|
+
* with the picker on a narrower page.
|
|
1384
|
+
*
|
|
1385
|
+
* @remarks
|
|
1386
|
+
* Beside the body the column starts at the gutter, so the fills of its rows start where the
|
|
1387
|
+
* title starts. The column is as wide as the theme's sidebar unless a person resized it. A
|
|
1388
|
+
* sticky sidebar keeps to the top of its row and is at most as tall as the room under the
|
|
1389
|
+
* sticky bands, as a sticky aside is. The handle is centred on the column's end edge, in the
|
|
1390
|
+
* gap before the body.
|
|
1391
|
+
*/
|
|
1392
|
+
sidebar: {
|
|
1393
|
+
...BAND$1,
|
|
1394
|
+
"&[data-beside]": {
|
|
1395
|
+
"&[data-sticky]": {
|
|
1396
|
+
...STICKY_COLUMN,
|
|
1397
|
+
...CAPPED_COLUMN
|
|
1398
|
+
},
|
|
1399
|
+
inlineSize: `var(${SIDEBAR_SIZE}, {sizes.sidebar})`,
|
|
1400
|
+
paddingInlineEnd: "0",
|
|
1401
|
+
position: "relative"
|
|
1402
|
+
},
|
|
1403
|
+
gridArea: "sidebar"
|
|
1404
|
+
},
|
|
1405
|
+
/**
|
|
1406
|
+
* The padding of a sticky sidebar's scroll area, the room a focus ring takes at its edges.
|
|
1407
|
+
*/
|
|
1408
|
+
sidebarContent: { padding: RING_ROOM },
|
|
1409
|
+
/**
|
|
1410
|
+
* The strip on a resizable sidebar's end edge, centred on the edge.
|
|
1411
|
+
*/
|
|
1412
|
+
sidebarHandle: {
|
|
1413
|
+
...STRIP$3,
|
|
1414
|
+
insetBlock: "0",
|
|
1415
|
+
insetInlineEnd: "calc({sizes.6} / -2)",
|
|
1416
|
+
position: "absolute"
|
|
1182
1417
|
},
|
|
1418
|
+
/**
|
|
1419
|
+
* A sticky sidebar's scroll area, pulled out on every side by the room its content's padding
|
|
1420
|
+
* takes, so the content keeps its place.
|
|
1421
|
+
*/
|
|
1422
|
+
sidebarScroller: { margin: `calc(${RING_ROOM} * -1)` },
|
|
1183
1423
|
title: {
|
|
1184
1424
|
gridArea: "title",
|
|
1185
1425
|
minInlineSize: "0",
|
|
@@ -1187,7 +1427,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1187
1427
|
},
|
|
1188
1428
|
toolbar: {
|
|
1189
1429
|
...BAND$1,
|
|
1190
|
-
...ROW$
|
|
1430
|
+
...ROW$1,
|
|
1191
1431
|
"&[data-sticky]": STUCK,
|
|
1192
1432
|
gridArea: "toolbar"
|
|
1193
1433
|
},
|
|
@@ -1250,6 +1490,10 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1250
1490
|
"picker",
|
|
1251
1491
|
"palette",
|
|
1252
1492
|
"toolbar",
|
|
1493
|
+
"sidebar",
|
|
1494
|
+
"sidebarScroller",
|
|
1495
|
+
"sidebarContent",
|
|
1496
|
+
"sidebarHandle",
|
|
1253
1497
|
"body",
|
|
1254
1498
|
"aside",
|
|
1255
1499
|
"asideScroller",
|
|
@@ -1257,6 +1501,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1257
1501
|
"footer",
|
|
1258
1502
|
"trail"
|
|
1259
1503
|
],
|
|
1504
|
+
staticCss: [{ folded: ["true"] }],
|
|
1260
1505
|
variants: {
|
|
1261
1506
|
/**
|
|
1262
1507
|
* Position of the content when the measure is narrower than the page.
|
|
@@ -1333,49 +1578,7 @@ const recipe$5 = defineSlotRecipe({
|
|
|
1333
1578
|
* The page offers three sizes, because larger steps belong to a display heading. A section in
|
|
1334
1579
|
* the page reads this size too.
|
|
1335
1580
|
*/
|
|
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
|
-
})
|
|
1581
|
+
size: SIZES
|
|
1379
1582
|
}
|
|
1380
1583
|
});
|
|
1381
1584
|
//#endregion
|
|
@@ -1413,7 +1616,7 @@ const AFTER = `.${CLASS$2}__root + &`;
|
|
|
1413
1616
|
/**
|
|
1414
1617
|
* Selects a band of a narrow section.
|
|
1415
1618
|
*/
|
|
1416
|
-
const NARROW
|
|
1619
|
+
const NARROW = `.${CLASS$2}__root[data-narrow] > &`;
|
|
1417
1620
|
/**
|
|
1418
1621
|
* Selects the actions of a narrow section.
|
|
1419
1622
|
*/
|
|
@@ -1457,7 +1660,7 @@ const SPACED = {
|
|
|
1457
1660
|
/**
|
|
1458
1661
|
* Styles a row that centres its items, wraps and shrinks.
|
|
1459
1662
|
*/
|
|
1460
|
-
const ROW
|
|
1663
|
+
const ROW = {
|
|
1461
1664
|
alignItems: "center",
|
|
1462
1665
|
display: "flex",
|
|
1463
1666
|
flexWrap: "wrap",
|
|
@@ -1466,14 +1669,14 @@ const ROW$1 = {
|
|
|
1466
1669
|
/**
|
|
1467
1670
|
* Defines the section recipe: a plain section at size `md` by default.
|
|
1468
1671
|
*/
|
|
1469
|
-
const recipe$
|
|
1672
|
+
const recipe$3 = defineSlotRecipe({
|
|
1470
1673
|
base: {
|
|
1471
1674
|
action: {
|
|
1472
1675
|
...FOLDING,
|
|
1473
1676
|
flexShrink: "0"
|
|
1474
1677
|
},
|
|
1475
1678
|
actions: {
|
|
1476
|
-
...ROW
|
|
1679
|
+
...ROW,
|
|
1477
1680
|
flexWrap: "nowrap",
|
|
1478
1681
|
gridArea: "actions",
|
|
1479
1682
|
justifySelf: "end",
|
|
@@ -1488,7 +1691,7 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1488
1691
|
minInlineSize: "0"
|
|
1489
1692
|
},
|
|
1490
1693
|
footer: {
|
|
1491
|
-
...ROW
|
|
1694
|
+
...ROW,
|
|
1492
1695
|
"& > :last-child:not(:first-child)": { marginInlineStart: "auto" },
|
|
1493
1696
|
justifyContent: "space-between"
|
|
1494
1697
|
},
|
|
@@ -1599,7 +1802,7 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1599
1802
|
}
|
|
1600
1803
|
},
|
|
1601
1804
|
header: {
|
|
1602
|
-
[NARROW
|
|
1805
|
+
[NARROW]: { marginBlockEnd: `var(${BANDS})` },
|
|
1603
1806
|
padding: "0"
|
|
1604
1807
|
},
|
|
1605
1808
|
root: {
|
|
@@ -1644,8 +1847,8 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1644
1847
|
"lg"
|
|
1645
1848
|
]),
|
|
1646
1849
|
description: sizeVariants((size) => ({
|
|
1647
|
-
|
|
1648
|
-
|
|
1850
|
+
textStyle: `body.${below(size)}`,
|
|
1851
|
+
marginBlockStart: size === "lg" ? "{spacing.1}" : "{spacing.0.5}"
|
|
1649
1852
|
}), [
|
|
1650
1853
|
"sm",
|
|
1651
1854
|
"md",
|
|
@@ -1722,7 +1925,7 @@ const recipe$4 = defineSlotRecipe({
|
|
|
1722
1925
|
/**
|
|
1723
1926
|
* Selects a part inside a sidebar collapsed to a rail.
|
|
1724
1927
|
*/
|
|
1725
|
-
const ICONIC
|
|
1928
|
+
const ICONIC = "[data-iconic] &";
|
|
1726
1929
|
/**
|
|
1727
1930
|
* Selects the children of a band that fold to an icon by themselves: a search, a nav block, a
|
|
1728
1931
|
* navigation list and a switcher.
|
|
@@ -1750,7 +1953,7 @@ const BANDED = {
|
|
|
1750
1953
|
display: "flex",
|
|
1751
1954
|
flexDirection: "column",
|
|
1752
1955
|
flexShrink: "0",
|
|
1753
|
-
[ICONIC
|
|
1956
|
+
[ICONIC]: {
|
|
1754
1957
|
alignItems: "center",
|
|
1755
1958
|
[WORDS]: { srOnly: true }
|
|
1756
1959
|
},
|
|
@@ -1810,16 +2013,21 @@ function squared(size) {
|
|
|
1810
2013
|
*/
|
|
1811
2014
|
function banded(size) {
|
|
1812
2015
|
return {
|
|
2016
|
+
textStyle: `label.${below(size)}`,
|
|
1813
2017
|
gap: dense(`{spacing.gap.${below(size)}}`),
|
|
1814
2018
|
[LINES]: { marginInline: marked(size) },
|
|
1815
|
-
padding: dense(`{spacing.gap.${size}}`)
|
|
1816
|
-
textStyle: `label.${below(size)}`
|
|
2019
|
+
padding: dense(`{spacing.gap.${size}}`)
|
|
1817
2020
|
};
|
|
1818
2021
|
}
|
|
1819
2022
|
/**
|
|
1820
2023
|
* Styles a plain sidebar at the middle size.
|
|
2024
|
+
*
|
|
2025
|
+
* @remarks
|
|
2026
|
+
* `staticCss` lists every size and every look. A sidebar in a panel over the page renders at `lg`
|
|
2027
|
+
* whatever its `size`, a product's frame states the size and the look as data, and the compiler
|
|
2028
|
+
* emits a variant only where a source states it as a literal.
|
|
1821
2029
|
*/
|
|
1822
|
-
const recipe$
|
|
2030
|
+
const recipe$2 = defineSlotRecipe({
|
|
1823
2031
|
base: {
|
|
1824
2032
|
content: {
|
|
1825
2033
|
display: "flex",
|
|
@@ -1827,7 +2035,7 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1827
2035
|
},
|
|
1828
2036
|
empty: {
|
|
1829
2037
|
color: "fg.muted",
|
|
1830
|
-
[ICONIC
|
|
2038
|
+
[ICONIC]: { display: "none" },
|
|
1831
2039
|
textAlign: "center"
|
|
1832
2040
|
},
|
|
1833
2041
|
footer: BANDED,
|
|
@@ -1855,7 +2063,7 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1855
2063
|
display: "flex",
|
|
1856
2064
|
flexShrink: "0",
|
|
1857
2065
|
gridColumn: "2 / 3",
|
|
1858
|
-
[ICONIC
|
|
2066
|
+
[ICONIC]: { display: "none" },
|
|
1859
2067
|
justifyContent: "center",
|
|
1860
2068
|
padding: "0"
|
|
1861
2069
|
},
|
|
@@ -1866,18 +2074,18 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1866
2074
|
display: "flex",
|
|
1867
2075
|
fontWeight: "medium",
|
|
1868
2076
|
gridColumn: "1 / 2",
|
|
1869
|
-
[ICONIC
|
|
2077
|
+
[ICONIC]: { srOnly: true },
|
|
1870
2078
|
textTransform: "uppercase"
|
|
1871
2079
|
},
|
|
1872
2080
|
navLabel: {
|
|
1873
2081
|
...truncate(),
|
|
2082
|
+
textStyle: "label.xs",
|
|
1874
2083
|
alignItems: "center",
|
|
1875
2084
|
color: "fg.subtle",
|
|
1876
2085
|
display: "flex",
|
|
1877
2086
|
fontWeight: "medium",
|
|
1878
2087
|
gridColumn: "1 / 2",
|
|
1879
|
-
[ICONIC
|
|
1880
|
-
textStyle: "label.xs",
|
|
2088
|
+
[ICONIC]: { srOnly: true },
|
|
1881
2089
|
textTransform: "uppercase"
|
|
1882
2090
|
},
|
|
1883
2091
|
root: {
|
|
@@ -1892,7 +2100,7 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1892
2100
|
minBlockSize: "0"
|
|
1893
2101
|
},
|
|
1894
2102
|
search: {
|
|
1895
|
-
[ICONIC
|
|
2103
|
+
[ICONIC]: {
|
|
1896
2104
|
display: "flex",
|
|
1897
2105
|
justifyContent: "center"
|
|
1898
2106
|
},
|
|
@@ -1921,6 +2129,19 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1921
2129
|
"empty",
|
|
1922
2130
|
"separator"
|
|
1923
2131
|
],
|
|
2132
|
+
staticCss: [{
|
|
2133
|
+
size: [
|
|
2134
|
+
"sm",
|
|
2135
|
+
"md",
|
|
2136
|
+
"lg"
|
|
2137
|
+
],
|
|
2138
|
+
variant: [
|
|
2139
|
+
"outline",
|
|
2140
|
+
"plain",
|
|
2141
|
+
"subtle",
|
|
2142
|
+
"surface"
|
|
2143
|
+
]
|
|
2144
|
+
}],
|
|
1924
2145
|
variants: {
|
|
1925
2146
|
size: onSlots({
|
|
1926
2147
|
/**
|
|
@@ -1938,8 +2159,8 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1938
2159
|
"lg"
|
|
1939
2160
|
]),
|
|
1940
2161
|
empty: sizeVariants((size) => ({
|
|
1941
|
-
|
|
1942
|
-
|
|
2162
|
+
textStyle: `body.${size}`,
|
|
2163
|
+
padding: dense(`{spacing.inset.${size}}`)
|
|
1943
2164
|
}), [
|
|
1944
2165
|
"sm",
|
|
1945
2166
|
"md",
|
|
@@ -1978,10 +2199,10 @@ const recipe$3 = defineSlotRecipe({
|
|
|
1978
2199
|
"lg"
|
|
1979
2200
|
]),
|
|
1980
2201
|
navHeading: sizeVariants((size) => ({
|
|
2202
|
+
textStyle: "label.xs",
|
|
1981
2203
|
marginBlockEnd: `calc(${dense(`{spacing.gap.${size}}`)} * -0.5)`,
|
|
1982
2204
|
paddingBlock: dense("{spacing.gap.xs}"),
|
|
1983
|
-
paddingInline: marked(size)
|
|
1984
|
-
textStyle: "label.xs"
|
|
2205
|
+
paddingInline: marked(size)
|
|
1985
2206
|
}), [
|
|
1986
2207
|
"sm",
|
|
1987
2208
|
"md",
|
|
@@ -2095,7 +2316,7 @@ const PILLED = `&:has(> .${CLASS$1}__resizeTriggerIndicator)`;
|
|
|
2095
2316
|
/**
|
|
2096
2317
|
* Defines the splitter recipe, in the primary palette by default.
|
|
2097
2318
|
*/
|
|
2098
|
-
const recipe$
|
|
2319
|
+
const recipe$1 = defineSlotRecipe({
|
|
2099
2320
|
base: {
|
|
2100
2321
|
panel: {
|
|
2101
2322
|
display: "flex",
|
|
@@ -2104,6 +2325,7 @@ const recipe$2 = defineSlotRecipe({
|
|
|
2104
2325
|
minInlineSize: "0"
|
|
2105
2326
|
},
|
|
2106
2327
|
resizeTrigger: {
|
|
2328
|
+
focusVisibleRing: "outside",
|
|
2107
2329
|
_touch: {
|
|
2108
2330
|
_before: {
|
|
2109
2331
|
content: "\"\"",
|
|
@@ -2129,7 +2351,6 @@ const recipe$2 = defineSlotRecipe({
|
|
|
2129
2351
|
marginBlock: `calc(${STRIP} * -0.5)`
|
|
2130
2352
|
},
|
|
2131
2353
|
focusRingColor: "colorPalette.focusRing",
|
|
2132
|
-
focusVisibleRing: "outside",
|
|
2133
2354
|
justifyItems: "center",
|
|
2134
2355
|
[PILLED]: { _focusVisible: { outlineStyle: "none" } },
|
|
2135
2356
|
position: "relative",
|
|
@@ -2228,224 +2449,6 @@ const recipe$2 = defineSlotRecipe({
|
|
|
2228
2449
|
palette: onSlot("root", paletteVariants()) }
|
|
2229
2450
|
});
|
|
2230
2451
|
//#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
2452
|
//#region src/toolbar/recipe.ts
|
|
2450
2453
|
/**
|
|
2451
2454
|
* Recipe for a toolbar: a row of controls with a start, a centre and an end band, and a search.
|
|
@@ -2460,9 +2463,11 @@ const recipe$1 = defineSlotRecipe({
|
|
|
2460
2463
|
* percentage width gives a band no content width, so the search states an inline size. An opened
|
|
2461
2464
|
* search covers the whole row, the padding and the edge of an outline or surface row included,
|
|
2462
2465
|
* 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
|
|
2466
|
+
* any surface. The title is semibold and leaves twice the gap after it, so the control after it
|
|
2467
|
+
* reads as the first of the row's controls and not as part of the title. A narrow row folds
|
|
2468
|
+
* those controls, and its title leaves the row's gap alone. The recipe has no
|
|
2469
|
+
* `palette` axis, because the controls in the row set their own palettes, and no `effect` axis,
|
|
2470
|
+
* because the row is not a control.
|
|
2466
2471
|
*/
|
|
2467
2472
|
/**
|
|
2468
2473
|
* Custom property the root sets to the gap between controls, which every band reads.
|
|
@@ -2548,6 +2553,13 @@ const recipe = defineSlotRecipe({
|
|
|
2548
2553
|
start: {
|
|
2549
2554
|
...BAND,
|
|
2550
2555
|
flexShrink: "0"
|
|
2556
|
+
},
|
|
2557
|
+
title: {
|
|
2558
|
+
...BAND,
|
|
2559
|
+
[`&[${NARROW$1}]`]: { marginInlineEnd: "0" },
|
|
2560
|
+
flexShrink: "0",
|
|
2561
|
+
fontWeight: "semibold",
|
|
2562
|
+
marginInlineEnd: `calc(var(${GAP}) * 2)`
|
|
2551
2563
|
}
|
|
2552
2564
|
},
|
|
2553
2565
|
className: CLASS,
|
|
@@ -2565,7 +2577,8 @@ const recipe = defineSlotRecipe({
|
|
|
2565
2577
|
"action",
|
|
2566
2578
|
"group",
|
|
2567
2579
|
"separator",
|
|
2568
|
-
"search"
|
|
2580
|
+
"search",
|
|
2581
|
+
"title"
|
|
2569
2582
|
],
|
|
2570
2583
|
variants: {
|
|
2571
2584
|
/**
|
|
@@ -2609,4 +2622,4 @@ const recipe = defineSlotRecipe({
|
|
|
2609
2622
|
}
|
|
2610
2623
|
});
|
|
2611
2624
|
//#endregion
|
|
2612
|
-
export { STICKY_OFFSET$1 as _,
|
|
2625
|
+
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 };
|