@pautena/react-design-system 0.0.1

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 (409) hide show
  1. package/.eslintrc.js +26 -0
  2. package/.github/workflows/ci.yml +23 -0
  3. package/.github/workflows/deploy-storybook.yaml +23 -0
  4. package/.github/workflows/publish.yml +31 -0
  5. package/.husky/pre-commit +5 -0
  6. package/.prettierignore +4 -0
  7. package/.prettierrc.js +5 -0
  8. package/.storybook/main.js +10 -0
  9. package/.storybook/preview.js +36 -0
  10. package/README.md +7 -0
  11. package/babel.config.js +3 -0
  12. package/dist/cjs/index.js +278 -0
  13. package/dist/cjs/index.js.map +1 -0
  14. package/dist/cjs/types/components/app-bar/app-bar.d.ts +2 -0
  15. package/dist/cjs/types/components/app-bar/app-bar.types.d.ts +13 -0
  16. package/dist/cjs/types/components/app-bar/index.d.ts +3 -0
  17. package/dist/cjs/types/components/app-bar/mini-app-bar/index.d.ts +1 -0
  18. package/dist/cjs/types/components/app-bar/mini-app-bar/mini-app-bar.d.ts +2 -0
  19. package/dist/cjs/types/components/bullet/bullet.d.ts +14 -0
  20. package/dist/cjs/types/components/bullet/index.d.ts +1 -0
  21. package/dist/cjs/types/components/center-container/center-container.d.ts +9 -0
  22. package/dist/cjs/types/components/center-container/index.d.ts +1 -0
  23. package/dist/cjs/types/components/drawer/drawer.context.d.ts +9 -0
  24. package/dist/cjs/types/components/drawer/drawer.d.ts +2 -0
  25. package/dist/cjs/types/components/drawer/drawer.mixins.d.ts +4 -0
  26. package/dist/cjs/types/components/drawer/drawer.mock.d.ts +3 -0
  27. package/dist/cjs/types/components/drawer/drawer.provider.d.ts +6 -0
  28. package/dist/cjs/types/components/drawer/drawer.types.d.ts +44 -0
  29. package/dist/cjs/types/components/drawer/index.d.ts +5 -0
  30. package/dist/cjs/types/components/drawer/mini-drawer/index.d.ts +1 -0
  31. package/dist/cjs/types/components/drawer/mini-drawer/mini-drawer.d.ts +1 -0
  32. package/dist/cjs/types/components/drawer-content/drawer-content.d.ts +5 -0
  33. package/dist/cjs/types/components/drawer-content/index.d.ts +1 -0
  34. package/dist/cjs/types/components/drawer-item/drawer-item.d.ts +33 -0
  35. package/dist/cjs/types/components/drawer-item/index.d.ts +1 -0
  36. package/dist/cjs/types/components/drawer-section/drawer-section.d.ts +16 -0
  37. package/dist/cjs/types/components/drawer-section/drawer-section.mock.d.ts +2 -0
  38. package/dist/cjs/types/components/drawer-section/index.d.ts +1 -0
  39. package/dist/cjs/types/components/header/header.d.ts +65 -0
  40. package/dist/cjs/types/components/header/header.dummy.d.ts +4 -0
  41. package/dist/cjs/types/components/header/index.d.ts +1 -0
  42. package/dist/cjs/types/components/index.d.ts +17 -0
  43. package/dist/cjs/types/components/label/index.d.ts +1 -0
  44. package/dist/cjs/types/components/label/label.d.ts +18 -0
  45. package/dist/cjs/types/components/link/index.d.ts +1 -0
  46. package/dist/cjs/types/components/link/link.d.ts +7 -0
  47. package/dist/cjs/types/components/loading-area/index.d.ts +1 -0
  48. package/dist/cjs/types/components/loading-area/loading-area.d.ts +4 -0
  49. package/dist/cjs/types/components/placeholder/index.d.ts +1 -0
  50. package/dist/cjs/types/components/placeholder/placeholder.d.ts +21 -0
  51. package/dist/cjs/types/components/placeholder/placeholder.mock.d.ts +2 -0
  52. package/dist/cjs/types/components/query-container/index.d.ts +1 -0
  53. package/dist/cjs/types/components/query-container/query-container.d.ts +39 -0
  54. package/dist/cjs/types/components/sign-in/index.d.ts +1 -0
  55. package/dist/cjs/types/components/sign-in/sign-in.d.ts +9 -0
  56. package/dist/cjs/types/components/tab/index.d.ts +3 -0
  57. package/dist/cjs/types/components/tab/tab-card/index.d.ts +1 -0
  58. package/dist/cjs/types/components/tab/tab-card/tab-card.d.ts +7 -0
  59. package/dist/cjs/types/components/tab/tab-card/tab-card.dummy.d.ts +7 -0
  60. package/dist/cjs/types/components/tab/tab-panel/index.d.ts +1 -0
  61. package/dist/cjs/types/components/tab/tab-panel/tab-panel.d.ts +7 -0
  62. package/dist/cjs/types/components/tab/tab.context.d.ts +4 -0
  63. package/dist/cjs/types/components/table/enhanced-remote-table/enhanced-remote-table.d.ts +13 -0
  64. package/dist/cjs/types/components/table/enhanced-remote-table/enhanced-remote-table.mock.d.ts +11 -0
  65. package/dist/cjs/types/components/table/enhanced-remote-table/index.d.ts +1 -0
  66. package/dist/cjs/types/components/table/enhanced-table/enhanced-table-head.d.ts +16 -0
  67. package/dist/cjs/types/components/table/enhanced-table/enhanced-table.d.ts +18 -0
  68. package/dist/cjs/types/components/table/enhanced-table/enhanced-table.mock.d.ts +17 -0
  69. package/dist/cjs/types/components/table/enhanced-table/index.d.ts +2 -0
  70. package/dist/cjs/types/components/table/index.d.ts +2 -0
  71. package/dist/cjs/types/components/table-list/index.d.ts +1 -0
  72. package/dist/cjs/types/components/table-list/table-list.d.ts +21 -0
  73. package/dist/cjs/types/components/value-displays/group-value-card/group-value-card.d.ts +15 -0
  74. package/dist/cjs/types/components/value-displays/group-value-card/group-value-card.mock.d.ts +1 -0
  75. package/dist/cjs/types/components/value-displays/group-value-card/index.d.ts +1 -0
  76. package/dist/cjs/types/components/value-displays/index.d.ts +4 -0
  77. package/dist/cjs/types/components/value-displays/value-boolean/index.d.ts +1 -0
  78. package/dist/cjs/types/components/value-displays/value-boolean/value-boolean.d.ts +14 -0
  79. package/dist/cjs/types/components/value-displays/value-card/index.d.ts +1 -0
  80. package/dist/cjs/types/components/value-displays/value-card/value-card.d.ts +6 -0
  81. package/dist/cjs/types/components/value-displays/value-text/index.d.ts +1 -0
  82. package/dist/cjs/types/components/value-displays/value-text/value-text.d.ts +14 -0
  83. package/dist/cjs/types/generators/generators.mock.d.ts +3 -0
  84. package/dist/cjs/types/generators/generators.model.d.ts +33 -0
  85. package/dist/cjs/types/generators/index.d.ts +4 -0
  86. package/dist/cjs/types/generators/model-form/index.d.ts +1 -0
  87. package/dist/cjs/types/generators/model-form/model-form.d.ts +8 -0
  88. package/dist/cjs/types/generators/model-router/index.d.ts +1 -0
  89. package/dist/cjs/types/generators/model-router/model-router.d.ts +35 -0
  90. package/dist/cjs/types/generators/model-router/screens/add-screen.d.ts +2 -0
  91. package/dist/cjs/types/generators/model-router/screens/details-screen.d.ts +2 -0
  92. package/dist/cjs/types/generators/model-router/screens/index.d.ts +4 -0
  93. package/dist/cjs/types/generators/model-router/screens/list-screen.d.ts +2 -0
  94. package/dist/cjs/types/generators/model-router/screens/update-screen.d.ts +2 -0
  95. package/dist/cjs/types/generators/object-details/index.d.ts +1 -0
  96. package/dist/cjs/types/generators/object-details/object-details.d.ts +6 -0
  97. package/dist/cjs/types/index.d.ts +4 -0
  98. package/dist/cjs/types/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.d.ts +10 -0
  99. package/dist/cjs/types/layouts/app-bar-with-drawer-layout/index.d.ts +1 -0
  100. package/dist/cjs/types/layouts/data-table-layout/data-table-layout.d.ts +12 -0
  101. package/dist/cjs/types/layouts/data-table-layout/index.d.ts +1 -0
  102. package/dist/cjs/types/layouts/details-layout/details-layout.d.ts +12 -0
  103. package/dist/cjs/types/layouts/details-layout/index.d.ts +1 -0
  104. package/dist/cjs/types/layouts/form-layout/form-layout.d.ts +8 -0
  105. package/dist/cjs/types/layouts/form-layout/index.d.ts +1 -0
  106. package/dist/cjs/types/layouts/header-layout/header-layout.d.ts +8 -0
  107. package/dist/cjs/types/layouts/header-layout/index.d.ts +1 -0
  108. package/dist/cjs/types/layouts/index.d.ts +7 -0
  109. package/dist/cjs/types/layouts/list-layout/index.d.ts +1 -0
  110. package/dist/cjs/types/layouts/list-layout/list-layout.d.ts +8 -0
  111. package/dist/cjs/types/layouts/tab-layout/index.d.ts +1 -0
  112. package/dist/cjs/types/layouts/tab-layout/tab-layout.d.ts +7 -0
  113. package/dist/cjs/types/providers/index.d.ts +1 -0
  114. package/dist/cjs/types/providers/notification-center/index.d.ts +1 -0
  115. package/dist/cjs/types/providers/notification-center/notification-center.context.d.ts +16 -0
  116. package/dist/cjs/types/providers/notification-center/notification-center.provider.d.ts +5 -0
  117. package/dist/cjs/types/utils/arrays.d.ts +5 -0
  118. package/dist/cjs/types/utils/arrays.test.d.ts +1 -0
  119. package/dist/cjs/types/utils/index.d.ts +2 -0
  120. package/dist/cjs/types/utils/theme.d.ts +4 -0
  121. package/dist/esm/index.js +278 -0
  122. package/dist/esm/index.js.map +1 -0
  123. package/dist/esm/types/components/app-bar/app-bar.d.ts +2 -0
  124. package/dist/esm/types/components/app-bar/app-bar.types.d.ts +13 -0
  125. package/dist/esm/types/components/app-bar/index.d.ts +3 -0
  126. package/dist/esm/types/components/app-bar/mini-app-bar/index.d.ts +1 -0
  127. package/dist/esm/types/components/app-bar/mini-app-bar/mini-app-bar.d.ts +2 -0
  128. package/dist/esm/types/components/bullet/bullet.d.ts +14 -0
  129. package/dist/esm/types/components/bullet/index.d.ts +1 -0
  130. package/dist/esm/types/components/center-container/center-container.d.ts +9 -0
  131. package/dist/esm/types/components/center-container/index.d.ts +1 -0
  132. package/dist/esm/types/components/drawer/drawer.context.d.ts +9 -0
  133. package/dist/esm/types/components/drawer/drawer.d.ts +2 -0
  134. package/dist/esm/types/components/drawer/drawer.mixins.d.ts +4 -0
  135. package/dist/esm/types/components/drawer/drawer.mock.d.ts +3 -0
  136. package/dist/esm/types/components/drawer/drawer.provider.d.ts +6 -0
  137. package/dist/esm/types/components/drawer/drawer.types.d.ts +44 -0
  138. package/dist/esm/types/components/drawer/index.d.ts +5 -0
  139. package/dist/esm/types/components/drawer/mini-drawer/index.d.ts +1 -0
  140. package/dist/esm/types/components/drawer/mini-drawer/mini-drawer.d.ts +1 -0
  141. package/dist/esm/types/components/drawer-content/drawer-content.d.ts +5 -0
  142. package/dist/esm/types/components/drawer-content/index.d.ts +1 -0
  143. package/dist/esm/types/components/drawer-item/drawer-item.d.ts +33 -0
  144. package/dist/esm/types/components/drawer-item/index.d.ts +1 -0
  145. package/dist/esm/types/components/drawer-section/drawer-section.d.ts +16 -0
  146. package/dist/esm/types/components/drawer-section/drawer-section.mock.d.ts +2 -0
  147. package/dist/esm/types/components/drawer-section/index.d.ts +1 -0
  148. package/dist/esm/types/components/header/header.d.ts +65 -0
  149. package/dist/esm/types/components/header/header.dummy.d.ts +4 -0
  150. package/dist/esm/types/components/header/index.d.ts +1 -0
  151. package/dist/esm/types/components/index.d.ts +17 -0
  152. package/dist/esm/types/components/label/index.d.ts +1 -0
  153. package/dist/esm/types/components/label/label.d.ts +18 -0
  154. package/dist/esm/types/components/link/index.d.ts +1 -0
  155. package/dist/esm/types/components/link/link.d.ts +7 -0
  156. package/dist/esm/types/components/loading-area/index.d.ts +1 -0
  157. package/dist/esm/types/components/loading-area/loading-area.d.ts +4 -0
  158. package/dist/esm/types/components/placeholder/index.d.ts +1 -0
  159. package/dist/esm/types/components/placeholder/placeholder.d.ts +21 -0
  160. package/dist/esm/types/components/placeholder/placeholder.mock.d.ts +2 -0
  161. package/dist/esm/types/components/query-container/index.d.ts +1 -0
  162. package/dist/esm/types/components/query-container/query-container.d.ts +39 -0
  163. package/dist/esm/types/components/sign-in/index.d.ts +1 -0
  164. package/dist/esm/types/components/sign-in/sign-in.d.ts +9 -0
  165. package/dist/esm/types/components/tab/index.d.ts +3 -0
  166. package/dist/esm/types/components/tab/tab-card/index.d.ts +1 -0
  167. package/dist/esm/types/components/tab/tab-card/tab-card.d.ts +7 -0
  168. package/dist/esm/types/components/tab/tab-card/tab-card.dummy.d.ts +7 -0
  169. package/dist/esm/types/components/tab/tab-panel/index.d.ts +1 -0
  170. package/dist/esm/types/components/tab/tab-panel/tab-panel.d.ts +7 -0
  171. package/dist/esm/types/components/tab/tab.context.d.ts +4 -0
  172. package/dist/esm/types/components/table/enhanced-remote-table/enhanced-remote-table.d.ts +13 -0
  173. package/dist/esm/types/components/table/enhanced-remote-table/enhanced-remote-table.mock.d.ts +11 -0
  174. package/dist/esm/types/components/table/enhanced-remote-table/index.d.ts +1 -0
  175. package/dist/esm/types/components/table/enhanced-table/enhanced-table-head.d.ts +16 -0
  176. package/dist/esm/types/components/table/enhanced-table/enhanced-table.d.ts +18 -0
  177. package/dist/esm/types/components/table/enhanced-table/enhanced-table.mock.d.ts +17 -0
  178. package/dist/esm/types/components/table/enhanced-table/index.d.ts +2 -0
  179. package/dist/esm/types/components/table/index.d.ts +2 -0
  180. package/dist/esm/types/components/table-list/index.d.ts +1 -0
  181. package/dist/esm/types/components/table-list/table-list.d.ts +21 -0
  182. package/dist/esm/types/components/value-displays/group-value-card/group-value-card.d.ts +15 -0
  183. package/dist/esm/types/components/value-displays/group-value-card/group-value-card.mock.d.ts +1 -0
  184. package/dist/esm/types/components/value-displays/group-value-card/index.d.ts +1 -0
  185. package/dist/esm/types/components/value-displays/index.d.ts +4 -0
  186. package/dist/esm/types/components/value-displays/value-boolean/index.d.ts +1 -0
  187. package/dist/esm/types/components/value-displays/value-boolean/value-boolean.d.ts +14 -0
  188. package/dist/esm/types/components/value-displays/value-card/index.d.ts +1 -0
  189. package/dist/esm/types/components/value-displays/value-card/value-card.d.ts +6 -0
  190. package/dist/esm/types/components/value-displays/value-text/index.d.ts +1 -0
  191. package/dist/esm/types/components/value-displays/value-text/value-text.d.ts +14 -0
  192. package/dist/esm/types/generators/generators.mock.d.ts +3 -0
  193. package/dist/esm/types/generators/generators.model.d.ts +33 -0
  194. package/dist/esm/types/generators/index.d.ts +4 -0
  195. package/dist/esm/types/generators/model-form/index.d.ts +1 -0
  196. package/dist/esm/types/generators/model-form/model-form.d.ts +8 -0
  197. package/dist/esm/types/generators/model-router/index.d.ts +1 -0
  198. package/dist/esm/types/generators/model-router/model-router.d.ts +35 -0
  199. package/dist/esm/types/generators/model-router/screens/add-screen.d.ts +2 -0
  200. package/dist/esm/types/generators/model-router/screens/details-screen.d.ts +2 -0
  201. package/dist/esm/types/generators/model-router/screens/index.d.ts +4 -0
  202. package/dist/esm/types/generators/model-router/screens/list-screen.d.ts +2 -0
  203. package/dist/esm/types/generators/model-router/screens/update-screen.d.ts +2 -0
  204. package/dist/esm/types/generators/object-details/index.d.ts +1 -0
  205. package/dist/esm/types/generators/object-details/object-details.d.ts +6 -0
  206. package/dist/esm/types/index.d.ts +4 -0
  207. package/dist/esm/types/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.d.ts +10 -0
  208. package/dist/esm/types/layouts/app-bar-with-drawer-layout/index.d.ts +1 -0
  209. package/dist/esm/types/layouts/data-table-layout/data-table-layout.d.ts +12 -0
  210. package/dist/esm/types/layouts/data-table-layout/index.d.ts +1 -0
  211. package/dist/esm/types/layouts/details-layout/details-layout.d.ts +12 -0
  212. package/dist/esm/types/layouts/details-layout/index.d.ts +1 -0
  213. package/dist/esm/types/layouts/form-layout/form-layout.d.ts +8 -0
  214. package/dist/esm/types/layouts/form-layout/index.d.ts +1 -0
  215. package/dist/esm/types/layouts/header-layout/header-layout.d.ts +8 -0
  216. package/dist/esm/types/layouts/header-layout/index.d.ts +1 -0
  217. package/dist/esm/types/layouts/index.d.ts +7 -0
  218. package/dist/esm/types/layouts/list-layout/index.d.ts +1 -0
  219. package/dist/esm/types/layouts/list-layout/list-layout.d.ts +8 -0
  220. package/dist/esm/types/layouts/tab-layout/index.d.ts +1 -0
  221. package/dist/esm/types/layouts/tab-layout/tab-layout.d.ts +7 -0
  222. package/dist/esm/types/providers/index.d.ts +1 -0
  223. package/dist/esm/types/providers/notification-center/index.d.ts +1 -0
  224. package/dist/esm/types/providers/notification-center/notification-center.context.d.ts +16 -0
  225. package/dist/esm/types/providers/notification-center/notification-center.provider.d.ts +5 -0
  226. package/dist/esm/types/utils/arrays.d.ts +5 -0
  227. package/dist/esm/types/utils/arrays.test.d.ts +1 -0
  228. package/dist/esm/types/utils/index.d.ts +2 -0
  229. package/dist/esm/types/utils/theme.d.ts +4 -0
  230. package/dist/index.d.ts +594 -0
  231. package/jest.config.js +14 -0
  232. package/jest.setup.ts +5 -0
  233. package/package.json +98 -0
  234. package/rollup.config.js +40 -0
  235. package/src/components/app-bar/app-bar.stories.tsx +54 -0
  236. package/src/components/app-bar/app-bar.test.tsx +142 -0
  237. package/src/components/app-bar/app-bar.tsx +150 -0
  238. package/src/components/app-bar/app-bar.types.ts +16 -0
  239. package/src/components/app-bar/index.ts +3 -0
  240. package/src/components/app-bar/mini-app-bar/index.ts +1 -0
  241. package/src/components/app-bar/mini-app-bar/mini-app-bar.tsx +31 -0
  242. package/src/components/bullet/bullet.stories.tsx +43 -0
  243. package/src/components/bullet/bullet.test.tsx +24 -0
  244. package/src/components/bullet/bullet.tsx +30 -0
  245. package/src/components/bullet/index.ts +1 -0
  246. package/src/components/center-container/center-container.stories.tsx +50 -0
  247. package/src/components/center-container/center-container.test.tsx +16 -0
  248. package/src/components/center-container/center-container.tsx +32 -0
  249. package/src/components/center-container/index.ts +1 -0
  250. package/src/components/drawer/__snapshots__/drawer.test.tsx.snap +20 -0
  251. package/src/components/drawer/drawer.context.ts +20 -0
  252. package/src/components/drawer/drawer.mixins.ts +24 -0
  253. package/src/components/drawer/drawer.mock.tsx +100 -0
  254. package/src/components/drawer/drawer.provider.tsx +23 -0
  255. package/src/components/drawer/drawer.test.tsx +97 -0
  256. package/src/components/drawer/drawer.tsx +30 -0
  257. package/src/components/drawer/drawer.types.ts +53 -0
  258. package/src/components/drawer/index.ts +5 -0
  259. package/src/components/drawer/mini-drawer/index.ts +1 -0
  260. package/src/components/drawer/mini-drawer/mini-drawer.stories.tsx +34 -0
  261. package/src/components/drawer/mini-drawer/mini-drawer.tsx +67 -0
  262. package/src/components/drawer-content/drawer-content.stories.tsx +29 -0
  263. package/src/components/drawer-content/drawer-content.test.tsx +34 -0
  264. package/src/components/drawer-content/drawer-content.tsx +18 -0
  265. package/src/components/drawer-content/index.ts +1 -0
  266. package/src/components/drawer-item/drawer-item.stories.tsx +62 -0
  267. package/src/components/drawer-item/drawer-item.test.tsx +119 -0
  268. package/src/components/drawer-item/drawer-item.tsx +69 -0
  269. package/src/components/drawer-item/index.ts +1 -0
  270. package/src/components/drawer-section/drawer-section.mock.tsx +39 -0
  271. package/src/components/drawer-section/drawer-section.stories.tsx +28 -0
  272. package/src/components/drawer-section/drawer-section.test.tsx +44 -0
  273. package/src/components/drawer-section/drawer-section.tsx +40 -0
  274. package/src/components/drawer-section/index.ts +1 -0
  275. package/src/components/header/header.dummy.ts +55 -0
  276. package/src/components/header/header.stories.tsx +116 -0
  277. package/src/components/header/header.test.tsx +167 -0
  278. package/src/components/header/header.tsx +185 -0
  279. package/src/components/header/index.ts +1 -0
  280. package/src/components/index.ts +17 -0
  281. package/src/components/label/index.ts +1 -0
  282. package/src/components/label/label.stories.tsx +49 -0
  283. package/src/components/label/label.test.tsx +30 -0
  284. package/src/components/label/label.tsx +60 -0
  285. package/src/components/link/index.ts +1 -0
  286. package/src/components/link/link.tsx +17 -0
  287. package/src/components/loading-area/index.ts +1 -0
  288. package/src/components/loading-area/loading-area.stories.tsx +17 -0
  289. package/src/components/loading-area/loading-area.test.tsx +11 -0
  290. package/src/components/loading-area/loading-area.tsx +13 -0
  291. package/src/components/placeholder/index.ts +1 -0
  292. package/src/components/placeholder/placeholder.mock.ts +15 -0
  293. package/src/components/placeholder/placeholder.stories.tsx +44 -0
  294. package/src/components/placeholder/placeholder.test.tsx +76 -0
  295. package/src/components/placeholder/placeholder.tsx +75 -0
  296. package/src/components/query-container/index.ts +1 -0
  297. package/src/components/query-container/query-container.stories.tsx +68 -0
  298. package/src/components/query-container/query-container.test.tsx +95 -0
  299. package/src/components/query-container/query-container.tsx +71 -0
  300. package/src/components/sign-in/index.ts +1 -0
  301. package/src/components/sign-in/sign-in.stories.tsx +36 -0
  302. package/src/components/sign-in/sign-in.test.tsx +95 -0
  303. package/src/components/sign-in/sign-in.tsx +97 -0
  304. package/src/components/tab/index.ts +3 -0
  305. package/src/components/tab/tab-card/index.ts +1 -0
  306. package/src/components/tab/tab-card/tab-card.dummy.tsx +27 -0
  307. package/src/components/tab/tab-card/tab-card.stories.tsx +22 -0
  308. package/src/components/tab/tab-card/tab-card.test.tsx +53 -0
  309. package/src/components/tab/tab-card/tab-card.tsx +30 -0
  310. package/src/components/tab/tab-panel/index.ts +1 -0
  311. package/src/components/tab/tab-panel/tab-panel.test.tsx +26 -0
  312. package/src/components/tab/tab-panel/tab-panel.tsx +27 -0
  313. package/src/components/tab/tab.context.ts +5 -0
  314. package/src/components/table/enhanced-remote-table/enhanced-remote-table.mock.tsx +27 -0
  315. package/src/components/table/enhanced-remote-table/enhanced-remote-table.stories.tsx +24 -0
  316. package/src/components/table/enhanced-remote-table/enhanced-remote-table.test.tsx +77 -0
  317. package/src/components/table/enhanced-remote-table/enhanced-remote-table.tsx +74 -0
  318. package/src/components/table/enhanced-remote-table/index.ts +1 -0
  319. package/src/components/table/enhanced-table/enhanced-table-head.tsx +58 -0
  320. package/src/components/table/enhanced-table/enhanced-table.mock.tsx +93 -0
  321. package/src/components/table/enhanced-table/enhanced-table.stories.tsx +21 -0
  322. package/src/components/table/enhanced-table/enhanced-table.test.tsx +107 -0
  323. package/src/components/table/enhanced-table/enhanced-table.tsx +136 -0
  324. package/src/components/table/enhanced-table/index.ts +2 -0
  325. package/src/components/table/index.ts +2 -0
  326. package/src/components/table-list/index.ts +1 -0
  327. package/src/components/table-list/table-list.stories.tsx +75 -0
  328. package/src/components/table-list/table-list.test.tsx +283 -0
  329. package/src/components/table-list/table-list.tsx +131 -0
  330. package/src/components/value-displays/group-value-card/group-value-card.mock.tsx +35 -0
  331. package/src/components/value-displays/group-value-card/group-value-card.stories.tsx +26 -0
  332. package/src/components/value-displays/group-value-card/group-value-card.test.tsx +58 -0
  333. package/src/components/value-displays/group-value-card/group-value-card.tsx +65 -0
  334. package/src/components/value-displays/group-value-card/index.ts +1 -0
  335. package/src/components/value-displays/index.ts +4 -0
  336. package/src/components/value-displays/value-boolean/index.ts +1 -0
  337. package/src/components/value-displays/value-boolean/value-boolean.stories.tsx +25 -0
  338. package/src/components/value-displays/value-boolean/value-boolean.test.tsx +27 -0
  339. package/src/components/value-displays/value-boolean/value-boolean.tsx +33 -0
  340. package/src/components/value-displays/value-card/index.ts +1 -0
  341. package/src/components/value-displays/value-card/value-card.stories.tsx +22 -0
  342. package/src/components/value-displays/value-card/value-card.test.tsx +18 -0
  343. package/src/components/value-displays/value-card/value-card.tsx +12 -0
  344. package/src/components/value-displays/value-text/index.ts +1 -0
  345. package/src/components/value-displays/value-text/value-test.test.tsx +21 -0
  346. package/src/components/value-displays/value-text/value-text.stories.tsx +26 -0
  347. package/src/components/value-displays/value-text/value-text.tsx +32 -0
  348. package/src/generators/generators.mock.ts +215 -0
  349. package/src/generators/generators.model.ts +41 -0
  350. package/src/generators/index.ts +4 -0
  351. package/src/generators/model-form/index.ts +1 -0
  352. package/src/generators/model-form/model-form.stories.tsx +30 -0
  353. package/src/generators/model-form/model-form.test.tsx +98 -0
  354. package/src/generators/model-form/model-form.tsx +97 -0
  355. package/src/generators/model-router/index.ts +1 -0
  356. package/src/generators/model-router/model-router.stories.tsx +160 -0
  357. package/src/generators/model-router/model-router.test.tsx +633 -0
  358. package/src/generators/model-router/model-router.tsx +54 -0
  359. package/src/generators/model-router/screens/add-screen.tsx +52 -0
  360. package/src/generators/model-router/screens/details-screen.tsx +53 -0
  361. package/src/generators/model-router/screens/index.ts +4 -0
  362. package/src/generators/model-router/screens/list-screen.tsx +81 -0
  363. package/src/generators/model-router/screens/update-screen.tsx +62 -0
  364. package/src/generators/object-details/index.ts +1 -0
  365. package/src/generators/object-details/object-details.stories.tsx +20 -0
  366. package/src/generators/object-details/object-details.test.tsx +21 -0
  367. package/src/generators/object-details/object-details.tsx +70 -0
  368. package/src/index.ts +4 -0
  369. package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.stories.tsx +29 -0
  370. package/src/layouts/app-bar-with-drawer-layout/app-bar-with-drawer-layout.tsx +34 -0
  371. package/src/layouts/app-bar-with-drawer-layout/index.ts +1 -0
  372. package/src/layouts/data-table-layout/data-table-layout.stories.tsx +94 -0
  373. package/src/layouts/data-table-layout/data-table-layout.tsx +30 -0
  374. package/src/layouts/data-table-layout/index.ts +1 -0
  375. package/src/layouts/details-layout/details-layout.stories.tsx +81 -0
  376. package/src/layouts/details-layout/details-layout.tsx +33 -0
  377. package/src/layouts/details-layout/index.ts +1 -0
  378. package/src/layouts/form-layout/form-layout.stories.tsx +65 -0
  379. package/src/layouts/form-layout/form-layout.tsx +18 -0
  380. package/src/layouts/form-layout/index.ts +1 -0
  381. package/src/layouts/header-layout/header-layout.stories.tsx +68 -0
  382. package/src/layouts/header-layout/header-layout.tsx +24 -0
  383. package/src/layouts/header-layout/index.ts +1 -0
  384. package/src/layouts/index.ts +7 -0
  385. package/src/layouts/list-layout/index.ts +1 -0
  386. package/src/layouts/list-layout/list-layout.stories.tsx +102 -0
  387. package/src/layouts/list-layout/list-layout.tsx +36 -0
  388. package/src/layouts/tab-layout/index.ts +1 -0
  389. package/src/layouts/tab-layout/tab-layout.stories.tsx +88 -0
  390. package/src/layouts/tab-layout/tab-layout.tsx +11 -0
  391. package/src/providers/index.ts +1 -0
  392. package/src/providers/notification-center/index.ts +1 -0
  393. package/src/providers/notification-center/notification-center.context.ts +37 -0
  394. package/src/providers/notification-center/notification-center.provider.tsx +51 -0
  395. package/src/providers/notification-center/notification-center.stories.tsx +52 -0
  396. package/src/providers/notification-center/notification-center.test.tsx +112 -0
  397. package/src/storybook.tsx +56 -0
  398. package/src/tests/assertions.ts +72 -0
  399. package/src/tests/components.tsx +60 -0
  400. package/src/tests/content-placeholder.stories.tsx +16 -0
  401. package/src/tests/index.ts +3 -0
  402. package/src/tests/skeleton-card.stories.tsx +18 -0
  403. package/src/tests/testing-library.tsx +65 -0
  404. package/src/utils/arrays.test.ts +9 -0
  405. package/src/utils/arrays.ts +7 -0
  406. package/src/utils/index.ts +2 -0
  407. package/src/utils/theme.ts +6 -0
  408. package/tsconfig.json +27 -0
  409. package/tsconfig.rollup.json +26 -0
