use-scroller 1.2.0 → 2.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.
Files changed (42) hide show
  1. package/README.md +390 -95
  2. package/dist/chunk-IFT3KMZJ.js +1203 -0
  3. package/dist/core.d.ts +123 -0
  4. package/dist/core.js +38 -0
  5. package/dist/index.d.ts +51 -0
  6. package/dist/index.js +348 -0
  7. package/package.json +38 -24
  8. package/dist/cjs/hooks/use-iso-morphic-effect.d.ts +0 -2
  9. package/dist/cjs/hooks/use-iso-morphic-effect.js +0 -6
  10. package/dist/cjs/hooks/use-scroll.d.ts +0 -24
  11. package/dist/cjs/hooks/use-scroll.js +0 -80
  12. package/dist/cjs/hooks/use-window-scroll.d.ts +0 -13
  13. package/dist/cjs/hooks/use-window-scroll.js +0 -62
  14. package/dist/cjs/index.d.ts +0 -3
  15. package/dist/cjs/index.js +0 -19
  16. package/dist/cjs/scroller.d.ts +0 -10
  17. package/dist/cjs/scroller.js +0 -94
  18. package/dist/cjs/types.d.ts +0 -17
  19. package/dist/cjs/types.js +0 -2
  20. package/dist/cjs/utils.d.ts +0 -37
  21. package/dist/cjs/utils.js +0 -92
  22. package/dist/esm/hooks/use-iso-morphic-effect.d.ts +0 -2
  23. package/dist/esm/hooks/use-iso-morphic-effect.js +0 -3
  24. package/dist/esm/hooks/use-scroll.d.ts +0 -24
  25. package/dist/esm/hooks/use-scroll.js +0 -76
  26. package/dist/esm/hooks/use-window-scroll.d.ts +0 -13
  27. package/dist/esm/hooks/use-window-scroll.js +0 -58
  28. package/dist/esm/index.d.ts +0 -3
  29. package/dist/esm/index.js +0 -3
  30. package/dist/esm/scroller.d.ts +0 -10
  31. package/dist/esm/scroller.js +0 -90
  32. package/dist/esm/types.d.ts +0 -17
  33. package/dist/esm/types.js +0 -1
  34. package/dist/esm/utils.d.ts +0 -37
  35. package/dist/esm/utils.js +0 -85
  36. package/src/hooks/use-iso-morphic-effect.ts +0 -4
  37. package/src/hooks/use-scroll.ts +0 -84
  38. package/src/hooks/use-window-scroll.ts +0 -73
  39. package/src/index.ts +0 -3
  40. package/src/scroller.ts +0 -107
  41. package/src/types.ts +0 -21
  42. package/src/utils.ts +0 -103
