UNPKG

@windijs/helpers

Version:

@windijs/helpers

1,284 lines (1,266 loc) 44.7 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var shared = require('@windijs/shared'); // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types // pre-defined keywords const initial = "initial"; const inherit = "inherit"; const unset = "unset"; const none = "none"; /** * Merge two object and their nested children */ function mergeObject(a, b) { return Object.entries(b).reduce((o, [k, v]) => { o[k] = v && typeof v === "object" ? mergeObject((o[k] = o[k] || (Array.isArray(v) ? [] : {})), v) : v; return o; }, a); } const SymbolCSS = Symbol.for("css"); const SymbolMeta = Symbol.for("meta"); const SymbolData = Symbol.for("data"); const SymbolProxy = Symbol.for("proxy"); function isProxy(i) { return i != null && SymbolProxy in i; } function isStyleObject(i) { return i != null && (typeof i === "object" || typeof i === "function") && i[SymbolCSS] != null; } function isStyleArray(i) { return Array.isArray(i) && i.find(o => isStyleObject(o) || isStyleArray(o)); } function getStyleVariants(style) { return style[SymbolMeta].variants; } function getStyleProps(style) { const { uid, children, props } = style[SymbolMeta]; if (Array.isArray(children)) style = children[0]; return [uid, ...(props ?? [])].filter(i => i != null); } function getStyleIdent(style) { return (getStyleVariants(style) .map(i => i + ":") .join("") + getStyleProps(style).join(".")); } function getFirstVar(style) { const css = style[SymbolCSS]; for (const [k, v] of shared.entries(css)) if (k.startsWith("--w-")) return [k, v]; return undefined; } function applyVariant(utility) { let css = utility[SymbolCSS]; for (const variant of utility[SymbolMeta].variants) css = { [variant]: css, }; return css; } function useArrayHelper() { // eslint-disable-next-line no-extend-native Array.prototype.toString = function () { return this.join(isStyleArray(this) ? " " : ","); }; } /** * Bundle all utilities to a single css object. * @param utilities - Utilities and Variants * @returns CSSObject */ function bundle(utilities) { let vcss; const css = new Map(); for (const utility of utilities.flat().filter(i => i != null)) { vcss = applyVariant(utility); for (const [k, v] of shared.entries(vcss)) if (v != null) css.set(k, css.has(k) && typeof v === "object" ? mergeObject(css.get(k), v) : v); } return css; } const prop = (strings, ...expr) => strings.map((string, i) => string + (expr[i] || "")).join(""); // https://drafts.csswg.org/cssom/#serialize-an-identifier function escapeCSS(str) { const length = str.length; let index = -1; let codeUnit; let result = ""; const firstCodeUnit = str.charCodeAt(0); while (++index < length) { codeUnit = str.charCodeAt(index); // Note: there’s no need to special-case astral symbols, surrogate // pairs, or lone surrogates. // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER // (U+FFFD). if (codeUnit === 0x0000) { result += "\uFFFD"; continue; } // Comma if (codeUnit === 44) { result += "\\2c "; continue; } if ( // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is // U+007F, […] (codeUnit >= 0x0001 && codeUnit <= 0x001f) || codeUnit === 0x007f || // If the character is the first character and is in the range [0-9] // (U+0030 to U+0039), […] (index === 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || // If the character is the second character and is in the range [0-9] // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] (index === 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit === 0x002d)) { // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point result += "\\" + codeUnit.toString(16) + " "; continue; } if ( // If the character is the first character and is a `-` (U+002D), and // there is no second character, […] index === 0 && length === 1 && codeUnit === 0x002d) { result += "\\" + str.charAt(index); continue; } // If the character is not handled by one of the above rules and is // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to // U+005A), or [a-z] (U+0061 to U+007A), […] if (codeUnit >= 0x0080 || codeUnit === 0x002d || codeUnit === 0x005f || (codeUnit >= 0x0030 && codeUnit <= 0x0039) || (codeUnit >= 0x0041 && codeUnit <= 0x005a) || (codeUnit >= 0x0061 && codeUnit <= 0x007a)) { // the character itself result += str.charAt(index); continue; } // Otherwise, the escaped character. // https://drafts.csswg.org/cssom/#escape-a-character result += "\\" + str.charAt(index); } return result; } // eslint-disable-next-line @typescript-eslint/no-use-before-define let CURRENT_NAMER = alphaNamer; let MINI_COUNT = 0; const MINI_MAP = {}; // a, b, c ... a0, a1, ... function alphaCount(n) { if (n < 26) return String.fromCharCode(n + 97); const x = (n - 26) % 36; return alphaCount(Math.floor((n - 26) / 36)) + (x < 10 ? x.toString() : String.fromCharCode(x + 87)); } function alphaNamer(style) { const key = getStyleIdent(style); if (key in MINI_MAP) return MINI_MAP[key]; return (MINI_MAP[key] = alphaCount(MINI_COUNT++)); } function atomicNamer(style) { // TODO: apply varaint for this return escapeCSS(getStyleProps(style).join(".")); } function hashNamer(style) { return "w-" + shared.hash(getStyleIdent(style)); } function useNamer(f) { CURRENT_NAMER = f; } function nameStyle(style) { return CURRENT_NAMER(style); } function inline(x, ...utilities) { const isGet = isStyleObject(x); const styles = []; for (const [key, value] of Object.entries(bundle(utilities))) if (typeof value === "string") isGet ? styles.push(key + ":" + value) : x.style.setProperty(key, value); if (isGet) return styles.join(";"); } function cssBlock(selector, body = [], rootIndent = 0, childIndent = rootIndent + 2) { const statements = []; for (const item of body) if (typeof item === "string") statements.push(shared.indent(item, childIndent)); else statements.push(cssBlock(item.selector, item.body, childIndent + 2)); return [shared.indent(selector, rootIndent) + " {", ...statements, shared.indent("}", rootIndent)].join("\n"); } function createRules(css, selector) { const rules = []; const rootRule = { selector, children: [] }; for (const [key, value] of shared.entries(css)) if (typeof value === "string" || value instanceof String) rootRule.children.push({ property: key, value: value }); else if (typeof value === "number") rootRule.children.push({ property: key, value: value.toString() }); else if (Array.isArray(value)) value.map(i => rootRule.children.push({ property: key, value: i })); else if (typeof value === "object" && value != null) { if (rootRule.children[0]) rules.push({ ...rootRule }); rootRule.children = []; const children = selector.charCodeAt(0) === 64 /* @ */ ? { [selector]: value } : value; if (key.charCodeAt(0) === 64 /* @ */) rules.push({ rule: key, children: createRules(children, selector) }); else rules.push(...createRules(children, key.replace(/&/g, selector))); } rootRule.children[0] && rules.push(rootRule); return rules; } function buildDecl({ value, property }) { if (Array.isArray(value)) return value.map(i => property + ": " + i + ";"); return property.startsWith("webkit") ? "-" : "" + shared.camelToDash(property) + ": " + value + ";"; } function buildRule({ selector, children }, indent = 0) { return cssBlock(selector, children.map(i => buildDecl(i)).flat(), indent); } function buildAtRule({ rule, children }, indent = 0) { // eslint-disable-next-line @typescript-eslint/no-use-before-define return cssBlock(rule, createBlockBody(children, indent + 2), indent, 0); } function createBlockBody(rules, indent = 0) { const blocks = []; for (const rule of rules) if ("selector" in rule) blocks.push(buildRule(rule, indent)); else blocks.push(buildAtRule(rule, indent)); return blocks; } function buildRules(rules) { return createBlockBody(rules).join("\n\n"); } function dedupRules(rules) { const styles = []; const atRules = {}; for (const r of rules) if ("selector" in r) styles.push(r); else if (r.rule in atRules) atRules[r.rule].children.push(...r.children); else atRules[r.rule] = r; return [...styles, ...Object.values(atRules)]; } /** build a single StyleObject to css */ function buildStyle(className, style) { return buildRules(createRules(applyVariant(style), "." + className)); } function atomic(...utilities) { const rules = []; for (const utility of utilities.flat().filter(i => i != null)) rules.push(...createRules(applyVariant(utility), "." + nameStyle(utility))); return buildRules(dedupRules(rules)); } const _unify = (selector, utilities) => buildRules(createRules(bundle(utilities), selector)); function unify(...params) { if (typeof params[0] === "string") return _unify(params[0], params.slice(1)); const map = Object.assign({}, ...params); return Object.entries(map) .map(([k, v]) => (Array.isArray(v) ? _unify(k, v) : _unify(k, [v]))) .join("\n\n"); } function build(...utilities) { const rules = []; for (const utility of utilities.flat().filter(i => i != null)) { const selector = utility[SymbolMeta].selector; if (typeof selector === "string") rules.push(...createRules(applyVariant(utility), selector)); } return buildRules(dedupRules(rules)); } function defineConfig(config) { return config; } // TODO: should return object, like CSSPercentage/CSSDimension... // TODO: support multiple add/sub/mul/div function sub(left, right) { if (typeof left === "object" && typeof right === "object") if (left.type === right.type) return left.value - right.value + (left.type === "percent" ? "%" : left.type); return left + " - " + right; } function add(left, right) { if (typeof left === "object" && typeof right === "object") if (left.type === right.type) return left.value + right.value + (left.type === "percent" ? "%" : left.type); return left + " + " + right; } function mul(left, right) { if (typeof left === "number" && typeof right === "object") return left * right.value + (right.type === "percent" ? "%" : right.type); if (typeof left === "object" && typeof right === "number") return left.value * right + (left.type === "percent" ? "%" : left.type); if (typeof left === "number" && typeof right === "number") return left * right + ""; return left + " * " + right; } function div(left, right) { if (typeof left === "object" && typeof right === "number") return left.value / right + (left.type === "percent" ? "%" : left.type); if (typeof left === "number" && typeof right === "number") return left / right + ""; return left + " / " + right; } const WindiPrecision = 10; function prec(n) { return +n.toFixed(WindiPrecision); } /* eslint-disable @typescript-eslint/no-this-alias */ function digitToHEX(d) { let hex = d.toString(16); hex = "00".slice(0, 2 - hex.length) + hex; return hex; } function rgbToHEX(rgba) { const rgb = rgba.slice(0, 3); return "#" + rgb.map(digitToHEX).join("").toLowerCase(); } function hexToRGB(hex) { if (hex.length === 4) hex = "#" + [hex[1], hex[1], hex[2], hex[2], hex[3], hex[3]].join(""); else if (hex.length === 5) hex = "#" + [hex[1], hex[1], hex[2], hex[2], hex[3], hex[3], hex[4], hex[4]].join(""); const c = +("0x" + hex.substring(1)); if (hex.length === 9) return [(c >> 24) & 255, (c >> 16) & 255, (c >> 8) & 255, (c & 255) / 256]; return [(c >> 16) & 255, (c >> 8) & 255, c & 255, 1]; } function sliceColor(str) { const params = str.slice(str.indexOf("(") + 1, str.indexOf(")")); return params.indexOf(",") !== -1 ? params.split(/,\s*/) : params.split(/\s+\/?\s*/); } function rgbToHSL(rgba) { const r = rgba[0] / 255; const g = rgba[1] / 255; const b = rgba[2] / 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h; let s; const l = (max + min) / 2; const d = max - min; const huecalc = { [r]: () => (60 * (g - b)) / d + (g < b ? 360 : 0), [g]: () => (60 * (b - r)) / d + 120, [b]: () => (60 * (r - g)) / d + 240, }; if (d === 0) h = s = 0; // grayscaled color else { s = l < 0.5 ? d / (max + min) : d / (2 - max - min); h = huecalc[max](); } return [h, s * 100, l * 100].concat([rgba[3]]); } function hueToRGB(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; } function hslToRGB(hsla) { let r; let g; let b; const h = hsla[0] / 360; const s = hsla[1] / 100; const l = hsla[2] / 100; if (s === 0) r = g = b = l; // grayscaled color else { const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hueToRGB(p, q, h + 1 / 3); g = hueToRGB(p, q, h); b = hueToRGB(p, q, h - 1 / 3); } return [r, g, b] .map(function (c) { return Math.round(c * 255); }) .concat([hsla[3]]); } function hwbToRGB(hue, whiteness, blackness, alpha = 1) { const scaledHue = (hue % 360) / 360; let scaledWhiteness = whiteness / 100; let scaledBlackness = blackness / 100; const sum = scaledWhiteness + scaledBlackness; if (sum > 1) { scaledWhiteness /= sum; scaledBlackness /= sum; } const factor = 1 - scaledWhiteness - scaledBlackness; function toRgb(hue) { const channel = hueToRGB(0, 1, hue) * factor + scaledWhiteness; return Math.round(channel * 255); } return [toRgb(scaledHue + 1 / 3), toRgb(scaledHue), toRgb(scaledHue - 1 / 3), alpha]; } function adjustWithScale(rgba, deg, scale = 0, index = 0, len = 100) { rgba = [...rgba]; rgba[index] = deg ? Math.max(Math.min(rgba[index] + deg, len), 0) : scale >= 0 ? Math.floor(((len - rgba[index]) * scale) / 100 + rgba[index]) : Math.floor(rgba[index] - (rgba[index] * Math.abs(scale)) / 100); return rgba; } function adjustHue(hsla, deg) { hsla = [...hsla]; hsla[0] = hsla[0] + deg; return hsla; } const adjustSaturation = (hsla, deg, scale = 0) => adjustWithScale(hsla, deg, scale, 1); const adjustLightness = (hsla, deg, scale = 0) => adjustWithScale(hsla, deg, scale, 2); const adjustRed = (rgba, deg, scale = 0) => adjustWithScale(rgba, deg, scale, 0, 255); const adjustGreen = (rgba, deg, scale = 0) => adjustWithScale(rgba, deg, scale, 1, 255); const adjustBlue = (rgba, deg, scale = 0) => adjustWithScale(rgba, deg, scale, 2, 255); const adjustAlpha = (hsla, deg, scale = 0) => { hsla = [...hsla]; hsla[3] = deg ? Math.round(Math.max(Math.min(hsla[3] + deg, 1), 0) * 100) / 100 : scale >= 0 ? Math.floor((1 - hsla[3]) * scale + hsla[3] * 100) / 100 : Math.floor(hsla[3] * (100 + scale)) / 100; return hsla; }; function mixColor(color1, color2, w = 50) { const weightScale = w / 100; const normalizedWeight = weightScale * 2 - 1; const alphaDistance = color1[3] - color2[3]; const combinedWeight1 = normalizedWeight * alphaDistance === -1 ? normalizedWeight : (normalizedWeight + alphaDistance) / (1 + normalizedWeight * alphaDistance); const weight1 = (combinedWeight1 + 1) / 2; const weight2 = 1 - weight1; return [ Math.round(color1[0] * weight1 + color2[0] * weight2), Math.round(color1[1] * weight1 + color2[1] * weight2), Math.round(color1[2] * weight1 + color2[2] * weight2), color1[3] * weightScale + color2[3] * (1 - weightScale), ]; } function subMixColor(color1, color2, w = 50) { return color1.map((c, i) => (i === 3 ? color2[i] + (c - color2[i]) * (w / 100) : Math.floor(color2[i] + (c - color2[i]) * (w / 100)))); } class Color { constructor(hexval, rgbaval, hslaval) { if (Array.isArray(hexval)) { if (hexval[3] == null) hexval.push(1); this.rgbaval = hexval; this.hexval = rgbToHEX(this.rgbaval); } else { this.hexval = hexval; this.rgbaval = rgbaval ?? hexToRGB(hexval); } this.hslaval = hslaval ?? rgbToHSL(this.rgbaval); } static hex(str) { const hexval = str.toLowerCase(); const rgbaval = hexToRGB(hexval); const hslaval = rgbToHSL(rgbaval); return new Color(hexval, rgbaval, hslaval); } static rgb(r, g, b, a = 1) { return Color.rgba(r, g, b, a); } static rgba(r, g, b, a) { const rgbaval = [r, g, b, a]; const hexval = rgbToHEX(rgbaval); const hslaval = rgbToHSL(rgbaval); return new Color(hexval, rgbaval, hslaval); } static hsl(h, s, l, a = 1) { return Color.hsla(h, s, l, a); } static hsla(h, s, l, a) { const hslaval = [h, s, l, a]; const rgbaval = hslToRGB(hslaval); const hexval = rgbToHEX(rgbaval); return new Color(hexval, rgbaval, hslaval); } static hwb(hue, whiteness, blackness, alpha = 1) { return Color.rgba(...hwbToRGB(hue, whiteness, blackness, alpha)); } get hex() { const v = this.hexval; return v[1] === v[2] && v[3] === v[4] && v[5] === v[6] ? "#" + v[1] + v[3] + v[5] : v; } get rgb() { return this.rgba.slice(0, 3); } get rgba() { return this.rgbaval; } get hsl() { return this.hsla.slice(0, 3); } get hsla() { return this.hslaval.map(i => prec(i)); } get hwb() { return [this.hue, this.whiteness, this.blackness]; } static mix(c1, c2, w = 50) { return Color.rgba(...mixColor(c1.rgbaval, c2.rgbaval, w)); } static subcolormix(c1, c2, w = 50) { return Color.rgba(...subMixColor(c1.rgbaval, c2.rgbaval, w)); } get red() { return this.rgbaval[0]; } get green() { return this.rgbaval[1]; } get blue() { return this.rgbaval[2]; } get hue() { return prec(this.hslaval[0]); } get saturation() { return prec(this.hslaval[1]); } get lightness() { return prec(this.hslaval[2]); } get alpha() { return this.rgbaval[3]; } get opacity() { return this.alpha; } get whiteness() { const [r, g, b] = this.rgbaval; return prec((Math.min(Math.min(r, g), b) / 255) * 100); } get blackness() { const [r, g, b] = this.rgbaval; return prec(100 - (Math.max(Math.max(r, g), b) / 255) * 100); } get ieHexStr() { return "#" + (digitToHEX(this.alpha * 255) + this.hexval.slice(1)).toUpperCase(); } get rgbStr() { return `rgb(${this.rgb.join(", ")})`; } get rgbaStr() { return `rgba(${this.rgba.join(", ")})`; } get hslStr() { const [h, s, l] = this.hsl; return `hsl(${h}, ${s}%, ${l}%)`; } get hslaStr() { const [h, s, l, a] = this.hsla; return `hsla(${h}, ${s}%, ${l}%, ${a})`; } get hwbStr() { const [h, w, b] = this.hwb; const a = this.opacity; return a < 1 ? `hwb(${h} ${w}% ${b}% / ${a})` : `hwb(${h} ${w}% ${b}%)`; } invert(weight = 100) { const inverted = this.rgba.map((c, i) => (i === 3 ? c : Math.round(255 - c))); return Color.mix(new Color(rgbToHEX(inverted), inverted, rgbToHSL(inverted).concat([inverted[3]])), this, weight); } adjustRed(deg, scale = 0) { return Color.rgba(...adjustRed(this.rgbaval, deg, scale)); } adjustGreen(deg, scale = 0) { return Color.rgba(...adjustGreen(this.rgbaval, deg, scale)); } adjustBlue(deg, scale = 0) { return Color.rgba(...adjustBlue(this.rgbaval, deg, scale)); } adjustHue(deg) { return Color.hsla(...adjustHue(this.hslaval, deg)); } adjustSaturation(deg, scale = 0) { return Color.hsla(...adjustSaturation(this.hslaval, deg, scale)); } adjustLightness(deg, scale = 0) { return Color.hsla(...adjustLightness(this.hslaval, deg, scale)); } adjustAlpha(deg, scale = 0) { return Color.hsla(...adjustAlpha(this.hslaval, deg, scale)); } complement() { return this.adjustHue(180); } saturate(deg) { return this.adjustSaturation(deg); } desaturate(deg) { return this.adjustSaturation(-deg); } grayscale() { return this.adjustSaturation(-100); } lighten(amount) { return this.adjustLightness(amount); } darken(amount) { return this.adjustLightness(-amount); } opacify(deg) { return this.adjustAlpha(deg); } transparentize(deg) { return this.adjustAlpha(-deg); } fadeIn(deg) { return this.adjustAlpha(deg); } fadeOut(deg) { return this.adjustAlpha(-deg); } adjust(opt) { let color = this; for (const [k, v] of Object.entries(opt)) color = color[("adjust" + k[0].toUpperCase() + k.slice(1))](v); return color; } scale(opt) { let color = this; for (const [k, v] of Object.entries(opt)) color = color[("adjust" + k[0].toUpperCase() + k.slice(1))](undefined, v); return color; } change(opt) { let rgba = this.rgba; let hsla = this.hsla; for (const [k, v] of Object.entries(opt)) switch (k) { case "red": rgba[0] = v; hsla = rgbToHSL(rgba); break; case "green": rgba[1] = v; hsla = rgbToHSL(rgba); break; case "blue": rgba[2] = v; hsla = rgbToHSL(rgba); break; case "hue": hsla[0] = v; rgba = hslToRGB(hsla); break; case "saturation": hsla[1] = v; rgba = hslToRGB(hsla); break; case "lightness": hsla[2] = v; rgba = hslToRGB(hsla); break; case "alpha": rgba[3] = v; hsla[3] = v; break; } return new Color(rgbToHEX(rgba), rgba, hsla); } // Color Sets lightenSet(n) { return [this].concat(shared.range(1, n).map(i => this.adjustLightness(undefined, (100 / n) * i))); } darkenSet(n) { return [this].concat(shared.range(1, n).map(i => this.adjustLightness(undefined, -((100 / n) * i)))); } desaturateSet(n) { return [this].concat(shared.range(1, n).map(i => this.adjustSaturation(undefined, -((100 / n) * i)))); } complementSet(n) { const comp = this.complement(); return shared.range(0, n) .reverse() .map(i => (i === n - 1 ? this : i === 0 ? comp : Color.subcolormix(this, comp, (100 / (n - 1)) * i))); } invertSet(n) { const inv = this.invert(); return shared.range(0, n) .reverse() .map(i => (i === n - 1 ? this : i === 0 ? inv : Color.subcolormix(this, inv, (100 / (n - 1)) * i))); } } function colorLuminance(color) { const rgb = color.rgb.map(i => i / 255).map(v => (v < 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2)); return prec(rgb[0] * 0.2126 + rgb[1] * 0.7152 + rgb[2] * 0.0722); } function getLightColor(color, lightness = 96) { return color.change({ lightness: color.lightness > 96 ? color.lightness : lightness }); } function getDarkColor(color, lightness = 29) { return color.change({ lightness: Math.max(lightness, Math.round(lightness + (0.53 - colorLuminance(color)) * 53)), }); } let CurrentMeta; function resetMeta(uid = "css", type = "css", props = [], variants = []) { CurrentMeta = { uid, type, props, variants }; } resetMeta(); function getMeta() { return CurrentMeta; } function getUid() { return CurrentMeta.uid; } function pushMetaProp(prop) { return CurrentMeta.props.push(prop); } function updateMetaType(type) { CurrentMeta.type = type; } function resetStyleMeta(style, meta = CurrentMeta) { style[SymbolMeta] = meta; return style; } const baseStyleTarget = (css, meta, data) => { if (data != null) // push func prop, for example bg.red.opacity(50) -> [..., opacity(50)] for (const [k, v] of Object.entries(data)) if (typeof v === "function") data[k] = (...args) => { pushMetaProp(shared.parenWrap(k, args.toString())); return v(...args); }; return { [SymbolProxy]: true, [SymbolCSS]: css, [SymbolMeta]: meta, [SymbolData]: data, }; }; const baseStyleHandler = (target, prop, receiver) => { if (prop === "css") return Reflect.get(target, SymbolCSS, receiver); if (prop === "meta") return Reflect.get(target, SymbolMeta, receiver); const data = Reflect.get(target, SymbolData, receiver); if (data && prop in data) return data[prop]; return Reflect.get(target, prop, receiver); }; let CurrentLoader = (css, meta, data) => new Proxy(baseStyleTarget(css, meta, data), { get: baseStyleHandler }); function useStyleLoader(loader) { CurrentLoader = loader; } function css(css, data, meta) { return CurrentLoader(css, meta ?? getMeta(), data); } const BUILDED_CLASSES = []; function injectCSS(css) { const container = document.getElementById("windijs"); if (container) container.textContent += "\n" + css; else { const el = document.createElement("style"); el.id = "windijs"; el.setAttribute("type", "text/css"); el.textContent = css; document.head.appendChild(el); } } /** Create a styleLoader */ function createStyleLoader(inject) { return (css, meta, data) => { const baseStyle = baseStyleTarget(css, meta, data); const className = nameStyle(baseStyle); return new Proxy({ [className]: true, ...baseStyle, }, { get(target, prop, receiver) { // for react, svelte... if (prop === "toString") return () => { inject(className, baseStyle); return Object.keys(target).join(" "); }; // for vue if (prop === className) { inject(className, baseStyle); return Reflect.get(target, prop, receiver); } return baseStyleHandler(target, prop, receiver); }, }); }; } /** CSS-In-JS Loader */ const cssInJsLoader = createStyleLoader((className, style) => { if (!BUILDED_CLASSES.includes(className)) { BUILDED_CLASSES.push(className); injectCSS(buildStyle(className, style)); } }); const SSR_CLASSES = []; const SSR_CSS_LIST = []; /** SSR Loader */ const ssrLoader = createStyleLoader((className, style) => { if (!SSR_CLASSES.includes(className)) { SSR_CLASSES.push(className); SSR_CSS_LIST.push(buildStyle(className, style)); } }); /** Mount server side generated css */ function mountCSS() { return SSR_CSS_LIST.join("\n"); } function apply(selector, ...utilities) { return css(bundle(utilities), undefined, { uid: "apply", type: "css", props: [selector], variants: [], selector, }); } function funcProxy(f) { return new Proxy(f, { get(target, p) { return Reflect.apply(target, undefined, [p]); }, apply(target, thisArg, argArray) { return Reflect.apply(target, thisArg, argArray); }, }); } let GLOBAL_STYLES = []; function queryStyles(selector) { for (let i = GLOBAL_STYLES.length - 1; i >= 0; i--) if (GLOBAL_STYLES[i].selector === selector) return GLOBAL_STYLES[i].children; } function globalApply(selector, ...utilities) { const style = apply(selector, ...utilities); GLOBAL_STYLES.push({ selector, children: utilities.flat().filter(i => i != null), style, }); return style; } function createDollarCall(selector) { return new Proxy(globalApply, { get(target, p) { // eslint-disable-next-line @typescript-eslint/no-use-before-define if (p === "ATTR") return createAttrProxy(selector); if (p === "styles") return queryStyles(selector) ?? []; if (p === "$") selector += ", "; else if (p === "$$") selector += " > "; else if (p === "_") selector += " "; else if (p === "__") selector += " + "; else if (p === "_$_") selector += " ~ "; else if (p.charCodeAt(0) < 91) selector += p.toLowerCase(); // HTML Elements // eslint-disable-next-line @typescript-eslint/no-unused-vars else selector += "." + p; return createDollarCall(selector); }, apply(target, thisArg, argArray) { return Reflect.apply(target, thisArg, [selector, ...argArray]); }, }); } const attrMatches = { match: "=", hyphenMatch: "|=", contains: "~=", includes: "*=", startsWith: "^=", endsWith: "$=", }; const createAttrProxy = (selector) => funcProxy(function (attribute) { return new Proxy(globalApply, { get(target, p) { if (p in attrMatches) return funcProxy(function (v) { selector += `[${attribute}${attrMatches[p]}${JSON.stringify(v)}]`; return createDollarCall(selector); }); return Reflect.get(createDollarCall(selector), p); }, apply(target, thisArg, argArray) { selector += `[${attribute}]`; return Reflect.apply(target, thisArg, [selector, ...argArray]); }, }); }); const $ = new Proxy(globalApply, { get(target, p) { if (p === "call") return (thisArg, ...args) => Reflect.apply(target, thisArg, args); if (p === "init") return () => (GLOBAL_STYLES = []); if (p === "exports") return GLOBAL_STYLES; if (p === "styles") return new Proxy(GLOBAL_STYLES.map(i => i.children).flat(), { get(target, p) { if (Reflect.has(target, p)) return Reflect.get(target, p); return queryStyles(p); }, }); let selector = ""; if (p === "ID") return funcProxy(function (id) { selector += "#" + id; return createDollarCall(selector); }); if (p === "ATTR") return createAttrProxy(selector); if (p === "All") selector += "*"; else if (p === "Root") selector += ":root"; // TODO: support :host(.selector) else if (p === "Host") selector += ":host"; else if (p.charCodeAt(0) < 91) selector += p.toLowerCase(); // HTML Elements // eslint-disable-next-line @typescript-eslint/no-unused-vars else selector += "." + p; return createDollarCall(selector); }, }); function quote(str) { return `${JSON.stringify(str).replace(/\\\\/g, "\\")}`; } // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Functions // TODO: more detailed help documentation for css functions // TODO: support var as type & param // TODO: support calc as type & param // reference functionns function attr(name, type, fallback) { const defaultValue = fallback != null ? ", " + fallback : ""; if (!type) return shared.parenWrap("attr", name + defaultValue); return shared.parenWrap("attr", name + " " + type + defaultValue); } function url(url, base64 = false, dataType = "image/png") { return shared.parenWrap("url", base64 ? `data:${dataType};base64,` + url : url); } function $var(name, defaultValue) { return defaultValue ? `var(--${name}, ${defaultValue})` : `var(--${name})`; } // shape functions function path(path, fillRule) { return shared.parenWrap("path", fillRule ? fillRule + ", " + JSON.stringify(path) : JSON.stringify(path)); } // color functions /** Creates a Color from hue, white and black. */ function hwb(hue, whiteness, blackness, alpha) { return shared.parenWrap("hwb", [hue, whiteness, blackness].join(" ") + (alpha ? " / " + alpha : "")); } // filter functions function dropShadow(offsetX, offsetY, blurRadius, color) { return shared.parenWrap("drop-shadow", [offsetX, offsetY, blurRadius, color].join(" ")); } function counters(name, char, style) { return shared.parenWrap("counters", [name, JSON.stringify(char), style].filter(i => i != null).join(", ")); } // shape functions function circle(shapeRadius, positon) { return shared.parenWrap("circle", positon == null ? shapeRadius.toString() : shapeRadius + " at " + (Array.isArray(positon) ? positon.join(" ") : positon)); } function ellipse(shapeRadiusX, shapeRadiusY, positon) { const shapeRadius = [shapeRadiusX, shapeRadiusY].join(" "); return shared.parenWrap("ellipse", positon == null ? shapeRadius : shapeRadius + " at " + (Array.isArray(positon) ? positon.join(" ") : positon)); } function round(radius, radius2, radius3, radius4) { if (Array.isArray(radius) || Array.isArray(radius2)) return [radius, radius2].map(i => (Array.isArray(i) ? i.join(" ") : i)).join(" / "); return [radius, radius2, radius3, radius4].filter(i => i != null).join(" "); } class Inset { constructor(values) { this.values = []; this.values = values; this.round = ((a, b, c, d) => shared.parenWrap("inset", this.values.filter(i => i != null).join(" ") + " round " + round(a, b, c, d))); } toString() { return shared.parenWrap("inset", this.values.filter(i => i != null).join(" ")); } } function inset(lengthOrPercent, lengthOrPercent2, lengthOrPercent3, lengthOrPercent4) { return new Inset([lengthOrPercent, lengthOrPercent2, lengthOrPercent3, lengthOrPercent4]); } function polygon(fillRule, ...lengthOrPercent) { return shared.parenWrap("polygon", [fillRule, ...lengthOrPercent] .filter(i => i != null) .map(i => (Array.isArray(i) ? i.join(" ") : i)) .join(", ")); } const { matrix, matrix3d, perspective, rotate, rotate3d, rotateX, rotateY, rotateZ, scale, scale3d, scaleX, scaleY, scaleZ, skew, skewX, skewY, translate, translate3d, translateX, translateY, translateZ, steps, calc, clamp, max, min, abs, sign, blur, brightness, contrast, grayscale, invert, opacity, saturate, sepia, rgb, rgba, hsl, hsla, counter, env, minmax, repeat, } = new Proxy({}, { get(_, p) { return (...args) => p + "(" + args.filter(i => i != null).join(", ") + ")"; }, }); const { hueRotate, fitContent, cubicBezier, linearGradient, radialGradient, conicGradient, repeatingConicGradient, repeatingLinearGradient, repeatingRadialGradient, } = new Proxy({}, { get(_, p) { return (...args) => shared.camelToDash(p) + "(" + args .map(i => (Array.isArray(i) ? i.join(" ") : i)) .filter(i => i != null) .join(", ") + ")"; }, }); const filters = { blur, brightness, contrast, dropShadow, grayscale, hueRotate, invert, saturate, sepia, }; // export const transforms = { rotate, rotate3d, rotateX, rotateY, rotateZ, scale, scale3d, scaleX, scaleY, scaleZ, skew, skewX, skewY, translate, translate3d, translateX, translateY, translateZ }; const transforms = { rotate, scale, skew, translate }; // Color const color = new Proxy({}, { get: (_, v) => { const map = { var: $var, calc, rgb, rgba, hsl, hsla, hwb }; return v in map ? map[v] : v; }, }); function dimension(type, suffix = type) { return new Proxy({}, { get: (_, value) => Object.create({ value: +value, type, valueOf: () => value + suffix, toString: () => value + suffix, }), }); } const percent = dimension("percent", "%"); const { deg, grad, rad, turn } = new Proxy({}, { get: (_, k) => dimension(k) }); const { s, ms } = new Proxy({}, { get: (_, k) => dimension(k) }); const fr = dimension("fr"); const $in = dimension("in"); const { dpi, dpcm, dppx, x } = new Proxy({}, { get: (_, k) => dimension(k) }); const { px, pc, pt, cm, mm, Q, ch, ex, em, rem, vw, vh, vmax, vmin } = new Proxy({}, { get: (_, k) => dimension(k), }); exports.$ = $; exports.$in = $in; exports.$var = $var; exports.Color = Color; exports.Q = Q; exports.SymbolCSS = SymbolCSS; exports.SymbolData = SymbolData; exports.SymbolMeta = SymbolMeta; exports.SymbolProxy = SymbolProxy; exports.abs = abs; exports.add = add; exports.adjustAlpha = adjustAlpha; exports.adjustBlue = adjustBlue; exports.adjustGreen = adjustGreen; exports.adjustHue = adjustHue; exports.adjustLightness = adjustLightness; exports.adjustRed = adjustRed; exports.adjustSaturation = adjustSaturation; exports.alphaCount = alphaCount; exports.alphaNamer = alphaNamer; exports.apply = apply; exports.applyVariant = applyVariant; exports.atomic = atomic; exports.atomicNamer = atomicNamer; exports.attr = attr; exports.baseStyleHandler = baseStyleHandler; exports.baseStyleTarget = baseStyleTarget; exports.blur = blur; exports.brightness = brightness; exports.build = build; exports.buildAtRule = buildAtRule; exports.buildDecl = buildDecl; exports.buildRule = buildRule; exports.buildRules = buildRules; exports.buildStyle = buildStyle; exports.bundle = bundle; exports.calc = calc; exports.ch = ch; exports.circle = circle; exports.clamp = clamp; exports.cm = cm; exports.color = color; exports.colorLuminance = colorLuminance; exports.conicGradient = conicGradient; exports.contrast = contrast; exports.counter = counter; exports.counters = counters; exports.createRules = createRules; exports.createStyleLoader = createStyleLoader; exports.css = css; exports.cssInJsLoader = cssInJsLoader; exports.cubicBezier = cubicBezier; exports.dedupRules = dedupRules; exports.defineConfig = defineConfig; exports.deg = deg; exports.digitToHEX = digitToHEX; exports.div = div; exports.dpcm = dpcm; exports.dpi = dpi; exports.dppx = dppx; exports.dropShadow = dropShadow; exports.ellipse = ellipse; exports.em = em; exports.env = env; exports.escapeCSS = escapeCSS; exports.ex = ex; exports.filters = filters; exports.fitContent = fitContent; exports.fr = fr; exports.getDarkColor = getDarkColor; exports.getFirstVar = getFirstVar; exports.getLightColor = getLightColor; exports.getMeta = getMeta; exports.getStyleIdent = getStyleIdent; exports.getStyleProps = getStyleProps; exports.getStyleVariants = getStyleVariants; exports.getUid = getUid; exports.grad = grad; exports.grayscale = grayscale; exports.hashNamer = hashNamer; exports.hexToRGB = hexToRGB; exports.hsl = hsl; exports.hslToRGB = hslToRGB; exports.hsla = hsla; exports.hueRotate = hueRotate; exports.hueToRGB = hueToRGB; exports.hwb = hwb; exports.hwbToRGB = hwbToRGB; exports.inherit = inherit; exports.initial = initial; exports.injectCSS = injectCSS; exports.inline = inline; exports.inset = inset; exports.invert = invert; exports.isProxy = isProxy; exports.isStyleArray = isStyleArray; exports.isStyleObject = isStyleObject; exports.linearGradient = linearGradient; exports.matrix = matrix; exports.matrix3d = matrix3d; exports.max = max; exports.mergeObject = mergeObject; exports.min = min; exports.minmax = minmax; exports.mixColor = mixColor; exports.mm = mm; exports.mountCSS = mountCSS; exports.ms = ms; exports.mul = mul; exports.nameStyle = nameStyle; exports.none = none; exports.opacity = opacity; exports.path = path; exports.pc = pc; exports.percent = percent; exports.perspective = perspective; exports.polygon = polygon; exports.prec = prec; exports.prop = prop; exports.pt = pt; exports.pushMetaProp = pushMetaProp; exports.px = px; exports.queryStyles = queryStyles; exports.quote = quote; exports.rad = rad; exports.radialGradient = radialGradient; exports.rem = rem; exports.repeat = repeat; exports.repeatingConicGradient = repeatingConicGradient; exports.repeatingLinearGradient = repeatingLinearGradient; exports.repeatingRadialGradient = repeatingRadialGradient; exports.resetMeta = resetMeta; exports.resetStyleMeta = resetStyleMeta; exports.rgb = rgb; exports.rgbToHEX = rgbToHEX; exports.rgbToHSL = rgbToHSL; exports.rgba = rgba; exports.rotate = rotate; exports.rotate3d = rotate3d; exports.rotateX = rotateX; exports.rotateY = rotateY; exports.rotateZ = rotateZ; exports.s = s; exports.saturate = saturate; exports.scale = scale; exports.scale3d = scale3d; exports.scaleX = scaleX; exports.scaleY = scaleY; exports.scaleZ = scaleZ; exports.sepia = sepia; exports.sign = sign; exports.skew = skew; exports.skewX = skewX; exports.skewY = skewY; exports.sliceColor = sliceColor; exports.ssrLoader = ssrLoader; exports.steps = steps; exports.sub = sub; exports.subMixColor = subMixColor; exports.transforms = transforms; exports.translate = translate; exports.translate3d = translate3d; exports.translateX = translateX; exports.translateY = translateY; exports.translateZ = translateZ; exports.turn = turn; exports.unify = unify; exports.unset = unset; exports.updateMetaType = updateMetaType; exports.url = url; exports.useArrayHelper = useArrayHelper; exports.useNamer = useNamer; exports.useStyleLoader = useStyleLoader; exports.vh = vh; exports.vmax = vmax; exports.vmin = vmin; exports.vw = vw; exports.x = x;