@recursica/mui-adapter 0.5.0 → 0.7.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 (212) hide show
  1. package/ARCHITECTURE.md +15 -0
  2. package/CHANGELOG.md +15 -0
  3. package/SETUP.md +77 -0
  4. package/USAGE.md +55 -0
  5. package/dist/mui-adapter.cjs +74 -1
  6. package/dist/mui-adapter.cjs.map +1 -1
  7. package/dist/mui-adapter.css +1 -1
  8. package/dist/mui-adapter.js +6863 -205
  9. package/dist/mui-adapter.js.map +1 -1
  10. package/dist/src/components/Accordion/Accordion.d.ts +43 -2
  11. package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +6 -2
  12. package/dist/src/components/Autocomplete/Autocomplete.d.ts +12 -2
  13. package/dist/src/components/Avatar/Avatar.d.ts +10 -3
  14. package/dist/src/components/Badge/Badge.d.ts +10 -3
  15. package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +9 -3
  16. package/dist/src/components/Button/Button.d.ts +2 -17
  17. package/dist/src/components/Card/Card.d.ts +38 -3
  18. package/dist/src/components/Checkbox/Checkbox.d.ts +13 -2
  19. package/dist/src/components/Checkbox/CheckboxGroup.d.ts +18 -0
  20. package/dist/src/components/Checkbox/index.d.ts +5 -1
  21. package/dist/src/components/Chip/Chip.d.ts +9 -2
  22. package/dist/src/components/Container/Container.d.ts +1 -5
  23. package/dist/src/components/DatePicker/DatePicker.d.ts +2 -1
  24. package/dist/src/components/Dropdown/Dropdown.d.ts +12 -2
  25. package/dist/src/components/Flex/Flex.d.ts +2 -22
  26. package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +5 -2
  27. package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +9 -2
  28. package/dist/src/components/Group/Group.d.ts +2 -7
  29. package/dist/src/components/HoverCard/HoverCard.d.ts +28 -2
  30. package/dist/src/components/Label/Label.d.ts +6 -2
  31. package/dist/src/components/Link/Link.d.ts +2 -6
  32. package/dist/src/components/Loader/Loader.d.ts +2 -7
  33. package/dist/src/components/Menu/Menu.d.ts +25 -3
  34. package/dist/src/components/Modal/Modal.d.ts +37 -2
  35. package/dist/src/components/NumberInput/NumberInput.d.ts +12 -2
  36. package/dist/src/components/Pagination/Pagination.d.ts +12 -3
  37. package/dist/src/components/Pagination/Pagination.icons.d.ts +8 -0
  38. package/dist/src/components/Panel/Panel.d.ts +52 -3
  39. package/dist/src/components/Radio/Radio.d.ts +13 -3
  40. package/dist/src/components/Radio/RadioGroup.d.ts +9 -0
  41. package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
  42. package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +4 -2
  43. package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
  44. package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
  45. package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +28 -0
  46. package/dist/src/components/ReadOnlyField/index.d.ts +1 -0
  47. package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +21 -3
  48. package/dist/src/components/Slider/Slider.d.ts +18 -2
  49. package/dist/src/components/Stack/Stack.d.ts +2 -5
  50. package/dist/src/components/Stepper/Stepper.d.ts +41 -2
  51. package/dist/src/components/Switch/Switch.d.ts +10 -3
  52. package/dist/src/components/Switch/SwitchGroup.d.ts +13 -0
  53. package/dist/src/components/Table/Table.d.ts +2 -1
  54. package/dist/src/components/Tabs/Tabs.d.ts +20 -3
  55. package/dist/src/components/Text/Text.d.ts +2 -16
  56. package/dist/src/components/TextArea/TextArea.d.ts +12 -2
  57. package/dist/src/components/TextField/TextField.d.ts +12 -2
  58. package/dist/src/components/TimePicker/TimePicker.d.ts +2 -1
  59. package/dist/src/components/Timeline/Timeline.d.ts +15 -2
  60. package/dist/src/components/Timeline/TimelineItem.d.ts +18 -0
  61. package/dist/src/components/Title/Title.d.ts +2 -15
  62. package/dist/src/components/Toast/Toast.d.ts +20 -2
  63. package/dist/src/components/Tooltip/Tooltip.d.ts +28 -3
  64. package/dist/src/components/TransferList/TransferList.d.ts +2 -1
  65. package/dist/src/components/Typography/Typography.d.ts +1 -1
  66. package/dist/src/utils/RequireAccessibleLabel.d.ts +1 -18
  67. package/dist/src/utils/filterStylingProps.d.ts +1 -11
  68. package/llms.txt +16 -0
  69. package/package.json +14 -3
  70. package/src/components/Accordion/Accordion.module.css +294 -56
  71. package/src/components/Accordion/Accordion.stories.tsx +131 -21
  72. package/src/components/Accordion/Accordion.tsx +260 -5
  73. package/src/components/AssistiveElement/AssistiveElement.module.css +114 -20
  74. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +60 -20
  75. package/src/components/AssistiveElement/AssistiveElement.tsx +81 -5
  76. package/src/components/Autocomplete/Autocomplete.module.css +319 -42
  77. package/src/components/Autocomplete/Autocomplete.stories.tsx +175 -23
  78. package/src/components/Autocomplete/Autocomplete.tsx +181 -6
  79. package/src/components/Avatar/Avatar.module.css +343 -73
  80. package/src/components/Avatar/Avatar.stories.tsx +94 -22
  81. package/src/components/Avatar/Avatar.tsx +99 -6
  82. package/src/components/Badge/Badge.module.css +127 -29
  83. package/src/components/Badge/Badge.stories.tsx +65 -22
  84. package/src/components/Badge/Badge.tsx +67 -6
  85. package/src/components/Breadcrumb/Breadcrumb.module.css +25 -5
  86. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +57 -22
  87. package/src/components/Breadcrumb/Breadcrumb.tsx +59 -6
  88. package/src/components/Button/Button.module.css +19 -61
  89. package/src/components/Button/Button.stories.tsx +24 -23
  90. package/src/components/Button/Button.tsx +7 -18
  91. package/src/components/Card/Card.module.css +154 -38
  92. package/src/components/Card/Card.stories.tsx +117 -19
  93. package/src/components/Card/Card.tsx +181 -5
  94. package/src/components/Checkbox/Checkbox.module.css +249 -39
  95. package/src/components/Checkbox/Checkbox.stories.tsx +81 -19
  96. package/src/components/Checkbox/Checkbox.tsx +246 -5
  97. package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
  98. package/src/components/Checkbox/CheckboxGroup.tsx +137 -0
  99. package/src/components/Checkbox/index.ts +6 -1
  100. package/src/components/Chip/Chip.module.css +246 -43
  101. package/src/components/Chip/Chip.stories.tsx +101 -21
  102. package/src/components/Chip/Chip.tsx +136 -6
  103. package/src/components/Container/Container.stories.tsx +103 -20
  104. package/src/components/Container/Container.tsx +1 -13
  105. package/src/components/DatePicker/DatePicker.stories.tsx +125 -19
  106. package/src/components/DatePicker/DatePicker.tsx +3 -1
  107. package/src/components/Dropdown/Dropdown.module.css +291 -41
  108. package/src/components/Dropdown/Dropdown.stories.tsx +80 -21
  109. package/src/components/Dropdown/Dropdown.tsx +180 -6
  110. package/src/components/FileInput/FileInput.stories.tsx +2 -19
  111. package/src/components/FileUpload/FileUpload.stories.tsx +2 -19
  112. package/src/components/Flex/Flex.stories.tsx +113 -20
  113. package/src/components/Flex/Flex.tsx +16 -26
  114. package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
  115. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +67 -20
  116. package/src/components/FormControlLayout/FormControlLayout.tsx +69 -4
  117. package/src/components/FormControlWrapper/FormControlWrapper.module.css +87 -0
  118. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +116 -22
  119. package/src/components/FormControlWrapper/FormControlWrapper.tsx +126 -6
  120. package/src/components/Group/Group.stories.tsx +6 -30
  121. package/src/components/Group/Group.tsx +14 -9
  122. package/src/components/HoverCard/HoverCard.module.css +90 -22
  123. package/src/components/HoverCard/HoverCard.stories.tsx +158 -21
  124. package/src/components/HoverCard/HoverCard.tsx +147 -5
  125. package/src/components/Label/Label.module.css +140 -35
  126. package/src/components/Label/Label.stories.tsx +108 -21
  127. package/src/components/Label/Label.tsx +82 -5
  128. package/src/components/Link/Link.module.css +4 -3
  129. package/src/components/Link/Link.stories.tsx +2 -8
  130. package/src/components/Link/Link.tsx +1 -5
  131. package/src/components/Loader/Loader.module.css +1 -2
  132. package/src/components/Loader/Loader.tsx +1 -7
  133. package/src/components/Menu/IMPLEMENTATION_NOTES.md +4 -0
  134. package/src/components/Menu/Menu.module.css +285 -51
  135. package/src/components/Menu/Menu.stories.tsx +229 -25
  136. package/src/components/Menu/Menu.tsx +73 -6
  137. package/src/components/Modal/Modal.module.css +171 -35
  138. package/src/components/Modal/Modal.stories.tsx +66 -22
  139. package/src/components/Modal/Modal.tsx +215 -5
  140. package/src/components/NumberInput/NumberInput.module.css +276 -42
  141. package/src/components/NumberInput/NumberInput.stories.tsx +83 -20
  142. package/src/components/NumberInput/NumberInput.tsx +136 -6
  143. package/src/components/Pagination/IMPLEMENTATION_NOTES.md +3 -0
  144. package/src/components/Pagination/Pagination.icons.tsx +66 -0
  145. package/src/components/Pagination/Pagination.module.css +234 -20
  146. package/src/components/Pagination/Pagination.stories.tsx +34 -21
  147. package/src/components/Pagination/Pagination.tsx +74 -6
  148. package/src/components/Panel/Panel.module.css +206 -38
  149. package/src/components/Panel/Panel.stories.tsx +214 -22
  150. package/src/components/Panel/Panel.tsx +130 -5
  151. package/src/components/Radio/Radio.module.css +235 -37
  152. package/src/components/Radio/Radio.stories.tsx +77 -19
  153. package/src/components/Radio/Radio.tsx +210 -5
  154. package/src/components/Radio/RadioGroup.stories.tsx +117 -0
  155. package/src/components/Radio/RadioGroup.tsx +125 -0
  156. package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
  157. package/src/components/ReadOnlyField/ReadOnlyField.module.css +53 -15
  158. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +147 -19
  159. package/src/components/ReadOnlyField/ReadOnlyField.tsx +105 -5
  160. package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
  161. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
  162. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
  163. package/src/components/ReadOnlyField/index.ts +1 -0
  164. package/src/components/SegmentedControl/SegmentedControl.module.css +179 -47
  165. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +102 -20
  166. package/src/components/SegmentedControl/SegmentedControl.tsx +140 -6
  167. package/src/components/Slider/Slider.module.css +539 -86
  168. package/src/components/Slider/Slider.stories.tsx +157 -19
  169. package/src/components/Slider/Slider.tsx +283 -5
  170. package/src/components/Stack/Stack.stories.tsx +4 -25
  171. package/src/components/Stack/Stack.tsx +1 -5
  172. package/src/components/Stepper/IMPLEMENTATION_NOTES.md +4 -0
  173. package/src/components/Stepper/Stepper.module.css +410 -71
  174. package/src/components/Stepper/Stepper.stories.tsx +146 -20
  175. package/src/components/Stepper/Stepper.tsx +147 -6
  176. package/src/components/Switch/Switch.module.css +259 -39
  177. package/src/components/Switch/Switch.stories.tsx +98 -19
  178. package/src/components/Switch/Switch.tsx +200 -6
  179. package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
  180. package/src/components/Switch/SwitchGroup.tsx +120 -0
  181. package/src/components/Table/Table.stories.tsx +1 -19
  182. package/src/components/Table/Table.tsx +3 -1
  183. package/src/components/Tabs/IMPLEMENTATION_NOTES.md +4 -0
  184. package/src/components/Tabs/Tabs.module.css +422 -79
  185. package/src/components/Tabs/Tabs.stories.tsx +156 -20
  186. package/src/components/Tabs/Tabs.tsx +86 -6
  187. package/src/components/Text/Text.stories.tsx +5 -17
  188. package/src/components/Text/Text.tsx +1 -15
  189. package/src/components/TextArea/TextArea.module.css +155 -32
  190. package/src/components/TextArea/TextArea.stories.tsx +80 -21
  191. package/src/components/TextArea/TextArea.tsx +146 -6
  192. package/src/components/TextField/TextField.module.css +261 -42
  193. package/src/components/TextField/TextField.stories.tsx +147 -20
  194. package/src/components/TextField/TextField.tsx +169 -6
  195. package/src/components/TimePicker/TimePicker.stories.tsx +2 -19
  196. package/src/components/TimePicker/TimePicker.tsx +3 -1
  197. package/src/components/Timeline/Timeline.module.css +365 -76
  198. package/src/components/Timeline/Timeline.stories.tsx +114 -21
  199. package/src/components/Timeline/Timeline.tsx +83 -5
  200. package/src/components/Timeline/TimelineItem.tsx +90 -0
  201. package/src/components/Title/Title.stories.tsx +0 -18
  202. package/src/components/Title/Title.tsx +1 -7
  203. package/src/components/Toast/Toast.module.css +166 -28
  204. package/src/components/Toast/Toast.stories.tsx +54 -22
  205. package/src/components/Toast/Toast.tsx +124 -5
  206. package/src/components/Tooltip/Tooltip.module.css +89 -24
  207. package/src/components/Tooltip/Tooltip.stories.tsx +152 -22
  208. package/src/components/Tooltip/Tooltip.tsx +88 -5
  209. package/src/components/TransferList/TransferList.stories.tsx +1 -19
  210. package/src/components/TransferList/TransferList.tsx +3 -1
  211. package/src/utils/RequireAccessibleLabel.ts +1 -12
  212. package/src/utils/filterStylingProps.ts +7 -20
