From e8bdb062a7a6416f2fe3584bc6bc3a3c98978bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Wed, 5 May 2021 18:21:37 +0300 Subject: [PATCH 1/2] placeCaretAtHorizontalEdge: allow scrolling on initial call --- packages/dom/src/dom/place-caret-at-horizontal-edge.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/dom/src/dom/place-caret-at-horizontal-edge.js b/packages/dom/src/dom/place-caret-at-horizontal-edge.js index 53f8475949732c..29bd207795439e 100644 --- a/packages/dom/src/dom/place-caret-at-horizontal-edge.js +++ b/packages/dom/src/dom/place-caret-at-horizontal-edge.js @@ -13,14 +13,14 @@ import isRTL from './is-rtl'; /** * Places the caret at start or end of a given element. * - * @param {HTMLElement} container Focusable element. - * @param {boolean} isReverse True for end, false for start. - * @param {boolean} [mayUseScroll=false] Whether to allow scrolling. + * @param {HTMLElement} container Focusable element. + * @param {boolean} isReverse True for end, false for start. + * @param {boolean} [mayUseScroll=true] Whether to allow scrolling. */ export default function placeCaretAtHorizontalEdge( container, isReverse, - mayUseScroll = false + mayUseScroll = true ) { if ( ! container ) { return; From a31172e3700c48b690c90e2ff9abb1aebf174653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Wed, 5 May 2021 18:36:54 +0300 Subject: [PATCH 2/2] Avoid parameter --- packages/dom/README.md | 1 - .../src/dom/place-caret-at-horizontal-edge.js | 57 +++++++++++-------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/dom/README.md b/packages/dom/README.md index 0f3c190dbe22af..198a01b89ed7cf 100644 --- a/packages/dom/README.md +++ b/packages/dom/README.md @@ -284,7 +284,6 @@ _Parameters_ - _container_ `HTMLElement`: Focusable element. - _isReverse_ `boolean`: True for end, false for start. -- _mayUseScroll_ `[boolean]`: Whether to allow scrolling. # **placeCaretAtVerticalEdge** diff --git a/packages/dom/src/dom/place-caret-at-horizontal-edge.js b/packages/dom/src/dom/place-caret-at-horizontal-edge.js index 29bd207795439e..e2d3b676a8364e 100644 --- a/packages/dom/src/dom/place-caret-at-horizontal-edge.js +++ b/packages/dom/src/dom/place-caret-at-horizontal-edge.js @@ -10,18 +10,33 @@ import hiddenCaretRangeFromPoint from './hidden-caret-range-from-point'; import isInputOrTextArea from './is-input-or-text-area'; import isRTL from './is-rtl'; +/** + * Gets the range to place. + * + * @param {HTMLElement} container Focusable element. + * @param {boolean} isReverse True for end, false for start. + * + * @return {Range|null} The range to place. + */ +function getRange( container, isReverse ) { + const { ownerDocument } = container; + // In the case of RTL scripts, the horizontal edge is at the opposite side. + const isReverseDir = isRTL( container ) ? ! isReverse : isReverse; + const containerRect = container.getBoundingClientRect(); + // When placing at the end (isReverse), find the closest range to the bottom + // right corner. When placing at the start, to the top left corner. + const x = isReverse ? containerRect.right - 1 : containerRect.left + 1; + const y = isReverseDir ? containerRect.bottom - 1 : containerRect.top + 1; + return hiddenCaretRangeFromPoint( ownerDocument, x, y, container ); +} + /** * Places the caret at start or end of a given element. * - * @param {HTMLElement} container Focusable element. - * @param {boolean} isReverse True for end, false for start. - * @param {boolean} [mayUseScroll=true] Whether to allow scrolling. + * @param {HTMLElement} container Focusable element. + * @param {boolean} isReverse True for end, false for start. */ -export default function placeCaretAtHorizontalEdge( - container, - isReverse, - mayUseScroll = true -) { +export default function placeCaretAtHorizontalEdge( container, isReverse ) { if ( ! container ) { return; } @@ -49,15 +64,7 @@ export default function placeCaretAtHorizontalEdge( return; } - const { ownerDocument } = container; - // In the case of RTL scripts, the horizontal edge is at the opposite side. - const isReverseDir = isRTL( container ) ? ! isReverse : isReverse; - const containerRect = container.getBoundingClientRect(); - // When placing at the end (isReverse), find the closest range to the bottom - // right corner. When placing at the start, to the top left corner. - const x = isReverse ? containerRect.right - 1 : containerRect.left + 1; - const y = isReverseDir ? containerRect.bottom - 1 : containerRect.top + 1; - const range = hiddenCaretRangeFromPoint( ownerDocument, x, y, container ); + let range = getRange( container, isReverse ); // If no range range can be created or it is outside the container, the // element may be out of view. @@ -66,17 +73,19 @@ export default function placeCaretAtHorizontalEdge( ! range.startContainer || ! container.contains( range.startContainer ) ) { - if ( ! mayUseScroll ) { + container.scrollIntoView( isReverse ); + range = getRange( container, isReverse ); + + if ( + ! range || + ! range.startContainer || + ! container.contains( range.startContainer ) + ) { return; } - - // Only try to scroll into view once to avoid an infinite loop. - mayUseScroll = false; - container.scrollIntoView( isReverse ); - placeCaretAtHorizontalEdge( container, isReverse, mayUseScroll ); - return; } + const { ownerDocument } = container; const { defaultView } = ownerDocument; assertIsDefined( defaultView, 'defaultView' ); const selection = defaultView.getSelection();