motion 11.16.4 → 11.16.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/dist/cjs/index.js +659 -658
  2. package/dist/cjs/react-client.js +524 -523
  3. package/dist/cjs/react-m.js +6 -6
  4. package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-target.mjs +2 -2
  5. package/dist/es/framer-motion/dist/es/animation/optimized-appear/store-id.mjs +1 -1
  6. package/dist/es/framer-motion/dist/es/animation/utils/default-transitions.mjs +1 -1
  7. package/dist/es/framer-motion/dist/es/motion/utils/is-forced-motion-value.mjs +1 -1
  8. package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +12 -12
  9. package/dist/es/framer-motion/dist/es/render/dom/DOMKeyframesResolver.mjs +4 -3
  10. package/dist/es/framer-motion/dist/es/render/dom/scroll/offsets/index.mjs +6 -5
  11. package/dist/es/framer-motion/dist/es/render/dom/utils/unit-conversion.mjs +2 -14
  12. package/dist/es/framer-motion/dist/es/render/html/HTMLVisualElement.mjs +6 -6
  13. package/dist/es/framer-motion/dist/es/render/html/utils/build-styles.mjs +2 -2
  14. package/dist/es/framer-motion/dist/es/render/html/utils/build-transform.mjs +1 -1
  15. package/dist/es/framer-motion/dist/es/render/html/utils/keys-position.mjs +13 -0
  16. package/dist/es/framer-motion/dist/es/render/svg/SVGVisualElement.mjs +6 -6
  17. package/dist/es/framer-motion/dist/es/render/svg/utils/scrape-motion-values.mjs +1 -1
  18. package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
  19. package/dist/es/framer-motion/dist/es/utils/interpolate.mjs +4 -1
  20. package/dist/es/framer-motion/dist/es/value/index.mjs +1 -1
  21. package/dist/es/framer-motion/dist/es/value/use-will-change/get-will-change-name.mjs +1 -1
  22. package/dist/motion.dev.js +659 -658
  23. package/dist/motion.js +1 -1
  24. package/package.json +3 -3
  25. /package/dist/es/framer-motion/dist/es/render/html/utils/{transform.mjs → keys-transform.mjs} +0 -0
@@ -1094,6 +1094,16 @@
1094
1094
  */
1095
1095
  const transformProps = new Set(transformPropOrder);
1096
1096
 
1097
+ const positionalKeys = new Set([
1098
+ "width",
1099
+ "height",
1100
+ "top",
1101
+ "left",
1102
+ "right",
1103
+ "bottom",
1104
+ ...transformPropOrder,
1105
+ ]);
1106
+
1097
1107
  const isKeyframesTarget = (v) => {
1098
1108
  return Array.isArray(v);
1099
1109
  };
@@ -1359,7 +1369,7 @@
1359
1369
  * This will be replaced by the build step with the latest version number.
1360
1370
  * When MotionValues are provided to motion components, warn if versions are mixed.
1361
1371
  */
1362
- this.version = "11.16.4";
1372
+ this.version = "11.16.6";
1363
1373
  /**
1364
1374
  * Tracks whether this value can output a velocity. Currently this is only true
1365
1375
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -1810,62 +1820,6 @@
1810
1820
  }
1811
1821
  }
1812
1822
 
1813
- /**
1814
- * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
1815
- */
1816
- const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
1817
-
1818
- const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
1819
- const isCSSVariableName =
1820
- /*@__PURE__*/ checkStringStartsWith("--");
1821
- const startsAsVariableToken =
1822
- /*@__PURE__*/ checkStringStartsWith("var(--");
1823
- const isCSSVariableToken = (value) => {
1824
- const startsWithToken = startsAsVariableToken(value);
1825
- if (!startsWithToken)
1826
- return false;
1827
- // Ensure any comments are stripped from the value as this can harm performance of the regex.
1828
- return singleCssVariableRegex.test(value.split("/*")[0].trim());
1829
- };
1830
- const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
1831
-
1832
- /**
1833
- * Parse Framer's special CSS variable format into a CSS token and a fallback.
1834
- *
1835
- * ```
1836
- * `var(--foo, #fff)` => [`--foo`, '#fff']
1837
- * ```
1838
- *
1839
- * @param current
1840
- */
1841
- const splitCSSVariableRegex =
1842
- // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
1843
- /^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
1844
- function parseCSSVariable(current) {
1845
- const match = splitCSSVariableRegex.exec(current);
1846
- if (!match)
1847
- return [,];
1848
- const [, token1, token2, fallback] = match;
1849
- return [`--${token1 !== null && token1 !== void 0 ? token1 : token2}`, fallback];
1850
- }
1851
- const maxDepth = 4;
1852
- function getVariableValue(current, element, depth = 1) {
1853
- exports.invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
1854
- const [token, fallback] = parseCSSVariable(current);
1855
- // No CSS variable detected
1856
- if (!token)
1857
- return;
1858
- // Attempt to read this CSS variable off the element
1859
- const resolved = window.getComputedStyle(element).getPropertyValue(token);
1860
- if (resolved) {
1861
- const trimmed = resolved.trim();
1862
- return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
1863
- }
1864
- return isCSSVariableToken(fallback)
1865
- ? getVariableValue(fallback, element, depth + 1)
1866
- : fallback;
1867
- }
1868
-
1869
1823
  const number = {
1870
1824
  test: (v) => typeof v === "number",
1871
1825
  parse: parseFloat,
@@ -1880,6 +1834,97 @@
1880
1834
  default: 1,
1881
1835
  };
1882
1836
 
