@@ -4,8 +4,12 @@ import {
4
4
chakra ,
5
5
Circle ,
6
6
Flex ,
7
+ FlexProps ,
7
8
RadioProps ,
9
+ SquareProps ,
10
+ Stack ,
8
11
Text ,
12
+ TextProps ,
9
13
useRadio ,
10
14
useRadioGroup ,
11
15
useToken ,
@@ -21,6 +25,90 @@ import { Question } from "../../types"
21
25
interface CustomRadioProps extends RadioProps {
22
26
index : number
23
27
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
+ )
24
112
}
25
113
26
114
interface IProps {
@@ -52,91 +140,18 @@ const QuizRadioGroup: React.FC<IProps> = ({
52
140
[ selectedAnswer ]
53
141
)
54
142
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
-
127
143
// Render QuizRadioGroup
128
144
return (
129
- < Flex { ...getRootProps ( ) } direction = "column" w = "100%" >
145
+ < Stack spacing = "6" { ...getRootProps ( ) } w = "100%" >
130
146
< Text
131
147
textAlign = { { base : "center" , md : "left" } }
132
148
fontWeight = "700"
133
- fontSize = "2xl"
134
- mb = { 6 }
149
+ size = "2xl"
135
150
>
136
151
{ t ( prompt ) }
137
152
</ Text >
138
153
139
- < Flex direction = "column" gap = { 4 } >
154
+ < Stack gap = "4" >
140
155
{ answers . map ( ( { id, label } , index ) => {
141
156
const display =
142
157
! showAnswer || id === selectedAnswer ? "inline-flex" : "none"
@@ -146,21 +161,23 @@ const QuizRadioGroup: React.FC<IProps> = ({
146
161
display = { display }
147
162
index = { index }
148
163
label = { t ( label ) }
164
+ showAnswer = { showAnswer }
165
+ isSelectedCorrect = { isSelectedCorrect }
149
166
{ ...getRadioProps ( { value : id } ) }
150
167
/>
151
168
)
152
169
} ) }
153
- </ Flex >
170
+ </ Stack >
154
171
155
172
{ showAnswer && (
156
- < Box mt = { 5 } >
173
+ < Box >
157
174
< Text fontWeight = "bold" mt = { 0 } mb = { 2 } >
158
175
< Translation id = "explanation" />
159
176
</ Text >
160
177
< Text m = { 0 } > { t ( explanation ) } </ Text >
161
178
</ Box >
162
179
) }
163
- </ Flex >
180
+ </ Stack >
164
181
)
165
182
}
166
183
0 commit comments