import { useQueryStates } from 'nuqs';
import { useCallback, useMemo, useRef } from 'react';
import { useColorMode } from '../components/setup/color-mode';
import { getBackgroundLightProps } from '../constants/backgroundThemeProps';
const isHexColor = value => typeof value === 'string' && /^#?[0-9a-fA-F]{3,8}$/.test(value);
const sameValue = (a, b) => (Array.isArray(a) || Array.isArray(b) ? JSON.stringify(a) === JSON.stringify(b) : a === b);
const createParser = defaultValue => {
if (Array.isArray(defaultValue)) {
return {
parse: v =>
v === null || v === ''
? null
: v.split(',').map(item => (isHexColor(item) && !item.startsWith('#') ? `#${item}` : item)),
serialize: v =>
Array.isArray(v) ? v.map(item => (isHexColor(item) ? item.replace(/^#/, '') : item)).join(',') : String(v),
eq: sameValue
};
}
if (typeof defaultValue === 'number') {
return {
parse: v => (v === null || v === '' ? null : Number(v)),
serialize: v => String(v),
eq: (a, b) => a === b
};
}
if (typeof defaultValue === 'boolean') {
return {
parse: v => (v === null || v === '' ? null : v === 'true'),
serialize: v => String(v),
eq: (a, b) => a === b
};
}
if (typeof defaultValue === 'string' && defaultValue.startsWith('#') && isHexColor(defaultValue)) {
return {
parse: v => (v === null || v === '' ? null : `#${v}`),
serialize: v => v.replace(/^#/, ''),
eq: (a, b) => a === b
};
}
return {
parse: v => (v === null || v === '' ? null : v),
serialize: v => String(v),
eq: (a, b) => a === b
};
};
export function useComponentProps(defaultProps) {
const defaultPropsRef = useRef(defaultProps);
const { colorMode } = useColorMode();
const lightProps = useMemo(() => getBackgroundLightProps(), []);
const effectiveDefaultProps = useMemo(
() =>
colorMode === 'light' && lightProps ? { ...defaultPropsRef.current, ...lightProps } : defaultPropsRef.current,
[colorMode, lightProps]
);
const parsers = useMemo(() => {
const result = {};
for (const [key, defaultValue] of Object.entries(defaultPropsRef.current)) {
result[key] = createParser(defaultValue);
}
return result;
}, []);
const [queryState, setQueryState] = useQueryStates(parsers);
const props = useMemo(() => {
const merged = { ...effectiveDefaultProps };
for (const [key, value] of Object.entries(queryState)) {
if (value !== null) {
merged[key] = value;
}
}
return merged;
}, [effectiveDefaultProps, queryState]);
const hasChanges = useMemo(() => {
return Object.values(queryState).some(v => v !== null);
}, [queryState]);
const updateProp = useCallback(
(name, value) => {
const newValue = sameValue(value, effectiveDefaultProps[name]) ? null : value;
setQueryState({ [name]: newValue });
},
[effectiveDefaultProps, setQueryState]
);
const updateProps = useCallback(
updates => {
const newState = {};
for (const [name, value] of Object.entries(updates)) {
newState[name] = sameValue(value, effectiveDefaultProps[name]) ? null : value;
}
setQueryState(newState);
},
[effectiveDefaultProps, setQueryState]
);
const resetProps = useCallback(() => {
const resetState = {};
for (const key of Object.keys(defaultPropsRef.current)) {
resetState[key] = null;
}
setQueryState(resetState);
}, [setQueryState]);
const getShareUrl = useCallback(() => {
return window.location.href;
}, []);
return {
props,
defaultProps: effectiveDefaultProps,
updateProp,
updateProps,
resetProps,
hasChanges,
getShareUrl
};
}
export default useComponentProps;