@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,199 @@
|
|
|
1
|
+
# FileUpload - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `FileUpload` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { FileUpload } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
`FileUpload` is a **controlled** component: it never stores the selected files itself. `onFilesAdded` reports newly dropped/picked files, `onFileRemove` reports which file was removed, and you own the `files` array in between.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import React, { useState } from "react";
|
|
21
|
+
import { FileUpload } from "@recursica/adapter-mui-v7";
|
|
22
|
+
import { type RecursicaFileUploadItem } from "@recursica/adapter-common";
|
|
23
|
+
|
|
24
|
+
export default function Demo() {
|
|
25
|
+
const [files, setFiles] = useState<RecursicaFileUploadItem[]>([]);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<FileUpload
|
|
29
|
+
label="Upload Files"
|
|
30
|
+
assistiveText="Max file size 5MB"
|
|
31
|
+
files={files}
|
|
32
|
+
onFilesAdded={(added) =>
|
|
33
|
+
setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
|
|
34
|
+
}
|
|
35
|
+
onFileRemove={(id) =>
|
|
36
|
+
setFiles((prev) =>
|
|
37
|
+
prev.filter((item) => (item.id ?? item.file.name) !== id),
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. Props Reference
|
|
48
|
+
|
|
49
|
+
| Prop | Type | Description |
|
|
50
|
+
| ------------------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
51
|
+
| `files` | `RecursicaFileUploadItem[]` | Files currently selected, rendered as removable chips below the dropzone. Each item is `{ file: File; id?: string }`. |
|
|
52
|
+
| `onFilesAdded` | `(files: File[]) => void` | Called with newly dropped/picked files. Only the new files — merge them into `files` yourself. |
|
|
53
|
+
| `onFileRemove` | `(id: string) => void` | Called with a file's `id` (or `file.name` if no `id` was given) when its remove (X) icon is activated. |
|
|
54
|
+
| `accept` | `string` | Native `accept` attribute (e.g. `".pdf,.png"` or `"image/*"`) — constrains the picker dialog, and is also enforced against dropped files (via `onFilesRejected`), since the browser never applies `accept` to a `drop` event itself. |
|
|
55
|
+
| `multiple` | `boolean` | Whether more than one file can be selected/dropped at once. Defaults to `true`. |
|
|
56
|
+
| `maxSize` | `number` | Maximum size per file, in bytes. Oversized files go to `onFilesRejected` instead of `onFilesAdded`. |
|
|
57
|
+
| `maxFiles` | `number` | Maximum total number of files allowed in `files`. Files that would exceed it go to `onFilesRejected` instead of `onFilesAdded`. |
|
|
58
|
+
| `onFilesRejected` | `(files: File[]) => void` | Called with files rejected for exceeding `maxSize`/`maxFiles` or not matching `accept`. |
|
|
59
|
+
| `invalidFileTypeMessage` | `React.ReactNode` | Error message shown when a file is rejected for not matching `accept`. Defaults to `"File type not accepted"`. An explicit `error` prop always takes priority over this. |
|
|
60
|
+
| `maxFilesMessage` | `React.ReactNode` | Error message shown when a file is rejected for exceeding `maxFiles`. Defaults to `"Maximum of {maxFiles} files allowed"`. An explicit `error` prop always takes priority over this. |
|
|
61
|
+
| `icon` | `React.ReactNode` | Icon shown above the dropzone label. Defaults to the built-in upload icon. |
|
|
62
|
+
| `dropzoneLabel` | `React.ReactNode` | Text shown inside the dropzone. Defaults to `"Drag and drop files here to upload"`. |
|
|
63
|
+
| `browseButtonLabel` | `React.ReactNode` | Label for the button that opens the native file picker. Defaults to `"Browse files"`. |
|
|
64
|
+
| `removeFileLabel` | `string` | Screen-reader label for each file chip's remove button. Defaults to `"Remove"`. |
|
|
65
|
+
| `disabled` | `boolean` | Disables the dropzone, browse button, and every file chip's remove icon. |
|
|
66
|
+
| `readOnly` | `boolean` | Renders `files` as a static chip list with no remove icon, and omits the dropzone/browse button entirely. |
|
|
67
|
+
|
|
68
|
+
`FileUpload` also accepts the standard Recursica form-control props (`label`, `assistiveText`, `error`, `required`, `withAsterisk`, `formLayout`, `labelSize`, `labelAlignment`, `labelOptionalText`, `labelWithEditIcon`, `onLabelEditClick`) — see [FormControlWrapper's USAGE.md](../FormControlWrapper/USAGE.md) for how these behave.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 4. Rejecting Oversized Files
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<FileUpload
|
|
76
|
+
label="Upload Files"
|
|
77
|
+
assistiveText="Max file size 5MB"
|
|
78
|
+
maxSize={5 * 1024 * 1024}
|
|
79
|
+
files={files}
|
|
80
|
+
onFilesAdded={(added) =>
|
|
81
|
+
setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
|
|
82
|
+
}
|
|
83
|
+
onFilesRejected={(rejected) =>
|
|
84
|
+
setError(`${rejected.length} file(s) exceeded the 5MB limit.`)
|
|
85
|
+
}
|
|
86
|
+
onFileRemove={(id) =>
|
|
87
|
+
setFiles((prev) =>
|
|
88
|
+
prev.filter((item) => (item.id ?? item.file.name) !== id),
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 5. Rejecting Files by Extension/MIME Type
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
<FileUpload
|
|
100
|
+
label="Upload Files"
|
|
101
|
+
assistiveText="Only .pdf and .png files are accepted"
|
|
102
|
+
accept=".pdf,.png"
|
|
103
|
+
files={files}
|
|
104
|
+
onFilesAdded={(added) =>
|
|
105
|
+
setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
|
|
106
|
+
}
|
|
107
|
+
onFileRemove={(id) =>
|
|
108
|
+
setFiles((prev) =>
|
|
109
|
+
prev.filter((item) => (item.id ?? item.file.name) !== id),
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
/>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
This applies equally to a file picked via "Browse files" and one dragged directly onto the
|
|
116
|
+
dropzone — the browser's own `accept` filtering never covers drag-and-drop, so `FileUpload`
|
|
117
|
+
re-validates it itself before calling `onFilesAdded`/`onFilesRejected`.
|
|
118
|
+
|
|
119
|
+
A mismatched file automatically puts the control into its error state with the message
|
|
120
|
+
`"File type not accepted"` — no need to wire `onFilesRejected` into your own `error` prop just to
|
|
121
|
+
show something. Override the message with `invalidFileTypeMessage`, or pass your own `error` prop
|
|
122
|
+
to take over the error state entirely:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<FileUpload
|
|
126
|
+
label="Upload Files"
|
|
127
|
+
accept=".pdf,.png"
|
|
128
|
+
invalidFileTypeMessage="Only PDF and PNG files are supported"
|
|
129
|
+
files={files}
|
|
130
|
+
onFilesAdded={(added) =>
|
|
131
|
+
setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
|
|
132
|
+
}
|
|
133
|
+
onFileRemove={(id) =>
|
|
134
|
+
setFiles((prev) =>
|
|
135
|
+
prev.filter((item) => (item.id ?? item.file.name) !== id),
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
/>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 6. Limiting the Number of Files
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
<FileUpload
|
|
147
|
+
label="Upload Files"
|
|
148
|
+
assistiveText="Up to 2 files allowed"
|
|
149
|
+
maxFiles={2}
|
|
150
|
+
files={files}
|
|
151
|
+
onFilesAdded={(added) =>
|
|
152
|
+
setFiles((prev) => [...prev, ...added.map((file) => ({ file }))])
|
|
153
|
+
}
|
|
154
|
+
onFileRemove={(id) =>
|
|
155
|
+
setFiles((prev) =>
|
|
156
|
+
prev.filter((item) => (item.id ?? item.file.name) !== id),
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
/>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Once `files` reaches `maxFiles`, further dropped/picked files are rejected the same way an
|
|
163
|
+
`accept` mismatch is — automatically switching the control into its error state with the default
|
|
164
|
+
`maxFilesMessage` ("Maximum of 2 files allowed" for the example above). Override the message with
|
|
165
|
+
`maxFilesMessage`, or pass your own `error` prop to take over the error state entirely.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 7. Read-only Mode
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<FileUpload label="Uploaded Files" readOnly files={files} />
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Renders `files` as a plain, non-removable chip list with no dropzone or Browse button — for
|
|
176
|
+
displaying files that were already submitted and can no longer be changed. `onFilesAdded`/
|
|
177
|
+
`onFileRemove` aren't called in this mode since there's nothing to add or remove.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 8. Keyboard Navigation of the File List
|
|
182
|
+
|
|
183
|
+
Once files are selected, their chips form a single roving-tabindex group, not one tab stop per
|
|
184
|
+
chip: `Tab` lands on the first chip's remove icon, `Enter`/`Space` removes the focused chip, and
|
|
185
|
+
`ArrowLeft`/`ArrowRight`/`ArrowUp`/`ArrowDown` move focus between chips (wrapping at both ends).
|
|
186
|
+
This is a group-level pattern, not an option on `Chip` used standalone elsewhere. (Not applicable
|
|
187
|
+
in `readOnly` mode, which has no remove icons to navigate to.)
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 9. Design System Integration
|
|
192
|
+
|
|
193
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
194
|
+
|
|
195
|
+
> [!IMPORTANT]
|
|
196
|
+
>
|
|
197
|
+
> - **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.
|
|
198
|
+
> - **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.
|
|
199
|
+
> - **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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./FileUpload";
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Flex } from "./Flex";
|
|
4
|
+
import { Button } from "../Button";
|
|
5
|
+
import { Text } from "../Text/Text";
|
|
6
|
+
|
|
7
|
+
type FlexStoryProps = React.ComponentProps<typeof Flex>;
|
|
8
|
+
|
|
9
|
+
const meta: Meta<FlexStoryProps> = {
|
|
10
|
+
title: "UI-Kit/Flex",
|
|
11
|
+
component: Flex,
|
|
12
|
+
tags: ["autodocs"],
|
|
13
|
+
parameters: {
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component:
|
|
17
|
+
"Flex is a bare-metal flex container that maps directly to Mantine's Flex component, providing unopinionated control over direction, alignment, and wrapping.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
args: {
|
|
22
|
+
gap: "rec-default",
|
|
23
|
+
align: "center",
|
|
24
|
+
justify: "flex-start",
|
|
25
|
+
direction: "row",
|
|
26
|
+
wrap: "wrap",
|
|
27
|
+
},
|
|
28
|
+
argTypes: {
|
|
29
|
+
gap: {
|
|
30
|
+
control: "select",
|
|
31
|
+
options: [
|
|
32
|
+
"rec-none",
|
|
33
|
+
"rec-sm",
|
|
34
|
+
"rec-default",
|
|
35
|
+
"rec-md",
|
|
36
|
+
"rec-lg",
|
|
37
|
+
"rec-xl",
|
|
38
|
+
"rec-2xl",
|
|
39
|
+
"xs",
|
|
40
|
+
"sm",
|
|
41
|
+
"md",
|
|
42
|
+
"lg",
|
|
43
|
+
"xl",
|
|
44
|
+
],
|
|
45
|
+
description: "Gap between elements",
|
|
46
|
+
},
|
|
47
|
+
direction: {
|
|
48
|
+
control: "select",
|
|
49
|
+
options: ["row", "column", "row-reverse", "column-reverse"],
|
|
50
|
+
description: "Flex-direction property",
|
|
51
|
+
},
|
|
52
|
+
align: {
|
|
53
|
+
control: "select",
|
|
54
|
+
options: ["flex-start", "center", "flex-end", "stretch"],
|
|
55
|
+
description: "Align-items property",
|
|
56
|
+
},
|
|
57
|
+
justify: {
|
|
58
|
+
control: "select",
|
|
59
|
+
options: [
|
|
60
|
+
"flex-start",
|
|
61
|
+
"center",
|
|
62
|
+
"flex-end",
|
|
63
|
+
"space-between",
|
|
64
|
+
"space-around",
|
|
65
|
+
],
|
|
66
|
+
description: "Justify-content property",
|
|
67
|
+
},
|
|
68
|
+
wrap: {
|
|
69
|
+
control: "select",
|
|
70
|
+
options: ["wrap", "nowrap", "wrap-reverse"],
|
|
71
|
+
description: "Flex-wrap property",
|
|
72
|
+
},
|
|
73
|
+
defaultChecked: {
|
|
74
|
+
table: { disable: true },
|
|
75
|
+
},
|
|
76
|
+
rowGap: {
|
|
77
|
+
table: { disable: true },
|
|
78
|
+
},
|
|
79
|
+
columnGap: {
|
|
80
|
+
table: { disable: true },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export default meta;
|
|
86
|
+
|
|
87
|
+
type Story = StoryObj<FlexStoryProps>;
|
|
88
|
+
|
|
89
|
+
export const Default: Story = {
|
|
90
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
91
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
92
|
+
<Flex {...args}>
|
|
93
|
+
<Button variant="solid">Block A</Button>
|
|
94
|
+
<Button variant="outline">Block B</Button>
|
|
95
|
+
<Text>Text inside Flex</Text>
|
|
96
|
+
</Flex>
|
|
97
|
+
),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const StaticGapSmallColumn: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
gap: "rec-sm",
|
|
103
|
+
direction: "column",
|
|
104
|
+
},
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
106
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
107
|
+
<Flex {...args}>
|
|
108
|
+
<Button variant="solid">Item 1</Button>
|
|
109
|
+
<Button variant="solid">Item 2</Button>
|
|
110
|
+
<Button variant="solid">Item 3</Button>
|
|
111
|
+
</Flex>
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const StaticGapLargeRow: Story = {
|
|
116
|
+
args: {
|
|
117
|
+
gap: "rec-xl",
|
|
118
|
+
direction: "row",
|
|
119
|
+
},
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
121
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
122
|
+
<Flex {...args}>
|
|
123
|
+
<Button variant="solid">Item 1</Button>
|
|
124
|
+
<Button variant="solid">Item 2</Button>
|
|
125
|
+
<Button variant="solid">Item 3</Button>
|
|
126
|
+
</Flex>
|
|
127
|
+
),
|
|
128
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Flex component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flex layout wrapper.
|
|
3
|
+
*
|
|
4
|
+
* NOTE: MUI does not have a native `<Flex>` component (it relies on `<Box display="flex">`
|
|
5
|
+
* or `<Stack>`). Per the layout-components rule, when a UI kit lacks an equivalent component
|
|
6
|
+
* it's built following a prop definition similar to Mantine's own `Flex` (gap/rowGap/columnGap/
|
|
7
|
+
* direction/align/justify/wrap) — this shape is owned locally here, not shared as a formal
|
|
8
|
+
* cross-adapter Recursica contract.
|
|
9
|
+
*
|
|
10
|
+
* Like Stack and Group, this is a primitive layout component. It strictly filters out the
|
|
11
|
+
* `sx` prop using `OmitSx` and `filterSxProp` to enforce the use of standard layout scales.
|
|
12
|
+
*/
|
|
13
|
+
import { forwardRef } from "react";
|
|
14
|
+
import { Box as MUIBox, type BoxProps as MUIBoxProps } from "@mui/material";
|
|
15
|
+
import {
|
|
16
|
+
SPACING_MAP,
|
|
17
|
+
type OmitSx,
|
|
18
|
+
filterSxProp,
|
|
19
|
+
type WithRecursicaSpacing,
|
|
20
|
+
} from "../../utils/filterStylingProps";
|
|
21
|
+
|
|
22
|
+
interface FlexOwnProps {
|
|
23
|
+
/** Global gap spacing key or CSS value */
|
|
24
|
+
gap?: string | number;
|
|
25
|
+
/** Horizontal row spacing */
|
|
26
|
+
rowGap?: string | number;
|
|
27
|
+
/** Vertical column spacing */
|
|
28
|
+
columnGap?: string | number;
|
|
29
|
+
/** Flex direction */
|
|
30
|
+
direction?: React.CSSProperties["flexDirection"];
|
|
31
|
+
/** Align items */
|
|
32
|
+
align?: React.CSSProperties["alignItems"];
|
|
33
|
+
/** Justify content */
|
|
34
|
+
justify?: React.CSSProperties["justifyContent"];
|
|
35
|
+
/** Flex wrap */
|
|
36
|
+
wrap?: React.CSSProperties["flexWrap"];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type FlexProps = WithRecursicaSpacing<
|
|
40
|
+
OmitSx<MUIBoxProps & FlexOwnProps>
|
|
41
|
+
>;
|
|
42
|
+
|
|
43
|
+
export const Flex = forwardRef<HTMLDivElement, FlexProps>(function Flex(
|
|
44
|
+
{
|
|
45
|
+
children,
|
|
46
|
+
gap = "rec-default",
|
|
47
|
+
rowGap,
|
|
48
|
+
columnGap,
|
|
49
|
+
direction,
|
|
50
|
+
align,
|
|
51
|
+
justify,
|
|
52
|
+
wrap,
|
|
53
|
+
...rest
|
|
54
|
+
},
|
|
55
|
+
ref,
|
|
56
|
+
) {
|
|
57
|
+
const safeProps = filterSxProp(rest as Record<string, unknown>);
|
|
58
|
+
const resolvedGap =
|
|
59
|
+
typeof gap === "string" && gap in SPACING_MAP
|
|
60
|
+
? SPACING_MAP[gap as keyof typeof SPACING_MAP]
|
|
61
|
+
: gap;
|
|
62
|
+
const resolvedRowGap =
|
|
63
|
+
typeof rowGap === "string" && rowGap in SPACING_MAP
|
|
64
|
+
? SPACING_MAP[rowGap as keyof typeof SPACING_MAP]
|
|
65
|
+
: rowGap;
|
|
66
|
+
const resolvedColumnGap =
|
|
67
|
+
typeof columnGap === "string" && columnGap in SPACING_MAP
|
|
68
|
+
? SPACING_MAP[columnGap as keyof typeof SPACING_MAP]
|
|
69
|
+
: columnGap;
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<MUIBox
|
|
73
|
+
ref={ref}
|
|
74
|
+
{...safeProps}
|
|
75
|
+
display="flex"
|
|
76
|
+
gap={resolvedGap}
|
|
77
|
+
rowGap={resolvedRowGap}
|
|
78
|
+
columnGap={resolvedColumnGap}
|
|
79
|
+
flexDirection={direction}
|
|
80
|
+
alignItems={align}
|
|
81
|
+
justifyContent={justify}
|
|
82
|
+
flexWrap={wrap}
|
|
83
|
+
>
|
|
84
|
+
{children}
|
|
85
|
+
</MUIBox>
|
|
86
|
+
);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
Flex.displayName = "Flex";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Flex - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Flex` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Flex } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Flex } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Flex gap="md" justify="space-between" align="center">
|
|
24
|
+
<Text>Item 1</Text>
|
|
25
|
+
<Text>Item 2</Text>
|
|
26
|
+
</Flex>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 3. Design System Integration
|
|
34
|
+
|
|
35
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
36
|
+
|
|
37
|
+
> [!IMPORTANT]
|
|
38
|
+
>
|
|
39
|
+
> - **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.
|
|
40
|
+
> - **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.
|
|
41
|
+
> - **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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Flex";
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
/* Recursica Reset Boundary */
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
display: flex;
|
|
5
|
+
margin: 0; /* Hardcoded structural reset */
|
|
6
|
+
width: 100%;
|
|
7
|
+
|
|
8
|
+
/* Recursica Layout Overrides mapped down dynamically from components */
|
|
9
|
+
padding: 0; /* Hardcoded structural reset */
|
|
10
|
+
max-width: var(--form-control-max-width);
|
|
11
|
+
min-width: var(--form-control-min-width);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* =========================================
|
|
15
|
+
LAYOUT MODES
|
|
16
|
+
========================================= */
|
|
17
|
+
|
|
18
|
+
.root[data-form-layout="stacked"] {
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.root[data-form-layout="side-by-side"] {
|
|
23
|
+
/* Aligns the Input/Component identically horizontally beside the label mapping */
|
|
24
|
+
flex-direction: row;
|
|
25
|
+
align-items: flex-start;
|
|
26
|
+
flex-wrap: wrap; /* Allows collapse if screen is too thin, though standard flex width should hold */
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* =========================================
|
|
30
|
+
GRID SECTIONS
|
|
31
|
+
========================================= */
|
|
32
|
+
|
|
33
|
+
.leftSection {
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
Stacked margins natively apply spacing *below* the label
|
|
41
|
+
*/
|
|
42
|
+
.root[data-form-layout="stacked"] .leftSection {
|
|
43
|
+
margin-bottom: var(
|
|
44
|
+
--recursica_ui-kit_globals_form_properties_label-field-gap-vertical
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
Side-by-side margins natively apply spacing *right* of the label
|
|
50
|
+
and forces vertical padding to align the label perfectly with 1st line of input text
|
|
51
|
+
*/
|
|
52
|
+
.root[data-form-layout="side-by-side"] .leftSection {
|
|
53
|
+
margin-right: var(
|
|
54
|
+
--recursica_ui-kit_components_label_variants_layouts_side-by-side_properties_gutter
|
|
55
|
+
);
|
|
56
|
+
padding-top: var(
|
|
57
|
+
--recursica_ui-kit_components_label_variants_layouts_side-by-side_properties_vertical-padding
|
|
58
|
+
);
|
|
59
|
+
min-height: var(
|
|
60
|
+
--recursica_ui-kit_components_label_variants_layouts_side-by-side_properties_min-height
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Label column sizing hooks (Only applies functionally in side-by-side mode) */
|
|
65
|
+
.root[data-form-layout="side-by-side"] .leftSection[data-label-size="small"] {
|
|
66
|
+
width: var(
|
|
67
|
+
--recursica_ui-kit_components_label_variants_layouts_side-by-side_variants_sizes_small_properties_width
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.root[data-form-layout="side-by-side"] .leftSection[data-label-size="default"] {
|
|
72
|
+
width: var(
|
|
73
|
+
--recursica_ui-kit_components_label_variants_layouts_side-by-side_variants_sizes_default_properties_width
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.root[data-form-layout="side-by-side"] .leftSection[data-label-size="md"] {
|
|
78
|
+
/* No 'medium' defined explicitly in generated token scope, mapped fallback to default */
|
|
79
|
+
width: var(
|
|
80
|
+
--recursica_ui-kit_components_label_variants_layouts_side-by-side_variants_sizes_default_properties_width
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/*
|
|
85
|
+
Right Section dynamically wraps the input element natively
|
|
86
|
+
*/
|
|
87
|
+
.rightSection {
|
|
88
|
+
display: flex; /* Groups internal field alongside subsequent errors/descriptions */
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
flex: 1; /* Consumes the remaining x-axis in grid columns natively */
|
|
91
|
+
min-width: 0; /* Break boundary preventing internal flex explosion */
|
|
92
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { FormControlLayout } from "./FormControlLayout";
|
|
3
|
+
import { Switch } from "../Switch/Switch";
|
|
4
|
+
import { Label } from "../Label/Label";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof FormControlLayout> = {
|
|
7
|
+
title: "UI-Kit/FormControlLayout",
|
|
8
|
+
component: FormControlLayout,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "padded",
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component:
|
|
14
|
+
"A layout component used to correctly position form inputs alongside their labels.\n\n**When to use this:**\nTypically, you should use `FormControlWrapper` instead, which uses this component under the hood to handle layout automatically.\n\nHowever, this component is useful when you need to align standalone inputs (like a `Switch` or `Checkbox` without a label) so they perfectly match the spacing and alignment of your other form fields in a `side-by-side` layout.",
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
tags: ["autodocs"],
|
|
19
|
+
argTypes: {
|
|
20
|
+
formLayout: {
|
|
21
|
+
control: "radio",
|
|
22
|
+
options: ["stacked", "side-by-side"],
|
|
23
|
+
},
|
|
24
|
+
labelSize: {
|
|
25
|
+
control: "radio",
|
|
26
|
+
options: ["default", "small"],
|
|
27
|
+
description: "Dictates the physical width of the left column.",
|
|
28
|
+
},
|
|
29
|
+
children: {
|
|
30
|
+
table: { disable: true },
|
|
31
|
+
},
|
|
32
|
+
leftSection: {
|
|
33
|
+
table: { disable: true },
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export default meta;
|
|
39
|
+
type Story = StoryObj<typeof FormControlLayout>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The Default layout demonstrates wrapping a standalone primitive without a Label.
|
|
43
|
+
* In a stacked layout, an omitted leftSection naturally results in no structural padding.
|
|
44
|
+
*/
|
|
45
|
+
export const Default: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
formLayout: "stacked",
|
|
48
|
+
labelSize: "default",
|
|
49
|
+
leftSection: (
|
|
50
|
+
<div
|
|
51
|
+
style={{ padding: 8, border: "1px dashed #ccc", background: "#fafafa" }}
|
|
52
|
+
>
|
|
53
|
+
Left Section Boundary
|
|
54
|
+
</div>
|
|
55
|
+
),
|
|
56
|
+
children: <Switch label="Input area content" />,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Demonstrates the stacked layout without a left section.
|
|
62
|
+
* The input should natively pull flush to the top left since there is no left column.
|
|
63
|
+
*/
|
|
64
|
+
export const StackedLayout: Story = {
|
|
65
|
+
args: {
|
|
66
|
+
formLayout: "stacked",
|
|
67
|
+
labelSize: "default",
|
|
68
|
+
children: <Switch label="Flush stacked switch" />,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Demonstrates how a naked boolean primitive perfectly aligns in a side-by-side layout
|
|
74
|
+
* by utilizing the layout wrapper. The left column maintains its precise design system width
|
|
75
|
+
* even when `leftSection` is undefined, forcing the component into the correct form column!
|
|
76
|
+
*/
|
|
77
|
+
export const SideBySideLayout: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
formLayout: "side-by-side",
|
|
80
|
+
labelSize: "default",
|
|
81
|
+
children: <Switch label="Offset switch aligning with grid" />,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A real Label (not a placeholder) in a stacked layout, at `labelSize="default"`. Even
|
|
87
|
+
* though the label sits above the field rather than beside it, its own column still caps
|
|
88
|
+
* to the design system's stacked-layout width (224px) rather than stretching to the full
|
|
89
|
+
* container — long label text wraps instead of spanning edge-to-edge.
|
|
90
|
+
*/
|
|
91
|
+
export const StackedLayoutWithLabelDefault: Story = {
|
|
92
|
+
args: {
|
|
93
|
+
formLayout: "stacked",
|
|
94
|
+
labelSize: "default",
|
|
95
|
+
leftSection: (
|
|
96
|
+
<Label labelSize="default">
|
|
97
|
+
A fairly long label to show the stacked-layout width cap in action
|
|
98
|
+
</Label>
|
|
99
|
+
),
|
|
100
|
+
children: <Switch label="Input area content" />,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Same as above, at `labelSize="small"` — the stacked-layout width cap is narrower (80px).
|
|
106
|
+
*/
|
|
107
|
+
export const StackedLayoutWithLabelSmall: Story = {
|
|
108
|
+
args: {
|
|
109
|
+
formLayout: "stacked",
|
|
110
|
+
labelSize: "small",
|
|
111
|
+
leftSection: (
|
|
112
|
+
<Label labelSize="small">
|
|
113
|
+
A fairly long label to show the stacked-layout width cap in action
|
|
114
|
+
</Label>
|
|
115
|
+
),
|
|
116
|
+
children: <Switch label="Input area content" />,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future FormControlLayout component tests. Add tests here if/when needed.
|