Skip to content

Commit

Permalink
feat: add hook for sync tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
eyoue committed Feb 1, 2024
1 parent 4024223 commit 02e7f93
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 4 deletions.
17 changes: 14 additions & 3 deletions src/components/Stories/Stories.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';

import {Modal} from '@gravity-ui/uikit';
import type {ModalCloseReason} from '@gravity-ui/uikit';
import {Modal} from '@gravity-ui/uikit';

import {block} from '../utils/cn';

import {IndexType, StoriesLayout} from './components/StoriesLayout/StoriesLayout';
import type {StoriesLayoutProps} from './components/StoriesLayout/StoriesLayout';
import {IndexType, StoriesLayout} from './components/StoriesLayout/StoriesLayout';
import {useSyncWithLS} from './hooks';
import type {StoriesItem} from './types';

import './Stories.scss';
Expand All @@ -26,6 +27,7 @@ export interface StoriesProps {
disableOutsideClick?: boolean;
className?: string;
action?: StoriesLayoutProps['action'];
syncInTabs?: boolean;
}

export function Stories({
Expand All @@ -38,6 +40,7 @@ export function Stories({
disableOutsideClick = true,
className,
action,
syncInTabs,
}: StoriesProps) {
const [storyIndex, setStoryIndex] = React.useState(initialStoryIndex);

Expand All @@ -48,13 +51,21 @@ export function Stories({
[onClose],
);

const {callback: closeWithLS} = useSyncWithLS<NonNullable<StoriesProps['onClose']>>({
callback: (event, reason) => {
if (syncInTabs) onClose?.(event, reason);
},
uniqueKey: `close-story-${initialStoryIndex}`,
});

const handleButtonClose = React.useCallback<
(event: MouseEvent | KeyboardEvent | React.MouseEvent<HTMLElement, MouseEvent>) => void
>(
(event) => {
handleClose(event, 'closeButtonClick');
if (syncInTabs) closeWithLS(event, 'closeButtonClick');
},
[handleClose],
[handleClose, syncInTabs, closeWithLS],
);

const handleGotoPrevious = React.useCallback(() => {
Expand Down
10 changes: 9 additions & 1 deletion src/components/Stories/__stories__/Stories.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import React from 'react';
import {Button} from '@gravity-ui/uikit';
import type {Meta, StoryFn} from '@storybook/react';

import {Stories} from '../Stories';
import type {StoriesProps} from '../Stories';
import {Stories} from '../Stories';
import type {StoriesItem} from '../types';

export default {
Expand Down Expand Up @@ -62,6 +62,7 @@ const DefaultTemplate: StoryFn<StoriesProps> = (props: StoriesProps) => {
<Stories
{...props}
open={visible}
syncInTabs={props.syncInTabs}
onClose={() => {
setVisible(false);
}}
Expand Down Expand Up @@ -94,3 +95,10 @@ WithCustomAction.args = {
children: 'View examples',
},
};

export const WithSyncInTabs = DefaultTemplate.bind({});
WithSyncInTabs.args = {
open: true,
syncInTabs: true,
items: [items[0]],
};
1 change: 1 addition & 0 deletions src/components/Stories/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useSyncWithLS';
19 changes: 19 additions & 0 deletions src/components/Stories/hooks/useSyncWithLS/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!--GITHUB_BLOCK-->

# useSyncWithLS

<!--/GITHUB_BLOCK-->

```tsx
import {useSyncWithLS} from '@gravity-ui/components';
```

The `useSyncWithLS` hook executes callback when value changed in Local Storage

## Properties

| Name | Description | Type | Default |
| :------------- | :----------------------------------------------------------- | :------------: | :---------: |
| callback | Callback function called when key in local storage triggered | `VoidFunction` | |
| dataSourceName | Name for data source of keys | `string` | 'sync-tabs' |
| uniqueKey | Key in local storage for handle | `string` | |
2 changes: 2 additions & 0 deletions src/components/Stories/hooks/useSyncWithLS/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {useSyncWithLS} from './useSyncWithLS';
export type {UseSyncWithLSInputProps, UseSyncWithLSOutputProps} from './useSyncWithLS';
40 changes: 40 additions & 0 deletions src/components/Stories/hooks/useSyncWithLS/useSyncWithLS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';

export type UseSyncWithLSInputProps<T> = {
callback: T;
uniqueKey: string;
dataSourceName?: string;
};
export type UseSyncWithLSOutputProps = {callback: (...args: unknown[]) => void};

export const useSyncWithLS = <T extends Function>({
dataSourceName = 'sync-tabs',
callback,
uniqueKey,
}: UseSyncWithLSInputProps<T>): UseSyncWithLSOutputProps => {
const key = `${dataSourceName}.${uniqueKey}`;

const handler = (event: StorageEvent) => {
if (event.key === key && event.newValue) {
return callback();
}
return undefined;
};

React.useEffect(() => {
// Action in non-active tab
window.addEventListener('storage', handler);

return () => {
window.removeEventListener('storage', handler);
localStorage.removeItem(key);
};
});

return {
callback: React.useCallback(() => {
localStorage.setItem(key, String(Number(localStorage.getItem(key) || '0') + 1));
return callback();
}, [key, callback]),
};
};
1 change: 1 addition & 0 deletions src/components/Stories/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './Stories';
export * from './hooks';
export * from './types';

0 comments on commit 02e7f93

Please sign in to comment.