1837
+ // If this number is a decimal, make it just five decimal places
1838
+ // to avoid exponents
1839
+ const sanitize = (v) => Math.round(v * 100000) / 100000;
1840
+
1841
+ const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
1842
+
1843
+ function isNullish(v) {
1844
+ return v == null;
1845
+ }
1846
+
1847
+ const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
1848
+
1849
+ /**
1850
+ * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
1851
+ * but false if a number or multiple colors
1852
+ */
1853
+ const isColorString = (type, testProp) => (v) => {
1854
+ return Boolean((typeof v === "string" &&
1855
+ singleColorRegex.test(v) &&
1856
+ v.startsWith(type)) ||
1857
+ (testProp &&
1858
+ !isNullish(v) &&
1859
+ Object.prototype.hasOwnProperty.call(v, testProp)));
1860
+ };
1861
+ const splitColor = (aName, bName, cName) => (v) => {
1862
+ if (typeof v !== "string")
1863
+ return v;
1864
+ const [a, b, c, alpha] = v.match(floatRegex);
1865
+ return {
1866
+ [aName]: parseFloat(a),
1867
+ [bName]: parseFloat(b),
1868
+ [cName]: parseFloat(c),
1869
+ alpha: alpha !== undefined ? parseFloat(alpha) : 1,
1870
+ };
1871
+ };
1872
+
1873
+ const clampRgbUnit = (v) => clamp(0, 255, v);
1874
+ const rgbUnit = {
1875
+ ...number,
1876
+ transform: (v) => Math.round(clampRgbUnit(v)),
1877
+ };
1878
+ const rgba = {
1879
+ test: /*@__PURE__*/ isColorString("rgb", "red"),
1880
+ parse: /*@__PURE__*/ splitColor("red", "green", "blue"),
1881
+ transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
1882
+ rgbUnit.transform(red) +
1883
+ ", " +
1884
+ rgbUnit.transform(green) +
1885
+ ", " +
1886
+ rgbUnit.transform(blue) +
1887
+ ", " +
1888
+ sanitize(alpha.transform(alpha$1)) +
1889
+ ")",
1890
+ };
1891
+
1892
+ function parseHex(v) {
1893
+ let r = "";
1894
+ let g = "";
1895
+ let b = "";
1896
+ let a = "";
1897
+ // If we have 6 characters, ie #FF0000
1898
+ if (v.length > 5) {
1899
+ r = v.substring(1, 3);
1900
+ g = v.substring(3, 5);
1901
+ b = v.substring(5, 7);
1902
+ a = v.substring(7, 9);
1903
+ // Or we have 3 characters, ie #F00
1904
+ }
1905
+ else {
1906
+ r = v.substring(1, 2);
1907
+ g = v.substring(2, 3);
1908
+ b = v.substring(3, 4);
1909
+ a = v.substring(4, 5);
1910
+ r += r;
1911
+ g += g;
1912
+ b += b;
1913
+ a += a;
1914
+ }
1915
+ return {
1916
+ red: parseInt(r, 16),
1917
+ green: parseInt(g, 16),
1918
+ blue: parseInt(b, 16),
1919
+ alpha: a ? parseInt(a, 16) / 255 : 1,
1920
+ };
1921
+ }
1922
+ const hex = {
1923
+ test: /*@__PURE__*/ isColorString("#"),
1924
+ parse: parseHex,
1925
+ transform: rgba.transform,
1926
+ };
1927
+
1883
1928
  const createUnitType = (unit) => ({
1884
1929
  test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
1885
1930
  parse: parseFloat,
@@ -1896,87 +1941,347 @@
1896
1941
  transform: (v) => percent.transform(v * 100),
1897
1942
  };
1898
1943
 
1899
- const positionalKeys = new Set([
1900
- "width",
1901
- "height",
1902
- "top",
1903
- "left",
1904
- "right",
1905
- "bottom",
1906
- "x",
1907
- "y",
1908
- "translateX",
1909
- "translateY",
1910
- ]);
1911
- const isNumOrPxType = (v) => v === number || v === px;
1912
- const getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(", ")[pos]);
1913
- const getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {
1914
- if (transform === "none" || !transform)
1915
- return 0;
1916
- const matrix3d = transform.match(/^matrix3d\((.+)\)$/u);
1917
- if (matrix3d) {
1918
- return getPosFromMatrix(matrix3d[1], pos3);
1919
- }
1920
- else {
1921
- const matrix = transform.match(/^matrix\((.+)\)$/u);
1922
- if (matrix) {
1923
- return getPosFromMatrix(matrix[1], pos2);
1944
+ const hsla = {
1945
+ test: /*@__PURE__*/ isColorString("hsl", "hue"),
1946
+ parse: /*@__PURE__*/ splitColor("hue", "saturation", "lightness"),
1947
+ transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
1948
+ return ("hsla(" +
1949
+ Math.round(hue) +
1950
+ ", " +
1951
+ percent.transform(sanitize(saturation)) +
1952
+ ", " +
1953
+ percent.transform(sanitize(lightness)) +
1954
+ ", " +
1955
+ sanitize(alpha.transform(alpha$1)) +
1956
+ ")");
1957
+ },
1958
+ };
1959
+
1960
+ const color = {
1961
+ test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
1962
+ parse: (v) => {
1963
+ if (rgba.test(v)) {
1964
+ return rgba.parse(v);
1924
1965
  }
1925
- else {
1926
- return 0;
1966
+ else if (hsla.test(v)) {
1967
+ return hsla.parse(v);
1927
1968
  }
1928
- }
1929
- };
1930
- const transformKeys = new Set(["x", "y", "z"]);
1931
- const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
1932
- function removeNonTranslationalTransform(visualElement) {
1933
- const removedTransforms = [];
1934
- nonTranslationalTransformKeys.forEach((key) => {
1935
- const value = visualElement.getValue(key);
1936
- if (value !== undefined) {
1937
- removedTransforms.push([key, value.get()]);
1938
- value.set(key.startsWith("scale") ? 1 : 0);
1969
+ else {
1970
+ return hex.parse(v);
1939
1971
  }
1940
- });
1941
- return removedTransforms;
1942
- }
1943
- const positionalValues = {
1944
- // Dimensions
1945
- width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
1946
- height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
1947
- top: (_bbox, { top }) => parseFloat(top),
1948
- left: (_bbox, { left }) => parseFloat(left),
1949
- bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
1950
- right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
1951
- // Transform
1952
- x: getTranslateFromMatrix(4, 13),
1953
- y: getTranslateFromMatrix(5, 14),
1972
+ },
1973
+ transform: (v) => {
1974
+ return typeof v === "string"
1975
+ ? v
1976
+ : v.hasOwnProperty("red")
1977
+ ? rgba.transform(v)
1978
+ : hsla.transform(v);
1979
+ },
1954
1980
  };
1955
- // Alias translate longform names
1956
- positionalValues.translateX = positionalValues.x;
1957
- positionalValues.translateY = positionalValues.y;
1958
1981
 
1959
- /**
1960
- * Tests a provided value against a ValueType
1961
- */
1962
- const testValueType = (v) => (type) => type.test(v);
1982
+ const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
1963
1983
 
1964
- /**
1965
- * ValueType for "auto"
1966
- */
1967
- const auto = {
1968
- test: (v) => v === "auto",
1969
- parse: (v) => v,
1970
- };
1984
+ function test(v) {
1985
+ var _a, _b;
1986
+ return (isNaN(v) &&
1987
+ typeof v === "string" &&
1988
+ (((_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) || 0) +
1989
+ (((_b = v.match(colorRegex)) === null || _b === void 0 ? void 0 : _b.length) || 0) >
1990
+ 0);
1991
+ }
1992
+ const NUMBER_TOKEN = "number";
1993
+ const COLOR_TOKEN = "color";
1994
+ const VAR_TOKEN = "var";
1995
+ const VAR_FUNCTION_TOKEN = "var(";
1996
+ const SPLIT_TOKEN = "${}";
1997
+ // this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`
1998
+ const complexRegex = /var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;
1999
+ function analyseComplexValue(value) {
2000
+ const originalValue = value.toString();
2001
+ const values = [];
2002
+ const indexes = {
2003
+ color: [],
2004
+ number: [],
2005
+ var: [],
2006
+ };
2007
+ const types = [];
2008
+ let i = 0;
2009
+ const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
2010
+ if (color.test(parsedValue)) {
2011
+ indexes.color.push(i);
2012
+ types.push(COLOR_TOKEN);
2013
+ values.push(color.parse(parsedValue));
2014
+ }
2015
+ else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
2016
+ indexes.var.push(i);
2017
+ types.push(VAR_TOKEN);
2018
+ values.push(parsedValue);
2019
+ }
2020
+ else {
2021
+ indexes.number.push(i);
2022
+ types.push(NUMBER_TOKEN);
2023
+ values.push(parseFloat(parsedValue));
2024
+ }
2025
+ ++i;
2026
+ return SPLIT_TOKEN;
2027
+ });
2028
+ const split = tokenised.split(SPLIT_TOKEN);
2029
+ return { values, split, indexes, types };
2030
+ }
2031
+ function parseComplexValue(v) {
2032
+ return analyseComplexValue(v).values;
2033
+ }
2034
+ function createTransformer(source) {
2035
+ const { split, types } = analyseComplexValue(source);
2036
+ const numSections = split.length;
2037
+ return (v) => {
2038
+ let output = "";
2039
+ for (let i = 0; i < numSections; i++) {
2040
+ output += split[i];
2041
+ if (v[i] !== undefined) {
2042
+ const type = types[i];
2043
+ if (type === NUMBER_TOKEN) {
2044
+ output += sanitize(v[i]);
2045
+ }
2046
+ else if (type === COLOR_TOKEN) {
2047
+ output += color.transform(v[i]);
2048
+ }
2049
+ else {
2050
+ output += v[i];
2051
+ }
2052
+ }
2053
+ }
2054
+ return output;
2055
+ };
2056
+ }
2057
+ const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
2058
+ function getAnimatableNone$1(v) {
2059
+ const parsed = parseComplexValue(v);
2060
+ const transformer = createTransformer(v);
2061
+ return transformer(parsed.map(convertNumbersToZero));
2062
+ }
2063
+ const complex = {
2064
+ test,
2065
+ parse: parseComplexValue,
2066
+ createTransformer,
2067
+ getAnimatableNone: getAnimatableNone$1,
2068
+ };
1971
2069
 
1972
2070
  /**
1973
- * A list of value types commonly used for dimensions
2071
+ * Properties that should default to 1 or 100%
1974
2072
  */
1975
- const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
2073
+ const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
2074
+ function applyDefaultFilter(v) {
2075
+ const [name, value] = v.slice(0, -1).split("(");
2076
+ if (name === "drop-shadow")
2077
+ return v;
2078
+ const [number] = value.match(floatRegex) || [];
2079
+ if (!number)
2080
+ return v;
2081
+ const unit = value.replace(number, "");
2082
+ let defaultValue = maxDefaults.has(name) ? 1 : 0;
2083
+ if (number !== value)
2084
+ defaultValue *= 100;
2085
+ return name + "(" + defaultValue + unit + ")";
2086
+ }
2087
+ const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
2088
+ const filter = {
2089
+ ...complex,
2090
+ getAnimatableNone: (v) => {
2091
+ const functions = v.match(functionRegex);
2092
+ return functions ? functions.map(applyDefaultFilter).join(" ") : v;
2093
+ },
2094
+ };
2095
+
2096
+ const browserNumberValueTypes = {
2097
+ // Border props
2098
+ borderWidth: px,
2099
+ borderTopWidth: px,
2100
+ borderRightWidth: px,
2101
+ borderBottomWidth: px,
2102
+ borderLeftWidth: px,
2103
+ borderRadius: px,
2104
+ radius: px,
2105
+ borderTopLeftRadius: px,
2106
+ borderTopRightRadius: px,
2107
+ borderBottomRightRadius: px,
2108
+ borderBottomLeftRadius: px,
2109
+ // Positioning props
2110
+ width: px,
2111
+ maxWidth: px,
2112
+ height: px,
2113
+ maxHeight: px,
2114
+ top: px,
2115
+ right: px,
2116
+ bottom: px,
2117
+ left: px,
2118
+ // Spacing props
2119
+ padding: px,
2120
+ paddingTop: px,
2121
+ paddingRight: px,
2122
+ paddingBottom: px,
2123
+ paddingLeft: px,
2124
+ margin: px,
2125
+ marginTop: px,
2126
+ marginRight: px,
2127
+ marginBottom: px,
2128
+ marginLeft: px,
2129
+ // Misc
2130
+ backgroundPositionX: px,
2131
+ backgroundPositionY: px,
2132
+ };
2133
+
2134
+ const transformValueTypes = {
2135
+ rotate: degrees,
2136
+ rotateX: degrees,
2137
+ rotateY: degrees,
2138
+ rotateZ: degrees,
2139
+ scale,
2140
+ scaleX: scale,
2141
+ scaleY: scale,
2142
+ scaleZ: scale,
2143
+ skew: degrees,
2144
+ skewX: degrees,
2145
+ skewY: degrees,
2146
+ distance: px,
2147
+ translateX: px,
2148
+ translateY: px,
2149
+ translateZ: px,
2150
+ x: px,
2151
+ y: px,
2152
+ z: px,
2153
+ perspective: px,
2154
+ transformPerspective: px,
2155
+ opacity: alpha,
2156
+ originX: progressPercentage,
2157
+ originY: progressPercentage,
2158
+ originZ: px,
2159
+ };
2160
+
2161
+ const int = {
2162
+ ...number,
2163
+ transform: Math.round,
2164
+ };
2165
+
2166
+ const numberValueTypes = {
2167
+ ...browserNumberValueTypes,
2168
+ ...transformValueTypes,
2169
+ zIndex: int,
2170
+ size: px,
2171
+ // SVG
2172
+ fillOpacity: alpha,
2173
+ strokeOpacity: alpha,
2174
+ numOctaves: int,
2175
+ };
2176
+
1976
2177
  /**
1977
- * Tests a dimensional value against the list of dimension ValueTypes
2178
+ * A map of default value types for common values
1978
2179
  */
1979
- const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
2180
+ const defaultValueTypes = {
2181
+ ...numberValueTypes,
2182
+ // Color props
2183
+ color,
2184
+ backgroundColor: color,
2185
+ outlineColor: color,
2186
+ fill: color,
2187
+ stroke: color,
2188
+ // Border props
2189
+ borderColor: color,
2190
+ borderTopColor: color,
2191
+ borderRightColor: color,
2192
+ borderBottomColor: color,
2193
+ borderLeftColor: color,
2194
+ filter,
2195
+ WebkitFilter: filter,
2196
+ };
2197
+ /**
2198
+ * Gets the default ValueType for the provided value key
2199
+ */
2200
+ const getDefaultValueType = (key) => defaultValueTypes[key];
2201
+
2202
+ function getAnimatableNone(key, value) {
2203
+ let defaultValueType = getDefaultValueType(key);
2204
+ if (defaultValueType !== filter)
2205
+ defaultValueType = complex;
2206
+ // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
2207
+ return defaultValueType.getAnimatableNone
2208
+ ? defaultValueType.getAnimatableNone(value)
2209
+ : undefined;
2210
+ }
2211
+
2212
+ /**
2213
+ * If we encounter keyframes like "none" or "0" and we also have keyframes like
2214
+ * "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
2215
+ * the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
2216
+ * zero equivalents, i.e. "#fff0" or "0px 0px".
2217
+ */
2218
+ const invalidTemplates = new Set(["auto", "none", "0"]);
2219
+ function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
2220
+ let i = 0;
2221
+ let animatableTemplate = undefined;
2222
+ while (i < unresolvedKeyframes.length && !animatableTemplate) {
2223
+ const keyframe = unresolvedKeyframes[i];
2224
+ if (typeof keyframe === "string" &&
2225
+ !invalidTemplates.has(keyframe) &&
2226
+ analyseComplexValue(keyframe).values.length) {
2227
+ animatableTemplate = unresolvedKeyframes[i];
2228
+ }
2229
+ i++;
2230
+ }
2231
+ if (animatableTemplate && name) {
2232
+ for (const noneIndex of noneKeyframeIndexes) {
2233
+ unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
2234
+ }
2235
+ }
2236
+ }
2237
+
2238
+ const isNumOrPxType = (v) => v === number || v === px;
2239
+ const getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(", ")[pos]);
2240
+ const getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {
2241
+ if (transform === "none" || !transform)
2242
+ return 0;
2243
+ const matrix3d = transform.match(/^matrix3d\((.+)\)$/u);
2244
+ if (matrix3d) {
2245
+ return getPosFromMatrix(matrix3d[1], pos3);
2246
+ }
2247
+ else {
2248
+ const matrix = transform.match(/^matrix\((.+)\)$/u);
2249
+ if (matrix) {
2250
+ return getPosFromMatrix(matrix[1], pos2);
2251
+ }
2252
+ else {
2253
+ return 0;
2254
+ }
2255
+ }
2256
+ };
2257
+ const transformKeys = new Set(["x", "y", "z"]);
2258
+ const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
2259
+ function removeNonTranslationalTransform(visualElement) {
2260
+ const removedTransforms = [];
2261
+ nonTranslationalTransformKeys.forEach((key) => {
2262
+ const value = visualElement.getValue(key);
2263
+ if (value !== undefined) {
2264
+ removedTransforms.push([key, value.get()]);
2265
+ value.set(key.startsWith("scale") ? 1 : 0);
2266
+ }
2267
+ });
2268
+ return removedTransforms;
2269
+ }
2270
+ const positionalValues = {
2271
+ // Dimensions
2272
+ width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
2273
+ height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
2274
+ top: (_bbox, { top }) => parseFloat(top),
2275
+ left: (_bbox, { left }) => parseFloat(left),
2276
+ bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
2277
+ right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
2278
+ // Transform
2279
+ x: getTranslateFromMatrix(4, 13),
2280
+ y: getTranslateFromMatrix(5, 14),
2281
+ };
2282
+ // Alias translate longform names
2283
+ positionalValues.translateX = positionalValues.x;
2284
+ positionalValues.translateY = positionalValues.y;
1980
2285
 
