@recursica/adapter-mantine-v8 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 (362) hide show
  1. package/.storybook/commonArgTypes.ts +148 -0
  2. package/ARCHITECTURE.md +18 -0
  3. package/CHANGELOG.md +688 -0
  4. package/LICENSE +21 -0
  5. package/OVERSTYLING.md +56 -0
  6. package/README.md +70 -0
  7. package/SETUP.md +93 -0
  8. package/USAGE.md +57 -0
  9. package/dist/adapter-mantine-v8.cjs +12 -0
  10. package/dist/adapter-mantine-v8.cjs.map +1 -0
  11. package/dist/adapter-mantine-v8.css +1 -0
  12. package/dist/adapter-mantine-v8.js +5759 -0
  13. package/dist/adapter-mantine-v8.js.map +1 -0
  14. package/dist/index.d.ts +2095 -0
  15. package/dist/test.html +1 -0
  16. package/dist/vite.svg +1 -0
  17. package/docs/PHILOSOPHY.md +39 -0
  18. package/llms.txt +74 -0
  19. package/package.json +131 -0
  20. package/recursica_brand.json +2677 -0
  21. package/recursica_tokens.json +799 -0
  22. package/recursica_ui-kit.json +14981 -0
  23. package/recursica_variables_scoped.css +30489 -0
  24. package/src/GlobalExemptions.modules.css +7 -0
  25. package/src/Introduction.stories.tsx +154 -0
  26. package/src/OverStyling.tsx +79 -0
  27. package/src/Version.tsx +44 -0
  28. package/src/components/Accordion/ACCORDION_IMPLEMENTATION_NOTES.md +72 -0
  29. package/src/components/Accordion/Accordion.module.css +367 -0
  30. package/src/components/Accordion/Accordion.stories.tsx +189 -0
  31. package/src/components/Accordion/Accordion.test.tsx +1 -0
  32. package/src/components/Accordion/Accordion.tsx +220 -0
  33. package/src/components/Accordion/USAGE.md +51 -0
  34. package/src/components/Accordion/index.ts +1 -0
  35. package/src/components/AssistiveElement/ASSISTIVEELEMENT_IMPLEMENTATION_NOTES.md +45 -0
  36. package/src/components/AssistiveElement/AssistiveElement.module.css +111 -0
  37. package/src/components/AssistiveElement/AssistiveElement.stories.tsx +68 -0
  38. package/src/components/AssistiveElement/AssistiveElement.test.tsx +1 -0
  39. package/src/components/AssistiveElement/AssistiveElement.tsx +93 -0
  40. package/src/components/AssistiveElement/USAGE.md +36 -0
  41. package/src/components/AutoComplete/AUTOCOMPLETE_IMPLEMENTATION_NOTES.md +42 -0
  42. package/src/components/AutoComplete/AutoComplete.module.css +430 -0
  43. package/src/components/AutoComplete/AutoComplete.stories.tsx +336 -0
  44. package/src/components/AutoComplete/AutoComplete.test.tsx +1 -0
  45. package/src/components/AutoComplete/AutoComplete.tsx +179 -0
  46. package/src/components/AutoComplete/USAGE.md +80 -0
  47. package/src/components/Avatar/AVATAR_IMPLEMENTATION_NOTES.md +34 -0
  48. package/src/components/Avatar/Avatar.module.css +336 -0
  49. package/src/components/Avatar/Avatar.stories.tsx +92 -0
  50. package/src/components/Avatar/Avatar.test.tsx +1 -0
  51. package/src/components/Avatar/Avatar.tsx +108 -0
  52. package/src/components/Avatar/USAGE.md +38 -0
  53. package/src/components/Avatar/index.ts +1 -0
  54. package/src/components/Badge/BADGE_IMPLEMENTATION_NOTES.md +18 -0
  55. package/src/components/Badge/Badge.module.css +127 -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 +64 -0
  59. package/src/components/Badge/USAGE.md +56 -0
  60. package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +47 -0
  61. package/src/components/Breadcrumb/Breadcrumb.module.css +48 -0
  62. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +114 -0
  63. package/src/components/Breadcrumb/Breadcrumb.test.tsx +1 -0
  64. package/src/components/Breadcrumb/Breadcrumb.tsx +85 -0
  65. package/src/components/Breadcrumb/USAGE.md +55 -0
  66. package/src/components/Breadcrumb/markCurrentPageItem.test.ts +49 -0
  67. package/src/components/Button/Button.module.css +446 -0
  68. package/src/components/Button/Button.stories.tsx +196 -0
  69. package/src/components/Button/Button.styleIsolation.dom.test.tsx +98 -0
  70. package/src/components/Button/Button.tsx +184 -0
  71. package/src/components/Button/IMPLEMENTATION_NOTES.md +109 -0
  72. package/src/components/Button/USAGE.md +80 -0
  73. package/src/components/Button/index.ts +1 -0
  74. package/src/components/Card/CARD_IMPLEMENTATION_NOTES.md +17 -0
  75. package/src/components/Card/Card.module.css +119 -0
  76. package/src/components/Card/Card.stories.tsx +131 -0
  77. package/src/components/Card/Card.test.tsx +1 -0
  78. package/src/components/Card/Card.tsx +248 -0
  79. package/src/components/Card/USAGE.md +63 -0
  80. package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +25 -0
  81. package/src/components/Checkbox/Checkbox.module.css +267 -0
  82. package/src/components/Checkbox/Checkbox.stories.tsx +97 -0
  83. package/src/components/Checkbox/Checkbox.test.tsx +1 -0
  84. package/src/components/Checkbox/Checkbox.tsx +151 -0
  85. package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
  86. package/src/components/Checkbox/CheckboxGroup.tsx +147 -0
  87. package/src/components/Checkbox/USAGE.md +48 -0
  88. package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +110 -0
  89. package/src/components/Chip/Chip.module.css +288 -0
  90. package/src/components/Chip/Chip.stories.tsx +128 -0
  91. package/src/components/Chip/Chip.test.tsx +1 -0
  92. package/src/components/Chip/Chip.tsx +157 -0
  93. package/src/components/Chip/USAGE.md +55 -0
  94. package/src/components/Container/CONTAINER_IMPLEMENTATION_NOTES.md +4 -0
  95. package/src/components/Container/Container.module.css +7 -0
  96. package/src/components/Container/Container.stories.tsx +118 -0
  97. package/src/components/Container/Container.test.tsx +1 -0
  98. package/src/components/Container/Container.tsx +69 -0
  99. package/src/components/Container/USAGE.md +47 -0
  100. package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +31 -0
  101. package/src/components/DatePicker/DatePicker.icons.tsx +27 -0
  102. package/src/components/DatePicker/DatePicker.module.css +566 -0
  103. package/src/components/DatePicker/DatePicker.stories.tsx +158 -0
  104. package/src/components/DatePicker/DatePicker.test.tsx +1 -0
  105. package/src/components/DatePicker/DatePicker.tsx +218 -0
  106. package/src/components/DatePicker/USAGE.md +49 -0
  107. package/src/components/Dropdown/BareDropdown.tsx +97 -0
  108. package/src/components/Dropdown/DROPDOWN_IMPLEMENTATION_NOTES.md +12 -0
  109. package/src/components/Dropdown/Dropdown.module.css +477 -0
  110. package/src/components/Dropdown/Dropdown.stories.tsx +252 -0
  111. package/src/components/Dropdown/Dropdown.test.tsx +1 -0
  112. package/src/components/Dropdown/Dropdown.tsx +213 -0
  113. package/src/components/Dropdown/USAGE.md +69 -0
  114. package/src/components/FileInput/FILEINPUT_IMPLEMENTATION_NOTES.md +153 -0
  115. package/src/components/FileInput/FileInput.module.css +280 -0
  116. package/src/components/FileInput/FileInput.stories.tsx +313 -0
  117. package/src/components/FileInput/FileInput.test.tsx +1 -0
  118. package/src/components/FileInput/FileInput.tsx +417 -0
  119. package/src/components/FileInput/USAGE.md +145 -0
  120. package/src/components/FileUpload/FILEUPLOAD_IMPLEMENTATION_NOTES.md +244 -0
  121. package/src/components/FileUpload/FileUpload.module.css +205 -0
  122. package/src/components/FileUpload/FileUpload.stories.tsx +362 -0
  123. package/src/components/FileUpload/FileUpload.test.tsx +1 -0
  124. package/src/components/FileUpload/FileUpload.tsx +354 -0
  125. package/src/components/FileUpload/USAGE.md +199 -0
  126. package/src/components/Flex/FLEX_IMPLEMENTATION_NOTES.md +4 -0
  127. package/src/components/Flex/Flex.module.css +7 -0
  128. package/src/components/Flex/Flex.stories.tsx +128 -0
  129. package/src/components/Flex/Flex.test.tsx +1 -0
  130. package/src/components/Flex/Flex.tsx +75 -0
  131. package/src/components/Flex/USAGE.md +48 -0
  132. package/src/components/FormControlLayout/FormControlLayout.module.css +90 -0
  133. package/src/components/FormControlLayout/FormControlLayout.stories.tsx +118 -0
  134. package/src/components/FormControlLayout/FormControlLayout.test.tsx +1 -0
  135. package/src/components/FormControlLayout/FormControlLayout.tsx +74 -0
  136. package/src/components/FormControlLayout/USAGE.md +40 -0
  137. package/src/components/FormControlWrapper/FORMCONTROLWRAPPER_IMPLEMENTATION_NOTES.md +32 -0
  138. package/src/components/FormControlWrapper/FormControlWrapper.module.css +75 -0
  139. package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +129 -0
  140. package/src/components/FormControlWrapper/FormControlWrapper.test.tsx +1 -0
  141. package/src/components/FormControlWrapper/FormControlWrapper.tsx +151 -0
  142. package/src/components/FormControlWrapper/USAGE.md +47 -0
  143. package/src/components/Grid/GRID_IMPLEMENTATION_NOTES.md +18 -0
  144. package/src/components/Grid/Grid.module.css +11 -0
  145. package/src/components/Grid/Grid.stories.tsx +206 -0
  146. package/src/components/Grid/Grid.test.tsx +1 -0
  147. package/src/components/Grid/Grid.tsx +140 -0
  148. package/src/components/Grid/USAGE.md +47 -0
  149. package/src/components/Group/GROUP_IMPLEMENTATION_NOTES.md +4 -0
  150. package/src/components/Group/Group.module.css +7 -0
  151. package/src/components/Group/Group.stories.tsx +120 -0
  152. package/src/components/Group/Group.test.tsx +1 -0
  153. package/src/components/Group/Group.tsx +60 -0
  154. package/src/components/Group/USAGE.md +48 -0
  155. package/src/components/Heading/HEADING_IMPLEMENTATION_NOTES.md +18 -0
  156. package/src/components/Heading/Heading.module.css +13 -0
  157. package/src/components/Heading/Heading.stories.tsx +50 -0
  158. package/src/components/Heading/Heading.test.tsx +1 -0
  159. package/src/components/Heading/Heading.tsx +52 -0
  160. package/src/components/Heading/USAGE.md +36 -0
  161. package/src/components/HoverCard/HOVERCARD_IMPLEMENTATION_NOTES.md +77 -0
  162. package/src/components/HoverCard/HoverCard.module.css +90 -0
  163. package/src/components/HoverCard/HoverCard.stories.tsx +172 -0
  164. package/src/components/HoverCard/HoverCard.test.tsx +1 -0
  165. package/src/components/HoverCard/HoverCard.tsx +133 -0
  166. package/src/components/HoverCard/USAGE.md +52 -0
  167. package/src/components/Label/LABEL_IMPLEMENTATION_NOTES.md +48 -0
  168. package/src/components/Label/Label.module.css +141 -0
  169. package/src/components/Label/Label.stories.tsx +131 -0
  170. package/src/components/Label/Label.test.tsx +1 -0
  171. package/src/components/Label/Label.tsx +113 -0
  172. package/src/components/Label/USAGE.md +47 -0
  173. package/src/components/Label/index.ts +1 -0
  174. package/src/components/Layer/USAGE.md +54 -0
  175. package/src/components/Link/IMPLEMENTATION_NOTES.md +19 -0
  176. package/src/components/Link/Link.module.css +110 -0
  177. package/src/components/Link/Link.stories.tsx +58 -0
  178. package/src/components/Link/Link.test.tsx +1 -0
  179. package/src/components/Link/Link.tsx +67 -0
  180. package/src/components/Link/USAGE.md +56 -0
  181. package/src/components/Link/index.ts +1 -0
  182. package/src/components/Loader/LOADER_IMPLEMENTATION_NOTES.md +24 -0
  183. package/src/components/Loader/Loader.animate.dom.test.tsx +82 -0
  184. package/src/components/Loader/Loader.module.css +63 -0
  185. package/src/components/Loader/Loader.stories.tsx +123 -0
  186. package/src/components/Loader/Loader.test.tsx +1 -0
  187. package/src/components/Loader/Loader.tsx +69 -0
  188. package/src/components/Loader/USAGE.md +44 -0
  189. package/src/components/Menu/MENU_IMPLEMENTATION_NOTES.md +88 -0
  190. package/src/components/Menu/Menu.module.css +280 -0
  191. package/src/components/Menu/Menu.stories.tsx +371 -0
  192. package/src/components/Menu/Menu.test.tsx +1 -0
  193. package/src/components/Menu/Menu.tsx +373 -0
  194. package/src/components/Menu/USAGE.md +55 -0
  195. package/src/components/Modal/MODAL_IMPLEMENTATION_NOTES.md +32 -0
  196. package/src/components/Modal/Modal.module.css +302 -0
  197. package/src/components/Modal/Modal.stories.tsx +105 -0
  198. package/src/components/Modal/Modal.test.tsx +1 -0
  199. package/src/components/Modal/Modal.tsx +368 -0
  200. package/src/components/Modal/USAGE.md +58 -0
  201. package/src/components/Modal/index.ts +1 -0
  202. package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +24 -0
  203. package/src/components/NumberInput/NumberInput.module.css +302 -0
  204. package/src/components/NumberInput/NumberInput.stories.tsx +96 -0
  205. package/src/components/NumberInput/NumberInput.test.tsx +1 -0
  206. package/src/components/NumberInput/NumberInput.tsx +157 -0
  207. package/src/components/NumberInput/USAGE.md +52 -0
  208. package/src/components/Pagination/IMPLEMENTATION_NOTES.md +16 -0
  209. package/src/components/Pagination/Pagination.icons.tsx +66 -0
  210. package/src/components/Pagination/Pagination.module.css +188 -0
  211. package/src/components/Pagination/Pagination.stories.tsx +48 -0
  212. package/src/components/Pagination/Pagination.test.tsx +1 -0
  213. package/src/components/Pagination/Pagination.tsx +265 -0
  214. package/src/components/Pagination/USAGE.md +36 -0
  215. package/src/components/Pagination/index.ts +5 -0
  216. package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +116 -0
  217. package/src/components/Panel/Panel.module.css +209 -0
  218. package/src/components/Panel/Panel.stories.tsx +227 -0
  219. package/src/components/Panel/Panel.test.tsx +1 -0
  220. package/src/components/Panel/Panel.tsx +269 -0
  221. package/src/components/Panel/USAGE.md +56 -0
  222. package/src/components/Popover/IMPLEMENTATION_NOTES.md +77 -0
  223. package/src/components/Popover/Popover.module.css +86 -0
  224. package/src/components/Popover/Popover.stories.tsx +133 -0
  225. package/src/components/Popover/Popover.test.tsx +1 -0
  226. package/src/components/Popover/Popover.tsx +142 -0
  227. package/src/components/Popover/USAGE.md +61 -0
  228. package/src/components/Popover/index.ts +1 -0
  229. package/src/components/Radio/Radio.module.css +231 -0
  230. package/src/components/Radio/Radio.stories.tsx +93 -0
  231. package/src/components/Radio/Radio.test.tsx +1 -0
  232. package/src/components/Radio/Radio.tsx +168 -0
  233. package/src/components/Radio/RadioGroup.stories.tsx +117 -0
  234. package/src/components/Radio/RadioGroup.tsx +124 -0
  235. package/src/components/Radio/USAGE.md +36 -0
  236. package/src/components/ReadOnlyField/READ_ONLY_FIELD_IMPLEMENTATION_NOTES.md +15 -0
  237. package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
  238. package/src/components/ReadOnlyField/ReadOnlyField.module.css +54 -0
  239. package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +163 -0
  240. package/src/components/ReadOnlyField/ReadOnlyField.test.tsx +1 -0
  241. package/src/components/ReadOnlyField/ReadOnlyField.tsx +114 -0
  242. package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
  243. package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
  244. package/src/components/ReadOnlyField/USAGE.md +44 -0
  245. package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
  246. package/src/components/ReadOnlyField/index.ts +5 -0
  247. package/src/components/RecursicaThemeProvider/USAGE.md +60 -0
  248. package/src/components/SegmentedControl/IMPLEMENTATION_NOTES.md +25 -0
  249. package/src/components/SegmentedControl/SegmentedControl.module.css +185 -0
  250. package/src/components/SegmentedControl/SegmentedControl.stories.tsx +106 -0
  251. package/src/components/SegmentedControl/SegmentedControl.test.tsx +1 -0
  252. package/src/components/SegmentedControl/SegmentedControl.tsx +110 -0
  253. package/src/components/SegmentedControl/USAGE.md +55 -0
  254. package/src/components/Slider/IMPLEMENTATION_NOTES.md +92 -0
  255. package/src/components/Slider/Slider.module.css +588 -0
  256. package/src/components/Slider/Slider.stories.tsx +282 -0
  257. package/src/components/Slider/Slider.test.tsx +1 -0
  258. package/src/components/Slider/Slider.tsx +391 -0
  259. package/src/components/Slider/USAGE.md +56 -0
  260. package/src/components/Stack/STACK_IMPLEMENTATION_NOTES.md +4 -0
  261. package/src/components/Stack/Stack.module.css +7 -0
  262. package/src/components/Stack/Stack.stories.tsx +108 -0
  263. package/src/components/Stack/Stack.test.tsx +1 -0
  264. package/src/components/Stack/Stack.tsx +62 -0
  265. package/src/components/Stack/USAGE.md +48 -0
  266. package/src/components/Stepper/IMPLEMENTATION_NOTES.md +28 -0
  267. package/src/components/Stepper/Stepper.module.css +404 -0
  268. package/src/components/Stepper/Stepper.stories.tsx +148 -0
  269. package/src/components/Stepper/Stepper.test.tsx +1 -0
  270. package/src/components/Stepper/Stepper.tsx +93 -0
  271. package/src/components/Stepper/USAGE.md +41 -0
  272. package/src/components/Switch/SWITCH_IMPLEMENTATION_NOTES.md +64 -0
  273. package/src/components/Switch/Switch.module.css +279 -0
  274. package/src/components/Switch/Switch.stories.tsx +114 -0
  275. package/src/components/Switch/Switch.test.tsx +1 -0
  276. package/src/components/Switch/Switch.tsx +177 -0
  277. package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
  278. package/src/components/Switch/SwitchGroup.tsx +127 -0
  279. package/src/components/Switch/USAGE.md +42 -0
  280. package/src/components/Table/TABLE_IMPLEMENTATION_NOTES.md +78 -0
  281. package/src/components/Table/Table.icons.tsx +40 -0
  282. package/src/components/Table/Table.module.css +444 -0
  283. package/src/components/Table/Table.stories.tsx +140 -0
  284. package/src/components/Table/Table.test.tsx +1 -0
  285. package/src/components/Table/Table.tsx +243 -0
  286. package/src/components/Table/USAGE.md +78 -0
  287. package/src/components/Tabs/IMPLEMENTATION_NOTES.md +27 -0
  288. package/src/components/Tabs/Tabs.module.css +591 -0
  289. package/src/components/Tabs/Tabs.stories.tsx +154 -0
  290. package/src/components/Tabs/Tabs.test.tsx +1 -0
  291. package/src/components/Tabs/Tabs.tsx +114 -0
  292. package/src/components/Tabs/USAGE.md +45 -0
  293. package/src/components/Text/TEXT_IMPLEMENTATION_NOTES.md +12 -0
  294. package/src/components/Text/Text.module.css +13 -0
  295. package/src/components/Text/Text.stories.tsx +75 -0
  296. package/src/components/Text/Text.test.tsx +1 -0
  297. package/src/components/Text/Text.tsx +53 -0
  298. package/src/components/Text/USAGE.md +40 -0
  299. package/src/components/TextArea/TEXTAREA_IMPLEMENTATION_NOTES.md +7 -0
  300. package/src/components/TextArea/TextArea.module.css +183 -0
  301. package/src/components/TextArea/TextArea.stories.tsx +94 -0
  302. package/src/components/TextArea/TextArea.test.tsx +1 -0
  303. package/src/components/TextArea/TextArea.tsx +137 -0
  304. package/src/components/TextArea/USAGE.md +48 -0
  305. package/src/components/TextField/TEXTFIELD_IMPLEMENTATION_NOTES.md +19 -0
  306. package/src/components/TextField/TextField.module.css +264 -0
  307. package/src/components/TextField/TextField.stories.tsx +162 -0
  308. package/src/components/TextField/TextField.test.tsx +1 -0
  309. package/src/components/TextField/TextField.tsx +139 -0
  310. package/src/components/TextField/USAGE.md +44 -0
  311. package/src/components/TimePicker/TIMEPICKER_IMPLEMENTATION_NOTES.md +119 -0
  312. package/src/components/TimePicker/TimePicker.module.css +291 -0
  313. package/src/components/TimePicker/TimePicker.stories.tsx +141 -0
  314. package/src/components/TimePicker/TimePicker.test.tsx +1 -0
  315. package/src/components/TimePicker/TimePicker.tsx +304 -0
  316. package/src/components/TimePicker/USAGE.md +57 -0
  317. package/src/components/Timeline/TIMELINE_IMPLEMENTATION_NOTES.md +13 -0
  318. package/src/components/Timeline/Timeline.module.css +373 -0
  319. package/src/components/Timeline/Timeline.stories.tsx +128 -0
  320. package/src/components/Timeline/Timeline.test.tsx +1 -0
  321. package/src/components/Timeline/Timeline.tsx +73 -0
  322. package/src/components/Timeline/TimelineItem.tsx +79 -0
  323. package/src/components/Timeline/USAGE.md +49 -0
  324. package/src/components/Toast/TOAST_IMPLEMENTATION_NOTES.md +39 -0
  325. package/src/components/Toast/Toast.module.css +184 -0
  326. package/src/components/Toast/Toast.stories.tsx +67 -0
  327. package/src/components/Toast/Toast.test.tsx +1 -0
  328. package/src/components/Toast/Toast.tsx +82 -0
  329. package/src/components/Toast/USAGE.md +50 -0
  330. package/src/components/Toast/index.ts +1 -0
  331. package/src/components/Tooltip/TOOLTIP_IMPLEMENTATION_NOTES.md +85 -0
  332. package/src/components/Tooltip/Tooltip.module.css +91 -0
  333. package/src/components/Tooltip/Tooltip.stories.tsx +165 -0
  334. package/src/components/Tooltip/Tooltip.test.tsx +1 -0
  335. package/src/components/Tooltip/Tooltip.tsx +117 -0
  336. package/src/components/Tooltip/USAGE.md +80 -0
  337. package/src/components/TransferList/TRANSFERLIST_IMPLEMENTATION_NOTES.md +111 -0
  338. package/src/components/TransferList/TransferList.module.css +182 -0
  339. package/src/components/TransferList/TransferList.stories.tsx +121 -0
  340. package/src/components/TransferList/TransferList.test.tsx +1 -0
  341. package/src/components/TransferList/TransferList.tsx +419 -0
  342. package/src/components/TransferList/USAGE.md +77 -0
  343. package/src/components/Tree/IMPLEMENTATION_NOTES.md +48 -0
  344. package/src/components/Tree/Tree.module.css +232 -0
  345. package/src/components/Tree/Tree.stories.tsx +104 -0
  346. package/src/components/Tree/Tree.test.tsx +1 -0
  347. package/src/components/Tree/Tree.tsx +220 -0
  348. package/src/components/Tree/USAGE.md +96 -0
  349. package/src/components/Tree/index.ts +1 -0
  350. package/src/components/index.ts +52 -0
  351. package/src/env.d.ts +7 -0
  352. package/src/index.ts +179 -0
  353. package/src/types/index.ts +9 -0
  354. package/src/types/mantine.d.ts +7 -0
  355. package/src/types/scss-modules.d.ts +9 -0
  356. package/src/utils/ColorSchemeWrapper.tsx +27 -0
  357. package/src/utils/RequireAccessibleLabel.ts +1 -0
  358. package/src/utils/copyToClipboard.ts +36 -0
  359. package/src/utils/filterStylingProps.test.ts +85 -0
  360. package/src/utils/filterStylingProps.ts +150 -0
  361. package/src/utils/index.ts +1 -0
  362. package/src/utils/renderRichOption.tsx +65 -0
