@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.
- package/dist/cjs/index.js +4 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/alerts/expandable-alert/expandable-alert.d.ts +4 -1
- package/dist/cjs/types/components/data-display/board/board.d.ts +1 -2
- package/dist/cjs/types/components/feedback/query-container/query-container.d.ts +7 -3
- package/dist/cjs/types/components/inputs/index.d.ts +1 -0
- package/dist/cjs/types/components/value-displays/group-value-card/group-value-card.mock.d.ts +3 -1
- package/dist/cjs/types/components/value-displays/value-base/value-edit.d.ts +7 -2
- package/dist/cjs/types/components/value-displays/value-content/value-content.d.ts +10 -1
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/alerts/expandable-alert/expandable-alert.d.ts +4 -1
- package/dist/esm/types/components/data-display/board/board.d.ts +1 -2
- package/dist/esm/types/components/feedback/query-container/query-container.d.ts +7 -3
- package/dist/esm/types/components/inputs/index.d.ts +1 -0
- package/dist/esm/types/components/value-displays/group-value-card/group-value-card.mock.d.ts +3 -1
- package/dist/esm/types/components/value-displays/value-base/value-edit.d.ts +7 -2
- package/dist/esm/types/components/value-displays/value-content/value-content.d.ts +10 -1
- package/dist/index.d.ts +26 -9
- package/package.json +2 -1
- package/src/components/alerts/expandable-alert/expandable-alert.stories.tsx +23 -1
- package/src/components/alerts/expandable-alert/expandable-alert.tsx +11 -4
- package/src/components/data-display/board/board.test.tsx +60 -43
- package/src/components/data-display/board/board.tsx +24 -17
- package/src/components/feedback/query-container/query-container.stories.tsx +19 -6
- package/src/components/feedback/query-container/query-container.test.tsx +65 -17
- package/src/components/feedback/query-container/query-container.tsx +20 -5
- package/src/components/inputs/autocomplete/autocomplete.stories.tsx +8 -0
- package/src/components/inputs/index.ts +1 -0
- package/src/components/inputs/text-field/text-field.stories.tsx +8 -0
- package/src/components/inputs/text-field/text-field.tsx +2 -2
- package/src/components/value-displays/group-value-card/group-value-card.mock.tsx +28 -8
- package/src/components/value-displays/group-value-card/group-value-card.stories.tsx +19 -2
- package/src/components/value-displays/group-value-card/group-value-card.test.tsx +16 -18
- package/src/components/value-displays/value-base/value-edit.test.tsx +88 -0
- package/src/components/value-displays/value-base/value-edit.tsx +28 -6
- package/src/components/value-displays/value-boolean/value-boolean.stories.tsx +9 -0
- package/src/components/value-displays/value-boolean/value-boolean.test.tsx +29 -15
- package/src/components/value-displays/value-boolean/value-boolean.tsx +18 -11
- package/src/components/value-displays/value-content/value-content.test.tsx +20 -6
- package/src/components/value-displays/value-content/value-content.tsx +24 -10
- package/src/components/value-displays/value-datetime/value-datetime.stories.tsx +11 -0
- package/src/components/value-displays/value-datetime/value-datetime.test.tsx +9 -9
- package/src/components/value-displays/value-datetime/value-datetime.tsx +14 -10
- package/src/components/value-displays/value-rating/value-rating.stories.tsx +10 -0
- package/src/components/value-displays/value-rating/value-rating.test.tsx +11 -11
- package/src/components/value-displays/value-rating/value-rating.tsx +10 -8
- package/src/components/value-displays/value-text/value-text.stories.tsx +9 -0
- package/src/components/value-displays/value-text/value-text.test.tsx +20 -9
- package/src/components/value-displays/value-text/value-text.tsx +23 -10
- package/src/generators/model-form/model-form.test.tsx +1 -1
- package/src/generators/model-router/model-router.test.tsx +3 -3
- package/src/layouts/header-layout/header-layout.stories.tsx +2 -2
- 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 })).
|
|
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")).
|
|
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")).
|
|
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)).
|
|
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)).
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
103
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
90
104
|
await userEvent.click(screen.getByRole("checkbox"));
|
|
91
|
-
await userEvent.click(screen.
|
|
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.
|
|
115
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
102
116
|
await userEvent.click(screen.getByRole("checkbox"));
|
|
103
|
-
await userEvent.click(screen.
|
|
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.
|
|
125
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
112
126
|
await userEvent.click(screen.getByRole("checkbox"));
|
|
113
|
-
await userEvent.click(screen.
|
|
114
|
-
await userEvent.click(screen.
|
|
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,
|
|
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
|
|
39
|
-
|
|
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
|
|
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 = ({
|
|
8
|
+
const renderComponent = ({
|
|
9
|
+
tooltip,
|
|
10
|
+
hideLabel,
|
|
11
|
+
}: { tooltip?: string; hideLabel?: boolean } = {}) => {
|
|
9
12
|
render(
|
|
10
|
-
<ValueContent
|
|
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 })).
|
|
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 })).
|
|
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)).
|
|
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)).
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
108
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
109
109
|
pickDatetime(screen.getByRole("textbox"), newValue, fmt);
|
|
110
|
-
await userEvent.click(screen.
|
|
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.
|
|
120
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
121
121
|
pickDatetime(screen.getByRole("textbox"), NewValue, datetimeFormat);
|
|
122
|
-
await userEvent.click(screen.
|
|
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.
|
|
130
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
131
131
|
pickDatetime(screen.getByRole("textbox"), NewValue, datetimeFormat);
|
|
132
|
-
await userEvent.click(screen.
|
|
133
|
-
await userEvent.click(screen.
|
|
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,
|
|
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
|
|
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
|
-
|
|
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>
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
77
|
-
await userEvent.click(screen.
|
|
78
|
-
await userEvent.click(screen.
|
|
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.
|
|
87
|
+
await userEvent.click(screen.getByRole("button", { name: /edit/i }));
|
|
88
88
|
await userEvent.click(screen.getAllByRole("radio")[3]);
|
|
89
|
-
await userEvent.click(screen.
|
|
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.
|
|
98
|
-
await userEvent.click(screen.
|
|
99
|
-
await userEvent.click(screen.
|
|
100
|
-
await userEvent.click(screen.
|
|
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={(
|
|
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
|
-
|
|
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
|
);
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
113
|
-
await userEvent.click(screen.
|
|
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
|
});
|