diff --git a/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.js b/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.js index 80b4295a..8194dc5e 100644 --- a/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.js +++ b/src/components/Widgets/Markdown/MarkdownControl/RawEditor/index.js @@ -18,16 +18,16 @@ export default class RawEditor extends React.Component { return !this.state.editorState.equals(nextState.editorState); } - handleChange = editorState => { - this.setState({ editorState }); - } + handleChange = change => { + this.setState({ editorState: change.state }); + }; /** * When the document value changes, serialize from Slate's AST back to plain * text (which is Markdown) and pass that up as the new value. */ - handleDocumentChange = debounce((doc, editorState) => { - const value = Plain.serialize(editorState); + handleDocumentChange = debounce((doc, change) => { + const value = Plain.serialize(change.state); this.props.onChange(value); }, 150); @@ -36,10 +36,10 @@ export default class RawEditor extends React.Component { * to the document. Selection logic (where to insert, whether to replace) is * handled by Slate. */ - handlePaste = (e, data, state) => { + handlePaste = (e, data, change) => { if (data.text) { const fragment = Plain.deserialize(data.text).document; - return state.transform().insertFragment(fragment).apply(); + return change.insertFragment(fragment); } }; diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.js b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.js index 34d2ceab..319baa73 100644 --- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.js +++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/index.js @@ -35,17 +35,17 @@ export default class Editor extends Component { return !this.state.editorState.equals(nextState.editorState); } - handlePaste = (e, data, state) => { + handlePaste = (e, data, change) => { if (data.type !== 'html' || data.isShift) { return; } const ast = htmlToSlate(data.html); const { document: doc } = Raw.deserialize(ast, { terse: true }); - return state.transform().insertFragment(doc).apply(); + return change.insertFragment(doc); } - handleDocumentChange = debounce((doc, editorState) => { - const raw = Raw.serialize(editorState, { terse: true }); + handleDocumentChange = debounce((doc, change) => { + const raw = Raw.serialize(change.state, { terse: true }); const plugins = this.state.shortcodePlugins; const markdown = slateToMarkdown(raw, plugins); this.props.onChange(markdown); @@ -56,21 +56,22 @@ export default class Editor extends Component { handleMarkClick = (event, type) => { event.preventDefault(); - const resolvedState = this.state.editorState.transform().focus().toggleMark(type).apply(); - this.ref.onChange(resolvedState); - this.setState({ editorState: resolvedState }); + const resolvedChange = this.state.editorState.change().focus().toggleMark(type); + this.ref.onChange(resolvedChange); + this.setState({ editorState: resolvedChange.state }); }; handleBlockClick = (event, type) => { event.preventDefault(); let { editorState } = this.state; const { document: doc, selection } = editorState; - const transform = editorState.transform(); + const { unwrapList, wrapInList } = EditListConfigured.changes; + let change = editorState.change(); // Handle everything except list buttons. if (!['bulleted-list', 'numbered-list'].includes(type)) { const isActive = this.hasBlock(type); - const transformed = transform.setBlock(isActive ? 'paragraph' : type); + change = change.setBlock(isActive ? 'paragraph' : type); } // Handle the extra wrapping required for list buttons. @@ -81,19 +82,18 @@ export default class Editor extends Component { const isInList = EditListConfigured.utils.isSelectionInList(editorState); if (isInList && isSameListType) { - EditListConfigured.transforms.unwrapList(transform, type); + change = change.call(unwrapList, type); } else if (isInList) { const currentListType = type === 'bulleted-list' ? 'numbered-list' : 'bulleted-list'; - EditListConfigured.transforms.unwrapList(transform, currentListType); - EditListConfigured.transforms.wrapInList(transform, type); + change = change.call(unwrapList, currentListType).call(wrapInList, type); } else { - EditListConfigured.transforms.wrapInList(transform, type); + change = change.call(wrapInList, type); } } - const resolvedState = transform.focus().apply(); - this.ref.onChange(resolvedState); - this.setState({ editorState: resolvedState }); + const resolvedChange = change.focus(); + this.ref.onChange(resolvedChange); + this.setState({ editorState: resolvedChange.state }); }; hasLinks = () => { @@ -101,12 +101,12 @@ export default class Editor extends Component { }; handleLink = () => { - let { editorState } = this.state; + let change = this.state.editorState.change(); // If the current selection contains links, clicking the "link" button // should simply unlink them. if (this.hasLinks()) { - editorState = editorState.transform().unwrapInline('link').apply(); + change = change.unwrapInline('link'); } else { @@ -115,23 +115,20 @@ export default class Editor extends Component { // If nothing is entered in the URL prompt, do nothing. if (!url) return; - let transform = editorState.transform(); - // If no text is selected, use the entered URL as text. - if (editorState.isCollapsed) { - transform = transform + if (change.state.isCollapsed) { + change = change .insertText(url) .extend(0 - url.length); } - editorState = transform + change = change .wrapInline({ type: 'link', data: { url } }) - .collapseToEnd() - .apply(); + .collapseToEnd(); } - this.ref.onChange(editorState); - this.setState({ editorState }); + this.ref.onChange(change); + this.setState({ editorState: change.state }); }; handlePluginSubmit = (plugin, shortcodeData) => { @@ -142,9 +139,9 @@ export default class Editor extends Component { }; const nodes = [Text.createFromString('')]; const block = { kind: 'block', type: 'shortcode', data, isVoid: true, nodes }; - const resolvedState = editorState.transform().insertBlock(block).focus().apply(); - this.ref.onChange(resolvedState); - this.setState({ editorState: resolvedState }); + const resolvedChange = editorState.change().insertBlock(block).focus(); + this.ref.onChange(resolvedChange); + this.setState({ editorState: resolvedChange.state }); }; handleToggle = () => { @@ -158,6 +155,10 @@ export default class Editor extends Component { return { onAction: e => handler(e, type), active: isActive(type) }; }; + handleChange = change => { + this.setState({ editorState: change.state }); + }; + render() { const { onAddAsset, onRemoveAsset, getAsset } = this.props; @@ -194,7 +195,7 @@ export default class Editor extends Component { state={this.state.editorState} schema={this.state.schema} plugins={plugins} - onChange={editorState => this.setState({ editorState })} + onChange={this.handleChange} onDocumentChange={this.handleDocumentChange} onKeyDown={onKeyDown} onPaste={this.handlePaste} diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/keys.js b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/keys.js index 3a5f839d..4ef0ca79 100644 --- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/keys.js +++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/keys.js @@ -2,7 +2,7 @@ import { Block, Text } from 'slate'; export default onKeyDown; -function onKeyDown(e, data, state) { +function onKeyDown(e, data, change) { const createDefaultBlock = () => { return Block.create({ type: 'paragraph', @@ -18,7 +18,7 @@ function onKeyDown(e, data, state) { * If the selected block is the first block in the document, create the * new block above it. If not, create the new block below it. */ - const { document: doc, selection, anchorBlock, focusBlock } = state; + const { document: doc, selection, anchorBlock, focusBlock } = change.state; const singleBlockSelected = anchorBlock === focusBlock; if (!singleBlockSelected || !focusBlock.isVoid) return; @@ -31,10 +31,9 @@ function onKeyDown(e, data, state) { const newBlock = createDefaultBlock(); const newBlockIndex = focusBlockIsFirstChild ? 0 : focusBlockIndex + 1; - return state.transform() + return change .insertNodeByKey(focusBlockParent.key, newBlockIndex, newBlock) - .collapseToStartOf(newBlock) - .apply(); + .collapseToStartOf(newBlock); } if (data.isMod) { @@ -61,7 +60,7 @@ function onKeyDown(e, data, state) { if (mark) { e.preventDefault(); - return state.transform().toggleMark(mark).apply(); + return change.toggleMark(mark); } } }; diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/plugins.js b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/plugins.js index 6418e0d1..694d19cf 100644 --- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/plugins.js +++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/plugins.js @@ -4,31 +4,30 @@ import EditList from 'slate-edit-list'; import EditTable from 'slate-edit-table'; const SoftBreak = (options = {}) => ({ - onKeyDown(e, data, state) { + onKeyDown(e, data, change) { if (data.key != 'enter') return; if (options.shift && e.shiftKey == false) return; const { onlyIn, ignoreIn, closeAfter, unwrapBlocks, defaultBlock = 'paragraph' } = options; - const { type, nodes } = state.startBlock; + const { type, nodes } = change.state.startBlock; if (onlyIn && !onlyIn.includes(type)) return; if (ignoreIn && ignoreIn.includes(type)) return; const shouldClose = nodes.last().characters.takeLast(closeAfter).every(c => c.text === '\n'); if (closeAfter && shouldClose) { - const trimmed = state.transform().deleteBackward(closeAfter); + const trimmed = change.deleteBackward(closeAfter); const unwrapped = unwrapBlocks ? unwrapBlocks.reduce((acc, blockType) => acc.unwrapBlock(blockType), trimmed) : trimmed; - return unwrapped.insertBlock(defaultBlock).apply(); + return unwrapped.insertBlock(defaultBlock); } const textNode = Text.createFromString('\n'); const breakNode = Inline.create({ type: 'break', nodes: [ textNode ] }); - return state.transform() + return change .insertInline(breakNode) .insertText('') - .collapseToStartOfNextText() - .apply(); + .collapseToStartOfNextText(); } }); @@ -42,10 +41,11 @@ export const SoftBreakConfigured = SoftBreak(SoftBreakOpts); export const ParagraphSoftBreakConfigured = SoftBreak({ onlyIn: ['paragraph'], shift: true }); const BreakToDefaultBlock = ({ onlyIn = [], defaultBlock = 'paragraph' }) => ({ - onKeyDown(e, data, state) { + onKeyDown(e, data, change) { + const { state } = change; if (data.key != 'enter' || e.shiftKey == true || state.isExpanded) return; if (onlyIn.includes(state.startBlock.type)) { - return state.transform().insertBlock(defaultBlock).apply(); + return change.insertBlock(defaultBlock); } } }); @@ -57,11 +57,11 @@ const BreakToDefaultBlockOpts = { export const BreakToDefaultBlockConfigured = BreakToDefaultBlock(BreakToDefaultBlockOpts); const BackspaceCloseBlock = (options = {}) => ({ - onKeyDown(e, data, state) { + onKeyDown(e, data, change) { if (data.key != 'backspace') return; const { defaultBlock = 'paragraph', ignoreIn, onlyIn } = options; - const { startBlock } = state; + const { startBlock } = change.state; const { type } = startBlock; if (onlyIn && !onlyIn.includes(type)) return; @@ -71,7 +71,7 @@ const BackspaceCloseBlock = (options = {}) => ({ const isEmpty = !characters || characters.isEmpty(); if (isEmpty) { - return state.transform().insertBlock(defaultBlock).focus().apply(); + return change.insertBlock(defaultBlock).focus(); } } }); diff --git a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/rules.js b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/rules.js index a367b875..96c189e0 100644 --- a/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/rules.js +++ b/src/components/Widgets/Markdown/MarkdownControl/VisualEditor/rules.js @@ -15,13 +15,13 @@ const enforceNeverEmpty = { const hasBlocks = !doc.getBlocks().isEmpty(); return hasBlocks ? null : {}; }, - normalize: transform => { + normalize: change => { const block = Block.create({ type: 'paragraph', nodes: [Text.createFromString('')], }); - const { key } = transform.state.document; - return transform.insertNodeByKey(key, 0, block).focus(); + const { key } = change.state.document; + return change.insertNodeByKey(key, 0, block).focus(); }, }; @@ -35,8 +35,8 @@ const shortcodesAtRoot = { return node.type === 'shortcode' && doc.getParent(node.key).key !== doc.key; }); }, - normalize: (transform, doc, node) => { - return transform.unwrapNodeByKey(node.key); + normalize: (change, doc, node) => { + return change.unwrapNodeByKey(node.key); }, };