motion 11.16.3 → 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 (29) hide show
  1. package/dist/cjs/index.js +664 -663
  2. package/dist/cjs/mini.js +1 -1
  3. package/dist/cjs/react-client.js +531 -529
  4. package/dist/cjs/react-m.js +6 -6
  5. package/dist/cjs/react-mini.js +1 -1
  6. package/dist/es/framer-motion/dist/es/animation/interfaces/visual-element-target.mjs +2 -2
  7. package/dist/es/framer-motion/dist/es/animation/optimized-appear/store-id.mjs +1 -1
  8. package/dist/es/framer-motion/dist/es/animation/utils/default-transitions.mjs +1 -1
  9. package/dist/es/framer-motion/dist/es/motion/utils/is-forced-motion-value.mjs +1 -1
  10. package/dist/es/framer-motion/dist/es/render/VisualElement.mjs +12 -12
  11. package/dist/es/framer-motion/dist/es/render/dom/DOMKeyframesResolver.mjs +4 -3
  12. package/dist/es/framer-motion/dist/es/render/dom/scroll/offsets/index.mjs +6 -5
  13. package/dist/es/framer-motion/dist/es/render/dom/utils/unit-conversion.mjs +2 -14
  14. package/dist/es/framer-motion/dist/es/render/html/HTMLVisualElement.mjs +6 -6
  15. package/dist/es/framer-motion/dist/es/render/html/utils/build-styles.mjs +2 -2
  16. package/dist/es/framer-motion/dist/es/render/html/utils/build-transform.mjs +1 -1
  17. package/dist/es/framer-motion/dist/es/render/html/utils/keys-position.mjs +13 -0
  18. package/dist/es/framer-motion/dist/es/render/svg/SVGVisualElement.mjs +6 -6
  19. package/dist/es/framer-motion/dist/es/render/svg/utils/scrape-motion-values.mjs +1 -1
  20. package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
  21. package/dist/es/framer-motion/dist/es/utils/interpolate.mjs +4 -1
  22. package/dist/es/framer-motion/dist/es/value/index.mjs +1 -1
  23. package/dist/es/framer-motion/dist/es/value/use-will-change/get-will-change-name.mjs +1 -1
  24. package/dist/es/motion-dom/dist/es/animation/controls/BaseGroup.mjs +1 -1
  25. package/dist/es/motion-dom/dist/es/gestures/press/utils/is-keyboard-accessible.mjs +2 -1
  26. package/dist/motion.dev.js +664 -663
  27. package/dist/motion.js +1 -1
  28. package/package.json +3 -3
  29. /package/dist/es/framer-motion/dist/es/render/html/utils/{transform.mjs → keys-transform.mjs} +0 -0
@@ -166,7 +166,7 @@ class BaseGroupPlaybackControls {
166
166
  if (supportsScrollTimeline() && animation.attachTimeline) {
167
167
  return animation.attachTimeline(timeline);
168
168
  }
169
- else {
169
+ else if (typeof fallback === "function") {
170
170
  return fallback(animation);
171
171
  }
172
172
  });
@@ -461,7 +461,8 @@ const focusableElements = new Set([
461
461
  "A",
462
462
  ]);
463
463
  function isElementKeyboardAccessible(element) {
464
- return focusableElements.has(element.tagName) || element.tabIndex !== -1;
464
+ return (focusableElements.has(element.tagName) ||
465
+ element.tabIndex !== -1);
465
466
  }
466
467
 
467
468
  const isPressing = new WeakSet();
