@berenjena/react-dev-panel 2.4.2 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +43 -1
  2. package/dist/assets/index.css +1 -1
  3. package/dist/assets/index10.css +1 -1
  4. package/dist/assets/index11.css +1 -1
  5. package/dist/assets/index12.css +1 -1
  6. package/dist/assets/index13.css +1 -1
  7. package/dist/assets/index14.css +1 -1
  8. package/dist/assets/index15.css +1 -1
  9. package/dist/assets/index2.css +1 -1
  10. package/dist/assets/index3.css +1 -1
  11. package/dist/assets/index4.css +1 -1
  12. package/dist/assets/index5.css +1 -1
  13. package/dist/assets/index6.css +1 -1
  14. package/dist/assets/index7.css +1 -1
  15. package/dist/assets/index8.css +1 -1
  16. package/dist/assets/index9.css +1 -1
  17. package/dist/components/ControlErrorBoundary/index.d.ts +24 -0
  18. package/dist/components/ControlErrorBoundary/index.js +17 -0
  19. package/dist/components/ControlRenderer/controls/BooleanControl/index.js +10 -9
  20. package/dist/components/ControlRenderer/controls/ButtonControl/index.js +4 -3
  21. package/dist/components/ControlRenderer/controls/ButtonGroupControl/index.js +6 -5
  22. package/dist/components/ControlRenderer/controls/ColorControl/index.js +2 -1
  23. package/dist/components/ControlRenderer/controls/DateControl/index.js +8 -7
  24. package/dist/components/ControlRenderer/controls/DragAndDropControl/index.js +15 -14
  25. package/dist/components/ControlRenderer/controls/LocalStorageControl/index.js +111 -110
  26. package/dist/components/ControlRenderer/controls/MultiSelectControl/index.d.ts +2 -0
  27. package/dist/components/ControlRenderer/controls/MultiSelectControl/index.js +8 -5
  28. package/dist/components/ControlRenderer/controls/MultiSelectControl/types.d.ts +2 -0
  29. package/dist/components/ControlRenderer/controls/NumberControl/index.js +10 -9
  30. package/dist/components/ControlRenderer/controls/RangeControl/index.js +6 -5
  31. package/dist/components/ControlRenderer/controls/SelectControl/index.js +5 -4
  32. package/dist/components/ControlRenderer/controls/SeparatorControl/index.js +2 -1
  33. package/dist/components/ControlRenderer/controls/TextControl/index.js +7 -6
  34. package/dist/components/ControlRenderer/controls/index.js +1 -0
  35. package/dist/components/ControlRenderer/index.js +28 -26
  36. package/dist/components/DevPanel/index.js +12 -11
  37. package/dist/components/DevPanel/types.d.ts +17 -0
  38. package/dist/components/DevPanelPortal/index.js +5 -4
  39. package/dist/components/EmptyContent/index.js +2 -1
  40. package/dist/components/Icon/index.js +11 -10
  41. package/dist/components/Input/index.js +2 -1
  42. package/dist/components/Section/index.js +2 -1
  43. package/dist/components/Select/index.js +11 -10
  44. package/dist/components/Textarea/index.js +5 -4
  45. package/dist/components/index.js +3 -2
  46. package/dist/hooks/useDebounceCallback/index.js +1 -0
  47. package/dist/hooks/useDevPanel/consoleApi.d.ts +37 -0
  48. package/dist/hooks/useDevPanel/consoleApi.js +16 -0
  49. package/dist/hooks/useDevPanel/index.d.ts +5 -1
  50. package/dist/hooks/useDevPanel/index.js +50 -41
  51. package/dist/hooks/useDevPanel/mountDevPanelPortal.d.ts +18 -0
  52. package/dist/hooks/useDevPanel/mountDevPanelPortal.js +20 -0
  53. package/dist/hooks/useDragAndDrop/index.js +1 -0
  54. package/dist/hooks/useHotKey/index.js +4 -3
  55. package/dist/hooks/useHotkeys/index.js +1 -0
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.js +4 -3
  58. package/dist/managers/DevPanelManager.js +1 -0
  59. package/dist/store/BaseStoreService.d.ts +2 -7
  60. package/dist/store/BaseStoreService.js +14 -7
  61. package/dist/store/ControlPersistenceService.d.ts +2 -0
  62. package/dist/store/ControlPersistenceService.js +34 -26
  63. package/dist/store/SectionsStore.js +3 -2
  64. package/dist/store/UIStore.d.ts +14 -0
  65. package/dist/store/UIStore.js +37 -22
  66. package/dist/utils/className/className.js +6 -5
  67. package/dist/utils/className/index.js +3 -2
  68. package/dist/utils/copyToClipboard/copyToClipboard.js +1 -0
  69. package/dist/utils/copyToClipboard/index.js +3 -2
  70. package/dist/utils/createHotkey/createHotkey.js +4 -3
  71. package/dist/utils/createHotkey/index.js +3 -2
  72. package/dist/utils/debounce/debounce.js +4 -3
  73. package/dist/utils/debounce/index.js +3 -2
  74. package/dist/utils/deepEqual/deepEqual.d.ts +19 -0
  75. package/dist/utils/deepEqual/deepEqual.js +22 -0
  76. package/dist/utils/formatHotkey/formatHotkey.js +1 -0
  77. package/dist/utils/formatHotkey/index.js +1 -0
  78. package/dist/utils/getConstrainedPosition/getConstrainedPosition.js +6 -5
  79. package/dist/utils/getConstrainedPosition/index.js +3 -2
  80. package/dist/utils/getCurrentElementPosition/getCurrentElementPosition.js +1 -0
  81. package/dist/utils/getCurrentElementPosition/index.js +3 -2
  82. package/dist/utils/getPositionAdjustment/getPositionAdjustment.js +6 -5
  83. package/dist/utils/getPositionAdjustment/index.js +3 -2
  84. package/dist/utils/getStringPreview/getStringPreview.js +3 -2
  85. package/dist/utils/getStringPreview/index.js +1 -0
  86. package/dist/utils/hasControlChanged/hasControlChanged.js +7 -5
  87. package/dist/utils/hasControlChanged/index.js +3 -2
  88. package/dist/utils/isMacOS/index.js +3 -2
  89. package/dist/utils/isMacOS/isMacOS.js +3 -2
  90. package/dist/utils/isValidPersistedValue/isValidPersistedValue.d.ts +13 -0
  91. package/dist/utils/isValidPersistedValue/isValidPersistedValue.js +22 -0
  92. package/dist/utils/prettifyJson/index.js +3 -2
  93. package/dist/utils/prettifyJson/prettifyJson.js +5 -4
  94. package/package.json +7 -3
  95. package/dist/assets/index16.css +0 -1
