@getvitops/generator 5.0.0 → 7.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 +363 -0
- package/assets/bricks/elements/carousel.php +55 -9
- package/assets/css/animation.css +9 -0
- package/assets/css/global.css +24 -0
- package/assets/css/index.css +2 -0
- package/assets/css/patterns/carousel.css +602 -179
- package/assets/css/patterns/counter.css +50 -0
- package/assets/css/patterns/forms.css +1 -1
- package/assets/css/patterns/gallery.css +60 -0
- package/assets/css/patterns/lightbox.css +22 -41
- package/assets/css/patterns/list.css +1 -1
- package/assets/css/patterns/tag.css +1 -2
- package/assets/css/patterns/tree.css +111 -8
- package/assets/css/utilities.css +17 -0
- package/assets/js/elements.js +7 -844
- package/assets/js/polyfills/invokers-polyfill.js +1 -0
- package/assets/js/polyfills/template-shadowroot.js +1 -14
- package/assets/js/polyfills.js +1 -1
- package/config.schema.json +100 -1
- package/dist/index.d.mts +63 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +108 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,368 @@
|
|
|
1
1
|
# @getvitops/generator
|
|
2
2
|
|
|
3
|
+
## 7.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- aad43b7: A gallery/lightbox that is a fully working modal lightbox with **zero JavaScript**, plus
|
|
8
|
+
`ImageMetadata` support in `<Carousel />`.
|
|
9
|
+
|
|
10
|
+
Only `@getvitops/core`, `generator` and `astro` change here. This changeset makes **no
|
|
11
|
+
consumer-facing change** to `utils`, `cli` or `vite` — they still ship in this release because
|
|
12
|
+
the six share one version, but from a different changeset (`localbusiness-schema.md`) that
|
|
13
|
+
touches `utils` and `generator` for an unrelated reason.
|
|
14
|
+
|
|
15
|
+
**Breaking — `css`/`bricks`/`tailwind` (all formats):** the `.lightbox` thumbnail grid is now
|
|
16
|
+
`.gallery`, so it composes with the dialog it opens (`.lightbox-dialog`, unchanged) rather than
|
|
17
|
+
sharing its name. `vitops lint --fix` cannot cover this: `movedTokens()` renames colour token
|
|
18
|
+
names only, and there is no class-rename mechanism in `@getvitops/cli`. Migrate by hand:
|
|
19
|
+
|
|
20
|
+
| Old | New |
|
|
21
|
+
| ------------------ | ----------------- |
|
|
22
|
+
| `.lightbox` | `.gallery` |
|
|
23
|
+
| `.lightbox__item` | `.gallery__item` |
|
|
24
|
+
| `.lightbox__thumb` | `.gallery__thumb` |
|
|
25
|
+
|
|
26
|
+
`.lightbox-dialog` and its `__content` / `__image` / `__close` / `__nav` / `__nav-button` /
|
|
27
|
+
`__caption` parts are unchanged.
|
|
28
|
+
|
|
29
|
+
**Added — `css`/`bricks`/`tailwind` (all formats):** `patterns/gallery.css` — the `.gallery` grid,
|
|
30
|
+
now on the token cascade (`--br-gallery` etc.) it only half-had before.
|
|
31
|
+
|
|
32
|
+
**Added — `wc`:** `<wc-gallery>` (`@getvitops/core/elements`). Wraps a `.gallery` grid of
|
|
33
|
+
`command="show-modal"` triggers and the `.lightbox-dialog`s they open. With no JS, each trigger is
|
|
34
|
+
a real Invoker Commands button for its own dialog — open and close both work. `<wc-gallery>` adds
|
|
35
|
+
what the fallback deliberately cannot contain: prev/next, arrow keys, swipe (horizontal to step,
|
|
36
|
+
vertical to dismiss), an announced image counter, neighbour preload, and a thumbnail → full-image
|
|
37
|
+
`document.startViewTransition` morph where supported. Prev/next can't exist in the fallback — a
|
|
38
|
+
second `show-modal` invoker inside an already-open dialog stacks a second modal rather than
|
|
39
|
+
replacing the first — so it is generated by the element, never authored, the same rule
|
|
40
|
+
`<wc-tree>`'s search field follows.
|
|
41
|
+
|
|
42
|
+
**Added — `astro`:** `<Gallery />` (`@getvitops/astro/components/Gallery.astro`) — emits a
|
|
43
|
+
`.gallery` grid plus one `.lightbox-dialog` per image and its own `<wc-gallery>`; do not wrap it in
|
|
44
|
+
one. Images take `string | ImageMetadata`, rendered through a new internal `<ResponsiveImage />`
|
|
45
|
+
helper: a plain string renders the same raw `<img>` every component here used before, unchanged;
|
|
46
|
+
an `astro:assets` import renders through `<Picture />` for AVIF/WebP derivatives.
|
|
47
|
+
|
|
48
|
+
**Changed — `astro`:** `<Carousel />`'s `CarouselSlide.src` now also accepts `ImageMetadata`,
|
|
49
|
+
through the same `<ResponsiveImage />` helper, plus a new `formats` prop. Every existing
|
|
50
|
+
string-`src` call site renders byte-identical markup — purely additive.
|
|
51
|
+
|
|
52
|
+
**Added — `wc`:** the Invoker Commands API (`<button command commandfor>`) polyfill
|
|
53
|
+
(`invokers-polyfill`, feature-detected via `@getvitops/core/polyfills`) — resolves the TODO
|
|
54
|
+
`polyfills.ts` carried since 4.0. `<wc-gallery>`'s fallback and `<Drawer />` (which already emitted
|
|
55
|
+
`command="show-modal"` unconditionally) both now get real cross-browser coverage rather than
|
|
56
|
+
depending on it being "too new to rely on yet." Fetched only in an engine that doesn't support the
|
|
57
|
+
API natively, so a current browser downloads none of it.
|
|
58
|
+
|
|
59
|
+
**Migration:** rename `.lightbox` → `.gallery` and `.lightbox__item`/`.lightbox__thumb` →
|
|
60
|
+
`.gallery__item`/`.gallery__thumb` wherever authored (see table above); everything else is
|
|
61
|
+
additive. Consumers using the CSS pattern with no JS need no other change — the fallback markup is
|
|
62
|
+
unchanged in shape, only the class names moved.
|
|
63
|
+
|
|
64
|
+
- eb9ac79: `<wc-tree>` gains WAI-ARIA tree semantics and roving-tabindex keyboard navigation, and the
|
|
65
|
+
keyboard-navigation code behind it lands as shared utilities the next roving-tabindex component
|
|
66
|
+
(Dropdown, Tabs, Combobox) can reuse.
|
|
67
|
+
|
|
68
|
+
**Breaking — `wc` (`@getvitops/core`).** On upgrade, `<wc-tree>` now unwraps every branch's
|
|
69
|
+
`<details>`/`<summary>` into a plain, JS-owned structure (`role="tree"` on the root,
|
|
70
|
+
`role="treeitem"` on every item, `role="group"` on every nested list, a roving `tabindex`, and
|
|
71
|
+
`aria-expanded` mirroring expand state). This is a deliberate, named exception to the framework's
|
|
72
|
+
normal "parse the fallback and augment it in place" rule — the alternative, an ARIA-attribute
|
|
73
|
+
overlay left on top of the native `<details>`/`<summary>` structure, was tried first and rejected
|
|
74
|
+
because `<summary>` stays focusable regardless, which leaves a permanent duplicate `role="button"`
|
|
75
|
+
node inside every branch. The no-JS fallback is completely unaffected: it is still native nested
|
|
76
|
+
`<details>`, exactly as `<Tree />` has always rendered it, and `enhance={false}` still gets the
|
|
77
|
+
bare fragment with no `<wc-tree>` at all.
|
|
78
|
+
|
|
79
|
+
Two concrete things break for a consumer that reached into the enhanced DOM directly:
|
|
80
|
+
- A script holding a reference to the original `<details>`/`<summary>` nodes — including one
|
|
81
|
+
captured via `getElementById` before upgrade, since the flat markup shape's `<details>` carries
|
|
82
|
+
the item's `id` — loses that reference once JS runs. `tree-toggle` (mirroring the existing
|
|
83
|
+
`tree-filter` custom event) is the replacement surface for reacting to expand/collapse.
|
|
84
|
+
- `<wc-tree>` becomes a single tab stop. Tabbing through every row in a large tree no longer
|
|
85
|
+
works; arrow keys replace it (Up/Down between visible nodes, Right/Left to open/close a branch or
|
|
86
|
+
step in/out, Home/End, type-ahead), matching the WAI-ARIA tree pattern. Left/Right flip under
|
|
87
|
+
`direction: rtl`.
|
|
88
|
+
|
|
89
|
+
**Fixed — `wc` (`@getvitops/core`).** `<wc-carousel>`'s dot-nav arrow keys now follow writing
|
|
90
|
+
direction. In an RTL document, `ArrowLeft` moves the roving tabindex to the visually-left dot and
|
|
91
|
+
`ArrowRight` to the visually-right one — previously both were index-based and moved the focus ring
|
|
92
|
+
against the direction the dots are actually drawn in. `ArrowUp`/`ArrowDown` are unchanged and never
|
|
93
|
+
flip (`direction` is a horizontal-axis property). The prev/next buttons are unchanged too — they
|
|
94
|
+
still step to the previous/next slide in both directions, and only their glyph flips. Also fixed:
|
|
95
|
+
two arrow presses faster than the dot nav's smooth scroll can settle now reliably advance two dots
|
|
96
|
+
instead of sometimes landing on the same one twice.
|
|
97
|
+
|
|
98
|
+
**Changed — `css`/`bricks`/`tailwind` (all formats).** `patterns/tree.css` gains a `.tree__summary`
|
|
99
|
+
row class (the enhanced-state replacement for `<summary>`), a hand-rolled expand/collapse animation
|
|
100
|
+
replacing the native `<details>` one that no longer applies post-upgrade, and a focus ring scoped to
|
|
101
|
+
the row rather than the whole item (the roving tabindex now lands on `.tree__item`, whose box wraps
|
|
102
|
+
its entire subtree once expanded). Visually equivalent to before; no consumer class rename needed.
|
|
103
|
+
|
|
104
|
+
**Added — `wc` (`@getvitops/core`, internal).** `web-components/utils/keynav.ts` (generic
|
|
105
|
+
key-decoding + type-ahead primitives) and `utils/tree-nav.ts` (tree-specific navigation decisions)
|
|
106
|
+
are new pure modules, and `utils/RovingTabindex.ts` is a new shared `ReactiveController` — modelled
|
|
107
|
+
on the existing `DragController` — that owns roving-tabindex bookkeeping for any keyboard-navigable
|
|
108
|
+
group. `<wc-carousel>`'s dot nav now runs on it too, and `<wc-gallery>` reuses `keynav.ts`'s
|
|
109
|
+
`stepIndex`. None of the three are in `@getvitops/core`'s public `exports` map. Only
|
|
110
|
+
`RovingTabindex` is re-exported from `web-components/index.ts`, the same way `DragController`
|
|
111
|
+
already is, not as new published API; `keynav.ts` and `tree-nav.ts` stay internal modules imported
|
|
112
|
+
directly by path (as `RovingTabindex.ts` and `gallery.ts` already do) since neither is consumed
|
|
113
|
+
outside the components that already import them directly.
|
|
114
|
+
|
|
115
|
+
**This changeset makes no consumer-facing change in `@getvitops/generator` beyond documentation
|
|
116
|
+
output.** `tiers.ts`'s `tree` entry gains `tree__summary` to its class list and describes the new
|
|
117
|
+
keyboard navigation and ARIA semantics — this changes what `vitops docs components` /
|
|
118
|
+
`concepts/components.md` render for the `tree` pattern, nothing else. `generator`'s real change in
|
|
119
|
+
this release is unrelated to `wc-tree` — see `localbusiness-schema.md`.
|
|
120
|
+
|
|
121
|
+
### Minor Changes
|
|
122
|
+
|
|
123
|
+
- c0c092b: `vitops search` now works from a `gcloud` login, and attributes API usage per site.
|
|
124
|
+
|
|
125
|
+
**Being logged in is enough.** With no `VITOPS_GOOGLE_*` set, an Application Default Credentials
|
|
126
|
+
login is used — the credential `gcloud auth application-default login` already wrote. It needs the
|
|
127
|
+
Search Console scopes, which are not in the default ADC set:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
gcloud auth application-default login \
|
|
131
|
+
--scopes=openid,https://www.googleapis.com/auth/siteverification,\
|
|
132
|
+
https://www.googleapis.com/auth/webmasters,https://www.googleapis.com/auth/cloud-platform
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Explicit `VITOPS_GOOGLE_*` vars still win. Ambient credentials are only a fallback, because a stale
|
|
136
|
+
local login silently overriding a deliberate CI secret is the worst available precedence.
|
|
137
|
+
|
|
138
|
+
Beyond convenience, this removes a documented footgun: an OAuth client you create yourself sits in
|
|
139
|
+
_Testing_ publishing status, where Google **expires the refresh token after 7 days**. The Cloud SDK
|
|
140
|
+
client is published, so an ADC credential doesn't rot between onboarding runs.
|
|
141
|
+
|
|
142
|
+
**New: `site.google.project`** — the Google Cloud project API usage is attributed to, sent as
|
|
143
|
+
`x-goog-user-project`. One project per site is what keeps each site's usage and billing separate,
|
|
144
|
+
and it is the same field Maps or anything else will read later, rather than a `quotaProject` here
|
|
145
|
+
and a `mapsProject` there.
|
|
146
|
+
|
|
147
|
+
It is **required for a user credential and wrong for a service account**, which is why it is not
|
|
148
|
+
sent unconditionally. A user credential authenticates through a shared OAuth client that owns no
|
|
149
|
+
project, so Google refuses the call outright — measured: `403 "requires a quota project, which is
|
|
150
|
+
not set by default"`. A service account already belongs to a project, and pointing it at a
|
|
151
|
+
different one would newly require `serviceusage.services.use` there, turning a working CI
|
|
152
|
+
credential into a 403 for no benefit.
|
|
153
|
+
|
|
154
|
+
Using it needs both APIs (`searchconsole.googleapis.com`, `siteverification.googleapis.com`)
|
|
155
|
+
enabled on that project, and `serviceusage.services.use` for the identity — one grant per site,
|
|
156
|
+
which suits an agency administering many sites from one admin identity.
|
|
157
|
+
|
|
158
|
+
An ADC credential with no `site.google.project` is now **refused before any request is made**,
|
|
159
|
+
naming the file the credential came from and the project gcloud recorded with it:
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
✖ this Google credential comes from ~/.config/gcloud/application_default_credentials.json,
|
|
163
|
+
which authenticates through a shared OAuth client that owns no project — so it needs
|
|
164
|
+
"site.google.project" in site.json to say which project the API usage belongs to.
|
|
165
|
+
gcloud recorded "acme-web" as the quota project for that login, so that is probably the value.
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
That is the mistake waiting for the _second_ site: the command gets copied from whatever
|
|
169
|
+
onboarded the first one, the field is left out, and Google's own answer names neither the config
|
|
170
|
+
field nor the credential.
|
|
171
|
+
|
|
172
|
+
**Fixed: an ADC file in `GOOGLE_APPLICATION_CREDENTIALS` no longer hard-exits.** That variable is
|
|
173
|
+
Google's own convention _and_ where gcloud writes ADC, so the same variable carries two kinds of
|
|
174
|
+
credential. Parsing an `authorized_user` file as a service account failed with `service account
|
|
175
|
+
JSON is missing client_email or private_key` — while holding a credential the command already knew
|
|
176
|
+
how to use. It is now discriminated on `type`, the field Google's own libraries switch on.
|
|
177
|
+
|
|
178
|
+
**Also fixed — `search setup --dry` and `--check` are not offline.** The docs implied otherwise. The
|
|
179
|
+
state gather runs before the planner, so both read from Cloudflare and Google and both need
|
|
180
|
+
credentials. They still create and change nothing; `notify --dry` remains genuinely request-free.
|
|
181
|
+
|
|
182
|
+
New in `@getvitops/utils/indexing`: `parseAdcUser`, `adcQuotaProject`, `adcCredentialsPath` (pure,
|
|
183
|
+
so what is decidable is asserted without a filesystem), plus `googleHeaders` and the `GoogleAuth` /
|
|
184
|
+
`GoogleAuthLike` types. The seven exported Google request functions now take a token **or** a
|
|
185
|
+
`{ token, quotaProject }` — a bare string still works everywhere, so nothing needs changing.
|
|
186
|
+
|
|
187
|
+
- 2b50f9e: Extract the LocalBusiness JSON-LD builder out of `<LocalBusiness />` into a reusable
|
|
188
|
+
`localBusinessGraph()`, and add the location fields listing platforms (GBP, Bing Places, Apple
|
|
189
|
+
Business Connect) actually need.
|
|
190
|
+
|
|
191
|
+
**Added — `@getvitops/utils`.** `localBusinessGraph(options)` (+ its `LocalBusinessGraphOptions`,
|
|
192
|
+
`OpeningHoursSpecification` and `SpecialHoursSpecification` types) is now exported from
|
|
193
|
+
`@getvitops/utils`, alongside the existing `organizationGraph`/`articleGraph`/`breadcrumbGraph`/
|
|
194
|
+
`faqGraph` builders — same module, same shape, usable anywhere a JSON-LD graph is built outside an
|
|
195
|
+
Astro component.
|
|
196
|
+
|
|
197
|
+
**Added — `authoring`/`config` (`@getvitops/generator`).** Four new `organization.locations.<slug>`
|
|
198
|
+
fields: `hoursSpecial` (dated deviations from the recurring `hours` — holiday hours, a one-off
|
|
199
|
+
closure), `photos` (`ImageRefSchema[]` → JSON-LD `image`), `sameAs` (this location's own listing
|
|
200
|
+
URLs, distinct from `organization.sameAs`, which is the company overall), and `listings` (external
|
|
201
|
+
listing ids keyed by platform — `google` | `bing` | `apple` — not consumed by the generator today;
|
|
202
|
+
recorded so a future listings-sync command has a stable id to match against).
|
|
203
|
+
|
|
204
|
+
**Changed — `astro`.** `<LocalBusiness />`'s `Props` type is now `LocalBusinessGraphOptions`
|
|
205
|
+
(re-exported, not redefined) rather than a local interface that had drifted from what the builder
|
|
206
|
+
actually accepted. No markup or prop-name change for an existing consumer.
|
|
207
|
+
|
|
208
|
+
- a6a8b39: `radii.pill` / `--br-pill` is gone. `999px` is a shape, not a design decision, so it no longer
|
|
209
|
+
has a config-editable token of its own — it's now the `rounded-full` utility, named and valued
|
|
210
|
+
to match Tailwind's own class, alongside a new `rounded-none`.
|
|
211
|
+
|
|
212
|
+
**Breaking — `css`/`bricks` only** (the tailwind format never emitted `--br-pill`; Tailwind
|
|
213
|
+
already ships `rounded-full`/`rounded-none` natively and always has). A consumer who overrode
|
|
214
|
+
`--br-pill` directly, or set `radii.pill` in their own `design-system.json` expecting it to
|
|
215
|
+
reshape the switch track, the facet-list count or the badge-indicator bubble, has to migrate:
|
|
216
|
+
- The switch track, facet count and badge indicator each already had their own consumer hook
|
|
217
|
+
(`--br-switch-track`, `--br-count`, `--br-badge-indicator`) and now fall back straight to the
|
|
218
|
+
literal `999px` instead of chaining through `--br-pill`. Override the specific hook instead of
|
|
219
|
+
the removed shared one.
|
|
220
|
+
- `.badge` is unaffected — it already resolved to `999px` and still does, now via its own
|
|
221
|
+
override (`patterns.items.badge.overrides.br`) rather than a shared primitive.
|
|
222
|
+
- Anything that wants a fully round corner outside those three patterns should reach for
|
|
223
|
+
`class="rounded-full"` (or `rounded-none` to zero one out) rather than a `--br-*` variable.
|
|
224
|
+
|
|
225
|
+
This is **not** reachable by `vitops lint --fix` — its token-rename table is built from colour
|
|
226
|
+
role names, and there is no equivalent static table for a shape primitive going away — so this
|
|
227
|
+
entry is the migration.
|
|
228
|
+
|
|
229
|
+
`radii.circle` / `--br-circle` (50%) is untouched: `status`, the radio and the switch thumb all
|
|
230
|
+
depend on it, and Tailwind has no equivalent to defer to.
|
|
231
|
+
|
|
232
|
+
- 7b391b3: Add `<wc-counter>` — animates a number from a start value to the value already in its fallback
|
|
233
|
+
text, on intersection. The stat/percentage figure in a media tile ("0 → 94%"), a KPI row, a
|
|
234
|
+
metrics band.
|
|
235
|
+
|
|
236
|
+
No consumer-facing change in this release outside `core`, `generator` and `astro` — `utils`,
|
|
237
|
+
`cli` and `vite` still ship in this release only because the six share one version.
|
|
238
|
+
|
|
239
|
+
**Added — `css`/`bricks`/`tailwind` (all formats):** `.counter` / `.counter__value` /
|
|
240
|
+
`.counter__presentation` (`patterns/counter.css`). A registered `--_n` custom property drives the
|
|
241
|
+
count via a plain CSS `@keyframes` animation — the interpolation and the easing curve are CSS's,
|
|
242
|
+
never duplicated in JS.
|
|
243
|
+
|
|
244
|
+
**Added — `wc` (`@getvitops/core`).** `<wc-counter>` parses the final value out of its own
|
|
245
|
+
`.counter__value` fallback text — never from a separate attribute, so the no-JS reading and the
|
|
246
|
+
animated reading can't disagree — and renders it back through `Intl.NumberFormat`, seeded from the
|
|
247
|
+
fallback text's own separators (a grouped `1,284` never animates through ungrouped intermediates).
|
|
248
|
+
`counter()` cannot do that part: no decimals, no locale grouping, which is the one thing here that
|
|
249
|
+
genuinely needs JavaScript.
|
|
250
|
+
- Triggers on intersection via a single shared `IntersectionObserver`, not on upgrade — a counter
|
|
251
|
+
below the fold that finished before the visitor scrolled to it would have done nothing.
|
|
252
|
+
- `prefers-reduced-motion: reduce` means don't animate at all, checked before the observer is even
|
|
253
|
+
created, with `patterns/counter.css`'s own reduced-motion query as a second belt.
|
|
254
|
+
- The accessible name stays the final value for the whole animation: `.counter__value` is toggled
|
|
255
|
+
to the framework's `.sr-only` utility while running, never hidden — `display: none`/`visibility:
|
|
256
|
+
hidden` would pull it out of the accessible-name computation along with the visual hiding, and a
|
|
257
|
+
screen reader must never be read ~60 intermediate numbers. The animated text lives in a separate
|
|
258
|
+
`aria-hidden` presentation span it never reaches.
|
|
259
|
+
- `data-from` (default `0`), `data-duration` (ms, default `1200`), `data-easing` (`linear` |
|
|
260
|
+
`ease-in` | `ease-out` | `float-sine` | `float-bounce` — maps onto the real
|
|
261
|
+
`--custom-ease-*`/`--ease-float-*` tokens, so a curve edited in `animation.css` cannot drift out
|
|
262
|
+
of step with this element), `data-decimals` (inferred from the fallback text when absent).
|
|
263
|
+
- Never leaves an intermediate value on screen as the resting state: disconnecting mid-animation
|
|
264
|
+
restores the fallback immediately, and it was never mutated in the first place — only the
|
|
265
|
+
presentation span was ever written to.
|
|
266
|
+
|
|
267
|
+
**Added — `astro`.** `<Counter value="94%" />` emits its own `<wc-counter>` — do NOT wrap it in
|
|
268
|
+
one, same rule as `Gallery`/`Carousel`/`Tree`. `value` is the only source of the final figure;
|
|
269
|
+
there is no separate `to` prop, for the same one-source-of-truth reason the element itself parses
|
|
270
|
+
its fallback rather than taking a duplicate attribute. `enhance={false}` emits the bare fallback
|
|
271
|
+
for a page that cannot run `elements.js`.
|
|
272
|
+
|
|
273
|
+
### Patch Changes
|
|
274
|
+
|
|
275
|
+
- **Added — `utils`.** `itemListGraph()`, a pure schema.org `ItemList` JSON-LD builder — a sibling
|
|
276
|
+
of `breadcrumbGraph()`/`localBusinessGraph()`. Extracted from `@getvitops/astro`'s `<Carousel />`
|
|
277
|
+
so any consumer can build a valid `ItemList` (Google's "all-in-one page" carousel format:
|
|
278
|
+
`ListItem.item` carrying `@type`/`name`/`url`) for content that isn't one of the six Google
|
|
279
|
+
carousel rich-result types (`Article`/`Recipe`/`Movie`/`Course`/`Restaurant`/`Product`) — the
|
|
280
|
+
entity type is no longer constrained to that set.
|
|
281
|
+
|
|
282
|
+
**Changed — `astro`.** `<Carousel />`'s `CarouselItem['type']` now accepts any string, not just
|
|
283
|
+
the six carousel rich-result types — non-breaking, the union only widens. It's a thin wrapper
|
|
284
|
+
over `itemListGraph()` now; behaviour for existing callers is unchanged.
|
|
285
|
+
|
|
286
|
+
No consumer-facing change in this release outside `utils` and `astro` — `generator`, `cli` and
|
|
287
|
+
`vite` still ship in this release only because the six share one version.
|
|
288
|
+
|
|
289
|
+
**Fixed — `core` (`css`/`bricks`/`tailwind` build output, all formats).** The CSS and HTML
|
|
290
|
+
authored inside Lit's `css`/`html` tagged templates in `<wc-*>` component sources previously
|
|
291
|
+
survived JS minification verbatim — a JS minifier treats a template literal's cooked text as
|
|
292
|
+
opaque, so `elements.js` shipped ~690 lines of indented, unminified CSS (and the equivalent in
|
|
293
|
+
HTML) inside an otherwise-minified 886-line file. Two source-level build transforms now collapse
|
|
294
|
+
both before bundling: `postcss` + `postcss-lit` + `cssnano` for `css` templates, `minify-html-literals`
|
|
295
|
+
(`conservativeCollapse: true`, so whitespace between inline elements in light-DOM components never
|
|
296
|
+
collapses to zero) for `html` templates. `elements.js` drops from 886 lines / ~101 KB to 49 lines /
|
|
297
|
+
~96 KB. A second build step deduplicates the 17 `@license` comment blocks (only 6 are textually
|
|
298
|
+
distinct) down to one verbatim copy of each — required by BSD-3/MIT/Apache-2.0's notice-retention
|
|
299
|
+
terms either way, just no longer repeated once per source file that carries it. No API change;
|
|
300
|
+
build-time only, and none of the added tooling (`postcss`, `postcss-lit`, `cssnano`,
|
|
301
|
+
`minify-html-literals`) is a runtime or published dependency.
|
|
302
|
+
|
|
303
|
+
- Updated dependencies [c0c092b]
|
|
304
|
+
- Updated dependencies
|
|
305
|
+
- Updated dependencies [2b50f9e]
|
|
306
|
+
- @getvitops/utils@7.0.0
|
|
307
|
+
|
|
308
|
+
## 6.0.0
|
|
309
|
+
|
|
310
|
+
### Major Changes
|
|
311
|
+
|
|
312
|
+
- Carousel rework: a scroll strip that is operable and discoverable with no JS in every engine, and
|
|
313
|
+
real controls where the scroll-marker pseudo-elements are missing.
|
|
314
|
+
|
|
315
|
+
`::scroll-button()`, `::scroll-marker` and `::scroll-marker-group` are still Chromium-only, and
|
|
316
|
+
there is no usable polyfill (the one prototype targets the superseded syntax and only re-parses
|
|
317
|
+
inline `<style>` elements). So the carousel no longer assumes them: `<wc-carousel>` builds real
|
|
318
|
+
prev/next `<button>`s and a real dot nav where they are absent, styled from the same declarations
|
|
319
|
+
as the native ones. Which branch is live is decided **by the stylesheet** — one `@supports` sets
|
|
320
|
+
`--carousel-native-nav: 1` and the element reads it back — so the condition is written once and
|
|
321
|
+
the two cannot disagree.
|
|
322
|
+
|
|
323
|
+
**Breaking — `.carousel` is now a shell and `.carousel__track` is the scroller** (all formats). The
|
|
324
|
+
hint and the controls need a home outside the scrollport, and absolute positioning against the
|
|
325
|
+
shell replaces `position: fixed` + `anchor-name`/`position-area`, which pinned controls to a
|
|
326
|
+
viewport corner in any engine without anchor positioning. The 5.x single-element form is still
|
|
327
|
+
styled via `:not(:has(> .carousel__track))` and is promoted by the element at runtime, but it is
|
|
328
|
+
deprecated: wrap your slides in `<ul class="carousel__track">`.
|
|
329
|
+
|
|
330
|
+
**Breaking — looping is opt-in.** `<wc-carousel loop>` clones the slides; the default no longer
|
|
331
|
+
does. Cloning triples the markup, duplicates every image element and makes the scrollbar report 3×
|
|
332
|
+
the real content. `autoplay` implies `loop`. Migration: add `loop`.
|
|
333
|
+
|
|
334
|
+
**Breaking — `[part='autoplay']` is now `.carousel__autoplay`** (aliased for one release; `part`
|
|
335
|
+
only crosses a shadow boundary and this element is light DOM, so it was never a part). The button
|
|
336
|
+
is also a child of the shell rather than the track, where it used to occupy a slide-width column.
|
|
337
|
+
|
|
338
|
+
**Breaking — the host role is `group`, not `region`.** `region` is a landmark, so every carousel
|
|
339
|
+
grew an entry in the landmark list. Pass `landmark` to `<Carousel />` where it really is one.
|
|
340
|
+
|
|
341
|
+
**Changed (visual)** — the scrollbar is visible by default (`scrollbar-width: thin`, was `none`)
|
|
342
|
+
and a "Scroll for more" hint renders above the strip; both dim once the visitor scrolls, via a
|
|
343
|
+
scroll-progress timeline where available and a `data-scrolled` attribute otherwise. Opt out with
|
|
344
|
+
`.carousel--no-scrollbar` and `hint={false}`. `@getvitops/core`'s `global.css` also gains a narrow
|
|
345
|
+
media reset (`max-inline-size: 100%` on replaced elements, `block-size: auto` on `img`/`video`) —
|
|
346
|
+
deliberately without `display: block`, which would change inline images in prose.
|
|
347
|
+
|
|
348
|
+
**Added** — `@getvitops/astro/components/Carousel.astro`, a tier-3 wrapper emitting semantic
|
|
349
|
+
`<ul>`/`<li>`/`<figure>` markup with the right per-slide image priorities: the first slide eager
|
|
350
|
+
and high (the LCP candidate), the rest `lazy`/`low`/`async`. `loading="lazy"` is honoured for
|
|
351
|
+
images clipped by a horizontal scroll container, so off-screen slides defer with no JavaScript at
|
|
352
|
+
all. Also new: `carousel--markers-below` and `carousel--no-scrollbar`, and
|
|
353
|
+
`--carousel-slide-aspect`, which keeps slide heights equal whatever each image's aspect ratio is.
|
|
354
|
+
|
|
355
|
+
**Fixed** — `::scroll-button()` glyphs sat off-centre in their circles (`global.css`'s `*` reset
|
|
356
|
+
does not reach a pseudo-element, so the button was `content-box` with the UA's `padding: 1px 6px`
|
|
357
|
+
and `inline-size` + `aspect-ratio` sized an ellipse); the hover state was a no-op (it set the same
|
|
358
|
+
token as the base rule); slide heights varied with each image's aspect ratio; navigation used
|
|
359
|
+
physical `left`/`right` and so put "previous" on the wrong side in RTL; cloned slides duplicated
|
|
360
|
+
their `id`s; and `scrollBy(clientWidth)` overshot whenever `--carousel-slide-size` was not `100%`.
|
|
361
|
+
|
|
362
|
+
### Patch Changes
|
|
363
|
+
|
|
364
|
+
- @getvitops/utils@6.0.0
|
|
365
|
+
|
|
3
366
|
## 5.0.0
|
|
4
367
|
|
|
5
368
|
### Major Changes
|
|
@@ -2,14 +2,24 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Vitops — Carousel element (Bricks Builder).
|
|
4
4
|
*
|
|
5
|
-
* Renders the <wc-carousel> Lit component (src/web-components/WCCarousel.ts)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Renders the <wc-carousel> Lit component (src/web-components/WCCarousel.ts) around a
|
|
6
|
+
* `.carousel__track` scroll container. Each direct child of the element is a slide.
|
|
7
|
+
*
|
|
8
|
+
* Without JS the `.carousel` classes still yield a working scroll-snap carousel with a
|
|
9
|
+
* visible scrollbar, a "scroll for more" hint and — in Chromium — native prev/next
|
|
10
|
+
* buttons and dot navigation, so the builder canvas stays functional. Where those
|
|
11
|
+
* pseudo-elements are missing (Firefox, older Safari) the component builds real
|
|
12
|
+
* buttons and dots styled to match.
|
|
9
13
|
*
|
|
10
14
|
* The `.carousel` base rides on the built-in "CSS classes" setting (defaulted below) so
|
|
11
15
|
* it applies in the canvas and the frontend. Add modifier classes there:
|
|
12
|
-
* `carousel--scroll-buttons`, `carousel--scroll-markers`, `carousel--auto-pages
|
|
16
|
+
* `carousel--scroll-buttons`, `carousel--scroll-markers`, `carousel--auto-pages`,
|
|
17
|
+
* `carousel--inert`, `carousel--force-stop`, `carousel--no-scrollbar`,
|
|
18
|
+
* `carousel--markers-below`.
|
|
19
|
+
*
|
|
20
|
+
* Note the slide track here is a <div>, not a <ul>: Bricks children are blocks, so the
|
|
21
|
+
* list semantics the Astro component emits are not available on this platform. The CSS
|
|
22
|
+
* targets `> *`, so everything else is identical.
|
|
13
23
|
*
|
|
14
24
|
* Owned by the framework repo (vitops: bricks/elements/); copied into the theme's
|
|
15
25
|
* dist/bricks/ on build — do not hand-edit in the theme.
|
|
@@ -41,7 +51,14 @@ class Vitops_Element_Carousel extends \Bricks\Element {
|
|
|
41
51
|
'label' => esc_html__( 'Autoplay interval (ms)', 'bricks' ),
|
|
42
52
|
'type' => 'number',
|
|
43
53
|
'placeholder' => '0',
|
|
44
|
-
'description' => esc_html__( 'Milliseconds between slides. Leave empty / 0 to disable.', 'bricks' ),
|
|
54
|
+
'description' => esc_html__( 'Milliseconds between slides. Leave empty / 0 to disable. Autoplay implies looping.', 'bricks' ),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
$this->controls['loop'] = array(
|
|
58
|
+
'tab' => 'content',
|
|
59
|
+
'label' => esc_html__( 'Loop', 'bricks' ),
|
|
60
|
+
'type' => 'checkbox',
|
|
61
|
+
'description' => esc_html__( 'Clone the slides at both ends for a seamless infinite strip. Off by default: it triples the markup and duplicates every image.', 'bricks' ),
|
|
45
62
|
);
|
|
46
63
|
|
|
47
64
|
$this->controls['label'] = array(
|
|
@@ -50,14 +67,30 @@ class Vitops_Element_Carousel extends \Bricks\Element {
|
|
|
50
67
|
'type' => 'text',
|
|
51
68
|
);
|
|
52
69
|
|
|
70
|
+
$this->controls['aspect'] = array(
|
|
71
|
+
'tab' => 'content',
|
|
72
|
+
'label' => esc_html__( 'Slide media aspect ratio', 'bricks' ),
|
|
73
|
+
'type' => 'text',
|
|
74
|
+
'placeholder' => '16 / 9',
|
|
75
|
+
'description' => esc_html__( 'Sets --carousel-slide-aspect, the ratio each slide\'s media box takes. Keeps slide heights equal whatever the image.', 'bricks' ),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
$this->controls['hint'] = array(
|
|
79
|
+
'tab' => 'content',
|
|
80
|
+
'label' => esc_html__( 'Scroll hint', 'bricks' ),
|
|
81
|
+
'type' => 'text',
|
|
82
|
+
'placeholder' => 'Scroll for more',
|
|
83
|
+
'description' => esc_html__( 'Shown beside the strip and dimmed once the visitor scrolls. Clear to omit it.', 'bricks' ),
|
|
84
|
+
);
|
|
85
|
+
|
|
53
86
|
$this->controls['modifiersInfo'] = array(
|
|
54
87
|
'tab' => 'content',
|
|
55
88
|
'type' => 'info',
|
|
56
|
-
'content' => esc_html__( 'Add modifier classes in "CSS classes": carousel--scroll-buttons, carousel--scroll-markers, carousel--auto-pages. Each direct child is a slide.', 'bricks' ),
|
|
89
|
+
'content' => esc_html__( 'Add modifier classes in "CSS classes": carousel--scroll-buttons, carousel--scroll-markers, carousel--auto-pages, carousel--inert, carousel--force-stop, carousel--no-scrollbar, carousel--markers-below. Each direct child is a slide.', 'bricks' ),
|
|
57
90
|
);
|
|
58
91
|
|
|
59
92
|
// Base carousel class defaulted onto the built-in "CSS classes" setting.
|
|
60
|
-
$this->controls['_cssClasses']['default'] = 'carousel';
|
|
93
|
+
$this->controls['_cssClasses']['default'] = 'carousel carousel--scroll-buttons carousel--scroll-markers';
|
|
61
94
|
}
|
|
62
95
|
|
|
63
96
|
// Seed three empty slides — the author fills each.
|
|
@@ -72,18 +105,31 @@ class Vitops_Element_Carousel extends \Bricks\Element {
|
|
|
72
105
|
public function render() {
|
|
73
106
|
$s = $this->settings;
|
|
74
107
|
$attrs = array();
|
|
108
|
+
$style = '';
|
|
75
109
|
|
|
76
110
|
if ( isset( $s['autoplay'] ) && '' !== $s['autoplay'] && (int) $s['autoplay'] > 0 ) {
|
|
77
111
|
$attrs[] = 'autoplay="' . esc_attr( $s['autoplay'] ) . '"';
|
|
78
112
|
}
|
|
113
|
+
if ( ! empty( $s['loop'] ) ) {
|
|
114
|
+
$attrs[] = 'loop';
|
|
115
|
+
}
|
|
79
116
|
if ( ! empty( $s['label'] ) ) {
|
|
80
117
|
$attrs[] = 'aria-label="' . esc_attr( $s['label'] ) . '"';
|
|
81
118
|
}
|
|
119
|
+
if ( ! empty( $s['aspect'] ) ) {
|
|
120
|
+
$style = ' style="--carousel-slide-aspect:' . esc_attr( $s['aspect'] ) . '"';
|
|
121
|
+
}
|
|
82
122
|
|
|
83
123
|
$attr_str = implode( ' ', $attrs );
|
|
124
|
+
$hint = isset( $s['hint'] ) ? $s['hint'] : esc_html__( 'Scroll for more', 'bricks' );
|
|
84
125
|
|
|
85
|
-
echo "<wc-carousel {$attr_str} {$this->render_attributes( '_root' )}>";
|
|
126
|
+
echo "<wc-carousel {$attr_str} {$this->render_attributes( '_root' )}{$style}>";
|
|
127
|
+
echo '<div class="carousel__track" tabindex="0">';
|
|
86
128
|
echo \Bricks\Frontend::render_children( $this );
|
|
129
|
+
echo '</div>';
|
|
130
|
+
if ( '' !== $hint ) {
|
|
131
|
+
echo '<p class="carousel__hint font-footnote" aria-hidden="true">' . esc_html( $hint ) . '</p>';
|
|
132
|
+
}
|
|
87
133
|
echo '</wc-carousel>';
|
|
88
134
|
}
|
|
89
135
|
}
|
package/assets/css/animation.css
CHANGED
|
@@ -71,6 +71,15 @@
|
|
|
71
71
|
animation-duration: var(--animation-duration-xslow);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/* The gallery/lightbox thumbnail → full-image morph (see patterns/lightbox.css)
|
|
75
|
+
needs a shorter duration than a whole-page navigation. Scoped to `*` because a
|
|
76
|
+
repo-wide `::view-transition-old/new` selector belongs at the engine layer, not
|
|
77
|
+
inside the one pattern partial that happens to use it first. */
|
|
78
|
+
::view-transition-old(*),
|
|
79
|
+
::view-transition-new(*) {
|
|
80
|
+
animation-duration: 0.3s;
|
|
81
|
+
}
|
|
82
|
+
|
|
74
83
|
/* ===========================================
|
|
75
84
|
* Keyframes - Layout Stage (most expensive)
|
|
76
85
|
* =========================================== */
|
package/assets/css/global.css
CHANGED
|
@@ -26,6 +26,30 @@
|
|
|
26
26
|
box-sizing: border-box;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
/* Media never overflows its container. `:where()` so it carries zero specificity
|
|
30
|
+
and this file's layer (`vitops.base`) so it loses to everything, including a
|
|
31
|
+
consumer's unlayered rule.
|
|
32
|
+
|
|
33
|
+
Deliberately NOT the classic `img { display: block }` half of this reset. That
|
|
34
|
+
is the part that breaks things here: inline images in prose lose baseline
|
|
35
|
+
alignment, `patterns/icon.css`'s `.icon > img` and marquee logo runs break onto
|
|
36
|
+
their own lines, and `layout.css`'s
|
|
37
|
+
`.rhythm > :where(p, h1…h6, ul, ol) + :where(figure, img, picture, video)`
|
|
38
|
+
rules start spacing images that were previously inline. Every framework pattern
|
|
39
|
+
that wants a block image already declares it (media.css, subgrid.css,
|
|
40
|
+
carousel.css), which is the right place for it.
|
|
41
|
+
|
|
42
|
+
`svg` is excluded from `block-size: auto` because `patterns/svg.css` ships a
|
|
43
|
+
bare `svg` rule and SVGs commonly size from presentation attributes;
|
|
44
|
+
`max-inline-size` alone is safe there. */
|
|
45
|
+
:where(img, svg, video, canvas, iframe, embed, object) {
|
|
46
|
+
max-inline-size: 100%;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:where(img, video) {
|
|
50
|
+
block-size: auto;
|
|
51
|
+
}
|
|
52
|
+
|
|
29
53
|
/* Drop the UA's 8px body margin. The framework owns page gutters via `.centered`
|
|
30
54
|
(--gutter), so the UA default just offsets every full-bleed surface — sticky
|
|
31
55
|
headers and `bg-*` bands end up inset by 8px with a sliver of canvas showing
|
package/assets/css/index.css
CHANGED
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
panel surface navshell's desktop block has to undo. */
|
|
44
44
|
@import './patterns/navshell.css';
|
|
45
45
|
@import './patterns/notification.css';
|
|
46
|
+
@import './patterns/gallery.css';
|
|
46
47
|
@import './patterns/lightbox.css';
|
|
47
48
|
@import './patterns/overlay.css';
|
|
48
49
|
/* was forms.css */
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
@import './patterns/text-effects.css';
|
|
70
71
|
@import './patterns/svg.css';
|
|
71
72
|
@import './patterns/marquee.css';
|
|
73
|
+
@import './patterns/counter.css';
|
|
72
74
|
@import './patterns/nav.css';
|
|
73
75
|
@import './patterns/carousel.css';
|
|
74
76
|
@import './patterns/copy.css';
|