1981
2286
  const toResolve = new Set();
1982
2287
  let isScheduled = false;
@@ -2071,457 +2376,150 @@
2071
2376
  if (this.isAsync) {
2072
2377
  toResolve.add(this);
2073
2378
  if (!isScheduled) {
2074
- isScheduled = true;
2075
- frame.read(readAllKeyframes);
2076
- frame.resolveKeyframes(measureAllKeyframes);
2077
- }
2078
- }
2079
- else {
2080
- this.readKeyframes();
2081
- this.complete();
2082
- }
2083
- }
2084
- readKeyframes() {
2085
- const { unresolvedKeyframes, name, element, motionValue } = this;
2086
- /**
2087
- * If a keyframe is null, we hydrate it either by reading it from
2088
- * the instance, or propagating from previous keyframes.
2089
- */
2090
- for (let i = 0; i < unresolvedKeyframes.length; i++) {
2091
- if (unresolvedKeyframes[i] === null) {
2092
- /**
2093
- * If the first keyframe is null, we need to find its value by sampling the element
2094
- */
2095
- if (i === 0) {
2096
- const currentValue = motionValue === null || motionValue === void 0 ? void 0 : motionValue.get();
2097
- const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
2098
- if (currentValue !== undefined) {
2099
- unresolvedKeyframes[0] = currentValue;
2100
- }
2101
- else if (element && name) {
2102
- const valueAsRead = element.readValue(name, finalKeyframe);
2103
- if (valueAsRead !== undefined && valueAsRead !== null) {
2104
- unresolvedKeyframes[0] = valueAsRead;
2105
- }
2106
- }
2107
- if (unresolvedKeyframes[0] === undefined) {
2108
- unresolvedKeyframes[0] = finalKeyframe;
2109
- }
2110
- if (motionValue && currentValue === undefined) {
2111
- motionValue.set(unresolvedKeyframes[0]);
2112
- }
2113
- }
2114
- else {
2115
- unresolvedKeyframes[i] = unresolvedKeyframes[i - 1];
2116
- }
2117
- }
2118
- }
2119
- }
2120
- setFinalKeyframe() { }
2121
- measureInitialState() { }
2122
- renderEndStyles() { }
2123
- measureEndState() { }
2124
- complete() {
2125
- this.isComplete = true;
2126
- this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);
2127
- toResolve.delete(this);
2128
- }
2129
- cancel() {
2130
- if (!this.isComplete) {
2131
- this.isScheduled = false;
2132
- toResolve.delete(this);
2133
- }
2134
- }
2135
- resume() {
2136
- if (!this.isComplete)
2137
- this.scheduleResolve();
2138
- }
2139
- }
2140
-
2141
- // If this number is a decimal, make it just five decimal places
2142
- // to avoid exponents
2143
- const sanitize = (v) => Math.round(v * 100000) / 100000;
2144
-
2145
- const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
2146
-
2147
- function isNullish(v) {
2148
- return v == null;
2149
- }
2150
-
2151
- const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
2152
-
2153
- /**
2154
- * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
2155
- * but false if a number or multiple colors
2156
- */
2157
- const isColorString = (type, testProp) => (v) => {
2158
- return Boolean((typeof v === "string" &&
2159
- singleColorRegex.test(v) &&
2160
- v.startsWith(type)) ||
2161
- (testProp &&
2162
- !isNullish(v) &&
2163
- Object.prototype.hasOwnProperty.call(v, testProp)));
2164
- };
2165
- const splitColor = (aName, bName, cName) => (v) => {
2166
- if (typeof v !== "string")
2167
- return v;
2168
- const [a, b, c, alpha] = v.match(floatRegex);
2169
- return {
2170
- [aName]: parseFloat(a),
2171
- [bName]: parseFloat(b),
2172
- [cName]: parseFloat(c),
2173
- alpha: alpha !== undefined ? parseFloat(alpha) : 1,
2174
- };
2175
- };
2176
-
2177
- const clampRgbUnit = (v) => clamp(0, 255, v);
2178
- const rgbUnit = {
2179
- ...number,
2180
- transform: (v) => Math.round(clampRgbUnit(v)),
2181
- };
2182
- const rgba = {
2183
- test: /*@__PURE__*/ isColorString("rgb", "red"),
2184
- parse: /*@__PURE__*/ splitColor("red", "green", "blue"),
2185
- transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
2186
- rgbUnit.transform(red) +
2187
- ", " +
2188
- rgbUnit.transform(green) +
2189
- ", " +
2190
- rgbUnit.transform(blue) +
2191
- ", " +
2192
- sanitize(alpha.transform(alpha$1)) +
2193
- ")",
2194
- };
2195
-
2196
- function parseHex(v) {
2197
- let r = "";
2198
- let g = "";
2199
- let b = "";
2200
- let a = "";
2201
- // If we have 6 characters, ie #FF0000
2202
- if (v.length > 5) {
2203
- r = v.substring(1, 3);
2204
- g = v.substring(3, 5);
2205
- b = v.substring(5, 7);
2206
- a = v.substring(7, 9);
2207
- // Or we have 3 characters, ie #F00
2208
- }
2209
- else {
2210
- r = v.substring(1, 2);
2211
- g = v.substring(2, 3);
2212
- b = v.substring(3, 4);
2213
- a = v.substring(4, 5);
2214
- r += r;
2215
- g += g;
2216
- b += b;
2217
- a += a;
2218
- }
2219
- return {
2220
- red: parseInt(r, 16),
2221
- green: parseInt(g, 16),
2222
- blue: parseInt(b, 16),
2223
- alpha: a ? parseInt(a, 16) / 255 : 1,
2224
- };
2225
- }
2226
- const hex = {
2227
- test: /*@__PURE__*/ isColorString("#"),
2228
- parse: parseHex,
2229
- transform: rgba.transform,
2230
- };
2231
-
2232
- const hsla = {
2233
- test: /*@__PURE__*/ isColorString("hsl", "hue"),
2234
- parse: /*@__PURE__*/ splitColor("hue", "saturation", "lightness"),
2235
- transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
2236
- return ("hsla(" +
2237
- Math.round(hue) +
2238
- ", " +
2239
- percent.transform(sanitize(saturation)) +
2240
- ", " +
2241
- percent.transform(sanitize(lightness)) +
2242
- ", " +
2243
- sanitize(alpha.transform(alpha$1)) +
2244
- ")");
2245
- },
2246
- };
2247
-
2248
- const color = {
2249
- test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
2250
- parse: (v) => {
2251
- if (rgba.test(v)) {
2252
- return rgba.parse(v);
2253
- }
2254
- else if (hsla.test(v)) {
2255
- return hsla.parse(v);
2256
- }
2257
- else {
2258
- return hex.parse(v);
2259
- }
2260
- },
2261
- transform: (v) => {
2262
- return typeof v === "string"
2263
- ? v
2264
- : v.hasOwnProperty("red")
2265
- ? rgba.transform(v)
2266
- : hsla.transform(v);
2267
- },
2268
- };
2269
-
2270
- const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
2271
-
2272
- function test(v) {
2273
- var _a, _b;
2274
- return (isNaN(v) &&
2275
- typeof v === "string" &&
2276
- (((_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) || 0) +
2277
- (((_b = v.match(colorRegex)) === null || _b === void 0 ? void 0 : _b.length) || 0) >
2278
- 0);
2279
- }
2280
- const NUMBER_TOKEN = "number";
2281
- const COLOR_TOKEN = "color";
2282
- const VAR_TOKEN = "var";
2283
- const VAR_FUNCTION_TOKEN = "var(";
2284
- const SPLIT_TOKEN = "${}";
2285
- // this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`
2286
- const complexRegex = /var\s*\(\s*--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)|#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\)|-?(?:\d+(?:\.\d+)?|\.\d+)/giu;
2287
- function analyseComplexValue(value) {
2288
- const originalValue = value.toString();
2289
- const values = [];
2290
- const indexes = {
2291
- color: [],
2292
- number: [],
2293
- var: [],
2294
- };
2295
- const types = [];
2296
- let i = 0;
2297
- const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
2298
- if (color.test(parsedValue)) {
2299
- indexes.color.push(i);
2300
- types.push(COLOR_TOKEN);
2301
- values.push(color.parse(parsedValue));
2302
- }
2303
- else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
2304
- indexes.var.push(i);
2305
- types.push(VAR_TOKEN);
2306
- values.push(parsedValue);
2379
+ isScheduled = true;
2380
+ frame.read(readAllKeyframes);
2381
+ frame.resolveKeyframes(measureAllKeyframes);
2382
+ }
2307
2383
  }
