@brandonsoccer22/gsap-editorial-carousel 0.1.2 → 0.1.3
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 +1 -1
- package/dist/index.cjs +605 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +79 -0
- package/dist/index.d.ts +79 -0
- package/dist/index.js +600 -0
- package/dist/index.js.map +1 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Content editors can add animation classes and data attributes directly in a CMS
|
|
|
8
8
|
## Install
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npm
|
|
11
|
+
npm i @brandonsoccer22/gsap-editorial-carousel gsap
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
## Markup (semantic + user-placed controls)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var gsap = require('gsap');
|
|
4
|
+
|
|
5
|
+
// src/carousel.ts
|
|
6
|
+
|
|
7
|
+
// src/dom.ts
|
|
8
|
+
function resolveRoot(root) {
|
|
9
|
+
if (typeof root === "string") {
|
|
10
|
+
const el = document.querySelector(root);
|
|
11
|
+
if (!el) {
|
|
12
|
+
throw new Error(`Carousel root not found for selector: ${root}`);
|
|
13
|
+
}
|
|
14
|
+
if (!(el instanceof HTMLElement)) {
|
|
15
|
+
throw new Error(`Carousel root must be an HTMLElement for selector: ${root}`);
|
|
16
|
+
}
|
|
17
|
+
return el;
|
|
18
|
+
}
|
|
19
|
+
if (!(root instanceof HTMLElement)) {
|
|
20
|
+
throw new Error("Carousel root must be an HTMLElement.");
|
|
21
|
+
}
|
|
22
|
+
return root;
|
|
23
|
+
}
|
|
24
|
+
function qs(root, selector) {
|
|
25
|
+
return root.querySelector(selector);
|
|
26
|
+
}
|
|
27
|
+
function qsa(root, selector) {
|
|
28
|
+
return Array.from(root.querySelectorAll(selector));
|
|
29
|
+
}
|
|
30
|
+
function toggleClass(el, name, active) {
|
|
31
|
+
if (active) {
|
|
32
|
+
el.classList.add(name);
|
|
33
|
+
} else {
|
|
34
|
+
el.classList.remove(name);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function setAriaDisabled(el, disabled) {
|
|
38
|
+
el.setAttribute("aria-disabled", disabled ? "true" : "false");
|
|
39
|
+
}
|
|
40
|
+
function setDisabled(el, disabled, disabledClass) {
|
|
41
|
+
if (!el) return;
|
|
42
|
+
const isButton = el instanceof HTMLButtonElement || el instanceof HTMLInputElement;
|
|
43
|
+
if (isButton) {
|
|
44
|
+
el.disabled = disabled;
|
|
45
|
+
}
|
|
46
|
+
setAriaDisabled(el, disabled);
|
|
47
|
+
toggleClass(el, disabledClass, disabled);
|
|
48
|
+
}
|
|
49
|
+
function ensureRootFocusable(root) {
|
|
50
|
+
if (!root.hasAttribute("tabindex")) {
|
|
51
|
+
root.setAttribute("tabindex", "0");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/a11y.ts
|
|
56
|
+
function setSlidesState(slides, activeIndex, activeClass) {
|
|
57
|
+
slides.forEach((slide, index) => {
|
|
58
|
+
const isActive = index === activeIndex;
|
|
59
|
+
slide.setAttribute("aria-hidden", isActive ? "false" : "true");
|
|
60
|
+
toggleClass(slide, activeClass, isActive);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function setDotsState(dots, activeIndex, activeClass) {
|
|
64
|
+
dots.forEach((dot, index) => {
|
|
65
|
+
const isActive = index === activeIndex;
|
|
66
|
+
if (isActive) {
|
|
67
|
+
dot.setAttribute("aria-current", "true");
|
|
68
|
+
} else {
|
|
69
|
+
dot.removeAttribute("aria-current");
|
|
70
|
+
}
|
|
71
|
+
toggleClass(dot, activeClass, isActive);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/registry.ts
|
|
76
|
+
var registry = /* @__PURE__ */ new Map();
|
|
77
|
+
function registerAnimation(name, factory) {
|
|
78
|
+
registry.set(name, factory);
|
|
79
|
+
}
|
|
80
|
+
function registerAnimations(map) {
|
|
81
|
+
Object.entries(map).forEach(([name, factory]) => {
|
|
82
|
+
registerAnimation(name, factory);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
function getAnimation(name) {
|
|
86
|
+
return registry.get(name);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/defaults.ts
|
|
90
|
+
var defaultSelectors = {
|
|
91
|
+
root: "[data-carousel]",
|
|
92
|
+
slide: "[data-carousel-slide], .gsap-carousel__slide",
|
|
93
|
+
prev: "[data-carousel-prev]",
|
|
94
|
+
next: "[data-carousel-next]",
|
|
95
|
+
dots: "[data-carousel-dots]",
|
|
96
|
+
dotTemplate: "[data-carousel-dot-template]"
|
|
97
|
+
};
|
|
98
|
+
var defaultClassNames = {
|
|
99
|
+
activeSlide: "is-active",
|
|
100
|
+
animatingRoot: "is-animating",
|
|
101
|
+
disabledControl: "is-disabled",
|
|
102
|
+
dot: "gsap-carousel__dot",
|
|
103
|
+
activeDot: "is-active"
|
|
104
|
+
};
|
|
105
|
+
var defaultOptions = {
|
|
106
|
+
loop: true,
|
|
107
|
+
initialIndex: 0,
|
|
108
|
+
transition: {
|
|
109
|
+
overlap: 0
|
|
110
|
+
},
|
|
111
|
+
defaults: {
|
|
112
|
+
dur: 0.6,
|
|
113
|
+
ease: "power2.out"
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
var didRegister = false;
|
|
117
|
+
function ensureDefaultAnimationsRegistered() {
|
|
118
|
+
if (didRegister) return;
|
|
119
|
+
didRegister = true;
|
|
120
|
+
const fadeIn = ({ el, gsap: gsap3, opts, tl }) => {
|
|
121
|
+
tl.fromTo(
|
|
122
|
+
el,
|
|
123
|
+
{ autoAlpha: 0 },
|
|
124
|
+
{
|
|
125
|
+
autoAlpha: 1,
|
|
126
|
+
duration: opts.dur,
|
|
127
|
+
delay: opts.delay,
|
|
128
|
+
ease: opts.ease
|
|
129
|
+
},
|
|
130
|
+
opts.at
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
fadeIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
|
|
134
|
+
tl.to(
|
|
135
|
+
el,
|
|
136
|
+
{
|
|
137
|
+
autoAlpha: 0,
|
|
138
|
+
duration: opts.dur,
|
|
139
|
+
delay: opts.delay,
|
|
140
|
+
ease: opts.ease
|
|
141
|
+
},
|
|
142
|
+
opts.at
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
const fadeUp = ({ el, gsap: gsap3, opts, tl }) => {
|
|
146
|
+
tl.fromTo(
|
|
147
|
+
el,
|
|
148
|
+
{ autoAlpha: 0, y: 24 },
|
|
149
|
+
{
|
|
150
|
+
autoAlpha: 1,
|
|
151
|
+
y: 0,
|
|
152
|
+
duration: opts.dur,
|
|
153
|
+
delay: opts.delay,
|
|
154
|
+
ease: opts.ease
|
|
155
|
+
},
|
|
156
|
+
opts.at
|
|
157
|
+
);
|
|
158
|
+
};
|
|
159
|
+
fadeUp.reverse = ({ el, gsap: gsap3, opts, tl }) => {
|
|
160
|
+
tl.to(
|
|
161
|
+
el,
|
|
162
|
+
{
|
|
163
|
+
autoAlpha: 0,
|
|
164
|
+
y: -12,
|
|
165
|
+
duration: opts.dur,
|
|
166
|
+
delay: opts.delay,
|
|
167
|
+
ease: opts.ease
|
|
168
|
+
},
|
|
169
|
+
opts.at
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
const slideIn = ({ el, gsap: gsap3, opts, tl }) => {
|
|
173
|
+
tl.fromTo(
|
|
174
|
+
el,
|
|
175
|
+
{ autoAlpha: 0, x: opts.direction * 40 },
|
|
176
|
+
{
|
|
177
|
+
autoAlpha: 1,
|
|
178
|
+
x: 0,
|
|
179
|
+
duration: opts.dur,
|
|
180
|
+
delay: opts.delay,
|
|
181
|
+
ease: opts.ease
|
|
182
|
+
},
|
|
183
|
+
opts.at
|
|
184
|
+
);
|
|
185
|
+
};
|
|
186
|
+
slideIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
|
|
187
|
+
tl.to(
|
|
188
|
+
el,
|
|
189
|
+
{
|
|
190
|
+
autoAlpha: 0,
|
|
191
|
+
x: opts.direction * -24,
|
|
192
|
+
duration: opts.dur,
|
|
193
|
+
delay: opts.delay,
|
|
194
|
+
ease: opts.ease
|
|
195
|
+
},
|
|
196
|
+
opts.at
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
registerAnimations({
|
|
200
|
+
"fade-in": fadeIn,
|
|
201
|
+
"fade-up": fadeUp,
|
|
202
|
+
"slide-in": slideIn
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// src/timeline.ts
|
|
207
|
+
var defaultExitDuration = 0.25;
|
|
208
|
+
function getDataNumber(el, name, fallback) {
|
|
209
|
+
const value = el.getAttribute(name);
|
|
210
|
+
if (!value) return fallback;
|
|
211
|
+
const parsed = Number.parseFloat(value);
|
|
212
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
213
|
+
}
|
|
214
|
+
function getDataString(el, name) {
|
|
215
|
+
const value = el.getAttribute(name);
|
|
216
|
+
return value && value.trim() ? value.trim() : void 0;
|
|
217
|
+
}
|
|
218
|
+
function parsePositionOffset(value) {
|
|
219
|
+
if (!value) return null;
|
|
220
|
+
const trimmed = value.trim();
|
|
221
|
+
const numberPattern = /^[+-]?(?:\d+\.?\d*|\.\d+)$/;
|
|
222
|
+
const relativeMatch = trimmed.match(/^([+-])=([+-]?(?:\d+\.?\d*|\.\d+))$/);
|
|
223
|
+
if (relativeMatch) {
|
|
224
|
+
const amount = Number.parseFloat(relativeMatch[2]);
|
|
225
|
+
if (!Number.isFinite(amount)) return null;
|
|
226
|
+
return relativeMatch[1] === "+" ? amount : -amount;
|
|
227
|
+
}
|
|
228
|
+
if (numberPattern.test(trimmed)) {
|
|
229
|
+
const amount = Number.parseFloat(trimmed);
|
|
230
|
+
return Number.isFinite(amount) ? amount : null;
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
function findAnimationName(el) {
|
|
235
|
+
const classList = Array.from(el.classList);
|
|
236
|
+
for (const className of classList) {
|
|
237
|
+
if (getAnimation(className)) return className;
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
function collectAnimItems(slide, options) {
|
|
242
|
+
const elements = Array.from(slide.querySelectorAll("[class]"));
|
|
243
|
+
const items = [];
|
|
244
|
+
elements.forEach((el) => {
|
|
245
|
+
var _a;
|
|
246
|
+
const animName = findAnimationName(el);
|
|
247
|
+
if (!animName) return;
|
|
248
|
+
const seq = Math.max(1, Math.floor(getDataNumber(el, "data-seq", 1)));
|
|
249
|
+
const exitSeq = Math.max(1, Math.floor(getDataNumber(el, "data-exit-seq", seq)));
|
|
250
|
+
const dur = getDataNumber(el, "data-dur", options.defaults.dur);
|
|
251
|
+
const delay = getDataNumber(el, "data-delay", 0);
|
|
252
|
+
const ease = (_a = getDataString(el, "data-ease")) != null ? _a : options.defaults.ease;
|
|
253
|
+
const at = getDataString(el, "data-at");
|
|
254
|
+
items.push({ el, animName, seq, exitSeq, dur, delay, ease, at });
|
|
255
|
+
});
|
|
256
|
+
return items;
|
|
257
|
+
}
|
|
258
|
+
function groupBySequence(items, getSequence) {
|
|
259
|
+
const map = /* @__PURE__ */ new Map();
|
|
260
|
+
items.forEach((item) => {
|
|
261
|
+
var _a;
|
|
262
|
+
const sequence = getSequence(item);
|
|
263
|
+
const bucket = (_a = map.get(sequence)) != null ? _a : [];
|
|
264
|
+
bucket.push(item);
|
|
265
|
+
map.set(sequence, bucket);
|
|
266
|
+
});
|
|
267
|
+
return map;
|
|
268
|
+
}
|
|
269
|
+
function buildSlideEnterTimeline(slide, direction, options, gsapInstance) {
|
|
270
|
+
const tl = gsapInstance.timeline();
|
|
271
|
+
const items = collectAnimItems(slide, options);
|
|
272
|
+
if (!items.length) return tl;
|
|
273
|
+
const grouped = groupBySequence(items, (item) => item.seq);
|
|
274
|
+
const order = Array.from(grouped.keys()).sort((a, b) => a - b);
|
|
275
|
+
let cursor = 0;
|
|
276
|
+
order.forEach((seq) => {
|
|
277
|
+
const group = grouped.get(seq);
|
|
278
|
+
if (!group) return;
|
|
279
|
+
let groupMax = 0;
|
|
280
|
+
group.forEach((item) => {
|
|
281
|
+
var _a;
|
|
282
|
+
const factory = getAnimation(item.animName);
|
|
283
|
+
if (!factory) return;
|
|
284
|
+
const offset = (_a = parsePositionOffset(item.at)) != null ? _a : 0;
|
|
285
|
+
const position = cursor + offset;
|
|
286
|
+
factory({
|
|
287
|
+
el: item.el,
|
|
288
|
+
tl,
|
|
289
|
+
gsap: gsapInstance,
|
|
290
|
+
opts: {
|
|
291
|
+
dur: item.dur,
|
|
292
|
+
delay: item.delay,
|
|
293
|
+
ease: item.ease,
|
|
294
|
+
direction,
|
|
295
|
+
at: position
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
groupMax = Math.max(groupMax, offset + item.delay + item.dur);
|
|
299
|
+
});
|
|
300
|
+
cursor += Math.max(groupMax, 0);
|
|
301
|
+
});
|
|
302
|
+
return tl;
|
|
303
|
+
}
|
|
304
|
+
function buildSlideExitTimeline(slide, direction, options, gsapInstance) {
|
|
305
|
+
const tl = gsapInstance.timeline();
|
|
306
|
+
const items = collectAnimItems(slide, options);
|
|
307
|
+
if (!items.length) return tl;
|
|
308
|
+
const grouped = groupBySequence(items, (item) => item.exitSeq);
|
|
309
|
+
const order = Array.from(grouped.keys()).sort((a, b) => a - b);
|
|
310
|
+
let cursor = 0;
|
|
311
|
+
order.forEach((seq) => {
|
|
312
|
+
const group = grouped.get(seq);
|
|
313
|
+
if (!group) return;
|
|
314
|
+
let groupMax = 0;
|
|
315
|
+
group.forEach((item) => {
|
|
316
|
+
var _a;
|
|
317
|
+
const exitName = getDataString(item.el, "data-exit");
|
|
318
|
+
const factory = exitName ? getAnimation(exitName) : getAnimation(item.animName);
|
|
319
|
+
const reverseFactory = factory && "reverse" in factory ? factory.reverse : void 0;
|
|
320
|
+
const offset = (_a = parsePositionOffset(item.at)) != null ? _a : 0;
|
|
321
|
+
const position = cursor + offset;
|
|
322
|
+
let usedDuration = item.dur;
|
|
323
|
+
if (exitName && factory) {
|
|
324
|
+
factory({
|
|
325
|
+
el: item.el,
|
|
326
|
+
tl,
|
|
327
|
+
gsap: gsapInstance,
|
|
328
|
+
opts: {
|
|
329
|
+
dur: item.dur,
|
|
330
|
+
delay: item.delay,
|
|
331
|
+
ease: item.ease,
|
|
332
|
+
direction,
|
|
333
|
+
at: position
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
} else if (!exitName && reverseFactory) {
|
|
337
|
+
reverseFactory({
|
|
338
|
+
el: item.el,
|
|
339
|
+
tl,
|
|
340
|
+
gsap: gsapInstance,
|
|
341
|
+
opts: {
|
|
342
|
+
dur: item.dur,
|
|
343
|
+
delay: item.delay,
|
|
344
|
+
ease: item.ease,
|
|
345
|
+
direction,
|
|
346
|
+
at: position
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
} else {
|
|
350
|
+
usedDuration = Math.min(item.dur, defaultExitDuration);
|
|
351
|
+
tl.to(
|
|
352
|
+
item.el,
|
|
353
|
+
{
|
|
354
|
+
autoAlpha: 0,
|
|
355
|
+
duration: usedDuration,
|
|
356
|
+
delay: item.delay,
|
|
357
|
+
ease: item.ease
|
|
358
|
+
},
|
|
359
|
+
position
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
groupMax = Math.max(groupMax, offset + item.delay + usedDuration);
|
|
363
|
+
});
|
|
364
|
+
cursor += Math.max(groupMax, 0);
|
|
365
|
+
});
|
|
366
|
+
return tl;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/reducedMotion.ts
|
|
370
|
+
function prefersReducedMotion() {
|
|
371
|
+
if (typeof window === "undefined" || !("matchMedia" in window)) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/carousel.ts
|
|
378
|
+
var generatedDotSelector = '[data-carousel-dot="true"]';
|
|
379
|
+
function createCarousel(rootInput, options = {}) {
|
|
380
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
381
|
+
ensureDefaultAnimationsRegistered();
|
|
382
|
+
const root = resolveRoot(rootInput);
|
|
383
|
+
const gsapInstance = (_a = options.gsap) != null ? _a : gsap.gsap;
|
|
384
|
+
ensureRootFocusable(root);
|
|
385
|
+
const ctx = gsapInstance.context(() => {
|
|
386
|
+
}, root);
|
|
387
|
+
const resolved = {
|
|
388
|
+
loop: (_b = options.loop) != null ? _b : defaultOptions.loop,
|
|
389
|
+
initialIndex: (_c = options.initialIndex) != null ? _c : defaultOptions.initialIndex,
|
|
390
|
+
transition: { ...defaultOptions.transition, ...options.transition },
|
|
391
|
+
selectors: { ...defaultSelectors, ...options.selectors },
|
|
392
|
+
classNames: { ...defaultClassNames, ...options.classNames },
|
|
393
|
+
defaults: { ...defaultOptions.defaults, ...options.defaults },
|
|
394
|
+
onInit: options.onInit,
|
|
395
|
+
onBeforeChange: options.onBeforeChange,
|
|
396
|
+
onAfterChange: options.onAfterChange
|
|
397
|
+
};
|
|
398
|
+
const slides = qsa(root, resolved.selectors.slide);
|
|
399
|
+
if (!slides.length) {
|
|
400
|
+
throw new Error("Carousel requires at least one slide element.");
|
|
401
|
+
}
|
|
402
|
+
const controls = resolveControls(root, resolved, slides.length);
|
|
403
|
+
const reducedMotion = prefersReducedMotion();
|
|
404
|
+
const state = { activeTimeline: null };
|
|
405
|
+
let currentIndex = normalizeIndex(resolved.initialIndex, slides.length, resolved.loop);
|
|
406
|
+
let animating = false;
|
|
407
|
+
setSlidesState(slides, currentIndex, resolved.classNames.activeSlide);
|
|
408
|
+
setDotsState(controls.dots, currentIndex, resolved.classNames.activeDot);
|
|
409
|
+
const onPrevClick = (event) => {
|
|
410
|
+
event.preventDefault();
|
|
411
|
+
prev();
|
|
412
|
+
};
|
|
413
|
+
const onNextClick = (event) => {
|
|
414
|
+
event.preventDefault();
|
|
415
|
+
next();
|
|
416
|
+
};
|
|
417
|
+
const onDotsClick = (event) => {
|
|
418
|
+
var _a2;
|
|
419
|
+
const target = (_a2 = event.target) == null ? void 0 : _a2.closest(generatedDotSelector);
|
|
420
|
+
if (!target) return;
|
|
421
|
+
event.preventDefault();
|
|
422
|
+
const indexAttr = target.getAttribute("data-carousel-dot-index");
|
|
423
|
+
if (!indexAttr) return;
|
|
424
|
+
const index = Number.parseInt(indexAttr, 10);
|
|
425
|
+
if (!Number.isFinite(index)) return;
|
|
426
|
+
goTo(index);
|
|
427
|
+
};
|
|
428
|
+
(_d = controls.prev) == null ? void 0 : _d.addEventListener("click", onPrevClick);
|
|
429
|
+
(_e = controls.next) == null ? void 0 : _e.addEventListener("click", onNextClick);
|
|
430
|
+
(_f = controls.dotsContainer) == null ? void 0 : _f.addEventListener("click", onDotsClick);
|
|
431
|
+
const instance = {
|
|
432
|
+
goTo,
|
|
433
|
+
next,
|
|
434
|
+
prev,
|
|
435
|
+
destroy,
|
|
436
|
+
getIndex: () => currentIndex,
|
|
437
|
+
getCount: () => slides.length,
|
|
438
|
+
isAnimating: () => animating
|
|
439
|
+
};
|
|
440
|
+
(_g = resolved.onInit) == null ? void 0 : _g.call(resolved, instance);
|
|
441
|
+
function disableControls(disabled) {
|
|
442
|
+
toggleClass(root, resolved.classNames.animatingRoot, disabled);
|
|
443
|
+
setDisabled(controls.prev, disabled, resolved.classNames.disabledControl);
|
|
444
|
+
setDisabled(controls.next, disabled, resolved.classNames.disabledControl);
|
|
445
|
+
if (controls.dotsContainer) {
|
|
446
|
+
setAriaDisabled(controls.dotsContainer, disabled);
|
|
447
|
+
}
|
|
448
|
+
controls.dots.forEach((dot) => {
|
|
449
|
+
setAriaDisabled(dot, disabled);
|
|
450
|
+
toggleClass(dot, resolved.classNames.disabledControl, disabled);
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
function applyActiveState(nextIndex) {
|
|
454
|
+
currentIndex = nextIndex;
|
|
455
|
+
setSlidesState(slides, currentIndex, resolved.classNames.activeSlide);
|
|
456
|
+
setDotsState(controls.dots, currentIndex, resolved.classNames.activeDot);
|
|
457
|
+
}
|
|
458
|
+
function finalizeTransition(from, to, direction) {
|
|
459
|
+
var _a2;
|
|
460
|
+
animating = false;
|
|
461
|
+
disableControls(false);
|
|
462
|
+
state.activeTimeline = null;
|
|
463
|
+
(_a2 = resolved.onAfterChange) == null ? void 0 : _a2.call(resolved, { from, to, direction });
|
|
464
|
+
}
|
|
465
|
+
function transitionTo(nextIndex, immediate) {
|
|
466
|
+
var _a2;
|
|
467
|
+
if (animating) return;
|
|
468
|
+
if (nextIndex === currentIndex) return;
|
|
469
|
+
const from = currentIndex;
|
|
470
|
+
const to = nextIndex;
|
|
471
|
+
const direction = getDirection(from, to, slides.length, resolved.loop);
|
|
472
|
+
animating = true;
|
|
473
|
+
disableControls(true);
|
|
474
|
+
(_a2 = resolved.onBeforeChange) == null ? void 0 : _a2.call(resolved, { from, to, direction });
|
|
475
|
+
if (immediate || reducedMotion) {
|
|
476
|
+
applyActiveState(to);
|
|
477
|
+
finalizeTransition(from, to, direction);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
const exitTl = ctx.add(() => buildSlideExitTimeline(slides[from], direction, resolved, gsapInstance));
|
|
481
|
+
const enterTl = ctx.add(() => buildSlideEnterTimeline(slides[to], direction, resolved, gsapInstance));
|
|
482
|
+
const master = ctx.add(
|
|
483
|
+
() => gsapInstance.timeline({
|
|
484
|
+
onComplete: () => {
|
|
485
|
+
finalizeTransition(from, to, direction);
|
|
486
|
+
}
|
|
487
|
+
})
|
|
488
|
+
);
|
|
489
|
+
state.activeTimeline = master;
|
|
490
|
+
const overlap = Math.max(0, resolved.transition.overlap);
|
|
491
|
+
const enterAt = Math.max(0, exitTl.duration() - overlap);
|
|
492
|
+
master.add(exitTl, 0);
|
|
493
|
+
master.add(() => applyActiveState(to), enterAt);
|
|
494
|
+
master.add(enterTl, enterAt);
|
|
495
|
+
}
|
|
496
|
+
function goTo(index, opts) {
|
|
497
|
+
if (animating) return;
|
|
498
|
+
const nextIndex = normalizeIndex(index, slides.length, resolved.loop);
|
|
499
|
+
if (nextIndex === currentIndex) return;
|
|
500
|
+
transitionTo(nextIndex, opts == null ? void 0 : opts.immediate);
|
|
501
|
+
}
|
|
502
|
+
function next(opts) {
|
|
503
|
+
if (animating) return;
|
|
504
|
+
const nextIndex = resolveNextIndex(currentIndex, slides.length, resolved.loop);
|
|
505
|
+
if (nextIndex === currentIndex) return;
|
|
506
|
+
transitionTo(nextIndex, opts == null ? void 0 : opts.immediate);
|
|
507
|
+
}
|
|
508
|
+
function prev(opts) {
|
|
509
|
+
if (animating) return;
|
|
510
|
+
const nextIndex = resolvePrevIndex(currentIndex, slides.length, resolved.loop);
|
|
511
|
+
if (nextIndex === currentIndex) return;
|
|
512
|
+
transitionTo(nextIndex, opts == null ? void 0 : opts.immediate);
|
|
513
|
+
}
|
|
514
|
+
function destroy() {
|
|
515
|
+
var _a2, _b2, _c2, _d2;
|
|
516
|
+
(_a2 = controls.prev) == null ? void 0 : _a2.removeEventListener("click", onPrevClick);
|
|
517
|
+
(_b2 = controls.next) == null ? void 0 : _b2.removeEventListener("click", onNextClick);
|
|
518
|
+
(_c2 = controls.dotsContainer) == null ? void 0 : _c2.removeEventListener("click", onDotsClick);
|
|
519
|
+
(_d2 = state.activeTimeline) == null ? void 0 : _d2.kill();
|
|
520
|
+
animating = false;
|
|
521
|
+
ctx.revert();
|
|
522
|
+
if (controls.dotsContainer) {
|
|
523
|
+
controls.dotsContainer.querySelectorAll(generatedDotSelector).forEach((dot) => {
|
|
524
|
+
dot.remove();
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
if (controls.dotTemplate) {
|
|
528
|
+
controls.dotTemplate.hidden = false;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return instance;
|
|
532
|
+
}
|
|
533
|
+
function resolveControls(root, options, slideCount) {
|
|
534
|
+
const rootId = root.getAttribute("id");
|
|
535
|
+
const queryWithFallback = (selector) => {
|
|
536
|
+
if (rootId) {
|
|
537
|
+
const scoped = document.querySelector(`${selector}[data-for="${rootId}"]`);
|
|
538
|
+
if (scoped) return scoped;
|
|
539
|
+
}
|
|
540
|
+
return qs(root, selector);
|
|
541
|
+
};
|
|
542
|
+
const prev = queryWithFallback(options.selectors.prev);
|
|
543
|
+
const next = queryWithFallback(options.selectors.next);
|
|
544
|
+
const dotsContainer = queryWithFallback(options.selectors.dots);
|
|
545
|
+
const dotTemplate = dotsContainer ? qs(dotsContainer, options.selectors.dotTemplate) : null;
|
|
546
|
+
const dots = dotsContainer ? setupDots(dotsContainer, dotTemplate, options, slideCount) : [];
|
|
547
|
+
return { prev, next, dotsContainer, dotTemplate, dots };
|
|
548
|
+
}
|
|
549
|
+
function setupDots(container, template, options, slideCount) {
|
|
550
|
+
const dots = qsa(container, generatedDotSelector);
|
|
551
|
+
dots.forEach((dot) => dot.remove());
|
|
552
|
+
if (!template) return [];
|
|
553
|
+
const clones = [];
|
|
554
|
+
for (let i = 0; i < slideCount; i += 1) {
|
|
555
|
+
const clone = template.cloneNode(true);
|
|
556
|
+
clone.removeAttribute("id");
|
|
557
|
+
clone.setAttribute("data-carousel-dot", "true");
|
|
558
|
+
clone.setAttribute("data-carousel-dot-index", String(i));
|
|
559
|
+
clone.setAttribute("aria-label", `Go to slide ${i + 1}`);
|
|
560
|
+
clone.classList.add(options.classNames.dot);
|
|
561
|
+
if (clone instanceof HTMLButtonElement && !clone.getAttribute("type")) {
|
|
562
|
+
clone.setAttribute("type", "button");
|
|
563
|
+
}
|
|
564
|
+
container.appendChild(clone);
|
|
565
|
+
clones.push(clone);
|
|
566
|
+
}
|
|
567
|
+
template.hidden = true;
|
|
568
|
+
return clones;
|
|
569
|
+
}
|
|
570
|
+
function normalizeIndex(index, count, loop) {
|
|
571
|
+
if (count <= 0) return 0;
|
|
572
|
+
if (loop) {
|
|
573
|
+
const wrapped = (index % count + count) % count;
|
|
574
|
+
return wrapped;
|
|
575
|
+
}
|
|
576
|
+
if (index < 0) return 0;
|
|
577
|
+
if (index >= count) return count - 1;
|
|
578
|
+
return index;
|
|
579
|
+
}
|
|
580
|
+
function resolveNextIndex(current, count, loop) {
|
|
581
|
+
if (count <= 0) return current;
|
|
582
|
+
if (current + 1 < count) return current + 1;
|
|
583
|
+
return loop ? 0 : current;
|
|
584
|
+
}
|
|
585
|
+
function resolvePrevIndex(current, count, loop) {
|
|
586
|
+
if (count <= 0) return current;
|
|
587
|
+
if (current - 1 >= 0) return current - 1;
|
|
588
|
+
return loop ? count - 1 : current;
|
|
589
|
+
}
|
|
590
|
+
function getDirection(from, to, count, loop) {
|
|
591
|
+
if (!loop) return to > from ? 1 : -1;
|
|
592
|
+
if (from === count - 1 && to === 0) return 1;
|
|
593
|
+
if (from === 0 && to === count - 1) return -1;
|
|
594
|
+
return to > from ? 1 : -1;
|
|
595
|
+
}
|
|
596
|
+
function registerGsapPlugins(...plugins) {
|
|
597
|
+
gsap.gsap.registerPlugin(...plugins);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
exports.createCarousel = createCarousel;
|
|
601
|
+
exports.registerAnimation = registerAnimation;
|
|
602
|
+
exports.registerAnimations = registerAnimations;
|
|
603
|
+
exports.registerGsapPlugins = registerGsapPlugins;
|
|
604
|
+
//# sourceMappingURL=index.cjs.map
|
|
605
|
+
//# sourceMappingURL=index.cjs.map
|