diff --git a/package.json b/package.json index 94e16ab352..7499be5f32 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,17 @@ "@sentry/node": "^6.14.3", "@styled-icons/feather": "^10.0.0", "@styled-icons/styled-icon": "^10.0.0", + "@tiptap/extension-bubble-menu": "^2.0.0-beta.49", + "@tiptap/extension-code-block": "^2.0.0-beta.29", + "@tiptap/extension-heading": "^2.0.0-beta.23", + "@tiptap/extension-highlight": "^2.0.0-beta.30", + "@tiptap/extension-image": "^2.0.0-beta.24", + "@tiptap/extension-link": "^2.0.0-beta.28", + "@tiptap/extension-placeholder": "^2.0.0-beta.43", + "@tiptap/extension-typography": "^2.0.0-beta.19", + "@tiptap/react": "^2.0.0-beta.93", + "@tiptap/starter-kit": "^2.0.0-beta.140", + "@types/marked": "^4.0.0", "@types/socket.io-client": "^1.4.32", "@types/ua-parser-js": "^0.7.36", "approx-string-match": "^1.1.0", @@ -79,7 +90,9 @@ "immutability-helper": "^3.0.1", "jsdom": "^16.2.2", "json-date-parser": "^1.0.1", + "json2md": "^1.12.0", "lodash": "^4.17.4", + "marked": "^4.0.2", "moment": "^2.18.1", "moment-timezone": "^0.5.14", "mousetrap": "^1.6.5", @@ -132,6 +145,7 @@ "styled-props": "^1.1.2", "through2": "^2.0.3", "traverse": "^0.6.6", + "turndown": "^7.1.1", "tweetnacl": "^1.0.1", "tweetnacl-async": "^2.0.0", "tweetnacl-util": "^0.15.0", @@ -184,6 +198,7 @@ "@types/simple-peer": "^6.1.6", "@types/sinon": "^7.0.3", "@types/styled-components": "^5.1.4", + "@types/turndown": "^5.0.1", "@types/url-regex": "^4.1.0", "@types/whatwg-url": "^6.4.0", "atob": "^2.1.2", diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 5815a708f2..28e9a6d78f 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -3,18 +3,23 @@ import styled from 'styled-components' import onClickOutside from 'react-onclickoutside' import { ButtonTooltip } from 'src/common-ui/components' -import { MarkdownPreviewAnnotationInsertMenu } from 'src/markdown-preview/markdown-preview-insert-menu' import { FocusableComponent } from './types' -import { insertTab, uninsertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' import TagHolder from 'src/tags/ui/tag-holder' import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' import { ClickAway } from 'src/util/click-away-wrapper' import TagPicker, { TagPickerDependencies } from 'src/tags/ui/TagPicker' import SaveBtn from './save-btn' +import MemexEditor, { MemexEditorInstance } from './editor/editor' +import MarkdownHelp from './MarkdownHelp' +import * as icons from 'src/common-ui/components/design-library/icons' +import TagsSegment from 'src/common-ui/components/result-item-tags-segment' +import type { NoteResultHoverState } from './types' +import type { AnnotationFooterEventProps } from 'src/annotations/components/AnnotationFooter' interface State { isTagPickerShown: boolean + isMarkdownHelpShown: boolean } export interface AnnotationCreateEventProps { @@ -22,6 +27,11 @@ export interface AnnotationCreateEventProps { onCancel: () => void onTagsUpdate: (tags: string[]) => void onCommentChange: (text: string) => void + onTagsHover?: React.MouseEventHandler + annotationFooterDependencies?: AnnotationFooterEventProps + onFooterHover?: React.MouseEventHandler + onNoteHover?: React.MouseEventHandler + onUnhover?: React.MouseEventHandler } export interface AnnotationCreateGeneralProps { @@ -29,6 +39,9 @@ export interface AnnotationCreateGeneralProps { autoFocus?: boolean comment: string tags: string[] + onTagClick?: (tag: string) => void + hoverState: NoteResultHoverState + toggleMarkdownHelp?: () => void } export interface Props @@ -45,13 +58,23 @@ export class AnnotationCreate extends React.Component implements FocusableComponent { static ALT_KEY = getKeyName({ key: 'alt' }) static MOD_KEY = getKeyName({ key: 'mod' }) - private textAreaRef = React.createRef() - private markdownPreviewRef = React.createRef< - MarkdownPreviewAnnotationInsertMenu - >() + //private textAreaRef = React.createRef() + // private markdownPreviewRef = React.createRef< + // MarkdownPreviewAnnotationInsertMenu + // >() + + private annotCreateRef = React.createRef() + + static defaultProps: Pick = { + tags: [], + hoverState: null, + } + + private editor: MemexEditorInstance state: State = { isTagPickerShown: false, + isMarkdownHelpShown: false, } componentDidMount() { @@ -62,8 +85,8 @@ export class AnnotationCreate extends React.Component focus() { const inputLen = this.props.comment.length - this.textAreaRef.current.focus() - this.textAreaRef.current.setSelectionRange(inputLen, inputLen) + // this.textAreaRef.current.focus() + // this.textAreaRef.current.setSelectionRange(inputLen, inputLen) } handleClickOutside() { @@ -73,6 +96,9 @@ export class AnnotationCreate extends React.Component } private hideTagPicker = () => this.setState({ isTagPickerShown: false }) + private toggleMarkdownHelp = () => this.props.toggleMarkdownHelp + private hideMarkdownHelp = () => + this.setState({ isMarkdownHelpShown: false }) private handleCancel = () => this.props.onCancel() private handleSave = async ( shouldShare: boolean, @@ -80,12 +106,8 @@ export class AnnotationCreate extends React.Component ) => { const saveP = this.props.onSave(shouldShare, isProtected) - if ( - this.markdownPreviewRef?.current?.markdownPreviewRef.current?.state - .showPreview - ) { - this.markdownPreviewRef.current.markdownPreviewRef.current.togglePreview() - } + this.editor?.resetState() + this.setState({ isMarkdownHelpShown: false }) await saveP } @@ -119,15 +141,15 @@ export class AnnotationCreate extends React.Component return this.handleSave(false, false) } - if (e.key === 'Tab' && !e.shiftKey) { - e.preventDefault() - insertTab({ el: this.textAreaRef.current }) - } + // if (e.key === 'Tab' && !e.shiftKey) { + // e.preventDefault() + // insertTab({ el: this.textAreaRef.current }) + // } - if (e.key === 'Tab' && e.shiftKey) { - e.preventDefault() - uninsertTab({ el: this.textAreaRef.current }) - } + // if (e.key === 'Tab' && e.shiftKey) { + // e.preventDefault() + // uninsertTab({ el: this.textAreaRef.current }) + // } } private renderTagPicker() { @@ -136,7 +158,7 @@ export class AnnotationCreate extends React.Component this.setState({ isTagPickerShown }) const tagPicker = !this.state.isTagPickerShown ? null : ( - + setPickerShown(false)}> ) } + private renderMarkdownHelpButton() { + const setPickerShown = (isMarkdownHelpShown: boolean) => + this.setState({ isMarkdownHelpShown }) + + return ( + + + this.props.toggleMarkdownHelp()} + /> + + + ) + } + private renderActionButtons() { return ( - + Cancel @@ -184,28 +225,37 @@ export class AnnotationCreate extends React.Component render() { return ( - ( - - this.props.onCommentChange(e.target.value) - } - /> - )} + onContentUpdate={(content) => + this.props.onCommentChange(content) + } + markdownContent={this.props.comment} + setEditorInstanceRef={(editor) => (this.editor = editor)} + placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} + toggleMarkdownHelp={() => { + this.props.toggleMarkdownHelp() + }} /> {this.props.comment !== '' && ( <> - {this.renderTagPicker()} - {this.renderActionButtons()} + + + + {this.renderActionButtons()} + {this.renderMarkdownHelpButton()} + + {this.renderTagPicker()} + )} @@ -215,6 +265,33 @@ export class AnnotationCreate extends React.Component export default onClickOutside(AnnotationCreate) +const FooterContainer = styled.div` + border-top: 1px solid #f0f0f0; + display: flex; + justify-content: space-between; + align-items: center; + padding: 5px 15px 5px 5px; +` + +const SaveActionBar = styled.div` + display: flex; + justify-content: flex-start; + align-items: center; +` + +const MarkdownButtonContainer = styled.div` + display: flex; +` + +const MarkdownButton = styled.img` + display: flex; + height: 16px; + opacity: 0.8; + mask-position: center center; + margin-left: 10px; + cursor: pointer; +` + const TextBoxContainerStyled = styled.div` box-shadow: none; cursor: default; @@ -268,8 +345,6 @@ const FooterStyled = styled.div` flex-direction: row-reverse; justify-content: flex-end; align-items: center; - margin: 0 5px 3px 5px; - height: 26px; animation: slideIn 0.2s ease-in-out; animation-fill-mode: forwards; ` @@ -296,6 +371,6 @@ const CancelBtnStyled = styled.div` const Flex = styled.div` display: flex; - padding: 0 5px 5px; justify-content: flex-end; + align-items: center; ` diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index e63eee8224..ec820c5dde 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -1,10 +1,12 @@ import * as React from 'react' import styled from 'styled-components' -import { MarkdownPreviewAnnotationInsertMenu } from 'src/markdown-preview/markdown-preview-insert-menu' -import { FocusableComponent } from './types' -import { uninsertTab, insertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' +import MemexEditor, { MemexEditorInstance } from './editor/editor' + +interface State { + isMarkdownHelpShown: boolean +} export interface AnnotationEditEventProps { onEditConfirm: (shouldShare: boolean, isProtected?: boolean) => void @@ -14,6 +16,7 @@ export interface AnnotationEditEventProps { export interface AnnotationEditGeneralProps { comment: string + toggleMarkdownHelp?: () => void } export interface Props @@ -23,81 +26,57 @@ export interface Props rows: number } -class AnnotationEdit extends React.Component - implements FocusableComponent { +class AnnotationEdit extends React.Component { static MOD_KEY = getKeyName({ key: 'mod' }) - private textAreaRef = React.createRef() - componentDidMount() { - this.focusOnInputEnd() + state: State = { + isMarkdownHelpShown: false, } - focus() { - this.textAreaRef.current.focus() - } + private editor: MemexEditorInstance - focusOnInputEnd() { - const inputLen = this.props.comment.length - this.textAreaRef.current.setSelectionRange(inputLen, inputLen) - this.focus() + private saveEdit(shouldShare, isProtected) { + this.props.onEditConfirm(shouldShare, isProtected) + //AnnotationEditable.removeMarkdownHelp() } private handleInputKeyDown: React.KeyboardEventHandler = (e) => { e.stopPropagation() if (e.key === 'Enter' && e.shiftKey && e.metaKey) { - return this.props.onEditConfirm(true, false) + return this.saveEdit(true, false) } if (e.key === 'Enter' && e.shiftKey && e.altKey) { - return this.props.onEditConfirm(true, true) + return this.saveEdit(true, true) } if (e.key === 'Enter' && e.altKey) { - return this.props.onEditConfirm(false, true) + return this.saveEdit(false, true) } if (e.key === 'Enter' && e.metaKey) { - return this.props.onEditConfirm(false, false) + return this.saveEdit(false, false) } if (e.key === 'Escape') { this.props.onEditCancel() return } - - if (e.key === 'Tab' && !e.shiftKey) { - e.preventDefault() - insertTab({ el: this.textAreaRef.current }) - } - - if (e.key === 'Tab' && e.shiftKey) { - e.preventDefault() - uninsertTab({ el: this.textAreaRef.current }) - } } render() { return ( - <> - ( - - this.props.onCommentChange(e.target.value) - } - /> - )} - /> - + + this.props.onCommentChange(content) + } + markdownContent={this.props.comment} + onKeyDown={this.handleInputKeyDown} + toggleMarkdownHelp={() => { + this.props.toggleMarkdownHelp() + }} + /> ) } } diff --git a/src/annotations/components/AnnotationEditable.tsx b/src/annotations/components/AnnotationEditable.tsx index 1756cdd827..26a91893ff 100644 --- a/src/annotations/components/AnnotationEditable.tsx +++ b/src/annotations/components/AnnotationEditable.tsx @@ -24,6 +24,9 @@ import Margin from 'src/dashboard-refactor/components/Margin' import type { NoteResultHoverState } from './types' import { getKeyName } from 'src/util/os-specific-key-names' import { getShareButtonData } from '../sharing-utils' +import MarkdownHelp from './MarkdownHelp' +import { ClickAway } from 'src/util/click-away-wrapper' +import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' export interface HighlightProps extends AnnotationProps { body: string @@ -63,6 +66,7 @@ export interface AnnotationProps { renderTagsPickerForAnnotation?: (id: string) => JSX.Element renderCopyPasterForAnnotation?: (id: string) => JSX.Element renderShareMenuForAnnotation?: (id: string) => JSX.Element + toggleMarkdownHelp?: () => void } export interface AnnotationEditableEventProps { @@ -73,6 +77,10 @@ export interface AnnotationEditableEventProps { onUnhover?: React.MouseEventHandler } +interface State { + isMarkdownHelpShown: boolean +} + export type Props = (HighlightProps | NoteProps) & AnnotationEditableEventProps export default class AnnotationEditable extends React.Component { @@ -85,10 +93,21 @@ export default class AnnotationEditable extends React.Component { hoverState: null, } - focus() { - this.annotEditRef?.current?.focusOnInputEnd() + state: State = { + isMarkdownHelpShown: false, } + public removeMarkdownHelp() { + this.setState({ + isMarkdownHelpShown: false, + }) + } + + focus() {} + + private hideMarkdownHelp = () => + this.setState({ isMarkdownHelpShown: false }) + private get creationInfo() { // TODO: Figure out why these dates are so unpredictable and fix it const handleDateData = (date: string | number | Date): number => @@ -198,6 +217,10 @@ export default class AnnotationEditable extends React.Component { ref={this.annotEditRef} {...annotationEditDependencies} rows={2} + comment={comment} + toggleMarkdownHelp={() => { + this.props.toggleMarkdownHelp() + }} /> ) } @@ -334,6 +357,26 @@ export default class AnnotationEditable extends React.Component { ] } + private renderMarkdownHelpButton() { + const setPickerShown = (isMarkdownHelpShown: boolean) => + this.setState({ isMarkdownHelpShown }) + return ( + + + + setPickerShown(!this.state.isMarkdownHelpShown) + } + /> + + + ) + } + private renderFooter() { const { mode, @@ -382,19 +425,22 @@ export default class AnnotationEditable extends React.Component { {mode === 'delete' && ( Really? )} - - - - Cancel - - - - {confirmBtn} - - + + + + + Cancel + + + + {confirmBtn} + + + {this.renderMarkdownHelpButton()} + ) } @@ -410,8 +456,10 @@ export default class AnnotationEditable extends React.Component { }} > - {this.renderHighlightBody()} - {this.renderNote()} + + {this.renderHighlightBody()} + {this.renderNote()} + { + {!this.state.isMarkdownHelpShown ? null : ( + + + + )} ) } @@ -495,6 +553,24 @@ const EditNoteIcon = styled.div` mask-size: 16px; cursor: pointer; ` +const MarkdownButtonContainer = styled.div` + display: flex; +` + +const MarkdownButton = styled.img` + display: flex; + height: 16px; + opacity: 0.8; + mask-position: center center; + margin-left: 10px; + cursor: pointer; +` + +const SaveActionBar = styled.div` + display: flex; + justify-content: flex-start; + align-items: center; +` const HighlightActionsBox = styled.div` position: absolute; @@ -507,7 +583,6 @@ const HighlightActionsBox = styled.div` const NoteTextBox = styled.div` position: relative; - min-height: 30px; display: flex; justify-content: space-between; align-items: center; @@ -517,14 +592,6 @@ const NoteTextBox = styled.div` word-break: break-word; hyphens: auto; width: 100%; - - & *:first-child { - margin-top: 0px; - } - - & *:last-child { - margin-bottom: 0px; - } ` const NoteText = styled(Markdown)` @@ -608,10 +675,10 @@ const CommentBox = styled.div` word-wrap: break-word; white-space: pre-wrap; margin: 0px; - padding: 10px 15px 10px 15px; + padding: 15px 15px 15px 15px; line-height: 1.4; text-align: left; - border-top: 1px solid #e0e0e0; + border-top: 1px solid #f0f0f0; overflow: visible; flex-direction: row-reverse; display: flex; @@ -631,7 +698,7 @@ const CommentBox = styled.div` const DefaultFooterStyled = styled.div` display: flex; - border-top: 1px solid #e0e0e0; + border-top: 1px solid #f0f0f0; & div { border-top: none; @@ -664,6 +731,12 @@ const AnnotationStyled = styled.div` `}; ` +const ContentContainer = styled.div` + display: flex; + box-sizing: border-box; + flex-direction: column; +` + const DeleteConfirmStyled = styled.span` box-sizing: border-box; font-weight: 800; @@ -697,7 +770,7 @@ const BtnContainerStyled = styled.div` flex-direction: row-reverse; width: 100%; justify-content: flex-end; - padding: 0 5px 5px; + align-items: center; ` const ActionBtnStyled = styled.button` @@ -729,5 +802,7 @@ const ActionBtnStyled = styled.button` const DeletionBox = styled.div` display: flex; justify-content: space-between; - padding-left: 10px; + border-top: 1px solid #f0f0f0; + padding: 5px; +} ` diff --git a/src/annotations/components/HoverControlledAnnotationCreate.tsx b/src/annotations/components/HoverControlledAnnotationCreate.tsx new file mode 100644 index 0000000000..84590312a5 --- /dev/null +++ b/src/annotations/components/HoverControlledAnnotationCreate.tsx @@ -0,0 +1,37 @@ +import React from 'react' + +import AnnotationCreate, { Props } from './AnnotationCreate' +import { NoteResultHoverState } from './types' + +export * from './AnnotationCreate' + +interface State { + hoverState: NoteResultHoverState +} + +export default class HoverControlledAnnotationEditable extends React.Component< + Props, + State +> { + static defaultProps = AnnotationCreate + + state: State = { hoverState: null } + + private setHoverState: ( + hoverState: NoteResultHoverState, + ) => React.MouseEventHandler = (hoverState) => (e) => + this.setState({ hoverState }) + + render() { + return ( + + ) + } +} diff --git a/src/annotations/components/MarkdownHelp.tsx b/src/annotations/components/MarkdownHelp.tsx new file mode 100644 index 0000000000..045121f18b --- /dev/null +++ b/src/annotations/components/MarkdownHelp.tsx @@ -0,0 +1,285 @@ +import * as React from 'react' +import styled from 'styled-components' +import onClickOutside from 'react-onclickoutside' +import { getKeyName } from 'src/util/os-specific-key-names' + +interface Props {} + +interface State {} + +export class MarkdownHelp extends React.Component { + static MOD_KEY = getKeyName({ key: 'mod' }) + static ALT_KEY = getKeyName({ key: 'alt' }) + + render() { + return ( + + + Editor Formatting + + + Bold + + **bold** + + {MarkdownHelp.MOD_KEY}+B + + + + + Italic + + *italic* + + {MarkdownHelp.MOD_KEY}+I + + + + + + Link + + + Highlight text and paste url + + {MarkdownHelp.MOD_KEY}+V + + + + YouTube timestamp + + + [1:15] + + + + In Editor:
+ {MarkdownHelp.MOD_KEY}+Y + + + + +
    +
  1. Ordered List
  2. +
+ + 1. Item One + + + {MarkdownHelp.MOD_KEY}+shift+7 + + + + + +
    +
  • Bullet List
  • +
+ + - Item One or * Item One + + + {MarkdownHelp.MOD_KEY}+shift+8 + + + + + +
Block Quote
+ + > this is the quote + + + {MarkdownHelp.MOD_KEY}+shift+b + + + + + +

Heading 1

+ + # Heading 1 + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+1 + + + + + +

Heading 2

+ + ## Heading 2 + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+2 + + + + + +

Heading 3

+ + ### Heading 3 + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+3 + + + + + + Inline Code + + `inline Code` + + + {MarkdownHelp.MOD_KEY}+shift+E + + + + + + + Multi-Line
+ Code Block +
+ + ```code blocks``` + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+C + + + + + + Strikethrough + + ~~Strikethrough~~ + + + {MarkdownHelp.MOD_KEY}+shift+X + + + +
+
+ ) + } +} + +const TutorialTable = styled.table` + width: 100%; + + & tr { + height: 40px; + display: flex; + justify-content: space-between; + align-items: center; + } + + td:first-child { + width: 50px; + white-space: nowrap; + } + + td:nth-child(2) { + white-space: nowrap; + text-align: center; + } + + & td:last-child { + display: flex; + justify-content: flex-end; + width: 50px; + font-size: 14px; + white-space: nowrap; + display: flex; + align-items: center; + + & span { + margin-right: 5px; + } + } + + & code { + padding: 2px 3px 1px; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + color: #e01e5a; + font-size: 14px; + font-family: Monaco, Menlo, Consolas, Courier New, monospace !important; + } + + & ul { + margin-inline-start: -20px; + } + + & ol { + margin-inline-start: -20px; + } + + & h1 { + font-size: 18px; + } + + & h2 { + font-size: 16px; + } + + & h3 { + font-size: 14px; + } + + & blockquote { + border-left: #5cd9a6 3px solid; + margin-inline-start: 0px; + margin-inline-end: 0px; + padding-left: 10px; + } +` + +const CodeBlock = styled.pre` + width: fit-content; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + padding: 5px; + font-family: 'Monaco', 'Menlo', 'Consolas', 'Courier New', monospace !important; + } +` + +const Highlight = styled.div` + background-color: yellow; +` + +const Link = styled.a`` + +const ShortCuts = styled.div` + border: 1px solid #f29d9d; + border-radius: 3px; + padding: 2px 5px; + font-size: 12px; + width: fit-content; + align-self: flex-end; + background-color: #f29d9d60; +` + +const FormattingTitle = styled.div` + font-size: 16px; + color: #c0c0c0; + display: flex; + justify-content: space-between; + align-items: center; +` + +const MarkdownHelpContainer = styled.div` + padding: 15px; +` + +export default onClickOutside(MarkdownHelp) diff --git a/src/annotations/components/editor/YoutubeInsert.tsx b/src/annotations/components/editor/YoutubeInsert.tsx new file mode 100644 index 0000000000..c593878a70 --- /dev/null +++ b/src/annotations/components/editor/YoutubeInsert.tsx @@ -0,0 +1,19 @@ +import { extractIdFromUrl, isUrlYTVideo } from 'src/util/youtube-url' + +export const GetYoutubeTimeStamp = () => { + const videoEl = document.querySelector('.video-stream') + + const timestampSecs = Math.trunc(videoEl?.currentTime ?? 0) + const humanTimestamp = `${Math.floor(timestampSecs / 60)}:${( + timestampSecs % 60 + ) + .toString() + .padStart(2, '0')}` + + const videoId = extractIdFromUrl(document.location.href) + const videoURLwithTime = `https://youtu.be/${videoId}?t=${timestampSecs}` + + const YoutubeData = [videoURLwithTime, humanTimestamp] + + return YoutubeData +} diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx new file mode 100644 index 0000000000..e8f924b375 --- /dev/null +++ b/src/annotations/components/editor/editor.tsx @@ -0,0 +1,180 @@ +import React, { useRef, useEffect } from 'react' +import TurndownService from 'turndown' +import { marked } from 'marked' +import { + useEditor, + EditorContent, + BubbleMenu, + FloatingMenu, +} from '@tiptap/react' +import StarterKit from '@tiptap/starter-kit' +import Typography from '@tiptap/extension-typography' +import Placeholder from '@tiptap/extension-placeholder' +import Link from '@tiptap/extension-link' +import CodeBlock from '@tiptap/extension-code-block' +import Heading from '@tiptap/extension-heading' +import Image from '@tiptap/extension-image' +import { GetYoutubeTimeStamp } from './YoutubeInsert' + +import './styles.css' + +const turndownService = new TurndownService({ + headingStyle: 'atx', + hr: '---', + codeBlockStyle: 'fenced', +}) + +export interface MemexEditorInstance { + resetState: () => void +} + +interface Props { + markdownContent: string + placeholder?: string + onKeyDown?: React.KeyboardEventHandler + onContentUpdate: (markdownContent: string) => void + setEditorInstanceRef?: (instance: MemexEditorInstance) => void + toggleMarkdownHelp?: () => void +} + +const MemexEditor = (props: Props) => { + const renderer = { + image(url) { + return ` + {'test'}/ + ` + }, + } + marked.use({ renderer }) + + const InsertYoutubeLink = Link.extend({ + addKeyboardShortcuts() { + return { + // ↓ your new keyboard shortcut + 'Mod-y': () => + this.editor + .chain() + .insertContent( + `${ + GetYoutubeTimeStamp()[1] + }`, + ) + .run(), + } + }, + }) + + const editor = useEditor({ + extensions: [ + StarterKit.configure({ + codeBlock: false, + heading: false, + }), + Typography, + InsertYoutubeLink, + CodeBlock.configure({ + HTMLAttributes: { + class: 'CodeBlock', + }, + }), + Heading.configure({ + levels: [1, 2, 3], + }), + Link.configure({ + linkOnPaste: true, + }), + Placeholder.configure({ + placeholder: props.placeholder, + emptyEditorClass: 'is-editor-empty', + }), + Image.configure({ + inline: true, + }), + ], + content: marked.parse(props.markdownContent), + onCreate: ({ editor }) => { + editor.commands.focus('end') + console.log(getTextToInsert()[1]) + console.log(getTextToInsert()[0]) + }, + onUpdate: ({ editor }) => { + const htmlContent = editor.getHTML() + const markdownContent = turndownService.turndown(htmlContent) + props.onContentUpdate(markdownContent) + }, + autofocus: true, + editorProps: props.onKeyDown + ? { + handleDOMEvents: { + keydown: (view, event) => { + // NOTE: this seems to be typed incorrectly + // removing the 'as any's will throw errors at you, + // but fixing them result in editor KB shortcuts stop working + return props.onKeyDown(event as any) as any + }, + }, + } + : undefined, + }) + const memexEditorRef = useRef() + + useEffect(() => { + memexEditorRef.current = { + resetState: () => { + editor.commands.clearContent() + }, + } + + props.setEditorInstanceRef?.(memexEditorRef.current) + }, [editor]) + + return ( + <> + + {editor && ( + + + + + + + )} + + + ) +} + +export default MemexEditor diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css new file mode 100644 index 0000000000..c7b384a6e7 --- /dev/null +++ b/src/annotations/components/editor/styles.css @@ -0,0 +1,209 @@ +/* stylelint-disable declaration-no-important, selector-pseudo-class-no-unknown */ + +:global .ProseMirror p.is-editor-empty:first-child::before { + content: attr(data-placeholder); + float: left; + color: #adb5bd; + pointer-events: none; + height: 0; +} + +:global .ProseMirrorContainer { + min-height: 50px; + resize: vertical; + border-top: 1px solid #f0f0f0; + + &:first-child { + border-top: none; + } + + & > div { + background-color: white; + border: none; + border-radius: 3px; + } +} + +:global .ProseMirror { + outline: none; + padding: 15px 15px; + width: fill-available; + background-color: #f0f0f07a; + border-radius: 3px; + border: 1px solid #e0e0e0; + + &:focus { + border-radius: 3px; + } + + & * { + width: fill-available; + } + + & ul { + margin-block-start: 0.5em; + margin-block-end: 0.5em; + } + + & p { + margin-block-start: 0.5em; + margin-block-end: 0.5em; + line-height: 20px; + + & img { + max-width: fill-available; + height: auto; + } + } + + & h1 { + margin-block-start: 1em; + margin-block-end: 0.5em; + line-height: 22px; + font-size: 18px; + } + + & img { + max-width: fill-available; + height: auto; + } + + & h2 { + margin-block-start: 1em; + margin-block-end: 0.5em; + line-height: 22px; + font-size: 16px; + } + + & h3 { + margin-block-start: 1em; + margin-block-end: 0.5em; + line-height: 22px; + font-size: 14px; + } + + & h4 { + margin-block-start: 1em; + margin-block-end: 0.5em; + } + + & h5 { + margin-block-start: 1em; + margin-block-end: 0.5em; + } + + & blockquote { + border-left: #5cd9a6 3px solid; + margin-inline-start: 10px; + padding-left: 10px; + } + + & code { + padding: 2px 3px 1px; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + color: #e01e5a; + font-family: 'Monaco', 'Menlo', 'Consolas', 'Courier New', monospace !important; + } + + & pre { + width: fill-available; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + padding: 10px; + font-family: 'Monaco', 'Menlo', 'Consolas', 'Courier New', monospace !important; + + & code { + width: 100%; + padding: unset; + border: none; + border-radius: unset; + background-color: unset; + color: inherit; + } + } + + & > *:first-child { + margin-block-start: 0em; + } + + & > *:last-child { + margin-block-end: 0em; + } +} + +:global .bubble-menu { + display: flex; + background-color: #2a2a2a; + padding: 0.2rem; + border-radius: 0.5rem; + font-family: sans-serif; + cursor: pointer; + + & > * { + all: initial; + line-height: 20px; + } + + & button { + border: none; + background: #2a2a2a; + color: #fff; + font-size: 0.85rem; + font-family: sans-serif; + font-weight: 500; + padding: 1px 0.2rem 0 0.2rem; + cursor: pointer; + + &:hover, + &.is-active { + opacity: 1; + color: #d0d0d0; + text-decoration: solid 1px underline; + } + } +} + +:global .floating-menu { + display: flex; + padding: 0.2rem; + border-radius: 0.5rem; + font-family: sans-serif; + + & > * { + all: initial; + line-height: 20px; + } + + & button { + border: none; + background: none; + font-size: 14px; + color: #a0a0a0; + font-weight: 500; + padding: 0 0.2rem; + font-family: sans-serif; + + &:hover, + &.is-active { + opacity: 1; + } + + &:focus { + text-decoration: underline 1px solid #a0a0a0; + } + + &.is-active { + color: #545454; + } + } + + & .NoNotePlaceholder { + font-size: 14px; + color: #818181; + margin-right: 10px; + margin-left: -5px; + } +} diff --git a/src/common-ui/components/design-library/HoverBox.tsx b/src/common-ui/components/design-library/HoverBox.tsx index b0f7a1dcd8..1039ad43f3 100644 --- a/src/common-ui/components/design-library/HoverBox.tsx +++ b/src/common-ui/components/design-library/HoverBox.tsx @@ -8,6 +8,7 @@ export interface Props { bottom?: string width?: string withRelativeContainer?: boolean + position?: string } export class HoverBox extends React.Component { @@ -34,7 +35,7 @@ export const HoverBoxDiv = styled.div` box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px; overflow: visible; - position: absolute; + position: ${(props) => (props.position ? props.position : 'absolute')};; border-radius: 3px; width: ${(props) => (props.width ? props.width : '300px')}; ${(props) => (props.top ? `top: ${props.top};` : '')} diff --git a/src/common-ui/components/result-item-tags-segment.tsx b/src/common-ui/components/result-item-tags-segment.tsx index 244aafec8f..eeb8cd12f2 100644 --- a/src/common-ui/components/result-item-tags-segment.tsx +++ b/src/common-ui/components/result-item-tags-segment.tsx @@ -5,7 +5,6 @@ import * as icons from 'src/common-ui/components/design-library/icons' export interface Props extends Pick, 'onMouseEnter'> { tags: string[] - maxTags?: number showEditBtn: boolean onTagClick?: (tag: string) => void onEditBtnClick: React.MouseEventHandler @@ -13,7 +12,6 @@ export interface Props extends Pick, 'onMouseEnter'> { export default function TagsSegment({ tags, - maxTags = 8, onTagClick, showEditBtn, onEditBtnClick, @@ -26,7 +24,7 @@ export default function TagsSegment({ return ( - {tags.slice(0, maxTags).map((tag) => ( + {tags.slice(0).map((tag) => ( onTagClick(tag) : undefined} @@ -41,15 +39,16 @@ export default function TagsSegment({ } const Container = styled.div` - display: flex; + display: inline-box; align-items: center; justify-content: space-between; - border-top: 1px solid #e0e0e0; + border-top: 1px solid #f0f0f0; padding: 5px 15px; ` const TagsContainer = styled.div` display: flex; + flex-wrap: wrap; ` const TagPill = styled.div` @@ -81,4 +80,7 @@ const EditIcon = styled.button` mask-repeat: no-repeat; mask-size: 16px; cursor: pointer; + right: 30px; + position: relative; + z-index: 10; ` diff --git a/src/dashboard-refactor/lists-sidebar/index.tsx b/src/dashboard-refactor/lists-sidebar/index.tsx index 23ceac870e..2370dc4e18 100644 --- a/src/dashboard-refactor/lists-sidebar/index.tsx +++ b/src/dashboard-refactor/lists-sidebar/index.tsx @@ -134,7 +134,6 @@ export default class ListsSidebar extends PureComponent { searchBarProps, listsGroups, } = this.props - console.log(listsGroups) return ( void + onKeyDown: () => void } export class MarkdownPreviewAnnotationInsertMenu extends React.PureComponent< diff --git a/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx b/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx index bf6d3995c1..a489339809 100644 --- a/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx +++ b/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx @@ -22,6 +22,8 @@ import { AnnotationEditGeneralProps, AnnotationEditEventProps, } from 'src/annotations/components/AnnotationEdit' +import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' +import MarkdownHelp from 'src/annotations/components/MarkdownHelp' import type { AnnotationSharingAccess } from 'src/content-sharing/ui/types' import type { SidebarContainerState } from '../containers/types' import { ExternalLink } from 'src/common-ui/components/design-library/actions/ExternalLink' @@ -70,6 +72,7 @@ export interface AnnotationsSidebarProps interface AnnotationsSidebarState { searchText?: string + isMarkdownHelpShown?: boolean } class AnnotationsSidebar extends React.Component< @@ -77,8 +80,12 @@ class AnnotationsSidebar extends React.Component< AnnotationsSidebarState > { private annotationCreateRef // TODO: Figure out how to properly type refs to onClickOutside HOCs + private annotationEditRef - state = { searchText: '' } + state = { + searchText: '', + isMarkdownHelpShown: false, + } componentDidMount() { document.addEventListener('keydown', this.onKeydown, false) @@ -90,6 +97,9 @@ class AnnotationsSidebar extends React.Component< focusCreateForm = () => this.annotationCreateRef?.getInstance()?.focus() + private toggleMarkdownHelp = () => + this.setState({ isMarkdownHelpShown: !this.state.isMarkdownHelpShown }) + private onKeydown = (e: KeyboardEvent) => { if (e.key === 'Escape') { this.props.onClickOutside(e as any) @@ -153,13 +163,24 @@ class AnnotationsSidebar extends React.Component< return ( - - (this.annotationCreateRef = ref)} - autoFocus - /> - + this.toggleMarkdownHelp()} + /> + {!this.state.isMarkdownHelpShown ? null : ( + + {/* setPickerShown(false)}>*/} + + {/**/} + + )} ) } @@ -373,30 +394,46 @@ class AnnotationsSidebar extends React.Component< const annots = this.props.annotations.map((annot, i) => { const footerDeps = this.props.bindAnnotationFooterEventProps(annot) return ( - + 0 + } + toggleMarkdownHelp={() => this.toggleMarkdownHelp()} + ref={(ref) => (this.annotationEditRef = ref)} + /> + {!this.state.isMarkdownHelpShown ? null : ( + (this.annotationEditRef = ref)} + > + {/* setPickerShown(false)}>*/} + + {/**/} + )} - annotationFooterDependencies={footerDeps} - isClickable={ - this.props.theme.canClickAnnotations && - annot.body?.length > 0 - } - /> + ) }) @@ -674,10 +711,6 @@ const AnnotationsSectionStyled = styled.section` const NewAnnotationBoxStyled = styled.div` position: relative; width: 100%; - - &:hover { - background: white; - } ` const TopSectionStyled = styled.div` diff --git a/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx b/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx index 8e08db62ed..ab22bf79c1 100644 --- a/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx +++ b/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx @@ -39,6 +39,7 @@ import Icon from '@worldbrain/memex-common/lib/common-ui/components/icon' import { sidebarNotesTypeToString } from '../utils' import { getListShareUrl } from 'src/content-sharing/utils' import { ClickAway } from 'src/util/click-away-wrapper' +import type { AnnotationMode } from 'src/sidebar/annotations-sidebar/types' const DEF_CONTEXT: { context: AnnotationEventContext } = { context: 'pageAnnotations', @@ -222,6 +223,7 @@ export class AnnotationsSidebarContainer< loadDefaultSuggestions: this.props.tags.fetchInitialTagSuggestions, comment: this.state.commentBox.commentText, tags: this.state.commentBox.tags, + hoverState: null, } } diff --git a/src/tags/ui/tag-holder.css b/src/tags/ui/tag-holder.css index d77adb637d..d55e8b4bd2 100644 --- a/src/tags/ui/tag-holder.css +++ b/src/tags/ui/tag-holder.css @@ -1,11 +1,10 @@ .tagHolder { position: relative; - display: inline-block; - justify-content: flex-start; + display: flex; + justify-content: center; align-items: center; box-sizing: border-box; cursor: pointer; - padding: 5px 10px 5px 15px; } .tag { @@ -22,7 +21,7 @@ .tagIcon { mask-image: url('/img/tag_empty.svg'); - mask-size: 15px; + mask-size: 16px; width: 20px; height: 20px; mask-repeat: no-repeat; @@ -30,13 +29,18 @@ background-color: #3a2f45; opacity: 0.6; display: flex; - margin-right: 5px; } .tagText { vertical-align: center; } +.tagHolderContainer { + & > div { + display: flex; + } +} + .placeholder { display: inline-flex; color: #888; @@ -45,12 +49,6 @@ align-items: center; padding: 2px 5px; border-radius: 3px; - margin-left: -10px; - - &:hover { - color: #3a2f45; - background-color: #e0e0e0; - } } .placeholder_alt { diff --git a/src/tags/ui/tag-holder.tsx b/src/tags/ui/tag-holder.tsx index 533eac47f3..f06c1344ce 100644 --- a/src/tags/ui/tag-holder.tsx +++ b/src/tags/ui/tag-holder.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import classNames from 'classnames' - +import { ButtonTooltip } from 'src/common-ui/components' import { maxPossibleTags } from 'src/sidebar/annotations-sidebar/utils' import { ClickHandler } from 'src/sidebar/annotations-sidebar/types' @@ -72,17 +72,19 @@ class TagHolder extends React.Component { const { tags, clickHandler } = this.props return ( -
- {this._renderTags()} - 0 && styles.placeholder_alt, - )} - > - {!tags.length && } - Add tag - +
+ +
+ 0 && styles.placeholder_alt, + )} + > + + +
+
) } diff --git a/tsconfig.jest.json b/tsconfig.jest.json index ea41fe93d3..ccaba2d9ce 100644 --- a/tsconfig.jest.json +++ b/tsconfig.jest.json @@ -4,6 +4,7 @@ "target": "ES6", "module": "commonjs", "sourceMap": false, - "inlineSourceMap": true + "inlineSourceMap": true, + "jsx": "react-jsx" } } diff --git a/yarn.lock b/yarn.lock index 62ab9c1aea..bc8840e38e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3316,6 +3316,11 @@ resolved "https://registry.yarnpkg.com/@panva/asn1.js/-/asn1.js-1.0.0.tgz#dd55ae7b8129e02049f009408b97c61ccf9032f6" integrity sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw== +"@popperjs/core@^2.9.0": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590" + integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -4175,6 +4180,213 @@ "@testing-library/dom" "^6.15.0" "@types/testing-library__react" "^9.1.2" +"@tiptap/core@^2.0.0-beta.138": + version "2.0.0-beta.138" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.138.tgz#3a73b32b10f07ba2842142552457b52abf8cfc41" + integrity sha512-Cg3ig6c+NCBILYaVNf5h8vJdsRynhKzy+zQzH/91kLoWzpNV5J6R2sW32Oufuwvr0Kra1+kKKh/WIGpB3Ia4RA== + dependencies: + "@types/prosemirror-commands" "^1.0.4" + "@types/prosemirror-keymap" "^1.0.4" + "@types/prosemirror-model" "^1.13.2" + "@types/prosemirror-schema-list" "^1.0.3" + "@types/prosemirror-state" "^1.2.8" + "@types/prosemirror-transform" "^1.1.4" + "@types/prosemirror-view" "^1.19.1" + prosemirror-commands "^1.1.12" + prosemirror-keymap "^1.1.5" + prosemirror-model "^1.15.0" + prosemirror-schema-list "^1.1.6" + prosemirror-state "^1.3.4" + prosemirror-transform "^1.3.3" + prosemirror-view "^1.22.0" + +"@tiptap/extension-blockquote@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.24.tgz#4dcaf676ded8c3b551efd8f2d6b51cc882ba7d03" + integrity sha512-u9D/ZOziO4rMBKeLj7JA7fOc9h8wU6zrzVEsX9MbJwmuicoJZ1lIQ9cyrFWwmlfznzuXLaAxm3iZuHt7xxMppQ== + +"@tiptap/extension-bold@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.24.tgz#a8d1076922580db528cc6988fde08f731dcfe733" + integrity sha512-2VTCtY2JI0wpDwWT0a2fMFkjbgxDpwD3wvtY3/ndh5pyNX0JQCXtJarFzfZZurWvLNQ8QPRRel73182RBYUOHQ== + +"@tiptap/extension-bubble-menu@^2.0.0-beta.49": + version "2.0.0-beta.49" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.49.tgz#f9863b1abad5f87d298d4e6527005484137a6166" + integrity sha512-JbaSG3otBuMKRyTn0OqVscZnwqJ7c+qyKAnoZJit5EK1RS72cTfGWZvvAxaslAM4DeE9avJeudUi/tN5Iafv4A== + dependencies: + prosemirror-state "^1.3.4" + prosemirror-view "^1.22.0" + tippy.js "^6.3.6" + +"@tiptap/extension-bullet-list@^2.0.0-beta.23": + version "2.0.0-beta.23" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.23.tgz#64698c98039ad301c94a9041bbd117e82957be21" + integrity sha512-ReoUiz9f1IX87RX+GRE+fCaLEzNNwmiP4kli3QH8/qrLK3qxvZYr9N31fUeOHecCctUofPSbQB79B39zSo9Ouw== + +"@tiptap/extension-code-block@^2.0.0-beta.29": + version "2.0.0-beta.29" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.29.tgz#ad7f537bc1f12decf027d66c7328f36a8b07795c" + integrity sha512-IoBJxqZ4F7dApRL3NisvMCBJmzpV0LmfJlFQacgm64Li15dP/QyDuvXpku03gT3y9e4f9Gv/KTKwJizXEVABhw== + dependencies: + prosemirror-state "^1.3.4" + +"@tiptap/extension-code@^2.0.0-beta.25": + version "2.0.0-beta.25" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.25.tgz#055dc8dc6d19d3f0439f57dd8ba6433e2f2fd733" + integrity sha512-kXBR4Zp79lpUEfqJtBGv9tO1mj9jFQLMj0iVhj8e8ZporNKei5JfDOY83kwFcKAE60i7tiRDtV3OizpAKMeqDg== + +"@tiptap/extension-document@^2.0.0-beta.15": + version "2.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.15.tgz#5d17a0289244a913ab2ef08e8495a1e46950711e" + integrity sha512-ypENC+xUYD5m2t+KOKNYqyXnanXd5fxyIyhR1qeEEwwQwMXGNrO3kCH6O4mIDCpy+/WqHvVay2tV5dVsXnvY8w== + +"@tiptap/extension-dropcursor@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.24.tgz#e0263c8d784304cb885aea299bfd5255d3435765" + integrity sha512-B4bzY84g82VY78kv6BFNSCgO9Sc3dtgkvzFDJ57X2QweYyLkXbYeZxI8SqO7Nva1QRZadBlFyRPm+aP1rLZsew== + dependencies: + "@types/prosemirror-dropcursor" "^1.0.3" + prosemirror-dropcursor "^1.3.5" + +"@tiptap/extension-floating-menu@^2.0.0-beta.44": + version "2.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.44.tgz#fca9eefd9bcc74fdf035b012b9eb9fbfda331cf1" + integrity sha512-R8EF6XXlwoiHvCuXV3qGsEKae5u0OYrKHJNeOgau5SANg/ab+pjFzr3Lrt43NFpOKf5rzD3p2OJxnikudceLSg== + dependencies: + prosemirror-state "^1.3.4" + prosemirror-view "^1.22.0" + tippy.js "^6.3.6" + +"@tiptap/extension-gapcursor@^2.0.0-beta.33": + version "2.0.0-beta.33" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.33.tgz#99414204e61655d4df61efc27823732176719532" + integrity sha512-Yu6BJ1bseyXIgLlcw/2R/2wWe1mIQilMwW7hhfDJPLbFwLJrMINtA9hxd2qY7mtW19/CveT5HOihQS6QEk59iw== + dependencies: + "@types/prosemirror-gapcursor" "^1.0.4" + prosemirror-gapcursor "^1.2.0" + +"@tiptap/extension-hard-break@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.30.tgz#165494f1194a7bad08907e6d64d349dd15851b72" + integrity sha512-X9xj/S+CikrbIE7ccUFVwit5QHEbflnKVxod+4zPwr1cxogFbE9AyLZE2MpYdx3z9LcnTYYi9leBqFrP4T/Olw== + +"@tiptap/extension-heading@^2.0.0-beta.23": + version "2.0.0-beta.23" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.23.tgz#8aafadc58a8d536b7f7885e4ff0f64d30908a868" + integrity sha512-/WLymJjY+MMvee79rWHSKDBGVRw4dbBUMrFLqKLjQQBS1xS8+UW2TYzRrAH6HAH4Tc6WO39ZDbd9K9kc9wqPnA== + +"@tiptap/extension-highlight@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.30.tgz#7a245214021356220839f852b4d28dabbd1f029e" + integrity sha512-68hMjVDUmj0UhTtq2Kp6BiTb9JPhpjT+HXHMch5SkZaoiLVfTleMF1jECU1HsDGs/hnktkCshUQN6BLJqo+4pg== + +"@tiptap/extension-history@^2.0.0-beta.21": + version "2.0.0-beta.21" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.21.tgz#5d96a17a83a7130744f0757a3275dd5b11eb1bf7" + integrity sha512-0v8Cl30V4dsabdpspLdk+f+lMoIvLFlJN5WRxtc7RRZ5gfJVxPHwooIKdvC51brfh/oJtWFCNMRjhoz0fRaF9A== + dependencies: + "@types/prosemirror-history" "^1.0.3" + prosemirror-history "^1.2.0" + +"@tiptap/extension-horizontal-rule@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.30.tgz#56d497f1187384d131f3f3320f30748c1e4b766f" + integrity sha512-h/PlkvfcMuoBGRfD7Cbeh8mxZiEc2pKveLDwOfCES9TKV5i2lqcIgctpohWyISuFcTq4K+OFgr910+Rsp8qwEg== + dependencies: + prosemirror-state "^1.3.4" + +"@tiptap/extension-image@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.24.tgz#1010676f79925cbe11a44b6d8eee1251910fbc1d" + integrity sha512-7oiX/Ovj9WN4xTBqWbQWd4H3SUO2eNzOiKHebVo3eqWG8NxzOGfuU0iRCENtEa7vTiRrFgyeBotneMALDpDnTQ== + +"@tiptap/extension-italic@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.24.tgz#0a08d06dbd8dbf10f18ed17f019aa42d7ac9dbe0" + integrity sha512-pMAWFaLFb0Z0SC5pjoTKzC6m4CQOdUYeVlHvTS/550Z9lf8cqMawQ8H6Yk6brIuANyh7iUi4/zpq4H4rAdUCuw== + +"@tiptap/extension-link@^2.0.0-beta.28": + version "2.0.0-beta.28" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.28.tgz#4385f36b6bb31fab34a86fb7c686ca05a37ed572" + integrity sha512-dZNaEjoDhgjmts44KqgtOYObCdDYZq/yFhsZ8QfqEgNHJMvBNTDaPXwBDW9i3BTkkyLTmwR/qwWxqDrfDdKh2A== + dependencies: + linkifyjs "^3.0.3" + prosemirror-state "^1.3.4" + +"@tiptap/extension-list-item@^2.0.0-beta.19": + version "2.0.0-beta.19" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.19.tgz#657f2c5624a30f3effff723f4fadb0851a61dab8" + integrity sha512-z/5NrRKwwJc2ZkgoGxRQmA/VENxQugZoxKhUu2qoUdg5cJRcW+ERoKTiY1/AR+4M2k1izNWQMIz3nQNWMx1kQA== + +"@tiptap/extension-ordered-list@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.24.tgz#69c56e2cfbf582b338d5dbc94c5eda4593775cb5" + integrity sha512-pXgwV+vuBAHMBGnUPa8fjxHapGCitfBJ1k8o3XvhotO7243Y7KOfYT7kg6XrY6dmTwCX2WLkIc912PP/E60y3A== + +"@tiptap/extension-paragraph@^2.0.0-beta.22": + version "2.0.0-beta.22" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.22.tgz#7740fb6393296ec58e98332b2855ebdc3fd05226" + integrity sha512-BY6GWHlMvGiXLgPHcfZRUHKzMi1jKw3i1JrpMEQ8JLwYD3koI/6UOB/qphwUJkCkIPQXNkZw4/aSBxL9uChRDg== + +"@tiptap/extension-placeholder@^2.0.0-beta.43": + version "2.0.0-beta.43" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.0-beta.43.tgz#8ea1dff868a9389950b31112a12ff7b869ffe531" + integrity sha512-EhZgkFClmHap8Bt9ChhAHGbTF+xvR0ZE/Y+xN8wEK73PUEHYYh8QBpAy1hTrgM+gQoO4AEIGNeT/7VvL2Ge7FQ== + dependencies: + prosemirror-model "^1.15.0" + prosemirror-state "^1.3.4" + prosemirror-view "^1.22.0" + +"@tiptap/extension-strike@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.26.tgz#19eda1a61706ac9690ecbc794c711deb4e1efc3e" + integrity sha512-BA+oqqYOZzRLiMYlHX6BJXlIGaNIR9LObgkHEXAj/JPK7do4wDOcuVaw+dlWS+tzvTebLbC9GYAALfNqVBlTwA== + +"@tiptap/extension-text@^2.0.0-beta.15": + version "2.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.15.tgz#f08cff1b78f1c6996464dfba1fef8ec1e107617f" + integrity sha512-S3j2+HyV2gsXZP8Wg/HA+YVXQsZ3nrXgBM9HmGAxB0ESOO50l7LWfip0f3qcw1oRlh5H3iLPkA6/f7clD2/TFA== + +"@tiptap/extension-typography@^2.0.0-beta.19": + version "2.0.0-beta.19" + resolved "https://registry.yarnpkg.com/@tiptap/extension-typography/-/extension-typography-2.0.0-beta.19.tgz#3a3cf25590b7d84bcf40525d558ab5997c554b3d" + integrity sha512-9Y3or/X0IkHqfJg1eOqqMiPFgXKQKNOwDy+xN6qhORQSUzCPOCHttAUdp8AN/WUEQOoOK4uaRida8ik1ATK7ZQ== + +"@tiptap/react@^2.0.0-beta.93": + version "2.0.0-beta.93" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.0.0-beta.93.tgz#353087e4254a996c906fd76fcdfc2af32ae68faa" + integrity sha512-kI3FV51IuP9njD3ZopGBaUhcQ0l+em36mK3HUM50fiFPOOyF5tCUtF6/AI+gw3ivUbBwLC13YfHEj1OnKkkjWQ== + dependencies: + "@tiptap/extension-bubble-menu" "^2.0.0-beta.49" + "@tiptap/extension-floating-menu" "^2.0.0-beta.44" + prosemirror-view "^1.22.0" + +"@tiptap/starter-kit@^2.0.0-beta.140": + version "2.0.0-beta.140" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.140.tgz#4610a28084742f3512ea7cbb8e8f2b2428690013" + integrity sha512-19E5duT0rRcp2SHZK0OYiIEjnYLn+Lf1GBBnsTFRoze8mHP2Zym11HmcpW6iyuaWj9mPFjlXJJr6yTc0HmpPpA== + dependencies: + "@tiptap/core" "^2.0.0-beta.138" + "@tiptap/extension-blockquote" "^2.0.0-beta.24" + "@tiptap/extension-bold" "^2.0.0-beta.24" + "@tiptap/extension-bullet-list" "^2.0.0-beta.23" + "@tiptap/extension-code" "^2.0.0-beta.25" + "@tiptap/extension-code-block" "^2.0.0-beta.29" + "@tiptap/extension-document" "^2.0.0-beta.15" + "@tiptap/extension-dropcursor" "^2.0.0-beta.24" + "@tiptap/extension-gapcursor" "^2.0.0-beta.33" + "@tiptap/extension-hard-break" "^2.0.0-beta.30" + "@tiptap/extension-heading" "^2.0.0-beta.23" + "@tiptap/extension-history" "^2.0.0-beta.21" + "@tiptap/extension-horizontal-rule" "^2.0.0-beta.30" + "@tiptap/extension-italic" "^2.0.0-beta.24" + "@tiptap/extension-list-item" "^2.0.0-beta.19" + "@tiptap/extension-ordered-list" "^2.0.0-beta.24" + "@tiptap/extension-paragraph" "^2.0.0-beta.22" + "@tiptap/extension-strike" "^2.0.0-beta.26" + "@tiptap/extension-text" "^2.0.0-beta.15" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -4427,6 +4639,11 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== +"@types/marked@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.0.tgz#2e7036d348adc7f5916946349596194b99eb4673" + integrity sha512-Zuz0vlQDfPuop4aFFWFdFTTpVmFqkwAQJ4Onxmgc2ZMxhgaO0UxEwWpz23uHXd9QhwsFB1BJBmWNjheZmqdBuQ== + "@types/mdast@^3.0.0", "@types/mdast@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb" @@ -4488,6 +4705,11 @@ dependencies: "@types/bn.js" "*" +"@types/orderedmap@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/orderedmap/-/orderedmap-1.0.0.tgz#807455a192bba52cbbb4517044bc82bdbfa8c596" + integrity sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw== + "@types/pdfjs-dist@^2.1.6": version "2.1.7" resolved "https://registry.yarnpkg.com/@types/pdfjs-dist/-/pdfjs-dist-2.1.7.tgz#a92d94b9d699a93ab8a762839f7819dc04e96484" @@ -4504,6 +4726,89 @@ dependencies: "@types/react" "*" +"@types/prosemirror-commands@*", "@types/prosemirror-commands@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz#d08551415127d93ae62e7239d30db0b5e7208e22" + integrity sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-dropcursor@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz#49250849b8a0b86e8c29eb1ba70a463e53e46947" + integrity sha512-b0/8njnJ4lwyHKcGuCMf3x7r1KjxyugB1R/c2iMCjplsJHSC7UY9+OysqgJR5uUXRekUSGniiLgBtac/lvH6wg== + dependencies: + "@types/prosemirror-state" "*" + +"@types/prosemirror-gapcursor@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz#7df7d373edb33ea8da12084bfd462cf84cd69761" + integrity sha512-9xKjFIG5947dzerFvkLWp6F53JwrUYoYwh3SgcTFEp8SbSfNNrez/PFYVZKPnoqPoaK5WtTdQTaMwpCV9rXQIg== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-history@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-history/-/prosemirror-history-1.0.3.tgz#f1110efbe758129b5475e466ff077f0a8d9b964f" + integrity sha512-5TloMDRavgLjOAKXp1Li8u0xcsspzbT1Cm9F2pwHOkgvQOz1jWQb2VIXO7RVNsFjLBZdIXlyfSLivro3DuMWXg== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-keymap@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz#f73c79810e8d0e0a20d153d84f998f02e5afbc0c" + integrity sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg== + dependencies: + "@types/prosemirror-commands" "*" + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-model@*", "@types/prosemirror-model@^1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@types/prosemirror-model/-/prosemirror-model-1.13.2.tgz#2adad3ec478f83204f155d7fb94c9dfde2fc3296" + integrity sha512-a2rDB0aZ+7aIP7uBqQq1wLb4Hg4qqEvpkCqvhsgT/gG8IWC0peCAZfQ24sgTco0qSJLeDgIbtPeU6mgr869/kg== + dependencies: + "@types/orderedmap" "*" + +"@types/prosemirror-schema-list@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz#bdf1893a7915fbdc5c49b3cac9368e96213d70de" + integrity sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA== + dependencies: + "@types/orderedmap" "*" + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.8.tgz#65080eeec52f63c50bf7034377f07773b4f6b2ac" + integrity sha512-mq9uyQWcpu8jeamO6Callrdvf/e1H/aRLR2kZWSpZrPHctEsxWHBbluD/wqVjXBRIOoMHLf6ZvOkrkmGLoCHVA== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-transform" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-transform@*", "@types/prosemirror-transform@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-transform/-/prosemirror-transform-1.1.4.tgz#c3565e81b2ef3ce3254e6927d6f63eb8d7bb20d0" + integrity sha512-HP1PauvkqSgDquZut8HaLOTUDQ6jja/LAy4OA7tTS1XG7wqRnX3gLUyEj0mD6vFd4y8BPkNddNdOh/BeGHlUjg== + dependencies: + "@types/prosemirror-model" "*" + +"@types/prosemirror-view@*", "@types/prosemirror-view@^1.19.1": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.19.1.tgz#f12309ef07dfb701d20c2e4d0292d42ba34a081b" + integrity sha512-fyQ4NVxAdfISWrE2qT8cpZdosXoH/1JuVYMBs9CdaXPbvi/8R2L2tkkcMRM314piKrO8nfYH5OBZKzP2Ax3jtA== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-transform" "*" + "@types/q@^1.5.1": version "1.5.2" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" @@ -4693,6 +4998,11 @@ "@types/testing-library__dom" "*" pretty-format "^25.1.0" +"@types/turndown@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/turndown/-/turndown-5.0.1.tgz#fcda7b02cda4c9d445be1440036df20f335b9387" + integrity sha512-N8Ad4e3oJxh9n9BiZx9cbe/0M3kqDpOTm2wzj13wdDUxDPjfjloWIJaquZzWE1cYTAHpjOH3rcTnXQdpEfS/SQ== + "@types/ua-parser-js@^0.7.36": version "0.7.36" resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz#9bd0b47f26b5a3151be21ba4ce9f5fa457c5f190" @@ -9601,6 +9911,11 @@ domhandler@^4.0.0, domhandler@^4.1.0, domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" +domino@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe" + integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ== + dompurify@^2.0.11: version "2.0.11" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.11.tgz#cd47935774230c5e478b183a572e726300b3891d" @@ -13000,6 +13315,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indento@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/indento/-/indento-1.1.13.tgz#751331b327c04740eeb7be40c5606e6e255c9e36" + integrity sha512-YZWk3mreBEM7sBPddsiQnW9Z8SGg/gNpFfscJq00HCDS7pxcQWWWMSVKJU7YkTRyDu1Zv2s8zaK8gQWKmCXHlg== + index-of@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/index-of/-/index-of-0.2.0.tgz#38c1e2367ea55dffad3b6eb592ec1cc3090d7d65" @@ -14997,6 +15317,13 @@ json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" +json2md@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/json2md/-/json2md-1.12.0.tgz#3ac0a2f8f5af140d6f29d91ab1107ca696305165" + integrity sha512-bpJpuqECzkndCa10aGPxeJNikmkDN7PAGXHvrBGTI4uey6QbTL5p0rkhk9lB3lKU4J7yGvkSmVBt8VhzUGu/fA== + dependencies: + indento "^1.1.13" + json3@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" @@ -15343,6 +15670,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +linkifyjs@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-3.0.3.tgz#51ea2160b4c60c2c87c27757a1e9eacd422c6076" + integrity sha512-ba5opS5wRHSbDC8VaiDdN14nPGm6LqyRsIPQZGG4qXV4scFdrPneT/uoZOaq9QAPBf6W9I9D/6tNSzWH//815Q== + listenercount@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" @@ -15984,6 +16316,11 @@ marked@^0.7.0: resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e" integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg== +marked@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.3.tgz#986760a428d8fd666251ec578429bf9a239a34bc" + integrity sha512-vSwKKtw+lCA0uFK/02JT4tBfNxEREpoTg21NoXqcmX0ySBIEyLMYWmt8WPsM61QNFaDBZkggupyNXLsV7uPuRg== + material-colors@^1.2.1: version "1.2.6" resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" @@ -17445,6 +17782,11 @@ ora@^3.4.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" +orderedmap@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-1.1.1.tgz#c618e77611b3b21d0fe3edc92586265e0059c789" + integrity sha512-3Ux8um0zXbVacKUkcytc0u3HgC0b0bBLT+I60r2J/En72cI0nZffqrA7Xtf2Hqs27j1g82llR5Mhbd0Z1XW4AQ== + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -19209,6 +19551,90 @@ property-information@^5.0.1: dependencies: xtend "^4.0.1" +prosemirror-commands@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.12.tgz#5cb0fef4e5a0039e2fa19b42a5626af03d7c2ec3" + integrity sha512-+CrMs3w/ZVPSkR+REg8KL/clyFLv/1+SgY/OMN+CB22Z24j9TZDje72vL36lOZ/E4NeRXuiCcmENcW/vAcG67A== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-dropcursor@^1.3.5: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.4.0.tgz#91a859d4ee79c99b1c0ba6ee61c093b195c0d9f0" + integrity sha512-6+YwTjmqDwlA/Dm+5wK67ezgqgjA/MhSDgaNxKUzH97SmeuWFXyLeDRxxOPZeSo7yTxcDGUCWTEjmQZsVBuMrQ== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + prosemirror-view "^1.1.0" + +prosemirror-gapcursor@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.2.0.tgz#28fb60bf3d9baf1f920907d2c3e613137204e8f3" + integrity sha512-yCLy5+0rVqLir/KcHFathQj4Rf8aRHi80FmEfKtM0JmyzvwdomslLzDZ/pX4oFhFKDgjl/WBBBFNqDyNifWg7g== + dependencies: + prosemirror-keymap "^1.0.0" + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-view "^1.0.0" + +prosemirror-history@^1.2.0: + 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-keymap@^1.0.0, prosemirror-keymap@^1.1.5: + 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.3, prosemirror-model@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.15.0.tgz#23bc09098daa7c309dba90a76a1b989ce6f61405" + integrity sha512-hQJv7SnIhlAy9ga3lhPPgaufhvCbQB9tHwscJ9E1H1pPHmN8w5V/lURueoYv9Kc3/bpNWoyHa8r3g//m7N0ChQ== + dependencies: + orderedmap "^1.1.0" + +prosemirror-schema-list@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.6.tgz#c3e13fe2f74750e4a53ff88d798dc0c4ccca6707" + integrity sha512-aFGEdaCWmJzouZ8DwedmvSsL50JpRkqhQ6tcpThwJONVVmCgI36LJHtoQ4VGZbusMavaBhXXr33zyD2IVsTlkw== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.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== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.3.3.tgz#5f6712b0577a119cc418686fe7588b6dd9b7464d" + integrity sha512-9NLVXy1Sfa2G6qPqhWMkEvwQQMTw7OyTqOZbJaGQWsCeH3hH5Cw+c5eNaLM1Uu75EyKLsEZhJ93XpHJBa6RX8A== + dependencies: + prosemirror-model "^1.0.0" + +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.22.0: + version "1.23.0" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.23.0.tgz#07f5539006ad4cba46eea81d78f1a892536858ac" + integrity sha512-lQlaOZqHa6+igCryOIaH7gMJKT8Jbi2w99NFiE6BEUrlhakI2OU5uUeqpHk5S5ejddwv7BEtFyGCMl3SPjak7A== + dependencies: + prosemirror-model "^1.14.3" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + proto3-json-serializer@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/proto3-json-serializer/-/proto3-json-serializer-0.1.5.tgz#c619769a59dc7fd8adf4e6c5060b9bf3039c8304" @@ -20997,6 +21423,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +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== + router@^1.3.1: version "1.3.3" resolved "https://registry.yarnpkg.com/router/-/router-1.3.3.tgz#c142f6b5ea4d6b3359022ca95b6580bd217f89cf" @@ -22917,6 +23348,13 @@ tinycolor2@^1.4.1: resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= +tippy.js@^6.3.6: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + tlds@^1.187.0: version "1.203.1" resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.203.1.tgz#4dc9b02f53de3315bc98b80665e13de3edfc1dfc" @@ -23247,6 +23685,13 @@ tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" +turndown@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.1.1.tgz#96992f2d9b40a1a03d3ea61ad31b5a5c751ef77f" + integrity sha512-BEkXaWH7Wh7e9bd2QumhfAXk5g34+6QUmmWx+0q6ThaVOLuLUqsnkq35HQ5SBHSaxjSfSM7US5o4lhJNH7B9MA== + dependencies: + domino "^2.1.6" + tweetnacl-async@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/tweetnacl-async/-/tweetnacl-async-2.0.0.tgz#0f7eed1107f862f88d4d95cc05398eb9a6413d1d" @@ -24014,6 +24459,11 @@ w3c-hr-time@^1.0.2: dependencies: 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: version "1.1.2" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794"