UNPKG

alien-dom

Version:

Next-generation JSX client renderer with observable data primitives, immediate DOM references, and more.

1,041 lines (1,031 loc) 30.3 kB
import { isString, isNode, isFunction, toArray, isNumber, isPromise, deleteTimeline, getPrivate, kAlienAnimatedState, isSvgChild, setPrivate, isBoolean, AnimatedTransform, parseValue, resolveTransformFn, applyAnimatedValue, keys, cssTransformDefaults, defineEffectType, observe, applyProp, unmount, mountLastChild, mountFirstChild, updateStyle, getEffects, enableEffect, isIterable, cssTransformUnits, canMatch } from './chunk-JH7ONIU5.mjs'; // ../node_modules/.pnpm/linear-color@1.2.0/node_modules/linear-color/dist/mix-color.mjs var mix = (from, to, progress) => -progress * from + progress * to + from; 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 hslaToRgba({ hue, saturation, lightness, alpha: alpha2 }) { hue /= 360; saturation /= 100; lightness /= 100; let red = 0; let green = 0; let blue = 0; if (!saturation) { red = green = blue = lightness; } else { const q = lightness < 0.5 ? lightness * (1 + saturation) : lightness + saturation - lightness * saturation; const p = 2 * lightness - q; red = hueToRgb(p, q, hue + 1 / 3); green = hueToRgb(p, q, hue); blue = hueToRgb(p, q, hue - 1 / 3); } return { red: Math.round(red * 255), green: Math.round(green * 255), blue: Math.round(blue * 255), alpha: alpha2 }; } var clamp = (min, max, v) => Math.min(Math.max(v, min), max); var number = { test: (v) => typeof v === "number", parse: parseFloat, transform: (v) => v }; var alpha = { ...number, transform: (v) => clamp(0, 1, v) }; var sanitize = (v) => Math.round(v * 1e5) / 1e5; var floatRegex = /(-)?([\d]*\.?[\d])+/g; var singleColorRegex = /^(#[0-9a-f]{3,8}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2}(-?[\d\.]+%?)\s*[\,\/]?\s*[\d\.]*%?\))$/i; function isString2(v) { return typeof v === "string"; } var isColorString = (type, testProp) => (v) => { return Boolean( isString2(v) && singleColorRegex.test(v) && v.startsWith(type) || testProp && Object.prototype.hasOwnProperty.call(v, testProp) ); }; var splitColor = (aName, bName, cName) => (v) => { if (!isString2(v)) return v; const [a, b, c, alpha2] = v.match(floatRegex); return { [aName]: parseFloat(a), [bName]: parseFloat(b), [cName]: parseFloat(c), alpha: alpha2 !== void 0 ? parseFloat(alpha2) : 1 }; }; var clampRgbUnit = (v) => clamp(0, 255, v); var rgbUnit = { ...number, transform: (v) => Math.round(clampRgbUnit(v)) }; var rgba = { test: isColorString("rgb", "red"), parse: splitColor("red", "green", "blue"), transform: ({ red, green, blue, alpha: alpha2 = 1 }) => "rgba(" + rgbUnit.transform(red) + ", " + rgbUnit.transform(green) + ", " + rgbUnit.transform(blue) + ", " + sanitize(alpha.transform(alpha2)) + ")" }; function parseHex(v) { let r = ""; let g = ""; let b = ""; let a = ""; if (v.length > 5) { r = v.substring(1, 3); g = v.substring(3, 5); b = v.substring(5, 7); a = v.substring(7, 9); } else { r = v.substring(1, 2); g = v.substring(2, 3); b = v.substring(3, 4); a = v.substring(4, 5); r += r; g += g; b += b; a += a; } return { red: parseInt(r, 16), green: parseInt(g, 16), blue: parseInt(b, 16), alpha: a ? parseInt(a, 16) / 255 : 1 }; } var hex = { test: isColorString("#"), parse: parseHex, transform: rgba.transform }; var createUnitType = (unit) => ({ test: (v) => isString2(v) && v.endsWith(unit) && v.split(" ").length === 1, parse: parseFloat, transform: (v) => `${v}${unit}` }); var percent = createUnitType("%"); var hsla = { test: isColorString("hsl", "hue"), parse: splitColor("hue", "saturation", "lightness"), transform: ({ hue, saturation, lightness, alpha: alpha2 = 1 }) => { return "hsla(" + Math.round(hue) + ", " + percent.transform(sanitize(saturation)) + ", " + percent.transform(sanitize(lightness)) + ", " + sanitize(alpha.transform(alpha2)) + ")"; } }; var mixLinearColor = (from, to, v) => { const fromExpo = from * from; return Math.sqrt(Math.max(0, v * (to * to - fromExpo) + fromExpo)); }; var colorTypes = [hex, rgba, hsla]; var getColorType = (v) => colorTypes.find((type) => type.test(v)); var rgbaToString = { value: function() { return rgba.transform(this); } }; function parseColor(color) { const type = getColorType(color); if (!type) { throw Error( `'${color}' is not an animatable color. Use the equivalent color code instead.` ); } let model = isString2(color) ? type.parse(color) : color; if (type === hsla) { model = hslaToRgba(model); } Object.defineProperty(model, "toString", rgbaToString); return model; } function mixColor(from, to, v) { from = parseColor(from); to = parseColor(to); return rgba.transform({ red: mixLinearColor(from.red, to.red, v), green: mixLinearColor(from.green, to.green, v), blue: mixLinearColor(from.blue, to.blue, v), alpha: mix(from.alpha, to.alpha, v) }); } // core/animate.ts var animatedElements = /* @__PURE__ */ new Map(); function animate(selector, _animations) { const targets = isString(selector) ? document.querySelectorAll(selector) : isNode(selector) ? [selector] : selector; if (isFunction(_animations)) { const step = _animations; if (targets.length) { targets.forEach((target, index) => { const state = ensureAnimatedElement(target); state.step = step; state.frame = { target, done: false, t0: 0, dt: 0, time: 0, duration: 0, current: {}, index }; animatedElements.set(target, state); }); startLoop(); } } else { const animations = toArray(_animations); const springs = animations.map( (animation) => toSpringResolver(animation.spring) ); targets.forEach((target) => { let timelines; let state = ensureAnimatedElement(target); state.nodes ||= {}; const definedKeys = /* @__PURE__ */ new Set(); animations.forEach((animation, i) => { let keys2 = Object.keys({ ...animation.to, ...animation.from }); keys2.forEach((key) => { const to = animation.to?.[key]; const from = animation.from != null ? animation.from[key] : null; if (to != null || from != null) { definedKeys.add(key); } }); if (animation.delay) { const { delay } = animation; if (isNumber(delay)) { if (delay > 0) { keys2.forEach((key) => { timelines = addTimelineTimeout( timelines, target, state, animation, springs[i], delay, key ); }); keys2.length = 0; } } else if (isFunction(delay) || isPromise(delay)) { keys2.forEach((key) => { timelines = addTimelinePromise( timelines, target, state, animation, springs[i], delay, key ); }); keys2.length = 0; } else { keys2 = keys2.filter((key) => { const keyDelay = delay[key]; if (keyDelay) { if (isNumber(keyDelay)) { timelines = addTimelineTimeout( timelines, target, state, animation, springs[i], keyDelay, key ); } else { timelines = addTimelinePromise( timelines, target, state, animation, springs[i], keyDelay, key ); } return false; } return true; }); } } if (keys2.length) { applyAnimation(target, state, animation, springs[i], keys2); } }); const oldTimelines = state.timelines; if (oldTimelines) { definedKeys.forEach((key) => { deleteTimeline(oldTimelines, key); }); } if (timelines) { state.timelines = { ...oldTimelines, ...timelines }; } }); } } function ensureAnimatedElement(target) { let state = getPrivate(target, kAlienAnimatedState); if (!state) { state = { svgMode: isSvgChild(target), nodes: null, step: null, frame: null, timelines: null, transform: null, anchor: null, style: {}, onStart: null }; setPrivate(target, kAlienAnimatedState, state); } return state; } function addTimelineTimeout(timelines, target, state, animation, spring, delay, key) { if (delay > 0) { const dilation = animation.dilate ?? 1; const timerId = setTimeout(() => { applyAnimation(target, state, animation, spring, [key]); }, delay * dilation); const timeline = (timelines ||= {})[key] ||= []; timeline.push({ ...animation, timerId }); } else { applyAnimation(target, state, animation, spring, [key]); } return timelines; } function addTimelinePromise(timelines, target, state, animation, spring, delay, key) { const abortCtrl = new AbortController(); const promise = isFunction(delay) ? delay(abortCtrl.signal, key) : Promise.race([ delay, new Promise( (resolve) => abortCtrl.signal.addEventListener("abort", resolve) ) ]); if (promise) { const timeline = (timelines ||= {})[key] ||= []; timeline.push({ ...animation, abortCtrl }); promise.then(() => { if (!abortCtrl.signal.aborted) { applyAnimation(target, state, animation, spring, [key]); } }, console.error); } else { applyAnimation(target, state, animation, spring, [key]); } return timelines; } function applyAnimation(target, state, animation, spring, keys2) { startLoop(); const { nodes, svgMode } = state; const { onStart, onChange, onRest } = animation; const frame = onChange || onRest ? {} : null; state.anchor = animation.anchor || // If an anchor gets unset, we need to reset it to the default. state.anchor && (svgMode ? svgDefaultAnchor : htmlDefaultAnchor); state.onStart = onStart || null; for (const key of keys2) { const oldNode = nodes[key]; const node = updateAnimatedNode( target, svgMode, key, animation.to?.[key], animation.from?.[key], oldNode, spring, animation.dilate, !animation.velocity || isNumber(animation.velocity) ? animation.velocity : animation.velocity[key], !animation.immediate || isBoolean(animation.immediate) ? animation.immediate : animation.immediate[key], frame, onChange, onRest ); if (node && !oldNode) { nodes[key] = node; if (node.transformFn) { state.transform ||= new AnimatedTransform(target, svgMode); } } if (node && !node.done) { animatedElements.set(target, state); } } } function updateAnimatedNode(target, svgMode, key, to, from, node, spring, dilate, velocity, immediate, frame, onChange, onRest) { let parsedFrom; let parsedTo; const isColor = isColorKey(key, svgMode); if (isColor) { parsedFrom = from != null ? parseColor(resolveCssVariable(from, target)) : null; parsedTo = to != null ? parseColor(resolveCssVariable(to, target)) : parsedFrom; } else { const defaultUnit = svgMode ? void 0 : defaultUnits[key]; parsedFrom = from != null ? parseValue(from, defaultUnit) : null; parsedTo = parseValue(to, defaultUnit) ?? parsedFrom; } if (!parsedTo) { return null; } node ||= { v0: 0, done: false, to: parsedTo, from: null, nextFrom: null, lastPosition: null, lastVelocity: null, dilation: 1, isRelative: false, transformFn: resolveTransformFn(key, svgMode), spring: null, frame: null, onChange: null, onRest: null }; node.done = false; node.to = parsedTo; node.from = null; node.nextFrom = parsedFrom || node.nextFrom; node.spring = spring(key); node.frame = frame || null; node.dilation = dilate ?? 1; node.onChange = onChange || null; node.onRest = onRest || null; if (parsedFrom || isColor) { node.lastPosition = null; } if (immediate || velocity != null || isNaN(node.v0)) { node.v0 = immediate ? NaN : velocity ?? 0; node.lastVelocity = null; } if (svgMode && !isColor) { node.isRelative = scaleKeys.includes(key) || parsedTo[1] == "%" || !!parsedFrom && parsedFrom[1] == "%"; } return node; } var htmlDefaultAnchor = [0.5, 0.5]; var svgDefaultAnchor = [0, 0]; var htmlColorKeys = ["backgroundColor", "color"]; var svgColorKeys = ["fill", "stroke"]; function isColorKey(key, svgMode) { return (svgMode ? svgColorKeys : htmlColorKeys).includes(key); } var defaultUnits = { ...cssTransformUnits, borderRadius: "px" }; var svgNonZeroDefaults = { fill: "rgba(0,0,0,0)", fillOpacity: "1", stroke: "rgba(0,0,0,0)", strokeOpacity: "1", opacity: "1" }; var scaleKeys = ["scale", "scaleX", "scaleY"]; var loop; var lastTime; function startLoop() { if (loop) return; loop = requestAnimationFrame(function step(now) { const dt = Math.min(64, now - (lastTime || now)); lastTime = now; let stepResults; for (const [target, state] of animatedElements) { if (!target.isConnected) { animatedElements.delete(target); continue; } if (state.nodes) { ensureFromValues(target, state, state.nodes); } if (state.step) { const { step: step2, frame } = state; frame.t0 ??= now; frame.dt = dt; frame.time = now; frame.duration += dt; const stepResult = step2(frame); stepResults ||= /* @__PURE__ */ new Map(); stepResults.set(target, stepResult); } } let loopDone = true; for (const [target, state] of animatedElements) { const { nodes, svgMode, style, onStart } = state; if (onStart) { onStart(target); state.onStart = null; } const frames = /* @__PURE__ */ new Map(); if (nodes) { for (const [key, node] of Object.entries(nodes)) { if (node.done) { continue; } if (node.from == null) { continue; } const position = advance(node, node.spring, dt, key); if (node.frame) { const values = frames.get(node.frame) || []; frames.set(node.frame, values); values.push([key, node]); } const { to } = node; if (Array.isArray(to)) { if (node.transformFn) { state.transform.addCall(key, position, to[1], node.transformFn); } else { const value = position + to[1]; applyAnimatedValue(target, style, svgMode, key, value); } } else { const value = mixColor(node.from, to, position); applyAnimatedValue(target, style, svgMode, key, value); } } } if (state.step) { const frame = state.frame; const stepResult = stepResults.get(target); if (stepResult) { for (const key of keys(stepResult)) { const value = stepResult[key]; if (value !== void 0) { frame.current[key] = value; } const transformFn = resolveTransformFn(key, svgMode); if (transformFn) { const defaultUnit = svgMode ? void 0 : defaultUnits[key]; const parsed = parseValue(value, defaultUnit); if (parsed) { state.transform ||= new AnimatedTransform(target, svgMode); state.transform.addCall(key, parsed[0], parsed[1], transformFn); } } else { applyAnimatedValue(target, null, svgMode, key, value); } } } if (frame.done) { state.step = null; state.frame = null; } } state.transform?.apply(state); for (const [frame, values] of frames) { let frameDone = true; for (const [prop, node] of values) { frame[prop] = readValue(node); if (!node.done) { frameDone = false; } } const { onChange, onRest } = values[0][1]; if (onChange) { onChange(frame, target); } if (onRest && frameDone) { onRest(frame, target); } } const done = !(state.nodes && Object.values(state.nodes).some((node) => !node.done)) && !state.step; if (done) { animatedElements.delete(target); } else { loopDone = false; } } if (loopDone) { for (const [, state] of animatedElements) { if (state.nodes) { const done = Object.values(state.nodes).every((node) => node.done); if (!done) { loopDone = false; break; } } if (state.frame && !state.frame.done) { loopDone = false; break; } } } if (loopDone) { loop = void 0; lastTime = void 0; } else { loop = requestAnimationFrame(step); } }); } function readValue({ lastPosition, from, to }) { if (lastPosition == null) { return void 0; } if (Array.isArray(to)) { const unit = to[1]; if (unit) { return lastPosition + unit; } return lastPosition; } return mixColor(from, to, lastPosition); } var maxPrecision = 0.1 / (window.devicePixelRatio || 1); var defaultPrecisions = { opacity: 0.01 }; function advance(node, config, dt, prop) { let from; let to; if (Array.isArray(node.to)) { from = node.from[0]; to = node.to[0]; } else { from = 0; to = 1; } if (node.lastPosition == null && node.from == null) { return to; } let position = node.lastPosition == null ? from : node.lastPosition; let velocity = node.lastVelocity == null ? node.v0 : node.lastVelocity; let finished = false; const equalFromTo = from == to; if (isNaN(velocity) || equalFromTo && velocity === 0) { finished = true; } else { const precision = defaultPrecisions[prop] || (equalFromTo ? 5e-3 : Math.min(Math.abs(to - from) * 1e-3, maxPrecision)); const restVelocity = config.restVelocity || precision / 10; const bounceFactor = config.clamp ? 0 : config.bounce; const canBounce = bounceFactor !== void 0; const isGrowing = equalFromTo ? node.v0 > 0 : from < to; let isMoving; let isBouncing = false; const step = 1; const stepFactor = 1 / node.dilation; const numSteps = Math.max(1, Math.ceil(dt / step)); for (let n = 0; n < numSteps; ++n) { isMoving = Math.abs(velocity) > restVelocity; if (!isMoving) { finished = Math.abs(to - position) <= precision; if (finished) { break; } } if (canBounce) { isBouncing = position == to || position > to == isGrowing; if (isBouncing) { velocity = -velocity * bounceFactor; position = to; } } const springForce = -config.tension * 1e-6 * (position - to); const dampingForce = -config.friction * 1e-3 * velocity; const acceleration = (springForce + dampingForce) / config.mass; velocity = velocity + acceleration * step * stepFactor; position = position + velocity * step * stepFactor; } } if (finished) { node.done = true; velocity = 0; position = to; } node.lastVelocity = velocity; node.lastPosition = position; return position; } function toSpringResolver(spring) { if (!isFunction(spring)) { const resolved = resolveSpring(spring || {}); return () => resolved; } return (key) => resolveSpring(spring(key) || {}); } function resolveSpring(spring) { let { frequency, damping, tension, friction, mass = 1 } = spring; if (frequency != null) { frequency = Math.max(0.01, frequency); damping = Math.max(0, damping ?? 1); tension = Math.pow(2 * Math.PI / frequency, 2) * mass; friction = 4 * Math.PI * damping * mass / frequency; } else { tension = 170 * (tension ?? 1); friction = 26 * (friction ?? 1); } return { ...spring, tension, friction, mass }; } function ensureFromValues(target, state, nodes) { let computedStyle; const getStyleProp = (prop) => { if (state.svgMode) { return target.getAttribute(prop) || svgNonZeroDefaults[prop] || "0"; } return target.style[prop] || (computedStyle ||= getComputedStyle(target))[prop]; }; for (const [key, node] of Object.entries(nodes)) { if (node.nextFrom) { node.from = node.nextFrom; node.nextFrom = null; } if (node.done || node.from) { continue; } if (node.transformFn) { let from; for (const [fn, args] of state.transform.read()) { if (fn == node.transformFn) { from = args[0]; break; } if (state.svgMode && fn == "scale") { if (key == "scaleX") { from = args[0]; break; } if (key == "scaleY") { from = args[1]; break; } } } const to = node.to; if (!from || from[1] == to[1] || isNaN(node.v0)) { node.from = from || [cssTransformDefaults[node.transformFn] || 0, to[1]]; } else { console.error(`Unit mismatch for "${key}": ${from[1]} != ${to[1]}`); } } else { const value = getStyleProp(key); node.from = isColorKey(key, state.svgMode) ? parseColor(resolveCssVariable(value, target)) : [parseFloat(value), ""]; } } } function resolveCssVariable(value, target) { if (value.startsWith("var(")) { const varNameStart = value.indexOf("(") + 1; const varName = value.slice(varNameStart, -1); const varValue = getComputedStyle(target).getPropertyValue(varName); if (!varValue) { throw Error(`CSS variable not found: ${varName}`); } return varValue; } return value; } // functions/observeAs.ts var observeAs = /* @__PURE__ */ defineEffectType( (target, action) => observe(() => action(target)).destructor ); // addons/element/attributes.ts function patchAttributes(context, attributes) { for (const name of keys(attributes)) { applyProp(context, name, attributes[name]); } } // addons/element/classList.ts function hasClass(context, className) { return context.classList.contains(className); } function addClass(context, classes) { for (const name of splitClassNames(classes)) { context.classList.add(name); } } function removeClass(context, classes) { for (const name of splitClassNames(classes)) { context.classList.remove(name); } } function removeMatchingClass(context, pattern) { const test = isFunction(pattern) ? pattern : pattern.test.bind(pattern); for (let i = 0; i < context.classList.length; i++) { const token = context.classList.item(i); if (test(token)) { context.classList.remove(token); } } } function toggleClass(context, classes, force) { for (const name of splitClassNames(classes)) { context.classList.toggle(name, isFunction(force) ? force(name) : force); } } function hasEveryClass(context, classes) { return toArray(classes).every( (className) => className.split(/\s+/).every((name) => context.classList.contains(name)) ); } function hasSomeClass(context, classes) { return toArray(classes).some( (className) => className.split(/\s+/).some((name) => context.classList.contains(name)) ); } function matchClass(context, pattern) { for (let i = 0; i < context.classList.length; i++) { const token = context.classList.item(i); if (isFunction(pattern)) { const match = pattern(token); if (match || match === "") { return match; } } else { const match = pattern.exec(token); if (match) { return match[1] ?? match[0]; } } } return ""; } function* splitClassNames(classes) { for (const className of toArray(classes)) { yield* className.split(/\s+/); } } // internal/unwrap.ts function unwrap(node) { const children = []; const parent = node.parentNode; if (parent) { while (node.firstChild) { children.push(node.firstChild); parent.insertBefore(node.firstChild, node); } parent.removeChild(node); } return children; } // addons/elementExtensions.ts var AlienElement = class { $(selector) { return this.querySelector(selector); } $$(selector) { return this.querySelectorAll(selector); } siblings(selector) { const self = this; const siblings = this.parentNode ? Array.from(this.parentNode.childNodes) : []; let cursor = -1; const iterable = { [Symbol.iterator]: () => ({ next() { const value = iterable.next(); return { value, done: !value }; } }), next() { let sibling; while ((sibling = siblings[++cursor]) && sibling != self) { if (!selector) { return sibling; } if (canMatch(sibling) && sibling.matches(selector)) { return sibling; } } }, first() { for (const sibling of siblings) { if (sibling == self) { continue; } if (!selector) { return sibling; } if (canMatch(sibling) && sibling.matches(selector)) { return sibling; } } } }; return iterable; } filter(selector) { return this.matches(selector) ? this : null; } replaceText(value) { if (typeof value == "function") { return observeAs(this, (target) => { target.textContent = value(); }); } else { this.textContent = value; } return this; } empty() { while (this.firstChild) { unmount(this.firstChild); } return this; } appendTo(parent) { mountLastChild(parent, this); return this; } prependTo(parent) { mountFirstChild(parent, this); return this; } hasClass(name) { return hasSomeClass(this, name); } addClass(name) { addClass(this, name); return this; } removeClass(name) { removeClass(this, name); return this; } removeMatchingClasses(pattern) { removeMatchingClass(this, pattern); return this; } toggleClass(name, value) { return this.classList.toggle(name, value); } /** * Returns the first class name that matches the given pattern. * * If a capturing group exists in the pattern, the captured value will * be returned. Otherwise, the entire match will be returned. * * An empty string is returned if no match is found. */ matchClass(pattern) { return matchClass(this, pattern); } css(style) { updateStyle(this, style, 1 /* Interrupt */); return this; } // TODO: update `props` type to allow ReadonlyRef values set(props) { patchAttributes(this, props); return this; } spring(animations) { animate(this, animations); return this; } }; var setMethodImpl = (obj, name, method) => obj.prototype[name] = function(...args) { return method(this, ...args); }; setMethodImpl(AlienElement, "unwrap", unwrap); setMethodImpl(AlienElement, "effects", getEffects); for (const [suffix, flags] of [ ["", 0], ["Once", 1 /* Once */], ["Async", 2 /* Async */], ["OnceAsync", 1 /* Once */ | 2 /* Async */] ]) { setMethodImpl( AlienElement, "effect" + suffix, function(node, effect, target, args) { return enableEffect( getEffects(node), effect, flags, target, arguments.length > 2 && args ); } ); } // addons/global/nodeList.ts var AlienNodeListPrototype = /* @__PURE__ */ defineAlienNodeList(); var AlienElementListPrototype = { ...AlienNodeListPrototype, __proto__: Array.prototype, // Exists for compatibility with NodeList. item(index) { return this[index] || null; } }; function createAlienElementList(arg) { if (arg && arg instanceof NodeList) { return arg; } const list = !arg ? [] : isIterable(arg) ? [...arg] : [arg]; Object.setPrototypeOf(list, AlienElementListPrototype); return list; } function defineAlienNodeList() { return { [Symbol.iterator]() { const out = []; this.forEach((value, index) => { out[index] = value; }); return out[Symbol.iterator](); }, map(iterator) { const out = []; this.forEach((value, index) => { out.push(iterator(value, index)); }); return out; }, filter(selector) { const out = []; const filter = typeof selector == "string" ? (value) => canMatch(value) && value.matches(selector) : selector; this.forEach((value, index) => { if (filter(value, index)) { out.push(value); } }); return out; }, mapFilter(iterator) { const out = []; this.forEach((value, index) => { const result = iterator(value, index); if (result != null) { out.push(result); } }); return out; }, find(selector) { const filter = typeof selector == "string" ? (value) => canMatch(value) && value.matches(selector) : selector; for (let i = 0; i < this.length; i++) { if (filter(this[i], i)) { return this[i]; } } } }; } export { AlienElement, AlienNodeListPrototype, addClass, animate, createAlienElementList, hasClass, hasEveryClass, hasSomeClass, matchClass, mixColor, observeAs, parseColor, patchAttributes, removeClass, removeMatchingClass, toggleClass };