motion 12.8.0 → 12.9.0

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.
@@ -1873,7 +1873,6 @@ class JSAnimation extends WithPromise {
1873
1873
  this.holdTime = null;
1874
1874
  }
1875
1875
  finish() {
1876
- this.notifyFinished();
1877
1876
  this.teardown();
1878
1877
  this.state = "finished";
1879
1878
  const { onComplete } = this.options;
@@ -1886,6 +1885,7 @@ class JSAnimation extends WithPromise {
1886
1885
  this.teardown();
1887
1886
  }
1888
1887
  teardown() {
1888
+ this.notifyFinished();
1889
1889
  this.state = "idle";
1890
1890
  this.stopDriver();
1891
1891
  this.startTime = this.holdTime = null;
@@ -2325,7 +2325,7 @@ class NativeAnimation extends WithPromise {
2325
2325
  this.isStopped = false;
2326
2326
  if (!options)
2327
2327
  return;
2328
- const { element, name, keyframes, pseudoElement, allowFlatten = false, finalKeyframe, } = options;
2328
+ const { element, name, keyframes, pseudoElement, allowFlatten = false, finalKeyframe, onComplete, } = options;
2329
2329
  this.isPseudoElement = Boolean(pseudoElement);
2330
2330
  this.allowFlatten = allowFlatten;
2331
2331
  this.options = options;
@@ -2351,8 +2351,13 @@ class NativeAnimation extends WithPromise {
2351
2351
  }
2352
2352
  this.animation.cancel();
2353
2353
  }
2354
+ onComplete?.();
2354
2355
  this.notifyFinished();
2355
2356
  };
2357
+ /**
2358
+ * TODO: In a breaking change, we should replace this with `.notifyCancel()`
2359
+ */
2360
+ this.animation.oncancel = () => this.notifyFinished();
2356
2361
  }
