mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-12 08:52:38 +00:00
* Fix #3202 UI Markdown text editor is broken * Move markdownwithpreview component to rich-text-editor folder * Remove unused component files * Fixed component import error on test files * Fix Failing test * Remove Markdownwith preview component. * Fix failing tests * Add support for readonly * Add unit test Co-authored-by: Vivek Ratnavel Subramanian <vivekratnavel90@gmail.com>
This commit is contained in:
parent
4dce0a061a
commit
d429f0b868
@ -23,6 +23,7 @@
|
|||||||
"@fortawesome/react-fontawesome": "^0.1.17",
|
"@fortawesome/react-fontawesome": "^0.1.17",
|
||||||
"@okta/okta-auth-js": "^6.1.0",
|
"@okta/okta-auth-js": "^6.1.0",
|
||||||
"@okta/okta-react": "^6.4.2",
|
"@okta/okta-react": "^6.4.2",
|
||||||
|
"@toast-ui/react-editor": "^3.1.3",
|
||||||
"autoprefixer": "^9.8.6",
|
"autoprefixer": "^9.8.6",
|
||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"babel-plugin-named-asset-import": "^0.3.6",
|
"babel-plugin-named-asset-import": "^0.3.6",
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import ColumnTestForm from './ColumnTestForm';
|
|||||||
|
|
||||||
const mockFunction = jest.fn();
|
const mockFunction = jest.fn();
|
||||||
|
|
||||||
jest.mock('../../common/editor/MarkdownWithPreview', () => {
|
jest.mock('../../common/rich-text-editor/RichTextEditor', () => {
|
||||||
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ import {
|
|||||||
import SVGIcons from '../../../utils/SvgUtils';
|
import SVGIcons from '../../../utils/SvgUtils';
|
||||||
import { getDataTypeString } from '../../../utils/TableUtils';
|
import { getDataTypeString } from '../../../utils/TableUtils';
|
||||||
import { Button } from '../../buttons/Button/Button';
|
import { Button } from '../../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../../common/rich-text-editor/RichTextEditor';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data?: ColumnTest;
|
data?: ColumnTest;
|
||||||
@ -657,10 +657,10 @@ const ColumnTestForm = ({
|
|||||||
htmlFor="description">
|
htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview
|
<RichTextEditor
|
||||||
data-testid="description"
|
data-testid="description"
|
||||||
|
initialValue={description}
|
||||||
ref={markdownRef}
|
ref={markdownRef}
|
||||||
value={description}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import TableTestForm from './TableTestForm';
|
|||||||
|
|
||||||
const mockFunction = jest.fn();
|
const mockFunction = jest.fn();
|
||||||
|
|
||||||
jest.mock('../../common/editor/MarkdownWithPreview', () => {
|
jest.mock('../../common/rich-text-editor/RichTextEditor', () => {
|
||||||
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import {
|
|||||||
requiredField,
|
requiredField,
|
||||||
} from '../../../utils/CommonUtils';
|
} from '../../../utils/CommonUtils';
|
||||||
import { Button } from '../../buttons/Button/Button';
|
import { Button } from '../../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../../common/rich-text-editor/RichTextEditor';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data?: TableTest;
|
data?: TableTest;
|
||||||
@ -319,10 +319,10 @@ const TableTestForm = ({
|
|||||||
htmlFor="description">
|
htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview
|
<RichTextEditor
|
||||||
data-testid="description"
|
data-testid="description"
|
||||||
|
initialValue={description}
|
||||||
ref={markdownRef}
|
ref={markdownRef}
|
||||||
value={description}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import {
|
|||||||
requiredField,
|
requiredField,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { Button } from '../buttons/Button/Button';
|
import { Button } from '../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../common/rich-text-editor/RichTextEditor';
|
||||||
import PageLayout from '../containers/PageLayout';
|
import PageLayout from '../containers/PageLayout';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component';
|
import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component';
|
||||||
@ -212,11 +212,11 @@ const AddGlossary = ({
|
|||||||
htmlFor="description">
|
htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview
|
<RichTextEditor
|
||||||
data-testid="description"
|
data-testid="description"
|
||||||
|
initialValue={description}
|
||||||
readonly={!allowAccess}
|
readonly={!allowAccess}
|
||||||
ref={markdownRef}
|
ref={markdownRef}
|
||||||
value={description}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,10 @@ jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
|||||||
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditor', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditor</p>);
|
||||||
|
});
|
||||||
|
|
||||||
jest.mock('../../axiosAPIs/glossaryAPI', () => ({
|
jest.mock('../../axiosAPIs/glossaryAPI', () => ({
|
||||||
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
|
addGlossaries: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import {
|
|||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import SVGIcons from '../../utils/SvgUtils';
|
import SVGIcons from '../../utils/SvgUtils';
|
||||||
import { Button } from '../buttons/Button/Button';
|
import { Button } from '../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../common/rich-text-editor/RichTextEditor';
|
||||||
import PageLayout from '../containers/PageLayout';
|
import PageLayout from '../containers/PageLayout';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import RelatedTermsModal from '../Modals/RelatedTermsModal/RelatedTermsModal';
|
import RelatedTermsModal from '../Modals/RelatedTermsModal/RelatedTermsModal';
|
||||||
@ -325,11 +325,11 @@ const AddGlossaryTerm = ({
|
|||||||
htmlFor="description">
|
htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview
|
<RichTextEditor
|
||||||
data-testid="description"
|
data-testid="description"
|
||||||
|
initialValue={description}
|
||||||
readonly={!allowAccess}
|
readonly={!allowAccess}
|
||||||
ref={markdownRef}
|
ref={markdownRef}
|
||||||
value={description}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,10 @@ jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
|
|||||||
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
return jest.fn().mockReturnValue(<p>RichTextEditorPreviewer</p>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
jest.mock('../common/rich-text-editor/RichTextEditor', () => {
|
||||||
|
return jest.fn().mockReturnValue(<p>RichTextEditor</p>);
|
||||||
|
});
|
||||||
|
|
||||||
const mockOnCancel = jest.fn();
|
const mockOnCancel = jest.fn();
|
||||||
const mockOnSave = jest.fn();
|
const mockOnSave = jest.fn();
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ import {
|
|||||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||||
import { Button } from '../buttons/Button/Button';
|
import { Button } from '../buttons/Button/Button';
|
||||||
import CopyToClipboardButton from '../buttons/CopyToClipboardButton/CopyToClipboardButton';
|
import CopyToClipboardButton from '../buttons/CopyToClipboardButton/CopyToClipboardButton';
|
||||||
import MarkdownWithPreview from '../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../common/rich-text-editor/RichTextEditor';
|
||||||
import PageLayout from '../containers/PageLayout';
|
import PageLayout from '../containers/PageLayout';
|
||||||
import DropDown from '../dropdown/DropDown';
|
import DropDown from '../dropdown/DropDown';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
@ -502,11 +502,11 @@ const AddWebhook: FunctionComponent<AddWebhookProps> = ({
|
|||||||
htmlFor="description">
|
htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview
|
<RichTextEditor
|
||||||
data-testid="description"
|
data-testid="description"
|
||||||
|
initialValue={description}
|
||||||
readonly={!allowAccess}
|
readonly={!allowAccess}
|
||||||
ref={markdownRef}
|
ref={markdownRef}
|
||||||
value={description}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import { EntityReference as UserTeams } from '../../generated/entity/teams/user'
|
|||||||
import jsonData from '../../jsons/en';
|
import jsonData from '../../jsons/en';
|
||||||
import { errorMsg, requiredField } from '../../utils/CommonUtils';
|
import { errorMsg, requiredField } from '../../utils/CommonUtils';
|
||||||
import { Button } from '../buttons/Button/Button';
|
import { Button } from '../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../common/rich-text-editor/RichTextEditor';
|
||||||
import PageLayout from '../containers/PageLayout';
|
import PageLayout from '../containers/PageLayout';
|
||||||
import DropDown from '../dropdown/DropDown';
|
import DropDown from '../dropdown/DropDown';
|
||||||
import { DropDownListItem } from '../dropdown/types';
|
import { DropDownListItem } from '../dropdown/types';
|
||||||
@ -246,7 +246,7 @@ const CreateUser = ({
|
|||||||
<label className="tw-block tw-form-label tw-mb-0" htmlFor="description">
|
<label className="tw-block tw-form-label tw-mb-0" htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview ref={markdownRef} value={description} />
|
<RichTextEditor initialValue={description} ref={markdownRef} />
|
||||||
</Field>
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
<label className="tw-block tw-form-label tw-mb-0">Teams:</label>
|
<label className="tw-block tw-form-label tw-mb-0">Teams:</label>
|
||||||
|
|||||||
@ -33,7 +33,7 @@ jest.mock('../dropdown/DropDown', () => {
|
|||||||
return jest.fn().mockReturnValue(<p>Dropdown component</p>);
|
return jest.fn().mockReturnValue(<p>Dropdown component</p>);
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.mock('../common/editor/MarkdownWithPreview', () => {
|
jest.mock('../common/rich-text-editor/RichTextEditor', () => {
|
||||||
return jest.fn().mockReturnValue(<p>MarkdownWithPreview component</p>);
|
return jest.fn().mockReturnValue(<p>MarkdownWithPreview component</p>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -36,7 +36,7 @@ const mockOnCancel = jest.fn();
|
|||||||
|
|
||||||
const mockServiceList: Array<ServiceDataObj> = [{ name: mockData.name }];
|
const mockServiceList: Array<ServiceDataObj> = [{ name: mockData.name }];
|
||||||
|
|
||||||
jest.mock('../../common/editor/MarkdownWithPreview', () => {
|
jest.mock('../../common/rich-text-editor/RichTextEditor', () => {
|
||||||
return jest
|
return jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockReturnValue(<p data-testid="description">MarkdownWithPreview</p>);
|
.mockReturnValue(<p data-testid="description">MarkdownWithPreview</p>);
|
||||||
|
|||||||
@ -69,7 +69,7 @@ import {
|
|||||||
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
|
||||||
import { Button } from '../../buttons/Button/Button';
|
import { Button } from '../../buttons/Button/Button';
|
||||||
import CronEditor from '../../common/CronEditor/CronEditor';
|
import CronEditor from '../../common/CronEditor/CronEditor';
|
||||||
import MarkdownWithPreview from '../../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../../common/rich-text-editor/RichTextEditor';
|
||||||
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
|
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
|
||||||
import IngestionStepper from '../../IngestionStepper/IngestionStepper.component';
|
import IngestionStepper from '../../IngestionStepper/IngestionStepper.component';
|
||||||
|
|
||||||
@ -1681,10 +1681,10 @@ export const AddServiceModal: FunctionComponent<Props> = ({
|
|||||||
<label className="tw-block tw-form-label" htmlFor="description">
|
<label className="tw-block tw-form-label" htmlFor="description">
|
||||||
Description:
|
Description:
|
||||||
</label>
|
</label>
|
||||||
<MarkdownWithPreview
|
<RichTextEditor
|
||||||
data-testid="description"
|
data-testid="description"
|
||||||
|
initialValue={description}
|
||||||
ref={markdownRef}
|
ref={markdownRef}
|
||||||
value={description}
|
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|||||||
@ -19,7 +19,7 @@ const mockOnSave = jest.fn();
|
|||||||
const mockOnCancel = jest.fn();
|
const mockOnCancel = jest.fn();
|
||||||
const mockValue = 'Test value';
|
const mockValue = 'Test value';
|
||||||
|
|
||||||
jest.mock('../../common/editor/MarkdownWithPreview', () => {
|
jest.mock('../../common/rich-text-editor/RichTextEditor', () => {
|
||||||
return () => jest.fn().mockImplementation(() => mockValue);
|
return () => jest.fn().mockImplementation(() => mockValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -11,15 +11,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import {
|
||||||
|
faWindowMaximize,
|
||||||
|
faWindowMinimize,
|
||||||
|
} from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import React, { FunctionComponent, useRef, useState } from 'react';
|
import React, { FunctionComponent, useRef, useState } from 'react';
|
||||||
import { Button } from '../../buttons/Button/Button';
|
import { Button } from '../../buttons/Button/Button';
|
||||||
import MarkdownWithPreview from '../../common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../../common/rich-text-editor/RichTextEditor';
|
||||||
import {
|
|
||||||
faWindowMinimize,
|
|
||||||
faWindowMaximize,
|
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
|
|
||||||
type EditorContentRef = {
|
type EditorContentRef = {
|
||||||
getEditorContent: () => string;
|
getEditorContent: () => string;
|
||||||
@ -98,11 +98,7 @@ export const ModalWithMarkdownEditor: FunctionComponent<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="tw-modal-body tw-pt-0 tw-pb-1">
|
<div className="tw-modal-body tw-pt-0 tw-pb-1">
|
||||||
<MarkdownWithPreview
|
<RichTextEditor initialValue={value} ref={markdownRef} />
|
||||||
data-testid="markdown-with-preview"
|
|
||||||
ref={markdownRef}
|
|
||||||
value={value}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="tw-modal-footer">
|
<div className="tw-modal-footer">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 Collate
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.field-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 2px;
|
|
||||||
margin-left: 15px;
|
|
||||||
border-left: 3px solid #d9ceee;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-child {
|
|
||||||
display: flex;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
.field-child::before {
|
|
||||||
content: '';
|
|
||||||
display: inline-block;
|
|
||||||
width: 32px;
|
|
||||||
height: 3px;
|
|
||||||
background: #d9ceee;
|
|
||||||
position: relative;
|
|
||||||
top: 11px;
|
|
||||||
}
|
|
||||||
.field-child-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #7147e8;
|
|
||||||
}
|
|
||||||
.field-child-icon i {
|
|
||||||
vertical-align: sub;
|
|
||||||
margin-right: 2px;
|
|
||||||
margin-left: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-label {
|
|
||||||
display: flex;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-label-name {
|
|
||||||
padding: 4px 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.child-fields-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
/* margin-top: -11px; */
|
|
||||||
}
|
|
||||||
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 Collate
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, { CSSProperties, useCallback, useState } from 'react';
|
|
||||||
import './SchemaTreeStructure.css';
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { faPlusCircle, faMinusCircle } from '@fortawesome/free-solid-svg-icons';
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
positions?: Array<number>;
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
fields?: Array<Props>;
|
|
||||||
isCollapsed?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStyle = (type: string) => {
|
|
||||||
const sharedStyles = {
|
|
||||||
padding: '4px 8px',
|
|
||||||
borderRadius: '5px',
|
|
||||||
minWidth: '60px',
|
|
||||||
textAlign: 'center',
|
|
||||||
display: 'inline-block',
|
|
||||||
};
|
|
||||||
switch (type) {
|
|
||||||
case 'double':
|
|
||||||
return {
|
|
||||||
backgroundColor: '#B02AAC33',
|
|
||||||
color: '#B02AAC',
|
|
||||||
...sharedStyles,
|
|
||||||
};
|
|
||||||
|
|
||||||
case 'string':
|
|
||||||
return {
|
|
||||||
backgroundColor: '#51c41a33',
|
|
||||||
color: '#51c41a',
|
|
||||||
...sharedStyles,
|
|
||||||
};
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
return {
|
|
||||||
backgroundColor: '#1890FF33',
|
|
||||||
color: '#1890FF',
|
|
||||||
...sharedStyles,
|
|
||||||
};
|
|
||||||
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
backgroundColor: '#EEEAF8',
|
|
||||||
...sharedStyles,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const SchemaTreeStructure = ({
|
|
||||||
name,
|
|
||||||
type,
|
|
||||||
fields,
|
|
||||||
isCollapsed = false,
|
|
||||||
// to track position of element [L0,L1,L2,...Ln]
|
|
||||||
positions = [],
|
|
||||||
}: Props) => {
|
|
||||||
const [showChildren, setShowChildren] = useState<boolean>(!isCollapsed);
|
|
||||||
const flag = (fields ?? []).length > 0;
|
|
||||||
|
|
||||||
const showChildrenHandler = useCallback(() => {
|
|
||||||
setShowChildren(!showChildren);
|
|
||||||
}, [showChildren, setShowChildren]);
|
|
||||||
|
|
||||||
const getIcon = () => {
|
|
||||||
return (
|
|
||||||
flag &&
|
|
||||||
(showChildren ? (
|
|
||||||
<FontAwesomeIcon icon={faMinusCircle} />
|
|
||||||
) : (
|
|
||||||
<FontAwesomeIcon icon={faPlusCircle} />
|
|
||||||
))
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="field-wrapper"
|
|
||||||
style={{ paddingLeft: flag ? '26px' : '0px' }}>
|
|
||||||
<div
|
|
||||||
className="field-child"
|
|
||||||
style={{ marginLeft: flag ? '-26px' : '0px' }}>
|
|
||||||
<p className="field-child-icon" onClick={showChildrenHandler}>
|
|
||||||
{getIcon()}
|
|
||||||
</p>
|
|
||||||
<p className="field-label">
|
|
||||||
<span style={getStyle(type) as CSSProperties}>{type}</span>
|
|
||||||
<span className="field-label-name">{name}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
{flag && showChildren && (
|
|
||||||
<div className="child-fields-wrapper">
|
|
||||||
{(fields ?? []).map((field, index) => (
|
|
||||||
<SchemaTreeStructure
|
|
||||||
isCollapsed
|
|
||||||
key={index}
|
|
||||||
positions={[...positions, index]}
|
|
||||||
{...field}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SchemaTreeStructure;
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 Collate
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React, {
|
|
||||||
forwardRef,
|
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import RichTextEditor from '../rich-text-editor/RichTextEditor';
|
|
||||||
import { editorRef } from '../rich-text-editor/RichTextEditor.interface';
|
|
||||||
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
|
|
||||||
|
|
||||||
type EditorContentRef = {
|
|
||||||
getEditorContent: (value: string) => string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
value: string;
|
|
||||||
readonly?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
const MarkdownWithPreview = forwardRef<editorRef, Props>(
|
|
||||||
({ value, readonly }: Props, ref) => {
|
|
||||||
const [activeTab, setActiveTab] = useState<number>(1);
|
|
||||||
const [preview, setPreview] = useState<string>('');
|
|
||||||
const [initValue, setInitValue] = useState<string>(value ?? '');
|
|
||||||
|
|
||||||
const editorRef = useRef<EditorContentRef>();
|
|
||||||
const getTabClasses = (tab: number, activeTab: number) => {
|
|
||||||
return (
|
|
||||||
'tw-gh-tabs tw-cursor-pointer' + (activeTab === tab ? ' active' : '')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateInternalValue = () => {
|
|
||||||
if (editorRef.current) {
|
|
||||||
setInitValue(editorRef.current?.getEditorContent('markdown'));
|
|
||||||
setPreview(editorRef.current?.getEditorContent('markdown'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPreview = () => {
|
|
||||||
if (preview.length < 1) {
|
|
||||||
return 'Nothing to preview';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RichTextEditorPreviewer
|
|
||||||
enableSeeMoreVariant={false}
|
|
||||||
markdown={preview}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
|
||||||
getEditorContent() {
|
|
||||||
return activeTab === 2
|
|
||||||
? initValue
|
|
||||||
: editorRef.current?.getEditorContent('markdown');
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setInitValue(value ?? '');
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className="tw-bg-transparent">
|
|
||||||
<nav className="tw-flex tw-flex-row tw-gh-tabs-container tw-px-6">
|
|
||||||
<p
|
|
||||||
className={getTabClasses(1, activeTab)}
|
|
||||||
data-testid="tab"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setActiveTab(1);
|
|
||||||
}}>
|
|
||||||
{'Write '}
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
className={getTabClasses(2, activeTab)}
|
|
||||||
data-testid="tab"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
setActiveTab(2);
|
|
||||||
updateInternalValue();
|
|
||||||
}}>
|
|
||||||
{'View '}
|
|
||||||
</p>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
<div className="tw-my-5 tw-bg-white">
|
|
||||||
{activeTab === 1 && (
|
|
||||||
<RichTextEditor
|
|
||||||
format="markdown"
|
|
||||||
initvalue={initValue}
|
|
||||||
readonly={readonly}
|
|
||||||
ref={editorRef}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{activeTab === 2 && (
|
|
||||||
<div className="editor-wrapper tw-flex tw-flex-col tw-flex-1 tw-overflow-y-auto tw-p-3 tw-pl-6 tw-min-h-32 tw-border tw-border-main tw-rounded tw-max-h-none">
|
|
||||||
{getPreview()}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
MarkdownWithPreview.displayName = 'MarkdownWithPreview';
|
|
||||||
|
|
||||||
export default MarkdownWithPreview;
|
|
||||||
File diff suppressed because one or more lines are too long
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ReactNode } from 'react';
|
import { HTMLAttributes, ReactNode } from 'react';
|
||||||
|
|
||||||
export type editorRef = ReactNode | HTMLElement | string;
|
export type editorRef = ReactNode | HTMLElement | string;
|
||||||
export enum Format {
|
export enum Format {
|
||||||
@ -35,3 +35,19 @@ export interface PreviewerProp {
|
|||||||
maxLen?: number;
|
maxLen?: number;
|
||||||
enableSeeMoreVariant?: boolean;
|
enableSeeMoreVariant?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PreviewStyle = 'tab' | 'vertical';
|
||||||
|
|
||||||
|
export type EditorType = 'markdown' | 'wysiwyg';
|
||||||
|
|
||||||
|
export interface RichTextEditorProp extends HTMLAttributes<HTMLDivElement> {
|
||||||
|
initialValue: string;
|
||||||
|
placeHolder?: string;
|
||||||
|
previewStyle?: PreviewStyle;
|
||||||
|
editorType?: EditorType;
|
||||||
|
previewHighlight?: boolean;
|
||||||
|
extendedAutolinks?: boolean;
|
||||||
|
hideModeSwitch?: boolean;
|
||||||
|
useCommandShortcut?: boolean;
|
||||||
|
readonly?: boolean;
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 Collate
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { findByTestId, queryByTestId, render } from '@testing-library/react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
|
import RichTextEditor from './RichTextEditor';
|
||||||
|
|
||||||
|
jest.mock('@toast-ui/react-editor', () => {
|
||||||
|
class Editor extends Component {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
getInstance() {}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
getRootElement() {}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <p>Editor</p>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Viewer extends Component {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
getInstance() {}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
getRootElement() {}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <p>Viewer</p>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
Editor,
|
||||||
|
Viewer,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockProp = {
|
||||||
|
initialValue: '',
|
||||||
|
readonly: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Test RichText Editor', () => {
|
||||||
|
it('Should render rich text editor', async () => {
|
||||||
|
const { container } = render(<RichTextEditor {...mockProp} />, {
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = await findByTestId(container, 'editor');
|
||||||
|
|
||||||
|
expect(editor).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should render viewer if readOnly is true', async () => {
|
||||||
|
const { container } = render(<RichTextEditor {...mockProp} readonly />, {
|
||||||
|
wrapper: MemoryRouter,
|
||||||
|
});
|
||||||
|
|
||||||
|
const editor = queryByTestId(container, 'editor');
|
||||||
|
const viewer = await findByTestId(container, 'viewer');
|
||||||
|
|
||||||
|
expect(editor).not.toBeInTheDocument();
|
||||||
|
expect(viewer).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -11,122 +11,87 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { convertFromRaw, convertToRaw, EditorState } from 'draft-js';
|
/* eslint-disable */
|
||||||
import { draftjsToMd } from 'draftjs-md-converter';
|
|
||||||
import { markdownToDraft } from 'markdown-draft-js';
|
import { Editor, Viewer } from '@toast-ui/react-editor';
|
||||||
import React, {
|
import React, {
|
||||||
|
createRef,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
useEffect,
|
useEffect,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { Editor } from 'react-draft-wysiwyg';
|
import './RichTextEditor.css';
|
||||||
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
|
import { editorRef, RichTextEditorProp } from './RichTextEditor.interface';
|
||||||
import ListUl from '../../../assets/svg/list-ul.svg';
|
|
||||||
import { EditorProp, editorRef, Format } from './RichTextEditor.interface';
|
|
||||||
import { Bold, Info, Italic, Link } from './ToolBarOptions';
|
|
||||||
|
|
||||||
const getIntialContent = (format: string, content?: string) => {
|
const RichTextEditor = forwardRef<editorRef, RichTextEditorProp>(
|
||||||
/*eslint-disable */
|
|
||||||
|
|
||||||
if (content) {
|
|
||||||
switch (format) {
|
|
||||||
case Format.MARKDOWN:
|
|
||||||
const rawData = markdownToDraft(content, {
|
|
||||||
remarkablePreset: 'commonmark',
|
|
||||||
remarkableOptions: {
|
|
||||||
html: false,
|
|
||||||
disable: {
|
|
||||||
inline: ['links', 'emphasis'],
|
|
||||||
block: ['heading', 'code', 'list'],
|
|
||||||
},
|
|
||||||
enable: {
|
|
||||||
block: 'table',
|
|
||||||
core: ['abbr'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preserveNewlines: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
const state = convertFromRaw({ ...rawData });
|
|
||||||
|
|
||||||
return EditorState.createWithContent(state);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return EditorState.createEmpty();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return EditorState.createEmpty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const RichTextEditor = forwardRef<editorRef, EditorProp>(
|
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
format = 'markdown',
|
placeHolder = 'Write your description',
|
||||||
initvalue,
|
previewStyle = 'tab',
|
||||||
readonly = false,
|
editorType = 'markdown',
|
||||||
customOptions,
|
previewHighlight = false,
|
||||||
}: EditorProp,
|
useCommandShortcut = false,
|
||||||
|
extendedAutolinks = true,
|
||||||
|
hideModeSwitch = true,
|
||||||
|
initialValue = '',
|
||||||
|
readonly,
|
||||||
|
}: RichTextEditorProp,
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const [editorState, setEditorState] = useState(
|
const richTextEditorRef = createRef<Editor>();
|
||||||
getIntialContent(format, initvalue)
|
|
||||||
);
|
const [editorValue, setEditorValue] = useState(initialValue);
|
||||||
const onEditorStateChange = (newState: typeof editorState) => {
|
|
||||||
setEditorState(newState);
|
const onChangeHandler = () => {
|
||||||
|
const value = richTextEditorRef.current
|
||||||
|
?.getInstance()
|
||||||
|
.getMarkdown() as string;
|
||||||
|
setEditorValue(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
getEditorContent(_format: 'json' | 'markdown') {
|
getEditorContent() {
|
||||||
// use switch case for multiple format support
|
return editorValue;
|
||||||
return draftjsToMd(convertToRaw(editorState.getCurrentContent()));
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEditorState(getIntialContent(format, initvalue));
|
setEditorValue(initialValue);
|
||||||
}, [initvalue, format]);
|
}, [initialValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="tw-my-4">
|
||||||
<div
|
{readonly ? (
|
||||||
className="tw-min-h-32 tw-border tw-border-main tw-rounded tw-overflow-y-auto"
|
<div
|
||||||
data-testid="enterDescription">
|
className="tw-border tw-border-main tw-p-2 tw-rounded"
|
||||||
<Editor
|
data-testid="viewer">
|
||||||
editorClassName="tw-px-1 tw-min-h-32"
|
<Viewer
|
||||||
editorState={editorState}
|
extendedAutolinks={extendedAutolinks}
|
||||||
readOnly={readonly}
|
initialValue={editorValue}
|
||||||
toolbar={{
|
ref={richTextEditorRef}
|
||||||
options: ['list'],
|
/>
|
||||||
list: {
|
</div>
|
||||||
className: 'my-list tw-order-4',
|
) : (
|
||||||
options: ['unordered'],
|
<div data-testid="editor">
|
||||||
unordered: {
|
<Editor
|
||||||
icon: ListUl,
|
extendedAutolinks={extendedAutolinks}
|
||||||
className: 'list-option ',
|
hideModeSwitch={hideModeSwitch}
|
||||||
},
|
initialEditType={editorType}
|
||||||
},
|
initialValue={editorValue}
|
||||||
}}
|
placeholder={placeHolder}
|
||||||
toolbarClassName="tw-py-2 tw-border-0 tw-border-b tw-border-main"
|
previewHighlight={previewHighlight}
|
||||||
toolbarCustomButtons={
|
previewStyle={previewStyle}
|
||||||
customOptions ?? [
|
ref={richTextEditorRef}
|
||||||
<Bold key="bold" />,
|
toolbarItems={[['bold', 'italic'], ['ul', 'ol'], ['link']]}
|
||||||
<Italic key="italic" />,
|
useCommandShortcut={useCommandShortcut}
|
||||||
<Link key="link" />,
|
onChange={onChangeHandler}
|
||||||
<Info key="info" />,
|
/>
|
||||||
]
|
</div>
|
||||||
}
|
)}
|
||||||
toolbarHidden={readonly}
|
</div>
|
||||||
wrapperClassName="editor-wrapper"
|
|
||||||
onEditorStateChange={onEditorStateChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
RichTextEditor.displayName = 'RichTextEditor';
|
|
||||||
|
|
||||||
export default RichTextEditor;
|
export default RichTextEditor;
|
||||||
|
|||||||
@ -1,378 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 Collate
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
|
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
||||||
import { EditorState, Modifier, SelectionState } from 'draft-js';
|
|
||||||
import {
|
|
||||||
faLink,
|
|
||||||
faListUl,
|
|
||||||
faListOl,
|
|
||||||
faItalic,
|
|
||||||
faInfoCircle,
|
|
||||||
} from '@fortawesome/free-solid-svg-icons';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import PopOver from '../popover/PopOver';
|
|
||||||
|
|
||||||
const getSelectedText = (editorState: any) => {
|
|
||||||
const selection = editorState.getSelection();
|
|
||||||
const anchorKey = selection.getAnchorKey();
|
|
||||||
const currentContent = editorState.getCurrentContent();
|
|
||||||
const currentBlock = currentContent.getBlockForKey(anchorKey);
|
|
||||||
|
|
||||||
const start = selection.getStartOffset();
|
|
||||||
const end = selection.getEndOffset();
|
|
||||||
const selectedText = currentBlock.getText().slice(start, end);
|
|
||||||
|
|
||||||
return selectedText;
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateEditorSelection = (eState: any, offsetDiff: any) => {
|
|
||||||
const selection = eState.getSelection();
|
|
||||||
const newFocusOffset = selection.focusOffset + offsetDiff;
|
|
||||||
|
|
||||||
const newSelection = new SelectionState({
|
|
||||||
anchorKey: selection.anchorKey,
|
|
||||||
anchorOffset: newFocusOffset,
|
|
||||||
focusKey: selection.focusKey,
|
|
||||||
focusOffset: newFocusOffset,
|
|
||||||
});
|
|
||||||
const newEditorState = EditorState.forceSelection(eState, newSelection);
|
|
||||||
|
|
||||||
return EditorState.push(newEditorState, newEditorState.getCurrentContent());
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Bold extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
makeBold = () => {
|
|
||||||
const { editorState, onChange } = this.props as any;
|
|
||||||
const selectedText = getSelectedText(editorState);
|
|
||||||
|
|
||||||
const contentState = Modifier.replaceText(
|
|
||||||
editorState.getCurrentContent(),
|
|
||||||
editorState.getSelection(),
|
|
||||||
`${
|
|
||||||
selectedText.startsWith('**') && selectedText.endsWith('**')
|
|
||||||
? selectedText.replaceAll('**', '')
|
|
||||||
: `**${selectedText}**`
|
|
||||||
}`,
|
|
||||||
editorState.getCurrentInlineStyle()
|
|
||||||
);
|
|
||||||
|
|
||||||
const eState = EditorState.push(
|
|
||||||
editorState,
|
|
||||||
contentState,
|
|
||||||
'insert-characters'
|
|
||||||
);
|
|
||||||
|
|
||||||
onChange(updateEditorSelection(eState, -2));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="rdw-option-wrapper tw-font-bold"
|
|
||||||
data-testid="boldButton"
|
|
||||||
onClick={this.makeBold}>
|
|
||||||
<PopOver
|
|
||||||
arrow={false}
|
|
||||||
position="bottom"
|
|
||||||
size="small"
|
|
||||||
title="Add bold text"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<p>B</p>
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Link extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
makeLink = () => {
|
|
||||||
const { editorState, onChange } = this.props as any;
|
|
||||||
|
|
||||||
const selectedText = getSelectedText(editorState);
|
|
||||||
|
|
||||||
const contentState = Modifier.replaceText(
|
|
||||||
editorState.getCurrentContent(),
|
|
||||||
editorState.getSelection(),
|
|
||||||
`${
|
|
||||||
selectedText.startsWith('[') && selectedText.endsWith(')')
|
|
||||||
? selectedText.replace(/ *\([^)]*\) */g, '').replace(/[\])}[{(]/g, '')
|
|
||||||
: `[${selectedText}](url)`
|
|
||||||
}`,
|
|
||||||
editorState.getCurrentInlineStyle()
|
|
||||||
);
|
|
||||||
const eState = EditorState.push(
|
|
||||||
editorState,
|
|
||||||
contentState,
|
|
||||||
'insert-characters'
|
|
||||||
);
|
|
||||||
onChange(updateEditorSelection(eState, -6));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="rdw-option-wrapper "
|
|
||||||
data-testid="linkButton"
|
|
||||||
onClick={this.makeLink}>
|
|
||||||
<PopOver
|
|
||||||
arrow={false}
|
|
||||||
position="bottom"
|
|
||||||
size="small"
|
|
||||||
title="Add link"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<FontAwesomeIcon icon={faLink} />
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Italic extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
makeItalic = () => {
|
|
||||||
const { editorState, onChange } = this.props as any;
|
|
||||||
const selectedText = getSelectedText(editorState);
|
|
||||||
|
|
||||||
const contentState = Modifier.replaceText(
|
|
||||||
editorState.getCurrentContent(),
|
|
||||||
editorState.getSelection(),
|
|
||||||
`${
|
|
||||||
selectedText.startsWith('_') && selectedText.endsWith('_')
|
|
||||||
? selectedText.replaceAll('_', '')
|
|
||||||
: `_${selectedText}_`
|
|
||||||
}`,
|
|
||||||
editorState.getCurrentInlineStyle()
|
|
||||||
);
|
|
||||||
const eState = EditorState.push(
|
|
||||||
editorState,
|
|
||||||
contentState,
|
|
||||||
'insert-characters'
|
|
||||||
);
|
|
||||||
|
|
||||||
onChange(updateEditorSelection(eState, -1));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="rdw-option-wrapper "
|
|
||||||
data-testid="italicButton"
|
|
||||||
onClick={this.makeItalic}>
|
|
||||||
<PopOver
|
|
||||||
arrow={false}
|
|
||||||
position="bottom"
|
|
||||||
size="small"
|
|
||||||
title="Add italic text"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<FontAwesomeIcon icon={faItalic} />
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class Heading extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
makeHeading = () => {
|
|
||||||
const { editorState, onChange } = this.props as any;
|
|
||||||
const selectedText = getSelectedText(editorState);
|
|
||||||
|
|
||||||
const contentState = Modifier.replaceText(
|
|
||||||
editorState.getCurrentContent(),
|
|
||||||
editorState.getSelection(),
|
|
||||||
`${
|
|
||||||
selectedText.startsWith('### ')
|
|
||||||
? selectedText.replaceAll('### ', '')
|
|
||||||
: `### ${selectedText}`
|
|
||||||
}`,
|
|
||||||
editorState.getCurrentInlineStyle()
|
|
||||||
);
|
|
||||||
const eState = EditorState.push(
|
|
||||||
editorState,
|
|
||||||
contentState,
|
|
||||||
'insert-characters'
|
|
||||||
);
|
|
||||||
onChange(updateEditorSelection(eState, 0));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="rdw-option-wrapper" onClick={this.makeHeading}>
|
|
||||||
<PopOver
|
|
||||||
position="bottom"
|
|
||||||
size="small"
|
|
||||||
title="Add header text"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<p>H</p>
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ULLIST extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
makeLIST = () => {
|
|
||||||
const { editorState, onChange } = this.props as any;
|
|
||||||
const selectedText = getSelectedText(editorState);
|
|
||||||
const selection = editorState.getSelection();
|
|
||||||
const text = selectedText.startsWith('- ')
|
|
||||||
? selectedText.replaceAll('- ', '')
|
|
||||||
: `${
|
|
||||||
selection.anchorOffset > 0 && selectedText.length <= 0
|
|
||||||
? `\n\n- ${selectedText}`
|
|
||||||
: `- ${selectedText}`
|
|
||||||
}`;
|
|
||||||
const contentState = Modifier.replaceText(
|
|
||||||
editorState.getCurrentContent(),
|
|
||||||
editorState.getSelection(),
|
|
||||||
text,
|
|
||||||
editorState.getCurrentInlineStyle()
|
|
||||||
);
|
|
||||||
onChange(EditorState.push(editorState, contentState, 'insert-characters'));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="rdw-option-wrapper " onClick={this.makeLIST}>
|
|
||||||
<PopOver
|
|
||||||
position="bottom"
|
|
||||||
size="small"
|
|
||||||
title="Add unordered list"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<FontAwesomeIcon icon={faListUl} />
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class OLLIST extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
makeLIST = () => {
|
|
||||||
const { editorState, onChange } = this.props as any;
|
|
||||||
const selection = editorState.getSelection();
|
|
||||||
const currentKey = selection.getStartKey();
|
|
||||||
const currentBlock = editorState
|
|
||||||
.getCurrentContent()
|
|
||||||
.getBlockForKey(currentKey);
|
|
||||||
const textArr = currentBlock.getText().split('\n') || [];
|
|
||||||
const lastText = textArr[textArr.length - 1];
|
|
||||||
const match = lastText.match(/(\d+)/)?.[0];
|
|
||||||
let len = 0;
|
|
||||||
for (const txt of textArr) {
|
|
||||||
len += txt.length;
|
|
||||||
if (len >= selection.focusOffset) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newSelection = new SelectionState({
|
|
||||||
anchorKey: selection.anchorKey,
|
|
||||||
anchorOffset: textArr.join(',').length,
|
|
||||||
focusKey: selection.focusKey,
|
|
||||||
focusOffset: textArr.join(',').length,
|
|
||||||
});
|
|
||||||
|
|
||||||
const contentState = Modifier.replaceText(
|
|
||||||
editorState.getCurrentContent(),
|
|
||||||
newSelection,
|
|
||||||
`${
|
|
||||||
selection.anchorOffset > 0
|
|
||||||
? `\n${match ? parseInt(match) + 1 : 1}. `
|
|
||||||
: `${match ? parseInt(match) + 1 : 1}. `
|
|
||||||
}`,
|
|
||||||
editorState.getCurrentInlineStyle()
|
|
||||||
);
|
|
||||||
|
|
||||||
onChange(EditorState.push(editorState, contentState, 'insert-characters'));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="rdw-option-wrapper " onClick={this.makeLIST}>
|
|
||||||
<PopOver
|
|
||||||
position="bottom"
|
|
||||||
size="small"
|
|
||||||
title="Add unordered list"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<FontAwesomeIcon icon={faListOl} />
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Info extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
onChange: PropTypes.func,
|
|
||||||
editorState: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<div className="rdw-option-wrapper tw-order-5 tw-font-bold tw-ml-auto">
|
|
||||||
<PopOver
|
|
||||||
arrow={false}
|
|
||||||
html={
|
|
||||||
<div className="tw-flex tw-pb-1 tw-text-white tw-text-left">
|
|
||||||
<div>
|
|
||||||
<p className="tw-pt-2">
|
|
||||||
Using headings in markdown is not allowed.
|
|
||||||
</p>
|
|
||||||
<p className="tw-pt-2">
|
|
||||||
Use{' '}
|
|
||||||
<span className=" tw-py-0.5 tw-px-1 tw-ml-1 tw-border tw-rounded tw-text-xs">{`<br/>`}</span>{' '}
|
|
||||||
tag to add empty lines.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
position="left"
|
|
||||||
size="small"
|
|
||||||
trigger="mouseenter">
|
|
||||||
<FontAwesomeIcon icon={faInfoCircle} />
|
|
||||||
</PopOver>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -10,7 +10,7 @@ const mockInitialData = {
|
|||||||
name: '',
|
name: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('../../components/common/editor/MarkdownWithPreview', () => {
|
jest.mock('../../components/common/rich-text-editor/RichTextEditor', () => {
|
||||||
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import MarkdownWithPreview from '../../components/common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../../components/common/rich-text-editor/RichTextEditor';
|
||||||
import { CreateTagCategory } from '../../generated/api/tags/createTagCategory';
|
import { CreateTagCategory } from '../../generated/api/tags/createTagCategory';
|
||||||
import { errorMsg } from '../../utils/CommonUtils';
|
import { errorMsg } from '../../utils/CommonUtils';
|
||||||
|
|
||||||
@ -120,7 +120,10 @@ const Form: React.FC<FormProp> = forwardRef(
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="tw-form-label">Description</label>
|
<label className="tw-form-label">Description</label>
|
||||||
<MarkdownWithPreview ref={markdownRef} value={data.description} />
|
<RichTextEditor
|
||||||
|
initialValue={data.description}
|
||||||
|
ref={markdownRef}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import Form from './Form';
|
|||||||
|
|
||||||
const mockFunction = jest.fn();
|
const mockFunction = jest.fn();
|
||||||
|
|
||||||
jest.mock('../../components/common/editor/MarkdownWithPreview', () => {
|
jest.mock('../../components/common/rich-text-editor/RichTextEditor', () => {
|
||||||
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
return jest.fn().mockReturnValue(<div>MarkdownWithPreview component</div>);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import MarkdownWithPreview from '../../components/common/editor/MarkdownWithPreview';
|
import RichTextEditor from '../../components/common/rich-text-editor/RichTextEditor';
|
||||||
import { errorMsg } from '../../utils/CommonUtils';
|
import { errorMsg } from '../../utils/CommonUtils';
|
||||||
|
|
||||||
type FormProp = {
|
type FormProp = {
|
||||||
@ -114,7 +114,10 @@ const Form: React.FC<FormProp> = forwardRef(
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className="tw-form-label">Description</label>
|
<label className="tw-form-label">Description</label>
|
||||||
<MarkdownWithPreview ref={markdownRef} value={data.description} />
|
<RichTextEditor
|
||||||
|
initialValue={data.description}
|
||||||
|
ref={markdownRef}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1794,6 +1794,27 @@
|
|||||||
traverse "^0.6.6"
|
traverse "^0.6.6"
|
||||||
unified "^9.2.1"
|
unified "^9.2.1"
|
||||||
|
|
||||||
|
"@toast-ui/editor@^3.1.3":
|
||||||
|
version "3.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@toast-ui/editor/-/editor-3.1.3.tgz#12f15dab1fc9c1db336683f51208f8ba8017abb9"
|
||||||
|
integrity sha512-4W8nKIhct4bGOKNMkYY2nGzt2k+8LUWlINwGZvCbNgIo6WKlcOarsbWD0o8stOAleaq2TeG6ixIvYK/wTG0OxA==
|
||||||
|
dependencies:
|
||||||
|
dompurify "^2.3.3"
|
||||||
|
prosemirror-commands "^1.1.9"
|
||||||
|
prosemirror-history "^1.1.3"
|
||||||
|
prosemirror-inputrules "^1.1.3"
|
||||||
|
prosemirror-keymap "^1.1.4"
|
||||||
|
prosemirror-model "^1.14.1"
|
||||||
|
prosemirror-state "^1.3.4"
|
||||||
|
prosemirror-view "^1.18.7"
|
||||||
|
|
||||||
|
"@toast-ui/react-editor@^3.1.3":
|
||||||
|
version "3.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@toast-ui/react-editor/-/react-editor-3.1.3.tgz#5d55ecf08df4c6a230c104f5e4dbab9212107941"
|
||||||
|
integrity sha512-k5W53y/R3cZvSH3UfDgeT8L1k8MpRri4O9hcTeuXtnbkkCtPQjt0m696tKrZvSXRNeqa4mKT0m8uNbHJAqWD4g==
|
||||||
|
dependencies:
|
||||||
|
"@toast-ui/editor" "^3.1.3"
|
||||||
|
|
||||||
"@tootallnate/once@1":
|
"@tootallnate/once@1":
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||||
@ -5001,6 +5022,11 @@ dompurify@^2.0.7:
|
|||||||
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.4.tgz#1cf5cf0105ccb4debdf6db162525bd41e6ddacc6"
|
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.4.tgz#1cf5cf0105ccb4debdf6db162525bd41e6ddacc6"
|
||||||
integrity sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==
|
integrity sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ==
|
||||||
|
|
||||||
|
dompurify@^2.3.3:
|
||||||
|
version "2.3.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875"
|
||||||
|
integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==
|
||||||
|
|
||||||
domutils@^1.7.0:
|
domutils@^1.7.0:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
|
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
|
||||||
@ -9930,6 +9956,11 @@ optionator@^0.8.1, optionator@^0.8.3:
|
|||||||
type-check "~0.3.2"
|
type-check "~0.3.2"
|
||||||
word-wrap "~1.2.3"
|
word-wrap "~1.2.3"
|
||||||
|
|
||||||
|
orderedmap@^1.1.0:
|
||||||
|
version "1.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-1.1.5.tgz#4174c90b61bd7c25294932edf789f3b5677744d0"
|
||||||
|
integrity sha512-/fzlCGKRmfayGoI9UUXvJfc2nMZlJHW30QqEvwPvlg8tsX7jyiUSomYie6mYqx7Z9bOMGoag0H/q1PS/0PjYkg==
|
||||||
|
|
||||||
organize-imports-cli@^0.7.0:
|
organize-imports-cli@^0.7.0:
|
||||||
version "0.7.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/organize-imports-cli/-/organize-imports-cli-0.7.0.tgz#a6ffcec2d31c5de60748efe8861ea8cecd727276"
|
resolved "https://registry.yarnpkg.com/organize-imports-cli/-/organize-imports-cli-0.7.0.tgz#a6ffcec2d31c5de60748efe8861ea8cecd727276"
|
||||||
@ -10570,6 +10601,70 @@ prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.8.1:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
react-is "^16.13.1"
|
react-is "^16.13.1"
|
||||||
|
|
||||||
|
prosemirror-commands@^1.1.9:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.2.2.tgz#1bd167372ee20abf488aca9cece63c43fab182c9"
|
||||||
|
integrity sha512-TX+KpWudMon06frryfpO/u7hsQv2hu8L4VSVbCpi3/7wXHBgl+35mV85qfa3RpT8xD2f3MdeoTqH0vy5JdbXPg==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-history@^1.1.3:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.2.0.tgz#04cc4df8d2f7b2a46651a2780de191ada6d465ea"
|
||||||
|
integrity sha512-B9v9xtf4fYbKxQwIr+3wtTDNLDZcmMMmGiI3TAPShnUzvo+Rmv1GiUrsQChY1meetHl7rhML2cppF3FTs7f7UQ==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.2.2"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
rope-sequence "^1.3.0"
|
||||||
|
|
||||||
|
prosemirror-inputrules@^1.1.3:
|
||||||
|
version "1.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.1.3.tgz#93f9199ca02473259c30d7e352e4c14022d54638"
|
||||||
|
integrity sha512-ZaHCLyBtvbyIHv0f5p6boQTIJjlD6o2NPZiEaZWT2DA+j591zS29QQEMT4lBqwcLW3qRSf7ZvoKNbf05YrsStw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-keymap@^1.1.4:
|
||||||
|
version "1.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.1.5.tgz#b5984c7d30f5c75956c853126c54e9e624c0327b"
|
||||||
|
integrity sha512-8SZgPH3K+GLsHL2wKuwBD9rxhsbnVBTwpHCO4VUO5GmqUQlxd/2GtBVWTsyLq4Dp3N9nGgPd3+lZFKUDuVp+Vw==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
w3c-keyname "^2.2.0"
|
||||||
|
|
||||||
|
prosemirror-model@^1.0.0, prosemirror-model@^1.14.1, prosemirror-model@^1.16.0:
|
||||||
|
version "1.16.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.16.1.tgz#fb388270bc9609b66298d6a7e15d0cc1d6c61253"
|
||||||
|
integrity sha512-r1/w0HDU40TtkXp0DyKBnFPYwd8FSlUSJmGCGFv4DeynfeSlyQF2FD0RQbVEMOe6P3PpUSXM6LZBV7W/YNZ4mA==
|
||||||
|
dependencies:
|
||||||
|
orderedmap "^1.1.0"
|
||||||
|
|
||||||
|
prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.4:
|
||||||
|
version "1.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.3.4.tgz#4c6b52628216e753fc901c6d2bfd84ce109e8952"
|
||||||
|
integrity sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
prosemirror-transform "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0:
|
||||||
|
version "1.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.4.2.tgz#35f56091bcab3359f1eb90e82ce9f20cc52105c1"
|
||||||
|
integrity sha512-bcIsf3uRZhfab0xRfyyxOEh6eqSszq/hJbDbmUumFnbHBoWhB/uXbpz6vvUxfk0XiEvrZDJ+5pXRrNDc1Hu3vQ==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.0.0"
|
||||||
|
|
||||||
|
prosemirror-view@^1.18.7:
|
||||||
|
version "1.23.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.23.11.tgz#297f6ef8d10e1ff78c505d9c57358e062810a80e"
|
||||||
|
integrity sha512-iBqsyrQZz9NYcJ13JC7sPZ+4PdbBbUXhs1qzbxkDQ2tplcVROwxmAn3bnxpVFst/guv+XFI5KTHHbw5stvKt0g==
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model "^1.16.0"
|
||||||
|
prosemirror-state "^1.0.0"
|
||||||
|
prosemirror-transform "^1.1.0"
|
||||||
property-information@^6.0.0:
|
property-information@^6.0.0:
|
||||||
version "6.1.1"
|
version "6.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22"
|
resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22"
|
||||||
@ -11693,6 +11788,11 @@ rimraf@^3.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
glob "^7.1.3"
|
glob "^7.1.3"
|
||||||
|
|
||||||
|
rope-sequence@^1.3.0:
|
||||||
|
version "1.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.2.tgz#a19e02d72991ca71feb6b5f8a91154e48e3c098b"
|
||||||
|
integrity sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg==
|
||||||
|
|
||||||
rsvp@^4.8.4:
|
rsvp@^4.8.4:
|
||||||
version "4.8.5"
|
version "4.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
|
||||||
@ -13618,6 +13718,11 @@ w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
browser-process-hrtime "^1.0.0"
|
browser-process-hrtime "^1.0.0"
|
||||||
|
|
||||||
|
w3c-keyname@^2.2.0:
|
||||||
|
version "2.2.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.4.tgz#4ade6916f6290224cdbd1db8ac49eab03d0eef6b"
|
||||||
|
integrity sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==
|
||||||
|
|
||||||
w3c-xmlserializer@^1.1.2:
|
w3c-xmlserializer@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794"
|
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user