ngx-edge-slider 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/ngx-edge-slider-workspace/.editorconfig +16 -0
  2. package/ngx-edge-slider-workspace/.vscode/extensions.json +4 -0
  3. package/ngx-edge-slider-workspace/.vscode/launch.json +20 -0
  4. package/ngx-edge-slider-workspace/.vscode/tasks.json +42 -0
  5. package/ngx-edge-slider-workspace/README.md +27 -0
  6. package/ngx-edge-slider-workspace/angular.json +140 -0
  7. package/ngx-edge-slider-workspace/package-lock.json +13339 -0
  8. package/ngx-edge-slider-workspace/package.json +39 -0
  9. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/README.md +24 -0
  10. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/ng-package.json +7 -0
  11. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/package.json +12 -0
  12. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/assets/icons/arrow-black.svg +3 -0
  13. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/assets/icons/arrow-gray.svg +3 -0
  14. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/ngx-edge-slider.component.html +78 -0
  15. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/ngx-edge-slider.component.scss +344 -0
  16. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/ngx-edge-slider.component.ts +610 -0
  17. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/ngx-edge-slider.interface.ts +34 -0
  18. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/ngx-edge-slider.module.ts +18 -0
  19. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/lib/ngx-edge-slider.service.ts +9 -0
  20. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/src/public-api.ts +7 -0
  21. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/tsconfig.lib.json +14 -0
  22. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/tsconfig.lib.prod.json +10 -0
  23. package/ngx-edge-slider-workspace/projects/ngx-edge-slider/tsconfig.spec.json +14 -0
  24. package/ngx-edge-slider-workspace/projects/test-app/src/app/app.component.html +11 -0
  25. package/ngx-edge-slider-workspace/projects/test-app/src/app/app.component.scss +0 -0
  26. package/ngx-edge-slider-workspace/projects/test-app/src/app/app.component.spec.ts +27 -0
  27. package/ngx-edge-slider-workspace/projects/test-app/src/app/app.component.ts +57 -0
  28. package/ngx-edge-slider-workspace/projects/test-app/src/app/app.module.ts +18 -0
  29. package/ngx-edge-slider-workspace/projects/test-app/src/assets/.gitkeep +0 -0
  30. package/ngx-edge-slider-workspace/projects/test-app/src/assets/slide2_desktop_1950x.webp +0 -0
  31. package/ngx-edge-slider-workspace/projects/test-app/src/favicon.ico +0 -0
  32. package/ngx-edge-slider-workspace/projects/test-app/src/index.html +13 -0
  33. package/ngx-edge-slider-workspace/projects/test-app/src/main.ts +7 -0
  34. package/ngx-edge-slider-workspace/projects/test-app/src/styles.scss +1 -0
  35. package/ngx-edge-slider-workspace/projects/test-app/tsconfig.app.json +14 -0
  36. package/ngx-edge-slider-workspace/projects/test-app/tsconfig.spec.json +14 -0
  37. package/ngx-edge-slider-workspace/tsconfig.json +39 -0
  38. package/package.json +24 -0
