Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/image [email protected] #2691

Merged
merged 17 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<>
Expand All @@ -29,14 +33,14 @@ const ImageViewerBasic = ({ ...props }: any) => {
>
<ImageViewerBackdrop>
<ImageViewerContent
//@ts-ignore
images={Images}
renderImages={(item: any) => (
<ImageViewerImage key={item.id} source={{ uri: item.url }} />
renderImages={({ item }) => (
<ImageViewerImage source={{ uri: item.url }} />
)}
keyExtractor={(item, index) => item.id + '-' + index}
>
<ImageViewerCloseButton>
<Icon as={CloseIcon}/>
<Icon as={CloseIcon} />
</ImageViewerCloseButton>
</ImageViewerContent>
</ImageViewerBackdrop>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
Icon,
Center,
} from '../../core-components/nativewind';
import {
import {
Pressable,
Image
} from 'react-native';
Expand Down Expand Up @@ -60,23 +60,29 @@ This is an illustration of **ImageViewer** component.
const Images = [{ id: 1, url: 'https://picsum.photos/1000/1000' }];
return (
<Center>
<Pressable onPress={() => setVisible(true)}>
<Image
source={{ uri: Images[0].url }}
className="w-[200px] h-[200px]"
resizeMode="contain"
/>
</Pressable>
<ImageViewer isOpen={visible} onClose={() => setVisible(false)}>
<ImageViewerBackdrop>
<ImageViewerContent images={Images} renderImages={(item) => (<ImageViewerImage key={item.id} source={{ uri: item.url }} />)} >
<ImageViewerCloseButton>
<Icon as={CloseIcon}/>
</ImageViewerCloseButton>
</ImageViewerContent>
</ImageViewerBackdrop>
</ImageViewer>
</Center>
<Pressable onPress={() => setVisible(true)}>
<Image
source={{ uri: Images[0].url }}
className="w-[200px] h-[200px]"
resizeMode="contain"
/>
</Pressable>
<ImageViewer isOpen={visible} onClose={() => setVisible(false)}>
<ImageViewerBackdrop>
<ImageViewerContent
images={Images}
renderImages={(item) => (
<ImageViewerImage key={item.id} source={{ uri: item.url }} />
)}
keyExtractor={(item, index) => item.id + '-' + index}
>
<ImageViewerCloseButton>
<Icon as={CloseIcon}/>
</ImageViewerCloseButton>
</ImageViewerContent>
</ImageViewerBackdrop>
</ImageViewer>
</Center>
);
}
`,
Expand Down Expand Up @@ -306,6 +312,27 @@ The `ImageViewerContent` component is responsible for rendering the images withi
<Table.TText>Yes</Table.TText>
</Table.TD>
</Table.TR>
<Table.TR>
<Table.TD>
<Table.TText>
<InlineCode>keyExtractor</InlineCode>
</Table.TText>
</Table.TD>
<Table.TD>
<Table.TText>
<InlineCode>(item: any, index: number) => string</InlineCode>
</Table.TText>
</Table.TD>
<Table.TD>
<Table.TText>-</Table.TText>
</Table.TD>
<Table.TD>
<Table.TText>Function to extract the key for each image item</Table.TText>
</Table.TD>
<Table.TD>
<Table.TText>Yes</Table.TText>
</Table.TD>
</Table.TR>
</Table.TBody>
</Table>
</TableContainer>
Expand Down Expand Up @@ -350,23 +377,29 @@ import { Center } from '@/components/ui/center';
const Images = [{ id: 1, url: 'https://picsum.photos/1000/1000' }];
return (
<Center>
<Pressable onPress={() => setVisible(true)}>
<Image
source={{ uri: Images[0].url }}
className="w-[200px] h-[200px]"
resizeMode="contain"
/>
</Pressable>
<ImageViewer isOpen={visible} onClose={() => setVisible(false)}>
<ImageViewerBackdrop>
<ImageViewerContent images={Images} renderImages={(item) => (<ImageViewerImage key={item.id} source={{ uri: item.url }} />)} >
<ImageViewerCloseButton>
<Icon as={CloseIcon}/>
</ImageViewerCloseButton>
</ImageViewerContent>
</ImageViewerBackdrop>
</ImageViewer>
</Center>
<Pressable onPress={() => setVisible(true)}>
<Image
source={{ uri: Images[0].url }}
className="w-[200px] h-[200px]"
resizeMode="contain"
/>
</Pressable>
<ImageViewer isOpen={visible} onClose={() => setVisible(false)}>
<ImageViewerBackdrop>
<ImageViewerContent
images={Images}
renderImages={(item) => (
<ImageViewerImage key={item.id} source={{ uri: item.url }} />
)}
keyExtractor={(item, index) => item.id + '-' + index}
>
<ImageViewerCloseButton>
<Icon as={CloseIcon}/>
</ImageViewerCloseButton>
</ImageViewerContent>
</ImageViewerBackdrop>
</ImageViewer>
</Center>
);
}
`,
Expand Down
6 changes: 6 additions & 0 deletions packages/unstyled/image-viewer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @gluestack-ui/image-viewer

## 0.0.6

### Patch Changes

- fix: fixed typings, added keyExtractor, improved pinch gesture and made working on native

## 0.0.5

### Patch Changes
Expand Down
10 changes: 6 additions & 4 deletions packages/unstyled/image-viewer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export default () => (
renderImages={(item) => (
<ImageViewerImage key={item.id} source={{ uri: item.url }} />
)}
keyExtractor={(item, index) => `${item.id}-${index}`}
/>
</ImageViewerBackdrop>
</ImageViewer>
Expand All @@ -88,10 +89,11 @@ export default () => (

### ImageViewerContent

| Prop | Type | Default | Description |
| ------------ | ------------------------ | ------- | ---------------------------------- |
| images | Array<any> | - | Array of image objects to display |
| renderImages | (item: any) => ReactNode | - | Function to render each image item |
| Prop | Type | Default | Description |
| ------------ | ------------------------------------ | ------- | ----------------------------------------------- |
| images | Array<any> | - | 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).

Expand Down
2 changes: 1 addition & 1 deletion packages/unstyled/image-viewer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gluestack-ui/image-viewer",
"version": "0.0.5",
"version": "0.0.6",
"main": "lib/index",
"module": "lib/index",
"types": "lib/index.d.ts",
Expand Down
4 changes: 2 additions & 2 deletions packages/unstyled/image-viewer/src/ImageViewer.tsx
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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);
Expand Down
20 changes: 15 additions & 5 deletions packages/unstyled/image-viewer/src/ImageViewerContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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;
})
Expand Down Expand Up @@ -147,7 +148,7 @@ const ImageViewerContent = (
);

