@getvitops/core 2.1.0 → 4.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.
@@ -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
- * Modeless — a panel you work *alongside* rather than through. Drops the
29
- * scrim so the page behind stays legible, which is the whole point for a
30
- * live editor or an inspector: you're watching what your edits do.
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
- * Pair with `popover="manual"`. An `auto` popover light-dismisses on the
33
- * first click outside — i.e. exactly the interaction a modeless panel exists
34
- * to allow — and `manual` also drops Esc, so give it an explicit close
35
- * control (and wire Esc yourself if the panel warrants it).
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
- &[open],
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
- &[open],
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
- &[open],
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
- &[open],
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
  }
@@ -19,7 +19,19 @@
19
19
  opacity 0.2s ease,
20
20
  translate 0.2s ease,
21
21
  visibility 0.2s allow-discrete;
22
+ /* `position: absolute`, anchored to the `position: relative` host above.
23
+ This is the whole reason a hover dropdown ever worked or didn't: a closed
24
+ popover is NOT in the top layer, but it keeps the UA's
25
+ `[popover] { position: fixed }`. Resetting only `inset` left it fixed to
26
+ the VIEWPORT at whatever static position it resolved to — measured 3300px
27
+ below its own trigger and off-screen, so the panel faithfully faded in
28
+ somewhere nobody was looking, which reads exactly like "hover does
29
+ nothing". Anchoring it puts it under the trigger and makes it follow on
30
+ scroll. */
31
+ position: absolute;
22
32
  inset: auto;
33
+ inset-block-start: 100%;
34
+ inset-inline-start: 0;
23
35
  margin: 0;
24
36
  }
25
37
 
@@ -39,7 +51,9 @@
39
51
  padding-block-start: var(--dropdown-gap, 0.5rem);
40
52
  }
41
53
 
54
+ /* Was `!important`, to beat popover.css's then plain-specificity ::backdrop.
55
+ That rule is `:where()` (0,0,0) now, so ordinary specificity is enough. */
42
56
  > [popover]::backdrop {
43
- background: transparent !important;
57
+ background: transparent;
44
58
  }
45
59
  }
@@ -52,9 +52,9 @@ dialog.lightbox-dialog {
52
52
  display: grid;
53
53
  place-items: center;
54
54
 
55
- &::backdrop {
56
- background: transparent;
57
- }
55
+ /* No scrim. Stated through popover.css's token rather than overriding its
56
+ ::backdrop rule, so it keeps the shared fade timing. */
57
+ --scrim: transparent;
58
58
 
59
59
  &[open] {
60
60
  display: grid;
@@ -1,21 +1,47 @@
1
1
  /**
2
2
  * Marquee — CSS-only infinite scrolling row/column migrated from old-css-lib.
3
- * Duplicate the .marquee__content for a seamless loop. Pauses on hover with the
4
- * --pause-hover modifier; reverses / goes vertical via modifiers.
3
+ *
4
+ * <div class="marquee marquee--pause-hover">
5
+ * <div class="marquee__content"><span class="marquee__item">…</span></div>
6
+ * <div class="marquee__content" aria-hidden="true">…the same items…</div>
7
+ * </div>
8
+ *
9
+ * TWO `.marquee__content` blocks, not one. Each is `min-inline-size: 100%` and the
10
+ * keyframe travels exactly its own width, so the second copy is what occupies the
11
+ * space the first vacates. With a single copy the track scrolls off and leaves
12
+ * blank space — which reads as "the marquee isn't working" rather than as a
13
+ * missing duplicate.
14
+ *
15
+ * Spacing is `--marquee-gap`, and it has to be applied in BOTH places: between
16
+ * items inside a copy, and between the two copies. The keyframe then travels
17
+ * `100% + gap`, because the seam between copies is one more gap that has to be
18
+ * consumed for the loop to be seamless — translate by a bare `-100%` and the
19
+ * items visibly bunch up once per revolution.
5
20
  */
6
21
 
7
22
  .marquee {
8
23
  --_marquee-direction: var(--marquee-direction, normal);
9
24
 
25
+ /* `<wc-marquee>` overrides this to `auto`, releasing the 100% floor. */
26
+ --_marquee-min: 100%;
27
+
10
28
  display: flex;
29
+ gap: var(--marquee-gap, 1rem);
11
30
  overflow: hidden;
12
31
  user-select: none;
13
32
  mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
14
33
 
15
34
  .marquee__content {
16
35
  display: flex;
36
+ gap: var(--marquee-gap, 1rem);
17
37
  flex-shrink: 0;
18
- min-inline-size: 100%;
38
+ /* 100% pads a short copy out to the track width, which puts the leftover
39
+ space at the end of every copy and makes the seam gap wider than the item
40
+ gaps. `<wc-marquee>` sets `--_marquee-min: auto` and clones enough copies to
41
+ cover the track, so the copy can be its own width and every gap matches.
42
+ Without the element this stays 100% — the CSS-only loop still works, it
43
+ just needs the author to duplicate the content. */
44
+ min-inline-size: var(--_marquee-min, 100%);
19
45
  animation: marquee-scroll var(--marquee-duration, 20s) linear infinite;
20
46
  animation-direction: var(--_marquee-direction);
21
47
  }
@@ -54,7 +80,9 @@
54
80
  translate: 0 0;
55
81
  }
56
82
  to {
57
- translate: -100% 0;
83
+ /* One copy + one gap. `--_marquee-distance` is the measured px value when
84
+ the element is present; the percentage is the CSS-only equivalent. */
85
+ translate: calc(-1 * var(--_marquee-distance, calc(100% + var(--marquee-gap, 1rem)))) 0;
58
86
  }
59
87
  }
60
88
 
@@ -63,6 +91,6 @@
63
91
  translate: 0 0;
64
92
  }
