UNPKG

react-native-gesture-image-viewer

Version:

🖼️ React Native Image Viewer - Reanimated-powered image gestures with full control

127 lines (126 loc) 3.8 kB
"use strict"; import { useCallback, useMemo, useRef, useSyncExternalStore } from 'react'; import { registry } from "./GestureViewerRegistry.js"; /** * Hook to control the gesture viewer programmatically. * * @param id - Viewer instance identifier (default: 'default') * @returns Methods and state for controlling the viewer * * **Available methods:** * - `goToIndex(index: number)` - Navigate to specific index (0 to totalCount-1) * - `goToPrevious()` - Navigate to previous item * - `goToNext()` - Navigate to next item * - `zoomIn(multiplier?: number)` - Zoom in (default: 0.25) * - `zoomOut(multiplier?: number)` - Zoom out (default: 0.25) * - `resetZoom(scale?: number)` - Reset zoom level (default: 1.0) * - `rotate(angle?: 0|90|180|270|360, clockwise?: boolean)` - Rotate content (default: 90° clockwise) * * **Available state:** * - `currentIndex: number` - Current active index (read-only) * - `totalCount: number` - Total number of items (read-only) * * @example * ```tsx * const { goToIndex, goToNext, goToPrevious, zoomIn, zoomOut, resetZoom, rotate, currentIndex, totalCount } = useGestureViewerController(); * * // Navigate to specific index * goToIndex(2); * * // Go to next image * goToNext(); * * // Zoom in by 25% * zoomIn(); * * // Zoom out by 50% * zoomOut(0.5); * * // Reset to original size * resetZoom(); * * // Rotate 90 degrees clockwise * rotate(); * * // Rotate 180 degrees * rotate(180); * * // Check current state * console.log(`Image ${currentIndex + 1} of ${totalCount}`); * * // Check navigation availability * const canGoNext = currentIndex < totalCount - 1; * const canGoPrevious = currentIndex > 0; * ``` */ export const useGestureViewerController = (id = 'default') => { const managerRef = useRef(null); const stateRef = useRef({ currentIndex: 0, totalCount: 0 }); const updateState = useCallback((newState, onStoreChange) => { if (stateRef.current.currentIndex !== newState.currentIndex || stateRef.current.totalCount !== newState.totalCount) { stateRef.current = { currentIndex: newState.currentIndex, totalCount: newState.totalCount }; onStoreChange(); } }, []); const subscribe = useCallback(onStoreChange => { let unsubscribeFromManager = null; const unsubscribeFromRegistry = registry.subscribeToManager(id, newManager => { unsubscribeFromManager?.(); unsubscribeFromManager = null; managerRef.current = newManager; if (newManager) { unsubscribeFromManager = newManager.subscribe(newState => { updateState(newState, onStoreChange); }); updateState(newManager.getState(), onStoreChange); return; } updateState({ currentIndex: 0, totalCount: 0 }, onStoreChange); }); return () => { unsubscribeFromRegistry(); unsubscribeFromManager?.(); }; }, [id, updateState]); const getSnapshot = useCallback(() => { return stateRef.current; }, []); const state = useSyncExternalStore(subscribe, getSnapshot); const controller = useMemo(() => ({ goToIndex: index => { managerRef.current?.goToIndex(index); }, goToPrevious: () => { managerRef.current?.goToPrevious(); }, goToNext: () => { managerRef.current?.goToNext(); }, zoomIn: multiplier => { managerRef.current?.zoomIn(multiplier); }, zoomOut: multiplier => { managerRef.current?.zoomOut(multiplier); }, resetZoom: scale => { managerRef.current?.resetZoom(scale); }, rotate: (angle, clockwise) => { managerRef.current?.rotate(angle, clockwise); } }), []); return { ...controller, ...state }; }; //# sourceMappingURL=useGestureViewerController.js.map