@tedi-design-system/angular 8.2.0-rc.4 → 8.2.0-rc.6
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, signal, inject, ElementRef, Directive, booleanAttribute, output, ViewContainerRef, Renderer2, effect, HostListener, Injectable, InjectionToken, model, isDevMode, forwardRef, contentChild, DestroyRef, afterRenderEffect, contentChildren, PLATFORM_ID, REQUEST, isSignal, Pipe, Injector, HostAttributeToken, viewChild, NgZone, viewChildren, afterNextRender, Optional, SkipSelf, linkedSignal, untracked, ViewChild, TemplateRef, numberAttribute, HostBinding, runInInjectionContext, ContentChildren, RendererStyleFlags2, ContentChild, makeEnvironmentProviders } from '@angular/core';
|
|
2
|
+
import { input, computed, ViewEncapsulation, ChangeDetectionStrategy, Component, signal, inject, ElementRef, Directive, booleanAttribute, output, ViewContainerRef, Renderer2, effect, HostListener, Injectable, InjectionToken, model, isDevMode, forwardRef, contentChild, DestroyRef, afterRenderEffect, contentChildren, PLATFORM_ID, REQUEST, isSignal, Pipe, Injector, HostAttributeToken, viewChild, NgZone, viewChildren, afterNextRender, ErrorHandler, Optional, SkipSelf, linkedSignal, untracked, ViewChild, TemplateRef, numberAttribute, HostBinding, runInInjectionContext, ContentChildren, RendererStyleFlags2, ContentChild, makeEnvironmentProviders } from '@angular/core';
|
|
3
3
|
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
4
4
|
import * as i1 from '@angular/cdk/overlay';
|
|
5
5
|
import { CdkOverlayOrigin, OverlayContainer, OverlayModule, Overlay, OverlayConfig, CdkConnectedOverlay } from '@angular/cdk/overlay';
|
|
@@ -11,6 +11,7 @@ import * as i2 from '@angular/cdk/a11y';
|
|
|
11
11
|
import { _IdGenerator, CdkTrapFocus, A11yModule, LiveAnnouncer, ActiveDescendantKeyManager } from '@angular/cdk/a11y';
|
|
12
12
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
13
13
|
import { Dialog } from '@angular/cdk/dialog';
|
|
14
|
+
import { isObservable, firstValueFrom } from 'rxjs';
|
|
14
15
|
import * as i1$2 from '@angular/cdk/scrolling';
|
|
15
16
|
import { CdkScrollable, CdkVirtualScrollViewport, ScrollingModule } from '@angular/cdk/scrolling';
|
|
16
17
|
import * as i3 from '@angular/cdk/listbox';
|
|
@@ -8691,15 +8692,50 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
8691
8692
|
/**
|
|
8692
8693
|
* Reference to a modal opened via `ModalService`.
|
|
8693
8694
|
* Provides methods to close the modal and observe its lifecycle.
|
|
8695
|
+
* The opener and the content share the same instance.
|
|
8694
8696
|
*/
|
|
8695
8697
|
class ModalRef {
|
|
8696
8698
|
dialogRef;
|
|
8697
|
-
|
|
8699
|
+
errorHandler;
|
|
8700
|
+
/** Checked before every close, except `ModalService.closeAll()` and navigation. */
|
|
8701
|
+
canClose = null;
|
|
8702
|
+
pendingGuard = false;
|
|
8703
|
+
constructor(dialogRef, errorHandler = new ErrorHandler()) {
|
|
8698
8704
|
this.dialogRef = dialogRef;
|
|
8705
|
+
this.errorHandler = errorHandler;
|
|
8699
8706
|
}
|
|
8700
|
-
/** Close the modal, optionally returning a result. */
|
|
8707
|
+
/** Close the modal, optionally returning a result. Subject to `canClose`. */
|
|
8701
8708
|
close(result) {
|
|
8702
|
-
this.
|
|
8709
|
+
this.requestClose("programmatic", result);
|
|
8710
|
+
}
|
|
8711
|
+
/** @internal */
|
|
8712
|
+
requestClose(reason, result) {
|
|
8713
|
+
if (this.pendingGuard)
|
|
8714
|
+
return;
|
|
8715
|
+
let verdict;
|
|
8716
|
+
try {
|
|
8717
|
+
verdict = this.canClose ? this.canClose(result, reason) : true;
|
|
8718
|
+
}
|
|
8719
|
+
catch (error) {
|
|
8720
|
+
this.errorHandler.handleError(error);
|
|
8721
|
+
return;
|
|
8722
|
+
}
|
|
8723
|
+
if (typeof verdict === "boolean") {
|
|
8724
|
+
if (verdict)
|
|
8725
|
+
this.dialogRef.close(result);
|
|
8726
|
+
return;
|
|
8727
|
+
}
|
|
8728
|
+
this.pendingGuard = true;
|
|
8729
|
+
const decision = isObservable(verdict)
|
|
8730
|
+
? firstValueFrom(verdict, { defaultValue: false })
|
|
8731
|
+
: verdict;
|
|
8732
|
+
decision
|
|
8733
|
+
.then((allowed) => {
|
|
8734
|
+
if (allowed)
|
|
8735
|
+
this.dialogRef.close(result);
|
|
8736
|
+
})
|
|
8737
|
+
.catch((error) => this.errorHandler.handleError(error))
|
|
8738
|
+
.finally(() => (this.pendingGuard = false));
|
|
8703
8739
|
}
|
|
8704
8740
|
/** Observable that emits when the modal is closed, with the optional result value. */
|
|
8705
8741
|
get closed() {
|
|
@@ -8755,6 +8791,7 @@ class ModalService {
|
|
|
8755
8791
|
overlay = inject(Overlay);
|
|
8756
8792
|
injector = inject(Injector);
|
|
8757
8793
|
idGenerator = inject(_IdGenerator);
|
|
8794
|
+
errorHandler = inject(ErrorHandler);
|
|
8758
8795
|
/**
|
|
8759
8796
|
* Open a modal dialog with the given component as content.
|
|
8760
8797
|
*
|
|
@@ -8777,6 +8814,7 @@ class ModalService {
|
|
|
8777
8814
|
const { data, size = "default", width = "sm", position = "center", scrollBehavior = "content", closeOnBackdropClick = true, closeOnEscape = true, fullscreen = false, maxWidth, ariaLabel, ariaLabelledBy, } = config;
|
|
8778
8815
|
const panelClasses = this.buildPanelClasses(size, width, position, scrollBehavior, fullscreen);
|
|
8779
8816
|
const isPresetWidth = WIDTH_PRESETS.includes(width);
|
|
8817
|
+
let modalRef;
|
|
8780
8818
|
const dialogRef = this.dialog.open(component, {
|
|
8781
8819
|
data,
|
|
8782
8820
|
panelClass: panelClasses,
|
|
@@ -8791,7 +8829,10 @@ class ModalService {
|
|
|
8791
8829
|
positionStrategy: this.buildPositionStrategy(position, scrollBehavior),
|
|
8792
8830
|
scrollStrategy: this.overlay.scrollStrategies.block(),
|
|
8793
8831
|
providers: (ref) => [
|
|
8794
|
-
{
|
|
8832
|
+
{
|
|
8833
|
+
provide: ModalRef,
|
|
8834
|
+
useValue: (modalRef = new ModalRef(ref, this.errorHandler)),
|
|
8835
|
+
},
|
|
8795
8836
|
{ provide: MODAL_DATA, useValue: data },
|
|
8796
8837
|
{ provide: MODAL_SIZE, useValue: signal(size) },
|
|
8797
8838
|
],
|
|
@@ -8802,13 +8843,13 @@ class ModalService {
|
|
|
8802
8843
|
if (maxWidth) {
|
|
8803
8844
|
dialogRef.overlayRef.overlayElement.style.setProperty("--_tedi-modal-max-width", maxWidth);
|
|
8804
8845
|
}
|
|
8805
|
-
this.setupDialogBehavior(dialogRef, scrollBehavior, closeOnBackdropClick, closeOnEscape);
|
|
8846
|
+
this.setupDialogBehavior(dialogRef, modalRef, scrollBehavior, closeOnBackdropClick, closeOnEscape);
|
|
8806
8847
|
if (!ariaLabel && !ariaLabelledBy) {
|
|
8807
8848
|
this.labelFromHeading(dialogRef);
|
|
8808
8849
|
}
|
|
8809
|
-
return
|
|
8850
|
+
return modalRef;
|
|
8810
8851
|
}
|
|
8811
|
-
/** Close all open modals
|
|
8852
|
+
/** Close all open modals, ignoring `canClose`. */
|
|
8812
8853
|
closeAll() {
|
|
8813
8854
|
this.dialog.closeAll();
|
|
8814
8855
|
}
|
|
@@ -8824,7 +8865,8 @@ class ModalService {
|
|
|
8824
8865
|
labelFromHeading(dialogRef) {
|
|
8825
8866
|
afterNextRender(() => {
|
|
8826
8867
|
// The container, not the pane, is what carries role="dialog".
|
|
8827
|
-
|
|
8868
|
+
// The pane is null if the modal closed before rendering.
|
|
8869
|
+
const container = dialogRef.overlayRef.overlayElement?.querySelector("cdk-dialog-container");
|
|
8828
8870
|
if (!container)
|
|
8829
8871
|
return;
|
|
8830
8872
|
const headingId = resolveModalHeadingId(container, this.idGenerator);
|
|
@@ -8855,19 +8897,19 @@ class ModalService {
|
|
|
8855
8897
|
}
|
|
8856
8898
|
return classes;
|
|
8857
8899
|
}
|
|
8858
|
-
setupDialogBehavior(dialogRef, scrollBehavior, closeOnBackdropClick, closeOnEscape) {
|
|
8900
|
+
setupDialogBehavior(dialogRef, modalRef, scrollBehavior, closeOnBackdropClick, closeOnEscape) {
|
|
8859
8901
|
if (scrollBehavior === "page") {
|
|
8860
8902
|
const host = dialogRef.overlayRef.hostElement;
|
|
8861
8903
|
host.style.overflow = "auto";
|
|
8862
8904
|
host.style.paddingBlock = "var(--layout-grid-gutters-16)";
|
|
8863
8905
|
}
|
|
8864
8906
|
if (closeOnBackdropClick) {
|
|
8865
|
-
dialogRef.backdropClick.subscribe(() =>
|
|
8907
|
+
dialogRef.backdropClick.subscribe(() => modalRef.requestClose("backdrop"));
|
|
8866
8908
|
}
|
|
8867
8909
|
if (closeOnEscape) {
|
|
8868
8910
|
dialogRef.keydownEvents.subscribe((event) => {
|
|
8869
8911
|
if (event.key === "Escape") {
|
|
8870
|
-
|
|
8912
|
+
modalRef.requestClose("escape");
|
|
8871
8913
|
}
|
|
8872
8914
|
});
|
|
8873
8915
|
}
|
|
@@ -9123,7 +9165,7 @@ class ModalHeaderComponent {
|
|
|
9123
9165
|
}, ...(ngDevMode ? [{ debugName: "effectiveCloseButtonSize" }] : []));
|
|
9124
9166
|
closeModal() {
|
|
9125
9167
|
if (this.modalRef) {
|
|
9126
|
-
this.modalRef.close
|
|
9168
|
+
this.modalRef.requestClose("close-button");
|
|
9127
9169
|
}
|
|
9128
9170
|
else if (this.modal) {
|
|
9129
9171
|
this.modal.open.set(false);
|
|
@@ -15612,6 +15654,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
15612
15654
|
}]
|
|
15613
15655
|
}] });
|
|
15614
15656
|
|
|
15657
|
+
/** Ignore tiny calculation differences when deciding the carousel’s position. */
|
|
15658
|
+
const EPSILON = 0.001;
|
|
15615
15659
|
class CarouselContentComponent {
|
|
15616
15660
|
/** Slides per view (minimum 1, can be fractional, e.g. 1.25 for peeking) */
|
|
15617
15661
|
slidesPerView = input({ xs: 1 }, ...(ngDevMode ? [{ debugName: "slidesPerView", transform: (v) => breakpointInput(v) }] : [{ transform: (v) => breakpointInput(v) }]));
|
|
@@ -15621,6 +15665,12 @@ class CarouselContentComponent {
|
|
|
15621
15665
|
fade = input(false, ...(ngDevMode ? [{ debugName: "fade" }] : []));
|
|
15622
15666
|
/** Transition duration in ms */
|
|
15623
15667
|
transitionMs = input(400, ...(ngDevMode ? [{ debugName: "transitionMs" }] : []));
|
|
15668
|
+
/**
|
|
15669
|
+
* Whether navigation wraps around at the ends. When `false`, it stops at the
|
|
15670
|
+
* first and last reachable positions and disables the corresponding arrow.
|
|
15671
|
+
* @default true
|
|
15672
|
+
*/
|
|
15673
|
+
loop = input(true, ...(ngDevMode ? [{ debugName: "loop", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
15624
15674
|
/** Accessible label for the carousel region. Falls back to the `carousel` translation. */
|
|
15625
15675
|
ariaLabel = input(...(ngDevMode ? [undefined, { debugName: "ariaLabel" }] : []));
|
|
15626
15676
|
translationService = inject(TediTranslationService);
|
|
@@ -15684,18 +15734,46 @@ class CarouselContentComponent {
|
|
|
15684
15734
|
return this.gap().xs;
|
|
15685
15735
|
}
|
|
15686
15736
|
}, ...(ngDevMode ? [{ debugName: "currentGap" }] : []));
|
|
15687
|
-
buffer = computed(() => this.slides().length, ...(ngDevMode ? [{ debugName: "buffer" }] : []));
|
|
15737
|
+
buffer = computed(() => (this.loop() ? this.slides().length : 0), ...(ngDevMode ? [{ debugName: "buffer" }] : []));
|
|
15738
|
+
/** Furthest track position in bounded mode; may be fractional to show the last slide fully. */
|
|
15739
|
+
maxIndex = computed(() => Math.max(0, this.slides().length - this.currentSlidesPerView()), ...(ngDevMode ? [{ debugName: "maxIndex" }] : []));
|
|
15740
|
+
/** Number of indicator positions: one per slide when looping, or one per reachable stop when bounded. */
|
|
15741
|
+
positionCount = computed(() => {
|
|
15742
|
+
if (this.loop() || !this.slides().length) {
|
|
15743
|
+
return this.slides().length;
|
|
15744
|
+
}
|
|
15745
|
+
return Math.ceil(this.maxIndex() - EPSILON) + 1;
|
|
15746
|
+
}, ...(ngDevMode ? [{ debugName: "positionCount" }] : []));
|
|
15747
|
+
/** Index of the active indicator; a fractional final stop gets its own index. */
|
|
15748
|
+
activePosition = computed(() => {
|
|
15749
|
+
if (this.loop()) {
|
|
15750
|
+
return this.slideIndex();
|
|
15751
|
+
}
|
|
15752
|
+
const nearest = this.snap(this.trackIndex());
|
|
15753
|
+
return nearest >= this.maxIndex() - EPSILON
|
|
15754
|
+
? this.positionCount() - 1
|
|
15755
|
+
: Math.round(nearest);
|
|
15756
|
+
}, ...(ngDevMode ? [{ debugName: "activePosition" }] : []));
|
|
15757
|
+
/** Index of the leftmost visible slide, skipping a partially visible one in bounded mode. */
|
|
15688
15758
|
slideIndex = computed(() => {
|
|
15689
15759
|
const slidesCount = this.slides().length;
|
|
15690
15760
|
if (slidesCount === 0) {
|
|
15691
15761
|
return 0;
|
|
15692
15762
|
}
|
|
15763
|
+
if (!this.loop()) {
|
|
15764
|
+
return Math.min(Math.max(Math.ceil(this.trackIndex() - EPSILON), 0), slidesCount - 1);
|
|
15765
|
+
}
|
|
15693
15766
|
const i = Math.floor(this.trackIndex());
|
|
15694
15767
|
return ((i % slidesCount) + slidesCount) % slidesCount;
|
|
15695
15768
|
}, ...(ngDevMode ? [{ debugName: "slideIndex" }] : []));
|
|
15696
15769
|
renderedActiveIndex = computed(() => {
|
|
15770
|
+
if (!this.loop()) {
|
|
15771
|
+
return this.trackIndex();
|
|
15772
|
+
}
|
|
15697
15773
|
return this.trackIndex() - this.windowBase() + this.buffer();
|
|
15698
15774
|
}, ...(ngDevMode ? [{ debugName: "renderedActiveIndex" }] : []));
|
|
15775
|
+
canPrev = computed(() => this.loop() || this.trackIndex() > EPSILON, ...(ngDevMode ? [{ debugName: "canPrev" }] : []));
|
|
15776
|
+
canNext = computed(() => this.loop() || this.trackIndex() < this.maxIndex() - EPSILON, ...(ngDevMode ? [{ debugName: "canNext" }] : []));
|
|
15699
15777
|
/**
|
|
15700
15778
|
* Checks if a slide at the given rendered index is currently visible in the viewport.
|
|
15701
15779
|
* Used to determine which slides should be accessible to screen readers.
|
|
@@ -15711,6 +15789,9 @@ class CarouselContentComponent {
|
|
|
15711
15789
|
if (!slidesCount) {
|
|
15712
15790
|
return [];
|
|
15713
15791
|
}
|
|
15792
|
+
if (!this.loop()) {
|
|
15793
|
+
return Array.from({ length: slidesCount }, (_, i) => i);
|
|
15794
|
+
}
|
|
15714
15795
|
const total = 2 * this.buffer() + Math.ceil(this.currentSlidesPerView());
|
|
15715
15796
|
const start = this.windowBase() - this.buffer();
|
|
15716
15797
|
return Array.from({ length: total }, (_, i) => (((start + i) % slidesCount) + slidesCount) % slidesCount);
|
|
@@ -15743,7 +15824,7 @@ class CarouselContentComponent {
|
|
|
15743
15824
|
}
|
|
15744
15825
|
const totalGapWidth = gap * (slidesPerView - 1);
|
|
15745
15826
|
const slideWidth = (viewportWidth - totalGapWidth) / slidesPerView;
|
|
15746
|
-
const offsetSlides = this.
|
|
15827
|
+
const offsetSlides = this.renderedActiveIndex();
|
|
15747
15828
|
const translateX = -offsetSlides * (slideWidth + gap);
|
|
15748
15829
|
return {
|
|
15749
15830
|
gap: `${gap}px`,
|
|
@@ -15753,6 +15834,16 @@ class CarouselContentComponent {
|
|
|
15753
15834
|
: "none",
|
|
15754
15835
|
};
|
|
15755
15836
|
}, ...(ngDevMode ? [{ debugName: "trackStyle" }] : []));
|
|
15837
|
+
constructor() {
|
|
15838
|
+
// Re-clamp without animation when bounded mode starts or its limit changes.
|
|
15839
|
+
// Don't track the current position: normal navigation must not rerun this effect.
|
|
15840
|
+
effect(() => {
|
|
15841
|
+
if (!this.loop()) {
|
|
15842
|
+
const max = this.maxIndex();
|
|
15843
|
+
untracked(() => this.clampIntoRange(max));
|
|
15844
|
+
}
|
|
15845
|
+
});
|
|
15846
|
+
}
|
|
15756
15847
|
locked = false;
|
|
15757
15848
|
dragging = false;
|
|
15758
15849
|
pendingFocus = false;
|
|
@@ -15789,9 +15880,7 @@ class CarouselContentComponent {
|
|
|
15789
15880
|
}
|
|
15790
15881
|
const deltaSlides = delta / cellWidth;
|
|
15791
15882
|
this.scrollDelta += deltaSlides;
|
|
15792
|
-
const
|
|
15793
|
-
const min = this.windowBase() - maxDelta;
|
|
15794
|
-
const max = this.windowBase() + maxDelta;
|
|
15883
|
+
const { min, max } = this.dragBounds(this.windowBase());
|
|
15795
15884
|
const unclamped = this.trackIndex() + deltaSlides;
|
|
15796
15885
|
const clamped = Math.min(Math.max(unclamped, min), max);
|
|
15797
15886
|
const wasClamped = clamped !== unclamped;
|
|
@@ -15800,17 +15889,20 @@ class CarouselContentComponent {
|
|
|
15800
15889
|
clearTimeout(this.wheelTimeout);
|
|
15801
15890
|
this.wheelTimeout = setTimeout(() => {
|
|
15802
15891
|
this.animate.set(true);
|
|
15892
|
+
// Recalculate bounds: the viewport or slide count may have changed before snapping.
|
|
15893
|
+
const { min, max } = this.dragBounds(this.windowBase());
|
|
15803
15894
|
const direction = Math.sign(this.scrollDelta);
|
|
15804
15895
|
const current = this.trackIndex();
|
|
15805
|
-
let snapIndex =
|
|
15896
|
+
let snapIndex = this.snap(current);
|
|
15806
15897
|
if (Math.abs(this.scrollDelta) > 0.3) {
|
|
15807
15898
|
snapIndex = direction > 0 ? Math.ceil(current) : Math.floor(current);
|
|
15808
15899
|
}
|
|
15900
|
+
// If scrolling hit a limit, snap inward when looping or to the exact bound otherwise.
|
|
15809
15901
|
if (wasClamped) {
|
|
15810
15902
|
if (current <= min)
|
|
15811
|
-
snapIndex = Math.ceil(min);
|
|
15903
|
+
snapIndex = this.loop() ? Math.ceil(min) : min;
|
|
15812
15904
|
if (current >= max)
|
|
15813
|
-
snapIndex = Math.floor(max);
|
|
15905
|
+
snapIndex = this.loop() ? Math.floor(max) : max;
|
|
15814
15906
|
}
|
|
15815
15907
|
const finalIndex = Math.min(Math.max(snapIndex, min), max);
|
|
15816
15908
|
this.trackIndex.set(finalIndex);
|
|
@@ -15851,7 +15943,9 @@ class CarouselContentComponent {
|
|
|
15851
15943
|
this.animate.set(false);
|
|
15852
15944
|
this.startX = ev.clientX;
|
|
15853
15945
|
this.startIndex = this.trackIndex();
|
|
15854
|
-
this.
|
|
15946
|
+
if (this.loop()) {
|
|
15947
|
+
this.windowBase.set(Math.floor(this.startIndex));
|
|
15948
|
+
}
|
|
15855
15949
|
}
|
|
15856
15950
|
onPointerMove(ev) {
|
|
15857
15951
|
if (!this.dragging) {
|
|
@@ -15867,9 +15961,7 @@ class CarouselContentComponent {
|
|
|
15867
15961
|
}
|
|
15868
15962
|
const deltaSlides = dx / cellWidth;
|
|
15869
15963
|
const targetIndex = this.startIndex - deltaSlides;
|
|
15870
|
-
const
|
|
15871
|
-
const min = this.windowBase() - maxDelta;
|
|
15872
|
-
const max = this.windowBase() + maxDelta;
|
|
15964
|
+
const { min, max } = this.dragBounds(Math.floor(this.startIndex));
|
|
15873
15965
|
const clamped = Math.min(Math.max(targetIndex, min), max);
|
|
15874
15966
|
this.trackIndex.set(clamped);
|
|
15875
15967
|
}
|
|
@@ -15879,13 +15971,14 @@ class CarouselContentComponent {
|
|
|
15879
15971
|
}
|
|
15880
15972
|
this.dragging = false;
|
|
15881
15973
|
this.animate.set(true);
|
|
15882
|
-
this.trackIndex.set(
|
|
15974
|
+
this.trackIndex.set(this.snap(this.trackIndex()));
|
|
15883
15975
|
}
|
|
15884
15976
|
ngAfterViewInit() {
|
|
15885
15977
|
const viewport = this.host.nativeElement;
|
|
15886
15978
|
this.viewportWidth.set(viewport.clientWidth);
|
|
15887
|
-
|
|
15888
|
-
|
|
15979
|
+
// Use the fractional width to keep track translation aligned with CSS-sized slides.
|
|
15980
|
+
this.ro = new ResizeObserver(([entry]) => {
|
|
15981
|
+
this.viewportWidth.set(entry.contentRect.width);
|
|
15889
15982
|
});
|
|
15890
15983
|
this.ro.observe(viewport);
|
|
15891
15984
|
}
|
|
@@ -15893,20 +15986,21 @@ class CarouselContentComponent {
|
|
|
15893
15986
|
this.ro?.disconnect();
|
|
15894
15987
|
}
|
|
15895
15988
|
next() {
|
|
15896
|
-
if (!this.slides().length || this.locked) {
|
|
15989
|
+
if (!this.slides().length || this.locked || !this.canNext()) {
|
|
15897
15990
|
return;
|
|
15898
15991
|
}
|
|
15899
15992
|
this.animate.set(true);
|
|
15900
|
-
|
|
15993
|
+
// Move to the next whole position, clamping to a fractional final position.
|
|
15994
|
+
this.trackIndex.update((i) => this.clampIndex(Math.floor(i + EPSILON) + 1));
|
|
15901
15995
|
this.lockNavigation();
|
|
15902
15996
|
this.announceSlideChange();
|
|
15903
15997
|
}
|
|
15904
15998
|
prev() {
|
|
15905
|
-
if (!this.slides().length || this.locked) {
|
|
15999
|
+
if (!this.slides().length || this.locked || !this.canPrev()) {
|
|
15906
16000
|
return;
|
|
15907
16001
|
}
|
|
15908
16002
|
this.animate.set(true);
|
|
15909
|
-
this.trackIndex.update((i) => i - 1);
|
|
16003
|
+
this.trackIndex.update((i) => this.clampIndex(Math.ceil(i - EPSILON) - 1));
|
|
15910
16004
|
this.lockNavigation();
|
|
15911
16005
|
this.announceSlideChange();
|
|
15912
16006
|
}
|
|
@@ -15915,11 +16009,16 @@ class CarouselContentComponent {
|
|
|
15915
16009
|
if (!slidesCount || this.locked) {
|
|
15916
16010
|
return;
|
|
15917
16011
|
}
|
|
15918
|
-
const current = this.slideIndex();
|
|
15919
|
-
const normalized = ((index % slidesCount) + slidesCount) % slidesCount;
|
|
15920
|
-
const delta = normalized - current;
|
|
15921
16012
|
this.animate.set(true);
|
|
15922
|
-
this.
|
|
16013
|
+
if (this.loop()) {
|
|
16014
|
+
const current = this.slideIndex();
|
|
16015
|
+
const normalized = ((index % slidesCount) + slidesCount) % slidesCount;
|
|
16016
|
+
const delta = normalized - current;
|
|
16017
|
+
this.trackIndex.update((i) => i + delta);
|
|
16018
|
+
}
|
|
16019
|
+
else {
|
|
16020
|
+
this.trackIndex.set(this.clampIndex(index));
|
|
16021
|
+
}
|
|
15923
16022
|
if (options?.focusSlide) {
|
|
15924
16023
|
// Focus after transition completes so DOM positions are stable
|
|
15925
16024
|
this.pendingFocus = true;
|
|
@@ -15934,7 +16033,8 @@ class CarouselContentComponent {
|
|
|
15934
16033
|
*/
|
|
15935
16034
|
focusActiveSlide() {
|
|
15936
16035
|
setTimeout(() => {
|
|
15937
|
-
|
|
16036
|
+
// A bounded track can rest at a fractional index; focus the first fully visible slide.
|
|
16037
|
+
const activeIndex = Math.ceil(this.renderedActiveIndex() - EPSILON);
|
|
15938
16038
|
const slideElement = this.slideElements()[activeIndex];
|
|
15939
16039
|
if (slideElement) {
|
|
15940
16040
|
slideElement.nativeElement.focus({ preventScroll: true });
|
|
@@ -15954,14 +16054,42 @@ class CarouselContentComponent {
|
|
|
15954
16054
|
this.focusActiveSlide();
|
|
15955
16055
|
}
|
|
15956
16056
|
}
|
|
16057
|
+
clampIntoRange(max) {
|
|
16058
|
+
const current = this.trackIndex();
|
|
16059
|
+
const clamped = Math.min(Math.max(current, 0), max);
|
|
16060
|
+
if (clamped !== current) {
|
|
16061
|
+
this.animate.set(false);
|
|
16062
|
+
this.trackIndex.set(clamped);
|
|
16063
|
+
this.windowBase.set(Math.floor(clamped));
|
|
16064
|
+
}
|
|
16065
|
+
}
|
|
16066
|
+
clampIndex(value) {
|
|
16067
|
+
return this.loop() ? value : Math.min(Math.max(value, 0), this.maxIndex());
|
|
16068
|
+
}
|
|
16069
|
+
/** Snap to the nearest reachable position, including a fractional end. */
|
|
16070
|
+
snap(value) {
|
|
16071
|
+
if (this.loop()) {
|
|
16072
|
+
return Math.round(value);
|
|
16073
|
+
}
|
|
16074
|
+
const below = this.clampIndex(Math.floor(value));
|
|
16075
|
+
const above = this.clampIndex(Math.ceil(value));
|
|
16076
|
+
return value - below <= above - value ? below : above;
|
|
16077
|
+
}
|
|
16078
|
+
/**
|
|
16079
|
+
* Range the track may be dragged or wheeled within. A looping track stays inside
|
|
16080
|
+
* its rendered duplicate buffer around `base`; a bounded one stops at the ends.
|
|
16081
|
+
*/
|
|
16082
|
+
dragBounds(base) {
|
|
16083
|
+
if (!this.loop()) {
|
|
16084
|
+
return { min: 0, max: this.maxIndex() };
|
|
16085
|
+
}
|
|
16086
|
+
const maxDelta = this.buffer() * 0.9;
|
|
16087
|
+
return { min: base - maxDelta, max: base + maxDelta };
|
|
16088
|
+
}
|
|
15957
16089
|
lockNavigation() {
|
|
15958
16090
|
this.locked = true;
|
|
15959
16091
|
setTimeout(() => (this.locked = false), this.transitionMs());
|
|
15960
16092
|
}
|
|
15961
|
-
/**
|
|
15962
|
-
* Announces the current slide position to screen readers via LiveAnnouncer.
|
|
15963
|
-
* Called after navigation to inform users of the slide change.
|
|
15964
|
-
*/
|
|
15965
16093
|
announceSlideChange() {
|
|
15966
16094
|
setTimeout(() => {
|
|
15967
16095
|
const slideNumber = this.slideIndex() + 1;
|
|
@@ -15971,7 +16099,7 @@ class CarouselContentComponent {
|
|
|
15971
16099
|
}, 100);
|
|
15972
16100
|
}
|
|
15973
16101
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
15974
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: CarouselContentComponent, isStandalone: true, selector: "tedi-carousel-content", inputs: { slidesPerView: { classPropertyName: "slidesPerView", publicName: "slidesPerView", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, fade: { classPropertyName: "fade", publicName: "fade", isSignal: true, isRequired: false, transformFunction: null }, transitionMs: { classPropertyName: "transitionMs", publicName: "transitionMs", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "tabindex": "0", "role": "region", "aria-roledescription": "carousel", "aria-live": "off" }, listeners: { "scroll": "onScroll()", "wheel": "onWheel($event)", "keydown": "onKeyDown($event)", "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp()", "pointercancel": "onPointerUp()", "lostpointercapture": "onPointerUp()" }, properties: { "attr.aria-label": "resolvedAriaLabel()", "class": "classes()" } }, queries: [{ propertyName: "slides", predicate: CarouselSlideDirective, isSignal: true }], viewQueries: [{ propertyName: "track", first: true, predicate: ["track"], descendants: true, isSignal: true }, { propertyName: "slideElements", predicate: ["slide"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #track\n class=\"tedi-carousel__track\"\n [style]=\"trackStyle()\"\n (transitionend)=\"onTransitionEnd($event)\"\n>\n @for (idx of renderedIndices(); track $index) {\n <div\n #slide\n class=\"tedi-carousel__slide\"\n [attr.role]=\"isSlideVisible($index) ? 'group' : 'presentation'\"\n aria-roledescription=\"slide\"\n [attr.aria-label]=\"\n translationService.track('carousel.slide', idx + 1, slides().length)()\n \"\n [attr.aria-current]=\"$index === renderedActiveIndex() ? 'true' : null\"\n [attr.aria-hidden]=\"isSlideVisible($index) ? null : 'true'\"\n [attr.tabindex]=\"isSlideVisible($index) ? '-1' : null\"\n [style.flex]=\"slideFlex()\"\n >\n <ng-container *ngTemplateOutlet=\"slides()[idx].template\"></ng-container>\n </div>\n }\n</div>\n", styles: [".tedi-carousel__content{position:relative;width:100%;overflow:hidden;overscroll-behavior:contain;touch-action:pan-y;cursor:grab}.tedi-carousel__content:focus-visible{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:calc(-1 * var(--tedi-borders-03))}.tedi-carousel__content:active{cursor:grabbing}.tedi-carousel__content--fade-right{-webkit-mask-image:linear-gradient(to right,black 90%,transparent 100%);mask-image:linear-gradient(to right,black 90%,transparent 100%)}.tedi-carousel__content--fade-x{-webkit-mask-image:linear-gradient(to right,black 85%,transparent 100%),linear-gradient(to left,black 85%,transparent 100%);mask-image:linear-gradient(to right,black 85%,transparent 100%),linear-gradient(to left,black 85%,transparent 100%);-webkit-mask-composite:source-in;mask-composite:intersect}.tedi-carousel__track{display:flex;will-change:transform}.tedi-carousel__slide{-webkit-user-select:none;user-select:none;scroll-snap-align:none;scroll-margin:0;-webkit-user-drag:none}.tedi-carousel__slide:focus{outline:none}.tedi-carousel__slide:focus-visible{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:calc(-1 * var(--tedi-borders-03))}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
16102
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: CarouselContentComponent, isStandalone: true, selector: "tedi-carousel-content", inputs: { slidesPerView: { classPropertyName: "slidesPerView", publicName: "slidesPerView", isSignal: true, isRequired: false, transformFunction: null }, gap: { classPropertyName: "gap", publicName: "gap", isSignal: true, isRequired: false, transformFunction: null }, fade: { classPropertyName: "fade", publicName: "fade", isSignal: true, isRequired: false, transformFunction: null }, transitionMs: { classPropertyName: "transitionMs", publicName: "transitionMs", isSignal: true, isRequired: false, transformFunction: null }, loop: { classPropertyName: "loop", publicName: "loop", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "tabindex": "0", "role": "region", "aria-roledescription": "carousel", "aria-live": "off" }, listeners: { "scroll": "onScroll()", "wheel": "onWheel($event)", "keydown": "onKeyDown($event)", "pointerdown": "onPointerDown($event)", "pointermove": "onPointerMove($event)", "pointerup": "onPointerUp()", "pointercancel": "onPointerUp()", "lostpointercapture": "onPointerUp()" }, properties: { "attr.aria-label": "resolvedAriaLabel()", "class": "classes()" } }, queries: [{ propertyName: "slides", predicate: CarouselSlideDirective, isSignal: true }], viewQueries: [{ propertyName: "track", first: true, predicate: ["track"], descendants: true, isSignal: true }, { propertyName: "slideElements", predicate: ["slide"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #track\n class=\"tedi-carousel__track\"\n [style]=\"trackStyle()\"\n (transitionend)=\"onTransitionEnd($event)\"\n>\n @for (idx of renderedIndices(); track $index) {\n <div\n #slide\n class=\"tedi-carousel__slide\"\n [attr.role]=\"isSlideVisible($index) ? 'group' : 'presentation'\"\n aria-roledescription=\"slide\"\n [attr.aria-label]=\"\n translationService.track('carousel.slide', idx + 1, slides().length)()\n \"\n [attr.aria-current]=\"$index === renderedActiveIndex() ? 'true' : null\"\n [attr.aria-hidden]=\"isSlideVisible($index) ? null : 'true'\"\n [attr.tabindex]=\"isSlideVisible($index) ? '-1' : null\"\n [style.flex]=\"slideFlex()\"\n >\n <ng-container *ngTemplateOutlet=\"slides()[idx].template\"></ng-container>\n </div>\n }\n</div>\n", styles: [".tedi-carousel__content{position:relative;width:100%;overflow:hidden;overscroll-behavior:contain;touch-action:pan-y;cursor:grab}.tedi-carousel__content:focus-visible{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:calc(-1 * var(--tedi-borders-03))}.tedi-carousel__content:active{cursor:grabbing}.tedi-carousel__content--fade-right{-webkit-mask-image:linear-gradient(to right,black 90%,transparent 100%);mask-image:linear-gradient(to right,black 90%,transparent 100%)}.tedi-carousel__content--fade-x{-webkit-mask-image:linear-gradient(to right,black 85%,transparent 100%),linear-gradient(to left,black 85%,transparent 100%);mask-image:linear-gradient(to right,black 85%,transparent 100%),linear-gradient(to left,black 85%,transparent 100%);-webkit-mask-composite:source-in;mask-composite:intersect}.tedi-carousel__track{display:flex;will-change:transform}.tedi-carousel__slide{-webkit-user-select:none;user-select:none;scroll-snap-align:none;scroll-margin:0;-webkit-user-drag:none}.tedi-carousel__slide:focus{outline:none}.tedi-carousel__slide:focus-visible{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:calc(-1 * var(--tedi-borders-03))}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
15975
16103
|
}
|
|
15976
16104
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselContentComponent, decorators: [{
|
|
15977
16105
|
type: Component,
|
|
@@ -15983,7 +16111,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
15983
16111
|
"aria-live": "off",
|
|
15984
16112
|
"[class]": "classes()",
|
|
15985
16113
|
}, template: "<div\n #track\n class=\"tedi-carousel__track\"\n [style]=\"trackStyle()\"\n (transitionend)=\"onTransitionEnd($event)\"\n>\n @for (idx of renderedIndices(); track $index) {\n <div\n #slide\n class=\"tedi-carousel__slide\"\n [attr.role]=\"isSlideVisible($index) ? 'group' : 'presentation'\"\n aria-roledescription=\"slide\"\n [attr.aria-label]=\"\n translationService.track('carousel.slide', idx + 1, slides().length)()\n \"\n [attr.aria-current]=\"$index === renderedActiveIndex() ? 'true' : null\"\n [attr.aria-hidden]=\"isSlideVisible($index) ? null : 'true'\"\n [attr.tabindex]=\"isSlideVisible($index) ? '-1' : null\"\n [style.flex]=\"slideFlex()\"\n >\n <ng-container *ngTemplateOutlet=\"slides()[idx].template\"></ng-container>\n </div>\n }\n</div>\n", styles: [".tedi-carousel__content{position:relative;width:100%;overflow:hidden;overscroll-behavior:contain;touch-action:pan-y;cursor:grab}.tedi-carousel__content:focus-visible{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:calc(-1 * var(--tedi-borders-03))}.tedi-carousel__content:active{cursor:grabbing}.tedi-carousel__content--fade-right{-webkit-mask-image:linear-gradient(to right,black 90%,transparent 100%);mask-image:linear-gradient(to right,black 90%,transparent 100%)}.tedi-carousel__content--fade-x{-webkit-mask-image:linear-gradient(to right,black 85%,transparent 100%),linear-gradient(to left,black 85%,transparent 100%);mask-image:linear-gradient(to right,black 85%,transparent 100%),linear-gradient(to left,black 85%,transparent 100%);-webkit-mask-composite:source-in;mask-composite:intersect}.tedi-carousel__track{display:flex;will-change:transform}.tedi-carousel__slide{-webkit-user-select:none;user-select:none;scroll-snap-align:none;scroll-margin:0;-webkit-user-drag:none}.tedi-carousel__slide:focus{outline:none}.tedi-carousel__slide:focus-visible{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:calc(-1 * var(--tedi-borders-03))}\n"] }]
|
|
15986
|
-
}], propDecorators: { slidesPerView: [{ type: i0.Input, args: [{ isSignal: true, alias: "slidesPerView", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], fade: [{ type: i0.Input, args: [{ isSignal: true, alias: "fade", required: false }] }], transitionMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "transitionMs", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], track: [{ type: i0.ViewChild, args: ["track", { isSignal: true }] }], slideElements: [{ type: i0.ViewChildren, args: ["slide", { isSignal: true }] }], slides: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => CarouselSlideDirective), { isSignal: true }] }], onScroll: [{
|
|
16114
|
+
}], ctorParameters: () => [], propDecorators: { slidesPerView: [{ type: i0.Input, args: [{ isSignal: true, alias: "slidesPerView", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], fade: [{ type: i0.Input, args: [{ isSignal: true, alias: "fade", required: false }] }], transitionMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "transitionMs", required: false }] }], loop: [{ type: i0.Input, args: [{ isSignal: true, alias: "loop", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], track: [{ type: i0.ViewChild, args: ["track", { isSignal: true }] }], slideElements: [{ type: i0.ViewChildren, args: ["slide", { isSignal: true }] }], slides: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => CarouselSlideDirective), { isSignal: true }] }], onScroll: [{
|
|
15987
16115
|
type: HostListener,
|
|
15988
16116
|
args: ["scroll"]
|
|
15989
16117
|
}], onWheel: [{
|
|
@@ -16012,11 +16140,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImpo
|
|
|
16012
16140
|
class CarouselComponent {
|
|
16013
16141
|
carouselContent = contentChild.required(CarouselContentComponent);
|
|
16014
16142
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16015
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.24", type: CarouselComponent, isStandalone: true, selector: "tedi-carousel", queries: [{ propertyName: "carouselContent", first: true, predicate: CarouselContentComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-content select=\"tedi-carousel-header\" />\n<ng-content select=\"tedi-carousel-content\" />\n<ng-content select=\"tedi-carousel-footer\" />\n", styles: ["tedi-carousel{display:flex;flex-direction:column;gap:var(--layout-grid-gutters-08)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
16143
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.24", type: CarouselComponent, isStandalone: true, selector: "tedi-carousel", queries: [{ propertyName: "carouselContent", first: true, predicate: CarouselContentComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<ng-content select=\"tedi-carousel-header\" />\n<div class=\"tedi-carousel__body\">\n <ng-content select=\"tedi-carousel-content\" />\n <ng-content select=\"tedi-carousel-navigation\" />\n</div>\n<ng-content select=\"tedi-carousel-footer\" />\n", styles: ["tedi-carousel{display:flex;flex-direction:column;gap:var(--layout-grid-gutters-08)}.tedi-carousel__body{position:relative;display:flex;flex-direction:column}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
16016
16144
|
}
|
|
16017
16145
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselComponent, decorators: [{
|
|
16018
16146
|
type: Component,
|
|
16019
|
-
args: [{ standalone: true, selector: "tedi-carousel", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content select=\"tedi-carousel-header\" />\n<ng-content select=\"tedi-carousel-content\" />\n<ng-content select=\"tedi-carousel-footer\" />\n", styles: ["tedi-carousel{display:flex;flex-direction:column;gap:var(--layout-grid-gutters-08)}\n"] }]
|
|
16147
|
+
args: [{ standalone: true, selector: "tedi-carousel", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-content select=\"tedi-carousel-header\" />\n<div class=\"tedi-carousel__body\">\n <ng-content select=\"tedi-carousel-content\" />\n <ng-content select=\"tedi-carousel-navigation\" />\n</div>\n<ng-content select=\"tedi-carousel-footer\" />\n", styles: ["tedi-carousel{display:flex;flex-direction:column;gap:var(--layout-grid-gutters-08)}.tedi-carousel__body{position:relative;display:flex;flex-direction:column}\n"] }]
|
|
16020
16148
|
}], propDecorators: { carouselContent: [{ type: i0.ContentChild, args: [i0.forwardRef(() => CarouselContentComponent), { isSignal: true }] }] } });
|
|
16021
16149
|
|
|
16022
16150
|
class CarouselFooterComponent {
|
|
@@ -16044,11 +16172,11 @@ class CarouselIndicatorsComponent {
|
|
|
16044
16172
|
variant = input("dots", ...(ngDevMode ? [{ debugName: "variant" }] : []));
|
|
16045
16173
|
translationService = inject(TediTranslationService);
|
|
16046
16174
|
carousel = inject(CarouselComponent);
|
|
16047
|
-
indicatorsArray = computed(() => Array.from({ length: this.carousel.carouselContent().
|
|
16175
|
+
indicatorsArray = computed(() => Array.from({ length: this.carousel.carouselContent().positionCount() }, (_, i) => ({
|
|
16048
16176
|
index: i,
|
|
16049
|
-
active: this.carousel.carouselContent().
|
|
16177
|
+
active: this.carousel.carouselContent().activePosition() === i,
|
|
16050
16178
|
})), ...(ngDevMode ? [{ debugName: "indicatorsArray" }] : []));
|
|
16051
|
-
activeSlideNumber = computed(() => this.carousel.carouselContent().
|
|
16179
|
+
activeSlideNumber = computed(() => this.carousel.carouselContent().activePosition() + 1, ...(ngDevMode ? [{ debugName: "activeSlideNumber" }] : []));
|
|
16052
16180
|
handleNext() {
|
|
16053
16181
|
this.carousel.carouselContent().next();
|
|
16054
16182
|
}
|
|
@@ -16059,16 +16187,24 @@ class CarouselIndicatorsComponent {
|
|
|
16059
16187
|
this.carousel.carouselContent().goToIndex(index, { focusSlide: true });
|
|
16060
16188
|
}
|
|
16061
16189
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselIndicatorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16062
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: CarouselIndicatorsComponent, isStandalone: true, selector: "tedi-carousel-indicators", inputs: { withArrows: { classPropertyName: "withArrows", publicName: "withArrows", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (withArrows()) {\n <button\n tedi-button\n type=\"button\"\n variant=\"neutral\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n}\n\n@if (variant() === \"dots\") {\n @for (indicator of indicatorsArray(); track indicator.index) {\n <button\n type=\"button\"\n class=\"tedi-carousel__indicator\"\n [attr.aria-label]=\"\n translationService.track('carousel.showSlide', indicator.index + 1)()\n \"\n [ngClass]=\"indicator.active ? 'tedi-carousel__indicator--active' : null\"\n (click)=\"handleIndicatorClick(indicator.index)\"\n ></button>\n }\n} @else if (
|
|
16190
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: CarouselIndicatorsComponent, isStandalone: true, selector: "tedi-carousel-indicators", inputs: { withArrows: { classPropertyName: "withArrows", publicName: "withArrows", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (withArrows()) {\n <button\n tedi-button\n type=\"button\"\n variant=\"neutral\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n [disabled]=\"!carousel.carouselContent().canPrev()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n}\n\n@if (variant() === \"dots\") {\n @for (indicator of indicatorsArray(); track indicator.index) {\n <button\n type=\"button\"\n class=\"tedi-carousel__indicator\"\n [attr.aria-label]=\"\n translationService.track('carousel.showSlide', indicator.index + 1)()\n \"\n [ngClass]=\"indicator.active ? 'tedi-carousel__indicator--active' : null\"\n (click)=\"handleIndicatorClick(indicator.index)\"\n ></button>\n }\n} @else if (indicatorsArray().length) {\n <div>\n <b tedi-text color=\"brand\">{{ activeSlideNumber() }}</b>\n <span tedi-text color=\"tertiary\"> / {{ indicatorsArray().length }}</span>\n </div>\n}\n\n@if (withArrows()) {\n <button\n tedi-button\n type=\"button\"\n variant=\"neutral\"\n [attr.aria-label]=\"translationService.track('carousel.moveForward')()\"\n [disabled]=\"!carousel.carouselContent().canNext()\"\n (click)=\"handleNext()\"\n >\n <tedi-icon name=\"arrow_forward\" [size]=\"18\" />\n </button>\n}\n", styles: ["tedi-carousel-indicators{display:flex;gap:var(--layout-grid-gutters-04);align-items:center;min-height:24px}.tedi-carousel__indicator{position:relative;width:24px;height:24px;cursor:pointer;background:none;border:none}.tedi-carousel__indicator:after{position:absolute;top:50%;left:50%;width:22px;height:8px;content:\"\";background-color:transparent;border:1px solid var(--tedi-primary-600);border-radius:100px;transform:translate(-50%,-50%)}.tedi-carousel__indicator:hover:after{border-color:var(--tedi-primary-700)}.tedi-carousel__indicator:active:after{background-color:var(--tedi-primary-800);border-color:var(--tedi-primary-800)}.tedi-carousel__indicator:focus-visible:after{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:var(--tedi-borders-01)}.tedi-carousel__indicator--active:after{background-color:var(--tedi-primary-600)}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ButtonComponent, selector: "[tedi-button]", inputs: ["variant", "size"] }, { kind: "component", type: IconComponent, selector: "tedi-icon", inputs: ["name", "size", "color", "background", "variant", "type", "label"] }, { kind: "component", type: TextComponent, selector: "[tedi-text]", inputs: ["modifiers", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
16063
16191
|
}
|
|
16064
16192
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselIndicatorsComponent, decorators: [{
|
|
16065
16193
|
type: Component,
|
|
16066
|
-
args: [{ standalone: true, selector: "tedi-carousel-indicators", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgClass, ButtonComponent, IconComponent, TextComponent], template: "@if (withArrows()) {\n <button\n tedi-button\n type=\"button\"\n variant=\"neutral\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n}\n\n@if (variant() === \"dots\") {\n @for (indicator of indicatorsArray(); track indicator.index) {\n <button\n type=\"button\"\n class=\"tedi-carousel__indicator\"\n [attr.aria-label]=\"\n translationService.track('carousel.showSlide', indicator.index + 1)()\n \"\n [ngClass]=\"indicator.active ? 'tedi-carousel__indicator--active' : null\"\n (click)=\"handleIndicatorClick(indicator.index)\"\n ></button>\n }\n} @else if (
|
|
16194
|
+
args: [{ standalone: true, selector: "tedi-carousel-indicators", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [NgClass, ButtonComponent, IconComponent, TextComponent], template: "@if (withArrows()) {\n <button\n tedi-button\n type=\"button\"\n variant=\"neutral\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n [disabled]=\"!carousel.carouselContent().canPrev()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n}\n\n@if (variant() === \"dots\") {\n @for (indicator of indicatorsArray(); track indicator.index) {\n <button\n type=\"button\"\n class=\"tedi-carousel__indicator\"\n [attr.aria-label]=\"\n translationService.track('carousel.showSlide', indicator.index + 1)()\n \"\n [ngClass]=\"indicator.active ? 'tedi-carousel__indicator--active' : null\"\n (click)=\"handleIndicatorClick(indicator.index)\"\n ></button>\n }\n} @else if (indicatorsArray().length) {\n <div>\n <b tedi-text color=\"brand\">{{ activeSlideNumber() }}</b>\n <span tedi-text color=\"tertiary\"> / {{ indicatorsArray().length }}</span>\n </div>\n}\n\n@if (withArrows()) {\n <button\n tedi-button\n type=\"button\"\n variant=\"neutral\"\n [attr.aria-label]=\"translationService.track('carousel.moveForward')()\"\n [disabled]=\"!carousel.carouselContent().canNext()\"\n (click)=\"handleNext()\"\n >\n <tedi-icon name=\"arrow_forward\" [size]=\"18\" />\n </button>\n}\n", styles: ["tedi-carousel-indicators{display:flex;gap:var(--layout-grid-gutters-04);align-items:center;min-height:24px}.tedi-carousel__indicator{position:relative;width:24px;height:24px;cursor:pointer;background:none;border:none}.tedi-carousel__indicator:after{position:absolute;top:50%;left:50%;width:22px;height:8px;content:\"\";background-color:transparent;border:1px solid var(--tedi-primary-600);border-radius:100px;transform:translate(-50%,-50%)}.tedi-carousel__indicator:hover:after{border-color:var(--tedi-primary-700)}.tedi-carousel__indicator:active:after{background-color:var(--tedi-primary-800);border-color:var(--tedi-primary-800)}.tedi-carousel__indicator:focus-visible:after{outline:var(--tedi-borders-02) solid var(--tedi-primary-500);outline-offset:var(--tedi-borders-01)}.tedi-carousel__indicator--active:after{background-color:var(--tedi-primary-600)}\n"] }]
|
|
16067
16195
|
}], propDecorators: { withArrows: [{ type: i0.Input, args: [{ isSignal: true, alias: "withArrows", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }] } });
|
|
16068
16196
|
|
|
16069
16197
|
class CarouselNavigationComponent {
|
|
16198
|
+
/**
|
|
16199
|
+
* Shows floating navigation buttons over the slides. Place navigation directly
|
|
16200
|
+
* inside `tedi-carousel`, outside the header and footer.
|
|
16201
|
+
* @default false
|
|
16202
|
+
*/
|
|
16203
|
+
overlay = input(false, ...(ngDevMode ? [{ debugName: "overlay", transform: booleanAttribute }] : [{ transform: booleanAttribute }]));
|
|
16070
16204
|
translationService = inject(TediTranslationService);
|
|
16071
16205
|
carousel = inject(CarouselComponent);
|
|
16206
|
+
canPrev = computed(() => this.carousel.carouselContent().canPrev(), ...(ngDevMode ? [{ debugName: "canPrev" }] : []));
|
|
16207
|
+
canNext = computed(() => this.carousel.carouselContent().canNext(), ...(ngDevMode ? [{ debugName: "canNext" }] : []));
|
|
16072
16208
|
handleNext() {
|
|
16073
16209
|
this.carousel.carouselContent().next();
|
|
16074
16210
|
}
|
|
@@ -16076,12 +16212,14 @@ class CarouselNavigationComponent {
|
|
|
16076
16212
|
this.carousel.carouselContent().prev();
|
|
16077
16213
|
}
|
|
16078
16214
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselNavigationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
16079
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
16215
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.24", type: CarouselNavigationComponent, isStandalone: true, selector: "tedi-carousel-navigation", inputs: { overlay: { classPropertyName: "overlay", publicName: "overlay", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.tedi-carousel-navigation--overlay": "overlay()" } }, ngImport: i0, template: "@if (overlay()) {\n <button\n tedi-floating-button\n type=\"button\"\n variant=\"secondary\"\n position=\"static\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n [disabled]=\"!canPrev()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n <button\n tedi-floating-button\n type=\"button\"\n variant=\"secondary\"\n position=\"static\"\n [attr.aria-label]=\"translationService.track('carousel.moveForward')()\"\n [disabled]=\"!canNext()\"\n (click)=\"handleNext()\"\n >\n <tedi-icon name=\"arrow_forward\" [size]=\"18\" />\n </button>\n} @else {\n <button\n tedi-button\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n [disabled]=\"!canPrev()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n <button\n tedi-button\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"translationService.track('carousel.moveForward')()\"\n [disabled]=\"!canNext()\"\n (click)=\"handleNext()\"\n >\n <tedi-icon name=\"arrow_forward\" [size]=\"18\" />\n </button>\n}\n", styles: ["tedi-carousel-navigation{display:flex;gap:var(--layout-grid-gutters-08);align-items:center}tedi-carousel-navigation.tedi-carousel-navigation--overlay{position:absolute;inset:0;z-index:1;box-sizing:border-box;justify-content:space-between;padding:var(--layout-grid-gutters-08);pointer-events:none}tedi-carousel-navigation.tedi-carousel-navigation--overlay>*{pointer-events:auto}\n"], dependencies: [{ kind: "component", type: ButtonComponent, selector: "[tedi-button]", inputs: ["variant", "size"] }, { kind: "component", type: FloatingButtonComponent, selector: "[tedi-floating-button]", inputs: ["variant", "size", "axis", "position", "placement", "offset", "zIndex"] }, { kind: "component", type: IconComponent, selector: "tedi-icon", inputs: ["name", "size", "color", "background", "variant", "type", "label"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
16080
16216
|
}
|
|
16081
16217
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: CarouselNavigationComponent, decorators: [{
|
|
16082
16218
|
type: Component,
|
|
16083
|
-
args: [{ standalone: true, selector: "tedi-carousel-navigation", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ButtonComponent,
|
|
16084
|
-
|
|
16219
|
+
args: [{ standalone: true, selector: "tedi-carousel-navigation", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [ButtonComponent, FloatingButtonComponent, IconComponent], host: {
|
|
16220
|
+
"[class.tedi-carousel-navigation--overlay]": "overlay()",
|
|
16221
|
+
}, template: "@if (overlay()) {\n <button\n tedi-floating-button\n type=\"button\"\n variant=\"secondary\"\n position=\"static\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n [disabled]=\"!canPrev()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n <button\n tedi-floating-button\n type=\"button\"\n variant=\"secondary\"\n position=\"static\"\n [attr.aria-label]=\"translationService.track('carousel.moveForward')()\"\n [disabled]=\"!canNext()\"\n (click)=\"handleNext()\"\n >\n <tedi-icon name=\"arrow_forward\" [size]=\"18\" />\n </button>\n} @else {\n <button\n tedi-button\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"translationService.track('carousel.moveBack')()\"\n [disabled]=\"!canPrev()\"\n (click)=\"handlePrev()\"\n >\n <tedi-icon name=\"arrow_back\" [size]=\"18\" />\n </button>\n <button\n tedi-button\n type=\"button\"\n variant=\"secondary\"\n [attr.aria-label]=\"translationService.track('carousel.moveForward')()\"\n [disabled]=\"!canNext()\"\n (click)=\"handleNext()\"\n >\n <tedi-icon name=\"arrow_forward\" [size]=\"18\" />\n </button>\n}\n", styles: ["tedi-carousel-navigation{display:flex;gap:var(--layout-grid-gutters-08);align-items:center}tedi-carousel-navigation.tedi-carousel-navigation--overlay{position:absolute;inset:0;z-index:1;box-sizing:border-box;justify-content:space-between;padding:var(--layout-grid-gutters-08);pointer-events:none}tedi-carousel-navigation.tedi-carousel-navigation--overlay>*{pointer-events:auto}\n"] }]
|
|
16222
|
+
}], propDecorators: { overlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "overlay", required: false }] }] } });
|
|
16085
16223
|
|
|
16086
16224
|
const range = (start, end) => {
|
|
16087
16225
|
if (end < start)
|