@styleflow.app/flowpress-astro-core 1.0.0-beta.0 → 1.0.0-beta.2

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
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 1.0.0-beta.2
6
+
7
+ - Added exact `@splidejs/splide@4.1.4` support and dedicated renderers for
8
+ `sf/carousel` and `sf/carousel-item` with responsive item counts, arrows,
9
+ pagination, drag, focused keyboard control, loop and autoplay.
10
+ - Added accessible live-region integration and mandatory Play/Pause controls
11
+ for autoplay, including hover/focus pauses and reduced-motion protection.
12
+ - Added defensive CMS clamps, per-instance custom-element lifecycle cleanup,
13
+ readable no-JavaScript layouts and a diagnostic static fallback that keeps
14
+ legacy content whose direct children are not carousel items.
15
+
16
+ ## 1.0.0-beta.1
17
+
18
+ - Updated the exact `@styleflow.app/astro` dependency to `1.0.0-beta.1`,
19
+ keeping consumer trees on one runtime while adopting deterministic CLI
20
+ reports. Runtime behavior is unchanged.
21
+
5
22
  ## 1.0.0-beta.0
6
23
 
7
24
  - Adopted the grouped Styleflow vNext project contract and the exact Astro v1
package/README.md CHANGED
@@ -9,8 +9,8 @@ The package must not import from an application or project plugin.
9
9
  ## Install
10
10
 
11
11
  ```bash
12
- pnpm add @styleflow.app/flowpress-astro-core@1.0.0-beta.0 \
13
- @styleflow.app/astro@1.0.0-beta.0
12
+ pnpm add @styleflow.app/flowpress-astro-core@1.0.0-beta.2 \
13
+ @styleflow.app/astro@1.0.0-beta.1
14
14
  ```
15
15
 
16
16
  Prereleases are pinned exactly. The package expects Astro 7 or newer and the
@@ -54,6 +54,22 @@ visible characters. The exported
54
54
  from rendered CMS blocks so consumers can generate Tailwind
55
55
  `@source inline()` directives before compiling their frontend CSS.
56
56
 
57
+ `sf/carousel` renders an accessible horizontal Splide carousel whose direct
58
+ children must be `sf/carousel-item`; each item can recursively contain any
59
+ renderable block. Item counts inherit across `base/sm/md/lg/xl/2xl`, with
60
+ defaults `1/1/2/3/3/3`. Arrows, pagination, drag/swipe, focused keyboard
61
+ navigation, loop and autoplay follow CMS attributes. Autoplay always includes
62
+ one Play/Pause control, pauses on configured hover/focus states and starts
63
+ paused under reduced-motion preferences. Every custom element owns and
64
+ destroys exactly one Splide instance.
65
+
66
+ Stored CMS values are clamped to the public contract: item counts and movement
67
+ `1–12`, gap `0–128px`, autoplay interval `1000–60000ms`, and transition speed
68
+ `0–5000ms`. Without JavaScript, all valid items remain a readable responsive
69
+ grid and dead controls are hidden. If a legacy carousel contains any direct
70
+ child other than `sf/carousel-item`, no interactive instance is initialized:
71
+ the complete content renders statically, with a development diagnostic.
72
+
57
73
  Heading, rich-text, quote and matching core blocks accept Gutenberg alignment
58
74
  from either `style.typography.textAlign` or the FlowPress `textAlign` field.
59
75
  Only `left`, `center`, `right`, `justify`, `start` and `end` reach CSS.
@@ -142,7 +158,7 @@ The TypeScript template-hierarchy suite is self-contained. Its additional PHP
142
158
  parity test runs when the sibling `flowpress-wordpress-core` checkout is
143
159
  available locally and is skipped in a standalone package checkout.
144
160
 
145
- Publish `1.0.0-beta.0` on `next` only after Components and WordPress Core are
161
+ Publish v1 betas on `next` only after Components and WordPress Core are
146
162
  available. Inspect `npm view`, `gitHead`, integrity and the downloaded tarball.
147
163
  Promote to `latest` only after the DMO canary and rollback gate.
148
164
 
