(options: UseFileSystemOptions = {})
| 88 | * const fs = useFileSystem({ useLocalApi: true }); |
| 89 | */ |
| 90 | export function useFileSystem(options: UseFileSystemOptions = {}): UseFileSystemReturn { |
| 91 | const { useLocalApi = false, fileApi: customFileApi, loadFromCloud = false } = options; |
| 92 | |
| 93 | // Create store (only on first render) |
| 94 | const storeRef = useRef<FileSystemStore | null>(null); |
| 95 | if (!storeRef.current) { |
| 96 | // Priority: customFileApi > useLocalApi > default real API |
| 97 | const api = customFileApi || (useLocalApi ? createLocalFileApi() : defaultFileApi); |
| 98 | storeRef.current = createFileSystemStore(api); |
| 99 | } |
| 100 | const store = storeRef.current; |
| 101 | |
| 102 | // State |
| 103 | const [, forceUpdate] = useState({}); |
| 104 | const [isLoading, setIsLoading] = useState(loadFromCloud); |
| 105 | const [error, setError] = useState<Error | null>(null); |
| 106 | |
| 107 | // Subscribe to store changes |
| 108 | useEffect(() => { |
| 109 | const unsubscribe = store.subscribe(() => { |
| 110 | forceUpdate({}); |
| 111 | }); |
| 112 | return unsubscribe; |
| 113 | }, [store]); |
| 114 | |
| 115 | // Initialize from cloud |
| 116 | useEffect(() => { |
| 117 | if (loadFromCloud) { |
| 118 | store |
| 119 | .initFromCloud() |
| 120 | .then(() => { |
| 121 | setIsLoading(false); |
| 122 | }) |
| 123 | .catch((err) => { |
| 124 | setError(err); |
| 125 | setIsLoading(false); |
| 126 | }); |
| 127 | } |
| 128 | }, [store, loadFromCloud]); |
| 129 | |
| 130 | // Query methods |
| 131 | const getById = useCallback((id: string) => store.getById(id), [store]); |
| 132 | const getByPath = useCallback((path: string) => store.getByPath(path), [store]); |
| 133 | const getChildren = useCallback((nodeId: string) => store.getChildren(nodeId), [store]); |
| 134 | const getChildrenByPath = useCallback((path: string) => store.getChildrenByPath(path), [store]); |
| 135 | const exists = useCallback((path: string) => store.exists(path), [store]); |
| 136 | |
| 137 | // Write methods |
| 138 | const addNode = useCallback((params: CreateFileNodeParams) => store.addNode(params), [store]); |
| 139 | const updateNode = useCallback( |
| 140 | (id: string, updates: UpdateFileNodeParams) => store.updateNode(id, updates), |
| 141 | [store], |
| 142 | ); |
| 143 | const removeNode = useCallback((id: string) => store.removeNode(id), [store]); |
| 144 | const removeByPath = useCallback((path: string) => store.removeByPath(path), [store]); |
| 145 | const moveNode = useCallback( |
| 146 | (id: string, newPath: string) => store.moveNode(id, newPath), |
| 147 | [store], |
no test coverage detected