sse-hooks 1.0.0 → 1.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.
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ ## 🪝 Available Hooks
2
+
3
+ <!-- HOOKS:START -->
4
+
5
+ - [`useBoolean`](/docs/use-boolean) — handles boolean state with useful utility functions.
6
+ - [`useClickAnyWhere`](/docs/use-click-any-where) — handles click events anywhere on the document.
7
+ - [`useCookie`](/docs/use-cookie) — manages state synchronized with a browser [cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies).
8
+ It handles serialization, prefixes, updates across tabs, and custom event synchronization.
9
+ - [`useCopyToClipboard`](/docs/use-copy-to-clipboard) — copies text to the clipboard using the [Clipboard API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API).
10
+ - [`useCountdown`](/docs/use-countdown) — manages countdown.
11
+ - [`useCounter`](/docs/use-counter) — manages a counter with increment, decrement, reset, and setCount functionalities.
12
+ - [`useDarkMode`](/docs/use-dark-mode) — returns the current state of the dark mode.
13
+ - [`useDebounceCallback`](/docs/use-debounce-callback) — creates a debounced version of a callback function.
14
+ - [`useDebounceValue`](/docs/use-debounce-value) — returns a debounced version of the provided value, along with a function to update it.
15
+ - [`useDocumentTitle`](/docs/use-document-title) — sets the document title.
16
+ - [`useEventCallback`](/docs/use-event-callback) — creates a memoized event callback.
17
+ - [`useEventListener`](/docs/use-event-listener) —
18
+ - [`useFetch`](/docs/use-fetch) — provides a wrapper around the native [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) to handle HTTP requests with state management, abort capability, and TypeScript support.
19
+ - [`useHover`](/docs/use-hover) — tracks whether a DOM element is being hovered over.
20
+ - [`useIndexedDB`](/docs/use-indexed-d-b) — provides an interface to the [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) for client-side storage of significant amounts of structured data.
21
+ - [`useIntersectionObserver`](/docs/use-intersection-observer) — tracks the intersection of a DOM element with its containing element or the viewport using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API).
22
+ - [`useInterval`](/docs/use-interval) — creates an interval that invokes a callback function at a specified delay using the [setInterval API](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval).
23
+ - [`useIsClient`](/docs/use-is-client) — determines if the code is running on the client side (in the browser).
24
+ - [`useIsMounted`](/docs/use-is-mounted) — determines if the component is currently mounted.
25
+ - [`useLocalStorage`](/docs/use-local-storage) — uses the [localStorage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to persist state across page reloads.
26
+ - [`useMap`](/docs/use-map) — manages a key-value [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) state with setter actions.
27
+ - [`useMediaQuery`](/docs/use-media-query) — tracks the state of a media query using the [Match Media API](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia).
28
+ - [`useReadLocalStorage`](/docs/use-read-local-storage) —
29
+ - [`useResizeObserver`](/docs/use-resize-observer) — observes the size of an element using the [ResizeObserver API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
30
+ - [`useScreen`](/docs/use-screen) —
31
+ - [`useScript`](/docs/use-script) — dynamically loads scripts and tracking their loading status.
32
+ - [`useScrollLock`](/docs/use-scroll-lock) — A custom hook that locks and unlocks scroll.
33
+ - [`useSessionStorage`](/docs/use-session-storage) — uses the [sessionStorage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) to persist state across page reloads.
34
+ - [`useStep`](/docs/use-step) — manages and navigates between steps in a multi-step process.
35
+ - [`useTernaryDarkMode`](/docs/use-ternary-dark-mode) — manages ternary (system, dark, light) dark mode with local storage support.
36
+ - [`useTimeout`](/docs/use-timeout) — handles timeouts in React components using the [setTimeout API](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout).
37
+ - [`useToggle`](/docs/use-toggle) — manages a boolean toggle state in React components.
38
+ - [`useUnmount`](/docs/use-unmount) — runs a cleanup function when the component is unmounted.
39
+ - [`useWindowSize`](/docs/use-window-size) —
40
+ <!-- HOOKS:END -->
package/dist/index.cjs CHANGED
@@ -24,6 +24,150 @@ function useBoolean(defaultValue = false) {
24
24
  return { value, setValue, setTrue, setFalse, toggle };
25
25
  }
26
26
 
27
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
28
+
29
+ function useEventListener(eventName, handler, element, options) {
30
+ const savedHandler = react.useRef(handler);
31
+ useIsomorphicLayoutEffect(() => {
32
+ savedHandler.current = handler;
33
+ }, [handler]);
34
+ react.useEffect(() => {
35
+ const targetElement = element?.current ?? window;
36
+ if (!(targetElement && targetElement.addEventListener)) return;
37
+ const listener = (event) => {
38
+ savedHandler.current(event);
39
+ };
40
+ targetElement.addEventListener(eventName, listener, options);
41
+ return () => {
42
+ targetElement.removeEventListener(eventName, listener, options);
43
+ };
44
+ }, [eventName, element, options]);
45
+ }
46
+
47
+ function useClickAnyWhere(handler) {
48
+ useEventListener("click", (event) => {
49
+ handler(event);
50
+ });
51
+ }
52
+
53
+ function useEventCallback(fn) {
54
+ const ref = react.useRef(() => {
55
+ throw new Error("Cannot call an event handler while rendering.");
56
+ });
57
+ useIsomorphicLayoutEffect(() => {
58
+ ref.current = fn;
59
+ }, [fn]);
60
+ return react.useCallback((...args) => ref.current?.(...args), [ref]);
61
+ }
62
+
63
+ const IS_SERVER$7 = typeof document === "undefined";
64
+ function parseCookies() {
65
+ if (IS_SERVER$7) return {};
66
+ return document.cookie.split("; ").reduce(
67
+ (acc, part) => {
68
+ const [k, ...v] = part.split("=");
69
+ if (k && v) {
70
+ acc[decodeURIComponent(k.trim())] = decodeURIComponent(v.join("="));
71
+ }
72
+ return acc;
73
+ },
74
+ {}
75
+ );
76
+ }
77
+ function buildCookie(key, value, options) {
78
+ let cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
79
+ if (options.path) cookie += `; path=${options.path}`;
80
+ if (options.domain) cookie += `; domain=${options.domain}`;
81
+ if (options.expires) cookie += `; expires=${options.expires.toUTCString()}`;
82
+ if (options.maxAge) cookie += `; max-age=${options.maxAge}`;
83
+ if (options.secure) cookie += `; secure`;
84
+ if (options.sameSite) cookie += `; samesite=${options.sameSite}`;
85
+ return cookie;
86
+ }
87
+ function useCookie(key, initialValue, options = {}) {
88
+ const { initializeWithValue = true, prefix = "" } = options;
89
+ const cookieKey = prefix + key;
90
+ const serializer = react.useCallback(
91
+ (value) => {
92
+ if (options.serializer) return options.serializer(value);
93
+ return JSON.stringify(value);
94
+ },
95
+ [options]
96
+ );
97
+ const deserializer = react.useCallback(
98
+ (value) => {
99
+ if (options.deserializer) return options.deserializer(value);
100
+ if (value === "undefined") return void 0;
101
+ const fallback = initialValue instanceof Function ? initialValue() : initialValue;
102
+ try {
103
+ return JSON.parse(value);
104
+ } catch {
105
+ return fallback;
106
+ }
107
+ },
108
+ [options, initialValue]
109
+ );
110
+ const readValue = react.useCallback(() => {
111
+ const fallback = initialValue instanceof Function ? initialValue() : initialValue;
112
+ if (IS_SERVER$7) return fallback;
113
+ const cookies = parseCookies();
114
+ if (!(cookieKey in cookies)) return fallback;
115
+ return deserializer(cookies[cookieKey]);
116
+ }, [cookieKey, deserializer, initialValue]);
117
+ const [storedValue, setStoredValue] = react.useState(() => {
118
+ if (initializeWithValue) return readValue();
119
+ return initialValue instanceof Function ? initialValue() : initialValue;
120
+ });
121
+ const setValue = useEventCallback((value) => {
122
+ if (IS_SERVER$7) return;
123
+ try {
124
+ const newValue = value instanceof Function ? value(readValue()) : value;
125
+ const serialized = serializer(newValue);
126
+ document.cookie = buildCookie(cookieKey, serialized, {
127
+ path: "/",
128
+ ...options
129
+ });
130
+ setStoredValue(newValue);
131
+ window.dispatchEvent(
132
+ new CustomEvent("cookie-change", { detail: { key: cookieKey } })
133
+ );
134
+ } catch (error) {
135
+ console.warn(`Error setting cookie "${cookieKey}":`, error);
136
+ }
137
+ });
138
+ const removeValue = useEventCallback(() => {
139
+ if (IS_SERVER$7) return;
140
+ const fallback = initialValue instanceof Function ? initialValue() : initialValue;
141
+ document.cookie = buildCookie(cookieKey, "", {
142
+ path: "/",
143
+ ...options,
144
+ expires: /* @__PURE__ */ new Date(0)
145
+ });
146
+ setStoredValue(fallback);
147
+ window.dispatchEvent(
148
+ new CustomEvent("cookie-change", { detail: { key: cookieKey } })
149
+ );
150
+ });
151
+ react.useEffect(() => {
152
+ setStoredValue(readValue());
153
+ }, [cookieKey]);
154
+ const handleChange = react.useCallback(
155
+ (event) => {
156
+ if ("detail" in event && event.detail?.key !== cookieKey) return;
157
+ if ("key" in event && event.key !== cookieKey) return;
158
+ setStoredValue(readValue());
159
+ },
160
+ [cookieKey, readValue]
161
+ );
162
+ useEventListener("cookie-change", handleChange);
163
+ useEventListener("visibilitychange", () => {
164
+ if (document.visibilityState === "visible") {
165
+ setStoredValue(readValue());
166
+ }
167
+ });
168
+ return [storedValue, setValue, removeValue];
169
+ }
170
+
27
171
  function useCopyToClipboard() {
28
172
  const [copiedText, setCopiedText] = react.useState(null);
29
173
  const copy = react.useCallback(async (text) => {
@@ -64,8 +208,6 @@ function useCounter(initialValue) {
64
208
  };
65
209
  }
66
210
 
67
- const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
68
-
69
211
  function useInterval(callback, delay) {
70
212
  const savedCallback = react.useRef(callback);
71
213
  useIsomorphicLayoutEffect(() => {
@@ -120,34 +262,6 @@ function useCountdown({
120
262
  return [count, { startCountdown, stopCountdown, resetCountdown }];
121
263
  }
122
264
 
123
- function useEventCallback(fn) {
124
- const ref = react.useRef(() => {
125
- throw new Error("Cannot call an event handler while rendering.");
126
- });
127
- useIsomorphicLayoutEffect(() => {
128
- ref.current = fn;
129
- }, [fn]);
130
- return react.useCallback((...args) => ref.current?.(...args), [ref]);
131
- }
132
-
133
- function useEventListener(eventName, handler, element, options) {
134
- const savedHandler = react.useRef(handler);
135
- useIsomorphicLayoutEffect(() => {
136
- savedHandler.current = handler;
137
- }, [handler]);
138
- react.useEffect(() => {
139
- const targetElement = element?.current ?? window;
140
- if (!(targetElement && targetElement.addEventListener)) return;
141
- const listener = (event) => {
142
- savedHandler.current(event);
143
- };
144
- targetElement.addEventListener(eventName, listener, options);
145
- return () => {
146
- targetElement.removeEventListener(eventName, listener, options);
147
- };
148
- }, [eventName, element, options]);
149
- }
150
-
151
265
  const IS_SERVER$6 = typeof window === "undefined";
152
266
  function useLocalStorage(key, initialValue, options = {}) {
153
267
  const { initializeWithValue = true } = options;
@@ -282,7 +396,7 @@ function useMediaQuery(query, {
282
396
  }
283
397
 
284
398
  const COLOR_SCHEME_QUERY$1 = "(prefers-color-scheme: dark)";
285
- const LOCAL_STORAGE_KEY$1 = "usehooks-ts-dark-mode";
399
+ const LOCAL_STORAGE_KEY$1 = "sse-hooks-dark-mode";
286
400
  function useDarkMode(options = {}) {
287
401
  const {
288
402
  defaultValue,
@@ -1110,23 +1224,21 @@ function useSessionStorage(key, initialValue, options = {}) {
1110
1224
  }
1111
1225
  return initialValue instanceof Function ? initialValue() : initialValue;
1112
1226
  });
1113
- const setValue = useEventCallback(
1114
- (value) => {
1115
- if (IS_SERVER$1) {
1116
- console.warn(
1117
- `Tried setting sessionStorage key \u201C${key}\u201D even though environment is not a client`
1118
- );
1119
- }
1120
- try {
1121
- const newValue = value instanceof Function ? value(readValue()) : value;
1122
- window.sessionStorage.setItem(key, serializer(newValue));
1123
- setStoredValue(newValue);
1124
- window.dispatchEvent(new StorageEvent("session-storage", { key }));
1125
- } catch (error) {
1126
- console.warn(`Error setting sessionStorage key \u201C${key}\u201D:`, error);
1127
- }
1227
+ const setValue = useEventCallback((value) => {
1228
+ if (IS_SERVER$1) {
1229
+ console.warn(
1230
+ `Tried setting sessionStorage key \u201C${key}\u201D even though environment is not a client`
1231
+ );
1128
1232
  }
1129
- );
1233
+ try {
1234
+ const newValue = value instanceof Function ? value(readValue()) : value;
1235
+ window.sessionStorage.setItem(key, serializer(newValue));
1236
+ setStoredValue(newValue);
1237
+ window.dispatchEvent(new StorageEvent("session-storage", { key }));
1238
+ } catch (error) {
1239
+ console.warn(`Error setting sessionStorage key \u201C${key}\u201D:`, error);
1240
+ }
1241
+ });
1130
1242
  const removeValue = useEventCallback(() => {
1131
1243
  if (IS_SERVER$1) {
1132
1244
  console.warn(
@@ -1197,7 +1309,7 @@ function useStep(maxStep) {
1197
1309
  }
1198
1310
 
1199
1311
  const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
1200
- const LOCAL_STORAGE_KEY = "usehooks-ts-ternary-dark-mode";
1312
+ const LOCAL_STORAGE_KEY = "sse-hooks-ternary-dark-mode";
1201
1313
  function useTernaryDarkMode({
1202
1314
  defaultValue = "system",
1203
1315
  localStorageKey = LOCAL_STORAGE_KEY,
@@ -1286,6 +1398,8 @@ function useWindowSize(options = {}) {
1286
1398
  }
1287
1399
 
1288
1400
  exports.useBoolean = useBoolean;
1401
+ exports.useClickAnyWhere = useClickAnyWhere;
1402
+ exports.useCookie = useCookie;
1289
1403
  exports.useCopyToClipboard = useCopyToClipboard;
1290
1404
  exports.useCountdown = useCountdown;
1291
1405
  exports.useCounter = useCounter;