@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 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/useEffectIgnoreInitial.tsx
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, import_react.useRef)(true);
37
- (0, import_react.useEffect)(
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 import_react2 = require("react");
115
+ var import_react3 = require("react");
52
116
  var useOnResize = (callback, options = {}) => {
53
117
  const { outerElement, throttle: throttleDuration = 100 } = options;
54
- const lastExecutedRef = (0, import_react2.useRef)(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, import_react2.useEffect)(() => {
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 import_react3 = require("react");
137
+ var import_react4 = require("react");
74
138
  var useOutsideAlerter = (ref, callback, ignore = []) => {
75
- (0, import_react3.useEffect)(() => {
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 import_react4 = require("react");
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, import_react4.createContext)(null);
109
- const useHook = () => useSafeContext((0, import_react4.useContext)(Context));
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 import_react5 = require("react");
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, import_react5.useRef)(0);
123
- const [size, setSize] = (0, import_react5.useState)(
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, import_react5.useEffect)(() => {
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 import_react6 = require("react");
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, import_react6.useState)(null);
218
- const toRef = (0, import_react6.useRef)(to);
219
- const [timeleft, setTimeleft] = (0, import_react6.useState)(getTimeleft());
220
- const [minInterval, setMinInterval] = (0, import_react6.useState)(void 0);
221
- const minIntervalRef = (0, import_react6.useRef)(minInterval);
222
- const [secInterval, setSecInterval] = (0, import_react6.useState)(void 0);
223
- const secIntervalRef = (0, import_react6.useRef)(secInterval);
224
- (0, import_react6.useEffect)(() => {
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, import_react6.useEffect)(() => {
312
+ (0, import_react7.useEffect)(() => {
249
313
  setTimeleft(getTimeleft());
250
314
  }, [...depsFormat]);
251
- (0, import_react6.useEffect)(
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 = useRef(true);
9
- useEffect(
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 useEffect2, useRef as useRef2 } from "react";
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 = useRef2(0);
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
- useEffect2(() => {
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 useEffect3 } from "react";
108
+ import { useEffect as useEffect4 } from "react";
46
109
  var useOutsideAlerter = (ref, callback, ignore = []) => {
47
- useEffect3(() => {
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 useEffect4, useRef as useRef3, useState } from "react";
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 = useRef3(0);
95
- const [size, setSize] = useState(
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
- useEffect4(() => {
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 useEffect5, useRef as useRef4, useState as useState2 } from "react";
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] = useState2(null);
148
- const toRef = useRef4(to);
149
- const [timeleft, setTimeleft] = useState2(getTimeleft());
150
- const [minInterval, setMinInterval] = useState2(void 0);
151
- const minIntervalRef = useRef4(minInterval);
152
- const [secInterval, setSecInterval] = useState2(void 0);
153
- const secIntervalRef = useRef4(secInterval);
154
- useEffect5(() => {
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
- useEffect5(() => {
241
+ useEffect6(() => {
179
242
  setTimeleft(getTimeleft());
180
243
  }, [...depsFormat]);
181
- useEffect5(
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.2",
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.0",
35
+ "@w3ux/utils": "^3.1.1",
36
36
  "date-fns": "^4.1.0"
37
37
  },
38
38
  "peerDependencies": {