@siberiacancode/reactuse 0.2.31 → 0.2.33
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 +71 -71
- package/dist/cjs/helpers/createStore/createStore.cjs +1 -1
- package/dist/cjs/helpers/createStore/createStore.cjs.map +1 -1
- package/dist/cjs/hooks/useActiveElement/useActiveElement.cjs +1 -1
- package/dist/cjs/hooks/useActiveElement/useActiveElement.cjs.map +1 -1
- package/dist/cjs/hooks/useAsyncEffect/useAsyncEffect.cjs +2 -0
- package/dist/cjs/hooks/useAsyncEffect/useAsyncEffect.cjs.map +1 -0
- package/dist/cjs/hooks/useControllableState/useControllableState.cjs +2 -0
- package/dist/cjs/hooks/useControllableState/useControllableState.cjs.map +1 -0
- package/dist/cjs/hooks/useFocusTrap/useFocusTrap.cjs +2 -0
- package/dist/cjs/hooks/useFocusTrap/useFocusTrap.cjs.map +1 -0
- package/dist/cjs/hooks/useScroll/useScroll.cjs +1 -1
- package/dist/cjs/hooks/useScroll/useScroll.cjs.map +1 -1
- package/dist/cjs/index.cjs +1 -1
- package/dist/esm/helpers/createStore/createStore.mjs +4 -4
- package/dist/esm/helpers/createStore/createStore.mjs.map +1 -1
- package/dist/esm/hooks/useActiveElement/useActiveElement.mjs +5 -7
- package/dist/esm/hooks/useActiveElement/useActiveElement.mjs.map +1 -1
- package/dist/esm/hooks/useAsyncEffect/useAsyncEffect.mjs +10 -0
- package/dist/esm/hooks/useAsyncEffect/useAsyncEffect.mjs.map +1 -0
- package/dist/esm/hooks/useControllableState/useControllableState.mjs +17 -0
- package/dist/esm/hooks/useControllableState/useControllableState.mjs.map +1 -0
- package/dist/esm/hooks/useFocusTrap/useFocusTrap.mjs +56 -0
- package/dist/esm/hooks/useFocusTrap/useFocusTrap.mjs.map +1 -0
- package/dist/esm/hooks/useScroll/useScroll.mjs +53 -35
- package/dist/esm/hooks/useScroll/useScroll.mjs.map +1 -1
- package/dist/esm/index.mjs +270 -264
- package/dist/esm/index.mjs.map +1 -1
- package/dist/types/hooks/elements.d.ts +1 -0
- package/dist/types/hooks/lifecycle.d.ts +1 -0
- package/dist/types/hooks/state.d.ts +1 -0
- package/dist/types/hooks/useActiveElement/useActiveElement.d.ts +5 -3
- package/dist/types/hooks/useAsyncEffect/useAsyncEffect.d.ts +14 -0
- package/dist/types/hooks/useControllableState/useControllableState.d.ts +34 -0
- package/dist/types/hooks/useFocusTrap/useFocusTrap.d.ts +42 -0
- package/dist/types/hooks/useScroll/useScroll.d.ts +33 -14
- package/package.json +89 -89
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useState as h } from "react";
|
|
2
|
+
import { useIsomorphicLayoutEffect as p } from "../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.mjs";
|
|
3
|
+
import { useRefState as v } from "../useRefState/useRefState.mjs";
|
|
4
|
+
import { isTarget as g } from "../../utils/helpers/isTarget.mjs";
|
|
5
|
+
import { getElement as S } from "../../utils/helpers/getElement.mjs";
|
|
6
|
+
const L = [
|
|
7
|
+
"input:not([disabled])",
|
|
8
|
+
"select:not([disabled])",
|
|
9
|
+
"textarea:not([disabled])",
|
|
10
|
+
"button:not([disabled])",
|
|
11
|
+
"a[href]",
|
|
12
|
+
"area[href]",
|
|
13
|
+
"summary",
|
|
14
|
+
"iframe",
|
|
15
|
+
"object",
|
|
16
|
+
"embed",
|
|
17
|
+
"audio[controls]",
|
|
18
|
+
"video[controls]",
|
|
19
|
+
"[contenteditable]",
|
|
20
|
+
'[tabindex]:not([tabindex^="-"])'
|
|
21
|
+
].join(","), y = (e) => Array.from(
|
|
22
|
+
e.querySelectorAll(L)
|
|
23
|
+
).filter((o) => {
|
|
24
|
+
const n = o;
|
|
25
|
+
return n.tabIndex !== -1 && !n.hidden && n.style.display !== "none";
|
|
26
|
+
}), x = (e) => {
|
|
27
|
+
const t = e.querySelector(
|
|
28
|
+
"[data-autofocus]"
|
|
29
|
+
);
|
|
30
|
+
if (t) return t.focus();
|
|
31
|
+
const o = y(e);
|
|
32
|
+
o.length > 0 && o[0].focus();
|
|
33
|
+
}, F = (...e) => {
|
|
34
|
+
const t = g(e[0]) ? e[0] : void 0, o = t ? e[1] : e[0], [n, c] = h(o), i = v(), l = () => c(!0), u = () => c(!1), a = () => c((r) => !r);
|
|
35
|
+
return p(() => {
|
|
36
|
+
if (!n) return;
|
|
37
|
+
const r = t ? S(t) : i.current;
|
|
38
|
+
if (!r) return;
|
|
39
|
+
const f = r;
|
|
40
|
+
x(f);
|
|
41
|
+
const m = (s) => {
|
|
42
|
+
if (s.key !== "Tab") return;
|
|
43
|
+
const [d, ...E] = y(f);
|
|
44
|
+
if (!E.length) return;
|
|
45
|
+
const b = E.at(-1);
|
|
46
|
+
s.shiftKey && document.activeElement === d && (s.preventDefault(), b.focus()), document.activeElement === b && (s.preventDefault(), d.focus());
|
|
47
|
+
};
|
|
48
|
+
return document.addEventListener("keydown", m), () => {
|
|
49
|
+
document.removeEventListener("keydown", m);
|
|
50
|
+
};
|
|
51
|
+
}, [n, t, i.state]), t ? { active: n, enable: l, disable: u, toggle: a } : { active: n, enable: l, disable: u, toggle: a, ref: i };
|
|
52
|
+
};
|
|
53
|
+
export {
|
|
54
|
+
F as useFocusTrap
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=useFocusTrap.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFocusTrap.mjs","sources":["../../../../src/hooks/useFocusTrap/useFocusTrap.ts"],"sourcesContent":["import { useState } from \"react\";\n\nimport type { HookTarget } from \"@/utils/helpers\";\n\nimport { getElement, isTarget } from \"@/utils/helpers\";\n\nimport type { StateRef } from \"../useRefState/useRefState\";\n\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect/useIsomorphicLayoutEffect\";\nimport { useRefState } from \"../useRefState/useRefState\";\n\nconst FOCUSABLE_ELEMENTS_SELECTOR = [\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"button:not([disabled])\",\n \"a[href]\",\n \"area[href]\",\n \"summary\",\n \"iframe\",\n \"object\",\n \"embed\",\n \"audio[controls]\",\n \"video[controls]\",\n \"[contenteditable]\",\n '[tabindex]:not([tabindex^=\"-\"])',\n].join(\",\");\n\nconst getFocusableElements = (element: HTMLElement): HTMLElement[] => {\n const elements = Array.from(\n element.querySelectorAll(FOCUSABLE_ELEMENTS_SELECTOR)\n );\n return elements.filter((el) => {\n const htmlEl = el as HTMLElement;\n return (\n htmlEl.tabIndex !== -1 &&\n !htmlEl.hidden &&\n htmlEl.style.display !== \"none\"\n );\n }) as HTMLElement[];\n};\n\nconst focusElement = (element: HTMLElement) => {\n const autofocusElement = element.querySelector(\n \"[data-autofocus]\"\n ) as HTMLElement;\n if (autofocusElement) return autofocusElement.focus();\n\n const focusableElements = getFocusableElements(element);\n if (focusableElements.length > 0) {\n focusableElements[0].focus();\n }\n};\n\n/** The use focus trap return type */\nexport interface UseFocusTrapReturn {\n /** Whether focus trap is active */\n active: boolean;\n /** Disable focus trap */\n disable: () => void;\n /** Enable focus trap */\n enable: () => void;\n /** Toggle focus trap */\n toggle: () => void;\n}\n\nexport interface UseFocusTrap {\n (target: HookTarget, active?: boolean): UseFocusTrapReturn;\n\n <Target extends HTMLElement>(\n active?: boolean,\n target?: never\n ): UseFocusTrapReturn & {\n ref: StateRef<Target>;\n };\n}\n\n/**\n * @name useFocusTrap\n * @description - Hook that traps focus within a given element\n * @category Elements\n * @usage medium\n *\n * @overload\n * @param {HookTarget} target The target element for focus trap\n * @param {boolean} [active=true] Whether focus trap is active\n * @returns {UseFocusTrapReturn} Object with control methods and state\n *\n * @example\n * const { active, disable, toggle, enable } = useFocusTrap(ref, true);\n *\n * @overload\n * @template Target The target element type\n * @param {boolean} [active=true] Whether focus trap is active\n * @returns {UseFocusTrapReturn & { ref: StateRef<Target> }} Object with ref and controls\n *\n * @example\n * const { ref, active, disable, toggle, enable } = useFocusTrap(true);\n */\nexport const useFocusTrap = ((...params: any[]) => {\n const target = (isTarget(params[0]) ? params[0] : undefined) as\n | HookTarget\n | undefined;\n const initialActive = target ? params[1] : params[0];\n\n const [active, setActive] = useState(initialActive);\n const internalRef = useRefState<HTMLElement>();\n\n const enable = () => setActive(true);\n const disable = () => setActive(false);\n const toggle = () => setActive((prevActive: boolean) => !prevActive);\n\n useIsomorphicLayoutEffect(() => {\n if (!active) return;\n\n const element = target ? getElement(target) : internalRef.current;\n if (!element) return;\n\n const htmlElement = element as HTMLElement;\n focusElement(htmlElement);\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Tab\") return;\n\n const [firstElement, ...restElements] = getFocusableElements(htmlElement);\n if (!restElements.length) return;\n\n const lastElement = restElements.at(-1)!;\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n }\n\n if (document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n };\n\n document.addEventListener(\"keydown\", onKeyDown);\n\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [active, target, internalRef.state]);\n\n if (target) return { active, enable, disable, toggle };\n return { active, enable, disable, toggle, ref: internalRef };\n}) as UseFocusTrap;\n"],"names":["FOCUSABLE_ELEMENTS_SELECTOR","getFocusableElements","element","el","htmlEl","focusElement","autofocusElement","focusableElements","useFocusTrap","params","target","isTarget","initialActive","active","setActive","useState","internalRef","useRefState","enable","disable","toggle","prevActive","useIsomorphicLayoutEffect","getElement","htmlElement","onKeyDown","event","firstElement","restElements","lastElement"],"mappings":";;;;;AAWA,MAAMA,IAA8B;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG,GAEJC,IAAuB,CAACC,MACX,MAAM;AAAA,EACrBA,EAAQ,iBAAiBF,CAA2B;AAAA,EAEtC,OAAO,CAACG,MAAO;AAC7B,QAAMC,IAASD;AACf,SACEC,EAAO,aAAa,MACpB,CAACA,EAAO,UACRA,EAAO,MAAM,YAAY;AAAA,CAE5B,GAGGC,IAAe,CAACH,MAAyB;AAC7C,QAAMI,IAAmBJ,EAAQ;AAAA,IAC/B;AAAA,EAAA;AAEF,MAAII,EAAkB,QAAOA,EAAiB,MAAA;AAE9C,QAAMC,IAAoBN,EAAqBC,CAAO;AACtD,EAAIK,EAAkB,SAAS,KAC7BA,EAAkB,CAAC,EAAE,MAAA;AAEzB,GA+CaC,IAAgB,IAAIC,MAAkB;AACjD,QAAMC,IAAUC,EAASF,EAAO,CAAC,CAAC,IAAIA,EAAO,CAAC,IAAI,QAG5CG,IAAgBF,IAASD,EAAO,CAAC,IAAIA,EAAO,CAAC,GAE7C,CAACI,GAAQC,CAAS,IAAIC,EAASH,CAAa,GAC5CI,IAAcC,EAAA,GAEdC,IAAS,MAAMJ,EAAU,EAAI,GAC7BK,IAAU,MAAML,EAAU,EAAK,GAC/BM,IAAS,MAAMN,EAAU,CAACO,MAAwB,CAACA,CAAU;AAqCnE,SAnCAC,EAA0B,MAAM;AAC9B,QAAI,CAACT,EAAQ;AAEb,UAAMX,IAAUQ,IAASa,EAAWb,CAAM,IAAIM,EAAY;AAC1D,QAAI,CAACd,EAAS;AAEd,UAAMsB,IAActB;AACpB,IAAAG,EAAamB,CAAW;AAExB,UAAMC,IAAY,CAACC,MAAyB;AAC1C,UAAIA,EAAM,QAAQ,MAAO;AAEzB,YAAM,CAACC,GAAc,GAAGC,CAAY,IAAI3B,EAAqBuB,CAAW;AACxE,UAAI,CAACI,EAAa,OAAQ;AAE1B,YAAMC,IAAcD,EAAa,GAAG,EAAE;AAEtC,MAAIF,EAAM,YAAY,SAAS,kBAAkBC,MAC/CD,EAAM,eAAA,GACNG,EAAY,MAAA,IAGV,SAAS,kBAAkBA,MAC7BH,EAAM,eAAA,GACNC,EAAa,MAAA;AAAA,IACf;AAGF,oBAAS,iBAAiB,WAAWF,CAAS,GAEvC,MAAM;AACX,eAAS,oBAAoB,WAAWA,CAAS;AAAA,IAAA;AAAA,EACnD,GACC,CAACZ,GAAQH,GAAQM,EAAY,KAAK,CAAC,GAElCN,IAAe,EAAE,QAAAG,GAAQ,QAAAK,GAAQ,SAAAC,GAAS,QAAAC,EAAA,IACvC,EAAE,QAAAP,GAAQ,QAAAK,GAAQ,SAAAC,GAAS,QAAAC,GAAQ,KAAKJ,EAAA;AACjD;"}
|
|
@@ -1,47 +1,65 @@
|
|
|
1
|
-
import { useRef as
|
|
2
|
-
import { useRefState as
|
|
3
|
-
import { isTarget as
|
|
4
|
-
import { getElement as
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const [
|
|
9
|
-
|
|
10
|
-
if (!
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
import { useRef as S, useState as j, useEffect as A } from "react";
|
|
2
|
+
import { useRefState as O } from "../useRefState/useRefState.mjs";
|
|
3
|
+
import { isTarget as P } from "../../utils/helpers/isTarget.mjs";
|
|
4
|
+
import { getElement as W } from "../../utils/helpers/getElement.mjs";
|
|
5
|
+
const I = 1, q = (...o) => {
|
|
6
|
+
const c = P(o[0]) ? o[0] : void 0, g = c ? typeof o[1] == "object" ? o[1] : { onScroll: o[1] } : typeof o[0] == "object" ? o[0] : { onScroll: o[0] }, d = O(), p = S(g), f = S(null);
|
|
7
|
+
p.current = g;
|
|
8
|
+
const [E, R] = j(!1), u = S({ x: 0, y: 0 });
|
|
9
|
+
A(() => {
|
|
10
|
+
if (!c && !d.state) return;
|
|
11
|
+
const e = (c ? W(c) : d.current) ?? window;
|
|
12
|
+
f.current = e;
|
|
13
|
+
const l = (t) => {
|
|
14
|
+
R(!1), g?.onStop?.(t);
|
|
15
|
+
}, s = (t) => {
|
|
16
|
+
R(!0);
|
|
17
|
+
const r = t.target === document ? t.target.documentElement : t.target, { display: b, flexDirection: h, direction: V } = r.style, x = V === "rtl" ? -1 : 1, i = r.scrollLeft;
|
|
18
|
+
let n = r.scrollTop;
|
|
19
|
+
r instanceof Document && !n && (n = window.document.body.scrollTop);
|
|
20
|
+
const m = p.current?.offset, a = i * x <= (m?.left ?? 0), T = i * x + r.clientWidth >= r.scrollWidth - (m?.right ?? 0) - I, L = n <= (m?.top ?? 0), w = n + r.clientHeight >= r.scrollHeight - (m?.bottom ?? 0) - I, D = b === "flex" && h === "column-reverse", H = b === "flex" && h === "column-reverse", _ = {
|
|
21
|
+
x: i,
|
|
22
|
+
y: n,
|
|
21
23
|
directions: {
|
|
22
|
-
left:
|
|
23
|
-
right:
|
|
24
|
-
top:
|
|
25
|
-
bottom:
|
|
24
|
+
left: i < u.current.x,
|
|
25
|
+
right: i > u.current.x,
|
|
26
|
+
top: n < u.current.y,
|
|
27
|
+
bottom: n > u.current.y
|
|
26
28
|
},
|
|
27
29
|
arrived: {
|
|
28
|
-
left:
|
|
29
|
-
right:
|
|
30
|
-
top:
|
|
31
|
-
bottom:
|
|
30
|
+
left: H ? T : a,
|
|
31
|
+
right: H ? a : T,
|
|
32
|
+
top: D ? w : L,
|
|
33
|
+
bottom: D ? L : w
|
|
32
34
|
}
|
|
33
35
|
};
|
|
34
|
-
|
|
36
|
+
u.current = { x: i, y: n }, p.current?.onScroll?.(_, t);
|
|
35
37
|
};
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
+
return e.addEventListener("scroll", s), e.addEventListener("scrollend", l), () => {
|
|
39
|
+
e.removeEventListener("scroll", s), e.removeEventListener("scrollend", l);
|
|
38
40
|
};
|
|
39
|
-
}, [
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
}, [c, d.state]);
|
|
42
|
+
const v = (e) => {
|
|
43
|
+
if (!f.current) return;
|
|
44
|
+
const { behavior: l, block: s, inline: t } = e ?? {};
|
|
45
|
+
f.current.scrollIntoView({
|
|
46
|
+
behavior: l,
|
|
47
|
+
block: s,
|
|
48
|
+
inline: t
|
|
49
|
+
});
|
|
50
|
+
}, y = (e) => {
|
|
51
|
+
if (!f.current) return;
|
|
52
|
+
const { x: l, y: s, behavior: t } = e ?? {};
|
|
53
|
+
f.current.scrollTo({ left: l, top: s, behavior: t });
|
|
54
|
+
};
|
|
55
|
+
return c ? { scrollIntoView: v, scrollTo: y, scrolling: E } : {
|
|
56
|
+
ref: d,
|
|
57
|
+
scrolling: E,
|
|
58
|
+
scrollIntoView: v,
|
|
59
|
+
scrollTo: y
|
|
42
60
|
};
|
|
43
61
|
};
|
|
44
62
|
export {
|
|
45
|
-
|
|
63
|
+
q as useScroll
|
|
46
64
|
};
|
|
47
65
|
//# sourceMappingURL=useScroll.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScroll.mjs","sources":["../../../../src/hooks/useScroll/useScroll.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\n\nimport type { HookTarget } from '@/utils/helpers';\n\nimport { getElement, isTarget } from '@/utils/helpers';\n\nimport type { StateRef } from '../useRefState/useRefState';\n\nimport { useRefState } from '../useRefState/useRefState';\n\nconst ARRIVED_STATE_THRESHOLD_PIXELS = 1;\n\nexport interface UseScrollOptions {\n /** The on scroll callback */\n onScroll?: (params: UseScrollCallbackParams, event: Event) => void;\n\n /** The on end scroll callback */\n onStop?: (event: Event) => void;\n\n /** Offset arrived states by x pixels. */\n offset?: {\n left?: number;\n right?: number;\n top?: number;\n bottom?: number;\n };\n}\n\nexport interface UseScrollCallbackParams {\n /** The element x position */\n x: number;\n /** The element y position */\n y: number;\n /** State of scroll arrived */\n arrived: {\n left: boolean;\n right: boolean;\n top: boolean;\n bottom: boolean;\n };\n /** State of scroll direction */\n directions: {\n left: boolean;\n right: boolean;\n top: boolean;\n bottom: boolean;\n };\n}\n\nexport interface UseScroll {\n (\n target?: HookTarget,\n callback?: (params: UseScrollCallbackParams, event: Event) => void\n ): boolean;\n\n (target?: HookTarget, options?: UseScrollOptions): boolean;\n\n <Target extends Element>(\n callback?: (params: UseScrollCallbackParams, event: Event) => void,\n target?: never\n ): {\n ref: StateRef<Target>;\n scrolling: boolean;\n };\n\n <Target extends Element>(\n options?: UseScrollOptions,\n target?: never\n ): {\n ref: StateRef<Target>;\n scrolling: boolean;\n };\n}\n\n/**\n * @name useScroll\n * @description - Hook that allows you to control scroll a element\n * @category Sensors\n * @usage low\n *\n * @overload\n * @template Target The target element\n * @param {ScrollBehavior} [options.behavior=auto] The behavior of scrolling\n * @param {number} [options.offset.left=0] The left offset for arrived states\n * @param {number} [options.offset.right=0] The right offset for arrived states\n * @param {number} [options.offset.top=0] The top offset for arrived states\n * @param {number} [options.offset.bottom=0] The bottom offset for arrived states\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [options.onScroll] The callback function to be invoked on scroll\n * @param {(event: Event) => void} [options.onStop] The callback function to be invoked on scroll end\n * @returns {boolean} The state of scrolling\n *\n * @example\n * const scrolling = useScroll(ref, options);\n *\n * @overload\n * @template Target The target element\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [callback] The callback function to be invoked on scroll\n * @returns {boolean} The state of scrolling\n *\n * @example\n * const scrolling = useScroll(ref, () => console.log('callback'));\n *\n * @overload\n * @template Target The target element\n * @param {Target} [target=window] The target element to scroll\n * @param {ScrollBehavior} [options.behavior=auto] The behavior of scrolling\n * @param {number} [options.offset.left=0] The left offset for arrived states\n * @param {number} [options.offset.right=0] The right offset for arrived states\n * @param {number} [options.offset.top=0] The top offset for arrived states\n * @param {number} [options.offset.bottom=0] The bottom offset for arrived states\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [options.onScroll] The callback function to be invoked on scroll\n * @param {(event: Event) => void} [options.onStop] The callback function to be invoked on scroll end\n * @returns {[StateRef<Target>, boolean]} The state of scrolling\n *\n * @example\n * const { ref, scrolling } = useScroll(options);\n *\n * @overload\n * @template Target The target element\n * @param {Target} target The target element to scroll\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [callback] The callback function to be invoked on scroll\n * @returns {[StateRef<Target>, boolean]} The state of scrolling\n *\n * @example\n * const { ref, scrolling } = useScroll(() => console.log('callback'));\n */\nexport const useScroll = ((...params: any[]) => {\n const target = (isTarget(params[0]) ? params[0] : undefined) as HookTarget | undefined;\n const options = (\n target\n ? typeof params[1] === 'object'\n ? params[1]\n : { onScroll: params[1] }\n : typeof params[0] === 'object'\n ? params[0]\n : { onScroll: params[0] }\n ) as UseScrollOptions | undefined;\n\n const internalRef = useRefState<Element>();\n const internalOptionsRef = useRef(options);\n internalOptionsRef.current = options;\n\n const [scrolling, setScrolling] = useState(false);\n const scrollPositionRef = useRef({ x: 0, y: 0 });\n\n useEffect(() => {\n if (!target && !internalRef.state) return;\n const element = ((target ? getElement(target) : internalRef.current) as Element) ?? window;\n\n const onScrollEnd = (event: Event) => {\n setScrolling(false);\n options?.onStop?.(event);\n };\n\n const onScroll = (event: Event) => {\n setScrolling(true);\n const target = (\n event.target === document ? (event.target as Document).documentElement : event.target\n ) as HTMLElement;\n\n const { display, flexDirection, direction } = target.style;\n const directionMultiplier = direction === 'rtl' ? -1 : 1;\n\n const scrollLeft = target.scrollLeft;\n let scrollTop = target.scrollTop;\n if (target instanceof Document && !scrollTop) scrollTop = window.document.body.scrollTop;\n\n const offset = internalOptionsRef.current?.offset;\n const left = scrollLeft * directionMultiplier <= (offset?.left ?? 0);\n const right =\n scrollLeft * directionMultiplier + target.clientWidth >=\n target.scrollWidth - (offset?.right ?? 0) - ARRIVED_STATE_THRESHOLD_PIXELS;\n const top = scrollTop <= (offset?.top ?? 0);\n const bottom =\n scrollTop + target.clientHeight >=\n target.scrollHeight - (offset?.bottom ?? 0) - ARRIVED_STATE_THRESHOLD_PIXELS;\n\n const isColumnReverse = display === 'flex' && flexDirection === 'column-reverse';\n const isRowReverse = display === 'flex' && flexDirection === 'column-reverse';\n\n const params = {\n x: scrollLeft,\n y: scrollTop,\n directions: {\n left: scrollLeft < scrollPositionRef.current.x,\n right: scrollLeft > scrollPositionRef.current.x,\n top: scrollTop < scrollPositionRef.current.y,\n bottom: scrollTop > scrollPositionRef.current.y\n },\n arrived: {\n left: isRowReverse ? right : left,\n right: isRowReverse ? left : right,\n top: isColumnReverse ? bottom : top,\n bottom: isColumnReverse ? top : bottom\n }\n };\n\n scrollPositionRef.current = { x: scrollLeft, y: scrollTop };\n internalOptionsRef.current?.onScroll?.(params, event);\n };\n\n element.addEventListener('scroll', onScroll);\n element.addEventListener('scrollend', onScrollEnd);\n\n return () => {\n element.removeEventListener('scroll', onScroll);\n element.removeEventListener('scrollend', onScrollEnd);\n };\n }, [target, internalRef.state]);\n\n if (target) return scrolling;\n return {\n ref: internalRef,\n scrolling\n };\n}) as UseScroll;\n"],"names":["ARRIVED_STATE_THRESHOLD_PIXELS","useScroll","params","target","isTarget","options","internalRef","useRefState","internalOptionsRef","useRef","scrolling","setScrolling","useState","scrollPositionRef","useEffect","element","getElement","onScrollEnd","event","onScroll","display","flexDirection","direction","directionMultiplier","scrollLeft","scrollTop","offset","left","right","top","bottom","isColumnReverse","isRowReverse"],"mappings":";;;;AAUA,MAAMA,IAAiC,GAoH1BC,IAAa,IAAIC,MAAkB;AAC9C,QAAMC,IAAUC,EAASF,EAAO,CAAC,CAAC,IAAIA,EAAO,CAAC,IAAI,QAC5CG,IACJF,IACI,OAAOD,EAAO,CAAC,KAAM,WACnBA,EAAO,CAAC,IACR,EAAE,UAAUA,EAAO,CAAC,EAAA,IACtB,OAAOA,EAAO,CAAC,KAAM,WACnBA,EAAO,CAAC,IACR,EAAE,UAAUA,EAAO,CAAC,EAAA,GAGtBI,IAAcC,EAAA,GACdC,IAAqBC,EAAOJ,CAAO;AACzC,EAAAG,EAAmB,UAAUH;AAE7B,QAAM,CAACK,GAAWC,CAAY,IAAIC,EAAS,EAAK,GAC1CC,IAAoBJ,EAAO,EAAE,GAAG,GAAG,GAAG,GAAG;AAmE/C,SAjEAK,EAAU,MAAM;AACd,QAAI,CAACX,KAAU,CAACG,EAAY,MAAO;AACnC,UAAMS,KAAYZ,IAASa,EAAWb,CAAM,IAAIG,EAAY,YAAwB,QAE9EW,IAAc,CAACC,MAAiB;AACpC,MAAAP,EAAa,EAAK,GAClBN,GAAS,SAASa,CAAK;AAAA,IAAA,GAGnBC,IAAW,CAACD,MAAiB;AACjC,MAAAP,EAAa,EAAI;AACjB,YAAMR,IACJe,EAAM,WAAW,WAAYA,EAAM,OAAoB,kBAAkBA,EAAM,QAG3E,EAAE,SAAAE,GAAS,eAAAC,GAAe,WAAAC,EAAA,IAAcnB,EAAO,OAC/CoB,IAAsBD,MAAc,QAAQ,KAAK,GAEjDE,IAAarB,EAAO;AAC1B,UAAIsB,IAAYtB,EAAO;AACvB,MAAIA,aAAkB,YAAY,CAACsB,MAAWA,IAAY,OAAO,SAAS,KAAK;AAE/E,YAAMC,IAASlB,EAAmB,SAAS,QACrCmB,IAAOH,IAAaD,MAAwBG,GAAQ,QAAQ,IAC5DE,IACJJ,IAAaD,IAAsBpB,EAAO,eAC1CA,EAAO,eAAeuB,GAAQ,SAAS,KAAK1B,GACxC6B,IAAMJ,MAAcC,GAAQ,OAAO,IACnCI,IACJL,IAAYtB,EAAO,gBACnBA,EAAO,gBAAgBuB,GAAQ,UAAU,KAAK1B,GAE1C+B,IAAkBX,MAAY,UAAUC,MAAkB,kBAC1DW,IAAeZ,MAAY,UAAUC,MAAkB,kBAEvDnB,IAAS;AAAA,QACb,GAAGsB;AAAA,QACH,GAAGC;AAAA,QACH,YAAY;AAAA,UACV,MAAMD,IAAaX,EAAkB,QAAQ;AAAA,UAC7C,OAAOW,IAAaX,EAAkB,QAAQ;AAAA,UAC9C,KAAKY,IAAYZ,EAAkB,QAAQ;AAAA,UAC3C,QAAQY,IAAYZ,EAAkB,QAAQ;AAAA,QAAA;AAAA,QAEhD,SAAS;AAAA,UACP,MAAMmB,IAAeJ,IAAQD;AAAA,UAC7B,OAAOK,IAAeL,IAAOC;AAAA,UAC7B,KAAKG,IAAkBD,IAASD;AAAA,UAChC,QAAQE,IAAkBF,IAAMC;AAAA,QAAA;AAAA,MAClC;AAGF,MAAAjB,EAAkB,UAAU,EAAE,GAAGW,GAAY,GAAGC,EAAA,GAChDjB,EAAmB,SAAS,WAAWN,GAAQgB,CAAK;AAAA,IAAA;AAGtD,WAAAH,EAAQ,iBAAiB,UAAUI,CAAQ,GAC3CJ,EAAQ,iBAAiB,aAAaE,CAAW,GAE1C,MAAM;AACX,MAAAF,EAAQ,oBAAoB,UAAUI,CAAQ,GAC9CJ,EAAQ,oBAAoB,aAAaE,CAAW;AAAA,IAAA;AAAA,EACtD,GACC,CAACd,GAAQG,EAAY,KAAK,CAAC,GAE1BH,IAAeO,IACZ;AAAA,IACL,KAAKJ;AAAA,IACL,WAAAI;AAAA,EAAA;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"useScroll.mjs","sources":["../../../../src/hooks/useScroll/useScroll.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\n\nimport type { HookTarget } from '@/utils/helpers';\n\nimport { getElement, isTarget } from '@/utils/helpers';\n\nimport type { StateRef } from '../useRefState/useRefState';\n\nimport { useRefState } from '../useRefState/useRefState';\n\nconst ARRIVED_STATE_THRESHOLD_PIXELS = 1;\n\nexport interface UseScrollOptions {\n /** The on scroll callback */\n onScroll?: (params: UseScrollCallbackParams, event: Event) => void;\n\n /** The on end scroll callback */\n onStop?: (event: Event) => void;\n\n /** Offset arrived states by x pixels. */\n offset?: {\n left?: number;\n right?: number;\n top?: number;\n bottom?: number;\n };\n}\n\nexport interface UseScrollCallbackParams {\n /** The element x position */\n x: number;\n /** The element y position */\n y: number;\n /** State of scroll arrived */\n arrived: {\n left: boolean;\n right: boolean;\n top: boolean;\n bottom: boolean;\n };\n /** State of scroll direction */\n directions: {\n left: boolean;\n right: boolean;\n top: boolean;\n bottom: boolean;\n };\n}\n\n/** The scroll into view params type */\nexport interface ScrollIntoViewParams {\n behavior?: ScrollBehavior;\n block?: ScrollLogicalPosition;\n inline?: ScrollLogicalPosition;\n}\n/** The scroll to params type */\nexport interface ScrollToParams {\n behavior?: ScrollBehavior;\n x: number;\n y: number;\n}\n\n/** The use scroll return type */\nexport interface UseScrollReturn {\n /** The state of scrolling */\n scrolling: boolean;\n /** Function to scroll element into view */\n scrollIntoView: (params?: ScrollIntoViewParams) => void;\n /** Function to scroll element to a specific position */\n scrollTo: (params?: ScrollToParams) => void;\n}\n\nexport interface UseScroll {\n (\n target?: HookTarget,\n callback?: (params: UseScrollCallbackParams, event: Event) => void\n ): UseScrollReturn;\n\n (target?: HookTarget, options?: UseScrollOptions): UseScrollReturn;\n\n <Target extends Element>(\n callback?: (params: UseScrollCallbackParams, event: Event) => void,\n target?: never\n ): UseScrollReturn & { ref: StateRef<Target> };\n\n <Target extends Element>(\n options?: UseScrollOptions,\n target?: never\n ): UseScrollReturn & {\n ref: StateRef<Target>;\n };\n}\n\n/**\n * @name useScroll\n * @description - Hook that allows you to control scroll a element\n * @category Sensors\n * @usage low\n *\n * @overload\n * @template Target The target element\n * @param {ScrollBehavior} [options.behavior=auto] The behavior of scrolling\n * @param {number} [options.offset.left=0] The left offset for arrived states\n * @param {number} [options.offset.right=0] The right offset for arrived states\n * @param {number} [options.offset.top=0] The top offset for arrived states\n * @param {number} [options.offset.bottom=0] The bottom offset for arrived states\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [options.onScroll] The callback function to be invoked on scroll\n * @param {(event: Event) => void} [options.onStop] The callback function to be invoked on scroll end\n * @returns {UseScrollReturn} The state of scrolling\n *\n * @example\n * const { scrolling, scrollIntoView, scrollTo} = useScroll(ref, options);\n *\n * @overload\n * @template Target The target element\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [callback] The callback function to be invoked on scroll\n * @returns {UseScrollReturn} The state of scrolling\n *\n * @example\n * const { scrolling, scrollIntoView, scrollTo} = useScroll(ref, () => console.log('callback'));\n *\n * @overload\n * @template Target The target element\n * @param {Target} [target=window] The target element to scroll\n * @param {ScrollBehavior} [options.behavior=auto] The behavior of scrolling\n * @param {number} [options.offset.left=0] The left offset for arrived states\n * @param {number} [options.offset.right=0] The right offset for arrived states\n * @param {number} [options.offset.top=0] The top offset for arrived states\n * @param {number} [options.offset.bottom=0] The bottom offset for arrived states\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [options.onScroll] The callback function to be invoked on scroll\n * @param {(event: Event) => void} [options.onStop] The callback function to be invoked on scroll end\n * @returns {UseScrollReturn & { ref: StateRef<Target> }} The state of scrolling\n *\n * @example\n * const { ref, scrolling, scrollIntoView, scrollTo} = useScroll(options);\n *\n * @overload\n * @template Target The target element\n * @param {Target} target The target element to scroll\n * @param {(params: UseScrollCallbackParams, event: Event) => void} [callback] The callback function to be invoked on scroll\n * @returns {UseScrollReturn & { ref: StateRef<Target> }} The state of scrolling\n *\n * @example\n * const { ref, scrolling, scrollIntoView, scrollTo} = useScroll(() => console.log('callback'));\n */\nexport const useScroll = ((...params: any[]) => {\n const target = (isTarget(params[0]) ? params[0] : undefined) as HookTarget | undefined;\n const options = (\n target\n ? typeof params[1] === 'object'\n ? params[1]\n : { onScroll: params[1] }\n : typeof params[0] === 'object'\n ? params[0]\n : { onScroll: params[0] }\n ) as UseScrollOptions | undefined;\n\n const internalRef = useRefState<Element>();\n const internalOptionsRef = useRef(options);\n const elementRef = useRef<Element>(null);\n internalOptionsRef.current = options;\n\n const [scrolling, setScrolling] = useState(false);\n const scrollPositionRef = useRef({ x: 0, y: 0 });\n\n useEffect(() => {\n if (!target && !internalRef.state) return;\n const element = ((target ? getElement(target) : internalRef.current) as Element) ?? window;\n\n elementRef.current = element;\n\n const onScrollEnd = (event: Event) => {\n setScrolling(false);\n options?.onStop?.(event);\n };\n\n const onScroll = (event: Event) => {\n setScrolling(true);\n const target = (\n event.target === document ? (event.target as Document).documentElement : event.target\n ) as HTMLElement;\n\n const { display, flexDirection, direction } = target.style;\n const directionMultiplier = direction === 'rtl' ? -1 : 1;\n\n const scrollLeft = target.scrollLeft;\n let scrollTop = target.scrollTop;\n if (target instanceof Document && !scrollTop) scrollTop = window.document.body.scrollTop;\n\n const offset = internalOptionsRef.current?.offset;\n const left = scrollLeft * directionMultiplier <= (offset?.left ?? 0);\n const right =\n scrollLeft * directionMultiplier + target.clientWidth >=\n target.scrollWidth - (offset?.right ?? 0) - ARRIVED_STATE_THRESHOLD_PIXELS;\n const top = scrollTop <= (offset?.top ?? 0);\n const bottom =\n scrollTop + target.clientHeight >=\n target.scrollHeight - (offset?.bottom ?? 0) - ARRIVED_STATE_THRESHOLD_PIXELS;\n\n const isColumnReverse = display === 'flex' && flexDirection === 'column-reverse';\n const isRowReverse = display === 'flex' && flexDirection === 'column-reverse';\n\n const params = {\n x: scrollLeft,\n y: scrollTop,\n directions: {\n left: scrollLeft < scrollPositionRef.current.x,\n right: scrollLeft > scrollPositionRef.current.x,\n top: scrollTop < scrollPositionRef.current.y,\n bottom: scrollTop > scrollPositionRef.current.y\n },\n arrived: {\n left: isRowReverse ? right : left,\n right: isRowReverse ? left : right,\n top: isColumnReverse ? bottom : top,\n bottom: isColumnReverse ? top : bottom\n }\n };\n\n scrollPositionRef.current = { x: scrollLeft, y: scrollTop };\n internalOptionsRef.current?.onScroll?.(params, event);\n };\n\n element.addEventListener('scroll', onScroll);\n element.addEventListener('scrollend', onScrollEnd);\n\n return () => {\n element.removeEventListener('scroll', onScroll);\n element.removeEventListener('scrollend', onScrollEnd);\n };\n }, [target, internalRef.state]);\n\n const scrollIntoView = (params?: {\n behavior?: ScrollBehavior;\n block?: ScrollLogicalPosition;\n inline?: ScrollLogicalPosition;\n }) => {\n if (!elementRef.current) return;\n\n const { behavior, block, inline } = params ?? {};\n\n elementRef.current.scrollIntoView({\n behavior,\n block,\n inline\n });\n };\n\n const scrollTo = (params?: { x: number; y: number; behavior?: ScrollBehavior }) => {\n if (!elementRef.current) return;\n\n const { x, y, behavior } = params ?? {};\n\n elementRef.current.scrollTo({ left: x, top: y, behavior });\n };\n\n if (target) return { scrollIntoView, scrollTo, scrolling };\n return {\n ref: internalRef,\n scrolling,\n scrollIntoView,\n scrollTo\n };\n}) as UseScroll;\n"],"names":["ARRIVED_STATE_THRESHOLD_PIXELS","useScroll","params","target","isTarget","options","internalRef","useRefState","internalOptionsRef","useRef","elementRef","scrolling","setScrolling","useState","scrollPositionRef","useEffect","element","getElement","onScrollEnd","event","onScroll","display","flexDirection","direction","directionMultiplier","scrollLeft","scrollTop","offset","left","right","top","bottom","isColumnReverse","isRowReverse","scrollIntoView","behavior","block","inline","scrollTo","x","y"],"mappings":"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"}
|