From c6212f927daf3c928f479afa052e4772216a2d8a Mon Sep 17 00:00:00 2001
From: Armand Philippot <git@armandphilippot.com>
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<HTMLLabelElement>(null);
   const checkboxRef = useRef<HTMLInputElement>(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<HTMLDivElement>(deactivateItem);
 
+  useOnRouteChange(deactivate, 'end');
+
+  const handleActivation = useCallback(() => {
+    if (onActivation) onActivation(isActive);
+  }, [isActive, onActivation]);
+
+  useTimeout(handleActivation, activationHandlerDelay);
+
   return (
     <ListItem {...props} className={itemClass} hideMarker ref={ref}>
       <Checkbox
@@ -120,7 +129,7 @@ const NavbarItemWithRef: ForwardRefRenderFunction<
         id={id}
         isChecked={isActive}
         name={id}
-        onChange={onToggle}
+        onChange={toggle}
         ref={checkboxRef}
         value={id}
       />
-- 
cgit v1.2.3

