@brandonsoccer22/gsap-editorial-carousel 0.1.2 → 0.1.4

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/dist/index.js ADDED
@@ -0,0 +1,971 @@
1
+ import { gsap } from 'gsap';
2
+
3
+ // src/carousel.ts
4
+
5
+ // src/dom.ts
6
+ function resolveRoot(root) {
7
+ if (typeof root === "string") {
8
+ const el = document.querySelector(root);
9
+ if (!el) {
10
+ throw new Error(`Carousel root not found for selector: ${root}`);
11
+ }
12
+ if (!(el instanceof HTMLElement)) {
13
+ throw new Error(`Carousel root must be an HTMLElement for selector: ${root}`);
14
+ }
15
+ return el;
16
+ }
17
+ if (!(root instanceof HTMLElement)) {
18
+ throw new Error("Carousel root must be an HTMLElement.");
19
+ }
20
+ return root;
21
+ }
22
+ function qs(root, selector) {
23
+ return root.querySelector(selector);
24
+ }
25
+ function qsa(root, selector) {
26
+ return Array.from(root.querySelectorAll(selector));
27
+ }
28
+ function toggleClass(el, name, active) {
29
+ if (active) {
30
+ el.classList.add(name);
31
+ } else {
32
+ el.classList.remove(name);
33
+ }
34
+ }
35
+ function setAriaDisabled(el, disabled) {
36
+ el.setAttribute("aria-disabled", disabled ? "true" : "false");
37
+ }
38
+ function setDisabled(el, disabled, disabledClass) {
39
+ if (!el) return;
40
+ const isButton = el instanceof HTMLButtonElement || el instanceof HTMLInputElement;
41
+ if (isButton) {
42
+ el.disabled = disabled;
43
+ }
44
+ setAriaDisabled(el, disabled);
45
+ toggleClass(el, disabledClass, disabled);
46
+ }
47
+ function ensureRootFocusable(root) {
48
+ if (!root.hasAttribute("tabindex")) {
49
+ root.setAttribute("tabindex", "0");
50
+ }
51
+ }
52
+
53
+ // src/a11y.ts
54
+ function setSlidesState(slides, activeIndex, activeClass) {
55
+ slides.forEach((slide, index) => {
56
+ const isActive = index === activeIndex;
57
+ slide.setAttribute("aria-hidden", isActive ? "false" : "true");
58
+ if (isActive) {
59
+ slide.removeAttribute("inert");
60
+ } else {
61
+ slide.setAttribute("inert", "");
62
+ }
63
+ toggleClass(slide, activeClass, isActive);
64
+ });
65
+ }
66
+ function setDotsState(dots, activeIndex, activeClass) {
67
+ dots.forEach((dot, index) => {
68
+ const isActive = index === activeIndex;
69
+ if (isActive) {
70
+ dot.setAttribute("aria-current", "true");
71
+ } else {
72
+ dot.removeAttribute("aria-current");
73
+ }
74
+ toggleClass(dot, activeClass, isActive);
75
+ });
76
+ }
77
+
78
+ // src/registry.ts
79
+ var registry = /* @__PURE__ */ new Map();
80
+ function registerAnimation(name, factory) {
81
+ registry.set(name, factory);
82
+ }
83
+ function registerAnimations(map) {
84
+ Object.entries(map).forEach(([name, factory]) => {
85
+ registerAnimation(name, factory);
86
+ });
87
+ }
88
+ function getAnimation(name) {
89
+ return registry.get(name);
90
+ }
91
+
92
+ // src/defaults.ts
93
+ var defaultSelectors = {
94
+ root: "[data-carousel]",
95
+ slide: "[data-carousel-slide], .gsap-carousel__slide",
96
+ prev: "[data-carousel-prev]",
97
+ next: "[data-carousel-next]",
98
+ dots: "[data-carousel-dots]",
99
+ dotTemplate: "[data-carousel-dot-template]"
100
+ };
101
+ var defaultClassNames = {
102
+ activeSlide: "is-active",
103
+ animatingRoot: "is-animating",
104
+ disabledControl: "is-disabled",
105
+ dot: "gsap-carousel__dot",
106
+ activeDot: "is-active"
107
+ };
108
+ var defaultOptions = {
109
+ loop: true,
110
+ initialIndex: 0,
111
+ transition: {
112
+ overlap: 0
113
+ },
114
+ defaults: {
115
+ dur: 0.6,
116
+ ease: "power2.out"
117
+ }
118
+ };
119
+ var didRegister = false;
120
+ function ensureDefaultAnimationsRegistered() {
121
+ if (didRegister) return;
122
+ didRegister = true;
123
+ const fadeIn = ({ el, gsap: gsap3, opts, tl }) => {
124
+ tl.fromTo(
125
+ el,
126
+ { autoAlpha: 0 },
127
+ {
128
+ autoAlpha: 1,
129
+ duration: opts.dur,
130
+ delay: opts.delay,
131
+ ease: opts.ease
132
+ },
133
+ opts.at
134
+ );
135
+ };
136
+ fadeIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
137
+ tl.to(
138
+ el,
139
+ {
140
+ autoAlpha: 0,
141
+ duration: opts.dur,
142
+ delay: opts.delay,
143
+ ease: opts.ease
144
+ },
145
+ opts.at
146
+ );
147
+ tl.set(el, { autoAlpha: 0 }, ">");
148
+ };
149
+ const fadeUp = ({ el, gsap: gsap3, opts, tl }) => {
150
+ tl.fromTo(
151
+ el,
152
+ { autoAlpha: 0, y: 24 },
153
+ {
154
+ autoAlpha: 1,
155
+ y: 0,
156
+ duration: opts.dur,
157
+ delay: opts.delay,
158
+ ease: opts.ease
159
+ },
160
+ opts.at
161
+ );
162
+ };
163
+ fadeUp.reverse = ({ el, gsap: gsap3, opts, tl }) => {
164
+ tl.to(
165
+ el,
166
+ {
167
+ autoAlpha: 0,
168
+ y: -12,
169
+ duration: opts.dur,
170
+ delay: opts.delay,
171
+ ease: opts.ease
172
+ },
173
+ opts.at
174
+ );
175
+ tl.set(el, { autoAlpha: 0 }, ">");
176
+ };
177
+ const fadeDown = ({ el, gsap: gsap3, opts, tl }) => {
178
+ tl.fromTo(
179
+ el,
180
+ { autoAlpha: 0, y: -24 },
181
+ {
182
+ autoAlpha: 1,
183
+ y: 0,
184
+ duration: opts.dur,
185
+ delay: opts.delay,
186
+ ease: opts.ease
187
+ },
188
+ opts.at
189
+ );
190
+ };
191
+ fadeDown.reverse = ({ el, gsap: gsap3, opts, tl }) => {
192
+ tl.to(
193
+ el,
194
+ {
195
+ autoAlpha: 0,
196
+ y: 12,
197
+ duration: opts.dur,
198
+ delay: opts.delay,
199
+ ease: opts.ease
200
+ },
201
+ opts.at
202
+ );
203
+ tl.set(el, { autoAlpha: 0 }, ">");
204
+ };
205
+ const slideIn = ({ el, gsap: gsap3, opts, tl }) => {
206
+ tl.fromTo(
207
+ el,
208
+ { autoAlpha: 0, x: opts.direction * 40 },
209
+ {
210
+ autoAlpha: 1,
211
+ x: 0,
212
+ duration: opts.dur,
213
+ delay: opts.delay,
214
+ ease: opts.ease
215
+ },
216
+ opts.at
217
+ );
218
+ };
219
+ slideIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
220
+ tl.to(
221
+ el,
222
+ {
223
+ autoAlpha: 0,
224
+ x: opts.direction * -24,
225
+ duration: opts.dur,
226
+ delay: opts.delay,
227
+ ease: opts.ease
228
+ },
229
+ opts.at
230
+ );
231
+ tl.set(el, { autoAlpha: 0 }, ">");
232
+ };
233
+ const fadeOut = ({ el, gsap: gsap3, opts, tl }) => {
234
+ tl.to(
235
+ el,
236
+ {
237
+ autoAlpha: 0,
238
+ duration: opts.dur,
239
+ delay: opts.delay,
240
+ ease: opts.ease
241
+ },
242
+ opts.at
243
+ );
244
+ tl.set(el, { autoAlpha: 0 }, ">");
245
+ };
246
+ fadeOut.reverse = ({ el, gsap: gsap3, opts, tl }) => {
247
+ tl.to(
248
+ el,
249
+ {
250
+ autoAlpha: 1,
251
+ duration: opts.dur,
252
+ delay: opts.delay,
253
+ ease: opts.ease
254
+ },
255
+ opts.at
256
+ );
257
+ };
258
+ const slideOut = ({ el, gsap: gsap3, opts, tl }) => {
259
+ tl.to(
260
+ el,
261
+ {
262
+ autoAlpha: 0,
263
+ x: opts.direction * -24,
264
+ duration: opts.dur,
265
+ delay: opts.delay,
266
+ ease: opts.ease
267
+ },
268
+ opts.at
269
+ );
270
+ tl.set(el, { autoAlpha: 0 }, ">");
271
+ };
272
+ slideOut.reverse = ({ el, gsap: gsap3, opts, tl }) => {
273
+ tl.to(
274
+ el,
275
+ {
276
+ autoAlpha: 1,
277
+ x: 0,
278
+ duration: opts.dur,
279
+ delay: opts.delay,
280
+ ease: opts.ease
281
+ },
282
+ opts.at
283
+ );
284
+ };
285
+ registerAnimations({
286
+ "fade-in": fadeIn,
287
+ "fade-down": fadeDown,
288
+ "fade-down-in": fadeDownIn,
289
+ "fade-down-out": fadeDownOut,
290
+ "fade-out": fadeOut,
291
+ "fade-up": fadeUp,
292
+ "fade-up-in": fadeUpIn,
293
+ "fade-up-out": fadeUpOut,
294
+ "fade-start-in": fadeStartIn,
295
+ "fade-start-out": fadeStartOut,
296
+ "fade-end-in": fadeEndIn,
297
+ "fade-end-out": fadeEndOut,
298
+ "slide-in": slideIn,
299
+ "slide-out": slideOut
300
+ });
301
+ }
302
+ var fadeUpIn = ({ el, gsap: gsap3, opts, tl }) => {
303
+ tl.fromTo(
304
+ el,
305
+ { autoAlpha: 0, y: 24 },
306
+ {
307
+ autoAlpha: 1,
308
+ y: 0,
309
+ duration: opts.dur,
310
+ delay: opts.delay,
311
+ ease: opts.ease
312
+ },
313
+ opts.at
314
+ );
315
+ };
316
+ fadeUpIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
317
+ tl.to(
318
+ el,
319
+ {
320
+ autoAlpha: 0,
321
+ y: -12,
322
+ duration: opts.dur,
323
+ delay: opts.delay,
324
+ ease: opts.ease
325
+ },
326
+ opts.at
327
+ );
328
+ tl.set(el, { autoAlpha: 0 }, ">");
329
+ };
330
+ var fadeUpOut = ({ el, gsap: gsap3, opts, tl }) => {
331
+ tl.to(
332
+ el,
333
+ {
334
+ autoAlpha: 0,
335
+ y: -12,
336
+ duration: opts.dur,
337
+ delay: opts.delay,
338
+ ease: opts.ease
339
+ },
340
+ opts.at
341
+ );
342
+ tl.set(el, { autoAlpha: 0 }, ">");
343
+ };
344
+ fadeUpOut.reverse = ({ el, gsap: gsap3, opts, tl }) => {
345
+ tl.fromTo(
346
+ el,
347
+ { autoAlpha: 0, y: 24 },
348
+ {
349
+ autoAlpha: 1,
350
+ y: 0,
351
+ duration: opts.dur,
352
+ delay: opts.delay,
353
+ ease: opts.ease
354
+ },
355
+ opts.at
356
+ );
357
+ };
358
+ var fadeDownIn = ({ el, gsap: gsap3, opts, tl }) => {
359
+ tl.fromTo(
360
+ el,
361
+ { autoAlpha: 0, y: -24 },
362
+ {
363
+ autoAlpha: 1,
364
+ y: 0,
365
+ duration: opts.dur,
366
+ delay: opts.delay,
367
+ ease: opts.ease
368
+ },
369
+ opts.at
370
+ );
371
+ };
372
+ fadeDownIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
373
+ tl.to(
374
+ el,
375
+ {
376
+ autoAlpha: 0,
377
+ y: 12,
378
+ duration: opts.dur,
379
+ delay: opts.delay,
380
+ ease: opts.ease
381
+ },
382
+ opts.at
383
+ );
384
+ tl.set(el, { autoAlpha: 0 }, ">");
385
+ };
386
+ var fadeDownOut = ({ el, gsap: gsap3, opts, tl }) => {
387
+ tl.to(
388
+ el,
389
+ {
390
+ autoAlpha: 0,
391
+ y: 12,
392
+ duration: opts.dur,
393
+ delay: opts.delay,
394
+ ease: opts.ease
395
+ },
396
+ opts.at
397
+ );
398
+ tl.set(el, { autoAlpha: 0 }, ">");
399
+ };
400
+ fadeDownOut.reverse = ({ el, gsap: gsap3, opts, tl }) => {
401
+ tl.fromTo(
402
+ el,
403
+ { autoAlpha: 0, y: -24 },
404
+ {
405
+ autoAlpha: 1,
406
+ y: 0,
407
+ duration: opts.dur,
408
+ delay: opts.delay,
409
+ ease: opts.ease
410
+ },
411
+ opts.at
412
+ );
413
+ };
414
+ var fadeStartIn = ({ el, gsap: gsap3, opts, tl }) => {
415
+ tl.fromTo(
416
+ el,
417
+ { autoAlpha: 0, x: -24 },
418
+ {
419
+ autoAlpha: 1,
420
+ x: 0,
421
+ duration: opts.dur,
422
+ delay: opts.delay,
423
+ ease: opts.ease
424
+ },
425
+ opts.at
426
+ );
427
+ };
428
+ fadeStartIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
429
+ tl.to(
430
+ el,
431
+ {
432
+ autoAlpha: 0,
433
+ x: -12,
434
+ duration: opts.dur,
435
+ delay: opts.delay,
436
+ ease: opts.ease
437
+ },
438
+ opts.at
439
+ );
440
+ tl.set(el, { autoAlpha: 0 }, ">");
441
+ };
442
+ var fadeStartOut = ({ el, gsap: gsap3, opts, tl }) => {
443
+ tl.to(
444
+ el,
445
+ {
446
+ autoAlpha: 0,
447
+ x: -12,
448
+ duration: opts.dur,
449
+ delay: opts.delay,
450
+ ease: opts.ease
451
+ },
452
+ opts.at
453
+ );
454
+ tl.set(el, { autoAlpha: 0 }, ">");
455
+ };
456
+ fadeStartOut.reverse = ({ el, gsap: gsap3, opts, tl }) => {
457
+ tl.fromTo(
458
+ el,
459
+ { autoAlpha: 0, x: -24 },
460
+ {
461
+ autoAlpha: 1,
462
+ x: 0,
463
+ duration: opts.dur,
464
+ delay: opts.delay,
465
+ ease: opts.ease
466
+ },
467
+ opts.at
468
+ );
469
+ };
470
+ var fadeEndIn = ({ el, gsap: gsap3, opts, tl }) => {
471
+ tl.fromTo(
472
+ el,
473
+ { autoAlpha: 0, x: 24 },
474
+ {
475
+ autoAlpha: 1,
476
+ x: 0,
477
+ duration: opts.dur,
478
+ delay: opts.delay,
479
+ ease: opts.ease
480
+ },
481
+ opts.at
482
+ );
483
+ };
484
+ fadeEndIn.reverse = ({ el, gsap: gsap3, opts, tl }) => {
485
+ tl.to(
486
+ el,
487
+ {
488
+ autoAlpha: 0,
489
+ x: 12,
490
+ duration: opts.dur,
491
+ delay: opts.delay,
492
+ ease: opts.ease
493
+ },
494
+ opts.at
495
+ );
496
+ tl.set(el, { autoAlpha: 0 }, ">");
497
+ };
498
+ var fadeEndOut = ({ el, gsap: gsap3, opts, tl }) => {
499
+ tl.to(
500
+ el,
501
+ {
502
+ autoAlpha: 0,
503
+ x: 12,
504
+ duration: opts.dur,
505
+ delay: opts.delay,
506
+ ease: opts.ease
507
+ },
508
+ opts.at
509
+ );
510
+ tl.set(el, { autoAlpha: 0 }, ">");
511
+ };
512
+ fadeEndOut.reverse = ({ el, gsap: gsap3, opts, tl }) => {
513
+ tl.fromTo(
514
+ el,
515
+ { autoAlpha: 0, x: 24 },
516
+ {
517
+ autoAlpha: 1,
518
+ x: 0,
519
+ duration: opts.dur,
520
+ delay: opts.delay,
521
+ ease: opts.ease
522
+ },
523
+ opts.at
524
+ );
525
+ };
526
+
527
+ // src/timeline.ts
528
+ function getDataNumber(el, name, fallback) {
529
+ const value = el.getAttribute(name);
530
+ if (!value) return fallback;
531
+ const parsed = Number.parseFloat(value);
532
+ return Number.isFinite(parsed) ? parsed : fallback;
533
+ }
534
+ function getDataString(el, name) {
535
+ const value = el.getAttribute(name);
536
+ return value && value.trim() ? value.trim() : void 0;
537
+ }
538
+ function parsePositionOffset(value) {
539
+ if (!value) return null;
540
+ const trimmed = value.trim();
541
+ const numberPattern = /^[+-]?(?:\d+\.?\d*|\.\d+)$/;
542
+ const relativeMatch = trimmed.match(/^([+-])=([+-]?(?:\d+\.?\d*|\.\d+))$/);
543
+ if (relativeMatch) {
544
+ const amount = Number.parseFloat(relativeMatch[2]);
545
+ if (!Number.isFinite(amount)) return null;
546
+ return relativeMatch[1] === "+" ? amount : -amount;
547
+ }
548
+ if (numberPattern.test(trimmed)) {
549
+ const amount = Number.parseFloat(trimmed);
550
+ return Number.isFinite(amount) ? amount : null;
551
+ }
552
+ return null;
553
+ }
554
+ function findAnimationName(el) {
555
+ const classList = Array.from(el.classList);
556
+ for (const className of classList) {
557
+ if (getAnimation(className)) return className;
558
+ }
559
+ return null;
560
+ }
561
+ function collectExternalControls(slide, options) {
562
+ const root = slide.closest(options.selectors.root);
563
+ if (!root) return [];
564
+ const rootId = root.getAttribute("id");
565
+ const selector = `${options.selectors.prev}, ${options.selectors.next}`;
566
+ let candidates = [];
567
+ if (rootId) {
568
+ const scopedSelector = `${selector}[data-for="${rootId}"]`;
569
+ candidates = Array.from(document.querySelectorAll(scopedSelector));
570
+ if (!candidates.length) {
571
+ candidates = Array.from(root.querySelectorAll(selector));
572
+ }
573
+ } else {
574
+ candidates = Array.from(root.querySelectorAll(selector));
575
+ }
576
+ return candidates.filter((el) => !el.closest(options.selectors.slide));
577
+ }
578
+ function collectAnimItems(slide, options) {
579
+ const elements = Array.from(slide.querySelectorAll("[class]"));
580
+ const externalControls = collectExternalControls(slide, options);
581
+ const items = [];
582
+ elements.concat(externalControls).forEach((el) => {
583
+ var _a, _b;
584
+ const animName = findAnimationName(el);
585
+ if (!animName) return;
586
+ const seq = Math.max(1, Math.floor(getDataNumber(el, "data-seq", 1)));
587
+ const exitSeq = Math.max(1, Math.floor(getDataNumber(el, "data-exit-seq", seq)));
588
+ const dur = getDataNumber(el, "data-dur", options.defaults.dur);
589
+ const delay = getDataNumber(el, "data-delay", 0);
590
+ const ease = (_a = getDataString(el, "data-ease")) != null ? _a : options.defaults.ease;
591
+ const exitDur = getDataNumber(el, "data-exit-dur", dur);
592
+ const exitDelay = getDataNumber(el, "data-exit-delay", delay);
593
+ const exitEase = (_b = getDataString(el, "data-exit-ease")) != null ? _b : ease;
594
+ const at = getDataString(el, "data-at");
595
+ items.push({ el, animName, seq, exitSeq, dur, delay, ease, exitDur, exitDelay, exitEase, at });
596
+ });
597
+ return items;
598
+ }
599
+ function groupBySequence(items, getSequence) {
600
+ const map = /* @__PURE__ */ new Map();
601
+ items.forEach((item) => {
602
+ var _a;
603
+ const sequence = getSequence(item);
604
+ const bucket = (_a = map.get(sequence)) != null ? _a : [];
605
+ bucket.push(item);
606
+ map.set(sequence, bucket);
607
+ });
608
+ return map;
609
+ }
610
+ function buildSlideEnterTimeline(slide, direction, options, gsapInstance) {
611
+ const tl = gsapInstance.timeline();
612
+ const items = collectAnimItems(slide, options);
613
+ if (!items.length) return tl;
614
+ const grouped = groupBySequence(items, (item) => item.seq);
615
+ const order = Array.from(grouped.keys()).sort((a, b) => a - b);
616
+ let cursor = 0;
617
+ order.forEach((seq) => {
618
+ const group = grouped.get(seq);
619
+ if (!group) return;
620
+ let groupMax = 0;
621
+ group.forEach((item) => {
622
+ var _a;
623
+ const factory = getAnimation(item.animName);
624
+ if (!factory) return;
625
+ const offset = (_a = parsePositionOffset(item.at)) != null ? _a : 0;
626
+ const position = cursor + offset;
627
+ factory({
628
+ el: item.el,
629
+ tl,
630
+ gsap: gsapInstance,
631
+ opts: {
632
+ dur: item.dur,
633
+ delay: item.delay,
634
+ ease: item.ease,
635
+ direction,
636
+ at: position
637
+ }
638
+ });
639
+ groupMax = Math.max(groupMax, offset + item.delay + item.dur);
640
+ });
641
+ cursor += Math.max(groupMax, 0);
642
+ });
643
+ return tl;
644
+ }
645
+ function buildSlideExitTimeline(slide, direction, options, gsapInstance) {
646
+ const tl = gsapInstance.timeline();
647
+ const items = collectAnimItems(slide, options);
648
+ if (!items.length) return tl;
649
+ const grouped = groupBySequence(items, (item) => item.exitSeq);
650
+ const order = Array.from(grouped.keys()).sort((a, b) => a - b);
651
+ let cursor = 0;
652
+ order.forEach((seq) => {
653
+ const group = grouped.get(seq);
654
+ if (!group) return;
655
+ let groupMax = 0;
656
+ group.forEach((item) => {
657
+ var _a;
658
+ const exitName = getDataString(item.el, "data-exit");
659
+ const factory = exitName ? getAnimation(exitName) : getAnimation(item.animName);
660
+ const reverseFactory = factory && "reverse" in factory ? factory.reverse : void 0;
661
+ const offset = (_a = parsePositionOffset(item.at)) != null ? _a : 0;
662
+ const position = cursor + offset;
663
+ let usedDuration = item.exitDur;
664
+ if (exitName && factory) {
665
+ factory({
666
+ el: item.el,
667
+ tl,
668
+ gsap: gsapInstance,
669
+ opts: {
670
+ dur: item.exitDur,
671
+ delay: item.exitDelay,
672
+ ease: item.exitEase,
673
+ direction,
674
+ at: position
675
+ }
676
+ });
677
+ } else if (!exitName && reverseFactory) {
678
+ reverseFactory({
679
+ el: item.el,
680
+ tl,
681
+ gsap: gsapInstance,
682
+ opts: {
683
+ dur: item.exitDur,
684
+ delay: item.exitDelay,
685
+ ease: item.exitEase,
686
+ direction,
687
+ at: position
688
+ }
689
+ });
690
+ } else {
691
+ tl.to(
692
+ item.el,
693
+ {
694
+ autoAlpha: 0,
695
+ duration: usedDuration,
696
+ delay: item.exitDelay,
697
+ ease: item.exitEase
698
+ },
699
+ position
700
+ );
701
+ }
702
+ groupMax = Math.max(groupMax, offset + item.exitDelay + usedDuration);
703
+ });
704
+ cursor += Math.max(groupMax, 0);
705
+ });
706
+ return tl;
707
+ }
708
+
709
+ // src/reducedMotion.ts
710
+ function prefersReducedMotion() {
711
+ if (typeof window === "undefined" || !("matchMedia" in window)) {
712
+ return false;
713
+ }
714
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
715
+ }
716
+
717
+ // src/carousel.ts
718
+ var generatedDotSelector = '[data-carousel-dot="true"]';
719
+ function createCarousel(rootInput, options = {}) {
720
+ var _a, _b, _c, _d;
721
+ ensureDefaultAnimationsRegistered();
722
+ const root = resolveRoot(rootInput);
723
+ const gsapInstance = (_a = options.gsap) != null ? _a : gsap;
724
+ ensureRootFocusable(root);
725
+ const ctx = gsapInstance.context(() => {
726
+ }, root);
727
+ const resolved = {
728
+ loop: (_b = options.loop) != null ? _b : defaultOptions.loop,
729
+ initialIndex: (_c = options.initialIndex) != null ? _c : defaultOptions.initialIndex,
730
+ transition: { ...defaultOptions.transition, ...options.transition },
731
+ selectors: { ...defaultSelectors, ...options.selectors },
732
+ classNames: { ...defaultClassNames, ...options.classNames },
733
+ defaults: { ...defaultOptions.defaults, ...options.defaults },
734
+ onInit: options.onInit,
735
+ onBeforeChange: options.onBeforeChange,
736
+ onAfterChange: options.onAfterChange
737
+ };
738
+ const slides = qsa(root, resolved.selectors.slide);
739
+ if (!slides.length) {
740
+ throw new Error("Carousel requires at least one slide element.");
741
+ }
742
+ const controls = resolveControls(root, resolved, slides.length);
743
+ const reducedMotion = prefersReducedMotion();
744
+ const state = { activeTimeline: null };
745
+ let currentIndex = normalizeIndex(resolved.initialIndex, slides.length, resolved.loop);
746
+ let animating = false;
747
+ setSlidesState(slides, currentIndex, resolved.classNames.activeSlide);
748
+ setAllDotsState(currentIndex);
749
+ const onPrevClick = (event) => {
750
+ event.preventDefault();
751
+ prev();
752
+ };
753
+ const onNextClick = (event) => {
754
+ event.preventDefault();
755
+ next();
756
+ };
757
+ const onDotsClick = (event) => {
758
+ var _a2;
759
+ const target = (_a2 = event.target) == null ? void 0 : _a2.closest(generatedDotSelector);
760
+ if (!target) return;
761
+ event.preventDefault();
762
+ const indexAttr = target.getAttribute("data-carousel-dot-index");
763
+ if (!indexAttr) return;
764
+ const index = Number.parseInt(indexAttr, 10);
765
+ if (!Number.isFinite(index)) return;
766
+ if (animating) return;
767
+ const nextIndex = normalizeIndex(index, slides.length, resolved.loop);
768
+ if (nextIndex === currentIndex) return;
769
+ setAllDotsState(nextIndex);
770
+ goTo(nextIndex);
771
+ };
772
+ controls.prev.forEach((control) => control.addEventListener("click", onPrevClick));
773
+ controls.next.forEach((control) => control.addEventListener("click", onNextClick));
774
+ controls.dotsContainers.forEach((container) => container.addEventListener("click", onDotsClick));
775
+ const instance = {
776
+ goTo,
777
+ next,
778
+ prev,
779
+ destroy,
780
+ getIndex: () => currentIndex,
781
+ getCount: () => slides.length,
782
+ isAnimating: () => animating
783
+ };
784
+ (_d = resolved.onInit) == null ? void 0 : _d.call(resolved, instance);
785
+ function disableControls(disabled) {
786
+ toggleClass(root, resolved.classNames.animatingRoot, disabled);
787
+ controls.prev.forEach((control) => {
788
+ setDisabled(control, disabled, resolved.classNames.disabledControl);
789
+ });
790
+ controls.next.forEach((control) => {
791
+ setDisabled(control, disabled, resolved.classNames.disabledControl);
792
+ });
793
+ controls.dotsContainers.forEach((container) => {
794
+ setAriaDisabled(container, disabled);
795
+ });
796
+ controls.dots.forEach((dotGroup) => {
797
+ dotGroup.forEach((dot) => {
798
+ setAriaDisabled(dot, disabled);
799
+ toggleClass(dot, resolved.classNames.disabledControl, disabled);
800
+ });
801
+ });
802
+ }
803
+ function setAllDotsState(activeIndex) {
804
+ controls.dots.forEach((dotGroup) => {
805
+ setDotsState(dotGroup, activeIndex, resolved.classNames.activeDot);
806
+ });
807
+ }
808
+ function applyActiveState(nextIndex) {
809
+ currentIndex = nextIndex;
810
+ setSlidesState(slides, currentIndex, resolved.classNames.activeSlide);
811
+ setAllDotsState(currentIndex);
812
+ }
813
+ function finalizeTransition(from, to, direction) {
814
+ var _a2;
815
+ animating = false;
816
+ disableControls(false);
817
+ state.activeTimeline = null;
818
+ (_a2 = resolved.onAfterChange) == null ? void 0 : _a2.call(resolved, { from, to, direction });
819
+ }
820
+ function transitionTo(nextIndex, immediate) {
821
+ var _a2, _b2;
822
+ if (animating) return;
823
+ if (nextIndex === currentIndex) return;
824
+ const from = currentIndex;
825
+ const to = nextIndex;
826
+ const direction = getDirection(from, to, slides.length, resolved.loop);
827
+ animating = true;
828
+ disableControls(true);
829
+ (_a2 = resolved.onBeforeChange) == null ? void 0 : _a2.call(resolved, { from, to, direction });
830
+ if (immediate || reducedMotion) {
831
+ applyActiveState(to);
832
+ finalizeTransition(from, to, direction);
833
+ return;
834
+ }
835
+ const exitTl = ctx.add(() => buildSlideExitTimeline(slides[from], direction, resolved, gsapInstance));
836
+ const enterTl = ctx.add(() => buildSlideEnterTimeline(slides[to], direction, resolved, gsapInstance));
837
+ const master = ctx.add(
838
+ () => gsapInstance.timeline({
839
+ onComplete: () => {
840
+ finalizeTransition(from, to, direction);
841
+ }
842
+ })
843
+ );
844
+ state.activeTimeline = master;
845
+ const overlap = Math.max(0, (_b2 = resolved.transition.exitOverlap) != null ? _b2 : resolved.transition.overlap);
846
+ const enterAt = Math.max(0, exitTl.duration() - overlap);
847
+ master.add(exitTl, 0);
848
+ master.add(() => applyActiveState(to), enterAt);
849
+ master.add(enterTl, enterAt);
850
+ }
851
+ function goTo(index, opts) {
852
+ if (animating) return;
853
+ const nextIndex = normalizeIndex(index, slides.length, resolved.loop);
854
+ if (nextIndex === currentIndex) return;
855
+ transitionTo(nextIndex, opts == null ? void 0 : opts.immediate);
856
+ }
857
+ function next(opts) {
858
+ if (animating) return;
859
+ const nextIndex = resolveNextIndex(currentIndex, slides.length, resolved.loop);
860
+ if (nextIndex === currentIndex) return;
861
+ setAllDotsState(nextIndex);
862
+ transitionTo(nextIndex, opts == null ? void 0 : opts.immediate);
863
+ }
864
+ function prev(opts) {
865
+ if (animating) return;
866
+ const nextIndex = resolvePrevIndex(currentIndex, slides.length, resolved.loop);
867
+ if (nextIndex === currentIndex) return;
868
+ setAllDotsState(nextIndex);
869
+ transitionTo(nextIndex, opts == null ? void 0 : opts.immediate);
870
+ }
871
+ function destroy() {
872
+ var _a2;
873
+ controls.prev.forEach((control) => control.removeEventListener("click", onPrevClick));
874
+ controls.next.forEach((control) => control.removeEventListener("click", onNextClick));
875
+ controls.dotsContainers.forEach((container) => container.removeEventListener("click", onDotsClick));
876
+ (_a2 = state.activeTimeline) == null ? void 0 : _a2.kill();
877
+ animating = false;
878
+ ctx.revert();
879
+ controls.dotsContainers.forEach((container) => {
880
+ container.querySelectorAll(generatedDotSelector).forEach((dot) => {
881
+ dot.remove();
882
+ });
883
+ });
884
+ controls.dotTemplates.forEach((template) => {
885
+ if (template) {
886
+ template.hidden = false;
887
+ }
888
+ });
889
+ }
890
+ return instance;
891
+ }
892
+ function resolveControls(root, options, slideCount) {
893
+ const rootId = root.getAttribute("id");
894
+ const queryAllWithFallback = (selector) => {
895
+ if (rootId) {
896
+ const scoped = Array.from(document.querySelectorAll(`${selector}[data-for="${rootId}"]`));
897
+ if (scoped.length) return scoped;
898
+ }
899
+ return qsa(root, selector);
900
+ };
901
+ const prev = queryAllWithFallback(options.selectors.prev);
902
+ const next = queryAllWithFallback(options.selectors.next);
903
+ const dotsContainers = queryAllWithFallback(options.selectors.dots);
904
+ const dotTemplates = [];
905
+ const dots = dotsContainers.map((container) => {
906
+ const template = qs(container, options.selectors.dotTemplate);
907
+ dotTemplates.push(template);
908
+ return setupDots(container, template, options, slideCount);
909
+ });
910
+ return { prev, next, dotsContainers, dotTemplates, dots };
911
+ }
912
+ function setupDots(container, template, options, slideCount) {
913
+ const dots = qsa(container, generatedDotSelector);
914
+ dots.forEach((dot) => dot.remove());
915
+ if (!template) return [];
916
+ const clones = [];
917
+ const disableOpacityAttr = template.getAttribute("data-carousel-disable-opacity");
918
+ for (let i = 0; i < slideCount; i += 1) {
919
+ const clone = template.cloneNode(true);
920
+ clone.removeAttribute("id");
921
+ clone.setAttribute("data-carousel-dot", "true");
922
+ clone.setAttribute("data-carousel-dot-index", String(i));
923
+ if (disableOpacityAttr !== null) {
924
+ clone.setAttribute("data-carousel-disable-opacity", disableOpacityAttr);
925
+ } else {
926
+ clone.removeAttribute("data-carousel-disable-opacity");
927
+ }
928
+ clone.setAttribute("aria-label", `Go to slide ${i + 1}`);
929
+ clone.classList.add(options.classNames.dot);
930
+ if (clone instanceof HTMLButtonElement && !clone.getAttribute("type")) {
931
+ clone.setAttribute("type", "button");
932
+ }
933
+ container.appendChild(clone);
934
+ clones.push(clone);
935
+ }
936
+ template.hidden = true;
937
+ return clones;
938
+ }
939
+ function normalizeIndex(index, count, loop) {
940
+ if (count <= 0) return 0;
941
+ if (loop) {
942
+ const wrapped = (index % count + count) % count;
943
+ return wrapped;
944
+ }
945
+ if (index < 0) return 0;
946
+ if (index >= count) return count - 1;
947
+ return index;
948
+ }
949
+ function resolveNextIndex(current, count, loop) {
950
+ if (count <= 0) return current;
951
+ if (current + 1 < count) return current + 1;
952
+ return loop ? 0 : current;
953
+ }
954
+ function resolvePrevIndex(current, count, loop) {
955
+ if (count <= 0) return current;
956
+ if (current - 1 >= 0) return current - 1;
957
+ return loop ? count - 1 : current;
958
+ }
959
+ function getDirection(from, to, count, loop) {
960
+ if (!loop) return to > from ? 1 : -1;
961
+ if (from === count - 1 && to === 0) return 1;
962
+ if (from === 0 && to === count - 1) return -1;
963
+ return to > from ? 1 : -1;
964
+ }
965
+ function registerGsapPlugins(...plugins) {
966
+ gsap.registerPlugin(...plugins);
967
+ }
968
+
969
+ export { createCarousel, registerAnimation, registerAnimations, registerGsapPlugins };
970
+ //# sourceMappingURL=index.js.map
971
+ //# sourceMappingURL=index.js.map