@saleor/macaw-ui 0.2.4

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.
Files changed (186) hide show
  1. package/README.md +40 -0
  2. package/dist/ActionBar/ActionBar.d.ts +8 -0
  3. package/dist/ActionBar/context.d.ts +9 -0
  4. package/dist/ActionBar/index.d.ts +2 -0
  5. package/dist/ActionBar/styles.d.ts +2 -0
  6. package/dist/Alert/Alert.d.ts +9 -0
  7. package/dist/Alert/index.d.ts +1 -0
  8. package/dist/Alert/styles.d.ts +2 -0
  9. package/dist/Backlink/Backlink.d.ts +6 -0
  10. package/dist/Backlink/context.d.ts +5 -0
  11. package/dist/Backlink/index.d.ts +2 -0
  12. package/dist/Backlink/styles.d.ts +2 -0
  13. package/dist/ConfirmButton/ConfirmButton.d.ts +11 -0
  14. package/dist/ConfirmButton/index.d.ts +1 -0
  15. package/dist/ConfirmButton/styles.d.ts +2 -0
  16. package/dist/Notification/Notification.d.ts +3 -0
  17. package/dist/Notification/index.d.ts +2 -0
  18. package/dist/Notification/styles.d.ts +2 -0
  19. package/dist/Notification/types.d.ts +16 -0
  20. package/dist/ResponsiveTable/ResponsiveTable.d.ts +8 -0
  21. package/dist/ResponsiveTable/index.d.ts +1 -0
  22. package/dist/ResponsiveTable/styles.d.ts +2 -0
  23. package/dist/Savebar/ButtonTooltipDecorator.d.ts +6 -0
  24. package/dist/Savebar/Savebar.d.ts +14 -0
  25. package/dist/Savebar/index.d.ts +1 -0
  26. package/dist/Savebar/styles.d.ts +2 -0
  27. package/dist/Sidebar/ExpandButton.d.ts +6 -0
  28. package/dist/Sidebar/MenuItem.d.ts +11 -0
  29. package/dist/Sidebar/Sidebar.d.ts +6 -0
  30. package/dist/Sidebar/fixtures.d.ts +2 -0
  31. package/dist/Sidebar/index.d.ts +4 -0
  32. package/dist/Sidebar/types.d.ts +16 -0
  33. package/dist/SidebarDrawer/MenuItemBtn.d.ts +7 -0
  34. package/dist/SidebarDrawer/SidebarDrawer.d.ts +4 -0
  35. package/dist/SidebarDrawer/index.d.ts +2 -0
  36. package/dist/SidebarDrawer/styles.d.ts +2 -0
  37. package/dist/SquareButton/SquareButton.d.ts +3 -0
  38. package/dist/SquareButton/index.d.ts +1 -0
  39. package/dist/Tooltip/Tooltip.d.ts +6 -0
  40. package/dist/Tooltip/index.d.ts +1 -0
  41. package/dist/Tooltip/styles.d.ts +3 -0
  42. package/dist/UserChipMenu/UserChipMenu.d.ts +8 -0
  43. package/dist/UserChipMenu/UserChipMenuItem.d.ts +6 -0
  44. package/dist/UserChipMenu/context.d.ts +4 -0
  45. package/dist/UserChipMenu/index.d.ts +2 -0
  46. package/dist/UserChipMenu/styles.d.ts +2 -0
  47. package/dist/extensions/index.d.ts +3 -0
  48. package/dist/extensions/sendMessage.d.ts +3 -0
  49. package/dist/extensions/types.d.ts +22 -0
  50. package/dist/extensions/useExtensionMessage.d.ts +2 -0
  51. package/dist/icons/ArrowDropdownIcon.d.ts +2 -0
  52. package/dist/icons/CheckboxCheckedIcon.d.ts +1 -0
  53. package/dist/icons/CheckboxIcon.d.ts +1 -0
  54. package/dist/icons/CheckboxIndeterminateIcon.d.ts +1 -0
  55. package/dist/icons/CompleteIcon.d.ts +2 -0
  56. package/dist/icons/InfoIcon.d.ts +2 -0
  57. package/dist/icons/Logo.d.ts +2 -0
  58. package/dist/icons/NotAllowedIcon.d.ts +2 -0
  59. package/dist/icons/NotAllowedInvertedIcon.d.ts +2 -0
  60. package/dist/icons/WarningIcon.d.ts +2 -0
  61. package/dist/icons/index.d.ts +9 -0
  62. package/dist/index.d.ts +15 -0
  63. package/dist/index.js +8 -0
  64. package/dist/localStorageKeys.d.ts +4 -0
  65. package/dist/macaw-ui.cjs.development.js +2582 -0
  66. package/dist/macaw-ui.cjs.development.js.map +1 -0
  67. package/dist/macaw-ui.cjs.production.min.js +2 -0
  68. package/dist/macaw-ui.cjs.production.min.js.map +1 -0
  69. package/dist/macaw-ui.esm.js +2536 -0
  70. package/dist/macaw-ui.esm.js.map +1 -0
  71. package/dist/theme/Baseline.d.ts +2 -0
  72. package/dist/theme/ThemeProvider.d.ts +17 -0
  73. package/dist/theme/context.d.ts +3 -0
  74. package/dist/theme/createSaleorTheme/createSaleorTheme.d.ts +3 -0
  75. package/dist/theme/createSaleorTheme/index.d.ts +2 -0
  76. package/dist/theme/createSaleorTheme/overrides/buttons.d.ts +3 -0
  77. package/dist/theme/createSaleorTheme/overrides/index.d.ts +3 -0
  78. package/dist/theme/createSaleorTheme/overrides/inputs.d.ts +3 -0
  79. package/dist/theme/createSaleorTheme/overrides/tables.d.ts +3 -0
  80. package/dist/theme/createSaleorTheme/palette.d.ts +2 -0
  81. package/dist/theme/createSaleorTheme/shadows.d.ts +2 -0
  82. package/dist/theme/createSaleorTheme/types.d.ts +53 -0
  83. package/dist/theme/index.d.ts +4 -0
  84. package/dist/theme/styles.d.ts +5 -0
  85. package/dist/theme/themes.d.ts +3 -0
  86. package/dist/theme/types.d.ts +6 -0
  87. package/dist/theme/utils.d.ts +1 -0
  88. package/dist/tools/useLocalStorage.d.ts +5 -0
  89. package/dist/tools/useWindowScroll.d.ts +5 -0
  90. package/dist/utils/Decorator.d.ts +4 -0
  91. package/package.json +117 -0
  92. package/src/ActionBar/ActionBar.stories.tsx +34 -0
  93. package/src/ActionBar/ActionBar.tsx +58 -0
  94. package/src/ActionBar/context.tsx +32 -0
  95. package/src/ActionBar/index.ts +2 -0
  96. package/src/ActionBar/styles.ts +27 -0
  97. package/src/Alert/Alert.stories.tsx +30 -0
  98. package/src/Alert/Alert.tsx +86 -0
  99. package/src/Alert/index.ts +1 -0
  100. package/src/Alert/styles.ts +46 -0
  101. package/src/Backlink/Backlink.stories.tsx +51 -0
  102. package/src/Backlink/Backlink.tsx +40 -0
  103. package/src/Backlink/context.tsx +27 -0
  104. package/src/Backlink/index.ts +2 -0
  105. package/src/Backlink/styles.ts +41 -0
  106. package/src/ConfirmButton/ConfirmButton.stories.tsx +72 -0
  107. package/src/ConfirmButton/ConfirmButton.tsx +119 -0
  108. package/src/ConfirmButton/index.ts +1 -0
  109. package/src/ConfirmButton/styles.ts +44 -0
  110. package/src/Notification/Notification.stories.tsx +42 -0
  111. package/src/Notification/Notification.tsx +98 -0
  112. package/src/Notification/index.ts +2 -0
  113. package/src/Notification/styles.ts +74 -0
  114. package/src/Notification/types.ts +18 -0
  115. package/src/ResponsiveTable/ResponsiveTable.tsx +24 -0
  116. package/src/ResponsiveTable/index.ts +1 -0
  117. package/src/ResponsiveTable/styles.ts +23 -0
  118. package/src/Savebar/ButtonTooltipDecorator.tsx +22 -0
  119. package/src/Savebar/Savebar.stories.tsx +57 -0
  120. package/src/Savebar/Savebar.tsx +79 -0
  121. package/src/Savebar/index.ts +1 -0
  122. package/src/Savebar/styles.ts +25 -0
  123. package/src/Sidebar/ExpandButton.tsx +44 -0
  124. package/src/Sidebar/MenuItem.tsx +217 -0
  125. package/src/Sidebar/Sidebar.stories.tsx +21 -0
  126. package/src/Sidebar/Sidebar.tsx +88 -0
  127. package/src/Sidebar/fixtures.ts +39 -0
  128. package/src/Sidebar/index.ts +4 -0
  129. package/src/Sidebar/types.ts +18 -0
  130. package/src/SidebarDrawer/MenuItemBtn.tsx +40 -0
  131. package/src/SidebarDrawer/SidebarDrawer.stories.tsx +13 -0
  132. package/src/SidebarDrawer/SidebarDrawer.tsx +113 -0
  133. package/src/SidebarDrawer/index.ts +2 -0
  134. package/src/SidebarDrawer/styles.ts +69 -0
  135. package/src/SquareButton/SquareButton.stories.tsx +15 -0
  136. package/src/SquareButton/SquareButton.tsx +35 -0
  137. package/src/SquareButton/index.ts +1 -0
  138. package/src/Tooltip/Tooltip.stories.tsx +19 -0
  139. package/src/Tooltip/Tooltip.tsx +25 -0
  140. package/src/Tooltip/index.ts +1 -0
  141. package/src/Tooltip/styles.ts +28 -0
  142. package/src/UserChipMenu/UserChipMenu.stories.tsx +40 -0
  143. package/src/UserChipMenu/UserChipMenu.tsx +113 -0
  144. package/src/UserChipMenu/UserChipMenuItem.tsx +33 -0
  145. package/src/UserChipMenu/context.ts +19 -0
  146. package/src/UserChipMenu/index.ts +2 -0
  147. package/src/UserChipMenu/styles.ts +65 -0
  148. package/src/assets/placeholder_64x64.png +0 -0
  149. package/src/extensions/index.ts +3 -0
  150. package/src/extensions/sendMessage.ts +23 -0
  151. package/src/extensions/types.ts +26 -0
  152. package/src/extensions/useExtensionMessage.ts +13 -0
  153. package/src/icons/ArrowDropdownIcon.tsx +11 -0
  154. package/src/icons/CheckboxCheckedIcon.tsx +15 -0
  155. package/src/icons/CheckboxIcon.tsx +7 -0
  156. package/src/icons/CheckboxIndeterminateIcon.tsx +17 -0
  157. package/src/icons/CompleteIcon.tsx +25 -0
  158. package/src/icons/InfoIcon.tsx +23 -0
  159. package/src/icons/Logo.tsx +32 -0
  160. package/src/icons/NotAllowedIcon.tsx +25 -0
  161. package/src/icons/NotAllowedInvertedIcon.tsx +25 -0
  162. package/src/icons/WarningIcon.tsx +23 -0
  163. package/src/icons/index.ts +9 -0
  164. package/src/index.tsx +15 -0
  165. package/src/localStorageKeys.ts +4 -0
  166. package/src/theme/Baseline.tsx +30 -0
  167. package/src/theme/ThemeProvider.tsx +84 -0
  168. package/src/theme/context.ts +8 -0
  169. package/src/theme/createSaleorTheme/createSaleorTheme.ts +267 -0
  170. package/src/theme/createSaleorTheme/index.ts +2 -0
  171. package/src/theme/createSaleorTheme/overrides/buttons.ts +94 -0
  172. package/src/theme/createSaleorTheme/overrides/index.ts +15 -0
  173. package/src/theme/createSaleorTheme/overrides/inputs.ts +149 -0
  174. package/src/theme/createSaleorTheme/overrides/tables.ts +74 -0
  175. package/src/theme/createSaleorTheme/palette.ts +38 -0
  176. package/src/theme/createSaleorTheme/shadows.ts +46 -0
  177. package/src/theme/createSaleorTheme/types.ts +84 -0
  178. package/src/theme/index.ts +4 -0
  179. package/src/theme/styles.ts +40 -0
  180. package/src/theme/themes.ts +113 -0
  181. package/src/theme/types.ts +7 -0
  182. package/src/theme/utils.test.ts +43 -0
  183. package/src/theme/utils.ts +13 -0
  184. package/src/tools/useLocalStorage.ts +56 -0
  185. package/src/tools/useWindowScroll.ts +26 -0
  186. package/src/utils/Decorator.tsx +23 -0
