ngx-edge-slider 2.2.2 → 2.2.4
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/assets/ngx-simple-slider.css +1 -0
- package/assets/ngx-simple-slider.css.map +1 -0
- package/assets/ngx-simple-slider.min.css +1 -0
- package/assets/ngx-simple-slider.min.css.map +1 -0
- package/esm2022/WingmanColt-ngx-edge-slider.mjs +5 -0
- package/fesm2022/WingmanColt-ngx-edge-slider.mjs +824 -0
- package/fesm2022/WingmanColt-ngx-edge-slider.mjs.map +1 -0
- package/package.json +5 -2
- package/README.md +0 -653
|
@@ -0,0 +1,824 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable, EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, Input, Output, ViewChild, NgModule, Pipe } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject, Subject, fromEvent, merge, auditTime, takeUntil } from 'rxjs';
|
|
4
|
+
import * as i7 from '@angular/common';
|
|
5
|
+
import { CommonModule } from '@angular/common';
|
|
6
|
+
import * as i1 from '@angular/platform-browser';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_CONFIG = {
|
|
9
|
+
slides: [],
|
|
10
|
+
slidesPerView: 1,
|
|
11
|
+
slidesToSlide: 1,
|
|
12
|
+
loop: 0,
|
|
13
|
+
vertical: false,
|
|
14
|
+
changeToClickedSlide: false,
|
|
15
|
+
isThumbs: false,
|
|
16
|
+
plugins: {
|
|
17
|
+
draggable: false,
|
|
18
|
+
pagination: false,
|
|
19
|
+
navigation: false,
|
|
20
|
+
autoplay: undefined,
|
|
21
|
+
},
|
|
22
|
+
gap: 0,
|
|
23
|
+
showOn: { mobile: true, tablet: true, desktop: true },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const INITIAL_SLIDER_STATE = {
|
|
27
|
+
currentSlide: 0,
|
|
28
|
+
selectedSlide: -1,
|
|
29
|
+
slidesPerView: 1,
|
|
30
|
+
visibleSlides: [],
|
|
31
|
+
gap: 0,
|
|
32
|
+
maxStartIndex: 0,
|
|
33
|
+
canPrev: false,
|
|
34
|
+
canNext: false,
|
|
35
|
+
translate: "translateX(0px)",
|
|
36
|
+
transition: "transform 300ms ease",
|
|
37
|
+
pager: null,
|
|
38
|
+
isAnimating: false,
|
|
39
|
+
isVisible: false,
|
|
40
|
+
isDragging: false,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class SliderStore {
|
|
44
|
+
state$ = new BehaviorSubject({
|
|
45
|
+
currentSlide: 0,
|
|
46
|
+
selectedSlide: -1,
|
|
47
|
+
slidesPerView: 1,
|
|
48
|
+
visibleSlides: [],
|
|
49
|
+
translate: "translateX(0)",
|
|
50
|
+
transition: "transform 300ms ease",
|
|
51
|
+
pager: null,
|
|
52
|
+
isVisible: true,
|
|
53
|
+
isAnimating: false,
|
|
54
|
+
isDragging: false,
|
|
55
|
+
});
|
|
56
|
+
view$ = this.state$.asObservable();
|
|
57
|
+
get snapshot() {
|
|
58
|
+
return this.state$.value;
|
|
59
|
+
}
|
|
60
|
+
update(patch) {
|
|
61
|
+
this.state$.next({ ...this.snapshot, ...patch });
|
|
62
|
+
}
|
|
63
|
+
reset() {
|
|
64
|
+
this.state$.next(INITIAL_SLIDER_STATE);
|
|
65
|
+
}
|
|
66
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
67
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderStore });
|
|
68
|
+
}
|
|
69
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderStore, decorators: [{
|
|
70
|
+
type: Injectable
|
|
71
|
+
}] });
|
|
72
|
+
|
|
73
|
+
class SliderEngine {
|
|
74
|
+
store;
|
|
75
|
+
config;
|
|
76
|
+
plugins = [];
|
|
77
|
+
syncThumbsEngine;
|
|
78
|
+
// RX lifecycle
|
|
79
|
+
destroy$ = new Subject();
|
|
80
|
+
// Container-based breakpoints
|
|
81
|
+
containerEl;
|
|
82
|
+
ro;
|
|
83
|
+
measuredSlideSizePx;
|
|
84
|
+
constructor(store) {
|
|
85
|
+
this.store = store;
|
|
86
|
+
}
|
|
87
|
+
/* ---------------- Public API ---------------- */
|
|
88
|
+
init(config, plugins = []) {
|
|
89
|
+
this.config = { ...DEFAULT_CONFIG, ...config, plugins: { ...(config.plugins ?? {}) } };
|
|
90
|
+
this.plugins = plugins;
|
|
91
|
+
this.plugins.forEach((p) => p.init?.(this));
|
|
92
|
+
this.setupViewportSignals();
|
|
93
|
+
this.applyBreakpoint();
|
|
94
|
+
this.clampIndicesAfterLayoutChange();
|
|
95
|
+
this.recalculate();
|
|
96
|
+
}
|
|
97
|
+
/** Call this from the component once you have the slider host element */
|
|
98
|
+
attachContainer(el) {
|
|
99
|
+
this.containerEl = el;
|
|
100
|
+
// Observe container size changes (robust in grids/sidebars/tabs)
|
|
101
|
+
this.ro?.disconnect();
|
|
102
|
+
this.ro = new ResizeObserver(() => {
|
|
103
|
+
// We reuse the same debounced layout handler
|
|
104
|
+
this.onLayoutSignal();
|
|
105
|
+
});
|
|
106
|
+
this.ro.observe(el);
|
|
107
|
+
this.measureSlideSize();
|
|
108
|
+
// Apply immediately based on real container width
|
|
109
|
+
this.onLayoutSignal();
|
|
110
|
+
}
|
|
111
|
+
measureSlideSize() {
|
|
112
|
+
if (!this.containerEl)
|
|
113
|
+
return;
|
|
114
|
+
const firstSlide = this.containerEl.querySelector(".slide");
|
|
115
|
+
if (!firstSlide)
|
|
116
|
+
return;
|
|
117
|
+
const rect = firstSlide.getBoundingClientRect();
|
|
118
|
+
if (rect.width > 0)
|
|
119
|
+
this.measuredSlideSizePx = rect.width;
|
|
120
|
+
}
|
|
121
|
+
destroy() {
|
|
122
|
+
// Stop Rx streams
|
|
123
|
+
this.destroy$.next();
|
|
124
|
+
this.destroy$.complete();
|
|
125
|
+
// Disconnect ResizeObserver
|
|
126
|
+
this.ro?.disconnect();
|
|
127
|
+
this.ro = undefined;
|
|
128
|
+
this.containerEl = undefined;
|
|
129
|
+
// Plugin cleanup
|
|
130
|
+
this.plugins.forEach((p) => p.destroy?.());
|
|
131
|
+
this.plugins = [];
|
|
132
|
+
// Reset store
|
|
133
|
+
this.store.reset();
|
|
134
|
+
}
|
|
135
|
+
next() {
|
|
136
|
+
this.goTo(this.store.snapshot.currentSlide + this.slideStep());
|
|
137
|
+
this.plugins.forEach((p) => p.onNext?.());
|
|
138
|
+
}
|
|
139
|
+
previous() {
|
|
140
|
+
this.goTo(this.store.snapshot.currentSlide - this.slideStep());
|
|
141
|
+
this.plugins.forEach((p) => p.onPrevious?.());
|
|
142
|
+
}
|
|
143
|
+
getContainerEl() {
|
|
144
|
+
return this.containerEl;
|
|
145
|
+
}
|
|
146
|
+
selectSlide(index) {
|
|
147
|
+
const slidesPerView = this.store.snapshot.slidesPerView;
|
|
148
|
+
// 1️⃣ Mark selected
|
|
149
|
+
this.store.update({ selectedSlide: index });
|
|
150
|
+
// 2️⃣ Calculate page start
|
|
151
|
+
let pageStart = Math.floor(index / slidesPerView) * slidesPerView;
|
|
152
|
+
// 3️⃣ Clamp to maxStartIndex
|
|
153
|
+
pageStart = Math.min(pageStart, this.maxStartIndex);
|
|
154
|
+
// 4️⃣ If synced with thumbs, also clamp to their max index
|
|
155
|
+
if (this.syncThumbsEngine) {
|
|
156
|
+
const thumbMaxIndex = this.syncThumbsEngine.getMaxStartIndex();
|
|
157
|
+
pageStart = Math.min(pageStart, thumbMaxIndex);
|
|
158
|
+
}
|
|
159
|
+
// 5️⃣ Move main slider
|
|
160
|
+
if (pageStart !== this.store.snapshot.currentSlide) {
|
|
161
|
+
this.goToSlide(pageStart);
|
|
162
|
+
}
|
|
163
|
+
// 6️⃣ Notify plugins
|
|
164
|
+
this.plugins.forEach((p) => p.onSlideClick?.(index));
|
|
165
|
+
}
|
|
166
|
+
/* ---------------- Drag ---------------- */
|
|
167
|
+
handleDragStart(event) {
|
|
168
|
+
this.store.update({ isDragging: true });
|
|
169
|
+
this.plugins.forEach((p) => p.onDragStart?.(event));
|
|
170
|
+
}
|
|
171
|
+
handleDragMove(event) {
|
|
172
|
+
this.plugins.forEach((p) => p.onDragMove?.(event));
|
|
173
|
+
}
|
|
174
|
+
handleDragEnd() {
|
|
175
|
+
this.store.update({ isDragging: false });
|
|
176
|
+
this.plugins.forEach((p) => p.onDragEnd?.());
|
|
177
|
+
}
|
|
178
|
+
goTo(index) {
|
|
179
|
+
this.goToSlide(index); // reuse your existing private method
|
|
180
|
+
}
|
|
181
|
+
/* ---------------- Internals ---------------- */
|
|
182
|
+
goToSlide(index) {
|
|
183
|
+
const clamped = Math.max(0, Math.min(index, this.maxStartIndex));
|
|
184
|
+
// console.log("[Engine] goToSlide index:", index, "clamped:", clamped);
|
|
185
|
+
this.store.update({ currentSlide: clamped });
|
|
186
|
+
this.recalculate();
|
|
187
|
+
// NOTE: calling onSlideClick here is a bit semantically odd (since it’s not always a click),
|
|
188
|
+
// but I preserved your behavior.
|
|
189
|
+
this.plugins.forEach((p) => p.onSlideClick?.(index));
|
|
190
|
+
}
|
|
191
|
+
recalculate() {
|
|
192
|
+
if (this.store.snapshot.isDragging)
|
|
193
|
+
return; // skip during drag
|
|
194
|
+
const slides = this.config.slides ?? [];
|
|
195
|
+
const maxStartIndex = this.getMaxStartIndex();
|
|
196
|
+
const current = this.store.snapshot.currentSlide;
|
|
197
|
+
this.store.update({
|
|
198
|
+
visibleSlides: slides,
|
|
199
|
+
translate: this.translate(current),
|
|
200
|
+
pager: this.buildPager(),
|
|
201
|
+
maxStartIndex,
|
|
202
|
+
canPrev: current > 0,
|
|
203
|
+
canNext: current < maxStartIndex,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
translate(index) {
|
|
207
|
+
const axis = this.config.vertical ? "Y" : "X";
|
|
208
|
+
const containerSize = this.containerEl
|
|
209
|
+
? this.config.vertical
|
|
210
|
+
? this.containerEl.clientHeight
|
|
211
|
+
: this.containerEl.clientWidth
|
|
212
|
+
: this.config.vertical
|
|
213
|
+
? window.innerHeight
|
|
214
|
+
: window.innerWidth;
|
|
215
|
+
const gap = this.store.snapshot.gap ?? 0;
|
|
216
|
+
const spv = this.store.snapshot.slidesPerView;
|
|
217
|
+
const slideSize = this.config.isThumbs && this.measuredSlideSizePx
|
|
218
|
+
? this.measuredSlideSizePx
|
|
219
|
+
: spv > 0
|
|
220
|
+
? (containerSize - gap * (spv - 1)) / spv
|
|
221
|
+
: containerSize;
|
|
222
|
+
// move by "pageStart * (slideSize + gap)"
|
|
223
|
+
const offset = index * (slideSize + gap);
|
|
224
|
+
return `translate${axis}(-${offset}px)`;
|
|
225
|
+
}
|
|
226
|
+
/** Debounced layout signals for resize/orientation/container changes */
|
|
227
|
+
setupViewportSignals() {
|
|
228
|
+
// If you want "only after resizing stops", replace auditTime with debounceTime(120)
|
|
229
|
+
const resize$ = fromEvent(window, "resize", { passive: true });
|
|
230
|
+
const orientation$ = fromEvent(window, "orientationchange", { passive: true });
|
|
231
|
+
merge(resize$, orientation$)
|
|
232
|
+
.pipe(auditTime(80), // good compromise: responsive without over-recalc
|
|
233
|
+
takeUntil(this.destroy$))
|
|
234
|
+
.subscribe(() => this.onLayoutSignal());
|
|
235
|
+
}
|
|
236
|
+
onLayoutSignal() {
|
|
237
|
+
const beforeSlidesPerView = this.store.snapshot.slidesPerView;
|
|
238
|
+
const beforeVisible = this.store.snapshot.isVisible;
|
|
239
|
+
this.applyBreakpoint();
|
|
240
|
+
const afterSlidesPerView = this.store.snapshot.slidesPerView;
|
|
241
|
+
const afterVisible = this.store.snapshot.isVisible;
|
|
242
|
+
if (beforeSlidesPerView !== afterSlidesPerView || beforeVisible !== afterVisible) {
|
|
243
|
+
this.clampIndicesAfterLayoutChange();
|
|
244
|
+
}
|
|
245
|
+
this.measureSlideSize();
|
|
246
|
+
this.recalculate();
|
|
247
|
+
}
|
|
248
|
+
getBreakpointWidth() {
|
|
249
|
+
if (this.containerEl) {
|
|
250
|
+
// Prefer clientWidth (layout), fallback to rect width
|
|
251
|
+
return this.containerEl.clientWidth || this.containerEl.getBoundingClientRect().width || window.innerWidth;
|
|
252
|
+
}
|
|
253
|
+
return window.innerWidth;
|
|
254
|
+
}
|
|
255
|
+
applyBreakpoint() {
|
|
256
|
+
const width = this.getBreakpointWidth();
|
|
257
|
+
const bp = this.config.breakpoints;
|
|
258
|
+
let override;
|
|
259
|
+
let device = "desktop";
|
|
260
|
+
if (width < 768) {
|
|
261
|
+
override = bp?.mobile;
|
|
262
|
+
device = "mobile";
|
|
263
|
+
}
|
|
264
|
+
else if (width < 1024) {
|
|
265
|
+
override = bp?.tablet;
|
|
266
|
+
device = "tablet";
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
override = bp?.desktop;
|
|
270
|
+
device = "desktop";
|
|
271
|
+
}
|
|
272
|
+
// Merge overrides
|
|
273
|
+
this.config = { ...this.config, ...override };
|
|
274
|
+
this.store.update({
|
|
275
|
+
slidesPerView: this.config.slidesPerView,
|
|
276
|
+
gap: this.config.gap ?? 0, // ✅ NEW
|
|
277
|
+
isVisible: this.config.showOn?.[device] ?? true,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
clampIndicesAfterLayoutChange() {
|
|
281
|
+
const max = this.getMaxStartIndex();
|
|
282
|
+
const current = this.store.snapshot.currentSlide;
|
|
283
|
+
const selected = this.store.snapshot.selectedSlide;
|
|
284
|
+
const clampedCurrent = Math.max(0, Math.min(current, max));
|
|
285
|
+
const clampedSelected = selected === -1 ? -1 : Math.max(0, Math.min(selected, (this.config.slides?.length ?? 0) - 1));
|
|
286
|
+
this.store.update({
|
|
287
|
+
currentSlide: clampedCurrent,
|
|
288
|
+
selectedSlide: clampedSelected,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
buildPager() {
|
|
292
|
+
const totalSlides = this.config.slides.length;
|
|
293
|
+
const currentSlide = this.store.snapshot.selectedSlide !== -1 ? this.store.snapshot.selectedSlide : this.store.snapshot.currentSlide;
|
|
294
|
+
const maxVisibleDots = 5;
|
|
295
|
+
let start = Math.max(0, currentSlide - Math.floor(maxVisibleDots / 2));
|
|
296
|
+
let end = start + maxVisibleDots;
|
|
297
|
+
if (end > totalSlides) {
|
|
298
|
+
end = totalSlides;
|
|
299
|
+
start = Math.max(0, end - maxVisibleDots);
|
|
300
|
+
}
|
|
301
|
+
const visibleDots = Array.from({ length: end - start }, (_, i) => start + i);
|
|
302
|
+
const activeDotIndex = visibleDots.indexOf(currentSlide);
|
|
303
|
+
return {
|
|
304
|
+
currentPage: currentSlide,
|
|
305
|
+
totalPages: totalSlides,
|
|
306
|
+
visibleDots,
|
|
307
|
+
activeDotIndex,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
slideStep() {
|
|
311
|
+
return this.store.snapshot.slidesPerView;
|
|
312
|
+
}
|
|
313
|
+
get maxStartIndex() {
|
|
314
|
+
const total = this.config.slides?.length ?? 0;
|
|
315
|
+
return Math.max(0, total - this.store.snapshot.slidesPerView);
|
|
316
|
+
}
|
|
317
|
+
getMaxStartIndex() {
|
|
318
|
+
const total = this.config.slides?.length ?? 0;
|
|
319
|
+
const spv = this.store.snapshot.slidesPerView || 1;
|
|
320
|
+
return Math.max(0, total - spv);
|
|
321
|
+
}
|
|
322
|
+
/* -------- Plugin-safe API -------- */
|
|
323
|
+
getState() {
|
|
324
|
+
return this.store.snapshot;
|
|
325
|
+
}
|
|
326
|
+
getStateObservable() {
|
|
327
|
+
return this.store.view$;
|
|
328
|
+
}
|
|
329
|
+
setState(patch) {
|
|
330
|
+
this.store.update(patch);
|
|
331
|
+
}
|
|
332
|
+
getConfig() {
|
|
333
|
+
return this.config;
|
|
334
|
+
}
|
|
335
|
+
/** Link this slider to thumbs */
|
|
336
|
+
syncWithThumbs(thumbsEngine) {
|
|
337
|
+
this.syncThumbsEngine = thumbsEngine;
|
|
338
|
+
}
|
|
339
|
+
/* -------- Read-only helpers -------- */
|
|
340
|
+
getSlidesPerView() {
|
|
341
|
+
return this.store.snapshot.slidesPerView;
|
|
342
|
+
}
|
|
343
|
+
getCurrentSlide() {
|
|
344
|
+
return this.store.snapshot.currentSlide;
|
|
345
|
+
}
|
|
346
|
+
getSelectedSlide() {
|
|
347
|
+
return this.store.snapshot.selectedSlide;
|
|
348
|
+
}
|
|
349
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderEngine, deps: [{ token: SliderStore }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
350
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderEngine });
|
|
351
|
+
}
|
|
352
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderEngine, decorators: [{
|
|
353
|
+
type: Injectable
|
|
354
|
+
}], ctorParameters: () => [{ type: SliderStore }] });
|
|
355
|
+
|
|
356
|
+
class SliderAutoplayPlugin {
|
|
357
|
+
engine;
|
|
358
|
+
timerId;
|
|
359
|
+
delay = 4000; // default
|
|
360
|
+
init(engine) {
|
|
361
|
+
this.engine = engine;
|
|
362
|
+
this.start();
|
|
363
|
+
}
|
|
364
|
+
setConfig(config) {
|
|
365
|
+
if (!config)
|
|
366
|
+
return;
|
|
367
|
+
if (typeof config.delay === "number") {
|
|
368
|
+
this.delay = config.delay;
|
|
369
|
+
}
|
|
370
|
+
// restart autoplay with new config
|
|
371
|
+
this.start();
|
|
372
|
+
}
|
|
373
|
+
onDragStart() {
|
|
374
|
+
this.stop();
|
|
375
|
+
}
|
|
376
|
+
onDragEnd() {
|
|
377
|
+
this.start();
|
|
378
|
+
}
|
|
379
|
+
start() {
|
|
380
|
+
this.stop();
|
|
381
|
+
this.timerId = setInterval(() => {
|
|
382
|
+
this.engine.next();
|
|
383
|
+
}, this.delay);
|
|
384
|
+
}
|
|
385
|
+
stop() {
|
|
386
|
+
if (this.timerId) {
|
|
387
|
+
clearInterval(this.timerId);
|
|
388
|
+
this.timerId = null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
destroy() {
|
|
392
|
+
this.stop();
|
|
393
|
+
}
|
|
394
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderAutoplayPlugin, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
395
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderAutoplayPlugin });
|
|
396
|
+
}
|
|
397
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderAutoplayPlugin, decorators: [{
|
|
398
|
+
type: Injectable
|
|
399
|
+
}] });
|
|
400
|
+
|
|
401
|
+
class SliderDraggablePlugin {
|
|
402
|
+
engine;
|
|
403
|
+
startX = 0;
|
|
404
|
+
deltaX = 0;
|
|
405
|
+
hasDragged = false;
|
|
406
|
+
isDragging = false;
|
|
407
|
+
dragThreshold = 50;
|
|
408
|
+
// Expose drag state to template
|
|
409
|
+
get isDraggingPointer() {
|
|
410
|
+
return this.isDragging;
|
|
411
|
+
}
|
|
412
|
+
init(engine) {
|
|
413
|
+
this.engine = engine;
|
|
414
|
+
}
|
|
415
|
+
onDragStart(event) {
|
|
416
|
+
this.startX = event.clientX;
|
|
417
|
+
this.deltaX = 0;
|
|
418
|
+
this.hasDragged = false;
|
|
419
|
+
this.isDragging = true;
|
|
420
|
+
// Set engine dragging state
|
|
421
|
+
this.engine.setState({ isDragging: true });
|
|
422
|
+
}
|
|
423
|
+
onDragMove(event) {
|
|
424
|
+
if (!this.isDragging)
|
|
425
|
+
return;
|
|
426
|
+
const moveX = event.clientX - this.startX;
|
|
427
|
+
this.deltaX += moveX;
|
|
428
|
+
this.hasDragged = true;
|
|
429
|
+
const currentTranslate = this.extractTranslate(this.engine.getState().translate);
|
|
430
|
+
const newTranslate = currentTranslate + moveX;
|
|
431
|
+
this.engine.setState({ translate: `translateX(${newTranslate}px)` });
|
|
432
|
+
this.startX = event.clientX;
|
|
433
|
+
}
|
|
434
|
+
onDragEnd() {
|
|
435
|
+
if (this.hasDragged) {
|
|
436
|
+
if (this.deltaX > this.dragThreshold) {
|
|
437
|
+
this.engine.previous();
|
|
438
|
+
}
|
|
439
|
+
else if (this.deltaX < -this.dragThreshold) {
|
|
440
|
+
this.engine.next();
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
// Small drag → snap back
|
|
444
|
+
this.engine.recalculate();
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
this.isDragging = false;
|
|
448
|
+
this.hasDragged = false;
|
|
449
|
+
this.deltaX = 0;
|
|
450
|
+
this.engine.setState({ isDragging: false });
|
|
451
|
+
}
|
|
452
|
+
/** Extract numeric value from 'translateX(-123px)' */
|
|
453
|
+
extractTranslate(transform) {
|
|
454
|
+
if (!transform)
|
|
455
|
+
return 0;
|
|
456
|
+
const match = transform.match(/-?\d+(\.\d+)?/);
|
|
457
|
+
return match ? parseFloat(match[0]) : 0;
|
|
458
|
+
}
|
|
459
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderDraggablePlugin, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
460
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderDraggablePlugin });
|
|
461
|
+
}
|
|
462
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderDraggablePlugin, decorators: [{
|
|
463
|
+
type: Injectable
|
|
464
|
+
}] });
|
|
465
|
+
|
|
466
|
+
class SliderNavigationPlugin {
|
|
467
|
+
engine;
|
|
468
|
+
isPagerMode = false;
|
|
469
|
+
_canPrev$ = new BehaviorSubject(false);
|
|
470
|
+
_canNext$ = new BehaviorSubject(false);
|
|
471
|
+
sub;
|
|
472
|
+
get canPrev$() {
|
|
473
|
+
return this._canPrev$.asObservable();
|
|
474
|
+
}
|
|
475
|
+
get canNext$() {
|
|
476
|
+
return this._canNext$.asObservable();
|
|
477
|
+
}
|
|
478
|
+
init(engine, isPagerMode = false) {
|
|
479
|
+
this.engine = engine;
|
|
480
|
+
this.isPagerMode = isPagerMode;
|
|
481
|
+
// Subscribe to state changes
|
|
482
|
+
this.sub = this.engine.getStateObservable?.()?.subscribe(() => this.updateArrows());
|
|
483
|
+
// ✅ Force initial check after a short delay (to catch async slides)
|
|
484
|
+
setTimeout(() => this.updateArrows());
|
|
485
|
+
}
|
|
486
|
+
destroy() {
|
|
487
|
+
this.sub?.unsubscribe();
|
|
488
|
+
}
|
|
489
|
+
next() {
|
|
490
|
+
if (!this.engine)
|
|
491
|
+
return;
|
|
492
|
+
if (this.isPagerMode) {
|
|
493
|
+
const state = this.engine.getState();
|
|
494
|
+
const cfg = this.engine.getConfig();
|
|
495
|
+
const totalSlides = cfg?.slides?.length ?? 0;
|
|
496
|
+
const perView = state?.slidesPerView ?? cfg?.slidesPerView ?? 1;
|
|
497
|
+
const step = cfg?.slidesToSlide ?? 1;
|
|
498
|
+
const maxIndex = Math.max(0, totalSlides - perView);
|
|
499
|
+
const current = state?.currentSlide ?? 0;
|
|
500
|
+
const newIndex = Math.min(maxIndex, current + step);
|
|
501
|
+
this.engine.goTo(newIndex);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
this.engine.next();
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
prev() {
|
|
508
|
+
if (!this.engine)
|
|
509
|
+
return;
|
|
510
|
+
if (this.isPagerMode) {
|
|
511
|
+
const state = this.engine.getState();
|
|
512
|
+
const cfg = this.engine.getConfig();
|
|
513
|
+
const step = cfg?.slidesToSlide ?? 1;
|
|
514
|
+
const current = state?.currentSlide ?? 0;
|
|
515
|
+
const newIndex = Math.max(0, current - step);
|
|
516
|
+
this.engine.goTo(newIndex);
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
this.engine.previous();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
updateArrows() {
|
|
523
|
+
if (!this.engine)
|
|
524
|
+
return;
|
|
525
|
+
const state = this.engine.getState();
|
|
526
|
+
const cfg = this.engine.getConfig();
|
|
527
|
+
const totalSlides = cfg?.slides?.length ?? 0;
|
|
528
|
+
const perView = state?.slidesPerView ?? 1;
|
|
529
|
+
const canPrev = totalSlides > 0 && (state?.currentSlide ?? 0) > 0;
|
|
530
|
+
const canNext = totalSlides > 0 && (state?.currentSlide ?? 0) < Math.max(0, totalSlides - perView);
|
|
531
|
+
if (this._canPrev$.value !== canPrev)
|
|
532
|
+
this._canPrev$.next(canPrev);
|
|
533
|
+
if (this._canNext$.value !== canNext)
|
|
534
|
+
this._canNext$.next(canNext);
|
|
535
|
+
}
|
|
536
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderNavigationPlugin, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
537
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderNavigationPlugin });
|
|
538
|
+
}
|
|
539
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderNavigationPlugin, decorators: [{
|
|
540
|
+
type: Injectable
|
|
541
|
+
}] });
|
|
542
|
+
|
|
543
|
+
class SliderPaginationPlugin {
|
|
544
|
+
engine;
|
|
545
|
+
maxVisibleDots = 10;
|
|
546
|
+
sub;
|
|
547
|
+
_pager$ = new BehaviorSubject(null);
|
|
548
|
+
pager$ = this._pager$.asObservable();
|
|
549
|
+
init(engine) {
|
|
550
|
+
this.engine = engine;
|
|
551
|
+
this.sub = this.engine.getStateObservable().subscribe(() => {
|
|
552
|
+
this.updatePager();
|
|
553
|
+
});
|
|
554
|
+
// initial
|
|
555
|
+
setTimeout(() => this.updatePager());
|
|
556
|
+
}
|
|
557
|
+
destroy() {
|
|
558
|
+
this.sub?.unsubscribe();
|
|
559
|
+
this._pager$.next(null);
|
|
560
|
+
}
|
|
561
|
+
/** Go to a slide by slide index (NOT dot index) */
|
|
562
|
+
goToSlide(slideIndex) {
|
|
563
|
+
this.engine.selectSlide(slideIndex);
|
|
564
|
+
}
|
|
565
|
+
updatePager() {
|
|
566
|
+
const state = this.engine.getState();
|
|
567
|
+
const totalSlides = state.visibleSlides?.length ?? 0;
|
|
568
|
+
if (totalSlides <= 0) {
|
|
569
|
+
this._pager$.next(null);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
// ✅ important: selectedSlide is -1 initially; fallback to currentSlide
|
|
573
|
+
const current = state.selectedSlide !== -1 ? state.selectedSlide : state.currentSlide;
|
|
574
|
+
const maxDots = Math.max(1, this.maxVisibleDots);
|
|
575
|
+
// ✅ clamp to >= 0
|
|
576
|
+
const safeCurrent = Math.max(0, Math.min(current, totalSlides - 1));
|
|
577
|
+
const pageStart = Math.max(0, Math.floor(safeCurrent / maxDots) * maxDots);
|
|
578
|
+
const pageEnd = Math.min(pageStart + maxDots, totalSlides);
|
|
579
|
+
const visibleDots = Array.from({ length: pageEnd - pageStart }, (_, i) => pageStart + i);
|
|
580
|
+
const activeDotIndex = visibleDots.indexOf(safeCurrent);
|
|
581
|
+
this._pager$.next({ visibleDots, activeDotIndex });
|
|
582
|
+
}
|
|
583
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderPaginationPlugin, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
584
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderPaginationPlugin });
|
|
585
|
+
}
|
|
586
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SliderPaginationPlugin, decorators: [{
|
|
587
|
+
type: Injectable
|
|
588
|
+
}] });
|
|
589
|
+
|
|
590
|
+
class SimpleSliderComponent {
|
|
591
|
+
engine;
|
|
592
|
+
store;
|
|
593
|
+
draggable;
|
|
594
|
+
pagination;
|
|
595
|
+
navigation;
|
|
596
|
+
autoplay;
|
|
597
|
+
config;
|
|
598
|
+
slideTemplate;
|
|
599
|
+
navigationTemplate;
|
|
600
|
+
paginationTemplate;
|
|
601
|
+
slideChange = new EventEmitter();
|
|
602
|
+
isDraggingPointer = false;
|
|
603
|
+
dragStartX = 0;
|
|
604
|
+
dragStartY = 0;
|
|
605
|
+
lastIndex = -1;
|
|
606
|
+
lastSlidesRef = null;
|
|
607
|
+
destroy$ = new Subject();
|
|
608
|
+
state$;
|
|
609
|
+
sliderHost;
|
|
610
|
+
constructor(engine, store, draggable, pagination, navigation, autoplay) {
|
|
611
|
+
this.engine = engine;
|
|
612
|
+
this.store = store;
|
|
613
|
+
this.draggable = draggable;
|
|
614
|
+
this.pagination = pagination;
|
|
615
|
+
this.navigation = navigation;
|
|
616
|
+
this.autoplay = autoplay;
|
|
617
|
+
}
|
|
618
|
+
ngOnInit() {
|
|
619
|
+
this.state$ = this.store.view$;
|
|
620
|
+
this.state$.pipe(takeUntil(this.destroy$)).subscribe((state) => {
|
|
621
|
+
if (state.currentSlide !== this.lastIndex) {
|
|
622
|
+
this.lastIndex = state.currentSlide;
|
|
623
|
+
this.slideChange.emit(state.currentSlide);
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
this.lastSlidesRef = this.config?.slides ?? null;
|
|
627
|
+
this.resolvePlugins(this.config);
|
|
628
|
+
}
|
|
629
|
+
ngAfterViewInit() {
|
|
630
|
+
if (this.sliderHost?.nativeElement) {
|
|
631
|
+
this.engine.attachContainer(this.sliderHost.nativeElement);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
ngOnChanges(changes) {
|
|
635
|
+
if (!changes["config"] || !this.config)
|
|
636
|
+
return;
|
|
637
|
+
const newSlidesRef = this.config.slides ?? null;
|
|
638
|
+
if (newSlidesRef !== this.lastSlidesRef) {
|
|
639
|
+
this.lastSlidesRef = newSlidesRef;
|
|
640
|
+
this.engine.destroy();
|
|
641
|
+
this.resolvePlugins(this.config);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
ngOnDestroy() {
|
|
645
|
+
this.destroySlider();
|
|
646
|
+
}
|
|
647
|
+
goTo(index) {
|
|
648
|
+
this.engine.selectSlide(index); // add this line
|
|
649
|
+
//this.slideChange.emit(index);
|
|
650
|
+
}
|
|
651
|
+
destroySlider() {
|
|
652
|
+
this.destroy$.next();
|
|
653
|
+
this.destroy$.complete();
|
|
654
|
+
this.engine.destroy();
|
|
655
|
+
} // destroys plugins and clears store
|
|
656
|
+
onNext() {
|
|
657
|
+
this.engine.next();
|
|
658
|
+
}
|
|
659
|
+
onPrevious() {
|
|
660
|
+
this.engine.previous();
|
|
661
|
+
}
|
|
662
|
+
selectSlide(index) {
|
|
663
|
+
this.engine.selectSlide(index);
|
|
664
|
+
}
|
|
665
|
+
onRecalculate() {
|
|
666
|
+
this.engine.recalculate();
|
|
667
|
+
}
|
|
668
|
+
// Navigation
|
|
669
|
+
/** Expose navigation observables safely */
|
|
670
|
+
get canPrev$() {
|
|
671
|
+
if (!this.navigation) {
|
|
672
|
+
console.warn("Navigation plugin is not enabled.");
|
|
673
|
+
return null;
|
|
674
|
+
}
|
|
675
|
+
return this.navigation.canPrev$;
|
|
676
|
+
}
|
|
677
|
+
get canNext$() {
|
|
678
|
+
if (!this.navigation) {
|
|
679
|
+
console.warn("Navigation plugin is not enabled.");
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
return this.navigation.canNext$;
|
|
683
|
+
}
|
|
684
|
+
/** Expose next/prev methods */
|
|
685
|
+
next() {
|
|
686
|
+
this.navigation?.next();
|
|
687
|
+
}
|
|
688
|
+
prev() {
|
|
689
|
+
this.navigation?.prev();
|
|
690
|
+
}
|
|
691
|
+
/** Expose pagination observable */
|
|
692
|
+
get pager$() {
|
|
693
|
+
if (!this.pagination) {
|
|
694
|
+
console.warn("Pagination plugin is not enabled for this slider.");
|
|
695
|
+
return null;
|
|
696
|
+
}
|
|
697
|
+
return this.pagination.pager$;
|
|
698
|
+
}
|
|
699
|
+
/** Expose a goToSlide method */
|
|
700
|
+
goToSlide(index) {
|
|
701
|
+
this.pagination.goToSlide(index);
|
|
702
|
+
}
|
|
703
|
+
// Handle Pointers
|
|
704
|
+
onPointerDown(event) {
|
|
705
|
+
// Only start drag if not clicking a nav button
|
|
706
|
+
if (event.target.closest(".nav-btn")) {
|
|
707
|
+
return; // ignore
|
|
708
|
+
}
|
|
709
|
+
this.dragStartX = event.clientX;
|
|
710
|
+
this.dragStartY = event.clientY;
|
|
711
|
+
this.isDraggingPointer = false;
|
|
712
|
+
// Do not capture yet; wait until movement exceeds threshold
|
|
713
|
+
this.engine.handleDragStart(event);
|
|
714
|
+
}
|
|
715
|
+
onPointerMove(event) {
|
|
716
|
+
const dx = Math.abs(event.clientX - this.dragStartX);
|
|
717
|
+
const dy = Math.abs(event.clientY - this.dragStartY);
|
|
718
|
+
if (!this.isDraggingPointer && (dx > 5 || dy > 5)) {
|
|
719
|
+
this.isDraggingPointer = true;
|
|
720
|
+
// Now start capturing pointer so dragging works outside the slider bounds
|
|
721
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
722
|
+
}
|
|
723
|
+
if (this.isDraggingPointer) {
|
|
724
|
+
this.engine.handleDragMove(event);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
onPointerUp(event) {
|
|
728
|
+
if (!event)
|
|
729
|
+
return;
|
|
730
|
+
if (!this.isDraggingPointer) {
|
|
731
|
+
const target = event.target;
|
|
732
|
+
// Only select the slide if click is not on an interactive child
|
|
733
|
+
const slideEl = target.closest(".slide");
|
|
734
|
+
if (slideEl && !target.closest("button, video, a")) {
|
|
735
|
+
const indexAttr = slideEl.getAttribute("data-index");
|
|
736
|
+
const index = indexAttr ? parseInt(indexAttr, 10) : null;
|
|
737
|
+
if (index !== null)
|
|
738
|
+
this.engine.selectSlide(index);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
this.engine.handleDragEnd();
|
|
742
|
+
this.isDraggingPointer = false;
|
|
743
|
+
// Release pointer capture if it was captured
|
|
744
|
+
try {
|
|
745
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
746
|
+
}
|
|
747
|
+
catch { }
|
|
748
|
+
}
|
|
749
|
+
resolvePlugins(config) {
|
|
750
|
+
const runtimePlugins = [];
|
|
751
|
+
const cfg = config.plugins ?? {}; // <-- safe fallback
|
|
752
|
+
if (cfg.draggable)
|
|
753
|
+
runtimePlugins.push(this.draggable);
|
|
754
|
+
if (cfg.pagination)
|
|
755
|
+
runtimePlugins.push(this.pagination);
|
|
756
|
+
if (cfg.navigation)
|
|
757
|
+
runtimePlugins.push(this.navigation);
|
|
758
|
+
if (cfg.autoplay) {
|
|
759
|
+
this.autoplay.setConfig(cfg.autoplay);
|
|
760
|
+
runtimePlugins.push(this.autoplay);
|
|
761
|
+
}
|
|
762
|
+
this.engine.init({ ...config, plugins: undefined }, runtimePlugins);
|
|
763
|
+
if (cfg.navigation) {
|
|
764
|
+
setTimeout(() => this.navigation?.updateArrows?.());
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SimpleSliderComponent, deps: [{ token: SliderEngine }, { token: SliderStore }, { token: SliderDraggablePlugin }, { token: SliderPaginationPlugin }, { token: SliderNavigationPlugin }, { token: SliderAutoplayPlugin }], target: i0.ɵɵFactoryTarget.Component });
|
|
768
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: SimpleSliderComponent, isStandalone: true, selector: "app-simple-slider", inputs: { config: "config", slideTemplate: "slideTemplate", navigationTemplate: "navigationTemplate", paginationTemplate: "paginationTemplate" }, outputs: { slideChange: "slideChange" }, providers: [SliderEngine, SliderStore, SliderDraggablePlugin, SliderPaginationPlugin, SliderNavigationPlugin, SliderAutoplayPlugin], viewQueries: [{ propertyName: "sliderHost", first: true, predicate: ["sliderHost"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"state$ | async as state\">\r\n <div\r\n class=\"slider\"\r\n #sliderHost\r\n [class.slider-vertical]=\"state.vertical\"\r\n [class.slider-draggable]=\"state.isDragging\"\r\n [class.slider--main]=\"!config.isThumbs\"\r\n [class.slider--thumbs]=\"config.isThumbs\"\r\n *ngIf=\"state.visibleSlides?.length > 0 && state.isVisible\"\r\n (pointerdown)=\"onPointerDown($event)\"\r\n (pointermove)=\"onPointerMove($event)\"\r\n (pointerup)=\"onPointerUp($event)\"\r\n (pointercancel)=\"onPointerUp($event)\">\r\n <div\r\n class=\"slider__wrapper\"\r\n [ngStyle]=\"{\r\n transform: state.translate,\r\n transition: draggable.isDraggingPointer ? 'none' : 'transform 0.3s ease',\r\n display: 'flex',\r\n 'flex-direction': state.vertical ? 'column' : 'row',\r\n 'justify-content': state.visibleSlides?.length < state.slidesPerView ? 'center' : 'flex-start',\r\n gap: (state.slidesPerView > 1 ? state.gap || 0 : 0) + 'px',\r\n }\">\r\n <div\r\n *ngFor=\"let slide of state.visibleSlides; let i = index\"\r\n class=\"slide\"\r\n [attr.data-index]=\"i\"\r\n [class.slide--current]=\"state.selectedSlide === i\"\r\n [style.flex]=\"\r\n !config.isThumbs\r\n ? '0 0 calc(' +\r\n 100 / state.slidesPerView +\r\n '% - ' +\r\n ((state.gap || 0) * (state.slidesPerView - 1)) / state.slidesPerView +\r\n 'px)'\r\n : '0 0 ' + thumbSize + 'px'\r\n \"\r\n [style.width]=\"config.isThumbs ? thumbSize + 'px' : null\"\r\n [style.height]=\"config.isThumbs ? thumbSize + 'px' : null\"\r\n (click)=\"engine.selectSlide(i)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"slideTemplate ? slideTemplate : defaultSlideTemplate; context: { slide: slide, index: i }\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n</ng-container>\r\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i7.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
769
|
+
}
|
|
770
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SimpleSliderComponent, decorators: [{
|
|
771
|
+
type: Component,
|
|
772
|
+
args: [{ selector: "app-simple-slider", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: true, imports: [CommonModule], providers: [SliderEngine, SliderStore, SliderDraggablePlugin, SliderPaginationPlugin, SliderNavigationPlugin, SliderAutoplayPlugin], template: "<ng-container *ngIf=\"state$ | async as state\">\r\n <div\r\n class=\"slider\"\r\n #sliderHost\r\n [class.slider-vertical]=\"state.vertical\"\r\n [class.slider-draggable]=\"state.isDragging\"\r\n [class.slider--main]=\"!config.isThumbs\"\r\n [class.slider--thumbs]=\"config.isThumbs\"\r\n *ngIf=\"state.visibleSlides?.length > 0 && state.isVisible\"\r\n (pointerdown)=\"onPointerDown($event)\"\r\n (pointermove)=\"onPointerMove($event)\"\r\n (pointerup)=\"onPointerUp($event)\"\r\n (pointercancel)=\"onPointerUp($event)\">\r\n <div\r\n class=\"slider__wrapper\"\r\n [ngStyle]=\"{\r\n transform: state.translate,\r\n transition: draggable.isDraggingPointer ? 'none' : 'transform 0.3s ease',\r\n display: 'flex',\r\n 'flex-direction': state.vertical ? 'column' : 'row',\r\n 'justify-content': state.visibleSlides?.length < state.slidesPerView ? 'center' : 'flex-start',\r\n gap: (state.slidesPerView > 1 ? state.gap || 0 : 0) + 'px',\r\n }\">\r\n <div\r\n *ngFor=\"let slide of state.visibleSlides; let i = index\"\r\n class=\"slide\"\r\n [attr.data-index]=\"i\"\r\n [class.slide--current]=\"state.selectedSlide === i\"\r\n [style.flex]=\"\r\n !config.isThumbs\r\n ? '0 0 calc(' +\r\n 100 / state.slidesPerView +\r\n '% - ' +\r\n ((state.gap || 0) * (state.slidesPerView - 1)) / state.slidesPerView +\r\n 'px)'\r\n : '0 0 ' + thumbSize + 'px'\r\n \"\r\n [style.width]=\"config.isThumbs ? thumbSize + 'px' : null\"\r\n [style.height]=\"config.isThumbs ? thumbSize + 'px' : null\"\r\n (click)=\"engine.selectSlide(i)\">\r\n <ng-container\r\n *ngTemplateOutlet=\"slideTemplate ? slideTemplate : defaultSlideTemplate; context: { slide: slide, index: i }\"></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n</ng-container>\r\n" }]
|
|
773
|
+
}], ctorParameters: () => [{ type: SliderEngine }, { type: SliderStore }, { type: SliderDraggablePlugin }, { type: SliderPaginationPlugin }, { type: SliderNavigationPlugin }, { type: SliderAutoplayPlugin }], propDecorators: { config: [{
|
|
774
|
+
type: Input
|
|
775
|
+
}], slideTemplate: [{
|
|
776
|
+
type: Input
|
|
777
|
+
}], navigationTemplate: [{
|
|
778
|
+
type: Input
|
|
779
|
+
}], paginationTemplate: [{
|
|
780
|
+
type: Input
|
|
781
|
+
}], slideChange: [{
|
|
782
|
+
type: Output
|
|
783
|
+
}], sliderHost: [{
|
|
784
|
+
type: ViewChild,
|
|
785
|
+
args: ["sliderHost", { static: false }]
|
|
786
|
+
}] } });
|
|
787
|
+
|
|
788
|
+
class NgxEdgeSliderModule {
|
|
789
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxEdgeSliderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
790
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: NgxEdgeSliderModule, imports: [SimpleSliderComponent], exports: [SimpleSliderComponent] });
|
|
791
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxEdgeSliderModule, imports: [SimpleSliderComponent] });
|
|
792
|
+
}
|
|
793
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgxEdgeSliderModule, decorators: [{
|
|
794
|
+
type: NgModule,
|
|
795
|
+
args: [{
|
|
796
|
+
imports: [SimpleSliderComponent],
|
|
797
|
+
exports: [SimpleSliderComponent],
|
|
798
|
+
}]
|
|
799
|
+
}] });
|
|
800
|
+
|
|
801
|
+
class SafeUrlPipe {
|
|
802
|
+
sanitizer;
|
|
803
|
+
constructor(sanitizer) {
|
|
804
|
+
this.sanitizer = sanitizer;
|
|
805
|
+
}
|
|
806
|
+
transform(url) {
|
|
807
|
+
return this.sanitizer.bypassSecurityTrustResourceUrl(url);
|
|
808
|
+
}
|
|
809
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SafeUrlPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
|
|
810
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: SafeUrlPipe, name: "safeUrl" });
|
|
811
|
+
}
|
|
812
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SafeUrlPipe, decorators: [{
|
|
813
|
+
type: Pipe,
|
|
814
|
+
args: [{ name: "safeUrl" }]
|
|
815
|
+
}], ctorParameters: () => [{ type: i1.DomSanitizer }] });
|
|
816
|
+
|
|
817
|
+
// components
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* Generated bundle index. Do not edit.
|
|
821
|
+
*/
|
|
822
|
+
|
|
823
|
+
export { DEFAULT_CONFIG, INITIAL_SLIDER_STATE, NgxEdgeSliderModule, SafeUrlPipe, SimpleSliderComponent, SliderAutoplayPlugin, SliderDraggablePlugin, SliderEngine, SliderNavigationPlugin, SliderPaginationPlugin, SliderStore };
|
|
824
|
+
//# sourceMappingURL=WingmanColt-ngx-edge-slider.mjs.map
|