Skip to content

Commit c980d21

Browse files
committed
Merge branch 'main' of https://github.com/uidotdev/usehooks into experimental
2 parents 05ceb5e + fa7f8bf commit c980d21

File tree

5 files changed

+125
-75
lines changed

5 files changed

+125
-75
lines changed

index.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,15 +190,15 @@ declare module "@uidotdev/usehooks" {
190190
export function useHistoryState<T>(initialPresent?: T): HistoryState<T>;
191191

192192
export function useHover<T extends Element>(): [
193-
React.MutableRefObject<T>,
193+
React.RefCallback<T>,
194194
boolean
195195
];
196196

197197
export function useIdle(ms?: number): boolean;
198198

199199
export function useIntersectionObserver<T extends Element>(
200200
options?: IntersectionObserverInit
201-
): [React.MutableRefObject<T>, IntersectionObserverEntry | null];
201+
): [React.RefCallback<T>, IntersectionObserverEntry | null];
202202

203203
export function useInterval(cb: () => any, ms: number): () => void;
204204

@@ -242,7 +242,7 @@ declare module "@uidotdev/usehooks" {
242242
export function useMap<T>(initialState?: T): Map<T, any>;
243243

244244
export function useMeasure<T extends Element>(): [
245-
React.MutableRefObject<T>,
245+
React.RefCallback<T>,
246246
{
247247
width: number | null;
248248
height: number | null;
@@ -287,7 +287,7 @@ declare module "@uidotdev/usehooks" {
287287
options?: {
288288
removeOnUnmount?: boolean;
289289
}
290-
): "idle" | "loading" | "ready" | "error";
290+
): "unknown" | "loading" | "ready" | "error";
291291

292292
export function useSessionStorage<T>(
293293
key: string,

index.js

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ export function useHover() {
586586

587587
const customRef = React.useCallback(
588588
(node) => {
589-
if (previousNode.current instanceof HTMLElement) {
589+
if (previousNode.current?.nodeType === Node.ELEMENT_NODE) {
590590
previousNode.current.removeEventListener(
591591
"mouseenter",
592592
handleMouseEnter
@@ -597,7 +597,7 @@ export function useHover() {
597597
);
598598
}
599599

600-
if (node instanceof HTMLElement) {
600+
if (node?.nodeType === Node.ELEMENT_NODE) {
601601
node.addEventListener("mouseenter", handleMouseEnter);
602602
node.addEventListener("mouseleave", handleMouseLeave);
603603
}
@@ -671,7 +671,7 @@ export function useIntersectionObserver(options = {}) {
671671
previousObserver.current = null;
672672
}
673673

674-
if (node instanceof HTMLElement) {
674+
if (node?.nodeType === Node.ELEMENT_NODE) {
675675
const observer = new IntersectionObserver(
676676
([entry]) => {
677677
setEntry(entry);
@@ -1003,7 +1003,7 @@ export function useMeasure() {
10031003
previousObserver.current = null;
10041004
}
10051005

1006-
if (node instanceof HTMLElement) {
1006+
if (node?.nodeType === Node.ELEMENT_NODE) {
10071007
const observer = new ResizeObserver(([entry]) => {
10081008
if (entry && entry.borderBoxSize) {
10091009
const { inlineSize: width, blockSize: height } =
@@ -1064,7 +1064,7 @@ export function useMouse() {
10641064
y: event.pageY,
10651065
};
10661066

1067-
if (ref.current instanceof HTMLElement) {
1067+
if (ref.current?.nodeType === Node.ELEMENT_NODE) {
10681068
const { left, top } = ref.current.getBoundingClientRect();
10691069
const elementPositionX = left + window.scrollX;
10701070
const elementPositionY = top + window.scrollY;
@@ -1386,29 +1386,50 @@ export function useScript(src, options = {}) {
13861386
React.useEffect(() => {
13871387
let script = document.querySelector(`script[src="${src}"]`);
13881388

1389+
const domStatus = script?.getAttribute("data-status");
1390+
if (domStatus) {
1391+
setStatus(domStatus);
1392+
return;
1393+
}
1394+
13891395
if (script === null) {
13901396
script = document.createElement("script");
13911397
script.src = src;
13921398
script.async = true;
1399+
script.setAttribute("data-status", "loading");
13931400
document.body.appendChild(script);
1394-
}
13951401

1396-
const handleScriptLoad = () => setStatus("ready");
1397-
const handleScriptError = () => setStatus("error");
1402+
const handleScriptLoad = () => {
1403+
script.setAttribute("data-status", "ready");
1404+
setStatus("ready");
1405+
removeEventListeners();
1406+
};
13981407

1399-
script.addEventListener("load", handleScriptLoad);
1400-
script.addEventListener("error", handleScriptError);
1408+
const handleScriptError = () => {
1409+
script.setAttribute("data-status", "error");
1410+
setStatus("error");
1411+
removeEventListeners();
1412+
};
14011413

1402-
const removeOnUnmount = optionsRef.current.removeOnUnmount;
1414+
const removeEventListeners = () => {
1415+
script.removeEventListener("load", handleScriptLoad);
1416+
script.removeEventListener("error", handleScriptError);
1417+
};
14031418

1404-
return () => {
1405-
script.removeEventListener("load", handleScriptLoad);
1406-
script.removeEventListener("error", handleScriptError);
1419+
script.addEventListener("load", handleScriptLoad);
1420+
script.addEventListener("error", handleScriptError);
14071421

1408-
if (removeOnUnmount === true) {
1409-
script.remove();
1410-
}
1411-
};
1422+
const removeOnUnmount = optionsRef.current.removeOnUnmount;
1423+
1424+
return () => {
1425+
if (removeOnUnmount === true) {
1426+
script.remove();
1427+
removeEventListeners();
1428+
}
1429+
};
1430+
} else {
1431+
setStatus("unknown");
1432+
}
14121433
}, [src]);
14131434

14141435
return status;

usehooks.com/src/content/hooks/useScript.mdx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ import StaticCodeContainer from "../../components/StaticCodeContainer.astro";
1717
scripts into a React component. It manages the loading and status of the
1818
script, allowing you to conditionally render components or perform actions
1919
based on whether the script has been successfully loaded or encountered an
20-
error. The hook keeps track of the script’s status, such as "loading,"
21-
"ready," or "error," and provides this status as a return value. Additionally,
20+
error. The hook keeps track of the script’s status and provides this status as a return value. Additionally,
2221
it offers options to remove the script when the component is unmounted,
2322
ensuring proper cleanup.
2423
</HookDescription>
@@ -38,7 +37,7 @@ import StaticCodeContainer from "../../components/StaticCodeContainer.astro";
3837
<div class="table-container">
3938
| Name | Type | Description |
4039
| ------ | ------ | ----------- |
41-
| status | string | This represents the status of the script load. Possible values are: `loading`, `ready`, and `error`. |
40+
| status | string | This represents the status of the script load, `loading`, `ready`, `error`, or `unknown`. An `unknown` script is one that previously exists in the document, but was not added via `useScript`. |
4241
</div>
4342
</div>
4443

usehooks.com/src/layouts/Layout.astro

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ const {
1313
ogImage = new URL("/meta/og.jpg", Astro.url),
1414
} = Astro.props;
1515
16-
const pathname = Astro.url.pathname
17-
18-
const url = pathname[pathname.length - 1] === "/"
19-
? new URL(pathname.slice(0, pathname.length -1), Astro.site)
20-
: new URL(Astro.url.pathname, Astro.site)
16+
const pathname = Astro.url.pathname;
2117
18+
const url =
19+
pathname[pathname.length - 1] === "/"
20+
? new URL(pathname.slice(0, pathname.length - 1), Astro.site)
21+
: new URL(Astro.url.pathname, Astro.site);
2222
---
2323

2424
<!DOCTYPE html>
@@ -90,6 +90,34 @@ const url = pathname[pathname.length - 1] === "/"
9090
data-api="/stats/api/event"
9191
data-domain="usehooks.com"
9292
></script>
93+
94+
<script defer>
95+
!(function (f, b, e, v, n, t, s) {
96+
if (f.fbq) return;
97+
n = f.fbq = function () {
98+
n.callMethod
99+
? n.callMethod.apply(n, arguments)
100+
: n.queue.push(arguments);
101+
};
102+
if (!f._fbq) f._fbq = n;
103+
n.push = n;
104+
n.loaded = !0;
105+
n.version = "2.0";
106+
n.queue = [];
107+
t = b.createElement(e);
108+
t.async = !0;
109+
t.src = v;
110+
s = b.getElementsByTagName(e)[0];
111+
s.parentNode.insertBefore(t, s);
112+
})(
113+
window,
114+
document,
115+
"script",
116+
"https://connect.facebook.net/en_US/fbevents.js"
117+
);
118+
fbq("init", "186849069509023");
119+
fbq("track", "PageView");
120+
</script>
93121
</head>
94122
<body>
95123
<slot />

usehooks.com/src/sections/Footer.astro

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,59 @@
22
---
33

44
<footer class="main-footer">
5-
<a href="/" class="logo image">
6-
<img src="/img/logo-useHooks.svg" width="546" height="80" alt="useHooks" />
7-
</a>
8-
<a href="https://ui.dev" class="byline">by ui.dev</a>
9-
<nav>
10-
<a href="https://github.com/uidotdev/usehooks">Fork on GitHub</a>
11-
<a href="https://bytes.dev">JavaScript Newsletter</a>
12-
<a href="https://react.gg">Learn React</a>
13-
</nav>
5+
<a href="/" class="logo image">
6+
<img src="/img/logo-useHooks.svg" width="546" height="80" alt="useHooks" />
7+
</a>
8+
<a href="https://ui.dev" class="byline">by ui.dev</a>
9+
<nav>
10+
<a href="https://github.com/uidotdev/usehooks">View the Repo</a>
11+
<a href="https://bytes.dev">JavaScript Newsletter</a>
12+
<a href="https://reactnewsletter.com">React Newsletter</a>
13+
<a href="https://react.gg">Learn React</a>
14+
<a href="https://query.gg">Learn React Query</a>
15+
</nav>
1416
</footer>
1517

1618
<style>
17-
.main-footer {
18-
width: 100%;
19-
margin-top: 4rem;
20-
padding: var(--body-padding);
21-
display: flex;
22-
flex-direction: column;
23-
align-items: center;
24-
gap: 2rem;
25-
border-radius: .5rem;
26-
border: var(--border-dark);
27-
font-size: var(--font-sm);
28-
}
19+
.main-footer {
20+
width: 100%;
21+
margin-top: 4rem;
22+
padding: var(--body-padding);
23+
display: flex;
24+
flex-direction: column;
25+
align-items: center;
26+
gap: 2rem;
27+
border-radius: 0.5rem;
28+
border: var(--border-dark);
29+
font-size: var(--font-sm);
30+
}
2931

30-
nav {
31-
display: flex;
32-
flex-wrap: wrap;
33-
justify-content: center;
34-
gap: 1rem 2rem;
35-
text-align: center;
36-
}
32+
nav {
33+
display: flex;
34+
flex-wrap: wrap;
35+
justify-content: center;
36+
gap: 1rem 2rem;
37+
text-align: center;
38+
}
3739

38-
.logo {
39-
width: 180px;
40-
}
40+
.logo {
41+
width: 180px;
42+
}
4143

42-
.byline {
43-
margin-top: -.5rem;
44-
padding: .3em .5em;
45-
display: inline-block;
46-
border-radius: .3em;
47-
background-color: var(--charcoal);
48-
}
44+
.byline {
45+
margin-top: -0.5rem;
46+
padding: 0.3em 0.5em;
47+
display: inline-block;
48+
border-radius: 0.3em;
49+
background-color: var(--charcoal);
50+
}
4951

50-
.byline:hover {
51-
background-color: var(--yellow);
52-
color: var(--charcoal);
53-
}
52+
.byline:hover {
53+
background-color: var(--yellow);
54+
color: var(--charcoal);
55+
}
5456

55-
nav a:hover {
56-
text-decoration: underline;
57-
}
57+
nav a:hover {
58+
text-decoration: underline;
59+
}
5860
</style>

0 commit comments

Comments
 (0)