@ttoss/react-hooks 2.3.12 → 2.3.14

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/dist/index.cjs ADDED
@@ -0,0 +1,219 @@
1
+ /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
+ Object.defineProperty(exports, Symbol.toStringTag, {
3
+ value: 'Module'
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
15
+ key = keys[i];
16
+ if (!__hasOwnProp.call(to, key) && key !== except) {
17
+ __defProp(to, key, {
18
+ get: (k => from[k]).bind(null, key),
19
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
+ });
21
+ }
22
+ }
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
27
+ value: mod,
28
+ enumerable: true
29
+ }) : target, mod));
30
+
31
+ //#endregion
32
+ let react = require("react");
33
+ react = __toESM(react, 1);
34
+
35
+ //#region src/useDebounce.ts
36
+ const useDebounce = (value, delay) => {
37
+ const [debouncedValue, setDebouncedValue] = react.useState(value);
38
+ react.useEffect(() => {
39
+ const timer = setTimeout(() => {
40
+ return setDebouncedValue(value);
41
+ }, delay || 500);
42
+ return () => {
43
+ clearTimeout(timer);
44
+ };
45
+ }, [value, delay]);
46
+ return debouncedValue;
47
+ };
48
+
49
+ //#endregion
50
+ //#region src/useScript.ts
51
+ /**
52
+ * https://usehooks.com/useScript/
53
+ *
54
+ * @param src: string - the url of the script to load.
55
+ * @returns status: Status
56
+ */
57
+ const useScript = src => {
58
+ /**
59
+ * Keep track of script status ("idle", "loading", "ready", "error")
60
+ */
61
+ const [status, setStatus] = react.useState(src ? "loading" : "idle");
62
+ react.useEffect(() => {
63
+ /**
64
+ * Allow falsy src value if waiting on other data needed for
65
+ * constructing the script URL passed to this hook.
66
+ */
67
+ if (!src) {
68
+ setStatus("idle");
69
+ return;
70
+ }
71
+ /**
72
+ * Fetch existing script element by src.
73
+ * It may have been added by another instance of this hook.
74
+ */
75
+ let script = document.querySelector(`script[src="${src}"]`);
76
+ if (!script) {
77
+ /**
78
+ * Create script element and set its src.
79
+ */
80
+ script = document.createElement("script");
81
+ script.src = src;
82
+ script.async = true;
83
+ script.setAttribute("data-status", "loading");
84
+ /**
85
+ * Add script to document body
86
+ */
87
+ document.body.appendChild(script);
88
+ /**
89
+ * Store status in attribute on script.
90
+ * This can be read by other instances of this hook.
91
+ */
92
+ const setAttributeFromEvent = event => {
93
+ if (script) script.setAttribute("data-status", event.type === "load" ? "ready" : "error");
94
+ };
95
+ script.addEventListener("load", setAttributeFromEvent);
96
+ script.addEventListener("error", setAttributeFromEvent);
97
+ } else
98
+ /**
99
+ * Grab existing script status from attribute and set to state.
100
+ */
101
+ setStatus(script.getAttribute("data-status") || "error");
102
+ /**
103
+ * Script event handler to update status in state
104
+ * Note: Even if the script already exists we still need to add
105
+ * event handlers to update the state for *this* hook instance.
106
+ */
107
+ const setStateFromEvent = event => {
108
+ setStatus(event.type === "load" ? "ready" : "error");
109
+ };
110
+ /**
111
+ * Add event listeners.
112
+ */
113
+ script.addEventListener("load", setStateFromEvent);
114
+ script.addEventListener("error", setStateFromEvent);
115
+ /**
116
+ * Remove event listeners on cleanup.
117
+ */
118
+ return () => {
119
+ if (script) {
120
+ script.removeEventListener("load", setStateFromEvent);
121
+ script.removeEventListener("error", setStateFromEvent);
122
+ }
123
+ };
124
+ },
125
+ /**
126
+ * Only re-run effect if script src changes.
127
+ */
128
+ [src]);
129
+ return {
130
+ status
131
+ };
132
+ };
133
+
134
+ //#endregion
135
+ //#region src/useStorage.ts
136
+ function useStorage(key, defaultValue, options) {
137
+ const {
138
+ serializer,
139
+ parser,
140
+ logger,
141
+ syncData,
142
+ storage
143
+ } = react.useMemo(() => {
144
+ return {
145
+ serializer: JSON.stringify,
146
+ parser: JSON.parse,
147
+ logger: console.log,
148
+ syncData: true,
149
+ ...options
150
+ };
151
+ }, [options]);
152
+ const effectiveStorage = storage ?? (typeof window !== "undefined" ? window.localStorage : void 0);
153
+ const rawValueRef = react.useRef(null);
154
+ const [value, setValue] = react.useState(() => {
155
+ if (typeof window === "undefined" || !effectiveStorage) return defaultValue;
156
+ try {
157
+ rawValueRef.current = effectiveStorage.getItem(key);
158
+ return rawValueRef.current ? parser(rawValueRef.current) : defaultValue;
159
+ } catch (error) {
160
+ logger(error);
161
+ return defaultValue;
162
+ }
163
+ });
164
+ react.useEffect(() => {
165
+ if (typeof window === "undefined" || !effectiveStorage) return;
166
+ const updateLocalStorage = () => {
167
+ if (value !== void 0) {
168
+ const newValue = serializer(value);
169
+ const oldValue = rawValueRef.current;
170
+ rawValueRef.current = newValue;
171
+ effectiveStorage.setItem(key, newValue);
172
+ window.dispatchEvent(new StorageEvent("storage", {
173
+ storageArea: effectiveStorage,
174
+ url: window.location.href,
175
+ key,
176
+ newValue,
177
+ oldValue
178
+ }));
179
+ } else {
180
+ effectiveStorage.removeItem(key);
181
+ window.dispatchEvent(new StorageEvent("storage", {
182
+ storageArea: effectiveStorage,
183
+ url: window.location.href,
184
+ key
185
+ }));
186
+ }
187
+ };
188
+ try {
189
+ updateLocalStorage();
190
+ } catch (error) {
191
+ logger(error);
192
+ }
193
+ }, [key, logger, serializer, effectiveStorage, value]);
194
+ react.useEffect(() => {
195
+ if (!syncData) return;
196
+ const handleStorageChange = e => {
197
+ if (e.key !== key || e.storageArea !== effectiveStorage) return;
198
+ try {
199
+ if (e.newValue !== rawValueRef.current) {
200
+ rawValueRef.current = e.newValue;
201
+ setValue(e.newValue ? parser(e.newValue) : void 0);
202
+ }
203
+ } catch (error) {
204
+ logger(error);
205
+ }
206
+ };
207
+ if (typeof window === "undefined") return;
208
+ window.addEventListener("storage", handleStorageChange);
209
+ return () => {
210
+ return window.removeEventListener("storage", handleStorageChange);
211
+ };
212
+ }, [key, logger, parser, effectiveStorage, syncData]);
213
+ return [value, setValue];
214
+ }
215
+
216
+ //#endregion
217
+ exports.useDebounce = useDebounce;
218
+ exports.useScript = useScript;
219
+ exports.useStorage = useStorage;
@@ -1,7 +1,10 @@
1
- import * as React from 'react';
2
1
 
