@pautena/react-design-system 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) 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 +24 -17
  25. package/src/components/feedback/query-container/query-container.stories.tsx +19 -6
  26. package/src/components/feedback/query-container/query-container.test.tsx +65 -17
  27. package/src/components/feedback/query-container/query-container.tsx +20 -5
  28. package/src/components/inputs/autocomplete/autocomplete.stories.tsx +8 -0
  29. package/src/components/inputs/index.ts +1 -0
  30. package/src/components/inputs/text-field/text-field.stories.tsx +8 -0
  31. package/src/components/inputs/text-field/text-field.tsx +2 -2
  32. package/src/components/value-displays/group-value-card/group-value-card.mock.tsx +28 -8
  33. package/src/components/value-displays/group-value-card/group-value-card.stories.tsx +19 -2
  34. package/src/components/value-displays/group-value-card/group-value-card.test.tsx +16 -18
  35. package/src/components/value-displays/value-base/value-edit.test.tsx +88 -0
  36. package/src/components/value-displays/value-base/value-edit.tsx +28 -6
  37. package/src/components/value-displays/value-boolean/value-boolean.stories.tsx +9 -0
  38. package/src/components/value-displays/value-boolean/value-boolean.test.tsx +29 -15
  39. package/src/components/value-displays/value-boolean/value-boolean.tsx +18 -11
  40. package/src/components/value-displays/value-content/value-content.test.tsx +20 -6
  41. package/src/components/value-displays/value-content/value-content.tsx +24 -10
  42. package/src/components/value-displays/value-datetime/value-datetime.stories.tsx +11 -0
  43. package/src/components/value-displays/value-datetime/value-datetime.test.tsx +9 -9
  44. package/src/components/value-displays/value-datetime/value-datetime.tsx +14 -10
  45. package/src/components/value-displays/value-rating/value-rating.stories.tsx +10 -0
  46. package/src/components/value-displays/value-rating/value-rating.test.tsx +11 -11
  47. package/src/components/value-displays/value-rating/value-rating.tsx +10 -8
  48. package/src/components/value-displays/value-text/value-text.stories.tsx +9 -0
  49. package/src/components/value-displays/value-text/value-text.test.tsx +20 -9
  50. package/src/components/value-displays/value-text/value-text.tsx +23 -10
  51. package/src/generators/model-form/model-form.test.tsx +1 -1
  52. package/src/generators/model-router/model-router.test.tsx +3 -3
  53. package/src/layouts/header-layout/header-layout.stories.tsx +2 -2
  54. package/src/layouts/header-layout/header-layout.tsx +1 -7