2308
2384
  else {
2309
- indexes.number.push(i);
2310
- types.push(NUMBER_TOKEN);
2311
- values.push(parseFloat(parsedValue));
2385
+ this.readKeyframes();
2386
+ this.complete();
2312
2387
  }
2313
- ++i;
2314
- return SPLIT_TOKEN;
2315
- });
2316
- const split = tokenised.split(SPLIT_TOKEN);
2317
- return { values, split, indexes, types };
2318
- }
2319
- function parseComplexValue(v) {
2320
- return analyseComplexValue(v).values;
2321
- }
2322
- function createTransformer(source) {
2323
- const { split, types } = analyseComplexValue(source);
2324
- const numSections = split.length;
2325
- return (v) => {
2326
- let output = "";
2327
- for (let i = 0; i < numSections; i++) {
2328
- output += split[i];
2329
- if (v[i] !== undefined) {
2330
- const type = types[i];
2331
- if (type === NUMBER_TOKEN) {
2332
- output += sanitize(v[i]);
2333
- }
2334
- else if (type === COLOR_TOKEN) {
2335
- output += color.transform(v[i]);
2388
+ }
2389
+ readKeyframes() {
2390
+ const { unresolvedKeyframes, name, element, motionValue } = this;
2391
+ /**
2392
+ * If a keyframe is null, we hydrate it either by reading it from
2393
+ * the instance, or propagating from previous keyframes.
2394
+ */
2395
+ for (let i = 0; i < unresolvedKeyframes.length; i++) {
2396
+ if (unresolvedKeyframes[i] === null) {
2397
+ /**
2398
+ * If the first keyframe is null, we need to find its value by sampling the element
2399
+ */
2400
+ if (i === 0) {
2401
+ const currentValue = motionValue === null || motionValue === void 0 ? void 0 : motionValue.get();
2402
+ const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
2403
+ if (currentValue !== undefined) {
2404
+ unresolvedKeyframes[0] = currentValue;
2405
+ }
2406
+ else if (element && name) {
2407
+ const valueAsRead = element.readValue(name, finalKeyframe);
2408
+ if (valueAsRead !== undefined && valueAsRead !== null) {
2409
+ unresolvedKeyframes[0] = valueAsRead;
2410
+ }
2411
+ }
2412
+ if (unresolvedKeyframes[0] === undefined) {
2413
+ unresolvedKeyframes[0] = finalKeyframe;
2414
+ }
2415
+ if (motionValue && currentValue === undefined) {
2416
+ motionValue.set(unresolvedKeyframes[0]);
2417
+ }
2336
2418
  }
2337
2419
  else {
2338
- output += v[i];
2420
+ unresolvedKeyframes[i] = unresolvedKeyframes[i - 1];
2339
2421
  }
2340
2422
  }
2341
2423
  }
2342
- return output;
2343
- };
2344
- }
2345
- const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
2346
- function getAnimatableNone$1(v) {
2347
- const parsed = parseComplexValue(v);
2348
- const transformer = createTransformer(v);
2349
- return transformer(parsed.map(convertNumbersToZero));
2424
+ }
2425
+ setFinalKeyframe() { }
2426
+ measureInitialState() { }
2427
+ renderEndStyles() { }
2428
+ measureEndState() { }
2429
+ complete() {
2430
+ this.isComplete = true;
2431
+ this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);
2432
+ toResolve.delete(this);
2433
+ }
2434
+ cancel() {
2435
+ if (!this.isComplete) {
2436
+ this.isScheduled = false;
2437
+ toResolve.delete(this);
2438
+ }
2439
+ }
2440
+ resume() {
2441
+ if (!this.isComplete)
2442
+ this.scheduleResolve();
2443
+ }
2350
2444
  }
2351
- const complex = {
2352
- test,
2353
- parse: parseComplexValue,
2354
- createTransformer,
2355
- getAnimatableNone: getAnimatableNone$1,
2356
- };
2357
2445
 
2358
2446
  /**
2359
- * Properties that should default to 1 or 100%
2447
+ * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
2360
2448
  */
2361
- const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
2362
- function applyDefaultFilter(v) {
2363
- const [name, value] = v.slice(0, -1).split("(");
2364
- if (name === "drop-shadow")
2365
- return v;
2366
- const [number] = value.match(floatRegex) || [];
2367
- if (!number)
2368
- return v;
2369
- const unit = value.replace(number, "");
2370
- let defaultValue = maxDefaults.has(name) ? 1 : 0;
2371
- if (number !== value)
2372
- defaultValue *= 100;
2373
- return name + "(" + defaultValue + unit + ")";
2374
- }
2375
- const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
2376
- const filter = {
2377
- ...complex,
2378
- getAnimatableNone: (v) => {
2379
- const functions = v.match(functionRegex);
2380
- return functions ? functions.map(applyDefaultFilter).join(" ") : v;
2381
- },
2382
- };
2383
-
2384
- const browserNumberValueTypes = {
2385
- // Border props
2386
- borderWidth: px,
2387
- borderTopWidth: px,
2388
- borderRightWidth: px,
2389
- borderBottomWidth: px,
2390
- borderLeftWidth: px,
2391
- borderRadius: px,
2392
- radius: px,
2393
- borderTopLeftRadius: px,
2394
- borderTopRightRadius: px,
2395
- borderBottomRightRadius: px,
2396
- borderBottomLeftRadius: px,
2397
- // Positioning props
2398
- width: px,
2399
- maxWidth: px,
2400
- height: px,
2401
- maxHeight: px,
2402
- top: px,
2403
- right: px,
2404
- bottom: px,
2405
- left: px,
2406
- // Spacing props
2407
- padding: px,
2408
- paddingTop: px,
2409
- paddingRight: px,
2410
- paddingBottom: px,
2411
- paddingLeft: px,
2412
- margin: px,
2413
- marginTop: px,
2414
- marginRight: px,
2415
- marginBottom: px,
2416
- marginLeft: px,
2417
- // Misc
2418
- backgroundPositionX: px,
2419
- backgroundPositionY: px,
2420
- };
2421
-
2422
- const transformValueTypes = {
2423
- rotate: degrees,
2424
- rotateX: degrees,
2425
- rotateY: degrees,
2426
- rotateZ: degrees,
2427
- scale,
2428
- scaleX: scale,
2429
- scaleY: scale,
2430
- scaleZ: scale,
2431
- skew: degrees,
2432
- skewX: degrees,
2433
- skewY: degrees,
2434
- distance: px,
2435
- translateX: px,
2436
- translateY: px,
2437
- translateZ: px,
2438
- x: px,
2439
- y: px,
2440
- z: px,
2441
- perspective: px,
2442
- transformPerspective: px,
2443
- opacity: alpha,
2444
- originX: progressPercentage,
2445
- originY: progressPercentage,
2446
- originZ: px,
2447
- };
2448
-
2449
- const int = {
2450
- ...number,
2451
- transform: Math.round,
2452
- };
2449
+ const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
2453
2450
 
2454
- const numberValueTypes = {
2455
- ...browserNumberValueTypes,
2456
- ...transformValueTypes,
2457
- zIndex: int,
2458
- size: px,
2459
- // SVG
2460
- fillOpacity: alpha,
2461
- strokeOpacity: alpha,
2462
- numOctaves: int,
2451
+ const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
2452
+ const isCSSVariableName =
2453
+ /*@__PURE__*/ checkStringStartsWith("--");
2454
+ const startsAsVariableToken =
2455
+ /*@__PURE__*/ checkStringStartsWith("var(--");
2456
+ const isCSSVariableToken = (value) => {
2457
+ const startsWithToken = startsAsVariableToken(value);
2458
+ if (!startsWithToken)
2459
+ return false;
2460
+ // Ensure any comments are stripped from the value as this can harm performance of the regex.
2461
+ return singleCssVariableRegex.test(value.split("/*")[0].trim());
2463
2462
  };
2463
+ const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
2464
2464
 
2465
2465
  /**
2466
- * A map of default value types for common values
2466
+ * Parse Framer's special CSS variable format into a CSS token and a fallback.
2467
+ *
2468
+ * ```
2469
+ * `var(--foo, #fff)` => [`--foo`, '#fff']
2470
+ * ```
2471
+ *
2472
+ * @param current
2467
2473
  */
2468
- const defaultValueTypes = {
2469
- ...numberValueTypes,
2470
- // Color props
2471
- color,
2472
- backgroundColor: color,
2473
- outlineColor: color,
2474
- fill: color,
2475
- stroke: color,
2476
- // Border props
2477
- borderColor: color,
2478
- borderTopColor: color,
2479
- borderRightColor: color,
2480
- borderBottomColor: color,
2481
- borderLeftColor: color,
2482
- filter,
2483
- WebkitFilter: filter,
2484
- };
2474
+ const splitCSSVariableRegex =
2475
+ // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
2476
+ /^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
2477
+ function parseCSSVariable(current) {
2478
+ const match = splitCSSVariableRegex.exec(current);
2479
+ if (!match)
2480
+ return [,];
2481
+ const [, token1, token2, fallback] = match;
2482
+ return [`--${token1 !== null && token1 !== void 0 ? token1 : token2}`, fallback];
2483
+ }
2484
+ const maxDepth = 4;
2485
+ function getVariableValue(current, element, depth = 1) {
2486
+ exports.invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
2487
+ const [token, fallback] = parseCSSVariable(current);
2488
+ // No CSS variable detected
2489
+ if (!token)
2490
+ return;
2491
+ // Attempt to read this CSS variable off the element
2492
+ const resolved = window.getComputedStyle(element).getPropertyValue(token);
2493
+ if (resolved) {
2494
+ const trimmed = resolved.trim();
2495
+ return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
2496
+ }
2497
+ return isCSSVariableToken(fallback)
2498
+ ? getVariableValue(fallback, element, depth + 1)
2499
+ : fallback;
2500
+ }
2501
+
2485
2502
  /**
2486
- * Gets the default ValueType for the provided value key
2503
+ * Tests a provided value against a ValueType
2487
2504
  */
2488
- const getDefaultValueType = (key) => defaultValueTypes[key];
2505
+ const testValueType = (v) => (type) => type.test(v);
2489
2506
 
2490
- function getAnimatableNone(key, value) {
2491
- let defaultValueType = getDefaultValueType(key);
2492
- if (defaultValueType !== filter)
2493
- defaultValueType = complex;
2494
- // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
2495
- return defaultValueType.getAnimatableNone
2496
- ? defaultValueType.getAnimatableNone(value)
2497
- : undefined;
2498
- }
2507
+ /**
2508
+ * ValueType for "auto"
2509
+ */
2510
+ const auto = {
2511
+ test: (v) => v === "auto",
2512
+ parse: (v) => v,
2513
+ };
2499
2514
 
2500
2515
  /**
2501
- * If we encounter keyframes like "none" or "0" and we also have keyframes like
2502
- * "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
2503
- * the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
2504
- * zero equivalents, i.e. "#fff0" or "0px 0px".
2516
+ * A list of value types commonly used for dimensions
2505
2517
  */
2506
- const invalidTemplates = new Set(["auto", "none", "0"]);
2507
- function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
2508
- let i = 0;
2509
- let animatableTemplate = undefined;
2510
- while (i < unresolvedKeyframes.length && !animatableTemplate) {
2511
- const keyframe = unresolvedKeyframes[i];
2512
- if (typeof keyframe === "string" &&
2513
- !invalidTemplates.has(keyframe) &&
2514
- analyseComplexValue(keyframe).values.length) {
2515
- animatableTemplate = unresolvedKeyframes[i];
2516
- }
2517
- i++;
2518
- }
2519
- if (animatableTemplate && name) {
2520
- for (const noneIndex of noneKeyframeIndexes) {
2521
- unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
2522
- }
2523
- }
2524
- }
2518
+ const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
2519
+ /**
2520
+ * Tests a dimensional value against the list of dimension ValueTypes
2521
+ */
2522
+ const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
2525
2523
 
2526
2524
  class DOMKeyframesResolver extends KeyframeResolver {
2527
2525
  constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
@@ -3187,8 +3185,9 @@
3187
3185
  */
3188
3186
  if (inputLength === 1)
3189
3187
  return () => output[0];
3190
- if (inputLength === 2 && input[0] === input[1])
3188
+ if (inputLength === 2 && output[0] === output[1])
3191
3189
  return () => output[1];
3190
+ const isZeroDeltaRange = input[0] === input[1];
3192
3191
  // If input runs highest -> lowest, reverse both arrays
3193
3192
  if (input[0] > input[inputLength - 1]) {
3194
3193
  input = [...input].reverse();
@@ -3197,6 +3196,8 @@
3197
3196
  const mixers = createMixers(output, ease, mixer);
3198
3197
  const numMixers = mixers.length;
3199
3198
  const interpolator = (v) => {
3199
+ if (isZeroDeltaRange && v < input[0])
3200
+ return output[0];
3200
3201
  let i = 0;
3201
3202
  if (numMixers > 1) {
3202
3203
  for (; i < input.length - 2; i++) {
@@ -4166,7 +4167,7 @@
4166
4167
  }
4167
4168
  }
4168
4169
  addValueToWillChange(visualElement, key);
4169
- value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && transformProps.has(key)
4170
+ value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && positionalKeys.has(key)
4170
4171
  ? { type: false }
4171
4172
  : valueTransition, visualElement, isHandoff));
4172
4173
  const animation = value.animation;
@@ -4188,43 +4189,37 @@
4188
4189
  return element instanceof SVGElement && element.tagName !== "svg";
4189
4190
  }
4190
4191
 
4191
- const scaleCorrectors = {};
4192
-
4193
- function isForcedMotionValue(key, { layout, layoutId }) {
4194
- return (transformProps.has(key) ||
4195
- key.startsWith("origin") ||
4196
- ((layout || layoutId !== undefined) &&
4197
- (!!scaleCorrectors[key] || key === "opacity")));
4198
- }
4199
-
4200
- function scrapeMotionValuesFromProps$1(props, prevProps, visualElement) {
4201
- var _a;
4202
- const { style } = props;
4203
- const newValues = {};
4204
- for (const key in style) {
4205
- if (isMotionValue(style[key]) ||
4206
- (prevProps.style &&
4207
- isMotionValue(prevProps.style[key])) ||
4208
- isForcedMotionValue(key, props) ||
4209
- ((_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.getValue(key)) === null || _a === void 0 ? void 0 : _a.liveStyle) !== undefined) {
4210
- newValues[key] = style[key];
4211
- }
4212
- }
4213
- return newValues;
4214
- }
4192
+ const createAxis = () => ({ min: 0, max: 0 });
4193
+ const createBox = () => ({
4194
+ x: createAxis(),
4195
+ y: createAxis(),
4196
+ });
4215
4197
 
4216
- function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
4217
- const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
4218
- for (const key in props) {
4219
- if (isMotionValue(props[key]) ||
4220
- isMotionValue(prevProps[key])) {
4221
- const targetKey = transformPropOrder.indexOf(key) !== -1
4222
- ? "attr" + key.charAt(0).toUpperCase() + key.substring(1)
4223
- : key;
4224
- newValues[targetKey] = props[key];
4225
- }
4226
- }
4227
- return newValues;
4198
+ const featureProps = {
4199
+ animation: [
4200
+ "animate",
4201
+ "variants",
4202
+ "whileHover",
4203
+ "whileTap",
4204
+ "exit",
4205
+ "whileInView",
4206
+ "whileFocus",
4207
+ "whileDrag",
4208
+ ],
4209
+ exit: ["exit"],
4210
+ drag: ["drag", "dragControls"],
4211
+ focus: ["whileFocus"],
4212
+ hover: ["whileHover", "onHoverStart", "onHoverEnd"],
4213
+ tap: ["whileTap", "onTap", "onTapStart", "onTapCancel"],
4214
+ pan: ["onPan", "onPanStart", "onPanSessionStart", "onPanEnd"],
4215
+ inView: ["whileInView", "onViewportEnter", "onViewportLeave"],
4216
+ layout: ["layout", "layoutId"],
4217
+ };
4218
+ const featureDefinitions = {};
4219
+ for (const key in featureProps) {
4220
+ featureDefinitions[key] = {
4221
+ isEnabled: (props) => featureProps[key].some((name) => !!props[name]),
4222
+ };
4228
4223
  }
4229
4224
 
4230
4225
  const isBrowser = typeof window !== "undefined";
@@ -4248,6 +4243,15 @@
4248
4243
  }
