@myxo-victor/chexjs 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,217 @@
1
+ /**
2
+ * OrbitJS Engine V3.1.0 - Professional Grade
3
+ * Fixed Visibility & Dynamic Rendering Support
4
+ * Features: Seamless Loop, Touch, Hover-Pause, Auto-Dots, Chex-Ready.
5
+ * @author Myxo victor
6
+ * Single Image slider (Allows us to display slide through bunch of images 1 by 1)
7
+ */
8
+
9
+ const orbit = {
10
+ _sliders: [],
11
+
12
+ /**
13
+ * Initialize the sliding logic
14
+ * @param {Object} config - { IDs: ['id1', 'id2'], interval: 4000, dots: true }
15
+ */
16
+ slides: function(config) {
17
+ // 1. Initial Check & Delay for Dynamic Content (Chex support)
18
+ const init = () => {
19
+ const ids = config.IDs || [];
20
+ const elements = ids.map(id => document.getElementById(id)).filter(el => el !== null);
21
+
22
+ // If elements aren't in the DOM yet, retry in 100ms
23
+ if (elements.length === 0) {
24
+ setTimeout(init, 100);
25
+ return;
26
+ }
27
+
28
+ this._build(config, elements);
29
+ };
30
+
31
+ init();
32
+ },
33
+
34
+ _build: function(config, elements) {
35
+ const interval = config.interval || 4000;
36
+ const showDots = config.dots !== false;
37
+ const pauseOnHover = config.pauseOnHover !== false;
38
+ const wrapper = elements[0].parentElement;
39
+ const originalCount = elements.length;
40
+
41
+ // Prevent nested/duplicate initialization (can blank out content)
42
+ if (wrapper && wrapper.classList && wrapper.classList.contains('orbit-track')) {
43
+ return;
44
+ }
45
+ if (wrapper && wrapper.querySelector && wrapper.querySelector('.orbit-track')) {
46
+ return;
47
+ }
48
+
49
+ // 2. Setup Wrapper Layout
50
+ // If height is 0, images will be invisible. We force a min-height.
51
+ if (wrapper.offsetHeight === 0) {
52
+ wrapper.style.minHeight = "300px";
53
+ }
54
+ wrapper.style.position = 'relative';
55
+ wrapper.style.overflow = 'hidden';
56
+ wrapper.style.display = 'block';
57
+ wrapper.style.touchAction = 'pan-y';
58
+
59
+ // 3. Create Seamless Track
60
+ const track = document.createElement('div');
61
+ track.className = 'orbit-track';
62
+ track.style.cssText = `
63
+ display: flex;
64
+ width: 100%;
65
+ height: 100%;
66
+ z-index: 5;
67
+ transition: transform 0.8s cubic-bezier(0.645, 0.045, 0.355, 1);
68
+ will-change: transform;
69
+ `;
70
+
71
+ // 4. Handle Clones for Seamless Loop
72
+ const firstClone = elements[0].cloneNode(true);
73
+ const lastClone = elements[elements.length - 1].cloneNode(true);
74
+ firstClone.id += '-clone';
75
+ lastClone.id += '-clone';
76
+
77
+ const trackElements = [lastClone, ...elements, firstClone];
78
+
79
+ trackElements.forEach(el => {
80
+ el.style.flex = '0 0 100%';
81
+ el.style.width = '100%';
82
+ el.style.height = '100%';
83
+ el.style.objectFit = 'cover';
84
+ el.style.display = 'block'; // Force visibility
85
+ el.style.visibility = 'visible';
86
+ el.style.opacity = '1';
87
+ track.appendChild(el);
88
+ });
89
+
90
+ // 5. Replace contents and start
91
+ wrapper.innerHTML = '';
92
+ wrapper.appendChild(track);
93
+
94
+ // Force a browser reflow to ensure the -100% takes effect immediately
95
+ track.offsetHeight;
96
+ let currentIndex = 1;
97
+ track.style.transform = `translateX(-100%)`;
98
+
99
+ const state = {
100
+ wrapper, track, originalCount, currentIndex, interval,
101
+ timer: null, started: false, isTransitioning: false, dots: []
102
+ };
103
+
104
+ if (showDots) this._createDots(wrapper, state);
105
+ if (pauseOnHover) {
106
+ wrapper.addEventListener('mouseenter', () => this._pause(state));
107
+ wrapper.addEventListener('mouseleave', () => this._start(state));
108
+ }
109
+
110
+ this._addTouchListeners(wrapper, state);
111
+ track.addEventListener('transitionend', () => this._handleTransitionEnd(state));
112
+
113
+ this._sliders.push(state);
114
+ this._observe(wrapper, state);
115
+ },
116
+
117
+ _createDots: function(wrapper, state) {
118
+ const dotsContainer = document.createElement('div');
119
+ dotsContainer.style.cssText = 'position:absolute;bottom:20px;left:50%;transform:translateX(-50%);display:flex;gap:10px;z-index:20;';
120
+
121
+ for (let i = 0; i < state.originalCount; i++) {
122
+ const dot = document.createElement('div');
123
+ dot.style.cssText = 'width:10px;height:10px;border-radius:50%;background:rgba(255,255,255,0.5);cursor:pointer;transition:0.3s;';
124
+ if (i === 0) dot.style.background = '#fff';
125
+ dot.onclick = (e) => { e.stopPropagation(); this._goTo(state, i + 1); };
126
+ dotsContainer.appendChild(dot);
127
+ state.dots.push(dot);
128
+ }
129
+ wrapper.appendChild(dotsContainer);
130
+ },
131
+
132
+ _updateDots: function(state) {
133
+ if (state.dots.length === 0) return;
134
+ let activeDot = state.currentIndex - 1;
135
+ if (activeDot >= state.originalCount) activeDot = 0;
136
+ if (activeDot < 0) activeDot = state.originalCount - 1;
137
+
138
+ state.dots.forEach((dot, i) => {
139
+ dot.style.background = i === activeDot ? '#fff' : 'rgba(255,255,255,0.5)';
140
+ dot.style.transform = i === activeDot ? 'scale(1.2)' : 'scale(1)';
141
+ });
142
+ },
143
+
144
+ _addTouchListeners: function(wrapper, state) {
145
+ let startX = 0;
146
+ wrapper.addEventListener('touchstart', (e) => {
147
+ startX = e.touches[0].clientX;
148
+ this._pause(state);
149
+ }, {passive: true});
150
+
151
+ wrapper.addEventListener('touchend', (e) => {
152
+ let endX = e.changedTouches[0].clientX;
153
+ let diff = startX - endX;
154
+ if (Math.abs(diff) > 50) {
155
+ diff > 0 ? this._next(state) : this._prev(state);
156
+ }
157
+ this._start(state);
158
+ }, {passive: true});
159
+ },
160
+
161
+ _handleTransitionEnd: function(state) {
162
+ state.isTransitioning = false;
163
+ if (state.currentIndex === 0) {
164
+ state.track.style.transition = 'none';
165
+ state.currentIndex = state.originalCount;
166
+ state.track.style.transform = `translateX(-${state.currentIndex * 100}%)`;
167
+ } else if (state.currentIndex === state.originalCount + 1) {
168
+ state.track.style.transition = 'none';
169
+ state.currentIndex = 1;
170
+ state.track.style.transform = `translateX(-100%)`;
171
+ }
172
+ this._updateDots(state);
173
+ },
174
+
175
+ _goTo: function(state, index) {
176
+ if (state.isTransitioning) return;
177
+ state.isTransitioning = true;
178
+ state.currentIndex = index;
179
+ state.track.style.transition = 'transform 0.8s cubic-bezier(0.645, 0.045, 0.355, 1)';
180
+ state.track.style.transform = `translateX(-${index * 100}%)`;
181
+ this._updateDots(state);
182
+ },
183
+
184
+ _next: function(state) { this._goTo(state, state.currentIndex + 1); },
185
+ _prev: function(state) { this._goTo(state, state.currentIndex - 1); },
186
+
187
+ _observe: function(target, state) {
188
+ const observer = new IntersectionObserver((entries) => {
189
+ entries.forEach(entry => {
190
+ if (entry.isIntersecting && !state.started) {
191
+ this._start(state);
192
+ state.started = true;
193
+ }
194
+ });
195
+ }, { threshold: 0.1 });
196
+ observer.observe(target);
197
+ },
198
+
199
+ _start: function(state) {
200
+ if (state.timer) clearInterval(state.timer);
201
+ state.timer = setInterval(() => this._next(state), state.interval);
202
+ },
203
+
204
+ _pause: function(state) { clearInterval(state.timer); }
205
+ };
206
+
207
+
208
+ /**************************
209
+ How to use this library
210
+ **************************
211
+ */
212
+
213
+ /* orbit.slides({
214
+ IDs: ['ic','ic','ic'],
215
+ interval: 5000,
216
+ dots: true
217
+ })*/
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Racket.js - Generic HTML Element Infinite Slider Engine
3
+ * Supports standard arrays, handles auto-hiding of source nodes,
4
+ * clones entire rich DOM structures, and adapts dynamically
5
+ * to mobile viewports (1 slide) and desktop viewports (3 slides).
6
+ * Use for image slider or carousel
7
+ */
8
+ class Racket {
9
+ constructor() {
10
+ this.rawInputList = []; // Holds raw ID/selector inputs
11
+ this.slides = []; // Stores resolved, hidden source nodes
12
+ this.intervalDuration = 2000; // Carousel speed
13
+ this.currentPage = 0; // Slide page index
14
+ this.container = null; // Slider mounting viewport
15
+ this.timer = null; // Animation rotation timer
16
+ this.isPlaying = false; // Playback state
17
+ this.track = null; // Inner moving rail
18
+ this.changeCallback = null; // Realtime callback updates
19
+ this.isTransitioning = false; // Transition guard locks
20
+ this.isHovered = false; // Cursor tracking
21
+ this.isHoverPaused = false; // Hover suspension state
22
+ this.lastItemsPerPage = this.getItemsPerPage(); // Cache to check breakpoint changes
23
+ this.resizeBound = false; // Guard duplicate resize listeners
24
+ }
25
+
26
+ /**
27
+ * Helper to detect active items per page based on viewport size.
28
+ * Mobile (< 768px) shows 1 slide at a time. Desktop (>= 768px) shows 3.
29
+ * @returns {number}
30
+ */
31
+ getItemsPerPage() {
32
+ if (typeof window !== 'undefined' && window.innerWidth < 768) {
33
+ return 1;
34
+ }
35
+ return 3;
36
+ }
37
+
38
+ /**
39
+ * Mounts the Racket slider onto a targeted DOM element wrapper.
40
+ * @param {string|HTMLElement} selector
41
+ */
42
+ mount(selector) {
43
+ this.container = typeof selector === 'string'
44
+ ? document.querySelector(selector)
45
+ : selector;
46
+
47
+ if (!this.container) {
48
+ console.warn(`Racket.js: Mounting container "${selector}" not found yet. Retrying on render.`);
49
+ } else {
50
+ this.setupHoverEvents();
51
+ this.setupResizeEvent();
52
+ }
53
+ return this;
54
+ }
55
+
56
+ /**
57
+ * Listens for mouse hover patterns to suspend playback.
58
+ */
59
+ setupHoverEvents() {
60
+ if (!this.container) return;
61
+
62
+ // Use a flag to avoid adding duplicate event listeners
63
+ if (this.container.dataset.racketHoverBound) return;
64
+ this.container.dataset.racketHoverBound = "true";
65
+
66
+ this.container.addEventListener('mouseenter', () => {
67
+ this.isHovered = true;
68
+ if (this.isPlaying && !this.isHoverPaused) {
69
+ this.isHoverPaused = true;
70
+ if (this.timer) {
71
+ clearInterval(this.timer);
72
+ this.timer = null;
73
+ }
74
+ this.updatePosition();
75
+ if (window.logToSandboxConsole) {
76
+ window.logToSandboxConsole('Carousel auto-rotation paused on hover 🧊', 'info');
77
+ }
78
+ }
79
+ });
80
+
81
+ this.container.addEventListener('mouseleave', () => {
82
+ this.isHovered = false;
83
+ if (this.isPlaying && this.isHoverPaused) {
84
+ this.isHoverPaused = false;
85
+ this.startTimer();
86
+ this.updatePosition();
87
+ if (window.logToSandboxConsole) {
88
+ window.logToSandboxConsole('Carousel auto-rotation resumed 🚀', 'info');
89
+ }
90
+ }
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Attaches window resize listeners to trigger smooth layout adaptions.
96
+ */
97
+ setupResizeEvent() {
98
+ if (this.resizeBound || typeof window === 'undefined') return;
99
+ this.resizeBound = true;
100
+
101
+ let resizeTimeout;
102
+ window.addEventListener('resize', () => {
103
+ clearTimeout(resizeTimeout);
104
+ resizeTimeout = setTimeout(() => {
105
+ const currentBreakpointVal = this.getItemsPerPage();
106
+ if (currentBreakpointVal !== this.lastItemsPerPage) {
107
+ this.lastItemsPerPage = currentBreakpointVal;
108
+ this.currentPage = 0; // Reset to start index to avoid layout miscalculation
109
+ this.render();
110
+ if (window.logToSandboxConsole) {
111
+ window.logToSandboxConsole(`Responsive Layout update: Displaying ${currentBreakpointVal} item(s) per frame 📱💻`, 'info');
112
+ }
113
+ }
114
+ }, 150);
115
+ });
116
+ }
117
+
118
+ /**
119
+ * Accepts array list representing raw image IDs or direct URLs.
120
+ * @param {Array} imgArray
121
+ */
122
+ images(imgArray) {
123
+ this.rawInputList = Array.isArray(imgArray) ? imgArray : [imgArray];
124
+ this.render();
125
+ return this;
126
+ }
127
+
128
+ /**
129
+ * Adjusts the transition frequency duration limit.
130
+ * @param {number} ms
131
+ */
132
+ duration(ms) {
133
+ this.intervalDuration = Number(ms) || 2000;
134
+ if (this.isPlaying && !this.isHoverPaused) {
135
+ this.play();
136
+ } else {
137
+ this.updatePosition();
138
+ }
139
+ return this;
140
+ }
141
+
142
+ /**
143
+ * Resolves elements from IDs, clones them, hides the static versions,
144
+ * and compiles the infinite scrolling layout.
145
+ */
146
+ render() {
147
+ this.slides = [];
148
+ this.rawInputList.forEach(item => {
149
+ if (typeof item === 'string') {
150
+ const trimmed = item.trim();
151
+ const element = document.getElementById(trimmed) || document.querySelector(trimmed);
152
+ if (element) {
153
+ // Hide the static element from the page layout so they don't appear stacked!
154
+ element.style.display = 'none';
155
+ this.slides.push({ type: 'dom', node: element });
156
+ } else {
157
+ // Fallback to simple URL string
158
+ this.slides.push({ type: 'url', url: item });
159
+ }
160
+ } else {
161
+ this.slides.push({ type: 'url', url: String(item) });
162
+ }
163
+ });
164
+
165
+ if (this.slides.length === 0) return;
166
+
167
+ if (!this.container) {
168
+ const firstDom = this.slides.find(s => s.type === 'dom');
169
+ if (firstDom && firstDom.node.parentElement) {
170
+ this.container = firstDom.node.parentElement;
171
+ this.setupHoverEvents();
172
+ this.setupResizeEvent();
173
+ }
174
+ }
175
+
176
+ if (!this.container) return;
177
+
178
+ // Setup container dimensions & structural viewport wrapper
179
+ this.container.style.position = 'relative';
180
+ this.container.style.overflow = 'hidden';
181
+
182
+ let viewport = this.container.querySelector('.racket-viewport-wrapper');
183
+ if (!viewport) {
184
+ viewport = document.createElement('div');
185
+ viewport.className = 'racket-viewport-wrapper';
186
+ viewport.style.overflow = 'hidden';
187
+ viewport.style.width = '100%';
188
+ this.container.appendChild(viewport);
189
+ } else {
190
+ viewport.innerHTML = ''; // Clean old slider rails
191
+ }
192
+
193
+ const track = document.createElement('div');
194
+ track.className = 'racket-track';
195
+ track.style.display = 'flex';
196
+ track.style.transition = 'transform 0.6s cubic-bezier(0.16, 1, 0.3, 1)';
197
+ track.style.width = '100%';
198
+ viewport.appendChild(track);
199
+
200
+ // Dynamic items per view page depending on responsiveness parameters
201
+ const itemsPerPage = this.getItemsPerPage();
202
+ const originalCount = this.slides.length;
203
+ const paddedSlides = [...this.slides];
204
+
205
+ // Align padding sizes dynamically to avoid division remainders
206
+ while (paddedSlides.length % itemsPerPage !== 0) {
207
+ paddedSlides.push(this.slides[paddedSlides.length % originalCount]);
208
+ }
209
+ const totalPages = paddedSlides.length / itemsPerPage;
210
+
211
+ // Build responsive dynamic circular buffers (cloned items for infinite scrolling loop)
212
+ const lastPageItems = paddedSlides.slice((totalPages - 1) * itemsPerPage);
213
+ const firstPageItems = paddedSlides.slice(0, itemsPerPage);
214
+ const trackItems = [...lastPageItems, ...paddedSlides, ...firstPageItems];
215
+
216
+ trackItems.forEach((slide) => {
217
+ const itemWrapper = document.createElement('div');
218
+ itemWrapper.style.flex = `0 0 calc(100% / ${itemsPerPage})`;
219
+ itemWrapper.style.maxWidth = `calc(100% / ${itemsPerPage})`;
220
+ itemWrapper.style.boxSizing = 'border-box';
221
+ itemWrapper.style.padding = '8px'; // Uniform gap spacing
222
+
223
+ if (slide.type === 'dom') {
224
+ // Clone the entire rich card element (maintaining styles, names, text, and images)
225
+ const clone = slide.node.cloneNode(true);
226
+ clone.style.display = ''; // Clear display: none
227
+ clone.style.width = '100%';
228
+ clone.removeAttribute('id'); // Avoid element ID duplication
229
+ itemWrapper.appendChild(clone);
230
+ } else {
231
+ // Render simple fallback image block
232
+ const imgWrapper = document.createElement('div');
233
+ imgWrapper.style.position = 'relative';
234
+ imgWrapper.style.width = '100%';
235
+ imgWrapper.style.overflow = 'hidden';
236
+ imgWrapper.style.borderRadius = '12px';
237
+ imgWrapper.style.aspectRatio = '4/3';
238
+ imgWrapper.style.backgroundColor = '#111827';
239
+
240
+ const img = document.createElement('img');
241
+ img.src = slide.url;
242
+ img.style.width = '100%';
243
+ img.style.height = '100%';
244
+ img.style.objectFit = 'cover';
245
+ imgWrapper.appendChild(img);
246
+ itemWrapper.appendChild(imgWrapper);
247
+ }
248
+
249
+ track.appendChild(itemWrapper);
250
+ });
251
+
252
+ this.track = track;
253
+
254
+ this.track.addEventListener('transitionend', () => {
255
+ this.isTransitioning = false;
256
+ if (this.currentPage >= totalPages) {
257
+ this.track.style.transition = 'none';
258
+ this.currentPage = 0;
259
+ this.updatePosition();
260
+ this.track.offsetHeight; // Force layout flow reflow
261
+ this.track.style.transition = 'transform 0.6s cubic-bezier(0.16, 1, 0.3, 1)';
262
+ }
263
+ if (this.currentPage <= -1) {
264
+ this.track.style.transition = 'none';
265
+ this.currentPage = totalPages - 1;
266
+ this.updatePosition();
267
+ this.track.offsetHeight; // Force layout flow reflow
268
+ this.track.style.transition = 'transform 0.6s cubic-bezier(0.16, 1, 0.3, 1)';
269
+ }
270
+ });
271
+
272
+ this.updatePosition();
273
+ }
274
+
275
+ /**
276
+ * Transforms slider tracks smoothly relative to target index.
277
+ */
278
+ updatePosition() {
279
+ if (!this.track || this.slides.length === 0) return;
280
+ const itemsPerPage = this.getItemsPerPage();
281
+ const originalCount = this.slides.length;
282
+ const totalPages = Math.ceil(originalCount / itemsPerPage);
283
+
284
+ const visualPageIndex = this.currentPage + 1;
285
+ this.track.style.transform = `translateX(-${visualPageIndex * 100}%)`;
286
+
287
+ if (this.changeCallback) {
288
+ let normalizedPage = this.currentPage;
289
+ if (normalizedPage >= totalPages) normalizedPage = 0;
290
+ if (normalizedPage < 0) normalizedPage = totalPages - 1;
291
+
292
+ this.changeCallback({
293
+ currentIndex: normalizedPage * itemsPerPage,
294
+ pageIndex: normalizedPage,
295
+ totalPages: totalPages,
296
+ interval: this.intervalDuration,
297
+ isPlaying: this.isPlaying,
298
+ isHoverPaused: this.isHoverPaused,
299
+ itemsPerPage: itemsPerPage
300
+ });
301
+ }
302
+ }
303
+
304
+ next() {
305
+ if (this.isTransitioning) return this;
306
+ this.isTransitioning = true;
307
+ this.currentPage++;
308
+ this.updatePosition();
309
+ return this;
310
+ }
311
+
312
+ prev() {
313
+ if (this.isTransitioning) return this;
314
+ this.isTransitioning = true;
315
+ this.currentPage--;
316
+ this.updatePosition();
317
+ return this;
318
+ }
319
+
320
+ startTimer() {
321
+ if (this.timer) clearInterval(this.timer);
322
+ this.timer = setInterval(() => {
323
+ this.next();
324
+ }, this.intervalDuration);
325
+ }
326
+
327
+ play() {
328
+ this.isPlaying = true;
329
+ if (this.isHovered) {
330
+ this.isHoverPaused = true;
331
+ if (this.timer) {
332
+ clearInterval(this.timer);
333
+ this.timer = null;
334
+ }
335
+ } else {
336
+ this.isHoverPaused = false;
337
+ this.startTimer();
338
+ }
339
+ this.updatePosition();
340
+ return this;
341
+ }
342
+
343
+ stop() {
344
+ this.isPlaying = false;
345
+ this.isHoverPaused = false;
346
+ if (this.timer) {
347
+ clearInterval(this.timer);
348
+ this.timer = null;
349
+ }
350
+ this.updatePosition();
351
+ return this;
352
+ }
353
+
354
+ onUpdate(fn) {
355
+ this.changeCallback = fn;
356
+ return this;
357
+ }
358
+ }
359
+
360
+ if (typeof window !== 'undefined') {
361
+ window.Racket = Racket;
362
+ window.racket = new Racket();
363
+ }
364
+
365
+
366
+ /**************************
367
+ How to use this library
368
+ **************************
369
+ */
370
+ /*
371
+ racket.images(['img1', 'img2', 'img3'])//list of image IDs
372
+ racket.duration([2000])//Duration
373
+ racket.play()//Start carousel
374
+ */
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Rinx Text Slider V1.0
3
+ * Specifically designed for sliding text blocks inside overlays
4
+ * without breaking parent container layouts.
5
+ * This library allows us to make a container holding some texts to slide one by one
6
+ */
7
+
8
+ const rinx = {
9
+ _instances: [],
10
+
11
+ slides: function(config) {
12
+ const ids = config.IDs || [];
13
+ const interval = config.interval || 3000;
14
+ const effect = config.effect || 'fade'; // 'fade' or 'slide'
15
+
16
+ const elements = ids.map(id => document.getElementById(id)).filter(el => el !== null);
17
+ if (elements.length === 0) return;
18
+
19
+ // Setup Initial State
20
+ elements.forEach((el, index) => {
21
+ el.style.transition = 'all 0.8s ease-in-out';
22
+ if (index === 0) {
23
+ el.style.opacity = '1';
24
+ el.style.display = 'block';
25
+ el.style.transform = 'translateX(0)';
26
+ } else {
27
+ el.style.opacity = '0';
28
+ el.style.display = 'none';
29
+ el.style.transform = 'translateX(20px)';
30
+ }
31
+ });
32
+
33
+ let currentIndex = 0;
34
+
35
+ const state = {
36
+ elements: elements,
37
+ interval: interval,
38
+ timer: null,
39
+ next: () => {
40
+ const current = elements[currentIndex];
41
+ currentIndex = (currentIndex + 1) % elements.length;
42
+ const nextEl = elements[currentIndex];
43
+
44
+ // Hide Current
45
+ current.style.opacity = '0';
46
+ current.style.transform = 'translateX(-20px)';
47
+
48
+ setTimeout(() => {
49
+ current.style.display = 'none';
50
+
51
+ // Show Next
52
+ nextEl.style.display = 'block';
53
+ // Small timeout to trigger CSS transition after display:block
54
+ setTimeout(() => {
55
+ nextEl.style.opacity = '1';
56
+ nextEl.style.transform = 'translateX(0)';
57
+ }, 50);
58
+ }, 400); // Wait for fade out
59
+ }
60
+ };
61
+
62
+ state.timer = setInterval(state.next, interval);
63
+ this._instances.push(state);
64
+ return state;
65
+ },
66
+
67
+ destroyAll: function() {
68
+ if (!this._instances || this._instances.length === 0) return;
69
+ this._instances.forEach((instance) => {
70
+ if (instance && instance.timer) clearInterval(instance.timer);
71
+ if (instance) instance.timer = null;
72
+ });
73
+ this._instances = [];
74
+ }
75
+ };
76
+
77
+
78
+ /**************************
79
+ How to use this library
80
+ ***************************
81
+ */
82
+ /*
83
+ rinx.slides({
84
+ IDs: ['scroll1', 'scroll2', 'scroll3'],
85
+ interval: 5000,
86
+ effect:'slide'
87
+ });
88
+ */