UNPKG

@react-spring/web

Version:
384 lines (379 loc) 8.52 kB
// src/index.ts import { Globals } from "@react-spring/core"; import { unstable_batchedUpdates } from "react-dom"; import { createStringInterpolator, colors } from "@react-spring/shared"; import { createHost } from "@react-spring/animated"; // src/applyAnimatedValues.ts var isCustomPropRE = /^--/; function dangerousStyleValue(name, value) { if (value == null || typeof value === "boolean" || value === "") return ""; if (typeof value === "number" && value !== 0 && !isCustomPropRE.test(name) && !(isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name])) return value + "px"; return ("" + value).trim(); } var attributeCache = {}; function applyAnimatedValues(instance, props) { if (!instance.nodeType || !instance.setAttribute) { return false; } const isFilterElement = instance.nodeName === "filter" || instance.parentNode && instance.parentNode.nodeName === "filter"; const { className, style, children, scrollTop, scrollLeft, viewBox, ...attributes } = props; const values = Object.values(attributes); const names = Object.keys(attributes).map( (name) => isFilterElement || instance.hasAttribute(name) ? name : attributeCache[name] || (attributeCache[name] = name.replace( /([A-Z])/g, // Attributes are written in dash case (n) => "-" + n.toLowerCase() )) ); if (children !== void 0) { instance.textContent = children; } for (const name in style) { if (style.hasOwnProperty(name)) { const value = dangerousStyleValue(name, style[name]); if (isCustomPropRE.test(name)) { instance.style.setProperty(name, value); } else { instance.style[name] = value; } } } names.forEach((name, i) => { instance.setAttribute(name, values[i]); }); if (className !== void 0) { instance.className = className; } if (scrollTop !== void 0) { instance.scrollTop = scrollTop; } if (scrollLeft !== void 0) { instance.scrollLeft = scrollLeft; } if (viewBox !== void 0) { instance.setAttribute("viewBox", viewBox); } } var isUnitlessNumber = { animationIterationCount: true, borderImageOutset: true, borderImageSlice: true, borderImageWidth: true, boxFlex: true, boxFlexGroup: true, boxOrdinalGroup: true, columnCount: true, columns: true, flex: true, flexGrow: true, flexPositive: true, flexShrink: true, flexNegative: true, flexOrder: true, gridRow: true, gridRowEnd: true, gridRowSpan: true, gridRowStart: true, gridColumn: true, gridColumnEnd: true, gridColumnSpan: true, gridColumnStart: true, fontWeight: true, lineClamp: true, lineHeight: true, opacity: true, order: true, orphans: true, tabSize: true, widows: true, zIndex: true, zoom: true, // SVG-related properties fillOpacity: true, floodOpacity: true, stopOpacity: true, strokeDasharray: true, strokeDashoffset: true, strokeMiterlimit: true, strokeOpacity: true, strokeWidth: true }; var prefixKey = (prefix, key) => prefix + key.charAt(0).toUpperCase() + key.substring(1); var prefixes = ["Webkit", "Ms", "Moz", "O"]; isUnitlessNumber = Object.keys(isUnitlessNumber).reduce((acc, prop) => { prefixes.forEach((prefix) => acc[prefixKey(prefix, prop)] = acc[prop]); return acc; }, isUnitlessNumber); // src/AnimatedStyle.ts import { AnimatedObject } from "@react-spring/animated"; import { is, each, toArray, eachProp, FluidValue, getFluidValue, callFluidObservers, hasFluidValue, addFluidObserver, removeFluidObserver } from "@react-spring/shared"; var domTransforms = /^(matrix|translate|scale|rotate|skew)/; var pxTransforms = /^(translate)/; var degTransforms = /^(rotate|skew)/; var addUnit = (value, unit) => is.num(value) && value !== 0 ? value + unit : value; var isValueIdentity = (value, id) => is.arr(value) ? value.every((v) => isValueIdentity(v, id)) : is.num(value) ? value === id : parseFloat(value) === id; var AnimatedStyle = class extends AnimatedObject { constructor({ x, y, z, ...style }) { const inputs = []; const transforms = []; if (x || y || z) { inputs.push([x || 0, y || 0, z || 0]); transforms.push((xyz) => [ `translate3d(${xyz.map((v) => addUnit(v, "px")).join(",")})`, // prettier-ignore isValueIdentity(xyz, 0) ]); } eachProp(style, (value, key) => { if (key === "transform") { inputs.push([value || ""]); transforms.push((transform) => [transform, transform === ""]); } else if (domTransforms.test(key)) { delete style[key]; if (is.und(value)) return; const unit = pxTransforms.test(key) ? "px" : degTransforms.test(key) ? "deg" : ""; inputs.push(toArray(value)); transforms.push( key === "rotate3d" ? ([x2, y2, z2, deg]) => [ `rotate3d(${x2},${y2},${z2},${addUnit(deg, unit)})`, isValueIdentity(deg, 0) ] : (input) => [ `${key}(${input.map((v) => addUnit(v, unit)).join(",")})`, isValueIdentity(input, key.startsWith("scale") ? 1 : 0) ] ); } }); if (inputs.length) { style.transform = new FluidTransform(inputs, transforms); } super(style); } }; var FluidTransform = class extends FluidValue { constructor(inputs, transforms) { super(); this.inputs = inputs; this.transforms = transforms; this._value = null; } get() { return this._value || (this._value = this._get()); } _get() { let transform = ""; let identity = true; each(this.inputs, (input, i) => { const arg1 = getFluidValue(input[0]); const [t, id] = this.transforms[i]( is.arr(arg1) ? arg1 : input.map(getFluidValue) ); transform += " " + t; identity = identity && id; }); return identity ? "none" : transform; } // Start observing our inputs once we have an observer. observerAdded(count) { if (count == 1) each( this.inputs, (input) => each( input, (value) => hasFluidValue(value) && addFluidObserver(value, this) ) ); } // Stop observing our inputs once we have no observers. observerRemoved(count) { if (count == 0) each( this.inputs, (input) => each( input, (value) => hasFluidValue(value) && removeFluidObserver(value, this) ) ); } eventObserved(event) { if (event.type == "change") { this._value = null; } callFluidObservers(this, event); } }; // src/primitives.ts var primitives = [ "a", "abbr", "address", "area", "article", "aside", "audio", "b", "base", "bdi", "bdo", "big", "blockquote", "body", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup", "data", "datalist", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed", "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "keygen", "label", "legend", "li", "link", "main", "map", "mark", "menu", "menuitem", "meta", "meter", "nav", "noscript", "object", "ol", "optgroup", "option", "output", "p", "param", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s", "samp", "script", "section", "select", "small", "source", "span", "strong", "style", "sub", "summary", "sup", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "u", "ul", "var", "video", "wbr", // SVG "circle", "clipPath", "defs", "ellipse", "foreignObject", "g", "image", "line", "linearGradient", "mask", "path", "pattern", "polygon", "polyline", "radialGradient", "rect", "stop", "svg", "text", "tspan" ]; // src/index.ts export * from "@react-spring/core"; Globals.assign({ batchedUpdates: unstable_batchedUpdates, createStringInterpolator, colors }); var host = createHost(primitives, { applyAnimatedValues, createAnimatedStyle: (style) => new AnimatedStyle(style), // eslint-disable-next-line @typescript-eslint/no-unused-vars getComponentProps: ({ scrollTop, scrollLeft, ...props }) => props }); var animated = host.animated; export { animated as a, animated };