Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add shift+up and shift+down support for decorator nodes #4586

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions packages/lexical-rich-text/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,72 @@ export function registerRichText(editor: LexicalEditor): () => void {
KEY_ARROW_UP_COMMAND,
(event) => {
const selection = $getSelection();
if (event.shiftKey) {
if ($isRangeSelection(selection)) {
const anchorNode = selection.anchor.getNode();

if (!$isRootNode(anchorNode)) {
const anchorNodeTopElement = anchorNode.getTopLevelElement();
const focusNode = selection.focus.getNode().getTopLevelElement();

if (!focusNode || !anchorNodeTopElement) {
return false;
}
const focusNodeTopElement = focusNode.getTopLevelElement();
if (!focusNodeTopElement) {
return false;
}

// if on or about to move to decorator node selection, select the entire current node using root node offsets
const previousSibling = focusNodeTopElement.getPreviousSibling();
if (
$isDecoratorNode(anchorNodeTopElement) ||
$isDecoratorNode(previousSibling)
) {
// if at the start of the line, treat that line/node as not selected
if (selection.anchor.offset === 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't assume that offset 0 is start of the line, for example

Screen.Recording.2023-06-01.at.6.44.55.am.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not certain how you managed this - could you explain?

selection.focus.set(
'root',
focusNode.getIndexWithinParent() - 1,
'element',
);
selection.anchor.set(
'root',
anchorNodeTopElement.getIndexWithinParent(),
'element',
);
} else {
selection.focus.set(
'root',
focusNode.getIndexWithinParent(),
'element',
);
selection.anchor.set(
'root',
anchorNodeTopElement.getIndexWithinParent() + 1,
'element',
);
Comment on lines +754 to +758
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to modify the anchor selection? I presume this one's correct already?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No - it would be correct, it just felt better to be consistent about shifting to using root entirely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If removed, this would have an impact on the change made in LexicalSelection.ts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If removed, this would have an impact on the change made in LexicalSelection.ts.

}
event.preventDefault();
return true;
}
}

// if using the root node, simply add the card above
9larsons marked this conversation as resolved.
Show resolved Hide resolved
if ($isRootNode(anchorNode)) {
const offset = selection.focus.offset;
if (offset > 0) {
selection.focus.set(
'root',
selection.focus.offset - 1,
'element',
);
}
event.preventDefault();
return true;
}
}
}
if (
$isNodeSelection(selection) &&
!$isTargetWithinDecorator(event.target as HTMLElement)
Expand Down Expand Up @@ -743,6 +809,80 @@ export function registerRichText(editor: LexicalEditor): () => void {
KEY_ARROW_DOWN_COMMAND,
(event) => {
const selection = $getSelection();

if (event.shiftKey) {
9larsons marked this conversation as resolved.
Show resolved Hide resolved
if ($isRangeSelection(selection)) {
const anchorNode = selection.anchor.getNode();

if (!$isRootNode(anchorNode)) {
const anchorNodeTopElement = anchorNode.getTopLevelElement();
const focusNode = selection.focus.getNode().getTopLevelElement();

if (!focusNode || !anchorNodeTopElement) {
return false;
}
const focusNodeTopElement = focusNode.getTopLevelElement();
if (!focusNodeTopElement) {
return false;
}

// if on or about to move to decorator node selection, select the entire current node using root node offsets
const nextSibling = focusNodeTopElement.getNextSibling();
if (
$isDecoratorNode(anchorNodeTopElement) ||
$isDecoratorNode(nextSibling)
) {
// if at end of a line, treat it as if that line/node is not selected
if (
selection.anchor.offset ===
anchorNodeTopElement.getTextContentSize()
) {
selection.anchor.set(
'root',
anchorNodeTopElement.getIndexWithinParent() + 1,
'element',
);
selection.focus.set(
'root',
focusNode.getIndexWithinParent() + 2,
'element',
);
} else {
selection.anchor.set(
'root',
anchorNodeTopElement.getIndexWithinParent(),
'element',
);
selection.focus.set(
'root',
focusNode.getIndexWithinParent() + 1,
'element',
);
}
event.preventDefault();
return true;
}
}

// if using the root node, simply add the node below
if ($isRootNode(anchorNode)) {
const offset = selection.focus.offset;
if (
offset <=
anchorNode.getLastChildOrThrow().getIndexWithinParent()
) {
selection.focus.set(
'root',
selection.focus.offset + 1,
'element',
);
}
event.preventDefault();
return true;
}
}
}

if ($isNodeSelection(selection)) {
// If selection is on a node, let's try and move selection
// back to being a range selection.
Expand Down
6 changes: 4 additions & 2 deletions packages/lexical/src/LexicalSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,10 @@ export class RangeSelection implements BaseSelection {
lastNode.replace(textNode);
lastNode = textNode;
}
lastNode = (lastNode as TextNode).spliceText(0, endOffset, '');
// root node selections only select whole nodes, so no text splices is necessary
if (!$isRootNode(endPoint.getNode())) {
lastNode = (lastNode as TextNode).spliceText(0, endOffset, '');
}
markedNodeKeysForKeep.add(lastNode.__key);
} else {
const lastNodeParent = lastNode.getParentOrThrow();
Expand Down Expand Up @@ -2243,7 +2246,6 @@ function $updateCaretSelectionForUnicodeCharacter(
const focus = selection.focus;
const anchorNode = anchor.getNode();
const focusNode = focus.getNode();

if (
anchorNode === focusNode &&
anchor.type === 'text' &&
Expand Down