@berenjena/react-dev-panel 1.0.3 → 1.0.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.
@@ -1,6 +1,6 @@
1
1
  import { jsxs as o, jsx as e } from "react/jsx-runtime";
2
2
  import { ControlRenderer as i } from "../ControlRenderer/ControlRenderer.js";
3
- import { useDevPanelActions as r } from "../../store/store.js";
3
+ import { a as r } from "../../UIStore-CQdr4U-2.js";
4
4
  import '../../assets/Section.css';const d = "_section_1vgul_1", g = "_header_1vgul_8", _ = "_title_1vgul_15", p = "_toggle_1vgul_20", m = "_collapsed_1vgul_29", v = "_content_1vgul_35", l = {
5
5
  section: d,
6
6
  header: g,
@@ -10,9 +10,9 @@ import '../../assets/Section.css';const d = "_section_1vgul_1", g = "_header_1vg
10
10
  content: v
11
11
  };
12
12
  function x({ sectionName: n, section: t }) {
13
- const c = r();
13
+ const { toggleSectionCollapse: c } = r();
14
14
  return /* @__PURE__ */ o("div", { className: l.section, children: [
15
- /* @__PURE__ */ o("div", { className: l.header, onClick: () => c.toggleSectionCollapse(n), children: [
15
+ /* @__PURE__ */ o("div", { className: l.header, onClick: () => c(n), children: [
16
16
  /* @__PURE__ */ e("span", { className: l.title, children: t.name }),
17
17
  /* @__PURE__ */ e("span", { className: l.toggle, children: /* @__PURE__ */ e("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", className: t.isCollapsed ? l.collapsed : void 0, children: /* @__PURE__ */ e("path", { d: "M10.211 7.155A.75.75 0 0 0 9 7.747v8.501a.75.75 0 0 0 1.212.591l5.498-4.258a.746.746 0 0 0-.001-1.183l-5.498-4.243z" }) }) })
18
18
  ] }),
@@ -0,0 +1 @@
1
+ export * from './useDebounceCallback';
@@ -0,0 +1,4 @@
1
+ import { useDebouncedCallback as a } from "./useDebounceCallback.js";
2
+ export {
3
+ a as useDebouncedCallback
4
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Creates a debounced version of a callback.
3
+ *
4
+ * @param callback - Function to debounce
5
+ * @param delay - Delay in ms before calling the callback
6
+ * @returns A debounced version of the callback
7
+ */
8
+ export declare function useDebouncedCallback<T extends (...args: Parameters<T>) => void>(callback: T, delay: number): (...args: Parameters<T>) => void;
@@ -0,0 +1,17 @@
1
+ import { useRef as n, useEffect as c, useCallback as o } from "react";
2
+ function f(r, t) {
3
+ const e = n(null);
4
+ return c(() => () => {
5
+ e.current && clearTimeout(e.current);
6
+ }, []), o(
7
+ (...u) => {
8
+ e.current && clearTimeout(e.current), e.current = window.setTimeout(() => {
9
+ r(...u);
10
+ }, t);
11
+ },
12
+ [r, t]
13
+ );
14
+ }
15
+ export {
16
+ f as useDebouncedCallback
17
+ };
@@ -1,15 +1,15 @@
1
- import { useRef as f, useEffect as s } from "react";
2
- import { useDevPanelStore as p } from "../../store/store.js";
3
- import { hasControlsChanged as v } from "../../utils/hasControlChanged/hasControlChanged.js";
4
- function C(e, r) {
5
- const { sections: t, registerSection: o, unregisterSection: i } = p(), n = f(void 0);
6
- s(() => {
7
- const u = t[e] !== void 0;
8
- (v(r, n.current) || !u) && (o(e, r), n.current = r);
9
- }, [e, r, t, o]), s(() => () => {
10
- i(e);
11
- }, [e, i]);
1
+ import { useRef as f, useEffect as i } from "react";
2
+ import { u as c, a as v } from "../../UIStore-CQdr4U-2.js";
3
+ import { hasControlsChanged as p } from "../../utils/hasControlChanged/hasControlChanged.js";
4
+ function g(e, t) {
5
+ const r = c(), { registerSection: s, unregisterSection: n } = v(), o = f(void 0);
6
+ i(() => {
7
+ const u = r[e] !== void 0;
8
+ (p(t, o.current) || !u) && (s(e, t), o.current = t);
9
+ }, [e, t, r, s]), i(() => () => {
10
+ n(e);
11
+ }, [e, n]);
12
12
  }
13
13
  export {
14
- C as useDevPanel
14
+ g as useDevPanel
15
15
  };
@@ -0,0 +1,90 @@
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
+ export declare abstract class BaseStoreService<TState, TPersistedState = TState> {
9
+ /** Set of listeners subscribed to state changes */
10
+ protected readonly listeners: Set<() => void>;
11
+ /** The localStorage key for persisting state */
12
+ protected readonly storageKey: string;
13
+ /** Whether this store should persist state to localStorage */
14
+ protected readonly shouldPersist: boolean;
15
+ /** The current state */
16
+ protected state: TState;
17
+ /**
18
+ * Creates a new BaseStoreService instance.
19
+ *
20
+ * @param storageKey - The localStorage key for persisting state (used only if shouldPersist is true)
21
+ * @param defaultState - The default state value
22
+ * @param shouldLoadOnInit - Whether to load persisted state on initialization (only works if shouldPersist is true)
23
+ * @param shouldPersist - Whether to persist state to localStorage (default: true)
24
+ */
25
+ constructor(storageKey: string, defaultState: TState, shouldLoadOnInit?: boolean, shouldPersist?: boolean);
26
+ /**
27
+ * Abstract method to transform current state to persistable format.
28
+ * Must be implemented by subclasses.
29
+ *
30
+ * @param state - The current state
31
+ * @returns The state in persistable format
32
+ */
33
+ protected abstract toPersistableState(state: TState): TPersistedState;
34
+ /**
35
+ * Abstract method to transform persisted state back to current state format.
36
+ * Must be implemented by subclasses.
37
+ *
38
+ * @param persistedState - The persisted state
39
+ * @param defaultState - The default state to fall back to
40
+ * @returns The state in current format
41
+ */
42
+ protected abstract fromPersistedState(persistedState: TPersistedState, defaultState: TState): TState;
43
+ /**
44
+ * Abstract method to get the service name for error messages.
45
+ * Must be implemented by subclasses.
46
+ *
47
+ * @returns The service name
48
+ */
49
+ protected abstract getServiceName(): string;
50
+ /**
51
+ * Saves the current state to localStorage.
52
+ *
53
+ * @protected
54
+ */
55
+ protected saveState(): void;
56
+ /**
57
+ * Loads previously persisted state from localStorage.
58
+ * If no state exists or loading fails, keeps the current state.
59
+ *
60
+ * @protected
61
+ */
62
+ protected loadState(): void;
63
+ /**
64
+ * Notifies all subscribed listeners about state changes.
65
+ *
66
+ * @protected
67
+ */
68
+ protected notifySubscribers(): void;
69
+ /**
70
+ * Updates the state using an updater function, persists the new state,
71
+ * and notifies all subscribers if the state changed.
72
+ *
73
+ * @param updater - Function that receives current state and returns new state
74
+ * @protected
75
+ */
76
+ protected setState(updater: (state: TState) => TState): void;
77
+ /**
78
+ * Returns the current state snapshot for useSyncExternalStore.
79
+ *
80
+ * @returns The current state
81
+ */
82
+ getSnapshot: () => TState;
83
+ /**
84
+ * Subscribes a listener to state changes for useSyncExternalStore.
85
+ *
86
+ * @param listener - Function to call when state changes
87
+ * @returns Unsubscribe function
88
+ */
89
+ subscribe: (listener: () => void) => (() => void);
90
+ }
@@ -0,0 +1,90 @@
1
+ class r {
2
+ /** Set of listeners subscribed to state changes */
3
+ listeners = /* @__PURE__ */ new Set();
4
+ /** The localStorage key for persisting state */
5
+ storageKey;
6
+ /** Whether this store should persist state to localStorage */
7
+ shouldPersist;
8
+ /** The current state */
9
+ state;
10
+ /**
11
+ * Creates a new BaseStoreService instance.
12
+ *
13
+ * @param storageKey - The localStorage key for persisting state (used only if shouldPersist is true)
14
+ * @param defaultState - The default state value
15
+ * @param shouldLoadOnInit - Whether to load persisted state on initialization (only works if shouldPersist is true)
16
+ * @param shouldPersist - Whether to persist state to localStorage (default: true)
17
+ */
18
+ constructor(t, e, a = !0, s = !0) {
19
+ this.storageKey = t, this.shouldPersist = s, this.state = e, a && s && this.loadState();
20
+ }
21
+ /**
22
+ * Saves the current state to localStorage.
23
+ *
24
+ * @protected
25
+ */
26
+ saveState() {
27
+ if (this.shouldPersist)
28
+ try {
29
+ const t = this.toPersistableState(this.state);
30
+ localStorage.setItem(this.storageKey, JSON.stringify(t));
31
+ } catch {
32
+ console.warn(`Failed to save ${this.getServiceName()} state to localStorage`);
33
+ }
34
+ }
35
+ /**
36
+ * Loads previously persisted state from localStorage.
37
+ * If no state exists or loading fails, keeps the current state.
38
+ *
39
+ * @protected
40
+ */
41
+ loadState() {
42
+ if (this.shouldPersist)
43
+ try {
44
+ const t = localStorage.getItem(this.storageKey);
45
+ if (t) {
46
+ const e = JSON.parse(t);
47
+ this.state = this.fromPersistedState(e, this.state);
48
+ }
49
+ } catch {
50
+ console.warn(`Failed to load persisted ${this.getServiceName()} state from localStorage`);
51
+ }
52
+ }
53
+ /**
54
+ * Notifies all subscribed listeners about state changes.
55
+ *
56
+ * @protected
57
+ */
58
+ notifySubscribers() {
59
+ this.listeners.forEach((t) => t());
60
+ }
61
+ /**
62
+ * Updates the state using an updater function, persists the new state,
63
+ * and notifies all subscribers if the state changed.
64
+ *
65
+ * @param updater - Function that receives current state and returns new state
66
+ * @protected
67
+ */
68
+ setState(t) {
69
+ const e = t(this.state);
70
+ JSON.stringify(e) !== JSON.stringify(this.state) && (this.state = e, this.saveState(), this.notifySubscribers());
71
+ }
72
+ /**
73
+ * Returns the current state snapshot for useSyncExternalStore.
74
+ *
75
+ * @returns The current state
76
+ */
77
+ getSnapshot = () => this.state;
78
+ /**
79
+ * Subscribes a listener to state changes for useSyncExternalStore.
80
+ *
81
+ * @param listener - Function to call when state changes
82
+ * @returns Unsubscribe function
83
+ */
84
+ subscribe = (t) => (this.listeners.add(t), () => {
85
+ this.listeners.delete(t);
86
+ });
87
+ }
88
+ export {
89
+ r as BaseStoreService
90
+ };
@@ -0,0 +1,40 @@
1
+ import { ControlsGroup } from '../components/ControlRenderer/controls/types';
2
+ import { DevPanelSection } from '../components/DevPanel/types';
3
+ type SectionsState = Record<string, DevPanelSection>;
4
+ /**
5
+ * React hook that subscribes only to the sections state of the dev panel.
6
+ * This hook will not re-render when UI state (position, visibility) changes.
7
+ *
8
+ * @returns Record of section names to section objects
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const sections = useDevPanelSections();
13
+ * const sectionNames = Object.keys(sections);
14
+ * ```
15
+ */
16
+ export declare function useDevPanelSections(): SectionsState;
17
+ /**
18
+ * React hook that provides access to section actions without subscribing to state.
19
+ * Ideal for components that only need to trigger section actions without rendering on changes.
20
+ *
21
+ * @returns Object containing all available section actions
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const { registerSection, toggleSectionCollapse } = useDevPanelSectionActions();
26
+ *
27
+ * // Add a new section
28
+ * registerSection('mySection', myControls);
29
+ *
30
+ * // Toggle section collapse
31
+ * toggleSectionCollapse('mySection');
32
+ * ```
33
+ */
34
+ export declare function useDevPanelSectionActions(): {
35
+ registerSection: (name: string, controls: ControlsGroup) => void;
36
+ unregisterSection: (name: string) => void;
37
+ toggleSectionCollapse: (name: string) => void;
38
+ reset: () => void;
39
+ };
40
+ export {};
@@ -0,0 +1,7 @@
1
+ import "react";
2
+ import "./BaseStoreService.js";
3
+ import { a, u as i } from "../UIStore-CQdr4U-2.js";
4
+ export {
5
+ a as useDevPanelSectionActions,
6
+ i as useDevPanelSections
7
+ };
@@ -1,28 +1,25 @@
1
- import { ControlsGroup } from '../components/ControlRenderer/controls/types';
2
- import { DevPanelState, Position } from '../components/DevPanel/types';
1
+ import { DevPanelUIState, Position } from '../components/DevPanel/types';
3
2
  /**
4
- * React hook that provides access to the complete dev panel state and actions.
3
+ * React hook that provides access to the complete dev panel UI state and actions.
5
4
  * Uses useSyncExternalStore for optimal performance and React 18 compatibility.
5
+ * This hook will not re-render when sections state changes.
6
6
  *
7
- * @returns Object containing the current state and all available actions
7
+ * @returns Object containing the current UI state and all available UI actions
8
8
  *
9
9
  * @example
10
10
  * ```typescript
11
11
  * const {
12
12
  * isVisible,
13
- * sections,
13
+ * position,
14
14
  * setVisible,
15
- * registerSection
16
- * } = useDevPanelStore();
15
+ * setPosition
16
+ * } = useDevPanelUI();
17
17
  * ```
18
18
  */
19
- export declare function useDevPanelStore(): DevPanelState & {
19
+ export declare function useDevPanelUI(): DevPanelUIState & {
20
20
  setVisible: (visible: boolean) => void;
21
21
  setCollapsed: (collapsed: boolean) => void;
22
22
  setPosition: (position: Position) => void;
23
- registerSection: (name: string, controls: ControlsGroup) => void;
24
- unregisterSection: (name: string) => void;
25
- toggleSectionCollapse: (name: string) => void;
26
23
  reset: () => void;
27
24
  };
28
25
  /**
@@ -63,44 +60,29 @@ export declare function useDevPanelCollapsed(): boolean;
63
60
  */
64
61
  export declare function useDevPanelPosition(): Position;
65
62
  /**
66
- * React hook that subscribes only to the sections state of the dev panel.
67
- * Optimized for components that only need to access panel sections.
63
+ * React hook that provides access to all dev panel UI actions without subscribing to state.
64
+ * Ideal for components that only need to trigger UI actions without rendering on state changes.
68
65
  *
69
- * @returns Record of section names to section objects
66
+ * @returns Object containing all available UI actions
70
67
  *
71
68
  * @example
72
69
  * ```typescript
73
- * const sections = useDevPanelSections();
74
- * const sectionNames = Object.keys(sections);
75
- * ```
76
- */
77
- export declare function useDevPanelSections(): Record<string, import('../components/DevPanel/types').DevPanelSection>;
78
- /**
79
- * React hook that provides access to all dev panel actions without subscribing to state.
80
- * Ideal for components that only need to trigger actions without rendering on state changes.
81
- *
82
- * @returns Object containing all available actions
83
- *
84
- * @example
85
- * ```typescript
86
- * const { setVisible, registerSection, reset } = useDevPanelActions();
70
+ * const { setVisible, setPosition, reset } = useDevPanelUIActions();
87
71
  *
88
72
  * // Toggle panel visibility
89
73
  * setVisible(true);
90
74
  *
91
- * // Add a new section
92
- * registerSection('mySection', myControls);
75
+ * // Update position
76
+ * setPosition({ x: 100, y: 100 });
93
77
  *
94
- * // Reset everything
78
+ * // Reset UI state
95
79
  * reset();
96
80
  * ```
97
81
  */
98
- export declare function useDevPanelActions(): {
82
+ export declare function useDevPanelUIActions(): {
99
83
  setVisible: (visible: boolean) => void;
100
84
  setCollapsed: (collapsed: boolean) => void;
101
85
  setPosition: (position: Position) => void;
102
- registerSection: (name: string, controls: ControlsGroup) => void;
103
- unregisterSection: (name: string) => void;
104
- toggleSectionCollapse: (name: string) => void;
105
86
  reset: () => void;
106
87
  };
88
+ export declare const useDevPanelStore: typeof useDevPanelUI;
@@ -0,0 +1,11 @@
1
+ import "react";
2
+ import "./BaseStoreService.js";
3
+ import { d as o, e as n, g as i, b as P, f as t, c as u } from "../UIStore-CQdr4U-2.js";
4
+ export {
5
+ o as useDevPanelCollapsed,
6
+ n as useDevPanelPosition,
7
+ i as useDevPanelStore,
8
+ P as useDevPanelUI,
9
+ t as useDevPanelUIActions,
10
+ u as useDevPanelVisible
11
+ };
@@ -1 +1,3 @@
1
- export * from './store';
1
+ export * from './BaseStoreService';
2
+ export * from './SectionsStore';
3
+ export * from './UIStore';
@@ -1,9 +1,13 @@
1
- import { useDevPanelActions as l, useDevPanelCollapsed as n, useDevPanelPosition as o, useDevPanelSections as a, useDevPanelStore as P, useDevPanelVisible as i } from "./store.js";
1
+ import { BaseStoreService as a } from "./BaseStoreService.js";
2
+ import { d as o, e as l, a as i, u as t, g as u, b as v, f as P, c as D } from "../UIStore-CQdr4U-2.js";
2
3
  export {
3
- l as useDevPanelActions,
4
- n as useDevPanelCollapsed,
5
- o as useDevPanelPosition,
6
- a as useDevPanelSections,
7
- P as useDevPanelStore,
8
- i as useDevPanelVisible
4
+ a as BaseStoreService,
5
+ o as useDevPanelCollapsed,
6
+ l as useDevPanelPosition,
7
+ i as useDevPanelSectionActions,
8
+ t as useDevPanelSections,
9
+ u as useDevPanelStore,
10
+ v as useDevPanelUI,
11
+ P as useDevPanelUIActions,
12
+ D as useDevPanelVisible
9
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "private": false,
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "type": "module",
5
5
  "module": "./dist/index.js",
6
6
  "name": "@berenjena/react-dev-panel",