Skip to content

Commit

Permalink
Writing flow: fix horizontal caret placing for empty editable with pl…
Browse files Browse the repository at this point in the history
…aceholder (#30463)

* Writing flow: fix horizontal caret placing for empty rich text with placeholder

* Prevent placeholder from catching selection (esp in FF)

* Scroll into view if needed
  • Loading branch information
ellatrix authored Apr 2, 2021
1 parent 2557a44 commit aca801a
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 17 deletions.
1 change: 1 addition & 0 deletions packages/block-library/src/query-pagination-next/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function QueryPaginationNextEdit( {
<PlainText
__experimentalVersion={ 2 }
tagName="a"
style={ { display: 'inline-block' } }
aria-label={ __( 'Next page link' ) }
placeholder={ __( 'Next Page' ) }
value={ label }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default function QueryPaginationPreviousEdit( {
<PlainText
__experimentalVersion={ 2 }
tagName="a"
style={ { display: 'inline-block' } }
aria-label={ __( 'Previous page link' ) }
placeholder={ __( 'Previous Page' ) }
value={ label }
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/site-title/edit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export default function SiteTitleEdit( { attributes, setAttributes } ) {
<TagName { ...blockProps }>
<RichText
tagName="a"
style={ { display: 'inline-block' } }
aria-label={ __( 'Site title text' ) }
placeholder={ __( 'Write site title…' ) }
value={ title }
Expand Down
1 change: 1 addition & 0 deletions packages/dom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ _Parameters_
- _container_ `Element`: Focusable element.
- _isReverse_ `boolean`: True for end, false for start.
- _mayUseScroll_ `boolean`: Whether to allow scrolling.
<a name="placeCaretAtVerticalEdge" href="#placeCaretAtVerticalEdge">#</a> **placeCaretAtVerticalEdge**
Expand Down
51 changes: 35 additions & 16 deletions packages/dom/src/dom/place-caret-at-horizontal-edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,23 @@
*/
import { includes } from 'lodash';

/**
* Internal dependencies
*/
import hiddenCaretRangeFromPoint from './hidden-caret-range-from-point';

/**
* Places the caret at start or end of a given element.
*
* @param {Element} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
* @param {Element} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
* @param {boolean} mayUseScroll Whether to allow scrolling.
*/
export default function placeCaretAtHorizontalEdge( container, isReverse ) {
export default function placeCaretAtHorizontalEdge(
container,
isReverse,
mayUseScroll
) {
if ( ! container ) {
return;
}
Expand Down Expand Up @@ -37,25 +47,34 @@ export default function placeCaretAtHorizontalEdge( container, isReverse ) {
return;
}

// Select on extent child of the container, not the container itself. This
// avoids the selection always being `endOffset` of 1 when placed at end,
// where `startContainer`, `endContainer` would always be container itself.
const rangeTarget = container[ isReverse ? 'lastChild' : 'firstChild' ];
const { ownerDocument } = container;
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 = isReverse ? containerRect.bottom - 1 : containerRect.top + 1;
const range = hiddenCaretRangeFromPoint( ownerDocument, x, y, container );

// If no range range can be created or it is outside the container, the
// element may be out of view.
if (
! range ||
! range.startContainer ||
! container.contains( range.startContainer )
) {
if ( ! mayUseScroll ) {
return;
}

// If no range target, it implies that the container is empty. Focusing is
// sufficient for caret to be placed correctly.
if ( ! rangeTarget ) {
// 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;
const selection = defaultView.getSelection();
const range = ownerDocument.createRange();

range.selectNodeContents( rangeTarget );
range.collapse( ! isReverse );

selection.removeAllRanges();
selection.addRange( range );
}
2 changes: 1 addition & 1 deletion packages/rich-text/src/component/use-inline-warning.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function useInlineWarning( { ref } ) {

if ( computedStyle.display === 'inline' ) {
// eslint-disable-next-line no-console
console.warn( message );
console.error( message );
}
}
}, [] );
Expand Down
2 changes: 2 additions & 0 deletions packages/rich-text/src/to-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ export function toTree( {
// selection. The placeholder is also not editable after
// all.
contenteditable: 'false',
style:
'pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;',
},
} );
}
Expand Down

0 comments on commit aca801a

Please sign in to comment.