-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WEB-434] feat: add support to insert a new empty line on clicking at…
… bottom of the editor (#3856) * fix: horizontal rule no more causes issues on last node * fixed the mismatched transaction by using native tiptap stuff * added support to add new line onclick at bottom if last node is an image TODO: blockquote at last node * fix: simplified adding node at end of the document logic * feat: rewrite entire logic handling all cases * feat: arrow down and arrow up keys add empty node at top and bottom of doc from first/last row's cells * feat: added arrow up and down key support to images too * remove unnecessary console logs * chore: formatting components * fix: reduced bottom padding to increase onclick area --------- Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
- Loading branch information
1 parent
8997ee2
commit 899771a
Showing
13 changed files
with
291 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
packages/editor/core/src/ui/extensions/image/utilities/insert-line-above-image.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { Node as ProseMirrorNode } from "@tiptap/pm/model"; | ||
import { KeyboardShortcutCommand } from "@tiptap/core"; | ||
|
||
export const insertLineAboveImageAction: KeyboardShortcutCommand = ({ editor }) => { | ||
const { selection, doc } = editor.state; | ||
const { $from, $to } = selection; | ||
|
||
let imageNode: ProseMirrorNode | null = null; | ||
let imagePos: number | null = null; | ||
|
||
// Check if the selection itself is an image node | ||
doc.nodesBetween($from.pos, $to.pos, (node, pos) => { | ||
if (node.type.name === "image") { | ||
imageNode = node; | ||
imagePos = pos; | ||
return false; // Stop iterating once an image node is found | ||
} | ||
return true; | ||
}); | ||
|
||
if (imageNode === null || imagePos === null) return false; | ||
|
||
// Since we want to insert above the image, we use the imagePos directly | ||
const insertPos = imagePos; | ||
|
||
if (insertPos < 0) return false; | ||
|
||
// Check for an existing node immediately before the image | ||
if (insertPos === 0) { | ||
// If the previous node doesn't exist or isn't a paragraph, create and insert a new empty node there | ||
editor.chain().insertContentAt(insertPos, { type: "paragraph" }).run(); | ||
editor.chain().setTextSelection(insertPos).run(); | ||
} else { | ||
const prevNode = doc.nodeAt(insertPos); | ||
|
||
if (prevNode && prevNode.type.name === "paragraph") { | ||
// If the previous node is a paragraph, move the cursor there | ||
editor.chain().setTextSelection(insertPos).run(); | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
}; |
46 changes: 46 additions & 0 deletions
46
packages/editor/core/src/ui/extensions/image/utilities/insert-line-below-image.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { Node as ProseMirrorNode } from "@tiptap/pm/model"; | ||
import { KeyboardShortcutCommand } from "@tiptap/core"; | ||
|
||
export const insertLineBelowImageAction: KeyboardShortcutCommand = ({ editor }) => { | ||
const { selection, doc } = editor.state; | ||
const { $from, $to } = selection; | ||
|
||
let imageNode: ProseMirrorNode | null = null; | ||
let imagePos: number | null = null; | ||
|
||
// Check if the selection itself is an image node | ||
doc.nodesBetween($from.pos, $to.pos, (node, pos) => { | ||
if (node.type.name === "image") { | ||
imageNode = node; | ||
imagePos = pos; | ||
return false; // Stop iterating once an image node is found | ||
} | ||
return true; | ||
}); | ||
|
||
if (imageNode === null || imagePos === null) return false; | ||
|
||
const guaranteedImageNode: ProseMirrorNode = imageNode; | ||
const nextNodePos = imagePos + guaranteedImageNode.nodeSize; | ||
|
||
// Check for an existing node immediately after the image | ||
const nextNode = doc.nodeAt(nextNodePos); | ||
|
||
if (nextNode && nextNode.type.name === "paragraph") { | ||
// If the next node is a paragraph, move the cursor there | ||
const endOfParagraphPos = nextNodePos + nextNode.nodeSize - 1; | ||
editor.chain().setTextSelection(endOfParagraphPos).run(); | ||
} else if (!nextNode) { | ||
// If the next node doesn't exist i.e. we're at the end of the document, create and insert a new empty node there | ||
editor.chain().insertContentAt(nextNodePos, { type: "paragraph" }).run(); | ||
editor | ||
.chain() | ||
.setTextSelection(nextNodePos + 1) | ||
.run(); | ||
} else { | ||
// If the next node is not a paragraph, do not proceed | ||
return false; | ||
} | ||
|
||
return true; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
50 changes: 50 additions & 0 deletions
50
...ges/editor/core/src/ui/extensions/table/table/utilities/insert-line-above-table-action.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { KeyboardShortcutCommand } from "@tiptap/core"; | ||
import { findParentNodeOfType } from "src/lib/utils"; | ||
|
||
export const insertLineAboveTableAction: KeyboardShortcutCommand = ({ editor }) => { | ||
// Check if the current selection or the closest node is a table | ||
if (!editor.isActive("table")) return false; | ||
|
||
// Get the current selection | ||
const { selection } = editor.state; | ||
|
||
// Find the table node and its position | ||
const tableNode = findParentNodeOfType(selection, "table"); | ||
if (!tableNode) return false; | ||
|
||
const tablePos = tableNode.pos; | ||
|
||
// Determine if the selection is in the first row of the table | ||
const firstRow = tableNode.node.child(0); | ||
const selectionPath = (selection.$anchor as any).path; | ||
const selectionInFirstRow = selectionPath.includes(firstRow); | ||
|
||
if (!selectionInFirstRow) return false; | ||
|
||
// Check if the table is at the very start of the document or its parent node | ||
if (tablePos === 0) { | ||
// The table is at the start, so just insert a paragraph at the current position | ||
editor.chain().insertContentAt(tablePos, { type: "paragraph" }).run(); | ||
editor | ||
.chain() | ||
.setTextSelection(tablePos + 1) | ||
.run(); | ||
} else { | ||
// The table is not at the start, check for the node immediately before the table | ||
const prevNodePos = tablePos - 1; | ||
|
||
if (prevNodePos <= 0) return false; | ||
|
||
const prevNode = editor.state.doc.nodeAt(prevNodePos - 1); | ||
|
||
if (prevNode && prevNode.type.name === "paragraph") { | ||
// If there's a paragraph before the table, move the cursor to the end of that paragraph | ||
const endOfParagraphPos = tablePos - prevNode.nodeSize; | ||
editor.chain().setTextSelection(endOfParagraphPos).run(); | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
}; |
48 changes: 48 additions & 0 deletions
48
...ges/editor/core/src/ui/extensions/table/table/utilities/insert-line-below-table-action.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { KeyboardShortcutCommand } from "@tiptap/core"; | ||
import { findParentNodeOfType } from "src/lib/utils"; | ||
|
||
export const insertLineBelowTableAction: KeyboardShortcutCommand = ({ editor }) => { | ||
// Check if the current selection or the closest node is a table | ||
if (!editor.isActive("table")) return false; | ||
|
||
// Get the current selection | ||
const { selection } = editor.state; | ||
|
||
// Find the table node and its position | ||
const tableNode = findParentNodeOfType(selection, "table"); | ||
if (!tableNode) return false; | ||
|
||
const tablePos = tableNode.pos; | ||
const table = tableNode.node; | ||
|
||
// Determine if the selection is in the last row of the table | ||
const rowCount = table.childCount; | ||
const lastRow = table.child(rowCount - 1); | ||
const selectionPath = (selection.$anchor as any).path; | ||
const selectionInLastRow = selectionPath.includes(lastRow); | ||
|
||
if (!selectionInLastRow) return false; | ||
|
||
// Calculate the position immediately after the table | ||
const nextNodePos = tablePos + table.nodeSize; | ||
|
||
// Check for an existing node immediately after the table | ||
const nextNode = editor.state.doc.nodeAt(nextNodePos); | ||
|
||
if (nextNode && nextNode.type.name === "paragraph") { | ||
// If the next node is an paragraph, move the cursor there | ||
const endOfParagraphPos = nextNodePos + nextNode.nodeSize - 1; | ||
editor.chain().setTextSelection(endOfParagraphPos).run(); | ||
} else if (!nextNode) { | ||
// If the next node doesn't exist i.e. we're at the end of the document, create and insert a new empty node there | ||
editor.chain().insertContentAt(nextNodePos, { type: "paragraph" }).run(); | ||
editor | ||
.chain() | ||
.setTextSelection(nextNodePos + 1) | ||
.run(); | ||
} else { | ||
return false; | ||
} | ||
|
||
return true; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.