@testing-library/user-event
Version:
Fire events the same way the user does
60 lines (57 loc) • 2.47 kB
JavaScript
import { getUIValue } from '../../document/UI.js';
import '../../utils/dataTransfer/Clipboard.js';
import { hasOwnSelection } from '../../utils/focus/selection.js';
function resolveCaretPosition({ target, node, offset }) {
if (hasOwnSelection(target)) {
return {
node: target,
offset: offset !== null && offset !== undefined ? offset : getUIValue(target).length
};
} else if (node) {
return {
node,
offset: offset !== null && offset !== undefined ? offset : node.nodeType === 3 ? node.nodeValue.length : node.childNodes.length
};
}
return findNodeAtTextOffset(target, offset);
}
function findNodeAtTextOffset(node, offset, isRoot = true) {
// When clicking after the content the browser behavior can be complicated:
// 1. If there is textContent after the last element child,
// the cursor is moved there.
// 2. If there is textContent in the last element child,
// the browser moves the cursor to the last non-empty text node inside this element.
// 3. Otherwise the cursor is moved to the end of the target.
let i = offset === undefined ? node.childNodes.length - 1 : 0;
const step = offset === undefined ? -1 : 1;
while(offset === undefined ? i >= (isRoot ? Math.max(node.childNodes.length - 1, 0) : 0) : i <= node.childNodes.length){
if (offset && i === node.childNodes.length) {
throw new Error('The given offset is out of bounds.');
}
const c = node.childNodes.item(i);
const text = String(c.textContent);
if (text.length) {
if (offset !== undefined && text.length < offset) {
offset -= text.length;
} else if (c.nodeType === 1) {
return findNodeAtTextOffset(c, offset, false);
} else {
// The pre-commit hooks keeps changing this
// See https://github.com/kentcdodds/kcd-scripts/issues/218
/* istanbul ignore else */ // eslint-disable-next-line no-lonely-if
if (c.nodeType === 3) {
return {
node: c,
offset: offset !== null && offset !== undefined ? offset : c.nodeValue.length
};
}
}
}
i += step;
}
return {
node,
offset: node.childNodes.length
};
}
export { resolveCaretPosition };