/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format * @flow strict-local * @emails oncall+draft_js */ 'use strict'; const getRangeClientRects = require("./getRangeClientRects"); export type FakeClientRect = {| left: number, width: number, right: number, top: number, bottom: number, height: number, |}; /** * Like range.getBoundingClientRect() but normalizes for browser bugs. */ function getRangeBoundingClientRect(range: Range): FakeClientRect { // "Return a DOMRect object describing the smallest rectangle that includes // the first rectangle in list and all of the remaining rectangles of which // the height or width is not zero." // http://www.w3.org/TR/cssom-view/#dom-range-getboundingclientrect const rects = getRangeClientRects(range); let top = 0; let right = 0; let bottom = 0; let left = 0; if (rects.length) { // If the first rectangle has 0 width, we use the second, this is needed // because Chrome renders a 0 width rectangle when the selection contains // a line break. if (rects.length > 1 && rects[0].width === 0) { ({ top, right, bottom, left } = rects[1]); } else { ({ top, right, bottom, left } = rects[0]); } for (let ii = 1; ii < rects.length; ii++) { const rect = rects[ii]; if (rect.height !== 0 && rect.width !== 0) { top = Math.min(top, rect.top); right = Math.max(right, rect.right); bottom = Math.max(bottom, rect.bottom); left = Math.min(left, rect.left); } } } return { top, right, bottom, left, width: right - left, height: bottom - top }; } module.exports = getRangeBoundingClientRect;