@atlaskit/editor-plugin-expand
Version:
Expand plugin for @atlaskit/editor-core
77 lines • 2.79 kB
JavaScript
import { Selection } from '@atlaskit/editor-prosemirror/state';
import { getExpandTitleInput } from '../utils';
/**
* The empty paragraph holding the caret, when its previous sibling is a collapsed expand or nested
* expand and it is not the last child of its container. The last child is kept so there is always a
* line to type in after the expand.
*/
const getEmptyLineAfterCollapsedExpand = (state, isCollapsed) => {
const {
$from
} = state.selection;
const {
paragraph,
expand,
nestedExpand
} = state.schema.nodes;
const textblock = $from.parent;
if (textblock.type !== paragraph || textblock.content.size > 0) {
return undefined;
}
const container = $from.node(-1);
const index = $from.index(-1);
const isLastChild = index === container.childCount - 1;
if (index === 0 || isLastChild) {
return undefined;
}
const previousSibling = container.child(index - 1);
const isExpand = previousSibling.type === expand || previousSibling.type === nestedExpand;
if (!isExpand || !isCollapsed(previousSibling)) {
return undefined;
}
const lineStart = $from.before();
return {
expandContentStart: lineStart - previousSibling.nodeSize + 1,
lineStart,
lineEnd: $from.after()
};
};
/**
* Backspace in an empty line directly after a collapsed expand: deletes the line and moves focus to
* the end of the expand title, in one transaction. Returns false, without changing anything, when
* the caret is anywhere else or the title input cannot be found, so other Backspace handling runs.
*/
export const deleteEmptyLineAfterCollapsedExpand = ({
focusTitle,
isCollapsed
}) => (state, dispatch, editorView) => {
if (!editorView || !state.selection.empty) {
return false;
}
const emptyLine = getEmptyLineAfterCollapsedExpand(state, isCollapsed);
if (!emptyLine) {
return false;
}
const titleInput = getExpandTitleInput(editorView, emptyLine.expandContentStart);
if (!titleInput) {
return false;
}
if (!dispatch) {
return true;
}
const tr = state.tr.delete(emptyLine.lineStart, emptyLine.lineEnd);
const selectionInsideExpand = Selection.findFrom(tr.doc.resolve(emptyLine.expandContentStart), 1, true);
if (selectionInsideExpand) {
tr.setSelection(selectionInsideExpand);
}
dispatch(tr);
const titleInputAfterDelete = getExpandTitleInput(editorView, emptyLine.expandContentStart);
if (!(titleInputAfterDelete !== null && titleInputAfterDelete !== void 0 && titleInputAfterDelete.isConnected)) {
focusTitle(emptyLine.expandContentStart)(editorView.state, dispatch, editorView);
return true;
}
titleInputAfterDelete.focus();
const titleEnd = titleInputAfterDelete.value.length;
titleInputAfterDelete.setSelectionRange(titleEnd, titleEnd);
return true;
};