@@ -620,6 +621,16 @@ const transformPropOrder = [
620
621
  */
621
622
  const transformProps = new Set(transformPropOrder);
622
623
 
624
+ const positionalKeys = new Set([
625
+ "width",
626
+ "height",
627
+ "top",
628
+ "left",
629
+ "right",
630
+ "bottom",
631
+ ...transformPropOrder,
632
+ ]);
633
+
623
634
  const isCustomValue = (v) => {
624
635
  return Boolean(v && typeof v === "object" && v.mix && v.toValue);
625
636
  };
@@ -904,7 +915,7 @@ class MotionValue {
904
915
  * This will be replaced by the build step with the latest version number.
905
916
  * When MotionValues are provided to motion components, warn if versions are mixed.
906
917
  */
907
- this.version = "11.16.3";
918
+ this.version = "11.16.6";
908
919
  /**
909
920
  * Tracks whether this value can output a velocity. Currently this is only true
910
921
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -1317,62 +1328,6 @@ function isNone(value) {
1317
1328
  }
1318
1329
  }
1319
1330
 
1320
- /**
1321
- * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
1322
- */
1323
- const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
1324
-
1325
- const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
1326
- const isCSSVariableName =
1327
- /*@__PURE__*/ checkStringStartsWith("--");
1328
- const startsAsVariableToken =
1329
- /*@__PURE__*/ checkStringStartsWith("var(--");
1330
- const isCSSVariableToken = (value) => {
1331
- const startsWithToken = startsAsVariableToken(value);
1332
- if (!startsWithToken)
1333
- return false;
1334
- // Ensure any comments are stripped from the value as this can harm performance of the regex.
1335
- return singleCssVariableRegex.test(value.split("/*")[0].trim());
1336
- };
1337
- const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
1338
-
1339
- /**
1340
- * Parse Framer's special CSS variable format into a CSS token and a fallback.
1341
- *
1342
- * ```
1343
- * `var(--foo, #fff)` => [`--foo`, '#fff']
1344
- * ```
1345
- *
1346
- * @param current
1347
- */
1348
- const splitCSSVariableRegex =
1349
- // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
1350
- /^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
1351
- function parseCSSVariable(current) {
1352
- const match = splitCSSVariableRegex.exec(current);
1353
- if (!match)
1354
- return [,];
1355
- const [, token1, token2, fallback] = match;
1356
- return [`--${token1 !== null && token1 !== void 0 ? token1 : token2}`, fallback];
1357
- }
1358
- const maxDepth = 4;
1359
- function getVariableValue(current, element, depth = 1) {
1360
- invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
1361
- const [token, fallback] = parseCSSVariable(current);
1362
- // No CSS variable detected
1363
- if (!token)
1364
- return;
1365
- // Attempt to read this CSS variable off the element
1366
- const resolved = window.getComputedStyle(element).getPropertyValue(token);
1367
- if (resolved) {
1368
- const trimmed = resolved.trim();
1369
- return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
1370
- }
1371
- return isCSSVariableToken(fallback)
1372
- ? getVariableValue(fallback, element, depth + 1)
1373
- : fallback;
1374
- }
1375
-
1376
1331
  const clamp = (min, max, v) => {
1377
1332
  if (v > max)
1378
1333
  return max;
@@ -1395,6 +1350,97 @@ const scale = {
1395
1350
  default: 1,
1396
1351
  };
1397
1352
 
1353
+ // If this number is a decimal, make it just five decimal places
1354
+ // to avoid exponents
1355
+ const sanitize = (v) => Math.round(v * 100000) / 100000;
1356
+
1357
+ const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
1358
+
1359
+ function isNullish(v) {
1360
+ return v == null;
1361
+ }
1362
+
1363
+ const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
1364
+
1365
+ /**
1366
+ * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
1367
+ * but false if a number or multiple colors
1368
+ */
1369
+ const isColorString = (type, testProp) => (v) => {
1370
+ return Boolean((typeof v === "string" &&
1371
+ singleColorRegex.test(v) &&
1372
+ v.startsWith(type)) ||
1373
+ (testProp &&
1374
+ !isNullish(v) &&
1375
+ Object.prototype.hasOwnProperty.call(v, testProp)));
1376
+ };
1377
+ const splitColor = (aName, bName, cName) => (v) => {
1378
+ if (typeof v !== "string")
1379
+ return v;
1380
+ const [a, b, c, alpha] = v.match(floatRegex);
1381
+ return {
1382
+ [aName]: parseFloat(a),
1383
+ [bName]: parseFloat(b),
1384
+ [cName]: parseFloat(c),
1385
+ alpha: alpha !== undefined ? parseFloat(alpha) : 1,
1386
+ };
1387
+ };
1388
+
1389
+ const clampRgbUnit = (v) => clamp(0, 255, v);
1390
+ const rgbUnit = {
1391
+ ...number,
1392
+ transform: (v) => Math.round(clampRgbUnit(v)),
1393
+ };
1394
+ const rgba = {
1395
+ test: /*@__PURE__*/ isColorString("rgb", "red"),
1396
+ parse: /*@__PURE__*/ splitColor("red", "green", "blue"),
1397
+ transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
1398
+ rgbUnit.transform(red) +
1399
+ ", " +
1400
+ rgbUnit.transform(green) +
1401
+ ", " +
1402
+ rgbUnit.transform(blue) +
1403
+ ", " +
1404
+ sanitize(alpha.transform(alpha$1)) +
1405
+ ")",
1406
+ };
1407
+
1408
+ function parseHex(v) {
1409
+ let r = "";
1410
+ let g = "";
1411
+ let b = "";
1412
+ let a = "";
1413
+ // If we have 6 characters, ie #FF0000
1414
+ if (v.length > 5) {
1415
+ r = v.substring(1, 3);
1416
+ g = v.substring(3, 5);
1417
+ b = v.substring(5, 7);
1418
+ a = v.substring(7, 9);
1419
+ // Or we have 3 characters, ie #F00
1420
+ }
1421
+ else {
1422
+ r = v.substring(1, 2);
1423
+ g = v.substring(2, 3);
1424
+ b = v.substring(3, 4);
1425
+ a = v.substring(4, 5);
1426
+ r += r;
1427
+ g += g;
1428
+ b += b;
1429
+ a += a;
1430
+ }
1431
+ return {
1432
+ red: parseInt(r, 16),
1433
+ green: parseInt(g, 16),
1434
+ blue: parseInt(b, 16),
1435
+ alpha: a ? parseInt(a, 16) / 255 : 1,
1436
+ };
1437
+ }
1438
+ const hex = {
1439
+ test: /*@__PURE__*/ isColorString("#"),
1440
+ parse: parseHex,
1441
+ transform: rgba.transform,
1442
+ };
1443
+
1398
1444
  const createUnitType = (unit) => ({
1399
1445
  test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
1400
1446
  parse: parseFloat,
@@ -1411,87 +1457,347 @@ const progressPercentage = {
1411
1457
  transform: (v) => percent.transform(v * 100),
1412
1458
  };
1413
1459
 
1414
- const positionalKeys = new Set([
1415
- "width",
1416
- "height",
1417
- "top",
1418
- "left",
1419
- "right",
1420
- "bottom",
1421
- "x",
1422
- "y",
1423
- "translateX",
1424
- "translateY",
1425
- ]);
1426
- const isNumOrPxType = (v) => v === number || v === px;
1427
- const getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(", ")[pos]);
1428
- const getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {
1429
- if (transform === "none" || !transform)
1430
- return 0;
1431
- const matrix3d = transform.match(/^matrix3d\((.+)\)$/u);
1432
- if (matrix3d) {
1433
- return getPosFromMatrix(matrix3d[1], pos3);
1434
- }
1435
- else {
1436
- const matrix = transform.match(/^matrix\((.+)\)$/u);
1437
- if (matrix) {
1438
- return getPosFromMatrix(matrix[1], pos2);
1460
+ const hsla = {
1461
+ test: /*@__PURE__*/ isColorString("hsl", "hue"),
1462
+ parse: /*@__PURE__*/ splitColor("hue", "saturation", "lightness"),
1463
+ transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
1464
+ return ("hsla(" +
1465
+ Math.round(hue) +
1466
+ ", " +
1467
+ percent.transform(sanitize(saturation)) +
1468
+ ", " +
1469
+ percent.transform(sanitize(lightness)) +
1470
+ ", " +
1471
+ sanitize(alpha.transform(alpha$1)) +
1472
+ ")");
1473
+ },
1474
+ };
1475
+
1476
+ const color = {
1477
+ test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
1478
+ parse: (v) => {
1479
+ if (rgba.test(v)) {
1480
+ return rgba.parse(v);
1439
1481
  }
1440
- else {
1441
- return 0;
1482
+ else if (hsla.test(v)) {
1483
+ return hsla.parse(v);
1442
1484
  }
1443
- }
1444
- };
1445
- const transformKeys = new Set(["x", "y", "z"]);
1446
- const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
1447
- function removeNonTranslationalTransform(visualElement) {
1448
- const removedTransforms = [];
1449
- nonTranslationalTransformKeys.forEach((key) => {
1450
- const value = visualElement.getValue(key);
1451
- if (value !== undefined) {
1452
- removedTransforms.push([key, value.get()]);
1453
- value.set(key.startsWith("scale") ? 1 : 0);
1485
+ else {
1486
+ return hex.parse(v);
1454
1487
  }
1455
- });
1456
- return removedTransforms;
1457
- }
1458
- const positionalValues = {
1459
- // Dimensions
1460
- width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
1461
- height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
1462
- top: (_bbox, { top }) => parseFloat(top),
1463
- left: (_bbox, { left }) => parseFloat(left),
1464
- bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
1465
- right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
1466
- // Transform
1467
- x: getTranslateFromMatrix(4, 13),
1468
- y: getTranslateFromMatrix(5, 14),
1488
+ },
1489
+ transform: (v) => {
1490
+ return typeof v === "string"
1491
+ ? v
1492
+ : v.hasOwnProperty("red")
1493
+ ? rgba.transform(v)
1494
+ : hsla.transform(v);
1495
+ },
1469
1496
  };
1470
- // Alias translate longform names
1471
- positionalValues.translateX = positionalValues.x;
1472
- positionalValues.translateY = positionalValues.y;
1473
1497
 
1474
- /**
1475
- * Tests a provided value against a ValueType
1476
- */
1477
- const testValueType = (v) => (type) => type.test(v);
1498
+ const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
1478
1499
 
1479
- /**
1480
- * ValueType for "auto"
1481
- */
1482
- const auto = {
1483
- test: (v) => v === "auto",
1484
- parse: (v) => v,
1500
+ function test(v) {
1501
+ var _a, _b;
1502
+ return (isNaN(v) &&
1503
+ typeof v === "string" &&
1504
+ (((_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) || 0) +
1505
+ (((_b = v.match(colorRegex)) === null || _b === void 0 ? void 0 : _b.length) || 0) >
1506
+ 0);
1507
+ }
1508
+ const NUMBER_TOKEN = "number";
1509
+ const COLOR_TOKEN = "color";
1510
+ const VAR_TOKEN = "var";
1511
+ const VAR_FUNCTION_TOKEN = "var(";
1512
+ const SPLIT_TOKEN = "${}";
1513
+ // this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`
1514
+ 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;
1515
+ function analyseComplexValue(value) {
1516
+ const originalValue = value.toString();
1517
+ const values = [];
1518
+ const indexes = {
1519
+ color: [],
1520
+ number: [],
1521
+ var: [],
1522
+ };
1523
+ const types = [];
1524
+ let i = 0;
1525
+ const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
1526
+ if (color.test(parsedValue)) {
1527
+ indexes.color.push(i);
1528
+ types.push(COLOR_TOKEN);
1529
+ values.push(color.parse(parsedValue));
1530
+ }
1531
+ else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
1532
+ indexes.var.push(i);
1533
+ types.push(VAR_TOKEN);
1534
+ values.push(parsedValue);
1535
+ }
1536
+ else {
1537
+ indexes.number.push(i);
1538
+ types.push(NUMBER_TOKEN);
1539
+ values.push(parseFloat(parsedValue));
1540
+ }
1541
+ ++i;
1542
+ return SPLIT_TOKEN;
1543
+ });
1544
+ const split = tokenised.split(SPLIT_TOKEN);
1545
+ return { values, split, indexes, types };
1546
+ }
1547
+ function parseComplexValue(v) {
1548
+ return analyseComplexValue(v).values;
1549
+ }
1550
+ function createTransformer(source) {
1551
+ const { split, types } = analyseComplexValue(source);
1552
+ const numSections = split.length;
1553
+ return (v) => {
1554
+ let output = "";
1555
+ for (let i = 0; i < numSections; i++) {
1556
+ output += split[i];
1557
+ if (v[i] !== undefined) {
1558
+ const type = types[i];
1559
+ if (type === NUMBER_TOKEN) {
1560
+ output += sanitize(v[i]);
1561
+ }
1562
+ else if (type === COLOR_TOKEN) {
1563
+ output += color.transform(v[i]);
1564
+ }
1565
+ else {
1566
+ output += v[i];
1567
+ }
1568
+ }
1569
+ }
1570
+ return output;
1571
+ };
1572
+ }
1573
+ const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
1574
+ function getAnimatableNone$1(v) {
1575
+ const parsed = parseComplexValue(v);
1576
+ const transformer = createTransformer(v);
1577
+ return transformer(parsed.map(convertNumbersToZero));
1578
+ }
1579
+ const complex = {
1580
+ test,
1581
+ parse: parseComplexValue,
1582
+ createTransformer,
1583
+ getAnimatableNone: getAnimatableNone$1,
1584
+ };
1585
+
1586
+ /**
1587
+ * Properties that should default to 1 or 100%
1588
+ */
1589
+ const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
1590
+ function applyDefaultFilter(v) {
1591
+ const [name, value] = v.slice(0, -1).split("(");
1592
+ if (name === "drop-shadow")
1593
+ return v;
1594
+ const [number] = value.match(floatRegex) || [];
1595
+ if (!number)
1596
+ return v;
1597
+ const unit = value.replace(number, "");
1598
+ let defaultValue = maxDefaults.has(name) ? 1 : 0;
1599
+ if (number !== value)
1600
+ defaultValue *= 100;
1601
+ return name + "(" + defaultValue + unit + ")";
1602
+ }
1603
+ const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
1604
+ const filter = {
1605
+ ...complex,
1606
+ getAnimatableNone: (v) => {
1607
+ const functions = v.match(functionRegex);
1608
+ return functions ? functions.map(applyDefaultFilter).join(" ") : v;
1609
+ },
1610
+ };
1611
+
1612
+ const browserNumberValueTypes = {
1613
+ // Border props
1614
+ borderWidth: px,
1615
+ borderTopWidth: px,
1616
+ borderRightWidth: px,
1617
+ borderBottomWidth: px,
1618
+ borderLeftWidth: px,
1619
+ borderRadius: px,
1620
+ radius: px,
1621
+ borderTopLeftRadius: px,
1622
+ borderTopRightRadius: px,
1623
+ borderBottomRightRadius: px,
1624
+ borderBottomLeftRadius: px,
1625
+ // Positioning props
1626
+ width: px,
1627
+ maxWidth: px,
1628
+ height: px,
1629
+ maxHeight: px,
1630
+ top: px,
1631
+ right: px,
1632
+ bottom: px,
1633
+ left: px,
1634
+ // Spacing props
1635
+ padding: px,
1636
+ paddingTop: px,
1637
+ paddingRight: px,
1638
+ paddingBottom: px,
1639
+ paddingLeft: px,
1640
+ margin: px,
1641
+ marginTop: px,
1642
+ marginRight: px,
1643
+ marginBottom: px,
1644
+ marginLeft: px,
1645
+ // Misc
1646
+ backgroundPositionX: px,
1647
+ backgroundPositionY: px,
1648
+ };
1649
+
1650
+ const transformValueTypes = {
1651
+ rotate: degrees,
1652
+ rotateX: degrees,
1653
+ rotateY: degrees,
1654
+ rotateZ: degrees,
1655
+ scale,
1656
+ scaleX: scale,
1657
+ scaleY: scale,
1658
+ scaleZ: scale,
1659
+ skew: degrees,
1660
+ skewX: degrees,
1661
+ skewY: degrees,
1662
+ distance: px,
1663
+ translateX: px,
1664
+ translateY: px,
1665
+ translateZ: px,
1666
+ x: px,
1667
+ y: px,
1668
+ z: px,
1669
+ perspective: px,
1670
+ transformPerspective: px,
1671
+ opacity: alpha,
1672
+ originX: progressPercentage,
1673
+ originY: progressPercentage,
1674
+ originZ: px,
1675
+ };
1676
+
1677
+ const int = {
1678
+ ...number,
1679
+ transform: Math.round,
1680
+ };
1681
+
1682
+ const numberValueTypes = {
1683
+ ...browserNumberValueTypes,
1684
+ ...transformValueTypes,
1685
+ zIndex: int,
1686
+ size: px,
1687
+ // SVG
1688
+ fillOpacity: alpha,
1689
+ strokeOpacity: alpha,
1690
+ numOctaves: int,
1691
+ };
1692
+
1693
+ /**
1694
+ * A map of default value types for common values
1695
+ */
1696
+ const defaultValueTypes = {
1697
+ ...numberValueTypes,
1698
+ // Color props
1699
+ color,
1700
+ backgroundColor: color,
1701
+ outlineColor: color,
1702
+ fill: color,
1703
+ stroke: color,
1704
+ // Border props
1705
+ borderColor: color,
1706
+ borderTopColor: color,
1707
+ borderRightColor: color,
1708
+ borderBottomColor: color,
1709
+ borderLeftColor: color,
1710
+ filter,
1711
+ WebkitFilter: filter,
1712
+ };
1713
+ /**
1714
+ * Gets the default ValueType for the provided value key
1715
+ */
1716
+ const getDefaultValueType = (key) => defaultValueTypes[key];
1717
+
1718
+ function getAnimatableNone(key, value) {
1719
+ let defaultValueType = getDefaultValueType(key);
1720
+ if (defaultValueType !== filter)
1721
+ defaultValueType = complex;
1722
+ // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
1723
+ return defaultValueType.getAnimatableNone
1724
+ ? defaultValueType.getAnimatableNone(value)
1725
+ : undefined;
1726
+ }
1727
+
1728
+ /**
1729
+ * If we encounter keyframes like "none" or "0" and we also have keyframes like
1730
+ * "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
1731
+ * the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
1732
+ * zero equivalents, i.e. "#fff0" or "0px 0px".
1733
+ */
1734
+ const invalidTemplates = new Set(["auto", "none", "0"]);
1735
+ function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
1736
+ let i = 0;
1737
+ let animatableTemplate = undefined;
1738
+ while (i < unresolvedKeyframes.length && !animatableTemplate) {
1739
+ const keyframe = unresolvedKeyframes[i];
1740
+ if (typeof keyframe === "string" &&
1741
+ !invalidTemplates.has(keyframe) &&
1742
+ analyseComplexValue(keyframe).values.length) {
1743
+ animatableTemplate = unresolvedKeyframes[i];
1744
+ }
1745
+ i++;
1746
+ }
1747
+ if (animatableTemplate && name) {
1748
+ for (const noneIndex of noneKeyframeIndexes) {
1749
+ unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
1750
+ }
1751
+ }
1752
+ }
1753
+
1754
+ const isNumOrPxType = (v) => v === number || v === px;
1755
+ const getPosFromMatrix = (matrix, pos) => parseFloat(matrix.split(", ")[pos]);
1756
+ const getTranslateFromMatrix = (pos2, pos3) => (_bbox, { transform }) => {
1757
+ if (transform === "none" || !transform)
1758
+ return 0;
1759
+ const matrix3d = transform.match(/^matrix3d\((.+)\)$/u);
1760
+ if (matrix3d) {
1761
+ return getPosFromMatrix(matrix3d[1], pos3);
1762
+ }
1763
+ else {
1764
+ const matrix = transform.match(/^matrix\((.+)\)$/u);
1765
+ if (matrix) {
1766
+ return getPosFromMatrix(matrix[1], pos2);
1767
+ }
1768
+ else {
1769
+ return 0;
1770
+ }
1771
+ }
1772
+ };
1773
+ const transformKeys = new Set(["x", "y", "z"]);
1774
+ const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
1775
+ function removeNonTranslationalTransform(visualElement) {
1776
+ const removedTransforms = [];
1777
+ nonTranslationalTransformKeys.forEach((key) => {
1778
+ const value = visualElement.getValue(key);
1779
+ if (value !== undefined) {
1780
+ removedTransforms.push([key, value.get()]);
1781
+ value.set(key.startsWith("scale") ? 1 : 0);
1782
+ }
1783
+ });
1784
+ return removedTransforms;
1785
+ }
1786
+ const positionalValues = {
1787
+ // Dimensions
1788
+ width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
1789
+ height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
1790
+ top: (_bbox, { top }) => parseFloat(top),
1791
+ left: (_bbox, { left }) => parseFloat(left),
1792
+ bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
1793
+ right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
1794
+ // Transform
1795
+ x: getTranslateFromMatrix(4, 13),
1796
+ y: getTranslateFromMatrix(5, 14),
1485
1797
  };
1486
-
1487
- /**
1488
- * A list of value types commonly used for dimensions
1489
- */
1490
- const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
1491
- /**
1492
- * Tests a dimensional value against the list of dimension ValueTypes
1493
- */
1494
- const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
1798
+ // Alias translate longform names
1799
+ positionalValues.translateX = positionalValues.x;
1800
+ positionalValues.translateY = positionalValues.y;
1495
1801
 
1496
1802
  const toResolve = new Set();
1497
1803
  let isScheduled = false;
@@ -1639,404 +1945,97 @@ class KeyframeResolver {
1639
1945
  complete() {
1640
1946
  this.isComplete = true;
1641
1947
  this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);
1642
- toResolve.delete(this);
1643
- }
1644
- cancel() {
1645
- if (!this.isComplete) {
1646
- this.isScheduled = false;
1647
- toResolve.delete(this);
1648
- }
1649
- }
1650
- resume() {
1651
- if (!this.isComplete)
1652
- this.scheduleResolve();
1653
- }
1654
- }
1655
-
1656
- // If this number is a decimal, make it just five decimal places
1657
- // to avoid exponents
1658
- const sanitize = (v) => Math.round(v * 100000) / 100000;
1659
-
1660
- const floatRegex = /-?(?:\d+(?:\.\d+)?|\.\d+)/gu;
1661
-
1662
- function isNullish(v) {
1663
- return v == null;
1664
- }
1665
-
1666
- const singleColorRegex = /^(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))$/iu;
1667
-
1668
- /**
1669
- * Returns true if the provided string is a color, ie rgba(0,0,0,0) or #000,
1670
- * but false if a number or multiple colors
1671
- */
1672
- const isColorString = (type, testProp) => (v) => {
1673
- return Boolean((typeof v === "string" &&
1674
- singleColorRegex.test(v) &&
1675
- v.startsWith(type)) ||
1676
- (testProp &&
1677
- !isNullish(v) &&
1678
- Object.prototype.hasOwnProperty.call(v, testProp)));
1679
- };
1680
- const splitColor = (aName, bName, cName) => (v) => {
1681
- if (typeof v !== "string")
1682
- return v;
1683
- const [a, b, c, alpha] = v.match(floatRegex);
1684
- return {
1685
- [aName]: parseFloat(a),
1686
- [bName]: parseFloat(b),
1687
- [cName]: parseFloat(c),
1688
- alpha: alpha !== undefined ? parseFloat(alpha) : 1,
1689
- };
1690
- };
1691
-
1692
- const clampRgbUnit = (v) => clamp(0, 255, v);
1693
- const rgbUnit = {
1694
- ...number,
1695
- transform: (v) => Math.round(clampRgbUnit(v)),
1696
- };
1697
- const rgba = {
1698
- test: /*@__PURE__*/ isColorString("rgb", "red"),
1699
- parse: /*@__PURE__*/ splitColor("red", "green", "blue"),
1700
- transform: ({ red, green, blue, alpha: alpha$1 = 1 }) => "rgba(" +
1701
- rgbUnit.transform(red) +
1702
- ", " +
1703
- rgbUnit.transform(green) +
1704
- ", " +
1705
- rgbUnit.transform(blue) +
1706
- ", " +
1707
- sanitize(alpha.transform(alpha$1)) +
1708
- ")",
1709
- };
1710
-
1711
- function parseHex(v) {
1712
- let r = "";
1713
- let g = "";
1714
- let b = "";
1715
- let a = "";
1716
- // If we have 6 characters, ie #FF0000
1717
- if (v.length > 5) {
1718
- r = v.substring(1, 3);
1719
- g = v.substring(3, 5);
1720
- b = v.substring(5, 7);
1721
- a = v.substring(7, 9);
1722
- // Or we have 3 characters, ie #F00
1723
- }
1724
- else {
1725
- r = v.substring(1, 2);
1726
- g = v.substring(2, 3);
1727
- b = v.substring(3, 4);
1728
- a = v.substring(4, 5);
1729
- r += r;
1730
- g += g;
1731
- b += b;
1732
- a += a;
1733
- }
1734
- return {
1735
- red: parseInt(r, 16),
1736
- green: parseInt(g, 16),
1737
- blue: parseInt(b, 16),
1738
- alpha: a ? parseInt(a, 16) / 255 : 1,
1739
- };
1740
- }
1741
- const hex = {
1742
- test: /*@__PURE__*/ isColorString("#"),
1743
- parse: parseHex,
1744
- transform: rgba.transform,
1745
- };
1746
-
1747
- const hsla = {
1748
- test: /*@__PURE__*/ isColorString("hsl", "hue"),
1749
- parse: /*@__PURE__*/ splitColor("hue", "saturation", "lightness"),
1750
- transform: ({ hue, saturation, lightness, alpha: alpha$1 = 1 }) => {
1751
- return ("hsla(" +
1752
- Math.round(hue) +
1753
- ", " +
1754
- percent.transform(sanitize(saturation)) +
1755
- ", " +
1756
- percent.transform(sanitize(lightness)) +
1757
- ", " +
1758
- sanitize(alpha.transform(alpha$1)) +
1759
- ")");
1760
- },
1761
- };
1762
-
1763
- const color = {
1764
- test: (v) => rgba.test(v) || hex.test(v) || hsla.test(v),
1765
- parse: (v) => {
1766
- if (rgba.test(v)) {
1767
- return rgba.parse(v);
1768
- }
1769
- else if (hsla.test(v)) {
1770
- return hsla.parse(v);
1771
- }
1772
- else {
1773
- return hex.parse(v);
1774
- }
1775
- },
1776
- transform: (v) => {
1777
- return typeof v === "string"
1778
- ? v
1779
- : v.hasOwnProperty("red")
1780
- ? rgba.transform(v)
1781
- : hsla.transform(v);
1782
- },
1783
- };
1784
-
1785
- const colorRegex = /(?:#[\da-f]{3,8}|(?:rgb|hsl)a?\((?:-?[\d.]+%?[,\s]+){2}-?[\d.]+%?\s*(?:[,/]\s*)?(?:\b\d+(?:\.\d+)?|\.\d+)?%?\))/giu;
1786
-
1787
- function test(v) {
1788
- var _a, _b;
1789
- return (isNaN(v) &&
1790
- typeof v === "string" &&
1791
- (((_a = v.match(floatRegex)) === null || _a === void 0 ? void 0 : _a.length) || 0) +
1792
- (((_b = v.match(colorRegex)) === null || _b === void 0 ? void 0 : _b.length) || 0) >
1793
- 0);
1794
- }
1795
- const NUMBER_TOKEN = "number";
1796
- const COLOR_TOKEN = "color";
1797
- const VAR_TOKEN = "var";
1798
- const VAR_FUNCTION_TOKEN = "var(";
1799
- const SPLIT_TOKEN = "${}";
1800
- // this regex consists of the `singleCssVariableRegex|rgbHSLValueRegex|digitRegex`
1801
- 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;
1802
- function analyseComplexValue(value) {
1803
- const originalValue = value.toString();
1804
- const values = [];
1805
- const indexes = {
1806
- color: [],
1807
- number: [],
1808
- var: [],
1809
- };
1810
- const types = [];
1811
- let i = 0;
1812
- const tokenised = originalValue.replace(complexRegex, (parsedValue) => {
1813
- if (color.test(parsedValue)) {
1814
- indexes.color.push(i);
1815
- types.push(COLOR_TOKEN);
1816
- values.push(color.parse(parsedValue));
1817
- }
1818
- else if (parsedValue.startsWith(VAR_FUNCTION_TOKEN)) {
1819
- indexes.var.push(i);
1820
- types.push(VAR_TOKEN);
1821
- values.push(parsedValue);
1822
- }
1823
- else {
1824
- indexes.number.push(i);
1825
- types.push(NUMBER_TOKEN);
1826
- values.push(parseFloat(parsedValue));
1827
- }
1828
- ++i;
1829
- return SPLIT_TOKEN;
1830
- });
1831
- const split = tokenised.split(SPLIT_TOKEN);
1832
- return { values, split, indexes, types };
1833
- }
1834
- function parseComplexValue(v) {
1835
- return analyseComplexValue(v).values;
1836
- }
1837
- function createTransformer(source) {
1838
- const { split, types } = analyseComplexValue(source);
1839
- const numSections = split.length;
1840
- return (v) => {
1841
- let output = "";
1842
- for (let i = 0; i < numSections; i++) {
1843
- output += split[i];
1844
- if (v[i] !== undefined) {
1845
- const type = types[i];
1846
- if (type === NUMBER_TOKEN) {
1847
- output += sanitize(v[i]);
1848
- }
1849
- else if (type === COLOR_TOKEN) {
1850
- output += color.transform(v[i]);
1851
- }
1852
- else {
1853
- output += v[i];
1854
- }
1855
- }
1856
- }
1857
- return output;
1858
- };
1859
- }
1860
- const convertNumbersToZero = (v) => typeof v === "number" ? 0 : v;
1861
- function getAnimatableNone$1(v) {
1862
- const parsed = parseComplexValue(v);
1863
- const transformer = createTransformer(v);
1864
- return transformer(parsed.map(convertNumbersToZero));
1948
+ toResolve.delete(this);
1949
+ }
1950
+ cancel() {
1951
+ if (!this.isComplete) {
1952
+ this.isScheduled = false;
1953
+ toResolve.delete(this);
1954
+ }
1955
+ }
1956
+ resume() {
1957
+ if (!this.isComplete)
1958
+ this.scheduleResolve();
1959
+ }
1865
1960
  }
1866
- const complex = {
1867
- test,
1868
- parse: parseComplexValue,
1869
- createTransformer,
1870
- getAnimatableNone: getAnimatableNone$1,
1871
- };
1872
1961
 
1873
1962
  /**
1874
- * Properties that should default to 1 or 100%
1963
+ * Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
1875
1964
  */
1876
- const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
1877
- function applyDefaultFilter(v) {
1878
- const [name, value] = v.slice(0, -1).split("(");
1879
- if (name === "drop-shadow")
1880
- return v;
1881
- const [number] = value.match(floatRegex) || [];
1882
- if (!number)
1883
- return v;
1884
- const unit = value.replace(number, "");
1885
- let defaultValue = maxDefaults.has(name) ? 1 : 0;
1886
- if (number !== value)
1887
- defaultValue *= 100;
1888
- return name + "(" + defaultValue + unit + ")";
1889
- }
1890
- const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
1891
- const filter = {
1892
- ...complex,
1893
- getAnimatableNone: (v) => {
1894
- const functions = v.match(functionRegex);
1895
- return functions ? functions.map(applyDefaultFilter).join(" ") : v;
1896
- },
1897
- };
1898
-
1899
- const browserNumberValueTypes = {
1900
- // Border props
1901
- borderWidth: px,
1902
- borderTopWidth: px,
1903
- borderRightWidth: px,
1904
- borderBottomWidth: px,
1905
- borderLeftWidth: px,
1906
- borderRadius: px,
1907
- radius: px,
1908
- borderTopLeftRadius: px,
1909
- borderTopRightRadius: px,
1910
- borderBottomRightRadius: px,
1911
- borderBottomLeftRadius: px,
1912
- // Positioning props
1913
- width: px,
1914
- maxWidth: px,
1915
- height: px,
1916
- maxHeight: px,
1917
- top: px,
1918
- right: px,
1919
- bottom: px,
1920
- left: px,
1921
- // Spacing props
1922
- padding: px,
1923
- paddingTop: px,
1924
- paddingRight: px,
1925
- paddingBottom: px,
1926
- paddingLeft: px,
1927
- margin: px,
1928
- marginTop: px,
1929
- marginRight: px,
1930
- marginBottom: px,
1931
- marginLeft: px,
1932
- // Misc
1933
- backgroundPositionX: px,
1934
- backgroundPositionY: px,
1935
- };
1965
+ const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
1936
1966
 
1937
- const transformValueTypes = {
1938
- rotate: degrees,
1939
- rotateX: degrees,
1940
- rotateY: degrees,
1941
- rotateZ: degrees,
1942
- scale,
1943
- scaleX: scale,
1944
- scaleY: scale,
1945
- scaleZ: scale,
1946
- skew: degrees,
1947
- skewX: degrees,
1948
- skewY: degrees,
1949
- distance: px,
1950
- translateX: px,
1951
- translateY: px,
1952
- translateZ: px,
1953
- x: px,
1954
- y: px,
1955
- z: px,
1956
- perspective: px,
1957
- transformPerspective: px,
1958
- opacity: alpha,
1959
- originX: progressPercentage,
1960
- originY: progressPercentage,
1961
- originZ: px,
1967
+ const checkStringStartsWith = (token) => (key) => typeof key === "string" && key.startsWith(token);
1968
+ const isCSSVariableName =
1969
+ /*@__PURE__*/ checkStringStartsWith("--");
1970
+ const startsAsVariableToken =
1971
+ /*@__PURE__*/ checkStringStartsWith("var(--");
1972
+ const isCSSVariableToken = (value) => {
1973
+ const startsWithToken = startsAsVariableToken(value);
1974
+ if (!startsWithToken)
1975
+ return false;
1976
+ // Ensure any comments are stripped from the value as this can harm performance of the regex.
1977
+ return singleCssVariableRegex.test(value.split("/*")[0].trim());
1962
1978
  };
1979
+ const singleCssVariableRegex = /var\(--(?:[\w-]+\s*|[\w-]+\s*,(?:\s*[^)(\s]|\s*\((?:[^)(]|\([^)(]*\))*\))+\s*)\)$/iu;
1963
1980
 
1964
- const int = {
1965
- ...number,
1966
- transform: Math.round,
1967
- };
1981
+ /**
1982
+ * Parse Framer's special CSS variable format into a CSS token and a fallback.
1983
+ *
1984
+ * ```
1985
+ * `var(--foo, #fff)` => [`--foo`, '#fff']
1986
+ * ```
1987
+ *
1988
+ * @param current
1989
+ */
1990
+ const splitCSSVariableRegex =
1991
+ // eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
1992
+ /^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
1993
+ function parseCSSVariable(current) {
1994
+ const match = splitCSSVariableRegex.exec(current);
1995
+ if (!match)
1996
+ return [,];
1997
+ const [, token1, token2, fallback] = match;
1998
+ return [`--${token1 !== null && token1 !== void 0 ? token1 : token2}`, fallback];
1999
+ }
2000
+ const maxDepth = 4;
2001
+ function getVariableValue(current, element, depth = 1) {
2002
+ invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
2003
+ const [token, fallback] = parseCSSVariable(current);
2004
+ // No CSS variable detected
2005
+ if (!token)
2006
+ return;
2007
+ // Attempt to read this CSS variable off the element
2008
+ const resolved = window.getComputedStyle(element).getPropertyValue(token);
2009
+ if (resolved) {
2010
+ const trimmed = resolved.trim();
2011
+ return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
2012
+ }
2013
+ return isCSSVariableToken(fallback)
2014
+ ? getVariableValue(fallback, element, depth + 1)
2015
+ : fallback;
2016
+ }
1968
2017
 
1969
- const numberValueTypes = {
1970
- ...browserNumberValueTypes,
1971
- ...transformValueTypes,
1972
- zIndex: int,
1973
- size: px,
1974
- // SVG
1975
- fillOpacity: alpha,
1976
- strokeOpacity: alpha,
1977
- numOctaves: int,
1978
- };
2018
+ /**
2019
+ * Tests a provided value against a ValueType
2020
+ */
2021
+ const testValueType = (v) => (type) => type.test(v);
1979
2022
 
1980
2023
  /**
1981
- * A map of default value types for common values
2024
+ * ValueType for "auto"
1982
2025
  */
1983
- const defaultValueTypes = {
1984
- ...numberValueTypes,
1985
- // Color props
1986
- color,
1987
- backgroundColor: color,
1988
- outlineColor: color,
1989
- fill: color,
1990
- stroke: color,
1991
- // Border props
1992
- borderColor: color,
1993
- borderTopColor: color,
1994
- borderRightColor: color,
1995
- borderBottomColor: color,
1996
- borderLeftColor: color,
1997
- filter,
1998
- WebkitFilter: filter,
2026
+ const auto = {
2027
+ test: (v) => v === "auto",
2028
+ parse: (v) => v,
1999
2029
  };
2030
+
2000
2031
  /**
2001
- * Gets the default ValueType for the provided value key
2032
+ * A list of value types commonly used for dimensions
2002
2033
  */
2003
- const getDefaultValueType = (key) => defaultValueTypes[key];
2004
-
2005
- function getAnimatableNone(key, value) {
2006
- let defaultValueType = getDefaultValueType(key);
2007
- if (defaultValueType !== filter)
2008
- defaultValueType = complex;
2009
- // If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
2010
- return defaultValueType.getAnimatableNone
2011
- ? defaultValueType.getAnimatableNone(value)
2012
- : undefined;
2013
- }
2014
-
2034
+ const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
2015
2035
  /**
2016
- * If we encounter keyframes like "none" or "0" and we also have keyframes like
2017
- * "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
2018
- * the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
2019
- * zero equivalents, i.e. "#fff0" or "0px 0px".
2036
+ * Tests a dimensional value against the list of dimension ValueTypes
2020
2037
  */
2021
- const invalidTemplates = new Set(["auto", "none", "0"]);
2022
- function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
2023
- let i = 0;
2024
- let animatableTemplate = undefined;
2025
- while (i < unresolvedKeyframes.length && !animatableTemplate) {
2026
- const keyframe = unresolvedKeyframes[i];
2027
- if (typeof keyframe === "string" &&
2028
- !invalidTemplates.has(keyframe) &&
2029
- analyseComplexValue(keyframe).values.length) {
2030
- animatableTemplate = unresolvedKeyframes[i];
2031
- }
2032
- i++;
2033
- }
2034
- if (animatableTemplate && name) {
2035
- for (const noneIndex of noneKeyframeIndexes) {
2036
- unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
2037
- }
2038
- }
2039
- }
2038
+ const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
2040
2039
 
2041
2040
  class DOMKeyframesResolver extends KeyframeResolver {
2042
2041
  constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
@@ -3001,8 +3000,9 @@ function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {})
3001
3000
  */
3002
3001
  if (inputLength === 1)
3003
3002
  return () => output[0];
3004
- if (inputLength === 2 && input[0] === input[1])
3003
+ if (inputLength === 2 && output[0] === output[1])
3005
3004
  return () => output[1];
3005
+ const isZeroDeltaRange = input[0] === input[1];
3006
3006
  // If input runs highest -> lowest, reverse both arrays
3007
3007
  if (input[0] > input[inputLength - 1]) {
3008
3008
  input = [...input].reverse();
@@ -3011,6 +3011,8 @@ function interpolate(input, output, { clamp: isClamp = true, ease, mixer } = {})
3011
3011
  const mixers = createMixers(output, ease, mixer);
3012
3012
  const numMixers = mixers.length;
3013
3013
  const interpolator = (v) => {
3014
+ if (isZeroDeltaRange && v < input[0])
3015
+ return output[0];
3014
3016
  let i = 0;
3015
3017
  if (numMixers > 1) {
3016
3018
  for (; i < input.length - 2; i++) {
@@ -3994,7 +3996,7 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
3994
3996
  }
3995
3997
  }
3996
3998
  addValueToWillChange(visualElement, key);
3997
- value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && transformProps.has(key)
3999
+ value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && positionalKeys.has(key)
3998
4000
  ? { type: false }
3999
4001
  : valueTransition, visualElement, isHandoff));
4000
4002
  const animation = value.animation;
@@ -9160,6 +9162,17 @@ function initPrefersReducedMotion() {
9160
9162
  }
9161
9163
  }
9162
9164
 
9165
+ /**
9166
+ * A list of all ValueTypes
9167
+ */
9168
+ const valueTypes = [...dimensionValueTypes, color, complex];
9169
+ /**
9170
+ * Tests a value against the list of ValueTypes
9171
+ */
9172
+ const findValueType = (v) => valueTypes.find(testValueType(v));
9173
+
9174
+ const visualElementStore = new WeakMap();
9175
+
9163
9176
  function updateMotionValuesFromProps(element, next, prev) {
9164
9177
  for (const key in next) {
9165
9178
  const nextValue = next[key];
@@ -9175,7 +9188,7 @@ function updateMotionValuesFromProps(element, next, prev) {
9175
9188
  * and warn against mismatches.
9176
9189
  */
9177
9190
  if (process.env.NODE_ENV === "development") {
9178
- warnOnce(nextValue.version === "11.16.3", `Attempting to mix Motion versions ${nextValue.version} with 11.16.3 may not work as expected.`);
9191
+ warnOnce(nextValue.version === "11.16.6", `Attempting to mix Motion versions ${nextValue.version} with 11.16.6 may not work as expected.`);
9179
9192
  }
9180
9193
  }
9181
9194
  else if (isMotionValue(prevValue)) {
@@ -9214,17 +9227,6 @@ function updateMotionValuesFromProps(element, next, prev) {
9214
9227
  return next;
9215
9228
  }
9216
9229
 
9217
- const visualElementStore = new WeakMap();
9218
-
9219
- /**
9220
- * A list of all ValueTypes
9221
- */
9222
- const valueTypes = [...dimensionValueTypes, color, complex];
9223
- /**
9224
- * Tests a value against the list of ValueTypes
9225
- */
9226
- const findValueType = (v) => valueTypes.find(testValueType(v));
9227
-
9228
9230
  const propEventHandlers = [
9229
9231
  "AnimationStart",
9230
9232
  "AnimationComplete",