@@ -7,6 +7,8 @@ import type {
7
7
  import type { StyleflowContract } from "../styleflow.js";
8
8
  import type { FlowpressBlock } from "../types.js";
9
9
  import ColumnBlock from "./blocks/ColumnBlock.astro";
10
+ import CarouselBlock from "./blocks/CarouselBlock.astro";
11
+ import CarouselItemBlock from "./blocks/CarouselItemBlock.astro";
10
12
  import FormBlock from "./blocks/FormBlock.astro";
11
13
  import GridBlock from "./blocks/GridBlock.astro";
12
14
  import HeroBlock from "./blocks/HeroBlock.astro";
@@ -108,6 +110,40 @@ function youtubeEmbedUrl(value: unknown): string | null {
108
110
  );
109
111
  }
110
112
 
113
+ if (name === "carousel") {
114
+ const invalidChildNames = children
115
+ .filter((child) => child.name !== "sf/carousel-item")
116
+ .map((child) => child.name);
117
+ return (
118
+ <CarouselBlock
119
+ block={block}
120
+ contract={contract}
121
+ validChildren={invalidChildNames.length === 0}
122
+ invalidChildNames={invalidChildNames}
123
+ >
124
+ <Astro.self
125
+ blocks={children}
126
+ contract={contract}
127
+ blockRenderers={blockRenderers}
128
+ iconRenderer={IconRenderer}
129
+ />
130
+ </CarouselBlock>
131
+ );
132
+ }
133
+
134
+ if (name === "carousel-item") {
135
+ return (
136
+ <CarouselItemBlock block={block} contract={contract}>
137
+ <Astro.self
138
+ blocks={children}
139
+ contract={contract}
140
+ blockRenderers={blockRenderers}
141
+ iconRenderer={IconRenderer}
142
+ />
143
+ </CarouselItemBlock>
144
+ );
145
+ }
146
+
111
147
  if (name === "number-spinner") {
112
148
  return <NumberSpinnerBlock block={block} contract={contract} />;
113
149
  }
