@getvitops/generator 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.
- package/CHANGELOG.md +411 -0
- package/assets/bricks/elements/color-scheme-toggle.php +3 -3
- 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/consent.css +14 -3
- 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 +253 -408
- package/assets/css/patterns/split-link.css +3 -3
- package/assets/css/patterns/tree.css +118 -8
- package/assets/js/consent.js +1 -1
- package/assets/js/elements.js +26 -26
- package/{site.schema.json → config.schema.json} +2364 -2264
- package/dist/index.d.mts +1269 -541
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +4542 -3010
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,416 @@
|
|
|
1
1
|
# @getvitops/generator
|
|
2
2
|
|
|
3
|
+
## 4.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- f7bc0a0: Add `vitops search setup` — onboard domains into Google Search Console as domain properties.
|
|
8
|
+
|
|
9
|
+
**Breaking:** the `vitops indexing` command has been renamed to **`vitops search notify`**. There is
|
|
10
|
+
no alias — update any scripts or CI that call `vitops indexing` to `vitops search notify` (same flags,
|
|
11
|
+
same behaviour).
|
|
12
|
+
|
|
13
|
+
**New: `vitops search setup`.** For each domain in a site config's new `site.searchConsole` block
|
|
14
|
+
(a record keyed by bare hostname), it:
|
|
15
|
+
- ensures the apex verification TXT record in Cloudflare,
|
|
16
|
+
- verifies ownership via the Site Verification API (DNS_TXT), retried with exponential backoff while
|
|
17
|
+
DNS propagates — a still-unverified domain is reported **PENDING**, not failed,
|
|
18
|
+
- adds the `sc-domain:` property via the Search Console API,
|
|
19
|
+
- adds any `delegatedOwners` to the verified Site Verification web resource.
|
|
20
|
+
|
|
21
|
+
It is idempotent (a re-run of an onboarded domain is a no-op), supports `--check` (report drift, exit
|
|
22
|
+
non-zero, mutate nothing) and `--dry` (print the plan, change nothing), and `--domain <name>` to
|
|
23
|
+
scope to one entry. DNS records are only ever created, never edited or deleted.
|
|
24
|
+
|
|
25
|
+
Credentials come from the environment, never the config: `CLOUDFLARE_API_TOKEN` (a `Zone:DNS:Edit`
|
|
26
|
+
token) and a Google **user OAuth refresh token** as `VITOPS_GOOGLE_CLIENT_ID` /
|
|
27
|
+
`VITOPS_GOOGLE_CLIENT_SECRET` / `VITOPS_GOOGLE_REFRESH_TOKEN` (scoped to `siteverification` +
|
|
28
|
+
`webmasters`). Granting a Google Group **Full-User** access has no Search Console API and is surfaced
|
|
29
|
+
as a reminder in the summary rather than automated.
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- 14813fa: Document which tier provides each pattern — `vitops docs components`.
|
|
34
|
+
|
|
35
|
+
The toolkit ships four tiers that compose: CSS framework classes, `<wc-*>` web components, Astro
|
|
36
|
+
components, Bricks elements. Nothing said so. The class reference listed pattern names, the
|
|
37
|
+
elements reference listed Bricks controls, and the fact that `tree` is _also_ a web component
|
|
38
|
+
_and_ an Astro component existed only in the source layout. The cost is silent: you hand-write
|
|
39
|
+
the markup a component already emits, or you wrap a component that already emits its own tag.
|
|
40
|
+
|
|
41
|
+
`TIERS` in `@getvitops/generator` is the new manifest — per pattern, its CSS partial and
|
|
42
|
+
representative classes, its `wc-*` tag and which bundle that ships in, its Astro component(s),
|
|
43
|
+
its Bricks element, and one line saying what to actually write. `tierPatterns(tier)` projects one
|
|
44
|
+
tier. `vitops docs components` renders all four in one document, and the reference sections it
|
|
45
|
+
feeds render the same data per tier.
|
|
46
|
+
|
|
47
|
+
It is **authored rather than derived, and drift-guarded** instead. Naming convention carries most
|
|
48
|
+
of it and breaks exactly where it matters — `splitter.css` hosts two components, `tag.css` serves
|
|
49
|
+
three config patterns, `anchor-link.css` provides `.link`, `layout.css` provides `.split` and
|
|
50
|
+
`.centered` — so a derivation would need an exceptions table longer than the rule, and a rename
|
|
51
|
+
would silently drop a link. Instead, tests fail the build when a hand-written CSS partial, a
|
|
52
|
+
`customElements.define`, an exported Astro component or a Bricks element isn't accounted for.
|
|
53
|
+
|
|
54
|
+
Four things the manifest records that cannot be inferred, each a real failure mode:
|
|
55
|
+
- **Whether an Astro component wraps a web component.** `Tree` and `CookieConsent` emit the
|
|
56
|
+
`<wc-*>` tag with the fallback inside; `Details`, `Drawer`, `Popover`, `NavShell` and `Subgrid`
|
|
57
|
+
emit tier-1 markup with no web component at all. Reading the first group as the second gives
|
|
58
|
+
`<wc-tree><Tree /></wc-tree>` — two elements on one tree, which renders and misbehaves.
|
|
59
|
+
- **Where each element ships.** `elements.js` for the registered set, its own bundle for
|
|
60
|
+
`<wc-consent>` and `<wc-theme-editor>`, and **no bundle at all** for the four editor-v2 tags —
|
|
61
|
+
which are registered, importable-looking and inert in a consumer project. The guard checks this
|
|
62
|
+
against what `js/elements.ts` imports, so it can't claim an element ships when it doesn't.
|
|
63
|
+
- **Whether a pattern is config-authored.** `patterns.items` patterns get the token cascade,
|
|
64
|
+
states, role variants and override hooks; a structural partial gets none of them. The docs also
|
|
65
|
+
now say when a config-authored pattern is **absent from your config**, because naming its
|
|
66
|
+
classes while your build emits none of them is worse than omitting it.
|
|
67
|
+
- **The import specifier, verbatim.** These are published as the line to copy, so they are checked
|
|
68
|
+
against `@getvitops/astro`'s `exports`. That guard immediately caught
|
|
69
|
+
`@getvitops/astro/components/../CookieConsent.astro` — plausible-looking, right basename, not an
|
|
70
|
+
importable path (`CookieConsent.astro` ships from the package root).
|
|
71
|
+
|
|
72
|
+
- c6b99e7: Ad-click attribution and conversion notifications ship as part of the toolchain.
|
|
73
|
+
|
|
74
|
+
A visitor arriving on an ad carries a click ID in the URL; `<Tracking />` captures it into a first-party `_ac` cookie, and when that visitor later submits a form or taps a `tel:` link, the conversion handler reads the cookie back and notifies whoever the config says. Previously this was per-site code.
|
|
75
|
+
|
|
76
|
+
**Added — `@getvitops/utils/tracking`.** The attribution vocabulary and cookie, as pure functions over a cookie _string_ so the browser capture and the server-side handler share one implementation: `parseTrackingCookie`, `serializeTrackingCookie`, `mergeTracking`, `identifyPlatform`, `getPrimaryClickId`, plus the click-ID/UTM tables. No DOM, no network, no clock — every function that needs "now" takes it as an argument, so it runs unchanged in a Worker.
|
|
77
|
+
|
|
78
|
+
**Added — `@getvitops/utils/notify`.** Conversion notifications, split the way `indexing/` is: `plan.ts` decides everything purely (which channels fire, who they reach, and **why anything is skipped**), `render.ts` turns the event into prose, `email.ts` executes and decides nothing. A misconfigured site can therefore be told exactly why no notification will arrive — a silently unsent one is indistinguishable from no conversion.
|
|
79
|
+
|
|
80
|
+
The `ConversionEvent` is the abstraction: the event is the _fact_, and how it reads is the channel's business.
|
|
81
|
+
|
|
82
|
+
**Added — the `email` channel, via Cloudflare Email Sending.** Uses the current structured binding (`env.EMAIL.send({ to, from, subject, html, text })`), not the legacy `EmailMessage` + hand-built MIME path. The binding is **passed in, never imported**, so `@getvitops/utils` takes no Cloudflare dependency and the sender is testable with a stub. Retries only the transient error codes; a configuration fault like `E_SENDER_NOT_VERIFIED` is surfaced verbatim rather than collapsed into "send failed". With no binding it prints the notification — the dev path.
|
|
83
|
+
|
|
84
|
+
Remember to onboard the sending domain (`wrangler email sending enable <domain>`) and add `"send_email": [{ "name": "EMAIL" }]` to `wrangler.jsonc`, or every send fails.
|
|
85
|
+
|
|
86
|
+
**Added — `<Tracking />` and `createConversionRoute()`** in `@getvitops/astro` (`@getvitops/astro/Tracking.astro`, `@getvitops/astro/routes`). The route factory handles both the `tel:` beacon and a form POST; validation and business rules stay the consumer's, because every site's form differs. A failed notification never fails the request — the visitor has already submitted, and refusing them because our mail didn't go out turns a lost notification into a lost conversion.
|
|
87
|
+
|
|
88
|
+
**Added — `site.tracking` and a widened `site.notifications`.** `notifications.email` now accepts a full channel object as well as a bare address (which still means what it did). `tracking` gains `category`.
|
|
89
|
+
|
|
90
|
+
**Fixed — the capture script now asks for consent instead of only reading it.** It previously checked `granted('marketing')` passively, which under the demand-driven banner is a permanent no-op: nothing else on a page demands `marketing`, so the banner never offered it, so it was never granted, so `_ac` was never written — silently, on every site with the gate enabled. It now calls `require()`, which is what raises the banner, and only when the URL actually carried a click ID or UTM. A visitor arriving organically has nothing to attribute and is never asked.
|
|
91
|
+
|
|
92
|
+
The integration adds `marketing` to the offered categories when tracking is on, so the banner has a row for the category the script will demand, and warns when tracking is enabled with `consent` off.
|
|
93
|
+
|
|
94
|
+
**Fixed — revoking consent now clears `_ac`.** The marker `<Tracking />` emits carries `data-consent-cookies`, which the consent runtime's cleanup reads. There was no cleanup path for this cookie before.
|
|
95
|
+
|
|
96
|
+
**Fixed — the cookie notice discloses `_ac`.** It is first-party, so no provider table would ever name it, and a site running attribution alongside a cookieless analytics provider was previously described as setting no cookies at all.
|
|
97
|
+
|
|
98
|
+
- c6b99e7: Consent is now demand-driven: the banner appears when something actually needs permission, not on every first visit.
|
|
99
|
+
|
|
100
|
+
Previously, enabling the gate showed a banner to every new visitor regardless of what the site did — including sites whose only analytics provider was cookieless, where there was nothing to consent to. The build decided whether the machinery shipped and the runtime showed the banner because no cookie existed yet.
|
|
101
|
+
|
|
102
|
+
Now those are two separate facts. The build decides what the banner _can_ ask (rows in the markup); the runtime decides what it _does_ ask. A gated tag registers its demand when it reaches its loading strategy, and `<color-scheme-toggle>` registers `preferences` when a visitor picks a scheme. A site that gates nothing never interrupts anyone.
|
|
103
|
+
|
|
104
|
+
**Breaking — consent cookie schema (v1 → v2).** Consent is now recorded per category as granted / declined / **not yet asked**. The third state is what lets a later demand ask about a category an earlier prompt didn't cover: accepting an analytics banner no longer silently declines preferences. Every stored v1 choice is invalid and re-prompts once — a v1 cookie asserted a definite answer for categories the visitor was never shown.
|
|
105
|
+
|
|
106
|
+
**Breaking — `ConsentApi`.**
|
|
107
|
+
- `needed()` now means "something demanded a category the visitor hasn't answered", not "no cookie yet". A custom banner calling it will now stay hidden until something asks.
|
|
108
|
+
- `ConsentState.decided` (a single boolean) is gone. Use `decidedFor(state, category)`, or `undecidedCategories(state)`.
|
|
109
|
+
- New: `require(category)` registers a demand and reports whether it is granted; `request(category)` resolves once the visitor answers it; `demanded()` lists what has asked so far.
|
|
110
|
+
- `acceptAll()` / `rejectAll()` still mean every optional category. The banner no longer routes its buttons through them — "Accept" applies to the categories on screen.
|
|
111
|
+
|
|
112
|
+
**Breaking — `<color-scheme-toggle>` persistence.** The chosen scheme still applies immediately, but writing it to `localStorage` now waits on the `preferences` category **when the site has a consent gate**. Sites without `consent` enabled are unaffected and keep storing as before. If your site enables consent and offers a theme toggle, make sure `preferences` is among the offered categories (it is by default).
|
|
113
|
+
|
|
114
|
+
**Changed — offered categories.** `consent.categories` defaults to `['analytics', 'preferences']` (plus `marketing` when a configured tag needs it) rather than only what analytics detection could see. An unused row is hidden markup, so offering broadly costs nothing and covers `data-consent` markup no build-time scan can find. Pass `categories` explicitly to narrow it.
|
|
115
|
+
|
|
116
|
+
**Added — `<Head />` emits a small inline consent stub** when the gate is on. `consent.js` and `elements.js` are both deferred with no ordering between them, so without it a theme toggle could be clicked before the gate existed, read "no gate", and store. The stub answers `false` and queues, and the runtime replays the queue on load.
|
|
117
|
+
|
|
118
|
+
**Fixed — the generated cookie notice** now discloses the stored display preference when `preferences` is offered, and no longer promises a banner "shown when you first visit", which is no longer how the banner works.
|
|
119
|
+
|
|
120
|
+
- 14813fa: Document the consent, conversion-tracking, search and legal subsystems for agents.
|
|
121
|
+
|
|
122
|
+
`vitops docs` gains four topics — `consent`, `tracking`, `search`, `legal` — and the docs
|
|
123
|
+
bundle gains the matching concept docs under `concepts/`. Until now these subsystems were
|
|
124
|
+
described only by their generated config-schema field descriptions, so an agent working in a
|
|
125
|
+
consumer project had no account of the rules that make them work, and every one of those rules
|
|
126
|
+
fails **silently** when broken:
|
|
127
|
+
- a gated tag given a live `src` instead of `type="text/plain"` fetches the third party anyway,
|
|
128
|
+
so the gate becomes decorative;
|
|
129
|
+
- a caller using `granted()` instead of `require()` never raises the banner, so on a site where
|
|
130
|
+
nothing else demands that category the permission is never offered, never granted, and the
|
|
131
|
+
write never happens;
|
|
132
|
+
- an absent `window.vitopsConsent` read as "denied" rather than "this site has no gate";
|
|
133
|
+
- a consent patch widened to every category records consent nobody gave;
|
|
134
|
+
- a sitemap with no `<lastmod>` makes edited pages undetectable, so `search notify` looks
|
|
135
|
+
healthy while never resubmitting anything;
|
|
136
|
+
- a stale IndexNow key file returns `202` and is then discarded;
|
|
137
|
+
- Google's Indexing API accepts ordinary URLs, discards them, and violates its own terms.
|
|
138
|
+
|
|
139
|
+
The packaged agent skill now covers consent and conversion tracking, and its description names
|
|
140
|
+
these subsystems so it is actually surfaced when they are the task.
|
|
141
|
+
|
|
142
|
+
Also fixed: the icons concept doc still called the Astro integration `getvitops()`, renamed to
|
|
143
|
+
`vitops()` in 3.0.
|
|
144
|
+
|
|
145
|
+
- 14813fa: Add `<wc-tree>`, and a schema walker that feeds it.
|
|
146
|
+
|
|
147
|
+
`<wc-tree>` is progressive enhancement for the existing `.tree` pattern: given a nested
|
|
148
|
+
`<details>` disclosure tree it adds a filter, expand-all / collapse-all, and hash deep-linking.
|
|
149
|
+
It ships in `elements.js`.
|
|
150
|
+
|
|
151
|
+
`@getvitops/astro` gains `./components/Tree.astro` and `./components/tree.ts` (its `TreeItem`
|
|
152
|
+
type) to build that markup from data. As with every wrapper over a web component, `<Tree />`
|
|
153
|
+
emits the `<wc-tree>` tag itself with the accessible fallback inside — so `<Tree items={…} />`
|
|
154
|
+
is the whole call, and wrapping it in your own `<wc-tree>` nests two elements on one tree.
|
|
155
|
+
|
|
156
|
+
The slotted markup is the whole content and works without it — every node readable, expandable
|
|
157
|
+
and linkable — so the element only adds what CSS cannot do. Four things worth knowing:
|
|
158
|
+
- **The toolbar is generated, never authored.** A search field that does nothing is worse than
|
|
159
|
+
no search field, so the controls exist only once the element upgrades.
|
|
160
|
+
- **Deep-linking is the non-obvious one.** A node inside a closed `<details>` has no layout box,
|
|
161
|
+
so the browser's own fragment navigation finds nothing and silently stays at the top of the
|
|
162
|
+
page. `<wc-tree>` opens the target's ancestors — and the target's own disclosure — then scrolls.
|
|
163
|
+
- **Filtering matches a node's own label and description, never its subtree's text.** The obvious
|
|
164
|
+
`textContent` implementation makes every ancestor of a hit match, so the root matches any query
|
|
165
|
+
and the filter narrows nothing. That decision lives in a pure, tested module (`matchTree`)
|
|
166
|
+
rather than in the DOM wiring.
|
|
167
|
+
- **It initialises even when upgraded mid-insertion.** An element connected during an
|
|
168
|
+
`innerHTML` write — a view-transition swap, a client-side navigation — has no children yet
|
|
169
|
+
(measured: zero). Setup retries once the insertion completes, because the failure mode was
|
|
170
|
+
silent: no toolbar, no filter, no deep link, no error.
|
|
171
|
+
|
|
172
|
+
`patterns/tree.css` now supports two markup shapes: the item may be the `<details>` (the
|
|
173
|
+
pattern's original contract) or an `<li class="tree__item">` wrapping one, which is what gives
|
|
174
|
+
assistive tech list position and depth.
|
|
175
|
+
|
|
176
|
+
**`.tree` indent is fixed and now fluid**, which matters for any deep tree. Three separate leaks
|
|
177
|
+
compounded, each invisible in the CSS and each charging roughly one extra indent per level:
|
|
178
|
+
- the rule set both `margin-inline-start` and `padding-inline-start` to `--tree-indent`;
|
|
179
|
+
- `.tree { padding: var(--_p) }` applied to every nested `.tree`, not just the outermost — on all
|
|
180
|
+
four sides, so it narrowed from the end as well;
|
|
181
|
+
- `patterns/details.css` gives every non-summary child of a `<details>`
|
|
182
|
+
`margin-inline: var(--_content-margin)`, and its `details, .details` selector takes `:is()`
|
|
183
|
+
specificity under CSS nesting (**0-1-1**), so `.tree { margin: 0 }` at 0-1-0 _loses_ to it. A
|
|
184
|
+
nested tree is exactly such a child.
|
|
185
|
+
|
|
186
|
+
Measured in a browser: **41px per level against a 24px design**, so a 9-deep tree spent 382px on
|
|
187
|
+
indent and left its deepest label 162px wide. Now 24px per level, 198px total, and 653px of label.
|
|
188
|
+
The nested rule resets both box axes before applying the one indent it owes, and the default is
|
|
189
|
+
`clamp(0.75rem, 2.5vw, 1.5rem)` — 12px on a phone, 24px on a desktop — because a tree's depth is a
|
|
190
|
+
property of the data and cannot be known when the pattern is written. `--tree-indent` still
|
|
191
|
+
overrides it, and the `--lines` elbow derives from the same resolved value so the two cannot
|
|
192
|
+
disagree.
|
|
193
|
+
|
|
194
|
+
**Leaf rows now align with their branch siblings.** A branch spends a toggle column on its chevron
|
|
195
|
+
before its label; a leaf has none, so every leaf label sat one full column (24px, measured) to the
|
|
196
|
+
inline-start of its siblings and nothing at a given depth lined up. `.tree` exposes
|
|
197
|
+
`--_node-indent` (the toggle column) and `--_leaf-indent` (what a row without a toggle owes to
|
|
198
|
+
reach the same label column); `.tree__content` and `.tree__desc` both read the latter rather than
|
|
199
|
+
re-deriving the sum.
|
|
200
|
+
|
|
201
|
+
`<wc-tree>` also wraps its generated filter in `.input-group`, because `forms.css` styles text
|
|
202
|
+
controls as `.form-group > input` / `.input-group > input` — a bare `<input>` rendered with the
|
|
203
|
+
browser's 2px inset border and square corners next to the framework's own rounded controls.
|
|
204
|
+
|
|
205
|
+
`schemaTreeNodes(schema, { idPrefix, maxDepth, prune })` is new in `@getvitops/generator`: it walks
|
|
206
|
+
a JSON Schema — the same walk behind the `authoring.md` / `config.md` references — and returns tree
|
|
207
|
+
**data**, not markup, so each medium renders it (markdown for agents, an accessible `<details>`
|
|
208
|
+
tree for a site). Field ids are dotted config paths (`site.analytics.clarityId`), so any field can
|
|
209
|
+
be linked to directly.
|
|
210
|
+
|
|
211
|
+
`prune` exists for a specific hazard. The project config declares `designSystem.themes` as a
|
|
212
|
+
looser shape than `DesignSystemSchema`, because the full one is applied separately by
|
|
213
|
+
`resolveTheme` — so its embedded copy is an **approximation**, and measurably missing the
|
|
214
|
+
descriptions for `colors`, `colors.palette`, `colors.roles` and `colors.utilities`. Anything
|
|
215
|
+
rendering that copy as the token reference would silently document the colour system less well
|
|
216
|
+
than the toolchain already does; `prune` lets a caller stop at the wrapper and render `jsonSchema`
|
|
217
|
+
alongside instead.
|
|
218
|
+
|
|
219
|
+
`renderInlineMarkdown()` is exported for schema description text. It **lifts code spans out before
|
|
220
|
+
applying emphasis**, and that ordering is load-bearing rather than tidy: `colors.utilities`
|
|
221
|
+
describes its families as `` `bg-*` ``, `` `text-*` ``, `` `border-*` `` — literal asterisk
|
|
222
|
+
_wildcards_. Run emphasis over the raw string and the `*` closing `bg-*` pairs with the one
|
|
223
|
+
closing `text-*`, italicising the text between two unrelated utilities and eating both asterisks,
|
|
224
|
+
leaving prose that names families which don't exist. It also now renders single-asterisk emphasis,
|
|
225
|
+
which the schema does use (`*presentation*`, `*domain properties*`) and which previously printed
|
|
226
|
+
the asterisks literally.
|
|
227
|
+
|
|
228
|
+
Also fixed: `config.md` claimed "Only the wrapper is listed here" under `designSystem` and then
|
|
229
|
+
emitted the entire token schema anyway — `themes.<name>` _is_ a design system, so the walk
|
|
230
|
+
descended into it. It now stops at the wrapper and delegates to `authoring.md` as it always said
|
|
231
|
+
it did.
|
|
232
|
+
|
|
233
|
+
### Patch Changes
|
|
234
|
+
|
|
235
|
+
- Updated dependencies [c6b99e7]
|
|
236
|
+
- Updated dependencies [f7bc0a0]
|
|
237
|
+
- Updated dependencies [ceed51f]
|
|
238
|
+
- @getvitops/utils@4.0.0
|
|
239
|
+
|
|
240
|
+
## 3.0.0
|
|
241
|
+
|
|
242
|
+
### Major Changes
|
|
243
|
+
|
|
244
|
+
- 6e68ace: **Breaking:** the site config is now a three-section `Config` — `designSystem`,
|
|
245
|
+
`organization`, `site`.
|
|
246
|
+
|
|
247
|
+
The flat `SiteConfig` held the company (`organization`, `contact`, `locations`) and the
|
|
248
|
+
deployment (`analytics`, `environments`, `seo`, `legal`) as peers, so no single noun
|
|
249
|
+
described it, and a second site sharing the same company had no way to say so. The three
|
|
250
|
+
sections split those apart: several sites can now carry one `organization` and differ only
|
|
251
|
+
in `site`.
|
|
252
|
+
|
|
253
|
+
**Migrating.** `designSystem` stays at the root, and the fields already under
|
|
254
|
+
`organization` stay where they are. Everything else moves into one of two sections:
|
|
255
|
+
- → `site`: `defaultLocale`, `locales`, `domains`, `dns`, `cloudflare`, `environments`,
|
|
256
|
+
`abTesting`, `fonts`, `tags`, `postTypes`, `galleries`, `testimonials`, `templates`,
|
|
257
|
+
`navigation`, `seo`, `analytics`, `notifications`, `tracking`, `security`, `legal`,
|
|
258
|
+
`icons`, `favicon`, `deployment`
|
|
259
|
+
- → `organization`: `contact`, `primaryLocation`, `locations`, `services`, `links`
|
|
260
|
+
|
|
261
|
+
You do not have to work this out from the list: `vitops validate` detects a pre-3.0 flat
|
|
262
|
+
config and prints every move by name, rather than reporting a dozen unknown keys.
|
|
263
|
+
|
|
264
|
+
```jsonc
|
|
265
|
+
{
|
|
266
|
+
"designSystem": {
|
|
267
|
+
"themes": {
|
|
268
|
+
"default": {
|
|
269
|
+
/* … */
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
"organization": {
|
|
274
|
+
"name": "Acme",
|
|
275
|
+
"contact": "hq",
|
|
276
|
+
"locations": {
|
|
277
|
+
"hq": {
|
|
278
|
+
/* … */
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
"site": {
|
|
283
|
+
"defaultLocale": "en",
|
|
284
|
+
"domains": {
|
|
285
|
+
/* … */
|
|
286
|
+
},
|
|
287
|
+
"analytics": {
|
|
288
|
+
/* … */
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Renamed exports** (`@getvitops/generator`): `SiteConfigSchema` → `ConfigSchema`,
|
|
295
|
+
`SiteConfig` → `Config`, `validateSite` → `validateConfig`, `resolveSiteConfig` →
|
|
296
|
+
`resolveConfig`, `isSiteConfig` → `isConfig`, `siteJsonSchema` → `configJsonSchema`,
|
|
297
|
+
`SITE_SCHEMA_URL` → `CONFIG_SCHEMA_URL`, `SiteValidationResult` →
|
|
298
|
+
`ConfigValidationResult`. `ResolvedInput.site` is now `ResolvedInput.config`. New:
|
|
299
|
+
`OrganizationConfig` and `SiteSection` for the two sections.
|
|
300
|
+
|
|
301
|
+
**Renamed schema file:** `@getvitops/generator/site.schema.json` →
|
|
302
|
+
`@getvitops/generator/config.schema.json`. Update the `$schema` key in your config.
|
|
303
|
+
|
|
304
|
+
Option names are unchanged — `vitops({ site: { input } })`, the Vite plugin's `site`,
|
|
305
|
+
and `generate({ site })` still point at the config file.
|
|
306
|
+
|
|
307
|
+
**The Astro integration is now `vitops()`, not `getvitops()`.** It is a default export,
|
|
308
|
+
so the name is yours and nothing breaks on upgrade, but every example now reads
|
|
309
|
+
`import vitops from '@getvitops/astro'` — matching the Vite plugin, which has always been
|
|
310
|
+
`vitops`. The `@getvitops/*` package scope and the internal `virtual:getvitops/*` module
|
|
311
|
+
ids are unchanged; neither is an import name.
|
|
312
|
+
|
|
313
|
+
**Added:** a generated config authoring reference — `vitops docs config`, `docs/config.md`
|
|
314
|
+
in the OKF bundle, and _Config reference_ on the docs site. It is walked from the published
|
|
315
|
+
JSON Schema by the same helper that renders the `design-system.json` reference, so it
|
|
316
|
+
cannot describe a field validation does not accept.
|
|
317
|
+
|
|
318
|
+
- b115993: Nav shells, a top-layer animation driver, and a pile of fixes to things that never worked
|
|
319
|
+
|
|
320
|
+
### Breaking
|
|
321
|
+
- **Two custom elements renamed.** `<copy-button>` → `<wc-copy>`, `<multi-field>` →
|
|
322
|
+
`<wc-multifield>`. Update your markup. The Bricks element keys
|
|
323
|
+
(`vitops-copy-button`, `vitops-multi-field`) are **unchanged**, so elements already
|
|
324
|
+
placed on a Bricks page keep working; so are the `--multi-field-*` custom properties
|
|
325
|
+
and the `multi-field-*` events.
|
|
326
|
+
- **`<details>` now animates open and closed** where `prefers-reduced-motion` allows.
|
|
327
|
+
It was previously instant by deliberate choice — the transition used to deadlock the
|
|
328
|
+
disclosure shut. Re-verified on Chrome 149 with a real click; both `block-size` and
|
|
329
|
+
`content-visibility` must stay in the transition list, and dropping the latter
|
|
330
|
+
reproduces the deadlock.
|
|
331
|
+
- **Drawers and dialogs now animate on close.** Both drove their entry with
|
|
332
|
+
`animation:` on `[open]`, which by construction plays once — so the close was
|
|
333
|
+
instant. They now use the top-layer driver and animate both ways.
|
|
334
|
+
- **`.rhythm` gives every non-heading block heading-spacing before a heading.** The
|
|
335
|
+
pairs used to enumerate `p` (later `p, pre, blockquote, table, dl, ul, ol`), so a
|
|
336
|
+
heading after anything else got paragraph spacing. They are now defined by what a
|
|
337
|
+
heading _is_ — `h1`–`h6` plus the `font-display` / `font-title` / `font-heading` type
|
|
338
|
+
roles — and inverted to `:not(<heading>) + <heading>`. Expect slightly more space
|
|
339
|
+
above headings that follow a code block, table, figure-like `<div>` or component.
|
|
340
|
+
- **`popover.css` no longer pins `[popover]:popover-open { opacity: 1 }`.** It never
|
|
341
|
+
animated anything on its own, but it outranked `.transition` and made every
|
|
342
|
+
top-layer fade impossible. Removing it is what lets the driver work.
|
|
343
|
+
- **`nav.css`'s `.drawer-menu` timing** now follows `--animation-duration` /
|
|
344
|
+
`--custom-ease-out` instead of hand-set 0.4s / 0.7s.
|
|
345
|
+
|
|
346
|
+
### Fixed
|
|
347
|
+
- **`.sitenav--bp-sm` dropdowns could never open.** Its desktop block had drifted onto
|
|
348
|
+
an older markup shape, selecting `.sitenav__disclosure > .sitenav__submenu` where the
|
|
349
|
+
submenu is the disclosure's _sibling_. The four "intentionally parallel" breakpoint
|
|
350
|
+
blocks are now one shared block behind a style query — `md`/`lg`/`xl` were
|
|
351
|
+
byte-identical and only `sm` had rotted, which is exactly the drift the arrangement
|
|
352
|
+
invited. 583 → 361 lines.
|
|
353
|
+
- **Hover dropdowns rendered off-screen.** A closed popover is not in the top layer but
|
|
354
|
+
keeps the UA's `position: fixed`, and `.dropdown--show-on-hover` reset only `inset` —
|
|
355
|
+
so the panel faithfully faded in ~3300px from its trigger. Now anchored to it, and it
|
|
356
|
+
follows on scroll. Affects `.split-link--show-on-hover` too.
|
|
357
|
+
- **Horizontal overflow on narrow screens.** `.centered > *` floors at
|
|
358
|
+
`min-inline-size: 0`; `body` gets `overflow-wrap: break-word`; `patterns/code.css`
|
|
359
|
+
gains the `pre` rules it never had (`max-inline-size: 100%`, `overflow-x: auto`) and
|
|
360
|
+
gives inline `<code>` `overflow-wrap: anywhere`. Note a scroll container does _not_
|
|
361
|
+
zero its min-content contribution in Chrome, which is what made a single `<pre>` hold
|
|
362
|
+
a 390px viewport open at 797px.
|
|
363
|
+
- **`.split-<a>-<b>` now publishes `--_flex-direction: row`.** Only `.flex-*` did, so
|
|
364
|
+
`class="split flex-col md-split-1-2"` left the variable reading `column` at every
|
|
365
|
+
width and a nested `.grouped` collapsed its borders on the wrong axis.
|
|
366
|
+
- **`.toc-layout` uses `minmax(0, 1fr)`** instead of a bare `1fr`, whose automatic
|
|
367
|
+
minimum is min-content.
|
|
368
|
+
|
|
369
|
+
### Added
|
|
370
|
+
- **`patterns/navshell.css` + `<NavShell>` / `<NavShellToggle>`** — a navigation aside
|
|
371
|
+
beside content at width, collapsing to a toggle and drawer below it. **It nests**: a
|
|
372
|
+
site nav wrapping an on-this-page nav, each promoting at its own breakpoint, via a
|
|
373
|
+
style query on an inherited flag rather than four copied blocks. Its content column
|
|
374
|
+
is a container, so an inner shell measures the space it actually has. The toggle can
|
|
375
|
+
live outside the shell (a site header) with `toggle="external"`.
|
|
376
|
+
- **`patterns/navbar.css`** — `.navbar` extracted from `nav.css`, where it was only
|
|
377
|
+
half of that file's drawer⇄navbar pair, plus `--start` / `--center` / `--end`,
|
|
378
|
+
`__spacer` and `--sticky` (old `.navbar-sticky` aliased).
|
|
379
|
+
- **A top-layer animation driver.** `animation.css` gained the fourth driver alongside
|
|
380
|
+
`animate-view` / `animate-scroll` / `animate-trigger` / `transition`, and every effect
|
|
381
|
+
gained an `open-<fx>` state variant. Overlays now state _where they start_
|
|
382
|
+
(`--translate-x-from`) instead of owning a keyframe: `class="drawer drawer--right
|
|
383
|
+
open-fade-in"` composes slide and fade. Applied at zero specificity with identity
|
|
384
|
+
defaults, so a popover that sets no effect vars is unchanged.
|
|
385
|
+
- **One scrim.** `--scrim` / `--scrim-filter` tokens and `.no-scrim` in `popover.css`,
|
|
386
|
+
replacing 18 `::backdrop` blocks across seven partials. `.drawer--modeless` is aliased.
|
|
387
|
+
- **`<wc-marquee>`** — clones the content enough times to cover the track, so every gap
|
|
388
|
+
matches including the seam. The CSS-only `.marquee` is unchanged and still works
|
|
389
|
+
without it; the element only makes the spacing right. `--marquee-gap` added.
|
|
390
|
+
- **`--width-nav`** joins `--width-measure` / `-breakout` / `-spotlight` as the nav
|
|
391
|
+
column width.
|
|
392
|
+
- **`.skip-link`** in `patterns/anchor-link.css`, using a clip rather than the
|
|
393
|
+
`-100vw` idiom (which overflows in RTL and ignores the scrollbar gutter).
|
|
394
|
+
- **`.table-wrapper`** documented as the scroll wrapper for wide tables.
|
|
395
|
+
|
|
396
|
+
### Notes
|
|
397
|
+
- `patterns/nav.css` is marked legacy. Its header promised a Lit nav component that was
|
|
398
|
+
never written and is not planned — the house pattern is native. Use `navbar`,
|
|
399
|
+
`sitenav` or `navshell`; removal is a later change.
|
|
400
|
+
- `scroll-target.css`'s `.is-current` no longer claims to be a JS scroll-spy fallback.
|
|
401
|
+
There is no such code; `:target-current` is the only working highlight, which today
|
|
402
|
+
means Chrome.
|
|
403
|
+
- `elements.js` gains one element (`wc-marquee`), so the shared bundle is slightly
|
|
404
|
+
larger for every consumer.
|
|
405
|
+
- A registered custom property's `initial-value` must be computationally independent —
|
|
406
|
+
`16rem` is not, so `@property` silently drops the whole rule. `navshell` uses an
|
|
407
|
+
inline fallback instead.
|
|
408
|
+
|
|
409
|
+
### Patch Changes
|
|
410
|
+
|
|
411
|
+
- Updated dependencies [6e68ace]
|
|
412
|
+
- @getvitops/utils@3.0.0
|
|
413
|
+
|
|
3
414
|
## 2.1.0
|
|
4
415
|
|
|
5
416
|
### Minor Changes
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Vitops — Color Scheme Toggle element (Bricks Builder).
|
|
4
4
|
*
|
|
5
|
-
* Renders the <color-scheme-toggle> Lit component (src/web-components/WCColorSchemeToggle.ts):
|
|
5
|
+
* Renders the <wc-color-scheme-toggle> Lit component (src/web-components/WCColorSchemeToggle.ts):
|
|
6
6
|
* a segmented System / Light / Dark theme toggle, hidden until JS loads. Optionally seed
|
|
7
7
|
* the initial `scheme`.
|
|
8
8
|
*
|
|
@@ -21,7 +21,7 @@ class Vitops_Element_Color_Scheme_Toggle extends \Bricks\Element {
|
|
|
21
21
|
public $category = 'vitops';
|
|
22
22
|
public $name = 'vitops-color-scheme-toggle';
|
|
23
23
|
public $icon = 'ti-shine';
|
|
24
|
-
public $css_selector = 'color-scheme-toggle';
|
|
24
|
+
public $css_selector = 'wc-color-scheme-toggle';
|
|
25
25
|
|
|
26
26
|
public function get_label() {
|
|
27
27
|
return esc_html__( 'Color Scheme Toggle', 'bricks' );
|
|
@@ -56,6 +56,6 @@ class Vitops_Element_Color_Scheme_Toggle extends \Bricks\Element {
|
|
|
56
56
|
|
|
57
57
|
$attr_str = implode( ' ', $attrs );
|
|
58
58
|
|
|
59
|
-
echo "<color-scheme-toggle {$attr_str} {$this->render_attributes( '_root' )}></color-scheme-toggle>";
|
|
59
|
+
echo "<wc-color-scheme-toggle {$attr_str} {$this->render_attributes( '_root' )}></wc-color-scheme-toggle>";
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Vitops — Copy Button element (Bricks Builder).
|
|
4
4
|
*
|
|
5
|
-
* Renders the <copy
|
|
5
|
+
* Renders the <wc-copy> Lit component (src/web-components/WCCopy.ts): a
|
|
6
6
|
* copy-to-clipboard button, hidden until connected (Clipboard API gate). The `value`
|
|
7
7
|
* is copied; `label` is the button text (falls back to slotted text).
|
|
8
8
|
*
|
|
@@ -21,7 +21,7 @@ class Vitops_Element_Copy extends \Bricks\Element {
|
|
|
21
21
|
public $category = 'vitops';
|
|
22
22
|
public $name = 'vitops-copy-button';
|
|
23
23
|
public $icon = 'ti-clipboard';
|
|
24
|
-
public $css_selector = 'copy
|
|
24
|
+
public $css_selector = 'wc-copy';
|
|
25
25
|
|
|
26
26
|
public function get_label() {
|
|
27
27
|
return esc_html__( 'Copy Button', 'bricks' );
|
|
@@ -60,6 +60,6 @@ class Vitops_Element_Copy extends \Bricks\Element {
|
|
|
60
60
|
$attr_str = implode( ' ', $attrs );
|
|
61
61
|
$fallback = ! empty( $s['label'] ) ? esc_html( $s['label'] ) : esc_html__( 'Copy to clipboard', 'bricks' );
|
|
62
62
|
|
|
63
|
-
echo "<copy
|
|
63
|
+
echo "<wc-copy {$attr_str} {$this->render_attributes( '_root' )}>{$fallback}</wc-copy>";
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Vitops — Multi Field element (Bricks Builder).
|
|
4
4
|
*
|
|
5
|
-
* Renders the <multi-field> Lit component (src/web-components/WCMultiField.ts): a
|
|
5
|
+
* Renders the <wc-multi-field> Lit component (src/web-components/WCMultiField.ts): a
|
|
6
6
|
* form-associated repeatable input group (add / remove entries, min / max). Default
|
|
7
7
|
* entries are supplied as slotted <input value="…"> children, which the component reads
|
|
8
8
|
* on connect.
|
|
@@ -22,7 +22,7 @@ class Vitops_Element_Multi_Field extends \Bricks\Element {
|
|
|
22
22
|
public $category = 'vitops';
|
|
23
23
|
public $name = 'vitops-multi-field';
|
|
24
24
|
public $icon = 'ti-list';
|
|
25
|
-
public $css_selector = 'multi-field';
|
|
25
|
+
public $css_selector = 'wc-multi-field';
|
|
26
26
|
|
|
27
27
|
public function get_label() {
|
|
28
28
|
return esc_html__( 'Multi Field', 'bricks' );
|
|
@@ -143,6 +143,6 @@ class Vitops_Element_Multi_Field extends \Bricks\Element {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
echo "<multi-field {$attr_str} {$this->render_attributes( '_root' )}>{$inputs}</multi-field>";
|
|
146
|
+
echo "<wc-multi-field {$attr_str} {$this->render_attributes( '_root' )}>{$inputs}</wc-multi-field>";
|
|
147
147
|
}
|
|
148
148
|
}
|
package/assets/css/animation.css
CHANGED
|
@@ -529,6 +529,85 @@
|
|
|
529
529
|
}
|
|
530
530
|
}
|
|
531
531
|
|
|
532
|
+
/* ===========================================
|
|
533
|
+
* Tier 1c: Top layer (popover / dialog open-close)
|
|
534
|
+
* The `open-<fx>` state variants (generated, like hover-/focus-/active-) already
|
|
535
|
+
* supply the VALUES. What a top-layer element additionally needs is mechanism,
|
|
536
|
+
* and that is the same for every effect — so it lives here, once:
|
|
537
|
+
*
|
|
538
|
+
* <div popover class="drawer drawer--start transition open-slide-right">
|
|
539
|
+
*
|
|
540
|
+
* Before this existed there was no driver for the top layer, so every overlay
|
|
541
|
+
* pattern hand-rolled one: drawer.css drove entry with four @keyframes and
|
|
542
|
+
* `animation:`, which only plays on OPEN (its close was instant), while
|
|
543
|
+
* sitenav.css used a transition and animated both ways. Same job, two
|
|
544
|
+
* mechanisms, two behaviours.
|
|
545
|
+
* =========================================== */
|
|
546
|
+
|
|
547
|
+
/* Applied to the top layer BY DEFAULT, and at `:where()` zero specificity.
|
|
548
|
+
*
|
|
549
|
+
* Not an opt-in class, unlike the other three drivers, for two reasons. It is
|
|
550
|
+
* free: every endpoint below defaults to identity (opacity 1, translate 0,
|
|
551
|
+
* scale 1), so a popover that sets no effect vars transitions between two
|
|
552
|
+
* identical states and looks exactly as it did before. And it preserves the DX
|
|
553
|
+
* the keyframes had — `.drawer--right` animated without asking the author for a
|
|
554
|
+
* driver class, and it still does; it just states its start as
|
|
555
|
+
* `--translate-x-from: 100%` instead of owning a keyframe.
|
|
556
|
+
*
|
|
557
|
+
* Zero specificity means any pattern that wants different motion simply
|
|
558
|
+
* declares it. */
|
|
559
|
+
:where([popover], dialog) {
|
|
560
|
+
opacity: var(--t-opacity, var(--opacity-from, 1));
|
|
561
|
+
translate: var(--t-translate-x, var(--translate-x-from, 0))
|
|
562
|
+
var(--t-translate-y, var(--translate-y-from, 0));
|
|
563
|
+
scale: var(--t-scale-x, var(--scale-x-from, 1)) var(--t-scale-y, var(--scale-y-from, 1));
|
|
564
|
+
rotate: var(--t-rotate, var(--rotate-from, 0deg));
|
|
565
|
+
clip-path: var(--t-clip, var(--clip-from, none));
|
|
566
|
+
|
|
567
|
+
/* `display` and `overlay` are discrete, and BOTH must transition or the
|
|
568
|
+
element is yanked out of the top layer the instant it closes — you get an
|
|
569
|
+
entry animation and no exit, which is exactly the asymmetry drawer.css had.
|
|
570
|
+
`allow-discrete` is what keeps it rendered for the duration. */
|
|
571
|
+
transition-property: opacity, translate, scale, rotate, clip-path, display, overlay;
|
|
572
|
+
transition-duration: var(--animation-duration);
|
|
573
|
+
transition-timing-function: var(--custom-ease-out);
|
|
574
|
+
transition-behavior: allow-discrete;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* The open flip. Mirrors what the generated `open-<fx>` variants do, so the
|
|
578
|
+
common case needs no effect class at all; an explicit `open-<fx>` still wins
|
|
579
|
+
on specificity and can pick a different effect. */
|
|
580
|
+
:where([popover]:popover-open, dialog[open]) {
|
|
581
|
+
--t-opacity: var(--opacity-to, 1);
|
|
582
|
+
--t-translate-x: var(--translate-x-to, 0);
|
|
583
|
+
--t-translate-y: var(--translate-y-to, 0);
|
|
584
|
+
--t-scale-x: var(--scale-x-to, 1);
|
|
585
|
+
--t-scale-y: var(--scale-y-to, 1);
|
|
586
|
+
--t-rotate: var(--rotate-to, 0deg);
|
|
587
|
+
--t-clip: var(--clip-to, none);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* The entry half. A closed popover is `display: none`, so it has no
|
|
591
|
+
before-change style and the open transition would simply not run —
|
|
592
|
+
@starting-style supplies one.
|
|
593
|
+
*
|
|
594
|
+
* It declares the PROPERTIES rather than resetting the `--t-*` custom
|
|
595
|
+
* properties, which sidesteps a specificity trap: the generated
|
|
596
|
+
* `.open-<fx>:popover-open` rules are (0,2,0), set `--t-*`, and are imported
|
|
597
|
+
* after this file, so a custom-property reset here would have to outrank them.
|
|
598
|
+
* Setting `opacity`/`translate`/… directly at (0,2,0) instead competes only with
|
|
599
|
+
* the (0,0,0) base rule above, which it beats regardless of what any effect
|
|
600
|
+
* class does. */
|
|
601
|
+
@starting-style {
|
|
602
|
+
:is([popover], dialog):is(:popover-open, [open]) {
|
|
603
|
+
opacity: var(--opacity-from, 1);
|
|
604
|
+
translate: var(--translate-x-from, 0) var(--translate-y-from, 0);
|
|
605
|
+
scale: var(--scale-x-from, 1) var(--scale-y-from, 1);
|
|
606
|
+
rotate: var(--rotate-from, 0deg);
|
|
607
|
+
clip-path: var(--clip-from, none);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
532
611
|
/* Respect reduced-motion: drop keyframes, transitions, and continuous floats so
|
|
533
612
|
elements settle at their natural resolved state. Plain selectors + !important
|
|
534
613
|
so this reliably overrides the driver/float rules (a legitimate a11y override). */
|
|
@@ -543,6 +622,17 @@
|
|
|
543
622
|
.transition {
|
|
544
623
|
transition: none !important;
|
|
545
624
|
}
|
|
625
|
+
/* The top-layer driver is applied by default rather than by class, so it needs
|
|
626
|
+
naming here explicitly — `.transition` above does not cover it. `display`
|
|
627
|
+
and `overlay` must still change, they just must not be animated, and
|
|
628
|
+
`transition: none` is exactly that. */
|
|
629
|
+
[popover],
|
|
630
|
+
dialog {
|
|
631
|
+
transition: none !important;
|
|
632
|
+
}
|
|
633
|
+
:where([popover], dialog)::backdrop {
|
|
634
|
+
transition: none !important;
|
|
635
|
+
}
|
|
546
636
|
}
|
|
547
637
|
|
|
548
638
|
/* ===========================================
|
package/assets/css/global.css
CHANGED
|
@@ -32,6 +32,16 @@
|
|
|
32
32
|
around them. */
|
|
33
33
|
body {
|
|
34
34
|
margin: 0;
|
|
35
|
+
|
|
36
|
+
/* Long unbreakable strings are the single most common source of horizontal
|
|
37
|
+
page scroll, and prose is full of them — URLs, file paths, CSS selectors.
|
|
38
|
+
`break-word` rather than `anywhere` on purpose: it only takes effect when a
|
|
39
|
+
word would otherwise overflow, and it does NOT contribute to min-content
|
|
40
|
+
sizing, so no existing layout's intrinsic measurements move. (`anywhere`
|
|
41
|
+
does affect min-content, which would silently resize every intrinsically
|
|
42
|
+
sized box in a consumer's site.) Inline <code> gets the stronger `anywhere`
|
|
43
|
+
in patterns/code.css, where a break mid-token is the correct trade. */
|
|
44
|
+
overflow-wrap: break-word;
|
|
35
45
|
}
|
|
36
46
|
|
|
37
47
|
@media (prefers-reduced-motion: no-preference) {
|
package/assets/css/index.css
CHANGED
|
@@ -33,7 +33,12 @@
|
|
|
33
33
|
@import './patterns/tooltip.css';
|
|
34
34
|
@import './patterns/dropdown.css';
|
|
35
35
|
@import './patterns/split-link.css';
|
|
36
|
+
/* navbar before sitenav: sitenav's wide state composes it. */
|
|
37
|
+
@import './patterns/navbar.css';
|
|
36
38
|
@import './patterns/sitenav.css';
|
|
39
|
+
/* After sitenav (the nav family stays contiguous) and after drawer.css, whose
|
|
40
|
+
panel surface navshell's desktop block has to undo. */
|
|
41
|
+
@import './patterns/navshell.css';
|
|
37
42
|
@import './patterns/notification.css';
|
|
38
43
|
@import './patterns/lightbox.css';
|
|
39
44
|
@import './patterns/overlay.css';
|