@@ -1,52 +1,61 @@
1
- import { useRef as d, useEffect as s, createElement as v } from "react";
2
- import { createRoot as S } from "react-dom/client";
3
- import { DevPanelPortal as E } from "../../components/DevPanelPortal/index.js";
1
+ "use client";
2
+ import { useRef as d, useEffect as f } from "react";
4
3
  import { DevPanelManager as P } from "../../managers/DevPanelManager.js";
5
- import { controlPersistenceService as m } from "../../store/ControlPersistenceService.js";
6
- import { useDevPanelSections as w, useDevPanelSectionActions as D } from "../../store/SectionsStore.js";
7
- import { hasControlsChanged as R } from "../../utils/hasControlChanged/hasControlChanged.js";
8
- function j(t, o, i) {
9
- const p = w(), { registerSection: g, unregisterSection: h } = D(), C = d(void 0), c = d(null), f = d(/* @__PURE__ */ new Set());
10
- c.current || (c.current = P.getInstance()), s(() => {
11
- Object.entries(o).forEach(([e, n]) => {
12
- const r = `${t}-${e}`;
13
- if (n.persist && !f.current.has(r)) {
14
- const a = m.getPersistedValue(t, e);
15
- a !== void 0 && "onChange" in n && typeof n.onChange == "function" && n.onChange(a), f.current.add(r);
4
+ import { controlPersistenceService as C } from "../../store/ControlPersistenceService.js";
5
+ import { useDevPanelSections as $, useDevPanelSectionActions as m } from "../../store/SectionsStore.js";
6
+ import { hasControlsChanged as E } from "../../utils/hasControlChanged/hasControlChanged.js";
7
+ import { isValidPersistedValue as V } from "../../utils/isValidPersistedValue/isValidPersistedValue.js";
8
+ import { mountDevPanelPortal as b } from "./mountDevPanelPortal.js";
9
+ function M(e, i, o) {
10
+ const v = $(), { registerSection: l, unregisterSection: a } = m(), p = d(void 0), c = d(null), h = d(/* @__PURE__ */ new Set()), s = o?.enabled ?? !0;
11
+ c.current || (c.current = P.getInstance()), f(() => {
12
+ s && Object.entries(i).forEach(([n, r]) => {
13
+ const t = `${e}-${n}`;
14
+ if (r.persist && !h.current.has(t)) {
15
+ const u = C.getPersistedValue(e, n);
16
+ u !== void 0 && "onChange" in r && typeof r.onChange == "function" && (V(r, u) ? r.onChange(u) : (console.warn(
17
+ `[DevPanel] Ignoring persisted value for "${e}.${n}": type does not match control "${r.type}". Dropping stored value.`
18
+ ), C.removePersistedValue(e, n))), h.current.add(t);
16
19
  }
17
20
  });
18
- }, [t, o]);
19
- const u = d({});
20
- s(() => {
21
- const e = {};
22
- Object.entries(o).forEach(([n, r]) => {
23
- if (r.persist && "onChange" in r && typeof r.onChange == "function") {
24
- const a = r.onChange;
25
- e[n] = {
26
- ...r,
27
- onChange: (l) => {
28
- m.setPersistedValue(t, n, l), a(l);
21
+ }, [s, e, i]);
22
+ const g = d({});
23
+ f(() => {
24
+ const n = {};
25
+ Object.entries(i).forEach(([r, t]) => {
26
+ if (t.persist && "onChange" in t && typeof t.onChange == "function") {
27
+ const u = t.onChange;
28
+ n[r] = {
29
+ ...t,
30
+ onChange: (S) => {
31
+ C.setPersistedValue(e, r, S);
32
+ try {
33
+ u(S);
34
+ } catch (D) {
35
+ console.error(`[DevPanel] Error in onChange for "${e}.${r}":`, D);
36
+ }
29
37
  }
30
38
  };
31
39
  } else
32
- e[n] = r;
33
- }), u.current = e;
34
- }, [t, o]), s(() => {
35
- const e = c.current, n = p[t] !== void 0;
36
- R(u.current, C.current) || !n ? (g(t, u.current), C.current = u.current, e.addSection(t, i)) : i && e.updateProps(i);
37
- }, [t, o, i, p, g]), s(() => {
38
- const e = f.current;
40
+ n[r] = t;
41
+ }), g.current = n;
42
+ }, [e, i]), f(() => {
43
+ const n = c.current, r = v[e] !== void 0;
44
+ if (!s) {
45
+ r && (a(e), n.removeSection(e), p.current = void 0);
46
+ return;
47
+ }
48
+ E(g.current, p.current) || !r ? (l(e, g.current), p.current = g.current, n.addSection(e, o)) : o && n.updateProps(o);
49
+ }, [s, e, i, o, v, l, a]), f(() => {
50
+ const n = h.current;
39
51
  return () => {
40
- const n = c.current;
41
- h(t), n.removeSection(t), e.clear();
52
+ const r = c.current;
53
+ a(e), r.removeSection(e), n.clear();
42
54
  };
43
- }, [t, h]), s(() => {
44
- if (window.__devPanelAutoMounted) return;
45
- window.__devPanelAutoMounted = !0;
46
- const e = document.createElement("div");
47
- e.id = "dev-panel-portal-container", e.style.display = "none", document.body.appendChild(e), S(e).render(v(E));
48
- }, []);
55
+ }, [e, a]), f(() => {
56
+ s && b();
57
+ }, [s]);
49
58
  }
50
59
  export {
51
- j as useDevPanel
60
+ M as useDevPanel
52
61
  };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Mounts the DevPanelPortal into a dedicated, hidden container appended to
3
+ * `document.body`, creating a single React root for the whole app.
4
+ *
5
+ * Idempotent and safe to call from every `useDevPanel` call site:
6
+ * - No-op in non-browser environments (SSR) — guarded by `typeof document`.
7
+ * - No-op if already mounted in this runtime (the stored `root` acts as guard).
8
+ * - Self-heals across HMR/module reloads: a stale container left over from a
9
+ * previous module instance is removed before creating a fresh root, so the
10
+ * portal never duplicates and never leaks an orphaned container.
11
+ */
12
+ export declare function mountDevPanelPortal(): void;
13
+ /**
14
+ * Tears down the DevPanelPortal root and removes its container from the DOM.
15
+ * Intended for HMR resets and tests; the portal re-mounts on the next
16
+ * `mountDevPanelPortal` call.
17
+ */
18
+ export declare function unmountDevPanelPortal(): void;
@@ -0,0 +1,20 @@
1
+ "use client";
2
+ import { createElement as r } from "react";
3
+ import { createRoot as l } from "react-dom/client";
4
+ import { DevPanelPortal as i } from "../../components/DevPanelPortal/index.js";
5
+ import { registerDevPanelConsoleApi as m, unregisterDevPanelConsoleApi as u } from "./consoleApi.js";
6
+ const o = "dev-panel-portal-container";
7
+ let n = null, e = null;
8
+ function f() {
9
+ if (typeof document > "u" || n)
10
+ return;
11
+ const t = document.getElementById(o);
12
+ t && t.remove(), e = document.createElement("div"), e.id = o, e.style.display = "none", document.body.appendChild(e), n = l(e), n.render(r(i)), m();
13
+ }
14
+ function s() {
15
+ n?.unmount(), n = null, e?.remove(), e = null, u();
16
+ }
17
+ export {
18
+ f as mountDevPanelPortal,
19
+ s as unmountDevPanelPortal
20
+ };
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { useRef as g, useState as p, useCallback as u, useEffect as f } from "react";
2
3
  import { debounce as E } from "../../utils/debounce/debounce.js";
3
4
  import { getConstrainedPosition as D } from "../../utils/getConstrainedPosition/getConstrainedPosition.js";
@@ -1,7 +1,8 @@
1
+ "use client";
1
2
  import { useHotkeys as t } from "../useHotkeys/index.js";
2
- function s(o, e = {}) {
3
- t([o], e);
3
+ function u(e, o = {}) {
4
+ t([e], o);
4
5
  }
5
6
  export {
6
- s as useHotkey
7
+ u as useHotkey
7
8
  };
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { useRef as K, useCallback as y, useEffect as w } from "react";
2
3
  function M(h, p = {}) {
3
4
  const { enabled: a = !0, target: c = window, preventDefault: f = !1, stopPropagation: l = !1 } = p, u = K([]);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { useDevPanel } from './hooks/useDevPanel';
2
+ export type { DevPanelConsoleApi } from './hooks/useDevPanel/consoleApi';
2
3
  export type { DevPanelProps } from './components/DevPanel/types';
3
4
  export type { ControlsGroup } from './components/ControlRenderer/controls/types';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- import { useDevPanel as r } from "./hooks/useDevPanel/index.js";
2
- import './assets/index.css';export {
3
- r as useDevPanel
1
+ "use client";
2
+ import { useDevPanel as n } from "./hooks/useDevPanel/index.js";
3
+ export {
4
+ n as useDevPanel
4
5
  };
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  class e {
2
3
  static instance = null;
3
4
  currentProps = {};
@@ -1,13 +1,8 @@
1
- /**
2
- * Abstract base class for state management services using the useSyncExternalStore pattern.
3
- * Provides common functionality for subscription management, state updates, and persistence.
4
- *
5
- * @template TState - The type of the state object
6
- * @template TPersistedState - The type of the persisted state object (usually a subset of TState)
7
- */
8
1
  export declare abstract class BaseStoreService<TState, TPersistedState = TState> {
9
2
  /** Set of listeners subscribed to state changes */
10
3
  protected readonly listeners: Set<() => void>;
4
+ /** Whether a persistence failure has already been logged (avoids log spam). */
5
+ private persistenceWarned;
11
6
  /** The localStorage key for persisting state */
12
7
  protected readonly storageKey: string;
13
8
  /** Whether this store should persist state to localStorage */
@@ -1,6 +1,10 @@
1
- class r {
1
+ "use client";
2
+ import { deepEqual as r } from "../utils/deepEqual/deepEqual.js";
3
+ class n {
2
4
  /** Set of listeners subscribed to state changes */
3
5
  listeners = /* @__PURE__ */ new Set();
6
+ /** Whether a persistence failure has already been logged (avoids log spam). */
7
+ persistenceWarned = !1;
4
8
  /** The localStorage key for persisting state */
5
9
  storageKey;
6
10
  /** Whether this store should persist state to localStorage */
@@ -24,12 +28,15 @@ class r {
24
28
  * @protected
25
29
  */
26
30
  saveState() {
27
- if (this.shouldPersist)
31
+ if (!(!this.shouldPersist || typeof localStorage > "u"))
28
32
  try {
29
33
  const t = this.toPersistableState(this.state);
30
34
  localStorage.setItem(this.storageKey, JSON.stringify(t));
31
- } catch {
32
- console.warn(`Failed to save ${this.getServiceName()} state to localStorage`);
35
+ } catch (t) {
36
+ if (!this.persistenceWarned) {
37
+ const e = t instanceof DOMException && t.name === "QuotaExceededError" ? "localStorage quota exceeded" : "localStorage unavailable";
38
+ console.warn(`[DevPanel] Failed to save ${this.getServiceName()} state (${e}).`), this.persistenceWarned = !0;
39
+ }
33
40
  }
34
41
  }
35
42
  /**
@@ -39,7 +46,7 @@ class r {
39
46
  * @protected
40
47
  */
41
48
  loadState() {
42
- if (this.shouldPersist)
49
+ if (!(!this.shouldPersist || typeof localStorage > "u"))
43
50
  try {
44
51
  const t = localStorage.getItem(this.storageKey);
45
52
  if (t) {
@@ -67,7 +74,7 @@ class r {
67
74
  */
68
75
  setState(t) {
69
76
  const e = t(this.state);
70
- JSON.stringify(e) !== JSON.stringify(this.state) && (this.state = e, this.saveState(), this.notifySubscribers());
77
+ r(e, this.state) || (this.state = e, this.saveState(), this.notifySubscribers());
71
78
  }
72
79
  /**
73
80
  * Returns the current state snapshot for useSyncExternalStore.
@@ -86,5 +93,5 @@ class r {
86
93
  });
87
94
  }
88
95
  export {
89
- r as BaseStoreService
96
+ n as BaseStoreService
90
97
  };
@@ -3,6 +3,8 @@
3
3
  */
4
4
  declare class ControlPersistenceService {
5
5
  private readonly storageKey;
6
+ /** Whether a write failure has already been logged (avoids log spam). */
7
+ private writeWarned;
6
8
  /**
7
9
  * Gets persisted value for a control
8
10
  * @param sectionName - Name of the section
@@ -1,5 +1,8 @@
1
+ "use client";
1
2
  class a {
2
3
  storageKey = "dev-panel-controls-persistence";
4
+ /** Whether a write failure has already been logged (avoids log spam). */
5
+ writeWarned = !1;
3
6
  /**
4
7
  * Gets persisted value for a control
5
8
  * @param sectionName - Name of the section
@@ -7,12 +10,13 @@ class a {
7
10
  * @returns Persisted value or undefined if not found
8
11
  */
9
12
  getPersistedValue(e, s) {
10
- try {
11
- const t = localStorage.getItem(this.storageKey);
12
- return t ? JSON.parse(t)[e]?.[s] : void 0;
13
- } catch {
14
- return;
15
- }
13
+ if (!(typeof localStorage > "u"))
14
+ try {
15
+ const r = localStorage.getItem(this.storageKey);
16
+ return r ? JSON.parse(r)[e]?.[s] : void 0;
17
+ } catch {
18
+ return;
19
+ }
16
20
  }
17
21
  /**
18
22
  * Sets persisted value for a control
@@ -20,12 +24,14 @@ class a {
20
24
  * @param controlKey - Key of the control within the section
21
25
  * @param value - Value to persist
22
26
  */
23
- setPersistedValue(e, s, t) {
24
- try {
25
- const r = localStorage.getItem(this.storageKey), o = r ? JSON.parse(r) : {};
26
- o[e] || (o[e] = {}), o[e][s] = t, localStorage.setItem(this.storageKey, JSON.stringify(o));
27
- } catch {
28
- }
27
+ setPersistedValue(e, s, r) {
28
+ if (!(typeof localStorage > "u"))
29
+ try {
30
+ const t = localStorage.getItem(this.storageKey), o = t ? JSON.parse(t) : {};
31
+ o[e] || (o[e] = {}), o[e][s] = r, localStorage.setItem(this.storageKey, JSON.stringify(o));
32
+ } catch (t) {
33
+ this.writeWarned || (console.warn(`[DevPanel] Failed to persist "${e}.${s}" (quota exceeded or value not serializable).`, t), this.writeWarned = !0);
34
+ }
29
35
  }
30
36
  /**
31
37
  * Removes persisted value for a control
@@ -33,26 +39,28 @@ class a {
33
39
  * @param controlKey - Key of the control within the section
34
40
  */
35
41
  removePersistedValue(e, s) {
36
- try {
37
- const t = localStorage.getItem(this.storageKey);
38
- if (!t) return;
39
- const r = JSON.parse(t);
40
- r[e] && (delete r[e][s], Object.keys(r[e]).length === 0 && delete r[e], localStorage.setItem(this.storageKey, JSON.stringify(r)));
41
- } catch {
42
- }
42
+ if (!(typeof localStorage > "u"))
43
+ try {
44
+ const r = localStorage.getItem(this.storageKey);
45
+ if (!r) return;
46
+ const t = JSON.parse(r);
47
+ t[e] && (delete t[e][s], Object.keys(t[e]).length === 0 && delete t[e], localStorage.setItem(this.storageKey, JSON.stringify(t)));
48
+ } catch {
49
+ }
43
50
  }
44
51
  /**
45
52
  * Removes all persisted values for a section
46
53
  * @param sectionName - Name of the section
47
54
  */
48
55
  removeSection(e) {
49
- try {
50
- const s = localStorage.getItem(this.storageKey);
51
- if (!s) return;
52
- const t = JSON.parse(s);
53
- delete t[e], localStorage.setItem(this.storageKey, JSON.stringify(t));
54
- } catch {
55
- }
56
+ if (!(typeof localStorage > "u"))
57
+ try {
58
+ const s = localStorage.getItem(this.storageKey);
59
+ if (!s) return;
60
+ const r = JSON.parse(s);
61
+ delete r[e], localStorage.setItem(this.storageKey, JSON.stringify(r));
62
+ } catch {
63
+ }
56
64
  }
57
65
  }
58
66
  const l = new a();
@@ -1,7 +1,8 @@
1
+ "use client";
1
2
  import { useSyncExternalStore as n } from "react";
2
3
  import { BaseStoreService as c } from "./BaseStoreService.js";
3
4
  const S = "dev-panel-sections-storage";
4
- class a extends c {
5
+ class l extends c {
5
6
  /**
6
7
  * Creates a new DevPanelSectionsService instance.
7
8
  */
@@ -96,7 +97,7 @@ class a extends c {
96
97
  this.setState(() => ({}));
97
98
  };
98
99
  }
99
- const r = new a();
100
+ const r = new l();
100
101
  function p() {
101
102
  return n(r.subscribe, r.getSnapshot);
102
103
  }
@@ -1,4 +1,18 @@
1
1
  import { DevPanelUIState, Position } from '../components/DevPanel/types';
2
+ /**
3
+ * Imperatively shows the dev panel. Usable outside React (e.g. the console API).
4
+ * The panel still only appears on screen if at least one section is registered.
5
+ */
6
+ export declare function showDevPanel(): void;
7
+ /**
8
+ * Imperatively hides the dev panel. Usable outside React (e.g. the console API).
9
+ */
10
+ export declare function hideDevPanel(): void;
11
+ /**
12
+ * Imperatively toggles the dev panel visibility — mirrors the keyboard hotkey.
13
+ * Usable outside React (e.g. the console API).
14
+ */
15
+ export declare function toggleDevPanel(): void;
2
16
  /**
3
17
  * React hook that provides access to the complete dev panel UI state and actions.
4
18
  * Uses useSyncExternalStore for optimal performance and React 18 compatibility.
@@ -1,12 +1,13 @@
1
+ "use client";
1
2
  import { useSyncExternalStore as r } from "react";
2
3
  import { BaseStoreService as o } from "./BaseStoreService.js";
3
- const u = "dev-panel-ui-storage", h = { x: 20, y: 20 }, n = {
4
+ const u = "dev-panel-ui-storage", l = { x: 20, y: 20 }, n = {
4
5
  isVisible: !1,
5
6
  isCollapsed: !1,
6
- position: h,
7
+ position: l,
7
8
  currentTheme: "auto"
8
9
  };
9
- class a extends o {
10
+ class h extends o {
10
11
  /**
11
12
  * Creates a new DevPanelUIService instance and loads persisted state from localStorage.
12
13
  */
@@ -58,6 +59,8 @@ class a extends o {
58
59
  * @private
59
60
  */
60
61
  applyTheme(t) {
62
+ if (typeof document > "u")
63
+ return;
61
64
  const s = document.documentElement;
62
65
  t === "auto" || t === "" ? s.removeAttribute("data-dev-panel-theme") : s.setAttribute("data-dev-panel-theme", t);
63
66
  }
@@ -113,8 +116,17 @@ class a extends o {
113
116
  this.setState(() => ({ ...n })), this.applyTheme(n.currentTheme);
114
117
  };
115
118
  }
116
- const e = new a();
117
- function l() {
119
+ const e = new h();
120
+ function T() {
121
+ e.setVisible(!0);
122
+ }
123
+ function p() {
124
+ e.setVisible(!1);
125
+ }
126
+ function b() {
127
+ e.setVisible(!e.getSnapshot().isVisible);
128
+ }
129
+ function a() {
118
130
  return {
119
131
  ...r(e.subscribe, e.getSnapshot),
120
132
  setVisible: e.setVisible,
@@ -126,19 +138,19 @@ function l() {
126
138
  reset: e.reset
127
139
  };
128
140
  }
129
- function c() {
141
+ function d() {
130
142
  return r(e.subscribe, () => e.getSnapshot().isVisible);
131
143
  }
132
- function p() {
144
+ function S() {
133
145
  return r(e.subscribe, () => e.getSnapshot().isCollapsed);
134
146
  }
135
- function b() {
147
+ function f() {
136
148
  return r(e.subscribe, () => e.getSnapshot().position);
137
149
  }
138
- function S() {
150
+ function g() {
139
151
  return r(e.subscribe, () => e.getSnapshot().currentTheme);
140
152
  }
141
- function d() {
153
+ function P() {
142
154
  return {
143
155
  currentTheme: r(e.subscribe, () => e.getSnapshot().currentTheme),
144
156
  setTheme: e.setTheme,
@@ -146,7 +158,7 @@ function d() {
146
158
  getCurrentTheme: e.getCurrentTheme
147
159
  };
148
160
  }
149
- function C() {
161
+ function v() {
150
162
  return {
151
163
  setVisible: e.setVisible,
152
164
  setCollapsed: e.setCollapsed,
@@ -157,22 +169,25 @@ function C() {
157
169
  reset: e.reset
158
170
  };
159
171
  }
160
- function g() {
172
+ function C() {
161
173
  return {
162
174
  setTheme: e.setTheme,
163
175
  resetTheme: e.resetTheme,
164
176
  getCurrentTheme: e.getCurrentTheme
165
177
  };
166
178
  }
167
- const P = l;
179
+ const V = a;
168
180
  export {
169
- S as useCurrentTheme,
170
- p as useDevPanelCollapsed,
171
- b as useDevPanelPosition,
172
- P as useDevPanelStore,
173
- d as useDevPanelTheme,
174
- g as useDevPanelThemeActions,
175
- l as useDevPanelUI,
176
- C as useDevPanelUIActions,
177
- c as useDevPanelVisible
181
+ p as hideDevPanel,
182
+ T as showDevPanel,
183
+ b as toggleDevPanel,
184
+ g as useCurrentTheme,
185
+ S as useDevPanelCollapsed,
186
+ f as useDevPanelPosition,
187
+ V as useDevPanelStore,
188
+ P as useDevPanelTheme,
189
+ C as useDevPanelThemeActions,
190
+ a as useDevPanelUI,
191
+ v as useDevPanelUIActions,
192
+ d as useDevPanelVisible
178
193
  };
@@ -1,15 +1,16 @@
1
- function f(...o) {
1
+ "use client";
2
+ function c(...t) {
2
3
  const s = [];
3
- for (const e of o)
4
+ for (const e of t)
4
5
  if (e) {
5
6
  if (typeof e == "string")
6
7
  s.push(e);
7
8
  else if (typeof e == "object")
8
- for (const [t, n] of Object.entries(e))
9
- n && s.push(t);
9
+ for (const [o, n] of Object.entries(e))
10
+ n && s.push(o);
10
11
  }
11
12
  return { className: s.join(" ") };
12
13
  }
13
14
  export {
14
- f as className
15
+ c as className
15
16
  };
@@ -1,4 +1,5 @@
1
- import { className as m } from "./className.js";
1
+ "use client";
2
+ import { className as a } from "./className.js";
2
3
  export {
3
- m as className
4
+ a as className
4
5
  };
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  async function t(o) {
2
3
  try {
3
4
  await navigator.clipboard.writeText(o);
@@ -1,4 +1,5 @@
1
- import { copyToClipboard as r } from "./copyToClipboard.js";
1
+ "use client";
2
+ import { copyToClipboard as p } from "./copyToClipboard.js";
2
3
  export {
3
- r as copyToClipboard
4
+ p as copyToClipboard
4
5
  };
@@ -1,4 +1,5 @@
1
- function c(e, a, t = {}, y = {}) {
1
+ "use client";
2
+ function l(e, a, t = {}, c = {}) {
2
3
  return {
3
4
  key: e,
4
5
  action: a,
@@ -6,9 +7,9 @@ function c(e, a, t = {}, y = {}) {
6
7
  shiftKey: t.shift,
7
8
  altKey: t.alt,
8
9
  metaKey: t.meta,
9
- ...y
10
+ ...c
10
11
  };
11
12
  }
12
13
  export {
13
- c as createHotkey
14
+ l as createHotkey
14
15
  };
@@ -1,4 +1,5 @@
1
- import { createHotkey as r } from "./createHotkey.js";
1
+ "use client";
2
+ import { createHotkey as o } from "./createHotkey.js";
2
3
  export {
3
- r as createHotkey
4
+ o as createHotkey
4
5
  };
@@ -1,7 +1,8 @@
1
- function i(t, o) {
1
+ "use client";
2
+ function i(t, u) {
2
3
  let e;
3
- return (...u) => {
4
- clearTimeout(e), e = setTimeout(() => t(...u), o);
4
+ return (...o) => {
5
+ clearTimeout(e), e = setTimeout(() => t(...o), u);
5
6
  };
6
7
  }
7
8
  export {
@@ -1,4 +1,5 @@
1
- import { debounce as r } from "./debounce.js";
1
+ "use client";
2
+ import { debounce as c } from "./debounce.js";
2
3
  export {
3
- r as debounce
4
+ c as debounce
4
5
  };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Structural deep-equality check used to skip redundant store updates and
3
+ * re-registrations.
4
+ *
5
+ * Preferable to comparing two `JSON.stringify` outputs because it:
6
+ * - does not allocate two full string copies on every call;
7
+ * - is insensitive to object key order;
8
+ * - compares functions by reference (`Object.is`) instead of silently dropping
9
+ * them, so a control whose only change is a new `onChange` handler is still
10
+ * detected as changed.
11
+ *
12
+ * Note: like `JSON.stringify`, it does not guard against circular references;
13
+ * the states compared here (UI state, control descriptors) are never circular.
14
+ *
15
+ * @param a - First value
16
+ * @param b - Second value
17
+ * @returns `true` when the two values are structurally equal
18
+ */
19
+ export declare function deepEqual(a: unknown, b: unknown): boolean;