@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,157 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Stepper, Step, StepLabel } from "./Stepper";
|
|
4
|
+
import { Button } from "../Button/Button";
|
|
5
|
+
import { Group } from "../Group/Group";
|
|
6
|
+
import { Flex } from "../Flex/Flex";
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Stepper> = {
|
|
9
|
+
title: "UI-Kit/Stepper",
|
|
10
|
+
component: Stepper,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
parameters: {
|
|
13
|
+
layout: "centered",
|
|
14
|
+
},
|
|
15
|
+
argTypes: {
|
|
16
|
+
size: {
|
|
17
|
+
control: "radio",
|
|
18
|
+
options: ["small", "large"],
|
|
19
|
+
},
|
|
20
|
+
orientation: {
|
|
21
|
+
control: "radio",
|
|
22
|
+
options: ["horizontal", "vertical"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
type Story = StoryObj<typeof Stepper>;
|
|
29
|
+
|
|
30
|
+
const InteractiveStepper = (args: React.ComponentProps<typeof Stepper>) => {
|
|
31
|
+
const [active, setActive] = useState(1);
|
|
32
|
+
const nextStep = () =>
|
|
33
|
+
setActive((current) => (current < 3 ? current + 1 : current));
|
|
34
|
+
const prevStep = () =>
|
|
35
|
+
setActive((current) => (current > 0 ? current - 1 : current));
|
|
36
|
+
|
|
37
|
+
const steps = [
|
|
38
|
+
{
|
|
39
|
+
label: "First step",
|
|
40
|
+
description: "Create an account and set up your billing profile",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: "Second step",
|
|
44
|
+
description:
|
|
45
|
+
"Verify email and ensure all notification preferences are correct",
|
|
46
|
+
},
|
|
47
|
+
{ label: "Final step", description: "Get full access" },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<Flex direction="column" style={{ width: 600 }}>
|
|
52
|
+
<Stepper {...args} activeStep={active}>
|
|
53
|
+
{steps.map((step, index) => (
|
|
54
|
+
<Step key={index} completed={active > index}>
|
|
55
|
+
<StepLabel description={step.description}>{step.label}</StepLabel>
|
|
56
|
+
</Step>
|
|
57
|
+
))}
|
|
58
|
+
</Stepper>
|
|
59
|
+
|
|
60
|
+
{active === steps.length && (
|
|
61
|
+
<div style={{ marginTop: 24, textAlign: "center" }}>
|
|
62
|
+
Completed, click back button to get to previous step
|
|
63
|
+
</div>
|
|
64
|
+
)}
|
|
65
|
+
|
|
66
|
+
<Group mt={24} justify="center" gap={8}>
|
|
67
|
+
<Button variant="outline" onClick={prevStep} disabled={active === 0}>
|
|
68
|
+
Previous step
|
|
69
|
+
</Button>
|
|
70
|
+
<Button variant="outline" onClick={nextStep} disabled={active === 3}>
|
|
71
|
+
Next step
|
|
72
|
+
</Button>
|
|
73
|
+
</Group>
|
|
74
|
+
</Flex>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const Default: Story = {
|
|
79
|
+
render: (args) => <InteractiveStepper {...args} />,
|
|
80
|
+
args: {
|
|
81
|
+
size: "large",
|
|
82
|
+
orientation: "horizontal",
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const Small: Story = {
|
|
87
|
+
render: (args) => <InteractiveStepper {...args} />,
|
|
88
|
+
args: {
|
|
89
|
+
size: "small",
|
|
90
|
+
orientation: "horizontal",
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const Vertical: Story = {
|
|
95
|
+
render: (args) => <InteractiveStepper {...args} />,
|
|
96
|
+
args: {
|
|
97
|
+
size: "large",
|
|
98
|
+
orientation: "vertical",
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const StressTestStepper = (args: React.ComponentProps<typeof Stepper>) => {
|
|
103
|
+
const [active, setActive] = useState(1);
|
|
104
|
+
const nextStep = () =>
|
|
105
|
+
setActive((current) => (current < 3 ? current + 1 : current));
|
|
106
|
+
const prevStep = () =>
|
|
107
|
+
setActive((current) => (current > 0 ? current - 1 : current));
|
|
108
|
+
|
|
109
|
+
const steps = [
|
|
110
|
+
{
|
|
111
|
+
label:
|
|
112
|
+
"This is an extremely long step title designed to test how the layout handles multiline text wrapping and constraints",
|
|
113
|
+
description: "Create an account and set up your billing profile",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
label: "Second step",
|
|
117
|
+
description:
|
|
118
|
+
"Verify email and ensure all notification preferences are correct",
|
|
119
|
+
},
|
|
120
|
+
{ label: "Final step", description: undefined },
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<Flex direction="column" style={{ width: 600 }}>
|
|
125
|
+
<Stepper {...args} activeStep={active}>
|
|
126
|
+
{steps.map((step, index) => (
|
|
127
|
+
<Step key={index} completed={active > index}>
|
|
128
|
+
<StepLabel description={step.description}>{step.label}</StepLabel>
|
|
129
|
+
</Step>
|
|
130
|
+
))}
|
|
131
|
+
</Stepper>
|
|
132
|
+
|
|
133
|
+
{active === steps.length && (
|
|
134
|
+
<div style={{ marginTop: 24, textAlign: "center" }}>
|
|
135
|
+
Completed, click back button to get to previous step
|
|
136
|
+
</div>
|
|
137
|
+
)}
|
|
138
|
+
|
|
139
|
+
<Group mt={24} justify="center" gap={8}>
|
|
140
|
+
<Button variant="outline" onClick={prevStep} disabled={active === 0}>
|
|
141
|
+
Previous step
|
|
142
|
+
</Button>
|
|
143
|
+
<Button variant="outline" onClick={nextStep} disabled={active === 3}>
|
|
144
|
+
Next step
|
|
145
|
+
</Button>
|
|
146
|
+
</Group>
|
|
147
|
+
</Flex>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export const LayoutStressTest: Story = {
|
|
152
|
+
render: (args) => <StressTestStepper {...args} />,
|
|
153
|
+
args: {
|
|
154
|
+
size: "large",
|
|
155
|
+
orientation: "horizontal",
|
|
156
|
+
},
|
|
157
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Stepper component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Stepper as MuiStepper,
|
|
4
|
+
Step as MuiStep,
|
|
5
|
+
StepLabel as MuiStepLabel,
|
|
6
|
+
StepButton as MuiStepButton,
|
|
7
|
+
StepConnector as MuiStepConnector,
|
|
8
|
+
type StepperProps as MuiStepperProps,
|
|
9
|
+
type StepProps as MuiStepProps,
|
|
10
|
+
type StepLabelProps as MuiStepLabelProps,
|
|
11
|
+
type StepButtonProps as MuiStepButtonProps,
|
|
12
|
+
type StepConnectorProps as MuiStepConnectorProps,
|
|
13
|
+
type StepIconProps as MuiStepIconProps,
|
|
14
|
+
} from "@mui/material";
|
|
15
|
+
import {
|
|
16
|
+
filterStylingProps,
|
|
17
|
+
mergeClassNames,
|
|
18
|
+
type RecursicaOverStyled,
|
|
19
|
+
} from "../../utils/filterStylingProps";
|
|
20
|
+
import styles from "./Stepper.module.css";
|
|
21
|
+
|
|
22
|
+
import { type RecursicaStepperProps } from "@recursica/adapter-common";
|
|
23
|
+
|
|
24
|
+
// Same inline check glyph used by Checkbox.tsx (fill="currentColor" so the CSS
|
|
25
|
+
// module drives color via `.stepCompletedIcon`).
|
|
26
|
+
function CheckIcon(props: React.ComponentProps<"svg">) {
|
|
27
|
+
return (
|
|
28
|
+
<svg
|
|
29
|
+
viewBox="0 0 10 7"
|
|
30
|
+
fill="none"
|
|
31
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
32
|
+
{...props}
|
|
33
|
+
>
|
|
34
|
+
<path
|
|
35
|
+
d="M4 4.586L1.707 2.293A1 1 0 1 0 .293 3.707l3 3a.997.997 0 0 0 1.414 0l5-5A1 1 0 1 0 8.293.293L4 4.586z"
|
|
36
|
+
fill="currentColor"
|
|
37
|
+
fillRule="evenodd"
|
|
38
|
+
clipRule="evenodd"
|
|
39
|
+
/>
|
|
40
|
+
</svg>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// MUI's default StepIcon draws its own self-contained circle+check SVG
|
|
45
|
+
// (Material's `check_circle` glyph, colored via `theme.palette.primary.main`)
|
|
46
|
+
// whenever `icon` is the auto-injected step number — it never defers to our
|
|
47
|
+
// `.stepIcon` background/border tokens. We render the indicator ourselves so
|
|
48
|
+
// the recursica-token circle (`.stepIconCircle`) is the only circle, and the
|
|
49
|
+
// completed check mark is our own token-colored glyph.
|
|
50
|
+
function RecursicaStepIcon(props: MuiStepIconProps) {
|
|
51
|
+
const { icon, active, completed, error } = props;
|
|
52
|
+
if (typeof icon !== "number" && typeof icon !== "string") {
|
|
53
|
+
return <>{icon}</>;
|
|
54
|
+
}
|
|
55
|
+
return (
|
|
56
|
+
<span
|
|
57
|
+
className={styles.stepIconCircle}
|
|
58
|
+
data-active={active || undefined}
|
|
59
|
+
data-completed={completed || undefined}
|
|
60
|
+
data-error={error || undefined}
|
|
61
|
+
>
|
|
62
|
+
{completed ? <CheckIcon className={styles.stepCompletedIcon} /> : icon}
|
|
63
|
+
</span>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface RecursicaStepperPropsExtended
|
|
68
|
+
extends Omit<Partial<MuiStepperProps>, "size">,
|
|
69
|
+
RecursicaStepperProps {}
|
|
70
|
+
|
|
71
|
+
export type StepperProps = RecursicaOverStyled<RecursicaStepperPropsExtended>;
|
|
72
|
+
|
|
73
|
+
export const Stepper = forwardRef<HTMLDivElement, StepperProps>(
|
|
74
|
+
function Stepper(props, ref) {
|
|
75
|
+
const {
|
|
76
|
+
overStyled = false,
|
|
77
|
+
size = "large",
|
|
78
|
+
orientation = "horizontal",
|
|
79
|
+
className,
|
|
80
|
+
style,
|
|
81
|
+
...rest
|
|
82
|
+
} = props;
|
|
83
|
+
|
|
84
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
85
|
+
const isHorizontal = orientation === "horizontal";
|
|
86
|
+
|
|
87
|
+
const mergedClassNames = mergeClassNames(
|
|
88
|
+
{ root: styles.steps },
|
|
89
|
+
(sanitizedProps as Record<string, unknown>).classes as
|
|
90
|
+
| Partial<Record<string, string>>
|
|
91
|
+
| undefined,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<div
|
|
96
|
+
className={`${styles.root} ${isHorizontal ? styles.horizontal : styles.vertical} ${size === "large" ? styles.large : styles.small} ${className || ""}`}
|
|
97
|
+
style={style as React.CSSProperties}
|
|
98
|
+
data-size={size}
|
|
99
|
+
data-orientation={orientation}
|
|
100
|
+
>
|
|
101
|
+
<MuiStepper
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
+
ref={ref as any}
|
|
104
|
+
{...(sanitizedProps as MuiStepperProps)}
|
|
105
|
+
orientation={orientation}
|
|
106
|
+
// `alternativeLabel` is MUI's real primitive for "label centered under
|
|
107
|
+
// the icon" (see its own prop doc) — required for the icon/label
|
|
108
|
+
// layout and for the connector's centered absolute positioning.
|
|
109
|
+
alternativeLabel={isHorizontal}
|
|
110
|
+
connector={
|
|
111
|
+
isHorizontal ? (
|
|
112
|
+
<MuiStepConnector
|
|
113
|
+
classes={{
|
|
114
|
+
root: styles.separator,
|
|
115
|
+
line: styles.separatorLine,
|
|
116
|
+
}}
|
|
117
|
+
/>
|
|
118
|
+
) : (
|
|
119
|
+
// Vertical connecting line is drawn as a `.stepIcon::after` rail
|
|
120
|
+
// (see module CSS) so its length tracks each step's actual
|
|
121
|
+
// rendered height (multi-line descriptions included) the same
|
|
122
|
+
// way mantine's absolutely-positioned separator does — MUI's
|
|
123
|
+
// own vertical `StepConnector` is a fixed-height sibling that
|
|
124
|
+
// can't do that without `StepContent`, which recursica hides.
|
|
125
|
+
<></>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
classes={mergedClassNames}
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
Stepper.displayName = "Stepper";
|
|
136
|
+
|
|
137
|
+
export type StepProps = RecursicaOverStyled<MuiStepProps>;
|
|
138
|
+
|
|
139
|
+
export const Step = forwardRef<HTMLDivElement, StepProps>(
|
|
140
|
+
function Step(props, ref) {
|
|
141
|
+
const { overStyled = false, className, ...rest } = props;
|
|
142
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
143
|
+
const mergedClassNames = mergeClassNames(
|
|
144
|
+
{ root: styles.step },
|
|
145
|
+
(sanitizedProps as Record<string, unknown>).classes as
|
|
146
|
+
| Partial<Record<string, string>>
|
|
147
|
+
| undefined,
|
|
148
|
+
);
|
|
149
|
+
return (
|
|
150
|
+
<MuiStep
|
|
151
|
+
ref={ref}
|
|
152
|
+
{...(sanitizedProps as MuiStepProps)}
|
|
153
|
+
classes={mergedClassNames}
|
|
154
|
+
className={className || ""}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
Step.displayName = "Step";
|
|
161
|
+
|
|
162
|
+
export type StepButtonProps = RecursicaOverStyled<MuiStepButtonProps>;
|
|
163
|
+
|
|
164
|
+
export const StepButton = forwardRef<HTMLButtonElement, StepButtonProps>(
|
|
165
|
+
function StepButton(props, ref) {
|
|
166
|
+
const { overStyled = false, className, ...rest } = props;
|
|
167
|
+
return (
|
|
168
|
+
<MuiStepButton
|
|
169
|
+
ref={ref}
|
|
170
|
+
className={className || ""}
|
|
171
|
+
{...(filterStylingProps(rest, overStyled) as MuiStepButtonProps)}
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
StepButton.displayName = "StepButton";
|
|
178
|
+
|
|
179
|
+
export type StepLabelProps = RecursicaOverStyled<
|
|
180
|
+
MuiStepLabelProps & { description?: React.ReactNode }
|
|
181
|
+
>;
|
|
182
|
+
|
|
183
|
+
export const StepLabel = forwardRef<HTMLDivElement, StepLabelProps>(
|
|
184
|
+
function StepLabel(props, ref) {
|
|
185
|
+
const {
|
|
186
|
+
overStyled = false,
|
|
187
|
+
className,
|
|
188
|
+
description,
|
|
189
|
+
StepIconComponent = RecursicaStepIcon,
|
|
190
|
+
...rest
|
|
191
|
+
} = props;
|
|
192
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
193
|
+
const mergedClassNames = mergeClassNames(
|
|
194
|
+
{
|
|
195
|
+
root: styles.stepLabelRoot,
|
|
196
|
+
label: styles.stepLabel,
|
|
197
|
+
iconContainer: styles.stepIcon,
|
|
198
|
+
labelContainer: styles.stepBody,
|
|
199
|
+
},
|
|
200
|
+
(sanitizedProps as Record<string, unknown>).classes as
|
|
201
|
+
| Partial<Record<string, string>>
|
|
202
|
+
| undefined,
|
|
203
|
+
);
|
|
204
|
+
return (
|
|
205
|
+
<MuiStepLabel
|
|
206
|
+
ref={ref}
|
|
207
|
+
{...(sanitizedProps as MuiStepLabelProps)}
|
|
208
|
+
className={className || ""}
|
|
209
|
+
classes={mergedClassNames}
|
|
210
|
+
StepIconComponent={StepIconComponent}
|
|
211
|
+
optional={
|
|
212
|
+
description ? (
|
|
213
|
+
<div className={styles.stepDescription}>{description}</div>
|
|
214
|
+
) : (
|
|
215
|
+
rest.optional
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
/>
|
|
219
|
+
);
|
|
220
|
+
},
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
StepLabel.displayName = "StepLabel";
|
|
224
|
+
|
|
225
|
+
export type StepConnectorProps = RecursicaOverStyled<MuiStepConnectorProps>;
|
|
226
|
+
|
|
227
|
+
export const StepConnector = forwardRef<HTMLDivElement, StepConnectorProps>(
|
|
228
|
+
function StepConnector(props, ref) {
|
|
229
|
+
const { overStyled = false, className, ...rest } = props;
|
|
230
|
+
return (
|
|
231
|
+
<MuiStepConnector
|
|
232
|
+
ref={ref}
|
|
233
|
+
className={className || ""}
|
|
234
|
+
{...(filterStylingProps(rest, overStyled) as MuiStepConnectorProps)}
|
|
235
|
+
/>
|
|
236
|
+
);
|
|
237
|
+
},
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
StepConnector.displayName = "StepConnector";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Stepper - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Stepper` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Stepper } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Stepper } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Stepper active={1}>
|
|
24
|
+
<Stepper.Step label="First step" description="Create account" />
|
|
25
|
+
<Stepper.Step label="Second step" description="Verify email" />
|
|
26
|
+
</Stepper>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 3. Design System Integration
|
|
34
|
+
|
|
35
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
36
|
+
|
|
37
|
+
> [!IMPORTANT]
|
|
38
|
+
>
|
|
39
|
+
> - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
|
|
40
|
+
> - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
|
|
41
|
+
> - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
|
|
42
|
+
> - **Default step icon**: `StepLabel` renders its own token-driven circle (with a check mark
|
|
43
|
+
> once a step is completed) by default. Pass your own `StepIconComponent` prop to `StepLabel`
|
|
44
|
+
> to override it for a given step, or pass a custom `icon` node (e.g. `<StepLabel icon={<MyIcon />}>`)
|
|
45
|
+
> to render arbitrary content in place of the circle entirely.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Stepper";
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Switch Implementation Notes
|
|
2
|
+
|
|
3
|
+
Decisions and gotchas specific to wrapping `@mui/material`'s `Switch` for the UI Kit's Switch.
|
|
4
|
+
|
|
5
|
+
## Label/description/error
|
|
6
|
+
|
|
7
|
+
MUI's `Switch` has no built-in label/description/error rendering — built by hand here.
|
|
8
|
+
The label is a plain `<label>`; description/error render through the shared
|
|
9
|
+
`AssistiveElement` component (`assistiveWithIcon={false}`) instead of local styled divs,
|
|
10
|
+
so they inherit real design tokens rather than hardcoded Mantine defaults.
|
|
11
|
+
|
|
12
|
+
## `Switch.Group` compound export
|
|
13
|
+
|
|
14
|
+
`SwitchGroup.tsx` existed but wasn't attached as `Switch.Group`. Fixed.
|
|
15
|
+
|
|
16
|
+
## `SwitchGroup` didn't control its children — now fixed
|
|
17
|
+
|
|
18
|
+
MUI's `FormGroup` has no controlled-value concept — no equivalent to Mantine's real
|
|
19
|
+
`Switch.Group`, which threads a `string[]` of checked values and `checked`/`onChange` to each
|
|
20
|
+
child via context. This adapter's `SwitchGroup` used to destructure and discard
|
|
21
|
+
`value`/`defaultValue`/`onChange` entirely — purely cosmetic.
|
|
22
|
+
|
|
23
|
+
Fixed the same way this adapter's own `Checkbox`/`CheckboxGroup` already solved the identical
|
|
24
|
+
problem (a closer, in-repo precedent than `Accordion`, which the notes previously pointed to
|
|
25
|
+
without checking Checkbox first): a `SwitchGroupContext` provider on `SwitchGroup` carrying
|
|
26
|
+
`value`/`onChange`/`name`/`readOnly`, consumed by `Switch` to compute `isChecked` from array
|
|
27
|
+
membership and to translate each toggle into an add/remove against that array before calling
|
|
28
|
+
the group's `onChange`. Standalone (ungrouped) `Switch` usage is untouched — the group-derived
|
|
29
|
+
`checked`/`onChange` are only spread onto `<MuiSwitch>` when a `SwitchGroupContext` is present.
|
|
30
|
+
Verified live: initial `value`/`defaultValue` now renders correctly, clicking a sibling
|
|
31
|
+
switch toggles only its own entry in the array, and `readOnly` on the group disables every
|
|
32
|
+
child — all confirmed against the existing `SwitchGroup.stories.tsx` scenarios via Playwright.
|
|
33
|
+
|
|
34
|
+
## Thumb icon (check/x glyph)
|
|
35
|
+
|
|
36
|
+
MUI's `icon`/`checkedIcon` props are the _same mechanism_ MUI uses internally to render its
|
|
37
|
+
own default circular thumb (`icon: <the circle>, checkedIcon: <the circle>`, then
|
|
38
|
+
spread-overwritten by whatever public `icon`/`checkedIcon` the caller passes) — confirmed
|
|
39
|
+
against MUI's own `Switch.js`/`SwitchBase.js` source. Passing a raw glyph into them replaces
|
|
40
|
+
the whole thumb circle, it doesn't add an icon inside it.
|
|
41
|
+
|
|
42
|
+
Fixed the same way `Checkbox` in this adapter already solved the identical problem: build our
|
|
43
|
+
own combined node — a `.thumb`-styled `<span>` wrapping `.thumbIconWrapper` with both
|
|
44
|
+
`CheckIcon`/`CloseIcon` (inline SVGs, same paths as Mantine's, copied rather than imported
|
|
45
|
+
since adapter-mui-v7 doesn't depend on `@mantine/core`) — and pass _that same node reference_ as
|
|
46
|
+
both `icon` and `checkedIcon` (mirroring MUI's own `icon={icon} checkedIcon={icon}` pattern).
|
|
47
|
+
Same reference means it never unmounts/remounts on toggle, which is what lets the two glyphs
|
|
48
|
+
crossfade via CSS opacity instead of a hard swap — matching Mantine's `thumbIcon` behavior.
|
|
49
|
+
Verified against a live Storybook via adapter-tester (geometry + SVG count now match Mantine
|
|
50
|
+
1:1 across Default/Static Variations stories).
|
|
51
|
+
|
|
52
|
+
## Track/thumb geometry, checked-state selectors, focus ring
|
|
53
|
+
|
|
54
|
+
Original CSS was a copy of mantine-adapter's file, but MUI's DOM is structurally different
|
|
55
|
+
(`track`/`switchBase` are siblings, not nested; MUI hardcodes its own root box, hit-area
|
|
56
|
+
padding, and thumb travel distance for its own 20px default thumb). Fixed by driving
|
|
57
|
+
`.switchRoot`/`.switchBase`/`.thumb` sizing entirely from our tokens, replacing
|
|
58
|
+
`input:checked + .track` sibling selectors (never matched in MUI's DOM) with `:has()`-scoped
|
|
59
|
+
selectors, adding an explicit focus ring from `--recursica_brand_states_focus_*` tokens, and
|
|
60
|
+
hardcoding `color="default"` so MUI's own primary-blue hover/focus circle never activates.
|
|
61
|
+
Verified via live measurement (adapter-tester): track/thumb box dimensions now match Mantine
|
|
62
|
+
exactly (64×28 track, 20×20 thumb).
|
|
63
|
+
|
|
64
|
+
Two gotchas worth flagging for future MUI adapter work:
|
|
65
|
+
|
|
66
|
+
1. `classes.root` targets MUI's own switch span, but this component's outer wrapper `<div>`
|
|
67
|
+
(switch+label row) also uses `.root` — sizing one squeezes the other. Split into
|
|
68
|
+
`.switchRoot` (MUI switch only) vs `.root` (outer wrapper, cursor only).
|
|
69
|
+
2. CSS Modules hashes literal MUI state classes (`Mui-checked`, `Mui-focusVisible`) unless
|
|
70
|
+
wrapped in `:global()` — same pattern already used in `Accordion`/`Button`.
|
|
71
|
+
|
|
72
|
+
## Disabled-state opacity didn't reach the thumb
|
|
73
|
+
|
|
74
|
+
**Found 2026-08-14, reported by Matt:** the Read Only story's thumb stayed full-color/opacity
|
|
75
|
+
while Mantine's dimmed along with the track. Same root cause as the geometry work above:
|
|
76
|
+
Mantine nests `.thumb` inside `.track`, so an `opacity` on `.track` visually dims the thumb for
|
|
77
|
+
free; MUI has them as siblings, so the disabled-opacity selectors (which only targeted
|
|
78
|
+
`.track`) never touched the thumb at all. Fixed by adding `.thumb` to both selectors alongside
|
|
79
|
+
`.track`. Verified live: thumb now dims identically to Mantine in both the plain-disabled and
|
|
80
|
+
disabled-checked cases.
|
|
81
|
+
|
|
82
|
+
## Track opacity — MUI's own always-on defaults, unrelated to our tokens
|
|
83
|
+
|
|
84
|
+
MUI's `SwitchTrack` styled component sets `opacity: 0.38` unconditionally (its own faded-pill
|
|
85
|
+
baseline), and separately `.Mui-checked + .track { opacity: 0.5 }` when checked — neither has
|
|
86
|
+
an equivalent in our token schema, and neither was being cancelled. Result: every enabled track
|
|
87
|
+
was dimmed by MUI's own opacity, most visibly on the checked state (deep red washed out to
|
|
88
|
+
pink). Fixed with an explicit `opacity: 1` in both the base `.track` rule and the
|
|
89
|
+
`.root:has(input:checked) .track` rule (needed in both — MUI's checked-specific selector is
|
|
90
|
+
more specific than its own base rule, so overriding only the base wasn't enough). Disabled-state
|
|
91
|
+
opacity is unaffected; those selectors are already more specific than either of these.
|
|
92
|
+
|
|
93
|
+
## Focus ring was on the thumb's hit-area circle, not the track
|
|
94
|
+
|
|
95
|
+
`.switchBase:global(.Mui-focusVisible)` is MUI's actual focusable element, but it's sized to
|
|
96
|
+
the thumb's 20×20 hit area, not the 64×28 track — so the ring drew a small circle instead of
|
|
97
|
+
outlining the switch. Moved to `.switchBase:global(.Mui-focusVisible) ~ .track` (siblings under
|
|
98
|
+
`.switchRoot`, switchBase first) so the ring renders on the track itself. Mantine-adapter had
|
|
99
|
+
the mirror-image bug: no override at all, so Mantine's own default outline (blue) showed on the
|
|
100
|
+
hidden `<input>` — fixed there with `.root input:focus-visible { outline: none }` +
|
|
101
|
+
`.root input:focus-visible + .track { ... }`, drawing the same Recursica-token ring in the same
|
|
102
|
+
place.
|
|
103
|
+
|
|
104
|
+
## `classNames` prop-name bug — external override was silently inert
|
|
105
|
+
|
|
106
|
+
The external override merge read `restRecord.classNames`, but MUI's actual prop is `classes`
|
|
107
|
+
(that's Mantine's naming, copied over by mistake) — fixed. Note only `root`/`track`/
|
|
108
|
+
`switchBase` are real MUI `classes` slots; `body`/`trackLabel`/`labelWrapper`/`label` are this
|
|
109
|
+
component's own hardcoded elements (styled directly in JSX, not via MUI's `classes` prop) and
|
|
110
|
+
remain unreachable through this override path — a separate, pre-existing gap, not something the
|
|
111
|
+
prop-name fix could address.
|
|
112
|
+
|
|
113
|
+
## `CustomReadOnly` story showed no label text
|
|
114
|
+
|
|
115
|
+
**Found 2026-08-30, source-of-truth audit against mantine.** `Switch.tsx` destructures `label`
|
|
116
|
+
out of `props` (needed for the normal, non-read-only render path), but the `readOnly` branch
|
|
117
|
+
built its `roNode` from `restRecord.label` — `restRecord` comes from `rest`, which no longer has
|
|
118
|
+
`label` on it since it was already pulled off `props` separately. Result: the `readOnlyComponent`
|
|
119
|
+
render prop always received `label={undefined}`, so `ui-kit-switch--custom-read-only` rendered
|
|
120
|
+
just "DISABLED" instead of "Standard Switch DISABLED". Mantine's version never destructures
|
|
121
|
+
`label` separately, so `restRecord.label` was always populated there — same story args on both
|
|
122
|
+
sides, the bug was purely in this component's own prop plumbing. Fixed by reading the already-
|
|
123
|
+
destructured `label` variable instead of `restRecord.label`.
|
|
124
|
+
|
|
125
|
+
## `StaticVariations` story spacing didn't match mantine
|
|
126
|
+
|
|
127
|
+
**Found 2026-08-30, source-of-truth audit against mantine.** The story used `<Stack
|
|
128
|
+
spacing="xl">`, but `"xl"` isn't a key in this adapter's `SPACING_MAP` (only `"rec-*"`-prefixed
|
|
129
|
+
tokens are) — MUI's `Stack` then received an unrecognized raw string as its native `spacing`
|
|
130
|
+
prop, which resolves to an invalid CSS length and collapses to no gap at all, bunching every
|
|
131
|
+
switch together. Fixed by using `spacing="rec-xl"` (24px via
|
|
132
|
+
`--recursica_brand_dimensions_general_xl`), the closest existing token. Note this is 24px vs.
|
|
133
|
+
mantine's native `gap="xl"` (32px, Mantine's own spacing scale, unrelated to Recursica tokens) —
|
|
134
|
+
close enough visually and no exact rec-\* equivalent of Mantine's "xl" exists; flagged rather than
|
|
135
|
+
chasing pixel-parity on an arbitrary story-only value.
|
|
136
|
+
|
|
137
|
+
## `SwitchGroup` side-by-side layout always rendered as if stacked
|
|
138
|
+
|
|
139
|
+
**Found 2026-08-14, reported by Matt:** the `SideBySideLayout` story showed the group label
|
|
140
|
+
above the switches instead of beside them. Root cause: `SwitchGroup` passed the switch-item's
|
|
141
|
+
own inline label max-width token (200px) as the group's `controlMaxWidth` — but the mandatory
|
|
142
|
+
side-by-side label column is a fixed 224px, wider than that cap, so the label always overflowed
|
|
143
|
+
onto its own line regardless of layout mode. Reproduced identically in Mantine (same code
|
|
144
|
+
pattern, not a MUI-only bug). Fixed by not capping the group's control width at all — each
|
|
145
|
+
switch's own label already wraps at 200px via `.labelWrapper`, so no group-level cap is needed.
|
|
146
|
+
Verified live in both adapters: side-by-side now shows the label column at left with the
|
|
147
|
+
switches beside it; stacked layout unaffected.
|