torch-glare 2.5.6 → 2.6.0
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/README.md +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -403
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -325
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -395
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -88
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -72
- package/apps/lib/components/DataViews/states.tsx +0 -73
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -451
- package/apps/lib/components/DropdownMenu.tsx +0 -554
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -85
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -168
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -114
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -67
- package/apps/lib/components/FormBuilder/types.ts +0 -316
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -250
- package/apps/lib/components/FormRenderer/detail.tsx +0 -256
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -358
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -17
- package/apps/lib/components/FormRenderer/notch-action.tsx +0 -64
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -393
- package/apps/lib/components/FormRenderer/types.ts +0 -115
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -168
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -255
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -597
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -61
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useHtmlDir.ts +0 -31
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -300
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1217
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/scroller.ts +0 -26
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -738
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1521
- package/docs/components/data-views/migration.md +0 -81
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -284
- package/docs/components/form-renderer.md +0 -396
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -483
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -60
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1523
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -726
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
|
@@ -1,796 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: LabeledRadio
|
|
3
|
-
version: 2.4.5
|
|
4
|
-
status: stable
|
|
5
|
-
category: components/forms
|
|
6
|
-
tags: [form, radio, label, selection, accessible, compound]
|
|
7
|
-
last-reviewed: 2024-11-05
|
|
8
|
-
bundle-size: 2.2kb
|
|
9
|
-
dependencies:
|
|
10
|
-
- "@/components/Radio": "internal"
|
|
11
|
-
- "@/components/Label": "internal"
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# LabeledRadio
|
|
15
|
-
|
|
16
|
-
> A radio button component with integrated label, supporting required indicators and secondary labels. Combines Radio and Label components for a complete form field solution with automatic accessibility handling.
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
21
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npx torch-glare@latest init
|
|
25
|
-
npx torch-glare@latest add LabeledRadio
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
`add` also copies any components, hooks, and utilities that `LabeledRadio` depends on.
|
|
29
|
-
|
|
30
|
-
## Import
|
|
31
|
-
|
|
32
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
33
|
-
|
|
34
|
-
```tsx
|
|
35
|
-
import { LabeledRadio } from "@/components/LabeledRadio";
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Quick Examples
|
|
39
|
-
|
|
40
|
-
### Basic Usage
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
import { LabeledRadio } from '@/components/LabeledRadio'
|
|
44
|
-
import { RadioGroup } from '@/components/Radio'
|
|
45
|
-
|
|
46
|
-
function Example() {
|
|
47
|
-
const [selected, setSelected] = useState('option1')
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<RadioGroup value={selected} onValueChange={setSelected}>
|
|
51
|
-
<LabeledRadio
|
|
52
|
-
value="option1"
|
|
53
|
-
id="radio1"
|
|
54
|
-
label="Option 1"
|
|
55
|
-
/>
|
|
56
|
-
<LabeledRadio
|
|
57
|
-
value="option2"
|
|
58
|
-
id="radio2"
|
|
59
|
-
label="Option 2"
|
|
60
|
-
/>
|
|
61
|
-
<LabeledRadio
|
|
62
|
-
value="option3"
|
|
63
|
-
id="radio3"
|
|
64
|
-
label="Option 3"
|
|
65
|
-
/>
|
|
66
|
-
</RadioGroup>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### With Secondary Labels
|
|
72
|
-
|
|
73
|
-
```typescript
|
|
74
|
-
function DetailedOptions() {
|
|
75
|
-
const [plan, setPlan] = useState('basic')
|
|
76
|
-
|
|
77
|
-
return (
|
|
78
|
-
<RadioGroup value={plan} onValueChange={setPlan}>
|
|
79
|
-
<LabeledRadio
|
|
80
|
-
value="basic"
|
|
81
|
-
id="plan-basic"
|
|
82
|
-
label="Basic Plan"
|
|
83
|
-
secondaryLabel="$9.99/month"
|
|
84
|
-
/>
|
|
85
|
-
<LabeledRadio
|
|
86
|
-
value="pro"
|
|
87
|
-
id="plan-pro"
|
|
88
|
-
label="Pro Plan"
|
|
89
|
-
secondaryLabel="$19.99/month"
|
|
90
|
-
/>
|
|
91
|
-
<LabeledRadio
|
|
92
|
-
value="enterprise"
|
|
93
|
-
id="plan-enterprise"
|
|
94
|
-
label="Enterprise Plan"
|
|
95
|
-
secondaryLabel="Contact for pricing"
|
|
96
|
-
/>
|
|
97
|
-
</RadioGroup>
|
|
98
|
-
)
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### Required Selection
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
function RequiredRadioGroup() {
|
|
106
|
-
const [agreement, setAgreement] = useState('')
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<fieldset>
|
|
110
|
-
<legend>Terms Acceptance</legend>
|
|
111
|
-
<RadioGroup value={agreement} onValueChange={setAgreement} required>
|
|
112
|
-
<LabeledRadio
|
|
113
|
-
value="agree"
|
|
114
|
-
id="terms-agree"
|
|
115
|
-
label="I agree"
|
|
116
|
-
requiredLabel="*"
|
|
117
|
-
secondaryLabel="Accept all terms and conditions"
|
|
118
|
-
/>
|
|
119
|
-
<LabeledRadio
|
|
120
|
-
value="disagree"
|
|
121
|
-
id="terms-disagree"
|
|
122
|
-
label="I disagree"
|
|
123
|
-
requiredLabel="*"
|
|
124
|
-
secondaryLabel="Decline terms and conditions"
|
|
125
|
-
/>
|
|
126
|
-
</RadioGroup>
|
|
127
|
-
</fieldset>
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Different Sizes
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
function SizeVariants() {
|
|
136
|
-
const [size, setSize] = useState('medium')
|
|
137
|
-
|
|
138
|
-
return (
|
|
139
|
-
<div className="space-y-6">
|
|
140
|
-
<RadioGroup value={size} onValueChange={setSize}>
|
|
141
|
-
<LabeledRadio
|
|
142
|
-
value="small"
|
|
143
|
-
id="size-s"
|
|
144
|
-
label="Small size"
|
|
145
|
-
size="S"
|
|
146
|
-
/>
|
|
147
|
-
<LabeledRadio
|
|
148
|
-
value="medium"
|
|
149
|
-
id="size-m"
|
|
150
|
-
label="Medium size (default)"
|
|
151
|
-
size="M"
|
|
152
|
-
/>
|
|
153
|
-
<LabeledRadio
|
|
154
|
-
value="large"
|
|
155
|
-
id="size-l"
|
|
156
|
-
label="Large size"
|
|
157
|
-
size="L"
|
|
158
|
-
/>
|
|
159
|
-
</RadioGroup>
|
|
160
|
-
</div>
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Themed Options
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
function ThemedRadios() {
|
|
169
|
-
const [theme, setTheme] = useState('light')
|
|
170
|
-
|
|
171
|
-
return (
|
|
172
|
-
<RadioGroup value={theme} onValueChange={setTheme}>
|
|
173
|
-
<LabeledRadio
|
|
174
|
-
value="light"
|
|
175
|
-
id="theme-light"
|
|
176
|
-
label="Light Theme"
|
|
177
|
-
theme="light"
|
|
178
|
-
/>
|
|
179
|
-
<LabeledRadio
|
|
180
|
-
value="dark"
|
|
181
|
-
id="theme-dark"
|
|
182
|
-
label="Dark Theme"
|
|
183
|
-
theme="dark"
|
|
184
|
-
/>
|
|
185
|
-
<LabeledRadio
|
|
186
|
-
value="auto"
|
|
187
|
-
id="theme-auto"
|
|
188
|
-
label="Auto Theme"
|
|
189
|
-
theme="default"
|
|
190
|
-
/>
|
|
191
|
-
</RadioGroup>
|
|
192
|
-
)
|
|
193
|
-
}
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Shipping Options
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
function ShippingOptions() {
|
|
200
|
-
const [shipping, setShipping] = useState('standard')
|
|
201
|
-
|
|
202
|
-
const options = [
|
|
203
|
-
{
|
|
204
|
-
value: 'standard',
|
|
205
|
-
label: 'Standard Shipping',
|
|
206
|
-
secondary: '5-7 business days - Free'
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
value: 'express',
|
|
210
|
-
label: 'Express Shipping',
|
|
211
|
-
secondary: '2-3 business days - $9.99'
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
value: 'overnight',
|
|
215
|
-
label: 'Overnight Shipping',
|
|
216
|
-
secondary: 'Next business day - $24.99'
|
|
217
|
-
}
|
|
218
|
-
]
|
|
219
|
-
|
|
220
|
-
return (
|
|
221
|
-
<div className="p-4 border rounded">
|
|
222
|
-
<h3 className="font-semibold mb-4">Select Shipping Method</h3>
|
|
223
|
-
<RadioGroup value={shipping} onValueChange={setShipping}>
|
|
224
|
-
<div className="space-y-3">
|
|
225
|
-
{options.map((option) => (
|
|
226
|
-
<div
|
|
227
|
-
key={option.value}
|
|
228
|
-
className="p-3 border rounded hover:bg-gray-50"
|
|
229
|
-
>
|
|
230
|
-
<LabeledRadio
|
|
231
|
-
value={option.value}
|
|
232
|
-
id={`shipping-${option.value}`}
|
|
233
|
-
label={option.label}
|
|
234
|
-
secondaryLabel={option.secondary}
|
|
235
|
-
/>
|
|
236
|
-
</div>
|
|
237
|
-
))}
|
|
238
|
-
</div>
|
|
239
|
-
</RadioGroup>
|
|
240
|
-
</div>
|
|
241
|
-
)
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## API Reference
|
|
246
|
-
|
|
247
|
-
### LabeledRadio Props
|
|
248
|
-
|
|
249
|
-
| Prop | Type | Default | Description |
|
|
250
|
-
|------|------|---------|-------------|
|
|
251
|
-
| `value` | `string` | - | Radio button value |
|
|
252
|
-
| `id` | `string` | - | HTML id for accessibility |
|
|
253
|
-
| `label` | `string` | - | Primary label text |
|
|
254
|
-
| `secondaryLabel` | `string` | - | Additional descriptive text |
|
|
255
|
-
| `requiredLabel` | `string` | - | Required field indicator |
|
|
256
|
-
| `size` | `'S' \| 'M' \| 'L'` | `'M'` | Size variant |
|
|
257
|
-
| `theme` | `'dark' \| 'light' \| 'default'` | - | Theme variant |
|
|
258
|
-
| `name` | `string` | - | Form field name |
|
|
259
|
-
| `disabled` | `boolean` | `false` | Disables the radio |
|
|
260
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
261
|
-
|
|
262
|
-
Note: Must be used within a `RadioGroup` component.
|
|
263
|
-
|
|
264
|
-
### TypeScript
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
import { ComponentProps } from 'react'
|
|
268
|
-
import { Radio } from '@/components/Radio'
|
|
269
|
-
|
|
270
|
-
interface LabeledRadioProps extends Omit<ComponentProps<typeof Radio>, 'size'> {
|
|
271
|
-
label?: string
|
|
272
|
-
secondaryLabel?: string
|
|
273
|
-
requiredLabel?: string
|
|
274
|
-
size?: 'S' | 'M' | 'L'
|
|
275
|
-
theme?: 'dark' | 'light' | 'default'
|
|
276
|
-
name?: string
|
|
277
|
-
id?: string
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
export const LabeledRadio: React.ForwardRefExoticComponent<LabeledRadioProps>
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
## Common Patterns
|
|
284
|
-
|
|
285
|
-
### Payment Methods
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
function PaymentMethodSelector() {
|
|
289
|
-
const [method, setMethod] = useState('card')
|
|
290
|
-
|
|
291
|
-
const methods = [
|
|
292
|
-
{
|
|
293
|
-
value: 'card',
|
|
294
|
-
label: 'Credit/Debit Card',
|
|
295
|
-
secondary: 'Visa, Mastercard, Amex',
|
|
296
|
-
icon: '💳'
|
|
297
|
-
},
|
|
298
|
-
{
|
|
299
|
-
value: 'paypal',
|
|
300
|
-
label: 'PayPal',
|
|
301
|
-
secondary: 'Pay with your PayPal account',
|
|
302
|
-
icon: '💰'
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
value: 'bank',
|
|
306
|
-
label: 'Bank Transfer',
|
|
307
|
-
secondary: '3-5 business days',
|
|
308
|
-
icon: '🏦'
|
|
309
|
-
}
|
|
310
|
-
]
|
|
311
|
-
|
|
312
|
-
return (
|
|
313
|
-
<div className="space-y-4">
|
|
314
|
-
<h3 className="font-semibold">Payment Method</h3>
|
|
315
|
-
<RadioGroup value={method} onValueChange={setMethod}>
|
|
316
|
-
{methods.map((m) => (
|
|
317
|
-
<div
|
|
318
|
-
key={m.value}
|
|
319
|
-
className="flex items-start space-x-2 p-3 border rounded hover:border-blue-500"
|
|
320
|
-
>
|
|
321
|
-
<span className="text-2xl mr-2">{m.icon}</span>
|
|
322
|
-
<LabeledRadio
|
|
323
|
-
value={m.value}
|
|
324
|
-
id={`payment-${m.value}`}
|
|
325
|
-
label={m.label}
|
|
326
|
-
secondaryLabel={m.secondary}
|
|
327
|
-
/>
|
|
328
|
-
</div>
|
|
329
|
-
))}
|
|
330
|
-
</RadioGroup>
|
|
331
|
-
</div>
|
|
332
|
-
)
|
|
333
|
-
}
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
### Notification Preferences
|
|
337
|
-
|
|
338
|
-
```typescript
|
|
339
|
-
function NotificationSettings() {
|
|
340
|
-
const [frequency, setFrequency] = useState('daily')
|
|
341
|
-
|
|
342
|
-
return (
|
|
343
|
-
<div className="space-y-4">
|
|
344
|
-
<h3 className="font-semibold">Email Notification Frequency</h3>
|
|
345
|
-
<RadioGroup value={frequency} onValueChange={setFrequency}>
|
|
346
|
-
<LabeledRadio
|
|
347
|
-
value="realtime"
|
|
348
|
-
id="freq-realtime"
|
|
349
|
-
label="Real-time"
|
|
350
|
-
secondaryLabel="Get notified immediately"
|
|
351
|
-
/>
|
|
352
|
-
<LabeledRadio
|
|
353
|
-
value="daily"
|
|
354
|
-
id="freq-daily"
|
|
355
|
-
label="Daily Digest"
|
|
356
|
-
secondaryLabel="Summary once a day at 9 AM"
|
|
357
|
-
/>
|
|
358
|
-
<LabeledRadio
|
|
359
|
-
value="weekly"
|
|
360
|
-
id="freq-weekly"
|
|
361
|
-
label="Weekly Summary"
|
|
362
|
-
secondaryLabel="Every Monday morning"
|
|
363
|
-
/>
|
|
364
|
-
<LabeledRadio
|
|
365
|
-
value="never"
|
|
366
|
-
id="freq-never"
|
|
367
|
-
label="Never"
|
|
368
|
-
secondaryLabel="No email notifications"
|
|
369
|
-
/>
|
|
370
|
-
</RadioGroup>
|
|
371
|
-
</div>
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
```
|
|
375
|
-
|
|
376
|
-
### Survey Questions
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
function SurveyForm() {
|
|
380
|
-
const [experience, setExperience] = useState('')
|
|
381
|
-
const [recommendation, setRecommendation] = useState('')
|
|
382
|
-
|
|
383
|
-
return (
|
|
384
|
-
<form className="space-y-6">
|
|
385
|
-
<div>
|
|
386
|
-
<h3 className="font-semibold mb-3">How was your experience?</h3>
|
|
387
|
-
<RadioGroup value={experience} onValueChange={setExperience}>
|
|
388
|
-
<LabeledRadio
|
|
389
|
-
value="excellent"
|
|
390
|
-
id="exp-excellent"
|
|
391
|
-
label="😊 Excellent"
|
|
392
|
-
size="L"
|
|
393
|
-
/>
|
|
394
|
-
<LabeledRadio
|
|
395
|
-
value="good"
|
|
396
|
-
id="exp-good"
|
|
397
|
-
label="🙂 Good"
|
|
398
|
-
size="L"
|
|
399
|
-
/>
|
|
400
|
-
<LabeledRadio
|
|
401
|
-
value="average"
|
|
402
|
-
id="exp-average"
|
|
403
|
-
label="😐 Average"
|
|
404
|
-
size="L"
|
|
405
|
-
/>
|
|
406
|
-
<LabeledRadio
|
|
407
|
-
value="poor"
|
|
408
|
-
id="exp-poor"
|
|
409
|
-
label="😕 Poor"
|
|
410
|
-
size="L"
|
|
411
|
-
/>
|
|
412
|
-
</RadioGroup>
|
|
413
|
-
</div>
|
|
414
|
-
|
|
415
|
-
<div>
|
|
416
|
-
<h3 className="font-semibold mb-3">Would you recommend us?</h3>
|
|
417
|
-
<RadioGroup value={recommendation} onValueChange={setRecommendation}>
|
|
418
|
-
<LabeledRadio
|
|
419
|
-
value="definitely"
|
|
420
|
-
id="rec-definitely"
|
|
421
|
-
label="Definitely"
|
|
422
|
-
secondaryLabel="I would highly recommend"
|
|
423
|
-
/>
|
|
424
|
-
<LabeledRadio
|
|
425
|
-
value="probably"
|
|
426
|
-
id="rec-probably"
|
|
427
|
-
label="Probably"
|
|
428
|
-
secondaryLabel="I might recommend"
|
|
429
|
-
/>
|
|
430
|
-
<LabeledRadio
|
|
431
|
-
value="not-sure"
|
|
432
|
-
id="rec-not-sure"
|
|
433
|
-
label="Not Sure"
|
|
434
|
-
secondaryLabel="I'm undecided"
|
|
435
|
-
/>
|
|
436
|
-
<LabeledRadio
|
|
437
|
-
value="no"
|
|
438
|
-
id="rec-no"
|
|
439
|
-
label="No"
|
|
440
|
-
secondaryLabel="I would not recommend"
|
|
441
|
-
/>
|
|
442
|
-
</RadioGroup>
|
|
443
|
-
</div>
|
|
444
|
-
|
|
445
|
-
<button type="submit">Submit Survey</button>
|
|
446
|
-
</form>
|
|
447
|
-
)
|
|
448
|
-
}
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
### Account Type Selection
|
|
452
|
-
|
|
453
|
-
```typescript
|
|
454
|
-
function AccountTypeSelector() {
|
|
455
|
-
const [accountType, setAccountType] = useState('')
|
|
456
|
-
|
|
457
|
-
const types = [
|
|
458
|
-
{
|
|
459
|
-
value: 'personal',
|
|
460
|
-
label: 'Personal Account',
|
|
461
|
-
secondary: 'For individual use',
|
|
462
|
-
features: ['5 GB storage', '1 user', 'Basic support']
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
value: 'team',
|
|
466
|
-
label: 'Team Account',
|
|
467
|
-
secondary: 'For small teams',
|
|
468
|
-
features: ['100 GB storage', '10 users', 'Priority support']
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
value: 'enterprise',
|
|
472
|
-
label: 'Enterprise Account',
|
|
473
|
-
secondary: 'For large organizations',
|
|
474
|
-
features: ['Unlimited storage', 'Unlimited users', '24/7 support']
|
|
475
|
-
}
|
|
476
|
-
]
|
|
477
|
-
|
|
478
|
-
return (
|
|
479
|
-
<div>
|
|
480
|
-
<h3 className="font-semibold mb-4">Choose Account Type</h3>
|
|
481
|
-
<RadioGroup value={accountType} onValueChange={setAccountType}>
|
|
482
|
-
{types.map((type) => (
|
|
483
|
-
<div
|
|
484
|
-
key={type.value}
|
|
485
|
-
className="mb-3 p-4 border rounded hover:shadow-md"
|
|
486
|
-
>
|
|
487
|
-
<LabeledRadio
|
|
488
|
-
value={type.value}
|
|
489
|
-
id={`account-${type.value}`}
|
|
490
|
-
label={type.label}
|
|
491
|
-
secondaryLabel={type.secondary}
|
|
492
|
-
size="L"
|
|
493
|
-
/>
|
|
494
|
-
<ul className="mt-2 ml-8 text-sm text-gray-600">
|
|
495
|
-
{type.features.map((feature, i) => (
|
|
496
|
-
<li key={i}>✓ {feature}</li>
|
|
497
|
-
))}
|
|
498
|
-
</ul>
|
|
499
|
-
</div>
|
|
500
|
-
))}
|
|
501
|
-
</RadioGroup>
|
|
502
|
-
</div>
|
|
503
|
-
)
|
|
504
|
-
}
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
## Testing
|
|
508
|
-
|
|
509
|
-
### Unit Test Example
|
|
510
|
-
|
|
511
|
-
```typescript
|
|
512
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
513
|
-
import { LabeledRadio } from '@/components/LabeledRadio'
|
|
514
|
-
import { RadioGroup } from '@/components/Radio'
|
|
515
|
-
|
|
516
|
-
describe('LabeledRadio', () => {
|
|
517
|
-
it('renders label and radio together', () => {
|
|
518
|
-
render(
|
|
519
|
-
<RadioGroup>
|
|
520
|
-
<LabeledRadio
|
|
521
|
-
value="test"
|
|
522
|
-
id="test-radio"
|
|
523
|
-
label="Test Label"
|
|
524
|
-
secondaryLabel="Secondary text"
|
|
525
|
-
/>
|
|
526
|
-
</RadioGroup>
|
|
527
|
-
)
|
|
528
|
-
|
|
529
|
-
expect(screen.getByText('Test Label')).toBeInTheDocument()
|
|
530
|
-
expect(screen.getByText('Secondary text')).toBeInTheDocument()
|
|
531
|
-
expect(screen.getByRole('radio')).toBeInTheDocument()
|
|
532
|
-
})
|
|
533
|
-
|
|
534
|
-
it('handles selection in group', () => {
|
|
535
|
-
const handleChange = jest.fn()
|
|
536
|
-
render(
|
|
537
|
-
<RadioGroup onValueChange={handleChange}>
|
|
538
|
-
<LabeledRadio value="opt1" id="opt1" label="Option 1" />
|
|
539
|
-
<LabeledRadio value="opt2" id="opt2" label="Option 2" />
|
|
540
|
-
</RadioGroup>
|
|
541
|
-
)
|
|
542
|
-
|
|
543
|
-
const radio2 = screen.getAllByRole('radio')[1]
|
|
544
|
-
fireEvent.click(radio2)
|
|
545
|
-
|
|
546
|
-
expect(handleChange).toHaveBeenCalledWith('opt2')
|
|
547
|
-
})
|
|
548
|
-
|
|
549
|
-
it('shows required indicator', () => {
|
|
550
|
-
render(
|
|
551
|
-
<RadioGroup>
|
|
552
|
-
<LabeledRadio
|
|
553
|
-
value="test"
|
|
554
|
-
id="test"
|
|
555
|
-
label="Required field"
|
|
556
|
-
requiredLabel="*"
|
|
557
|
-
/>
|
|
558
|
-
</RadioGroup>
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
expect(screen.getByText('*')).toBeInTheDocument()
|
|
562
|
-
})
|
|
563
|
-
|
|
564
|
-
it('applies size variants', () => {
|
|
565
|
-
const { rerender } = render(
|
|
566
|
-
<RadioGroup>
|
|
567
|
-
<LabeledRadio value="test" id="test" label="Test" size="S" />
|
|
568
|
-
</RadioGroup>
|
|
569
|
-
)
|
|
570
|
-
|
|
571
|
-
// Size S uses size S for label
|
|
572
|
-
expect(screen.getByText('Test')).toBeInTheDocument()
|
|
573
|
-
|
|
574
|
-
rerender(
|
|
575
|
-
<RadioGroup>
|
|
576
|
-
<LabeledRadio value="test" id="test" label="Test" size="L" />
|
|
577
|
-
</RadioGroup>
|
|
578
|
-
)
|
|
579
|
-
|
|
580
|
-
// Size L uses size M for label (per implementation)
|
|
581
|
-
expect(screen.getByText('Test')).toBeInTheDocument()
|
|
582
|
-
})
|
|
583
|
-
})
|
|
584
|
-
```
|
|
585
|
-
|
|
586
|
-
### Accessibility Test
|
|
587
|
-
|
|
588
|
-
```typescript
|
|
589
|
-
import { axe } from '@axe-core/react'
|
|
590
|
-
|
|
591
|
-
test('LabeledRadio meets WCAG standards', async () => {
|
|
592
|
-
const { container } = render(
|
|
593
|
-
<fieldset>
|
|
594
|
-
<legend>Select an option</legend>
|
|
595
|
-
<RadioGroup defaultValue="opt1">
|
|
596
|
-
<LabeledRadio
|
|
597
|
-
value="opt1"
|
|
598
|
-
id="accessible-opt1"
|
|
599
|
-
label="Option 1"
|
|
600
|
-
secondaryLabel="First option"
|
|
601
|
-
/>
|
|
602
|
-
<LabeledRadio
|
|
603
|
-
value="opt2"
|
|
604
|
-
id="accessible-opt2"
|
|
605
|
-
label="Option 2"
|
|
606
|
-
secondaryLabel="Second option"
|
|
607
|
-
/>
|
|
608
|
-
</RadioGroup>
|
|
609
|
-
</fieldset>
|
|
610
|
-
)
|
|
611
|
-
|
|
612
|
-
const results = await axe(container)
|
|
613
|
-
expect(results).toHaveNoViolations()
|
|
614
|
-
})
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
## Accessibility
|
|
618
|
-
|
|
619
|
-
### Automatic Features
|
|
620
|
-
|
|
621
|
-
- Label automatically associated with radio via `id`
|
|
622
|
-
- Proper ARIA attributes inherited from Radio component
|
|
623
|
-
- Required state communicated to screen readers
|
|
624
|
-
- Secondary label provides additional context
|
|
625
|
-
|
|
626
|
-
### Keyboard Support
|
|
627
|
-
|
|
628
|
-
- **Tab**: Move focus into radio group
|
|
629
|
-
- **Arrow Keys**: Navigate between options
|
|
630
|
-
- **Space**: Select focused option
|
|
631
|
-
|
|
632
|
-
### Screen Reader Support
|
|
633
|
-
|
|
634
|
-
```html
|
|
635
|
-
<!-- Rendered HTML structure -->
|
|
636
|
-
<label for="radio-id">
|
|
637
|
-
<span>Primary Label</span>
|
|
638
|
-
<span>*</span>
|
|
639
|
-
<span>Secondary Label</span>
|
|
640
|
-
<button
|
|
641
|
-
role="radio"
|
|
642
|
-
aria-checked="false"
|
|
643
|
-
id="radio-id"
|
|
644
|
-
/>
|
|
645
|
-
</label>
|
|
646
|
-
```
|
|
647
|
-
|
|
648
|
-
### Best Practices
|
|
649
|
-
|
|
650
|
-
```typescript
|
|
651
|
-
// Always use within RadioGroup
|
|
652
|
-
<RadioGroup>
|
|
653
|
-
<LabeledRadio {...props} />
|
|
654
|
-
</RadioGroup>
|
|
655
|
-
|
|
656
|
-
// Use fieldset/legend for semantic grouping
|
|
657
|
-
<fieldset>
|
|
658
|
-
<legend>Question</legend>
|
|
659
|
-
<RadioGroup>
|
|
660
|
-
<LabeledRadio {...props} />
|
|
661
|
-
</RadioGroup>
|
|
662
|
-
</fieldset>
|
|
663
|
-
```
|
|
664
|
-
|
|
665
|
-
## Styling
|
|
666
|
-
|
|
667
|
-
### Custom Styles
|
|
668
|
-
|
|
669
|
-
```typescript
|
|
670
|
-
<LabeledRadio
|
|
671
|
-
value="custom"
|
|
672
|
-
id="custom"
|
|
673
|
-
label="Custom styled"
|
|
674
|
-
className="text-blue-600 hover:text-blue-700"
|
|
675
|
-
size="L"
|
|
676
|
-
/>
|
|
677
|
-
```
|
|
678
|
-
|
|
679
|
-
### Size Variants Mapping
|
|
680
|
-
|
|
681
|
-
| LabeledRadio Size | Radio Size | Label Size |
|
|
682
|
-
|-------------------|------------|------------|
|
|
683
|
-
| S | S | S |
|
|
684
|
-
| M | M | M |
|
|
685
|
-
| L | M | M |
|
|
686
|
-
|
|
687
|
-
Note: Large size uses medium radio for visual balance.
|
|
688
|
-
|
|
689
|
-
## Performance
|
|
690
|
-
|
|
691
|
-
| Metric | Value |
|
|
692
|
-
|--------|-------|
|
|
693
|
-
| Bundle size (gzip) | 2.2kb |
|
|
694
|
-
| First render | <7ms |
|
|
695
|
-
| Re-render | <3ms |
|
|
696
|
-
| Tree-shakeable | ✅ |
|
|
697
|
-
|
|
698
|
-
### Optimization Tips
|
|
699
|
-
|
|
700
|
-
1. Use uncontrolled RadioGroup when possible
|
|
701
|
-
2. Memoize complex option lists
|
|
702
|
-
3. Use React.memo for option components
|
|
703
|
-
4. Keep RadioGroup structure flat
|
|
704
|
-
|
|
705
|
-
## Migration
|
|
706
|
-
|
|
707
|
-
### From Separate Radio and Label
|
|
708
|
-
|
|
709
|
-
```diff
|
|
710
|
-
// Old approach
|
|
711
|
-
- <RadioGroup>
|
|
712
|
-
- <div>
|
|
713
|
-
- <Radio value="opt" id="opt" />
|
|
714
|
-
- <label htmlFor="opt">Label</label>
|
|
715
|
-
- </div>
|
|
716
|
-
- </RadioGroup>
|
|
717
|
-
|
|
718
|
-
// New approach
|
|
719
|
-
+ <RadioGroup>
|
|
720
|
-
+ <LabeledRadio
|
|
721
|
-
+ value="opt"
|
|
722
|
-
+ id="opt"
|
|
723
|
-
+ label="Label"
|
|
724
|
-
+ />
|
|
725
|
-
+ </RadioGroup>
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
### From v1.0.x
|
|
729
|
-
|
|
730
|
-
```diff
|
|
731
|
-
// Import path
|
|
732
|
-
- import LabeledRadio from 'torch-glare/LabeledRadio'
|
|
733
|
-
+ import { LabeledRadio } from '@/components/LabeledRadio'
|
|
734
|
-
|
|
735
|
-
// Size prop values
|
|
736
|
-
- <LabeledRadio size="M" />
|
|
737
|
-
+ <LabeledRadio size="S" />
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
## Troubleshooting
|
|
741
|
-
|
|
742
|
-
### Radio not selectable
|
|
743
|
-
|
|
744
|
-
**Solution:** Ensure it's within RadioGroup
|
|
745
|
-
|
|
746
|
-
```typescript
|
|
747
|
-
// ❌ Wrong - not in group
|
|
748
|
-
<LabeledRadio value="opt" label="Option" />
|
|
749
|
-
|
|
750
|
-
// ✅ Correct - within RadioGroup
|
|
751
|
-
<RadioGroup>
|
|
752
|
-
<LabeledRadio value="opt" label="Option" />
|
|
753
|
-
</RadioGroup>
|
|
754
|
-
```
|
|
755
|
-
|
|
756
|
-
### Label not clickable
|
|
757
|
-
|
|
758
|
-
**Solution:** Provide unique `id` prop
|
|
759
|
-
|
|
760
|
-
```typescript
|
|
761
|
-
// ❌ Wrong - missing id
|
|
762
|
-
<LabeledRadio value="opt" label="Click me" />
|
|
763
|
-
|
|
764
|
-
// ✅ Correct - with id
|
|
765
|
-
<LabeledRadio value="opt" id="unique-id" label="Click me" />
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
## Related Components
|
|
769
|
-
|
|
770
|
-
- [Radio](/docs/components/radio.md) - Base radio component
|
|
771
|
-
- [RadioGroup](/docs/components/radio.md#radiogroup) - Radio group container
|
|
772
|
-
- [Label](/docs/components/label.md) - Label component
|
|
773
|
-
- [LabeledCheckBox](/docs/components/labeled-checkbox.md) - Checkbox with label
|
|
774
|
-
- [RadioCard](/docs/components/radio-card.md) - Card-style radio
|
|
775
|
-
|
|
776
|
-
## Browser Support
|
|
777
|
-
|
|
778
|
-
- Chrome 90+ ✅
|
|
779
|
-
- Firefox 88+ ✅
|
|
780
|
-
- Safari 14+ ✅
|
|
781
|
-
- Edge 90+ ✅
|
|
782
|
-
- Mobile browsers ✅
|
|
783
|
-
|
|
784
|
-
## Changelog
|
|
785
|
-
|
|
786
|
-
### v1.1.15
|
|
787
|
-
- Integrated Label component
|
|
788
|
-
- Added size variants
|
|
789
|
-
- Improved accessibility
|
|
790
|
-
|
|
791
|
-
### v1.1.14
|
|
792
|
-
- Added theme support
|
|
793
|
-
- Fixed label association
|
|
794
|
-
|
|
795
|
-
### v1.1.0
|
|
796
|
-
- Initial stable release
|