@atlaskit/editor-plugin-table
Version:
Table plugin for the @atlaskit/editor
97 lines • 3.89 kB
JavaScript
/**
* Fix an issue that composition text replacement in Safari removes empty nodes during text composition text deletion.
* https://github.com/ProseMirror/prosemirror/issues/934
* We will remove this plugin when Webkit fix the problem itself.
*/
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
const tableSafariDeleteCompositionTextIssueWorkaroundKey = new PluginKey('tableSafariDeleteCompositionTextIssueWorkaround');
export const createPlugin = () => {
return new SafePlugin({
key: tableSafariDeleteCompositionTextIssueWorkaroundKey,
state: {
init: () => ({
renderSpan: false,
decorations: DecorationSet.empty
}),
apply: (tr, value) => {
const renderSpan = tr.getMeta(tableSafariDeleteCompositionTextIssueWorkaroundKey);
if (typeof renderSpan === 'undefined') {
return value;
}
let decorations;
if (renderSpan) {
// Find position of the first text node in case it has multiple text nodes created by Japanese IME
const {
$from
} = tr.selection;
const pos = $from.before($from.depth);
const spanDecoration = Decoration.widget(pos, () => {
const spanElement = document.createElement('span');
return spanElement;
});
decorations = DecorationSet.create(tr.doc, [spanDecoration]);
} else {
decorations = DecorationSet.empty;
}
return {
renderSpan,
decorations
};
}
},
props: {
decorations: state => {
var _tableSafariDeleteCom;
return (_tableSafariDeleteCom = tableSafariDeleteCompositionTextIssueWorkaroundKey.getState(state)) === null || _tableSafariDeleteCom === void 0 ? void 0 : _tableSafariDeleteCom.decorations;
},
handleDOMEvents: {
beforeinput: (view, event) => {
if ((event === null || event === void 0 ? void 0 : event.inputType) !== 'deleteCompositionText') {
return false;
}
const selection = window.getSelection();
if (!selection || selection.rangeCount <= 0 || selection.type !== 'Range') {
return false;
}
const range = selection.getRangeAt(0);
const {
startContainer,
endContainer,
endOffset,
startOffset
} = range;
/**
* On Safari when composition text is deleted, it deletes any empty elements it finds up the dom tree. Prosemirror can sometimes be confused by this
* and will think that we meant to delete those elements. This fix forces the resulting node to not be empty.
* The condition here checks to see if the entire text node is about to be swapped inside of an element
*/
if (startContainer.nodeType === Node.TEXT_NODE && startContainer === endContainer && startOffset === 0 && endOffset === startContainer.length) {
const {
tr
} = view.state;
tr.setMeta(tableSafariDeleteCompositionTextIssueWorkaroundKey, true);
view.dispatch(tr);
}
return false;
},
input: (view, event) => {
if ((event === null || event === void 0 ? void 0 : event.inputType) !== 'deleteCompositionText') {
return false;
}
const selection = window.getSelection();
if (!selection) {
return false;
}
const {
tr
} = view.state;
tr.setMeta(tableSafariDeleteCompositionTextIssueWorkaroundKey, false);
view.dispatch(tr);
return false;
}
}
}
});
};