@@ -0,0 +1,200 @@
1
+ ---
2
+ import "@splidejs/splide/css/core";
3
+ import S from "@styleflow.app/astro/S.astro";
4
+ import { carouselOptions, carouselSettings } from "../../carousel.js";
5
+ import type { FlowpressBlock } from "../../types.js";
6
+ import type { StyleflowContract } from "../../styleflow.js";
7
+ import { blockHtmlAttributes, semanticProps } from "./helpers.js";
8
+
9
+ interface Props {
10
+ block: FlowpressBlock;
11
+ contract?: StyleflowContract;
12
+ validChildren: boolean;
13
+ invalidChildNames?: string[];
14
+ }
15
+
16
+ const { block, contract, validChildren, invalidChildNames = [] } = Astro.props;
17
+ const settings = carouselSettings(block.attributes);
18
+ const options = carouselOptions(settings);
19
+ const semantic = semanticProps(block.attributes, contract, {
20
+ surface: "default",
21
+ layoutRole: "container",
22
+ density: "regular"
23
+ });
24
+ const htmlAttributes = blockHtmlAttributes(
25
+ block.attributes,
26
+ `flowpress-carousel${validChildren ? " splide" : " flowpress-carousel--static"}`
27
+ );
28
+ const style = [
29
+ `--flowpress-carousel-gap:${settings.gap}px`,
30
+ `--flowpress-carousel-base:${settings.itemsPerView.base}`,
31
+ `--flowpress-carousel-sm:${settings.itemsPerView.sm}`,
32
+ `--flowpress-carousel-md:${settings.itemsPerView.md}`,
33
+ `--flowpress-carousel-lg:${settings.itemsPerView.lg}`,
34
+ `--flowpress-carousel-xl:${settings.itemsPerView.xl}`,
35
+ `--flowpress-carousel-2xl:${settings.itemsPerView["2xl"]}`
36
+ ].join(";");
37
+
38
+ if (!validChildren && import.meta.env.DEV) {
39
+ console.warn(
40
+ `[flowpress-carousel-invalid-children] sf/carousel accepts only sf/carousel-item; received: ${invalidChildNames.join(", ") || "unknown"}. Rendering static content.`
41
+ );
42
+ }
43
+ ---
44
+
45
+ {validChildren ? (
46
+ <flowpress-carousel>
47
+ <S
48
+ as="section"
49
+ {...semantic}
50
+ {...htmlAttributes}
51
+ aria-label={settings.ariaLabel}
52
+ data-flowpress-carousel-root
53
+ data-carousel-options={JSON.stringify(options)}
54
+ style={style}
55
+ >
56
+ {settings.showArrows ? (
57
+ <div class="splide__arrows" data-flowpress-carousel-controls>
58
+ <button class="splide__arrow splide__arrow--prev" type="button">
59
+ <span aria-hidden="true">←</span>
60
+ </button>
61
+ <button class="splide__arrow splide__arrow--next" type="button">
62
+ <span aria-hidden="true">→</span>
63
+ </button>
64
+ </div>
65
+ ) : null}
66
+ <div class="splide__track">
67
+ <ul class="splide__list">
68
+ <slot />
69
+ </ul>
70
+ </div>
71
+ {settings.showPagination ? <ul class="splide__pagination"></ul> : null}
72
+ {settings.autoplay ? (
73
+ <button
74
+ class="splide__toggle"
75
+ type="button"
76
+ data-flowpress-carousel-controls
77
+ >
78
+ <span class="splide__toggle__play">Avvia</span>
79
+ <span class="splide__toggle__pause">Pausa</span>
80
+ </button>
81
+ ) : null}
82
+ </S>
83
+ </flowpress-carousel>
84
+ ) : (
85
+ <S
86
+ as="section"
87
+ {...semantic}
88
+ {...htmlAttributes}
89
+ aria-label={settings.ariaLabel}
90
+ data-flowpress-carousel-invalid
91
+ data-invalid-children={invalidChildNames.join(",")}
92
+ style={style}
93
+ >
94
+ <slot />
95
+ </S>
96
+ )}
97
+
98
+ <script>
99
+ import Splide from "@splidejs/splide";
100
+ import type { Options } from "@splidejs/splide";
101
+
102
+ if (!customElements.get("flowpress-carousel")) {
103
+ customElements.define("flowpress-carousel", class extends HTMLElement {
104
+ private instance?: Splide;
105
+
106
+ connectedCallback() {
107
+ if (this.instance) return;
108
+ const root = this.querySelector<HTMLElement>("[data-flowpress-carousel-root]");
109
+ if (!root) return;
110
+ try {
111
+ const options = JSON.parse(root.dataset.carouselOptions || "{}") as Options;
112
+ this.instance = new Splide(root, options);
113
+ this.instance.mount();
114
+ } catch (error) {
115
+ console.error("[flowpress-carousel-init] Unable to initialize carousel.", error);
116
+ }
117
+ }
118
+
119
+ disconnectedCallback() {
120
+ this.instance?.destroy(true);
121
+ this.instance = undefined;
122
+ }
123
+ });
124
+ }
125
+ </script>
126
+
127
+ <style>
128
+ flowpress-carousel { display: block; }
129
+ .flowpress-carousel { min-width: 0; }
130
+ .flowpress-carousel:not(.is-initialized) .splide__list {
131
+ display: grid;
132
+ grid-template-columns: repeat(var(--flowpress-carousel-base), minmax(0, 1fr));
133
+ gap: var(--flowpress-carousel-gap);
134
+ }
135
+ .flowpress-carousel:not(.is-initialized) [data-flowpress-carousel-controls],
136
+ .flowpress-carousel:not(.is-initialized) .splide__pagination {
137
+ display: none;
138
+ }
139
+ .flowpress-carousel--static {
140
+ display: grid;
141
+ gap: var(--flowpress-carousel-gap);
142
+ }
143
+ .splide__arrows {
144
+ display: flex;
145
+ justify-content: space-between;
146
+ gap: 0.5rem;
147
+ margin-block-end: 0.75rem;
148
+ }
149
+ .splide__arrow:disabled { opacity: 0.45; }
150
+ .splide__pagination {
151
+ display: flex;
152
+ justify-content: center;
153
+ gap: 0.5rem;
154
+ margin: 0.75rem 0 0;
155
+ padding: 0;
156
+ }
157
+ :global(.splide__pagination__page) {
158
+ width: 0.75rem;
159
+ height: 0.75rem;
160
+ border-radius: 999px;
161
+ }
162
+ .splide__toggle { margin-block-start: 0.75rem; }
163
+ .splide__toggle__pause { display: none; }
164
+ .splide__toggle.is-active .splide__toggle__play { display: none; }
165
+ .splide__toggle.is-active .splide__toggle__pause { display: inline; }
166
+ .splide__arrow:focus-visible,
167
+ :global(.splide__pagination__page:focus-visible),
168
+ .splide__toggle:focus-visible {
169
+ outline: 3px solid currentColor;
170
+ outline-offset: 3px;
171
+ }
172
+ @media (min-width: 40rem) {
173
+ .flowpress-carousel:not(.is-initialized) .splide__list {
174
+ grid-template-columns: repeat(var(--flowpress-carousel-sm), minmax(0, 1fr));
175
+ }
176
+ }
177
+ @media (min-width: 48rem) {
178
+ .flowpress-carousel:not(.is-initialized) .splide__list {
179
+ grid-template-columns: repeat(var(--flowpress-carousel-md), minmax(0, 1fr));
180
+ }
181
+ }
182
+ @media (min-width: 64rem) {
183
+ .flowpress-carousel:not(.is-initialized) .splide__list {
184
+ grid-template-columns: repeat(var(--flowpress-carousel-lg), minmax(0, 1fr));
185
+ }
186
+ }
187
+ @media (min-width: 80rem) {
188
+ .flowpress-carousel:not(.is-initialized) .splide__list {
189
+ grid-template-columns: repeat(var(--flowpress-carousel-xl), minmax(0, 1fr));
190
+ }
191
+ }
192
+ @media (min-width: 96rem) {
193
+ .flowpress-carousel:not(.is-initialized) .splide__list {
194
+ grid-template-columns: repeat(var(--flowpress-carousel-2xl), minmax(0, 1fr));
195
+ }
196
+ }
197
+ @media (prefers-reduced-motion: reduce) {
198
+ .flowpress-carousel * { scroll-behavior: auto !important; }
199
+ }
200
+ </style>
@@ -0,0 +1,26 @@
1
+ ---
2
+ import S from "@styleflow.app/astro/S.astro";
3
+ import type { FlowpressBlock } from "../../types.js";
4
+ import type { StyleflowContract } from "../../styleflow.js";
5
+ import { blockHtmlAttributes, semanticProps } from "./helpers.js";
6
+
7
+ interface Props {
8
+ block: FlowpressBlock;
9
+ contract?: StyleflowContract;
10
+ }
11
+
12
+ const { block, contract } = Astro.props;
13
+ const semantic = semanticProps(block.attributes, contract);
14
+ const htmlAttributes = blockHtmlAttributes(
15
+ block.attributes,
16
+ "splide__slide flowpress-carousel-item"
17
+ );
18
+ ---
19
+
20
+ <S as="li" {...semantic} {...htmlAttributes}>
21
+ <slot />
22
+ </S>
23
+
24
+ <style>
25
+ .flowpress-carousel-item { min-width: 0; }
26
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { Options } from "@splidejs/splide";
2
+ declare const BREAKPOINTS: readonly ["base", "sm", "md", "lg", "xl", "2xl"];
3
+ export interface FlowpressCarouselSettings {
4
+ ariaLabel: string;
5
+ itemsPerView: Record<(typeof BREAKPOINTS)[number], number>;
6
+ itemsPerMove: number;
7
+ gap: number;
8
+ showArrows: boolean;
9
+ showPagination: boolean;
10
+ drag: boolean;
11
+ keyboard: boolean;
12
+ autoplay: boolean;
13
+ autoplayInterval: number;
14
+ pauseOnHover: boolean;
15
+ pauseOnFocus: boolean;
16
+ loop: boolean;
17
+ speed: number;
18
+ }
19
+ export declare function carouselSettings(attributes: Record<string, unknown>): FlowpressCarouselSettings;
20
+ export declare function carouselOptions(settings: FlowpressCarouselSettings): Options;
21
+ export {};
22
+ //# sourceMappingURL=carousel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carousel.d.ts","sourceRoot":"","sources":["../src/carousel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAEhD,QAAA,MAAM,WAAW,kDAAmD,CAAC;AAErE,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAqBD,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,yBAAyB,CAgD3B;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,yBAAyB,GAAG,OAAO,CA6C5E"}
@@ -0,0 +1,102 @@
1
+ const BREAKPOINTS = ["base", "sm", "md", "lg", "xl", "2xl"];
2
+ function boundedNumber(value, fallback, min, max) {
3
+ if (value === "" || value === null || value === undefined || value === "inherit") {
4
+ return fallback;
5
+ }
6
+ const numeric = Number(value);
7
+ return Number.isFinite(numeric)
8
+ ? Math.min(max, Math.max(min, Math.round(numeric)))
9
+ : fallback;
10
+ }
11
+ function booleanValue(value, fallback) {
12
+ return typeof value === "boolean" ? value : fallback;
13
+ }
14
+ export function carouselSettings(attributes) {
15
+ const defaults = { base: 1, sm: 1, md: 2, lg: 3, xl: 3, "2xl": 3 };
16
+ const values = {};
17
+ let inherited = defaults.base;
18
+ for (const breakpoint of BREAKPOINTS) {
19
+ const suffix = breakpoint === "base"
20
+ ? "Base"
21
+ : breakpoint === "2xl"
22
+ ? "2xl"
23
+ : breakpoint.charAt(0).toUpperCase() + breakpoint.slice(1);
24
+ const raw = attributes[`itemsPerView${suffix}`];
25
+ const fallback = breakpoint !== "base" && (raw === "" || raw === "inherit")
26
+ ? inherited
27
+ : breakpoint === "base"
28
+ ? defaults.base
29
+ : breakpoint === "md" || breakpoint === "lg"
30
+ ? defaults[breakpoint]
31
+ : inherited;
32
+ const value = boundedNumber(raw, fallback, 1, 12);
33
+ values[breakpoint] = value;
34
+ inherited = value;
35
+ }
36
+ const ariaLabel = typeof attributes.ariaLabel === "string"
37
+ ? attributes.ariaLabel.trim()
38
+ : "";
39
+ return {
40
+ ariaLabel: ariaLabel || "Carosello",
41
+ itemsPerView: values,
42
+ itemsPerMove: boundedNumber(attributes.itemsPerMove, 1, 1, 12),
43
+ gap: boundedNumber(attributes.gap, 24, 0, 128),
44
+ showArrows: booleanValue(attributes.showArrows, true),
45
+ showPagination: booleanValue(attributes.showPagination, true),
46
+ drag: booleanValue(attributes.drag, true),
47
+ keyboard: booleanValue(attributes.keyboard, true),
48
+ autoplay: booleanValue(attributes.autoplay, false),
49
+ autoplayInterval: boundedNumber(attributes.autoplayInterval, 5000, 1000, 60000),
50
+ pauseOnHover: booleanValue(attributes.pauseOnHover, true),
51
+ pauseOnFocus: booleanValue(attributes.pauseOnFocus, true),
52
+ loop: booleanValue(attributes.loop, false),
53
+ speed: boundedNumber(attributes.speed, 400, 0, 5000)
54
+ };
55
+ }
56
+ export function carouselOptions(settings) {
57
+ return {
58
+ label: settings.ariaLabel,
59
+ type: settings.loop ? "loop" : "slide",
60
+ perPage: settings.itemsPerView.base,
61
+ perMove: settings.itemsPerMove,
62
+ gap: `${settings.gap}px`,
63
+ arrows: settings.showArrows,
64
+ pagination: settings.showPagination,
65
+ drag: settings.drag,
66
+ keyboard: settings.keyboard ? "focused" : false,
67
+ autoplay: settings.autoplay,
68
+ interval: settings.autoplayInterval,
69
+ pauseOnHover: settings.pauseOnHover,
70
+ pauseOnFocus: settings.pauseOnFocus,
71
+ speed: settings.speed,
72
+ live: true,
73
+ mediaQuery: "min",
74
+ breakpoints: {
75
+ 640: { perPage: settings.itemsPerView.sm },
76
+ 768: { perPage: settings.itemsPerView.md },
77
+ 1024: { perPage: settings.itemsPerView.lg },
78
+ 1280: { perPage: settings.itemsPerView.xl },
79
+ 1536: { perPage: settings.itemsPerView["2xl"] }
80
+ },
81
+ reducedMotion: {
82
+ speed: 0,
83
+ rewindSpeed: 0,
84
+ autoplay: "pause"
85
+ },
86
+ i18n: {
87
+ prev: "Slide precedente",
88
+ next: "Slide successiva",
89
+ first: "Vai alla prima slide",
90
+ last: "Vai all'ultima slide",
91
+ slideX: "Vai alla slide %s",
92
+ pageX: "Vai alla pagina %s",
93
+ play: "Avvia autoplay",
94
+ pause: "Pausa autoplay",
95
+ carousel: "carosello",
96
+ slide: "slide",
97
+ select: "Seleziona una slide da mostrare",
98
+ slideLabel: "%s di %s"
99
+ }
100
+ };
101
+ }
102
+ //# sourceMappingURL=carousel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carousel.js","sourceRoot":"","sources":["../src/carousel.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAU,CAAC;AAmBrE,SAAS,aAAa,CACpB,KAAc,EACd,QAAgB,EAChB,GAAW,EACX,GAAW;IAEX,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACjF,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC7B,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,KAAc,EAAE,QAAiB;IACrD,OAAO,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,UAAmC;IAEnC,MAAM,QAAQ,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,EAA+C,CAAC;IAC/D,IAAI,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC9B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,UAAU,KAAK,MAAM;YAClC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,UAAU,KAAK,KAAK;gBACpB,CAAC,CAAC,KAAK;gBACP,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,UAAU,CAAC,eAAe,MAAM,EAAE,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,UAAU,KAAK,MAAM,IAAI,CAAC,GAAG,KAAK,EAAE,IAAI,GAAG,KAAK,SAAS,CAAC;YACzE,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,UAAU,KAAK,MAAM;gBACvB,CAAC,CAAC,QAAQ,CAAC,IAAI;gBACf,CAAC,CAAC,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,IAAI;oBAC1C,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC;oBACtB,CAAC,CAAC,SAAS,CAAC;QAChB,MAAM,KAAK,GAAG,aAAa,CACzB,GAAG,EACH,QAAQ,EACR,CAAC,EACD,EAAE,CACH,CAAC;QACF,MAAM,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;QAC3B,SAAS,GAAG,KAAK,CAAC;IACpB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,UAAU,CAAC,SAAS,KAAK,QAAQ;QACxD,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE;QAC7B,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;QACL,SAAS,EAAE,SAAS,IAAI,WAAW;QACnC,YAAY,EAAE,MAAM;QACpB,YAAY,EAAE,aAAa,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9D,GAAG,EAAE,aAAa,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC;QAC9C,UAAU,EAAE,YAAY,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC;QACrD,cAAc,EAAE,YAAY,CAAC,UAAU,CAAC,cAAc,EAAE,IAAI,CAAC;QAC7D,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC;QACzC,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC;QACjD,QAAQ,EAAE,YAAY,CAAC,UAAU,CAAC,QAAQ,EAAE,KAAK,CAAC;QAClD,gBAAgB,EAAE,aAAa,CAAC,UAAU,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC;QAC/E,YAAY,EAAE,YAAY,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC;QACzD,YAAY,EAAE,YAAY,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC;QACzD,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC;QAC1C,KAAK,EAAE,aAAa,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,QAAmC;IACjE,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,SAAS;QACzB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;QACtC,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,IAAI;QACnC,OAAO,EAAE,QAAQ,CAAC,YAAY;QAC9B,GAAG,EAAE,GAAG,QAAQ,CAAC,GAAG,IAAI;QACxB,MAAM,EAAE,QAAQ,CAAC,UAAU;QAC3B,UAAU,EAAE,QAAQ,CAAC,cAAc;QACnC,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;QAC/C,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,QAAQ,EAAE,QAAQ,CAAC,gBAAgB;QACnC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,YAAY,EAAE,QAAQ,CAAC,YAAY;QACnC,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE;YACX,GAAG,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE;YAC1C,GAAG,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE;YAC1C,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE;YAC3C,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,EAAE;YAC3C,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE;SAChD;QACD,aAAa,EAAE;YACb,KAAK,EAAE,CAAC;YACR,WAAW,EAAE,CAAC;YACd,QAAQ,EAAE,OAAO;SAClB;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,kBAAkB;YACxB,IAAI,EAAE,kBAAkB;YACxB,KAAK,EAAE,sBAAsB;YAC7B,IAAI,EAAE,sBAAsB;YAC5B,MAAM,EAAE,mBAAmB;YAC3B,KAAK,EAAE,oBAAoB;YAC3B,IAAI,EAAE,gBAAgB;YACtB,KAAK,EAAE,gBAAgB;YACvB,QAAQ,EAAE,WAAW;YACrB,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,iCAAiC;YACzC,UAAU,EAAE,UAAU;SACvB;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Options } from \"@splidejs/splide\";\n\nconst BREAKPOINTS = [\"base\", \"sm\", \"md\", \"lg\", \"xl\", \"2xl\"] as const;\n\nexport interface FlowpressCarouselSettings {\n ariaLabel: string;\n itemsPerView: Record<(typeof BREAKPOINTS)[number], number>;\n itemsPerMove: number;\n gap: number;\n showArrows: boolean;\n showPagination: boolean;\n drag: boolean;\n keyboard: boolean;\n autoplay: boolean;\n autoplayInterval: number;\n pauseOnHover: boolean;\n pauseOnFocus: boolean;\n loop: boolean;\n speed: number;\n}\n\nfunction boundedNumber(\n value: unknown,\n fallback: number,\n min: number,\n max: number\n): number {\n if (value === \"\" || value === null || value === undefined || value === \"inherit\") {\n return fallback;\n }\n const numeric = Number(value);\n return Number.isFinite(numeric)\n ? Math.min(max, Math.max(min, Math.round(numeric)))\n : fallback;\n}\n\nfunction booleanValue(value: unknown, fallback: boolean): boolean {\n return typeof value === \"boolean\" ? value : fallback;\n}\n\nexport function carouselSettings(\n attributes: Record<string, unknown>\n): FlowpressCarouselSettings {\n const defaults = { base: 1, sm: 1, md: 2, lg: 3, xl: 3, \"2xl\": 3 };\n const values = {} as FlowpressCarouselSettings[\"itemsPerView\"];\n let inherited = defaults.base;\n for (const breakpoint of BREAKPOINTS) {\n const suffix = breakpoint === \"base\"\n ? \"Base\"\n : breakpoint === \"2xl\"\n ? \"2xl\"\n : breakpoint.charAt(0).toUpperCase() + breakpoint.slice(1);\n const raw = attributes[`itemsPerView${suffix}`];\n const fallback = breakpoint !== \"base\" && (raw === \"\" || raw === \"inherit\")\n ? inherited\n : breakpoint === \"base\"\n ? defaults.base\n : breakpoint === \"md\" || breakpoint === \"lg\"\n ? defaults[breakpoint]\n : inherited;\n const value = boundedNumber(\n raw,\n fallback,\n 1,\n 12\n );\n values[breakpoint] = value;\n inherited = value;\n }\n\n const ariaLabel = typeof attributes.ariaLabel === \"string\"\n ? attributes.ariaLabel.trim()\n : \"\";\n\n return {\n ariaLabel: ariaLabel || \"Carosello\",\n itemsPerView: values,\n itemsPerMove: boundedNumber(attributes.itemsPerMove, 1, 1, 12),\n gap: boundedNumber(attributes.gap, 24, 0, 128),\n showArrows: booleanValue(attributes.showArrows, true),\n showPagination: booleanValue(attributes.showPagination, true),\n drag: booleanValue(attributes.drag, true),\n keyboard: booleanValue(attributes.keyboard, true),\n autoplay: booleanValue(attributes.autoplay, false),\n autoplayInterval: boundedNumber(attributes.autoplayInterval, 5000, 1000, 60000),\n pauseOnHover: booleanValue(attributes.pauseOnHover, true),\n pauseOnFocus: booleanValue(attributes.pauseOnFocus, true),\n loop: booleanValue(attributes.loop, false),\n speed: boundedNumber(attributes.speed, 400, 0, 5000)\n };\n}\n\nexport function carouselOptions(settings: FlowpressCarouselSettings): Options {\n return {\n label: settings.ariaLabel,\n type: settings.loop ? \"loop\" : \"slide\",\n perPage: settings.itemsPerView.base,\n perMove: settings.itemsPerMove,\n gap: `${settings.gap}px`,\n arrows: settings.showArrows,\n pagination: settings.showPagination,\n drag: settings.drag,\n keyboard: settings.keyboard ? \"focused\" : false,\n autoplay: settings.autoplay,\n interval: settings.autoplayInterval,\n pauseOnHover: settings.pauseOnHover,\n pauseOnFocus: settings.pauseOnFocus,\n speed: settings.speed,\n live: true,\n mediaQuery: \"min\",\n breakpoints: {\n 640: { perPage: settings.itemsPerView.sm },\n 768: { perPage: settings.itemsPerView.md },\n 1024: { perPage: settings.itemsPerView.lg },\n 1280: { perPage: settings.itemsPerView.xl },\n 1536: { perPage: settings.itemsPerView[\"2xl\"] }\n },\n reducedMotion: {\n speed: 0,\n rewindSpeed: 0,\n autoplay: \"pause\"\n },\n i18n: {\n prev: \"Slide precedente\",\n next: \"Slide successiva\",\n first: \"Vai alla prima slide\",\n last: \"Vai all'ultima slide\",\n slideX: \"Vai alla slide %s\",\n pageX: \"Vai alla pagina %s\",\n play: \"Avvia autoplay\",\n pause: \"Pausa autoplay\",\n carousel: \"carosello\",\n slide: \"slide\",\n select: \"Seleziona una slide da mostrare\",\n slideLabel: \"%s di %s\"\n }\n };\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./client.js";
2
+ export * from "./carousel.js";
2
3
  export * from "./block-renderers.js";
