From c6212f927daf3c928f479afa052e4772216a2d8a Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 21 Nov 2023 16:10:20 +0100 Subject: refactor(components): replace items prop in Navbar component * replace `items` prop with `children` prop: it is more readable this way, * handle navbar item state inside NavbarItem component: it avoid using three differents states and their methods to do exactly the same thing * remove useAutofocus hook since we can't use it anymore * add `onActivation` and `activationHandlerDelay` prop to NavbarItem component to be able to focus the search input only when the item is activated (it replicates the functioning of useAutofocus hook) * replace `ref` type in SearchForm component: it does not make sense to use an input ref for a form. Instead I use useImperativeHandle to provide different a focus method to the given ref. --- .../organisms/navbar/navbar-item/navbar-item.tsx | 41 +++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'src/components/organisms/navbar/navbar-item/navbar-item.tsx') diff --git a/src/components/organisms/navbar/navbar-item/navbar-item.tsx b/src/components/organisms/navbar/navbar-item/navbar-item.tsx index 8ef6ce3..993b613 100644 --- a/src/components/organisms/navbar/navbar-item/navbar-item.tsx +++ b/src/components/organisms/navbar/navbar-item/navbar-item.tsx @@ -6,8 +6,11 @@ import { useRef, } from 'react'; import { + useBoolean, useOnClickOutside, + useOnRouteChange, type useOnClickOutsideHandler, + useTimeout, } from '../../../../utils/hooks'; import { Checkbox, @@ -24,10 +27,16 @@ import { import { Modal } from '../../../molecules'; import styles from './navbar-item.module.scss'; +export type NavbarItemActivationHandler = (isActive: boolean) => void; + export type NavbarItemProps = Omit< ListItemProps, 'children' | 'hideMarker' | 'id' > & { + /** + * Add a delay (in ms) before triggering the `onActivation` handler. + */ + activationHandlerDelay?: number; /** * The modal contents. */ @@ -40,10 +49,6 @@ export type NavbarItemProps = Omit< * The item id. */ id: string; - /** - * Should the modal be visible? - */ - isActive: boolean; /** * An accessible name for the nav item. */ @@ -57,13 +62,9 @@ export type NavbarItemProps = Omit< */ modalVisibleFrom?: 'sm' | 'md'; /** - * A callback function to handle modal deactivation. + * A callback function to handle item activation. */ - onDeactivate?: () => void; - /** - * A callback function to handle modal toggle. - */ - onToggle: () => void; + onActivation?: NavbarItemActivationHandler; /** * Should we add the icon on the modal? * @@ -77,16 +78,15 @@ const NavbarItemWithRef: ForwardRefRenderFunction< NavbarItemProps > = ( { + activationHandlerDelay, children, className = '', icon, id, - isActive, label, modalHeading, modalVisibleFrom, - onDeactivate, - onToggle, + onActivation, showIconOnModal = false, ...props }, @@ -99,6 +99,7 @@ const NavbarItemWithRef: ForwardRefRenderFunction< : '', className, ].join(' '); + const { deactivate, state: isActive, toggle } = useBoolean(false); const labelRef = useRef(null); const checkboxRef = useRef(null); const deactivateItem: useOnClickOutsideHandler = useCallback( @@ -107,12 +108,20 @@ const NavbarItemWithRef: ForwardRefRenderFunction< e.target && checkboxRef.current?.contains(e.target as Node); const isLabel = e.target && labelRef.current?.contains(e.target as Node); - if (onDeactivate && !isCheckbox && !isLabel) onDeactivate(); + if (!isCheckbox && !isLabel) deactivate(); }, - [onDeactivate] + [deactivate] ); const modalRef = useOnClickOutside(deactivateItem); + useOnRouteChange(deactivate, 'end'); + + const handleActivation = useCallback(() => { + if (onActivation) onActivation(isActive); + }, [isActive, onActivation]); + + useTimeout(handleActivation, activationHandlerDelay); + return ( -- cgit v1.2.3