@ailuracode/alpine-carousel 0.1.0 → 2.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/README.md +58 -7
- package/dist/global.d.ts +13 -50
- package/dist/index.d.ts +147 -23
- package/dist/index.js +1 -312
- package/package.json +32 -3
- package/dist/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,14 +5,14 @@ Headless accessible carousel store for Alpine.js, powered by [Embla Carousel](ht
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
pnpm add @ailuracode/alpine-carousel @ailuracode/alpine-core alpinejs
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Peer dependencies: `embla-carousel` and `embla-carousel-autoplay` are bundled as direct dependencies.
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Quick start
|
|
14
14
|
|
|
15
|
-
```
|
|
15
|
+
```ts
|
|
16
16
|
import Alpine from "alpinejs";
|
|
17
17
|
import carousel from "@ailuracode/alpine-carousel";
|
|
18
18
|
|
|
@@ -34,8 +34,8 @@ Alpine.start();
|
|
|
34
34
|
<section x-bind="$store.carousel.carouselProps('gallery', { label: 'Featured gallery' })">
|
|
35
35
|
<div x-ref="viewport" x-bind="$store.carousel.viewportProps('gallery')" class="min-w-0 w-full overflow-hidden">
|
|
36
36
|
<div class="flex touch-pan-y pinch-zoom">
|
|
37
|
-
<div class="min-w-0 shrink-0 grow-0 [
|
|
38
|
-
<div class="min-w-0 shrink-0 grow-0 [
|
|
37
|
+
<div class="min-w-0 shrink-0 grow-0 flex-[0_0_var(--slide-size,100%)]" x-bind="$store.carousel.slideProps('gallery', 0)">Slide 1</div>
|
|
38
|
+
<div class="min-w-0 shrink-0 grow-0 flex-[0_0_var(--slide-size,100%)]" x-bind="$store.carousel.slideProps('gallery', 1)">Slide 2</div>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
@@ -59,7 +59,6 @@ Embla expects the **viewport** element (overflow hidden) with a **container** ch
|
|
|
59
59
|
| `current(id)` / `count(id)` | Current index and total slides |
|
|
60
60
|
| `canNext(id)` / `canPrevious(id)` | Scroll availability |
|
|
61
61
|
| `play(id)` / `pause(id)` / `isPlaying(id)` | Autoplay controls |
|
|
62
|
-
| `instance(id)` | Raw Embla API (advanced) |
|
|
63
62
|
| `handleKeydown(id, event)` | Arrow keys, Home, End |
|
|
64
63
|
| `carouselProps(id, options?)` | ARIA region props |
|
|
65
64
|
| `viewportProps(id, options?)` | Focusable viewport props; sets `--slide-size` (default `100%`, pass `{ slideSize: false }` to use CSS classes instead) |
|
|
@@ -68,12 +67,64 @@ Embla expects the **viewport** element (overflow hidden) with a **container** ch
|
|
|
68
67
|
|
|
69
68
|
### Reactive state
|
|
70
69
|
|
|
71
|
-
Each
|
|
70
|
+
Each entry in `$store.carousel.instances[id]` is a **reactive mirror** of controller state (updated on `change` and `slideChange`). Use store commands to mutate; direct writes to `instances[id]` do not affect the controller.
|
|
71
|
+
|
|
72
|
+
Exposed fields:
|
|
72
73
|
|
|
73
74
|
- `currentIndex`, `totalSlides`, `progress`
|
|
74
75
|
- `isFirst`, `isLast`, `isPlaying`
|
|
75
76
|
- `canNext`, `canPrevious`, `slidesInView`
|
|
76
77
|
|
|
78
|
+
## Standalone usage (no Alpine)
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import {
|
|
82
|
+
createCarouselController,
|
|
83
|
+
createCarouselStore,
|
|
84
|
+
createCarouselStoreFromController,
|
|
85
|
+
} from "@ailuracode/alpine-carousel";
|
|
86
|
+
|
|
87
|
+
const controller = createCarouselController();
|
|
88
|
+
controller.create("gallery", { loop: true });
|
|
89
|
+
controller.current("gallery"); // 0
|
|
90
|
+
|
|
91
|
+
const store = createCarouselStore();
|
|
92
|
+
// or: createCarouselStoreFromController(controller)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Controller API | Description |
|
|
96
|
+
|----------------|-------------|
|
|
97
|
+
| `hasInstance(id)` | Whether a carousel id is registered |
|
|
98
|
+
| `snapshotInstances()` | Shallow readonly copies for adapter sync |
|
|
99
|
+
| `current(id)` / `count(id)` / `isPlaying(id)` | Query methods |
|
|
100
|
+
|
|
101
|
+
Subscribe to `controller.on("change", …)` and `controller.on("slideChange", …)` for adapter sync.
|
|
102
|
+
|
|
103
|
+
## Architecture
|
|
104
|
+
|
|
105
|
+
`CarouselController` owns all mutable state and the Embla instances. The Alpine plugin mirrors snapshots into `$store.carousel.instances`.
|
|
106
|
+
|
|
107
|
+
## Migration
|
|
108
|
+
|
|
109
|
+
| Removed / changed | Replacement |
|
|
110
|
+
|-------------------|-------------|
|
|
111
|
+
| `controller.instances` getter | `snapshotInstances()` or `hasInstance(id)` |
|
|
112
|
+
| `controller.toStore()` | `createCarouselStore()` or `createCarouselStoreFromController(controller)` |
|
|
113
|
+
| `$store.carousel.instance(id)` | `goTo(id, index)`, `next(id)`, `previous(id)`, and other semantic store methods |
|
|
114
|
+
| `CarouselInstance.embla` / `.autoplay` / `.viewport` on snapshots | Use semantic store methods and readonly snapshot fields |
|
|
115
|
+
| `CarouselOptions.align` / `.containScroll` typed via Embla | Toolkit-owned `CarouselAlign` and `CarouselContainScroll` types |
|
|
116
|
+
| (none) | `storeKey` — see [Avoiding name collisions](#avoiding-name-collisions) |
|
|
117
|
+
|
|
118
|
+
### Avoiding name collisions
|
|
119
|
+
|
|
120
|
+
If your application already owns a `$store.carousel` — or another toolkit plugin registers on that name — rename the integration surface without touching the controller:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
Alpine.plugin(carouselPlugin({ storeKey: "slider" })); // → $store.slider
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The exposed constant `DEFAULT_CAROUSEL_STORE_KEY` keeps the rename discoverable from TypeScript.
|
|
127
|
+
|
|
77
128
|
## Options
|
|
78
129
|
|
|
79
130
|
| Option | Default | Maps to Embla |
|
package/dist/global.d.ts
CHANGED
|
@@ -1,57 +1,20 @@
|
|
|
1
1
|
/// <reference types="@types/alpinejs" />
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
delay?: number;
|
|
5
|
-
stopOnInteraction?: boolean;
|
|
6
|
-
stopOnMouseEnter?: boolean;
|
|
7
|
-
stopOnFocusIn?: boolean;
|
|
8
|
-
stopWhenHidden?: boolean;
|
|
9
|
-
};
|
|
3
|
+
import type { CarouselStore } from "./types";
|
|
10
4
|
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
5
|
+
export { CarouselController, createCarouselController, createCarouselStore } from "./controller";
|
|
6
|
+
export type { CarouselEvents, CarouselSlideChangeDetail } from "./events";
|
|
7
|
+
export type {
|
|
8
|
+
CarouselAlign,
|
|
9
|
+
CarouselAutoplayOptions,
|
|
10
|
+
CarouselContainScroll,
|
|
11
|
+
CarouselInstance,
|
|
12
|
+
CarouselOptions,
|
|
13
|
+
CarouselStore,
|
|
14
|
+
CreateCarouselOptions,
|
|
15
|
+
} from "./types";
|
|
23
16
|
|
|
24
|
-
export
|
|
25
|
-
instances: Record<string, import("./store.js").CarouselInstance>;
|
|
26
|
-
create(id: string, options?: CarouselOptions): void;
|
|
27
|
-
destroy(id: string): void;
|
|
28
|
-
bindViewport(id: string, viewport: HTMLElement | null): void;
|
|
29
|
-
next(id: string): void;
|
|
30
|
-
previous(id: string): void;
|
|
31
|
-
goTo(id: string, index: number): void;
|
|
32
|
-
current(id: string): number;
|
|
33
|
-
count(id: string): number;
|
|
34
|
-
canNext(id: string): boolean;
|
|
35
|
-
canPrevious(id: string): boolean;
|
|
36
|
-
play(id: string): void;
|
|
37
|
-
pause(id: string): void;
|
|
38
|
-
isPlaying(id: string): boolean;
|
|
39
|
-
instance(id: string): import("embla-carousel").EmblaCarouselType | null;
|
|
40
|
-
handleKeydown(id: string, event: KeyboardEvent): void;
|
|
41
|
-
carouselProps(
|
|
42
|
-
id: string,
|
|
43
|
-
options?: { label?: string }
|
|
44
|
-
): Record<string, string | boolean | undefined>;
|
|
45
|
-
viewportProps(
|
|
46
|
-
id: string,
|
|
47
|
-
options?: { slideSize?: string | false }
|
|
48
|
-
): Record<string, string | number | boolean | undefined>;
|
|
49
|
-
slideProps(id: string, index: number): Record<string, string | boolean | undefined>;
|
|
50
|
-
indicatorProps(id: string, index: number): Record<string, string | boolean | undefined>;
|
|
51
|
-
destroyAll(): void;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function createCarouselStore(): CarouselStore;
|
|
17
|
+
export function createCarouselController(id?: string): import("./types").CarouselStore;
|
|
55
18
|
|
|
56
19
|
export default function carouselPlugin(): import("alpinejs").PluginCallback;
|
|
57
20
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,43 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import { Alpine, PluginCallback, BaseController } from '@ailuracode/alpine-core';
|
|
2
|
+
export { Unsubscribe } from '@ailuracode/alpine-core';
|
|
3
|
+
import { Alpine as Alpine$1 } from 'alpinejs';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Strongly-typed event map for the carousel controller.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Detail payload for the `slideChange` event.
|
|
10
|
+
*/
|
|
11
|
+
interface CarouselSlideChangeDetail {
|
|
12
|
+
readonly carouselId: string;
|
|
13
|
+
readonly index: number;
|
|
14
|
+
readonly totalSlides: number;
|
|
15
|
+
}
|
|
16
|
+
/** Detail payload for the `change` event (adapter sync). */
|
|
17
|
+
interface CarouselChangeDetail {
|
|
18
|
+
readonly carouselId?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Event map for carousel state changes. Emits `slideChange` on
|
|
22
|
+
* every slide transition and `change` when instance state updates.
|
|
23
|
+
*/
|
|
24
|
+
interface CarouselEvents extends Record<string, unknown> {
|
|
25
|
+
slideChange: CarouselSlideChangeDetail;
|
|
26
|
+
change: CarouselChangeDetail;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Public type contracts for `@ailuracode/alpine-carousel`.
|
|
31
|
+
*
|
|
32
|
+
* Every public type lives in a `types.ts` module so consumers can import
|
|
33
|
+
* them without pulling the implementation. The shape IS the contract.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** Slide alignment within the viewport. */
|
|
37
|
+
type CarouselAlign = "start" | "center" | "end" | ((viewSize: number, snapSize: number, index: number) => number);
|
|
38
|
+
/** Scroll containment behavior at the start and end of the carousel. */
|
|
39
|
+
type CarouselContainScroll = "trimSnaps" | "keepSnaps" | false;
|
|
40
|
+
/** Autoplay configuration options. */
|
|
5
41
|
type CarouselAutoplayOptions = {
|
|
6
42
|
delay?: number;
|
|
7
43
|
stopOnInteraction?: boolean;
|
|
@@ -9,18 +45,20 @@ type CarouselAutoplayOptions = {
|
|
|
9
45
|
stopOnFocusIn?: boolean;
|
|
10
46
|
stopWhenHidden?: boolean;
|
|
11
47
|
};
|
|
48
|
+
/** Options passed when creating a carousel instance. */
|
|
12
49
|
type CarouselOptions = {
|
|
13
50
|
loop?: boolean;
|
|
14
51
|
autoplay?: boolean;
|
|
15
52
|
autoplayOptions?: CarouselAutoplayOptions;
|
|
16
53
|
axis?: "x" | "y";
|
|
17
|
-
align?:
|
|
18
|
-
containScroll?:
|
|
54
|
+
align?: CarouselAlign;
|
|
55
|
+
containScroll?: CarouselContainScroll;
|
|
19
56
|
dragFree?: boolean;
|
|
20
57
|
duration?: number;
|
|
21
58
|
ariaLive?: "off" | "polite" | "assertive";
|
|
22
59
|
onChange?: (index: number) => void;
|
|
23
60
|
};
|
|
61
|
+
/** Readonly snapshot of carousel state exposed through stores and adapters. */
|
|
24
62
|
type CarouselInstance = {
|
|
25
63
|
currentIndex: number;
|
|
26
64
|
totalSlides: number;
|
|
@@ -33,10 +71,8 @@ type CarouselInstance = {
|
|
|
33
71
|
slidesInView: number[];
|
|
34
72
|
options: CarouselOptions;
|
|
35
73
|
ariaLive: "off" | "polite" | "assertive";
|
|
36
|
-
viewport: HTMLElement | null;
|
|
37
|
-
embla: EmblaCarouselType | null;
|
|
38
|
-
autoplay: AutoplayType | null;
|
|
39
74
|
};
|
|
75
|
+
/** Alpine-facing store surface. */
|
|
40
76
|
type CarouselStore = {
|
|
41
77
|
instances: Record<string, CarouselInstance>;
|
|
42
78
|
create(id: string, options?: CarouselOptions): void;
|
|
@@ -52,7 +88,6 @@ type CarouselStore = {
|
|
|
52
88
|
play(id: string): void;
|
|
53
89
|
pause(id: string): void;
|
|
54
90
|
isPlaying(id: string): boolean;
|
|
55
|
-
instance(id: string): EmblaCarouselType | null;
|
|
56
91
|
handleKeydown(id: string, event: KeyboardEvent): void;
|
|
57
92
|
carouselProps(id: string, options?: {
|
|
58
93
|
label?: string;
|
|
@@ -64,20 +99,109 @@ type CarouselStore = {
|
|
|
64
99
|
indicatorProps(id: string, index: number): Record<string, string | boolean | undefined>;
|
|
65
100
|
destroyAll(): void;
|
|
66
101
|
};
|
|
67
|
-
/**
|
|
68
|
-
|
|
102
|
+
/** Options accepted by the carousel plugin factory. */
|
|
103
|
+
interface CreateCarouselOptions {
|
|
104
|
+
readonly id?: string;
|
|
105
|
+
/**
|
|
106
|
+
* `$store.carousel` store key the Alpine plugin registers under.
|
|
107
|
+
* Defaults to {@link DEFAULT_CAROUSEL_STORE_KEY}. Set when the
|
|
108
|
+
* host already owns a `carousel` store or another toolkit plugin
|
|
109
|
+
* would collide on that name — the rename avoids the collision
|
|
110
|
+
* without touching the controller.
|
|
111
|
+
*/
|
|
112
|
+
readonly storeKey?: string;
|
|
113
|
+
}
|
|
114
|
+
/** Default `$store.carousel` key registered by {@link carouselPlugin}. */
|
|
115
|
+
declare const DEFAULT_CAROUSEL_STORE_KEY = "carousel";
|
|
116
|
+
/** Typed view of `Alpine` the carousel plugin uses internally. */
|
|
117
|
+
type CarouselAlpine = Alpine<{
|
|
118
|
+
carousel: CarouselStore;
|
|
119
|
+
}> & {
|
|
120
|
+
cleanup?(callback: () => void): void;
|
|
121
|
+
};
|
|
122
|
+
/** `Alpine.plugin()` callback signature. */
|
|
123
|
+
type CarouselPluginCallback = PluginCallback<Alpine$1>;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Carousel controller — the framework-agnostic core of
|
|
127
|
+
* `@ailuracode/alpine-carousel`. Manages a registry of carousel
|
|
128
|
+
* instances powered by Embla Carousel, with autoplay, resize
|
|
129
|
+
* observation, and visibility handling.
|
|
130
|
+
*
|
|
131
|
+
* Emits a typed `slideChange` event on every slide transition so
|
|
132
|
+
* consumers can react programmatically.
|
|
133
|
+
*/
|
|
69
134
|
|
|
70
|
-
/**
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
135
|
+
/**
|
|
136
|
+
* Headless carousel controller. Manages a registry of carousel
|
|
137
|
+
* instances powered by Embla Carousel.
|
|
138
|
+
*/
|
|
139
|
+
declare class CarouselController extends BaseController<CarouselEvents> {
|
|
140
|
+
#private;
|
|
141
|
+
constructor(id?: string);
|
|
142
|
+
/** Whether a carousel instance is registered. */
|
|
143
|
+
hasInstance(id: string): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Returns a shallow snapshot of all instances for adapter sync.
|
|
146
|
+
* Mutating the returned objects does not affect controller state.
|
|
147
|
+
*/
|
|
148
|
+
snapshotInstances(): Record<string, CarouselInstance>;
|
|
149
|
+
create(id: string, options?: CarouselOptions): void;
|
|
150
|
+
/** Destroy a single carousel instance by id. */
|
|
151
|
+
destroy(id: string): void;
|
|
152
|
+
/** Destroy all instances and the controller itself. */
|
|
153
|
+
destroy(): void;
|
|
154
|
+
bindViewport(id: string, viewport: HTMLElement | null): void;
|
|
155
|
+
next(id: string): void;
|
|
156
|
+
previous(id: string): void;
|
|
157
|
+
goTo(id: string, index: number): void;
|
|
158
|
+
current(id: string): number;
|
|
159
|
+
count(id: string): number;
|
|
160
|
+
canNext(id: string): boolean;
|
|
161
|
+
canPrevious(id: string): boolean;
|
|
162
|
+
play(id: string): void;
|
|
163
|
+
pause(id: string): void;
|
|
164
|
+
isPlaying(id: string): boolean;
|
|
165
|
+
handleKeydown(id: string, event: KeyboardEvent): void;
|
|
166
|
+
carouselProps(id: string, options?: {
|
|
167
|
+
label?: string;
|
|
168
|
+
}): Record<string, string | boolean | undefined>;
|
|
169
|
+
viewportProps(_id: string, options?: {
|
|
170
|
+
slideSize?: string | false;
|
|
171
|
+
}): Record<string, string | number | boolean | undefined>;
|
|
172
|
+
slideProps(id: string, index: number): Record<string, string | boolean | undefined>;
|
|
173
|
+
indicatorProps(id: string, index: number): Record<string, string | boolean | undefined>;
|
|
174
|
+
destroyAll(): void;
|
|
81
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Creates a CarouselController and returns the controller instance.
|
|
178
|
+
* Convenience for non-Alpine consumers.
|
|
179
|
+
*/
|
|
180
|
+
declare function createCarouselController(id?: string): CarouselController;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Alpine.js integration for `@ailuracode/alpine-carousel`.
|
|
184
|
+
*
|
|
185
|
+
* Thin adapter that wires {@link CarouselController} into
|
|
186
|
+
* `$store.carousel` and the `$carousel` magic.
|
|
187
|
+
*/
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Plugin factory — returns the `Alpine.plugin()` callback. Pass
|
|
191
|
+
* {@link CreateCarouselOptions} to configure the controller,
|
|
192
|
+
* or `{}` for the package defaults.
|
|
193
|
+
*/
|
|
194
|
+
declare function carouselPlugin(options?: CreateCarouselOptions): CarouselPluginCallback;
|
|
195
|
+
/** Builds typed carousel plugin options. */
|
|
196
|
+
declare function carouselOptions<const T extends CreateCarouselOptions>(options: T): T;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Store factory for `@ailuracode/alpine-carousel`.
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
/** Builds a {@link CarouselStore} backed by a new {@link CarouselController}. */
|
|
203
|
+
declare function createCarouselStore(): CarouselStore;
|
|
204
|
+
/** Builds a {@link CarouselStore} that mirrors the given controller. */
|
|
205
|
+
declare function createCarouselStoreFromController(controller: CarouselController): CarouselStore;
|
|
82
206
|
|
|
83
|
-
export { type CarouselAutoplayOptions, type CarouselInstance, type CarouselOptions, type CarouselStore, createCarouselStore, carouselPlugin as default };
|
|
207
|
+
export { type CarouselAlign, type CarouselAlpine, type CarouselAutoplayOptions, type CarouselChangeDetail, type CarouselContainScroll, CarouselController, type CarouselEvents, type CarouselInstance, type CarouselOptions, type CarouselPluginCallback, type CarouselSlideChangeDetail, type CarouselStore, type CreateCarouselOptions, DEFAULT_CAROUSEL_STORE_KEY, carouselOptions, carouselPlugin, createCarouselController, createCarouselStore, createCarouselStoreFromController, carouselPlugin as default };
|
package/dist/index.js
CHANGED
|
@@ -1,312 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import EmblaCarousel from "embla-carousel";
|
|
3
|
-
import Autoplay from "embla-carousel-autoplay";
|
|
4
|
-
function createInstance(options = {}) {
|
|
5
|
-
return {
|
|
6
|
-
currentIndex: 0,
|
|
7
|
-
totalSlides: 0,
|
|
8
|
-
progress: 0,
|
|
9
|
-
isFirst: true,
|
|
10
|
-
isLast: false,
|
|
11
|
-
isPlaying: false,
|
|
12
|
-
canNext: false,
|
|
13
|
-
canPrevious: false,
|
|
14
|
-
slidesInView: [],
|
|
15
|
-
options,
|
|
16
|
-
ariaLive: options.ariaLive ?? "polite",
|
|
17
|
-
viewport: null,
|
|
18
|
-
embla: null,
|
|
19
|
-
autoplay: null
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function toEmblaOptions(options) {
|
|
23
|
-
return {
|
|
24
|
-
loop: options.loop ?? false,
|
|
25
|
-
axis: options.axis ?? "x",
|
|
26
|
-
align: options.align ?? "start",
|
|
27
|
-
containScroll: options.containScroll ?? "trimSnaps",
|
|
28
|
-
dragFree: options.dragFree ?? false,
|
|
29
|
-
duration: options.duration ?? 25
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
function createAutoplayPlugin(options) {
|
|
33
|
-
if (!options.autoplay) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
const autoplayOptions = options.autoplayOptions ?? {};
|
|
37
|
-
const stopOnMouseEnter = autoplayOptions.stopOnMouseEnter ?? false;
|
|
38
|
-
const stopOnInteraction = autoplayOptions.stopOnInteraction ?? !stopOnMouseEnter;
|
|
39
|
-
return Autoplay({
|
|
40
|
-
delay: autoplayOptions.delay ?? 4e3,
|
|
41
|
-
stopOnInteraction,
|
|
42
|
-
stopOnMouseEnter,
|
|
43
|
-
stopOnFocusIn: autoplayOptions.stopOnFocusIn ?? true,
|
|
44
|
-
playOnInit: true
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
function syncFromEmbla(store, id) {
|
|
48
|
-
const instance = store.instances[id];
|
|
49
|
-
const embla = instance?.embla;
|
|
50
|
-
if (!(instance && embla)) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const previousIndex = instance.currentIndex;
|
|
54
|
-
instance.currentIndex = embla.selectedScrollSnap();
|
|
55
|
-
instance.totalSlides = embla.scrollSnapList().length;
|
|
56
|
-
instance.progress = embla.scrollProgress();
|
|
57
|
-
instance.canNext = embla.canScrollNext();
|
|
58
|
-
instance.canPrevious = embla.canScrollPrev();
|
|
59
|
-
instance.slidesInView = embla.slidesInView();
|
|
60
|
-
instance.isFirst = instance.currentIndex === 0;
|
|
61
|
-
instance.isLast = instance.totalSlides > 0 && instance.currentIndex === instance.totalSlides - 1;
|
|
62
|
-
instance.isPlaying = instance.autoplay?.isPlaying() ?? false;
|
|
63
|
-
if (previousIndex !== instance.currentIndex) {
|
|
64
|
-
instance.options.onChange?.(instance.currentIndex);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function destroyEmbla(instance, id, cleanups) {
|
|
68
|
-
cleanups.get(id)?.();
|
|
69
|
-
cleanups.delete(id);
|
|
70
|
-
instance.embla?.destroy();
|
|
71
|
-
instance.embla = null;
|
|
72
|
-
instance.autoplay = null;
|
|
73
|
-
instance.viewport = null;
|
|
74
|
-
}
|
|
75
|
-
function addCleanup(id, cleanups, cleanup) {
|
|
76
|
-
const previous = cleanups.get(id);
|
|
77
|
-
cleanups.set(id, () => {
|
|
78
|
-
previous?.();
|
|
79
|
-
cleanup();
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
function setupVisibilityAutoplay(id, instance, cleanups) {
|
|
83
|
-
const stopWhenHidden = instance.options.autoplayOptions?.stopWhenHidden ?? true;
|
|
84
|
-
if (!(instance.options.autoplay && stopWhenHidden)) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const onVisibilityChange = () => {
|
|
88
|
-
if (document.hidden) {
|
|
89
|
-
instance.autoplay?.stop();
|
|
90
|
-
} else {
|
|
91
|
-
instance.autoplay?.play();
|
|
92
|
-
}
|
|
93
|
-
instance.isPlaying = instance.autoplay?.isPlaying() ?? false;
|
|
94
|
-
};
|
|
95
|
-
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
96
|
-
addCleanup(
|
|
97
|
-
id,
|
|
98
|
-
cleanups,
|
|
99
|
-
() => document.removeEventListener("visibilitychange", onVisibilityChange)
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
function setupResizeObserver(viewport, store, id, cleanups) {
|
|
103
|
-
if (typeof ResizeObserver === "undefined") {
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const observer = new ResizeObserver(() => {
|
|
107
|
-
store.instances[id]?.embla?.reInit();
|
|
108
|
-
syncFromEmbla(store, id);
|
|
109
|
-
});
|
|
110
|
-
observer.observe(viewport);
|
|
111
|
-
addCleanup(id, cleanups, () => observer.disconnect());
|
|
112
|
-
}
|
|
113
|
-
function getOrCreate(store, id, options) {
|
|
114
|
-
if (!store.instances[id]) {
|
|
115
|
-
store.instances[id] = createInstance(options);
|
|
116
|
-
} else if (options) {
|
|
117
|
-
store.instances[id].options = { ...store.instances[id].options, ...options };
|
|
118
|
-
store.instances[id].ariaLive = options.ariaLive ?? store.instances[id].ariaLive;
|
|
119
|
-
}
|
|
120
|
-
return store.instances[id];
|
|
121
|
-
}
|
|
122
|
-
function initEmbla(store, id, viewport, cleanups) {
|
|
123
|
-
const instance = store.instances[id];
|
|
124
|
-
if (!instance) {
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
destroyEmbla(instance, id, cleanups);
|
|
128
|
-
instance.viewport = viewport;
|
|
129
|
-
const plugins = [];
|
|
130
|
-
const autoplay = createAutoplayPlugin(instance.options);
|
|
131
|
-
if (autoplay) {
|
|
132
|
-
plugins.push(autoplay);
|
|
133
|
-
instance.autoplay = autoplay;
|
|
134
|
-
}
|
|
135
|
-
const embla = EmblaCarousel(viewport, toEmblaOptions(instance.options), plugins);
|
|
136
|
-
instance.embla = embla;
|
|
137
|
-
const sync = () => syncFromEmbla(store, id);
|
|
138
|
-
embla.on("select", sync);
|
|
139
|
-
embla.on("scroll", sync);
|
|
140
|
-
embla.on("reInit", sync);
|
|
141
|
-
embla.on("autoplay:play", sync);
|
|
142
|
-
embla.on("autoplay:stop", sync);
|
|
143
|
-
sync();
|
|
144
|
-
setupResizeObserver(viewport, store, id, cleanups);
|
|
145
|
-
setupVisibilityAutoplay(id, instance, cleanups);
|
|
146
|
-
if (typeof requestAnimationFrame !== "undefined") {
|
|
147
|
-
requestAnimationFrame(() => {
|
|
148
|
-
instance.embla?.reInit();
|
|
149
|
-
syncFromEmbla(store, id);
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
function createCarouselStore() {
|
|
154
|
-
const cleanups = /* @__PURE__ */ new Map();
|
|
155
|
-
const store = {
|
|
156
|
-
instances: {},
|
|
157
|
-
create(id, options = {}) {
|
|
158
|
-
getOrCreate(this, id, options);
|
|
159
|
-
},
|
|
160
|
-
destroy(id) {
|
|
161
|
-
const instance = this.instances[id];
|
|
162
|
-
if (!instance) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
destroyEmbla(instance, id, cleanups);
|
|
166
|
-
delete this.instances[id];
|
|
167
|
-
},
|
|
168
|
-
bindViewport(id, viewport) {
|
|
169
|
-
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
if (!viewport) {
|
|
173
|
-
const instance = this.instances[id];
|
|
174
|
-
if (instance) {
|
|
175
|
-
destroyEmbla(instance, id, cleanups);
|
|
176
|
-
}
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
getOrCreate(this, id);
|
|
180
|
-
initEmbla(this, id, viewport, cleanups);
|
|
181
|
-
},
|
|
182
|
-
next(id) {
|
|
183
|
-
this.instances[id]?.embla?.scrollNext();
|
|
184
|
-
},
|
|
185
|
-
previous(id) {
|
|
186
|
-
this.instances[id]?.embla?.scrollPrev();
|
|
187
|
-
},
|
|
188
|
-
goTo(id, index) {
|
|
189
|
-
this.instances[id]?.embla?.scrollTo(index);
|
|
190
|
-
},
|
|
191
|
-
current(id) {
|
|
192
|
-
return this.instances[id]?.currentIndex ?? 0;
|
|
193
|
-
},
|
|
194
|
-
count(id) {
|
|
195
|
-
return this.instances[id]?.totalSlides ?? 0;
|
|
196
|
-
},
|
|
197
|
-
canNext(id) {
|
|
198
|
-
return this.instances[id]?.canNext ?? false;
|
|
199
|
-
},
|
|
200
|
-
canPrevious(id) {
|
|
201
|
-
return this.instances[id]?.canPrevious ?? false;
|
|
202
|
-
},
|
|
203
|
-
play(id) {
|
|
204
|
-
this.instances[id]?.autoplay?.play();
|
|
205
|
-
const instance = this.instances[id];
|
|
206
|
-
if (instance) {
|
|
207
|
-
instance.isPlaying = instance.autoplay?.isPlaying() ?? false;
|
|
208
|
-
}
|
|
209
|
-
},
|
|
210
|
-
pause(id) {
|
|
211
|
-
this.instances[id]?.autoplay?.stop();
|
|
212
|
-
const instance = this.instances[id];
|
|
213
|
-
if (instance) {
|
|
214
|
-
instance.isPlaying = instance.autoplay?.isPlaying() ?? false;
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
isPlaying(id) {
|
|
218
|
-
return this.instances[id]?.isPlaying ?? false;
|
|
219
|
-
},
|
|
220
|
-
instance(id) {
|
|
221
|
-
return this.instances[id]?.embla ?? null;
|
|
222
|
-
},
|
|
223
|
-
handleKeydown(id, event) {
|
|
224
|
-
const instance = this.instances[id];
|
|
225
|
-
if (!instance?.embla) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
switch (event.key) {
|
|
229
|
-
case "ArrowLeft":
|
|
230
|
-
case "ArrowUp":
|
|
231
|
-
event.preventDefault();
|
|
232
|
-
this.previous(id);
|
|
233
|
-
break;
|
|
234
|
-
case "ArrowRight":
|
|
235
|
-
case "ArrowDown":
|
|
236
|
-
event.preventDefault();
|
|
237
|
-
this.next(id);
|
|
238
|
-
break;
|
|
239
|
-
case "Home":
|
|
240
|
-
event.preventDefault();
|
|
241
|
-
this.goTo(id, 0);
|
|
242
|
-
break;
|
|
243
|
-
case "End": {
|
|
244
|
-
event.preventDefault();
|
|
245
|
-
const last = this.count(id) - 1;
|
|
246
|
-
if (last >= 0) {
|
|
247
|
-
this.goTo(id, last);
|
|
248
|
-
}
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
default:
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
carouselProps(id, options = {}) {
|
|
256
|
-
const instance = this.instances[id];
|
|
257
|
-
return {
|
|
258
|
-
role: "region",
|
|
259
|
-
"aria-roledescription": "carousel",
|
|
260
|
-
"aria-live": instance?.ariaLive ?? "polite",
|
|
261
|
-
"aria-label": options.label
|
|
262
|
-
};
|
|
263
|
-
},
|
|
264
|
-
viewportProps(_id, options = {}) {
|
|
265
|
-
const props = {
|
|
266
|
-
tabindex: 0
|
|
267
|
-
};
|
|
268
|
-
if (options.slideSize !== false) {
|
|
269
|
-
props.style = `--slide-size: ${options.slideSize ?? "100%"}`;
|
|
270
|
-
}
|
|
271
|
-
return props;
|
|
272
|
-
},
|
|
273
|
-
slideProps(id, index) {
|
|
274
|
-
const current = this.current(id);
|
|
275
|
-
const total = this.count(id);
|
|
276
|
-
return {
|
|
277
|
-
role: "group",
|
|
278
|
-
"aria-roledescription": "slide",
|
|
279
|
-
"aria-label": `${index + 1} of ${total}`,
|
|
280
|
-
"aria-hidden": current !== index ? true : void 0
|
|
281
|
-
};
|
|
282
|
-
},
|
|
283
|
-
indicatorProps(id, index) {
|
|
284
|
-
const selected = this.current(id) === index;
|
|
285
|
-
return {
|
|
286
|
-
type: "button",
|
|
287
|
-
"aria-label": `Go to slide ${index + 1}`,
|
|
288
|
-
"aria-current": selected ? "true" : void 0
|
|
289
|
-
};
|
|
290
|
-
},
|
|
291
|
-
destroyAll() {
|
|
292
|
-
for (const id of Object.keys(this.instances)) {
|
|
293
|
-
this.destroy(id);
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
return store;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// src/index.ts
|
|
301
|
-
function carouselPlugin() {
|
|
302
|
-
return function registerCarousel(Alpine) {
|
|
303
|
-
const store = createCarouselStore();
|
|
304
|
-
Alpine.store("carousel", store);
|
|
305
|
-
Alpine.magic("carousel", () => Alpine.store("carousel"));
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
export {
|
|
309
|
-
createCarouselStore,
|
|
310
|
-
carouselPlugin as default
|
|
311
|
-
};
|
|
312
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import{BaseController as C,generateId as m}from"@ailuracode/alpine-core";import h from"embla-carousel";import v from"embla-carousel-autoplay";function x(s={}){return{currentIndex:0,totalSlides:0,progress:0,isFirst:!0,isLast:!1,isPlaying:!1,canNext:!1,canPrevious:!1,slidesInView:[],options:s,ariaLive:s.ariaLive??"polite",viewport:null,embla:null,autoplay:null}}function I(s){return{loop:s.loop??!1,axis:s.axis??"x",align:s.align??"start",containScroll:s.containScroll??"trimSnaps",dragFree:s.dragFree??!1,duration:s.duration??25}}function P(s){if(!s.autoplay)return null;let e=s.autoplayOptions??{},n=e.stopOnMouseEnter??!1,r=e.stopOnInteraction??!n;return v({delay:e.delay??4e3,stopOnInteraction:r,stopOnMouseEnter:n,stopOnFocusIn:e.stopOnFocusIn??!0,playOnInit:!0})}function O(s){return{currentIndex:s.currentIndex,totalSlides:s.totalSlides,progress:s.progress,isFirst:s.isFirst,isLast:s.isLast,isPlaying:s.isPlaying,canNext:s.canNext,canPrevious:s.canPrevious,slidesInView:[...s.slidesInView],options:{...s.options},ariaLive:s.ariaLive}}var u=class extends C{#e={};#s=new Map;constructor(e){super(e??m("carousel"))}hasInstance(e){return e in this.#e}snapshotInstances(){let e={};for(let[n,r]of Object.entries(this.#e))e[n]=O(r);return e}create(e,n={}){this.isDestroyed||(this.#o(e,n),this.#n(e))}destroy(e){if(e!==void 0){if(this.isDestroyed||!this.#e[e])return;this.#r(e),delete this.#e[e],this.#n(e)}else this.destroyAll(),super.destroy()}bindViewport(e,n){if(!this.isDestroyed&&!(typeof window>"u"||typeof document>"u")){if(!n){this.#e[e]&&this.#r(e);return}this.#o(e),this.#u(e,n),this.#n(e)}}next(e){this.#e[e]?.embla?.scrollNext()}previous(e){this.#e[e]?.embla?.scrollPrev()}goTo(e,n){this.#e[e]?.embla?.scrollTo(n)}current(e){return this.#e[e]?.currentIndex??0}count(e){return this.#e[e]?.totalSlides??0}canNext(e){return this.#e[e]?.canNext??!1}canPrevious(e){return this.#e[e]?.canPrevious??!1}play(e){this.#e[e]?.autoplay?.play();let n=this.#e[e];n&&(n.isPlaying=n.autoplay?.isPlaying()??!1,this.#n(e))}pause(e){this.#e[e]?.autoplay?.stop();let n=this.#e[e];n&&(n.isPlaying=n.autoplay?.isPlaying()??!1,this.#n(e))}isPlaying(e){return this.#e[e]?.isPlaying??!1}handleKeydown(e,n){if(this.#e[e]?.embla)switch(n.key){case"ArrowLeft":case"ArrowUp":n.preventDefault(),this.previous(e);break;case"ArrowRight":case"ArrowDown":n.preventDefault(),this.next(e);break;case"Home":n.preventDefault(),this.goTo(e,0);break;case"End":{n.preventDefault();let t=this.count(e)-1;t>=0&&this.goTo(e,t);break}default:break}}carouselProps(e,n={}){return{role:"region","aria-roledescription":"carousel","aria-live":this.#e[e]?.ariaLive??"polite","aria-label":n.label}}viewportProps(e,n={}){let r={tabindex:0};return n.slideSize!==!1&&(r.style=`--slide-size: ${n.slideSize??"100%"}`),r}slideProps(e,n){let r=this.current(e),t=this.count(e);return{role:"group","aria-roledescription":"slide","aria-label":`${n+1} of ${t}`,"aria-hidden":r!==n?!0:void 0}}indicatorProps(e,n){let r=this.current(e)===n;return{type:"button","aria-label":`Go to slide ${n+1}`,"aria-current":r?"true":void 0}}destroyAll(){for(let e of Object.keys(this.#e))this.destroy(e);this.#n()}#n(e){this.emit("change",{carouselId:e})}#o(e,n){return this.#e[e]?n&&(this.#e[e].options={...this.#e[e].options,...n},this.#e[e].ariaLive=n.ariaLive??this.#e[e].ariaLive):this.#e[e]=x(n),this.#e[e]}#t(e){let n=this.#e[e],r=n?.embla;if(!(n&&r))return;let t=n.currentIndex;n.currentIndex=r.selectedScrollSnap(),n.totalSlides=r.scrollSnapList().length,n.progress=r.scrollProgress(),n.canNext=r.canScrollNext(),n.canPrevious=r.canScrollPrev(),n.slidesInView=r.slidesInView(),n.isFirst=n.currentIndex===0,n.isLast=n.totalSlides>0&&n.currentIndex===n.totalSlides-1,n.isPlaying=n.autoplay?.isPlaying()??!1,t!==n.currentIndex&&(this.emit("slideChange",{carouselId:e,index:n.currentIndex,totalSlides:n.totalSlides}),n.options.onChange?.(n.currentIndex)),this.#n(e)}#r(e){this.#s.get(e)?.(),this.#s.delete(e);let n=this.#e[e];n?.embla?.destroy(),n&&(n.embla=null,n.autoplay=null,n.viewport=null)}#i(e,n){let r=this.#s.get(e);this.#s.set(e,()=>{r?.(),n()})}#a(e,n){let r=n.options.autoplayOptions?.stopWhenHidden??!0;if(!(n.options.autoplay&&r))return;let t=()=>{document.hidden?n.autoplay?.stop():n.autoplay?.play(),n.isPlaying=n.autoplay?.isPlaying()??!1};document.addEventListener("visibilitychange",t),this.#i(e,()=>document.removeEventListener("visibilitychange",t))}#l(e,n){if(typeof ResizeObserver>"u")return;let r=new ResizeObserver(()=>{this.#e[e]?.embla?.reInit(),this.#t(e)});r.observe(n),this.#i(e,()=>r.disconnect())}#u(e,n){let r=this.#e[e];if(!r)return;this.#r(e),r.viewport=n;let t=[],o=P(r.options);o&&(t.push(o),r.autoplay=o);let i=h(n,I(r.options),t);r.embla=i;let l=()=>this.#t(e);i.on("select",l),i.on("scroll",l),i.on("reInit",l),i.on("autoplay:play",l),i.on("autoplay:stop",l),l(),this.#l(e,n),this.#a(e,r),typeof requestAnimationFrame<"u"&&requestAnimationFrame(()=>{r.embla?.reInit(),this.#t(e)})}};function A(s){return new u(s)}import{bridgeControllerStore as R,syncRecordFromSnapshot as T}from"@ailuracode/alpine-core";import{syncRecordFromSnapshot as S}from"@ailuracode/alpine-core";function E(s,e){w(s,e.snapshotInstances())}function w(s,e){S(s,e)}function L(){return c(new u)}function c(s){let e={},n=()=>{E(e,s)},r={instances:e,create:(t,o)=>{s.create(t,o),n()},destroy:t=>{s.destroy(t),n()},bindViewport:(t,o)=>{s.bindViewport(t,o),n()},next:t=>{s.next(t)},previous:t=>{s.previous(t)},goTo:(t,o)=>{s.goTo(t,o)},current:t=>s.current(t),count:t=>s.count(t),canNext:t=>s.canNext(t),canPrevious:t=>s.canPrevious(t),play:t=>{s.play(t),n()},pause:t=>{s.pause(t),n()},isPlaying:t=>s.isPlaying(t),handleKeydown:(t,o)=>s.handleKeydown(t,o),carouselProps:(t,o)=>s.carouselProps(t,o),viewportProps:(t,o)=>s.viewportProps(t,o),slideProps:(t,o)=>s.slideProps(t,o),indicatorProps:(t,o)=>s.indicatorProps(t,o),destroyAll:()=>{s.destroyAll(),n()}};return s.on("change",n),s.on("slideChange",n),r}var g="carousel";function y(s={}){let e=s.storeKey??g;return function(r){let t=r,o=new u(s.id);R({alpine:t,storeKey:e,store:c(o),controller:o,packageName:"carousel",subscribe:i=>{i.current=a=>i.instances[a]?.currentIndex??0,i.count=a=>i.instances[a]?.totalSlides??0,i.canNext=a=>i.instances[a]?.canNext??!1,i.canPrevious=a=>i.instances[a]?.canPrevious??!1,i.isPlaying=a=>i.instances[a]?.isPlaying??!1,i.slideProps=(a,p)=>{let d=i.current(a),b=i.count(a);return{role:"group","aria-roledescription":"slide","aria-label":`${p+1} of ${b}`,"aria-hidden":d!==p?!0:void 0}},i.indicatorProps=(a,p)=>{let d=i.current(a)===p;return{type:"button","aria-label":`Go to slide ${p+1}`,"aria-current":d?"true":void 0}};let l=()=>{T(i.instances,o.snapshotInstances())},f=[o.on("change",l),o.on("slideChange",l)];return()=>{for(let a of f)a()}}})}}function F(s){return s}export{u as CarouselController,g as DEFAULT_CAROUSEL_STORE_KEY,F as carouselOptions,y as carouselPlugin,A as createCarouselController,L as createCarouselStore,c as createCarouselStoreFromController,y as default};
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ailuracode/alpine-carousel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Alpine.js headless accessible carousel store powered by Embla Carousel",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "ailuracode",
|
|
8
|
+
"sideEffects": false,
|
|
8
9
|
"publishConfig": {
|
|
9
10
|
"access": "public"
|
|
10
11
|
},
|
|
@@ -35,7 +36,13 @@
|
|
|
35
36
|
"embla-carousel": "^8.6.0",
|
|
36
37
|
"embla-carousel-autoplay": "^8.6.0"
|
|
37
38
|
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/alpinejs": "^3.13.11",
|
|
41
|
+
"alpinejs": "^3.15.12",
|
|
42
|
+
"@ailuracode/alpine-core": "0.3.0"
|
|
43
|
+
},
|
|
38
44
|
"peerDependencies": {
|
|
45
|
+
"@ailuracode/alpine-core": "^0.3.0",
|
|
39
46
|
"alpinejs": "^3.0.0",
|
|
40
47
|
"@types/alpinejs": "^3.13.11"
|
|
41
48
|
},
|
|
@@ -54,8 +61,30 @@
|
|
|
54
61
|
"accessibility",
|
|
55
62
|
"headless"
|
|
56
63
|
],
|
|
64
|
+
"toolkit": {
|
|
65
|
+
"bundleBudget": {
|
|
66
|
+
"category": "complex-feature"
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"size-limit": [
|
|
70
|
+
{
|
|
71
|
+
"name": "full surface",
|
|
72
|
+
"path": "dist/index.js",
|
|
73
|
+
"import": "*",
|
|
74
|
+
"ignore": [
|
|
75
|
+
"alpinejs",
|
|
76
|
+
"@ailuracode/alpine-core",
|
|
77
|
+
"@types/alpinejs"
|
|
78
|
+
],
|
|
79
|
+
"gzip": true,
|
|
80
|
+
"brotli": true,
|
|
81
|
+
"limit": "12 kB"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
57
84
|
"scripts": {
|
|
58
|
-
"build": "tsup src/index.ts --format esm --dts --clean --
|
|
59
|
-
"
|
|
85
|
+
"build": "tsup src/index.ts --format esm --dts --clean --out-dir dist --minify && cp src/global.d.ts dist/global.d.ts",
|
|
86
|
+
"size": "size-limit",
|
|
87
|
+
"test": "vitest run --config ../../vitest.config.ts packages/carousel",
|
|
88
|
+
"test:e2e": "playwright test --config playwright.config.ts"
|
|
60
89
|
}
|
|
61
90
|
}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts","../src/index.ts"],"sourcesContent":["import EmblaCarousel, { type EmblaCarouselType, type EmblaOptionsType } from \"embla-carousel\";\nimport Autoplay, { type AutoplayType } from \"embla-carousel-autoplay\";\n\nexport type CarouselAutoplayOptions = {\n delay?: number;\n stopOnInteraction?: boolean;\n stopOnMouseEnter?: boolean;\n stopOnFocusIn?: boolean;\n stopWhenHidden?: boolean;\n};\n\nexport type CarouselOptions = {\n loop?: boolean;\n autoplay?: boolean;\n autoplayOptions?: CarouselAutoplayOptions;\n axis?: \"x\" | \"y\";\n align?: EmblaOptionsType[\"align\"];\n containScroll?: EmblaOptionsType[\"containScroll\"];\n dragFree?: boolean;\n duration?: number;\n ariaLive?: \"off\" | \"polite\" | \"assertive\";\n onChange?: (index: number) => void;\n};\n\nexport type CarouselInstance = {\n currentIndex: number;\n totalSlides: number;\n progress: number;\n isFirst: boolean;\n isLast: boolean;\n isPlaying: boolean;\n canNext: boolean;\n canPrevious: boolean;\n slidesInView: number[];\n options: CarouselOptions;\n ariaLive: \"off\" | \"polite\" | \"assertive\";\n viewport: HTMLElement | null;\n embla: EmblaCarouselType | null;\n autoplay: AutoplayType | null;\n};\n\nexport type CarouselStore = {\n instances: Record<string, CarouselInstance>;\n create(id: string, options?: CarouselOptions): void;\n destroy(id: string): void;\n bindViewport(id: string, viewport: HTMLElement | null): void;\n next(id: string): void;\n previous(id: string): void;\n goTo(id: string, index: number): void;\n current(id: string): number;\n count(id: string): number;\n canNext(id: string): boolean;\n canPrevious(id: string): boolean;\n play(id: string): void;\n pause(id: string): void;\n isPlaying(id: string): boolean;\n instance(id: string): EmblaCarouselType | null;\n handleKeydown(id: string, event: KeyboardEvent): void;\n carouselProps(\n id: string,\n options?: { label?: string }\n ): Record<string, string | boolean | undefined>;\n viewportProps(\n id: string,\n options?: { slideSize?: string | false }\n ): Record<string, string | number | boolean | undefined>;\n slideProps(id: string, index: number): Record<string, string | boolean | undefined>;\n indicatorProps(id: string, index: number): Record<string, string | boolean | undefined>;\n destroyAll(): void;\n};\n\nfunction createInstance(options: CarouselOptions = {}): CarouselInstance {\n return {\n currentIndex: 0,\n totalSlides: 0,\n progress: 0,\n isFirst: true,\n isLast: false,\n isPlaying: false,\n canNext: false,\n canPrevious: false,\n slidesInView: [],\n options,\n ariaLive: options.ariaLive ?? \"polite\",\n viewport: null,\n embla: null,\n autoplay: null,\n };\n}\n\nfunction toEmblaOptions(options: CarouselOptions): EmblaOptionsType {\n return {\n loop: options.loop ?? false,\n axis: options.axis ?? \"x\",\n align: options.align ?? \"start\",\n containScroll: options.containScroll ?? \"trimSnaps\",\n dragFree: options.dragFree ?? false,\n duration: options.duration ?? 25,\n };\n}\n\nfunction createAutoplayPlugin(options: CarouselOptions): AutoplayType | null {\n if (!options.autoplay) {\n return null;\n }\n\n const autoplayOptions = options.autoplayOptions ?? {};\n const stopOnMouseEnter = autoplayOptions.stopOnMouseEnter ?? false;\n const stopOnInteraction = autoplayOptions.stopOnInteraction ?? !stopOnMouseEnter;\n\n return Autoplay({\n delay: autoplayOptions.delay ?? 4000,\n stopOnInteraction,\n stopOnMouseEnter,\n stopOnFocusIn: autoplayOptions.stopOnFocusIn ?? true,\n playOnInit: true,\n });\n}\n\nfunction syncFromEmbla(store: CarouselStore, id: string): void {\n const instance = store.instances[id];\n const embla = instance?.embla;\n if (!(instance && embla)) {\n return;\n }\n\n const previousIndex = instance.currentIndex;\n instance.currentIndex = embla.selectedScrollSnap();\n instance.totalSlides = embla.scrollSnapList().length;\n instance.progress = embla.scrollProgress();\n instance.canNext = embla.canScrollNext();\n instance.canPrevious = embla.canScrollPrev();\n instance.slidesInView = embla.slidesInView();\n instance.isFirst = instance.currentIndex === 0;\n instance.isLast = instance.totalSlides > 0 && instance.currentIndex === instance.totalSlides - 1;\n instance.isPlaying = instance.autoplay?.isPlaying() ?? false;\n\n if (previousIndex !== instance.currentIndex) {\n instance.options.onChange?.(instance.currentIndex);\n }\n}\n\nfunction destroyEmbla(\n instance: CarouselInstance,\n id: string,\n cleanups: Map<string, () => void>\n): void {\n cleanups.get(id)?.();\n cleanups.delete(id);\n instance.embla?.destroy();\n instance.embla = null;\n instance.autoplay = null;\n instance.viewport = null;\n}\n\nfunction addCleanup(id: string, cleanups: Map<string, () => void>, cleanup: () => void): void {\n const previous = cleanups.get(id);\n cleanups.set(id, () => {\n previous?.();\n cleanup();\n });\n}\n\nfunction setupVisibilityAutoplay(\n id: string,\n instance: CarouselInstance,\n cleanups: Map<string, () => void>\n): void {\n const stopWhenHidden = instance.options.autoplayOptions?.stopWhenHidden ?? true;\n if (!(instance.options.autoplay && stopWhenHidden)) {\n return;\n }\n\n const onVisibilityChange = () => {\n if (document.hidden) {\n instance.autoplay?.stop();\n } else {\n instance.autoplay?.play();\n }\n instance.isPlaying = instance.autoplay?.isPlaying() ?? false;\n };\n\n document.addEventListener(\"visibilitychange\", onVisibilityChange);\n addCleanup(id, cleanups, () =>\n document.removeEventListener(\"visibilitychange\", onVisibilityChange)\n );\n}\n\nfunction setupResizeObserver(\n viewport: HTMLElement,\n store: CarouselStore,\n id: string,\n cleanups: Map<string, () => void>\n): void {\n if (typeof ResizeObserver === \"undefined\") {\n return;\n }\n\n const observer = new ResizeObserver(() => {\n store.instances[id]?.embla?.reInit();\n syncFromEmbla(store, id);\n });\n observer.observe(viewport);\n addCleanup(id, cleanups, () => observer.disconnect());\n}\n\nfunction getOrCreate(\n store: CarouselStore,\n id: string,\n options?: CarouselOptions\n): CarouselInstance {\n if (!store.instances[id]) {\n store.instances[id] = createInstance(options);\n } else if (options) {\n store.instances[id].options = { ...store.instances[id].options, ...options };\n store.instances[id].ariaLive = options.ariaLive ?? store.instances[id].ariaLive;\n }\n return store.instances[id];\n}\n\nfunction initEmbla(\n store: CarouselStore,\n id: string,\n viewport: HTMLElement,\n cleanups: Map<string, () => void>\n): void {\n const instance = store.instances[id];\n if (!instance) {\n return;\n }\n\n destroyEmbla(instance, id, cleanups);\n instance.viewport = viewport;\n\n const plugins = [];\n const autoplay = createAutoplayPlugin(instance.options);\n if (autoplay) {\n plugins.push(autoplay);\n instance.autoplay = autoplay;\n }\n\n const embla = EmblaCarousel(viewport, toEmblaOptions(instance.options), plugins);\n instance.embla = embla;\n\n const sync = () => syncFromEmbla(store, id);\n embla.on(\"select\", sync);\n embla.on(\"scroll\", sync);\n embla.on(\"reInit\", sync);\n embla.on(\"autoplay:play\", sync);\n embla.on(\"autoplay:stop\", sync);\n sync();\n setupResizeObserver(viewport, store, id, cleanups);\n setupVisibilityAutoplay(id, instance, cleanups);\n\n if (typeof requestAnimationFrame !== \"undefined\") {\n requestAnimationFrame(() => {\n instance.embla?.reInit();\n syncFromEmbla(store, id);\n });\n }\n}\n\n/** Creates the headless carousel store powered by Embla Carousel. */\nexport function createCarouselStore(): CarouselStore {\n const cleanups = new Map<string, () => void>();\n\n const store: CarouselStore = {\n instances: {},\n\n create(id, options = {}) {\n getOrCreate(this, id, options);\n },\n\n destroy(id) {\n const instance = this.instances[id];\n if (!instance) {\n return;\n }\n destroyEmbla(instance, id, cleanups);\n delete this.instances[id];\n },\n\n bindViewport(id, viewport) {\n if (typeof window === \"undefined\" || typeof document === \"undefined\") {\n return;\n }\n\n if (!viewport) {\n const instance = this.instances[id];\n if (instance) {\n destroyEmbla(instance, id, cleanups);\n }\n return;\n }\n\n getOrCreate(this, id);\n initEmbla(this, id, viewport, cleanups);\n },\n\n next(id) {\n this.instances[id]?.embla?.scrollNext();\n },\n\n previous(id) {\n this.instances[id]?.embla?.scrollPrev();\n },\n\n goTo(id, index) {\n this.instances[id]?.embla?.scrollTo(index);\n },\n\n current(id) {\n return this.instances[id]?.currentIndex ?? 0;\n },\n\n count(id) {\n return this.instances[id]?.totalSlides ?? 0;\n },\n\n canNext(id) {\n return this.instances[id]?.canNext ?? false;\n },\n\n canPrevious(id) {\n return this.instances[id]?.canPrevious ?? false;\n },\n\n play(id) {\n this.instances[id]?.autoplay?.play();\n const instance = this.instances[id];\n if (instance) {\n instance.isPlaying = instance.autoplay?.isPlaying() ?? false;\n }\n },\n\n pause(id) {\n this.instances[id]?.autoplay?.stop();\n const instance = this.instances[id];\n if (instance) {\n instance.isPlaying = instance.autoplay?.isPlaying() ?? false;\n }\n },\n\n isPlaying(id) {\n return this.instances[id]?.isPlaying ?? false;\n },\n\n instance(id) {\n return this.instances[id]?.embla ?? null;\n },\n\n handleKeydown(id, event) {\n const instance = this.instances[id];\n if (!instance?.embla) {\n return;\n }\n\n switch (event.key) {\n case \"ArrowLeft\":\n case \"ArrowUp\":\n event.preventDefault();\n this.previous(id);\n break;\n case \"ArrowRight\":\n case \"ArrowDown\":\n event.preventDefault();\n this.next(id);\n break;\n case \"Home\":\n event.preventDefault();\n this.goTo(id, 0);\n break;\n case \"End\": {\n event.preventDefault();\n const last = this.count(id) - 1;\n if (last >= 0) {\n this.goTo(id, last);\n }\n break;\n }\n default:\n break;\n }\n },\n\n carouselProps(id, options = {}) {\n const instance = this.instances[id];\n return {\n role: \"region\",\n \"aria-roledescription\": \"carousel\",\n \"aria-live\": instance?.ariaLive ?? \"polite\",\n \"aria-label\": options.label,\n };\n },\n\n viewportProps(_id, options = {}) {\n const props: Record<string, string | number | boolean | undefined> = {\n tabindex: 0,\n };\n\n if (options.slideSize !== false) {\n props.style = `--slide-size: ${options.slideSize ?? \"100%\"}`;\n }\n\n return props;\n },\n\n slideProps(id, index) {\n const current = this.current(id);\n const total = this.count(id);\n return {\n role: \"group\",\n \"aria-roledescription\": \"slide\",\n \"aria-label\": `${index + 1} of ${total}`,\n \"aria-hidden\": current !== index ? true : undefined,\n };\n },\n\n indicatorProps(id, index) {\n const selected = this.current(id) === index;\n return {\n type: \"button\",\n \"aria-label\": `Go to slide ${index + 1}`,\n \"aria-current\": selected ? \"true\" : undefined,\n };\n },\n\n destroyAll() {\n for (const id of Object.keys(this.instances)) {\n this.destroy(id);\n }\n },\n };\n\n return store;\n}\n","import type AlpineType from \"alpinejs\";\nimport { type CarouselStore, createCarouselStore } from \"./store.js\";\n\nexport {\n type CarouselAutoplayOptions,\n type CarouselInstance,\n type CarouselOptions,\n type CarouselStore,\n createCarouselStore,\n} from \"./store.js\";\n\n/** Alpine.js carousel plugin. Registers `$store.carousel`. */\nexport default function carouselPlugin(): AlpineType.PluginCallback {\n return function registerCarousel(Alpine) {\n const store = createCarouselStore();\n Alpine.store(\"carousel\", store);\n Alpine.magic(\"carousel\", () => Alpine.store(\"carousel\"));\n };\n}\n\ndeclare global {\n namespace Alpine {\n interface Stores {\n carousel: CarouselStore;\n }\n interface Magics<T> {\n $carousel: CarouselStore;\n }\n }\n}\n"],"mappings":"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","names":[]}
|