@griddo/ax 11.11.7 → 11.11.8-rc.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/jest/componentsMock.js +7 -5
- package/package.json +2 -2
- package/src/__tests__/components/Browser/Browser.test.tsx +438 -87
- package/src/__tests__/components/Browser/Browser.utils.test.ts +55 -0
- package/src/__tests__/components/ConfigPanel/ConfigPanel.test.tsx +1 -3
- package/src/__tests__/components/Fields/Button/Button.test.tsx +29 -27
- package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/ErrorItem.test.tsx +158 -0
- package/src/__tests__/components/HeadingsPreviewModal/ErrorsBanner/ErrorsBanner.test.tsx +90 -0
- package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.test.tsx +178 -0
- package/src/__tests__/components/HeadingsPreviewModal/HeadingsPreviewModal.utils.test.tsx +150 -0
- package/src/__tests__/components/KeywordsPreviewModal/KeywordItem/KeywordItem.test.tsx +91 -0
- package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.test.tsx +122 -0
- package/src/__tests__/components/KeywordsPreviewModal/KeywordsPreviewModal.utils.test.ts +15 -0
- package/src/__tests__/components/KeywordsPreviewModal/atoms.test.tsx +101 -0
- package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +1 -1
- package/src/__tests__/modules/FramePreview/FramePreview.test.tsx +318 -0
- package/src/__tests__/modules/FramePreview/FramePreview.utils.test.ts +242 -0
- package/src/__tests__/modules/FramePreview/HeadingsOverlay/HeadingsOverlay.test.tsx +185 -0
- package/src/components/Browser/index.tsx +294 -144
- package/src/components/Browser/style.tsx +75 -6
- package/src/components/Browser/utils.tsx +13 -0
- package/src/components/BrowserContent/index.tsx +2 -2
- package/src/components/Button/index.tsx +2 -1
- package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +2 -4
- package/src/components/Fields/AsyncSelect/style.tsx +13 -0
- package/src/components/Fields/FieldGroup/index.tsx +5 -2
- package/src/components/Fields/FieldGroup/style.tsx +32 -7
- package/src/components/Fields/HeadingField/index.tsx +2 -2
- package/src/components/Fields/HiddenField/style.tsx +1 -1
- package/src/components/Fields/NumberField/index.tsx +15 -16
- package/src/components/Fields/NumberField/style.tsx +2 -0
- package/src/components/Fields/ReferenceField/index.tsx +1 -1
- package/src/components/Fields/SEOPreview/index.tsx +36 -0
- package/src/components/Fields/SEOPreview/style.tsx +24 -0
- package/src/components/Fields/Select/index.tsx +5 -1
- package/src/components/Fields/Select/style.tsx +56 -0
- package/src/components/Fields/SummaryButton/index.tsx +18 -9
- package/src/components/Fields/SummaryButton/style.tsx +1 -2
- package/src/components/Fields/TagsField/index.tsx +8 -9
- package/src/components/Fields/UrlField/index.tsx +26 -27
- package/src/components/Fields/index.tsx +2 -0
- package/src/components/FloatingNote/index.tsx +35 -0
- package/src/components/FloatingNote/style.tsx +26 -0
- package/src/components/FloatingPanel/index.tsx +5 -2
- package/src/components/FloatingPanel/style.tsx +2 -1
- package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/index.tsx +85 -0
- package/src/components/HeadingsPreviewModal/ErrorsBanner/ErrorItem/style.tsx +80 -0
- package/src/components/HeadingsPreviewModal/ErrorsBanner/index.tsx +57 -0
- package/src/components/HeadingsPreviewModal/ErrorsBanner/style.tsx +82 -0
- package/src/components/HeadingsPreviewModal/HeadingItem/index.tsx +71 -0
- package/src/components/HeadingsPreviewModal/HeadingItem/style.tsx +77 -0
- package/src/components/HeadingsPreviewModal/index.tsx +146 -0
- package/src/components/HeadingsPreviewModal/style.tsx +82 -0
- package/src/components/HeadingsPreviewModal/utils.tsx +257 -0
- package/src/components/IconAction/index.tsx +1 -1
- package/src/components/KeywordsPreviewModal/KeywordItem/index.tsx +46 -0
- package/src/components/KeywordsPreviewModal/KeywordItem/style.tsx +64 -0
- package/src/components/KeywordsPreviewModal/atoms.tsx +96 -0
- package/src/components/KeywordsPreviewModal/index.tsx +99 -0
- package/src/components/KeywordsPreviewModal/style.tsx +87 -0
- package/src/components/KeywordsPreviewModal/utils.tsx +22 -0
- package/src/components/MainWrapper/AppBar/index.tsx +8 -1
- package/src/components/MainWrapper/index.tsx +7 -1
- package/src/components/Notification/index.tsx +2 -2
- package/src/components/OcassionalToast/index.tsx +8 -1
- package/src/components/OcassionalToast/style.tsx +15 -1
- package/src/components/PageFinder/index.tsx +1 -1
- package/src/components/ResizePanel/index.tsx +4 -3
- package/src/components/ResizePanel/style.tsx +1 -1
- package/src/components/SearchField/style.tsx +2 -2
- package/src/components/SideModal/index.tsx +2 -1
- package/src/components/Tabs/index.tsx +13 -4
- package/src/components/Tabs/style.tsx +7 -8
- package/src/components/Toast/index.tsx +4 -2
- package/src/components/Tooltip/index.tsx +4 -3
- package/src/components/index.tsx +8 -2
- package/src/forms/fields.tsx +70 -68
- package/src/hooks/forms.tsx +22 -1
- package/src/hooks/index.tsx +13 -3
- package/src/hooks/modals.tsx +103 -15
- package/src/hooks/users.tsx +25 -8
- package/src/modules/Forms/atoms.tsx +2 -2
- package/src/modules/FramePreview/HeadingsOverlay/index.tsx +113 -0
- package/src/modules/FramePreview/HeadingsOverlay/style.tsx +24 -0
- package/src/modules/FramePreview/index.tsx +55 -16
- package/src/modules/FramePreview/style.tsx +34 -2
- package/src/modules/FramePreview/utils.tsx +140 -0
- package/src/modules/GlobalEditor/Editor/index.tsx +37 -3
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +19 -2
- package/src/modules/GlobalEditor/Preview/index.tsx +0 -2
- package/src/modules/GlobalEditor/Preview/style.tsx +1 -1
- package/src/modules/GlobalEditor/index.tsx +119 -57
- package/src/modules/PageEditor/Editor/index.tsx +33 -2
- package/src/modules/PageEditor/PageBrowser/index.tsx +20 -2
- package/src/modules/PageEditor/Preview/index.tsx +0 -2
- package/src/modules/PageEditor/Preview/style.tsx +1 -1
- package/src/modules/PageEditor/atoms.tsx +1 -1
- package/src/modules/PageEditor/index.tsx +130 -66
- package/src/modules/PublicPreview/index.tsx +8 -5
- package/src/schemas/pages/GlobalPage.ts +87 -70
- package/src/schemas/pages/Page.ts +87 -70
- package/src/types/index.tsx +12 -0
- package/src/components/PageInfoBanner/index.tsx +0 -38
- package/src/components/PageInfoBanner/styles.tsx +0 -40
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import type { IModal } from "@ax/types";
|
|
4
|
+
import { Modal, FieldsBehavior } from "@ax/components";
|
|
5
|
+
|
|
6
|
+
import * as S from "./style";
|
|
7
|
+
|
|
8
|
+
const AddKeywordsModal = (props: IAddKeywordsModal) => {
|
|
9
|
+
const { isOpen, toggleModal, addNewKeyword } = props;
|
|
10
|
+
|
|
11
|
+
const [value, setValue] = useState<string[]>([]);
|
|
12
|
+
|
|
13
|
+
const handleChange = (newValue: string[]) => setValue(newValue);
|
|
14
|
+
|
|
15
|
+
const handleClick = () => {
|
|
16
|
+
addNewKeyword(value);
|
|
17
|
+
setValue([]);
|
|
18
|
+
toggleModal();
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const handleClose = () => {
|
|
22
|
+
isOpen && toggleModal();
|
|
23
|
+
setValue([]);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const mainModalAction = {
|
|
27
|
+
title: "Create keyword",
|
|
28
|
+
onClick: handleClick,
|
|
29
|
+
disabled: !value.length,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const secondaryModalAction = { title: "Cancel", onClick: handleClose };
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Modal
|
|
36
|
+
isOpen={isOpen}
|
|
37
|
+
hide={handleClose}
|
|
38
|
+
title="New keyword"
|
|
39
|
+
secondaryAction={secondaryModalAction}
|
|
40
|
+
mainAction={mainModalAction}
|
|
41
|
+
size="S"
|
|
42
|
+
height={282}
|
|
43
|
+
>
|
|
44
|
+
<S.ModalContent>
|
|
45
|
+
<FieldsBehavior
|
|
46
|
+
fieldType="TagsField"
|
|
47
|
+
name="keywords"
|
|
48
|
+
title="Keywords"
|
|
49
|
+
value={value}
|
|
50
|
+
onChange={handleChange}
|
|
51
|
+
placeholder="Type a keyword..."
|
|
52
|
+
helptext="Type a tag and press enter to create it"
|
|
53
|
+
/>
|
|
54
|
+
</S.ModalContent>
|
|
55
|
+
</Modal>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface IAddKeywordsModal extends IModal {
|
|
60
|
+
addNewKeyword: (value: string[]) => void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const DeleteKeywordsModal = (props: IDeleteKeywordsModal) => {
|
|
64
|
+
const { isOpen, toggleModal, deleteKeyword } = props;
|
|
65
|
+
|
|
66
|
+
const mainModalAction = {
|
|
67
|
+
title: "Delete keyword",
|
|
68
|
+
onClick: deleteKeyword,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const secondaryModalAction = { title: "Cancel", onClick: toggleModal };
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Modal
|
|
75
|
+
isOpen={isOpen}
|
|
76
|
+
hide={toggleModal}
|
|
77
|
+
title="Delete keyword"
|
|
78
|
+
secondaryAction={secondaryModalAction}
|
|
79
|
+
mainAction={mainModalAction}
|
|
80
|
+
size="S"
|
|
81
|
+
height={240}
|
|
82
|
+
>
|
|
83
|
+
<S.ModalContent>
|
|
84
|
+
You are about to <strong>delete a keyword that is currently in use.</strong>
|
|
85
|
+
<br />
|
|
86
|
+
Please make sure you want to delete it.
|
|
87
|
+
</S.ModalContent>
|
|
88
|
+
</Modal>
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
interface IDeleteKeywordsModal extends IModal {
|
|
93
|
+
deleteKeyword: () => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { AddKeywordsModal, DeleteKeywordsModal };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { FloatingPanel, Icon, Toast } from "@ax/components";
|
|
4
|
+
import { useModal, useToast } from "@ax/hooks";
|
|
5
|
+
|
|
6
|
+
import { AddKeywordsModal } from "./atoms";
|
|
7
|
+
import KeywordItem from "./KeywordItem";
|
|
8
|
+
import { countKeywords } from "./utils";
|
|
9
|
+
|
|
10
|
+
import * as S from "./style";
|
|
11
|
+
|
|
12
|
+
const KeywordsPreviewModal = (props: IKeywordsPreviewProps) => {
|
|
13
|
+
const { isOpen, browserRef, keywords, keywordsFilter, toggleModal, setKeywordsFilter, addKeywords, deleteKeyword } =
|
|
14
|
+
props;
|
|
15
|
+
const [keywordCounts, setKeywordCounts] = useState<Record<string, number>>({});
|
|
16
|
+
const [deletedKeyword, setDeletedKeyword] = useState<string | null>(null);
|
|
17
|
+
const { isOpen: isAddOpen, toggleModal: toggleAddModal } = useModal();
|
|
18
|
+
const { isVisible, toggleToast, setIsVisible, state: toastState } = useToast();
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (isOpen && browserRef.current) {
|
|
22
|
+
const keywordCount = countKeywords(browserRef.current, keywords);
|
|
23
|
+
setKeywordCounts(keywordCount);
|
|
24
|
+
}
|
|
25
|
+
}, [isOpen, browserRef, keywords]);
|
|
26
|
+
|
|
27
|
+
const handleDeleteTag = () => setKeywordsFilter([]);
|
|
28
|
+
|
|
29
|
+
const handleAddTag = (tag: string) => () =>
|
|
30
|
+
keywordsFilter.includes(tag) ? setKeywordsFilter([]) : setKeywordsFilter([tag]);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (deletedKeyword && !keywords.includes(deletedKeyword)) {
|
|
34
|
+
toggleToast("1 Keyword deleted");
|
|
35
|
+
setDeletedKeyword(null);
|
|
36
|
+
}
|
|
37
|
+
}, [keywords, deletedKeyword, toggleToast]);
|
|
38
|
+
|
|
39
|
+
const handleDeleteKeyword = (value: string) => {
|
|
40
|
+
setDeletedKeyword(value);
|
|
41
|
+
deleteKeyword(value);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<S.Wrapper>
|
|
46
|
+
<FloatingPanel title="Keywords" toggleModal={toggleModal} closeOnOutsideClick={false} isOpen={isOpen} width={358}>
|
|
47
|
+
{isOpen && (
|
|
48
|
+
<S.KeywordsWrapper>
|
|
49
|
+
{keywordsFilter.length > 0 && (
|
|
50
|
+
<S.FilterWrapper>
|
|
51
|
+
<S.FilterText>Show keyword:</S.FilterText>
|
|
52
|
+
<S.TagList>
|
|
53
|
+
{keywordsFilter.map((tag: string) => {
|
|
54
|
+
return <S.StyledTag key={tag} text={tag} color="#FFFFFF" onDeleteAction={handleDeleteTag} />;
|
|
55
|
+
})}
|
|
56
|
+
</S.TagList>
|
|
57
|
+
</S.FilterWrapper>
|
|
58
|
+
)}
|
|
59
|
+
<S.KeywordsListWrapper>
|
|
60
|
+
{keywords.length === 0 && <S.StyledSummaryButton />}
|
|
61
|
+
{Object.keys(keywordCounts).map((key, index) => {
|
|
62
|
+
const isSelected = keywordsFilter.includes(key);
|
|
63
|
+
return (
|
|
64
|
+
<KeywordItem
|
|
65
|
+
keyword={key}
|
|
66
|
+
count={keywordCounts[key]}
|
|
67
|
+
isSelected={isSelected}
|
|
68
|
+
onClick={handleAddTag(key)}
|
|
69
|
+
deleteKeyword={handleDeleteKeyword}
|
|
70
|
+
key={`${key}-${index}`}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
})}
|
|
74
|
+
<S.AddKeywordButton onClick={toggleAddModal}>
|
|
75
|
+
<Icon name="add" size="16" />
|
|
76
|
+
Add new keyword
|
|
77
|
+
</S.AddKeywordButton>
|
|
78
|
+
</S.KeywordsListWrapper>
|
|
79
|
+
</S.KeywordsWrapper>
|
|
80
|
+
)}
|
|
81
|
+
</FloatingPanel>
|
|
82
|
+
<AddKeywordsModal isOpen={isAddOpen} toggleModal={toggleAddModal} addNewKeyword={addKeywords} />
|
|
83
|
+
{isVisible && <Toast message={toastState} setIsVisible={setIsVisible} />}
|
|
84
|
+
</S.Wrapper>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
interface IKeywordsPreviewProps {
|
|
89
|
+
isOpen: boolean;
|
|
90
|
+
browserRef: React.RefObject<HTMLDivElement>;
|
|
91
|
+
toggleModal: () => void;
|
|
92
|
+
keywords: string[];
|
|
93
|
+
keywordsFilter: string[];
|
|
94
|
+
setKeywordsFilter: (value: string[]) => void;
|
|
95
|
+
addKeywords: (value: string[]) => void;
|
|
96
|
+
deleteKeyword: (value: string) => void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export default KeywordsPreviewModal;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
import SummaryButton from "../Fields/SummaryButton";
|
|
4
|
+
import Tag from "../Tag";
|
|
5
|
+
|
|
6
|
+
const Wrapper = styled.div``;
|
|
7
|
+
|
|
8
|
+
const KeywordsWrapper = styled.div`
|
|
9
|
+
padding: ${(p) => `${p.theme.spacing.m} ${p.theme.spacing.m} 80px ${p.theme.spacing.s}`};
|
|
10
|
+
overflow-y: auto;
|
|
11
|
+
height: 100%;
|
|
12
|
+
width: 100%;
|
|
13
|
+
position: relative;
|
|
14
|
+
|
|
15
|
+
::-webkit-scrollbar {
|
|
16
|
+
-webkit-appearance: none;
|
|
17
|
+
width: 4px;
|
|
18
|
+
height: 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
::-webkit-scrollbar-thumb {
|
|
22
|
+
border-radius: 4px;
|
|
23
|
+
background-color: ${(p) => p.theme.colors.iconNonActive};
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const KeywordsListWrapper = styled.div``;
|
|
28
|
+
|
|
29
|
+
const FilterWrapper = styled.div`
|
|
30
|
+
display: flex;
|
|
31
|
+
background-color: ${(p) => p.theme.color.uiBackground03};
|
|
32
|
+
width: 100%;
|
|
33
|
+
padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.xs}`};
|
|
34
|
+
align-items: center;
|
|
35
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
36
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const FilterText = styled.div`
|
|
40
|
+
${(p) => p.theme.textStyle.uiS};
|
|
41
|
+
color: ${(p) => p.theme.color.textHighEmphasis};
|
|
42
|
+
margin-right: ${(p) => p.theme.spacing.xs};
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
const StyledTag = styled(Tag)`
|
|
47
|
+
margin-right: ${(p) => p.theme.spacing.xs};
|
|
48
|
+
margin-bottom: 0;
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
const TagList = styled.div``;
|
|
52
|
+
|
|
53
|
+
const AddKeywordButton = styled.button`
|
|
54
|
+
display: flex;
|
|
55
|
+
${(p) => p.theme.textStyle.fieldLabel};
|
|
56
|
+
color: ${(p) => p.theme.colors.interactive01};
|
|
57
|
+
min-height: 40px;
|
|
58
|
+
width: 100%;
|
|
59
|
+
border: ${(p) => `1px dashed ${p.theme.colors.interactive01}`};
|
|
60
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
61
|
+
align-items: center;
|
|
62
|
+
justify-content: center;
|
|
63
|
+
svg {
|
|
64
|
+
margin-right: ${(p) => p.theme.spacing.xxs};
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const ModalContent = styled.div`
|
|
69
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const StyledSummaryButton = styled(SummaryButton)`
|
|
73
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
Wrapper,
|
|
78
|
+
KeywordsWrapper,
|
|
79
|
+
KeywordsListWrapper,
|
|
80
|
+
FilterWrapper,
|
|
81
|
+
FilterText,
|
|
82
|
+
StyledTag,
|
|
83
|
+
TagList,
|
|
84
|
+
AddKeywordButton,
|
|
85
|
+
ModalContent,
|
|
86
|
+
StyledSummaryButton,
|
|
87
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const countKeywords = (html: HTMLDivElement, keywords: string[]) => {
|
|
2
|
+
const frameObject = html.querySelector<HTMLIFrameElement>(".frame-content");
|
|
3
|
+
const frameContent = frameObject?.contentWindow?.document.getElementById("___griddo") as HTMLElement;
|
|
4
|
+
|
|
5
|
+
if (!frameContent) {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const htmlContent = frameContent.innerText.toLowerCase();
|
|
10
|
+
const keywordCounts: Record<string, number> = {};
|
|
11
|
+
|
|
12
|
+
keywords.forEach((keyword) => {
|
|
13
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
14
|
+
const regex = new RegExp(lowerKeyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
|
|
15
|
+
const matches = htmlContent.match(regex);
|
|
16
|
+
keywordCounts[keyword] = matches ? matches.length : 0;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return keywordCounts;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { countKeywords };
|
|
@@ -190,6 +190,7 @@ const AppBar = (props: IProps): JSX.Element => {
|
|
|
190
190
|
setSelectedTab={tabs.action}
|
|
191
191
|
isInAppBar={true}
|
|
192
192
|
inversed={inversed}
|
|
193
|
+
disabled={tabs.disabled}
|
|
193
194
|
/>
|
|
194
195
|
</S.TabsContent>
|
|
195
196
|
</S.WrapperTabs>
|
|
@@ -291,7 +292,13 @@ export interface IAppBarProps {
|
|
|
291
292
|
backLink?: boolean | string;
|
|
292
293
|
rightButton?: { label: string; disabled?: boolean; action: (e: any) => void };
|
|
293
294
|
rightLineButton?: { label: string; disabled?: boolean; action: (e: any) => void };
|
|
294
|
-
tabs?: {
|
|
295
|
+
tabs?: {
|
|
296
|
+
tabSet?: any;
|
|
297
|
+
icons?: { name: string; text: string }[];
|
|
298
|
+
selectedTab: string;
|
|
299
|
+
action: (e: any) => void;
|
|
300
|
+
disabled?: boolean;
|
|
301
|
+
};
|
|
295
302
|
downArrowMenu?: { displayed: boolean; options: any; button: any };
|
|
296
303
|
title: string;
|
|
297
304
|
subtitle?: string;
|
|
@@ -38,7 +38,13 @@ export interface IWrapperProps {
|
|
|
38
38
|
fixedAppBar?: boolean;
|
|
39
39
|
additionalClass?: string;
|
|
40
40
|
downArrowMenu?: { displayed: boolean; options: any; button: any };
|
|
41
|
-
tabs?: {
|
|
41
|
+
tabs?: {
|
|
42
|
+
tabSet?: any;
|
|
43
|
+
icons?: { name: string; text: string }[];
|
|
44
|
+
selectedTab: string;
|
|
45
|
+
action: (e: any) => void;
|
|
46
|
+
disabled?: boolean;
|
|
47
|
+
};
|
|
42
48
|
pageStatus?: string;
|
|
43
49
|
language?: { locale: string; id: number | null } | null;
|
|
44
50
|
availableLanguages?: ILanguage[];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState } from "react";
|
|
2
2
|
import { Icon } from "@ax/components";
|
|
3
3
|
import SubNotification from "./SubNotification";
|
|
4
4
|
|
|
@@ -45,7 +45,7 @@ const Notification = (props: INotificationProps): JSX.Element => {
|
|
|
45
45
|
const handleClick = () => (onClick ? onClick() : handleErrorClick());
|
|
46
46
|
|
|
47
47
|
const handleClose = () => {
|
|
48
|
-
resetError
|
|
48
|
+
resetError?.();
|
|
49
49
|
setIsVisible(false);
|
|
50
50
|
};
|
|
51
51
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createPortal } from "react-dom";
|
|
2
|
+
|
|
2
3
|
import { Icon } from "@ax/components";
|
|
3
4
|
|
|
4
5
|
import * as S from "./style";
|
|
5
6
|
|
|
6
7
|
const OcassionalToast = (props: IOcassionalToastProps): JSX.Element => {
|
|
7
|
-
const { message, icon = "alert" } = props;
|
|
8
|
+
const { message, icon = "alert", onDismiss } = props;
|
|
8
9
|
|
|
9
10
|
return createPortal(
|
|
10
11
|
<S.Wrapper data-testid="occasional-toast-wrapper">
|
|
@@ -12,6 +13,11 @@ const OcassionalToast = (props: IOcassionalToastProps): JSX.Element => {
|
|
|
12
13
|
<Icon name={icon} />
|
|
13
14
|
</S.IconWrapper>
|
|
14
15
|
<S.Text data-testid="occasional-toast-message">{message}</S.Text>
|
|
16
|
+
{onDismiss && (
|
|
17
|
+
<S.DismissButton type="button" onClick={onDismiss}>
|
|
18
|
+
<Icon name="close" size="16px" />
|
|
19
|
+
</S.DismissButton>
|
|
20
|
+
)}
|
|
15
21
|
</S.Wrapper>,
|
|
16
22
|
document.body,
|
|
17
23
|
);
|
|
@@ -20,6 +26,7 @@ const OcassionalToast = (props: IOcassionalToastProps): JSX.Element => {
|
|
|
20
26
|
export interface IOcassionalToastProps {
|
|
21
27
|
message: string | React.ReactNode;
|
|
22
28
|
icon?: string;
|
|
29
|
+
onDismiss?: () => void;
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
export default OcassionalToast;
|
|
@@ -37,4 +37,18 @@ const IconWrapper = styled.div`
|
|
|
37
37
|
}
|
|
38
38
|
`;
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
const DismissButton = styled.button`
|
|
41
|
+
background: none;
|
|
42
|
+
border: none;
|
|
43
|
+
svg {
|
|
44
|
+
path {
|
|
45
|
+
fill: ${(p) => p.theme.color.textHighEmphasisInverse};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
margin-left: ${(p) => p.theme.spacing.xs};
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
export { Wrapper, Text, IconWrapper, DismissButton };
|
|
@@ -120,7 +120,7 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
|
|
|
120
120
|
if (isReqOk(response.status)) {
|
|
121
121
|
setState((state) => ({ ...state, items: response.data.items, totalItems: response.data.totalItems }));
|
|
122
122
|
} else {
|
|
123
|
-
console.
|
|
123
|
+
console.error("Error en getAndSetItems");
|
|
124
124
|
}
|
|
125
125
|
setIsLoading(false);
|
|
126
126
|
};
|
|
@@ -4,10 +4,10 @@ import ResizeHandle from "./ResizeHandle";
|
|
|
4
4
|
|
|
5
5
|
import * as S from "./style";
|
|
6
6
|
|
|
7
|
-
const MIN_WIDTH =
|
|
7
|
+
const MIN_WIDTH = 368;
|
|
8
8
|
|
|
9
9
|
const ResizePanel = (props: IResizePanelProps): JSX.Element => {
|
|
10
|
-
const { leftPanel, rightPanel, fixed = true, full = false } = props;
|
|
10
|
+
const { leftPanel, rightPanel, fixed = true, full = false, disabled } = props;
|
|
11
11
|
|
|
12
12
|
const [rwidth, setRwidth] = useState(MIN_WIDTH);
|
|
13
13
|
const rightPanelRef = useRef<HTMLDivElement>(null);
|
|
@@ -44,7 +44,7 @@ const ResizePanel = (props: IResizePanelProps): JSX.Element => {
|
|
|
44
44
|
leftPanel
|
|
45
45
|
)}
|
|
46
46
|
</S.LeftPanel>
|
|
47
|
-
<ResizeHandle onMouseMove={resize} />
|
|
47
|
+
{!disabled && <ResizeHandle onMouseMove={resize} />}
|
|
48
48
|
<S.RightPanel ref={rightPanelRef} data-testid="right-panel" style={{ width: rwidth ? `${rwidth}px` : "auto" }}>
|
|
49
49
|
{rightPanel}
|
|
50
50
|
</S.RightPanel>
|
|
@@ -57,6 +57,7 @@ export interface IResizePanelProps {
|
|
|
57
57
|
rightPanel: JSX.Element | JSX.Element[];
|
|
58
58
|
fixed?: boolean;
|
|
59
59
|
full?: boolean;
|
|
60
|
+
disabled?: boolean;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
export default ResizePanel;
|
|
@@ -11,7 +11,7 @@ const RightPanel = styled.section`
|
|
|
11
11
|
position: relative;
|
|
12
12
|
padding: ${(p) => `0 ${p.theme.spacing.m} ${p.theme.spacing.m} ${p.theme.spacing.m}`};
|
|
13
13
|
flex-shrink: 0;
|
|
14
|
-
min-width:
|
|
14
|
+
min-width: 368px;
|
|
15
15
|
max-width: ${(p) => `calc(100% - 500px - ${p.theme.spacing.m})`};
|
|
16
16
|
flex-direction: column;
|
|
17
17
|
`;
|
|
@@ -140,6 +140,7 @@ const SideModal = (props: ISideModalProps): JSX.Element | null => {
|
|
|
140
140
|
|
|
141
141
|
const filteredOptions = options.options?.map((option) => {
|
|
142
142
|
const optionComponent = typeof option === "string" ? option : option.component;
|
|
143
|
+
const optionKey = typeof option === "string" ? option : (option.id ?? option.editorID ?? optionComponent);
|
|
143
144
|
const displayName = getDisplayName(optionComponent);
|
|
144
145
|
if (searchQuery.length > 0) {
|
|
145
146
|
const name = displayName.toLowerCase();
|
|
@@ -147,7 +148,7 @@ const SideModal = (props: ISideModalProps): JSX.Element | null => {
|
|
|
147
148
|
if (!name.includes(search)) return null;
|
|
148
149
|
}
|
|
149
150
|
return (
|
|
150
|
-
<SideModalOption option={option} handleClick={handleClick} key={
|
|
151
|
+
<SideModalOption option={option} handleClick={handleClick} key={optionKey} theme={theme}>
|
|
151
152
|
{displayName}
|
|
152
153
|
</SideModalOption>
|
|
153
154
|
);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useEffect } from "react";
|
|
2
2
|
import { Icon, Tooltip } from "@ax/components";
|
|
3
3
|
|
|
4
4
|
import * as S from "./style";
|
|
5
5
|
|
|
6
6
|
const Tabs = (props: ITabsProps): JSX.Element => {
|
|
7
|
-
const { tabs, icons, active, setSelectedTab, isInAppBar, noMargins, inversed } = props;
|
|
7
|
+
const { tabs, icons, active, setSelectedTab, isInAppBar, noMargins, inversed, disabled } = props;
|
|
8
8
|
|
|
9
9
|
useEffect(() => {
|
|
10
10
|
tabs && tabs.length === 1 && setSelectedTab(tabs[0]);
|
|
@@ -14,7 +14,10 @@ const Tabs = (props: ITabsProps): JSX.Element => {
|
|
|
14
14
|
return (
|
|
15
15
|
<S.TabsRow isInAppBar={isInAppBar} noMargins={noMargins} data-testid="tabs-row">
|
|
16
16
|
{tabs.map((tab: any) => {
|
|
17
|
-
const handleClick = () =>
|
|
17
|
+
const handleClick = () => {
|
|
18
|
+
if (disabled) return;
|
|
19
|
+
setSelectedTab(tab);
|
|
20
|
+
};
|
|
18
21
|
return (
|
|
19
22
|
<S.TabItem
|
|
20
23
|
isInAppBar={isInAppBar}
|
|
@@ -22,6 +25,7 @@ const Tabs = (props: ITabsProps): JSX.Element => {
|
|
|
22
25
|
active={tab === active}
|
|
23
26
|
onClick={handleClick}
|
|
24
27
|
data-testid="tab"
|
|
28
|
+
isDisabled={disabled}
|
|
25
29
|
>
|
|
26
30
|
{tab}
|
|
27
31
|
</S.TabItem>
|
|
@@ -35,13 +39,17 @@ const Tabs = (props: ITabsProps): JSX.Element => {
|
|
|
35
39
|
return (
|
|
36
40
|
<S.TabsRow icons={true} isInAppBar={isInAppBar} data-testid="icons-tabs-row">
|
|
37
41
|
{icons.map((tab: ITabIcon) => {
|
|
38
|
-
const handleClick = () =>
|
|
42
|
+
const handleClick = () => {
|
|
43
|
+
if (disabled) return;
|
|
44
|
+
setSelectedTab(tab.name);
|
|
45
|
+
};
|
|
39
46
|
return (
|
|
40
47
|
<S.TabItem
|
|
41
48
|
key={tab.name}
|
|
42
49
|
active={tab.name === active}
|
|
43
50
|
onClick={handleClick}
|
|
44
51
|
inversed={inversed}
|
|
52
|
+
isDisabled={disabled}
|
|
45
53
|
data-testid="icon-tab"
|
|
46
54
|
>
|
|
47
55
|
<S.TabIcon>
|
|
@@ -67,6 +75,7 @@ export interface ITabsProps {
|
|
|
67
75
|
setSelectedTab: any;
|
|
68
76
|
noMargins?: boolean;
|
|
69
77
|
inversed?: boolean;
|
|
78
|
+
disabled?: boolean;
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
export interface ITabIcon {
|
|
@@ -8,15 +8,14 @@ const TabsRow = styled.div<{ icons?: boolean; isInAppBar?: boolean; noMargins?:
|
|
|
8
8
|
height: ${(p) => (p.noMargins || p.isInAppBar ? "auto" : "100%")};
|
|
9
9
|
`;
|
|
10
10
|
|
|
11
|
-
const TabItem = styled.button<{ active: boolean; isInAppBar?: boolean; inversed?: boolean }>`
|
|
11
|
+
const TabItem = styled.button<{ active: boolean; isInAppBar?: boolean; inversed?: boolean; isDisabled?: boolean }>`
|
|
12
12
|
flex-grow: 1;
|
|
13
|
-
border: none;
|
|
14
|
-
border-bottom: 4px solid
|
|
15
|
-
${(p) =>
|
|
16
|
-
!p.active ? "transparent" : p.inversed ? p.theme.color.iconHighEmphasisInverse : p.theme.color.interactive01};
|
|
17
13
|
${(p) => p.theme.textStyle.headingXS};
|
|
14
|
+
border: none;
|
|
15
|
+
border-bottom: ${(p) => (p.active ? "4px solid" : "none")};
|
|
16
|
+
border-color: ${(p) => (p.isDisabled ? p.theme.color.interactiveDisabled : p.inversed ? p.theme.color.iconHighEmphasisInverse : p.theme.color.interactive01)};
|
|
18
17
|
color: ${(p) => (p.active ? p.theme.color.textHighEmphasis : p.theme.color.textMediumEmphasis)};
|
|
19
|
-
cursor: ${(p) => (p.active ? "initial" : "pointer")};
|
|
18
|
+
cursor: ${(p) => (p.active || p.isDisabled ? "initial" : "pointer")};
|
|
20
19
|
background: transparent;
|
|
21
20
|
height: ${(p) => (p.isInAppBar ? "100%" : "48px")};
|
|
22
21
|
|
|
@@ -24,7 +23,7 @@ const TabItem = styled.button<{ active: boolean; isInAppBar?: boolean; inversed?
|
|
|
24
23
|
color: ${(p) => (p.active ? p.theme.color.textHighEmphasis : p.theme.color.interactive01)};
|
|
25
24
|
svg {
|
|
26
25
|
path {
|
|
27
|
-
fill: ${(p) => (p.inversed ? p.theme.color.iconHighEmphasisInverse : p.theme.color.interactive01)};
|
|
26
|
+
fill: ${(p) => (p.isDisabled ? p.theme.color.interactiveDisabled : p.inversed ? p.theme.color.iconHighEmphasisInverse : p.theme.color.interactive01)};
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
}
|
|
@@ -39,7 +38,7 @@ const TabItem = styled.button<{ active: boolean; isInAppBar?: boolean; inversed?
|
|
|
39
38
|
height: ${(p) => p.theme.spacing.m};
|
|
40
39
|
path {
|
|
41
40
|
fill: ${(p) =>
|
|
42
|
-
!p.active
|
|
41
|
+
!p.active || p.isDisabled
|
|
43
42
|
? p.theme.color.interactiveDisabled
|
|
44
43
|
: p.inversed
|
|
45
44
|
? p.theme.color.iconHighEmphasisInverse
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useRef, useEffect } from "react";
|
|
2
2
|
import { useLocation } from "react-router-dom";
|
|
3
3
|
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
@@ -14,7 +14,9 @@ const Toast = (props: IToastProps): JSX.Element => {
|
|
|
14
14
|
const isEditor = pathname.includes("/editor");
|
|
15
15
|
|
|
16
16
|
let temp: NodeJS.Timeout;
|
|
17
|
-
const setTemp = (time: number) =>
|
|
17
|
+
const setTemp = (time: number) => {
|
|
18
|
+
temp = setTimeout(() => setIsVisible(false), time);
|
|
19
|
+
};
|
|
18
20
|
|
|
19
21
|
const close = () => {
|
|
20
22
|
if (toast.current) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
1
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
2
|
|
|
4
3
|
import { useHandleClickOutside } from "@ax/hooks";
|
|
@@ -6,7 +5,7 @@ import { useHandleClickOutside } from "@ax/hooks";
|
|
|
6
5
|
import * as S from "./style";
|
|
7
6
|
|
|
8
7
|
const Tooltip = (props: ITooltipProps) => {
|
|
9
|
-
const { content, children, hideOnClick = true, bottom, left, expanded, top } = props;
|
|
8
|
+
const { content, children, hideOnClick = true, bottom, left, expanded, top, className } = props;
|
|
10
9
|
|
|
11
10
|
const initialState: IState = {
|
|
12
11
|
active: false,
|
|
@@ -100,6 +99,7 @@ const Tooltip = (props: ITooltipProps) => {
|
|
|
100
99
|
onMouseLeave={hideTip}
|
|
101
100
|
onMouseDown={handleClick}
|
|
102
101
|
expanded={expanded}
|
|
102
|
+
className={className}
|
|
103
103
|
>
|
|
104
104
|
<div ref={childrenRef}>{children}</div>
|
|
105
105
|
<S.Tip
|
|
@@ -127,13 +127,14 @@ interface IState {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
export interface ITooltipProps {
|
|
130
|
-
content?:
|
|
130
|
+
content?: React.ReactNode;
|
|
131
131
|
children: any;
|
|
132
132
|
hideOnClick?: boolean;
|
|
133
133
|
bottom?: boolean;
|
|
134
134
|
left?: number;
|
|
135
135
|
expanded?: boolean;
|
|
136
136
|
top?: number;
|
|
137
|
+
className?: string;
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
export default Tooltip;
|