dst-rg 1.0.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.
Files changed (249) hide show
  1. package/.gitlab-ci.yml +43 -0
  2. package/.storybook/main.ts +15 -0
  3. package/.storybook/preview.ts +15 -0
  4. package/README.md +254 -0
  5. package/components.json +21 -0
  6. package/dist/Avatar.png +0 -0
  7. package/dist/assets/index-CCq7hmG3.js +186 -0
  8. package/dist/assets/index-Mg-hjQGu.css +1 -0
  9. package/dist/index.html +15 -0
  10. package/dist/test.png +0 -0
  11. package/dist/vite.svg +1 -0
  12. package/eslint.config.js +29 -0
  13. package/index.html +14 -0
  14. package/package.json +102 -0
  15. package/postcss.config.mjs +11 -0
  16. package/rollup.config.mjs +55 -0
  17. package/src/assets/react.svg +1 -0
  18. package/src/assets/style/animation.css +27 -0
  19. package/src/assets/style/box-shadow.css +25 -0
  20. package/src/assets/style/colors.css +402 -0
  21. package/src/assets/style/dark-theme.css +288 -0
  22. package/src/assets/style/font-size.css +14 -0
  23. package/src/assets/style/gradient.css +3 -0
  24. package/src/assets/style/index.css +12 -0
  25. package/src/assets/style/light-theme.css +148 -0
  26. package/src/assets/style/line-height.css +13 -0
  27. package/src/assets/style/max-width.css +5 -0
  28. package/src/assets/style/radius.css +13 -0
  29. package/src/assets/style/utility-colors.css +166 -0
  30. package/src/components/Accordion/_.stories.tsx +75 -0
  31. package/src/components/Accordion/_.test.tsx +77 -0
  32. package/src/components/Accordion/index.tsx +47 -0
  33. package/src/components/Accordion/type.ts +24 -0
  34. package/src/components/Avatar/_.stories.tsx +179 -0
  35. package/src/components/Avatar/_.style.ts +40 -0
  36. package/src/components/Avatar/_.test.tsx +150 -0
  37. package/src/components/Avatar/_.types.ts +66 -0
  38. package/src/components/Avatar/index.tsx +63 -0
  39. package/src/components/Badge/_.stories.tsx +75 -0
  40. package/src/components/Badge/_.style.ts +53 -0
  41. package/src/components/Badge/_.test.tsx +27 -0
  42. package/src/components/Badge/_.types.ts +11 -0
  43. package/src/components/Badge/index.tsx +42 -0
  44. package/src/components/Breadcrumbs/_.stories.tsx +95 -0
  45. package/src/components/Breadcrumbs/_.test.tsx +29 -0
  46. package/src/components/Breadcrumbs/_.type.ts +15 -0
  47. package/src/components/Breadcrumbs/index.tsx +103 -0
  48. package/src/components/Button/_.stories.tsx +85 -0
  49. package/src/components/Button/_.style.ts +56 -0
  50. package/src/components/Button/_.test.tsx +103 -0
  51. package/src/components/Button/_.types.ts +14 -0
  52. package/src/components/Button/index.tsx +70 -0
  53. package/src/components/Checkbox/_.stories.tsx +96 -0
  54. package/src/components/Checkbox/_.style.ts +24 -0
  55. package/src/components/Checkbox/_.test.tsx +85 -0
  56. package/src/components/Checkbox/_.types.ts +23 -0
  57. package/src/components/Checkbox/index.tsx +93 -0
  58. package/src/components/CheckboxGroup/PaymentCard/_.stories.tsx +104 -0
  59. package/src/components/CheckboxGroup/PaymentCard/_.style.ts +28 -0
  60. package/src/components/CheckboxGroup/PaymentCard/_.test.tsx +58 -0
  61. package/src/components/CheckboxGroup/PaymentCard/_.types.ts +28 -0
  62. package/src/components/CheckboxGroup/PaymentCard/index.tsx +71 -0
  63. package/src/components/CheckboxGroup/PlanCard/_.stories.tsx +165 -0
  64. package/src/components/CheckboxGroup/PlanCard/_.style.ts +32 -0
  65. package/src/components/CheckboxGroup/PlanCard/_.test.tsx +54 -0
  66. package/src/components/CheckboxGroup/PlanCard/_.types.ts +35 -0
  67. package/src/components/CheckboxGroup/PlanCard/index.tsx +53 -0
  68. package/src/components/CheckboxGroup/UserCard/_.stories.tsx +89 -0
  69. package/src/components/CheckboxGroup/UserCard/_.style.ts +42 -0
  70. package/src/components/CheckboxGroup/UserCard/_.test.tsx +66 -0
  71. package/src/components/CheckboxGroup/UserCard/_.types.ts +26 -0
  72. package/src/components/CheckboxGroup/UserCard/index.tsx +75 -0
  73. package/src/components/Dropdown/_.stories.tsx +180 -0
  74. package/src/components/Dropdown/_.style.ts +108 -0
  75. package/src/components/Dropdown/_.test.tsx +334 -0
  76. package/src/components/Dropdown/_.types.ts +12 -0
  77. package/src/components/Dropdown/index.tsx +130 -0
  78. package/src/components/FileUpload/_.stories.tsx +74 -0
  79. package/src/components/FileUpload/_.style.ts +0 -0
  80. package/src/components/FileUpload/_.test.tsx +222 -0
  81. package/src/components/FileUpload/_.types.ts +53 -0
  82. package/src/components/FileUpload/index.tsx +44 -0
  83. package/src/components/ImageMagnify/_.stories.tsx +226 -0
  84. package/src/components/ImageMagnify/_.style.ts +109 -0
  85. package/src/components/ImageMagnify/_.types.ts +44 -0
  86. package/src/components/ImageMagnify/index.tsx +204 -0
  87. package/src/components/Input/_.stories.tsx +177 -0
  88. package/src/components/Input/_.style.ts +79 -0
  89. package/src/components/Input/_.test.tsx +146 -0
  90. package/src/components/Input/_.types.ts +66 -0
  91. package/src/components/Input/index.tsx +231 -0
  92. package/src/components/InputTags/_.stories.tsx +51 -0
  93. package/src/components/InputTags/_.style.ts +28 -0
  94. package/src/components/InputTags/_.test.tsx +123 -0
  95. package/src/components/InputTags/_.types.ts +26 -0
  96. package/src/components/InputTags/index.tsx +140 -0
  97. package/src/components/Message/_.stories.tsx +79 -0
  98. package/src/components/Message/_.style.ts +87 -0
  99. package/src/components/Message/_.test.tsx +73 -0
  100. package/src/components/Message/_.types.ts +13 -0
  101. package/src/components/Message/index.tsx +57 -0
  102. package/src/components/Metric/_.stories.tsx +142 -0
  103. package/src/components/Metric/_.style.ts +14 -0
  104. package/src/components/Metric/_.test.tsx +166 -0
  105. package/src/components/Metric/_.types.ts +18 -0
  106. package/src/components/Metric/index.tsx +100 -0
  107. package/src/components/Modal/_.stories.tsx +93 -0
  108. package/src/components/Modal/_.style.ts +31 -0
  109. package/src/components/Modal/_.test.tsx +90 -0
  110. package/src/components/Modal/_.types.ts +14 -0
  111. package/src/components/Modal/index.tsx +82 -0
  112. package/src/components/Pagination/_.stories.tsx +118 -0
  113. package/src/components/Pagination/_.test.tsx +51 -0
  114. package/src/components/Pagination/index.tsx +256 -0
  115. package/src/components/Pagination/type.ts +48 -0
  116. package/src/components/PriceSlider/_.stories.tsx +107 -0
  117. package/src/components/PriceSlider/_.test.tsx +63 -0
  118. package/src/components/PriceSlider/_.type.tsx +19 -0
  119. package/src/components/PriceSlider/index.tsx +86 -0
  120. package/src/components/Progress/_.stories.tsx +93 -0
  121. package/src/components/Progress/_.style.ts +15 -0
  122. package/src/components/Progress/_.test.tsx +34 -0
  123. package/src/components/Progress/_.types.ts +17 -0
  124. package/src/components/Progress/index.tsx +173 -0
  125. package/src/components/Radio/_.stories.tsx +391 -0
  126. package/src/components/Radio/_.style.ts +33 -0
  127. package/src/components/Radio/_.test.tsx +77 -0
  128. package/src/components/Radio/_.types.ts +14 -0
  129. package/src/components/Radio/index.tsx +59 -0
  130. package/src/components/Select/_.stories.tsx +308 -0
  131. package/src/components/Select/_.style.ts +5 -0
  132. package/src/components/Select/_.types.ts +24 -0
  133. package/src/components/Select/index.tsx +172 -0
  134. package/src/components/Switch/_.stories.tsx +61 -0
  135. package/src/components/Switch/_.test.tsx +69 -0
  136. package/src/components/Switch/_.type.ts +12 -0
  137. package/src/components/Switch/index.tsx +70 -0
  138. package/src/components/Tabs/_.stories.tsx +508 -0
  139. package/src/components/Tabs/_.style.ts +63 -0
  140. package/src/components/Tabs/_.test.tsx +174 -0
  141. package/src/components/Tabs/_.type.ts +19 -0
  142. package/src/components/Tabs/index.tsx +35 -0
  143. package/src/components/Tag/_.stories.tsx +78 -0
  144. package/src/components/Tag/_.style.ts +71 -0
  145. package/src/components/Tag/_.test.tsx +44 -0
  146. package/src/components/Tag/_.types.ts +27 -0
  147. package/src/components/Tag/index.tsx +46 -0
  148. package/src/components/TextArea/_.stories.tsx +62 -0
  149. package/src/components/TextArea/_.style.ts +11 -0
  150. package/src/components/TextArea/_.test.tsx +43 -0
  151. package/src/components/TextArea/_.types.ts +29 -0
  152. package/src/components/TextArea/index.tsx +83 -0
  153. package/src/components/Toast/_.style.tsx +27 -0
  154. package/src/components/Toast/_.type.ts +30 -0
  155. package/src/components/Toast/_.utils.ts +23 -0
  156. package/src/components/Toast/container.tsx +171 -0
  157. package/src/components/Toast/index.tsx +29 -0
  158. package/src/components/Tooltip/_.stories.tsx +106 -0
  159. package/src/components/Tooltip/_.style.ts +27 -0
  160. package/src/components/Tooltip/_.test.tsx +54 -0
  161. package/src/components/Tooltip/_.types.ts +31 -0
  162. package/src/components/Tooltip/index.tsx +80 -0
  163. package/src/components/developers/AmirHossein.tsx +149 -0
  164. package/src/components/developers/Fardin.tsx +130 -0
  165. package/src/components/developers/Maryam.tsx +260 -0
  166. package/src/components/developers/Milad.tsx +431 -0
  167. package/src/components/developers/Rasoul.tsx +198 -0
  168. package/src/components/index.ts +28 -0
  169. package/src/components/ui/accordion.tsx +162 -0
  170. package/src/components/ui/avatars-component/avatar-description.tsx +30 -0
  171. package/src/components/ui/avatars-component/avatar-groups.tsx +68 -0
  172. package/src/components/ui/avatars-component/avatar-single.tsx +50 -0
  173. package/src/components/ui/card.tsx +92 -0
  174. package/src/components/ui/checkbox-group/plan-card/basic/_.test.tsx +66 -0
  175. package/src/components/ui/checkbox-group/plan-card/basic/index.tsx +70 -0
  176. package/src/components/ui/checkbox-group/plan-card/with-header/_.test.tsx +110 -0
  177. package/src/components/ui/checkbox-group/plan-card/with-header/header.test.tsx +96 -0
  178. package/src/components/ui/checkbox-group/plan-card/with-header/header.tsx +74 -0
  179. package/src/components/ui/checkbox-group/plan-card/with-header/index.tsx +65 -0
  180. package/src/components/ui/file-content/File-content.tsx +43 -0
  181. package/src/components/ui/file-uploader-components/file-uploader-box.tsx +76 -0
  182. package/src/components/ui/file-uploader-components/file-uploader-item.tsx +64 -0
  183. package/src/components/ui/icon-wrapper/_.test.tsx +60 -0
  184. package/src/components/ui/icon-wrapper/index.tsx +19 -0
  185. package/src/components/ui/input-component/input-label.tsx +11 -0
  186. package/src/components/ui/number.tsx +18 -0
  187. package/src/components/ui/pagination/card-minimal-center-align.tsx +96 -0
  188. package/src/components/ui/pagination/card-minimal-right-aligne.tsx +90 -0
  189. package/src/components/ui/pagination/default-pagination.tsx +128 -0
  190. package/src/components/ui/pagination/get-pagination-item.tsx +36 -0
  191. package/src/components/ui/pagination/pagination-card-button-group-aligned.tsx +94 -0
  192. package/src/components/ui/pagination/pagination-card-minimal-left-aligned.tsx +90 -0
  193. package/src/components/ui/pagination/pagination-content.tsx +15 -0
  194. package/src/components/ui/pagination/pagination-item.tsx +11 -0
  195. package/src/components/ui/pagination/pagination-link.tsx +42 -0
  196. package/src/components/ui/tab-components/tabs-content.tsx +15 -0
  197. package/src/components/ui/tab-components/tabs-list.tsx +27 -0
  198. package/src/components/ui/tab-components/tabs-trigger.tsx +25 -0
  199. package/src/components/ui/text-content-wrapper.tsx +36 -0
  200. package/src/hooks/useClickOutside.ts +23 -0
  201. package/src/icons/general/ArrowLeft.tsx +31 -0
  202. package/src/icons/general/ArrowRight.tsx +31 -0
  203. package/src/icons/general/activity-heart.tsx +31 -0
  204. package/src/icons/general/activity.tsx +31 -0
  205. package/src/icons/general/anchor.tsx +31 -0
  206. package/src/icons/general/archive.tsx +31 -0
  207. package/src/icons/general/arrow-left.tsx +25 -0
  208. package/src/icons/general/arrow-right.tsx +25 -0
  209. package/src/icons/general/asterisk-01.tsx +31 -0
  210. package/src/icons/general/asterisk-02.tsx +31 -0
  211. package/src/icons/general/at-sign.tsx +31 -0
  212. package/src/icons/general/attention-mark.tsx +43 -0
  213. package/src/icons/general/bookmark-add.tsx +31 -0
  214. package/src/icons/general/bookmark.tsx +31 -0
  215. package/src/icons/general/chevron-left.tsx +25 -0
  216. package/src/icons/general/chevron-right.tsx +25 -0
  217. package/src/icons/general/circle-minues.tsx +25 -0
  218. package/src/icons/general/circle-plus.tsx +25 -0
  219. package/src/icons/general/circle-question-mark.tsx +32 -0
  220. package/src/icons/general/circle.tsx +32 -0
  221. package/src/icons/general/copy.tsx +43 -0
  222. package/src/icons/general/email.tsx +32 -0
  223. package/src/icons/general/home.tsx +25 -0
  224. package/src/icons/general/layer.tsx +36 -0
  225. package/src/icons/general/leading.tsx +19 -0
  226. package/src/icons/general/master-card.tsx +37 -0
  227. package/src/icons/general/minus.tsx +36 -0
  228. package/src/icons/general/plus.tsx +19 -0
  229. package/src/icons/general/remove.tsx +32 -0
  230. package/src/icons/general/slash-divider.tsx +26 -0
  231. package/src/icons/general/tick-box.tsx +37 -0
  232. package/src/icons/general/trailing.tsx +19 -0
  233. package/src/icons/general/unkown-format.tsx +25 -0
  234. package/src/icons/general/visa-card.tsx +38 -0
  235. package/src/icons/general/x-close.tsx +35 -0
  236. package/src/icons/icons.type.ts +7 -0
  237. package/src/index.css +21 -0
  238. package/src/index.ts +3 -0
  239. package/src/lib/utils.ts +6 -0
  240. package/src/lib/zIndexUtils.ts +2 -0
  241. package/src/main.tsx +50 -0
  242. package/src/vite-env.d.ts +1 -0
  243. package/tests/setup.ts +8 -0
  244. package/tsconfig.app.json +31 -0
  245. package/tsconfig.json +7 -0
  246. package/tsconfig.node.json +24 -0
  247. package/tsconfig.rollup.json +12 -0
  248. package/vite.config.ts +20 -0
  249. package/vitest.config.ts +47 -0
