@recursica/mui-adapter 0.5.0 → 0.7.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/ARCHITECTURE.md +15 -0
- package/CHANGELOG.md +15 -0
- package/SETUP.md +77 -0
- package/USAGE.md +55 -0
- package/dist/mui-adapter.cjs +74 -1
- package/dist/mui-adapter.cjs.map +1 -1
- package/dist/mui-adapter.css +1 -1
- package/dist/mui-adapter.js +6863 -205
- package/dist/mui-adapter.js.map +1 -1
- package/dist/src/components/Accordion/Accordion.d.ts +43 -2
- package/dist/src/components/AssistiveElement/AssistiveElement.d.ts +6 -2
- package/dist/src/components/Autocomplete/Autocomplete.d.ts +12 -2
- package/dist/src/components/Avatar/Avatar.d.ts +10 -3
- package/dist/src/components/Badge/Badge.d.ts +10 -3
- package/dist/src/components/Breadcrumb/Breadcrumb.d.ts +9 -3
- package/dist/src/components/Button/Button.d.ts +2 -17
- package/dist/src/components/Card/Card.d.ts +38 -3
- package/dist/src/components/Checkbox/Checkbox.d.ts +13 -2
- package/dist/src/components/Checkbox/CheckboxGroup.d.ts +18 -0
- package/dist/src/components/Checkbox/index.d.ts +5 -1
- package/dist/src/components/Chip/Chip.d.ts +9 -2
- package/dist/src/components/Container/Container.d.ts +1 -5
- package/dist/src/components/DatePicker/DatePicker.d.ts +2 -1
- package/dist/src/components/Dropdown/Dropdown.d.ts +12 -2
- package/dist/src/components/Flex/Flex.d.ts +2 -22
- package/dist/src/components/FormControlLayout/FormControlLayout.d.ts +5 -2
- package/dist/src/components/FormControlWrapper/FormControlWrapper.d.ts +9 -2
- package/dist/src/components/Group/Group.d.ts +2 -7
- package/dist/src/components/HoverCard/HoverCard.d.ts +28 -2
- package/dist/src/components/Label/Label.d.ts +6 -2
- package/dist/src/components/Link/Link.d.ts +2 -6
- package/dist/src/components/Loader/Loader.d.ts +2 -7
- package/dist/src/components/Menu/Menu.d.ts +25 -3
- package/dist/src/components/Modal/Modal.d.ts +37 -2
- package/dist/src/components/NumberInput/NumberInput.d.ts +12 -2
- package/dist/src/components/Pagination/Pagination.d.ts +12 -3
- package/dist/src/components/Pagination/Pagination.icons.d.ts +8 -0
- package/dist/src/components/Panel/Panel.d.ts +52 -3
- package/dist/src/components/Radio/Radio.d.ts +13 -3
- package/dist/src/components/Radio/RadioGroup.d.ts +9 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyBooleanField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyField.d.ts +4 -2
- package/dist/src/components/ReadOnlyField/ReadOnlySwitchField.d.ts +5 -0
- package/dist/src/components/ReadOnlyField/ReadOnlyTextField.d.ts +8 -0
- package/dist/src/components/ReadOnlyField/WithReadOnlyWrapper.d.ts +28 -0
- package/dist/src/components/ReadOnlyField/index.d.ts +1 -0
- package/dist/src/components/SegmentedControl/SegmentedControl.d.ts +21 -3
- package/dist/src/components/Slider/Slider.d.ts +18 -2
- package/dist/src/components/Stack/Stack.d.ts +2 -5
- package/dist/src/components/Stepper/Stepper.d.ts +41 -2
- package/dist/src/components/Switch/Switch.d.ts +10 -3
- package/dist/src/components/Switch/SwitchGroup.d.ts +13 -0
- package/dist/src/components/Table/Table.d.ts +2 -1
- package/dist/src/components/Tabs/Tabs.d.ts +20 -3
- package/dist/src/components/Text/Text.d.ts +2 -16
- package/dist/src/components/TextArea/TextArea.d.ts +12 -2
- package/dist/src/components/TextField/TextField.d.ts +12 -2
- package/dist/src/components/TimePicker/TimePicker.d.ts +2 -1
- package/dist/src/components/Timeline/Timeline.d.ts +15 -2
- package/dist/src/components/Timeline/TimelineItem.d.ts +18 -0
- package/dist/src/components/Title/Title.d.ts +2 -15
- package/dist/src/components/Toast/Toast.d.ts +20 -2
- package/dist/src/components/Tooltip/Tooltip.d.ts +28 -3
- package/dist/src/components/TransferList/TransferList.d.ts +2 -1
- package/dist/src/components/Typography/Typography.d.ts +1 -1
- package/dist/src/utils/RequireAccessibleLabel.d.ts +1 -18
- package/dist/src/utils/filterStylingProps.d.ts +1 -11
- package/llms.txt +16 -0
- package/package.json +14 -3
- package/src/components/Accordion/Accordion.module.css +294 -56
- package/src/components/Accordion/Accordion.stories.tsx +131 -21
- package/src/components/Accordion/Accordion.tsx +260 -5
- package/src/components/AssistiveElement/AssistiveElement.module.css +114 -20
- package/src/components/AssistiveElement/AssistiveElement.stories.tsx +60 -20
- package/src/components/AssistiveElement/AssistiveElement.tsx +81 -5
- package/src/components/Autocomplete/Autocomplete.module.css +319 -42
- package/src/components/Autocomplete/Autocomplete.stories.tsx +175 -23
- package/src/components/Autocomplete/Autocomplete.tsx +181 -6
- package/src/components/Avatar/Avatar.module.css +343 -73
- package/src/components/Avatar/Avatar.stories.tsx +94 -22
- package/src/components/Avatar/Avatar.tsx +99 -6
- package/src/components/Badge/Badge.module.css +127 -29
- package/src/components/Badge/Badge.stories.tsx +65 -22
- package/src/components/Badge/Badge.tsx +67 -6
- package/src/components/Breadcrumb/Breadcrumb.module.css +25 -5
- package/src/components/Breadcrumb/Breadcrumb.stories.tsx +57 -22
- package/src/components/Breadcrumb/Breadcrumb.tsx +59 -6
- package/src/components/Button/Button.module.css +19 -61
- package/src/components/Button/Button.stories.tsx +24 -23
- package/src/components/Button/Button.tsx +7 -18
- package/src/components/Card/Card.module.css +154 -38
- package/src/components/Card/Card.stories.tsx +117 -19
- package/src/components/Card/Card.tsx +181 -5
- package/src/components/Checkbox/Checkbox.module.css +249 -39
- package/src/components/Checkbox/Checkbox.stories.tsx +81 -19
- package/src/components/Checkbox/Checkbox.tsx +246 -5
- package/src/components/Checkbox/CheckboxGroup.stories.tsx +139 -0
- package/src/components/Checkbox/CheckboxGroup.tsx +137 -0
- package/src/components/Checkbox/index.ts +6 -1
- package/src/components/Chip/Chip.module.css +246 -43
- package/src/components/Chip/Chip.stories.tsx +101 -21
- package/src/components/Chip/Chip.tsx +136 -6
- package/src/components/Container/Container.stories.tsx +103 -20
- package/src/components/Container/Container.tsx +1 -13
- package/src/components/DatePicker/DatePicker.stories.tsx +125 -19
- package/src/components/DatePicker/DatePicker.tsx +3 -1
- package/src/components/Dropdown/Dropdown.module.css +291 -41
- package/src/components/Dropdown/Dropdown.stories.tsx +80 -21
- package/src/components/Dropdown/Dropdown.tsx +180 -6
- package/src/components/FileInput/FileInput.stories.tsx +2 -19
- package/src/components/FileUpload/FileUpload.stories.tsx +2 -19
- package/src/components/Flex/Flex.stories.tsx +113 -20
- package/src/components/Flex/Flex.tsx +16 -26
- package/src/components/FormControlLayout/FormControlLayout.module.css +92 -0
- package/src/components/FormControlLayout/FormControlLayout.stories.tsx +67 -20
- package/src/components/FormControlLayout/FormControlLayout.tsx +69 -4
- package/src/components/FormControlWrapper/FormControlWrapper.module.css +87 -0
- package/src/components/FormControlWrapper/FormControlWrapper.stories.tsx +116 -22
- package/src/components/FormControlWrapper/FormControlWrapper.tsx +126 -6
- package/src/components/Group/Group.stories.tsx +6 -30
- package/src/components/Group/Group.tsx +14 -9
- package/src/components/HoverCard/HoverCard.module.css +90 -22
- package/src/components/HoverCard/HoverCard.stories.tsx +158 -21
- package/src/components/HoverCard/HoverCard.tsx +147 -5
- package/src/components/Label/Label.module.css +140 -35
- package/src/components/Label/Label.stories.tsx +108 -21
- package/src/components/Label/Label.tsx +82 -5
- package/src/components/Link/Link.module.css +4 -3
- package/src/components/Link/Link.stories.tsx +2 -8
- package/src/components/Link/Link.tsx +1 -5
- package/src/components/Loader/Loader.module.css +1 -2
- package/src/components/Loader/Loader.tsx +1 -7
- package/src/components/Menu/IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Menu/Menu.module.css +285 -51
- package/src/components/Menu/Menu.stories.tsx +229 -25
- package/src/components/Menu/Menu.tsx +73 -6
- package/src/components/Modal/Modal.module.css +171 -35
- package/src/components/Modal/Modal.stories.tsx +66 -22
- package/src/components/Modal/Modal.tsx +215 -5
- package/src/components/NumberInput/NumberInput.module.css +276 -42
- package/src/components/NumberInput/NumberInput.stories.tsx +83 -20
- package/src/components/NumberInput/NumberInput.tsx +136 -6
- package/src/components/Pagination/IMPLEMENTATION_NOTES.md +3 -0
- package/src/components/Pagination/Pagination.icons.tsx +66 -0
- package/src/components/Pagination/Pagination.module.css +234 -20
- package/src/components/Pagination/Pagination.stories.tsx +34 -21
- package/src/components/Pagination/Pagination.tsx +74 -6
- package/src/components/Panel/Panel.module.css +206 -38
- package/src/components/Panel/Panel.stories.tsx +214 -22
- package/src/components/Panel/Panel.tsx +130 -5
- package/src/components/Radio/Radio.module.css +235 -37
- package/src/components/Radio/Radio.stories.tsx +77 -19
- package/src/components/Radio/Radio.tsx +210 -5
- package/src/components/Radio/RadioGroup.stories.tsx +117 -0
- package/src/components/Radio/RadioGroup.tsx +125 -0
- package/src/components/ReadOnlyField/ReadOnlyBooleanField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyField.module.css +53 -15
- package/src/components/ReadOnlyField/ReadOnlyField.stories.tsx +147 -19
- package/src/components/ReadOnlyField/ReadOnlyField.tsx +105 -5
- package/src/components/ReadOnlyField/ReadOnlySwitchField.tsx +21 -0
- package/src/components/ReadOnlyField/ReadOnlyTextField.tsx +48 -0
- package/src/components/ReadOnlyField/WithReadOnlyWrapper.tsx +93 -0
- package/src/components/ReadOnlyField/index.ts +1 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +179 -47
- package/src/components/SegmentedControl/SegmentedControl.stories.tsx +102 -20
- package/src/components/SegmentedControl/SegmentedControl.tsx +140 -6
- package/src/components/Slider/Slider.module.css +539 -86
- package/src/components/Slider/Slider.stories.tsx +157 -19
- package/src/components/Slider/Slider.tsx +283 -5
- package/src/components/Stack/Stack.stories.tsx +4 -25
- package/src/components/Stack/Stack.tsx +1 -5
- package/src/components/Stepper/IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Stepper/Stepper.module.css +410 -71
- package/src/components/Stepper/Stepper.stories.tsx +146 -20
- package/src/components/Stepper/Stepper.tsx +147 -6
- package/src/components/Switch/Switch.module.css +259 -39
- package/src/components/Switch/Switch.stories.tsx +98 -19
- package/src/components/Switch/Switch.tsx +200 -6
- package/src/components/Switch/SwitchGroup.stories.tsx +132 -0
- package/src/components/Switch/SwitchGroup.tsx +120 -0
- package/src/components/Table/Table.stories.tsx +1 -19
- package/src/components/Table/Table.tsx +3 -1
- package/src/components/Tabs/IMPLEMENTATION_NOTES.md +4 -0
- package/src/components/Tabs/Tabs.module.css +422 -79
- package/src/components/Tabs/Tabs.stories.tsx +156 -20
- package/src/components/Tabs/Tabs.tsx +86 -6
- package/src/components/Text/Text.stories.tsx +5 -17
- package/src/components/Text/Text.tsx +1 -15
- package/src/components/TextArea/TextArea.module.css +155 -32
- package/src/components/TextArea/TextArea.stories.tsx +80 -21
- package/src/components/TextArea/TextArea.tsx +146 -6
- package/src/components/TextField/TextField.module.css +261 -42
- package/src/components/TextField/TextField.stories.tsx +147 -20
- package/src/components/TextField/TextField.tsx +169 -6
- package/src/components/TimePicker/TimePicker.stories.tsx +2 -19
- package/src/components/TimePicker/TimePicker.tsx +3 -1
- package/src/components/Timeline/Timeline.module.css +365 -76
- package/src/components/Timeline/Timeline.stories.tsx +114 -21
- package/src/components/Timeline/Timeline.tsx +83 -5
- package/src/components/Timeline/TimelineItem.tsx +90 -0
- package/src/components/Title/Title.stories.tsx +0 -18
- package/src/components/Title/Title.tsx +1 -7
- package/src/components/Toast/Toast.module.css +166 -28
- package/src/components/Toast/Toast.stories.tsx +54 -22
- package/src/components/Toast/Toast.tsx +124 -5
- package/src/components/Tooltip/Tooltip.module.css +89 -24
- package/src/components/Tooltip/Tooltip.stories.tsx +152 -22
- package/src/components/Tooltip/Tooltip.tsx +88 -5
- package/src/components/TransferList/TransferList.stories.tsx +1 -19
- package/src/components/TransferList/TransferList.tsx +3 -1
- package/src/utils/RequireAccessibleLabel.ts +1 -12
- package/src/utils/filterStylingProps.ts +7 -20
|
@@ -1,23 +1,91 @@
|
|
|
1
|
+
/* HARDCODED VALUES:
|
|
2
|
+
- border-style: solid. Structural rendering rule for the dropdown border (Mantine uses Paper
|
|
3
|
+
which may not set border-style natively). Same pattern as Menu.
|
|
4
|
+
- arrowSize defaults to 16 in HoverCard.tsx. Mantine uses arrowSize for inline width/height
|
|
5
|
+
and positioning (-arrowSize/2) calculations that cannot be CSS-driven. The default matches
|
|
6
|
+
the Recursica beak-size token (16px). See COMPONENT_ISSUES.md for details.
|
|
7
|
+
- All structural layout (display, position, overflow) is deferred to Mantine's native
|
|
8
|
+
behavior. We only override visual design tokens (colors, typography, spacing, borders).
|
|
1
9
|
/* EXEMPTIONS:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/* recursica-ignore: --recursica_ui-kit_components_hover-card-
|
|
7
|
-
|
|
8
|
-
/*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
/*
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
- beak-size is ignored here because Mantine's popover arrows compute their sizing and positional offsets
|
|
11
|
+
dynamically within the React rendering engine (requires inline pixel number rather than standard CSS variables).
|
|
12
|
+
The beak size is checked in JS against a fixed value of 16px. If this variable changes, the TSX components
|
|
13
|
+
need to be reviewed/re-compiled. */
|
|
14
|
+
/* recursica-ignore: --recursica_ui-kit_components_hover-card-popover_properties_beak-size = 16px */
|
|
15
|
+
|
|
16
|
+
/* ======================================
|
|
17
|
+
DROPDOWN CONTAINER
|
|
18
|
+
====================================== */
|
|
19
|
+
|
|
20
|
+
.dropdown {
|
|
21
|
+
background-color: var(
|
|
22
|
+
--recursica_ui-kit_components_hover-card-popover_properties_colors_background
|
|
23
|
+
);
|
|
24
|
+
border-style: solid; /* HARDCODE: Mantine Paper does not set border-style natively */
|
|
25
|
+
border-width: var(
|
|
26
|
+
--recursica_ui-kit_components_hover-card-popover_properties_border-size
|
|
27
|
+
);
|
|
28
|
+
border-color: var(
|
|
29
|
+
--recursica_ui-kit_components_hover-card-popover_properties_colors_border-color
|
|
30
|
+
);
|
|
31
|
+
border-radius: var(
|
|
32
|
+
--recursica_ui-kit_components_hover-card-popover_properties_border-radius
|
|
33
|
+
);
|
|
34
|
+
box-shadow: var(
|
|
35
|
+
--recursica_ui-kit_components_hover-card-popover_properties_elevation
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
min-width: var(
|
|
39
|
+
--recursica_ui-kit_components_hover-card-popover_properties_min-width
|
|
40
|
+
);
|
|
41
|
+
max-width: var(
|
|
42
|
+
--recursica_ui-kit_components_hover-card-popover_properties_max-width
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
padding: var(
|
|
46
|
+
--recursica_ui-kit_components_hover-card-popover_properties_vertical-padding
|
|
47
|
+
)
|
|
48
|
+
var(
|
|
49
|
+
--recursica_ui-kit_components_hover-card-popover_properties_horizontal-padding
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
/* Typography */
|
|
53
|
+
font-family: var(
|
|
54
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-family
|
|
55
|
+
);
|
|
56
|
+
font-size: var(
|
|
57
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-size
|
|
58
|
+
);
|
|
59
|
+
font-style: var(
|
|
60
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-style
|
|
61
|
+
);
|
|
62
|
+
font-weight: var(
|
|
63
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_font-weight
|
|
64
|
+
);
|
|
65
|
+
letter-spacing: var(
|
|
66
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_letter-spacing
|
|
67
|
+
);
|
|
68
|
+
line-height: var(
|
|
69
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_line-height
|
|
70
|
+
);
|
|
71
|
+
text-decoration: var(
|
|
72
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_text-decoration
|
|
73
|
+
);
|
|
74
|
+
text-transform: var(
|
|
75
|
+
--recursica_ui-kit_components_hover-card-popover_properties_content-text_text-transform
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
color: var(
|
|
79
|
+
--recursica_ui-kit_components_hover-card-popover_properties_colors_content
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ======================================
|
|
84
|
+
ARROW / BEAK
|
|
85
|
+
====================================== */
|
|
86
|
+
|
|
87
|
+
.arrow {
|
|
88
|
+
border-color: var(
|
|
89
|
+
--recursica_ui-kit_components_hover-card-popover_properties_colors_border-color
|
|
90
|
+
);
|
|
91
|
+
}
|
|
@@ -1,35 +1,172 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
2
|
import { HoverCard } from "./HoverCard";
|
|
3
|
-
import {
|
|
3
|
+
import { Button } from "../Button";
|
|
4
|
+
import { Text } from "../Text/Text";
|
|
5
|
+
import { Group } from "../Group/Group";
|
|
6
|
+
import { Stack } from "../Stack/Stack";
|
|
7
|
+
import { Avatar } from "../Avatar";
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
9
|
+
/**
|
|
10
|
+
* HoverCard story axes:
|
|
11
|
+
* - position: dropdown alignment relative to target
|
|
12
|
+
* - withArrow: arrow indicator on the dropdown
|
|
13
|
+
* - openDelay / closeDelay: hover timing controls
|
|
14
|
+
* - content variations: plain text, rich content (avatar + text + actions)
|
|
15
|
+
* - layer: tested via the global Layer decorator (withLayer/layer args)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
type HoverCardStoryArgs = Record<string, any>;
|
|
20
|
+
|
|
21
|
+
const meta: Meta = {
|
|
22
|
+
title: "UI-Kit/HoverCard",
|
|
7
23
|
component: HoverCard,
|
|
8
24
|
tags: ["autodocs"],
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
+
argTypes: {
|
|
26
|
+
position: {
|
|
27
|
+
control: "select",
|
|
28
|
+
options: [
|
|
29
|
+
"bottom",
|
|
30
|
+
"bottom-start",
|
|
31
|
+
"bottom-end",
|
|
32
|
+
"top",
|
|
33
|
+
"top-start",
|
|
34
|
+
"top-end",
|
|
35
|
+
"left",
|
|
36
|
+
"left-start",
|
|
37
|
+
"left-end",
|
|
38
|
+
"right",
|
|
39
|
+
"right-start",
|
|
40
|
+
"right-end",
|
|
25
41
|
],
|
|
42
|
+
description: "The position of the dropdown relative to the target.",
|
|
43
|
+
},
|
|
44
|
+
withBeak: {
|
|
45
|
+
control: "boolean",
|
|
46
|
+
description:
|
|
47
|
+
"Whether to display a beak (arrow) pointing to the target. Recursica equivalent of Mantine's withArrow.",
|
|
48
|
+
},
|
|
49
|
+
offset: {
|
|
50
|
+
control: "number",
|
|
51
|
+
description:
|
|
52
|
+
"Distance in px between the dropdown and the target element.",
|
|
53
|
+
},
|
|
54
|
+
openDelay: {
|
|
55
|
+
control: "number",
|
|
56
|
+
description: "Delay in ms before the dropdown opens on hover.",
|
|
57
|
+
},
|
|
58
|
+
closeDelay: {
|
|
59
|
+
control: "number",
|
|
60
|
+
description: "Delay in ms before the dropdown closes when hover ends.",
|
|
61
|
+
},
|
|
62
|
+
disabled: {
|
|
63
|
+
control: "boolean",
|
|
64
|
+
description: "If set, the hover card dropdown will not be rendered.",
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
parameters: {
|
|
68
|
+
layout: "centered",
|
|
69
|
+
docs: {
|
|
70
|
+
description: {
|
|
71
|
+
component: `
|
|
72
|
+
The \`HoverCard\` component displays a popover-style dropdown when the user hovers over a target element. It wraps Mantine's composable \`HoverCard\` while enforcing strict Recursica design token styling.
|
|
73
|
+
|
|
74
|
+
### Composable API
|
|
75
|
+
|
|
76
|
+
HoverCard uses a dot-notation composition pattern:
|
|
77
|
+
- \`<HoverCard>\` — Root container managing open/close state on hover
|
|
78
|
+
- \`<HoverCard.Target>\` — Wrapper for the trigger element (must be a single element supporting ref)
|
|
79
|
+
- \`<HoverCard.Dropdown>\` — The popup panel displaying content on hover
|
|
80
|
+
|
|
81
|
+
### Key Behaviors
|
|
82
|
+
- The dropdown opens when the user hovers over the target and closes when they move away
|
|
83
|
+
- \`openDelay\` and \`closeDelay\` control the timing of open/close transitions
|
|
84
|
+
- The dropdown stays open while the user hovers over it, allowing interaction with its content
|
|
85
|
+
`,
|
|
86
|
+
},
|
|
26
87
|
},
|
|
27
88
|
},
|
|
28
89
|
};
|
|
29
90
|
|
|
30
91
|
export default meta;
|
|
31
|
-
|
|
92
|
+
|
|
93
|
+
type Story = StoryObj<HoverCardStoryArgs>;
|
|
32
94
|
|
|
33
95
|
export const Default: Story = {
|
|
34
|
-
|
|
96
|
+
args: {
|
|
97
|
+
position: "top",
|
|
98
|
+
withBeak: true,
|
|
99
|
+
offset: 5,
|
|
100
|
+
openDelay: 0,
|
|
101
|
+
closeDelay: 150,
|
|
102
|
+
},
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
104
|
+
render: ({ withLayer, layer, ...args }: HoverCardStoryArgs) => {
|
|
105
|
+
return (
|
|
106
|
+
<HoverCard {...args}>
|
|
107
|
+
<HoverCard.Target>
|
|
108
|
+
<Button variant="solid">Hover me</Button>
|
|
109
|
+
</HoverCard.Target>
|
|
110
|
+
|
|
111
|
+
<HoverCard.Dropdown>
|
|
112
|
+
<Text>
|
|
113
|
+
This is a hover card with informational content that appears when
|
|
114
|
+
you hover over the target element.
|
|
115
|
+
</Text>
|
|
116
|
+
</HoverCard.Dropdown>
|
|
117
|
+
</HoverCard>
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const WithoutBeak: Story = {
|
|
123
|
+
args: {
|
|
124
|
+
position: "top",
|
|
125
|
+
withBeak: false,
|
|
126
|
+
offset: 5,
|
|
127
|
+
},
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
129
|
+
render: ({ withLayer, layer, ...args }: HoverCardStoryArgs) => {
|
|
130
|
+
return (
|
|
131
|
+
<HoverCard {...args}>
|
|
132
|
+
<HoverCard.Target>
|
|
133
|
+
<Button variant="outline">Without Beak</Button>
|
|
134
|
+
</HoverCard.Target>
|
|
135
|
+
|
|
136
|
+
<HoverCard.Dropdown>
|
|
137
|
+
<Text>
|
|
138
|
+
This hover card has the beak disabled, showing a clean dropdown
|
|
139
|
+
without the pointing indicator.
|
|
140
|
+
</Text>
|
|
141
|
+
</HoverCard.Dropdown>
|
|
142
|
+
</HoverCard>
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export const RichContent: Story = {
|
|
148
|
+
args: {
|
|
149
|
+
position: "top",
|
|
150
|
+
offset: 5,
|
|
151
|
+
},
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
153
|
+
render: ({ withLayer, layer, ...args }: HoverCardStoryArgs) => {
|
|
154
|
+
return (
|
|
155
|
+
<HoverCard {...args}>
|
|
156
|
+
<HoverCard.Target>
|
|
157
|
+
<Button variant="solid">User Profile</Button>
|
|
158
|
+
</HoverCard.Target>
|
|
159
|
+
|
|
160
|
+
<HoverCard.Dropdown>
|
|
161
|
+
<Group>
|
|
162
|
+
<Avatar src={null} alt="User avatar" />
|
|
163
|
+
<Stack>
|
|
164
|
+
<Text>Jane Doe</Text>
|
|
165
|
+
<Text>Software Engineer at Recursica</Text>
|
|
166
|
+
</Stack>
|
|
167
|
+
</Group>
|
|
168
|
+
</HoverCard.Dropdown>
|
|
169
|
+
</HoverCard>
|
|
170
|
+
);
|
|
171
|
+
},
|
|
35
172
|
};
|
|
@@ -1,8 +1,150 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import
|
|
1
|
+
import React, { isValidElement } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Tooltip as MuiTooltip,
|
|
4
|
+
type TooltipProps as MuiTooltipProps,
|
|
5
|
+
} from "@mui/material";
|
|
6
|
+
import {
|
|
7
|
+
filterStylingProps,
|
|
8
|
+
type RecursicaOverStyled,
|
|
9
|
+
} from "../../utils/filterStylingProps";
|
|
10
|
+
import styles from "./HoverCard.module.css";
|
|
3
11
|
|
|
4
|
-
|
|
12
|
+
// ============================================================
|
|
13
|
+
// HOVERCARD ROOT
|
|
14
|
+
// ============================================================
|
|
5
15
|
|
|
6
|
-
|
|
7
|
-
|
|
16
|
+
import { type RecursicaHoverCardProps } from "@recursica/adapter-common";
|
|
17
|
+
|
|
18
|
+
export type HoverCardProps = RecursicaOverStyled<
|
|
19
|
+
Omit<MuiTooltipProps, "title" | "children"> & RecursicaHoverCardProps
|
|
20
|
+
>;
|
|
21
|
+
|
|
22
|
+
const HoverCardBase = function HoverCard({
|
|
23
|
+
overStyled = false,
|
|
24
|
+
withBeak = true,
|
|
25
|
+
position = "top",
|
|
26
|
+
openDelay = 0,
|
|
27
|
+
closeDelay = 150,
|
|
28
|
+
disabled = false,
|
|
29
|
+
offset = 5,
|
|
30
|
+
children,
|
|
31
|
+
...rest
|
|
32
|
+
}: HoverCardProps) {
|
|
33
|
+
const sanitizedProps = filterStylingProps(
|
|
34
|
+
rest as Record<string, unknown>,
|
|
35
|
+
overStyled,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
// Bind CSS module classes to Mui's internal classNames API
|
|
39
|
+
const mergedClassNames: Partial<Record<string, string>> = {
|
|
40
|
+
tooltip: styles.dropdown,
|
|
41
|
+
arrow: styles.arrow,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const classNamesProp = (sanitizedProps as Record<string, unknown>).classNames;
|
|
45
|
+
if (
|
|
46
|
+
classNamesProp &&
|
|
47
|
+
typeof classNamesProp === "object" &&
|
|
48
|
+
!Array.isArray(classNamesProp)
|
|
49
|
+
) {
|
|
50
|
+
const o = classNamesProp as Record<string, string>;
|
|
51
|
+
Object.keys(o).forEach((key) => {
|
|
52
|
+
if (mergedClassNames[key]) {
|
|
53
|
+
mergedClassNames[key] = `${mergedClassNames[key]} ${o[key]}`;
|
|
54
|
+
} else {
|
|
55
|
+
mergedClassNames[key] = o[key];
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Find Target and Dropdown children
|
|
61
|
+
let targetNode: React.ReactNode = null;
|
|
62
|
+
let dropdownNode: React.ReactNode = null;
|
|
63
|
+
|
|
64
|
+
React.Children.forEach(children, (child) => {
|
|
65
|
+
if (isValidElement(child)) {
|
|
66
|
+
const childElement = child as any;
|
|
67
|
+
if (childElement.type?.displayName === "HoverCardTarget") {
|
|
68
|
+
targetNode = childElement.props.children;
|
|
69
|
+
} else if (childElement.type?.displayName === "HoverCardDropdown") {
|
|
70
|
+
dropdownNode = childElement.props.children;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!targetNode) {
|
|
76
|
+
// Fallback if structure is wrong
|
|
77
|
+
targetNode = <div />;
|
|
78
|
+
}
|
|
79
|
+
if (!dropdownNode) {
|
|
80
|
+
dropdownNode = <div />;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<MuiTooltip
|
|
85
|
+
title={dropdownNode}
|
|
86
|
+
placement={position as any}
|
|
87
|
+
arrow={withBeak}
|
|
88
|
+
enterDelay={openDelay}
|
|
89
|
+
leaveDelay={closeDelay}
|
|
90
|
+
disableHoverListener={disabled}
|
|
91
|
+
slotProps={{
|
|
92
|
+
popper: {
|
|
93
|
+
modifiers: [
|
|
94
|
+
{
|
|
95
|
+
name: "offset",
|
|
96
|
+
options: {
|
|
97
|
+
offset: [0, offset],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
}}
|
|
103
|
+
classes={mergedClassNames as any}
|
|
104
|
+
{...(sanitizedProps as any)}
|
|
105
|
+
>
|
|
106
|
+
{/* Tooltip requires a single valid React element child that accepts a ref */}
|
|
107
|
+
{isValidElement(targetNode) ? targetNode : <span>{targetNode}</span>}
|
|
108
|
+
</MuiTooltip>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
HoverCardBase.displayName = "HoverCard";
|
|
112
|
+
|
|
113
|
+
// ============================================================
|
|
114
|
+
// HOVERCARD TARGET
|
|
115
|
+
// ============================================================
|
|
116
|
+
|
|
117
|
+
export type HoverCardTargetProps = { children?: React.ReactNode };
|
|
118
|
+
|
|
119
|
+
const HoverCardTarget = function HoverCardTarget({
|
|
120
|
+
children,
|
|
121
|
+
}: HoverCardTargetProps) {
|
|
122
|
+
return <>{children}</>;
|
|
123
|
+
};
|
|
124
|
+
HoverCardTarget.displayName = "HoverCardTarget";
|
|
125
|
+
|
|
126
|
+
// ============================================================
|
|
127
|
+
// HOVERCARD DROPDOWN
|
|
128
|
+
// ============================================================
|
|
129
|
+
|
|
130
|
+
export type HoverCardDropdownProps = { children?: React.ReactNode };
|
|
131
|
+
|
|
132
|
+
const HoverCardDropdown = function HoverCardDropdown({
|
|
133
|
+
children,
|
|
134
|
+
}: HoverCardDropdownProps) {
|
|
135
|
+
return <>{children}</>;
|
|
8
136
|
};
|
|
137
|
+
HoverCardDropdown.displayName = "HoverCardDropdown";
|
|
138
|
+
|
|
139
|
+
// ============================================================
|
|
140
|
+
// DOT NOTATION EXPORT
|
|
141
|
+
// ============================================================
|
|
142
|
+
|
|
143
|
+
type HoverCardComponent = typeof HoverCardBase & {
|
|
144
|
+
Target: typeof HoverCardTarget;
|
|
145
|
+
Dropdown: typeof HoverCardDropdown;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export const HoverCard = HoverCardBase as HoverCardComponent;
|
|
149
|
+
HoverCard.Target = HoverCardTarget;
|
|
150
|
+
HoverCard.Dropdown = HoverCardDropdown;
|
|
@@ -1,35 +1,140 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
1
|
+
.root {
|
|
2
|
+
/* Prevent default MUI absolute positioning logic */
|
|
3
|
+
position: relative;
|
|
4
|
+
transform: none;
|
|
5
|
+
pointer-events: auto;
|
|
6
|
+
white-space: normal;
|
|
7
|
+
|
|
8
|
+
/* Reset MUI structural overrides */
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
display: flex;
|
|
12
|
+
width: 100%;
|
|
13
|
+
|
|
14
|
+
/* Recursica Font Map */
|
|
15
|
+
font-family: var(
|
|
16
|
+
--recursica_ui-kit_components_label_properties_label-text_font-family
|
|
17
|
+
);
|
|
18
|
+
font-size: var(
|
|
19
|
+
--recursica_ui-kit_components_label_properties_label-text_font-size
|
|
20
|
+
);
|
|
21
|
+
font-style: var(
|
|
22
|
+
--recursica_ui-kit_components_label_properties_label-text_font-style
|
|
23
|
+
);
|
|
24
|
+
font-weight: var(
|
|
25
|
+
--recursica_ui-kit_components_label_properties_label-text_font-weight
|
|
26
|
+
);
|
|
27
|
+
letter-spacing: var(
|
|
28
|
+
--recursica_ui-kit_components_label_properties_label-text_letter-spacing
|
|
29
|
+
);
|
|
30
|
+
line-height: var(
|
|
31
|
+
--recursica_ui-kit_components_label_properties_label-text_line-height
|
|
32
|
+
);
|
|
33
|
+
text-decoration: var(
|
|
34
|
+
--recursica_ui-kit_components_label_properties_label-text_text-decoration
|
|
35
|
+
);
|
|
36
|
+
text-transform: var(
|
|
37
|
+
--recursica_ui-kit_components_label_properties_label-text_text-transform
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
color: var(--recursica_ui-kit_components_label_properties_colors_text);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.innerLayout {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
gap: var(
|
|
47
|
+
--recursica_ui-kit_components_label_properties_label-optional-text-gap
|
|
48
|
+
);
|
|
49
|
+
width: 100%;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.text {
|
|
53
|
+
/* Natively intercepts MUI asterisk rendering securely wrapping inline with typography */
|
|
54
|
+
display: inline;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.required {
|
|
58
|
+
/* Override the `.MuiInputLabel-asterisk` natively */
|
|
59
|
+
color: var(--recursica_ui-kit_components_label_properties_colors_asterisk);
|
|
60
|
+
margin-left: var(
|
|
61
|
+
--recursica_ui-kit_components_label_properties_required-indicator-gap
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.root :global(.MuiFormLabel-asterisk) {
|
|
66
|
+
display: none !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* MUI propagates .Mui-error to the label automatically on FormControl error.
|
|
70
|
+
We explicitly override this bleed to prevent the main label text from turning red,
|
|
71
|
+
while allowing the asterisk to take the error color! */
|
|
72
|
+
.root:global(.Mui-error) {
|
|
73
|
+
color: var(--recursica_ui-kit_components_label_properties_colors_text);
|
|
74
|
+
}
|
|
75
|
+
.root:global(.Mui-error) .required {
|
|
76
|
+
color: var(
|
|
77
|
+
--recursica_ui-kit_components_assistive-element_variants_types_error_properties_colors_text-color
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.endNodes {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: var(
|
|
85
|
+
--recursica_ui-kit_components_label_properties_label-optional-text-gap
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.optionalText {
|
|
90
|
+
color: inherit;
|
|
91
|
+
font-family: var(
|
|
92
|
+
--recursica_ui-kit_components_label_properties_optional-text_font-family
|
|
93
|
+
);
|
|
94
|
+
font-size: var(
|
|
95
|
+
--recursica_ui-kit_components_label_properties_optional-text_font-size
|
|
96
|
+
);
|
|
97
|
+
font-style: var(
|
|
98
|
+
--recursica_ui-kit_components_label_properties_optional-text_font-style
|
|
99
|
+
);
|
|
100
|
+
font-weight: var(
|
|
101
|
+
--recursica_ui-kit_components_label_properties_optional-text_font-weight
|
|
102
|
+
);
|
|
103
|
+
letter-spacing: var(
|
|
104
|
+
--recursica_ui-kit_components_label_properties_optional-text_letter-spacing
|
|
105
|
+
);
|
|
106
|
+
line-height: var(
|
|
107
|
+
--recursica_ui-kit_components_label_properties_optional-text_line-height
|
|
108
|
+
);
|
|
109
|
+
text-decoration: var(
|
|
110
|
+
--recursica_ui-kit_components_label_properties_optional-text_text-decoration
|
|
111
|
+
);
|
|
112
|
+
text-transform: var(
|
|
113
|
+
--recursica_ui-kit_components_label_properties_optional-text_text-transform
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.actionArea {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.editIcon {
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: center;
|
|
126
|
+
cursor: pointer;
|
|
127
|
+
background: none;
|
|
128
|
+
border: none;
|
|
129
|
+
padding: 0;
|
|
130
|
+
|
|
131
|
+
width: 16px;
|
|
132
|
+
height: 16px;
|
|
133
|
+
color: inherit;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.editIcon :global(svg) {
|
|
137
|
+
width: 100%;
|
|
138
|
+
height: 100%;
|
|
139
|
+
stroke-width: 2px;
|
|
140
|
+
}
|