@usels/core 0.0.1-beta.3
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 +21 -0
- package/dist/browser/useEventListener/index.d.mts +56 -0
- package/dist/browser/useEventListener/index.d.ts +56 -0
- package/dist/browser/useEventListener/index.js +112 -0
- package/dist/browser/useEventListener/index.js.map +1 -0
- package/dist/browser/useEventListener/index.mjs +88 -0
- package/dist/browser/useEventListener/index.mjs.map +1 -0
- package/dist/browser/useMediaQuery/demo.d.mts +5 -0
- package/dist/browser/useMediaQuery/demo.d.ts +5 -0
- package/dist/browser/useMediaQuery/demo.js +82 -0
- package/dist/browser/useMediaQuery/demo.js.map +1 -0
- package/dist/browser/useMediaQuery/demo.mjs +62 -0
- package/dist/browser/useMediaQuery/demo.mjs.map +1 -0
- package/dist/browser/useMediaQuery/index.d.mts +11 -0
- package/dist/browser/useMediaQuery/index.d.ts +11 -0
- package/dist/browser/useMediaQuery/index.js +89 -0
- package/dist/browser/useMediaQuery/index.js.map +1 -0
- package/dist/browser/useMediaQuery/index.mjs +64 -0
- package/dist/browser/useMediaQuery/index.mjs.map +1 -0
- package/dist/components/Auto/index.d.mts +33 -0
- package/dist/components/Auto/index.d.ts +33 -0
- package/dist/components/Auto/index.js +66 -0
- package/dist/components/Auto/index.js.map +1 -0
- package/dist/components/Auto/index.mjs +34 -0
- package/dist/components/Auto/index.mjs.map +1 -0
- package/dist/elements/useDocumentVisibility/demo.d.mts +5 -0
- package/dist/elements/useDocumentVisibility/demo.d.ts +5 -0
- package/dist/elements/useDocumentVisibility/demo.js +130 -0
- package/dist/elements/useDocumentVisibility/demo.js.map +1 -0
- package/dist/elements/useDocumentVisibility/demo.mjs +114 -0
- package/dist/elements/useDocumentVisibility/demo.mjs.map +1 -0
- package/dist/elements/useDocumentVisibility/index.d.mts +5 -0
- package/dist/elements/useDocumentVisibility/index.d.ts +5 -0
- package/dist/elements/useDocumentVisibility/index.js +45 -0
- package/dist/elements/useDocumentVisibility/index.js.map +1 -0
- package/dist/elements/useDocumentVisibility/index.mjs +21 -0
- package/dist/elements/useDocumentVisibility/index.mjs.map +1 -0
- package/dist/elements/useElementBounding/demo.d.mts +5 -0
- package/dist/elements/useElementBounding/demo.d.ts +5 -0
- package/dist/elements/useElementBounding/demo.js +86 -0
- package/dist/elements/useElementBounding/demo.js.map +1 -0
- package/dist/elements/useElementBounding/demo.mjs +66 -0
- package/dist/elements/useElementBounding/demo.mjs.map +1 -0
- package/dist/elements/useElementBounding/index.d.mts +46 -0
- package/dist/elements/useElementBounding/index.d.ts +46 -0
- package/dist/elements/useElementBounding/index.js +122 -0
- package/dist/elements/useElementBounding/index.js.map +1 -0
- package/dist/elements/useElementBounding/index.mjs +98 -0
- package/dist/elements/useElementBounding/index.mjs.map +1 -0
- package/dist/elements/useElementSize/demo.d.mts +5 -0
- package/dist/elements/useElementSize/demo.d.ts +5 -0
- package/dist/elements/useElementSize/demo.js +82 -0
- package/dist/elements/useElementSize/demo.js.map +1 -0
- package/dist/elements/useElementSize/demo.mjs +62 -0
- package/dist/elements/useElementSize/demo.mjs.map +1 -0
- package/dist/elements/useElementSize/index.d.mts +34 -0
- package/dist/elements/useElementSize/index.d.ts +34 -0
- package/dist/elements/useElementSize/index.js +85 -0
- package/dist/elements/useElementSize/index.js.map +1 -0
- package/dist/elements/useElementSize/index.mjs +61 -0
- package/dist/elements/useElementSize/index.mjs.map +1 -0
- package/dist/elements/useElementVisibility/demo.d.mts +5 -0
- package/dist/elements/useElementVisibility/demo.d.ts +5 -0
- package/dist/elements/useElementVisibility/demo.js +110 -0
- package/dist/elements/useElementVisibility/demo.js.map +1 -0
- package/dist/elements/useElementVisibility/demo.mjs +90 -0
- package/dist/elements/useElementVisibility/demo.mjs.map +1 -0
- package/dist/elements/useElementVisibility/index.d.mts +43 -0
- package/dist/elements/useElementVisibility/index.d.ts +43 -0
- package/dist/elements/useElementVisibility/index.js +58 -0
- package/dist/elements/useElementVisibility/index.js.map +1 -0
- package/dist/elements/useElementVisibility/index.mjs +34 -0
- package/dist/elements/useElementVisibility/index.mjs.map +1 -0
- package/dist/elements/useIntersectionObserver/demo.d.mts +5 -0
- package/dist/elements/useIntersectionObserver/demo.d.ts +5 -0
- package/dist/elements/useIntersectionObserver/demo.js +173 -0
- package/dist/elements/useIntersectionObserver/demo.js.map +1 -0
- package/dist/elements/useIntersectionObserver/demo.mjs +153 -0
- package/dist/elements/useIntersectionObserver/demo.mjs.map +1 -0
- package/dist/elements/useIntersectionObserver/index.d.mts +47 -0
- package/dist/elements/useIntersectionObserver/index.d.ts +47 -0
- package/dist/elements/useIntersectionObserver/index.js +111 -0
- package/dist/elements/useIntersectionObserver/index.js.map +1 -0
- package/dist/elements/useIntersectionObserver/index.mjs +87 -0
- package/dist/elements/useIntersectionObserver/index.mjs.map +1 -0
- package/dist/elements/useMouseInElement/demo.d.mts +5 -0
- package/dist/elements/useMouseInElement/demo.d.ts +5 -0
- package/dist/elements/useMouseInElement/demo.js +103 -0
- package/dist/elements/useMouseInElement/demo.js.map +1 -0
- package/dist/elements/useMouseInElement/demo.mjs +83 -0
- package/dist/elements/useMouseInElement/demo.mjs.map +1 -0
- package/dist/elements/useMouseInElement/index.d.mts +56 -0
- package/dist/elements/useMouseInElement/index.d.ts +56 -0
- package/dist/elements/useMouseInElement/index.js +148 -0
- package/dist/elements/useMouseInElement/index.js.map +1 -0
- package/dist/elements/useMouseInElement/index.mjs +124 -0
- package/dist/elements/useMouseInElement/index.mjs.map +1 -0
- package/dist/elements/useMutationObserver/demo.d.mts +5 -0
- package/dist/elements/useMutationObserver/demo.d.ts +5 -0
- package/dist/elements/useMutationObserver/demo.js +240 -0
- package/dist/elements/useMutationObserver/demo.js.map +1 -0
- package/dist/elements/useMutationObserver/demo.mjs +220 -0
- package/dist/elements/useMutationObserver/demo.mjs.map +1 -0
- package/dist/elements/useMutationObserver/index.d.mts +15 -0
- package/dist/elements/useMutationObserver/index.d.ts +15 -0
- package/dist/elements/useMutationObserver/index.js +69 -0
- package/dist/elements/useMutationObserver/index.js.map +1 -0
- package/dist/elements/useMutationObserver/index.mjs +45 -0
- package/dist/elements/useMutationObserver/index.mjs.map +1 -0
- package/dist/elements/useParentElement/demo.d.mts +5 -0
- package/dist/elements/useParentElement/demo.d.ts +5 -0
- package/dist/elements/useParentElement/demo.js +132 -0
- package/dist/elements/useParentElement/demo.js.map +1 -0
- package/dist/elements/useParentElement/demo.mjs +112 -0
- package/dist/elements/useParentElement/demo.mjs.map +1 -0
- package/dist/elements/useParentElement/index.d.mts +7 -0
- package/dist/elements/useParentElement/index.d.ts +7 -0
- package/dist/elements/useParentElement/index.js +47 -0
- package/dist/elements/useParentElement/index.js.map +1 -0
- package/dist/elements/useParentElement/index.mjs +23 -0
- package/dist/elements/useParentElement/index.mjs.map +1 -0
- package/dist/elements/useRef$/index.js +89 -0
- package/dist/elements/useRef$/index.js.map +1 -0
- package/dist/elements/useRef$/index.mjs +62 -0
- package/dist/elements/useRef$/index.mjs.map +1 -0
- package/dist/elements/useRef_/index.d.mts +60 -0
- package/dist/elements/useRef_/index.d.ts +60 -0
- package/dist/elements/useResizeObserver/demo.d.mts +5 -0
- package/dist/elements/useResizeObserver/demo.d.ts +5 -0
- package/dist/elements/useResizeObserver/demo.js +90 -0
- package/dist/elements/useResizeObserver/demo.js.map +1 -0
- package/dist/elements/useResizeObserver/demo.mjs +70 -0
- package/dist/elements/useResizeObserver/demo.mjs.map +1 -0
- package/dist/elements/useResizeObserver/index.d.mts +36 -0
- package/dist/elements/useResizeObserver/index.d.ts +36 -0
- package/dist/elements/useResizeObserver/index.js +74 -0
- package/dist/elements/useResizeObserver/index.js.map +1 -0
- package/dist/elements/useResizeObserver/index.mjs +49 -0
- package/dist/elements/useResizeObserver/index.mjs.map +1 -0
- package/dist/elements/useWindowFocus/demo.d.mts +5 -0
- package/dist/elements/useWindowFocus/demo.d.ts +5 -0
- package/dist/elements/useWindowFocus/demo.js +100 -0
- package/dist/elements/useWindowFocus/demo.js.map +1 -0
- package/dist/elements/useWindowFocus/demo.mjs +80 -0
- package/dist/elements/useWindowFocus/demo.mjs.map +1 -0
- package/dist/elements/useWindowFocus/index.d.mts +5 -0
- package/dist/elements/useWindowFocus/index.d.ts +5 -0
- package/dist/elements/useWindowFocus/index.js +42 -0
- package/dist/elements/useWindowFocus/index.js.map +1 -0
- package/dist/elements/useWindowFocus/index.mjs +18 -0
- package/dist/elements/useWindowFocus/index.mjs.map +1 -0
- package/dist/elements/useWindowSize/demo.d.mts +5 -0
- package/dist/elements/useWindowSize/demo.d.ts +5 -0
- package/dist/elements/useWindowSize/demo.js +78 -0
- package/dist/elements/useWindowSize/demo.js.map +1 -0
- package/dist/elements/useWindowSize/demo.mjs +58 -0
- package/dist/elements/useWindowSize/demo.mjs.map +1 -0
- package/dist/elements/useWindowSize/index.d.mts +17 -0
- package/dist/elements/useWindowSize/index.d.ts +17 -0
- package/dist/elements/useWindowSize/index.js +96 -0
- package/dist/elements/useWindowSize/index.js.map +1 -0
- package/dist/elements/useWindowSize/index.mjs +76 -0
- package/dist/elements/useWindowSize/index.mjs.map +1 -0
- package/dist/function/get/index.d.mts +45 -0
- package/dist/function/get/index.d.ts +45 -0
- package/dist/function/get/index.js +39 -0
- package/dist/function/get/index.js.map +1 -0
- package/dist/function/get/index.mjs +15 -0
- package/dist/function/get/index.mjs.map +1 -0
- package/dist/function/peek/index.d.mts +46 -0
- package/dist/function/peek/index.d.ts +46 -0
- package/dist/function/peek/index.js +39 -0
- package/dist/function/peek/index.js.map +1 -0
- package/dist/function/peek/index.mjs +15 -0
- package/dist/function/peek/index.mjs.map +1 -0
- package/dist/function/useMayObservableOptions/index.d.mts +59 -0
- package/dist/function/useMayObservableOptions/index.d.ts +59 -0
- package/dist/function/useMayObservableOptions/index.js +109 -0
- package/dist/function/useMayObservableOptions/index.js.map +1 -0
- package/dist/function/useMayObservableOptions/index.mjs +88 -0
- package/dist/function/useMayObservableOptions/index.mjs.map +1 -0
- package/dist/function/useSupported/index.d.mts +6 -0
- package/dist/function/useSupported/index.d.ts +6 -0
- package/dist/function/useSupported/index.js +37 -0
- package/dist/function/useSupported/index.js.map +1 -0
- package/dist/function/useSupported/index.mjs +13 -0
- package/dist/function/useSupported/index.mjs.map +1 -0
- package/dist/function/useWhenMounted/index.d.mts +6 -0
- package/dist/function/useWhenMounted/index.d.ts +6 -0
- package/dist/function/useWhenMounted/index.js +37 -0
- package/dist/function/useWhenMounted/index.js.map +1 -0
- package/dist/function/useWhenMounted/index.mjs +13 -0
- package/dist/function/useWhenMounted/index.mjs.map +1 -0
- package/dist/index.d.mts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +22 -0
- package/dist/index.mjs.map +1 -0
- package/dist/sensors/useScroll/demo.d.mts +5 -0
- package/dist/sensors/useScroll/demo.d.ts +5 -0
- package/dist/sensors/useScroll/demo.js +121 -0
- package/dist/sensors/useScroll/demo.js.map +1 -0
- package/dist/sensors/useScroll/demo.mjs +101 -0
- package/dist/sensors/useScroll/demo.mjs.map +1 -0
- package/dist/sensors/useScroll/index.d.mts +42 -0
- package/dist/sensors/useScroll/index.d.ts +42 -0
- package/dist/sensors/useScroll/index.js +149 -0
- package/dist/sensors/useScroll/index.js.map +1 -0
- package/dist/sensors/useScroll/index.mjs +125 -0
- package/dist/sensors/useScroll/index.mjs.map +1 -0
- package/dist/sensors/useWindowScroll/demo.d.mts +5 -0
- package/dist/sensors/useWindowScroll/demo.d.ts +5 -0
- package/dist/sensors/useWindowScroll/demo.js +84 -0
- package/dist/sensors/useWindowScroll/demo.js.map +1 -0
- package/dist/sensors/useWindowScroll/demo.mjs +64 -0
- package/dist/sensors/useWindowScroll/demo.mjs.map +1 -0
- package/dist/sensors/useWindowScroll/index.d.mts +9 -0
- package/dist/sensors/useWindowScroll/index.d.ts +9 -0
- package/dist/sensors/useWindowScroll/index.js +36 -0
- package/dist/sensors/useWindowScroll/index.js.map +1 -0
- package/dist/sensors/useWindowScroll/index.mjs +12 -0
- package/dist/sensors/useWindowScroll/index.mjs.map +1 -0
- package/dist/shared/configurable.d.mts +21 -0
- package/dist/shared/configurable.d.ts +21 -0
- package/dist/shared/configurable.js +39 -0
- package/dist/shared/configurable.js.map +1 -0
- package/dist/shared/configurable.mjs +12 -0
- package/dist/shared/configurable.mjs.map +1 -0
- package/dist/shared/index.d.mts +4 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.js +31 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/index.mjs +7 -0
- package/dist/shared/index.mjs.map +1 -0
- package/dist/shared/normalizeTargets/index.d.mts +21 -0
- package/dist/shared/normalizeTargets/index.d.ts +21 -0
- package/dist/shared/normalizeTargets/index.js +36 -0
- package/dist/shared/normalizeTargets/index.js.map +1 -0
- package/dist/shared/normalizeTargets/index.mjs +12 -0
- package/dist/shared/normalizeTargets/index.mjs.map +1 -0
- package/dist/shared/utils.d.mts +15 -0
- package/dist/shared/utils.d.ts +15 -0
- package/dist/shared/utils.js +87 -0
- package/dist/shared/utils.js.map +1 -0
- package/dist/shared/utils.mjs +52 -0
- package/dist/shared/utils.mjs.map +1 -0
- package/dist/types.d.mts +52 -0
- package/dist/types.d.ts +52 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +1 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +54 -0
- package/src/browser/useEventListener/index.md +109 -0
- package/src/browser/useEventListener/index.spec.ts +611 -0
- package/src/browser/useEventListener/index.ts +242 -0
- package/src/browser/useMediaQuery/demo.tsx +58 -0
- package/src/browser/useMediaQuery/index.md +40 -0
- package/src/browser/useMediaQuery/index.spec.ts +267 -0
- package/src/browser/useMediaQuery/index.ts +96 -0
- package/src/components/Auto/index.tsx +65 -0
- package/src/elements/useDocumentVisibility/demo.tsx +111 -0
- package/src/elements/useDocumentVisibility/index.md +51 -0
- package/src/elements/useDocumentVisibility/index.spec.ts +114 -0
- package/src/elements/useDocumentVisibility/index.ts +26 -0
- package/src/elements/useElementBounding/demo.tsx +63 -0
- package/src/elements/useElementBounding/index.md +59 -0
- package/src/elements/useElementBounding/index.ts +159 -0
- package/src/elements/useElementSize/demo.tsx +48 -0
- package/src/elements/useElementSize/index.md +60 -0
- package/src/elements/useElementSize/index.spec.ts +295 -0
- package/src/elements/useElementSize/index.ts +100 -0
- package/src/elements/useElementVisibility/deep-observable-pattern.spec.ts +453 -0
- package/src/elements/useElementVisibility/demo.tsx +97 -0
- package/src/elements/useElementVisibility/index.md +98 -0
- package/src/elements/useElementVisibility/index.spec.ts +227 -0
- package/src/elements/useElementVisibility/index.ts +78 -0
- package/src/elements/useIntersectionObserver/demo.tsx +180 -0
- package/src/elements/useIntersectionObserver/index.md +99 -0
- package/src/elements/useIntersectionObserver/index.spec.ts +482 -0
- package/src/elements/useIntersectionObserver/index.ts +149 -0
- package/src/elements/useMouseInElement/demo.tsx +79 -0
- package/src/elements/useMouseInElement/index.md +71 -0
- package/src/elements/useMouseInElement/index.spec.ts +398 -0
- package/src/elements/useMouseInElement/index.ts +209 -0
- package/src/elements/useMutationObserver/demo.tsx +270 -0
- package/src/elements/useMutationObserver/index.md +99 -0
- package/src/elements/useMutationObserver/index.spec.ts +421 -0
- package/src/elements/useMutationObserver/index.ts +66 -0
- package/src/elements/useParentElement/demo.tsx +120 -0
- package/src/elements/useParentElement/index.md +67 -0
- package/src/elements/useParentElement/index.spec.ts +208 -0
- package/src/elements/useParentElement/index.ts +35 -0
- package/src/elements/useRef$/index.md +62 -0
- package/src/elements/useRef$/index.spec.ts +205 -0
- package/src/elements/useRef$/index.ts +137 -0
- package/src/elements/useRef$/useImperativeHandle.spec.ts +339 -0
- package/src/elements/useResizeObserver/demo.tsx +56 -0
- package/src/elements/useResizeObserver/index.md +51 -0
- package/src/elements/useResizeObserver/index.spec.ts +312 -0
- package/src/elements/useResizeObserver/index.ts +106 -0
- package/src/elements/useWindowFocus/demo.tsx +71 -0
- package/src/elements/useWindowFocus/index.md +35 -0
- package/src/elements/useWindowFocus/index.spec.ts +103 -0
- package/src/elements/useWindowFocus/index.ts +21 -0
- package/src/elements/useWindowSize/demo.tsx +46 -0
- package/src/elements/useWindowSize/index.md +50 -0
- package/src/elements/useWindowSize/index.spec.ts +310 -0
- package/src/elements/useWindowSize/index.ts +107 -0
- package/src/function/get/index.md +25 -0
- package/src/function/get/index.spec.ts +87 -0
- package/src/function/get/index.ts +70 -0
- package/src/function/peek/index.spec.ts +97 -0
- package/src/function/peek/index.ts +69 -0
- package/src/function/useMayObservableOptions/index.spec.ts +521 -0
- package/src/function/useMayObservableOptions/index.ts +173 -0
- package/src/function/useSupported/index.md +38 -0
- package/src/function/useSupported/index.spec.ts +116 -0
- package/src/function/useSupported/index.ts +14 -0
- package/src/function/useWhenMounted/index.md +25 -0
- package/src/function/useWhenMounted/index.spec.ts +120 -0
- package/src/function/useWhenMounted/index.ts +16 -0
- package/src/index.ts +25 -0
- package/src/sensors/useScroll/demo.tsx +98 -0
- package/src/sensors/useScroll/index.md +112 -0
- package/src/sensors/useScroll/index.spec.ts +678 -0
- package/src/sensors/useScroll/index.ts +201 -0
- package/src/sensors/useWindowScroll/demo.tsx +69 -0
- package/src/sensors/useWindowScroll/index.md +88 -0
- package/src/sensors/useWindowScroll/index.spec.ts +69 -0
- package/src/sensors/useWindowScroll/index.ts +11 -0
- package/src/shared/configurable.ts +35 -0
- package/src/shared/index.ts +4 -0
- package/src/shared/normalizeTargets/index.spec.ts +76 -0
- package/src/shared/normalizeTargets/index.ts +27 -0
- package/src/shared/utils.ts +67 -0
- package/src/types.ts +56 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +10 -0
- package/vitest.config.ts +22 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { ObservableHint, type Observable } from "@legendapp/state";
|
|
3
|
+
import { useObservable, useObserve } from "@legendapp/state/react";
|
|
4
|
+
import { get } from "../../function/get";
|
|
5
|
+
import { useSupported } from "../../function/useSupported";
|
|
6
|
+
import type { MaybeObservable } from "../../types";
|
|
7
|
+
import { useWhenMounted } from "../../function/useWhenMounted";
|
|
8
|
+
import { useEventListener } from "../useEventListener";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Local helpers
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
function pxValue(value: string): number {
|
|
15
|
+
const num = parseFloat(value);
|
|
16
|
+
const unit = value
|
|
17
|
+
.trim()
|
|
18
|
+
.replace(/^-?\d+(?:\.\d+)?/, "")
|
|
19
|
+
.trim();
|
|
20
|
+
if (unit === "px" || unit === "") return num;
|
|
21
|
+
if (unit === "em" || unit === "rem") return num * 16;
|
|
22
|
+
return num;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function evaluateSSRQuery(query: string, ssrWidth: number): boolean {
|
|
26
|
+
const queryStrings = query.split(",");
|
|
27
|
+
return queryStrings.some((queryString) => {
|
|
28
|
+
const not = queryString.includes("not all");
|
|
29
|
+
const minWidth = queryString.match(
|
|
30
|
+
/\(\s*min-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/,
|
|
31
|
+
);
|
|
32
|
+
const maxWidth = queryString.match(
|
|
33
|
+
/\(\s*max-width:\s*(-?\d+(?:\.\d*)?[a-z]+\s*)\)/,
|
|
34
|
+
);
|
|
35
|
+
let res = Boolean(minWidth || maxWidth);
|
|
36
|
+
if (minWidth && res) res = ssrWidth >= pxValue(minWidth[1]);
|
|
37
|
+
if (maxWidth && res) res = ssrWidth <= pxValue(maxWidth[1]);
|
|
38
|
+
return not ? !res : res;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Types
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
export interface UseMediaQueryOptions {
|
|
47
|
+
ssrWidth?: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type UseMediaQueryReturn = Observable<boolean>;
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Hook
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
57
|
+
export function useMediaQuery(
|
|
58
|
+
query: MaybeObservable<string>,
|
|
59
|
+
options: UseMediaQueryOptions = {},
|
|
60
|
+
): UseMediaQueryReturn {
|
|
61
|
+
const { ssrWidth } = options;
|
|
62
|
+
|
|
63
|
+
const isSupported = useSupported(
|
|
64
|
+
() => "matchMedia" in window && typeof window.matchMedia === "function",
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const matches$ = useObservable(() =>
|
|
68
|
+
typeof ssrWidth === "number"
|
|
69
|
+
? evaluateSSRQuery(get(query), ssrWidth)
|
|
70
|
+
: false,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const mql$ = useWhenMounted(() =>
|
|
74
|
+
isSupported.get()
|
|
75
|
+
? ObservableHint.opaque(window.matchMedia(get(query)))
|
|
76
|
+
: null,
|
|
77
|
+
);
|
|
78
|
+
useObserve(() => {
|
|
79
|
+
const mql = mql$.get();
|
|
80
|
+
if (!mql) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
matches$.set(mql.matches.valueOf());
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
useEventListener(
|
|
87
|
+
mql$,
|
|
88
|
+
"change",
|
|
89
|
+
(e: Event) => {
|
|
90
|
+
matches$.set((e as MediaQueryListEvent).matches);
|
|
91
|
+
},
|
|
92
|
+
{ passive: true },
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return matches$;
|
|
96
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import React, {
|
|
3
|
+
createElement,
|
|
4
|
+
type FC,
|
|
5
|
+
type ReactNode,
|
|
6
|
+
type ReactElement,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { Computed, Show } from "@legendapp/state/react";
|
|
9
|
+
import type { Selector } from "@legendapp/state";
|
|
10
|
+
|
|
11
|
+
type AutoPropsIf<T> = {
|
|
12
|
+
if: Selector<T>;
|
|
13
|
+
ifReady?: never;
|
|
14
|
+
withState?: boolean; // Show is already reactive to parent state; withState is accepted but has no effect
|
|
15
|
+
children: () => ReactNode;
|
|
16
|
+
else?: ReactNode | (() => ReactNode);
|
|
17
|
+
wrap?: FC<{ children: ReactNode }>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type AutoPropsIfReady<T> = {
|
|
21
|
+
if?: never;
|
|
22
|
+
ifReady: Selector<T>;
|
|
23
|
+
withState?: boolean; // Same as above
|
|
24
|
+
children: () => ReactNode;
|
|
25
|
+
else?: ReactNode | (() => ReactNode);
|
|
26
|
+
wrap?: FC<{ children: ReactNode }>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type AutoPropsReactive = {
|
|
30
|
+
if?: never;
|
|
31
|
+
ifReady?: never;
|
|
32
|
+
withState?: boolean;
|
|
33
|
+
children: () => ReactNode;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type AutoProps<T = unknown> =
|
|
37
|
+
| AutoPropsIf<T>
|
|
38
|
+
| AutoPropsIfReady<T>
|
|
39
|
+
| AutoPropsReactive;
|
|
40
|
+
|
|
41
|
+
export function Auto<T>({
|
|
42
|
+
if: ifProp,
|
|
43
|
+
ifReady,
|
|
44
|
+
withState,
|
|
45
|
+
children,
|
|
46
|
+
...rest
|
|
47
|
+
}: AutoProps<T>): ReactElement | null {
|
|
48
|
+
if (ifProp !== undefined) {
|
|
49
|
+
const { else: elseProp, wrap } = rest as AutoPropsIf<T>;
|
|
50
|
+
return createElement(Show<T>, {
|
|
51
|
+
if: ifProp,
|
|
52
|
+
else: elseProp,
|
|
53
|
+
wrap,
|
|
54
|
+
children,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (ifReady !== undefined) {
|
|
58
|
+
const { else: elseProp, wrap } = rest as AutoPropsIfReady<T>;
|
|
59
|
+
return createElement(Show<T>, { ifReady, else: elseProp, wrap, children });
|
|
60
|
+
}
|
|
61
|
+
return createElement(
|
|
62
|
+
withState ? Computed : React.memo(Computed, () => true),
|
|
63
|
+
{ children },
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { useDocumentVisibility } from ".";
|
|
3
|
+
import {
|
|
4
|
+
Computed,
|
|
5
|
+
useObservable,
|
|
6
|
+
useObserveEffect,
|
|
7
|
+
} from "@legendapp/state/react";
|
|
8
|
+
|
|
9
|
+
const dot: React.CSSProperties = {
|
|
10
|
+
display: "inline-block",
|
|
11
|
+
width: "8px",
|
|
12
|
+
height: "8px",
|
|
13
|
+
borderRadius: "50%",
|
|
14
|
+
marginRight: "6px",
|
|
15
|
+
verticalAlign: "middle",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function StateRow({
|
|
19
|
+
label,
|
|
20
|
+
value,
|
|
21
|
+
}: {
|
|
22
|
+
label: string;
|
|
23
|
+
value: DocumentVisibilityState;
|
|
24
|
+
}) {
|
|
25
|
+
const visible = value === "visible";
|
|
26
|
+
return (
|
|
27
|
+
<div
|
|
28
|
+
style={{
|
|
29
|
+
display: "flex",
|
|
30
|
+
alignItems: "center",
|
|
31
|
+
padding: "10px 14px",
|
|
32
|
+
borderRadius: "6px",
|
|
33
|
+
border: `1px solid ${visible ? "var(--sl-color-green, #22c55e)" : "var(--sl-color-orange, #f97316)"}`,
|
|
34
|
+
background: visible
|
|
35
|
+
? "var(--sl-color-green-low, #f0fdf4)"
|
|
36
|
+
: "var(--sl-color-orange-low, #fff7ed)",
|
|
37
|
+
transition: "border-color 0.3s, background 0.3s",
|
|
38
|
+
gap: "10px",
|
|
39
|
+
}}
|
|
40
|
+
>
|
|
41
|
+
<span
|
|
42
|
+
style={{
|
|
43
|
+
...dot,
|
|
44
|
+
background: visible
|
|
45
|
+
? "var(--sl-color-green, #22c55e)"
|
|
46
|
+
: "var(--sl-color-orange, #f97316)",
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
<span style={{ color: "var(--sl-color-gray-2, #64748b)", minWidth: "80px" }}>
|
|
50
|
+
{label}
|
|
51
|
+
</span>
|
|
52
|
+
<strong
|
|
53
|
+
style={{
|
|
54
|
+
color: visible
|
|
55
|
+
? "var(--sl-color-green, #22c55e)"
|
|
56
|
+
: "var(--sl-color-orange, #f97316)",
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
"{value}"
|
|
60
|
+
</strong>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export default function UseDocumentVisibilityDemo() {
|
|
66
|
+
const visibility$ = useDocumentVisibility();
|
|
67
|
+
// Delayed display: stays on 'hidden' for 2s after returning to visible
|
|
68
|
+
const delayed$ = useObservable<DocumentVisibilityState>("visible");
|
|
69
|
+
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
70
|
+
|
|
71
|
+
useObserveEffect(() => {
|
|
72
|
+
const state = visibility$.get();
|
|
73
|
+
if (timerRef.current !== null) clearTimeout(timerRef.current);
|
|
74
|
+
if (state === "hidden") {
|
|
75
|
+
delayed$.set("hidden");
|
|
76
|
+
} else {
|
|
77
|
+
timerRef.current = setTimeout(() => {
|
|
78
|
+
delayed$.set("visible");
|
|
79
|
+
}, 2000);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
style={{
|
|
86
|
+
display: "flex",
|
|
87
|
+
flexDirection: "column",
|
|
88
|
+
gap: "8px",
|
|
89
|
+
fontFamily: "monospace",
|
|
90
|
+
fontSize: "13px",
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
<Computed>
|
|
94
|
+
{() => <StateRow label="Instant" value={visibility$.get()} />}
|
|
95
|
+
</Computed>
|
|
96
|
+
<Computed>
|
|
97
|
+
{() => <StateRow label="2s delay" value={delayed$.get()} />}
|
|
98
|
+
</Computed>
|
|
99
|
+
<p
|
|
100
|
+
style={{
|
|
101
|
+
margin: 0,
|
|
102
|
+
fontSize: "11px",
|
|
103
|
+
color: "var(--sl-color-gray-3, #94a3b8)",
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
Switch to another tab and come back — the 2s delay row stays{" "}
|
|
107
|
+
<strong>"hidden"</strong> long enough to confirm the transition.
|
|
108
|
+
</p>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useDocumentVisibility
|
|
3
|
+
category: elements
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Tracks the browser tab's visibility state (`'visible'` or `'hidden'`) as a reactive `Observable<DocumentVisibilityState>`.
|
|
7
|
+
Updates automatically when the user switches tabs or minimizes the window.
|
|
8
|
+
SSR-safe: returns `'visible'` when `document` is not available.
|
|
9
|
+
|
|
10
|
+
## Demo
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { useDocumentVisibility } from '@usels/core'
|
|
16
|
+
|
|
17
|
+
function Component() {
|
|
18
|
+
const visibility$ = useDocumentVisibility()
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<p>Tab is {visibility$.get()}</p>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Pausing work when the tab is hidden
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
const visibility$ = useDocumentVisibility()
|
|
30
|
+
|
|
31
|
+
useObserve(() => {
|
|
32
|
+
if (visibility$.get() === 'hidden') pausePolling()
|
|
33
|
+
else resumePolling()
|
|
34
|
+
})
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Tracking page view time
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
const visibility$ = useDocumentVisibility()
|
|
41
|
+
const visibleSince = useObservable(Date.now())
|
|
42
|
+
|
|
43
|
+
useObserve(() => {
|
|
44
|
+
if (visibility$.get() === 'visible') {
|
|
45
|
+
visibleSince.set(Date.now())
|
|
46
|
+
} else {
|
|
47
|
+
const elapsed = Date.now() - visibleSince.get()
|
|
48
|
+
trackVisibleTime(elapsed)
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
```
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { renderHook, act } from "@testing-library/react";
|
|
3
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
4
|
+
import { useDocumentVisibility } from ".";
|
|
5
|
+
|
|
6
|
+
const flush = () => new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
7
|
+
|
|
8
|
+
function mockVisibilityState(value: DocumentVisibilityState) {
|
|
9
|
+
return vi.spyOn(document, "visibilityState", "get").mockReturnValue(value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe("useDocumentVisibility()", () => {
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
vi.restoreAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("returns an Observable", () => {
|
|
18
|
+
const { result } = renderHook(() => useDocumentVisibility());
|
|
19
|
+
expect(typeof result.current.get).toBe("function");
|
|
20
|
+
expect(typeof result.current.set).toBe("function");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("initial value is 'visible' before mount syncs", () => {
|
|
24
|
+
mockVisibilityState("hidden");
|
|
25
|
+
// renderHook runs the hook — the observable initializes to 'visible' first,
|
|
26
|
+
// then useMount sets it to the actual state. We just assert the final value.
|
|
27
|
+
const { result } = renderHook(() => useDocumentVisibility());
|
|
28
|
+
expect(result.current.get()).toBe("hidden");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("reflects 'visible' when document.visibilityState is 'visible'", () => {
|
|
32
|
+
mockVisibilityState("visible");
|
|
33
|
+
const { result } = renderHook(() => useDocumentVisibility());
|
|
34
|
+
expect(result.current.get()).toBe("visible");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("sets to 'hidden' when visibilitychange fires with hidden state", () => {
|
|
38
|
+
mockVisibilityState("visible");
|
|
39
|
+
const { result } = renderHook(() => useDocumentVisibility());
|
|
40
|
+
|
|
41
|
+
act(() => {
|
|
42
|
+
mockVisibilityState("hidden");
|
|
43
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
expect(result.current.get()).toBe("hidden");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("sets to 'visible' when visibilitychange fires with visible state", () => {
|
|
50
|
+
mockVisibilityState("hidden");
|
|
51
|
+
const { result } = renderHook(() => useDocumentVisibility());
|
|
52
|
+
|
|
53
|
+
act(() => {
|
|
54
|
+
mockVisibilityState("visible");
|
|
55
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(result.current.get()).toBe("visible");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("toggles correctly across multiple visibility changes", () => {
|
|
62
|
+
mockVisibilityState("visible");
|
|
63
|
+
const { result } = renderHook(() => useDocumentVisibility());
|
|
64
|
+
|
|
65
|
+
act(() => {
|
|
66
|
+
mockVisibilityState("hidden");
|
|
67
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
68
|
+
});
|
|
69
|
+
expect(result.current.get()).toBe("hidden");
|
|
70
|
+
|
|
71
|
+
act(() => {
|
|
72
|
+
mockVisibilityState("visible");
|
|
73
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
74
|
+
});
|
|
75
|
+
expect(result.current.get()).toBe("visible");
|
|
76
|
+
|
|
77
|
+
act(() => {
|
|
78
|
+
mockVisibilityState("hidden");
|
|
79
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
80
|
+
});
|
|
81
|
+
expect(result.current.get()).toBe("hidden");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("removes event listener on unmount", async () => {
|
|
85
|
+
const addSpy = vi.spyOn(document, "addEventListener");
|
|
86
|
+
const removeSpy = vi.spyOn(document, "removeEventListener");
|
|
87
|
+
|
|
88
|
+
const { unmount } = renderHook(() => useDocumentVisibility());
|
|
89
|
+
unmount();
|
|
90
|
+
await flush(); // useMount defers cleanup via queueMicrotask in test env
|
|
91
|
+
|
|
92
|
+
const added = addSpy.mock.calls.some(([type]) => type === "visibilitychange");
|
|
93
|
+
const removed = removeSpy.mock.calls.some(([type]) => type === "visibilitychange");
|
|
94
|
+
|
|
95
|
+
expect(added).toBe(true);
|
|
96
|
+
expect(removed).toBe(true);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("does not respond to events after unmount", async () => {
|
|
100
|
+
mockVisibilityState("visible");
|
|
101
|
+
const { result, unmount } = renderHook(() => useDocumentVisibility());
|
|
102
|
+
|
|
103
|
+
unmount();
|
|
104
|
+
await flush(); // wait for cleanup
|
|
105
|
+
|
|
106
|
+
act(() => {
|
|
107
|
+
mockVisibilityState("hidden");
|
|
108
|
+
document.dispatchEvent(new Event("visibilitychange"));
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Value stays at 'visible' — no listener active after cleanup
|
|
112
|
+
expect(result.current.get()).toBe("visible");
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import type { Observable } from "@legendapp/state";
|
|
3
|
+
import { useObservable, useMount } from "@legendapp/state/react";
|
|
4
|
+
|
|
5
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
6
|
+
export function useDocumentVisibility(): Observable<DocumentVisibilityState> {
|
|
7
|
+
// Always initialize with 'visible' to match SSR output and avoid hydration mismatch.
|
|
8
|
+
// The actual value is synced after mount.
|
|
9
|
+
const visibility$ = useObservable<DocumentVisibilityState>("visible");
|
|
10
|
+
|
|
11
|
+
useMount(() => {
|
|
12
|
+
visibility$.set(document.visibilityState);
|
|
13
|
+
|
|
14
|
+
const handler = () => {
|
|
15
|
+
visibility$.set(document.visibilityState);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
document.addEventListener("visibilitychange", handler, { passive: true });
|
|
19
|
+
|
|
20
|
+
return () => {
|
|
21
|
+
document.removeEventListener("visibilitychange", handler);
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return visibility$;
|
|
26
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useRef$ } from "../useRef$";
|
|
2
|
+
import { useElementBounding } from ".";
|
|
3
|
+
|
|
4
|
+
export default function UseElementBoundingDemo() {
|
|
5
|
+
const el$ = useRef$<HTMLDivElement>();
|
|
6
|
+
const { x$, y$, top$, left$, width$, height$ } = useElementBounding(el$);
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "12px" }}>
|
|
10
|
+
{/* Bounding values readout */}
|
|
11
|
+
<div
|
|
12
|
+
style={{
|
|
13
|
+
display: "grid",
|
|
14
|
+
gridTemplateColumns: "repeat(3, 1fr)",
|
|
15
|
+
gap: "6px",
|
|
16
|
+
fontFamily: "monospace",
|
|
17
|
+
fontSize: "13px",
|
|
18
|
+
padding: "10px 14px",
|
|
19
|
+
background: "var(--sl-color-gray-6, #f1f5f9)",
|
|
20
|
+
borderRadius: "6px",
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
{(
|
|
24
|
+
[
|
|
25
|
+
["x", x$.get()],
|
|
26
|
+
["y", y$.get()],
|
|
27
|
+
["top", top$.get()],
|
|
28
|
+
["left", left$.get()],
|
|
29
|
+
["width", width$.get()],
|
|
30
|
+
["height", height$.get()],
|
|
31
|
+
] as [string, number][]
|
|
32
|
+
).map(([label, val]) => (
|
|
33
|
+
<span key={label}>
|
|
34
|
+
{label}: <strong>{Math.round(val)}px</strong>
|
|
35
|
+
</span>
|
|
36
|
+
))}
|
|
37
|
+
</div>
|
|
38
|
+
|
|
39
|
+
{/* Resizable target element */}
|
|
40
|
+
<div
|
|
41
|
+
ref={el$}
|
|
42
|
+
style={{
|
|
43
|
+
resize: "both",
|
|
44
|
+
overflow: "auto",
|
|
45
|
+
width: "240px",
|
|
46
|
+
height: "100px",
|
|
47
|
+
padding: "12px",
|
|
48
|
+
border: "1px solid var(--sl-color-gray-5, #cbd5e1)",
|
|
49
|
+
borderRadius: "6px",
|
|
50
|
+
fontFamily: "monospace",
|
|
51
|
+
fontSize: "13px",
|
|
52
|
+
color: "var(--sl-color-gray-3, #94a3b8)",
|
|
53
|
+
userSelect: "none",
|
|
54
|
+
display: "flex",
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
justifyContent: "center",
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
resize me ↘
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: useElementBounding
|
|
3
|
+
category: elements
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Tracks the bounding rect of a DOM element — `x`, `y`, `top`, `right`, `bottom`, `left`, `width`, `height` — as reactive `Observable<number>` values.
|
|
7
|
+
Uses [ResizeObserver](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) for size changes, [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) for `style`/`class` attribute changes, and `scroll`/`resize` window events for position changes.
|
|
8
|
+
`requestAnimationFrame` is used by default so CSS transform animations are captured accurately.
|
|
9
|
+
|
|
10
|
+
## Demo
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```tsx twoslash
|
|
15
|
+
// @noErrors
|
|
16
|
+
import { useRef$, useElementBounding } from '@usels/core'
|
|
17
|
+
|
|
18
|
+
function Component() {
|
|
19
|
+
const el$ = useRef$<HTMLDivElement>()
|
|
20
|
+
const { top$, left$, width$, height$ } = useElementBounding(el$)
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div ref={el$}>
|
|
24
|
+
{width$.get()} × {height$.get()} at ({left$.get()}, {top$.get()})
|
|
25
|
+
</div>
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Manual update
|
|
31
|
+
|
|
32
|
+
```tsx twoslash
|
|
33
|
+
// @noErrors
|
|
34
|
+
import { useRef$, Ref$, useElementBounding } from '@usels/core'
|
|
35
|
+
declare const el$: Ref$<HTMLDivElement>
|
|
36
|
+
// ---cut---
|
|
37
|
+
const { top$, left$, update } = useElementBounding(el$)
|
|
38
|
+
|
|
39
|
+
// Force-recalculate bounding rect imperatively
|
|
40
|
+
update()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Disable window scroll tracking
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
const { top$, left$ } = useElementBounding(el$, { windowScroll: false })
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Skip requestAnimationFrame (synchronous reads)
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
const { width$, height$ } = useElementBounding(el$, { useCssTransforms: false })
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Keep values on unmount (no reset)
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
const { top$ } = useElementBounding(el$, { reset: false })
|
|
59
|
+
```
|