@ceed/ads 1.29.1 → 1.30.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
- package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
- package/dist/components/SearchBar/SearchBar.d.ts +21 -0
- package/dist/components/SearchBar/index.d.ts +3 -0
- package/dist/components/data-display/Badge.md +39 -71
- package/dist/components/data-display/DataTable.md +1 -1
- package/dist/components/data-display/InfoSign.md +98 -74
- package/dist/components/data-display/Typography.md +97 -363
- package/dist/components/feedback/Dialog.md +62 -76
- package/dist/components/feedback/Modal.md +44 -259
- package/dist/components/feedback/llms.txt +0 -2
- package/dist/components/index.d.ts +2 -0
- package/dist/components/inputs/Autocomplete.md +107 -356
- package/dist/components/inputs/ButtonGroup.md +106 -115
- package/dist/components/inputs/Calendar.md +459 -98
- package/dist/components/inputs/CurrencyInput.md +5 -183
- package/dist/components/inputs/DatePicker.md +431 -108
- package/dist/components/inputs/DateRangePicker.md +492 -131
- package/dist/components/inputs/FilterMenu.md +19 -169
- package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
- package/dist/components/inputs/IconButton.md +88 -137
- package/dist/components/inputs/Input.md +0 -5
- package/dist/components/inputs/MonthPicker.md +422 -95
- package/dist/components/inputs/MonthRangePicker.md +466 -89
- package/dist/components/inputs/PercentageInput.md +16 -185
- package/dist/components/inputs/RadioButton.md +35 -163
- package/dist/components/inputs/RadioTileGroup.md +61 -150
- package/dist/components/inputs/SearchBar.md +44 -0
- package/dist/components/inputs/Select.md +326 -222
- package/dist/components/inputs/Switch.md +376 -136
- package/dist/components/inputs/Textarea.md +10 -213
- package/dist/components/inputs/Uploader/Uploader.md +66 -145
- package/dist/components/inputs/llms.txt +1 -3
- package/dist/components/navigation/Breadcrumbs.md +322 -80
- package/dist/components/navigation/Dropdown.md +221 -92
- package/dist/components/navigation/IconMenuButton.md +502 -40
- package/dist/components/navigation/InsetDrawer.md +738 -68
- package/dist/components/navigation/Link.md +298 -39
- package/dist/components/navigation/Menu.md +285 -92
- package/dist/components/navigation/MenuButton.md +448 -55
- package/dist/components/navigation/Pagination.md +338 -47
- package/dist/components/navigation/ProfileMenu.md +268 -45
- package/dist/components/navigation/Stepper.md +28 -160
- package/dist/components/navigation/Tabs.md +316 -57
- package/dist/components/surfaces/Sheet.md +334 -151
- package/dist/index.browser.js +15 -13
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +289 -288
- package/dist/index.d.ts +1 -1
- package/dist/index.js +426 -369
- package/dist/llms.txt +1 -8
- package/framer/index.js +1 -1
- package/package.json +16 -15
- package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
- package/dist/components/feedback/CircularProgress.md +0 -257
- package/dist/components/feedback/Skeleton.md +0 -280
- package/dist/components/inputs/FormControl.md +0 -361
- package/dist/components/inputs/RadioList.md +0 -241
- package/dist/components/inputs/Slider.md +0 -334
- package/dist/guides/ThemeProvider.md +0 -116
- package/dist/guides/llms.txt +0 -9
|
@@ -2,12 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
PercentageInput is a specialized numeric input for entering percentage values. It automatically appends a `%` suffix, formats numbers with thousand separators, and supports min/max validation with built-in error states. Use it for any field where users need to enter a percentage, such as tax rates, discounts, or commission rates.
|
|
6
|
-
|
|
7
|
-
> **Tip: Use built-in form props**
|
|
8
|
-
>
|
|
9
|
-
> This component supports `label` and `helperText` props directly. Use these instead of wrapping with FormControl + FormLabel + FormHelperText for simpler forms.
|
|
10
|
-
|
|
11
5
|
```tsx
|
|
12
6
|
<PercentageInput placeholder="Enter a percentage" />
|
|
13
7
|
```
|
|
@@ -28,29 +22,7 @@ PercentageInput is a specialized numeric input for entering percentage values. I
|
|
|
28
22
|
| min | — | — |
|
|
29
23
|
| max | — | — |
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
import { PercentageInput } from '@ceed/ads';
|
|
35
|
-
|
|
36
|
-
function MyComponent() {
|
|
37
|
-
const [rate, setRate] = React.useState(0);
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<PercentageInput
|
|
41
|
-
label="Tax Rate"
|
|
42
|
-
value={rate}
|
|
43
|
-
onChange={(e) => setRate(e.target.value)}
|
|
44
|
-
min={0}
|
|
45
|
-
max={100}
|
|
46
|
-
/>
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Sizes
|
|
52
|
-
|
|
53
|
-
PercentageInput supports three sizes: `sm`, `md` (default), and `lg`.
|
|
25
|
+
### Sizes
|
|
54
26
|
|
|
55
27
|
```tsx
|
|
56
28
|
<Stack gap={2}>
|
|
@@ -60,80 +32,66 @@ PercentageInput supports three sizes: `sm`, `md` (default), and `lg`.
|
|
|
60
32
|
</Stack>
|
|
61
33
|
```
|
|
62
34
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
### With Label
|
|
35
|
+
### Disabled
|
|
66
36
|
|
|
67
37
|
```tsx
|
|
68
38
|
<PercentageInput
|
|
69
39
|
placeholder="Enter a percentage"
|
|
70
|
-
|
|
40
|
+
disabled
|
|
71
41
|
/>
|
|
72
42
|
```
|
|
73
43
|
|
|
74
|
-
|
|
75
|
-
<PercentageInput label="Discount Rate" />
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### With Helper Text
|
|
44
|
+
### Error
|
|
79
45
|
|
|
80
46
|
```tsx
|
|
81
47
|
<PercentageInput
|
|
82
48
|
placeholder="Enter a percentage"
|
|
83
|
-
|
|
84
|
-
helperText="Please enter a percentage"
|
|
49
|
+
error
|
|
85
50
|
/>
|
|
86
51
|
```
|
|
87
52
|
|
|
88
|
-
|
|
89
|
-
<PercentageInput label="Commission" helperText="Enter the commission percentage." />
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Error State
|
|
53
|
+
### WithLabel
|
|
93
54
|
|
|
94
55
|
```tsx
|
|
95
56
|
<PercentageInput
|
|
96
57
|
placeholder="Enter a percentage"
|
|
97
|
-
|
|
58
|
+
label="Percentage Input"
|
|
98
59
|
/>
|
|
99
60
|
```
|
|
100
61
|
|
|
101
|
-
###
|
|
62
|
+
### WithHelperText
|
|
102
63
|
|
|
103
64
|
```tsx
|
|
104
65
|
<PercentageInput
|
|
105
66
|
placeholder="Enter a percentage"
|
|
106
67
|
label="Percentage Input"
|
|
107
68
|
helperText="Please enter a percentage"
|
|
108
|
-
error
|
|
109
69
|
/>
|
|
110
70
|
```
|
|
111
71
|
|
|
112
|
-
###
|
|
72
|
+
### WithErrorText
|
|
113
73
|
|
|
114
74
|
```tsx
|
|
115
75
|
<PercentageInput
|
|
116
76
|
placeholder="Enter a percentage"
|
|
117
77
|
label="Percentage Input"
|
|
118
78
|
helperText="Please enter a percentage"
|
|
119
|
-
|
|
79
|
+
error
|
|
120
80
|
/>
|
|
121
81
|
```
|
|
122
82
|
|
|
123
|
-
###
|
|
83
|
+
### Required
|
|
124
84
|
|
|
125
85
|
```tsx
|
|
126
86
|
<PercentageInput
|
|
127
87
|
placeholder="Enter a percentage"
|
|
128
|
-
|
|
88
|
+
label="Percentage Input"
|
|
89
|
+
helperText="Please enter a percentage"
|
|
90
|
+
required
|
|
129
91
|
/>
|
|
130
92
|
```
|
|
131
93
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
Set `min` and `max` to enforce value boundaries. When the entered value is outside the range, the input automatically shows an error state.
|
|
135
|
-
|
|
136
|
-
### Minimum Value
|
|
94
|
+
### Min
|
|
137
95
|
|
|
138
96
|
```tsx
|
|
139
97
|
<PercentageInput
|
|
@@ -145,12 +103,7 @@ Set `min` and `max` to enforce value boundaries. When the entered value is outsi
|
|
|
145
103
|
/>
|
|
146
104
|
```
|
|
147
105
|
|
|
148
|
-
|
|
149
|
-
<PercentageInput min={10} defaultValue={5} />
|
|
150
|
-
{/* Shows error because 5 < 10 */}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Maximum Value
|
|
106
|
+
### Max
|
|
154
107
|
|
|
155
108
|
```tsx
|
|
156
109
|
<PercentageInput
|
|
@@ -161,125 +114,3 @@ Set `min` and `max` to enforce value boundaries. When the entered value is outsi
|
|
|
161
114
|
defaultValue={5000}
|
|
162
115
|
/>
|
|
163
116
|
```
|
|
164
|
-
|
|
165
|
-
```tsx
|
|
166
|
-
<PercentageInput max={500} defaultValue={5000} />
|
|
167
|
-
{/* Shows error because 5000 > 500 */}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Decimal Scale
|
|
171
|
-
|
|
172
|
-
Use `maxDecimalScale` to control the number of decimal places allowed. The default is `0` (integers only).
|
|
173
|
-
|
|
174
|
-
```tsx
|
|
175
|
-
// Integer only (default)
|
|
176
|
-
<PercentageInput maxDecimalScale={0} />
|
|
177
|
-
|
|
178
|
-
// Up to 2 decimal places: 12.34%
|
|
179
|
-
<PercentageInput maxDecimalScale={2} />
|
|
180
|
-
|
|
181
|
-
// Up to 3 decimal places: 12.345%
|
|
182
|
-
<PercentageInput maxDecimalScale={3} />
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## Minor Unit Mode
|
|
186
|
-
|
|
187
|
-
When `useMinorUnit` is `true`, the component converts between display values and minor units based on `maxDecimalScale`. This is useful when your API stores percentages in integer form.
|
|
188
|
-
|
|
189
|
-
```tsx
|
|
190
|
-
// Display shows "20.12%", onChange returns 20120
|
|
191
|
-
<PercentageInput useMinorUnit maxDecimalScale={3} value={20120} />
|
|
192
|
-
|
|
193
|
-
// Display shows "20.12%", onChange returns 20.12
|
|
194
|
-
<PercentageInput useMinorUnit={false} maxDecimalScale={2} value={20.12} />
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
## Common Use Cases
|
|
198
|
-
|
|
199
|
-
### Discount Configuration
|
|
200
|
-
|
|
201
|
-
```tsx
|
|
202
|
-
function DiscountSetting() {
|
|
203
|
-
const [discount, setDiscount] = React.useState(0);
|
|
204
|
-
|
|
205
|
-
return (
|
|
206
|
-
<PercentageInput
|
|
207
|
-
label="Discount"
|
|
208
|
-
helperText="Enter 0-100%"
|
|
209
|
-
value={discount}
|
|
210
|
-
onChange={(e) => setDiscount(e.target.value)}
|
|
211
|
-
min={0}
|
|
212
|
-
max={100}
|
|
213
|
-
/>
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Tax Rate Settings
|
|
219
|
-
|
|
220
|
-
```tsx
|
|
221
|
-
function TaxRateForm() {
|
|
222
|
-
return (
|
|
223
|
-
<Stack gap={2}>
|
|
224
|
-
<PercentageInput
|
|
225
|
-
label="VAT Rate"
|
|
226
|
-
defaultValue={10}
|
|
227
|
-
maxDecimalScale={2}
|
|
228
|
-
min={0}
|
|
229
|
-
max={100}
|
|
230
|
-
/>
|
|
231
|
-
<PercentageInput
|
|
232
|
-
label="Local Tax Rate"
|
|
233
|
-
defaultValue={2.5}
|
|
234
|
-
maxDecimalScale={2}
|
|
235
|
-
min={0}
|
|
236
|
-
max={50}
|
|
237
|
-
/>
|
|
238
|
-
</Stack>
|
|
239
|
-
);
|
|
240
|
-
}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### Progress / Completion Tracker
|
|
244
|
-
|
|
245
|
-
```tsx
|
|
246
|
-
function CompletionTracker({ value, onChange }) {
|
|
247
|
-
return (
|
|
248
|
-
<PercentageInput
|
|
249
|
-
label="Completion"
|
|
250
|
-
value={value}
|
|
251
|
-
onChange={(e) => onChange(e.target.value)}
|
|
252
|
-
min={0}
|
|
253
|
-
max={100}
|
|
254
|
-
helperText={value >= 100 ? 'Task is complete!' : `${100 - value}% remaining`}
|
|
255
|
-
/>
|
|
256
|
-
);
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
## Best Practices
|
|
261
|
-
|
|
262
|
-
1. **Always set min and max**: Bound the valid range to prevent unreasonable values.
|
|
263
|
-
|
|
264
|
-
```tsx
|
|
265
|
-
// ✅ Clear bounds
|
|
266
|
-
<PercentageInput min={0} max={100} />
|
|
267
|
-
|
|
268
|
-
// ❌ Unbounded — user could enter 99999%
|
|
269
|
-
<PercentageInput />
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
2. **Use `maxDecimalScale` appropriately**: Set it to `0` for whole percentages (discounts, progress), or `2`–`3` for precise rates (tax, interest).
|
|
273
|
-
|
|
274
|
-
3. **Use `useMinorUnit` for API compatibility**: When your backend stores percentages as integers (e.g., 1050 for 10.50%), enable `useMinorUnit` with the appropriate `maxDecimalScale`.
|
|
275
|
-
|
|
276
|
-
4. **Provide context via labels and helper text**: Clarify what the percentage represents and what range is valid.
|
|
277
|
-
|
|
278
|
-
5. **Handle edge cases**: Consider what happens at boundary values (0%, 100%) and negative percentages if allowed.
|
|
279
|
-
|
|
280
|
-
## Accessibility
|
|
281
|
-
|
|
282
|
-
- The input has proper labeling via the `label` prop, linked with `aria-labelledby`.
|
|
283
|
-
- Error states trigger `aria-invalid` with associated error messages via `aria-describedby`.
|
|
284
|
-
- The `%` suffix is a visual decoration — ensure labels clarify that the field expects a percentage for screen readers.
|
|
285
|
-
- Min/max validation errors are communicated visually; add descriptive `helperText` to make the valid range clear.
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Radio buttons are built on Joy UI's Radio and RadioGroup components, supporting multiple visual variants, sizes, colors, and advanced customization such as custom icons, overlay interactions, and icon-free designs. They are ideal for settings forms, preference panels, and any UI where a user must commit to a single option from a predefined list.
|
|
5
|
+
Radio 컴포넌트는 사용자가 여러 옵션 중 하나만 선택할 수 있는 단일 선택 인터페이스를 제공합니다. 라디오 버튼은 그룹으로 사용되어야 하며, 하나가 선택되면 다른 옵션들은 자동으로 해제됩니다.
|
|
8
6
|
|
|
9
7
|
```tsx
|
|
10
8
|
<Radio />
|
|
@@ -30,28 +28,35 @@ Radio buttons are built on Joy UI's Radio and RadioGroup components, supporting
|
|
|
30
28
|
## Usage
|
|
31
29
|
|
|
32
30
|
```tsx
|
|
33
|
-
import { Radio
|
|
31
|
+
import { Radio } from '@ceed/ads';
|
|
34
32
|
|
|
35
33
|
function MyComponent() {
|
|
36
34
|
const [selectedValue, setSelectedValue] = useState('option1');
|
|
37
35
|
|
|
38
36
|
return (
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
<div>
|
|
38
|
+
<Radio
|
|
39
|
+
name="example"
|
|
40
|
+
value="option1"
|
|
41
|
+
checked={selectedValue === 'option1'}
|
|
42
|
+
onChange={(e) => setSelectedValue(e.target.value)}
|
|
43
|
+
label="옵션 1"
|
|
44
|
+
/>
|
|
45
|
+
<Radio
|
|
46
|
+
name="example"
|
|
47
|
+
value="option2"
|
|
48
|
+
checked={selectedValue === 'option2'}
|
|
49
|
+
onChange={(e) => setSelectedValue(e.target.value)}
|
|
50
|
+
label="옵션 2"
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
48
53
|
);
|
|
49
54
|
}
|
|
50
55
|
```
|
|
51
56
|
|
|
52
|
-
##
|
|
57
|
+
## Examples
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
### Variants
|
|
55
60
|
|
|
56
61
|
```tsx
|
|
57
62
|
<FormControl>
|
|
@@ -65,9 +70,7 @@ Radio supports four visual variants: `outlined` (default), `soft`, `solid`, and
|
|
|
65
70
|
</FormControl>
|
|
66
71
|
```
|
|
67
72
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Three size presets are available: `sm`, `md` (default), and `lg`. Use smaller sizes for compact layouts and larger sizes for touch-friendly interfaces.
|
|
73
|
+
### Sizes
|
|
71
74
|
|
|
72
75
|
```tsx
|
|
73
76
|
<FormControl>
|
|
@@ -80,9 +83,7 @@ Three size presets are available: `sm`, `md` (default), and `lg`. Use smaller si
|
|
|
80
83
|
</FormControl>
|
|
81
84
|
```
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
Radio supports five semantic colors: `primary`, `neutral`, `danger`, `success`, and `warning`. Use semantic colors to convey meaning -- for example, `danger` for destructive options or `success` for confirmed selections.
|
|
86
|
+
### Colors
|
|
86
87
|
|
|
87
88
|
```tsx
|
|
88
89
|
<FormControl>
|
|
@@ -97,9 +98,9 @@ Radio supports five semantic colors: `primary`, `neutral`, `danger`, `success`,
|
|
|
97
98
|
</FormControl>
|
|
98
99
|
```
|
|
99
100
|
|
|
100
|
-
|
|
101
|
+
### Custom Icons
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
아이콘을 커스터마이징하여 특별한 용도로 사용할 수 있습니다.
|
|
103
104
|
|
|
104
105
|
```tsx
|
|
105
106
|
<RadioGroup aria-label="platform" defaultValue="Website" overlay name="platform" sx={{
|
|
@@ -141,9 +142,9 @@ Replace the default radio indicator with custom icons using the `checkedIcon` pr
|
|
|
141
142
|
</RadioGroup>
|
|
142
143
|
```
|
|
143
144
|
|
|
144
|
-
|
|
145
|
+
### No Icon
|
|
145
146
|
|
|
146
|
-
|
|
147
|
+
아이콘 없이 텍스트만으로 구성할 수 있습니다.
|
|
147
148
|
|
|
148
149
|
```tsx
|
|
149
150
|
<Box sx={{
|
|
@@ -194,9 +195,9 @@ Storage
|
|
|
194
195
|
</Box>
|
|
195
196
|
```
|
|
196
197
|
|
|
197
|
-
|
|
198
|
+
### Segmented Controls
|
|
198
199
|
|
|
199
|
-
|
|
200
|
+
세그먼트 컨트롤 스타일로 사용할 수 있습니다.
|
|
200
201
|
|
|
201
202
|
```tsx
|
|
202
203
|
<Box sx={{
|
|
@@ -237,9 +238,9 @@ Radio buttons can be styled as segmented controls for compact, inline option swi
|
|
|
237
238
|
</Box>
|
|
238
239
|
```
|
|
239
240
|
|
|
240
|
-
|
|
241
|
+
### Product Attributes
|
|
241
242
|
|
|
242
|
-
|
|
243
|
+
제품 속성 선택 등의 용도로 활용할 수 있습니다.
|
|
243
244
|
|
|
244
245
|
```tsx
|
|
245
246
|
<Box sx={{
|
|
@@ -336,143 +337,14 @@ Size
|
|
|
336
337
|
</Box>
|
|
337
338
|
```
|
|
338
339
|
|
|
339
|
-
## Common Use Cases
|
|
340
|
-
|
|
341
|
-
### Survey / Questionnaire Form
|
|
342
|
-
|
|
343
|
-
```tsx
|
|
344
|
-
function SurveyQuestion() {
|
|
345
|
-
const [answer, setAnswer] = useState('');
|
|
346
|
-
|
|
347
|
-
return (
|
|
348
|
-
<FormControl>
|
|
349
|
-
<FormLabel>How satisfied are you with our service?</FormLabel>
|
|
350
|
-
<RadioGroup
|
|
351
|
-
name="satisfaction"
|
|
352
|
-
value={answer}
|
|
353
|
-
onChange={(e) => setAnswer(e.target.value)}
|
|
354
|
-
>
|
|
355
|
-
<Radio value="very-satisfied" label="Very Satisfied" color="success" />
|
|
356
|
-
<Radio value="satisfied" label="Satisfied" />
|
|
357
|
-
<Radio value="neutral" label="Neutral" />
|
|
358
|
-
<Radio value="dissatisfied" label="Dissatisfied" color="warning" />
|
|
359
|
-
<Radio value="very-dissatisfied" label="Very Dissatisfied" color="danger" />
|
|
360
|
-
</RadioGroup>
|
|
361
|
-
</FormControl>
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### Payment Method Selection
|
|
367
|
-
|
|
368
|
-
```tsx
|
|
369
|
-
function PaymentMethodSelector() {
|
|
370
|
-
const [method, setMethod] = useState('credit-card');
|
|
371
|
-
|
|
372
|
-
return (
|
|
373
|
-
<FormControl>
|
|
374
|
-
<FormLabel>Payment Method</FormLabel>
|
|
375
|
-
<RadioGroup
|
|
376
|
-
name="payment"
|
|
377
|
-
value={method}
|
|
378
|
-
onChange={(e) => setMethod(e.target.value)}
|
|
379
|
-
sx={{ gap: 1.5 }}
|
|
380
|
-
>
|
|
381
|
-
{[
|
|
382
|
-
{ value: 'credit-card', label: 'Credit Card' },
|
|
383
|
-
{ value: 'bank-transfer', label: 'Bank Transfer' },
|
|
384
|
-
{ value: 'paypal', label: 'PayPal' },
|
|
385
|
-
].map((option) => (
|
|
386
|
-
<Sheet key={option.value} variant="outlined" sx={{ p: 2, borderRadius: 'md' }}>
|
|
387
|
-
<Radio
|
|
388
|
-
overlay
|
|
389
|
-
value={option.value}
|
|
390
|
-
label={option.label}
|
|
391
|
-
slotProps={{
|
|
392
|
-
action: ({ checked }) => ({
|
|
393
|
-
sx: {
|
|
394
|
-
...(checked && {
|
|
395
|
-
'--variant-borderWidth': '2px',
|
|
396
|
-
borderColor: 'primary.500',
|
|
397
|
-
}),
|
|
398
|
-
},
|
|
399
|
-
}),
|
|
400
|
-
}}
|
|
401
|
-
/>
|
|
402
|
-
</Sheet>
|
|
403
|
-
))}
|
|
404
|
-
</RadioGroup>
|
|
405
|
-
</FormControl>
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### Shipping Speed Selection
|
|
411
|
-
|
|
412
|
-
```tsx
|
|
413
|
-
function ShippingOptions() {
|
|
414
|
-
const [shipping, setShipping] = useState('standard');
|
|
415
|
-
|
|
416
|
-
return (
|
|
417
|
-
<FormControl>
|
|
418
|
-
<FormLabel>Shipping Speed</FormLabel>
|
|
419
|
-
<RadioGroup
|
|
420
|
-
name="shipping"
|
|
421
|
-
value={shipping}
|
|
422
|
-
onChange={(e) => setShipping(e.target.value)}
|
|
423
|
-
>
|
|
424
|
-
<Radio value="standard" label="Standard (5-7 business days) - Free" />
|
|
425
|
-
<Radio value="express" label="Express (2-3 business days) - $9.99" />
|
|
426
|
-
<Radio value="overnight" label="Overnight (next day) - $24.99" />
|
|
427
|
-
</RadioGroup>
|
|
428
|
-
</FormControl>
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
```
|
|
432
|
-
|
|
433
340
|
## Best Practices
|
|
434
341
|
|
|
435
|
-
1.
|
|
436
|
-
|
|
437
|
-
```tsx
|
|
438
|
-
// ✅ Wrapped in RadioGroup
|
|
439
|
-
<RadioGroup name="options" value={value} onChange={handleChange}>
|
|
440
|
-
<Radio value="a" label="Option A" />
|
|
441
|
-
<Radio value="b" label="Option B" />
|
|
442
|
-
</RadioGroup>
|
|
443
|
-
|
|
444
|
-
// ❌ Standalone radios without a group
|
|
445
|
-
<Radio name="options" value="a" label="Option A" />
|
|
446
|
-
<Radio name="options" value="b" label="Option B" />
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
2. **Provide clear labels**: Every radio button must have a visible label or an `aria-label` to describe its purpose.
|
|
450
|
-
|
|
451
|
-
```tsx
|
|
452
|
-
// ✅ Descriptive label
|
|
453
|
-
<Radio value="monthly" label="Monthly billing ($10/month)" />
|
|
454
|
-
|
|
455
|
-
// ❌ Vague label
|
|
456
|
-
<Radio value="monthly" label="Option 1" />
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
3. **Set a default selection**: Pre-select the most common or recommended option using `defaultValue` or a controlled `value` to reduce user effort.
|
|
460
|
-
|
|
461
|
-
```tsx
|
|
462
|
-
// ✅ Sensible default
|
|
463
|
-
<RadioGroup defaultValue="standard" name="shipping">
|
|
464
|
-
<Radio value="standard" label="Standard Shipping" />
|
|
465
|
-
<Radio value="express" label="Express Shipping" />
|
|
466
|
-
</RadioGroup>
|
|
467
|
-
```
|
|
342
|
+
1. **그룹 사용**: Radio 버튼들은 반드시 동일한 `name` 속성을 가진 그룹으로 사용해야 합니다.
|
|
468
343
|
|
|
469
|
-
|
|
344
|
+
2. **레이블 제공**: 접근성을 위해 항상 의미 있는 `label`을 제공하세요.
|
|
470
345
|
|
|
471
|
-
|
|
346
|
+
3. **초기값 설정**: 사용자 경험을 위해 적절한 초기값을 설정하는 것이 좋습니다.
|
|
472
347
|
|
|
473
|
-
|
|
348
|
+
4. **적절한 간격**: 여러 라디오 버튼 간에는 충분한 간격을 두어 선택하기 쉽게 만드세요.
|
|
474
349
|
|
|
475
|
-
|
|
476
|
-
- **ARIA roles**: `RadioGroup` renders with `role="radiogroup"`, and each `Radio` renders with `role="radio"` and `aria-checked` reflecting its state.
|
|
477
|
-
- **Labeling**: Always connect a `FormLabel` to the `RadioGroup` via `aria-labelledby`, or provide an `aria-label` directly on the group so screen readers can announce the group purpose.
|
|
478
|
-
- **Focus management**: When using `overlay` or `disableIcon` patterns, ensure the interactive area is clearly communicated -- the `overlay` prop extends the clickable area to the parent container, which is also reflected in focus styling.
|
|
350
|
+
5. **상태 관리**: 제어 컴포넌트로 사용하여 상태를 명확히 관리하세요.
|