@@ -0,0 +1,76 @@
1
+ import React, { ReactElement } from "react";
2
+ import { render, screen } from "../../tests";
3
+ import userEvent from "@testing-library/user-event";
4
+ import { Placeholder, PlaceholderAction } from "./placeholder";
5
+ import { actions as actionData } from "./placeholder.mock";
6
+ import SearchIcon from "@mui/icons-material/Search";
7
+
8
+ const actions = actionData.map((a) => ({ ...a, onClick: jest.fn() }));
9
+
10
+ describe("Placeholder", () => {
11
+ const renderComponent = ({
12
+ actions = undefined,
13
+ icon = undefined,
14
+ }: { actions?: PlaceholderAction[]; icon?: ReactElement } = {}) => {
15
+ return render(
16
+ <Placeholder
17
+ title="Lorem ipsum"
18
+ subtitle="Lorem ipsum sit amet"
19
+ actions={actions}
20
+ icon={() => icon}
21
+ />,
22
+ );
23
+ };
24
+
25
+ it("would render the title", () => {
26
+ renderComponent();
27
+
28
+ expect(screen.getByRole("heading", { name: /lorem ipsum/i, level: 1 })).toBeInTheDocument();
29
+ });
30
+
31
+ it("would render the subtitle", () => {
32
+ renderComponent();
33
+
34
+ expect(
35
+ screen.getByRole("heading", { name: /lorem ipsum sit amet/i, level: 2 }),
36
+ ).toBeInTheDocument();
37
+ });
38
+
39
+ describe("icon", () => {
40
+ it("wouldn't render an icon if it's not set", () => {
41
+ renderComponent({ icon: undefined });
42
+
43
+ expect(screen.queryByTestId("SearchIcon")).not.toBeInTheDocument();
44
+ });
45
+
46
+ it("would render an icon if it's set", () => {
47
+ renderComponent({ icon: <SearchIcon /> });
48
+
49
+ expect(screen.queryByTestId("SearchIcon")).toBeInTheDocument();
50
+ });
51
+ });
52
+
53
+ describe("actions", () => {
54
+ it("wouldn't render an action if they are not set", () => {
55
+ renderComponent({ actions: undefined });
56
+
57
+ expect(screen.queryByRole("button")).not.toBeInTheDocument();
58
+ });
59
+
60
+ it("would render a button for each action", () => {
61
+ renderComponent({ actions });
62
+
63
+ expect(screen.queryAllByRole("button")).toHaveLength(actions.length);
64
+ expect(screen.queryByRole("button", { name: /add/i })).toBeInTheDocument();
65
+ expect(screen.queryByRole("button", { name: /edit/i })).toBeInTheDocument();
66
+ });
67
+
68
+ it("would call onClick if a button is clicked", async () => {
69
+ renderComponent({ actions });
70
+
71
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
72
+
73
+ expect(actions[1].onClick).toHaveBeenCalledTimes(1);
74
+ });
75
+ });
76
+ });
@@ -0,0 +1,75 @@
1
+ import React, { ReactElement } from "react";
2
+ import { Box, Typography, Button } from "@mui/material";
3
+
4
+ type IconColor =
5
+ | "inherit"
6
+ | "action"
7
+ | "disabled"
8
+ | "primary"
9
+ | "secondary"
10
+ | "error"
11
+ | "info"
12
+ | "success"
13
+ | "warning";
14
+
15
+ export interface PlaceholderAction {
16
+ id: string;
17
+ text: string;
18
+ href?: string;
19
+ onClick?: () => void;
20
+ }
21
+
22
+ export interface PlaceholderIconArgs {
23
+ size: number;
24
+ color: IconColor;
25
+ }
26
+
27
+ export interface PlaceholderProps {
28
+ title: string;
29
+ subtitle: string;
30
+ iconSize?: number;
31
+ icon?: ({ size, color }: PlaceholderIconArgs) => ReactElement;
32
+ actions?: PlaceholderAction[];
33
+ }
34
+
35
+ export const Placeholder = ({
36
+ title,
37
+ subtitle,
38
+ icon,
39
+ iconSize = 200,
40
+ actions,
41
+ }: PlaceholderProps) => {
42
+ return (
43
+ <Box
44
+ display="flex"
45
+ flexDirection="column"
46
+ justifyContent="center"
47
+ alignItems="center"
48
+ textAlign="center"
49
+ >
50
+ {icon && icon({ size: iconSize, color: "primary" })}
51
+ <Typography variant="h4" role="heading" aria-level={1}>
52
+ {title}
53
+ </Typography>
54
+ <Typography variant="subtitle1" role="heading" aria-level={2} sx={{ mt: 2 }}>
55
+ {subtitle}
56
+ </Typography>
57
+ {actions && (
58
+ <Box sx={{ pt: 2 }}>
59
+ {actions.map(({ id, text, href, onClick }, index) => (
60
+ <Button
61
+ key={id}
62
+ role="button"
63
+ variant="contained"
64
+ href={href}
65
+ onClick={onClick}
66
+ sx={{ mr: index < actions.length - 1 ? 2 : 0 }}
67
+ >
68
+ {text}
69
+ </Button>
70
+ ))}
71
+ </Box>
72
+ )}
73
+ </Box>
74
+ );
75
+ };
@@ -0,0 +1 @@
1
+ export * from "./query-container";
@@ -0,0 +1,68 @@
1
+ import React from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { createTemplate, withPadding } from "../../storybook";
4
+ import { QueryContainer, QueryContainerProps } from "./query-container";
5
+ import { Typography, Box } from "@mui/material";
6
+
7
+ export default {
8
+ title: "Components/QueryContainer",
9
+ component: QueryContainer,
10
+ decorators: [withPadding()],
11
+ parameters: {
12
+ layout: "fullscreen",
13
+ },
14
+ } as ComponentMeta<typeof QueryContainer>;
15
+
16
+ const Template = createTemplate((args: QueryContainerProps) => {
17
+ return (
18
+ <Box height={300}>
19
+ <QueryContainer {...args}>
20
+ <Typography>Children content</Typography>
21
+ </QueryContainer>
22
+ </Box>
23
+ );
24
+ });
25
+
26
+ export const Fetching = Template.bind({});
27
+ Fetching.args = {
28
+ isFetching: true,
29
+ };
30
+
31
+ export const Error = Template.bind({});
32
+ Error.args = {
33
+ isFetching: false,
34
+ error: {
35
+ name: "Sign in error",
36
+ message: "User and password doesn't match",
37
+ },
38
+ };
39
+
40
+ export const ErrorWithOnlyMessage = Template.bind({});
41
+ ErrorWithOnlyMessage.args = {
42
+ isFetching: false,
43
+ error: {
44
+ message: "Internal error",
45
+ },
46
+ };
47
+
48
+ export const Success = Template.bind({});
49
+ Success.args = {
50
+ isFetching: false,
51
+ success: {
52
+ name: "Item added",
53
+ message: "The new item has been created with id 1",
54
+ },
55
+ };
56
+
57
+ export const SuccessWithOnlyMessage = Template.bind({});
58
+ SuccessWithOnlyMessage.args = {
59
+ isFetching: false,
60
+ success: {
61
+ message: "The new item has been created with id 1",
62
+ },
63
+ };
64
+
65
+ export const Content = Template.bind({});
66
+ Content.args = {
67
+ isFetching: false,
68
+ };
@@ -0,0 +1,95 @@
1
+ import React from "react";
2
+ import { QueryContainer, QueryContainerError, QueryContainerSuccess } from "./query-container";
3
+ import { expectProgressIndicator, render, screen } from "../../tests";
4
+ import { Typography } from "@mui/material";
5
+
6
+ describe("QueryContainer", () => {
7
+ const renderComponent = ({
8
+ isFetching = false,
9
+ error = undefined,
10
+ success = undefined,
11
+ }: {
12
+ isFetching?: boolean;
13
+ error?: QueryContainerError;
14
+ success?: QueryContainerSuccess;
15
+ } = {}) => {
16
+ return render(
17
+ <QueryContainer isFetching={isFetching} error={error} success={success}>
18
+ <Typography>children content</Typography>
19
+ </QueryContainer>,
20
+ );
21
+ };
22
+
23
+ it("would render a loading indicator if isFetching is true", () => {
24
+ renderComponent({ isFetching: true });
25
+
26
+ expectProgressIndicator();
27
+ });
28
+
29
+ describe("error", () => {
30
+ it("would render an error alert", () => {
31
+ renderComponent({ error: { message: "Internal error" } });
32
+
33
+ expect(screen.getByRole("alert")).toHaveAttribute("aria-describedby", "error");
34
+ });
35
+
36
+ it("would render the error message if error is defined", () => {
37
+ renderComponent({ error: { message: "Internal error" } });
38
+
39
+ expect(screen.getByText(/internal error/i)).toBeInTheDocument();
40
+ });
41
+
42
+ it("would render the error title if error.name is defined", () => {
43
+ renderComponent({ error: { name: "Internal error", message: "There was an error" } });
44
+
45
+ expect(screen.getByRole("heading", { name: /internal error/i })).toBeInTheDocument();
46
+ });
47
+
48
+ it("wouldn't render the error title if error is defined but the error.name not", () => {
49
+ renderComponent({ error: { message: "Internal error" } });
50
+
51
+ expect(screen.queryByRole("heading")).not.toBeInTheDocument();
52
+ });
53
+ });
54
+
55
+ describe("success", () => {
56
+ it("would render a success alert", () => {
57
+ renderComponent({ success: { message: "Item added" } });
58
+
59
+ expect(screen.getByRole("alert")).toHaveAttribute("aria-describedby", "success");
60
+ });
61
+
62
+ it("would render the success message if success is defined", () => {
63
+ renderComponent({ success: { message: "Item added" } });
64
+
65
+ expect(screen.getByText(/item added/i)).toBeInTheDocument();
66
+ });
67
+
68
+ it("would render the success title if success.name is defined", () => {
69
+ renderComponent({
70
+ success: { name: "Item added", message: "The item has been added successfully" },
71
+ });
72
+
73
+ expect(screen.getByRole("heading", { name: /item added/i })).toBeInTheDocument();
74
+ });
75
+
76
+ it("wouldn't render the error title if success is defined but the success.name not", () => {
77
+ renderComponent({ success: { message: "Item added" } });
78
+
79
+ expect(screen.queryByRole("heading")).not.toBeInTheDocument();
80
+ });
81
+ //TODO validate the severity of the alert
82
+
83
+ it("would render the content", () => {
84
+ renderComponent({ success: { message: "Item added" } });
85
+
86
+ expect(screen.getByText(/children content/i)).toBeInTheDocument();
87
+ });
88
+ });
89
+
90
+ it("would render the children if isFetching is false and there is no defined error", () => {
91
+ renderComponent({ isFetching: false, error: undefined });
92
+
93
+ expect(screen.getByText(/children content/i)).toBeInTheDocument();
94
+ });
95
+ });
@@ -0,0 +1,71 @@
1
+ import { Alert, AlertTitle, Box } from "@mui/material";
2
+ import React from "react";
3
+ import { PropsWithChildren } from "react";
4
+ import { LoadingArea } from "../loading-area";
5
+
6
+ export interface QueryContainerError {
7
+ /**
8
+ * The error title
9
+ */
10
+ name?: string;
11
+ /**
12
+ * The description of the error
13
+ */
14
+ message: string;
15
+ }
16
+
17
+ export interface QueryContainerSuccess {
18
+ /**
19
+ * The success title
20
+ */
21
+ name?: string;
22
+ /**
23
+ * The success text
24
+ */
25
+ message: string;
26
+ }
27
+
28
+ export type QueryContainerProps = PropsWithChildren<{
29
+ /**
30
+ * There is a query in progress
31
+ */
32
+ isFetching: boolean;
33
+ /**
34
+ * The query has returned an error
35
+ */
36
+ error?: QueryContainerError;
37
+ /**
38
+ * The query has finished successfully
39
+ */
40
+ success?: QueryContainerSuccess;
41
+ }>;
42
+
43
+ /**
44
+ * Component to show different indicators based on the usual api query statuses
45
+ */
46
+ export function QueryContainer({ isFetching, error, success, children }: QueryContainerProps) {
47
+ if (isFetching) {
48
+ return <LoadingArea />;
49
+ }
50
+
51
+ if (error) {
52
+ return (
53
+ <Alert severity="error" role="alert" aria-describedby="error">
54
+ {error.name && <AlertTitle role="heading">{error.name}</AlertTitle>}
55
+ {error.message}
56
+ </Alert>
57
+ );
58
+ }
59
+
60
+ return (
61
+ <Box>
62
+ {success && (
63
+ <Alert severity="success" role="alert" aria-describedby="success" sx={{ mb: 2 }}>
64
+ {success.name && <AlertTitle role="heading">{success.name}</AlertTitle>}
65
+ {success.message}
66
+ </Alert>
67
+ )}
68
+ {children}
69
+ </Box>
70
+ );
71
+ }
@@ -0,0 +1 @@
1
+ export * from "./sign-in";
@@ -0,0 +1,36 @@
1
+ import { ComponentMeta } from "@storybook/react";
2
+ import { SignIn } from "./sign-in";
3
+ import { createTemplate } from "../../storybook";
4
+
5
+ export default {
6
+ title: "Forms/Sign In",
7
+ component: SignIn,
8
+ parameters: {
9
+ layout: "centered",
10
+ },
11
+ } as ComponentMeta<typeof SignIn>;
12
+
13
+ const Template = createTemplate(SignIn);
14
+
15
+ export const Default = Template.bind({});
16
+ Default.args = {
17
+ title: "Sign in into Garmin Workouts",
18
+ subtitle: "Enter your details below",
19
+ };
20
+
21
+ export const Error = Template.bind({});
22
+ Error.args = {
23
+ title: "Sign in into Garmin Workouts",
24
+ subtitle: "Enter your details below",
25
+ error: {
26
+ name: "InvalidCredentials",
27
+ message: "Invalid user credentials",
28
+ },
29
+ };
30
+
31
+ export const Loading = Template.bind({});
32
+ Loading.args = {
33
+ title: "Sign in into Garmin Workouts",
34
+ subtitle: "Enter your details below",
35
+ loading: true,
36
+ };
@@ -0,0 +1,95 @@
1
+ import React from "react";
2
+ import { SignIn } from "./sign-in";
3
+ import { expectProgressIndicator, render, screen } from "../../tests";
4
+ import userEvent from "@testing-library/user-event";
5
+
6
+ async function submitSignIn(email: string | null, password: string | null) {
7
+ email && (await userEvent.type(screen.getByRole("input", { name: /email/i }), email));
8
+ password && (await userEvent.type(screen.getByRole("input", { name: /password/i }), password));
9
+ await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
10
+ }
11
+
12
+ describe("SignIn", () => {
13
+ it("the title is displayed", () => {
14
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={() => null} />);
15
+ expect(screen.getByText("Lorem ipsum")).toBeInTheDocument();
16
+ });
17
+
18
+ it("the subtitle is displayed", () => {
19
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={() => null} />);
20
+ expect(screen.getByText("Sit amet")).toBeInTheDocument();
21
+ });
22
+
23
+ it("if I enter an email and a password and I submit onSubmitSignIn is called", async () => {
24
+ const onSubmitSignIn = jest.fn();
25
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={onSubmitSignIn} />);
26
+
27
+ await submitSignIn("test@example.com", "password1");
28
+
29
+ expect(onSubmitSignIn).toHaveBeenCalledTimes(1);
30
+ expect(onSubmitSignIn).toHaveBeenCalledWith("test@example.com", "password1");
31
+ });
32
+
33
+ it("if I don't enter an email and I submit an error is shown and onSubmitSignIn is not called", async () => {
34
+ const onSubmitSignIn = jest.fn();
35
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={onSubmitSignIn} />);
36
+
37
+ await submitSignIn(null, "password1");
38
+
39
+ expect(screen.getByText(/please fill out this field/i)).toBeInTheDocument();
40
+ expect(onSubmitSignIn).not.toHaveBeenCalled();
41
+ });
42
+
43
+ it("if I don't enter a valid email and I submit onSubmitSignIn is not called", async () => {
44
+ const onSubmitSignIn = jest.fn();
45
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={onSubmitSignIn} />);
46
+
47
+ await submitSignIn("invalid.com", "password1");
48
+
49
+ expect(onSubmitSignIn).not.toHaveBeenCalled();
50
+ });
51
+
52
+ it("if I don't enter an password and I submit an error is shown and onSubmitSignIn is not called", async () => {
53
+ const onSubmitSignIn = jest.fn();
54
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={onSubmitSignIn} />);
55
+
56
+ await submitSignIn("test@example.com", null);
57
+
58
+ expect(screen.getByText(/please fill out this field/i)).toBeInTheDocument();
59
+ expect(onSubmitSignIn).not.toHaveBeenCalled();
60
+ });
61
+
62
+ it("if I have an error and I enter the fields the errors are removed when I submit", async () => {
63
+ const onSubmitSignIn = jest.fn();
64
+ render(<SignIn title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={onSubmitSignIn} />);
65
+
66
+ await userEvent.click(screen.getByRole("button", { name: /sign in/i }));
67
+ expect(screen.getAllByText(/please fill out this field/i)).toBeTruthy();
68
+
69
+ await submitSignIn("test@example.com", "password1");
70
+
71
+ expect(screen.queryByText(/please fill out this field/i)).not.toBeInTheDocument();
72
+ expect(onSubmitSignIn).toHaveBeenCalledTimes(1);
73
+ expect(onSubmitSignIn).toHaveBeenCalledWith("test@example.com", "password1");
74
+ });
75
+
76
+ describe("if loading is true", () => {
77
+ it("the inputs and buttons are disabled", () => {
78
+ render(
79
+ <SignIn loading title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={() => null} />,
80
+ );
81
+
82
+ expect(screen.getByRole("input", { name: /email/i })).toBeDisabled();
83
+ expect(screen.getByRole("input", { name: /password/i })).toBeDisabled();
84
+ expect(screen.getByRole("button", { name: /sign in/i })).toBeDisabled();
85
+ });
86
+
87
+ it("a loading spinner appears", () => {
88
+ render(
89
+ <SignIn loading title="Lorem ipsum" subtitle="Sit amet" onSubmitSignIn={() => null} />,
90
+ );
91
+
92
+ expectProgressIndicator();
93
+ });
94
+ });
95
+ });
@@ -0,0 +1,97 @@
1
+ import React, { FormEvent, useState } from "react";
2
+ import { Stack, Box, TextField, Typography, Alert } from "@mui/material";
3
+ import { LoadingButton } from "@mui/lab";
4
+
5
+ interface Props {
6
+ title: string;
7
+ subtitle: string;
8
+ error?: Error;
9
+ loading?: boolean;
10
+ onSubmitSignIn: (email: string, password: string) => void;
11
+ }
12
+
13
+ export function SignIn({ title, subtitle, loading, error, onSubmitSignIn }: Props) {
14
+ const [emailError, setEmailError] = useState("");
15
+ const [passwordError, setPasswordError] = useState("");
16
+
17
+ function handleSubmit(e: FormEvent<HTMLFormElement>) {
18
+ e.preventDefault();
19
+ setEmailError("");
20
+ setPasswordError("");
21
+
22
+ const data = new FormData(e.currentTarget);
23
+ const email = data.get("email")?.toString();
24
+ const password = data.get("password")?.toString();
25
+
26
+ if (!email) {
27
+ setEmailError("Please fill out this field");
28
+ }
29
+
30
+ if (!password) {
31
+ setPasswordError("Please fill out this field");
32
+ }
33
+
34
+ if (email && password) {
35
+ onSubmitSignIn(email, password);
36
+ }
37
+ }
38
+
39
+ return (
40
+ <>
41
+ <Box marginBottom={2}>
42
+ <Typography component="h1" variant="h4">
43
+ {title}
44
+ </Typography>
45
+ <Typography variant="body1">{subtitle}</Typography>
46
+ </Box>
47
+ <Box component="form" onSubmit={handleSubmit}>
48
+ {error && (
49
+ <Stack width="100%" marginTop={1}>
50
+ <Alert variant="filled" severity="error">
51
+ {error.message}
52
+ </Alert>
53
+ </Stack>
54
+ )}
55
+ <TextField
56
+ margin="normal"
57
+ fullWidth
58
+ id="email"
59
+ label="Email Address"
60
+ name="email"
61
+ autoComplete="email"
62
+ autoFocus
63
+ disabled={loading}
64
+ type="email"
65
+ inputProps={{ role: "input" }}
66
+ error={!!emailError}
67
+ helperText={emailError}
68
+ />
69
+ <TextField
70
+ margin="normal"
71
+ fullWidth
72
+ role="input"
73
+ name="password"
74
+ label="Password"
75
+ type="password"
76
+ id="password"
77
+ disabled={loading}
78
+ autoComplete="current-password"
79
+ inputProps={{ role: "input" }}
80
+ error={!!passwordError}
81
+ helperText={passwordError}
82
+ />
83
+ <LoadingButton
84
+ type="submit"
85
+ fullWidth
86
+ variant="contained"
87
+ loading={loading}
88
+ disabled={loading}
89
+ role="button"
90
+ sx={{ mt: 2 }}
91
+ >
92
+ Sign In
93
+ </LoadingButton>
94
+ </Box>
95
+ </>
96
+ );
97
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./tab-panel";
2
+ export * from "./tab-card";
3
+ export * from "./tab.context";
@@ -0,0 +1 @@
1
+ export * from "./tab-card";
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import { TabCard } from "./tab-card";
3
+ import { TabPanel } from "../tab-panel";
4
+ import { Typography } from "@mui/material";
5
+
6
+ export const DummyTabs = ["tab 1", "tab 2.1", "tab 2.2", "tab 3"];
7
+
8
+ interface Props {
9
+ tabs: string[];
10
+ initialTab: number;
11
+ }
12
+
13
+ export function TabCardDummy({ tabs, initialTab }: Props) {
14
+ return (
15
+ <TabCard tabs={tabs} initialTab={initialTab}>
16
+ <TabPanel index={0}>
17
+ <Typography>Panel 1</Typography>
18
+ </TabPanel>
19
+ <TabPanel index={[1, 2]}>
20
+ <Typography>Panel 2</Typography>
21
+ </TabPanel>
22
+ <TabPanel index={3}>
23
+ <Typography>Panel 3</Typography>
24
+ </TabPanel>
25
+ </TabCard>
26
+ );
27
+ }
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import { ComponentMeta } from "@storybook/react";
3
+ import { TabCard } from "./tab-card";
4
+ import { createTemplate } from "../../../storybook";
5
+ import { DummyTabs, TabCardDummy } from "./tab-card.dummy";
6
+
7
+ export default {
8
+ title: "Cards/Tab card",
9
+ component: TabCard,
10
+ parameters: {
11
+ layout: "fullscreen",
12
+ },
13
+ } as ComponentMeta<typeof TabCard>;
14
+
15
+ const Template = createTemplate((props) => {
16
+ return <TabCardDummy {...props} />;
17
+ });
18
+
19
+ export const Default = Template.bind({});
20
+ Default.args = {
21
+ tabs: DummyTabs,
22
+ };