framer-motion 7.7.0 → 7.7.1

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 (62) hide show
  1. package/dist/cjs/index.js +529 -155
  2. package/dist/es/animation/legacy-popmotion/index.mjs +1 -1
  3. package/dist/es/animation/legacy-popmotion/inertia.mjs +2 -2
  4. package/dist/es/animation/utils/is-animatable.mjs +1 -1
  5. package/dist/es/frameloop/create-render-step.mjs +88 -0
  6. package/dist/es/frameloop/data.mjs +6 -0
  7. package/dist/es/frameloop/index.mjs +59 -0
  8. package/dist/es/frameloop/on-next-frame.mjs +12 -0
  9. package/dist/es/gestures/PanSession.mjs +4 -3
  10. package/dist/es/gestures/drag/VisualElementDragControls.mjs +1 -1
  11. package/dist/es/motion/features/layout/MeasureLayout.mjs +1 -1
  12. package/dist/es/projection/animation/mix-values.mjs +1 -1
  13. package/dist/es/projection/geometry/delta-remove.mjs +1 -1
  14. package/dist/es/projection/node/create-projection-node.mjs +1 -1
  15. package/dist/es/projection/styles/scale-border-radius.mjs +1 -1
  16. package/dist/es/projection/styles/scale-box-shadow.mjs +1 -1
  17. package/dist/es/render/VisualElement.mjs +1 -1
  18. package/dist/es/render/dom/utils/unit-conversion.mjs +2 -1
  19. package/dist/es/render/dom/value-types/animatable-none.mjs +2 -1
  20. package/dist/es/render/dom/value-types/defaults.mjs +2 -1
  21. package/dist/es/render/dom/value-types/dimensions.mjs +2 -1
  22. package/dist/es/render/dom/value-types/find.mjs +2 -1
  23. package/dist/es/render/dom/value-types/number.mjs +2 -1
  24. package/dist/es/render/dom/value-types/type-int.mjs +1 -1
  25. package/dist/es/render/svg/utils/path.mjs +1 -1
  26. package/dist/es/render/svg/utils/transform-origin.mjs +1 -1
  27. package/dist/es/render/utils/motion-values.mjs +1 -1
  28. package/dist/es/render/utils/setters.mjs +1 -1
  29. package/dist/es/utils/delay.mjs +1 -1
  30. package/dist/es/utils/interpolate.mjs +1 -1
  31. package/dist/es/utils/mix-color.mjs +4 -1
  32. package/dist/es/utils/mix-complex.mjs +5 -24
  33. package/dist/es/utils/use-animation-frame.mjs +1 -1
  34. package/dist/es/utils/use-force-update.mjs +1 -1
  35. package/dist/es/utils/use-instant-transition.mjs +1 -1
  36. package/dist/es/value/index.mjs +4 -3
  37. package/dist/es/value/types/color/hex.mjs +40 -0
  38. package/dist/es/value/types/color/hsla.mjs +22 -0
  39. package/dist/es/value/types/color/index.mjs +28 -0
  40. package/dist/es/value/types/color/rgba.mjs +25 -0
  41. package/dist/es/value/types/color/utils.mjs +23 -0
  42. package/dist/es/value/types/complex/filter.mjs +30 -0
  43. package/dist/es/value/types/complex/index.mjs +61 -0
  44. package/dist/es/value/types/numbers/index.mjs +17 -0
  45. package/dist/es/value/types/numbers/units.mjs +19 -0
  46. package/dist/es/value/types/utils.mjs +15 -0
  47. package/dist/es/value/use-combine-values.mjs +1 -1
  48. package/dist/framer-motion.dev.js +284 -230
  49. package/dist/framer-motion.js +1 -1
  50. package/dist/index.d.ts +7 -2
  51. package/dist/projection.dev.js +5451 -5397
  52. package/dist/size-rollup-dom-animation-assets.js +1 -1
  53. package/dist/size-rollup-dom-animation.js +1 -1
  54. package/dist/size-rollup-dom-max-assets.js +1 -1
  55. package/dist/size-rollup-dom-max.js +1 -1
  56. package/dist/size-rollup-m.js +1 -1
  57. package/dist/size-rollup-motion.js +1 -1
  58. package/dist/size-webpack-dom-animation.js +1 -1
  59. package/dist/size-webpack-dom-max.js +1 -1
  60. package/dist/size-webpack-m.js +1 -1
  61. package/dist/three-entry.d.ts +7 -2
  62. package/package.json +9 -11