@@ -0,0 +1,610 @@
1
+ import { Component, Input, OnInit, OnDestroy, ChangeDetectionStrategy, EventEmitter, Output, TemplateRef, ViewEncapsulation } from '@angular/core';
2
+ import { SlideBreakpointConfig, SlideConfig } from './ngx-edge-slider.interface';
3
+ import { throttle } from 'lodash';
4
+
5
+ @Component({
6
+ selector: 'lib-ngx-edge-slider',
7
+ templateUrl: './ngx-edge-slider.component.html',
8
+ styleUrls: ['./ngx-edge-slider.component.scss'],
9
+ changeDetection: ChangeDetectionStrategy.OnPush,
10
+ encapsulation: ViewEncapsulation.Emulated, // Disable view encapsulation
11
+ })
12
+ export class NgxEdgeSliderComponent implements OnInit, OnDestroy {
13
+ @Input() slideTemplate!: TemplateRef<any>;
14
+ @Input() config: Partial<SlideConfig> = {};
15
+
16
+ @Output() onSlideChange = new EventEmitter<number>();
17
+ @Output() onSlideClick = new EventEmitter<number>();
18
+
19
+ currentSlide: number = 0;
20
+ selectedSlide: number = -1;
21
+ slideChanging: boolean = false;
22
+
23
+ slidesPerViewAdjusted = 1;
24
+ visibleSlides: any[] = [];
25
+
26
+ currentPage: number = 1; // Starting page
27
+ visibleDots: number[] = []; // Array holding visible dots (page numbers)
28
+ pager: any;
29
+
30
+ translateStyle = 'translateX(0)'; // CSS transform for translation
31
+ shouldTranslate = false; // Flag to control translation
32
+ isMobile: boolean = false;
33
+
34
+ private isForwardNavigation = true;
35
+ private autoPlayInterval: number | null = null;
36
+ private debounceTimer: any | null = null;
37
+ private clickBlocked = false;
38
+
39
+ // Declare the clicked anchor element and whether dragging is in progress
40
+ public isDragStarted = false;
41
+ private isDragging = false; // Flag to track dragging state
42
+ private startX: number = 0;
43
+ private startY: number = 0;
44
+
45
+ private isVerticalScrolling = false; // Flag to track vertical scrolling
46
+ private maxVerticalDeviation = 20;
47
+ private minSwipeDistance = 10;
48
+ private largeSwipeThreshold: number = 50; // This sets the minimum distance (in pixels) for a swipe to be considered "large." If the swipe distance (deltaX) is greater than this threshold, the default slide step (e.g., slidesToSlide or slidesPerViewAdjusted) will be used. If it's less, only one slide is moved.
49
+
50
+ private onMoveThrottled: any;
51
+ private handleResize = throttle(() => {
52
+ this.updateSlider();
53
+ }, 100);
54
+
55
+ ngOnInit() {
56
+ this.sliderInit();
57
+ }
58
+
59
+ ngOnDestroy() {
60
+ this.sliderDestroy();
61
+ }
62
+
63
+ sliderInit() {
64
+ // Check if slides are provided; if not, exit early
65
+ if (!this.config.slides || this.config.slides.length <= 0) {
66
+ console.warn('EdgeSlider: No slides provided. Initialization aborted.');
67
+ return;
68
+ }
69
+
70
+ this.onMoveThrottled = throttle(this.onMove.bind(this), 20);
71
+ this.config.slidesToSlide = this.config.slidesToSlide ?? this.slidesPerViewAdjusted;
72
+
73
+ // If the slides array is empty or only has one or two slides, disable looping
74
+ if (this.config.slides?.length <= 2) {
75
+ this.config.loop = 0;
76
+ }
77
+
78
+ this.config = { ...this.config }; // Copy config for local use
79
+ this.updateSlider();
80
+
81
+ if (this.config.autoPlay) {
82
+ this.startAutoPlay();
83
+ }
84
+
85
+ // Initialize slidesPerView based on screen size
86
+ window.addEventListener('resize', this.handleResize);
87
+ }
88
+ private calculateSlidesPerView(): void {
89
+ this.shouldTranslate = this.config.slides.length > this.slidesPerViewAdjusted;
90
+ }
91
+
92
+ updateTranslateStyle() {
93
+ // if(this.currentSlide >= (this.config.slides.length - 3))
94
+ // return this.translateStyle = 'none';
95
+ //else {
96
+ return this.translateStyle = this.shouldTranslate
97
+ ? `translate${this.config.vertical ? 'Y' : 'X'}(-${(this.currentSlide * 100) / this.slidesPerViewAdjusted}%)`
98
+ : 'none';
99
+ //}
100
+ }
101
+
102
+ private updateConfigForBreakpoint(): void {
103
+ const width = window.innerWidth;
104
+ const breakpoints = this.config.breakpoints;
105
+
106
+ // Determine which breakpoint to apply based on width
107
+ let breakpointConfig: SlideBreakpointConfig | undefined;
108
+ if (width < 768) {
109
+ breakpointConfig = breakpoints?.mobile;
110
+ this.isMobile = true;
111
+ } else if (width >= 768 && width < 1024) {
112
+ breakpointConfig = breakpoints?.tablet;
113
+ this.isMobile = false;
114
+ } else if (width >= 1024) {
115
+ breakpointConfig = breakpoints?.desktop;
116
+ this.isMobile = false;
117
+ }
118
+
119
+ // Merge the selected breakpoint configuration into `this.config`
120
+ // Use spread syntax to create a new configuration while keeping defaults
121
+ this.config = new SlideConfig({
122
+ ...this.config, // Base config
123
+ ...breakpointConfig // Override with breakpoint-specific settings if any
124
+ });
125
+
126
+ // Adjust slidesPerView and any other property for internal use
127
+ this.slidesPerViewAdjusted = this.config.slidesPerView ?? 1;
128
+ //this.updateVisibleSlides();
129
+ }
130
+
131
+
132
+ private updateSlider(): void {
133
+ if (!this.config.slides || this.config.slides.length <= 0) {
134
+ console.warn('EdgeSlider: No slides provided. Initialization aborted.');
135
+ return;
136
+ }
137
+
138
+ this.updateConfigForBreakpoint(); // Apply initial configuration
139
+ this.updateVisibleSlides();
140
+ this.calculateSlidesPerView();
141
+ this.pager = this.getPaginationPager(this.config.slides.length, this.currentPage, this.slidesPerViewAdjusted);
142
+ }
143
+
144
+ private startAutoPlay(): void {
145
+ if (!this.config.slides || this.config.slides.length <= 1)
146
+ return;
147
+
148
+ const play = () => {
149
+ this.onNextClick();
150
+ this.autoPlayInterval = requestAnimationFrame(play);
151
+ };
152
+
153
+ this.autoPlayInterval = requestAnimationFrame(play);
154
+ }
155
+
156
+ private stopAutoPlay(): void {
157
+ if (this.autoPlayInterval) {
158
+ cancelAnimationFrame(this.autoPlayInterval);
159
+ this.autoPlayInterval = null;
160
+ }
161
+ }
162
+ private calculateSlideStep(currentIndex: number, isSwipe: boolean, deltaX?: number): number {
163
+ const slidesToSlide = this.config.slidesToSlide || 0;
164
+ const totalSlides = this.config.slides?.length;
165
+ // Use a default slide step for button clicks or large swipes
166
+ if (!isSwipe || Math.abs(deltaX) > this.largeSwipeThreshold) {
167
+ if (slidesToSlide === 0 || slidesToSlide >= this.slidesPerViewAdjusted) {
168
+ return this.slidesPerViewAdjusted;
169
+ }
170
+
171
+ const slidesLeft = totalSlides - currentIndex - this.slidesPerViewAdjusted;
172
+ return slidesLeft < slidesToSlide ? slidesLeft : slidesToSlide;
173
+ }
174
+
175
+ // For small swipes, only move by 1 slide
176
+ return totalSlides > 1 ? this.config.slidesToSlide : 1;
177
+ }
178
+
179
+ onNextClick(slideStep?: number, targetIndex?: number): void {
180
+ if (!this.config.slides || this.config.slides.length <= 1 || this.clickBlocked)
181
+ return;
182
+
183
+ this.isForwardNavigation = true;
184
+ this.slideChanging = true;
185
+
186
+ // If a targetIndex is provided, navigate directly to that index.
187
+ if (targetIndex !== undefined) {
188
+ this.currentSlide = targetIndex;
189
+ } else {
190
+ slideStep = slideStep ?? this.calculateSlideStep(this.currentSlide, false);
191
+
192
+ if (this.config.loop === 2) { // Infinite loop
193
+ this.currentSlide = (this.currentSlide + slideStep) % this.config.slides.length;
194
+ } else if (this.config.loop === 1) { // Loop back to start
195
+ const remainingSlides = this.config.slides.length - this.slidesPerViewAdjusted;
196
+ this.currentSlide = (this.currentSlide + slideStep) > remainingSlides ? 0 : this.currentSlide + slideStep;
197
+ } else { // No loop
198
+ const remainingSlides = this.config.slides.length - this.slidesPerViewAdjusted;
199
+ this.currentSlide = Math.min(remainingSlides, this.currentSlide + slideStep);
200
+ }
201
+ }
202
+
203
+ this.emitSlideChange();
204
+ }
205
+
206
+ onPreviousClick(slideStep?: number, targetIndex?: number): void {
207
+ if (!this.config.slides || this.config.slides.length <= 1 || this.clickBlocked)
208
+ return;
209
+
210
+ this.isForwardNavigation = false;
211
+ this.slideChanging = true;
212
+
213
+ // If a targetIndex is provided, navigate directly to that index.
214
+ if (targetIndex !== undefined) {
215
+ this.currentSlide = targetIndex;
216
+ } else {
217
+ slideStep = slideStep ?? this.calculateSlideStep(this.currentSlide, false);
218
+ if (this.config.loop === 2) { // Infinite loop
219
+ this.currentSlide = (this.currentSlide - slideStep + this.config.slides.length) % this.config.slides.length;
220
+ } else if (this.config.loop === 1) { // Loop back to end
221
+ this.currentSlide = (this.currentSlide - slideStep) < 0 ? this.config.slides.length - this.slidesPerViewAdjusted : this.currentSlide - slideStep;
222
+ } else { // No loop
223
+ this.currentSlide = slideStep > 0 ? Math.max(0, this.currentSlide - slideStep) : 0;
224
+ }
225
+ }
226
+
227
+ this.emitSlideChange();
228
+ }
229
+
230
+ private blockClicks(): void {
231
+ this.clickBlocked = true;
232
+ clearTimeout(this.debounceTimer);
233
+ this.debounceTimer = setTimeout(() => {
234
+ this.clickBlocked = false;
235
+ }, this.config.slideChangeDelay || 500); // Adjust delay as needed
236
+ }
237
+
238
+ private updateVisibleSlides(): void {
239
+ if (!this.isForwardNavigation) return; // Only update if navigating forward
240
+
241
+ const startIndex = this.currentSlide;
242
+ const endIndex = Math.min(this.config.slides.length, startIndex + this.slidesPerViewAdjusted);
243
+
244
+ // Slice the range of slides for this "page"
245
+ this.visibleSlides = this.config.slides.slice(startIndex, endIndex);
246
+
247
+ if (this.config.loop > 0 && endIndex - startIndex < this.slidesPerViewAdjusted) {
248
+ const remainingSlides = this.slidesPerViewAdjusted - (endIndex - startIndex);
249
+ this.visibleSlides = this.visibleSlides.concat(this.config.slides.slice(0, remainingSlides));
250
+ }
251
+
252
+ }
253
+
254
+ handleOnSlideClick(index: number): void {
255
+ if(!this.config.changeToClickedSlide)
256
+ return;
257
+
258
+ if (index < 0 || index >= this.config.slides.length) {
259
+ console.warn(`Invalid index ${index}. It should be between 0 and ${this.config.slides.length - 1}.`);
260
+ return;
261
+ }
262
+
263
+ if(index > -1 && index == this.selectedSlide) {
264
+ this.selectedSlide = -1;
265
+ return
266
+ }
267
+
268
+ // Check if the clicked index is forward or backward compared to the current slide.
269
+ if (index > this.selectedSlide) {
270
+ // Clicked on a later slide (move forward)
271
+ this.onNextClick(undefined, index);
272
+ this.selectedSlide = index;
273
+ } else if (index < this.selectedSlide) {
274
+ // Clicked on an earlier slide (move backward)
275
+ this.onPreviousClick(undefined, index);
276
+ this.selectedSlide = index;
277
+ }
278
+
279
+ this.onSlideClick.emit(index);
280
+ }
281
+
282
+
283
+ private emitSlideChange(): void {
284
+ if(this.isForwardNavigation)
285
+ this.paginationNextPage();
286
+ else
287
+ this.paginationPreviousPage();
288
+
289
+ this.updateVisibleSlides();
290
+ this.blockClicks();
291
+ this.updateTranslateStyle();
292
+
293
+ //setTimeout(()=> { this.slideChanging = false; }, 1000); // anim duration time
294
+ this.slideChanging = false;
295
+ this.onSlideChange.emit(this.currentSlide);
296
+ }
297
+
298
+ private getPaginationPager(totalSlides: number, currentPage: number = 1, slidesPerPage: number = 5) {
299
+ // Calculate total pages based on totalSlides and slidesPerPage
300
+ let totalPages = Math.ceil(totalSlides / slidesPerPage);
301
+
302
+ // Paginate Range: Show at most 4 dots at a time
303
+ let paginateRange = 4;
304
+
305
+ // Ensure currentPage isn't out of range
306
+ if (currentPage < 1) {
307
+ currentPage = 1;
308
+ } else if (currentPage > totalPages) {
309
+ currentPage = totalPages;
310
+ }
311
+
312
+ let startDot: number, endDot: number;
313
+
314
+ // When there are fewer than 4 pages, show all dots
315
+ if (totalPages <= paginateRange) {
316
+ startDot = 1;
317
+ endDot = totalPages;
318
+ } else if (currentPage <= paginateRange - 2) {
319
+ // First page group (showing the first 4 dots)
320
+ startDot = 1;
321
+ endDot = paginateRange;
322
+ } else if (currentPage >= totalPages - 1) {
323
+ // Last page group (show the last 4 dots)
324
+ startDot = totalPages - paginateRange + 1;
325
+ endDot = totalPages;
326
+ } else {
327
+ // Middle pages, showing 4 dots around the currentPage
328
+ startDot = currentPage - 1;
329
+ endDot = currentPage + 2;
330
+ }
331
+
332
+ // Ensure the dots stay within bounds
333
+ startDot = Math.max(startDot, 1); // Ensure the start dot doesn't go below 1
334
+ endDot = Math.min(endDot, totalPages); // Ensure the end dot doesn't go beyond total pages
335
+
336
+ // Create an array of visible dots (pages to show in the pager)
337
+ let visibleDots = Array.from({ length: endDot - startDot + 1 }, (_, i) => startDot + i);
338
+
339
+ // Return pager object with properties for pagination
340
+ return {
341
+ totalSlides: totalSlides,
342
+ currentPage: currentPage,
343
+ slidesPerPage: slidesPerPage,
344
+ totalPages: totalPages,
345
+ startDot: startDot,
346
+ endDot: endDot,
347
+ visibleDots: visibleDots,
348
+ };
349
+ }
350
+
351
+ paginationNextPage() {
352
+ if (this.pager.currentPage < this.pager.totalPages) {
353
+ // Move to the next page
354
+ this.pager.currentPage++;
355
+
356
+ // Update pager with new dot range
357
+ this.pager = this.getPaginationPager(this.config.slides.length, this.pager.currentPage, this.slidesPerViewAdjusted);
358
+ }
359
+ }
360
+
361
+ paginationPreviousPage() {
362
+ if (this.pager.currentPage > 1) {
363
+ // Move to the previous page
364
+ this.pager.currentPage--;
365
+
366
+ // Update pager with new dot range
367
+ this.pager = this.getPaginationPager(this.config.slides.length, this.pager.currentPage, this.slidesPerViewAdjusted);
368
+ }
369
+ }
370
+
371
+ isSlideActive(index: number): boolean {
372
+ // Check if the currentSlide index matches the given index
373
+ return this.currentSlide === index ||
374
+ (index === 0 && this.currentSlide === this.config.slides?.length) || // Wrap-around for the last slide to the first
375
+ (index === this.config.slides?.length - 1 && this.currentSlide === -1); // Wrap-around for the first slide to the last
376
+ }
377
+
378
+ isCurrentSlide(index: number): boolean {
379
+ return index === this.currentSlide;
380
+ }
381
+
382
+ get activeSlideIndex(): number {
383
+ return this.currentSlide;
384
+ }
385
+
386
+ get isPreviousDisabled(): boolean {
387
+ return this.config.loop === 0 && this.currentSlide === 0;
388
+ }
389
+
390
+ get isNextDisabled(): boolean {
391
+ const totalSlides = this.config.slides?.length || 0;
392
+ // Check if looping is disabled, and if the currentSlide is the last visible slide
393
+ return this.config.loop === 0 && (this.currentSlide >= totalSlides - this.slidesPerViewAdjusted);
394
+ }
395
+
396
+ get slideWidth(): string {
397
+ return `calc(100% / ${this.slidesPerViewAdjusted})`;
398
+ }
399
+
400
+ get canClickPrevious(): boolean {
401
+ // Check if clicking the previous button is allowed
402
+ if (this.config.loop === 2) {
403
+ // Infinite loop, always allow
404
+ return true;
405
+ }
406
+
407
+ if (this.config.loop === 1) {
408
+ // Loop back to the end if at the start
409
+ return true;
410
+ }
411
+
412
+ // Non-looping, disable if at the first slide
413
+ return this.currentSlide > 0;
414
+ }
415
+
416
+ get canClickNext(): boolean {
417
+ // Check if clicking the next button is allowed
418
+ if (this.config.loop === 2) {
419
+ // Infinite loop, always allow
420
+ return true;
421
+ }
422
+
423
+ if (this.config.loop === 1) {
424
+ // Loop back to the start if at the end
425
+ return true;
426
+ }
427
+
428
+ // Non-looping, disable if at the last visible slide
429
+ const totalSlides = this.config.slides?.length || 0;
430
+ return this.currentSlide < totalSlides - this.slidesPerViewAdjusted;
431
+ }
432
+
433
+ trackBySlideId(index: number, slide: any): number {
434
+ return slide.id;
435
+ }
436
+
437
+ sliderDestroy(): void {
438
+ if (this.onMoveThrottled) {
439
+ this.onMoveThrottled.cancel(); // Cancel any pending throttled actions
440
+ }
441
+
442
+ this.stopAutoPlay();
443
+
444
+ this.config = undefined;
445
+ this.slideTemplate = undefined;
446
+
447
+ // Manually reset any other properties
448
+ this.isDragStarted = undefined;
449
+ this.isDragging = undefined;
450
+
451
+ this.startX = undefined;
452
+ this.startY = undefined;
453
+
454
+ this.currentSlide = undefined;
455
+ this.selectedSlide = undefined;
456
+ this.slideChanging = undefined;
457
+
458
+ this.slidesPerViewAdjusted = undefined;
459
+ this.visibleSlides = undefined;
460
+
461
+ this.translateStyle = undefined; // CSS transform for translation
462
+ this.shouldTranslate = undefined; // Flag to control translation
463
+
464
+ this.isForwardNavigation = undefined;
465
+ this.autoPlayInterval = undefined;
466
+ this.debounceTimer = undefined;
467
+ this.clickBlocked = undefined;
468
+
469
+ this.minSwipeDistance = undefined;
470
+ this.maxVerticalDeviation = undefined;
471
+ this.largeSwipeThreshold = undefined;
472
+
473
+ window.removeEventListener('resize', this.handleResize);
474
+ }
475
+
476
+
477
+ onStart(event: MouseEvent | TouchEvent): void {
478
+ const e = event instanceof MouseEvent ? event : event.touches[0];
479
+ if (this.config.draggable) {
480
+ const target = e.target as HTMLElement;
481
+
482
+ // Check if the element or any of its ancestors has the 'drag-handle' class
483
+ if (target.closest('.drag-handle')) {
484
+ this.isDragStarted = true;
485
+ this.isDragging = false; // Reset dragging state
486
+ this.isVerticalScrolling = false; // Reset vertical scrolling state
487
+
488
+ this.startX = e.clientX || e.pageX;
489
+ this.startY = e.clientY || e.pageY;
490
+
491
+ // Activate the drag handle
492
+ const dragHandle = document.querySelector('.drag-handle');
493
+ if (dragHandle) {
494
+ dragHandle.classList.add('active');
495
+ }
496
+ }
497
+
498
+ /* if (['IMG', 'A', 'P', 'BUTTON', 'DIV', 'SPAN'].includes(target.tagName)) {
499
+ this.isDragStarted = true;
500
+ this.isDragging = true; // Start dragging
501
+ this.startX = e.clientX || e.pageX;
502
+ this.startY = e.clientY || e.pageY; // Track initial Y for scroll detection
503
+
504
+ if (target.tagName === 'A') {
505
+ this.anchorClicked = target as HTMLAnchorElement;
506
+ }
507
+ // Add dragging class to disable pointer events for other content
508
+ document.querySelector('.slide-content')?.classList.add('dragging');
509
+
510
+ // Activate the drag handle
511
+ const dragHandle = document.querySelector('.drag-handle');
512
+ if (dragHandle) {
513
+ dragHandle.classList.add('active');
514
+ }
515
+ }
516
+ */
517
+ }
518
+ }
519
+
520
+
521
+
522
+ onMove(event: MouseEvent | TouchEvent): void {
523
+ if (!this.isDragStarted) return;
524
+
525
+ const e = event instanceof MouseEvent ? event : event.touches[0];
526
+ const deltaX = (e.clientX || e.pageX) - this.startX;
527
+ const deltaY = (e.clientY || e.pageY) - this.startY;
528
+
529
+ // Detect vertical scrolling
530
+ if (!this.isDragging && Math.abs(deltaY) > this.maxVerticalDeviation && Math.abs(deltaY) > Math.abs(deltaX)) {
531
+ this.isVerticalScrolling = true; // Allow scrolling
532
+ this.isDragStarted = false; // Stop dragging logic
533
+ return;
534
+ }
535
+
536
+
537
+ if (Math.abs(deltaX) > this.minSwipeDistance && Math.abs(deltaY) < this.maxVerticalDeviation) {
538
+ event.preventDefault();
539
+ this.isDragging = true;
540
+
541
+ const isSwipeRight = deltaX > 0;
542
+ const slideStep = this.calculateSlideStep(this.currentSlide, true, deltaX);
543
+
544
+ if (isSwipeRight) {
545
+ this.onPreviousClick(slideStep);
546
+ } else {
547
+ this.onNextClick(slideStep);
548
+ }
549
+
550
+ // Reset dragging state after navigation
551
+ this.isDragStarted = false;
552
+ }
553
+
554
+ }
555
+
556
+ // Use throttle to improve performance
557
+ onThrottledMove(event: MouseEvent | TouchEvent): void {
558
+ // Block if dragging is in progress
559
+ if (this.isDragging) {
560
+ event.preventDefault();
561
+ return;
562
+ }
563
+
564
+ this.onMoveThrottled(event);
565
+ }
566
+
567
+
568
+ onEnd(event: MouseEvent | TouchEvent): void {
569
+ if (!this.isDragStarted) return;
570
+
571
+ const e = event instanceof MouseEvent ? event : event.changedTouches[0];
572
+ const deltaX = (e.clientX || e.pageX) - this.startX;
573
+
574
+ // Detect and navigate based on swipe distance
575
+ if (!this.isVerticalScrolling && Math.abs(deltaX) > this.minSwipeDistance) {
576
+ const isSwipeRight = deltaX > 0;
577
+ const slideStep = this.calculateSlideStep(this.currentSlide, true, deltaX);
578
+
579
+ if (isSwipeRight) {
580
+ this.onPreviousClick(slideStep);
581
+ } else {
582
+ this.onNextClick(slideStep);
583
+ }
584
+ }
585
+
586
+ const dragHandle = document.querySelector('.drag-handle');
587
+ if (dragHandle) {
588
+ dragHandle.classList.remove('active');
589
+ }
590
+
591
+ // Reset dragging state
592
+ this.isDragStarted = false;
593
+ this.isDragging = false;
594
+ this.isVerticalScrolling = false;
595
+ }
596
+
597
+
598
+ onLeave(): void {
599
+ this.isDragStarted = false;
600
+ this.isDragging = false; // End dragging
601
+ this.isVerticalScrolling = false; // Reset vertical scrolling flag
602
+
603
+ const dragHandle = document.querySelector('.drag-handle');
604
+ if (dragHandle) {
605
+ dragHandle.classList.remove('active');
606
+ }
607
+
608
+ }
609
+
610
+ }
@@ -0,0 +1,34 @@
1
+ export class SlideConfig {
2
+ title?: string;
3
+ titlePosition?: string;
4
+
5
+ draggable?:boolean = false;
6
+ slides: any[] = [];
7
+ slidesToSlide: number = 1;
8
+ slideChangeDelay: number = 300;
9
+ slidesPerView: number = 1;
10
+ slideWidth?: number;
11
+ changeToClickedSlide?:boolean;
12
+ autoPlay: boolean = false;
13
+ delay: number = 5000;
14
+ loop: number = 0;
15
+ vertical: boolean = false;
16
+
17
+ navEnabled?: boolean;
18
+ navPosition?: string;
19
+ navHoverable?: boolean = false;
20
+ paginationEnabled?: boolean;
21
+ paginationPosition?: string;
22
+ breakpoints?: SlideBreakpoints;
23
+
24
+ constructor(config?: Partial<SlideConfig>) {
25
+ Object.assign(this, config);
26
+ }
27
+ }
28
+
29
+ export interface SlideBreakpointConfig extends Partial<SlideConfig> { }
30
+ export interface SlideBreakpoints {
31
+ mobile?: SlideBreakpointConfig;
32
+ tablet?: SlideBreakpointConfig;
33
+ desktop?: SlideBreakpointConfig;
34
+ }
@@ -0,0 +1,18 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { NgxEdgeSliderComponent } from './ngx-edge-slider.component';
3
+ import { CommonModule } from '@angular/common';
4
+
5
+
6
+
7
+ @NgModule({
8
+ declarations: [
9
+ NgxEdgeSliderComponent
10
+ ],
11
+ imports: [
12
+ CommonModule
13
+ ],
14
+ exports: [
15
+ NgxEdgeSliderComponent
16
+ ]
17
+ })
18
+ export class NgxEdgeSliderModule { }
@@ -0,0 +1,9 @@
1
+ import { Injectable } from '@angular/core';
2
+
3
+ @Injectable({
4
+ providedIn: 'root'
5
+ })
6
+ export class NgxEdgeSliderService {
7
+
8
+ constructor() { }
9
+ }
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Public API Surface of ngx-edge-slider
3
+ */
4
+
5
+ export * from './lib/ngx-edge-slider.service';
6
+ export * from './lib/ngx-edge-slider.component';
7
+ export * from './lib/ngx-edge-slider.module';
@@ -0,0 +1,14 @@
1
+ /* To learn more about this file see: https://angular.io/config/tsconfig. */
2
+ {
3
+ "extends": "../../tsconfig.json",
4
+ "compilerOptions": {
5
+ "outDir": "../../out-tsc/lib",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "inlineSources": true,
9
+ "types": []
10
+ },
11
+ "exclude": [
12
+ "**/*.spec.ts"
13
+ ]
14
+ }