@pautena/react-design-system 0.7.2 → 0.7.3

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 (51) hide show
  1. package/dist/cjs/index.js +4 -4
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/alerts/expandable-alert/expandable-alert.d.ts +4 -1
  4. package/dist/cjs/types/components/data-display/board/board.d.ts +1 -2
  5. package/dist/cjs/types/components/feedback/query-container/query-container.d.ts +7 -3
  6. package/dist/cjs/types/components/inputs/index.d.ts +1 -0
  7. package/dist/cjs/types/components/value-displays/group-value-card/group-value-card.mock.d.ts +3 -1
  8. package/dist/cjs/types/components/value-displays/value-base/value-edit.d.ts +7 -2
  9. package/dist/cjs/types/components/value-displays/value-content/value-content.d.ts +10 -1
  10. package/dist/esm/index.js +4 -4
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/types/components/alerts/expandable-alert/expandable-alert.d.ts +4 -1
  13. package/dist/esm/types/components/data-display/board/board.d.ts +1 -2
  14. package/dist/esm/types/components/feedback/query-container/query-container.d.ts +7 -3
  15. package/dist/esm/types/components/inputs/index.d.ts +1 -0
  16. package/dist/esm/types/components/value-displays/group-value-card/group-value-card.mock.d.ts +3 -1
  17. package/dist/esm/types/components/value-displays/value-base/value-edit.d.ts +7 -2
  18. package/dist/esm/types/components/value-displays/value-content/value-content.d.ts +10 -1
  19. package/dist/index.d.ts +26 -9
  20. package/package.json +2 -1
  21. package/src/components/alerts/expandable-alert/expandable-alert.stories.tsx +23 -1
  22. package/src/components/alerts/expandable-alert/expandable-alert.tsx +11 -4
  23. package/src/components/data-display/board/board.test.tsx +60 -43
  24. package/src/components/data-display/board/board.tsx +13 -16
  25. package/src/components/feedback/query-container/query-container.stories.tsx +19 -6
  26. package/src/components/feedback/query-container/query-container.test.tsx +41 -17
  27. package/src/components/feedback/query-container/query-container.tsx +17 -5
  28. package/src/components/inputs/index.ts +1 -0
  29. package/src/components/value-displays/group-value-card/group-value-card.mock.tsx +28 -8
  30. package/src/components/value-displays/group-value-card/group-value-card.stories.tsx +19 -2
  31. package/src/components/value-displays/group-value-card/group-value-card.test.tsx +16 -18
  32. package/src/components/value-displays/value-base/value-edit.test.tsx +88 -0
  33. package/src/components/value-displays/value-base/value-edit.tsx +28 -6
  34. package/src/components/value-displays/value-boolean/value-boolean.stories.tsx +9 -0
  35. package/src/components/value-displays/value-boolean/value-boolean.test.tsx +29 -15
  36. package/src/components/value-displays/value-boolean/value-boolean.tsx +18 -11
  37. package/src/components/value-displays/value-content/value-content.test.tsx +20 -6
  38. package/src/components/value-displays/value-content/value-content.tsx +24 -10
  39. package/src/components/value-displays/value-datetime/value-datetime.stories.tsx +11 -0
  40. package/src/components/value-displays/value-datetime/value-datetime.test.tsx +9 -9
  41. package/src/components/value-displays/value-datetime/value-datetime.tsx +14 -10
  42. package/src/components/value-displays/value-rating/value-rating.stories.tsx +10 -0
  43. package/src/components/value-displays/value-rating/value-rating.test.tsx +11 -11
  44. package/src/components/value-displays/value-rating/value-rating.tsx +10 -8
  45. package/src/components/value-displays/value-text/value-text.stories.tsx +9 -0
  46. package/src/components/value-displays/value-text/value-text.test.tsx +20 -9
  47. package/src/components/value-displays/value-text/value-text.tsx +23 -10
  48. package/src/generators/model-form/model-form.test.tsx +1 -1
  49. package/src/generators/model-router/model-router.test.tsx +3 -3
  50. package/src/layouts/header-layout/header-layout.stories.tsx +2 -2
  51. package/src/layouts/header-layout/header-layout.tsx +1 -7
@@ -1,4 +1,5 @@
1
- import { AlertColor } from "@mui/material";
1
+ import { AlertColor, SxProps, Theme } from "@mui/material";
2
+ import { ReactElement } from "react";
2
3
  import React from "react";