@@ -558,207 +558,52 @@
558
558
  : value;
559
559
  };
560
560
 
561
- const clamp$2 = (min, max) => (v) => Math.max(Math.min(v, max), min);
562
- const sanitize = (v) => (v % 1 ? Number(v.toFixed(5)) : v);
563
- const floatRegex = /(-)?([\d]*\.?[\d])+/g;
564
- const colorRegex = /(#[0-9a-f]{6}|#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2}(-?[\d\.]+%?)\s*[\,\/]?\s*[\d\.]*%?\))/gi;
565
- const singleColorRegex = /^(#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2}(-?[\d\.]+%?)\s*[\,\/]?\s*[\d\.]*%?\))$/i;
566
- function isString$1(v) {
567
- return typeof v === 'string';
568
- }
561
+ const clamp$1 = (min, max, v) => Math.min(Math.max(v, min), max);
569
562
 
570
563
  const number = {
571
- test: (v) => typeof v === 'number',
564
+ test: (v) => typeof v === "number",
572
565
  parse: parseFloat,
573
566
  transform: (v) => v,
574
567
  };
575
- const alpha = Object.assign(Object.assign({}, number), { transform: clamp$2(0, 1) });
576
- const scale = Object.assign(Object.assign({}, number), { default: 1 });
577
-
578
- const createUnitType = (unit) => ({
579
- test: (v) => isString$1(v) && v.endsWith(unit) && v.split(' ').length === 1,
580
- parse: parseFloat,
581
- transform: (v) => `${v}${unit}`,
582
- });
583
- const degrees = createUnitType('deg');
584
- const percent = createUnitType('%');
585
- const px = createUnitType('px');
586
- const vh = createUnitType('vh');
587
- const vw = createUnitType('vw');
588
- const progressPercentage = Object.assign(Object.assign({}, percent), { parse: (v) => percent.parse(v) / 100, transform: (v) => percent.transform(v * 100) });
589
-
590
- const isColorString = (type, testProp) => (v) => {
591
- return Boolean((isString$1(v) && singleColorRegex.test(v) && v.startsWith(type)) ||
592
- (testProp && Object.prototype.hasOwnProperty.call(v, testProp)));
593
- };
594
- const splitColor = (aName, bName, cName) => (v) => {
595
- if (!isString$1(v))
596
- return v;
597
- const [a, b, c, alpha] = v.match(floatRegex);
598
- return {
599
- [aName]: parseFloat(a),
600
- [bName]: parseFloat(b),
601
- [cName]: parseFloat(c),
602
- alpha: alpha !== undefined ? parseFloat(alpha) : 1,
603
- };
604
- };
605
-
606
- const hsla = {
607
- test: isColorString('hsl', 'hue'),
608
- parse: splitColor('hue', 'saturation', 'lightness'),
609
- transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
610
- return ('hsla(' +
611
- Math.round(hue) +
612
- ', ' +
613
- percent.transform(sanitize(saturation)) +
614
- ', ' +
615
- percent.transform(sanitize(lightness)) +
616
- ', ' +
617
- sanitize(alpha.transform(alpha$1)) +
618
- ')');
619
- },
568
+ const alpha = {
569
+ ...number,
570
+ transform: (v) => clamp$1(0, 1, v),
620
571
  };
621
-
622
- const clampRgbUnit = clamp$2(0, 255);
623
- const rgbUnit = Object.assign(Object.assign({}, number), { transform: (v) => Math.round(clampRgbUnit(v)) });
624
- const rgba = {
625
- test: isColorString('rgb', 'red'),
626
- parse: splitColor('red', 'green', 'blue'),
627
- transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => 'rgba(' +
628
- rgbUnit.transform(red) +
629
- ', ' +
630
- rgbUnit.transform(green) +
631
- ', ' +
632
- rgbUnit.transform(blue) +
633
- ', ' +
634
- sanitize(alpha.transform(alpha$1)) +
635
- ')',
572
+ const scale = {
573
+ ...number,
574
+ default: 1,
636
575
  };
637
576
 
638
- function parseHex(v) {
639
- let r = '';
640
- let g = '';
641
- let b = '';
642
- let a = '';
643
- if (v.length > 5) {
644
- r = v.substr(1, 2);
645
- g = v.substr(3, 2);
646
- b = v.substr(5, 2);
647
- a = v.substr(7, 2);
648
- }
649
- else {
650
- r = v.substr(1, 1);
651
- g = v.substr(2, 1);
652
- b = v.substr(3, 1);
653
- a = v.substr(4, 1);
654
- r += r;
655
- g += g;
656
- b += b;
657
- a += a;
658
- }
659
- return {
660
- red: parseInt(r, 16),
661
- green: parseInt(g, 16),
662
- blue: parseInt(b, 16),
663
- alpha: a ? parseInt(a, 16) / 255 : 1,
664
- };
577
+ /**
578
+ * TODO: When we move from string as a source of truth to data models
579
+ * everything in this folder should probably be referred to as models vs types
580
+ */
581
+ // If this number is a decimal, make it just five decimal places
582
+ // to avoid exponents
583
+ const sanitize = (v) => Math.round(v * 100000) / 100000;
584
+ const floatRegex = /(-)?([\d]*\.?[\d])+/g;
585
+ const colorRegex = /(#[0-9a-f]{6}|#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2}(-?[\d\.]+%?)\s*[\,\/]?\s*[\d\.]*%?\))/gi;
586
+ const singleColorRegex = /^(#[0-9a-f]{3}|#(?:[0-9a-f]{2}){2,4}|(rgb|hsl)a?\((-?[\d\.]+%?[,\s]+){2}(-?[\d\.]+%?)\s*[\,\/]?\s*[\d\.]*%?\))$/i;
587
+ function isString$1(v) {
588
+ return typeof v === "string";
665
589
  }
666
- const hex = {
667
- test: isColorString('#'),
668
- parse: parseHex,
669
- transform: rgba.transform,
670
- };
671
590
 
672
- const color = {
673
- test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
674
- parse: (v) => {
675
- if (rgba.test(v)) {
676
- return rgba.parse(v);
677
- }
678
- else if (hsla.test(v)) {
679
- return hsla.parse(v);
680
- }
681
- else {
682
- return hex.parse(v);
683
- }
684
- },
685
- transform: (v) => {
686
- return isString$1(v)
687
- ? v
688
- : v.hasOwnProperty('red')
689
- ? rgba.transform(v)
690
- : hsla.transform(v);
691
- },
591
+ const createUnitType = (unit) => ({
592
+ test: (v) => isString$1(v) && v.endsWith(unit) && v.split(" ").length === 1,
593
+ parse: parseFloat,
594
+ transform: (v) => `${v}${unit}`,
595
+ });
596
+ const degrees = createUnitType("deg");
597
+ const percent = createUnitType("%");
598
+ const px = createUnitType("px");
599
+ const vh = createUnitType("vh");
600
+ const vw = createUnitType("vw");
601
+ const progressPercentage = {
602
+ ...percent,
603
+ parse: (v) => percent.parse(v) / 100,
604
+ transform: (v) => percent.transform(v * 100),
692
605
  };
693
606
 
694
- const colorToken = '${c}';
695
- const numberToken = '${n}';
696
- function test(v) {
697
- var _a, _b, _c, _d;
698
- return (isNaN(v) &&
699
- isString$1(v) &&
700
- ((_b = (_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) + ((_d = (_c = v.match(colorRegex)) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) > 0);
701
- }
702
- function analyse$1(v) {
703
- if (typeof v === 'number')
704
- v = `${v}`;
705
- const values = [];
706
- let numColors = 0;
707
- const colors = v.match(colorRegex);
708
- if (colors) {
709
- numColors = colors.length;
710
- v = v.replace(colorRegex, colorToken);
711
- values.push(...colors.map(color.parse));
712
- }
713
- const numbers = v.match(floatRegex);
714
- if (numbers) {
715
- v = v.replace(floatRegex, numberToken);
716
- values.push(...numbers.map(number.parse));
717
- }
718
- return { values, numColors, tokenised: v };
719
- }
720
- function parse(v) {
721
- return analyse$1(v).values;
722
- }
723
- function createTransformer(v) {
724
- const { values, numColors, tokenised } = analyse$1(v);
725
- const numValues = values.length;
726
- return (v) => {
727
- let output = tokenised;
728
- for (let i = 0; i < numValues; i++) {
729
- output = output.replace(i < numColors ? colorToken : numberToken, i < numColors ? color.transform(v[i]) : sanitize(v[i]));
730
- }
731
- return output;
732
- };
733
- }
734
- const convertNumbersToZero = (v) => typeof v === 'number' ? 0 : v;
735
- function getAnimatableNone$1(v) {
736
- const parsed = parse(v);
737
- const transformer = createTransformer(v);
738
- return transformer(parsed.map(convertNumbersToZero));
739
- }
740
- const complex = { test, parse, createTransformer, getAnimatableNone: getAnimatableNone$1 };
741
-
742
- const maxDefaults = new Set(['brightness', 'contrast', 'saturate', 'opacity']);
743
- function applyDefaultFilter(v) {
744
- let [name, value] = v.slice(0, -1).split('(');
745
- if (name === 'drop-shadow')
746
- return v;
747
- const [number] = value.match(floatRegex) || [];
748
- if (!number)
749
- return v;
750
- const unit = value.replace(number, '');
751
- let defaultValue = maxDefaults.has(name) ? 1 : 0;
752
- if (number !== value)
753
- defaultValue *= 100;
754
- return name + '(' + defaultValue + unit + ')';
755
- }
756
- const functionRegex = /([a-z-]*)\(.*?\)/g;
757
- const filter = Object.assign(Object.assign({}, complex), { getAnimatableNone: (v) => {
758
- const functions = v.match(functionRegex);
759
- return functions ? functions.map(applyDefaultFilter).join(' ') : v;
760
- } });
761
-
762
607
  const int = {
763
608
  ...number,
764
609
  transform: Math.round,
@@ -2154,6 +1999,175 @@
2154
1999
  return Array.isArray(ease) && typeof ease[0] !== "number";
2155
2000
  };
2156
2001
 
2002
+ /**
2003
+ * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
2004
+ * but false if a number or multiple colors
2005
+ */
2006
+ const isColorString = (type, testProp) => (v) => {
2007
+ return Boolean((isString$1(v) && singleColorRegex.test(v) && v.startsWith(type)) ||
2008
+ (testProp && Object.prototype.hasOwnProperty.call(v, testProp)));
2009
+ };
2010
+ const splitColor = (aName, bName, cName) => (v) => {
2011
+ if (!isString$1(v))
2012
+ return v;
2013
+ const [a, b, c, alpha] = v.match(floatRegex);
2014
+ return {
2015
+ [aName]: parseFloat(a),
2016
+ [bName]: parseFloat(b),
2017
+ [cName]: parseFloat(c),
2018
+ alpha: alpha !== undefined ? parseFloat(alpha) : 1,
2019
+ };
2020
+ };
2021
+
2022
+ const clampRgbUnit = (v) => clamp$1(0, 255, v);
2023
+ const rgbUnit = {
2024
+ ...number,
2025
+ transform: (v) => Math.round(clampRgbUnit(v)),
2026
+ };
2027
+ const rgba = {
2028
+ test: isColorString("rgb", "red"),
2029
+ parse: splitColor("red", "green", "blue"),
2030
+ transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
2031
+ rgbUnit.transform(red) +
2032
+ ", " +
2033
+ rgbUnit.transform(green) +
2034
+ ", " +
2035
+ rgbUnit.transform(blue) +
2036
+ ", " +
2037
+ sanitize(alpha.transform(alpha$1)) +
2038
+ ")",
2039
+ };
2040
+
2041
+ function parseHex(v) {
2042
+ let r = "";
2043
+ let g = "";
2044
+ let b = "";
2045
+ let a = "";
2046
+ // If we have 6 characters, ie #FF0000
2047
+ if (v.length > 5) {
2048
+ r = v.substring(1, 3);
2049
+ g = v.substring(3, 5);
2050
+ b = v.substring(5, 7);
2051
+ a = v.substring(7, 9);
2052
+ // Or we have 3 characters, ie #F00
2053
+ }
2054
+ else {
2055
+ r = v.substring(1, 2);
2056
+ g = v.substring(2, 3);
2057
+ b = v.substring(3, 4);
2058
+ a = v.substring(4, 5);
2059
+ r += r;
2060
+ g += g;
2061
+ b += b;
2062
+ a += a;
2063
+ }
2064
+ return {
2065
+ red: parseInt(r, 16),
2066
+ green: parseInt(g, 16),
2067
+ blue: parseInt(b, 16),
2068
+ alpha: a ? parseInt(a, 16) / 255 : 1,
2069
+ };
2070
+ }
2071
+ const hex = {
2072
+ test: isColorString("#"),
2073
+ parse: parseHex,
2074
+ transform: rgba.transform,
2075
+ };
2076
+
2077
+ const hsla = {
2078
+ test: isColorString("hsl", "hue"),
2079
+ parse: splitColor("hue", "saturation", "lightness"),
2080
+ transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
2081
+ return ("hsla(" +
2082
+ Math.round(hue) +
2083
+ ", " +
2084
+ percent.transform(sanitize(saturation)) +
2085
+ ", " +
2086
+ percent.transform(sanitize(lightness)) +
2087
+ ", " +
2088
+ sanitize(alpha.transform(alpha$1)) +
2089
+ ")");
2090
+ },
2091
+ };
2092
+
2093
+ const color = {
2094
+ test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
2095
+ parse: (v) => {
2096
+ if (rgba.test(v)) {
2097
+ return rgba.parse(v);
2098
+ }
2099
+ else if (hsla.test(v)) {
2100
+ return hsla.parse(v);
2101
+ }
2102
+ else {
2103
+ return hex.parse(v);
2104
+ }
2105
+ },
2106
+ transform: (v) => {
2107
+ return isString$1(v)
2108
+ ? v
2109
+ : v.hasOwnProperty("red")
2110
+ ? rgba.transform(v)
2111
+ : hsla.transform(v);
2112
+ },
2113
+ };
2114
+
2115
+ const colorToken = "${c}";
2116
+ const numberToken = "${n}";
2117
+ function test(v) {
2118
+ var _a, _b, _c, _d;
2119
+ return (isNaN(v) &&
2120
+ isString$1(v) &&
2121
+ ((_b = (_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) +
2122
+ ((_d = (_c = v.match(colorRegex)) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0) >
2123
+ 0);
2124
+ }
2125
+ function analyseComplexValue(v) {
2126
+ if (typeof v === "number")
2127
+ v = `${v}`;
2128
+ const values = [];
2129
+ let numColors = 0;
2130
+ let numNumbers = 0;
2131
+ const colors = v.match(colorRegex);
2132
+ if (colors) {
2133
+ numColors = colors.length;
2134
+ // Strip colors from input so they're not picked up by number regex.
2135
+ // There's a better way to combine these regex searches, but its beyond my regex skills
2136
+ v = v.replace(colorRegex, colorToken);
2137
+ values.push(...colors.map(color.parse));
2138
+ }
2139
+ const numbers = v.match(floatRegex);
2140
+ if (numbers) {
2141
+ numNumbers = numbers.length;
2142
+ v = v.replace(floatRegex, numberToken);
2143
+ values.push(...numbers.map(number.parse));
2144
+ }
2145
+ return { values, numColors, numNumbers, tokenised: v };
2146
+ }
2147
+ function parse(v) {
2148
+ return analyseComplexValue(v).values;
2149
+ }
2150
+ function createTransformer(source) {
2151
+ const { values, numColors, tokenised } = analyseComplexValue(source);
2152
+ const numValues = values.length;
2153
+ return (v) => {
2154
+ let output = tokenised;
2155
+ for (let i = 0; i < numValues; i++) {
2156
+ output = output.replace(i < numColors ? colorToken : numberToken, i < numColors
2157
+ ? color.transform(v[i])
2158
+ : sanitize(v[i]));
2159
+ }
2160
+ return output;
2161
+ };
2162
+ }
2163
+ const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
2164
+ function getAnimatableNone$1(v) {
2165
+ const parsed = parse(v);
2166
+ const transformer = createTransformer(v);
2167
+ return transformer(parsed.map(convertNumbersToZero));
2168
+ }
2169
+ const complex = { test, parse, createTransformer, getAnimatableNone: getAnimatableNone$1 };
2170
+
2157
2171
  /**
2158
2172
  * Check if a value is animatable. Examples:
2159
2173
  *
@@ -2231,6 +2245,32 @@
2231
2245
  return { to, ...transitionFactory(to) };
2232
2246
  };
2233
2247
 
2248
+ /**
2249
+ * Properties that should default to 1 or 100%
2250
+ */
2251
+ const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
2252
+ function applyDefaultFilter(v) {
2253
+ const [name, value] = v.slice(0, -1).split("(");
2254
+ if (name === "drop-shadow")
2255
+ return v;
2256
+ const [number] = value.match(floatRegex) || [];
2257
+ if (!number)
2258
+ return v;
2259
+ const unit = value.replace(number, "");
2260
+ let defaultValue = maxDefaults.has(name) ? 1 : 0;
2261
+ if (number !== value)
2262
+ defaultValue *= 100;
2263
+ return name + "(" + defaultValue + unit + ")";
2264
+ }
2265
+ const functionRegex = /([a-z-]*)\(.*?\)/g;
2266
+ const filter = {
2267
+ ...complex,
2268
+ getAnimatableNone: (v) => {
2269
+ const functions = v.match(functionRegex);
2270
+ return functions ? functions.map(applyDefaultFilter).join(" ") : v;
2271
+ },
2272
+ };
2273
+
2234
2274
  /**
2235
2275
  * A map of default value types for common values
2236
2276
  */
@@ -2269,6 +2309,9 @@
2269
2309
  current: false,
2270
2310
  };
2271
2311
 
2312
+ /*
2313
+ Detect and load appropriate clock setting for the execution environment
2314
+ */
2272
2315
  const defaultTimestep = (1 / 60) * 1000;
2273
2316
  const getCurrentTime = typeof performance !== "undefined"
2274
2317
  ? () => performance.now()
@@ -2278,39 +2321,71 @@
2278
2321
  : (callback) => setTimeout(() => callback(getCurrentTime()), defaultTimestep);
2279
2322
 
2280
2323
  function createRenderStep(runNextFrame) {
2324
+ /**
2325
+ * We create and reuse two arrays, one to queue jobs for the current frame
2326
+ * and one for the next. We reuse to avoid triggering GC after x frames.
2327
+ */
2281
2328
  let toRun = [];
2282
2329
  let toRunNextFrame = [];
2330
+ /**
2331
+ *
2332
+ */
2283
2333
  let numToRun = 0;
2334
+ /**
2335
+ * Track whether we're currently processing jobs in this step. This way
2336
+ * we can decide whether to schedule new jobs for this frame or next.
2337
+ */
2284
2338
  let isProcessing = false;
2285
2339
  let flushNextFrame = false;
2340
+ /**
2341
+ * A set of processes which were marked keepAlive when scheduled.
2342
+ */
2286
2343
  const toKeepAlive = new WeakSet();
2287
2344
  const step = {
2345
+ /**
2346
+ * Schedule a process to run on the next frame.
2347
+ */
2288
2348
  schedule: (callback, keepAlive = false, immediate = false) => {
2289
2349
  const addToCurrentFrame = immediate && isProcessing;
2290
2350
  const buffer = addToCurrentFrame ? toRun : toRunNextFrame;
2291
2351
  if (keepAlive)
2292
2352
  toKeepAlive.add(callback);
2353
+ // If the buffer doesn't already contain this callback, add it
2293
2354
  if (buffer.indexOf(callback) === -1) {
2294
2355
  buffer.push(callback);
2356
+ // If we're adding it to the currently running buffer, update its measured size
2295
2357
  if (addToCurrentFrame && isProcessing)
2296
2358
  numToRun = toRun.length;
2297
2359
  }
2298
2360
  return callback;
2299
2361
  },
2362
+ /**
2363
+ * Cancel the provided callback from running on the next frame.
2364
+ */
2300
2365
  cancel: (callback) => {
2301
2366
  const index = toRunNextFrame.indexOf(callback);
2302
2367
  if (index !== -1)
2303
2368
  toRunNextFrame.splice(index, 1);
2304
2369
  toKeepAlive.delete(callback);
2305
2370
  },
2371
+ /**
2372
+ * Execute all schedule callbacks.
2373
+ */
2306
2374
  process: (frameData) => {
2375
+ /**
2376
+ * If we're already processing we've probably been triggered by a flushSync
2377
+ * inside an existing process. Instead of executing, mark flushNextFrame
2378
+ * as true and ensure we flush the following frame at the end of this one.
2379
+ */
2307
2380
  if (isProcessing) {
2308
2381
  flushNextFrame = true;
2309
2382
  return;
2310
2383
  }
2311
2384
  isProcessing = true;
2312
2385
  [toRun, toRunNextFrame] = [toRunNextFrame, toRun];
2386
+ // Clear the next frame list
2313
2387
  toRunNextFrame.length = 0;
2388
+ // Execute this frame
2314
2389
  numToRun = toRun.length;
2315
2390
  if (numToRun) {
2316
2391
  for (let i = 0; i < numToRun; i++) {
@@ -2332,14 +2407,15 @@
2332
2407
  return step;
2333
2408
  }
2334
2409
 
2410
+ const frameData = {
2411
+ delta: 0,
2412
+ timestamp: 0,
2413
+ };
2414
+
2335
2415
  const maxElapsed$1 = 40;
2336
2416
  let useDefaultElapsed = true;
2337
2417
  let runNextFrame = false;
2338
2418
  let isProcessing = false;
2339
- const frame = {
2340
- delta: 0,
2341
- timestamp: 0,
2342
- };
2343
2419
  const stepsOrder = [
2344
2420
  "read",
2345
2421
  "update",
@@ -2365,16 +2441,16 @@
2365
2441
  return acc;
2366
2442
  }, {});
2367
2443
  const flushSync = stepsOrder.reduce((acc, key) => {
2368
- acc[key] = () => steps[key].process(frame);
2444
+ acc[key] = () => steps[key].process(frameData);
2369
2445
  return acc;
2370
2446
  }, {});
2371
- const processStep = (stepId) => steps[stepId].process(frame);
2447
+ const processStep = (stepId) => steps[stepId].process(frameData);
2372
2448
  const processFrame = (timestamp) => {
2373
2449
  runNextFrame = false;
2374
- frame.delta = useDefaultElapsed
2450
+ frameData.delta = useDefaultElapsed
2375
2451
  ? defaultTimestep
2376
- : Math.max(Math.min(timestamp - frame.timestamp, maxElapsed$1), 1);
2377
- frame.timestamp = timestamp;
2452
+ : Math.max(Math.min(timestamp - frameData.timestamp, maxElapsed$1), 1);
2453
+ frameData.timestamp = timestamp;
2378
2454
  isProcessing = true;
2379
2455
  stepsOrder.forEach(processStep);
2380
2456
  isProcessing = false;
@@ -2389,7 +2465,6 @@
2389
2465
  if (!isProcessing)
2390
2466
  onNextFrame(processFrame);
2391
2467
  };
2392
- const getFrameData = () => frame;
2393
2468
 
2394
2469
  function delay(callback, timeout) {
2395
2470
  const start = performance.now();
@@ -2404,8 +2479,6 @@
2404
2479
  return () => cancelSync.read(checkElapsed);
2405
2480
  }
2406
2481
 
2407
- const clamp$1 = (min, max, v) => Math.min(Math.max(v, min), max);
2408
-
2409
2482
  /*
2410
2483
  Value in range from progress
2411
2484
 
@@ -2484,6 +2557,7 @@
2484
2557
  invariant(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);
2485
2558
  let model = type.parse(color);
2486
2559
  if (type === hsla) {
2560
+ // TODO Remove this cast - needed since Framer Motion's stricter typing
2487
2561
  model = hslaToRgba(model);
2488
2562
  }
2489
2563
  return model;
@@ -2538,34 +2612,14 @@
2538
2612
  return output;
2539
2613
  };
2540
2614
  };
2541
- /**
2542
- * TODO: Combine with function within complex when style-value-types moved inside Framer Motion
2543
- */
2544
- function analyse(value) {
2545
- const parsed = complex.parse(value);
2546
- const numValues = parsed.length;
2547
- let numNumbers = 0;
2548
- let numColors = 0;
2549
- for (let i = 0; i < numValues; i++) {
2550
- // Parsed complex values return with colors first, so if we've seen any number
2551
- // we're already past that part of the array and don't need to continue running typeof
2552
- if (numNumbers || typeof parsed[i] === "number") {
2553
- numNumbers++;
2554
- }
2555
- else {
2556
- numColors++;
2557
- }
2558
- }
2559
- return { parsed, numNumbers, numColors };
2560
- }
2561
2615
  const mixComplex = (origin, target) => {
2562
2616
  const template = complex.createTransformer(target);
2563
- const originStats = analyse(origin);
2564
- const targetStats = analyse(target);
2617
+ const originStats = analyseComplexValue(origin);
2618
+ const targetStats = analyseComplexValue(target);
2565
2619
  const canInterpolate = originStats.numColors === targetStats.numColors &&
2566
2620
  originStats.numNumbers >= targetStats.numNumbers;
2567
2621
  if (canInterpolate) {
2568
- return pipe(mixArray(originStats.parsed, targetStats.parsed), template);
2622
+ return pipe(mixArray(originStats.values, targetStats.values), template);
2569
2623
  }
2570
2624
  else {
2571
2625
  warning(true, `Complex values '${origin}' and '${target}' too different to mix. Ensure all colors are of the same type, and that each contains the same quantity of number and color values. Falling back to instant transition.`);
@@ -3134,7 +3188,7 @@
3134
3188
  const checkBoundary = (v) => {
3135
3189
  prev = current;
3136
3190
  current = v;
3137
- velocity = velocityPerSecond$1(v - prev, getFrameData().delta);
3191
+ velocity = velocityPerSecond$1(v - prev, frameData.delta);
3138
3192
  if ((heading === 1 && v > boundary) ||
3139
3193
  (heading === -1 && v < boundary)) {
3140
3194
  startSpring({ from: v, to: boundary, velocity });
@@ -3425,7 +3479,7 @@
3425
3479
  * This will be replaced by the build step with the latest version number.
3426
3480
  * When MotionValues are provided to motion components, warn if versions are mixed.
3427
3481
  */
3428
- this.version = "7.7.0";
3482
+ this.version = "7.7.1";
3429
3483
  /**
3430
3484
  * Duration, in milliseconds, since last updating frame.
3431
3485
  *
@@ -3468,7 +3522,7 @@
3468
3522
  this.prev = this.current;
3469
3523
  this.current = v;
3470
3524
  // Update timestamp
3471
- const { delta, timestamp } = getFrameData();
3525
+ const { delta, timestamp } = frameData;
3472
3526
  if (this.lastUpdated !== timestamp) {
3473
3527
  this.timeDelta = delta;
3474
3528
  this.lastUpdated = timestamp;
@@ -4395,7 +4449,7 @@
4395
4449
  if (!isPanStarted && !isDistancePastThreshold)
4396
4450
  return;
4397
4451
  const { point } = info;
4398
- const { timestamp } = getFrameData();
4452
+ const { timestamp } = frameData;
4399
4453
  this.history.push({ ...point, timestamp });
4400
4454
  const { onStart, onMove } = this.handlers;
4401
4455
  if (!isPanStarted) {
@@ -4432,7 +4486,7 @@
4432
4486
  const info = extractEventInfo(event);
4433
4487
  const initialInfo = transformPoint(info, this.transformPagePoint);
4434
4488
  const { point } = initialInfo;
4435
- const { timestamp } = getFrameData();
4489
+ const { timestamp } = frameData;
4436
4490
  this.history = [{ ...point, timestamp }];
4437
4491
  const { onSessionStart } = handlers;
4438
4492
  onSessionStart &&
@@ -5710,7 +5764,7 @@
5710
5764
  * and warn against mismatches.
5711
5765
  */
5712
5766
  {
5713
- warnOnce(nextValue.version === "7.7.0", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.7.0 may not work as expected.`);
5767
+ warnOnce(nextValue.version === "7.7.1", `Attempting to mix Framer Motion versions ${nextValue.version} with 7.7.1 may not work as expected.`);
5714
5768
  }
5715
5769
  }
5716
5770
  else if (isMotionValue(prevValue)) {