2357
2362
  play() {
2358
2363
  if (this.isStopped)
@@ -2677,7 +2682,7 @@ class AsyncMotionValueAnimation extends WithPromise {
2677
2682
  }
2678
2683
  onKeyframesResolved(keyframes, finalKeyframe, options, sync) {
2679
2684
  this.keyframeResolver = undefined;
2680
- const { name, type, velocity, delay, isHandoff, onUpdate, onComplete } = options;
2685
+ const { name, type, velocity, delay, isHandoff, onUpdate } = options;
2681
2686
  this.resolvedAt = time.now();
2682
2687
  /**
2683
2688
  * If we can't animate this value with the resolved keyframes
@@ -2727,12 +2732,7 @@ class AsyncMotionValueAnimation extends WithPromise {
2727
2732
  element: resolvedOptions.motionValue.owner.current,
2728
2733
  })
2729
2734
  : new JSAnimation(resolvedOptions);
2730
- animation.finished
2731
- .then(() => {
2732
- onComplete?.();
2733
- this.notifyFinished();
2734
- })
2735
- .catch(noop);
2735
+ animation.finished.then(() => this.notifyFinished()).catch(noop);
2736
2736
  if (this.pendingTimeline) {
2737
2737
  this.stopTimeline = animation.attachTimeline(this.pendingTimeline);
2738
2738
  this.pendingTimeline = undefined;
@@ -3171,6 +3171,22 @@ class DOMKeyframesResolver extends KeyframeResolver {
3171
3171
  }
3172
3172
  }
3173
3173
 
3174
+ function resolveElements(elementOrSelector, scope, selectorCache) {
3175
+ if (elementOrSelector instanceof EventTarget) {
3176
+ return [elementOrSelector];
3177
+ }
3178
+ else if (typeof elementOrSelector === "string") {
3179
+ let root = document;
3180
+ if (scope) {
3181
+ root = scope.current;
3182
+ }
3183
+ const elements = selectorCache?.[elementOrSelector] ??
3184
+ root.querySelectorAll(elementOrSelector);
3185
+ return elements ? Array.from(elements) : [];
3186
+ }
3187
+ return Array.from(elementOrSelector);
3188
+ }
3189
+
3174
3190
  const { schedule: microtask, cancel: cancelMicrotask } =
3175
3191
  /* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
3176
3192
 
@@ -3207,22 +3223,6 @@ function setDragLock(axis) {
3207
3223
  }
3208
3224
  }
3209
3225
 
3210
- function resolveElements(elementOrSelector, scope, selectorCache) {
3211
- if (elementOrSelector instanceof EventTarget) {
3212
- return [elementOrSelector];
3213
- }
3214
- else if (typeof elementOrSelector === "string") {
3215
- let root = document;
3216
- if (scope) {
3217
- root = scope.current;
3218
- }
3219
- const elements = selectorCache?.[elementOrSelector] ??
3220
- root.querySelectorAll(elementOrSelector);
3221
- return elements ? Array.from(elements) : [];
3222
- }
3223
- return Array.from(elementOrSelector);
3224
- }
3225
-
3226
3226
  function setupGesture(elementOrSelector, options) {
3227
3227
  const elements = resolveElements(elementOrSelector);
3228
3228
  const gestureAbortController = new AbortController();
@@ -3449,7 +3449,7 @@ class MotionValue {
3449
3449
  * This will be replaced by the build step with the latest version number.
3450
3450
  * When MotionValues are provided to motion components, warn if versions are mixed.
3451
3451
  */
3452
- this.version = "12.8.0";
3452
+ this.version = "12.9.0";
3453
3453
  /**
3454
3454
  * Tracks whether this value can output a velocity. Currently this is only true
3455
3455
  * if the value is numerical, but we might be able to widen the scope here and support
@@ -3475,12 +3475,12 @@ class MotionValue {
3475
3475
  this.prev = this.current;
3476
3476
  this.setCurrent(v);
3477
3477
  // Update update subscribers
3478
- if (this.current !== this.prev && this.events.change) {
3479
- this.events.change.notify(this.current);
3478
+ if (this.current !== this.prev) {
3479
+ this.events.change?.notify(this.current);
3480
3480
  }
3481
3481
  // Update render subscribers
3482
- if (render && this.events.renderRequest) {
3483
- this.events.renderRequest.notify(this.current);
3482
+ if (render) {
3483
+ this.events.renderRequest?.notify(this.current);
3484
3484
  }
3485
3485
  };
3486
3486
  this.hasAnimated = false;
@@ -3593,8 +3593,6 @@ class MotionValue {
3593
3593
  * @public
3594
3594
  */
3595
3595
  set(v, render = true) {
3596
- if (v === "none")
3597
- console.trace();
3598
3596
  if (!render || !this.passiveEffect) {
3599
3597
  this.updateAndNotify(v, render);
3600
3598
  }
@@ -3986,6 +3984,17 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
3986
3984
  delay,
3987
3985
  ...getValueTransition(transition || {}, key),
3988
3986
  };
3987
+ /**
3988
+ * If the value is already at the defined target, skip the animation.
3989
+ */
3990
+ const currentValue = value.get();
3991
+ if (currentValue !== undefined &&
3992
+ !value.isAnimating &&
3993
+ !Array.isArray(valueTarget) &&
3994
+ valueTarget === currentValue &&
3995
+ !valueTransition.velocity) {
3996
+ continue;
3997
+ }
3989
3998
  /**
3990
3999
  * If this is the first time a value is being animated, check
3991
4000
  * to see if we're handling off from an existing animation.
@@ -5085,7 +5094,7 @@ function calcViewportConstraints(layoutBox, constraintsBox) {
5085
5094
  * Calculate a transform origin relative to the source axis, between 0-1, that results
5086
5095
  * in an asthetically pleasing scale/transform needed to project from source to target.
5087
5096
  */
5088
- function calcOrigin$1(source, target) {
5097
+ function calcOrigin(source, target) {
5089
5098
  let origin = 0.5;
5090
5099
  const sourceLength = calcLength(source);
5091
5100
  const targetLength = calcLength(target);
@@ -5479,7 +5488,7 @@ class VisualElementDragControls {
5479
5488
  const axisValue = this.getAxisMotionValue(axis);
5480
5489
  if (axisValue && this.constraints !== false) {
5481
5490
  const latest = axisValue.get();
5482
- boxProgress[axis] = calcOrigin$1({ min: latest, max: latest }, this.constraints[axis]);
5491
+ boxProgress[axis] = calcOrigin({ min: latest, max: latest }, this.constraints[axis]);
5483
5492
  }
5484
5493
  });
5485
5494
  /**
@@ -8832,25 +8841,10 @@ function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true
8832
8841
  attrs[keys.array] = `${pathLength} ${pathSpacing}`;
8833
8842
  }
8834
8843
 
8835
- function calcOrigin(origin, offset, size) {
8836
- return typeof origin === "string"
8837
- ? origin
8838
- : px.transform(offset + size * origin);
8839
- }
8840
- /**
8841
- * The SVG transform origin defaults are different to CSS and is less intuitive,
8842
- * so we use the measured dimensions of the SVG to reconcile these.
8843
- */
8844
- function calcSVGTransformOrigin(dimensions, originX, originY) {
8845
- const pxOriginX = calcOrigin(originX, dimensions.x, dimensions.width);
8846
- const pxOriginY = calcOrigin(originY, dimensions.y, dimensions.height);
8847
- return `${pxOriginX} ${pxOriginY}`;
8848
- }
8849
-
8850
8844
  /**
8851
8845
  * Build SVG visual attrbutes, like cx and style.transform
8852
8846
  */
8853
- function buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathLength, pathSpacing = 1, pathOffset = 0,
8847
+ function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing = 1, pathOffset = 0,
8854
8848
  // This is object creation, which we try to avoid per-frame.
8855
8849
  ...latest }, isSVGTag, transformTemplate) {
8856
8850
  buildHTMLStyles(state, latest, transformTemplate);
@@ -8866,20 +8860,26 @@ function buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathL
8866
8860
  }
8867
8861
  state.attrs = state.style;
8868
8862
  state.style = {};
8869
- const { attrs, style, dimensions } = state;
8863
+ const { attrs, style } = state;
8870
8864
  /**
8871
- * However, we apply transforms as CSS transforms. So if we detect a transform we take it from attrs
8872
- * and copy it into style.
8865
+ * However, we apply transforms as CSS transforms.
8866
+ * So if we detect a transform, transformOrigin we take it from attrs and copy it into style.
8873
8867
  */
8874
8868
  if (attrs.transform) {
8875
- if (dimensions)
8876
- style.transform = attrs.transform;
8869
+ style.transform = attrs.transform;
8877
8870
  delete attrs.transform;
8878
8871
  }
8879
- // Parse transformOrigin
8880
- if (dimensions &&
8881
- (originX !== undefined || originY !== undefined || style.transform)) {
8882
- style.transformOrigin = calcSVGTransformOrigin(dimensions, originX !== undefined ? originX : 0.5, originY !== undefined ? originY : 0.5);
8872
+ if (style.transform || attrs.transformOrigin) {
8873
+ style.transformOrigin = attrs.transformOrigin ?? "50% 50%";
8874
+ delete attrs.transformOrigin;
8875
+ }
8876
+ if (style.transform) {
8877
+ /**
8878
+ * SVG's element transform-origin uses its own median as a reference.
8879
+ * Therefore, transformBox becomes a fill-box
8880
+ */
8881
+ style.transformBox = "fill-box";
8882
+ delete attrs.transformBox;
8883
8883
  }
8884
8884
  // Render attrX/attrY/attrScale as attributes
8885
8885
  if (attrX !== undefined)
@@ -8958,20 +8958,11 @@ function useConstant(init) {
8958
8958
  return ref.current;
8959
8959
  }
8960
8960
 
8961
- function makeState({ scrapeMotionValuesFromProps, createRenderState, onUpdate, }, props, context, presenceContext) {
8961
+ function makeState({ scrapeMotionValuesFromProps, createRenderState, }, props, context, presenceContext) {
8962
8962
  const state = {
8963
8963
  latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
8964
8964
  renderState: createRenderState(),
8965
8965
  };
8966
- if (onUpdate) {
8967
- /**
8968
- * onMount works without the VisualElement because it could be
8969
- * called before the VisualElement payload has been hydrated.
8970
- * (e.g. if someone is using m components <m.circle />)
8971
- */
8972
- state.onMount = (instance) => onUpdate({ props, current: instance, ...state });
8973
- state.onUpdate = (visualElement) => onUpdate(visualElement);
8974
- }
8975
8966
  return state;
8976
8967
  }
8977
8968
  const makeUseVisualState = (config) => (props, isStatic) => {
@@ -9058,68 +9049,6 @@ const htmlMotionConfig = {
9058
9049
  }),
9059
9050
  };
9060
9051
 
9061
- function updateSVGDimensions(instance, renderState) {
9062
- try {
9063
- renderState.dimensions =
9064
- typeof instance.getBBox === "function"
9065
- ? instance.getBBox()
9066
- : instance.getBoundingClientRect();
9067
- }
9068
- catch (e) {
9069
- // Most likely trying to measure an unrendered element under Firefox
9070
- renderState.dimensions = {
9071
- x: 0,
9072
- y: 0,
9073
- width: 0,
9074
- height: 0,
9075
- };
9076
- }
9077
- }
9078
-
9079
- function renderHTML(element, { style, vars }, styleProp, projection) {
9080
- Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
9081
- // Loop over any CSS variables and assign those.
9082
- for (const key in vars) {
9083
- element.style.setProperty(key, vars[key]);
9084
- }
9085
- }
9086
-
9087
- /**
9088
- * A set of attribute names that are always read/written as camel case.
9089
- */
9090
- const camelCaseAttributes = new Set([
9091
- "baseFrequency",
9092
- "diffuseConstant",
9093
- "kernelMatrix",
9094
- "kernelUnitLength",
9095
- "keySplines",
9096
- "keyTimes",
9097
- "limitingConeAngle",
9098
- "markerHeight",
9099
- "markerWidth",
9100
- "numOctaves",
9101
- "targetX",
9102
- "targetY",
9103
- "surfaceScale",
9104
- "specularConstant",
9105
- "specularExponent",
9106
- "stdDeviation",
9107
- "tableValues",
9108
- "viewBox",
9109
- "gradientTransform",
9110
- "pathLength",
9111
- "startOffset",
9112
- "textLength",
9113
- "lengthAdjust",
9114
- ]);
9115
-
9116
- function renderSVG(element, renderState, _styleProp, projection) {
9117
- renderHTML(element, renderState, undefined, projection);
9118
- for (const key in renderState.attrs) {
9119
- element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
9120
- }
9121
- }
9122
-
9123
9052
  function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
9124
9053
  const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
9125
9054
  for (const key in props) {
@@ -9134,49 +9063,10 @@ function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
9134
9063
  return newValues;
9135
9064
  }
9136
9065
 
9137
- const layoutProps = ["x", "y", "width", "height", "cx", "cy", "r"];
9138
9066
  const svgMotionConfig = {
9139
9067
  useVisualState: makeUseVisualState({
9140
9068
  scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,
9141
9069
  createRenderState: createSvgRenderState,
9142
- onUpdate: ({ props, prevProps, current, renderState, latestValues, }) => {
9143
- if (!current)
9144
- return;
9145
- let hasTransform = !!props.drag;
9146
- if (!hasTransform) {
9147
- for (const key in latestValues) {
9148
- if (transformProps.has(key)) {
9149
- hasTransform = true;
9150
- break;
9151
- }
9152
- }
9153
- }
9154
- if (!hasTransform)
9155
- return;
9156
- let needsMeasure = !prevProps;
9157
- if (prevProps) {
9158
- /**
9159
- * Check the layout props for changes, if any are found we need to
9160
- * measure the element again.
9161
- */
9162
- for (let i = 0; i < layoutProps.length; i++) {
9163
- const key = layoutProps[i];
9164
- if (props[key] !==
9165
- prevProps[key]) {
9166
- needsMeasure = true;
9167
- }
9168
- }
9169
- }
9170
- if (!needsMeasure)
9171
- return;
9172
- frame.read(() => {
9173
- updateSVGDimensions(current, renderState);
9174
- frame.render(() => {
9175
- buildSVGAttrs(renderState, latestValues, isSVGTag(current.tagName), props.transformTemplate);
9176
- renderSVG(current, renderState);
9177
- });
9178
- });
9179
- },
9180
9070
  }),
9181
9071
  };
9182
9072
 
@@ -9232,7 +9122,7 @@ function updateMotionValuesFromProps(element, next, prev) {
9232
9122
  * and warn against mismatches.
9233
9123
  */
9234
9124
  if (process.env.NODE_ENV === "development") {
9235
- warnOnce(nextValue.version === "12.8.0", `Attempting to mix Motion versions ${nextValue.version} with 12.8.0 may not work as expected.`);
9125
+ warnOnce(nextValue.version === "12.9.0", `Attempting to mix Motion versions ${nextValue.version} with 12.9.0 may not work as expected.`);
9236
9126
  }
9237
9127
  }
9238
9128
  else if (isMotionValue(prevValue)) {
@@ -9365,8 +9255,7 @@ class VisualElement {
9365
9255
  frame.render(this.render, false, true);
9366
9256
  }
9367
9257
  };
9368
- const { latestValues, renderState, onUpdate } = visualState;
9369
- this.onUpdate = onUpdate;
9258
+ const { latestValues, renderState } = visualState;
9370
9259
  this.latestValues = latestValues;
9371
9260
  this.baseTarget = { ...latestValues };
9372
9261
  this.initialValues = props.initial ? { ...latestValues } : {};
@@ -9568,7 +9457,6 @@ class VisualElement {
9568
9457
  if (this.handleChildMotionValue) {
9569
9458
  this.handleChildMotionValue();
9570
9459
  }
9571
- this.onUpdate && this.onUpdate(this);
9572
9460
  }
9573
9461
  getProps() {
9574
9462
  return this.props;
@@ -9766,6 +9654,14 @@ class DOMVisualElement extends VisualElement {
9766
9654
  }
9767
9655
  }
9768
9656
 
9657
+ function renderHTML(element, { style, vars }, styleProp, projection) {
9658
+ Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
9659
+ // Loop over any CSS variables and assign those.
9660
+ for (const key in vars) {
9661
+ element.style.setProperty(key, vars[key]);
9662
+ }
9663
+ }
9664
+
9769
9665
  function getComputedStyle$1(element) {
9770
9666
  return window.getComputedStyle(element);
9771
9667
  }
@@ -9798,17 +9694,48 @@ class HTMLVisualElement extends DOMVisualElement {
9798
9694
  }
9799
9695
  }
9800
9696
 
9697
+ /**
9698
+ * A set of attribute names that are always read/written as camel case.
9699
+ */
9700
+ const camelCaseAttributes = new Set([
9701
+ "baseFrequency",
9702
+ "diffuseConstant",
9703
+ "kernelMatrix",
9704
+ "kernelUnitLength",
9705
+ "keySplines",
9706
+ "keyTimes",
9707
+ "limitingConeAngle",
9708
+ "markerHeight",
9709
+ "markerWidth",
9710
+ "numOctaves",
9711
+ "targetX",
9712
+ "targetY",
9713
+ "surfaceScale",
9714
+ "specularConstant",
9715
+ "specularExponent",
9716
+ "stdDeviation",
9717
+ "tableValues",
9718
+ "viewBox",
9719
+ "gradientTransform",
9720
+ "pathLength",
9721
+ "startOffset",
9722
+ "textLength",
9723
+ "lengthAdjust",
9724
+ ]);
9725
+
9726
+ function renderSVG(element, renderState, _styleProp, projection) {
9727
+ renderHTML(element, renderState, undefined, projection);
9728
+ for (const key in renderState.attrs) {
9729
+ element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
9730
+ }
9731
+ }
9732
+
9801
9733
  class SVGVisualElement extends DOMVisualElement {
9802
9734
  constructor() {
9803
9735
  super(...arguments);
9804
9736
  this.type = "svg";
9805
9737
  this.isSVGTag = false;
9806
9738
  this.measureInstanceViewportBox = createBox;
9807
- this.updateDimensions = () => {
9808
- if (this.current && !this.renderState.dimensions) {
9809
- updateSVGDimensions(this.current, this.renderState);
9810
- }
9811
- };
9812
9739
  }
9813
9740
  getBaseTargetFromProps(props, key) {
9814
9741
  return props[key];
@@ -9824,11 +9751,6 @@ class SVGVisualElement extends DOMVisualElement {
9824
9751
  scrapeMotionValuesFromProps(props, prevProps, visualElement) {
9825
9752
  return scrapeMotionValuesFromProps(props, prevProps, visualElement);
9826
9753
  }
9827
- onBindTransform() {
9828
- if (this.current && !this.renderState.dimensions) {
9829
- frame.postRender(this.updateDimensions);
9830
- }
9831
- }
9832
9754
  build(renderState, latestValues, props) {
9833
9755
  buildSVGAttrs(renderState, latestValues, this.isSVGTag, props.transformTemplate);
9834
9756
  }