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