@betterstore/react 0.2.43 → 0.2.45
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.
- package/CHANGELOG.md +12 -0
- package/dist/components/checkout-embed/steps/payment/form.d.ts +2 -1
- package/dist/components/checkout-embed/useFormStore.d.ts +2 -0
- package/dist/components/payment-element/index.d.ts +2 -1
- package/dist/index.cjs.js +1803 -1947
- package/dist/index.mjs +1803 -1947
- package/package.json +2 -2
package/dist/index.cjs.js
CHANGED
|
@@ -3943,8 +3943,10 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, pre
|
|
|
3943
3943
|
};
|
|
3944
3944
|
|
|
3945
3945
|
const stepsOrder = [
|
|
3946
|
+
"setup", // Compute
|
|
3946
3947
|
"read", // Read
|
|
3947
3948
|
"resolveKeyframes", // Write/Read/Write/Read
|
|
3949
|
+
"preUpdate", // Compute
|
|
3948
3950
|
"update", // Compute
|
|
3949
3951
|
"preRender", // Compute
|
|
3950
3952
|
"render", // Write
|
|
@@ -4043,9 +4045,7 @@ function createRenderStep(runNextFrame, stepName) {
|
|
|
4043
4045
|
return step;
|
|
4044
4046
|
}
|
|
4045
4047
|
|
|
4046
|
-
const MotionGlobalConfig = {
|
|
4047
|
-
useManualTiming: false,
|
|
4048
|
-
};
|
|
4048
|
+
const MotionGlobalConfig = {};
|
|
4049
4049
|
|
|
4050
4050
|
const maxElapsed = 40;
|
|
4051
4051
|
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
@@ -4061,11 +4061,13 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
4061
4061
|
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
4062
4062
|
return acc;
|
|
4063
4063
|
}, {});
|
|
4064
|
-
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
4064
|
+
const { setup, read, resolveKeyframes, preUpdate, update, preRender, render, postRender, } = steps;
|
|
4065
4065
|
const processBatch = () => {
|
|
4066
|
-
const timestamp =
|
|
4066
|
+
const timestamp = MotionGlobalConfig.useManualTiming
|
|
4067
|
+
? state.timestamp
|
|
4068
|
+
: performance.now();
|
|
4067
4069
|
runNextFrame = false;
|
|
4068
|
-
{
|
|
4070
|
+
if (!MotionGlobalConfig.useManualTiming) {
|
|
4069
4071
|
state.delta = useDefaultElapsed
|
|
4070
4072
|
? 1000 / 60
|
|
4071
4073
|
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
|
|
@@ -4073,8 +4075,10 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
4073
4075
|
state.timestamp = timestamp;
|
|
4074
4076
|
state.isProcessing = true;
|
|
4075
4077
|
// Unrolled render loop for better per-frame performance
|
|
4078
|
+
setup.process(state);
|
|
4076
4079
|
read.process(state);
|
|
4077
4080
|
resolveKeyframes.process(state);
|
|
4081
|
+
preUpdate.process(state);
|
|
4078
4082
|
update.process(state);
|
|
4079
4083
|
preRender.process(state);
|
|
4080
4084
|
render.process(state);
|
|
@@ -4689,7 +4693,7 @@ const transformPropOrder = [
|
|
|
4689
4693
|
/**
|
|
4690
4694
|
* A quick lookup for transform props.
|
|
4691
4695
|
*/
|
|
4692
|
-
const transformProps = new Set(transformPropOrder);
|
|
4696
|
+
const transformProps = /*@__PURE__*/ (() => new Set(transformPropOrder))();
|
|
4693
4697
|
|
|
4694
4698
|
function isForcedMotionValue(key, { layout, layoutId }) {
|
|
4695
4699
|
return (transformProps.has(key) ||
|
|
@@ -4731,6 +4735,12 @@ const scale = {
|
|
|
4731
4735
|
default: 1,
|
|
4732
4736
|
};
|
|
4733
4737
|
|
|
4738
|
+
const int = {
|
|
4739
|
+
...number,
|
|
4740
|
+
transform: Math.round,
|
|
4741
|
+
};
|
|
4742
|
+
|
|
4743
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
4734
4744
|
const createUnitType = (unit) => ({
|
|
4735
4745
|
test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
|
|
4736
4746
|
parse: parseFloat,
|
|
@@ -4741,13 +4751,40 @@ const percent = /*@__PURE__*/ createUnitType("%");
|
|
|
4741
4751
|
const px = /*@__PURE__*/ createUnitType("px");
|
|
4742
4752
|
const vh = /*@__PURE__*/ createUnitType("vh");
|
|
4743
4753
|
const vw = /*@__PURE__*/ createUnitType("vw");
|
|
4744
|
-
const progressPercentage = {
|
|
4754
|
+
const progressPercentage = /*@__PURE__*/ (() => ({
|
|
4745
4755
|
...percent,
|
|
4746
4756
|
parse: (v) => percent.parse(v) / 100,
|
|
4747
4757
|
transform: (v) => percent.transform(v * 100),
|
|
4758
|
+
}))();
|
|
4759
|
+
|
|
4760
|
+
const transformValueTypes = {
|
|
4761
|
+
rotate: degrees,
|
|
4762
|
+
rotateX: degrees,
|
|
4763
|
+
rotateY: degrees,
|
|
4764
|
+
rotateZ: degrees,
|
|
4765
|
+
scale,
|
|
4766
|
+
scaleX: scale,
|
|
4767
|
+
scaleY: scale,
|
|
4768
|
+
scaleZ: scale,
|
|
4769
|
+
skew: degrees,
|
|
4770
|
+
skewX: degrees,
|
|
4771
|
+
skewY: degrees,
|
|
4772
|
+
distance: px,
|
|
4773
|
+
translateX: px,
|
|
4774
|
+
translateY: px,
|
|
4775
|
+
translateZ: px,
|
|
4776
|
+
x: px,
|
|
4777
|
+
y: px,
|
|
4778
|
+
z: px,
|
|
4779
|
+
perspective: px,
|
|
4780
|
+
transformPerspective: px,
|
|
4781
|
+
opacity: alpha,
|
|
4782
|
+
originX: progressPercentage,
|
|
4783
|
+
originY: progressPercentage,
|
|
4784
|
+
originZ: px,
|
|
4748
4785
|
};
|
|
4749
4786
|
|
|
4750
|
-
const
|
|
4787
|
+
const numberValueTypes = {
|
|
4751
4788
|
// Border props
|
|
4752
4789
|
borderWidth: px,
|
|
4753
4790
|
borderTopWidth: px,
|
|
@@ -4783,45 +4820,8 @@ const browserNumberValueTypes = {
|
|
|
4783
4820
|
// Misc
|
|
4784
4821
|
backgroundPositionX: px,
|
|
4785
4822
|
backgroundPositionY: px,
|
|
4786
|
-
};
|
|
4787
|
-
|
|
4788
|
-
const transformValueTypes = {
|
|
4789
|
-
rotate: degrees,
|
|
4790
|
-
rotateX: degrees,
|
|
4791
|
-
rotateY: degrees,
|
|
4792
|
-
rotateZ: degrees,
|
|
4793
|
-
scale,
|
|
4794
|
-
scaleX: scale,
|
|
4795
|
-
scaleY: scale,
|
|
4796
|
-
scaleZ: scale,
|
|
4797
|
-
skew: degrees,
|
|
4798
|
-
skewX: degrees,
|
|
4799
|
-
skewY: degrees,
|
|
4800
|
-
distance: px,
|
|
4801
|
-
translateX: px,
|
|
4802
|
-
translateY: px,
|
|
4803
|
-
translateZ: px,
|
|
4804
|
-
x: px,
|
|
4805
|
-
y: px,
|
|
4806
|
-
z: px,
|
|
4807
|
-
perspective: px,
|
|
4808
|
-
transformPerspective: px,
|
|
4809
|
-
opacity: alpha,
|
|
4810
|
-
originX: progressPercentage,
|
|
4811
|
-
originY: progressPercentage,
|
|
4812
|
-
originZ: px,
|
|
4813
|
-
};
|
|
4814
|
-
|
|
4815
|
-
const int = {
|
|
4816
|
-
...number,
|
|
4817
|
-
transform: Math.round,
|
|
4818
|
-
};
|
|
4819
|
-
|
|
4820
|
-
const numberValueTypes = {
|
|
4821
|
-
...browserNumberValueTypes,
|
|
4822
4823
|
...transformValueTypes,
|
|
4823
4824
|
zIndex: int,
|
|
4824
|
-
size: px,
|
|
4825
4825
|
// SVG
|
|
4826
4826
|
fillOpacity: alpha,
|
|
4827
4827
|
strokeOpacity: alpha,
|
|
@@ -5088,25 +5088,10 @@ function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true
|
|
|
5088
5088
|
attrs[keys.array] = `${pathLength} ${pathSpacing}`;
|
|
5089
5089
|
}
|
|
5090
5090
|
|
|
5091
|
-
function calcOrigin$1(origin, offset, size) {
|
|
5092
|
-
return typeof origin === "string"
|
|
5093
|
-
? origin
|
|
5094
|
-
: px.transform(offset + size * origin);
|
|
5095
|
-
}
|
|
5096
|
-
/**
|
|
5097
|
-
* The SVG transform origin defaults are different to CSS and is less intuitive,
|
|
5098
|
-
* so we use the measured dimensions of the SVG to reconcile these.
|
|
5099
|
-
*/
|
|
5100
|
-
function calcSVGTransformOrigin(dimensions, originX, originY) {
|
|
5101
|
-
const pxOriginX = calcOrigin$1(originX, dimensions.x, dimensions.width);
|
|
5102
|
-
const pxOriginY = calcOrigin$1(originY, dimensions.y, dimensions.height);
|
|
5103
|
-
return `${pxOriginX} ${pxOriginY}`;
|
|
5104
|
-
}
|
|
5105
|
-
|
|
5106
5091
|
/**
|
|
5107
5092
|
* Build SVG visual attrbutes, like cx and style.transform
|
|
5108
5093
|
*/
|
|
5109
|
-
function buildSVGAttrs(state, { attrX, attrY, attrScale,
|
|
5094
|
+
function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing = 1, pathOffset = 0,
|
|
5110
5095
|
// This is object creation, which we try to avoid per-frame.
|
|
5111
5096
|
...latest }, isSVGTag, transformTemplate) {
|
|
5112
5097
|
buildHTMLStyles(state, latest, transformTemplate);
|
|
@@ -5122,20 +5107,26 @@ function buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathL
|
|
|
5122
5107
|
}
|
|
5123
5108
|
state.attrs = state.style;
|
|
5124
5109
|
state.style = {};
|
|
5125
|
-
const { attrs, style
|
|
5110
|
+
const { attrs, style } = state;
|
|
5126
5111
|
/**
|
|
5127
|
-
* However, we apply transforms as CSS transforms.
|
|
5128
|
-
* and copy it into style.
|
|
5112
|
+
* However, we apply transforms as CSS transforms.
|
|
5113
|
+
* So if we detect a transform, transformOrigin we take it from attrs and copy it into style.
|
|
5129
5114
|
*/
|
|
5130
5115
|
if (attrs.transform) {
|
|
5131
|
-
|
|
5132
|
-
style.transform = attrs.transform;
|
|
5116
|
+
style.transform = attrs.transform;
|
|
5133
5117
|
delete attrs.transform;
|
|
5134
5118
|
}
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5119
|
+
if (style.transform || attrs.transformOrigin) {
|
|
5120
|
+
style.transformOrigin = attrs.transformOrigin ?? "50% 50%";
|
|
5121
|
+
delete attrs.transformOrigin;
|
|
5122
|
+
}
|
|
5123
|
+
if (style.transform) {
|
|
5124
|
+
/**
|
|
5125
|
+
* SVG's element transform-origin uses its own median as a reference.
|
|
5126
|
+
* Therefore, transformBox becomes a fill-box
|
|
5127
|
+
*/
|
|
5128
|
+
style.transformBox = "fill-box";
|
|
5129
|
+
delete attrs.transformBox;
|
|
5139
5130
|
}
|
|
5140
5131
|
// Render attrX/attrY/attrScale as attributes
|
|
5141
5132
|
if (attrX !== undefined)
|
|
@@ -5234,44 +5225,20 @@ function resolveVariantFromProps(props, definition, custom, visualElement) {
|
|
|
5234
5225
|
return definition;
|
|
5235
5226
|
}
|
|
5236
5227
|
|
|
5237
|
-
const isKeyframesTarget = (v) => {
|
|
5238
|
-
return Array.isArray(v);
|
|
5239
|
-
};
|
|
5240
|
-
|
|
5241
|
-
const isCustomValue = (v) => {
|
|
5242
|
-
return Boolean(v && typeof v === "object" && v.mix && v.toValue);
|
|
5243
|
-
};
|
|
5244
|
-
const resolveFinalValueInKeyframes = (v) => {
|
|
5245
|
-
// TODO maybe throw if v.length - 1 is placeholder token?
|
|
5246
|
-
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
5247
|
-
};
|
|
5248
|
-
|
|
5249
5228
|
/**
|
|
5250
5229
|
* If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
|
|
5251
5230
|
*
|
|
5252
5231
|
* TODO: Remove and move to library
|
|
5253
5232
|
*/
|
|
5254
5233
|
function resolveMotionValue(value) {
|
|
5255
|
-
|
|
5256
|
-
return isCustomValue(unwrappedValue)
|
|
5257
|
-
? unwrappedValue.toValue()
|
|
5258
|
-
: unwrappedValue;
|
|
5234
|
+
return isMotionValue(value) ? value.get() : value;
|
|
5259
5235
|
}
|
|
5260
5236
|
|
|
5261
|
-
function makeState({ scrapeMotionValuesFromProps, createRenderState,
|
|
5237
|
+
function makeState({ scrapeMotionValuesFromProps, createRenderState, }, props, context, presenceContext) {
|
|
5262
5238
|
const state = {
|
|
5263
5239
|
latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
|
|
5264
5240
|
renderState: createRenderState(),
|
|
5265
5241
|
};
|
|
5266
|
-
if (onUpdate) {
|
|
5267
|
-
/**
|
|
5268
|
-
* onMount works without the VisualElement because it could be
|
|
5269
|
-
* called before the VisualElement payload has been hydrated.
|
|
5270
|
-
* (e.g. if someone is using m components <m.circle />)
|
|
5271
|
-
*/
|
|
5272
|
-
state.onMount = (instance) => onUpdate({ props, current: instance, ...state });
|
|
5273
|
-
state.onUpdate = (visualElement) => onUpdate(visualElement);
|
|
5274
|
-
}
|
|
5275
5242
|
return state;
|
|
5276
5243
|
}
|
|
5277
5244
|
const makeUseVisualState = (config) => (props, isStatic) => {
|
|
@@ -5358,68 +5325,6 @@ const htmlMotionConfig = {
|
|
|
5358
5325
|
}),
|
|
5359
5326
|
};
|
|
5360
5327
|
|
|
5361
|
-
function updateSVGDimensions(instance, renderState) {
|
|
5362
|
-
try {
|
|
5363
|
-
renderState.dimensions =
|
|
5364
|
-
typeof instance.getBBox === "function"
|
|
5365
|
-
? instance.getBBox()
|
|
5366
|
-
: instance.getBoundingClientRect();
|
|
5367
|
-
}
|
|
5368
|
-
catch (e) {
|
|
5369
|
-
// Most likely trying to measure an unrendered element under Firefox
|
|
5370
|
-
renderState.dimensions = {
|
|
5371
|
-
x: 0,
|
|
5372
|
-
y: 0,
|
|
5373
|
-
width: 0,
|
|
5374
|
-
height: 0,
|
|
5375
|
-
};
|
|
5376
|
-
}
|
|
5377
|
-
}
|
|
5378
|
-
|
|
5379
|
-
function renderHTML(element, { style, vars }, styleProp, projection) {
|
|
5380
|
-
Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
|
|
5381
|
-
// Loop over any CSS variables and assign those.
|
|
5382
|
-
for (const key in vars) {
|
|
5383
|
-
element.style.setProperty(key, vars[key]);
|
|
5384
|
-
}
|
|
5385
|
-
}
|
|
5386
|
-
|
|
5387
|
-
/**
|
|
5388
|
-
* A set of attribute names that are always read/written as camel case.
|
|
5389
|
-
*/
|
|
5390
|
-
const camelCaseAttributes = new Set([
|
|
5391
|
-
"baseFrequency",
|
|
5392
|
-
"diffuseConstant",
|
|
5393
|
-
"kernelMatrix",
|
|
5394
|
-
"kernelUnitLength",
|
|
5395
|
-
"keySplines",
|
|
5396
|
-
"keyTimes",
|
|
5397
|
-
"limitingConeAngle",
|
|
5398
|
-
"markerHeight",
|
|
5399
|
-
"markerWidth",
|
|
5400
|
-
"numOctaves",
|
|
5401
|
-
"targetX",
|
|
5402
|
-
"targetY",
|
|
5403
|
-
"surfaceScale",
|
|
5404
|
-
"specularConstant",
|
|
5405
|
-
"specularExponent",
|
|
5406
|
-
"stdDeviation",
|
|
5407
|
-
"tableValues",
|
|
5408
|
-
"viewBox",
|
|
5409
|
-
"gradientTransform",
|
|
5410
|
-
"pathLength",
|
|
5411
|
-
"startOffset",
|
|
5412
|
-
"textLength",
|
|
5413
|
-
"lengthAdjust",
|
|
5414
|
-
]);
|
|
5415
|
-
|
|
5416
|
-
function renderSVG(element, renderState, _styleProp, projection) {
|
|
5417
|
-
renderHTML(element, renderState, undefined, projection);
|
|
5418
|
-
for (const key in renderState.attrs) {
|
|
5419
|
-
element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
|
|
5420
|
-
}
|
|
5421
|
-
}
|
|
5422
|
-
|
|
5423
5328
|
function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
|
|
5424
5329
|
const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
|
|
5425
5330
|
for (const key in props) {
|
|
@@ -5434,49 +5339,10 @@ function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
|
|
|
5434
5339
|
return newValues;
|
|
5435
5340
|
}
|
|
5436
5341
|
|
|
5437
|
-
const layoutProps = ["x", "y", "width", "height", "cx", "cy", "r"];
|
|
5438
5342
|
const svgMotionConfig = {
|
|
5439
5343
|
useVisualState: makeUseVisualState({
|
|
5440
5344
|
scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,
|
|
5441
5345
|
createRenderState: createSvgRenderState,
|
|
5442
|
-
onUpdate: ({ props, prevProps, current, renderState, latestValues, }) => {
|
|
5443
|
-
if (!current)
|
|
5444
|
-
return;
|
|
5445
|
-
let hasTransform = !!props.drag;
|
|
5446
|
-
if (!hasTransform) {
|
|
5447
|
-
for (const key in latestValues) {
|
|
5448
|
-
if (transformProps.has(key)) {
|
|
5449
|
-
hasTransform = true;
|
|
5450
|
-
break;
|
|
5451
|
-
}
|
|
5452
|
-
}
|
|
5453
|
-
}
|
|
5454
|
-
if (!hasTransform)
|
|
5455
|
-
return;
|
|
5456
|
-
let needsMeasure = !prevProps;
|
|
5457
|
-
if (prevProps) {
|
|
5458
|
-
/**
|
|
5459
|
-
* Check the layout props for changes, if any are found we need to
|
|
5460
|
-
* measure the element again.
|
|
5461
|
-
*/
|
|
5462
|
-
for (let i = 0; i < layoutProps.length; i++) {
|
|
5463
|
-
const key = layoutProps[i];
|
|
5464
|
-
if (props[key] !==
|
|
5465
|
-
prevProps[key]) {
|
|
5466
|
-
needsMeasure = true;
|
|
5467
|
-
}
|
|
5468
|
-
}
|
|
5469
|
-
}
|
|
5470
|
-
if (!needsMeasure)
|
|
5471
|
-
return;
|
|
5472
|
-
frame.read(() => {
|
|
5473
|
-
updateSVGDimensions(current, renderState);
|
|
5474
|
-
frame.render(() => {
|
|
5475
|
-
buildSVGAttrs(renderState, latestValues, isSVGTag(current.tagName), props.transformTemplate);
|
|
5476
|
-
renderSVG(current, renderState);
|
|
5477
|
-
});
|
|
5478
|
-
});
|
|
5479
|
-
},
|
|
5480
5346
|
}),
|
|
5481
5347
|
};
|
|
5482
5348
|
|
|
@@ -5501,15 +5367,9 @@ function resolveVariant(visualElement, definition, custom) {
|
|
|
5501
5367
|
return resolveVariantFromProps(props, definition, custom !== undefined ? custom : props.custom, visualElement);
|
|
5502
5368
|
}
|
|
5503
5369
|
|
|
5504
|
-
const
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
"top",
|
|
5508
|
-
"left",
|
|
5509
|
-
"right",
|
|
5510
|
-
"bottom",
|
|
5511
|
-
...transformPropOrder,
|
|
5512
|
-
]);
|
|
5370
|
+
const isKeyframesTarget = (v) => {
|
|
5371
|
+
return Array.isArray(v);
|
|
5372
|
+
};
|
|
5513
5373
|
|
|
5514
5374
|
let now;
|
|
5515
5375
|
function clearTime() {
|
|
@@ -5620,7 +5480,7 @@ class MotionValue {
|
|
|
5620
5480
|
* This will be replaced by the build step with the latest version number.
|
|
5621
5481
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
5622
5482
|
*/
|
|
5623
|
-
this.version = "12.
|
|
5483
|
+
this.version = "12.9.0";
|
|
5624
5484
|
/**
|
|
5625
5485
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
5626
5486
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -5646,12 +5506,12 @@ class MotionValue {
|
|
|
5646
5506
|
this.prev = this.current;
|
|
5647
5507
|
this.setCurrent(v);
|
|
5648
5508
|
// Update update subscribers
|
|
5649
|
-
if (this.current !== this.prev
|
|
5650
|
-
this.events.change
|
|
5509
|
+
if (this.current !== this.prev) {
|
|
5510
|
+
this.events.change?.notify(this.current);
|
|
5651
5511
|
}
|
|
5652
5512
|
// Update render subscribers
|
|
5653
|
-
if (render
|
|
5654
|
-
this.events.renderRequest
|
|
5513
|
+
if (render) {
|
|
5514
|
+
this.events.renderRequest?.notify(this.current);
|
|
5655
5515
|
}
|
|
5656
5516
|
};
|
|
5657
5517
|
this.hasAnimated = false;
|
|
@@ -5884,6 +5744,7 @@ class MotionValue {
|
|
|
5884
5744
|
* @public
|
|
5885
5745
|
*/
|
|
5886
5746
|
destroy() {
|
|
5747
|
+
this.events.destroy?.notify();
|
|
5887
5748
|
this.clearListeners();
|
|
5888
5749
|
this.stop();
|
|
5889
5750
|
if (this.stopPassiveEffect) {
|
|
@@ -5907,6 +5768,10 @@ function setMotionValue(visualElement, key, value) {
|
|
|
5907
5768
|
visualElement.addValue(key, motionValue(value));
|
|
5908
5769
|
}
|
|
5909
5770
|
}
|
|
5771
|
+
function resolveFinalValueInKeyframes(v) {
|
|
5772
|
+
// TODO maybe throw if v.length - 1 is placeholder token?
|
|
5773
|
+
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
5774
|
+
}
|
|
5910
5775
|
function setTarget(visualElement, definition) {
|
|
5911
5776
|
const resolved = resolveVariant(visualElement, definition);
|
|
5912
5777
|
let { transitionEnd = {}, transition = {}, ...target } = resolved || {};
|
|
@@ -5941,89 +5806,79 @@ function getOptimisedAppearId(visualElement) {
|
|
|
5941
5806
|
return visualElement.props[optimizedAppearDataAttribute];
|
|
5942
5807
|
}
|
|
5943
5808
|
|
|
5944
|
-
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
usually improved times, depending on the curve.
|
|
5953
|
-
I also removed the lookup table, as for the added bundle size and loop we're
|
|
5954
|
-
only cutting ~4 or so subdivision iterations. I bumped the max iterations up
|
|
5955
|
-
to 12 to compensate and this still tended to be faster for no perceivable
|
|
5956
|
-
loss in accuracy.
|
|
5957
|
-
Usage
|
|
5958
|
-
const easeOut = cubicBezier(.17,.67,.83,.67);
|
|
5959
|
-
const x = easeOut(0.5); // returns 0.627...
|
|
5960
|
-
*/
|
|
5961
|
-
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
5962
|
-
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
5963
|
-
t;
|
|
5964
|
-
const subdivisionPrecision = 0.0000001;
|
|
5965
|
-
const subdivisionMaxIterations = 12;
|
|
5966
|
-
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
5967
|
-
let currentX;
|
|
5968
|
-
let currentT;
|
|
5969
|
-
let i = 0;
|
|
5970
|
-
do {
|
|
5971
|
-
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
5972
|
-
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
5973
|
-
if (currentX > 0.0) {
|
|
5974
|
-
upperBound = currentT;
|
|
5975
|
-
}
|
|
5976
|
-
else {
|
|
5977
|
-
lowerBound = currentT;
|
|
5978
|
-
}
|
|
5979
|
-
} while (Math.abs(currentX) > subdivisionPrecision &&
|
|
5980
|
-
++i < subdivisionMaxIterations);
|
|
5981
|
-
return currentT;
|
|
5982
|
-
}
|
|
5983
|
-
function cubicBezier(mX1, mY1, mX2, mY2) {
|
|
5984
|
-
// If this is a linear gradient, return linear easing
|
|
5985
|
-
if (mX1 === mY1 && mX2 === mY2)
|
|
5986
|
-
return noop;
|
|
5987
|
-
const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
|
|
5988
|
-
// If animation is at start/end, return t without easing
|
|
5989
|
-
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
|
|
5809
|
+
const isNotNull$1 = (value) => value !== null;
|
|
5810
|
+
function getFinalKeyframe$1(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
|
|
5811
|
+
const resolvedKeyframes = keyframes.filter(isNotNull$1);
|
|
5812
|
+
const index = repeat && repeatType !== "loop" && repeat % 2 === 1
|
|
5813
|
+
? 0
|
|
5814
|
+
: resolvedKeyframes.length - 1;
|
|
5815
|
+
return resolvedKeyframes[index]
|
|
5816
|
+
;
|
|
5990
5817
|
}
|
|
5991
5818
|
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
const
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
const
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
const circInOut = mirrorEasing(circIn);
|
|
6009
|
-
|
|
5819
|
+
const underDampedSpring = {
|
|
5820
|
+
type: "spring",
|
|
5821
|
+
stiffness: 500,
|
|
5822
|
+
damping: 25,
|
|
5823
|
+
restSpeed: 10,
|
|
5824
|
+
};
|
|
5825
|
+
const criticallyDampedSpring = (target) => ({
|
|
5826
|
+
type: "spring",
|
|
5827
|
+
stiffness: 550,
|
|
5828
|
+
damping: target === 0 ? 2 * Math.sqrt(550) : 30,
|
|
5829
|
+
restSpeed: 10,
|
|
5830
|
+
});
|
|
5831
|
+
const keyframesTransition = {
|
|
5832
|
+
type: "keyframes",
|
|
5833
|
+
duration: 0.8,
|
|
5834
|
+
};
|
|
6010
5835
|
/**
|
|
6011
|
-
*
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
5836
|
+
* Default easing curve is a slightly shallower version of
|
|
5837
|
+
* the default browser easing curve.
|
|
5838
|
+
*/
|
|
5839
|
+
const ease = {
|
|
5840
|
+
type: "keyframes",
|
|
5841
|
+
ease: [0.25, 0.1, 0.35, 1],
|
|
5842
|
+
duration: 0.3,
|
|
5843
|
+
};
|
|
5844
|
+
const getDefaultTransition = (valueKey, { keyframes }) => {
|
|
5845
|
+
if (keyframes.length > 2) {
|
|
5846
|
+
return keyframesTransition;
|
|
6021
5847
|
}
|
|
6022
|
-
else {
|
|
6023
|
-
return
|
|
5848
|
+
else if (transformProps.has(valueKey)) {
|
|
5849
|
+
return valueKey.startsWith("scale")
|
|
5850
|
+
? criticallyDampedSpring(keyframes[1])
|
|
5851
|
+
: underDampedSpring;
|
|
6024
5852
|
}
|
|
5853
|
+
return ease;
|
|
5854
|
+
};
|
|
5855
|
+
|
|
5856
|
+
/**
|
|
5857
|
+
* Decide whether a transition is defined on a given Transition.
|
|
5858
|
+
* This filters out orchestration options and returns true
|
|
5859
|
+
* if any options are left.
|
|
5860
|
+
*/
|
|
5861
|
+
function isTransitionDefined({ when, delay: _delay, delayChildren, staggerChildren, staggerDirection, repeat, repeatType, repeatDelay, from, elapsed, ...transition }) {
|
|
5862
|
+
return !!Object.keys(transition).length;
|
|
5863
|
+
}
|
|
5864
|
+
|
|
5865
|
+
function getValueTransition(transition, key) {
|
|
5866
|
+
return (transition?.[key] ??
|
|
5867
|
+
transition?.["default"] ??
|
|
5868
|
+
transition);
|
|
6025
5869
|
}
|
|
6026
5870
|
|
|
5871
|
+
/**
|
|
5872
|
+
* Converts seconds to milliseconds
|
|
5873
|
+
*
|
|
5874
|
+
* @param seconds - Time in seconds.
|
|
5875
|
+
* @return milliseconds - Converted time in milliseconds.
|
|
5876
|
+
*/
|
|
5877
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
5878
|
+
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
5879
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
5880
|
+
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
5881
|
+
|
|
6027
5882
|
// If this number is a decimal, make it just five decimal places
|
|
6028
5883
|
// to avoid exponents
|
|
6029
5884
|
const sanitize = (v) => Math.round(v * 100000) / 100000;
|
|
@@ -6240,848 +6095,129 @@ const complex = {
|
|
|
6240
6095
|
getAnimatableNone: getAnimatableNone$1,
|
|
6241
6096
|
};
|
|
6242
6097
|
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
if (
|
|
6250
|
-
return
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6098
|
+
// Adapted from https://gist.github.com/mjackson/5311256
|
|
6099
|
+
function hueToRgb(p, q, t) {
|
|
6100
|
+
if (t < 0)
|
|
6101
|
+
t += 1;
|
|
6102
|
+
if (t > 1)
|
|
6103
|
+
t -= 1;
|
|
6104
|
+
if (t < 1 / 6)
|
|
6105
|
+
return p + (q - p) * 6 * t;
|
|
6106
|
+
if (t < 1 / 2)
|
|
6107
|
+
return q;
|
|
6108
|
+
if (t < 2 / 3)
|
|
6109
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
6110
|
+
return p;
|
|
6111
|
+
}
|
|
6112
|
+
function hslaToRgba({ hue, saturation, lightness, alpha }) {
|
|
6113
|
+
hue /= 360;
|
|
6114
|
+
saturation /= 100;
|
|
6115
|
+
lightness /= 100;
|
|
6116
|
+
let red = 0;
|
|
6117
|
+
let green = 0;
|
|
6118
|
+
let blue = 0;
|
|
6119
|
+
if (!saturation) {
|
|
6120
|
+
red = green = blue = lightness;
|
|
6121
|
+
}
|
|
6122
|
+
else {
|
|
6123
|
+
const q = lightness < 0.5
|
|
6124
|
+
? lightness * (1 + saturation)
|
|
6125
|
+
: lightness + saturation - lightness * saturation;
|
|
6126
|
+
const p = 2 * lightness - q;
|
|
6127
|
+
red = hueToRgb(p, q, hue + 1 / 3);
|
|
6128
|
+
green = hueToRgb(p, q, hue);
|
|
6129
|
+
blue = hueToRgb(p, q, hue - 1 / 3);
|
|
6130
|
+
}
|
|
6131
|
+
return {
|
|
6132
|
+
red: Math.round(red * 255),
|
|
6133
|
+
green: Math.round(green * 255),
|
|
6134
|
+
blue: Math.round(blue * 255),
|
|
6135
|
+
alpha,
|
|
6136
|
+
};
|
|
6259
6137
|
}
|
|
6260
|
-
const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
|
|
6261
|
-
const filter = {
|
|
6262
|
-
...complex,
|
|
6263
|
-
getAnimatableNone: (v) => {
|
|
6264
|
-
const functions = v.match(functionRegex);
|
|
6265
|
-
return functions ? functions.map(applyDefaultFilter).join(" ") : v;
|
|
6266
|
-
},
|
|
6267
|
-
};
|
|
6268
6138
|
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6139
|
+
function mixImmediate(a, b) {
|
|
6140
|
+
return (p) => (p > 0 ? b : a);
|
|
6141
|
+
}
|
|
6142
|
+
|
|
6143
|
+
/*
|
|
6144
|
+
Value in range from progress
|
|
6145
|
+
|
|
6146
|
+
Given a lower limit and an upper limit, we return the value within
|
|
6147
|
+
that range as expressed by progress (usually a number from 0 to 1)
|
|
6148
|
+
|
|
6149
|
+
So progress = 0.5 would change
|
|
6150
|
+
|
|
6151
|
+
from -------- to
|
|
6152
|
+
|
|
6153
|
+
to
|
|
6154
|
+
|
|
6155
|
+
from ---- to
|
|
6156
|
+
|
|
6157
|
+
E.g. from = 10, to = 20, progress = 0.5 => 15
|
|
6158
|
+
|
|
6159
|
+
@param [number]: Lower limit of range
|
|
6160
|
+
@param [number]: Upper limit of range
|
|
6161
|
+
@param [number]: The progress between lower and upper limits expressed 0-1
|
|
6162
|
+
@return [number]: Value as calculated from progress within range (not limited within range)
|
|
6163
|
+
*/
|
|
6164
|
+
const mixNumber$1 = (from, to, progress) => {
|
|
6165
|
+
return from + (to - from) * progress;
|
|
6288
6166
|
};
|
|
6289
|
-
/**
|
|
6290
|
-
* Gets the default ValueType for the provided value key
|
|
6291
|
-
*/
|
|
6292
|
-
const getDefaultValueType = (key) => defaultValueTypes[key];
|
|
6293
6167
|
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6168
|
+
// Linear color space blending
|
|
6169
|
+
// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw
|
|
6170
|
+
// Demonstrated http://codepen.io/osublake/pen/xGVVaN
|
|
6171
|
+
const mixLinearColor = (from, to, v) => {
|
|
6172
|
+
const fromExpo = from * from;
|
|
6173
|
+
const expo = v * (to * to - fromExpo) + fromExpo;
|
|
6174
|
+
return expo < 0 ? 0 : Math.sqrt(expo);
|
|
6175
|
+
};
|
|
6176
|
+
const colorTypes = [hex, rgba, hsla];
|
|
6177
|
+
const getColorType = (v) => colorTypes.find((type) => type.test(v));
|
|
6178
|
+
function asRGBA(color) {
|
|
6179
|
+
const type = getColorType(color);
|
|
6180
|
+
warning(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);
|
|
6181
|
+
if (!Boolean(type))
|
|
6182
|
+
return false;
|
|
6183
|
+
let model = type.parse(color);
|
|
6184
|
+
if (type === hsla) {
|
|
6185
|
+
// TODO Remove this cast - needed since Motion's stricter typing
|
|
6186
|
+
model = hslaToRgba(model);
|
|
6187
|
+
}
|
|
6188
|
+
return model;
|
|
6302
6189
|
}
|
|
6190
|
+
const mixColor = (from, to) => {
|
|
6191
|
+
const fromRGBA = asRGBA(from);
|
|
6192
|
+
const toRGBA = asRGBA(to);
|
|
6193
|
+
if (!fromRGBA || !toRGBA) {
|
|
6194
|
+
return mixImmediate(from, to);
|
|
6195
|
+
}
|
|
6196
|
+
const blended = { ...fromRGBA };
|
|
6197
|
+
return (v) => {
|
|
6198
|
+
blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);
|
|
6199
|
+
blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);
|
|
6200
|
+
blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);
|
|
6201
|
+
blended.alpha = mixNumber$1(fromRGBA.alpha, toRGBA.alpha, v);
|
|
6202
|
+
return rgba.transform(blended);
|
|
6203
|
+
};
|
|
6204
|
+
};
|
|
6303
6205
|
|
|
6206
|
+
const invisibleValues = new Set(["none", "hidden"]);
|
|
6304
6207
|
/**
|
|
6305
|
-
*
|
|
6306
|
-
* "
|
|
6307
|
-
* the
|
|
6308
|
-
* zero equivalents, i.e. "#fff0" or "0px 0px".
|
|
6208
|
+
* Returns a function that, when provided a progress value between 0 and 1,
|
|
6209
|
+
* will return the "none" or "hidden" string only when the progress is that of
|
|
6210
|
+
* the origin or target.
|
|
6309
6211
|
*/
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
let animatableTemplate = undefined;
|
|
6314
|
-
while (i < unresolvedKeyframes.length && !animatableTemplate) {
|
|
6315
|
-
const keyframe = unresolvedKeyframes[i];
|
|
6316
|
-
if (typeof keyframe === "string" &&
|
|
6317
|
-
!invalidTemplates.has(keyframe) &&
|
|
6318
|
-
analyseComplexValue(keyframe).values.length) {
|
|
6319
|
-
animatableTemplate = unresolvedKeyframes[i];
|
|
6320
|
-
}
|
|
6321
|
-
i++;
|
|
6212
|
+
function mixVisibility(origin, target) {
|
|
6213
|
+
if (invisibleValues.has(origin)) {
|
|
6214
|
+
return (p) => (p <= 0 ? origin : target);
|
|
6322
6215
|
}
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
|
|
6326
|
-
}
|
|
6216
|
+
else {
|
|
6217
|
+
return (p) => (p >= 1 ? target : origin);
|
|
6327
6218
|
}
|
|
6328
6219
|
}
|
|
6329
6220
|
|
|
6330
|
-
const radToDeg = (rad) => (rad * 180) / Math.PI;
|
|
6331
|
-
const rotate = (v) => {
|
|
6332
|
-
const angle = radToDeg(Math.atan2(v[1], v[0]));
|
|
6333
|
-
return rebaseAngle(angle);
|
|
6334
|
-
};
|
|
6335
|
-
const matrix2dParsers = {
|
|
6336
|
-
x: 4,
|
|
6337
|
-
y: 5,
|
|
6338
|
-
translateX: 4,
|
|
6339
|
-
translateY: 5,
|
|
6340
|
-
scaleX: 0,
|
|
6341
|
-
scaleY: 3,
|
|
6342
|
-
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
|
|
6343
|
-
rotate,
|
|
6344
|
-
rotateZ: rotate,
|
|
6345
|
-
skewX: (v) => radToDeg(Math.atan(v[1])),
|
|
6346
|
-
skewY: (v) => radToDeg(Math.atan(v[2])),
|
|
6347
|
-
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
|
|
6348
|
-
};
|
|
6349
|
-
const rebaseAngle = (angle) => {
|
|
6350
|
-
angle = angle % 360;
|
|
6351
|
-
if (angle < 0)
|
|
6352
|
-
angle += 360;
|
|
6353
|
-
return angle;
|
|
6354
|
-
};
|
|
6355
|
-
const rotateZ = rotate;
|
|
6356
|
-
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
6357
|
-
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
|
|
6358
|
-
const matrix3dParsers = {
|
|
6359
|
-
x: 12,
|
|
6360
|
-
y: 13,
|
|
6361
|
-
z: 14,
|
|
6362
|
-
translateX: 12,
|
|
6363
|
-
translateY: 13,
|
|
6364
|
-
translateZ: 14,
|
|
6365
|
-
scaleX,
|
|
6366
|
-
scaleY,
|
|
6367
|
-
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
|
|
6368
|
-
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
|
|
6369
|
-
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
|
|
6370
|
-
rotateZ,
|
|
6371
|
-
rotate: rotateZ,
|
|
6372
|
-
skewX: (v) => radToDeg(Math.atan(v[4])),
|
|
6373
|
-
skewY: (v) => radToDeg(Math.atan(v[1])),
|
|
6374
|
-
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
|
|
6375
|
-
};
|
|
6376
|
-
function defaultTransformValue(name) {
|
|
6377
|
-
return name.includes("scale") ? 1 : 0;
|
|
6378
|
-
}
|
|
6379
|
-
function parseValueFromTransform(transform, name) {
|
|
6380
|
-
if (!transform || transform === "none") {
|
|
6381
|
-
return defaultTransformValue(name);
|
|
6382
|
-
}
|
|
6383
|
-
const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
|
|
6384
|
-
let parsers;
|
|
6385
|
-
let match;
|
|
6386
|
-
if (matrix3dMatch) {
|
|
6387
|
-
parsers = matrix3dParsers;
|
|
6388
|
-
match = matrix3dMatch;
|
|
6389
|
-
}
|
|
6390
|
-
else {
|
|
6391
|
-
const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
|
|
6392
|
-
parsers = matrix2dParsers;
|
|
6393
|
-
match = matrix2dMatch;
|
|
6394
|
-
}
|
|
6395
|
-
if (!match) {
|
|
6396
|
-
return defaultTransformValue(name);
|
|
6397
|
-
}
|
|
6398
|
-
const valueParser = parsers[name];
|
|
6399
|
-
const values = match[1].split(",").map(convertTransformToNumber);
|
|
6400
|
-
return typeof valueParser === "function"
|
|
6401
|
-
? valueParser(values)
|
|
6402
|
-
: values[valueParser];
|
|
6403
|
-
}
|
|
6404
|
-
const readTransformValue = (instance, name) => {
|
|
6405
|
-
const { transform = "none" } = getComputedStyle(instance);
|
|
6406
|
-
return parseValueFromTransform(transform, name);
|
|
6407
|
-
};
|
|
6408
|
-
function convertTransformToNumber(value) {
|
|
6409
|
-
return parseFloat(value.trim());
|
|
6410
|
-
}
|
|
6411
|
-
|
|
6412
|
-
const isNumOrPxType = (v) => v === number || v === px;
|
|
6413
|
-
const transformKeys = new Set(["x", "y", "z"]);
|
|
6414
|
-
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
|
6415
|
-
function removeNonTranslationalTransform(visualElement) {
|
|
6416
|
-
const removedTransforms = [];
|
|
6417
|
-
nonTranslationalTransformKeys.forEach((key) => {
|
|
6418
|
-
const value = visualElement.getValue(key);
|
|
6419
|
-
if (value !== undefined) {
|
|
6420
|
-
removedTransforms.push([key, value.get()]);
|
|
6421
|
-
value.set(key.startsWith("scale") ? 1 : 0);
|
|
6422
|
-
}
|
|
6423
|
-
});
|
|
6424
|
-
return removedTransforms;
|
|
6425
|
-
}
|
|
6426
|
-
const positionalValues = {
|
|
6427
|
-
// Dimensions
|
|
6428
|
-
width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
|
|
6429
|
-
height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
|
|
6430
|
-
top: (_bbox, { top }) => parseFloat(top),
|
|
6431
|
-
left: (_bbox, { left }) => parseFloat(left),
|
|
6432
|
-
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
|
6433
|
-
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
|
6434
|
-
// Transform
|
|
6435
|
-
x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
|
|
6436
|
-
y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
|
|
6437
|
-
};
|
|
6438
|
-
// Alias translate longform names
|
|
6439
|
-
positionalValues.translateX = positionalValues.x;
|
|
6440
|
-
positionalValues.translateY = positionalValues.y;
|
|
6441
|
-
|
|
6442
|
-
const toResolve = new Set();
|
|
6443
|
-
let isScheduled = false;
|
|
6444
|
-
let anyNeedsMeasurement = false;
|
|
6445
|
-
function measureAllKeyframes() {
|
|
6446
|
-
if (anyNeedsMeasurement) {
|
|
6447
|
-
const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);
|
|
6448
|
-
const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));
|
|
6449
|
-
const transformsToRestore = new Map();
|
|
6450
|
-
/**
|
|
6451
|
-
* Write pass
|
|
6452
|
-
* If we're measuring elements we want to remove bounding box-changing transforms.
|
|
6453
|
-
*/
|
|
6454
|
-
elementsToMeasure.forEach((element) => {
|
|
6455
|
-
const removedTransforms = removeNonTranslationalTransform(element);
|
|
6456
|
-
if (!removedTransforms.length)
|
|
6457
|
-
return;
|
|
6458
|
-
transformsToRestore.set(element, removedTransforms);
|
|
6459
|
-
element.render();
|
|
6460
|
-
});
|
|
6461
|
-
// Read
|
|
6462
|
-
resolversToMeasure.forEach((resolver) => resolver.measureInitialState());
|
|
6463
|
-
// Write
|
|
6464
|
-
elementsToMeasure.forEach((element) => {
|
|
6465
|
-
element.render();
|
|
6466
|
-
const restore = transformsToRestore.get(element);
|
|
6467
|
-
if (restore) {
|
|
6468
|
-
restore.forEach(([key, value]) => {
|
|
6469
|
-
element.getValue(key)?.set(value);
|
|
6470
|
-
});
|
|
6471
|
-
}
|
|
6472
|
-
});
|
|
6473
|
-
// Read
|
|
6474
|
-
resolversToMeasure.forEach((resolver) => resolver.measureEndState());
|
|
6475
|
-
// Write
|
|
6476
|
-
resolversToMeasure.forEach((resolver) => {
|
|
6477
|
-
if (resolver.suspendedScrollY !== undefined) {
|
|
6478
|
-
window.scrollTo(0, resolver.suspendedScrollY);
|
|
6479
|
-
}
|
|
6480
|
-
});
|
|
6481
|
-
}
|
|
6482
|
-
anyNeedsMeasurement = false;
|
|
6483
|
-
isScheduled = false;
|
|
6484
|
-
toResolve.forEach((resolver) => resolver.complete());
|
|
6485
|
-
toResolve.clear();
|
|
6486
|
-
}
|
|
6487
|
-
function readAllKeyframes() {
|
|
6488
|
-
toResolve.forEach((resolver) => {
|
|
6489
|
-
resolver.readKeyframes();
|
|
6490
|
-
if (resolver.needsMeasurement) {
|
|
6491
|
-
anyNeedsMeasurement = true;
|
|
6492
|
-
}
|
|
6493
|
-
});
|
|
6494
|
-
}
|
|
6495
|
-
function flushKeyframeResolvers() {
|
|
6496
|
-
readAllKeyframes();
|
|
6497
|
-
measureAllKeyframes();
|
|
6498
|
-
}
|
|
6499
|
-
class KeyframeResolver {
|
|
6500
|
-
constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {
|
|
6501
|
-
/**
|
|
6502
|
-
* Track whether this resolver has completed. Once complete, it never
|
|
6503
|
-
* needs to attempt keyframe resolution again.
|
|
6504
|
-
*/
|
|
6505
|
-
this.isComplete = false;
|
|
6506
|
-
/**
|
|
6507
|
-
* Track whether this resolver is async. If it is, it'll be added to the
|
|
6508
|
-
* resolver queue and flushed in the next frame. Resolvers that aren't going
|
|
6509
|
-
* to trigger read/write thrashing don't need to be async.
|
|
6510
|
-
*/
|
|
6511
|
-
this.isAsync = false;
|
|
6512
|
-
/**
|
|
6513
|
-
* Track whether this resolver needs to perform a measurement
|
|
6514
|
-
* to resolve its keyframes.
|
|
6515
|
-
*/
|
|
6516
|
-
this.needsMeasurement = false;
|
|
6517
|
-
/**
|
|
6518
|
-
* Track whether this resolver is currently scheduled to resolve
|
|
6519
|
-
* to allow it to be cancelled and resumed externally.
|
|
6520
|
-
*/
|
|
6521
|
-
this.isScheduled = false;
|
|
6522
|
-
this.unresolvedKeyframes = [...unresolvedKeyframes];
|
|
6523
|
-
this.onComplete = onComplete;
|
|
6524
|
-
this.name = name;
|
|
6525
|
-
this.motionValue = motionValue;
|
|
6526
|
-
this.element = element;
|
|
6527
|
-
this.isAsync = isAsync;
|
|
6528
|
-
}
|
|
6529
|
-
scheduleResolve() {
|
|
6530
|
-
this.isScheduled = true;
|
|
6531
|
-
if (this.isAsync) {
|
|
6532
|
-
toResolve.add(this);
|
|
6533
|
-
if (!isScheduled) {
|
|
6534
|
-
isScheduled = true;
|
|
6535
|
-
frame.read(readAllKeyframes);
|
|
6536
|
-
frame.resolveKeyframes(measureAllKeyframes);
|
|
6537
|
-
}
|
|
6538
|
-
}
|
|
6539
|
-
else {
|
|
6540
|
-
this.readKeyframes();
|
|
6541
|
-
this.complete();
|
|
6542
|
-
}
|
|
6543
|
-
}
|
|
6544
|
-
readKeyframes() {
|
|
6545
|
-
const { unresolvedKeyframes, name, element, motionValue } = this;
|
|
6546
|
-
/**
|
|
6547
|
-
* If a keyframe is null, we hydrate it either by reading it from
|
|
6548
|
-
* the instance, or propagating from previous keyframes.
|
|
6549
|
-
*/
|
|
6550
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6551
|
-
if (unresolvedKeyframes[i] === null) {
|
|
6552
|
-
/**
|
|
6553
|
-
* If the first keyframe is null, we need to find its value by sampling the element
|
|
6554
|
-
*/
|
|
6555
|
-
if (i === 0) {
|
|
6556
|
-
const currentValue = motionValue?.get();
|
|
6557
|
-
const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
6558
|
-
if (currentValue !== undefined) {
|
|
6559
|
-
unresolvedKeyframes[0] = currentValue;
|
|
6560
|
-
}
|
|
6561
|
-
else if (element && name) {
|
|
6562
|
-
const valueAsRead = element.readValue(name, finalKeyframe);
|
|
6563
|
-
if (valueAsRead !== undefined && valueAsRead !== null) {
|
|
6564
|
-
unresolvedKeyframes[0] = valueAsRead;
|
|
6565
|
-
}
|
|
6566
|
-
}
|
|
6567
|
-
if (unresolvedKeyframes[0] === undefined) {
|
|
6568
|
-
unresolvedKeyframes[0] = finalKeyframe;
|
|
6569
|
-
}
|
|
6570
|
-
if (motionValue && currentValue === undefined) {
|
|
6571
|
-
motionValue.set(unresolvedKeyframes[0]);
|
|
6572
|
-
}
|
|
6573
|
-
}
|
|
6574
|
-
else {
|
|
6575
|
-
unresolvedKeyframes[i] = unresolvedKeyframes[i - 1];
|
|
6576
|
-
}
|
|
6577
|
-
}
|
|
6578
|
-
}
|
|
6579
|
-
}
|
|
6580
|
-
setFinalKeyframe() { }
|
|
6581
|
-
measureInitialState() { }
|
|
6582
|
-
renderEndStyles() { }
|
|
6583
|
-
measureEndState() { }
|
|
6584
|
-
complete() {
|
|
6585
|
-
this.isComplete = true;
|
|
6586
|
-
this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);
|
|
6587
|
-
toResolve.delete(this);
|
|
6588
|
-
}
|
|
6589
|
-
cancel() {
|
|
6590
|
-
if (!this.isComplete) {
|
|
6591
|
-
this.isScheduled = false;
|
|
6592
|
-
toResolve.delete(this);
|
|
6593
|
-
}
|
|
6594
|
-
}
|
|
6595
|
-
resume() {
|
|
6596
|
-
if (!this.isComplete)
|
|
6597
|
-
this.scheduleResolve();
|
|
6598
|
-
}
|
|
6599
|
-
}
|
|
6600
|
-
|
|
6601
|
-
/**
|
|
6602
|
-
* Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
|
|
6603
|
-
*/
|
|
6604
|
-
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
|
|
6605
|
-
|
|
6606
|
-
/**
|
|
6607
|
-
* Parse Framer's special CSS variable format into a CSS token and a fallback.
|
|
6608
|
-
*
|
|
6609
|
-
* ```
|
|
6610
|
-
* `var(--foo, #fff)` => [`--foo`, '#fff']
|
|
6611
|
-
* ```
|
|
6612
|
-
*
|
|
6613
|
-
* @param current
|
|
6614
|
-
*/
|
|
6615
|
-
const splitCSSVariableRegex =
|
|
6616
|
-
// eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
|
|
6617
|
-
/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
|
|
6618
|
-
function parseCSSVariable(current) {
|
|
6619
|
-
const match = splitCSSVariableRegex.exec(current);
|
|
6620
|
-
if (!match)
|
|
6621
|
-
return [,];
|
|
6622
|
-
const [, token1, token2, fallback] = match;
|
|
6623
|
-
return [`--${token1 ?? token2}`, fallback];
|
|
6624
|
-
}
|
|
6625
|
-
const maxDepth = 4;
|
|
6626
|
-
function getVariableValue(current, element, depth = 1) {
|
|
6627
|
-
invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
|
|
6628
|
-
const [token, fallback] = parseCSSVariable(current);
|
|
6629
|
-
// No CSS variable detected
|
|
6630
|
-
if (!token)
|
|
6631
|
-
return;
|
|
6632
|
-
// Attempt to read this CSS variable off the element
|
|
6633
|
-
const resolved = window.getComputedStyle(element).getPropertyValue(token);
|
|
6634
|
-
if (resolved) {
|
|
6635
|
-
const trimmed = resolved.trim();
|
|
6636
|
-
return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
|
|
6637
|
-
}
|
|
6638
|
-
return isCSSVariableToken(fallback)
|
|
6639
|
-
? getVariableValue(fallback, element, depth + 1)
|
|
6640
|
-
: fallback;
|
|
6641
|
-
}
|
|
6642
|
-
|
|
6643
|
-
/**
|
|
6644
|
-
* Tests a provided value against a ValueType
|
|
6645
|
-
*/
|
|
6646
|
-
const testValueType = (v) => (type) => type.test(v);
|
|
6647
|
-
|
|
6648
|
-
/**
|
|
6649
|
-
* ValueType for "auto"
|
|
6650
|
-
*/
|
|
6651
|
-
const auto = {
|
|
6652
|
-
test: (v) => v === "auto",
|
|
6653
|
-
parse: (v) => v,
|
|
6654
|
-
};
|
|
6655
|
-
|
|
6656
|
-
/**
|
|
6657
|
-
* A list of value types commonly used for dimensions
|
|
6658
|
-
*/
|
|
6659
|
-
const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
|
|
6660
|
-
/**
|
|
6661
|
-
* Tests a dimensional value against the list of dimension ValueTypes
|
|
6662
|
-
*/
|
|
6663
|
-
const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
|
|
6664
|
-
|
|
6665
|
-
class DOMKeyframesResolver extends KeyframeResolver {
|
|
6666
|
-
constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
|
|
6667
|
-
super(unresolvedKeyframes, onComplete, name, motionValue, element, true);
|
|
6668
|
-
}
|
|
6669
|
-
readKeyframes() {
|
|
6670
|
-
const { unresolvedKeyframes, element, name } = this;
|
|
6671
|
-
if (!element || !element.current)
|
|
6672
|
-
return;
|
|
6673
|
-
super.readKeyframes();
|
|
6674
|
-
/**
|
|
6675
|
-
* If any keyframe is a CSS variable, we need to find its value by sampling the element
|
|
6676
|
-
*/
|
|
6677
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6678
|
-
let keyframe = unresolvedKeyframes[i];
|
|
6679
|
-
if (typeof keyframe === "string") {
|
|
6680
|
-
keyframe = keyframe.trim();
|
|
6681
|
-
if (isCSSVariableToken(keyframe)) {
|
|
6682
|
-
const resolved = getVariableValue(keyframe, element.current);
|
|
6683
|
-
if (resolved !== undefined) {
|
|
6684
|
-
unresolvedKeyframes[i] = resolved;
|
|
6685
|
-
}
|
|
6686
|
-
if (i === unresolvedKeyframes.length - 1) {
|
|
6687
|
-
this.finalKeyframe = keyframe;
|
|
6688
|
-
}
|
|
6689
|
-
}
|
|
6690
|
-
}
|
|
6691
|
-
}
|
|
6692
|
-
/**
|
|
6693
|
-
* Resolve "none" values. We do this potentially twice - once before and once after measuring keyframes.
|
|
6694
|
-
* This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which
|
|
6695
|
-
* have a far bigger performance impact.
|
|
6696
|
-
*/
|
|
6697
|
-
this.resolveNoneKeyframes();
|
|
6698
|
-
/**
|
|
6699
|
-
* Check to see if unit type has changed. If so schedule jobs that will
|
|
6700
|
-
* temporarily set styles to the destination keyframes.
|
|
6701
|
-
* Skip if we have more than two keyframes or this isn't a positional value.
|
|
6702
|
-
* TODO: We can throw if there are multiple keyframes and the value type changes.
|
|
6703
|
-
*/
|
|
6704
|
-
if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {
|
|
6705
|
-
return;
|
|
6706
|
-
}
|
|
6707
|
-
const [origin, target] = unresolvedKeyframes;
|
|
6708
|
-
const originType = findDimensionValueType(origin);
|
|
6709
|
-
const targetType = findDimensionValueType(target);
|
|
6710
|
-
/**
|
|
6711
|
-
* Either we don't recognise these value types or we can animate between them.
|
|
6712
|
-
*/
|
|
6713
|
-
if (originType === targetType)
|
|
6714
|
-
return;
|
|
6715
|
-
/**
|
|
6716
|
-
* If both values are numbers or pixels, we can animate between them by
|
|
6717
|
-
* converting them to numbers.
|
|
6718
|
-
*/
|
|
6719
|
-
if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {
|
|
6720
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6721
|
-
const value = unresolvedKeyframes[i];
|
|
6722
|
-
if (typeof value === "string") {
|
|
6723
|
-
unresolvedKeyframes[i] = parseFloat(value);
|
|
6724
|
-
}
|
|
6725
|
-
}
|
|
6726
|
-
}
|
|
6727
|
-
else {
|
|
6728
|
-
/**
|
|
6729
|
-
* Else, the only way to resolve this is by measuring the element.
|
|
6730
|
-
*/
|
|
6731
|
-
this.needsMeasurement = true;
|
|
6732
|
-
}
|
|
6733
|
-
}
|
|
6734
|
-
resolveNoneKeyframes() {
|
|
6735
|
-
const { unresolvedKeyframes, name } = this;
|
|
6736
|
-
const noneKeyframeIndexes = [];
|
|
6737
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6738
|
-
if (isNone(unresolvedKeyframes[i])) {
|
|
6739
|
-
noneKeyframeIndexes.push(i);
|
|
6740
|
-
}
|
|
6741
|
-
}
|
|
6742
|
-
if (noneKeyframeIndexes.length) {
|
|
6743
|
-
makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);
|
|
6744
|
-
}
|
|
6745
|
-
}
|
|
6746
|
-
measureInitialState() {
|
|
6747
|
-
const { element, unresolvedKeyframes, name } = this;
|
|
6748
|
-
if (!element || !element.current)
|
|
6749
|
-
return;
|
|
6750
|
-
if (name === "height") {
|
|
6751
|
-
this.suspendedScrollY = window.pageYOffset;
|
|
6752
|
-
}
|
|
6753
|
-
this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
6754
|
-
unresolvedKeyframes[0] = this.measuredOrigin;
|
|
6755
|
-
// Set final key frame to measure after next render
|
|
6756
|
-
const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
6757
|
-
if (measureKeyframe !== undefined) {
|
|
6758
|
-
element.getValue(name, measureKeyframe).jump(measureKeyframe, false);
|
|
6759
|
-
}
|
|
6760
|
-
}
|
|
6761
|
-
measureEndState() {
|
|
6762
|
-
const { element, name, unresolvedKeyframes } = this;
|
|
6763
|
-
if (!element || !element.current)
|
|
6764
|
-
return;
|
|
6765
|
-
const value = element.getValue(name);
|
|
6766
|
-
value && value.jump(this.measuredOrigin, false);
|
|
6767
|
-
const finalKeyframeIndex = unresolvedKeyframes.length - 1;
|
|
6768
|
-
const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];
|
|
6769
|
-
unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
6770
|
-
if (finalKeyframe !== null && this.finalKeyframe === undefined) {
|
|
6771
|
-
this.finalKeyframe = finalKeyframe;
|
|
6772
|
-
}
|
|
6773
|
-
// If we removed transform values, reapply them before the next render
|
|
6774
|
-
if (this.removedTransforms?.length) {
|
|
6775
|
-
this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {
|
|
6776
|
-
element
|
|
6777
|
-
.getValue(unsetTransformName)
|
|
6778
|
-
.set(unsetTransformValue);
|
|
6779
|
-
});
|
|
6780
|
-
}
|
|
6781
|
-
this.resolveNoneKeyframes();
|
|
6782
|
-
}
|
|
6783
|
-
}
|
|
6784
|
-
|
|
6785
|
-
/**
|
|
6786
|
-
* Check if a value is animatable. Examples:
|
|
6787
|
-
*
|
|
6788
|
-
* ✅: 100, "100px", "#fff"
|
|
6789
|
-
* ❌: "block", "url(2.jpg)"
|
|
6790
|
-
* @param value
|
|
6791
|
-
*
|
|
6792
|
-
* @internal
|
|
6793
|
-
*/
|
|
6794
|
-
const isAnimatable = (value, name) => {
|
|
6795
|
-
// If the list of keys tat might be non-animatable grows, replace with Set
|
|
6796
|
-
if (name === "zIndex")
|
|
6797
|
-
return false;
|
|
6798
|
-
// If it's a number or a keyframes array, we can animate it. We might at some point
|
|
6799
|
-
// need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
|
|
6800
|
-
// but for now lets leave it like this for performance reasons
|
|
6801
|
-
if (typeof value === "number" || Array.isArray(value))
|
|
6802
|
-
return true;
|
|
6803
|
-
if (typeof value === "string" && // It's animatable if we have a string
|
|
6804
|
-
(complex.test(value) || value === "0") && // And it contains numbers and/or colors
|
|
6805
|
-
!value.startsWith("url(") // Unless it starts with "url("
|
|
6806
|
-
) {
|
|
6807
|
-
return true;
|
|
6808
|
-
}
|
|
6809
|
-
return false;
|
|
6810
|
-
};
|
|
6811
|
-
|
|
6812
|
-
function isGenerator(type) {
|
|
6813
|
-
return typeof type === "function" && "applyToOptions" in type;
|
|
6814
|
-
}
|
|
6815
|
-
|
|
6816
|
-
function hasKeyframesChanged(keyframes) {
|
|
6817
|
-
const current = keyframes[0];
|
|
6818
|
-
if (keyframes.length === 1)
|
|
6819
|
-
return true;
|
|
6820
|
-
for (let i = 0; i < keyframes.length; i++) {
|
|
6821
|
-
if (keyframes[i] !== current)
|
|
6822
|
-
return true;
|
|
6823
|
-
}
|
|
6824
|
-
}
|
|
6825
|
-
function canAnimate(keyframes, name, type, velocity) {
|
|
6826
|
-
/**
|
|
6827
|
-
* Check if we're able to animate between the start and end keyframes,
|
|
6828
|
-
* and throw a warning if we're attempting to animate between one that's
|
|
6829
|
-
* animatable and another that isn't.
|
|
6830
|
-
*/
|
|
6831
|
-
const originKeyframe = keyframes[0];
|
|
6832
|
-
if (originKeyframe === null)
|
|
6833
|
-
return false;
|
|
6834
|
-
/**
|
|
6835
|
-
* These aren't traditionally animatable but we do support them.
|
|
6836
|
-
* In future we could look into making this more generic or replacing
|
|
6837
|
-
* this function with mix() === mixImmediate
|
|
6838
|
-
*/
|
|
6839
|
-
if (name === "display" || name === "visibility")
|
|
6840
|
-
return true;
|
|
6841
|
-
const targetKeyframe = keyframes[keyframes.length - 1];
|
|
6842
|
-
const isOriginAnimatable = isAnimatable(originKeyframe, name);
|
|
6843
|
-
const isTargetAnimatable = isAnimatable(targetKeyframe, name);
|
|
6844
|
-
warning(isOriginAnimatable === isTargetAnimatable, `You are trying to animate ${name} from "${originKeyframe}" to "${targetKeyframe}". ${originKeyframe} is not an animatable value - to enable this animation set ${originKeyframe} to a value animatable to ${targetKeyframe} via the \`style\` property.`);
|
|
6845
|
-
// Always skip if any of these are true
|
|
6846
|
-
if (!isOriginAnimatable || !isTargetAnimatable) {
|
|
6847
|
-
return false;
|
|
6848
|
-
}
|
|
6849
|
-
return (hasKeyframesChanged(keyframes) ||
|
|
6850
|
-
((type === "spring" || isGenerator(type)) && velocity));
|
|
6851
|
-
}
|
|
6852
|
-
|
|
6853
|
-
const isNotNull = (value) => value !== null;
|
|
6854
|
-
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
|
|
6855
|
-
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
6856
|
-
const index = repeat && repeatType !== "loop" && repeat % 2 === 1
|
|
6857
|
-
? 0
|
|
6858
|
-
: resolvedKeyframes.length - 1;
|
|
6859
|
-
return !index || finalKeyframe === undefined
|
|
6860
|
-
? resolvedKeyframes[index]
|
|
6861
|
-
: finalKeyframe;
|
|
6862
|
-
}
|
|
6863
|
-
|
|
6864
|
-
/**
|
|
6865
|
-
* Maximum time allowed between an animation being created and it being
|
|
6866
|
-
* resolved for us to use the latter as the start time.
|
|
6867
|
-
*
|
|
6868
|
-
* This is to ensure that while we prefer to "start" an animation as soon
|
|
6869
|
-
* as it's triggered, we also want to avoid a visual jump if there's a big delay
|
|
6870
|
-
* between these two moments.
|
|
6871
|
-
*/
|
|
6872
|
-
const MAX_RESOLVE_DELAY = 40;
|
|
6873
|
-
class BaseAnimation {
|
|
6874
|
-
constructor({ autoplay = true, delay = 0, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", ...options }) {
|
|
6875
|
-
// Track whether the animation has been stopped. Stopped animations won't restart.
|
|
6876
|
-
this.isStopped = false;
|
|
6877
|
-
this.hasAttemptedResolve = false;
|
|
6878
|
-
this.createdAt = time.now();
|
|
6879
|
-
this.options = {
|
|
6880
|
-
autoplay,
|
|
6881
|
-
delay,
|
|
6882
|
-
type,
|
|
6883
|
-
repeat,
|
|
6884
|
-
repeatDelay,
|
|
6885
|
-
repeatType,
|
|
6886
|
-
...options,
|
|
6887
|
-
};
|
|
6888
|
-
this.updateFinishedPromise();
|
|
6889
|
-
}
|
|
6890
|
-
/**
|
|
6891
|
-
* This method uses the createdAt and resolvedAt to calculate the
|
|
6892
|
-
* animation startTime. *Ideally*, we would use the createdAt time as t=0
|
|
6893
|
-
* as the following frame would then be the first frame of the animation in
|
|
6894
|
-
* progress, which would feel snappier.
|
|
6895
|
-
*
|
|
6896
|
-
* However, if there's a delay (main thread work) between the creation of
|
|
6897
|
-
* the animation and the first commited frame, we prefer to use resolvedAt
|
|
6898
|
-
* to avoid a sudden jump into the animation.
|
|
6899
|
-
*/
|
|
6900
|
-
calcStartTime() {
|
|
6901
|
-
if (!this.resolvedAt)
|
|
6902
|
-
return this.createdAt;
|
|
6903
|
-
return this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY
|
|
6904
|
-
? this.resolvedAt
|
|
6905
|
-
: this.createdAt;
|
|
6906
|
-
}
|
|
6907
|
-
/**
|
|
6908
|
-
* A getter for resolved data. If keyframes are not yet resolved, accessing
|
|
6909
|
-
* this.resolved will synchronously flush all pending keyframe resolvers.
|
|
6910
|
-
* This is a deoptimisation, but at its worst still batches read/writes.
|
|
6911
|
-
*/
|
|
6912
|
-
get resolved() {
|
|
6913
|
-
if (!this._resolved && !this.hasAttemptedResolve) {
|
|
6914
|
-
flushKeyframeResolvers();
|
|
6915
|
-
}
|
|
6916
|
-
return this._resolved;
|
|
6917
|
-
}
|
|
6918
|
-
/**
|
|
6919
|
-
* A method to be called when the keyframes resolver completes. This method
|
|
6920
|
-
* will check if its possible to run the animation and, if not, skip it.
|
|
6921
|
-
* Otherwise, it will call initPlayback on the implementing class.
|
|
6922
|
-
*/
|
|
6923
|
-
onKeyframesResolved(keyframes, finalKeyframe) {
|
|
6924
|
-
this.resolvedAt = time.now();
|
|
6925
|
-
this.hasAttemptedResolve = true;
|
|
6926
|
-
const { name, type, velocity, delay, onComplete, onUpdate, isGenerator, } = this.options;
|
|
6927
|
-
/**
|
|
6928
|
-
* If we can't animate this value with the resolved keyframes
|
|
6929
|
-
* then we should complete it immediately.
|
|
6930
|
-
*/
|
|
6931
|
-
if (!isGenerator && !canAnimate(keyframes, name, type, velocity)) {
|
|
6932
|
-
// Finish immediately
|
|
6933
|
-
if (!delay) {
|
|
6934
|
-
onUpdate &&
|
|
6935
|
-
onUpdate(getFinalKeyframe(keyframes, this.options, finalKeyframe));
|
|
6936
|
-
onComplete && onComplete();
|
|
6937
|
-
this.resolveFinishedPromise();
|
|
6938
|
-
return;
|
|
6939
|
-
}
|
|
6940
|
-
// Finish after a delay
|
|
6941
|
-
else {
|
|
6942
|
-
this.options.duration = 0;
|
|
6943
|
-
}
|
|
6944
|
-
}
|
|
6945
|
-
const resolvedAnimation = this.initPlayback(keyframes, finalKeyframe);
|
|
6946
|
-
if (resolvedAnimation === false)
|
|
6947
|
-
return;
|
|
6948
|
-
this._resolved = {
|
|
6949
|
-
keyframes,
|
|
6950
|
-
finalKeyframe,
|
|
6951
|
-
...resolvedAnimation,
|
|
6952
|
-
};
|
|
6953
|
-
this.onPostResolved();
|
|
6954
|
-
}
|
|
6955
|
-
onPostResolved() { }
|
|
6956
|
-
/**
|
|
6957
|
-
* Allows the returned animation to be awaited or promise-chained. Currently
|
|
6958
|
-
* resolves when the animation finishes at all but in a future update could/should
|
|
6959
|
-
* reject if its cancels.
|
|
6960
|
-
*/
|
|
6961
|
-
then(resolve, reject) {
|
|
6962
|
-
return this.currentFinishedPromise.then(resolve, reject);
|
|
6963
|
-
}
|
|
6964
|
-
flatten() {
|
|
6965
|
-
if (!this.options.allowFlatten)
|
|
6966
|
-
return;
|
|
6967
|
-
this.options.type = "keyframes";
|
|
6968
|
-
this.options.ease = "linear";
|
|
6969
|
-
}
|
|
6970
|
-
updateFinishedPromise() {
|
|
6971
|
-
this.currentFinishedPromise = new Promise((resolve) => {
|
|
6972
|
-
this.resolveFinishedPromise = resolve;
|
|
6973
|
-
});
|
|
6974
|
-
}
|
|
6975
|
-
}
|
|
6976
|
-
|
|
6977
|
-
/*
|
|
6978
|
-
Value in range from progress
|
|
6979
|
-
|
|
6980
|
-
Given a lower limit and an upper limit, we return the value within
|
|
6981
|
-
that range as expressed by progress (usually a number from 0 to 1)
|
|
6982
|
-
|
|
6983
|
-
So progress = 0.5 would change
|
|
6984
|
-
|
|
6985
|
-
from -------- to
|
|
6986
|
-
|
|
6987
|
-
to
|
|
6988
|
-
|
|
6989
|
-
from ---- to
|
|
6990
|
-
|
|
6991
|
-
E.g. from = 10, to = 20, progress = 0.5 => 15
|
|
6992
|
-
|
|
6993
|
-
@param [number]: Lower limit of range
|
|
6994
|
-
@param [number]: Upper limit of range
|
|
6995
|
-
@param [number]: The progress between lower and upper limits expressed 0-1
|
|
6996
|
-
@return [number]: Value as calculated from progress within range (not limited within range)
|
|
6997
|
-
*/
|
|
6998
|
-
const mixNumber$1 = (from, to, progress) => {
|
|
6999
|
-
return from + (to - from) * progress;
|
|
7000
|
-
};
|
|
7001
|
-
|
|
7002
|
-
// Adapted from https://gist.github.com/mjackson/5311256
|
|
7003
|
-
function hueToRgb(p, q, t) {
|
|
7004
|
-
if (t < 0)
|
|
7005
|
-
t += 1;
|
|
7006
|
-
if (t > 1)
|
|
7007
|
-
t -= 1;
|
|
7008
|
-
if (t < 1 / 6)
|
|
7009
|
-
return p + (q - p) * 6 * t;
|
|
7010
|
-
if (t < 1 / 2)
|
|
7011
|
-
return q;
|
|
7012
|
-
if (t < 2 / 3)
|
|
7013
|
-
return p + (q - p) * (2 / 3 - t) * 6;
|
|
7014
|
-
return p;
|
|
7015
|
-
}
|
|
7016
|
-
function hslaToRgba({ hue, saturation, lightness, alpha }) {
|
|
7017
|
-
hue /= 360;
|
|
7018
|
-
saturation /= 100;
|
|
7019
|
-
lightness /= 100;
|
|
7020
|
-
let red = 0;
|
|
7021
|
-
let green = 0;
|
|
7022
|
-
let blue = 0;
|
|
7023
|
-
if (!saturation) {
|
|
7024
|
-
red = green = blue = lightness;
|
|
7025
|
-
}
|
|
7026
|
-
else {
|
|
7027
|
-
const q = lightness < 0.5
|
|
7028
|
-
? lightness * (1 + saturation)
|
|
7029
|
-
: lightness + saturation - lightness * saturation;
|
|
7030
|
-
const p = 2 * lightness - q;
|
|
7031
|
-
red = hueToRgb(p, q, hue + 1 / 3);
|
|
7032
|
-
green = hueToRgb(p, q, hue);
|
|
7033
|
-
blue = hueToRgb(p, q, hue - 1 / 3);
|
|
7034
|
-
}
|
|
7035
|
-
return {
|
|
7036
|
-
red: Math.round(red * 255),
|
|
7037
|
-
green: Math.round(green * 255),
|
|
7038
|
-
blue: Math.round(blue * 255),
|
|
7039
|
-
alpha,
|
|
7040
|
-
};
|
|
7041
|
-
}
|
|
7042
|
-
|
|
7043
|
-
function mixImmediate(a, b) {
|
|
7044
|
-
return (p) => (p > 0 ? b : a);
|
|
7045
|
-
}
|
|
7046
|
-
|
|
7047
|
-
// Linear color space blending
|
|
7048
|
-
// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw
|
|
7049
|
-
// Demonstrated http://codepen.io/osublake/pen/xGVVaN
|
|
7050
|
-
const mixLinearColor = (from, to, v) => {
|
|
7051
|
-
const fromExpo = from * from;
|
|
7052
|
-
const expo = v * (to * to - fromExpo) + fromExpo;
|
|
7053
|
-
return expo < 0 ? 0 : Math.sqrt(expo);
|
|
7054
|
-
};
|
|
7055
|
-
const colorTypes = [hex, rgba, hsla];
|
|
7056
|
-
const getColorType = (v) => colorTypes.find((type) => type.test(v));
|
|
7057
|
-
function asRGBA(color) {
|
|
7058
|
-
const type = getColorType(color);
|
|
7059
|
-
warning(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);
|
|
7060
|
-
if (!Boolean(type))
|
|
7061
|
-
return false;
|
|
7062
|
-
let model = type.parse(color);
|
|
7063
|
-
if (type === hsla) {
|
|
7064
|
-
// TODO Remove this cast - needed since Motion's stricter typing
|
|
7065
|
-
model = hslaToRgba(model);
|
|
7066
|
-
}
|
|
7067
|
-
return model;
|
|
7068
|
-
}
|
|
7069
|
-
const mixColor = (from, to) => {
|
|
7070
|
-
const fromRGBA = asRGBA(from);
|
|
7071
|
-
const toRGBA = asRGBA(to);
|
|
7072
|
-
if (!fromRGBA || !toRGBA) {
|
|
7073
|
-
return mixImmediate(from, to);
|
|
7074
|
-
}
|
|
7075
|
-
const blended = { ...fromRGBA };
|
|
7076
|
-
return (v) => {
|
|
7077
|
-
blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);
|
|
7078
|
-
blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);
|
|
7079
|
-
blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);
|
|
7080
|
-
blended.alpha = mixNumber$1(fromRGBA.alpha, toRGBA.alpha, v);
|
|
7081
|
-
return rgba.transform(blended);
|
|
7082
|
-
};
|
|
7083
|
-
};
|
|
7084
|
-
|
|
7085
6221
|
/**
|
|
7086
6222
|
* Pipe
|
|
7087
6223
|
* Compose other transformers to run linearily
|
|
@@ -7092,21 +6228,6 @@ const mixColor = (from, to) => {
|
|
|
7092
6228
|
const combineFunctions = (a, b) => (v) => b(a(v));
|
|
7093
6229
|
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
|
7094
6230
|
|
|
7095
|
-
const invisibleValues = new Set(["none", "hidden"]);
|
|
7096
|
-
/**
|
|
7097
|
-
* Returns a function that, when provided a progress value between 0 and 1,
|
|
7098
|
-
* will return the "none" or "hidden" string only when the progress is that of
|
|
7099
|
-
* the origin or target.
|
|
7100
|
-
*/
|
|
7101
|
-
function mixVisibility(origin, target) {
|
|
7102
|
-
if (invisibleValues.has(origin)) {
|
|
7103
|
-
return (p) => (p <= 0 ? origin : target);
|
|
7104
|
-
}
|
|
7105
|
-
else {
|
|
7106
|
-
return (p) => (p >= 1 ? target : origin);
|
|
7107
|
-
}
|
|
7108
|
-
}
|
|
7109
|
-
|
|
7110
6231
|
function mixNumber(a, b) {
|
|
7111
6232
|
return (p) => mixNumber$1(a, b, p);
|
|
7112
6233
|
}
|
|
@@ -7187,16 +6308,71 @@ const mixComplex = (origin, target) => {
|
|
|
7187
6308
|
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.`);
|
|
7188
6309
|
return mixImmediate(origin, target);
|
|
7189
6310
|
}
|
|
7190
|
-
};
|
|
6311
|
+
};
|
|
6312
|
+
|
|
6313
|
+
function mix(from, to, p) {
|
|
6314
|
+
if (typeof from === "number" &&
|
|
6315
|
+
typeof to === "number" &&
|
|
6316
|
+
typeof p === "number") {
|
|
6317
|
+
return mixNumber$1(from, to, p);
|
|
6318
|
+
}
|
|
6319
|
+
const mixer = getMixer(from);
|
|
6320
|
+
return mixer(from, to);
|
|
6321
|
+
}
|
|
6322
|
+
|
|
6323
|
+
const frameloopDriver = (update) => {
|
|
6324
|
+
const passTimestamp = ({ timestamp }) => update(timestamp);
|
|
6325
|
+
return {
|
|
6326
|
+
start: () => frame.update(passTimestamp, true),
|
|
6327
|
+
stop: () => cancelFrame(passTimestamp),
|
|
6328
|
+
/**
|
|
6329
|
+
* If we're processing this frame we can use the
|
|
6330
|
+
* framelocked timestamp to keep things in sync.
|
|
6331
|
+
*/
|
|
6332
|
+
now: () => (frameData.isProcessing ? frameData.timestamp : time.now()),
|
|
6333
|
+
};
|
|
6334
|
+
};
|
|
6335
|
+
|
|
6336
|
+
const generateLinearEasing = (easing, duration, // as milliseconds
|
|
6337
|
+
resolution = 10 // as milliseconds
|
|
6338
|
+
) => {
|
|
6339
|
+
let points = "";
|
|
6340
|
+
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
6341
|
+
for (let i = 0; i < numPoints; i++) {
|
|
6342
|
+
points += easing(i / (numPoints - 1)) + ", ";
|
|
6343
|
+
}
|
|
6344
|
+
return `linear(${points.substring(0, points.length - 2)})`;
|
|
6345
|
+
};
|
|
6346
|
+
|
|
6347
|
+
/**
|
|
6348
|
+
* Implement a practical max duration for keyframe generation
|
|
6349
|
+
* to prevent infinite loops
|
|
6350
|
+
*/
|
|
6351
|
+
const maxGeneratorDuration = 20000;
|
|
6352
|
+
function calcGeneratorDuration(generator) {
|
|
6353
|
+
let duration = 0;
|
|
6354
|
+
const timeStep = 50;
|
|
6355
|
+
let state = generator.next(duration);
|
|
6356
|
+
while (!state.done && duration < maxGeneratorDuration) {
|
|
6357
|
+
duration += timeStep;
|
|
6358
|
+
state = generator.next(duration);
|
|
6359
|
+
}
|
|
6360
|
+
return duration >= maxGeneratorDuration ? Infinity : duration;
|
|
6361
|
+
}
|
|
7191
6362
|
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
6363
|
+
/**
|
|
6364
|
+
* Create a progress => progress easing function from a generator.
|
|
6365
|
+
*/
|
|
6366
|
+
function createGeneratorEasing(options, scale = 100, createGenerator) {
|
|
6367
|
+
const generator = createGenerator({ ...options, keyframes: [0, scale] });
|
|
6368
|
+
const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
|
|
6369
|
+
return {
|
|
6370
|
+
type: "keyframes",
|
|
6371
|
+
ease: (progress) => {
|
|
6372
|
+
return generator.next(duration * progress).value / scale;
|
|
6373
|
+
},
|
|
6374
|
+
duration: millisecondsToSeconds(duration),
|
|
6375
|
+
};
|
|
7200
6376
|
}
|
|
7201
6377
|
|
|
7202
6378
|
const velocitySampleDuration = 5; // ms
|
|
@@ -7231,17 +6407,6 @@ const springDefaults = {
|
|
|
7231
6407
|
maxDamping: 1,
|
|
7232
6408
|
};
|
|
7233
6409
|
|
|
7234
|
-
/**
|
|
7235
|
-
* Converts seconds to milliseconds
|
|
7236
|
-
*
|
|
7237
|
-
* @param seconds - Time in seconds.
|
|
7238
|
-
* @return milliseconds - Converted time in milliseconds.
|
|
7239
|
-
*/
|
|
7240
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
7241
|
-
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
7242
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
7243
|
-
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
7244
|
-
|
|
7245
6410
|
const safeMin = 0.001;
|
|
7246
6411
|
function findSpring({ duration = springDefaults.duration, bounce = springDefaults.bounce, velocity = springDefaults.velocity, mass = springDefaults.mass, }) {
|
|
7247
6412
|
let envelope;
|
|
@@ -7322,81 +6487,6 @@ function calcAngularFreq(undampedFreq, dampingRatio) {
|
|
|
7322
6487
|
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
7323
6488
|
}
|
|
7324
6489
|
|
|
7325
|
-
/**
|
|
7326
|
-
* Implement a practical max duration for keyframe generation
|
|
7327
|
-
* to prevent infinite loops
|
|
7328
|
-
*/
|
|
7329
|
-
const maxGeneratorDuration = 20000;
|
|
7330
|
-
function calcGeneratorDuration(generator) {
|
|
7331
|
-
let duration = 0;
|
|
7332
|
-
const timeStep = 50;
|
|
7333
|
-
let state = generator.next(duration);
|
|
7334
|
-
while (!state.done && duration < maxGeneratorDuration) {
|
|
7335
|
-
duration += timeStep;
|
|
7336
|
-
state = generator.next(duration);
|
|
7337
|
-
}
|
|
7338
|
-
return duration >= maxGeneratorDuration ? Infinity : duration;
|
|
7339
|
-
}
|
|
7340
|
-
|
|
7341
|
-
/**
|
|
7342
|
-
* Create a progress => progress easing function from a generator.
|
|
7343
|
-
*/
|
|
7344
|
-
function createGeneratorEasing(options, scale = 100, createGenerator) {
|
|
7345
|
-
const generator = createGenerator({ ...options, keyframes: [0, scale] });
|
|
7346
|
-
const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
|
|
7347
|
-
return {
|
|
7348
|
-
type: "keyframes",
|
|
7349
|
-
ease: (progress) => {
|
|
7350
|
-
return generator.next(duration * progress).value / scale;
|
|
7351
|
-
},
|
|
7352
|
-
duration: millisecondsToSeconds(duration),
|
|
7353
|
-
};
|
|
7354
|
-
}
|
|
7355
|
-
|
|
7356
|
-
/**
|
|
7357
|
-
* Add the ability for test suites to manually set support flags
|
|
7358
|
-
* to better test more environments.
|
|
7359
|
-
*/
|
|
7360
|
-
const supportsFlags = {};
|
|
7361
|
-
|
|
7362
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
7363
|
-
function memo(callback) {
|
|
7364
|
-
let result;
|
|
7365
|
-
return () => {
|
|
7366
|
-
if (result === undefined)
|
|
7367
|
-
result = callback();
|
|
7368
|
-
return result;
|
|
7369
|
-
};
|
|
7370
|
-
}
|
|
7371
|
-
|
|
7372
|
-
function memoSupports(callback, supportsFlag) {
|
|
7373
|
-
const memoized = memo(callback);
|
|
7374
|
-
return () => supportsFlags[supportsFlag] ?? memoized();
|
|
7375
|
-
}
|
|
7376
|
-
|
|
7377
|
-
const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
|
|
7378
|
-
try {
|
|
7379
|
-
document
|
|
7380
|
-
.createElement("div")
|
|
7381
|
-
.animate({ opacity: 0 }, { easing: "linear(0, 1)" });
|
|
7382
|
-
}
|
|
7383
|
-
catch (e) {
|
|
7384
|
-
return false;
|
|
7385
|
-
}
|
|
7386
|
-
return true;
|
|
7387
|
-
}, "linearEasing");
|
|
7388
|
-
|
|
7389
|
-
const generateLinearEasing = (easing, duration, // as milliseconds
|
|
7390
|
-
resolution = 10 // as milliseconds
|
|
7391
|
-
) => {
|
|
7392
|
-
let points = "";
|
|
7393
|
-
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
7394
|
-
for (let i = 0; i < numPoints; i++) {
|
|
7395
|
-
points += easing(i / (numPoints - 1)) + ", ";
|
|
7396
|
-
}
|
|
7397
|
-
return `linear(${points.substring(0, points.length - 2)})`;
|
|
7398
|
-
};
|
|
7399
|
-
|
|
7400
6490
|
const durationKeys = ["duration", "bounce"];
|
|
7401
6491
|
const physicsKeys = ["stiffness", "damping", "mass"];
|
|
7402
6492
|
function isSpringType(options, keys) {
|
|
@@ -7523,7 +6613,7 @@ function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce
|
|
|
7523
6613
|
next: (t) => {
|
|
7524
6614
|
const current = resolveSpring(t);
|
|
7525
6615
|
if (!isResolvedFromDuration) {
|
|
7526
|
-
let currentVelocity = 0.0;
|
|
6616
|
+
let currentVelocity = t === 0 ? initialVelocity : 0.0;
|
|
7527
6617
|
/**
|
|
7528
6618
|
* We only need to calculate velocity for under-damped springs
|
|
7529
6619
|
* as over- and critically-damped springs can't overshoot, so
|
|
@@ -7557,7 +6647,7 @@ function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce
|
|
|
7557
6647
|
}
|
|
7558
6648
|
spring.applyToOptions = (options) => {
|
|
7559
6649
|
const generatorOptions = createGeneratorEasing(options, 100, spring);
|
|
7560
|
-
options.ease =
|
|
6650
|
+
options.ease = generatorOptions.ease;
|
|
7561
6651
|
options.duration = secondsToMilliseconds(generatorOptions.duration);
|
|
7562
6652
|
options.type = "keyframes";
|
|
7563
6653
|
return options;
|
|
@@ -7646,44 +6736,6 @@ function inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, b
|
|
|
7646
6736
|
};
|
|
7647
6737
|
}
|
|
7648
6738
|
|
|
7649
|
-
const easeIn = /*@__PURE__*/ cubicBezier(0.42, 0, 1, 1);
|
|
7650
|
-
const easeOut = /*@__PURE__*/ cubicBezier(0, 0, 0.58, 1);
|
|
7651
|
-
const easeInOut = /*@__PURE__*/ cubicBezier(0.42, 0, 0.58, 1);
|
|
7652
|
-
|
|
7653
|
-
const isEasingArray = (ease) => {
|
|
7654
|
-
return Array.isArray(ease) && typeof ease[0] !== "number";
|
|
7655
|
-
};
|
|
7656
|
-
|
|
7657
|
-
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
|
7658
|
-
|
|
7659
|
-
const easingLookup = {
|
|
7660
|
-
linear: noop,
|
|
7661
|
-
easeIn,
|
|
7662
|
-
easeInOut,
|
|
7663
|
-
easeOut,
|
|
7664
|
-
circIn,
|
|
7665
|
-
circInOut,
|
|
7666
|
-
circOut,
|
|
7667
|
-
backIn,
|
|
7668
|
-
backInOut,
|
|
7669
|
-
backOut,
|
|
7670
|
-
anticipate,
|
|
7671
|
-
};
|
|
7672
|
-
const easingDefinitionToFunction = (definition) => {
|
|
7673
|
-
if (isBezierDefinition(definition)) {
|
|
7674
|
-
// If cubic bezier definition, create bezier curve
|
|
7675
|
-
invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`);
|
|
7676
|
-
const [x1, y1, x2, y2] = definition;
|
|
7677
|
-
return cubicBezier(x1, y1, x2, y2);
|
|
7678
|
-
}
|
|
7679
|
-
else if (typeof definition === "string") {
|
|
7680
|
-
// Else lookup from table
|
|
7681
|
-
invariant(easingLookup[definition] !== undefined, `Invalid easing type '${definition}'`);
|
|
7682
|
-
return easingLookup[definition];
|
|
7683
|
-
}
|
|
7684
|
-
return definition;
|
|
7685
|
-
};
|
|
7686
|
-
|
|
7687
6739
|
/*
|
|
7688
6740
|
Progress within given range
|
|
7689
6741
|
|
|
@@ -7704,7 +6756,7 @@ const progress = (from, to, value) => {
|
|
|
7704
6756
|
|
|
7705
6757
|
function createMixers(output, ease, customMixer) {
|
|
7706
6758
|
const mixers = [];
|
|
7707
|
-
const mixerFactory = customMixer || mix;
|
|
6759
|
+
const mixerFactory = customMixer || MotionGlobalConfig.mix || mix;
|
|
7708
6760
|
const numMixers = output.length - 1;
|
|
7709
6761
|
for (let i = 0; i < numMixers; i++) {
|
|
7710
6762
|
let mixer = mixerFactory(output[i], output[i + 1]);
|
|
@@ -7778,17 +6830,124 @@ function fillOffset(offset, remaining) {
|
|
|
7778
6830
|
const offsetProgress = progress(0, remaining, i);
|
|
7779
6831
|
offset.push(mixNumber$1(min, 1, offsetProgress));
|
|
7780
6832
|
}
|
|
7781
|
-
}
|
|
7782
|
-
|
|
7783
|
-
function defaultOffset(arr) {
|
|
7784
|
-
const offset = [0];
|
|
7785
|
-
fillOffset(offset, arr.length - 1);
|
|
7786
|
-
return offset;
|
|
7787
|
-
}
|
|
7788
|
-
|
|
7789
|
-
function convertOffsetToTimes(offset, duration) {
|
|
7790
|
-
return offset.map((o) => o * duration);
|
|
7791
|
-
}
|
|
6833
|
+
}
|
|
6834
|
+
|
|
6835
|
+
function defaultOffset(arr) {
|
|
6836
|
+
const offset = [0];
|
|
6837
|
+
fillOffset(offset, arr.length - 1);
|
|
6838
|
+
return offset;
|
|
6839
|
+
}
|
|
6840
|
+
|
|
6841
|
+
function convertOffsetToTimes(offset, duration) {
|
|
6842
|
+
return offset.map((o) => o * duration);
|
|
6843
|
+
}
|
|
6844
|
+
|
|
6845
|
+
/*
|
|
6846
|
+
Bezier function generator
|
|
6847
|
+
This has been modified from Gaëtan Renaudeau's BezierEasing
|
|
6848
|
+
https://github.com/gre/bezier-easing/blob/master/src/index.js
|
|
6849
|
+
https://github.com/gre/bezier-easing/blob/master/LICENSE
|
|
6850
|
+
|
|
6851
|
+
I've removed the newtonRaphsonIterate algo because in benchmarking it
|
|
6852
|
+
wasn't noticiably faster than binarySubdivision, indeed removing it
|
|
6853
|
+
usually improved times, depending on the curve.
|
|
6854
|
+
I also removed the lookup table, as for the added bundle size and loop we're
|
|
6855
|
+
only cutting ~4 or so subdivision iterations. I bumped the max iterations up
|
|
6856
|
+
to 12 to compensate and this still tended to be faster for no perceivable
|
|
6857
|
+
loss in accuracy.
|
|
6858
|
+
Usage
|
|
6859
|
+
const easeOut = cubicBezier(.17,.67,.83,.67);
|
|
6860
|
+
const x = easeOut(0.5); // returns 0.627...
|
|
6861
|
+
*/
|
|
6862
|
+
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
6863
|
+
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
6864
|
+
t;
|
|
6865
|
+
const subdivisionPrecision = 0.0000001;
|
|
6866
|
+
const subdivisionMaxIterations = 12;
|
|
6867
|
+
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
6868
|
+
let currentX;
|
|
6869
|
+
let currentT;
|
|
6870
|
+
let i = 0;
|
|
6871
|
+
do {
|
|
6872
|
+
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
6873
|
+
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
6874
|
+
if (currentX > 0.0) {
|
|
6875
|
+
upperBound = currentT;
|
|
6876
|
+
}
|
|
6877
|
+
else {
|
|
6878
|
+
lowerBound = currentT;
|
|
6879
|
+
}
|
|
6880
|
+
} while (Math.abs(currentX) > subdivisionPrecision &&
|
|
6881
|
+
++i < subdivisionMaxIterations);
|
|
6882
|
+
return currentT;
|
|
6883
|
+
}
|
|
6884
|
+
function cubicBezier(mX1, mY1, mX2, mY2) {
|
|
6885
|
+
// If this is a linear gradient, return linear easing
|
|
6886
|
+
if (mX1 === mY1 && mX2 === mY2)
|
|
6887
|
+
return noop;
|
|
6888
|
+
const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
|
|
6889
|
+
// If animation is at start/end, return t without easing
|
|
6890
|
+
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
|
|
6891
|
+
}
|
|
6892
|
+
|
|
6893
|
+
const easeIn = /*@__PURE__*/ cubicBezier(0.42, 0, 1, 1);
|
|
6894
|
+
const easeOut = /*@__PURE__*/ cubicBezier(0, 0, 0.58, 1);
|
|
6895
|
+
const easeInOut = /*@__PURE__*/ cubicBezier(0.42, 0, 0.58, 1);
|
|
6896
|
+
|
|
6897
|
+
const isEasingArray = (ease) => {
|
|
6898
|
+
return Array.isArray(ease) && typeof ease[0] !== "number";
|
|
6899
|
+
};
|
|
6900
|
+
|
|
6901
|
+
// Accepts an easing function and returns a new one that outputs mirrored values for
|
|
6902
|
+
// the second half of the animation. Turns easeIn into easeInOut.
|
|
6903
|
+
const mirrorEasing = (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
|
|
6904
|
+
|
|
6905
|
+
// Accepts an easing function and returns a new one that outputs reversed values.
|
|
6906
|
+
// Turns easeIn into easeOut.
|
|
6907
|
+
const reverseEasing = (easing) => (p) => 1 - easing(1 - p);
|
|
6908
|
+
|
|
6909
|
+
const backOut = /*@__PURE__*/ cubicBezier(0.33, 1.53, 0.69, 0.99);
|
|
6910
|
+
const backIn = /*@__PURE__*/ reverseEasing(backOut);
|
|
6911
|
+
const backInOut = /*@__PURE__*/ mirrorEasing(backIn);
|
|
6912
|
+
|
|
6913
|
+
const anticipate = (p) => (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
|
|
6914
|
+
|
|
6915
|
+
const circIn = (p) => 1 - Math.sin(Math.acos(p));
|
|
6916
|
+
const circOut = reverseEasing(circIn);
|
|
6917
|
+
const circInOut = mirrorEasing(circIn);
|
|
6918
|
+
|
|
6919
|
+
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
|
6920
|
+
|
|
6921
|
+
const easingLookup = {
|
|
6922
|
+
linear: noop,
|
|
6923
|
+
easeIn,
|
|
6924
|
+
easeInOut,
|
|
6925
|
+
easeOut,
|
|
6926
|
+
circIn,
|
|
6927
|
+
circInOut,
|
|
6928
|
+
circOut,
|
|
6929
|
+
backIn,
|
|
6930
|
+
backInOut,
|
|
6931
|
+
backOut,
|
|
6932
|
+
anticipate,
|
|
6933
|
+
};
|
|
6934
|
+
const isValidEasing = (easing) => {
|
|
6935
|
+
return typeof easing === "string";
|
|
6936
|
+
};
|
|
6937
|
+
const easingDefinitionToFunction = (definition) => {
|
|
6938
|
+
if (isBezierDefinition(definition)) {
|
|
6939
|
+
// If cubic bezier definition, create bezier curve
|
|
6940
|
+
invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`);
|
|
6941
|
+
const [x1, y1, x2, y2] = definition;
|
|
6942
|
+
return cubicBezier(x1, y1, x2, y2);
|
|
6943
|
+
}
|
|
6944
|
+
else if (isValidEasing(definition)) {
|
|
6945
|
+
// Else lookup from table
|
|
6946
|
+
invariant(easingLookup[definition] !== undefined, `Invalid easing type '${definition}'`);
|
|
6947
|
+
return easingLookup[definition];
|
|
6948
|
+
}
|
|
6949
|
+
return definition;
|
|
6950
|
+
};
|
|
7792
6951
|
|
|
7793
6952
|
function defaultEasing(values, easing) {
|
|
7794
6953
|
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
|
|
@@ -7833,68 +6992,84 @@ function keyframes({ duration = 300, keyframes: keyframeValues, times, ease = "e
|
|
|
7833
6992
|
};
|
|
7834
6993
|
}
|
|
7835
6994
|
|
|
7836
|
-
const
|
|
7837
|
-
|
|
7838
|
-
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
now: () => (frameData.isProcessing ? frameData.timestamp : time.now()),
|
|
7846
|
-
};
|
|
7847
|
-
};
|
|
6995
|
+
const isNotNull = (value) => value !== null;
|
|
6996
|
+
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe, speed = 1) {
|
|
6997
|
+
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
6998
|
+
const useFirstKeyframe = speed < 0 || (repeat && repeatType !== "loop" && repeat % 2 === 1);
|
|
6999
|
+
const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;
|
|
7000
|
+
return !index || finalKeyframe === undefined
|
|
7001
|
+
? resolvedKeyframes[index]
|
|
7002
|
+
: finalKeyframe;
|
|
7003
|
+
}
|
|
7848
7004
|
|
|
7849
|
-
const
|
|
7005
|
+
const transitionTypeMap = {
|
|
7850
7006
|
decay: inertia,
|
|
7851
7007
|
inertia,
|
|
7852
7008
|
tween: keyframes,
|
|
7853
7009
|
keyframes: keyframes,
|
|
7854
7010
|
spring,
|
|
7855
7011
|
};
|
|
7012
|
+
function replaceTransitionType(transition) {
|
|
7013
|
+
if (typeof transition.type === "string") {
|
|
7014
|
+
transition.type = transitionTypeMap[transition.type];
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
|
|
7018
|
+
class WithPromise {
|
|
7019
|
+
constructor() {
|
|
7020
|
+
this.count = 0;
|
|
7021
|
+
this.updateFinished();
|
|
7022
|
+
}
|
|
7023
|
+
get finished() {
|
|
7024
|
+
return this._finished;
|
|
7025
|
+
}
|
|
7026
|
+
updateFinished() {
|
|
7027
|
+
this.count++;
|
|
7028
|
+
this._finished = new Promise((resolve) => {
|
|
7029
|
+
this.resolve = resolve;
|
|
7030
|
+
});
|
|
7031
|
+
}
|
|
7032
|
+
notifyFinished() {
|
|
7033
|
+
this.resolve();
|
|
7034
|
+
}
|
|
7035
|
+
/**
|
|
7036
|
+
* Allows the animation to be awaited.
|
|
7037
|
+
*
|
|
7038
|
+
* @deprecated Use `finished` instead.
|
|
7039
|
+
*/
|
|
7040
|
+
then(onResolve, onReject) {
|
|
7041
|
+
return this.finished.then(onResolve, onReject);
|
|
7042
|
+
}
|
|
7043
|
+
}
|
|
7044
|
+
|
|
7856
7045
|
const percentToProgress = (percent) => percent / 100;
|
|
7857
|
-
|
|
7858
|
-
* Animation that runs on the main thread. Designed to be WAAPI-spec in the subset of
|
|
7859
|
-
* features we expose publically. Mostly the compatibility is to ensure visual identity
|
|
7860
|
-
* between both WAAPI and main thread animations.
|
|
7861
|
-
*/
|
|
7862
|
-
class MainThreadAnimation extends BaseAnimation {
|
|
7046
|
+
class JSAnimation extends WithPromise {
|
|
7863
7047
|
constructor(options) {
|
|
7864
|
-
super(
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
this.holdTime = null;
|
|
7869
|
-
/**
|
|
7870
|
-
* The time at which the animation was cancelled.
|
|
7871
|
-
*/
|
|
7872
|
-
this.cancelTime = null;
|
|
7048
|
+
super();
|
|
7049
|
+
this.state = "idle";
|
|
7050
|
+
this.startTime = null;
|
|
7051
|
+
this.isStopped = false;
|
|
7873
7052
|
/**
|
|
7874
7053
|
* The current time of the animation.
|
|
7875
7054
|
*/
|
|
7876
7055
|
this.currentTime = 0;
|
|
7877
7056
|
/**
|
|
7878
|
-
*
|
|
7879
|
-
*/
|
|
7880
|
-
this.playbackSpeed = 1;
|
|
7881
|
-
/**
|
|
7882
|
-
* The state of the animation to apply when the animation is resolved. This
|
|
7883
|
-
* allows calls to the public API to control the animation before it is resolved,
|
|
7884
|
-
* without us having to resolve it first.
|
|
7057
|
+
* The time at which the animation was paused.
|
|
7885
7058
|
*/
|
|
7886
|
-
this.
|
|
7059
|
+
this.holdTime = null;
|
|
7887
7060
|
/**
|
|
7888
|
-
*
|
|
7061
|
+
* Playback speed as a factor. 0 would be stopped, -1 reverse and 2 double speed.
|
|
7889
7062
|
*/
|
|
7890
|
-
this.
|
|
7891
|
-
this.state = "idle";
|
|
7063
|
+
this.playbackSpeed = 1;
|
|
7892
7064
|
/**
|
|
7893
7065
|
* This method is bound to the instance to fix a pattern where
|
|
7894
7066
|
* animation.stop is returned as a reference from a useEffect.
|
|
7895
7067
|
*/
|
|
7896
7068
|
this.stop = () => {
|
|
7897
|
-
this.
|
|
7069
|
+
const { motionValue } = this.options;
|
|
7070
|
+
if (motionValue && motionValue.updatedAt !== time.now()) {
|
|
7071
|
+
this.tick(time.now());
|
|
7072
|
+
}
|
|
7898
7073
|
this.isStopped = true;
|
|
7899
7074
|
if (this.state === "idle")
|
|
7900
7075
|
return;
|
|
@@ -7902,49 +7077,35 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
7902
7077
|
const { onStop } = this.options;
|
|
7903
7078
|
onStop && onStop();
|
|
7904
7079
|
};
|
|
7905
|
-
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
}
|
|
7911
|
-
|
|
7912
|
-
|
|
7913
|
-
|
|
7914
|
-
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
}
|
|
7918
|
-
initPlayback(keyframes$1) {
|
|
7919
|
-
const { type = "keyframes", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;
|
|
7920
|
-
const generatorFactory = isGenerator(type)
|
|
7921
|
-
? type
|
|
7922
|
-
: generators[type] || keyframes;
|
|
7923
|
-
/**
|
|
7924
|
-
* If our generator doesn't support mixing numbers, we need to replace keyframes with
|
|
7925
|
-
* [0, 100] and then make a function that maps that to the actual keyframes.
|
|
7926
|
-
*
|
|
7927
|
-
* 100 is chosen instead of 1 as it works nicer with spring animations.
|
|
7928
|
-
*/
|
|
7929
|
-
let mapPercentToKeyframes;
|
|
7930
|
-
let mirroredGenerator;
|
|
7080
|
+
this.options = options;
|
|
7081
|
+
this.initAnimation();
|
|
7082
|
+
this.play();
|
|
7083
|
+
if (options.autoplay === false)
|
|
7084
|
+
this.pause();
|
|
7085
|
+
}
|
|
7086
|
+
initAnimation() {
|
|
7087
|
+
const { options } = this;
|
|
7088
|
+
replaceTransitionType(options);
|
|
7089
|
+
const { type = keyframes, repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = options;
|
|
7090
|
+
let { keyframes: keyframes$1 } = options;
|
|
7091
|
+
const generatorFactory = type || keyframes;
|
|
7931
7092
|
if (process.env.NODE_ENV !== "production" &&
|
|
7932
7093
|
generatorFactory !== keyframes) {
|
|
7933
7094
|
invariant(keyframes$1.length <= 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${keyframes$1}`);
|
|
7934
7095
|
}
|
|
7935
7096
|
if (generatorFactory !== keyframes &&
|
|
7936
7097
|
typeof keyframes$1[0] !== "number") {
|
|
7937
|
-
|
|
7098
|
+
this.mixKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));
|
|
7938
7099
|
keyframes$1 = [0, 100];
|
|
7939
7100
|
}
|
|
7940
|
-
const generator = generatorFactory({ ...
|
|
7101
|
+
const generator = generatorFactory({ ...options, keyframes: keyframes$1 });
|
|
7941
7102
|
/**
|
|
7942
7103
|
* If we have a mirror repeat type we need to create a second generator that outputs the
|
|
7943
7104
|
* mirrored (not reversed) animation and later ping pong between the two generators.
|
|
7944
7105
|
*/
|
|
7945
7106
|
if (repeatType === "mirror") {
|
|
7946
|
-
mirroredGenerator = generatorFactory({
|
|
7947
|
-
...
|
|
7107
|
+
this.mirroredGenerator = generatorFactory({
|
|
7108
|
+
...options,
|
|
7948
7109
|
keyframes: [...keyframes$1].reverse(),
|
|
7949
7110
|
velocity: -velocity,
|
|
7950
7111
|
});
|
|
@@ -7961,38 +7122,29 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
7961
7122
|
generator.calculatedDuration = calcGeneratorDuration(generator);
|
|
7962
7123
|
}
|
|
7963
7124
|
const { calculatedDuration } = generator;
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
mirroredGenerator,
|
|
7969
|
-
mapPercentToKeyframes,
|
|
7970
|
-
calculatedDuration,
|
|
7971
|
-
resolvedDuration,
|
|
7972
|
-
totalDuration,
|
|
7973
|
-
};
|
|
7125
|
+
this.calculatedDuration = calculatedDuration;
|
|
7126
|
+
this.resolvedDuration = calculatedDuration + repeatDelay;
|
|
7127
|
+
this.totalDuration = this.resolvedDuration * (repeat + 1) - repeatDelay;
|
|
7128
|
+
this.generator = generator;
|
|
7974
7129
|
}
|
|
7975
|
-
|
|
7976
|
-
const
|
|
7977
|
-
|
|
7978
|
-
if (this.
|
|
7979
|
-
this.
|
|
7130
|
+
updateTime(timestamp) {
|
|
7131
|
+
const animationTime = Math.round(timestamp - this.startTime) * this.playbackSpeed;
|
|
7132
|
+
// Update currentTime
|
|
7133
|
+
if (this.holdTime !== null) {
|
|
7134
|
+
this.currentTime = this.holdTime;
|
|
7980
7135
|
}
|
|
7981
7136
|
else {
|
|
7982
|
-
|
|
7137
|
+
// Rounding the time because floating point arithmetic is not always accurate, e.g. 3000.367 - 1000.367 =
|
|
7138
|
+
// 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for
|
|
7139
|
+
// example.
|
|
7140
|
+
this.currentTime = animationTime;
|
|
7983
7141
|
}
|
|
7984
7142
|
}
|
|
7985
7143
|
tick(timestamp, sample = false) {
|
|
7986
|
-
const {
|
|
7987
|
-
// If the animations has failed to resolve, return the final keyframe.
|
|
7988
|
-
if (!resolved) {
|
|
7989
|
-
const { keyframes } = this.options;
|
|
7990
|
-
return { done: true, value: keyframes[keyframes.length - 1] };
|
|
7991
|
-
}
|
|
7992
|
-
const { finalKeyframe, generator, mirroredGenerator, mapPercentToKeyframes, keyframes, calculatedDuration, totalDuration, resolvedDuration, } = resolved;
|
|
7144
|
+
const { generator, totalDuration, mixKeyframes, mirroredGenerator, resolvedDuration, calculatedDuration, } = this;
|
|
7993
7145
|
if (this.startTime === null)
|
|
7994
7146
|
return generator.next(0);
|
|
7995
|
-
const { delay, repeat, repeatType, repeatDelay, onUpdate } = this.options;
|
|
7147
|
+
const { delay = 0, keyframes, repeat, repeatType, repeatDelay, type, onUpdate, finalKeyframe, } = this.options;
|
|
7996
7148
|
/**
|
|
7997
7149
|
* requestAnimationFrame timestamps can come through as lower than
|
|
7998
7150
|
* the startTime as set by performance.now(). Here we prevent this,
|
|
@@ -8005,23 +7157,15 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8005
7157
|
else if (this.speed < 0) {
|
|
8006
7158
|
this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);
|
|
8007
7159
|
}
|
|
8008
|
-
// Update currentTime
|
|
8009
7160
|
if (sample) {
|
|
8010
7161
|
this.currentTime = timestamp;
|
|
8011
7162
|
}
|
|
8012
|
-
else if (this.holdTime !== null) {
|
|
8013
|
-
this.currentTime = this.holdTime;
|
|
8014
|
-
}
|
|
8015
7163
|
else {
|
|
8016
|
-
|
|
8017
|
-
// 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for
|
|
8018
|
-
// example.
|
|
8019
|
-
this.currentTime =
|
|
8020
|
-
Math.round(timestamp - this.startTime) * this.speed;
|
|
7164
|
+
this.updateTime(timestamp);
|
|
8021
7165
|
}
|
|
8022
7166
|
// Rebase on delay
|
|
8023
|
-
const timeWithoutDelay = this.currentTime - delay * (this.
|
|
8024
|
-
const isInDelayPhase = this.
|
|
7167
|
+
const timeWithoutDelay = this.currentTime - delay * (this.playbackSpeed >= 0 ? 1 : -1);
|
|
7168
|
+
const isInDelayPhase = this.playbackSpeed >= 0
|
|
8025
7169
|
? timeWithoutDelay < 0
|
|
8026
7170
|
: timeWithoutDelay > totalDuration;
|
|
8027
7171
|
this.currentTime = Math.max(timeWithoutDelay, 0);
|
|
@@ -8082,20 +7226,21 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8082
7226
|
const state = isInDelayPhase
|
|
8083
7227
|
? { done: false, value: keyframes[0] }
|
|
8084
7228
|
: frameGenerator.next(elapsed);
|
|
8085
|
-
if (
|
|
8086
|
-
state.value =
|
|
7229
|
+
if (mixKeyframes) {
|
|
7230
|
+
state.value = mixKeyframes(state.value);
|
|
8087
7231
|
}
|
|
8088
7232
|
let { done } = state;
|
|
8089
7233
|
if (!isInDelayPhase && calculatedDuration !== null) {
|
|
8090
7234
|
done =
|
|
8091
|
-
this.
|
|
7235
|
+
this.playbackSpeed >= 0
|
|
8092
7236
|
? this.currentTime >= totalDuration
|
|
8093
7237
|
: this.currentTime <= 0;
|
|
8094
7238
|
}
|
|
8095
7239
|
const isAnimationFinished = this.holdTime === null &&
|
|
8096
7240
|
(this.state === "finished" || (this.state === "running" && done));
|
|
8097
|
-
|
|
8098
|
-
|
|
7241
|
+
// TODO: The exception for inertia could be cleaner here
|
|
7242
|
+
if (isAnimationFinished && type !== inertia) {
|
|
7243
|
+
state.value = getFinalKeyframe(keyframes, this.options, finalKeyframe, this.speed);
|
|
8099
7244
|
}
|
|
8100
7245
|
if (onUpdate) {
|
|
8101
7246
|
onUpdate(state.value);
|
|
@@ -8105,9 +7250,16 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8105
7250
|
}
|
|
8106
7251
|
return state;
|
|
8107
7252
|
}
|
|
7253
|
+
/**
|
|
7254
|
+
* Allows the returned animation to be awaited or promise-chained. Currently
|
|
7255
|
+
* resolves when the animation finishes at all but in a future update could/should
|
|
7256
|
+
* reject if its cancels.
|
|
7257
|
+
*/
|
|
7258
|
+
then(resolve, reject) {
|
|
7259
|
+
return this.finished.then(resolve, reject);
|
|
7260
|
+
}
|
|
8108
7261
|
get duration() {
|
|
8109
|
-
|
|
8110
|
-
return resolved ? millisecondsToSeconds(resolved.calculatedDuration) : 0;
|
|
7262
|
+
return millisecondsToSeconds(this.calculatedDuration);
|
|
8111
7263
|
}
|
|
8112
7264
|
get time() {
|
|
8113
7265
|
return millisecondsToSeconds(this.currentTime);
|
|
@@ -8115,125 +7267,417 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8115
7267
|
set time(newTime) {
|
|
8116
7268
|
newTime = secondsToMilliseconds(newTime);
|
|
8117
7269
|
this.currentTime = newTime;
|
|
8118
|
-
if (this.
|
|
7270
|
+
if (this.startTime === null ||
|
|
7271
|
+
this.holdTime !== null ||
|
|
7272
|
+
this.playbackSpeed === 0) {
|
|
8119
7273
|
this.holdTime = newTime;
|
|
8120
7274
|
}
|
|
8121
7275
|
else if (this.driver) {
|
|
8122
|
-
this.startTime = this.driver.now() - newTime / this.
|
|
7276
|
+
this.startTime = this.driver.now() - newTime / this.playbackSpeed;
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
get speed() {
|
|
7280
|
+
return this.playbackSpeed;
|
|
7281
|
+
}
|
|
7282
|
+
set speed(newSpeed) {
|
|
7283
|
+
this.updateTime(time.now());
|
|
7284
|
+
const hasChanged = this.playbackSpeed !== newSpeed;
|
|
7285
|
+
this.playbackSpeed = newSpeed;
|
|
7286
|
+
if (hasChanged) {
|
|
7287
|
+
this.time = millisecondsToSeconds(this.currentTime);
|
|
8123
7288
|
}
|
|
8124
7289
|
}
|
|
8125
|
-
|
|
8126
|
-
|
|
7290
|
+
play() {
|
|
7291
|
+
if (this.isStopped)
|
|
7292
|
+
return;
|
|
7293
|
+
const { driver = frameloopDriver, onPlay, startTime } = this.options;
|
|
7294
|
+
if (!this.driver) {
|
|
7295
|
+
this.driver = driver((timestamp) => this.tick(timestamp));
|
|
7296
|
+
}
|
|
7297
|
+
onPlay && onPlay();
|
|
7298
|
+
const now = this.driver.now();
|
|
7299
|
+
if (this.holdTime !== null) {
|
|
7300
|
+
this.startTime = now - this.holdTime;
|
|
7301
|
+
}
|
|
7302
|
+
else if (this.state === "finished") {
|
|
7303
|
+
this.updateFinished();
|
|
7304
|
+
this.startTime = now;
|
|
7305
|
+
}
|
|
7306
|
+
else if (!this.startTime) {
|
|
7307
|
+
this.startTime = startTime ?? now;
|
|
7308
|
+
}
|
|
7309
|
+
if (this.state === "finished" && this.speed < 0) {
|
|
7310
|
+
this.startTime += this.calculatedDuration;
|
|
7311
|
+
}
|
|
7312
|
+
this.holdTime = null;
|
|
7313
|
+
/**
|
|
7314
|
+
* Set playState to running only after we've used it in
|
|
7315
|
+
* the previous logic.
|
|
7316
|
+
*/
|
|
7317
|
+
this.state = "running";
|
|
7318
|
+
this.driver.start();
|
|
7319
|
+
}
|
|
7320
|
+
pause() {
|
|
7321
|
+
this.state = "paused";
|
|
7322
|
+
this.updateTime(time.now());
|
|
7323
|
+
this.holdTime = this.currentTime;
|
|
7324
|
+
}
|
|
7325
|
+
complete() {
|
|
7326
|
+
if (this.state !== "running") {
|
|
7327
|
+
this.play();
|
|
7328
|
+
}
|
|
7329
|
+
this.state = "finished";
|
|
7330
|
+
this.holdTime = null;
|
|
7331
|
+
}
|
|
7332
|
+
finish() {
|
|
7333
|
+
this.teardown();
|
|
7334
|
+
this.state = "finished";
|
|
7335
|
+
const { onComplete } = this.options;
|
|
7336
|
+
onComplete && onComplete();
|
|
7337
|
+
}
|
|
7338
|
+
cancel() {
|
|
7339
|
+
this.holdTime = null;
|
|
7340
|
+
this.startTime = 0;
|
|
7341
|
+
this.tick(0);
|
|
7342
|
+
this.teardown();
|
|
7343
|
+
}
|
|
7344
|
+
teardown() {
|
|
7345
|
+
this.notifyFinished();
|
|
7346
|
+
this.state = "idle";
|
|
7347
|
+
this.stopDriver();
|
|
7348
|
+
this.startTime = this.holdTime = null;
|
|
7349
|
+
}
|
|
7350
|
+
stopDriver() {
|
|
7351
|
+
if (!this.driver)
|
|
7352
|
+
return;
|
|
7353
|
+
this.driver.stop();
|
|
7354
|
+
this.driver = undefined;
|
|
7355
|
+
}
|
|
7356
|
+
sample(sampleTime) {
|
|
7357
|
+
this.startTime = 0;
|
|
7358
|
+
return this.tick(sampleTime, true);
|
|
7359
|
+
}
|
|
7360
|
+
attachTimeline(timeline) {
|
|
7361
|
+
if (this.options.allowFlatten) {
|
|
7362
|
+
this.options.type = "keyframes";
|
|
7363
|
+
this.options.ease = "linear";
|
|
7364
|
+
this.initAnimation();
|
|
7365
|
+
}
|
|
7366
|
+
return timeline.observe(this);
|
|
7367
|
+
}
|
|
7368
|
+
}
|
|
7369
|
+
|
|
7370
|
+
function fillWildcards(keyframes) {
|
|
7371
|
+
for (let i = 1; i < keyframes.length; i++) {
|
|
7372
|
+
keyframes[i] ?? (keyframes[i] = keyframes[i - 1]);
|
|
7373
|
+
}
|
|
7374
|
+
}
|
|
7375
|
+
|
|
7376
|
+
const radToDeg = (rad) => (rad * 180) / Math.PI;
|
|
7377
|
+
const rotate = (v) => {
|
|
7378
|
+
const angle = radToDeg(Math.atan2(v[1], v[0]));
|
|
7379
|
+
return rebaseAngle(angle);
|
|
7380
|
+
};
|
|
7381
|
+
const matrix2dParsers = {
|
|
7382
|
+
x: 4,
|
|
7383
|
+
y: 5,
|
|
7384
|
+
translateX: 4,
|
|
7385
|
+
translateY: 5,
|
|
7386
|
+
scaleX: 0,
|
|
7387
|
+
scaleY: 3,
|
|
7388
|
+
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
|
|
7389
|
+
rotate,
|
|
7390
|
+
rotateZ: rotate,
|
|
7391
|
+
skewX: (v) => radToDeg(Math.atan(v[1])),
|
|
7392
|
+
skewY: (v) => radToDeg(Math.atan(v[2])),
|
|
7393
|
+
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
|
|
7394
|
+
};
|
|
7395
|
+
const rebaseAngle = (angle) => {
|
|
7396
|
+
angle = angle % 360;
|
|
7397
|
+
if (angle < 0)
|
|
7398
|
+
angle += 360;
|
|
7399
|
+
return angle;
|
|
7400
|
+
};
|
|
7401
|
+
const rotateZ = rotate;
|
|
7402
|
+
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
7403
|
+
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
|
|
7404
|
+
const matrix3dParsers = {
|
|
7405
|
+
x: 12,
|
|
7406
|
+
y: 13,
|
|
7407
|
+
z: 14,
|
|
7408
|
+
translateX: 12,
|
|
7409
|
+
translateY: 13,
|
|
7410
|
+
translateZ: 14,
|
|
7411
|
+
scaleX,
|
|
7412
|
+
scaleY,
|
|
7413
|
+
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
|
|
7414
|
+
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
|
|
7415
|
+
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
|
|
7416
|
+
rotateZ,
|
|
7417
|
+
rotate: rotateZ,
|
|
7418
|
+
skewX: (v) => radToDeg(Math.atan(v[4])),
|
|
7419
|
+
skewY: (v) => radToDeg(Math.atan(v[1])),
|
|
7420
|
+
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
|
|
7421
|
+
};
|
|
7422
|
+
function defaultTransformValue(name) {
|
|
7423
|
+
return name.includes("scale") ? 1 : 0;
|
|
7424
|
+
}
|
|
7425
|
+
function parseValueFromTransform(transform, name) {
|
|
7426
|
+
if (!transform || transform === "none") {
|
|
7427
|
+
return defaultTransformValue(name);
|
|
7428
|
+
}
|
|
7429
|
+
const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
|
|
7430
|
+
let parsers;
|
|
7431
|
+
let match;
|
|
7432
|
+
if (matrix3dMatch) {
|
|
7433
|
+
parsers = matrix3dParsers;
|
|
7434
|
+
match = matrix3dMatch;
|
|
7435
|
+
}
|
|
7436
|
+
else {
|
|
7437
|
+
const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
|
|
7438
|
+
parsers = matrix2dParsers;
|
|
7439
|
+
match = matrix2dMatch;
|
|
7440
|
+
}
|
|
7441
|
+
if (!match) {
|
|
7442
|
+
return defaultTransformValue(name);
|
|
8127
7443
|
}
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
7444
|
+
const valueParser = parsers[name];
|
|
7445
|
+
const values = match[1].split(",").map(convertTransformToNumber);
|
|
7446
|
+
return typeof valueParser === "function"
|
|
7447
|
+
? valueParser(values)
|
|
7448
|
+
: values[valueParser];
|
|
7449
|
+
}
|
|
7450
|
+
const readTransformValue = (instance, name) => {
|
|
7451
|
+
const { transform = "none" } = getComputedStyle(instance);
|
|
7452
|
+
return parseValueFromTransform(transform, name);
|
|
7453
|
+
};
|
|
7454
|
+
function convertTransformToNumber(value) {
|
|
7455
|
+
return parseFloat(value.trim());
|
|
7456
|
+
}
|
|
7457
|
+
|
|
7458
|
+
const isNumOrPxType = (v) => v === number || v === px;
|
|
7459
|
+
const transformKeys = new Set(["x", "y", "z"]);
|
|
7460
|
+
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
|
7461
|
+
function removeNonTranslationalTransform(visualElement) {
|
|
7462
|
+
const removedTransforms = [];
|
|
7463
|
+
nonTranslationalTransformKeys.forEach((key) => {
|
|
7464
|
+
const value = visualElement.getValue(key);
|
|
7465
|
+
if (value !== undefined) {
|
|
7466
|
+
removedTransforms.push([key, value.get()]);
|
|
7467
|
+
value.set(key.startsWith("scale") ? 1 : 0);
|
|
8133
7468
|
}
|
|
7469
|
+
});
|
|
7470
|
+
return removedTransforms;
|
|
7471
|
+
}
|
|
7472
|
+
const positionalValues = {
|
|
7473
|
+
// Dimensions
|
|
7474
|
+
width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
|
|
7475
|
+
height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
|
|
7476
|
+
top: (_bbox, { top }) => parseFloat(top),
|
|
7477
|
+
left: (_bbox, { left }) => parseFloat(left),
|
|
7478
|
+
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
|
7479
|
+
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
|
7480
|
+
// Transform
|
|
7481
|
+
x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
|
|
7482
|
+
y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
|
|
7483
|
+
};
|
|
7484
|
+
// Alias translate longform names
|
|
7485
|
+
positionalValues.translateX = positionalValues.x;
|
|
7486
|
+
positionalValues.translateY = positionalValues.y;
|
|
7487
|
+
|
|
7488
|
+
const toResolve = new Set();
|
|
7489
|
+
let isScheduled = false;
|
|
7490
|
+
let anyNeedsMeasurement = false;
|
|
7491
|
+
let isForced = false;
|
|
7492
|
+
function measureAllKeyframes() {
|
|
7493
|
+
if (anyNeedsMeasurement) {
|
|
7494
|
+
const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);
|
|
7495
|
+
const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));
|
|
7496
|
+
const transformsToRestore = new Map();
|
|
7497
|
+
/**
|
|
7498
|
+
* Write pass
|
|
7499
|
+
* If we're measuring elements we want to remove bounding box-changing transforms.
|
|
7500
|
+
*/
|
|
7501
|
+
elementsToMeasure.forEach((element) => {
|
|
7502
|
+
const removedTransforms = removeNonTranslationalTransform(element);
|
|
7503
|
+
if (!removedTransforms.length)
|
|
7504
|
+
return;
|
|
7505
|
+
transformsToRestore.set(element, removedTransforms);
|
|
7506
|
+
element.render();
|
|
7507
|
+
});
|
|
7508
|
+
// Read
|
|
7509
|
+
resolversToMeasure.forEach((resolver) => resolver.measureInitialState());
|
|
7510
|
+
// Write
|
|
7511
|
+
elementsToMeasure.forEach((element) => {
|
|
7512
|
+
element.render();
|
|
7513
|
+
const restore = transformsToRestore.get(element);
|
|
7514
|
+
if (restore) {
|
|
7515
|
+
restore.forEach(([key, value]) => {
|
|
7516
|
+
element.getValue(key)?.set(value);
|
|
7517
|
+
});
|
|
7518
|
+
}
|
|
7519
|
+
});
|
|
7520
|
+
// Read
|
|
7521
|
+
resolversToMeasure.forEach((resolver) => resolver.measureEndState());
|
|
7522
|
+
// Write
|
|
7523
|
+
resolversToMeasure.forEach((resolver) => {
|
|
7524
|
+
if (resolver.suspendedScrollY !== undefined) {
|
|
7525
|
+
window.scrollTo(0, resolver.suspendedScrollY);
|
|
7526
|
+
}
|
|
7527
|
+
});
|
|
8134
7528
|
}
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
if (
|
|
8144
|
-
|
|
8145
|
-
const { driver = frameloopDriver, onPlay, startTime } = this.options;
|
|
8146
|
-
if (!this.driver) {
|
|
8147
|
-
this.driver = driver((timestamp) => this.tick(timestamp));
|
|
8148
|
-
}
|
|
8149
|
-
onPlay && onPlay();
|
|
8150
|
-
const now = this.driver.now();
|
|
8151
|
-
if (this.holdTime !== null) {
|
|
8152
|
-
this.startTime = now - this.holdTime;
|
|
8153
|
-
}
|
|
8154
|
-
else if (!this.startTime) {
|
|
8155
|
-
this.startTime = startTime ?? this.calcStartTime();
|
|
8156
|
-
}
|
|
8157
|
-
else if (this.state === "finished") {
|
|
8158
|
-
this.startTime = now;
|
|
8159
|
-
}
|
|
8160
|
-
if (this.state === "finished") {
|
|
8161
|
-
this.updateFinishedPromise();
|
|
7529
|
+
anyNeedsMeasurement = false;
|
|
7530
|
+
isScheduled = false;
|
|
7531
|
+
toResolve.forEach((resolver) => resolver.complete(isForced));
|
|
7532
|
+
toResolve.clear();
|
|
7533
|
+
}
|
|
7534
|
+
function readAllKeyframes() {
|
|
7535
|
+
toResolve.forEach((resolver) => {
|
|
7536
|
+
resolver.readKeyframes();
|
|
7537
|
+
if (resolver.needsMeasurement) {
|
|
7538
|
+
anyNeedsMeasurement = true;
|
|
8162
7539
|
}
|
|
8163
|
-
|
|
8164
|
-
|
|
7540
|
+
});
|
|
7541
|
+
}
|
|
7542
|
+
function flushKeyframeResolvers() {
|
|
7543
|
+
isForced = true;
|
|
7544
|
+
readAllKeyframes();
|
|
7545
|
+
measureAllKeyframes();
|
|
7546
|
+
isForced = false;
|
|
7547
|
+
}
|
|
7548
|
+
class KeyframeResolver {
|
|
7549
|
+
constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {
|
|
8165
7550
|
/**
|
|
8166
|
-
*
|
|
8167
|
-
*
|
|
7551
|
+
* Track whether this resolver has completed. Once complete, it never
|
|
7552
|
+
* needs to attempt keyframe resolution again.
|
|
8168
7553
|
*/
|
|
8169
|
-
this.
|
|
8170
|
-
|
|
7554
|
+
this.isComplete = false;
|
|
7555
|
+
/**
|
|
7556
|
+
* Track whether this resolver is async. If it is, it'll be added to the
|
|
7557
|
+
* resolver queue and flushed in the next frame. Resolvers that aren't going
|
|
7558
|
+
* to trigger read/write thrashing don't need to be async.
|
|
7559
|
+
*/
|
|
7560
|
+
this.isAsync = false;
|
|
7561
|
+
/**
|
|
7562
|
+
* Track whether this resolver needs to perform a measurement
|
|
7563
|
+
* to resolve its keyframes.
|
|
7564
|
+
*/
|
|
7565
|
+
this.needsMeasurement = false;
|
|
7566
|
+
/**
|
|
7567
|
+
* Track whether this resolver is currently scheduled to resolve
|
|
7568
|
+
* to allow it to be cancelled and resumed externally.
|
|
7569
|
+
*/
|
|
7570
|
+
this.isScheduled = false;
|
|
7571
|
+
this.unresolvedKeyframes = [...unresolvedKeyframes];
|
|
7572
|
+
this.onComplete = onComplete;
|
|
7573
|
+
this.name = name;
|
|
7574
|
+
this.motionValue = motionValue;
|
|
7575
|
+
this.element = element;
|
|
7576
|
+
this.isAsync = isAsync;
|
|
8171
7577
|
}
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
7578
|
+
scheduleResolve() {
|
|
7579
|
+
this.isScheduled = true;
|
|
7580
|
+
if (this.isAsync) {
|
|
7581
|
+
toResolve.add(this);
|
|
7582
|
+
if (!isScheduled) {
|
|
7583
|
+
isScheduled = true;
|
|
7584
|
+
frame.read(readAllKeyframes);
|
|
7585
|
+
frame.resolveKeyframes(measureAllKeyframes);
|
|
7586
|
+
}
|
|
7587
|
+
}
|
|
7588
|
+
else {
|
|
7589
|
+
this.readKeyframes();
|
|
7590
|
+
this.complete();
|
|
8176
7591
|
}
|
|
8177
|
-
this.state = "paused";
|
|
8178
|
-
this.holdTime = this.currentTime ?? 0;
|
|
8179
7592
|
}
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
7593
|
+
readKeyframes() {
|
|
7594
|
+
const { unresolvedKeyframes, name, element, motionValue } = this;
|
|
7595
|
+
// If initial keyframe is null we need to read it from the DOM
|
|
7596
|
+
if (unresolvedKeyframes[0] === null) {
|
|
7597
|
+
const currentValue = motionValue?.get();
|
|
7598
|
+
// TODO: This doesn't work if the final keyframe is a wildcard
|
|
7599
|
+
const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
7600
|
+
if (currentValue !== undefined) {
|
|
7601
|
+
unresolvedKeyframes[0] = currentValue;
|
|
7602
|
+
}
|
|
7603
|
+
else if (element && name) {
|
|
7604
|
+
const valueAsRead = element.readValue(name, finalKeyframe);
|
|
7605
|
+
if (valueAsRead !== undefined && valueAsRead !== null) {
|
|
7606
|
+
unresolvedKeyframes[0] = valueAsRead;
|
|
7607
|
+
}
|
|
7608
|
+
}
|
|
7609
|
+
if (unresolvedKeyframes[0] === undefined) {
|
|
7610
|
+
unresolvedKeyframes[0] = finalKeyframe;
|
|
7611
|
+
}
|
|
7612
|
+
if (motionValue && currentValue === undefined) {
|
|
7613
|
+
motionValue.set(unresolvedKeyframes[0]);
|
|
7614
|
+
}
|
|
8183
7615
|
}
|
|
8184
|
-
|
|
8185
|
-
this.holdTime = null;
|
|
7616
|
+
fillWildcards(unresolvedKeyframes);
|
|
8186
7617
|
}
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
7618
|
+
setFinalKeyframe() { }
|
|
7619
|
+
measureInitialState() { }
|
|
7620
|
+
renderEndStyles() { }
|
|
7621
|
+
measureEndState() { }
|
|
7622
|
+
complete(isForced = false) {
|
|
7623
|
+
this.isComplete = true;
|
|
7624
|
+
this.onComplete(this.unresolvedKeyframes, this.finalKeyframe, isForced);
|
|
7625
|
+
toResolve.delete(this);
|
|
8192
7626
|
}
|
|
8193
7627
|
cancel() {
|
|
8194
|
-
if (this.
|
|
8195
|
-
this.
|
|
7628
|
+
if (!this.isComplete) {
|
|
7629
|
+
this.isScheduled = false;
|
|
7630
|
+
toResolve.delete(this);
|
|
8196
7631
|
}
|
|
8197
|
-
this.teardown();
|
|
8198
|
-
this.updateFinishedPromise();
|
|
8199
|
-
}
|
|
8200
|
-
teardown() {
|
|
8201
|
-
this.state = "idle";
|
|
8202
|
-
this.stopDriver();
|
|
8203
|
-
this.resolveFinishedPromise();
|
|
8204
|
-
this.updateFinishedPromise();
|
|
8205
|
-
this.startTime = this.cancelTime = null;
|
|
8206
|
-
this.resolver.cancel();
|
|
8207
7632
|
}
|
|
8208
|
-
|
|
8209
|
-
if (!this.
|
|
8210
|
-
|
|
8211
|
-
this.driver.stop();
|
|
8212
|
-
this.driver = undefined;
|
|
8213
|
-
}
|
|
8214
|
-
sample(time) {
|
|
8215
|
-
this.startTime = 0;
|
|
8216
|
-
return this.tick(time, true);
|
|
8217
|
-
}
|
|
8218
|
-
get finished() {
|
|
8219
|
-
return this.currentFinishedPromise;
|
|
7633
|
+
resume() {
|
|
7634
|
+
if (!this.isComplete)
|
|
7635
|
+
this.scheduleResolve();
|
|
8220
7636
|
}
|
|
8221
7637
|
}
|
|
8222
7638
|
|
|
7639
|
+
const isCSSVar = (name) => name.startsWith("--");
|
|
7640
|
+
|
|
7641
|
+
function setStyle(element, name, value) {
|
|
7642
|
+
isCSSVar(name)
|
|
7643
|
+
? element.style.setProperty(name, value)
|
|
7644
|
+
: (element.style[name] = value);
|
|
7645
|
+
}
|
|
7646
|
+
|
|
7647
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
7648
|
+
function memo(callback) {
|
|
7649
|
+
let result;
|
|
7650
|
+
return () => {
|
|
7651
|
+
if (result === undefined)
|
|
7652
|
+
result = callback();
|
|
7653
|
+
return result;
|
|
7654
|
+
};
|
|
7655
|
+
}
|
|
7656
|
+
|
|
7657
|
+
const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
|
|
7658
|
+
|
|
8223
7659
|
/**
|
|
8224
|
-
*
|
|
7660
|
+
* Add the ability for test suites to manually set support flags
|
|
7661
|
+
* to better test more environments.
|
|
8225
7662
|
*/
|
|
8226
|
-
const
|
|
8227
|
-
"opacity",
|
|
8228
|
-
"clipPath",
|
|
8229
|
-
"filter",
|
|
8230
|
-
"transform",
|
|
8231
|
-
// TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
|
|
8232
|
-
// or until we implement support for linear() easing.
|
|
8233
|
-
// "background-color"
|
|
8234
|
-
]);
|
|
7663
|
+
const supportsFlags = {};
|
|
8235
7664
|
|
|
8236
|
-
|
|
7665
|
+
function memoSupports(callback, supportsFlag) {
|
|
7666
|
+
const memoized = memo(callback);
|
|
7667
|
+
return () => supportsFlags[supportsFlag] ?? memoized();
|
|
7668
|
+
}
|
|
7669
|
+
|
|
7670
|
+
const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
|
|
7671
|
+
try {
|
|
7672
|
+
document
|
|
7673
|
+
.createElement("div")
|
|
7674
|
+
.animate({ opacity: 0 }, { easing: "linear(0, 1)" });
|
|
7675
|
+
}
|
|
7676
|
+
catch (e) {
|
|
7677
|
+
return false;
|
|
7678
|
+
}
|
|
7679
|
+
return true;
|
|
7680
|
+
}, "linearEasing");
|
|
8237
7681
|
|
|
8238
7682
|
const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
|
|
8239
7683
|
|
|
@@ -8253,8 +7697,10 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
8253
7697
|
if (!easing) {
|
|
8254
7698
|
return undefined;
|
|
8255
7699
|
}
|
|
8256
|
-
else if (typeof easing === "function"
|
|
8257
|
-
return
|
|
7700
|
+
else if (typeof easing === "function") {
|
|
7701
|
+
return supportsLinearEasing()
|
|
7702
|
+
? generateLinearEasing(easing, duration)
|
|
7703
|
+
: "ease-out";
|
|
8258
7704
|
}
|
|
8259
7705
|
else if (isBezierDefinition(easing)) {
|
|
8260
7706
|
return cubicBezierAsString(easing);
|
|
@@ -8268,7 +7714,7 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
8268
7714
|
}
|
|
8269
7715
|
}
|
|
8270
7716
|
|
|
8271
|
-
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "
|
|
7717
|
+
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeOut", times, } = {}, pseudoElement = undefined) {
|
|
8272
7718
|
const keyframeOptions = {
|
|
8273
7719
|
[valueName]: keyframes,
|
|
8274
7720
|
};
|
|
@@ -8280,473 +7726,517 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
8280
7726
|
*/
|
|
8281
7727
|
if (Array.isArray(easing))
|
|
8282
7728
|
keyframeOptions.easing = easing;
|
|
8283
|
-
const
|
|
7729
|
+
const options = {
|
|
8284
7730
|
delay,
|
|
8285
7731
|
duration,
|
|
8286
7732
|
easing: !Array.isArray(easing) ? easing : "linear",
|
|
8287
7733
|
fill: "both",
|
|
8288
7734
|
iterations: repeat + 1,
|
|
8289
7735
|
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
8290
|
-
|
|
8291
|
-
|
|
7736
|
+
};
|
|
7737
|
+
if (pseudoElement)
|
|
7738
|
+
options.pseudoElement = pseudoElement;
|
|
7739
|
+
const animation = element.animate(keyframeOptions, options);
|
|
8292
7740
|
return animation;
|
|
8293
7741
|
}
|
|
8294
7742
|
|
|
8295
|
-
function
|
|
8296
|
-
|
|
8297
|
-
animation.onfinish = null;
|
|
7743
|
+
function isGenerator(type) {
|
|
7744
|
+
return typeof type === "function" && "applyToOptions" in type;
|
|
8298
7745
|
}
|
|
8299
7746
|
|
|
8300
|
-
function
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
(
|
|
7747
|
+
function applyGeneratorOptions({ type, ...options }) {
|
|
7748
|
+
if (isGenerator(type) && supportsLinearEasing()) {
|
|
7749
|
+
return type.applyToOptions(options);
|
|
7750
|
+
}
|
|
7751
|
+
else {
|
|
7752
|
+
options.duration ?? (options.duration = 300);
|
|
7753
|
+
options.ease ?? (options.ease = "easeOut");
|
|
7754
|
+
}
|
|
7755
|
+
return options;
|
|
8307
7756
|
}
|
|
8308
7757
|
|
|
8309
7758
|
/**
|
|
8310
|
-
*
|
|
8311
|
-
* results (more than one keyframe per frame at 60fps) and
|
|
8312
|
-
* keyframe quantity.
|
|
8313
|
-
*/
|
|
8314
|
-
const sampleDelta = 10; //ms
|
|
8315
|
-
/**
|
|
8316
|
-
* Implement a practical max duration for keyframe generation
|
|
8317
|
-
* to prevent infinite loops
|
|
8318
|
-
*/
|
|
8319
|
-
const maxDuration = 20000;
|
|
8320
|
-
/**
|
|
8321
|
-
* Check if an animation can run natively via WAAPI or requires pregenerated keyframes.
|
|
8322
|
-
* WAAPI doesn't support spring or function easings so we run these as JS animation before
|
|
8323
|
-
* handing off.
|
|
7759
|
+
* NativeAnimation implements AnimationPlaybackControls for the browser's Web Animations API.
|
|
8324
7760
|
*/
|
|
8325
|
-
|
|
8326
|
-
return (isGenerator(options.type) ||
|
|
8327
|
-
options.type === "spring" ||
|
|
8328
|
-
!isWaapiSupportedEasing(options.ease));
|
|
8329
|
-
}
|
|
8330
|
-
function pregenerateKeyframes(keyframes, options) {
|
|
8331
|
-
/**
|
|
8332
|
-
* Create a main-thread animation to pregenerate keyframes.
|
|
8333
|
-
* We sample this at regular intervals to generate keyframes that we then
|
|
8334
|
-
* linearly interpolate between.
|
|
8335
|
-
*/
|
|
8336
|
-
const sampleAnimation = new MainThreadAnimation({
|
|
8337
|
-
...options,
|
|
8338
|
-
keyframes,
|
|
8339
|
-
repeat: 0,
|
|
8340
|
-
delay: 0,
|
|
8341
|
-
isGenerator: true,
|
|
8342
|
-
});
|
|
8343
|
-
let state = { done: false, value: keyframes[0] };
|
|
8344
|
-
const pregeneratedKeyframes = [];
|
|
8345
|
-
/**
|
|
8346
|
-
* Bail after 20 seconds of pre-generated keyframes as it's likely
|
|
8347
|
-
* we're heading for an infinite loop.
|
|
8348
|
-
*/
|
|
8349
|
-
let t = 0;
|
|
8350
|
-
while (!state.done && t < maxDuration) {
|
|
8351
|
-
state = sampleAnimation.sample(t);
|
|
8352
|
-
pregeneratedKeyframes.push(state.value);
|
|
8353
|
-
t += sampleDelta;
|
|
8354
|
-
}
|
|
8355
|
-
return {
|
|
8356
|
-
times: undefined,
|
|
8357
|
-
keyframes: pregeneratedKeyframes,
|
|
8358
|
-
duration: t - sampleDelta,
|
|
8359
|
-
ease: "linear",
|
|
8360
|
-
};
|
|
8361
|
-
}
|
|
8362
|
-
const unsupportedEasingFunctions = {
|
|
8363
|
-
anticipate,
|
|
8364
|
-
backInOut,
|
|
8365
|
-
circInOut,
|
|
8366
|
-
};
|
|
8367
|
-
function isUnsupportedEase(key) {
|
|
8368
|
-
return key in unsupportedEasingFunctions;
|
|
8369
|
-
}
|
|
8370
|
-
class AcceleratedAnimation extends BaseAnimation {
|
|
7761
|
+
class NativeAnimation extends WithPromise {
|
|
8371
7762
|
constructor(options) {
|
|
8372
|
-
super(
|
|
8373
|
-
|
|
8374
|
-
this.
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
7763
|
+
super();
|
|
7764
|
+
this.finishedTime = null;
|
|
7765
|
+
this.isStopped = false;
|
|
7766
|
+
if (!options)
|
|
7767
|
+
return;
|
|
7768
|
+
const { element, name, keyframes, pseudoElement, allowFlatten = false, finalKeyframe, onComplete, } = options;
|
|
7769
|
+
this.isPseudoElement = Boolean(pseudoElement);
|
|
7770
|
+
this.allowFlatten = allowFlatten;
|
|
7771
|
+
this.options = options;
|
|
7772
|
+
invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
|
|
7773
|
+
const transition = applyGeneratorOptions(options);
|
|
7774
|
+
this.animation = startWaapiAnimation(element, name, keyframes, transition, pseudoElement);
|
|
7775
|
+
if (transition.autoplay === false) {
|
|
7776
|
+
this.animation.pause();
|
|
7777
|
+
}
|
|
7778
|
+
this.animation.onfinish = () => {
|
|
7779
|
+
this.finishedTime = this.time;
|
|
7780
|
+
if (!pseudoElement) {
|
|
7781
|
+
const keyframe = getFinalKeyframe(keyframes, this.options, finalKeyframe, this.speed);
|
|
7782
|
+
if (this.updateMotionValue) {
|
|
7783
|
+
this.updateMotionValue(keyframe);
|
|
7784
|
+
}
|
|
7785
|
+
else {
|
|
7786
|
+
/**
|
|
7787
|
+
* If we can, we want to commit the final style as set by the user,
|
|
7788
|
+
* rather than the computed keyframe value supplied by the animation.
|
|
7789
|
+
*/
|
|
7790
|
+
setStyle(element, name, keyframe);
|
|
7791
|
+
}
|
|
7792
|
+
this.animation.cancel();
|
|
7793
|
+
}
|
|
7794
|
+
onComplete?.();
|
|
7795
|
+
this.notifyFinished();
|
|
7796
|
+
};
|
|
8379
7797
|
/**
|
|
8380
|
-
*
|
|
8381
|
-
* the animation failed to initialised.
|
|
7798
|
+
* TODO: In a breaking change, we should replace this with `.notifyCancel()`
|
|
8382
7799
|
*/
|
|
8383
|
-
|
|
8384
|
-
|
|
7800
|
+
this.animation.oncancel = () => this.notifyFinished();
|
|
7801
|
+
}
|
|
7802
|
+
play() {
|
|
7803
|
+
if (this.isStopped)
|
|
7804
|
+
return;
|
|
7805
|
+
this.animation.play();
|
|
7806
|
+
if (this.state === "finished") {
|
|
7807
|
+
this.updateFinished();
|
|
8385
7808
|
}
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
7809
|
+
}
|
|
7810
|
+
pause() {
|
|
7811
|
+
this.animation.pause();
|
|
7812
|
+
}
|
|
7813
|
+
complete() {
|
|
7814
|
+
this.animation.finish?.();
|
|
7815
|
+
}
|
|
7816
|
+
cancel() {
|
|
7817
|
+
try {
|
|
7818
|
+
this.animation.cancel();
|
|
8395
7819
|
}
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
if (
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
}
|
|
8409
|
-
duration = pregeneratedAnimation.duration;
|
|
8410
|
-
times = pregeneratedAnimation.times;
|
|
8411
|
-
ease = pregeneratedAnimation.ease;
|
|
8412
|
-
type = "keyframes";
|
|
8413
|
-
}
|
|
8414
|
-
const animation = startWaapiAnimation(motionValue.owner.current, name, keyframes, { ...this.options, duration, times, ease });
|
|
8415
|
-
// Override the browser calculated startTime with one synchronised to other JS
|
|
8416
|
-
// and WAAPI animations starting this event loop.
|
|
8417
|
-
animation.startTime = startTime ?? this.calcStartTime();
|
|
8418
|
-
if (this.pendingTimeline) {
|
|
8419
|
-
attachTimeline(animation, this.pendingTimeline);
|
|
8420
|
-
this.pendingTimeline = undefined;
|
|
7820
|
+
catch (e) { }
|
|
7821
|
+
}
|
|
7822
|
+
stop() {
|
|
7823
|
+
if (this.isStopped)
|
|
7824
|
+
return;
|
|
7825
|
+
this.isStopped = true;
|
|
7826
|
+
const { state } = this;
|
|
7827
|
+
if (state === "idle" || state === "finished") {
|
|
7828
|
+
return;
|
|
7829
|
+
}
|
|
7830
|
+
if (this.updateMotionValue) {
|
|
7831
|
+
this.updateMotionValue();
|
|
8421
7832
|
}
|
|
8422
7833
|
else {
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
7834
|
+
this.commitStyles();
|
|
7835
|
+
}
|
|
7836
|
+
if (!this.isPseudoElement)
|
|
7837
|
+
this.cancel();
|
|
7838
|
+
}
|
|
7839
|
+
/**
|
|
7840
|
+
* WAAPI doesn't natively have any interruption capabilities.
|
|
7841
|
+
*
|
|
7842
|
+
* In this method, we commit styles back to the DOM before cancelling
|
|
7843
|
+
* the animation.
|
|
7844
|
+
*
|
|
7845
|
+
* This is designed to be overridden by NativeAnimationExtended, which
|
|
7846
|
+
* will create a renderless JS animation and sample it twice to calculate
|
|
7847
|
+
* its current value, "previous" value, and therefore allow
|
|
7848
|
+
* Motion to also correctly calculate velocity for any subsequent animation
|
|
7849
|
+
* while deferring the commit until the next animation frame.
|
|
7850
|
+
*/
|
|
7851
|
+
commitStyles() {
|
|
7852
|
+
if (!this.isPseudoElement) {
|
|
7853
|
+
this.animation.commitStyles?.();
|
|
8438
7854
|
}
|
|
8439
|
-
return {
|
|
8440
|
-
animation,
|
|
8441
|
-
duration,
|
|
8442
|
-
times,
|
|
8443
|
-
type,
|
|
8444
|
-
ease,
|
|
8445
|
-
keyframes: keyframes,
|
|
8446
|
-
};
|
|
8447
7855
|
}
|
|
8448
7856
|
get duration() {
|
|
8449
|
-
const
|
|
8450
|
-
|
|
8451
|
-
return 0;
|
|
8452
|
-
const { duration } = resolved;
|
|
8453
|
-
return millisecondsToSeconds(duration);
|
|
7857
|
+
const duration = this.animation.effect?.getComputedTiming?.().duration || 0;
|
|
7858
|
+
return millisecondsToSeconds(Number(duration));
|
|
8454
7859
|
}
|
|
8455
7860
|
get time() {
|
|
8456
|
-
|
|
8457
|
-
if (!resolved)
|
|
8458
|
-
return 0;
|
|
8459
|
-
const { animation } = resolved;
|
|
8460
|
-
return millisecondsToSeconds(animation.currentTime || 0);
|
|
7861
|
+
return millisecondsToSeconds(Number(this.animation.currentTime) || 0);
|
|
8461
7862
|
}
|
|
8462
7863
|
set time(newTime) {
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
return;
|
|
8466
|
-
const { animation } = resolved;
|
|
8467
|
-
animation.currentTime = secondsToMilliseconds(newTime);
|
|
7864
|
+
this.finishedTime = null;
|
|
7865
|
+
this.animation.currentTime = secondsToMilliseconds(newTime);
|
|
8468
7866
|
}
|
|
7867
|
+
/**
|
|
7868
|
+
* The playback speed of the animation.
|
|
7869
|
+
* 1 = normal speed, 2 = double speed, 0.5 = half speed.
|
|
7870
|
+
*/
|
|
8469
7871
|
get speed() {
|
|
8470
|
-
|
|
8471
|
-
if (!resolved)
|
|
8472
|
-
return 1;
|
|
8473
|
-
const { animation } = resolved;
|
|
8474
|
-
return animation.playbackRate;
|
|
8475
|
-
}
|
|
8476
|
-
get finished() {
|
|
8477
|
-
return this.resolved.animation.finished;
|
|
7872
|
+
return this.animation.playbackRate;
|
|
8478
7873
|
}
|
|
8479
7874
|
set speed(newSpeed) {
|
|
8480
|
-
|
|
8481
|
-
if (
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
animation.playbackRate = newSpeed;
|
|
7875
|
+
// Allow backwards playback after finishing
|
|
7876
|
+
if (newSpeed < 0)
|
|
7877
|
+
this.finishedTime = null;
|
|
7878
|
+
this.animation.playbackRate = newSpeed;
|
|
8485
7879
|
}
|
|
8486
7880
|
get state() {
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
const { animation } = resolved;
|
|
8491
|
-
return animation.playState;
|
|
7881
|
+
return this.finishedTime !== null
|
|
7882
|
+
? "finished"
|
|
7883
|
+
: this.animation.playState;
|
|
8492
7884
|
}
|
|
8493
7885
|
get startTime() {
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
// Coerce to number as TypeScript incorrectly types this
|
|
8499
|
-
// as CSSNumberish
|
|
8500
|
-
return animation.startTime;
|
|
7886
|
+
return Number(this.animation.startTime);
|
|
7887
|
+
}
|
|
7888
|
+
set startTime(newStartTime) {
|
|
7889
|
+
this.animation.startTime = newStartTime;
|
|
8501
7890
|
}
|
|
8502
7891
|
/**
|
|
8503
|
-
*
|
|
8504
|
-
* Currently used for scroll animations.
|
|
7892
|
+
* Attaches a timeline to the animation, for instance the `ScrollTimeline`.
|
|
8505
7893
|
*/
|
|
8506
|
-
attachTimeline(timeline) {
|
|
8507
|
-
if (
|
|
8508
|
-
this.
|
|
7894
|
+
attachTimeline({ timeline, observe }) {
|
|
7895
|
+
if (this.allowFlatten) {
|
|
7896
|
+
this.animation.effect?.updateTiming({ easing: "linear" });
|
|
8509
7897
|
}
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
const { animation } = resolved;
|
|
8515
|
-
attachTimeline(animation, timeline);
|
|
7898
|
+
this.animation.onfinish = null;
|
|
7899
|
+
if (timeline && supportsScrollTimeline()) {
|
|
7900
|
+
this.animation.timeline = timeline;
|
|
7901
|
+
return noop;
|
|
8516
7902
|
}
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
play() {
|
|
8520
|
-
if (this.isStopped)
|
|
8521
|
-
return;
|
|
8522
|
-
const { resolved } = this;
|
|
8523
|
-
if (!resolved)
|
|
8524
|
-
return;
|
|
8525
|
-
const { animation } = resolved;
|
|
8526
|
-
if (animation.playState === "finished") {
|
|
8527
|
-
this.updateFinishedPromise();
|
|
7903
|
+
else {
|
|
7904
|
+
return observe(this);
|
|
8528
7905
|
}
|
|
8529
|
-
animation.play();
|
|
8530
7906
|
}
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
7907
|
+
}
|
|
7908
|
+
|
|
7909
|
+
const unsupportedEasingFunctions = {
|
|
7910
|
+
anticipate,
|
|
7911
|
+
backInOut,
|
|
7912
|
+
circInOut,
|
|
7913
|
+
};
|
|
7914
|
+
function isUnsupportedEase(key) {
|
|
7915
|
+
return key in unsupportedEasingFunctions;
|
|
7916
|
+
}
|
|
7917
|
+
function replaceStringEasing(transition) {
|
|
7918
|
+
if (typeof transition.ease === "string" &&
|
|
7919
|
+
isUnsupportedEase(transition.ease)) {
|
|
7920
|
+
transition.ease = unsupportedEasingFunctions[transition.ease];
|
|
8537
7921
|
}
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
const { animation, keyframes, duration, type, ease, times } = resolved;
|
|
8549
|
-
if (animation.playState === "idle" ||
|
|
8550
|
-
animation.playState === "finished") {
|
|
8551
|
-
return;
|
|
8552
|
-
}
|
|
7922
|
+
}
|
|
7923
|
+
|
|
7924
|
+
/**
|
|
7925
|
+
* 10ms is chosen here as it strikes a balance between smooth
|
|
7926
|
+
* results (more than one keyframe per frame at 60fps) and
|
|
7927
|
+
* keyframe quantity.
|
|
7928
|
+
*/
|
|
7929
|
+
const sampleDelta = 10; //ms
|
|
7930
|
+
class NativeAnimationExtended extends NativeAnimation {
|
|
7931
|
+
constructor(options) {
|
|
8553
7932
|
/**
|
|
8554
|
-
*
|
|
7933
|
+
* The base NativeAnimation function only supports a subset
|
|
7934
|
+
* of Motion easings, and WAAPI also only supports some
|
|
7935
|
+
* easing functions via string/cubic-bezier definitions.
|
|
8555
7936
|
*
|
|
8556
|
-
*
|
|
8557
|
-
*
|
|
8558
|
-
*
|
|
8559
|
-
* Motion to calculate velocity for any subsequent animation.
|
|
7937
|
+
* This function replaces those unsupported easing functions
|
|
7938
|
+
* with a JS easing function. This will later get compiled
|
|
7939
|
+
* to a linear() easing function.
|
|
8560
7940
|
*/
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);
|
|
7941
|
+
replaceStringEasing(options);
|
|
7942
|
+
/**
|
|
7943
|
+
* Ensure we replace the transition type with a generator function
|
|
7944
|
+
* before passing to WAAPI.
|
|
7945
|
+
*
|
|
7946
|
+
* TODO: Does this have a better home? It could be shared with
|
|
7947
|
+
* JSAnimation.
|
|
7948
|
+
*/
|
|
7949
|
+
replaceTransitionType(options);
|
|
7950
|
+
super(options);
|
|
7951
|
+
if (options.startTime) {
|
|
7952
|
+
this.startTime = options.startTime;
|
|
8574
7953
|
}
|
|
8575
|
-
|
|
8576
|
-
onStop && onStop();
|
|
8577
|
-
this.cancel();
|
|
7954
|
+
this.options = options;
|
|
8578
7955
|
}
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
7956
|
+
/**
|
|
7957
|
+
* WAAPI doesn't natively have any interruption capabilities.
|
|
7958
|
+
*
|
|
7959
|
+
* Rather than read commited styles back out of the DOM, we can
|
|
7960
|
+
* create a renderless JS animation and sample it twice to calculate
|
|
7961
|
+
* its current value, "previous" value, and therefore allow
|
|
7962
|
+
* Motion to calculate velocity for any subsequent animation.
|
|
7963
|
+
*/
|
|
7964
|
+
updateMotionValue(value) {
|
|
7965
|
+
const { motionValue, onUpdate, onComplete, element, ...options } = this.options;
|
|
7966
|
+
if (!motionValue)
|
|
8582
7967
|
return;
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
cancel() {
|
|
8586
|
-
const { resolved } = this;
|
|
8587
|
-
if (!resolved)
|
|
7968
|
+
if (value !== undefined) {
|
|
7969
|
+
motionValue.set(value);
|
|
8588
7970
|
return;
|
|
8589
|
-
resolved.animation.cancel();
|
|
8590
|
-
}
|
|
8591
|
-
static supports(options) {
|
|
8592
|
-
const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
|
|
8593
|
-
if (!motionValue ||
|
|
8594
|
-
!motionValue.owner ||
|
|
8595
|
-
!(motionValue.owner.current instanceof HTMLElement)) {
|
|
8596
|
-
return false;
|
|
8597
7971
|
}
|
|
8598
|
-
const
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
* no way to read the value from WAAPI every frame.
|
|
8606
|
-
*/
|
|
8607
|
-
!onUpdate &&
|
|
8608
|
-
!repeatDelay &&
|
|
8609
|
-
repeatType !== "mirror" &&
|
|
8610
|
-
damping !== 0 &&
|
|
8611
|
-
type !== "inertia");
|
|
7972
|
+
const sampleAnimation = new JSAnimation({
|
|
7973
|
+
...options,
|
|
7974
|
+
autoplay: false,
|
|
7975
|
+
});
|
|
7976
|
+
const sampleTime = secondsToMilliseconds(this.finishedTime ?? this.time);
|
|
7977
|
+
motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);
|
|
7978
|
+
sampleAnimation.stop();
|
|
8612
7979
|
}
|
|
8613
7980
|
}
|
|
8614
7981
|
|
|
8615
|
-
const underDampedSpring = {
|
|
8616
|
-
type: "spring",
|
|
8617
|
-
stiffness: 500,
|
|
8618
|
-
damping: 25,
|
|
8619
|
-
restSpeed: 10,
|
|
8620
|
-
};
|
|
8621
|
-
const criticallyDampedSpring = (target) => ({
|
|
8622
|
-
type: "spring",
|
|
8623
|
-
stiffness: 550,
|
|
8624
|
-
damping: target === 0 ? 2 * Math.sqrt(550) : 30,
|
|
8625
|
-
restSpeed: 10,
|
|
8626
|
-
});
|
|
8627
|
-
const keyframesTransition = {
|
|
8628
|
-
type: "keyframes",
|
|
8629
|
-
duration: 0.8,
|
|
8630
|
-
};
|
|
8631
7982
|
/**
|
|
8632
|
-
*
|
|
8633
|
-
*
|
|
7983
|
+
* Check if a value is animatable. Examples:
|
|
7984
|
+
*
|
|
7985
|
+
* ✅: 100, "100px", "#fff"
|
|
7986
|
+
* ❌: "block", "url(2.jpg)"
|
|
7987
|
+
* @param value
|
|
7988
|
+
*
|
|
7989
|
+
* @internal
|
|
8634
7990
|
*/
|
|
8635
|
-
const
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
7991
|
+
const isAnimatable = (value, name) => {
|
|
7992
|
+
// If the list of keys tat might be non-animatable grows, replace with Set
|
|
7993
|
+
if (name === "zIndex")
|
|
7994
|
+
return false;
|
|
7995
|
+
// If it's a number or a keyframes array, we can animate it. We might at some point
|
|
7996
|
+
// need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
|
|
7997
|
+
// but for now lets leave it like this for performance reasons
|
|
7998
|
+
if (typeof value === "number" || Array.isArray(value))
|
|
7999
|
+
return true;
|
|
8000
|
+
if (typeof value === "string" && // It's animatable if we have a string
|
|
8001
|
+
(complex.test(value) || value === "0") && // And it contains numbers and/or colors
|
|
8002
|
+
!value.startsWith("url(") // Unless it starts with "url("
|
|
8003
|
+
) {
|
|
8004
|
+
return true;
|
|
8648
8005
|
}
|
|
8649
|
-
return
|
|
8006
|
+
return false;
|
|
8650
8007
|
};
|
|
8651
8008
|
|
|
8009
|
+
function hasKeyframesChanged(keyframes) {
|
|
8010
|
+
const current = keyframes[0];
|
|
8011
|
+
if (keyframes.length === 1)
|
|
8012
|
+
return true;
|
|
8013
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
8014
|
+
if (keyframes[i] !== current)
|
|
8015
|
+
return true;
|
|
8016
|
+
}
|
|
8017
|
+
}
|
|
8018
|
+
function canAnimate(keyframes, name, type, velocity) {
|
|
8019
|
+
/**
|
|
8020
|
+
* Check if we're able to animate between the start and end keyframes,
|
|
8021
|
+
* and throw a warning if we're attempting to animate between one that's
|
|
8022
|
+
* animatable and another that isn't.
|
|
8023
|
+
*/
|
|
8024
|
+
const originKeyframe = keyframes[0];
|
|
8025
|
+
if (originKeyframe === null)
|
|
8026
|
+
return false;
|
|
8027
|
+
/**
|
|
8028
|
+
* These aren't traditionally animatable but we do support them.
|
|
8029
|
+
* In future we could look into making this more generic or replacing
|
|
8030
|
+
* this function with mix() === mixImmediate
|
|
8031
|
+
*/
|
|
8032
|
+
if (name === "display" || name === "visibility")
|
|
8033
|
+
return true;
|
|
8034
|
+
const targetKeyframe = keyframes[keyframes.length - 1];
|
|
8035
|
+
const isOriginAnimatable = isAnimatable(originKeyframe, name);
|
|
8036
|
+
const isTargetAnimatable = isAnimatable(targetKeyframe, name);
|
|
8037
|
+
warning(isOriginAnimatable === isTargetAnimatable, `You are trying to animate ${name} from "${originKeyframe}" to "${targetKeyframe}". ${originKeyframe} is not an animatable value - to enable this animation set ${originKeyframe} to a value animatable to ${targetKeyframe} via the \`style\` property.`);
|
|
8038
|
+
// Always skip if any of these are true
|
|
8039
|
+
if (!isOriginAnimatable || !isTargetAnimatable) {
|
|
8040
|
+
return false;
|
|
8041
|
+
}
|
|
8042
|
+
return (hasKeyframesChanged(keyframes) ||
|
|
8043
|
+
((type === "spring" || isGenerator(type)) && velocity));
|
|
8044
|
+
}
|
|
8045
|
+
|
|
8652
8046
|
/**
|
|
8653
|
-
*
|
|
8654
|
-
* This filters out orchestration options and returns true
|
|
8655
|
-
* if any options are left.
|
|
8047
|
+
* A list of values that can be hardware-accelerated.
|
|
8656
8048
|
*/
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8049
|
+
const acceleratedValues = new Set([
|
|
8050
|
+
"opacity",
|
|
8051
|
+
"clipPath",
|
|
8052
|
+
"filter",
|
|
8053
|
+
"transform",
|
|
8054
|
+
// TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
|
|
8055
|
+
// or until we implement support for linear() easing.
|
|
8056
|
+
// "background-color"
|
|
8057
|
+
]);
|
|
8058
|
+
const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
|
|
8059
|
+
function supportsBrowserAnimation(options) {
|
|
8060
|
+
const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
|
|
8061
|
+
if (!motionValue ||
|
|
8062
|
+
!motionValue.owner ||
|
|
8063
|
+
!(motionValue.owner.current instanceof HTMLElement)) {
|
|
8064
|
+
return false;
|
|
8065
|
+
}
|
|
8066
|
+
const { onUpdate, transformTemplate } = motionValue.owner.getProps();
|
|
8067
|
+
return (supportsWaapi() &&
|
|
8068
|
+
name &&
|
|
8069
|
+
acceleratedValues.has(name) &&
|
|
8070
|
+
(name !== "transform" || !transformTemplate) &&
|
|
8071
|
+
/**
|
|
8072
|
+
* If we're outputting values to onUpdate then we can't use WAAPI as there's
|
|
8073
|
+
* no way to read the value from WAAPI every frame.
|
|
8074
|
+
*/
|
|
8075
|
+
!onUpdate &&
|
|
8076
|
+
!repeatDelay &&
|
|
8077
|
+
repeatType !== "mirror" &&
|
|
8078
|
+
damping !== 0 &&
|
|
8079
|
+
type !== "inertia");
|
|
8665
8080
|
}
|
|
8666
8081
|
|
|
8667
|
-
|
|
8668
|
-
|
|
8669
|
-
|
|
8670
|
-
|
|
8671
|
-
|
|
8672
|
-
|
|
8673
|
-
|
|
8082
|
+
/**
|
|
8083
|
+
* Maximum time allowed between an animation being created and it being
|
|
8084
|
+
* resolved for us to use the latter as the start time.
|
|
8085
|
+
*
|
|
8086
|
+
* This is to ensure that while we prefer to "start" an animation as soon
|
|
8087
|
+
* as it's triggered, we also want to avoid a visual jump if there's a big delay
|
|
8088
|
+
* between these two moments.
|
|
8089
|
+
*/
|
|
8090
|
+
const MAX_RESOLVE_DELAY = 40;
|
|
8091
|
+
class AsyncMotionValueAnimation extends WithPromise {
|
|
8092
|
+
constructor({ autoplay = true, delay = 0, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", keyframes, name, motionValue, element, ...options }) {
|
|
8093
|
+
super();
|
|
8094
|
+
/**
|
|
8095
|
+
* Bound to support return animation.stop pattern
|
|
8096
|
+
*/
|
|
8097
|
+
this.stop = () => {
|
|
8098
|
+
if (this._animation) {
|
|
8099
|
+
this._animation.stop();
|
|
8100
|
+
this.stopTimeline?.();
|
|
8101
|
+
}
|
|
8102
|
+
else {
|
|
8103
|
+
this.keyframeResolver?.cancel();
|
|
8104
|
+
}
|
|
8105
|
+
};
|
|
8106
|
+
this.createdAt = time.now();
|
|
8107
|
+
const optionsWithDefaults = {
|
|
8108
|
+
autoplay,
|
|
8109
|
+
delay,
|
|
8110
|
+
type,
|
|
8111
|
+
repeat,
|
|
8112
|
+
repeatDelay,
|
|
8113
|
+
repeatType,
|
|
8114
|
+
name,
|
|
8115
|
+
motionValue,
|
|
8116
|
+
element,
|
|
8117
|
+
...options,
|
|
8118
|
+
};
|
|
8119
|
+
const KeyframeResolver$1 = element?.KeyframeResolver || KeyframeResolver;
|
|
8120
|
+
this.keyframeResolver = new KeyframeResolver$1(keyframes, (resolvedKeyframes, finalKeyframe, forced) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe, optionsWithDefaults, !forced), name, motionValue, element);
|
|
8121
|
+
this.keyframeResolver?.scheduleResolve();
|
|
8122
|
+
}
|
|
8123
|
+
onKeyframesResolved(keyframes, finalKeyframe, options, sync) {
|
|
8124
|
+
this.keyframeResolver = undefined;
|
|
8125
|
+
const { name, type, velocity, delay, isHandoff, onUpdate } = options;
|
|
8126
|
+
this.resolvedAt = time.now();
|
|
8127
|
+
/**
|
|
8128
|
+
* If we can't animate this value with the resolved keyframes
|
|
8129
|
+
* then we should complete it immediately.
|
|
8130
|
+
*/
|
|
8131
|
+
if (!canAnimate(keyframes, name, type, velocity)) {
|
|
8132
|
+
if (MotionGlobalConfig.instantAnimations || !delay) {
|
|
8133
|
+
onUpdate?.(getFinalKeyframe(keyframes, options, finalKeyframe));
|
|
8134
|
+
}
|
|
8135
|
+
keyframes[0] = keyframes[keyframes.length - 1];
|
|
8136
|
+
options.duration = 0;
|
|
8137
|
+
options.repeat = 0;
|
|
8138
|
+
}
|
|
8139
|
+
/**
|
|
8140
|
+
* Resolve startTime for the animation.
|
|
8141
|
+
*
|
|
8142
|
+
* This method uses the createdAt and resolvedAt to calculate the
|
|
8143
|
+
* animation startTime. *Ideally*, we would use the createdAt time as t=0
|
|
8144
|
+
* as the following frame would then be the first frame of the animation in
|
|
8145
|
+
* progress, which would feel snappier.
|
|
8146
|
+
*
|
|
8147
|
+
* However, if there's a delay (main thread work) between the creation of
|
|
8148
|
+
* the animation and the first commited frame, we prefer to use resolvedAt
|
|
8149
|
+
* to avoid a sudden jump into the animation.
|
|
8150
|
+
*/
|
|
8151
|
+
const startTime = sync
|
|
8152
|
+
? !this.resolvedAt
|
|
8153
|
+
? this.createdAt
|
|
8154
|
+
: this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY
|
|
8155
|
+
? this.resolvedAt
|
|
8156
|
+
: this.createdAt
|
|
8157
|
+
: undefined;
|
|
8158
|
+
const resolvedOptions = {
|
|
8159
|
+
startTime,
|
|
8160
|
+
finalKeyframe,
|
|
8161
|
+
...options,
|
|
8162
|
+
keyframes,
|
|
8163
|
+
};
|
|
8164
|
+
/**
|
|
8165
|
+
* Animate via WAAPI if possible. If this is a handoff animation, the optimised animation will be running via
|
|
8166
|
+
* WAAPI. Therefore, this animation must be JS to ensure it runs "under" the
|
|
8167
|
+
* optimised animation.
|
|
8168
|
+
*/
|
|
8169
|
+
const animation = !isHandoff && supportsBrowserAnimation(resolvedOptions)
|
|
8170
|
+
? new NativeAnimationExtended({
|
|
8171
|
+
...resolvedOptions,
|
|
8172
|
+
element: resolvedOptions.motionValue.owner.current,
|
|
8173
|
+
})
|
|
8174
|
+
: new JSAnimation(resolvedOptions);
|
|
8175
|
+
animation.finished.then(() => this.notifyFinished()).catch(noop);
|
|
8176
|
+
if (this.pendingTimeline) {
|
|
8177
|
+
this.stopTimeline = animation.attachTimeline(this.pendingTimeline);
|
|
8178
|
+
this.pendingTimeline = undefined;
|
|
8179
|
+
}
|
|
8180
|
+
this._animation = animation;
|
|
8674
8181
|
}
|
|
8675
8182
|
get finished() {
|
|
8676
|
-
|
|
8183
|
+
if (!this._animation) {
|
|
8184
|
+
return this._finished;
|
|
8185
|
+
}
|
|
8186
|
+
else {
|
|
8187
|
+
return this.animation.finished;
|
|
8188
|
+
}
|
|
8677
8189
|
}
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
*/
|
|
8681
|
-
getAll(propName) {
|
|
8682
|
-
return this.animations[0][propName];
|
|
8190
|
+
then(onResolve, _onReject) {
|
|
8191
|
+
return this.finished.finally(onResolve).then(() => { });
|
|
8683
8192
|
}
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8193
|
+
get animation() {
|
|
8194
|
+
if (!this._animation) {
|
|
8195
|
+
flushKeyframeResolvers();
|
|
8687
8196
|
}
|
|
8197
|
+
return this._animation;
|
|
8688
8198
|
}
|
|
8689
|
-
|
|
8690
|
-
|
|
8691
|
-
if (supportsScrollTimeline() && animation.attachTimeline) {
|
|
8692
|
-
return animation.attachTimeline(timeline);
|
|
8693
|
-
}
|
|
8694
|
-
else if (typeof fallback === "function") {
|
|
8695
|
-
return fallback(animation);
|
|
8696
|
-
}
|
|
8697
|
-
});
|
|
8698
|
-
return () => {
|
|
8699
|
-
subscriptions.forEach((cancel, i) => {
|
|
8700
|
-
cancel && cancel();
|
|
8701
|
-
this.animations[i].stop();
|
|
8702
|
-
});
|
|
8703
|
-
};
|
|
8199
|
+
get duration() {
|
|
8200
|
+
return this.animation.duration;
|
|
8704
8201
|
}
|
|
8705
8202
|
get time() {
|
|
8706
|
-
return this.
|
|
8203
|
+
return this.animation.time;
|
|
8707
8204
|
}
|
|
8708
|
-
set time(
|
|
8709
|
-
this.
|
|
8205
|
+
set time(newTime) {
|
|
8206
|
+
this.animation.time = newTime;
|
|
8710
8207
|
}
|
|
8711
8208
|
get speed() {
|
|
8712
|
-
return this.
|
|
8209
|
+
return this.animation.speed;
|
|
8713
8210
|
}
|
|
8714
|
-
|
|
8715
|
-
this.
|
|
8211
|
+
get state() {
|
|
8212
|
+
return this.animation.state;
|
|
8213
|
+
}
|
|
8214
|
+
set speed(newSpeed) {
|
|
8215
|
+
this.animation.speed = newSpeed;
|
|
8716
8216
|
}
|
|
8717
8217
|
get startTime() {
|
|
8718
|
-
return this.
|
|
8218
|
+
return this.animation.startTime;
|
|
8719
8219
|
}
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
max = Math.max(max, this.animations[i].duration);
|
|
8220
|
+
attachTimeline(timeline) {
|
|
8221
|
+
if (this._animation) {
|
|
8222
|
+
this.stopTimeline = this.animation.attachTimeline(timeline);
|
|
8724
8223
|
}
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
}
|
|
8730
|
-
flatten() {
|
|
8731
|
-
this.runAll("flatten");
|
|
8224
|
+
else {
|
|
8225
|
+
this.pendingTimeline = timeline;
|
|
8226
|
+
}
|
|
8227
|
+
return () => this.stop();
|
|
8732
8228
|
}
|
|
8733
8229
|
play() {
|
|
8734
|
-
this.
|
|
8230
|
+
this.animation.play();
|
|
8735
8231
|
}
|
|
8736
8232
|
pause() {
|
|
8737
|
-
this.
|
|
8738
|
-
}
|
|
8739
|
-
cancel() {
|
|
8740
|
-
this.runAll("cancel");
|
|
8233
|
+
this.animation.pause();
|
|
8741
8234
|
}
|
|
8742
8235
|
complete() {
|
|
8743
|
-
this.
|
|
8236
|
+
this.animation.complete();
|
|
8744
8237
|
}
|
|
8745
|
-
|
|
8746
|
-
|
|
8747
|
-
class GroupAnimationWithThen extends GroupAnimation {
|
|
8748
|
-
then(onResolve, _onReject) {
|
|
8749
|
-
return this.finished.finally(onResolve).then(() => { });
|
|
8238
|
+
cancel() {
|
|
8239
|
+
this.animation.cancel();
|
|
8750
8240
|
}
|
|
8751
8241
|
}
|
|
8752
8242
|
|
|
@@ -8764,7 +8254,7 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8764
8254
|
*/
|
|
8765
8255
|
let { elapsed = 0 } = transition;
|
|
8766
8256
|
elapsed = elapsed - secondsToMilliseconds(delay);
|
|
8767
|
-
|
|
8257
|
+
const options = {
|
|
8768
8258
|
keyframes: Array.isArray(target) ? target : [null, target],
|
|
8769
8259
|
ease: "easeOut",
|
|
8770
8260
|
velocity: value.getVelocity(),
|
|
@@ -8787,22 +8277,18 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8787
8277
|
* unique transition settings for this value.
|
|
8788
8278
|
*/
|
|
8789
8279
|
if (!isTransitionDefined(valueTransition)) {
|
|
8790
|
-
options
|
|
8791
|
-
...options,
|
|
8792
|
-
...getDefaultTransition(name, options),
|
|
8793
|
-
};
|
|
8280
|
+
Object.assign(options, getDefaultTransition(name, options));
|
|
8794
8281
|
}
|
|
8795
8282
|
/**
|
|
8796
8283
|
* Both WAAPI and our internal animation functions use durations
|
|
8797
8284
|
* as defined by milliseconds, while our external API defines them
|
|
8798
8285
|
* as seconds.
|
|
8799
8286
|
*/
|
|
8800
|
-
|
|
8801
|
-
|
|
8802
|
-
|
|
8803
|
-
|
|
8804
|
-
|
|
8805
|
-
}
|
|
8287
|
+
options.duration && (options.duration = secondsToMilliseconds(options.duration));
|
|
8288
|
+
options.repeatDelay && (options.repeatDelay = secondsToMilliseconds(options.repeatDelay));
|
|
8289
|
+
/**
|
|
8290
|
+
* Support deprecated way to set initial value. Prefer keyframe syntax.
|
|
8291
|
+
*/
|
|
8806
8292
|
if (options.from !== undefined) {
|
|
8807
8293
|
options.keyframes[0] = options.from;
|
|
8808
8294
|
}
|
|
@@ -8814,6 +8300,12 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8814
8300
|
shouldSkip = true;
|
|
8815
8301
|
}
|
|
8816
8302
|
}
|
|
8303
|
+
if (MotionGlobalConfig.instantAnimations ||
|
|
8304
|
+
MotionGlobalConfig.skipAnimations) {
|
|
8305
|
+
shouldSkip = true;
|
|
8306
|
+
options.duration = 0;
|
|
8307
|
+
options.delay = 0;
|
|
8308
|
+
}
|
|
8817
8309
|
/**
|
|
8818
8310
|
* If the transition type or easing has been explicitly set by the user
|
|
8819
8311
|
* then we don't want to allow flattening the animation.
|
|
@@ -8825,30 +8317,28 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8825
8317
|
* this early check prevents the need to create an animation at all.
|
|
8826
8318
|
*/
|
|
8827
8319
|
if (shouldSkip && !isHandoff && value.get() !== undefined) {
|
|
8828
|
-
const finalKeyframe = getFinalKeyframe(options.keyframes, valueTransition);
|
|
8320
|
+
const finalKeyframe = getFinalKeyframe$1(options.keyframes, valueTransition);
|
|
8829
8321
|
if (finalKeyframe !== undefined) {
|
|
8830
8322
|
frame.update(() => {
|
|
8831
8323
|
options.onUpdate(finalKeyframe);
|
|
8832
8324
|
options.onComplete();
|
|
8833
8325
|
});
|
|
8834
|
-
|
|
8835
|
-
// than returning undefined
|
|
8836
|
-
return new GroupAnimationWithThen([]);
|
|
8326
|
+
return;
|
|
8837
8327
|
}
|
|
8838
8328
|
}
|
|
8839
|
-
|
|
8840
|
-
* Animate via WAAPI if possible. If this is a handoff animation, the optimised animation will be running via
|
|
8841
|
-
* WAAPI. Therefore, this animation must be JS to ensure it runs "under" the
|
|
8842
|
-
* optimised animation.
|
|
8843
|
-
*/
|
|
8844
|
-
if (!isHandoff && AcceleratedAnimation.supports(options)) {
|
|
8845
|
-
return new AcceleratedAnimation(options);
|
|
8846
|
-
}
|
|
8847
|
-
else {
|
|
8848
|
-
return new MainThreadAnimation(options);
|
|
8849
|
-
}
|
|
8329
|
+
return new AsyncMotionValueAnimation(options);
|
|
8850
8330
|
};
|
|
8851
8331
|
|
|
8332
|
+
const positionalKeys = new Set([
|
|
8333
|
+
"width",
|
|
8334
|
+
"height",
|
|
8335
|
+
"top",
|
|
8336
|
+
"left",
|
|
8337
|
+
"right",
|
|
8338
|
+
"bottom",
|
|
8339
|
+
...transformPropOrder,
|
|
8340
|
+
]);
|
|
8341
|
+
|
|
8852
8342
|
/**
|
|
8853
8343
|
* Decide whether we should block this animation. Previously, we achieved this
|
|
8854
8344
|
* just by checking whether the key was listed in protectedKeys, but this
|
|
@@ -8880,6 +8370,17 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
|
|
|
8880
8370
|
delay,
|
|
8881
8371
|
...getValueTransition(transition || {}, key),
|
|
8882
8372
|
};
|
|
8373
|
+
/**
|
|
8374
|
+
* If the value is already at the defined target, skip the animation.
|
|
8375
|
+
*/
|
|
8376
|
+
const currentValue = value.get();
|
|
8377
|
+
if (currentValue !== undefined &&
|
|
8378
|
+
!value.isAnimating &&
|
|
8379
|
+
!Array.isArray(valueTarget) &&
|
|
8380
|
+
valueTarget === currentValue &&
|
|
8381
|
+
!valueTransition.velocity) {
|
|
8382
|
+
continue;
|
|
8383
|
+
}
|
|
8883
8384
|
/**
|
|
8884
8385
|
* If this is the first time a value is being animated, check
|
|
8885
8386
|
* to see if we're handling off from an existing animation.
|
|
@@ -10832,7 +10333,7 @@ function delay(callback, timeout) {
|
|
|
10832
10333
|
callback(elapsed - timeout);
|
|
10833
10334
|
}
|
|
10834
10335
|
};
|
|
10835
|
-
frame.
|
|
10336
|
+
frame.setup(checkElapsed, true);
|
|
10836
10337
|
return () => cancelFrame(checkElapsed);
|
|
10837
10338
|
}
|
|
10838
10339
|
|
|
@@ -12126,9 +11627,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
12126
11627
|
}
|
|
12127
11628
|
setAnimationOrigin(delta, hasOnlyRelativeTargetChanged = false) {
|
|
12128
11629
|
const snapshot = this.snapshot;
|
|
12129
|
-
const snapshotLatestValues = snapshot
|
|
12130
|
-
? snapshot.latestValues
|
|
12131
|
-
: {};
|
|
11630
|
+
const snapshotLatestValues = snapshot ? snapshot.latestValues : {};
|
|
12132
11631
|
const mixedValues = { ...this.latestValues };
|
|
12133
11632
|
const targetDelta = createDelta();
|
|
12134
11633
|
if (!this.relativeParent ||
|
|
@@ -13196,15 +12695,6 @@ function initPrefersReducedMotion() {
|
|
|
13196
12695
|
}
|
|
13197
12696
|
}
|
|
13198
12697
|
|
|
13199
|
-
/**
|
|
13200
|
-
* A list of all ValueTypes
|
|
13201
|
-
*/
|
|
13202
|
-
const valueTypes = [...dimensionValueTypes, color, complex];
|
|
13203
|
-
/**
|
|
13204
|
-
* Tests a value against the list of ValueTypes
|
|
13205
|
-
*/
|
|
13206
|
-
const findValueType = (v) => valueTypes.find(testValueType(v));
|
|
13207
|
-
|
|
13208
12698
|
const visualElementStore = new WeakMap();
|
|
13209
12699
|
|
|
13210
12700
|
function updateMotionValuesFromProps(element, next, prev) {
|
|
@@ -13222,7 +12712,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
13222
12712
|
* and warn against mismatches.
|
|
13223
12713
|
*/
|
|
13224
12714
|
if (process.env.NODE_ENV === "development") {
|
|
13225
|
-
warnOnce(nextValue.version === "12.
|
|
12715
|
+
warnOnce(nextValue.version === "12.9.0", `Attempting to mix Motion versions ${nextValue.version} with 12.9.0 may not work as expected.`);
|
|
13226
12716
|
}
|
|
13227
12717
|
}
|
|
13228
12718
|
else if (isMotionValue(prevValue)) {
|
|
@@ -13261,6 +12751,108 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
13261
12751
|
return next;
|
|
13262
12752
|
}
|
|
13263
12753
|
|
|
12754
|
+
/**
|
|
12755
|
+
* Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
|
|
12756
|
+
*/
|
|
12757
|
+
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
|
|
12758
|
+
|
|
12759
|
+
/**
|
|
12760
|
+
* Check if the value is a zero value string like "0px" or "0%"
|
|
12761
|
+
*/
|
|
12762
|
+
const isZeroValueString = (v) => /^0[^.\s]+$/u.test(v);
|
|
12763
|
+
|
|
12764
|
+
/**
|
|
12765
|
+
* ValueType for "auto"
|
|
12766
|
+
*/
|
|
12767
|
+
const auto = {
|
|
12768
|
+
test: (v) => v === "auto",
|
|
12769
|
+
parse: (v) => v,
|
|
12770
|
+
};
|
|
12771
|
+
|
|
12772
|
+
/**
|
|
12773
|
+
* Tests a provided value against a ValueType
|
|
12774
|
+
*/
|
|
12775
|
+
const testValueType = (v) => (type) => type.test(v);
|
|
12776
|
+
|
|
12777
|
+
/**
|
|
12778
|
+
* A list of value types commonly used for dimensions
|
|
12779
|
+
*/
|
|
12780
|
+
const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
|
|
12781
|
+
/**
|
|
12782
|
+
* Tests a dimensional value against the list of dimension ValueTypes
|
|
12783
|
+
*/
|
|
12784
|
+
const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
|
|
12785
|
+
|
|
12786
|
+
/**
|
|
12787
|
+
* A list of all ValueTypes
|
|
12788
|
+
*/
|
|
12789
|
+
const valueTypes = [...dimensionValueTypes, color, complex];
|
|
12790
|
+
/**
|
|
12791
|
+
* Tests a value against the list of ValueTypes
|
|
12792
|
+
*/
|
|
12793
|
+
const findValueType = (v) => valueTypes.find(testValueType(v));
|
|
12794
|
+
|
|
12795
|
+
/**
|
|
12796
|
+
* Properties that should default to 1 or 100%
|
|
12797
|
+
*/
|
|
12798
|
+
const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
|
|
12799
|
+
function applyDefaultFilter(v) {
|
|
12800
|
+
const [name, value] = v.slice(0, -1).split("(");
|
|
12801
|
+
if (name === "drop-shadow")
|
|
12802
|
+
return v;
|
|
12803
|
+
const [number] = value.match(floatRegex) || [];
|
|
12804
|
+
if (!number)
|
|
12805
|
+
return v;
|
|
12806
|
+
const unit = value.replace(number, "");
|
|
12807
|
+
let defaultValue = maxDefaults.has(name) ? 1 : 0;
|
|
12808
|
+
if (number !== value)
|
|
12809
|
+
defaultValue *= 100;
|
|
12810
|
+
return name + "(" + defaultValue + unit + ")";
|
|
12811
|
+
}
|
|
12812
|
+
const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
|
|
12813
|
+
const filter = {
|
|
12814
|
+
...complex,
|
|
12815
|
+
getAnimatableNone: (v) => {
|
|
12816
|
+
const functions = v.match(functionRegex);
|
|
12817
|
+
return functions ? functions.map(applyDefaultFilter).join(" ") : v;
|
|
12818
|
+
},
|
|
12819
|
+
};
|
|
12820
|
+
|
|
12821
|
+
/**
|
|
12822
|
+
* A map of default value types for common values
|
|
12823
|
+
*/
|
|
12824
|
+
const defaultValueTypes = {
|
|
12825
|
+
...numberValueTypes,
|
|
12826
|
+
// Color props
|
|
12827
|
+
color,
|
|
12828
|
+
backgroundColor: color,
|
|
12829
|
+
outlineColor: color,
|
|
12830
|
+
fill: color,
|
|
12831
|
+
stroke: color,
|
|
12832
|
+
// Border props
|
|
12833
|
+
borderColor: color,
|
|
12834
|
+
borderTopColor: color,
|
|
12835
|
+
borderRightColor: color,
|
|
12836
|
+
borderBottomColor: color,
|
|
12837
|
+
borderLeftColor: color,
|
|
12838
|
+
filter,
|
|
12839
|
+
WebkitFilter: filter,
|
|
12840
|
+
};
|
|
12841
|
+
/**
|
|
12842
|
+
* Gets the default ValueType for the provided value key
|
|
12843
|
+
*/
|
|
12844
|
+
const getDefaultValueType = (key) => defaultValueTypes[key];
|
|
12845
|
+
|
|
12846
|
+
function getAnimatableNone(key, value) {
|
|
12847
|
+
let defaultValueType = getDefaultValueType(key);
|
|
12848
|
+
if (defaultValueType !== filter)
|
|
12849
|
+
defaultValueType = complex;
|
|
12850
|
+
// If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
|
|
12851
|
+
return defaultValueType.getAnimatableNone
|
|
12852
|
+
? defaultValueType.getAnimatableNone(value)
|
|
12853
|
+
: undefined;
|
|
12854
|
+
}
|
|
12855
|
+
|
|
13264
12856
|
const propEventHandlers = [
|
|
13265
12857
|
"AnimationStart",
|
|
13266
12858
|
"AnimationComplete",
|
|
@@ -13355,8 +12947,7 @@ class VisualElement {
|
|
|
13355
12947
|
frame.render(this.render, false, true);
|
|
13356
12948
|
}
|
|
13357
12949
|
};
|
|
13358
|
-
const { latestValues, renderState
|
|
13359
|
-
this.onUpdate = onUpdate;
|
|
12950
|
+
const { latestValues, renderState } = visualState;
|
|
13360
12951
|
this.latestValues = latestValues;
|
|
13361
12952
|
this.baseTarget = { ...latestValues };
|
|
13362
12953
|
this.initialValues = props.initial ? { ...latestValues } : {};
|
|
@@ -13558,7 +13149,6 @@ class VisualElement {
|
|
|
13558
13149
|
if (this.handleChildMotionValue) {
|
|
13559
13150
|
this.handleChildMotionValue();
|
|
13560
13151
|
}
|
|
13561
|
-
this.onUpdate && this.onUpdate(this);
|
|
13562
13152
|
}
|
|
13563
13153
|
getProps() {
|
|
13564
13154
|
return this.props;
|
|
@@ -13718,6 +13308,202 @@ class VisualElement {
|
|
|
13718
13308
|
}
|
|
13719
13309
|
}
|
|
13720
13310
|
|
|
13311
|
+
/**
|
|
13312
|
+
* Parse Framer's special CSS variable format into a CSS token and a fallback.
|
|
13313
|
+
*
|
|
13314
|
+
* ```
|
|
13315
|
+
* `var(--foo, #fff)` => [`--foo`, '#fff']
|
|
13316
|
+
* ```
|
|
13317
|
+
*
|
|
13318
|
+
* @param current
|
|
13319
|
+
*/
|
|
13320
|
+
const splitCSSVariableRegex =
|
|
13321
|
+
// eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
|
|
13322
|
+
/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
|
|
13323
|
+
function parseCSSVariable(current) {
|
|
13324
|
+
const match = splitCSSVariableRegex.exec(current);
|
|
13325
|
+
if (!match)
|
|
13326
|
+
return [,];
|
|
13327
|
+
const [, token1, token2, fallback] = match;
|
|
13328
|
+
return [`--${token1 ?? token2}`, fallback];
|
|
13329
|
+
}
|
|
13330
|
+
const maxDepth = 4;
|
|
13331
|
+
function getVariableValue(current, element, depth = 1) {
|
|
13332
|
+
invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
|
|
13333
|
+
const [token, fallback] = parseCSSVariable(current);
|
|
13334
|
+
// No CSS variable detected
|
|
13335
|
+
if (!token)
|
|
13336
|
+
return;
|
|
13337
|
+
// Attempt to read this CSS variable off the element
|
|
13338
|
+
const resolved = window.getComputedStyle(element).getPropertyValue(token);
|
|
13339
|
+
if (resolved) {
|
|
13340
|
+
const trimmed = resolved.trim();
|
|
13341
|
+
return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
|
|
13342
|
+
}
|
|
13343
|
+
return isCSSVariableToken(fallback)
|
|
13344
|
+
? getVariableValue(fallback, element, depth + 1)
|
|
13345
|
+
: fallback;
|
|
13346
|
+
}
|
|
13347
|
+
|
|
13348
|
+
function isNone(value) {
|
|
13349
|
+
if (typeof value === "number") {
|
|
13350
|
+
return value === 0;
|
|
13351
|
+
}
|
|
13352
|
+
else if (value !== null) {
|
|
13353
|
+
return value === "none" || value === "0" || isZeroValueString(value);
|
|
13354
|
+
}
|
|
13355
|
+
else {
|
|
13356
|
+
return true;
|
|
13357
|
+
}
|
|
13358
|
+
}
|
|
13359
|
+
|
|
13360
|
+
/**
|
|
13361
|
+
* If we encounter keyframes like "none" or "0" and we also have keyframes like
|
|
13362
|
+
* "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
|
|
13363
|
+
* the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
|
|
13364
|
+
* zero equivalents, i.e. "#fff0" or "0px 0px".
|
|
13365
|
+
*/
|
|
13366
|
+
const invalidTemplates = new Set(["auto", "none", "0"]);
|
|
13367
|
+
function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
|
|
13368
|
+
let i = 0;
|
|
13369
|
+
let animatableTemplate = undefined;
|
|
13370
|
+
while (i < unresolvedKeyframes.length && !animatableTemplate) {
|
|
13371
|
+
const keyframe = unresolvedKeyframes[i];
|
|
13372
|
+
if (typeof keyframe === "string" &&
|
|
13373
|
+
!invalidTemplates.has(keyframe) &&
|
|
13374
|
+
analyseComplexValue(keyframe).values.length) {
|
|
13375
|
+
animatableTemplate = unresolvedKeyframes[i];
|
|
13376
|
+
}
|
|
13377
|
+
i++;
|
|
13378
|
+
}
|
|
13379
|
+
if (animatableTemplate && name) {
|
|
13380
|
+
for (const noneIndex of noneKeyframeIndexes) {
|
|
13381
|
+
unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
|
|
13382
|
+
}
|
|
13383
|
+
}
|
|
13384
|
+
}
|
|
13385
|
+
|
|
13386
|
+
class DOMKeyframesResolver extends KeyframeResolver {
|
|
13387
|
+
constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
|
|
13388
|
+
super(unresolvedKeyframes, onComplete, name, motionValue, element, true);
|
|
13389
|
+
}
|
|
13390
|
+
readKeyframes() {
|
|
13391
|
+
const { unresolvedKeyframes, element, name } = this;
|
|
13392
|
+
if (!element || !element.current)
|
|
13393
|
+
return;
|
|
13394
|
+
super.readKeyframes();
|
|
13395
|
+
/**
|
|
13396
|
+
* If any keyframe is a CSS variable, we need to find its value by sampling the element
|
|
13397
|
+
*/
|
|
13398
|
+
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
13399
|
+
let keyframe = unresolvedKeyframes[i];
|
|
13400
|
+
if (typeof keyframe === "string") {
|
|
13401
|
+
keyframe = keyframe.trim();
|
|
13402
|
+
if (isCSSVariableToken(keyframe)) {
|
|
13403
|
+
const resolved = getVariableValue(keyframe, element.current);
|
|
13404
|
+
if (resolved !== undefined) {
|
|
13405
|
+
unresolvedKeyframes[i] = resolved;
|
|
13406
|
+
}
|
|
13407
|
+
if (i === unresolvedKeyframes.length - 1) {
|
|
13408
|
+
this.finalKeyframe = keyframe;
|
|
13409
|
+
}
|
|
13410
|
+
}
|
|
13411
|
+
}
|
|
13412
|
+
}
|
|
13413
|
+
/**
|
|
13414
|
+
* Resolve "none" values. We do this potentially twice - once before and once after measuring keyframes.
|
|
13415
|
+
* This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which
|
|
13416
|
+
* have a far bigger performance impact.
|
|
13417
|
+
*/
|
|
13418
|
+
this.resolveNoneKeyframes();
|
|
13419
|
+
/**
|
|
13420
|
+
* Check to see if unit type has changed. If so schedule jobs that will
|
|
13421
|
+
* temporarily set styles to the destination keyframes.
|
|
13422
|
+
* Skip if we have more than two keyframes or this isn't a positional value.
|
|
13423
|
+
* TODO: We can throw if there are multiple keyframes and the value type changes.
|
|
13424
|
+
*/
|
|
13425
|
+
if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {
|
|
13426
|
+
return;
|
|
13427
|
+
}
|
|
13428
|
+
const [origin, target] = unresolvedKeyframes;
|
|
13429
|
+
const originType = findDimensionValueType(origin);
|
|
13430
|
+
const targetType = findDimensionValueType(target);
|
|
13431
|
+
/**
|
|
13432
|
+
* Either we don't recognise these value types or we can animate between them.
|
|
13433
|
+
*/
|
|
13434
|
+
if (originType === targetType)
|
|
13435
|
+
return;
|
|
13436
|
+
/**
|
|
13437
|
+
* If both values are numbers or pixels, we can animate between them by
|
|
13438
|
+
* converting them to numbers.
|
|
13439
|
+
*/
|
|
13440
|
+
if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {
|
|
13441
|
+
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
13442
|
+
const value = unresolvedKeyframes[i];
|
|
13443
|
+
if (typeof value === "string") {
|
|
13444
|
+
unresolvedKeyframes[i] = parseFloat(value);
|
|
13445
|
+
}
|
|
13446
|
+
}
|
|
13447
|
+
}
|
|
13448
|
+
else {
|
|
13449
|
+
/**
|
|
13450
|
+
* Else, the only way to resolve this is by measuring the element.
|
|
13451
|
+
*/
|
|
13452
|
+
this.needsMeasurement = true;
|
|
13453
|
+
}
|
|
13454
|
+
}
|
|
13455
|
+
resolveNoneKeyframes() {
|
|
13456
|
+
const { unresolvedKeyframes, name } = this;
|
|
13457
|
+
const noneKeyframeIndexes = [];
|
|
13458
|
+
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
13459
|
+
if (unresolvedKeyframes[i] === null ||
|
|
13460
|
+
isNone(unresolvedKeyframes[i])) {
|
|
13461
|
+
noneKeyframeIndexes.push(i);
|
|
13462
|
+
}
|
|
13463
|
+
}
|
|
13464
|
+
if (noneKeyframeIndexes.length) {
|
|
13465
|
+
makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);
|
|
13466
|
+
}
|
|
13467
|
+
}
|
|
13468
|
+
measureInitialState() {
|
|
13469
|
+
const { element, unresolvedKeyframes, name } = this;
|
|
13470
|
+
if (!element || !element.current)
|
|
13471
|
+
return;
|
|
13472
|
+
if (name === "height") {
|
|
13473
|
+
this.suspendedScrollY = window.pageYOffset;
|
|
13474
|
+
}
|
|
13475
|
+
this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
13476
|
+
unresolvedKeyframes[0] = this.measuredOrigin;
|
|
13477
|
+
// Set final key frame to measure after next render
|
|
13478
|
+
const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
13479
|
+
if (measureKeyframe !== undefined) {
|
|
13480
|
+
element.getValue(name, measureKeyframe).jump(measureKeyframe, false);
|
|
13481
|
+
}
|
|
13482
|
+
}
|
|
13483
|
+
measureEndState() {
|
|
13484
|
+
const { element, name, unresolvedKeyframes } = this;
|
|
13485
|
+
if (!element || !element.current)
|
|
13486
|
+
return;
|
|
13487
|
+
const value = element.getValue(name);
|
|
13488
|
+
value && value.jump(this.measuredOrigin, false);
|
|
13489
|
+
const finalKeyframeIndex = unresolvedKeyframes.length - 1;
|
|
13490
|
+
const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];
|
|
13491
|
+
unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
13492
|
+
if (finalKeyframe !== null && this.finalKeyframe === undefined) {
|
|
13493
|
+
this.finalKeyframe = finalKeyframe;
|
|
13494
|
+
}
|
|
13495
|
+
// If we removed transform values, reapply them before the next render
|
|
13496
|
+
if (this.removedTransforms?.length) {
|
|
13497
|
+
this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {
|
|
13498
|
+
element
|
|
13499
|
+
.getValue(unsetTransformName)
|
|
13500
|
+
.set(unsetTransformValue);
|
|
13501
|
+
});
|
|
13502
|
+
}
|
|
13503
|
+
this.resolveNoneKeyframes();
|
|
13504
|
+
}
|
|
13505
|
+
}
|
|
13506
|
+
|
|
13721
13507
|
class DOMVisualElement extends VisualElement {
|
|
13722
13508
|
constructor() {
|
|
13723
13509
|
super(...arguments);
|
|
@@ -13756,6 +13542,14 @@ class DOMVisualElement extends VisualElement {
|
|
|
13756
13542
|
}
|
|
13757
13543
|
}
|
|
13758
13544
|
|
|
13545
|
+
function renderHTML(element, { style, vars }, styleProp, projection) {
|
|
13546
|
+
Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
|
|
13547
|
+
// Loop over any CSS variables and assign those.
|
|
13548
|
+
for (const key in vars) {
|
|
13549
|
+
element.style.setProperty(key, vars[key]);
|
|
13550
|
+
}
|
|
13551
|
+
}
|
|
13552
|
+
|
|
13759
13553
|
function getComputedStyle$1(element) {
|
|
13760
13554
|
return window.getComputedStyle(element);
|
|
13761
13555
|
}
|
|
@@ -13788,17 +13582,48 @@ class HTMLVisualElement extends DOMVisualElement {
|
|
|
13788
13582
|
}
|
|
13789
13583
|
}
|
|
13790
13584
|
|
|
13585
|
+
/**
|
|
13586
|
+
* A set of attribute names that are always read/written as camel case.
|
|
13587
|
+
*/
|
|
13588
|
+
const camelCaseAttributes = new Set([
|
|
13589
|
+
"baseFrequency",
|
|
13590
|
+
"diffuseConstant",
|
|
13591
|
+
"kernelMatrix",
|
|
13592
|
+
"kernelUnitLength",
|
|
13593
|
+
"keySplines",
|
|
13594
|
+
"keyTimes",
|
|
13595
|
+
"limitingConeAngle",
|
|
13596
|
+
"markerHeight",
|
|
13597
|
+
"markerWidth",
|
|
13598
|
+
"numOctaves",
|
|
13599
|
+
"targetX",
|
|
13600
|
+
"targetY",
|
|
13601
|
+
"surfaceScale",
|
|
13602
|
+
"specularConstant",
|
|
13603
|
+
"specularExponent",
|
|
13604
|
+
"stdDeviation",
|
|
13605
|
+
"tableValues",
|
|
13606
|
+
"viewBox",
|
|
13607
|
+
"gradientTransform",
|
|
13608
|
+
"pathLength",
|
|
13609
|
+
"startOffset",
|
|
13610
|
+
"textLength",
|
|
13611
|
+
"lengthAdjust",
|
|
13612
|
+
]);
|
|
13613
|
+
|
|
13614
|
+
function renderSVG(element, renderState, _styleProp, projection) {
|
|
13615
|
+
renderHTML(element, renderState, undefined, projection);
|
|
13616
|
+
for (const key in renderState.attrs) {
|
|
13617
|
+
element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
|
|
13618
|
+
}
|
|
13619
|
+
}
|
|
13620
|
+
|
|
13791
13621
|
class SVGVisualElement extends DOMVisualElement {
|
|
13792
13622
|
constructor() {
|
|
13793
13623
|
super(...arguments);
|
|
13794
13624
|
this.type = "svg";
|
|
13795
13625
|
this.isSVGTag = false;
|
|
13796
13626
|
this.measureInstanceViewportBox = createBox;
|
|
13797
|
-
this.updateDimensions = () => {
|
|
13798
|
-
if (this.current && !this.renderState.dimensions) {
|
|
13799
|
-
updateSVGDimensions(this.current, this.renderState);
|
|
13800
|
-
}
|
|
13801
|
-
};
|
|
13802
13627
|
}
|
|
13803
13628
|
getBaseTargetFromProps(props, key) {
|
|
13804
13629
|
return props[key];
|
|
@@ -13814,11 +13639,6 @@ class SVGVisualElement extends DOMVisualElement {
|
|
|
13814
13639
|
scrapeMotionValuesFromProps(props, prevProps, visualElement) {
|
|
13815
13640
|
return scrapeMotionValuesFromProps(props, prevProps, visualElement);
|
|
13816
13641
|
}
|
|
13817
|
-
onBindTransform() {
|
|
13818
|
-
if (this.current && !this.renderState.dimensions) {
|
|
13819
|
-
frame.postRender(this.updateDimensions);
|
|
13820
|
-
}
|
|
13821
|
-
}
|
|
13822
13642
|
build(renderState, latestValues, props) {
|
|
13823
13643
|
buildSVGAttrs(renderState, latestValues, this.isSVGTag, props.transformTemplate);
|
|
13824
13644
|
}
|
|
@@ -34145,20 +33965,20 @@ var initStripe = function initStripe(maybeStripe, args, startTime) {
|
|
|
34145
33965
|
return stripe;
|
|
34146
33966
|
}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
34147
33967
|
|
|
34148
|
-
var stripePromise
|
|
33968
|
+
var stripePromise;
|
|
34149
33969
|
var loadCalled = false;
|
|
34150
33970
|
|
|
34151
33971
|
var getStripePromise = function getStripePromise() {
|
|
34152
|
-
if (stripePromise
|
|
34153
|
-
return stripePromise
|
|
33972
|
+
if (stripePromise) {
|
|
33973
|
+
return stripePromise;
|
|
34154
33974
|
}
|
|
34155
33975
|
|
|
34156
|
-
stripePromise
|
|
33976
|
+
stripePromise = loadScript(null)["catch"](function (error) {
|
|
34157
33977
|
// clear cache on error
|
|
34158
|
-
stripePromise
|
|
33978
|
+
stripePromise = null;
|
|
34159
33979
|
return Promise.reject(error);
|
|
34160
33980
|
});
|
|
34161
|
-
return stripePromise
|
|
33981
|
+
return stripePromise;
|
|
34162
33982
|
}; // Execute our own script injection after a tick to give users time to do their
|
|
34163
33983
|
// own script injection.
|
|
34164
33984
|
|
|
@@ -34228,9 +34048,8 @@ const CheckoutForm$1 = ({ onSuccess, onError, children, setSubmitting, }) => {
|
|
|
34228
34048
|
};
|
|
34229
34049
|
var CheckoutForm$2 = React.memo(CheckoutForm$1);
|
|
34230
34050
|
|
|
34231
|
-
|
|
34232
|
-
const stripePromise = loadStripe(
|
|
34233
|
-
function PaymentElement({ paymentSecret, checkoutAppearance, locale, fonts, onSuccess, onError, children, setSubmitting, }) {
|
|
34051
|
+
function PaymentElement({ paymentSecret, publicKey, checkoutAppearance, locale, fonts, onSuccess, onError, children, setSubmitting, }) {
|
|
34052
|
+
const stripePromise = loadStripe(publicKey !== null && publicKey !== void 0 ? publicKey : "");
|
|
34234
34053
|
const options = {
|
|
34235
34054
|
locale: locale !== null && locale !== void 0 ? locale : "en",
|
|
34236
34055
|
appearance: checkoutAppearance,
|
|
@@ -34242,7 +34061,7 @@ function PaymentElement({ paymentSecret, checkoutAppearance, locale, fonts, onSu
|
|
|
34242
34061
|
}
|
|
34243
34062
|
var PaymentElement$1 = React.memo(PaymentElement);
|
|
34244
34063
|
|
|
34245
|
-
function PaymentForm({ paymentSecret, onSuccess, onError, onBack, onDoubleBack, contactEmail, shippingAddress, shippingName, shippingPrice, checkoutAppearance, fonts, locale, }) {
|
|
34064
|
+
function PaymentForm({ paymentSecret, onSuccess, onError, onBack, onDoubleBack, contactEmail, shippingAddress, shippingName, shippingPrice, checkoutAppearance, fonts, locale, publicKey, }) {
|
|
34246
34065
|
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
34247
34066
|
const { t } = useTranslation();
|
|
34248
34067
|
return (React.createElement("div", { className: "space-y-6" },
|
|
@@ -34271,7 +34090,7 @@ function PaymentForm({ paymentSecret, onSuccess, onError, onBack, onDoubleBack,
|
|
|
34271
34090
|
" \u00B7 ",
|
|
34272
34091
|
shippingPrice)),
|
|
34273
34092
|
React.createElement(Button, { variant: "link", size: "link", onClick: onBack }, t("CheckoutEmbed.Shipping.change")))),
|
|
34274
|
-
React.createElement("div", { className: "mt-8" }, paymentSecret && (React.createElement(PaymentElement$1, { fonts: fonts, checkoutAppearance: convertCheckoutAppearanceToStripeAppearance(checkoutAppearance, fonts), locale: locale, paymentSecret: paymentSecret, onSuccess: onSuccess, onError: onError, setSubmitting: setIsSubmitting },
|
|
34093
|
+
React.createElement("div", { className: "mt-8" }, paymentSecret && (React.createElement(PaymentElement$1, { fonts: fonts, checkoutAppearance: convertCheckoutAppearanceToStripeAppearance(checkoutAppearance, fonts), locale: locale, paymentSecret: paymentSecret, onSuccess: onSuccess, onError: onError, setSubmitting: setIsSubmitting, publicKey: publicKey },
|
|
34275
34094
|
React.createElement("div", { className: "flex justify-between items-center pt-8" },
|
|
34276
34095
|
React.createElement(Button, { type: "button", variant: "ghost", onClick: onBack },
|
|
34277
34096
|
React.createElement(ChevronLeft, null),
|
|
@@ -34439,6 +34258,8 @@ const useFormStore = create()(persist((set) => ({
|
|
|
34439
34258
|
setFormData: (formData) => set({ formData }),
|
|
34440
34259
|
step: "customer",
|
|
34441
34260
|
setStep: (step) => set({ step }),
|
|
34261
|
+
checkoutId: "",
|
|
34262
|
+
setCheckoutId: (checkoutId) => set({ checkoutId }),
|
|
34442
34263
|
}), { name: `checkout` }));
|
|
34443
34264
|
|
|
34444
34265
|
const motionSettings = {
|
|
@@ -34448,8 +34269,9 @@ const motionSettings = {
|
|
|
34448
34269
|
transition: { duration: 0.2 },
|
|
34449
34270
|
};
|
|
34450
34271
|
function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl, clientSecret, customer, currency, checkoutAppearance, fonts, locale, setShippingCost, exchangeRate, }) {
|
|
34451
|
-
const { formData, setFormData, step, setStep } = useFormStore();
|
|
34272
|
+
const { formData, setFormData, step, setStep, checkoutId: storedCheckoutId, setCheckoutId, } = useFormStore();
|
|
34452
34273
|
const [paymentSecret, setPaymentSecret] = React.useState(null);
|
|
34274
|
+
const [publicKey, setPublicKey] = React.useState(null);
|
|
34453
34275
|
const [shippingRates, setShippingRates] = React.useState([]);
|
|
34454
34276
|
const validateStep = React.useCallback(() => {
|
|
34455
34277
|
if (step === "customer")
|
|
@@ -34471,21 +34293,53 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34471
34293
|
validateStep();
|
|
34472
34294
|
}, [step]);
|
|
34473
34295
|
React.useEffect(() => {
|
|
34474
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
34475
|
-
if (
|
|
34296
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19;
|
|
34297
|
+
if (checkoutId !== storedCheckoutId) {
|
|
34298
|
+
setStep("customer");
|
|
34299
|
+
setCheckoutId(checkoutId);
|
|
34300
|
+
if (customer) {
|
|
34301
|
+
setFormData({
|
|
34302
|
+
customerId: customer.id,
|
|
34303
|
+
customer: {
|
|
34304
|
+
firstName: (_c = (_b = (_a = customer.address) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.split(" ")[0]) !== null && _c !== void 0 ? _c : "",
|
|
34305
|
+
lastName: (_f = (_e = (_d = customer.address) === null || _d === void 0 ? void 0 : _d.name) === null || _e === void 0 ? void 0 : _e.split(" ")[1]) !== null && _f !== void 0 ? _f : "",
|
|
34306
|
+
phone: (_h = (_g = customer.address) === null || _g === void 0 ? void 0 : _g.phone) !== null && _h !== void 0 ? _h : "",
|
|
34307
|
+
email: (_j = customer.email) !== null && _j !== void 0 ? _j : "",
|
|
34308
|
+
address: {
|
|
34309
|
+
line1: (_l = (_k = customer.address) === null || _k === void 0 ? void 0 : _k.line1) !== null && _l !== void 0 ? _l : "",
|
|
34310
|
+
line2: (_o = (_m = customer.address) === null || _m === void 0 ? void 0 : _m.line2) !== null && _o !== void 0 ? _o : "",
|
|
34311
|
+
city: (_q = (_p = customer.address) === null || _p === void 0 ? void 0 : _p.city) !== null && _q !== void 0 ? _q : "",
|
|
34312
|
+
zipCode: (_s = (_r = customer.address) === null || _r === void 0 ? void 0 : _r.zipCode) !== null && _s !== void 0 ? _s : "",
|
|
34313
|
+
country: (_u = (_t = customer.address) === null || _t === void 0 ? void 0 : _t.country) !== null && _u !== void 0 ? _u : "",
|
|
34314
|
+
countryCode: (_w = (_v = customer.address) === null || _v === void 0 ? void 0 : _v.countryCode) !== null && _w !== void 0 ? _w : "",
|
|
34315
|
+
},
|
|
34316
|
+
},
|
|
34317
|
+
});
|
|
34318
|
+
}
|
|
34319
|
+
else if ((_x = formData.customer) === null || _x === void 0 ? void 0 : _x.email) {
|
|
34320
|
+
setFormData({
|
|
34321
|
+
customer: formData.customer,
|
|
34322
|
+
});
|
|
34323
|
+
}
|
|
34324
|
+
else {
|
|
34325
|
+
setFormData({});
|
|
34326
|
+
}
|
|
34327
|
+
return;
|
|
34328
|
+
}
|
|
34329
|
+
if (customer && !((_y = formData.customer) === null || _y === void 0 ? void 0 : _y.email)) {
|
|
34476
34330
|
const step = customer.id ? "shipping" : "customer";
|
|
34477
34331
|
setFormData(Object.assign(Object.assign({}, formData), { customerId: customer.id, customer: {
|
|
34478
|
-
firstName: (
|
|
34479
|
-
lastName: (
|
|
34480
|
-
phone: (
|
|
34481
|
-
email: (
|
|
34332
|
+
firstName: (_1 = (_0 = (_z = customer.address) === null || _z === void 0 ? void 0 : _z.name) === null || _0 === void 0 ? void 0 : _0.split(" ")[0]) !== null && _1 !== void 0 ? _1 : "",
|
|
34333
|
+
lastName: (_4 = (_3 = (_2 = customer.address) === null || _2 === void 0 ? void 0 : _2.name) === null || _3 === void 0 ? void 0 : _3.split(" ")[1]) !== null && _4 !== void 0 ? _4 : "",
|
|
34334
|
+
phone: (_6 = (_5 = customer.address) === null || _5 === void 0 ? void 0 : _5.phone) !== null && _6 !== void 0 ? _6 : "",
|
|
34335
|
+
email: (_7 = customer.email) !== null && _7 !== void 0 ? _7 : "",
|
|
34482
34336
|
address: {
|
|
34483
|
-
line1: (
|
|
34484
|
-
line2: (
|
|
34485
|
-
city: (
|
|
34486
|
-
zipCode: (
|
|
34487
|
-
country: (
|
|
34488
|
-
countryCode: (
|
|
34337
|
+
line1: (_9 = (_8 = customer.address) === null || _8 === void 0 ? void 0 : _8.line1) !== null && _9 !== void 0 ? _9 : "",
|
|
34338
|
+
line2: (_11 = (_10 = customer.address) === null || _10 === void 0 ? void 0 : _10.line2) !== null && _11 !== void 0 ? _11 : "",
|
|
34339
|
+
city: (_13 = (_12 = customer.address) === null || _12 === void 0 ? void 0 : _12.city) !== null && _13 !== void 0 ? _13 : "",
|
|
34340
|
+
zipCode: (_15 = (_14 = customer.address) === null || _14 === void 0 ? void 0 : _14.zipCode) !== null && _15 !== void 0 ? _15 : "",
|
|
34341
|
+
country: (_17 = (_16 = customer.address) === null || _16 === void 0 ? void 0 : _16.country) !== null && _17 !== void 0 ? _17 : "",
|
|
34342
|
+
countryCode: (_19 = (_18 = customer.address) === null || _18 === void 0 ? void 0 : _18.countryCode) !== null && _19 !== void 0 ? _19 : "",
|
|
34489
34343
|
},
|
|
34490
34344
|
} }));
|
|
34491
34345
|
setStep(step);
|
|
@@ -34549,8 +34403,9 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34549
34403
|
pickupPointId: data.pickupPointId,
|
|
34550
34404
|
},
|
|
34551
34405
|
});
|
|
34552
|
-
const paymentSecret = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34406
|
+
const { paymentSecret, publicKey } = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34553
34407
|
setPaymentSecret(paymentSecret);
|
|
34408
|
+
setPublicKey(publicKey);
|
|
34554
34409
|
setShippingCost(data.price);
|
|
34555
34410
|
setStep("payment");
|
|
34556
34411
|
});
|
|
@@ -34569,8 +34424,9 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34569
34424
|
};
|
|
34570
34425
|
React.useEffect(() => {
|
|
34571
34426
|
const asyncFunc = () => __awaiter(this, void 0, void 0, function* () {
|
|
34572
|
-
const paymentSecret = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34427
|
+
const { paymentSecret, publicKey } = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34573
34428
|
setPaymentSecret(paymentSecret);
|
|
34429
|
+
setPublicKey(publicKey);
|
|
34574
34430
|
});
|
|
34575
34431
|
if (!paymentSecret && step === "payment") {
|
|
34576
34432
|
asyncFunc();
|
|
@@ -34583,7 +34439,7 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34583
34439
|
step === "shipping" && formData.customer && (React.createElement(motion.div, Object.assign({ key: "shipping" }, motionSettings, { className: "absolute w-full" }),
|
|
34584
34440
|
React.createElement(ShippingMethodForm, { setFormData: setFormData, formData: formData, shippingRates: shippingRates, initialData: formData.shipping, onSubmit: handleShippingSubmit, onBack: handleBack, contactEmail: formData.customer.email, shippingAddress: formatAddress(formData.customer.address), currency: currency, exchangeRate: exchangeRate, locale: locale, countryCode: formData.customer.address.countryCode }))),
|
|
34585
34441
|
step === "payment" && formData.customer && formData.shipping && (React.createElement(motion.div, Object.assign({ key: "payment" }, motionSettings, { className: "absolute w-full" }),
|
|
34586
|
-
React.createElement(PaymentForm, { locale: locale, fonts: fonts, checkoutAppearance: checkoutAppearance, paymentSecret: paymentSecret, onSuccess: onSuccess, onError: onError, onBack: handleBack, onDoubleBack: handleDoubleBack, contactEmail: formData.customer.email, shippingAddress: formatAddress(formData.customer.address), shippingName: formData.shipping.name, shippingPrice: storeHelpers.formatPrice(formData.shipping.price, currency, exchangeRate) }))))));
|
|
34442
|
+
React.createElement(PaymentForm, { locale: locale, fonts: fonts, checkoutAppearance: checkoutAppearance, paymentSecret: paymentSecret, onSuccess: onSuccess, onError: onError, onBack: handleBack, onDoubleBack: handleDoubleBack, contactEmail: formData.customer.email, shippingAddress: formatAddress(formData.customer.address), shippingName: formData.shipping.name, shippingPrice: storeHelpers.formatPrice(formData.shipping.price, currency, exchangeRate), publicKey: publicKey }))))));
|
|
34587
34443
|
}
|
|
34588
34444
|
|
|
34589
34445
|
function CheckoutFormLoading() {
|