4249
4244
  }
4250
4245
 
4246
+ /**
4247
+ * A list of all ValueTypes
4248
+ */
4249
+ const valueTypes = [...dimensionValueTypes, color, complex];
4250
+ /**
4251
+ * Tests a value against the list of ValueTypes
4252
+ */
4253
+ const findValueType = (v) => valueTypes.find(testValueType(v));
4254
+
4251
4255
  function isAnimationControls(v) {
4252
4256
  return (v !== null &&
4253
4257
  typeof v === "object" &&
@@ -4295,7 +4299,7 @@
4295
4299
  * and warn against mismatches.
4296
4300
  */
4297
4301
  {
4298
- warnOnce(nextValue.version === "11.16.4", `Attempting to mix Motion versions ${nextValue.version} with 11.16.4 may not work as expected.`);
4302
+ warnOnce(nextValue.version === "11.16.6", `Attempting to mix Motion versions ${nextValue.version} with 11.16.6 may not work as expected.`);
4299
4303
  }
4300
4304
  }
4301
4305
  else if (isMotionValue(prevValue)) {
@@ -4334,48 +4338,6 @@
4334
4338
  return next;
4335
4339
  }
4336
4340
 
4337
- const featureProps = {
4338
- animation: [
4339
- "animate",
4340
- "variants",
4341
- "whileHover",
4342
- "whileTap",
4343
- "exit",
4344
- "whileInView",
4345
- "whileFocus",
4346
- "whileDrag",
4347
- ],
4348
- exit: ["exit"],
4349
- drag: ["drag", "dragControls"],
4350
- focus: ["whileFocus"],
4351
- hover: ["whileHover", "onHoverStart", "onHoverEnd"],
4352
- tap: ["whileTap", "onTap", "onTapStart", "onTapCancel"],
4353
- pan: ["onPan", "onPanStart", "onPanSessionStart", "onPanEnd"],
4354
- inView: ["whileInView", "onViewportEnter", "onViewportLeave"],
4355
- layout: ["layout", "layoutId"],
4356
- };
4357
- const featureDefinitions = {};
4358
- for (const key in featureProps) {
4359
- featureDefinitions[key] = {
4360
- isEnabled: (props) => featureProps[key].some((name) => !!props[name]),
4361
- };
4362
- }
4363
-
4364
- /**
4365
- * A list of all ValueTypes
4366
- */
4367
- const valueTypes = [...dimensionValueTypes, color, complex];
4368
- /**
4369
- * Tests a value against the list of ValueTypes
4370
- */
4371
- const findValueType = (v) => valueTypes.find(testValueType(v));
4372
-
4373
- const createAxis = () => ({ min: 0, max: 0 });
4374
- const createBox = () => ({
4375
- x: createAxis(),
4376
- y: createAxis(),
4377
- });
4378
-
4379
4341
  const propEventHandlers = [
4380
4342
  "AnimationStart",
4381
4343
  "AnimationComplete",
@@ -5112,6 +5074,8 @@
5112
5074
  "lengthAdjust",
5113
5075
  ]);
