@griddo/ax 1.63.4 → 1.64.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/griddo-config/cx-polyfills/builder.ssr.js +6 -0
- package/config/griddo-config/cx-polyfills/componentsBundle.js +4 -0
- package/config/{griddo-config.js → griddo-config/index.js} +36 -15
- package/config/griddo-config/ssrHelpers.js +47 -0
- package/config/jest/componentsMock.js +29 -0
- package/config/jest/fileMock.js +1 -0
- package/config/jest/setup.js +5 -0
- package/config/jest/styleMock.js +1 -0
- package/config/jest/test-utils.js +17 -0
- package/config/paths.js +36 -5
- package/config/webpack.config.js +1 -1
- package/config/webpackDevServer.config.js +4 -1
- package/config/webpackSchemas.config.js +4 -1
- package/package.json +35 -64
- package/scripts/build.js +9 -2
- package/src/__mocks__/reducers/analyticsState.tsx +14 -0
- package/src/__mocks__/reducers/pageEditor.tsx +30 -0
- package/src/api/sites.tsx +28 -6
- package/src/api/structuredData.tsx +1 -1
- package/src/api/users.tsx +5 -4
- package/src/components/ActionMenu/style.tsx +2 -0
- package/src/components/Browser/index.tsx +9 -5
- package/src/{modules/Content/PageItem/atoms.tsx → components/CategoryCell/index.tsx} +4 -6
- package/src/components/CategoryCell/style.tsx +11 -0
- package/src/components/Fields/AnalyticsField/PageAnalytics/index.tsx +19 -19
- package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/atoms.tsx +26 -16
- package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/index.tsx +8 -13
- package/src/components/Fields/AnalyticsField/index.test.tsx +100 -0
- package/src/components/Fields/AnalyticsField/index.tsx +9 -2
- package/src/components/Fields/AnalyticsField/utils.tsx +2 -2
- package/src/components/Fields/ArrayFieldGroup/ArrayFieldItem/style.tsx +2 -1
- package/src/components/Fields/CheckField/index.test.tsx +95 -0
- package/src/components/Fields/CheckField/index.tsx +9 -3
- package/src/components/Fields/CheckField/style.tsx +32 -24
- package/src/components/Fields/CheckGroup/index.test.tsx +274 -0
- package/src/components/Fields/CheckGroup/index.tsx +2 -1
- package/src/components/Fields/FileField/FileDragAndDrop/style.tsx +3 -2
- package/src/components/Fields/FileField/style.tsx +2 -1
- package/src/components/Fields/MultiCheckSelect/style.tsx +18 -18
- package/src/components/Fields/NoteField/style.tsx +9 -9
- package/src/components/Fields/ReferenceField/AutoPanel/AutoItem/index.tsx +1 -1
- package/src/components/Fields/Select/style.tsx +41 -37
- package/src/components/Fields/TagField/index.test.tsx +136 -0
- package/src/components/Fields/TagField/index.tsx +8 -12
- package/src/components/Fields/TextArea/index.test.tsx +69 -0
- package/src/components/Fields/TextArea/index.tsx +4 -13
- package/src/components/Fields/TextArea/style.tsx +2 -2
- package/src/components/Fields/TextField/index.test.tsx +144 -0
- package/src/components/Fields/TextField/index.tsx +23 -19
- package/src/components/Fields/TextField/style.tsx +16 -7
- package/src/components/Fields/UniqueCheck/index.test.tsx +43 -0
- package/src/components/Fields/UrlField/utils.tsx +8 -6
- package/src/components/FieldsBehavior/index.tsx +0 -2
- package/src/components/FieldsBehavior/style.tsx +21 -21
- package/src/components/Gallery/GalleryFilters/Orientation/style.tsx +2 -1
- package/src/components/Gallery/GalleryFilters/SortBy/style.tsx +2 -1
- package/src/components/Icon/index.tsx +12 -10
- package/src/components/IconAction/index.tsx +7 -1
- package/src/components/IconAction/style.tsx +10 -10
- package/src/components/SearchField/index.tsx +11 -8
- package/src/components/SearchField/style.tsx +21 -12
- package/src/components/TableFilters/CategoryFilter/index.tsx +1 -1
- package/src/components/TableFilters/CategoryFilter/style.tsx +2 -1
- package/src/components/TableFilters/DateFilter/style.tsx +2 -1
- package/src/components/TableFilters/LiveFilter/index.tsx +2 -2
- package/src/components/TableFilters/LiveFilter/style.tsx +2 -1
- package/src/components/TableFilters/NameFilter/style.tsx +2 -1
- package/src/components/TableFilters/SiteFilter/index.tsx +38 -24
- package/src/components/TableFilters/SiteFilter/style.tsx +2 -1
- package/src/components/TableFilters/StatusFilter/style.tsx +2 -1
- package/src/components/TableFilters/TranslationsFilter/style.tsx +2 -1
- package/src/components/TableFilters/TypeFilter/style.tsx +2 -1
- package/src/components/Tag/index.tsx +9 -7
- package/src/components/Tag/style.tsx +20 -8
- package/src/components/index.tsx +4 -2
- package/src/containers/App/reducer.tsx +0 -2
- package/src/containers/PageEditor/actions.tsx +2 -2
- package/src/containers/Sites/actions.tsx +30 -19
- package/src/containers/Users/actions.tsx +10 -2
- package/src/containers/Users/reducer.tsx +3 -1
- package/src/helpers/fields.tsx +2 -4
- package/src/helpers/index.tsx +3 -0
- package/src/helpers/themes.tsx +9 -0
- package/src/index.tsx +3 -0
- package/src/modules/Analytics/GroupPanel/utils.tsx +3 -3
- package/src/modules/App/Routing/NavMenu/index.tsx +13 -12
- package/src/modules/Content/PageItem/index.tsx +31 -9
- package/src/modules/Content/PageItem/style.tsx +0 -7
- package/src/modules/Content/atoms.tsx +78 -0
- package/src/modules/Content/index.tsx +104 -33
- package/src/modules/Content/style.tsx +10 -7
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +0 -4
- package/src/modules/GlobalEditor/index.tsx +3 -3
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +0 -4
- package/src/modules/PageEditor/PageBrowser/index.tsx +0 -4
- package/src/modules/PageEditor/atoms.tsx +74 -0
- package/src/modules/PageEditor/index.tsx +30 -9
- package/src/modules/PageEditor/style.tsx +4 -0
- package/src/modules/PublicPreview/index.tsx +3 -5
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/TemplateBrowser/index.tsx +0 -4
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/index.tsx +2 -3
- package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/index.tsx +1 -1
- package/src/modules/Settings/Globals/index.tsx +3 -3
- package/src/modules/StructuredData/Form/index.tsx +2 -4
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +22 -18
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/atoms.tsx +3 -24
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +2 -2
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/style.tsx +0 -7
- package/src/modules/StructuredData/StructuredDataList/OptionTable/index.tsx +2 -4
- package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +46 -14
- package/src/modules/StructuredData/StructuredDataList/hooks.tsx +21 -9
- package/src/modules/StructuredData/StructuredDataList/index.tsx +48 -20
- package/src/modules/Users/Profile/index.tsx +12 -7
- package/src/modules/Users/UserCreate/SiteItem/index.tsx +44 -0
- package/src/modules/Users/UserCreate/SiteItem/style.tsx +30 -0
- package/src/modules/Users/UserCreate/index.tsx +120 -10
- package/src/modules/Users/UserCreate/style.tsx +54 -1
- package/src/modules/Users/UserEdit/index.tsx +53 -15
- package/src/modules/Users/UserForm/index.tsx +152 -5
- package/src/modules/Users/UserForm/style.tsx +40 -2
- package/src/modules/Users/UserList/BulkHeader/TableHeader/index.tsx +40 -2
- package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +0 -1
- package/src/modules/Users/UserList/BulkHeader/index.tsx +10 -1
- package/src/modules/Users/UserList/UserItem/index.tsx +70 -15
- package/src/modules/Users/UserList/hooks.tsx +58 -1
- package/src/modules/Users/UserList/index.tsx +80 -34
- package/src/modules/Users/index.tsx +18 -11
- package/src/routes/site.tsx +8 -0
- package/src/types/index.tsx +7 -0
- package/tsconfig.json +2 -0
- package/patches/connected-react-router+6.9.2.patch +0 -12
- package/scripts/test.js +0 -45
|
@@ -1,35 +1,39 @@
|
|
|
1
1
|
import styled, { css } from "styled-components";
|
|
2
2
|
import Select from "react-select";
|
|
3
3
|
|
|
4
|
-
export const StyledSelect = styled(Select)<{
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export const StyledSelect = styled(Select)<{
|
|
5
|
+
isDisabled: boolean | undefined;
|
|
6
|
+
error: boolean | undefined;
|
|
7
|
+
alignRight: boolean | undefined;
|
|
8
|
+
}>`
|
|
9
|
+
${(p) => p.theme.textStyle?.fieldContent};
|
|
10
|
+
color: ${(p) => p.theme.color?.textHighEmphasis};
|
|
11
|
+
margin-bottom: ${(p) => p.theme.spacing?.xxs};
|
|
8
12
|
|
|
9
13
|
.react-select__control {
|
|
10
|
-
background-color: ${(p) => p.theme.color
|
|
14
|
+
background-color: ${(p) => p.theme.color?.interactiveBackground};
|
|
11
15
|
box-sizing: border-box;
|
|
12
16
|
border-radius: 4px;
|
|
13
|
-
border-color: ${(p) => (p.error ? p.theme.color
|
|
17
|
+
border-color: ${(p) => (p.error ? p.theme.color?.error : p.theme.color?.uiLine)};
|
|
14
18
|
box-shadow: none;
|
|
15
|
-
height: ${(p) => p.theme.spacing
|
|
16
|
-
max-width: calc(${(p) => p.theme.spacing
|
|
19
|
+
height: ${(p) => p.theme.spacing?.l};
|
|
20
|
+
max-width: calc(${(p) => p.theme.spacing?.xl} * 6);
|
|
17
21
|
:hover {
|
|
18
|
-
border-color: ${(p) => (p.error ? p.theme.color
|
|
22
|
+
border-color: ${(p) => (p.error ? p.theme.color?.error : p.theme.color?.uiLine)};
|
|
19
23
|
}
|
|
20
24
|
.react-select__placeholder {
|
|
21
|
-
color: ${(p) => p.theme.color
|
|
25
|
+
color: ${(p) => p.theme.color?.textLowEmphasis};
|
|
22
26
|
}
|
|
23
27
|
.react-select__indicator-separator {
|
|
24
28
|
display: none;
|
|
25
29
|
}
|
|
26
30
|
.react-select__indicator {
|
|
27
|
-
color: ${(p) => (p.isDisabled ? p.theme.color
|
|
31
|
+
color: ${(p) => (p.isDisabled ? p.theme.color?.interactiveDisabled : p.theme.color?.interactive01)};
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
.react-select__control--is-focused {
|
|
32
|
-
border-color: ${(p) => (p.error ? p.theme.color
|
|
36
|
+
border-color: ${(p) => (p.error ? p.theme.color?.error : p.theme.color?.interactive01)} !important;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
.react-select__control--menu-is-open {
|
|
@@ -39,61 +43,61 @@ export const StyledSelect = styled(Select)<{ isDisabled: boolean | undefined; er
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
.react-select__control--is-disabled {
|
|
42
|
-
border-color: ${(p) => p.theme.color
|
|
46
|
+
border-color: ${(p) => p.theme.color?.interactiveDisabled};
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
.react-select__menu {
|
|
46
50
|
box-shadow: 0px 6px 6px rgba(32, 34, 76, 0.08);
|
|
47
51
|
border-radius: 4px;
|
|
48
|
-
min-width: calc(${(p) => p.theme.spacing
|
|
49
|
-
max-width: calc(${(p) => p.theme.spacing
|
|
52
|
+
min-width: calc(${(p) => p.theme.spacing?.xl} * 2);
|
|
53
|
+
max-width: calc(${(p) => p.theme.spacing?.xl} * 6);
|
|
50
54
|
margin-top: 0;
|
|
51
55
|
z-index: 99;
|
|
52
56
|
.react-select__menu-list {
|
|
53
|
-
max-height: calc(${(p) => p.theme.spacing
|
|
57
|
+
max-height: calc(${(p) => p.theme.spacing?.l} * 3);
|
|
54
58
|
overflow: auto;
|
|
55
59
|
padding: 0;
|
|
56
60
|
.react-select__option {
|
|
57
|
-
background-color: ${(p) => p.theme.color
|
|
58
|
-
min-height: ${(p) => p.theme.spacing
|
|
59
|
-
padding: ${(p) => p.theme.spacing
|
|
61
|
+
background-color: ${(p) => p.theme.color?.interactiveBackground};
|
|
62
|
+
min-height: ${(p) => p.theme.spacing?.l};
|
|
63
|
+
padding: ${(p) => p.theme.spacing?.s};
|
|
60
64
|
&:first-child {
|
|
61
|
-
${(p) =>
|
|
65
|
+
${(p) =>
|
|
66
|
+
p.hasEmptyOption &&
|
|
62
67
|
css`
|
|
63
68
|
font-style: italic;
|
|
64
|
-
color: ${(p) => p.theme.color
|
|
65
|
-
background-color: ${(p) => p.theme.color
|
|
66
|
-
`
|
|
67
|
-
}
|
|
69
|
+
color: ${(p) => p.theme.color?.textLowEmphasis};
|
|
70
|
+
background-color: ${(p) => p.theme.color?.uiLineInverse};
|
|
71
|
+
`}
|
|
68
72
|
}
|
|
69
73
|
:hover {
|
|
70
74
|
cursor: pointer;
|
|
71
|
-
background-color: ${(p) => p.theme.color
|
|
75
|
+
background-color: ${(p) => p.theme.color?.overlayHoverPrimary};
|
|
72
76
|
}
|
|
73
77
|
:focus {
|
|
74
|
-
background-color: ${(p) => p.theme.color
|
|
75
|
-
border: 0.5px solid ${(p) => p.theme.color
|
|
78
|
+
background-color: ${(p) => p.theme.color?.overlayFocusPrimary};
|
|
79
|
+
border: 0.5px solid ${(p) => p.theme.color?.interactive02};
|
|
76
80
|
}
|
|
77
81
|
:active {
|
|
78
|
-
background-color: ${(p) => p.theme.color
|
|
82
|
+
background-color: ${(p) => p.theme.color?.overlayPressedPrimary};
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
.react-select__option--is-selected {
|
|
82
|
-
color: ${(p) => p.theme.color
|
|
83
|
-
background-color: ${(p) => p.theme.color
|
|
86
|
+
color: ${(p) => p.theme.color?.textHighEmphasis};
|
|
87
|
+
background-color: ${(p) => p.theme.color?.overlayPressedPrimary};
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
&.inline {
|
|
89
|
-
${(p) => p.theme.textStyle
|
|
93
|
+
${(p) => p.theme.textStyle?.uiS};
|
|
90
94
|
text-transform: capitalize;
|
|
91
95
|
|
|
92
96
|
.react-select__control {
|
|
93
97
|
background: transparent;
|
|
94
98
|
border: none;
|
|
95
99
|
height: auto;
|
|
96
|
-
justify-content: ${(p) => p.alignRight ? "flex-end" : "flex-start"};
|
|
100
|
+
justify-content: ${(p) => (p.alignRight ? "flex-end" : "flex-start")};
|
|
97
101
|
|
|
98
102
|
.react-select__value-container {
|
|
99
103
|
flex: 0 1 auto;
|
|
@@ -101,15 +105,15 @@ export const StyledSelect = styled(Select)<{ isDisabled: boolean | undefined; er
|
|
|
101
105
|
.react-select__single-value {
|
|
102
106
|
position: relative;
|
|
103
107
|
transform: none;
|
|
104
|
-
color: ${(p) => p.theme.color
|
|
108
|
+
color: ${(p) => p.theme.color?.interactive01};
|
|
105
109
|
overflow: visible;
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
.react-select__indicator {
|
|
109
113
|
padding: 0;
|
|
110
114
|
svg {
|
|
111
|
-
width: ${(p) => p.theme.spacing
|
|
112
|
-
height: ${(p) => p.theme.spacing
|
|
115
|
+
width: ${(p) => p.theme.spacing?.s};
|
|
116
|
+
height: ${(p) => p.theme.spacing?.s};
|
|
113
117
|
}
|
|
114
118
|
}
|
|
115
119
|
.react-select__input {
|
|
@@ -122,13 +126,13 @@ export const StyledSelect = styled(Select)<{ isDisabled: boolean | undefined; er
|
|
|
122
126
|
.react-select__control--is-disabled {
|
|
123
127
|
.react-select__value-container {
|
|
124
128
|
.react-select__single-value {
|
|
125
|
-
color: ${(p) => p.theme.color
|
|
129
|
+
color: ${(p) => p.theme.color?.interactiveDisabled};
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
.react-select__menu {
|
|
131
|
-
${(p) => p.theme.textStyle
|
|
135
|
+
${(p) => p.theme.textStyle?.fieldContent};
|
|
132
136
|
}
|
|
133
137
|
}
|
|
134
138
|
`;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import TagField from "./index";
|
|
3
|
+
import { ThemeProvider } from "styled-components";
|
|
4
|
+
import { parseTheme } from "@griddo/core";
|
|
5
|
+
import globalTheme from "../../../themes/theme.json";
|
|
6
|
+
import { render, screen, within, cleanup, fireEvent } from "@testing-library/react";
|
|
7
|
+
|
|
8
|
+
afterEach(cleanup);
|
|
9
|
+
|
|
10
|
+
const props = {
|
|
11
|
+
value: [],
|
|
12
|
+
onChange: jest.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe("TagField component", () => {
|
|
16
|
+
test("should render the component", () => {
|
|
17
|
+
render(
|
|
18
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
19
|
+
<TagField {...props} />
|
|
20
|
+
</ThemeProvider>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const tagFieldWrapper = screen.getAllByTestId("tagFieldWrapper");
|
|
24
|
+
expect(tagFieldWrapper).toBeTruthy();
|
|
25
|
+
expect(tagFieldWrapper).toHaveLength(1);
|
|
26
|
+
|
|
27
|
+
const tagFieldInput = screen.getAllByTestId("tagFieldInput");
|
|
28
|
+
expect(tagFieldInput).toBeTruthy();
|
|
29
|
+
expect(tagFieldInput).toHaveLength(1);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("should render the tags if have values", () => {
|
|
33
|
+
const defaultProps = {
|
|
34
|
+
value: ["one", "two"],
|
|
35
|
+
onChange: jest.fn(),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
render(
|
|
39
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
40
|
+
<TagField {...defaultProps} />
|
|
41
|
+
</ThemeProvider>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const tagFieldWrapper = screen.getByTestId("tagFieldWrapper");
|
|
45
|
+
expect(tagFieldWrapper).toBeTruthy();
|
|
46
|
+
|
|
47
|
+
const tagFieldInput = screen.getByTestId("tagFieldInput");
|
|
48
|
+
expect(tagFieldInput).toBeTruthy();
|
|
49
|
+
|
|
50
|
+
const tagRendered = within(tagFieldWrapper).getAllByTestId("tagComponent");
|
|
51
|
+
expect(tagRendered).toHaveLength(2);
|
|
52
|
+
|
|
53
|
+
const tagComponent = screen.getByTestId("tagFieldWrapper");
|
|
54
|
+
expect(tagComponent.textContent).toBe("onetwo");
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("TagField events", () => {
|
|
59
|
+
test("should call the value when call onchange", () => {
|
|
60
|
+
render(
|
|
61
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
62
|
+
<TagField {...props} />
|
|
63
|
+
</ThemeProvider>
|
|
64
|
+
);
|
|
65
|
+
const tagFieldInput = screen.getByTestId<HTMLInputElement>("tagFieldInput");
|
|
66
|
+
|
|
67
|
+
fireEvent.change(tagFieldInput, { target: { value: "test" } });
|
|
68
|
+
expect(tagFieldInput.value).toBe("test");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("should add new value on keyDown if it's not in array", () => {
|
|
72
|
+
const onChange = jest.fn();
|
|
73
|
+
const defaultProps = {
|
|
74
|
+
value: [],
|
|
75
|
+
onChange,
|
|
76
|
+
};
|
|
77
|
+
render(
|
|
78
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
79
|
+
<TagField {...defaultProps} />
|
|
80
|
+
</ThemeProvider>
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const tagFieldInput = screen.getByTestId<HTMLInputElement>("tagFieldInput");
|
|
84
|
+
fireEvent.input(tagFieldInput, { target: { value: "test" } });
|
|
85
|
+
fireEvent.keyDown(tagFieldInput, { key: "Enter", code: "Enter", charCode: 13 });
|
|
86
|
+
expect(onChange).toHaveBeenCalledWith(["test"]);
|
|
87
|
+
});
|
|
88
|
+
test("shouldn't add new value on keyDown if it's in array", () => {
|
|
89
|
+
const onChange = jest.fn();
|
|
90
|
+
const defaultProps = {
|
|
91
|
+
value: ["test"],
|
|
92
|
+
onChange,
|
|
93
|
+
};
|
|
94
|
+
render(
|
|
95
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
96
|
+
<TagField {...defaultProps} />
|
|
97
|
+
</ThemeProvider>
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const tagFieldInput = screen.getByTestId<HTMLInputElement>("tagFieldInput");
|
|
101
|
+
fireEvent.input(tagFieldInput, { target: { value: "test" } });
|
|
102
|
+
fireEvent.keyDown(tagFieldInput, { key: "Enter", code: "Enter", charCode: 13 });
|
|
103
|
+
expect(onChange).toBeCalledTimes(0);
|
|
104
|
+
});
|
|
105
|
+
test("should delete value from array", () => {
|
|
106
|
+
const onChange = jest.fn();
|
|
107
|
+
const defaultProps = {
|
|
108
|
+
value: ["one", "two"],
|
|
109
|
+
onChange,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
render(
|
|
113
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
114
|
+
<TagField {...defaultProps} />
|
|
115
|
+
</ThemeProvider>
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const tagFieldWrapper = screen.getByTestId("tagFieldWrapper");
|
|
119
|
+
const tagRendered = within(tagFieldWrapper).getAllByTestId("tagComponent");
|
|
120
|
+
expect(tagRendered).toHaveLength(2);
|
|
121
|
+
fireEvent.click(tagRendered[0], 0);
|
|
122
|
+
expect(onChange).toBeCalledTimes(1);
|
|
123
|
+
});
|
|
124
|
+
test("should call the focus function", () => {
|
|
125
|
+
// we can check if the focus function is been called
|
|
126
|
+
const useRefSpy = jest.spyOn(React, "useRef").mockReturnValueOnce({ current: { focus: jest.fn() } });
|
|
127
|
+
render(
|
|
128
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
129
|
+
<TagField {...props} />
|
|
130
|
+
</ThemeProvider>
|
|
131
|
+
);
|
|
132
|
+
const tagFieldWrapper = screen.getByTestId("tagFieldWrapper");
|
|
133
|
+
fireEvent.click(tagFieldWrapper);
|
|
134
|
+
expect(useRefSpy).toBeCalledTimes(1);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -3,11 +3,9 @@ import { Tag } from "@ax/components";
|
|
|
3
3
|
|
|
4
4
|
import * as S from "./style";
|
|
5
5
|
|
|
6
|
-
const TagField = (props: IProps) => {
|
|
6
|
+
const TagField = (props: IProps): JSX.Element => {
|
|
7
7
|
const { value, onChange } = props;
|
|
8
|
-
|
|
9
8
|
const valueArray = value && Array.isArray(value) ? value : [];
|
|
10
|
-
|
|
11
9
|
const [inputValue, setInputValue] = useState("");
|
|
12
10
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
13
11
|
|
|
@@ -35,19 +33,17 @@ const TagField = (props: IProps) => {
|
|
|
35
33
|
onChange(newValue);
|
|
36
34
|
};
|
|
37
35
|
|
|
38
|
-
const Tags =
|
|
39
|
-
valueArray &&
|
|
40
|
-
valueArray.map((tag: string, index: number) => {
|
|
41
|
-
const handleDelete = () => deleteTag(index);
|
|
42
|
-
return <Tag key={tag} text={tag} deleteAction={handleDelete} />;
|
|
43
|
-
});
|
|
44
|
-
|
|
45
36
|
const placeholder = valueArray.length > 0 ? "" : "Type a tag...";
|
|
46
37
|
|
|
47
38
|
return (
|
|
48
|
-
<S.Wrapper onClick={_handleClick}>
|
|
49
|
-
{
|
|
39
|
+
<S.Wrapper data-testid="tagFieldWrapper" onClick={_handleClick}>
|
|
40
|
+
{valueArray &&
|
|
41
|
+
valueArray.map((tag: string, index: number) => {
|
|
42
|
+
const handleDelete = () => deleteTag(index);
|
|
43
|
+
return <Tag key={tag} text={tag} onDeleteAction={handleDelete} />;
|
|
44
|
+
})}
|
|
50
45
|
<S.Input
|
|
46
|
+
data-testid="tagFieldInput"
|
|
51
47
|
ref={inputRef}
|
|
52
48
|
type="text"
|
|
53
49
|
value={inputValue}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import TextArea from "./index";
|
|
3
|
+
import { ThemeProvider } from "styled-components";
|
|
4
|
+
import { parseTheme } from "@griddo/core";
|
|
5
|
+
import globalTheme from "../../../themes/theme.json";
|
|
6
|
+
import { render, screen, cleanup, fireEvent } from "@testing-library/react";
|
|
7
|
+
|
|
8
|
+
afterEach(cleanup);
|
|
9
|
+
|
|
10
|
+
const props = {
|
|
11
|
+
name: "",
|
|
12
|
+
value: "",
|
|
13
|
+
onChange: jest.fn(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
describe("TextArea component rendering", () => {
|
|
17
|
+
test("should render the component with no CheckField", () => {
|
|
18
|
+
render(
|
|
19
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
20
|
+
<TextArea {...props} />
|
|
21
|
+
</ThemeProvider>
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const textAreaComponent = screen.getAllByTestId("textAreaComponent");
|
|
25
|
+
expect(textAreaComponent).toHaveLength(1);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("TextArea events", () => {
|
|
30
|
+
test("should call the onChange", () => {
|
|
31
|
+
const setStateMock = jest.fn();
|
|
32
|
+
const useStateMock: any = (useState: string) => [useState, setStateMock];
|
|
33
|
+
jest.spyOn(React, "useState").mockImplementation(useStateMock);
|
|
34
|
+
|
|
35
|
+
render(
|
|
36
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
37
|
+
<TextArea {...props} />
|
|
38
|
+
</ThemeProvider>
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const textAreaComponent = screen.getByTestId("textAreaComponent");
|
|
42
|
+
expect(textAreaComponent).toBeTruthy();
|
|
43
|
+
fireEvent.change(textAreaComponent, { target: { value: "test" } });
|
|
44
|
+
expect(setStateMock).toHaveBeenCalledWith("test");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("should call the onBlur", () => {
|
|
48
|
+
const handleValidationMock = jest.fn();
|
|
49
|
+
const defaultProps = {
|
|
50
|
+
name: "name",
|
|
51
|
+
value: "value",
|
|
52
|
+
onChange: jest.fn(),
|
|
53
|
+
handleValidation: handleValidationMock,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
render(
|
|
57
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
58
|
+
<TextArea {...defaultProps} />
|
|
59
|
+
</ThemeProvider>
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const textAreaComponent = screen.getByTestId("textAreaComponent");
|
|
63
|
+
|
|
64
|
+
expect(textAreaComponent).toBeTruthy();
|
|
65
|
+
fireEvent.blur(textAreaComponent, { target: { value: "name" } });
|
|
66
|
+
expect(handleValidationMock).toHaveBeenCalledTimes(1);
|
|
67
|
+
expect(handleValidationMock).toHaveBeenCalledWith("name");
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
import React, { memo, useEffect, useRef
|
|
1
|
+
import React, { memo, useEffect, useRef } from "react";
|
|
2
2
|
|
|
3
3
|
import * as S from "./style";
|
|
4
4
|
|
|
5
5
|
const TextArea = (props: ITextAreaProps): JSX.Element => {
|
|
6
|
-
const {
|
|
7
|
-
value,
|
|
8
|
-
placeholder,
|
|
9
|
-
error,
|
|
10
|
-
name,
|
|
11
|
-
onChange,
|
|
12
|
-
disabled,
|
|
13
|
-
handleValidation,
|
|
14
|
-
editorID,
|
|
15
|
-
rows = 1
|
|
16
|
-
} = props;
|
|
6
|
+
const { value, placeholder, error, name, onChange, disabled, handleValidation, editorID, rows = 1 } = props;
|
|
17
7
|
|
|
18
|
-
const [state, setState] = useState<string>(value);
|
|
8
|
+
const [state, setState] = React.useState<string>(value);
|
|
19
9
|
const timeOutRef = useRef<ReturnType<typeof setTimeout>>();
|
|
20
10
|
|
|
21
11
|
useEffect(() => {
|
|
@@ -45,6 +35,7 @@ const TextArea = (props: ITextAreaProps): JSX.Element => {
|
|
|
45
35
|
|
|
46
36
|
return (
|
|
47
37
|
<S.TextArea
|
|
38
|
+
data-testid="textAreaComponent"
|
|
48
39
|
name={name}
|
|
49
40
|
minRows={rows}
|
|
50
41
|
maxRows={4}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
2
|
import TextareaAutosize from "react-textarea-autosize";
|
|
3
3
|
|
|
4
|
-
export const TextArea = styled(TextareaAutosize)
|
|
4
|
+
export const TextArea = styled(TextareaAutosize)<{ $error: boolean | undefined }>`
|
|
5
5
|
${(p) => p.theme.textStyle.fieldContent};
|
|
6
|
-
border: 1px solid ${p => (p.$error === true ? p.theme.color.error : p.theme.color.uiLine)};
|
|
6
|
+
border: 1px solid ${(p) => (p.$error === true ? p.theme.color.error : p.theme.color.uiLine)};
|
|
7
7
|
border-radius: 4px;
|
|
8
8
|
background-color: ${(p) => p.theme.color.uiBackground02};
|
|
9
9
|
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import TextField from "./index";
|
|
3
|
+
import { ThemeProvider } from "styled-components";
|
|
4
|
+
import { parseTheme } from "@griddo/core";
|
|
5
|
+
import globalTheme from "../../../themes/theme.json";
|
|
6
|
+
import { render, screen, within, cleanup, fireEvent } from "@testing-library/react";
|
|
7
|
+
|
|
8
|
+
afterEach(cleanup);
|
|
9
|
+
|
|
10
|
+
const defaultProps = {
|
|
11
|
+
value: "",
|
|
12
|
+
onChange: jest.fn(),
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
describe("TextField component rendering", () => {
|
|
16
|
+
test("should render the component", () => {
|
|
17
|
+
render(
|
|
18
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
19
|
+
<TextField {...defaultProps} />
|
|
20
|
+
</ThemeProvider>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
const textFieldContainer = screen.getByTestId("textFieldContainer");
|
|
24
|
+
const inputComponent = screen.getByTestId("inputComponent");
|
|
25
|
+
|
|
26
|
+
expect(textFieldContainer).toBeTruthy();
|
|
27
|
+
expect(inputComponent).toBeTruthy();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("should render the component with prefix", () => {
|
|
31
|
+
const props = {
|
|
32
|
+
value: "value",
|
|
33
|
+
onChange: jest.fn(),
|
|
34
|
+
prefix: "prefix",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
render(
|
|
38
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
39
|
+
<TextField {...props} />
|
|
40
|
+
</ThemeProvider>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const textFieldContainer = screen.getByTestId("textFieldContainer");
|
|
44
|
+
const inputComponent = screen.getByTestId("inputComponent");
|
|
45
|
+
const prefix = screen.getByTestId("prefix");
|
|
46
|
+
expect(textFieldContainer).toBeTruthy();
|
|
47
|
+
expect(inputComponent).toBeTruthy();
|
|
48
|
+
expect(prefix).toBeTruthy();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should render the component with backgroundIcon", () => {
|
|
52
|
+
const props = {
|
|
53
|
+
value: "value",
|
|
54
|
+
onChange: jest.fn(),
|
|
55
|
+
icon: "icon",
|
|
56
|
+
iconPosition: "in",
|
|
57
|
+
};
|
|
58
|
+
render(
|
|
59
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
60
|
+
<TextField {...props} />
|
|
61
|
+
</ThemeProvider>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const textFieldContainer = screen.getByTestId("textFieldContainer");
|
|
65
|
+
const inputComponent = screen.getByTestId("inputComponent");
|
|
66
|
+
const backgroundIconComponent = screen.getByTestId("backgroundIconComponent");
|
|
67
|
+
|
|
68
|
+
expect(textFieldContainer).toBeTruthy();
|
|
69
|
+
expect(inputComponent).toBeTruthy();
|
|
70
|
+
expect(backgroundIconComponent).toBeTruthy();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should render the component with button", () => {
|
|
74
|
+
const props = {
|
|
75
|
+
value: "value",
|
|
76
|
+
onChange: jest.fn(),
|
|
77
|
+
icon: "icon",
|
|
78
|
+
iconPosition: "out",
|
|
79
|
+
};
|
|
80
|
+
render(
|
|
81
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
82
|
+
<TextField {...props} />
|
|
83
|
+
</ThemeProvider>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const textFieldContainer = screen.getByTestId("textFieldContainer");
|
|
87
|
+
const inputComponent = screen.getByTestId("inputComponent");
|
|
88
|
+
const iconWrapperComponent = screen.getByTestId("iconWrapperComponent");
|
|
89
|
+
|
|
90
|
+
expect(textFieldContainer).toBeTruthy();
|
|
91
|
+
expect(inputComponent).toBeTruthy();
|
|
92
|
+
expect(iconWrapperComponent).toBeTruthy();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("onClick from buttons", () => {
|
|
97
|
+
test("onClickIcon been called in BackgroundIcon", () => {
|
|
98
|
+
const onClickIconMock = jest.fn();
|
|
99
|
+
const props = {
|
|
100
|
+
value: "value",
|
|
101
|
+
onChange: jest.fn(),
|
|
102
|
+
icon: "icon",
|
|
103
|
+
iconPosition: "in",
|
|
104
|
+
onClickIcon: onClickIconMock,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
render(
|
|
108
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
109
|
+
<TextField {...props} />
|
|
110
|
+
</ThemeProvider>
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
const backgroundIconComponent = screen.getByTestId("backgroundIconComponent");
|
|
114
|
+
expect(backgroundIconComponent).toBeTruthy();
|
|
115
|
+
|
|
116
|
+
// onClick called with simulate method
|
|
117
|
+
fireEvent.click(backgroundIconComponent);
|
|
118
|
+
expect(onClickIconMock).toBeCalledTimes(1);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("onClickIcon been called in BackgroundIcon", () => {
|
|
122
|
+
const onClickIconMock = jest.fn();
|
|
123
|
+
const props = {
|
|
124
|
+
value: "value",
|
|
125
|
+
onChange: jest.fn(),
|
|
126
|
+
icon: "icon",
|
|
127
|
+
iconPosition: "out",
|
|
128
|
+
onClickIcon: onClickIconMock,
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
render(
|
|
132
|
+
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
133
|
+
<TextField {...props} />
|
|
134
|
+
</ThemeProvider>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const iconWrapperComponent = screen.getByTestId("iconWrapperComponent");
|
|
138
|
+
expect(iconWrapperComponent).toBeTruthy();
|
|
139
|
+
const iconActionComponent = within(iconWrapperComponent).getByTestId("iconActionComponent");
|
|
140
|
+
expect(iconActionComponent).toBeTruthy();
|
|
141
|
+
fireEvent.click(iconActionComponent);
|
|
142
|
+
expect(onClickIconMock).toBeCalledTimes(1);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
@@ -66,31 +66,22 @@ const TextField = (props: ITextFieldProps): JSX.Element => {
|
|
|
66
66
|
handleValidation && handleValidation(newValue, validators);
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
const Button = () =>
|
|
70
|
-
icon && iconPosition === "out" ? (
|
|
71
|
-
<S.IconWrapper readonly={readonly} error={error}>
|
|
72
|
-
<IconAction icon={icon} onClick={onClickIcon} disabled={disabled} size="s" />
|
|
73
|
-
</S.IconWrapper>
|
|
74
|
-
) : null;
|
|
75
|
-
|
|
76
|
-
const BackgroundIcon = () =>
|
|
77
|
-
icon && iconPosition === "in" ? (
|
|
78
|
-
<S.BackgroundIcon onClick={onClickIcon}>
|
|
79
|
-
<Icon name={icon} size="24" />
|
|
80
|
-
</S.BackgroundIcon>
|
|
81
|
-
) : null;
|
|
82
|
-
|
|
83
69
|
const hasBackgroundIcon = !!icon && iconPosition === "in";
|
|
84
70
|
const hasButton = !!icon && iconPosition === "out";
|
|
85
71
|
|
|
86
|
-
const Prefix = () => (
|
|
72
|
+
const Prefix = () => (
|
|
73
|
+
<S.Prefix data-testid="prefix" ref={prefixRef}>
|
|
74
|
+
{prefix}
|
|
75
|
+
</S.Prefix>
|
|
76
|
+
);
|
|
87
77
|
|
|
88
78
|
const inputValue = !autoComplete ? state : value || "";
|
|
89
79
|
|
|
90
80
|
return (
|
|
91
|
-
<S.FieldWrapper error={error} className={className}>
|
|
92
|
-
<Prefix />
|
|
81
|
+
<S.FieldWrapper data-testid="textFieldContainer" error={error} className={className}>
|
|
82
|
+
{prefix && <Prefix />}
|
|
93
83
|
<S.Input
|
|
84
|
+
data-testid="inputComponent"
|
|
94
85
|
type={inputType}
|
|
95
86
|
value={inputValue}
|
|
96
87
|
name={name}
|
|
@@ -106,8 +97,21 @@ const TextField = (props: ITextFieldProps): JSX.Element => {
|
|
|
106
97
|
hasPrefix={!!prefix}
|
|
107
98
|
prefixWidth={width}
|
|
108
99
|
/>
|
|
109
|
-
|
|
110
|
-
|
|
100
|
+
{hasBackgroundIcon && (
|
|
101
|
+
<S.BackgroundIcon data-testid="backgroundIconComponent" onClick={onClickIcon}>
|
|
102
|
+
<Icon name={icon || ""} size="24" />
|
|
103
|
+
</S.BackgroundIcon>
|
|
104
|
+
)}
|
|
105
|
+
{hasButton && (
|
|
106
|
+
<S.IconWrapper data-testid="iconWrapperComponent" readonly={readonly} error={error}>
|
|
107
|
+
<IconAction
|
|
108
|
+
icon={icon || ""}
|
|
109
|
+
onClick={onClickIcon}
|
|
110
|
+
disabled={disabled}
|
|
111
|
+
size="s"
|
|
112
|
+
/>
|
|
113
|
+
</S.IconWrapper>
|
|
114
|
+
)}
|
|
111
115
|
</S.FieldWrapper>
|
|
112
116
|
);
|
|
113
117
|
};
|