fix: Enter at beginning of collapsed heading should create a new heading above (#3754)

This commit is contained in:
Tom Moor
2022-07-09 11:23:12 +02:00
committed by GitHub
parent 2893924e9a
commit caaf6dd76b
2 changed files with 67 additions and 32 deletions

View File

@@ -405,6 +405,7 @@ const EditorStyles = styled.div<{
&.collapsed { &.collapsed {
svg { svg {
transform: rotate(${(props) => (props.rtl ? "90deg" : "-90deg")}); transform: rotate(${(props) => (props.rtl ? "90deg" : "-90deg")});
pointer-events: none;
} }
transition-delay: 0.1s; transition-delay: 0.1s;
opacity: 1; opacity: 1;

View File

@@ -13,49 +13,83 @@ export default function splitHeading(type: NodeType) {
return false; return false;
} }
// check that the caret is at the end of the content, if it isn't then // is the selection at the beginning of the node
// standard node splitting behaviour applies const startPos = $from.before() + 1;
const endPos = $to.after() - 1; if (startPos === from) {
if (endPos !== to) { const collapsedNodes = findCollapsedNodes(state.doc);
const allBlocks = findBlockNodes(state.doc);
const previousBlock = allBlocks
.filter((a) => a.pos + a.node.nodeSize < startPos)
.pop();
const previousBlockIsCollapsed = !!collapsedNodes.find(
(a) => a.pos === previousBlock?.pos
);
if (previousBlockIsCollapsed) {
// Insert a new heading directly before this one
const transaction = state.tr.insert(
$from.before(),
type.create({ ...$from.parent.attrs, collapsed: false })
);
// Move the selection into the new heading node and make sure it's on screen
dispatch(
transaction
.setSelection(
TextSelection.near(transaction.doc.resolve($from.before()))
)
.scrollIntoView()
);
return true;
}
return false; return false;
} }
// If the node isn't collapsed standard behavior applies // If the heading isn't collapsed standard behavior applies
if (!$from.parent.attrs.collapsed) { if (!$from.parent.attrs.collapsed) {
return false; return false;
} }
// Find the next visible block after this one. It takes into account nested // is the selection at the end of the node. If not standard node-splitting
// collapsed headings and reaching the end of the document // behavior applies
const allBlocks = findBlockNodes(state.doc); const endPos = $to.after() - 1;
const collapsedBlocks = findCollapsedNodes(state.doc); if (endPos === to) {
const visibleBlocks = allBlocks.filter( // Find the next visible block after this one. It takes into account nested
(a) => !collapsedBlocks.find((b) => b.pos === a.pos) // collapsed headings and reaching the end of the document
); const collapsedNodes = findCollapsedNodes(state.doc);
const nextVisibleBlock = visibleBlocks.find((a) => a.pos > from); const allBlocks = findBlockNodes(state.doc);
const pos = nextVisibleBlock const visibleBlocks = allBlocks.filter(
? nextVisibleBlock.pos (a) => !collapsedNodes.find((b) => b.pos === a.pos)
: state.doc.content.size; );
const nextVisibleBlock = visibleBlocks.find((a) => a.pos > from);
const pos = nextVisibleBlock
? nextVisibleBlock.pos
: state.doc.content.size;
// Insert our new heading directly before the next visible block // Insert a new heading directly before the next visible block
const transaction = state.tr.insert( const transaction = state.tr.insert(
pos, pos,
type.create({ ...$from.parent.attrs, collapsed: false }) type.create({ ...$from.parent.attrs, collapsed: false })
); );
// Move the selection into the new heading node and make sure it's on screen // Move the selection into the new heading node and make sure it's on screen
dispatch( dispatch(
transaction transaction
.setSelection( .setSelection(
TextSelection.near( TextSelection.near(
transaction.doc.resolve( transaction.doc.resolve(
Math.min(pos + 1, transaction.doc.content.size) Math.min(pos + 1, transaction.doc.content.size)
)
) )
) )
) .scrollIntoView()
.scrollIntoView() );
);
return true; return true;
}
return false;
}; };
} }