tw-slide 0.1.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 ADDED
@@ -0,0 +1,183 @@
1
+ # tw-slide
2
+
3
+ Modern, lightweight presentation library powered by **Tailwind CSS**.
4
+
5
+ Style your slides with utility classes you already know. No themes, no config files — just HTML + Tailwind.
6
+
7
+ ## Features
8
+
9
+ - **Tailwind-native** — style every slide with utility classes
10
+ - **Tiny** — ~4.5KB gzipped, zero runtime dependencies
11
+ - **6 transitions** — fade, slide, zoom, flip, cube, none
12
+ - **8 fragment animations** — fade-in, fade-up, fade-down, fade-left, fade-right, grow, shrink, highlight
13
+ - **Plugin system** — progress bar, slide numbers, overview mode
14
+ - **TypeScript-first** — full type safety and autocompletion
15
+ - **Keyboard & touch** — arrow keys, swipe gestures, hash navigation
16
+ - **Dark / light mode** — one class toggle
17
+ - **Accessible** — respects `prefers-reduced-motion`
18
+ - **Print-ready** — built-in PDF export styles
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ npm install tw-slide
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ### HTML
29
+
30
+ ```html
31
+ <div class="ts-deck ts-dark">
32
+ <section class="ts-slide">
33
+ <div class="ts-content text-center">
34
+ <h1 class="text-6xl font-bold text-white">Hello, TailSlide</h1>
35
+ <p class="text-xl text-gray-400 mt-4">Press → to continue</p>
36
+ </div>
37
+ </section>
38
+
39
+ <section class="ts-slide">
40
+ <div class="ts-content">
41
+ <h2 class="text-4xl font-bold text-white">Fragments</h2>
42
+ <p class="ts-fragment text-gray-300" data-ts-animation="fade-up">I appear first</p>
43
+ <p class="ts-fragment text-gray-300" data-ts-animation="fade-up">I appear second</p>
44
+ </div>
45
+ </section>
46
+ </div>
47
+ ```
48
+
49
+ ### JavaScript
50
+
51
+ ```js
52
+ import TailSlide, { ProgressPlugin, SlideNumberPlugin, OverviewPlugin } from 'tw-slide';
53
+ import 'tw-slide/style.css';
54
+
55
+ const deck = new TailSlide({
56
+ transition: 'slide',
57
+ dark: true,
58
+ });
59
+
60
+ deck.use(new ProgressPlugin());
61
+ deck.use(new SlideNumberPlugin());
62
+ deck.use(new OverviewPlugin());
63
+ ```
64
+
65
+ ## Configuration
66
+
67
+ ```js
68
+ new TailSlide({
69
+ el: '.ts-deck', // container selector or element
70
+ transition: 'slide', // none | fade | slide | zoom | flip | cube
71
+ transitionSpeed: 500, // transition duration in ms
72
+ easing: 'ease-in-out', // CSS easing function
73
+ keyboard: true, // enable keyboard navigation
74
+ touch: true, // enable touch/swipe
75
+ hash: true, // sync URL hash with current slide
76
+ progress: true, // show progress bar (needs ProgressPlugin)
77
+ slideNumber: true, // show slide numbers (needs SlideNumberPlugin)
78
+ dark: true, // dark mode
79
+ loop: false, // loop back to first slide
80
+ autoSlide: 0, // auto-advance interval in ms (0 = off)
81
+ startSlide: 0, // starting slide index
82
+ });
83
+ ```
84
+
85
+ ## Keyboard Shortcuts
86
+
87
+ | Key | Action |
88
+ |-----|--------|
89
+ | `→` `↓` `Space` `N` | Next slide / fragment |
90
+ | `←` `↑` `P` | Previous slide / fragment |
91
+ | `Home` | First slide |
92
+ | `End` | Last slide |
93
+ | `O` | Toggle overview mode |
94
+ | `Esc` | Toggle overview mode |
95
+
96
+ ## Fragments
97
+
98
+ Add `ts-fragment` class to reveal elements step by step. Set animation type with `data-ts-animation`:
99
+
100
+ ```html
101
+ <p class="ts-fragment" data-ts-animation="fade-up">Appears with fade-up</p>
102
+ <p class="ts-fragment" data-ts-animation="grow">Appears with grow</p>
103
+ ```
104
+
105
+ **Available animations:** `fade-in` (default), `fade-up`, `fade-down`, `fade-left`, `fade-right`, `grow`, `shrink`, `highlight`
106
+
107
+ ## Plugins
108
+
109
+ ### ProgressPlugin
110
+
111
+ Thin progress bar at the top of the viewport.
112
+
113
+ ```js
114
+ deck.use(new ProgressPlugin());
115
+ ```
116
+
117
+ ### SlideNumberPlugin
118
+
119
+ Displays current / total slide number at bottom-right.
120
+
121
+ ```js
122
+ deck.use(new SlideNumberPlugin());
123
+ ```
124
+
125
+ ### OverviewPlugin
126
+
127
+ Grid overview of all slides. Toggle with `O` key or click a slide to navigate.
128
+
129
+ ```js
130
+ deck.use(new OverviewPlugin());
131
+ ```
132
+
133
+ ## API
134
+
135
+ ```js
136
+ deck.next(); // next fragment or slide
137
+ deck.prev(); // previous fragment or slide
138
+ deck.goTo(3); // jump to slide index
139
+ deck.getState(); // { currentSlide, currentFragment, totalSlides, ... }
140
+ deck.toggleOverview(); // toggle overview mode
141
+ deck.on('slide:changed', (e) => console.log(e.from, e.to));
142
+ deck.destroy(); // clean up
143
+ ```
144
+
145
+ ### Events
146
+
147
+ | Event | Payload |
148
+ |-------|---------|
149
+ | `slide:changed` | `{ from: number, to: number }` |
150
+ | `fragment:shown` | `{ slide: number, fragment: number, element: HTMLElement }` |
151
+ | `fragment:hidden` | `{ slide: number, fragment: number, element: HTMLElement }` |
152
+ | `deck:ready` | `{ totalSlides: number }` |
153
+ | `deck:destroyed` | `{}` |
154
+ | `overview:open` | `{}` |
155
+ | `overview:close` | `{}` |
156
+
157
+ ## Custom Plugin
158
+
159
+ ```ts
160
+ import type { TailSlidePlugin, TailSlideAPI } from 'tw-slide';
161
+
162
+ class MyPlugin implements TailSlidePlugin {
163
+ name = 'my-plugin';
164
+
165
+ init(deck: TailSlideAPI) {
166
+ deck.on('slide:changed', ({ to }) => {
167
+ console.log(`Now on slide ${to}`);
168
+ });
169
+ }
170
+
171
+ destroy() {}
172
+ }
173
+
174
+ deck.use(new MyPlugin());
175
+ ```
176
+
177
+ ## Browser Support
178
+
179
+ All modern browsers (Chrome, Firefox, Safari, Edge). Uses [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API).
180
+
181
+ ## License
182
+
183
+ MIT
@@ -0,0 +1,8 @@
1
+ import { TailSlideEvents, EventCallback } from '../types';
2
+ export declare class EventEmitter {
3
+ private listeners;
4
+ on<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
5
+ off<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
6
+ emit<K extends keyof TailSlideEvents>(event: K, data: TailSlideEvents[K]): void;
7
+ removeAll(): void;
8
+ }
@@ -0,0 +1,19 @@
1
+ import { TailSlideAPI, TailSlideConfig } from '../types';
2
+ export declare class Navigation {
3
+ private deck;
4
+ private config;
5
+ private container;
6
+ private touchStartX;
7
+ private touchStartY;
8
+ private handleKeyDown;
9
+ private handleClick;
10
+ private handleTouchStart;
11
+ private handleTouchEnd;
12
+ constructor(deck: TailSlideAPI, config: Required<TailSlideConfig>);
13
+ private bind;
14
+ private onKeyDown;
15
+ private onClick;
16
+ private onTouchStart;
17
+ private onTouchEnd;
18
+ destroy(): void;
19
+ }
@@ -0,0 +1,16 @@
1
+ import { DeckState } from '../types';
2
+ export declare class StateManager {
3
+ private state;
4
+ constructor(totalSlides: number);
5
+ get(): DeckState;
6
+ get currentSlide(): number;
7
+ set currentSlide(value: number);
8
+ get currentFragment(): number;
9
+ set currentFragment(value: number);
10
+ get totalSlides(): number;
11
+ set totalSlides(value: number);
12
+ get isOverview(): boolean;
13
+ set isOverview(value: boolean);
14
+ get isPaused(): boolean;
15
+ set isPaused(value: boolean);
16
+ }
@@ -0,0 +1,33 @@
1
+ import { TailSlideConfig, TailSlideAPI, TailSlidePlugin, TailSlideEvents, DeckState, EventCallback } from '../types';
2
+ export declare class TailSlide implements TailSlideAPI {
3
+ private config;
4
+ private container;
5
+ private slides;
6
+ private events;
7
+ private state;
8
+ private navigation;
9
+ private plugins;
10
+ private fragmentManager;
11
+ private autoSlideTimer;
12
+ private hashChangeHandler;
13
+ constructor(config?: TailSlideConfig);
14
+ goTo(index: number): void;
15
+ next(): void;
16
+ prev(): void;
17
+ getState(): DeckState;
18
+ getConfig(): Required<TailSlideConfig>;
19
+ getContainer(): HTMLElement;
20
+ getSlides(): HTMLElement[];
21
+ getFragments(slideIndex: number): HTMLElement[];
22
+ on<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
23
+ off<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
24
+ use(plugin: TailSlidePlugin): void;
25
+ toggleOverview(): void;
26
+ destroy(): void;
27
+ private updateSlideClasses;
28
+ private clamp;
29
+ private getSlideFromHash;
30
+ private syncHash;
31
+ private startAutoSlide;
32
+ private stopAutoSlide;
33
+ }
@@ -0,0 +1,7 @@
1
+ export declare class FragmentManager {
2
+ getFragments(slide: HTMLElement): HTMLElement[];
3
+ show(el: HTMLElement): void;
4
+ hide(el: HTMLElement): void;
5
+ showAllUpTo(fragments: HTMLElement[], index: number): void;
6
+ hideAllFrom(fragments: HTMLElement[], index: number): void;
7
+ }
@@ -0,0 +1,6 @@
1
+ export { TailSlide } from './core/TailSlide';
2
+ export { TailSlide as default } from './core/TailSlide';
3
+ export { ProgressPlugin } from './plugins/progress';
4
+ export { SlideNumberPlugin } from './plugins/slideNumber';
5
+ export { OverviewPlugin } from './plugins/overview';
6
+ export type { TailSlideConfig, TailSlideAPI, TailSlidePlugin, TailSlideEvents, DeckState, EventCallback, TransitionType, FragmentAnimation, EasingFunction, } from './types';
@@ -0,0 +1,13 @@
1
+ import { TailSlidePlugin, TailSlideAPI } from '../types';
2
+ export declare class OverviewPlugin implements TailSlidePlugin {
3
+ readonly name = "overview";
4
+ private deck;
5
+ private wrapper;
6
+ private keyHandler;
7
+ private clickHandler;
8
+ init(deck: TailSlideAPI): void;
9
+ destroy(): void;
10
+ private toggle;
11
+ private wrapSlides;
12
+ private unwrapSlides;
13
+ }
@@ -0,0 +1,10 @@
1
+ import { TailSlidePlugin, TailSlideAPI } from '../types';
2
+ export declare class ProgressPlugin implements TailSlidePlugin {
3
+ readonly name = "progress";
4
+ private bar;
5
+ private deck;
6
+ private handler;
7
+ init(deck: TailSlideAPI): void;
8
+ destroy(): void;
9
+ private update;
10
+ }
@@ -0,0 +1,10 @@
1
+ import { TailSlidePlugin, TailSlideAPI } from '../types';
2
+ export declare class SlideNumberPlugin implements TailSlidePlugin {
3
+ readonly name = "slideNumber";
4
+ private el;
5
+ private deck;
6
+ private handler;
7
+ init(deck: TailSlideAPI): void;
8
+ destroy(): void;
9
+ private update;
10
+ }
@@ -0,0 +1,564 @@
1
+ const p = {
2
+ el: ".ts-deck",
3
+ transition: "slide",
4
+ transitionSpeed: 500,
5
+ easing: "ease-in-out",
6
+ keyboard: !0,
7
+ hash: !0,
8
+ progress: !0,
9
+ slideNumber: !0,
10
+ touch: !0,
11
+ clickToAdvance: !1,
12
+ autoSlide: 0,
13
+ loop: !1,
14
+ startSlide: 0,
15
+ dark: !0,
16
+ deckClass: ""
17
+ };
18
+ class m {
19
+ constructor() {
20
+ this.listeners = /* @__PURE__ */ new Map();
21
+ }
22
+ on(t, e) {
23
+ this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(e);
24
+ }
25
+ off(t, e) {
26
+ var s;
27
+ (s = this.listeners.get(t)) == null || s.delete(e);
28
+ }
29
+ emit(t, e) {
30
+ var s;
31
+ (s = this.listeners.get(t)) == null || s.forEach((n) => n(e));
32
+ }
33
+ removeAll() {
34
+ this.listeners.clear();
35
+ }
36
+ }
37
+ class y {
38
+ constructor(t) {
39
+ this.state = {
40
+ currentSlide: 0,
41
+ currentFragment: -1,
42
+ totalSlides: t,
43
+ isOverview: !1,
44
+ isPaused: !1
45
+ };
46
+ }
47
+ get() {
48
+ return { ...this.state };
49
+ }
50
+ get currentSlide() {
51
+ return this.state.currentSlide;
52
+ }
53
+ set currentSlide(t) {
54
+ this.state.currentSlide = t;
55
+ }
56
+ get currentFragment() {
57
+ return this.state.currentFragment;
58
+ }
59
+ set currentFragment(t) {
60
+ this.state.currentFragment = t;
61
+ }
62
+ get totalSlides() {
63
+ return this.state.totalSlides;
64
+ }
65
+ set totalSlides(t) {
66
+ this.state.totalSlides = t;
67
+ }
68
+ get isOverview() {
69
+ return this.state.isOverview;
70
+ }
71
+ set isOverview(t) {
72
+ this.state.isOverview = t;
73
+ }
74
+ get isPaused() {
75
+ return this.state.isPaused;
76
+ }
77
+ set isPaused(t) {
78
+ this.state.isPaused = t;
79
+ }
80
+ }
81
+ const v = 50;
82
+ class w {
83
+ constructor(t, e) {
84
+ this.touchStartX = 0, this.touchStartY = 0, this.deck = t, this.config = e, this.container = t.getContainer(), this.handleKeyDown = this.onKeyDown.bind(this), this.handleClick = this.onClick.bind(this), this.handleTouchStart = this.onTouchStart.bind(this), this.handleTouchEnd = this.onTouchEnd.bind(this), this.bind();
85
+ }
86
+ bind() {
87
+ this.config.keyboard && document.addEventListener("keydown", this.handleKeyDown), this.config.clickToAdvance && this.container.addEventListener("click", this.handleClick), this.config.touch && (this.container.addEventListener("touchstart", this.handleTouchStart, {
88
+ passive: !0
89
+ }), this.container.addEventListener("touchend", this.handleTouchEnd));
90
+ }
91
+ onKeyDown(t) {
92
+ if (!(t.metaKey || t.ctrlKey || t.altKey))
93
+ switch (t.key) {
94
+ case "ArrowRight":
95
+ case "ArrowDown":
96
+ case " ":
97
+ case "n":
98
+ t.preventDefault(), this.deck.next();
99
+ break;
100
+ case "ArrowLeft":
101
+ case "ArrowUp":
102
+ case "p":
103
+ t.preventDefault(), this.deck.prev();
104
+ break;
105
+ case "Home":
106
+ t.preventDefault(), this.deck.goTo(0);
107
+ break;
108
+ case "End":
109
+ t.preventDefault(), this.deck.goTo(this.deck.getSlides().length - 1);
110
+ break;
111
+ case "Escape":
112
+ t.preventDefault(), this.deck.toggleOverview();
113
+ break;
114
+ }
115
+ }
116
+ onClick(t) {
117
+ this.deck.next();
118
+ }
119
+ onTouchStart(t) {
120
+ const e = t.touches[0];
121
+ this.touchStartX = e.clientX, this.touchStartY = e.clientY;
122
+ }
123
+ onTouchEnd(t) {
124
+ const e = t.changedTouches[0], s = e.clientX - this.touchStartX, n = e.clientY - this.touchStartY;
125
+ Math.abs(s) < v || Math.abs(n) > Math.abs(s) || (t.preventDefault(), s < 0 ? this.deck.next() : this.deck.prev());
126
+ }
127
+ destroy() {
128
+ document.removeEventListener("keydown", this.handleKeyDown), this.container.removeEventListener("click", this.handleClick), this.container.removeEventListener("touchstart", this.handleTouchStart), this.container.removeEventListener("touchend", this.handleTouchEnd);
129
+ }
130
+ }
131
+ const S = () => typeof window < "u" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
132
+ function l(i, t, e) {
133
+ return new Promise((s) => {
134
+ const n = i.animate(t, e);
135
+ n.onfinish = () => s(), n.oncancel = () => s();
136
+ });
137
+ }
138
+ async function k(i, t) {
139
+ i && (i.style.opacity = "0", i.style.pointerEvents = "none", i.classList.remove("ts-active")), t.style.opacity = "1", t.style.pointerEvents = "auto", t.classList.add("ts-active");
140
+ }
141
+ async function E(i, t, e, s) {
142
+ const n = [];
143
+ t.style.opacity = "0", t.style.pointerEvents = "auto", t.classList.add("ts-active"), n.push(
144
+ l(t, [{ opacity: 0 }, { opacity: 1 }], {
145
+ duration: e,
146
+ easing: s,
147
+ fill: "forwards"
148
+ })
149
+ ), i && n.push(
150
+ l(i, [{ opacity: 1 }, { opacity: 0 }], {
151
+ duration: e,
152
+ easing: s,
153
+ fill: "forwards"
154
+ }).then(() => {
155
+ i.style.opacity = "0", i.style.pointerEvents = "none", i.classList.remove("ts-active");
156
+ })
157
+ ), await Promise.all(n), t.style.opacity = "1";
158
+ }
159
+ async function L(i, t, e, s, n) {
160
+ const a = n === "forward" ? "100%" : "-100%", o = n === "forward" ? "-100%" : "100%", r = [];
161
+ t.style.opacity = "1", t.style.pointerEvents = "auto", t.classList.add("ts-active"), r.push(
162
+ l(
163
+ t,
164
+ [
165
+ { transform: `translateX(${a})`, opacity: 1 },
166
+ { transform: "translateX(0)", opacity: 1 }
167
+ ],
168
+ { duration: e, easing: s, fill: "forwards" }
169
+ )
170
+ ), i && r.push(
171
+ l(
172
+ i,
173
+ [
174
+ { transform: "translateX(0)", opacity: 1 },
175
+ { transform: `translateX(${o})`, opacity: 1 }
176
+ ],
177
+ { duration: e, easing: s, fill: "forwards" }
178
+ ).then(() => {
179
+ i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.classList.remove("ts-active");
180
+ })
181
+ ), await Promise.all(r), t.style.transform = "";
182
+ }
183
+ async function T(i, t, e, s, n) {
184
+ const a = n === "forward" ? "scale(0.8)" : "scale(1.2)", o = n === "forward" ? "scale(1.2)" : "scale(0.8)", r = [];
185
+ t.style.opacity = "0", t.style.pointerEvents = "auto", t.classList.add("ts-active"), r.push(
186
+ l(
187
+ t,
188
+ [
189
+ { transform: a, opacity: 0 },
190
+ { transform: "scale(1)", opacity: 1 }
191
+ ],
192
+ { duration: e, easing: s, fill: "forwards" }
193
+ )
194
+ ), i && r.push(
195
+ l(
196
+ i,
197
+ [
198
+ { transform: "scale(1)", opacity: 1 },
199
+ { transform: o, opacity: 0 }
200
+ ],
201
+ { duration: e, easing: s, fill: "forwards" }
202
+ ).then(() => {
203
+ i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.classList.remove("ts-active");
204
+ })
205
+ ), await Promise.all(r), t.style.opacity = "1", t.style.transform = "";
206
+ }
207
+ async function b(i, t, e, s, n) {
208
+ const a = n === "forward" ? -180 : 180, o = n === "forward" ? 180 : -180, r = e / 2, c = t.parentElement;
209
+ c && (c.style.perspective = "1200px"), i && (await l(
210
+ i,
211
+ [
212
+ { transform: "rotateY(0deg)", opacity: 1 },
213
+ { transform: `rotateY(${o}deg)`, opacity: 0 }
214
+ ],
215
+ { duration: r, easing: s, fill: "forwards" }
216
+ ), i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.classList.remove("ts-active")), t.style.pointerEvents = "auto", t.classList.add("ts-active"), await l(
217
+ t,
218
+ [
219
+ { transform: `rotateY(${a}deg)`, opacity: 0 },
220
+ { transform: "rotateY(0deg)", opacity: 1 }
221
+ ],
222
+ { duration: r, easing: s, fill: "forwards" }
223
+ ), t.style.opacity = "1", t.style.transform = "";
224
+ }
225
+ async function C(i, t, e, s, n) {
226
+ const a = t.parentElement;
227
+ a && (a.style.perspective = "1200px");
228
+ const o = n === "forward" ? 90 : -90, r = n === "forward" ? -90 : 90, c = "translateZ(-50vw)", h = [];
229
+ t.style.pointerEvents = "auto", t.classList.add("ts-active"), t.style.transformOrigin = n === "forward" ? "left center" : "right center", h.push(
230
+ l(
231
+ t,
232
+ [
233
+ {
234
+ transform: `${c} rotateY(${o}deg)`,
235
+ opacity: 0.6
236
+ },
237
+ { transform: "translateZ(0) rotateY(0deg)", opacity: 1 }
238
+ ],
239
+ { duration: e, easing: s, fill: "forwards" }
240
+ ).then(() => {
241
+ t.style.opacity = "1", t.style.transform = "", t.style.transformOrigin = "";
242
+ })
243
+ ), i && (i.style.transformOrigin = n === "forward" ? "right center" : "left center", h.push(
244
+ l(
245
+ i,
246
+ [
247
+ { transform: "translateZ(0) rotateY(0deg)", opacity: 1 },
248
+ {
249
+ transform: `${c} rotateY(${r}deg)`,
250
+ opacity: 0.6
251
+ }
252
+ ],
253
+ { duration: e, easing: s, fill: "forwards" }
254
+ ).then(() => {
255
+ i.style.opacity = "0", i.style.pointerEvents = "none", i.style.transform = "", i.style.transformOrigin = "", i.classList.remove("ts-active");
256
+ })
257
+ )), await Promise.all(h);
258
+ }
259
+ async function A(i, t, e, s) {
260
+ const n = S() ? "none" : e, { duration: a, easing: o, direction: r = "forward" } = s;
261
+ switch (n) {
262
+ case "none":
263
+ return k(i, t);
264
+ case "fade":
265
+ return E(i, t, a, o);
266
+ case "slide":
267
+ return L(i, t, a, o, r);
268
+ case "zoom":
269
+ return T(i, t, a, o, r);
270
+ case "flip":
271
+ return b(i, t, a, o, r);
272
+ case "cube":
273
+ return C(i, t, a, o, r);
274
+ }
275
+ }
276
+ const d = 300, u = "ease-out";
277
+ function f(i) {
278
+ switch (i) {
279
+ case "fade-in":
280
+ return {
281
+ from: { opacity: 0 },
282
+ to: { opacity: 1 }
283
+ };
284
+ case "fade-up":
285
+ return {
286
+ from: { opacity: 0, transform: "translateY(20px)" },
287
+ to: { opacity: 1, transform: "translateY(0)" }
288
+ };
289
+ case "fade-down":
290
+ return {
291
+ from: { opacity: 0, transform: "translateY(-20px)" },
292
+ to: { opacity: 1, transform: "translateY(0)" }
293
+ };
294
+ case "fade-left":
295
+ return {
296
+ from: { opacity: 0, transform: "translateX(20px)" },
297
+ to: { opacity: 1, transform: "translateX(0)" }
298
+ };
299
+ case "fade-right":
300
+ return {
301
+ from: { opacity: 0, transform: "translateX(-20px)" },
302
+ to: { opacity: 1, transform: "translateX(0)" }
303
+ };
304
+ case "grow":
305
+ return {
306
+ from: { opacity: 0, transform: "scale(0.5)" },
307
+ to: { opacity: 1, transform: "scale(1)" }
308
+ };
309
+ case "shrink":
310
+ return {
311
+ from: { opacity: 0, transform: "scale(1.5)" },
312
+ to: { opacity: 1, transform: "scale(1)" }
313
+ };
314
+ case "highlight":
315
+ return {
316
+ from: { backgroundColor: "transparent" },
317
+ to: { backgroundColor: "rgba(255, 213, 79, 0.4)" }
318
+ };
319
+ }
320
+ }
321
+ function g(i) {
322
+ return i.dataset.tsAnimation || "fade-in";
323
+ }
324
+ class F {
325
+ getFragments(t) {
326
+ const e = t.querySelectorAll(".ts-fragment");
327
+ return Array.from(e).sort((s, n) => {
328
+ const a = parseInt(s.dataset.tsIndex || "0", 10), o = parseInt(n.dataset.tsIndex || "0", 10);
329
+ return a !== o ? a - o : 0;
330
+ });
331
+ }
332
+ show(t) {
333
+ const e = g(t), { from: s, to: n } = f(e);
334
+ t.classList.add("ts-fragment-visible"), t.animate([s, n], {
335
+ duration: d,
336
+ easing: u,
337
+ fill: "forwards"
338
+ });
339
+ }
340
+ hide(t) {
341
+ const e = g(t), { from: s, to: n } = f(e);
342
+ t.classList.remove("ts-fragment-visible"), t.animate([n, s], {
343
+ duration: d,
344
+ easing: u,
345
+ fill: "forwards"
346
+ });
347
+ }
348
+ showAllUpTo(t, e) {
349
+ for (let s = 0; s <= e && s < t.length; s++) {
350
+ const n = t[s];
351
+ n.classList.contains("ts-fragment-visible") || this.show(n);
352
+ }
353
+ }
354
+ hideAllFrom(t, e) {
355
+ for (let s = e; s < t.length; s++) {
356
+ const n = t[s];
357
+ n.classList.contains("ts-fragment-visible") && this.hide(n);
358
+ }
359
+ }
360
+ }
361
+ class H {
362
+ constructor(t = {}) {
363
+ this.slides = [], this.navigation = null, this.plugins = [], this.autoSlideTimer = null, this.hashChangeHandler = null, this.config = { ...p, ...t }, this.events = new m();
364
+ const e = this.config.el, s = typeof e == "string" ? document.querySelector(e) : e;
365
+ if (!s)
366
+ throw new Error(`TailSlide: container "${e}" not found`);
367
+ this.container = s, this.container.classList.add("ts-deck"), this.config.deckClass && this.container.classList.add(...this.config.deckClass.split(/\s+/)), this.config.dark && this.container.classList.add("ts-dark"), this.slides = Array.from(this.container.querySelectorAll(".ts-slide")), this.state = new y(this.slides.length), this.fragmentManager = new F();
368
+ const n = this.getSlideFromHash() ?? this.config.startSlide;
369
+ this.state.currentSlide = this.clamp(n), this.updateSlideClasses(), this.navigation = new w(this, this.config), this.config.hash && (this.hashChangeHandler = () => {
370
+ const a = this.getSlideFromHash();
371
+ a !== null && a !== this.state.currentSlide && this.goTo(a);
372
+ }, window.addEventListener("hashchange", this.hashChangeHandler), this.syncHash()), this.config.autoSlide > 0 && this.startAutoSlide(), this.events.emit("deck:ready", { totalSlides: this.slides.length });
373
+ }
374
+ // ─── Public API ────────────────────────────────────────────────
375
+ goTo(t) {
376
+ const e = this.clamp(t);
377
+ if (e === this.state.currentSlide) return;
378
+ const s = this.state.currentSlide, n = e > s ? "forward" : "backward";
379
+ A(
380
+ this.slides[s],
381
+ this.slides[e],
382
+ this.config.transition,
383
+ {
384
+ duration: this.config.transitionSpeed,
385
+ easing: this.config.easing,
386
+ direction: n
387
+ }
388
+ ), this.state.currentSlide = e, this.state.currentFragment = -1, this.updateSlideClasses(), this.syncHash(), this.events.emit("slide:changed", { from: s, to: e });
389
+ }
390
+ next() {
391
+ if (this.state.isPaused) return;
392
+ const t = this.getFragments(this.state.currentSlide);
393
+ if (t.length > 0) {
394
+ const s = this.state.currentFragment + 1;
395
+ if (s < t.length) {
396
+ this.state.currentFragment = s, this.fragmentManager.show(t[s]), this.events.emit("fragment:shown", {
397
+ slide: this.state.currentSlide,
398
+ fragment: s,
399
+ element: t[s]
400
+ });
401
+ return;
402
+ }
403
+ }
404
+ const e = this.state.currentSlide + 1;
405
+ e < this.slides.length ? this.goTo(e) : this.config.loop && this.goTo(0);
406
+ }
407
+ prev() {
408
+ if (this.state.isPaused) return;
409
+ const t = this.getFragments(this.state.currentSlide);
410
+ if (t.length > 0 && this.state.currentFragment >= 0) {
411
+ const s = this.state.currentFragment;
412
+ this.fragmentManager.hide(t[s]), this.state.currentFragment = s - 1, this.events.emit("fragment:hidden", {
413
+ slide: this.state.currentSlide,
414
+ fragment: s,
415
+ element: t[s]
416
+ });
417
+ return;
418
+ }
419
+ const e = this.state.currentSlide - 1;
420
+ if (e >= 0) {
421
+ this.goTo(e);
422
+ const s = this.getFragments(e);
423
+ s.forEach((n) => this.fragmentManager.show(n)), this.state.currentFragment = s.length - 1;
424
+ } else this.config.loop && this.goTo(this.slides.length - 1);
425
+ }
426
+ getState() {
427
+ return this.state.get();
428
+ }
429
+ getConfig() {
430
+ return { ...this.config };
431
+ }
432
+ getContainer() {
433
+ return this.container;
434
+ }
435
+ getSlides() {
436
+ return [...this.slides];
437
+ }
438
+ getFragments(t) {
439
+ const e = this.slides[t];
440
+ return e ? Array.from(e.querySelectorAll(".ts-fragment")) : [];
441
+ }
442
+ on(t, e) {
443
+ this.events.on(t, e);
444
+ }
445
+ off(t, e) {
446
+ this.events.off(t, e);
447
+ }
448
+ use(t) {
449
+ this.plugins.push(t), t.init(this);
450
+ }
451
+ toggleOverview() {
452
+ this.state.isOverview = !this.state.isOverview, this.state.isOverview ? (this.container.classList.add("ts-overview"), this.events.emit("overview:open", {})) : (this.container.classList.remove("ts-overview"), this.events.emit("overview:close", {}));
453
+ }
454
+ destroy() {
455
+ var t;
456
+ this.stopAutoSlide(), (t = this.navigation) == null || t.destroy(), this.navigation = null, this.hashChangeHandler && (window.removeEventListener("hashchange", this.hashChangeHandler), this.hashChangeHandler = null), this.plugins.forEach((e) => e.destroy()), this.plugins = [], this.events.emit("deck:destroyed", {}), this.events.removeAll();
457
+ }
458
+ // ─── Private ───────────────────────────────────────────────────
459
+ updateSlideClasses() {
460
+ const t = this.state.currentSlide;
461
+ this.slides.forEach((s, n) => {
462
+ s.classList.remove("ts-active", "ts-past", "ts-future"), s.setAttribute("aria-hidden", String(n !== t)), n < t ? s.classList.add("ts-past") : n === t ? s.classList.add("ts-active") : s.classList.add("ts-future");
463
+ }), this.getFragments(t).forEach((s) => this.fragmentManager.hide(s)), this.state.currentFragment = -1;
464
+ }
465
+ clamp(t) {
466
+ return Math.max(0, Math.min(t, this.slides.length - 1));
467
+ }
468
+ getSlideFromHash() {
469
+ const t = window.location.hash.match(/^#\/(\d+)$/);
470
+ if (!t) return null;
471
+ const e = parseInt(t[1], 10);
472
+ return isNaN(e) ? null : e;
473
+ }
474
+ syncHash() {
475
+ if (!this.config.hash) return;
476
+ const t = `#/${this.state.currentSlide}`;
477
+ window.location.hash !== t && history.replaceState(null, "", t);
478
+ }
479
+ startAutoSlide() {
480
+ this.autoSlideTimer = setInterval(() => {
481
+ this.state.isPaused || this.next();
482
+ }, this.config.autoSlide);
483
+ }
484
+ stopAutoSlide() {
485
+ this.autoSlideTimer !== null && (clearInterval(this.autoSlideTimer), this.autoSlideTimer = null);
486
+ }
487
+ }
488
+ class x {
489
+ constructor() {
490
+ this.name = "progress", this.bar = null, this.deck = null, this.handler = null;
491
+ }
492
+ init(t) {
493
+ this.deck = t, this.bar = document.createElement("div"), this.bar.className = "ts-progress", t.getContainer().appendChild(this.bar), this.handler = () => this.update(), t.on("slide:changed", this.handler), this.update();
494
+ }
495
+ destroy() {
496
+ var t;
497
+ this.handler && this.deck && this.deck.off("slide:changed", this.handler), (t = this.bar) == null || t.remove(), this.bar = null, this.deck = null, this.handler = null;
498
+ }
499
+ update() {
500
+ if (!this.bar || !this.deck) return;
501
+ const { currentSlide: t, totalSlides: e } = this.deck.getState(), s = e > 1 ? t / (e - 1) * 100 : 100;
502
+ this.bar.style.width = `${s}%`;
503
+ }
504
+ }
505
+ class O {
506
+ constructor() {
507
+ this.name = "slideNumber", this.el = null, this.deck = null, this.handler = null;
508
+ }
509
+ init(t) {
510
+ this.deck = t, this.el = document.createElement("div"), this.el.className = "ts-slide-number", t.getContainer().appendChild(this.el), this.handler = () => this.update(), t.on("slide:changed", this.handler), this.update();
511
+ }
512
+ destroy() {
513
+ var t;
514
+ this.handler && this.deck && this.deck.off("slide:changed", this.handler), (t = this.el) == null || t.remove(), this.el = null, this.deck = null, this.handler = null;
515
+ }
516
+ update() {
517
+ if (!this.el || !this.deck) return;
518
+ const { currentSlide: t, totalSlides: e } = this.deck.getState();
519
+ this.el.textContent = `${t + 1} / ${e}`;
520
+ }
521
+ }
522
+ class M {
523
+ constructor() {
524
+ this.name = "overview", this.deck = null, this.wrapper = null, this.keyHandler = null, this.clickHandler = null;
525
+ }
526
+ init(t) {
527
+ this.deck = t, this.keyHandler = (e) => {
528
+ if (e.key === "o" || e.key === "O") {
529
+ if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return;
530
+ e.preventDefault(), this.toggle();
531
+ }
532
+ }, document.addEventListener("keydown", this.keyHandler), this.clickHandler = (e) => {
533
+ if (!t.getState().isOverview) return;
534
+ const s = e.target.closest(".ts-slide");
535
+ if (!s) return;
536
+ const a = t.getSlides().indexOf(s);
537
+ a !== -1 && (t.goTo(a), t.toggleOverview());
538
+ }, t.getContainer().addEventListener("click", this.clickHandler);
539
+ }
540
+ destroy() {
541
+ this.keyHandler && (document.removeEventListener("keydown", this.keyHandler), this.keyHandler = null), this.clickHandler && this.deck && (this.deck.getContainer().removeEventListener("click", this.clickHandler), this.clickHandler = null), this.unwrapSlides(), this.deck = null;
542
+ }
543
+ toggle() {
544
+ if (!this.deck) return;
545
+ this.deck.getState().isOverview ? this.unwrapSlides() : this.wrapSlides(), this.deck.toggleOverview();
546
+ }
547
+ wrapSlides() {
548
+ if (!this.deck || this.wrapper) return;
549
+ const t = this.deck.getContainer(), e = t.querySelectorAll(":scope > .ts-slide");
550
+ this.wrapper = document.createElement("div"), this.wrapper.className = "ts-slides-container", e.forEach((s) => this.wrapper.appendChild(s)), t.appendChild(this.wrapper);
551
+ }
552
+ unwrapSlides() {
553
+ if (!this.wrapper || !this.deck) return;
554
+ const t = this.deck.getContainer();
555
+ this.wrapper.querySelectorAll(".ts-slide").forEach((s) => t.appendChild(s)), this.wrapper.remove(), this.wrapper = null;
556
+ }
557
+ }
558
+ export {
559
+ M as OverviewPlugin,
560
+ x as ProgressPlugin,
561
+ O as SlideNumberPlugin,
562
+ H as TailSlide,
563
+ H as default
564
+ };
@@ -0,0 +1 @@
1
+ (function(l,h){typeof exports=="object"&&typeof module<"u"?h(exports):typeof define=="function"&&define.amd?define(["exports"],h):(l=typeof globalThis<"u"?globalThis:l||self,h(l.TailSlide={}))})(this,(function(l){"use strict";const h={el:".ts-deck",transition:"slide",transitionSpeed:500,easing:"ease-in-out",keyboard:!0,hash:!0,progress:!0,slideNumber:!0,touch:!0,clickToAdvance:!1,autoSlide:0,loop:!1,startSlide:0,dark:!0,deckClass:""};class y{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){var s;(s=this.listeners.get(t))==null||s.delete(e)}emit(t,e){var s;(s=this.listeners.get(t))==null||s.forEach(n=>n(e))}removeAll(){this.listeners.clear()}}class w{constructor(t){this.state={currentSlide:0,currentFragment:-1,totalSlides:t,isOverview:!1,isPaused:!1}}get(){return{...this.state}}get currentSlide(){return this.state.currentSlide}set currentSlide(t){this.state.currentSlide=t}get currentFragment(){return this.state.currentFragment}set currentFragment(t){this.state.currentFragment=t}get totalSlides(){return this.state.totalSlides}set totalSlides(t){this.state.totalSlides=t}get isOverview(){return this.state.isOverview}set isOverview(t){this.state.isOverview=t}get isPaused(){return this.state.isPaused}set isPaused(t){this.state.isPaused=t}}const S=50;class k{constructor(t,e){this.touchStartX=0,this.touchStartY=0,this.deck=t,this.config=e,this.container=t.getContainer(),this.handleKeyDown=this.onKeyDown.bind(this),this.handleClick=this.onClick.bind(this),this.handleTouchStart=this.onTouchStart.bind(this),this.handleTouchEnd=this.onTouchEnd.bind(this),this.bind()}bind(){this.config.keyboard&&document.addEventListener("keydown",this.handleKeyDown),this.config.clickToAdvance&&this.container.addEventListener("click",this.handleClick),this.config.touch&&(this.container.addEventListener("touchstart",this.handleTouchStart,{passive:!0}),this.container.addEventListener("touchend",this.handleTouchEnd))}onKeyDown(t){if(!(t.metaKey||t.ctrlKey||t.altKey))switch(t.key){case"ArrowRight":case"ArrowDown":case" ":case"n":t.preventDefault(),this.deck.next();break;case"ArrowLeft":case"ArrowUp":case"p":t.preventDefault(),this.deck.prev();break;case"Home":t.preventDefault(),this.deck.goTo(0);break;case"End":t.preventDefault(),this.deck.goTo(this.deck.getSlides().length-1);break;case"Escape":t.preventDefault(),this.deck.toggleOverview();break}}onClick(t){this.deck.next()}onTouchStart(t){const e=t.touches[0];this.touchStartX=e.clientX,this.touchStartY=e.clientY}onTouchEnd(t){const e=t.changedTouches[0],s=e.clientX-this.touchStartX,n=e.clientY-this.touchStartY;Math.abs(s)<S||Math.abs(n)>Math.abs(s)||(t.preventDefault(),s<0?this.deck.next():this.deck.prev())}destroy(){document.removeEventListener("keydown",this.handleKeyDown),this.container.removeEventListener("click",this.handleClick),this.container.removeEventListener("touchstart",this.handleTouchStart),this.container.removeEventListener("touchend",this.handleTouchEnd)}}const E=()=>typeof window<"u"&&window.matchMedia("(prefers-reduced-motion: reduce)").matches;function c(i,t,e){return new Promise(s=>{const n=i.animate(t,e);n.onfinish=()=>s(),n.oncancel=()=>s()})}async function T(i,t){i&&(i.style.opacity="0",i.style.pointerEvents="none",i.classList.remove("ts-active")),t.style.opacity="1",t.style.pointerEvents="auto",t.classList.add("ts-active")}async function L(i,t,e,s){const n=[];t.style.opacity="0",t.style.pointerEvents="auto",t.classList.add("ts-active"),n.push(c(t,[{opacity:0},{opacity:1}],{duration:e,easing:s,fill:"forwards"})),i&&n.push(c(i,[{opacity:1},{opacity:0}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.classList.remove("ts-active")})),await Promise.all(n),t.style.opacity="1"}async function b(i,t,e,s,n){const a=n==="forward"?"100%":"-100%",o=n==="forward"?"-100%":"100%",r=[];t.style.opacity="1",t.style.pointerEvents="auto",t.classList.add("ts-active"),r.push(c(t,[{transform:`translateX(${a})`,opacity:1},{transform:"translateX(0)",opacity:1}],{duration:e,easing:s,fill:"forwards"})),i&&r.push(c(i,[{transform:"translateX(0)",opacity:1},{transform:`translateX(${o})`,opacity:1}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.classList.remove("ts-active")})),await Promise.all(r),t.style.transform=""}async function C(i,t,e,s,n){const a=n==="forward"?"scale(0.8)":"scale(1.2)",o=n==="forward"?"scale(1.2)":"scale(0.8)",r=[];t.style.opacity="0",t.style.pointerEvents="auto",t.classList.add("ts-active"),r.push(c(t,[{transform:a,opacity:0},{transform:"scale(1)",opacity:1}],{duration:e,easing:s,fill:"forwards"})),i&&r.push(c(i,[{transform:"scale(1)",opacity:1},{transform:o,opacity:0}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.classList.remove("ts-active")})),await Promise.all(r),t.style.opacity="1",t.style.transform=""}async function A(i,t,e,s,n){const a=n==="forward"?-180:180,o=n==="forward"?180:-180,r=e/2,d=t.parentElement;d&&(d.style.perspective="1200px"),i&&(await c(i,[{transform:"rotateY(0deg)",opacity:1},{transform:`rotateY(${o}deg)`,opacity:0}],{duration:r,easing:s,fill:"forwards"}),i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.classList.remove("ts-active")),t.style.pointerEvents="auto",t.classList.add("ts-active"),await c(t,[{transform:`rotateY(${a}deg)`,opacity:0},{transform:"rotateY(0deg)",opacity:1}],{duration:r,easing:s,fill:"forwards"}),t.style.opacity="1",t.style.transform=""}async function F(i,t,e,s,n){const a=t.parentElement;a&&(a.style.perspective="1200px");const o=n==="forward"?90:-90,r=n==="forward"?-90:90,d="translateZ(-50vw)",u=[];t.style.pointerEvents="auto",t.classList.add("ts-active"),t.style.transformOrigin=n==="forward"?"left center":"right center",u.push(c(t,[{transform:`${d} rotateY(${o}deg)`,opacity:.6},{transform:"translateZ(0) rotateY(0deg)",opacity:1}],{duration:e,easing:s,fill:"forwards"}).then(()=>{t.style.opacity="1",t.style.transform="",t.style.transformOrigin=""})),i&&(i.style.transformOrigin=n==="forward"?"right center":"left center",u.push(c(i,[{transform:"translateZ(0) rotateY(0deg)",opacity:1},{transform:`${d} rotateY(${r}deg)`,opacity:.6}],{duration:e,easing:s,fill:"forwards"}).then(()=>{i.style.opacity="0",i.style.pointerEvents="none",i.style.transform="",i.style.transformOrigin="",i.classList.remove("ts-active")}))),await Promise.all(u)}async function H(i,t,e,s){const n=E()?"none":e,{duration:a,easing:o,direction:r="forward"}=s;switch(n){case"none":return T(i,t);case"fade":return L(i,t,a,o);case"slide":return b(i,t,a,o,r);case"zoom":return C(i,t,a,o,r);case"flip":return A(i,t,a,o,r);case"cube":return F(i,t,a,o,r)}}const f=300,g="ease-out";function p(i){switch(i){case"fade-in":return{from:{opacity:0},to:{opacity:1}};case"fade-up":return{from:{opacity:0,transform:"translateY(20px)"},to:{opacity:1,transform:"translateY(0)"}};case"fade-down":return{from:{opacity:0,transform:"translateY(-20px)"},to:{opacity:1,transform:"translateY(0)"}};case"fade-left":return{from:{opacity:0,transform:"translateX(20px)"},to:{opacity:1,transform:"translateX(0)"}};case"fade-right":return{from:{opacity:0,transform:"translateX(-20px)"},to:{opacity:1,transform:"translateX(0)"}};case"grow":return{from:{opacity:0,transform:"scale(0.5)"},to:{opacity:1,transform:"scale(1)"}};case"shrink":return{from:{opacity:0,transform:"scale(1.5)"},to:{opacity:1,transform:"scale(1)"}};case"highlight":return{from:{backgroundColor:"transparent"},to:{backgroundColor:"rgba(255, 213, 79, 0.4)"}}}}function m(i){return i.dataset.tsAnimation||"fade-in"}class O{getFragments(t){const e=t.querySelectorAll(".ts-fragment");return Array.from(e).sort((s,n)=>{const a=parseInt(s.dataset.tsIndex||"0",10),o=parseInt(n.dataset.tsIndex||"0",10);return a!==o?a-o:0})}show(t){const e=m(t),{from:s,to:n}=p(e);t.classList.add("ts-fragment-visible"),t.animate([s,n],{duration:f,easing:g,fill:"forwards"})}hide(t){const e=m(t),{from:s,to:n}=p(e);t.classList.remove("ts-fragment-visible"),t.animate([n,s],{duration:f,easing:g,fill:"forwards"})}showAllUpTo(t,e){for(let s=0;s<=e&&s<t.length;s++){const n=t[s];n.classList.contains("ts-fragment-visible")||this.show(n)}}hideAllFrom(t,e){for(let s=e;s<t.length;s++){const n=t[s];n.classList.contains("ts-fragment-visible")&&this.hide(n)}}}class v{constructor(t={}){this.slides=[],this.navigation=null,this.plugins=[],this.autoSlideTimer=null,this.hashChangeHandler=null,this.config={...h,...t},this.events=new y;const e=this.config.el,s=typeof e=="string"?document.querySelector(e):e;if(!s)throw new Error(`TailSlide: container "${e}" not found`);this.container=s,this.container.classList.add("ts-deck"),this.config.deckClass&&this.container.classList.add(...this.config.deckClass.split(/\s+/)),this.config.dark&&this.container.classList.add("ts-dark"),this.slides=Array.from(this.container.querySelectorAll(".ts-slide")),this.state=new w(this.slides.length),this.fragmentManager=new O;const n=this.getSlideFromHash()??this.config.startSlide;this.state.currentSlide=this.clamp(n),this.updateSlideClasses(),this.navigation=new k(this,this.config),this.config.hash&&(this.hashChangeHandler=()=>{const a=this.getSlideFromHash();a!==null&&a!==this.state.currentSlide&&this.goTo(a)},window.addEventListener("hashchange",this.hashChangeHandler),this.syncHash()),this.config.autoSlide>0&&this.startAutoSlide(),this.events.emit("deck:ready",{totalSlides:this.slides.length})}goTo(t){const e=this.clamp(t);if(e===this.state.currentSlide)return;const s=this.state.currentSlide,n=e>s?"forward":"backward";H(this.slides[s],this.slides[e],this.config.transition,{duration:this.config.transitionSpeed,easing:this.config.easing,direction:n}),this.state.currentSlide=e,this.state.currentFragment=-1,this.updateSlideClasses(),this.syncHash(),this.events.emit("slide:changed",{from:s,to:e})}next(){if(this.state.isPaused)return;const t=this.getFragments(this.state.currentSlide);if(t.length>0){const s=this.state.currentFragment+1;if(s<t.length){this.state.currentFragment=s,this.fragmentManager.show(t[s]),this.events.emit("fragment:shown",{slide:this.state.currentSlide,fragment:s,element:t[s]});return}}const e=this.state.currentSlide+1;e<this.slides.length?this.goTo(e):this.config.loop&&this.goTo(0)}prev(){if(this.state.isPaused)return;const t=this.getFragments(this.state.currentSlide);if(t.length>0&&this.state.currentFragment>=0){const s=this.state.currentFragment;this.fragmentManager.hide(t[s]),this.state.currentFragment=s-1,this.events.emit("fragment:hidden",{slide:this.state.currentSlide,fragment:s,element:t[s]});return}const e=this.state.currentSlide-1;if(e>=0){this.goTo(e);const s=this.getFragments(e);s.forEach(n=>this.fragmentManager.show(n)),this.state.currentFragment=s.length-1}else this.config.loop&&this.goTo(this.slides.length-1)}getState(){return this.state.get()}getConfig(){return{...this.config}}getContainer(){return this.container}getSlides(){return[...this.slides]}getFragments(t){const e=this.slides[t];return e?Array.from(e.querySelectorAll(".ts-fragment")):[]}on(t,e){this.events.on(t,e)}off(t,e){this.events.off(t,e)}use(t){this.plugins.push(t),t.init(this)}toggleOverview(){this.state.isOverview=!this.state.isOverview,this.state.isOverview?(this.container.classList.add("ts-overview"),this.events.emit("overview:open",{})):(this.container.classList.remove("ts-overview"),this.events.emit("overview:close",{}))}destroy(){var t;this.stopAutoSlide(),(t=this.navigation)==null||t.destroy(),this.navigation=null,this.hashChangeHandler&&(window.removeEventListener("hashchange",this.hashChangeHandler),this.hashChangeHandler=null),this.plugins.forEach(e=>e.destroy()),this.plugins=[],this.events.emit("deck:destroyed",{}),this.events.removeAll()}updateSlideClasses(){const t=this.state.currentSlide;this.slides.forEach((s,n)=>{s.classList.remove("ts-active","ts-past","ts-future"),s.setAttribute("aria-hidden",String(n!==t)),n<t?s.classList.add("ts-past"):n===t?s.classList.add("ts-active"):s.classList.add("ts-future")}),this.getFragments(t).forEach(s=>this.fragmentManager.hide(s)),this.state.currentFragment=-1}clamp(t){return Math.max(0,Math.min(t,this.slides.length-1))}getSlideFromHash(){const t=window.location.hash.match(/^#\/(\d+)$/);if(!t)return null;const e=parseInt(t[1],10);return isNaN(e)?null:e}syncHash(){if(!this.config.hash)return;const t=`#/${this.state.currentSlide}`;window.location.hash!==t&&history.replaceState(null,"",t)}startAutoSlide(){this.autoSlideTimer=setInterval(()=>{this.state.isPaused||this.next()},this.config.autoSlide)}stopAutoSlide(){this.autoSlideTimer!==null&&(clearInterval(this.autoSlideTimer),this.autoSlideTimer=null)}}class x{constructor(){this.name="progress",this.bar=null,this.deck=null,this.handler=null}init(t){this.deck=t,this.bar=document.createElement("div"),this.bar.className="ts-progress",t.getContainer().appendChild(this.bar),this.handler=()=>this.update(),t.on("slide:changed",this.handler),this.update()}destroy(){var t;this.handler&&this.deck&&this.deck.off("slide:changed",this.handler),(t=this.bar)==null||t.remove(),this.bar=null,this.deck=null,this.handler=null}update(){if(!this.bar||!this.deck)return;const{currentSlide:t,totalSlides:e}=this.deck.getState(),s=e>1?t/(e-1)*100:100;this.bar.style.width=`${s}%`}}class P{constructor(){this.name="slideNumber",this.el=null,this.deck=null,this.handler=null}init(t){this.deck=t,this.el=document.createElement("div"),this.el.className="ts-slide-number",t.getContainer().appendChild(this.el),this.handler=()=>this.update(),t.on("slide:changed",this.handler),this.update()}destroy(){var t;this.handler&&this.deck&&this.deck.off("slide:changed",this.handler),(t=this.el)==null||t.remove(),this.el=null,this.deck=null,this.handler=null}update(){if(!this.el||!this.deck)return;const{currentSlide:t,totalSlides:e}=this.deck.getState();this.el.textContent=`${t+1} / ${e}`}}class M{constructor(){this.name="overview",this.deck=null,this.wrapper=null,this.keyHandler=null,this.clickHandler=null}init(t){this.deck=t,this.keyHandler=e=>{if(e.key==="o"||e.key==="O"){if(e.target instanceof HTMLInputElement||e.target instanceof HTMLTextAreaElement)return;e.preventDefault(),this.toggle()}},document.addEventListener("keydown",this.keyHandler),this.clickHandler=e=>{if(!t.getState().isOverview)return;const s=e.target.closest(".ts-slide");if(!s)return;const a=t.getSlides().indexOf(s);a!==-1&&(t.goTo(a),t.toggleOverview())},t.getContainer().addEventListener("click",this.clickHandler)}destroy(){this.keyHandler&&(document.removeEventListener("keydown",this.keyHandler),this.keyHandler=null),this.clickHandler&&this.deck&&(this.deck.getContainer().removeEventListener("click",this.clickHandler),this.clickHandler=null),this.unwrapSlides(),this.deck=null}toggle(){if(!this.deck)return;this.deck.getState().isOverview?this.unwrapSlides():this.wrapSlides(),this.deck.toggleOverview()}wrapSlides(){if(!this.deck||this.wrapper)return;const t=this.deck.getContainer(),e=t.querySelectorAll(":scope > .ts-slide");this.wrapper=document.createElement("div"),this.wrapper.className="ts-slides-container",e.forEach(s=>this.wrapper.appendChild(s)),t.appendChild(this.wrapper)}unwrapSlides(){if(!this.wrapper||!this.deck)return;const t=this.deck.getContainer();this.wrapper.querySelectorAll(".ts-slide").forEach(s=>t.appendChild(s)),this.wrapper.remove(),this.wrapper=null}}l.OverviewPlugin=M,l.ProgressPlugin=x,l.SlideNumberPlugin=P,l.TailSlide=v,l.default=v,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
@@ -0,0 +1,7 @@
1
+ import { TransitionType } from '../types';
2
+ export interface TransitionOptions {
3
+ duration: number;
4
+ easing: string;
5
+ direction?: 'forward' | 'backward';
6
+ }
7
+ export declare function applyTransition(from: HTMLElement | null, to: HTMLElement, type: TransitionType, options: TransitionOptions): Promise<void>;
@@ -0,0 +1 @@
1
+ *,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media(min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media(min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media(min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media(min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media(min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.ts-deck{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;font-family:ui-sans-serif,system-ui,-apple-system,sans-serif;background-color:#fff;color:#1a1a1a}.ts-deck.ts-dark{background-color:#0a0a0a;color:#f5f5f5}.ts-slide{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;padding:2rem;opacity:0;pointer-events:none;will-change:transform,opacity;z-index:0}.ts-slide.ts-active{opacity:1;pointer-events:auto;z-index:10}.ts-slide.ts-past,.ts-slide.ts-future{opacity:0;pointer-events:none}.ts-slide>.ts-content{width:100%;max-width:64rem;margin:0 auto}.ts-fragment{opacity:0;will-change:transform,opacity}.ts-fragment.ts-fragment-visible{opacity:1}.ts-progress{position:fixed;top:0;left:0;height:.1875rem;background-color:#3b82f6;transition:width .3s ease-out;z-index:50}.ts-dark .ts-progress{background-color:#60a5fa}.ts-slide-number{position:fixed;bottom:1rem;right:1rem;font-size:.875rem;line-height:1.25rem;opacity:.6;z-index:50;font-variant-numeric:tabular-nums}.ts-deck.ts-overview{overflow:auto}.ts-deck.ts-overview .ts-slide{position:relative;opacity:1;pointer-events:auto;cursor:pointer;border:2px solid transparent;border-radius:.5rem;transition:border-color .2s ease,box-shadow .2s ease}.ts-deck.ts-overview .ts-slide:hover{border-color:#3b82f6;box-shadow:0 0 0 2px #3b82f64d}.ts-deck.ts-overview .ts-slide.ts-active{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f666}.ts-overview .ts-slides-container{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:1.5rem;padding:2rem;width:100%;min-height:100vh;align-content:start}.ts-overview .ts-slides-container .ts-slide{aspect-ratio:16 / 9;inset:auto;height:auto;padding:1rem;font-size:.5em}.ts-overview .ts-progress,.ts-overview .ts-slide-number{display:none}.ts-slide h1{font-size:clamp(1.5rem,5vw,3.5rem);font-weight:700;line-height:1.1;margin-bottom:.75em}.ts-slide h2{font-size:clamp(1.25rem,4vw,2.5rem);font-weight:600;line-height:1.2;margin-bottom:.5em}.ts-slide h3{font-size:clamp(1rem,3vw,1.75rem);font-weight:600;line-height:1.3;margin-bottom:.5em}.ts-slide p{font-size:clamp(.875rem,2vw,1.25rem);line-height:1.6;margin-bottom:.75em}.ts-slide ul,.ts-slide ol{font-size:clamp(.875rem,2vw,1.25rem);line-height:1.6;padding-left:1.5em;margin-bottom:.75em}.ts-slide li{margin-bottom:.25em}.ts-slide code{font-size:.9em;padding:.125em .375em;border-radius:.25rem;background-color:#0000000f}.ts-dark .ts-slide code{background-color:#ffffff1a}.ts-slide pre{font-size:clamp(.75rem,1.5vw,1rem);padding:1em;border-radius:.5rem;overflow-x:auto;background-color:#0000000a;margin-bottom:.75em}.ts-dark .ts-slide pre{background-color:#ffffff0f}.ts-slide pre code{padding:0;background:none}.ts-slide img{max-width:100%;height:auto;border-radius:.5rem}@media(min-width:640px){.ts-slide{padding:3rem}}@media(min-width:1024px){.ts-slide{padding:4rem}}.col-span-2{grid-column:span 2 / span 2}.row-span-2{grid-row:span 2 / span 2}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-16{margin-bottom:4rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-2{height:.5rem}.h-3{height:.75rem}.w-10{width:2.5rem}.w-2{width:.5rem}.w-3{width:.75rem}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-xl{max-width:36rem}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-2{gap:.5rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-blue-500\/20{border-color:#3b82f633}.border-gray-600{--tw-border-opacity: 1;border-color:rgb(75 85 99 / var(--tw-border-opacity, 1))}.border-pink-500\/30{border-color:#ec48994d}.border-purple-500\/20{border-color:#a855f733}.border-teal-500\/20{border-color:#14b8a633}.border-violet-500\/30{border-color:#8b5cf64d}.border-white\/\[0\.06\]{border-color:#ffffff0f}.border-white\/\[0\.08\]{border-color:#ffffff14}.bg-\[\#0d1117\]{--tw-bg-opacity: 1;background-color:rgb(13 17 23 / var(--tw-bg-opacity, 1))}.bg-\[\#111\]{--tw-bg-opacity: 1;background-color:rgb(17 17 17 / var(--tw-bg-opacity, 1))}.bg-blue-400{--tw-bg-opacity: 1;background-color:rgb(96 165 250 / var(--tw-bg-opacity, 1))}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-600{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-green-500\/80{background-color:#22c55ecc}.bg-pink-500\/20{background-color:#ec489933}.bg-red-500\/80{background-color:#ef4444cc}.bg-violet-600\/20{background-color:#7c3aed33}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/\[0\.03\]{background-color:#ffffff08}.bg-white\/\[0\.04\]{background-color:#ffffff0a}.bg-white\/\[0\.06\]{background-color:#ffffff0f}.bg-yellow-500\/80{background-color:#eab308cc}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-amber-400{--tw-gradient-from: #fbbf24 var(--tw-gradient-from-position);--tw-gradient-to: rgb(251 191 36 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-blue-400{--tw-gradient-from: #60a5fa var(--tw-gradient-from-position);--tw-gradient-to: rgb(96 165 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-blue-600{--tw-gradient-from: #2563eb var(--tw-gradient-from-position);--tw-gradient-to: rgb(37 99 235 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-blue-900\/40{--tw-gradient-from: rgb(30 58 138 / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(30 58 138 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-cyan-400{--tw-gradient-from: #22d3ee var(--tw-gradient-from-position);--tw-gradient-to: rgb(34 211 238 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-emerald-400{--tw-gradient-from: #34d399 var(--tw-gradient-from-position);--tw-gradient-to: rgb(52 211 153 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-emerald-600{--tw-gradient-from: #059669 var(--tw-gradient-from-position);--tw-gradient-to: rgb(5 150 105 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-pink-400{--tw-gradient-from: #f472b6 var(--tw-gradient-from-position);--tw-gradient-to: rgb(244 114 182 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-600{--tw-gradient-from: #9333ea var(--tw-gradient-from-position);--tw-gradient-to: rgb(147 51 234 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-purple-900\/40{--tw-gradient-from: rgb(88 28 135 / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(88 28 135 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-rose-400{--tw-gradient-from: #fb7185 var(--tw-gradient-from-position);--tw-gradient-to: rgb(251 113 133 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-teal-400{--tw-gradient-from: #2dd4bf var(--tw-gradient-from-position);--tw-gradient-to: rgb(45 212 191 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-teal-900\/40{--tw-gradient-from: rgb(19 78 74 / .4) var(--tw-gradient-from-position);--tw-gradient-to: rgb(19 78 74 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-violet-400{--tw-gradient-from: #a78bfa var(--tw-gradient-from-position);--tw-gradient-to: rgb(167 139 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-300{--tw-gradient-from: #fde047 var(--tw-gradient-from-position);--tw-gradient-to: rgb(253 224 71 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-purple-500{--tw-gradient-to: rgb(168 85 247 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #a855f7 var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-violet-400{--tw-gradient-to: rgb(167 139 250 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), #a78bfa var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-blue-500{--tw-gradient-to: #3b82f6 var(--tw-gradient-to-position)}.to-blue-800{--tw-gradient-to: #1e40af var(--tw-gradient-to-position)}.to-cyan-400{--tw-gradient-to: #22d3ee var(--tw-gradient-to-position)}.to-emerald-500{--tw-gradient-to: #10b981 var(--tw-gradient-to-position)}.to-emerald-900\/40{--tw-gradient-to: rgb(6 78 59 / .4) var(--tw-gradient-to-position)}.to-fuchsia-500{--tw-gradient-to: #d946ef var(--tw-gradient-to-position)}.to-indigo-900\/40{--tw-gradient-to: rgb(49 46 129 / .4) var(--tw-gradient-to-position)}.to-orange-400{--tw-gradient-to: #fb923c var(--tw-gradient-to-position)}.to-orange-500{--tw-gradient-to: #f97316 var(--tw-gradient-to-position)}.to-pink-500{--tw-gradient-to: #ec4899 var(--tw-gradient-to-position)}.to-pink-600{--tw-gradient-to: #db2777 var(--tw-gradient-to-position)}.to-purple-500{--tw-gradient-to: #a855f7 var(--tw-gradient-to-position)}.to-purple-600{--tw-gradient-to: #9333ea var(--tw-gradient-to-position)}.to-red-500{--tw-gradient-to: #ef4444 var(--tw-gradient-to-position)}.to-rose-500{--tw-gradient-to: #f43f5e var(--tw-gradient-to-position)}.to-teal-700{--tw-gradient-to: #0f766e var(--tw-gradient-to-position)}.to-violet-900\/40{--tw-gradient-to: rgb(76 29 149 / .4) var(--tw-gradient-to-position)}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.text-left{text-align:left}.text-center{text-align:center}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-6xl{font-size:3.75rem;line-height:1}.text-7xl{font-size:4.5rem;line-height:1}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.leading-relaxed{line-height:1.625}.tracking-\[0\.3em\]{letter-spacing:.3em}.tracking-wider{letter-spacing:.05em}.text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.text-blue-200{--tw-text-opacity: 1;color:rgb(191 219 254 / var(--tw-text-opacity, 1))}.text-blue-300{--tw-text-opacity: 1;color:rgb(147 197 253 / var(--tw-text-opacity, 1))}.text-blue-300\/60{color:#93c5fd99}.text-blue-400{--tw-text-opacity: 1;color:rgb(96 165 250 / var(--tw-text-opacity, 1))}.text-emerald-200{--tw-text-opacity: 1;color:rgb(167 243 208 / var(--tw-text-opacity, 1))}.text-emerald-400{--tw-text-opacity: 1;color:rgb(52 211 153 / var(--tw-text-opacity, 1))}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-orange-400{--tw-text-opacity: 1;color:rgb(251 146 60 / var(--tw-text-opacity, 1))}.text-pink-200{--tw-text-opacity: 1;color:rgb(251 207 232 / var(--tw-text-opacity, 1))}.text-pink-400{--tw-text-opacity: 1;color:rgb(244 114 182 / var(--tw-text-opacity, 1))}.text-purple-300\/60{color:#d8b4fe99}.text-purple-400{--tw-text-opacity: 1;color:rgb(192 132 252 / var(--tw-text-opacity, 1))}.text-rose-400{--tw-text-opacity: 1;color:rgb(251 113 133 / var(--tw-text-opacity, 1))}.text-teal-300\/60{color:#5eead499}.text-teal-400{--tw-text-opacity: 1;color:rgb(45 212 191 / var(--tw-text-opacity, 1))}.text-violet-300{--tw-text-opacity: 1;color:rgb(196 181 253 / var(--tw-text-opacity, 1))}.text-violet-400\/60{color:#a78bfa99}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-300{--tw-text-opacity: 1;color:rgb(253 224 71 / var(--tw-text-opacity, 1))}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}@media print{.ts-deck{position:static;overflow:visible;background:#fff!important;color:#000!important}.ts-slide{position:relative!important;opacity:1!important;pointer-events:auto!important;page-break-after:always;page-break-inside:avoid;-moz-column-break-after:page;break-after:page;-moz-column-break-inside:avoid;break-inside:avoid;min-height:100vh;padding:2rem;z-index:auto!important}.ts-slide:last-child{page-break-after:auto;-moz-column-break-after:auto;break-after:auto}.ts-fragment{opacity:1!important;transform:none!important}.ts-progress,.ts-slide-number{display:none!important}}.hover\:border-violet-500\/40:hover{border-color:#8b5cf666}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-7xl{font-size:4.5rem;line-height:1}.md\:text-8xl{font-size:6rem;line-height:1}}
@@ -0,0 +1,99 @@
1
+ export type TransitionType = 'none' | 'fade' | 'slide' | 'zoom' | 'flip' | 'cube';
2
+ export type FragmentAnimation = 'fade-in' | 'fade-up' | 'fade-down' | 'fade-left' | 'fade-right' | 'grow' | 'shrink' | 'highlight';
3
+ export type EasingFunction = 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'linear' | string;
4
+ export interface TailSlideConfig {
5
+ /** CSS selector or element for the deck container */
6
+ el?: string | HTMLElement;
7
+ /** Default transition between slides */
8
+ transition?: TransitionType;
9
+ /** Transition duration in ms */
10
+ transitionSpeed?: number;
11
+ /** Easing function for transitions */
12
+ easing?: EasingFunction;
13
+ /** Enable keyboard navigation */
14
+ keyboard?: boolean;
15
+ /** Enable hash-based URL navigation */
16
+ hash?: boolean;
17
+ /** Show progress bar */
18
+ progress?: boolean;
19
+ /** Show slide numbers */
20
+ slideNumber?: boolean;
21
+ /** Enable touch/swipe navigation */
22
+ touch?: boolean;
23
+ /** Enable click to advance */
24
+ clickToAdvance?: boolean;
25
+ /** Auto-slide interval in ms (0 = disabled) */
26
+ autoSlide?: number;
27
+ /** Loop back to first slide after last */
28
+ loop?: boolean;
29
+ /** Start slide index (0-based) */
30
+ startSlide?: number;
31
+ /** Dark mode */
32
+ dark?: boolean;
33
+ /** Custom CSS classes for the deck */
34
+ deckClass?: string;
35
+ }
36
+ export declare const DEFAULT_CONFIG: Required<TailSlideConfig>;
37
+ export interface DeckState {
38
+ currentSlide: number;
39
+ currentFragment: number;
40
+ totalSlides: number;
41
+ isOverview: boolean;
42
+ isPaused: boolean;
43
+ }
44
+ export interface TailSlideEvents {
45
+ 'slide:changed': {
46
+ from: number;
47
+ to: number;
48
+ };
49
+ 'fragment:shown': {
50
+ slide: number;
51
+ fragment: number;
52
+ element: HTMLElement;
53
+ };
54
+ 'fragment:hidden': {
55
+ slide: number;
56
+ fragment: number;
57
+ element: HTMLElement;
58
+ };
59
+ 'deck:ready': {
60
+ totalSlides: number;
61
+ };
62
+ 'deck:destroyed': {};
63
+ 'overview:open': {};
64
+ 'overview:close': {};
65
+ }
66
+ export type EventCallback<T = unknown> = (data: T) => void;
67
+ export interface TailSlidePlugin {
68
+ name: string;
69
+ init(deck: TailSlideAPI): void;
70
+ destroy(): void;
71
+ }
72
+ export interface TailSlideAPI {
73
+ /** Navigate to a specific slide */
74
+ goTo(index: number): void;
75
+ /** Go to next slide/fragment */
76
+ next(): void;
77
+ /** Go to previous slide/fragment */
78
+ prev(): void;
79
+ /** Get current state */
80
+ getState(): DeckState;
81
+ /** Get config */
82
+ getConfig(): Required<TailSlideConfig>;
83
+ /** Get the deck container element */
84
+ getContainer(): HTMLElement;
85
+ /** Get all slide elements */
86
+ getSlides(): HTMLElement[];
87
+ /** Get fragments for a specific slide */
88
+ getFragments(slideIndex: number): HTMLElement[];
89
+ /** Register an event listener */
90
+ on<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
91
+ /** Remove an event listener */
92
+ off<K extends keyof TailSlideEvents>(event: K, callback: EventCallback<TailSlideEvents[K]>): void;
93
+ /** Register a plugin */
94
+ use(plugin: TailSlidePlugin): void;
95
+ /** Toggle overview mode */
96
+ toggleOverview(): void;
97
+ /** Destroy the instance */
98
+ destroy(): void;
99
+ }
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "tw-slide",
3
+ "version": "0.1.0",
4
+ "description": "Modern Tailwind-based presentation library for the web",
5
+ "type": "module",
6
+ "main": "dist/tailslide.umd.js",
7
+ "module": "dist/tailslide.es.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/tailslide.es.js",
13
+ "require": "./dist/tailslide.umd.js"
14
+ },
15
+ "./style.css": "./dist/tail-slide.css"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "dev": "vite serve demo",
22
+ "build": "vite build",
23
+ "build:demo": "vite build --config vite.demo.config.ts",
24
+ "preview": "vite preview",
25
+ "typecheck": "tsc --noEmit"
26
+ },
27
+ "keywords": [
28
+ "presentation",
29
+ "slides",
30
+ "tailwind",
31
+ "html",
32
+ "javascript",
33
+ "typescript"
34
+ ],
35
+ "license": "MIT",
36
+ "devDependencies": {
37
+ "autoprefixer": "^10.4.21",
38
+ "postcss": "^8.5.3",
39
+ "tailwindcss": "^3.4.17",
40
+ "typescript": "^5.7.3",
41
+ "vite": "^6.1.0",
42
+ "vite-plugin-dts": "^4.5.0"
43
+ },
44
+ "repository": {
45
+ "type": "git",
46
+ "url": ""
47
+ }
48
+ }