@recursica/adapter-mui-v7 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 (389) hide show
  1. package/.storybook/commonArgTypes.ts +148 -0
  2. package/ARCHITECTURE.md +18 -0
  3. package/CHANGELOG.md +582 -0
  4. package/LICENSE +21 -0
  5. package/OVERSTYLING.md +59 -0
  6. package/README.md +70 -0
  7. package/SETUP.md +92 -0
  8. package/USAGE.md +57 -0
  9. package/dist/adapter-mui-v7.cjs +292 -0
  10. package/dist/adapter-mui-v7.cjs.map +1 -0
  11. package/dist/adapter-mui-v7.css +1 -0
  12. package/dist/adapter-mui-v7.js +40757 -0
  13. package/dist/adapter-mui-v7.js.map +1 -0
  14. package/dist/index.d.ts +2350 -0
  15. package/dist/vite.svg +1 -0
  16. package/docs/PHILOSOPHY.md +39 -0
  17. package/llms.txt +76 -0
  18. package/package.json +151 -0
  19. package/recursica_brand.json +2677 -0
  20. package/recursica_tokens.json +799 -0
  21. package/recursica_ui-kit.json +14981 -0
  22. package/recursica_variables_scoped.css +30489 -0
  23. package/src/GlobalExemptions.modules.css +7 -0
  24. package/src/Introduction.stories.tsx +184 -0
  25. package/src/OverStyling.tsx +87 -0
  26. package/src/Version.tsx +37 -0
  27. package/src/components/Accordion/ACCORDION_IMPLEMENTATION_NOTES.md +107 -0
  28. package/src/components/Accordion/Accordion.module.css +362 -0
  29. package/src/components/Accordion/Accordion.stories.tsx +198 -0
  30. package/src/components/Accordion/Accordion.test.tsx +1 -0
  31. package/src/components/Accordion/Accordion.tsx +285 -0
  32. package/src/components/Accordion/USAGE.md +43 -0
  33. package/src/components/Accordion/index.ts +1 -0
  34. package/src/components/AssistiveElement/ASSISTIVEELEMENT_IMPLEMENTATION_NOTES.md +59 -0
  35. package/src/components/AssistiveElement/AssistiveElement.module.css +121 -0
  36. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +68 -0
  37. package/src/components/AssistiveElement/AssistiveElement.test.tsx +1 -0
  38. package/src/components/AssistiveElement/AssistiveElement.tsx +94 -0
  39. package/src/components/AssistiveElement/USAGE.md +36 -0
  40. package/src/components/AssistiveElement/index.ts +1 -0
  41. package/src/components/AutoComplete/AutoComplete.module.css +456 -0
  42. package/src/components/AutoComplete/AutoComplete.stories.tsx +336 -0
  43. package/src/components/AutoComplete/AutoComplete.test.tsx +1 -0
  44. package/src/components/AutoComplete/AutoComplete.tsx +266 -0
  45. package/src/components/AutoComplete/IMPLEMENTATION_NOTES.md +37 -0
  46. package/src/components/AutoComplete/USAGE.md +68 -0
  47. package/src/components/AutoComplete/index.ts +1 -0
  48. package/src/components/Avatar/AVATAR_IMPLEMENTATION_NOTES.md +36 -0
  49. package/src/components/Avatar/Avatar.module.css +336 -0
  50. package/src/components/Avatar/Avatar.stories.tsx +92 -0
  51. package/src/components/Avatar/Avatar.test.tsx +1 -0
  52. package/src/components/Avatar/Avatar.tsx +88 -0
  53. package/src/components/Avatar/USAGE.md +38 -0
  54. package/src/components/Avatar/index.ts +1 -0
  55. package/src/components/Badge/Badge.module.css +115 -0
  56. package/src/components/Badge/Badge.stories.tsx +78 -0
  57. package/src/components/Badge/Badge.test.tsx +1 -0
  58. package/src/components/Badge/Badge.tsx +61 -0
  59. package/src/components/Badge/USAGE.md +40 -0
  60. package/src/components/Badge/index.ts +1 -0
  61. package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +51 -0
  62. package/src/components/Breadcrumb/Breadcrumb.module.css +51 -0
  63. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +114 -0
  64. package/src/components/Breadcrumb/Breadcrumb.test.tsx +1 -0
  65. package/src/components/Breadcrumb/Breadcrumb.tsx +70 -0
  66. package/src/components/Breadcrumb/USAGE.md +42 -0
  67. package/src/components/Breadcrumb/index.ts +1 -0
  68. package/src/components/Button/BUTTON_IMPLEMENTATION_NOTES.md +123 -0
  69. package/src/components/Button/Button.module.css +413 -0
  70. package/src/components/Button/Button.stories.tsx +196 -0
  71. package/src/components/Button/Button.styleIsolation.dom.test.tsx +98 -0
  72. package/src/components/Button/Button.tsx +156 -0
  73. package/src/components/Button/USAGE.md +46 -0
  74. package/src/components/Button/index.ts +1 -0
  75. package/src/components/Card/CARD_IMPLEMENTATION_NOTES.md +15 -0
  76. package/src/components/Card/Card.module.css +155 -0
  77. package/src/components/Card/Card.stories.tsx +131 -0
  78. package/src/components/Card/Card.test.tsx +1 -0
  79. package/src/components/Card/Card.tsx +202 -0
  80. package/src/components/Card/USAGE.md +57 -0
  81. package/src/components/Card/index.ts +1 -0
  82. package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +14 -0
  83. package/src/components/Checkbox/Checkbox.module.css +286 -0
  84. package/src/components/Checkbox/Checkbox.stories.tsx +97 -0
  85. package/src/components/Checkbox/Checkbox.test.tsx +1 -0
  86. package/src/components/Checkbox/Checkbox.tsx +259 -0
  87. package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
  88. package/src/components/Checkbox/CheckboxGroup.tsx +148 -0
  89. package/src/components/Checkbox/USAGE.md +36 -0
  90. package/src/components/Checkbox/index.ts +6 -0
  91. package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +102 -0
  92. package/src/components/Chip/Chip.module.css +283 -0
  93. package/src/components/Chip/Chip.stories.tsx +154 -0
  94. package/src/components/Chip/Chip.test.tsx +1 -0
  95. package/src/components/Chip/Chip.tsx +168 -0
  96. package/src/components/Chip/USAGE.md +55 -0
  97. package/src/components/Chip/index.ts +1 -0
  98. package/src/components/Container/Container.stories.tsx +118 -0
  99. package/src/components/Container/Container.test.tsx +1 -0
  100. package/src/components/Container/Container.tsx +51 -0
  101. package/src/components/Container/IMPLEMENTATION_NOTES.md +5 -0
  102. package/src/components/Container/USAGE.md +48 -0
  103. package/src/components/Container/index.ts +1 -0
  104. package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +29 -0
  105. package/src/components/DatePicker/DatePicker.icons.tsx +35 -0
  106. package/src/components/DatePicker/DatePicker.module.css +464 -0
  107. package/src/components/DatePicker/DatePicker.stories.tsx +163 -0
  108. package/src/components/DatePicker/DatePicker.test.tsx +1 -0
  109. package/src/components/DatePicker/DatePicker.tsx +229 -0
  110. package/src/components/DatePicker/USAGE.md +49 -0
  111. package/src/components/DatePicker/index.ts +1 -0
  112. package/src/components/Dropdown/BareDropdown.tsx +168 -0
  113. package/src/components/Dropdown/DROPDOWN_IMPLEMENTATION_NOTES.md +45 -0
  114. package/src/components/Dropdown/Dropdown.icons.tsx +33 -0
  115. package/src/components/Dropdown/Dropdown.module.css +535 -0
  116. package/src/components/Dropdown/Dropdown.stories.tsx +252 -0
  117. package/src/components/Dropdown/Dropdown.test.tsx +1 -0
  118. package/src/components/Dropdown/Dropdown.tsx +319 -0
  119. package/src/components/Dropdown/USAGE.md +68 -0
  120. package/src/components/Dropdown/index.ts +1 -0
  121. package/src/components/FileInput/FILEINPUT_IMPLEMENTATION_NOTES.md +153 -0
  122. package/src/components/FileInput/FileInput.module.css +268 -0
  123. package/src/components/FileInput/FileInput.stories.tsx +313 -0
  124. package/src/components/FileInput/FileInput.test.tsx +1 -0
  125. package/src/components/FileInput/FileInput.tsx +415 -0
  126. package/src/components/FileInput/USAGE.md +145 -0
  127. package/src/components/FileInput/index.ts +1 -0
  128. package/src/components/FileUpload/FILEUPLOAD_IMPLEMENTATION_NOTES.md +249 -0
  129. package/src/components/FileUpload/FileUpload.module.css +200 -0
  130. package/src/components/FileUpload/FileUpload.stories.tsx +362 -0
  131. package/src/components/FileUpload/FileUpload.test.tsx +1 -0
  132. package/src/components/FileUpload/FileUpload.tsx +352 -0
  133. package/src/components/FileUpload/USAGE.md +199 -0
  134. package/src/components/FileUpload/index.ts +1 -0
  135. package/src/components/Flex/Flex.stories.tsx +128 -0
  136. package/src/components/Flex/Flex.test.tsx +1 -0
  137. package/src/components/Flex/Flex.tsx +89 -0
  138. package/src/components/Flex/USAGE.md +41 -0
  139. package/src/components/Flex/index.ts +1 -0
  140. package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
  141. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +118 -0
  142. package/src/components/FormControlLayout/FormControlLayout.test.tsx +1 -0
  143. package/src/components/FormControlLayout/FormControlLayout.tsx +72 -0
  144. package/src/components/FormControlLayout/USAGE.md +40 -0
  145. package/src/components/FormControlLayout/index.ts +1 -0
  146. package/src/components/FormControlWrapper/FORMCONTROLWRAPPER_IMPLEMENTATION_NOTES.md +35 -0
  147. package/src/components/FormControlWrapper/FormControlWrapper.module.css +87 -0
  148. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +129 -0
  149. package/src/components/FormControlWrapper/FormControlWrapper.test.tsx +1 -0
  150. package/src/components/FormControlWrapper/FormControlWrapper.tsx +149 -0
  151. package/src/components/FormControlWrapper/USAGE.md +40 -0
  152. package/src/components/FormControlWrapper/index.ts +1 -0
  153. package/src/components/Grid/Grid.module.css +72 -0
  154. package/src/components/Grid/Grid.stories.tsx +161 -0
  155. package/src/components/Grid/Grid.test.tsx +1 -0
  156. package/src/components/Grid/Grid.tsx +155 -0
  157. package/src/components/Grid/IMPLEMENTATION_NOTES.md +24 -0
  158. package/src/components/Grid/USAGE.md +53 -0
  159. package/src/components/Grid/index.ts +1 -0
  160. package/src/components/Group/Group.stories.tsx +120 -0
  161. package/src/components/Group/Group.test.tsx +1 -0
  162. package/src/components/Group/Group.tsx +116 -0
  163. package/src/components/Group/USAGE.md +41 -0
  164. package/src/components/Group/index.ts +1 -0
  165. package/src/components/Heading/Heading.stories.tsx +50 -0
  166. package/src/components/Heading/Heading.test.tsx +1 -0
  167. package/src/components/Heading/Heading.tsx +28 -0
  168. package/src/components/Heading/USAGE.md +36 -0
  169. package/src/components/Heading/index.ts +1 -0
  170. package/src/components/HoverCard/HoverCard.module.css +107 -0
  171. package/src/components/HoverCard/HoverCard.stories.tsx +172 -0
  172. package/src/components/HoverCard/HoverCard.test.tsx +1 -0
  173. package/src/components/HoverCard/HoverCard.tsx +145 -0
  174. package/src/components/HoverCard/USAGE.md +45 -0
  175. package/src/components/HoverCard/index.ts +1 -0
  176. package/src/components/Label/LABEL_IMPLEMENTATION_NOTES.md +27 -0
  177. package/src/components/Label/Label.module.css +169 -0
  178. package/src/components/Label/Label.stories.tsx +131 -0
  179. package/src/components/Label/Label.test.tsx +1 -0
  180. package/src/components/Label/Label.tsx +96 -0
  181. package/src/components/Label/USAGE.md +36 -0
  182. package/src/components/Label/index.ts +1 -0
  183. package/src/components/Layer/USAGE.md +50 -0
  184. package/src/components/Link/LINK_IMPLEMENTATION_NOTES.md +9 -0
  185. package/src/components/Link/Link.module.css +105 -0
  186. package/src/components/Link/Link.stories.tsx +58 -0
  187. package/src/components/Link/Link.test.tsx +1 -0
  188. package/src/components/Link/Link.tsx +45 -0
  189. package/src/components/Link/USAGE.md +40 -0
  190. package/src/components/Link/index.ts +1 -0
  191. package/src/components/Loader/LOADER_IMPLEMENTATION_NOTES.md +25 -0
  192. package/src/components/Loader/Loader.animate.dom.test.tsx +72 -0
  193. package/src/components/Loader/Loader.module.css +175 -0
  194. package/src/components/Loader/Loader.stories.tsx +123 -0
  195. package/src/components/Loader/Loader.test.tsx +1 -0
  196. package/src/components/Loader/Loader.tsx +72 -0
  197. package/src/components/Loader/USAGE.md +42 -0
  198. package/src/components/Loader/index.ts +1 -0
  199. package/src/components/Menu/IMPLEMENTATION_NOTES.md +5 -0
  200. package/src/components/Menu/Menu.module.css +283 -0
  201. package/src/components/Menu/Menu.stories.tsx +405 -0
  202. package/src/components/Menu/Menu.test.tsx +1 -0
  203. package/src/components/Menu/Menu.tsx +103 -0
  204. package/src/components/Menu/USAGE.md +53 -0
  205. package/src/components/Menu/index.ts +1 -0
  206. package/src/components/Modal/MODAL_IMPLEMENTATION_NOTES.md +31 -0
  207. package/src/components/Modal/Modal.module.css +302 -0
  208. package/src/components/Modal/Modal.stories.tsx +105 -0
  209. package/src/components/Modal/Modal.test.tsx +1 -0
  210. package/src/components/Modal/Modal.tsx +231 -0
  211. package/src/components/Modal/USAGE.md +40 -0
  212. package/src/components/Modal/index.ts +1 -0
  213. package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +93 -0
  214. package/src/components/NumberInput/NumberInput.module.css +303 -0
  215. package/src/components/NumberInput/NumberInput.stories.tsx +96 -0
  216. package/src/components/NumberInput/NumberInput.test.tsx +1 -0
  217. package/src/components/NumberInput/NumberInput.tsx +273 -0
  218. package/src/components/NumberInput/USAGE.md +36 -0
  219. package/src/components/NumberInput/index.ts +1 -0
  220. package/src/components/Pagination/IMPLEMENTATION_NOTES.md +40 -0
  221. package/src/components/Pagination/Pagination.icons.tsx +66 -0
  222. package/src/components/Pagination/Pagination.module.css +197 -0
  223. package/src/components/Pagination/Pagination.stories.tsx +48 -0
  224. package/src/components/Pagination/Pagination.test.tsx +1 -0
  225. package/src/components/Pagination/Pagination.tsx +123 -0
  226. package/src/components/Pagination/USAGE.md +36 -0
  227. package/src/components/Pagination/index.ts +1 -0
  228. package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +133 -0
  229. package/src/components/Panel/Panel.module.css +231 -0
  230. package/src/components/Panel/Panel.stories.tsx +227 -0
  231. package/src/components/Panel/Panel.test.tsx +1 -0
  232. package/src/components/Panel/Panel.tsx +186 -0
  233. package/src/components/Panel/USAGE.md +46 -0
  234. package/src/components/Panel/index.ts +1 -0
  235. package/src/components/Popover/IMPLEMENTATION_NOTES.md +22 -0
  236. package/src/components/Popover/Popover.module.css +118 -0
  237. package/src/components/Popover/Popover.stories.tsx +133 -0
  238. package/src/components/Popover/Popover.test.tsx +1 -0
  239. package/src/components/Popover/Popover.tsx +267 -0
  240. package/src/components/Popover/USAGE.md +69 -0
  241. package/src/components/Popover/index.ts +1 -0
  242. package/src/components/Radio/RADIO_IMPLEMENTATION_NOTES.md +12 -0
  243. package/src/components/Radio/Radio.module.css +247 -0
  244. package/src/components/Radio/Radio.stories.tsx +93 -0
  245. package/src/components/Radio/Radio.test.tsx +1 -0
  246. package/src/components/Radio/Radio.tsx +223 -0
  247. package/src/components/Radio/RadioGroup.stories.tsx +117 -0
  248. package/src/components/Radio/RadioGroup.tsx +122 -0
  249. package/src/components/Radio/USAGE.md +36 -0
  250. package/src/components/Radio/index.ts +2 -0
  251. package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
  252. package/src/components/ReadOnlyField/ReadOnlyField.module.css +54 -0
  253. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +163 -0
  254. package/src/components/ReadOnlyField/ReadOnlyField.test.tsx +1 -0
  255. package/src/components/ReadOnlyField/ReadOnlyField.tsx +108 -0
  256. package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
  257. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
  258. package/src/components/ReadOnlyField/USAGE.md +36 -0
  259. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
  260. package/src/components/ReadOnlyField/index.ts +2 -0
  261. package/src/components/RecursicaThemeProvider/USAGE.md +60 -0
  262. package/src/components/SegmentedControl/IMPLEMENTATION_NOTES.md +14 -0
  263. package/src/components/SegmentedControl/SegmentedControl.module.css +201 -0
  264. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +106 -0
  265. package/src/components/SegmentedControl/SegmentedControl.test.tsx +1 -0
  266. package/src/components/SegmentedControl/SegmentedControl.tsx +149 -0
  267. package/src/components/SegmentedControl/USAGE.md +49 -0
  268. package/src/components/SegmentedControl/index.ts +1 -0
  269. package/src/components/Slider/IMPLEMENTATION_NOTES.md +55 -0
  270. package/src/components/Slider/Slider.module.css +635 -0
  271. package/src/components/Slider/Slider.stories.tsx +282 -0
  272. package/src/components/Slider/Slider.test.tsx +1 -0
  273. package/src/components/Slider/Slider.tsx +435 -0
  274. package/src/components/Slider/USAGE.md +56 -0
  275. package/src/components/Slider/index.ts +1 -0
  276. package/src/components/Stack/Stack.stories.tsx +108 -0
  277. package/src/components/Stack/Stack.test.tsx +1 -0
  278. package/src/components/Stack/Stack.tsx +43 -0
  279. package/src/components/Stack/USAGE.md +41 -0
  280. package/src/components/Stack/index.ts +1 -0
  281. package/src/components/Stepper/IMPLEMENTATION_NOTES.md +120 -0
  282. package/src/components/Stepper/Stepper.module.css +474 -0
  283. package/src/components/Stepper/Stepper.stories.tsx +157 -0
  284. package/src/components/Stepper/Stepper.test.tsx +1 -0
  285. package/src/components/Stepper/Stepper.tsx +240 -0
  286. package/src/components/Stepper/USAGE.md +45 -0
  287. package/src/components/Stepper/index.ts +1 -0
  288. package/src/components/Switch/SWITCH_IMPLEMENTATION_NOTES.md +147 -0
  289. package/src/components/Switch/Switch.module.css +346 -0
  290. package/src/components/Switch/Switch.stories.tsx +114 -0
  291. package/src/components/Switch/Switch.test.tsx +1 -0
  292. package/src/components/Switch/Switch.tsx +294 -0
  293. package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
  294. package/src/components/Switch/SwitchGroup.tsx +156 -0
  295. package/src/components/Switch/USAGE.md +36 -0
  296. package/src/components/Switch/index.ts +2 -0
  297. package/src/components/Table/TABLE_IMPLEMENTATION_NOTES.md +75 -0
  298. package/src/components/Table/Table.module.css +462 -0
  299. package/src/components/Table/Table.stories.tsx +154 -0
  300. package/src/components/Table/Table.test.tsx +1 -0
  301. package/src/components/Table/Table.tsx +250 -0
  302. package/src/components/Table/USAGE.md +90 -0
  303. package/src/components/Table/index.ts +1 -0
  304. package/src/components/Tabs/IMPLEMENTATION_NOTES.md +76 -0
  305. package/src/components/Tabs/Tabs.module.css +801 -0
  306. package/src/components/Tabs/Tabs.stories.tsx +174 -0
  307. package/src/components/Tabs/Tabs.test.tsx +1 -0
  308. package/src/components/Tabs/Tabs.tsx +103 -0
  309. package/src/components/Tabs/USAGE.md +61 -0
  310. package/src/components/Tabs/index.ts +1 -0
  311. package/src/components/Text/TEXT_IMPLEMENTATION_NOTES.md +10 -0
  312. package/src/components/Text/Text.stories.tsx +75 -0
  313. package/src/components/Text/Text.test.tsx +1 -0
  314. package/src/components/Text/Text.tsx +19 -0
  315. package/src/components/Text/USAGE.md +40 -0
  316. package/src/components/Text/index.ts +1 -0
  317. package/src/components/TextArea/TEXTAREA_IMPLEMENTATION_NOTES.md +42 -0
  318. package/src/components/TextArea/TextArea.module.css +203 -0
  319. package/src/components/TextArea/TextArea.stories.tsx +94 -0
  320. package/src/components/TextArea/TextArea.test.tsx +1 -0
  321. package/src/components/TextArea/TextArea.tsx +162 -0
  322. package/src/components/TextArea/USAGE.md +38 -0
  323. package/src/components/TextArea/index.ts +1 -0
  324. package/src/components/TextField/TextField.module.css +271 -0
  325. package/src/components/TextField/TextField.stories.tsx +162 -0
  326. package/src/components/TextField/TextField.test.tsx +1 -0
  327. package/src/components/TextField/TextField.tsx +182 -0
  328. package/src/components/TextField/USAGE.md +38 -0
  329. package/src/components/TextField/index.ts +1 -0
  330. package/src/components/TimePicker/TIMEPICKER_IMPLEMENTATION_NOTES.md +89 -0
  331. package/src/components/TimePicker/TimePicker.module.css +262 -0
  332. package/src/components/TimePicker/TimePicker.stories.tsx +155 -0
  333. package/src/components/TimePicker/TimePicker.test.tsx +1 -0
  334. package/src/components/TimePicker/TimePicker.tsx +277 -0
  335. package/src/components/TimePicker/USAGE.md +61 -0
  336. package/src/components/TimePicker/index.ts +1 -0
  337. package/src/components/Timeline/IMPLEMENTATION_NOTES.md +42 -0
  338. package/src/components/Timeline/Timeline.module.css +363 -0
  339. package/src/components/Timeline/Timeline.stories.tsx +128 -0
  340. package/src/components/Timeline/Timeline.test.tsx +1 -0
  341. package/src/components/Timeline/Timeline.tsx +90 -0
  342. package/src/components/Timeline/TimelineItem.tsx +95 -0
  343. package/src/components/Timeline/USAGE.md +41 -0
  344. package/src/components/Timeline/index.ts +2 -0
  345. package/src/components/Toast/TOAST_IMPLEMENTATION_NOTES.md +37 -0
  346. package/src/components/Toast/Toast.module.css +193 -0
  347. package/src/components/Toast/Toast.stories.tsx +67 -0
  348. package/src/components/Toast/Toast.test.tsx +1 -0
  349. package/src/components/Toast/Toast.tsx +121 -0
  350. package/src/components/Toast/USAGE.md +42 -0
  351. package/src/components/Toast/index.ts +1 -0
  352. package/src/components/Tooltip/Tooltip.module.css +83 -0
  353. package/src/components/Tooltip/Tooltip.stories.tsx +165 -0
  354. package/src/components/Tooltip/Tooltip.test.tsx +1 -0
  355. package/src/components/Tooltip/Tooltip.tsx +78 -0
  356. package/src/components/Tooltip/USAGE.md +40 -0
  357. package/src/components/Tooltip/index.ts +1 -0
  358. package/src/components/TransferList/TRANSFERLIST_IMPLEMENTATION_NOTES.md +140 -0
  359. package/src/components/TransferList/TransferList.module.css +174 -0
  360. package/src/components/TransferList/TransferList.stories.tsx +121 -0
  361. package/src/components/TransferList/TransferList.test.tsx +1 -0
  362. package/src/components/TransferList/TransferList.tsx +419 -0
  363. package/src/components/TransferList/USAGE.md +77 -0
  364. package/src/components/TransferList/index.ts +1 -0
  365. package/src/components/Tree/IMPLEMENTATION_NOTES.md +53 -0
  366. package/src/components/Tree/Tree.module.css +272 -0
  367. package/src/components/Tree/Tree.stories.tsx +104 -0
  368. package/src/components/Tree/Tree.test.tsx +1 -0
  369. package/src/components/Tree/Tree.tsx +298 -0
  370. package/src/components/Tree/USAGE.md +99 -0
  371. package/src/components/Tree/index.ts +1 -0
  372. package/src/components/Typography/TYPOGRAPHY_IMPLEMENTATION_NOTES.md +17 -0
  373. package/src/components/Typography/Typography.module.css +13 -0
  374. package/src/components/Typography/Typography.test.tsx +1 -0
  375. package/src/components/Typography/Typography.tsx +43 -0
  376. package/src/components/Typography/USAGE.md +40 -0
  377. package/src/components/Typography/index.ts +1 -0
  378. package/src/components/index.ts +50 -0
  379. package/src/env.d.ts +7 -0
  380. package/src/index.ts +194 -0
  381. package/src/types/index.ts +9 -0
  382. package/src/types/scss-modules.d.ts +9 -0
  383. package/src/utils/ColorSchemeWrapper.tsx +23 -0
  384. package/src/utils/RequireAccessibleLabel.ts +1 -0
  385. package/src/utils/copyToClipboard.ts +36 -0
  386. package/src/utils/filterStylingProps.test.ts +85 -0
  387. package/src/utils/filterStylingProps.ts +143 -0
  388. package/src/utils/index.ts +1 -0
  389. package/src/utils/renderRichOption.tsx +51 -0
