@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,368 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Modal as MantineModal,
|
|
4
|
+
type ModalProps as MantineModalProps,
|
|
5
|
+
type ModalRootProps as MantineModalRootProps,
|
|
6
|
+
type ModalOverlayProps as MantineModalOverlayProps,
|
|
7
|
+
type ModalContentProps as MantineModalContentProps,
|
|
8
|
+
type ModalHeaderProps as MantineModalHeaderProps,
|
|
9
|
+
type ModalTitleProps as MantineModalTitleProps,
|
|
10
|
+
type ModalCloseButtonProps as MantineModalCloseButtonProps,
|
|
11
|
+
type ModalBodyProps as MantineModalBodyProps,
|
|
12
|
+
} from "@mantine/core";
|
|
13
|
+
import {
|
|
14
|
+
filterStylingProps,
|
|
15
|
+
omitUnsupportedProps,
|
|
16
|
+
mergeClassNames,
|
|
17
|
+
type RecursicaOverStyled,
|
|
18
|
+
} from "../../utils/filterStylingProps";
|
|
19
|
+
import styles from "./Modal.module.css";
|
|
20
|
+
|
|
21
|
+
import { type RecursicaModalProps } from "@recursica/adapter-common";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Properties for the strictly-tokenized Modal component.
|
|
25
|
+
* Native Mantine abstract properties like `size`, `radius`, and `shadow` have been stripped out
|
|
26
|
+
* because they directly conflict with the non-negotiable pixel boundaries defined in the Recursica UI Kit.
|
|
27
|
+
*/
|
|
28
|
+
export type ModalProps = RecursicaOverStyled<
|
|
29
|
+
Omit<MantineModalProps, "size" | "radius" | "shadow"> & RecursicaModalProps
|
|
30
|
+
>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The `Modal` component displays a window overlaid on the primary viewport.
|
|
34
|
+
*
|
|
35
|
+
* **Recursica Abstract:**
|
|
36
|
+
* This component acts as a strict structural wrapper around Mantine's `<Modal>`.
|
|
37
|
+
* It automatically enforces Figma UI Kit geometries (`max-width: 960px`, `min-width: 304px`)
|
|
38
|
+
* and handles internal body scrolling explicitly via CSS module overrides.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <Modal opened={opened} onClose={close} title="Hello World">
|
|
43
|
+
* Modal Content
|
|
44
|
+
* </Modal>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
const ModalInner = React.forwardRef<HTMLDivElement, ModalProps>(function Modal(
|
|
48
|
+
{
|
|
49
|
+
overStyled = false,
|
|
50
|
+
children,
|
|
51
|
+
title,
|
|
52
|
+
withCloseButton = true,
|
|
53
|
+
overlayProps,
|
|
54
|
+
withOverlay = true,
|
|
55
|
+
closeButtonProps,
|
|
56
|
+
...rest
|
|
57
|
+
},
|
|
58
|
+
ref,
|
|
59
|
+
) {
|
|
60
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
61
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
62
|
+
const UNSUPPORTED_PROPS = [
|
|
63
|
+
"size", // Modal width/height are enforced via CSS module tokens (min/max-width, min/max-height), not Mantine's `size` scale.
|
|
64
|
+
"radius", // Modal corner radius is token-driven via `.content` in Modal.module.css, not Mantine's `radius` prop.
|
|
65
|
+
] as const satisfies readonly (keyof MantineModalProps)[];
|
|
66
|
+
|
|
67
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
68
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
69
|
+
UNSUPPORTED_PROPS,
|
|
70
|
+
) as Partial<typeof rest>;
|
|
71
|
+
|
|
72
|
+
const mergedClassNames = mergeClassNames(
|
|
73
|
+
{
|
|
74
|
+
root: styles.root,
|
|
75
|
+
inner: styles.inner,
|
|
76
|
+
content: styles.content,
|
|
77
|
+
header: styles.header,
|
|
78
|
+
title: styles.title,
|
|
79
|
+
close: styles.close,
|
|
80
|
+
},
|
|
81
|
+
(sanitizedProps as Record<string, unknown>).classNames as
|
|
82
|
+
| Partial<Record<string, string>>
|
|
83
|
+
| undefined,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<MantineModal.Root
|
|
88
|
+
ref={ref}
|
|
89
|
+
{...(sanitizedProps as unknown as Omit<
|
|
90
|
+
MantineModalProps,
|
|
91
|
+
"size" | "radius" | "shadow"
|
|
92
|
+
>)}
|
|
93
|
+
classNames={mergedClassNames}
|
|
94
|
+
>
|
|
95
|
+
{withOverlay && <MantineModal.Overlay {...overlayProps} />}
|
|
96
|
+
<MantineModal.Content>
|
|
97
|
+
{(title || withCloseButton) && (
|
|
98
|
+
<MantineModal.Header>
|
|
99
|
+
{title && <MantineModal.Title>{title}</MantineModal.Title>}
|
|
100
|
+
{withCloseButton && (
|
|
101
|
+
<MantineModal.CloseButton {...closeButtonProps} />
|
|
102
|
+
)}
|
|
103
|
+
</MantineModal.Header>
|
|
104
|
+
)}
|
|
105
|
+
<ModalBody>{children}</ModalBody>
|
|
106
|
+
</MantineModal.Content>
|
|
107
|
+
</MantineModal.Root>
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
ModalInner.displayName = "Modal";
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The `Modal.Footer` provides a perfectly padded container for modal actions.
|
|
115
|
+
*
|
|
116
|
+
* **Recursica Abstract:**
|
|
117
|
+
* By default, this container aligns its children to the right (`justify-content: flex-end`)
|
|
118
|
+
* and applies the standard Figma button-gap spacing.
|
|
119
|
+
*
|
|
120
|
+
* > [!IMPORTANT]
|
|
121
|
+
* > **Button Hierarchy:** Recursica design language explicitly requires that the
|
|
122
|
+
* > primary action button MUST be the right-most element, with the secondary
|
|
123
|
+
* > (outline variant) action placed immediately to the left of it.
|
|
124
|
+
*/
|
|
125
|
+
export type ModalFooterProps = RecursicaOverStyled<
|
|
126
|
+
React.ComponentPropsWithoutRef<"div">
|
|
127
|
+
>;
|
|
128
|
+
|
|
129
|
+
const ModalFooter = React.forwardRef<HTMLDivElement, ModalFooterProps>(
|
|
130
|
+
function ModalFooter({ overStyled = false, className, ...rest }, ref) {
|
|
131
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
132
|
+
return (
|
|
133
|
+
<div
|
|
134
|
+
ref={ref}
|
|
135
|
+
{...sanitizedProps}
|
|
136
|
+
className={`${styles.footer} ${className || ""}`}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
);
|
|
141
|
+
ModalFooter.displayName = "Modal.Footer";
|
|
142
|
+
|
|
143
|
+
export type ModalBodyProps = RecursicaOverStyled<MantineModalBodyProps>;
|
|
144
|
+
|
|
145
|
+
const ModalBody = React.forwardRef<HTMLDivElement, ModalBodyProps>(
|
|
146
|
+
function ModalBody(
|
|
147
|
+
{ overStyled = false, className, onScroll, children, ...rest },
|
|
148
|
+
ref,
|
|
149
|
+
) {
|
|
150
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
151
|
+
const internalRef = React.useRef<HTMLDivElement>(null);
|
|
152
|
+
const [scrolledTop, setScrolledTop] = React.useState(false);
|
|
153
|
+
const [scrolledBottom, setScrolledBottom] = React.useState(false);
|
|
154
|
+
|
|
155
|
+
const checkScroll = React.useCallback(() => {
|
|
156
|
+
if (internalRef.current) {
|
|
157
|
+
const { scrollTop, scrollHeight, clientHeight } = internalRef.current;
|
|
158
|
+
setScrolledTop(scrollTop > 0);
|
|
159
|
+
setScrolledBottom(Math.ceil(scrollTop + clientHeight) < scrollHeight);
|
|
160
|
+
}
|
|
161
|
+
}, []);
|
|
162
|
+
|
|
163
|
+
// Re-check scroll on mount and window resize
|
|
164
|
+
React.useEffect(() => {
|
|
165
|
+
checkScroll();
|
|
166
|
+
window.addEventListener("resize", checkScroll);
|
|
167
|
+
return () => window.removeEventListener("resize", checkScroll);
|
|
168
|
+
}, [checkScroll, children]);
|
|
169
|
+
|
|
170
|
+
const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {
|
|
171
|
+
checkScroll();
|
|
172
|
+
onScroll?.(e);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// Intercept children to pull Modal.Footer out of the scrolling container
|
|
176
|
+
let footer: React.ReactNode = null;
|
|
177
|
+
const bodyChildren: React.ReactNode[] = [];
|
|
178
|
+
|
|
179
|
+
React.Children.forEach(children, (child) => {
|
|
180
|
+
if (
|
|
181
|
+
React.isValidElement(child) &&
|
|
182
|
+
(child.type === ModalFooter ||
|
|
183
|
+
(child.type as React.ComponentType)?.displayName === "Modal.Footer")
|
|
184
|
+
) {
|
|
185
|
+
footer = child;
|
|
186
|
+
} else {
|
|
187
|
+
bodyChildren.push(child);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
return (
|
|
192
|
+
<MantineModal.Body
|
|
193
|
+
{...sanitizedProps}
|
|
194
|
+
ref={(node) => {
|
|
195
|
+
if (typeof ref === "function") ref(node);
|
|
196
|
+
else if (ref)
|
|
197
|
+
(ref as React.MutableRefObject<HTMLDivElement | null>).current =
|
|
198
|
+
node;
|
|
199
|
+
}}
|
|
200
|
+
className={`${styles.bodyWrapper} ${className || ""}`}
|
|
201
|
+
>
|
|
202
|
+
<div
|
|
203
|
+
ref={internalRef}
|
|
204
|
+
onScroll={handleScroll}
|
|
205
|
+
data-scrolled-top={scrolledTop || undefined}
|
|
206
|
+
data-scrolled-bottom={scrolledBottom || undefined}
|
|
207
|
+
className={styles.scrollArea}
|
|
208
|
+
>
|
|
209
|
+
{bodyChildren}
|
|
210
|
+
</div>
|
|
211
|
+
{footer}
|
|
212
|
+
</MantineModal.Body>
|
|
213
|
+
);
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
ModalBody.displayName = "Modal.Body";
|
|
217
|
+
|
|
218
|
+
// ============================================================
|
|
219
|
+
// MODAL SUB-COMPONENTS (wrapped so overStyled/filterStylingProps applies)
|
|
220
|
+
// ============================================================
|
|
221
|
+
|
|
222
|
+
export type ModalRootProps = RecursicaOverStyled<MantineModalRootProps>;
|
|
223
|
+
|
|
224
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
225
|
+
// through even if a caller forces them via plain JavaScript. `Modal.Root` is used directly for
|
|
226
|
+
// advanced composition, so it doesn't benefit from the top-level `Modal`'s `Omit<>` protection.
|
|
227
|
+
const MODAL_ROOT_UNSUPPORTED_PROPS = [
|
|
228
|
+
"size", // Modal width/height are enforced via CSS module tokens, not Mantine's `size` scale.
|
|
229
|
+
"radius", // Modal corner radius is token-driven via `.content` in Modal.module.css, not Mantine's `radius` prop.
|
|
230
|
+
] as const satisfies readonly (keyof MantineModalRootProps)[];
|
|
231
|
+
|
|
232
|
+
const ModalRoot = React.forwardRef<HTMLDivElement, ModalRootProps>(
|
|
233
|
+
function ModalRoot({ overStyled = false, ...rest }, ref) {
|
|
234
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
235
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
236
|
+
MODAL_ROOT_UNSUPPORTED_PROPS,
|
|
237
|
+
) as Partial<typeof rest>;
|
|
238
|
+
return (
|
|
239
|
+
<MantineModal.Root
|
|
240
|
+
ref={ref}
|
|
241
|
+
{...(sanitizedProps as unknown as MantineModalRootProps)}
|
|
242
|
+
/>
|
|
243
|
+
);
|
|
244
|
+
},
|
|
245
|
+
);
|
|
246
|
+
ModalRoot.displayName = "Modal.Root";
|
|
247
|
+
|
|
248
|
+
export type ModalOverlayProps = RecursicaOverStyled<MantineModalOverlayProps>;
|
|
249
|
+
|
|
250
|
+
const ModalOverlay = React.forwardRef<HTMLDivElement, ModalOverlayProps>(
|
|
251
|
+
function ModalOverlay({ overStyled = false, ...rest }, ref) {
|
|
252
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
253
|
+
return (
|
|
254
|
+
<MantineModal.Overlay
|
|
255
|
+
ref={ref}
|
|
256
|
+
{...(sanitizedProps as unknown as MantineModalOverlayProps)}
|
|
257
|
+
/>
|
|
258
|
+
);
|
|
259
|
+
},
|
|
260
|
+
);
|
|
261
|
+
ModalOverlay.displayName = "Modal.Overlay";
|
|
262
|
+
|
|
263
|
+
export type ModalContentProps = RecursicaOverStyled<MantineModalContentProps>;
|
|
264
|
+
|
|
265
|
+
// Modal corner radius is token-driven via `.content` in Modal.module.css, not Mantine's
|
|
266
|
+
// native `radius` prop — deleted at runtime so it can't leak through via plain JavaScript.
|
|
267
|
+
const MODAL_CONTENT_UNSUPPORTED_PROPS = [
|
|
268
|
+
"radius",
|
|
269
|
+
] as const satisfies readonly (keyof MantineModalContentProps)[];
|
|
270
|
+
|
|
271
|
+
const ModalContent = React.forwardRef<HTMLDivElement, ModalContentProps>(
|
|
272
|
+
function ModalContent({ overStyled = false, ...rest }, ref) {
|
|
273
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
274
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
275
|
+
MODAL_CONTENT_UNSUPPORTED_PROPS,
|
|
276
|
+
) as Partial<typeof rest>;
|
|
277
|
+
return (
|
|
278
|
+
<MantineModal.Content
|
|
279
|
+
ref={ref}
|
|
280
|
+
{...(sanitizedProps as unknown as MantineModalContentProps)}
|
|
281
|
+
/>
|
|
282
|
+
);
|
|
283
|
+
},
|
|
284
|
+
);
|
|
285
|
+
ModalContent.displayName = "Modal.Content";
|
|
286
|
+
|
|
287
|
+
export type ModalHeaderProps = RecursicaOverStyled<MantineModalHeaderProps>;
|
|
288
|
+
|
|
289
|
+
const ModalHeader = React.forwardRef<HTMLElement, ModalHeaderProps>(
|
|
290
|
+
function ModalHeader({ overStyled = false, ...rest }, ref) {
|
|
291
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
292
|
+
return (
|
|
293
|
+
<MantineModal.Header
|
|
294
|
+
ref={ref}
|
|
295
|
+
{...(sanitizedProps as unknown as MantineModalHeaderProps)}
|
|
296
|
+
/>
|
|
297
|
+
);
|
|
298
|
+
},
|
|
299
|
+
);
|
|
300
|
+
ModalHeader.displayName = "Modal.Header";
|
|
301
|
+
|
|
302
|
+
export type ModalTitleProps = RecursicaOverStyled<MantineModalTitleProps>;
|
|
303
|
+
|
|
304
|
+
const ModalTitle = React.forwardRef<HTMLHeadingElement, ModalTitleProps>(
|
|
305
|
+
function ModalTitle({ overStyled = false, ...rest }, ref) {
|
|
306
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
307
|
+
return (
|
|
308
|
+
<MantineModal.Title
|
|
309
|
+
ref={ref}
|
|
310
|
+
{...(sanitizedProps as unknown as MantineModalTitleProps)}
|
|
311
|
+
/>
|
|
312
|
+
);
|
|
313
|
+
},
|
|
314
|
+
);
|
|
315
|
+
ModalTitle.displayName = "Modal.Title";
|
|
316
|
+
|
|
317
|
+
export type ModalCloseButtonProps =
|
|
318
|
+
RecursicaOverStyled<MantineModalCloseButtonProps>;
|
|
319
|
+
|
|
320
|
+
// The close button's dimensions and corner radius are enforced by Modal.module.css's `.close`
|
|
321
|
+
// (standard icon-button tokens), not Mantine's native `size`/`radius` scales.
|
|
322
|
+
const MODAL_CLOSE_BUTTON_UNSUPPORTED_PROPS = [
|
|
323
|
+
"size",
|
|
324
|
+
"radius",
|
|
325
|
+
] as const satisfies readonly (keyof MantineModalCloseButtonProps)[];
|
|
326
|
+
|
|
327
|
+
const ModalCloseButton = React.forwardRef<
|
|
328
|
+
HTMLButtonElement,
|
|
329
|
+
ModalCloseButtonProps
|
|
330
|
+
>(function ModalCloseButton({ overStyled = false, ...rest }, ref) {
|
|
331
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
332
|
+
filterStylingProps(rest, overStyled) as Record<string, unknown>,
|
|
333
|
+
MODAL_CLOSE_BUTTON_UNSUPPORTED_PROPS,
|
|
334
|
+
) as Partial<typeof rest>;
|
|
335
|
+
return (
|
|
336
|
+
<MantineModal.CloseButton
|
|
337
|
+
ref={ref}
|
|
338
|
+
{...(sanitizedProps as unknown as MantineModalCloseButtonProps)}
|
|
339
|
+
/>
|
|
340
|
+
);
|
|
341
|
+
});
|
|
342
|
+
ModalCloseButton.displayName = "Modal.CloseButton";
|
|
343
|
+
|
|
344
|
+
interface ModalComponent
|
|
345
|
+
extends React.ForwardRefExoticComponent<
|
|
346
|
+
ModalProps & React.RefAttributes<HTMLDivElement>
|
|
347
|
+
> {
|
|
348
|
+
Root: typeof ModalRoot;
|
|
349
|
+
Overlay: typeof ModalOverlay;
|
|
350
|
+
Content: typeof ModalContent;
|
|
351
|
+
Header: typeof ModalHeader;
|
|
352
|
+
Title: typeof ModalTitle;
|
|
353
|
+
CloseButton: typeof ModalCloseButton;
|
|
354
|
+
Body: typeof ModalBody;
|
|
355
|
+
Footer: typeof ModalFooter;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export const Modal = ModalInner as ModalComponent & {
|
|
359
|
+
Footer: typeof ModalFooter;
|
|
360
|
+
};
|
|
361
|
+
Modal.Root = ModalRoot;
|
|
362
|
+
Modal.Overlay = ModalOverlay;
|
|
363
|
+
Modal.Content = ModalContent;
|
|
364
|
+
Modal.Header = ModalHeader;
|
|
365
|
+
Modal.Title = ModalTitle;
|
|
366
|
+
Modal.CloseButton = ModalCloseButton;
|
|
367
|
+
Modal.Body = ModalBody;
|
|
368
|
+
Modal.Footer = ModalFooter;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Modal - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Modal` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Modal } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Modal } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Modal opened={isOpen} onClose={close} title="Modal Title">
|
|
24
|
+
<Text>This is a styled Modal wrapping the native primitive.</Text>
|
|
25
|
+
</Modal>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. Design System Integration
|
|
33
|
+
|
|
34
|
+
All Recursica components in the `@recursica/adapter-mantine-v8` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
35
|
+
|
|
36
|
+
> [!IMPORTANT]
|
|
37
|
+
>
|
|
38
|
+
> - **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.
|
|
39
|
+
> - **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.
|
|
40
|
+
> - **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.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 4. Key Integration Features & Constraints
|
|
45
|
+
|
|
46
|
+
## Architecture
|
|
47
|
+
|
|
48
|
+
`Modal` wraps Mantine's `<Modal>` component. Native Mantine styling props (`size`, `radius`, `shadow`) are not used — appearance and sizing are fully controlled by the design system tokens instead.
|
|
49
|
+
|
|
50
|
+
## Limitations & Structural Decisions
|
|
51
|
+
|
|
52
|
+
### 1. Stripped `size` Prop
|
|
53
|
+
|
|
54
|
+
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.
|
|
55
|
+
|
|
56
|
+
### 2. Scroll Dividers
|
|
57
|
+
|
|
58
|
+
When the modal's content overflows and becomes scrollable, a divider line automatically appears, styled using the design system's scroll-divider color and thickness tokens.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Modal";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# NumberInput Implementation Notes
|
|
2
|
+
|
|
3
|
+
This document contains specific design decisions, architectural constraints, and hacks required to bridge the Recursica design system with Mantine's underlying `NumberInput` primitive.
|
|
4
|
+
|
|
5
|
+
## 1. Native Macro Wrapper Bypass
|
|
6
|
+
|
|
7
|
+
**Decision:** The `<NumberInput>` component explicitly bypasses Mantine's native `Input.Wrapper` DOM injections.
|
|
8
|
+
**Implementation:** We pass `label={undefined}`, `description={undefined}`, and `error={undefined}` directly into the primitive `<MantineNumberInput>`. All visual form control geometry is delegated exclusively to our unified `<FormControlWrapper>`, ensuring 100% token adherence for label spacing and assistive text styling without duplicate DOM rendering.
|
|
9
|
+
|
|
10
|
+
## 2. Right Section & Controls Override
|
|
11
|
+
|
|
12
|
+
**Decision:** Passing a `rightSection` element will natively remove the increment/decrement arrow controls.
|
|
13
|
+
**Implementation:** Mantine inherently renders its stepper controls inside the `rightSection` DOM slot. Providing a custom right-aligned icon or text element intentionally overwrites this slot. If a layout strictly requires both a custom right-aligned element and the stepper controls simultaneously, the integrator must manually rebuild the arrows using Mantine's `handlersRef` within a custom right-section wrapper.
|
|
14
|
+
|
|
15
|
+
## 3. Controls Styling
|
|
16
|
+
|
|
17
|
+
**Decision:** The increment/decrement control arrows rely partially on native Mantine CSS inheritance.
|
|
18
|
+
**Implementation:** The current Recursica design system tokens do not provide explicit UI styling parameters (`background`, `border`, `hover` states) for the inner number-input arrows. We have explicitly removed Mantine's default borders to cleanly nest them inside the unified input box, and mapped the icon colors to the generic `trailing-icon` token variable, but further visual configurations currently fall back to Mantine defaults.
|
|
19
|
+
|
|
20
|
+
## 4. Section Text Color (non-svg content)
|
|
21
|
+
|
|
22
|
+
**Bug:** `leftSection`/`rightSection` content that isn't an `<svg>` (e.g. a plain `<span>$</span>` currency stand-in, as used in the story) rendered in Mantine's own gray (`--mantine-color-dimmed`, via `--input-section-color`) instead of the Recursica leading/trailing-icon token. Only the `.section :global(svg)` rule was token-colored; anything else fell through to Mantine's `Input.Section` default.
|
|
23
|
+
**Fix:** `.section` now sets `--input-section-color` — the exact variable Mantine's own `Input.Section` rule reads — to the Recursica leading-icon/trailing-icon token per position. This colors any section content (svg or plain text) with the real token instead of leaving a Mantine-library gray leaking through. The `:global(svg)` color rule is left in place (redundant but harmless).
|
|
24
|
+
**Note:** the on-screen color didn't change — Recursica's token already resolves near-black; this fixed the _source_ it comes from, not the value.
|