@pautena/react-design-system 0.1.2 → 0.2.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.
Files changed (191) hide show
  1. package/README.md +4 -0
  2. package/dist/cjs/index.js +4 -259
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/generators/model-router/screens/add-screen.d.ts +1 -1
  5. package/dist/cjs/types/generators/model-router/screens/list-screen.d.ts +1 -1
  6. package/dist/cjs/types/generators/model-router/screens/screens.types.d.ts +20 -0
  7. package/dist/cjs/types/generators/model-router/screens/update-screen.d.ts +1 -1
  8. package/dist/cjs/types/index.d.ts +1 -0
  9. package/dist/esm/index.js +4 -259
  10. package/dist/esm/index.js.map +1 -1
  11. package/dist/esm/types/generators/model-router/screens/add-screen.d.ts +1 -1
  12. package/dist/esm/types/generators/model-router/screens/list-screen.d.ts +1 -1
  13. package/dist/esm/types/generators/model-router/screens/screens.types.d.ts +20 -0
  14. package/dist/esm/types/generators/model-router/screens/update-screen.d.ts +1 -1
  15. package/dist/esm/types/index.d.ts +1 -0
  16. package/dist/index.d.ts +52 -3
  17. package/package.json +13 -2
  18. package/src/components/app-bar/app-bar.stories.tsx +54 -0
  19. package/src/components/app-bar/app-bar.test.tsx +142 -0
  20. package/src/components/app-bar/app-bar.tsx +150 -0
  21. package/src/components/app-bar/app-bar.types.ts +17 -0
  22. package/src/components/app-bar/index.ts +3 -0
  23. package/src/components/app-bar/mini-app-bar/index.ts +1 -0
  24. package/src/components/app-bar/mini-app-bar/mini-app-bar.tsx +31 -0
  25. package/src/components/bullet/bullet.stories.tsx +43 -0
  26. package/src/components/bullet/bullet.test.tsx +24 -0
  27. package/src/components/bullet/bullet.tsx +30 -0
  28. package/src/components/bullet/index.ts +1 -0
  29. package/src/components/center-container/center-container.stories.tsx +50 -0
  30. package/src/components/center-container/center-container.test.tsx +16 -0
  31. package/src/components/center-container/center-container.tsx +32 -0
  32. package/src/components/center-container/index.ts +1 -0
  33. package/src/components/content/content.stories.tsx +23 -0
  34. package/src/components/content/content.test.tsx +26 -0
  35. package/src/components/content/content.tsx +11 -0
  36. package/src/components/content/content.types.ts +5 -0
  37. package/src/components/content/index.ts +2 -0
  38. package/src/components/drawer/__snapshots__/drawer.test.tsx.snap +20 -0
  39. package/src/components/drawer/drawer.context.ts +20 -0
  40. package/src/components/drawer/drawer.mixins.ts +24 -0
  41. package/src/components/drawer/drawer.mock.tsx +100 -0
  42. package/src/components/drawer/drawer.provider.tsx +23 -0
  43. package/src/components/drawer/drawer.test.tsx +97 -0
  44. package/src/components/drawer/drawer.tsx +30 -0
  45. package/src/components/drawer/drawer.types.ts +53 -0
  46. package/src/components/drawer/index.ts +5 -0
  47. package/src/components/drawer/mini-drawer/index.ts +1 -0
  48. package/src/components/drawer/mini-drawer/mini-drawer.stories.tsx +34 -0
  49. package/src/components/drawer/mini-drawer/mini-drawer.tsx +67 -0
  50. package/src/components/drawer-content/drawer-content.stories.tsx +29 -0
  51. package/src/components/drawer-content/drawer-content.test.tsx +34 -0
  52. package/src/components/drawer-content/drawer-content.tsx +18 -0
  53. package/src/components/drawer-content/index.ts +1 -0
  54. package/src/components/drawer-item/drawer-item.stories.tsx +62 -0
  55. package/src/components/drawer-item/drawer-item.test.tsx +119 -0
  56. package/src/components/drawer-item/drawer-item.tsx +71 -0
  57. package/src/components/drawer-item/index.ts +1 -0
  58. package/src/components/drawer-section/drawer-section.mock.tsx +39 -0
  59. package/src/components/drawer-section/drawer-section.stories.tsx +28 -0
  60. package/src/components/drawer-section/drawer-section.test.tsx +44 -0
  61. package/src/components/drawer-section/drawer-section.tsx +40 -0
  62. package/src/components/drawer-section/index.ts +1 -0
  63. package/src/components/header/header.dummy.ts +55 -0
  64. package/src/components/header/header.stories.tsx +116 -0
  65. package/src/components/header/header.test.tsx +159 -0
  66. package/src/components/header/header.tsx +121 -0
  67. package/src/components/header/header.types.ts +61 -0
  68. package/src/components/header/index.ts +2 -0
  69. package/src/components/index.ts +18 -0
  70. package/src/components/label/index.ts +1 -0
  71. package/src/components/label/label.stories.tsx +49 -0
  72. package/src/components/label/label.test.tsx +30 -0
  73. package/src/components/label/label.tsx +60 -0
  74. package/src/components/link/index.ts +1 -0
  75. package/src/components/link/link.tsx +17 -0
  76. package/src/components/loading-area/index.ts +1 -0
  77. package/src/components/loading-area/loading-area.stories.tsx +17 -0
  78. package/src/components/loading-area/loading-area.test.tsx +11 -0
  79. package/src/components/loading-area/loading-area.tsx +13 -0
  80. package/src/components/placeholder/index.ts +1 -0
  81. package/src/components/placeholder/placeholder.mock.ts +15 -0
  82. package/src/components/placeholder/placeholder.stories.tsx +44 -0
  83. package/src/components/placeholder/placeholder.test.tsx +76 -0
  84. package/src/components/placeholder/placeholder.tsx +75 -0
  85. package/src/components/query-container/index.ts +1 -0
  86. package/src/components/query-container/query-container.stories.tsx +68 -0
  87. package/src/components/query-container/query-container.test.tsx +95 -0
  88. package/src/components/query-container/query-container.tsx +71 -0
  89. package/src/components/sign-in/index.ts +1 -0
  90. package/src/components/sign-in/sign-in.stories.tsx +36 -0
  91. package/src/components/sign-in/sign-in.test.tsx +95 -0
  92. package/src/components/sign-in/sign-in.tsx +97 -0
  93. package/src/components/tab/index.ts +2 -0
  94. package/src/components/tab/tab-card/index.ts +1 -0
  95. package/src/components/tab/tab-card/tab-card.dummy.tsx +30 -0
  96. package/src/components/tab/tab-card/tab-card.stories.tsx +22 -0
  97. package/src/components/tab/tab-card/tab-card.test.tsx +53 -0
  98. package/src/components/tab/tab-card/tab-card.tsx +27 -0
  99. package/src/components/tab/tab-panel/index.ts +1 -0
  100. package/src/components/tab/tab-panel/tab-panel.test.tsx +26 -0
  101. package/src/components/tab/tab-panel/tab-panel.tsx +27 -0
  102. package/src/components/table/enhanced-remote-table/enhanced-remote-table.mock.tsx +27 -0
  103. package/src/components/table/enhanced-remote-table/enhanced-remote-table.stories.tsx +24 -0
  104. package/src/components/table/enhanced-remote-table/enhanced-remote-table.test.tsx +77 -0
  105. package/src/components/table/enhanced-remote-table/enhanced-remote-table.tsx +74 -0
  106. package/src/components/table/enhanced-remote-table/index.ts +1 -0
  107. package/src/components/table/enhanced-table/enhanced-table-head.tsx +58 -0
  108. package/src/components/table/enhanced-table/enhanced-table.mock.tsx +93 -0
  109. package/src/components/table/enhanced-table/enhanced-table.stories.tsx +21 -0
  110. package/src/components/table/enhanced-table/enhanced-table.test.tsx +107 -0
  111. package/src/components/table/enhanced-table/enhanced-table.tsx +136 -0
  112. package/src/components/table/enhanced-table/index.ts +2 -0
  113. package/src/components/table/index.ts +2 -0
  114. package/src/components/table-list/index.ts +1 -0
  115. package/src/components/table-list/table-list.stories.tsx +75 -0
  116. package/src/components/table-list/table-list.test.tsx +291 -0
  117. package/src/components/table-list/table-list.tsx +127 -0
  118. package/src/components/value-displays/group-value-card/group-value-card.mock.tsx +35 -0
  119. package/src/components/value-displays/group-value-card/group-value-card.stories.tsx +26 -0
  120. package/src/components/value-displays/group-value-card/group-value-card.test.tsx +58 -0
  121. package/src/components/value-displays/group-value-card/group-value-card.tsx +63 -0
  122. package/src/components/value-displays/group-value-card/index.ts +1 -0
  123. package/src/components/value-displays/index.ts +4 -0
  124. package/src/components/value-displays/value-boolean/index.ts +1 -0
  125. package/src/components/value-displays/value-boolean/value-boolean.stories.tsx +25 -0
  126. package/src/components/value-displays/value-boolean/value-boolean.test.tsx +27 -0
  127. package/src/components/value-displays/value-boolean/value-boolean.tsx +33 -0
  128. package/src/components/value-displays/value-card/index.ts +1 -0
  129. package/src/components/value-displays/value-card/value-card.stories.tsx +22 -0
  130. package/src/components/value-displays/value-card/value-card.test.tsx +18 -0
  131. package/src/components/value-displays/value-card/value-card.tsx +12 -0
  132. package/src/components/value-displays/value-text/index.ts +1 -0
  133. package/src/components/value-displays/value-text/value-test.test.tsx +21 -0
  134. package/src/components/value-displays/value-text/value-text.stories.tsx +26 -0
  135. package/src/components/value-displays/value-text/value-text.tsx +32 -0
  136. package/src/generators/generators.mock.ts +238 -0
  137. package/src/generators/generators.model.ts +46 -0
  138. package/src/generators/index.ts +4 -0
  139. package/src/generators/model-form/index.ts +1 -0
  140. package/src/generators/model-form/model-form.stories.tsx +30 -0
  141. package/src/generators/model-form/model-form.test.tsx +100 -0
  142. package/src/generators/model-form/model-form.tsx +97 -0
  143. package/src/generators/model-router/index.ts +1 -0
  144. package/src/generators/model-router/model-router.test.tsx +831 -0
  145. package/src/generators/model-router/model-router.tsx +30 -0
  146. package/src/generators/model-router/model-router.types.ts +14 -0
  147. package/src/generators/model-router/screens/add-screen.tsx +70 -0
  148. package/src/generators/model-router/screens/details-screen.tsx +62 -0
  149. package/src/generators/model-router/screens/index.ts +4 -0
  150. package/src/generators/model-router/screens/list-screen.tsx +125 -0
  151. package/src/generators/model-router/screens/screens.types.ts +38 -0
  152. package/src/generators/model-router/screens/update-screen.tsx +97 -0
  153. package/src/generators/model-router/stories/details-screen.stories.tsx +38 -0
  154. package/src/generators/model-router/stories/list-screen.stories.tsx +96 -0
  155. package/src/generators/model-router/stories/model-router.stories.tsx +176 -0
  156. package/src/generators/model-router/stories/templates.tsx +39 -0
  157. package/src/generators/object-details/index.ts +1 -0
  158. package/src/generators/object-details/object-details.stories.tsx +20 -0
  159. package/src/generators/object-details/object-details.test.tsx +21 -0
  160. package/src/generators/object-details/object-details.tsx +76 -0
  161. package/src/index.ts +5 -0
  162. package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.stories.tsx +28 -0
  163. package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.test.tsx +30 -0
  164. package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.tsx +37 -0
  165. package/src/layouts/app-bar-with-drawer-layout/index.ts +1 -0
  166. package/src/layouts/header-layout/header-layout.stories.tsx +204 -0
  167. package/src/layouts/header-layout/header-layout.test.tsx +37 -0
  168. package/src/layouts/header-layout/header-layout.tsx +23 -0
  169. package/src/layouts/header-layout/index.ts +1 -0
  170. package/src/layouts/index.ts +2 -0
  171. package/src/providers/index.ts +2 -0
  172. package/src/providers/notification-center/index.ts +2 -0
  173. package/src/providers/notification-center/notification-center.context.ts +37 -0
  174. package/src/providers/notification-center/notification-center.provider.tsx +51 -0
  175. package/src/providers/notification-center/notification-center.stories.tsx +52 -0
  176. package/src/providers/notification-center/notification-center.test.tsx +112 -0
  177. package/src/providers/tab-provider/index.ts +2 -0
  178. package/src/providers/tab-provider/tab-provider.context.ts +8 -0
  179. package/src/providers/tab-provider/tab-provider.provider.tsx +13 -0
  180. package/src/storybook.tsx +90 -0
  181. package/src/tests/assertions.ts +76 -0
  182. package/src/tests/components.tsx +60 -0
  183. package/src/tests/content-placeholder.stories.tsx +16 -0
  184. package/src/tests/index.ts +3 -0
  185. package/src/tests/skeleton-card.stories.tsx +18 -0
  186. package/src/tests/testing-library.tsx +65 -0
  187. package/src/utils/arrays.test.ts +9 -0
  188. package/src/utils/arrays.ts +7 -0
  189. package/src/utils/index.ts +2 -0
  190. package/src/utils/theme.ts +11 -0
  191. package/.prettierrc.js +0 -5
