@@ -66,6 +66,7 @@ function ThemeToggleComponent() {
6666
6767 return (
6868 < button
69+ type = "button"
6970 onClick = { toggleTheme }
7071 className = "relative p-2 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-offset-2 dark:focus:ring-offset-gray-800 active:scale-95"
7172 aria-label = { `Switch to ${ theme === 'light' ? 'dark' : 'light' } mode` }
@@ -78,6 +79,7 @@ function ThemeToggleComponent() {
7879 stroke = "currentColor"
7980 viewBox = "0 0 24 24"
8081 xmlns = "http://www.w3.org/2000/svg"
82+ aria-hidden = "true"
8183 >
8284 < path
8385 strokeLinecap = "round"
@@ -93,6 +95,7 @@ function ThemeToggleComponent() {
9395 stroke = "currentColor"
9496 viewBox = "0 0 24 24"
9597 xmlns = "http://www.w3.org/2000/svg"
98+ aria-hidden = "true"
9699 >
97100 < path
98101 strokeLinecap = "round"
@@ -186,7 +189,7 @@ export const DarkTheme: Story = {
186189 } ,
187190 } ,
188191 decorators : [
189- ( Story , context ) => {
192+ ( Story , _context ) => {
190193 React . useEffect ( ( ) => {
191194 document . documentElement . classList . add ( 'dark' ) ;
192195 return ( ) => document . documentElement . classList . remove ( 'dark' ) ;
@@ -313,18 +316,12 @@ export const InNavbarContext: Story = {
313316 < div className = "flex items-center gap-4" >
314317 < div className = "text-xl font-bold text-gray-900 dark:text-white" > Coding Tricks</ div >
315318 < div className = "hidden md:flex items-center gap-4" >
316- < a
317- href = "#"
318- className = "text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
319- >
319+ < span className = "text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white cursor-pointer" >
320320 Problems
321- </ a >
322- < a
323- href = "#"
324- className = "text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white"
325- >
321+ </ span >
322+ < span className = "text-gray-600 dark:text-gray-300 hover:text-gray-900 dark:hover:text-white cursor-pointer" >
326323 Topics
327- </ a >
324+ </ span >
328325 </ div >
329326 </ div >
330327 < div className = "flex items-center gap-4" >
@@ -742,120 +739,138 @@ export const MultipleToggles: Story = {
742739} ;
743740
744741/**
745- * Interactive Test: Visual Color Change - Shows the visible background color change.
746- * Captures before and after states for visual regression testing.
742+ * Component for VisualColorChangeTest story - extracted to satisfy React hooks rules.
747743 */
748- export const VisualColorChangeTest : Story = {
749- parameters : {
750- layout : 'fullscreen' ,
751- chromatic : {
752- disableSnapshot : false ,
753- delay : 500 , // Wait for animations to complete
754- } ,
755- } ,
756- render : ( ) => {
757- const [ clickCount , setClickCount ] = useState ( 0 ) ;
758- const { theme, toggleTheme } = useMockTheme ( ) ;
744+ function VisualColorChangeTestComponent ( ) : React . ReactElement {
745+ const [ clickCount , setClickCount ] = useState ( 0 ) ;
746+ const { theme, toggleTheme } = useMockTheme ( ) ;
759747
760- const handleClick = ( ) => {
761- toggleTheme ( ) ;
762- setClickCount ( ( prev ) => prev + 1 ) ;
763- } ;
748+ const handleClick = ( ) => {
749+ toggleTheme ( ) ;
750+ setClickCount ( ( prev ) => prev + 1 ) ;
751+ } ;
764752
765- return (
766- < div
767- data-testid = "visual-test-container"
768- className = { `min-h-screen p-8 transition-all duration-300 ${
769- theme === 'dark' ? 'bg-gray-900' : 'bg-gray-50'
770- } `}
771- >
772- < div className = "max-w-md mx-auto" >
773- < div
774- className = { `p-6 rounded-xl shadow-lg transition-all duration-300 ${
775- theme === 'dark' ? 'bg-gray-800 text-white' : 'bg-white text-gray-900'
776- } `}
777- >
778- < h2 className = "text-xl font-bold mb-4" > Theme Toggle Test</ h2 >
779- < p className = { `mb-4 ${ theme === 'dark' ? 'text-gray-300' : 'text-gray-600' } ` } >
780- Click the button below to test the theme toggle functionality. The entire background
781- and card should change colors.
782- </ p >
783- < div className = "flex items-center justify-between" >
784- < div >
785- < p className = "text-sm font-medium" > Current Theme:</ p >
786- < p
787- data-testid = "current-theme"
788- className = { `text-lg font-bold ${
789- theme === 'dark' ? 'text-blue-400' : 'text-blue-600'
790- } `}
791- >
792- { theme === 'dark' ? 'Dark Mode' : 'Light Mode' }
793- </ p >
794- < p className = "text-xs text-gray-500 mt-1" >
795- Toggled { clickCount } time{ clickCount !== 1 ? 's' : '' }
796- </ p >
797- </ div >
798- < button
799- onClick = { handleClick }
800- data-testid = "theme-toggle-btn"
801- className = { `p-3 rounded-lg transition-all duration-200 ${
802- theme === 'dark'
803- ? 'bg-gray-700 hover:bg-gray-600 text-gray-300'
804- : 'bg-gray-100 hover:bg-gray-200 text-gray-700'
753+ return (
754+ < div
755+ data-testid = "visual-test-container"
756+ className = { `min-h-screen p-8 transition-all duration-300 ${
757+ theme === 'dark' ? 'bg-gray-900' : 'bg-gray-50'
758+ } `}
759+ >
760+ < div className = "max-w-md mx-auto" >
761+ < div
762+ className = { `p-6 rounded-xl shadow-lg transition-all duration-300 ${
763+ theme === 'dark' ? 'bg-gray-800 text-white' : 'bg-white text-gray-900'
764+ } `}
765+ >
766+ < h2 className = "text-xl font-bold mb-4" > Theme Toggle Test</ h2 >
767+ < p className = { `mb-4 ${ theme === 'dark' ? 'text-gray-300' : 'text-gray-600' } ` } >
768+ Click the button below to test the theme toggle functionality. The entire background and
769+ card should change colors.
770+ </ p >
771+ < div className = "flex items-center justify-between" >
772+ < div >
773+ < p className = "text-sm font-medium" > Current Theme:</ p >
774+ < p
775+ data-testid = "current-theme"
776+ className = { `text-lg font-bold ${
777+ theme === 'dark' ? 'text-blue-400' : 'text-blue-600'
805778 } `}
806- aria-label = { `Switch to ${ theme === 'light' ? 'dark' : 'light' } mode` }
807779 >
808- { theme === 'light' ? (
809- < svg className = "w-6 h-6" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
810- < path
811- strokeLinecap = "round"
812- strokeLinejoin = "round"
813- strokeWidth = { 2 }
814- d = "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
815- />
816- </ svg >
817- ) : (
818- < svg className = "w-6 h-6" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
819- < path
820- strokeLinecap = "round"
821- strokeLinejoin = "round"
822- strokeWidth = { 2 }
823- d = "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
824- />
825- </ svg >
826- ) }
827- </ button >
828- </ div >
829- </ div >
830-
831- { /* Color samples that change with theme */ }
832- < div className = "mt-6 grid grid-cols-3 gap-4" >
833- < div
834- className = { `p-4 rounded-lg text-center ${
835- theme === 'dark' ? 'bg-blue-900 text-blue-200' : 'bg-blue-100 text-blue-800'
836- } `}
837- >
838- Primary
839- </ div >
840- < div
841- className = { `p-4 rounded-lg text-center ${
842- theme === 'dark' ? 'bg-green-900 text-green-200' : 'bg-green-100 text-green-800'
843- } `}
844- >
845- Success
780+ { theme === 'dark' ? 'Dark Mode' : 'Light Mode' }
781+ </ p >
782+ < p className = "text-xs text-gray-500 mt-1" >
783+ Toggled { clickCount } time{ clickCount !== 1 ? 's' : '' }
784+ </ p >
846785 </ div >
847- < div
848- className = { `p-4 rounded-lg text-center ${
849- theme === 'dark' ? 'bg-red-900 text-red-200' : 'bg-red-100 text-red-800'
786+ < button
787+ type = "button"
788+ onClick = { handleClick }
789+ data-testid = "theme-toggle-btn"
790+ className = { `p-3 rounded-lg transition-all duration-200 ${
791+ theme === 'dark'
792+ ? 'bg-gray-700 hover:bg-gray-600 text-gray-300'
793+ : 'bg-gray-100 hover:bg-gray-200 text-gray-700'
850794 } `}
795+ aria-label = { `Switch to ${ theme === 'light' ? 'dark' : 'light' } mode` }
851796 >
852- Danger
853- </ div >
797+ { theme === 'light' ? (
798+ < svg
799+ className = "w-6 h-6"
800+ fill = "none"
801+ stroke = "currentColor"
802+ viewBox = "0 0 24 24"
803+ aria-hidden = "true"
804+ >
805+ < path
806+ strokeLinecap = "round"
807+ strokeLinejoin = "round"
808+ strokeWidth = { 2 }
809+ d = "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
810+ />
811+ </ svg >
812+ ) : (
813+ < svg
814+ className = "w-6 h-6"
815+ fill = "none"
816+ stroke = "currentColor"
817+ viewBox = "0 0 24 24"
818+ aria-hidden = "true"
819+ >
820+ < path
821+ strokeLinecap = "round"
822+ strokeLinejoin = "round"
823+ strokeWidth = { 2 }
824+ d = "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"
825+ />
826+ </ svg >
827+ ) }
828+ </ button >
829+ </ div >
830+ </ div >
831+
832+ { /* Color samples that change with theme */ }
833+ < div className = "mt-6 grid grid-cols-3 gap-4" >
834+ < div
835+ className = { `p-4 rounded-lg text-center ${
836+ theme === 'dark' ? 'bg-blue-900 text-blue-200' : 'bg-blue-100 text-blue-800'
837+ } `}
838+ >
839+ Primary
840+ </ div >
841+ < div
842+ className = { `p-4 rounded-lg text-center ${
843+ theme === 'dark' ? 'bg-green-900 text-green-200' : 'bg-green-100 text-green-800'
844+ } `}
845+ >
846+ Success
847+ </ div >
848+ < div
849+ className = { `p-4 rounded-lg text-center ${
850+ theme === 'dark' ? 'bg-red-900 text-red-200' : 'bg-red-100 text-red-800'
851+ } `}
852+ >
853+ Danger
854854 </ div >
855855 </ div >
856856 </ div >
857- ) ;
857+ </ div >
858+ ) ;
859+ }
860+
861+ /**
862+ * Interactive Test: Visual Color Change - Shows the visible background color change.
863+ * Captures before and after states for visual regression testing.
864+ */
865+ export const VisualColorChangeTest : Story = {
866+ parameters : {
867+ layout : 'fullscreen' ,
868+ chromatic : {
869+ disableSnapshot : false ,
870+ delay : 500 , // Wait for animations to complete
871+ } ,
858872 } ,
873+ render : ( ) => < VisualColorChangeTestComponent /> ,
859874 decorators : [
860875 ( Story ) => (
861876 < MockThemeProvider initialTheme = "light" >
0 commit comments