aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/organisms/toolbar
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-05-18 14:27:11 +0200
committerArmand Philippot <git@armandphilippot.com>2022-05-18 14:27:11 +0200
commitb214baab3e17d92f784b4f782863deafc5558ee4 (patch)
treecdc20c7e77ba6926285917eead8bb088bdc843f8 /src/components/organisms/toolbar
parent54883bb5c36cf21462a421605a709fdd6f04b150 (diff)
chore: close toolbar modals on click/focus outside
Diffstat (limited to 'src/components/organisms/toolbar')
-rw-r--r--src/components/organisms/toolbar/main-nav.tsx16
-rw-r--r--src/components/organisms/toolbar/search.stories.tsx1
-rw-r--r--src/components/organisms/toolbar/search.test.tsx5
-rw-r--r--src/components/organisms/toolbar/search.tsx16
-rw-r--r--src/components/organisms/toolbar/settings.stories.tsx8
-rw-r--r--src/components/organisms/toolbar/settings.tsx16
-rw-r--r--src/components/organisms/toolbar/toolbar.tsx18
7 files changed, 37 insertions, 43 deletions
diff --git a/src/components/organisms/toolbar/main-nav.tsx b/src/components/organisms/toolbar/main-nav.tsx
index 35e3fd6..d205112 100644
--- a/src/components/organisms/toolbar/main-nav.tsx
+++ b/src/components/organisms/toolbar/main-nav.tsx
@@ -5,7 +5,7 @@ import Nav, {
type NavProps,
type NavItem,
} from '@components/molecules/nav/nav';
-import { FC } from 'react';
+import { forwardRef, ForwardRefRenderFunction } from 'react';
import { useIntl } from 'react-intl';
import mainNavStyles from './main-nav.module.scss';
import sharedStyles from './toolbar-items.module.scss';
@@ -34,12 +34,10 @@ export type MainNavProps = {
*
* Render the main navigation.
*/
-const MainNav: FC<MainNavProps> = ({
- className = '',
- isActive,
- items,
- setIsActive,
-}) => {
+const MainNav: ForwardRefRenderFunction<HTMLDivElement, MainNavProps> = (
+ { className = '', isActive, items, setIsActive },
+ ref
+) => {
const intl = useIntl();
const label = isActive
? intl.formatMessage({
@@ -54,7 +52,7 @@ const MainNav: FC<MainNavProps> = ({
});
return (
- <div className={`${sharedStyles.item} ${mainNavStyles.item}`}>
+ <div className={`${sharedStyles.item} ${mainNavStyles.item}`} ref={ref}>
<Checkbox
id="main-nav-button"
name="main-nav-button"
@@ -79,4 +77,4 @@ const MainNav: FC<MainNavProps> = ({
);
};
-export default MainNav;
+export default forwardRef(MainNav);
diff --git a/src/components/organisms/toolbar/search.stories.tsx b/src/components/organisms/toolbar/search.stories.tsx
index c6063a0..6aaffde 100644
--- a/src/components/organisms/toolbar/search.stories.tsx
+++ b/src/components/organisms/toolbar/search.stories.tsx
@@ -1,6 +1,5 @@
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { useState } from 'react';
-import { IntlProvider } from 'react-intl';
import Search from './search';
/**
diff --git a/src/components/organisms/toolbar/search.test.tsx b/src/components/organisms/toolbar/search.test.tsx
index a18b679..7c77eac 100644
--- a/src/components/organisms/toolbar/search.test.tsx
+++ b/src/components/organisms/toolbar/search.test.tsx
@@ -11,9 +11,4 @@ describe('Search', () => {
render(<Search searchPage="#" isActive={true} setIsActive={() => null} />);
expect(screen.getByRole('checkbox')).toHaveAccessibleName('Close search');
});
-
- it('renders a search form', () => {
- render(<Search searchPage="#" isActive={true} setIsActive={() => null} />);
- expect(screen.getByRole('searchbox')).toBeInTheDocument();
- });
});
diff --git a/src/components/organisms/toolbar/search.tsx b/src/components/organisms/toolbar/search.tsx
index a1471ef..5695348 100644
--- a/src/components/organisms/toolbar/search.tsx
+++ b/src/components/organisms/toolbar/search.tsx
@@ -1,7 +1,7 @@
import Checkbox, { type CheckboxProps } from '@components/atoms/forms/checkbox';
import Label from '@components/atoms/forms/label';
import MagnifyingGlass from '@components/atoms/icons/magnifying-glass';
-import { FC } from 'react';
+import { forwardRef, ForwardRefRenderFunction } from 'react';
import { useIntl } from 'react-intl';
import SearchModal, { type SearchModalProps } from '../modals/search-modal';
import searchStyles from './search.module.scss';
@@ -26,12 +26,10 @@ export type SearchProps = {
setIsActive: CheckboxProps['setValue'];
};
-const Search: FC<SearchProps> = ({
- className = '',
- isActive,
- searchPage,
- setIsActive,
-}) => {
+const Search: ForwardRefRenderFunction<HTMLDivElement, SearchProps> = (
+ { className = '', isActive, searchPage, setIsActive },
+ ref
+) => {
const intl = useIntl();
const label = isActive
? intl.formatMessage({
@@ -46,7 +44,7 @@ const Search: FC<SearchProps> = ({
});
return (
- <div className={`${sharedStyles.item} ${searchStyles.item}`}>
+ <div className={`${sharedStyles.item} ${searchStyles.item}`} ref={ref}>
<Checkbox
id="search-button"
name="search-button"
@@ -69,4 +67,4 @@ const Search: FC<SearchProps> = ({
);
};
-export default Search;
+export default forwardRef(Search);
diff --git a/src/components/organisms/toolbar/settings.stories.tsx b/src/components/organisms/toolbar/settings.stories.tsx
index 1ec0897..aab4b9e 100644
--- a/src/components/organisms/toolbar/settings.stories.tsx
+++ b/src/components/organisms/toolbar/settings.stories.tsx
@@ -1,6 +1,5 @@
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { useState } from 'react';
-import { IntlProvider } from 'react-intl';
import Settings from './settings';
/**
@@ -57,13 +56,6 @@ export default {
},
},
},
- decorators: [
- (Story) => (
- <IntlProvider locale="en">
- <Story />
- </IntlProvider>
- ),
- ],
} as ComponentMeta<typeof Settings>;
const Template: ComponentStory<typeof Settings> = ({
diff --git a/src/components/organisms/toolbar/settings.tsx b/src/components/organisms/toolbar/settings.tsx
index 3b10226..43d3190 100644
--- a/src/components/organisms/toolbar/settings.tsx
+++ b/src/components/organisms/toolbar/settings.tsx
@@ -1,7 +1,7 @@
import Checkbox, { type CheckboxProps } from '@components/atoms/forms/checkbox';
import Label from '@components/atoms/forms/label';
import Cog from '@components/atoms/icons/cog';
-import { FC } from 'react';
+import { FC, forwardRef, ForwardRefRenderFunction } from 'react';
import { useIntl } from 'react-intl';
import SettingsModal, {
type SettingsModalProps,
@@ -28,12 +28,10 @@ export type SettingsProps = {
tooltipClassName?: SettingsModalProps['tooltipClassName'];
};
-const Settings: FC<SettingsProps> = ({
- className = '',
- isActive,
- setIsActive,
- tooltipClassName = '',
-}) => {
+const Settings: ForwardRefRenderFunction<HTMLDivElement, SettingsProps> = (
+ { className = '', isActive, setIsActive, tooltipClassName = '' },
+ ref
+) => {
const intl = useIntl();
const label = isActive
? intl.formatMessage({
@@ -48,7 +46,7 @@ const Settings: FC<SettingsProps> = ({
});
return (
- <div className={`${sharedStyles.item} ${settingsStyles.item}`}>
+ <div className={`${sharedStyles.item} ${settingsStyles.item}`} ref={ref}>
<Checkbox
id="settings-button"
name="settings-button"
@@ -71,4 +69,4 @@ const Settings: FC<SettingsProps> = ({
);
};
-export default Settings;
+export default forwardRef(Settings);
diff --git a/src/components/organisms/toolbar/toolbar.tsx b/src/components/organisms/toolbar/toolbar.tsx
index 6593055..e4188fe 100644
--- a/src/components/organisms/toolbar/toolbar.tsx
+++ b/src/components/organisms/toolbar/toolbar.tsx
@@ -1,4 +1,5 @@
-import { FC, useState } from 'react';
+import useClickOutside from '@utils/hooks/use-click-outside';
+import { FC, useRef, useState } from 'react';
import MainNav, { type MainNavProps } from '../toolbar/main-nav';
import Search, { type SearchProps } from '../toolbar/search';
import Settings from '../toolbar/settings';
@@ -22,8 +23,18 @@ export type ToolbarProps = Pick<SearchProps, 'searchPage'> & {
*/
const Toolbar: FC<ToolbarProps> = ({ className = '', nav, searchPage }) => {
const [isNavOpened, setIsNavOpened] = useState<boolean>(false);
- const [isSettingsOpened, setIsSettingsOpened] = useState<boolean>(false);
const [isSearchOpened, setIsSearchOpened] = useState<boolean>(false);
+ const [isSettingsOpened, setIsSettingsOpened] = useState<boolean>(false);
+ const mainNavRef = useRef<HTMLDivElement>(null);
+ const searchRef = useRef<HTMLDivElement>(null);
+ const settingsRef = useRef<HTMLDivElement>(null);
+
+ useClickOutside(mainNavRef, () => isNavOpened && setIsNavOpened(false));
+ useClickOutside(searchRef, () => isSearchOpened && setIsSearchOpened(false));
+ useClickOutside(
+ settingsRef,
+ () => isSettingsOpened && setIsSettingsOpened(false)
+ );
return (
<div className={`${styles.wrapper} ${className}`}>
@@ -32,18 +43,21 @@ const Toolbar: FC<ToolbarProps> = ({ className = '', nav, searchPage }) => {
isActive={isNavOpened}
setIsActive={setIsNavOpened}
className={styles.modal}
+ ref={mainNavRef}
/>
<Search
searchPage={searchPage}
isActive={isSearchOpened}
setIsActive={setIsSearchOpened}
className={`${styles.modal} ${styles['modal--search']}`}
+ ref={searchRef}
/>
<Settings
isActive={isSettingsOpened}
setIsActive={setIsSettingsOpened}
className={`${styles.modal} ${styles['modal--settings']}`}
tooltipClassName={styles.tooltip}
+ ref={settingsRef}
/>
</div>
);