@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,176 @@
1
+ import React from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { withMemoryRouter, withNotificationCenter } from "../../../storybook";
4
+ import { ModelRouter } from "../model-router";
5
+ import { IdleRequest } from "../model-router.types";
6
+ import { MockInstance, mockModel } from "../../generators.mock";
7
+ import { HandlerFunction } from "@storybook/addon-actions";
8
+ import { useState } from "react";
9
+ import {
10
+ data,
11
+ onRequestDeleteAction,
12
+ onRequestItem,
13
+ onRequestListAction,
14
+ onRequestUpdateItemAction,
15
+ onSubmitNewItemAction,
16
+ onSubmitUpdateAction,
17
+ REQUEST_TIMEOUT,
18
+ } from "./templates";
19
+
20
+ interface DummyModelRouterProps {
21
+ requestTimeout: number;
22
+ initialData: MockInstance[];
23
+ deleteFeature?: boolean;
24
+ updateFeature?: boolean;
25
+ addFeature?: boolean;
26
+ detailsFeature?: boolean;
27
+ onRequestListAction: HandlerFunction;
28
+ onSubmitNewItemAction: HandlerFunction;
29
+ onRequestItem: HandlerFunction;
30
+ onRequestUpdateItemAction: HandlerFunction;
31
+ onSubmitUpdateAction: HandlerFunction;
32
+ onRequestDeleteAction: HandlerFunction;
33
+ }
34
+
35
+ export const DummyModelRouter = (args: DummyModelRouterProps) => {
36
+ const {
37
+ requestTimeout,
38
+ initialData,
39
+ deleteFeature = true,
40
+ updateFeature = true,
41
+ addFeature = true,
42
+ detailsFeature = true,
43
+ onRequestListAction,
44
+ onSubmitNewItemAction,
45
+ onRequestItem,
46
+ onRequestUpdateItemAction,
47
+ onSubmitUpdateAction,
48
+ onRequestDeleteAction,
49
+ } = args;
50
+
51
+ const [data, setData] = useState<MockInstance[]>([]);
52
+ const [updateItem, setUpdateItem] = useState<MockInstance | undefined>(undefined);
53
+ const [listRequestState, setListRequestState] = useState(IdleRequest);
54
+ const [newItemRequestState, setNewItemRequestState] = useState(IdleRequest);
55
+ const [submitUpdateItemRequestState, setSubmitUpdateItemRequestState] = useState(IdleRequest);
56
+ const [removeRequestState, setRemoveRequestState] = useState(IdleRequest);
57
+ const [detailRequestState, setDetailRequestState] = useState(IdleRequest);
58
+ const [updateItemRequestState, setUpdateItemRequestState] = useState(IdleRequest);
59
+ const [detailInstance, setDetailInstance] = useState<MockInstance | undefined>(undefined);
60
+
61
+ const handleRequestList = () => {
62
+ onRequestListAction();
63
+ setListRequestState({ idle: false, loading: true });
64
+ setTimeout(() => {
65
+ setData(initialData);
66
+ setListRequestState({ idle: true, loading: false, success: true });
67
+ }, requestTimeout);
68
+ };
69
+
70
+ const handleClickDeleteItem = (item) => {
71
+ setRemoveRequestState({ idle: false, loading: true });
72
+ onRequestDeleteAction(item);
73
+
74
+ setTimeout(() => {
75
+ setData((d) => [...d.filter((d) => d !== item)]);
76
+ setRemoveRequestState({ idle: true, loading: false, success: true });
77
+ }, requestTimeout);
78
+ };
79
+
80
+ const handleSubmitNewItem = (obj: MockInstance) => {
81
+ setNewItemRequestState({ idle: false, loading: true });
82
+ onSubmitNewItemAction(obj);
83
+
84
+ setTimeout(() => {
85
+ setData((d) => [...d, obj]);
86
+ setNewItemRequestState({ idle: true, loading: false, success: true });
87
+ }, requestTimeout);
88
+ };
89
+
90
+ const handleRequestItem = (id: string) => {
91
+ setDetailInstance(undefined);
92
+ setDetailRequestState({ idle: false, loading: true });
93
+ onRequestItem(id);
94
+
95
+ setTimeout(() => {
96
+ setDetailInstance(data?.find((d) => d.id === id));
97
+ setDetailRequestState({ idle: true, loading: false, success: true });
98
+ }, requestTimeout);
99
+ };
100
+
101
+ const handleRequestUpdateItem = (id: string) => {
102
+ setUpdateItemRequestState({ idle: false, loading: true });
103
+ onRequestUpdateItemAction(id);
104
+
105
+ setTimeout(() => {
106
+ setUpdateItem(data?.find((d) => d.id === id));
107
+ setUpdateItemRequestState({ idle: true, loading: false, success: true });
108
+ }, requestTimeout);
109
+ };
110
+
111
+ const handleSubmitUpdateItem = (obj: MockInstance) => {
112
+ setSubmitUpdateItemRequestState({ idle: false, loading: true });
113
+ onSubmitUpdateAction(obj);
114
+
115
+ setTimeout(() => {
116
+ setData((d) => [
117
+ ...(d || []).map((item) => {
118
+ if (item === obj) {
119
+ return obj;
120
+ }
121
+ return item;
122
+ }),
123
+ ]);
124
+ setSubmitUpdateItemRequestState({ idle: true, loading: false, success: true });
125
+ }, requestTimeout);
126
+ };
127
+
128
+ return (
129
+ <ModelRouter
130
+ {...args}
131
+ modelName="Items"
132
+ model={mockModel}
133
+ deleteFeature={deleteFeature}
134
+ updateFeature={updateFeature}
135
+ addFeature={addFeature}
136
+ detailsFeature={detailsFeature}
137
+ onRequestList={handleRequestList}
138
+ listData={data}
139
+ listRequest={listRequestState}
140
+ deleteRequest={removeRequestState}
141
+ onClickDeleteItem={handleClickDeleteItem}
142
+ itemRequest={detailRequestState}
143
+ detailsItem={detailInstance}
144
+ onRequestItem={handleRequestItem}
145
+ newItemRequest={newItemRequestState}
146
+ onSubmitNewItem={handleSubmitNewItem}
147
+ submitUpdateItemRequest={submitUpdateItemRequestState}
148
+ updateItemRequest={updateItemRequestState}
149
+ updateItem={updateItem}
150
+ onRequestUpdateItem={handleRequestUpdateItem}
151
+ onSubmitUpdateItem={handleSubmitUpdateItem}
152
+ />
153
+ );
154
+ };
155
+
156
+ const args: DummyModelRouterProps = {
157
+ requestTimeout: REQUEST_TIMEOUT,
158
+ initialData: data,
159
+ onRequestListAction,
160
+ onSubmitNewItemAction,
161
+ onRequestItem,
162
+ onRequestUpdateItemAction,
163
+ onSubmitUpdateAction,
164
+ onRequestDeleteAction,
165
+ };
166
+
167
+ DummyModelRouter.args = args;
168
+
169
+ export default {
170
+ title: "Generators/ModelRouter",
171
+ component: DummyModelRouter,
172
+ decorators: [withMemoryRouter(), withNotificationCenter],
173
+ parameters: {
174
+ layout: "fullscreen",
175
+ },
176
+ } as ComponentMeta<typeof DummyModelRouter>;
@@ -0,0 +1,39 @@
1
+ import { action } from "@storybook/addon-actions";
2
+ import { ModelRouter } from "../model-router";
3
+ import { createTemplate } from "../../../storybook";
4
+ import { createModelInstance, MockInstance, mockModel } from "../../generators.mock";
5
+ import { IdleRequest } from "../model-router.types";
6
+
7
+ export const onRequestListAction = action("Request list data");
8
+ export const onSubmitNewItemAction = action("Submit new item");
9
+ export const onRequestItem = action("Details screen mount");
10
+ export const onRequestUpdateItemAction = action("Request update instance");
11
+ export const onSubmitUpdateAction = action("Submit update form");
12
+ export const onRequestDeleteAction = action("click delete item option");
13
+
14
+ export const REQUEST_TIMEOUT = 2000;
15
+
16
+ export const item1 = createModelInstance<MockInstance>(mockModel, 100);
17
+ export const data = [
18
+ item1,
19
+ createModelInstance<MockInstance>(mockModel, 101),
20
+ createModelInstance<MockInstance>(mockModel, 102),
21
+ createModelInstance<MockInstance>(mockModel, 103),
22
+ createModelInstance<MockInstance>(mockModel, 104),
23
+ ];
24
+
25
+ export const ModelRouterTemplate = createTemplate(ModelRouter);
26
+
27
+ export const baseArgs = {
28
+ modelName: "Items",
29
+ model: mockModel,
30
+ listData: data,
31
+ listRequest: IdleRequest,
32
+ deleteRequest: IdleRequest,
33
+ newItemRequest: IdleRequest,
34
+ updateItemRequest: IdleRequest,
35
+ submitUpdateItemRequest: IdleRequest,
36
+ itemRequest: IdleRequest,
37
+ // onRequestList:onRequestListAction,
38
+ // onRequestUpdateItem: onRequestUpdateItemAction,
39
+ };
@@ -0,0 +1 @@
1
+ export * from "./object-details";
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { ObjectDetails } from "./object-details";
4
+ import { withPadding } from "../../storybook";
5
+ import { createModelInstance, mockModel } from "../generators.mock";
6
+
7
+ const instance = createModelInstance(mockModel);
8
+
9
+ export default {
10
+ title: "Generators/ObjectDetails",
11
+ component: ObjectDetails,
12
+ decorators: [withPadding()],
13
+ parameters: {
14
+ layout: "fullscreen",
15
+ },
16
+ } as ComponentMeta<typeof ObjectDetails>;
17
+
18
+ export const Default = () => {
19
+ return <ObjectDetails model={mockModel} instance={instance} />;
20
+ };
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import { expectModelFieldValue, render } from "../../tests";
3
+ import { mockModel, createModelInstance } from "../generators.mock";
4
+ import { ObjectDetails } from "./object-details";
5
+
6
+ describe("ObjectDetails", () => {
7
+ const renderComponent = () => {
8
+ const instance = createModelInstance(mockModel);
9
+ return {
10
+ ...render(<ObjectDetails model={mockModel} instance={instance} />),
11
+ instance,
12
+ model: mockModel,
13
+ };
14
+ };
15
+
16
+ it("would render a label/value pair for each detail", () => {
17
+ const { instance, model } = renderComponent();
18
+
19
+ model.fields.forEach((detail) => expectModelFieldValue(detail, instance));
20
+ });
21
+ });
@@ -0,0 +1,76 @@
1
+ import React from "react";
2
+ import { Grid } from "@mui/material";
3
+ import {
4
+ GroupValueCard,
5
+ GroupValueItem,
6
+ ValueBoolean,
7
+ ValueCard,
8
+ ValueText,
9
+ } from "../../components";
10
+ import { ModelField, GroupField, Model, BasicModelInstance } from "../generators.model";
11
+
12
+ const singleDetailValueFactory = <T extends BasicModelInstance>(
13
+ { id, name, type }: ModelField,
14
+ instance: T,
15
+ ) => {
16
+ const value = instance[id];
17
+ if (type === "boolean") {
18
+ return <ValueBoolean label={name} value={value} />;
19
+ }
20
+ return <ValueText label={name} value={value?.toString()} />;
21
+ };
22
+
23
+ interface ObjectDetailGroupProps<T extends BasicModelInstance> {
24
+ field: GroupField;
25
+ instance: T;
26
+ }
27
+
28
+ const ObjectDetailGroup = <T extends BasicModelInstance>({
29
+ field: { name, description, value },
30
+ instance,
31
+ }: ObjectDetailGroupProps<T>) => {
32
+ return (
33
+ <GroupValueCard title={name} subtitle={description}>
34
+ {value.map((field) => {
35
+ const { id, xs, sm, md, lg, xl } = field;
36
+ return (
37
+ <GroupValueItem key={id} xs={xs} sm={sm} md={md} lg={lg} xl={xl}>
38
+ {singleDetailValueFactory(field, instance)}
39
+ </GroupValueItem>
40
+ );
41
+ })}
42
+ </GroupValueCard>
43
+ );
44
+ };
45
+
46
+ export interface ObjectDetailsProps<T extends BasicModelInstance> {
47
+ model: Model;
48
+ instance: T;
49
+ }
50
+
51
+ export const ObjectDetails = <T extends BasicModelInstance>({
52
+ model,
53
+ instance,
54
+ }: ObjectDetailsProps<T>) => {
55
+ return (
56
+ <Grid container spacing={2}>
57
+ {model.fields.map((field) => {
58
+ const { id, type, xs = 3, sm, md, lg, xl } = field;
59
+
60
+ if (type === "group") {
61
+ return (
62
+ <Grid item key={id} xs={12}>
63
+ <ObjectDetailGroup field={field} instance={instance[id]} />
64
+ </Grid>
65
+ );
66
+ }
67
+
68
+ return (
69
+ <Grid item key={id} xs={xs} sm={sm} md={md} lg={lg} xl={xl}>
70
+ <ValueCard>{singleDetailValueFactory(field, instance)}</ValueCard>
71
+ </Grid>
72
+ );
73
+ })}
74
+ </Grid>
75
+ );
76
+ };
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./components";
2
+ export * from "./utils";
3
+ export * from "./layouts";
4
+ export * from "./generators";
5
+ export * from "./providers";
@@ -0,0 +1,28 @@
1
+ import React from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { AppBarWithDrawerLayout } from "./app-bar-with-drawer-layout";
4
+ import { ContentPlaceholder } from "../../tests";
5
+ import { mockNav } from "../../components/drawer/drawer.mock";
6
+ import { MiniAppBar } from "../../components/app-bar";
7
+ import { DrawerContent, MiniDrawer } from "../../components";
8
+ import { withMemoryRouter } from "~/storybook";
9
+
10
+ export default {
11
+ title: "Layouts/AppBarWithDrawer",
12
+ component: AppBarWithDrawerLayout,
13
+ decorators: [withMemoryRouter()],
14
+ parameters: {
15
+ layout: "fullscreen",
16
+ },
17
+ } as ComponentMeta<typeof AppBarWithDrawerLayout>;
18
+
19
+ export const MiniDrawerStory = () => (
20
+ <AppBarWithDrawerLayout>
21
+ <MiniDrawer>
22
+ <DrawerContent nav={mockNav} />
23
+ </MiniDrawer>
24
+ <MiniAppBar title="Lorem ipsum" onClickSignOut={() => null} />
25
+ <ContentPlaceholder p={3} />
26
+ </AppBarWithDrawerLayout>
27
+ );
28
+ MiniDrawerStory.storyName = "Mini drawer";
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { MiniDrawerStory } from "./app-bar-with-drawer-layout.stories";
3
+ import { expectContentPlaceholder, render, screen } from "../../tests";
4
+ import userEvent from "@testing-library/user-event";
5
+
6
+ describe("AppBarWithDrawerLayout", () => {
7
+ const renderComponent = () => {
8
+ return render(<MiniDrawerStory />);
9
+ };
10
+
11
+ it("would render a drawer", async () => {
12
+ renderComponent();
13
+
14
+ await userEvent.click(screen.getByTestId("MenuIcon"));
15
+
16
+ expect(screen.getByRole("button", { name: /item 1.1/i })).toBeInTheDocument();
17
+ });
18
+
19
+ it("would render an appbar", () => {
20
+ renderComponent();
21
+
22
+ expect(screen.getByRole("heading", { level: 1, name: /lorem ipsum/i })).toBeInTheDocument();
23
+ });
24
+
25
+ it("would render the content", async () => {
26
+ renderComponent();
27
+
28
+ await expectContentPlaceholder();
29
+ });
30
+ });
@@ -0,0 +1,37 @@
1
+ import React, { ReactNode } from "react";
2
+ import { styled } from "@mui/material/styles";
3
+ import { AppBarElement } from "../../components/app-bar";
4
+ import { DrawerElement } from "../../components/drawer";
5
+ import { Box } from "@mui/material";
6
+ import { DrawerProvider } from "../../components/drawer/drawer.provider";
7
+
8
+ const DrawerHeader = styled("div")(({ theme }) => ({
9
+ display: "flex",
10
+ alignItems: "center",
11
+ justifyContent: "flex-end",
12
+ padding: theme.spacing(0, 1),
13
+ ...theme.mixins.toolbar,
14
+ }));
15
+
16
+ export interface AppBarWithDrawerLayoutProps {
17
+ children: [DrawerElement, AppBarElement, ReactNode];
18
+ }
19
+
20
+ export const AppBarWithDrawerLayout = ({
21
+ children: childrenProps,
22
+ }: AppBarWithDrawerLayoutProps) => {
23
+ const [appBar, drawer, children] = childrenProps;
24
+
25
+ return (
26
+ <Box sx={{ display: "flex" }}>
27
+ <DrawerProvider>
28
+ {appBar}
29
+ {drawer}
30
+ <Box sx={{ flexGrow: 1 }}>
31
+ <DrawerHeader />
32
+ {children}
33
+ </Box>
34
+ </DrawerProvider>
35
+ </Box>
36
+ );
37
+ };
@@ -0,0 +1 @@
1
+ export * from "./app-bar-with-drawer-layout";
@@ -0,0 +1,204 @@
1
+ import React, { ReactElement } from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { createTemplate } from "../../storybook";
4
+ import { HeaderLayout } from "./header-layout";
5
+ import { withMemoryRouter } from "~/storybook";
6
+ import { SkeletonGrid } from "../../tests";
7
+ import { withFullHeight } from "../../storybook";
8
+ import { Content, Header, HeaderProps, HeaderTab, TableList, TabPanel } from "../../components";
9
+ import { Box, Typography } from "@mui/material";
10
+ import { useDemoData } from "@mui/x-data-grid-generator";
11
+ import { ModelForm, ObjectDetails } from "../../generators";
12
+ import { mockModel, createModelInstance } from "../../generators/generators.mock";
13
+ import { action } from "@storybook/addon-actions";
14
+ import { DataGrid } from "@mui/x-data-grid";
15
+
16
+ const breadcrumbs = [
17
+ {
18
+ id: "list",
19
+ text: "Items",
20
+ link: "/items",
21
+ },
22
+ {
23
+ id: "item",
24
+ text: "Item 1",
25
+ link: "/items/1",
26
+ },
27
+ ];
28
+
29
+ const actions = [
30
+ {
31
+ id: "new",
32
+ text: "Add",
33
+ },
34
+ ];
35
+
36
+ const tabs: HeaderTab[] = [
37
+ {
38
+ id: "tab1",
39
+ label: "Tab 1",
40
+ },
41
+ {
42
+ id: "tab2",
43
+ label: "Tab 2",
44
+ disabled: true,
45
+ },
46
+ {
47
+ id: "tab3",
48
+ label: "Tab 3",
49
+ },
50
+ ];
51
+
52
+ export default {
53
+ title: "Layouts/HeaderLayout",
54
+ component: HeaderLayout,
55
+ decorators: [withMemoryRouter(), withFullHeight],
56
+ parameters: {
57
+ layout: "fullscreen",
58
+ },
59
+ } as ComponentMeta<typeof HeaderLayout>;
60
+
61
+ interface HeaderLayoutStoryProps {
62
+ headerProps: HeaderProps;
63
+ contentChildren: ReactElement;
64
+ }
65
+
66
+ const Template = createTemplate(
67
+ ({ headerProps, contentChildren, ...rest }: HeaderLayoutStoryProps) => {
68
+ return (
69
+ <HeaderLayout {...rest}>
70
+ <Header {...headerProps} />
71
+ <Content>{contentChildren}</Content>
72
+ </HeaderLayout>
73
+ );
74
+ },
75
+ );
76
+
77
+ export const Skeleton = Template.bind({});
78
+ Skeleton.args = {
79
+ headerProps: {
80
+ title: "Lorem ipsum",
81
+ subtitle: "Dolor sit amet",
82
+ breadcrumbs,
83
+ actions,
84
+ },
85
+ contentChildren: <SkeletonGrid />,
86
+ };
87
+
88
+ const ListContent = () => {
89
+ const { data } = useDemoData({
90
+ dataSet: "Commodity",
91
+ rowLength: 100,
92
+ maxColumns: 3,
93
+ editable: true,
94
+ });
95
+
96
+ const { rows } = data;
97
+ const columns = data.columns.map(({ field, headerName }) => ({
98
+ id: field,
99
+ label: headerName || "",
100
+ sort: true,
101
+ disablePadding: false,
102
+ numeric: false,
103
+ }));
104
+
105
+ return <TableList data={rows} columns={columns} defaultSort={columns[0].id} defaultOrder="asc" />;
106
+ };
107
+
108
+ export const List = Template.bind({});
109
+ List.args = {
110
+ headerProps: {
111
+ title: "Lorem ipsum",
112
+ subtitle: "Dolor sit amet",
113
+ breadcrumbs,
114
+ actions,
115
+ },
116
+ contentChildren: <ListContent />,
117
+ };
118
+
119
+ export const Details = Template.bind({});
120
+ Details.args = {
121
+ headerProps: {
122
+ title: "Lorem ipsum",
123
+ subtitle: "Dolor sit amet",
124
+ breadcrumbs,
125
+ actions,
126
+ },
127
+ contentChildren: <ObjectDetails model={mockModel} instance={createModelInstance(mockModel)} />,
128
+ };
129
+
130
+ export const Form = Template.bind({});
131
+ Form.args = {
132
+ headerProps: {
133
+ title: "Lorem ipsum",
134
+ subtitle: "Dolor sit amet",
135
+ breadcrumbs,
136
+ actions,
137
+ },
138
+ contentChildren: (
139
+ <ModelForm
140
+ model={mockModel}
141
+ initialValues={createModelInstance(mockModel)}
142
+ saveButtonText="Save"
143
+ onSubmit={action("Save form data")}
144
+ />
145
+ ),
146
+ };
147
+
148
+ const DataTableContent = () => {
149
+ const { data } = useDemoData({
150
+ dataSet: "Commodity",
151
+ rowLength: 100,
152
+ maxColumns: 7,
153
+ editable: true,
154
+ });
155
+
156
+ return <DataGrid rows={data.rows} columns={data.columns} pagination sx={{ height: 400 }} />;
157
+ };
158
+
159
+ export const DataTable = Template.bind({});
160
+ DataTable.args = {
161
+ headerProps: {
162
+ title: "Lorem ipsum",
163
+ subtitle: "Dolor sit amet",
164
+ breadcrumbs,
165
+ actions,
166
+ },
167
+ contentChildren: <DataTableContent />,
168
+ };
169
+
170
+ export const Tabs = Template.bind({});
171
+ Tabs.args = {
172
+ headerProps: {
173
+ title: "Lorem ipsum",
174
+ subtitle: "Dolor sit amet",
175
+ breadcrumbs,
176
+ actions,
177
+ tabs,
178
+ },
179
+ contentChildren: (
180
+ <Box>
181
+ <TabPanel index={0}>
182
+ <Typography>Panel 1</Typography>
183
+ </TabPanel>
184
+ <TabPanel index={[1, 2]}>
185
+ <Typography>Panel 2</Typography>
186
+ </TabPanel>
187
+ <TabPanel index={3}>
188
+ <Typography>Panel 3</Typography>
189
+ </TabPanel>
190
+ </Box>
191
+ ),
192
+ };
193
+
194
+ export const Loading = Template.bind({});
195
+ Loading.args = {
196
+ loading: true,
197
+ headerProps: {
198
+ title: "Lorem ipsum",
199
+ subtitle: "Dolor sit amet",
200
+ breadcrumbs,
201
+ actions,
202
+ },
203
+ contentChildren: <SkeletonGrid />,
204
+ };
@@ -0,0 +1,37 @@
1
+ import React from "react";
2
+ import { HeaderLayout } from "./header-layout";
3
+ import { render, screen } from "../../tests";
4
+ import { Content, Header } from "../../components";
5
+ import { Typography } from "@mui/material";
6
+
7
+ describe("HeaderLayout", () => {
8
+ const renderComponent = () => {
9
+ return render(
10
+ <HeaderLayout>
11
+ <Header title="Lorem ipsum" subtitle="Dolor sit amet" />
12
+ <Content>
13
+ <Typography>Test content</Typography>
14
+ </Content>
15
+ </HeaderLayout>,
16
+ );
17
+ };
18
+
19
+ it("would render the header", () => {
20
+ renderComponent();
21
+
22
+ expect(screen.getByRole("heading", { level: 1, name: /lorem ipsum/i })).toBeInTheDocument();
23
+ expect(screen.getByRole("heading", { level: 2, name: /dolor sit amet/i })).toBeInTheDocument();
24
+ });
25
+
26
+ it("would render a main element", () => {
27
+ renderComponent();
28
+
29
+ expect(screen.getByRole("main")).toBeInTheDocument();
30
+ });
31
+
32
+ it("would render the content", () => {
33
+ renderComponent();
34
+
35
+ expect(screen.getByText(/test content/i)).toBeInTheDocument();
36
+ });
37
+ });