UNPKG

solids

Version:

CSS-only Material Design Primitives

151 lines (132 loc) 4.92 kB
/** * @license * * Copyright 2019 Stijn de Witt. Some rights reserved. * Licensed under the MIT Open Source license. * https://opensource.org/licenses/MIT * See LICENSE for details. * * Based on code copyright 2018 Google Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0. * http://www.apache.org/licenses/LICENSE-2.0 * See LICENSE-MDC for details. * * Unless required by applicable law or agreed to in writing, software * distributed under these licenses is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the licenses for the specific language governing permissions and * limitations under these licenses. * */ /** * Stores result from supportsCssVariables to avoid redundant processing to detect CSS custom variable support. * @private {boolean|undefined} */ let supportsCssVariables_; /** * Stores result from applyPassive to avoid redundant processing to detect passive event listener support. * @private {boolean|undefined} */ let supportsPassive_; /** * @param {!Window} windowObj * @return {boolean} */ function detectEdgePseudoVarBug(windowObj) { // Detect versions of Edge with buggy var() support // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11495448/ const document = windowObj.document; const node = document.createElement('div'); node.className = 'mdc-ripple-surface--test-edge-var-bug'; document.body.appendChild(node); // The bug exists if ::before style ends up propagating to the parent element. // Additionally, getComputedStyle returns null in iframes with display: "none" in Firefox, // but Firefox is known to support CSS custom properties correctly. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=548397 const computedStyle = windowObj.getComputedStyle(node); const hasPseudoVarBug = computedStyle !== null && computedStyle.borderTopStyle === 'solid'; node.remove(); return hasPseudoVarBug; } /** * @param {!Window} windowObj * @param {boolean=} forceRefresh * @return {boolean|undefined} */ function supportsCssVariables(windowObj, forceRefresh = false) { let supportsCssVariables = supportsCssVariables_; if (typeof supportsCssVariables_ === 'boolean' && !forceRefresh) { return supportsCssVariables; } const supportsFunctionPresent = windowObj.CSS && typeof windowObj.CSS.supports === 'function'; if (!supportsFunctionPresent) { return; } const explicitlySupportsCssVars = windowObj.CSS.supports('--css-vars', 'yes'); // See: https://bugs.webkit.org/show_bug.cgi?id=154669 // See: README section on Safari const weAreFeatureDetectingSafari10plus = ( windowObj.CSS.supports('(--css-vars: yes)') && windowObj.CSS.supports('color', '#00000000') ); if (explicitlySupportsCssVars || weAreFeatureDetectingSafari10plus) { supportsCssVariables = !detectEdgePseudoVarBug(windowObj); } else { supportsCssVariables = false; } if (!forceRefresh) { supportsCssVariables_ = supportsCssVariables; } return supportsCssVariables; } // /** * Determine whether the current browser supports passive event listeners, and if so, use them. * @param {!Window=} globalObj * @param {boolean=} forceRefresh * @return {boolean|{passive: boolean}} */ function applyPassive(globalObj = window, forceRefresh = false) { if (supportsPassive_ === undefined || forceRefresh) { let isSupported = false; try { globalObj.document.addEventListener('test', null, {get passive() { isSupported = true; }}); } catch (e) { } supportsPassive_ = isSupported; } return supportsPassive_ ? {passive: true} : false; } /** * @param {!Object} HTMLElementPrototype * @return {!Array<string>} */ function getMatchesProperty(HTMLElementPrototype) { return [ 'webkitMatchesSelector', 'msMatchesSelector', 'matches', ].filter((p) => p in HTMLElementPrototype).pop(); } /** * @param {!Event} ev * @param {{x: number, y: number}} pageOffset * @param {!ClientRect} clientRect * @return {{x: number, y: number}} */ function getNormalizedEventCoords(ev, pageOffset, clientRect) { const {x, y} = pageOffset; const documentX = x + clientRect.left; const documentY = y + clientRect.top; let normalizedX; let normalizedY; // Determine touch point relative to the ripple container. if (ev.type === 'touchstart') { normalizedX = ev.changedTouches[0].pageX - documentX; normalizedY = ev.changedTouches[0].pageY - documentY; } else { normalizedX = ev.pageX - documentX; normalizedY = ev.pageY - documentY; } return {x: normalizedX, y: normalizedY}; } export {supportsCssVariables, applyPassive, getMatchesProperty, getNormalizedEventCoords};