@w3ux/hooks 2.4.2 → 2.4.4
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/index.cjs +91 -26
- package/index.cjs.map +1 -1
- package/index.d.cts +12 -1
- package/index.d.ts +12 -1
- package/index.js +87 -23
- package/index.js.map +1 -1
- package/package.json +2 -2
package/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
createSafeContext: () => createSafeContext,
|
|
24
|
+
useAutoFitText: () => useAutoFitText,
|
|
24
25
|
useEffectIgnoreInitial: () => useEffectIgnoreInitial,
|
|
25
26
|
useOnResize: () => useOnResize,
|
|
26
27
|
useOutsideAlerter: () => useOutsideAlerter,
|
|
@@ -30,11 +31,74 @@ __export(index_exports, {
|
|
|
30
31
|
});
|
|
31
32
|
module.exports = __toCommonJS(index_exports);
|
|
32
33
|
|
|
33
|
-
// src/
|
|
34
|
+
// src/useAutoFitText.tsx
|
|
34
35
|
var import_react = require("react");
|
|
36
|
+
var useAutoFitText = ({
|
|
37
|
+
minFontSize = 0.625,
|
|
38
|
+
maxFontSize = 1.08,
|
|
39
|
+
unit = "rem"
|
|
40
|
+
} = {}) => {
|
|
41
|
+
const containerRef = (0, import_react.useRef)(null);
|
|
42
|
+
const [fontSize, setFontSize] = (0, import_react.useState)(`${maxFontSize}${unit}`);
|
|
43
|
+
const calculateOptimalFontSize = (0, import_react.useCallback)(
|
|
44
|
+
(container) => {
|
|
45
|
+
const containerWidth = container.offsetWidth;
|
|
46
|
+
if (containerWidth === 0) return;
|
|
47
|
+
const originalFontSize = container.style.fontSize;
|
|
48
|
+
let low = minFontSize;
|
|
49
|
+
let high = maxFontSize;
|
|
50
|
+
let bestSize = minFontSize;
|
|
51
|
+
const precision = 1e-3;
|
|
52
|
+
while (high - low > precision) {
|
|
53
|
+
const mid = (low + high) / 2;
|
|
54
|
+
container.style.fontSize = `${mid}${unit}`;
|
|
55
|
+
const scrollWidth = container.scrollWidth;
|
|
56
|
+
if (scrollWidth <= containerWidth) {
|
|
57
|
+
bestSize = mid;
|
|
58
|
+
low = mid;
|
|
59
|
+
} else {
|
|
60
|
+
high = mid;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
container.style.fontSize = originalFontSize;
|
|
64
|
+
const newFontSize = `${bestSize}${unit}`;
|
|
65
|
+
setFontSize((prev) => prev === newFontSize ? prev : newFontSize);
|
|
66
|
+
},
|
|
67
|
+
[minFontSize, maxFontSize, unit]
|
|
68
|
+
);
|
|
69
|
+
(0, import_react.useEffect)(() => {
|
|
70
|
+
const container = containerRef.current;
|
|
71
|
+
if (!container) return;
|
|
72
|
+
let debounceTimer = null;
|
|
73
|
+
const debouncedCalculate = () => {
|
|
74
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
75
|
+
debounceTimer = setTimeout(() => {
|
|
76
|
+
calculateOptimalFontSize(container);
|
|
77
|
+
}, 5);
|
|
78
|
+
};
|
|
79
|
+
const resizeObserver = new ResizeObserver(debouncedCalculate);
|
|
80
|
+
const mutationObserver = new MutationObserver(debouncedCalculate);
|
|
81
|
+
resizeObserver.observe(container);
|
|
82
|
+
mutationObserver.observe(container, {
|
|
83
|
+
childList: true,
|
|
84
|
+
subtree: true,
|
|
85
|
+
characterData: true
|
|
86
|
+
});
|
|
87
|
+
calculateOptimalFontSize(container);
|
|
88
|
+
return () => {
|
|
89
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
90
|
+
resizeObserver.disconnect();
|
|
91
|
+
mutationObserver.disconnect();
|
|
92
|
+
};
|
|
93
|
+
}, [calculateOptimalFontSize]);
|
|
94
|
+
return { containerRef, fontSize };
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/useEffectIgnoreInitial.tsx
|
|
98
|
+
var import_react2 = require("react");
|
|
35
99
|
var useEffectIgnoreInitial = (fn, deps) => {
|
|
36
|
-
const isInitial = (0,
|
|
37
|
-
(0,
|
|
100
|
+
const isInitial = (0, import_react2.useRef)(true);
|
|
101
|
+
(0, import_react2.useEffect)(
|
|
38
102
|
() => {
|
|
39
103
|
if (!isInitial.current) {
|
|
40
104
|
if (typeof fn === "function") {
|
|
@@ -48,10 +112,10 @@ var useEffectIgnoreInitial = (fn, deps) => {
|
|
|
48
112
|
};
|
|
49
113
|
|
|
50
114
|
// src/useOnResize.tsx
|
|
51
|
-
var
|
|
115
|
+
var import_react3 = require("react");
|
|
52
116
|
var useOnResize = (callback, options = {}) => {
|
|
53
117
|
const { outerElement, throttle: throttleDuration = 100 } = options;
|
|
54
|
-
const lastExecutedRef = (0,
|
|
118
|
+
const lastExecutedRef = (0, import_react3.useRef)(0);
|
|
55
119
|
const handleResize = () => {
|
|
56
120
|
const now = Date.now();
|
|
57
121
|
if (now - lastExecutedRef.current < throttleDuration) {
|
|
@@ -60,7 +124,7 @@ var useOnResize = (callback, options = {}) => {
|
|
|
60
124
|
lastExecutedRef.current = now;
|
|
61
125
|
callback();
|
|
62
126
|
};
|
|
63
|
-
(0,
|
|
127
|
+
(0, import_react3.useEffect)(() => {
|
|
64
128
|
const target = outerElement?.current || window;
|
|
65
129
|
target.addEventListener("resize", handleResize);
|
|
66
130
|
return () => {
|
|
@@ -70,9 +134,9 @@ var useOnResize = (callback, options = {}) => {
|
|
|
70
134
|
};
|
|
71
135
|
|
|
72
136
|
// src/useOutsideAlerter.tsx
|
|
73
|
-
var
|
|
137
|
+
var import_react4 = require("react");
|
|
74
138
|
var useOutsideAlerter = (ref, callback, ignore = []) => {
|
|
75
|
-
(0,
|
|
139
|
+
(0, import_react4.useEffect)(() => {
|
|
76
140
|
const handleClickOutside = (ev) => {
|
|
77
141
|
if (ev) {
|
|
78
142
|
if (ref.current && !ref.current.contains(ev.target)) {
|
|
@@ -95,7 +159,7 @@ var useOutsideAlerter = (ref, callback, ignore = []) => {
|
|
|
95
159
|
};
|
|
96
160
|
|
|
97
161
|
// src/useSafeContext.tsx
|
|
98
|
-
var
|
|
162
|
+
var import_react5 = require("react");
|
|
99
163
|
var useSafeContext = (ctx) => {
|
|
100
164
|
if (ctx === null || ctx === void 0) {
|
|
101
165
|
throw new Error(
|
|
@@ -105,13 +169,13 @@ var useSafeContext = (ctx) => {
|
|
|
105
169
|
return ctx;
|
|
106
170
|
};
|
|
107
171
|
var createSafeContext = () => {
|
|
108
|
-
const Context = (0,
|
|
109
|
-
const useHook = () => useSafeContext((0,
|
|
172
|
+
const Context = (0, import_react5.createContext)(null);
|
|
173
|
+
const useHook = () => useSafeContext((0, import_react5.useContext)(Context));
|
|
110
174
|
return [Context, useHook];
|
|
111
175
|
};
|
|
112
176
|
|
|
113
177
|
// src/useSize.tsx
|
|
114
|
-
var
|
|
178
|
+
var import_react6 = require("react");
|
|
115
179
|
var useSize = (element, options = {}) => {
|
|
116
180
|
const { outerElement, throttle: throttleDuration = 100 } = options;
|
|
117
181
|
const getSize = (el = null) => {
|
|
@@ -119,8 +183,8 @@ var useSize = (element, options = {}) => {
|
|
|
119
183
|
const height = el?.offsetHeight || 0;
|
|
120
184
|
return { width, height };
|
|
121
185
|
};
|
|
122
|
-
const lastExecutedRef = (0,
|
|
123
|
-
const [size, setSize] = (0,
|
|
186
|
+
const lastExecutedRef = (0, import_react6.useRef)(0);
|
|
187
|
+
const [size, setSize] = (0, import_react6.useState)(
|
|
124
188
|
getSize(element?.current)
|
|
125
189
|
);
|
|
126
190
|
const handleResize = () => {
|
|
@@ -131,7 +195,7 @@ var useSize = (element, options = {}) => {
|
|
|
131
195
|
lastExecutedRef.current = now;
|
|
132
196
|
setSize(getSize(element?.current));
|
|
133
197
|
};
|
|
134
|
-
(0,
|
|
198
|
+
(0, import_react6.useEffect)(() => {
|
|
135
199
|
const listenFor = outerElement?.current || window;
|
|
136
200
|
listenFor.addEventListener("resize", handleResize);
|
|
137
201
|
return () => {
|
|
@@ -143,7 +207,7 @@ var useSize = (element, options = {}) => {
|
|
|
143
207
|
|
|
144
208
|
// src/useTimeLeft/index.tsx
|
|
145
209
|
var import_utils = require("@w3ux/utils");
|
|
146
|
-
var
|
|
210
|
+
var import_react7 = require("react");
|
|
147
211
|
|
|
148
212
|
// src/util.ts
|
|
149
213
|
var import_date_fns = require("date-fns");
|
|
@@ -214,14 +278,14 @@ var useTimeLeft = (props) => {
|
|
|
214
278
|
raw
|
|
215
279
|
};
|
|
216
280
|
};
|
|
217
|
-
const [to, setTo] = (0,
|
|
218
|
-
const toRef = (0,
|
|
219
|
-
const [timeleft, setTimeleft] = (0,
|
|
220
|
-
const [minInterval, setMinInterval] = (0,
|
|
221
|
-
const minIntervalRef = (0,
|
|
222
|
-
const [secInterval, setSecInterval] = (0,
|
|
223
|
-
const secIntervalRef = (0,
|
|
224
|
-
(0,
|
|
281
|
+
const [to, setTo] = (0, import_react7.useState)(null);
|
|
282
|
+
const toRef = (0, import_react7.useRef)(to);
|
|
283
|
+
const [timeleft, setTimeleft] = (0, import_react7.useState)(getTimeleft());
|
|
284
|
+
const [minInterval, setMinInterval] = (0, import_react7.useState)(void 0);
|
|
285
|
+
const minIntervalRef = (0, import_react7.useRef)(minInterval);
|
|
286
|
+
const [secInterval, setSecInterval] = (0, import_react7.useState)(void 0);
|
|
287
|
+
const secIntervalRef = (0, import_react7.useRef)(secInterval);
|
|
288
|
+
(0, import_react7.useEffect)(() => {
|
|
225
289
|
setTimeleft(getTimeleft());
|
|
226
290
|
if (inLastHour()) {
|
|
227
291
|
if (!secIntervalRef.current) {
|
|
@@ -245,10 +309,10 @@ var useTimeLeft = (props) => {
|
|
|
245
309
|
(0, import_utils.setStateWithRef)(interval, setMinInterval, minIntervalRef);
|
|
246
310
|
}
|
|
247
311
|
}, [to, inLastHour(), lastMinuteCountdown(), ...depsTimeleft]);
|
|
248
|
-
(0,
|
|
312
|
+
(0, import_react7.useEffect)(() => {
|
|
249
313
|
setTimeleft(getTimeleft());
|
|
250
314
|
}, [...depsFormat]);
|
|
251
|
-
(0,
|
|
315
|
+
(0, import_react7.useEffect)(
|
|
252
316
|
() => () => {
|
|
253
317
|
clearInterval(minInterval);
|
|
254
318
|
clearInterval(secInterval);
|
|
@@ -267,6 +331,7 @@ var useTimeLeft = (props) => {
|
|
|
267
331
|
// Annotate the CommonJS export names for ESM import in node:
|
|
268
332
|
0 && (module.exports = {
|
|
269
333
|
createSafeContext,
|
|
334
|
+
useAutoFitText,
|
|
270
335
|
useEffectIgnoreInitial,
|
|
271
336
|
useOnResize,
|
|
272
337
|
useOutsideAlerter,
|
package/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx","../src/useEffectIgnoreInitial.tsx","../src/useOnResize.tsx","../src/useOutsideAlerter.tsx","../src/useSafeContext.tsx","../src/useSize.tsx","../src/useTimeLeft/index.tsx","../src/util.ts","../src/useTimeLeft/defaults.ts"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nexport * from './useEffectIgnoreInitial'\nexport * from './useOnResize'\nexport * from './useOutsideAlerter'\nexport * from './useSafeContext'\nexport * from './useSize'\nexport * from './useTimeLeft'\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { useEffect, useRef } from 'react'\n\nexport const useEffectIgnoreInitial = <T, U>(fn: T, deps: U[]) => {\n\tconst isInitial = useRef<boolean>(true)\n\n\tuseEffect(\n\t\t() => {\n\t\t\tif (!isInitial.current) {\n\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\tfn()\n\t\t\t\t}\n\t\t\t}\n\t\t\tisInitial.current = false\n\t\t},\n\t\tdeps ? [...deps] : undefined,\n\t)\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef } from 'react'\n\ninterface UseOnResizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n/**\n * Custom hook that triggers a callback function when the specified element\n * or the window is resized.\n *\n * @param callback - The function to be executed on resize.\n * @param options - Optional parameters to customize the behavior:\n * - outerElement: A ref to an HTMLElement to listen for resize events.\n * - throttle: Optional duration in milliseconds to throttle the callback execution.\n * Default is 100 milliseconds.\n */\nexport const useOnResize = (\n\tcallback: () => void,\n\toptions: UseOnResizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// Throttled resize handler to limit the frequency of callback execution.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\n\t\t// Check if the callback can be executed based on the throttle duration.\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t}\n\n\t\tlastExecutedRef.current = now\n\t\tcallback()\n\t}\n\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\tconst target = outerElement?.current || window\n\n\t\t// Add the resize event listener when the component mounts.\n\t\ttarget.addEventListener('resize', handleResize)\n\n\t\t// Clean up the event listener when the component unmounts.\n\t\treturn () => {\n\t\t\ttarget.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [throttleDuration, callback])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { type RefObject, useEffect } from 'react'\n\n// A hook that alerts clicks outside of the passed ref.\nexport const useOutsideAlerter = (\n\tref: RefObject<HTMLElement | null>,\n\tcallback: () => void,\n\tignore: string[] = [],\n) => {\n\tuseEffect(() => {\n\t\tconst handleClickOutside = (ev: MouseEvent) => {\n\t\t\tif (ev) {\n\t\t\t\tif (ref.current && !ref.current.contains(ev.target as Node)) {\n\t\t\t\t\tconst target = ev.target as HTMLElement\n\t\t\t\t\t// Ignore tags with a name of `ignore`, or if there is a class of `ignore` in the parent\n\t\t\t\t\t// tree.\n\t\t\t\t\tconst tagName = target.tagName.toLowerCase()\n\t\t\t\t\tconst ignored = ignore.some(\n\t\t\t\t\t\t(i) =>\n\t\t\t\t\t\t\ti.toLowerCase() === tagName || target.closest(`.${i}`) !== null,\n\t\t\t\t\t)\n\n\t\t\t\t\tif (!ignored) {\n\t\t\t\t\t\tcallback()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('mousedown', handleClickOutside)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('mousedown', handleClickOutside)\n\t\t}\n\t}, [ref])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { Context } from 'react'\nimport { createContext, useContext } from 'react'\n\nexport const useSafeContext = <T,>(ctx: T | null | undefined): T => {\n\tif (ctx === null || ctx === undefined) {\n\t\tthrow new Error(\n\t\t\t'Context value is null or undefined. Please ensure the context Provider is used correctly.',\n\t\t)\n\t}\n\treturn ctx\n}\n\nexport const createSafeContext = <T,>(): [Context<T | null>, () => T] => {\n\tconst Context = createContext<T | null>(null)\n\tconst useHook = () => useSafeContext<T>(useContext(Context))\n\treturn [Context, useHook]\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef, useState } from 'react'\n\n// Define the type for the options parameter.\ninterface UseSizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n// Custom hook to get the width and height of a specified element. Updates the `size` state when the\n// specified \"outer element\" (or the window by default) resizes.\nexport const useSize = (\n\telement: RefObject<HTMLElement | null>,\n\toptions: UseSizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\n\t// Helper function to retrieve the width and height of an element\n\t// If no element is found, default dimensions are set to 0.\n\tconst getSize = (el: HTMLElement | null = null) => {\n\t\tconst width = el?.offsetWidth || 0\n\t\tconst height = el?.offsetHeight || 0\n\t\treturn { width, height }\n\t}\n\n\t// Ref to store the last execution time of the `resizeThrottle` handler.\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// State to store the current width and height of the specified element.\n\tconst [size, setSize] = useState<{ width: number; height: number }>(\n\t\tgetSize(element?.current),\n\t)\n\n\t// Throttle the resize event handler to limit how often size updates occur.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t} // Exit if `throttleDuration` has not passed.\n\n\t\tlastExecutedRef.current = now // Update last execution time.\n\n\t\tsetSize(getSize(element?.current))\n\t}\n\n\t// Set up the resize event listener on mount and clean it up on unmount.\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\t// If `outerElement` is provided, listen to its resize events; otherwise, listen to the window's.\n\t\tconst listenFor = outerElement?.current || window\n\n\t\tlistenFor.addEventListener('resize', handleResize)\n\n\t\t// Clean up event listener when the component unmounts to avoid memory leaks.\n\t\treturn () => {\n\t\t\tlistenFor.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [outerElement?.current])\n\n\t// Return the current size of the element.\n\treturn size\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type {\n\tTimeLeftAll,\n\tTimeLeftRaw,\n\tTimeleftDuration,\n\tUseTimeleftProps,\n} from '@w3ux/types'\nimport { setStateWithRef } from '@w3ux/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { getDuration } from '../util'\n\nexport const useTimeLeft = (props?: UseTimeleftProps) => {\n\tconst depsTimeleft = props?.depsTimeleft || []\n\tconst depsFormat = props?.depsFormat || []\n\n\t// check whether timeleft is within a minute of finishing.\n\tconst inLastHour = () => {\n\t\tconst { days, hours } = getDuration(toRef.current)\n\t\treturn !days && !hours\n\t}\n\n\t// get the amount of seconds left if timeleft is in the last minute.\n\tconst lastMinuteCountdown = () => {\n\t\tconst { seconds } = getDuration(toRef.current)\n\t\tif (!inLastHour()) {\n\t\t\treturn 60\n\t\t}\n\t\treturn seconds\n\t}\n\n\t// calculate resulting timeleft object from latest duration.\n\tconst getTimeleft = (c?: TimeleftDuration): TimeLeftAll => {\n\t\tconst { days, hours, minutes, seconds } = c || getDuration(toRef.current)\n\t\tconst raw: TimeLeftRaw = {\n\t\t\tdays,\n\t\t\thours,\n\t\t\tminutes,\n\t\t}\n\t\tif (!days && !hours) {\n\t\t\traw.seconds = seconds\n\t\t}\n\t\treturn {\n\t\t\traw,\n\t\t}\n\t}\n\n\t// the end time as a date.\n\tconst [to, setTo] = useState<Date | null>(null)\n\tconst toRef = useRef(to)\n\n\t// resulting timeleft object to be returned.\n\tconst [timeleft, setTimeleft] = useState<TimeLeftAll>(getTimeleft())\n\n\t// timeleft refresh intervals.\n\tconst [minInterval, setMinInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst minIntervalRef = useRef(minInterval)\n\n\tconst [secInterval, setSecInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst secIntervalRef = useRef(secInterval)\n\n\t// refresh effects.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t\tif (inLastHour()) {\n\t\t\t// refresh timeleft every second.\n\t\t\tif (!secIntervalRef.current) {\n\t\t\t\tconst interval = setInterval(() => {\n\t\t\t\t\tif (!inLastHour()) {\n\t\t\t\t\t\tclearInterval(secIntervalRef.current)\n\t\t\t\t\t\tsetStateWithRef(undefined, setSecInterval, secIntervalRef)\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t\t}, 1000)\n\n\t\t\t\tsetStateWithRef(interval, setSecInterval, secIntervalRef)\n\t\t\t}\n\t\t}\n\t\t// refresh timeleft every minute.\n\t\telse if (!minIntervalRef.current) {\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (inLastHour()) {\n\t\t\t\t\tclearInterval(minIntervalRef.current)\n\t\t\t\t\tsetStateWithRef(undefined, setMinInterval, minIntervalRef)\n\t\t\t\t}\n\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t}, 60000)\n\t\t\tsetStateWithRef(interval, setMinInterval, minIntervalRef)\n\t\t}\n\t}, [to, inLastHour(), lastMinuteCountdown(), ...depsTimeleft])\n\n\t// re-render the timeleft upon formatting changes.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t}, [...depsFormat])\n\n\t// clear intervals on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tclearInterval(minInterval)\n\t\t\tclearInterval(secInterval)\n\t\t},\n\t\t[],\n\t)\n\n\t// Set the end time and calculate timeleft.\n\tconst setFromNow = (dateFrom: Date, dateTo: Date) => {\n\t\tsetTimeleft(getTimeleft(getDuration(dateFrom)))\n\t\tsetStateWithRef(dateTo, setTo, toRef)\n\t}\n\n\treturn {\n\t\tsetFromNow,\n\t\ttimeleft,\n\t}\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { TimeleftDuration } from '@w3ux/types'\nimport { differenceInDays, getUnixTime, intervalToDuration } from 'date-fns'\nimport { defaultDuration } from './useTimeLeft/defaults.js'\n\n// calculates the current timeleft duration.\nexport const getDuration = (toDate: Date | null): TimeleftDuration => {\n\tif (!toDate) {\n\t\treturn defaultDuration\n\t}\n\tif (getUnixTime(toDate) <= getUnixTime(new Date())) {\n\t\treturn defaultDuration\n\t}\n\n\ttoDate.setSeconds(toDate.getSeconds())\n\tconst d = intervalToDuration({\n\t\tstart: Date.now(),\n\t\tend: toDate,\n\t})\n\n\tconst days = differenceInDays(toDate, Date.now())\n\tconst hours = d?.hours || 0\n\tconst minutes = d?.minutes || 0\n\tconst seconds = d?.seconds || 0\n\tconst lastHour = days === 0 && hours === 0\n\tconst lastMinute = lastHour && minutes === 0\n\n\treturn {\n\t\tdays,\n\t\thours,\n\t\tminutes,\n\t\tseconds,\n\t\tlastMinute,\n\t}\n}\n\n// Helper: Adds `seconds` to the current time and returns the resulting date.\nexport const secondsFromNow = (seconds: number): Date => {\n\tconst end = new Date()\n\tend.setSeconds(end.getSeconds() + seconds)\n\treturn end\n}\n\n// Helper: Calculates the duration between the current time and the provided date.\nexport const getDurationFromNow = (toDate: Date | null): TimeleftDuration => {\n\tif (!toDate) {\n\t\treturn defaultDuration\n\t}\n\tif (getUnixTime(toDate) <= getUnixTime(new Date())) {\n\t\treturn defaultDuration\n\t}\n\n\ttoDate.setSeconds(toDate.getSeconds())\n\tconst d = intervalToDuration({\n\t\tstart: Date.now(),\n\t\tend: toDate,\n\t})\n\n\tconst days = differenceInDays(toDate, Date.now())\n\tconst hours = d?.hours || 0\n\tconst minutes = d?.minutes || 0\n\tconst seconds = d?.seconds || 0\n\tconst lastHour = days === 0 && hours === 0\n\tconst lastMinute = lastHour && minutes === 0\n\n\treturn {\n\t\tdays,\n\t\thours,\n\t\tminutes,\n\t\tseconds,\n\t\tlastMinute,\n\t}\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { TimeleftDuration } from '@w3ux/types'\n\nexport const defaultDuration: TimeleftDuration = {\n\tdays: 0,\n\thours: 0,\n\tminutes: 0,\n\tseconds: 0,\n\tlastMinute: false,\n}\n\nexport const defaultRefreshInterval = 60\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/useAutoFitText.tsx","../src/useEffectIgnoreInitial.tsx","../src/useOnResize.tsx","../src/useOutsideAlerter.tsx","../src/useSafeContext.tsx","../src/useSize.tsx","../src/useTimeLeft/index.tsx","../src/util.ts","../src/useTimeLeft/defaults.ts"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nexport * from './useAutoFitText'\nexport * from './useEffectIgnoreInitial'\nexport * from './useOnResize'\nexport * from './useOutsideAlerter'\nexport * from './useSafeContext'\nexport * from './useSize'\nexport * from './useTimeLeft'\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\nexport interface UseAutoFitTextOptions {\n\tminFontSize?: number\n\tmaxFontSize?: number\n\tunit?: string\n}\n\nexport const useAutoFitText = ({\n\tminFontSize = 0.625,\n\tmaxFontSize = 1.08,\n\tunit = 'rem',\n}: UseAutoFitTextOptions = {}) => {\n\tconst containerRef = useRef<HTMLElement>(null)\n\tconst [fontSize, setFontSize] = useState(`${maxFontSize}${unit}`)\n\n\tconst calculateOptimalFontSize = useCallback(\n\t\t(container: HTMLElement) => {\n\t\t\tconst containerWidth = container.offsetWidth\n\n\t\t\tif (containerWidth === 0) return\n\n\t\t\t// Store original font size to restore after measurement\n\t\t\tconst originalFontSize = container.style.fontSize\n\n\t\t\t// Binary search for the optimal font size\n\t\t\t// scrollWidth gives us the actual width needed for the text content at each font size\n\t\t\tlet low = minFontSize\n\t\t\tlet high = maxFontSize\n\t\t\tlet bestSize = minFontSize\n\n\t\t\t// Use a precision of 0.001 for decimal units like rem\n\t\t\tconst precision = 0.001\n\n\t\t\twhile (high - low > precision) {\n\t\t\t\tconst mid = (low + high) / 2\n\t\t\t\tcontainer.style.fontSize = `${mid}${unit}`\n\n\t\t\t\t// scrollWidth measures the text content width at this font size\n\t\t\t\tconst scrollWidth = container.scrollWidth\n\n\t\t\t\tif (scrollWidth <= containerWidth) {\n\t\t\t\t\tbestSize = mid\n\t\t\t\t\tlow = mid\n\t\t\t\t} else {\n\t\t\t\t\thigh = mid\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Restore original font size before updating state\n\t\t\tcontainer.style.fontSize = originalFontSize\n\n\t\t\t// Only update state if the value actually changed\n\t\t\tconst newFontSize = `${bestSize}${unit}`\n\t\t\tsetFontSize((prev) => (prev === newFontSize ? prev : newFontSize))\n\t\t},\n\t\t[minFontSize, maxFontSize, unit],\n\t)\n\n\tuseEffect(() => {\n\t\tconst container = containerRef.current\n\t\tif (!container) return\n\n\t\t// Debounce timer to prevent excessive recalculations\n\t\tlet debounceTimer: ReturnType<typeof setTimeout> | null = null\n\n\t\tconst debouncedCalculate = () => {\n\t\t\tif (debounceTimer) clearTimeout(debounceTimer)\n\t\t\tdebounceTimer = setTimeout(() => {\n\t\t\t\tcalculateOptimalFontSize(container)\n\t\t\t}, 5)\n\t\t}\n\n\t\t// ResizeObserver handles container size changes (including window resize)\n\t\tconst resizeObserver = new ResizeObserver(debouncedCalculate)\n\n\t\t// Watch for text content changes (e.g., language switches)\n\t\tconst mutationObserver = new MutationObserver(debouncedCalculate)\n\n\t\t// Initial calculation\n\t\tresizeObserver.observe(container)\n\t\tmutationObserver.observe(container, {\n\t\t\tchildList: true,\n\t\t\tsubtree: true,\n\t\t\tcharacterData: true,\n\t\t})\n\n\t\t// Trigger initial calculation after mount\n\t\tcalculateOptimalFontSize(container)\n\n\t\treturn () => {\n\t\t\tif (debounceTimer) clearTimeout(debounceTimer)\n\t\t\tresizeObserver.disconnect()\n\t\t\tmutationObserver.disconnect()\n\t\t}\n\t}, [calculateOptimalFontSize])\n\n\treturn { containerRef, fontSize }\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { useEffect, useRef } from 'react'\n\nexport const useEffectIgnoreInitial = <T, U>(fn: T, deps: U[]) => {\n\tconst isInitial = useRef<boolean>(true)\n\n\tuseEffect(\n\t\t() => {\n\t\t\tif (!isInitial.current) {\n\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\tfn()\n\t\t\t\t}\n\t\t\t}\n\t\t\tisInitial.current = false\n\t\t},\n\t\tdeps ? [...deps] : undefined,\n\t)\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef } from 'react'\n\ninterface UseOnResizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n/**\n * Custom hook that triggers a callback function when the specified element\n * or the window is resized.\n *\n * @param callback - The function to be executed on resize.\n * @param options - Optional parameters to customize the behavior:\n * - outerElement: A ref to an HTMLElement to listen for resize events.\n * - throttle: Optional duration in milliseconds to throttle the callback execution.\n * Default is 100 milliseconds.\n */\nexport const useOnResize = (\n\tcallback: () => void,\n\toptions: UseOnResizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// Throttled resize handler to limit the frequency of callback execution.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\n\t\t// Check if the callback can be executed based on the throttle duration.\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t}\n\n\t\tlastExecutedRef.current = now\n\t\tcallback()\n\t}\n\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\tconst target = outerElement?.current || window\n\n\t\t// Add the resize event listener when the component mounts.\n\t\ttarget.addEventListener('resize', handleResize)\n\n\t\t// Clean up the event listener when the component unmounts.\n\t\treturn () => {\n\t\t\ttarget.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [throttleDuration, callback])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { type RefObject, useEffect } from 'react'\n\n// A hook that alerts clicks outside of the passed ref.\nexport const useOutsideAlerter = (\n\tref: RefObject<HTMLElement | null>,\n\tcallback: () => void,\n\tignore: string[] = [],\n) => {\n\tuseEffect(() => {\n\t\tconst handleClickOutside = (ev: MouseEvent) => {\n\t\t\tif (ev) {\n\t\t\t\tif (ref.current && !ref.current.contains(ev.target as Node)) {\n\t\t\t\t\tconst target = ev.target as HTMLElement\n\t\t\t\t\t// Ignore tags with a name of `ignore`, or if there is a class of `ignore` in the parent\n\t\t\t\t\t// tree.\n\t\t\t\t\tconst tagName = target.tagName.toLowerCase()\n\t\t\t\t\tconst ignored = ignore.some(\n\t\t\t\t\t\t(i) =>\n\t\t\t\t\t\t\ti.toLowerCase() === tagName || target.closest(`.${i}`) !== null,\n\t\t\t\t\t)\n\n\t\t\t\t\tif (!ignored) {\n\t\t\t\t\t\tcallback()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('mousedown', handleClickOutside)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('mousedown', handleClickOutside)\n\t\t}\n\t}, [ref])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { Context } from 'react'\nimport { createContext, useContext } from 'react'\n\nexport const useSafeContext = <T,>(ctx: T | null | undefined): T => {\n\tif (ctx === null || ctx === undefined) {\n\t\tthrow new Error(\n\t\t\t'Context value is null or undefined. Please ensure the context Provider is used correctly.',\n\t\t)\n\t}\n\treturn ctx\n}\n\nexport const createSafeContext = <T,>(): [Context<T | null>, () => T] => {\n\tconst Context = createContext<T | null>(null)\n\tconst useHook = () => useSafeContext<T>(useContext(Context))\n\treturn [Context, useHook]\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef, useState } from 'react'\n\n// Define the type for the options parameter.\ninterface UseSizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n// Custom hook to get the width and height of a specified element. Updates the `size` state when the\n// specified \"outer element\" (or the window by default) resizes.\nexport const useSize = (\n\telement: RefObject<HTMLElement | null>,\n\toptions: UseSizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\n\t// Helper function to retrieve the width and height of an element\n\t// If no element is found, default dimensions are set to 0.\n\tconst getSize = (el: HTMLElement | null = null) => {\n\t\tconst width = el?.offsetWidth || 0\n\t\tconst height = el?.offsetHeight || 0\n\t\treturn { width, height }\n\t}\n\n\t// Ref to store the last execution time of the `resizeThrottle` handler.\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// State to store the current width and height of the specified element.\n\tconst [size, setSize] = useState<{ width: number; height: number }>(\n\t\tgetSize(element?.current),\n\t)\n\n\t// Throttle the resize event handler to limit how often size updates occur.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t} // Exit if `throttleDuration` has not passed.\n\n\t\tlastExecutedRef.current = now // Update last execution time.\n\n\t\tsetSize(getSize(element?.current))\n\t}\n\n\t// Set up the resize event listener on mount and clean it up on unmount.\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\t// If `outerElement` is provided, listen to its resize events; otherwise, listen to the window's.\n\t\tconst listenFor = outerElement?.current || window\n\n\t\tlistenFor.addEventListener('resize', handleResize)\n\n\t\t// Clean up event listener when the component unmounts to avoid memory leaks.\n\t\treturn () => {\n\t\t\tlistenFor.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [outerElement?.current])\n\n\t// Return the current size of the element.\n\treturn size\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type {\n\tTimeLeftAll,\n\tTimeLeftRaw,\n\tTimeleftDuration,\n\tUseTimeleftProps,\n} from '@w3ux/types'\nimport { setStateWithRef } from '@w3ux/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { getDuration } from '../util'\n\nexport const useTimeLeft = (props?: UseTimeleftProps) => {\n\tconst depsTimeleft = props?.depsTimeleft || []\n\tconst depsFormat = props?.depsFormat || []\n\n\t// check whether timeleft is within a minute of finishing.\n\tconst inLastHour = () => {\n\t\tconst { days, hours } = getDuration(toRef.current)\n\t\treturn !days && !hours\n\t}\n\n\t// get the amount of seconds left if timeleft is in the last minute.\n\tconst lastMinuteCountdown = () => {\n\t\tconst { seconds } = getDuration(toRef.current)\n\t\tif (!inLastHour()) {\n\t\t\treturn 60\n\t\t}\n\t\treturn seconds\n\t}\n\n\t// calculate resulting timeleft object from latest duration.\n\tconst getTimeleft = (c?: TimeleftDuration): TimeLeftAll => {\n\t\tconst { days, hours, minutes, seconds } = c || getDuration(toRef.current)\n\t\tconst raw: TimeLeftRaw = {\n\t\t\tdays,\n\t\t\thours,\n\t\t\tminutes,\n\t\t}\n\t\tif (!days && !hours) {\n\t\t\traw.seconds = seconds\n\t\t}\n\t\treturn {\n\t\t\traw,\n\t\t}\n\t}\n\n\t// the end time as a date.\n\tconst [to, setTo] = useState<Date | null>(null)\n\tconst toRef = useRef(to)\n\n\t// resulting timeleft object to be returned.\n\tconst [timeleft, setTimeleft] = useState<TimeLeftAll>(getTimeleft())\n\n\t// timeleft refresh intervals.\n\tconst [minInterval, setMinInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst minIntervalRef = useRef(minInterval)\n\n\tconst [secInterval, setSecInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst secIntervalRef = useRef(secInterval)\n\n\t// refresh effects.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t\tif (inLastHour()) {\n\t\t\t// refresh timeleft every second.\n\t\t\tif (!secIntervalRef.current) {\n\t\t\t\tconst interval = setInterval(() => {\n\t\t\t\t\tif (!inLastHour()) {\n\t\t\t\t\t\tclearInterval(secIntervalRef.current)\n\t\t\t\t\t\tsetStateWithRef(undefined, setSecInterval, secIntervalRef)\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t\t}, 1000)\n\n\t\t\t\tsetStateWithRef(interval, setSecInterval, secIntervalRef)\n\t\t\t}\n\t\t}\n\t\t// refresh timeleft every minute.\n\t\telse if (!minIntervalRef.current) {\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (inLastHour()) {\n\t\t\t\t\tclearInterval(minIntervalRef.current)\n\t\t\t\t\tsetStateWithRef(undefined, setMinInterval, minIntervalRef)\n\t\t\t\t}\n\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t}, 60000)\n\t\t\tsetStateWithRef(interval, setMinInterval, minIntervalRef)\n\t\t}\n\t}, [to, inLastHour(), lastMinuteCountdown(), ...depsTimeleft])\n\n\t// re-render the timeleft upon formatting changes.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t}, [...depsFormat])\n\n\t// clear intervals on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tclearInterval(minInterval)\n\t\t\tclearInterval(secInterval)\n\t\t},\n\t\t[],\n\t)\n\n\t// Set the end time and calculate timeleft.\n\tconst setFromNow = (dateFrom: Date, dateTo: Date) => {\n\t\tsetTimeleft(getTimeleft(getDuration(dateFrom)))\n\t\tsetStateWithRef(dateTo, setTo, toRef)\n\t}\n\n\treturn {\n\t\tsetFromNow,\n\t\ttimeleft,\n\t}\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { TimeleftDuration } from '@w3ux/types'\nimport { differenceInDays, getUnixTime, intervalToDuration } from 'date-fns'\nimport { defaultDuration } from './useTimeLeft/defaults.js'\n\n// calculates the current timeleft duration.\nexport const getDuration = (toDate: Date | null): TimeleftDuration => {\n\tif (!toDate) {\n\t\treturn defaultDuration\n\t}\n\tif (getUnixTime(toDate) <= getUnixTime(new Date())) {\n\t\treturn defaultDuration\n\t}\n\n\ttoDate.setSeconds(toDate.getSeconds())\n\tconst d = intervalToDuration({\n\t\tstart: Date.now(),\n\t\tend: toDate,\n\t})\n\n\tconst days = differenceInDays(toDate, Date.now())\n\tconst hours = d?.hours || 0\n\tconst minutes = d?.minutes || 0\n\tconst seconds = d?.seconds || 0\n\tconst lastHour = days === 0 && hours === 0\n\tconst lastMinute = lastHour && minutes === 0\n\n\treturn {\n\t\tdays,\n\t\thours,\n\t\tminutes,\n\t\tseconds,\n\t\tlastMinute,\n\t}\n}\n\n// Helper: Adds `seconds` to the current time and returns the resulting date.\nexport const secondsFromNow = (seconds: number): Date => {\n\tconst end = new Date()\n\tend.setSeconds(end.getSeconds() + seconds)\n\treturn end\n}\n\n// Helper: Calculates the duration between the current time and the provided date.\nexport const getDurationFromNow = (toDate: Date | null): TimeleftDuration => {\n\tif (!toDate) {\n\t\treturn defaultDuration\n\t}\n\tif (getUnixTime(toDate) <= getUnixTime(new Date())) {\n\t\treturn defaultDuration\n\t}\n\n\ttoDate.setSeconds(toDate.getSeconds())\n\tconst d = intervalToDuration({\n\t\tstart: Date.now(),\n\t\tend: toDate,\n\t})\n\n\tconst days = differenceInDays(toDate, Date.now())\n\tconst hours = d?.hours || 0\n\tconst minutes = d?.minutes || 0\n\tconst seconds = d?.seconds || 0\n\tconst lastHour = days === 0 && hours === 0\n\tconst lastMinute = lastHour && minutes === 0\n\n\treturn {\n\t\tdays,\n\t\thours,\n\t\tminutes,\n\t\tseconds,\n\t\tlastMinute,\n\t}\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { TimeleftDuration } from '@w3ux/types'\n\nexport const defaultDuration: TimeleftDuration = {\n\tdays: 0,\n\thours: 0,\n\tminutes: 0,\n\tseconds: 0,\n\tlastMinute: false,\n}\n\nexport const defaultRefreshInterval = 60\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","import_react","import_react"]}
|
package/index.d.cts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
1
2
|
import { RefObject, Context } from 'react';
|
|
2
3
|
import { UseTimeleftProps, TimeLeftAll } from '@w3ux/types';
|
|
3
4
|
|
|
5
|
+
interface UseAutoFitTextOptions {
|
|
6
|
+
minFontSize?: number;
|
|
7
|
+
maxFontSize?: number;
|
|
8
|
+
unit?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const useAutoFitText: ({ minFontSize, maxFontSize, unit, }?: UseAutoFitTextOptions) => {
|
|
11
|
+
containerRef: react.RefObject<HTMLElement | null>;
|
|
12
|
+
fontSize: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
4
15
|
declare const useEffectIgnoreInitial: <T, U>(fn: T, deps: U[]) => void;
|
|
5
16
|
|
|
6
17
|
interface UseOnResizeOptions {
|
|
@@ -38,4 +49,4 @@ declare const useTimeLeft: (props?: UseTimeleftProps) => {
|
|
|
38
49
|
timeleft: TimeLeftAll;
|
|
39
50
|
};
|
|
40
51
|
|
|
41
|
-
export { createSafeContext, useEffectIgnoreInitial, useOnResize, useOutsideAlerter, useSafeContext, useSize, useTimeLeft };
|
|
52
|
+
export { type UseAutoFitTextOptions, createSafeContext, useAutoFitText, useEffectIgnoreInitial, useOnResize, useOutsideAlerter, useSafeContext, useSize, useTimeLeft };
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
1
2
|
import { RefObject, Context } from 'react';
|
|
2
3
|
import { UseTimeleftProps, TimeLeftAll } from '@w3ux/types';
|
|
3
4
|
|
|
5
|
+
interface UseAutoFitTextOptions {
|
|
6
|
+
minFontSize?: number;
|
|
7
|
+
maxFontSize?: number;
|
|
8
|
+
unit?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const useAutoFitText: ({ minFontSize, maxFontSize, unit, }?: UseAutoFitTextOptions) => {
|
|
11
|
+
containerRef: react.RefObject<HTMLElement | null>;
|
|
12
|
+
fontSize: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
4
15
|
declare const useEffectIgnoreInitial: <T, U>(fn: T, deps: U[]) => void;
|
|
5
16
|
|
|
6
17
|
interface UseOnResizeOptions {
|
|
@@ -38,4 +49,4 @@ declare const useTimeLeft: (props?: UseTimeleftProps) => {
|
|
|
38
49
|
timeleft: TimeLeftAll;
|
|
39
50
|
};
|
|
40
51
|
|
|
41
|
-
export { createSafeContext, useEffectIgnoreInitial, useOnResize, useOutsideAlerter, useSafeContext, useSize, useTimeLeft };
|
|
52
|
+
export { type UseAutoFitTextOptions, createSafeContext, useAutoFitText, useEffectIgnoreInitial, useOnResize, useOutsideAlerter, useSafeContext, useSize, useTimeLeft };
|
package/index.js
CHANGED
|
@@ -2,11 +2,74 @@ import {
|
|
|
2
2
|
getDuration
|
|
3
3
|
} from "./chunk-I2A6YRXU.js";
|
|
4
4
|
|
|
5
|
+
// src/useAutoFitText.tsx
|
|
6
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
7
|
+
var useAutoFitText = ({
|
|
8
|
+
minFontSize = 0.625,
|
|
9
|
+
maxFontSize = 1.08,
|
|
10
|
+
unit = "rem"
|
|
11
|
+
} = {}) => {
|
|
12
|
+
const containerRef = useRef(null);
|
|
13
|
+
const [fontSize, setFontSize] = useState(`${maxFontSize}${unit}`);
|
|
14
|
+
const calculateOptimalFontSize = useCallback(
|
|
15
|
+
(container) => {
|
|
16
|
+
const containerWidth = container.offsetWidth;
|
|
17
|
+
if (containerWidth === 0) return;
|
|
18
|
+
const originalFontSize = container.style.fontSize;
|
|
19
|
+
let low = minFontSize;
|
|
20
|
+
let high = maxFontSize;
|
|
21
|
+
let bestSize = minFontSize;
|
|
22
|
+
const precision = 1e-3;
|
|
23
|
+
while (high - low > precision) {
|
|
24
|
+
const mid = (low + high) / 2;
|
|
25
|
+
container.style.fontSize = `${mid}${unit}`;
|
|
26
|
+
const scrollWidth = container.scrollWidth;
|
|
27
|
+
if (scrollWidth <= containerWidth) {
|
|
28
|
+
bestSize = mid;
|
|
29
|
+
low = mid;
|
|
30
|
+
} else {
|
|
31
|
+
high = mid;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
container.style.fontSize = originalFontSize;
|
|
35
|
+
const newFontSize = `${bestSize}${unit}`;
|
|
36
|
+
setFontSize((prev) => prev === newFontSize ? prev : newFontSize);
|
|
37
|
+
},
|
|
38
|
+
[minFontSize, maxFontSize, unit]
|
|
39
|
+
);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const container = containerRef.current;
|
|
42
|
+
if (!container) return;
|
|
43
|
+
let debounceTimer = null;
|
|
44
|
+
const debouncedCalculate = () => {
|
|
45
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
46
|
+
debounceTimer = setTimeout(() => {
|
|
47
|
+
calculateOptimalFontSize(container);
|
|
48
|
+
}, 5);
|
|
49
|
+
};
|
|
50
|
+
const resizeObserver = new ResizeObserver(debouncedCalculate);
|
|
51
|
+
const mutationObserver = new MutationObserver(debouncedCalculate);
|
|
52
|
+
resizeObserver.observe(container);
|
|
53
|
+
mutationObserver.observe(container, {
|
|
54
|
+
childList: true,
|
|
55
|
+
subtree: true,
|
|
56
|
+
characterData: true
|
|
57
|
+
});
|
|
58
|
+
calculateOptimalFontSize(container);
|
|
59
|
+
return () => {
|
|
60
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
61
|
+
resizeObserver.disconnect();
|
|
62
|
+
mutationObserver.disconnect();
|
|
63
|
+
};
|
|
64
|
+
}, [calculateOptimalFontSize]);
|
|
65
|
+
return { containerRef, fontSize };
|
|
66
|
+
};
|
|
67
|
+
|
|
5
68
|
// src/useEffectIgnoreInitial.tsx
|
|
6
|
-
import { useEffect, useRef } from "react";
|
|
69
|
+
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
7
70
|
var useEffectIgnoreInitial = (fn, deps) => {
|
|
8
|
-
const isInitial =
|
|
9
|
-
|
|
71
|
+
const isInitial = useRef2(true);
|
|
72
|
+
useEffect2(
|
|
10
73
|
() => {
|
|
11
74
|
if (!isInitial.current) {
|
|
12
75
|
if (typeof fn === "function") {
|
|
@@ -20,10 +83,10 @@ var useEffectIgnoreInitial = (fn, deps) => {
|
|
|
20
83
|
};
|
|
21
84
|
|
|
22
85
|
// src/useOnResize.tsx
|
|
23
|
-
import { useEffect as
|
|
86
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
24
87
|
var useOnResize = (callback, options = {}) => {
|
|
25
88
|
const { outerElement, throttle: throttleDuration = 100 } = options;
|
|
26
|
-
const lastExecutedRef =
|
|
89
|
+
const lastExecutedRef = useRef3(0);
|
|
27
90
|
const handleResize = () => {
|
|
28
91
|
const now = Date.now();
|
|
29
92
|
if (now - lastExecutedRef.current < throttleDuration) {
|
|
@@ -32,7 +95,7 @@ var useOnResize = (callback, options = {}) => {
|
|
|
32
95
|
lastExecutedRef.current = now;
|
|
33
96
|
callback();
|
|
34
97
|
};
|
|
35
|
-
|
|
98
|
+
useEffect3(() => {
|
|
36
99
|
const target = outerElement?.current || window;
|
|
37
100
|
target.addEventListener("resize", handleResize);
|
|
38
101
|
return () => {
|
|
@@ -42,9 +105,9 @@ var useOnResize = (callback, options = {}) => {
|
|
|
42
105
|
};
|
|
43
106
|
|
|
44
107
|
// src/useOutsideAlerter.tsx
|
|
45
|
-
import { useEffect as
|
|
108
|
+
import { useEffect as useEffect4 } from "react";
|
|
46
109
|
var useOutsideAlerter = (ref, callback, ignore = []) => {
|
|
47
|
-
|
|
110
|
+
useEffect4(() => {
|
|
48
111
|
const handleClickOutside = (ev) => {
|
|
49
112
|
if (ev) {
|
|
50
113
|
if (ref.current && !ref.current.contains(ev.target)) {
|
|
@@ -83,7 +146,7 @@ var createSafeContext = () => {
|
|
|
83
146
|
};
|
|
84
147
|
|
|
85
148
|
// src/useSize.tsx
|
|
86
|
-
import { useEffect as
|
|
149
|
+
import { useEffect as useEffect5, useRef as useRef4, useState as useState2 } from "react";
|
|
87
150
|
var useSize = (element, options = {}) => {
|
|
88
151
|
const { outerElement, throttle: throttleDuration = 100 } = options;
|
|
89
152
|
const getSize = (el = null) => {
|
|
@@ -91,8 +154,8 @@ var useSize = (element, options = {}) => {
|
|
|
91
154
|
const height = el?.offsetHeight || 0;
|
|
92
155
|
return { width, height };
|
|
93
156
|
};
|
|
94
|
-
const lastExecutedRef =
|
|
95
|
-
const [size, setSize] =
|
|
157
|
+
const lastExecutedRef = useRef4(0);
|
|
158
|
+
const [size, setSize] = useState2(
|
|
96
159
|
getSize(element?.current)
|
|
97
160
|
);
|
|
98
161
|
const handleResize = () => {
|
|
@@ -103,7 +166,7 @@ var useSize = (element, options = {}) => {
|
|
|
103
166
|
lastExecutedRef.current = now;
|
|
104
167
|
setSize(getSize(element?.current));
|
|
105
168
|
};
|
|
106
|
-
|
|
169
|
+
useEffect5(() => {
|
|
107
170
|
const listenFor = outerElement?.current || window;
|
|
108
171
|
listenFor.addEventListener("resize", handleResize);
|
|
109
172
|
return () => {
|
|
@@ -115,7 +178,7 @@ var useSize = (element, options = {}) => {
|
|
|
115
178
|
|
|
116
179
|
// src/useTimeLeft/index.tsx
|
|
117
180
|
import { setStateWithRef } from "@w3ux/utils";
|
|
118
|
-
import { useEffect as
|
|
181
|
+
import { useEffect as useEffect6, useRef as useRef5, useState as useState3 } from "react";
|
|
119
182
|
var useTimeLeft = (props) => {
|
|
120
183
|
const depsTimeleft = props?.depsTimeleft || [];
|
|
121
184
|
const depsFormat = props?.depsFormat || [];
|
|
@@ -144,14 +207,14 @@ var useTimeLeft = (props) => {
|
|
|
144
207
|
raw
|
|
145
208
|
};
|
|
146
209
|
};
|
|
147
|
-
const [to, setTo] =
|
|
148
|
-
const toRef =
|
|
149
|
-
const [timeleft, setTimeleft] =
|
|
150
|
-
const [minInterval, setMinInterval] =
|
|
151
|
-
const minIntervalRef =
|
|
152
|
-
const [secInterval, setSecInterval] =
|
|
153
|
-
const secIntervalRef =
|
|
154
|
-
|
|
210
|
+
const [to, setTo] = useState3(null);
|
|
211
|
+
const toRef = useRef5(to);
|
|
212
|
+
const [timeleft, setTimeleft] = useState3(getTimeleft());
|
|
213
|
+
const [minInterval, setMinInterval] = useState3(void 0);
|
|
214
|
+
const minIntervalRef = useRef5(minInterval);
|
|
215
|
+
const [secInterval, setSecInterval] = useState3(void 0);
|
|
216
|
+
const secIntervalRef = useRef5(secInterval);
|
|
217
|
+
useEffect6(() => {
|
|
155
218
|
setTimeleft(getTimeleft());
|
|
156
219
|
if (inLastHour()) {
|
|
157
220
|
if (!secIntervalRef.current) {
|
|
@@ -175,10 +238,10 @@ var useTimeLeft = (props) => {
|
|
|
175
238
|
setStateWithRef(interval, setMinInterval, minIntervalRef);
|
|
176
239
|
}
|
|
177
240
|
}, [to, inLastHour(), lastMinuteCountdown(), ...depsTimeleft]);
|
|
178
|
-
|
|
241
|
+
useEffect6(() => {
|
|
179
242
|
setTimeleft(getTimeleft());
|
|
180
243
|
}, [...depsFormat]);
|
|
181
|
-
|
|
244
|
+
useEffect6(
|
|
182
245
|
() => () => {
|
|
183
246
|
clearInterval(minInterval);
|
|
184
247
|
clearInterval(secInterval);
|
|
@@ -196,6 +259,7 @@ var useTimeLeft = (props) => {
|
|
|
196
259
|
};
|
|
197
260
|
export {
|
|
198
261
|
createSafeContext,
|
|
262
|
+
useAutoFitText,
|
|
199
263
|
useEffectIgnoreInitial,
|
|
200
264
|
useOnResize,
|
|
201
265
|
useOutsideAlerter,
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useEffectIgnoreInitial.tsx","../src/useOnResize.tsx","../src/useOutsideAlerter.tsx","../src/useSafeContext.tsx","../src/useSize.tsx","../src/useTimeLeft/index.tsx"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { useEffect, useRef } from 'react'\n\nexport const useEffectIgnoreInitial = <T, U>(fn: T, deps: U[]) => {\n\tconst isInitial = useRef<boolean>(true)\n\n\tuseEffect(\n\t\t() => {\n\t\t\tif (!isInitial.current) {\n\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\tfn()\n\t\t\t\t}\n\t\t\t}\n\t\t\tisInitial.current = false\n\t\t},\n\t\tdeps ? [...deps] : undefined,\n\t)\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef } from 'react'\n\ninterface UseOnResizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n/**\n * Custom hook that triggers a callback function when the specified element\n * or the window is resized.\n *\n * @param callback - The function to be executed on resize.\n * @param options - Optional parameters to customize the behavior:\n * - outerElement: A ref to an HTMLElement to listen for resize events.\n * - throttle: Optional duration in milliseconds to throttle the callback execution.\n * Default is 100 milliseconds.\n */\nexport const useOnResize = (\n\tcallback: () => void,\n\toptions: UseOnResizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// Throttled resize handler to limit the frequency of callback execution.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\n\t\t// Check if the callback can be executed based on the throttle duration.\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t}\n\n\t\tlastExecutedRef.current = now\n\t\tcallback()\n\t}\n\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\tconst target = outerElement?.current || window\n\n\t\t// Add the resize event listener when the component mounts.\n\t\ttarget.addEventListener('resize', handleResize)\n\n\t\t// Clean up the event listener when the component unmounts.\n\t\treturn () => {\n\t\t\ttarget.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [throttleDuration, callback])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { type RefObject, useEffect } from 'react'\n\n// A hook that alerts clicks outside of the passed ref.\nexport const useOutsideAlerter = (\n\tref: RefObject<HTMLElement | null>,\n\tcallback: () => void,\n\tignore: string[] = [],\n) => {\n\tuseEffect(() => {\n\t\tconst handleClickOutside = (ev: MouseEvent) => {\n\t\t\tif (ev) {\n\t\t\t\tif (ref.current && !ref.current.contains(ev.target as Node)) {\n\t\t\t\t\tconst target = ev.target as HTMLElement\n\t\t\t\t\t// Ignore tags with a name of `ignore`, or if there is a class of `ignore` in the parent\n\t\t\t\t\t// tree.\n\t\t\t\t\tconst tagName = target.tagName.toLowerCase()\n\t\t\t\t\tconst ignored = ignore.some(\n\t\t\t\t\t\t(i) =>\n\t\t\t\t\t\t\ti.toLowerCase() === tagName || target.closest(`.${i}`) !== null,\n\t\t\t\t\t)\n\n\t\t\t\t\tif (!ignored) {\n\t\t\t\t\t\tcallback()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('mousedown', handleClickOutside)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('mousedown', handleClickOutside)\n\t\t}\n\t}, [ref])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { Context } from 'react'\nimport { createContext, useContext } from 'react'\n\nexport const useSafeContext = <T,>(ctx: T | null | undefined): T => {\n\tif (ctx === null || ctx === undefined) {\n\t\tthrow new Error(\n\t\t\t'Context value is null or undefined. Please ensure the context Provider is used correctly.',\n\t\t)\n\t}\n\treturn ctx\n}\n\nexport const createSafeContext = <T,>(): [Context<T | null>, () => T] => {\n\tconst Context = createContext<T | null>(null)\n\tconst useHook = () => useSafeContext<T>(useContext(Context))\n\treturn [Context, useHook]\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef, useState } from 'react'\n\n// Define the type for the options parameter.\ninterface UseSizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n// Custom hook to get the width and height of a specified element. Updates the `size` state when the\n// specified \"outer element\" (or the window by default) resizes.\nexport const useSize = (\n\telement: RefObject<HTMLElement | null>,\n\toptions: UseSizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\n\t// Helper function to retrieve the width and height of an element\n\t// If no element is found, default dimensions are set to 0.\n\tconst getSize = (el: HTMLElement | null = null) => {\n\t\tconst width = el?.offsetWidth || 0\n\t\tconst height = el?.offsetHeight || 0\n\t\treturn { width, height }\n\t}\n\n\t// Ref to store the last execution time of the `resizeThrottle` handler.\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// State to store the current width and height of the specified element.\n\tconst [size, setSize] = useState<{ width: number; height: number }>(\n\t\tgetSize(element?.current),\n\t)\n\n\t// Throttle the resize event handler to limit how often size updates occur.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t} // Exit if `throttleDuration` has not passed.\n\n\t\tlastExecutedRef.current = now // Update last execution time.\n\n\t\tsetSize(getSize(element?.current))\n\t}\n\n\t// Set up the resize event listener on mount and clean it up on unmount.\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\t// If `outerElement` is provided, listen to its resize events; otherwise, listen to the window's.\n\t\tconst listenFor = outerElement?.current || window\n\n\t\tlistenFor.addEventListener('resize', handleResize)\n\n\t\t// Clean up event listener when the component unmounts to avoid memory leaks.\n\t\treturn () => {\n\t\t\tlistenFor.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [outerElement?.current])\n\n\t// Return the current size of the element.\n\treturn size\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type {\n\tTimeLeftAll,\n\tTimeLeftRaw,\n\tTimeleftDuration,\n\tUseTimeleftProps,\n} from '@w3ux/types'\nimport { setStateWithRef } from '@w3ux/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { getDuration } from '../util'\n\nexport const useTimeLeft = (props?: UseTimeleftProps) => {\n\tconst depsTimeleft = props?.depsTimeleft || []\n\tconst depsFormat = props?.depsFormat || []\n\n\t// check whether timeleft is within a minute of finishing.\n\tconst inLastHour = () => {\n\t\tconst { days, hours } = getDuration(toRef.current)\n\t\treturn !days && !hours\n\t}\n\n\t// get the amount of seconds left if timeleft is in the last minute.\n\tconst lastMinuteCountdown = () => {\n\t\tconst { seconds } = getDuration(toRef.current)\n\t\tif (!inLastHour()) {\n\t\t\treturn 60\n\t\t}\n\t\treturn seconds\n\t}\n\n\t// calculate resulting timeleft object from latest duration.\n\tconst getTimeleft = (c?: TimeleftDuration): TimeLeftAll => {\n\t\tconst { days, hours, minutes, seconds } = c || getDuration(toRef.current)\n\t\tconst raw: TimeLeftRaw = {\n\t\t\tdays,\n\t\t\thours,\n\t\t\tminutes,\n\t\t}\n\t\tif (!days && !hours) {\n\t\t\traw.seconds = seconds\n\t\t}\n\t\treturn {\n\t\t\traw,\n\t\t}\n\t}\n\n\t// the end time as a date.\n\tconst [to, setTo] = useState<Date | null>(null)\n\tconst toRef = useRef(to)\n\n\t// resulting timeleft object to be returned.\n\tconst [timeleft, setTimeleft] = useState<TimeLeftAll>(getTimeleft())\n\n\t// timeleft refresh intervals.\n\tconst [minInterval, setMinInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst minIntervalRef = useRef(minInterval)\n\n\tconst [secInterval, setSecInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst secIntervalRef = useRef(secInterval)\n\n\t// refresh effects.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t\tif (inLastHour()) {\n\t\t\t// refresh timeleft every second.\n\t\t\tif (!secIntervalRef.current) {\n\t\t\t\tconst interval = setInterval(() => {\n\t\t\t\t\tif (!inLastHour()) {\n\t\t\t\t\t\tclearInterval(secIntervalRef.current)\n\t\t\t\t\t\tsetStateWithRef(undefined, setSecInterval, secIntervalRef)\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t\t}, 1000)\n\n\t\t\t\tsetStateWithRef(interval, setSecInterval, secIntervalRef)\n\t\t\t}\n\t\t}\n\t\t// refresh timeleft every minute.\n\t\telse if (!minIntervalRef.current) {\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (inLastHour()) {\n\t\t\t\t\tclearInterval(minIntervalRef.current)\n\t\t\t\t\tsetStateWithRef(undefined, setMinInterval, minIntervalRef)\n\t\t\t\t}\n\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t}, 60000)\n\t\t\tsetStateWithRef(interval, setMinInterval, minIntervalRef)\n\t\t}\n\t}, [to, inLastHour(), lastMinuteCountdown(), ...depsTimeleft])\n\n\t// re-render the timeleft upon formatting changes.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t}, [...depsFormat])\n\n\t// clear intervals on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tclearInterval(minInterval)\n\t\t\tclearInterval(secInterval)\n\t\t},\n\t\t[],\n\t)\n\n\t// Set the end time and calculate timeleft.\n\tconst setFromNow = (dateFrom: Date, dateTo: Date) => {\n\t\tsetTimeleft(getTimeleft(getDuration(dateFrom)))\n\t\tsetStateWithRef(dateTo, setTo, toRef)\n\t}\n\n\treturn {\n\t\tsetFromNow,\n\t\ttimeleft,\n\t}\n}\n"],"mappings":"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","names":["useEffect","useRef","useEffect","useEffect","useRef","useEffect","useRef","useState","useState","useRef","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/useAutoFitText.tsx","../src/useEffectIgnoreInitial.tsx","../src/useOnResize.tsx","../src/useOutsideAlerter.tsx","../src/useSafeContext.tsx","../src/useSize.tsx","../src/useTimeLeft/index.tsx"],"sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\nexport interface UseAutoFitTextOptions {\n\tminFontSize?: number\n\tmaxFontSize?: number\n\tunit?: string\n}\n\nexport const useAutoFitText = ({\n\tminFontSize = 0.625,\n\tmaxFontSize = 1.08,\n\tunit = 'rem',\n}: UseAutoFitTextOptions = {}) => {\n\tconst containerRef = useRef<HTMLElement>(null)\n\tconst [fontSize, setFontSize] = useState(`${maxFontSize}${unit}`)\n\n\tconst calculateOptimalFontSize = useCallback(\n\t\t(container: HTMLElement) => {\n\t\t\tconst containerWidth = container.offsetWidth\n\n\t\t\tif (containerWidth === 0) return\n\n\t\t\t// Store original font size to restore after measurement\n\t\t\tconst originalFontSize = container.style.fontSize\n\n\t\t\t// Binary search for the optimal font size\n\t\t\t// scrollWidth gives us the actual width needed for the text content at each font size\n\t\t\tlet low = minFontSize\n\t\t\tlet high = maxFontSize\n\t\t\tlet bestSize = minFontSize\n\n\t\t\t// Use a precision of 0.001 for decimal units like rem\n\t\t\tconst precision = 0.001\n\n\t\t\twhile (high - low > precision) {\n\t\t\t\tconst mid = (low + high) / 2\n\t\t\t\tcontainer.style.fontSize = `${mid}${unit}`\n\n\t\t\t\t// scrollWidth measures the text content width at this font size\n\t\t\t\tconst scrollWidth = container.scrollWidth\n\n\t\t\t\tif (scrollWidth <= containerWidth) {\n\t\t\t\t\tbestSize = mid\n\t\t\t\t\tlow = mid\n\t\t\t\t} else {\n\t\t\t\t\thigh = mid\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Restore original font size before updating state\n\t\t\tcontainer.style.fontSize = originalFontSize\n\n\t\t\t// Only update state if the value actually changed\n\t\t\tconst newFontSize = `${bestSize}${unit}`\n\t\t\tsetFontSize((prev) => (prev === newFontSize ? prev : newFontSize))\n\t\t},\n\t\t[minFontSize, maxFontSize, unit],\n\t)\n\n\tuseEffect(() => {\n\t\tconst container = containerRef.current\n\t\tif (!container) return\n\n\t\t// Debounce timer to prevent excessive recalculations\n\t\tlet debounceTimer: ReturnType<typeof setTimeout> | null = null\n\n\t\tconst debouncedCalculate = () => {\n\t\t\tif (debounceTimer) clearTimeout(debounceTimer)\n\t\t\tdebounceTimer = setTimeout(() => {\n\t\t\t\tcalculateOptimalFontSize(container)\n\t\t\t}, 5)\n\t\t}\n\n\t\t// ResizeObserver handles container size changes (including window resize)\n\t\tconst resizeObserver = new ResizeObserver(debouncedCalculate)\n\n\t\t// Watch for text content changes (e.g., language switches)\n\t\tconst mutationObserver = new MutationObserver(debouncedCalculate)\n\n\t\t// Initial calculation\n\t\tresizeObserver.observe(container)\n\t\tmutationObserver.observe(container, {\n\t\t\tchildList: true,\n\t\t\tsubtree: true,\n\t\t\tcharacterData: true,\n\t\t})\n\n\t\t// Trigger initial calculation after mount\n\t\tcalculateOptimalFontSize(container)\n\n\t\treturn () => {\n\t\t\tif (debounceTimer) clearTimeout(debounceTimer)\n\t\t\tresizeObserver.disconnect()\n\t\t\tmutationObserver.disconnect()\n\t\t}\n\t}, [calculateOptimalFontSize])\n\n\treturn { containerRef, fontSize }\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { useEffect, useRef } from 'react'\n\nexport const useEffectIgnoreInitial = <T, U>(fn: T, deps: U[]) => {\n\tconst isInitial = useRef<boolean>(true)\n\n\tuseEffect(\n\t\t() => {\n\t\t\tif (!isInitial.current) {\n\t\t\t\tif (typeof fn === 'function') {\n\t\t\t\t\tfn()\n\t\t\t\t}\n\t\t\t}\n\t\t\tisInitial.current = false\n\t\t},\n\t\tdeps ? [...deps] : undefined,\n\t)\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef } from 'react'\n\ninterface UseOnResizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n/**\n * Custom hook that triggers a callback function when the specified element\n * or the window is resized.\n *\n * @param callback - The function to be executed on resize.\n * @param options - Optional parameters to customize the behavior:\n * - outerElement: A ref to an HTMLElement to listen for resize events.\n * - throttle: Optional duration in milliseconds to throttle the callback execution.\n * Default is 100 milliseconds.\n */\nexport const useOnResize = (\n\tcallback: () => void,\n\toptions: UseOnResizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// Throttled resize handler to limit the frequency of callback execution.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\n\t\t// Check if the callback can be executed based on the throttle duration.\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t}\n\n\t\tlastExecutedRef.current = now\n\t\tcallback()\n\t}\n\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\tconst target = outerElement?.current || window\n\n\t\t// Add the resize event listener when the component mounts.\n\t\ttarget.addEventListener('resize', handleResize)\n\n\t\t// Clean up the event listener when the component unmounts.\n\t\treturn () => {\n\t\t\ttarget.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [throttleDuration, callback])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { type RefObject, useEffect } from 'react'\n\n// A hook that alerts clicks outside of the passed ref.\nexport const useOutsideAlerter = (\n\tref: RefObject<HTMLElement | null>,\n\tcallback: () => void,\n\tignore: string[] = [],\n) => {\n\tuseEffect(() => {\n\t\tconst handleClickOutside = (ev: MouseEvent) => {\n\t\t\tif (ev) {\n\t\t\t\tif (ref.current && !ref.current.contains(ev.target as Node)) {\n\t\t\t\t\tconst target = ev.target as HTMLElement\n\t\t\t\t\t// Ignore tags with a name of `ignore`, or if there is a class of `ignore` in the parent\n\t\t\t\t\t// tree.\n\t\t\t\t\tconst tagName = target.tagName.toLowerCase()\n\t\t\t\t\tconst ignored = ignore.some(\n\t\t\t\t\t\t(i) =>\n\t\t\t\t\t\t\ti.toLowerCase() === tagName || target.closest(`.${i}`) !== null,\n\t\t\t\t\t)\n\n\t\t\t\t\tif (!ignored) {\n\t\t\t\t\t\tcallback()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tdocument.addEventListener('mousedown', handleClickOutside)\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('mousedown', handleClickOutside)\n\t\t}\n\t}, [ref])\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { Context } from 'react'\nimport { createContext, useContext } from 'react'\n\nexport const useSafeContext = <T,>(ctx: T | null | undefined): T => {\n\tif (ctx === null || ctx === undefined) {\n\t\tthrow new Error(\n\t\t\t'Context value is null or undefined. Please ensure the context Provider is used correctly.',\n\t\t)\n\t}\n\treturn ctx\n}\n\nexport const createSafeContext = <T,>(): [Context<T | null>, () => T] => {\n\tconst Context = createContext<T | null>(null)\n\tconst useHook = () => useSafeContext<T>(useContext(Context))\n\treturn [Context, useHook]\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { RefObject } from 'react'\nimport { useEffect, useRef, useState } from 'react'\n\n// Define the type for the options parameter.\ninterface UseSizeOptions {\n\touterElement?: RefObject<HTMLElement | null>\n\tthrottle?: number\n}\n\n// Custom hook to get the width and height of a specified element. Updates the `size` state when the\n// specified \"outer element\" (or the window by default) resizes.\nexport const useSize = (\n\telement: RefObject<HTMLElement | null>,\n\toptions: UseSizeOptions = {},\n) => {\n\tconst { outerElement, throttle: throttleDuration = 100 } = options\n\n\t// Helper function to retrieve the width and height of an element\n\t// If no element is found, default dimensions are set to 0.\n\tconst getSize = (el: HTMLElement | null = null) => {\n\t\tconst width = el?.offsetWidth || 0\n\t\tconst height = el?.offsetHeight || 0\n\t\treturn { width, height }\n\t}\n\n\t// Ref to store the last execution time of the `resizeThrottle` handler.\n\tconst lastExecutedRef = useRef<number>(0)\n\n\t// State to store the current width and height of the specified element.\n\tconst [size, setSize] = useState<{ width: number; height: number }>(\n\t\tgetSize(element?.current),\n\t)\n\n\t// Throttle the resize event handler to limit how often size updates occur.\n\tconst handleResize = () => {\n\t\tconst now = Date.now()\n\t\tif (now - lastExecutedRef.current < throttleDuration) {\n\t\t\treturn\n\t\t} // Exit if `throttleDuration` has not passed.\n\n\t\tlastExecutedRef.current = now // Update last execution time.\n\n\t\tsetSize(getSize(element?.current))\n\t}\n\n\t// Set up the resize event listener on mount and clean it up on unmount.\n\tuseEffect(() => {\n\t\t// Determine the target for the resize event listener.\n\t\t// If `outerElement` is provided, listen to its resize events; otherwise, listen to the window's.\n\t\tconst listenFor = outerElement?.current || window\n\n\t\tlistenFor.addEventListener('resize', handleResize)\n\n\t\t// Clean up event listener when the component unmounts to avoid memory leaks.\n\t\treturn () => {\n\t\t\tlistenFor.removeEventListener('resize', handleResize)\n\t\t}\n\t}, [outerElement?.current])\n\n\t// Return the current size of the element.\n\treturn size\n}\n","/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type {\n\tTimeLeftAll,\n\tTimeLeftRaw,\n\tTimeleftDuration,\n\tUseTimeleftProps,\n} from '@w3ux/types'\nimport { setStateWithRef } from '@w3ux/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { getDuration } from '../util'\n\nexport const useTimeLeft = (props?: UseTimeleftProps) => {\n\tconst depsTimeleft = props?.depsTimeleft || []\n\tconst depsFormat = props?.depsFormat || []\n\n\t// check whether timeleft is within a minute of finishing.\n\tconst inLastHour = () => {\n\t\tconst { days, hours } = getDuration(toRef.current)\n\t\treturn !days && !hours\n\t}\n\n\t// get the amount of seconds left if timeleft is in the last minute.\n\tconst lastMinuteCountdown = () => {\n\t\tconst { seconds } = getDuration(toRef.current)\n\t\tif (!inLastHour()) {\n\t\t\treturn 60\n\t\t}\n\t\treturn seconds\n\t}\n\n\t// calculate resulting timeleft object from latest duration.\n\tconst getTimeleft = (c?: TimeleftDuration): TimeLeftAll => {\n\t\tconst { days, hours, minutes, seconds } = c || getDuration(toRef.current)\n\t\tconst raw: TimeLeftRaw = {\n\t\t\tdays,\n\t\t\thours,\n\t\t\tminutes,\n\t\t}\n\t\tif (!days && !hours) {\n\t\t\traw.seconds = seconds\n\t\t}\n\t\treturn {\n\t\t\traw,\n\t\t}\n\t}\n\n\t// the end time as a date.\n\tconst [to, setTo] = useState<Date | null>(null)\n\tconst toRef = useRef(to)\n\n\t// resulting timeleft object to be returned.\n\tconst [timeleft, setTimeleft] = useState<TimeLeftAll>(getTimeleft())\n\n\t// timeleft refresh intervals.\n\tconst [minInterval, setMinInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst minIntervalRef = useRef(minInterval)\n\n\tconst [secInterval, setSecInterval] = useState<\n\t\tReturnType<typeof setInterval> | undefined\n\t>(undefined)\n\tconst secIntervalRef = useRef(secInterval)\n\n\t// refresh effects.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t\tif (inLastHour()) {\n\t\t\t// refresh timeleft every second.\n\t\t\tif (!secIntervalRef.current) {\n\t\t\t\tconst interval = setInterval(() => {\n\t\t\t\t\tif (!inLastHour()) {\n\t\t\t\t\t\tclearInterval(secIntervalRef.current)\n\t\t\t\t\t\tsetStateWithRef(undefined, setSecInterval, secIntervalRef)\n\t\t\t\t\t}\n\t\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t\t}, 1000)\n\n\t\t\t\tsetStateWithRef(interval, setSecInterval, secIntervalRef)\n\t\t\t}\n\t\t}\n\t\t// refresh timeleft every minute.\n\t\telse if (!minIntervalRef.current) {\n\t\t\tconst interval = setInterval(() => {\n\t\t\t\tif (inLastHour()) {\n\t\t\t\t\tclearInterval(minIntervalRef.current)\n\t\t\t\t\tsetStateWithRef(undefined, setMinInterval, minIntervalRef)\n\t\t\t\t}\n\t\t\t\tsetTimeleft(getTimeleft())\n\t\t\t}, 60000)\n\t\t\tsetStateWithRef(interval, setMinInterval, minIntervalRef)\n\t\t}\n\t}, [to, inLastHour(), lastMinuteCountdown(), ...depsTimeleft])\n\n\t// re-render the timeleft upon formatting changes.\n\tuseEffect(() => {\n\t\tsetTimeleft(getTimeleft())\n\t}, [...depsFormat])\n\n\t// clear intervals on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tclearInterval(minInterval)\n\t\t\tclearInterval(secInterval)\n\t\t},\n\t\t[],\n\t)\n\n\t// Set the end time and calculate timeleft.\n\tconst setFromNow = (dateFrom: Date, dateTo: Date) => {\n\t\tsetTimeleft(getTimeleft(getDuration(dateFrom)))\n\t\tsetStateWithRef(dateTo, setTo, toRef)\n\t}\n\n\treturn {\n\t\tsetFromNow,\n\t\ttimeleft,\n\t}\n}\n"],"mappings":"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","names":["useEffect","useRef","useEffect","useRef","useEffect","useEffect","useRef","useState","useEffect","useRef","useState","useState","useRef","useEffect"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@w3ux/hooks",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.4",
|
|
4
4
|
"license": "GPL-3.0-only",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "A collection of general purpose React hooks",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@w3ux/utils": "^3.1.
|
|
35
|
+
"@w3ux/utils": "^3.1.1",
|
|
36
36
|
"date-fns": "^4.1.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|