@@ -13,7 +13,7 @@ import {
1313} from "lexical" ;
1414import { $createNodeFromSerializedNode } from "shared/converters/usfm/emptyUsfmNodes" ;
1515import { $isTypedMarkNode } from "shared/nodes/features/TypedMarkNode" ;
16- import { $isCharNode , CharNode } from "shared/nodes/scripture/usj/CharNode" ;
16+ import { CharNode } from "shared/nodes/scripture/usj/CharNode" ;
1717import { $isNoteNode , GENERATOR_NOTE_CALLER } from "shared/nodes/scripture/usj/NoteNode" ;
1818import { getNextVerse } from "shared/nodes/scripture/usj/node.utils" ;
1919import { ParaNode } from "shared/nodes/scripture/usj/ParaNode" ;
@@ -130,8 +130,9 @@ export function getUsjMarkerAction(
130130 nodeToInsert . selectStart ( ) ;
131131 }
132132 } else {
133- const nodes = $addVerseLeadingSpaceIfNeeded ( selection , nodeToInsert ) ;
134- selection . insertNodes ( nodes ) ;
133+ selection . insertNodes ( [ nodeToInsert ] ) ;
134+ $moveTextLeadingSpaceToPreviousNode ( nodeToInsert ) ;
135+ $moveVerseFollowingSpaceToPreviousNode ( nodeToInsert ) ;
135136 }
136137 } else {
137138 // Insert the node directly
@@ -282,10 +283,16 @@ function handleTextNode(
282283function $wrapNode ( node : LexicalNode , wrapper : LexicalNode ) : void {
283284 if ( $isTextNode ( wrapper ) ) {
284285 let text = node . getTextContent ( ) ;
285- // CharNodes can't start with a space.
286- if ( $isTextNode ( node ) && $isCharNode ( wrapper ) && text . startsWith ( " " ) ) {
287- wrapper . insertBefore ( $createTextNode ( " " ) ) ;
286+ // Inline nodes can't start with a space.
287+ if ( $isTextNode ( node ) && wrapper . isInline ( ) && text . startsWith ( " " ) ) {
288288 text = text . trimStart ( ) ;
289+ const previousNode = wrapper . getPreviousSibling ( ) ;
290+ if ( $isTextNode ( previousNode ) ) {
291+ const previousText = previousNode . getTextContent ( ) ;
292+ if ( ! previousText . endsWith ( " " ) ) previousNode . setTextContent ( `${ previousText } ` ) ;
293+ } else {
294+ wrapper . insertBefore ( $createTextNode ( " " ) ) ;
295+ }
289296 }
290297 wrapper . setTextContent ( text ) ;
291298 node . remove ( ) ;
@@ -298,31 +305,45 @@ function $wrapNode(node: LexicalNode, wrapper: LexicalNode): void {
298305// #endregion
299306
300307/**
301- * Adds a leading space before a verse node if needed .
308+ * Moves the leading space of a text node to the previous node .
302309 *
303- * This function checks if the given selection is collapsed and if the node to be inserted is a
304- * verse node or an immutable verse node. If both conditions are met, it further checks if the
305- * anchor node of the selection is a text node and if there is no leading space before the insertion
306- * point. If there is no leading space, it prepends a space to the node to be inserted.
310+ * This function checks if the given node is a text node and if it starts with a space. If both
311+ * conditions are met, it trims the leading space from the text node and appends a space to the
312+ * previous node if it is a text node and doesn't end in a space already.
307313 *
308- * @param selection - The current selection range in the editor.
309- * @param nodeToInsert - The node that is to be inserted into the editor.
310- * @returns An array containing the nodes to be inserted, potentially with a leading space node.
314+ * @param node - The node to check for leading space.
311315 */
312- function $addVerseLeadingSpaceIfNeeded (
313- selection : RangeSelection ,
314- nodeToInsert : LexicalNode ,
315- ) : LexicalNode [ ] {
316- if ( ! selection . isCollapsed ( ) ) return [ nodeToInsert ] ;
317- if ( ! $isSomeVerseNode ( nodeToInsert ) ) return [ nodeToInsert ] ;
316+ function $moveTextLeadingSpaceToPreviousNode ( node : LexicalNode ) : void {
317+ if ( ! $isTextNode ( node ) || ! node . getTextContent ( ) . startsWith ( " " ) ) return ;
318+
319+ node . setTextContent ( node . getTextContent ( ) . trimStart ( ) ) ;
320+ const previousNode = node . getPreviousSibling ( ) ;
321+ if ( $isTextNode ( previousNode ) ) {
322+ const previousText = previousNode . getTextContent ( ) ;
323+ if ( ! previousText . endsWith ( " " ) ) previousNode . setTextContent ( `${ previousText } ` ) ;
324+ }
325+ }
318326
319- const anchorNode = selection . anchor . getNode ( ) ;
320- if ( ! $isTextNode ( anchorNode ) ) return [ nodeToInsert ] ;
327+ /**
328+ * Moves the leading space of a node following a verse node to the previous node.
329+ *
330+ * This function checks if the previous node ends in a space and adds one if needed. It then checks
331+ * if the following node starts with a space and removes it.
332+ *
333+ * @param node - The node to check for leading space.
334+ */
335+ function $moveVerseFollowingSpaceToPreviousNode ( node : LexicalNode ) {
336+ if ( ! $isSomeVerseNode ( node ) ) return ;
321337
322- const offset = selection . anchor . offset ;
323- const textContent = anchorNode . getTextContent ( ) ;
324- const hasLeadingSpace = textContent [ offset - 1 ] === " " ;
325- if ( hasLeadingSpace ) return [ nodeToInsert ] ;
338+ const previousNode = node . getPreviousSibling ( ) ;
339+ if ( $isTextNode ( previousNode ) ) {
340+ const previousText = previousNode . getTextContent ( ) ;
341+ if ( ! previousText . endsWith ( " " ) ) previousNode . setTextContent ( `${ previousText } ` ) ;
342+ }
326343
327- return [ $createTextNode ( " " ) , nodeToInsert ] ;
344+ const nextNode = node . getNextSibling ( ) ;
345+ if ( $isTextNode ( nextNode ) ) {
346+ const nextText = nextNode . getTextContent ( ) ;
347+ if ( nextText . startsWith ( " " ) ) nextNode . setTextContent ( nextText . trimStart ( ) ) ;
348+ }
328349}
0 commit comments