UNPKG

@gechiui/dom

Version:
136 lines (104 loc) 4.87 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = isEdge; var _isRtl = _interopRequireDefault(require("./is-rtl")); var _getRangeHeight = _interopRequireDefault(require("./get-range-height")); var _getRectangleFromRange = _interopRequireDefault(require("./get-rectangle-from-range")); var _isSelectionForward = _interopRequireDefault(require("./is-selection-forward")); var _hiddenCaretRangeFromPoint = _interopRequireDefault(require("./hidden-caret-range-from-point")); var _assertIsDefined = require("../utils/assert-is-defined"); var _isInputOrTextArea = _interopRequireDefault(require("./is-input-or-text-area")); /** * Internal dependencies */ /** * Check whether the selection is at the edge of the container. Checks for * horizontal position by default. Set `onlyVertical` to true to check only * vertically. * * @param {Element} container Focusable element. * @param {boolean} isReverse Set to true to check left, false to check right. * @param {boolean} [onlyVertical=false] Set to true to check only vertical position. * * @return {boolean} True if at the edge, false if not. */ function isEdge(container, isReverse) { let onlyVertical = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if ((0, _isInputOrTextArea.default)(container) && typeof container.selectionStart === 'number') { if (container.selectionStart !== container.selectionEnd) { return false; } if (isReverse) { return container.selectionStart === 0; } return container.value.length === container.selectionStart; } if (! /** @type {HTMLElement} */ container.isContentEditable) { return true; } const { ownerDocument } = container; const { defaultView } = ownerDocument; (0, _assertIsDefined.assertIsDefined)(defaultView, 'defaultView'); const selection = defaultView.getSelection(); if (!selection || !selection.rangeCount) { return false; } const range = selection.getRangeAt(0); const collapsedRange = range.cloneRange(); const isForward = (0, _isSelectionForward.default)(selection); const isCollapsed = selection.isCollapsed; // Collapse in direction of selection. if (!isCollapsed) { collapsedRange.collapse(!isForward); } const collapsedRangeRect = (0, _getRectangleFromRange.default)(collapsedRange); const rangeRect = (0, _getRectangleFromRange.default)(range); if (!collapsedRangeRect || !rangeRect) { return false; } // Only consider the multiline selection at the edge if the direction is // towards the edge. The selection is multiline if it is taller than the // collapsed selection. const rangeHeight = (0, _getRangeHeight.default)(range); if (!isCollapsed && rangeHeight && rangeHeight > collapsedRangeRect.height && isForward === isReverse) { return false; } // In the case of RTL scripts, the horizontal edge is at the opposite side. const isReverseDir = (0, _isRtl.default)(container) ? !isReverse : isReverse; const containerRect = container.getBoundingClientRect(); // To check if a selection is at the edge, we insert a test selection at the // edge of the container and check if the selections have the same vertical // or horizontal position. If they do, the selection is at the edge. // This method proves to be better than a DOM-based calculation for the // horizontal edge, since it ignores empty textnodes and a trailing line // break element. In other words, we need to check visual positioning, not // DOM positioning. // It also proves better than using the computed style for the vertical // edge, because we cannot know the padding and line height reliably in // pixels. `getComputedStyle` may return a value with different units. const x = isReverseDir ? containerRect.left + 1 : containerRect.right - 1; const y = isReverse ? containerRect.top + 1 : containerRect.bottom - 1; const testRange = (0, _hiddenCaretRangeFromPoint.default)(ownerDocument, x, y, /** @type {HTMLElement} */ container); if (!testRange) { return false; } const testRect = (0, _getRectangleFromRange.default)(testRange); if (!testRect) { return false; } const verticalSide = isReverse ? 'top' : 'bottom'; const horizontalSide = isReverseDir ? 'left' : 'right'; const verticalDiff = testRect[verticalSide] - rangeRect[verticalSide]; const horizontalDiff = testRect[horizontalSide] - collapsedRangeRect[horizontalSide]; // Allow the position to be 1px off. const hasVerticalDiff = Math.abs(verticalDiff) <= 1; const hasHorizontalDiff = Math.abs(horizontalDiff) <= 1; return onlyVertical ? hasVerticalDiff : hasVerticalDiff && hasHorizontalDiff; } //# sourceMappingURL=is-edge.js.map