@versini/ui-hooks 5.1.0 → 5.1.1

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.
@@ -1,25 +1,45 @@
1
- import { useRef as u, useEffect as d, useCallback as l } from "react";
2
- const o = 50, s = 120, m = () => {
3
- const c = u(null), r = u(null), i = u(/* @__PURE__ */ new Set());
4
- d(() => typeof window > "u" ? void 0 : ((() => {
5
- if (c.current && r.current)
6
- return;
7
- const e = document.createElement("input");
8
- e.type = "checkbox", e.setAttribute("switch", ""), e.style.display = "none", e.setAttribute("aria-hidden", "true");
9
- const t = document.createElement("label");
10
- t.style.display = "none", t.setAttribute("aria-hidden", "true"), t.appendChild(e), document.body.appendChild(t), c.current = e, r.current = t;
11
- })(), () => {
12
- for (const e of i.current)
13
- clearTimeout(e);
14
- i.current.clear(), r.current && document.body.contains(r.current) && document.body.removeChild(r.current), c.current = null, r.current = null;
15
- }), []);
16
- const a = l(() => {
1
+ import { useRef as s, useEffect as p, useCallback as l } from "react";
2
+ const u = 50, d = 120;
3
+ let t = null, c = 0;
4
+ const f = () => {
5
+ if (typeof window > "u" || t && document.body.contains(t))
6
+ return;
7
+ const r = document.querySelector(
8
+ 'label[data-haptic-singleton="true"]'
9
+ );
10
+ if (r) {
11
+ t = r;
12
+ return;
13
+ }
14
+ t = null;
15
+ const e = document.createElement("input");
16
+ e.type = "checkbox", e.setAttribute("switch", ""), e.style.display = "none", e.setAttribute("aria-hidden", "true"), e.dataset.hapticSingleton = "true";
17
+ const i = document.createElement("label");
18
+ i.style.display = "none", i.setAttribute("aria-hidden", "true"), i.dataset.hapticSingleton = "true", i.appendChild(e), document.body.appendChild(i), t = i;
19
+ }, m = () => {
20
+ t && document.body && document.body.contains(t) && document.body.removeChild(t), t = null;
21
+ }, h = () => {
22
+ const r = s(/* @__PURE__ */ new Set());
23
+ p(() => {
24
+ c++;
25
+ try {
26
+ f();
27
+ } catch (n) {
28
+ throw c--, n;
29
+ }
30
+ return () => {
31
+ for (const n of r.current)
32
+ clearTimeout(n);
33
+ r.current.clear(), c--, c === 0 && m();
34
+ };
35
+ }, []);
36
+ const e = l(() => {
17
37
  try {
18
38
  if (navigator?.vibrate) {
19
- navigator.vibrate(o);
39
+ navigator.vibrate(u);
20
40
  return;
21
41
  }
22
- r.current?.click();
42
+ t?.click();
23
43
  } catch {
24
44
  }
25
45
  }, []);
@@ -27,23 +47,23 @@ const o = 50, s = 120, m = () => {
27
47
  (n = 1) => {
28
48
  if (!(typeof window > "u") && !(n < 1)) {
29
49
  if (navigator?.vibrate && n > 1) {
30
- const e = [];
31
- for (let t = 0; t < n; t++)
32
- e.push(o), t < n - 1 && e.push(s - o);
33
- navigator.vibrate(e);
50
+ const o = [];
51
+ for (let a = 0; a < n; a++)
52
+ o.push(u), a < n - 1 && o.push(d - u);
53
+ navigator.vibrate(o);
34
54
  return;
35
55
  }
36
- for (let e = 0; e < n; e++) {
37
- const t = setTimeout(() => {
38
- a(), i.current.delete(t);
39
- }, e * s);
40
- i.current.add(t);
56
+ for (let o = 0; o < n; o++) {
57
+ const a = setTimeout(() => {
58
+ e(), r.current.delete(a);
59
+ }, o * d);
60
+ r.current.add(a);
41
61
  }
42
62
  }
43
63
  },
44
- [a]
64
+ [e]
45
65
  ) };
46
66
  };
47
67
  export {
48
- m as useHaptic
68
+ h as useHaptic
49
69
  };
package/dist/index.d.ts CHANGED
@@ -20,8 +20,12 @@ declare function useClickOutside<T extends HTMLElement = any>(handler: () => voi
20
20
 
21
21
  /**
22
22
  * Custom hook providing imperative haptic feedback for mobile devices. Uses
23
- * navigator.vibrate when available, falls back to iOS switch element trick
24
- * for Safari on iOS devices that don't support the Vibration API.
23
+ * navigator.vibrate when available, falls back to iOS switch element trick for
24
+ * Safari on iOS devices that don't support the Vibration API.
25
+ *
26
+ * This hook uses a singleton pattern - only one haptic element is created in
27
+ * the DOM regardless of how many components use this hook. The element is
28
+ * automatically cleaned up when the last component unmounts.
25
29
  *
26
30
  * @example
27
31
  * ```tsx
@@ -33,6 +37,7 @@ declare function useClickOutside<T extends HTMLElement = any>(handler: () => voi
33
37
  * // Trigger two rapid haptic pulses
34
38
  * haptic(2);
35
39
  * ```
40
+ *
36
41
  */
37
42
  declare const useHaptic: () => {
38
43
  haptic: (count?: number) => void;
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { useUniqueId as S } from "./hooks/useUniqueId.js";
12
12
  import { useViewportSize as M } from "./hooks/useViewportSize.js";
13
13
  import { useVisualViewportSize as R } from "./hooks/useVisualViewportSize.js";
14
14
  /*!
15
- @versini/ui-hooks v5.1.0
15
+ @versini/ui-hooks v5.1.1
16
16
  © 2025 gizmette.com
17
17
  */
18
18
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@versini/ui-hooks",
3
- "version": "5.1.0",
3
+ "version": "5.1.1",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
@@ -36,5 +36,5 @@
36
36
  "test:watch": "vitest",
37
37
  "test": "vitest run"
38
38
  },
39
- "gitHead": "e2e7b5c53c77d1773d7e0e463bac2a75b936a0d3"
39
+ "gitHead": "eeceef78affd19e3dcae621833a83a892f09c204"
40
40
  }