@@ -4,8 +4,12 @@ import {
44 chakra ,
55 Circle ,
66 Flex ,
7+ FlexProps ,
78 RadioProps ,
9+ SquareProps ,
10+ Stack ,
811 Text ,
12+ TextProps ,
913 useRadio ,
1014 useRadioGroup ,
1115 useToken ,
@@ -21,6 +25,90 @@ import { Question } from "../../types"
2125interface CustomRadioProps extends RadioProps {
2226 index : number
2327 label : string
28+ showAnswer : boolean
29+ isSelectedCorrect : boolean
30+ }
31+
32+ const CustomRadio : React . FC < CustomRadioProps > = ( {
33+ index,
34+ label,
35+ showAnswer,
36+ isSelectedCorrect,
37+ ...radioProps
38+ } ) => {
39+ const { state, getInputProps, getRadioProps, htmlProps } =
40+ useRadio ( radioProps )
41+
42+ // Memoized values
43+ const buttonBg = useMemo < string > ( ( ) => {
44+ if ( ! state . isChecked ) return "body.inverted"
45+ if ( ! showAnswer ) return "primary.base"
46+ if ( ! isSelectedCorrect ) return "error.base"
47+ return "success.base"
48+ } , [ state . isChecked , showAnswer , isSelectedCorrect ] )
49+
50+ const primaryBaseColor = useToken ( "colors" , "primary.base" )
51+
52+ const focusProps : FlexProps = {
53+ outline : showAnswer ? "none" : `1px solid ${ primaryBaseColor } ` ,
54+ }
55+
56+ const controlFocusProps : SquareProps = {
57+ bg : showAnswer ? "white" : "primary.pressed" ,
58+ }
59+
60+ const getRadioControlBg = ( ) : SquareProps [ "bg" ] => {
61+ if ( showAnswer ) return "white"
62+
63+ if ( state . isChecked ) return "primary.pressed"
64+
65+ return "disabled"
66+ }
67+
68+ const getControlLabelColor = ( ) : TextProps [ "color" ] => {
69+ if ( ! showAnswer ) return "white"
70+
71+ if ( isSelectedCorrect ) return "success.base"
72+
73+ return "error.base"
74+ }
75+
76+ // Render CustomRadio component
77+ return (
78+ < chakra . label { ...htmlProps } cursor = "pointer" w = "100%" >
79+ < input { ...getInputProps ( ) } />
80+ < Flex
81+ { ...getRadioProps ( ) }
82+ w = "100%"
83+ p = { 2 }
84+ alignItems = "center"
85+ bg = { buttonBg }
86+ color = { state . isChecked ? "white" : "text" }
87+ borderRadius = "base"
88+ _hover = { { ...focusProps , cursor : showAnswer ? "default" : "pointer" } }
89+ _focus = { focusProps }
90+ data-group
91+ >
92+ < Circle
93+ size = "25px"
94+ bg = { getRadioControlBg ( ) }
95+ _groupHover = { controlFocusProps }
96+ _groupFocus = { controlFocusProps }
97+ me = { 2 }
98+ >
99+ < Text
100+ m = "0"
101+ fontWeight = "700"
102+ fontSize = "lg"
103+ color = { getControlLabelColor ( ) }
104+ >
105+ { String . fromCharCode ( 97 + index ) . toUpperCase ( ) }
106+ </ Text >
107+ </ Circle >
108+ { label }
109+ </ Flex >
110+ </ chakra . label >
111+ )
24112}
25113
26114interface IProps {
@@ -52,91 +140,18 @@ const QuizRadioGroup: React.FC<IProps> = ({
52140 [ selectedAnswer ]
53141 )
54142
55- // Custom radio button component
56- const CustomRadio : React . FC < CustomRadioProps > = ( {
57- index,
58- label,
59- ...radioProps
60- } ) => {
61- const { state, getInputProps, getCheckboxProps, htmlProps } =
62- useRadio ( radioProps )
63-
64- // Memoized values
65- const buttonBg = useMemo < string > ( ( ) => {
66- if ( ! state . isChecked ) return "body.inverted"
67- if ( ! showAnswer ) return "primary.base"
68- if ( ! isSelectedCorrect ) return "error.base"
69- return "success.base"
70- } , [ state . isChecked , showAnswer , isSelectedCorrect ] )
71-
72- const primaryBaseColor = useToken ( "colors" , "primary.base" )
73-
74- // Render CustomRadio component
75- return (
76- < chakra . label { ...htmlProps } cursor = "pointer" data-group w = "100%" >
77- < input { ...getInputProps ( { } ) } hidden />
78- < Flex
79- { ...getCheckboxProps ( ) }
80- w = "100%"
81- p = { 2 }
82- alignItems = "center"
83- bg = { buttonBg }
84- color = { state . isChecked ? "white" : "text" }
85- borderRadius = "base"
86- _hover = { {
87- boxShadow : showAnswer ? "none" : "primary.base" ,
88- outline : showAnswer ? "none" : `1px solid ${ primaryBaseColor } ` ,
89- cursor : showAnswer ? "default" : "pointer" ,
90- } }
91- >
92- < Circle
93- size = "25px"
94- bg = {
95- showAnswer
96- ? "white"
97- : state . isChecked
98- ? "primary.pressed"
99- : "disabled"
100- }
101- _groupHover = { {
102- bg : showAnswer ? "white" : "primary.pressed" ,
103- } }
104- me = { 2 }
105- >
106- < Text
107- m = "0"
108- fontWeight = "700"
109- fontSize = "lg"
110- color = {
111- ! showAnswer
112- ? "white"
113- : isSelectedCorrect
114- ? "success.base"
115- : "error.base"
116- }
117- >
118- { String . fromCharCode ( 97 + index ) . toUpperCase ( ) }
119- </ Text >
120- </ Circle >
121- { label }
122- </ Flex >
123- </ chakra . label >
124- )
125- }
126-
127143 // Render QuizRadioGroup
128144 return (
129- < Flex { ...getRootProps ( ) } direction = "column" w = "100%" >
145+ < Stack spacing = "6" { ...getRootProps ( ) } w = "100%" >
130146 < Text
131147 textAlign = { { base : "center" , md : "left" } }
132148 fontWeight = "700"
133- fontSize = "2xl"
134- mb = { 6 }
149+ size = "2xl"
135150 >
136151 { t ( prompt ) }
137152 </ Text >
138153
139- < Flex direction = "column" gap = { 4 } >
154+ < Stack gap = "4" >
140155 { answers . map ( ( { id, label } , index ) => {
141156 const display =
142157 ! showAnswer || id === selectedAnswer ? "inline-flex" : "none"
@@ -146,21 +161,23 @@ const QuizRadioGroup: React.FC<IProps> = ({
146161 display = { display }
147162 index = { index }
148163 label = { t ( label ) }
164+ showAnswer = { showAnswer }
165+ isSelectedCorrect = { isSelectedCorrect }
149166 { ...getRadioProps ( { value : id } ) }
150167 />
151168 )
152169 } ) }
153- </ Flex >
170+ </ Stack >
154171
155172 { showAnswer && (
156- < Box mt = { 5 } >
173+ < Box >
157174 < Text fontWeight = "bold" mt = { 0 } mb = { 2 } >
158175 < Translation id = "explanation" />
159176 </ Text >
160177 < Text m = { 0 } > { t ( explanation ) } </ Text >
161178 </ Box >
162179 ) }
163- </ Flex >
180+ </ Stack >
164181 )
165182}
166183
0 commit comments