3
4
  export * from "./env.js";
4
5
  export * from "./number-spinner.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./client.js";
2
+ export * from "./carousel.js";
2
3
  export * from "./block-renderers.js";
3
4
  export * from "./env.js";
4
5
  export * from "./number-spinner.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./client.js\";\nexport * from \"./block-renderers.js\";\nexport * from \"./env.js\";\nexport * from \"./number-spinner.js\";\nexport * from \"./styleflow.js\";\nexport * from \"./style-classes.js\";\nexport * from \"./template-hierarchy.js\";\nexport * from \"./types.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,UAAU,CAAC;AACzB,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./client.js\";\nexport * from \"./carousel.js\";\nexport * from \"./block-renderers.js\";\nexport * from \"./env.js\";\nexport * from \"./number-spinner.js\";\nexport * from \"./styleflow.js\";\nexport * from \"./style-classes.js\";\nexport * from \"./template-hierarchy.js\";\nexport * from \"./types.js\";\n"]}
@@ -1 +1 @@
1
- {"root":["../src/astro.d.ts","../src/block-renderers.ts","../src/client.ts","../src/env.ts","../src/index.ts","../src/number-spinner.ts","../src/style-classes.ts","../src/styleflow.ts","../src/template-hierarchy.ts","../src/templates.ts","../src/types.ts","../src/astro/blocks/helpers.ts"],"version":"5.9.3"}
1
+ {"root":["../src/astro.d.ts","../src/block-renderers.ts","../src/carousel.ts","../src/client.ts","../src/env.ts","../src/index.ts","../src/number-spinner.ts","../src/style-classes.ts","../src/styleflow.ts","../src/template-hierarchy.ts","../src/templates.ts","../src/types.ts","../src/astro/blocks/helpers.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@styleflow.app/flowpress-astro-core",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "description": "Project-agnostic WordPress routing, templates, SEO and GraphQL runtime for FlowPress Astro apps.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -44,7 +44,8 @@
44
44
  "prepublishOnly": "npm run typecheck && npm test && npm run build"
45
45
  },
46
46
  "dependencies": {
47
- "@styleflow.app/astro": "1.0.0-beta.0"
47
+ "@splidejs/splide": "4.1.4",
48
+ "@styleflow.app/astro": "1.0.0-beta.1"
48
49
  },
49
50
  "peerDependencies": {
50
51
  "astro": ">=7.0.0"