@recursica/adapter-mantine-v8 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 +688 -0
- package/LICENSE +21 -0
- package/OVERSTYLING.md +56 -0
- package/README.md +70 -0
- package/SETUP.md +93 -0
- package/USAGE.md +57 -0
- package/dist/adapter-mantine-v8.cjs +12 -0
- package/dist/adapter-mantine-v8.cjs.map +1 -0
- package/dist/adapter-mantine-v8.css +1 -0
- package/dist/adapter-mantine-v8.js +5759 -0
- package/dist/adapter-mantine-v8.js.map +1 -0
- package/dist/index.d.ts +2095 -0
- package/dist/test.html +1 -0
- package/dist/vite.svg +1 -0
- package/docs/PHILOSOPHY.md +39 -0
- package/llms.txt +74 -0
- package/package.json +131 -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 +154 -0
- package/src/OverStyling.tsx +79 -0
- package/src/Version.tsx +44 -0
- package/src/components/Accordion/ACCORDION_IMPLEMENTATION_NOTES.md +72 -0
- package/src/components/Accordion/Accordion.module.css +367 -0
- package/src/components/Accordion/Accordion.stories.tsx +189 -0
- package/src/components/Accordion/Accordion.test.tsx +1 -0
- package/src/components/Accordion/Accordion.tsx +220 -0
- package/src/components/Accordion/USAGE.md +51 -0
- package/src/components/Accordion/index.ts +1 -0
- package/src/components/AssistiveElement/ASSISTIVEELEMENT_IMPLEMENTATION_NOTES.md +45 -0
- package/src/components/AssistiveElement/AssistiveElement.module.css +111 -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 +93 -0
- package/src/components/AssistiveElement/USAGE.md +36 -0
- package/src/components/AutoComplete/AUTOCOMPLETE_IMPLEMENTATION_NOTES.md +42 -0
- package/src/components/AutoComplete/AutoComplete.module.css +430 -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 +179 -0
- package/src/components/AutoComplete/USAGE.md +80 -0
- package/src/components/Avatar/AVATAR_IMPLEMENTATION_NOTES.md +34 -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 +108 -0
- package/src/components/Avatar/USAGE.md +38 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/Badge/BADGE_IMPLEMENTATION_NOTES.md +18 -0
- package/src/components/Badge/Badge.module.css +127 -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 +64 -0
- package/src/components/Badge/USAGE.md +56 -0
- package/src/components/Breadcrumb/BREADCRUMB_IMPLEMENTATION_NOTES.md +47 -0
- package/src/components/Breadcrumb/Breadcrumb.module.css +48 -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 +85 -0
- package/src/components/Breadcrumb/USAGE.md +55 -0
- package/src/components/Breadcrumb/markCurrentPageItem.test.ts +49 -0
- package/src/components/Button/Button.module.css +446 -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 +184 -0
- package/src/components/Button/IMPLEMENTATION_NOTES.md +109 -0
- package/src/components/Button/USAGE.md +80 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Card/CARD_IMPLEMENTATION_NOTES.md +17 -0
- package/src/components/Card/Card.module.css +119 -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 +248 -0
- package/src/components/Card/USAGE.md +63 -0
- package/src/components/Checkbox/CHECKBOX_IMPLEMENTATION_NOTES.md +25 -0
- package/src/components/Checkbox/Checkbox.module.css +267 -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 +151 -0
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +147 -0
- package/src/components/Checkbox/USAGE.md +48 -0
- package/src/components/Chip/CHIP_IMPLEMENTATION_NOTES.md +110 -0
- package/src/components/Chip/Chip.module.css +288 -0
- package/src/components/Chip/Chip.stories.tsx +128 -0
- package/src/components/Chip/Chip.test.tsx +1 -0
- package/src/components/Chip/Chip.tsx +157 -0
- package/src/components/Chip/USAGE.md +55 -0
- package/src/components/Container/CONTAINER_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Container/Container.module.css +7 -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 +69 -0
- package/src/components/Container/USAGE.md +47 -0
- package/src/components/DatePicker/DATEPICKER_IMPLEMENTATION_NOTES.md +31 -0
- package/src/components/DatePicker/DatePicker.icons.tsx +27 -0
- package/src/components/DatePicker/DatePicker.module.css +566 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +158 -0
- package/src/components/DatePicker/DatePicker.test.tsx +1 -0
- package/src/components/DatePicker/DatePicker.tsx +218 -0
- package/src/components/DatePicker/USAGE.md +49 -0
- package/src/components/Dropdown/BareDropdown.tsx +97 -0
- package/src/components/Dropdown/DROPDOWN_IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Dropdown/Dropdown.module.css +477 -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 +213 -0
- package/src/components/Dropdown/USAGE.md +69 -0
- package/src/components/FileInput/FILEINPUT_IMPLEMENTATION_NOTES.md +153 -0
- package/src/components/FileInput/FileInput.module.css +280 -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 +417 -0
- package/src/components/FileInput/USAGE.md +145 -0
- package/src/components/FileUpload/FILEUPLOAD_IMPLEMENTATION_NOTES.md +244 -0
- package/src/components/FileUpload/FileUpload.module.css +205 -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 +354 -0
- package/src/components/FileUpload/USAGE.md +199 -0
- package/src/components/Flex/FLEX_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Flex/Flex.module.css +7 -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 +75 -0
- package/src/components/Flex/USAGE.md +48 -0
- package/src/components/FormControlLayout/FormControlLayout.module.css +90 -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 +74 -0
- package/src/components/FormControlLayout/USAGE.md +40 -0
- package/src/components/FormControlWrapper/FORMCONTROLWRAPPER_IMPLEMENTATION_NOTES.md +32 -0
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +75 -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 +151 -0
- package/src/components/FormControlWrapper/USAGE.md +47 -0
- package/src/components/Grid/GRID_IMPLEMENTATION_NOTES.md +18 -0
- package/src/components/Grid/Grid.module.css +11 -0
- package/src/components/Grid/Grid.stories.tsx +206 -0
- package/src/components/Grid/Grid.test.tsx +1 -0
- package/src/components/Grid/Grid.tsx +140 -0
- package/src/components/Grid/USAGE.md +47 -0
- package/src/components/Group/GROUP_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Group/Group.module.css +7 -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 +60 -0
- package/src/components/Group/USAGE.md +48 -0
- package/src/components/Heading/HEADING_IMPLEMENTATION_NOTES.md +18 -0
- package/src/components/Heading/Heading.module.css +13 -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 +52 -0
- package/src/components/Heading/USAGE.md +36 -0
- package/src/components/HoverCard/HOVERCARD_IMPLEMENTATION_NOTES.md +77 -0
- package/src/components/HoverCard/HoverCard.module.css +90 -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 +133 -0
- package/src/components/HoverCard/USAGE.md +52 -0
- package/src/components/Label/LABEL_IMPLEMENTATION_NOTES.md +48 -0
- package/src/components/Label/Label.module.css +141 -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 +113 -0
- package/src/components/Label/USAGE.md +47 -0
- package/src/components/Label/index.ts +1 -0
- package/src/components/Layer/USAGE.md +54 -0
- package/src/components/Link/IMPLEMENTATION_NOTES.md +19 -0
- package/src/components/Link/Link.module.css +110 -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 +67 -0
- package/src/components/Link/USAGE.md +56 -0
- package/src/components/Link/index.ts +1 -0
- package/src/components/Loader/LOADER_IMPLEMENTATION_NOTES.md +24 -0
- package/src/components/Loader/Loader.animate.dom.test.tsx +82 -0
- package/src/components/Loader/Loader.module.css +63 -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 +69 -0
- package/src/components/Loader/USAGE.md +44 -0
- package/src/components/Menu/MENU_IMPLEMENTATION_NOTES.md +88 -0
- package/src/components/Menu/Menu.module.css +280 -0
- package/src/components/Menu/Menu.stories.tsx +371 -0
- package/src/components/Menu/Menu.test.tsx +1 -0
- package/src/components/Menu/Menu.tsx +373 -0
- package/src/components/Menu/USAGE.md +55 -0
- package/src/components/Modal/MODAL_IMPLEMENTATION_NOTES.md +32 -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 +368 -0
- package/src/components/Modal/USAGE.md +58 -0
- package/src/components/Modal/index.ts +1 -0
- package/src/components/NumberInput/NUMBER_INPUT_IMPLEMENTATION_NOTES.md +24 -0
- package/src/components/NumberInput/NumberInput.module.css +302 -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 +157 -0
- package/src/components/NumberInput/USAGE.md +52 -0
- package/src/components/Pagination/IMPLEMENTATION_NOTES.md +16 -0
- package/src/components/Pagination/Pagination.icons.tsx +66 -0
- package/src/components/Pagination/Pagination.module.css +188 -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 +265 -0
- package/src/components/Pagination/USAGE.md +36 -0
- package/src/components/Pagination/index.ts +5 -0
- package/src/components/Panel/PANEL_IMPLEMENTATION_NOTES.md +116 -0
- package/src/components/Panel/Panel.module.css +209 -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 +269 -0
- package/src/components/Panel/USAGE.md +56 -0
- package/src/components/Popover/IMPLEMENTATION_NOTES.md +77 -0
- package/src/components/Popover/Popover.module.css +86 -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 +142 -0
- package/src/components/Popover/USAGE.md +61 -0
- package/src/components/Popover/index.ts +1 -0
- package/src/components/Radio/Radio.module.css +231 -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 +168 -0
- package/src/components/Radio/RadioGroup.stories.tsx +117 -0
- package/src/components/Radio/RadioGroup.tsx +124 -0
- package/src/components/Radio/USAGE.md +36 -0
- package/src/components/ReadOnlyField/READ_ONLY_FIELD_IMPLEMENTATION_NOTES.md +15 -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 +114 -0
- package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
- package/src/components/ReadOnlyField/USAGE.md +44 -0
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
- package/src/components/ReadOnlyField/index.ts +5 -0
- package/src/components/RecursicaThemeProvider/USAGE.md +60 -0
- package/src/components/SegmentedControl/IMPLEMENTATION_NOTES.md +25 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +185 -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 +110 -0
- package/src/components/SegmentedControl/USAGE.md +55 -0
- package/src/components/Slider/IMPLEMENTATION_NOTES.md +92 -0
- package/src/components/Slider/Slider.module.css +588 -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 +391 -0
- package/src/components/Slider/USAGE.md +56 -0
- package/src/components/Stack/STACK_IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Stack/Stack.module.css +7 -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 +62 -0
- package/src/components/Stack/USAGE.md +48 -0
- package/src/components/Stepper/IMPLEMENTATION_NOTES.md +28 -0
- package/src/components/Stepper/Stepper.module.css +404 -0
- package/src/components/Stepper/Stepper.stories.tsx +148 -0
- package/src/components/Stepper/Stepper.test.tsx +1 -0
- package/src/components/Stepper/Stepper.tsx +93 -0
- package/src/components/Stepper/USAGE.md +41 -0
- package/src/components/Switch/SWITCH_IMPLEMENTATION_NOTES.md +64 -0
- package/src/components/Switch/Switch.module.css +279 -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 +177 -0
- package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
- package/src/components/Switch/SwitchGroup.tsx +127 -0
- package/src/components/Switch/USAGE.md +42 -0
- package/src/components/Table/TABLE_IMPLEMENTATION_NOTES.md +78 -0
- package/src/components/Table/Table.icons.tsx +40 -0
- package/src/components/Table/Table.module.css +444 -0
- package/src/components/Table/Table.stories.tsx +140 -0
- package/src/components/Table/Table.test.tsx +1 -0
- package/src/components/Table/Table.tsx +243 -0
- package/src/components/Table/USAGE.md +78 -0
- package/src/components/Tabs/IMPLEMENTATION_NOTES.md +27 -0
- package/src/components/Tabs/Tabs.module.css +591 -0
- package/src/components/Tabs/Tabs.stories.tsx +154 -0
- package/src/components/Tabs/Tabs.test.tsx +1 -0
- package/src/components/Tabs/Tabs.tsx +114 -0
- package/src/components/Tabs/USAGE.md +45 -0
- package/src/components/Text/TEXT_IMPLEMENTATION_NOTES.md +12 -0
- package/src/components/Text/Text.module.css +13 -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 +53 -0
- package/src/components/Text/USAGE.md +40 -0
- package/src/components/TextArea/TEXTAREA_IMPLEMENTATION_NOTES.md +7 -0
- package/src/components/TextArea/TextArea.module.css +183 -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 +137 -0
- package/src/components/TextArea/USAGE.md +48 -0
- package/src/components/TextField/TEXTFIELD_IMPLEMENTATION_NOTES.md +19 -0
- package/src/components/TextField/TextField.module.css +264 -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 +139 -0
- package/src/components/TextField/USAGE.md +44 -0
- package/src/components/TimePicker/TIMEPICKER_IMPLEMENTATION_NOTES.md +119 -0
- package/src/components/TimePicker/TimePicker.module.css +291 -0
- package/src/components/TimePicker/TimePicker.stories.tsx +141 -0
- package/src/components/TimePicker/TimePicker.test.tsx +1 -0
- package/src/components/TimePicker/TimePicker.tsx +304 -0
- package/src/components/TimePicker/USAGE.md +57 -0
- package/src/components/Timeline/TIMELINE_IMPLEMENTATION_NOTES.md +13 -0
- package/src/components/Timeline/Timeline.module.css +373 -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 +73 -0
- package/src/components/Timeline/TimelineItem.tsx +79 -0
- package/src/components/Timeline/USAGE.md +49 -0
- package/src/components/Toast/TOAST_IMPLEMENTATION_NOTES.md +39 -0
- package/src/components/Toast/Toast.module.css +184 -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 +82 -0
- package/src/components/Toast/USAGE.md +50 -0
- package/src/components/Toast/index.ts +1 -0
- package/src/components/Tooltip/TOOLTIP_IMPLEMENTATION_NOTES.md +85 -0
- package/src/components/Tooltip/Tooltip.module.css +91 -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 +117 -0
- package/src/components/Tooltip/USAGE.md +80 -0
- package/src/components/TransferList/TRANSFERLIST_IMPLEMENTATION_NOTES.md +111 -0
- package/src/components/TransferList/TransferList.module.css +182 -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/Tree/IMPLEMENTATION_NOTES.md +48 -0
- package/src/components/Tree/Tree.module.css +232 -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 +220 -0
- package/src/components/Tree/USAGE.md +96 -0
- package/src/components/Tree/index.ts +1 -0
- package/src/components/index.ts +52 -0
- package/src/env.d.ts +7 -0
- package/src/index.ts +179 -0
- package/src/types/index.ts +9 -0
- package/src/types/mantine.d.ts +7 -0
- package/src/types/scss-modules.d.ts +9 -0
- package/src/utils/ColorSchemeWrapper.tsx +27 -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 +150 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/renderRichOption.tsx +65 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { forwardRef, type CSSProperties } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Menu as MantineMenu,
|
|
4
|
+
type MenuProps as MantineMenuProps,
|
|
5
|
+
type MenuTargetProps as MantineMenuTargetProps,
|
|
6
|
+
type MenuDropdownProps as MantineMenuDropdownProps,
|
|
7
|
+
type MenuItemProps as MantineMenuItemProps,
|
|
8
|
+
type MenuDividerProps as MantineMenuDividerProps,
|
|
9
|
+
type MenuLabelProps as MantineMenuLabelProps,
|
|
10
|
+
type MenuSubProps as MantineMenuSubProps,
|
|
11
|
+
type MenuSubTargetProps as MantineMenuSubTargetProps,
|
|
12
|
+
type MenuSubDropdownProps as MantineMenuSubDropdownProps,
|
|
13
|
+
createPolymorphicComponent,
|
|
14
|
+
} from "@mantine/core";
|
|
15
|
+
import {
|
|
16
|
+
filterStylingProps,
|
|
17
|
+
omitUnsupportedProps,
|
|
18
|
+
mergeClassNames,
|
|
19
|
+
type RecursicaOverStyled,
|
|
20
|
+
} from "../../utils/filterStylingProps";
|
|
21
|
+
import styles from "./Menu.module.css";
|
|
22
|
+
|
|
23
|
+
import { type RecursicaMenuProps } from "@recursica/adapter-common";
|
|
24
|
+
|
|
25
|
+
// ============================================================
|
|
26
|
+
// MENU ROOT
|
|
27
|
+
// ============================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Recursica Menu component wrapping Mantine's composable Menu.
|
|
31
|
+
*
|
|
32
|
+
* Usage follows the composable dot-notation pattern:
|
|
33
|
+
* ```tsx
|
|
34
|
+
* <Menu>
|
|
35
|
+
* <Menu.Target><Button>Open</Button></Menu.Target>
|
|
36
|
+
* <Menu.Dropdown>
|
|
37
|
+
* <Menu.Label>Section</Menu.Label>
|
|
38
|
+
* <Menu.Item>Action</Menu.Item>
|
|
39
|
+
* <Menu.Divider />
|
|
40
|
+
* <Menu.Item>Another action</Menu.Item>
|
|
41
|
+
* </Menu.Dropdown>
|
|
42
|
+
* </Menu>
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export type MenuProps = RecursicaOverStyled<
|
|
46
|
+
MantineMenuProps & RecursicaMenuProps
|
|
47
|
+
>;
|
|
48
|
+
|
|
49
|
+
const MenuBase = function Menu({ overStyled = false, ...rest }: MenuProps) {
|
|
50
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
51
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
52
|
+
const { maxHeight, ...menuRestRecord } = restRecord;
|
|
53
|
+
|
|
54
|
+
// Bind CSS module classes to Mantine's internal classNames API
|
|
55
|
+
const mergedClassNames = mergeClassNames(
|
|
56
|
+
{
|
|
57
|
+
dropdown: styles.dropdown,
|
|
58
|
+
item: styles.item,
|
|
59
|
+
itemLabel: styles.itemLabel,
|
|
60
|
+
itemSection: styles.itemSection,
|
|
61
|
+
divider: styles.divider,
|
|
62
|
+
label: styles.label,
|
|
63
|
+
chevron: styles.chevron,
|
|
64
|
+
},
|
|
65
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// `maxHeight` is a caller-supplied override of the token-driven dropdown max-height, applied
|
|
69
|
+
// via Mantine's per-part `styles` API (same mechanism as `classNames` above) rather than a CSS
|
|
70
|
+
// module change, since it's an explicit per-instance escape hatch, not a design token. The CSS
|
|
71
|
+
// module deliberately leaves `overflow` unset (see MENU_IMPLEMENTATION_NOTES.md §8) so it
|
|
72
|
+
// doesn't clip sub-menus at the token default height; once a caller opts into a fixed
|
|
73
|
+
// `maxHeight`, though, items need to scroll instead of spilling out past the boundary.
|
|
74
|
+
const callerStyles = menuRestRecord.styles as
|
|
75
|
+
| Partial<Record<string, CSSProperties>>
|
|
76
|
+
| undefined;
|
|
77
|
+
const mergedStyles = maxHeight
|
|
78
|
+
? {
|
|
79
|
+
...callerStyles,
|
|
80
|
+
dropdown: {
|
|
81
|
+
...callerStyles?.dropdown,
|
|
82
|
+
maxHeight: maxHeight as CSSProperties["maxHeight"],
|
|
83
|
+
overflowY: "auto" as CSSProperties["overflowY"],
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
: callerStyles;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<MantineMenu
|
|
90
|
+
{...(menuRestRecord as unknown as MantineMenuProps)}
|
|
91
|
+
classNames={mergedClassNames}
|
|
92
|
+
{...(mergedStyles ? { styles: mergedStyles } : {})}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
MenuBase.displayName = "Menu";
|
|
97
|
+
|
|
98
|
+
// ============================================================
|
|
99
|
+
// MENU TARGET
|
|
100
|
+
// ============================================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Wrapper for the element that triggers the menu.
|
|
104
|
+
* Requires a single child element that supports ref forwarding.
|
|
105
|
+
*/
|
|
106
|
+
export type MenuTargetProps = RecursicaOverStyled<MantineMenuTargetProps>;
|
|
107
|
+
|
|
108
|
+
const MenuTarget = function MenuTarget({
|
|
109
|
+
overStyled = false,
|
|
110
|
+
...rest
|
|
111
|
+
}: MenuTargetProps) {
|
|
112
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<MantineMenu.Target
|
|
116
|
+
{...(sanitizedProps as unknown as MantineMenuTargetProps)}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
MenuTarget.displayName = "MenuTarget";
|
|
121
|
+
|
|
122
|
+
// ============================================================
|
|
123
|
+
// MENU DROPDOWN
|
|
124
|
+
// ============================================================
|
|
125
|
+
|
|
126
|
+
/** The dropdown panel containing menu items, dividers, and labels. */
|
|
127
|
+
export type MenuDropdownProps = RecursicaOverStyled<MantineMenuDropdownProps>;
|
|
128
|
+
|
|
129
|
+
const MenuDropdown = forwardRef<HTMLDivElement, MenuDropdownProps>(
|
|
130
|
+
function MenuDropdown({ overStyled = false, ...rest }, ref) {
|
|
131
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
132
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
133
|
+
.className as string | undefined;
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<MantineMenu.Dropdown
|
|
137
|
+
{...(sanitizedProps as unknown as MantineMenuDropdownProps)}
|
|
138
|
+
ref={ref}
|
|
139
|
+
className={classNameProp}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
MenuDropdown.displayName = "MenuDropdown";
|
|
145
|
+
|
|
146
|
+
// ============================================================
|
|
147
|
+
// MENU ITEM
|
|
148
|
+
// ============================================================
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* An individual actionable item within the menu dropdown.
|
|
152
|
+
*
|
|
153
|
+
* **Note:** Mantine's `color` prop is stripped to enforce design token adherence.
|
|
154
|
+
*/
|
|
155
|
+
export type MenuItemProps = RecursicaOverStyled<
|
|
156
|
+
Omit<MantineMenuItemProps, "color">
|
|
157
|
+
>;
|
|
158
|
+
|
|
159
|
+
const _MenuItem = forwardRef<HTMLButtonElement, MenuItemProps>(
|
|
160
|
+
function MenuItem({ overStyled = false, ...rest }, ref) {
|
|
161
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
162
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
163
|
+
const UNSUPPORTED_PROPS = [
|
|
164
|
+
"color", // Colors are token-driven; the library's native palette isn't exposed.
|
|
165
|
+
] as const satisfies readonly (keyof MantineMenuItemProps)[];
|
|
166
|
+
|
|
167
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
168
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
169
|
+
UNSUPPORTED_PROPS,
|
|
170
|
+
);
|
|
171
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
172
|
+
|
|
173
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<MantineMenu.Item
|
|
177
|
+
{...(sanitizedProps as unknown as MantineMenuItemProps)}
|
|
178
|
+
ref={ref}
|
|
179
|
+
className={classNameProp}
|
|
180
|
+
/>
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
);
|
|
184
|
+
_MenuItem.displayName = "MenuItem";
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* An individual actionable item within the menu dropdown.
|
|
188
|
+
*
|
|
189
|
+
* Supports polymorphism via the `component` prop for link-style items.
|
|
190
|
+
* @example
|
|
191
|
+
* ```tsx
|
|
192
|
+
* <Menu.Item component="a" href="/settings">Settings</Menu.Item>
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
const MenuItem = createPolymorphicComponent<"button", MenuItemProps>(_MenuItem);
|
|
196
|
+
|
|
197
|
+
// ============================================================
|
|
198
|
+
// MENU DIVIDER
|
|
199
|
+
// ============================================================
|
|
200
|
+
|
|
201
|
+
/** A visual separator between groups of menu items. */
|
|
202
|
+
export type MenuDividerProps = RecursicaOverStyled<MantineMenuDividerProps>;
|
|
203
|
+
|
|
204
|
+
const MenuDivider = forwardRef<HTMLHRElement, MenuDividerProps>(
|
|
205
|
+
function MenuDivider({ overStyled = false, ...rest }, ref) {
|
|
206
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
207
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
208
|
+
.className as string | undefined;
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
<MantineMenu.Divider
|
|
212
|
+
{...(sanitizedProps as unknown as MantineMenuDividerProps)}
|
|
213
|
+
ref={ref}
|
|
214
|
+
className={classNameProp}
|
|
215
|
+
/>
|
|
216
|
+
);
|
|
217
|
+
},
|
|
218
|
+
);
|
|
219
|
+
MenuDivider.displayName = "MenuDivider";
|
|
220
|
+
|
|
221
|
+
// ============================================================
|
|
222
|
+
// MENU LABEL
|
|
223
|
+
// ============================================================
|
|
224
|
+
|
|
225
|
+
/** A non-interactive section label used to categorize groups of menu items. */
|
|
226
|
+
export type MenuLabelProps = RecursicaOverStyled<MantineMenuLabelProps>;
|
|
227
|
+
|
|
228
|
+
const MenuLabel = forwardRef<HTMLDivElement, MenuLabelProps>(function MenuLabel(
|
|
229
|
+
{ overStyled = false, ...rest },
|
|
230
|
+
ref,
|
|
231
|
+
) {
|
|
232
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
233
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
234
|
+
.className as string | undefined;
|
|
235
|
+
|
|
236
|
+
return (
|
|
237
|
+
<MantineMenu.Label
|
|
238
|
+
{...(sanitizedProps as unknown as MantineMenuLabelProps)}
|
|
239
|
+
ref={ref}
|
|
240
|
+
className={classNameProp}
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
MenuLabel.displayName = "MenuLabel";
|
|
245
|
+
|
|
246
|
+
// ============================================================
|
|
247
|
+
// MENU SUB (SUBMENU CONTAINER)
|
|
248
|
+
// ============================================================
|
|
249
|
+
|
|
250
|
+
/** Container for a submenu, wrapping Menu.Sub.Target and Menu.Sub.Dropdown. */
|
|
251
|
+
export type MenuSubProps = MantineMenuSubProps;
|
|
252
|
+
|
|
253
|
+
const MenuSubBase = function MenuSub(props: MenuSubProps) {
|
|
254
|
+
return <MantineMenu.Sub {...props} />;
|
|
255
|
+
};
|
|
256
|
+
MenuSubBase.displayName = "MenuSub";
|
|
257
|
+
|
|
258
|
+
// ============================================================
|
|
259
|
+
// MENU SUB TARGET
|
|
260
|
+
// ============================================================
|
|
261
|
+
|
|
262
|
+
/** Wrapper for the element that triggers the submenu. */
|
|
263
|
+
export type MenuSubTargetProps = MantineMenuSubTargetProps;
|
|
264
|
+
|
|
265
|
+
const MenuSubTarget = function MenuSubTarget(props: MenuSubTargetProps) {
|
|
266
|
+
return <MantineMenu.Sub.Target {...props} />;
|
|
267
|
+
};
|
|
268
|
+
MenuSubTarget.displayName = "MenuSubTarget";
|
|
269
|
+
|
|
270
|
+
// ============================================================
|
|
271
|
+
// MENU SUB ITEM (triggers submenu)
|
|
272
|
+
// ============================================================
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* A menu item that acts as a submenu trigger.
|
|
276
|
+
* Renders within Menu.Sub.Target and displays a chevron indicator.
|
|
277
|
+
*/
|
|
278
|
+
export type MenuSubItemProps = RecursicaOverStyled<
|
|
279
|
+
Omit<MantineMenuItemProps, "color">
|
|
280
|
+
>;
|
|
281
|
+
|
|
282
|
+
const _MenuSubItem = forwardRef<HTMLButtonElement, MenuSubItemProps>(
|
|
283
|
+
function MenuSubItem({ overStyled = false, ...rest }, ref) {
|
|
284
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
285
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
286
|
+
const UNSUPPORTED_PROPS = [
|
|
287
|
+
"color", // Colors are token-driven; the library's native palette isn't exposed.
|
|
288
|
+
] as const satisfies readonly (keyof MantineMenuItemProps)[];
|
|
289
|
+
|
|
290
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
291
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
292
|
+
UNSUPPORTED_PROPS,
|
|
293
|
+
);
|
|
294
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
295
|
+
|
|
296
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<MantineMenu.Sub.Item
|
|
300
|
+
{...(sanitizedProps as unknown as MantineMenuItemProps)}
|
|
301
|
+
ref={ref}
|
|
302
|
+
className={classNameProp}
|
|
303
|
+
/>
|
|
304
|
+
);
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
_MenuSubItem.displayName = "MenuSubItem";
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* A menu item that acts as a submenu trigger.
|
|
311
|
+
*
|
|
312
|
+
* Supports polymorphism via the `component` prop.
|
|
313
|
+
*/
|
|
314
|
+
const MenuSubItem = createPolymorphicComponent<"button", MenuSubItemProps>(
|
|
315
|
+
_MenuSubItem,
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
// ============================================================
|
|
319
|
+
// MENU SUB DROPDOWN
|
|
320
|
+
// ============================================================
|
|
321
|
+
|
|
322
|
+
/** The dropdown panel for a submenu. */
|
|
323
|
+
export type MenuSubDropdownProps =
|
|
324
|
+
RecursicaOverStyled<MantineMenuSubDropdownProps>;
|
|
325
|
+
|
|
326
|
+
const MenuSubDropdown = forwardRef<HTMLDivElement, MenuSubDropdownProps>(
|
|
327
|
+
function MenuSubDropdown({ overStyled = false, ...rest }, ref) {
|
|
328
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
329
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
330
|
+
.className as string | undefined;
|
|
331
|
+
|
|
332
|
+
return (
|
|
333
|
+
<MantineMenu.Sub.Dropdown
|
|
334
|
+
{...(sanitizedProps as unknown as MantineMenuSubDropdownProps)}
|
|
335
|
+
ref={ref}
|
|
336
|
+
className={classNameProp}
|
|
337
|
+
/>
|
|
338
|
+
);
|
|
339
|
+
},
|
|
340
|
+
);
|
|
341
|
+
MenuSubDropdown.displayName = "MenuSubDropdown";
|
|
342
|
+
|
|
343
|
+
// ============================================================
|
|
344
|
+
// DOT NOTATION EXPORT
|
|
345
|
+
// ============================================================
|
|
346
|
+
|
|
347
|
+
type MenuSubComponent = typeof MenuSubBase & {
|
|
348
|
+
Target: typeof MenuSubTarget;
|
|
349
|
+
Item: typeof MenuSubItem;
|
|
350
|
+
Dropdown: typeof MenuSubDropdown;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
const MenuSub = MenuSubBase as MenuSubComponent;
|
|
354
|
+
MenuSub.Target = MenuSubTarget;
|
|
355
|
+
MenuSub.Item = MenuSubItem;
|
|
356
|
+
MenuSub.Dropdown = MenuSubDropdown;
|
|
357
|
+
|
|
358
|
+
type MenuComponent = typeof MenuBase & {
|
|
359
|
+
Target: typeof MenuTarget;
|
|
360
|
+
Dropdown: typeof MenuDropdown;
|
|
361
|
+
Item: typeof MenuItem;
|
|
362
|
+
Divider: typeof MenuDivider;
|
|
363
|
+
Label: typeof MenuLabel;
|
|
364
|
+
Sub: MenuSubComponent;
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
export const Menu = MenuBase as MenuComponent;
|
|
368
|
+
Menu.Target = MenuTarget;
|
|
369
|
+
Menu.Dropdown = MenuDropdown;
|
|
370
|
+
Menu.Item = MenuItem;
|
|
371
|
+
Menu.Divider = MenuDivider;
|
|
372
|
+
Menu.Label = MenuLabel;
|
|
373
|
+
Menu.Sub = MenuSub;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Menu - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Menu` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Menu } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Menu } from "@recursica/adapter-mantine-v8";
|
|
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-mantine-v8` 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
|
+
- The full Mantine composition API is supported, including sub-menus: `Menu`, `Menu.Target`, `Menu.Dropdown`, `Menu.Item`, `Menu.Divider`, `Menu.Label`, `Menu.Sub`, `Menu.Sub.Target`, `Menu.Sub.Item`, and `Menu.Sub.Dropdown`.
|
|
54
|
+
- The `color` prop on `Menu.Item` (and `Menu.Sub.Item`) — used by Mantine for semantics like a "danger" item — is ignored unless `overStyled={true}` is set.
|
|
55
|
+
- `maxHeight` on the root `<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,32 @@
|
|
|
1
|
+
# Modal Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Architecture
|
|
4
|
+
|
|
5
|
+
The `Modal` component strictly wraps Mantine's `<Modal>` primitive. We strip Mantine's abstract native styling props (`size`, `radius`, `shadow`) via the `overStyled` interface and strictly inject CSS variable definitions onto the internal node abstractions (`.content`, `.header`, `.body`, `.title`).
|
|
6
|
+
|
|
7
|
+
## Limitations & Structural Decisions
|
|
8
|
+
|
|
9
|
+
### 1. Stripped `size` Prop
|
|
10
|
+
|
|
11
|
+
Mantine natively exposes an abstract `size` prop (`"sm" | "md" | "lg" | "xl"`) that scales the Modal geometry. The Recursica UI Kit explicitly dictates strict geometric bounding boxes: `max-width: 960px` and `min-width: 304px`. To enforce absolute parity with the design system, the `size` prop has been intentionally omitted from the component's interface. The width of the Modal will scale fluidly strictly between these Figma-driven pixel limits.
|
|
12
|
+
|
|
13
|
+
### 2. Scroll Dividers behavior
|
|
14
|
+
|
|
15
|
+
Mantine internally handles scroll state natively, dynamically showing/hiding a divider line when content overflows in `.body`. This logic is tightly coupled to React DOM measurements internally. Our component inherits this dynamic behavior rather than statically rendering a permanent divider, matching Mantine's robust overflow UX. However, we aggressively override the generated `border-bottom` via CSS modules to ensure that when it _does_ appear, it correctly utilizes the `--recursica_ui-kit_components_modal_colors_scroll-divider` variable and `--recursica_ui-kit_components_modal_properties_scroll-divider-thickness` token.
|
|
16
|
+
|
|
17
|
+
### 3. Title truncation
|
|
18
|
+
|
|
19
|
+
`.title` truncates with an ellipsis (`overflow: clip; overflow-clip-margin: 0.35em`, `white-space: nowrap`, `text-overflow: ellipsis`) rather than wrapping. It also needs `flex: 1 1 auto; min-width: 0;` since it's a flex child of `.header` alongside the close button — without `min-width: 0`, a flex item won't shrink below its content's intrinsic width, so ellipsis never engages. `.header`'s `display: flex` is likewise explicit rather than relied upon from Mantine's own header class, so the mui-adapter's plain-`<div>` header gets identical layout.
|
|
20
|
+
|
|
21
|
+
`.title` used plain `overflow: hidden` until 2026-08-28 (Matt Massey) — it clipped descenders
|
|
22
|
+
(e.g. "g" in a long title) whenever `text_line-height` is tighter than the font's natural
|
|
23
|
+
ascent+descent. `overflow-clip-margin` gives ink a small bleed allowance while still clipping
|
|
24
|
+
genuinely overflowing text, same project-wide fix as Chip's `CHIP_IMPLEMENTATION_NOTES.md`.
|
|
25
|
+
|
|
26
|
+
### 4. Width was pinned to Mantine's `md` size, not content-driven
|
|
27
|
+
|
|
28
|
+
Despite §1 above, `.content` never actually scaled fluidly: Mantine's own CSS sets `flex: 0 0 var(--modal-size)` (defaulting to 440px) on the Content element, and our module only added `min-width`/`max-width` without touching `flex`. A fixed flex-basis with `flex-shrink: 0` pins the box at exactly 440px regardless of those bounds, so they were unreachable dead code — e.g. "Authentication Required" (the `Default` story's title) didn't fit at 440px and silently wrapped to two lines. Overriding to `flex: 0 1 auto` makes the width shrink-to-fit the content within `min-width`/`max-width`, which is what makes title truncation (§3) only kick in once a title would exceed `max-width` rather than truncating titles that would otherwise fit. `.content[data-full-screen]` restores Mantine's own `flex: 0 0 100%` since the shrink-to-fit override would otherwise stop `fullScreen` from filling the viewport.
|
|
29
|
+
|
|
30
|
+
### 5. Close button restyled to match Button
|
|
31
|
+
|
|
32
|
+
`.close` reuses Button's text-variant/icon-only/small tokens (radius, padding, background/icon color, hover overlay, focus ring) instead of Mantine's native CloseButton look. Two overrides need `!important`/an explicit reset to win: Mantine's `CloseIcon` sizes itself via an inline `style` (`--cb-icon-size`, default `70%`), which beats any plain class rule — same category as Tree's `--level-offset` override; and Mantine's own subtle-variant `:hover` background (from `CloseButton.css`) is pinned back to the Button background token so only our `::after` overlay renders hover feedback.
|