65
93
  to {
66
- translate: 0 -100%;
94
+ translate: 0 calc(-1 * var(--_marquee-distance, calc(100% + var(--marquee-gap, 1rem))));
67
95
  }
68
96
  }
@@ -1,8 +1,18 @@
1
1
  /**
2
- * Nav — base / navbar / drawer / collapse navigation presentations migrated
3
- * from old-css-lib. CSS shell: drawer + submenu use the Popover API / <details>
4
- * with @starting-style transitions (polyfilled). The open/close toggle wiring
5
- * arrives with the Lit nav component; the CSS degrades to plain links without it.
2
+ * Nav — LEGACY. Base / drawer / collapse navigation presentations migrated from
3
+ * old-css-lib, superseded by the three patterns below. Kept because it ships in
4
+ * a published major; removal is its own breaking change.
5
+ *
6
+ * This header used to say "the open/close toggle wiring arrives with the Lit nav
7
+ * component". No such component was ever written, and none is planned — the
8
+ * house pattern is native (`popovertarget` + `[popover]`, `<details>`), which
9
+ * needs no JS at all beyond the Popover polyfill.
10
+ *
11
+ * Which one you actually want:
12
+ * · `patterns/navbar.css` — a horizontal row of links, with alignment.
13
+ * · `patterns/sitenav.css` — navbar at width ⇄ toggle + drawer below it.
14
+ * · `patterns/navshell.css` — a nav ASIDE beside main content, collapsing to a
15
+ * toggle + drawer. Nestable (site nav + on-page nav).
6
16
  */
7
17
 
