@orangesk/orange-design-system 2.0.0-beta.18 → 2.0.0-beta.19
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/build/components/Accordion/style.css +1 -1
- package/build/components/Accordion/style.css.map +1 -1
- package/build/components/AnchorNavigation/style.css +1 -1
- package/build/components/AnchorNavigation/style.css.map +1 -1
- package/build/components/Megamenu/style.css +1 -1
- package/build/components/Megamenu/style.css.map +1 -1
- package/build/components/index.js +1 -23
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/index.d.ts +2 -2
- package/build/components/types/src/components/Accordion/Accordion.d.ts +2 -2
- package/build/components/types/src/components/Accordion/Accordion.static.d.ts +1 -0
- package/build/components/types/src/components/Carousel/Carousel.static.d.ts +38 -18
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/megamenu.css +1 -1
- package/build/lib/megamenu.css.map +1 -1
- package/build/lib/megamenu.js +1 -1
- package/build/lib/megamenu.js.map +1 -1
- package/build/lib/scripts.js +1 -9
- package/build/lib/scripts.js.map +1 -1
- package/build/lib/style.css +1 -1
- package/build/lib/style.css.map +1 -1
- package/build/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/components/Accordion/Accordion.static.ts +36 -30
- package/src/components/Accordion/Accordion.tsx +4 -4
- package/src/components/Accordion/AccordionHeader.tsx +0 -10
- package/src/components/Accordion/styles/mixins.scss +0 -6
- package/src/components/Accordion/styles/style.scss +2 -2
- package/src/components/Accordion/tests/Accordion.unit.test.js +12 -26
- package/src/components/AnchorNavigation/AnchorNavigation.static.ts +0 -1
- package/src/components/AnchorNavigation/styles/mixins.scss +4 -0
- package/src/components/Carousel/Carousel.static.ts +177 -91
- package/src/components/Carousel/tests/Carousel.static.test.js +213 -0
- package/src/components/Carousel/tests/Carousel.unit.test.js +58 -0
- package/src/components/Expander/Expander.static.ts +11 -12
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Footer/tests/Footer.conformance.test.js +4 -4
- package/src/components/Footer/tests/Footer.unit.test.js +4 -4
- package/src/components/Megamenu/Megamenu.tsx +71 -55
- package/src/components/Megamenu/MegamenuBlog.tsx +3 -6
- package/src/components/Megamenu/static.ts +0 -9
- package/src/components/Megamenu/styles/mixins.scss +1 -1
- package/src/components/PromoBanner/PromoBanner.tsx +2 -0
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
@use "../../Megamenu/styles/config" as megamenuConfig;
|
|
8
8
|
@use "sass:map" as sass-map;
|
|
9
9
|
|
|
10
|
+
$body-text-small: sass-map.get(typography.$body-text, "small");
|
|
11
|
+
|
|
10
12
|
@mixin anchor-navigation() {
|
|
11
13
|
position: sticky;
|
|
12
14
|
top: 0;
|
|
@@ -35,6 +37,8 @@
|
|
|
35
37
|
text-decoration: none !important;
|
|
36
38
|
display: inline-block;
|
|
37
39
|
cursor: pointer;
|
|
40
|
+
font-size: sass-map.get($body-text-small, "font-size") !important;
|
|
41
|
+
line-height: sass-map.get($body-text-small, "line-height") !important;
|
|
38
42
|
font-weight: 700 !important;
|
|
39
43
|
|
|
40
44
|
&:last-child {
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
CLASS_SLIDE_NEXT,
|
|
28
28
|
CLASS_SLIDE_PREV,
|
|
29
29
|
CLASS_BLEED_RIGHT,
|
|
30
|
+
CLASS_VIEWPORT_WRAPPER,
|
|
30
31
|
} from "./constants";
|
|
31
32
|
|
|
32
33
|
export const defaultConfig: SwiperOptions = {
|
|
@@ -49,6 +50,7 @@ export const defaultConfig: SwiperOptions = {
|
|
|
49
50
|
enabled: true,
|
|
50
51
|
horizontalClass: CLASS_SCROLLBAR_HORIZONTAL,
|
|
51
52
|
dragClass: CLASS_SCROLLBAR_DRAG,
|
|
53
|
+
hide: false,
|
|
52
54
|
},
|
|
53
55
|
slidesPerView: 1.2,
|
|
54
56
|
a11y: {
|
|
@@ -105,7 +107,6 @@ export default class Carousel {
|
|
|
105
107
|
|
|
106
108
|
(this.element as any).ODS_Carousel = this;
|
|
107
109
|
|
|
108
|
-
// Defer initialization to ensure DOM is ready
|
|
109
110
|
requestAnimationFrame(() => {
|
|
110
111
|
this.init();
|
|
111
112
|
});
|
|
@@ -121,30 +122,110 @@ export default class Carousel {
|
|
|
121
122
|
|
|
122
123
|
this.instance = new Swiper(this.viewport, {
|
|
123
124
|
...this.config,
|
|
125
|
+
enabled: false,
|
|
124
126
|
modules: [Navigation, Pagination, Scrollbar, A11y, Keyboard],
|
|
125
127
|
on: {
|
|
126
128
|
slideChange: this.handleSlideChange,
|
|
127
129
|
slideChangeTransitionEnd: () => {
|
|
128
|
-
// Update external controls after transition completes
|
|
129
130
|
this.updateExternalControlsState();
|
|
130
131
|
},
|
|
131
132
|
},
|
|
132
133
|
});
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
this.updateCarouselEnabledState();
|
|
136
|
+
|
|
135
137
|
if (this.element.classList.contains(CLASS_BLEED_RIGHT)) {
|
|
136
138
|
this.adjustConfigForBleedRight();
|
|
139
|
+
this.fixBleedRightScrollbar();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (this.instance && typeof this.instance.on === "function") {
|
|
143
|
+
this.instance.on("resize", () => {
|
|
144
|
+
this.updateCarouselEnabledState();
|
|
145
|
+
});
|
|
137
146
|
}
|
|
138
147
|
|
|
139
|
-
// Initialize external controls
|
|
140
148
|
this.initExternalControls();
|
|
141
149
|
}
|
|
142
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Fix scrollbar drag size and position for bleed-right carousels.
|
|
153
|
+
* Overrides Swiper's default scrollbar calculations to work correctly with bleed-right layouts.
|
|
154
|
+
*/
|
|
155
|
+
fixBleedRightScrollbar() {
|
|
156
|
+
const updateScrollbar = () => {
|
|
157
|
+
const viewportWrapper = this.element.querySelector(
|
|
158
|
+
`.${CLASS_VIEWPORT_WRAPPER}`,
|
|
159
|
+
) as HTMLElement;
|
|
160
|
+
const scrollbar = this.instance?.scrollbar;
|
|
161
|
+
|
|
162
|
+
if (!viewportWrapper || !scrollbar || !scrollbar.dragEl) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const slidesCount = this.instance.slides.length;
|
|
167
|
+
const slidesPerView = Number(this.instance.params.slidesPerView) || 1;
|
|
168
|
+
|
|
169
|
+
// Only show scrollbar when there are more slides than visible at once
|
|
170
|
+
if (slidesCount > slidesPerView) {
|
|
171
|
+
if (scrollbar.el) {
|
|
172
|
+
scrollbar.el.style.display = "";
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const scrollbarWidth = scrollbar.el.offsetWidth;
|
|
176
|
+
|
|
177
|
+
// Calculate drag handle size based on the ratio of visible slides to total slides
|
|
178
|
+
// Example: 3 visible out of 5 total = 60% of scrollbar width
|
|
179
|
+
const visibleRatio = slidesPerView / slidesCount;
|
|
180
|
+
const dragSize = visibleRatio * scrollbarWidth;
|
|
181
|
+
// Ensure minimum 30px for usability
|
|
182
|
+
const finalDragSize = Math.max(dragSize, 30);
|
|
183
|
+
|
|
184
|
+
scrollbar.dragEl.style.width = `${finalDragSize}px`;
|
|
185
|
+
scrollbar.dragEl.style.display = "";
|
|
186
|
+
|
|
187
|
+
// Calculate scrollbar position based on carousel's actual scroll position
|
|
188
|
+
const maxScrollableSlides = slidesCount - slidesPerView;
|
|
189
|
+
const currentTranslate = Math.abs(this.instance.translate || 0);
|
|
190
|
+
const slideSize = this.instance.slidesSizesGrid?.[0] || 0;
|
|
191
|
+
|
|
192
|
+
// Determine how far we've scrolled as a ratio (0 = start, 1 = end)
|
|
193
|
+
const maxTranslateValue = maxScrollableSlides * slideSize;
|
|
194
|
+
const scrollRatio =
|
|
195
|
+
maxTranslateValue > 0
|
|
196
|
+
? Math.min(currentTranslate / maxTranslateValue, 1)
|
|
197
|
+
: 0;
|
|
198
|
+
|
|
199
|
+
// Position scrollbar drag handle proportionally
|
|
200
|
+
const maxDragTranslate = scrollbarWidth - finalDragSize;
|
|
201
|
+
const dragTranslateX = scrollRatio * maxDragTranslate;
|
|
202
|
+
|
|
203
|
+
scrollbar.dragEl.style.transform = `translate3d(${dragTranslateX}px, 0, 0)`;
|
|
204
|
+
} else {
|
|
205
|
+
// Hide scrollbar when all slides are visible (no scrolling needed)
|
|
206
|
+
if (scrollbar.el) {
|
|
207
|
+
scrollbar.el.style.display = "none";
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Initial update (double requestAnimationFrame ensures DOM is fully ready)
|
|
213
|
+
requestAnimationFrame(() => {
|
|
214
|
+
requestAnimationFrame(updateScrollbar);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Keep scrollbar in sync with carousel state changes
|
|
218
|
+
this.instance.on("progress", updateScrollbar);
|
|
219
|
+
this.instance.on("slideChange", updateScrollbar);
|
|
220
|
+
this.instance.on("resize", updateScrollbar);
|
|
221
|
+
this.instance.on("update", updateScrollbar);
|
|
222
|
+
this.instance.on("setTranslate", updateScrollbar);
|
|
223
|
+
}
|
|
224
|
+
|
|
143
225
|
getElements() {
|
|
144
226
|
this.viewport = this.element.querySelector(SELECTOR_VIEWPORT)!;
|
|
145
227
|
this.track = this.viewport.querySelector(SELECTOR_TRACK)!;
|
|
146
228
|
|
|
147
|
-
// Ensure pagination container has proper role
|
|
148
229
|
const paginationEl = this.element.querySelector(
|
|
149
230
|
SELECTOR_DOTS,
|
|
150
231
|
) as HTMLElement | null;
|
|
@@ -186,71 +267,90 @@ export default class Carousel {
|
|
|
186
267
|
};
|
|
187
268
|
}
|
|
188
269
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
270
|
+
/**
|
|
271
|
+
* Enable or disable the carousel based on whether content requires scrolling.
|
|
272
|
+
* Carousel is enabled only when there are more slides than can fit in the current viewport.
|
|
273
|
+
*/
|
|
274
|
+
private updateCarouselEnabledState(): void {
|
|
275
|
+
if (!this.instance || !this.instance.params) return;
|
|
192
276
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// Find the container element
|
|
196
|
-
const container = this.element.closest(".container") as HTMLElement;
|
|
197
|
-
if (!container || !this.instance) return;
|
|
277
|
+
const slidesCount = this.instance.slides.length;
|
|
278
|
+
const slidesPerView = Number(this.instance.params.slidesPerView) || 1;
|
|
198
279
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
280
|
+
if (slidesCount > slidesPerView) {
|
|
281
|
+
this.instance.enable();
|
|
282
|
+
} else {
|
|
283
|
+
this.instance.disable();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
204
286
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Calculate how much the carousel should extend beyond the container (bleed effect).
|
|
289
|
+
* On screens 2560px and wider, the bleed effect is disabled.
|
|
290
|
+
*/
|
|
291
|
+
private calculateBleedAmount(container: HTMLElement): number {
|
|
292
|
+
const containerWidth = container.offsetWidth;
|
|
293
|
+
const halfViewportWidth = window.innerWidth / 2;
|
|
294
|
+
const halfContainerWidth = containerWidth / 2;
|
|
295
|
+
let bleedAmount = halfViewportWidth - halfContainerWidth;
|
|
296
|
+
|
|
297
|
+
if (window.innerWidth >= 2560) {
|
|
298
|
+
bleedAmount = 0;
|
|
299
|
+
}
|
|
209
300
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// Update the Swiper configuration
|
|
213
|
-
// Add offset only on the right side for right bleed effect
|
|
214
|
-
this.instance.params.slidesOffsetAfter = bleedAmount;
|
|
215
|
-
this.instance.update();
|
|
216
|
-
} else {
|
|
217
|
-
// Remove offset if no bleeding should occur
|
|
218
|
-
this.instance.params.slidesOffsetAfter = 0;
|
|
219
|
-
this.instance.update();
|
|
220
|
-
}
|
|
301
|
+
return Math.max(bleedAmount, 0);
|
|
302
|
+
}
|
|
221
303
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Apply the bleed offset to extend the carousel beyond the container edge.
|
|
306
|
+
* Only applies when content exceeds the visible area.
|
|
307
|
+
*/
|
|
308
|
+
private applyBleedOffset(
|
|
309
|
+
viewportWrapper: HTMLElement,
|
|
310
|
+
bleedAmount: number,
|
|
311
|
+
): void {
|
|
312
|
+
const visibleWidth = viewportWrapper.clientWidth;
|
|
313
|
+
const totalWidth = this.track.scrollWidth;
|
|
314
|
+
const contentFitsWithoutScroll = totalWidth <= visibleWidth + 5;
|
|
315
|
+
|
|
316
|
+
if (bleedAmount > 0 && !contentFitsWithoutScroll) {
|
|
317
|
+
this.instance.params.slidesOffsetAfter = bleedAmount;
|
|
318
|
+
} else {
|
|
319
|
+
this.instance.params.slidesOffsetAfter = 0;
|
|
320
|
+
}
|
|
234
321
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
} else {
|
|
238
|
-
this.instance.params.slidesOffsetAfter = 0;
|
|
239
|
-
}
|
|
240
|
-
this.instance.update();
|
|
241
|
-
}
|
|
242
|
-
};
|
|
322
|
+
this.instance.update();
|
|
323
|
+
}
|
|
243
324
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Configure bleed-right carousel to extend beyond the container edge.
|
|
327
|
+
* Calculates the exact offset needed for the carousel to reach the viewport edge
|
|
328
|
+
* while keeping the last slide aligned with the container edge when scrolled to the end.
|
|
329
|
+
*/
|
|
330
|
+
adjustConfigForBleedRight() {
|
|
331
|
+
requestAnimationFrame(() => {
|
|
332
|
+
const container = this.element.closest(".container") as HTMLElement;
|
|
333
|
+
if (!container || !this.instance) return;
|
|
334
|
+
|
|
335
|
+
const viewportWrapper = this.element.querySelector(
|
|
336
|
+
`.${CLASS_VIEWPORT_WRAPPER}`,
|
|
337
|
+
) as HTMLElement;
|
|
338
|
+
if (!viewportWrapper) return;
|
|
339
|
+
|
|
340
|
+
const bleedAmount = this.calculateBleedAmount(container);
|
|
341
|
+
this.applyBleedOffset(viewportWrapper, bleedAmount);
|
|
342
|
+
|
|
343
|
+
// Recalculate bleed on window resize
|
|
344
|
+
this.instance.on("resize", () => {
|
|
345
|
+
const newBleedAmount = this.calculateBleedAmount(container);
|
|
346
|
+
this.applyBleedOffset(viewportWrapper, newBleedAmount);
|
|
347
|
+
});
|
|
247
348
|
});
|
|
248
349
|
}
|
|
249
350
|
|
|
250
351
|
/**
|
|
251
|
-
*
|
|
252
|
-
* Updates
|
|
253
|
-
* Also updates accessibility attributes for pagination buttons and external controls state.
|
|
352
|
+
* Handle carousel slide change events.
|
|
353
|
+
* Updates tooltip positions and accessibility states for the active slide.
|
|
254
354
|
*/
|
|
255
355
|
handleSlideChange() {
|
|
256
356
|
const activeSlide = this.track.querySelector(SELECTOR_ACTIVE);
|
|
@@ -266,13 +366,11 @@ export default class Carousel {
|
|
|
266
366
|
this.hideAllTooltips(nonActiveSlides);
|
|
267
367
|
}
|
|
268
368
|
|
|
269
|
-
// Update external controls state based on current position
|
|
270
369
|
this.updateExternalControlsState();
|
|
271
370
|
}
|
|
272
371
|
|
|
273
372
|
/**
|
|
274
|
-
*
|
|
275
|
-
* @param {HTMLElement} element - The element containing tooltip triggers.
|
|
373
|
+
* Update tooltip positions for elements within a slide.
|
|
276
374
|
*/
|
|
277
375
|
updateTooltipPosition(element: HTMLElement) {
|
|
278
376
|
const tooltipTriggers = element.querySelectorAll(
|
|
@@ -295,8 +393,7 @@ export default class Carousel {
|
|
|
295
393
|
}
|
|
296
394
|
|
|
297
395
|
/**
|
|
298
|
-
*
|
|
299
|
-
* @param {NodeListOf<HTMLElement>} elements - The elements containing tooltip triggers.
|
|
396
|
+
* Hide all tooltips for non-active slides.
|
|
300
397
|
*/
|
|
301
398
|
hideAllTooltips(elements: NodeListOf<Element>) {
|
|
302
399
|
elements.forEach((element) => {
|
|
@@ -322,20 +419,18 @@ export default class Carousel {
|
|
|
322
419
|
}
|
|
323
420
|
|
|
324
421
|
/**
|
|
325
|
-
* Initialize external controls that reference this carousel
|
|
422
|
+
* Initialize external navigation controls that reference this carousel via data attributes.
|
|
423
|
+
* Supports prev/next buttons placed anywhere in the DOM.
|
|
326
424
|
*/
|
|
327
425
|
initExternalControls() {
|
|
328
|
-
// Get carousel ID from data-carousel-id or element id
|
|
329
426
|
const carouselId = this.element.dataset.carouselId || this.element.id;
|
|
330
427
|
|
|
331
428
|
if (!carouselId) {
|
|
332
|
-
return;
|
|
429
|
+
return;
|
|
333
430
|
}
|
|
334
431
|
|
|
335
|
-
// Store carousel ID for later use
|
|
336
432
|
this.carouselId = carouselId;
|
|
337
433
|
|
|
338
|
-
// Find all elements with data-carousel-controls matching this carousel's ID
|
|
339
434
|
const controlElements = document.querySelectorAll(
|
|
340
435
|
`[data-carousel-controls="${carouselId}"]`,
|
|
341
436
|
);
|
|
@@ -343,12 +438,10 @@ export default class Carousel {
|
|
|
343
438
|
controlElements.forEach((control) => {
|
|
344
439
|
const htmlControl = control as HTMLElement;
|
|
345
440
|
|
|
346
|
-
// Skip if already initialized to avoid duplicate event listeners
|
|
347
441
|
if (htmlControl.hasAttribute("data-carousel-initialized")) {
|
|
348
442
|
return;
|
|
349
443
|
}
|
|
350
444
|
|
|
351
|
-
// Remove any existing event listener first (just in case)
|
|
352
445
|
if ((htmlControl as any)._carouselClickHandler) {
|
|
353
446
|
htmlControl.removeEventListener(
|
|
354
447
|
"click",
|
|
@@ -358,7 +451,6 @@ export default class Carousel {
|
|
|
358
451
|
|
|
359
452
|
const action = htmlControl.dataset.carouselAction;
|
|
360
453
|
|
|
361
|
-
// Create bound event handler to avoid multiple listeners
|
|
362
454
|
const clickHandler = (e: Event) => {
|
|
363
455
|
e.preventDefault();
|
|
364
456
|
if (htmlControl.hasAttribute("disabled")) {
|
|
@@ -374,7 +466,6 @@ export default class Carousel {
|
|
|
374
466
|
if (action === "next" || action === "prev") {
|
|
375
467
|
htmlControl.addEventListener("click", clickHandler);
|
|
376
468
|
|
|
377
|
-
// Add ARIA attributes for accessibility
|
|
378
469
|
htmlControl.setAttribute(
|
|
379
470
|
"aria-label",
|
|
380
471
|
action === "next"
|
|
@@ -383,20 +474,18 @@ export default class Carousel {
|
|
|
383
474
|
);
|
|
384
475
|
htmlControl.setAttribute("type", "button");
|
|
385
476
|
|
|
386
|
-
// Store the handler reference for potential cleanup
|
|
387
477
|
(htmlControl as any)._carouselClickHandler = clickHandler;
|
|
388
478
|
}
|
|
389
479
|
|
|
390
|
-
// Mark as initialized to avoid duplicate event listeners
|
|
391
480
|
htmlControl.setAttribute("data-carousel-initialized", "true");
|
|
392
481
|
});
|
|
393
482
|
|
|
394
|
-
// Update initial state of external controls
|
|
395
483
|
this.updateExternalControlsState();
|
|
396
484
|
}
|
|
397
485
|
|
|
398
486
|
/**
|
|
399
|
-
* Update the disabled state of external controls
|
|
487
|
+
* Update the disabled state of external navigation controls.
|
|
488
|
+
* Controls are disabled at the start/end of the carousel based on slide position.
|
|
400
489
|
*/
|
|
401
490
|
updateExternalControlsState() {
|
|
402
491
|
if (!this.carouselId || !this.instance) {
|
|
@@ -404,19 +493,21 @@ export default class Carousel {
|
|
|
404
493
|
}
|
|
405
494
|
|
|
406
495
|
const isAtStart = this.instance.isBeginning;
|
|
407
|
-
const
|
|
496
|
+
const slidesCount = this.instance.slides.length;
|
|
497
|
+
const slidesPerView = this.instance.params.slidesPerView as number;
|
|
498
|
+
const activeIndex = this.instance.activeIndex;
|
|
499
|
+
|
|
500
|
+
// Check if we've reached the end (when there are no more slides to scroll to)
|
|
501
|
+
const isAtEnd = activeIndex + slidesPerView >= slidesCount;
|
|
408
502
|
|
|
409
|
-
// Find all prev controls for this carousel
|
|
410
503
|
const prevControls = document.querySelectorAll(
|
|
411
504
|
`[data-carousel-controls="${this.carouselId}"][data-carousel-action="prev"]`,
|
|
412
505
|
);
|
|
413
506
|
|
|
414
|
-
// Find all next controls for this carousel
|
|
415
507
|
const nextControls = document.querySelectorAll(
|
|
416
508
|
`[data-carousel-controls="${this.carouselId}"][data-carousel-action="next"]`,
|
|
417
509
|
);
|
|
418
510
|
|
|
419
|
-
// Update prev controls
|
|
420
511
|
prevControls.forEach((control) => {
|
|
421
512
|
const htmlControl = control as HTMLElement;
|
|
422
513
|
if (isAtStart) {
|
|
@@ -430,7 +521,6 @@ export default class Carousel {
|
|
|
430
521
|
}
|
|
431
522
|
});
|
|
432
523
|
|
|
433
|
-
// Update next controls
|
|
434
524
|
nextControls.forEach((control) => {
|
|
435
525
|
const htmlControl = control as HTMLElement;
|
|
436
526
|
if (isAtEnd) {
|
|
@@ -446,7 +536,7 @@ export default class Carousel {
|
|
|
446
536
|
}
|
|
447
537
|
|
|
448
538
|
/**
|
|
449
|
-
*
|
|
539
|
+
* Navigate to the next slide.
|
|
450
540
|
*/
|
|
451
541
|
slideNext() {
|
|
452
542
|
if (this.instance) {
|
|
@@ -455,7 +545,7 @@ export default class Carousel {
|
|
|
455
545
|
}
|
|
456
546
|
|
|
457
547
|
/**
|
|
458
|
-
*
|
|
548
|
+
* Navigate to the previous slide.
|
|
459
549
|
*/
|
|
460
550
|
slidePrev() {
|
|
461
551
|
if (this.instance) {
|
|
@@ -464,16 +554,14 @@ export default class Carousel {
|
|
|
464
554
|
}
|
|
465
555
|
|
|
466
556
|
/**
|
|
467
|
-
* Get the current active slide index
|
|
468
|
-
* @returns {number} The current slide index
|
|
557
|
+
* Get the current active slide index.
|
|
469
558
|
*/
|
|
470
559
|
getActiveIndex(): number {
|
|
471
560
|
return this.instance ? this.instance.activeIndex : 0;
|
|
472
561
|
}
|
|
473
562
|
|
|
474
563
|
/**
|
|
475
|
-
*
|
|
476
|
-
* @param {Function} callback - Callback function to execute on slide change
|
|
564
|
+
* Register a callback for slide change events.
|
|
477
565
|
*/
|
|
478
566
|
onSlideChange(callback: (activeIndex: number) => void) {
|
|
479
567
|
if (this.instance) {
|
|
@@ -518,9 +606,7 @@ export default class Carousel {
|
|
|
518
606
|
}
|
|
519
607
|
|
|
520
608
|
/**
|
|
521
|
-
* Find carousel instance by ID or data attribute
|
|
522
|
-
* @param {string} carouselId - The ID or data attribute value of the carousel
|
|
523
|
-
* @returns {Carousel | null} The carousel instance or null
|
|
609
|
+
* Find a carousel instance by its ID or data-carousel-id attribute.
|
|
524
610
|
*/
|
|
525
611
|
static getInstanceById(carouselId: string): Carousel | null {
|
|
526
612
|
const element =
|