{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "z-page-file-drop-root",
  "title": "Z Page File Drop Root",
  "dependencies": [
    "react-dropzone@15.0.0"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://ui.orchid.ai/r/orchid-foundation.json",
    "https://ui.orchid.ai/r/orchid-theme.json"
  ],
  "files": [
    {
      "path": "registry/ui/orchid/spectrum/molecules/z-page-file-drop-root/z-page-file-drop-root.tsx",
      "content": "\"use client\";\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';\nimport { type DropEvent, type FileRejection, useDropzone } from 'react-dropzone';\nimport { cn } from \"../../../lib/ui-utils\";\ntype DropHandler = (files: File[]) => void | Promise<void>;\ntype PageFileDropContextValue = {\n    isDefaultAiDropActive: boolean;\n    registerAiDropHandler: (id: string, handler: DropHandler | null) => void;\n    setOverrideActive: (id: string, isActive: boolean) => void;\n    setDefaultAiDropSuppressed: (id: string, isSuppressed: boolean) => void;\n    suppressDefaultAiDropOnce: () => void;\n};\nconst PageFileDropContext = createContext<PageFileDropContextValue | null>(null);\ntype Props = {\n    children: React.ReactNode;\n    enabled?: boolean;\n    className?: string;\n};\nexport function ZPageFileDropRoot({ children, enabled = true, className }: Props) {\n    const aiDropHandlersRef = useRef(new Map<string, DropHandler>());\n    const activeOverrideIdsRef = useRef(new Set<string>());\n    const suppressedDefaultAiDropIdsRef = useRef(new Set<string>());\n    const suppressedDefaultAiDropsRef = useRef(0);\n    const [activeOverrideCount, setActiveOverrideCount] = useState(0);\n    const [suppressedDefaultAiDropCount, setSuppressedDefaultAiDropCount] = useState(0);\n    const registerAiDropHandler = useCallback((id: string, handler: DropHandler | null) => {\n        const aiDropHandlers = aiDropHandlersRef.current;\n        if (handler) {\n            if (!aiDropHandlers.has(id) && aiDropHandlers.size > 0) {\n                throw new Error('ZPageFileDropRoot supports only one page-default AI drop handler.');\n            }\n            aiDropHandlers.set(id, handler);\n            return;\n        }\n        aiDropHandlers.delete(id);\n    }, []);\n    const setOverrideActive = useCallback((id: string, isActive: boolean) => {\n        const activeOverrideIds = activeOverrideIdsRef.current;\n        const previousSize = activeOverrideIds.size;\n        if (isActive) {\n            activeOverrideIds.add(id);\n        }\n        else {\n            activeOverrideIds.delete(id);\n        }\n        if (activeOverrideIds.size !== previousSize) {\n            setActiveOverrideCount(activeOverrideIds.size);\n        }\n    }, []);\n    const setDefaultAiDropSuppressed = useCallback((id: string, isSuppressed: boolean) => {\n        const suppressedIds = suppressedDefaultAiDropIdsRef.current;\n        const previousSize = suppressedIds.size;\n        if (isSuppressed) {\n            suppressedIds.add(id);\n        }\n        else {\n            suppressedIds.delete(id);\n        }\n        if (suppressedIds.size !== previousSize) {\n            setSuppressedDefaultAiDropCount(suppressedIds.size);\n        }\n    }, []);\n    const handleDrop = useCallback((files: File[], _: FileRejection[], event: DropEvent) => {\n        if (shouldIgnorePageDefaultDrop(files, event)) {\n            return;\n        }\n        if (suppressedDefaultAiDropIdsRef.current.size > 0) {\n            return;\n        }\n        if (suppressedDefaultAiDropsRef.current > 0) {\n            suppressedDefaultAiDropsRef.current -= 1;\n            return;\n        }\n        if (activeOverrideIdsRef.current.size > 0) {\n            return;\n        }\n        if (files.length === 0) {\n            return;\n        }\n        const aiDropHandler = aiDropHandlersRef.current.values().next().value;\n        void aiDropHandler?.(files);\n    }, []);\n    const { getRootProps, getInputProps, isDragActive } = useDropzone({\n        noClick: true,\n        noKeyboard: true,\n        noDragEventsBubbling: false,\n        preventDropOnDocument: true,\n        disabled: !enabled,\n        onDrop: handleDrop,\n    });\n    const contextValue = useMemo<PageFileDropContextValue>(() => ({\n        isDefaultAiDropActive: isDragActive && activeOverrideCount === 0 && suppressedDefaultAiDropCount === 0,\n        registerAiDropHandler,\n        setOverrideActive,\n        setDefaultAiDropSuppressed,\n        suppressDefaultAiDropOnce: () => {\n            suppressedDefaultAiDropsRef.current += 1;\n        },\n    }), [\n        activeOverrideCount,\n        isDragActive,\n        registerAiDropHandler,\n        setDefaultAiDropSuppressed,\n        setOverrideActive,\n        suppressedDefaultAiDropCount,\n    ]);\n    return (<PageFileDropContext.Provider value={contextValue}>\n      <div {...getRootProps({ className: cn(className) })}>\n        <input {...getInputProps({ className: 'hidden', tabIndex: -1 })}/>\n        {children}\n      </div>\n    </PageFileDropContext.Provider>);\n}\nexport function usePageFileDropContext() {\n    return useContext(PageFileDropContext);\n}\nfunction shouldIgnorePageDefaultDrop(files: File[], event: DropEvent) {\n    if (!isDropInsideRichEditor(event)) {\n        return false;\n    }\n    if (files.length === 0) {\n        return false;\n    }\n    return files.every((file) => file.type.startsWith('image/'));\n}\nfunction isDropInsideRichEditor(event: DropEvent) {\n    if (!('target' in event)) {\n        return false;\n    }\n    const target = event.target;\n    return target instanceof HTMLElement && !!target.closest('[contenteditable=\"true\"]');\n}\n",
      "type": "registry:ui",
      "target": "@ui/orchid/spectrum/molecules/z-page-file-drop-root/z-page-file-drop-root.tsx"
    }
  ],
  "type": "registry:ui"
}