const animatedStyle = useAnimatedStyle(() => {
setScale(scale.value);
runOnJS(setScale)(scale.value);
if (scale.value <= 1) {
}
return {
Expand All @@ -165,7 +166,16 @@ const ImageViewerContent = (
{children}
<StyledGestureDetector gesture={composedGesture}>
<StyledAnimated style={animatedStyle}>
{images.map(renderImages)}
{images.slice(0, 1).map((item: any, index: number) => {
const RenderImage = renderImages;
return (
<RenderImage
key={keyExtractor ? keyExtractor(item, index) : index}
item={item}
index={index}
/>
);
})}
</StyledAnimated>
</StyledGestureDetector>
</StyledGestureHandlerRootView>
Expand Down
47 changes: 37 additions & 10 deletions packages/unstyled/image-viewer/src/types.ts
Original file line number Diff line number Diff line change
@@ -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<any>;
/**
* 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<
Expand All @@ -31,10 +56,12 @@ export type IImageViewerComponentType<
ImageViewerBackdropProps
> = React.ForwardRefExoticComponent<
React.PropsWithoutRef<ImageViewerProps> &
InterfaceImageViewerProps &
React.RefAttributes<ImageViewerProps>
> & {
Content: React.ForwardRefExoticComponent<
React.PropsWithoutRef<ImageViewerContentProps> &
InterfaceImageViewerContentProps &
React.RefAttributes<ImageViewerContentProps>
>;
CloseButton: React.ForwardRefExoticComponent<
Expand Down
Loading