@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,220 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Accordion as MantineAccordion,
|
|
4
|
+
type AccordionProps as MantineAccordionProps,
|
|
5
|
+
type AccordionItemProps,
|
|
6
|
+
type AccordionControlProps,
|
|
7
|
+
type AccordionPanelProps,
|
|
8
|
+
} from "@mantine/core";
|
|
9
|
+
import {
|
|
10
|
+
filterStylingProps,
|
|
11
|
+
omitUnsupportedProps,
|
|
12
|
+
mergeClassNames,
|
|
13
|
+
type RecursicaOverStyled,
|
|
14
|
+
} from "../../utils/filterStylingProps";
|
|
15
|
+
import styles from "./Accordion.module.css";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
type RecursicaAccordionProps,
|
|
19
|
+
type RecursicaAccordionItemProps,
|
|
20
|
+
type RecursicaAccordionControlProps,
|
|
21
|
+
type RecursicaAccordionPanelProps,
|
|
22
|
+
} from "@recursica/adapter-common";
|
|
23
|
+
|
|
24
|
+
// ==== ACCORDION CONTAINER ====
|
|
25
|
+
export type AccordionProps = RecursicaOverStyled<
|
|
26
|
+
Omit<
|
|
27
|
+
MantineAccordionProps,
|
|
28
|
+
"value" | "defaultValue" | "multiple" | "variant"
|
|
29
|
+
> &
|
|
30
|
+
RecursicaAccordionProps
|
|
31
|
+
>;
|
|
32
|
+
|
|
33
|
+
// Maps Recursica's public variant vocabulary to Mantine's own. `unstyled` is a Mantine
|
|
34
|
+
// sentinel with no meaning to Recursica consumers — it exists only to suppress Mantine's
|
|
35
|
+
// built-in variant CSS so our module CSS is the sole source of styling. Anything outside
|
|
36
|
+
// this map (a caller-supplied custom variant string) passes straight through to Mantine.
|
|
37
|
+
const mapVariant: Record<string, string> = {
|
|
38
|
+
default: "unstyled",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const AccordionBase = function Accordion({
|
|
42
|
+
variant = "default",
|
|
43
|
+
overStyled = false,
|
|
44
|
+
...rest
|
|
45
|
+
}: AccordionProps) {
|
|
46
|
+
const resolvedVariant =
|
|
47
|
+
typeof variant === "string" && mapVariant[variant]
|
|
48
|
+
? mapVariant[variant]
|
|
49
|
+
: variant;
|
|
50
|
+
|
|
51
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
52
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
53
|
+
|
|
54
|
+
// Bind all deep CSS module references natively into the global class mapping schema
|
|
55
|
+
const mergedClassNames = mergeClassNames(
|
|
56
|
+
{
|
|
57
|
+
root: styles.root,
|
|
58
|
+
item: styles.item,
|
|
59
|
+
control: styles.control,
|
|
60
|
+
label: styles.label,
|
|
61
|
+
chevron: styles.chevron,
|
|
62
|
+
icon: styles.icon,
|
|
63
|
+
panel: styles.panel,
|
|
64
|
+
content: styles.content,
|
|
65
|
+
},
|
|
66
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<MantineAccordion
|
|
73
|
+
{...(sanitizedProps as unknown as MantineAccordionProps)}
|
|
74
|
+
variant={resolvedVariant as MantineAccordionProps["variant"]}
|
|
75
|
+
className={classNameProp}
|
|
76
|
+
classNames={mergedClassNames}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
AccordionBase.displayName = "Accordion";
|
|
81
|
+
|
|
82
|
+
// We need to omit and re-merge native props like in Badge
|
|
83
|
+
export type AccordionItemWrapperProps = RecursicaOverStyled<
|
|
84
|
+
AccordionItemProps & RecursicaAccordionItemProps
|
|
85
|
+
>;
|
|
86
|
+
|
|
87
|
+
export const AccordionItem = forwardRef<
|
|
88
|
+
HTMLDivElement,
|
|
89
|
+
AccordionItemWrapperProps
|
|
90
|
+
>(function AccordionItem(
|
|
91
|
+
{
|
|
92
|
+
title,
|
|
93
|
+
leftIcon,
|
|
94
|
+
divider = true,
|
|
95
|
+
children,
|
|
96
|
+
disabled = false,
|
|
97
|
+
overStyled = false,
|
|
98
|
+
...rest
|
|
99
|
+
},
|
|
100
|
+
ref,
|
|
101
|
+
) {
|
|
102
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
103
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
104
|
+
.className as string | undefined;
|
|
105
|
+
|
|
106
|
+
const finalClass =
|
|
107
|
+
[divider ? undefined : styles.noDivider, classNameProp]
|
|
108
|
+
.filter(Boolean)
|
|
109
|
+
.join(" ") || undefined;
|
|
110
|
+
|
|
111
|
+
// If the user utilizes the explicit 'title' prop from Recursica, we securely auto-construct the Mantine sub-hierarchy natively!
|
|
112
|
+
// If not, we defer to raw composable children (meaning the integrator maps `<Accordion.Control>` manually).
|
|
113
|
+
// `disabled` has no native concept at the Item level — only Control has a real `disabled`
|
|
114
|
+
// prop (it renders a `<button>`, so the native HTML `disabled` attribute alone blocks click,
|
|
115
|
+
// focus, and keyboard activation with no extra guards needed). We forward it there in the
|
|
116
|
+
// auto-composed path; a manually-composed `<Accordion.Control>` needs it passed explicitly.
|
|
117
|
+
return (
|
|
118
|
+
<MantineAccordion.Item
|
|
119
|
+
ref={ref}
|
|
120
|
+
{...(sanitizedProps as unknown as AccordionItemProps)}
|
|
121
|
+
className={finalClass}
|
|
122
|
+
data-disabled={disabled || undefined}
|
|
123
|
+
>
|
|
124
|
+
{title ? (
|
|
125
|
+
<>
|
|
126
|
+
<AccordionControl leftIcon={leftIcon} disabled={disabled}>
|
|
127
|
+
{title}
|
|
128
|
+
</AccordionControl>
|
|
129
|
+
<AccordionPanel>{children}</AccordionPanel>
|
|
130
|
+
</>
|
|
131
|
+
) : (
|
|
132
|
+
children
|
|
133
|
+
)}
|
|
134
|
+
</MantineAccordion.Item>
|
|
135
|
+
);
|
|
136
|
+
});
|
|
137
|
+
AccordionItem.displayName = "AccordionItem";
|
|
138
|
+
|
|
139
|
+
// ==== ACCORDION CONTROL ====
|
|
140
|
+
export type AccordionControlWrapperProps = RecursicaOverStyled<
|
|
141
|
+
// Mantine's native `icon` slot is resolved internally from `leftIcon` — omitted so a
|
|
142
|
+
// caller can't silently override it by passing `icon` directly. Mantine's per-control
|
|
143
|
+
// `chevron` override is left as-is; nothing here computes it, so it passes through safely.
|
|
144
|
+
Omit<AccordionControlProps, "icon"> & RecursicaAccordionControlProps
|
|
145
|
+
>;
|
|
146
|
+
|
|
147
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
148
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
149
|
+
const UNSUPPORTED_PROPS = [
|
|
150
|
+
"icon", // Mantine's native icon slot is fully computed here from `leftIcon`; the `Omit<>` on
|
|
151
|
+
// AccordionControlWrapperProps only stops a well-typed caller, this is the runtime backstop.
|
|
152
|
+
] as const satisfies readonly (keyof AccordionControlProps)[];
|
|
153
|
+
|
|
154
|
+
export const AccordionControl = forwardRef<
|
|
155
|
+
HTMLButtonElement,
|
|
156
|
+
AccordionControlWrapperProps
|
|
157
|
+
>(function AccordionControl(
|
|
158
|
+
{ leftIcon, children, overStyled = false, ...rest },
|
|
159
|
+
ref,
|
|
160
|
+
) {
|
|
161
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
162
|
+
filterStylingProps(rest, overStyled),
|
|
163
|
+
UNSUPPORTED_PROPS,
|
|
164
|
+
);
|
|
165
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
166
|
+
.className as string | undefined;
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<MantineAccordion.Control
|
|
170
|
+
ref={ref}
|
|
171
|
+
{...(sanitizedProps as unknown as AccordionControlProps)}
|
|
172
|
+
className={classNameProp}
|
|
173
|
+
icon={
|
|
174
|
+
leftIcon ? (
|
|
175
|
+
<span className={styles.iconLeftWrapper} aria-hidden>
|
|
176
|
+
{leftIcon}
|
|
177
|
+
</span>
|
|
178
|
+
) : undefined
|
|
179
|
+
}
|
|
180
|
+
>
|
|
181
|
+
{children}
|
|
182
|
+
</MantineAccordion.Control>
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
AccordionControl.displayName = "AccordionControl";
|
|
186
|
+
|
|
187
|
+
// ==== ACCORDION PANEL ====
|
|
188
|
+
export type AccordionPanelWrapperProps = RecursicaOverStyled<
|
|
189
|
+
AccordionPanelProps & RecursicaAccordionPanelProps
|
|
190
|
+
>;
|
|
191
|
+
|
|
192
|
+
export const AccordionPanel = forwardRef<
|
|
193
|
+
HTMLDivElement,
|
|
194
|
+
AccordionPanelWrapperProps
|
|
195
|
+
>(function AccordionPanel({ overStyled = false, ...rest }, ref) {
|
|
196
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
197
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
198
|
+
.className as string | undefined;
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<MantineAccordion.Panel
|
|
202
|
+
ref={ref}
|
|
203
|
+
{...(sanitizedProps as unknown as AccordionPanelProps)}
|
|
204
|
+
className={classNameProp}
|
|
205
|
+
/>
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
AccordionPanel.displayName = "AccordionPanel";
|
|
209
|
+
|
|
210
|
+
// ==== DOT NOTATION EXPORT ====
|
|
211
|
+
type AccordionComponent = typeof AccordionBase & {
|
|
212
|
+
Item: typeof AccordionItem;
|
|
213
|
+
Control: typeof AccordionControl;
|
|
214
|
+
Panel: typeof AccordionPanel;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const Accordion = AccordionBase as AccordionComponent;
|
|
218
|
+
Accordion.Item = AccordionItem;
|
|
219
|
+
Accordion.Control = AccordionControl;
|
|
220
|
+
Accordion.Panel = AccordionPanel;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Accordion - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Accordion` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Accordion } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Accordion } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Accordion>
|
|
24
|
+
<Accordion.Item value="item-1">
|
|
25
|
+
<Accordion.Control>Section 1</Accordion.Control>
|
|
26
|
+
<Accordion.Panel>Section 1 content</Accordion.Panel>
|
|
27
|
+
</Accordion.Item>
|
|
28
|
+
</Accordion>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 3. Design System Integration
|
|
36
|
+
|
|
37
|
+
All Recursica components in the `@recursica/adapter-mantine-v8` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
38
|
+
|
|
39
|
+
> [!IMPORTANT]
|
|
40
|
+
>
|
|
41
|
+
> - **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.
|
|
42
|
+
> - **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.
|
|
43
|
+
> - **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.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 4. Key Integration Features & Constraints
|
|
48
|
+
|
|
49
|
+
### Composition Patterns
|
|
50
|
+
|
|
51
|
+
`Accordion.Item` supports two ways of providing content: pass `title` (and optionally `leftIcon`) directly on `Accordion.Item` for a simple control/panel pair, with `children` treated as the panel content; or omit `title` and compose manually with `Accordion.Control` and `Accordion.Panel` for full control over the control's contents.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Accordion";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# AssistiveElement – implementation notes
|
|
2
|
+
|
|
3
|
+
Decisions and design tweaks specific to the UI Kit's AssistiveElement wrapped against
|
|
4
|
+
`@mantine/core`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Plain `<div>` — no underlying component wrapped
|
|
9
|
+
|
|
10
|
+
**Decision:** Unlike most components in this adapter, `AssistiveElement` doesn't wrap any real
|
|
11
|
+
`@mantine/core` component at all — it's a bare `<div>` with two `<span>` wrappers (icon, text).
|
|
12
|
+
Mantine has no dedicated helper/error-text component to wrap in the first place (it composes
|
|
13
|
+
that presentation ad hoc per-field via `TextInput`'s own `error`/`description` props instead of
|
|
14
|
+
a standalone component), so there's nothing here to inherit layout or ARIA semantics from.
|
|
15
|
+
**Implementation:** A `<div>` is a reasonable generic container, but it carries no semantic
|
|
16
|
+
meaning of its own. `role="alert"` is now defaulted automatically for the `"error"` variant
|
|
17
|
+
(see §3) — the one piece of ARIA behavior that genuinely belongs at this component's own level.
|
|
18
|
+
`aria-describedby`/`aria-errormessage` association with a field is a different story: this
|
|
19
|
+
component has no reference to any sibling field, so it can't wire that itself. It's already
|
|
20
|
+
handled one layer up, in `FormControlWrapper` — which generates the ids, passes them down via
|
|
21
|
+
this component's own `id` prop, and clones `aria-describedby`/`aria-errormessage` onto the
|
|
22
|
+
field. Only a fully standalone `<AssistiveElement>` used outside `FormControlWrapper` still
|
|
23
|
+
needs that wiring done by hand, via the standard HTML attributes that pass through `{...rest}`.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. Fixed icon per variant, no custom icon slot
|
|
28
|
+
|
|
29
|
+
**Decision:** `assistiveWithIcon` only toggles visibility — there's no prop to swap in a custom
|
|
30
|
+
icon. The icon is always the one belonging to the current `assistiveVariant` (`InfoIcon` for
|
|
31
|
+
`"help"`, `AlertIcon` for `"error"`).
|
|
32
|
+
**Implementation:** `IconComponent = assistiveVariant === "error" ? AlertIcon : InfoIcon` is
|
|
33
|
+
resolved directly in the render body; there's no icon prop in `RecursicaAssistiveElementProps`
|
|
34
|
+
to intercept.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 3. `role="alert"` defaults on for the error variant
|
|
39
|
+
|
|
40
|
+
**Decision:** Error text needs to be announced by assistive tech as it appears or changes;
|
|
41
|
+
static help text doesn't. Rather than requiring every integrator to remember `role="alert"`,
|
|
42
|
+
`assistiveVariant="error"` defaults it automatically.
|
|
43
|
+
**Implementation:** `role` is destructured out and resolved as `role ?? (assistiveVariant ===
|
|
44
|
+
"error" ? "alert" : undefined)` before the spread — an explicit caller-supplied `role` always
|
|
45
|
+
wins over the default, and `"help"` gets no default at all.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AssistiveElement.module.css
|
|
3
|
+
*
|
|
4
|
+
* HARDCODED VALUES:
|
|
5
|
+
* - margin / padding: 0 — Structural resets.
|
|
6
|
+
* - display: flex / align-items: flex-start — layout alignment.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
.root {
|
|
10
|
+
display: flex !important;
|
|
11
|
+
align-items: flex-start !important; /* Forces the icon to align with the first line of text */
|
|
12
|
+
margin: 0 !important; /* HARDCODE: structural reset */
|
|
13
|
+
padding: 0 !important; /* HARDCODE: structural reset */
|
|
14
|
+
|
|
15
|
+
gap: var(
|
|
16
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-text-gap
|
|
17
|
+
);
|
|
18
|
+
margin-top: var(
|
|
19
|
+
--recursica_ui-kit_components_assistive-element_properties_top-margin
|
|
20
|
+
) !important;
|
|
21
|
+
max-width: var(
|
|
22
|
+
--recursica_ui-kit_components_assistive-element_properties_max-width
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.textWrapper {
|
|
27
|
+
/* Text properties securely governed via layout mappings */
|
|
28
|
+
font-family: var(
|
|
29
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-family
|
|
30
|
+
);
|
|
31
|
+
font-size: var(
|
|
32
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-size
|
|
33
|
+
);
|
|
34
|
+
font-style: var(
|
|
35
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-style
|
|
36
|
+
);
|
|
37
|
+
font-weight: var(
|
|
38
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-weight
|
|
39
|
+
);
|
|
40
|
+
letter-spacing: var(
|
|
41
|
+
--recursica_ui-kit_components_assistive-element_properties_text_letter-spacing
|
|
42
|
+
);
|
|
43
|
+
line-height: var(
|
|
44
|
+
--recursica_ui-kit_components_assistive-element_properties_text_line-height
|
|
45
|
+
);
|
|
46
|
+
text-decoration: var(
|
|
47
|
+
--recursica_ui-kit_components_assistive-element_properties_text_text-decoration
|
|
48
|
+
);
|
|
49
|
+
text-transform: var(
|
|
50
|
+
--recursica_ui-kit_components_assistive-element_properties_text_text-transform
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/* Fallback text wrap structures */
|
|
54
|
+
overflow-wrap: break-word;
|
|
55
|
+
white-space: normal;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.iconWrapper {
|
|
59
|
+
flex-shrink: 0 !important; /* Prevent squishing */
|
|
60
|
+
display: flex !important;
|
|
61
|
+
align-items: center !important;
|
|
62
|
+
justify-content: center !important;
|
|
63
|
+
|
|
64
|
+
width: var(
|
|
65
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
66
|
+
) !important;
|
|
67
|
+
height: calc(
|
|
68
|
+
var(
|
|
69
|
+
--recursica_ui-kit_components_assistive-element_properties_text_line-height
|
|
70
|
+
) *
|
|
71
|
+
var(
|
|
72
|
+
--recursica_ui-kit_components_assistive-element_properties_text_font-size
|
|
73
|
+
)
|
|
74
|
+
) !important; /* Forces exact centering bounds within the first text line vertically */
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.iconWrapper svg {
|
|
78
|
+
width: var(
|
|
79
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
80
|
+
) !important;
|
|
81
|
+
height: var(
|
|
82
|
+
--recursica_ui-kit_components_assistive-element_properties_icon-size
|
|
83
|
+
) !important;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* VARIANT MAPPINGS
|
|
88
|
+
* Inherits colors natively mapped per variant.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
.root[data-variant="help"] .textWrapper {
|
|
92
|
+
color: var(
|
|
93
|
+
--recursica_ui-kit_components_assistive-element_variants_types_help_properties_colors_text-color
|
|
94
|
+
) !important;
|
|
95
|
+
}
|
|
96
|
+
.root[data-variant="help"] .iconWrapper svg {
|
|
97
|
+
color: var(
|
|
98
|
+
--recursica_ui-kit_components_assistive-element_variants_types_help_properties_colors_icon-color
|
|
99
|
+
) !important;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.root[data-variant="error"] .textWrapper {
|
|
103
|
+
color: var(
|
|
104
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_text-color
|
|
105
|
+
) !important;
|
|
106
|
+
}
|
|
107
|
+
.root[data-variant="error"] .iconWrapper svg {
|
|
108
|
+
color: var(
|
|
109
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_icon-color
|
|
110
|
+
) !important;
|
|
111
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { AssistiveElement } from "./AssistiveElement";
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof AssistiveElement> = {
|
|
5
|
+
title: "UI-Kit/AssistiveElement",
|
|
6
|
+
component: AssistiveElement,
|
|
7
|
+
tags: ["autodocs"],
|
|
8
|
+
parameters: {
|
|
9
|
+
docs: {
|
|
10
|
+
description: {
|
|
11
|
+
component:
|
|
12
|
+
"The `AssistiveElement` is a semantic structural primitive designed to standardize Helper and Error descriptive blocks natively beneath form components globally. By explicitly wiring to the `--recursica_ui-kit_components_assistive-element` layout tokens, this component safely injects custom SVGs (Alerts vs Info circles) alongside constrained flex-wrapping typography strings, preserving flawless line-height and alignment logic entirely decoupled from underlying input engine frameworks.",
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
argTypes: {
|
|
17
|
+
assistiveVariant: {
|
|
18
|
+
control: "radio",
|
|
19
|
+
options: ["help", "error"],
|
|
20
|
+
},
|
|
21
|
+
assistiveWithIcon: {
|
|
22
|
+
control: "boolean",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default meta;
|
|
28
|
+
|
|
29
|
+
type Story = StoryObj<typeof AssistiveElement>;
|
|
30
|
+
|
|
31
|
+
export const DefaultHelp: Story = {
|
|
32
|
+
args: {
|
|
33
|
+
children:
|
|
34
|
+
"This is a standard assistive layout explaining specific configurations.",
|
|
35
|
+
assistiveVariant: "help",
|
|
36
|
+
assistiveWithIcon: true,
|
|
37
|
+
},
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
39
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
40
|
+
<AssistiveElement {...args} />
|
|
41
|
+
),
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const ErrorState: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
children:
|
|
47
|
+
"Invalid property. You must satisfy the constraints outlined above.",
|
|
48
|
+
assistiveVariant: "error",
|
|
49
|
+
assistiveWithIcon: true,
|
|
50
|
+
},
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
52
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
53
|
+
<AssistiveElement {...args} />
|
|
54
|
+
),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const NoIconHelp: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
children:
|
|
60
|
+
"Fallback textual representation without visual injection targets.",
|
|
61
|
+
assistiveVariant: "help",
|
|
62
|
+
assistiveWithIcon: false,
|
|
63
|
+
},
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
65
|
+
render: ({ withLayer, layer, ...args }: any) => (
|
|
66
|
+
<AssistiveElement {...args} />
|
|
67
|
+
),
|
|
68
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future AssistiveElement component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
filterStylingProps,
|
|
4
|
+
type RecursicaOverStyled,
|
|
5
|
+
} from "../../utils/filterStylingProps";
|
|
6
|
+
import styles from "./AssistiveElement.module.css";
|
|
7
|
+
|
|
8
|
+
import { type RecursicaAssistiveElementProps } from "@recursica/adapter-common";
|
|
9
|
+
|
|
10
|
+
export type AssistiveElementProps = RecursicaOverStyled<
|
|
11
|
+
React.HTMLAttributes<HTMLDivElement> & RecursicaAssistiveElementProps
|
|
12
|
+
>;
|
|
13
|
+
|
|
14
|
+
const InfoIcon = () => (
|
|
15
|
+
<svg
|
|
16
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
17
|
+
viewBox="0 0 24 24"
|
|
18
|
+
fill="none"
|
|
19
|
+
stroke="currentColor"
|
|
20
|
+
strokeWidth="2"
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
|
+
>
|
|
24
|
+
<circle cx="12" cy="12" r="10" />
|
|
25
|
+
<path d="M12 16v-4" />
|
|
26
|
+
<path d="M12 8h.01" />
|
|
27
|
+
</svg>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const AlertIcon = () => (
|
|
31
|
+
<svg
|
|
32
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
33
|
+
viewBox="0 0 24 24"
|
|
34
|
+
fill="none"
|
|
35
|
+
stroke="currentColor"
|
|
36
|
+
strokeWidth="2"
|
|
37
|
+
strokeLinecap="round"
|
|
38
|
+
strokeLinejoin="round"
|
|
39
|
+
>
|
|
40
|
+
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" />
|
|
41
|
+
<path d="M12 9v4" />
|
|
42
|
+
<path d="M12 17h.01" />
|
|
43
|
+
</svg>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
export const AssistiveElement = forwardRef<
|
|
47
|
+
HTMLDivElement,
|
|
48
|
+
AssistiveElementProps
|
|
49
|
+
>(function AssistiveElement(
|
|
50
|
+
{
|
|
51
|
+
assistiveVariant = "help",
|
|
52
|
+
assistiveWithIcon = true,
|
|
53
|
+
children,
|
|
54
|
+
className,
|
|
55
|
+
role,
|
|
56
|
+
overStyled = false,
|
|
57
|
+
...rest
|
|
58
|
+
},
|
|
59
|
+
ref,
|
|
60
|
+
) {
|
|
61
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
62
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
63
|
+
|
|
64
|
+
const rootClass = styles.root;
|
|
65
|
+
const finalClass = className ? `${rootClass} ${className}` : rootClass;
|
|
66
|
+
|
|
67
|
+
const IconComponent = assistiveVariant === "error" ? AlertIcon : InfoIcon;
|
|
68
|
+
|
|
69
|
+
// Announce error text as it appears/changes; a caller-supplied `role` always wins. No
|
|
70
|
+
// default for `help` — static descriptive text doesn't need a live region.
|
|
71
|
+
const resolvedRole =
|
|
72
|
+
role ?? (assistiveVariant === "error" ? "alert" : undefined);
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
ref={ref}
|
|
77
|
+
{...restRecord} // Spread standard HTML attributes (like id, aria-*) natively.
|
|
78
|
+
className={finalClass}
|
|
79
|
+
data-variant={assistiveVariant}
|
|
80
|
+
role={resolvedRole}
|
|
81
|
+
style={restRecord.style as React.CSSProperties}
|
|
82
|
+
>
|
|
83
|
+
{assistiveWithIcon && (
|
|
84
|
+
<span className={styles.iconWrapper}>
|
|
85
|
+
<IconComponent />
|
|
86
|
+
</span>
|
|
87
|
+
)}
|
|
88
|
+
<span className={styles.textWrapper}>{children}</span>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
AssistiveElement.displayName = "AssistiveElement";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# AssistiveElement - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `AssistiveElement` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { AssistiveElement } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { AssistiveElement } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <AssistiveElement state="error" message="This field is required" />;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 3. Design System Integration
|
|
29
|
+
|
|
30
|
+
All Recursica components in the `@recursica/adapter-mantine-v8` 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.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# AutoComplete Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Form Control Wrapping
|
|
4
|
+
|
|
5
|
+
The `AutoComplete` component is wrapped using the `WithReadOnlyWrapper` to seamlessly bridge standard `InputWrapperProps` attributes (like `label`, `error`, `assistiveText`) directly onto the macro Recursica `<FormControlWrapper>`.
|
|
6
|
+
|
|
7
|
+
## CSS Layout Execution
|
|
8
|
+
|
|
9
|
+
The baseline structure maps identical `HARDCODED VALUES` as standard text inputs (`border-width: 1px`, `display: flex`). The `.root` dynamically overrides the `--input-left-section-size` and `--input-right-section-size` to accurately allocate whitespace for prepended or appended icons natively matching the underlying UI token layout system securely.
|
|
10
|
+
|
|
11
|
+
## Dropdown Styling
|
|
12
|
+
|
|
13
|
+
The Mantine `<Autocomplete>` dropdown menu and options are styled strictly using native UI-Kit variables mapping border radii, shadows, and base colors (`.dropdown` and `.option`).
|
|
14
|
+
|
|
15
|
+
## State Cascade Architecture
|
|
16
|
+
|
|
17
|
+
Focus, errors, and disabled visual states are enforced explicitly via the outer `<FormControlWrapper>` boundary emitting context down structurally (`[data-error]`, `[data-disabled]`) and evaluated efficiently against scoped nested selectors natively inside `AutoComplete.module.css`.
|
|
18
|
+
|
|
19
|
+
## Missing Selected Option Highlight
|
|
20
|
+
|
|
21
|
+
`.option:hover`/`.option[data-hovered="true"]` work — hover has a real background tint. There's no
|
|
22
|
+
equivalent for "this option matches the current value" though, and it isn't fixable in CSS alone:
|
|
23
|
+
Mantine's `Autocomplete` never passes a `value` prop into its internal `OptionsDropdown` (only
|
|
24
|
+
`search`, for filtering — see `node_modules/@mantine/core/esm/components/Autocomplete/Autocomplete.mjs`),
|
|
25
|
+
so `OptionsDropdown`'s `checked` (and the `data-combobox-active` attribute it drives — the same one
|
|
26
|
+
`Dropdown`'s equivalent highlight below keys off) never gets set on any option, no matter what's
|
|
27
|
+
typed into the field. See `Dropdown.module.css`'s `.option[data-combobox-active="true"]` rule for
|
|
28
|
+
what a real fix would key off, if this ever gets solved upstream or by reimplementing option
|
|
29
|
+
rendering with our own value comparison.
|
|
30
|
+
|
|
31
|
+
## Rich Option Content (`leadingIcon`/`supportingText`)
|
|
32
|
+
|
|
33
|
+
`data` items accept optional `leadingIcon`/`supportingText` fields, via the shared `RecursicaComboboxItem` type in `@recursica/adapter-common` (see `MANTINE_ADAPTER_RICH_OPTION_DATA.md` at the repo root) — the same type `Dropdown` and both `mui-adapter` components use. `AutoComplete.tsx` installs a default `renderOption` (`../../utils/renderRichOption.tsx`, shared with `Dropdown`) that reads these off Mantine's parsed `option`. `label` on the shared type is optional — Mantine's `getParsedComboboxData` only preserves an item's extra fields when it already has both `value` and `label`; an item with `value` only is rebuilt into a bare `{value, label: value, disabled}` object first, dropping `leadingIcon`/`supportingText`. `AutoComplete.tsx` runs `data` through adapter-common's `normalizeComboboxData` (backfills `label` from `value`) before handing it to Mantine, so the rich fields always survive regardless of whether the caller set `label` (`Dropdown.tsx` does the same now that its `label` is optional too). New CSS classes (`.optionContent`/`.optionIcon`/`.optionText`/`.optionSupportingText`) reuse the menu-item component's icon/supporting-text tokens, matching Dropdown's equivalent addition — no dedicated autocomplete-option tokens exist for either. The icon is a conditional child (only rendered when `leadingIcon` is set, not a hidden reserved slot), so label/supportingText shift left when there's no icon; `.optionContent`'s `align-items: center` keeps the label vertically centered when there's no `supportingText`.
|
|
34
|
+
|
|
35
|
+
## `wrapItemText`
|
|
36
|
+
|
|
37
|
+
`label`/`supportingText` default to single-line truncation with an ellipsis (`.optionText > *` — `overflow: clip; overflow-clip-margin: 0.35em; text-overflow: ellipsis; white-space: nowrap`). Passing `wrapItemText` adds `.optionTextWrap` alongside `.optionText`, which re-enables wrapping (`white-space: normal; overflow-wrap: anywhere`) for both children — same later-cascade-wins mechanism (`.optionTextWrap > *` declared after `.optionText > *`, equal specificity) as the rest of this file's overrides. `renderRichOption`/`renderRichOptionContent` (shared util, both adapters) take `wrapItemText` as a third parameter and combine the two class names when it's true.
|
|
38
|
+
|
|
39
|
+
`.optionText > *` used plain `overflow: hidden` until 2026-08-28 (Matt Massey) — it clipped
|
|
40
|
+
descenders (e.g. "g") whenever `text_line-height` is tighter than the font's natural
|
|
41
|
+
ascent+descent. `overflow-clip-margin` gives ink a small bleed allowance while still clipping
|
|
42
|
+
genuinely overflowing text; same project-wide fix as Chip's `CHIP_IMPLEMENTATION_NOTES.md`.
|