@recursica/adapter-mui-v7 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.storybook/commonArgTypes.ts +148 -0
- package/ARCHITECTURE.md +18 -0
- package/CHANGELOG.md +582 -0
- package/LICENSE +21 -0
- package/OVERSTYLING.md +59 -0
- package/README.md +70 -0
- package/SETUP.md +92 -0
- package/USAGE.md +57 -0
- package/dist/adapter-mui-v7.cjs +292 -0
- package/dist/adapter-mui-v7.cjs.map +1 -0
- package/dist/adapter-mui-v7.css +1 -0
- package/dist/adapter-mui-v7.js +40757 -0
- package/dist/adapter-mui-v7.js.map +1 -0
- package/dist/index.d.ts +2350 -0
- package/dist/vite.svg +1 -0
- package/docs/PHILOSOPHY.md +39 -0
- package/llms.txt +76 -0
- package/package.json +151 -0
- package/recursica_brand.json +2677 -0
- package/recursica_tokens.json +799 -0
- package/recursica_ui-kit.json +14981 -0
- package/recursica_variables_scoped.css +30489 -0
- package/src/GlobalExemptions.modules.css +7 -0
- package/src/Introduction.stories.tsx +184 -0
- package/src/OverStyling.tsx +87 -0
- package/src/Version.tsx +37 -0
- package/src/components/Accordion/ACCORDION_IMPLEMENTATION_NOTES.md +107 -0
- package/src/components/Accordion/Accordion.module.css +362 -0
- package/src/components/Accordion/Accordion.stories.tsx +198 -0
- package/src/components/Accordion/Accordion.test.tsx +1 -0
- package/src/components/Accordion/Accordion.tsx +285 -0
- package/src/components/Accordion/USAGE.md +43 -0
- package/src/components/Accordion/index.ts +1 -0
- package/src/components/AssistiveElement/ASSISTIVEELEMENT_IMPLEMENTATION_NOTES.md +59 -0
- package/src/components/AssistiveElement/AssistiveElement.module.css +121 -0
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +68 -0
- package/src/components/AssistiveElement/AssistiveElement.test.tsx +1 -0
- package/src/components/AssistiveElement/AssistiveElement.tsx +94 -0
- package/src/components/AssistiveElement/USAGE.md +36 -0
- package/src/components/AssistiveElement/index.ts +1 -0
- package/src/components/AutoComplete/AutoComplete.module.css +456 -0
- package/src/components/AutoComplete/AutoComplete.stories.tsx +336 -0
- package/src/components/AutoComplete/AutoComplete.test.tsx +1 -0
- package/src/components/AutoComplete/AutoComplete.tsx +266 -0
- package/src/components/AutoComplete/IMPLEMENTATION_NOTES.md +37 -0
- package/src/components/AutoComplete/USAGE.md +68 -0
- package/src/components/AutoComplete/index.ts +1 -0
- package/src/components/Avatar/AVATAR_IMPLEMENTATION_NOTES.md +36 -0
- package/src/components/Avatar/Avatar.module.css +336 -0
- package/src/components/Avatar/Avatar.stories.tsx +92 -0
- package/src/components/Avatar/Avatar.test.tsx +1 -0
- package/src/components/Avatar/Avatar.tsx +88 -0
- package/src/components/Avatar/USAGE.md +38 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/Badge/Badge.module.css +115 -0
- package/src/components/Badge/Badge.stories.tsx +78 -0
- package/src/components/Badge/Badge.test.tsx +1 -0
- package/src/components/Badge/Badge.tsx +61 -0
- package/src/components/Badge/USAGE.md +40 -0
- package/src/components/Badge/index.ts +1 -0
- package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +51 -0
- package/src/components/Breadcrumb/Breadcrumb.module.css +51 -0
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +114 -0
- package/src/components/Breadcrumb/Breadcrumb.test.tsx +1 -0
- package/src/components/Breadcrumb/Breadcrumb.tsx +70 -0
- package/src/components/Breadcrumb/USAGE.md +42 -0
- package/src/components/Breadcrumb/index.ts +1 -0
- package/src/components/Button/BUTTON_IMPLEMENTATION_NOTES.md +123 -0
- package/src/components/Button/Button.module.css +413 -0
- package/src/components/Button/Button.stories.tsx +196 -0
- package/src/components/Button/Button.styleIsolation.dom.test.tsx +98 -0
- package/src/components/Button/Button.tsx +156 -0
- package/src/components/Button/USAGE.md +46 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Card/CARD_IMPLEMENTATION_NOTES.md +15 -0
- package/src/components/Card/Card.module.css +155 -0
- package/src/components/Card/Card.stories.tsx +131 -0
- package/src/components/Card/Card.test.tsx +1 -0
- package/src/components/Card/Card.tsx +202 -0
- package/src/components/Card/USAGE.md +57 -0
- package/src/components/Card/index.ts +1 -0
- package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +14 -0
- package/src/components/Checkbox/Checkbox.module.css +286 -0
- package/src/components/Checkbox/Checkbox.stories.tsx +97 -0
- package/src/components/Checkbox/Checkbox.test.tsx +1 -0
- package/src/components/Checkbox/Checkbox.tsx +259 -0
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +148 -0
- package/src/components/Checkbox/USAGE.md +36 -0
- package/src/components/Checkbox/index.ts +6 -0
- package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +102 -0
- package/src/components/Chip/Chip.module.css +283 -0
- package/src/components/Chip/Chip.stories.tsx +154 -0
- package/src/components/Chip/Chip.test.tsx +1 -0
- package/src/components/Chip/Chip.tsx +168 -0
- package/src/components/Chip/USAGE.md +55 -0
- package/src/components/Chip/index.ts +1 -0
- package/src/components/Container/Container.stories.tsx +118 -0
- package/src/components/Container/Container.test.tsx +1 -0
- package/src/components/Container/Container.tsx +51 -0
- package/src/components/Container/IMPLEMENTATION_NOTES.md +5 -0
- package/src/components/Container/USAGE.md +48 -0
- package/src/components/Container/index.ts +1 -0
- package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +29 -0
- package/src/components/DatePicker/DatePicker.icons.tsx +35 -0
- package/src/components/DatePicker/DatePicker.module.css +464 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +163 -0
- package/src/components/DatePicker/DatePicker.test.tsx +1 -0
- package/src/components/DatePicker/DatePicker.tsx +229 -0
- package/src/components/DatePicker/USAGE.md +49 -0
- package/src/components/DatePicker/index.ts +1 -0
- package/src/components/Dropdown/BareDropdown.tsx +168 -0
- package/src/components/Dropdown/DROPDOWN_IMPLEMENTATION_NOTES.md +45 -0
- package/src/components/Dropdown/Dropdown.icons.tsx +33 -0
- package/src/components/Dropdown/Dropdown.module.css +535 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +252 -0
- package/src/components/Dropdown/Dropdown.test.tsx +1 -0
- package/src/components/Dropdown/Dropdown.tsx +319 -0
- package/src/components/Dropdown/USAGE.md +68 -0
- package/src/components/Dropdown/index.ts +1 -0
- package/src/components/FileInput/FILEINPUT_IMPLEMENTATION_NOTES.md +153 -0
- package/src/components/FileInput/FileInput.module.css +268 -0
- package/src/components/FileInput/FileInput.stories.tsx +313 -0
- package/src/components/FileInput/FileInput.test.tsx +1 -0
- package/src/components/FileInput/FileInput.tsx +415 -0
- package/src/components/FileInput/USAGE.md +145 -0
- package/src/components/FileInput/index.ts +1 -0
- package/src/components/FileUpload/FILEUPLOAD_IMPLEMENTATION_NOTES.md +249 -0
- package/src/components/FileUpload/FileUpload.module.css +200 -0
- package/src/components/FileUpload/FileUpload.stories.tsx +362 -0
- package/src/components/FileUpload/FileUpload.test.tsx +1 -0
- package/src/components/FileUpload/FileUpload.tsx +352 -0
- package/src/components/FileUpload/USAGE.md +199 -0
- package/src/components/FileUpload/index.ts +1 -0
- package/src/components/Flex/Flex.stories.tsx +128 -0
- package/src/components/Flex/Flex.test.tsx +1 -0
- package/src/components/Flex/Flex.tsx +89 -0
- package/src/components/Flex/USAGE.md +41 -0
- package/src/components/Flex/index.ts +1 -0
- package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
- package/src/components/FormControlLayout/FormControlLayout.stories.tsx +118 -0
- package/src/components/FormControlLayout/FormControlLayout.test.tsx +1 -0
- package/src/components/FormControlLayout/FormControlLayout.tsx +72 -0
- package/src/components/FormControlLayout/USAGE.md +40 -0
- package/src/components/FormControlLayout/index.ts +1 -0
- package/src/components/FormControlWrapper/FORMCONTROLWRAPPER_IMPLEMENTATION_NOTES.md +35 -0
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +87 -0
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +129 -0
- package/src/components/FormControlWrapper/FormControlWrapper.test.tsx +1 -0
- package/src/components/FormControlWrapper/FormControlWrapper.tsx +149 -0
- package/src/components/FormControlWrapper/USAGE.md +40 -0
- package/src/components/FormControlWrapper/index.ts +1 -0
- package/src/components/Grid/Grid.module.css +72 -0
- package/src/components/Grid/Grid.stories.tsx +161 -0
- package/src/components/Grid/Grid.test.tsx +1 -0
- package/src/components/Grid/Grid.tsx +155 -0
- package/src/components/Grid/IMPLEMENTATION_NOTES.md +24 -0
- package/src/components/Grid/USAGE.md +53 -0
- package/src/components/Grid/index.ts +1 -0
- package/src/components/Group/Group.stories.tsx +120 -0
- package/src/components/Group/Group.test.tsx +1 -0
- package/src/components/Group/Group.tsx +116 -0
- package/src/components/Group/USAGE.md +41 -0
- package/src/components/Group/index.ts +1 -0
- package/src/components/Heading/Heading.stories.tsx +50 -0
- package/src/components/Heading/Heading.test.tsx +1 -0
- package/src/components/Heading/Heading.tsx +28 -0
- package/src/components/Heading/USAGE.md +36 -0
- package/src/components/Heading/index.ts +1 -0
- package/src/components/HoverCard/HoverCard.module.css +107 -0
- package/src/components/HoverCard/HoverCard.stories.tsx +172 -0
- package/src/components/HoverCard/HoverCard.test.tsx +1 -0
- package/src/components/HoverCard/HoverCard.tsx +145 -0
- package/src/components/HoverCard/USAGE.md +45 -0
- package/src/components/HoverCard/index.ts +1 -0
- package/src/components/Label/LABEL_IMPLEMENTATION_NOTES.md +27 -0
- package/src/components/Label/Label.module.css +169 -0
- package/src/components/Label/Label.stories.tsx +131 -0
- package/src/components/Label/Label.test.tsx +1 -0
- package/src/components/Label/Label.tsx +96 -0
- package/src/components/Label/USAGE.md +36 -0
- package/src/components/Label/index.ts +1 -0
- package/src/components/Layer/USAGE.md +50 -0
- package/src/components/Link/LINK_IMPLEMENTATION_NOTES.md +9 -0
- package/src/components/Link/Link.module.css +105 -0
- package/src/components/Link/Link.stories.tsx +58 -0
- package/src/components/Link/Link.test.tsx +1 -0
- package/src/components/Link/Link.tsx +45 -0
- package/src/components/Link/USAGE.md +40 -0
- package/src/components/Link/index.ts +1 -0
- package/src/components/Loader/LOADER_IMPLEMENTATION_NOTES.md +25 -0
- package/src/components/Loader/Loader.animate.dom.test.tsx +72 -0
- package/src/components/Loader/Loader.module.css +175 -0
- package/src/components/Loader/Loader.stories.tsx +123 -0
- package/src/components/Loader/Loader.test.tsx +1 -0
- package/src/components/Loader/Loader.tsx +72 -0
- package/src/components/Loader/USAGE.md +42 -0
- package/src/components/Loader/index.ts +1 -0
- package/src/components/Menu/IMPLEMENTATION_NOTES.md +5 -0
- package/src/components/Menu/Menu.module.css +283 -0
- package/src/components/Menu/Menu.stories.tsx +405 -0
- package/src/components/Menu/Menu.test.tsx +1 -0
- package/src/components/Menu/Menu.tsx +103 -0
- package/src/components/Menu/USAGE.md +53 -0
- package/src/components/Menu/index.ts +1 -0
- package/src/components/Modal/MODAL_IMPLEMENTATION_NOTES.md +31 -0
- package/src/components/Modal/Modal.module.css +302 -0
- package/src/components/Modal/Modal.stories.tsx +105 -0
- package/src/components/Modal/Modal.test.tsx +1 -0
- package/src/components/Modal/Modal.tsx +231 -0
- package/src/components/Modal/USAGE.md +40 -0
- package/src/components/Modal/index.ts +1 -0
- package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +93 -0
- package/src/components/NumberInput/NumberInput.module.css +303 -0
- package/src/components/NumberInput/NumberInput.stories.tsx +96 -0
- package/src/components/NumberInput/NumberInput.test.tsx +1 -0
- package/src/components/NumberInput/NumberInput.tsx +273 -0
- package/src/components/NumberInput/USAGE.md +36 -0
- package/src/components/NumberInput/index.ts +1 -0
- package/src/components/Pagination/IMPLEMENTATION_NOTES.md +40 -0
- package/src/components/Pagination/Pagination.icons.tsx +66 -0
- package/src/components/Pagination/Pagination.module.css +197 -0
- package/src/components/Pagination/Pagination.stories.tsx +48 -0
- package/src/components/Pagination/Pagination.test.tsx +1 -0
- package/src/components/Pagination/Pagination.tsx +123 -0
- package/src/components/Pagination/USAGE.md +36 -0
- package/src/components/Pagination/index.ts +1 -0
- package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +133 -0
- package/src/components/Panel/Panel.module.css +231 -0
- package/src/components/Panel/Panel.stories.tsx +227 -0
- package/src/components/Panel/Panel.test.tsx +1 -0
- package/src/components/Panel/Panel.tsx +186 -0
- package/src/components/Panel/USAGE.md +46 -0
- package/src/components/Panel/index.ts +1 -0
- package/src/components/Popover/IMPLEMENTATION_NOTES.md +22 -0
- package/src/components/Popover/Popover.module.css +118 -0
- package/src/components/Popover/Popover.stories.tsx +133 -0
- package/src/components/Popover/Popover.test.tsx +1 -0
- package/src/components/Popover/Popover.tsx +267 -0
- package/src/components/Popover/USAGE.md +69 -0
- package/src/components/Popover/index.ts +1 -0
- package/src/components/Radio/RADIO_IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Radio/Radio.module.css +247 -0
- package/src/components/Radio/Radio.stories.tsx +93 -0
- package/src/components/Radio/Radio.test.tsx +1 -0
- package/src/components/Radio/Radio.tsx +223 -0
- package/src/components/Radio/RadioGroup.stories.tsx +117 -0
- package/src/components/Radio/RadioGroup.tsx +122 -0
- package/src/components/Radio/USAGE.md +36 -0
- package/src/components/Radio/index.ts +2 -0
- package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyField.module.css +54 -0
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +163 -0
- package/src/components/ReadOnlyField/ReadOnlyField.test.tsx +1 -0
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +108 -0
- package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
- package/src/components/ReadOnlyField/USAGE.md +36 -0
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
- package/src/components/ReadOnlyField/index.ts +2 -0
- package/src/components/RecursicaThemeProvider/USAGE.md +60 -0
- package/src/components/SegmentedControl/IMPLEMENTATION_NOTES.md +14 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +201 -0
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +106 -0
- package/src/components/SegmentedControl/SegmentedControl.test.tsx +1 -0
- package/src/components/SegmentedControl/SegmentedControl.tsx +149 -0
- package/src/components/SegmentedControl/USAGE.md +49 -0
- package/src/components/SegmentedControl/index.ts +1 -0
- package/src/components/Slider/IMPLEMENTATION_NOTES.md +55 -0
- package/src/components/Slider/Slider.module.css +635 -0
- package/src/components/Slider/Slider.stories.tsx +282 -0
- package/src/components/Slider/Slider.test.tsx +1 -0
- package/src/components/Slider/Slider.tsx +435 -0
- package/src/components/Slider/USAGE.md +56 -0
- package/src/components/Slider/index.ts +1 -0
- package/src/components/Stack/Stack.stories.tsx +108 -0
- package/src/components/Stack/Stack.test.tsx +1 -0
- package/src/components/Stack/Stack.tsx +43 -0
- package/src/components/Stack/USAGE.md +41 -0
- package/src/components/Stack/index.ts +1 -0
- package/src/components/Stepper/IMPLEMENTATION_NOTES.md +120 -0
- package/src/components/Stepper/Stepper.module.css +474 -0
- package/src/components/Stepper/Stepper.stories.tsx +157 -0
- package/src/components/Stepper/Stepper.test.tsx +1 -0
- package/src/components/Stepper/Stepper.tsx +240 -0
- package/src/components/Stepper/USAGE.md +45 -0
- package/src/components/Stepper/index.ts +1 -0
- package/src/components/Switch/SWITCH_IMPLEMENTATION_NOTES.md +147 -0
- package/src/components/Switch/Switch.module.css +346 -0
- package/src/components/Switch/Switch.stories.tsx +114 -0
- package/src/components/Switch/Switch.test.tsx +1 -0
- package/src/components/Switch/Switch.tsx +294 -0
- package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
- package/src/components/Switch/SwitchGroup.tsx +156 -0
- package/src/components/Switch/USAGE.md +36 -0
- package/src/components/Switch/index.ts +2 -0
- package/src/components/Table/TABLE_IMPLEMENTATION_NOTES.md +75 -0
- package/src/components/Table/Table.module.css +462 -0
- package/src/components/Table/Table.stories.tsx +154 -0
- package/src/components/Table/Table.test.tsx +1 -0
- package/src/components/Table/Table.tsx +250 -0
- package/src/components/Table/USAGE.md +90 -0
- package/src/components/Table/index.ts +1 -0
- package/src/components/Tabs/IMPLEMENTATION_NOTES.md +76 -0
- package/src/components/Tabs/Tabs.module.css +801 -0
- package/src/components/Tabs/Tabs.stories.tsx +174 -0
- package/src/components/Tabs/Tabs.test.tsx +1 -0
- package/src/components/Tabs/Tabs.tsx +103 -0
- package/src/components/Tabs/USAGE.md +61 -0
- package/src/components/Tabs/index.ts +1 -0
- package/src/components/Text/TEXT_IMPLEMENTATION_NOTES.md +10 -0
- package/src/components/Text/Text.stories.tsx +75 -0
- package/src/components/Text/Text.test.tsx +1 -0
- package/src/components/Text/Text.tsx +19 -0
- package/src/components/Text/USAGE.md +40 -0
- package/src/components/Text/index.ts +1 -0
- package/src/components/TextArea/TEXTAREA_IMPLEMENTATION_NOTES.md +42 -0
- package/src/components/TextArea/TextArea.module.css +203 -0
- package/src/components/TextArea/TextArea.stories.tsx +94 -0
- package/src/components/TextArea/TextArea.test.tsx +1 -0
- package/src/components/TextArea/TextArea.tsx +162 -0
- package/src/components/TextArea/USAGE.md +38 -0
- package/src/components/TextArea/index.ts +1 -0
- package/src/components/TextField/TextField.module.css +271 -0
- package/src/components/TextField/TextField.stories.tsx +162 -0
- package/src/components/TextField/TextField.test.tsx +1 -0
- package/src/components/TextField/TextField.tsx +182 -0
- package/src/components/TextField/USAGE.md +38 -0
- package/src/components/TextField/index.ts +1 -0
- package/src/components/TimePicker/TIMEPICKER_IMPLEMENTATION_NOTES.md +89 -0
- package/src/components/TimePicker/TimePicker.module.css +262 -0
- package/src/components/TimePicker/TimePicker.stories.tsx +155 -0
- package/src/components/TimePicker/TimePicker.test.tsx +1 -0
- package/src/components/TimePicker/TimePicker.tsx +277 -0
- package/src/components/TimePicker/USAGE.md +61 -0
- package/src/components/TimePicker/index.ts +1 -0
- package/src/components/Timeline/IMPLEMENTATION_NOTES.md +42 -0
- package/src/components/Timeline/Timeline.module.css +363 -0
- package/src/components/Timeline/Timeline.stories.tsx +128 -0
- package/src/components/Timeline/Timeline.test.tsx +1 -0
- package/src/components/Timeline/Timeline.tsx +90 -0
- package/src/components/Timeline/TimelineItem.tsx +95 -0
- package/src/components/Timeline/USAGE.md +41 -0
- package/src/components/Timeline/index.ts +2 -0
- package/src/components/Toast/TOAST_IMPLEMENTATION_NOTES.md +37 -0
- package/src/components/Toast/Toast.module.css +193 -0
- package/src/components/Toast/Toast.stories.tsx +67 -0
- package/src/components/Toast/Toast.test.tsx +1 -0
- package/src/components/Toast/Toast.tsx +121 -0
- package/src/components/Toast/USAGE.md +42 -0
- package/src/components/Toast/index.ts +1 -0
- package/src/components/Tooltip/Tooltip.module.css +83 -0
- package/src/components/Tooltip/Tooltip.stories.tsx +165 -0
- package/src/components/Tooltip/Tooltip.test.tsx +1 -0
- package/src/components/Tooltip/Tooltip.tsx +78 -0
- package/src/components/Tooltip/USAGE.md +40 -0
- package/src/components/Tooltip/index.ts +1 -0
- package/src/components/TransferList/TRANSFERLIST_IMPLEMENTATION_NOTES.md +140 -0
- package/src/components/TransferList/TransferList.module.css +174 -0
- package/src/components/TransferList/TransferList.stories.tsx +121 -0
- package/src/components/TransferList/TransferList.test.tsx +1 -0
- package/src/components/TransferList/TransferList.tsx +419 -0
- package/src/components/TransferList/USAGE.md +77 -0
- package/src/components/TransferList/index.ts +1 -0
- package/src/components/Tree/IMPLEMENTATION_NOTES.md +53 -0
- package/src/components/Tree/Tree.module.css +272 -0
- package/src/components/Tree/Tree.stories.tsx +104 -0
- package/src/components/Tree/Tree.test.tsx +1 -0
- package/src/components/Tree/Tree.tsx +298 -0
- package/src/components/Tree/USAGE.md +99 -0
- package/src/components/Tree/index.ts +1 -0
- package/src/components/Typography/TYPOGRAPHY_IMPLEMENTATION_NOTES.md +17 -0
- package/src/components/Typography/Typography.module.css +13 -0
- package/src/components/Typography/Typography.test.tsx +1 -0
- package/src/components/Typography/Typography.tsx +43 -0
- package/src/components/Typography/USAGE.md +40 -0
- package/src/components/Typography/index.ts +1 -0
- package/src/components/index.ts +50 -0
- package/src/env.d.ts +7 -0
- package/src/index.ts +194 -0
- package/src/types/index.ts +9 -0
- package/src/types/scss-modules.d.ts +9 -0
- package/src/utils/ColorSchemeWrapper.tsx +23 -0
- package/src/utils/RequireAccessibleLabel.ts +1 -0
- package/src/utils/copyToClipboard.ts +36 -0
- package/src/utils/filterStylingProps.test.ts +85 -0
- package/src/utils/filterStylingProps.ts +143 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/renderRichOption.tsx +51 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Button } from "./Button";
|
|
4
|
+
import { Layer } from "@recursica/adapter-common";
|
|
5
|
+
|
|
6
|
+
type ButtonStoryProps = React.ComponentProps<typeof Button>;
|
|
7
|
+
|
|
8
|
+
const meta: Meta<ButtonStoryProps> = {
|
|
9
|
+
title: "UI-Kit/Button",
|
|
10
|
+
component: Button,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
argTypes: {
|
|
13
|
+
disabled: {
|
|
14
|
+
control: "boolean",
|
|
15
|
+
},
|
|
16
|
+
variant: {
|
|
17
|
+
control: "select",
|
|
18
|
+
options: ["solid", "outline", "text"],
|
|
19
|
+
description: "The visual variant of the button",
|
|
20
|
+
},
|
|
21
|
+
size: {
|
|
22
|
+
control: "radio",
|
|
23
|
+
options: ["default", "small"],
|
|
24
|
+
description: "The size of the button",
|
|
25
|
+
},
|
|
26
|
+
loading: {
|
|
27
|
+
control: "boolean",
|
|
28
|
+
description: "Sets the button to a loading state",
|
|
29
|
+
},
|
|
30
|
+
useRecursicaLoader: {
|
|
31
|
+
control: "boolean",
|
|
32
|
+
description:
|
|
33
|
+
"Use the Recursica Loader component instead of the default Mantine loader",
|
|
34
|
+
},
|
|
35
|
+
loaderVariant: {
|
|
36
|
+
control: "select",
|
|
37
|
+
options: ["oval", "bars", "dots"],
|
|
38
|
+
description: "The visual variant of the Recursica Loader",
|
|
39
|
+
},
|
|
40
|
+
loaderSize: {
|
|
41
|
+
control: "select",
|
|
42
|
+
options: [undefined, "sm", "md", "lg", "small", "default", "large"],
|
|
43
|
+
description: "The size variant for the loader",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
args: {
|
|
47
|
+
useRecursicaLoader: true,
|
|
48
|
+
loaderVariant: "oval",
|
|
49
|
+
loaderSize: undefined,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export default meta;
|
|
54
|
+
|
|
55
|
+
type Story = StoryObj<ButtonStoryProps>;
|
|
56
|
+
|
|
57
|
+
export const Default: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
children: "Explore Button",
|
|
60
|
+
variant: "solid",
|
|
61
|
+
size: "default",
|
|
62
|
+
disabled: false,
|
|
63
|
+
},
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
65
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
66
|
+
return <Button {...args} />;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const SolidDefault: Story = {
|
|
71
|
+
args: {
|
|
72
|
+
children: "Solid Default",
|
|
73
|
+
variant: "solid",
|
|
74
|
+
size: "default",
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const OutlineSmall: Story = {
|
|
79
|
+
args: {
|
|
80
|
+
children: "Outline Small",
|
|
81
|
+
variant: "outline",
|
|
82
|
+
size: "small",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const TextWithIcon: Story = {
|
|
87
|
+
args: {
|
|
88
|
+
children: "Text With Icon",
|
|
89
|
+
variant: "text",
|
|
90
|
+
size: "default",
|
|
91
|
+
icon: (
|
|
92
|
+
<svg
|
|
93
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
94
|
+
width="24"
|
|
95
|
+
height="24"
|
|
96
|
+
viewBox="0 0 24 24"
|
|
97
|
+
fill="none"
|
|
98
|
+
stroke="currentColor"
|
|
99
|
+
strokeWidth="2"
|
|
100
|
+
strokeLinecap="round"
|
|
101
|
+
strokeLinejoin="round"
|
|
102
|
+
>
|
|
103
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
104
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
105
|
+
</svg>
|
|
106
|
+
),
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export const IconOnly: Story = {
|
|
111
|
+
args: {
|
|
112
|
+
variant: "solid",
|
|
113
|
+
size: "default",
|
|
114
|
+
"aria-label": "Search",
|
|
115
|
+
icon: (
|
|
116
|
+
<svg
|
|
117
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
118
|
+
width="24"
|
|
119
|
+
height="24"
|
|
120
|
+
viewBox="0 0 24 24"
|
|
121
|
+
fill="none"
|
|
122
|
+
stroke="currentColor"
|
|
123
|
+
strokeWidth="2"
|
|
124
|
+
strokeLinecap="round"
|
|
125
|
+
strokeLinejoin="round"
|
|
126
|
+
>
|
|
127
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
128
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
129
|
+
</svg>
|
|
130
|
+
),
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const LayerOneSolid: Story = {
|
|
135
|
+
args: {
|
|
136
|
+
children: "Layer 1 Solid",
|
|
137
|
+
variant: "solid",
|
|
138
|
+
size: "default",
|
|
139
|
+
},
|
|
140
|
+
render: (args: ButtonStoryProps) => (
|
|
141
|
+
<Layer layer={1} style={{ padding: "24px" }}>
|
|
142
|
+
<Button {...args} />
|
|
143
|
+
</Layer>
|
|
144
|
+
),
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const DisabledSolid: Story = {
|
|
148
|
+
args: {
|
|
149
|
+
children: "Disabled Solid",
|
|
150
|
+
variant: "solid",
|
|
151
|
+
size: "default",
|
|
152
|
+
disabled: true,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const PolymorphicAsLink: Story = {
|
|
157
|
+
args: {
|
|
158
|
+
children: "Button as Link",
|
|
159
|
+
variant: "solid",
|
|
160
|
+
size: "default",
|
|
161
|
+
component: "a",
|
|
162
|
+
href: "https://example.com",
|
|
163
|
+
target: "_blank",
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
export const TruncatedLabel: Story = {
|
|
168
|
+
args: {
|
|
169
|
+
children:
|
|
170
|
+
"This is an exceptionally long button label designed to demonstrate how the component handles text overflow by applying an ellipsis rather than breaking the layout or wrapping to multiple lines.",
|
|
171
|
+
variant: "solid",
|
|
172
|
+
size: "default",
|
|
173
|
+
},
|
|
174
|
+
render: (args: ButtonStoryProps) => (
|
|
175
|
+
<div style={{ maxWidth: "250px" }}>
|
|
176
|
+
<Button {...args} />
|
|
177
|
+
</div>
|
|
178
|
+
),
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
export const Loading: Story = {
|
|
182
|
+
args: {
|
|
183
|
+
children: "Saving Changes",
|
|
184
|
+
variant: "solid",
|
|
185
|
+
size: "default",
|
|
186
|
+
loading: true,
|
|
187
|
+
},
|
|
188
|
+
parameters: {
|
|
189
|
+
docs: {
|
|
190
|
+
description: {
|
|
191
|
+
story:
|
|
192
|
+
"When `loading={true}` is applied, the Button injects the Recursica `<Loader />` component. Per Recursica design rules, placing a Button in a loading state automatically forces the `disabled={true}` state on the underlying element. This ensures the button immediately receives the brand theme disabled opacities without relying solely on semantic logic.",
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
4
|
+
import { flushSync } from "react-dom";
|
|
5
|
+
import { ThemeProvider, createTheme, Button as MuiButton } from "@mui/material";
|
|
6
|
+
import { Button as RecursicaButton } from "./Button";
|
|
7
|
+
|
|
8
|
+
function mount(node: React.ReactElement): {
|
|
9
|
+
container: HTMLElement;
|
|
10
|
+
root: Root;
|
|
11
|
+
} {
|
|
12
|
+
const container = document.createElement("div");
|
|
13
|
+
document.body.appendChild(container);
|
|
14
|
+
const root = createRoot(container);
|
|
15
|
+
flushSync(() => root.render(node));
|
|
16
|
+
return { container, root };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function unmount({ container, root }: { container: HTMLElement; root: Root }) {
|
|
20
|
+
root.unmount();
|
|
21
|
+
container.remove();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const theme = createTheme({ colorSchemes: { light: true, dark: true } });
|
|
25
|
+
|
|
26
|
+
function withProvider(node: React.ReactElement) {
|
|
27
|
+
return <ThemeProvider theme={theme}>{node}</ThemeProvider>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Guards against Recursica's Button CSS bleeding onto (or being bled onto by) a plain,
|
|
32
|
+
* unwrapped MUI Button rendered in the same document. The two must be visibly different
|
|
33
|
+
* (Recursica's own classes/data-attributes), but the plain kit button must render identically
|
|
34
|
+
* whether or not a Recursica Button exists alongside it.
|
|
35
|
+
*/
|
|
36
|
+
describe("Button style isolation from the underlying MUI kit", () => {
|
|
37
|
+
it("adds Recursica-only classes/attributes without leaking them onto a plain MUI Button", () => {
|
|
38
|
+
const recursica = mount(
|
|
39
|
+
withProvider(<RecursicaButton>Recursica</RecursicaButton>),
|
|
40
|
+
);
|
|
41
|
+
const kit = mount(withProvider(<MuiButton>Plain</MuiButton>));
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const recursicaButton = recursica.container.querySelector("button")!;
|
|
45
|
+
const kitButton = kit.container.querySelector("button")!;
|
|
46
|
+
|
|
47
|
+
const recursicaClasses = Array.from(recursicaButton.classList);
|
|
48
|
+
const kitClasses = new Set(kitButton.classList);
|
|
49
|
+
const recursicaOnlyClasses = recursicaClasses.filter(
|
|
50
|
+
(cls) => !kitClasses.has(cls),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Recursica's Button.module.css classes must exist...
|
|
54
|
+
expect(recursicaOnlyClasses.length).toBeGreaterThan(0);
|
|
55
|
+
// ...and none of them are present on the plain kit button.
|
|
56
|
+
for (const cls of recursicaOnlyClasses) {
|
|
57
|
+
expect(kitButton.classList.contains(cls)).toBe(false);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Recursica-only markers confirm the two are meaningfully different components.
|
|
61
|
+
expect(recursicaButton.getAttribute("data-variant")).toBe("solid");
|
|
62
|
+
expect(kitButton.getAttribute("data-variant")).toBeNull();
|
|
63
|
+
} finally {
|
|
64
|
+
unmount(recursica);
|
|
65
|
+
unmount(kit);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("renders a plain MUI Button identically whether or not Recursica's Button is mounted alongside it", () => {
|
|
70
|
+
const recursica = mount(
|
|
71
|
+
withProvider(<RecursicaButton>Recursica</RecursicaButton>),
|
|
72
|
+
);
|
|
73
|
+
const kitAlongsideRecursica = mount(
|
|
74
|
+
withProvider(<MuiButton>Plain</MuiButton>),
|
|
75
|
+
);
|
|
76
|
+
const kitIsolated = mount(withProvider(<MuiButton>Plain</MuiButton>));
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const kitButton =
|
|
80
|
+
kitAlongsideRecursica.container.querySelector("button")!;
|
|
81
|
+
const isolatedButton = kitIsolated.container.querySelector("button")!;
|
|
82
|
+
|
|
83
|
+
expect(Array.from(kitButton.classList).sort()).toEqual(
|
|
84
|
+
Array.from(isolatedButton.classList).sort(),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const kitStyle = getComputedStyle(kitButton);
|
|
88
|
+
const isolatedStyle = getComputedStyle(isolatedButton);
|
|
89
|
+
expect(kitStyle.borderRadius).toBe(isolatedStyle.borderRadius);
|
|
90
|
+
expect(kitStyle.backgroundColor).toBe(isolatedStyle.backgroundColor);
|
|
91
|
+
expect(kitStyle.fontFamily).toBe(isolatedStyle.fontFamily);
|
|
92
|
+
} finally {
|
|
93
|
+
unmount(recursica);
|
|
94
|
+
unmount(kitAlongsideRecursica);
|
|
95
|
+
unmount(kitIsolated);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import { Loader } from "../Loader/Loader";
|
|
3
|
+
import {
|
|
4
|
+
Button as MuiButton,
|
|
5
|
+
type ButtonProps as MuiButtonProps,
|
|
6
|
+
} from "@mui/material";
|
|
7
|
+
import {
|
|
8
|
+
filterStylingProps,
|
|
9
|
+
omitUnsupportedProps,
|
|
10
|
+
withCallerOverride,
|
|
11
|
+
type RecursicaOverStyled,
|
|
12
|
+
} from "../../utils/filterStylingProps";
|
|
13
|
+
import styles from "./Button.module.css";
|
|
14
|
+
|
|
15
|
+
import { type RecursicaButtonProps } from "@recursica/adapter-common";
|
|
16
|
+
|
|
17
|
+
export type ButtonProps = RecursicaOverStyled<
|
|
18
|
+
Omit<MuiButtonProps, "variant" | "size" | "color" | "fullWidth"> &
|
|
19
|
+
RecursicaButtonProps
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
function hasVisibleChildren(children: React.ReactNode): boolean {
|
|
23
|
+
if (children == null || children === "") return false;
|
|
24
|
+
if (typeof children === "string") return children.trim() !== "";
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Recursica Button component wrapping MUI's Button.
|
|
30
|
+
*
|
|
31
|
+
* Supports polymorphism via the `component` prop for custom element rendering.
|
|
32
|
+
* This is particularly useful when you need a button that behaves as a hyperlink (rendering an `<a>` tag)
|
|
33
|
+
* or integrates with a routing library (e.g., `react-router-dom` or Next.js), while preserving full visual styling.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```tsx
|
|
37
|
+
* // Renders as an <a> tag natively
|
|
38
|
+
* <Button component="a" href="/dashboard" target="_blank">Navigate</Button>
|
|
39
|
+
*
|
|
40
|
+
* // Renders using a custom router link
|
|
41
|
+
* <Button component={Link} to="/home">Home</Button>
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
|
45
|
+
function Button(
|
|
46
|
+
{
|
|
47
|
+
variant = "solid",
|
|
48
|
+
size = "default",
|
|
49
|
+
icon,
|
|
50
|
+
children,
|
|
51
|
+
overStyled = false,
|
|
52
|
+
loaderVariant = "oval",
|
|
53
|
+
loaderSize,
|
|
54
|
+
useRecursicaLoader = true,
|
|
55
|
+
...rest
|
|
56
|
+
},
|
|
57
|
+
ref,
|
|
58
|
+
) {
|
|
59
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
60
|
+
// through even if a caller forces them via plain JavaScript, bypassing the Omit<> above.
|
|
61
|
+
const UNSUPPORTED_PROPS = [
|
|
62
|
+
"color", // Recursica handles colors internally via tokens
|
|
63
|
+
] as const satisfies readonly (keyof MuiButtonProps)[];
|
|
64
|
+
|
|
65
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
66
|
+
filterStylingProps(rest, overStyled),
|
|
67
|
+
UNSUPPORTED_PROPS,
|
|
68
|
+
);
|
|
69
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
70
|
+
|
|
71
|
+
const hasStartIcon = !!icon || !!restRecord["startIcon"];
|
|
72
|
+
const hasEndIcon = !!restRecord["endIcon"];
|
|
73
|
+
const hasVisibleText = hasVisibleChildren(children);
|
|
74
|
+
const isIconOnly = (hasStartIcon || hasEndIcon) && !hasVisibleText;
|
|
75
|
+
|
|
76
|
+
let contentType = "label";
|
|
77
|
+
if (isIconOnly) {
|
|
78
|
+
contentType = "icon-only";
|
|
79
|
+
} else if (hasStartIcon || hasEndIcon) {
|
|
80
|
+
contentType = "icon-label";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
typeof process !== "undefined" &&
|
|
85
|
+
process.env.NODE_ENV !== "production" &&
|
|
86
|
+
isIconOnly &&
|
|
87
|
+
!restRecord["aria-label"]
|
|
88
|
+
) {
|
|
89
|
+
console.warn(
|
|
90
|
+
'[Recursica Button] Icon-only buttons must provide an accessible name. Pass aria-label (e.g. aria-label="Submit").',
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
95
|
+
const finalClass = classNameProp
|
|
96
|
+
? `${styles.root} ${classNameProp}`
|
|
97
|
+
: styles.root;
|
|
98
|
+
|
|
99
|
+
// We don't map Recursica variant/size to MUI's because we want to completely disable MUI's native
|
|
100
|
+
// variant logic (e.g., elevation, shadows) and style everything strictly through our CSS Modules.
|
|
101
|
+
// However, Mui Button requires some string, but we can just leave it as standard or ignore since
|
|
102
|
+
// our CSS resets its properties anyway, but to be clean we just don't pass variant to MUI.
|
|
103
|
+
|
|
104
|
+
const resolvedLoaderSize = withCallerOverride(
|
|
105
|
+
size === "small" ? "small" : "default",
|
|
106
|
+
loaderSize,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
let loadingIndicator = restRecord.loadingIndicator as React.ReactNode;
|
|
110
|
+
if (useRecursicaLoader) {
|
|
111
|
+
// overStyled + style unlock the "--loader-color" override below — this is a fully
|
|
112
|
+
// internal composition (no external prop threading), so it doesn't widen Loader's public
|
|
113
|
+
// contract. Matches the button's own text-color token instead of Loader's standalone
|
|
114
|
+
// indicator-color default. See IMPLEMENTATION_NOTES.md.
|
|
115
|
+
loadingIndicator = (
|
|
116
|
+
<Loader
|
|
117
|
+
variant={loaderVariant}
|
|
118
|
+
size={resolvedLoaderSize}
|
|
119
|
+
overStyled
|
|
120
|
+
style={
|
|
121
|
+
{ "--loader-color": "var(--button-color)" } as React.CSSProperties
|
|
122
|
+
}
|
|
123
|
+
/>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<MuiButton
|
|
129
|
+
ref={ref}
|
|
130
|
+
{...sanitizedProps}
|
|
131
|
+
disableRipple
|
|
132
|
+
disableElevation
|
|
133
|
+
className={finalClass}
|
|
134
|
+
loading={!!restRecord.loading}
|
|
135
|
+
loadingIndicator={loadingIndicator}
|
|
136
|
+
fullWidth={!!restRecord.fullWidth}
|
|
137
|
+
startIcon={
|
|
138
|
+
icon != null ? (
|
|
139
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
140
|
+
{icon}
|
|
141
|
+
</span>
|
|
142
|
+
) : undefined
|
|
143
|
+
}
|
|
144
|
+
data-variant={variant}
|
|
145
|
+
data-size={size}
|
|
146
|
+
data-content={contentType}
|
|
147
|
+
{...(restRecord.loading ? { "data-loading": "true" } : {})}
|
|
148
|
+
disabled={!!restRecord.disabled || !!restRecord.loading}
|
|
149
|
+
>
|
|
150
|
+
<span className={styles.labelText}>{children}</span>
|
|
151
|
+
</MuiButton>
|
|
152
|
+
);
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
Button.displayName = "Button";
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Button - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Button` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Button } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Button } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Button variant="primary" onClick={() => console.log("Clicked!")}>
|
|
24
|
+
Click Me
|
|
25
|
+
</Button>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Design System Integration
|
|
33
|
+
|
|
34
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
35
|
+
|
|
36
|
+
> [!IMPORTANT]
|
|
37
|
+
>
|
|
38
|
+
> - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
|
|
39
|
+
> - **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.
|
|
40
|
+
> - **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.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 4. Key Integration Features & Constraints
|
|
45
|
+
|
|
46
|
+
When `loading={true}` is passed to the Button, the button is also automatically disabled, and its loading indicator's color may not always match the button's text color, which can affect contrast in some variants.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Button";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Card Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Architecture Overrides
|
|
4
|
+
|
|
5
|
+
Because MUI natively constructs `Card` bounding boxes using `<Paper>` components (which lack the precise edge-to-edge layouts native to Mantine's sections), we implemented custom margins for edge-to-edge section components:
|
|
6
|
+
|
|
7
|
+
- `<Card.Header>` explicitly hooks `--recursica_ui-kit_components_card_properties_header-background` and corresponding padding variables, stretching edge-to-edge via negative margin resets.
|
|
8
|
+
- `<Card.Footer>` explicitly hooks `--recursica_ui-kit_components_card_properties_footer-background` and corresponding padding variables.
|
|
9
|
+
|
|
10
|
+
## Layout Alignment Exceptions
|
|
11
|
+
|
|
12
|
+
To allow Cards to fit cleanly inside dynamic/flex layouts (like dashboard panels, grid tracks, or sidebar layout segments), the Card wrapper implements a custom gatekeeper bypass for outer styling properties:
|
|
13
|
+
|
|
14
|
+
- Exposes a safe subset of flexbox/dimensions styling properties (`flex`, `flexGrow`, `flexShrink`, `flexBasis`, `grow`, `h`, `height`) on the root `<Card>` component to allow proper sizing alongside layout siblings.
|
|
15
|
+
- Sets `<Card.Content>` to `flex-grow: 1;` by default via CSS modules. Since the root `<Card>` has `display: flex; flex-direction: column;`, this makes the content area expand to fill all vertical space, pushing `<Card.Footer>` to align at the absolute bottom of the bounding box.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- display: flex on root
|
|
3
|
+
- flex-direction: column
|
|
4
|
+
- gap: section-gap
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
.root {
|
|
8
|
+
/* HARDCODE: Map Recursica explicitly into Mantine's variable format so internal components know the margins */
|
|
9
|
+
--card-padding: var(--recursica_ui-kit_components_card_properties_padding);
|
|
10
|
+
|
|
11
|
+
background-color: var(
|
|
12
|
+
--recursica_ui-kit_components_card_properties_colors_background-color
|
|
13
|
+
);
|
|
14
|
+
border-radius: var(
|
|
15
|
+
--recursica_ui-kit_components_card_properties_borders_border-radius
|
|
16
|
+
);
|
|
17
|
+
border: var(--recursica_ui-kit_components_card_properties_borders_border-size)
|
|
18
|
+
solid var(--recursica_ui-kit_components_card_properties_colors_border-color);
|
|
19
|
+
box-shadow: var(
|
|
20
|
+
--recursica_ui-kit_components_card_properties_elevations_elevation
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
padding: var(--card-padding);
|
|
24
|
+
min-width: var(--recursica_ui-kit_components_card_properties_min-width);
|
|
25
|
+
max-width: var(--recursica_ui-kit_components_card_properties_max-width);
|
|
26
|
+
color: var(--recursica_ui-kit_components_card_properties_colors_content);
|
|
27
|
+
|
|
28
|
+
display: flex;
|
|
29
|
+
flex-direction: column;
|
|
30
|
+
gap: var(--recursica_ui-kit_components_card_properties_section-gap);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.header {
|
|
34
|
+
background-color: var(
|
|
35
|
+
--recursica_ui-kit_components_card_properties_colors_header-background-color
|
|
36
|
+
);
|
|
37
|
+
padding: var(--recursica_ui-kit_components_card_properties_header-padding);
|
|
38
|
+
color: var(--recursica_ui-kit_components_card_properties_colors_title);
|
|
39
|
+
border-bottom: var(--recursica_ui-kit_components_card_properties_divider-size)
|
|
40
|
+
solid
|
|
41
|
+
var(--recursica_ui-kit_components_card_properties_colors_divider-color);
|
|
42
|
+
|
|
43
|
+
/* Direct Figma Typography Mapping */
|
|
44
|
+
font-family: var(
|
|
45
|
+
--recursica_ui-kit_components_card_properties_header-style_fontFamily
|
|
46
|
+
);
|
|
47
|
+
font-size: var(
|
|
48
|
+
--recursica_ui-kit_components_card_properties_header-style_fontSize
|
|
49
|
+
);
|
|
50
|
+
font-style: var(
|
|
51
|
+
--recursica_ui-kit_components_card_properties_header-style_fontStyle
|
|
52
|
+
);
|
|
53
|
+
font-weight: var(
|
|
54
|
+
--recursica_ui-kit_components_card_properties_header-style_fontWeight
|
|
55
|
+
);
|
|
56
|
+
letter-spacing: var(
|
|
57
|
+
--recursica_ui-kit_components_card_properties_header-style_letterSpacing
|
|
58
|
+
);
|
|
59
|
+
line-height: var(
|
|
60
|
+
--recursica_ui-kit_components_card_properties_header-style_lineHeight
|
|
61
|
+
);
|
|
62
|
+
text-transform: var(
|
|
63
|
+
--recursica_ui-kit_components_card_properties_header-style_textCase
|
|
64
|
+
);
|
|
65
|
+
text-decoration: var(
|
|
66
|
+
--recursica_ui-kit_components_card_properties_header-style_textDecoration
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/* Edge-to-edge behavior */
|
|
70
|
+
margin-left: calc(var(--card-padding) * -1) !important;
|
|
71
|
+
margin-right: calc(var(--card-padding) * -1) !important;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.header:first-child {
|
|
75
|
+
margin-top: calc(var(--card-padding) * -1) !important;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.header:last-child {
|
|
79
|
+
margin-bottom: calc(var(--card-padding) * -1) !important;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.footer {
|
|
83
|
+
background-color: var(
|
|
84
|
+
--recursica_ui-kit_components_card_properties_colors_footer-background-color
|
|
85
|
+
);
|
|
86
|
+
padding: var(--recursica_ui-kit_components_card_properties_footer-padding);
|
|
87
|
+
border-top: var(--recursica_ui-kit_components_card_properties_divider-size)
|
|
88
|
+
solid
|
|
89
|
+
var(--recursica_ui-kit_components_card_properties_colors_divider-color);
|
|
90
|
+
|
|
91
|
+
/* Edge-to-edge behavior */
|
|
92
|
+
margin-left: calc(var(--card-padding) * -1) !important;
|
|
93
|
+
margin-right: calc(var(--card-padding) * -1) !important;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.footer:first-child {
|
|
97
|
+
margin-top: calc(var(--card-padding) * -1) !important;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.footer:last-child {
|
|
101
|
+
margin-bottom: calc(var(--card-padding) * -1) !important;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.section {
|
|
105
|
+
/* Just maps standard section spacing overrides if passed explicitly */
|
|
106
|
+
margin-top: var(
|
|
107
|
+
--recursica_ui-kit_components_card_properties_vertical-gutter
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
/* Edge-to-edge behavior */
|
|
111
|
+
margin-left: calc(var(--card-padding) * -1) !important;
|
|
112
|
+
margin-right: calc(var(--card-padding) * -1) !important;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.section:first-child {
|
|
116
|
+
margin-top: calc(var(--card-padding) * -1) !important;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.section:last-child {
|
|
120
|
+
margin-bottom: calc(var(--card-padding) * -1) !important;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.content {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-direction: column;
|
|
126
|
+
gap: var(--recursica_ui-kit_components_card_properties_vertical-gutter);
|
|
127
|
+
padding: 0;
|
|
128
|
+
flex-grow: 1;
|
|
129
|
+
|
|
130
|
+
/* Direct Figma Typography Mapping */
|
|
131
|
+
font-family: var(
|
|
132
|
+
--recursica_ui-kit_components_card_properties_content-style_fontFamily
|
|
133
|
+
);
|
|
134
|
+
font-size: var(
|
|
135
|
+
--recursica_ui-kit_components_card_properties_content-style_fontSize
|
|
136
|
+
);
|
|
137
|
+
font-style: var(
|
|
138
|
+
--recursica_ui-kit_components_card_properties_content-style_fontStyle
|
|
139
|
+
);
|
|
140
|
+
font-weight: var(
|
|
141
|
+
--recursica_ui-kit_components_card_properties_content-style_fontWeight
|
|
142
|
+
);
|
|
143
|
+
letter-spacing: var(
|
|
144
|
+
--recursica_ui-kit_components_card_properties_content-style_letterSpacing
|
|
145
|
+
);
|
|
146
|
+
line-height: var(
|
|
147
|
+
--recursica_ui-kit_components_card_properties_content-style_lineHeight
|
|
148
|
+
);
|
|
149
|
+
text-transform: var(
|
|
150
|
+
--recursica_ui-kit_components_card_properties_content-style_textCase
|
|
151
|
+
);
|
|
152
|
+
text-decoration: var(
|
|
153
|
+
--recursica_ui-kit_components_card_properties_content-style_textDecoration
|
|
154
|
+
);
|
|
155
|
+
}
|