@getvitops/generator 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +246 -0
- package/assets/bricks/elements/copy-button.php +3 -3
- package/assets/bricks/elements/multi-field.php +3 -3
- package/assets/css/animation.css +90 -0
- package/assets/css/global.css +10 -0
- package/assets/css/index.css +5 -0
- package/assets/css/layout-utilities.css +46 -0
- package/assets/css/layout.css +87 -2
- package/assets/css/patterns/anchor-link.css +36 -0
- package/assets/css/patterns/code.css +24 -0
- package/assets/css/patterns/details.css +28 -16
- package/assets/css/patterns/dialog.css +13 -31
- package/assets/css/patterns/drawer.css +27 -66
- package/assets/css/patterns/dropdown.css +15 -1
- package/assets/css/patterns/lightbox.css +3 -3
- package/assets/css/patterns/marquee.css +33 -5
- package/assets/css/patterns/nav.css +27 -79
- package/assets/css/patterns/navbar.css +86 -0
- package/assets/css/patterns/navshell.css +383 -0
- package/assets/css/patterns/popover.css +56 -8
- package/assets/css/patterns/scroll-target.css +18 -4
- package/assets/css/patterns/sitenav.css +117 -338
- package/assets/css/patterns/split-link.css +3 -3
- package/assets/js/elements.js +3 -3
- package/{site.schema.json → config.schema.json} +2320 -2240
- package/dist/index.d.mts +947 -412
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3278 -3045
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
|
@@ -156,43 +156,57 @@
|
|
|
156
156
|
grid-column: fullbleed;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
/* Every ratio publishes `--_flex-direction` alongside `flex-direction`. Only the
|
|
160
|
+
`.flex-*` utilities used to do that, so `class="split flex-col md-split-1-2"`
|
|
161
|
+
left the variable reading `column` at ALL widths — and patterns/grouped.css
|
|
162
|
+
resolves its collapsed-border axis from a `@container style(--_flex-direction:
|
|
163
|
+
column)` query, so a `.grouped` inside a re-rowed split collapsed on the wrong
|
|
164
|
+
axis with nothing to indicate why. */
|
|
159
165
|
.split-1-2 {
|
|
160
166
|
flex-direction: row;
|
|
167
|
+
--_flex-direction: row;
|
|
161
168
|
--_split-a: 1;
|
|
162
169
|
--_split-b: 2;
|
|
163
170
|
}
|
|
164
171
|
.split-2-1 {
|
|
165
172
|
flex-direction: row;
|
|
173
|
+
--_flex-direction: row;
|
|
166
174
|
--_split-a: 2;
|
|
167
175
|
--_split-b: 1;
|
|
168
176
|
}
|
|
169
177
|
.split-1-3 {
|
|
170
178
|
flex-direction: row;
|
|
179
|
+
--_flex-direction: row;
|
|
171
180
|
--_split-a: 1;
|
|
172
181
|
--_split-b: 3;
|
|
173
182
|
}
|
|
174
183
|
.split-3-1 {
|
|
175
184
|
flex-direction: row;
|
|
185
|
+
--_flex-direction: row;
|
|
176
186
|
--_split-a: 3;
|
|
177
187
|
--_split-b: 1;
|
|
178
188
|
}
|
|
179
189
|
.split-1-4 {
|
|
180
190
|
flex-direction: row;
|
|
191
|
+
--_flex-direction: row;
|
|
181
192
|
--_split-a: 1;
|
|
182
193
|
--_split-b: 4;
|
|
183
194
|
}
|
|
184
195
|
.split-4-1 {
|
|
185
196
|
flex-direction: row;
|
|
197
|
+
--_flex-direction: row;
|
|
186
198
|
--_split-a: 4;
|
|
187
199
|
--_split-b: 1;
|
|
188
200
|
}
|
|
189
201
|
.split-2-3 {
|
|
190
202
|
flex-direction: row;
|
|
203
|
+
--_flex-direction: row;
|
|
191
204
|
--_split-a: 2;
|
|
192
205
|
--_split-b: 3;
|
|
193
206
|
}
|
|
194
207
|
.split-3-2 {
|
|
195
208
|
flex-direction: row;
|
|
209
|
+
--_flex-direction: row;
|
|
196
210
|
--_split-a: 3;
|
|
197
211
|
--_split-b: 2;
|
|
198
212
|
}
|
|
@@ -393,41 +407,49 @@
|
|
|
393
407
|
@container (min-width: 30rem) {
|
|
394
408
|
.sm-split-1-2 {
|
|
395
409
|
flex-direction: row;
|
|
410
|
+
--_flex-direction: row;
|
|
396
411
|
--_split-a: 1;
|
|
397
412
|
--_split-b: 2;
|
|
398
413
|
}
|
|
399
414
|
.sm-split-2-1 {
|
|
400
415
|
flex-direction: row;
|
|
416
|
+
--_flex-direction: row;
|
|
401
417
|
--_split-a: 2;
|
|
402
418
|
--_split-b: 1;
|
|
403
419
|
}
|
|
404
420
|
.sm-split-1-3 {
|
|
405
421
|
flex-direction: row;
|
|
422
|
+
--_flex-direction: row;
|
|
406
423
|
--_split-a: 1;
|
|
407
424
|
--_split-b: 3;
|
|
408
425
|
}
|
|
409
426
|
.sm-split-3-1 {
|
|
410
427
|
flex-direction: row;
|
|
428
|
+
--_flex-direction: row;
|
|
411
429
|
--_split-a: 3;
|
|
412
430
|
--_split-b: 1;
|
|
413
431
|
}
|
|
414
432
|
.sm-split-1-4 {
|
|
415
433
|
flex-direction: row;
|
|
434
|
+
--_flex-direction: row;
|
|
416
435
|
--_split-a: 1;
|
|
417
436
|
--_split-b: 4;
|
|
418
437
|
}
|
|
419
438
|
.sm-split-4-1 {
|
|
420
439
|
flex-direction: row;
|
|
440
|
+
--_flex-direction: row;
|
|
421
441
|
--_split-a: 4;
|
|
422
442
|
--_split-b: 1;
|
|
423
443
|
}
|
|
424
444
|
.sm-split-2-3 {
|
|
425
445
|
flex-direction: row;
|
|
446
|
+
--_flex-direction: row;
|
|
426
447
|
--_split-a: 2;
|
|
427
448
|
--_split-b: 3;
|
|
428
449
|
}
|
|
429
450
|
.sm-split-3-2 {
|
|
430
451
|
flex-direction: row;
|
|
452
|
+
--_flex-direction: row;
|
|
431
453
|
--_split-a: 3;
|
|
432
454
|
--_split-b: 2;
|
|
433
455
|
}
|
|
@@ -441,41 +463,49 @@
|
|
|
441
463
|
@container (min-width: 48rem) {
|
|
442
464
|
.md-split-1-2 {
|
|
443
465
|
flex-direction: row;
|
|
466
|
+
--_flex-direction: row;
|
|
444
467
|
--_split-a: 1;
|
|
445
468
|
--_split-b: 2;
|
|
446
469
|
}
|
|
447
470
|
.md-split-2-1 {
|
|
448
471
|
flex-direction: row;
|
|
472
|
+
--_flex-direction: row;
|
|
449
473
|
--_split-a: 2;
|
|
450
474
|
--_split-b: 1;
|
|
451
475
|
}
|
|
452
476
|
.md-split-1-3 {
|
|
453
477
|
flex-direction: row;
|
|
478
|
+
--_flex-direction: row;
|
|
454
479
|
--_split-a: 1;
|
|
455
480
|
--_split-b: 3;
|
|
456
481
|
}
|
|
457
482
|
.md-split-3-1 {
|
|
458
483
|
flex-direction: row;
|
|
484
|
+
--_flex-direction: row;
|
|
459
485
|
--_split-a: 3;
|
|
460
486
|
--_split-b: 1;
|
|
461
487
|
}
|
|
462
488
|
.md-split-1-4 {
|
|
463
489
|
flex-direction: row;
|
|
490
|
+
--_flex-direction: row;
|
|
464
491
|
--_split-a: 1;
|
|
465
492
|
--_split-b: 4;
|
|
466
493
|
}
|
|
467
494
|
.md-split-4-1 {
|
|
468
495
|
flex-direction: row;
|
|
496
|
+
--_flex-direction: row;
|
|
469
497
|
--_split-a: 4;
|
|
470
498
|
--_split-b: 1;
|
|
471
499
|
}
|
|
472
500
|
.md-split-2-3 {
|
|
473
501
|
flex-direction: row;
|
|
502
|
+
--_flex-direction: row;
|
|
474
503
|
--_split-a: 2;
|
|
475
504
|
--_split-b: 3;
|
|
476
505
|
}
|
|
477
506
|
.md-split-3-2 {
|
|
478
507
|
flex-direction: row;
|
|
508
|
+
--_flex-direction: row;
|
|
479
509
|
--_split-a: 3;
|
|
480
510
|
--_split-b: 2;
|
|
481
511
|
}
|
|
@@ -489,41 +519,49 @@
|
|
|
489
519
|
@container (min-width: 64rem) {
|
|
490
520
|
.lg-split-1-2 {
|
|
491
521
|
flex-direction: row;
|
|
522
|
+
--_flex-direction: row;
|
|
492
523
|
--_split-a: 1;
|
|
493
524
|
--_split-b: 2;
|
|
494
525
|
}
|
|
495
526
|
.lg-split-2-1 {
|
|
496
527
|
flex-direction: row;
|
|
528
|
+
--_flex-direction: row;
|
|
497
529
|
--_split-a: 2;
|
|
498
530
|
--_split-b: 1;
|
|
499
531
|
}
|
|
500
532
|
.lg-split-1-3 {
|
|
501
533
|
flex-direction: row;
|
|
534
|
+
--_flex-direction: row;
|
|
502
535
|
--_split-a: 1;
|
|
503
536
|
--_split-b: 3;
|
|
504
537
|
}
|
|
505
538
|
.lg-split-3-1 {
|
|
506
539
|
flex-direction: row;
|
|
540
|
+
--_flex-direction: row;
|
|
507
541
|
--_split-a: 3;
|
|
508
542
|
--_split-b: 1;
|
|
509
543
|
}
|
|
510
544
|
.lg-split-1-4 {
|
|
511
545
|
flex-direction: row;
|
|
546
|
+
--_flex-direction: row;
|
|
512
547
|
--_split-a: 1;
|
|
513
548
|
--_split-b: 4;
|
|
514
549
|
}
|
|
515
550
|
.lg-split-4-1 {
|
|
516
551
|
flex-direction: row;
|
|
552
|
+
--_flex-direction: row;
|
|
517
553
|
--_split-a: 4;
|
|
518
554
|
--_split-b: 1;
|
|
519
555
|
}
|
|
520
556
|
.lg-split-2-3 {
|
|
521
557
|
flex-direction: row;
|
|
558
|
+
--_flex-direction: row;
|
|
522
559
|
--_split-a: 2;
|
|
523
560
|
--_split-b: 3;
|
|
524
561
|
}
|
|
525
562
|
.lg-split-3-2 {
|
|
526
563
|
flex-direction: row;
|
|
564
|
+
--_flex-direction: row;
|
|
527
565
|
--_split-a: 3;
|
|
528
566
|
--_split-b: 2;
|
|
529
567
|
}
|
|
@@ -537,41 +575,49 @@
|
|
|
537
575
|
@container (min-width: 80rem) {
|
|
538
576
|
.xl-split-1-2 {
|
|
539
577
|
flex-direction: row;
|
|
578
|
+
--_flex-direction: row;
|
|
540
579
|
--_split-a: 1;
|
|
541
580
|
--_split-b: 2;
|
|
542
581
|
}
|
|
543
582
|
.xl-split-2-1 {
|
|
544
583
|
flex-direction: row;
|
|
584
|
+
--_flex-direction: row;
|
|
545
585
|
--_split-a: 2;
|
|
546
586
|
--_split-b: 1;
|
|
547
587
|
}
|
|
548
588
|
.xl-split-1-3 {
|
|
549
589
|
flex-direction: row;
|
|
590
|
+
--_flex-direction: row;
|
|
550
591
|
--_split-a: 1;
|
|
551
592
|
--_split-b: 3;
|
|
552
593
|
}
|
|
553
594
|
.xl-split-3-1 {
|
|
554
595
|
flex-direction: row;
|
|
596
|
+
--_flex-direction: row;
|
|
555
597
|
--_split-a: 3;
|
|
556
598
|
--_split-b: 1;
|
|
557
599
|
}
|
|
558
600
|
.xl-split-1-4 {
|
|
559
601
|
flex-direction: row;
|
|
602
|
+
--_flex-direction: row;
|
|
560
603
|
--_split-a: 1;
|
|
561
604
|
--_split-b: 4;
|
|
562
605
|
}
|
|
563
606
|
.xl-split-4-1 {
|
|
564
607
|
flex-direction: row;
|
|
608
|
+
--_flex-direction: row;
|
|
565
609
|
--_split-a: 4;
|
|
566
610
|
--_split-b: 1;
|
|
567
611
|
}
|
|
568
612
|
.xl-split-2-3 {
|
|
569
613
|
flex-direction: row;
|
|
614
|
+
--_flex-direction: row;
|
|
570
615
|
--_split-a: 2;
|
|
571
616
|
--_split-b: 3;
|
|
572
617
|
}
|
|
573
618
|
.xl-split-3-2 {
|
|
574
619
|
flex-direction: row;
|
|
620
|
+
--_flex-direction: row;
|
|
575
621
|
--_split-a: 3;
|
|
576
622
|
--_split-b: 2;
|
|
577
623
|
}
|
package/assets/css/layout.css
CHANGED
|
@@ -46,10 +46,82 @@
|
|
|
46
46
|
.rhythm > * + * {
|
|
47
47
|
margin-top: calc(var(--rhythm-base) * var(--rhythm-p-p));
|
|
48
48
|
}
|
|
49
|
-
|
|
49
|
+
/* The heading pairs are defined by what a heading IS, not by a list of what can
|
|
50
|
+
sit next to one.
|
|
51
|
+
These used to enumerate the other side (`p`, then `p, pre, blockquote, table,
|
|
52
|
+
dl, ul, ol`), and an enumeration is a list that is always one element short:
|
|
53
|
+
first a `<pre>` got paragraph-to-paragraph spacing before a heading, then a
|
|
54
|
+
`<div class="marquee">` did. Any block is content; only headings are special.
|
|
55
|
+
So the rules invert — `:not(<heading>) + <heading>` — and nothing has to be
|
|
56
|
+
added here again.
|
|
57
|
+
|
|
58
|
+
`:where()` keeps the whole selector at (0,1,0), the same weight as the generic
|
|
59
|
+
`* + *` above, so SOURCE ORDER is what makes these win. Keep them below it,
|
|
60
|
+
and keep the media pairs below these — `figure + h2` matches both, and the
|
|
61
|
+
media rule is meant to take it.
|
|
62
|
+
|
|
63
|
+
A heading is also a TYPE ROLE, not just a tag: this framework's own idiom is
|
|
64
|
+
`<p class="font-heading">` inside a card, which is a heading in every sense
|
|
65
|
+
that matters to rhythm.
|
|
66
|
+
|
|
67
|
+
Those three are matched with `[class~="…"]`, not `.font-heading`, and the
|
|
68
|
+
difference is not cosmetic. `LAYER_CONTRACT` asserts that a utility's class
|
|
69
|
+
name appears first in `vitops.utilities`; writing `.font-display` here — in a
|
|
70
|
+
partial that lands in `vitops.components` — reads to that guard exactly like a
|
|
71
|
+
utility defined in the wrong layer, and it fails the build. The attribute form
|
|
72
|
+
says what is true: this rule REFERENCES the class, it does not define it. */
|
|
73
|
+
.rhythm
|
|
74
|
+
> :where(
|
|
75
|
+
h1,
|
|
76
|
+
h2,
|
|
77
|
+
h3,
|
|
78
|
+
h4,
|
|
79
|
+
h5,
|
|
80
|
+
h6,
|
|
81
|
+
[class~='font-display'],
|
|
82
|
+
[class~='font-title'],
|
|
83
|
+
[class~='font-heading']
|
|
84
|
+
)
|
|
85
|
+
+ :not(
|
|
86
|
+
:where(
|
|
87
|
+
h1,
|
|
88
|
+
h2,
|
|
89
|
+
h3,
|
|
90
|
+
h4,
|
|
91
|
+
h5,
|
|
92
|
+
h6,
|
|
93
|
+
[class~='font-display'],
|
|
94
|
+
[class~='font-title'],
|
|
95
|
+
[class~='font-heading']
|
|
96
|
+
)
|
|
97
|
+
) {
|
|
50
98
|
margin-top: calc(var(--rhythm-base) * var(--rhythm-h-p));
|
|
51
99
|
}
|
|
52
|
-
.rhythm
|
|
100
|
+
.rhythm
|
|
101
|
+
> :not(
|
|
102
|
+
:where(
|
|
103
|
+
h1,
|
|
104
|
+
h2,
|
|
105
|
+
h3,
|
|
106
|
+
h4,
|
|
107
|
+
h5,
|
|
108
|
+
h6,
|
|
109
|
+
[class~='font-display'],
|
|
110
|
+
[class~='font-title'],
|
|
111
|
+
[class~='font-heading']
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
+ :where(
|
|
115
|
+
h1,
|
|
116
|
+
h2,
|
|
117
|
+
h3,
|
|
118
|
+
h4,
|
|
119
|
+
h5,
|
|
120
|
+
h6,
|
|
121
|
+
[class~='font-display'],
|
|
122
|
+
[class~='font-title'],
|
|
123
|
+
[class~='font-heading']
|
|
124
|
+
) {
|
|
53
125
|
margin-top: calc(var(--rhythm-base) * var(--rhythm-p-h));
|
|
54
126
|
}
|
|
55
127
|
.rhythm > :where(h1, h2, h3, h4, h5, h6) + :where(h1, h2, h3, h4, h5, h6) {
|
|
@@ -81,6 +153,11 @@
|
|
|
81
153
|
--width-measure: 65ch;
|
|
82
154
|
--width-breakout: 90ch;
|
|
83
155
|
--width-spotlight: 120ch;
|
|
156
|
+
/* A navigation column beside content (`navshell`). In `rem`, not `ch`, unlike
|
|
157
|
+
the three above: those are reading measures and scale with the text they
|
|
158
|
+
hold, while a nav column is chrome sized in the page's own rhythm — it
|
|
159
|
+
should not get wider because the prose font has a wide `0` glyph. */
|
|
160
|
+
--width-nav: 16rem;
|
|
84
161
|
--gutter: clamp(1rem, 4cqi, 3rem);
|
|
85
162
|
}
|
|
86
163
|
|
|
@@ -110,6 +187,14 @@ body {
|
|
|
110
187
|
|
|
111
188
|
.centered > * {
|
|
112
189
|
grid-column: measure;
|
|
190
|
+
/* A grid item's automatic minimum size is its MIN-CONTENT size, and every
|
|
191
|
+
track here is definite (`--_measure` is a min() of two lengths; the rest are
|
|
192
|
+
minmax(0, …)). So a track child holding something with a large min-content —
|
|
193
|
+
a wide <pre>, a long unbreakable token — pushes past its track and the whole
|
|
194
|
+
document scrolls sideways. This caps the container; wrapping or scrolling
|
|
195
|
+
the CONTENT (see global.css and patterns/code.css) is what stops the visual
|
|
196
|
+
overflow. */
|
|
197
|
+
min-inline-size: 0;
|
|
113
198
|
}
|
|
114
199
|
|
|
115
200
|
/* Vertical rhythm region (usually on the Section) */
|
|
@@ -64,3 +64,39 @@ a[target='_blank'].link--external::after {
|
|
|
64
64
|
mask-size: contain;
|
|
65
65
|
mask-repeat: no-repeat;
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Skip link — the first focusable thing on a page, jumping past the chrome to
|
|
70
|
+
* the main landmark. Every site needs one and every site was hand-rolling it.
|
|
71
|
+
*
|
|
72
|
+
* `clip-path` + a 1px box rather than the old `inset-inline-start: -100vw`
|
|
73
|
+
* idiom: `100vw` includes the scrollbar gutter (`global.css` sets
|
|
74
|
+
* `scrollbar-gutter: stable`), and a negatively-positioned box DOES contribute
|
|
75
|
+
* scrollable overflow in RTL, where the page then scrolls to nothing. This
|
|
76
|
+
* version has no position to get wrong in either direction.
|
|
77
|
+
*
|
|
78
|
+
* Not `.sr-only` — that name is in the generator's TW_CLASH list, so the
|
|
79
|
+
* tailwind format ships no rule for it and a consumer on that format would get a
|
|
80
|
+
* permanently visible skip link.
|
|
81
|
+
*/
|
|
82
|
+
.skip-link:not(:focus-visible) {
|
|
83
|
+
position: absolute;
|
|
84
|
+
inline-size: 1px;
|
|
85
|
+
block-size: 1px;
|
|
86
|
+
padding: 0;
|
|
87
|
+
margin: -1px;
|
|
88
|
+
overflow: hidden;
|
|
89
|
+
clip-path: inset(50%);
|
|
90
|
+
white-space: nowrap;
|
|
91
|
+
border: 0;
|
|
92
|
+
}
|
|
93
|
+
.skip-link:focus-visible {
|
|
94
|
+
position: absolute;
|
|
95
|
+
inset-inline-start: 0.5rem;
|
|
96
|
+
inset-block-start: 0.5rem;
|
|
97
|
+
z-index: var(--z-tier-top);
|
|
98
|
+
padding: 0.5rem 0.75rem;
|
|
99
|
+
background: var(--color-bg-surface);
|
|
100
|
+
color: var(--color-text-surface);
|
|
101
|
+
border-radius: var(--br-control, 0.375rem);
|
|
102
|
+
}
|
|
@@ -14,4 +14,28 @@
|
|
|
14
14
|
color: var(--color-text-neutral);
|
|
15
15
|
padding: 0.1em 0.4em;
|
|
16
16
|
border-radius: var(--br-default);
|
|
17
|
+
|
|
18
|
+
/* `anywhere`, not the `break-word` global.css gives prose: an inline code span
|
|
19
|
+
is usually ONE token with no break opportunity at all — a 61-character CSS
|
|
20
|
+
selector or a package path — so `break-word` never fires and it overflows
|
|
21
|
+
the measure. Breaking mid-token is the right trade for code in running text.
|
|
22
|
+
`anywhere` does affect min-content sizing, which is the point here: it lets
|
|
23
|
+
an intrinsically sized ancestor shrink instead of being held open. */
|
|
24
|
+
overflow-wrap: anywhere;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* ── Code blocks. The framework had NO `pre` rule, so every consumer re-derived
|
|
28
|
+
this — and a <pre> is the widest thing on a typical docs page.
|
|
29
|
+
|
|
30
|
+
Worth knowing, because it is the reverse of what the spec reads like: making a
|
|
31
|
+
<pre> a scroll container does NOT zero its min-content contribution in Chrome.
|
|
32
|
+
Measured at 390px on this repo's own docs site, a `pre` with `overflow-x: auto`
|
|
33
|
+
still reported a 797px min-content, its parent inherited 829px, and any
|
|
34
|
+
ancestor sized under `fit-content` resolved to THAT rather than the available
|
|
35
|
+
width. `max-inline-size: 100%` is what actually caps it. ── */
|
|
36
|
+
:where(pre) {
|
|
37
|
+
max-inline-size: 100%;
|
|
38
|
+
overflow-x: auto;
|
|
39
|
+
/* Don't chain a horizontal flick out to the page once the block ends. */
|
|
40
|
+
overscroll-behavior-x: contain;
|
|
17
41
|
}
|
|
@@ -38,30 +38,42 @@ details,
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* Animated collapse — `block-size: 0 → auto`, backed by the
|
|
42
|
+
* `interpolate-size: allow-keywords` in patterns/reveal.css.
|
|
42
43
|
*
|
|
43
|
-
* This
|
|
44
|
-
* `content-visibility`
|
|
45
|
-
* `
|
|
46
|
-
*
|
|
47
|
-
* so `auto` resolves to `0`, so the transition has nothing to run — and the
|
|
48
|
-
* disclosure never opens *at all*. Not "opens without animating": every
|
|
49
|
-
* `<details>` on the page becomes inert, which is a total content-loss bug.
|
|
44
|
+
* This was previously disabled with a long note saying the transition
|
|
45
|
+
* DEADLOCKS: `content-visibility` stays `hidden`, the content never gets
|
|
46
|
+
* layout, `auto` resolves to `0`, and the disclosure never opens at all —
|
|
47
|
+
* total content loss, not merely a missing animation.
|
|
50
48
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
49
|
+
* Re-verified on Chrome 149.0.7827.200 by the standard that note itself set:
|
|
50
|
+
* a real dispatched click on a bare `<details>`, not an `@supports` query.
|
|
51
|
+
* It opens, and it animates both ways — measured 25 → 41 → 133 → 196px on
|
|
52
|
+
* open and 196 → 132 → 25px on close.
|
|
55
53
|
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
54
|
+
* Keep BOTH properties in the transition list. `content-visibility` with
|
|
55
|
+
* `allow-discrete` is the load-bearing half: it is precisely what lets the
|
|
56
|
+
* content take layout during the transition, and dropping it is what
|
|
57
|
+
* reproduces the deadlock. If this ever regresses, the tell is a `<details>`
|
|
58
|
+
* that will not open on the first click — check a real interaction, because
|
|
59
|
+
* the syntax stays valid either way.
|
|
60
60
|
*/
|
|
61
61
|
&::details-content {
|
|
62
62
|
display: block;
|
|
63
63
|
overflow: hidden;
|
|
64
64
|
block-size: 0;
|
|
65
|
+
|
|
66
|
+
/* Re-added and re-verified — see the note above, which this supersedes.
|
|
67
|
+
`content-visibility` MUST be in the transition list with `allow-discrete`:
|
|
68
|
+
that is the exact thing whose absence caused the deadlock, because
|
|
69
|
+
`content-visibility: hidden` leaves the content unlaid-out and `auto`
|
|
70
|
+
resolves to 0. Behind reduced-motion, so the no-preference case keeps the
|
|
71
|
+
instant open the previous version guaranteed. */
|
|
72
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
73
|
+
transition:
|
|
74
|
+
block-size var(--animation-duration) var(--custom-ease-out),
|
|
75
|
+
content-visibility var(--animation-duration) allow-discrete;
|
|
76
|
+
}
|
|
65
77
|
}
|
|
66
78
|
|
|
67
79
|
> summary + * {
|
|
@@ -29,16 +29,20 @@ dialog.dialog {
|
|
|
29
29
|
color: var(--color-text-surface);
|
|
30
30
|
max-block-size: calc(100vh - 2rem);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
/* The scrim itself is one rule in popover.css; this only says how it should
|
|
33
|
+
look for a dialog. It also fades in/out from there, so the bespoke
|
|
34
|
+
`dialog-backdrop-enter` keyframe that used to run here is gone (it only ever
|
|
35
|
+
animated the entry). */
|
|
36
|
+
--scrim-filter: blur(4px);
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
/* The entry, as effect vars rather than a keyframe. Same three endpoints the
|
|
39
|
+
`dialog-enter` keyframe used, now run by the top-layer driver in
|
|
40
|
+
animation.css — which means the dialog also animates OUT, which it never did
|
|
41
|
+
(an `animation:` on `[open]` only ever plays once, on open). */
|
|
42
|
+
--opacity-from: 0;
|
|
43
|
+
--scale-x-from: 0.95;
|
|
44
|
+
--scale-y-from: 0.95;
|
|
45
|
+
--translate-y-from: -1rem;
|
|
42
46
|
|
|
43
47
|
.dialog__header {
|
|
44
48
|
display: flex;
|
|
@@ -75,25 +79,3 @@ dialog.dialog {
|
|
|
75
79
|
margin-block-start: 1.5rem;
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
|
-
|
|
79
|
-
@keyframes dialog-enter {
|
|
80
|
-
from {
|
|
81
|
-
opacity: 0;
|
|
82
|
-
scale: 0.95;
|
|
83
|
-
translate: 0 -1rem;
|
|
84
|
-
}
|
|
85
|
-
to {
|
|
86
|
-
opacity: 1;
|
|
87
|
-
scale: 1;
|
|
88
|
-
translate: 0 0;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@keyframes dialog-backdrop-enter {
|
|
93
|
-
from {
|
|
94
|
-
opacity: 0;
|
|
95
|
-
}
|
|
96
|
-
to {
|
|
97
|
-
opacity: 1;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
@@ -21,24 +21,30 @@
|
|
|
21
21
|
max-block-size: none;
|
|
22
22
|
|
|
23
23
|
&::backdrop {
|
|
24
|
-
backdrop-filter: blur(4px);
|
|
24
|
+
backdrop-filter: var(--scrim-filter, blur(4px));
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* Each edge states WHERE IT STARTS in the animation system's own vocabulary
|
|
29
|
+
* (`--translate-<axis>-from`) instead of owning a keyframe. Add `.transition`
|
|
30
|
+
* and the top-layer driver in animation.css animates it — both ways.
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
32
|
+
* This replaced four `@keyframes drawer-slide-in-*` driven by `animation:`,
|
|
33
|
+
* which only ever played on OPEN: the drawer's close was instant, while
|
|
34
|
+
* sitenav's transition-based copy of the same idea animated both ways.
|
|
35
|
+
*
|
|
36
|
+
* The var is set here rather than asking authors for a `.slide-*` effect
|
|
37
|
+
* class, because both would trip them up: the effect names read backwards for
|
|
38
|
+
* an edge panel (a LEFT drawer starts off-screen left and travels right, i.e.
|
|
39
|
+
* `.slide-right`), and `--slide-distance` defaults to 2rem where a drawer
|
|
40
|
+
* needs the full 100%. An explicit effect class still overrides this.
|
|
41
|
+
*
|
|
42
|
+
* EVERY edge states BOTH axes. The unset axis does not inherit a sensible
|
|
43
|
+
* zero — it inherits whatever the bare `.drawer` default left there, and the
|
|
44
|
+
* default is the left edge's `-100%`. Setting only `--translate-y-from` on
|
|
45
|
+
* `.drawer--bottom` therefore produced `translate: -100% 100%` and the panel
|
|
46
|
+
* flew in diagonally from the bottom-left corner.
|
|
36
47
|
*/
|
|
37
|
-
&.drawer--modeless::backdrop {
|
|
38
|
-
background: none;
|
|
39
|
-
backdrop-filter: none;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
48
|
&,
|
|
43
49
|
&.drawer--left {
|
|
44
50
|
inset-block: 0;
|
|
@@ -46,11 +52,8 @@
|
|
|
46
52
|
block-size: 100dvh;
|
|
47
53
|
inline-size: min(100dvi, var(--drawer-max-inline-size, 280px));
|
|
48
54
|
border-radius: 0;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
&:popover-open {
|
|
52
|
-
animation: drawer-slide-in-left 0.3s ease;
|
|
53
|
-
}
|
|
55
|
+
--translate-x-from: -100%;
|
|
56
|
+
--translate-y-from: 0;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
&.drawer--right {
|
|
@@ -58,22 +61,16 @@
|
|
|
58
61
|
inset-inline-end: 0;
|
|
59
62
|
inset-inline-start: auto;
|
|
60
63
|
inline-size: min(100dvi, var(--drawer-max-inline-size, 280px));
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
&:popover-open {
|
|
64
|
-
animation: drawer-slide-in-right 0.3s ease;
|
|
65
|
-
}
|
|
64
|
+
--translate-x-from: 100%;
|
|
65
|
+
--translate-y-from: 0;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
&.drawer--top {
|
|
69
69
|
inset-block-start: 0;
|
|
70
70
|
inset-inline: 0;
|
|
71
71
|
block-size: min(100dvb, var(--drawer-max-block-size, 100dvb));
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
&:popover-open {
|
|
75
|
-
animation: drawer-slide-in-top 0.3s ease;
|
|
76
|
-
}
|
|
72
|
+
--translate-x-from: 0;
|
|
73
|
+
--translate-y-from: -100%;
|
|
77
74
|
}
|
|
78
75
|
|
|
79
76
|
&.drawer--bottom {
|
|
@@ -81,43 +78,7 @@
|
|
|
81
78
|
inset-block-start: auto;
|
|
82
79
|
inset-inline: 0;
|
|
83
80
|
block-size: min(100dvb, var(--drawer-max-block-size, 100dvb));
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
&:popover-open {
|
|
87
|
-
animation: drawer-slide-in-bottom 0.3s ease;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
@keyframes drawer-slide-in-left {
|
|
93
|
-
from {
|
|
94
|
-
translate: -100% 0;
|
|
95
|
-
}
|
|
96
|
-
to {
|
|
97
|
-
translate: 0 0;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
@keyframes drawer-slide-in-right {
|
|
101
|
-
from {
|
|
102
|
-
translate: 100% 0;
|
|
103
|
-
}
|
|
104
|
-
to {
|
|
105
|
-
translate: 0 0;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
@keyframes drawer-slide-in-top {
|
|
109
|
-
from {
|
|
110
|
-
translate: 0 -100%;
|
|
111
|
-
}
|
|
112
|
-
to {
|
|
113
|
-
translate: 0 0;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
@keyframes drawer-slide-in-bottom {
|
|
117
|
-
from {
|
|
118
|
-
translate: 0 100%;
|
|
119
|
-
}
|
|
120
|
-
to {
|
|
121
|
-
translate: 0 0;
|
|
81
|
+
--translate-x-from: 0;
|
|
82
|
+
--translate-y-from: 100%;
|
|
122
83
|
}
|
|
123
84
|
}
|