@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,127 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- border-style: solid (needs a token if we support other border styles)
|
|
3
|
+
- box-sizing: border-box
|
|
4
|
+
- display: inline-flex
|
|
5
|
+
- align-items: center
|
|
6
|
+
- justify-content: center
|
|
7
|
+
- text-transform: uppercase (Mantine does this, but our tokens also specify it so we map it)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
.root {
|
|
11
|
+
/* HARDCODE: Basic structural assumptions */
|
|
12
|
+
box-sizing: border-box;
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
border-style: solid;
|
|
17
|
+
|
|
18
|
+
/* Base style resets to fully clear Mantine's defaults before applying ours */
|
|
19
|
+
background-color: transparent;
|
|
20
|
+
color: inherit;
|
|
21
|
+
border-color: transparent;
|
|
22
|
+
|
|
23
|
+
/* Apply global badge properties */
|
|
24
|
+
border-radius: var(
|
|
25
|
+
--recursica_ui-kit_components_badge_properties_border-radius
|
|
26
|
+
);
|
|
27
|
+
border-width: var(--recursica_ui-kit_components_badge_properties_border-size);
|
|
28
|
+
box-shadow: var(--recursica_ui-kit_components_badge_properties_elevation);
|
|
29
|
+
|
|
30
|
+
padding-left: var(
|
|
31
|
+
--recursica_ui-kit_components_badge_properties_padding-horizontal
|
|
32
|
+
);
|
|
33
|
+
padding-right: var(
|
|
34
|
+
--recursica_ui-kit_components_badge_properties_padding-horizontal
|
|
35
|
+
);
|
|
36
|
+
padding-top: var(
|
|
37
|
+
--recursica_ui-kit_components_badge_properties_padding-vertical
|
|
38
|
+
);
|
|
39
|
+
padding-bottom: var(
|
|
40
|
+
--recursica_ui-kit_components_badge_properties_padding-vertical
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
font-family: var(
|
|
44
|
+
--recursica_ui-kit_components_badge_properties_text_font-family
|
|
45
|
+
);
|
|
46
|
+
font-size: var(--recursica_ui-kit_components_badge_properties_text_font-size);
|
|
47
|
+
font-weight: var(
|
|
48
|
+
--recursica_ui-kit_components_badge_properties_text_font-weight
|
|
49
|
+
);
|
|
50
|
+
font-style: var(
|
|
51
|
+
--recursica_ui-kit_components_badge_properties_text_font-style
|
|
52
|
+
);
|
|
53
|
+
letter-spacing: var(
|
|
54
|
+
--recursica_ui-kit_components_badge_properties_text_letter-spacing
|
|
55
|
+
);
|
|
56
|
+
line-height: var(
|
|
57
|
+
--recursica_ui-kit_components_badge_properties_text_line-height
|
|
58
|
+
);
|
|
59
|
+
text-decoration: var(
|
|
60
|
+
--recursica_ui-kit_components_badge_properties_text_text-decoration
|
|
61
|
+
);
|
|
62
|
+
text-transform: var(
|
|
63
|
+
--recursica_ui-kit_components_badge_properties_text_text-transform
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Variant Definitions */
|
|
68
|
+
|
|
69
|
+
.root[data-variant="alert"] {
|
|
70
|
+
background-color: var(
|
|
71
|
+
--recursica_ui-kit_components_badge_variants_styles_alert_properties_colors_background-color
|
|
72
|
+
);
|
|
73
|
+
border-color: var(
|
|
74
|
+
--recursica_ui-kit_components_badge_variants_styles_alert_properties_colors_border-color
|
|
75
|
+
);
|
|
76
|
+
color: var(
|
|
77
|
+
--recursica_ui-kit_components_badge_variants_styles_alert_properties_colors_text-color
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.root[data-variant="primary-color"] {
|
|
82
|
+
background-color: var(
|
|
83
|
+
--recursica_ui-kit_components_badge_variants_styles_primary-color_properties_colors_background-color
|
|
84
|
+
);
|
|
85
|
+
border-color: var(
|
|
86
|
+
--recursica_ui-kit_components_badge_variants_styles_primary-color_properties_colors_border-color
|
|
87
|
+
);
|
|
88
|
+
color: var(
|
|
89
|
+
--recursica_ui-kit_components_badge_variants_styles_primary-color_properties_colors_text-color
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.root[data-variant="success"] {
|
|
94
|
+
background-color: var(
|
|
95
|
+
--recursica_ui-kit_components_badge_variants_styles_success_properties_colors_background-color
|
|
96
|
+
);
|
|
97
|
+
border-color: var(
|
|
98
|
+
--recursica_ui-kit_components_badge_variants_styles_success_properties_colors_border-color
|
|
99
|
+
);
|
|
100
|
+
color: var(
|
|
101
|
+
--recursica_ui-kit_components_badge_variants_styles_success_properties_colors_text-color
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.root[data-variant="warning"] {
|
|
106
|
+
background-color: var(
|
|
107
|
+
--recursica_ui-kit_components_badge_variants_styles_warning_properties_colors_background-color
|
|
108
|
+
);
|
|
109
|
+
border-color: var(
|
|
110
|
+
--recursica_ui-kit_components_badge_variants_styles_warning_properties_colors_border-color
|
|
111
|
+
);
|
|
112
|
+
color: var(
|
|
113
|
+
--recursica_ui-kit_components_badge_variants_styles_warning_properties_colors_text-color
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* Target Mantine internal children if needed for typography constraints */
|
|
118
|
+
.root :global(.mantine-Badge-label),
|
|
119
|
+
.root :global(.mantine-Badge-section) {
|
|
120
|
+
/* HARDCODE: Prevent Mantine from overriding our typography setup inside inner wrappers */
|
|
121
|
+
font-size: inherit;
|
|
122
|
+
font-weight: inherit;
|
|
123
|
+
line-height: inherit;
|
|
124
|
+
font-family: inherit;
|
|
125
|
+
letter-spacing: inherit;
|
|
126
|
+
text-transform: inherit;
|
|
127
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Badge } from "./Badge";
|
|
4
|
+
import { Layer } from "@recursica/adapter-common";
|
|
5
|
+
|
|
6
|
+
type BadgeStoryProps = React.ComponentProps<typeof Badge>;
|
|
7
|
+
|
|
8
|
+
const meta: Meta<BadgeStoryProps> = {
|
|
9
|
+
title: "UI-Kit/Badge",
|
|
10
|
+
component: Badge,
|
|
11
|
+
tags: ["autodocs"],
|
|
12
|
+
argTypes: {
|
|
13
|
+
variant: {
|
|
14
|
+
control: "select",
|
|
15
|
+
options: ["alert", "primary-color", "success", "warning"],
|
|
16
|
+
description: "The style / intent mapping for the badge",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default meta;
|
|
22
|
+
|
|
23
|
+
type Story = StoryObj<BadgeStoryProps>;
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {
|
|
26
|
+
args: {
|
|
27
|
+
children: "Badge Label",
|
|
28
|
+
variant: "primary-color",
|
|
29
|
+
},
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
|
|
31
|
+
render: ({ withLayer, layer, ...args }: any) => {
|
|
32
|
+
return <Badge {...args} />;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const StaticAlert: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
children: "Alert Badge",
|
|
39
|
+
variant: "alert",
|
|
40
|
+
},
|
|
41
|
+
render: (args: BadgeStoryProps) => <Badge {...args} />,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const StaticPrimary: Story = {
|
|
45
|
+
args: {
|
|
46
|
+
children: "Primary Badge",
|
|
47
|
+
variant: "primary-color",
|
|
48
|
+
},
|
|
49
|
+
render: (args: BadgeStoryProps) => <Badge {...args} />,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const StaticSuccess: Story = {
|
|
53
|
+
args: {
|
|
54
|
+
children: "Success Badge",
|
|
55
|
+
variant: "success",
|
|
56
|
+
},
|
|
57
|
+
render: (args: BadgeStoryProps) => <Badge {...args} />,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const StaticWarning: Story = {
|
|
61
|
+
args: {
|
|
62
|
+
children: "Warning Badge",
|
|
63
|
+
variant: "warning",
|
|
64
|
+
},
|
|
65
|
+
render: (args: BadgeStoryProps) => <Badge {...args} />,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const LayerOneAlert: Story = {
|
|
69
|
+
args: {
|
|
70
|
+
children: "Layer 1 Alert",
|
|
71
|
+
variant: "alert",
|
|
72
|
+
},
|
|
73
|
+
render: (args: BadgeStoryProps) => (
|
|
74
|
+
<Layer layer={1} style={{ padding: "24px" }}>
|
|
75
|
+
<Badge {...args} />
|
|
76
|
+
</Layer>
|
|
77
|
+
),
|
|
78
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Badge component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Badge as MantineBadge,
|
|
4
|
+
type BadgeProps as MantineBadgeProps,
|
|
5
|
+
createPolymorphicComponent,
|
|
6
|
+
} from "@mantine/core";
|
|
7
|
+
import {
|
|
8
|
+
filterStylingProps,
|
|
9
|
+
mergeClassNames,
|
|
10
|
+
type RecursicaOverStyled,
|
|
11
|
+
} from "../../utils/filterStylingProps";
|
|
12
|
+
import styles from "./Badge.module.css";
|
|
13
|
+
|
|
14
|
+
import { type RecursicaBadgeProps } from "@recursica/adapter-common";
|
|
15
|
+
|
|
16
|
+
export type BadgeProps = RecursicaOverStyled<
|
|
17
|
+
Omit<MantineBadgeProps, "variant" | "size" | "color" | "radius"> &
|
|
18
|
+
RecursicaBadgeProps
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
const _Badge = forwardRef<HTMLDivElement, BadgeProps>(function Badge(
|
|
22
|
+
{ variant = "primary-color", overStyled = false, ...rest },
|
|
23
|
+
ref,
|
|
24
|
+
) {
|
|
25
|
+
// Strip all visual override injections unless developer has specifically opted into overStyling.
|
|
26
|
+
// External layout props like margins are safely preserved.
|
|
27
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
28
|
+
|
|
29
|
+
const mergedClassNames = mergeClassNames(
|
|
30
|
+
{
|
|
31
|
+
root: styles.root,
|
|
32
|
+
section: styles.section,
|
|
33
|
+
label: styles.label,
|
|
34
|
+
},
|
|
35
|
+
(sanitizedProps as Record<string, unknown>).classNames as
|
|
36
|
+
| Partial<Record<string, string>>
|
|
37
|
+
| undefined,
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
41
|
+
.className as string | undefined;
|
|
42
|
+
const finalClass = classNameProp
|
|
43
|
+
? `${styles.root} ${classNameProp}`
|
|
44
|
+
: styles.root;
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<MantineBadge
|
|
48
|
+
ref={ref}
|
|
49
|
+
{...sanitizedProps}
|
|
50
|
+
variant="filled" // We manage visual style purely through our CSS variables mapping
|
|
51
|
+
data-variant={variant}
|
|
52
|
+
className={finalClass}
|
|
53
|
+
classNames={mergedClassNames}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
_Badge.displayName = "Badge";
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Recursica Badge component wrapping Mantine's Badge.
|
|
61
|
+
*
|
|
62
|
+
* Supports polymorphism via the `component` prop or `renderRoot` for custom element rendering.
|
|
63
|
+
*/
|
|
64
|
+
export const Badge = createPolymorphicComponent<"div", BadgeProps>(_Badge);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Badge - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Badge` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Badge } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Badge } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Badge variant="filled" size="md">
|
|
24
|
+
Active
|
|
25
|
+
</Badge>
|
|
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
|
+
## 1. Sizing
|
|
47
|
+
|
|
48
|
+
Badge does not currently support a `size` prop; badges render at a single fixed size.
|
|
49
|
+
|
|
50
|
+
## 2. Intent-Based Variants
|
|
51
|
+
|
|
52
|
+
Badge exposes a `variant` prop with intent-based values (`alert`, `primary-color`, `success`, `warning`) rather than Mantine's `outline`/`filled`/`light` style options. The default variant is `primary-color`.
|
|
53
|
+
|
|
54
|
+
## 3. The `overStyled` Prop
|
|
55
|
+
|
|
56
|
+
This component implements the newly added `overStyled` architectural standard. By default, passing inline `{style}` React properties to `Badge` will be ignored. This prevents accidental cascading regressions of our strict CSS-variables layouts unless a developer explicitly forces `overStyled={true}`.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Breadcrumb Implementation Notes
|
|
2
|
+
|
|
3
|
+
## Missing Variants and Sizes
|
|
4
|
+
|
|
5
|
+
The `Breadcrumb` currently does not establish any size (`xs`, `sm`, etc.) or variant variables in the underlying design tokens (`recursica_ui-kit.json`). Only basic structural definitions for `padding` and `item-gap` exist. Because of this, the `size` and `variant` properties have been explicitly omitted from the passed mantine props.
|
|
6
|
+
|
|
7
|
+
## Gap Styling
|
|
8
|
+
|
|
9
|
+
We attach `gap` to `.root` directly within `.module.css`. Mantine's inner `separator` divs can natively accept our CSS variables for structural layout.
|
|
10
|
+
|
|
11
|
+
## Composition and Separators
|
|
12
|
+
|
|
13
|
+
We preserve standard hierarchical composition based on Mantine's defaults. The component natively accepts typical anchor tags as children without wrapping them in structural spans, allowing developers to utilize `Link` wrappers as needed contextually.
|
|
14
|
+
The separator character is inherited natively from Mantine's default configuration (`/`) unless overridden by passing `separator={<Icon />}` to the component props.
|
|
15
|
+
|
|
16
|
+
## Current-page Crumb: Best-effort Enforcement, Not a Guarantee
|
|
17
|
+
|
|
18
|
+
**The last crumb should always be plain, non-interactive text — a `<span>`, not a `Link`.** It
|
|
19
|
+
represents the current page; per standard breadcrumb UX and the ARIA breadcrumb pattern, it
|
|
20
|
+
shouldn't be clickable. Passing a `Link` (or an anchor) for the last item is a misuse of the
|
|
21
|
+
component, even though `Breadcrumb.tsx` tries to correct for it — see below.
|
|
22
|
+
|
|
23
|
+
Breadcrumb intentionally keeps the flexible Mantine `children`-as-anchors interface (unlike BEAM's
|
|
24
|
+
`Breadcrumb.Item`, which renders its own `Link` internally and can't accept a caller-supplied
|
|
25
|
+
router-aware Link or `onClick`). That flexibility means Breadcrumb.tsx can't fully own what the
|
|
26
|
+
last item renders as, so it does what it can via `markCurrentPageItem` (`@recursica/adapter-common`):
|
|
27
|
+
|
|
28
|
+
- Adds `aria-current="page"` to the last child, always.
|
|
29
|
+
- If that child looks interactive (has `href` or `onClick`), strips both and sets `tabIndex={-1}`.
|
|
30
|
+
- In dev, warns to the console when it had to strip anything — a signal the caller should switch
|
|
31
|
+
that item to plain text instead of relying on this fallback.
|
|
32
|
+
|
|
33
|
+
Backed up by a CSS rule targeting `[aria-current="page"]` (Breadcrumb.module.css) that resets
|
|
34
|
+
color/text-decoration and sets `pointer-events: none`, and sets `font-family`/`font-size` to Link's own tokens
|
|
35
|
+
(per product decision: the current item should typographically match Link, just without Link's
|
|
36
|
+
color/decoration/interactivity).
|
|
37
|
+
|
|
38
|
+
**Why this isn't a real guarantee:** `cloneElement` can only override props an element actually
|
|
39
|
+
reads. A custom Link component (e.g. React Router's `<Link to="...">`) that navigates from its own
|
|
40
|
+
internal handler, independent of a passed-through `onClick`, will still navigate — stripping
|
|
41
|
+
`onClick`/`href` here doesn't touch that internal logic, and `pointer-events: none` only blocks
|
|
42
|
+
mouse activation, not keyboard/Enter on a focusable custom element. Treat all of the above as a
|
|
43
|
+
safety net for the common case (plain anchors, our own `Link`), not a substitute for callers doing
|
|
44
|
+
the right thing and passing plain text for the last crumb.
|
|
45
|
+
|
|
46
|
+
The story's `items` convenience prop demonstrates the correct pattern: every crumb except the last
|
|
47
|
+
is wrapped in `Link`, and the last is a plain `<span>`.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- align-items: center
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
.root {
|
|
6
|
+
/* HARDCODE: Basic structural flex layout for breadcrumbs */
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
|
|
10
|
+
/* Base style resets */
|
|
11
|
+
background-color: transparent;
|
|
12
|
+
color: inherit;
|
|
13
|
+
|
|
14
|
+
/* Apply global breadcrumb properties */
|
|
15
|
+
padding: var(--recursica_ui-kit_components_breadcrumb_properties_padding);
|
|
16
|
+
|
|
17
|
+
/* Mantine's breadcrumbs uses gap on the root or pseudo classes, but standard gap is safest since flex is used */
|
|
18
|
+
gap: var(--recursica_ui-kit_components_breadcrumb_properties_item-gap);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.separator {
|
|
22
|
+
/* Separator base resets if needed */
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
/* Neutralize Mantine's built-in margin-inline (--mantine-spacing-xs default) so .root's gap alone controls spacing */
|
|
27
|
+
margin-inline: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Current-page item (last crumb): Breadcrumb.tsx (via markCurrentPageItem) marks it
|
|
31
|
+
aria-current="page". This is a style-layer backstop in case that item still renders as a Link
|
|
32
|
+
despite having its href/onClick stripped — see BREADCRUMB_IMPLEMENTATION_NOTES.md. Two classes'
|
|
33
|
+
worth of specificity beats Link's single .root color/text-decoration rule regardless of module
|
|
34
|
+
load order. pointer-events only blocks mouse activation, not a router Link's own internal
|
|
35
|
+
handler — the last crumb should really just be plain text. */
|
|
36
|
+
.root [aria-current="page"] {
|
|
37
|
+
color: inherit;
|
|
38
|
+
text-decoration: none;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
|
|
41
|
+
/* Per product decision: the current-page item should match Link's font-family/size (it's
|
|
42
|
+
typically rendered as plain text, with no font styling of its own — otherwise it falls back
|
|
43
|
+
to Mantine's default font-size) but not any of Link's other styling. */
|
|
44
|
+
font-family: var(
|
|
45
|
+
--recursica_ui-kit_components_link_properties_text_font-family
|
|
46
|
+
);
|
|
47
|
+
font-size: var(--recursica_ui-kit_components_link_properties_text_font-size);
|
|
48
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import { Breadcrumb } from "./Breadcrumb";
|
|
4
|
+
import { Link } from "../Link";
|
|
5
|
+
|
|
6
|
+
type BreadcrumbStoryProps = React.ComponentProps<typeof Breadcrumb> & {
|
|
7
|
+
items?: string[];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const meta: Meta<BreadcrumbStoryProps> = {
|
|
11
|
+
title: "UI-Kit/Breadcrumb",
|
|
12
|
+
component: Breadcrumb,
|
|
13
|
+
tags: ["autodocs"],
|
|
14
|
+
parameters: {
|
|
15
|
+
docs: {
|
|
16
|
+
description: {
|
|
17
|
+
component:
|
|
18
|
+
"**Proper usage** (see `Default`): every crumb except the last is a `Link`; the last " +
|
|
19
|
+
"crumb — the current page — is plain text (e.g. a `<span>`), not a link. `Breadcrumb` " +
|
|
20
|
+
"does its best to neutralize a `Link` passed as the last item anyway (see " +
|
|
21
|
+
"`LastItemAsLink`), but that's a safety net, not something to rely on — see " +
|
|
22
|
+
"BREADCRUMB_IMPLEMENTATION_NOTES.md.",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
argTypes: {
|
|
27
|
+
children: {
|
|
28
|
+
table: {
|
|
29
|
+
disable: true,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
items: {
|
|
33
|
+
control: "object",
|
|
34
|
+
description:
|
|
35
|
+
"Array of string labels used to dynamically generate the interactive Breadcrumb nodes.",
|
|
36
|
+
table: {
|
|
37
|
+
category: "Story Controls",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
separator: {
|
|
41
|
+
control: "text",
|
|
42
|
+
description: "Custom separator between items",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
args: {
|
|
46
|
+
items: ["Home", "Components", "Breadcrumbs"],
|
|
47
|
+
},
|
|
48
|
+
render: ({ items, children, ...args }) => {
|
|
49
|
+
const mappedChildren = items
|
|
50
|
+
? items.map((label, index) =>
|
|
51
|
+
// The last crumb represents the current page, so it's plain text,
|
|
52
|
+
// not a link — matches standard breadcrumb UX.
|
|
53
|
+
index === items.length - 1 ? (
|
|
54
|
+
<span key={index}>{label}</span>
|
|
55
|
+
) : (
|
|
56
|
+
<Link href="#" key={index}>
|
|
57
|
+
{label}
|
|
58
|
+
</Link>
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
: children;
|
|
62
|
+
|
|
63
|
+
return <Breadcrumb children={mappedChildren} {...args} />;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default meta;
|
|
68
|
+
|
|
69
|
+
type Story = StoryObj<BreadcrumbStoryProps>;
|
|
70
|
+
|
|
71
|
+
export const Default: Story = {
|
|
72
|
+
args: {
|
|
73
|
+
items: ["Dashboard", "Settings", "Security"],
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const CustomSeparator: Story = {
|
|
78
|
+
args: {
|
|
79
|
+
items: ["Root", "Branch", "Leaf"],
|
|
80
|
+
separator: "→",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const LastItemAsLink: Story = {
|
|
85
|
+
name: "Last Item As Link (Incorrect Usage)",
|
|
86
|
+
args: {
|
|
87
|
+
// Bypass the `items` convenience prop (which always renders the last crumb as a span) to
|
|
88
|
+
// demonstrate what happens if a caller wraps every crumb, including the last, in a `Link`.
|
|
89
|
+
items: undefined,
|
|
90
|
+
children: [
|
|
91
|
+
<Link href="#" key="dashboard">
|
|
92
|
+
Dashboard
|
|
93
|
+
</Link>,
|
|
94
|
+
<Link href="#" key="settings">
|
|
95
|
+
Settings
|
|
96
|
+
</Link>,
|
|
97
|
+
<Link href="#" key="security">
|
|
98
|
+
Security
|
|
99
|
+
</Link>,
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
parameters: {
|
|
103
|
+
docs: {
|
|
104
|
+
description: {
|
|
105
|
+
story:
|
|
106
|
+
"Incorrect usage, kept as a story to prove Breadcrumb still handles it: the last " +
|
|
107
|
+
'crumb is a `Link`, but Breadcrumb adds `aria-current="page"`, strips its `href`/' +
|
|
108
|
+
"`onClick`, drops it from the tab order, and the CSS reset removes Link's color/" +
|
|
109
|
+
"underline — it renders identically to `Default`'s plain-text current item. Don't " +
|
|
110
|
+
"rely on this; pass plain text for the last crumb instead.",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// Placeholder for future Breadcrumb component tests. Add tests here if/when needed.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Breadcrumbs as MantineBreadcrumbs,
|
|
4
|
+
type BreadcrumbsProps as MantineBreadcrumbsProps,
|
|
5
|
+
} from "@mantine/core";
|
|
6
|
+
import {
|
|
7
|
+
filterStylingProps,
|
|
8
|
+
mergeClassNames,
|
|
9
|
+
type RecursicaOverStyled,
|
|
10
|
+
} from "../../utils/filterStylingProps";
|
|
11
|
+
import styles from "./Breadcrumb.module.css";
|
|
12
|
+
|
|
13
|
+
// Currently there are no Recursica prop additions specific to Breadcrumbs (like size or variant)
|
|
14
|
+
// according to recursica_ui-kit.json
|
|
15
|
+
import {
|
|
16
|
+
markCurrentPageItem,
|
|
17
|
+
type RecursicaBreadcrumbProps,
|
|
18
|
+
} from "@recursica/adapter-common";
|
|
19
|
+
|
|
20
|
+
export type BreadcrumbProps = RecursicaOverStyled<
|
|
21
|
+
Omit<MantineBreadcrumbsProps, "variant" | "size"> & RecursicaBreadcrumbProps
|
|
22
|
+
>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The last child should always be plain, non-interactive text (e.g. a `<span>`) — it represents
|
|
26
|
+
* the current page and shouldn't be a link. Breadcrumb tries to correct for a Link/anchor passed
|
|
27
|
+
* there anyway via `markCurrentPageItem` (aria-current, stripped href/onClick, CSS reset in
|
|
28
|
+
* Breadcrumb.module.css), but that's a best-effort safety net, not a guarantee — it can't stop a
|
|
29
|
+
* custom Link component (e.g. a router Link) that navigates from its own internal handler. See
|
|
30
|
+
* BREADCRUMB_IMPLEMENTATION_NOTES.md.
|
|
31
|
+
*/
|
|
32
|
+
export const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>(
|
|
33
|
+
function Breadcrumb(
|
|
34
|
+
{ overStyled = false, separator = ">", children, ...rest },
|
|
35
|
+
ref,
|
|
36
|
+
) {
|
|
37
|
+
const sanitizedProps = filterStylingProps(
|
|
38
|
+
{ separator, children: markCurrentPageItem(children), ...rest },
|
|
39
|
+
overStyled,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const mergedClassNames = mergeClassNames(
|
|
43
|
+
{
|
|
44
|
+
root: styles.root,
|
|
45
|
+
separator: styles.separator,
|
|
46
|
+
},
|
|
47
|
+
(sanitizedProps as Record<string, unknown>).classNames as
|
|
48
|
+
| Partial<Record<string, string>>
|
|
49
|
+
| undefined,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// Mantine's Breadcrumbs, unlike MUI's, doesn't hide the separator from screen
|
|
53
|
+
// readers by default — it's a plain text node. Match MUI's built-in aria-hidden,
|
|
54
|
+
// letting a caller override it via attributes.separator["aria-hidden"] if needed.
|
|
55
|
+
const callerAttributes = (sanitizedProps as Record<string, unknown>)
|
|
56
|
+
.attributes as
|
|
57
|
+
| Partial<Record<string, Record<string, unknown>>>
|
|
58
|
+
| undefined;
|
|
59
|
+
const mergedAttributes = {
|
|
60
|
+
...callerAttributes,
|
|
61
|
+
separator: {
|
|
62
|
+
"aria-hidden": true,
|
|
63
|
+
...callerAttributes?.separator,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const classNameProp = (sanitizedProps as Record<string, unknown>)
|
|
68
|
+
.className as string | undefined;
|
|
69
|
+
const finalClass = classNameProp
|
|
70
|
+
? `${styles.root} ${classNameProp}`
|
|
71
|
+
: styles.root;
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<MantineBreadcrumbs
|
|
75
|
+
ref={ref}
|
|
76
|
+
{...(sanitizedProps as unknown as MantineBreadcrumbsProps)}
|
|
77
|
+
className={finalClass}
|
|
78
|
+
classNames={mergedClassNames}
|
|
79
|
+
attributes={mergedAttributes}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
Breadcrumb.displayName = "Breadcrumb";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Breadcrumb - Usage Guide
|
|
2
|
+
|
|
3
|
+
This document describes how to integrate and use the `Breadcrumb` component in your projects using `@recursica/adapter-mantine-v8`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Import Reference
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Breadcrumb } from "@recursica/adapter-mantine-v8";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Basic Example
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import React from "react";
|
|
19
|
+
import { Breadcrumb } from "@recursica/adapter-mantine-v8";
|
|
20
|
+
|
|
21
|
+
export default function Demo() {
|
|
22
|
+
return (
|
|
23
|
+
<Breadcrumb>
|
|
24
|
+
<Link href="/">Home</Link>
|
|
25
|
+
<Link href="/components">Components</Link>
|
|
26
|
+
<Text>Button</Text>
|
|
27
|
+
</Breadcrumb>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 3. Design System Integration
|
|
35
|
+
|
|
36
|
+
All Recursica components in the `@recursica/adapter-mantine-v8` package adhere strictly to design system spacing, scaling, and behavior patterns.
|
|
37
|
+
|
|
38
|
+
> [!IMPORTANT]
|
|
39
|
+
>
|
|
40
|
+
> - **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.
|
|
41
|
+
> - **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.
|
|
42
|
+
> - **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.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 4. Key Integration Features & Constraints
|
|
47
|
+
|
|
48
|
+
## Missing Variants and Sizes
|
|
49
|
+
|
|
50
|
+
Breadcrumb does not currently support `size` or `variant` props.
|
|
51
|
+
|
|
52
|
+
## Composition and Separators
|
|
53
|
+
|
|
54
|
+
We preserve standard hierarchical composition based on Mantine's defaults. The component natively accepts typical anchor tags as children without wrapping them in structural spans, allowing developers to utilize `Link` wrappers as needed contextually.
|
|
55
|
+
The separator character is inherited natively from Mantine's default configuration (`/`) unless overridden by passing `separator={<Icon />}` to the component props.
|