3
- declare const useDebounce: <T>(value: T, delay?: number) => T;
2
+ import * as React from "react";
4
3
 
4
+ //#region src/useDebounce.d.ts
5
+ declare const useDebounce: <T>(value: T, delay?: number) => T;
6
+ //#endregion
7
+ //#region src/useScript.d.ts
5
8
  type ScriptStatus = 'idle' | 'loading' | 'ready' | 'error';
6
9
  /**
7
10
  * https://usehooks.com/useScript/
@@ -10,20 +13,21 @@ type ScriptStatus = 'idle' | 'loading' | 'ready' | 'error';
10
13
  * @returns status: Status
11
14
  */
12
15
  declare const useScript: (src: string) => {
13
- status: ScriptStatus;
16
+ status: ScriptStatus;
14
17
  };
15
-
18
+ //#endregion
19
+ //#region src/useStorage.d.ts
16
20
  type Serializer<T> = (object: T | undefined) => string;
17
21
  type Parser<T> = (val: string) => T | undefined;
18
22
  type Setter<T> = React.Dispatch<React.SetStateAction<T | undefined>>;
19
23
  type Options<T> = Partial<{
20
- serializer: Serializer<T>;
21
- parser: Parser<T>;
22
- logger: (error: any) => void;
23
- syncData: boolean;
24
- storage?: Storage;
24
+ serializer: Serializer<T>;
25
+ parser: Parser<T>;
26
+ logger: (error: any) => void;
27
+ syncData: boolean;
28
+ storage?: Storage;
25
29
  }>;
