@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,232 @@
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_disabled
4
+ * recursica-allow-brand: --recursica_brand_states_focus_blur
5
+ * recursica-allow-brand: --recursica_brand_states_focus_border-size
6
+ * recursica-allow-brand: --recursica_brand_states_focus_color
7
+ * recursica-allow-brand: --recursica_brand_states_focus_margin
8
+ * recursica-allow-brand: --recursica_brand_states_hover_color
9
+ * recursica-allow-brand: --recursica_brand_states_hover_opacity
10
+ */
11
+
12
+ /* HARDCODED VALUES:
13
+ * - list-style/margin/padding resets on .root/.subtree: layout resets, no corresponding
14
+ * design tokens (structural, not visual design values).
15
+ * - .expandGlyph's rotation transition (150ms ease): no dedicated timing token exists for Tree;
16
+ * the glyph itself is sized/colored entirely by Button's own "text"/"small" tokens now, not a
17
+ * hand-drawn size/color like the previous plain-SVG implementation.
18
+ * - Hover overlay uses the generic --recursica_brand_states_hover_* tokens (same technique as
19
+ * Menu/Accordion/Button): Tree has no component-specific hover tokens of its own.
20
+ *
21
+ * NOTE: the row's box model (padding/border/font/color/background) lives entirely on `.label`,
22
+ * not `.row` — the highlighted "chip" (hover/selected/focus) covers only the label, never the
23
+ * expand button. `.row` itself is a plain flex layout container (indentation + button-node-gap).
24
+ */
25
+
26
+ .root {
27
+ margin: 0;
28
+ padding: 0;
29
+ list-style: none;
30
+ max-width: var(--recursica_ui-kit_components_tree_properties_max-width);
31
+ display: flex;
32
+ flex-direction: column;
33
+ gap: var(--recursica_ui-kit_components_tree_properties_item-gap);
34
+
35
+ /* Mantine computes each node's --label-offset (per-level indent) from --level-offset via its
36
+ own internal vars resolver (same category of override as Timeline's --mantine-spacing-xl /
37
+ --tl-line-width). Use !important to reliably beat Mantine's own generated rule. */
38
+ --level-offset: var(
39
+ --recursica_ui-kit_components_tree_properties_indent
40
+ ) !important;
41
+ }
42
+
43
+ /* Whole-tree `disabled` (no per-node concept — see RecursicaTreeProps.ts). `pointer-events: none`
44
+ blocks every mouse interaction tree-wide in one rule (row clicks, chevron clicks); keyboard is
45
+ separately blocked in Tree.tsx, since pointer-events has no effect on Tab/Enter/Space/arrows.
46
+ Uses the generic disabled opacity token, same convention as every other disabled component in
47
+ the design system (no tree-specific disabled token exists). */
48
+ .root[data-disabled] {
49
+ opacity: var(--recursica_brand_states_disabled);
50
+ pointer-events: none;
51
+ }
52
+
53
+ .subtree {
54
+ margin: 0;
55
+ padding: 0;
56
+ list-style: none;
57
+ display: flex;
58
+ flex-direction: column;
59
+ gap: var(--recursica_ui-kit_components_tree_properties_item-gap);
60
+ }
61
+
62
+ .node {
63
+ /* Mantine's own base class already resets margin/padding/list-style and sets cursor:pointer
64
+ on this <li>; it also holds the subtree as a second child, so all node-level visual styling
65
+ (box model, colors, typography) lives on .label instead, not here. */
66
+ position: relative;
67
+ }
68
+
69
+ /* Mantine's roving-tabindex keyboard navigation (arrow up/down moves focus between rows, left/
70
+ right expand/collapse, matching the WAI-ARIA treeitem pattern) already works out of the box —
71
+ but with no visible indicator, it looked broken. DOM focus lands on this <li> (.node), not the
72
+ visible row box, so the ring is drawn on .label instead — the "node" content area, deliberately
73
+ excluding the expand Button, which never shows a focus state of its own (it's not independently
74
+ focusable at all: tabIndex={-1}). */
75
+ .node:focus-visible {
76
+ outline: none;
77
+ }
78
+ /* `> .row` (child combinator), not a plain descendant selector: a node's own `.row` is always a
79
+ direct child of its `.node` <li>, while every descendant node's `.row` (inside the nested
80
+ `.subtree` <ul>) is not — without the `>`, focusing a parent node drew the ring on every
81
+ expanded descendant's label too, since they're all still descendants of the focused `.node`. */
82
+ .node:focus-visible > .row .label {
83
+ box-shadow:
84
+ 0 0 0 var(--recursica_brand_states_focus_border-size)
85
+ var(--recursica_brand_states_focus_color),
86
+ 0 0 var(--recursica_brand_states_focus_blur)
87
+ var(--recursica_brand_states_focus_margin)
88
+ var(--recursica_brand_states_focus_color);
89
+ }
90
+
91
+ .row {
92
+ position: relative;
93
+ box-sizing: border-box;
94
+ display: flex;
95
+ align-items: center;
96
+ cursor: pointer;
97
+ margin-left: var(--label-offset, 0px);
98
+ gap: var(--recursica_ui-kit_components_tree_properties_button-node-gap);
99
+ }
100
+
101
+ /* The expand Button is always rendered (even for leaf nodes, which have nothing to toggle) so
102
+ every row reserves identical layout space — hidden via visibility (not display) on leaf rows so
103
+ the label stays aligned across the whole tree without duplicating Button's own size tokens. */
104
+ .expandButton {
105
+ position: relative;
106
+ z-index: 1;
107
+ flex-shrink: 0;
108
+ }
109
+ .row:not([data-has-children]) .expandButton {
110
+ visibility: hidden;
111
+ }
112
+
113
+ .expandGlyph {
114
+ color: inherit;
115
+ }
116
+ .row[data-has-children] .expandGlyph {
117
+ transition: transform 150ms ease;
118
+ }
119
+ .row[data-expanded] .expandGlyph {
120
+ transform: rotate(90deg);
121
+ }
122
+
123
+ .label {
124
+ position: relative;
125
+ z-index: 1;
126
+ /* Sized to its own content, not stretched to fill the row's remaining width — the
127
+ hover/selected/focus "chip" should cover just the label, not the full row width. */
128
+ flex: 0 1 auto;
129
+ box-sizing: border-box;
130
+ display: flex;
131
+ align-items: center;
132
+ padding: var(--recursica_ui-kit_components_tree_properties_vertical-padding)
133
+ var(--recursica_ui-kit_components_tree_properties_horizontal-padding);
134
+ border-style: solid; /* HARDCODE: structural border rule; thickness/color are tokened */
135
+ border-width: var(--recursica_ui-kit_components_tree_properties_border-size);
136
+ border-radius: var(
137
+ --recursica_ui-kit_components_tree_properties_border-radius
138
+ );
139
+
140
+ font-family: var(
141
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-family
142
+ );
143
+ font-size: var(
144
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-size
145
+ );
146
+ font-style: var(
147
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-style
148
+ );
149
+ font-weight: var(
150
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_font-weight
151
+ );
152
+ letter-spacing: var(
153
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_letter-spacing
154
+ );
155
+ line-height: var(
156
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_line-height
157
+ );
158
+ text-decoration: var(
159
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_text-decoration
160
+ );
161
+ text-transform: var(
162
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_text_text-transform
163
+ );
164
+
165
+ color: var(
166
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_colors_text-color
167
+ );
168
+ background-color: var(
169
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_colors_background-color
170
+ );
171
+ border-color: var(
172
+ --recursica_ui-kit_components_tree_variants_selection-states_unselected_properties_colors_border-color
173
+ );
174
+ }
175
+
176
+ /* Hover overlay via ::after pseudo-element (same technique as Menu/Accordion), scoped to the
177
+ label's own box so hover never visually covers the expand button. `.label`'s `position:
178
+ relative` + `z-index: 1` above already forms a stacking context, so `z-index: -1` here paints
179
+ the overlay behind the label's real text content within that context, not behind `.label`
180
+ itself. */
181
+ .label::after {
182
+ content: "";
183
+ position: absolute;
184
+ inset: 0;
185
+ border-radius: inherit;
186
+ z-index: -1;
187
+ pointer-events: none;
188
+ background-color: var(--recursica_brand_states_hover_color);
189
+ opacity: 0;
190
+ transition: opacity 150ms ease;
191
+ }
192
+ .row:hover .label::after,
193
+ .row[data-hovered] .label::after {
194
+ opacity: var(--recursica_brand_states_hover_opacity);
195
+ }
196
+
197
+ .label[data-selected] {
198
+ font-family: var(
199
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-family
200
+ );
201
+ font-size: var(
202
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-size
203
+ );
204
+ font-style: var(
205
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-style
206
+ );
207
+ font-weight: var(
208
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_font-weight
209
+ );
210
+ letter-spacing: var(
211
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_letter-spacing
212
+ );
213
+ line-height: var(
214
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_line-height
215
+ );
216
+ text-decoration: var(
217
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_text-decoration
218
+ );
219
+ text-transform: var(
220
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_text_text-transform
221
+ );
222
+
223
+ color: var(
224
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_colors_text-color
225
+ );
226
+ background-color: var(
227
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_colors_background-color
228
+ );
229
+ border-color: var(
230
+ --recursica_ui-kit_components_tree_variants_selection-states_selected_properties_colors_border-color
231
+ );
232
+ }
@@ -0,0 +1,104 @@
1
+ import type { Meta, StoryObj } from "@storybook/react";
2
+ import { Tree } from "./Tree";
3
+ import { Layer, type RecursicaTreeNode } from "@recursica/adapter-common";
4
+
5
+ const sampleData: RecursicaTreeNode[] = [
6
+ {
7
+ value: "documents",
8
+ label: "Documents",
9
+ children: [
10
+ { value: "documents/resume.pdf", label: "resume.pdf" },
11
+ { value: "documents/cover-letter.docx", label: "cover-letter.docx" },
12
+ {
13
+ value: "documents/taxes",
14
+ label: "Taxes",
15
+ children: [
16
+ { value: "documents/taxes/2023.pdf", label: "2023.pdf" },
17
+ { value: "documents/taxes/2024.pdf", label: "2024.pdf" },
18
+ ],
19
+ },
20
+ ],
21
+ },
22
+ {
23
+ value: "photos",
24
+ label: "Photos",
25
+ children: [
26
+ { value: "photos/vacation.jpg", label: "vacation.jpg" },
27
+ { value: "photos/family.jpg", label: "family.jpg" },
28
+ ],
29
+ },
30
+ { value: "readme.md", label: "readme.md" },
31
+ ];
32
+
33
+ const meta: Meta<typeof Tree> = {
34
+ title: "UI-Kit/Tree",
35
+ component: Tree,
36
+ tags: ["autodocs"],
37
+ parameters: {
38
+ docs: {
39
+ description: {
40
+ component: `
41
+ The \`Tree\` component renders hierarchical \`data\` as an expandable/selectable tree, wrapping \`@mantine/core\`'s \`Tree\` with a fully custom node renderer so every visual property (row box model, selected/unselected colors and typography, indent, item spacing) comes from Recursica's \`tree\` design tokens.
42
+
43
+ Each node needs a unique \`value\` and a \`label\`; a \`children\` array (even empty) makes a node expandable.
44
+ `,
45
+ },
46
+ },
47
+ },
48
+ };
49
+
50
+ export default meta;
51
+
52
+ export const Default: StoryObj<typeof Tree> = {
53
+ render: () => (
54
+ <Tree data={sampleData} initialExpandedValues={["documents"]} />
55
+ ),
56
+ };
57
+
58
+ export const AllExpanded: StoryObj<typeof Tree> = {
59
+ render: () => <Tree data={sampleData} initialExpandedValues="*" />,
60
+ };
61
+
62
+ export const PreSelected: StoryObj<typeof Tree> = {
63
+ render: () => (
64
+ <Tree
65
+ data={sampleData}
66
+ initialExpandedValues={["documents"]}
67
+ initialSelectedValues={["documents/resume.pdf"]}
68
+ />
69
+ ),
70
+ };
71
+
72
+ export const MultipleSelection: StoryObj<typeof Tree> = {
73
+ render: () => (
74
+ <Tree
75
+ data={sampleData}
76
+ initialExpandedValues="*"
77
+ initialSelectedValues={["documents/resume.pdf", "photos/vacation.jpg"]}
78
+ multiple
79
+ />
80
+ ),
81
+ };
82
+
83
+ /** Whole tree disabled, with a node pre-selected so the selected chip's styling under the
84
+ * disabled dimming can be checked alongside unselected rows. */
85
+ export const Disabled: StoryObj<typeof Tree> = {
86
+ render: () => (
87
+ <Tree
88
+ data={sampleData}
89
+ initialExpandedValues={["documents"]}
90
+ initialSelectedValues={["documents/resume.pdf"]}
91
+ disabled
92
+ />
93
+ ),
94
+ };
95
+
96
+ /** Demonstrates the component nested inside a non-default layer — the one case where an
97
+ * explicit `<Layer>` wrap belongs in a story (see COMPONENT_STORYBOOK_GUIDE.md §9). */
98
+ export const LayerOne: StoryObj<typeof Tree> = {
99
+ render: () => (
100
+ <Layer layer={1} style={{ padding: "24px" }}>
101
+ <Tree data={sampleData} initialExpandedValues={["documents"]} />
102
+ </Layer>
103
+ ),
104
+ };
@@ -0,0 +1 @@
1
+ // Placeholder for future Tree component tests. Add tests here if/when needed.
@@ -0,0 +1,220 @@
1
+ import React, { forwardRef, useEffect } from "react";
2
+ import {
3
+ Tree as MantineTree,
4
+ useTree,
5
+ getTreeExpandedState,
6
+ type RenderTreeNodePayload,
7
+ } from "@mantine/core";
8
+ import { useMergedRef } from "@mantine/hooks";
9
+ import {
10
+ filterStylingProps,
11
+ mergeClassNames,
12
+ type RecursicaOverStyled,
13
+ } from "../../utils/filterStylingProps";
14
+ import { type RecursicaTreeProps } from "@recursica/adapter-common";
15
+ import { Button } from "../Button/Button";
16
+ import styles from "./Tree.module.css";
17
+
18
+ export type TreeProps = RecursicaOverStyled<
19
+ RecursicaTreeProps & Omit<React.ComponentPropsWithoutRef<"ul">, "children">
20
+ >;
21
+
22
+ /** Simple chevron glyph; rotates via the row's `[data-expanded]` in CSS (`.row[data-expanded]
23
+ * .expandGlyph`) — this reaches the glyph regardless of how deeply `Button` nests it internally,
24
+ * since it's a plain descendant-combinator selector, not dependent on Button's own DOM structure.
25
+ * Uses `currentColor` so it always matches Button's own tokened icon color for the "text" variant. */
26
+ function ExpandGlyph() {
27
+ return (
28
+ <svg
29
+ className={styles.expandGlyph}
30
+ viewBox="0 0 16 16"
31
+ width="1em"
32
+ height="1em"
33
+ fill="none"
34
+ stroke="currentColor"
35
+ strokeWidth="2"
36
+ strokeLinecap="round"
37
+ strokeLinejoin="round"
38
+ aria-hidden="true"
39
+ >
40
+ <path d="M5 3l5 5-5 5" />
41
+ </svg>
42
+ );
43
+ }
44
+
45
+ /** Curried so the fixed-shape `renderNode` callback (Mantine controls its signature) can still
46
+ * close over `disabled`, which isn't part of `RenderTreeNodePayload`. */
47
+ function createRenderTreeNode(disabled: boolean) {
48
+ return function renderTreeNode({
49
+ node,
50
+ hasChildren,
51
+ expanded,
52
+ selected,
53
+ tree,
54
+ elementProps,
55
+ }: RenderTreeNodePayload) {
56
+ return (
57
+ <div
58
+ {...elementProps}
59
+ className={styles.row}
60
+ data-has-children={hasChildren || undefined}
61
+ data-expanded={hasChildren && expanded ? true : undefined}
62
+ >
63
+ {/* The only element that toggles expand/collapse on click — independent of selection,
64
+ which `elementProps.onClick` (spread onto `.row` above) handles for the rest of the
65
+ row. Stops propagation so the click never also reaches `.row`'s own handler and
66
+ selects the node. Never independently focusable/tab-stoppable (tabIndex={-1},
67
+ aria-hidden), so the row stays the only focusable element and this button never
68
+ shows its own focus state. `onMouseDown` prevents the browser's default
69
+ click-focuses-the-button behavior (tabIndex={-1} only removes it from the tab
70
+ order, it doesn't stop a direct mouse click from focusing it) — without this, a
71
+ click here leaves the (aria-hidden) button focused, which browsers now flag as an
72
+ accessibility violation ("focus must not be hidden from assistive technology").
73
+ Always rendered, even for leaf nodes, so every row reserves the same layout space;
74
+ CSS hides it (visibility, not display) when there are no children to toggle. Guards
75
+ `disabled` itself (not just via the CSS `pointer-events: none` on `.root`) since this
76
+ handler bypasses Mantine's own `expandOnClick`/`selectOnClick` flags entirely by
77
+ calling `tree.toggleExpanded` directly. */}
78
+ <Button
79
+ overStyled
80
+ variant="text"
81
+ size="small"
82
+ icon={<ExpandGlyph />}
83
+ aria-label="Toggle subtree"
84
+ aria-hidden="true"
85
+ tabIndex={-1}
86
+ className={styles.expandButton}
87
+ onMouseDown={(event) => event.preventDefault()}
88
+ onClick={(event) => {
89
+ event.stopPropagation();
90
+ if (disabled) return;
91
+ tree.toggleExpanded(node.value);
92
+ }}
93
+ />
94
+ <span className={styles.label} data-selected={selected || undefined}>
95
+ {node.label}
96
+ </span>
97
+ </div>
98
+ );
99
+ };
100
+ }
101
+
102
+ /**
103
+ * Recursively renders hierarchical `data` as an expandable/selectable tree.
104
+ *
105
+ * **Recursica Abstract:**
106
+ * Wraps Mantine's `Tree` with a fully custom node renderer so every visual aspect (row box
107
+ * model, selected/unselected colors and typography, indent, item spacing) comes from
108
+ * Recursica's `tree` design tokens rather than Mantine's defaults.
109
+ *
110
+ * **Interaction pattern (fixed, not prop-configurable):** expand/collapse and select are
111
+ * independent — the chevron button toggles a node's subtree only, clicking the rest of a row
112
+ * (or pressing `Enter`/`Space`) selects it only, and `ArrowLeft`/`ArrowRight` toggle expansion
113
+ * only. See `RecursicaTreeProps` for the full breakdown.
114
+ */
115
+ export const Tree = forwardRef<HTMLUListElement, TreeProps>(function Tree(
116
+ {
117
+ overStyled = false,
118
+ data,
119
+ initialExpandedValues,
120
+ initialSelectedValues,
121
+ multiple = false,
122
+ disabled = false,
123
+ onNodeExpand,
124
+ onNodeCollapse,
125
+ onSelectedChange,
126
+ ...rest
127
+ },
128
+ ref,
129
+ ) {
130
+ const sanitizedProps = filterStylingProps(rest, overStyled);
131
+
132
+ const tree = useTree({
133
+ initialExpandedState: initialExpandedValues
134
+ ? getTreeExpandedState(data, initialExpandedValues)
135
+ : undefined,
136
+ initialSelectedState: initialSelectedValues,
137
+ multiple,
138
+ onNodeExpand,
139
+ onNodeCollapse,
140
+ });
141
+
142
+ // Mantine's `useTree` tracks selection internally but has no `onSelectedChange` callback of
143
+ // its own; surface one at the Recursica layer by watching the controller's selectedState.
144
+ useEffect(() => {
145
+ onSelectedChange?.(tree.selectedState);
146
+ }, [tree.selectedState, onSelectedChange]);
147
+
148
+ // `Enter`/`Space` select the focused node. Mantine's own `TreeNode` only wires this for
149
+ // `Space`, and only as an expand toggle (`expandOnSpace`, disabled below) — it has no
150
+ // select-on-key behavior and no `Enter` handling at all, and its key handler lives on the
151
+ // `<li role="treeitem">` itself (not reachable through `renderNode`'s `elementProps`), so this
152
+ // is added as a native listener on the tree root instead. `tree.select` is referentially
153
+ // stable (Mantine wraps it in `useCallback` with no deps), so this effect only re-runs when
154
+ // `disabled` actually changes.
155
+ const rootRef = React.useRef<HTMLUListElement>(null);
156
+ useEffect(() => {
157
+ const root = rootRef.current;
158
+ if (!root) return;
159
+ const handleKeyDown = (event: KeyboardEvent) => {
160
+ if (disabled) return;
161
+ if (event.key !== "Enter" && event.key !== " ") return;
162
+ const treeItem = (event.target as HTMLElement).closest<HTMLElement>(
163
+ '[role="treeitem"]',
164
+ );
165
+ const value = treeItem?.dataset.value;
166
+ if (!value) return;
167
+ event.preventDefault();
168
+ tree.select(value);
169
+ };
170
+ root.addEventListener("keydown", handleKeyDown);
171
+ return () => root.removeEventListener("keydown", handleKeyDown);
172
+ // eslint-disable-next-line react-hooks/exhaustive-deps
173
+ }, [tree.select, disabled]);
174
+
175
+ // When disabled, block every keydown at the capture phase — before it can reach either the
176
+ // listener above or Mantine's own internal per-node keydown handling (`ArrowLeft`/`ArrowRight`
177
+ // expand/collapse, baked into `TreeNode` itself with no prop to disable it). A capture-phase
178
+ // `stopPropagation` here keeps the event from ever reaching its target, so neither listener
179
+ // fires — this is the only reachable way to block Mantine's internal handling for a component
180
+ // with no `disabled` concept of its own. Mouse clicks are separately blocked via `pointer-
181
+ // events: none` in CSS (`.root[data-disabled]`); this effect only needs to cover keyboard.
182
+ useEffect(() => {
183
+ const root = rootRef.current;
184
+ if (!root || !disabled) return;
185
+ const blockAllKeydown = (event: KeyboardEvent) => {
186
+ event.preventDefault();
187
+ event.stopPropagation();
188
+ };
189
+ root.addEventListener("keydown", blockAllKeydown, { capture: true });
190
+ return () =>
191
+ root.removeEventListener("keydown", blockAllKeydown, { capture: true });
192
+ }, [disabled]);
193
+ const mergedRef = useMergedRef(ref, rootRef);
194
+
195
+ const restRecord = sanitizedProps as Record<string, unknown>;
196
+ const classNameProp = restRecord.className as string | undefined;
197
+ const rootClass = classNameProp
198
+ ? `${styles.root} ${classNameProp}`
199
+ : styles.root;
200
+
201
+ return (
202
+ <MantineTree
203
+ ref={mergedRef}
204
+ {...(sanitizedProps as unknown as Record<string, unknown>)}
205
+ data={data}
206
+ tree={tree}
207
+ expandOnClick={false}
208
+ selectOnClick={!disabled}
209
+ expandOnSpace={false}
210
+ renderNode={createRenderTreeNode(disabled)}
211
+ data-disabled={disabled || undefined}
212
+ classNames={mergeClassNames(
213
+ { root: rootClass, node: styles.node, subtree: styles.subtree },
214
+ restRecord.classNames as Partial<Record<string, string>> | undefined,
215
+ )}
216
+ />
217
+ );
218
+ });
219
+
220
+ Tree.displayName = "Tree";
@@ -0,0 +1,96 @@
1
+ # Tree - Usage Guide
2
+
3
+ This document describes how to integrate and use the `Tree` component in your projects using `@recursica/adapter-mantine-v8`.
4
+
5
+ ---
6
+
7
+ ## 1. Import Reference
8
+
9
+ ```tsx
10
+ import { Tree } from "@recursica/adapter-mantine-v8";
11
+ ```
12
+
13
+ ---
14
+
15
+ ## 2. Basic Example
16
+
17
+ ```tsx
18
+ import React from "react";
19
+ import { Tree } from "@recursica/adapter-mantine-v8";
20
+
21
+ export default function Demo() {
22
+ return (
23
+ <Tree
24
+ data={[
25
+ {
26
+ value: "1",
27
+ label: "Root",
28
+ children: [
29
+ { value: "1.1", label: "Child A" },
30
+ { value: "1.2", label: "Child B" },
31
+ ],
32
+ },
33
+ { value: "2", label: "Sibling" },
34
+ ]}
35
+ />
36
+ );
37
+ }
38
+ ```
39
+
40
+ Each node needs a unique `value` and a `label`. Any node with a `children` array (even an empty one) renders an expand/collapse chevron.
41
+
42
+ ---
43
+
44
+ ## 3. Controlled Selection / Expansion
45
+
46
+ ```tsx
47
+ <Tree
48
+ data={data}
49
+ initialExpandedValues={["1"]}
50
+ initialSelectedValues={["1.1"]}
51
+ multiple
52
+ onSelectedChange={(values) => console.log("selected:", values)}
53
+ onNodeExpand={(value) => console.log("expanded:", value)}
54
+ onNodeCollapse={(value) => console.log("collapsed:", value)}
55
+ />
56
+ ```
57
+
58
+ - `initialExpandedValues` accepts an array of node values, or `"*"` to start with every node expanded.
59
+ - `multiple` allows more than one node to be selected at once (default: single-select).
60
+
61
+ ### Interaction pattern
62
+
63
+ Expanding/collapsing and selecting are independent, fixed interactions (not prop-configurable):
64
+
65
+ - Clicking the expand/collapse chevron toggles that node's subtree only — it never selects.
66
+ - Clicking anywhere else on a row selects it — it never toggles expansion.
67
+ - `Enter`/`Space` on a focused node selects it, even if the node has children.
68
+ - `ArrowLeft`/`ArrowRight` expand/collapse the focused node only, without changing selection.
69
+ - `ArrowUp`/`ArrowDown` move focus between rows.
70
+
71
+ ### Disabled
72
+
73
+ ```tsx
74
+ <Tree data={data} initialSelectedValues={["1.1"]} disabled />
75
+ ```
76
+
77
+ `disabled` disables the whole tree — no expand/collapse or select via click or keyboard, dimmed to the standard disabled opacity. A pre-selected node stays visibly selected, just dimmed along with the rest. There's no per-node disabled state (see **Known Constraints** below).
78
+
79
+ ---
80
+
81
+ ## 4. Design System Integration
82
+
83
+ All Recursica components in the `@recursica/adapter-mantine-v8` package adhere strictly to design system spacing, scaling, and behavior patterns.
84
+
85
+ > [!IMPORTANT]
86
+ >
87
+ > - **Anti-override protection**: Rogue style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
88
+ > - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
89
+ > - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
90
+
91
+ ---
92
+
93
+ ## 5. Known Constraints
94
+
95
+ - No checkbox/multi-check styling is exposed — the underlying Mantine `Tree` supports a `checked` node state, but Recursica's `tree` design tokens don't yet define a checked visual state, so it isn't part of the Recursica API.
96
+ - No per-node `disabled` state — the Figma UI Kit tokens don't define one, and Mantine's `Tree` data shape has no built-in `disabled` field either.
@@ -0,0 +1 @@
1
+ export * from "./Tree";