@@ -0,0 +1,280 @@
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
+ * recursica-allow-brand: --recursica_brand_states_hover_color
8
+ * recursica-allow-brand: --recursica_brand_states_hover_opacity
9
+ */
10
+
11
+ /* EXEMPTIONS:
12
+ - border-size is constant across disabled/error states — only border-color changes; the
13
+ disabled/error border-size tokens are never applied by design. */
14
+ /* recursica-ignore: --recursica_ui-kit_components_file-input_variants_states_disabled_properties_border-size */
15
+ /* recursica-ignore: --recursica_ui-kit_components_file-input_variants_states_error_properties_border-size */
16
+
17
+ /* LAYOUT SPACING OVERRIDES:
18
+ - Sets the --form-control-margin-bottom spacing hook to map component-specific layout tokens.
19
+ - Also sets the --file-input-control-{max,min}-width hooks consumed inline in FileInput.tsx,
20
+ since max-width/min-width are split per layout variant (same shape as TextField). */
21
+ .layoutOverride {
22
+ --form-control-margin-bottom: var(
23
+ --recursica_ui-kit_components_file-input_variants_layouts_stacked_properties_top-bottom-margin
24
+ );
25
+ --file-input-control-max-width: var(
26
+ --recursica_ui-kit_components_file-input_variants_layouts_stacked_properties_max-width
27
+ );
28
+ --file-input-control-min-width: var(
29
+ --recursica_ui-kit_components_file-input_variants_layouts_stacked_properties_min-width
30
+ );
31
+ }
32
+
33
+ .layoutOverride[data-form-layout="side-by-side"] {
34
+ --form-control-margin-bottom: var(
35
+ --recursica_ui-kit_components_file-input_variants_layouts_side-by-side_properties_top-bottom-margin
36
+ );
37
+ --file-input-control-max-width: var(
38
+ --recursica_ui-kit_components_file-input_variants_layouts_side-by-side_properties_max-width
39
+ );
40
+ --file-input-control-min-width: var(
41
+ --recursica_ui-kit_components_file-input_variants_layouts_side-by-side_properties_min-width
42
+ );
43
+ }
44
+
45
+ /* HARDCODED VALUES:
46
+ - border-style: solid. Native structural rendering rule (matches TextField).
47
+ - outline: none. Bypassing the browser focus ring to rely strictly on the state cascade below.
48
+ - .root's cursor/position/overflow: structural, not a design-token concern. */
49
+
50
+ .root {
51
+ display: flex;
52
+ align-items: center;
53
+ position: relative;
54
+ box-sizing: border-box;
55
+ width: 100%;
56
+ max-width: var(--file-input-control-max-width);
57
+ min-width: var(--file-input-control-min-width);
58
+ min-height: var(
59
+ --recursica_ui-kit_components_file-input_properties_min-height
60
+ );
61
+ gap: var(--recursica_ui-kit_components_file-input_properties_icon-text-gap);
62
+ padding-top: var(
63
+ --recursica_ui-kit_components_file-input_properties_vertical-padding
64
+ );
65
+ padding-bottom: var(
66
+ --recursica_ui-kit_components_file-input_properties_vertical-padding
67
+ );
68
+ padding-left: var(
69
+ --recursica_ui-kit_components_file-input_properties_horizontal-padding
70
+ );
71
+ padding-right: var(
72
+ --recursica_ui-kit_components_file-input_properties_horizontal-padding
73
+ );
74
+ border-width: var(
75
+ --recursica_ui-kit_components_file-input_properties_border-size
76
+ );
77
+ border-style: solid;
78
+ border-radius: var(
79
+ --recursica_ui-kit_components_file-input_properties_border-radius
80
+ );
81
+ background-color: var(
82
+ --recursica_ui-kit_components_file-input_properties_colors_background-color
83
+ );
84
+ border-color: var(
85
+ --recursica_ui-kit_components_file-input_properties_colors_border-color
86
+ );
87
+ color: var(
88
+ --recursica_ui-kit_components_file-input_properties_colors_text-color
89
+ );
90
+ cursor: pointer;
91
+ outline: none;
92
+ }
93
+
94
+ .root[data-disabled="true"],
95
+ .root[data-readonly="true"] {
96
+ cursor: default;
97
+ }
98
+
99
+ .root > * {
100
+ position: relative;
101
+ }
102
+
103
+ /* Dragging-over state: reuses the generic hover overlay recipe (see Button.module.css) for the
104
+ background, and the shared "selected" border bridge var FormControlWrapper already exposes —
105
+ file-input has no color tokens of its own for this state. Same recipe as FileUpload's
106
+ dropzone; see "Dragging-over visual state" in FILEINPUT_IMPLEMENTATION_NOTES.md. */
107
+ .root::after {
108
+ content: "";
109
+ position: absolute;
110
+ inset: 0;
111
+ border-radius: inherit;
112
+ z-index: 0;
113
+ pointer-events: none;
114
+ transition: opacity 150ms ease;
115
+ opacity: 0;
116
+ background-color: var(--recursica_brand_states_hover_color);
117
+ }
118
+ .root[data-dragging="true"] {
119
+ border-color: var(--form-field-border-selected);
120
+ }
121
+ .root[data-dragging="true"]::after {
122
+ opacity: var(--recursica_brand_states_hover_opacity);
123
+ }
124
+
125
+ .leadingIcon {
126
+ display: flex;
127
+ flex: none;
128
+ width: var(--recursica_ui-kit_components_file-input_properties_icon-size);
129
+ height: var(--recursica_ui-kit_components_file-input_properties_icon-size);
130
+ color: var(
131
+ --recursica_ui-kit_components_file-input_properties_colors_leading-icon
132
+ );
133
+ }
134
+ .leadingIcon svg {
135
+ width: 100%;
136
+ height: 100%;
137
+ }
138
+
139
+ .content {
140
+ display: flex;
141
+ align-items: center;
142
+ flex: 1 1 auto;
143
+ min-width: 0; /* HARDCODE: lets the value/chip row actually shrink and ellipsize */
144
+ overflow: hidden;
145
+ }
146
+
147
+ .value {
148
+ font-family: var(
149
+ --recursica_ui-kit_components_file-input_properties_text_font-family
150
+ );
151
+ font-size: var(
152
+ --recursica_ui-kit_components_file-input_properties_text_font-size
153
+ );
154
+ font-style: var(
155
+ --recursica_ui-kit_components_file-input_properties_text_font-style
156
+ );
157
+ font-weight: var(
158
+ --recursica_ui-kit_components_file-input_properties_text_font-weight
159
+ );
160
+ letter-spacing: var(
161
+ --recursica_ui-kit_components_file-input_properties_text_letter-spacing
162
+ );
163
+ line-height: var(
164
+ --recursica_ui-kit_components_file-input_properties_text_line-height
165
+ );
166
+ text-decoration: var(
167
+ --recursica_ui-kit_components_file-input_properties_text_text-decoration
168
+ );
169
+ text-transform: var(
170
+ --recursica_ui-kit_components_file-input_properties_text_text-transform
171
+ );
172
+ width: 100%;
173
+ white-space: nowrap;
174
+ text-overflow: ellipsis;
175
+ /* HARDCODE: x-only clipping — clipping y too (plain overflow: hidden) cuts off descenders
176
+ (e.g. the "g" in "image.png"); same fix as Chip.module.css's .children. */
177
+ overflow-x: clip;
178
+ overflow-y: visible;
179
+ }
180
+
181
+ .value[data-placeholder="true"] {
182
+ opacity: var(
183
+ --recursica_ui-kit_components_file-input_properties_placeholder-opacity
184
+ );
185
+ }
186
+
187
+ .chipRow {
188
+ display: flex;
189
+ align-items: center;
190
+ flex-wrap: nowrap;
191
+ /* HARDCODE: x-only scroll — the chip list can exceed the control's own width (more files than
192
+ fit on one line), so it scrolls horizontally within the control instead of wrapping/growing
193
+ it or clipping the overflow away. */
194
+ overflow-x: auto;
195
+ overflow-y: hidden;
196
+ gap: var(--recursica_ui-kit_components_file-input_properties_icon-text-gap);
197
+ /* HARDCODE: scrollbar stays functional (still scrolls via wheel/trackpad/drag) but hidden —
198
+ the control isn't tall enough to host a visible scrollbar without clipping the chips. */
199
+ scrollbar-width: none; /* Firefox */
200
+ -ms-overflow-style: none; /* legacy Edge */
201
+ }
202
+ .chipRow::-webkit-scrollbar {
203
+ display: none; /* Chrome, Safari */
204
+ }
205
+
206
+ .chipWrapper {
207
+ display: flex;
208
+ min-width: 0;
209
+ flex: none;
210
+ }
211
+
212
+ /* Structural placement only — the button's own "text" variant/size="small" tokens (including its
213
+ own disabled state) own its visual appearance, same as Tree's .expandButton. */
214
+ /* EXEMPTIONS:
215
+ - trailing-icon color (base/disabled/error) is ignored — the trailing icon is a nested Button
216
+ that owns its own color tokens per state; FileInput never recolors it directly. */
217
+ /* recursica-ignore: --recursica_ui-kit_components_file-input_properties_colors_trailing-icon */
218
+ /* recursica-ignore: --recursica_ui-kit_components_file-input_variants_states_disabled_properties_colors_trailing-icon */
219
+ /* recursica-ignore: --recursica_ui-kit_components_file-input_variants_states_error_properties_colors_trailing-icon */
220
+ .trailingIcon {
221
+ position: relative;
222
+ z-index: 1;
223
+ flex: none;
224
+ }
225
+
226
+ /* -------------------------------------
227
+ STATE CASCADE ARCHITECTURE
228
+ -------------------------------------- */
229
+
230
+ /* Focus State Mapping (Triggered internally via browser pseudo-class on the root control) */
231
+ /* file-input has no per-component focus colors (see EXEMPTIONS above); apply the generic focus
232
+ ring tokens as a box-shadow ring instead of a color swap (matches TextField/DatePicker). */
233
+ .root:focus-visible {
234
+ box-shadow:
235
+ 0 0 0 var(--recursica_brand_states_focus_border-size)
236
+ var(--recursica_brand_states_focus_color),
237
+ 0 0 var(--recursica_brand_states_focus_blur)
238
+ var(--recursica_brand_states_focus_margin)
239
+ var(--recursica_brand_states_focus_color);
240
+ }
241
+
242
+ /* Error State Mapping (Propagated strictly down from the wrapper DOM context) */
243
+ .root[data-error="true"] {
244
+ border-color: var(
245
+ --recursica_ui-kit_components_file-input_variants_states_error_properties_colors_border-color
246
+ ) !important;
247
+ background-color: var(
248
+ --recursica_ui-kit_components_file-input_variants_states_error_properties_colors_background-color
249
+ ) !important;
250
+ color: var(
251
+ --recursica_ui-kit_components_file-input_variants_states_error_properties_colors_text-color
252
+ ) !important;
253
+ }
254
+ .root[data-error="true"] .leadingIcon {
255
+ color: var(
256
+ --recursica_ui-kit_components_file-input_variants_states_error_properties_colors_leading-icon
257
+ ) !important;
258
+ }
259
+
260
+ /* Disabled State Mapping (Propagated strictly down from the wrapper DOM context) */
261
+ .root[data-disabled="true"] {
262
+ border-color: var(
263
+ --recursica_ui-kit_components_file-input_variants_states_disabled_properties_colors_border-color
264
+ ) !important;
265
+ background-color: var(
266
+ --recursica_ui-kit_components_file-input_variants_states_disabled_properties_colors_background-color
267
+ ) !important;
268
+ color: var(
269
+ --recursica_ui-kit_components_file-input_variants_states_disabled_properties_colors_text-color
270
+ ) !important;
271
+ opacity: var(
272
+ --recursica_ui-kit_components_file-input_variants_states_disabled_properties_opacity
273
+ ) !important;
274
+ cursor: not-allowed;
275
+ }
276
+ .root[data-disabled="true"] .leadingIcon {
277
+ color: var(
278
+ --recursica_ui-kit_components_file-input_variants_states_disabled_properties_colors_leading-icon
279
+ ) !important;
280
+ }
@@ -0,0 +1,313 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import React, { useState } from "react";
3
+ import { FileInput } from "./FileInput";
4
+ import { type RecursicaFileUploadItem } from "@recursica/adapter-common";
5
+ import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
6
+
7
+ function mockFile(name: string, size = 1024) {
8
+ return new File([new Uint8Array(size)], name);
9
+ }
10
+
11
+ const meta: Meta<typeof FileInput> = {
12
+ title: "UI-Kit/FileInput",
13
+ component: FileInput,
14
+ tags: ["autodocs"],
15
+ parameters: {
16
+ docs: {
17
+ description: {
18
+ component: `
19
+ The \`FileInput\` component is a single-line, \`TextField\`-shaped control for choosing files, integrated directly into the \`FormControlWrapper\` architecture. It shares \`FileUpload\`'s selection/validation interface (\`accept\`/\`maxSize\`/\`maxFiles\`, \`readOnly\`) behind a different presentation — every selected file renders as a removable chip in a horizontally scrollable row, and a trailing \`Button\` clears the current selection.
20
+
21
+ ### Examples
22
+ \`\`\`tsx
23
+ <FileInput
24
+ label="Resume"
25
+ files={files}
26
+ onFilesAdded={(added) => setFiles(added.map((file) => ({ file })))}
27
+ onFileRemove={() => setFiles([])}
28
+ />
29
+ \`\`\`
30
+ `,
31
+ },
32
+ },
33
+ },
34
+ argTypes: {
35
+ ...formControlArgTypes,
36
+ accept: {
37
+ control: "text",
38
+ description:
39
+ "Native `accept` attribute for the file picker (e.g. `.pdf,.png`).",
40
+ },
41
+ multiple: {
42
+ control: "boolean",
43
+ description:
44
+ "Whether more than one file can be selected/dropped at once. Defaults to `false`.",
45
+ },
46
+ maxSize: {
47
+ control: "number",
48
+ description: "Maximum size per file, in bytes.",
49
+ },
50
+ maxFiles: {
51
+ control: "number",
52
+ description:
53
+ "Maximum total number of files allowed. Only meaningful when `multiple` is `true`.",
54
+ },
55
+ readOnly: {
56
+ control: "boolean",
57
+ description:
58
+ "Renders `files` as a static, non-interactive display with no clear/remove icons.",
59
+ },
60
+ placeholder: {
61
+ control: "text",
62
+ },
63
+ icon: {
64
+ table: { disable: true },
65
+ },
66
+ clearIcon: {
67
+ table: { disable: true },
68
+ },
69
+ files: {
70
+ table: { disable: true },
71
+ },
72
+ onFilesAdded: {
73
+ table: { disable: true },
74
+ },
75
+ onFileRemove: {
76
+ table: { disable: true },
77
+ },
78
+ onFilesRejected: {
79
+ table: { disable: true },
80
+ },
81
+ },
82
+ };
83
+
84
+ export default meta;
85
+
86
+ type Story = StoryObj<typeof FileInput>;
87
+ type FileInputStoryArgs = React.ComponentProps<typeof FileInput> & {
88
+ withLayer?: boolean;
89
+ layer?: number;
90
+ };
91
+
92
+ export const Default: Story = {
93
+ args: {
94
+ label: "Resume",
95
+ },
96
+ /* eslint-disable @typescript-eslint/no-unused-vars */
97
+ render: function FileInputStory({
98
+ withLayer,
99
+ layer,
100
+ ...args
101
+ }: FileInputStoryArgs) {
102
+ /* eslint-enable @typescript-eslint/no-unused-vars */
103
+ const [files, setFiles] = useState<RecursicaFileUploadItem[]>([]);
104
+ return (
105
+ <FileInput
106
+ {...args}
107
+ files={files}
108
+ onFilesAdded={(added) => setFiles(added.map((file) => ({ file })))}
109
+ onFileRemove={() => setFiles([])}
110
+ />
111
+ );
112
+ },
113
+ };
114
+
115
+ export const WithFile: Story = {
116
+ args: {
117
+ label: "Resume",
118
+ },
119
+ /* eslint-disable @typescript-eslint/no-unused-vars */
120
+ render: function FileInputStory({
121
+ withLayer,
122
+ layer,
123
+ ...args
124
+ }: FileInputStoryArgs) {
125
+ /* eslint-enable @typescript-eslint/no-unused-vars */
126
+ const [files, setFiles] = useState<RecursicaFileUploadItem[]>([
127
+ { file: mockFile("resume.pdf") },
128
+ ]);
129
+ return (
130
+ <FileInput
131
+ {...args}
132
+ files={files}
133
+ onFilesAdded={(added) => setFiles(added.map((file) => ({ file })))}
134
+ onFileRemove={() => setFiles([])}
135
+ />
136
+ );
137
+ },
138
+ };
139
+
140
+ export const MultipleFiles: Story = {
141
+ args: {
142
+ label: "Attachments",
143
+ assistiveText: "Up to 5 files",
144
+ multiple: true,
145
+ },
146
+ /* eslint-disable @typescript-eslint/no-unused-vars */
147
+ render: function FileInputStory({
148
+ withLayer,
149
+ layer,
150
+ ...args
151
+ }: FileInputStoryArgs) {
152
+ /* eslint-enable @typescript-eslint/no-unused-vars */
153
+ const [files, setFiles] = useState<RecursicaFileUploadItem[]>([
154
+ { file: mockFile("document.pdf") },
155
+ { file: mockFile("image.png") },
156
+ { file: mockFile("spreadsheet.xlsx") },
157
+ ]);
158
+ return (
159
+ <FileInput
160
+ {...args}
161
+ files={files}
162
+ onFilesAdded={(added) =>
163
+ setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
164
+ }
165
+ onFileRemove={(id) =>
166
+ setFiles((prev) =>
167
+ prev.filter((item) => (item.id ?? item.file.name) !== id),
168
+ )
169
+ }
170
+ />
171
+ );
172
+ },
173
+ };
174
+
175
+ export const SideBySide: Story = {
176
+ args: {
177
+ label: "Resume",
178
+ assistiveText: "PDF or Word document",
179
+ formLayout: "side-by-side",
180
+ },
181
+ /* eslint-disable @typescript-eslint/no-unused-vars */
182
+ render: function FileInputStory({
183
+ withLayer,
184
+ layer,
185
+ ...args
186
+ }: FileInputStoryArgs) {
187
+ /* eslint-enable @typescript-eslint/no-unused-vars */
188
+ const [files, setFiles] = useState<RecursicaFileUploadItem[]>([]);
189
+ return (
190
+ <FileInput
191
+ {...args}
192
+ files={files}
193
+ onFilesAdded={(added) => setFiles(added.map((file) => ({ file })))}
194
+ onFileRemove={() => setFiles([])}
195
+ />
196
+ );
197
+ },
198
+ };
199
+
200
+ export const Disabled: Story = {
201
+ args: {
202
+ label: "Resume",
203
+ disabled: true,
204
+ },
205
+ /* eslint-disable @typescript-eslint/no-unused-vars */
206
+ render: function FileInputStory({
207
+ withLayer,
208
+ layer,
209
+ ...args
210
+ }: FileInputStoryArgs) {
211
+ /* eslint-enable @typescript-eslint/no-unused-vars */
212
+ const [files] = useState<RecursicaFileUploadItem[]>([
213
+ { file: mockFile("resume.pdf") },
214
+ ]);
215
+ return <FileInput {...args} files={files} />;
216
+ },
217
+ };
218
+
219
+ export const ErrorState: Story = {
220
+ args: {
221
+ label: "Resume",
222
+ error: "A file is required.",
223
+ },
224
+ };
225
+
226
+ export const ReadOnly: Story = {
227
+ args: {
228
+ label: "Attachments",
229
+ assistiveText: "Submitted files cannot be changed",
230
+ multiple: true,
231
+ readOnly: true,
232
+ },
233
+ /* eslint-disable @typescript-eslint/no-unused-vars */
234
+ render: function FileInputStory({
235
+ withLayer,
236
+ layer,
237
+ ...args
238
+ }: FileInputStoryArgs) {
239
+ /* eslint-enable @typescript-eslint/no-unused-vars */
240
+ const [files] = useState<RecursicaFileUploadItem[]>([
241
+ { file: mockFile("document.pdf") },
242
+ { file: mockFile("image.png") },
243
+ ]);
244
+ return <FileInput {...args} files={files} />;
245
+ },
246
+ };
247
+
248
+ // Demonstrates that `accept` isn't just cosmetic on the native file-picker dialog — files that
249
+ // don't match it are rejected the same way whether picked or dropped directly (drag-and-drop
250
+ // bypasses the native `accept` filtering entirely, so this only works because FileInput
251
+ // re-validates it itself, same as FileUpload). Drag a non-.pdf file onto the control to see it
252
+ // switch into its error state with the default `invalidFileTypeMessage`.
253
+ export const AcceptRestriction: Story = {
254
+ args: {
255
+ label: "Resume",
256
+ assistiveText: "Only .pdf files are accepted",
257
+ accept: ".pdf",
258
+ },
259
+ /* eslint-disable @typescript-eslint/no-unused-vars */
260
+ render: function FileInputStory({
261
+ withLayer,
262
+ layer,
263
+ ...args
264
+ }: FileInputStoryArgs) {
265
+ /* eslint-enable @typescript-eslint/no-unused-vars */
266
+ const [files, setFiles] = useState<RecursicaFileUploadItem[]>([]);
267
+ return (
268
+ <FileInput
269
+ {...args}
270
+ files={files}
271
+ onFilesAdded={(added) => setFiles(added.map((file) => ({ file })))}
272
+ onFileRemove={() => setFiles([])}
273
+ />
274
+ );
275
+ },
276
+ };
277
+
278
+ // Demonstrates `maxFiles` in multiple-file mode: already at the 2-file cap below, so
279
+ // dropping/picking another file is rejected with the default `maxFilesMessage`.
280
+ export const MaxFilesRestriction: Story = {
281
+ args: {
282
+ label: "Attachments",
283
+ assistiveText: "Up to 2 files allowed",
284
+ multiple: true,
285
+ maxFiles: 2,
286
+ },
287
+ /* eslint-disable @typescript-eslint/no-unused-vars */
288
+ render: function FileInputStory({
289
+ withLayer,
290
+ layer,
291
+ ...args
292
+ }: FileInputStoryArgs) {
293
+ /* eslint-enable @typescript-eslint/no-unused-vars */
294
+ const [files, setFiles] = useState<RecursicaFileUploadItem[]>([
295
+ { file: mockFile("document.pdf") },
296
+ { file: mockFile("image.png") },
297
+ ]);
298
+ return (
299
+ <FileInput
300
+ {...args}
301
+ files={files}
302
+ onFilesAdded={(added) =>
303
+ setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
304
+ }
305
+ onFileRemove={(id) =>
306
+ setFiles((prev) =>
307
+ prev.filter((item) => (item.id ?? item.file.name) !== id),
308
+ )
309
+ }
310
+ />
311
+ );
312
+ },
313
+ };
@@ -0,0 +1 @@
1
+ // Placeholder for future FileInput component tests. Add tests here if/when needed.