Skip to content

Commit 8ff4fe5

Browse files
committed
feat(Gallery): add a hook for opening the gallery from the custom content
1 parent 8266e89 commit 8ff4fe5

File tree

12 files changed

+286
-27
lines changed

12 files changed

+286
-27
lines changed

src/components/Gallery/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The children of the Gallery should be an array of [GalleryItem with the required
1212
| open | `Boolean` | | | | The modal opened state |
1313
| onOpenChange | `(open: boolean) => void` | | | | The modal toggle handler |
1414
| className | `String` | | | | The modal class |
15+
| container | `HTMLElement` | | | | The modal container |
1516
| emptyMessage | `String` | | | No data | No data message |
1617

1718
### GalleryItem

src/components/Gallery/__stories__/mockData.ts

+32-27
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,36 @@
11
export const images = [
2-
'https://i.pinimg.com/originals/d8/bd/b4/d8bdb45a931b4265bec8e8d3f15021bf.jpg',
3-
'https://i.pinimg.com/originals/c2/31/a0/c231a069c5e24099723564dae736f438.jpg',
4-
'https://cs4.pikabu.ru/post_img/big/2015/02/27/6/1425024947_2006737473.jpeg',
5-
'https://i.pinimg.com/originals/ef/7b/97/ef7b9724ad06cd6dfce92193e95a5caa.jpg',
6-
'https://avatars.mds.yandex.net/i?id=ea31df78678a1b3f4f1fb7199090831d_l-5235412-images-thumbs&n=13',
7-
'https://i.ytimg.com/vi/WA63GQpLzjA/maxresdefault.jpg',
8-
'https://i.pinimg.com/originals/02/eb/fd/02ebfd63d5435ec87c7413b8b2428214.jpg',
9-
'https://mir-s3-cdn-cf.behance.net/project_modules/max_3840/2b800731080995.5640a39521da5.jpg',
10-
'https://pic.rutubelist.ru/video/7a/1b/7a1b88f88ff7a470ea6f8131d51c2c5c.jpg',
11-
'https://i.pinimg.com/originals/4b/c7/ed/4bc7ed612f2080303644deb0f857b70f.jpg',
12-
'https://img1.reactor.cc/pics/post/нейроарт-нейронные-сети-красивые-картинки-art-7821877.png',
13-
'https://steamuserimages-a.akamaihd.net/ugc/841461304090603934/D3243F5856FEAE2052FC7CDB748B5BB65E6B247A/?imw=512&imh=306&ima=fit&impolicy=Letterbox&imcolor=%23000000&letterbox=true',
14-
'https://celes.club/uploads/posts/2022-06/1654752045_50-celes-club-p-multyashnii-kosmos-oboi-krasivie-53.jpg',
15-
// duplicate the list to show the previews scroll
16-
'https://i.pinimg.com/originals/d8/bd/b4/d8bdb45a931b4265bec8e8d3f15021bf.jpg',
17-
'https://i.pinimg.com/originals/c2/31/a0/c231a069c5e24099723564dae736f438.jpg',
18-
'https://cs4.pikabu.ru/post_img/big/2015/02/27/6/1425024947_2006737473.jpeg',
19-
'https://i.pinimg.com/originals/ef/7b/97/ef7b9724ad06cd6dfce92193e95a5caa.jpg',
20-
'https://avatars.mds.yandex.net/i?id=ea31df78678a1b3f4f1fb7199090831d_l-5235412-images-thumbs&n=13',
21-
'https://i.ytimg.com/vi/WA63GQpLzjA/maxresdefault.jpg',
22-
'https://i.pinimg.com/originals/02/eb/fd/02ebfd63d5435ec87c7413b8b2428214.jpg',
23-
'https://mir-s3-cdn-cf.behance.net/project_modules/max_3840/2b800731080995.5640a39521da5.jpg',
24-
'https://pic.rutubelist.ru/video/7a/1b/7a1b88f88ff7a470ea6f8131d51c2c5c.jpg',
25-
'https://i.pinimg.com/originals/4b/c7/ed/4bc7ed612f2080303644deb0f857b70f.jpg',
26-
'https://img1.reactor.cc/pics/post/нейроарт-нейронные-сети-красивые-картинки-art-7821877.png',
27-
'https://steamuserimages-a.akamaihd.net/ugc/841461304090603934/D3243F5856FEAE2052FC7CDB748B5BB65E6B247A/?imw=512&imh=306&ima=fit&impolicy=Letterbox&imcolor=%23000000&letterbox=true',
28-
'https://celes.club/uploads/posts/2022-06/1654752045_50-celes-club-p-multyashnii-kosmos-oboi-krasivie-53.jpg',
2+
'https://i.pinimg.com/originals/e7/44/1a/e7441aebde7c4d5a5afc476d5fa87082.jpg',
3+
'https://i.pinimg.com/736x/46/81/f0/4681f0072c3b5b8a96fdf78c4e12037c.jpg',
4+
'https://i.pinimg.com/736x/ae/2a/a3/ae2aa360b9c18d0be08ef7279ab81638.jpg',
5+
'https://i.pinimg.com/originals/42/b4/eb/42b4ebb23e452387a84c3ad02295003f.jpg',
6+
'https://i.pinimg.com/736x/3a/e0/af/3ae0af7c666a284847d682156b8a6496.jpg',
7+
'https://i.pinimg.com/736x/30/91/28/3091283eeff577749c5e3c81a9af7ce1.jpg',
8+
'https://i.pinimg.com/736x/61/ce/22/61ce22263ae275efa9b9c7b02b3dea61.jpg',
9+
'https://i.pinimg.com/736x/72/70/a6/7270a6d918468fcce5c297afc281bf35.jpg',
10+
'https://i.pinimg.com/originals/cc/8d/cf/cc8dcfb1f6bcb54a2836019558027ef7.jpg',
11+
'https://i.pinimg.com/736x/cd/74/75/cd7475dd2fa19d339e147b627896c5d4.jpg',
12+
'https://i.pinimg.com/736x/aa/21/dd/aa21ddd2b3de5298953ca0762838951e.jpg',
13+
'https://i.pinimg.com/originals/9c/3a/16/9c3a161254af0369c2a32bae240da2ff.jpg',
14+
'https://i.pinimg.com/originals/d0/48/41/d048413c59db4dd7d1e332da991ce347.jpg',
15+
'https://i.pinimg.com/736x/a9/4a/4b/a94a4b6810787f415166bc9d0bef71eb.jpg',
16+
'https://i.pinimg.com/736x/9c/b2/d1/9cb2d19f5cf6bdb53b7c1f42f480db3f.jpg',
17+
'https://i.pinimg.com/736x/34/94/5e/34945e08218f073f4f1d3b147108b06a.jpg',
18+
'https://i.pinimg.com/originals/a6/30/93/a6309348c1dab1899d022b8759dc659b.jpg',
19+
'https://i.pinimg.com/736x/69/e0/aa/69e0aac5a17f8790da23dcc379e6fd05.jpg',
20+
'https://i.pinimg.com/736x/e3/f2/b4/e3f2b4f87a0ae9744a0b14c81710463c.jpg',
21+
'https://i.pinimg.com/736x/f0/d4/01/f0d4011c75b92f165dbab83c8654ebf1.jpg',
22+
'https://i.pinimg.com/736x/69/51/5a/69515a0da57d33b5df80d5af0c14ef7e.jpg',
23+
'https://i.pinimg.com/736x/07/b6/f5/07b6f527be3860832e55e6ec041766b6.jpg',
24+
'https://i.pinimg.com/originals/32/a3/30/32a33050f32ba74c2b66456d458cb792.jpg',
25+
'https://i.pinimg.com/originals/07/73/12/077312668712ae5aba52766b5b3e2b8e.jpg',
26+
'https://i.pinimg.com/736x/5d/15/35/5d1535227d2eb616b21113d69e5cf49b.jpg',
27+
'https://i.pinimg.com/736x/12/e5/5a/12e55a138ef6345d359d9f6cf0715a5d.jpg',
28+
'https://i.pinimg.com/736x/90/da/f6/90daf6e058bc377b1a3c1cf53d63bde7.jpg',
29+
'https://i.pinimg.com/originals/0f/e4/66/0fe4667784f51ac62a7fbb8c84b16f2f.jpg',
30+
'https://i.pinimg.com/736x/ed/11/1e/ed111e9003c2d972b7e09816deef26de.jpg',
31+
'https://i.pinimg.com/736x/cf/4e/ac/cf4eac1954a1c1b4c9d43dbb8f8752a8.jpg',
32+
'https://i.pinimg.com/originals/ee/50/90/ee509026a73aae62ef3ffd1860f2db5f.jpg',
33+
'https://i.pinimg.com/originals/d8/a0/53/d8a0536b3855ee1cdeaaf1eb3bb71aed.jpg',
2934
];
3035

3136
export type GalleryFile =

src/hooks/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './useGallery';

src/hooks/useGallery/Gallery.tsx

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as React from 'react';
2+
3+
export const Gallery = React.lazy(() =>
4+
import('../../components/Gallery/Gallery').then((module) => ({default: module.Gallery})),
5+
);
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react';
2+
3+
import type {GalleryItemProps} from '../../components';
4+
5+
export type GalleryContextType = {
6+
openGallery: (items: GalleryItemProps[], initialFileIndex?: number) => void;
7+
};
8+
9+
export const GalleryContext = React.createContext<GalleryContextType>({
10+
openGallery: () => {},
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import * as React from 'react';
2+
3+
import {ThemeProvider} from '@gravity-ui/uikit';
4+
import type {ThemeProviderProps} from '@gravity-ui/uikit';
5+
6+
import {GalleryItem} from '../../components';
7+
import type {GalleryItemProps, GalleryProps} from '../../components';
8+
9+
import {Gallery} from './Gallery';
10+
import {GalleryContext} from './GalleryContext';
11+
import type {GalleryContextType} from './GalleryContext';
12+
13+
export type GalleryContextProviderProps = React.PropsWithChildren<
14+
Pick<GalleryProps, 'container' | 'className' | 'emptyMessage'>
15+
> &
16+
Pick<ThemeProviderProps, 'theme'>;
17+
18+
export const GalleryContextProvider = ({
19+
children,
20+
container,
21+
emptyMessage,
22+
theme,
23+
className,
24+
}: GalleryContextProviderProps) => {
25+
const [isOpen, setIsOpen] = React.useState(false);
26+
const [{items, initialItemIndex}, setGalleryProps] = React.useState<{
27+
items: GalleryItemProps[];
28+
initialItemIndex: number;
29+
}>({items: [], initialItemIndex: 0});
30+
31+
const contextValue = React.useMemo<GalleryContextType>(
32+
() => ({
33+
openGallery: (items, initialFileIndex) => {
34+
setGalleryProps({
35+
items,
36+
initialItemIndex: initialFileIndex ?? 0,
37+
});
38+
setIsOpen(true);
39+
},
40+
}),
41+
[],
42+
);
43+
44+
return (
45+
<GalleryContext.Provider value={contextValue}>
46+
{children}
47+
{isOpen && (
48+
<React.Suspense fallback={null}>
49+
<ThemeProvider theme={theme}>
50+
<Gallery
51+
open={isOpen}
52+
onOpenChange={setIsOpen}
53+
container={container}
54+
className={className}
55+
emptyMessage={emptyMessage}
56+
initialItemIndex={initialItemIndex}
57+
>
58+
{items.map((file, index) => (
59+
<GalleryItem key={index} {...file} />
60+
))}
61+
</Gallery>
62+
</ThemeProvider>
63+
</React.Suspense>
64+
)}
65+
</GalleryContext.Provider>
66+
);
67+
};

src/hooks/useGallery/README.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
## useGallery
2+
3+
The hook for opening the gallery
4+
5+
### PropTypes
6+
7+
_GalleryContextProvider_:
8+
9+
| Property | Type | Required | Values | Default | Description |
10+
| :----------- | :---------------------------- | :------- | :----- | :------ | :------------------ |
11+
| theme | `ThemeProviderProps['theme']` | | | `dark` | The gallery theme |
12+
| className | `String` | | | | The modal class |
13+
| container | `HTMLElement` | | | | The modal container |
14+
| emptyMessage | `String` | | | No data | No data message |
15+
16+
_openFilesGallery returns function with args_:
17+
18+
| Property | Type | Required | Values | Default | Description |
19+
| :--------------- | :-------------- | :------- | :----- | :------ | :--------------------- |
20+
| items | `GalleryItem[]` | Yes | | | The gallery items |
21+
| initialItemIndex | `number` | | | 0 | The initial item index |
22+
23+
### Usage
24+
25+
First you should wrap your content into the GalleryContextProvider to be able to use the hook
26+
27+
```tsx
28+
import {GalleryContextProvider} from '@gravity-ui/components';
29+
30+
<GalleryContextProvider theme="dark" emptyMessage="Seems like your gallery is empty!">
31+
children
32+
</GalleryContextProvider>;
33+
```
34+
35+
Then use the hook inside your custom hooks or components
36+
37+
```tsx
38+
import {useGallery, getGalleryItemImage} from '@gravity-ui/components';
39+
40+
const openGallery = useGallery();
41+
42+
const images = [
43+
'https://i.pinimg.com/originals/d8/bd/b4/d8bdb45a931b4265bec8e8d3f15021bf.jpg',
44+
'https://i.pinimg.com/originals/c2/31/a0/c231a069c5e24099723564dae736f438.jpg',
45+
];
46+
47+
openGallery(
48+
images.map((image) => getGalleryItemImage({src: image, name: image})),
49+
2,
50+
);
51+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import {FilePreview, Text} from '@gravity-ui/uikit';
2+
3+
import {getGalleryItemImage} from '../../../components';
4+
import {GalleryContextProvider} from '../GalleryContextProvider';
5+
import {useGallery} from '../useGallery';
6+
7+
import {images} from './mockData';
8+
9+
const UseGalleryExample = () => {
10+
const openGallery = useGallery();
11+
12+
const handleOpen = (index: number) => {
13+
openGallery(
14+
images.map((image) => getGalleryItemImage({src: image, name: image})),
15+
index,
16+
);
17+
};
18+
19+
return (
20+
<div>
21+
<Text variant="subheader-3" as={'h2' as const}>
22+
Click an item to open the gallery
23+
</Text>
24+
<div
25+
style={{
26+
display: 'grid',
27+
justifyItems: 'center',
28+
alignItems: 'center',
29+
gridTemplateColumns: 'repeat(6, 1fr)',
30+
gridGap: 8,
31+
width: 800,
32+
}}
33+
>
34+
{images.map((image, index) => (
35+
<FilePreview
36+
onClick={() => handleOpen(index)}
37+
key={image}
38+
imageSrc={image}
39+
file={{name: image, type: 'image/jpeg'} as File}
40+
/>
41+
))}
42+
</div>
43+
</div>
44+
);
45+
};
46+
47+
export const UseGalleryShowcase = () => {
48+
return (
49+
<GalleryContextProvider>
50+
<UseGalleryExample />
51+
</GalleryContextProvider>
52+
);
53+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export const images = [
2+
'https://i.pinimg.com/originals/e7/44/1a/e7441aebde7c4d5a5afc476d5fa87082.jpg',
3+
'https://i.pinimg.com/736x/46/81/f0/4681f0072c3b5b8a96fdf78c4e12037c.jpg',
4+
'https://i.pinimg.com/736x/ae/2a/a3/ae2aa360b9c18d0be08ef7279ab81638.jpg',
5+
'https://i.pinimg.com/originals/42/b4/eb/42b4ebb23e452387a84c3ad02295003f.jpg',
6+
'https://i.pinimg.com/736x/3a/e0/af/3ae0af7c666a284847d682156b8a6496.jpg',
7+
'https://i.pinimg.com/736x/30/91/28/3091283eeff577749c5e3c81a9af7ce1.jpg',
8+
'https://i.pinimg.com/736x/61/ce/22/61ce22263ae275efa9b9c7b02b3dea61.jpg',
9+
'https://i.pinimg.com/736x/72/70/a6/7270a6d918468fcce5c297afc281bf35.jpg',
10+
'https://i.pinimg.com/originals/cc/8d/cf/cc8dcfb1f6bcb54a2836019558027ef7.jpg',
11+
'https://i.pinimg.com/736x/cd/74/75/cd7475dd2fa19d339e147b627896c5d4.jpg',
12+
'https://i.pinimg.com/736x/aa/21/dd/aa21ddd2b3de5298953ca0762838951e.jpg',
13+
'https://i.pinimg.com/originals/9c/3a/16/9c3a161254af0369c2a32bae240da2ff.jpg',
14+
'https://i.pinimg.com/originals/d0/48/41/d048413c59db4dd7d1e332da991ce347.jpg',
15+
'https://i.pinimg.com/736x/a9/4a/4b/a94a4b6810787f415166bc9d0bef71eb.jpg',
16+
'https://i.pinimg.com/736x/9c/b2/d1/9cb2d19f5cf6bdb53b7c1f42f480db3f.jpg',
17+
'https://i.pinimg.com/736x/34/94/5e/34945e08218f073f4f1d3b147108b06a.jpg',
18+
'https://i.pinimg.com/originals/a6/30/93/a6309348c1dab1899d022b8759dc659b.jpg',
19+
'https://i.pinimg.com/736x/69/e0/aa/69e0aac5a17f8790da23dcc379e6fd05.jpg',
20+
'https://i.pinimg.com/736x/e3/f2/b4/e3f2b4f87a0ae9744a0b14c81710463c.jpg',
21+
'https://i.pinimg.com/736x/f0/d4/01/f0d4011c75b92f165dbab83c8654ebf1.jpg',
22+
'https://i.pinimg.com/736x/69/51/5a/69515a0da57d33b5df80d5af0c14ef7e.jpg',
23+
'https://i.pinimg.com/736x/07/b6/f5/07b6f527be3860832e55e6ec041766b6.jpg',
24+
'https://i.pinimg.com/originals/32/a3/30/32a33050f32ba74c2b66456d458cb792.jpg',
25+
'https://i.pinimg.com/originals/07/73/12/077312668712ae5aba52766b5b3e2b8e.jpg',
26+
'https://i.pinimg.com/736x/5d/15/35/5d1535227d2eb616b21113d69e5cf49b.jpg',
27+
'https://i.pinimg.com/736x/12/e5/5a/12e55a138ef6345d359d9f6cf0715a5d.jpg',
28+
'https://i.pinimg.com/736x/90/da/f6/90daf6e058bc377b1a3c1cf53d63bde7.jpg',
29+
'https://i.pinimg.com/originals/0f/e4/66/0fe4667784f51ac62a7fbb8c84b16f2f.jpg',
30+
'https://i.pinimg.com/736x/ed/11/1e/ed111e9003c2d972b7e09816deef26de.jpg',
31+
'https://i.pinimg.com/736x/cf/4e/ac/cf4eac1954a1c1b4c9d43dbb8f8752a8.jpg',
32+
'https://i.pinimg.com/originals/ee/50/90/ee509026a73aae62ef3ffd1860f2db5f.jpg',
33+
'https://i.pinimg.com/originals/d8/a0/53/d8a0536b3855ee1cdeaaf1eb3bb71aed.jpg',
34+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type {Meta} from '@storybook/react';
2+
3+
import {UseGalleryShowcase} from './UseGalleryShowcase';
4+
5+
export default {
6+
title: 'Hooks/useGallery',
7+
parameters: {
8+
a11y: {
9+
element: '#storybook-root',
10+
config: {
11+
rules: [
12+
{
13+
id: 'color-contrast',
14+
enabled: false,
15+
},
16+
],
17+
},
18+
},
19+
},
20+
} as Meta;
21+
22+
export const Showcase = UseGalleryShowcase;

src/hooks/useGallery/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './useGallery';
2+
export * from './GalleryContextProvider';

src/hooks/useGallery/useGallery.tsx

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as React from 'react';
2+
3+
import {GalleryContext} from './GalleryContext';
4+
5+
export function useGallery() {
6+
return React.useContext(GalleryContext).openGallery;
7+
}

0 commit comments

Comments
 (0)