From 1ae44bfb5d24271837cd8e28be58b886d82bcd56 Mon Sep 17 00:00:00 2001 From: karan-palan Date: Sun, 19 Jan 2025 19:07:10 +0530 Subject: [PATCH 1/2] fix[dark-mode-toggle]: fix dark/light mode toggle on mobile --- components/DarkModeToggle.tsx | 39 +++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/components/DarkModeToggle.tsx b/components/DarkModeToggle.tsx index cadf3b7ac..1735b126a 100644 --- a/components/DarkModeToggle.tsx +++ b/components/DarkModeToggle.tsx @@ -1,5 +1,5 @@ import { useTheme } from 'next-themes'; -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import React from 'react'; import Image from 'next/image'; @@ -35,6 +35,7 @@ export default function DarkModeToggle() { const [activeThemeIcon, setActiveThemeIcon] = useState( '/icons/theme-switch.svg', ); + useEffect(() => { switch (theme) { case 'system': @@ -46,8 +47,30 @@ export default function DarkModeToggle() { } }, [theme, resolvedTheme]); + const dropdownRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + setShowSelect(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, []); + return ( -
+
{ - setShowSelect(false); - }} + className={`absolute right-0 p-2 bg-white dark:bg-gray-800 rounded-lg border dark:border-gray-700 z-10 w-max ${ + showSelect ? 'block' : 'hidden' + }`} tabIndex={0} data-test='theme-dropdown' > @@ -93,7 +114,7 @@ export default function DarkModeToggle() { > System theme System theme Date: Sun, 19 Jan 2025 19:43:10 +0530 Subject: [PATCH 2/2] fix[dark-mode-toggle]: add tests --- components/DarkModeToggle.tsx | 1 + cypress/components/DarkModeToggle.cy.tsx | 30 +++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/components/DarkModeToggle.tsx b/components/DarkModeToggle.tsx index 1735b126a..f1dbc4f32 100644 --- a/components/DarkModeToggle.tsx +++ b/components/DarkModeToggle.tsx @@ -89,6 +89,7 @@ export default function DarkModeToggle() { />
setShowSelect(false)} className={`absolute right-0 p-2 bg-white dark:bg-gray-800 rounded-lg border dark:border-gray-700 z-10 w-max ${ showSelect ? 'block' : 'hidden' }`} diff --git a/cypress/components/DarkModeToggle.cy.tsx b/cypress/components/DarkModeToggle.cy.tsx index 839e9a06b..be2a0f84e 100644 --- a/cypress/components/DarkModeToggle.cy.tsx +++ b/cypress/components/DarkModeToggle.cy.tsx @@ -43,13 +43,13 @@ describe('DarkModeToggle Component', () => { cy.get(TOGGLE_BUTTON).click(); // check if the menu is open - cy.get(THEME_DROPDOWN).should('have.css', 'display', 'block'); + cy.get(THEME_DROPDOWN).should('be.visible'); // click on the toggle button again to close the menu cy.get(TOGGLE_BUTTON).click(); // check if the menu is closed - cy.get(THEME_DROPDOWN).should('have.css', 'display', 'none'); + cy.get(THEME_DROPDOWN).should('not.be.visible'); }); // Should close the menu on mouse leave @@ -58,13 +58,31 @@ describe('DarkModeToggle Component', () => { cy.get(TOGGLE_BUTTON).click(); // check if the menu is open - cy.get(THEME_DROPDOWN).should('have.css', 'display', 'block'); + cy.get(THEME_DROPDOWN).should('be.visible'); - // trigger mouse leave event on the menu - cy.get(THEME_DROPDOWN).trigger('mouseout'); + // simulate mouse leave event on the menu + cy.get(THEME_DROPDOWN).then(($el) => { + const mouseOutEvent = new Event('mouseout', { bubbles: true }); + $el[0].dispatchEvent(mouseOutEvent); + }); // check if the menu is closed - cy.get(THEME_DROPDOWN).should('have.css', 'display', 'none'); + cy.get(THEME_DROPDOWN).should('not.be.visible'); + }); + + // Should close the menu when clicking outside + it('should close the menu when clicking outside', () => { + // Click on the toggle button to open the menu + cy.get(TOGGLE_BUTTON).click(); + + // Check if the menu is open + cy.get(THEME_DROPDOWN).should('be.visible'); + + // Simulate clicking outside the dropdown + cy.get('body').click(0, 0); // Click at the top-left corner of the body + + // Check if the menu is closed + cy.get(THEME_DROPDOWN).should('not.be.visible'); }); });