@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,285 @@
|
|
|
1
|
+
import React, { forwardRef, createContext, useContext, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Accordion as MuiAccordion,
|
|
4
|
+
AccordionSummary as MuiAccordionSummary,
|
|
5
|
+
AccordionDetails as MuiAccordionDetails,
|
|
6
|
+
type AccordionProps as MuiAccordionProps,
|
|
7
|
+
type AccordionSummaryProps as MuiAccordionSummaryProps,
|
|
8
|
+
type AccordionDetailsProps as MuiAccordionDetailsProps,
|
|
9
|
+
} from "@mui/material";
|
|
10
|
+
import {
|
|
11
|
+
filterStylingProps,
|
|
12
|
+
type RecursicaOverStyled,
|
|
13
|
+
} from "../../utils/filterStylingProps";
|
|
14
|
+
import styles from "./Accordion.module.css";
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
type RecursicaAccordionProps,
|
|
18
|
+
type RecursicaAccordionItemProps,
|
|
19
|
+
type RecursicaAccordionControlProps,
|
|
20
|
+
type RecursicaAccordionPanelProps,
|
|
21
|
+
} from "@recursica/adapter-common";
|
|
22
|
+
|
|
23
|
+
const ChevronIcon = () => (
|
|
24
|
+
<svg
|
|
25
|
+
viewBox="0 0 24 24"
|
|
26
|
+
fill="none"
|
|
27
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
28
|
+
stroke="currentColor"
|
|
29
|
+
strokeWidth="2"
|
|
30
|
+
strokeLinecap="round"
|
|
31
|
+
strokeLinejoin="round"
|
|
32
|
+
style={{ width: "100%", height: "100%" }}
|
|
33
|
+
>
|
|
34
|
+
<polyline points="6 9 12 15 18 9"></polyline>
|
|
35
|
+
</svg>
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const AccordionContext = createContext<{
|
|
39
|
+
value: string | string[] | null;
|
|
40
|
+
onChange: (val: string) => void;
|
|
41
|
+
chevron?: React.ReactNode;
|
|
42
|
+
} | null>(null);
|
|
43
|
+
|
|
44
|
+
// ==== ACCORDION CONTAINER ====
|
|
45
|
+
export type AccordionProps = RecursicaOverStyled<
|
|
46
|
+
React.HTMLAttributes<HTMLDivElement> &
|
|
47
|
+
RecursicaAccordionProps & {
|
|
48
|
+
// MUI has no native multi-panel accordion group to match (its own `Accordion` is a
|
|
49
|
+
// single controlled item) — this signature is Recursica's own, same as TransferList.
|
|
50
|
+
onChange?: (value: string | string[] | null) => void;
|
|
51
|
+
}
|
|
52
|
+
>;
|
|
53
|
+
|
|
54
|
+
const AccordionBase = forwardRef<HTMLDivElement, AccordionProps>(
|
|
55
|
+
function Accordion(
|
|
56
|
+
{
|
|
57
|
+
variant = "default",
|
|
58
|
+
overStyled = false,
|
|
59
|
+
value,
|
|
60
|
+
defaultValue,
|
|
61
|
+
onChange,
|
|
62
|
+
multiple = false,
|
|
63
|
+
chevron,
|
|
64
|
+
children,
|
|
65
|
+
...rest
|
|
66
|
+
},
|
|
67
|
+
ref,
|
|
68
|
+
) {
|
|
69
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
70
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
71
|
+
.className as string | undefined;
|
|
72
|
+
|
|
73
|
+
const finalClass =
|
|
74
|
+
[styles.root, classNameProp].filter(Boolean).join(" ") || undefined;
|
|
75
|
+
|
|
76
|
+
const [uncontrolledValue, setUncontrolledValue] = useState<
|
|
77
|
+
string | string[] | null
|
|
78
|
+
>(defaultValue !== undefined ? defaultValue : multiple ? [] : null);
|
|
79
|
+
const activeValue = value !== undefined ? value : uncontrolledValue;
|
|
80
|
+
|
|
81
|
+
const handleItemChange = (itemValue: string) => {
|
|
82
|
+
let newValue: string | string[] | null;
|
|
83
|
+
if (multiple) {
|
|
84
|
+
const arr = Array.isArray(activeValue)
|
|
85
|
+
? activeValue
|
|
86
|
+
: activeValue
|
|
87
|
+
? [activeValue as string]
|
|
88
|
+
: [];
|
|
89
|
+
newValue = arr.includes(itemValue)
|
|
90
|
+
? arr.filter((v) => v !== itemValue)
|
|
91
|
+
: [...arr, itemValue];
|
|
92
|
+
} else {
|
|
93
|
+
newValue = activeValue === itemValue ? null : itemValue;
|
|
94
|
+
}
|
|
95
|
+
setUncontrolledValue(newValue);
|
|
96
|
+
onChange?.(newValue);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<AccordionContext.Provider
|
|
101
|
+
value={{ value: activeValue, onChange: handleItemChange, chevron }}
|
|
102
|
+
>
|
|
103
|
+
<div
|
|
104
|
+
ref={ref}
|
|
105
|
+
{...(sanitizedProps as React.HTMLAttributes<HTMLDivElement>)}
|
|
106
|
+
className={finalClass}
|
|
107
|
+
data-variant={variant}
|
|
108
|
+
>
|
|
109
|
+
{children}
|
|
110
|
+
</div>
|
|
111
|
+
</AccordionContext.Provider>
|
|
112
|
+
);
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
AccordionBase.displayName = "Accordion";
|
|
116
|
+
|
|
117
|
+
export type AccordionItemWrapperProps = RecursicaOverStyled<
|
|
118
|
+
// `expanded`/`onChange` are computed internally from the group context — omitted so a
|
|
119
|
+
// caller can't silently detach this item from the controlled state. `defaultExpanded` has
|
|
120
|
+
// no meaning here since expansion is always driven by the group's `value`. `disabled` is
|
|
121
|
+
// shared as-is with `RecursicaAccordionItemProps.disabled` — same name, same shape, no
|
|
122
|
+
// reshaping needed; see ACCORDION_IMPLEMENTATION_NOTES.md.
|
|
123
|
+
Omit<
|
|
124
|
+
MuiAccordionProps,
|
|
125
|
+
"children" | "value" | "expanded" | "onChange" | "defaultExpanded"
|
|
126
|
+
> & {
|
|
127
|
+
children?: React.ReactNode;
|
|
128
|
+
value: string;
|
|
129
|
+
} & RecursicaAccordionItemProps
|
|
130
|
+
>;
|
|
131
|
+
|
|
132
|
+
export const AccordionItem = forwardRef<
|
|
133
|
+
HTMLDivElement,
|
|
134
|
+
AccordionItemWrapperProps
|
|
135
|
+
>(function AccordionItem(
|
|
136
|
+
{
|
|
137
|
+
title,
|
|
138
|
+
leftIcon,
|
|
139
|
+
divider = true,
|
|
140
|
+
children,
|
|
141
|
+
value,
|
|
142
|
+
disabled = false,
|
|
143
|
+
overStyled = false,
|
|
144
|
+
style,
|
|
145
|
+
...rest
|
|
146
|
+
},
|
|
147
|
+
ref,
|
|
148
|
+
) {
|
|
149
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
150
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
151
|
+
.className as string | undefined;
|
|
152
|
+
|
|
153
|
+
const finalClass =
|
|
154
|
+
[styles.item, divider ? undefined : styles.noDivider, classNameProp]
|
|
155
|
+
.filter(Boolean)
|
|
156
|
+
.join(" ") || undefined;
|
|
157
|
+
|
|
158
|
+
const ctx = useContext(AccordionContext);
|
|
159
|
+
const isExpanded = ctx
|
|
160
|
+
? Array.isArray(ctx.value)
|
|
161
|
+
? ctx.value.includes(value)
|
|
162
|
+
: ctx.value === value
|
|
163
|
+
: undefined;
|
|
164
|
+
|
|
165
|
+
const handleChange = () => {
|
|
166
|
+
ctx?.onChange(value);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// background-color: transparent allows Layer overrides to naturally penetrate
|
|
170
|
+
const mergedStyle = { backgroundColor: "transparent", ...style };
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<MuiAccordion
|
|
174
|
+
ref={ref}
|
|
175
|
+
{...(sanitizedProps as unknown as Omit<
|
|
176
|
+
MuiAccordionProps,
|
|
177
|
+
"expanded" | "onChange" | "defaultExpanded" | "disabled"
|
|
178
|
+
>)}
|
|
179
|
+
className={finalClass}
|
|
180
|
+
disableGutters
|
|
181
|
+
elevation={0}
|
|
182
|
+
square
|
|
183
|
+
expanded={isExpanded}
|
|
184
|
+
onChange={handleChange}
|
|
185
|
+
disabled={disabled}
|
|
186
|
+
data-disabled={disabled || undefined}
|
|
187
|
+
style={mergedStyle}
|
|
188
|
+
>
|
|
189
|
+
{
|
|
190
|
+
(title ? (
|
|
191
|
+
<>
|
|
192
|
+
<AccordionControl leftIcon={leftIcon}>{title}</AccordionControl>
|
|
193
|
+
<AccordionPanel>{children}</AccordionPanel>
|
|
194
|
+
</>
|
|
195
|
+
) : (
|
|
196
|
+
children
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
198
|
+
)) as any
|
|
199
|
+
}
|
|
200
|
+
</MuiAccordion>
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
AccordionItem.displayName = "AccordionItem";
|
|
204
|
+
|
|
205
|
+
// ==== ACCORDION CONTROL ====
|
|
206
|
+
export type AccordionControlWrapperProps = RecursicaOverStyled<
|
|
207
|
+
// `expandIcon` is resolved internally from the container's `chevron` (via context) —
|
|
208
|
+
// omitted so a caller can't silently override it with MUI's native chevron slot.
|
|
209
|
+
Omit<MuiAccordionSummaryProps, "expandIcon"> & RecursicaAccordionControlProps
|
|
210
|
+
>;
|
|
211
|
+
|
|
212
|
+
export const AccordionControl = forwardRef<
|
|
213
|
+
HTMLDivElement,
|
|
214
|
+
AccordionControlWrapperProps
|
|
215
|
+
>(function AccordionControl(
|
|
216
|
+
{ leftIcon, children, overStyled = false, ...rest },
|
|
217
|
+
ref,
|
|
218
|
+
) {
|
|
219
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
220
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
221
|
+
.className as string | undefined;
|
|
222
|
+
|
|
223
|
+
const finalClass =
|
|
224
|
+
[styles.control, classNameProp].filter(Boolean).join(" ") || undefined;
|
|
225
|
+
|
|
226
|
+
const ctx = useContext(AccordionContext);
|
|
227
|
+
const resolvedChevron = ctx?.chevron ?? <ChevronIcon />;
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<MuiAccordionSummary
|
|
231
|
+
ref={ref}
|
|
232
|
+
{...(sanitizedProps as unknown as MuiAccordionSummaryProps)}
|
|
233
|
+
className={finalClass}
|
|
234
|
+
expandIcon={<span className={styles.chevron}>{resolvedChevron}</span>}
|
|
235
|
+
>
|
|
236
|
+
{leftIcon && (
|
|
237
|
+
<span className={styles.iconLeftWrapper} aria-hidden>
|
|
238
|
+
{leftIcon}
|
|
239
|
+
</span>
|
|
240
|
+
)}
|
|
241
|
+
<div className={styles.label}>{children}</div>
|
|
242
|
+
</MuiAccordionSummary>
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
AccordionControl.displayName = "AccordionControl";
|
|
246
|
+
|
|
247
|
+
// ==== ACCORDION PANEL ====
|
|
248
|
+
export type AccordionPanelWrapperProps = RecursicaOverStyled<
|
|
249
|
+
MuiAccordionDetailsProps & RecursicaAccordionPanelProps
|
|
250
|
+
>;
|
|
251
|
+
|
|
252
|
+
export const AccordionPanel = forwardRef<
|
|
253
|
+
HTMLDivElement,
|
|
254
|
+
AccordionPanelWrapperProps
|
|
255
|
+
>(function AccordionPanel({ overStyled = false, children, ...rest }, ref) {
|
|
256
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
257
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
258
|
+
.className as string | undefined;
|
|
259
|
+
|
|
260
|
+
const finalClass =
|
|
261
|
+
[styles.panel, classNameProp].filter(Boolean).join(" ") || undefined;
|
|
262
|
+
|
|
263
|
+
return (
|
|
264
|
+
<MuiAccordionDetails
|
|
265
|
+
ref={ref}
|
|
266
|
+
{...(sanitizedProps as unknown as MuiAccordionDetailsProps)}
|
|
267
|
+
className={finalClass}
|
|
268
|
+
>
|
|
269
|
+
<div className={styles.content}>{children}</div>
|
|
270
|
+
</MuiAccordionDetails>
|
|
271
|
+
);
|
|
272
|
+
});
|
|
273
|
+
AccordionPanel.displayName = "AccordionPanel";
|
|
274
|
+
|
|
275
|
+
// ==== DOT NOTATION EXPORT ====
|
|
276
|
+
type AccordionComponent = typeof AccordionBase & {
|
|
277
|
+
Item: typeof AccordionItem;
|
|
278
|
+
Control: typeof AccordionControl;
|
|
279
|
+
Panel: typeof AccordionPanel;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const Accordion = AccordionBase as AccordionComponent;
|
|
283
|
+
Accordion.Item = AccordionItem;
|
|
284
|
+
Accordion.Control = AccordionControl;
|
|
285
|
+
Accordion.Panel = AccordionPanel;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Accordion - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Accordion` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Accordion } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Accordion } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Accordion>
|
|
24
|
+
<Accordion.Item value="item-1">
|
|
25
|
+
<Accordion.Control>Section 1</Accordion.Control>
|
|
26
|
+
<Accordion.Panel>Section 1 content</Accordion.Panel>
|
|
27
|
+
</Accordion.Item>
|
|
28
|
+
</Accordion>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Design System Integration
|
|
36
|
+
|
|
37
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
38
|
+
|
|
39
|
+
> [!IMPORTANT]
|
|
40
|
+
>
|
|
41
|
+
> - **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.
|
|
42
|
+
> - **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.
|
|
43
|
+
> - **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 "./Accordion";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# AssistiveElement – implementation notes
|
|
2
|
+
|
|
3
|
+
Decisions and design tweaks specific to the UI Kit's AssistiveElement wrapped against
|
|
4
|
+
`@mui/material`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Forced `component="div"` trades away `FormHelperText`'s default semantics
|
|
9
|
+
|
|
10
|
+
**Decision:** `FormHelperText` renders a `<p>` by default — a reasonable semantic choice for
|
|
11
|
+
standalone helper/error text. This adapter forces `component="div"` instead, purely so the
|
|
12
|
+
icon + text can sit side by side in a flex row; `<p>` can't contain the flex layout the same
|
|
13
|
+
way without other tradeoffs.
|
|
14
|
+
**Implementation:** `component="div"` and `error={isError}` (derived from `assistiveVariant`)
|
|
15
|
+
are both computed internally and omitted from `AssistiveElementProps` (`Omit<FormHelperTextProps,
|
|
16
|
+
"error" | "component">`) so a caller can't silently override either via spread.
|
|
17
|
+
`aria-describedby`/`aria-errormessage` association with a field is a different story: this
|
|
18
|
+
component has no reference to any sibling field, so it can't wire that itself. It's already
|
|
19
|
+
handled one layer up, in `FormControlWrapper` — which generates the ids, passes them down via
|
|
20
|
+
this component's own `id` prop, and clones `aria-describedby`/`aria-errormessage` onto the
|
|
21
|
+
field. Only a fully standalone `<AssistiveElement>` used outside `FormControlWrapper` still
|
|
22
|
+
needs that wiring done by hand. `role="alert"` for the error variant is handled here instead
|
|
23
|
+
(see §4) — that piece genuinely belongs at this component's own level.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. CSS specificity tie against MUI's own `.Mui-error` color
|
|
28
|
+
|
|
29
|
+
**Decision:** MUI's `FormHelperText` sets its own error color via `.MuiFormHelperText-root.Mui-error`
|
|
30
|
+
(two classes) whenever `error` is set. Our own `.root[data-variant="error"]` (one class + one
|
|
31
|
+
attribute) lands at the _same_ specificity — without help, whichever rule loads later in the
|
|
32
|
+
merged stylesheet wins, which is import-order luck rather than a deterministic override.
|
|
33
|
+
**Implementation:** `!important` on that one rule's `color` guarantees ours wins regardless of
|
|
34
|
+
load order (same reasoning as the focus-ring override in the Accordion adapter). Not needed for
|
|
35
|
+
the `help` variant — MUI's unconditional base `color` on `.root` alone already has lower
|
|
36
|
+
specificity than our attribute-qualified rule there.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3. Native passthrough capabilities, left unblocked and undocumented
|
|
41
|
+
|
|
42
|
+
**Decision:** `FormHelperText`'s own `disabled`/`filled`/`focused`/`margin`/`required`/`variant`/
|
|
43
|
+
`classes`/`sx` all pass straight through today (none of them are omitted, and none are
|
|
44
|
+
computed internally so there's nothing for them to silently override). They're also not added
|
|
45
|
+
to `RecursicaAssistiveElementProps` — same "accidental passthrough" class as Accordion's
|
|
46
|
+
`disabled` was before it got formalized. Known asymmetry: MUI callers can reach for these
|
|
47
|
+
today, Mantine callers can't (Mantine's `AssistiveElement` wraps no native component at all).
|
|
48
|
+
Revisit if a real use case shows up for any of them.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 4. `role="alert"` defaults on for the error variant
|
|
53
|
+
|
|
54
|
+
**Decision:** Error text needs to be announced by assistive tech as it appears or changes;
|
|
55
|
+
static help text doesn't. Rather than requiring every integrator to remember `role="alert"`,
|
|
56
|
+
`assistiveVariant="error"` defaults it automatically.
|
|
57
|
+
**Implementation:** `role` is destructured out and resolved as `role ?? (isError ? "alert" :
|
|
58
|
+
undefined)` before rendering — an explicit caller-supplied `role` always wins over the default,
|
|
59
|
+
and `"help"` gets no default at all.
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/*
|
|
2
|
+
ASSISTIVE ELEMENT ARCHITECTURE
|
|
3
|
+
This component strictly standardizes FormHelperText logic dynamically natively decoupled from the overarching input blocks.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.root {
|
|
7
|
+
/* Override MUI FormHelperText native resets structurally safely */
|
|
8
|
+
display: flex !important;
|
|
9
|
+
align-items: flex-start !important; /* Forces the icon to align with the first line of text */
|
|
10
|
+
margin: 0 !important; /* HARDCODE: structural reset */
|
|
11
|
+
padding: 0 !important; /* HARDCODE: structural reset */
|
|
12
|
+
width: 100%;
|
|
13
|
+
|
|
14
|
+
gap: var(
|
|
15
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-text-gap
|
|
16
|
+
);
|
|
17
|
+
margin-top: var(
|
|
18
|
+
--recursica_ui-kit_components_assistive-element_properties_top-margin
|
|
19
|
+
) !important;
|
|
20
|
+
max-width: var(
|
|
21
|
+
--recursica_ui-kit_components_assistive-element_properties_max-width
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
font-family: var(
|
|
25
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-family
|
|
26
|
+
);
|
|
27
|
+
font-size: var(
|
|
28
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-size
|
|
29
|
+
);
|
|
30
|
+
font-style: var(
|
|
31
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-style
|
|
32
|
+
);
|
|
33
|
+
font-weight: var(
|
|
34
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-weight
|
|
35
|
+
);
|
|
36
|
+
letter-spacing: var(
|
|
37
|
+
--recursica_ui-kit_components_assistive-element_properties_text_letter-spacing
|
|
38
|
+
);
|
|
39
|
+
line-height: var(
|
|
40
|
+
--recursica_ui-kit_components_assistive-element_properties_text_line-height
|
|
41
|
+
);
|
|
42
|
+
text-decoration: var(
|
|
43
|
+
--recursica_ui-kit_components_assistive-element_properties_text_text-decoration
|
|
44
|
+
);
|
|
45
|
+
text-transform: var(
|
|
46
|
+
--recursica_ui-kit_components_assistive-element_properties_text_text-transform
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.text {
|
|
51
|
+
overflow-wrap: break-word;
|
|
52
|
+
white-space: normal;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/* Base Icon Architecture */
|
|
56
|
+
.icon {
|
|
57
|
+
flex-shrink: 0 !important; /* Prevent squishing */
|
|
58
|
+
display: flex !important;
|
|
59
|
+
align-items: center !important;
|
|
60
|
+
justify-content: center !important;
|
|
61
|
+
|
|
62
|
+
width: var(
|
|
63
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
64
|
+
) !important;
|
|
65
|
+
height: calc(
|
|
66
|
+
var(
|
|
67
|
+
--recursica_ui-kit_components_assistive-element_properties_text_line-height
|
|
68
|
+
) *
|
|
69
|
+
var(
|
|
70
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-size
|
|
71
|
+
)
|
|
72
|
+
) !important; /* Forces exact centering bounds within the first text line vertically */
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.icon :global(svg) {
|
|
76
|
+
width: var(
|
|
77
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
78
|
+
) !important;
|
|
79
|
+
height: var(
|
|
80
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
81
|
+
) !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* =========================================
|
|
85
|
+
VARIANTS: Default / Help
|
|
86
|
+
========================================= */
|
|
87
|
+
|
|
88
|
+
.root[data-variant="help"] {
|
|
89
|
+
color: var(
|
|
90
|
+
--recursica_ui-kit_components_assistive-element_variants_types_help_properties_colors_text-color
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.root[data-variant="help"] .icon {
|
|
95
|
+
color: var(
|
|
96
|
+
--recursica_ui-kit_components_assistive-element_variants_types_help_properties_colors_icon-color
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* =========================================
|
|
101
|
+
VARIANTS: Error
|
|
102
|
+
========================================= */
|
|
103
|
+
|
|
104
|
+
/* MUI's own `FormHelperText` sets its error color via `.MuiFormHelperText-root.Mui-error`
|
|
105
|
+
(two classes) whenever `error` is set — the exact same specificity as our own
|
|
106
|
+
`.root[data-variant="error"]` (one class + one attribute), so whichever rule loads later
|
|
107
|
+
in the merged stylesheet would otherwise win. `!important` makes ours win deterministically
|
|
108
|
+
regardless of CSS import order (same reasoning as the focus-ring override elsewhere in this
|
|
109
|
+
codebase). Not needed for the `help` variant above — MUI's unconditional base `color` on
|
|
110
|
+
`.root` alone has lower specificity than ours there already. */
|
|
111
|
+
.root[data-variant="error"] {
|
|
112
|
+
color: var(
|
|
113
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_text-color
|
|
114
|
+
) !important;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.root[data-variant="error"] .icon {
|
|
118
|
+
color: var(
|
|
119
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_icon-color
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { AssistiveElement } from "./AssistiveElement";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof AssistiveElement> = {
|
|
5
|
+
title: "UI-Kit/AssistiveElement",
|
|
6
|
+
component: AssistiveElement,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component:
|
|
12
|
+
"The `AssistiveElement` is a semantic structural primitive designed to standardize Helper and Error descriptive blocks natively beneath form components globally. By explicitly wiring to the `--recursica_ui-kit_components_assistive-element` layout tokens, this component safely injects custom SVGs (Alerts vs Info circles) alongside constrained flex-wrapping typography strings, preserving flawless line-height and alignment logic entirely decoupled from underlying input engine frameworks.",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
assistiveVariant: {
|
|
18
|
+
control: "radio",
|
|
19
|
+
options: ["help", "error"],
|
|
20
|
+
},
|
|
21
|
+
assistiveWithIcon: {
|
|
22
|
+
control: "boolean",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
|
|
29
|
+
type Story = StoryObj<typeof AssistiveElement>;
|
|
30
|
+
|
|
31
|
+
export const DefaultHelp: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
children:
|
|
34
|
+
"This is a standard assistive layout explaining specific configurations.",
|
|
35
|
+
assistiveVariant: "help",
|
|
36
|
+
assistiveWithIcon: true,
|
|
37
|
+
},
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
39
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
40
|
+
<AssistiveElement {...args} />
|
|
41
|
+
),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const ErrorState: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
children:
|
|
47
|
+
"Invalid property. You must satisfy the constraints outlined above.",
|
|
48
|
+
assistiveVariant: "error",
|
|
49
|
+
assistiveWithIcon: true,
|
|
50
|
+
},
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
52
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
53
|
+
<AssistiveElement {...args} />
|
|
54
|
+
),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const NoIconHelp: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
children:
|
|
60
|
+
"Fallback textual representation without visual injection targets.",
|
|
61
|
+
assistiveVariant: "help",
|
|
62
|
+
assistiveWithIcon: false,
|
|
63
|
+
},
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
65
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
66
|
+
<AssistiveElement {...args} />
|
|
67
|
+
),
|
|
68
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future AssistiveElement component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { FormHelperText, type FormHelperTextProps } from "@mui/material";
|
|
3
|
+
import {
|
|
4
|
+
filterStylingProps,
|
|
5
|
+
type RecursicaOverStyled,
|
|
6
|
+
} from "../../utils/filterStylingProps";
|
|
7
|
+
import styles from "./AssistiveElement.module.css";
|
|
8
|
+
|
|
9
|
+
import { type RecursicaAssistiveElementProps } from "@recursica/adapter-common";
|
|
10
|
+
|
|
11
|
+
// `error`/`component` are computed internally (from `assistiveVariant`, and forced to "div"
|
|
12
|
+
// for layout) — omitted so a caller can't silently override either via spread.
|
|
13
|
+
export type AssistiveElementProps = RecursicaOverStyled<
|
|
14
|
+
Omit<FormHelperTextProps, "error" | "component"> &
|
|
15
|
+
RecursicaAssistiveElementProps
|
|
16
|
+
>;
|
|
17
|
+
|
|
18
|
+
export const AssistiveElement = React.forwardRef<
|
|
19
|
+
HTMLParagraphElement,
|
|
20
|
+
AssistiveElementProps
|
|
21
|
+
>(function AssistiveElement(props, ref) {
|
|
22
|
+
const {
|
|
23
|
+
assistiveVariant = "help",
|
|
24
|
+
assistiveWithIcon = true,
|
|
25
|
+
overStyled = false,
|
|
26
|
+
className,
|
|
27
|
+
children,
|
|
28
|
+
role,
|
|
29
|
+
...rest
|
|
30
|
+
} = props;
|
|
31
|
+
|
|
32
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
33
|
+
|
|
34
|
+
const HelpIcon = () => (
|
|
35
|
+
<svg
|
|
36
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
viewBox="0 0 24 24"
|
|
38
|
+
fill="none"
|
|
39
|
+
stroke="currentColor"
|
|
40
|
+
strokeWidth="2"
|
|
41
|
+
strokeLinecap="round"
|
|
42
|
+
strokeLinejoin="round"
|
|
43
|
+
>
|
|
44
|
+
<circle cx="12" cy="12" r="10" />
|
|
45
|
+
<path d="M12 16v-4" />
|
|
46
|
+
<path d="M12 8h.01" />
|
|
47
|
+
</svg>
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const ErrorIcon = () => (
|
|
51
|
+
<svg
|
|
52
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
strokeWidth="2"
|
|
57
|
+
strokeLinecap="round"
|
|
58
|
+
strokeLinejoin="round"
|
|
59
|
+
>
|
|
60
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
|
|
61
|
+
<path d="M12 9v4" />
|
|
62
|
+
<path d="M12 17h.01" />
|
|
63
|
+
</svg>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Map to MUI's native error prop if it's explicitly an error state
|
|
67
|
+
const isError = assistiveVariant === "error";
|
|
68
|
+
|
|
69
|
+
// Announce error text as it appears/changes; a caller-supplied `role` always wins. No
|
|
70
|
+
// default for `help` — static descriptive text doesn't need a live region.
|
|
71
|
+
const resolvedRole = role ?? (isError ? "alert" : undefined);
|
|
72
|
+
|
|
73
|
+
// Force component = "div" so flex layouts execute correctly inside HelperText
|
|
74
|
+
return (
|
|
75
|
+
<FormHelperText
|
|
76
|
+
ref={ref}
|
|
77
|
+
{...(sanitizedProps as Omit<FormHelperTextProps, "error" | "component">)}
|
|
78
|
+
component="div"
|
|
79
|
+
error={isError}
|
|
80
|
+
role={resolvedRole}
|
|
81
|
+
data-variant={assistiveVariant}
|
|
82
|
+
className={className ? `${styles.root} ${className}` : styles.root}
|
|
83
|
+
>
|
|
84
|
+
{assistiveWithIcon && (
|
|
85
|
+
<div className={styles.icon}>
|
|
86
|
+
{assistiveVariant === "error" ? <ErrorIcon /> : <HelpIcon />}
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
<span className={styles.text}>{children}</span>
|
|
90
|
+
</FormHelperText>
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
AssistiveElement.displayName = "AssistiveElement";
|