@asante-org/atlascopco-vt-litesitegenerator 3.6.18 → 3.6.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/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, useEffect, useId, useCallback, useMemo, forwardRef, useImperativeHandle } from 'react';
1
+ import React, { useState, useRef, useMemo, useEffect, useId, useCallback, forwardRef, useImperativeHandle } from 'react';
2
2
 
3
3
  function _extends() {
4
4
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
@@ -140,6 +140,37 @@ var LsgBanner = function (_a) {
140
140
  })))));
141
141
  };
142
142
 
143
+ /******************************************************************************
144
+ Copyright (c) Microsoft Corporation.
145
+
146
+ Permission to use, copy, modify, and/or distribute this software for any
147
+ purpose with or without fee is hereby granted.
148
+
149
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
150
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
151
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
152
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
153
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
154
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
155
+ PERFORMANCE OF THIS SOFTWARE.
156
+ ***************************************************************************** */
157
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
158
+
159
+ var __assign = function () {
160
+ __assign = Object.assign || function __assign(t) {
161
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
162
+ s = arguments[i];
163
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
164
+ }
165
+ return t;
166
+ };
167
+ return __assign.apply(this, arguments);
168
+ };
169
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
170
+ var e = new Error(message);
171
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
172
+ };
173
+
143
174
  function isSafeUrl$1(url) {
144
175
  if (!url) return false;
145
176
  var lower = url.toLowerCase().trim();
@@ -2105,8 +2136,240 @@ function EmblaCarousel(root, userOptions, userPlugins) {
2105
2136
  }
2106
2137
  EmblaCarousel.globalOptions = undefined;
2107
2138
 
2139
+ function clampNumber(number, min, max) {
2140
+ return Math.min(Math.max(number, min), max);
2141
+ }
2142
+ function isNumber(value) {
2143
+ return typeof value === 'number' && !isNaN(value);
2144
+ }
2145
+ function Fade(userOptions = {}) {
2146
+ const fullOpacity = 1;
2147
+ const noOpacity = 0;
2148
+ const fadeFriction = 0.68;
2149
+ let emblaApi;
2150
+ let opacities = [];
2151
+ let fadeToNextDistance;
2152
+ let distanceFromPointerDown = 0;
2153
+ let fadeVelocity = 0;
2154
+ let progress = 0;
2155
+ let shouldFadePair = false;
2156
+ let defaultSettledBehaviour;
2157
+ let defaultProgressBehaviour;
2158
+ function init(emblaApiInstance) {
2159
+ emblaApi = emblaApiInstance;
2160
+ const selectedSnap = emblaApi.selectedScrollSnap();
2161
+ const {
2162
+ scrollBody,
2163
+ containerRect,
2164
+ axis
2165
+ } = emblaApi.internalEngine();
2166
+ const containerSize = axis.measureSize(containerRect);
2167
+ fadeToNextDistance = clampNumber(containerSize * 0.75, 200, 500);
2168
+ shouldFadePair = false;
2169
+ opacities = emblaApi.scrollSnapList().map((_, index) => index === selectedSnap ? fullOpacity : noOpacity);
2170
+ defaultSettledBehaviour = scrollBody.settled;
2171
+ defaultProgressBehaviour = emblaApi.scrollProgress;
2172
+ scrollBody.settled = settled;
2173
+ emblaApi.scrollProgress = scrollProgress;
2174
+ emblaApi.on('select', select).on('slideFocus', fadeToSelectedSnapInstantly).on('pointerDown', pointerDown).on('pointerUp', pointerUp);
2175
+ disableScroll();
2176
+ fadeToSelectedSnapInstantly();
2177
+ }
2178
+ function destroy() {
2179
+ const {
2180
+ scrollBody
2181
+ } = emblaApi.internalEngine();
2182
+ scrollBody.settled = defaultSettledBehaviour;
2183
+ emblaApi.scrollProgress = defaultProgressBehaviour;
2184
+ emblaApi.off('select', select).off('slideFocus', fadeToSelectedSnapInstantly).off('pointerDown', pointerDown).off('pointerUp', pointerUp);
2185
+ emblaApi.slideNodes().forEach(slideNode => {
2186
+ const slideStyle = slideNode.style;
2187
+ slideStyle.opacity = '';
2188
+ slideStyle.transform = '';
2189
+ slideStyle.pointerEvents = '';
2190
+ if (!slideNode.getAttribute('style')) slideNode.removeAttribute('style');
2191
+ });
2192
+ }
2193
+ function fadeToSelectedSnapInstantly() {
2194
+ const selectedSnap = emblaApi.selectedScrollSnap();
2195
+ setOpacities(selectedSnap, fullOpacity);
2196
+ }
2197
+ function pointerUp() {
2198
+ shouldFadePair = false;
2199
+ }
2200
+ function pointerDown() {
2201
+ shouldFadePair = false;
2202
+ distanceFromPointerDown = 0;
2203
+ fadeVelocity = 0;
2204
+ }
2205
+ function select() {
2206
+ const duration = emblaApi.internalEngine().scrollBody.duration();
2207
+ fadeVelocity = duration ? 0 : fullOpacity;
2208
+ shouldFadePair = true;
2209
+ if (!duration) fadeToSelectedSnapInstantly();
2210
+ }
2211
+ function getSlideTransform(position) {
2212
+ const {
2213
+ axis
2214
+ } = emblaApi.internalEngine();
2215
+ const translateAxis = axis.scroll.toUpperCase();
2216
+ return `translate${translateAxis}(${axis.direction(position)}px)`;
2217
+ }
2218
+ function disableScroll() {
2219
+ const {
2220
+ translate,
2221
+ slideLooper
2222
+ } = emblaApi.internalEngine();
2223
+ translate.clear();
2224
+ translate.toggleActive(false);
2225
+ slideLooper.loopPoints.forEach(({
2226
+ translate
2227
+ }) => {
2228
+ translate.clear();
2229
+ translate.toggleActive(false);
2230
+ });
2231
+ }
2232
+ function lockExcessiveScroll(fadeIndex) {
2233
+ const {
2234
+ scrollSnaps,
2235
+ location,
2236
+ target
2237
+ } = emblaApi.internalEngine();
2238
+ if (!isNumber(fadeIndex) || opacities[fadeIndex] < 0.5) return;
2239
+ location.set(scrollSnaps[fadeIndex]);
2240
+ target.set(location);
2241
+ }
2242
+ function setOpacities(fadeIndex, velocity) {
2243
+ const scrollSnaps = emblaApi.scrollSnapList();
2244
+ scrollSnaps.forEach((_, indexA) => {
2245
+ const absVelocity = Math.abs(velocity);
2246
+ const currentOpacity = opacities[indexA];
2247
+ const isFadeIndex = indexA === fadeIndex;
2248
+ const nextOpacity = isFadeIndex ? currentOpacity + absVelocity : currentOpacity - absVelocity;
2249
+ const clampedOpacity = clampNumber(nextOpacity, noOpacity, fullOpacity);
2250
+ opacities[indexA] = clampedOpacity;
2251
+ const fadePair = isFadeIndex && shouldFadePair;
2252
+ const indexB = emblaApi.previousScrollSnap();
2253
+ if (fadePair) opacities[indexB] = 1 - clampedOpacity;
2254
+ if (isFadeIndex) setProgress(fadeIndex, clampedOpacity);
2255
+ setOpacity(indexA);
2256
+ });
2257
+ }
2258
+ function setOpacity(index) {
2259
+ const slidesInSnap = emblaApi.internalEngine().slideRegistry[index];
2260
+ const {
2261
+ scrollSnaps,
2262
+ containerRect
2263
+ } = emblaApi.internalEngine();
2264
+ const opacity = opacities[index];
2265
+ slidesInSnap.forEach(slideIndex => {
2266
+ const slideStyle = emblaApi.slideNodes()[slideIndex].style;
2267
+ const roundedOpacity = parseFloat(opacity.toFixed(2));
2268
+ const hasOpacity = roundedOpacity > noOpacity;
2269
+ const position = hasOpacity ? scrollSnaps[index] : containerRect.width + 2;
2270
+ const transform = getSlideTransform(position);
2271
+ if (hasOpacity) slideStyle.transform = transform;
2272
+ slideStyle.opacity = roundedOpacity.toString();
2273
+ slideStyle.pointerEvents = opacity > 0.5 ? 'auto' : 'none';
2274
+ if (!hasOpacity) slideStyle.transform = transform;
2275
+ });
2276
+ }
2277
+ function setProgress(fadeIndex, opacity) {
2278
+ const {
2279
+ index,
2280
+ dragHandler,
2281
+ scrollSnaps
2282
+ } = emblaApi.internalEngine();
2283
+ const pointerDown = dragHandler.pointerDown();
2284
+ const snapFraction = 1 / (scrollSnaps.length - 1);
2285
+ let indexA = fadeIndex;
2286
+ let indexB = pointerDown ? emblaApi.selectedScrollSnap() : emblaApi.previousScrollSnap();
2287
+ if (pointerDown && indexA === indexB) {
2288
+ const reverseSign = Math.sign(distanceFromPointerDown) * -1;
2289
+ indexA = indexB;
2290
+ indexB = index.clone().set(indexB).add(reverseSign).get();
2291
+ }
2292
+ const currentPosition = indexB * snapFraction;
2293
+ const diffPosition = (indexA - indexB) * snapFraction;
2294
+ progress = currentPosition + diffPosition * opacity;
2295
+ }
2296
+ function getFadeIndex() {
2297
+ const {
2298
+ dragHandler,
2299
+ index,
2300
+ scrollBody
2301
+ } = emblaApi.internalEngine();
2302
+ const selectedSnap = emblaApi.selectedScrollSnap();
2303
+ if (!dragHandler.pointerDown()) return selectedSnap;
2304
+ const directionSign = Math.sign(scrollBody.velocity());
2305
+ const distanceSign = Math.sign(distanceFromPointerDown);
2306
+ const nextSnap = index.clone().set(selectedSnap).add(directionSign * -1).get();
2307
+ if (!directionSign || !distanceSign) return null;
2308
+ return distanceSign === directionSign ? nextSnap : selectedSnap;
2309
+ }
2310
+ function fade(emblaApi) {
2311
+ const {
2312
+ dragHandler,
2313
+ scrollBody
2314
+ } = emblaApi.internalEngine();
2315
+ const pointerDown = dragHandler.pointerDown();
2316
+ const velocity = scrollBody.velocity();
2317
+ const duration = scrollBody.duration();
2318
+ const fadeIndex = getFadeIndex();
2319
+ const noFadeIndex = !isNumber(fadeIndex);
2320
+ if (pointerDown) {
2321
+ if (!velocity) return;
2322
+ distanceFromPointerDown += velocity;
2323
+ fadeVelocity = Math.abs(velocity / fadeToNextDistance);
2324
+ lockExcessiveScroll(fadeIndex);
2325
+ }
2326
+ if (!pointerDown) {
2327
+ if (!duration || noFadeIndex) return;
2328
+ fadeVelocity += (fullOpacity - opacities[fadeIndex]) / duration;
2329
+ fadeVelocity *= fadeFriction;
2330
+ }
2331
+ if (noFadeIndex) return;
2332
+ setOpacities(fadeIndex, fadeVelocity);
2333
+ }
2334
+ function settled() {
2335
+ const {
2336
+ target,
2337
+ location
2338
+ } = emblaApi.internalEngine();
2339
+ const diffToTarget = target.get() - location.get();
2340
+ const notReachedTarget = Math.abs(diffToTarget) >= 1;
2341
+ const fadeIndex = getFadeIndex();
2342
+ const noFadeIndex = !isNumber(fadeIndex);
2343
+ fade(emblaApi);
2344
+ if (noFadeIndex || notReachedTarget) return false;
2345
+ return opacities[fadeIndex] > 0.999;
2346
+ }
2347
+ function scrollProgress() {
2348
+ return progress;
2349
+ }
2350
+ const self = {
2351
+ name: 'fade',
2352
+ options: userOptions,
2353
+ init,
2354
+ destroy
2355
+ };
2356
+ return self;
2357
+ }
2358
+ Fade.globalOptions = undefined;
2359
+
2360
+ var MOBILE_MEDIA_QUERY$1 = "(max-width: 767px)";
2361
+ /** Media track slides. Also the dot/aria-label source of truth. */
2362
+ var MEDIA_ITEM_SELECTOR = "[data-lsg-carousel-item]";
2363
+ /** Text track slides, one per media slide. */
2364
+ var CONTENT_ITEM_SELECTOR = "[data-lsg-carousel-content-item]";
2365
+ var directChildren = function (container, selector) {
2366
+ return container ? Array.from(container.children).filter(function (el) {
2367
+ return el instanceof HTMLElement && el.matches(selector);
2368
+ }) : [];
2369
+ };
2108
2370
  var LsgCarouselController = /** @class */function () {
2109
2371
  function LsgCarouselController(viewport, elements, options) {
2372
+ var _a;
2110
2373
  if (elements === void 0) {
2111
2374
  elements = {};
2112
2375
  }
@@ -2114,8 +2377,10 @@ var LsgCarouselController = /** @class */function () {
2114
2377
  options = {};
2115
2378
  }
2116
2379
  var _this = this;
2117
- var _a, _b, _c, _d;
2118
- this.embla = null;
2380
+ var _b, _c, _d, _e, _f, _g, _h;
2381
+ this.media = null;
2382
+ this.content = null;
2383
+ this.syncing = false;
2119
2384
  /**
2120
2385
  * Embla automatically falls back to non-looping mode when there is not enough
2121
2386
  * slide content to create a safe loop (most noticeable with two-up layouts and
@@ -2123,82 +2388,228 @@ var LsgCarouselController = /** @class */function () {
2123
2388
  * when there is no native previous snap, jump to the final authored snap.
2124
2389
  */
2125
2390
  this.scrollPrev = function () {
2126
- if (!_this.embla) return;
2127
- if (_this.embla.canScrollPrev()) {
2128
- _this.embla.scrollPrev();
2391
+ if (!_this.media) return;
2392
+ if (_this.media.canScrollPrev()) {
2393
+ _this.media.scrollPrev();
2129
2394
  return;
2130
2395
  }
2131
- var lastSnap = _this.embla.scrollSnapList().length - 1;
2132
- if (lastSnap >= 0) _this.embla.scrollTo(lastSnap);
2396
+ var lastSnap = _this.media.scrollSnapList().length - 1;
2397
+ if (lastSnap >= 0) _this.media.scrollTo(lastSnap);
2133
2398
  };
2134
2399
  /** See `scrollPrev` for why the explicit wrap fallback is required. */
2135
2400
  this.scrollNext = function () {
2136
- if (!_this.embla) return;
2137
- if (_this.embla.canScrollNext()) {
2138
- _this.embla.scrollNext();
2401
+ if (!_this.media) return;
2402
+ if (_this.media.canScrollNext()) {
2403
+ _this.media.scrollNext();
2139
2404
  return;
2140
2405
  }
2141
- if (_this.embla.scrollSnapList().length > 0) _this.embla.scrollTo(0);
2406
+ if (_this.media.scrollSnapList().length > 0) _this.media.scrollTo(0);
2407
+ };
2408
+ /**
2409
+ * The text track never initiates navigation, but it owns its own resize and
2410
+ * mutation observers. If one instance re-measures without the other, this pulls
2411
+ * the media track back onto the text track's index rather than letting them drift.
2412
+ */
2413
+ this.handleContentSelect = function () {
2414
+ if (!_this.media || !_this.content || _this.syncing) return;
2415
+ var target = _this.content.selectedScrollSnap();
2416
+ if (_this.media.selectedScrollSnap() === target) return;
2417
+ _this.syncing = true;
2418
+ try {
2419
+ _this.media.scrollTo(target, true);
2420
+ } finally {
2421
+ _this.syncing = false;
2422
+ }
2423
+ };
2424
+ /** Reader-initiated navigation: repaint state, then crossfade the text. */
2425
+ this.handleMediaSelect = function () {
2426
+ _this.syncSelectedState();
2427
+ _this.pushToContent();
2428
+ };
2429
+ /**
2430
+ * Re-measure events (breakpoint flip, resize, authored items added/removed).
2431
+ * The text is realigned with a hard cut because nothing moved for the reader.
2432
+ */
2433
+ this.handleResync = function () {
2434
+ _this.syncSelectedState();
2435
+ _this.pushToContent(true);
2142
2436
  };
2437
+ /** Repaints dot/arrow/a11y state from the media index. Never navigates. */
2143
2438
  this.syncSelectedState = function () {
2144
- var _a, _b;
2145
- var selected = (_b = (_a = _this.embla) === null || _a === void 0 ? void 0 : _a.selectedScrollSnap()) !== null && _b !== void 0 ? _b : 0;
2439
+ var _a, _b, _c, _d, _e, _f;
2440
+ var selected = (_b = (_a = _this.media) === null || _a === void 0 ? void 0 : _a.selectedScrollSnap()) !== null && _b !== void 0 ? _b : 0;
2441
+ var snapCount = (_d = (_c = _this.media) === null || _c === void 0 ? void 0 : _c.scrollSnapList().length) !== null && _d !== void 0 ? _d : 0;
2146
2442
  _this.paginationBtns.forEach(function (button, index) {
2147
2443
  var active = index === selected;
2148
2444
  button.classList.toggle("lsg-carousel__dot--active", active);
2149
2445
  button.setAttribute("aria-current", active ? "true" : "false");
2150
2446
  });
2447
+ // Cosmetic only. Looping plus the cyclic wrap above mean both arrows always
2448
+ // act, so `disabled`/`aria-disabled` would misreport them to assistive tech.
2449
+ // Themes use these classes to mute the leading/trailing half of the pill.
2450
+ (_e = _this.els.prevBtn) === null || _e === void 0 ? void 0 : _e.classList.toggle("lsg-carousel__arrow--at-start", selected === 0);
2451
+ (_f = _this.els.nextBtn) === null || _f === void 0 ? void 0 : _f.classList.toggle("lsg-carousel__arrow--at-end", snapCount > 0 && selected === snapCount - 1);
2452
+ // The fade plugin only sets opacity and pointer-events, so without this every
2453
+ // faded-out text block keeps its heading in the accessibility tree and its CTA
2454
+ // in the tab order - N copies of the same landmark for a sighted-equivalent
2455
+ // view of one.
2456
+ _this.contentSlides.forEach(function (slide, index) {
2457
+ var active = index === selected;
2458
+ slide.toggleAttribute("inert", !active);
2459
+ if (active) slide.removeAttribute("aria-hidden");else slide.setAttribute("aria-hidden", "true");
2460
+ });
2151
2461
  };
2152
2462
  this.els = elements;
2463
+ this.mediaViewport = viewport;
2153
2464
  this.paginationBtns = elements.paginationBtns ? Array.from(elements.paginationBtns) : [];
2154
- this.embla = EmblaCarousel(viewport, {
2465
+ var mediaTrack = viewport.firstElementChild;
2466
+ var mediaSlides = directChildren(mediaTrack, MEDIA_ITEM_SELECTOR);
2467
+ // Embla resolves `container` as `root.children[0]` and `slides` as its
2468
+ // element children. Passing both explicitly instead makes the instance
2469
+ // immune to AEM injecting its own nodes (e.g. the edit-mode
2470
+ // `div.new.section.aem-Grid-newComponent` drop target) into the track.
2471
+ this.media = EmblaCarousel(viewport, {
2155
2472
  align: "start",
2156
2473
  // Every authored media item owns a pagination dot. `trimSnaps` can remove
2157
2474
  // the final snap when two-up/peek layouts do not have enough overflow,
2158
2475
  // leaving the last authored item only partially reachable. Keep all snaps
2159
2476
  // so dot/item indexes stay 1:1 for 2, 3, 4, ... media items.
2477
+ //
2478
+ // This is ALSO load-bearing for the text/media sync: `containSnaps` is
2479
+ // `!loop && !!containScroll`, so with this `false` the snap list is
2480
+ // always `snapsAligned` - one snap per slide, whatever the slide's
2481
+ // flex-basis. That is the only reason a 380px peek track and a 100%-wide
2482
+ // crossfade track can share one index. Reverting this to `trimSnaps`
2483
+ // drops trailing snaps on the media track alone and desyncs the tail.
2160
2484
  containScroll: false,
2161
- direction: (_a = options.direction) !== null && _a !== void 0 ? _a : "ltr",
2162
- loop: (_b = options.loop) !== null && _b !== void 0 ? _b : true,
2485
+ direction: (_b = options.direction) !== null && _b !== void 0 ? _b : "ltr",
2486
+ loop: (_c = options.loop) !== null && _c !== void 0 ? _c : true,
2163
2487
  skipSnaps: false,
2164
- slidesToScroll: 1
2488
+ slidesToScroll: 1,
2489
+ container: mediaTrack !== null && mediaTrack !== void 0 ? mediaTrack : undefined,
2490
+ slides: mediaSlides.length ? mediaSlides : undefined,
2491
+ // All layouts collapse to the same mobile stack, which is never
2492
+ // mirrored. Embla restores the selected index when a breakpoint
2493
+ // re-activates, so the flip is not visible to the reader.
2494
+ breakpoints: (_a = {}, _a[MOBILE_MEDIA_QUERY$1] = {
2495
+ direction: "ltr"
2496
+ }, _a)
2165
2497
  });
2498
+ var contentViewport = (_d = elements.contentViewport) !== null && _d !== void 0 ? _d : null;
2499
+ var contentTrack = contentViewport === null || contentViewport === void 0 ? void 0 : contentViewport.firstElementChild;
2500
+ this.contentSlides = directChildren(contentTrack, CONTENT_ITEM_SELECTOR);
2501
+ // Unequal counts are the one remaining way the two tracks can desync, and a
2502
+ // text block silently paired with the wrong image is worse than no text
2503
+ // animation at all. Degrade to media-only rather than risk it.
2504
+ var countsMatch = mediaSlides.length > 0 && this.contentSlides.length === mediaSlides.length;
2505
+ if (contentViewport && contentTrack && countsMatch) {
2506
+ this.content = EmblaCarousel(contentViewport, {
2507
+ align: "start",
2508
+ // Must match the media track's snap arithmetic - see above.
2509
+ containScroll: false,
2510
+ // The text crossfades in place, so there is nothing to mirror.
2511
+ direction: "ltr",
2512
+ // Inert on a fade instance: the plugin calls `disableScroll()`, which
2513
+ // deactivates the translate and every loop point. Set for config
2514
+ // symmetry with the media track, not for behaviour.
2515
+ loop: (_e = options.loop) !== null && _e !== void 0 ? _e : true,
2516
+ skipSnaps: false,
2517
+ slidesToScroll: 1,
2518
+ // The reader drags the media, never the text. Without this the text
2519
+ // track would fight the media track for the same pointer.
2520
+ watchDrag: false,
2521
+ container: contentTrack,
2522
+ slides: this.contentSlides
2523
+ }, [Fade()]);
2524
+ }
2166
2525
  this.paginationHandlers = this.paginationBtns.map(function (_, index) {
2167
2526
  return function () {
2168
2527
  var _a;
2169
- (_a = _this.embla) === null || _a === void 0 ? void 0 : _a.scrollTo(index);
2528
+ (_a = _this.media) === null || _a === void 0 ? void 0 : _a.scrollTo(index);
2170
2529
  };
2171
2530
  });
2172
- (_c = this.els.prevBtn) === null || _c === void 0 ? void 0 : _c.addEventListener("click", this.scrollPrev);
2173
- (_d = this.els.nextBtn) === null || _d === void 0 ? void 0 : _d.addEventListener("click", this.scrollNext);
2531
+ (_f = this.els.prevBtn) === null || _f === void 0 ? void 0 : _f.addEventListener("click", this.scrollPrev);
2532
+ (_g = this.els.nextBtn) === null || _g === void 0 ? void 0 : _g.addEventListener("click", this.scrollNext);
2174
2533
  this.paginationBtns.forEach(function (button, index) {
2175
2534
  button.addEventListener("click", _this.paginationHandlers[index]);
2176
2535
  });
2177
- this.embla.on("select", this.syncSelectedState);
2178
- this.embla.on("reInit", this.syncSelectedState);
2179
- this.syncSelectedState();
2180
- }
2536
+ this.media.on("select", this.handleMediaSelect);
2537
+ this.media.on("reInit", this.handleResync);
2538
+ this.media.on("slidesChanged", this.handleResync);
2539
+ (_h = this.content) === null || _h === void 0 ? void 0 : _h.on("select", this.handleContentSelect);
2540
+ // Initial alignment is a hard cut - there is nothing to crossfade from.
2541
+ this.handleResync();
2542
+ }
2543
+ /**
2544
+ * Drive the text track from the media index.
2545
+ *
2546
+ * `jump` skips the crossfade (Embla sets duration 0, and the fade plugin then
2547
+ * snaps opacity instantly). Use it only for re-measure events, never for
2548
+ * reader-initiated navigation, or the text hard-cuts instead of fading.
2549
+ */
2550
+ LsgCarouselController.prototype.pushToContent = function (jump) {
2551
+ if (jump === void 0) {
2552
+ jump = false;
2553
+ }
2554
+ if (!this.media || !this.content || this.syncing) return;
2555
+ var target = this.media.selectedScrollSnap();
2556
+ if (this.content.selectedScrollSnap() === target) return;
2557
+ this.syncing = true;
2558
+ try {
2559
+ this.content.scrollTo(target, jump);
2560
+ } finally {
2561
+ this.syncing = false;
2562
+ }
2563
+ };
2181
2564
  Object.defineProperty(LsgCarouselController.prototype, "emblaApi", {
2182
2565
  get: function () {
2183
- return this.embla;
2566
+ return this.media;
2567
+ },
2568
+ enumerable: false,
2569
+ configurable: true
2570
+ });
2571
+ Object.defineProperty(LsgCarouselController.prototype, "contentApi", {
2572
+ /** Text track handle. Exposed for the index-parity checks in the test plan. */
2573
+ get: function () {
2574
+ return this.content;
2184
2575
  },
2185
2576
  enumerable: false,
2186
2577
  configurable: true
2187
2578
  });
2188
2579
  LsgCarouselController.prototype.destroy = function () {
2189
2580
  var _this = this;
2190
- var _a, _b;
2581
+ var _a, _b, _c, _d;
2191
2582
  (_a = this.els.prevBtn) === null || _a === void 0 ? void 0 : _a.removeEventListener("click", this.scrollPrev);
2192
2583
  (_b = this.els.nextBtn) === null || _b === void 0 ? void 0 : _b.removeEventListener("click", this.scrollNext);
2193
2584
  this.paginationBtns.forEach(function (button, index) {
2194
2585
  button.removeEventListener("click", _this.paginationHandlers[index]);
2195
2586
  });
2196
- if (this.embla) {
2197
- this.embla.off("select", this.syncSelectedState);
2198
- this.embla.off("reInit", this.syncSelectedState);
2199
- this.embla.destroy();
2200
- this.embla = null;
2587
+ // Content first: its plugin restores the inline opacity/transform it wrote,
2588
+ // and it reads `internalEngine()` while doing so.
2589
+ if (this.content) {
2590
+ this.content.off("select", this.handleContentSelect);
2591
+ this.content.destroy();
2592
+ this.content = null;
2593
+ }
2594
+ if (this.media) {
2595
+ this.media.off("select", this.handleMediaSelect);
2596
+ this.media.off("reInit", this.handleResync);
2597
+ this.media.off("slidesChanged", this.handleResync);
2598
+ this.media.destroy();
2599
+ this.media = null;
2201
2600
  }
2601
+ // Embla restores what Embla wrote. Everything below is ours, and leaving it
2602
+ // behind would make server-rendered markup re-initialise into a stale state.
2603
+ this.paginationBtns.forEach(function (button) {
2604
+ button.classList.remove("lsg-carousel__dot--active");
2605
+ button.removeAttribute("aria-current");
2606
+ });
2607
+ (_c = this.els.prevBtn) === null || _c === void 0 ? void 0 : _c.classList.remove("lsg-carousel__arrow--at-start");
2608
+ (_d = this.els.nextBtn) === null || _d === void 0 ? void 0 : _d.classList.remove("lsg-carousel__arrow--at-end");
2609
+ this.contentSlides.forEach(function (slide) {
2610
+ slide.removeAttribute("inert");
2611
+ slide.removeAttribute("aria-hidden");
2612
+ });
2202
2613
  };
2203
2614
  return LsgCarouselController;
2204
2615
  }();
@@ -2210,24 +2621,27 @@ var mediaTypeFor = function (item) {
2210
2621
  var directionForLayout = function (layout) {
2211
2622
  return layout === "media-left" ? "rtl" : "ltr";
2212
2623
  };
2624
+ var hasText = function (item) {
2625
+ return Boolean(item.preTitle || item.heading || item.body || item.cta);
2626
+ };
2213
2627
  var LsgCarousel = function (_a) {
2214
- var _b;
2215
- var heading = _a.heading,
2628
+ var _b = _a.items,
2629
+ items = _b === void 0 ? [] : _b,
2630
+ _c = _a.layout,
2631
+ layout = _c === void 0 ? "media-right" : _c,
2632
+ background = _a.background,
2633
+ _d = _a.headingTag,
2634
+ headingTag = _d === void 0 ? "h2" : _d,
2635
+ _e = _a.ariaLabel,
2636
+ ariaLabel = _e === void 0 ? "Media carousel" : _e,
2637
+ _f = _a.className,
2638
+ className = _f === void 0 ? "" : _f,
2639
+ heading = _a.heading,
2216
2640
  preTitle = _a.preTitle,
2217
2641
  body = _a.body,
2218
- cta = _a.cta,
2219
- _c = _a.items,
2220
- items = _c === void 0 ? [] : _c,
2221
- _d = _a.layout,
2222
- layout = _d === void 0 ? "media-right" : _d,
2223
- _e = _a.headingTag,
2224
- headingTag = _e === void 0 ? "h2" : _e,
2225
- _f = _a.ariaLabel,
2226
- ariaLabel = _f === void 0 ? "Media carousel" : _f,
2227
- _g = _a.className,
2228
- className = _g === void 0 ? "" : _g;
2229
- var rootRef = useRef(null);
2642
+ cta = _a.cta;
2230
2643
  var viewportRef = useRef(null);
2644
+ var contentViewportRef = useRef(null);
2231
2645
  var prevBtnRef = useRef(null);
2232
2646
  var nextBtnRef = useRef(null);
2233
2647
  var dotsRef = useRef(null);
@@ -2235,13 +2649,29 @@ var LsgCarousel = function (_a) {
2235
2649
  var HeadingTag = headingTag;
2236
2650
  var isCarousel = items.length > 1;
2237
2651
  var carouselDirection = directionForLayout(layout);
2652
+ // Legacy single-content-block callers passed the text alongside `items`. Fold
2653
+ // it onto the first item so their carousel still renders its copy.
2654
+ var resolvedItems = useMemo(function () {
2655
+ var legacy = {
2656
+ preTitle: preTitle,
2657
+ heading: heading,
2658
+ body: body,
2659
+ cta: cta
2660
+ };
2661
+ var hasLegacy = Boolean(legacy.preTitle || legacy.heading || legacy.body || legacy.cta);
2662
+ if (!hasLegacy || !items.length || hasText(items[0])) return items;
2663
+ return items.map(function (item, index) {
2664
+ return index === 0 ? __assign(__assign({}, legacy), item) : item;
2665
+ });
2666
+ }, [items, preTitle, heading, body, cta]);
2238
2667
  useEffect(function () {
2239
2668
  var _a, _b;
2240
2669
  if (!viewportRef.current || !isCarousel) return;
2241
2670
  controllerRef.current = new LsgCarouselController(viewportRef.current, {
2242
2671
  prevBtn: prevBtnRef.current,
2243
2672
  nextBtn: nextBtnRef.current,
2244
- paginationBtns: (_b = (_a = dotsRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("[data-lsg-carousel-dot]")) !== null && _b !== void 0 ? _b : []
2673
+ paginationBtns: (_b = (_a = dotsRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll("[data-lsg-carousel-dot]")) !== null && _b !== void 0 ? _b : [],
2674
+ contentViewport: contentViewportRef.current
2245
2675
  }, {
2246
2676
  loop: true,
2247
2677
  direction: carouselDirection
@@ -2251,55 +2681,72 @@ var LsgCarousel = function (_a) {
2251
2681
  (_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.destroy();
2252
2682
  controllerRef.current = null;
2253
2683
  };
2254
- }, [carouselDirection, isCarousel, items.length]);
2255
- var rootClasses = ["lsg-carousel", "lsg-carousel--".concat(layout), className].filter(Boolean).join(" ");
2684
+ }, [carouselDirection, isCarousel, resolvedItems.length]);
2685
+ var rootClasses = ["lsg-carousel", "lsg-carousel--".concat(layout),
2686
+ // In AEM this class arrives on the decoration div instead; the SCSS only
2687
+ // sets inherited custom properties, so either position works.
2688
+ background ? "lsg-carousel--bg-".concat(background) : "", className].filter(Boolean).join(" ");
2689
+ var keyFor = function (item, index) {
2690
+ var _a, _b, _c;
2691
+ return (_a = item.id) !== null && _a !== void 0 ? _a : "".concat(mediaTypeFor(item), "-").concat((_c = (_b = item.imageUrl) !== null && _b !== void 0 ? _b : item.videoUrl) !== null && _c !== void 0 ? _c : index, "-").concat(index);
2692
+ };
2256
2693
  return /*#__PURE__*/React.createElement("section", {
2257
- ref: rootRef,
2258
2694
  className: rootClasses,
2259
2695
  "data-lsg-is": "carousel",
2260
2696
  "data-lsg-carousel-layout": layout,
2261
2697
  "data-lsg-carousel-direction": carouselDirection,
2262
- "data-lsg-carousel-count": items.length,
2698
+ "data-lsg-carousel-count": resolvedItems.length,
2263
2699
  "aria-label": ariaLabel
2264
2700
  }, /*#__PURE__*/React.createElement("div", {
2265
2701
  className: "lsg-carousel__shell"
2266
2702
  }, /*#__PURE__*/React.createElement("div", {
2267
- className: "lsg-carousel__content"
2268
- }, preTitle && /*#__PURE__*/React.createElement("div", {
2269
- className: "lsg-carousel__pre-title"
2270
- }, /*#__PURE__*/React.createElement("span", {
2271
- className: "lsg-carousel__pre-title-marker",
2272
- "aria-hidden": "true"
2273
- }), /*#__PURE__*/React.createElement("span", null, preTitle)), /*#__PURE__*/React.createElement(HeadingTag, {
2274
- className: "lsg-carousel__heading"
2275
- }, heading), body && /*#__PURE__*/React.createElement("p", {
2276
- className: "lsg-carousel__body"
2277
- }, body), cta && /*#__PURE__*/React.createElement("div", {
2278
- className: "lsg-carousel__actions"
2279
- }, /*#__PURE__*/React.createElement(LsgButton, {
2280
- className: "lsg-carousel__cta",
2281
- href: cta.href,
2282
- external: cta.external,
2283
- variant: (_b = cta.variant) !== null && _b !== void 0 ? _b : "primary",
2284
- onClick: cta.onClick
2285
- }, cta.label))), /*#__PURE__*/React.createElement("div", {
2703
+ className: "lsg-carousel__content",
2704
+ ref: contentViewportRef,
2705
+ "data-lsg-carousel-content-viewport": true
2706
+ }, /*#__PURE__*/React.createElement("div", {
2707
+ className: "lsg-carousel__content-track"
2708
+ }, resolvedItems.map(function (item, index) {
2709
+ var _a;
2710
+ return /*#__PURE__*/React.createElement("div", {
2711
+ key: keyFor(item, index),
2712
+ className: "lsg-carousel__content-slide",
2713
+ "data-lsg-carousel-content-item": true
2714
+ }, item.preTitle && /*#__PURE__*/React.createElement("div", {
2715
+ className: "lsg-carousel__pre-title"
2716
+ }, /*#__PURE__*/React.createElement("span", {
2717
+ className: "lsg-carousel__pre-title-marker",
2718
+ "aria-hidden": "true"
2719
+ }), /*#__PURE__*/React.createElement("span", null, item.preTitle)), item.heading && /*#__PURE__*/React.createElement(HeadingTag, {
2720
+ className: "lsg-carousel__heading"
2721
+ }, item.heading), item.body && /*#__PURE__*/React.createElement("p", {
2722
+ className: "lsg-carousel__body"
2723
+ }, item.body), item.cta && /*#__PURE__*/React.createElement("div", {
2724
+ className: "lsg-carousel__actions"
2725
+ }, /*#__PURE__*/React.createElement(LsgButton, {
2726
+ className: "lsg-carousel__cta",
2727
+ href: item.cta.href,
2728
+ external: item.cta.external,
2729
+ variant: (_a = item.cta.variant) !== null && _a !== void 0 ? _a : "primary",
2730
+ onClick: item.cta.onClick
2731
+ }, item.cta.label)));
2732
+ }))), /*#__PURE__*/React.createElement("div", {
2286
2733
  className: "lsg-carousel__media-column"
2287
2734
  }, /*#__PURE__*/React.createElement("div", {
2288
2735
  className: "lsg-carousel__viewport",
2289
2736
  ref: viewportRef,
2290
- dir: carouselDirection
2737
+ dir: carouselDirection,
2738
+ "data-lsg-carousel-media-viewport": true
2291
2739
  }, /*#__PURE__*/React.createElement("div", {
2292
2740
  className: "lsg-carousel__track",
2293
2741
  role: "list"
2294
- }, items.map(function (item, index) {
2295
- var _a, _b, _c, _d, _e, _f, _g;
2742
+ }, resolvedItems.map(function (item, index) {
2743
+ var _a, _b, _c, _d;
2296
2744
  var type = mediaTypeFor(item);
2297
- var key = (_a = item.id) !== null && _a !== void 0 ? _a : "".concat(type, "-").concat((_c = (_b = item.imageUrl) !== null && _b !== void 0 ? _b : item.videoUrl) !== null && _c !== void 0 ? _c : index, "-").concat(index);
2298
2745
  return /*#__PURE__*/React.createElement("article", {
2299
- key: key,
2746
+ key: keyFor(item, index),
2300
2747
  className: "lsg-carousel__slide",
2301
2748
  role: "listitem",
2302
- "aria-label": "Slide ".concat(index + 1, " of ").concat(items.length),
2749
+ "aria-label": "Slide ".concat(index + 1, " of ").concat(resolvedItems.length),
2303
2750
  "data-lsg-carousel-item": true
2304
2751
  }, /*#__PURE__*/React.createElement("div", {
2305
2752
  className: "lsg-carousel__media"
@@ -2307,10 +2754,10 @@ var LsgCarousel = function (_a) {
2307
2754
  videoUrl: item.videoUrl,
2308
2755
  imageUrl: item.videoPoster,
2309
2756
  imageAlt: item.imageAlt,
2310
- controls: (_d = item.videoControls) !== null && _d !== void 0 ? _d : true,
2311
- autoplay: (_e = item.videoAutoPlay) !== null && _e !== void 0 ? _e : false,
2312
- muted: (_f = item.videoMuted) !== null && _f !== void 0 ? _f : true,
2313
- loop: (_g = item.videoLoop) !== null && _g !== void 0 ? _g : false,
2757
+ controls: (_a = item.videoControls) !== null && _a !== void 0 ? _a : true,
2758
+ autoplay: (_b = item.videoAutoPlay) !== null && _b !== void 0 ? _b : false,
2759
+ muted: (_c = item.videoMuted) !== null && _c !== void 0 ? _c : true,
2760
+ loop: (_d = item.videoLoop) !== null && _d !== void 0 ? _d : false,
2314
2761
  displayMode: "content",
2315
2762
  showTags: false,
2316
2763
  className: "lsg-carousel__video-component"
@@ -2325,8 +2772,10 @@ var LsgCarousel = function (_a) {
2325
2772
  className: "lsg-carousel__media-label"
2326
2773
  }, item.label)));
2327
2774
  }))), isCarousel && /*#__PURE__*/React.createElement("div", {
2328
- className: "lsg-carousel__navigation",
2775
+ className: "lsg-carousel__controls",
2329
2776
  "aria-label": "Carousel navigation"
2777
+ }, /*#__PURE__*/React.createElement("div", {
2778
+ className: "lsg-carousel__nav"
2330
2779
  }, /*#__PURE__*/React.createElement("button", {
2331
2780
  ref: prevBtnRef,
2332
2781
  className: "lsg-carousel__arrow lsg-carousel__arrow--prev",
@@ -2336,10 +2785,19 @@ var LsgCarousel = function (_a) {
2336
2785
  }, /*#__PURE__*/React.createElement("span", {
2337
2786
  className: "lsg-carousel__arrow-icon",
2338
2787
  "aria-hidden": "true"
2339
- })), /*#__PURE__*/React.createElement("div", {
2788
+ })), /*#__PURE__*/React.createElement("button", {
2789
+ ref: nextBtnRef,
2790
+ className: "lsg-carousel__arrow lsg-carousel__arrow--next",
2791
+ type: "button",
2792
+ "aria-label": "Next slide",
2793
+ "data-lsg-carousel-next": true
2794
+ }, /*#__PURE__*/React.createElement("span", {
2795
+ className: "lsg-carousel__arrow-icon",
2796
+ "aria-hidden": "true"
2797
+ }))), /*#__PURE__*/React.createElement("div", {
2340
2798
  className: "lsg-carousel__pagination",
2341
2799
  ref: dotsRef
2342
- }, items.map(function (item, index) {
2800
+ }, resolvedItems.map(function (item, index) {
2343
2801
  var _a;
2344
2802
  return /*#__PURE__*/React.createElement("button", {
2345
2803
  key: (_a = item.id) !== null && _a !== void 0 ? _a : "dot-".concat(index),
@@ -2349,15 +2807,6 @@ var LsgCarousel = function (_a) {
2349
2807
  "aria-current": index === 0 ? "true" : "false",
2350
2808
  "data-lsg-carousel-dot": true
2351
2809
  });
2352
- })), /*#__PURE__*/React.createElement("button", {
2353
- ref: nextBtnRef,
2354
- className: "lsg-carousel__arrow lsg-carousel__arrow--next",
2355
- type: "button",
2356
- "aria-label": "Next slide",
2357
- "data-lsg-carousel-next": true
2358
- }, /*#__PURE__*/React.createElement("span", {
2359
- className: "lsg-carousel__arrow-icon",
2360
- "aria-hidden": "true"
2361
2810
  }))))));
2362
2811
  };
2363
2812
 
@@ -3761,227 +4210,6 @@ var LsgFooter = function (_a) {
3761
4210
  }))))), bottomBar);
3762
4211
  };
3763
4212
 
3764
- function clampNumber(number, min, max) {
3765
- return Math.min(Math.max(number, min), max);
3766
- }
3767
- function isNumber(value) {
3768
- return typeof value === 'number' && !isNaN(value);
3769
- }
3770
- function Fade(userOptions = {}) {
3771
- const fullOpacity = 1;
3772
- const noOpacity = 0;
3773
- const fadeFriction = 0.68;
3774
- let emblaApi;
3775
- let opacities = [];
3776
- let fadeToNextDistance;
3777
- let distanceFromPointerDown = 0;
3778
- let fadeVelocity = 0;
3779
- let progress = 0;
3780
- let shouldFadePair = false;
3781
- let defaultSettledBehaviour;
3782
- let defaultProgressBehaviour;
3783
- function init(emblaApiInstance) {
3784
- emblaApi = emblaApiInstance;
3785
- const selectedSnap = emblaApi.selectedScrollSnap();
3786
- const {
3787
- scrollBody,
3788
- containerRect,
3789
- axis
3790
- } = emblaApi.internalEngine();
3791
- const containerSize = axis.measureSize(containerRect);
3792
- fadeToNextDistance = clampNumber(containerSize * 0.75, 200, 500);
3793
- shouldFadePair = false;
3794
- opacities = emblaApi.scrollSnapList().map((_, index) => index === selectedSnap ? fullOpacity : noOpacity);
3795
- defaultSettledBehaviour = scrollBody.settled;
3796
- defaultProgressBehaviour = emblaApi.scrollProgress;
3797
- scrollBody.settled = settled;
3798
- emblaApi.scrollProgress = scrollProgress;
3799
- emblaApi.on('select', select).on('slideFocus', fadeToSelectedSnapInstantly).on('pointerDown', pointerDown).on('pointerUp', pointerUp);
3800
- disableScroll();
3801
- fadeToSelectedSnapInstantly();
3802
- }
3803
- function destroy() {
3804
- const {
3805
- scrollBody
3806
- } = emblaApi.internalEngine();
3807
- scrollBody.settled = defaultSettledBehaviour;
3808
- emblaApi.scrollProgress = defaultProgressBehaviour;
3809
- emblaApi.off('select', select).off('slideFocus', fadeToSelectedSnapInstantly).off('pointerDown', pointerDown).off('pointerUp', pointerUp);
3810
- emblaApi.slideNodes().forEach(slideNode => {
3811
- const slideStyle = slideNode.style;
3812
- slideStyle.opacity = '';
3813
- slideStyle.transform = '';
3814
- slideStyle.pointerEvents = '';
3815
- if (!slideNode.getAttribute('style')) slideNode.removeAttribute('style');
3816
- });
3817
- }
3818
- function fadeToSelectedSnapInstantly() {
3819
- const selectedSnap = emblaApi.selectedScrollSnap();
3820
- setOpacities(selectedSnap, fullOpacity);
3821
- }
3822
- function pointerUp() {
3823
- shouldFadePair = false;
3824
- }
3825
- function pointerDown() {
3826
- shouldFadePair = false;
3827
- distanceFromPointerDown = 0;
3828
- fadeVelocity = 0;
3829
- }
3830
- function select() {
3831
- const duration = emblaApi.internalEngine().scrollBody.duration();
3832
- fadeVelocity = duration ? 0 : fullOpacity;
3833
- shouldFadePair = true;
3834
- if (!duration) fadeToSelectedSnapInstantly();
3835
- }
3836
- function getSlideTransform(position) {
3837
- const {
3838
- axis
3839
- } = emblaApi.internalEngine();
3840
- const translateAxis = axis.scroll.toUpperCase();
3841
- return `translate${translateAxis}(${axis.direction(position)}px)`;
3842
- }
3843
- function disableScroll() {
3844
- const {
3845
- translate,
3846
- slideLooper
3847
- } = emblaApi.internalEngine();
3848
- translate.clear();
3849
- translate.toggleActive(false);
3850
- slideLooper.loopPoints.forEach(({
3851
- translate
3852
- }) => {
3853
- translate.clear();
3854
- translate.toggleActive(false);
3855
- });
3856
- }
3857
- function lockExcessiveScroll(fadeIndex) {
3858
- const {
3859
- scrollSnaps,
3860
- location,
3861
- target
3862
- } = emblaApi.internalEngine();
3863
- if (!isNumber(fadeIndex) || opacities[fadeIndex] < 0.5) return;
3864
- location.set(scrollSnaps[fadeIndex]);
3865
- target.set(location);
3866
- }
3867
- function setOpacities(fadeIndex, velocity) {
3868
- const scrollSnaps = emblaApi.scrollSnapList();
3869
- scrollSnaps.forEach((_, indexA) => {
3870
- const absVelocity = Math.abs(velocity);
3871
- const currentOpacity = opacities[indexA];
3872
- const isFadeIndex = indexA === fadeIndex;
3873
- const nextOpacity = isFadeIndex ? currentOpacity + absVelocity : currentOpacity - absVelocity;
3874
- const clampedOpacity = clampNumber(nextOpacity, noOpacity, fullOpacity);
3875
- opacities[indexA] = clampedOpacity;
3876
- const fadePair = isFadeIndex && shouldFadePair;
3877
- const indexB = emblaApi.previousScrollSnap();
3878
- if (fadePair) opacities[indexB] = 1 - clampedOpacity;
3879
- if (isFadeIndex) setProgress(fadeIndex, clampedOpacity);
3880
- setOpacity(indexA);
3881
- });
3882
- }
3883
- function setOpacity(index) {
3884
- const slidesInSnap = emblaApi.internalEngine().slideRegistry[index];
3885
- const {
3886
- scrollSnaps,
3887
- containerRect
3888
- } = emblaApi.internalEngine();
3889
- const opacity = opacities[index];
3890
- slidesInSnap.forEach(slideIndex => {
3891
- const slideStyle = emblaApi.slideNodes()[slideIndex].style;
3892
- const roundedOpacity = parseFloat(opacity.toFixed(2));
3893
- const hasOpacity = roundedOpacity > noOpacity;
3894
- const position = hasOpacity ? scrollSnaps[index] : containerRect.width + 2;
3895
- const transform = getSlideTransform(position);
3896
- if (hasOpacity) slideStyle.transform = transform;
3897
- slideStyle.opacity = roundedOpacity.toString();
3898
- slideStyle.pointerEvents = opacity > 0.5 ? 'auto' : 'none';
3899
- if (!hasOpacity) slideStyle.transform = transform;
3900
- });
3901
- }
3902
- function setProgress(fadeIndex, opacity) {
3903
- const {
3904
- index,
3905
- dragHandler,
3906
- scrollSnaps
3907
- } = emblaApi.internalEngine();
3908
- const pointerDown = dragHandler.pointerDown();
3909
- const snapFraction = 1 / (scrollSnaps.length - 1);
3910
- let indexA = fadeIndex;
3911
- let indexB = pointerDown ? emblaApi.selectedScrollSnap() : emblaApi.previousScrollSnap();
3912
- if (pointerDown && indexA === indexB) {
3913
- const reverseSign = Math.sign(distanceFromPointerDown) * -1;
3914
- indexA = indexB;
3915
- indexB = index.clone().set(indexB).add(reverseSign).get();
3916
- }
3917
- const currentPosition = indexB * snapFraction;
3918
- const diffPosition = (indexA - indexB) * snapFraction;
3919
- progress = currentPosition + diffPosition * opacity;
3920
- }
3921
- function getFadeIndex() {
3922
- const {
3923
- dragHandler,
3924
- index,
3925
- scrollBody
3926
- } = emblaApi.internalEngine();
3927
- const selectedSnap = emblaApi.selectedScrollSnap();
3928
- if (!dragHandler.pointerDown()) return selectedSnap;
3929
- const directionSign = Math.sign(scrollBody.velocity());
3930
- const distanceSign = Math.sign(distanceFromPointerDown);
3931
- const nextSnap = index.clone().set(selectedSnap).add(directionSign * -1).get();
3932
- if (!directionSign || !distanceSign) return null;
3933
- return distanceSign === directionSign ? nextSnap : selectedSnap;
3934
- }
3935
- function fade(emblaApi) {
3936
- const {
3937
- dragHandler,
3938
- scrollBody
3939
- } = emblaApi.internalEngine();
3940
- const pointerDown = dragHandler.pointerDown();
3941
- const velocity = scrollBody.velocity();
3942
- const duration = scrollBody.duration();
3943
- const fadeIndex = getFadeIndex();
3944
- const noFadeIndex = !isNumber(fadeIndex);
3945
- if (pointerDown) {
3946
- if (!velocity) return;
3947
- distanceFromPointerDown += velocity;
3948
- fadeVelocity = Math.abs(velocity / fadeToNextDistance);
3949
- lockExcessiveScroll(fadeIndex);
3950
- }
3951
- if (!pointerDown) {
3952
- if (!duration || noFadeIndex) return;
3953
- fadeVelocity += (fullOpacity - opacities[fadeIndex]) / duration;
3954
- fadeVelocity *= fadeFriction;
3955
- }
3956
- if (noFadeIndex) return;
3957
- setOpacities(fadeIndex, fadeVelocity);
3958
- }
3959
- function settled() {
3960
- const {
3961
- target,
3962
- location
3963
- } = emblaApi.internalEngine();
3964
- const diffToTarget = target.get() - location.get();
3965
- const notReachedTarget = Math.abs(diffToTarget) >= 1;
3966
- const fadeIndex = getFadeIndex();
3967
- const noFadeIndex = !isNumber(fadeIndex);
3968
- fade(emblaApi);
3969
- if (noFadeIndex || notReachedTarget) return false;
3970
- return opacities[fadeIndex] > 0.999;
3971
- }
3972
- function scrollProgress() {
3973
- return progress;
3974
- }
3975
- const self = {
3976
- name: 'fade',
3977
- options: userOptions,
3978
- init,
3979
- destroy
3980
- };
3981
- return self;
3982
- }
3983
- Fade.globalOptions = undefined;
3984
-
3985
4213
  var LsgHeroController = /** @class */function () {
3986
4214
  function LsgHeroController(viewport, elements, options) {
3987
4215
  if (elements === void 0) {