@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,103 @@
|
|
|
1
|
+
import { forwardRef, type CSSProperties } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Menu as MuiMenu,
|
|
4
|
+
type MenuProps as MuiMenuProps,
|
|
5
|
+
MenuItem as MuiMenuItem,
|
|
6
|
+
type MenuItemProps as MuiMenuItemProps,
|
|
7
|
+
Divider as MuiDivider,
|
|
8
|
+
type DividerProps as MuiDividerProps,
|
|
9
|
+
} from "@mui/material";
|
|
10
|
+
import {
|
|
11
|
+
filterStylingProps,
|
|
12
|
+
mergeClassNames,
|
|
13
|
+
type RecursicaOverStyled,
|
|
14
|
+
} from "../../utils/filterStylingProps";
|
|
15
|
+
import styles from "./Menu.module.css";
|
|
16
|
+
|
|
17
|
+
import { type RecursicaMenuProps } from "@recursica/adapter-common";
|
|
18
|
+
|
|
19
|
+
export type MenuProps = RecursicaOverStyled<MuiMenuProps & RecursicaMenuProps>;
|
|
20
|
+
|
|
21
|
+
export const Menu = forwardRef<HTMLDivElement, MenuProps>(function Menu(
|
|
22
|
+
{ overStyled = false, className, maxHeight, ...rest },
|
|
23
|
+
ref,
|
|
24
|
+
) {
|
|
25
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
26
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
27
|
+
|
|
28
|
+
const mergedClassNames = mergeClassNames(
|
|
29
|
+
{
|
|
30
|
+
paper: styles.dropdown,
|
|
31
|
+
list: styles.dropdown,
|
|
32
|
+
},
|
|
33
|
+
restRecord.classes as Partial<Record<string, string>> | undefined,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// `maxHeight` is a caller-supplied override of the token-driven dropdown max-height, applied
|
|
37
|
+
// to the Paper slot's inline style — an explicit per-instance escape hatch, not a design token.
|
|
38
|
+
const callerSlotProps = restRecord.slotProps as
|
|
39
|
+
| { paper?: Record<string, unknown> }
|
|
40
|
+
| undefined;
|
|
41
|
+
const mergedSlotProps = maxHeight
|
|
42
|
+
? {
|
|
43
|
+
...callerSlotProps,
|
|
44
|
+
paper: {
|
|
45
|
+
...callerSlotProps?.paper,
|
|
46
|
+
style: {
|
|
47
|
+
...(callerSlotProps?.paper?.style as CSSProperties | undefined),
|
|
48
|
+
maxHeight,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
: callerSlotProps;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<MuiMenu
|
|
56
|
+
ref={ref}
|
|
57
|
+
{...(sanitizedProps as MuiMenuProps)}
|
|
58
|
+
className={className}
|
|
59
|
+
classes={mergedClassNames}
|
|
60
|
+
{...(mergedSlotProps
|
|
61
|
+
? { slotProps: mergedSlotProps as MuiMenuProps["slotProps"] }
|
|
62
|
+
: {})}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
Menu.displayName = "Menu";
|
|
68
|
+
|
|
69
|
+
export type MenuItemProps = RecursicaOverStyled<MuiMenuItemProps>;
|
|
70
|
+
|
|
71
|
+
export const MenuItem = forwardRef<HTMLLIElement, MenuItemProps>(
|
|
72
|
+
function MenuItem({ overStyled = false, className, ...rest }, ref) {
|
|
73
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<MuiMenuItem
|
|
77
|
+
ref={ref}
|
|
78
|
+
{...(sanitizedProps as MuiMenuItemProps)}
|
|
79
|
+
className={`${styles.item} ${className || ""}`}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
MenuItem.displayName = "MenuItem";
|
|
86
|
+
|
|
87
|
+
export type MenuDividerProps = RecursicaOverStyled<MuiDividerProps>;
|
|
88
|
+
|
|
89
|
+
export const MenuDivider = forwardRef<HTMLHRElement, MenuDividerProps>(
|
|
90
|
+
function MenuDivider({ overStyled = false, className, ...rest }, ref) {
|
|
91
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<MuiDivider
|
|
95
|
+
ref={ref}
|
|
96
|
+
{...(sanitizedProps as MuiDividerProps)}
|
|
97
|
+
className={`${styles.divider} ${className || ""}`}
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
MenuDivider.displayName = "MenuDivider";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Menu - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Menu` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Menu } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Menu } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Menu>
|
|
24
|
+
<Menu.Target>
|
|
25
|
+
<Button>Toggle Menu</Button>
|
|
26
|
+
</Menu.Target>
|
|
27
|
+
<Menu.Dropdown>
|
|
28
|
+
<Menu.Item>Profile</Menu.Item>
|
|
29
|
+
<Menu.Item>Settings</Menu.Item>
|
|
30
|
+
<Menu.Item color="red">Logout</Menu.Item>
|
|
31
|
+
</Menu.Dropdown>
|
|
32
|
+
</Menu>
|
|
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
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4. Notes
|
|
52
|
+
|
|
53
|
+
- `maxHeight` on `<Menu>` overrides the dropdown's token-driven max-height with an explicit pixel (or other CSS length) value, e.g. `<Menu maxHeight={320}>`. It's a per-instance escape hatch, not a design token — leave it unset to use the token default.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Menu";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Modal Implementation Notes
|
|
2
|
+
|
|
3
|
+
## `.title` descender clipping (Matt Massey, 2026-08-28)
|
|
4
|
+
|
|
5
|
+
`.title` truncates with an ellipsis (`white-space: nowrap; text-overflow: ellipsis`) rather than
|
|
6
|
+
wrapping, needing `flex: 1 1 auto; min-width: 0;` since it's a flex child of `.header` alongside
|
|
7
|
+
the close button. It used plain `overflow: hidden` to make the ellipsis work, which also clips
|
|
8
|
+
descenders (e.g. the "g" in a long title) whenever `text_line-height` is tighter than the font's
|
|
9
|
+
natural ascent+descent. Switched to `overflow: clip; overflow-clip-margin: 0.35em;` — same
|
|
10
|
+
truncation, but ink can bleed slightly past the line box before it's actually clipped.
|
|
11
|
+
Project-wide fix; see Chip's `CHIP_IMPLEMENTATION_NOTES.md` for the original discovery. Matches
|
|
12
|
+
mantine-adapter's equivalent `.title` rule (see its own `MODAL_IMPLEMENTATION_NOTES.md`).
|
|
13
|
+
|
|
14
|
+
## Vertical anchor position (source-of-truth audit, 2026-08-30)
|
|
15
|
+
|
|
16
|
+
**Decision:** Anchor the modal near the top of the viewport instead of MUI's own default
|
|
17
|
+
vertical centering, matching mantine's `Modal`, which has no `centered` override and so uses
|
|
18
|
+
its own library default (near-top, via `.mantine-Modal-inner`'s `align-items: flex-start` +
|
|
19
|
+
`padding: 30px 40px` — unstyled by any Recursica token).
|
|
20
|
+
|
|
21
|
+
**Implementation:** MUI's `Dialog` centers its paper both axes by default via
|
|
22
|
+
`.MuiDialog-container`. `.root :global(.MuiDialog-container)` overrides that to
|
|
23
|
+
`align-items: flex-start; padding: 30px 40px;`, matching mantine's numbers exactly since
|
|
24
|
+
neither side is token-driven — this is purely "reproduce the source of truth's own default
|
|
25
|
+
library shape" (see Grid's `IMPLEMENTATION_NOTES.md` for the same rule applied to Grid).
|
|
26
|
+
`.inner` (the paper) also gets `margin: 0` — MUI's paper ships its own default 32px margin on
|
|
27
|
+
top of the container padding, which would double the offset otherwise.
|
|
28
|
+
|
|
29
|
+
Residual: still a small width/horizontal-offset gap against mantine's golden after this fix
|
|
30
|
+
(diffPixels dropped from ~172k to ~25k, still over the 2500 threshold) — not yet root-caused,
|
|
31
|
+
see `OPEN_QUESTIONS.txt`.
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/* Brand-layer exemptions (recursica-allow-brand) — see recursica-token-analyzer README.md.
|
|
2
|
+
* Close button is styled to match the Button component's text/icon-only variant, so it reuses
|
|
3
|
+
* the same global hover/focus state tokens Button.module.css exempts.
|
|
4
|
+
* recursica-allow-brand: --recursica_brand_states_focus_blur
|
|
5
|
+
* recursica-allow-brand: --recursica_brand_states_focus_border-size
|
|
6
|
+
* recursica-allow-brand: --recursica_brand_states_focus_color
|
|
7
|
+
* recursica-allow-brand: --recursica_brand_states_focus_margin
|
|
8
|
+
* recursica-allow-brand: --recursica_brand_states_hover_color
|
|
9
|
+
* recursica-allow-brand: --recursica_brand_states_hover_opacity
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
.root {
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* MUI's Dialog container centers its paper vertically by default. Mantine's Modal has no such
|
|
16
|
+
behavior — it anchors near the top (its own `.mantine-Modal-inner` default: align-items:
|
|
17
|
+
flex-start, padding: 30px 40px, unstyled by any Recursica token). Reproducing that shape here
|
|
18
|
+
since nothing here is Recursica-token-driven; it's purely "match the source of truth's own
|
|
19
|
+
default library behavior" per the layout-components rule (see Grid's IMPLEMENTATION_NOTES.md). */
|
|
20
|
+
.root :global(.MuiDialog-container) {
|
|
21
|
+
align-items: flex-start;
|
|
22
|
+
padding: 30px 40px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.inner {
|
|
26
|
+
/* Mantine applies padding to inner to keep modal away from edges. We rely on content constraints. */
|
|
27
|
+
/* MUI's paper also ships its own default 32px margin on top of that — zero it out so the
|
|
28
|
+
container's padding (below) is the only source of edge spacing, matching Mantine's shape. */
|
|
29
|
+
margin: 0;
|
|
30
|
+
|
|
31
|
+
/* Unlike Mantine, where `.content` (Modal.Content) wraps header/body/footer as one element,
|
|
32
|
+
MUI's Dialog renders header/body(.content)/footer as separate siblings inside this Paper
|
|
33
|
+
(mapped via `classes.paper`) — so the border-radius belongs here, on the Paper that is the
|
|
34
|
+
whole visible modal, not on the body's DialogContent below. `overflow: hidden` clips the
|
|
35
|
+
header/footer's square corners to match. No box-shadow — Mantine's static default story
|
|
36
|
+
renders with none. */
|
|
37
|
+
border-radius: var(
|
|
38
|
+
--recursica_ui-kit_components_modal_properties_border-radius
|
|
39
|
+
);
|
|
40
|
+
overflow: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.content {
|
|
44
|
+
/* Geometric Bounds */
|
|
45
|
+
min-width: var(--recursica_ui-kit_components_modal_properties_min-width);
|
|
46
|
+
max-width: var(--recursica_ui-kit_components_modal_properties_max-width);
|
|
47
|
+
min-height: var(--recursica_ui-kit_components_modal_properties_min-height);
|
|
48
|
+
|
|
49
|
+
/* Restrict max-height to either the UI Kit max or the viewport bounds to force internal scrolling */
|
|
50
|
+
max-height: min(
|
|
51
|
+
var(--recursica_ui-kit_components_modal_properties_max-height),
|
|
52
|
+
calc(100vh - 4rem)
|
|
53
|
+
);
|
|
54
|
+
overflow: hidden;
|
|
55
|
+
|
|
56
|
+
/* Box model */
|
|
57
|
+
border-width: var(--recursica_ui-kit_components_modal_properties_border-size);
|
|
58
|
+
border-color: var(
|
|
59
|
+
--recursica_ui-kit_components_modal_properties_colors_border-color
|
|
60
|
+
);
|
|
61
|
+
border-style: solid;
|
|
62
|
+
|
|
63
|
+
/* Appearance */
|
|
64
|
+
background-color: var(
|
|
65
|
+
--recursica_ui-kit_components_modal_properties_colors_content-background-color
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
/* Internal Flex container to trap header and let body scroll */
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.header {
|
|
74
|
+
display: flex; /* HARDCODE: puts the title and close button side-by-side so the title has a bounded width to truncate against */
|
|
75
|
+
align-items: center;
|
|
76
|
+
justify-content: space-between;
|
|
77
|
+
padding: var(
|
|
78
|
+
--recursica_ui-kit_components_modal_properties_header-footer-vertical-padding
|
|
79
|
+
)
|
|
80
|
+
var(
|
|
81
|
+
--recursica_ui-kit_components_modal_properties_header-footer-horizontal-padding
|
|
82
|
+
);
|
|
83
|
+
background-color: transparent; /* Inherit from content */
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.title {
|
|
87
|
+
flex: 1 1 auto; /* HARDCODE: let the title claim the space between the header edge and the close button */
|
|
88
|
+
min-width: 0; /* HARDCODE: required for text-overflow ellipsis to take effect on a flex child */
|
|
89
|
+
overflow: clip; /* HARDCODE: `hidden` clips descenders (e.g. "g") when text_line-height is
|
|
90
|
+
tighter than the font's natural ascent+descent; overflow-clip-margin gives ink a small bleed
|
|
91
|
+
allowance while still clipping genuinely overflowing text (see Chip's IMPLEMENTATION_NOTES.md). */
|
|
92
|
+
overflow-clip-margin: 0.35em;
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
text-overflow: ellipsis;
|
|
95
|
+
|
|
96
|
+
color: var(--recursica_ui-kit_components_modal_properties_colors_title);
|
|
97
|
+
|
|
98
|
+
/* Direct Figma Typography Mapping */
|
|
99
|
+
font-family: var(
|
|
100
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontFamily
|
|
101
|
+
);
|
|
102
|
+
font-size: var(
|
|
103
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontSize
|
|
104
|
+
);
|
|
105
|
+
font-style: var(
|
|
106
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontStyle
|
|
107
|
+
);
|
|
108
|
+
font-weight: var(
|
|
109
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontWeight
|
|
110
|
+
);
|
|
111
|
+
letter-spacing: var(
|
|
112
|
+
--recursica_ui-kit_components_modal_properties_header-style_letterSpacing
|
|
113
|
+
);
|
|
114
|
+
line-height: var(
|
|
115
|
+
--recursica_ui-kit_components_modal_properties_header-style_lineHeight
|
|
116
|
+
);
|
|
117
|
+
text-transform: var(
|
|
118
|
+
--recursica_ui-kit_components_modal_properties_header-style_textCase
|
|
119
|
+
);
|
|
120
|
+
text-decoration: var(
|
|
121
|
+
--recursica_ui-kit_components_modal_properties_header-style_textDecoration
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.bodyWrapper {
|
|
126
|
+
/* This is the container that overrides Mantine's native Body. It strips padding and acts as a flex column. */
|
|
127
|
+
padding: 0;
|
|
128
|
+
display: flex;
|
|
129
|
+
flex-direction: column;
|
|
130
|
+
flex: 1 1 auto;
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
min-height: 0; /* Critical for flex child scrolling constraint */
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.scrollArea {
|
|
136
|
+
padding: var(
|
|
137
|
+
--recursica_ui-kit_components_modal_properties_content-vertical-padding
|
|
138
|
+
)
|
|
139
|
+
var(
|
|
140
|
+
--recursica_ui-kit_components_modal_properties_content-horizontal-padding
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
/* Internal scrolling */
|
|
144
|
+
flex: 1 1 auto;
|
|
145
|
+
overflow-y: auto;
|
|
146
|
+
min-height: 0; /* Critical for flex child scrolling constraint */
|
|
147
|
+
|
|
148
|
+
color: var(--recursica_ui-kit_components_modal_properties_colors_content);
|
|
149
|
+
|
|
150
|
+
/* Direct Figma Typography Mapping */
|
|
151
|
+
font-family: var(
|
|
152
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontFamily
|
|
153
|
+
);
|
|
154
|
+
font-size: var(
|
|
155
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontSize
|
|
156
|
+
);
|
|
157
|
+
font-style: var(
|
|
158
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontStyle
|
|
159
|
+
);
|
|
160
|
+
font-weight: var(
|
|
161
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontWeight
|
|
162
|
+
);
|
|
163
|
+
letter-spacing: var(
|
|
164
|
+
--recursica_ui-kit_components_modal_properties_content-style_letterSpacing
|
|
165
|
+
);
|
|
166
|
+
line-height: var(
|
|
167
|
+
--recursica_ui-kit_components_modal_properties_content-style_lineHeight
|
|
168
|
+
);
|
|
169
|
+
text-transform: var(
|
|
170
|
+
--recursica_ui-kit_components_modal_properties_content-style_textCase
|
|
171
|
+
);
|
|
172
|
+
text-decoration: var(
|
|
173
|
+
--recursica_ui-kit_components_modal_properties_content-style_textDecoration
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
/* Ensure button gap token is easily usable if developers use standard spacing */
|
|
177
|
+
--modal-button-gap: var(
|
|
178
|
+
--recursica_ui-kit_components_modal_properties_button-gap
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
/* Smooth divider transitions */
|
|
182
|
+
transition: border-color 0.15s ease;
|
|
183
|
+
border-top: var(
|
|
184
|
+
--recursica_ui-kit_components_modal_properties_scroll-divider-size
|
|
185
|
+
)
|
|
186
|
+
solid transparent;
|
|
187
|
+
border-bottom: var(
|
|
188
|
+
--recursica_ui-kit_components_modal_properties_scroll-divider-size
|
|
189
|
+
)
|
|
190
|
+
solid transparent;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.scrollArea[data-scrolled-top] {
|
|
194
|
+
border-top-color: var(
|
|
195
|
+
--recursica_ui-kit_components_modal_properties_colors_scroll-divider
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.scrollArea[data-scrolled-bottom] {
|
|
200
|
+
border-bottom-color: var(
|
|
201
|
+
--recursica_ui-kit_components_modal_properties_colors_scroll-divider
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.footer {
|
|
206
|
+
padding: var(
|
|
207
|
+
--recursica_ui-kit_components_modal_properties_header-footer-vertical-padding
|
|
208
|
+
)
|
|
209
|
+
var(
|
|
210
|
+
--recursica_ui-kit_components_modal_properties_header-footer-horizontal-padding
|
|
211
|
+
);
|
|
212
|
+
background-color: transparent;
|
|
213
|
+
display: flex;
|
|
214
|
+
justify-content: flex-end;
|
|
215
|
+
gap: var(--recursica_ui-kit_components_modal_properties_button-gap);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.close {
|
|
219
|
+
/* Matches the Button component's text-variant, icon-only, small-size visual treatment
|
|
220
|
+
(see Button.module.css) so the modal close control looks like a Recursica Button
|
|
221
|
+
rather than MUI's native IconButton. */
|
|
222
|
+
box-sizing: border-box;
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
justify-content: center;
|
|
226
|
+
position: relative;
|
|
227
|
+
overflow: hidden;
|
|
228
|
+
transition: all 0.2s ease;
|
|
229
|
+
|
|
230
|
+
height: var(
|
|
231
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_height
|
|
232
|
+
);
|
|
233
|
+
min-width: var(
|
|
234
|
+
--recursica_ui-kit_components_button_variants_content_icon-only_variants_sizes_small_properties_min-width
|
|
235
|
+
);
|
|
236
|
+
padding: 0
|
|
237
|
+
var(
|
|
238
|
+
--recursica_ui-kit_components_button_variants_content_icon-only_variants_sizes_small_properties_horizontal-padding
|
|
239
|
+
);
|
|
240
|
+
border-radius: var(
|
|
241
|
+
--recursica_ui-kit_components_button_variants_content_icon-only_variants_sizes_small_properties_border-radius
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
border-style: solid;
|
|
245
|
+
border-width: var(
|
|
246
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_border-size
|
|
247
|
+
);
|
|
248
|
+
border-color: var(
|
|
249
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_border-color
|
|
250
|
+
);
|
|
251
|
+
background-color: var(
|
|
252
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_background-color
|
|
253
|
+
);
|
|
254
|
+
color: var(
|
|
255
|
+
--recursica_ui-kit_components_button_variants_styles_text_properties_colors_icon-color
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.close svg {
|
|
260
|
+
position: relative;
|
|
261
|
+
z-index: 1;
|
|
262
|
+
width: var(
|
|
263
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_icon
|
|
264
|
+
);
|
|
265
|
+
height: var(
|
|
266
|
+
--recursica_ui-kit_components_button_variants_sizes_small_properties_icon
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.close::after {
|
|
271
|
+
content: "";
|
|
272
|
+
position: absolute;
|
|
273
|
+
inset: 0;
|
|
274
|
+
border-radius: inherit;
|
|
275
|
+
z-index: 0;
|
|
276
|
+
pointer-events: none;
|
|
277
|
+
transition: opacity 150ms ease;
|
|
278
|
+
opacity: 0;
|
|
279
|
+
background-color: var(--recursica_brand_states_hover_color);
|
|
280
|
+
}
|
|
281
|
+
.close:hover:not(:disabled)::after {
|
|
282
|
+
opacity: var(--recursica_brand_states_hover_opacity);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/* MuiIconButton injects its own `:hover` background via emotion at render time, which lands in
|
|
286
|
+
the DOM after this stylesheet and wins the tie at equal specificity — same class of conflict
|
|
287
|
+
documented in DatePicker.module.css's error/disabled state overrides. `!important` keeps the
|
|
288
|
+
button's own background transparent so only the `::after` overlay above renders the hover
|
|
289
|
+
feedback, matching Button's single-overlay hover treatment exactly. */
|
|
290
|
+
.close:hover {
|
|
291
|
+
background-color: transparent !important;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.close:focus-visible {
|
|
295
|
+
outline: none;
|
|
296
|
+
box-shadow:
|
|
297
|
+
0 0 0 var(--recursica_brand_states_focus_border-size)
|
|
298
|
+
var(--recursica_brand_states_focus_color),
|
|
299
|
+
0 0 var(--recursica_brand_states_focus_blur)
|
|
300
|
+
var(--recursica_brand_states_focus_margin)
|
|
301
|
+
var(--recursica_brand_states_focus_color);
|
|
302
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Modal, type ModalProps } from "./Modal";
|
|
4
|
+
import { Button } from "../Button";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Modal> = {
|
|
7
|
+
title: "UI-Kit/Modal",
|
|
8
|
+
component: Modal,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
argTypes: {
|
|
11
|
+
opened: { table: { disable: true } },
|
|
12
|
+
onClose: { table: { disable: true } },
|
|
13
|
+
defaultChecked: { table: { disable: true } },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
type Story = StoryObj<typeof Modal>;
|
|
20
|
+
|
|
21
|
+
const DefaultWrapper = (args: ModalProps) => {
|
|
22
|
+
// Starts opened so the modal is visible without pressing a button first.
|
|
23
|
+
const [opened, setOpened] = useState(true);
|
|
24
|
+
return (
|
|
25
|
+
<>
|
|
26
|
+
<Modal {...args} opened={opened} onClose={() => setOpened(false)}>
|
|
27
|
+
Please log in to continue accessing this feature.
|
|
28
|
+
<Modal.Footer>
|
|
29
|
+
<Button variant="outline" onClick={() => setOpened(false)}>
|
|
30
|
+
Cancel
|
|
31
|
+
</Button>
|
|
32
|
+
<Button onClick={() => setOpened(false)}>Confirm</Button>
|
|
33
|
+
</Modal.Footer>
|
|
34
|
+
</Modal>
|
|
35
|
+
<Button onClick={() => setOpened(true)}>Open Modal</Button>
|
|
36
|
+
</>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const Default: Story = {
|
|
41
|
+
args: {
|
|
42
|
+
title: "Authentication Required",
|
|
43
|
+
},
|
|
44
|
+
render: (args) => <DefaultWrapper {...args} />,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const LongTitleWrapper = (args: ModalProps) => {
|
|
48
|
+
const [opened, setOpened] = useState(true);
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<Modal {...args} opened={opened} onClose={() => setOpened(false)}>
|
|
52
|
+
The title above is longer than the header can display, so it truncates
|
|
53
|
+
with an ellipsis instead of wrapping onto a second line.
|
|
54
|
+
<Modal.Footer>
|
|
55
|
+
<Button onClick={() => setOpened(false)}>Got it</Button>
|
|
56
|
+
</Modal.Footer>
|
|
57
|
+
</Modal>
|
|
58
|
+
<Button onClick={() => setOpened(true)}>Open Modal</Button>
|
|
59
|
+
</>
|
|
60
|
+
);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const LongTitle: Story = {
|
|
64
|
+
args: {
|
|
65
|
+
title:
|
|
66
|
+
"This Modal Title Is Deliberately Long Enough To Exceed The Available Header Width",
|
|
67
|
+
},
|
|
68
|
+
render: (args) => <LongTitleWrapper {...args} />,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const ScrollingWrapper = (args: ModalProps) => {
|
|
72
|
+
// Starts opened so the modal is visible without pressing a button first.
|
|
73
|
+
const [opened, setOpened] = useState(true);
|
|
74
|
+
return (
|
|
75
|
+
<>
|
|
76
|
+
<Modal {...args} opened={opened} onClose={() => setOpened(false)}>
|
|
77
|
+
<p>
|
|
78
|
+
This modal demonstrates the dynamically injected scroll dividers. When
|
|
79
|
+
this body content overflows, the borders between the Header and Footer
|
|
80
|
+
automatically appear to define the scrolling boundary.
|
|
81
|
+
</p>
|
|
82
|
+
{Array(20)
|
|
83
|
+
.fill(0)
|
|
84
|
+
.map((_, i) => (
|
|
85
|
+
<p key={i}>Scrolling content block {i + 1}...</p>
|
|
86
|
+
))}
|
|
87
|
+
{/* The new Footer abstraction */}
|
|
88
|
+
<Modal.Footer>
|
|
89
|
+
<Button variant="outline" onClick={() => setOpened(false)}>
|
|
90
|
+
Decline
|
|
91
|
+
</Button>
|
|
92
|
+
<Button onClick={() => setOpened(false)}>Accept Terms</Button>
|
|
93
|
+
</Modal.Footer>
|
|
94
|
+
</Modal>
|
|
95
|
+
<Button onClick={() => setOpened(true)}>Open Scrolling Modal</Button>
|
|
96
|
+
</>
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const ScrollingContent: Story = {
|
|
101
|
+
args: {
|
|
102
|
+
title: "Terms and Conditions",
|
|
103
|
+
},
|
|
104
|
+
render: (args) => <ScrollingWrapper {...args} />,
|
|
105
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Modal component tests. Add tests here if/when needed.
|