@@ -0,0 +1,391 @@
1
+ import type { Meta, StoryObj } from "@storybook/react-vite";
2
+ import React, { useState } from "react";
3
+ import { Radio } from ".";
4
+ import { RadioProps } from "./_.types";
5
+
6
+ const meta: Meta<typeof Radio> = {
7
+ title: "Components/Radio",
8
+ component: Radio,
9
+ argTypes: {
10
+ onChange: { action: "changed" },
11
+ size: {
12
+ control: { type: "radio" },
13
+ options: ["sm", "md"],
14
+ },
15
+ disabled: {
16
+ control: "boolean",
17
+ },
18
+ checked: {
19
+ control: "boolean",
20
+ },
21
+ },
22
+ };
23
+
24
+ export default meta;
25
+ type Story = StoryObj<RadioProps>;
26
+
27
+ // ✅ Default - Unchecked, Enabled, Small Size
28
+ export const Default: Story = {
29
+ args: {
30
+ name: "default",
31
+ value: "option-1",
32
+ checked: false,
33
+ size: "sm",
34
+ disabled: false,
35
+ children: "Default Radio Option",
36
+ id: "radio-default",
37
+ },
38
+ render: (args) => {
39
+ const DefaultRadio = () => {
40
+ const [checked, setChecked] = useState(false);
41
+ return (
42
+ <Radio
43
+ {...args}
44
+ checked={checked}
45
+ onChange={(e) => {
46
+ setChecked(e.target.checked);
47
+ args.onChange?.(e);
48
+ }}
49
+ />
50
+ );
51
+ };
52
+ return <DefaultRadio />;
53
+ },
54
+ };
55
+
56
+ // ✅ Checked - Checked, Enabled, Small Size
57
+ export const Checked: Story = {
58
+ args: {
59
+ name: "checked",
60
+ value: "option-1",
61
+ checked: true,
62
+ size: "sm",
63
+ disabled: false,
64
+ children: "Checked Radio Option",
65
+ id: "radio-checked",
66
+ },
67
+ render: (args) => {
68
+ const CheckedRadio = () => {
69
+ const [checked, setChecked] = useState(true);
70
+ return (
71
+ <Radio
72
+ {...args}
73
+ checked={checked}
74
+ onChange={(e) => {
75
+ setChecked(e.target.checked);
76
+ args.onChange?.(e);
77
+ }}
78
+ />
79
+ );
80
+ };
81
+ return <CheckedRadio />;
82
+ },
83
+ };
84
+
85
+ // ✅ Disabled - Unchecked, Disabled, Small Size
86
+ export const Disabled: Story = {
87
+ args: {
88
+ name: "disabled",
89
+ value: "option-1",
90
+ checked: false,
91
+ size: "sm",
92
+ disabled: true,
93
+ children: "Disabled Radio Option",
94
+ id: "radio-disabled",
95
+ },
96
+ };
97
+
98
+ // ✅ CheckedDisabled - Checked, Disabled, Small Size
99
+ export const CheckedDisabled: Story = {
100
+ args: {
101
+ name: "checked-disabled",
102
+ value: "option-1",
103
+ checked: true,
104
+ size: "sm",
105
+ disabled: true,
106
+ children: "Checked & Disabled Radio Option",
107
+ id: "radio-checked-disabled",
108
+ },
109
+ };
110
+
111
+ // ✅ MediumSize - Unchecked, Enabled, Medium Size
112
+ export const MediumSize: Story = {
113
+ args: {
114
+ name: "medium-size",
115
+ value: "option-1",
116
+ checked: false,
117
+ size: "md",
118
+ disabled: false,
119
+ children: "Medium Size Radio Option",
120
+ id: "radio-medium-size",
121
+ },
122
+ render: (args) => {
123
+ const MediumSizeRadio = () => {
124
+ const [checked, setChecked] = useState(false);
125
+ return (
126
+ <Radio
127
+ {...args}
128
+ checked={checked}
129
+ onChange={(e) => {
130
+ setChecked(e.target.checked);
131
+ args.onChange?.(e);
132
+ }}
133
+ />
134
+ );
135
+ };
136
+ return <MediumSizeRadio />;
137
+ },
138
+ };
139
+
140
+ // ✅ MediumSizeChecked - Checked, Enabled, Medium Size
141
+ export const MediumSizeChecked: Story = {
142
+ args: {
143
+ name: "medium-size-checked",
144
+ value: "option-1",
145
+ checked: true,
146
+ size: "md",
147
+ disabled: false,
148
+ children: "Medium Size Checked Radio Option",
149
+ id: "radio-medium-size-checked",
150
+ },
151
+ render: (args) => {
152
+ const MediumSizeCheckedRadio = () => {
153
+ const [checked, setChecked] = useState(true);
154
+ return (
155
+ <Radio
156
+ {...args}
157
+ checked={checked}
158
+ onChange={(e) => {
159
+ setChecked(e.target.checked);
160
+ args.onChange?.(e);
161
+ }}
162
+ />
163
+ );
164
+ };
165
+ return <MediumSizeCheckedRadio />;
166
+ },
167
+ };
168
+
169
+ // ✅ MediumSizeDisabled - Unchecked, Disabled, Medium Size
170
+ export const MediumSizeDisabled: Story = {
171
+ args: {
172
+ name: "medium-size-disabled",
173
+ value: "option-1",
174
+ checked: false,
175
+ size: "md",
176
+ disabled: true,
177
+ children: "Medium Size Disabled Radio Option",
178
+ id: "radio-medium-size-disabled",
179
+ },
180
+ };
181
+
182
+ // ✅ MediumSizeCheckedDisabled - Checked, Disabled, Medium Size
183
+ export const MediumSizeCheckedDisabled: Story = {
184
+ args: {
185
+ name: "medium-size-checked-disabled",
186
+ value: "option-1",
187
+ checked: true,
188
+ size: "md",
189
+ disabled: true,
190
+ children: "Medium Size Checked & Disabled Radio Option",
191
+ id: "radio-medium-size-checked-disabled",
192
+ },
193
+ };
194
+
195
+ // ✅ RadioGroup - Multiple options in a group
196
+ export const RadioGroup: Story = {
197
+ args: {
198
+ size: "sm",
199
+ disabled: false,
200
+ },
201
+ render: (args) => {
202
+ const RadioGroupComponent = () => {
203
+ const [selectedValue, setSelectedValue] = useState("option-1");
204
+
205
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
206
+ setSelectedValue(e.target.value);
207
+ args.onChange?.(e);
208
+ };
209
+
210
+ return (
211
+ <div className="flex flex-col gap-2">
212
+ <Radio
213
+ {...args}
214
+ name="radio-group"
215
+ value="option-1"
216
+ checked={selectedValue === "option-1"}
217
+ onChange={handleChange}
218
+ id="radio-group-1"
219
+ >
220
+ Option 1
221
+ </Radio>
222
+ <Radio
223
+ {...args}
224
+ name="radio-group"
225
+ value="option-2"
226
+ checked={selectedValue === "option-2"}
227
+ onChange={handleChange}
228
+ id="radio-group-2"
229
+ >
230
+ Option 2
231
+ </Radio>
232
+ <Radio
233
+ {...args}
234
+ name="radio-group"
235
+ value="option-3"
236
+ checked={selectedValue === "option-3"}
237
+ onChange={handleChange}
238
+ id="radio-group-3"
239
+ >
240
+ Option 3
241
+ </Radio>
242
+ </div>
243
+ );
244
+ };
245
+ return <RadioGroupComponent />;
246
+ },
247
+ };
248
+
249
+ // ✅ RadioGroupWithDisabled - Radio group with some disabled options
250
+ export const RadioGroupWithDisabled: Story = {
251
+ args: {
252
+ size: "sm",
253
+ },
254
+ render: (args) => {
255
+ const RadioGroupWithDisabledComponent = () => {
256
+ const [selectedValue, setSelectedValue] = useState("option-4");
257
+
258
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
259
+ setSelectedValue(e.target.value);
260
+ args.onChange?.(e);
261
+ };
262
+
263
+ return (
264
+ <div className="flex flex-col gap-2">
265
+ <Radio
266
+ {...args}
267
+ name="radio-group-disabled"
268
+ value="option-1"
269
+ checked={selectedValue === "option-1"}
270
+ onChange={handleChange}
271
+ disabled={false}
272
+ id="radio-group-disabled-1"
273
+ >
274
+ Option 1 (Enabled)
275
+ </Radio>
276
+ <Radio
277
+ {...args}
278
+ name="radio-group-disabled"
279
+ value="option-2"
280
+ checked={selectedValue === "option-2"}
281
+ onChange={handleChange}
282
+ disabled={true}
283
+ id="radio-group-disabled-2"
284
+ >
285
+ Option 2 (Disabled)
286
+ </Radio>
287
+ <Radio
288
+ {...args}
289
+ name="radio-group-disabled"
290
+ value="option-3"
291
+ checked={selectedValue === "option-3"}
292
+ onChange={handleChange}
293
+ disabled={false}
294
+ id="radio-group-disabled-3"
295
+ >
296
+ Option 3 (Enabled)
297
+ </Radio>
298
+ <Radio
299
+ {...args}
300
+ name="radio-group-disabled"
301
+ value="option-4"
302
+ checked={selectedValue === "option-4"}
303
+ onChange={handleChange}
304
+ disabled={true}
305
+ id="radio-group-disabled-4"
306
+ >
307
+ Option 4 (Checked & Disabled)
308
+ </Radio>
309
+ </div>
310
+ );
311
+ };
312
+ return <RadioGroupWithDisabledComponent />;
313
+ },
314
+ };
315
+
316
+ // ✅ CustomLabel - Radio with custom label content
317
+ export const CustomLabel: Story = {
318
+ args: {
319
+ name: "custom-label",
320
+ value: "option-1",
321
+ checked: false,
322
+ size: "sm",
323
+ disabled: false,
324
+ id: "radio-custom-label",
325
+ },
326
+ render: (args) => {
327
+ const CustomLabelRadio = () => {
328
+ const [checked, setChecked] = useState(false);
329
+ return (
330
+ <Radio
331
+ {...args}
332
+ checked={checked}
333
+ onChange={(e) => {
334
+ setChecked(e.target.checked);
335
+ args.onChange?.(e);
336
+ }}
337
+ >
338
+ <div className="text-xs text-gray-700">
339
+ <strong>Label:</strong> Select me!
340
+ </div>
341
+ </Radio>
342
+ );
343
+ };
344
+ return <CustomLabelRadio />;
345
+ },
346
+ };
347
+
348
+ // ✅ WithExternalLabel - Radio with external label using htmlFor
349
+ export const WithExternalLabel: Story = {
350
+ render: () => {
351
+ const WithExternalLabelComponent = () => {
352
+ const [selectedValue, setSelectedValue] = useState("option-1");
353
+
354
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
355
+ setSelectedValue(e.target.value);
356
+ };
357
+
358
+ return (
359
+ <div className="flex flex-col gap-3">
360
+ <div className="flex items-center gap-2">
361
+ <Radio
362
+ name="external-group"
363
+ value="option-1"
364
+ checked={selectedValue === "option-1"}
365
+ onChange={handleChange}
366
+ id="radio-external-1"
367
+ size="sm"
368
+ />
369
+ <label htmlFor="radio-external-1" className="cursor-pointer">
370
+ Small radio with external label
371
+ </label>
372
+ </div>
373
+ <div className="flex items-center gap-2">
374
+ <Radio
375
+ name="external-group"
376
+ value="option-2"
377
+ checked={selectedValue === "option-2"}
378
+ onChange={handleChange}
379
+ id="radio-external-2"
380
+ size="md"
381
+ />
382
+ <label htmlFor="radio-external-2" className="cursor-pointer">
383
+ Medium radio with external label
384
+ </label>
385
+ </div>
386
+ </div>
387
+ );
388
+ };
389
+ return <WithExternalLabelComponent />;
390
+ },
391
+ };
@@ -0,0 +1,33 @@
1
+ import { cva } from "class-variance-authority";
2
+
3
+ const baseStyles =
4
+ "rounded-full border-[1px] flex items-center justify-center peer-checked:border-[5px]";
5
+
6
+ const sizeStyle = {
7
+ sm: "w-4 h-4",
8
+ md: "w-5 h-5 !peer-checked:border-[6px]",
9
+ };
10
+ const fontSize = {
11
+ sm: "text-xs",
12
+ md: "text-sm",
13
+ };
14
+ const ringPadding = {
15
+ sm: "p-2.5",
16
+ md: "p-3",
17
+ };
18
+ const radioVariants = cva(baseStyles, {
19
+ variants: {
20
+ size: sizeStyle,
21
+ disabled: {
22
+ true: " cursor-auto bg-rbg-disabled-subtle !border-rfg-disabled-subtle !border-[1px] ",
23
+ false: "group cursor-pointer border-rbg-brand-solid",
24
+ undefined: "group cursor-pointer border-rbg-brand-solid",
25
+ },
26
+ },
27
+
28
+ defaultVariants: {
29
+ size: "sm",
30
+ },
31
+ });
32
+
33
+ export { baseStyles, sizeStyle, fontSize, ringPadding, radioVariants };
@@ -0,0 +1,77 @@
1
+ import { render, screen, fireEvent } from "@testing-library/react";
2
+ import "@testing-library/jest-dom";
3
+ import { describe, expect, it, vi } from "vitest";
4
+ import { Radio } from ".";
5
+
6
+ describe("Radio Component", () => {
7
+ const defaultProps = {
8
+ name: "test-radio",
9
+ value: "option-1",
10
+ onChange: vi.fn(),
11
+ checked: false,
12
+ };
13
+
14
+ it("renders the radio button with label", () => {
15
+ render(<Radio {...defaultProps}>Label Text</Radio>);
16
+ const input = screen.getByRole("radio");
17
+ expect(input).toBeInTheDocument();
18
+ expect(input).not.toBeChecked();
19
+ expect(screen.getByText("Label Text")).toBeInTheDocument();
20
+ });
21
+
22
+ it("renders as checked when checked prop is true", () => {
23
+ render(
24
+ <Radio {...defaultProps} checked={true}>
25
+ Checked Option
26
+ </Radio>
27
+ );
28
+ const input = screen.getByRole("radio");
29
+ expect(input).toBeChecked();
30
+ });
31
+
32
+ it("calls onChange when clicked", () => {
33
+ render(<Radio {...defaultProps}>Click Me</Radio>);
34
+ const input = screen.getByRole("radio");
35
+ fireEvent.click(input);
36
+ expect(defaultProps.onChange).toHaveBeenCalledTimes(1);
37
+ });
38
+
39
+ it("is disabled when disabled prop is true", () => {
40
+ render(
41
+ <Radio {...defaultProps} disabled={true}>
42
+ Disabled Radio
43
+ </Radio>
44
+ );
45
+ const input = screen.getByRole("radio");
46
+ expect(input).toBeDisabled();
47
+ });
48
+
49
+ it("applies correct size classes for md", () => {
50
+ const { container } = render(
51
+ <Radio {...defaultProps} size="md">
52
+ Sized Radio
53
+ </Radio>
54
+ );
55
+ const radioRing = container.querySelector(".inline-flex > div");
56
+ expect(radioRing?.className).toMatch(/w-5/); // md size should apply w-5
57
+ });
58
+ it("renders correct classes for outer ring when checked and disabled (size: sm)", () => {
59
+ render(<Radio {...defaultProps} size="sm" disabled checked />);
60
+ const outerRing = screen.getByRole("radio").nextSibling
61
+ ?.nextSibling as HTMLElement;
62
+
63
+ expect(outerRing).toHaveClass("!border-4");
64
+ expect(outerRing).toHaveClass("!border-rfg-disabled-subtle");
65
+ expect(outerRing).toHaveClass("!p-0");
66
+ });
67
+
68
+ it("renders correct classes for outer ring when checked and disabled (size: md)", () => {
69
+ render(<Radio {...defaultProps} size="md" disabled checked />);
70
+ const outerRing = screen.getByRole("radio").nextSibling
71
+ ?.nextSibling as HTMLElement;
72
+
73
+ expect(outerRing).toHaveClass("!border-5");
74
+ expect(outerRing).toHaveClass("!border-rfg-disabled-subtle");
75
+ expect(outerRing).toHaveClass("!p-0");
76
+ });
77
+ });
@@ -0,0 +1,14 @@
1
+
2
+ export type RadioProps = {
3
+ id?: string;
4
+ name: string;
5
+ className?: string;
6
+ value: string;
7
+ disabled?: boolean;
8
+ checked?: boolean;
9
+ onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
10
+ size?: "sm" | "md";
11
+ children?: React.ReactNode;
12
+ cardOnclick?: () => void;
13
+
14
+ };
@@ -0,0 +1,59 @@
1
+ import { cn } from "@/lib/utils";
2
+ import { baseStyles, fontSize, radioVariants, ringPadding } from "./_.style";
3
+ import { RadioProps } from "./_.types";
4
+
5
+ export const Radio = ({
6
+ name,
7
+ value,
8
+ checked,
9
+ onChange,
10
+ size = "sm",
11
+ disabled,
12
+ className,
13
+ children,
14
+ id,
15
+ ...props
16
+ }: Readonly<RadioProps>) => {
17
+ return (
18
+ <div className="flex items-start gap-2">
19
+ <label
20
+ htmlFor={id}
21
+ className="inline-flex w-fit items-center cursor-pointer relative"
22
+ >
23
+ <input
24
+ type="radio"
25
+ name={name}
26
+ value={value}
27
+ checked={checked}
28
+ onChange={onChange}
29
+ className="sr-only peer"
30
+ disabled={disabled}
31
+ id={id}
32
+ {...props}
33
+ />
34
+ <div
35
+ className={cn(radioVariants({ size, disabled }), baseStyles)}
36
+ ></div>
37
+ <div
38
+ className={`peer-focus:border-2 peer-focus-within:border-1 border-brand-500 rounded-full absolute top-1/2 left-1/2 -translate-1/2 ${
39
+ ringPadding[size]
40
+ } ${
41
+ checked &&
42
+ disabled &&
43
+ `${
44
+ size === "sm" ? "!border-4" : "!border-5"
45
+ } !border-rfg-disabled-subtle !p-0 `
46
+ } `}
47
+ ></div>
48
+ </label>
49
+ {children && (
50
+ <label
51
+ htmlFor={id}
52
+ className={`cursor-pointer ${fontSize[size]} ${className}`}
53
+ >
54
+ {children}
55
+ </label>
56
+ )}
57
+ </div>
58
+ );
59
+ };