@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,93 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import React, { forwardRef } from "react";
|
|
3
|
+
import { type ReadOnlyFieldType } from "@recursica/adapter-common";
|
|
4
|
+
import {
|
|
5
|
+
FormControlWrapper,
|
|
6
|
+
type FormControlWrapperProps,
|
|
7
|
+
} from "../FormControlWrapper/FormControlWrapper";
|
|
8
|
+
import { ReadOnlyField } from "./ReadOnlyField";
|
|
9
|
+
|
|
10
|
+
export interface WithReadOnlyWrapperProps
|
|
11
|
+
extends Omit<FormControlWrapperProps, "children" | "overStyled"> {
|
|
12
|
+
/** Injects whether the field defaults to reading mode natively */
|
|
13
|
+
readOnly?: boolean;
|
|
14
|
+
/** Explicit React component directly overtaking the baseline text renderer when read-only mode is active */
|
|
15
|
+
readOnlyComponent?: React.ElementType<any>;
|
|
16
|
+
/** Custom renderer explicitly responsible for formatting missing/empty value mappings (overriding default 'N/A') */
|
|
17
|
+
emptyValueComponent?: React.ElementType<{ value?: any }>;
|
|
18
|
+
/** The full native props dictionary securely forwarded into the custom readOnlyComponent if active */
|
|
19
|
+
readOnlyNativeProps?: any;
|
|
20
|
+
/** Instructs the underlying generic ReadOnlyField which raw visual structure to bridge automatically */
|
|
21
|
+
readOnlyType?: ReadOnlyFieldType;
|
|
22
|
+
/** The isolated raw data value intercepted explicitly into the ReadOnly formatters */
|
|
23
|
+
readOnlyValue?: any;
|
|
24
|
+
/** Safely enables deep overrides transparently bypassing block filters */
|
|
25
|
+
overStyled?: boolean;
|
|
26
|
+
/** The nested active node dynamically exposed exclusively when read-only bounds are disabled */
|
|
27
|
+
activeComponent: React.ReactNode;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Universal execution barrier trapping readOnly states globally.
|
|
32
|
+
* Natively delegates active logic down avoiding duplicative internal component bindings dynamically.
|
|
33
|
+
*/
|
|
34
|
+
export const WithReadOnlyWrapper = forwardRef<
|
|
35
|
+
HTMLDivElement,
|
|
36
|
+
WithReadOnlyWrapperProps
|
|
37
|
+
>(function WithReadOnlyWrapper(
|
|
38
|
+
{
|
|
39
|
+
readOnly,
|
|
40
|
+
readOnlyComponent,
|
|
41
|
+
readOnlyType = "text",
|
|
42
|
+
readOnlyValue,
|
|
43
|
+
readOnlyNativeProps,
|
|
44
|
+
emptyValueComponent,
|
|
45
|
+
activeComponent,
|
|
46
|
+
overStyled,
|
|
47
|
+
onLabelEditClick,
|
|
48
|
+
...wrapperProps
|
|
49
|
+
},
|
|
50
|
+
ref,
|
|
51
|
+
) {
|
|
52
|
+
if (readOnly) {
|
|
53
|
+
if (readOnlyComponent) {
|
|
54
|
+
const ReadOnlyComponent = readOnlyComponent;
|
|
55
|
+
return (
|
|
56
|
+
<FormControlWrapper
|
|
57
|
+
ref={ref}
|
|
58
|
+
{...wrapperProps}
|
|
59
|
+
onLabelEditClick={onLabelEditClick}
|
|
60
|
+
overStyled={overStyled as true}
|
|
61
|
+
>
|
|
62
|
+
<ReadOnlyComponent {...readOnlyNativeProps} />
|
|
63
|
+
</FormControlWrapper>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<ReadOnlyField
|
|
69
|
+
ref={ref}
|
|
70
|
+
type={readOnlyType}
|
|
71
|
+
value={readOnlyValue}
|
|
72
|
+
emptyValueComponent={emptyValueComponent}
|
|
73
|
+
onLabelEditClick={onLabelEditClick}
|
|
74
|
+
overStyled={overStyled as true}
|
|
75
|
+
{...wrapperProps}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Active Standard Execution natively forwarding bound children implicitly
|
|
81
|
+
return (
|
|
82
|
+
<FormControlWrapper
|
|
83
|
+
ref={ref}
|
|
84
|
+
{...wrapperProps}
|
|
85
|
+
onLabelEditClick={onLabelEditClick}
|
|
86
|
+
overStyled={overStyled as true}
|
|
87
|
+
>
|
|
88
|
+
{activeComponent}
|
|
89
|
+
</FormControlWrapper>
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
WithReadOnlyWrapper.displayName = "WithReadOnlyWrapper";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# RecursicaThemeProvider - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use `RecursicaThemeProvider` in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
> [!NOTE] > `RecursicaThemeProvider` is defined once in `@recursica/adapter-common` and re-exported here so it shares the exact same behavior across every Recursica adapter.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Import Reference
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { RecursicaThemeProvider } from "@recursica/adapter-mui-v7";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. Basic Example
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { StyledEngineProvider } from "@mui/material/styles";
|
|
21
|
+
import { RecursicaThemeProvider } from "@recursica/adapter-mui-v7";
|
|
22
|
+
|
|
23
|
+
function App() {
|
|
24
|
+
return (
|
|
25
|
+
<StyledEngineProvider injectFirst>
|
|
26
|
+
<RecursicaThemeProvider theme="light">
|
|
27
|
+
{/* Your App Components */}
|
|
28
|
+
</RecursicaThemeProvider>
|
|
29
|
+
</StyledEngineProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
By default, `RecursicaThemeProvider` also wraps `children` in a base [`Layer`](../Layer/USAGE.md) (`layer={0}`), so surface/border/elevation variables resolve immediately — no separate `Layer` needed for the page background.
|
|
35
|
+
|
|
36
|
+
If you want to place the base layer yourself (e.g. to use `contentsOnly`, or to control exactly where layer 0 starts in the tree), opt out with `initLayer0={false}`:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { RecursicaThemeProvider, Layer } from "@recursica/adapter-mui-v7";
|
|
40
|
+
|
|
41
|
+
<RecursicaThemeProvider theme="light" initLayer0={false}>
|
|
42
|
+
<Layer layer={0}>{/* Your App Components */}</Layer>
|
|
43
|
+
</RecursicaThemeProvider>;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 3. Design System Integration
|
|
49
|
+
|
|
50
|
+
> [!IMPORTANT]
|
|
51
|
+
>
|
|
52
|
+
> - **Required for setup**: `RecursicaThemeProvider` must wrap your entire application, once, near the root, inside `<StyledEngineProvider injectFirst>`. See [SETUP.md](../../../SETUP.md) for the full setup sequence.
|
|
53
|
+
> - **`initLayer0` (default `true`)**: Automatically wraps `children` in a layer-0 [`Layer`](../Layer/USAGE.md). `RecursicaThemeProvider` itself only sets `data-recursica-theme` (`"light"` or `"dark"`, defaults to `"light"`) on `document.documentElement` — without a `Layer` in the tree (either the automatic one or one you add yourself with `initLayer0={false}`), none of Recursica's surface CSS variables resolve.
|
|
54
|
+
> - **Runtime theme switching**: Changing the `theme` prop re-runs the effect and updates `data-recursica-theme` immediately, so you can drive light/dark switching from application state.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 4. Key Integration Features & Constraints
|
|
59
|
+
|
|
60
|
+
`RecursicaThemeProvider` also wires up the `overStyled` development-mode visual auditing helper (see [OVERSTYLING.md](../../../OVERSTYLING.md)) — `recursica.toggleOverStyled()` in the browser console only works once this provider has mounted.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# SegmentedControl Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Labels rendering uppercase (2026-08-19)
|
|
4
|
+
|
|
5
|
+
- **Root cause:** `--recursica_ui-kit_components_segmented-control-item_variants_selection-states_{unselected,selected}_properties_text_text-transform` resolves to `--recursica_tokens_font_cases_original`, which has no definition in `recursica_variables_scoped.css` (only `_lowercase`/`_titlecase`/`_uppercase` are defined there). The resulting `var()` on `.label` is invalid, and since `text-transform` is an inherited property, the invalid value falls back to the inherited value from `.control` (`.MuiToggleButton-root`) — which carries MUI's own `text-transform: uppercase` button default. Mantine's control has no such native uppercase default, so the same broken token never surfaced there.
|
|
6
|
+
- **Fix:** Reset `text-transform: none` on `.root .control` alongside the other MUI ToggleButton baseline resets (padding/border/etc.) already there, so nothing uppercase is left to inherit. Matches the existing `text-transform: none` MUI-baseline reset pattern in `Button.module.css`. Not a design-token value — it's a structural reset of MUI's own default, same category as the other hardcoded resets already exempted at the top of this file.
|
|
7
|
+
|
|
8
|
+
## Per-item `icon`
|
|
9
|
+
|
|
10
|
+
`RecursicaSegmentedControlProps.data` objects accept an optional `icon`, rendered ahead of `label` inside the existing `.label` div (already a flex container with the icon-size/gap tokens wired), so no CSS changes were needed.
|
|
11
|
+
|
|
12
|
+
## Whole-control `disabled`
|
|
13
|
+
|
|
14
|
+
`RecursicaSegmentedControlProps.disabled` was previously typed `never` and stripped at runtime. It's now a real `boolean?`, passed straight through to MUI's native `ToggleButtonGroup.disabled`, which cascades to every child `ToggleButton` via `ToggleButtonGroupContext`. Per-item `data[].disabled` now passes `undefined` (not `false`) when unset, so it doesn't mask that context cascade — an item's own explicit `disabled` still overrides the group.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- border-style: solid; on container and indicator
|
|
3
|
+
- background-color: transparent; on label hover (overriding Mantine)
|
|
4
|
+
- Scope prefix .root to enforce Figma tokens over Mantine's inline calculation without using !important
|
|
5
|
+
- padding/border/border-radius/min-height/min-width: 0 and background-color: transparent on
|
|
6
|
+
.control (MUI's ToggleButton root) so its own baseline button box model does not stack on
|
|
7
|
+
top of .label's token-driven height/border/radius, mirroring Mantine's transparent .control wrapper
|
|
8
|
+
- text-transform: none on .control resets MUI's ToggleButton uppercase default (see comment
|
|
9
|
+
above that rule); needed because the item text-transform token has no valid scoped value
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
.root {
|
|
13
|
+
background-color: var(
|
|
14
|
+
--recursica_ui-kit_components_segmented-control_properties_colors_background-color
|
|
15
|
+
);
|
|
16
|
+
border: var(
|
|
17
|
+
--recursica_ui-kit_components_segmented-control_properties_border-size
|
|
18
|
+
)
|
|
19
|
+
solid
|
|
20
|
+
var(
|
|
21
|
+
--recursica_ui-kit_components_segmented-control_properties_colors_border-color
|
|
22
|
+
);
|
|
23
|
+
border-radius: var(
|
|
24
|
+
--recursica_ui-kit_components_segmented-control_properties_border-radius
|
|
25
|
+
);
|
|
26
|
+
padding: var(
|
|
27
|
+
--recursica_ui-kit_components_segmented-control_properties_padding-vertical
|
|
28
|
+
)
|
|
29
|
+
var(
|
|
30
|
+
--recursica_ui-kit_components_segmented-control_properties_padding-horizontal
|
|
31
|
+
);
|
|
32
|
+
box-shadow: var(
|
|
33
|
+
--recursica_ui-kit_components_segmented-control_properties_elevation
|
|
34
|
+
);
|
|
35
|
+
gap: var(--recursica_ui-kit_components_segmented-control_properties_item-gap);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* MUI's ToggleButton root ships its own padding/border/border-radius/min-height/min-width and a
|
|
39
|
+
text-transform: uppercase button default; reset all of it so it doesn't stack on top of (or leak
|
|
40
|
+
through, via inheritance, into) .label's token-driven box model/typography below. The
|
|
41
|
+
text-transform reset matters because the item's text-transform token
|
|
42
|
+
(segmented-control-item_..._text_text-transform) currently has no valid scoped value to resolve
|
|
43
|
+
to, so without this reset .label's own `text-transform: var(...)` below is invalid and the
|
|
44
|
+
inherited MUI uppercase default would otherwise show through (Mantine has no such native
|
|
45
|
+
default, so it never surfaced there). */
|
|
46
|
+
.root .control {
|
|
47
|
+
padding: 0;
|
|
48
|
+
border: none;
|
|
49
|
+
border-radius: 0;
|
|
50
|
+
min-height: 0;
|
|
51
|
+
min-width: 0;
|
|
52
|
+
background-color: transparent;
|
|
53
|
+
text-transform: none;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.root .control:hover {
|
|
57
|
+
background-color: transparent;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.root .label {
|
|
61
|
+
padding-left: var(
|
|
62
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_padding-horizontal
|
|
63
|
+
);
|
|
64
|
+
padding-right: var(
|
|
65
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_padding-horizontal
|
|
66
|
+
);
|
|
67
|
+
height: var(
|
|
68
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_height
|
|
69
|
+
);
|
|
70
|
+
border-radius: var(
|
|
71
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_border-radius
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
border: var(
|
|
75
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_border-size
|
|
76
|
+
)
|
|
77
|
+
solid
|
|
78
|
+
var(
|
|
79
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_colors_border-color
|
|
80
|
+
);
|
|
81
|
+
background-color: var(
|
|
82
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_colors_background-color
|
|
83
|
+
);
|
|
84
|
+
box-shadow: var(
|
|
85
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_elevation
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
font-family: var(
|
|
89
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_font-family
|
|
90
|
+
);
|
|
91
|
+
font-size: var(
|
|
92
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_font-size
|
|
93
|
+
);
|
|
94
|
+
font-style: var(
|
|
95
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_font-style
|
|
96
|
+
);
|
|
97
|
+
font-weight: var(
|
|
98
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_font-weight
|
|
99
|
+
);
|
|
100
|
+
letter-spacing: var(
|
|
101
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_letter-spacing
|
|
102
|
+
);
|
|
103
|
+
line-height: var(
|
|
104
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_line-height
|
|
105
|
+
);
|
|
106
|
+
text-decoration: var(
|
|
107
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_text-decoration
|
|
108
|
+
);
|
|
109
|
+
text-transform: var(
|
|
110
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_text_text-transform
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
color: var(
|
|
114
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_unselected_properties_colors_text-color
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
display: flex;
|
|
118
|
+
align-items: center;
|
|
119
|
+
justify-content: center;
|
|
120
|
+
gap: var(
|
|
121
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_icon-text-gap
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.root .label svg {
|
|
126
|
+
width: var(
|
|
127
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_icon-size
|
|
128
|
+
);
|
|
129
|
+
height: var(
|
|
130
|
+
--recursica_ui-kit_components_segmented-control-item_properties_item_icon-size
|
|
131
|
+
);
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Mantine adds a background on hover, we must strictly strip it */
|
|
136
|
+
.root .label:hover {
|
|
137
|
+
background-color: transparent;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Mantine adds separators via ::before on the .control */
|
|
141
|
+
.root .control::before {
|
|
142
|
+
background-color: var(
|
|
143
|
+
--recursica_ui-kit_components_segmented-control_properties_colors_divider-color
|
|
144
|
+
);
|
|
145
|
+
width: var(
|
|
146
|
+
--recursica_ui-kit_components_segmented-control_properties_divider-size
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/* Indicator mapping (MUI ToggleButton applies .Mui-selected to the button instead of rendering a sliding indicator).
|
|
151
|
+
Mui-selected must be wrapped in :global() — otherwise CSS Modules locally hashes it and the
|
|
152
|
+
selector never matches MUI's actual global class (silently dropping the selected state). */
|
|
153
|
+
.root .control:global(.Mui-selected) {
|
|
154
|
+
background-color: var(
|
|
155
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_colors_background-color
|
|
156
|
+
);
|
|
157
|
+
border: var(
|
|
158
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_border-size
|
|
159
|
+
)
|
|
160
|
+
solid
|
|
161
|
+
var(
|
|
162
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_colors_border-color
|
|
163
|
+
);
|
|
164
|
+
box-shadow: var(
|
|
165
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_elevation
|
|
166
|
+
);
|
|
167
|
+
border-radius: var(
|
|
168
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_border-radius
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Selected label text color override */
|
|
173
|
+
.root .control:global(.Mui-selected) .label {
|
|
174
|
+
color: var(
|
|
175
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_colors_text-color
|
|
176
|
+
);
|
|
177
|
+
font-family: var(
|
|
178
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_font-family
|
|
179
|
+
);
|
|
180
|
+
font-size: var(
|
|
181
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_font-size
|
|
182
|
+
);
|
|
183
|
+
font-style: var(
|
|
184
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_font-style
|
|
185
|
+
);
|
|
186
|
+
font-weight: var(
|
|
187
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_font-weight
|
|
188
|
+
);
|
|
189
|
+
letter-spacing: var(
|
|
190
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_letter-spacing
|
|
191
|
+
);
|
|
192
|
+
line-height: var(
|
|
193
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_line-height
|
|
194
|
+
);
|
|
195
|
+
text-decoration: var(
|
|
196
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_text-decoration
|
|
197
|
+
);
|
|
198
|
+
text-transform: var(
|
|
199
|
+
--recursica_ui-kit_components_segmented-control-item_variants_selection-states_selected_properties_text_text-transform
|
|
200
|
+
);
|
|
201
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { SegmentedControl } from "./SegmentedControl";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof SegmentedControl> = {
|
|
5
|
+
title: "UI-Kit/SegmentedControl",
|
|
6
|
+
component: SegmentedControl,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component:
|
|
12
|
+
"SegmentedControl provides a linear set of two or more segments, each of which functions as a mutually exclusive button.",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
orientation: {
|
|
18
|
+
control: "radio",
|
|
19
|
+
options: ["horizontal", "vertical"],
|
|
20
|
+
},
|
|
21
|
+
fullWidth: {
|
|
22
|
+
control: "boolean",
|
|
23
|
+
},
|
|
24
|
+
disabled: {
|
|
25
|
+
control: "boolean",
|
|
26
|
+
},
|
|
27
|
+
data: { table: { disable: true } },
|
|
28
|
+
defaultChecked: { table: { disable: true } },
|
|
29
|
+
},
|
|
30
|
+
} satisfies Meta<typeof SegmentedControl>;
|
|
31
|
+
|
|
32
|
+
export default meta;
|
|
33
|
+
type Story = StoryObj<typeof SegmentedControl>;
|
|
34
|
+
|
|
35
|
+
export const Default: Story = {
|
|
36
|
+
args: {
|
|
37
|
+
data: ["React", "Angular", "Vue", "Svelte"],
|
|
38
|
+
orientation: "horizontal",
|
|
39
|
+
fullWidth: false,
|
|
40
|
+
},
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
42
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
43
|
+
return <SegmentedControl {...args} />;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const FullWidth: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
data: ["Daily", "Weekly", "Monthly"],
|
|
50
|
+
fullWidth: true,
|
|
51
|
+
},
|
|
52
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
53
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
54
|
+
return <SegmentedControl {...args} />;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const Vertical: Story = {
|
|
59
|
+
args: {
|
|
60
|
+
data: ["Option 1", "Option 2", "Option 3"],
|
|
61
|
+
orientation: "vertical",
|
|
62
|
+
},
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
64
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
65
|
+
return <SegmentedControl {...args} />;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const Disabled: Story = {
|
|
70
|
+
args: {
|
|
71
|
+
data: ["Preview", "Code", "Edit"],
|
|
72
|
+
disabled: true,
|
|
73
|
+
},
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
75
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
76
|
+
return <SegmentedControl {...args} />;
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const CheckIcon = () => (
|
|
81
|
+
<svg
|
|
82
|
+
viewBox="0 0 24 24"
|
|
83
|
+
fill="none"
|
|
84
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
85
|
+
stroke="currentColor"
|
|
86
|
+
strokeWidth="2"
|
|
87
|
+
strokeLinecap="round"
|
|
88
|
+
strokeLinejoin="round"
|
|
89
|
+
>
|
|
90
|
+
<polyline points="20 6 9 17 4 12" />
|
|
91
|
+
</svg>
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
export const WithIcons: Story = {
|
|
95
|
+
args: {
|
|
96
|
+
data: [
|
|
97
|
+
{ value: "daily", label: "Daily", icon: <CheckIcon /> },
|
|
98
|
+
{ value: "weekly", label: "Weekly", icon: <CheckIcon /> },
|
|
99
|
+
{ value: "monthly", label: "Monthly", icon: <CheckIcon /> },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
|
|
103
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
104
|
+
return <SegmentedControl {...args} />;
|
|
105
|
+
},
|
|
106
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future SegmentedControl component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { forwardRef, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ToggleButtonGroup as MuiSegmentedControl,
|
|
4
|
+
ToggleButton,
|
|
5
|
+
type ToggleButtonGroupProps as MuiSegmentedControlProps,
|
|
6
|
+
} from "@mui/material";
|
|
7
|
+
import {
|
|
8
|
+
filterStylingProps,
|
|
9
|
+
mergeClassNames,
|
|
10
|
+
type RecursicaOverStyled,
|
|
11
|
+
} from "../../utils/filterStylingProps";
|
|
12
|
+
import styles from "./SegmentedControl.module.css";
|
|
13
|
+
|
|
14
|
+
import { type RecursicaSegmentedControlProps } from "@recursica/adapter-common";
|
|
15
|
+
|
|
16
|
+
export type SegmentedControlProps = RecursicaOverStyled<
|
|
17
|
+
Omit<
|
|
18
|
+
MuiSegmentedControlProps,
|
|
19
|
+
| "variant"
|
|
20
|
+
| "size"
|
|
21
|
+
| "radius"
|
|
22
|
+
| "color"
|
|
23
|
+
| "classNames"
|
|
24
|
+
| "className"
|
|
25
|
+
| "value"
|
|
26
|
+
> & {
|
|
27
|
+
className?: string;
|
|
28
|
+
classNames?: Partial<Record<string, string>>;
|
|
29
|
+
} & RecursicaSegmentedControlProps
|
|
30
|
+
>;
|
|
31
|
+
|
|
32
|
+
function useSegmentedControlClassNames(restRecord: Record<string, unknown>): {
|
|
33
|
+
className: string;
|
|
34
|
+
classNames: Partial<Record<string, string>>;
|
|
35
|
+
} {
|
|
36
|
+
const mergedClassNames = mergeClassNames(
|
|
37
|
+
{
|
|
38
|
+
root: styles.root,
|
|
39
|
+
control: styles.control,
|
|
40
|
+
label: styles.label,
|
|
41
|
+
},
|
|
42
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
46
|
+
const finalClass = classNameProp
|
|
47
|
+
? `${styles.root} ${classNameProp}`
|
|
48
|
+
: styles.root;
|
|
49
|
+
|
|
50
|
+
return { className: finalClass, classNames: mergedClassNames };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const _SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>(
|
|
54
|
+
function SegmentedControl(
|
|
55
|
+
{
|
|
56
|
+
overStyled = false,
|
|
57
|
+
orientation = "horizontal",
|
|
58
|
+
fullWidth,
|
|
59
|
+
data = [],
|
|
60
|
+
value,
|
|
61
|
+
disabled,
|
|
62
|
+
onChange,
|
|
63
|
+
...rest
|
|
64
|
+
},
|
|
65
|
+
ref,
|
|
66
|
+
) {
|
|
67
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
68
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
69
|
+
|
|
70
|
+
const stylingParams = useSegmentedControlClassNames(restRecord);
|
|
71
|
+
|
|
72
|
+
// MUI's ToggleButtonGroup is controlled-only and selects nothing when `value` is
|
|
73
|
+
// undefined; Mantine's SegmentedControl instead defaults to the first data item. Track an
|
|
74
|
+
// uncontrolled fallback so both adapters render the same default selection.
|
|
75
|
+
const firstValue = data.length
|
|
76
|
+
? typeof data[0] === "string"
|
|
77
|
+
? data[0]
|
|
78
|
+
: data[0].value
|
|
79
|
+
: undefined;
|
|
80
|
+
const [uncontrolledValue, setUncontrolledValue] = useState<
|
|
81
|
+
string | undefined
|
|
82
|
+
>(value ?? firstValue);
|
|
83
|
+
const activeValue = value !== undefined ? value : uncontrolledValue;
|
|
84
|
+
|
|
85
|
+
const handleChange = (
|
|
86
|
+
event: React.MouseEvent<HTMLElement>,
|
|
87
|
+
newValue: string | null,
|
|
88
|
+
) => {
|
|
89
|
+
if (newValue !== null) {
|
|
90
|
+
setUncontrolledValue(newValue);
|
|
91
|
+
onChange?.(event, newValue);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<MuiSegmentedControl
|
|
97
|
+
ref={ref}
|
|
98
|
+
{...(sanitizedProps as Omit<
|
|
99
|
+
MuiSegmentedControlProps,
|
|
100
|
+
"variant" | "size" | "value" | "onChange"
|
|
101
|
+
>)}
|
|
102
|
+
className={stylingParams.className}
|
|
103
|
+
classes={stylingParams.classNames}
|
|
104
|
+
orientation={orientation}
|
|
105
|
+
fullWidth={fullWidth}
|
|
106
|
+
data-orientation={orientation}
|
|
107
|
+
exclusive
|
|
108
|
+
disabled={disabled}
|
|
109
|
+
value={activeValue}
|
|
110
|
+
onChange={
|
|
111
|
+
handleChange as React.ComponentProps<
|
|
112
|
+
typeof MuiSegmentedControl
|
|
113
|
+
>["onChange"]
|
|
114
|
+
}
|
|
115
|
+
>
|
|
116
|
+
{data.map((item) => {
|
|
117
|
+
const itemValue = typeof item === "string" ? item : item.value;
|
|
118
|
+
const itemLabel = typeof item === "string" ? item : item.label;
|
|
119
|
+
// `undefined` (not `false`) for items with no per-item override, so the group-level
|
|
120
|
+
// `disabled` above can cascade through MUI's ToggleButtonGroupContext instead of being
|
|
121
|
+
// masked by an explicit `false` on every ToggleButton.
|
|
122
|
+
const itemDisabled =
|
|
123
|
+
typeof item === "string" ? undefined : item.disabled;
|
|
124
|
+
const itemIcon = typeof item === "string" ? undefined : item.icon;
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<ToggleButton
|
|
128
|
+
key={itemValue}
|
|
129
|
+
value={itemValue}
|
|
130
|
+
disabled={itemDisabled}
|
|
131
|
+
className={stylingParams.classNames.control}
|
|
132
|
+
>
|
|
133
|
+
<div className={stylingParams.classNames.label}>
|
|
134
|
+
{itemIcon}
|
|
135
|
+
{itemLabel}
|
|
136
|
+
</div>
|
|
137
|
+
</ToggleButton>
|
|
138
|
+
);
|
|
139
|
+
})}
|
|
140
|
+
</MuiSegmentedControl>
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
_SegmentedControl.displayName = "SegmentedControl";
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Recursica SegmentedControl component wrapping Mui's SegmentedControl.
|
|
148
|
+
*/
|
|
149
|
+
export const SegmentedControl = _SegmentedControl;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# SegmentedControl - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `SegmentedControl` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { SegmentedControl } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { SegmentedControl } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <SegmentedControl data={["Preview", "Code", "Edit"]} />;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Each `data` item may also be an object with an optional `icon`, rendered ahead of the label:
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<SegmentedControl
|
|
30
|
+
data={[
|
|
31
|
+
{ value: "daily", label: "Daily", icon: <CheckIcon /> },
|
|
32
|
+
{ value: "weekly", label: "Weekly" },
|
|
33
|
+
]}
|
|
34
|
+
/>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 3. Design System Integration
|
|
40
|
+
|
|
41
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
42
|
+
|
|
43
|
+
> [!IMPORTANT]
|
|
44
|
+
>
|
|
45
|
+
> - **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.
|
|
46
|
+
> - **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.
|
|
47
|
+
> - **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.
|
|
48
|
+
|
|
49
|
+
A top-level `disabled` disables every item at once; an individual item can still be disabled on its own via `data[].disabled`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./SegmentedControl";
|