package/dist/core.d.ts ADDED
@@ -0,0 +1,123 @@
1
+ type Axis = 'x' | 'y';
2
+ type ScrollTarget = HTMLElement | Window;
3
+
4
+ interface ScrollMetrics {
5
+ x: number;
6
+ y: number;
7
+ minX: number;
8
+ maxX: number;
9
+ maxY: number;
10
+ viewportWidth: number;
11
+ viewportHeight: number;
12
+ }
13
+ declare function readScroll(target: ScrollTarget): ScrollMetrics;
14
+ declare function isScrollable(element: HTMLElement, axis: Axis): boolean;
15
+ declare function findScrollParent(element: HTMLElement, axis: Axis): ScrollTarget;
16
+
17
+ type Easing = (t: number) => number;
18
+ declare const easings: {
19
+ linear: (t: number) => number;
20
+ easeInCubic: (t: number) => number;
21
+ easeOutCubic: (t: number) => number;
22
+ easeInOutCubic: (t: number) => number;
23
+ };
24
+ declare function cubicBezier(x1: number, y1: number, x2: number, y2: number): Easing;
25
+
26
+ type ScrollAnimation = {
27
+ type: 'tween';
28
+ duration?: number;
29
+ easing?: Easing;
30
+ } | {
31
+ type: 'spring';
32
+ stiffness?: number;
33
+ damping?: number;
34
+ mass?: number;
35
+ velocity?: {
36
+ x?: number;
37
+ y?: number;
38
+ };
39
+ } | {
40
+ type: 'instant';
41
+ };
42
+ type ScrollResult = 'completed' | 'interrupted' | 'cancelled';
43
+ interface ScrollHandle {
44
+ finished: Promise<ScrollResult>;
45
+ cancel(): void;
46
+ }
47
+ interface AnimateScrollOptions {
48
+ animation?: ScrollAnimation;
49
+ interruptible?: boolean;
50
+ respectReducedMotion?: boolean;
51
+ }
52
+ interface ScrollDestination {
53
+ x?: number;
54
+ y?: number;
55
+ }
56
+ declare function animateScroll(target: ScrollTarget, to: ScrollDestination, options?: AnimateScrollOptions): ScrollHandle;
57
+ declare function cancelScroll(target: ScrollTarget): void;
58
+
59
+ interface ScrollState {
60
+ x: number;
61
+ y: number;
62
+ minX: number;
63
+ maxX: number;
64
+ maxY: number;
65
+ progressX: number;
66
+ progressY: number;
67
+ atTop: boolean;
68
+ atBottom: boolean;
69
+ atLeft: boolean;
70
+ atRight: boolean;
71
+ canScrollX: boolean;
72
+ canScrollY: boolean;
73
+ directionX: Direction;
74
+ directionY: Direction;
75
+ velocityX: number;
76
+ velocityY: number;
77
+ isScrolling: boolean;
78
+ }
79
+ type Direction = -1 | 0 | 1;
80
+ declare function observeScroll(target: ScrollTarget, listener: (state: ScrollState) => void, { idleDelay }?: {
81
+ idleDelay?: number;
82
+ }): () => void;
83
+
84
+ declare function lockScroll({ allow }?: {
85
+ allow?: HTMLElement[];
86
+ }): () => void;
87
+
88
+ interface DragScrollOptions {
89
+ axis?: Axis;
90
+ mouse?: boolean;
91
+ }
92
+ declare function dragScroll(element: HTMLElement, { axis, mouse }?: DragScrollOptions): () => void;
93
+
94
+ declare function readSnapPositions(container: HTMLElement, axis: Axis): number[];
95
+
96
+ declare function observeActiveSection(sections: HTMLElement[], listener: (index: number) => void, { root, offset }?: {
97
+ root?: ScrollTarget;
98
+ offset?: number;
99
+ }): () => void;
100
+
101
+ type Edge = 'top' | 'bottom' | 'left' | 'right';
102
+ type ScrollAlign = 'start' | 'center' | 'end' | 'nearest';
103
+ interface ScrollToElementOptions extends AnimateScrollOptions {
104
+ align?: ScrollAlign;
105
+ offset?: number;
106
+ }
107
+ declare function scrollToEdge(target: ScrollTarget, edge: Edge, options?: AnimateScrollOptions): ScrollHandle;
108
+ declare function scrollBy(target: ScrollTarget, delta: ScrollDestination, options?: AnimateScrollOptions): ScrollHandle;
109
+ declare function scrollToElement(target: ScrollTarget, element: HTMLElement, options?: ScrollToElementOptions): ScrollHandle;
110
+
111
+ interface RestoreScrollOptions {
112
+ storage?: Storage;
113
+ timeout?: number;
114
+ }
115
+ declare function restoreScroll(target: ScrollTarget, key: string, { storage, timeout }?: RestoreScrollOptions): () => void;
116
+
117
+ interface StickToBottom {
118
+ scrollToBottom(options?: AnimateScrollOptions): ScrollHandle;
119
+ stop(): void;
120
+ }
121
+ declare function stickToBottom(element: HTMLElement, onChange?: (isAtBottom: boolean) => void): StickToBottom;
122
+
123
+ export { type AnimateScrollOptions, type Axis, type DragScrollOptions, type Easing, type Edge, type RestoreScrollOptions, type ScrollAlign, type ScrollAnimation, type ScrollDestination, type ScrollHandle, type ScrollMetrics, type ScrollResult, type ScrollState, type ScrollTarget, type ScrollToElementOptions, type StickToBottom, animateScroll, cancelScroll, cubicBezier, dragScroll, easings, findScrollParent, isScrollable, lockScroll, observeActiveSection, observeScroll, readScroll, readSnapPositions, restoreScroll, scrollBy, scrollToEdge, scrollToElement, stickToBottom };
package/dist/core.js ADDED
@@ -0,0 +1,38 @@
1
+ import {
2
+ animateScroll,
3
+ cancelScroll,
4
+ cubicBezier,
5
+ dragScroll,
6
+ easings,
7
+ findScrollParent,
8
+ isScrollable,
9
+ lockScroll,
10
+ observeActiveSection,
11
+ observeScroll,
12
+ readScroll,
13
+ readSnapPositions,
14
+ restoreScroll,
15
+ scrollBy,
16
+ scrollToEdge,
17
+ scrollToElement,
18
+ stickToBottom
19
+ } from "./chunk-IFT3KMZJ.js";
20
+ export {
21
+ animateScroll,
22
+ cancelScroll,
23
+ cubicBezier,
24
+ dragScroll,
25
+ easings,
26
+ findScrollParent,
27
+ isScrollable,
28
+ lockScroll,
29
+ observeActiveSection,
30
+ observeScroll,
31
+ readScroll,
32
+ readSnapPositions,
33
+ restoreScroll,
34
+ scrollBy,
35
+ scrollToEdge,
36
+ scrollToElement,
37
+ stickToBottom
38
+ };
@@ -0,0 +1,51 @@
1
+ import { ScrollDestination, AnimateScrollOptions, ScrollHandle, Edge, ScrollToElementOptions, ScrollState, DragScrollOptions, RestoreScrollOptions } from './core.js';
2
+ export { Axis, Easing, ScrollAlign, ScrollAnimation, ScrollMetrics, ScrollResult, ScrollTarget, StickToBottom, animateScroll, cancelScroll, cubicBezier, dragScroll, easings, findScrollParent, isScrollable, lockScroll, observeActiveSection, observeScroll, readScroll, readSnapPositions, restoreScroll, scrollBy, scrollToEdge, scrollToElement, stickToBottom } from './core.js';
3
+ import { RefObject } from 'react';
4
+
5
+ type ElementTarget = RefObject<HTMLElement | null> | 'window';
6
+
7
+ interface ScrollActions {
8
+ scrollTo(position: ScrollDestination, options?: AnimateScrollOptions): ScrollHandle;
9
+ scrollBy(delta: ScrollDestination, options?: AnimateScrollOptions): ScrollHandle;
10
+ scrollToEdge(edge: Edge, options?: AnimateScrollOptions): ScrollHandle;
11
+ scrollToElement(element: HTMLElement | RefObject<HTMLElement | null>, options?: ScrollToElementOptions): ScrollHandle;
12
+ cancel(): void;
13
+ }
14
+ declare function useScroll(target: ElementTarget, options?: AnimateScrollOptions): ScrollActions;
15
+
16
+ declare function useScrollState(target: ElementTarget): ScrollState;
17
+ declare function useScrollState<T>(target: ElementTarget, select: (state: ScrollState) => T): T;
18
+
19
+ declare function useScrollLock(active: boolean, { allow }?: {
20
+ allow?: Array<RefObject<HTMLElement | null>>;
21
+ }): void;
22
+
23
+ declare function useDragScroll(ref: RefObject<HTMLElement | null>, { axis, mouse }?: DragScrollOptions): void;
24
+
25
+ type Section = RefObject<HTMLElement | null> | string;
26
+ declare function useScrollSpy(sections: Section[], { root, offset }?: {
27
+ root?: RefObject<HTMLElement | null>;
28
+ offset?: number;
29
+ }): number;
30
+
31
+ interface InView {
32
+ inView: boolean;
33
+ entry: IntersectionObserverEntry | null;
34
+ }
35
+ interface InViewOptions {
36
+ root?: RefObject<HTMLElement | null>;
37
+ rootMargin?: string;
38
+ threshold?: number | number[];
39
+ once?: boolean;
40
+ }
41
+ declare function useInView(ref: RefObject<HTMLElement | null>, { root, rootMargin, threshold, once }?: InViewOptions): InView;
42
+
43
+ declare function useScrollRestoration(target: ElementTarget, key: string, { storage, timeout }?: RestoreScrollOptions): void;
44
+
45
+ interface StickToBottomState {
46
+ isAtBottom: boolean;
47
+ scrollToBottom(options?: AnimateScrollOptions): ScrollHandle;
48
+ }
49
+ declare function useStickToBottom(target: RefObject<HTMLElement | null>): StickToBottomState;
50
+
51
+ export { AnimateScrollOptions, DragScrollOptions, Edge, type InView, type InViewOptions, RestoreScrollOptions, type ScrollActions, ScrollDestination, ScrollHandle, ScrollState, ScrollToElementOptions, type StickToBottomState, useDragScroll, useInView, useScroll, useScrollLock, useScrollRestoration, useScrollSpy, useScrollState, useStickToBottom };
package/dist/index.js ADDED
@@ -0,0 +1,348 @@
1
+ 'use client'
2
+ import {
3
+ animateScroll,
4
+ cancelScroll,
5
+ cubicBezier,
6
+ dragScroll,
7
+ easings,
8
+ findScrollParent,
9
+ initialScrollState,
10
+ isScrollable,
11
+ isWindow,
12
+ lockScroll,
13
+ observeActiveSection,
14
+ observeScroll,
15
+ readScroll,
16
+ readSnapPositions,
17
+ restoreScroll,
18
+ scrollBy,
19
+ scrollToEdge,
20
+ scrollToElement,
21
+ stickToBottom
22
+ } from "./chunk-IFT3KMZJ.js";
23
+
24
+ // src/react/use-scroll.ts
25
+ import { useRef as useRef2, useState } from "react";
26
+
27
+ // src/react/use-element-effect.ts
28
+ import { useEffect, useLayoutEffect, useRef } from "react";
29
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
30
+ function resolveTarget(target) {
31
+ return target === "window" ? window : target.current;
32
+ }
33
+ function useElementEffect(target, effect, deps) {
34
+ const subscription = useRef(null);
35
+ function sync() {
36
+ const resolved = resolveTarget(target);
37
+ const previous = subscription.current;
38
+ if (previous && previous.target === resolved && sameDeps(previous.deps, deps)) return;
39
+ if (previous == null ? void 0 : previous.cleanup) previous.cleanup();
40
+ subscription.current = {
41
+ target: resolved,
42
+ deps,
43
+ cleanup: resolved ? effect(resolved) : void 0
44
+ };
45
+ }
46
+ useIsomorphicLayoutEffect(sync);
47
+ useEffect(sync);
48
+ useIsomorphicLayoutEffect(
49
+ () => () => {
50
+ var _a, _b;
51
+ (_b = (_a = subscription.current) == null ? void 0 : _a.cleanup) == null ? void 0 : _b.call(_a);
52
+ subscription.current = null;
53
+ },
54
+ []
55
+ );
56
+ }
57
+ function sameDeps(a, b) {
58
+ return a.length === b.length && a.every((dep, i) => Object.is(dep, b[i]));
59
+ }
60
+
61
+ // src/react/use-scroll.ts
62
+ function useScroll(target, options) {
63
+ const latest = useRef2({ target, options });
64
+ const lastStarted = useRef2(null);
65
+ useIsomorphicLayoutEffect(() => {
66
+ latest.current = { target, options };
67
+ });
68
+ useIsomorphicLayoutEffect(() => () => {
69
+ var _a;
70
+ return (_a = lastStarted.current) == null ? void 0 : _a.cancel();
71
+ }, []);
72
+ const [actions] = useState(() => {
73
+ function attachedTarget() {
74
+ const resolved = resolveTarget(latest.current.target);
75
+ if (!resolved) throw new Error("useScroll: ref is not attached to an element");
76
+ return resolved;
77
+ }
78
+ function track(handle) {
79
+ lastStarted.current = handle;
80
+ return handle;
81
+ }
82
+ function withDefaults(perCall) {
83
+ return { ...latest.current.options, ...perCall };
84
+ }
85
+ return {
86
+ scrollTo: (position, perCall) => track(animateScroll(attachedTarget(), position, withDefaults(perCall))),
87
+ scrollBy: (delta, perCall) => track(scrollBy(attachedTarget(), delta, withDefaults(perCall))),
88
+ scrollToEdge: (edge, perCall) => track(scrollToEdge(attachedTarget(), edge, withDefaults(perCall))),
89
+ scrollToElement: (element, perCall) => track(scrollToElement(attachedTarget(), attachedElement(element), withDefaults(perCall))),
90
+ cancel() {
91
+ const resolved = resolveTarget(latest.current.target);
92
+ if (resolved) cancelScroll(resolved);
93
+ }
94
+ };
95
+ });
96
+ return actions;
97
+ }
98
+ function attachedElement(element) {
99
+ if (!("current" in element)) return element;
100
+ if (!element.current) {
101
+ throw new Error("useScroll: scrollToElement ref is not attached to an element");
102
+ }
103
+ return element.current;
104
+ }
105
+
106
+ // src/react/use-scroll-state.ts
107
+ import { useMemo, useState as useState2, useSyncExternalStore } from "react";
108
+ function useScrollState(target, select) {
109
+ const [store] = useState2(createScrollStore);
110
+ useElementEffect(target, (element) => observeScroll(element, store.set), [store]);
111
+ const [getSnapshot, getServerSnapshot] = useMemo(() => {
112
+ const choose = select != null ? select : identity;
113
+ const selectFrom = memoizeLast(choose);
114
+ return [() => selectFrom(store.get()), () => selectFrom(initialScrollState)];
115
+ }, [store, select]);
116
+ return useSyncExternalStore(store.subscribe, getSnapshot, getServerSnapshot);
117
+ }
118
+ function createScrollStore() {
119
+ let state = initialScrollState;
120
+ const listeners = /* @__PURE__ */ new Set();
121
+ return {
122
+ get: () => state,
123
+ set(next) {
124
+ state = next;
125
+ for (const listener of listeners) listener();
126
+ },
127
+ subscribe(listener) {
128
+ listeners.add(listener);
129
+ return () => {
130
+ listeners.delete(listener);
131
+ };
132
+ }
133
+ };
134
+ }
135
+ function memoizeLast(fn) {
136
+ let last = null;
137
+ return (arg) => {
138
+ if (last === null || last.arg !== arg) last = { arg, result: fn(arg) };
139
+ return last.result;
140
+ };
141
+ }
142
+ function identity(value) {
143
+ return value;
144
+ }
145
+
146
+ // src/react/use-scroll-lock.ts
147
+ import { useRef as useRef3 } from "react";
148
+ function useScrollLock(active, { allow = [] } = {}) {
149
+ const held = useRef3(null);
150
+ useIsomorphicLayoutEffect(() => {
151
+ const previous = held.current;
152
+ if (!active) {
153
+ previous == null ? void 0 : previous.unlock();
154
+ held.current = null;
155
+ return;
156
+ }
157
+ const elements = allow.flatMap((ref) => ref.current ? [ref.current] : []);
158
+ if (previous && sameElements(previous.allow, elements)) return;
159
+ held.current = { allow: elements, unlock: lockScroll({ allow: elements }) };
160
+ previous == null ? void 0 : previous.unlock();
161
+ });
162
+ useIsomorphicLayoutEffect(
163
+ () => () => {
164
+ var _a;
165
+ (_a = held.current) == null ? void 0 : _a.unlock();
166
+ held.current = null;
167
+ },
168
+ []
169
+ );
170
+ }
171
+ function sameElements(a, b) {
172
+ return a.length === b.length && a.every((element, i) => element === b[i]);
173
+ }
174
+
175
+ // src/react/use-drag-scroll.ts
176
+ function useDragScroll(ref, { axis = "x", mouse = false } = {}) {
177
+ useElementEffect(
178
+ ref,
179
+ (element) => {
180
+ if (isWindow(element)) throw new Error("useDragScroll: ref must point at an element");
181
+ return dragScroll(element, { axis, mouse });
182
+ },
183
+ [axis, mouse]
184
+ );
185
+ }
186
+
187
+ // src/react/use-scroll-spy.ts
188
+ import { useRef as useRef4, useState as useState3 } from "react";
189
+ function useScrollSpy(sections, { root, offset = 0 } = {}) {
190
+ const [active, setActive] = useState3(-1);
191
+ const subscription = useRef4(null);
192
+ useIsomorphicLayoutEffect(() => {
193
+ const previous = subscription.current;
194
+ const rootTarget = resolveTarget(root != null ? root : "window");
195
+ if (!rootTarget) {
196
+ previous == null ? void 0 : previous.unsubscribe();
197
+ subscription.current = null;
198
+ return;
199
+ }
200
+ const elements = sections.map(resolveSection);
201
+ if (previous && previous.root === rootTarget && previous.offset === offset && sameElements2(previous.sections, elements)) {
202
+ return;
203
+ }
204
+ previous == null ? void 0 : previous.unsubscribe();
205
+ subscription.current = {
206
+ root: rootTarget,
207
+ sections: elements,
208
+ offset,
209
+ unsubscribe: observeActiveSection(elements, setActive, { root: rootTarget, offset })
210
+ };
211
+ });
212
+ useIsomorphicLayoutEffect(
213
+ () => () => {
214
+ var _a;
215
+ (_a = subscription.current) == null ? void 0 : _a.unsubscribe();
216
+ subscription.current = null;
217
+ },
218
+ []
219
+ );
220
+ return active;
221
+ }
222
+ function resolveSection(section, index) {
223
+ if (typeof section === "string") {
224
+ const element = document.getElementById(section);
225
+ if (!element) throw new Error(`useScrollSpy: no element with id "${section}"`);
226
+ return element;
227
+ }
228
+ if (!section.current) {
229
+ throw new Error(`useScrollSpy: section ref at index ${index} is not attached to an element`);
230
+ }
231
+ return section.current;
232
+ }
233
+ function sameElements2(a, b) {
234
+ return a.length === b.length && a.every((element, i) => element === b[i]);
235
+ }
236
+
237
+ // src/react/use-in-view.ts
238
+ import { useRef as useRef5, useState as useState4 } from "react";
239
+ var NOT_IN_VIEW = { inView: false, entry: null };
240
+ function useInView(ref, { root, rootMargin, threshold, once = false } = {}) {
241
+ const [state, setState] = useState4(NOT_IN_VIEW);
242
+ const observation = useRef5(null);
243
+ const seenOnce = useRef5(false);
244
+ useIsomorphicLayoutEffect(() => {
245
+ const previous = observation.current;
246
+ const element = ref.current;
247
+ const rootElement = root ? root.current : null;
248
+ if (!element || root && !rootElement || seenOnce.current) {
249
+ previous == null ? void 0 : previous.disconnect();
250
+ observation.current = null;
251
+ return;
252
+ }
253
+ const settings = JSON.stringify([rootMargin, threshold, once]);
254
+ if (previous && previous.element === element && previous.root === rootElement && previous.settings === settings) {
255
+ return;
256
+ }
257
+ previous == null ? void 0 : previous.disconnect();
258
+ const observer = new IntersectionObserver(
259
+ (entries) => {
260
+ const entry = entries[entries.length - 1];
261
+ const inView = entry.isIntersecting && observer.thresholds.some((t) => entry.intersectionRatio >= t);
262
+ setState({ inView, entry });
263
+ if (once && inView) {
264
+ seenOnce.current = true;
265
+ observer.disconnect();
266
+ }
267
+ },
268
+ { root: rootElement, rootMargin, threshold }
269
+ );
270
+ observer.observe(element);
271
+ observation.current = {
272
+ element,
273
+ root: rootElement,
274
+ settings,
275
+ disconnect: () => observer.disconnect()
276
+ };
277
+ });
278
+ useIsomorphicLayoutEffect(
279
+ () => () => {
280
+ var _a;
281
+ (_a = observation.current) == null ? void 0 : _a.disconnect();
282
+ observation.current = null;
283
+ },
284
+ []
285
+ );
286
+ return state;
287
+ }
288
+
289
+ // src/react/use-scroll-restoration.ts
290
+ function useScrollRestoration(target, key, { storage, timeout } = {}) {
291
+ useElementEffect(target, (element) => restoreScroll(element, key, { storage, timeout }), [
292
+ key,
293
+ storage,
294
+ timeout
295
+ ]);
296
+ }
297
+
298
+ // src/react/use-stick-to-bottom.ts
299
+ import { useRef as useRef6, useState as useState5 } from "react";
300
+ function useStickToBottom(target) {
301
+ const [isAtBottom, setIsAtBottom] = useState5(true);
302
+ const attached = useRef6(null);
303
+ useElementEffect(
304
+ target,
305
+ (element) => {
306
+ if (isWindow(element)) throw new Error("useStickToBottom: target must be an element ref");
307
+ const sticking = stickToBottom(element, setIsAtBottom);
308
+ attached.current = sticking;
309
+ return () => {
310
+ sticking.stop();
311
+ if (attached.current === sticking) attached.current = null;
312
+ };
313
+ },
314
+ []
315
+ );
316
+ const [scrollToBottom] = useState5(() => (options) => {
317
+ if (!attached.current) throw new Error("useStickToBottom: ref is not attached to an element");
318
+ return attached.current.scrollToBottom(options);
319
+ });
320
+ return { isAtBottom, scrollToBottom };
321
+ }
322
+ export {
323
+ animateScroll,
324
+ cancelScroll,
325
+ cubicBezier,
326
+ dragScroll,
327
+ easings,
328
+ findScrollParent,
329
+ isScrollable,
330
+ lockScroll,
331
+ observeActiveSection,
332
+ observeScroll,
333
+ readScroll,
334
+ readSnapPositions,
335
+ restoreScroll,
336
+ scrollBy,
337
+ scrollToEdge,
338
+ scrollToElement,
339
+ stickToBottom,
340
+ useDragScroll,
341
+ useInView,
342
+ useScroll,
343
+ useScrollLock,
344
+ useScrollRestoration,
345
+ useScrollSpy,
346
+ useScrollState,
347
+ useStickToBottom
348
+ };
package/package.json CHANGED
@@ -1,14 +1,25 @@
1
1
  {
2
2
  "name": "use-scroller",
3
- "version": "1.2.0",
3
+ "version": "2.1.0",
4
4
  "author": "silvi lila",
5
5
  "license": "MIT",
6
- "main": "./dist/cjs/index.js",
7
- "module": "./dist/esm/index.js",
8
- "types": "./dist/esm/index.d.ts",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./core": {
17
+ "types": "./dist/core.d.ts",
18
+ "default": "./dist/core.js"
19
+ }
20
+ },
9
21
  "files": [
10
- "dist",
11
- "src"
22
+ "dist"
12
23
  ],
