@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
package/package.json ADDED
@@ -0,0 +1,117 @@
1
+ {
2
+ "version": "0.2.4",
3
+ "license": "CC-BY-4.0",
4
+ "main": "dist/index.js",
5
+ "homepage": "https://macaw-ui.vercel.app/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git://github.com/mirumee/macaw-ui.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/mirumee/macaw-ui/issues"
12
+ },
13
+ "keywords": [
14
+ "saleor",
15
+ "macaw",
16
+ "macaw-ui",
17
+ "react",
18
+ "ui components"
19
+ ],
20
+ "typings": "dist/index.d.ts",
21
+ "files": [
22
+ "dist",
23
+ "src"
24
+ ],
25
+ "engines": {
26
+ "node": ">=10"
27
+ },
28
+ "scripts": {
29
+ "start": "tsdx watch",
30
+ "build": "tsdx build --tsconfig ./tsconfig.prod.json",
31
+ "test": "tsdx test --passWithNoTests",
32
+ "lint": "tsdx lint src",
33
+ "prepare": "npm run build",
34
+ "size": "size-limit",
35
+ "analyze": "size-limit --why",
36
+ "storybook": "start-storybook -p 6006",
37
+ "build-storybook": "build-storybook",
38
+ "release": "np"
39
+ },
40
+ "peerDependencies": {
41
+ "@material-ui/core": "^4.11.2",
42
+ "@material-ui/icons": "^4.11.2",
43
+ "@material-ui/lab": "^4.0.0-alpha.58",
44
+ "react": "^16.8.0 || ^17.0.0",
45
+ "react-helmet": "^6.1.0"
46
+ },
47
+ "husky": {
48
+ "hooks": {
49
+ "pre-commit": "tsdx lint",
50
+ "pre-push": "tsdx lint"
51
+ }
52
+ },
53
+ "np": {
54
+ "yarn": false
55
+ },
56
+ "prettier": {
57
+ "printWidth": 80,
58
+ "semi": true,
59
+ "singleQuote": false,
60
+ "trailingComma": "es5"
61
+ },
62
+ "name": "@saleor/macaw-ui",
63
+ "description": "Saleor's UI component library",
64
+ "author": "Saleor Commerce",
65
+ "module": "dist/macaw-ui.esm.js",
66
+ "private": false,
67
+ "publishConfig": {
68
+ "access": "public"
69
+ },
70
+ "sideEffects": false,
71
+ "size-limit": [
72
+ {
73
+ "path": "dist/macaw-ui.cjs.production.min.js",
74
+ "limit": "45 KB"
75
+ },
76
+ {
77
+ "path": "dist/macaw-ui.esm.js",
78
+ "limit": "25 KB"
79
+ }
80
+ ],
81
+ "devDependencies": {
82
+ "@babel/core": "^7.14.0",
83
+ "@material-ui/core": "^4.11.2",
84
+ "@material-ui/icons": "^4.11.2",
85
+ "@material-ui/lab": "^4.0.0-alpha.58",
86
+ "@size-limit/preset-small-lib": "^4.10.2",
87
+ "@storybook/addon-essentials": "^6.2.9",
88
+ "@storybook/addon-info": "^5.3.21",
89
+ "@storybook/addon-links": "^6.2.9",
90
+ "@storybook/addons": "^6.2.9",
91
+ "@storybook/react": "^6.2.9",
92
+ "@types/lodash": "^4.14.170",
93
+ "@types/react": "^17.0.5",
94
+ "@types/react-dom": "^17.0.4",
95
+ "@types/react-helmet": "^6.1.1",
96
+ "@types/react-inlinesvg": "^1.0.0",
97
+ "babel-loader": "^8.2.2",
98
+ "babel-plugin-import": "^1.13.3",
99
+ "eslint-plugin-simple-import-sort": "^5.0.3",
100
+ "husky": "^6.0.0",
101
+ "np": "^7.5.0",
102
+ "react": "^16.8.0 || ^17.0.0",
103
+ "react-dom": "^16.8.0 || ^17.0.0",
104
+ "react-is": "^17.0.2",
105
+ "rollup-plugin-svg": "^2.0.0",
106
+ "size-limit": "^4.10.2",
107
+ "tsdx": "^0.14.1",
108
+ "tslib": "^2.2.0",
109
+ "typescript": "^4.2.4"
110
+ },
111
+ "dependencies": {
112
+ "clsx": "^1.1.1",
113
+ "lodash": "^4.17.21",
114
+ "lodash-es": "^4.17.21",
115
+ "react-inlinesvg": "^2.3.0"
116
+ }
117
+ }
@@ -0,0 +1,34 @@
1
+ import { Meta, Story } from "@storybook/react";
2
+ import React from "react";
3
+
4
+ import { ConfirmButton, ConfirmButtonLabels } from "../ConfirmButton";
5
+ import { ActionBar } from "./ActionBar";
6
+ import { useActionBar } from "./context";
7
+
8
+ const Wrapper: React.FC = ({ children }) => {
9
+ const { anchor } = useActionBar();
10
+
11
+ return <div ref={anchor}>{children}</div>;
12
+ };
13
+
14
+ const labels: ConfirmButtonLabels = {
15
+ confirm: "Confirm",
16
+ error: "Error",
17
+ };
18
+
19
+ export const WithContent: Story = () => (
20
+ <ActionBar disabled={false} state="default">
21
+ <ConfirmButton labels={labels} transitionState="default" />
22
+ </ActionBar>
23
+ );
24
+
25
+ export default {
26
+ title: "ActionBar",
27
+ decorators: [
28
+ (Story) => (
29
+ <Wrapper>
30
+ <Story />
31
+ </Wrapper>
32
+ ),
33
+ ],
34
+ } as Meta;
@@ -0,0 +1,58 @@
1
+ import Card from "@material-ui/core/Card";
2
+ import CardContent from "@material-ui/core/CardContent";
3
+ import Container from "@material-ui/core/Container";
4
+ import Portal from "@material-ui/core/Portal";
5
+ import React from "react";
6
+
7
+ import { ConfirmButtonTransitionState } from "../ConfirmButton";
8
+ import useWindowScroll from "../tools/useWindowScroll";
9
+ import { useActionBar } from "./context";
10
+ import useStyles from "./styles";
11
+
12
+ export interface ActionBarProps {
13
+ disabled: boolean;
14
+ state: ConfirmButtonTransitionState;
15
+ children: React.ReactNode[] | React.ReactNode;
16
+ }
17
+
18
+ export const ActionBar: React.FC<ActionBarProps> = ({
19
+ disabled,
20
+ children,
21
+ state,
22
+ ...rest
23
+ }) => {
24
+ const classes = useStyles();
25
+
26
+ const { anchor, docked, setDocked } = useActionBar();
27
+ const scrollPosition = useWindowScroll();
28
+
29
+ React.useEffect(() => {
30
+ if (!disabled && state !== "loading") {
31
+ setDocked(false);
32
+ }
33
+ }, [disabled, state, setDocked]);
34
+ React.useEffect(() => () => setDocked(true), [setDocked]);
35
+
36
+ const scrolledToBottom =
37
+ scrollPosition.y + window.innerHeight >= document.body.scrollHeight;
38
+
39
+ if (!anchor.current) {
40
+ return null;
41
+ }
42
+
43
+ return (
44
+ <Portal container={anchor.current}>
45
+ <div className={classes.root} {...rest}>
46
+ <Container maxWidth="lg">
47
+ <Card
48
+ className={classes.paper}
49
+ elevation={!(docked || scrolledToBottom) ? 16 : 0}
50
+ >
51
+ <CardContent className={classes.content}>{children}</CardContent>
52
+ </Card>
53
+ </Container>
54
+ </div>
55
+ </Portal>
56
+ );
57
+ };
58
+ ActionBar.displayName = "ActionBar";
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+
3
+ export interface ActionBarContextType {
4
+ anchor: React.RefObject<HTMLDivElement>;
5
+ docked: boolean;
6
+ setDocked: (docked: boolean) => void;
7
+ }
8
+
9
+ export const ActionBarContext = React.createContext<
10
+ ActionBarContextType | undefined
11
+ >(undefined);
12
+ ActionBarContext.displayName = "ActionBarContext";
13
+
14
+ export const useActionBar = () => {
15
+ const ctx = React.useContext(ActionBarContext);
16
+ if (ctx === undefined) {
17
+ throw new Error("useActionBar must be used within a ActionBarContext");
18
+ }
19
+
20
+ return ctx;
21
+ };
22
+
23
+ export const ActionBarProvider: React.FC = ({ children }) => {
24
+ const [docked, setDocked] = React.useState(true);
25
+ const anchor = React.useRef<HTMLDivElement | null>(null);
26
+
27
+ return (
28
+ <ActionBarContext.Provider value={{ anchor, docked, setDocked }}>
29
+ {children}
30
+ </ActionBarContext.Provider>
31
+ );
32
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./ActionBar";
2
+ export * from "./context";
@@ -0,0 +1,27 @@
1
+ import { makeStyles } from "../theme";
2
+
3
+ const useStyles = makeStyles(
4
+ (theme) => ({
5
+ content: {
6
+ "&:last-child": {
7
+ paddingBottom: theme.spacing(2),
8
+ },
9
+ display: "flex",
10
+ paddingBottom: theme.spacing(2),
11
+ paddingTop: theme.spacing(2),
12
+ [theme.breakpoints.down("sm")]: {
13
+ marginTop: theme.spacing(1),
14
+ },
15
+ },
16
+ paper: {
17
+ borderBottomLeftRadius: 0,
18
+ borderBottomRightRadius: 0,
19
+ },
20
+ root: {
21
+ height: 70,
22
+ },
23
+ }),
24
+ { name: "Savebar" }
25
+ );
26
+
27
+ export default useStyles;
@@ -0,0 +1,30 @@
1
+ import { Meta, Story } from "@storybook/react";
2
+ import React from "react";
3
+
4
+ import { Alert, AlertProps } from "./Alert";
5
+
6
+ const props: AlertProps = {
7
+ close: false,
8
+ title: "Title",
9
+ variant: "info",
10
+ };
11
+
12
+ export const Info: Story = () => <Alert {...props} />;
13
+ export const Warn: Story = () => <Alert {...props} variant="warning" />;
14
+ export const Success: Story = () => <Alert {...props} variant="success" />;
15
+ export const Error: Story = () => <Alert {...props} variant="error" />;
16
+ export const WithClose: Story = () => <Alert {...props} close />;
17
+ export const WithContent: Story = () => (
18
+ <Alert {...props}>
19
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
20
+ </Alert>
21
+ );
22
+ export const WithContentAndClose: Story = () => (
23
+ <Alert {...props} close>
24
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit.
25
+ </Alert>
26
+ );
27
+
28
+ export default {
29
+ title: "Alert",
30
+ } as Meta;
@@ -0,0 +1,86 @@
1
+ import Card from "@material-ui/core/Card";
2
+ import CardContent from "@material-ui/core/CardContent";
3
+ import IconButton from "@material-ui/core/IconButton";
4
+ import Typography from "@material-ui/core/Typography";
5
+ import CloseIcon from "@material-ui/icons/Close";
6
+ import clsx from "clsx";
7
+ import React from "react";
8
+
9
+ import { CompleteIcon, InfoIcon, NotAllowedIcon, WarningIcon } from "../icons";
10
+ import useStyles from "./styles";
11
+
12
+ export type AlertVariant = "error" | "warning" | "success" | "info";
13
+ export interface AlertProps {
14
+ className?: string;
15
+ close?: boolean;
16
+ variant: AlertVariant;
17
+ title: string;
18
+ }
19
+
20
+ function getIcon(variant: AlertVariant): React.ReactElement {
21
+ switch (variant) {
22
+ case "error":
23
+ return <NotAllowedIcon />;
24
+ case "success":
25
+ return <CompleteIcon />;
26
+ case "warning":
27
+ return <WarningIcon />;
28
+ }
29
+ return <InfoIcon />;
30
+ }
31
+
32
+ export const Alert: React.FC<AlertProps> = ({
33
+ className,
34
+ close = true,
35
+ variant = "info",
36
+ title,
37
+ children,
38
+ }) => {
39
+ const classes = useStyles();
40
+ const [visible, setVisible] = React.useState(true);
41
+
42
+ if (!visible) {
43
+ return null;
44
+ }
45
+
46
+ return (
47
+ <Card
48
+ elevation={0}
49
+ className={clsx(className, classes.root, {
50
+ [classes.error]: variant === "error",
51
+ [classes.warning]: variant === "warning",
52
+ [classes.success]: variant === "success",
53
+ })}
54
+ data-test="alert"
55
+ >
56
+ <CardContent>
57
+ <div className={classes.container}>
58
+ <div>{getIcon(variant)}</div>
59
+ <div className={classes.content}>
60
+ <div className={classes.titleBar}>
61
+ <Typography variant="h5">{title}</Typography>
62
+ {close && (
63
+ <IconButton
64
+ className={clsx(classes.close, {
65
+ [classes.closeNoContent]: !!children,
66
+ })}
67
+ onClick={() => setVisible(false)}
68
+ data-test="close"
69
+ >
70
+ <CloseIcon />
71
+ </IconButton>
72
+ )}
73
+ </div>
74
+ {typeof children === "string" ? (
75
+ <Typography variant="body1">{children}</Typography>
76
+ ) : (
77
+ children
78
+ )}
79
+ </div>
80
+ </div>
81
+ </CardContent>
82
+ </Card>
83
+ );
84
+ };
85
+
86
+ Alert.displayName = "Alert";
@@ -0,0 +1 @@
1
+ export * from "./Alert";
@@ -0,0 +1,46 @@
1
+ import { makeStyles } from "../theme";
2
+
3
+ const useStyles = makeStyles(
4
+ (theme) => ({
5
+ close: {
6
+ color: theme.palette.common.black,
7
+ position: "absolute",
8
+ right: theme.spacing(-2),
9
+ top: theme.spacing(-1),
10
+ },
11
+ closeNoContent: {
12
+ "&$close": {
13
+ right: theme.spacing(-3),
14
+ top: theme.spacing(-3),
15
+ },
16
+ },
17
+ container: {
18
+ columnGap: theme.spacing(2),
19
+ display: "grid",
20
+ gridTemplateColumns: "40px 1fr",
21
+ },
22
+ content: {
23
+ padding: theme.spacing(0, 1),
24
+ },
25
+ root: {},
26
+ titleBar: {
27
+ marginTop: 6,
28
+ marginBottom: theme.spacing(1),
29
+ position: "relative",
30
+ },
31
+ error: {
32
+ background: theme.palette.alert.paper.error,
33
+ },
34
+ warning: {
35
+ background: theme.palette.alert.paper.warning,
36
+ },
37
+ success: {
38
+ background: theme.palette.alert.paper.success,
39
+ },
40
+ }),
41
+ {
42
+ name: "Alert",
43
+ }
44
+ );
45
+
46
+ export default useStyles;
@@ -0,0 +1,51 @@
1
+ import { Meta, Story } from "@storybook/react";
2
+ import React from "react";
3
+
4
+ import { Decorator } from "../utils/Decorator";
5
+ import { Backlink } from "./Backlink";
6
+ import { useBacklink } from "./context";
7
+
8
+ // Normally some other component would rerender and force Backlink to recheck
9
+ // anchor too, but since it's static view we need to hack it a bit
10
+ const Wrapper: React.FC = ({ children }) => {
11
+ const anchor = useBacklink();
12
+ const [initialized, setInitialized] = React.useState(false);
13
+ const timer = React.useRef<number>();
14
+
15
+ React.useEffect(() => {
16
+ timer.current = setInterval(() => {
17
+ if (!initialized && anchor.current) {
18
+ setInitialized(true);
19
+ clearInterval(timer.current);
20
+ }
21
+ }, 50) as any;
22
+
23
+ return () => clearInterval(timer.current);
24
+ }, []);
25
+
26
+ return (
27
+ <div>
28
+ <div ref={anchor} />
29
+ {initialized && children}
30
+ </div>
31
+ );
32
+ };
33
+
34
+ export const Default: Story = () => (
35
+ <Backlink onClick={() => undefined}>Go back</Backlink>
36
+ );
37
+ export const Loading: Story = () => (
38
+ <Backlink onClick={() => undefined}>{undefined}</Backlink>
39
+ );
40
+
41
+ export default {
42
+ title: "Backlink",
43
+ decorators: [
44
+ (Story) => (
45
+ <Wrapper>
46
+ <Story />
47
+ </Wrapper>
48
+ ),
49
+ Decorator,
50
+ ],
51
+ } as Meta;
@@ -0,0 +1,40 @@
1
+ import Portal from "@material-ui/core/Portal";
2
+ import Typography from "@material-ui/core/Typography";
3
+ import ArrowBackIcon from "@material-ui/icons/ArrowBack";
4
+ import Skeleton from "@material-ui/lab/Skeleton";
5
+ import React from "react";
6
+
7
+ import { useBacklink } from "./context";
8
+ import useStyles from "./styles";
9
+
10
+ export interface AppHeaderProps {
11
+ children: React.ReactNode;
12
+ onClick: () => void;
13
+ }
14
+
15
+ export const Backlink: React.FC<AppHeaderProps> = ({ children, onClick }) => {
16
+ const classes = useStyles();
17
+ const anchor = useBacklink();
18
+
19
+ if (!anchor.current) {
20
+ return null;
21
+ }
22
+
23
+ return (
24
+ <Portal container={anchor.current}>
25
+ <div
26
+ className={classes.root}
27
+ onClick={onClick}
28
+ data-test-id="app-header-back-button"
29
+ >
30
+ <ArrowBackIcon className={classes.backArrow} />
31
+ {children ? (
32
+ <Typography className={classes.title}>{children}</Typography>
33
+ ) : (
34
+ <Skeleton className={classes.skeleton} />
35
+ )}
36
+ </div>
37
+ </Portal>
38
+ );
39
+ };
40
+ Backlink.displayName = "Backlink";
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+
3
+ export type BacklinkContextType = React.RefObject<HTMLDivElement>;
4
+
5
+ export const BacklinkContext = React.createContext<
6
+ BacklinkContextType | undefined
7
+ >(undefined);
8
+ BacklinkContext.displayName = "BacklinkContext";
9
+
10
+ export const useBacklink = () => {
11
+ const ctx = React.useContext(BacklinkContext);
12
+ if (ctx === undefined) {
13
+ throw new Error("useBacklink must be used within a BacklinkContext");
14
+ }
15
+
16
+ return ctx;
17
+ };
18
+
19
+ export const BacklinkProvider: React.FC = ({ children }) => {
20
+ const anchor = React.useRef<HTMLDivElement | null>(null);
21
+
22
+ return (
23
+ <BacklinkContext.Provider value={anchor}>
24
+ {children}
25
+ </BacklinkContext.Provider>
26
+ );
27
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./Backlink";
2
+ export * from "./context";
@@ -0,0 +1,41 @@
1
+ import { makeStyles } from "../theme";
2
+
3
+ const useStyles = makeStyles(
4
+ (theme) => ({
5
+ backArrow: {
6
+ fontSize: 30,
7
+ },
8
+ menuButton: {
9
+ flex: "0 0 auto",
10
+ marginLeft: theme.spacing(-2),
11
+ marginRight: theme.spacing(),
12
+ marginTop: theme.spacing(-2),
13
+ },
14
+ root: {
15
+ "&:hover": {
16
+ color: theme.typography.body1.color,
17
+ },
18
+ alignItems: "center",
19
+ color: theme.palette.grey[500],
20
+ cursor: "pointer",
21
+ display: "flex",
22
+ marginTop: theme.spacing(0.5),
23
+ transition: theme.transitions.duration.standard + "ms",
24
+ [theme.breakpoints.down("sm")]: {
25
+ margin: theme.spacing(4, 0, 0, 0),
26
+ },
27
+ },
28
+ skeleton: {
29
+ width: "10rem",
30
+ },
31
+ title: {
32
+ color: "inherit",
33
+ flex: 1,
34
+ marginLeft: theme.spacing(),
35
+ textTransform: "uppercase",
36
+ },
37
+ }),
38
+ { name: "AppHeader" }
39
+ );
40
+
41
+ export default useStyles;
@@ -0,0 +1,72 @@
1
+ import { Meta, Story } from "@storybook/react";
2
+ import React from "react";
3
+
4
+ import {
5
+ ConfirmButton,
6
+ ConfirmButtonLabels,
7
+ ConfirmButtonTransitionState,
8
+ } from "./ConfirmButton";
9
+
10
+ const labels: ConfirmButtonLabels = {
11
+ confirm: "Confirm",
12
+ error: "Error",
13
+ };
14
+
15
+ export const Interactive: Story = () => {
16
+ const [
17
+ transitionState,
18
+ setTransitionState,
19
+ ] = React.useState<ConfirmButtonTransitionState>("default");
20
+ const timer = React.useRef<number>();
21
+ React.useEffect(
22
+ () => () => {
23
+ if (timer.current) {
24
+ clearTimeout(timer.current);
25
+ }
26
+ },
27
+ []
28
+ );
29
+
30
+ const handleClick = () => {
31
+ if (!timer.current) {
32
+ setTransitionState("loading");
33
+ timer.current = (setTimeout(
34
+ () => setTransitionState("success"),
35
+ 2000
36
+ ) as unknown) as number;
37
+ }
38
+ };
39
+
40
+ return (
41
+ <ConfirmButton
42
+ labels={labels}
43
+ transitionState={transitionState}
44
+ onClick={handleClick}
45
+ />
46
+ );
47
+ };
48
+
49
+ export const Default: Story = () => (
50
+ <ConfirmButton labels={labels} transitionState="default" />
51
+ );
52
+ export const Loading: Story = () => (
53
+ <ConfirmButton
54
+ labels={labels}
55
+ transitionState="loading"
56
+ noTransition={true}
57
+ />
58
+ );
59
+ export const Error: Story = () => (
60
+ <ConfirmButton labels={labels} transitionState="error" noTransition={true} />
61
+ );
62
+ export const Success: Story = () => (
63
+ <ConfirmButton
64
+ labels={labels}
65
+ transitionState="success"
66
+ noTransition={true}
67
+ />
68
+ );
69
+
70
+ export default {
71
+ title: "Confirm Button",
72
+ } as Meta;