diff --git a/example/storybook-nativewind/src/components/ImageViewer/ImageViewer.tsx b/example/storybook-nativewind/src/components/ImageViewer/ImageViewer.tsx index 40d2baee0..394892c95 100644 --- a/example/storybook-nativewind/src/components/ImageViewer/ImageViewer.tsx +++ b/example/storybook-nativewind/src/components/ImageViewer/ImageViewer.tsx @@ -10,7 +10,11 @@ import { import { Icon, CloseIcon } from '@/components/ui/icon'; const ImageViewerBasic = ({ ...props }: any) => { - const Images = [{ id: 1, url: 'https://picsum.photos/1000/1000' }]; + const Images = [ + { id: 1, url: 'https://picsum.photos/1000/1000', title: 'Image 1' }, + { id: 2, url: 'https://picsum.photos/1000/1000', title: 'Image 2' }, + { id: 3, url: 'https://picsum.photos/1000/1000', title: 'Image 3' }, + ]; const [visible, setVisible] = useState(false); return ( <> @@ -29,14 +33,14 @@ const ImageViewerBasic = ({ ...props }: any) => { > ( - + renderImages={({ item }) => ( + )} + keyExtractor={(item, index) => item.id + '-' + index} > - + diff --git a/example/storybook-nativewind/src/components/ImageViewer/index.nw.stories.mdx b/example/storybook-nativewind/src/components/ImageViewer/index.nw.stories.mdx index 8aac1d23b..2a47bdcd0 100644 --- a/example/storybook-nativewind/src/components/ImageViewer/index.nw.stories.mdx +++ b/example/storybook-nativewind/src/components/ImageViewer/index.nw.stories.mdx @@ -24,7 +24,7 @@ import { Icon, Center, } from '../../core-components/nativewind'; -import { +import { Pressable, Image } from 'react-native'; @@ -60,23 +60,29 @@ This is an illustration of **ImageViewer** component. const Images = [{ id: 1, url: 'https://picsum.photos/1000/1000' }]; return (
- setVisible(true)}> - - - setVisible(false)}> - - ()} > - - - - - - -
+ setVisible(true)}> + + + setVisible(false)}> + + ( + + )} + keyExtractor={(item, index) => item.id + '-' + index} + > + + + + + + + ); } `, @@ -306,6 +312,27 @@ The `ImageViewerContent` component is responsible for rendering the images withi Yes + + + + keyExtractor + + + + + (item: any, index: number) => string + + + + - + + + Function to extract the key for each image item + + + Yes + + @@ -350,23 +377,29 @@ import { Center } from '@/components/ui/center'; const Images = [{ id: 1, url: 'https://picsum.photos/1000/1000' }]; return (
- setVisible(true)}> - - - setVisible(false)}> - - ()} > - - - - - - -
+ setVisible(true)}> + + + setVisible(false)}> + + ( + + )} + keyExtractor={(item, index) => item.id + '-' + index} + > + + + + + + + ); } `, diff --git a/packages/unstyled/image-viewer/README.md b/packages/unstyled/image-viewer/README.md index e971c9abf..f1edbcf15 100644 --- a/packages/unstyled/image-viewer/README.md +++ b/packages/unstyled/image-viewer/README.md @@ -70,6 +70,7 @@ export default () => ( renderImages={(item) => ( )} + keyExtractor={(item, index) => `${item.id}-${index}`} /> @@ -88,10 +89,11 @@ export default () => ( ### ImageViewerContent -| Prop | Type | Default | Description | -| ------------ | ------------------------ | ------- | ---------------------------------- | -| images | Array | - | Array of image objects to display | -| renderImages | (item: any) => ReactNode | - | Function to render each image item | +| Prop | Type | Default | Description | +| ------------ | ------------------------------------ | ------- | ----------------------------------------------- | +| images | Array | - | Array of image objects to display | +| renderImages | (item: any) => ReactNode | - | Function to render each image item | +| keyExtractor | (item: any, index: number) => string | - | Function to extract the key for each image item | More guides on how to get started are available [here](https://ui.gluestack.io/docs/components/media-and-icons/image-viewer). diff --git a/packages/unstyled/image-viewer/src/ImageViewer.tsx b/packages/unstyled/image-viewer/src/ImageViewer.tsx index b2ae941e8..0de94c9c0 100644 --- a/packages/unstyled/image-viewer/src/ImageViewer.tsx +++ b/packages/unstyled/image-viewer/src/ImageViewer.tsx @@ -1,6 +1,6 @@ import React, { forwardRef } from 'react'; import { ImageViewerContext } from './ImageViewerContext'; -import type { ImageViewerProps } from './types'; +import type { InterfaceImageViewerProps } from './types'; const ImageViewer = (StyledRoot: any) => forwardRef( @@ -10,7 +10,7 @@ const ImageViewer = (StyledRoot: any) => isOpen, onClose, ...props - }: ImageViewerProps & { children: React.ReactNode }, + }: InterfaceImageViewerProps & { children: React.ReactNode }, ref?: any ) => { const [scale, setScale] = React.useState(1); diff --git a/packages/unstyled/image-viewer/src/ImageViewerContent.tsx b/packages/unstyled/image-viewer/src/ImageViewerContent.tsx index 24ff15e8c..3d44dbe0e 100644 --- a/packages/unstyled/image-viewer/src/ImageViewerContent.tsx +++ b/packages/unstyled/image-viewer/src/ImageViewerContent.tsx @@ -8,7 +8,7 @@ import { withTiming, } from 'react-native-reanimated'; import { Dimensions, StatusBar } from 'react-native'; -import type { ImageViewerContentProps } from './types'; +import type { InterfaceImageViewerContentProps } from './types'; const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = Dimensions.get('window'); const DOUBLE_TAP_DELAY = 300; @@ -24,8 +24,9 @@ const ImageViewerContent = ( { images, renderImages, + keyExtractor, children, - }: ImageViewerContentProps & { children: React.ReactNode }, + }: InterfaceImageViewerContentProps & { children: React.ReactNode }, ref?: any ) => { const { onClose, setScale }: any = useContext(ImageViewerContext); @@ -45,7 +46,7 @@ const ImageViewerContent = ( .onUpdate((event: any) => { // Apply the new scale based on the saved scale value const newScale = savedScale.value * event.scale; - scale.value = Math.min(Math.max(newScale, 0.5), 3); + scale.value = Math.min(Math.max(newScale, 0.5), 10); focalX.value = event.focalX; focalY.value = event.focalY; }) @@ -147,7 +148,7 @@ const ImageViewerContent = ( ); const animatedStyle = useAnimatedStyle(() => { - setScale(scale.value); + runOnJS(setScale)(scale.value); if (scale.value <= 1) { } return { @@ -165,7 +166,16 @@ const ImageViewerContent = ( {children} - {images.map(renderImages)} + {images.slice(0, 1).map((item: any, index: number) => { + const RenderImage = renderImages; + return ( + + ); + })} diff --git a/packages/unstyled/image-viewer/src/types.ts b/packages/unstyled/image-viewer/src/types.ts index 57e5347e2..1d01468c7 100644 --- a/packages/unstyled/image-viewer/src/types.ts +++ b/packages/unstyled/image-viewer/src/types.ts @@ -1,27 +1,52 @@ export interface ImageViewerContext { + /** + * Callback invoked when the ImageViewer is closed. + */ onClose: () => void; + /** + * If true, the ImageViewer will open. Useful for controllable state behavior. + */ isOpen: boolean | undefined; + /** + * The current scale of the Image. + */ scale: number | undefined; + /** + * Callback function to set the scale of the Image to be used in backdrop for adjusting the opacity. + */ setScale: (scale: number) => void; } -export interface ImageViewerProps { +export interface InterfaceImageViewerProps { /** - * If true, the modal will open. Useful for controllable state behavior. + * If true, the ImageViewer will open. Useful for controllable state behavior. */ - isOpen?: boolean; + isOpen: boolean; /** - * Callback invoked when the modal is closed. + * Callback invoked when the ImageViewer is closed. */ onClose?: any; - /** - * If true, the modal will be opened by default. - */ } -export interface ImageViewerContentProps { - images: any; - renderImages: (item: any) => React.ReactNode; +export interface InterfaceImageViewerContentProps { + /** + * The images to display in the ImageViewer. + */ + images: Array; + /** + * Callback React.ReactNode function to render the images. + */ + renderImages: ({ + item, + index, + }: { + item: any; + index: number; + }) => React.ReactNode; + /** + * Callback function to extract the key for the images. + */ + keyExtractor: (item: any, index: number) => React.Attributes['key']; } export type IImageViewerComponentType< @@ -31,10 +56,12 @@ export type IImageViewerComponentType< ImageViewerBackdropProps > = React.ForwardRefExoticComponent< React.PropsWithoutRef & + InterfaceImageViewerProps & React.RefAttributes > & { Content: React.ForwardRefExoticComponent< React.PropsWithoutRef & + InterfaceImageViewerContentProps & React.RefAttributes >; CloseButton: React.ForwardRefExoticComponent<