@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,35 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu story axes:
|
|
3
|
+
* - trigger: click (default) vs hover behavior
|
|
4
|
+
* - position: dropdown alignment relative to target
|
|
5
|
+
* - withArrow: arrow indicator on the dropdown
|
|
6
|
+
* - content variations: icons, dividers, labels, disabled items, submenus
|
|
7
|
+
* - layer: tested via the global Layer decorator (withLayer/layer args)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, { useState, useRef, useEffect } from "react";
|
|
1
11
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import { Menu } from "./Menu";
|
|
3
|
-
import {
|
|
12
|
+
import { Menu, MenuItem, MenuDivider } from "./Menu";
|
|
13
|
+
import { Button } from "../Button";
|
|
14
|
+
import { ListSubheader } from "@mui/material";
|
|
15
|
+
|
|
16
|
+
const SettingsIcon = (props: any) => (
|
|
17
|
+
<svg
|
|
18
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
19
|
+
width="14"
|
|
20
|
+
height="14"
|
|
21
|
+
viewBox="0 0 24 24"
|
|
22
|
+
fill="none"
|
|
23
|
+
stroke="currentColor"
|
|
24
|
+
strokeWidth="2"
|
|
25
|
+
strokeLinecap="round"
|
|
26
|
+
strokeLinejoin="round"
|
|
27
|
+
{...props}
|
|
28
|
+
>
|
|
29
|
+
<circle cx="12" cy="12" r="3" />
|
|
30
|
+
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
|
|
31
|
+
</svg>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const SearchIcon = (props: any) => (
|
|
35
|
+
<svg
|
|
36
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
37
|
+
width="14"
|
|
38
|
+
height="14"
|
|
39
|
+
viewBox="0 0 24 24"
|
|
40
|
+
fill="none"
|
|
41
|
+
stroke="currentColor"
|
|
42
|
+
strokeWidth="2"
|
|
43
|
+
strokeLinecap="round"
|
|
44
|
+
strokeLinejoin="round"
|
|
45
|
+
{...props}
|
|
46
|
+
>
|
|
47
|
+
<circle cx="11" cy="11" r="8" />
|
|
48
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
49
|
+
</svg>
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const MessageIcon = (props: any) => (
|
|
53
|
+
<svg
|
|
54
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
55
|
+
width="14"
|
|
56
|
+
height="14"
|
|
57
|
+
viewBox="0 0 24 24"
|
|
58
|
+
fill="none"
|
|
59
|
+
stroke="currentColor"
|
|
60
|
+
strokeWidth="2"
|
|
61
|
+
strokeLinecap="round"
|
|
62
|
+
strokeLinejoin="round"
|
|
63
|
+
{...props}
|
|
64
|
+
>
|
|
65
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
|
|
66
|
+
</svg>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const ImageIcon = (props: any) => (
|
|
70
|
+
<svg
|
|
71
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
72
|
+
width="14"
|
|
73
|
+
height="14"
|
|
74
|
+
viewBox="0 0 24 24"
|
|
75
|
+
fill="none"
|
|
76
|
+
stroke="currentColor"
|
|
77
|
+
strokeWidth="2"
|
|
78
|
+
strokeLinecap="round"
|
|
79
|
+
strokeLinejoin="round"
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
|
|
83
|
+
<circle cx="8.5" cy="8.5" r="1.5" />
|
|
84
|
+
<polyline points="21 15 16 10 5 21" />
|
|
85
|
+
</svg>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const TrashIcon = (props: any) => (
|
|
89
|
+
<svg
|
|
90
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
91
|
+
width="14"
|
|
92
|
+
height="14"
|
|
93
|
+
viewBox="0 0 24 24"
|
|
94
|
+
fill="none"
|
|
95
|
+
stroke="currentColor"
|
|
96
|
+
strokeWidth="2"
|
|
97
|
+
strokeLinecap="round"
|
|
98
|
+
strokeLinejoin="round"
|
|
99
|
+
{...props}
|
|
100
|
+
>
|
|
101
|
+
<polyline points="3 6 5 6 21 6" />
|
|
102
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
|
|
103
|
+
</svg>
|
|
104
|
+
);
|
|
4
105
|
|
|
5
|
-
const
|
|
6
|
-
|
|
106
|
+
const ArrowsIcon = (props: any) => (
|
|
107
|
+
<svg
|
|
108
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
109
|
+
width="14"
|
|
110
|
+
height="14"
|
|
111
|
+
viewBox="0 0 24 24"
|
|
112
|
+
fill="none"
|
|
113
|
+
stroke="currentColor"
|
|
114
|
+
strokeWidth="2"
|
|
115
|
+
strokeLinecap="round"
|
|
116
|
+
strokeLinejoin="round"
|
|
117
|
+
{...props}
|
|
118
|
+
>
|
|
119
|
+
<polyline points="17 1 21 5 17 9" />
|
|
120
|
+
<path d="M3 11V9a4 4 0 0 1 4-4h14" />
|
|
121
|
+
<polyline points="7 23 3 19 7 15" />
|
|
122
|
+
<path d="M21 13v2a4 4 0 0 1-4 4H3" />
|
|
123
|
+
</svg>
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
type MenuStoryArgs = Record<string, any>;
|
|
127
|
+
|
|
128
|
+
const meta: Meta = {
|
|
129
|
+
title: "UI-Kit/Menu",
|
|
7
130
|
component: Menu,
|
|
8
131
|
tags: ["autodocs"],
|
|
9
|
-
parameters: {
|
|
10
|
-
controls: {
|
|
11
|
-
include: [
|
|
12
|
-
"layer",
|
|
13
|
-
"withLayer",
|
|
14
|
-
"children",
|
|
15
|
-
"component",
|
|
16
|
-
"variant",
|
|
17
|
-
"size",
|
|
18
|
-
"icon",
|
|
19
|
-
"disabled",
|
|
20
|
-
"href",
|
|
21
|
-
"onClick",
|
|
22
|
-
"onChange",
|
|
23
|
-
"value",
|
|
24
|
-
"checked",
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
132
|
};
|
|
29
133
|
|
|
30
134
|
export default meta;
|
|
31
|
-
|
|
135
|
+
|
|
136
|
+
type Story = StoryObj<MenuStoryArgs>;
|
|
137
|
+
|
|
138
|
+
const InteractiveMenu = ({ children, openDelay, ...args }: any) => {
|
|
139
|
+
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
|
140
|
+
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
141
|
+
|
|
142
|
+
const open = Boolean(anchorEl) || args.opened;
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (args.opened && buttonRef.current) {
|
|
146
|
+
setAnchorEl(buttonRef.current);
|
|
147
|
+
}
|
|
148
|
+
}, [args.opened]);
|
|
149
|
+
|
|
150
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
151
|
+
setAnchorEl(event.currentTarget);
|
|
152
|
+
};
|
|
153
|
+
const handleClose = () => {
|
|
154
|
+
setAnchorEl(null);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<div>
|
|
159
|
+
<Button ref={buttonRef} variant="solid" onClick={handleClick}>
|
|
160
|
+
Toggle Menu
|
|
161
|
+
</Button>
|
|
162
|
+
<Menu anchorEl={anchorEl} open={open} onClose={handleClose} {...args}>
|
|
163
|
+
{children}
|
|
164
|
+
</Menu>
|
|
165
|
+
</div>
|
|
166
|
+
);
|
|
167
|
+
};
|
|
32
168
|
|
|
33
169
|
export const Default: Story = {
|
|
34
|
-
render: () =>
|
|
170
|
+
render: (args) => (
|
|
171
|
+
<InteractiveMenu {...args}>
|
|
172
|
+
<ListSubheader>Application</ListSubheader>
|
|
173
|
+
<MenuItem>
|
|
174
|
+
<SettingsIcon style={{ marginRight: 8 }} /> Settings
|
|
175
|
+
</MenuItem>
|
|
176
|
+
<MenuItem>
|
|
177
|
+
<MessageIcon style={{ marginRight: 8 }} /> Messages
|
|
178
|
+
</MenuItem>
|
|
179
|
+
<MenuItem>
|
|
180
|
+
<ImageIcon style={{ marginRight: 8 }} /> Gallery
|
|
181
|
+
</MenuItem>
|
|
182
|
+
<MenuItem>
|
|
183
|
+
<SearchIcon style={{ marginRight: 8 }} /> Search
|
|
184
|
+
</MenuItem>
|
|
185
|
+
<MenuDivider />
|
|
186
|
+
<ListSubheader>Danger zone</ListSubheader>
|
|
187
|
+
<MenuItem>
|
|
188
|
+
<ArrowsIcon style={{ marginRight: 8 }} /> Transfer my data
|
|
189
|
+
</MenuItem>
|
|
190
|
+
<MenuItem>
|
|
191
|
+
<TrashIcon style={{ marginRight: 8 }} /> Delete my account
|
|
192
|
+
</MenuItem>
|
|
193
|
+
</InteractiveMenu>
|
|
194
|
+
),
|
|
195
|
+
args: {
|
|
196
|
+
opened: true,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export const WithDisabledItems: Story = {
|
|
201
|
+
render: (args) => (
|
|
202
|
+
<InteractiveMenu {...args}>
|
|
203
|
+
<MenuItem>
|
|
204
|
+
<SettingsIcon style={{ marginRight: 8 }} /> Settings
|
|
205
|
+
</MenuItem>
|
|
206
|
+
<MenuItem disabled>
|
|
207
|
+
<SearchIcon style={{ marginRight: 8 }} /> Search (disabled)
|
|
208
|
+
</MenuItem>
|
|
209
|
+
<MenuItem>
|
|
210
|
+
<MessageIcon style={{ marginRight: 8 }} /> Messages
|
|
211
|
+
</MenuItem>
|
|
212
|
+
<MenuItem disabled>
|
|
213
|
+
<TrashIcon style={{ marginRight: 8 }} /> Delete (disabled)
|
|
214
|
+
</MenuItem>
|
|
215
|
+
</InteractiveMenu>
|
|
216
|
+
),
|
|
217
|
+
args: {
|
|
218
|
+
opened: true,
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
export const HoverTrigger: Story = {
|
|
223
|
+
render: (args) => (
|
|
224
|
+
<InteractiveMenu {...args}>
|
|
225
|
+
<MenuItem>
|
|
226
|
+
<SettingsIcon style={{ marginRight: 8 }} /> Settings
|
|
227
|
+
</MenuItem>
|
|
228
|
+
<MenuItem>
|
|
229
|
+
<MessageIcon style={{ marginRight: 8 }} /> Messages
|
|
230
|
+
</MenuItem>
|
|
231
|
+
<MenuItem>
|
|
232
|
+
<ImageIcon style={{ marginRight: 8 }} /> Gallery
|
|
233
|
+
</MenuItem>
|
|
234
|
+
</InteractiveMenu>
|
|
235
|
+
),
|
|
236
|
+
args: {
|
|
237
|
+
opened: true,
|
|
238
|
+
},
|
|
35
239
|
};
|
|
@@ -1,8 +1,75 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Menu as MuiMenu,
|
|
4
|
+
type MenuProps as MuiMenuProps,
|
|
5
|
+
MenuItem as MuiMenuItem,
|
|
6
|
+
type MenuItemProps as MuiMenuItemProps,
|
|
7
|
+
Divider as MuiDivider,
|
|
8
|
+
type DividerProps as MuiDividerProps,
|
|
9
|
+
} from "@mui/material";
|
|
10
|
+
import {
|
|
11
|
+
filterStylingProps,
|
|
12
|
+
type RecursicaOverStyled,
|
|
13
|
+
} from "../../utils/filterStylingProps";
|
|
14
|
+
import styles from "./Menu.module.css";
|
|
3
15
|
|
|
4
|
-
|
|
16
|
+
import { type RecursicaMenuProps } from "@recursica/adapter-common";
|
|
5
17
|
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
18
|
+
export type MenuProps = RecursicaOverStyled<MuiMenuProps & RecursicaMenuProps>;
|
|
19
|
+
|
|
20
|
+
export const Menu = forwardRef<HTMLDivElement, MenuProps>(function Menu(
|
|
21
|
+
{ overStyled = false, className, ...rest },
|
|
22
|
+
ref,
|
|
23
|
+
) {
|
|
24
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<MuiMenu
|
|
28
|
+
ref={ref}
|
|
29
|
+
className={`${styles.dropdown} ${className || ""}`}
|
|
30
|
+
classes={{
|
|
31
|
+
paper: styles.dropdown,
|
|
32
|
+
list: styles.dropdown,
|
|
33
|
+
}}
|
|
34
|
+
{...(sanitizedProps as MuiMenuProps)}
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
Menu.displayName = "Menu";
|
|
40
|
+
|
|
41
|
+
export type MenuItemProps = RecursicaOverStyled<MuiMenuItemProps>;
|
|
42
|
+
|
|
43
|
+
export const MenuItem = forwardRef<HTMLLIElement, MenuItemProps>(
|
|
44
|
+
function MenuItem({ overStyled = false, className, ...rest }, ref) {
|
|
45
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<MuiMenuItem
|
|
49
|
+
ref={ref}
|
|
50
|
+
className={`${styles.item} ${className || ""}`}
|
|
51
|
+
{...(sanitizedProps as MuiMenuItemProps)}
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
MenuItem.displayName = "MenuItem";
|
|
58
|
+
|
|
59
|
+
export type MenuDividerProps = RecursicaOverStyled<MuiDividerProps>;
|
|
60
|
+
|
|
61
|
+
export const MenuDivider = forwardRef<HTMLHRElement, MenuDividerProps>(
|
|
62
|
+
function MenuDivider({ overStyled = false, className, ...rest }, ref) {
|
|
63
|
+
const sanitizedProps = filterStylingProps(rest, overStyled);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<MuiDivider
|
|
67
|
+
ref={ref}
|
|
68
|
+
className={`${styles.divider} ${className || ""}`}
|
|
69
|
+
{...(sanitizedProps as MuiDividerProps)}
|
|
70
|
+
/>
|
|
71
|
+
);
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
MenuDivider.displayName = "MenuDivider";
|
|
@@ -1,36 +1,172 @@
|
|
|
1
1
|
/* EXEMPTIONS:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/* recursica-ignore: --recursica_ui-
|
|
6
|
-
/* recursica-ignore: --recursica_ui-
|
|
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
|
-
|
|
36
|
-
|
|
2
|
+
- content-style and header-style parent variables represent raw JSON styling objects rather than
|
|
3
|
+
direct CSS variables and cannot be applied directly in standard CSS files.
|
|
4
|
+
Sub-properties are fully and individually mapped to elements natively. */
|
|
5
|
+
/* recursica-ignore: --recursica_ui-kit_components_modal_properties_content-style */
|
|
6
|
+
/* recursica-ignore: --recursica_ui-kit_components_modal_properties_header-style */
|
|
7
|
+
|
|
8
|
+
.root {
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.inner {
|
|
12
|
+
/* Mantine applies padding to inner to keep modal away from edges. We rely on content constraints. */
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.content {
|
|
16
|
+
/* Geometric Bounds */
|
|
17
|
+
min-width: var(--recursica_ui-kit_components_modal_properties_min-width);
|
|
18
|
+
max-width: var(--recursica_ui-kit_components_modal_properties_max-width);
|
|
19
|
+
min-height: var(--recursica_ui-kit_components_modal_properties_min-height);
|
|
20
|
+
|
|
21
|
+
/* Restrict max-height to either the UI Kit max or the viewport bounds to force internal scrolling */
|
|
22
|
+
max-height: min(
|
|
23
|
+
var(--recursica_ui-kit_components_modal_properties_max-height),
|
|
24
|
+
calc(100vh - 4rem)
|
|
25
|
+
);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
|
|
28
|
+
/* Box model */
|
|
29
|
+
border-radius: var(
|
|
30
|
+
--recursica_ui-kit_components_modal_properties_border-radius
|
|
31
|
+
);
|
|
32
|
+
border-width: var(--recursica_ui-kit_components_modal_properties_border-size);
|
|
33
|
+
border-color: var(
|
|
34
|
+
--recursica_ui-kit_components_modal_properties_colors_border-color
|
|
35
|
+
);
|
|
36
|
+
border-style: solid;
|
|
37
|
+
|
|
38
|
+
/* Appearance */
|
|
39
|
+
background-color: var(
|
|
40
|
+
--recursica_ui-kit_components_modal_properties_colors_background
|
|
41
|
+
);
|
|
42
|
+
box-shadow: var(--recursica_ui-kit_components_modal_properties_elevation);
|
|
43
|
+
|
|
44
|
+
/* Internal Flex container to trap header and let body scroll */
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.header {
|
|
50
|
+
padding: var(--recursica_ui-kit_components_modal_properties_vertical-padding)
|
|
51
|
+
var(--recursica_ui-kit_components_modal_properties_horizontal-padding);
|
|
52
|
+
background-color: transparent; /* Inherit from content */
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.title {
|
|
56
|
+
color: var(--recursica_ui-kit_components_modal_properties_colors_title);
|
|
57
|
+
|
|
58
|
+
/* Direct Figma Typography Mapping */
|
|
59
|
+
font-family: var(
|
|
60
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontFamily
|
|
61
|
+
);
|
|
62
|
+
font-size: var(
|
|
63
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontSize
|
|
64
|
+
);
|
|
65
|
+
font-style: var(
|
|
66
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontStyle
|
|
67
|
+
);
|
|
68
|
+
font-weight: var(
|
|
69
|
+
--recursica_ui-kit_components_modal_properties_header-style_fontWeight
|
|
70
|
+
);
|
|
71
|
+
letter-spacing: var(
|
|
72
|
+
--recursica_ui-kit_components_modal_properties_header-style_letterSpacing
|
|
73
|
+
);
|
|
74
|
+
line-height: var(
|
|
75
|
+
--recursica_ui-kit_components_modal_properties_header-style_lineHeight
|
|
76
|
+
);
|
|
77
|
+
text-transform: var(
|
|
78
|
+
--recursica_ui-kit_components_modal_properties_header-style_textCase
|
|
79
|
+
);
|
|
80
|
+
text-decoration: var(
|
|
81
|
+
--recursica_ui-kit_components_modal_properties_header-style_textDecoration
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.bodyWrapper {
|
|
86
|
+
/* This is the container that overrides Mantine's native Body. It strips padding and acts as a flex column. */
|
|
87
|
+
padding: 0;
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
flex: 1 1 auto;
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
min-height: 0; /* Critical for flex child scrolling constraint */
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.scrollArea {
|
|
96
|
+
padding: var(--recursica_ui-kit_components_modal_properties_vertical-padding)
|
|
97
|
+
var(--recursica_ui-kit_components_modal_properties_horizontal-padding);
|
|
98
|
+
|
|
99
|
+
/* Internal scrolling */
|
|
100
|
+
flex: 1 1 auto;
|
|
101
|
+
overflow-y: auto;
|
|
102
|
+
min-height: 0; /* Critical for flex child scrolling constraint */
|
|
103
|
+
|
|
104
|
+
color: var(--recursica_ui-kit_components_modal_properties_colors_content);
|
|
105
|
+
|
|
106
|
+
/* Direct Figma Typography Mapping */
|
|
107
|
+
font-family: var(
|
|
108
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontFamily
|
|
109
|
+
);
|
|
110
|
+
font-size: var(
|
|
111
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontSize
|
|
112
|
+
);
|
|
113
|
+
font-style: var(
|
|
114
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontStyle
|
|
115
|
+
);
|
|
116
|
+
font-weight: var(
|
|
117
|
+
--recursica_ui-kit_components_modal_properties_content-style_fontWeight
|
|
118
|
+
);
|
|
119
|
+
letter-spacing: var(
|
|
120
|
+
--recursica_ui-kit_components_modal_properties_content-style_letterSpacing
|
|
121
|
+
);
|
|
122
|
+
line-height: var(
|
|
123
|
+
--recursica_ui-kit_components_modal_properties_content-style_lineHeight
|
|
124
|
+
);
|
|
125
|
+
text-transform: var(
|
|
126
|
+
--recursica_ui-kit_components_modal_properties_content-style_textCase
|
|
127
|
+
);
|
|
128
|
+
text-decoration: var(
|
|
129
|
+
--recursica_ui-kit_components_modal_properties_content-style_textDecoration
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
/* Ensure button gap token is easily usable if developers use standard spacing */
|
|
133
|
+
--modal-button-gap: var(
|
|
134
|
+
--recursica_ui-kit_components_modal_properties_button-gap
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
/* Smooth divider transitions */
|
|
138
|
+
transition: border-color 0.15s ease;
|
|
139
|
+
border-top: var(
|
|
140
|
+
--recursica_ui-kit_components_modal_properties_scroll-divider-thickness
|
|
141
|
+
)
|
|
142
|
+
solid transparent;
|
|
143
|
+
border-bottom: var(
|
|
144
|
+
--recursica_ui-kit_components_modal_properties_scroll-divider-thickness
|
|
145
|
+
)
|
|
146
|
+
solid transparent;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.scrollArea[data-scrolled-top] {
|
|
150
|
+
border-top-color: var(
|
|
151
|
+
--recursica_ui-kit_components_modal_properties_colors_scroll-divider
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.scrollArea[data-scrolled-bottom] {
|
|
156
|
+
border-bottom-color: var(
|
|
157
|
+
--recursica_ui-kit_components_modal_properties_colors_scroll-divider
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.footer {
|
|
162
|
+
padding: var(--recursica_ui-kit_components_modal_properties_vertical-padding)
|
|
163
|
+
var(--recursica_ui-kit_components_modal_properties_horizontal-padding);
|
|
164
|
+
background-color: transparent;
|
|
165
|
+
display: flex;
|
|
166
|
+
justify-content: flex-end;
|
|
167
|
+
gap: var(--recursica_ui-kit_components_modal_properties_button-gap);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.close {
|
|
171
|
+
/* Inherits standard icon button tokens natively, but we can override if required */
|
|
172
|
+
}
|
|
@@ -1,35 +1,79 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
1
2
|
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import { Modal } from "./Modal";
|
|
3
|
-
import {
|
|
3
|
+
import { Modal, type ModalProps } from "./Modal";
|
|
4
|
+
import { Button } from "../Button";
|
|
4
5
|
|
|
5
6
|
const meta: Meta<typeof Modal> = {
|
|
6
|
-
title: "UI-Kit
|
|
7
|
+
title: "UI-Kit/Modal",
|
|
7
8
|
component: Modal,
|
|
8
9
|
tags: ["autodocs"],
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"withLayer",
|
|
14
|
-
"children",
|
|
15
|
-
"component",
|
|
16
|
-
"variant",
|
|
17
|
-
"size",
|
|
18
|
-
"icon",
|
|
19
|
-
"disabled",
|
|
20
|
-
"href",
|
|
21
|
-
"onClick",
|
|
22
|
-
"onChange",
|
|
23
|
-
"value",
|
|
24
|
-
"checked",
|
|
25
|
-
],
|
|
26
|
-
},
|
|
10
|
+
argTypes: {
|
|
11
|
+
opened: { table: { disable: true } },
|
|
12
|
+
onClose: { table: { disable: true } },
|
|
13
|
+
defaultChecked: { table: { disable: true } },
|
|
27
14
|
},
|
|
28
15
|
};
|
|
29
16
|
|
|
30
17
|
export default meta;
|
|
18
|
+
|
|
31
19
|
type Story = StoryObj<typeof Modal>;
|
|
32
20
|
|
|
21
|
+
const DefaultWrapper = (args: ModalProps) => {
|
|
22
|
+
const [opened, setOpened] = useState(false);
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<Modal {...args} opened={opened} onClose={() => setOpened(false)}>
|
|
26
|
+
Please log in to continue accessing this feature.
|
|
27
|
+
<Modal.Footer>
|
|
28
|
+
<Button variant="outline" onClick={() => setOpened(false)}>
|
|
29
|
+
Cancel
|
|
30
|
+
</Button>
|
|
31
|
+
<Button onClick={() => setOpened(false)}>Confirm</Button>
|
|
32
|
+
</Modal.Footer>
|
|
33
|
+
</Modal>
|
|
34
|
+
<Button onClick={() => setOpened(true)}>Open Modal</Button>
|
|
35
|
+
</>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
33
39
|
export const Default: Story = {
|
|
34
|
-
|
|
40
|
+
args: {
|
|
41
|
+
title: "Authentication Required",
|
|
42
|
+
},
|
|
43
|
+
render: (args) => <DefaultWrapper {...args} />,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const ScrollingWrapper = (args: ModalProps) => {
|
|
47
|
+
const [opened, setOpened] = useState(false);
|
|
48
|
+
return (
|
|
49
|
+
<>
|
|
50
|
+
<Modal {...args} opened={opened} onClose={() => setOpened(false)}>
|
|
51
|
+
<p>
|
|
52
|
+
This modal demonstrates the dynamically injected scroll dividers. When
|
|
53
|
+
this body content overflows, the borders between the Header and Footer
|
|
54
|
+
automatically appear to define the scrolling boundary.
|
|
55
|
+
</p>
|
|
56
|
+
{Array(20)
|
|
57
|
+
.fill(0)
|
|
58
|
+
.map((_, i) => (
|
|
59
|
+
<p key={i}>Scrolling content block {i + 1}...</p>
|
|
60
|
+
))}
|
|
61
|
+
{/* The new Footer abstraction */}
|
|
62
|
+
<Modal.Footer>
|
|
63
|
+
<Button variant="outline" onClick={() => setOpened(false)}>
|
|
64
|
+
Decline
|
|
65
|
+
</Button>
|
|
66
|
+
<Button onClick={() => setOpened(false)}>Accept Terms</Button>
|
|
67
|
+
</Modal.Footer>
|
|
68
|
+
</Modal>
|
|
69
|
+
<Button onClick={() => setOpened(true)}>Open Scrolling Modal</Button>
|
|
70
|
+
</>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const ScrollingContent: Story = {
|
|
75
|
+
args: {
|
|
76
|
+
title: "Terms and Conditions",
|
|
77
|
+
},
|
|
78
|
+
render: (args) => <ScrollingWrapper {...args} />,
|
|
35
79
|
};
|