@griddo/ax 1.69.8 → 1.72.0
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/jest/componentsMock.js +0 -26
- package/package.json +4 -3
- package/src/Style/index.tsx +1 -1
- package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +97 -0
- package/src/__tests__/components/EmptyState/EmptyState.test.tsx +78 -0
- package/src/__tests__/components/FieldContainer/FieldContainer.test.tsx +82 -0
- package/src/__tests__/components/Fields/AnalyticsField/AnalyticsField.test.tsx +1 -1
- package/src/__tests__/components/Fields/AnalyticsField/PageAnalytics/PageAnalytics.test.tsx +1 -15
- package/src/__tests__/components/Fields/AnalyticsField/StructuredDataAnalytics/StructuredDataAnalytics.test.tsx +1 -16
- package/src/__tests__/components/Fields/ArrayFieldGroup/ArrayFieldGroup.test.tsx +8 -17
- package/src/__tests__/components/Fields/AsyncCheckGroup/AsyncCheckGroup.test.tsx +4 -16
- package/src/__tests__/components/Fields/AsyncSelect/AsyncSelect.test.tsx +2 -20
- package/src/__tests__/components/Fields/CheckField/CheckField.test.tsx +6 -6
- package/src/__tests__/components/Fields/CheckGroup/CheckGroup.test.tsx +15 -15
- package/src/__tests__/components/Fields/ColorPicker/ColorPicker.test.tsx +7 -16
- package/src/__tests__/components/Fields/ComponentArray/ComponentArray.test.tsx +2 -23
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +11 -31
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +15 -21
- package/src/__tests__/components/Fields/ComponentArray/SameComponentArray/SameComponentArray.test.tsx +6 -25
- package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +559 -0
- package/src/__tests__/components/Fields/ConditionalField/ConditionalField.test.tsx +1 -1
- package/src/__tests__/components/Fields/DateField/DateField.test.tsx +1 -1
- package/src/__tests__/components/Fields/FieldGroup/FieldGroup.test.tsx +1 -1
- package/src/__tests__/components/Fields/FieldsDivider/FieldsDivider.test.tsx +1 -1
- package/src/__tests__/components/Fields/FileField/FileField.test.tsx +3 -3
- package/src/__tests__/components/Fields/HeadingField/HeadingField.test.tsx +6 -6
- package/src/__tests__/components/Fields/HiddenField/HiddenField.test.tsx +2 -8
- package/src/__tests__/components/Fields/ImageField/ImageField.test.tsx +471 -0
- package/src/__tests__/components/Fields/MultiCheckSelect/MultiCheckSelect.test.tsx +2 -16
- package/src/__tests__/components/Fields/MultiCheckSelectGroup/MultiCheckSelectGroup.test.tsx +2 -2
- package/src/__tests__/components/Fields/NoteField/NoteField.test.tsx +2 -7
- package/src/__tests__/components/Fields/NumberField/NumberField.test.tsx +2 -15
- package/src/__tests__/components/Fields/RadioField/RadioField.test.tsx +2 -12
- package/src/__tests__/components/Fields/ReferenceField/ReferenceField.test.tsx +171 -19
- package/src/__tests__/components/Fields/RichText/RichText.test.tsx +2 -13
- package/src/__tests__/components/Fields/Select/Select.test.tsx +3 -23
- package/src/__tests__/components/Fields/SliderField/SliderField.test.tsx +2 -15
- package/src/__tests__/components/Fields/TagField/TagField.test.tsx +4 -4
- package/src/__tests__/components/Fields/TextArea/TextArea.test.tsx +1 -1
- package/src/__tests__/components/Fields/TextField/TextField.test.tsx +6 -6
- package/src/__tests__/components/Fields/TimeField/HourInput/HourInput.test.tsx +142 -0
- package/src/__tests__/components/Fields/TimeField/TimeField.test.tsx +100 -0
- package/src/__tests__/components/Fields/ToggleField/ToggleField.test.tsx +2 -10
- package/src/__tests__/components/Fields/Tooltip/Tooltip.test.tsx +152 -0
- package/src/__tests__/components/Fields/UniqueCheck/UniqueCheck.test.tsx +3 -3
- package/src/__tests__/components/Fields/UrlField/UrlField.test.tsx +4 -4
- package/src/__tests__/components/Fields/VisualUniqueSelection/ImageSelection/ImageSelection.test.tsx +2 -14
- package/src/__tests__/components/Fields/VisualUniqueSelection/ScrollableSelection/ScrollableSelection.test.tsx +6 -20
- package/src/__tests__/components/Fields/VisualUniqueSelection/VisualUniqueSelection.test.tsx +3 -29
- package/src/__tests__/components/Fields/Wysiwyg/Wysiwyg.test.tsx +1 -1
- package/src/__tests__/components/FieldsBehavior/FieldsBehavior.test.tsx +149 -0
- package/src/__tests__/components/TableFilters/CategoryFilter/CategoryFilter.test.tsx +241 -0
- package/src/__tests__/components/TableFilters/CustomizeFilters/CustomizeFilters.test.tsx +131 -0
- package/src/__tests__/components/TableFilters/DateFilter/DateFilter.test.tsx +148 -0
- package/src/__tests__/components/TableFilters/LiveFilter/LiveFilter.test.tsx +265 -0
- package/src/__tests__/components/TableFilters/NameFilter/NameFilter.test.tsx +197 -0
- package/src/__tests__/components/TableFilters/SiteFilter/SiteFilter.test.tsx +317 -0
- package/src/__tests__/components/TableFilters/StatusFilter/StatusFilter.test.tsx +197 -0
- package/src/__tests__/components/TableFilters/TranslationsFilter/TranslationsFilter.test.tsx +157 -0
- package/src/__tests__/components/TableFilters/TypeFilter/TypeFilter.test.tsx +164 -0
- package/src/__tests__/components/TableList/TableList.test.tsx +119 -0
- package/src/__tests__/components/Tabs/Tabs.test.tsx +205 -0
- package/src/__tests__/components/Tag/Tag.test.tsx +140 -0
- package/src/__tests__/components/Toast/Toast.test.tsx +102 -0
- package/src/api/navigation.tsx +1 -1
- package/src/components/Browser/index.tsx +1 -1
- package/src/components/Button/index.tsx +3 -3
- package/src/components/ConfigPanel/NavigationForm/Field/index.tsx +14 -3
- package/src/components/ElementsTooltip/index.tsx +10 -9
- package/src/components/EmptyState/index.tsx +2 -2
- package/src/components/FieldContainer/index.tsx +3 -3
- package/src/components/Fields/ArrayFieldGroup/index.tsx +1 -1
- package/src/components/Fields/AsyncCheckGroup/index.tsx +1 -1
- package/src/components/Fields/AsyncSelect/index.tsx +1 -1
- package/src/components/Fields/CheckField/index.tsx +3 -3
- package/src/components/Fields/CheckGroup/index.tsx +2 -2
- package/src/components/Fields/ComponentContainer/index.tsx +7 -6
- package/src/components/Fields/ComponentContainer/style.tsx +2 -2
- package/src/components/Fields/HeadingField/index.tsx +1 -1
- package/src/components/Fields/HiddenField/index.tsx +1 -1
- package/src/components/Fields/ImageField/index.tsx +10 -5
- package/src/components/Fields/MultiCheckSelect/index.tsx +3 -3
- package/src/components/Fields/NumberField/index.tsx +2 -1
- package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +5 -7
- package/src/components/Fields/ReferenceField/ItemList/Item/style.tsx +2 -2
- package/src/components/Fields/ReferenceField/ItemList/index.tsx +1 -1
- package/src/components/Fields/RichText/index.tsx +10 -6
- package/src/components/Fields/Select/index.tsx +2 -2
- package/src/components/Fields/SliderField/index.tsx +1 -1
- package/src/components/Fields/TextField/index.tsx +2 -7
- package/src/components/Fields/TimeField/HourInput/index.tsx +103 -0
- package/src/components/Fields/TimeField/HourInput/style.tsx +19 -0
- package/src/components/Fields/TimeField/HourInput/utils.tsx +35 -0
- package/src/components/Fields/TimeField/index.tsx +57 -0
- package/src/components/Fields/TimeField/style.tsx +37 -0
- package/src/components/Fields/index.tsx +2 -0
- package/src/components/FieldsBehavior/index.tsx +1 -1
- package/src/components/FloatingMenu/index.tsx +2 -2
- package/src/components/Gallery/GalleryFilters/Type/index.tsx +50 -0
- package/src/components/Gallery/GalleryFilters/Type/style.tsx +39 -0
- package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +2 -1
- package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/style.tsx +3 -3
- package/src/components/Gallery/hooks.tsx +10 -4
- package/src/components/Gallery/index.tsx +2 -0
- package/src/components/Icon/index.tsx +1 -1
- package/src/components/IconAction/index.tsx +1 -1
- package/src/components/Lists/index.tsx +1 -1
- package/src/components/Loading/index.tsx +1 -1
- package/src/components/Pagination/index.tsx +1 -1
- package/src/components/SideModal/SideModalOption/index.tsx +4 -2
- package/src/components/SideModal/index.tsx +1 -1
- package/src/components/TableFilters/CategoryFilter/index.tsx +2 -2
- package/src/components/TableFilters/CategoryFilter/style.tsx +1 -10
- package/src/components/TableFilters/CustomizeFilters/index.tsx +2 -3
- package/src/components/TableFilters/DateFilter/index.tsx +4 -4
- package/src/components/TableFilters/LiveFilter/index.tsx +1 -1
- package/src/components/TableFilters/LiveFilter/style.tsx +2 -10
- package/src/components/TableFilters/NameFilter/index.tsx +4 -4
- package/src/components/TableFilters/SiteFilter/index.tsx +16 -13
- package/src/components/TableFilters/SiteFilter/style.tsx +1 -10
- package/src/components/TableFilters/StatusFilter/index.tsx +3 -3
- package/src/components/TableFilters/TranslationsFilter/index.tsx +4 -7
- package/src/components/TableFilters/TranslationsFilter/style.tsx +1 -10
- package/src/components/TableFilters/TypeFilter/index.tsx +2 -2
- package/src/components/TableFilters/TypeFilter/style.tsx +1 -10
- package/src/components/TableList/index.tsx +6 -6
- package/src/components/TableList/style.tsx +1 -1
- package/src/components/Tabs/index.tsx +19 -7
- package/src/components/Tag/index.tsx +6 -6
- package/src/components/Toast/index.tsx +4 -4
- package/src/components/Tooltip/index.tsx +5 -3
- package/src/components/index.tsx +2 -0
- package/src/containers/Navigation/Defaults/actions.tsx +10 -5
- package/src/containers/Navigation/Defaults/utils.tsx +13 -4
- package/src/containers/Sites/actions.tsx +7 -0
- package/src/containers/Sites/constants.tsx +1 -0
- package/src/containers/Sites/interfaces.tsx +6 -0
- package/src/containers/Sites/reducer.tsx +4 -0
- package/src/containers/StructuredData/actions.tsx +21 -8
- package/src/containers/StructuredData/constants.tsx +2 -0
- package/src/containers/StructuredData/interfaces.tsx +7 -1
- package/src/containers/StructuredData/reducer.tsx +5 -1
- package/src/helpers/fields.tsx +2 -2
- package/src/helpers/index.tsx +3 -0
- package/src/helpers/parseTheme.js +456 -0
- package/src/helpers/schemas.tsx +2 -2
- package/src/hooks/forms.tsx +2 -1
- package/src/modules/App/Routing/NavMenu/index.tsx +9 -1
- package/src/modules/Content/BulkHeader/TableHeader/index.tsx +1 -1
- package/src/modules/Content/hooks.tsx +19 -12
- package/src/modules/Content/index.tsx +23 -14
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -0
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +3 -1
- package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +16 -18
- package/src/modules/Navigation/Defaults/DefaultsEditor/utils.tsx +37 -0
- package/src/modules/StructuredData/Form/ConnectedField/index.tsx +3 -2
- package/src/modules/StructuredData/Form/index.tsx +22 -17
- package/src/modules/StructuredData/StructuredDataList/hooks.tsx +30 -20
- package/src/modules/StructuredData/StructuredDataList/index.tsx +24 -14
- package/src/types/index.tsx +8 -7
|
@@ -78,7 +78,7 @@ const TextField = (props: ITextFieldProps): JSX.Element => {
|
|
|
78
78
|
const inputValue = !autoComplete ? state : value || "";
|
|
79
79
|
|
|
80
80
|
return (
|
|
81
|
-
<S.FieldWrapper data-testid="
|
|
81
|
+
<S.FieldWrapper data-testid="text-field-container" error={error} className={className}>
|
|
82
82
|
{prefix && <Prefix />}
|
|
83
83
|
<S.Input
|
|
84
84
|
data-testid="inputComponent"
|
|
@@ -104,12 +104,7 @@ const TextField = (props: ITextFieldProps): JSX.Element => {
|
|
|
104
104
|
)}
|
|
105
105
|
{hasButton && (
|
|
106
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
|
-
/>
|
|
107
|
+
<IconAction icon={icon || ""} onClick={onClickIcon} disabled={disabled} size="s" />
|
|
113
108
|
</S.IconWrapper>
|
|
114
109
|
)}
|
|
115
110
|
</S.FieldWrapper>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import React, { memo, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { isNumber } from "@ax/helpers";
|
|
3
|
+
import { validateTimeAndCursor } from "./utils";
|
|
4
|
+
|
|
5
|
+
import * as S from "./style";
|
|
6
|
+
|
|
7
|
+
const HourInput = (props: IProps) => {
|
|
8
|
+
const { value, onChange, disabled } = props;
|
|
9
|
+
|
|
10
|
+
const [cursorPosition, setCursorPosition] = useState(0);
|
|
11
|
+
const [count, setCount] = useState(0);
|
|
12
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
inputRef.current?.setSelectionRange(cursorPosition, cursorPosition);
|
|
16
|
+
}, [count, cursorPosition]);
|
|
17
|
+
|
|
18
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
19
|
+
const oldValue = value;
|
|
20
|
+
const inputEl = e.target;
|
|
21
|
+
const inputValue = inputEl.value;
|
|
22
|
+
const position = inputEl.selectionEnd || 0;
|
|
23
|
+
const isTyped = inputValue.length > oldValue.length;
|
|
24
|
+
const cursorCharacter = inputValue[position - 1];
|
|
25
|
+
const addedCharacter = isTyped ? cursorCharacter : null;
|
|
26
|
+
const removedCharacter = isTyped ? null : oldValue[position];
|
|
27
|
+
const replacedSingleCharacter = inputValue.length === oldValue.length ? oldValue[position - 1] : null;
|
|
28
|
+
const colon = ":";
|
|
29
|
+
|
|
30
|
+
let newValue = oldValue;
|
|
31
|
+
let newPosition = position;
|
|
32
|
+
|
|
33
|
+
if (addedCharacter !== null) {
|
|
34
|
+
if (position > 5) {
|
|
35
|
+
newPosition = 5;
|
|
36
|
+
} else if (position === 3 && addedCharacter === colon) {
|
|
37
|
+
newValue = `${inputValue.slice(0, position - 1)}${colon}${inputValue.slice(position + 1)}`;
|
|
38
|
+
} else if (position === 3 && isNumber(addedCharacter)) {
|
|
39
|
+
newValue = `${inputValue.slice(0, position - 1)}${colon}${addedCharacter}${inputValue.slice(position + 2)}`;
|
|
40
|
+
newPosition = position + 1;
|
|
41
|
+
} else if (isNumber(addedCharacter)) {
|
|
42
|
+
// user typed a number
|
|
43
|
+
newValue = inputValue.slice(0, position - 1) + addedCharacter + inputValue.slice(position + 1);
|
|
44
|
+
if (position === 2) {
|
|
45
|
+
newPosition = position + 1;
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// if user typed NOT a number, then keep old value & position
|
|
49
|
+
newPosition = position - 1;
|
|
50
|
+
}
|
|
51
|
+
} else if (replacedSingleCharacter !== null) {
|
|
52
|
+
// user replaced only a single character
|
|
53
|
+
if (isNumber(cursorCharacter)) {
|
|
54
|
+
if (position - 1 === 2) {
|
|
55
|
+
newValue = `${inputValue.slice(0, position - 1)}${colon}${inputValue.slice(position)}`;
|
|
56
|
+
} else {
|
|
57
|
+
newValue = inputValue;
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
// user replaced a number on some non-number character
|
|
61
|
+
newValue = oldValue;
|
|
62
|
+
newPosition = position - 1;
|
|
63
|
+
}
|
|
64
|
+
} else if (typeof cursorCharacter !== "undefined" && cursorCharacter !== colon && !isNumber(cursorCharacter)) {
|
|
65
|
+
// set of characters replaced by non-number
|
|
66
|
+
newValue = oldValue;
|
|
67
|
+
newPosition = position - 1;
|
|
68
|
+
} else if (removedCharacter !== null) {
|
|
69
|
+
if (position === 2 && removedCharacter === colon) {
|
|
70
|
+
newValue = `${inputValue.slice(0, position - 1)}0${colon}${inputValue.slice(position)}`;
|
|
71
|
+
newPosition = position - 1;
|
|
72
|
+
} else {
|
|
73
|
+
// user removed a number
|
|
74
|
+
newValue = `${inputValue.slice(0, position)}0${inputValue.slice(position)}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const [validatedTime, validatedCursorPosition] = validateTimeAndCursor(newValue, oldValue, newPosition);
|
|
79
|
+
|
|
80
|
+
setCursorPosition(validatedCursorPosition);
|
|
81
|
+
setCount(count + 1);
|
|
82
|
+
onChange(validatedTime);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<S.InputField
|
|
87
|
+
type="text"
|
|
88
|
+
value={value}
|
|
89
|
+
onChange={handleChange}
|
|
90
|
+
ref={inputRef}
|
|
91
|
+
disabled={disabled}
|
|
92
|
+
data-testid="time-field-input"
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
interface IProps {
|
|
98
|
+
value: string;
|
|
99
|
+
onChange: (value: string) => void;
|
|
100
|
+
disabled?: boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default memo(HourInput);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const InputField = styled.input`
|
|
4
|
+
${(p) => p.theme.textStyle.fieldContent};
|
|
5
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
6
|
+
width: 50px;
|
|
7
|
+
border: none;
|
|
8
|
+
|
|
9
|
+
&:active,
|
|
10
|
+
&:focus {
|
|
11
|
+
outline: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
&:disabled {
|
|
15
|
+
color: ${(p) => p.theme.color.interactiveDisabled};
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export { InputField };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const formatTimeItem = (value?: string | number): string => {
|
|
2
|
+
return `${value || ""}00`.substr(0, 2);
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const validateTimeAndCursor = (value = "", defaultValue = "", cursorPosition = 0): [string, number] => {
|
|
6
|
+
const [oldH, oldM] = defaultValue.split(":");
|
|
7
|
+
|
|
8
|
+
let newCursorPosition = Number(cursorPosition);
|
|
9
|
+
let [newH, newM] = String(value).split(":");
|
|
10
|
+
|
|
11
|
+
newH = formatTimeItem(newH);
|
|
12
|
+
if (Number(newH[0]) > 1) {
|
|
13
|
+
newH = oldH;
|
|
14
|
+
newCursorPosition -= 1;
|
|
15
|
+
} else if (Number(newH[0]) === 1) {
|
|
16
|
+
if (Number(oldH[0]) === 1 && Number(newH[1]) > 2) {
|
|
17
|
+
newH = `1${oldH[1]}`;
|
|
18
|
+
newCursorPosition -= 2;
|
|
19
|
+
} else if (Number(newH[1]) > 2) {
|
|
20
|
+
newH = "12";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
newM = formatTimeItem(newM);
|
|
25
|
+
if (Number(newM[0]) > 5) {
|
|
26
|
+
newM = oldM;
|
|
27
|
+
newCursorPosition -= 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const validatedValue = `${newH}:${newM}`;
|
|
31
|
+
|
|
32
|
+
return [validatedValue, newCursorPosition];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { validateTimeAndCursor };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import React, { memo, useState } from "react";
|
|
2
|
+
import { Select, Icon } from "@ax/components";
|
|
3
|
+
import HourInput from "./HourInput";
|
|
4
|
+
|
|
5
|
+
import * as S from "./style";
|
|
6
|
+
|
|
7
|
+
const TimeField = (props: IProps) => {
|
|
8
|
+
const { value, error, onChange, disabled } = props;
|
|
9
|
+
|
|
10
|
+
const safeValue = !value || !value.length ? "00:00 am" : value;
|
|
11
|
+
const splitValue = safeValue.split(" ");
|
|
12
|
+
const initValue = { time: splitValue[0], meridian: splitValue[1] };
|
|
13
|
+
const [state, setState] = useState(initValue);
|
|
14
|
+
|
|
15
|
+
const handleChange = (newValue: string) => {
|
|
16
|
+
setState({ ...state, time: newValue });
|
|
17
|
+
onChange(`${newValue} ${state.meridian}`);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const handleSelectChange = (newValue: string) => {
|
|
21
|
+
setState({ ...state, meridian: newValue });
|
|
22
|
+
onChange(`${state.time} ${newValue}`);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const selectOptions = [
|
|
26
|
+
{ value: "am", label: "AM" },
|
|
27
|
+
{ value: "pm", label: "PM" },
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<S.FieldWrapper error={error} data-testid="time-field-wrapper" disabled={disabled}>
|
|
32
|
+
<HourInput value={state.time} onChange={handleChange} disabled={disabled} />
|
|
33
|
+
<S.SelectWrapper>
|
|
34
|
+
<Select
|
|
35
|
+
name="timeSelect"
|
|
36
|
+
value={state.meridian}
|
|
37
|
+
options={selectOptions}
|
|
38
|
+
onChange={handleSelectChange}
|
|
39
|
+
type="inline"
|
|
40
|
+
disabled={disabled}
|
|
41
|
+
/>
|
|
42
|
+
</S.SelectWrapper>
|
|
43
|
+
<S.IconWrapper>
|
|
44
|
+
<Icon name="scheduled" size="24" />
|
|
45
|
+
</S.IconWrapper>
|
|
46
|
+
</S.FieldWrapper>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
interface IProps {
|
|
51
|
+
value?: string;
|
|
52
|
+
error?: boolean;
|
|
53
|
+
onChange: (value: string) => void;
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default memo(TimeField);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const FieldWrapper = styled.div<{ error?: boolean; disabled?: boolean }>`
|
|
4
|
+
display: flex;
|
|
5
|
+
height: ${(p) => p.theme.spacing.l};
|
|
6
|
+
max-width: ${(p) => `calc(8 * ${p.theme.spacing.l})`};
|
|
7
|
+
min-width: ${(p) => `calc(5 * ${p.theme.spacing.l})`};
|
|
8
|
+
width: 100%;
|
|
9
|
+
border: 1px solid
|
|
10
|
+
${(p) => (p.error ? p.theme.color.error : p.disabled ? p.theme.color.interactiveDisabled : p.theme.color.uiLine)};
|
|
11
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
12
|
+
background: ${(p) => p.theme.color.uiBackground02};
|
|
13
|
+
padding: ${(p) => `0 ${p.theme.spacing.s}`};
|
|
14
|
+
align-items: center;
|
|
15
|
+
|
|
16
|
+
&:focus-within {
|
|
17
|
+
border-color: ${(p) => (p.error ? p.theme.color.error : p.theme.color.interactive01)};
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const IconWrapper = styled.div`
|
|
22
|
+
width: ${(p) => p.theme.spacing.m};
|
|
23
|
+
height: ${(p) => p.theme.spacing.m};
|
|
24
|
+
margin-left: auto;
|
|
25
|
+
svg {
|
|
26
|
+
path {
|
|
27
|
+
fill: ${(p) => p.theme.color.interactive01};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const SelectWrapper = styled.div`
|
|
33
|
+
padding-top: 4px;
|
|
34
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
export { FieldWrapper, IconWrapper, SelectWrapper };
|
|
@@ -29,6 +29,7 @@ import SliderField from "./SliderField";
|
|
|
29
29
|
import TagField from "./TagField";
|
|
30
30
|
import TextArea from "./TextArea";
|
|
31
31
|
import TextField from "./TextField";
|
|
32
|
+
import TimeField from "./TimeField";
|
|
32
33
|
import ToggleField from "./ToggleField";
|
|
33
34
|
import UniqueCheck from "./UniqueCheck";
|
|
34
35
|
import UrlField from "./UrlField";
|
|
@@ -68,6 +69,7 @@ export {
|
|
|
68
69
|
TagField,
|
|
69
70
|
TextArea,
|
|
70
71
|
TextField,
|
|
72
|
+
TimeField,
|
|
71
73
|
ToggleField,
|
|
72
74
|
UniqueCheck,
|
|
73
75
|
UrlField,
|
|
@@ -80,7 +80,7 @@ const FieldsBehavior = (props: any): JSX.Element => {
|
|
|
80
80
|
|
|
81
81
|
return (
|
|
82
82
|
<S.Wrapper className={wrapperClass} showTitle={showTitle} id={objKey}>
|
|
83
|
-
<S.Content error={errorField} data-testid="
|
|
83
|
+
<S.Content error={errorField} data-testid="fields-behavior-wrapper">
|
|
84
84
|
<Field
|
|
85
85
|
{...props}
|
|
86
86
|
showAdvanced={showAdvanced}
|
|
@@ -64,11 +64,11 @@ const FloatingMenu = (props: IProps) => {
|
|
|
64
64
|
onMouseLeave={handleMouseLeave}
|
|
65
65
|
data-testid="floating-menu"
|
|
66
66
|
>
|
|
67
|
-
<S.ButtonWrapper ref={button}>
|
|
67
|
+
<S.ButtonWrapper ref={button} data-testid="floating-menu-button">
|
|
68
68
|
<Button />
|
|
69
69
|
</S.ButtonWrapper>
|
|
70
70
|
{isOpen && (
|
|
71
|
-
<S.MenuWrapper isInAppBar={isInAppBar} ref={menuOptions} position={position} offset={offset}>
|
|
71
|
+
<S.MenuWrapper isInAppBar={isInAppBar} ref={menuOptions} position={position} offset={offset} data-testid="floating-menu-wrapper">
|
|
72
72
|
<S.Menu>{children}</S.Menu>
|
|
73
73
|
</S.MenuWrapper>
|
|
74
74
|
)}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { FloatingMenu, Icon, ListTitle, ListItem } from "@ax/components";
|
|
4
|
+
|
|
5
|
+
import { areEquals } from "@ax/helpers";
|
|
6
|
+
|
|
7
|
+
import * as S from "./style";
|
|
8
|
+
|
|
9
|
+
const Type = ({ filterItems }: ITypeProps): JSX.Element => {
|
|
10
|
+
const initialState = ["all"];
|
|
11
|
+
const [selectedValue, setSelectedValue] = useState(initialState);
|
|
12
|
+
|
|
13
|
+
const setQuery = (selection: any) => {
|
|
14
|
+
if (!selection.length) {
|
|
15
|
+
selection = initialState;
|
|
16
|
+
}
|
|
17
|
+
setSelectedValue([selection]);
|
|
18
|
+
const pointer = "format";
|
|
19
|
+
filterItems(pointer, selection);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const isActive = !areEquals(selectedValue, initialState);
|
|
23
|
+
|
|
24
|
+
const Header = () => (
|
|
25
|
+
<S.Type isActive={isActive}>
|
|
26
|
+
Media type
|
|
27
|
+
<S.IconsWrapper>
|
|
28
|
+
{isActive && <Icon name="Filter" size="16" />}
|
|
29
|
+
<S.InteractiveArrow>
|
|
30
|
+
<Icon name="DownArrow" size="16" />
|
|
31
|
+
</S.InteractiveArrow>
|
|
32
|
+
</S.IconsWrapper>
|
|
33
|
+
</S.Type>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<FloatingMenu Button={Header} position="center" closeOnSelect={true}>
|
|
38
|
+
<ListTitle>Filter by type</ListTitle>
|
|
39
|
+
<ListItem isSelected={selectedValue.includes("all")} onClick={() => setQuery("all")}>All</ListItem>
|
|
40
|
+
<ListItem isSelected={selectedValue.includes("bitmap")} onClick={() => setQuery("bitmap")}>Image</ListItem>
|
|
41
|
+
<ListItem isSelected={selectedValue.includes("vectorial")} onClick={() => setQuery("vectorial")}>Icons</ListItem>
|
|
42
|
+
</FloatingMenu>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
interface ITypeProps {
|
|
47
|
+
filterItems(pointer: string, filter: string): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default Type;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
import { Header } from "@ax/components/TableList/style";
|
|
4
|
+
|
|
5
|
+
const Type = styled((props) => <Header {...props} />)<{ isActive: boolean }>`
|
|
6
|
+
width: 90px;
|
|
7
|
+
white-space: nowrap;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
flex-wrap: nowrap;
|
|
10
|
+
align-items: center;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
&:hover {
|
|
13
|
+
color: ${(p) => p.theme.color.interactive01};
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const IconsWrapper = styled.div`
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
svg {
|
|
22
|
+
margin-left: 4px;
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const InteractiveArrow = styled.div`
|
|
27
|
+
display: flex;
|
|
28
|
+
svg {
|
|
29
|
+
path {
|
|
30
|
+
fill: ${(p) => p.theme.color.interactive01};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const ChecksWrapper = styled.div`
|
|
36
|
+
padding: ${(p) => p.theme.spacing.xs} ${(p) => p.theme.spacing.s};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
export { Type, IconsWrapper, InteractiveArrow, ChecksWrapper };
|
|
@@ -71,7 +71,8 @@ const GalleryDetailPanel = (props: IProps) => {
|
|
|
71
71
|
|
|
72
72
|
const handleSetAsGlobal = async () => {
|
|
73
73
|
const saveAsGlobal = !isGlobalTab && addToGlobal.isChecked && imageSelected?.file;
|
|
74
|
-
const image =
|
|
74
|
+
const image =
|
|
75
|
+
saveAsGlobal && imageSelected && imageSelected.file && (await uploadImage(imageSelected.file, "global"));
|
|
75
76
|
if (image && image.id) await updateImage(image.id, imageForm);
|
|
76
77
|
setAddToGlobal({ value: "addToGlobal", isChecked: false });
|
|
77
78
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import styled from "styled-components";
|
|
2
3
|
import { Button } from "@ax/components";
|
|
3
4
|
|
|
@@ -163,9 +164,8 @@ export const FilesInput = styled.input<{ ref: any }>`
|
|
|
163
164
|
display: none;
|
|
164
165
|
`;
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}))<{ ref: any }>`
|
|
167
|
+
const _Button: any = React.forwardRef((props: any, ref?: React.Ref<HTMLDivElement>) => <Button {...props} />);
|
|
168
|
+
export const FilesButton = styled(_Button)`
|
|
169
169
|
margin-top: ${(p) => p.theme.spacing.xs};
|
|
170
170
|
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
171
171
|
`;
|
|
@@ -21,13 +21,14 @@ const useSortedListStatus = () => {
|
|
|
21
21
|
const useFilterQuery = () => {
|
|
22
22
|
const initialQueryValues = {
|
|
23
23
|
orientation: "",
|
|
24
|
-
order: ""
|
|
24
|
+
order: "",
|
|
25
|
+
format: ""
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
const [query, setQuery] = useState(initialQueryValues);
|
|
28
29
|
|
|
29
30
|
const setFilterQuery = (filterValues: any) => {
|
|
30
|
-
const { orientation, order } = filterValues;
|
|
31
|
+
const { orientation, order, format } = filterValues;
|
|
31
32
|
let filterQuery = "";
|
|
32
33
|
|
|
33
34
|
const currentQuery = (pointer: string, values: string) => {
|
|
@@ -44,15 +45,20 @@ const useFilterQuery = () => {
|
|
|
44
45
|
filterQuery = currentQuery("order", order);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
if (format) {
|
|
49
|
+
filterQuery = currentQuery("format", format);
|
|
50
|
+
}
|
|
51
|
+
|
|
47
52
|
return filterQuery;
|
|
48
53
|
};
|
|
49
54
|
|
|
50
55
|
const setFiltersSelection = (pointer: string, filter: string, isAscendent?: boolean) => {
|
|
51
|
-
const { orientation, order } = query;
|
|
56
|
+
const { orientation, order, format } = query;
|
|
52
57
|
const orderMethod = isAscendent ? "asc" : "desc";
|
|
53
58
|
const filterValues = {
|
|
54
59
|
orientation: pointer === "orientation" ? filter : orientation,
|
|
55
|
-
order: pointer === "order" ? `${filter}-${orderMethod}` : order
|
|
60
|
+
order: pointer === "order" ? `${filter}-${orderMethod}` : order,
|
|
61
|
+
format: pointer === "format" ? filter : format,
|
|
56
62
|
};
|
|
57
63
|
|
|
58
64
|
setQuery(filterValues);
|
|
@@ -8,6 +8,7 @@ import { Icon, Loader, Tabs, SearchField, EmptyState, ErrorToast, Notification }
|
|
|
8
8
|
|
|
9
9
|
import Orientation from "./GalleryFilters/Orientation";
|
|
10
10
|
import SortBy from "./GalleryFilters/SortBy";
|
|
11
|
+
import Type from "./GalleryFilters/Type";
|
|
11
12
|
import GalleryPanel from "./GalleryPanel";
|
|
12
13
|
import * as S from "./style";
|
|
13
14
|
import { useFilterQuery, useSortedListStatus } from "./hooks";
|
|
@@ -136,6 +137,7 @@ const Gallery = (props: IProps): JSX.Element => {
|
|
|
136
137
|
)}
|
|
137
138
|
<S.Filters>
|
|
138
139
|
<Orientation filterItems={filterItems} />
|
|
140
|
+
<Type filterItems={filterItems} />
|
|
139
141
|
<SortBy sortItems={sortItems} sortedState={sortedListStatus} />
|
|
140
142
|
</S.Filters>
|
|
141
143
|
</S.Header>
|
|
@@ -22,7 +22,7 @@ const Icon = (props: IProps) => {
|
|
|
22
22
|
const Svg = getImage(name);
|
|
23
23
|
|
|
24
24
|
if (Svg) {
|
|
25
|
-
return <Svg data-testid="
|
|
25
|
+
return <Svg data-testid="icon-component" height={size} width={size} viewBox="0 0 24 24" fill={fill} />;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return null;
|
|
@@ -7,7 +7,7 @@ const ListItem = (props: ListItemProps): JSX.Element => {
|
|
|
7
7
|
const { isSelected, children, onClick } = props;
|
|
8
8
|
|
|
9
9
|
return (
|
|
10
|
-
<S.StyledListItem isSelected={isSelected} onClick={onClick}>
|
|
10
|
+
<S.StyledListItem isSelected={isSelected} onClick={onClick} data-testid="list-item">
|
|
11
11
|
{children}
|
|
12
12
|
{isSelected && <Icon name="Done" size="16" />}
|
|
13
13
|
</S.StyledListItem>
|
|
@@ -36,7 +36,7 @@ const Pagination = (props: IProps) => {
|
|
|
36
36
|
const CurrentPage = size === "S" ? currPage : <S.Input type="text" value={currPage} onChange={_handleChange} />;
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
|
-
<S.Wrapper>
|
|
39
|
+
<S.Wrapper data-testid="pagination-wrapper">
|
|
40
40
|
<S.Literal size={size}>
|
|
41
41
|
Page {CurrentPage} of {lastPage}
|
|
42
42
|
</S.Literal>
|
|
@@ -14,7 +14,9 @@ const SideModalOption = (props: IProps) => {
|
|
|
14
14
|
|
|
15
15
|
const isNavigationDefault = ["header", "footer"].includes(option.type);
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const navigationThumbnail = isNavigationDefault &&
|
|
18
|
+
option.thumbnail && { alt: option.title, src: option.thumbnail.url };
|
|
19
|
+
const thumbnailProps = navigationThumbnail || getThumbnailData(option, theme);
|
|
18
20
|
|
|
19
21
|
const optionParam = option.component || option;
|
|
20
22
|
const label = isNavigationDefault ? option.title : getDisplayName(optionParam);
|
|
@@ -25,7 +27,7 @@ const SideModalOption = (props: IProps) => {
|
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
return (
|
|
28
|
-
<S.Item onClick={setOption}>
|
|
30
|
+
<S.Item onClick={setOption} data-testid="side-modal-option">
|
|
29
31
|
<S.Thumbnail {...thumbnailProps} />
|
|
30
32
|
{label}
|
|
31
33
|
</S.Item>
|
|
@@ -137,7 +137,7 @@ const SideModal = (props: ISideModalProps): JSX.Element | null => {
|
|
|
137
137
|
|
|
138
138
|
return isOpen
|
|
139
139
|
? createPortal(
|
|
140
|
-
<S.Wrapper ref={node} optionsType={optionsType}>
|
|
140
|
+
<S.Wrapper ref={node} optionsType={optionsType} data-testid="side-modal">
|
|
141
141
|
<S.Header>
|
|
142
142
|
<S.Title>{optionsType}</S.Title>
|
|
143
143
|
{showSearch && optionsType !== "components" && (
|
|
@@ -75,7 +75,7 @@ const CategoryFilter = (props: ICategoryFilterProps): JSX.Element => {
|
|
|
75
75
|
|
|
76
76
|
return (
|
|
77
77
|
<FloatingMenu Button={Header} position="left" closeOnSelect={false} isCheckGroup={true}>
|
|
78
|
-
<ListTitle>Filter by Category</ListTitle>
|
|
78
|
+
<ListTitle data-testid="category-filter-title">Filter by Category</ListTitle>
|
|
79
79
|
<S.ChecksWrapper>
|
|
80
80
|
<CheckGroup options={options} value={selectedValue} onChange={setQuery} selectAllOption={selectAllOption} />
|
|
81
81
|
</S.ChecksWrapper>
|
|
@@ -83,7 +83,7 @@ const CategoryFilter = (props: ICategoryFilterProps): JSX.Element => {
|
|
|
83
83
|
);
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
-
interface ICategoryFilterProps {
|
|
86
|
+
export interface ICategoryFilterProps {
|
|
87
87
|
filterItems(pointer: string, filter: string): void;
|
|
88
88
|
value: string;
|
|
89
89
|
structuredData: any;
|
|
@@ -19,18 +19,9 @@ const IconsWrapper = styled.div`
|
|
|
19
19
|
}
|
|
20
20
|
`;
|
|
21
21
|
|
|
22
|
-
const InteractiveArrow = styled.div`
|
|
23
|
-
display: flex;
|
|
24
|
-
svg {
|
|
25
|
-
path {
|
|
26
|
-
fill: ${(p) => p.theme.color.interactive01};
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
`;
|
|
30
|
-
|
|
31
22
|
const ChecksWrapper = styled.div`
|
|
32
23
|
padding: ${(p) => p.theme.spacing.xs} ${(p) => p.theme.spacing.s};
|
|
33
24
|
overflow-y: auto;
|
|
34
25
|
`;
|
|
35
26
|
|
|
36
|
-
export { HeaderWrapper, IconsWrapper,
|
|
27
|
+
export { HeaderWrapper, IconsWrapper, ChecksWrapper };
|
|
@@ -6,7 +6,6 @@ import * as S from "./style";
|
|
|
6
6
|
|
|
7
7
|
const CustomizeFilters = (props: ICustomizeFiltersProps): JSX.Element => {
|
|
8
8
|
const { columns, setColumns, value } = props;
|
|
9
|
-
|
|
10
9
|
const options = Object.keys(columns).map((col: string) => {
|
|
11
10
|
const disabled = value.length >= 5 && !value.includes(col);
|
|
12
11
|
return { name: col, title: columns[col].title, value: col, disabled };
|
|
@@ -31,7 +30,7 @@ const CustomizeFilters = (props: ICustomizeFiltersProps): JSX.Element => {
|
|
|
31
30
|
);
|
|
32
31
|
|
|
33
32
|
return (
|
|
34
|
-
<S.Wrapper>
|
|
33
|
+
<S.Wrapper data-testid="customize-filters-wrapper">
|
|
35
34
|
<FloatingMenu Button={Button} position="right" closeOnSelect={false}>
|
|
36
35
|
<ListTitle>Customize filters</ListTitle>
|
|
37
36
|
<S.Note>You can select up to five options</S.Note>
|
|
@@ -43,7 +42,7 @@ const CustomizeFilters = (props: ICustomizeFiltersProps): JSX.Element => {
|
|
|
43
42
|
);
|
|
44
43
|
};
|
|
45
44
|
|
|
46
|
-
interface ICustomizeFiltersProps {
|
|
45
|
+
export interface ICustomizeFiltersProps {
|
|
47
46
|
setColumns(newValue: any): void;
|
|
48
47
|
columns: Record<string, IColumn>;
|
|
49
48
|
value: string[];
|