@@ -0,0 +1,159 @@
1
+ import React from "react";
2
+ import { render, screen } from "../../tests";
3
+ import userEvent from "@testing-library/user-event";
4
+ import { Header } from "./header";
5
+ import {
6
+ HeaderAction,
7
+ HeaderActionVariant,
8
+ HeaderBreadcrumb,
9
+ HeaderPreset,
10
+ HeaderTab,
11
+ } from "./header.types";
12
+ import { breadcrumbs, actions as actionsData, tabs } from "./header.dummy";
13
+ import { TabProvider } from "../../providers";
14
+
15
+ const actions = actionsData.map((a) => ({ ...a, onClick: a.onClick && jest.fn() }));
16
+
17
+ function renderInstance({
18
+ title = "Lorem ipsum",
19
+ subtitle,
20
+ preset = "default",
21
+ breadcrumbs,
22
+ actions,
23
+ actionsVariant,
24
+ tabs,
25
+ selectedTab,
26
+ }: {
27
+ title?: string;
28
+ subtitle?: string | undefined;
29
+ preset?: HeaderPreset;
30
+ breadcrumbs?: HeaderBreadcrumb[];
31
+ actions?: HeaderAction[];
32
+ actionsVariant?: HeaderActionVariant;
33
+ tabs?: HeaderTab[];
34
+ selectedTab?: number;
35
+ }) {
36
+ const instance = render(
37
+ <TabProvider initialValue={selectedTab}>
38
+ <Header
39
+ title={title}
40
+ subtitle={subtitle}
41
+ preset={preset}
42
+ breadcrumbs={breadcrumbs}
43
+ actions={actions}
44
+ actionsVariant={actionsVariant}
45
+ tabs={tabs}
46
+ />
47
+ </TabProvider>,
48
+ );
49
+
50
+ return { ...instance };
51
+ }
52
+
53
+ describe("Header", () => {
54
+ it("renders the title", () => {
55
+ renderInstance({ title: "Lorem ipsum" });
56
+
57
+ expect(screen.getByRole("heading", { level: 1, name: /lorem ipsum/i })).toBeInTheDocument();
58
+ });
59
+
60
+ describe("subtitle", () => {
61
+ it("would renders when is set", () => {
62
+ renderInstance({ subtitle: "sit amet" });
63
+
64
+ expect(screen.queryByRole("heading", { level: 2, name: /sit amet/i })).toBeInTheDocument();
65
+ });
66
+
67
+ it("wouldn't render if it is not set", () => {
68
+ renderInstance({ subtitle: undefined });
69
+
70
+ expect(screen.queryByRole("heading", { level: 2 })).not.toBeInTheDocument();
71
+ });
72
+ });
73
+
74
+ describe("breadcrumbs", () => {
75
+ it("would render a list of links", () => {
76
+ renderInstance({ breadcrumbs });
77
+
78
+ expect(screen.getByRole("link", { name: /items/i })).toBeInTheDocument();
79
+ expect(screen.getByRole("link", { name: /item 1/i })).toBeInTheDocument();
80
+ });
81
+
82
+ it("would navigate to a breadcrumb when is", async () => {
83
+ const { history } = renderInstance({ breadcrumbs });
84
+
85
+ await userEvent.click(screen.getByRole("link", { name: /items/i }));
86
+
87
+ expect(history.location.pathname).toBe("/items");
88
+ });
89
+ });
90
+
91
+ describe("actions", () => {
92
+ it("would render a list of buttons", () => {
93
+ renderInstance({ actions });
94
+
95
+ expect(screen.getByRole("button", { name: /add/i })).toBeInTheDocument();
96
+ expect(screen.getByRole("button", { name: /edit/i })).toBeInTheDocument();
97
+ expect(screen.getByRole("button", { name: /disabled/i })).toBeInTheDocument();
98
+ expect(screen.getByRole("button", { name: /delete/i })).toBeInTheDocument();
99
+ });
100
+
101
+ it("clicks an action with an onClick defined it will be called", async () => {
102
+ renderInstance({ actions });
103
+
104
+ const button = actions[1];
105
+
106
+ await userEvent.click(screen.getByRole("button", { name: button.text }));
107
+
108
+ expect(button.onClick).toHaveBeenCalledTimes(1);
109
+ });
110
+
111
+ it("wouldn't be possible to click a disabled action", async () => {
112
+ renderInstance({ actions });
113
+
114
+ expect(screen.getByRole("button", { name: /disabled/i })).toBeDisabled();
115
+ });
116
+
117
+ it("would redirect to the expected url when click an action with an href", async () => {
118
+ const { history } = renderInstance({ actions });
119
+
120
+ await userEvent.click(screen.getByRole("button", { name: /add/i }));
121
+
122
+ expect(history.location.pathname).toBe("/items/add");
123
+ });
124
+ });
125
+
126
+ describe("tabs", () => {
127
+ it("would render a list of tabs", () => {
128
+ renderInstance({ tabs, selectedTab: 2 });
129
+
130
+ expect(screen.getByRole("tab", { name: /tab 1/i })).toBeInTheDocument();
131
+ expect(screen.getByRole("tab", { name: /tab 2/i })).toBeInTheDocument();
132
+ expect(screen.getByRole("tab", { name: /tab 3/i })).toBeInTheDocument();
133
+ });
134
+
135
+ it("would mark as active the selectedTab", () => {
136
+ renderInstance({ tabs, selectedTab: 2 });
137
+
138
+ expect(screen.getByRole("tab", { name: /tab 1/i, selected: false })).toBeInTheDocument();
139
+ expect(screen.getByRole("tab", { name: /tab 2/i, selected: false })).toBeInTheDocument();
140
+ expect(screen.getByRole("tab", { name: /tab 3/i, selected: true })).toBeInTheDocument();
141
+ });
142
+
143
+ it("wouldn't be possible to click a disabled tab", () => {
144
+ renderInstance({ tabs, selectedTab: 2 });
145
+
146
+ expect(screen.getByRole("tab", { name: /tab 2/i })).toBeDisabled();
147
+ });
148
+
149
+ it("would change the selected tab when a tab is clicked", async () => {
150
+ renderInstance({ tabs, selectedTab: 0 });
151
+
152
+ await userEvent.click(screen.getByRole("tab", { name: /tab 3/i }));
153
+
154
+ expect(screen.getByRole("tab", { name: /tab 1/i, selected: false })).toBeInTheDocument();
155
+ expect(screen.getByRole("tab", { name: /tab 2/i, selected: false })).toBeInTheDocument();
156
+ expect(screen.getByRole("tab", { name: /tab 3/i, selected: true })).toBeInTheDocument();
157
+ });
158
+ });
159
+ });
@@ -0,0 +1,121 @@
1
+ import React from "react";
2
+ import {
3
+ Breadcrumbs,
4
+ Typography,
5
+ Container,
6
+ useTheme,
7
+ Box,
8
+ Tabs,
9
+ Tab,
10
+ Button,
11
+ } from "@mui/material";
12
+ import { Link } from "../link";
13
+ import { useGetDefaultThemeColor } from "../../utils";
14
+ import { HeaderComponent, HeaderPreset, HeaderProps } from "./header.types";
15
+ import { useTab } from "~/providers";
16
+
17
+ /**
18
+ * Section used to explain give basic information about the page
19
+ * and put the main actions
20
+ */
21
+ export const Header: HeaderComponent = ({
22
+ title,
23
+ subtitle,
24
+ preset = "default",
25
+ actionsVariant = "outlined",
26
+ breadcrumbs,
27
+ actions,
28
+ tabs,
29
+ }: HeaderProps) => {
30
+ const { palette } = useTheme();
31
+ const defaultColor = useGetDefaultThemeColor();
32
+ const [selectedTab, setSelectedTab] = useTab();
33
+
34
+ const bgColorPresets: Record<HeaderPreset, string> = {
35
+ default: defaultColor,
36
+ primary: palette.primary.main,
37
+ secondary: palette.secondary.main,
38
+ inherit: "inherit",
39
+ transparent: "transparent",
40
+ };
41
+ const bgColor = bgColorPresets[preset];
42
+ const textColorPresets: Record<HeaderPreset, string> = {
43
+ default: palette.getContrastText(bgColorPresets.default),
44
+ primary: palette.primary.contrastText,
45
+ secondary: palette.secondary.contrastText,
46
+ inherit: "inherit",
47
+ transparent: palette.text.primary,
48
+ };
49
+ const textColor = textColorPresets[preset];
50
+
51
+ return (
52
+ <Box bgcolor={bgColor} color={textColor}>
53
+ <Container>
54
+ <Box sx={{ py: 3, display: "flex", flexDirection: "row", justifyContent: "space-between" }}>
55
+ <Box>
56
+ {breadcrumbs?.length && (
57
+ <Breadcrumbs
58
+ color="inherit"
59
+ separator="›"
60
+ aria-label="breadcrumb"
61
+ sx={{ marginTop: 1 }}
62
+ >
63
+ {breadcrumbs.map(({ id, link, text }) => (
64
+ <Link
65
+ key={id}
66
+ underline="hover"
67
+ color="inherit"
68
+ href={link}
69
+ variant="body2"
70
+ role="link"
71
+ >
72
+ {text}
73
+ </Link>
74
+ ))}
75
+ </Breadcrumbs>
76
+ )}
77
+ <Typography variant="h4" role="heading" aria-level={1}>
78
+ {title}
79
+ </Typography>
80
+ {subtitle && (
81
+ <Typography variant="body1" role="heading" aria-level={2}>
82
+ {subtitle}
83
+ </Typography>
84
+ )}
85
+ </Box>
86
+ {actions && (
87
+ <Box>
88
+ {actions.map(({ disabled, id, href, onClick, text }, i) => (
89
+ <Button
90
+ component={href ? Link : "button"}
91
+ role="button"
92
+ color="inherit"
93
+ disabled={disabled}
94
+ key={id}
95
+ variant={actionsVariant}
96
+ size="small"
97
+ href={href}
98
+ onClick={onClick}
99
+ sx={{ mr: i != actions.length - 1 ? 1 : 0 }}
100
+ >
101
+ {text}
102
+ </Button>
103
+ ))}
104
+ </Box>
105
+ )}
106
+ </Box>
107
+ {tabs && (
108
+ <Tabs
109
+ value={selectedTab}
110
+ textColor="inherit"
111
+ onChange={(_, index) => setSelectedTab(index)}
112
+ >
113
+ {tabs.map(({ id, label, disabled }) => (
114
+ <Tab key={id} label={label} disabled={disabled} />
115
+ ))}
116
+ </Tabs>
117
+ )}
118
+ </Container>
119
+ </Box>
120
+ );
121
+ };
@@ -0,0 +1,61 @@
1
+ import { PropTypes } from "@mui/material";
2
+ import { FunctionComponent, ReactElement } from "react";
3
+
4
+ export type HeaderPreset = PropTypes.Color | "transparent";
5
+ export type HeaderActionVariant = "text" | "outlined" | "contained";
6
+
7
+ export type HeaderAction = {
8
+ id: string;
9
+ text: string;
10
+ disabled?: boolean;
11
+ href?: string;
12
+ onClick?: () => void;
13
+ };
14
+
15
+ export interface HeaderBreadcrumb {
16
+ id: string;
17
+ text: string;
18
+ link: string;
19
+ }
20
+
21
+ export interface HeaderTab {
22
+ id: string;
23
+ label: string;
24
+ disabled?: boolean;
25
+ }
26
+
27
+ export type HeaderProps = {
28
+ /**
29
+ * Title of the header
30
+ */
31
+ title: string;
32
+ /**
33
+ * Subtitle of the header
34
+ */
35
+ subtitle?: string;
36
+ /**
37
+ * Color palete used to render the component
38
+ */
39
+ preset?: HeaderPreset;
40
+ /**
41
+ * List of breadcumbs to represent the path to reach
42
+ * the page that we are
43
+ */
44
+ breadcrumbs?: HeaderBreadcrumb[];
45
+ /**
46
+ * List of actions that can be performed by the user.
47
+ * Each action will be a button in the header.
48
+ */
49
+ actions?: HeaderAction[];
50
+ /**
51
+ * Variant used to render the actions
52
+ */
53
+ actionsVariant?: HeaderActionVariant;
54
+ /**
55
+ * If is set, a list of tabs is dispayed at the bottom
56
+ */
57
+ tabs?: HeaderTab[];
58
+ };
59
+
60
+ export type HeaderComponent = FunctionComponent<HeaderProps>;
61
+ export type HeaderElement = ReactElement<HeaderProps, HeaderComponent>;
@@ -0,0 +1,2 @@
1
+ export * from "./header";
2
+ export * from "./header.types";
@@ -0,0 +1,18 @@
1
+ export * from "./header";
2
+ export * from "./link";
3
+ export * from "./query-container";
4
+ export * from "./sign-in";
5
+ export * from "./tab";
6
+ export * from "./table";
7
+ export * from "./app-bar";
8
+ export * from "./drawer";
9
+ export * from "./table-list";
10
+ export * from "./placeholder";
11
+ export * from "./label";
12
+ export * from "./bullet";
13
+ export * from "./drawer-content";
14
+ export * from "./drawer-section";
15
+ export * from "./drawer-item";
16
+ export * from "./center-container";
17
+ export * from "./value-displays";
18
+ export * from "./content";
@@ -0,0 +1 @@
1
+ export * from "./label";
@@ -0,0 +1,49 @@
1
+ import { ComponentMeta } from "@storybook/react";
2
+ import { createTemplate } from "../../storybook";
3
+ import { Label } from "./label";
4
+
5
+ export default {
6
+ title: "Data Display/Label",
7
+ component: Label,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ } as ComponentMeta<typeof Label>;
12
+
13
+ const Template = createTemplate(Label);
14
+
15
+ export const Default = Template.bind({});
16
+ Default.args = {
17
+ text: "lorem",
18
+ variant: "default",
19
+ };
20
+
21
+ export const Primary = Template.bind({});
22
+ Primary.args = {
23
+ text: "lorem",
24
+ variant: "primary",
25
+ };
26
+
27
+ export const Secondary = Template.bind({});
28
+ Secondary.args = {
29
+ text: "lorem",
30
+ variant: "secondary",
31
+ };
32
+
33
+ export const Info = Template.bind({});
34
+ Info.args = {
35
+ text: "lorem",
36
+ variant: "info",
37
+ };
38
+
39
+ export const Warning = Template.bind({});
40
+ Warning.args = {
41
+ text: "lorem",
42
+ variant: "warning",
43
+ };
44
+
45
+ export const Error = Template.bind({});
46
+ Error.args = {
47
+ text: "lorem",
48
+ variant: "error",
49
+ };
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { Label, LabelVariant } from "./label";
3
+ import { render, screen } from "../../tests";
4
+
5
+ describe("Label", () => {
6
+ const renderComponent = (variant: LabelVariant | undefined = undefined) => {
7
+ return render(<Label variant={variant} text="lorem ipsum" />);
8
+ };
9
+
10
+ it("renders the label text", () => {
11
+ renderComponent();
12
+
13
+ expect(screen.getByText("LOREM IPSUM")).toBeInTheDocument();
14
+ });
15
+
16
+ it("renders as default without a variant", () => {
17
+ renderComponent(undefined);
18
+
19
+ expect(screen.getByRole("label")).toHaveAttribute("aria-describedby", "default");
20
+ });
21
+
22
+ it.each([["primary"], ["secondary"], ["default"], ["info"], ["warning"], ["error"]])(
23
+ "renders correctly with variant %s",
24
+ (variant: string) => {
25
+ renderComponent(variant as LabelVariant);
26
+
27
+ expect(screen.getByRole("label")).toHaveAttribute("aria-describedby", variant);
28
+ },
29
+ );
30
+ });
@@ -0,0 +1,60 @@
1
+ import { Box, Typography, useTheme } from "@mui/material";
2
+ import React from "react";
3
+
4
+ export type LabelVariant = "primary" | "secondary" | "default" | "info" | "warning" | "error";
5
+
6
+ export const labelClasses = {
7
+ root: "RdsLabel-root",
8
+ };
9
+
10
+ export interface LabelProps {
11
+ /**
12
+ * Content of the component
13
+ */
14
+ text: string;
15
+ /**
16
+ * Color palette used to draw the component
17
+ */
18
+ variant?: LabelVariant;
19
+ }
20
+
21
+ /**
22
+ * Compact element to represent a text
23
+ */
24
+ export const Label = ({ text, variant = "default" }: LabelProps) => {
25
+ const { palette } = useTheme();
26
+
27
+ const backgroundColor: Record<LabelVariant, string> = {
28
+ default: palette.mode === "light" ? palette.grey[100] : palette.grey[900],
29
+ primary: palette.primary.main,
30
+ secondary: palette.secondary.main,
31
+ info: palette.info.main,
32
+ warning: palette.warning.main,
33
+ error: palette.error.main,
34
+ };
35
+
36
+ const textColor: Record<LabelVariant, string> = {
37
+ default: palette.getContrastText(backgroundColor.default),
38
+ primary: palette.primary.contrastText,
39
+ secondary: palette.secondary.contrastText,
40
+ info: palette.info.contrastText,
41
+ warning: palette.warning.contrastText,
42
+ error: palette.error.contrastText,
43
+ };
44
+
45
+ return (
46
+ <Box
47
+ px={1}
48
+ sx={{ backgroundColor: backgroundColor[variant] }}
49
+ borderRadius={1}
50
+ color={textColor[variant]}
51
+ className={labelClasses.root}
52
+ role="label"
53
+ aria-describedby={variant}
54
+ >
55
+ <Typography variant="caption" fontWeight={700}>
56
+ {text.toUpperCase()}
57
+ </Typography>
58
+ </Box>
59
+ );
60
+ };
@@ -0,0 +1 @@
1
+ export * from "./link";
@@ -0,0 +1,17 @@
1
+ import React from "react";
2
+ import { Link as RouterLink, LinkProps as RouterLinkProps } from "react-router-dom";
3
+ import { forwardRef } from "react";
4
+ import { LinkProps, Link as MuiLink } from "@mui/material";
5
+
6
+ // eslint-disable-next-line react/display-name, @typescript-eslint/no-explicit-any
7
+ export const LinkBehaviour = forwardRef<
8
+ any,
9
+ Omit<RouterLinkProps, "to"> & { href: RouterLinkProps["to"] }
10
+ >((props, ref) => {
11
+ const { href, ...other } = props;
12
+ return <RouterLink ref={ref} to={href} {...other} />;
13
+ });
14
+
15
+ export const Link = forwardRef<any, LinkProps>((props, _) => {
16
+ return <MuiLink {...props} component={LinkBehaviour} />;
17
+ });
@@ -0,0 +1 @@
1
+ export * from "./loading-area";
@@ -0,0 +1,17 @@
1
+ import { ComponentMeta } from "@storybook/react";
2
+ import { createTemplate, withContainer } from "../../storybook";
3
+ import { LoadingArea } from "./loading-area";
4
+
5
+ export default {
6
+ title: "Components/LoadingArea",
7
+ component: LoadingArea,
8
+ decorators: [withContainer({ height: 300 })],
9
+ parameters: {
10
+ layout: "fullscreen",
11
+ },
12
+ } as ComponentMeta<typeof LoadingArea>;
13
+
14
+ const Template = createTemplate(LoadingArea);
15
+
16
+ export const Default = Template.bind({});
17
+ Default.args = {};
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import { render, expectProgressIndicator } from "../../tests";
3
+ import { LoadingArea } from "./loading-area";
4
+
5
+ describe("LoadingArea", () => {
6
+ it("would render a loading icon", () => {
7
+ render(<LoadingArea />);
8
+
9
+ expectProgressIndicator();
10
+ });
11
+ });
@@ -0,0 +1,13 @@
1
+ import { CircularProgress, Box } from "@mui/material";
2
+ import React from "react";
3
+
4
+ /**
5
+ * Displays a centered loading indicator
6
+ */
7
+ export const LoadingArea = () => {
8
+ return (
9
+ <Box width={1} height={1} display="flex" justifyContent="center" alignItems="center">
10
+ <CircularProgress />
11
+ </Box>
12
+ );
13
+ };
@@ -0,0 +1 @@
1
+ export * from "./placeholder";
@@ -0,0 +1,15 @@
1
+ import { PlaceholderAction } from "./placeholder";
2
+ import { action } from "@storybook/addon-actions";
3
+
4
+ export const actions: PlaceholderAction[] = [
5
+ {
6
+ id: "add",
7
+ text: "Add",
8
+ href: "/placeholders/add",
9
+ },
10
+ {
11
+ id: "edit",
12
+ text: "Edit",
13
+ onClick: action("on click edit action"),
14
+ },
15
+ ];
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { createTemplate } from "../../storybook";
4
+ import { Placeholder, PlaceholderIconArgs } from "./placeholder";
5
+ import SearchIcon from "@mui/icons-material/Search";
6
+ import { actions } from "./placeholder.mock";
7
+
8
+ export default {
9
+ title: "Components/Placeholder",
10
+ component: Placeholder,
11
+ parameters: {
12
+ layout: "fullscreen",
13
+ },
14
+ } as ComponentMeta<typeof Placeholder>;
15
+
16
+ const Template = createTemplate(Placeholder);
17
+
18
+ export const Default = Template.bind({});
19
+ Default.args = {
20
+ title: "Lorem ipsum dolor sit amet",
21
+ subtitle:
22
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eleifend at libero in tristique. Pellentesque bibendum arcu eget augue commodo, non convallis eros porttitor",
23
+ };
24
+
25
+ export const WithIcon = Template.bind({});
26
+ WithIcon.args = {
27
+ icon: ({ size, color }: PlaceholderIconArgs) => (
28
+ <SearchIcon color={color} sx={{ fontSize: size }} />
29
+ ),
30
+ title: "Lorem ipsum dolor sit amet",
31
+ subtitle:
32
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eleifend at libero in tristique. Pellentesque bibendum arcu eget augue commodo, non convallis eros porttitor",
33
+ };
34
+
35
+ export const WithActions = Template.bind({});
36
+ WithActions.args = {
37
+ icon: ({ size, color }: PlaceholderIconArgs) => (
38
+ <SearchIcon color={color} sx={{ fontSize: size }} />
39
+ ),
40
+ title: "Lorem ipsum dolor sit amet",
41
+ subtitle:
42
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eleifend at libero in tristique. Pellentesque bibendum arcu eget augue commodo, non convallis eros porttitor",
43
+ actions,
44
+ };