5114
5076
 
5077
+ const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
5078
+
5115
5079
  function renderHTML(element, { style, vars }, styleProp, projection) {
5116
5080
  Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
5117
5081
  // Loop over any CSS variables and assign those.
@@ -5127,7 +5091,44 @@
5127
5091
  }
5128
5092
  }
5129
5093
 
5130
- const isSVGTag = (tag) => typeof tag === "string" && tag.toLowerCase() === "svg";
5094
+ const scaleCorrectors = {};
5095
+
5096
+ function isForcedMotionValue(key, { layout, layoutId }) {
5097
+ return (transformProps.has(key) ||
5098
+ key.startsWith("origin") ||
5099
+ ((layout || layoutId !== undefined) &&
5100
+ (!!scaleCorrectors[key] || key === "opacity")));
5101
+ }
5102
+
5103
+ function scrapeMotionValuesFromProps$1(props, prevProps, visualElement) {
5104
+ var _a;
5105
+ const { style } = props;
5106
+ const newValues = {};
5107
+ for (const key in style) {
5108
+ if (isMotionValue(style[key]) ||
5109
+ (prevProps.style &&
5110
+ isMotionValue(prevProps.style[key])) ||
5111
+ isForcedMotionValue(key, props) ||
5112
+ ((_a = visualElement === null || visualElement === void 0 ? void 0 : visualElement.getValue(key)) === null || _a === void 0 ? void 0 : _a.liveStyle) !== undefined) {
5113
+ newValues[key] = style[key];
5114
+ }
5115
+ }
5116
+ return newValues;
5117
+ }
5118
+
5119
+ function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
5120
+ const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
5121
+ for (const key in props) {
5122
+ if (isMotionValue(props[key]) ||
5123
+ isMotionValue(prevProps[key])) {
5124
+ const targetKey = transformPropOrder.indexOf(key) !== -1
5125
+ ? "attr" + key.charAt(0).toUpperCase() + key.substring(1)
5126
+ : key;
5127
+ newValues[targetKey] = props[key];
5128
+ }
5129
+ }
5130
+ return newValues;
5131
+ }
5131
5132
 
