134 lines
3.6 KiB
Plaintext
134 lines
3.6 KiB
Plaintext
// @flow
|
|
|
|
/**
|
|
* Create a custom event
|
|
*
|
|
* @private
|
|
*/
|
|
export const createCustomEvent = (() => {
|
|
if (typeof window !== 'undefined' && typeof window.CustomEvent === "function") {
|
|
return function(
|
|
type: string,
|
|
options: ?{ detail?: Object, cancelable?: boolean },
|
|
): CustomEvent {
|
|
return new document.defaultView.CustomEvent(type, {
|
|
cancelable: (options && options.cancelable) || false,
|
|
detail: (options && options.detail) || undefined,
|
|
})
|
|
}
|
|
} else {
|
|
// Custom event polyfill from
|
|
// https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#polyfill
|
|
return function(
|
|
type: string,
|
|
options: ?{ detail?: Object, cancelable?: boolean },
|
|
): CustomEvent {
|
|
const event = document.createEvent("CustomEvent")
|
|
event.initCustomEvent(
|
|
type,
|
|
/* bubbles */ false,
|
|
(options && options.cancelable) || false,
|
|
(options && options.detail) || undefined,
|
|
)
|
|
return event
|
|
}
|
|
}
|
|
})()
|
|
|
|
/**
|
|
* Get the current coordinates of the `el` relative to the document.
|
|
*
|
|
* @private
|
|
*/
|
|
export function calculateElementOffset(
|
|
el: HTMLElement,
|
|
): { top: number, left: number } {
|
|
const rect = el.getBoundingClientRect()
|
|
const { defaultView, documentElement } = el.ownerDocument
|
|
const offset = {
|
|
top: rect.top + defaultView.pageYOffset,
|
|
left: rect.left + defaultView.pageXOffset,
|
|
}
|
|
if (documentElement) {
|
|
offset.top -= documentElement.clientTop
|
|
offset.left -= documentElement.clientLeft
|
|
}
|
|
return offset
|
|
}
|
|
|
|
const CHAR_CODE_ZERO = "0".charCodeAt(0)
|
|
const CHAR_CODE_NINE = "9".charCodeAt(0)
|
|
|
|
function isDigit(charCode: number): boolean {
|
|
return charCode >= CHAR_CODE_ZERO && charCode <= CHAR_CODE_NINE
|
|
}
|
|
|
|
/**
|
|
* Returns the line-height of the given node in pixels.
|
|
*
|
|
* @private
|
|
*/
|
|
export function getLineHeightPx(node: HTMLElement): number {
|
|
const computedStyle = window.getComputedStyle(node)
|
|
|
|
// If the char code starts with a digit, it is either a value in pixels,
|
|
// or unitless, as per:
|
|
// https://drafts.csswg.org/css2/visudet.html#propdef-line-height
|
|
// https://drafts.csswg.org/css2/cascade.html#computed-value
|
|
if (isDigit(computedStyle.lineHeight.charCodeAt(0))) {
|
|
// In real browsers the value is *always* in pixels, even for unit-less
|
|
// line-heights. However, we still check as per the spec.
|
|
if (
|
|
isDigit(
|
|
computedStyle.lineHeight.charCodeAt(
|
|
computedStyle.lineHeight.length - 1,
|
|
),
|
|
)
|
|
) {
|
|
return (
|
|
parseFloat(computedStyle.lineHeight) *
|
|
parseFloat(computedStyle.fontSize)
|
|
)
|
|
} else {
|
|
return parseFloat(computedStyle.lineHeight)
|
|
}
|
|
}
|
|
|
|
// Otherwise, the value is "normal".
|
|
// If the line-height is "normal", calculate by font-size
|
|
return calculateLineHeightPx(node.nodeName, computedStyle)
|
|
}
|
|
|
|
/**
|
|
* Returns calculated line-height of the given node in pixels.
|
|
*
|
|
* @private
|
|
*/
|
|
export function calculateLineHeightPx(
|
|
nodeName: string,
|
|
computedStyle: CSSStyleDeclaration,
|
|
): number {
|
|
const body = document.body
|
|
if (!body) {
|
|
return 0
|
|
}
|
|
|
|
const tempNode = document.createElement(nodeName)
|
|
tempNode.innerHTML = " "
|
|
tempNode.style.fontSize = computedStyle.fontSize
|
|
tempNode.style.fontFamily = computedStyle.fontFamily
|
|
tempNode.style.padding = "0"
|
|
body.appendChild(tempNode)
|
|
|
|
// Make sure textarea has only 1 row
|
|
if (tempNode instanceof HTMLTextAreaElement) {
|
|
;(tempNode: HTMLTextAreaElement).rows = 1
|
|
}
|
|
|
|
// Assume the height of the element is the line-height
|
|
const height = tempNode.offsetHeight
|
|
body.removeChild(tempNode)
|
|
|
|
return height
|
|
}
|