@@ -0,0 +1,89 @@
1
+ # TimePicker Implementation Notes
2
+
3
+ ## Architecture Overview
4
+
5
+ `TimePicker` is a composite of two independently-styled controls sitting side by side in a flex row:
6
+
7
+ 1. **The time field** — `@mui/x-date-pickers`'s `TimePicker`, always rendered with `format="hh:mm"` (or `"hh:mm:ss"` with `withSeconds`) — 12-hour digits, no native meridiem section.
8
+ 2. **The AM/PM selector** — `BareDropdown`, a headless variant of this adapter's own `Dropdown` component (see below), not a plain `Select`.
9
+
10
+ This shape is deliberate and **not configurable** — there is no prop to get a plain 24-hour field or to hide the AM/PM control. Every consumer gets the same 12-hour + Dropdown-styled-AM/PM composite. (Matt Massey, 2026-08-07 — an earlier revision of this component had a `hideAmPm` prop; it was removed once the design was confirmed fixed, and the shared `RecursicaTimePickerProps` contract in `adapter-common` no longer includes it.)
11
+
12
+ This was a deliberate choice over a native `<input type="time">`, in exchange for a real clock/list-based time selection UI, at the cost of a new dependency (`@mui/x-date-pickers` + `dayjs`, both added as optional peer deps + a real `dayjs` dependency).
13
+
14
+ ## `BareDropdown`
15
+
16
+ A new, **internal-only** component in `../Dropdown/BareDropdown.tsx` — not exported from this folder's `index.ts` (which only re-exports `./Dropdown`, not `./BareDropdown`). It's the same `@mui/material` `Select`/`MenuItem` primitives `Dropdown` wraps, styled via the **same** `Dropdown.module.css` classes (`root`/`input`/`icon`/`dropdown`/`option`), but with no `FormControlWrapper`/`WithReadOnlyWrapper` and no label/assistiveText/error/required props. Its `onChange` is normalized to `(value: string | null) => void` (just the selected value), unlike MUI's raw `Select` `onChange`, which hands back a `(event, child)` pair — this keeps its call signature identical to mantine-adapter's `BareDropdown` (whose underlying Mantine `Select` already has a plain-value `onChange`).
17
+
18
+ **Why not the public `Dropdown` component directly**: `Dropdown` wraps its own `FormControlWrapper`/`FormControlLayout` internally (it's meant to be used standalone). Nesting the full `Dropdown` inside `TimePicker` — which is already `FormControlWrapper`-wrapped — would double up `FormControl`/`FormControlLayout` structure. `BareDropdown` is the headless escape hatch for exactly this situation: reuse `Dropdown`'s visual styling without its structural wrapping. (Matt Massey, 2026-08-07.)
19
+
20
+ ## Internal state, unlike every other component here
21
+
22
+ Every other input in this adapter is a thin pass-through — the wrapped library component owns all interaction state. `TimePicker` is the exception: the time field and the AM/PM `BareDropdown` both mutate the _same_ conceptual value, so something has to reconcile them. `TimePicker.tsx` keeps a `useState<Dayjs | null>` for the full 24-hour internal value, seeded from `value`/`defaultValue`, synced when `value` changes (controlled usage), and updated by both controls (the field's own `onChange`, and the `BareDropdown`'s `onChange` — which just adds or subtracts 12 from the current hour). The public `value`/`onChange` API is unaffected — still a plain `"HH:mm"`/`"HH:mm:ss"` string; `dayjs` never leaks out.
23
+
24
+ ## `format="hh:mm"` has no meridiem section on purpose
25
+
26
+ Lowercase `hh` renders 12-hour digits (1–12) with no `a` (meridiem) token, so there's nothing for the user to toggle within the field itself — meridiem is only ever changed via the separate `BareDropdown`. Editing just the hour/minute digits preserves whichever meridiem the current internal value already has, since we always pass a fully-formed `Dayjs` value back into the field (never letting it manage its own uncontrolled state).
27
+
28
+ ## No `variant` prop to force "standard"
29
+
30
+ `@mui/x-date-pickers` v9's public `TimePicker`/`slotProps.field` API doesn't expose a `variant` prop at all (it's only reachable on an internal `textFieldProps` object this package doesn't surface). The CSS module defensively suppresses **both** the "standard" variant's underline (`::before`/`::after`) and the "outlined" variant's notched-outline, since which one actually renders isn't controllable from here — only one of the two suppressions will ever be doing anything at runtime.
31
+
32
+ ## Design tokens
33
+
34
+ - No dedicated `min-height` token exists for `time-picker` (unlike `text-field`/`date-picker`) — the field's height is derived from its own padding + line-height instead of a fixed token.
35
+ - `icon-size`/`icon-color`/`icon-text-gap` (plus the disabled/error `icon-color` variants) are wired via `leftSection` — see "Leading icon" below.
36
+ - `placeholder-opacity` remains exempted (`recursica-ignore`) — MUI X's field renders its empty-state "hh"/"mm" placeholder via its own internal `isFieldValueEmpty` styled-component variant (an inline opacity applied through emotion), not a native `::placeholder` pseudo-element this CSS module can target. Unlike mantine-adapter's `SpinInput` (a real `<input placeholder="--">`), there's no stable selector here to hook a token to without depending on MUI X's internal class names.
37
+ - The AM/PM `BareDropdown` draws its own border/background/padding from `Dropdown`'s own tokens via `Dropdown.module.css` — it does not reuse any `time-picker` tokens.
38
+
39
+ ## Known limitation — the popup clock/list view is unstyled
40
+
41
+ This pass covers the closed-state field and the AM/PM `BareDropdown` only. The open dropdown (digital clock list, depending on `views`) still renders with MUI's default theme, not Recursica tokens — there's no Figma-exported token set for it (mirrors the same category of gap `DatePicker`'s calendar popover has in `mantine-adapter`). Revisit once there's a design spec for it.
42
+
43
+ ## Read-Only Implementation
44
+
45
+ `readOnlyType="text"`, matching `DatePicker`'s convention.
46
+
47
+ ## Leading icon (Matt Massey, 2026-08-30)
48
+
49
+ Added `leftSection` (`RecursicaTimePickerProps`), matching `TextField`'s naming/convention: purely decorative, consumer-supplied, no default (unlike `DatePicker`'s fixed `CalendarIcon` — there's no single icon that fits every `TimePicker` use).
50
+
51
+ MUI X's `TimePicker` has no `leftSection` concept — wired via `slotProps.textField.slotProps.input.startAdornment` (the `textField`/`input` slots are exposed at the top level of `TimePicker`'s own `slotProps`, sibling to `field`, via `PickerFieldUISlotPropsFromContext` — confirmed by reading `useDesktopPicker.types.d.ts`/`PickerFieldUI.d.ts` directly, not just the top-level `TimePickerProps` surface). `startAdornment` renders as a plain sibling of `.MuiPickersInputBase-sectionsContainer` inside `PickersInputBase` (confirmed via `PickersInputBase.js`), so it's wrapped in the same `<div className={styles.section} data-position="left">` shape `TextField.tsx` already uses, rather than depending on MUI's own adornment styling. Also added `data-with-left-section` on `.root` so `.MuiPickersInputBase-sectionsContainer`'s own hardcoded `padding-left` (previously always the field's full `horizontal-padding`, structured for the no-icon case) collapses to just `icon-text-gap` once the icon itself is doing the border-inset job instead.
52
+
53
+ ## Visual review fix (Matt Massey, 2026-08-07)
54
+
55
+ **`BareDropdown`'s border color didn't match Mantine's version, despite both reading the same `Dropdown` tokens**: a real bug in `BareDropdown.tsx` — `className={styles.root}` was set explicitly on `<MuiSelect>`, then `{...sanitizedProps}` was spread _after_ it. Any caller passing its own `className` (like `TimePicker.tsx`'s `styles.amPmSelect`) silently overwrote `styles.root` entirely via that later spread, so `Dropdown.module.css`'s border-color/background/`width: 100%` never actually applied — MUI's own default border rendered instead. Fixed by extracting `className` explicitly and merging it (`` `${styles.root} ${className}` ``) before it reaches `<MuiSelect>`, the same pattern mantine-adapter's `BareDropdown` already used. This also explains why the AM/PM box's width had looked accidentally "correct" before: the competing `width: 100%` rule from `.root` was never actually being applied either.
56
+
57
+ ## Visual review round 2 (Matt Massey, 2026-08-08)
58
+
59
+ - **Time field's default clock icon removed**: `time-picker`'s own token schema has no icon slot (see EXEMPTIONS above) and the popup it opens isn't styled to Recursica tokens anyway (see "Known limitation" below) — showing a button to open an unstyled popup was worse than not showing one. Removed via `slots={{ openPickerButton: () => null }}`; this also shrank the field's own width back down, since the icon's reserved layout space is gone.
60
+ - **AM/PM `BareDropdown` looked shorter than the time field and had a doubled border**: a latent, pre-existing bug in the _shared_ `Dropdown.module.css`, not something new in this composite — confirmed the standalone `Dropdown` component has the exact same issue (measured its own `.input` box at 42.8px instead of the 48px `min-height` token). Root cause: MUI generates a compound class for the select's inner box (e.g. `.css-xxx-...-MuiSelect-select`) that sets its own `min-height: 1.4375em` (~23px) — two classes' worth of specificity, which beats `Dropdown.module.css`'s single-class `.input` rule, so the 48px token silently loses. Separately, MUI's outlined variant renders its own native `fieldset`/`notchedOutline` border _underneath_ `.input`'s own Recursica border — the second border Matt saw. Both fixed **scoped to this composite only** (`.amPmSelect :global(.MuiSelect-select) { min-height: ... !important }` + suppressing `.MuiOutlinedInput-notchedOutline`), matching the same technique already used to suppress the time field's own native decoration — _not_ fixed in the shared `Dropdown.module.css`, since that would change the standalone `Dropdown` component everywhere in the app, outside this component's scope. Flagged to Matt as a separate, real bug worth a dedicated fix.
61
+
62
+ ## Visual review round 3 (Matt Massey, 2026-08-08)
63
+
64
+ - **AM/PM value wasn't vertically centered**: a side effect of the round-2 min-height fix above — forcing the box to 48px left real slack below the text (`display: block`, top-aligned line box), which reads as "not centered" once the box is taller than its own padding + line-height. Added `display: flex; align-items: center` to the same scoped override so the slack distributes evenly instead.
65
+ - **AM/PM dropdown menu showed MUI's default blue selected-state tint instead of Recursica's**: `Dropdown.module.css`'s `.option[data-selected="true"]` rule (Recursica's neutral hover/selected tint) was never actually wired up — neither `Dropdown.tsx` nor `BareDropdown.tsx` ever set `data-selected` on the currently-selected `MenuItem`, so MUI's own `Mui-selected` class (with its default primary-blue background) rendered uncontested instead. This is a **shared, pre-existing gap** affecting the real `Dropdown` component too, just not visible there by default (`Dropdown`'s own default story has no value pre-selected, so nothing shows the tint) — unlike `TimePicker`'s AM/PM, which always has a value. Fixed in **both** `Dropdown.tsx` and `BareDropdown.tsx` (compare each `MenuItem`'s value against the select's current `value`/`defaultValue`) since this is a low-risk, purely-additive fix completing an already-designed CSS contract, not a new design decision — unlike the min-height/border fix above, which changes visual geometry and was deliberately scoped to this composite only.
66
+
67
+ ## Visual review round 4 (Matt Massey, 2026-08-08) — time field width
68
+
69
+ The time field itself rendered wider than intended (220px vs. the 130px `time-picker.properties.width` token), despite `.field { width: fit-content }` already being set. Root cause: `@mui/x-date-pickers` computes and inline-sets a literal pixel width on `.MuiPickersInputBase-sectionsContainer` based on the format string (182px for "hh:mm") — sized generously for the widest possible rendered value, independent of `.field`'s own width. Reset via `.field :global(.MuiPickersInputBase-sectionsContainer) { width: auto !important; flex-grow: 0 !important; }` — safe here because these are real text `<span>`s (not native `<input>`s), so `auto` sizes to their actual content correctly, unlike the native-`<input>`-in-`BareDropdown` case elsewhere in this file, where `auto` alone didn't help. Now matches Mantine's `.timeWrapper`'s 130px exactly.
70
+
71
+ ## Visual review round 5 (Matt Massey, 2026-08-08)
72
+
73
+ - **AM/PM error-state border wasn't changing**: `Dropdown.tsx`'s error/disabled state was set via `inputProps` (`data-error`/`data-disabled`), which only reaches the nested accessibility `<input>` — a different element from `.root` (the actual Select root carrying the border), which is what `Dropdown.module.css`'s `.root[data-error]`/`[data-disabled]` selectors require. The error border never actually applied, in the real `Dropdown` component or `BareDropdown`. Fixed by also setting `data-error`/`data-disabled` directly as top-level props on `<MuiSelect>` (they land on its root element) in both `Dropdown.tsx` and `BareDropdown.tsx` — the latter also needed an `error?: boolean` prop added to its own interface, since it previously had none.
74
+ - **Static/Editable ReadOnly showed "Invalid Date" instead of a value**: a real, separate bug — `toDayjs`'s 2-argument `dayjs(value, format)` call silently does nothing without the `customParseFormat` plugin registered; without it, dayjs falls back to native `Date` parsing, which fails on a bare "HH:mm" string (no date component). This went unnoticed until now because every prior interactive test produced `Dayjs` objects directly from the picker's own `onChange`, never actually exercising `toDayjs` with a real initial `value`/`defaultValue` string. Fixed by adding `dayjs.extend(customParseFormat)`.
75
+ - **Static/Editable ReadOnly showed the raw 24-hour value with no AM/PM** (e.g. "14:30" instead of "2:30 PM"): `readOnlyValue` was passed the raw internal string as-is. Added `formatReadOnlyTime` (uses `toDayjs` + dayjs's own `.format("h:mm A")`) before handing it to `WithReadOnlyWrapper`.
76
+
77
+ ## Leading icon positioned too far right (bug fix, Matt Massey, 2026-08-30)
78
+
79
+ Found during a mantine-vs-mui source-of-truth comparison of `ui-kit-timepicker--with-leading-icon`:
80
+ the icon rendered ~14px further right than `Dropdown`/`AutoComplete`/`TextField`'s own leading
81
+ icons, with a correspondingly oversized gap to the field's own border. Root cause: MUI X's
82
+ `MuiPickersInputBase-root` applies its own native `padding-left: 14px` whenever a `startAdornment`
83
+ is present (`.MuiPickersInputBase-adornedStart`, mirroring MUI core `InputBase`'s own adornment
84
+ padding) — on top of `.section`'s own token-driven `padding-left` (`horizontal-padding`), this
85
+ doubled the inset. Fixed by neutralizing MUI's native padding
86
+ (`.field :global(.MuiPickersInputBase-adornedStart) { padding-left: 0 !important; }`) so `.section`
87
+ is the sole source of the icon's inset from the border, matching mantine-adapter's corrected
88
+ rendering (see mantine-adapter's own `TIMEPICKER_IMPLEMENTATION_NOTES.md`, "Leading icon overlapped
89
+ the field text").
@@ -0,0 +1,262 @@
1
+ /* Brand-layer exemptions (recursica-allow-brand) — see recursica-token-analyzer README.md.
2
+ * Global hover/focus/disabled state tokens (recursica_variables_scoped.css header, 'Hover & Focus states' / 'Disabled state' — implicit rule for every interactive element; components must not define their own per-component treatment).
3
+ * recursica-allow-brand: --recursica_brand_states_focus_blur
4
+ * recursica-allow-brand: --recursica_brand_states_focus_border-size
5
+ * recursica-allow-brand: --recursica_brand_states_focus_color
6
+ * recursica-allow-brand: --recursica_brand_states_focus_margin
7
+ */
8
+
9
+ /* LAYOUT SPACING OVERRIDES:
10
+ - Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens. */
11
+ .layoutOverride {
12
+ --form-control-margin-bottom: var(
13
+ --recursica_ui-kit_components_time-picker_variants_layouts_stacked_properties_top-bottom-margin
14
+ );
15
+ }
16
+
17
+ .layoutOverride[data-form-layout="side-by-side"] {
18
+ --form-control-margin-bottom: var(
19
+ --recursica_ui-kit_components_time-picker_variants_layouts_side-by-side_properties_top-bottom-margin
20
+ );
21
+ }
22
+
23
+ /* HARDCODED VALUES:
24
+ - border-style: solid. Native structural rendering rule.
25
+ - display: flex on .root — the time field and the AM/PM BareDropdown are two visually separate
26
+ controls sitting side by side, not merged into one shared box (BareDropdown draws its own
27
+ border/background from Dropdown.module.css). See TIMEPICKER_IMPLEMENTATION_NOTES.md.
28
+ - MUI X's field variant can't be forced from this component's public API (see
29
+ TIMEPICKER_IMPLEMENTATION_NOTES.md) — whichever native decoration it renders is suppressed
30
+ below, and our own border/background are applied to .field instead.
31
+ */
32
+
33
+ .root {
34
+ display: flex;
35
+ align-items: flex-start;
36
+ gap: var(
37
+ --recursica_ui-kit_components_time-picker_properties_horizontal-padding
38
+ );
39
+ width: fit-content;
40
+ }
41
+
42
+ .field {
43
+ /* min-width, not width: the `width` token was authored for a single plain input (confirmed against
44
+ text-field's identical token shape); this is now only the time-entry half of the composite. */
45
+ min-width: var(--recursica_ui-kit_components_time-picker_properties_width);
46
+ width: fit-content;
47
+ border-radius: var(
48
+ --recursica_ui-kit_components_time-picker_properties_border-radius
49
+ );
50
+ border-width: var(
51
+ --recursica_ui-kit_components_time-picker_properties_border-size
52
+ );
53
+ border-style: solid;
54
+ border-color: var(
55
+ --recursica_ui-kit_components_time-picker_properties_colors_border-color
56
+ );
57
+ background-color: var(
58
+ --recursica_ui-kit_components_time-picker_properties_colors_background-color
59
+ );
60
+ color: var(
61
+ --recursica_ui-kit_components_time-picker_properties_colors_text-color
62
+ );
63
+ }
64
+
65
+ /* Suppress whichever native field decoration MUI X renders by default (its public API doesn't
66
+ expose a variant prop to force "standard" in this version) — .field draws the border instead,
67
+ regardless of whether the field defaults to "outlined" or "standard". */
68
+ .field :global(.MuiPickersInputBase-root::before),
69
+ .field :global(.MuiPickersInputBase-root::after),
70
+ .field :global(.MuiInput-root::before),
71
+ .field :global(.MuiInput-root::after) {
72
+ border-bottom: none !important;
73
+ }
74
+
75
+ .field :global(.MuiPickersOutlinedInput-notchedOutline) {
76
+ border: none !important;
77
+ }
78
+
79
+ .field :global(.MuiPickersInputBase-sectionsContainer) {
80
+ /* MUI X computes and inline-sets a literal pixel width here based on the format string (e.g.
81
+ 182px for "hh:mm"), sized generously to fit the widest possible rendered value — wider than
82
+ .field's own `width: fit-content` intends. Reset it so the field visually matches Mantine's
83
+ equally-compact time input; the section <span>s are real text content, so width: auto sizes to
84
+ them correctly (unlike the native-<input>-in-BareDropdown case elsewhere in this file, where
85
+ `auto` didn't help — no UA-default-sizing quirk here since these aren't native inputs). */
86
+ width: auto !important;
87
+ flex-grow: 0 !important;
88
+ padding-top: var(
89
+ --recursica_ui-kit_components_time-picker_properties_vertical-padding
90
+ );
91
+ padding-bottom: var(
92
+ --recursica_ui-kit_components_time-picker_properties_vertical-padding
93
+ );
94
+ padding-left: var(
95
+ --recursica_ui-kit_components_time-picker_properties_horizontal-padding
96
+ );
97
+ padding-right: var(
98
+ --recursica_ui-kit_components_time-picker_properties_horizontal-padding
99
+ );
100
+
101
+ font-family: var(
102
+ --recursica_ui-kit_components_time-picker_properties_text_font-family
103
+ );
104
+ font-size: var(
105
+ --recursica_ui-kit_components_time-picker_properties_text_font-size
106
+ );
107
+ font-style: var(
108
+ --recursica_ui-kit_components_time-picker_properties_text_font-style
109
+ );
110
+ font-weight: var(
111
+ --recursica_ui-kit_components_time-picker_properties_text_font-weight
112
+ );
113
+ letter-spacing: var(
114
+ --recursica_ui-kit_components_time-picker_properties_text_letter-spacing
115
+ );
116
+ line-height: var(
117
+ --recursica_ui-kit_components_time-picker_properties_text_line-height
118
+ );
119
+ text-decoration: var(
120
+ --recursica_ui-kit_components_time-picker_properties_text_text-decoration
121
+ );
122
+ text-transform: var(
123
+ --recursica_ui-kit_components_time-picker_properties_text_text-transform
124
+ );
125
+ }
126
+
127
+ .field :global(.MuiPickersInputBase-input) {
128
+ color: inherit;
129
+ }
130
+
131
+ /* Leading icon (leftSection), rendered via slotProps.textField.slotProps.input.startAdornment —
132
+ a sibling of .MuiPickersInputBase-sectionsContainer inside .field, same shape as TextField's own
133
+ startAdornment wrapping. Only one icon-color token exists for time-picker (unlike text-field's
134
+ separate leading/trailing) — this field has no right-side icon slot. */
135
+ .section {
136
+ display: flex;
137
+ align-items: center;
138
+ padding-left: var(
139
+ --recursica_ui-kit_components_time-picker_properties_horizontal-padding
140
+ );
141
+ }
142
+
143
+ /* MUI X's `MuiPickersInputBase-root` adds its own native 14px `padding-left` whenever a
144
+ startAdornment is present (`.MuiPickersInputBase-adornedStart`, mirroring MUI core InputBase's
145
+ own adornment padding) — stacked on top of `.section`'s own token-driven padding-left above,
146
+ this doubled the inset and pushed the icon noticeably right of where Dropdown/TextField/
147
+ AutoComplete's own leading icons sit (bug: icon read as "too far right"). `.section` alone
148
+ should own this inset. */
149
+ .field :global(.MuiPickersInputBase-adornedStart) {
150
+ padding-left: 0 !important;
151
+ }
152
+
153
+ .section :global(svg) {
154
+ width: var(--recursica_ui-kit_components_time-picker_properties_icon-size);
155
+ height: var(--recursica_ui-kit_components_time-picker_properties_icon-size);
156
+ color: var(
157
+ --recursica_ui-kit_components_time-picker_properties_colors_icon-color
158
+ );
159
+ }
160
+
161
+ /* With a leftSection present, the icon (not .field's own border) now owns the inset from the left
162
+ edge — sectionsContainer's own padding-left collapses to just the icon-text-gap between icon and
163
+ digits. */
164
+ .root[data-with-left-section="true"]
165
+ .field
166
+ :global(.MuiPickersInputBase-sectionsContainer) {
167
+ padding-left: var(
168
+ --recursica_ui-kit_components_time-picker_properties_icon-text-gap
169
+ ) !important;
170
+ }
171
+
172
+ /* The AM/PM BareDropdown reuses Dropdown.module.css's own border/background/padding entirely —
173
+ this only controls its size/alignment within the flex row. */
174
+ .amPmSelect {
175
+ flex: 0 0 auto;
176
+ align-self: flex-start;
177
+ width: auto;
178
+ min-width: 5.5rem;
179
+ }
180
+
181
+ /* MUI's own generated class for the select's inner box (a compound selector, e.g.
182
+ `.css-xxx-...-MuiSelect-select`) has higher specificity than Dropdown.module.css's single-class
183
+ `.input` rule, so its own `min-height: 1.4375em` (~23px) silently wins over our 48px token —
184
+ this is a latent bug in the shared Dropdown.module.css itself (the standalone Dropdown
185
+ component has the exact same undersized box; flagged separately, not fixed here to avoid an
186
+ app-wide change outside TimePicker's scope). `!important` here only re-asserts the height
187
+ Dropdown was always supposed to have, scoped to this composite. MUI's outlined variant also
188
+ renders its own native `fieldset`/`notchedOutline` border *in addition to* `.input`'s own
189
+ Recursica border — suppressed the same way the time field already suppresses its own native
190
+ decoration above. See TIMEPICKER_IMPLEMENTATION_NOTES.md. */
191
+ .amPmSelect :global(.MuiSelect-select) {
192
+ min-height: var(
193
+ --recursica_ui-kit_globals_form_field_size_single-line-input-height
194
+ ) !important;
195
+ box-sizing: border-box !important;
196
+ /* Forcing min-height above leaves real slack below the (block-flow, top-aligned) text once the
197
+ box is taller than its own padding + line-height — the value read as "not centered". Flex +
198
+ center distributes that slack evenly instead. */
199
+ display: flex !important;
200
+ align-items: center !important;
201
+ }
202
+
203
+ .amPmSelect :global(.MuiOutlinedInput-notchedOutline) {
204
+ border: none !important;
205
+ }
206
+
207
+ /* -------------------------------------
208
+ STATE CASCADE ARCHITECTURE
209
+ -------------------------------------- */
210
+
211
+ /* Focus State Mapping — applied to the time field only (the BareDropdown has its own via
212
+ Dropdown's own CSS module). */
213
+ .field:has(:global(.Mui-focused)) {
214
+ box-shadow:
215
+ 0 0 0 var(--recursica_brand_states_focus_border-size)
216
+ var(--recursica_brand_states_focus_color),
217
+ 0 0 var(--recursica_brand_states_focus_blur)
218
+ var(--recursica_brand_states_focus_margin)
219
+ var(--recursica_brand_states_focus_color);
220
+ }
221
+
222
+ /* Error State Mapping (data-error is set explicitly by TimePicker.tsx). */
223
+ .root[data-error="true"] .field {
224
+ border-color: var(
225
+ --recursica_ui-kit_components_time-picker_variants_states_error_properties_colors_border-color
226
+ ) !important;
227
+ background-color: var(
228
+ --recursica_ui-kit_components_time-picker_variants_states_error_properties_colors_background-color
229
+ ) !important;
230
+ color: var(
231
+ --recursica_ui-kit_components_time-picker_variants_states_error_properties_colors_text-color
232
+ ) !important;
233
+ }
234
+
235
+ .root[data-error="true"] .section :global(svg) {
236
+ color: var(
237
+ --recursica_ui-kit_components_time-picker_variants_states_error_properties_colors_icon-color
238
+ ) !important;
239
+ }
240
+
241
+ /* Disabled State Mapping */
242
+ .field:has(:global(.Mui-disabled)) {
243
+ border-color: var(
244
+ --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_colors_border-color
245
+ ) !important;
246
+ background-color: var(
247
+ --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_colors_background-color
248
+ ) !important;
249
+ color: var(
250
+ --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_colors_text-color
251
+ ) !important;
252
+ opacity: var(
253
+ --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_opacity
254
+ ) !important;
255
+ cursor: not-allowed;
256
+ }
257
+
258
+ .field:has(:global(.Mui-disabled)) .section :global(svg) {
259
+ color: var(
260
+ --recursica_ui-kit_components_time-picker_variants_states_disabled_properties_colors_icon-color
261
+ ) !important;
262
+ }
@@ -0,0 +1,155 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { TimePicker } from "./TimePicker";
3
+ import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
4
+
5
+ const meta: Meta<typeof TimePicker> = {
6
+ title: "UI-Kit/TimePicker",
7
+ component: TimePicker,
8
+ tags: ["autodocs"],
9
+ parameters: {
10
+ controls: {
11
+ include: [
12
+ "value",
13
+ "defaultValue",
14
+ "disabled",
15
+ "error",
16
+ "required",
17
+ "label",
18
+ "assistiveText",
19
+ "readOnly",
20
+ "withSeconds",
21
+ "formLayout",
22
+ ],
23
+ },
24
+ docs: {
25
+ description: {
26
+ component: `
27
+ The \`TimePicker\` primitive provides a 12-hour time field (via \`@mui/x-date-pickers\`) paired with a dedicated AM/PM \`Dropdown\`-style selector, integrated directly into the \`FormControlWrapper\` architecture. This composite is the only way this component operates — a Recursica-specific design, not a user-configurable option.
28
+
29
+ ### Examples
30
+ Always structure horizontal architectures via the generic \`formLayout\` parameter.
31
+ \`\`\`tsx
32
+ <TimePicker
33
+ label="Start Time"
34
+ assistiveText="Select the deployment kick-off time."
35
+ formLayout="stacked"
36
+ />
37
+ \`\`\`
38
+ `,
39
+ },
40
+ },
41
+ },
42
+ argTypes: {
43
+ ...formControlArgTypes,
44
+ disabled: {
45
+ control: "boolean",
46
+ description:
47
+ "Maps the formal disabled variable states structurally to the input core.",
48
+ },
49
+ error: {
50
+ control: "text",
51
+ description:
52
+ "Applies the strict error string boundary rendering invalid structures seamlessly.",
53
+ },
54
+ required: {
55
+ control: "boolean",
56
+ },
57
+ label: {
58
+ control: "text",
59
+ },
60
+ assistiveText: {
61
+ control: "text",
62
+ },
63
+ readOnly: {
64
+ control: "boolean",
65
+ description:
66
+ "Toggles structural read-only data presentation explicitly blocking standard component bindings.",
67
+ },
68
+ withSeconds: {
69
+ control: "boolean",
70
+ description: "Shows and allows editing the seconds segment.",
71
+ },
72
+ },
73
+ };
74
+
75
+ export default meta;
76
+
77
+ type Story = StoryObj<typeof TimePicker>;
78
+
79
+ export const Default: Story = {
80
+ args: {
81
+ disabled: false,
82
+ label: "Meeting Time",
83
+ assistiveText: "Choose the start time in your local timezone.",
84
+ },
85
+ };
86
+
87
+ export const FormsSideBySide: Story = {
88
+ args: {
89
+ label: "Incident Start Time",
90
+ assistiveText: "When did the incident originally occur?",
91
+ formLayout: "side-by-side",
92
+ },
93
+ };
94
+
95
+ export const WithSeconds: Story = {
96
+ args: {
97
+ label: "Precise Execution Time",
98
+ assistiveText: "Includes a seconds segment for exact scheduling.",
99
+ withSeconds: true,
100
+ },
101
+ };
102
+
103
+ export const Disabled: Story = {
104
+ args: {
105
+ label: "Disabled Time Slot",
106
+ disabled: true,
107
+ },
108
+ };
109
+
110
+ export const ErrorState: Story = {
111
+ args: {
112
+ label: "Deployment Window",
113
+ error: "The chosen time falls outside the allowed deployment window.",
114
+ required: true,
115
+ },
116
+ };
117
+
118
+ export const WithLeadingIcon: Story = {
119
+ args: {
120
+ label: "Meeting Time",
121
+ assistiveText: "Choose the start time in your local timezone.",
122
+ leftSection: (
123
+ <svg
124
+ width="24"
125
+ height="24"
126
+ viewBox="0 0 24 24"
127
+ fill="none"
128
+ stroke="currentColor"
129
+ strokeWidth="2"
130
+ strokeLinecap="round"
131
+ strokeLinejoin="round"
132
+ >
133
+ <circle cx="12" cy="12" r="10"></circle>
134
+ <polyline points="12 6 12 12 16 14"></polyline>
135
+ </svg>
136
+ ),
137
+ },
138
+ };
139
+
140
+ export const StaticReadOnly: Story = {
141
+ args: {
142
+ label: "Static ReadOnly Review",
143
+ value: "14:30",
144
+ readOnly: true,
145
+ },
146
+ };
147
+
148
+ export const EditableReadOnly: Story = {
149
+ args: {
150
+ label: "Editable ReadOnly Review",
151
+ defaultValue: "09:00",
152
+ readOnly: true,
153
+ labelWithEditIcon: true,
154
+ },
155
+ };
@@ -0,0 +1 @@
1
+ // Placeholder for future TimePicker component tests. Add tests here if/when needed.