@rethink-js/rt-slider 1.0.0 → 1.1.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.
package/README.md CHANGED
@@ -4,7 +4,6 @@
4
4
  ![JavaScript](https://img.shields.io/badge/language-JavaScript-F7DF1E?logo=javascript)
5
5
  [![npm version](https://img.shields.io/npm/v/%40rethink-js%2Frt-slider.svg)](https://www.npmjs.com/package/@rethink-js/rt-slider)
6
6
  [![jsDelivr hits](https://data.jsdelivr.com/v1/package/npm/@rethink-js/rt-slider/badge)](https://www.jsdelivr.com/package/npm/@rethink-js/rt-slider)
7
- [![bundle size](https://img.shields.io/bundlephobia/min/%40rethink-js%2Frt-slider)](https://bundlephobia.com/package/@rethink-js/rt-slider)
8
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-FFD632.svg)](https://opensource.org/licenses/MIT)
9
8
 
10
9
  `rt-slider` is a lightweight JavaScript utility that creates touch-friendly sliders with smooth inertia scrolling and physics with:
@@ -42,14 +41,13 @@
42
41
  ### 1.1 CDN (jsDelivr)
43
42
 
44
43
  ```html
45
- <script src="[https://cdn.jsdelivr.net/npm/@rethink-js/rt-slider@latest/dist/index.min.js](https://cdn.jsdelivr.net/npm/@rethink-js/rt-slider@latest/dist/index.min.js)"></script>
44
+ <script src="https://cdn.jsdelivr.net/npm/@rethink-js/rt-slider@latest/dist/index.min.js"></script>
46
45
  ```
47
46
 
48
47
  ### 1.2 npm
49
48
 
50
49
  ```bash
51
50
  npm install @rethink-js/rt-slider
52
-
53
51
  ```
54
52
 
55
53
  Then bundle or load `dist/index.min.js` as appropriate for your build setup.
@@ -77,7 +75,7 @@ Example:
77
75
  </div>
78
76
  </div>
79
77
 
80
- <script src="[https://cdn.jsdelivr.net/npm/@rethink-js/rt-slider@latest/dist/index.min.js](https://cdn.jsdelivr.net/npm/@rethink-js/rt-slider@latest/dist/index.min.js)"></script>
78
+ <script src="https://cdn.jsdelivr.net/npm/@rethink-js/rt-slider@latest/dist/index.min.js"></script>
81
79
  ```
82
80
 
83
81
  > Note: If you do not provide `data-rt-list` and `data-rt-item`, the slider will not initialize.
@@ -176,9 +174,9 @@ Used to pass complex configuration objects directly to the underlying Lenis inst
176
174
 
177
175
  The library automatically loads Lenis from a CDN if not present. You can rely on the default or load your own version before `rt-slider`.
178
176
 
179
- | Attribute | Description |
180
- | ---------------------- | --------------------------------------------------- |
181
- | `data-rt-lenis="true"` | Add this to a script tag to identify external Lenis |
177
+ | Attribute | Description |
178
+ | ----------------------------- | --------------------------------------------------- |
179
+ | `data-rt-slider-lenis="true"` | Add this to a script tag to identify external Lenis |
182
180
 
183
181
  ---
184
182
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @rethink-js/rt-slider v1.0.0 | MIT */
1
+ /*! @rethink-js/rt-slider v1.1.0 | MIT */
2
2
  (() => {
3
3
  // src/index.js
4
4
  (function() {
@@ -9,7 +9,7 @@
9
9
  if (typeof window.Lenis !== "undefined") return Promise.resolve();
10
10
  if (lenisLoadingPromise) return lenisLoadingPromise;
11
11
  lenisLoadingPromise = new Promise(function(resolve, reject) {
12
- var existing = document.querySelector('script[data-rt-lenis="true"]') || document.querySelector('script[src*="lenis"]');
12
+ var existing = document.querySelector('script[data-rt-slider-lenis="true"]') || document.querySelector('script[src*="lenis"]');
13
13
  if (existing) {
14
14
  if (typeof window.Lenis !== "undefined") {
15
15
  resolve();
@@ -25,7 +25,7 @@
25
25
  var s = document.createElement("script");
26
26
  s.src = "https://cdn.jsdelivr.net/npm/lenis@1.3.16/dist/lenis.min.js";
27
27
  s.async = true;
28
- s.dataset.rtLenis = "true";
28
+ s.setAttribute("data-rt-slider-lenis", "true");
29
29
  s.onload = function() {
30
30
  resolve();
31
31
  };
@@ -73,17 +73,21 @@
73
73
  return el.getAttribute(attr);
74
74
  }
75
75
  function injectOnce(key, css) {
76
- var s = document.head.querySelector('[data-rt-injected="' + key + '"]');
76
+ var s = document.head.querySelector(
77
+ '[data-rt-slider-injected="' + key + '"]'
78
+ );
77
79
  if (!s) {
78
80
  s = document.createElement("style");
79
- s.setAttribute("data-rt-injected", key);
81
+ s.setAttribute("data-rt-slider-injected", key);
80
82
  document.head.appendChild(s);
81
83
  }
82
84
  if (s.textContent !== css) s.textContent = css;
83
85
  return s;
84
86
  }
85
87
  function removeInjected(key) {
86
- var s = document.head.querySelector('[data-rt-injected="' + key + '"]');
88
+ var s = document.head.querySelector(
89
+ '[data-rt-slider-injected="' + key + '"]'
90
+ );
87
91
  if (s && s.parentNode) s.parentNode.removeChild(s);
88
92
  }
89
93
  function toSel(v) {
@@ -603,14 +607,58 @@
603
607
  var mr = parseFloat(cs.marginRight) || 0;
604
608
  return Math.max(1, Math.round(w + mr));
605
609
  };
606
- Slider.prototype.scrollByItems = function(n) {
607
- var step = this.itemStepWidth();
608
- var target = n > 0 ? this.scroller.scrollLeft + step * n : this.scroller.scrollLeft - step * Math.abs(n);
609
- var clamped = this.safeClampScroll(target);
610
+ Slider.prototype.getAlignTargetLeft = function() {
611
+ var ref = this.pickVisibleMarginRef();
612
+ if (ref) {
613
+ return ref.getBoundingClientRect().left;
614
+ }
615
+ var sRect = this.scroller.getBoundingClientRect();
616
+ var scrollerCS = getComputedStyle(this.scroller);
617
+ var listCS = getComputedStyle(this.list);
618
+ var scrollerBorderL = parseFloat(scrollerCS.borderLeftWidth || "0") || 0;
619
+ var scrollerPadL = parseFloat(scrollerCS.paddingLeft || "0") || 0;
620
+ var listPadL = parseFloat(listCS.paddingLeft || "0") || 0;
621
+ var gutter = Number.isFinite(this._lastGutterPx) ? this._lastGutterPx : 0;
622
+ return sRect.left + scrollerBorderL + scrollerPadL + listPadL + gutter;
623
+ };
624
+ Slider.prototype.getOrderedItems = function() {
625
+ if (!this.conf.item) return [];
626
+ var nodes = Array.from(this.list.querySelectorAll(this.conf.item));
627
+ return nodes.filter(function(n) {
628
+ return n && n.nodeType === 1;
629
+ });
630
+ };
631
+ Slider.prototype.getCurrentItemIndex = function(items) {
632
+ if (!items || !items.length) return -1;
633
+ var alignLeft = this.getAlignTargetLeft();
634
+ var bestIdx = 0;
635
+ var bestAbs = Infinity;
636
+ for (var i = 0; i < items.length; i++) {
637
+ var r = items[i].getBoundingClientRect();
638
+ var d = r.left - alignLeft;
639
+ var ad = Math.abs(d);
640
+ if (ad < bestAbs) {
641
+ bestAbs = ad;
642
+ bestIdx = i;
643
+ }
644
+ }
645
+ return bestIdx;
646
+ };
647
+ Slider.prototype.scrollAlignToItem = function(el) {
648
+ if (!el) return;
649
+ var total = this.scroller.scrollWidth;
650
+ var visible = this.scroller.clientWidth;
651
+ if (total <= visible + 1) return;
652
+ var alignLeft = this.getAlignTargetLeft();
653
+ var r = el.getBoundingClientRect();
654
+ var delta = r.left - alignLeft;
655
+ if (!Number.isFinite(delta)) return;
656
+ var target = this.safeClampScroll(this.scroller.scrollLeft + delta);
610
657
  if (this.lenis) {
658
+ var duration = 1.2;
611
659
  try {
612
- this.lenis.scrollTo(clamped, {
613
- duration: 1.2,
660
+ this.lenis.scrollTo(target, {
661
+ duration,
614
662
  easing: function(t) {
615
663
  return Math.min(1, 1.001 - Math.pow(2, -10 * t));
616
664
  },
@@ -619,11 +667,46 @@
619
667
  force: true
620
668
  });
621
669
  } catch (e) {
622
- this.scroller.scrollTo({ left: clamped, behavior: "smooth" });
670
+ this.scroller.scrollTo({ left: target, behavior: "smooth" });
623
671
  }
624
672
  } else {
625
- this.scroller.scrollTo({ left: clamped, behavior: "smooth" });
673
+ this.scroller.scrollTo({ left: target, behavior: "smooth" });
674
+ }
675
+ };
676
+ Slider.prototype.scrollByItems = function(n) {
677
+ var total = this.scroller.scrollWidth;
678
+ var visible = this.scroller.clientWidth;
679
+ if (total <= visible + 1) return;
680
+ var items = this.getOrderedItems();
681
+ if (!items.length) {
682
+ var step = this.itemStepWidth();
683
+ var fallback = n > 0 ? this.scroller.scrollLeft + step * n : this.scroller.scrollLeft - step * Math.abs(n);
684
+ var clamped = this.safeClampScroll(fallback);
685
+ if (this.lenis) {
686
+ try {
687
+ this.lenis.scrollTo(clamped, {
688
+ duration: 1.2,
689
+ easing: function(t) {
690
+ return Math.min(1, 1.001 - Math.pow(2, -10 * t));
691
+ },
692
+ immediate: false,
693
+ lock: false,
694
+ force: true
695
+ });
696
+ } catch (e) {
697
+ this.scroller.scrollTo({ left: clamped, behavior: "smooth" });
698
+ }
699
+ } else {
700
+ this.scroller.scrollTo({ left: clamped, behavior: "smooth" });
701
+ }
702
+ return;
626
703
  }
704
+ var curIdx = this.getCurrentItemIndex(items);
705
+ if (curIdx < 0) curIdx = 0;
706
+ var nextIdx = curIdx;
707
+ if (n > 0) nextIdx = Math.min(items.length - 1, curIdx + 1);
708
+ else if (n < 0) nextIdx = Math.max(0, curIdx - 1);
709
+ this.scrollAlignToItem(items[nextIdx]);
627
710
  };
628
711
  Slider.prototype.onPrevClick = function(e) {
629
712
  e.preventDefault();
@@ -966,22 +1049,22 @@
966
1049
  );
967
1050
  };
968
1051
  Slider.prototype.applyListStyles = function() {
969
- var listUID = assignUID(this.list, "data-rt-ss-id");
970
- var scrollerUID = assignUID(this.scroller, "data-rt-ss-scroller-id");
1052
+ var listUID = assignUID(this.list, "data-rt-slider-list-uid");
1053
+ var scrollerUID = assignUID(this.scroller, "data-rt-slider-scroller-uid");
971
1054
  var isDesktop = this.mq.matches;
972
1055
  var scrollbarStyles = "";
973
1056
  if (this.scrollTrack && this.scrollBar) {
974
- var trackUID = assignUID(this.scrollTrack, "data-rt-track-id");
975
- var barUID = assignUID(this.scrollBar, "data-rt-bar-id");
1057
+ var trackUID = assignUID(this.scrollTrack, "data-rt-slider-track-uid");
1058
+ var barUID = assignUID(this.scrollBar, "data-rt-slider-bar-uid");
976
1059
  if (isDesktop) {
977
- scrollbarStyles = '[data-rt-track-id="' + trackUID + '"]{position:relative; touch-action:none; overflow: visible !important;}[data-rt-track-id="' + trackUID + '"]::before{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:0; cursor:pointer; pointer-events:auto;}[data-rt-bar-id="' + barUID + '"]{position:relative; z-index:2; touch-action:none;}[data-rt-bar-id="' + barUID + '"]::after{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:3; cursor:grab; pointer-events:auto;}';
1060
+ scrollbarStyles = '[data-rt-slider-track-uid="' + trackUID + '"]{position:relative; touch-action:none; overflow: visible !important;}[data-rt-slider-track-uid="' + trackUID + '"]::before{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:0; cursor:pointer; pointer-events:auto;}[data-rt-slider-bar-uid="' + barUID + '"]{position:relative; z-index:2; touch-action:none;}[data-rt-slider-bar-uid="' + barUID + '"]::after{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:3; cursor:grab; pointer-events:auto;}';
978
1061
  } else {
979
- scrollbarStyles = '[data-rt-track-id="' + trackUID + '"]{position:relative; touch-action:auto; overflow: visible !important; pointer-events:none !important; user-select:none !important;}[data-rt-track-id="' + trackUID + '"]::before{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:0; pointer-events:none !important;}[data-rt-bar-id="' + barUID + '"]{position:relative; z-index:2; touch-action:auto; pointer-events:none !important; user-select:none !important;}[data-rt-bar-id="' + barUID + '"]::after{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:3; pointer-events:none !important;}';
1062
+ scrollbarStyles = '[data-rt-slider-track-uid="' + trackUID + '"]{position:relative; touch-action:auto; overflow: visible !important; pointer-events:none !important; user-select:none !important;}[data-rt-slider-track-uid="' + trackUID + '"]::before{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:0; pointer-events:none !important;}[data-rt-slider-bar-uid="' + barUID + '"]{position:relative; z-index:2; touch-action:auto; pointer-events:none !important; user-select:none !important;}[data-rt-slider-bar-uid="' + barUID + '"]::after{content:"";position:absolute;top:-30px;bottom:-30px;left:0;right:0;z-index:3; pointer-events:none !important;}';
980
1063
  }
981
1064
  }
982
- var hideNativeScrollbarCSS = '[data-rt-ss-id="' + listUID + '"]::-webkit-scrollbar{width:0 !important;height:0 !important;display:none !important;background:transparent !important;}[data-rt-ss-id="' + listUID + '"]::-webkit-scrollbar-thumb{background:transparent !important;}[data-rt-ss-id="' + listUID + '"]::-webkit-scrollbar-track{background:transparent !important;}[data-rt-ss-id="' + listUID + '"]{scrollbar-width:none !important;-ms-overflow-style:none !important;}[data-rt-ss-scroller-id="' + scrollerUID + '"]::-webkit-scrollbar{width:0 !important;height:0 !important;display:none !important;background:transparent !important;}[data-rt-ss-scroller-id="' + scrollerUID + '"]::-webkit-scrollbar-thumb{background:transparent !important;}[data-rt-ss-scroller-id="' + scrollerUID + '"]::-webkit-scrollbar-track{background:transparent !important;}[data-rt-ss-scroller-id="' + scrollerUID + '"]{scrollbar-width:none !important;-ms-overflow-style:none !important;}';
983
- var iosMaskCSS = isDesktop ? "" : '[data-rt-ss-scroller-id="' + scrollerUID + '"]{position:relative;padding-bottom:calc(var(--rt-slider-base-pb, 0px) + var(--rt-slider-mask-h, 12px));}[data-rt-ss-scroller-id="' + scrollerUID + '"]::after{content:"";position:absolute;left:0;right:0;bottom:0;height:var(--rt-slider-mask-h, 12px);pointer-events:none;z-index:2147483647;background:var(--rt-slider-mask-bg, transparent);}';
984
- var draggingCSS = '[data-rt-ss-scroller-id="' + scrollerUID + '"].is-dragging{cursor:grabbing !important;user-select:none}[data-rt-ss-id="' + listUID + '"].is-dragging{cursor:grabbing !important;user-select:none}[data-rt-ss-scroller-id="' + scrollerUID + '"].is-dragging img,[data-rt-ss-scroller-id="' + scrollerUID + '"].is-dragging a,[data-rt-ss-scroller-id="' + scrollerUID + '"].is-dragging ' + this.conf.item + '{user-select:none;-webkit-user-drag:none}[data-rt-ss-id="' + listUID + '"] img{-webkit-user-drag:none}';
1065
+ var hideNativeScrollbarCSS = '[data-rt-slider-list-uid="' + listUID + '"]::-webkit-scrollbar{width:0 !important;height:0 !important;display:none !important;background:transparent !important;}[data-rt-slider-list-uid="' + listUID + '"]::-webkit-scrollbar-thumb{background:transparent !important;}[data-rt-slider-list-uid="' + listUID + '"]::-webkit-scrollbar-track{background:transparent !important;}[data-rt-slider-list-uid="' + listUID + '"]{scrollbar-width:none !important;-ms-overflow-style:none !important;}[data-rt-slider-scroller-uid="' + scrollerUID + '"]::-webkit-scrollbar{width:0 !important;height:0 !important;display:none !important;background:transparent !important;}[data-rt-slider-scroller-uid="' + scrollerUID + '"]::-webkit-scrollbar-thumb{background:transparent !important;}[data-rt-slider-scroller-uid="' + scrollerUID + '"]::-webkit-scrollbar-track{background:transparent !important;}[data-rt-slider-scroller-uid="' + scrollerUID + '"]{scrollbar-width:none !important;-ms-overflow-style:none !important;}';
1066
+ var iosMaskCSS = isDesktop ? "" : '[data-rt-slider-scroller-uid="' + scrollerUID + '"]{position:relative;padding-bottom:calc(var(--rt-slider-base-pb, 0px) + var(--rt-slider-mask-h, 12px));}[data-rt-slider-scroller-uid="' + scrollerUID + '"]::after{content:"";position:absolute;left:0;right:0;bottom:0;height:var(--rt-slider-mask-h, 12px);pointer-events:none;z-index:2147483647;background:var(--rt-slider-mask-bg, transparent);}';
1067
+ var draggingCSS = '[data-rt-slider-scroller-uid="' + scrollerUID + '"].is-dragging{cursor:grabbing !important;user-select:none}[data-rt-slider-list-uid="' + listUID + '"].is-dragging{cursor:grabbing !important;user-select:none}[data-rt-slider-scroller-uid="' + scrollerUID + '"].is-dragging img,[data-rt-slider-scroller-uid="' + scrollerUID + '"].is-dragging a,[data-rt-slider-scroller-uid="' + scrollerUID + '"].is-dragging ' + this.conf.item + '{user-select:none;-webkit-user-drag:none}[data-rt-slider-list-uid="' + listUID + '"] img{-webkit-user-drag:none}';
985
1068
  this._injectedKey = "rt-ss-" + listUID;
986
1069
  injectOnce(
987
1070
  this._injectedKey,
@@ -1106,11 +1189,11 @@
1106
1189
  this.scrollTrack.addEventListener("pointerdown", this._onTPD);
1107
1190
  this._onTPM = this.onTrackPointerMove.bind(this);
1108
1191
  this.scrollTrack.addEventListener("pointermove", this._onTPM);
1109
- this._onTPU = this.onTrackPointerUp.bind(this);
1192
+ this._onTPU = this.endBarDrag.bind(this);
1110
1193
  this.scrollTrack.addEventListener("pointerup", this._onTPU);
1111
- this._onTPC = this.onTrackPointerCancel.bind(this);
1194
+ this._onTPC = this.endBarDrag.bind(this);
1112
1195
  this.scrollTrack.addEventListener("pointercancel", this._onTPC);
1113
- this._onTPL = this.onTrackPointerCancel.bind(this);
1196
+ this._onTPL = this.endBarDrag.bind(this);
1114
1197
  this.scrollTrack.addEventListener("pointerleave", this._onTPL);
1115
1198
  }
1116
1199
  } else {