5132
5133
  class SVGVisualElement extends DOMVisualElement {
5133
5134
  constructor() {
@@ -5746,25 +5747,6 @@
5746
5747
  return inset;
5747
5748
  }
5748
5749
 
5749
- const ScrollOffset = {
5750
- Enter: [
5751
- [0, 1],
5752
- [1, 1],
5753
- ],
5754
- Exit: [
5755
- [0, 0],
5756
- [1, 0],
5757
- ],
5758
- Any: [
5759
- [1, 0],
5760
- [0, 1],
5761
- ],
5762
- All: [
5763
- [0, 0],
5764
- [1, 1],
5765
- ],
5766
- };
5767
-
5768
5750
  const namedEdges = {
5769
5751
  start: 0,
5770
5752
  center: 0.5,
@@ -5841,6 +5823,25 @@
5841
5823
  return targetPoint - containerPoint;
5842
5824
  }
5843
5825
 
5826
+ const ScrollOffset = {
5827
+ Enter: [
5828
+ [0, 1],
5829
+ [1, 1],
5830
+ ],
5831
+ Exit: [
5832
+ [0, 0],
5833
+ [1, 0],
5834
+ ],
5835
+ Any: [
5836
+ [1, 0],
5837
+ [0, 1],
5838
+ ],
5839
+ All: [
5840
+ [0, 0],
5841
+ [1, 1],
5842
+ ],
5843
+ };
5844
+
5844
5845
  const point = { x: 0, y: 0 };
5845
5846
  function getTargetSize(target) {
5846
5847
  return "getBBox" in target && target.tagName !== "svg"
@@ -5887,10 +5888,10 @@
5887
5888
  * to map scroll value into a progress.
5888
5889
  */
5889
5890
  if (hasChanged) {
5890
- info[axis].interpolate = interpolate(info[axis].offset, defaultOffset$1(offsetDefinition));
5891
+ info[axis].interpolate = interpolate(info[axis].offset, defaultOffset$1(offsetDefinition), { clamp: false });
5891
5892
  info[axis].interpolatorOffsets = [...info[axis].offset];
5892
5893
  }
5893
- info[axis].progress = info[axis].interpolate(info[axis].current);
5894
+ info[axis].progress = clamp(0, 1, info[axis].interpolate(info[axis].current));
5894
5895
  }
5895
5896
 
5896
5897
  function measure(container, target = container, info) {