UNPKG

native-fn

Version:
1,303 lines (1,287 loc) 53.7 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Native = factory()); })(this, (function () { 'use strict'; var version = "1.0.26"; var packageJSON = { version: version}; var USER_AGENT = navigator.userAgent; var AppOpenState; (function (AppOpenState) { AppOpenState[AppOpenState["Scheme"] = 0] = "Scheme"; AppOpenState[AppOpenState["Universal"] = 1] = "Universal"; AppOpenState[AppOpenState["Intent"] = 2] = "Intent"; AppOpenState[AppOpenState["Fallback"] = 3] = "Fallback"; AppOpenState[AppOpenState["Store"] = 4] = "Store"; })(AppOpenState || (AppOpenState = {})); var Messengers; (function (Messengers) { Messengers["Telephone"] = "telephone"; Messengers["Message"] = "message"; Messengers["Mail"] = "mail"; })(Messengers || (Messengers = {})); var IS_SUPPORT_INTENT = !/firefox|opr/i.test(USER_AGENT); var OS; (function (OS) { OS["Unknown"] = "Unknown"; OS["Android"] = "Android"; OS["iOS"] = "iOS"; OS["Windows"] = "Windows"; OS["MacOS"] = "MacOS"; })(OS || (OS = {})); var Devices; (function (Devices) { Devices["Unknown"] = "Unknown"; Devices["Mobile"] = "Mobile"; Devices["Desktop"] = "Desktop"; })(Devices || (Devices = {})); var Engines; (function (Engines) { Engines["Unknown"] = "Unknown"; Engines["EdgeHTML"] = "EdgeHTML"; Engines["ArkWeb"] = "ArkWeb"; Engines["Blink"] = "Blink"; Engines["Presto"] = "Presto"; Engines["WebKit"] = "WebKit"; Engines["Trident"] = "Trident"; Engines["NetFront"] = "NetFront"; Engines["KHTML"] = "KHTML"; Engines["Tasman"] = "Tasman"; Engines["Gecko"] = "Gecko"; })(Engines || (Engines = {})); var OS_RESOLVER_MAP = (function () { function resolveIOSOrMacVersion(str) { if (str === undefined) return ""; return str.replace(/_/g, "."); } function resolveWindowsVersion(str) { if (str === undefined) return ""; var mapped = { "4.90": "ME", "NT3.51": "NT 3.11", "NT4.0": "NT 4.0", "NT 5.0": "2000", "NT 5.1": "XP", "NT 5.2": "XP", "NT 6.0": "Vista", "NT 6.1": "7", "NT 6.2": "8", "NT 6.3": "8.1", "NT 6.4": "10", "NT 10.0": "10", "ARM": "RT" }[str]; if (mapped !== undefined) return mapped; return str; } function resolveVersion(str) { if (str === undefined) return ""; return str; } return [ [/android\w*[-\/.; ]?([\d.]*)/i, OS.Android, Devices.Mobile, resolveVersion], [/microsoft windows (vista|xp)/i, OS.Windows, Devices.Desktop, resolveVersion], [/windows (?:phone(?: os)?|mobile|iot)[\/ ]?([.\w ]*)/i, OS.Windows, Devices.Desktop, resolveWindowsVersion], [/windows nt 6\.2; (arm)/i, OS.Windows, Devices.Desktop, resolveWindowsVersion], [/windows[\/ ]([ntce\d. ]+\w)(?!.+xbox)/i, OS.Windows, Devices.Desktop, resolveWindowsVersion], [/(?:win(?=[39n])|win 9x )([nt\d.]+)/i, OS.Windows, Devices.Desktop, resolveWindowsVersion], [/[adehimnop]{4,7}\b(?:.*os (\w+) like mac|; opera)/i, OS.iOS, Devices.Mobile, resolveIOSOrMacVersion], [/(?:ios;fbsv\/|iphone.+ios[\/ ])([\d.]+)/i, OS.iOS, Devices.Mobile, resolveIOSOrMacVersion], [/cfnetwork\/.+darwin/i, OS.iOS, Devices.Mobile, resolveVersion], [/mac os x ?([\w. ]*)/i, OS.MacOS, Devices.Desktop, resolveIOSOrMacVersion], [/(?:macintosh|mac_powerpc\b)(?!.+haiku)/i, OS.MacOS, Devices.Desktop, resolveIOSOrMacVersion], ]; })(); var ENGINE_RESOLVER_MAP = [ [/windows.+ edge\/([\w.]+)/i, Engines.EdgeHTML], [/arkweb\/([\w.]+)/i, Engines.ArkWeb], [/webkit\/537\.36.+chrome\/(?!27)([\w.]+)/i, Engines.Blink], [/presto\/([\w.]+)/i, Engines.Presto], [/webkit\/([\w.]+)/i, Engines.WebKit], [/trident\/([\w.]+)/i, Engines.Trident], [/netfront\/([\w.]+)/i, Engines.NetFront], [/khtml[\/ ]\(?([\w.]+)/i, Engines.KHTML], [/tasman[\/ ]\(?([\w.]+)/i, Engines.Tasman], [/rv:([\w.]{1,9})\b.+gecko/i, Engines.Gecko] ]; var OS_NAME = OS.Unknown; var OS_VERSION = ""; var DEVICE_NAME = Devices.Unknown; var ENGINE_NAME = Engines.Unknown; var ENGINE_VERSION = ""; for (var i = 0; i < OS_RESOLVER_MAP.length; i++) { var map = OS_RESOLVER_MAP[i]; var regexp = map[0]; var os = map[1]; var device = map[2]; var resolver = map[3]; var matched = USER_AGENT.match(regexp); if (matched !== null) { OS_NAME = os; OS_VERSION = resolver(matched[1]); DEVICE_NAME = device; break; } } for (var i = 0; i < ENGINE_RESOLVER_MAP.length; i++) { var map = ENGINE_RESOLVER_MAP[i]; var regexp = map[0]; var engine = map[1]; var matched = USER_AGENT.match(regexp); if (matched !== null) { ENGINE_NAME = engine; ENGINE_VERSION = matched[1]; break; } } var RENDERER = (function () { var canvas = document.createElement("canvas"); if (typeof canvas.getContext !== "function") return ""; var context = canvas.getContext("webgl2") || canvas.getContext("experimental-webgl") || canvas.getContext("webgl"); if (context === null) return ""; if (context instanceof WebGLRenderingContext || "getParameter" in context && typeof context.getParameter === "function") { var extension = context.getExtension("WEBGL_debug_renderer_info"); if (extension === null) return context.getParameter(context.RENDERER); else return context.getParameter(extension.UNMASKED_RENDERER_WEBGL); } else { return ""; } })(); var IS_MOBILE = DEVICE_NAME === Devices.Mobile; var IS_DESKTOP = DEVICE_NAME === Devices.Desktop; var IS_STANDALONE = (function () { if (OS_NAME === OS.iOS) return navigator.standalone; else return window.matchMedia("(display-mode: standalone)").matches; })(); var IS_WEBVIEW = /; ?wv|applewebkit(?!.*safari)/i.test(USER_AGENT); var Appearances; (function (Appearances) { Appearances["Unknown"] = "unknown"; Appearances["Light"] = "light"; Appearances["Dark"] = "dark"; })(Appearances || (Appearances = {})); var CHROME_VERSION = (function getChromeVersion() { var matched = USER_AGENT.match(/chrome\/([\w.]+) mobile/i); if (matched === null) return NaN; var version = parseInt(matched[1]); if (isNaN(version)) return NaN; return version; })(); var MEDIA_QUERY_LIST = window.matchMedia("(prefers-color-scheme: dark)"); var SUPPORT_PREFERS_COLOR_SCHEME = MEDIA_QUERY_LIST.media !== "not all"; var IS_FULL_SUPPORT_THEME_COLOR = isNaN(CHROME_VERSION) || CHROME_VERSION >= 92; var CONTEXT = document.createElement("canvas").getContext("2d", { willReadFrequently: true }); var SVG_PIXEL_DATA_URL = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxyZWN0IHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9IndoaXRlIi8+PC9zdmc+"; var IS_SAMSUNG = /Samsung/i.test(USER_AGENT); var IS_IE_MOBILE = /iemobile/i.test(USER_AGENT); var IS_WINDOWS_PHONE = /windows phone/i.test(USER_AGENT); var ENTRIES = []; var Platform = { os: OS_NAME, device: DEVICE_NAME, engine: ENGINE_NAME, osVersion: OS_VERSION, engineVersion: ENGINE_VERSION, renderer: RENDERER, isWebview: IS_WEBVIEW, isMobile: IS_MOBILE, isDesktop: IS_DESKTOP, isStandalone: IS_STANDALONE, }; function getTopmostWindow() { if (window.top !== null) return window.top; return window; } function openURLViaHref(url, index) { var top = getTopmostWindow(); var a = undefined; try { if (index === 0) { top.location.href = url; return; } a = top.document.createElement("a"); a.href = url; a.style.display = "none"; a.setAttribute("aria-hidden", "true"); top.document.body.appendChild(a); var fake = void 0; try { fake = new MouseEvent("click", { bubbles: true, cancelable: true, view: top }); } catch (_) { fake = top.document.createEvent("MouseEvents"); fake.initMouseEvent("click", true, true, top, 0, 0, 0, 0, 0, false, false, false, false, 0, null); } a.dispatchEvent(fake); } catch (_) { } finally { if (a !== undefined) top.document.body.removeChild(a); } } function openURLViaIframe(url) { var top = getTopmostWindow(); var iframe = document.createElement("iframe"); iframe.width = iframe.height = iframe.frameBorder = "0"; iframe.style.display = "none"; iframe.src = url; top.document.body.appendChild(iframe); window.setTimeout(function () { try { top.document.removeChild(iframe); } catch (_) { } }, 100); } function isDocumentHidden() { var top = getTopmostWindow(); var doc = top.document; if (doc.visibilityState === "hidden") return true; if (doc.hidden !== undefined) return doc.hidden; if (doc.webkitHidden !== undefined) return doc.webkitHidden; if (typeof doc.hasFocus === "function") return !doc.hasFocus(); return true; } function tryOpenUrl(url, index, timeout) { var top = getTopmostWindow(); if (Platform.os === OS.iOS) { var visibilitychange_1; var eventTarget_1; if (parseInt(Platform.osVersion) >= 8) { visibilitychange_1 = "visibilitychange"; eventTarget_1 = top.document; } else { visibilitychange_1 = "pagehide"; eventTarget_1 = top; } return new Promise(function (resolve, reject) { var timeoutId; var resolved = false; function cleanup() { if (timeoutId) clearTimeout(timeoutId); eventTarget_1.removeEventListener(visibilitychange_1, onVisibilityChange); } function done(success) { if (!resolved) { resolved = true; try { cleanup(); if (success) resolve(); else reject(); } catch (_) { resolve(); } } } function onVisibilityChange() { if (isDocumentHidden()) done(true); } timeoutId = window.setTimeout(function () { done(false); }, timeout); eventTarget_1.addEventListener(visibilitychange_1, onVisibilityChange); try { openURLViaIframe(url); openURLViaHref(url, index); } catch (_) { done(false); } }); } else { return new Promise(function (resolve, reject) { var timeoutId; var resolved = false; function cleanup() { if (timeoutId) clearTimeout(timeoutId); top.removeEventListener("blur", onBlur); top.removeEventListener("focus", onFocus); top.document.removeEventListener("visibilitychange", onVisibilityChange); } function done(success) { if (!resolved) { resolved = true; try { cleanup(); if (success) resolve(); else reject(); } catch (_) { resolve(); } } } function onBlur() { clearTimeout(timeoutId); top.removeEventListener("blur", onBlur); top.addEventListener("focus", onFocus); } function onFocus() { done(true); } function onVisibilityChange() { if (isDocumentHidden()) done(true); } timeoutId = window.setTimeout(function () { done(false); }, timeout); top.addEventListener("blur", onBlur); top.document.addEventListener("visibilitychange", onVisibilityChange); try { openURLViaIframe(url); openURLViaHref(url, index); } catch (_) { done(false); } }); } } function createCustomError(name, Base) { if (Base === void 0) { Base = Error; } function CustomError(message) { if (message === void 0) { message = ""; } if (!(this instanceof CustomError)) return new CustomError(message); var error = new Base(message); var proto = CustomError.prototype; if (typeof Object.setPrototypeOf === "function") Object.setPrototypeOf(error, proto); else error.__proto__ = proto; error.name = name; error.message = message; if (typeof Symbol === "function" && typeof Symbol.toStringTag === "symbol") Object.defineProperty(error, Symbol.toStringTag, { value: name, writable: false, enumerable: false, configurable: true }); var captureStackTrace = Base.captureStackTrace; if (typeof captureStackTrace === "function") captureStackTrace(error, CustomError); else if (Error.prototype.stack !== undefined) error.stack = new Base().stack; return error; } CustomError.prototype = Object.create(Base.prototype); CustomError.prototype.constructor = CustomError; try { CustomError.prototype.name = name; } catch (_) { } return CustomError; } var URLOpenError = createCustomError("URLOpenError"); var _a; var App = { open: open, messenger: (_a = {}, _a[Messengers.Telephone] = openMessengerTelephone, _a[Messengers.Message] = openMessengerMessage, _a[Messengers.Mail] = openMessengerMail, _a), }; function getTrackId(bundle) { try { var xhr = new XMLHttpRequest(); xhr.open("GET", "https://itunes.apple.com/lookup?bundleId=" + bundle, false); xhr.send(); if (xhr.status === 200) { var response = JSON.parse(xhr.response); if (response.results !== undefined && response.results.length > 0) return response.results[0].trackId; } return undefined; } catch (_) { return undefined; } } function createIntentURL(scheme, packageName, fallback) { var split = scheme.split("://"); var prefix = split[0]; var suffix = split[1]; var intent = "intent://"; if (suffix !== undefined) intent = intent + suffix; intent = intent + "#Intent;" + "scheme=" + prefix + ";" + "action=android.intent.action.VIEW;" + "category=android.intent.category.BROWSABLE;"; if (packageName !== undefined) intent = intent + "package=" + packageName + ";"; if (fallback !== undefined) intent = intent + "S.browser_fallback_url=" + fallback + ";"; else if (packageName !== undefined) intent = intent + "S.browser_fallback_url=" + createAppStoreURL(packageName, OS.Android) + ";"; return intent + "end"; } function parseIntentURL(intent) { var parsed = {}; var split = intent.split("#Intent;"); var host = split[0].substring(9); var suffix = split[1]; var parameterString = suffix.substring(0, suffix.length - 4); var parameters = parameterString.split(";"); var extras = {}; for (var i = 0; i < parameters.length; i++) { var part = parameters[i]; var index = part.indexOf("="); if (index !== -1) extras[part.substring(0, index)] = part.substring(index + 1); } if (extras["scheme"] !== undefined) parsed.scheme = (extras["scheme"] + "://" + host); if (extras["package"] !== undefined) parsed.packageName = extras["package"]; if (extras["S.browser_fallback_url"] !== undefined) parsed.fallback = extras["S.browser_fallback_url"]; return parsed; } function createAppStoreURL(packageName, os) { switch (os) { case OS.Android: return "market://details?id=" + packageName; case OS.iOS: return "itms-apps://itunes.apple.com/app/id" + packageName + "?mt=8"; case OS.Windows: return "ms-windows-store://pdp/?ProductId=" + packageName; case OS.MacOS: return "macappstore://itunes.apple.com/app/id" + packageName + "?mt=12"; default: throw new URLOpenError("Unsupported OS: \"" + USER_AGENT + "\""); } } function createWebStoreURL(packageName, os) { switch (os) { case OS.Android: return "https://play.google.com/store/apps/details?id=" + packageName; case OS.iOS: return "https://itunes.apple.com/app/id" + packageName + "?mt=8"; case OS.Windows: return "https://apps.microsoft.com/detail/" + packageName; case OS.MacOS: return "https://apps.apple.com/app/id" + packageName + "?mt=12"; default: throw new URLOpenError("Unsupported OS: \"" + USER_AGENT + "\""); } } function getDefaultTimeoutByOS(os) { switch (os) { case OS.iOS: return 2000; case OS.Android: return 1000; default: return 750; } } function open(options) { var os = OS_NAME; var urls = []; var tried = []; var timeout; function getURLOpenError() { var triedUrlString = ""; for (var i = 0; i < urls.length; i++) triedUrlString += "\n" + (i + 1) + ": " + tried[i]; if (triedUrlString.length > 0) triedUrlString = "\n" + triedUrlString + "\n"; return new URLOpenError("Failed to open any of the provided URLs: " + triedUrlString); } if (os === OS.Android) { var option = options[OS.Android]; if (option === undefined) return Promise.reject(getURLOpenError()); timeout = option.timeout; var scheme = option.scheme; var intent = option.intent; var packageName = option.packageName; var fallback = option.fallback; var allowWebStore = option.allowWebStore; if (intent !== undefined && (scheme === undefined || packageName === undefined || fallback === undefined)) { var parsed = parseIntentURL(intent); if (parsed.scheme !== undefined && scheme === undefined) scheme = parsed.scheme; if (parsed.packageName !== undefined && packageName === undefined) packageName = parsed.packageName; if (parsed.fallback !== undefined && fallback === undefined) fallback = parsed.fallback; } if (scheme !== undefined && intent === undefined) intent = createIntentURL(scheme, packageName, fallback); if (intent !== undefined && IS_SUPPORT_INTENT) urls.push([intent, AppOpenState.Intent]); if (scheme !== undefined) urls.push([scheme, AppOpenState.Scheme]); if (fallback !== undefined) urls.push([fallback, AppOpenState.Fallback]); if (packageName !== undefined) urls.push([createAppStoreURL(packageName, OS.Android), AppOpenState.Store]); if (packageName !== undefined && allowWebStore === true) urls.push([createWebStoreURL(packageName, OS.Android), AppOpenState.Store]); } else if (os === OS.iOS) { var option = options[OS.iOS]; if (option === undefined) return Promise.reject(getURLOpenError()); timeout = option.timeout; var scheme = option.scheme; var packageName = option.packageName; var trackId = option.trackId; var universal = option.universal; var fallback = option.fallback; var allowWebStore = option.allowWebStore; if (packageName !== undefined && trackId === undefined) trackId = getTrackId(packageName); if (universal !== undefined && parseInt(OS_VERSION) >= 9) urls.push([universal, AppOpenState.Universal]); if (scheme !== undefined) urls.push([scheme, AppOpenState.Scheme]); if (fallback !== undefined) urls.push([fallback, AppOpenState.Fallback]); if (trackId !== undefined) urls.push([createAppStoreURL(trackId, OS.iOS), AppOpenState.Store]); if (trackId !== undefined && allowWebStore === true) urls.push([createWebStoreURL(trackId, OS.iOS), AppOpenState.Store]); } else if (os === OS.Windows) { var option = options[OS.Windows]; if (option === undefined) return Promise.reject(getURLOpenError()); timeout = option.timeout; var scheme = option.scheme; var productId = option.productId; var fallback = option.fallback; var allowWebStore = option.allowWebStore; if (scheme !== undefined) urls.push([scheme, AppOpenState.Scheme]); if (fallback !== undefined) urls.push([fallback, AppOpenState.Fallback]); if (productId !== undefined) urls.push([createAppStoreURL(productId, OS.Windows), AppOpenState.Store]); if (productId !== undefined && allowWebStore === true) urls.push([createWebStoreURL(productId, OS.Windows), AppOpenState.Store]); } else if (os === OS.MacOS) { var option = options[OS.MacOS]; if (option === undefined) return Promise.reject(getURLOpenError()); timeout = option.timeout; var scheme = option.scheme; var packageName = option.packageName; var trackId = option.trackId; var fallback = option.fallback; var allowWebStore = option.allowWebStore; if (packageName !== undefined && trackId === undefined) trackId = getTrackId(packageName); if (scheme !== undefined) urls.push([scheme, AppOpenState.Scheme]); if (fallback !== undefined) urls.push([fallback, AppOpenState.Fallback]); if (trackId !== undefined) urls.push([createAppStoreURL(trackId, OS.MacOS), AppOpenState.Store]); if (trackId !== undefined && allowWebStore === true) urls.push([createWebStoreURL(trackId, OS.MacOS), AppOpenState.Store]); } if (timeout === undefined) timeout = getDefaultTimeoutByOS(os); return new Promise(function (resolve, reject) { function openURLSequential(index) { if (index === void 0) { index = 0; } if (index >= urls.length) return reject(getURLOpenError()); var entry = urls[index]; var url = entry[0]; tried[index] = url; return tryOpenUrl(url, index, timeout) .then(function () { resolve(entry[1]); }) .catch(function () { openURLSequential(index + 1); }); } return openURLSequential(); }); } function isArrayLike(value) { if (value == null || typeof value === "string") return false; var length = value.length; return typeof length === "number" && length >= 0 && !(length % 1); } function joining(values, mapfn, separator) { if (separator === void 0) { separator = ","; } var length = values.length; var result = ""; for (var i = 0; i < length; i++) { result = result + mapfn(values[i]); if (i !== length - 1) result = result + separator; } return result; } function encode(value) { return encodeURIComponent(value) .replace(/[!'()*]/g, function (c) { return "%" + c.charCodeAt(0).toString(16); }); } function toString(value) { if (typeof value === "string") return encode(value); if (typeof value === "number" || typeof value === "boolean") return encode(String(value)); if (value == null) return ""; if (isArrayLike(value)) return joining(value, function (v) { return toString(v); }); if (value instanceof HTMLInputElement) { var type = value.type; if (type === "checkbox") { return encode(value.checked.toString()); } else if (type === "radio") { if (value.checked) return encode(value.value); else return ""; } else if (type === "file") { var files = value.files; if (files === null) return ""; return joining(files, function (file) { return encode(file.name); }); } else { return encode(value.value); } } if (value instanceof HTMLSelectElement) { if (value.multiple) return joining(value.selectedOptions, function (option) { return encode(option.value); }); return encode(value.value); } if (value instanceof HTMLTextAreaElement) return encode(value.value); if (value instanceof HTMLElement) return encode(value.innerText); if (value instanceof Node) return toString(value.textContent); return encode(value.toString()); } function normalize(value) { if (value instanceof HTMLFormElement) return normalize(new FormData(value)); if (value instanceof FormData) { var result_1 = {}; value.forEach(function (value, key) { var name; if (value instanceof File) name = value.name; else name = value; if (Object.prototype.hasOwnProperty.call(result_1, key)) { var prev = result_1[key]; if (Array.isArray(prev)) prev.push(name); else result_1[key] = [prev, name]; } else { result_1[key] = name; } }); return normalize(result_1); } var result = {}; var keys = Object.keys(value); for (var i = 0; i < keys.length; i++) { var key = keys[i]; result[key] = toString(value[key]); } if (result.to === undefined) result.to = ""; if (result.cc === undefined) result.cc = ""; if (result.bcc === undefined) result.bcc = ""; if (result.subject === undefined) result.subject = ""; if (result.body === undefined) result.body = ""; return result; } function openMessenger(options, type) { options = normalize(options); return tryOpenUrl(type + ":" + options.to + "?cc=" + options.cc + "&bcc=" + options.bcc + "&subject=" + options.subject + "&body=" + options.body, 0, getDefaultTimeoutByOS(OS_NAME)); } function openMessengerTelephone(options) { return openMessenger(options, "tel"); } function openMessengerMessage(options) { return openMessenger(options, "sms"); } function openMessengerMail(options) { return openMessenger(options, "mailto"); } var EasingError = createCustomError("EasingError"); var CubicBezierSyntaxError = createCustomError("CubicBezierSyntaxError", EasingError); var LinearSyntaxError = createCustomError("LinearSyntaxError", EasingError); var StepSyntaxError = createCustomError("StepSyntaxError", EasingError); var UnsupportedEasingFunctionError = createCustomError("UnsupportedEasingFunctionError", EasingError); var EASING_KEYWORD = { "linear": "linear(0, 1)", "ease": "cubic-bezier(0.25, 0.1, 0.25, 1)", "ease-in": "cubic-bezier(0.42, 0, 1, 1)", "ease-out": "cubic-bezier(0, 0, 0.58, 1)", "ease-in-out": "cubic-bezier(0.42, 0, 0.58, 1)", "step-start": "steps(1, jump-start)", "step-end": "steps(1, jump-end)", }; function clamp(n, min, max) { if (n < min) return min; if (n > max) return max; return n; } function isEasingKeyword(easingFunction) { return !/(linear|cubic-bezier|steps)\((.*)\)/.test(easingFunction); } function isCubicBezierString(easingFunction) { return /cubic-bezier\(/.test(easingFunction); } function isLinearString(easingFunction) { return /linear\(/.test(easingFunction); } function isStepString(easingFunction) { return /steps\(\s*(\d+)\s*(?:,\s*(jump-start|jump-end|jump-none|jump-both|start|end)\s*)?\)$/.test(easingFunction); } function parseCubicBezier(easingFunction) { var match = easingFunction.match(/cubic-bezier\((.*)\)/); var content = match[1].trim(); var split = content.split(","); var values = []; if (split.length !== 4) throw new CubicBezierSyntaxError("Cubic-bezier must have exactly 4 numeric values"); for (var i = 0; i < 4; i++) { var value = parseFloat(split[i]); if (isNaN(value)) throw new CubicBezierSyntaxError("Cubic-bezier must have exactly 4 numeric values"); if (i % 2 === 0 && (value < 0 || value > 1)) throw new CubicBezierSyntaxError("x1 and x2 must be between 0 and 1"); values.push(value); } return { x1: values[0], y1: values[1], x2: values[2], y2: values[3] }; } function getCubicBezierValue(easingFunction) { var cubicBezier = parseCubicBezier(easingFunction); var x1 = cubicBezier.x1; var x2 = cubicBezier.x2; var y1 = cubicBezier.y1; var y2 = cubicBezier.y2; function findT(x, tolerance, maxIterations) { if (tolerance === void 0) { tolerance = 1e-6; } if (maxIterations === void 0) { maxIterations = 50; } if (x <= 0) return 0; if (x >= 1) return 1; var t = x; for (var i = 0; i < maxIterations; i++) { var xt = 3 * (1 - t) * (1 - t) * t * x1 + 3 * (1 - t) * t * t * x2 + t * t * t; var dx = 3 * (1 - t) * (1 - t) * x1 + 6 * (1 - t) * t * (x2 - x1) + 3 * t * t * (1 - x2); if (Math.abs(dx) < tolerance) break; var newT = t - (xt - x) / dx; if (Math.abs(newT - t) < tolerance) { t = newT; break; } t = Math.max(0, Math.min(1, newT)); } return t; } return function (x) { x = clamp(x, 0, 1); if (x === 0 || x === 1) return x; var t = findT(x); return 3 * (1 - t) * (1 - t) * t * y1 + 3 * (1 - t) * t * t * y2 + t * t * t; }; } function parseLinear(easingFunction) { var match = easingFunction.match(/linear\((.*)\)/); var content = match[1].trim(); var split = content.split(","); var points = []; for (var i = 0; i < split.length; i++) { var part = split[i].trim(); var percentage2 = part.match(/^([+-]?\d*\.?\d+)((?:\s+[+-]?\d*\.?\d+%){2,})$/); if (percentage2 !== null) { var value = parseFloat(percentage2[1]); var percents = percentage2[2].trim().split(/\s+/); points.push({ value: value, position: parseFloat(percents[0]) / 100, }, { value: value, position: parseFloat(percents[1]) / 100, }); continue; } var percentage1 = part.match(/^([+-]?\d*\.?\d+)\s+([+-]?\d*\.?\d+)%$/); if (percentage1 !== null) { points.push({ position: parseFloat(percentage1[2]) / 100, value: parseFloat(percentage1[1]) }); continue; } var number = part.match(/^([+-]?\d*\.?\d+)$/); if (number !== null) { points.push({ position: split.length === 1 ? 0 : i / (split.length - 1), value: parseFloat(number[1]) }); continue; } throw new LinearSyntaxError("Invalid linear point format: \"" + part + "\""); } if (points.length === 0) throw new LinearSyntaxError("No valid points found in linear function"); for (var i = 0; i < points.length - 1; i++) { for (var j = 0; j < points.length - i - 1; j++) { if (points[j].position > points[j + 1].position) { var temp = points[j]; points[j] = points[j + 1]; points[j + 1] = temp; } } } return points; } function getLinearValue(str) { var points = parseLinear(str); return function (t) { t = clamp(t, 0, 1); if (t <= points[0].position) return points[0].value; if (t >= points[points.length - 1].position) return points[points.length - 1].value; for (var i = 0; i < points.length - 1; i++) { var p1 = points[i]; var p2 = points[i + 1]; if (t >= p1.position && t <= p2.position) { var ratio = (t - p1.position) / (p2.position - p1.position); return p1.value + (p2.value - p1.value) * ratio; } } throw new LinearSyntaxError("Unexpected error in interpolation"); }; } function getStepValue(easingFunction) { var match = easingFunction.match(/steps\(\s*(\d+)\s*(?:,\s*(jump-start|jump-end|jump-none|jump-both|start|end)\s*)?\)$/); var count = parseInt(match[1], 10); var position = match[2]; return function (t) { t = clamp(t, 0, 1); if (t === 0) return position === "start" || position === "jump-start" ? 1 : 0; else if (t === 1) return 1; switch (position) { case "start": case "jump-start": return Math.ceil(t * count) / count; case "end": case "jump-end": return Math.floor(t * count) / count; case "jump-both": return Math.round(t * count) / count; case "jump-none": return Math.floor(t * count) / (count - 1); default: throw new StepSyntaxError("Unsupported step position: \"" + position + "\""); } }; } function parseEasingFunction(easingFunction) { if (isEasingKeyword(easingFunction)) easingFunction = EASING_KEYWORD[easingFunction]; if (isCubicBezierString(easingFunction)) return getCubicBezierValue(easingFunction); if (isLinearString(easingFunction)) return getLinearValue(easingFunction); if (isStepString(easingFunction)) return getStepValue(easingFunction); throw new UnsupportedEasingFunctionError("Unsupported easing function: \"" + easingFunction + "\""); } var UnsupportedColorError = createCustomError("UnsupportedColorError"); function parseColor(color) { if (!CSS.supports("color", color)) throw new UnsupportedColorError("Unsupported color: \"" + color + "\"."); if (CONTEXT !== null) { CONTEXT.clearRect(0, 0, 1, 1); CONTEXT.fillStyle = color; CONTEXT.fillRect(0, 0, 1, 1); var data = CONTEXT.getImageData(0, 0, 1, 1).data; return { red: data[0], green: data[1], blue: data[2], alpha: +(data[3] / 255).toFixed(2) }; } var div = document.createElement("div"); div.style.position = "absolute"; div.style.top = "-9999px"; div.style.width = div.style.height = "0"; div.style.color = color; document.body.appendChild(div); var computedColor = window.getComputedStyle(div).color; var matched = computedColor.match(/rgba?\(\s*(\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\s*\)/); document.body.removeChild(div); if (matched === null) throw new UnsupportedColorError("Unsupported color: \"" + color + "\"."); var rgba = { red: parseInt(matched[1], 10), green: parseInt(matched[2], 10), blue: parseInt(matched[3], 10), alpha: NaN }; if (matched[4] === undefined) rgba.alpha = 1; else rgba.alpha = parseFloat(matched[4]); return rgba; } var themeColorMetaGroup = {}; var themeIntervalId = null; var currentResolve = null; var currentAppearance = null; var appearanceIntervalId = null; var Theme = { setThemeColor: setThemeColor, getThemeColor: getThemeColor, removeThemeColor: removeThemeColor, detectAppearance: detectAppearance, onAppearanceChange: onAppearanceChange, }; function getThemeColorMeta(appearance) { if (appearance === void 0) { appearance = "default"; } var effective; if (!IS_FULL_SUPPORT_THEME_COLOR || !SUPPORT_PREFERS_COLOR_SCHEME || IS_IE_MOBILE || IS_WINDOWS_PHONE) effective = "default"; else effective = appearance; var meta = themeColorMetaGroup[effective]; if (meta !== undefined) return meta; meta = document.createElement("meta"); if (IS_IE_MOBILE) meta.setAttribute("name", "msapplication-navbutton-color"); else if (IS_WINDOWS_PHONE) meta.setAttribute("name", "msapplication-TileColor"); else meta.setAttribute("name", "theme-color"); if (appearance !== "default") meta.setAttribute("media", "(prefers-color-scheme: " + effective + ")"); document.head.prepend(meta); return themeColorMetaGroup[appearance] = meta; } function estimateDefaultThemeColor() { if (/version\/[\w.,]+ .*safari/i.test(USER_AGENT)) { if (navigator.standalone) { if (detectFromMediaQuery() === Appearances.Dark) return "#ffffffff"; else return "#000000ff"; } return rgbaToHex(parseColor(window.getComputedStyle(document.body).backgroundColor)); } if (/\b(?:crmo|crios)\/[\w.]+/i.test(USER_AGENT) || /chrome\/[\w.]+ mobile/i.test(USER_AGENT)) { if (detectFromMediaQuery() === Appearances.Dark) return "#28292cff"; else return "#ffffffff"; } return undefined; } function toHex(n) { var hex = n.toString(16); switch (hex.length) { case 0: return "00"; case 1: return "0" + hex; default: return hex; } } function rgbaToHex(rgba) { return "#" + toHex(rgba.red) + toHex(rgba.green) + toHex(rgba.blue) + toHex(Math.round(rgba.alpha * 255)); } function detectFromEngine() { return new Promise(function (resolve) { var img = new Image(); img.onload = function () { if (CONTEXT === null) return resolve(Appearances.Light); CONTEXT.drawImage(img, 0, 0); var data = CONTEXT.getImageData(0, 0, 1, 1).data; if ((data[0] & data[1] & data[2]) < 255) resolve(Appearances.Dark); else resolve(Appearances.Light); }; img.onerror = function () { resolve(Appearances.Unknown); }; img.src = SVG_PIXEL_DATA_URL; }); } function detectFromMediaQuery() { if (!SUPPORT_PREFERS_COLOR_SCHEME) return Appearances.Unknown; if (MEDIA_QUERY_LIST.matches) return Appearances.Dark; return Appearances.Light; } function startPolling() { detectFromEngine() .then(function (appearance) { currentAppearance = appearance; }); appearanceIntervalId = window.setInterval(function () { detectFromEngine() .then(function (appearance) { if (appearance !== currentAppearance) { currentAppearance = appearance; notify(appearance); } }); }, 2000); } function stopPolling() { currentAppearance = null; if (appearanceIntervalId !== null) { clearInterval(appearanceIntervalId); appearanceIntervalId = null; } } function addListener(capture) { currentAppearance = detectFromMediaQuery(); if (typeof MEDIA_QUERY_LIST.addEventListener === "function") MEDIA_QUERY_LIST.addEventListener("change", onMediaChange, capture); else if (typeof MEDIA_QUERY_LIST.addListener === "function") MEDIA_QUERY_LIST.addListener(onMediaChange); } function removeListener(capture) { currentAppearance = null; if (typeof MEDIA_QUERY_LIST.removeEventListener === "function") MEDIA_QUERY_LIST.removeEventListener("change", onMediaChange, capture); else if (typeof MEDIA_QUERY_LIST.removeListener === "function") MEDIA_QUERY_LIST.removeListener(onMediaChange); } function onMediaChange(ev) { var appearance; if (ev.matches) appearance = Appearances.Dark; else appearance = Appearances.Light; if (appearance !== currentAppearance) notify(currentAppearance = appearance); } function notify(appearance) { for (var i = 0; i < ENTRIES.length; i++) { var entry = ENTRIES[i]; entry.fn(appearance); if (entry.once) removeEntry(entry); } } function removeEntry(entry) { var index = indexOfEntry(entry); if (index !== -1) ENTRIES.splice(index, 1); if (ENTRIES.length === 0) { if (IS_SAMSUNG) stopPolling(); else removeListener(entry.capture); } } function indexOfEntry(entry) { for (var i = 0; i < ENTRIES.length; i++) if (ENTRIES[i].fn === entry.fn && ENTRIES[i].capture === entry.capture) return i; return -1; } function syncThemeColorMeta() { themeColorMetaGroup = {}; var selector; if (IS_IE_MOBILE) selector = "meta[name=\"msapplication-navbutton-color\"]"; else if (IS_WINDOWS_PHONE) selector = "meta[name=\"msapplication-TileColor\"]"; else selector = "meta[name=\"theme-color\"]"; var nodes = document.querySelectorAll(selector); if (!IS_FULL_SUPPORT_THEME_COLOR || !SUPPORT_PREFERS_COLOR_SCHEME || IS_IE_MOBILE || IS_WINDOWS_PHONE) { themeColorMetaGroup.default = nodes[0]; return; } for (var i = 0; i < nodes.length; i++) { var element = nodes.item(i); var media = element.getAttribute("media"); if (media === "(prefers-color-scheme: dark)" && themeColorMetaGroup.dark === undefined) themeColorMetaGroup.dark = element; else if (media === "(prefers-color-scheme: light)" && themeColorMetaGroup.light === undefined) themeColorMetaGroup.light = element; else if (media === null && themeColorMetaGroup.default === undefined) themeColorMetaGroup.default = element; if (themeColorMetaGroup.dark !== undefined && themeColorMetaGroup.light !== undefined && themeColorMetaGroup.default !== undefined) return; } } function getCurrentAppliedThemeColorMeta() { if (IS_IE_MOBILE) return document.querySelector("meta[name=\"msapplication-navbutton-color\"]"); if (IS_WINDOWS_PHONE) return document.querySelector("meta[name=\"msapplication-TileColor\"]"); if (!IS_FULL_SUPPORT_THEME_COLOR || !SUPPORT_PREFERS_COLOR_SCHEME) return document.querySelector("meta[name=\"theme-color\"]"); var nodes = document.querySelectorAll("meta[name=\"theme-color\"]"); var isDark = detectFromMediaQuery() === Appearances.Dark; var query; if (isDark) query = "(prefers-color-scheme: dark)"; else query = "(prefers-color-scheme: light)"; for (var i = 0; i < nodes.length; i++) { var element = nodes.item(i); if (!element.hasAttribute("content")) continue; var media = element.getAttribute("media"); if (media === null || media === query) return element; } return null; } function init() { var observer = new MutationObserver(function (mutations) { for (var i = 0; i < mutations.length; i++) { var mutation = mutations[i]; var addedNodes = mutation.addedNodes; var removedNodes = mutation.removedNodes; for (var j = 0; j < addedNodes.length; j++) if (addedNodes[j] instanceof HTMLMetaElement) return syncThemeColorMeta(); for (var j = 0; j < removedNodes.length; j++) if (removedNodes[j] instanceof HTMLMetaElement) return syncThemeColorMeta(); } }); if (typeof MEDIA_QUERY_LIST.addEventListener === "function") MEDIA_QUERY_LIST.addEventListener("change", syncThemeColorMeta); else if (typeof MEDIA_QUERY_LIST.addListener === "function") MEDIA_QUERY_LIST.addListener(syncThemeColorMeta); observer.observe(document.head, { childList: true }); syncThemeColorMeta(); } init(); function setThemeColor(color, options) { if (options === void 0) { options = { duration: 0, easingFunction: "linear", appearance: "default" }; } var duration = options.duration; var easingFn = parseEasingFunction(options.easingFunction); var appearance = options.appearance; if (themeIntervalId !== null) { window.cancelAnimationFrame(themeIntervalId); themeIntervalId = null; if (currentResolve !== null) { currentResolve(getThemeColor()); currentResolve = null; } } var themeColor = getThemeColor(); if (themeColor === undefined) { if (options.defaultColor !== undefined) { themeColor = options.defaultColor; } else { if (detectFromMediaQuery() === Appearances.Dark) themeColor = "#181818ff"; else themeColor = "#dcdcdcff"; } } var startColor = parseColor(themeColor); var endColor = parseColor(color); return new Promise(function (resolve) { currentResolve = resolve; var startTime = null; function animate(timestamp) { if (startTime === null) startTime = timestamp; var elapsed = timestamp - startTime; var t; if (duration === 0) t = 1; else t = Math.min(elapsed / duration, 1); var easedT = easingFn(t); var current = { red: Math.round(startColor.red + (endColor.red - startColor.red) * easedT), green: Math.round(startColor.green + (endColor.green - startColor.green) * easedT), blue: Math.round(startColor.blue + (endColor.blue - startColor.blue) * easedT), alpha: +(startColor.alpha + (endColor.alpha - startColor.alpha) * easedT).toFixed(2), }; getThemeColorMeta(appearance).setAttribute("content", rgbaToHex(current)); if (t < 1) { themeIntervalId = window.requestAnimationFrame(animate); } else { themeIntervalId = null; if (currentResolve !== null) {