@getvitops/generator 5.0.0 → 6.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 CHANGED
@@ -1,5 +1,63 @@
1
1
  # @getvitops/generator
2
2
 
3
+ ## 6.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - Carousel rework: a scroll strip that is operable and discoverable with no JS in every engine, and
8
+ real controls where the scroll-marker pseudo-elements are missing.
9
+
10
+ `::scroll-button()`, `::scroll-marker` and `::scroll-marker-group` are still Chromium-only, and
11
+ there is no usable polyfill (the one prototype targets the superseded syntax and only re-parses
12
+ inline `<style>` elements). So the carousel no longer assumes them: `<wc-carousel>` builds real
13
+ prev/next `<button>`s and a real dot nav where they are absent, styled from the same declarations
14
+ as the native ones. Which branch is live is decided **by the stylesheet** — one `@supports` sets
15
+ `--carousel-native-nav: 1` and the element reads it back — so the condition is written once and
16
+ the two cannot disagree.
17
+
18
+ **Breaking — `.carousel` is now a shell and `.carousel__track` is the scroller** (all formats). The
19
+ hint and the controls need a home outside the scrollport, and absolute positioning against the
20
+ shell replaces `position: fixed` + `anchor-name`/`position-area`, which pinned controls to a
21
+ viewport corner in any engine without anchor positioning. The 5.x single-element form is still
22
+ styled via `:not(:has(> .carousel__track))` and is promoted by the element at runtime, but it is
23
+ deprecated: wrap your slides in `<ul class="carousel__track">`.
24
+
25
+ **Breaking — looping is opt-in.** `<wc-carousel loop>` clones the slides; the default no longer
26
+ does. Cloning triples the markup, duplicates every image element and makes the scrollbar report 3×
27
+ the real content. `autoplay` implies `loop`. Migration: add `loop`.
28
+
29
+ **Breaking — `[part='autoplay']` is now `.carousel__autoplay`** (aliased for one release; `part`
30
+ only crosses a shadow boundary and this element is light DOM, so it was never a part). The button
31
+ is also a child of the shell rather than the track, where it used to occupy a slide-width column.
32
+
33
+ **Breaking — the host role is `group`, not `region`.** `region` is a landmark, so every carousel
34
+ grew an entry in the landmark list. Pass `landmark` to `<Carousel />` where it really is one.
35
+
36
+ **Changed (visual)** — the scrollbar is visible by default (`scrollbar-width: thin`, was `none`)
37
+ and a "Scroll for more" hint renders above the strip; both dim once the visitor scrolls, via a
38
+ scroll-progress timeline where available and a `data-scrolled` attribute otherwise. Opt out with
39
+ `.carousel--no-scrollbar` and `hint={false}`. `@getvitops/core`'s `global.css` also gains a narrow
40
+ media reset (`max-inline-size: 100%` on replaced elements, `block-size: auto` on `img`/`video`) —
41
+ deliberately without `display: block`, which would change inline images in prose.
42
+
43
+ **Added** — `@getvitops/astro/components/Carousel.astro`, a tier-3 wrapper emitting semantic
44
+ `<ul>`/`<li>`/`<figure>` markup with the right per-slide image priorities: the first slide eager
45
+ and high (the LCP candidate), the rest `lazy`/`low`/`async`. `loading="lazy"` is honoured for
46
+ images clipped by a horizontal scroll container, so off-screen slides defer with no JavaScript at
47
+ all. Also new: `carousel--markers-below` and `carousel--no-scrollbar`, and
48
+ `--carousel-slide-aspect`, which keeps slide heights equal whatever each image's aspect ratio is.
49
+
50
+ **Fixed** — `::scroll-button()` glyphs sat off-centre in their circles (`global.css`'s `*` reset
51
+ does not reach a pseudo-element, so the button was `content-box` with the UA's `padding: 1px 6px`
52
+ and `inline-size` + `aspect-ratio` sized an ellipse); the hover state was a no-op (it set the same
53
+ token as the base rule); slide heights varied with each image's aspect ratio; navigation used
54
+ physical `left`/`right` and so put "previous" on the wrong side in RTL; cloned slides duplicated
55
+ their `id`s; and `scrollBy(clientWidth)` overshot whenever `--carousel-slide-size` was not `100%`.
56
+
57
+ ### Patch Changes
58
+
59
+ - @getvitops/utils@6.0.0
60
+
3
61
  ## 5.0.0
4
62
 
5
63
  ### 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): an
6
- * infinite-loop carousel that progressively enhances the CSS-only `.carousel`. Each
7
- * direct child is a slide. Without JS the `.carousel` classes still yield a working
8
- * (non-looping) scroll-snap carousel, so the builder canvas stays functional.
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
  }
@@ -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