@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,435 @@
|
|
|
1
|
+
import React, { forwardRef, useState, useEffect, useRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Slider as MuiSlider,
|
|
4
|
+
type SliderProps as MuiSliderProps,
|
|
5
|
+
} from "@mui/material";
|
|
6
|
+
import { type ReadOnlyControlProps } from "@recursica/adapter-common";
|
|
7
|
+
import {
|
|
8
|
+
filterStylingProps,
|
|
9
|
+
omitUnsupportedProps,
|
|
10
|
+
mergeClassNames,
|
|
11
|
+
type RecursicaOverStyled,
|
|
12
|
+
} from "../../utils/filterStylingProps";
|
|
13
|
+
import { type RecursicaFormControlWrapperProps } from "../FormControlWrapper/FormControlWrapper";
|
|
14
|
+
import { WithReadOnlyWrapper } from "../ReadOnlyField/WithReadOnlyWrapper";
|
|
15
|
+
|
|
16
|
+
import styles from "./Slider.module.css";
|
|
17
|
+
|
|
18
|
+
import { type RecursicaSliderProps as BaseRecursicaSliderProps } from "@recursica/adapter-common";
|
|
19
|
+
|
|
20
|
+
export interface RecursicaSliderProps
|
|
21
|
+
extends Omit<
|
|
22
|
+
MuiSliderProps,
|
|
23
|
+
| "size"
|
|
24
|
+
| "color"
|
|
25
|
+
| "classes"
|
|
26
|
+
| "onChange"
|
|
27
|
+
| "onChangeCommitted"
|
|
28
|
+
| "value"
|
|
29
|
+
| "defaultValue"
|
|
30
|
+
>,
|
|
31
|
+
Omit<
|
|
32
|
+
RecursicaFormControlWrapperProps,
|
|
33
|
+
| "controlMaxWidth"
|
|
34
|
+
| "controlMinWidth"
|
|
35
|
+
| "error"
|
|
36
|
+
| "required"
|
|
37
|
+
| "withAsterisk"
|
|
38
|
+
| keyof MuiSliderProps
|
|
39
|
+
>,
|
|
40
|
+
ReadOnlyControlProps,
|
|
41
|
+
BaseRecursicaSliderProps {}
|
|
42
|
+
|
|
43
|
+
export type SliderProps = RecursicaOverStyled<RecursicaSliderProps>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Custom Read-Only visual representation of the Slider value.
|
|
47
|
+
* Utilizes component-specific read-only typography variables. Renders a "lower – upper" pair
|
|
48
|
+
* when the value is a range tuple.
|
|
49
|
+
*/
|
|
50
|
+
const SliderReadOnlyValue: React.FC<{ value: number | [number, number] }> = ({
|
|
51
|
+
value,
|
|
52
|
+
}) => {
|
|
53
|
+
const display = Array.isArray(value) ? `${value[0]} – ${value[1]}` : value;
|
|
54
|
+
return <div className={styles.readOnlyValue}>{display}</div>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Recursica Slider component wrapping Mui's Slider.
|
|
59
|
+
*
|
|
60
|
+
* MUI's own `Slider` already renders two thumbs natively when given a tuple `value`, so range
|
|
61
|
+
* mode here is a typing/handler concern rather than a different underlying component (contrast
|
|
62
|
+
* with the mantine-adapter, which swaps in Mantine's separate `RangeSlider`).
|
|
63
|
+
*
|
|
64
|
+
* Implements a bidirectional text input field next to the slider track, responsive layouts,
|
|
65
|
+
* custom typography-bound min/max labels (optionally overridden via `minLabel`/`maxLabel`),
|
|
66
|
+
* optional leading/trailing icons, and an explicit read-only layout.
|
|
67
|
+
*/
|
|
68
|
+
export const Slider = forwardRef<HTMLDivElement, SliderProps>(
|
|
69
|
+
function Slider(props, ref) {
|
|
70
|
+
const {
|
|
71
|
+
overStyled = false,
|
|
72
|
+
formLayout = "stacked",
|
|
73
|
+
|
|
74
|
+
// Label & Wrapper Maps
|
|
75
|
+
labelSize,
|
|
76
|
+
labelAlignment,
|
|
77
|
+
labelOptionalText,
|
|
78
|
+
labelWithEditIcon,
|
|
79
|
+
labelActionArea,
|
|
80
|
+
onLabelEditClick,
|
|
81
|
+
|
|
82
|
+
label,
|
|
83
|
+
tooltipLabel,
|
|
84
|
+
assistiveText,
|
|
85
|
+
assistiveWithIcon,
|
|
86
|
+
error,
|
|
87
|
+
required,
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
89
|
+
withAsterisk,
|
|
90
|
+
id,
|
|
91
|
+
className,
|
|
92
|
+
style,
|
|
93
|
+
disabled,
|
|
94
|
+
readOnly,
|
|
95
|
+
readOnlyComponent,
|
|
96
|
+
emptyValueComponent,
|
|
97
|
+
value,
|
|
98
|
+
defaultValue,
|
|
99
|
+
icon,
|
|
100
|
+
trailingIcon,
|
|
101
|
+
showInput = false,
|
|
102
|
+
showMinMaxLabels = true,
|
|
103
|
+
min = 0,
|
|
104
|
+
max = 100,
|
|
105
|
+
minLabel,
|
|
106
|
+
maxLabel,
|
|
107
|
+
step = 1,
|
|
108
|
+
onChange,
|
|
109
|
+
onChangeEnd,
|
|
110
|
+
...rest
|
|
111
|
+
} = props;
|
|
112
|
+
|
|
113
|
+
// Bidirectional state linking the slider track value to the input field string
|
|
114
|
+
// representation. A `[number, number]` value/defaultValue switches the component into
|
|
115
|
+
// two-thumb range mode — MUI's own Slider already renders two thumbs for a tuple value.
|
|
116
|
+
type SliderValue = number | [number, number];
|
|
117
|
+
|
|
118
|
+
const [internalValue, setInternalValue] = useState<SliderValue>(() => {
|
|
119
|
+
if (value !== undefined) return value;
|
|
120
|
+
if (defaultValue !== undefined) return defaultValue;
|
|
121
|
+
return min;
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const resolvedValue: SliderValue =
|
|
125
|
+
value !== undefined ? value : internalValue;
|
|
126
|
+
const isRange = Array.isArray(resolvedValue);
|
|
127
|
+
|
|
128
|
+
const [inputValue, setInputValue] = useState<string | [string, string]>(
|
|
129
|
+
() =>
|
|
130
|
+
Array.isArray(resolvedValue)
|
|
131
|
+
? [resolvedValue[0].toString(), resolvedValue[1].toString()]
|
|
132
|
+
: resolvedValue.toString(),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Synchronize text input(s) whenever the slider value changes
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
setInputValue(
|
|
138
|
+
Array.isArray(resolvedValue)
|
|
139
|
+
? [resolvedValue[0].toString(), resolvedValue[1].toString()]
|
|
140
|
+
: resolvedValue.toString(),
|
|
141
|
+
);
|
|
142
|
+
}, [resolvedValue]);
|
|
143
|
+
|
|
144
|
+
const handleValueChange = (_e: Event, val: number | number[]) => {
|
|
145
|
+
const normalized: SliderValue = Array.isArray(val)
|
|
146
|
+
? [val[0], val[1]]
|
|
147
|
+
: val;
|
|
148
|
+
if (value === undefined) {
|
|
149
|
+
setInternalValue(normalized);
|
|
150
|
+
}
|
|
151
|
+
onChange?.(normalized);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
155
|
+
const valStr = e.target.value;
|
|
156
|
+
setInputValue(valStr);
|
|
157
|
+
|
|
158
|
+
const parsed = parseFloat(valStr);
|
|
159
|
+
if (!isNaN(parsed)) {
|
|
160
|
+
// Clamp input value to bounds
|
|
161
|
+
const clamped = Math.max(min, Math.min(max, parsed));
|
|
162
|
+
handleValueChange(null as unknown as Event, clamped);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const handleInputBlur = () => {
|
|
167
|
+
setInputValue((resolvedValue as number).toString());
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// Range-mode input handlers: each bound clamps against the other thumb rather than the
|
|
171
|
+
// shared min/max, so the lower thumb can never cross the upper one and vice versa.
|
|
172
|
+
const handleLowerInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
173
|
+
const current = resolvedValue as [number, number];
|
|
174
|
+
const valStr = e.target.value;
|
|
175
|
+
setInputValue([valStr, current[1].toString()]);
|
|
176
|
+
|
|
177
|
+
const parsed = parseFloat(valStr);
|
|
178
|
+
if (!isNaN(parsed)) {
|
|
179
|
+
const clamped = Math.max(min, Math.min(current[1], parsed));
|
|
180
|
+
handleValueChange(null as unknown as Event, [clamped, current[1]]);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const handleUpperInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
185
|
+
const current = resolvedValue as [number, number];
|
|
186
|
+
const valStr = e.target.value;
|
|
187
|
+
setInputValue([current[0].toString(), valStr]);
|
|
188
|
+
|
|
189
|
+
const parsed = parseFloat(valStr);
|
|
190
|
+
if (!isNaN(parsed)) {
|
|
191
|
+
const clamped = Math.max(current[0], Math.min(max, parsed));
|
|
192
|
+
handleValueChange(null as unknown as Event, [current[0], clamped]);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const handleRangeInputBlur = () => {
|
|
197
|
+
const current = resolvedValue as [number, number];
|
|
198
|
+
setInputValue([current[0].toString(), current[1].toString()]);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
202
|
+
// through even if a caller forces them via plain JavaScript, bypassing the Omit<> above.
|
|
203
|
+
const UNSUPPORTED_PROPS = [
|
|
204
|
+
"size", // Recursica controls sizing via design tokens, not MUI's native small/medium size
|
|
205
|
+
"color", // Colors are token-driven; MUI's native palette isn't exposed
|
|
206
|
+
] as const satisfies readonly (keyof MuiSliderProps)[];
|
|
207
|
+
|
|
208
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
209
|
+
filterStylingProps(rest, overStyled),
|
|
210
|
+
UNSUPPORTED_PROPS,
|
|
211
|
+
);
|
|
212
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
213
|
+
|
|
214
|
+
// MUI always programmatically re-focuses its hidden native input on pointer interaction,
|
|
215
|
+
// which browsers' `:focus-visible` heuristic treats as keyboard-visible — unlike Mantine's
|
|
216
|
+
// plain div thumb, where a real click correctly resolves to a non-visible focus. Track
|
|
217
|
+
// pointer-vs-keyboard ourselves so the focus ring only paints for genuine keyboard focus,
|
|
218
|
+
// matching Mantine (a later keypress while still focused reveals the ring, same as native).
|
|
219
|
+
const pointerDownRef = useRef(false);
|
|
220
|
+
const [suppressFocusRing, setSuppressFocusRing] = useState(false);
|
|
221
|
+
const externalOnMouseDown = (sanitizedProps as MuiSliderProps).onMouseDown;
|
|
222
|
+
const externalOnFocus = (sanitizedProps as MuiSliderProps).onFocus;
|
|
223
|
+
const externalOnBlur = (sanitizedProps as MuiSliderProps).onBlur;
|
|
224
|
+
const externalOnKeyDown = (sanitizedProps as MuiSliderProps).onKeyDown;
|
|
225
|
+
|
|
226
|
+
const handleThumbMouseDown = (e: React.MouseEvent<HTMLSpanElement>) => {
|
|
227
|
+
pointerDownRef.current = true;
|
|
228
|
+
externalOnMouseDown?.(e);
|
|
229
|
+
};
|
|
230
|
+
const handleThumbFocus = (e: React.FocusEvent<HTMLSpanElement>) => {
|
|
231
|
+
setSuppressFocusRing(pointerDownRef.current);
|
|
232
|
+
pointerDownRef.current = false;
|
|
233
|
+
externalOnFocus?.(e);
|
|
234
|
+
};
|
|
235
|
+
const handleThumbBlur = (e: React.FocusEvent<HTMLSpanElement>) => {
|
|
236
|
+
setSuppressFocusRing(false);
|
|
237
|
+
externalOnBlur?.(e);
|
|
238
|
+
};
|
|
239
|
+
const handleThumbKeyDown = (e: React.KeyboardEvent<HTMLSpanElement>) => {
|
|
240
|
+
setSuppressFocusRing(false);
|
|
241
|
+
externalOnKeyDown?.(e);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// Securely map core native blocks down ensuring nested CSS modules map precisely. Note MUI's
|
|
245
|
+
// actual prop is "classes", not "classNames" (that's Mantine's naming) — this used to read
|
|
246
|
+
// the wrong key, silently no-op-ing any caller-supplied classes. The caller-facing slot names
|
|
247
|
+
// below (root/track/bar/thumb/mark/markLabel) mirror the mantine-adapter's own Slider
|
|
248
|
+
// classNames slots, translated to MUI's real classes slot names (root/rail/track/thumb/...).
|
|
249
|
+
const callerClasses = restRecord.classes as
|
|
250
|
+
| Partial<Record<string, string>>
|
|
251
|
+
| undefined;
|
|
252
|
+
const mergedClassNames = mergeClassNames(
|
|
253
|
+
{
|
|
254
|
+
root: styles.sliderRoot,
|
|
255
|
+
rail: styles.sliderTrack,
|
|
256
|
+
track: styles.sliderBar,
|
|
257
|
+
thumb: styles.sliderThumb,
|
|
258
|
+
mark: styles.sliderMark,
|
|
259
|
+
markLabel: styles.sliderMarkLabel,
|
|
260
|
+
valueLabel: styles.sliderTooltip,
|
|
261
|
+
},
|
|
262
|
+
callerClasses && {
|
|
263
|
+
root: callerClasses.root,
|
|
264
|
+
rail: callerClasses.track,
|
|
265
|
+
track: callerClasses.bar,
|
|
266
|
+
thumb: callerClasses.thumb,
|
|
267
|
+
mark: callerClasses.mark,
|
|
268
|
+
markLabel: callerClasses.markLabel,
|
|
269
|
+
},
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
const wrapperClass = className
|
|
273
|
+
? `${styles.layoutOverride} ${className}`
|
|
274
|
+
: styles.layoutOverride;
|
|
275
|
+
|
|
276
|
+
const leadingIcon = icon ? (
|
|
277
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
278
|
+
{icon}
|
|
279
|
+
</span>
|
|
280
|
+
) : null;
|
|
281
|
+
|
|
282
|
+
const trailingIconEl = trailingIcon ? (
|
|
283
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
284
|
+
{trailingIcon}
|
|
285
|
+
</span>
|
|
286
|
+
) : null;
|
|
287
|
+
|
|
288
|
+
// Duplicates the raw numeric value next to the track by default; when `tooltipLabel` is a
|
|
289
|
+
// formatter, reuse it here too so both displays agree instead of one showing raw numbers.
|
|
290
|
+
// Range mode formats each thumb independently and joins them with an en dash.
|
|
291
|
+
const displayValue = Array.isArray(resolvedValue)
|
|
292
|
+
? typeof tooltipLabel === "function"
|
|
293
|
+
? `${tooltipLabel(resolvedValue[0])} – ${tooltipLabel(resolvedValue[1])}`
|
|
294
|
+
: `${resolvedValue[0]} – ${resolvedValue[1]}`
|
|
295
|
+
: typeof tooltipLabel === "function"
|
|
296
|
+
? tooltipLabel(resolvedValue)
|
|
297
|
+
: resolvedValue;
|
|
298
|
+
|
|
299
|
+
return (
|
|
300
|
+
<WithReadOnlyWrapper
|
|
301
|
+
ref={ref}
|
|
302
|
+
className={wrapperClass}
|
|
303
|
+
style={style as React.CSSProperties}
|
|
304
|
+
controlMaxWidth={undefined}
|
|
305
|
+
controlMinWidth={undefined}
|
|
306
|
+
overStyled={overStyled as true}
|
|
307
|
+
formLayout={formLayout}
|
|
308
|
+
labelSize={labelSize}
|
|
309
|
+
labelAlignment={labelAlignment}
|
|
310
|
+
labelOptionalText={labelOptionalText}
|
|
311
|
+
labelWithEditIcon={labelWithEditIcon}
|
|
312
|
+
labelActionArea={labelActionArea}
|
|
313
|
+
onLabelEditClick={onLabelEditClick}
|
|
314
|
+
label={label}
|
|
315
|
+
assistiveText={assistiveText}
|
|
316
|
+
assistiveWithIcon={assistiveWithIcon}
|
|
317
|
+
error={!!error}
|
|
318
|
+
required={required}
|
|
319
|
+
id={id}
|
|
320
|
+
readOnly={readOnly}
|
|
321
|
+
readOnlyComponent={readOnlyComponent || SliderReadOnlyValue}
|
|
322
|
+
emptyValueComponent={emptyValueComponent}
|
|
323
|
+
readOnlyType="text"
|
|
324
|
+
readOnlyValue={resolvedValue}
|
|
325
|
+
readOnlyNativeProps={{ value: resolvedValue }}
|
|
326
|
+
activeComponent={
|
|
327
|
+
<div
|
|
328
|
+
className={styles.sliderContainer}
|
|
329
|
+
data-form-layout={formLayout}
|
|
330
|
+
data-disabled={disabled ? "true" : undefined}
|
|
331
|
+
data-error={error ? "true" : undefined}
|
|
332
|
+
data-suppress-focus-ring={suppressFocusRing ? "true" : undefined}
|
|
333
|
+
>
|
|
334
|
+
{isRange && showInput && (
|
|
335
|
+
<input
|
|
336
|
+
type="number"
|
|
337
|
+
className={styles.inputField}
|
|
338
|
+
value={(inputValue as [string, string])[0]}
|
|
339
|
+
onChange={handleLowerInputChange}
|
|
340
|
+
onBlur={handleRangeInputBlur}
|
|
341
|
+
min={min}
|
|
342
|
+
max={(resolvedValue as [number, number])[1]}
|
|
343
|
+
step={step ?? undefined}
|
|
344
|
+
disabled={disabled}
|
|
345
|
+
data-error={error ? "true" : undefined}
|
|
346
|
+
aria-label="Minimum value"
|
|
347
|
+
/>
|
|
348
|
+
)}
|
|
349
|
+
|
|
350
|
+
{leadingIcon}
|
|
351
|
+
|
|
352
|
+
{showMinMaxLabels && (
|
|
353
|
+
<span className={styles.minMaxGuide}>{minLabel ?? min}</span>
|
|
354
|
+
)}
|
|
355
|
+
|
|
356
|
+
<div className={styles.sliderTrackWrapper}>
|
|
357
|
+
<MuiSlider
|
|
358
|
+
{...(sanitizedProps as unknown as MuiSliderProps)}
|
|
359
|
+
classes={mergedClassNames}
|
|
360
|
+
disabled={disabled}
|
|
361
|
+
value={resolvedValue}
|
|
362
|
+
onChange={handleValueChange}
|
|
363
|
+
onMouseDown={handleThumbMouseDown}
|
|
364
|
+
onFocus={handleThumbFocus}
|
|
365
|
+
onBlur={handleThumbBlur}
|
|
366
|
+
onKeyDown={handleThumbKeyDown}
|
|
367
|
+
onChangeCommitted={
|
|
368
|
+
onChangeEnd as unknown as (
|
|
369
|
+
event: Event | React.SyntheticEvent,
|
|
370
|
+
value: number | number[],
|
|
371
|
+
) => void
|
|
372
|
+
}
|
|
373
|
+
min={min}
|
|
374
|
+
max={max}
|
|
375
|
+
step={step}
|
|
376
|
+
valueLabelDisplay={tooltipLabel === null ? "off" : "auto"}
|
|
377
|
+
valueLabelFormat={
|
|
378
|
+
typeof tooltipLabel === "function"
|
|
379
|
+
? (tooltipLabel as unknown as (
|
|
380
|
+
value: number,
|
|
381
|
+
index: number,
|
|
382
|
+
) => React.ReactNode)
|
|
383
|
+
: undefined
|
|
384
|
+
}
|
|
385
|
+
/>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
<div className={styles.rightGuideContainer}>
|
|
389
|
+
{!showInput && (
|
|
390
|
+
<span className={styles.currentValue}>{displayValue}</span>
|
|
391
|
+
)}
|
|
392
|
+
{showMinMaxLabels && (
|
|
393
|
+
<span className={styles.minMaxGuide}>{maxLabel ?? max}</span>
|
|
394
|
+
)}
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
{trailingIconEl}
|
|
398
|
+
|
|
399
|
+
{showInput &&
|
|
400
|
+
(isRange ? (
|
|
401
|
+
<input
|
|
402
|
+
type="number"
|
|
403
|
+
className={styles.inputField}
|
|
404
|
+
value={(inputValue as [string, string])[1]}
|
|
405
|
+
onChange={handleUpperInputChange}
|
|
406
|
+
onBlur={handleRangeInputBlur}
|
|
407
|
+
min={(resolvedValue as [number, number])[0]}
|
|
408
|
+
max={max}
|
|
409
|
+
step={step ?? undefined}
|
|
410
|
+
disabled={disabled}
|
|
411
|
+
data-error={error ? "true" : undefined}
|
|
412
|
+
aria-label="Maximum value"
|
|
413
|
+
/>
|
|
414
|
+
) : (
|
|
415
|
+
<input
|
|
416
|
+
type="number"
|
|
417
|
+
className={styles.inputField}
|
|
418
|
+
value={inputValue as string}
|
|
419
|
+
onChange={handleInputChange}
|
|
420
|
+
onBlur={handleInputBlur}
|
|
421
|
+
min={min}
|
|
422
|
+
max={max}
|
|
423
|
+
step={step ?? undefined}
|
|
424
|
+
disabled={disabled}
|
|
425
|
+
data-error={error ? "true" : undefined}
|
|
426
|
+
/>
|
|
427
|
+
))}
|
|
428
|
+
</div>
|
|
429
|
+
}
|
|
430
|
+
/>
|
|
431
|
+
);
|
|
432
|
+
},
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
Slider.displayName = "Slider";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Slider - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Slider` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Slider } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Slider } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <Slider defaultValue={50} min={0} max={100} label="Volume" />;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 3. Design System Integration
|
|
29
|
+
|
|
30
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
31
|
+
|
|
32
|
+
> [!IMPORTANT]
|
|
33
|
+
>
|
|
34
|
+
> - **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.
|
|
35
|
+
> - **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.
|
|
36
|
+
> - **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.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Key Integration Features & Constraints
|
|
41
|
+
|
|
42
|
+
The `label` prop is passed through to the surrounding form label rather than MUI's dragging tooltip; use `tooltipLabel` to set the label shown while dragging. When `showInput` is enabled, a numeric text input is rendered alongside the track and stays in sync with the slider's value. Set `showMinMaxLabels` to `false` to hide the min/max guides shown at either end of the track. Otherwise, the current value is displayed near the track instead — pass `tooltipLabel` as a formatter function (`(value) => ReactNode`) and that same formatter is reused for this display, instead of always showing the raw number. `minLabel`/`maxLabel` override the text shown at either end of the track (defaults to the numeric `min`/`max`). `icon` renders a leading icon next to the track; `trailingIcon` renders one on the opposite side, rendered right after the max label and before the numeric input.
|
|
43
|
+
|
|
44
|
+
### Range Mode
|
|
45
|
+
|
|
46
|
+
Pass a `[number, number]` tuple as `value`/`defaultValue` to render a two-thumb range slider — `onChange`/`onChangeEnd` are then called with a `[number, number]` tuple instead of a `number`. With `showInput` enabled, a second numeric input for the upper bound appears after the trailing icon, with the lower-bound input before the leading icon:
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Slider
|
|
50
|
+
label="Price Range"
|
|
51
|
+
defaultValue={[20, 80]}
|
|
52
|
+
min={0}
|
|
53
|
+
max={100}
|
|
54
|
+
onChange={(value) => console.log(value)} // [number, number]
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Slider";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Stack } from "./Stack";
|
|
4
|
+
import { Button } from "../Button";
|
|
5
|
+
import { Text } from "../Text/Text";
|
|
6
|
+
|
|
7
|
+
type StackStoryProps = React.ComponentProps<typeof Stack>;
|
|
8
|
+
|
|
9
|
+
const meta: Meta<StackStoryProps> = {
|
|
10
|
+
title: "UI-Kit/Stack",
|
|
11
|
+
component: Stack,
|
|
12
|
+
tags: ["autodocs"],
|
|
13
|
+
parameters: {
|
|
14
|
+
docs: {
|
|
15
|
+
description: {
|
|
16
|
+
component:
|
|
17
|
+
"Stack is a flex vertical layout container that maps directly to Mantine's Stack component allowing safe layout property passing.",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
args: {
|
|
22
|
+
spacing: "rec-default",
|
|
23
|
+
alignItems: "stretch",
|
|
24
|
+
justifyContent: "flex-start",
|
|
25
|
+
},
|
|
26
|
+
argTypes: {
|
|
27
|
+
spacing: {
|
|
28
|
+
control: "select",
|
|
29
|
+
options: [
|
|
30
|
+
"rec-none",
|
|
31
|
+
"rec-sm",
|
|
32
|
+
"rec-default",
|
|
33
|
+
"rec-md",
|
|
34
|
+
"rec-lg",
|
|
35
|
+
"rec-xl",
|
|
36
|
+
"rec-2xl",
|
|
37
|
+
"xs",
|
|
38
|
+
"sm",
|
|
39
|
+
"md",
|
|
40
|
+
"lg",
|
|
41
|
+
"xl",
|
|
42
|
+
],
|
|
43
|
+
description: "Space between elements",
|
|
44
|
+
},
|
|
45
|
+
alignItems: {
|
|
46
|
+
control: "select",
|
|
47
|
+
options: ["flex-start", "center", "flex-end", "stretch"],
|
|
48
|
+
description: "Align-items property",
|
|
49
|
+
},
|
|
50
|
+
justifyContent: {
|
|
51
|
+
control: "select",
|
|
52
|
+
options: [
|
|
53
|
+
"flex-start",
|
|
54
|
+
"center",
|
|
55
|
+
"flex-end",
|
|
56
|
+
"space-between",
|
|
57
|
+
"space-around",
|
|
58
|
+
],
|
|
59
|
+
description: "Justify-content property",
|
|
60
|
+
},
|
|
61
|
+
defaultChecked: {
|
|
62
|
+
table: { disable: true },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default meta;
|
|
68
|
+
|
|
69
|
+
type Story = StoryObj<StackStoryProps>;
|
|
70
|
+
|
|
71
|
+
export const Default: Story = {
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
73
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
74
|
+
<Stack {...args}>
|
|
75
|
+
<Button variant="solid">Primary Block</Button>
|
|
76
|
+
<Button variant="outline">Secondary Block</Button>
|
|
77
|
+
<Text>Text element within Stack</Text>
|
|
78
|
+
</Stack>
|
|
79
|
+
),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const StaticGapSmall: Story = {
|
|
83
|
+
args: {
|
|
84
|
+
spacing: "rec-sm",
|
|
85
|
+
},
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
87
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
88
|
+
<Stack {...args}>
|
|
89
|
+
<Button variant="solid">Item 1</Button>
|
|
90
|
+
<Button variant="solid">Item 2</Button>
|
|
91
|
+
<Button variant="solid">Item 3</Button>
|
|
92
|
+
</Stack>
|
|
93
|
+
),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const StaticGapLarge: Story = {
|
|
97
|
+
args: {
|
|
98
|
+
spacing: "rec-xl",
|
|
99
|
+
},
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
101
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
102
|
+
<Stack {...args}>
|
|
103
|
+
<Button variant="solid">Item 1</Button>
|
|
104
|
+
<Button variant="solid">Item 2</Button>
|
|
105
|
+
<Button variant="solid">Item 3</Button>
|
|
106
|
+
</Stack>
|
|
107
|
+
),
|
|
108
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Stack component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stack layout wrapper.
|
|
3
|
+
*
|
|
4
|
+
* MUI has a native `Stack`, so this simply passes through its own props (`direction`,
|
|
5
|
+
* `spacing`, `alignItems`, `justifyContent`, etc.) with no Recursica renaming — only
|
|
6
|
+
* `spacing` gains `rec-*` token support via `WithRecursicaSpacing`.
|
|
7
|
+
*/
|
|
8
|
+
import { forwardRef } from "react";
|
|
9
|
+
import {
|
|
10
|
+
Stack as MUIStack,
|
|
11
|
+
type StackProps as MUIStackProps,
|
|
12
|
+
} from "@mui/material";
|
|
13
|
+
import {
|
|
14
|
+
SPACING_MAP,
|
|
15
|
+
type OmitSx,
|
|
16
|
+
filterSxProp,
|
|
17
|
+
type WithRecursicaSpacing,
|
|
18
|
+
} from "../../utils/filterStylingProps";
|
|
19
|
+
|
|
20
|
+
export type StackProps = WithRecursicaSpacing<OmitSx<MUIStackProps>>;
|
|
21
|
+
|
|
22
|
+
export const Stack = forwardRef<HTMLDivElement, StackProps>(function Stack(
|
|
23
|
+
{ children, spacing = "rec-default", ...rest },
|
|
24
|
+
ref,
|
|
25
|
+
) {
|
|
26
|
+
const safeProps = filterSxProp(rest as Record<string, unknown>);
|
|
27
|
+
const resolvedSpacing =
|
|
28
|
+
typeof spacing === "string" && spacing in SPACING_MAP
|
|
29
|
+
? SPACING_MAP[spacing as keyof typeof SPACING_MAP]
|
|
30
|
+
: spacing;
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<MUIStack
|
|
34
|
+
ref={ref}
|
|
35
|
+
{...(safeProps as unknown as MUIStackProps)}
|
|
36
|
+
spacing={resolvedSpacing}
|
|
37
|
+
>
|
|
38
|
+
{children}
|
|
39
|
+
</MUIStack>
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
Stack.displayName = "Stack";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Stack - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Stack` component in your projects using `@recursica/adapter-mui-v7`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Stack } from "@recursica/adapter-mui-v7";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Stack } from "@recursica/adapter-mui-v7";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Stack spacing="md" alignItems="stretch">
|
|
24
|
+
<Text>Item 1</Text>
|
|
25
|
+
<Text>Item 2</Text>
|
|
26
|
+
</Stack>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 3. Design System Integration
|
|
34
|
+
|
|
35
|
+
All Recursica components in the `@recursica/adapter-mui-v7` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
36
|
+
|
|
37
|
+
> [!IMPORTANT]
|
|
38
|
+
>
|
|
39
|
+
> - **Anti-override protection**: Rogues style injections (like inline `style` or arbitrary `className`) are automatically blocked by our prop layer unless `overStyled={true}` is explicitly provided.
|
|
40
|
+
> - **No Direct Layers**: Do not pass a `layer` prop to this component. To place it on a specific visual layer, wrap it in a `<Layer layer={0|1|2|3}>` component natively.
|
|
41
|
+
> - **Variables and Theming**: Styling is entirely determined by local CSS variables defined in `recursica_variables_scoped.css` and mapped in the component's CSS module.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Stack";
|