13
24
  "keywords": [
14
25
  "react",
@@ -17,16 +28,13 @@
17
28
  ],
18
29
  "repository": {
19
30
  "type": "git",
20
- "url": "https://github.com/silvi97lila/use-scroller.git"
31
+ "url": "git+https://github.com/silverlila/use-scroller.git"
21
32
  },
22
33
  "scripts": {
23
- "build": "yarn clean && yarn build:esm && yarn build:cjs",
24
- "build:watch": "yarn build --watch",
25
- "build:esm": "tsc",
26
- "build:cjs": "tsc --module commonjs --outDir dist/cjs",
27
- "clean": "rm -rf ./dist",
28
- "test": "jest",
29
- "lint": "lint ./src/*",
34
+ "build": "tsup",
35
+ "typecheck": "tsc --noEmit",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
30
38
  "release": "yarn build && yarn changeset version && yarn changeset publish",
31
39
  "changeset": "changeset"
32
40
  },
@@ -37,23 +45,29 @@
37
45
  "trailingComma": "es5"
38
46
  },
39
47
  "peerDependencies": {
40
- "react": "^16 || ^17 || ^18",
41
- "react-dom": "^16 || ^17 || ^18"
48
+ "react": "^18 || ^19"
49
+ },
50
+ "peerDependenciesMeta": {
51
+ "react": {
52
+ "optional": true
53
+ }
42
54
  },
