UI : Update Markdown Parser (#6275)

*  UI : Update Markdown Parser

* Add unit test for different formats

* FIx cypress tests
This commit is contained in:
Sachin Chaurasiya 2022-07-22 22:06:01 +05:30 committed by GitHub
parent ba94121fce
commit c41af3eb0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 310 additions and 127 deletions

View File

@ -23,10 +23,10 @@ const updateService = () => {
.type(service.newDescription);
cy.get('[data-testid="save"]').click();
cy.get(
'[data-testid="description"] > [data-testid="viewer-container"] > p'
'[data-testid="description"] > [data-testid="viewer-container"] > [data-testid="markdown-parser"] > :nth-child(1) > .toastui-editor-contents > p'
).contains(service.newDescription);
cy.get(':nth-child(1) > .link-title').click();
cy.get('[data-testid="viewer-container"] > p').contains(
cy.get('.toastui-editor-contents > p').contains(
service.newDescription
);
};

View File

@ -25,7 +25,7 @@
"@okta/okta-auth-js": "^6.4.0",
"@okta/okta-react": "^6.4.3",
"@rjsf/core": "^4.1.1",
"@toast-ui/react-editor": "^3.1.3",
"@toast-ui/react-editor": "^3.1.8",
"antd": "^4.20.6",
"antlr4": "4.9.2",
"autoprefixer": "^9.8.6",

View File

@ -0,0 +1,4 @@
<svg width="208" height="128" viewBox="0 0 208 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 5H193C198.523 5 203 9.477 203 15V113C203 118.523 198.523 123 193 123H15C9.477 123 5 118.523 5 113V15C5 9.477 9.477 5 15 5Z" stroke="#6B7280" stroke-width="10"/>
<path d="M30 98V30H50L70 55L90 30H110V98H90V59L70 84L50 59V98H30ZM155 98L125 65H145V30H165V65H185L155 98Z" fill="#6B7280"/>
</svg>

After

Width:  |  Height:  |  Size: 405 B

View File

@ -0,0 +1,45 @@
import MarkdownIcon from '../../../assets/svg/markdown.svg';
/**
* Read more : https://nhn.github.io/tui.editor/latest/tutorial-example15-customizing-toolbar-buttons
* @returns HTMLElement for toolbar
*/
const markdownButton = (): HTMLButtonElement => {
const button = document.createElement('button');
button.className = 'toastui-editor-toolbar-icons markdown-icon';
button.style.backgroundImage = 'none';
button.style.margin = '0';
button.style.marginTop = '4px';
button.innerHTML = `
<a
href="https://www.markdownguide.org/cheat-sheet/"
rel="noreferrer"
target="_blank">
<img
alt="markdown-icon"
className="svg-icon"
src=${MarkdownIcon} />
</a>`;
return button;
};
export const EDITOR_TOOLBAR_ITEMS = [
'heading',
'bold',
'italic',
'strike',
'ul',
'ol',
'link',
'hr',
'quote',
'code',
'codeblock',
{
name: 'Markdown Guide',
el: markdownButton(),
tooltip: 'Markdown Guide',
},
];

View File

@ -15,6 +15,7 @@
import { Editor, Viewer } from '@toast-ui/react-editor';
import classNames from 'classnames';
import { uniqueId } from 'lodash';
import React, {
createRef,
forwardRef,
@ -22,6 +23,7 @@ import React, {
useImperativeHandle,
useState,
} from 'react';
import { EDITOR_TOOLBAR_ITEMS } from './EditorToolBar';
import './RichTextEditor.css';
import { editorRef, RichTextEditorProp } from './RichTextEditor.interface';
@ -32,7 +34,7 @@ const RichTextEditor = forwardRef<editorRef, RichTextEditorProp>(
previewStyle = 'tab',
editorType = 'markdown',
previewHighlight = false,
useCommandShortcut = false,
useCommandShortcut = true,
extendedAutolinks = true,
hideModeSwitch = true,
initialValue = '',
@ -75,6 +77,7 @@ const RichTextEditor = forwardRef<editorRef, RichTextEditorProp>(
<Viewer
extendedAutolinks={extendedAutolinks}
initialValue={editorValue}
key={uniqueId()}
ref={richTextEditorRef}
/>
</div>
@ -82,7 +85,7 @@ const RichTextEditor = forwardRef<editorRef, RichTextEditorProp>(
<div data-testid="editor">
<Editor
extendedAutolinks={extendedAutolinks}
height={height ?? '280px'}
height={height ?? '320px'}
hideModeSwitch={hideModeSwitch}
initialEditType={editorType}
initialValue={editorValue}
@ -90,7 +93,7 @@ const RichTextEditor = forwardRef<editorRef, RichTextEditorProp>(
previewHighlight={previewHighlight}
previewStyle={previewStyle}
ref={richTextEditorRef}
toolbarItems={[['bold', 'italic', 'ul', 'ol', 'link']]}
toolbarItems={[EDITOR_TOOLBAR_ITEMS]}
useCommandShortcut={useCommandShortcut}
onChange={onChangeHandler}
/>

View File

@ -0,0 +1,9 @@
body {
.toastui-editor-contents {
p {
margin-top: 0px;
margin-bottom: 10px;
color: #37352f;
}
}
}

View File

@ -16,8 +16,12 @@ import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import RichTextEditorPreviewer from './RichTextEditorPreviewer';
const mockDescription =
// eslint-disable-next-line max-len
'**Headings**\n\n# H1\n## H2\n### H3\n\n***\n**Bold**\n\n**bold text**\n\n\n***\n**Italic**\n\n*italic*\n\n***\n**BlockQuote**\n\n> blockquote\n\n***\n**Ordered List**\n\n1. First item\n2. Second item\n3. Third item\n\n\n***\n**Unordered List**\n\n- First item\n- Second item\n- Third item\n\n\n***\n**Code**\n\n`code`\n\n\n***\n**Horizontal Rule**\n\n---\n\n\n***\n**Link**\n[title](https://www.example.com)\n\n\n***\n**Image**\n\n![alt text](https://github.com/open-metadata/OpenMetadata/blob/main/docs/.gitbook/assets/openmetadata-banner.png?raw=true)\n\n\n***\n**Table**\n\n| Syntax | Description |\n| ----------- | ----------- |\n| Header | Title |\n| Paragraph | Text |\n***\n\n**Fenced Code Block**\n\n```\n{\n "firstName": "John",\n "lastName": "Smith",\n "age": 25\n}\n```\n\n\n***\n**Strikethrough**\n~~The world is flat.~~\n';
const mockProp = {
markdown: '',
markdown: mockDescription,
className: '',
blurClasses: 'see-more-blur',
maxHtClass: 'tw-h-24',
@ -25,20 +29,6 @@ const mockProp = {
enableSeeMoreVariant: true,
};
jest.mock('react-markdown', () => {
return jest.fn().mockImplementation(() => {
return <p data-testid="markdown-parser">markdown parser</p>;
});
});
jest.mock('rehype-raw', () => {
return jest.fn();
});
jest.mock('remark-gfm', () => {
return jest.fn();
});
describe('Test RichTextEditor Previewer Component', () => {
it('Should render RichTextEditorViewer Component', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
@ -53,4 +43,190 @@ describe('Test RichTextEditor Previewer Component', () => {
expect(markdownParser).toBeInTheDocument();
});
it('Should render bold markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const boldMarkdown = markdownParser.querySelectorAll('strong');
expect(boldMarkdown).toHaveLength(boldMarkdown.length);
expect(markdownParser).toBeInTheDocument();
});
it('Should render strikethrough markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const strikeThroughMarkdown = markdownParser.querySelector('del');
expect(strikeThroughMarkdown).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render headings markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const heading1 = markdownParser.querySelector('h1');
const heading2 = markdownParser.querySelector('h2');
const heading3 = markdownParser.querySelector('h3');
expect(heading1).toBeInTheDocument();
expect(heading2).toBeInTheDocument();
expect(heading3).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render italic markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const italicMarkdown = markdownParser.querySelector('em');
expect(italicMarkdown).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render blockquote markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const blockquoteMarkdown = markdownParser.querySelector('blockquote');
expect(blockquoteMarkdown).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render ordered list markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const orderedList = markdownParser.querySelector('ol');
expect(orderedList).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render unordered list markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const unorderedList = markdownParser.querySelector('ul');
expect(unorderedList).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render code markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const code = markdownParser.querySelector('code');
expect(code).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render code block markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const codeBlock = markdownParser.querySelector('pre');
expect(codeBlock).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render horizontal rule markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const horizontalRule = markdownParser.querySelector('hr');
expect(horizontalRule).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render link markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const link = markdownParser.querySelector('a');
expect(link).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render image markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const image = markdownParser.querySelector('img');
expect(image).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
it('Should render table markdown content', async () => {
const { container } = render(<RichTextEditorPreviewer {...mockProp} />, {
wrapper: MemoryRouter,
});
const markdownParser = await findByTestId(container, 'markdown-parser');
const table = markdownParser.querySelector('table');
expect(table).toBeInTheDocument();
expect(markdownParser).toBeInTheDocument();
});
});

View File

@ -11,16 +11,13 @@
* limitations under the License.
*/
import { Viewer } from '@toast-ui/react-editor';
import classNames from 'classnames';
import { uniqueId } from 'lodash';
import React, { useEffect, useState } from 'react';
// Markdown Parser and plugin imports
import MarkdownParser from 'react-markdown';
import { Link } from 'react-router-dom';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
import { isExternalUrl } from '../../../utils/StringsUtils';
import { BlurLayout } from './BlurLayout';
import { PreviewerProp } from './RichTextEditor.interface';
import './RichTextEditorPreviewer.less';
export const MAX_LENGTH = 300;
@ -33,21 +30,14 @@ const RichTextEditorPreviewer = ({
enableSeeMoreVariant = true,
}: PreviewerProp) => {
const [content, setContent] = useState<string>('');
const [displayMoreText, setDisplayMoreText] = useState(false);
const setModifiedContent = (markdownValue: string) => {
const modifiedContent = markdownValue
.replace(/&lt;/g, '<')
.replace(/&gt/g, '>');
setContent(modifiedContent);
};
const [displayMoreText, setDisplayMoreText] = useState<boolean>(false);
const displayMoreHandler = () => {
setDisplayMoreText((pre) => !pre);
};
useEffect(() => {
setModifiedContent(markdown);
setContent(markdown);
}, [markdown]);
return (
@ -63,54 +53,10 @@ const RichTextEditorPreviewer = ({
}
)}
data-testid="viewer-container">
<MarkdownParser
sourcePos
components={{
h1: 'p',
h2: 'p',
ul: ({ children, ...props }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { ordered, ...rest } = props;
<div data-testid="markdown-parser">
<Viewer extendedAutolinks initialValue={content} key={uniqueId()} />
</div>
return (
<ul className="tw-ml-3" {...rest}>
{children}
</ul>
);
},
ol: ({ children, ...props }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { ordered, ...rest } = props;
return (
<ol className="tw-ml-3" {...rest} style={{ listStyle: 'auto' }}>
{children}
</ol>
);
},
code: ({ children, ...props }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { inline, ...rest } = props;
return (
<code {...rest} className="tw-my">
{children}
</code>
);
},
a: ({ children, ...props }) => {
const href = props.href;
if (isExternalUrl(href)) {
return <a {...props}>{children}</a>;
} else {
return <Link to={props.href || ''}>{children}</Link>;
}
},
}}
rehypePlugins={[rehypeRaw]}
remarkPlugins={[remarkGfm]}>
{content}
</MarkdownParser>
<BlurLayout
blurClasses={blurClasses}
displayMoreHandler={displayMoreHandler}

View File

@ -2861,10 +2861,10 @@
traverse "^0.6.6"
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==
"@toast-ui/editor@^3.1.8":
version "3.1.8"
resolved "https://registry.yarnpkg.com/@toast-ui/editor/-/editor-3.1.8.tgz#b10c788c893b97b1ca9e57238e0f3233cc75c421"
integrity sha512-2IIHQnaxPZsCySvYAjgSlQWEQZGCakMl6S6mkKm+oWFMVyCBhLd1DMrooj7xI8kJEEZLTGsVj5OGvlHY1LboNg==
dependencies:
dompurify "^2.3.3"
prosemirror-commands "^1.1.9"
@ -2875,12 +2875,12 @@
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==
"@toast-ui/react-editor@^3.1.8":
version "3.1.8"
resolved "https://registry.yarnpkg.com/@toast-ui/react-editor/-/react-editor-3.1.8.tgz#da60a1b8698628558344f3ec860dafb6498c1854"
integrity sha512-u8M3aqAoCEErIcwyC9hUxPU+SLAEHLJowfjgLHJnksyel1T/GKvo8cB5a5juz0nvise1dmYnLYlldTSUK1eBbQ==
dependencies:
"@toast-ui/editor" "^3.1.3"
"@toast-ui/editor" "^3.1.8"
"@tootallnate/once@1":
version "1.1.2"
@ -6172,9 +6172,9 @@ dompurify@^2.0.7:
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==
version "2.3.10"
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.10.tgz#901f7390ffe16a91a5a556b94043314cd4850385"
integrity sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g==
domutils@^1.7.0:
version "1.7.0"
@ -11312,10 +11312,10 @@ optionator@^0.8.1, optionator@^0.8.3:
type-check "~0.3.2"
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==
orderedmap@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-2.0.0.tgz#12ff5ef6ea9d12d6430b80c701b35475e1c9ff34"
integrity sha512-buf4PoAMlh45b8a8gsGy/X6w279TSqkyAS0C0wdTSJwFSU+ljQFJON5I8NfjLHoCXwpSROIo2wr0g33T+kQshQ==
organize-imports-cli@^0.7.0:
version "0.7.0"
@ -11997,65 +11997,65 @@ property-information@^6.0.0:
integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w==
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==
version "1.3.0"
resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.3.0.tgz#361b2e2b2a347ce7453386459f97c3f549a1113b"
integrity sha512-BwBbZ5OAScPcm0x7H8SPbqjuEJnCU2RJT9LDyOiiIl/3NbL1nJZI4SFNHwU2e/tRr2Xe7JsptpzseqvZvToLBQ==
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==
version "1.3.0"
resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.3.0.tgz#bf5a1ff7759aca759ddf0c722c2fa5b14fb0ddc1"
integrity sha512-qo/9Wn4B/Bq89/YD+eNWFbAytu6dmIM85EhID+fz9Jcl9+DfGEo8TTSrRhP15+fFEoaPqpHSxlvSzSEbmlxlUA==
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==
version "1.2.0"
resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.2.0.tgz#476dde2dc244050b3aca00cf58a82adfad6749e7"
integrity sha512-eAW/M/NTSSzpCOxfR8Abw6OagdG0MiDAiWHQMQveIsZtoKVYzm0AflSPq/ymqJd56/Su1YPbwy9lM13wgHOFmQ==
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==
version "1.2.0"
resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.0.tgz#d5cc9da9b712020690a994b50b92a0e448a60bf5"
integrity sha512-TdSfu+YyLDd54ufN/ZeD1VtBRYpgZnTPnnbY+4R08DDgs84KrIPEPbJL8t1Lm2dkljFx6xeBE26YWH3aIzkPKg==
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==
version "1.18.1"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.18.1.tgz#1d5d6b6de7b983ee67a479dc607165fdef3935bd"
integrity sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==
dependencies:
orderedmap "^1.1.0"
orderedmap "^2.0.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==
version "1.4.1"
resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.1.tgz#f6e26c7b6a7e11206176689eb6ebbf91870953e1"
integrity sha512-U/LBDW2gNmVa07sz/D229XigSdDQ5CLFwVB1Vb32MJbAHHhWe/6pOc721faI17tqw4pZ49i1xfY/jEZ9tbIhPg==
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==
version "1.6.0"
resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.6.0.tgz#8162dbfaf124f9253a7ab28605a9460411a96a53"
integrity sha512-MAp7AjsjEGEqQY0sSMufNIUuEyB1ZR9Fqlm8dTwwWwpEJRv/plsKjWXBbx52q3Ml8MtaMcd7ic14zAHVB3WaMw==
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==
version "1.27.0"
resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.27.0.tgz#f43f7a7e83100f6b2863bb2381f2acec07926b0e"
integrity sha512-yNCQW5eiPkrMgjOT5Xa/ItIvcM7JBG7ikZKaHo26hdBW5OLNnIWGZ0BV6/OiBk742teLybLVNPCpYUcW405Ckg==
dependencies:
prosemirror-model "^1.16.0"
prosemirror-state "^1.0.0"
@ -13540,9 +13540,9 @@ rimraf@3.0.2, rimraf@^3.0.0:
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==
version "1.3.3"
resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.3.tgz#3f67fc106288b84b71532b4a5fd9d4881e4457f0"
integrity sha512-85aZYCxweiD5J8yTEbw+E6A27zSnLPNDL0WfPdw3YYodq7WjnTKo0q4dtyQ2gz23iPT8Q9CUyJtAaUNcTxRf5Q==
rsvp@^4.8.4:
version "4.8.5"