@@ -0,0 +1,217 @@
1
+ import ClickAwayListener from "@material-ui/core/ClickAwayListener";
2
+ import Paper from "@material-ui/core/Paper";
3
+ import Popper from "@material-ui/core/Popper";
4
+ import { fade } from "@material-ui/core/styles";
5
+ import Typography from "@material-ui/core/Typography";
6
+ import clsx from "clsx";
7
+ import React from "react";
8
+ import SVG from "react-inlinesvg";
9
+
10
+ import { makeStyles } from "../theme";
11
+ import { SidebarMenuItem } from "./types";
12
+
13
+ export interface MenuItemProps {
14
+ active: boolean;
15
+ isMenuShrunk: boolean;
16
+ menuItem: SidebarMenuItem;
17
+ onClick: (url: string) => void;
18
+ }
19
+
20
+ export const menuWidth = 210;
21
+ export const shrunkMenuWidth = 72;
22
+
23
+ const useStyles = makeStyles(
24
+ (theme) => ({
25
+ hideLabel: {
26
+ "&$label": {
27
+ opacity: 0,
28
+ },
29
+ },
30
+ icon: {
31
+ "& svg": {
32
+ height: 24,
33
+ width: 24,
34
+ },
35
+ marginRight: theme.spacing(1.5),
36
+ transition: theme.transitions.duration.shortest + "ms",
37
+ },
38
+ label: {
39
+ cursor: "pointer",
40
+ display: "block",
41
+ fontSize: 16,
42
+ fontWeight: "bold",
43
+ opacity: 1,
44
+ transition: theme.transitions.duration.shortest + "ms",
45
+ },
46
+ labelRoot: {
47
+ position: "absolute",
48
+ left: 72,
49
+ width: 200,
50
+ textAlign: "left",
51
+ pointerEvents: "none",
52
+ },
53
+ menuItemBtn: {
54
+ "&:focus": {
55
+ color: theme.palette.primary.main,
56
+ outline: 0,
57
+ },
58
+ background: "none",
59
+ border: "none",
60
+ color: "inherit",
61
+ cursor: "pointer",
62
+ display: "inline-flex",
63
+ margin: 0,
64
+ padding: 0,
65
+ },
66
+ paper: {
67
+ borderRadius: 16,
68
+ boxShadow: "0px 6px 30px rgba(0, 0, 0, 0.16)",
69
+ cursor: "default",
70
+ padding: theme.spacing(3),
71
+ textAlign: "left",
72
+ },
73
+ popper: {
74
+ marginLeft: theme.spacing(3),
75
+ zIndex: 2,
76
+ },
77
+ root: {
78
+ "&:hover, &:focus": {
79
+ color: theme.palette.primary.main,
80
+ outline: 0,
81
+ },
82
+ borderBottomRightRadius: 100,
83
+ borderTopRightRadius: 100,
84
+ color: fade(theme.palette.text.primary, 0.6),
85
+ cursor: "pointer",
86
+ display: "flex",
87
+ height: 56,
88
+ marginBottom: theme.spacing(),
89
+ overflow: "hidden",
90
+ padding: theme.spacing(2, 3, 2, 3.5),
91
+ transition: theme.transitions.duration.shortest + "ms",
92
+ width: shrunkMenuWidth,
93
+ },
94
+ rootActive: {
95
+ "&$root": {
96
+ background: theme.palette.background.paper,
97
+ boxShadow: "0px 6px 30px rgba(0, 0, 0, 0.16)",
98
+ color: theme.palette.primary.main,
99
+ },
100
+ },
101
+ rootExpanded: {
102
+ width: menuWidth,
103
+ },
104
+ subMenuLabel: {
105
+ "&$label": {
106
+ "&:not(:last-child)": {
107
+ marginBottom: theme.spacing(2),
108
+ },
109
+ },
110
+ "&:hover, &:focus": {
111
+ color: theme.palette.primary.main,
112
+ outline: 0,
113
+ },
114
+ background: "none",
115
+ border: "none",
116
+ color: fade(theme.palette.text.primary, 0.6),
117
+ padding: 0,
118
+ textAlign: "left",
119
+ textDecoration: "none",
120
+ whiteSpace: "nowrap",
121
+ },
122
+ }),
123
+ {
124
+ name: "MenuItem",
125
+ }
126
+ );
127
+
128
+ export const MenuItem: React.FC<MenuItemProps> = ({
129
+ active,
130
+ menuItem,
131
+ isMenuShrunk,
132
+ onClick,
133
+ }) => {
134
+ const classes = useStyles({});
135
+ const [open, setOpen] = React.useState(false);
136
+ const anchor = React.useRef<HTMLDivElement>(null);
137
+
138
+ const handleClick = (event: React.MouseEvent, menuItem: SidebarMenuItem) => {
139
+ event.stopPropagation();
140
+ if (menuItem.children) {
141
+ setOpen(true);
142
+ } else {
143
+ onClick(menuItem.url!);
144
+ setOpen(false);
145
+ }
146
+ };
147
+
148
+ return (
149
+ <div
150
+ className={clsx(classes.root, {
151
+ [classes.rootActive]: active,
152
+ [classes.rootExpanded]: !isMenuShrunk,
153
+ })}
154
+ ref={anchor}
155
+ onClick={(event) => handleClick(event, menuItem)}
156
+ >
157
+ <button
158
+ className={classes.menuItemBtn}
159
+ data-test="menu-item-label"
160
+ data-test-id={menuItem.id}
161
+ >
162
+ {menuItem.iconSrc && (
163
+ <SVG className={classes.icon} src={menuItem.iconSrc} />
164
+ )}
165
+ <Typography
166
+ aria-label={menuItem.ariaLabel}
167
+ className={clsx(classes.label, classes.labelRoot, {
168
+ [classes.hideLabel]: isMenuShrunk,
169
+ })}
170
+ variant="body2"
171
+ >
172
+ {menuItem.label}
173
+ </Typography>
174
+ </button>
175
+ {menuItem.children && (
176
+ <Popper
177
+ className={classes.popper}
178
+ open={open}
179
+ anchorEl={anchor.current}
180
+ transition
181
+ disablePortal
182
+ placement="right-start"
183
+ >
184
+ <ClickAwayListener onClickAway={() => setOpen(false)}>
185
+ <Paper className={classes.paper}>
186
+ {menuItem.children.map((subMenuItem) => {
187
+ const linkProps = subMenuItem.external
188
+ ? { href: subMenuItem.url, target: "_blank" }
189
+ : {};
190
+
191
+ return (
192
+ <Typography
193
+ aria-label={subMenuItem.ariaLabel}
194
+ component={subMenuItem.external ? "a" : "button"}
195
+ className={clsx(classes.label, classes.subMenuLabel)}
196
+ key={subMenuItem.url}
197
+ onClick={(event: React.MouseEvent<any>) =>
198
+ handleClick(event, subMenuItem)
199
+ }
200
+ data-test="submenu-item-label"
201
+ data-test-id={subMenuItem.id}
202
+ variant="body2"
203
+ {...linkProps}
204
+ >
205
+ {subMenuItem.label}
206
+ </Typography>
207
+ );
208
+ })}
209
+ </Paper>
210
+ </ClickAwayListener>
211
+ </Popper>
212
+ )}
213
+ </div>
214
+ );
215
+ };
216
+
217
+ MenuItem.displayName = "MenuItem";
@@ -0,0 +1,21 @@
1
+ import { Meta, Story } from "@storybook/react";
2
+ import React from "react";
3
+
4
+ import { SquareButton } from "../SquareButton";
5
+ import * as fixtures from "./fixtures";
6
+ import { Sidebar, SidebarProps } from "./Sidebar";
7
+
8
+ const props: SidebarProps = {
9
+ active: "menu1",
10
+ menuItems: fixtures.menu,
11
+ onMenuItemClick: () => undefined,
12
+ };
13
+
14
+ export const Default: Story = () => <Sidebar {...props} />;
15
+ export const WithToolbar: Story = () => (
16
+ <Sidebar {...props} toolbar={<SquareButton>tool</SquareButton>} />
17
+ );
18
+
19
+ export default {
20
+ title: "Sidebar",
21
+ } as Meta;
@@ -0,0 +1,88 @@
1
+ import clsx from "clsx";
2
+ import React from "react";
3
+
4
+ import { Logo } from "../icons/Logo";
5
+ import { localStorageKeys } from "../localStorageKeys";
6
+ import { makeStyles } from "../theme";
7
+ import useLocalStorage from "../tools/useLocalStorage";
8
+ import { ExpandButton } from "./ExpandButton";
9
+ import { MenuItem, menuWidth, shrunkMenuWidth } from "./MenuItem";
10
+ import { BaseSidebarProps } from "./types";
11
+
12
+ const useStyles = makeStyles(
13
+ (theme) => ({
14
+ expandButton: {
15
+ marginLeft: theme.spacing(2),
16
+ },
17
+ float: {
18
+ height: "100vh",
19
+ position: "fixed",
20
+ },
21
+ logo: {
22
+ margin: `36px 0 ${theme.spacing(3)} ${theme.spacing(3.5)}`,
23
+ },
24
+ root: {
25
+ transition: "width 0.5s ease",
26
+ width: menuWidth,
27
+ zIndex: 100,
28
+ },
29
+ rootShrink: {
30
+ width: shrunkMenuWidth,
31
+ },
32
+ toolbarContainer: {
33
+ margin: theme.spacing(1, 0, 1, 2),
34
+ },
35
+ }),
36
+ {
37
+ name: "SideBar",
38
+ }
39
+ );
40
+
41
+ export interface SidebarProps extends BaseSidebarProps {
42
+ active: string;
43
+ }
44
+
45
+ export const Sidebar: React.FC<SidebarProps> = ({
46
+ active,
47
+ menuItems,
48
+ toolbar,
49
+ onMenuItemClick,
50
+ }) => {
51
+ const classes = useStyles({});
52
+ const { value: isShrunkStr, setValue: setShrink } = useLocalStorage(
53
+ localStorageKeys.menuShrink,
54
+ false.toString()
55
+ );
56
+ const isShrunk = isShrunkStr === "true";
57
+
58
+ return (
59
+ <div
60
+ className={clsx(classes.root, {
61
+ [classes.rootShrink]: isShrunk,
62
+ })}
63
+ >
64
+ <div className={classes.float}>
65
+ <div className={classes.logo}>
66
+ <Logo />
67
+ </div>
68
+ {menuItems.map((menuItem) => (
69
+ <MenuItem
70
+ active={active === menuItem.id}
71
+ isMenuShrunk={isShrunk}
72
+ menuItem={menuItem}
73
+ onClick={onMenuItemClick}
74
+ key={menuItem.ariaLabel}
75
+ />
76
+ ))}
77
+ {toolbar && <div className={classes.toolbarContainer}>{toolbar}</div>}
78
+ <ExpandButton
79
+ className={classes.expandButton}
80
+ isShrunk={isShrunk}
81
+ onClick={() => setShrink((!isShrunk).toString())}
82
+ />
83
+ </div>
84
+ </div>
85
+ );
86
+ };
87
+
88
+ Sidebar.displayName = "SideBar";
@@ -0,0 +1,39 @@
1
+ import homeIcon from "../../stories/assets/menu-home-icon.svg";
2
+ import { SidebarMenuItem } from "./types";
3
+
4
+ export const menu: SidebarMenuItem[] = [
5
+ {
6
+ ariaLabel: "Menu 1",
7
+ id: "menu1",
8
+ label: "Menu 1",
9
+ iconSrc: homeIcon,
10
+ url: "/section1/",
11
+ },
12
+ {
13
+ ariaLabel: "Menu 2",
14
+ id: "menu2",
15
+ label: "Menu 2",
16
+ iconSrc: homeIcon,
17
+ children: [
18
+ {
19
+ ariaLabel: "Menu 2.1",
20
+ id: "menu21",
21
+ label: "Menu 21",
22
+ url: "/section21/",
23
+ },
24
+ {
25
+ ariaLabel: "Menu 2.2",
26
+ id: "menu22",
27
+ label: "Menu 22",
28
+ url: "/section22/",
29
+ },
30
+ {
31
+ ariaLabel: "Menu 2.3",
32
+ id: "menu23",
33
+ label: "Menu 22 - external",
34
+ url: "http://example.com",
35
+ external: true,
36
+ },
37
+ ],
38
+ },
39
+ ];
@@ -0,0 +1,4 @@
1
+ export * from "./Sidebar";
2
+ export * from "./MenuItem";
3
+ export * from "./types";
4
+ export * from "./ExpandButton";
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+
3
+ export interface SidebarMenuItem {
4
+ ariaLabel: string;
5
+ children?: SidebarMenuItem[];
6
+ iconSrc?: string;
7
+ label: string;
8
+ id: string;
9
+ url?: string;
10
+ external?: boolean;
11
+ }
12
+
13
+ export interface BaseSidebarProps {
14
+ className?: string;
15
+ menuItems: SidebarMenuItem[];
16
+ toolbar?: React.ReactNode;
17
+ onMenuItemClick: (url: string) => void;
18
+ }
@@ -0,0 +1,40 @@
1
+ import Typography from "@material-ui/core/Typography";
2
+ import React from "react";
3
+ import SVG from "react-inlinesvg";
4
+
5
+ import { SidebarMenuItem } from "../Sidebar/types";
6
+ import useStyles from "./styles";
7
+
8
+ export interface MenuItemBtnProps {
9
+ menuItem: SidebarMenuItem;
10
+ onClick: (url: string) => void;
11
+ }
12
+ export const MenuItemBtn: React.FC<MenuItemBtnProps> = ({
13
+ menuItem,
14
+ onClick,
15
+ }) => {
16
+ const classes = useStyles();
17
+ const linkProps = menuItem.external
18
+ ? { href: menuItem.url, target: "_blank" }
19
+ : {};
20
+ const Component = menuItem.external ? "a" : "button";
21
+
22
+ return (
23
+ <Component
24
+ className={classes.menuItemBtn}
25
+ data-test="menu-item-label"
26
+ data-test-id={menuItem.id}
27
+ onClick={() => onClick(menuItem.url!)}
28
+ {...linkProps}
29
+ >
30
+ {menuItem.iconSrc && (
31
+ <SVG className={classes.icon} src={menuItem.iconSrc} />
32
+ )}
33
+ <Typography aria-label={menuItem.ariaLabel} className={classes.label}>
34
+ {menuItem.label}
35
+ </Typography>
36
+ </Component>
37
+ );
38
+ };
39
+
40
+ MenuItemBtn.displayName = "MenuItemBtn";
@@ -0,0 +1,13 @@
1
+ import { Meta, Story } from "@storybook/react";
2
+ import React from "react";
3
+
4
+ import * as fixtures from "../Sidebar/fixtures";
5
+ import { SidebarDrawer } from "./SidebarDrawer";
6
+
7
+ export const Default: Story = () => (
8
+ <SidebarDrawer menuItems={fixtures.menu} onMenuItemClick={() => undefined} />
9
+ );
10
+
11
+ export default {
12
+ title: "Sidebar - mobile",
13
+ } as Meta;
@@ -0,0 +1,113 @@
1
+ import Drawer from "@material-ui/core/Drawer";
2
+ import Typography from "@material-ui/core/Typography";
3
+ import ArrowLeftIcon from "@material-ui/icons/ArrowLeft";
4
+ import MenuIcon from "@material-ui/icons/Menu";
5
+ import clsx from "clsx";
6
+ import React from "react";
7
+ import SVG from "react-inlinesvg";
8
+
9
+ import { Logo } from "../icons/Logo";
10
+ import { BaseSidebarProps, SidebarMenuItem } from "../Sidebar/types";
11
+ import { SquareButton } from "../SquareButton";
12
+ import { MenuItemBtn } from "./MenuItemBtn";
13
+ import useStyles from "./styles";
14
+
15
+ export type SideBarDrawerProps = BaseSidebarProps;
16
+
17
+ export const SidebarDrawer: React.FC<SideBarDrawerProps> = ({
18
+ menuItems,
19
+ onMenuItemClick,
20
+ }) => {
21
+ const [isOpened, setOpened] = React.useState(false);
22
+ const classes = useStyles({});
23
+ const [activeMenu, setActiveMenu] = React.useState<SidebarMenuItem | null>(
24
+ null
25
+ );
26
+ const [showSubmenu, setShowSubmenu] = React.useState(false);
27
+ const container = React.useRef<HTMLDivElement>(null);
28
+
29
+ const handleMenuItemClick = (url: string) => {
30
+ setOpened(false);
31
+ setShowSubmenu(false);
32
+ onMenuItemClick(url);
33
+ };
34
+
35
+ const handleMenuItemWithChildrenClick = (menuItem: SidebarMenuItem) => {
36
+ setActiveMenu(menuItem);
37
+ setShowSubmenu(true);
38
+ container.current?.scrollTo({
39
+ top: 0,
40
+ });
41
+ };
42
+
43
+ return (
44
+ <>
45
+ <SquareButton onClick={() => setOpened(true)}>
46
+ <MenuIcon />
47
+ </SquareButton>
48
+ <Drawer
49
+ classes={{
50
+ paper: classes.root,
51
+ }}
52
+ open={isOpened}
53
+ onClose={() => setOpened(false)}
54
+ >
55
+ <div
56
+ className={clsx(classes.container, {
57
+ [classes.containerSubMenu]: showSubmenu,
58
+ })}
59
+ ref={container}
60
+ >
61
+ <div
62
+ className={clsx(classes.innerContainer, {
63
+ [classes.secondaryContentActive]: showSubmenu,
64
+ })}
65
+ >
66
+ <div className={classes.content}>
67
+ <div className={classes.logo}>
68
+ <Logo />
69
+ </div>
70
+ {menuItems.map((menuItem) => (
71
+ <MenuItemBtn
72
+ menuItem={menuItem}
73
+ onClick={
74
+ menuItem.children
75
+ ? () => handleMenuItemWithChildrenClick(menuItem)
76
+ : handleMenuItemClick
77
+ }
78
+ key={menuItem.ariaLabel}
79
+ />
80
+ ))}
81
+ </div>
82
+ {activeMenu && (
83
+ <div className={classes.content}>
84
+ <div className={classes.subMenuTopBar}>
85
+ <div className={classes.activeMenuLabel}>
86
+ {activeMenu.iconSrc && (
87
+ <SVG className={classes.icon} src={activeMenu.iconSrc} />
88
+ )}
89
+ <Typography className={classes.label}>
90
+ {activeMenu.label}
91
+ </Typography>
92
+ </div>
93
+ <SquareButton onClick={() => setShowSubmenu(false)}>
94
+ <ArrowLeftIcon />
95
+ </SquareButton>
96
+ </div>
97
+ {activeMenu.children?.map((subMenuItem) => (
98
+ <MenuItemBtn
99
+ menuItem={subMenuItem}
100
+ onClick={handleMenuItemClick}
101
+ key={subMenuItem.ariaLabel}
102
+ />
103
+ ))}
104
+ </div>
105
+ )}
106
+ </div>
107
+ </div>
108
+ </Drawer>
109
+ </>
110
+ );
111
+ };
112
+
113
+ SidebarDrawer.displayName = "SideBarDrawer";
@@ -0,0 +1,2 @@
1
+ export * from "./MenuItemBtn";
2
+ export * from "./SidebarDrawer";
@@ -0,0 +1,69 @@
1
+ import { makeStyles } from "../theme";
2
+
3
+ const useStyles = makeStyles(
4
+ (theme) => ({
5
+ activeMenuLabel: {
6
+ display: "flex",
7
+ },
8
+ container: {
9
+ overflowX: "hidden",
10
+ width: "100%",
11
+ },
12
+ containerSubMenu: {
13
+ "&$container": {
14
+ overflow: "hidden",
15
+ },
16
+ },
17
+ content: {
18
+ width: "50%",
19
+ },
20
+ icon: {
21
+ marginRight: theme.spacing(2),
22
+ },
23
+ innerContainer: {
24
+ display: "flex",
25
+ position: "relative",
26
+ right: 0,
27
+ transition: theme.transitions.duration.short + "ms",
28
+ width: "200%",
29
+ },
30
+ label: {
31
+ fontWeight: "bold",
32
+ },
33
+ logo: {
34
+ display: "block",
35
+ marginBottom: theme.spacing(4),
36
+ },
37
+ menuItemBtn: {
38
+ alignItems: "center",
39
+ background: "none",
40
+ border: "none",
41
+ color: theme.palette.text.secondary,
42
+ display: "flex",
43
+ marginBottom: theme.spacing(3),
44
+ padding: 0,
45
+ textDecoration: "none",
46
+ },
47
+ root: {
48
+ background: theme.palette.background.default,
49
+ borderBottomRightRadius: 32,
50
+ borderTopRightRadius: 32,
51
+ padding: theme.spacing(3),
52
+ width: 260,
53
+ },
54
+ secondaryContentActive: {
55
+ right: "100%",
56
+ },
57
+ subMenuTopBar: {
58
+ alignItems: "center",
59
+ display: "flex",
60
+ justifyContent: "space-between",
61
+ marginBottom: theme.spacing(3),
62
+ },
63
+ }),
64
+ {
65
+ name: "SideBarDrawer",
66
+ }
67
+ );
68
+
69
+ export default useStyles;
@@ -0,0 +1,15 @@
1
+ import CloseIcon from "@material-ui/icons/Close";
2
+ import { Meta, Story } from "@storybook/react";
3
+ import React from "react";
4
+
5
+ import { SquareButton } from "./SquareButton";
6
+
7
+ export const Default: Story = () => (
8
+ <SquareButton>
9
+ <CloseIcon />
10
+ </SquareButton>
11
+ );
12
+
13
+ export default {
14
+ title: "Square button",
15
+ } as Meta;
@@ -0,0 +1,35 @@
1
+ import ButtonBase, { ButtonBaseProps } from "@material-ui/core/ButtonBase";
2
+ import clsx from "clsx";
3
+ import React from "react";
4
+
5
+ import { makeStyles } from "../theme";
6
+
7
+ const useStyles = makeStyles(
8
+ (theme) => ({
9
+ root: {
10
+ "&:hover, &:focus": {
11
+ background: "#daedeb",
12
+ },
13
+ background: theme.palette.background.paper,
14
+ borderRadius: 16,
15
+ color: theme.palette.primary.main,
16
+ height: 48,
17
+ transition: theme.transitions.duration.shortest + "ms",
18
+ width: 48,
19
+ },
20
+ }),
21
+ {
22
+ name: "ExpandButton",
23
+ }
24
+ );
25
+
26
+ export const SquareButton: React.FC<ButtonBaseProps> = ({
27
+ className,
28
+ ...rest
29
+ }) => {
30
+ const classes = useStyles({});
31
+
32
+ return <ButtonBase className={clsx(classes.root, className)} {...rest} />;
33
+ };
34
+
35
+ SquareButton.displayName = "SquareButton";
@@ -0,0 +1 @@
1
+ export * from "./SquareButton";