43
55
  "devDependencies": {
44
- "@babel/preset-env": "^7.20.2",
45
- "@babel/preset-typescript": "^7.18.6",
46
56
  "@changesets/cli": "^2.26.0",
47
- "@testing-library/react": "^13.4.0",
48
- "@types/jest": "^29.2.3",
49
- "@types/react": "^18.0.25",
50
- "@types/react-dom": "^18.0.9",
57
+ "@types/react": "^19.3.0",
58
+ "@types/react-dom": "^19.3.0",
51
59
  "@typescript-eslint/eslint-plugin": "^5.44.0",
52
60
  "@typescript-eslint/parser": "^5.44.0",
61
+ "@vitest/browser-playwright": "^4.1.11",
53
62
  "eslint": "^8.28.0",
54
63
  "eslint-plugin-react": "^7.31.11",
55
- "jest": "^29.3.1",
64
+ "playwright": "^1.63.0",
56
65
  "prettier": "2.8.0",
57
- "typescript": "^4.9.3"
66
+ "react": "^19.3.0",
67
+ "react-dom": "^19.3.0",
68
+ "tsup": "^8.5.1",
69
+ "typescript": "^5.9.3",
70
+ "vitest": "^4.1.11",
71
+ "vitest-browser-react": "^2.3.0"
58
72
  }