3
4
  export interface ExpandableAlertProps {
4
5
  severity: AlertColor;
@@ -6,6 +7,8 @@ export interface ExpandableAlertProps {
6
7
  title?: string;
7
8
  message: string;
8
9
  metadata?: string | string[];
10
+ metadataComponent?: ReactElement;
9
11
  onClose: () => void;
12
+ sx?: SxProps<Theme>;
10
13
  }
11
14
  export declare const ExpandableAlert: React.ForwardRefExoticComponent<ExpandableAlertProps & React.RefAttributes<any>>;
@@ -4,7 +4,6 @@ export type BoardProps = PropsWithChildren<{
4
4
  markdown?: string;
5
5
  content?: string | string[];
6
6
  spacing?: 0 | 1 | 2 | 3 | 4 | 5;
7
- timeoutCopyText?: number;
8
7
  sx?: SxProps<Theme>;
9
8
  }>;
10
- export declare const Board: ({ markdown: markdownProps, content: contentProp, spacing, timeoutCopyText, children, sx, }: BoardProps) => JSX.Element;
9
+ export declare const Board: ({ markdown: markdownProps, content: contentProp, spacing, children, sx, }: BoardProps) => JSX.Element;
@@ -21,9 +21,13 @@ export interface QueryContainerSuccess {
21
21
  }
22
22
  export type QueryContainerProps = PropsWithChildren<{
23
23
  /**
24
- * There is a query in progress
24
+ * There is a query in progress and we have available data
25
25
  */
26
- isFetching: boolean;
26
+ fetching: boolean;
27
+ /**
28
+ * There is a query in progress and we don't have available data
29
+ */
30
+ loading: boolean;
27
31
  /**
28
32
  * The query has returned an error
29
33
  */
@@ -36,4 +40,4 @@ export type QueryContainerProps = PropsWithChildren<{
36
40
  /**
37
41
  * Component to show different indicators based on the usual api query statuses
38
42
  */
39
- export declare function QueryContainer({ isFetching, error, success, children }: QueryContainerProps): JSX.Element;
43
+ export declare function QueryContainer({ fetching, loading, error, success, children, }: QueryContainerProps): JSX.Element;
@@ -1,3 +1,4 @@
1
1
  export * from "./select";
2
2
  export * from "./sign-in";
3
3
  export * from "./autocomplete";
4
+ export * from "./text-field";
@@ -1,2 +1,4 @@
1
1
  import { GroupValueCardProps } from "./group-value-card";
2
- export declare const GroupValueCardDummy: ({ dense, ...rest }: GroupValueCardProps) => JSX.Element;
2
+ export declare const GroupValueCardDummy: ({ dense, editable, ...rest }: GroupValueCardProps & {
3
+ editable?: boolean | undefined;
4
+ }) => JSX.Element;
@@ -2,10 +2,10 @@ import React from "react";
2
2
  import { SxProps, Theme } from "@mui/material";
3
3
  export interface ValueEditButtonsProps {
4
4
  onClickCancel: () => void;
5
- onSubmitEdit: () => void;
5
+ onClickSubmit: () => void;
6
6
  sx?: SxProps<Theme>;
7
7
  }
8
- export declare const ValueEditButtons: ({ onClickCancel, onSubmitEdit, sx }: ValueEditButtonsProps) => JSX.Element;
8
+ export declare const ValueEditButtons: ({ onClickCancel, onClickSubmit, sx }: ValueEditButtonsProps) => JSX.Element;
9
9
  /**
10
10
  * Hook to manage the editing behaviour
11
11
  */
@@ -17,3 +17,8 @@ export declare const useEditableValueDisplay: <T>(initialValue: T | undefined, o
17
17
  startEdit: () => void;
18
18
  submitEdit: () => void;
19
19
  };
20
+ export interface ValueEditButtonProps {
21
+ dense?: boolean;
22
+ onClick: () => void;
23
+ }
24
+ export declare const ValueEditButton: ({ dense, onClick }: ValueEditButtonProps) => JSX.Element;
@@ -1,3 +1,4 @@
1
+ import { SxProps, Theme } from "@mui/material";
1
2
  import React from "react";
2
3
  export declare const getValueContentLabelId: (label: string) => string;
3
4
  export interface ValueContentProps {
@@ -5,6 +6,10 @@ export interface ValueContentProps {
5
6
  * Name of the displayed value
6
7
  */
7
8
  label: string;
9
+ /**
10
+ * If true, the label will not be shown
11
+ */
12
+ hideLabel?: boolean;
8
13
  /**
9
14
  * If defined, a tooltip is going to be added arround the children;
10
15
  */
@@ -22,8 +27,12 @@ export interface ValueContentProps {
22
27
  * False by default
23
28
  */
24
29
  dense?: boolean;
30
+ /**
31
+ * Custom styles for the root component
32
+ */
33
+ sx?: SxProps<Theme>;
25
34
  }
26
35
  /**
27
36
  * Displays a string value with a label
28
37
  */
29
- export declare const ValueContent: ({ label, tooltip, tooltipEnterDelay, children, dense, }: ValueContentProps) => JSX.Element;
38
+ export declare const ValueContent: ({ label, hideLabel, tooltip, tooltipEnterDelay, children, dense, sx, }: ValueContentProps) => JSX.Element;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  import * as React$1 from 'react';
3
3
  import React__default, { PropsWithChildren, FunctionComponent, ReactElement, ReactNode, FormEvent, Dispatch, SetStateAction } from 'react';
4
4
  import * as _mui_material from '@mui/material';
5
- import { SxProps, Theme, GridProps, PropTypes, AppBarProps, DrawerProps as DrawerProps$1, ListSubheaderProps, ChipTypeMap, AutocompleteProps as AutocompleteProps$1, AlertColor, Color } from '@mui/material';
5
+ import { SxProps, Theme, GridProps, PropTypes, AppBarProps, DrawerProps as DrawerProps$1, ListSubheaderProps, ChipTypeMap, AutocompleteProps as AutocompleteProps$1, TextFieldProps as TextFieldProps$1, AlertColor, Color } from '@mui/material';
6
6
  import * as _mui_system from '@mui/system';
7
7
  import { ResponsiveStyleValue } from '@mui/system';
8
8
  import { MarkdownToJSX } from 'markdown-to-jsx';
@@ -15,10 +15,10 @@ import { LoremUnit } from 'lorem-ipsum/types/src/constants/units';
15
15
 
16
16
  interface ValueEditButtonsProps {
17
17
  onClickCancel: () => void;
18
- onSubmitEdit: () => void;
18
+ onClickSubmit: () => void;
19
19
  sx?: SxProps<Theme>;
20
20
  }
21
- declare const ValueEditButtons: ({ onClickCancel, onSubmitEdit, sx }: ValueEditButtonsProps) => JSX.Element;
21
+ declare const ValueEditButtons: ({ onClickCancel, onClickSubmit, sx }: ValueEditButtonsProps) => JSX.Element;
22
22
  /**
23
23
  * Hook to manage the editing behaviour
24
24
  */
@@ -30,6 +30,11 @@ declare const useEditableValueDisplay: <T>(initialValue: T | undefined, onEdit:
30
30
  startEdit: () => void;
31
31
  submitEdit: () => void;
32
32
  };
33
+ interface ValueEditButtonProps {
34
+ dense?: boolean;
35
+ onClick: () => void;
36
+ }
37
+ declare const ValueEditButton: ({ dense, onClick }: ValueEditButtonProps) => JSX.Element;
33
38
 
34
39
  interface BaseValueProps<T> {
35
40
  /**
@@ -151,9 +156,13 @@ interface QueryContainerSuccess {
151
156
  }
152
157
  type QueryContainerProps = PropsWithChildren<{
153
158
  /**
154
- * There is a query in progress
159
+ * There is a query in progress and we have available data
155
160
  */
156
- isFetching: boolean;
161
+ fetching: boolean;
162
+ /**
163
+ * There is a query in progress and we don't have available data
164
+ */
165
+ loading: boolean;
157
166
  /**
158
167
  * The query has returned an error
159
168
  */
@@ -166,7 +175,7 @@ type QueryContainerProps = PropsWithChildren<{
166
175
  /**
167
176
  * Component to show different indicators based on the usual api query statuses
168
177
  */
169
- declare function QueryContainer({ isFetching, error, success, children }: QueryContainerProps): JSX.Element;
178
+ declare function QueryContainer({ fetching, loading, error, success, children, }: QueryContainerProps): JSX.Element;
170
179
 
171
180
  type BulletVariant = "primary" | "secondary" | "default" | "info" | "warning" | "error";
172
181
  declare const bulletClasses: {
@@ -300,10 +309,9 @@ type BoardProps = PropsWithChildren<{
300
309
  markdown?: string;
301
310
  content?: string | string[];
302
311
  spacing?: 0 | 1 | 2 | 3 | 4 | 5;
303
- timeoutCopyText?: number;
304
312
  sx?: SxProps<Theme>;
305
313
  }>;
306
- declare const Board: ({ markdown: markdownProps, content: contentProp, spacing, timeoutCopyText, children, sx, }: BoardProps) => JSX.Element;
314
+ declare const Board: ({ markdown: markdownProps, content: contentProp, spacing, children, sx, }: BoardProps) => JSX.Element;
307
315
 
308
316
  interface MarkdownProps {
309
317
  content: string;
@@ -496,6 +504,13 @@ interface AutocompleteProps<T, Multiple extends boolean | undefined, DisableClea
496
504
  }
497
505
  declare const Autocomplete: <T, Multiple extends boolean | undefined, DisableClearable extends boolean | undefined, FreeSolo extends boolean | undefined, ChipComponent extends React__default.ElementType<any> = "div">(props: AutocompleteProps<T, Multiple, DisableClearable, FreeSolo, ChipComponent>) => JSX.Element;
498
506
 
507
+ type TextFieldProps = TextFieldProps$1 & {
508
+ fetching?: boolean;
509
+ loading?: boolean;
510
+ hexColor?: string;
511
+ };
512
+ declare const TextField: ({ id: overrideId, label, InputLabelProps, InputProps, fetching, loading, helperText, hexColor, size, fullWidth, sx, ...rest }: TextFieldProps) => JSX.Element;
513
+
499
514
  interface TabPanelProps {
500
515
  children?: React__default.ReactNode;
501
516
  index: number | number[];
@@ -601,7 +616,9 @@ interface ExpandableAlertProps {
601
616
  title?: string;
602
617
  message: string;
603
618
  metadata?: string | string[];
619
+ metadataComponent?: ReactElement;
604
620
  onClose: () => void;
621
+ sx?: SxProps<Theme>;
605
622
  }
606
623
  declare const ExpandableAlert: React__default.ForwardRefExoticComponent<ExpandableAlertProps & React__default.RefAttributes<any>>;
607
624
 
@@ -984,4 +1001,4 @@ type TabProviderProps = PropsWithChildren<{
984
1001
  }>;
985
1002
  declare const TabProvider: ({ children, initialValue }: TabProviderProps) => JSX.Element;
986
1003
 
987
- export { ArrayFieldType, ArrayGroupField, ArrayInstanceType, Autocomplete, AutocompleteProps, BaseFieldType, BaseValueProps, BasicModelInstance, Board, BoardProps, BootstrapDialog, BootstrapDialogDialogProps, Bullet, BulletProps, BulletVariant, CenterContainer, CenterContainerProps, ConfirmDialog, ConfirmDialogProps, Content, ContentComponent, ContentElement, ContentPlaceholder, ContentPlaceholderProps, ContentProps, DefaultPlaceholder, DialogAction, Drawer, DrawerAppBar, DrawerAppBarComponent, DrawerAppBarElement, DrawerAppBarProps, DrawerComponent, DrawerContent, DrawerContentComponent, DrawerContentElement, DrawerContentProps, DrawerContext, DrawerContextProps, DrawerElement, DrawerHeader, DrawerItemAvatar, DrawerItemBullet, DrawerItemLabel, DrawerLayout, DrawerLayoutProps, DrawerMain, DrawerMainProps, DrawerNavigation, DrawerNavigationItem, DrawerNavigationItemCollapsable, DrawerNavigationItemLink, DrawerNavigationSection, DrawerProps, DrawerProvider, DrawerProviderProps, DrawerSection, DrawerSectionProps, DrawerSize, DrawerState, DrawerSubheader, DrawerSubheaderProps, DrawerVariant, EditInputType, EditableValueProps, EnhancedRemoteTable, EnhancedRemoteTableProps, EnhancedTable, EnhancedTableHead, ExpandableAlert, ExpandableAlertProps, FieldType, FormDialog, FormDialogProps, GroupField, GroupInstanceType, GroupValueCard, GroupValueCardProps, HeadCell, Header, HeaderAction, HeaderActionVariant, HeaderBreadcrumb, HeaderComponent, HeaderElement, HeaderLayout, HeaderLayoutError, HeaderLayoutProps, HeaderNavigationButton, HeaderPreset, HeaderProps, HeaderTab, IdleRequest, Label, LabelProps, LabelVariant, LoadingArea, LoadingRequest, LoremIpsumPlaceholder, LoremIpsumPlaceholderProps, Markdown, MarkdownProps, Model, ModelField, ModelFieldTypes, ModelForm, ModelFormProps, ModelRouter, ModelRouterProps, Notification, NotificationCenterContext, NotificationCenterProps, NotificationCenterProvider, NotificationCenterProviderProps, NotificationCenterProviderUndefinedError, NotifyWhenValueChangesOptions, ObjectDetails, ObjectDetailsProps, Order, Placeholder, PlaceholderAction, PlaceholderIcon, PlaceholderIconArgs, PlaceholderProps, QueryContainer, QueryContainerError, QueryContainerProps, QueryContainerSuccess, RequestState, Select, SelectProps, SelectSize, SignIn, SignInProps, SingleFieldType, SkeletonCard, SkeletonCardProps, SkeletonGrid, SkeletonGridProps, SuccessRequest, TabCard, TabCardProps, TabContext, TabContextProvider, TabPanel, TabProvider, TableList, TableListProps, TableRowOption, UndefinedProvider, ValueBoolean, ValueBooleanProps, ValueCard, ValueCardProps, ValueDatetime, ValueDatetimeProps, ValueEditButtons, ValueEditButtonsProps, ValueItem, ValueItemComponent, ValueItemElement, ValueItemProps, ValueRating, ValueRatingProps, ValueText, ValueTextProps, bulletClasses, getDrawerItemColors, getFormData, getRandomItem, labelClasses, markdownDefaultOptions, newArrayWithSize, newBreakpointsCounter, newInstanceFromValuesOrZeroValue, useDialog, useDrawer, useEditableValueDisplay, useGetDefaultThemeColor, useNotificationCenter, useNotifyWhenValueChanges, useTab, valueItemClasses };
1004
+ export { ArrayFieldType, ArrayGroupField, ArrayInstanceType, Autocomplete, AutocompleteProps, BaseFieldType, BaseValueProps, BasicModelInstance, Board, BoardProps, BootstrapDialog, BootstrapDialogDialogProps, Bullet, BulletProps, BulletVariant, CenterContainer, CenterContainerProps, ConfirmDialog, ConfirmDialogProps, Content, ContentComponent, ContentElement, ContentPlaceholder, ContentPlaceholderProps, ContentProps, DefaultPlaceholder, DialogAction, Drawer, DrawerAppBar, DrawerAppBarComponent, DrawerAppBarElement, DrawerAppBarProps, DrawerComponent, DrawerContent, DrawerContentComponent, DrawerContentElement, DrawerContentProps, DrawerContext, DrawerContextProps, DrawerElement, DrawerHeader, DrawerItemAvatar, DrawerItemBullet, DrawerItemLabel, DrawerLayout, DrawerLayoutProps, DrawerMain, DrawerMainProps, DrawerNavigation, DrawerNavigationItem, DrawerNavigationItemCollapsable, DrawerNavigationItemLink, DrawerNavigationSection, DrawerProps, DrawerProvider, DrawerProviderProps, DrawerSection, DrawerSectionProps, DrawerSize, DrawerState, DrawerSubheader, DrawerSubheaderProps, DrawerVariant, EditInputType, EditableValueProps, EnhancedRemoteTable, EnhancedRemoteTableProps, EnhancedTable, EnhancedTableHead, ExpandableAlert, ExpandableAlertProps, FieldType, FormDialog, FormDialogProps, GroupField, GroupInstanceType, GroupValueCard, GroupValueCardProps, HeadCell, Header, HeaderAction, HeaderActionVariant, HeaderBreadcrumb, HeaderComponent, HeaderElement, HeaderLayout, HeaderLayoutError, HeaderLayoutProps, HeaderNavigationButton, HeaderPreset, HeaderProps, HeaderTab, IdleRequest, Label, LabelProps, LabelVariant, LoadingArea, LoadingRequest, LoremIpsumPlaceholder, LoremIpsumPlaceholderProps, Markdown, MarkdownProps, Model, ModelField, ModelFieldTypes, ModelForm, ModelFormProps, ModelRouter, ModelRouterProps, Notification, NotificationCenterContext, NotificationCenterProps, NotificationCenterProvider, NotificationCenterProviderProps, NotificationCenterProviderUndefinedError, NotifyWhenValueChangesOptions, ObjectDetails, ObjectDetailsProps, Order, Placeholder, PlaceholderAction, PlaceholderIcon, PlaceholderIconArgs, PlaceholderProps, QueryContainer, QueryContainerError, QueryContainerProps, QueryContainerSuccess, RequestState, Select, SelectProps, SelectSize, SignIn, SignInProps, SingleFieldType, SkeletonCard, SkeletonCardProps, SkeletonGrid, SkeletonGridProps, SuccessRequest, TabCard, TabCardProps, TabContext, TabContextProvider, TabPanel, TabProvider, TableList, TableListProps, TableRowOption, TextField, TextFieldProps, UndefinedProvider, ValueBoolean, ValueBooleanProps, ValueCard, ValueCardProps, ValueDatetime, ValueDatetimeProps, ValueEditButton, ValueEditButtonProps, ValueEditButtons, ValueEditButtonsProps, ValueItem, ValueItemComponent, ValueItemElement, ValueItemProps, ValueRating, ValueRatingProps, ValueText, ValueTextProps, bulletClasses, getDrawerItemColors, getFormData, getRandomItem, labelClasses, markdownDefaultOptions, newArrayWithSize, newBreakpointsCounter, newInstanceFromValuesOrZeroValue, useDialog, useDrawer, useEditableValueDisplay, useGetDefaultThemeColor, useNotificationCenter, useNotifyWhenValueChanges, useTab, valueItemClasses };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pautena/react-design-system",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "My custom design system on top of MUI",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -69,6 +69,7 @@
69
69
  "@storybook/testing-react": "^2.0.0",
70
70
  "@testing-library/jest-dom": "^5.16.5",
71
71
  "@testing-library/react": "^14.0.0",
72
+ "@testing-library/user-event": "^14.4.3",
72
73
  "@types/ramda": "^0.28.23",
73
74
  "@types/react": "^18.0.31",
74
75
  "@typescript-eslint/eslint-plugin": "^5.57.0",
@@ -2,7 +2,7 @@ import { Meta, StoryObj } from "@storybook/react";
2
2
  import React, { useState } from "react";
3
3
  import { ExpandableAlert } from "./expandable-alert";
4
4
  import { withContainer } from "~/storybook";
5
- import { Box, Button, Snackbar } from "@mui/material";
5
+ import { Box, Button, Snackbar, Typography } from "@mui/material";
6
6
 
7
7
  export default {
8
8
  title: "Components/Alerts/ExpandableAlert",
@@ -52,6 +52,28 @@ export const WihtoutMetadata: Story = {
52
52
  },
53
53
  };
54
54
 
55
+ export const MetadataCustomComponent = () => (
56
+ <ExpandableAlert
57
+ severity="info"
58
+ onClose={() => null}
59
+ title="Lorem ipsum"
60
+ message="Lorem ipsum dolor sit amet"
61
+ metadata={["lorem: ipsum", "foo: bar", "header: this", "host: localhost"]}
62
+ metadataComponent={
63
+ <>
64
+ <Typography variant="h6">lorem: ipsum</Typography>
65
+ <Typography variant="caption">foo: bar</Typography>
66
+ <Typography variant="body2" sx={{ textDecoration: "line-through" }}>
67
+ header: this
68
+ </Typography>
69
+ <Typography variant="body2" fontWeight={700}>
70
+ host: localhost
71
+ </Typography>
72
+ </>
73
+ }
74
+ />
75
+ );
76
+
55
77
  export const SnackbarAlert = () => {
56
78
  const [open, setOpen] = useState(false);
57
79
 
@@ -6,11 +6,13 @@ import {
6
6
  Box,
7
7
  Collapse,
8
8
  IconButton,
9
+ SxProps,
10
+ Theme,
9
11
  } from "@mui/material";
10
12
  import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
11
13
  import ExpandLessIcon from "@mui/icons-material/ExpandLess";
12
14
  import CloseIcon from "@mui/icons-material/Close";
13
- import { forwardRef, useState } from "react";
15
+ import { forwardRef, ReactElement, useState } from "react";
14
16
  import React from "react";
15
17
  import { Board } from "~/components/data-display";
16
18
 
@@ -20,7 +22,9 @@ export interface ExpandableAlertProps {
20
22
  title?: string;
21
23
  message: string;
22
24
  metadata?: string | string[];
25
+ metadataComponent?: ReactElement;
23
26
  onClose: () => void;
27
+ sx?: SxProps<Theme>;
24
28
  }
25
29
 
26
30
  const alertSx = {
@@ -30,7 +34,10 @@ const alertSx = {
30
34
  };
31
35
 
32
36
  export const ExpandableAlert = forwardRef<any, ExpandableAlertProps>(
33
- ({ severity, iconMapping, title, message, metadata, onClose }, ref) => {
37
+ (
38
+ { severity, iconMapping, title, message, metadata, metadataComponent, onClose, sx = {} },
39
+ ref,
40
+ ) => {
34
41
  const [expanded, setExpanded] = useState(false);
35
42
  return (
36
43
  <Alert
@@ -54,14 +61,14 @@ export const ExpandableAlert = forwardRef<any, ExpandableAlertProps>(
54
61
  )}
55
62
  </Box>
56
63
  }
57
- sx={alertSx}
64
+ sx={{ ...alertSx, ...sx }}
58
65
  >
59
66
  <Box sx={{ w: 1 }}>
60
67
  {title && <AlertTitle>{title}</AlertTitle>}
61
68
  {message}
62
69
  {metadata && (
63
70
  <Collapse in={expanded} sx={{ mt: 2 }}>
64
- <Board content={metadata} />
71
+ <Board content={metadata}>{metadataComponent}</Board>
65
72
  </Collapse>
66
73
  )}
67
74
  </Box>
@@ -1,9 +1,10 @@
1
1
  import React from "react";
2
- import { render, screen, waitFor } from "~/tests/testing-library";
2
+ import { render, screen } from "~/tests/testing-library";
3
3
  import { Board } from "./board";
4
4
  import { mockMarkdownContent } from "~/tests/mocks/markdown.mock";
5
5
  import userEvent from "@testing-library/user-event";
6
6
  import { vi } from "vitest";
7
+ import { Typography } from "@mui/material";
7
8
 
8
9
  const content = "This is the content";
9
10
 
@@ -12,6 +13,16 @@ const content2 = "This is the content 2";
12
13
  const content3 = "This is the content 3";
13
14
  const arrayContent = [content1, content2, content3];
14
15
 
16
+ const mockCopy = () => {
17
+ const copy = vi.fn();
18
+ Object.assign(navigator, {
19
+ clipboard: {
20
+ writeText: copy,
21
+ },
22
+ });
23
+ return { copy };
24
+ };
25
+
15
26
  describe("Board", () => {
16
27
  const renderComponent = ({
17
28
  markdown,
@@ -20,13 +31,8 @@ describe("Board", () => {
20
31
  markdown?: string;
21
32
  content?: string | string[];
22
33
  }) => {
23
- const copy = vi.fn();
24
- Object.assign(navigator, {
25
- clipboard: {
26
- writeText: copy,
27
- },
28
- });
29
- render(<Board markdown={markdown} content={content} timeoutCopyText={100} />);
34
+ const { copy } = mockCopy();
35
+ render(<Board markdown={markdown} content={content} />);
30
36
 
31
37
  return { copy };
32
38
  };
@@ -53,49 +59,60 @@ describe("Board", () => {
53
59
  ).toBeVisible();
54
60
  });
55
61
 
56
- it("should copy the string content to the clipboard if the copy button is clicked", async () => {
57
- const { copy } = renderComponent({ content });
58
-
59
- await userEvent.click(screen.getByRole("button"));
60
-
61
- expect(copy).toHaveBeenCalledTimes(1);
62
- expect(copy).toHaveBeenCalledWith(content);
63
- });
64
-
65
- it("should copy the string array content to the clipboard if the copy button is clicked", async () => {
66
- const expectedCopy = arrayContent.join("\n");
67
- const { copy } = renderComponent({ content: arrayContent });
68
-
69
- await userEvent.click(screen.getByRole("button"));
70
-
71
- expect(copy).toHaveBeenCalledTimes(1);
72
- expect(copy).toHaveBeenCalledWith(expectedCopy);
73
- });
62
+ describe("copy", () => {
63
+ it("should copy the string content to the clipboard if the copy button is clicked", async () => {
64
+ const { copy } = renderComponent({ content });
74
65
 
75
- it.skip("should copy the markdown content to the clipboard if the copy button is clicked", async () => {
76
- const { copy } = renderComponent({ markdown: mockMarkdownContent });
66
+ await userEvent.click(screen.getByRole("button"));
77
67
 
78
- await userEvent.click(screen.getByRole("button"));
68
+ expect(copy).toHaveBeenCalledTimes(1);
69
+ expect(copy).toHaveBeenCalledWith(content);
70
+ });
79
71
 
80
- expect(copy).toHaveBeenCalledTimes(1);
81
- expect(copy).toHaveBeenCalledWith(mockMarkdownContent);
82
- });
72
+ it("should copy the string array content to the clipboard if the copy button is clicked", async () => {
73
+ const expectedCopy = arrayContent.join("\n");
74
+ const { copy } = renderComponent({ content: arrayContent });
83
75
 
84
- it("should change the copy button text when is clicked", async () => {
85
- renderComponent({ content });
76
+ await userEvent.click(screen.getByRole("button"));
86
77
 
87
- await userEvent.click(screen.getByRole("button"));
88
-
89
- expect(screen.getByRole("button", { name: /copied/i })).toBeVisible();
90
- });
78
+ expect(copy).toHaveBeenCalledTimes(1);
79
+ expect(copy).toHaveBeenCalledWith(expectedCopy);
80
+ });
91
81
 
92
- it("should return to the original button text after a delay", async () => {
93
- renderComponent({ content });
82
+ it.skip("should copy the markdown content to the clipboard if the copy button is clicked", async () => {
83
+ const { copy } = renderComponent({ markdown: mockMarkdownContent });
94
84
 
95
- await userEvent.click(screen.getByRole("button"));
85
+ await userEvent.click(screen.getByRole("button"));
96
86
 
97
- expect(screen.getByRole("button", { name: /copied/i })).toBeVisible();
87
+ expect(copy).toHaveBeenCalledTimes(1);
88
+ expect(copy).toHaveBeenCalledWith(mockMarkdownContent);
89
+ });
98
90
 
99
- await waitFor(() => expect(screen.getByRole("button", { name: /copy/i })).toBeVisible());
91
+ it("should render the children and copy the string content if it has a custom children", async () => {
92
+ const content = "lorem: ipsum";
93
+ const { copy } = mockCopy();
94
+ render(
95
+ <Board content={content}>
96
+ <Typography variant="h6">row 1</Typography>
97
+ <Typography variant="caption"> row 2</Typography>
98
+ <Typography variant="body2" sx={{ textDecoration: "line-through" }}>
99
+ row 3
100
+ </Typography>
101
+ <Typography variant="body2" fontWeight={700}>
102
+ row 4
103
+ </Typography>
104
+ </Board>,
105
+ );
106
+
107
+ expect(screen.getByText(/row 1/i)).toBeVisible();
108
+ expect(screen.getByText(/row 2/i)).toBeVisible();
109
+ expect(screen.getByText(/row 3/i)).toBeVisible();
110
+ expect(screen.getByText(/row 4/i)).toBeVisible();
111
+
112
+ await userEvent.click(screen.getByRole("button"));
113
+
114
+ expect(copy).toHaveBeenCalledTimes(1);
115
+ expect(copy).toHaveBeenCalledWith(content);
116
+ });
100
117
  });
101
118
  });
@@ -1,13 +1,13 @@
1
- import { Box, Button, Paper, SxProps, Theme, Typography } from "@mui/material";
1
+ import { Box, IconButton, Paper, SxProps, Theme, Tooltip, Typography } from "@mui/material";
2
2
  import { blueGrey } from "@mui/material/colors";
3
- import React, { PropsWithChildren, ReactNode, useState } from "react";
3
+ import React, { PropsWithChildren, ReactNode } from "react";
4
4
  import { Markdown } from "../markdown";
5
+ import ContentCopyIcon from "@mui/icons-material/ContentCopy";
5
6
 
6
7
  export type BoardProps = PropsWithChildren<{
7
8
  markdown?: string;
8
9
  content?: string | string[];
9
10
  spacing?: 0 | 1 | 2 | 3 | 4 | 5;
10
- timeoutCopyText?: number;
11
11
  sx?: SxProps<Theme>;
12
12
  }>;
13
13
 
@@ -15,11 +15,9 @@ export const Board = ({
15
15
  markdown: markdownProps,
16
16
  content: contentProp,
17
17
  spacing = 0,
18
- timeoutCopyText = 2000,
19
18
  children,
20
19
  sx,
21
20
  }: BoardProps) => {
22
- const [copyText, setCopyText] = useState("Copy");
23
21
  let copyContent: string;
24
22
  let content: ReactNode;
25
23
 
@@ -39,22 +37,21 @@ export const Board = ({
39
37
 
40
38
  const markdown = markdownProps && <Markdown content={markdownProps} />;
41
39
 
42
- const handleCopy = () => {
43
- navigator.clipboard.writeText(copyContent);
44
- setCopyText("Copied!");
45
-
46
- setTimeout(() => setCopyText("Copy"), timeoutCopyText);
47
- };
48
-
49
40
  return (
50
41
  <Paper sx={{ p: 2, backgroundColor: blueGrey[800], color: "white", ...sx }}>
51
42
  <Box display="flex" flexDirection="row">
52
43
  <Box width={1}>{children || markdown || content}</Box>
53
- <Box width={100} sx={{ ml: 1 }}>
44
+ <Box sx={{ ml: 1 }}>
54
45
  {copyContent && (
55
- <Button fullWidth color="inherit" size="small" variant="outlined" onClick={handleCopy}>
56
- {copyText}
57
- </Button>
46
+ <IconButton
47
+ aria-label="copy board content"
48
+ color="inherit"
49
+ onClick={() => navigator.clipboard.writeText(copyContent)}
50
+ >
51
+ <Tooltip title="Copy">
52
+ <ContentCopyIcon />
53
+ </Tooltip>
54
+ </IconButton>
58
55
  )}
59
56
  </Box>
60
57
  </Box>
@@ -25,13 +25,26 @@ type Story = StoryObj<typeof QueryContainer>;
25
25
 
26
26
  export const Fetching: Story = {
27
27
  args: {
28
- isFetching: true,
28
+ fetching: true,
29
+ },
30
+ };
31
+
32
+ export const Loading: Story = {
33
+ args: {
34
+ loading: true,
35
+ },
36
+ };
37
+
38
+ export const FetchingAndLoading: Story = {
39
+ args: {
40
+ loading: true,
41
+ fetching: true,
29
42
  },
30
43
  };
31
44
 
32
45
  export const Error: Story = {
33
46
  args: {
34
- isFetching: false,
47
+ fetching: false,
35
48
  error: {
36
49
  name: "Sign in error",
37
50
  message: "User and password doesn't match",
@@ -41,7 +54,7 @@ export const Error: Story = {
41
54
 
42
55
  export const ErrorWithOnlyMessage: Story = {
43
56
  args: {
44
- isFetching: false,
57
+ fetching: false,
45
58
  error: {
46
59
  message: "Internal error",
47
60
  },
@@ -50,7 +63,7 @@ export const ErrorWithOnlyMessage: Story = {
50
63
 
51
64
  export const Success: Story = {
52
65
  args: {
53
- isFetching: false,
66
+ fetching: false,
54
67
  success: {
55
68
  name: "Item added",
56
69
  message: "The new item has been created with id 1",
@@ -60,7 +73,7 @@ export const Success: Story = {
60
73
 
61
74
  export const SuccessWithOnlyMessage: Story = {
62
75
  args: {
63
- isFetching: false,
76
+ fetching: false,
64
77
  success: {
65
78
  message: "The new item has been created with id 1",
66
79
  },
@@ -69,6 +82,6 @@ export const SuccessWithOnlyMessage: Story = {
69
82
 
70
83
  export const Content: Story = {
71
84
  args: {
72
- isFetching: false,
85
+ fetching: false,
73
86
  },
74
87
  };