@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,72 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { filterStylingProps } from "../../utils/filterStylingProps";
|
|
3
|
+
import styles from "./FormControlLayout.module.css";
|
|
4
|
+
|
|
5
|
+
import { type RecursicaFormControlLayoutProps } from "@recursica/adapter-common";
|
|
6
|
+
|
|
7
|
+
export interface FormControlLayoutProps
|
|
8
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
9
|
+
RecursicaFormControlLayoutProps {
|
|
10
|
+
overStyled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const FormControlLayout = React.forwardRef<
|
|
14
|
+
HTMLDivElement,
|
|
15
|
+
FormControlLayoutProps
|
|
16
|
+
>(function FormControlLayout(props, ref) {
|
|
17
|
+
const {
|
|
18
|
+
overStyled = false,
|
|
19
|
+
formLayout = "stacked",
|
|
20
|
+
labelSize = "default",
|
|
21
|
+
controlMaxWidth,
|
|
22
|
+
controlMinWidth,
|
|
23
|
+
leftSection,
|
|
24
|
+
className,
|
|
25
|
+
children,
|
|
26
|
+
style,
|
|
27
|
+
...rest
|
|
28
|
+
} = props;
|
|
29
|
+
|
|
30
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
ref={ref}
|
|
35
|
+
{...sanitizedProps}
|
|
36
|
+
className={className ? `${styles.root} ${className}` : styles.root}
|
|
37
|
+
data-form-layout={formLayout}
|
|
38
|
+
style={
|
|
39
|
+
{
|
|
40
|
+
...style,
|
|
41
|
+
...(controlMaxWidth
|
|
42
|
+
? { "--form-control-max-width": controlMaxWidth }
|
|
43
|
+
: {}),
|
|
44
|
+
...(controlMinWidth
|
|
45
|
+
? { "--form-control-min-width": controlMinWidth }
|
|
46
|
+
: {}),
|
|
47
|
+
} as React.CSSProperties
|
|
48
|
+
}
|
|
49
|
+
>
|
|
50
|
+
{/*
|
|
51
|
+
The left section strictly enforces the Label boundary sizes
|
|
52
|
+
We render it unconditionally if side-by-side to preserve the grid column layout
|
|
53
|
+
*/}
|
|
54
|
+
{formLayout === "side-by-side" ? (
|
|
55
|
+
<div className={styles.leftSection} data-label-size={labelSize}>
|
|
56
|
+
{leftSection}
|
|
57
|
+
</div>
|
|
58
|
+
) : (
|
|
59
|
+
leftSection && (
|
|
60
|
+
<div className={styles.leftSection} data-label-size={labelSize}>
|
|
61
|
+
{leftSection}
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
{/* The main content area natively flows into the remaining space */}
|
|
67
|
+
<div className={styles.rightSection}>{children}</div>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
FormControlLayout.displayName = "FormControlLayout";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# FormControlLayout - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `FormControlLayout` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { FormControlLayout } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { FormControlLayout } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<FormControlLayout label="Input Field" required>
|
|
24
|
+
<input type="text" />
|
|
25
|
+
</FormControlLayout>
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./FormControlLayout";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# FormControlWrapper Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Architectural Philosophy
|
|
4
|
+
|
|
5
|
+
Unlike the Mantine adapter (which tears out `Input.Wrapper` entirely), this adapter still
|
|
6
|
+
renders MUI's native `FormControl` as the root — MUI's own `disabled`/`error`/`focused`
|
|
7
|
+
cascading via `FormControlContext` to descendants is useful and kept. What's rebuilt on top is
|
|
8
|
+
label tracking, ARIA generation, and the help/error text block, mirroring the Mantine adapter's
|
|
9
|
+
own approach for consistency across frameworks.
|
|
10
|
+
|
|
11
|
+
### 1. Self-generated `id` fallback
|
|
12
|
+
|
|
13
|
+
MUI's `FormControl` doesn't generate or require an `id` itself — every ARIA relationship below
|
|
14
|
+
depends on having one. `React.useId()` provides a fallback (`recursica-fc-${generatedId}`)
|
|
15
|
+
whenever the caller doesn't pass their own `id`, matching the Mantine adapter, so the aria
|
|
16
|
+
wiring below fires by default instead of only when a caller happens to supply an `id`.
|
|
17
|
+
|
|
18
|
+
### 2. The `cloneElement` ARIA map
|
|
19
|
+
|
|
20
|
+
Same reasoning as the Mantine adapter: `aria-labelledby`/`aria-describedby`/`aria-errormessage`
|
|
21
|
+
are generated from the resolved `id` and injected onto the child field via `React.cloneElement`,
|
|
22
|
+
since there's no shared context gluing the field to this wrapper's label/assistive text.
|
|
23
|
+
|
|
24
|
+
- `aria-describedby` and `aria-errormessage` use **separate ids** (`${id}-assistive` /
|
|
25
|
+
`${id}-error`) rather than one shared id — help text and error text are never both visible
|
|
26
|
+
at once (error takes priority, same as Mantine), but keeping the ids distinct means each
|
|
27
|
+
attribute only ever points at content that's actually relevant to it.
|
|
28
|
+
- Neither is set if the child already carries its own explicit `aria-describedby`/
|
|
29
|
+
`aria-errormessage` — `cloneElement` never overwrites a caller's own value.
|
|
30
|
+
|
|
31
|
+
### 3. Strict `AssistiveElement` coupling
|
|
32
|
+
|
|
33
|
+
Same as Mantine: no generic MUI `FormHelperText` used directly here. `FormControlWrapper`
|
|
34
|
+
renders `<AssistiveElement>` itself, resolving to `"error"` or `"help"` depending on whether
|
|
35
|
+
`error` is set, and passing whichever id (`errorId`/`assistiveId`) matches.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*
|
|
2
|
+
FORM CONTROL WRAPPER
|
|
3
|
+
Strict architectural layout mapping handling grid bounds around MUI Form Controls natively.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.root {
|
|
7
|
+
/* Inherit MUI Reset overrides */
|
|
8
|
+
display: block;
|
|
9
|
+
width: 100%;
|
|
10
|
+
|
|
11
|
+
/* Global Form Field Colors */
|
|
12
|
+
--form-field-background: var(
|
|
13
|
+
--recursica_ui-kit_globals_form_field_colors_background-color
|
|
14
|
+
);
|
|
15
|
+
--form-field-background-read-only: var(
|
|
16
|
+
--recursica_ui-kit_globals_form_field_colors_background-color-read-only
|
|
17
|
+
);
|
|
18
|
+
--form-field-border: var(
|
|
19
|
+
--recursica_ui-kit_globals_form_field_colors_border-color
|
|
20
|
+
);
|
|
21
|
+
--form-field-border-error: var(
|
|
22
|
+
--recursica_ui-kit_globals_form_field_colors_error-border-color
|
|
23
|
+
);
|
|
24
|
+
--form-field-border-selected: var(
|
|
25
|
+
--recursica_ui-kit_globals_form_field_colors_border-selected
|
|
26
|
+
);
|
|
27
|
+
--form-field-disabled-background: var(
|
|
28
|
+
--recursica_ui-kit_globals_form_field_colors_disabled-background-color
|
|
29
|
+
);
|
|
30
|
+
--form-field-disabled-text: var(
|
|
31
|
+
--recursica_ui-kit_globals_form_field_colors_disabled-text
|
|
32
|
+
);
|
|
33
|
+
--form-field-icon: var(
|
|
34
|
+
--recursica_ui-kit_globals_form_field_colors_icon-color
|
|
35
|
+
);
|
|
36
|
+
--form-field-placeholder-text-opacity: var(
|
|
37
|
+
--recursica_ui-kit_globals_form_field_colors_placeholder-text-opacity
|
|
38
|
+
);
|
|
39
|
+
--form-field-text-valued: var(
|
|
40
|
+
--recursica_ui-kit_globals_form_field_colors_text-valued
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
/* Global Form Field Geometric Sizes */
|
|
44
|
+
/* No focus-specific border-color/border-size tokens exist anymore; components use the generic
|
|
45
|
+
--recursica_brand_states_focus_* ring tokens directly instead (see e.g. TextField.module.css). */
|
|
46
|
+
--form-field-border-radius: var(
|
|
47
|
+
--recursica_ui-kit_globals_form_field_size_border-radius
|
|
48
|
+
);
|
|
49
|
+
--form-field-border-size-default: var(
|
|
50
|
+
--recursica_ui-kit_globals_form_field_size_border-size-default
|
|
51
|
+
);
|
|
52
|
+
--form-field-horizontal-padding: var(
|
|
53
|
+
--recursica_ui-kit_globals_form_field_size_horizontal-padding
|
|
54
|
+
);
|
|
55
|
+
--form-field-icon-size: var(--recursica_ui-kit_globals_form_field_size_icon);
|
|
56
|
+
--form-field-icon-text-gap: var(
|
|
57
|
+
--recursica_ui-kit_globals_form_field_size_icon-text-gap
|
|
58
|
+
);
|
|
59
|
+
--form-field-max-width: var(
|
|
60
|
+
--recursica_ui-kit_globals_form_field_size_max-width
|
|
61
|
+
);
|
|
62
|
+
--form-field-min-width: var(
|
|
63
|
+
--recursica_ui-kit_globals_form_field_size_min-width
|
|
64
|
+
);
|
|
65
|
+
--form-field-single-line-input-height: var(
|
|
66
|
+
--recursica_ui-kit_globals_form_field_size_single-line-input-height
|
|
67
|
+
);
|
|
68
|
+
--form-field-vertical-gutter: var(
|
|
69
|
+
--recursica_ui-kit_globals_form_field_size_vertical-gutter
|
|
70
|
+
);
|
|
71
|
+
--form-field-vertical-padding: var(
|
|
72
|
+
--recursica_ui-kit_globals_form_field_size_vertical-padding
|
|
73
|
+
);
|
|
74
|
+
color: var(--form-field-text-valued);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.inputSection {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
flex: 1;
|
|
81
|
+
min-width: 0;
|
|
82
|
+
}
|
|
83
|
+
.assistive {
|
|
84
|
+
margin-top: var(
|
|
85
|
+
--recursica_ui-kit_globals_form_properties_label-field-gap-vertical
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import {
|
|
3
|
+
FormControlWrapper,
|
|
4
|
+
type FormControlWrapperProps,
|
|
5
|
+
} from "./FormControlWrapper";
|
|
6
|
+
import { TextField } from "../TextField/TextField";
|
|
7
|
+
import { formControlArgTypes } from "../../../.storybook/commonArgTypes";
|
|
8
|
+
|
|
9
|
+
type WrapperStoryProps = FormControlWrapperProps;
|
|
10
|
+
|
|
11
|
+
const meta: Meta<WrapperStoryProps> = {
|
|
12
|
+
title: "UI-Kit/FormControlWrapper",
|
|
13
|
+
component: FormControlWrapper,
|
|
14
|
+
tags: ["autodocs"],
|
|
15
|
+
parameters: {
|
|
16
|
+
docs: {
|
|
17
|
+
description: {
|
|
18
|
+
component:
|
|
19
|
+
"The `FormControlWrapper` is the ultimate structural replacement for Mantine's built-in `Input.Wrapper`. By abandoning Mantine's opinionated wrappers entirely, we centralize all label tracking, error rendering, ARIA generation, and grid layouts natively inside this single component.\n\n### Usage with Naked Primitives\nThis component wraps 'naked' elements like `<Input>` directly. The demonstration stories below utilize `<TextField>` as a native display vehicle, since `<TextField>` natively pipes all its properties structurally back into this wrapper.",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
argTypes: {
|
|
24
|
+
...formControlArgTypes,
|
|
25
|
+
error: {
|
|
26
|
+
control: "text",
|
|
27
|
+
description:
|
|
28
|
+
"Error string driving native assistive component and validation markers.",
|
|
29
|
+
},
|
|
30
|
+
assistiveText: {
|
|
31
|
+
control: "text",
|
|
32
|
+
description:
|
|
33
|
+
"Helper instructions safely dynamically anchored below the input box.",
|
|
34
|
+
},
|
|
35
|
+
assistiveWithIcon: {
|
|
36
|
+
control: "boolean",
|
|
37
|
+
},
|
|
38
|
+
required: {
|
|
39
|
+
control: "boolean",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default meta;
|
|
45
|
+
|
|
46
|
+
type Story = StoryObj<WrapperStoryProps>;
|
|
47
|
+
|
|
48
|
+
const renderWithTextField = (args: WrapperStoryProps) => (
|
|
49
|
+
// We explicitly cast args to 'any' here because Mantine enforces strict anatomy types for
|
|
50
|
+
// 'classNames', 'styles', and 'attributes'. WrapperStoryProps defines these for the Wrapper anatomy,
|
|
51
|
+
// but TextField expects them for the full TextInput anatomy, causing a TS intersection mismatch.
|
|
52
|
+
<TextField
|
|
53
|
+
placeholder="Form Control primitive mapped..."
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
{...(args as any)}
|
|
56
|
+
/>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
export const Default: Story = {
|
|
60
|
+
args: {
|
|
61
|
+
label: "Account Username",
|
|
62
|
+
formLayout: "stacked",
|
|
63
|
+
assistiveText: "Validation occurs immediately natively.",
|
|
64
|
+
},
|
|
65
|
+
render: renderWithTextField,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const VisualErrorState: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
label: "Encryption Protocol",
|
|
71
|
+
formLayout: "stacked",
|
|
72
|
+
error: "Strict validation limits reached. Handshake rejected securely.",
|
|
73
|
+
},
|
|
74
|
+
render: renderWithTextField,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const RequiredArchitecture: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
label: "Root Password",
|
|
80
|
+
formLayout: "side-by-side",
|
|
81
|
+
required: true,
|
|
82
|
+
assistiveText: "Bypass string structure required to initiate protocol.",
|
|
83
|
+
},
|
|
84
|
+
render: renderWithTextField,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export const WithoutAssistiveIcons: Story = {
|
|
88
|
+
args: {
|
|
89
|
+
label: "Server Domain",
|
|
90
|
+
assistiveText:
|
|
91
|
+
"A standard text boundary without default native icon parameters bounding.",
|
|
92
|
+
assistiveWithIcon: false,
|
|
93
|
+
},
|
|
94
|
+
render: renderWithTextField,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const NativeChildrenDirectly: Story = {
|
|
98
|
+
parameters: {
|
|
99
|
+
docs: {
|
|
100
|
+
description: {
|
|
101
|
+
story:
|
|
102
|
+
"Bypassing the TextField map to show exactly how native `<input>` hooks execute inside the raw wrapper natively perfectly.",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
args: {
|
|
107
|
+
label: "Raw HTML Checkbox",
|
|
108
|
+
formLayout: "side-by-side",
|
|
109
|
+
assistiveText: "This wraps a raw HTML input tag mapping correctly.",
|
|
110
|
+
},
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
112
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
113
|
+
<div
|
|
114
|
+
style={{
|
|
115
|
+
display: "flex",
|
|
116
|
+
gap: "10px",
|
|
117
|
+
alignItems: "center",
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
{/* We can cleanly wrap even un-styled HTML primitives! */}
|
|
121
|
+
<FormControlWrapper {...args}>
|
|
122
|
+
<input
|
|
123
|
+
type="checkbox"
|
|
124
|
+
style={{ margin: 0, width: "16px", height: "16px" }}
|
|
125
|
+
/>
|
|
126
|
+
</FormControlWrapper>
|
|
127
|
+
</div>
|
|
128
|
+
),
|
|
129
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future FormControlWrapper component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useId } from "react";
|
|
2
|
+
import { FormControl, type FormControlProps } from "@mui/material";
|
|
3
|
+
import { filterStylingProps } from "../../utils/filterStylingProps";
|
|
4
|
+
import { Label } from "../Label/Label";
|
|
5
|
+
import { AssistiveElement } from "../AssistiveElement/AssistiveElement";
|
|
6
|
+
import { FormControlLayout } from "../FormControlLayout/FormControlLayout";
|
|
7
|
+
import styles from "./FormControlWrapper.module.css";
|
|
8
|
+
|
|
9
|
+
import { type RecursicaFormControlWrapperProps as BaseRecursicaFormControlWrapperProps } from "@recursica/adapter-common";
|
|
10
|
+
|
|
11
|
+
export interface RecursicaFormControlWrapperProps
|
|
12
|
+
extends Omit<
|
|
13
|
+
FormControlProps,
|
|
14
|
+
"margin" | "variant" | "size" | "color" | "error"
|
|
15
|
+
>,
|
|
16
|
+
BaseRecursicaFormControlWrapperProps {
|
|
17
|
+
overStyled?: boolean;
|
|
18
|
+
label?: React.ReactNode;
|
|
19
|
+
focused?: boolean;
|
|
20
|
+
error?: React.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type FormControlWrapperProps = RecursicaFormControlWrapperProps;
|
|
24
|
+
|
|
25
|
+
export const FormControlWrapper = React.forwardRef<
|
|
26
|
+
HTMLDivElement,
|
|
27
|
+
FormControlWrapperProps
|
|
28
|
+
>(function FormControlWrapper(props, ref) {
|
|
29
|
+
const {
|
|
30
|
+
overStyled = false,
|
|
31
|
+
label,
|
|
32
|
+
assistiveText,
|
|
33
|
+
description,
|
|
34
|
+
helperText,
|
|
35
|
+
assistiveWithIcon = true,
|
|
36
|
+
error,
|
|
37
|
+
required,
|
|
38
|
+
disabled,
|
|
39
|
+
focused,
|
|
40
|
+
id: userProvidedId,
|
|
41
|
+
|
|
42
|
+
formLayout = "stacked",
|
|
43
|
+
labelSize = "default",
|
|
44
|
+
labelOptionalText,
|
|
45
|
+
labelWithEditIcon,
|
|
46
|
+
onLabelEditClick,
|
|
47
|
+
labelActionArea,
|
|
48
|
+
|
|
49
|
+
controlMaxWidth,
|
|
50
|
+
controlMinWidth,
|
|
51
|
+
|
|
52
|
+
className,
|
|
53
|
+
style,
|
|
54
|
+
children,
|
|
55
|
+
...rest
|
|
56
|
+
} = props;
|
|
57
|
+
|
|
58
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
59
|
+
|
|
60
|
+
// Generate a reliable ID when the caller doesn't provide one — matches the Mantine adapter,
|
|
61
|
+
// and is what makes the aria wiring below actually fire by default instead of only when a
|
|
62
|
+
// caller happens to pass their own `id`.
|
|
63
|
+
const generatedId = useId();
|
|
64
|
+
const id = userProvidedId || `recursica-fc-${generatedId}`;
|
|
65
|
+
|
|
66
|
+
// Map descriptions fallback exactly like Mantine
|
|
67
|
+
const finalAssistiveText = assistiveText || description || helperText;
|
|
68
|
+
|
|
69
|
+
// ARIA Bindings — separate ids for help text and error text (matching Mantine) so each can
|
|
70
|
+
// be referenced independently via `aria-describedby`/`aria-errormessage` rather than sharing
|
|
71
|
+
// one id for both.
|
|
72
|
+
const labelId = `${id}-label`;
|
|
73
|
+
const assistiveId = finalAssistiveText ? `${id}-assistive` : undefined;
|
|
74
|
+
const errorId = error ? `${id}-error` : undefined;
|
|
75
|
+
|
|
76
|
+
// Wrap children safely cloning aria hooks down natively. Never clobber a child's own
|
|
77
|
+
// explicit aria-describedby/aria-errormessage, matching Mantine's guard.
|
|
78
|
+
const mappedChildren = React.Children.map(children, (child) => {
|
|
79
|
+
if (React.isValidElement(child)) {
|
|
80
|
+
const childProps = child.props as Record<string, unknown>;
|
|
81
|
+
return React.cloneElement(child, {
|
|
82
|
+
"aria-labelledby": labelId,
|
|
83
|
+
...(assistiveId && !childProps["aria-describedby"]
|
|
84
|
+
? { "aria-describedby": assistiveId }
|
|
85
|
+
: {}),
|
|
86
|
+
...(errorId && !childProps["aria-errormessage"]
|
|
87
|
+
? { "aria-errormessage": errorId }
|
|
88
|
+
: {}),
|
|
89
|
+
} as React.HTMLAttributes<HTMLElement>);
|
|
90
|
+
}
|
|
91
|
+
return child;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<FormControl
|
|
96
|
+
ref={ref}
|
|
97
|
+
{...(sanitizedProps as FormControlProps)}
|
|
98
|
+
error={!!error}
|
|
99
|
+
required={required}
|
|
100
|
+
disabled={disabled}
|
|
101
|
+
focused={focused}
|
|
102
|
+
className={className ? `${styles.root} ${className}` : styles.root}
|
|
103
|
+
style={style}
|
|
104
|
+
data-error={error ? "true" : undefined}
|
|
105
|
+
data-disabled={disabled ? "true" : undefined}
|
|
106
|
+
data-focused={focused ? "true" : undefined}
|
|
107
|
+
>
|
|
108
|
+
<FormControlLayout
|
|
109
|
+
formLayout={formLayout}
|
|
110
|
+
labelSize={labelSize}
|
|
111
|
+
controlMaxWidth={controlMaxWidth}
|
|
112
|
+
controlMinWidth={controlMinWidth}
|
|
113
|
+
leftSection={
|
|
114
|
+
label && (
|
|
115
|
+
<Label
|
|
116
|
+
id={labelId}
|
|
117
|
+
htmlFor={id}
|
|
118
|
+
required={required}
|
|
119
|
+
labelOptionalText={labelOptionalText}
|
|
120
|
+
labelWithEditIcon={labelWithEditIcon}
|
|
121
|
+
onLabelEditClick={onLabelEditClick}
|
|
122
|
+
labelActionArea={labelActionArea}
|
|
123
|
+
>
|
|
124
|
+
{label}
|
|
125
|
+
</Label>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
>
|
|
129
|
+
<div className={styles.inputSection}>
|
|
130
|
+
{/* Natively wrap children into flex box */}
|
|
131
|
+
{mappedChildren}
|
|
132
|
+
|
|
133
|
+
{/* Append native assistive block dynamically below the input */}
|
|
134
|
+
{(finalAssistiveText || error) && (
|
|
135
|
+
<AssistiveElement
|
|
136
|
+
id={error ? errorId : assistiveId}
|
|
137
|
+
assistiveVariant={error ? "error" : "help"}
|
|
138
|
+
assistiveWithIcon={assistiveWithIcon}
|
|
139
|
+
>
|
|
140
|
+
{error && typeof error === "string" ? error : finalAssistiveText}
|
|
141
|
+
</AssistiveElement>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
</FormControlLayout>
|
|
145
|
+
</FormControl>
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
FormControlWrapper.displayName = "FormControlWrapper";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# FormControlWrapper - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `FormControlWrapper` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { FormControlWrapper } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { FormControlWrapper } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<FormControlWrapper label="Email Address" required error="Invalid email">
|
|
24
|
+
<input type="email" />
|
|
25
|
+
</FormControlWrapper>
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./FormControlWrapper";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* HARDCODED VALUES:
|
|
3
|
+
* - Breakpoint pixel thresholds below (600/900/1200/1536) match MUI's own default
|
|
4
|
+
* theme.breakpoints (xs/sm/md/lg/xl). They drive `visibleFrom`/`hiddenFrom`, which
|
|
5
|
+
* have no native MUI Grid equivalent to hook into. If the consuming app customizes
|
|
6
|
+
* its MUI theme breakpoints, these thresholds will not follow that change —
|
|
7
|
+
* structural layout mechanics, not a design token.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.root {
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.col {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.hiddenFromXs {
|
|
17
|
+
display: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@media (min-width: 600px) {
|
|
21
|
+
.hiddenFromSm {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@media (min-width: 900px) {
|
|
27
|
+
.hiddenFromMd {
|
|
28
|
+
display: none;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@media (min-width: 1200px) {
|
|
33
|
+
.hiddenFromLg {
|
|
34
|
+
display: none;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@media (min-width: 1536px) {
|
|
39
|
+
.hiddenFromXl {
|
|
40
|
+
display: none;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media (max-width: 599.98px) {
|
|
45
|
+
.visibleFromSm,
|
|
46
|
+
.visibleFromMd,
|
|
47
|
+
.visibleFromLg,
|
|
48
|
+
.visibleFromXl {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@media (max-width: 899.98px) {
|
|
54
|
+
.visibleFromMd,
|
|
55
|
+
.visibleFromLg,
|
|
56
|
+
.visibleFromXl {
|
|
57
|
+
display: none;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@media (max-width: 1199.98px) {
|
|
62
|
+
.visibleFromLg,
|
|
63
|
+
.visibleFromXl {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@media (max-width: 1535.98px) {
|
|
69
|
+
.visibleFromXl {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
}
|