59
73
  }
@@ -1,2 +0,0 @@
1
- import { useEffect } from 'react';
2
- export declare const useIsoMorphicEffect: typeof useEffect;
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useIsoMorphicEffect = void 0;
4
- var react_1 = require("react");
5
- var utils_1 = require("../utils");
6
- exports.useIsoMorphicEffect = utils_1.isServer ? react_1.useEffect : react_1.useLayoutEffect;
@@ -1,24 +0,0 @@
1
- /// <reference types="react" />
2
- import { ScrollOptions } from '../types';
3
- export declare function useScroll<T extends HTMLElement>(props?: Partial<ScrollOptions>): {
4
- ref: import("react").RefObject<T>;
5
- state: {
6
- left: number;
7
- top: number;
8
- isScrollable: boolean;
9
- isScrolledLeft: boolean;
10
- isScrolledRight: boolean;
11
- isScrolledTop: boolean;
12
- isScrolledBottom: boolean;
13
- maxScrollLeft: number;
14
- maxScrollTop: number;
15
- scrollPercentageX: number;
16
- scrollPercentageY: number;
17
- };
18
- scrollLeft: ((offset?: number | undefined) => void) | undefined;
19
- scrollRight: ((offset?: number | undefined) => void) | undefined;
20
- scrollBottom: ((offset?: number | undefined) => void) | undefined;
21
- scrollTop: ((offset?: number | undefined) => void) | undefined;
22
- scrollCenter: (() => void) | undefined;
23
- scrollTo: ((to: number) => void) | undefined;
24
- };