Skip to content

Commit

Permalink
Merge pull request #24 from editor-js/fix-focus
Browse files Browse the repository at this point in the history
fix(caret): focus method now will set caret inside the element
  • Loading branch information
neSpecc authored Oct 9, 2024
2 parents 792f8e5 + 8e183ba commit 2927c2e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/caret/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Utils useful for work with caret for Editor.js tools development",
"repository": "https://github.com/editor-js/utils/tree/main/packages/caret",
"link": "https://github.com/editor-js/utils/tree/main/packages/caret",
"version": "1.0.0",
"version": "1.0.1",
"main": "dist/index.js",
"license": "MIT",
"scripts": {
Expand Down
57 changes: 55 additions & 2 deletions packages/caret/src/focus/focus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,61 @@ export function focus(element: HTMLElement, atStart: boolean = true): void {
return;
}

range.selectNodeContents(element);
range.collapse(atStart);
/**
* Helper function to create a new text node and set the caret
* @param parent - parent element to append the text node
*/
const createAndFocusTextNode = (parent: HTMLElement): void => {
const textNode = document.createTextNode('');

parent.appendChild(textNode);
range.setStart(textNode, 0);
range.setEnd(textNode, 0);
};

/**
* Helper for checking for null and undefined
* @param v - value to check
*/
const isDefinedAndNotNull = <T>(v: T): v is T => v !== undefined && v !== null;

/**
* We need to set focus at start/end to the text node inside an element
*/

let childNodes = element.childNodes;
let nodeToFocus = atStart ? childNodes[0] : childNodes[childNodes.length - 1];

if (isDefinedAndNotNull(nodeToFocus)) {
/**
* Ensure the nodeToFocus is a text node,
* if it's not, drill down to find a text node
*/
while (isDefinedAndNotNull(nodeToFocus) && nodeToFocus.nodeType !== Node.TEXT_NODE) {
nodeToFocus = atStart ? nodeToFocus.firstChild : nodeToFocus.lastChild;
}

/**
* If a text node is found, place the caret
*/
if (isDefinedAndNotNull(nodeToFocus) && nodeToFocus.nodeType === Node.TEXT_NODE) {
const length = nodeToFocus.textContent?.length ?? 0;
const position = atStart ? 0 : length;

range.setStart(nodeToFocus, position);
range.setEnd(nodeToFocus, position);
} else {
/**
* If no text node is found, create one and set focus
*/
createAndFocusTextNode(element);
}
} else {
/**
* If the element is empty, create a text node and place the caret at the start
*/
createAndFocusTextNode(element);
}

selection.removeAllRanges();
selection.addRange(range);
Expand Down

0 comments on commit 2927c2e

Please sign in to comment.