{
  "name": "use-controllable-value",
  "author": "Brendan Dash (https://shadcn-hooks.com)",
  "description": "A hook to manage a controllable value",
  "dependencies": [
    "es-toolkit"
  ],
  "registryDependencies": [
    "@shadcnhooks/use-memoized-fn",
    "@shadcnhooks/use-update"
  ],
  "files": [
    {
      "path": "registry/hooks/use-controllable-value.ts",
      "content": "import { isFunction } from 'es-toolkit/predicate'\nimport { useMemo, useRef } from 'react'\nimport { useMemoizedFn } from '@/registry/hooks/use-memoized-fn'\nimport { useUpdate } from '@/registry/hooks/use-update'\nimport type { SetStateAction } from 'react'\n\nexport interface Options<T> {\n  defaultValue?: T\n  defaultValuePropName?: string\n  valuePropName?: string\n  trigger?: string\n}\n\nexport type Props = Record<string, any>\n\nexport interface StandardProps<T> {\n  value: T\n  defaultValue?: T\n  onChange: (val: T) => void\n}\n\nfunction useControllableValue<T = any>(\n  props: StandardProps<T>,\n): [T, (v: SetStateAction<T>) => void]\nfunction useControllableValue<T = any>(\n  props?: Props,\n  options?: Options<T>,\n): [T, (v: SetStateAction<T>, ...args: any[]) => void]\nfunction useControllableValue<T = any>(\n  defaultProps?: Props,\n  options: Options<T> = {},\n) {\n  const props = defaultProps ?? {}\n\n  const {\n    defaultValue,\n    defaultValuePropName = 'defaultValue',\n    valuePropName = 'value',\n    trigger = 'onChange',\n  } = options\n\n  const value = props[valuePropName] as T\n  const isControlled = Object.prototype.hasOwnProperty.call(\n    props,\n    valuePropName,\n  )\n\n  const initialValue = useMemo(() => {\n    if (isControlled) {\n      return value\n    }\n    if (Object.prototype.hasOwnProperty.call(props, defaultValuePropName)) {\n      return props[defaultValuePropName]\n    }\n    return defaultValue\n  }, [])\n\n  const stateRef = useRef(initialValue)\n  if (isControlled) {\n    stateRef.current = value\n  }\n\n  const update = useUpdate()\n\n  const setState = (v: SetStateAction<T>, ...args: any[]) => {\n    const r = isFunction(v) ? v(stateRef.current) : v\n\n    if (!isControlled) {\n      stateRef.current = r\n      update()\n    }\n    if (props[trigger]) {\n      props[trigger](r, ...args)\n    }\n  }\n\n  return [stateRef.current, useMemoizedFn(setState)] as const\n}\n\nexport { useControllableValue }\n",
      "type": "registry:hook"
    }
  ],
  "type": "registry:hook"
}