@@ -30,50 +30,64 @@ describe("ValueBoolean", () => {
30
30
  it("would render the label", () => {
31
31
  renderComponent({ value: true });
32
32
 
33
- expect(screen.getByRole("label", { name: /hello world/i })).toBeInTheDocument();
33
+ expect(screen.getByRole("label", { name: /hello world/i })).toBeVisible();
34
34
  });
35
35
 
36
36
  it("would render a check if value is true", () => {
37
37
  renderComponent({ value: true });
38
38
 
39
- expect(screen.getByTestId("CheckIcon")).toBeInTheDocument();
39
+ expect(screen.getByTestId("CheckIcon")).toBeVisible();
40
40
  });
41
41
 
42
42
  it("would render a cross if value is false", () => {
43
43
  renderComponent({ value: false });
44
44
 
45
- expect(screen.getByTestId("CloseIcon")).toBeInTheDocument();
45
+ expect(screen.getByTestId("CloseIcon")).toBeVisible();
46
+ });
47
+
48
+ describe("accessibility", () => {
49
+ it("should be checked if value is true", () => {
50
+ renderComponent({ value: true });
51
+
52
+ expect(screen.getByLabelText(/hello world/i)).toBeChecked();
53
+ });
54
+
55
+ it("shouldn't be checked if value is false", () => {
56
+ renderComponent({ value: false });
57
+
58
+ expect(screen.getByLabelText(/hello world/i)).not.toBeChecked();
59
+ });
46
60
  });
47
61
 
48
62
  it("should render the placeholder if value is undefined", () => {
49
63
  renderComponent({ value: undefined });
50
64
 
51
- expect(screen.getByText(/-/i)).toBeInTheDocument();
65
+ expect(screen.getByText(/-/i)).toBeVisible();
52
66
  });
53
67
 
54
68
  it("should render the custom placeholder if value is undefined and placeholder has value", () => {
55
69
  renderComponent({ value: undefined, placeholder: "_" });
56
70
 
57
- expect(screen.getByText(/_/i)).toBeInTheDocument();
71
+ expect(screen.getByText(/_/i)).toBeVisible();
58
72
  });
59
73
 
60
74
  describe("editable", () => {
61
75
  it("shouldn't render an option to edit if editable is false", () => {
62
76
  renderComponent({ value: true, editable: false });
63
77
 
64
- expect(screen.queryByTestId("EditIcon")).not.toBeInTheDocument();
78
+ expect(screen.queryByRole("button", { name: /edit/i })).not.toBeInTheDocument();
65
79
  });
66
80
 
67
81
  it("should render an option to edit if editable is true", () => {
68
82
  renderComponent({ value: true, editable: true });
69
83
 
70
- expect(screen.getByTestId("EditIcon")).toBeVisible();
84
+ expect(screen.getByRole("button", { name: /edit/i })).toBeVisible();
71
85
  });
72
86
 
73
87
  it("should render an input with the value if the edit button is clicked", async () => {
74
88
  renderComponent({ value: true, editable: true });
75
89
 
76
- await userEvent.click(screen.getByTestId("EditIcon"));
90
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
77
91
 
78
92
  expect(screen.getByRole("checkbox")).toBeChecked();
79
93
  });
@@ -86,9 +100,9 @@ describe("ValueBoolean", () => {
86
100
  async (expectedValue: boolean, initialValue: boolean) => {
87
101
  const { onEdit } = renderComponent({ value: initialValue, editable: true });
88
102
 
89
- await userEvent.click(screen.getByTestId("EditIcon"));
103
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
90
104
  await userEvent.click(screen.getByRole("checkbox"));
91
- await userEvent.click(screen.getByTestId("CheckIcon"));
105
+ await userEvent.click(screen.getByRole("button", { name: /submit/i }));
92
106
 
93
107
  expect(onEdit).toHaveBeenCalledTimes(1);
94
108
  expect(onEdit).toHaveBeenCalledWith(expectedValue);
@@ -98,9 +112,9 @@ describe("ValueBoolean", () => {
98
112
  it("should not call onEdit if the edition is cancelled", async () => {
99
113
  const { onEdit } = renderComponent({ value: true, editable: true });
100
114
 
101
- await userEvent.click(screen.getByTestId("EditIcon"));
115
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
102
116
  await userEvent.click(screen.getByRole("checkbox"));
103
- await userEvent.click(screen.getByTestId("ClearIcon"));
117
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
104
118
 
105
119
  expect(onEdit).not.toHaveBeenCalled();
106
120
  });
@@ -108,10 +122,10 @@ describe("ValueBoolean", () => {
108
122
  it("should have the original value if is edited again after clear a change", async () => {
109
123
  renderComponent({ value: true, editable: true });
110
124
 
111
- await userEvent.click(screen.getByTestId("EditIcon"));
125
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
112
126
  await userEvent.click(screen.getByRole("checkbox"));
113
- await userEvent.click(screen.getByTestId("ClearIcon"));
114
- await userEvent.click(screen.getByTestId("EditIcon"));
127
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
128
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
115
129
 
116
130
  expect(screen.getByRole("checkbox")).toBeChecked();
117
131
  });
@@ -1,4 +1,4 @@
1
- import { Box, IconButton, Switch, Typography, useTheme } from "@mui/material";
1
+ import { Box, Switch, Typography, useTheme } from "@mui/material";
2
2
  import React from "react";
3
3
  import CheckIcon from "@mui/icons-material/Check";
4
4
  import CloseIcon from "@mui/icons-material/Close";
@@ -7,10 +7,10 @@ import {
7
7
  DefaultPlaceholder,
8
8
  EditableValueProps,
9
9
  useEditableValueDisplay,
10
+ ValueEditButton,
10
11
  ValueEditButtons,
11
12
  } from "../value-base";
12
- import { ValueContent } from "../value-content";
13
- import EditIcon from "@mui/icons-material/Edit";
13
+ import { ValueContent, getValueContentLabelId } from "../value-content";
14
14
 
15
15
  export type ValueBooleanProps = BaseValueProps<boolean> & EditableValueProps<boolean>;
16
16
 
@@ -25,6 +25,7 @@ export const ValueBoolean = ({
25
25
  dense,
26
26
  onEdit = () => null,
27
27
  }: ValueBooleanProps) => {
28
+ const id = getValueContentLabelId(label);
28
29
  const { typography } = useTheme();
29
30
  const { isEditing, editValue, startEdit, cancelEdit, setEditValue, submitEdit } =
30
31
  useEditableValueDisplay(value, onEdit);
@@ -35,11 +36,21 @@ export const ValueBoolean = ({
35
36
  <ValueContent label={label} dense={dense}>
36
37
  {isEditing ? (
37
38
  <Box display="flex" alignItems="center">
38
- <Switch checked={editValue} onChange={(e) => setEditValue(e.target.checked)} />
39
- <ValueEditButtons onClickCancel={cancelEdit} onSubmitEdit={submitEdit} />
39
+ <Switch
40
+ size={dense ? "small" : "medium"}
41
+ checked={editValue}
42
+ onChange={(e) => setEditValue(e.target.checked)}
43
+ />
44
+ <ValueEditButtons onClickCancel={cancelEdit} onClickSubmit={submitEdit} />
40
45
  </Box>
41
46
  ) : (
42
- <Box display="flex" alignItems="center">
47
+ <Box
48
+ display="flex"
49
+ alignItems="center"
50
+ aria-labelledby={id}
51
+ role="checkbox"
52
+ aria-checked={value}
53
+ >
43
54
  {value === undefined ? (
44
55
  <Typography variant="h5">{placeholder}</Typography>
45
56
  ) : value ? (
@@ -47,11 +58,7 @@ export const ValueBoolean = ({
47
58
  ) : (
48
59
  <CloseIcon color="error" sx={iconSx} />
49
60
  )}
50
- {editable && (
51
- <IconButton size="small" onClick={startEdit} sx={{ ml: 1 }}>
52
- <EditIcon />
53
- </IconButton>
54
- )}
61
+ {editable && <ValueEditButton dense={dense} onClick={startEdit} />}
55
62
  </Box>
56
63
  )}
57
64
  </ValueContent>
@@ -5,9 +5,17 @@ import { ValueContent } from "./value-content";
5
5
  import userEvent from "@testing-library/user-event";
6
6
 
7
7
  describe("ValueContent", () => {
8
- const renderComponent = ({ tooltip }: { tooltip?: string } = {}) => {
8
+ const renderComponent = ({
9
+ tooltip,
10
+ hideLabel,
11
+ }: { tooltip?: string; hideLabel?: boolean } = {}) => {
9
12
  render(
10
- <ValueContent label="lorem ipsum" tooltip={tooltip} tooltipEnterDelay={0}>
13
+ <ValueContent
14
+ label="lorem ipsum"
15
+ tooltip={tooltip}
16
+ tooltipEnterDelay={0}
17
+ hideLabel={hideLabel}
18
+ >
11
19
  <Typography>Test content</Typography>
12
20
  </ValueContent>,
13
21
  );
@@ -16,7 +24,13 @@ describe("ValueContent", () => {
16
24
  it("should render a label", () => {
17
25
  renderComponent();
18
26
 
19
- expect(screen.getByRole("label", { name: /lorem ipsum/i })).toBeInTheDocument();
27
+ expect(screen.getByRole("label", { name: /lorem ipsum/i })).toBeVisible();
28
+ });
29
+
30
+ it("shouldn't render a label if hideLabel=true", () => {
31
+ renderComponent({ hideLabel: true });
32
+
33
+ expect(screen.queryByRole("label", { name: /lorem ipsum/i })).not.toBeInTheDocument();
20
34
  });
21
35
 
22
36
  describe("tooltip", () => {
@@ -25,7 +39,7 @@ describe("ValueContent", () => {
25
39
 
26
40
  await userEvent.hover(screen.getByText(/test content/i));
27
41
 
28
- expect(await screen.findByRole("tooltip", { name: /dolor sit amet/i })).toBeInTheDocument();
42
+ expect(await screen.findByRole("tooltip", { name: /dolor sit amet/i })).toBeVisible();
29
43
  });
30
44
 
31
45
  it("shouldn't render a tooltip if it's not defined", () => {
@@ -39,12 +53,12 @@ describe("ValueContent", () => {
39
53
  it("should render the children if tooltip is defined", () => {
40
54
  renderComponent({ tooltip: "dolor sit amet" });
41
55
 
42
- expect(screen.getByText(/test content/i)).toBeInTheDocument();
56
+ expect(screen.getByText(/test content/i)).toBeVisible();
43
57
  });
44
58
  it("should render the children if tooltip is undefined", () => {
45
59
  renderComponent({ tooltip: undefined });
46
60
 
47
- expect(screen.getByText(/test content/i)).toBeInTheDocument();
61
+ expect(screen.getByText(/test content/i)).toBeVisible();
48
62
  });
49
63
  });
50
64
  });
@@ -1,4 +1,4 @@
1
- import { Box, Tooltip, Typography, useTheme } from "@mui/material";
1
+ import { Box, SxProps, Theme, Tooltip, Typography, useTheme } from "@mui/material";
2
2
  import React from "react";
3
3
 
4
4
  export const getValueContentLabelId = (label: string): string =>
@@ -10,6 +10,11 @@ export interface ValueContentProps {
10
10
  */
11
11
  label: string;
12
12
 
13
+ /**
14
+ * If true, the label will not be shown
15
+ */
16
+ hideLabel?: boolean;
17
+
13
18
  /**
14
19
  * If defined, a tooltip is going to be added arround the children;
15
20
  */
@@ -30,6 +35,11 @@ export interface ValueContentProps {
30
35
  * False by default
31
36
  */
32
37
  dense?: boolean;
38
+
39
+ /**
40
+ * Custom styles for the root component
41
+ */
42
+ sx?: SxProps<Theme>;
33
43
  }
34
44
 
35
45
  /**
@@ -37,24 +47,28 @@ export interface ValueContentProps {
37
47
  */
38
48
  export const ValueContent = ({
39
49
  label,
50
+ hideLabel,
40
51
  tooltip,
41
52
  tooltipEnterDelay = 2000,
42
53
  children,
43
54
  dense,
55
+ sx,
44
56
  }: ValueContentProps) => {
45
57
  const { typography } = useTheme();
46
58
  const id = getValueContentLabelId(label);
47
59
 
48
60
  return (
49
- <Box width={1} lineHeight={dense ? 0 : undefined}>
50
- <Typography
51
- variant={dense ? "caption" : "subtitle2"}
52
- role="label"
53
- id={id}
54
- lineHeight={dense ? typography.pxToRem(15) : undefined}
55
- >
56
- {label}
57
- </Typography>
61
+ <Box width={1} lineHeight={dense ? 0 : undefined} sx={sx}>
62
+ {!hideLabel && (
63
+ <Typography
64
+ variant={dense ? "caption" : "subtitle2"}
65
+ role="label"
66
+ id={id}
67
+ lineHeight={dense ? typography.pxToRem(15) : undefined}
68
+ >
69
+ {label}
70
+ </Typography>
71
+ )}
58
72
  {tooltip ? (
59
73
  <Tooltip title={tooltip} placement="top" enterDelay={tooltipEnterDelay}>
60
74
  {children}
@@ -73,3 +73,14 @@ export const EditableDate: Story = {
73
73
  editInputType: "date",
74
74
  },
75
75
  };
76
+
77
+ export const DenseEditable: Story = {
78
+ args: {
79
+ label: "Lorem",
80
+ value: new Date(2022, 8, 22),
81
+ format: "yyyy/MM/dd",
82
+ editable: true,
83
+ editInputType: "date",
84
+ dense: true,
85
+ },
86
+ };
@@ -77,13 +77,13 @@ describe("ValueDatetime", () => {
77
77
  it("should render an option to edit if editable is true", () => {
78
78
  renderComponent({ value: DummyValue, editable: true });
79
79
 
80
- expect(screen.getByTestId("EditIcon")).toBeVisible();
80
+ expect(screen.getByRole("button", { name: /edit/i })).toBeVisible();
81
81
  });
82
82
 
83
83
  it("should render an input with the value if the edit button is clicked", async () => {
84
84
  renderComponent({ value: DummyValue, editable: true });
85
85
 
86
- await userEvent.click(screen.getByTestId("EditIcon"));
86
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
87
87
 
88
88
  assertDatetimeInputValue(screen.getByRole("textbox"), {
89
89
  value: DummyValue,
@@ -105,9 +105,9 @@ describe("ValueDatetime", () => {
105
105
  fmt,
106
106
  });
107
107
 
108
- await userEvent.click(screen.getByTestId("EditIcon"));
108
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
109
109
  pickDatetime(screen.getByRole("textbox"), newValue, fmt);
110
- await userEvent.click(screen.getByTestId("CheckIcon"));
110
+ await userEvent.click(screen.getByRole("button", { name: /submit/i }));
111
111
 
112
112
  expect(onEdit).toHaveBeenCalledTimes(1);
113
113
  expect(onEdit).toHaveBeenCalledWith(expectedDate);
@@ -117,9 +117,9 @@ describe("ValueDatetime", () => {
117
117
  it("should not call onEdit if the edition is cancelled", async () => {
118
118
  const { onEdit } = renderComponent({ value: DummyValue, editable: true });
119
119
 
120
- await userEvent.click(screen.getByTestId("EditIcon"));
120
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
121
121
  pickDatetime(screen.getByRole("textbox"), NewValue, datetimeFormat);
122
- await userEvent.click(screen.getByTestId("ClearIcon"));
122
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
123
123
 
124
124
  expect(onEdit).not.toHaveBeenCalled();
125
125
  });
@@ -127,10 +127,10 @@ describe("ValueDatetime", () => {
127
127
  it("should have the original value if is edited again after clear a change", async () => {
128
128
  renderComponent({ value: DummyValue, editable: true });
129
129
 
130
- await userEvent.click(screen.getByTestId("EditIcon"));
130
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
131
131
  pickDatetime(screen.getByRole("textbox"), NewValue, datetimeFormat);
132
- await userEvent.click(screen.getByTestId("ClearIcon"));
133
- await userEvent.click(screen.getByTestId("EditIcon"));
132
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
133
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
134
134
 
135
135
  assertDatetimeInputValue(screen.getByRole("textbox"), {
136
136
  value: DummyValue,
@@ -1,4 +1,4 @@
1
- import { Box, IconButton, TextField, Typography } from "@mui/material";
1
+ import { Box, TextField, Typography } from "@mui/material";
2
2
  import React from "react";
3
3
  import { format } from "date-fns";
4
4
  import {
@@ -7,8 +7,7 @@ import {
7
7
  EditableValueProps,
8
8
  } from "../value-base/value-displays.types";
9
9
  import { getValueContentLabelId, ValueContent } from "../value-content";
10
- import { useEditableValueDisplay, ValueEditButtons } from "../value-base";
11
- import EditIcon from "@mui/icons-material/Edit";
10
+ import { useEditableValueDisplay, ValueEditButton, ValueEditButtons } from "../value-base";
12
11
  import { DatePicker, DateTimePicker, TimePicker } from "@mui/x-date-pickers";
13
12
 
14
13
  export type EditInputType = "datetime" | "date" | "time";
@@ -51,16 +50,24 @@ export const ValueDatetime = ({
51
50
  : DatePicker;
52
51
 
53
52
  return (
54
- <ValueContent label={label} tooltip={value} dense={dense}>
53
+ <ValueContent
54
+ label={label}
55
+ hideLabel={isEditing}
56
+ tooltip={value}
57
+ dense={dense}
58
+ sx={{ display: "flex", flexDirection: "column" }}
59
+ >
55
60
  {isEditing ? (
56
61
  <EditPickerComponent
57
62
  value={editValue}
58
63
  format={fmt}
64
+ label={label}
59
65
  onChange={(newValue) => setEditValue(newValue ? newValue : undefined)}
60
66
  slots={{
61
67
  textField: (params) => (
62
68
  <TextField
63
69
  {...params}
70
+ size="small"
64
71
  InputProps={{
65
72
  ...params.InputProps,
66
73
  endAdornment: (
@@ -68,11 +75,12 @@ export const ValueDatetime = ({
68
75
  {params.InputProps?.endAdornment}
69
76
  <ValueEditButtons
70
77
  onClickCancel={cancelEdit}
71
- onSubmitEdit={submitEdit}
78
+ onClickSubmit={submitEdit}
72
79
  sx={{ ml: 2 }}
73
80
  />
74
81
  </>
75
82
  ),
83
+ sx: { marginY: !dense ? 1 : 0.2 },
76
84
  }}
77
85
  />
78
86
  ),
@@ -83,11 +91,7 @@ export const ValueDatetime = ({
83
91
  <Typography variant={dense ? "body1" : "h5"} noWrap aria-labelledby={id}>
84
92
  {value}
85
93
  </Typography>
86
- {editable && (
87
- <IconButton size="small" onClick={startEdit} sx={{ ml: 1 }}>
88
- <EditIcon />
89
- </IconButton>
90
- )}
94
+ {editable && <ValueEditButton dense={dense} onClick={startEdit} />}
91
95
  </Box>
92
96
  )}
93
97
  </ValueContent>
@@ -43,3 +43,13 @@ export const Editable: Story = {
43
43
  editable: true,
44
44
  },
45
45
  };
46
+
47
+ export const DenseEditable: Story = {
48
+ args: {
49
+ label: "Lorem",
50
+ value: 4,
51
+ maxRating: 7,
52
+ dense: true,
53
+ editable: true,
54
+ },
55
+ };
@@ -59,13 +59,13 @@ describe("ValueRating", () => {
59
59
  it("should render an option to edit if editable is true", () => {
60
60
  renderComponent({ editable: true });
61
61
 
62
- expect(screen.getByTestId("EditIcon")).toBeVisible();
62
+ expect(screen.getByRole("button", { name: /edit/i })).toBeVisible();
63
63
  });
64
64
 
65
65
  it("should render an input for each star + 1 for the zero value if the edit button is clicked", async () => {
66
66
  renderComponent({ editable: true });
67
67
 
68
- await userEvent.click(screen.getByTestId("EditIcon"));
68
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
69
69
 
70
70
  expect(screen.getAllByRole("radio")).toHaveLength(6);
71
71
  });
@@ -73,9 +73,9 @@ describe("ValueRating", () => {
73
73
  it("should submit the new value if is edited", async () => {
74
74
  const { onEdit } = renderComponent({ value: 2, editable: true });
75
75
 
76
- await userEvent.click(screen.getByTestId("EditIcon"));
77
- await userEvent.click(screen.getAllByRole("radio")[3]); // Click the fourth star
78
- await userEvent.click(screen.getByTestId("CheckIcon"));
76
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
77
+ await userEvent.click(screen.getByRole("radio", { name: /4 stars/i }));
78
+ await userEvent.click(screen.getByRole("button", { name: /submit/i }));
79
79
 
80
80
  expect(onEdit).toHaveBeenCalledTimes(1);
81
81
  expect(onEdit).toHaveBeenCalledWith(4);
@@ -84,9 +84,9 @@ describe("ValueRating", () => {
84
84
  it("should not call onEdit if the edition is cancelled", async () => {
85
85
  const { onEdit } = renderComponent({ editable: true });
86
86
 
87
- await userEvent.click(screen.getByTestId("EditIcon"));
87
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
88
88
  await userEvent.click(screen.getAllByRole("radio")[3]);
89
- await userEvent.click(screen.getByTestId("ClearIcon"));
89
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
90
90
 
91
91
  expect(onEdit).not.toHaveBeenCalled();
92
92
  });
@@ -94,10 +94,10 @@ describe("ValueRating", () => {
94
94
  it("should have the original value if is edited again after clear a change", async () => {
95
95
  renderComponent({ editable: true });
96
96
 
97
- await userEvent.click(screen.getByTestId("EditIcon"));
98
- await userEvent.click(screen.getAllByRole("radio")[3]);
99
- await userEvent.click(screen.getByTestId("ClearIcon"));
100
- await userEvent.click(screen.getByTestId("EditIcon"));
97
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
98
+ await userEvent.click(screen.getByLabelText(/3 stars/i));
99
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
100
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
101
101
 
102
102
  expect(screen.getAllByTestId("StarIcon")).toHaveLength(3);
103
103
  });
@@ -1,6 +1,6 @@
1
1
  import { Box, IconButton, Rating } from "@mui/material";
2
2
  import React from "react";
3
- import { useEditableValueDisplay, ValueEditButtons } from "../value-base";
3
+ import { useEditableValueDisplay, ValueEditButton, ValueEditButtons } from "../value-base";
4
4
  import { BaseValueProps, EditableValueProps } from "../value-base/value-displays.types";
5
5
  import { getValueContentLabelId, ValueContent } from "../value-content";
6
6
  import EditIcon from "@mui/icons-material/Edit";
@@ -33,14 +33,16 @@ export const ValueRating = ({
33
33
  max={maxRating}
34
34
  size={dense ? "small" : "medium"}
35
35
  value={isEditing ? editValue : value}
36
- onChange={(_, newValue) => newValue && setEditValue(newValue)}
36
+ onChange={(e, newValue) => {
37
+ if (Number.isNaN(newValue) && (e.currentTarget as any).value) {
38
+ setEditValue(parseInt((e.currentTarget as any).value, 10));
39
+ } else if (newValue) {
40
+ setEditValue(newValue);
41
+ }
42
+ }}
37
43
  />
38
- {editable && !isEditing && (
39
- <IconButton size="small" onClick={startEdit} sx={{ ml: 1 }}>
40
- <EditIcon />
41
- </IconButton>
42
- )}
43
- {isEditing && <ValueEditButtons onClickCancel={cancelEdit} onSubmitEdit={submitEdit} />}
44
+ {editable && !isEditing && <ValueEditButton dense={dense} onClick={startEdit} />}
45
+ {isEditing && <ValueEditButtons onClickCancel={cancelEdit} onClickSubmit={submitEdit} />}
44
46
  </Box>
45
47
  </ValueContent>
46
48
  );
@@ -61,3 +61,12 @@ export const Editable: Story = {
61
61
  editable: true,
62
62
  },
63
63
  };
64
+
65
+ export const DenseEditable: Story = {
66
+ args: {
67
+ label: "Lorem",
68
+ value: "lorem ipsum",
69
+ dense: true,
70
+ editable: true,
71
+ },
72
+ };
@@ -69,13 +69,13 @@ describe("ValueText", () => {
69
69
  it("should render an option to edit if editable is true", () => {
70
70
  renderComponent({ value: DummyValue, editable: true });
71
71
 
72
- expect(screen.getByTestId("EditIcon")).toBeVisible();
72
+ expect(screen.getByRole("button", { name: /edit/i })).toBeVisible();
73
73
  });
74
74
 
75
75
  it("should render an input with the value if the edit button is clicked", async () => {
76
76
  renderComponent({ value: DummyValue, editable: true });
77
77
 
78
- await userEvent.click(screen.getByTestId("EditIcon"));
78
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
79
79
 
80
80
  expect(screen.getByRole("textbox")).toHaveValue(DummyValue);
81
81
  });
@@ -83,10 +83,10 @@ describe("ValueText", () => {
83
83
  it("should submit the new value if is edited", async () => {
84
84
  const { onEdit } = renderComponent({ value: DummyValue, editable: true });
85
85
 
86
- await userEvent.click(screen.getByTestId("EditIcon"));
86
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
87
87
  await userEvent.clear(screen.getByRole("textbox"));
88
88
  await userEvent.type(screen.getByRole("textbox"), "new value");
89
- await userEvent.click(screen.getByTestId("CheckIcon"));
89
+ await userEvent.click(screen.getByRole("button", { name: /submit/i }));
90
90
 
91
91
  expect(onEdit).toHaveBeenCalledTimes(1);
92
92
  expect(onEdit).toHaveBeenCalledWith("new value");
@@ -95,10 +95,10 @@ describe("ValueText", () => {
95
95
  it("should not call onEdit if the edition is cancelled", async () => {
96
96
  const { onEdit } = renderComponent({ value: DummyValue, editable: true });
97
97
 
98
- await userEvent.click(screen.getByTestId("EditIcon"));
98
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
99
99
  await userEvent.clear(screen.getByRole("textbox"));
100
100
  await userEvent.type(screen.getByRole("textbox"), "new value");
101
- await userEvent.click(screen.getByTestId("ClearIcon"));
101
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
102
102
 
103
103
  expect(onEdit).not.toHaveBeenCalled();
104
104
  });
@@ -106,13 +106,24 @@ describe("ValueText", () => {
106
106
  it("should have the original value if is edited again after clear a change", async () => {
107
107
  renderComponent({ value: DummyValue, editable: true });
108
108
 
109
- await userEvent.click(screen.getByTestId("EditIcon"));
109
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
110
110
  await userEvent.clear(screen.getByRole("textbox"));
111
111
  await userEvent.type(screen.getByRole("textbox"), "new value");
112
- await userEvent.click(screen.getByTestId("ClearIcon"));
113
- await userEvent.click(screen.getByTestId("EditIcon"));
112
+ await userEvent.click(screen.getByRole("button", { name: /cancel/i }));
113
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
114
114
 
115
115
  expect(screen.getByRole("textbox")).toHaveValue(DummyValue);
116
116
  });
117
+
118
+ it("should call onEdit if the enter button is pressed", async () => {
119
+ const { onEdit } = renderComponent({ value: DummyValue, editable: true });
120
+
121
+ await userEvent.click(screen.getByRole("button", { name: /edit/i }));
122
+ await userEvent.clear(screen.getByRole("textbox"));
123
+ await userEvent.type(screen.getByRole("textbox"), "new value{enter}");
124
+
125
+ expect(onEdit).toHaveBeenCalledTimes(1);
126
+ expect(onEdit).toHaveBeenCalledWith("new value");
127
+ });
117
128
  });
118
129
  });