8
18
  nav:has(> .nav-items) {
@@ -133,48 +143,20 @@ nav:has(> .nav-items) {
133
143
  width: 100%;
134
144
  background: var(--color-bg-surface);
135
145
  color: var(--color-text-surface);
136
- opacity: 0;
137
- translate: -100%;
138
- transition-timing-function: var(--interact-easing, ease);
139
- transition:
140
- opacity 0.4s,
141
- translate 0.4s,
142
- overlay 0.4s allow-discrete,
143
- display 0.4s allow-discrete;
146
+
147
+ /* Entry direction only. The transition, the `@starting-style` and the scrim
148
+ used to be restated here in full; they now come from the top-layer driver in
149
+ animation.css and the single `::backdrop` in popover.css. Add an effect
150
+ class to change the motion (`class="drawer-menu open-fade-in"`).
151
+
152
+ Timing moved with them: this was a hand-set 0.4s / 0.7s pair and is now the
153
+ framework's `--animation-duration` + `--custom-ease-out`, like every other
154
+ transition in the system. */
155
+ --translate-x-from: -100%;
144
156
 
145
157
  &[open],
146
158
  &:popover-open {
147
159
  display: flex;
148
- opacity: 1;
149
- translate: 0%;
150
- }
151
-
152
- @starting-style {
153
- &[open],
154
- &:popover-open {
155
- opacity: 0;
156
- translate: -100%;
157
- }
158
- }
159
-
160
- &::backdrop {
161
- background-color: transparent;
162
- transition:
163
- display 0.7s allow-discrete,
164
- overlay 0.7s allow-discrete,
165
- background-color 0.7s;
166
- }
167
-
168
- &[open]::backdrop,
169
- &:popover-open::backdrop {
170
- background-color: rgb(0 0 0 / 25%);
171
- }
172
-
173
- @starting-style {
174
- &[open]::backdrop,
175
- &:popover-open::backdrop {
176
- background-color: transparent;
177
- }
178
160
  }
179
161
  }
180
162
 
@@ -193,43 +175,9 @@ nav:has(> .nav-items) {
193
175
  overflow-y: auto;
194
176
  }
195
177
 
196
- /* ── Navbar presentation ──────────────────────────────────────────────────── */
197
- .navbar {
198
- display: flex;
199
- align-items: center;
200
- gap: 2rem;
201
-
202
- nav {
203
- flex: 1;
204
- flex-direction: row;
205
- }
206
-
207
- .nav-items {
208
- flex: 1;
209
- flex-direction: row;
210
- gap: 2.25rem;
211
- border-bottom: none;
212
- padding-bottom: 0;
213
- }
214
-
215
- .nav-actions {
216
- flex-direction: row;
217
- gap: 2.25rem;
218
- border-top: none;
219
- padding-top: 0;
220
- }
221
-
222
- .nav-header {
223
- border-bottom: none;
224
- padding-bottom: 0;
225
- }
226
- }
227
-
228
- .navbar-sticky {
229
- position: sticky;
230
- top: 0;
231
- z-index: var(--z-tier-sticky);
232
- }
178
+ /* Navbar presentation moved to patterns/navbar.css, where it is a primitive
179
+ rather than one half of this file's drawer⇄navbar pair. `.navbar-sticky`
180
+ is aliased there so existing markup keeps working. */
233
181
 
234
182
  .nav-split {
235
183
  margin-block-start: auto;
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Navbar — a horizontal row of links, with alignment.
3
+ *
4
+ * <nav class="navbar navbar--end">
5
+ * <a class="link" href="/guides">Guides</a>
6
+ * <a class="link" href="/reference">Reference</a>
7
+ * </nav>
8
+ *
9
+ * Extracted from patterns/nav.css, where `.navbar` already lived but only as the
10
+ * horizontal half of that file's drawer⇄navbar pair — it could not be used on
11
+ * its own, and it had no way to say where the links should sit. It is a
12
+ * primitive now, so `sitenav` (and anything else that needs a link row at width)
13
+ * composes it instead of restating `display: flex` and a gap.
14
+ *
15
+ * Deliberately NOT a `.cluster`: a cluster wraps and is content-agnostic; a
16
+ * navbar is a single row of navigation that stays a row, and carries the
17
+ * alignment vocabulary a nav actually needs.
18
+ */
19
+ .navbar {
20
+ display: flex;
21
+ align-items: center;
22
+ gap: var(--navbar-gap, 2rem);
23
+
24
+ /* Links stay on one line — a navbar that wraps mid-row reads as broken chrome.
25
+ Above its breakpoint `sitenav` is what decides there is room; below it, the
26
+ drawer is the answer, not a wrapped bar. */
27
+ flex-wrap: nowrap;
28
+ }
29
+
30
+ /* ── Alignment. `--start` is the default and exists so the intent can be stated
31
+ rather than inferred from its absence. ── */
32
+ .navbar--start {
33
+ justify-content: flex-start;
34
+ }
35
+ .navbar--center {
36
+ justify-content: center;
37
+ }
38
+ .navbar--end {
39
+ justify-content: flex-end;
40
+ }
41
+
42
+ /**
43
+ * Push everything after this element to the far edge — the usual "brand on the
44
+ * left, links on the right" split, without a wrapper element per side.
45
+ */
46
+ .navbar__spacer {
47
+ margin-inline-start: auto;
48
+ }
49
+
50
+ .navbar--sticky,
51
+ /* The pre-extraction spelling. Kept so an existing consumer's markup keeps
52
+ working; prefer `.navbar--sticky`. */
53
+ .navbar-sticky {
54
+ position: sticky;
55
+ inset-block-start: var(--navbar-sticky-offset, 0);
56
+ z-index: var(--z-tier-sticky);
57
+ }
58
+
59
+ /* ── Legacy composition: nav.css's `.nav-*` parts inside a navbar. Kept with the
60
+ pattern they belong to so nav.css can be retired as one piece. ── */
61
+ .navbar {
62
+ nav {
63
+ flex: 1;
64
+ flex-direction: row;
65
+ }
66
+
67
+ .nav-items {
68
+ flex: 1;
69
+ flex-direction: row;
70
+ gap: 2.25rem;
71
+ border-bottom: none;
72
+ padding-bottom: 0;
73
+ }
74
+
75
+ .nav-actions {
76
+ flex-direction: row;
77
+ gap: 2.25rem;
78
+ border-top: none;
79
+ padding-top: 0;
80
+ }
81
+
82
+ .nav-header {
83
+ border-bottom: none;
84
+ padding-bottom: 0;
85
+ }
86
+ }