26
30
  declare function useStorage<T>(key: string, defaultValue: T, options?: Options<T>): [T, Setter<T>];
27
31
  declare function useStorage<T>(key: string, defaultValue?: undefined, options?: Options<T>): [T | undefined, Setter<T>];
28
-
29
- export { type ScriptStatus, useDebounce, useScript, useStorage };
32
+ //#endregion
33
+ export { type ScriptStatus, useDebounce, useScript, useStorage };
@@ -0,0 +1,33 @@
1
+
2
+ import * as React from "react";
3
+
4
+ //#region src/useDebounce.d.ts
5
+ declare const useDebounce: <T>(value: T, delay?: number) => T;
6
+ //#endregion
7
+ //#region src/useScript.d.ts
8
+ type ScriptStatus = 'idle' | 'loading' | 'ready' | 'error';
9
+ /**
10
+ * https://usehooks.com/useScript/
11
+ *
12
+ * @param src: string - the url of the script to load.
13
+ * @returns status: Status
14
+ */
15
+ declare const useScript: (src: string) => {
16
+ status: ScriptStatus;
17
+ };
18
+ //#endregion
19
+ //#region src/useStorage.d.ts
20
+ type Serializer<T> = (object: T | undefined) => string;
21
+ type Parser<T> = (val: string) => T | undefined;
22
+ type Setter<T> = React.Dispatch<React.SetStateAction<T | undefined>>;
23
+ type Options<T> = Partial<{
24
+ serializer: Serializer<T>;
25
+ parser: Parser<T>;
26
+ logger: (error: any) => void;
27
+ syncData: boolean;
28
+ storage?: Storage;
29
+ }>;
30
+ declare function useStorage<T>(key: string, defaultValue: T, options?: Options<T>): [T, Setter<T>];
31
+ declare function useStorage<T>(key: string, defaultValue?: undefined, options?: Options<T>): [T | undefined, Setter<T>];
32
+ //#endregion
33
+ export { type ScriptStatus, useDebounce, useScript, useStorage };
@@ -1,13 +1,8 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
- var __defProp = Object.defineProperty;
3
- var __name = (target, value) => __defProp(target, "name", {
4
- value,
5
- configurable: true
6
- });
7
-
8
- // src/useDebounce.ts
9
2
  import * as React from "react";