@@ -1,37 +1,235 @@
1
- /* EXEMPTIONS:
2
- This component is a placeholder stub. Once fully implemented, its specific
3
- tokens will be fully wired up to direct styles. */
4
-
5
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_properties_item-gap */
6
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_properties_padding */
7
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_gutter */
8
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_top-bottom-margin */
9
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_vertical-padding */
10
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_variants_layouts_stacked_properties_label-field-gap */
11
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-group_variants_layouts_stacked_properties_top-bottom-margin */
12
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_colors_disabled-text */
13
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_colors_text */
14
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_disabled-opacity */
15
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_label-gap */
16
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_max-width */
17
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_font-family */
18
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_font-size */
19
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_font-style */
20
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_font-weight */
21
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_letter-spacing */
22
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_line-height */
23
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_text-decoration */
24
- /* recursica-ignore: --recursica_ui-kit_components_radio-button-item_properties_text_text-transform */
25
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_border-radius */
26
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_border-size */
27
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_background-selected */
28
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_background-unselected */
29
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_border-selected */
30
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_border-unselected */
31
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_disabled-background */
32
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_disabled-border */
33
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_disabled-icon */
34
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_colors_icon-color */
35
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_disabled-opacity */
36
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_icon-size */
37
- /* recursica-ignore: --recursica_ui-kit_components_radio-button_properties_size */
1
+ /**
2
+ * Radio.module.css
3
+ *
4
+ * HARDCODED VALUES:
5
+ * - margin / padding: 0 — Structural resets; consider token if spacing needed.
6
+ * - cursor: pointer / not-allowed — Baseline interactive indications.
7
+ * - appearance / box-sizing / border-style — necessary normalization for inputs.
8
+ * - transition: all 0.2s ease — Animation curve; consider a transition token.
9
+ * - min-width: 0 — Forces text wrap boundary in flex children.
10
+ */
11
+
12
+ /* --- GROUP STYLES --- */
13
+ .groupRoot {
14
+ padding: var(
15
+ --recursica_ui-kit_components_radio-button-group_properties_padding
16
+ );
17
+ margin: 0; /* HARDCODE: structural reset; consider token if layout needs change */
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(
21
+ --recursica_ui-kit_components_radio-button-group_properties_item-gap
22
+ );
23
+ }
24
+
25
+ /* SideBySide Variant */
26
+ .groupRoot[data-layout="side-by-side"] {
27
+ flex-direction: row;
28
+ flex-wrap: wrap;
29
+ gap: var(
30
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_gutter
31
+ );
32
+ padding-top: var(
33
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_vertical-padding
34
+ );
35
+ padding-bottom: var(
36
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_vertical-padding
37
+ );
38
+ margin-top: var(
39
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_top-bottom-margin
40
+ );
41
+ margin-bottom: var(
42
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_side-by-side_properties_top-bottom-margin
43
+ );
44
+ }
45
+
46
+ /* Stacked Variant */
47
+ .groupRoot[data-layout="stacked"] {
48
+ flex-direction: column;
49
+ margin-top: var(
50
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_stacked_properties_label-field-gap
51
+ );
52
+ margin-bottom: var(
53
+ --recursica_ui-kit_components_radio-button-group_variants_layouts_stacked_properties_top-bottom-margin
54
+ );
55
+ }
56
+
57
+ /* --- PRIMITIVE RADIO STYLES --- */
58
+
59
+ .root {
60
+ max-width: var(
61
+ --recursica_ui-kit_components_radio-button-item_properties_max-width
62
+ );
63
+ }
64
+
65
+ .body {
66
+ display: flex;
67
+ align-items: flex-start;
68
+ gap: var(
69
+ --recursica_ui-kit_components_radio-button-item_properties_label-gap
70
+ );
71
+ }
72
+
73
+ .root .inner {
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ margin: 0; /* HARDCODE: structural reset */
78
+ width: var(--recursica_ui-kit_components_radio-button_properties_size);
79
+ height: var(--recursica_ui-kit_components_radio-button_properties_size);
80
+ /* Apply font-size to this element so that an 'em' based line-height token evaluates to the correct exact pixel value. */
81
+ font-size: var(
82
+ --recursica_ui-kit_components_radio-button-item_properties_text_font-size
83
+ );
84
+ /* Mathematically syncs the physical input radio bounding block visually with the center of the text's first line.
85
+ NOTE: Since the Figma line-height token resolves to an 'em' length (e.g. 1.05em), we CANNOT multiply it by font-size in CSS.
86
+ Instead, it naturally evaluates to the correct height because we applied the font-size above. */
87
+ margin-top: calc(
88
+ (
89
+ var(
90
+ --recursica_ui-kit_components_radio-button-item_properties_text_line-height
91
+ ) -
92
+ var(--recursica_ui-kit_components_radio-button_properties_size)
93
+ ) /
94
+ 2
95
+ );
96
+ }
97
+
98
+ /* Base explicit reset masking underlying framework defaults */
99
+ .root .radio {
100
+ cursor: pointer; /* HARDCODE: core interaction behavior */
101
+ appearance: none; /* HARDCODE: reset native widget */
102
+ box-sizing: border-box; /* HARDCODE: ensures size includes borders */
103
+ width: var(--recursica_ui-kit_components_radio-button_properties_size);
104
+ height: var(--recursica_ui-kit_components_radio-button_properties_size);
105
+ border-radius: var(
106
+ --recursica_ui-kit_components_radio-button_properties_border-radius
107
+ );
108
+ border-width: var(
109
+ --recursica_ui-kit_components_radio-button_properties_border-size
110
+ );
111
+ border-style: solid; /* HARDCODE: normalize primitive border-style */
112
+
113
+ /* Standard unchecked state */
114
+ background-color: var(
115
+ --recursica_ui-kit_components_radio-button_properties_colors_background-unselected
116
+ );
117
+ border-color: var(
118
+ --recursica_ui-kit_components_radio-button_properties_colors_border-unselected
119
+ );
120
+ transition: all 0.2s ease; /* HARDCODE: consider global transition token */
121
+ }
122
+
123
+ /* Checked State */
124
+ .root .radio:checked {
125
+ background-color: var(
126
+ --recursica_ui-kit_components_radio-button_properties_colors_background-selected
127
+ );
128
+ border-color: var(
129
+ --recursica_ui-kit_components_radio-button_properties_colors_border-selected
130
+ );
131
+ }
132
+
133
+ /* Disabled State */
134
+ .root .radio:disabled {
135
+ cursor: not-allowed; /* HARDCODE: disabled state default */
136
+ opacity: var(
137
+ --recursica_ui-kit_components_radio-button_properties_disabled-opacity
138
+ );
139
+ background-color: var(
140
+ --recursica_ui-kit_components_radio-button_properties_colors_disabled-background
141
+ );
142
+ border-color: var(
143
+ --recursica_ui-kit_components_radio-button_properties_colors_disabled-border
144
+ );
145
+ }
146
+
147
+ .root .icon {
148
+ position: absolute;
149
+ inset: 0;
150
+ margin: auto;
151
+ pointer-events: none;
152
+ width: var(--recursica_ui-kit_components_radio-button_properties_icon-size);
153
+ height: var(--recursica_ui-kit_components_radio-button_properties_icon-size);
154
+ color: var(
155
+ --recursica_ui-kit_components_radio-button_properties_colors_icon-color
156
+ );
157
+ }
158
+ .root .radio:disabled + .iconWrapper .icon,
159
+ .root .radio:disabled + .icon {
160
+ color: var(
161
+ --recursica_ui-kit_components_radio-button_properties_colors_disabled-icon
162
+ );
163
+ }
164
+
165
+ .root .labelWrapper {
166
+ padding: 0; /* HARDCODE: structural layout reset */
167
+ margin: 0; /* HARDCODE: structural layout reset */
168
+ flex: 1;
169
+ min-width: 0; /* HARDCODE: forces text wrap boundary in flex child */
170
+ }
171
+
172
+ .root .label {
173
+ cursor: pointer; /* HARDCODE: interactive affordance */
174
+ padding: 0; /* HARDCODE: reset layout */
175
+ margin: 0; /* HARDCODE: reset layout */
176
+ word-wrap: break-word;
177
+ white-space: normal;
178
+ color: var(
179
+ --recursica_ui-kit_components_radio-button-item_properties_colors_text
180
+ );
181
+ font-family: var(
182
+ --recursica_ui-kit_components_radio-button-item_properties_text_font-family
183
+ );
184
+ font-size: var(
185
+ --recursica_ui-kit_components_radio-button-item_properties_text_font-size
186
+ );
187
+ font-weight: var(
188
+ --recursica_ui-kit_components_radio-button-item_properties_text_font-weight
189
+ );
190
+ line-height: var(
191
+ --recursica_ui-kit_components_radio-button-item_properties_text_line-height
192
+ );
193
+ font-style: var(
194
+ --recursica_ui-kit_components_radio-button-item_properties_text_font-style
195
+ );
196
+ letter-spacing: var(
197
+ --recursica_ui-kit_components_radio-button-item_properties_text_letter-spacing
198
+ );
199
+ text-decoration: var(
200
+ --recursica_ui-kit_components_radio-button-item_properties_text_text-decoration
201
+ );
202
+ text-transform: var(
203
+ --recursica_ui-kit_components_radio-button-item_properties_text_text-transform
204
+ );
205
+ }
206
+ .root:has(input:disabled) .label {
207
+ cursor: not-allowed; /* HARDCODE: disabled interaction */
208
+ color: var(
209
+ --recursica_ui-kit_components_radio-button-item_properties_colors_disabled-text
210
+ );
211
+ opacity: var(
212
+ --recursica_ui-kit_components_radio-button-item_properties_disabled-opacity
213
+ );
214
+ }
215
+
216
+ .root .description {
217
+ margin-top: 5px; /* HARDCODE: mantine default */
218
+ color: #868e96; /* HARDCODE: mantine default dimmed */
219
+ font-size: 12px; /* HARDCODE: mantine default xs */
220
+ line-height: 1.2;
221
+ }
222
+
223
+ .root .error {
224
+ margin-top: 5px; /* HARDCODE: mantine default */
225
+ color: #fa5252; /* HARDCODE: mantine default error */
226
+ font-size: 12px; /* HARDCODE: mantine default xs */
227
+ line-height: 1.2;
228
+ }
229
+
230
+ .root .description[data-disabled="true"],
231
+ .root .error[data-disabled="true"] {
232
+ opacity: var(
233
+ --recursica_ui-kit_components_radio-button-item_properties_disabled-opacity
234
+ );
235
+ }
@@ -1,35 +1,93 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react";
2
2
  import { Radio } from "./Radio";
