UNPKG

@kamen/create-webapp

Version:
395 lines (343 loc) 10.2 kB
const primitiveTypeRe = /^string|number|bigint|boolean|symbol$/; const objectTypeRe = /^object|function$/; export {default as temporal} from './temporal.js'; /** * @param {*} value * @returns {boolean} */ export function isPrimitive(value) { return primitiveTypeRe.test(typeof value); } /** * @param {*} value * @returns {boolean} */ export function isObject(value) { return value !== null && objectTypeRe.test(typeof value); } /** * @param {number} offset * @param {number} length * @returns {number} */ export function modulo(offset, length) { return ((offset % length) + length) % length; } /** * @param {number} [min=0] * @param {number} [max=255] * @param {number} [step=1] * @returns {number[]} */ export function range(min = 0, max = 255, step = 1) { return Array.from({length: (max - min) / step + 1}, (_, index) => index * step + min); } /** * @param {number} value * @param {number} [min=0] * @param {number} [max=255] * @returns {number} */ export function clamp(value, min = 0, max = 255) { return Math.min(Math.max(value, min), max); } /** * @returns {string} */ export function randomSlug() { return Math.random().toString(36).slice(2); } /** * @param {number} [min=0] * @param {number} [max=255] * @returns {number} */ export function randomFromRange(min = 0, max = 255) { return Math.floor(Math.random() * (max - min + 1) + min); } /** * @template T * @param {T[]} [list=[]] * @returns {T} */ export function randomFromList(list = []) { return list[randomFromRange(0, list.length - 1)]; } /** * @param {number} [saturation=80] * @param {number} [lightness=80] * @param {number} [alpha=1] * @returns {string} */ export function randomColorFromSaturationLightnessAlpha(saturation = 80, lightness = 80, alpha = 1) { const hue = randomFromRange(0, 359); return `hsla(${hue}, ${saturation}%, ${lightness}%, ${alpha})`; } /** * @param {number} [min=0] * @param {number} [max=255] * @returns {Function<number>} */ export function createRandomFromRange(min = 0, max = 255) { return function () { return randomFromRange(min, max); } } /** * @template T * @param {T[]} [list=[]] * @returns {Function<T>} */ export function createRandomFromList(list = []) { return function () { return randomFromList(list); } } /** * @param {number} [saturation=80] * @param {number} [lightness=80] * @param {number} [alpha=1] * @returns {Function<string>} */ export function createRandomColorFromSaturationLightnessAlpha(saturation = 80, lightness = 80, alpha = 1) { return function () { return randomColorFromSaturationLightnessAlpha(saturation, lightness, alpha); } } /** * @param {string} [text=''] * @param {number} [saturation=80] * @param {number} [lightness=80] * @param {number} [alpha=1] * @returns {string} */ export function textToHsla(text = '', saturation = 80, lightness = 80, alpha = 1) { let hash = 0; for (let i = 0, {length} = text; i < length; i++) hash = text.charCodeAt(i) + ((hash << 5) - hash); return `hsla(${hash % 360}, ${saturation}%, ${lightness}%, ${alpha})`; } /** * @param {number} [max=1<<24] * @returns {Set<number>} */ export function sieveOfEratosthenes(max = 1 << 24) { const primes = new Set; for (let i = 2; i < max; i++) primes.add(i); for (let p = 2; p * p <= max; p++) if (primes.has(p)) for (let i = p * p; i <= max; i += p) primes.delete(i); return primes; } /** * @param {string|Function} code * @param {string} [type='text/javascript'] * @returns {string} */ export function createResource(code, type = 'text/javascript') { return URL.createObjectURL(new Blob([typeof code === 'function' ? code.toString() : code], {type})); } /** * @param {string|Function} code * @param {string} [tag='iframe'] * @param {string} [attribute='src'] * @param {string} [type='text/html'] * @param {Node} [container=document.body] * @returns {Element} */ export function createResourceTag(code, tag = 'iframe', attribute = 'src', type = 'text/html', container = document.body) { const element = document.createElement(tag); element.setAttribute(attribute, createResource(code, type)); return container.appendChild(element); } /** * @param {string|Function} code * @returns {Worker} */ export function createResourceClassicWorker(code) { return new Worker(createResource(code), {type: 'classic'}); } /** * @param {string|Function} code * @returns {Worker} */ export function createResourceModuleWorker(code) { return new Worker(createResource(code), {type: 'module'}); } /** * @param {string|Function} code * @param {Node} [container=document.head] * @returns {HTMLScriptElement} */ export function createResourceClassicScript(code, container = document.head) { return createResourceTag(code, 'script', 'type', 'text/javascript', container); } /** * @param {string|Function} code * @param {Node} [container=document.head] * @returns {HTMLScriptElement} */ export function createResourceModuleScript(code, container = document.head) { return createResourceTag(code, 'script', 'type', 'module', container); } /** * @param {string|Function} code * @param {Node} [container=document.head] * @returns {HTMLStyleElement} */ export function createResourceStyle(code, container = document.head) { return createResourceTag(code, 'style', 'type', 'text/css', container); } /** * @param {string|Function} code * @param {Node} [container=document.body] * @returns {HTMLIFrameElement} */ export function createResourceIframe(code, container = document.body) { return createResourceTag(code, 'iframe', 'src', 'text/html', container); } /** * @param {string} [module='axios'] * @returns {Promise} */ export function npmModule(module = 'axios') { const cdns = [ `https://esm.sh/${module}`, `https://esm.run/${module}`, `https://jspm.dev/${module}`, `https://unpkg.com/${module}?module`, `https://cdn.skypack.dev/${module}` ]; return Promise.any(cdns.map(cdn => import(cdn))); } /** * @param {string[]} [modules=[]] * @returns {Promise} */ export function npmModules(modules = []) { return Promise.allSettled(modules.map(npmModule)); } /** * @param {number} [version=2] * @param {Node} [root=document] * @param {string} [hook='__VUE_DEVTOOLS_GLOBAL_HOOK__'] * @returns {Element|string} */ export function findVue(version = 2, root = document, hook = '__VUE_DEVTOOLS_GLOBAL_HOOK__') { let element; const property = version === 2 ? '__vue__' : '__vue_app__'; const treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT); while (element = treeWalker.nextNode()) if (property in element) { const {[property]: app} = element; const {config} = version === 2 ? app.constructor : app; config.devtools = true; if (hook in window) window[hook].Vue = app.constructor; return app; } return 'Vue mountpoint not found'; } export class DOMUtils { static namespaces = class NameSpaces { static HTML = 'http://www.w3.org/1999/xhtml'; static MathML = 'http://www.w3.org/1998/Math/MathML'; static SVG = 'http://www.w3.org/2000/svg'; }; static createHTMLElement(tag = '') { return document.createElementNS(this.namespaces.HTML, tag); } static createMathMLElement(tag = '') { return document.createElementNS(this.namespaces.MathML, tag); } static createSVGElement(tag = '') { return document.createElementNS(this.namespaces.SVG, tag); } } /** * URL wrapper implementing builder pattern */ export class URLBuilder { static create(url, base) { return new this(url, base); } constructor(url, base) { this.url = new URL(url, base); } appendParams(name, value) { this.url.searchParams.append(name, value); return this; } deleteParams(name, value) { this.url.searchParams.delete(name, value); return this; } setParams(name, value) { this.url.searchParams.set(name, value); return this; } createParams(options) { this.url.searchParams = new URLSearchParams(options); return this; } get hash() { return this.url.hash; } toString() { return this.url.toString(); } } export class WrappedListIndexManager extends EventTarget { #counter = 0; #length = 16; #step = 1; static create() { return new this; } #dispatchEvent(detail = this.getIndex()) { return this.dispatchEvent(new CustomEvent('change', {detail})); } setCounter(counter = 0) { this.#counter = counter; this.#dispatchEvent(); return this; } setLength(length = 16) { this.#length = length; this.#dispatchEvent(); return this; } setStep(step = 1) { this.#step = step; return this; } increment(step = this.#step) { this.#counter += step; this.#dispatchEvent(); return this; } decrement(step = this.#step) { this.#counter -= step; this.#dispatchEvent(); return this; } getIndex() { return modulo(this.#counter, this.#length); } } export const introspection = { isPrimitive, isObject }; export const numbering = { modulo, range, clamp }; export const randomness = { randomFromRange, createRandomFromRange, randomFromList, createRandomFromList, randomColorFromSaturationLightnessAlpha, createRandomColorFromSaturationLightnessAlpha };