@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,113 @@
|
|
|
1
|
+
import React, { forwardRef } from "react";
|
|
2
|
+
import { Input, type InputLabelProps } from "@mantine/core";
|
|
3
|
+
import {
|
|
4
|
+
filterStylingProps,
|
|
5
|
+
omitUnsupportedProps,
|
|
6
|
+
mergeClassNames,
|
|
7
|
+
type RecursicaOverStyled,
|
|
8
|
+
} from "../../utils/filterStylingProps";
|
|
9
|
+
import styles from "./Label.module.css";
|
|
10
|
+
|
|
11
|
+
import { type RecursicaLabelProps } from "@recursica/adapter-common";
|
|
12
|
+
|
|
13
|
+
export type LabelProps = RecursicaOverStyled<
|
|
14
|
+
Omit<InputLabelProps, "size"> & RecursicaLabelProps
|
|
15
|
+
>;
|
|
16
|
+
|
|
17
|
+
export const Label = forwardRef<HTMLLabelElement, LabelProps>(function Label(
|
|
18
|
+
{
|
|
19
|
+
labelSize = "default",
|
|
20
|
+
labelAlignment,
|
|
21
|
+
required = false,
|
|
22
|
+
labelOptionalText,
|
|
23
|
+
labelWithEditIcon,
|
|
24
|
+
labelActionArea,
|
|
25
|
+
onLabelEditClick,
|
|
26
|
+
children,
|
|
27
|
+
overStyled = false,
|
|
28
|
+
...rest
|
|
29
|
+
},
|
|
30
|
+
ref,
|
|
31
|
+
) {
|
|
32
|
+
const resolvedAlignment = labelAlignment || "left";
|
|
33
|
+
|
|
34
|
+
let resolvedOptionalText: React.ReactNode | undefined;
|
|
35
|
+
if (!required) {
|
|
36
|
+
if (labelOptionalText === true) resolvedOptionalText = "optional";
|
|
37
|
+
else if (labelOptionalText) resolvedOptionalText = labelOptionalText;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Props this component intentionally doesn't support — deleted at runtime so they can't leak
|
|
41
|
+
// through even if a caller forces them via plain JavaScript, bypassing the `Omit<>` above.
|
|
42
|
+
const UNSUPPORTED_PROPS = [
|
|
43
|
+
"size", // Recursica controls label sizing via `labelSize` + design tokens, not Mantine's native `size`.
|
|
44
|
+
] as const satisfies readonly (keyof InputLabelProps)[];
|
|
45
|
+
|
|
46
|
+
const sanitizedProps = omitUnsupportedProps(
|
|
47
|
+
filterStylingProps(rest, overStyled),
|
|
48
|
+
UNSUPPORTED_PROPS,
|
|
49
|
+
);
|
|
50
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
51
|
+
|
|
52
|
+
const mergedClassNames = mergeClassNames(
|
|
53
|
+
{
|
|
54
|
+
label: styles.root,
|
|
55
|
+
required: styles.required,
|
|
56
|
+
},
|
|
57
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
61
|
+
const finalClass = classNameProp
|
|
62
|
+
? `${styles.root} ${classNameProp}`
|
|
63
|
+
: styles.root;
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<Input.Label
|
|
67
|
+
ref={ref}
|
|
68
|
+
{...sanitizedProps}
|
|
69
|
+
className={finalClass}
|
|
70
|
+
classNames={mergedClassNames}
|
|
71
|
+
data-size={labelSize}
|
|
72
|
+
data-alignment={resolvedAlignment}
|
|
73
|
+
required={required && !labelWithEditIcon}
|
|
74
|
+
>
|
|
75
|
+
<span className={styles.labelText}>{children}</span>
|
|
76
|
+
{resolvedOptionalText && (
|
|
77
|
+
<span className={styles.optionalText}>
|
|
78
|
+
{typeof resolvedOptionalText === "string"
|
|
79
|
+
? `(${resolvedOptionalText})`
|
|
80
|
+
: resolvedOptionalText}
|
|
81
|
+
</span>
|
|
82
|
+
)}
|
|
83
|
+
{labelActionArea ? (
|
|
84
|
+
<span className={styles.actionAreaWrapper}>{labelActionArea}</span>
|
|
85
|
+
) : labelWithEditIcon ? (
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
className={styles.editIconWrapper}
|
|
89
|
+
data-replaces-asterisk={required ? "true" : undefined}
|
|
90
|
+
onClick={onLabelEditClick}
|
|
91
|
+
aria-label="Edit"
|
|
92
|
+
>
|
|
93
|
+
<svg
|
|
94
|
+
width="16"
|
|
95
|
+
height="16"
|
|
96
|
+
viewBox="0 0 16 16"
|
|
97
|
+
fill="none"
|
|
98
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
99
|
+
>
|
|
100
|
+
<path
|
|
101
|
+
d="M11.5303 2.46967C11.8232 2.17678 12.2981 2.17678 12.591 2.46967L13.5303 3.40898C13.8232 3.70188 13.8232 4.17675 13.5303 4.46964L5.61288 12.3871C5.45268 12.5473 5.24434 12.6483 5.01809 12.6766L2.39534 13.0044C2.10091 13.0412 1.83856 12.7789 1.87538 12.4845L2.2032 9.86175C2.23147 9.63551 2.3325 9.42716 2.4927 9.26696L11.5303 2.46967Z"
|
|
102
|
+
stroke="currentColor"
|
|
103
|
+
strokeLinecap="round"
|
|
104
|
+
strokeLinejoin="round"
|
|
105
|
+
/>
|
|
106
|
+
</svg>
|
|
107
|
+
</button>
|
|
108
|
+
) : null}
|
|
109
|
+
</Input.Label>
|
|
110
|
+
);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
Label.displayName = "Label";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Label - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Label` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Label } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Label } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return <Label required>Field Label</Label>;
|
|
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.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 4. Behavior Notes
|
|
41
|
+
|
|
42
|
+
- A label cannot be both required and optional: if `required` is `true`, `optionalText` is not rendered.
|
|
43
|
+
- Set `optionalText` to `true` to render the default "(Optional)" text, or pass a custom string for different wording.
|
|
44
|
+
- `withEditIcon` and `required` are mutually exclusive: when both are set, the edit icon is shown in place of the required asterisk.
|
|
45
|
+
- `labelSize` only affects layout when the surrounding form uses `formLayout="side-by-side"`, where it constrains the label's width.
|
|
46
|
+
- `Label` does not currently support a `description` prop.
|
|
47
|
+
- The edit icon does not currently have a distinct hover background.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Label";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Layer - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Layer` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
> [!NOTE] > `Layer` is defined once in `@recursica/adapter-common` and re-exported here so it shares the exact same behavior across every Recursica adapter.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. Import Reference
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Layer } from "@recursica/adapter-mantine-v8";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. Basic Example
|
|
18
|
+
|
|
19
|
+
`Layer` sets `data-recursica-layer` on its root element, which is what makes the theme+layer scoped CSS variables (surface color, border, elevation, padding) in `recursica_variables_scoped.css` actually apply. [`RecursicaThemeProvider`](../RecursicaThemeProvider/USAGE.md) automatically wraps your app in a `layer={0}` `Layer` by default (via its `initLayer0` prop), so you don't need to add one yourself for the base page. You still add `Layer`s manually for anything visually elevated above the page background:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
import {
|
|
23
|
+
RecursicaThemeProvider,
|
|
24
|
+
Layer,
|
|
25
|
+
Card,
|
|
26
|
+
} from "@recursica/adapter-mantine-v8";
|
|
27
|
+
|
|
28
|
+
function App() {
|
|
29
|
+
return (
|
|
30
|
+
<RecursicaThemeProvider theme="light">
|
|
31
|
+
{/* Page background/surface already uses layer 0, applied automatically */}
|
|
32
|
+
<Layer layer={1}>
|
|
33
|
+
<Card>Elevated content sits on layer 1</Card>
|
|
34
|
+
</Layer>
|
|
35
|
+
</RecursicaThemeProvider>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 3. Design System Integration
|
|
43
|
+
|
|
44
|
+
> [!IMPORTANT]
|
|
45
|
+
>
|
|
46
|
+
> - **Layer 0 is automatic**: `RecursicaThemeProvider` applies it for you by default. Only opt out (`initLayer0={false}`) if you need to control exactly where layer 0 starts in the tree, or need `contentsOnly` on the base layer — see [RecursicaThemeProvider usage](../RecursicaThemeProvider/USAGE.md).
|
|
47
|
+
> - **Layers 1–3 are manual**: Wrap any content that's visually elevated above the page background (a Card, Modal, Popover, etc.) in its own `<Layer layer={1|2|3}>`. Nesting `Layer`s is how Recursica communicates elevation to descendant components — do **not** pass a `layer` prop directly to other components; wrap them in a `Layer` instead (every other component's `USAGE.md` repeats this rule).
|
|
48
|
+
> - **`contentsOnly`**: When `true`, `Layer` renders with `display: contents` and omits `data-recursica-layer` entirely — use this when you need a layer boundary in your component tree without adding an extra DOM box or applying layer styling (e.g. a purely structural wrapper).
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 4. Key Integration Features & Constraints
|
|
53
|
+
|
|
54
|
+
`Layer` has no visual variants of its own — its entire purpose is to bind a subtree to a numbered layer's design tokens. It does not accept `overStyled`; instead, if you find yourself needing to override a layer's surface styling, that's a signal you may want a different layer number rather than an escape hatch.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Link Component Implementation Notes
|
|
2
|
+
|
|
3
|
+
## States in Design Tokens
|
|
4
|
+
|
|
5
|
+
The design tokens (`recursica_variables_scoped.css`) provide the base link styling directly on `--recursica_ui-kit_components_link_properties_*` (no distinct `default` state), plus a `visited` variant that overrides only `colors_text-color`/`colors_icon-color`. Hover is not a per-component `link_variants_states_hover_*` token; it's driven by the brand-level `--recursica_brand_states_link_decoration` token (resolves to `underline`), applied on `.root:hover`. Earlier this token was exported as an invalid quoted string (`"underline"`), which silently failed and was mistaken for the token not existing at all — now fixed upstream to a bare keyword. There is no token for `active`. There isn't a per-component `focus` token either, but focus isn't left to the browser default: like every other interactive component (see Button), `.root:focus-visible` replaces the native outline with the global `--recursica_brand_states_focus_*` ring. This was previously missing here — Link (and anything composing it, e.g. Breadcrumb) fell back to the browser's native focus outline instead.
|
|
6
|
+
|
|
7
|
+
## Overriding Mantine's underline Prop
|
|
8
|
+
|
|
9
|
+
Mantine's `Anchor` component uses `underline="hover"` by default. Because our design system specifies exact `text-decoration` styles via CSS tokens, we explicitly pass `underline="never"` to the underlying Mantine component. This prevents Mantine from injecting its own text-decoration inline or via generic classnames, ensuring our scoped CSS remains the single source of truth.
|
|
10
|
+
|
|
11
|
+
## Base Layout
|
|
12
|
+
|
|
13
|
+
Mantine's `Anchor` renders an inline element by default and does not natively support `leftSection` like the `Button` component. To support an optional `icon` alongside the text, we enforce a baseline layout of `display: inline-flex` and `align-items: center` in `Link.module.css`.
|
|
14
|
+
|
|
15
|
+
When an icon is present, the component conditionally passes a `data-has-icon` attribute to the root element. The CSS module uses this attribute to apply the `icon-text-gap` token via the CSS `gap` property.
|
|
16
|
+
|
|
17
|
+
## Inner Wrappers
|
|
18
|
+
|
|
19
|
+
The icon and children are wrapped in internal `<span>` tags (`.iconWrapper` and `.labelText` respectively). This follows the component development guide for structural robustness, allowing us to enforce specific sizing on the icon and intrinsic text truncation behavior if the link is placed in a bounded container.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/* Brand-layer exemptions (recursica-allow-brand) — see recursica-token-analyzer README.md.
|
|
2
|
+
* Only source for link hover-underline; no per-component token exists (see IMPLEMENTATION_NOTES.md).
|
|
3
|
+
* recursica-allow-brand: --recursica_brand_states_link_decoration
|
|
4
|
+
* Global focus-ring tokens (recursica_variables_scoped.css header, 'Hover & Focus states' —
|
|
5
|
+
* implicit rule for every interactive element; components must not define their own per-component
|
|
6
|
+
* treatment). Same pattern as Button.module.css.
|
|
7
|
+
* recursica-allow-brand: --recursica_brand_states_focus_blur
|
|
8
|
+
* recursica-allow-brand: --recursica_brand_states_focus_border-size
|
|
9
|
+
* recursica-allow-brand: --recursica_brand_states_focus_color
|
|
10
|
+
* recursica-allow-brand: --recursica_brand_states_focus_margin
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/* EXEMPTIONS:
|
|
14
|
+
- text_text-transform is ignored because links naturally inherit casing directly from text
|
|
15
|
+
children rather than requiring custom CSS transforms. */
|
|
16
|
+
/* recursica-ignore: --recursica_ui-kit_components_link_properties_text_text-transform */
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
HARDCODED VALUES:
|
|
20
|
+
- display: inline-flex; (Base layout to align icon and text correctly)
|
|
21
|
+
- align-items: center;
|
|
22
|
+
- cursor: pointer;
|
|
23
|
+
- text-decoration: none; (Overridden by our design tokens instead of using Mantine's underline prop)
|
|
24
|
+
- color: inherit; (Reset before applying token)
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
.root {
|
|
28
|
+
/* HARDCODE: base layout */
|
|
29
|
+
display: inline;
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
|
|
32
|
+
/* HARDCODE: Reset underline and color so we can explicitly use our tokens */
|
|
33
|
+
text-decoration: none;
|
|
34
|
+
color: inherit;
|
|
35
|
+
|
|
36
|
+
/* Typography Tokens */
|
|
37
|
+
font-family: var(
|
|
38
|
+
--recursica_ui-kit_components_link_properties_text_font-family
|
|
39
|
+
);
|
|
40
|
+
font-size: var(--recursica_ui-kit_components_link_properties_text_font-size);
|
|
41
|
+
font-style: var(
|
|
42
|
+
--recursica_ui-kit_components_link_properties_text_font-style
|
|
43
|
+
);
|
|
44
|
+
font-weight: var(
|
|
45
|
+
--recursica_ui-kit_components_link_properties_text_font-weight
|
|
46
|
+
);
|
|
47
|
+
letter-spacing: var(
|
|
48
|
+
--recursica_ui-kit_components_link_properties_text_letter-spacing
|
|
49
|
+
);
|
|
50
|
+
line-height: var(
|
|
51
|
+
--recursica_ui-kit_components_link_properties_text_line-height
|
|
52
|
+
);
|
|
53
|
+
text-decoration: var(
|
|
54
|
+
--recursica_ui-kit_components_link_properties_text_text-decoration
|
|
55
|
+
);
|
|
56
|
+
color: var(--recursica_ui-kit_components_link_properties_colors_text-color);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.root[data-has-icon] {
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
align-items: center;
|
|
62
|
+
gap: var(--recursica_ui-kit_components_link_properties_icon-text-gap);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.root:visited {
|
|
66
|
+
color: var(
|
|
67
|
+
--recursica_ui-kit_components_link_variants_states_visited_properties_colors_text-color
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.root:hover {
|
|
72
|
+
text-decoration: var(--recursica_brand_states_link_decoration);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Focus State Mapping (native browser focus outline replaced with the recursica focus ring).
|
|
76
|
+
Was previously unset here, so Link (and anything using it, e.g. Breadcrumb) fell back to the
|
|
77
|
+
browser's native focus outline instead of the recursica ring. */
|
|
78
|
+
.root:focus-visible {
|
|
79
|
+
outline: none;
|
|
80
|
+
box-shadow:
|
|
81
|
+
0 0 0 var(--recursica_brand_states_focus_border-size)
|
|
82
|
+
var(--recursica_brand_states_focus_color),
|
|
83
|
+
0 0 var(--recursica_brand_states_focus_blur)
|
|
84
|
+
var(--recursica_brand_states_focus_margin)
|
|
85
|
+
var(--recursica_brand_states_focus_color);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Icon Support */
|
|
89
|
+
.iconWrapper {
|
|
90
|
+
/* HARDCODE: maintain intrinsic icon bounds */
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
|
|
95
|
+
width: var(--recursica_ui-kit_components_link_properties_icon-size);
|
|
96
|
+
height: var(--recursica_ui-kit_components_link_properties_icon-size);
|
|
97
|
+
color: var(--recursica_ui-kit_components_link_properties_colors_icon-color);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.root:visited .iconWrapper {
|
|
101
|
+
color: var(
|
|
102
|
+
--recursica_ui-kit_components_link_variants_states_visited_properties_colors_icon-color
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Label text wrapper */
|
|
107
|
+
.labelText {
|
|
108
|
+
/* HARDCODE: allows text truncation if bounded */
|
|
109
|
+
min-width: 0;
|
|
110
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
3
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
4
|
+
import { Link } from "./Link";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Link> = {
|
|
7
|
+
title: "UI-Kit/Link",
|
|
8
|
+
component: Link,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
args: {
|
|
11
|
+
children: "Link text",
|
|
12
|
+
href: "#",
|
|
13
|
+
},
|
|
14
|
+
render: ({ withLayer, layer, ...args }: any) => <Link {...args} />,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default meta;
|
|
18
|
+
|
|
19
|
+
type Story = StoryObj<typeof Link>;
|
|
20
|
+
|
|
21
|
+
export const Default: Story = {};
|
|
22
|
+
|
|
23
|
+
export const WithIcon: Story = {
|
|
24
|
+
args: {
|
|
25
|
+
icon: (
|
|
26
|
+
<svg
|
|
27
|
+
width="24"
|
|
28
|
+
height="24"
|
|
29
|
+
viewBox="0 0 24 24"
|
|
30
|
+
fill="none"
|
|
31
|
+
stroke="currentColor"
|
|
32
|
+
strokeWidth="2"
|
|
33
|
+
strokeLinecap="round"
|
|
34
|
+
strokeLinejoin="round"
|
|
35
|
+
>
|
|
36
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
|
|
37
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
|
|
38
|
+
</svg>
|
|
39
|
+
),
|
|
40
|
+
children: "Link with Icon",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const Polymorphic: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
component: "button",
|
|
47
|
+
onClick: () => alert("Button clicked!"),
|
|
48
|
+
children: "Rendered as <button>",
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const InlineText: Story = {
|
|
53
|
+
render: () => (
|
|
54
|
+
<p>
|
|
55
|
+
Here is some text with an <Link href="#">inline link</Link> inside it.
|
|
56
|
+
</p>
|
|
57
|
+
),
|
|
58
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Link component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Anchor as MantineAnchor,
|
|
4
|
+
type AnchorProps as MantineAnchorProps,
|
|
5
|
+
createPolymorphicComponent,
|
|
6
|
+
} from "@mantine/core";
|
|
7
|
+
import {
|
|
8
|
+
filterStylingProps,
|
|
9
|
+
mergeClassNames,
|
|
10
|
+
type RecursicaOverStyled,
|
|
11
|
+
} from "../../utils/filterStylingProps";
|
|
12
|
+
import styles from "./Link.module.css";
|
|
13
|
+
|
|
14
|
+
import { type RecursicaLinkProps } from "@recursica/adapter-common";
|
|
15
|
+
|
|
16
|
+
export type LinkProps = RecursicaOverStyled<
|
|
17
|
+
Omit<MantineAnchorProps, "underline"> & Omit<RecursicaLinkProps, "component">
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
const _Link = forwardRef<HTMLAnchorElement, LinkProps>(function Link(
|
|
21
|
+
{ icon, children, overStyled = false, ...rest },
|
|
22
|
+
ref,
|
|
23
|
+
) {
|
|
24
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
25
|
+
const restRecord = sanitizedProps as Record<string, unknown>;
|
|
26
|
+
|
|
27
|
+
const mergedClassNames = mergeClassNames(
|
|
28
|
+
{ root: styles.root },
|
|
29
|
+
restRecord.classNames as Partial<Record<string, string>> | undefined,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const classNameProp = restRecord.className as string | undefined;
|
|
33
|
+
const finalClass = classNameProp
|
|
34
|
+
? `${styles.root} ${classNameProp}`
|
|
35
|
+
: styles.root;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<MantineAnchor
|
|
39
|
+
ref={ref}
|
|
40
|
+
{...(sanitizedProps as Record<string, unknown>)}
|
|
41
|
+
className={finalClass}
|
|
42
|
+
classNames={mergedClassNames}
|
|
43
|
+
underline="never"
|
|
44
|
+
{...(icon ? { "data-has-icon": "" } : {})}
|
|
45
|
+
>
|
|
46
|
+
{icon && (
|
|
47
|
+
<span className={styles.iconWrapper} aria-hidden>
|
|
48
|
+
{icon}
|
|
49
|
+
</span>
|
|
50
|
+
)}
|
|
51
|
+
<span className={styles.labelText}>{children}</span>
|
|
52
|
+
</MantineAnchor>
|
|
53
|
+
);
|
|
54
|
+
});
|
|
55
|
+
_Link.displayName = "Link";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Recursica Link component wrapping Mantine's Anchor.
|
|
59
|
+
*
|
|
60
|
+
* Supports polymorphism via the `component` prop or `renderRoot` for custom element rendering (e.g. react-router Link).
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* <Link component="a" href="https://example.com">External Link</Link>
|
|
64
|
+
* <Link renderRoot={(props) => <RouterLink to="/home" {...props} />}>Home</Link>
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export const Link = createPolymorphicComponent<"a", LinkProps>(_Link);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Link - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Link` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Link } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Link } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Link href="/dashboard" variant="inline">
|
|
24
|
+
Go to Dashboard
|
|
25
|
+
</Link>
|
|
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
|
+
## States in Design Tokens
|
|
47
|
+
|
|
48
|
+
The design tokens (`recursica_variables_scoped.css`) provide the base link styling directly on `--recursica_ui-kit_components_link_properties_*` (no distinct `default` state), plus a `visited` variant that overrides only `colors_text-color`/`colors_icon-color`. There is no per-state token for `hover` anymore (a prior schema version had one); the component currently applies no distinct hover treatment beyond the browser's native `cursor: pointer`. There are no tokens for `active` or `focus` either; the component relies on the browser's default focus outline for accessibility unless overridden by a global reset.
|
|
49
|
+
|
|
50
|
+
## Underline Behavior
|
|
51
|
+
|
|
52
|
+
`Link` does not use Mantine's automatic hover-underline behavior; text decoration is fully controlled by the design system's tokens.
|
|
53
|
+
|
|
54
|
+
## Icon Support
|
|
55
|
+
|
|
56
|
+
When an `icon` is provided, it renders alongside the link text with spacing between them applied automatically via design tokens.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Link";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Loader Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Architecture & Integration
|
|
4
|
+
|
|
5
|
+
The `Loader` component acts as a strictly tokenized wrapper bridging the Recursica UI-Kit `loader` variables to the generic Mantine `@mantine/core` `Loader` primitive.
|
|
6
|
+
|
|
7
|
+
### Key Decisions:
|
|
8
|
+
|
|
9
|
+
- **Variant Mapping:** Recursica's `variant` directly proxies to Mantine's `type` prop for `"oval" | "bars" | "dots"`.
|
|
10
|
+
- **Property Overrides Disabled:** Natively overriding specific structural variants directly on the JSX interface like `thickness` and `borderRadius` has been intentionally omitted. Component rendering relies entirely on variables exposed by the underlying UI Kit mappings tied to the size prop.
|
|
11
|
+
|
|
12
|
+
### Token Mapping:
|
|
13
|
+
|
|
14
|
+
Sizes are bound through `data-size` attributes (`sm`, `md`, `lg` parsing to target `<div data-size="small">`, etc.).
|
|
15
|
+
|
|
16
|
+
Mantine natively sets sizing dynamically at the component root and parses thickness/variants differently natively (e.g., `oval` styles its geometry strictly via CSS `border`, while `bars` and `dots` utilize specific DOM inner spans `span.dot` / `span.bar`).
|
|
17
|
+
|
|
18
|
+
#### Specific CSS Targeting Hacks Used
|
|
19
|
+
|
|
20
|
+
- `border-width` and `border-radius` structurally style the `thickness` and `border-radius` configuration of the `oval` variant on the `::after` pseudo-element by resolving `--recursica_ui-kit_components_loader_variants_sizes_..._properties_thickness` and `_border-radius`.
|
|
21
|
+
|
|
22
|
+
### Unsupported Properties
|
|
23
|
+
|
|
24
|
+
- **xs and xl Sizing:** These sizes are explicitly unsupported in the Recursica standard logic (as surfaced in `filterStylingProps` and UI Kit mappings). Attempting to use them will safely default back or fallthrough statically unless defined later. See `COMPONENT_ISSUES.md`.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { createRoot, type Root } from "react-dom/client";
|
|
4
|
+
import { flushSync } from "react-dom";
|
|
5
|
+
import { MantineProvider } from "@mantine/core";
|
|
6
|
+
import "@mantine/core/styles.css";
|
|
7
|
+
import { Loader } from "./Loader";
|
|
8
|
+
|
|
9
|
+
function mount(node: React.ReactElement): {
|
|
10
|
+
container: HTMLElement;
|
|
11
|
+
root: Root;
|
|
12
|
+
} {
|
|
13
|
+
const container = document.createElement("div");
|
|
14
|
+
document.body.appendChild(container);
|
|
15
|
+
const root = createRoot(container);
|
|
16
|
+
flushSync(() => root.render(node));
|
|
17
|
+
return { container, root };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function unmount({ container, root }: { container: HTMLElement; root: Root }) {
|
|
21
|
+
root.unmount();
|
|
22
|
+
container.remove();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* `animate={false}` must deterministically freeze every variant — including
|
|
27
|
+
* the bars'/dots' individually-animated child spans that Mantine renders
|
|
28
|
+
* without our own class names, so they can only be reached by a descendant
|
|
29
|
+
* selector, not the `data-variant`-scoped rules the size/thickness CSS uses.
|
|
30
|
+
*/
|
|
31
|
+
describe("Loader animate prop", () => {
|
|
32
|
+
it.each(["oval", "bars", "dots"] as const)(
|
|
33
|
+
"freezes every animated element for variant=%s when animate is false, and animates by default",
|
|
34
|
+
(variant) => {
|
|
35
|
+
const animated = mount(
|
|
36
|
+
<MantineProvider defaultColorScheme="light">
|
|
37
|
+
<Loader variant={variant} />
|
|
38
|
+
</MantineProvider>,
|
|
39
|
+
);
|
|
40
|
+
const frozen = mount(
|
|
41
|
+
<MantineProvider defaultColorScheme="light">
|
|
42
|
+
<Loader variant={variant} animate={false} />
|
|
43
|
+
</MantineProvider>,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const animatedRoot =
|
|
48
|
+
animated.container.querySelector("[data-variant]")!;
|
|
49
|
+
const frozenRoot = frozen.container.querySelector("[data-variant]")!;
|
|
50
|
+
|
|
51
|
+
const animatedTargets = [
|
|
52
|
+
animatedRoot,
|
|
53
|
+
...Array.from(animatedRoot.querySelectorAll("*")),
|
|
54
|
+
];
|
|
55
|
+
const frozenTargets = [
|
|
56
|
+
frozenRoot,
|
|
57
|
+
...Array.from(frozenRoot.querySelectorAll("*")),
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
// At least one element (or the root's own ::after, for oval) actually
|
|
61
|
+
// animates by default — otherwise this test would trivially pass.
|
|
62
|
+
const hasAnimation = (el: Element, pseudo?: string) =>
|
|
63
|
+
getComputedStyle(el, pseudo).animationName !== "none";
|
|
64
|
+
const animatedHasMotion =
|
|
65
|
+
animatedTargets.some((el) => hasAnimation(el)) ||
|
|
66
|
+
hasAnimation(animatedRoot, "::after");
|
|
67
|
+
expect(animatedHasMotion).toBe(true);
|
|
68
|
+
|
|
69
|
+
// Frozen: nothing animates, root included, pseudo-element included.
|
|
70
|
+
for (const el of frozenTargets) {
|
|
71
|
+
expect(getComputedStyle(el).animationName).toBe("none");
|
|
72
|
+
}
|
|
73
|
+
expect(getComputedStyle(frozenRoot, "::after").animationName).toBe(
|
|
74
|
+
"none",
|
|
75
|
+
);
|
|
76
|
+
} finally {
|
|
77
|
+
unmount(animated);
|
|
78
|
+
unmount(frozen);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
});
|