3
- import { ComingSoon } from "@recursica/storybook-template";
4
3
 
5
4
  const meta: Meta<typeof Radio> = {
6
- title: "UI-Kit/🚧 Radio",
5
+ title: "UI-Kit/Radio",
7
6
  component: Radio,
8
7
  tags: ["autodocs"],
9
8
  parameters: {
10
- controls: {
11
- include: [
12
- "layer",
13
- "withLayer",
14
- "children",
15
- "component",
16
- "variant",
17
- "size",
18
- "icon",
19
- "disabled",
20
- "href",
21
- "onClick",
22
- "onChange",
23
- "value",
24
- "checked",
25
- ],
9
+ docs: {
10
+ description: {
11
+ component: `
12
+ The \`Radio\` component represents a fundamental standalone boolean selection node mapping to the native HTML \`<input type="radio">\`.
13
+
14
+ > [!WARNING]
15
+ > This component represents the isolated primitive structure. If you need macro form configurations, standard vertical alignments, side-by-side array wrappers, or integrated assistive text and error borders natively, you MUST use the \`<Radio.Group>\` orchestrator instead!
16
+ `,
17
+ },
18
+ },
19
+ },
20
+ argTypes: {
21
+ disabled: {
22
+ control: "boolean",
23
+ },
24
+ checked: {
25
+ control: "boolean",
26
+ },
27
+ readOnly: {
28
+ control: "boolean",
29
+ },
30
+ error: {
31
+ control: "boolean",
26
32
  },
33
+ defaultChecked: {
34
+ control: "boolean",
35
+ },
36
+ controlMaxWidth: { table: { disable: true } },
37
+ controlMinWidth: { table: { disable: true } },
27
38
  },
28
39
  };
29
40
 
30
41
  export default meta;
42
+
31
43
  type Story = StoryObj<typeof Radio>;
32
44
 
33
45
  export const Default: Story = {
34
- render: () => <ComingSoon componentName="Radio" />,
46
+ args: {
47
+ label: "Standard Radio Primitive",
48
+ },
49
+ };
50
+
51
+ export const SideBySideLayout: Story = {
52
+ args: {
53
+ label: "Opt-in form alignment",
54
+ formLayout: "side-by-side",
55
+ },
56
+ };
57
+
58
+ export const CheckedState: Story = {
59
+ args: {
60
+ ...Default.args,
61
+ defaultChecked: true,
62
+ },
63
+ };
64
+
65
+ export const DisabledUnchecked: Story = {
66
+ args: {
67
+ ...Default.args,
68
+ disabled: true,
69
+ },
70
+ };
71
+
72
+ export const DisabledChecked: Story = {
73
+ args: {
74
+ ...Default.args,
75
+ disabled: true,
76
+ defaultChecked: true,
77
+ },
78
+ };
79
+
80
+ export const ReadOnly: Story = {
81
+ args: {},
82
+ render: () => (
83
+ <div
84
+ style={{
85
+ display: "flex",
86
+ flexDirection: "column",
87
+ gap: "24px",
88
+ }}
89
+ >
90
+ <Radio label="Account Type" defaultChecked readOnly />
91
+ </div>
92
+ ),
35
93
  };
@@ -1,8 +1,213 @@
1
- import React from "react";
2
- import "./Radio.module.css";
1
+ import { forwardRef } from "react";
2
+ import {
3
+ Radio as MuiRadio,
4
+ type RadioProps as MuiRadioProps,
5
+ } from "@mui/material";
6
+ import { type ReadOnlyControlProps } from "@recursica/adapter-common";
7
+ import { RadioGroup } from "./RadioGroup";
8
+ import {
9
+ filterStylingProps,
10
+ type RecursicaOverStyled,
11
+ } from "../../utils/filterStylingProps";
12
+ import {
13
+ type RequireAccessibleLabel,
14
+ type RecursicaRadioProps,
15
+ } from "@recursica/adapter-common";
16
+ import {
17
+ FormControlLayout,
18
+ type FormControlLayoutProps,
19
+ } from "../FormControlLayout/FormControlLayout";
3
20
 
4
- export type RadioProps = React.HTMLAttributes<HTMLDivElement>;
21
+ import styles from "./Radio.module.css";
5
22
 
6
- export const Radio: React.FC<RadioProps> = (props) => {
7
- return <div {...props}>Radio</div>;
23
+ const RadioIcon: React.FC<{
24
+ className?: string;
25
+ style?: React.CSSProperties;
26
+ }> = ({ className, style }) => (
27
+ <svg
28
+ xmlns="http://www.w3.org/2000/svg"
29
+ viewBox="0 0 16 16"
30
+ fill="currentColor"
31
+ className={className}
32
+ style={style}
33
+ >
34
+ <circle cx="8" cy="8" r="5" />
35
+ </svg>
36
+ );
37
+
38
+ export type RadioWrapperProps = Omit<MuiRadioProps, "size" | "color"> &
39
+ RecursicaRadioProps &
40
+ ReadOnlyControlProps &
41
+ Pick<
42
+ FormControlLayoutProps,
43
+ "formLayout" | "labelSize" | "controlMaxWidth" | "controlMinWidth"
44
+ >;
45
+
46
+ export type RecursicaRadioPropsAlias =
47
+ RequireAccessibleLabel<RadioWrapperProps>;
48
+
49
+ export type RadioProps = RecursicaOverStyled<RecursicaRadioPropsAlias>;
50
+
51
+ type RadioComponent = React.ForwardRefExoticComponent<
52
+ RadioProps & React.RefAttributes<HTMLInputElement>
53
+ > & {
54
+ Group: typeof RadioGroup;
8
55
  };
56
+
57
+ export const Radio = forwardRef<HTMLInputElement, RadioProps>(
58
+ function Radio(props, ref) {
59
+ const {
60
+ overStyled = false,
61
+ readOnly,
62
+ readOnlyComponent,
63
+ disabled,
64
+ formLayout,
65
+ labelSize,
66
+ controlMaxWidth,
67
+ controlMinWidth,
68
+ label,
69
+ description,
70
+ error,
71
+ style,
72
+ ...rest
73
+ } = props;
74
+ const sanitizedProps = filterStylingProps(rest, overStyled);
75
+ const restRecord = sanitizedProps as Record<string, unknown>;
76
+
77
+ // Actively delete dimension bindings that bypass the abstraction
78
+ delete restRecord["size"];
79
+ delete restRecord["color"];
80
+
81
+ const mergedClassNames: Partial<Record<string, string>> = {
82
+ root: styles.root,
83
+ body: styles.body,
84
+ inner: styles.inner,
85
+ radio: styles.radio,
86
+ icon: styles.icon,
87
+ labelWrapper: styles.labelWrapper,
88
+ label: styles.label,
89
+ };
90
+
91
+ const classNamesProp = restRecord.classNames;
92
+ if (
93
+ classNamesProp &&
94
+ typeof classNamesProp === "object" &&
95
+ !Array.isArray(classNamesProp)
96
+ ) {
97
+ const o = classNamesProp as Partial<Record<string, string>>;
98
+ mergedClassNames.root = o.root ? `${styles.root} ${o.root}` : styles.root;
99
+ mergedClassNames.body = o.body ? `${styles.body} ${o.body}` : styles.body;
100
+ mergedClassNames.inner = o.inner
101
+ ? `${styles.inner} ${o.inner}`
102
+ : styles.inner;
103
+ mergedClassNames.radio = o.radio
104
+ ? `${styles.radio} ${o.radio}`
105
+ : styles.radio;
106
+ mergedClassNames.icon = o.icon ? `${styles.icon} ${o.icon}` : styles.icon;
107
+ mergedClassNames.labelWrapper = o.labelWrapper
108
+ ? `${styles.labelWrapper} ${o.labelWrapper}`
109
+ : styles.labelWrapper;
110
+ mergedClassNames.label = o.label
111
+ ? `${styles.label} ${o.label}`
112
+ : styles.label;
113
+ }
114
+
115
+ const classNameProp = restRecord.className as string | undefined;
116
+ const finalClass = classNameProp
117
+ ? `${styles.root} ${classNameProp}`
118
+ : styles.root;
119
+
120
+ if (readOnly && !!readOnlyComponent) {
121
+ const isChecked = !!(restRecord.checked ?? restRecord.defaultChecked);
122
+ const ReadOnlyComp = readOnlyComponent;
123
+ const roNode = (
124
+ <ReadOnlyComp
125
+ {...props}
126
+ checked={isChecked}
127
+ label={restRecord.label as React.ReactNode}
128
+ />
129
+ );
130
+
131
+ if (formLayout) {
132
+ return (
133
+ <FormControlLayout
134
+ formLayout={formLayout}
135
+ labelSize={labelSize}
136
+ controlMaxWidth={controlMaxWidth}
137
+ controlMinWidth={controlMinWidth}
138
+ >
139
+ {roNode}
140
+ </FormControlLayout>
141
+ );
142
+ }
143
+
144
+ return <>{roNode}</>;
145
+ }
146
+
147
+ // We omit Mui's sizing/coloring so we rely strictly on variables from Radio.module.css
148
+ const radioNode = (
149
+ <MuiRadio
150
+ ref={ref as any}
151
+ icon={<RadioIcon />}
152
+ checkedIcon={<RadioIcon className={styles.checked} />}
153
+ className={finalClass}
154
+ classes={mergedClassNames}
155
+ disabled={readOnly || disabled}
156
+ {...(sanitizedProps as unknown as MuiRadioProps)}
157
+ />
158
+ );
159
+
160
+ const finalNode = label ? (
161
+ <div className={finalClass} style={style as React.CSSProperties}>
162
+ <div className={styles.body}>
163
+ {radioNode}
164
+ <div className={styles.labelWrapper}>
165
+ <label
166
+ className={styles.label}
167
+ htmlFor={restRecord.id as string}
168
+ data-disabled={readOnly || disabled ? true : undefined}
169
+ >
170
+ {label as React.ReactNode}
171
+ </label>
172
+ {description && (
173
+ <div
174
+ className={styles.description}
175
+ data-disabled={readOnly || disabled ? true : undefined}
176
+ >
177
+ {description}
178
+ </div>
179
+ )}
180
+ {error && (
181
+ <div
182
+ className={styles.error}
183
+ data-disabled={readOnly || disabled ? true : undefined}
184
+ >
185
+ {error}
186
+ </div>
187
+ )}
188
+ </div>
189
+ </div>
190
+ </div>
191
+ ) : (
192
+ radioNode
193
+ );
194
+
195
+ if (formLayout) {
196
+ return (
197
+ <FormControlLayout
198
+ formLayout={formLayout}
199
+ labelSize={labelSize}
200
+ controlMaxWidth={controlMaxWidth}
201
+ controlMinWidth={controlMinWidth}
202
+ >
203
+ {finalNode}
204
+ </FormControlLayout>
205
+ );
206
+ }
207
+
208
+ return finalNode;
209
+ },
210
+ ) as RadioComponent;
211
+
212
+ Radio.displayName = "Radio";
213
+ Radio.Group = RadioGroup;