{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "use-array-state",
  "title": "UseArrayState",
  "description": "Manages an array as a React state with built-in array manipulation methods.",
  "files": [
    {
      "path": "registry/hooks/use-array-state.ts",
      "content": "'use client';\n\nimport { useCallback, useMemo, useState } from 'react';\n\nexport type UseArrayStateResult<T> = {\n  array: T[];\n  length: number;\n  push: (...items: T[]) => void;\n  pop: () => T | undefined;\n  shift: () => T | undefined;\n  unshift: (...items: T[]) => void;\n  insert: (index: number, ...items: T[]) => void;\n  remove: (index: number) => void;\n  removeWhere: (predicate: (item: T, index: number) => boolean) => void;\n  update: (index: number, item: T) => void;\n  updateWhere: (\n    predicate: (item: T, index: number) => boolean,\n    newItem: T,\n  ) => void;\n  clear: () => void;\n  reset: () => void;\n  setValue: (newArray: T[]) => void;\n  filter: (predicate: (item: T, index: number) => boolean) => void;\n  sort: (compareFn?: (a: T, b: T) => number) => void;\n  reverse: () => void;\n  map: <U>(transform: (item: T, index: number) => U) => U[];\n  find: (predicate: (item: T, index: number) => boolean) => T | undefined;\n  findIndex: (predicate: (item: T, index: number) => boolean) => number;\n  includes: (item: T) => boolean;\n  indexOf: (item: T) => number;\n  slice: (start?: number, end?: number) => T[];\n  isEmpty: boolean;\n  first: T | undefined;\n  last: T | undefined;\n};\n\nexport interface UseArrayStateOptions<T> {\n  /**\n   * Initial array value\n   */\n  initialValue?: T[];\n  /**\n   * Callback called whenever the array changes\n   */\n  onChange?: (array: T[]) => void;\n}\n\n/**\n * Manages an array as a React state with built-in array manipulation methods\n * @param options - Configuration options for the hook\n * @returns Object with array state and manipulation methods\n */\nexport function useArrayState<T>(\n  options: UseArrayStateOptions<T> = {},\n): UseArrayStateResult<T> {\n  const { initialValue = [], onChange } = options;\n\n  const [array, setArray] = useState<T[]>(initialValue);\n  const initialArray = useMemo(() => [...initialValue], [initialValue]);\n\n  // Helper to update array and call onChange\n  const updateArray = useCallback(\n    (newArray: T[]) => {\n      setArray(newArray);\n      if (onChange) {\n        onChange(newArray);\n      }\n    },\n    [onChange],\n  );\n\n  // Array manipulation methods\n  const push = useCallback(\n    (...items: T[]) => {\n      setArray((prev) => {\n        const newArray = [...prev, ...items];\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const pop = useCallback(() => {\n    let poppedItem: T | undefined;\n    setArray((prev) => {\n      if (prev.length === 0) return prev;\n      const newArray = [...prev];\n      poppedItem = newArray.pop();\n      if (onChange) onChange(newArray);\n      return newArray;\n    });\n    return poppedItem;\n  }, [onChange]);\n\n  const shift = useCallback(() => {\n    let shiftedItem: T | undefined;\n    setArray((prev) => {\n      if (prev.length === 0) return prev;\n      const newArray = [...prev];\n      shiftedItem = newArray.shift();\n      if (onChange) onChange(newArray);\n      return newArray;\n    });\n    return shiftedItem;\n  }, [onChange]);\n\n  const unshift = useCallback(\n    (...items: T[]) => {\n      setArray((prev) => {\n        const newArray = [...items, ...prev];\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const insert = useCallback(\n    (index: number, ...items: T[]) => {\n      setArray((prev) => {\n        const newArray = [...prev];\n        newArray.splice(index, 0, ...items);\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const remove = useCallback(\n    (index: number) => {\n      setArray((prev) => {\n        if (index < 0 || index >= prev.length) return prev;\n        const newArray = [...prev];\n        newArray.splice(index, 1);\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const removeWhere = useCallback(\n    (predicate: (item: T, index: number) => boolean) => {\n      setArray((prev) => {\n        const newArray = prev.filter((item, index) => !predicate(item, index));\n        if (newArray.length !== prev.length && onChange) {\n          onChange(newArray);\n        }\n        return newArray.length !== prev.length ? newArray : prev;\n      });\n    },\n    [onChange],\n  );\n\n  const update = useCallback(\n    (index: number, item: T) => {\n      setArray((prev) => {\n        if (index < 0 || index >= prev.length) return prev;\n        if (prev[index] === item) return prev;\n        const newArray = [...prev];\n        newArray[index] = item;\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const updateWhere = useCallback(\n    (predicate: (item: T, index: number) => boolean, newItem: T) => {\n      setArray((prev) => {\n        const index = prev.findIndex(predicate);\n        if (index === -1 || prev[index] === newItem) return prev;\n        const newArray = [...prev];\n        newArray[index] = newItem;\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const clear = useCallback(() => {\n    setArray((prev) => {\n      if (prev.length === 0) return prev;\n      const newArray: T[] = [];\n      if (onChange) onChange(newArray);\n      return newArray;\n    });\n  }, [onChange]);\n\n  const reset = useCallback(() => {\n    setArray((prev) => {\n      const newArray = [...initialArray];\n      if (JSON.stringify(prev) === JSON.stringify(newArray)) return prev;\n      if (onChange) onChange(newArray);\n      return newArray;\n    });\n  }, [initialArray, onChange]);\n\n  const setValue = useCallback(\n    (newArray: T[]) => {\n      setArray((prev) => {\n        if (JSON.stringify(prev) === JSON.stringify(newArray)) return prev;\n        if (onChange) onChange(newArray);\n        return newArray;\n      });\n    },\n    [onChange],\n  );\n\n  const filter = useCallback(\n    (predicate: (item: T, index: number) => boolean) => {\n      setArray((prev) => {\n        const newArray = prev.filter(predicate);\n        if (newArray.length !== prev.length && onChange) {\n          onChange(newArray);\n        }\n        return newArray.length !== prev.length ? newArray : prev;\n      });\n    },\n    [onChange],\n  );\n\n  const sort = useCallback(\n    (compareFn?: (a: T, b: T) => number) => {\n      setArray((prev) => {\n        const newArray = [...prev].sort(compareFn);\n        if (JSON.stringify(prev) !== JSON.stringify(newArray) && onChange) {\n          onChange(newArray);\n        }\n        return JSON.stringify(prev) !== JSON.stringify(newArray)\n          ? newArray\n          : prev;\n      });\n    },\n    [onChange],\n  );\n\n  const reverse = useCallback(() => {\n    setArray((prev) => {\n      if (prev.length <= 1) return prev;\n      const newArray = [...prev].reverse();\n      if (onChange) onChange(newArray);\n      return newArray;\n    });\n  }, [onChange]);\n\n  // Read-only methods\n  const map = useCallback(\n    <U>(transform: (item: T, index: number) => U): U[] => {\n      return array.map(transform);\n    },\n    [array],\n  );\n\n  const find = useCallback(\n    (predicate: (item: T, index: number) => boolean): T | undefined => {\n      return array.find(predicate);\n    },\n    [array],\n  );\n\n  const findIndex = useCallback(\n    (predicate: (item: T, index: number) => boolean): number => {\n      return array.findIndex(predicate);\n    },\n    [array],\n  );\n\n  const includes = useCallback(\n    (item: T): boolean => {\n      return array.includes(item);\n    },\n    [array],\n  );\n\n  const indexOf = useCallback(\n    (item: T): number => {\n      return array.indexOf(item);\n    },\n    [array],\n  );\n\n  const slice = useCallback(\n    (start?: number, end?: number): T[] => {\n      return array.slice(start, end);\n    },\n    [array],\n  );\n\n  // Computed properties\n  const length = array.length;\n  const isEmpty = length === 0;\n  const first = length > 0 ? array[0] : undefined;\n  const last = length > 0 ? array[length - 1] : undefined;\n\n  return {\n    array,\n    length,\n    push,\n    pop,\n    shift,\n    unshift,\n    insert,\n    remove,\n    removeWhere,\n    update,\n    updateWhere,\n    clear,\n    reset,\n    setValue,\n    filter,\n    sort,\n    reverse,\n    map,\n    find,\n    findIndex,\n    includes,\n    indexOf,\n    slice,\n    isEmpty,\n    first,\n    last,\n  };\n}\n",
      "type": "registry:hook",
      "target": "hooks/guarahooks/use-array-state.ts"
    }
  ],
  "categories": [
    "state-management"
  ],
  "type": "registry:hook"
}