Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 64x 64x 27x 27x 15x 15x 64x 64x 64x 64x 64x 27x 27x 27x 27x 64x 15x 15x 64x 54x 27x 54x 64x 64x 64x | import { useState, useCallback, useEffect, useRef } from "react";
import type { PanelSettings } from "../types";
import { DEFAULT_SETTINGS, DEFAULT_STORAGE_KEY } from "../constants";
import { safeGetJSON, safeSetJSON, isBrowser } from "../utils/storage";
/**
* Options for useSettings hook
*/
export interface UseSettingsOptions {
/** Storage key for persistence */
storageKey?: string;
/** Whether to persist settings */
persist?: boolean;
/** Initial settings override */
initialSettings?: Partial<PanelSettings>;
}
/**
* Return type for useSettings hook
*/
export interface UseSettingsReturn {
/** Current settings */
settings: PanelSettings;
/** Update settings (partial update) */
updateSettings: (updates: Partial<PanelSettings>) => void;
/** Reset settings to defaults */
resetSettings: () => void;
/** Whether settings have been loaded */
isLoaded: boolean;
}
/**
* Debounce function for saving settings
*/
function debounce<T extends (...args: never[]) => void>(
fn: T,
delay: number
): T {
let timeoutId: ReturnType<typeof setTimeout> | null = null;
return ((...args: Parameters<T>) => {
Iif (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
fn(...args);
timeoutId = null;
}, delay);
}) as T;
}
/**
* Hook to manage panel settings with optional persistence
*
* @param options - Configuration options
* @returns Settings and update functions
*
* @example
* ```tsx
* const { settings, updateSettings } = useSettings({
* storageKey: 'my-panel-settings',
* persist: true,
* });
*
* // Update a single setting
* updateSettings({ warningThreshold: 80 });
* ```
*/
export function useSettings(options: UseSettingsOptions = {}): UseSettingsReturn {
const {
storageKey = DEFAULT_STORAGE_KEY,
persist = true,
initialSettings = {},
} = options;
const [isLoaded, setIsLoaded] = useState(false);
const [settings, setSettings] = useState<PanelSettings>(() => ({
...DEFAULT_SETTINGS,
...initialSettings,
}));
// Ref to track if we should save
const shouldSaveRef = useRef(false);
// Load settings from storage on mount
useEffect(() => {
Iif (!isBrowser() || !persist) {
setIsLoaded(true);
return;
}
const stored = safeGetJSON<Partial<PanelSettings>>(storageKey, {});
setSettings((prev) => ({
...prev,
...stored,
}));
setIsLoaded(true);
}, [storageKey, persist]);
// Debounced save function
const saveToStorage = useCallback(
debounce((settingsToSave: PanelSettings) => {
Eif (persist && isBrowser()) {
safeSetJSON(storageKey, settingsToSave);
}
}, 500),
[storageKey, persist]
);
// Save settings when they change
useEffect(() => {
if (shouldSaveRef.current && isLoaded) {
saveToStorage(settings);
}
shouldSaveRef.current = true;
}, [settings, saveToStorage, isLoaded]);
const updateSettings = useCallback((updates: Partial<PanelSettings>) => {
setSettings((prev) => ({
...prev,
...updates,
}));
}, []);
const resetSettings = useCallback(() => {
setSettings({ ...DEFAULT_SETTINGS, ...initialSettings });
if (persist && isBrowser()) {
safeSetJSON(storageKey, { ...DEFAULT_SETTINGS, ...initialSettings });
}
}, [initialSettings, persist, storageKey]);
return {
settings,
updateSettings,
resetSettings,
isLoaded,
};
}
|