10
- var useDebounce = /* @__PURE__ */__name((value, delay) => {
3
+
4
+ //#region src/useDebounce.ts
5
+ const useDebounce = (value, delay) => {
11
6
  const [debouncedValue, setDebouncedValue] = React.useState(value);
12
7
  React.useEffect(() => {
13
8
  const timer = setTimeout(() => {
@@ -18,39 +13,77 @@ var useDebounce = /* @__PURE__ */__name((value, delay) => {
18
13
  };
19
14
  }, [value, delay]);
20
15
  return debouncedValue;
21
- }, "useDebounce");
16
+ };
22
17
 
23
- // src/useScript.ts
24
- import * as React2 from "react";
25
- var useScript = /* @__PURE__ */__name(src => {
26
- const [status, setStatus] = React2.useState(src ? "loading" : "idle");
27
- React2.useEffect(() => {
18
+ //#endregion
19
+ //#region src/useScript.ts
20
+ /**
21
+ * https://usehooks.com/useScript/
22
+ *
23
+ * @param src: string - the url of the script to load.
24
+ * @returns status: Status
25
+ */
26
+ const useScript = src => {
27
+ /**
28
+ * Keep track of script status ("idle", "loading", "ready", "error")
29
+ */
30
+ const [status, setStatus] = React.useState(src ? "loading" : "idle");
31
+ React.useEffect(() => {
32
+ /**
33
+ * Allow falsy src value if waiting on other data needed for
34
+ * constructing the script URL passed to this hook.
35
+ */
28
36
  if (!src) {
29
37
  setStatus("idle");
30
38
  return;
31
39
  }
40
+ /**
41
+ * Fetch existing script element by src.
42
+ * It may have been added by another instance of this hook.
43
+ */
32
44
  let script = document.querySelector(`script[src="${src}"]`);
33
45
  if (!script) {
46
+ /**
47
+ * Create script element and set its src.
48
+ */
34
49
  script = document.createElement("script");
35
50
  script.src = src;
36
51
  script.async = true;
37
52
  script.setAttribute("data-status", "loading");
53
+ /**
54
+ * Add script to document body
55
+ */
38
56
  document.body.appendChild(script);
39
- const setAttributeFromEvent = /* @__PURE__ */__name(event => {
40
- if (script) {
41
- script.setAttribute("data-status", event.type === "load" ? "ready" : "error");
42
- }
43
- }, "setAttributeFromEvent");
57
+ /**
58
+ * Store status in attribute on script.
59
+ * This can be read by other instances of this hook.
60
+ */
61
+ const setAttributeFromEvent = event => {
62
+ if (script) script.setAttribute("data-status", event.type === "load" ? "ready" : "error");
63
+ };
44
64
  script.addEventListener("load", setAttributeFromEvent);
45
65
  script.addEventListener("error", setAttributeFromEvent);
46
- } else {
66
+ } else
67
+ /**
68
+ * Grab existing script status from attribute and set to state.
69
+ */
47
70
  setStatus(script.getAttribute("data-status") || "error");
48
- }
49
- const setStateFromEvent = /* @__PURE__ */__name(event => {
71
+ /**
72
+ * Script event handler to update status in state
73
+ * Note: Even if the script already exists we still need to add
74
+ * event handlers to update the state for *this* hook instance.
75
+ */
76
+ const setStateFromEvent = event => {
50
77
  setStatus(event.type === "load" ? "ready" : "error");
51
- }, "setStateFromEvent");
78
+ };
79
+ /**
80
+ * Add event listeners.
81
+ */
52
82
  script.addEventListener("load", setStateFromEvent);
53
83
  script.addEventListener("error", setStateFromEvent);
84
+ /**
85
+ * Remove event listeners on cleanup.
86
+ */
54
87
  return () => {
55
88
  if (script) {
56
89
  script.removeEventListener("load", setStateFromEvent);
@@ -65,48 +98,41 @@ var useScript = /* @__PURE__ */__name(src => {
65
98
  return {
66
99
  status
67
100
  };
68
- }, "useScript");
101
+ };
69
102
 
70
- // src/useStorage.ts
71
- import * as React3 from "react";
103
+ //#endregion
104
+ //#region src/useStorage.ts
72
105
  function useStorage(key, defaultValue, options) {
73
- const opts = React3.useMemo(() => {
106
+ const {
107
+ serializer,
108
+ parser,
109
+ logger,
110
+ syncData,
111
+ storage
112
+ } = React.useMemo(() => {
74
113
  return {
75
114
  serializer: JSON.stringify,
76
115
  parser: JSON.parse,
77
- // eslint-disable-next-line no-console
78
116
  logger: console.log,
79
117
  syncData: true,
80
118
  ...options
81
119
  };
82
120
  }, [options]);
83
- const {
84
- serializer,
85
- parser,
86
- logger,
87
- syncData,
88
- storage
89
- } = opts;
90
121
  const effectiveStorage = storage ?? (typeof window !== "undefined" ? window.localStorage : void 0);
91
- const rawValueRef = React3.useRef(null);
92
- const [value, setValue] = React3.useState(() => {
93
- if (typeof window === "undefined" || !effectiveStorage) {
94
- return defaultValue;
95
- }
122
+ const rawValueRef = React.useRef(null);
123
+ const [value, setValue] = React.useState(() => {
124
+ if (typeof window === "undefined" || !effectiveStorage) return defaultValue;
96
125
  try {
97
126
  rawValueRef.current = effectiveStorage.getItem(key);
98
- const res = rawValueRef.current ? parser(rawValueRef.current) : defaultValue;
99
- return res;
127
+ return rawValueRef.current ? parser(rawValueRef.current) : defaultValue;
100
128
  } catch (error) {
101
129
  logger(error);
102
130
  return defaultValue;
103
131
  }
104
132
  });
105
- React3.useEffect(() => {
106
- if (typeof window === "undefined" || !effectiveStorage) {
107
- return;
108
- }
109
- const updateLocalStorage = /* @__PURE__ */__name(() => {
133
+ React.useEffect(() => {
134
+ if (typeof window === "undefined" || !effectiveStorage) return;
135
+ const updateLocalStorage = () => {
110
136
  if (value !== void 0) {
111
137
  const newValue = serializer(value);
112
138
  const oldValue = rawValueRef.current;
@@ -127,21 +153,17 @@ function useStorage(key, defaultValue, options) {
127
153
  key
128
154
  }));
129
155
  }
130
- }, "updateLocalStorage");
156
+ };
131
157
  try {
132
158
  updateLocalStorage();
133
159
  } catch (error) {
134
160
  logger(error);
135
161
  }
136
162
  }, [key, logger, serializer, effectiveStorage, value]);
137
- React3.useEffect(() => {
138
- if (!syncData) {
139
- return;
140
- }
141
- const handleStorageChange = /* @__PURE__ */__name(e => {
142
- if (e.key !== key || e.storageArea !== effectiveStorage) {
143
- return;
144
- }
163
+ React.useEffect(() => {
164
+ if (!syncData) return;
165
+ const handleStorageChange = e => {
166
+ if (e.key !== key || e.storageArea !== effectiveStorage) return;
145
167
  try {
146
168
  if (e.newValue !== rawValueRef.current) {
147
169
  rawValueRef.current = e.newValue;
@@ -150,10 +172,8 @@ function useStorage(key, defaultValue, options) {
150
172
  } catch (error) {
151
173
  logger(error);
152
174
  }
153
- }, "handleStorageChange");
154
- if (typeof window === "undefined") {
155
- return;
156
- }
175
+ };
176
+ if (typeof window === "undefined") return;
157
177
  window.addEventListener("storage", handleStorageChange);
158
178
  return () => {
159
179
  return window.removeEventListener("storage", handleStorageChange);
@@ -161,5 +181,6 @@ function useStorage(key, defaultValue, options) {
161
181
  }, [key, logger, parser, effectiveStorage, syncData]);
162
182
  return [value, setValue];
163
183
  }
164
- __name(useStorage, "useStorage");
184
+
185
+ //#endregion
165
186
  export { useDebounce, useScript, useStorage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/react-hooks",
3
- "version": "2.3.12",
3
+ "version": "2.3.14",
4
4
  "description": "React hooks.",
5
5
  "keywords": [
6
6
  "React",
@@ -19,8 +19,8 @@
19
19
  "type": "module",
20
20
  "exports": {
21
21
  ".": {
22
- "types": "./dist/index.d.ts",
23
- "default": "./dist/esm/index.js"
22
+ "types": "./dist/index.d.mts",
23
+ "default": "./dist/index.mjs"
24
24
  }
25
25
  },
26
26
  "files": [
@@ -29,10 +29,10 @@
29
29
  "devDependencies": {
30
30
  "@types/react": "^19.2.14",
31
31
  "jest": "^30.3.0",
32
- "react": "^19.2.4",
33
- "tsup": "^8.5.1",
34
- "@ttoss/config": "^1.37.12",
35
- "@ttoss/test-utils": "^4.2.12"
32
+ "react": "^19.2.6",
33
+ "tsdown": "^0.22.0",
34
+ "@ttoss/config": "^1.37.13",
35
+ "@ttoss/test-utils": "^4.2.13"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": ">=16.8.0"
@@ -42,7 +42,7 @@
42
42
  "provenance": true
43
43
  },
44
44
  "scripts": {
45
- "build": "tsup",
45
+ "build": "tsdown",
46
46
  "test": "jest --projects tests/unit"
47
47
  }
48
48
  }