use-snap-slider 0.1.4 → 1.0.1

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.
@@ -31,7 +31,10 @@ function createSnapSlider({
31
31
  indexDelta,
32
32
  initalSubscriptionPublish = true,
33
33
  itemSelector = ":scope > *",
34
- debug
34
+ debug,
35
+ scrollTimeThrottle = 500,
36
+ resizeTimeThrottle = 500,
37
+ scrollListenerThreshold = 2
35
38
  }) {
36
39
  let initalIndex = index;
37
40
  let state = {
@@ -175,40 +178,67 @@ function createSnapSlider({
175
178
  }
176
179
  }
177
180
  }
178
- let ticking = false;
181
+ function onScrollEnd() {
182
+ if (element) {
183
+ const scrollLeft = element.scrollLeft;
184
+ const positionItem = itemPositions.reduce((prev, curr) => {
185
+ return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
186
+ });
187
+ const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
188
+ const pxLeftScrolling = Math.abs(scrollLeft - positionItem);
189
+ prevIndexDelta = indexDelta2;
190
+ debug && console.log("onScrollEnd", {
191
+ pxLeftScrolling,
192
+ indexDelta: indexDelta2,
193
+ scrollLeft,
194
+ positionItem,
195
+ itemPositions
196
+ });
197
+ update({
198
+ event: "scroll",
199
+ ...fixIndex({
200
+ index: Math.floor(indexDelta2 / slidesPerPage),
201
+ indexDelta: indexDelta2
202
+ })
203
+ });
204
+ }
205
+ }
179
206
  function onScroll() {
180
- if (!ticking && element) {
207
+ if (element) {
181
208
  const scrollLeft = element.scrollLeft;
182
- window.requestAnimationFrame(() => {
183
- if (muteScrollListner) {
184
- const leftToScroll = Math.abs(left - scrollLeft);
185
- if (leftToScroll < 2) {
186
- muteScrollListner = false;
187
- }
188
- } else {
189
- const positionItem = itemPositions.reduce((prev, curr) => {
190
- return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
209
+ if (muteScrollListner) {
210
+ const leftToScroll = Math.abs(left - scrollLeft);
211
+ if (leftToScroll < 2) {
212
+ muteScrollListner = false;
213
+ }
214
+ } else {
215
+ const positionItem = itemPositions.reduce((prev, curr) => {
216
+ return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
217
+ });
218
+ const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
219
+ const pxLeftScrolling = Math.abs(scrollLeft - positionItem);
220
+ prevIndexDelta = indexDelta2;
221
+ debug && console.log("onScroll", {
222
+ pxLeftScrolling,
223
+ indexDelta: indexDelta2,
224
+ scrollLeft,
225
+ positionItem,
226
+ itemPositions
227
+ });
228
+ if (pxLeftScrolling < scrollListenerThreshold) {
229
+ update({
230
+ event: "scroll",
231
+ ...fixIndex({
232
+ index: Math.floor(indexDelta2 / slidesPerPage),
233
+ indexDelta: indexDelta2
234
+ })
191
235
  });
192
- const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
193
- const pxLeftScrolling = Math.abs(scrollLeft - positionItem);
194
- prevIndexDelta = indexDelta2;
195
- if (pxLeftScrolling < 2) {
196
- update({
197
- event: "scroll",
198
- ...fixIndex({
199
- index: Math.floor(indexDelta2 / slidesPerPage),
200
- indexDelta: indexDelta2
201
- })
202
- });
203
- }
204
236
  }
205
- ticking = false;
206
- });
207
- ticking = true;
237
+ }
208
238
  }
209
239
  }
210
- const onScrollFn = throttle(onScroll, 500);
211
- const onResizeFn = throttle(calculate, 500);
240
+ const onScrollFn = throttle(onScroll, scrollTimeThrottle);
241
+ const onResizeFn = throttle(calculate, resizeTimeThrottle);
212
242
  function setElement(_el) {
213
243
  if (element) {
214
244
  destroy();
@@ -216,7 +246,11 @@ function createSnapSlider({
216
246
  element = _el;
217
247
  updateIndexDelta();
218
248
  calculate();
219
- element == null ? void 0 : element.addEventListener("scroll", onScrollFn);
249
+ if ("onscrollend" in window) {
250
+ element?.addEventListener("scrollend", onScrollEnd);
251
+ } else {
252
+ element?.addEventListener("scroll", onScrollFn);
253
+ }
220
254
  window.addEventListener("resize", onResizeFn);
221
255
  }
222
256
  _element && setElement(_element);
@@ -241,7 +275,11 @@ function createSnapSlider({
241
275
  }
242
276
  };
243
277
  const destroy = () => {
244
- element == null ? void 0 : element.removeEventListener("scroll", onScrollFn);
278
+ if ("onscrollend" in window) {
279
+ element?.removeEventListener("scrollend", onScrollEnd);
280
+ } else {
281
+ element?.removeEventListener("scroll", onScrollFn);
282
+ }
245
283
  window.removeEventListener("resize", onResizeFn);
246
284
  };
247
285
  const goNext = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"snap-slider.cjs","sources":["../lib/throttle.ts","../lib/snap-slider.ts"],"sourcesContent":["export const throttle = (fn: Function, wait: number) => {\n let inThrottle: boolean\n let lastFn: ReturnType<typeof setTimeout>\n let lastTime: number\n return function (this: any) {\n const context = this\n const args = arguments\n if (!inThrottle) {\n fn.apply(context, args)\n lastTime = Date.now()\n inThrottle = true\n } else {\n clearTimeout(lastFn)\n lastFn = setTimeout(() => {\n if (Date.now() - lastTime >= wait) {\n fn.apply(context, args)\n lastTime = Date.now()\n }\n }, Math.max(wait - (Date.now() - lastTime), 0))\n }\n }\n}\n","import { throttle } from './throttle'\n\nexport type TSnapListnerEvent = 'scroll' | 'click' | 'inital' | 'goto'\n\nexport interface TSnapListnerStateIndex {\n index: number\n indexDelta: number\n}\n\nexport interface TSnapSliderState extends TSnapListnerStateIndex {\n count: number\n countDelta: number\n event: TSnapListnerEvent\n}\n\ninterface TSnapSliderStateUpdate {\n index?: number\n indexDelta?: number\n count?: number\n countDelta?: number\n event: TSnapListnerEvent\n}\n\nexport interface TSnapSliderStateFull extends TSnapSliderState {\n prevEnabled: boolean\n nextEnabled: boolean\n}\n\nexport type TSnapListner = (params: TSnapSliderStateFull) => void\n\nexport interface TSnapSliderParams\n extends Omit<TSnapSliderStateUpdate, 'event'> {\n element: HTMLElement | null\n itemSelector?: string\n initalSubscriptionPublish?: boolean\n circular?: boolean\n debug?: boolean\n}\n\nexport type TSnapSliderJumpToFn = (\n index?: number,\n indexDelta?: number,\n event?: TSnapListnerEvent\n) => void\n\nexport interface TSnapSlider {\n destroy: () => void\n getState: () => TSnapSliderStateFull\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n subscribe: (fn: TSnapListner) => () => void\n setElement: (el: HTMLElement) => void\n calculate: () => void\n}\n\nexport function createSnapSlider({\n element: _element,\n count = 1,\n countDelta,\n index = 0,\n circular,\n indexDelta,\n initalSubscriptionPublish = true,\n itemSelector = ':scope > *',\n debug,\n}: TSnapSliderParams): TSnapSlider {\n let initalIndex: number | undefined = index\n let state: TSnapSliderState = {\n index,\n indexDelta: indexDelta || index,\n event: 'inital',\n count,\n countDelta: countDelta || count,\n }\n let prevIndexDelta: number = index\n let slidesPerPage: number = 1\n let itemPositions: number[] = []\n let muteScrollListner: boolean = false\n let left: number = 0\n let element: HTMLElement | null\n function updateIndexDelta() {\n if (element) {\n const prev = element.scrollLeft\n const { indexDelta, event } = state\n left = indexDelta * (element.offsetWidth / slidesPerPage)\n if (prevIndexDelta !== indexDelta) {\n const distance = Math.abs(prev - left)\n const limitInstantScroll = element.offsetWidth * 2\n prevIndexDelta = indexDelta\n muteScrollListner = true\n const behavior: ScrollBehavior =\n distance > limitInstantScroll || event === 'click'\n ? 'instant'\n : 'smooth'\n element.scroll({\n left,\n top: 0,\n behavior,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\n behavior: 'instant',\n })\n initalIndex = undefined\n }\n }\n }\n }\n\n let publishDirty = false\n let listeners: TSnapListner[] = []\n const subscribe = (callback: TSnapListner) => {\n listeners.push(callback)\n if (element && (publishDirty || initalSubscriptionPublish)) {\n callback(getState())\n }\n return () => {\n listeners = listeners.filter((x) => x !== callback)\n if (listeners.length < 1) {\n destroy()\n }\n }\n }\n function notify() {\n listeners.forEach((callback) => {\n callback(getState())\n })\n }\n const getState = (): TSnapSliderStateFull => {\n const { indexDelta, countDelta } = state\n return {\n ...state,\n prevEnabled: circular || indexDelta > 0,\n nextEnabled: circular || countDelta - slidesPerPage > indexDelta,\n }\n }\n function update(params: TSnapSliderStateUpdate) {\n let dirty = false\n let indexDeltaDirty = false\n type TSnapSliderStateUpdateKey = keyof typeof params\n const keys: TSnapSliderStateUpdateKey[] = Object.keys(\n params\n ) as Array<TSnapSliderStateUpdateKey>\n state['event'] = params['event']\n keys.forEach((key) => {\n if (key !== 'event' && state[key] !== params[key]) {\n state[key] = Number(params[key])\n dirty = true\n if (key === 'indexDelta') {\n indexDeltaDirty = true\n }\n }\n })\n if (dirty) {\n publishDirty = listeners.length === 0\n notify()\n if (indexDeltaDirty) {\n updateIndexDelta()\n }\n }\n }\n function fixIndex(nextIndex: TSnapListnerStateIndex): TSnapListnerStateIndex {\n const { index, indexDelta } = nextIndex\n const { countDelta, count } = state\n const last = countDelta - slidesPerPage\n return {\n index: indexDelta < last ? index : count - 1,\n indexDelta,\n }\n }\n function calculate() {\n if (element) {\n let contentWidth = 0\n let itemWidth = 0\n itemPositions = []\n const slides = element.querySelectorAll<HTMLDivElement>(itemSelector)\n slides.forEach((slide) => {\n itemPositions.push(contentWidth)\n contentWidth += slide.clientWidth\n itemWidth = slide.clientWidth\n })\n slidesPerPage = Math.round(element.offsetWidth / itemWidth)\n const countDelta = itemPositions.length\n const count = Math.ceil(countDelta / slidesPerPage)\n const { index } = state\n const resetIndexMayby =\n index + 1 > count\n ? {\n index: 0,\n indexDelta: 0,\n }\n : {}\n\n if (!isNaN(count)) {\n // if element not mounted / hidden not update\n update({\n event: 'inital',\n count,\n countDelta,\n ...resetIndexMayby,\n })\n debug &&\n console.log('update count', {\n count,\n countDelta,\n itemPositions,\n slidesPerPage,\n clientWidth: element.clientWidth,\n offsetWidth: element.offsetWidth,\n itemSelector,\n slides,\n })\n }\n }\n }\n\n let ticking = false\n function onScroll() {\n if (!ticking && element) {\n const scrollLeft = element.scrollLeft\n window.requestAnimationFrame(() => {\n if (muteScrollListner) {\n const leftToScroll = Math.abs(left - scrollLeft)\n if (leftToScroll < 2) {\n muteScrollListner = false\n }\n } else {\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n const pxLeftScrolling = Math.abs(scrollLeft - positionItem)\n prevIndexDelta = indexDelta\n if (pxLeftScrolling < 2) {\n update({\n event: 'scroll',\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n }\n ticking = false\n })\n ticking = true\n }\n }\n const onScrollFn = throttle(onScroll, 500)\n const onResizeFn = throttle(calculate, 500)\n function setElement(_el: HTMLElement) {\n if (element) {\n destroy()\n }\n element = _el\n updateIndexDelta()\n calculate()\n element?.addEventListener('scroll', onScrollFn)\n window.addEventListener('resize', onResizeFn)\n }\n _element && setElement(_element)\n const jumpTo: TSnapSliderJumpToFn = function (\n index,\n indexDelta,\n event = 'goto'\n ) {\n if (indexDelta !== undefined) {\n update({\n event,\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n if (index !== undefined) {\n update({\n event,\n ...fixIndex({\n index,\n indexDelta: index * slidesPerPage,\n }),\n })\n }\n }\n const destroy = () => {\n element?.removeEventListener('scroll', onScrollFn)\n window.removeEventListener('resize', onResizeFn)\n }\n const goNext = () => {\n const { countDelta, indexDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta + slidesPerPage <= last\n ? indexDelta + slidesPerPage\n : circular && indexDelta === last\n ? 0\n : last\n jumpTo(undefined, next)\n }\n const goPrev = () => {\n const { indexDelta, countDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta - slidesPerPage >= 0\n ? indexDelta - slidesPerPage\n : circular && indexDelta === 0\n ? last\n : 0\n jumpTo(undefined, next)\n }\n return {\n destroy,\n getState,\n subscribe,\n jumpTo,\n setElement,\n calculate,\n goNext,\n goPrev,\n }\n}\n"],"names":["indexDelta","countDelta","index","count"],"mappings":"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"}
1
+ {"version":3,"file":"snap-slider.cjs","sources":["../lib/throttle.ts","../lib/snap-slider.ts"],"sourcesContent":["export const throttle = (fn: Function, wait: number) => {\n let inThrottle: boolean\n let lastFn: ReturnType<typeof setTimeout>\n let lastTime: number\n return function (this: any) {\n const context = this\n const args = arguments\n if (!inThrottle) {\n fn.apply(context, args)\n lastTime = Date.now()\n inThrottle = true\n } else {\n clearTimeout(lastFn)\n lastFn = setTimeout(() => {\n if (Date.now() - lastTime >= wait) {\n fn.apply(context, args)\n lastTime = Date.now()\n }\n }, Math.max(wait - (Date.now() - lastTime), 0))\n }\n }\n}\n","import { throttle } from './throttle'\n\nexport type TSnapListnerEvent = 'scroll' | 'click' | 'inital' | 'goto'\n\nexport interface TSnapListnerStateIndex {\n index: number\n indexDelta: number\n}\n\nexport interface TSnapSliderState extends TSnapListnerStateIndex {\n count: number\n countDelta: number\n event: TSnapListnerEvent\n}\n\ninterface TSnapSliderStateUpdate {\n index?: number\n indexDelta?: number\n count?: number\n countDelta?: number\n event: TSnapListnerEvent\n}\n\nexport interface TSnapSliderStateFull extends TSnapSliderState {\n prevEnabled: boolean\n nextEnabled: boolean\n}\n\nexport type TSnapListner = (params: TSnapSliderStateFull) => void\n\nexport type TSnapSliderOptions = {\n circular?: boolean\n debug?: boolean\n scrollTimeThrottle?: number\n resizeTimeThrottle?: number\n scrollListenerThreshold?: number\n}\n\nexport type TSnapSliderParams = Omit<TSnapSliderStateUpdate, 'event'> &\n TSnapSliderOptions & {\n element: HTMLElement | null\n itemSelector?: string\n initalSubscriptionPublish?: boolean\n }\n\nexport type TSnapSliderJumpToFn = (\n index?: number,\n indexDelta?: number,\n event?: TSnapListnerEvent\n) => void\n\nexport interface TSnapSlider {\n destroy: () => void\n getState: () => TSnapSliderStateFull\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n subscribe: (fn: TSnapListner) => () => void\n setElement: (el: HTMLElement) => void\n calculate: () => void\n}\n\nexport function createSnapSlider({\n element: _element,\n count = 1,\n countDelta,\n index = 0,\n circular,\n indexDelta,\n initalSubscriptionPublish = true,\n itemSelector = ':scope > *',\n debug,\n scrollTimeThrottle = 500,\n resizeTimeThrottle = 500,\n scrollListenerThreshold = 2,\n}: TSnapSliderParams): TSnapSlider {\n let initalIndex: number | undefined = index\n let state: TSnapSliderState = {\n index,\n indexDelta: indexDelta || index,\n event: 'inital',\n count,\n countDelta: countDelta || count,\n }\n let prevIndexDelta: number = index\n let slidesPerPage: number = 1\n let itemPositions: number[] = []\n let muteScrollListner: boolean = false\n let left: number = 0\n let element: HTMLElement | null\n function updateIndexDelta() {\n if (element) {\n const prev = element.scrollLeft\n const { indexDelta, event } = state\n left = indexDelta * (element.offsetWidth / slidesPerPage)\n if (prevIndexDelta !== indexDelta) {\n const distance = Math.abs(prev - left)\n const limitInstantScroll = element.offsetWidth * 2\n prevIndexDelta = indexDelta\n muteScrollListner = true\n const behavior: ScrollBehavior =\n distance > limitInstantScroll || event === 'click'\n ? 'instant'\n : 'smooth'\n element.scroll({\n left,\n top: 0,\n behavior,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\n behavior: 'instant',\n })\n initalIndex = undefined\n }\n }\n }\n }\n\n let publishDirty = false\n let listeners: TSnapListner[] = []\n const subscribe = (callback: TSnapListner) => {\n listeners.push(callback)\n if (element && (publishDirty || initalSubscriptionPublish)) {\n callback(getState())\n }\n return () => {\n listeners = listeners.filter((x) => x !== callback)\n if (listeners.length < 1) {\n destroy()\n }\n }\n }\n function notify() {\n listeners.forEach((callback) => {\n callback(getState())\n })\n }\n const getState = (): TSnapSliderStateFull => {\n const { indexDelta, countDelta } = state\n return {\n ...state,\n prevEnabled: circular || indexDelta > 0,\n nextEnabled: circular || countDelta - slidesPerPage > indexDelta,\n }\n }\n function update(params: TSnapSliderStateUpdate) {\n let dirty = false\n let indexDeltaDirty = false\n type TSnapSliderStateUpdateKey = keyof typeof params\n const keys: TSnapSliderStateUpdateKey[] = Object.keys(\n params\n ) as Array<TSnapSliderStateUpdateKey>\n state['event'] = params['event']\n keys.forEach((key) => {\n if (key !== 'event' && state[key] !== params[key]) {\n state[key] = Number(params[key])\n dirty = true\n if (key === 'indexDelta') {\n indexDeltaDirty = true\n }\n }\n })\n if (dirty) {\n publishDirty = listeners.length === 0\n notify()\n if (indexDeltaDirty) {\n updateIndexDelta()\n }\n }\n }\n function fixIndex(nextIndex: TSnapListnerStateIndex): TSnapListnerStateIndex {\n const { index, indexDelta } = nextIndex\n const { countDelta, count } = state\n const last = countDelta - slidesPerPage\n return {\n index: indexDelta < last ? index : count - 1,\n indexDelta,\n }\n }\n function calculate() {\n if (element) {\n let contentWidth = 0\n let itemWidth = 0\n itemPositions = []\n const slides = element.querySelectorAll<HTMLDivElement>(itemSelector)\n slides.forEach((slide) => {\n itemPositions.push(contentWidth)\n contentWidth += slide.clientWidth\n itemWidth = slide.clientWidth\n })\n slidesPerPage = Math.round(element.offsetWidth / itemWidth)\n const countDelta = itemPositions.length\n const count = Math.ceil(countDelta / slidesPerPage)\n const { index } = state\n const resetIndexMayby =\n index + 1 > count\n ? {\n index: 0,\n indexDelta: 0,\n }\n : {}\n\n if (!isNaN(count)) {\n // if element not mounted / hidden not update\n update({\n event: 'inital',\n count,\n countDelta,\n ...resetIndexMayby,\n })\n debug &&\n console.log('update count', {\n count,\n countDelta,\n itemPositions,\n slidesPerPage,\n clientWidth: element.clientWidth,\n offsetWidth: element.offsetWidth,\n itemSelector,\n slides,\n })\n }\n }\n }\n function onScrollEnd() {\n if (element) {\n const scrollLeft = element.scrollLeft\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n const pxLeftScrolling = Math.abs(scrollLeft - positionItem)\n prevIndexDelta = indexDelta\n debug &&\n console.log('onScrollEnd', {\n pxLeftScrolling,\n indexDelta,\n scrollLeft,\n positionItem,\n itemPositions,\n })\n update({\n event: 'scroll',\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n }\n function onScroll() {\n if (element) {\n const scrollLeft = element.scrollLeft\n if (muteScrollListner) {\n const leftToScroll = Math.abs(left - scrollLeft)\n if (leftToScroll < 2) {\n muteScrollListner = false\n }\n } else {\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n const pxLeftScrolling = Math.abs(scrollLeft - positionItem)\n prevIndexDelta = indexDelta\n debug &&\n console.log('onScroll', {\n pxLeftScrolling,\n indexDelta,\n scrollLeft,\n positionItem,\n itemPositions,\n })\n if (pxLeftScrolling < scrollListenerThreshold) {\n update({\n event: 'scroll',\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n }\n }\n }\n const onScrollFn = throttle(onScroll, scrollTimeThrottle)\n const onResizeFn = throttle(calculate, resizeTimeThrottle)\n function setElement(_el: HTMLElement) {\n if (element) {\n destroy()\n }\n element = _el\n updateIndexDelta()\n calculate()\n if ('onscrollend' in window) {\n element?.addEventListener('scrollend', onScrollEnd)\n } else {\n element?.addEventListener('scroll', onScrollFn)\n }\n window.addEventListener('resize', onResizeFn)\n }\n _element && setElement(_element)\n const jumpTo: TSnapSliderJumpToFn = function (\n index,\n indexDelta,\n event = 'goto'\n ) {\n if (indexDelta !== undefined) {\n update({\n event,\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n if (index !== undefined) {\n update({\n event,\n ...fixIndex({\n index,\n indexDelta: index * slidesPerPage,\n }),\n })\n }\n }\n const destroy = () => {\n if ('onscrollend' in window) {\n element?.removeEventListener('scrollend', onScrollEnd)\n } else {\n element?.removeEventListener('scroll', onScrollFn)\n }\n window.removeEventListener('resize', onResizeFn)\n }\n const goNext = () => {\n const { countDelta, indexDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta + slidesPerPage <= last\n ? indexDelta + slidesPerPage\n : circular && indexDelta === last\n ? 0\n : last\n jumpTo(undefined, next)\n }\n const goPrev = () => {\n const { indexDelta, countDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta - slidesPerPage >= 0\n ? indexDelta - slidesPerPage\n : circular && indexDelta === 0\n ? last\n : 0\n jumpTo(undefined, next)\n }\n return {\n destroy,\n getState,\n subscribe,\n jumpTo,\n setElement,\n calculate,\n goNext,\n goPrev,\n }\n}\n"],"names":["indexDelta","countDelta","index","count"],"mappings":"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"}
@@ -20,13 +20,18 @@ export interface TSnapSliderStateFull extends TSnapSliderState {
20
20
  nextEnabled: boolean;
21
21
  }
22
22
  export type TSnapListner = (params: TSnapSliderStateFull) => void;
23
- export interface TSnapSliderParams extends Omit<TSnapSliderStateUpdate, 'event'> {
23
+ export type TSnapSliderOptions = {
24
+ circular?: boolean;
25
+ debug?: boolean;
26
+ scrollTimeThrottle?: number;
27
+ resizeTimeThrottle?: number;
28
+ scrollListenerThreshold?: number;
29
+ };
30
+ export type TSnapSliderParams = Omit<TSnapSliderStateUpdate, 'event'> & TSnapSliderOptions & {
24
31
  element: HTMLElement | null;
25
32
  itemSelector?: string;
26
33
  initalSubscriptionPublish?: boolean;
27
- circular?: boolean;
28
- debug?: boolean;
29
- }
34
+ };
30
35
  export type TSnapSliderJumpToFn = (index?: number, indexDelta?: number, event?: TSnapListnerEvent) => void;
31
36
  export interface TSnapSlider {
32
37
  destroy: () => void;
@@ -38,5 +43,5 @@ export interface TSnapSlider {
38
43
  setElement: (el: HTMLElement) => void;
39
44
  calculate: () => void;
40
45
  }
41
- export declare function createSnapSlider({ element: _element, count, countDelta, index, circular, indexDelta, initalSubscriptionPublish, itemSelector, debug, }: TSnapSliderParams): TSnapSlider;
46
+ export declare function createSnapSlider({ element: _element, count, countDelta, index, circular, indexDelta, initalSubscriptionPublish, itemSelector, debug, scrollTimeThrottle, resizeTimeThrottle, scrollListenerThreshold, }: TSnapSliderParams): TSnapSlider;
42
47
  export {};
@@ -29,7 +29,10 @@ function createSnapSlider({
29
29
  indexDelta,
30
30
  initalSubscriptionPublish = true,
31
31
  itemSelector = ":scope > *",
32
- debug
32
+ debug,
33
+ scrollTimeThrottle = 500,
34
+ resizeTimeThrottle = 500,
35
+ scrollListenerThreshold = 2
33
36
  }) {
34
37
  let initalIndex = index;
35
38
  let state = {
@@ -173,40 +176,67 @@ function createSnapSlider({
173
176
  }
174
177
  }
175
178
  }
176
- let ticking = false;
179
+ function onScrollEnd() {
180
+ if (element) {
181
+ const scrollLeft = element.scrollLeft;
182
+ const positionItem = itemPositions.reduce((prev, curr) => {
183
+ return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
184
+ });
185
+ const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
186
+ const pxLeftScrolling = Math.abs(scrollLeft - positionItem);
187
+ prevIndexDelta = indexDelta2;
188
+ debug && console.log("onScrollEnd", {
189
+ pxLeftScrolling,
190
+ indexDelta: indexDelta2,
191
+ scrollLeft,
192
+ positionItem,
193
+ itemPositions
194
+ });
195
+ update({
196
+ event: "scroll",
197
+ ...fixIndex({
198
+ index: Math.floor(indexDelta2 / slidesPerPage),
199
+ indexDelta: indexDelta2
200
+ })
201
+ });
202
+ }
203
+ }
177
204
  function onScroll() {
178
- if (!ticking && element) {
205
+ if (element) {
179
206
  const scrollLeft = element.scrollLeft;
180
- window.requestAnimationFrame(() => {
181
- if (muteScrollListner) {
182
- const leftToScroll = Math.abs(left - scrollLeft);
183
- if (leftToScroll < 2) {
184
- muteScrollListner = false;
185
- }
186
- } else {
187
- const positionItem = itemPositions.reduce((prev, curr) => {
188
- return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
207
+ if (muteScrollListner) {
208
+ const leftToScroll = Math.abs(left - scrollLeft);
209
+ if (leftToScroll < 2) {
210
+ muteScrollListner = false;
211
+ }
212
+ } else {
213
+ const positionItem = itemPositions.reduce((prev, curr) => {
214
+ return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft) ? curr : prev;
215
+ });
216
+ const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
217
+ const pxLeftScrolling = Math.abs(scrollLeft - positionItem);
218
+ prevIndexDelta = indexDelta2;
219
+ debug && console.log("onScroll", {
220
+ pxLeftScrolling,
221
+ indexDelta: indexDelta2,
222
+ scrollLeft,
223
+ positionItem,
224
+ itemPositions
225
+ });
226
+ if (pxLeftScrolling < scrollListenerThreshold) {
227
+ update({
228
+ event: "scroll",
229
+ ...fixIndex({
230
+ index: Math.floor(indexDelta2 / slidesPerPage),
231
+ indexDelta: indexDelta2
232
+ })
189
233
  });
190
- const indexDelta2 = itemPositions.findIndex((x) => x === positionItem);
191
- const pxLeftScrolling = Math.abs(scrollLeft - positionItem);
192
- prevIndexDelta = indexDelta2;
193
- if (pxLeftScrolling < 2) {
194
- update({
195
- event: "scroll",
196
- ...fixIndex({
197
- index: Math.floor(indexDelta2 / slidesPerPage),
198
- indexDelta: indexDelta2
199
- })
200
- });
201
- }
202
234
  }
203
- ticking = false;
204
- });
205
- ticking = true;
235
+ }
206
236
  }
207
237
  }
208
- const onScrollFn = throttle(onScroll, 500);
209
- const onResizeFn = throttle(calculate, 500);
238
+ const onScrollFn = throttle(onScroll, scrollTimeThrottle);
239
+ const onResizeFn = throttle(calculate, resizeTimeThrottle);
210
240
  function setElement(_el) {
211
241
  if (element) {
212
242
  destroy();
@@ -214,7 +244,11 @@ function createSnapSlider({
214
244
  element = _el;
215
245
  updateIndexDelta();
216
246
  calculate();
217
- element == null ? void 0 : element.addEventListener("scroll", onScrollFn);
247
+ if ("onscrollend" in window) {
248
+ element?.addEventListener("scrollend", onScrollEnd);
249
+ } else {
250
+ element?.addEventListener("scroll", onScrollFn);
251
+ }
218
252
  window.addEventListener("resize", onResizeFn);
219
253
  }
220
254
  _element && setElement(_element);
@@ -239,7 +273,11 @@ function createSnapSlider({
239
273
  }
240
274
  };
241
275
  const destroy = () => {
242
- element == null ? void 0 : element.removeEventListener("scroll", onScrollFn);
276
+ if ("onscrollend" in window) {
277
+ element?.removeEventListener("scrollend", onScrollEnd);
278
+ } else {
279
+ element?.removeEventListener("scroll", onScrollFn);
280
+ }
243
281
  window.removeEventListener("resize", onResizeFn);
244
282
  };
245
283
  const goNext = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"snap-slider.es.js","sources":["../lib/throttle.ts","../lib/snap-slider.ts"],"sourcesContent":["export const throttle = (fn: Function, wait: number) => {\n let inThrottle: boolean\n let lastFn: ReturnType<typeof setTimeout>\n let lastTime: number\n return function (this: any) {\n const context = this\n const args = arguments\n if (!inThrottle) {\n fn.apply(context, args)\n lastTime = Date.now()\n inThrottle = true\n } else {\n clearTimeout(lastFn)\n lastFn = setTimeout(() => {\n if (Date.now() - lastTime >= wait) {\n fn.apply(context, args)\n lastTime = Date.now()\n }\n }, Math.max(wait - (Date.now() - lastTime), 0))\n }\n }\n}\n","import { throttle } from './throttle'\n\nexport type TSnapListnerEvent = 'scroll' | 'click' | 'inital' | 'goto'\n\nexport interface TSnapListnerStateIndex {\n index: number\n indexDelta: number\n}\n\nexport interface TSnapSliderState extends TSnapListnerStateIndex {\n count: number\n countDelta: number\n event: TSnapListnerEvent\n}\n\ninterface TSnapSliderStateUpdate {\n index?: number\n indexDelta?: number\n count?: number\n countDelta?: number\n event: TSnapListnerEvent\n}\n\nexport interface TSnapSliderStateFull extends TSnapSliderState {\n prevEnabled: boolean\n nextEnabled: boolean\n}\n\nexport type TSnapListner = (params: TSnapSliderStateFull) => void\n\nexport interface TSnapSliderParams\n extends Omit<TSnapSliderStateUpdate, 'event'> {\n element: HTMLElement | null\n itemSelector?: string\n initalSubscriptionPublish?: boolean\n circular?: boolean\n debug?: boolean\n}\n\nexport type TSnapSliderJumpToFn = (\n index?: number,\n indexDelta?: number,\n event?: TSnapListnerEvent\n) => void\n\nexport interface TSnapSlider {\n destroy: () => void\n getState: () => TSnapSliderStateFull\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n subscribe: (fn: TSnapListner) => () => void\n setElement: (el: HTMLElement) => void\n calculate: () => void\n}\n\nexport function createSnapSlider({\n element: _element,\n count = 1,\n countDelta,\n index = 0,\n circular,\n indexDelta,\n initalSubscriptionPublish = true,\n itemSelector = ':scope > *',\n debug,\n}: TSnapSliderParams): TSnapSlider {\n let initalIndex: number | undefined = index\n let state: TSnapSliderState = {\n index,\n indexDelta: indexDelta || index,\n event: 'inital',\n count,\n countDelta: countDelta || count,\n }\n let prevIndexDelta: number = index\n let slidesPerPage: number = 1\n let itemPositions: number[] = []\n let muteScrollListner: boolean = false\n let left: number = 0\n let element: HTMLElement | null\n function updateIndexDelta() {\n if (element) {\n const prev = element.scrollLeft\n const { indexDelta, event } = state\n left = indexDelta * (element.offsetWidth / slidesPerPage)\n if (prevIndexDelta !== indexDelta) {\n const distance = Math.abs(prev - left)\n const limitInstantScroll = element.offsetWidth * 2\n prevIndexDelta = indexDelta\n muteScrollListner = true\n const behavior: ScrollBehavior =\n distance > limitInstantScroll || event === 'click'\n ? 'instant'\n : 'smooth'\n element.scroll({\n left,\n top: 0,\n behavior,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\n behavior: 'instant',\n })\n initalIndex = undefined\n }\n }\n }\n }\n\n let publishDirty = false\n let listeners: TSnapListner[] = []\n const subscribe = (callback: TSnapListner) => {\n listeners.push(callback)\n if (element && (publishDirty || initalSubscriptionPublish)) {\n callback(getState())\n }\n return () => {\n listeners = listeners.filter((x) => x !== callback)\n if (listeners.length < 1) {\n destroy()\n }\n }\n }\n function notify() {\n listeners.forEach((callback) => {\n callback(getState())\n })\n }\n const getState = (): TSnapSliderStateFull => {\n const { indexDelta, countDelta } = state\n return {\n ...state,\n prevEnabled: circular || indexDelta > 0,\n nextEnabled: circular || countDelta - slidesPerPage > indexDelta,\n }\n }\n function update(params: TSnapSliderStateUpdate) {\n let dirty = false\n let indexDeltaDirty = false\n type TSnapSliderStateUpdateKey = keyof typeof params\n const keys: TSnapSliderStateUpdateKey[] = Object.keys(\n params\n ) as Array<TSnapSliderStateUpdateKey>\n state['event'] = params['event']\n keys.forEach((key) => {\n if (key !== 'event' && state[key] !== params[key]) {\n state[key] = Number(params[key])\n dirty = true\n if (key === 'indexDelta') {\n indexDeltaDirty = true\n }\n }\n })\n if (dirty) {\n publishDirty = listeners.length === 0\n notify()\n if (indexDeltaDirty) {\n updateIndexDelta()\n }\n }\n }\n function fixIndex(nextIndex: TSnapListnerStateIndex): TSnapListnerStateIndex {\n const { index, indexDelta } = nextIndex\n const { countDelta, count } = state\n const last = countDelta - slidesPerPage\n return {\n index: indexDelta < last ? index : count - 1,\n indexDelta,\n }\n }\n function calculate() {\n if (element) {\n let contentWidth = 0\n let itemWidth = 0\n itemPositions = []\n const slides = element.querySelectorAll<HTMLDivElement>(itemSelector)\n slides.forEach((slide) => {\n itemPositions.push(contentWidth)\n contentWidth += slide.clientWidth\n itemWidth = slide.clientWidth\n })\n slidesPerPage = Math.round(element.offsetWidth / itemWidth)\n const countDelta = itemPositions.length\n const count = Math.ceil(countDelta / slidesPerPage)\n const { index } = state\n const resetIndexMayby =\n index + 1 > count\n ? {\n index: 0,\n indexDelta: 0,\n }\n : {}\n\n if (!isNaN(count)) {\n // if element not mounted / hidden not update\n update({\n event: 'inital',\n count,\n countDelta,\n ...resetIndexMayby,\n })\n debug &&\n console.log('update count', {\n count,\n countDelta,\n itemPositions,\n slidesPerPage,\n clientWidth: element.clientWidth,\n offsetWidth: element.offsetWidth,\n itemSelector,\n slides,\n })\n }\n }\n }\n\n let ticking = false\n function onScroll() {\n if (!ticking && element) {\n const scrollLeft = element.scrollLeft\n window.requestAnimationFrame(() => {\n if (muteScrollListner) {\n const leftToScroll = Math.abs(left - scrollLeft)\n if (leftToScroll < 2) {\n muteScrollListner = false\n }\n } else {\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n const pxLeftScrolling = Math.abs(scrollLeft - positionItem)\n prevIndexDelta = indexDelta\n if (pxLeftScrolling < 2) {\n update({\n event: 'scroll',\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n }\n ticking = false\n })\n ticking = true\n }\n }\n const onScrollFn = throttle(onScroll, 500)\n const onResizeFn = throttle(calculate, 500)\n function setElement(_el: HTMLElement) {\n if (element) {\n destroy()\n }\n element = _el\n updateIndexDelta()\n calculate()\n element?.addEventListener('scroll', onScrollFn)\n window.addEventListener('resize', onResizeFn)\n }\n _element && setElement(_element)\n const jumpTo: TSnapSliderJumpToFn = function (\n index,\n indexDelta,\n event = 'goto'\n ) {\n if (indexDelta !== undefined) {\n update({\n event,\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n if (index !== undefined) {\n update({\n event,\n ...fixIndex({\n index,\n indexDelta: index * slidesPerPage,\n }),\n })\n }\n }\n const destroy = () => {\n element?.removeEventListener('scroll', onScrollFn)\n window.removeEventListener('resize', onResizeFn)\n }\n const goNext = () => {\n const { countDelta, indexDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta + slidesPerPage <= last\n ? indexDelta + slidesPerPage\n : circular && indexDelta === last\n ? 0\n : last\n jumpTo(undefined, next)\n }\n const goPrev = () => {\n const { indexDelta, countDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta - slidesPerPage >= 0\n ? indexDelta - slidesPerPage\n : circular && indexDelta === 0\n ? last\n : 0\n jumpTo(undefined, next)\n }\n return {\n destroy,\n getState,\n subscribe,\n jumpTo,\n setElement,\n calculate,\n goNext,\n goPrev,\n }\n}\n"],"names":["indexDelta","countDelta","index","count"],"mappings":"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"}
1
+ {"version":3,"file":"snap-slider.es.js","sources":["../lib/throttle.ts","../lib/snap-slider.ts"],"sourcesContent":["export const throttle = (fn: Function, wait: number) => {\n let inThrottle: boolean\n let lastFn: ReturnType<typeof setTimeout>\n let lastTime: number\n return function (this: any) {\n const context = this\n const args = arguments\n if (!inThrottle) {\n fn.apply(context, args)\n lastTime = Date.now()\n inThrottle = true\n } else {\n clearTimeout(lastFn)\n lastFn = setTimeout(() => {\n if (Date.now() - lastTime >= wait) {\n fn.apply(context, args)\n lastTime = Date.now()\n }\n }, Math.max(wait - (Date.now() - lastTime), 0))\n }\n }\n}\n","import { throttle } from './throttle'\n\nexport type TSnapListnerEvent = 'scroll' | 'click' | 'inital' | 'goto'\n\nexport interface TSnapListnerStateIndex {\n index: number\n indexDelta: number\n}\n\nexport interface TSnapSliderState extends TSnapListnerStateIndex {\n count: number\n countDelta: number\n event: TSnapListnerEvent\n}\n\ninterface TSnapSliderStateUpdate {\n index?: number\n indexDelta?: number\n count?: number\n countDelta?: number\n event: TSnapListnerEvent\n}\n\nexport interface TSnapSliderStateFull extends TSnapSliderState {\n prevEnabled: boolean\n nextEnabled: boolean\n}\n\nexport type TSnapListner = (params: TSnapSliderStateFull) => void\n\nexport type TSnapSliderOptions = {\n circular?: boolean\n debug?: boolean\n scrollTimeThrottle?: number\n resizeTimeThrottle?: number\n scrollListenerThreshold?: number\n}\n\nexport type TSnapSliderParams = Omit<TSnapSliderStateUpdate, 'event'> &\n TSnapSliderOptions & {\n element: HTMLElement | null\n itemSelector?: string\n initalSubscriptionPublish?: boolean\n }\n\nexport type TSnapSliderJumpToFn = (\n index?: number,\n indexDelta?: number,\n event?: TSnapListnerEvent\n) => void\n\nexport interface TSnapSlider {\n destroy: () => void\n getState: () => TSnapSliderStateFull\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n subscribe: (fn: TSnapListner) => () => void\n setElement: (el: HTMLElement) => void\n calculate: () => void\n}\n\nexport function createSnapSlider({\n element: _element,\n count = 1,\n countDelta,\n index = 0,\n circular,\n indexDelta,\n initalSubscriptionPublish = true,\n itemSelector = ':scope > *',\n debug,\n scrollTimeThrottle = 500,\n resizeTimeThrottle = 500,\n scrollListenerThreshold = 2,\n}: TSnapSliderParams): TSnapSlider {\n let initalIndex: number | undefined = index\n let state: TSnapSliderState = {\n index,\n indexDelta: indexDelta || index,\n event: 'inital',\n count,\n countDelta: countDelta || count,\n }\n let prevIndexDelta: number = index\n let slidesPerPage: number = 1\n let itemPositions: number[] = []\n let muteScrollListner: boolean = false\n let left: number = 0\n let element: HTMLElement | null\n function updateIndexDelta() {\n if (element) {\n const prev = element.scrollLeft\n const { indexDelta, event } = state\n left = indexDelta * (element.offsetWidth / slidesPerPage)\n if (prevIndexDelta !== indexDelta) {\n const distance = Math.abs(prev - left)\n const limitInstantScroll = element.offsetWidth * 2\n prevIndexDelta = indexDelta\n muteScrollListner = true\n const behavior: ScrollBehavior =\n distance > limitInstantScroll || event === 'click'\n ? 'instant'\n : 'smooth'\n element.scroll({\n left,\n top: 0,\n behavior,\n })\n } else {\n if (initalIndex) {\n muteScrollListner = true\n element.scroll({\n left,\n top: 0,\n behavior: 'instant',\n })\n initalIndex = undefined\n }\n }\n }\n }\n\n let publishDirty = false\n let listeners: TSnapListner[] = []\n const subscribe = (callback: TSnapListner) => {\n listeners.push(callback)\n if (element && (publishDirty || initalSubscriptionPublish)) {\n callback(getState())\n }\n return () => {\n listeners = listeners.filter((x) => x !== callback)\n if (listeners.length < 1) {\n destroy()\n }\n }\n }\n function notify() {\n listeners.forEach((callback) => {\n callback(getState())\n })\n }\n const getState = (): TSnapSliderStateFull => {\n const { indexDelta, countDelta } = state\n return {\n ...state,\n prevEnabled: circular || indexDelta > 0,\n nextEnabled: circular || countDelta - slidesPerPage > indexDelta,\n }\n }\n function update(params: TSnapSliderStateUpdate) {\n let dirty = false\n let indexDeltaDirty = false\n type TSnapSliderStateUpdateKey = keyof typeof params\n const keys: TSnapSliderStateUpdateKey[] = Object.keys(\n params\n ) as Array<TSnapSliderStateUpdateKey>\n state['event'] = params['event']\n keys.forEach((key) => {\n if (key !== 'event' && state[key] !== params[key]) {\n state[key] = Number(params[key])\n dirty = true\n if (key === 'indexDelta') {\n indexDeltaDirty = true\n }\n }\n })\n if (dirty) {\n publishDirty = listeners.length === 0\n notify()\n if (indexDeltaDirty) {\n updateIndexDelta()\n }\n }\n }\n function fixIndex(nextIndex: TSnapListnerStateIndex): TSnapListnerStateIndex {\n const { index, indexDelta } = nextIndex\n const { countDelta, count } = state\n const last = countDelta - slidesPerPage\n return {\n index: indexDelta < last ? index : count - 1,\n indexDelta,\n }\n }\n function calculate() {\n if (element) {\n let contentWidth = 0\n let itemWidth = 0\n itemPositions = []\n const slides = element.querySelectorAll<HTMLDivElement>(itemSelector)\n slides.forEach((slide) => {\n itemPositions.push(contentWidth)\n contentWidth += slide.clientWidth\n itemWidth = slide.clientWidth\n })\n slidesPerPage = Math.round(element.offsetWidth / itemWidth)\n const countDelta = itemPositions.length\n const count = Math.ceil(countDelta / slidesPerPage)\n const { index } = state\n const resetIndexMayby =\n index + 1 > count\n ? {\n index: 0,\n indexDelta: 0,\n }\n : {}\n\n if (!isNaN(count)) {\n // if element not mounted / hidden not update\n update({\n event: 'inital',\n count,\n countDelta,\n ...resetIndexMayby,\n })\n debug &&\n console.log('update count', {\n count,\n countDelta,\n itemPositions,\n slidesPerPage,\n clientWidth: element.clientWidth,\n offsetWidth: element.offsetWidth,\n itemSelector,\n slides,\n })\n }\n }\n }\n function onScrollEnd() {\n if (element) {\n const scrollLeft = element.scrollLeft\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n const pxLeftScrolling = Math.abs(scrollLeft - positionItem)\n prevIndexDelta = indexDelta\n debug &&\n console.log('onScrollEnd', {\n pxLeftScrolling,\n indexDelta,\n scrollLeft,\n positionItem,\n itemPositions,\n })\n update({\n event: 'scroll',\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n }\n function onScroll() {\n if (element) {\n const scrollLeft = element.scrollLeft\n if (muteScrollListner) {\n const leftToScroll = Math.abs(left - scrollLeft)\n if (leftToScroll < 2) {\n muteScrollListner = false\n }\n } else {\n const positionItem = itemPositions.reduce((prev, curr) => {\n return Math.abs(curr - scrollLeft) < Math.abs(prev - scrollLeft)\n ? curr\n : prev\n })\n const indexDelta = itemPositions.findIndex((x) => x === positionItem)\n const pxLeftScrolling = Math.abs(scrollLeft - positionItem)\n prevIndexDelta = indexDelta\n debug &&\n console.log('onScroll', {\n pxLeftScrolling,\n indexDelta,\n scrollLeft,\n positionItem,\n itemPositions,\n })\n if (pxLeftScrolling < scrollListenerThreshold) {\n update({\n event: 'scroll',\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n }\n }\n }\n const onScrollFn = throttle(onScroll, scrollTimeThrottle)\n const onResizeFn = throttle(calculate, resizeTimeThrottle)\n function setElement(_el: HTMLElement) {\n if (element) {\n destroy()\n }\n element = _el\n updateIndexDelta()\n calculate()\n if ('onscrollend' in window) {\n element?.addEventListener('scrollend', onScrollEnd)\n } else {\n element?.addEventListener('scroll', onScrollFn)\n }\n window.addEventListener('resize', onResizeFn)\n }\n _element && setElement(_element)\n const jumpTo: TSnapSliderJumpToFn = function (\n index,\n indexDelta,\n event = 'goto'\n ) {\n if (indexDelta !== undefined) {\n update({\n event,\n ...fixIndex({\n index: Math.floor(indexDelta / slidesPerPage),\n indexDelta,\n }),\n })\n }\n if (index !== undefined) {\n update({\n event,\n ...fixIndex({\n index,\n indexDelta: index * slidesPerPage,\n }),\n })\n }\n }\n const destroy = () => {\n if ('onscrollend' in window) {\n element?.removeEventListener('scrollend', onScrollEnd)\n } else {\n element?.removeEventListener('scroll', onScrollFn)\n }\n window.removeEventListener('resize', onResizeFn)\n }\n const goNext = () => {\n const { countDelta, indexDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta + slidesPerPage <= last\n ? indexDelta + slidesPerPage\n : circular && indexDelta === last\n ? 0\n : last\n jumpTo(undefined, next)\n }\n const goPrev = () => {\n const { indexDelta, countDelta } = state\n const last = countDelta - slidesPerPage\n const next =\n indexDelta - slidesPerPage >= 0\n ? indexDelta - slidesPerPage\n : circular && indexDelta === 0\n ? last\n : 0\n jumpTo(undefined, next)\n }\n return {\n destroy,\n getState,\n subscribe,\n jumpTo,\n setElement,\n calculate,\n goNext,\n goPrev,\n }\n}\n"],"names":["indexDelta","countDelta","index","count"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const react = require("react");
4
4
  const snapSlider = require("./snap-slider.cjs");
5
- function useSnapSlider(ref, count = 1, index = 0, circular = false, countHash, debug) {
5
+ function useSnapSlider(ref, count = 1, index = 0, countHash, options) {
6
6
  const [, forceUpdate] = react.useState(0);
7
7
  const mountedRef = react.useRef(false);
8
8
  react.useRef(false);
@@ -11,9 +11,8 @@ function useSnapSlider(ref, count = 1, index = 0, circular = false, countHash, d
11
11
  element: ref.current,
12
12
  count,
13
13
  index,
14
- circular,
15
14
  initalSubscriptionPublish: false,
16
- debug
15
+ ...options
17
16
  })
18
17
  );
19
18
  const result = observer.getState();
@@ -1 +1 @@
1
- {"version":3,"file":"use-snap-slider.cjs","sources":["../lib/use-snap-slider.ts"],"sourcesContent":["import { type MutableRefObject, useEffect, useRef, useState } from 'react'\nimport {\n createSnapSlider,\n TSnapSliderJumpToFn,\n type TSnapSliderStateFull,\n} from './snap-slider'\n\nexport interface TUseSnapSlider extends TSnapSliderStateFull {\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n}\n\nexport function useSnapSlider(\n ref: MutableRefObject<HTMLDivElement | null>,\n count: number = 1,\n index: number = 0,\n circular = false,\n countHash?: string | number,\n debug?: boolean\n): TUseSnapSlider {\n const [, forceUpdate] = useState<number>(0)\n const mountedRef = useRef<boolean>(false)\n const initRef = useRef<boolean>(false)\n const [observer] = useState(() =>\n createSnapSlider({\n element: ref.current,\n count,\n index,\n circular,\n initalSubscriptionPublish: false,\n debug,\n })\n )\n const result = observer.getState()\n useEffect(() => {\n if (mountedRef.current) {\n observer.jumpTo(0)\n observer.calculate()\n }\n }, [count, countHash, observer])\n useEffect(() => {\n mountedRef.current = true\n ref.current && observer.setElement(ref.current)\n const unsubscribe = observer.subscribe(() => {\n if (mountedRef.current) {\n forceUpdate((x) => x + 1)\n }\n })\n\n return () => {\n mountedRef.current = false\n unsubscribe()\n }\n }, [observer, forceUpdate])\n return {\n ...result,\n jumpTo: observer.jumpTo,\n goNext: observer.goNext,\n goPrev: observer.goPrev,\n }\n}\n"],"names":["useState","useRef","createSnapSlider","useEffect"],"mappings":";;;;AAagB,SAAA,cACd,KACA,QAAgB,GAChB,QAAgB,GAChB,WAAW,OACX,WACA,OACgB;AAChB,QAAM,GAAG,WAAW,IAAIA,eAAiB,CAAC;AACpC,QAAA,aAAaC,aAAgB,KAAK;AACxBA,QAAAA,OAAgB,KAAK;AAC/B,QAAA,CAAC,QAAQ,IAAID,MAAA;AAAA,IAAS,MAC1BE,4BAAiB;AAAA,MACf,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,2BAA2B;AAAA,MAC3B;AAAA,IACD,CAAA;AAAA,EACH;AACM,QAAA,SAAS,SAAS,SAAS;AACjCC,QAAAA,UAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACtB,eAAS,OAAO,CAAC;AACjB,eAAS,UAAU;AAAA,IAAA;AAAA,EAEpB,GAAA,CAAC,OAAO,WAAW,QAAQ,CAAC;AAC/BA,QAAAA,UAAU,MAAM;AACd,eAAW,UAAU;AACrB,QAAI,WAAW,SAAS,WAAW,IAAI,OAAO;AACxC,UAAA,cAAc,SAAS,UAAU,MAAM;AAC3C,UAAI,WAAW,SAAS;AACV,oBAAA,CAAC,MAAM,IAAI,CAAC;AAAA,MAAA;AAAA,IAC1B,CACD;AAED,WAAO,MAAM;AACX,iBAAW,UAAU;AACT,kBAAA;AAAA,IACd;AAAA,EAAA,GACC,CAAC,UAAU,WAAW,CAAC;AACnB,SAAA;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,EACnB;AACF;;"}
1
+ {"version":3,"file":"use-snap-slider.cjs","sources":["../lib/use-snap-slider.ts"],"sourcesContent":["import { RefObject, useEffect, useRef, useState } from 'react'\nimport {\n createSnapSlider,\n TSnapSliderJumpToFn,\n TSnapSliderOptions,\n type TSnapSliderStateFull,\n} from './snap-slider'\n\nexport interface TUseSnapSlider extends TSnapSliderStateFull {\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n}\n\nexport function useSnapSlider(\n ref: RefObject<HTMLDivElement | null>,\n count: number = 1,\n index: number = 0,\n countHash?: string | number,\n options?: TSnapSliderOptions\n): TUseSnapSlider {\n const [, forceUpdate] = useState<number>(0)\n const mountedRef = useRef<boolean>(false)\n const initRef = useRef<boolean>(false)\n const [observer] = useState(() =>\n createSnapSlider({\n element: ref.current,\n count,\n index,\n initalSubscriptionPublish: false,\n ...options,\n })\n )\n const result = observer.getState()\n useEffect(() => {\n if (mountedRef.current) {\n observer.jumpTo(0)\n observer.calculate()\n }\n }, [count, countHash, observer])\n useEffect(() => {\n mountedRef.current = true\n ref.current && observer.setElement(ref.current)\n const unsubscribe = observer.subscribe(() => {\n if (mountedRef.current) {\n forceUpdate((x) => x + 1)\n }\n })\n\n return () => {\n mountedRef.current = false\n unsubscribe()\n }\n }, [observer, forceUpdate])\n return {\n ...result,\n jumpTo: observer.jumpTo,\n goNext: observer.goNext,\n goPrev: observer.goPrev,\n }\n}\n"],"names":["useState","useRef","createSnapSlider","useEffect"],"mappings":";;;;AAcO,SAAS,cACd,KACA,QAAgB,GAChB,QAAgB,GAChB,WACA,SACgB;AAChB,QAAM,GAAG,WAAW,IAAIA,MAAAA,SAAiB,CAAC;AAC1C,QAAM,aAAaC,MAAAA,OAAgB,KAAK;AACxBA,QAAAA,OAAgB,KAAK;AACrC,QAAM,CAAC,QAAQ,IAAID,MAAAA;AAAAA,IAAS,MAC1BE,4BAAiB;AAAA,MACf,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA,2BAA2B;AAAA,MAC3B,GAAG;AAAA,IAAA,CACJ;AAAA,EAAA;AAEH,QAAM,SAAS,SAAS,SAAA;AACxBC,QAAAA,UAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACtB,eAAS,OAAO,CAAC;AACjB,eAAS,UAAA;AAAA,IACX;AAAA,EACF,GAAG,CAAC,OAAO,WAAW,QAAQ,CAAC;AAC/BA,QAAAA,UAAU,MAAM;AACd,eAAW,UAAU;AACrB,QAAI,WAAW,SAAS,WAAW,IAAI,OAAO;AAC9C,UAAM,cAAc,SAAS,UAAU,MAAM;AAC3C,UAAI,WAAW,SAAS;AACtB,oBAAY,CAAC,MAAM,IAAI,CAAC;AAAA,MAC1B;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,iBAAW,UAAU;AACrB,kBAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,WAAW,CAAC;AAC1B,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,EAAA;AAErB;;"}
@@ -1,8 +1,8 @@
1
- import { MutableRefObject } from 'react';
2
- import { TSnapSliderJumpToFn, TSnapSliderStateFull } from './snap-slider';
1
+ import { RefObject } from 'react';
2
+ import { TSnapSliderJumpToFn, TSnapSliderOptions, TSnapSliderStateFull } from './snap-slider';
3
3
  export interface TUseSnapSlider extends TSnapSliderStateFull {
4
4
  jumpTo: TSnapSliderJumpToFn;
5
5
  goNext: () => void;
6
6
  goPrev: () => void;
7
7
  }
8
- export declare function useSnapSlider(ref: MutableRefObject<HTMLDivElement | null>, count?: number, index?: number, circular?: boolean, countHash?: string | number, debug?: boolean): TUseSnapSlider;
8
+ export declare function useSnapSlider(ref: RefObject<HTMLDivElement | null>, count?: number, index?: number, countHash?: string | number, options?: TSnapSliderOptions): TUseSnapSlider;
@@ -1,6 +1,6 @@
1
1
  import { useState, useRef, useEffect } from "react";
2
2
  import { createSnapSlider } from "./snap-slider.es.js";
3
- function useSnapSlider(ref, count = 1, index = 0, circular = false, countHash, debug) {
3
+ function useSnapSlider(ref, count = 1, index = 0, countHash, options) {
4
4
  const [, forceUpdate] = useState(0);
5
5
  const mountedRef = useRef(false);
6
6
  useRef(false);
@@ -9,9 +9,8 @@ function useSnapSlider(ref, count = 1, index = 0, circular = false, countHash, d
9
9
  element: ref.current,
10
10
  count,
11
11
  index,
12
- circular,
13
12
  initalSubscriptionPublish: false,
14
- debug
13
+ ...options
15
14
  })
16
15
  );
17
16
  const result = observer.getState();
@@ -1 +1 @@
1
- {"version":3,"file":"use-snap-slider.es.js","sources":["../lib/use-snap-slider.ts"],"sourcesContent":["import { type MutableRefObject, useEffect, useRef, useState } from 'react'\nimport {\n createSnapSlider,\n TSnapSliderJumpToFn,\n type TSnapSliderStateFull,\n} from './snap-slider'\n\nexport interface TUseSnapSlider extends TSnapSliderStateFull {\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n}\n\nexport function useSnapSlider(\n ref: MutableRefObject<HTMLDivElement | null>,\n count: number = 1,\n index: number = 0,\n circular = false,\n countHash?: string | number,\n debug?: boolean\n): TUseSnapSlider {\n const [, forceUpdate] = useState<number>(0)\n const mountedRef = useRef<boolean>(false)\n const initRef = useRef<boolean>(false)\n const [observer] = useState(() =>\n createSnapSlider({\n element: ref.current,\n count,\n index,\n circular,\n initalSubscriptionPublish: false,\n debug,\n })\n )\n const result = observer.getState()\n useEffect(() => {\n if (mountedRef.current) {\n observer.jumpTo(0)\n observer.calculate()\n }\n }, [count, countHash, observer])\n useEffect(() => {\n mountedRef.current = true\n ref.current && observer.setElement(ref.current)\n const unsubscribe = observer.subscribe(() => {\n if (mountedRef.current) {\n forceUpdate((x) => x + 1)\n }\n })\n\n return () => {\n mountedRef.current = false\n unsubscribe()\n }\n }, [observer, forceUpdate])\n return {\n ...result,\n jumpTo: observer.jumpTo,\n goNext: observer.goNext,\n goPrev: observer.goPrev,\n }\n}\n"],"names":[],"mappings":";;AAagB,SAAA,cACd,KACA,QAAgB,GAChB,QAAgB,GAChB,WAAW,OACX,WACA,OACgB;AAChB,QAAM,GAAG,WAAW,IAAI,SAAiB,CAAC;AACpC,QAAA,aAAa,OAAgB,KAAK;AACxB,SAAgB,KAAK;AAC/B,QAAA,CAAC,QAAQ,IAAI;AAAA,IAAS,MAC1B,iBAAiB;AAAA,MACf,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA,2BAA2B;AAAA,MAC3B;AAAA,IACD,CAAA;AAAA,EACH;AACM,QAAA,SAAS,SAAS,SAAS;AACjC,YAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACtB,eAAS,OAAO,CAAC;AACjB,eAAS,UAAU;AAAA,IAAA;AAAA,EAEpB,GAAA,CAAC,OAAO,WAAW,QAAQ,CAAC;AAC/B,YAAU,MAAM;AACd,eAAW,UAAU;AACrB,QAAI,WAAW,SAAS,WAAW,IAAI,OAAO;AACxC,UAAA,cAAc,SAAS,UAAU,MAAM;AAC3C,UAAI,WAAW,SAAS;AACV,oBAAA,CAAC,MAAM,IAAI,CAAC;AAAA,MAAA;AAAA,IAC1B,CACD;AAED,WAAO,MAAM;AACX,iBAAW,UAAU;AACT,kBAAA;AAAA,IACd;AAAA,EAAA,GACC,CAAC,UAAU,WAAW,CAAC;AACnB,SAAA;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,EACnB;AACF;"}
1
+ {"version":3,"file":"use-snap-slider.es.js","sources":["../lib/use-snap-slider.ts"],"sourcesContent":["import { RefObject, useEffect, useRef, useState } from 'react'\nimport {\n createSnapSlider,\n TSnapSliderJumpToFn,\n TSnapSliderOptions,\n type TSnapSliderStateFull,\n} from './snap-slider'\n\nexport interface TUseSnapSlider extends TSnapSliderStateFull {\n jumpTo: TSnapSliderJumpToFn\n goNext: () => void\n goPrev: () => void\n}\n\nexport function useSnapSlider(\n ref: RefObject<HTMLDivElement | null>,\n count: number = 1,\n index: number = 0,\n countHash?: string | number,\n options?: TSnapSliderOptions\n): TUseSnapSlider {\n const [, forceUpdate] = useState<number>(0)\n const mountedRef = useRef<boolean>(false)\n const initRef = useRef<boolean>(false)\n const [observer] = useState(() =>\n createSnapSlider({\n element: ref.current,\n count,\n index,\n initalSubscriptionPublish: false,\n ...options,\n })\n )\n const result = observer.getState()\n useEffect(() => {\n if (mountedRef.current) {\n observer.jumpTo(0)\n observer.calculate()\n }\n }, [count, countHash, observer])\n useEffect(() => {\n mountedRef.current = true\n ref.current && observer.setElement(ref.current)\n const unsubscribe = observer.subscribe(() => {\n if (mountedRef.current) {\n forceUpdate((x) => x + 1)\n }\n })\n\n return () => {\n mountedRef.current = false\n unsubscribe()\n }\n }, [observer, forceUpdate])\n return {\n ...result,\n jumpTo: observer.jumpTo,\n goNext: observer.goNext,\n goPrev: observer.goPrev,\n }\n}\n"],"names":[],"mappings":";;AAcO,SAAS,cACd,KACA,QAAgB,GAChB,QAAgB,GAChB,WACA,SACgB;AAChB,QAAM,GAAG,WAAW,IAAI,SAAiB,CAAC;AAC1C,QAAM,aAAa,OAAgB,KAAK;AACxB,SAAgB,KAAK;AACrC,QAAM,CAAC,QAAQ,IAAI;AAAA,IAAS,MAC1B,iBAAiB;AAAA,MACf,SAAS,IAAI;AAAA,MACb;AAAA,MACA;AAAA,MACA,2BAA2B;AAAA,MAC3B,GAAG;AAAA,IAAA,CACJ;AAAA,EAAA;AAEH,QAAM,SAAS,SAAS,SAAA;AACxB,YAAU,MAAM;AACd,QAAI,WAAW,SAAS;AACtB,eAAS,OAAO,CAAC;AACjB,eAAS,UAAA;AAAA,IACX;AAAA,EACF,GAAG,CAAC,OAAO,WAAW,QAAQ,CAAC;AAC/B,YAAU,MAAM;AACd,eAAW,UAAU;AACrB,QAAI,WAAW,SAAS,WAAW,IAAI,OAAO;AAC9C,UAAM,cAAc,SAAS,UAAU,MAAM;AAC3C,UAAI,WAAW,SAAS;AACtB,oBAAY,CAAC,MAAM,IAAI,CAAC;AAAA,MAC1B;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,iBAAW,UAAU;AACrB,kBAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,UAAU,WAAW,CAAC;AAC1B,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,IACjB,QAAQ,SAAS;AAAA,EAAA;AAErB;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "use-snap-slider",
3
- "version": "0.1.4",
3
+ "version": "1.0.1",
4
4
  "description": "React hook to manage css snap sliders",
5
5
  "type": "module",
6
6
  "main": "./dist/use-snap-slider.cjs",
@@ -53,25 +53,27 @@
53
53
  "singleQuote": true
54
54
  },
55
55
  "devDependencies": {
56
- "@testing-library/jest-dom": "^6.6.3",
57
- "@testing-library/react": "^16.0.1",
58
- "@types/jest": "^29.5.14",
59
- "@types/node": "^22.9.1",
60
- "@types/react": "^18.3.12",
61
- "@types/react-dom": "^18.3.1",
62
- "@vitejs/plugin-react": "^4.3.3",
63
- "autoprefixer": "^10.4.20",
56
+ "@tailwindcss/postcss": "^4.1.17",
57
+ "@testing-library/jest-dom": "^6.9.1",
58
+ "@testing-library/react": "^16.3.0",
59
+ "@types/jest": "^30.0.0",
60
+ "@types/node": "^24.10.1",
61
+ "@types/react": "^19.2.6",
62
+ "@types/react-dom": "^19.2.3",
63
+ "@vitejs/plugin-react": "^5.1.1",
64
+ "autoprefixer": "^10.4.22",
64
65
  "classnames": "^2.5.1",
65
- "jest": "^29.7.0",
66
- "jest-environment-jsdom": "^29.7.0",
67
- "postcss": "^8.4.49",
68
- "react": "^18.3.1",
69
- "react-dom": "^18.3.1",
70
- "rimraf": "^6.0.1",
71
- "tailwindcss": "^3.4.15",
72
- "ts-jest": "^29.2.5",
73
- "typescript": "^5.6.3",
74
- "vite": "^5.4.11",
75
- "vite-plugin-dts": "^4.3.0"
66
+ "jest": "^30.2.0",
67
+ "jest-environment-jsdom": "^30.2.0",
68
+ "postcss": "^8.5.6",
69
+ "react": "^19.2.0",
70
+ "react-dom": "^19.2.0",
71
+ "react-router": "^7.9.6",
72
+ "rimraf": "^6.1.2",
73
+ "tailwindcss": "^4.1.16",
74
+ "ts-jest": "^29.4.5",
75
+ "typescript": "^5.9.3",
76
+ "vite": "^7.2.4",
77
+ "vite-plugin-dts": "^4.5.4"
76
78
  }
77
79
  }