@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.mjs
CHANGED
|
@@ -3920,8 +3920,10 @@ const AnimatePresence = ({ children, custom, initial = true, onExitComplete, pre
|
|
|
3920
3920
|
};
|
|
3921
3921
|
|
|
3922
3922
|
const stepsOrder = [
|
|
3923
|
+
"setup", // Compute
|
|
3923
3924
|
"read", // Read
|
|
3924
3925
|
"resolveKeyframes", // Write/Read/Write/Read
|
|
3926
|
+
"preUpdate", // Compute
|
|
3925
3927
|
"update", // Compute
|
|
3926
3928
|
"preRender", // Compute
|
|
3927
3929
|
"render", // Write
|
|
@@ -4020,9 +4022,7 @@ function createRenderStep(runNextFrame, stepName) {
|
|
|
4020
4022
|
return step;
|
|
4021
4023
|
}
|
|
4022
4024
|
|
|
4023
|
-
const MotionGlobalConfig = {
|
|
4024
|
-
useManualTiming: false,
|
|
4025
|
-
};
|
|
4025
|
+
const MotionGlobalConfig = {};
|
|
4026
4026
|
|
|
4027
4027
|
const maxElapsed = 40;
|
|
4028
4028
|
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
@@ -4038,11 +4038,13 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
4038
4038
|
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
4039
4039
|
return acc;
|
|
4040
4040
|
}, {});
|
|
4041
|
-
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
4041
|
+
const { setup, read, resolveKeyframes, preUpdate, update, preRender, render, postRender, } = steps;
|
|
4042
4042
|
const processBatch = () => {
|
|
4043
|
-
const timestamp =
|
|
4043
|
+
const timestamp = MotionGlobalConfig.useManualTiming
|
|
4044
|
+
? state.timestamp
|
|
4045
|
+
: performance.now();
|
|
4044
4046
|
runNextFrame = false;
|
|
4045
|
-
{
|
|
4047
|
+
if (!MotionGlobalConfig.useManualTiming) {
|
|
4046
4048
|
state.delta = useDefaultElapsed
|
|
4047
4049
|
? 1000 / 60
|
|
4048
4050
|
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
|
|
@@ -4050,8 +4052,10 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
4050
4052
|
state.timestamp = timestamp;
|
|
4051
4053
|
state.isProcessing = true;
|
|
4052
4054
|
// Unrolled render loop for better per-frame performance
|
|
4055
|
+
setup.process(state);
|
|
4053
4056
|
read.process(state);
|
|
4054
4057
|
resolveKeyframes.process(state);
|
|
4058
|
+
preUpdate.process(state);
|
|
4055
4059
|
update.process(state);
|
|
4056
4060
|
preRender.process(state);
|
|
4057
4061
|
render.process(state);
|
|
@@ -4666,7 +4670,7 @@ const transformPropOrder = [
|
|
|
4666
4670
|
/**
|
|
4667
4671
|
* A quick lookup for transform props.
|
|
4668
4672
|
*/
|
|
4669
|
-
const transformProps = new Set(transformPropOrder);
|
|
4673
|
+
const transformProps = /*@__PURE__*/ (() => new Set(transformPropOrder))();
|
|
4670
4674
|
|
|
4671
4675
|
function isForcedMotionValue(key, { layout, layoutId }) {
|
|
4672
4676
|
return (transformProps.has(key) ||
|
|
@@ -4708,6 +4712,12 @@ const scale = {
|
|
|
4708
4712
|
default: 1,
|
|
4709
4713
|
};
|
|
4710
4714
|
|
|
4715
|
+
const int = {
|
|
4716
|
+
...number,
|
|
4717
|
+
transform: Math.round,
|
|
4718
|
+
};
|
|
4719
|
+
|
|
4720
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
4711
4721
|
const createUnitType = (unit) => ({
|
|
4712
4722
|
test: (v) => typeof v === "string" && v.endsWith(unit) && v.split(" ").length === 1,
|
|
4713
4723
|
parse: parseFloat,
|
|
@@ -4718,13 +4728,40 @@ const percent = /*@__PURE__*/ createUnitType("%");
|
|
|
4718
4728
|
const px = /*@__PURE__*/ createUnitType("px");
|
|
4719
4729
|
const vh = /*@__PURE__*/ createUnitType("vh");
|
|
4720
4730
|
const vw = /*@__PURE__*/ createUnitType("vw");
|
|
4721
|
-
const progressPercentage = {
|
|
4731
|
+
const progressPercentage = /*@__PURE__*/ (() => ({
|
|
4722
4732
|
...percent,
|
|
4723
4733
|
parse: (v) => percent.parse(v) / 100,
|
|
4724
4734
|
transform: (v) => percent.transform(v * 100),
|
|
4735
|
+
}))();
|
|
4736
|
+
|
|
4737
|
+
const transformValueTypes = {
|
|
4738
|
+
rotate: degrees,
|
|
4739
|
+
rotateX: degrees,
|
|
4740
|
+
rotateY: degrees,
|
|
4741
|
+
rotateZ: degrees,
|
|
4742
|
+
scale,
|
|
4743
|
+
scaleX: scale,
|
|
4744
|
+
scaleY: scale,
|
|
4745
|
+
scaleZ: scale,
|
|
4746
|
+
skew: degrees,
|
|
4747
|
+
skewX: degrees,
|
|
4748
|
+
skewY: degrees,
|
|
4749
|
+
distance: px,
|
|
4750
|
+
translateX: px,
|
|
4751
|
+
translateY: px,
|
|
4752
|
+
translateZ: px,
|
|
4753
|
+
x: px,
|
|
4754
|
+
y: px,
|
|
4755
|
+
z: px,
|
|
4756
|
+
perspective: px,
|
|
4757
|
+
transformPerspective: px,
|
|
4758
|
+
opacity: alpha,
|
|
4759
|
+
originX: progressPercentage,
|
|
4760
|
+
originY: progressPercentage,
|
|
4761
|
+
originZ: px,
|
|
4725
4762
|
};
|
|
4726
4763
|
|
|
4727
|
-
const
|
|
4764
|
+
const numberValueTypes = {
|
|
4728
4765
|
// Border props
|
|
4729
4766
|
borderWidth: px,
|
|
4730
4767
|
borderTopWidth: px,
|
|
@@ -4760,45 +4797,8 @@ const browserNumberValueTypes = {
|
|
|
4760
4797
|
// Misc
|
|
4761
4798
|
backgroundPositionX: px,
|
|
4762
4799
|
backgroundPositionY: px,
|
|
4763
|
-
};
|
|
4764
|
-
|
|
4765
|
-
const transformValueTypes = {
|
|
4766
|
-
rotate: degrees,
|
|
4767
|
-
rotateX: degrees,
|
|
4768
|
-
rotateY: degrees,
|
|
4769
|
-
rotateZ: degrees,
|
|
4770
|
-
scale,
|
|
4771
|
-
scaleX: scale,
|
|
4772
|
-
scaleY: scale,
|
|
4773
|
-
scaleZ: scale,
|
|
4774
|
-
skew: degrees,
|
|
4775
|
-
skewX: degrees,
|
|
4776
|
-
skewY: degrees,
|
|
4777
|
-
distance: px,
|
|
4778
|
-
translateX: px,
|
|
4779
|
-
translateY: px,
|
|
4780
|
-
translateZ: px,
|
|
4781
|
-
x: px,
|
|
4782
|
-
y: px,
|
|
4783
|
-
z: px,
|
|
4784
|
-
perspective: px,
|
|
4785
|
-
transformPerspective: px,
|
|
4786
|
-
opacity: alpha,
|
|
4787
|
-
originX: progressPercentage,
|
|
4788
|
-
originY: progressPercentage,
|
|
4789
|
-
originZ: px,
|
|
4790
|
-
};
|
|
4791
|
-
|
|
4792
|
-
const int = {
|
|
4793
|
-
...number,
|
|
4794
|
-
transform: Math.round,
|
|
4795
|
-
};
|
|
4796
|
-
|
|
4797
|
-
const numberValueTypes = {
|
|
4798
|
-
...browserNumberValueTypes,
|
|
4799
4800
|
...transformValueTypes,
|
|
4800
4801
|
zIndex: int,
|
|
4801
|
-
size: px,
|
|
4802
4802
|
// SVG
|
|
4803
4803
|
fillOpacity: alpha,
|
|
4804
4804
|
strokeOpacity: alpha,
|
|
@@ -5065,25 +5065,10 @@ function buildSVGPath(attrs, length, spacing = 1, offset = 0, useDashCase = true
|
|
|
5065
5065
|
attrs[keys.array] = `${pathLength} ${pathSpacing}`;
|
|
5066
5066
|
}
|
|
5067
5067
|
|
|
5068
|
-
function calcOrigin$1(origin, offset, size) {
|
|
5069
|
-
return typeof origin === "string"
|
|
5070
|
-
? origin
|
|
5071
|
-
: px.transform(offset + size * origin);
|
|
5072
|
-
}
|
|
5073
|
-
/**
|
|
5074
|
-
* The SVG transform origin defaults are different to CSS and is less intuitive,
|
|
5075
|
-
* so we use the measured dimensions of the SVG to reconcile these.
|
|
5076
|
-
*/
|
|
5077
|
-
function calcSVGTransformOrigin(dimensions, originX, originY) {
|
|
5078
|
-
const pxOriginX = calcOrigin$1(originX, dimensions.x, dimensions.width);
|
|
5079
|
-
const pxOriginY = calcOrigin$1(originY, dimensions.y, dimensions.height);
|
|
5080
|
-
return `${pxOriginX} ${pxOriginY}`;
|
|
5081
|
-
}
|
|
5082
|
-
|
|
5083
5068
|
/**
|
|
5084
5069
|
* Build SVG visual attrbutes, like cx and style.transform
|
|
5085
5070
|
*/
|
|
5086
|
-
function buildSVGAttrs(state, { attrX, attrY, attrScale,
|
|
5071
|
+
function buildSVGAttrs(state, { attrX, attrY, attrScale, pathLength, pathSpacing = 1, pathOffset = 0,
|
|
5087
5072
|
// This is object creation, which we try to avoid per-frame.
|
|
5088
5073
|
...latest }, isSVGTag, transformTemplate) {
|
|
5089
5074
|
buildHTMLStyles(state, latest, transformTemplate);
|
|
@@ -5099,20 +5084,26 @@ function buildSVGAttrs(state, { attrX, attrY, attrScale, originX, originY, pathL
|
|
|
5099
5084
|
}
|
|
5100
5085
|
state.attrs = state.style;
|
|
5101
5086
|
state.style = {};
|
|
5102
|
-
const { attrs, style
|
|
5087
|
+
const { attrs, style } = state;
|
|
5103
5088
|
/**
|
|
5104
|
-
* However, we apply transforms as CSS transforms.
|
|
5105
|
-
* and copy it into style.
|
|
5089
|
+
* However, we apply transforms as CSS transforms.
|
|
5090
|
+
* So if we detect a transform, transformOrigin we take it from attrs and copy it into style.
|
|
5106
5091
|
*/
|
|
5107
5092
|
if (attrs.transform) {
|
|
5108
|
-
|
|
5109
|
-
style.transform = attrs.transform;
|
|
5093
|
+
style.transform = attrs.transform;
|
|
5110
5094
|
delete attrs.transform;
|
|
5111
5095
|
}
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5096
|
+
if (style.transform || attrs.transformOrigin) {
|
|
5097
|
+
style.transformOrigin = attrs.transformOrigin ?? "50% 50%";
|
|
5098
|
+
delete attrs.transformOrigin;
|
|
5099
|
+
}
|
|
5100
|
+
if (style.transform) {
|
|
5101
|
+
/**
|
|
5102
|
+
* SVG's element transform-origin uses its own median as a reference.
|
|
5103
|
+
* Therefore, transformBox becomes a fill-box
|
|
5104
|
+
*/
|
|
5105
|
+
style.transformBox = "fill-box";
|
|
5106
|
+
delete attrs.transformBox;
|
|
5116
5107
|
}
|
|
5117
5108
|
// Render attrX/attrY/attrScale as attributes
|
|
5118
5109
|
if (attrX !== undefined)
|
|
@@ -5211,44 +5202,20 @@ function resolveVariantFromProps(props, definition, custom, visualElement) {
|
|
|
5211
5202
|
return definition;
|
|
5212
5203
|
}
|
|
5213
5204
|
|
|
5214
|
-
const isKeyframesTarget = (v) => {
|
|
5215
|
-
return Array.isArray(v);
|
|
5216
|
-
};
|
|
5217
|
-
|
|
5218
|
-
const isCustomValue = (v) => {
|
|
5219
|
-
return Boolean(v && typeof v === "object" && v.mix && v.toValue);
|
|
5220
|
-
};
|
|
5221
|
-
const resolveFinalValueInKeyframes = (v) => {
|
|
5222
|
-
// TODO maybe throw if v.length - 1 is placeholder token?
|
|
5223
|
-
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
5224
|
-
};
|
|
5225
|
-
|
|
5226
5205
|
/**
|
|
5227
5206
|
* If the provided value is a MotionValue, this returns the actual value, otherwise just the value itself
|
|
5228
5207
|
*
|
|
5229
5208
|
* TODO: Remove and move to library
|
|
5230
5209
|
*/
|
|
5231
5210
|
function resolveMotionValue(value) {
|
|
5232
|
-
|
|
5233
|
-
return isCustomValue(unwrappedValue)
|
|
5234
|
-
? unwrappedValue.toValue()
|
|
5235
|
-
: unwrappedValue;
|
|
5211
|
+
return isMotionValue(value) ? value.get() : value;
|
|
5236
5212
|
}
|
|
5237
5213
|
|
|
5238
|
-
function makeState({ scrapeMotionValuesFromProps, createRenderState,
|
|
5214
|
+
function makeState({ scrapeMotionValuesFromProps, createRenderState, }, props, context, presenceContext) {
|
|
5239
5215
|
const state = {
|
|
5240
5216
|
latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
|
|
5241
5217
|
renderState: createRenderState(),
|
|
5242
5218
|
};
|
|
5243
|
-
if (onUpdate) {
|
|
5244
|
-
/**
|
|
5245
|
-
* onMount works without the VisualElement because it could be
|
|
5246
|
-
* called before the VisualElement payload has been hydrated.
|
|
5247
|
-
* (e.g. if someone is using m components <m.circle />)
|
|
5248
|
-
*/
|
|
5249
|
-
state.onMount = (instance) => onUpdate({ props, current: instance, ...state });
|
|
5250
|
-
state.onUpdate = (visualElement) => onUpdate(visualElement);
|
|
5251
|
-
}
|
|
5252
5219
|
return state;
|
|
5253
5220
|
}
|
|
5254
5221
|
const makeUseVisualState = (config) => (props, isStatic) => {
|
|
@@ -5335,68 +5302,6 @@ const htmlMotionConfig = {
|
|
|
5335
5302
|
}),
|
|
5336
5303
|
};
|
|
5337
5304
|
|
|
5338
|
-
function updateSVGDimensions(instance, renderState) {
|
|
5339
|
-
try {
|
|
5340
|
-
renderState.dimensions =
|
|
5341
|
-
typeof instance.getBBox === "function"
|
|
5342
|
-
? instance.getBBox()
|
|
5343
|
-
: instance.getBoundingClientRect();
|
|
5344
|
-
}
|
|
5345
|
-
catch (e) {
|
|
5346
|
-
// Most likely trying to measure an unrendered element under Firefox
|
|
5347
|
-
renderState.dimensions = {
|
|
5348
|
-
x: 0,
|
|
5349
|
-
y: 0,
|
|
5350
|
-
width: 0,
|
|
5351
|
-
height: 0,
|
|
5352
|
-
};
|
|
5353
|
-
}
|
|
5354
|
-
}
|
|
5355
|
-
|
|
5356
|
-
function renderHTML(element, { style, vars }, styleProp, projection) {
|
|
5357
|
-
Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
|
|
5358
|
-
// Loop over any CSS variables and assign those.
|
|
5359
|
-
for (const key in vars) {
|
|
5360
|
-
element.style.setProperty(key, vars[key]);
|
|
5361
|
-
}
|
|
5362
|
-
}
|
|
5363
|
-
|
|
5364
|
-
/**
|
|
5365
|
-
* A set of attribute names that are always read/written as camel case.
|
|
5366
|
-
*/
|
|
5367
|
-
const camelCaseAttributes = new Set([
|
|
5368
|
-
"baseFrequency",
|
|
5369
|
-
"diffuseConstant",
|
|
5370
|
-
"kernelMatrix",
|
|
5371
|
-
"kernelUnitLength",
|
|
5372
|
-
"keySplines",
|
|
5373
|
-
"keyTimes",
|
|
5374
|
-
"limitingConeAngle",
|
|
5375
|
-
"markerHeight",
|
|
5376
|
-
"markerWidth",
|
|
5377
|
-
"numOctaves",
|
|
5378
|
-
"targetX",
|
|
5379
|
-
"targetY",
|
|
5380
|
-
"surfaceScale",
|
|
5381
|
-
"specularConstant",
|
|
5382
|
-
"specularExponent",
|
|
5383
|
-
"stdDeviation",
|
|
5384
|
-
"tableValues",
|
|
5385
|
-
"viewBox",
|
|
5386
|
-
"gradientTransform",
|
|
5387
|
-
"pathLength",
|
|
5388
|
-
"startOffset",
|
|
5389
|
-
"textLength",
|
|
5390
|
-
"lengthAdjust",
|
|
5391
|
-
]);
|
|
5392
|
-
|
|
5393
|
-
function renderSVG(element, renderState, _styleProp, projection) {
|
|
5394
|
-
renderHTML(element, renderState, undefined, projection);
|
|
5395
|
-
for (const key in renderState.attrs) {
|
|
5396
|
-
element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
|
|
5397
|
-
}
|
|
5398
|
-
}
|
|
5399
|
-
|
|
5400
5305
|
function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
|
|
5401
5306
|
const newValues = scrapeMotionValuesFromProps$1(props, prevProps, visualElement);
|
|
5402
5307
|
for (const key in props) {
|
|
@@ -5411,49 +5316,10 @@ function scrapeMotionValuesFromProps(props, prevProps, visualElement) {
|
|
|
5411
5316
|
return newValues;
|
|
5412
5317
|
}
|
|
5413
5318
|
|
|
5414
|
-
const layoutProps = ["x", "y", "width", "height", "cx", "cy", "r"];
|
|
5415
5319
|
const svgMotionConfig = {
|
|
5416
5320
|
useVisualState: makeUseVisualState({
|
|
5417
5321
|
scrapeMotionValuesFromProps: scrapeMotionValuesFromProps,
|
|
5418
5322
|
createRenderState: createSvgRenderState,
|
|
5419
|
-
onUpdate: ({ props, prevProps, current, renderState, latestValues, }) => {
|
|
5420
|
-
if (!current)
|
|
5421
|
-
return;
|
|
5422
|
-
let hasTransform = !!props.drag;
|
|
5423
|
-
if (!hasTransform) {
|
|
5424
|
-
for (const key in latestValues) {
|
|
5425
|
-
if (transformProps.has(key)) {
|
|
5426
|
-
hasTransform = true;
|
|
5427
|
-
break;
|
|
5428
|
-
}
|
|
5429
|
-
}
|
|
5430
|
-
}
|
|
5431
|
-
if (!hasTransform)
|
|
5432
|
-
return;
|
|
5433
|
-
let needsMeasure = !prevProps;
|
|
5434
|
-
if (prevProps) {
|
|
5435
|
-
/**
|
|
5436
|
-
* Check the layout props for changes, if any are found we need to
|
|
5437
|
-
* measure the element again.
|
|
5438
|
-
*/
|
|
5439
|
-
for (let i = 0; i < layoutProps.length; i++) {
|
|
5440
|
-
const key = layoutProps[i];
|
|
5441
|
-
if (props[key] !==
|
|
5442
|
-
prevProps[key]) {
|
|
5443
|
-
needsMeasure = true;
|
|
5444
|
-
}
|
|
5445
|
-
}
|
|
5446
|
-
}
|
|
5447
|
-
if (!needsMeasure)
|
|
5448
|
-
return;
|
|
5449
|
-
frame.read(() => {
|
|
5450
|
-
updateSVGDimensions(current, renderState);
|
|
5451
|
-
frame.render(() => {
|
|
5452
|
-
buildSVGAttrs(renderState, latestValues, isSVGTag(current.tagName), props.transformTemplate);
|
|
5453
|
-
renderSVG(current, renderState);
|
|
5454
|
-
});
|
|
5455
|
-
});
|
|
5456
|
-
},
|
|
5457
5323
|
}),
|
|
5458
5324
|
};
|
|
5459
5325
|
|
|
@@ -5478,15 +5344,9 @@ function resolveVariant(visualElement, definition, custom) {
|
|
|
5478
5344
|
return resolveVariantFromProps(props, definition, custom !== undefined ? custom : props.custom, visualElement);
|
|
5479
5345
|
}
|
|
5480
5346
|
|
|
5481
|
-
const
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
"top",
|
|
5485
|
-
"left",
|
|
5486
|
-
"right",
|
|
5487
|
-
"bottom",
|
|
5488
|
-
...transformPropOrder,
|
|
5489
|
-
]);
|
|
5347
|
+
const isKeyframesTarget = (v) => {
|
|
5348
|
+
return Array.isArray(v);
|
|
5349
|
+
};
|
|
5490
5350
|
|
|
5491
5351
|
let now;
|
|
5492
5352
|
function clearTime() {
|
|
@@ -5597,7 +5457,7 @@ class MotionValue {
|
|
|
5597
5457
|
* This will be replaced by the build step with the latest version number.
|
|
5598
5458
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
5599
5459
|
*/
|
|
5600
|
-
this.version = "12.
|
|
5460
|
+
this.version = "12.9.0";
|
|
5601
5461
|
/**
|
|
5602
5462
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
5603
5463
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -5623,12 +5483,12 @@ class MotionValue {
|
|
|
5623
5483
|
this.prev = this.current;
|
|
5624
5484
|
this.setCurrent(v);
|
|
5625
5485
|
// Update update subscribers
|
|
5626
|
-
if (this.current !== this.prev
|
|
5627
|
-
this.events.change
|
|
5486
|
+
if (this.current !== this.prev) {
|
|
5487
|
+
this.events.change?.notify(this.current);
|
|
5628
5488
|
}
|
|
5629
5489
|
// Update render subscribers
|
|
5630
|
-
if (render
|
|
5631
|
-
this.events.renderRequest
|
|
5490
|
+
if (render) {
|
|
5491
|
+
this.events.renderRequest?.notify(this.current);
|
|
5632
5492
|
}
|
|
5633
5493
|
};
|
|
5634
5494
|
this.hasAnimated = false;
|
|
@@ -5861,6 +5721,7 @@ class MotionValue {
|
|
|
5861
5721
|
* @public
|
|
5862
5722
|
*/
|
|
5863
5723
|
destroy() {
|
|
5724
|
+
this.events.destroy?.notify();
|
|
5864
5725
|
this.clearListeners();
|
|
5865
5726
|
this.stop();
|
|
5866
5727
|
if (this.stopPassiveEffect) {
|
|
@@ -5884,6 +5745,10 @@ function setMotionValue(visualElement, key, value) {
|
|
|
5884
5745
|
visualElement.addValue(key, motionValue(value));
|
|
5885
5746
|
}
|
|
5886
5747
|
}
|
|
5748
|
+
function resolveFinalValueInKeyframes(v) {
|
|
5749
|
+
// TODO maybe throw if v.length - 1 is placeholder token?
|
|
5750
|
+
return isKeyframesTarget(v) ? v[v.length - 1] || 0 : v;
|
|
5751
|
+
}
|
|
5887
5752
|
function setTarget(visualElement, definition) {
|
|
5888
5753
|
const resolved = resolveVariant(visualElement, definition);
|
|
5889
5754
|
let { transitionEnd = {}, transition = {}, ...target } = resolved || {};
|
|
@@ -5918,89 +5783,79 @@ function getOptimisedAppearId(visualElement) {
|
|
|
5918
5783
|
return visualElement.props[optimizedAppearDataAttribute];
|
|
5919
5784
|
}
|
|
5920
5785
|
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
usually improved times, depending on the curve.
|
|
5930
|
-
I also removed the lookup table, as for the added bundle size and loop we're
|
|
5931
|
-
only cutting ~4 or so subdivision iterations. I bumped the max iterations up
|
|
5932
|
-
to 12 to compensate and this still tended to be faster for no perceivable
|
|
5933
|
-
loss in accuracy.
|
|
5934
|
-
Usage
|
|
5935
|
-
const easeOut = cubicBezier(.17,.67,.83,.67);
|
|
5936
|
-
const x = easeOut(0.5); // returns 0.627...
|
|
5937
|
-
*/
|
|
5938
|
-
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
5939
|
-
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
5940
|
-
t;
|
|
5941
|
-
const subdivisionPrecision = 0.0000001;
|
|
5942
|
-
const subdivisionMaxIterations = 12;
|
|
5943
|
-
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
5944
|
-
let currentX;
|
|
5945
|
-
let currentT;
|
|
5946
|
-
let i = 0;
|
|
5947
|
-
do {
|
|
5948
|
-
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
5949
|
-
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
5950
|
-
if (currentX > 0.0) {
|
|
5951
|
-
upperBound = currentT;
|
|
5952
|
-
}
|
|
5953
|
-
else {
|
|
5954
|
-
lowerBound = currentT;
|
|
5955
|
-
}
|
|
5956
|
-
} while (Math.abs(currentX) > subdivisionPrecision &&
|
|
5957
|
-
++i < subdivisionMaxIterations);
|
|
5958
|
-
return currentT;
|
|
5959
|
-
}
|
|
5960
|
-
function cubicBezier(mX1, mY1, mX2, mY2) {
|
|
5961
|
-
// If this is a linear gradient, return linear easing
|
|
5962
|
-
if (mX1 === mY1 && mX2 === mY2)
|
|
5963
|
-
return noop;
|
|
5964
|
-
const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
|
|
5965
|
-
// If animation is at start/end, return t without easing
|
|
5966
|
-
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
|
|
5786
|
+
const isNotNull$1 = (value) => value !== null;
|
|
5787
|
+
function getFinalKeyframe$1(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
|
|
5788
|
+
const resolvedKeyframes = keyframes.filter(isNotNull$1);
|
|
5789
|
+
const index = repeat && repeatType !== "loop" && repeat % 2 === 1
|
|
5790
|
+
? 0
|
|
5791
|
+
: resolvedKeyframes.length - 1;
|
|
5792
|
+
return resolvedKeyframes[index]
|
|
5793
|
+
;
|
|
5967
5794
|
}
|
|
5968
5795
|
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
const
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
const
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
const circInOut = mirrorEasing(circIn);
|
|
5986
|
-
|
|
5796
|
+
const underDampedSpring = {
|
|
5797
|
+
type: "spring",
|
|
5798
|
+
stiffness: 500,
|
|
5799
|
+
damping: 25,
|
|
5800
|
+
restSpeed: 10,
|
|
5801
|
+
};
|
|
5802
|
+
const criticallyDampedSpring = (target) => ({
|
|
5803
|
+
type: "spring",
|
|
5804
|
+
stiffness: 550,
|
|
5805
|
+
damping: target === 0 ? 2 * Math.sqrt(550) : 30,
|
|
5806
|
+
restSpeed: 10,
|
|
5807
|
+
});
|
|
5808
|
+
const keyframesTransition = {
|
|
5809
|
+
type: "keyframes",
|
|
5810
|
+
duration: 0.8,
|
|
5811
|
+
};
|
|
5987
5812
|
/**
|
|
5988
|
-
*
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5813
|
+
* Default easing curve is a slightly shallower version of
|
|
5814
|
+
* the default browser easing curve.
|
|
5815
|
+
*/
|
|
5816
|
+
const ease = {
|
|
5817
|
+
type: "keyframes",
|
|
5818
|
+
ease: [0.25, 0.1, 0.35, 1],
|
|
5819
|
+
duration: 0.3,
|
|
5820
|
+
};
|
|
5821
|
+
const getDefaultTransition = (valueKey, { keyframes }) => {
|
|
5822
|
+
if (keyframes.length > 2) {
|
|
5823
|
+
return keyframesTransition;
|
|
5998
5824
|
}
|
|
5999
|
-
else {
|
|
6000
|
-
return
|
|
5825
|
+
else if (transformProps.has(valueKey)) {
|
|
5826
|
+
return valueKey.startsWith("scale")
|
|
5827
|
+
? criticallyDampedSpring(keyframes[1])
|
|
5828
|
+
: underDampedSpring;
|
|
6001
5829
|
}
|
|
5830
|
+
return ease;
|
|
5831
|
+
};
|
|
5832
|
+
|
|
5833
|
+
/**
|
|
5834
|
+
* Decide whether a transition is defined on a given Transition.
|
|
5835
|
+
* This filters out orchestration options and returns true
|
|
5836
|
+
* if any options are left.
|
|
5837
|
+
*/
|
|
5838
|
+
function isTransitionDefined({ when, delay: _delay, delayChildren, staggerChildren, staggerDirection, repeat, repeatType, repeatDelay, from, elapsed, ...transition }) {
|
|
5839
|
+
return !!Object.keys(transition).length;
|
|
5840
|
+
}
|
|
5841
|
+
|
|
5842
|
+
function getValueTransition(transition, key) {
|
|
5843
|
+
return (transition?.[key] ??
|
|
5844
|
+
transition?.["default"] ??
|
|
5845
|
+
transition);
|
|
6002
5846
|
}
|
|
6003
5847
|
|
|
5848
|
+
/**
|
|
5849
|
+
* Converts seconds to milliseconds
|
|
5850
|
+
*
|
|
5851
|
+
* @param seconds - Time in seconds.
|
|
5852
|
+
* @return milliseconds - Converted time in milliseconds.
|
|
5853
|
+
*/
|
|
5854
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
5855
|
+
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
5856
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
5857
|
+
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
5858
|
+
|
|
6004
5859
|
// If this number is a decimal, make it just five decimal places
|
|
6005
5860
|
// to avoid exponents
|
|
6006
5861
|
const sanitize = (v) => Math.round(v * 100000) / 100000;
|
|
@@ -6217,848 +6072,129 @@ const complex = {
|
|
|
6217
6072
|
getAnimatableNone: getAnimatableNone$1,
|
|
6218
6073
|
};
|
|
6219
6074
|
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
if (
|
|
6227
|
-
return
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6075
|
+
// Adapted from https://gist.github.com/mjackson/5311256
|
|
6076
|
+
function hueToRgb(p, q, t) {
|
|
6077
|
+
if (t < 0)
|
|
6078
|
+
t += 1;
|
|
6079
|
+
if (t > 1)
|
|
6080
|
+
t -= 1;
|
|
6081
|
+
if (t < 1 / 6)
|
|
6082
|
+
return p + (q - p) * 6 * t;
|
|
6083
|
+
if (t < 1 / 2)
|
|
6084
|
+
return q;
|
|
6085
|
+
if (t < 2 / 3)
|
|
6086
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
6087
|
+
return p;
|
|
6088
|
+
}
|
|
6089
|
+
function hslaToRgba({ hue, saturation, lightness, alpha }) {
|
|
6090
|
+
hue /= 360;
|
|
6091
|
+
saturation /= 100;
|
|
6092
|
+
lightness /= 100;
|
|
6093
|
+
let red = 0;
|
|
6094
|
+
let green = 0;
|
|
6095
|
+
let blue = 0;
|
|
6096
|
+
if (!saturation) {
|
|
6097
|
+
red = green = blue = lightness;
|
|
6098
|
+
}
|
|
6099
|
+
else {
|
|
6100
|
+
const q = lightness < 0.5
|
|
6101
|
+
? lightness * (1 + saturation)
|
|
6102
|
+
: lightness + saturation - lightness * saturation;
|
|
6103
|
+
const p = 2 * lightness - q;
|
|
6104
|
+
red = hueToRgb(p, q, hue + 1 / 3);
|
|
6105
|
+
green = hueToRgb(p, q, hue);
|
|
6106
|
+
blue = hueToRgb(p, q, hue - 1 / 3);
|
|
6107
|
+
}
|
|
6108
|
+
return {
|
|
6109
|
+
red: Math.round(red * 255),
|
|
6110
|
+
green: Math.round(green * 255),
|
|
6111
|
+
blue: Math.round(blue * 255),
|
|
6112
|
+
alpha,
|
|
6113
|
+
};
|
|
6236
6114
|
}
|
|
6237
|
-
const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
|
|
6238
|
-
const filter = {
|
|
6239
|
-
...complex,
|
|
6240
|
-
getAnimatableNone: (v) => {
|
|
6241
|
-
const functions = v.match(functionRegex);
|
|
6242
|
-
return functions ? functions.map(applyDefaultFilter).join(" ") : v;
|
|
6243
|
-
},
|
|
6244
|
-
};
|
|
6245
6115
|
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6116
|
+
function mixImmediate(a, b) {
|
|
6117
|
+
return (p) => (p > 0 ? b : a);
|
|
6118
|
+
}
|
|
6119
|
+
|
|
6120
|
+
/*
|
|
6121
|
+
Value in range from progress
|
|
6122
|
+
|
|
6123
|
+
Given a lower limit and an upper limit, we return the value within
|
|
6124
|
+
that range as expressed by progress (usually a number from 0 to 1)
|
|
6125
|
+
|
|
6126
|
+
So progress = 0.5 would change
|
|
6127
|
+
|
|
6128
|
+
from -------- to
|
|
6129
|
+
|
|
6130
|
+
to
|
|
6131
|
+
|
|
6132
|
+
from ---- to
|
|
6133
|
+
|
|
6134
|
+
E.g. from = 10, to = 20, progress = 0.5 => 15
|
|
6135
|
+
|
|
6136
|
+
@param [number]: Lower limit of range
|
|
6137
|
+
@param [number]: Upper limit of range
|
|
6138
|
+
@param [number]: The progress between lower and upper limits expressed 0-1
|
|
6139
|
+
@return [number]: Value as calculated from progress within range (not limited within range)
|
|
6140
|
+
*/
|
|
6141
|
+
const mixNumber$1 = (from, to, progress) => {
|
|
6142
|
+
return from + (to - from) * progress;
|
|
6265
6143
|
};
|
|
6266
|
-
/**
|
|
6267
|
-
* Gets the default ValueType for the provided value key
|
|
6268
|
-
*/
|
|
6269
|
-
const getDefaultValueType = (key) => defaultValueTypes[key];
|
|
6270
6144
|
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6145
|
+
// Linear color space blending
|
|
6146
|
+
// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw
|
|
6147
|
+
// Demonstrated http://codepen.io/osublake/pen/xGVVaN
|
|
6148
|
+
const mixLinearColor = (from, to, v) => {
|
|
6149
|
+
const fromExpo = from * from;
|
|
6150
|
+
const expo = v * (to * to - fromExpo) + fromExpo;
|
|
6151
|
+
return expo < 0 ? 0 : Math.sqrt(expo);
|
|
6152
|
+
};
|
|
6153
|
+
const colorTypes = [hex, rgba, hsla];
|
|
6154
|
+
const getColorType = (v) => colorTypes.find((type) => type.test(v));
|
|
6155
|
+
function asRGBA(color) {
|
|
6156
|
+
const type = getColorType(color);
|
|
6157
|
+
warning(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);
|
|
6158
|
+
if (!Boolean(type))
|
|
6159
|
+
return false;
|
|
6160
|
+
let model = type.parse(color);
|
|
6161
|
+
if (type === hsla) {
|
|
6162
|
+
// TODO Remove this cast - needed since Motion's stricter typing
|
|
6163
|
+
model = hslaToRgba(model);
|
|
6164
|
+
}
|
|
6165
|
+
return model;
|
|
6279
6166
|
}
|
|
6167
|
+
const mixColor = (from, to) => {
|
|
6168
|
+
const fromRGBA = asRGBA(from);
|
|
6169
|
+
const toRGBA = asRGBA(to);
|
|
6170
|
+
if (!fromRGBA || !toRGBA) {
|
|
6171
|
+
return mixImmediate(from, to);
|
|
6172
|
+
}
|
|
6173
|
+
const blended = { ...fromRGBA };
|
|
6174
|
+
return (v) => {
|
|
6175
|
+
blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);
|
|
6176
|
+
blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);
|
|
6177
|
+
blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);
|
|
6178
|
+
blended.alpha = mixNumber$1(fromRGBA.alpha, toRGBA.alpha, v);
|
|
6179
|
+
return rgba.transform(blended);
|
|
6180
|
+
};
|
|
6181
|
+
};
|
|
6280
6182
|
|
|
6183
|
+
const invisibleValues = new Set(["none", "hidden"]);
|
|
6281
6184
|
/**
|
|
6282
|
-
*
|
|
6283
|
-
* "
|
|
6284
|
-
* the
|
|
6285
|
-
* zero equivalents, i.e. "#fff0" or "0px 0px".
|
|
6185
|
+
* Returns a function that, when provided a progress value between 0 and 1,
|
|
6186
|
+
* will return the "none" or "hidden" string only when the progress is that of
|
|
6187
|
+
* the origin or target.
|
|
6286
6188
|
*/
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
let animatableTemplate = undefined;
|
|
6291
|
-
while (i < unresolvedKeyframes.length && !animatableTemplate) {
|
|
6292
|
-
const keyframe = unresolvedKeyframes[i];
|
|
6293
|
-
if (typeof keyframe === "string" &&
|
|
6294
|
-
!invalidTemplates.has(keyframe) &&
|
|
6295
|
-
analyseComplexValue(keyframe).values.length) {
|
|
6296
|
-
animatableTemplate = unresolvedKeyframes[i];
|
|
6297
|
-
}
|
|
6298
|
-
i++;
|
|
6189
|
+
function mixVisibility(origin, target) {
|
|
6190
|
+
if (invisibleValues.has(origin)) {
|
|
6191
|
+
return (p) => (p <= 0 ? origin : target);
|
|
6299
6192
|
}
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
|
|
6303
|
-
}
|
|
6193
|
+
else {
|
|
6194
|
+
return (p) => (p >= 1 ? target : origin);
|
|
6304
6195
|
}
|
|
6305
6196
|
}
|
|
6306
6197
|
|
|
6307
|
-
const radToDeg = (rad) => (rad * 180) / Math.PI;
|
|
6308
|
-
const rotate = (v) => {
|
|
6309
|
-
const angle = radToDeg(Math.atan2(v[1], v[0]));
|
|
6310
|
-
return rebaseAngle(angle);
|
|
6311
|
-
};
|
|
6312
|
-
const matrix2dParsers = {
|
|
6313
|
-
x: 4,
|
|
6314
|
-
y: 5,
|
|
6315
|
-
translateX: 4,
|
|
6316
|
-
translateY: 5,
|
|
6317
|
-
scaleX: 0,
|
|
6318
|
-
scaleY: 3,
|
|
6319
|
-
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
|
|
6320
|
-
rotate,
|
|
6321
|
-
rotateZ: rotate,
|
|
6322
|
-
skewX: (v) => radToDeg(Math.atan(v[1])),
|
|
6323
|
-
skewY: (v) => radToDeg(Math.atan(v[2])),
|
|
6324
|
-
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
|
|
6325
|
-
};
|
|
6326
|
-
const rebaseAngle = (angle) => {
|
|
6327
|
-
angle = angle % 360;
|
|
6328
|
-
if (angle < 0)
|
|
6329
|
-
angle += 360;
|
|
6330
|
-
return angle;
|
|
6331
|
-
};
|
|
6332
|
-
const rotateZ = rotate;
|
|
6333
|
-
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
6334
|
-
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
|
|
6335
|
-
const matrix3dParsers = {
|
|
6336
|
-
x: 12,
|
|
6337
|
-
y: 13,
|
|
6338
|
-
z: 14,
|
|
6339
|
-
translateX: 12,
|
|
6340
|
-
translateY: 13,
|
|
6341
|
-
translateZ: 14,
|
|
6342
|
-
scaleX,
|
|
6343
|
-
scaleY,
|
|
6344
|
-
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
|
|
6345
|
-
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
|
|
6346
|
-
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
|
|
6347
|
-
rotateZ,
|
|
6348
|
-
rotate: rotateZ,
|
|
6349
|
-
skewX: (v) => radToDeg(Math.atan(v[4])),
|
|
6350
|
-
skewY: (v) => radToDeg(Math.atan(v[1])),
|
|
6351
|
-
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
|
|
6352
|
-
};
|
|
6353
|
-
function defaultTransformValue(name) {
|
|
6354
|
-
return name.includes("scale") ? 1 : 0;
|
|
6355
|
-
}
|
|
6356
|
-
function parseValueFromTransform(transform, name) {
|
|
6357
|
-
if (!transform || transform === "none") {
|
|
6358
|
-
return defaultTransformValue(name);
|
|
6359
|
-
}
|
|
6360
|
-
const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
|
|
6361
|
-
let parsers;
|
|
6362
|
-
let match;
|
|
6363
|
-
if (matrix3dMatch) {
|
|
6364
|
-
parsers = matrix3dParsers;
|
|
6365
|
-
match = matrix3dMatch;
|
|
6366
|
-
}
|
|
6367
|
-
else {
|
|
6368
|
-
const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
|
|
6369
|
-
parsers = matrix2dParsers;
|
|
6370
|
-
match = matrix2dMatch;
|
|
6371
|
-
}
|
|
6372
|
-
if (!match) {
|
|
6373
|
-
return defaultTransformValue(name);
|
|
6374
|
-
}
|
|
6375
|
-
const valueParser = parsers[name];
|
|
6376
|
-
const values = match[1].split(",").map(convertTransformToNumber);
|
|
6377
|
-
return typeof valueParser === "function"
|
|
6378
|
-
? valueParser(values)
|
|
6379
|
-
: values[valueParser];
|
|
6380
|
-
}
|
|
6381
|
-
const readTransformValue = (instance, name) => {
|
|
6382
|
-
const { transform = "none" } = getComputedStyle(instance);
|
|
6383
|
-
return parseValueFromTransform(transform, name);
|
|
6384
|
-
};
|
|
6385
|
-
function convertTransformToNumber(value) {
|
|
6386
|
-
return parseFloat(value.trim());
|
|
6387
|
-
}
|
|
6388
|
-
|
|
6389
|
-
const isNumOrPxType = (v) => v === number || v === px;
|
|
6390
|
-
const transformKeys = new Set(["x", "y", "z"]);
|
|
6391
|
-
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
|
6392
|
-
function removeNonTranslationalTransform(visualElement) {
|
|
6393
|
-
const removedTransforms = [];
|
|
6394
|
-
nonTranslationalTransformKeys.forEach((key) => {
|
|
6395
|
-
const value = visualElement.getValue(key);
|
|
6396
|
-
if (value !== undefined) {
|
|
6397
|
-
removedTransforms.push([key, value.get()]);
|
|
6398
|
-
value.set(key.startsWith("scale") ? 1 : 0);
|
|
6399
|
-
}
|
|
6400
|
-
});
|
|
6401
|
-
return removedTransforms;
|
|
6402
|
-
}
|
|
6403
|
-
const positionalValues = {
|
|
6404
|
-
// Dimensions
|
|
6405
|
-
width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
|
|
6406
|
-
height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
|
|
6407
|
-
top: (_bbox, { top }) => parseFloat(top),
|
|
6408
|
-
left: (_bbox, { left }) => parseFloat(left),
|
|
6409
|
-
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
|
6410
|
-
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
|
6411
|
-
// Transform
|
|
6412
|
-
x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
|
|
6413
|
-
y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
|
|
6414
|
-
};
|
|
6415
|
-
// Alias translate longform names
|
|
6416
|
-
positionalValues.translateX = positionalValues.x;
|
|
6417
|
-
positionalValues.translateY = positionalValues.y;
|
|
6418
|
-
|
|
6419
|
-
const toResolve = new Set();
|
|
6420
|
-
let isScheduled = false;
|
|
6421
|
-
let anyNeedsMeasurement = false;
|
|
6422
|
-
function measureAllKeyframes() {
|
|
6423
|
-
if (anyNeedsMeasurement) {
|
|
6424
|
-
const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);
|
|
6425
|
-
const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));
|
|
6426
|
-
const transformsToRestore = new Map();
|
|
6427
|
-
/**
|
|
6428
|
-
* Write pass
|
|
6429
|
-
* If we're measuring elements we want to remove bounding box-changing transforms.
|
|
6430
|
-
*/
|
|
6431
|
-
elementsToMeasure.forEach((element) => {
|
|
6432
|
-
const removedTransforms = removeNonTranslationalTransform(element);
|
|
6433
|
-
if (!removedTransforms.length)
|
|
6434
|
-
return;
|
|
6435
|
-
transformsToRestore.set(element, removedTransforms);
|
|
6436
|
-
element.render();
|
|
6437
|
-
});
|
|
6438
|
-
// Read
|
|
6439
|
-
resolversToMeasure.forEach((resolver) => resolver.measureInitialState());
|
|
6440
|
-
// Write
|
|
6441
|
-
elementsToMeasure.forEach((element) => {
|
|
6442
|
-
element.render();
|
|
6443
|
-
const restore = transformsToRestore.get(element);
|
|
6444
|
-
if (restore) {
|
|
6445
|
-
restore.forEach(([key, value]) => {
|
|
6446
|
-
element.getValue(key)?.set(value);
|
|
6447
|
-
});
|
|
6448
|
-
}
|
|
6449
|
-
});
|
|
6450
|
-
// Read
|
|
6451
|
-
resolversToMeasure.forEach((resolver) => resolver.measureEndState());
|
|
6452
|
-
// Write
|
|
6453
|
-
resolversToMeasure.forEach((resolver) => {
|
|
6454
|
-
if (resolver.suspendedScrollY !== undefined) {
|
|
6455
|
-
window.scrollTo(0, resolver.suspendedScrollY);
|
|
6456
|
-
}
|
|
6457
|
-
});
|
|
6458
|
-
}
|
|
6459
|
-
anyNeedsMeasurement = false;
|
|
6460
|
-
isScheduled = false;
|
|
6461
|
-
toResolve.forEach((resolver) => resolver.complete());
|
|
6462
|
-
toResolve.clear();
|
|
6463
|
-
}
|
|
6464
|
-
function readAllKeyframes() {
|
|
6465
|
-
toResolve.forEach((resolver) => {
|
|
6466
|
-
resolver.readKeyframes();
|
|
6467
|
-
if (resolver.needsMeasurement) {
|
|
6468
|
-
anyNeedsMeasurement = true;
|
|
6469
|
-
}
|
|
6470
|
-
});
|
|
6471
|
-
}
|
|
6472
|
-
function flushKeyframeResolvers() {
|
|
6473
|
-
readAllKeyframes();
|
|
6474
|
-
measureAllKeyframes();
|
|
6475
|
-
}
|
|
6476
|
-
class KeyframeResolver {
|
|
6477
|
-
constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {
|
|
6478
|
-
/**
|
|
6479
|
-
* Track whether this resolver has completed. Once complete, it never
|
|
6480
|
-
* needs to attempt keyframe resolution again.
|
|
6481
|
-
*/
|
|
6482
|
-
this.isComplete = false;
|
|
6483
|
-
/**
|
|
6484
|
-
* Track whether this resolver is async. If it is, it'll be added to the
|
|
6485
|
-
* resolver queue and flushed in the next frame. Resolvers that aren't going
|
|
6486
|
-
* to trigger read/write thrashing don't need to be async.
|
|
6487
|
-
*/
|
|
6488
|
-
this.isAsync = false;
|
|
6489
|
-
/**
|
|
6490
|
-
* Track whether this resolver needs to perform a measurement
|
|
6491
|
-
* to resolve its keyframes.
|
|
6492
|
-
*/
|
|
6493
|
-
this.needsMeasurement = false;
|
|
6494
|
-
/**
|
|
6495
|
-
* Track whether this resolver is currently scheduled to resolve
|
|
6496
|
-
* to allow it to be cancelled and resumed externally.
|
|
6497
|
-
*/
|
|
6498
|
-
this.isScheduled = false;
|
|
6499
|
-
this.unresolvedKeyframes = [...unresolvedKeyframes];
|
|
6500
|
-
this.onComplete = onComplete;
|
|
6501
|
-
this.name = name;
|
|
6502
|
-
this.motionValue = motionValue;
|
|
6503
|
-
this.element = element;
|
|
6504
|
-
this.isAsync = isAsync;
|
|
6505
|
-
}
|
|
6506
|
-
scheduleResolve() {
|
|
6507
|
-
this.isScheduled = true;
|
|
6508
|
-
if (this.isAsync) {
|
|
6509
|
-
toResolve.add(this);
|
|
6510
|
-
if (!isScheduled) {
|
|
6511
|
-
isScheduled = true;
|
|
6512
|
-
frame.read(readAllKeyframes);
|
|
6513
|
-
frame.resolveKeyframes(measureAllKeyframes);
|
|
6514
|
-
}
|
|
6515
|
-
}
|
|
6516
|
-
else {
|
|
6517
|
-
this.readKeyframes();
|
|
6518
|
-
this.complete();
|
|
6519
|
-
}
|
|
6520
|
-
}
|
|
6521
|
-
readKeyframes() {
|
|
6522
|
-
const { unresolvedKeyframes, name, element, motionValue } = this;
|
|
6523
|
-
/**
|
|
6524
|
-
* If a keyframe is null, we hydrate it either by reading it from
|
|
6525
|
-
* the instance, or propagating from previous keyframes.
|
|
6526
|
-
*/
|
|
6527
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6528
|
-
if (unresolvedKeyframes[i] === null) {
|
|
6529
|
-
/**
|
|
6530
|
-
* If the first keyframe is null, we need to find its value by sampling the element
|
|
6531
|
-
*/
|
|
6532
|
-
if (i === 0) {
|
|
6533
|
-
const currentValue = motionValue?.get();
|
|
6534
|
-
const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
6535
|
-
if (currentValue !== undefined) {
|
|
6536
|
-
unresolvedKeyframes[0] = currentValue;
|
|
6537
|
-
}
|
|
6538
|
-
else if (element && name) {
|
|
6539
|
-
const valueAsRead = element.readValue(name, finalKeyframe);
|
|
6540
|
-
if (valueAsRead !== undefined && valueAsRead !== null) {
|
|
6541
|
-
unresolvedKeyframes[0] = valueAsRead;
|
|
6542
|
-
}
|
|
6543
|
-
}
|
|
6544
|
-
if (unresolvedKeyframes[0] === undefined) {
|
|
6545
|
-
unresolvedKeyframes[0] = finalKeyframe;
|
|
6546
|
-
}
|
|
6547
|
-
if (motionValue && currentValue === undefined) {
|
|
6548
|
-
motionValue.set(unresolvedKeyframes[0]);
|
|
6549
|
-
}
|
|
6550
|
-
}
|
|
6551
|
-
else {
|
|
6552
|
-
unresolvedKeyframes[i] = unresolvedKeyframes[i - 1];
|
|
6553
|
-
}
|
|
6554
|
-
}
|
|
6555
|
-
}
|
|
6556
|
-
}
|
|
6557
|
-
setFinalKeyframe() { }
|
|
6558
|
-
measureInitialState() { }
|
|
6559
|
-
renderEndStyles() { }
|
|
6560
|
-
measureEndState() { }
|
|
6561
|
-
complete() {
|
|
6562
|
-
this.isComplete = true;
|
|
6563
|
-
this.onComplete(this.unresolvedKeyframes, this.finalKeyframe);
|
|
6564
|
-
toResolve.delete(this);
|
|
6565
|
-
}
|
|
6566
|
-
cancel() {
|
|
6567
|
-
if (!this.isComplete) {
|
|
6568
|
-
this.isScheduled = false;
|
|
6569
|
-
toResolve.delete(this);
|
|
6570
|
-
}
|
|
6571
|
-
}
|
|
6572
|
-
resume() {
|
|
6573
|
-
if (!this.isComplete)
|
|
6574
|
-
this.scheduleResolve();
|
|
6575
|
-
}
|
|
6576
|
-
}
|
|
6577
|
-
|
|
6578
|
-
/**
|
|
6579
|
-
* Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
|
|
6580
|
-
*/
|
|
6581
|
-
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
|
|
6582
|
-
|
|
6583
|
-
/**
|
|
6584
|
-
* Parse Framer's special CSS variable format into a CSS token and a fallback.
|
|
6585
|
-
*
|
|
6586
|
-
* ```
|
|
6587
|
-
* `var(--foo, #fff)` => [`--foo`, '#fff']
|
|
6588
|
-
* ```
|
|
6589
|
-
*
|
|
6590
|
-
* @param current
|
|
6591
|
-
*/
|
|
6592
|
-
const splitCSSVariableRegex =
|
|
6593
|
-
// eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
|
|
6594
|
-
/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
|
|
6595
|
-
function parseCSSVariable(current) {
|
|
6596
|
-
const match = splitCSSVariableRegex.exec(current);
|
|
6597
|
-
if (!match)
|
|
6598
|
-
return [,];
|
|
6599
|
-
const [, token1, token2, fallback] = match;
|
|
6600
|
-
return [`--${token1 ?? token2}`, fallback];
|
|
6601
|
-
}
|
|
6602
|
-
const maxDepth = 4;
|
|
6603
|
-
function getVariableValue(current, element, depth = 1) {
|
|
6604
|
-
invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
|
|
6605
|
-
const [token, fallback] = parseCSSVariable(current);
|
|
6606
|
-
// No CSS variable detected
|
|
6607
|
-
if (!token)
|
|
6608
|
-
return;
|
|
6609
|
-
// Attempt to read this CSS variable off the element
|
|
6610
|
-
const resolved = window.getComputedStyle(element).getPropertyValue(token);
|
|
6611
|
-
if (resolved) {
|
|
6612
|
-
const trimmed = resolved.trim();
|
|
6613
|
-
return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
|
|
6614
|
-
}
|
|
6615
|
-
return isCSSVariableToken(fallback)
|
|
6616
|
-
? getVariableValue(fallback, element, depth + 1)
|
|
6617
|
-
: fallback;
|
|
6618
|
-
}
|
|
6619
|
-
|
|
6620
|
-
/**
|
|
6621
|
-
* Tests a provided value against a ValueType
|
|
6622
|
-
*/
|
|
6623
|
-
const testValueType = (v) => (type) => type.test(v);
|
|
6624
|
-
|
|
6625
|
-
/**
|
|
6626
|
-
* ValueType for "auto"
|
|
6627
|
-
*/
|
|
6628
|
-
const auto = {
|
|
6629
|
-
test: (v) => v === "auto",
|
|
6630
|
-
parse: (v) => v,
|
|
6631
|
-
};
|
|
6632
|
-
|
|
6633
|
-
/**
|
|
6634
|
-
* A list of value types commonly used for dimensions
|
|
6635
|
-
*/
|
|
6636
|
-
const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
|
|
6637
|
-
/**
|
|
6638
|
-
* Tests a dimensional value against the list of dimension ValueTypes
|
|
6639
|
-
*/
|
|
6640
|
-
const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
|
|
6641
|
-
|
|
6642
|
-
class DOMKeyframesResolver extends KeyframeResolver {
|
|
6643
|
-
constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
|
|
6644
|
-
super(unresolvedKeyframes, onComplete, name, motionValue, element, true);
|
|
6645
|
-
}
|
|
6646
|
-
readKeyframes() {
|
|
6647
|
-
const { unresolvedKeyframes, element, name } = this;
|
|
6648
|
-
if (!element || !element.current)
|
|
6649
|
-
return;
|
|
6650
|
-
super.readKeyframes();
|
|
6651
|
-
/**
|
|
6652
|
-
* If any keyframe is a CSS variable, we need to find its value by sampling the element
|
|
6653
|
-
*/
|
|
6654
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6655
|
-
let keyframe = unresolvedKeyframes[i];
|
|
6656
|
-
if (typeof keyframe === "string") {
|
|
6657
|
-
keyframe = keyframe.trim();
|
|
6658
|
-
if (isCSSVariableToken(keyframe)) {
|
|
6659
|
-
const resolved = getVariableValue(keyframe, element.current);
|
|
6660
|
-
if (resolved !== undefined) {
|
|
6661
|
-
unresolvedKeyframes[i] = resolved;
|
|
6662
|
-
}
|
|
6663
|
-
if (i === unresolvedKeyframes.length - 1) {
|
|
6664
|
-
this.finalKeyframe = keyframe;
|
|
6665
|
-
}
|
|
6666
|
-
}
|
|
6667
|
-
}
|
|
6668
|
-
}
|
|
6669
|
-
/**
|
|
6670
|
-
* Resolve "none" values. We do this potentially twice - once before and once after measuring keyframes.
|
|
6671
|
-
* This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which
|
|
6672
|
-
* have a far bigger performance impact.
|
|
6673
|
-
*/
|
|
6674
|
-
this.resolveNoneKeyframes();
|
|
6675
|
-
/**
|
|
6676
|
-
* Check to see if unit type has changed. If so schedule jobs that will
|
|
6677
|
-
* temporarily set styles to the destination keyframes.
|
|
6678
|
-
* Skip if we have more than two keyframes or this isn't a positional value.
|
|
6679
|
-
* TODO: We can throw if there are multiple keyframes and the value type changes.
|
|
6680
|
-
*/
|
|
6681
|
-
if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {
|
|
6682
|
-
return;
|
|
6683
|
-
}
|
|
6684
|
-
const [origin, target] = unresolvedKeyframes;
|
|
6685
|
-
const originType = findDimensionValueType(origin);
|
|
6686
|
-
const targetType = findDimensionValueType(target);
|
|
6687
|
-
/**
|
|
6688
|
-
* Either we don't recognise these value types or we can animate between them.
|
|
6689
|
-
*/
|
|
6690
|
-
if (originType === targetType)
|
|
6691
|
-
return;
|
|
6692
|
-
/**
|
|
6693
|
-
* If both values are numbers or pixels, we can animate between them by
|
|
6694
|
-
* converting them to numbers.
|
|
6695
|
-
*/
|
|
6696
|
-
if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {
|
|
6697
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6698
|
-
const value = unresolvedKeyframes[i];
|
|
6699
|
-
if (typeof value === "string") {
|
|
6700
|
-
unresolvedKeyframes[i] = parseFloat(value);
|
|
6701
|
-
}
|
|
6702
|
-
}
|
|
6703
|
-
}
|
|
6704
|
-
else {
|
|
6705
|
-
/**
|
|
6706
|
-
* Else, the only way to resolve this is by measuring the element.
|
|
6707
|
-
*/
|
|
6708
|
-
this.needsMeasurement = true;
|
|
6709
|
-
}
|
|
6710
|
-
}
|
|
6711
|
-
resolveNoneKeyframes() {
|
|
6712
|
-
const { unresolvedKeyframes, name } = this;
|
|
6713
|
-
const noneKeyframeIndexes = [];
|
|
6714
|
-
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
6715
|
-
if (isNone(unresolvedKeyframes[i])) {
|
|
6716
|
-
noneKeyframeIndexes.push(i);
|
|
6717
|
-
}
|
|
6718
|
-
}
|
|
6719
|
-
if (noneKeyframeIndexes.length) {
|
|
6720
|
-
makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);
|
|
6721
|
-
}
|
|
6722
|
-
}
|
|
6723
|
-
measureInitialState() {
|
|
6724
|
-
const { element, unresolvedKeyframes, name } = this;
|
|
6725
|
-
if (!element || !element.current)
|
|
6726
|
-
return;
|
|
6727
|
-
if (name === "height") {
|
|
6728
|
-
this.suspendedScrollY = window.pageYOffset;
|
|
6729
|
-
}
|
|
6730
|
-
this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
6731
|
-
unresolvedKeyframes[0] = this.measuredOrigin;
|
|
6732
|
-
// Set final key frame to measure after next render
|
|
6733
|
-
const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
6734
|
-
if (measureKeyframe !== undefined) {
|
|
6735
|
-
element.getValue(name, measureKeyframe).jump(measureKeyframe, false);
|
|
6736
|
-
}
|
|
6737
|
-
}
|
|
6738
|
-
measureEndState() {
|
|
6739
|
-
const { element, name, unresolvedKeyframes } = this;
|
|
6740
|
-
if (!element || !element.current)
|
|
6741
|
-
return;
|
|
6742
|
-
const value = element.getValue(name);
|
|
6743
|
-
value && value.jump(this.measuredOrigin, false);
|
|
6744
|
-
const finalKeyframeIndex = unresolvedKeyframes.length - 1;
|
|
6745
|
-
const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];
|
|
6746
|
-
unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
6747
|
-
if (finalKeyframe !== null && this.finalKeyframe === undefined) {
|
|
6748
|
-
this.finalKeyframe = finalKeyframe;
|
|
6749
|
-
}
|
|
6750
|
-
// If we removed transform values, reapply them before the next render
|
|
6751
|
-
if (this.removedTransforms?.length) {
|
|
6752
|
-
this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {
|
|
6753
|
-
element
|
|
6754
|
-
.getValue(unsetTransformName)
|
|
6755
|
-
.set(unsetTransformValue);
|
|
6756
|
-
});
|
|
6757
|
-
}
|
|
6758
|
-
this.resolveNoneKeyframes();
|
|
6759
|
-
}
|
|
6760
|
-
}
|
|
6761
|
-
|
|
6762
|
-
/**
|
|
6763
|
-
* Check if a value is animatable. Examples:
|
|
6764
|
-
*
|
|
6765
|
-
* ✅: 100, "100px", "#fff"
|
|
6766
|
-
* ❌: "block", "url(2.jpg)"
|
|
6767
|
-
* @param value
|
|
6768
|
-
*
|
|
6769
|
-
* @internal
|
|
6770
|
-
*/
|
|
6771
|
-
const isAnimatable = (value, name) => {
|
|
6772
|
-
// If the list of keys tat might be non-animatable grows, replace with Set
|
|
6773
|
-
if (name === "zIndex")
|
|
6774
|
-
return false;
|
|
6775
|
-
// If it's a number or a keyframes array, we can animate it. We might at some point
|
|
6776
|
-
// need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
|
|
6777
|
-
// but for now lets leave it like this for performance reasons
|
|
6778
|
-
if (typeof value === "number" || Array.isArray(value))
|
|
6779
|
-
return true;
|
|
6780
|
-
if (typeof value === "string" && // It's animatable if we have a string
|
|
6781
|
-
(complex.test(value) || value === "0") && // And it contains numbers and/or colors
|
|
6782
|
-
!value.startsWith("url(") // Unless it starts with "url("
|
|
6783
|
-
) {
|
|
6784
|
-
return true;
|
|
6785
|
-
}
|
|
6786
|
-
return false;
|
|
6787
|
-
};
|
|
6788
|
-
|
|
6789
|
-
function isGenerator(type) {
|
|
6790
|
-
return typeof type === "function" && "applyToOptions" in type;
|
|
6791
|
-
}
|
|
6792
|
-
|
|
6793
|
-
function hasKeyframesChanged(keyframes) {
|
|
6794
|
-
const current = keyframes[0];
|
|
6795
|
-
if (keyframes.length === 1)
|
|
6796
|
-
return true;
|
|
6797
|
-
for (let i = 0; i < keyframes.length; i++) {
|
|
6798
|
-
if (keyframes[i] !== current)
|
|
6799
|
-
return true;
|
|
6800
|
-
}
|
|
6801
|
-
}
|
|
6802
|
-
function canAnimate(keyframes, name, type, velocity) {
|
|
6803
|
-
/**
|
|
6804
|
-
* Check if we're able to animate between the start and end keyframes,
|
|
6805
|
-
* and throw a warning if we're attempting to animate between one that's
|
|
6806
|
-
* animatable and another that isn't.
|
|
6807
|
-
*/
|
|
6808
|
-
const originKeyframe = keyframes[0];
|
|
6809
|
-
if (originKeyframe === null)
|
|
6810
|
-
return false;
|
|
6811
|
-
/**
|
|
6812
|
-
* These aren't traditionally animatable but we do support them.
|
|
6813
|
-
* In future we could look into making this more generic or replacing
|
|
6814
|
-
* this function with mix() === mixImmediate
|
|
6815
|
-
*/
|
|
6816
|
-
if (name === "display" || name === "visibility")
|
|
6817
|
-
return true;
|
|
6818
|
-
const targetKeyframe = keyframes[keyframes.length - 1];
|
|
6819
|
-
const isOriginAnimatable = isAnimatable(originKeyframe, name);
|
|
6820
|
-
const isTargetAnimatable = isAnimatable(targetKeyframe, name);
|
|
6821
|
-
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.`);
|
|
6822
|
-
// Always skip if any of these are true
|
|
6823
|
-
if (!isOriginAnimatable || !isTargetAnimatable) {
|
|
6824
|
-
return false;
|
|
6825
|
-
}
|
|
6826
|
-
return (hasKeyframesChanged(keyframes) ||
|
|
6827
|
-
((type === "spring" || isGenerator(type)) && velocity));
|
|
6828
|
-
}
|
|
6829
|
-
|
|
6830
|
-
const isNotNull = (value) => value !== null;
|
|
6831
|
-
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe) {
|
|
6832
|
-
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
6833
|
-
const index = repeat && repeatType !== "loop" && repeat % 2 === 1
|
|
6834
|
-
? 0
|
|
6835
|
-
: resolvedKeyframes.length - 1;
|
|
6836
|
-
return !index || finalKeyframe === undefined
|
|
6837
|
-
? resolvedKeyframes[index]
|
|
6838
|
-
: finalKeyframe;
|
|
6839
|
-
}
|
|
6840
|
-
|
|
6841
|
-
/**
|
|
6842
|
-
* Maximum time allowed between an animation being created and it being
|
|
6843
|
-
* resolved for us to use the latter as the start time.
|
|
6844
|
-
*
|
|
6845
|
-
* This is to ensure that while we prefer to "start" an animation as soon
|
|
6846
|
-
* as it's triggered, we also want to avoid a visual jump if there's a big delay
|
|
6847
|
-
* between these two moments.
|
|
6848
|
-
*/
|
|
6849
|
-
const MAX_RESOLVE_DELAY = 40;
|
|
6850
|
-
class BaseAnimation {
|
|
6851
|
-
constructor({ autoplay = true, delay = 0, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", ...options }) {
|
|
6852
|
-
// Track whether the animation has been stopped. Stopped animations won't restart.
|
|
6853
|
-
this.isStopped = false;
|
|
6854
|
-
this.hasAttemptedResolve = false;
|
|
6855
|
-
this.createdAt = time.now();
|
|
6856
|
-
this.options = {
|
|
6857
|
-
autoplay,
|
|
6858
|
-
delay,
|
|
6859
|
-
type,
|
|
6860
|
-
repeat,
|
|
6861
|
-
repeatDelay,
|
|
6862
|
-
repeatType,
|
|
6863
|
-
...options,
|
|
6864
|
-
};
|
|
6865
|
-
this.updateFinishedPromise();
|
|
6866
|
-
}
|
|
6867
|
-
/**
|
|
6868
|
-
* This method uses the createdAt and resolvedAt to calculate the
|
|
6869
|
-
* animation startTime. *Ideally*, we would use the createdAt time as t=0
|
|
6870
|
-
* as the following frame would then be the first frame of the animation in
|
|
6871
|
-
* progress, which would feel snappier.
|
|
6872
|
-
*
|
|
6873
|
-
* However, if there's a delay (main thread work) between the creation of
|
|
6874
|
-
* the animation and the first commited frame, we prefer to use resolvedAt
|
|
6875
|
-
* to avoid a sudden jump into the animation.
|
|
6876
|
-
*/
|
|
6877
|
-
calcStartTime() {
|
|
6878
|
-
if (!this.resolvedAt)
|
|
6879
|
-
return this.createdAt;
|
|
6880
|
-
return this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY
|
|
6881
|
-
? this.resolvedAt
|
|
6882
|
-
: this.createdAt;
|
|
6883
|
-
}
|
|
6884
|
-
/**
|
|
6885
|
-
* A getter for resolved data. If keyframes are not yet resolved, accessing
|
|
6886
|
-
* this.resolved will synchronously flush all pending keyframe resolvers.
|
|
6887
|
-
* This is a deoptimisation, but at its worst still batches read/writes.
|
|
6888
|
-
*/
|
|
6889
|
-
get resolved() {
|
|
6890
|
-
if (!this._resolved && !this.hasAttemptedResolve) {
|
|
6891
|
-
flushKeyframeResolvers();
|
|
6892
|
-
}
|
|
6893
|
-
return this._resolved;
|
|
6894
|
-
}
|
|
6895
|
-
/**
|
|
6896
|
-
* A method to be called when the keyframes resolver completes. This method
|
|
6897
|
-
* will check if its possible to run the animation and, if not, skip it.
|
|
6898
|
-
* Otherwise, it will call initPlayback on the implementing class.
|
|
6899
|
-
*/
|
|
6900
|
-
onKeyframesResolved(keyframes, finalKeyframe) {
|
|
6901
|
-
this.resolvedAt = time.now();
|
|
6902
|
-
this.hasAttemptedResolve = true;
|
|
6903
|
-
const { name, type, velocity, delay, onComplete, onUpdate, isGenerator, } = this.options;
|
|
6904
|
-
/**
|
|
6905
|
-
* If we can't animate this value with the resolved keyframes
|
|
6906
|
-
* then we should complete it immediately.
|
|
6907
|
-
*/
|
|
6908
|
-
if (!isGenerator && !canAnimate(keyframes, name, type, velocity)) {
|
|
6909
|
-
// Finish immediately
|
|
6910
|
-
if (!delay) {
|
|
6911
|
-
onUpdate &&
|
|
6912
|
-
onUpdate(getFinalKeyframe(keyframes, this.options, finalKeyframe));
|
|
6913
|
-
onComplete && onComplete();
|
|
6914
|
-
this.resolveFinishedPromise();
|
|
6915
|
-
return;
|
|
6916
|
-
}
|
|
6917
|
-
// Finish after a delay
|
|
6918
|
-
else {
|
|
6919
|
-
this.options.duration = 0;
|
|
6920
|
-
}
|
|
6921
|
-
}
|
|
6922
|
-
const resolvedAnimation = this.initPlayback(keyframes, finalKeyframe);
|
|
6923
|
-
if (resolvedAnimation === false)
|
|
6924
|
-
return;
|
|
6925
|
-
this._resolved = {
|
|
6926
|
-
keyframes,
|
|
6927
|
-
finalKeyframe,
|
|
6928
|
-
...resolvedAnimation,
|
|
6929
|
-
};
|
|
6930
|
-
this.onPostResolved();
|
|
6931
|
-
}
|
|
6932
|
-
onPostResolved() { }
|
|
6933
|
-
/**
|
|
6934
|
-
* Allows the returned animation to be awaited or promise-chained. Currently
|
|
6935
|
-
* resolves when the animation finishes at all but in a future update could/should
|
|
6936
|
-
* reject if its cancels.
|
|
6937
|
-
*/
|
|
6938
|
-
then(resolve, reject) {
|
|
6939
|
-
return this.currentFinishedPromise.then(resolve, reject);
|
|
6940
|
-
}
|
|
6941
|
-
flatten() {
|
|
6942
|
-
if (!this.options.allowFlatten)
|
|
6943
|
-
return;
|
|
6944
|
-
this.options.type = "keyframes";
|
|
6945
|
-
this.options.ease = "linear";
|
|
6946
|
-
}
|
|
6947
|
-
updateFinishedPromise() {
|
|
6948
|
-
this.currentFinishedPromise = new Promise((resolve) => {
|
|
6949
|
-
this.resolveFinishedPromise = resolve;
|
|
6950
|
-
});
|
|
6951
|
-
}
|
|
6952
|
-
}
|
|
6953
|
-
|
|
6954
|
-
/*
|
|
6955
|
-
Value in range from progress
|
|
6956
|
-
|
|
6957
|
-
Given a lower limit and an upper limit, we return the value within
|
|
6958
|
-
that range as expressed by progress (usually a number from 0 to 1)
|
|
6959
|
-
|
|
6960
|
-
So progress = 0.5 would change
|
|
6961
|
-
|
|
6962
|
-
from -------- to
|
|
6963
|
-
|
|
6964
|
-
to
|
|
6965
|
-
|
|
6966
|
-
from ---- to
|
|
6967
|
-
|
|
6968
|
-
E.g. from = 10, to = 20, progress = 0.5 => 15
|
|
6969
|
-
|
|
6970
|
-
@param [number]: Lower limit of range
|
|
6971
|
-
@param [number]: Upper limit of range
|
|
6972
|
-
@param [number]: The progress between lower and upper limits expressed 0-1
|
|
6973
|
-
@return [number]: Value as calculated from progress within range (not limited within range)
|
|
6974
|
-
*/
|
|
6975
|
-
const mixNumber$1 = (from, to, progress) => {
|
|
6976
|
-
return from + (to - from) * progress;
|
|
6977
|
-
};
|
|
6978
|
-
|
|
6979
|
-
// Adapted from https://gist.github.com/mjackson/5311256
|
|
6980
|
-
function hueToRgb(p, q, t) {
|
|
6981
|
-
if (t < 0)
|
|
6982
|
-
t += 1;
|
|
6983
|
-
if (t > 1)
|
|
6984
|
-
t -= 1;
|
|
6985
|
-
if (t < 1 / 6)
|
|
6986
|
-
return p + (q - p) * 6 * t;
|
|
6987
|
-
if (t < 1 / 2)
|
|
6988
|
-
return q;
|
|
6989
|
-
if (t < 2 / 3)
|
|
6990
|
-
return p + (q - p) * (2 / 3 - t) * 6;
|
|
6991
|
-
return p;
|
|
6992
|
-
}
|
|
6993
|
-
function hslaToRgba({ hue, saturation, lightness, alpha }) {
|
|
6994
|
-
hue /= 360;
|
|
6995
|
-
saturation /= 100;
|
|
6996
|
-
lightness /= 100;
|
|
6997
|
-
let red = 0;
|
|
6998
|
-
let green = 0;
|
|
6999
|
-
let blue = 0;
|
|
7000
|
-
if (!saturation) {
|
|
7001
|
-
red = green = blue = lightness;
|
|
7002
|
-
}
|
|
7003
|
-
else {
|
|
7004
|
-
const q = lightness < 0.5
|
|
7005
|
-
? lightness * (1 + saturation)
|
|
7006
|
-
: lightness + saturation - lightness * saturation;
|
|
7007
|
-
const p = 2 * lightness - q;
|
|
7008
|
-
red = hueToRgb(p, q, hue + 1 / 3);
|
|
7009
|
-
green = hueToRgb(p, q, hue);
|
|
7010
|
-
blue = hueToRgb(p, q, hue - 1 / 3);
|
|
7011
|
-
}
|
|
7012
|
-
return {
|
|
7013
|
-
red: Math.round(red * 255),
|
|
7014
|
-
green: Math.round(green * 255),
|
|
7015
|
-
blue: Math.round(blue * 255),
|
|
7016
|
-
alpha,
|
|
7017
|
-
};
|
|
7018
|
-
}
|
|
7019
|
-
|
|
7020
|
-
function mixImmediate(a, b) {
|
|
7021
|
-
return (p) => (p > 0 ? b : a);
|
|
7022
|
-
}
|
|
7023
|
-
|
|
7024
|
-
// Linear color space blending
|
|
7025
|
-
// Explained https://www.youtube.com/watch?v=LKnqECcg6Gw
|
|
7026
|
-
// Demonstrated http://codepen.io/osublake/pen/xGVVaN
|
|
7027
|
-
const mixLinearColor = (from, to, v) => {
|
|
7028
|
-
const fromExpo = from * from;
|
|
7029
|
-
const expo = v * (to * to - fromExpo) + fromExpo;
|
|
7030
|
-
return expo < 0 ? 0 : Math.sqrt(expo);
|
|
7031
|
-
};
|
|
7032
|
-
const colorTypes = [hex, rgba, hsla];
|
|
7033
|
-
const getColorType = (v) => colorTypes.find((type) => type.test(v));
|
|
7034
|
-
function asRGBA(color) {
|
|
7035
|
-
const type = getColorType(color);
|
|
7036
|
-
warning(Boolean(type), `'${color}' is not an animatable color. Use the equivalent color code instead.`);
|
|
7037
|
-
if (!Boolean(type))
|
|
7038
|
-
return false;
|
|
7039
|
-
let model = type.parse(color);
|
|
7040
|
-
if (type === hsla) {
|
|
7041
|
-
// TODO Remove this cast - needed since Motion's stricter typing
|
|
7042
|
-
model = hslaToRgba(model);
|
|
7043
|
-
}
|
|
7044
|
-
return model;
|
|
7045
|
-
}
|
|
7046
|
-
const mixColor = (from, to) => {
|
|
7047
|
-
const fromRGBA = asRGBA(from);
|
|
7048
|
-
const toRGBA = asRGBA(to);
|
|
7049
|
-
if (!fromRGBA || !toRGBA) {
|
|
7050
|
-
return mixImmediate(from, to);
|
|
7051
|
-
}
|
|
7052
|
-
const blended = { ...fromRGBA };
|
|
7053
|
-
return (v) => {
|
|
7054
|
-
blended.red = mixLinearColor(fromRGBA.red, toRGBA.red, v);
|
|
7055
|
-
blended.green = mixLinearColor(fromRGBA.green, toRGBA.green, v);
|
|
7056
|
-
blended.blue = mixLinearColor(fromRGBA.blue, toRGBA.blue, v);
|
|
7057
|
-
blended.alpha = mixNumber$1(fromRGBA.alpha, toRGBA.alpha, v);
|
|
7058
|
-
return rgba.transform(blended);
|
|
7059
|
-
};
|
|
7060
|
-
};
|
|
7061
|
-
|
|
7062
6198
|
/**
|
|
7063
6199
|
* Pipe
|
|
7064
6200
|
* Compose other transformers to run linearily
|
|
@@ -7069,21 +6205,6 @@ const mixColor = (from, to) => {
|
|
|
7069
6205
|
const combineFunctions = (a, b) => (v) => b(a(v));
|
|
7070
6206
|
const pipe = (...transformers) => transformers.reduce(combineFunctions);
|
|
7071
6207
|
|
|
7072
|
-
const invisibleValues = new Set(["none", "hidden"]);
|
|
7073
|
-
/**
|
|
7074
|
-
* Returns a function that, when provided a progress value between 0 and 1,
|
|
7075
|
-
* will return the "none" or "hidden" string only when the progress is that of
|
|
7076
|
-
* the origin or target.
|
|
7077
|
-
*/
|
|
7078
|
-
function mixVisibility(origin, target) {
|
|
7079
|
-
if (invisibleValues.has(origin)) {
|
|
7080
|
-
return (p) => (p <= 0 ? origin : target);
|
|
7081
|
-
}
|
|
7082
|
-
else {
|
|
7083
|
-
return (p) => (p >= 1 ? target : origin);
|
|
7084
|
-
}
|
|
7085
|
-
}
|
|
7086
|
-
|
|
7087
6208
|
function mixNumber(a, b) {
|
|
7088
6209
|
return (p) => mixNumber$1(a, b, p);
|
|
7089
6210
|
}
|
|
@@ -7164,16 +6285,71 @@ const mixComplex = (origin, target) => {
|
|
|
7164
6285
|
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.`);
|
|
7165
6286
|
return mixImmediate(origin, target);
|
|
7166
6287
|
}
|
|
7167
|
-
};
|
|
6288
|
+
};
|
|
6289
|
+
|
|
6290
|
+
function mix(from, to, p) {
|
|
6291
|
+
if (typeof from === "number" &&
|
|
6292
|
+
typeof to === "number" &&
|
|
6293
|
+
typeof p === "number") {
|
|
6294
|
+
return mixNumber$1(from, to, p);
|
|
6295
|
+
}
|
|
6296
|
+
const mixer = getMixer(from);
|
|
6297
|
+
return mixer(from, to);
|
|
6298
|
+
}
|
|
6299
|
+
|
|
6300
|
+
const frameloopDriver = (update) => {
|
|
6301
|
+
const passTimestamp = ({ timestamp }) => update(timestamp);
|
|
6302
|
+
return {
|
|
6303
|
+
start: () => frame.update(passTimestamp, true),
|
|
6304
|
+
stop: () => cancelFrame(passTimestamp),
|
|
6305
|
+
/**
|
|
6306
|
+
* If we're processing this frame we can use the
|
|
6307
|
+
* framelocked timestamp to keep things in sync.
|
|
6308
|
+
*/
|
|
6309
|
+
now: () => (frameData.isProcessing ? frameData.timestamp : time.now()),
|
|
6310
|
+
};
|
|
6311
|
+
};
|
|
6312
|
+
|
|
6313
|
+
const generateLinearEasing = (easing, duration, // as milliseconds
|
|
6314
|
+
resolution = 10 // as milliseconds
|
|
6315
|
+
) => {
|
|
6316
|
+
let points = "";
|
|
6317
|
+
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
6318
|
+
for (let i = 0; i < numPoints; i++) {
|
|
6319
|
+
points += easing(i / (numPoints - 1)) + ", ";
|
|
6320
|
+
}
|
|
6321
|
+
return `linear(${points.substring(0, points.length - 2)})`;
|
|
6322
|
+
};
|
|
6323
|
+
|
|
6324
|
+
/**
|
|
6325
|
+
* Implement a practical max duration for keyframe generation
|
|
6326
|
+
* to prevent infinite loops
|
|
6327
|
+
*/
|
|
6328
|
+
const maxGeneratorDuration = 20000;
|
|
6329
|
+
function calcGeneratorDuration(generator) {
|
|
6330
|
+
let duration = 0;
|
|
6331
|
+
const timeStep = 50;
|
|
6332
|
+
let state = generator.next(duration);
|
|
6333
|
+
while (!state.done && duration < maxGeneratorDuration) {
|
|
6334
|
+
duration += timeStep;
|
|
6335
|
+
state = generator.next(duration);
|
|
6336
|
+
}
|
|
6337
|
+
return duration >= maxGeneratorDuration ? Infinity : duration;
|
|
6338
|
+
}
|
|
7168
6339
|
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
6340
|
+
/**
|
|
6341
|
+
* Create a progress => progress easing function from a generator.
|
|
6342
|
+
*/
|
|
6343
|
+
function createGeneratorEasing(options, scale = 100, createGenerator) {
|
|
6344
|
+
const generator = createGenerator({ ...options, keyframes: [0, scale] });
|
|
6345
|
+
const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
|
|
6346
|
+
return {
|
|
6347
|
+
type: "keyframes",
|
|
6348
|
+
ease: (progress) => {
|
|
6349
|
+
return generator.next(duration * progress).value / scale;
|
|
6350
|
+
},
|
|
6351
|
+
duration: millisecondsToSeconds(duration),
|
|
6352
|
+
};
|
|
7177
6353
|
}
|
|
7178
6354
|
|
|
7179
6355
|
const velocitySampleDuration = 5; // ms
|
|
@@ -7208,17 +6384,6 @@ const springDefaults = {
|
|
|
7208
6384
|
maxDamping: 1,
|
|
7209
6385
|
};
|
|
7210
6386
|
|
|
7211
|
-
/**
|
|
7212
|
-
* Converts seconds to milliseconds
|
|
7213
|
-
*
|
|
7214
|
-
* @param seconds - Time in seconds.
|
|
7215
|
-
* @return milliseconds - Converted time in milliseconds.
|
|
7216
|
-
*/
|
|
7217
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
7218
|
-
const secondsToMilliseconds = (seconds) => seconds * 1000;
|
|
7219
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
7220
|
-
const millisecondsToSeconds = (milliseconds) => milliseconds / 1000;
|
|
7221
|
-
|
|
7222
6387
|
const safeMin = 0.001;
|
|
7223
6388
|
function findSpring({ duration = springDefaults.duration, bounce = springDefaults.bounce, velocity = springDefaults.velocity, mass = springDefaults.mass, }) {
|
|
7224
6389
|
let envelope;
|
|
@@ -7299,81 +6464,6 @@ function calcAngularFreq(undampedFreq, dampingRatio) {
|
|
|
7299
6464
|
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio);
|
|
7300
6465
|
}
|
|
7301
6466
|
|
|
7302
|
-
/**
|
|
7303
|
-
* Implement a practical max duration for keyframe generation
|
|
7304
|
-
* to prevent infinite loops
|
|
7305
|
-
*/
|
|
7306
|
-
const maxGeneratorDuration = 20000;
|
|
7307
|
-
function calcGeneratorDuration(generator) {
|
|
7308
|
-
let duration = 0;
|
|
7309
|
-
const timeStep = 50;
|
|
7310
|
-
let state = generator.next(duration);
|
|
7311
|
-
while (!state.done && duration < maxGeneratorDuration) {
|
|
7312
|
-
duration += timeStep;
|
|
7313
|
-
state = generator.next(duration);
|
|
7314
|
-
}
|
|
7315
|
-
return duration >= maxGeneratorDuration ? Infinity : duration;
|
|
7316
|
-
}
|
|
7317
|
-
|
|
7318
|
-
/**
|
|
7319
|
-
* Create a progress => progress easing function from a generator.
|
|
7320
|
-
*/
|
|
7321
|
-
function createGeneratorEasing(options, scale = 100, createGenerator) {
|
|
7322
|
-
const generator = createGenerator({ ...options, keyframes: [0, scale] });
|
|
7323
|
-
const duration = Math.min(calcGeneratorDuration(generator), maxGeneratorDuration);
|
|
7324
|
-
return {
|
|
7325
|
-
type: "keyframes",
|
|
7326
|
-
ease: (progress) => {
|
|
7327
|
-
return generator.next(duration * progress).value / scale;
|
|
7328
|
-
},
|
|
7329
|
-
duration: millisecondsToSeconds(duration),
|
|
7330
|
-
};
|
|
7331
|
-
}
|
|
7332
|
-
|
|
7333
|
-
/**
|
|
7334
|
-
* Add the ability for test suites to manually set support flags
|
|
7335
|
-
* to better test more environments.
|
|
7336
|
-
*/
|
|
7337
|
-
const supportsFlags = {};
|
|
7338
|
-
|
|
7339
|
-
/*#__NO_SIDE_EFFECTS__*/
|
|
7340
|
-
function memo(callback) {
|
|
7341
|
-
let result;
|
|
7342
|
-
return () => {
|
|
7343
|
-
if (result === undefined)
|
|
7344
|
-
result = callback();
|
|
7345
|
-
return result;
|
|
7346
|
-
};
|
|
7347
|
-
}
|
|
7348
|
-
|
|
7349
|
-
function memoSupports(callback, supportsFlag) {
|
|
7350
|
-
const memoized = memo(callback);
|
|
7351
|
-
return () => supportsFlags[supportsFlag] ?? memoized();
|
|
7352
|
-
}
|
|
7353
|
-
|
|
7354
|
-
const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
|
|
7355
|
-
try {
|
|
7356
|
-
document
|
|
7357
|
-
.createElement("div")
|
|
7358
|
-
.animate({ opacity: 0 }, { easing: "linear(0, 1)" });
|
|
7359
|
-
}
|
|
7360
|
-
catch (e) {
|
|
7361
|
-
return false;
|
|
7362
|
-
}
|
|
7363
|
-
return true;
|
|
7364
|
-
}, "linearEasing");
|
|
7365
|
-
|
|
7366
|
-
const generateLinearEasing = (easing, duration, // as milliseconds
|
|
7367
|
-
resolution = 10 // as milliseconds
|
|
7368
|
-
) => {
|
|
7369
|
-
let points = "";
|
|
7370
|
-
const numPoints = Math.max(Math.round(duration / resolution), 2);
|
|
7371
|
-
for (let i = 0; i < numPoints; i++) {
|
|
7372
|
-
points += easing(i / (numPoints - 1)) + ", ";
|
|
7373
|
-
}
|
|
7374
|
-
return `linear(${points.substring(0, points.length - 2)})`;
|
|
7375
|
-
};
|
|
7376
|
-
|
|
7377
6467
|
const durationKeys = ["duration", "bounce"];
|
|
7378
6468
|
const physicsKeys = ["stiffness", "damping", "mass"];
|
|
7379
6469
|
function isSpringType(options, keys) {
|
|
@@ -7500,7 +6590,7 @@ function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce
|
|
|
7500
6590
|
next: (t) => {
|
|
7501
6591
|
const current = resolveSpring(t);
|
|
7502
6592
|
if (!isResolvedFromDuration) {
|
|
7503
|
-
let currentVelocity = 0.0;
|
|
6593
|
+
let currentVelocity = t === 0 ? initialVelocity : 0.0;
|
|
7504
6594
|
/**
|
|
7505
6595
|
* We only need to calculate velocity for under-damped springs
|
|
7506
6596
|
* as over- and critically-damped springs can't overshoot, so
|
|
@@ -7534,7 +6624,7 @@ function spring(optionsOrVisualDuration = springDefaults.visualDuration, bounce
|
|
|
7534
6624
|
}
|
|
7535
6625
|
spring.applyToOptions = (options) => {
|
|
7536
6626
|
const generatorOptions = createGeneratorEasing(options, 100, spring);
|
|
7537
|
-
options.ease =
|
|
6627
|
+
options.ease = generatorOptions.ease;
|
|
7538
6628
|
options.duration = secondsToMilliseconds(generatorOptions.duration);
|
|
7539
6629
|
options.type = "keyframes";
|
|
7540
6630
|
return options;
|
|
@@ -7623,44 +6713,6 @@ function inertia({ keyframes, velocity = 0.0, power = 0.8, timeConstant = 325, b
|
|
|
7623
6713
|
};
|
|
7624
6714
|
}
|
|
7625
6715
|
|
|
7626
|
-
const easeIn = /*@__PURE__*/ cubicBezier(0.42, 0, 1, 1);
|
|
7627
|
-
const easeOut = /*@__PURE__*/ cubicBezier(0, 0, 0.58, 1);
|
|
7628
|
-
const easeInOut = /*@__PURE__*/ cubicBezier(0.42, 0, 0.58, 1);
|
|
7629
|
-
|
|
7630
|
-
const isEasingArray = (ease) => {
|
|
7631
|
-
return Array.isArray(ease) && typeof ease[0] !== "number";
|
|
7632
|
-
};
|
|
7633
|
-
|
|
7634
|
-
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
|
7635
|
-
|
|
7636
|
-
const easingLookup = {
|
|
7637
|
-
linear: noop,
|
|
7638
|
-
easeIn,
|
|
7639
|
-
easeInOut,
|
|
7640
|
-
easeOut,
|
|
7641
|
-
circIn,
|
|
7642
|
-
circInOut,
|
|
7643
|
-
circOut,
|
|
7644
|
-
backIn,
|
|
7645
|
-
backInOut,
|
|
7646
|
-
backOut,
|
|
7647
|
-
anticipate,
|
|
7648
|
-
};
|
|
7649
|
-
const easingDefinitionToFunction = (definition) => {
|
|
7650
|
-
if (isBezierDefinition(definition)) {
|
|
7651
|
-
// If cubic bezier definition, create bezier curve
|
|
7652
|
-
invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`);
|
|
7653
|
-
const [x1, y1, x2, y2] = definition;
|
|
7654
|
-
return cubicBezier(x1, y1, x2, y2);
|
|
7655
|
-
}
|
|
7656
|
-
else if (typeof definition === "string") {
|
|
7657
|
-
// Else lookup from table
|
|
7658
|
-
invariant(easingLookup[definition] !== undefined, `Invalid easing type '${definition}'`);
|
|
7659
|
-
return easingLookup[definition];
|
|
7660
|
-
}
|
|
7661
|
-
return definition;
|
|
7662
|
-
};
|
|
7663
|
-
|
|
7664
6716
|
/*
|
|
7665
6717
|
Progress within given range
|
|
7666
6718
|
|
|
@@ -7681,7 +6733,7 @@ const progress = (from, to, value) => {
|
|
|
7681
6733
|
|
|
7682
6734
|
function createMixers(output, ease, customMixer) {
|
|
7683
6735
|
const mixers = [];
|
|
7684
|
-
const mixerFactory = customMixer || mix;
|
|
6736
|
+
const mixerFactory = customMixer || MotionGlobalConfig.mix || mix;
|
|
7685
6737
|
const numMixers = output.length - 1;
|
|
7686
6738
|
for (let i = 0; i < numMixers; i++) {
|
|
7687
6739
|
let mixer = mixerFactory(output[i], output[i + 1]);
|
|
@@ -7755,17 +6807,124 @@ function fillOffset(offset, remaining) {
|
|
|
7755
6807
|
const offsetProgress = progress(0, remaining, i);
|
|
7756
6808
|
offset.push(mixNumber$1(min, 1, offsetProgress));
|
|
7757
6809
|
}
|
|
7758
|
-
}
|
|
7759
|
-
|
|
7760
|
-
function defaultOffset(arr) {
|
|
7761
|
-
const offset = [0];
|
|
7762
|
-
fillOffset(offset, arr.length - 1);
|
|
7763
|
-
return offset;
|
|
7764
|
-
}
|
|
7765
|
-
|
|
7766
|
-
function convertOffsetToTimes(offset, duration) {
|
|
7767
|
-
return offset.map((o) => o * duration);
|
|
7768
|
-
}
|
|
6810
|
+
}
|
|
6811
|
+
|
|
6812
|
+
function defaultOffset(arr) {
|
|
6813
|
+
const offset = [0];
|
|
6814
|
+
fillOffset(offset, arr.length - 1);
|
|
6815
|
+
return offset;
|
|
6816
|
+
}
|
|
6817
|
+
|
|
6818
|
+
function convertOffsetToTimes(offset, duration) {
|
|
6819
|
+
return offset.map((o) => o * duration);
|
|
6820
|
+
}
|
|
6821
|
+
|
|
6822
|
+
/*
|
|
6823
|
+
Bezier function generator
|
|
6824
|
+
This has been modified from Gaëtan Renaudeau's BezierEasing
|
|
6825
|
+
https://github.com/gre/bezier-easing/blob/master/src/index.js
|
|
6826
|
+
https://github.com/gre/bezier-easing/blob/master/LICENSE
|
|
6827
|
+
|
|
6828
|
+
I've removed the newtonRaphsonIterate algo because in benchmarking it
|
|
6829
|
+
wasn't noticiably faster than binarySubdivision, indeed removing it
|
|
6830
|
+
usually improved times, depending on the curve.
|
|
6831
|
+
I also removed the lookup table, as for the added bundle size and loop we're
|
|
6832
|
+
only cutting ~4 or so subdivision iterations. I bumped the max iterations up
|
|
6833
|
+
to 12 to compensate and this still tended to be faster for no perceivable
|
|
6834
|
+
loss in accuracy.
|
|
6835
|
+
Usage
|
|
6836
|
+
const easeOut = cubicBezier(.17,.67,.83,.67);
|
|
6837
|
+
const x = easeOut(0.5); // returns 0.627...
|
|
6838
|
+
*/
|
|
6839
|
+
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
6840
|
+
const calcBezier = (t, a1, a2) => (((1.0 - 3.0 * a2 + 3.0 * a1) * t + (3.0 * a2 - 6.0 * a1)) * t + 3.0 * a1) *
|
|
6841
|
+
t;
|
|
6842
|
+
const subdivisionPrecision = 0.0000001;
|
|
6843
|
+
const subdivisionMaxIterations = 12;
|
|
6844
|
+
function binarySubdivide(x, lowerBound, upperBound, mX1, mX2) {
|
|
6845
|
+
let currentX;
|
|
6846
|
+
let currentT;
|
|
6847
|
+
let i = 0;
|
|
6848
|
+
do {
|
|
6849
|
+
currentT = lowerBound + (upperBound - lowerBound) / 2.0;
|
|
6850
|
+
currentX = calcBezier(currentT, mX1, mX2) - x;
|
|
6851
|
+
if (currentX > 0.0) {
|
|
6852
|
+
upperBound = currentT;
|
|
6853
|
+
}
|
|
6854
|
+
else {
|
|
6855
|
+
lowerBound = currentT;
|
|
6856
|
+
}
|
|
6857
|
+
} while (Math.abs(currentX) > subdivisionPrecision &&
|
|
6858
|
+
++i < subdivisionMaxIterations);
|
|
6859
|
+
return currentT;
|
|
6860
|
+
}
|
|
6861
|
+
function cubicBezier(mX1, mY1, mX2, mY2) {
|
|
6862
|
+
// If this is a linear gradient, return linear easing
|
|
6863
|
+
if (mX1 === mY1 && mX2 === mY2)
|
|
6864
|
+
return noop;
|
|
6865
|
+
const getTForX = (aX) => binarySubdivide(aX, 0, 1, mX1, mX2);
|
|
6866
|
+
// If animation is at start/end, return t without easing
|
|
6867
|
+
return (t) => t === 0 || t === 1 ? t : calcBezier(getTForX(t), mY1, mY2);
|
|
6868
|
+
}
|
|
6869
|
+
|
|
6870
|
+
const easeIn = /*@__PURE__*/ cubicBezier(0.42, 0, 1, 1);
|
|
6871
|
+
const easeOut = /*@__PURE__*/ cubicBezier(0, 0, 0.58, 1);
|
|
6872
|
+
const easeInOut = /*@__PURE__*/ cubicBezier(0.42, 0, 0.58, 1);
|
|
6873
|
+
|
|
6874
|
+
const isEasingArray = (ease) => {
|
|
6875
|
+
return Array.isArray(ease) && typeof ease[0] !== "number";
|
|
6876
|
+
};
|
|
6877
|
+
|
|
6878
|
+
// Accepts an easing function and returns a new one that outputs mirrored values for
|
|
6879
|
+
// the second half of the animation. Turns easeIn into easeInOut.
|
|
6880
|
+
const mirrorEasing = (easing) => (p) => p <= 0.5 ? easing(2 * p) / 2 : (2 - easing(2 * (1 - p))) / 2;
|
|
6881
|
+
|
|
6882
|
+
// Accepts an easing function and returns a new one that outputs reversed values.
|
|
6883
|
+
// Turns easeIn into easeOut.
|
|
6884
|
+
const reverseEasing = (easing) => (p) => 1 - easing(1 - p);
|
|
6885
|
+
|
|
6886
|
+
const backOut = /*@__PURE__*/ cubicBezier(0.33, 1.53, 0.69, 0.99);
|
|
6887
|
+
const backIn = /*@__PURE__*/ reverseEasing(backOut);
|
|
6888
|
+
const backInOut = /*@__PURE__*/ mirrorEasing(backIn);
|
|
6889
|
+
|
|
6890
|
+
const anticipate = (p) => (p *= 2) < 1 ? 0.5 * backIn(p) : 0.5 * (2 - Math.pow(2, -10 * (p - 1)));
|
|
6891
|
+
|
|
6892
|
+
const circIn = (p) => 1 - Math.sin(Math.acos(p));
|
|
6893
|
+
const circOut = reverseEasing(circIn);
|
|
6894
|
+
const circInOut = mirrorEasing(circIn);
|
|
6895
|
+
|
|
6896
|
+
const isBezierDefinition = (easing) => Array.isArray(easing) && typeof easing[0] === "number";
|
|
6897
|
+
|
|
6898
|
+
const easingLookup = {
|
|
6899
|
+
linear: noop,
|
|
6900
|
+
easeIn,
|
|
6901
|
+
easeInOut,
|
|
6902
|
+
easeOut,
|
|
6903
|
+
circIn,
|
|
6904
|
+
circInOut,
|
|
6905
|
+
circOut,
|
|
6906
|
+
backIn,
|
|
6907
|
+
backInOut,
|
|
6908
|
+
backOut,
|
|
6909
|
+
anticipate,
|
|
6910
|
+
};
|
|
6911
|
+
const isValidEasing = (easing) => {
|
|
6912
|
+
return typeof easing === "string";
|
|
6913
|
+
};
|
|
6914
|
+
const easingDefinitionToFunction = (definition) => {
|
|
6915
|
+
if (isBezierDefinition(definition)) {
|
|
6916
|
+
// If cubic bezier definition, create bezier curve
|
|
6917
|
+
invariant(definition.length === 4, `Cubic bezier arrays must contain four numerical values.`);
|
|
6918
|
+
const [x1, y1, x2, y2] = definition;
|
|
6919
|
+
return cubicBezier(x1, y1, x2, y2);
|
|
6920
|
+
}
|
|
6921
|
+
else if (isValidEasing(definition)) {
|
|
6922
|
+
// Else lookup from table
|
|
6923
|
+
invariant(easingLookup[definition] !== undefined, `Invalid easing type '${definition}'`);
|
|
6924
|
+
return easingLookup[definition];
|
|
6925
|
+
}
|
|
6926
|
+
return definition;
|
|
6927
|
+
};
|
|
7769
6928
|
|
|
7770
6929
|
function defaultEasing(values, easing) {
|
|
7771
6930
|
return values.map(() => easing || easeInOut).splice(0, values.length - 1);
|
|
@@ -7810,68 +6969,84 @@ function keyframes({ duration = 300, keyframes: keyframeValues, times, ease = "e
|
|
|
7810
6969
|
};
|
|
7811
6970
|
}
|
|
7812
6971
|
|
|
7813
|
-
const
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
now: () => (frameData.isProcessing ? frameData.timestamp : time.now()),
|
|
7823
|
-
};
|
|
7824
|
-
};
|
|
6972
|
+
const isNotNull = (value) => value !== null;
|
|
6973
|
+
function getFinalKeyframe(keyframes, { repeat, repeatType = "loop" }, finalKeyframe, speed = 1) {
|
|
6974
|
+
const resolvedKeyframes = keyframes.filter(isNotNull);
|
|
6975
|
+
const useFirstKeyframe = speed < 0 || (repeat && repeatType !== "loop" && repeat % 2 === 1);
|
|
6976
|
+
const index = useFirstKeyframe ? 0 : resolvedKeyframes.length - 1;
|
|
6977
|
+
return !index || finalKeyframe === undefined
|
|
6978
|
+
? resolvedKeyframes[index]
|
|
6979
|
+
: finalKeyframe;
|
|
6980
|
+
}
|
|
7825
6981
|
|
|
7826
|
-
const
|
|
6982
|
+
const transitionTypeMap = {
|
|
7827
6983
|
decay: inertia,
|
|
7828
6984
|
inertia,
|
|
7829
6985
|
tween: keyframes,
|
|
7830
6986
|
keyframes: keyframes,
|
|
7831
6987
|
spring,
|
|
7832
6988
|
};
|
|
6989
|
+
function replaceTransitionType(transition) {
|
|
6990
|
+
if (typeof transition.type === "string") {
|
|
6991
|
+
transition.type = transitionTypeMap[transition.type];
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
|
|
6995
|
+
class WithPromise {
|
|
6996
|
+
constructor() {
|
|
6997
|
+
this.count = 0;
|
|
6998
|
+
this.updateFinished();
|
|
6999
|
+
}
|
|
7000
|
+
get finished() {
|
|
7001
|
+
return this._finished;
|
|
7002
|
+
}
|
|
7003
|
+
updateFinished() {
|
|
7004
|
+
this.count++;
|
|
7005
|
+
this._finished = new Promise((resolve) => {
|
|
7006
|
+
this.resolve = resolve;
|
|
7007
|
+
});
|
|
7008
|
+
}
|
|
7009
|
+
notifyFinished() {
|
|
7010
|
+
this.resolve();
|
|
7011
|
+
}
|
|
7012
|
+
/**
|
|
7013
|
+
* Allows the animation to be awaited.
|
|
7014
|
+
*
|
|
7015
|
+
* @deprecated Use `finished` instead.
|
|
7016
|
+
*/
|
|
7017
|
+
then(onResolve, onReject) {
|
|
7018
|
+
return this.finished.then(onResolve, onReject);
|
|
7019
|
+
}
|
|
7020
|
+
}
|
|
7021
|
+
|
|
7833
7022
|
const percentToProgress = (percent) => percent / 100;
|
|
7834
|
-
|
|
7835
|
-
* Animation that runs on the main thread. Designed to be WAAPI-spec in the subset of
|
|
7836
|
-
* features we expose publically. Mostly the compatibility is to ensure visual identity
|
|
7837
|
-
* between both WAAPI and main thread animations.
|
|
7838
|
-
*/
|
|
7839
|
-
class MainThreadAnimation extends BaseAnimation {
|
|
7023
|
+
class JSAnimation extends WithPromise {
|
|
7840
7024
|
constructor(options) {
|
|
7841
|
-
super(
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
this.holdTime = null;
|
|
7846
|
-
/**
|
|
7847
|
-
* The time at which the animation was cancelled.
|
|
7848
|
-
*/
|
|
7849
|
-
this.cancelTime = null;
|
|
7025
|
+
super();
|
|
7026
|
+
this.state = "idle";
|
|
7027
|
+
this.startTime = null;
|
|
7028
|
+
this.isStopped = false;
|
|
7850
7029
|
/**
|
|
7851
7030
|
* The current time of the animation.
|
|
7852
7031
|
*/
|
|
7853
7032
|
this.currentTime = 0;
|
|
7854
7033
|
/**
|
|
7855
|
-
*
|
|
7856
|
-
*/
|
|
7857
|
-
this.playbackSpeed = 1;
|
|
7858
|
-
/**
|
|
7859
|
-
* The state of the animation to apply when the animation is resolved. This
|
|
7860
|
-
* allows calls to the public API to control the animation before it is resolved,
|
|
7861
|
-
* without us having to resolve it first.
|
|
7034
|
+
* The time at which the animation was paused.
|
|
7862
7035
|
*/
|
|
7863
|
-
this.
|
|
7036
|
+
this.holdTime = null;
|
|
7864
7037
|
/**
|
|
7865
|
-
*
|
|
7038
|
+
* Playback speed as a factor. 0 would be stopped, -1 reverse and 2 double speed.
|
|
7866
7039
|
*/
|
|
7867
|
-
this.
|
|
7868
|
-
this.state = "idle";
|
|
7040
|
+
this.playbackSpeed = 1;
|
|
7869
7041
|
/**
|
|
7870
7042
|
* This method is bound to the instance to fix a pattern where
|
|
7871
7043
|
* animation.stop is returned as a reference from a useEffect.
|
|
7872
7044
|
*/
|
|
7873
7045
|
this.stop = () => {
|
|
7874
|
-
this.
|
|
7046
|
+
const { motionValue } = this.options;
|
|
7047
|
+
if (motionValue && motionValue.updatedAt !== time.now()) {
|
|
7048
|
+
this.tick(time.now());
|
|
7049
|
+
}
|
|
7875
7050
|
this.isStopped = true;
|
|
7876
7051
|
if (this.state === "idle")
|
|
7877
7052
|
return;
|
|
@@ -7879,49 +7054,35 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
7879
7054
|
const { onStop } = this.options;
|
|
7880
7055
|
onStop && onStop();
|
|
7881
7056
|
};
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
}
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7891
|
-
|
|
7892
|
-
|
|
7893
|
-
|
|
7894
|
-
}
|
|
7895
|
-
initPlayback(keyframes$1) {
|
|
7896
|
-
const { type = "keyframes", repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = this.options;
|
|
7897
|
-
const generatorFactory = isGenerator(type)
|
|
7898
|
-
? type
|
|
7899
|
-
: generators[type] || keyframes;
|
|
7900
|
-
/**
|
|
7901
|
-
* If our generator doesn't support mixing numbers, we need to replace keyframes with
|
|
7902
|
-
* [0, 100] and then make a function that maps that to the actual keyframes.
|
|
7903
|
-
*
|
|
7904
|
-
* 100 is chosen instead of 1 as it works nicer with spring animations.
|
|
7905
|
-
*/
|
|
7906
|
-
let mapPercentToKeyframes;
|
|
7907
|
-
let mirroredGenerator;
|
|
7057
|
+
this.options = options;
|
|
7058
|
+
this.initAnimation();
|
|
7059
|
+
this.play();
|
|
7060
|
+
if (options.autoplay === false)
|
|
7061
|
+
this.pause();
|
|
7062
|
+
}
|
|
7063
|
+
initAnimation() {
|
|
7064
|
+
const { options } = this;
|
|
7065
|
+
replaceTransitionType(options);
|
|
7066
|
+
const { type = keyframes, repeat = 0, repeatDelay = 0, repeatType, velocity = 0, } = options;
|
|
7067
|
+
let { keyframes: keyframes$1 } = options;
|
|
7068
|
+
const generatorFactory = type || keyframes;
|
|
7908
7069
|
if (process.env.NODE_ENV !== "production" &&
|
|
7909
7070
|
generatorFactory !== keyframes) {
|
|
7910
7071
|
invariant(keyframes$1.length <= 2, `Only two keyframes currently supported with spring and inertia animations. Trying to animate ${keyframes$1}`);
|
|
7911
7072
|
}
|
|
7912
7073
|
if (generatorFactory !== keyframes &&
|
|
7913
7074
|
typeof keyframes$1[0] !== "number") {
|
|
7914
|
-
|
|
7075
|
+
this.mixKeyframes = pipe(percentToProgress, mix(keyframes$1[0], keyframes$1[1]));
|
|
7915
7076
|
keyframes$1 = [0, 100];
|
|
7916
7077
|
}
|
|
7917
|
-
const generator = generatorFactory({ ...
|
|
7078
|
+
const generator = generatorFactory({ ...options, keyframes: keyframes$1 });
|
|
7918
7079
|
/**
|
|
7919
7080
|
* If we have a mirror repeat type we need to create a second generator that outputs the
|
|
7920
7081
|
* mirrored (not reversed) animation and later ping pong between the two generators.
|
|
7921
7082
|
*/
|
|
7922
7083
|
if (repeatType === "mirror") {
|
|
7923
|
-
mirroredGenerator = generatorFactory({
|
|
7924
|
-
...
|
|
7084
|
+
this.mirroredGenerator = generatorFactory({
|
|
7085
|
+
...options,
|
|
7925
7086
|
keyframes: [...keyframes$1].reverse(),
|
|
7926
7087
|
velocity: -velocity,
|
|
7927
7088
|
});
|
|
@@ -7938,38 +7099,29 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
7938
7099
|
generator.calculatedDuration = calcGeneratorDuration(generator);
|
|
7939
7100
|
}
|
|
7940
7101
|
const { calculatedDuration } = generator;
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7944
|
-
|
|
7945
|
-
mirroredGenerator,
|
|
7946
|
-
mapPercentToKeyframes,
|
|
7947
|
-
calculatedDuration,
|
|
7948
|
-
resolvedDuration,
|
|
7949
|
-
totalDuration,
|
|
7950
|
-
};
|
|
7102
|
+
this.calculatedDuration = calculatedDuration;
|
|
7103
|
+
this.resolvedDuration = calculatedDuration + repeatDelay;
|
|
7104
|
+
this.totalDuration = this.resolvedDuration * (repeat + 1) - repeatDelay;
|
|
7105
|
+
this.generator = generator;
|
|
7951
7106
|
}
|
|
7952
|
-
|
|
7953
|
-
const
|
|
7954
|
-
|
|
7955
|
-
if (this.
|
|
7956
|
-
this.
|
|
7107
|
+
updateTime(timestamp) {
|
|
7108
|
+
const animationTime = Math.round(timestamp - this.startTime) * this.playbackSpeed;
|
|
7109
|
+
// Update currentTime
|
|
7110
|
+
if (this.holdTime !== null) {
|
|
7111
|
+
this.currentTime = this.holdTime;
|
|
7957
7112
|
}
|
|
7958
7113
|
else {
|
|
7959
|
-
|
|
7114
|
+
// Rounding the time because floating point arithmetic is not always accurate, e.g. 3000.367 - 1000.367 =
|
|
7115
|
+
// 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for
|
|
7116
|
+
// example.
|
|
7117
|
+
this.currentTime = animationTime;
|
|
7960
7118
|
}
|
|
7961
7119
|
}
|
|
7962
7120
|
tick(timestamp, sample = false) {
|
|
7963
|
-
const {
|
|
7964
|
-
// If the animations has failed to resolve, return the final keyframe.
|
|
7965
|
-
if (!resolved) {
|
|
7966
|
-
const { keyframes } = this.options;
|
|
7967
|
-
return { done: true, value: keyframes[keyframes.length - 1] };
|
|
7968
|
-
}
|
|
7969
|
-
const { finalKeyframe, generator, mirroredGenerator, mapPercentToKeyframes, keyframes, calculatedDuration, totalDuration, resolvedDuration, } = resolved;
|
|
7121
|
+
const { generator, totalDuration, mixKeyframes, mirroredGenerator, resolvedDuration, calculatedDuration, } = this;
|
|
7970
7122
|
if (this.startTime === null)
|
|
7971
7123
|
return generator.next(0);
|
|
7972
|
-
const { delay, repeat, repeatType, repeatDelay, onUpdate } = this.options;
|
|
7124
|
+
const { delay = 0, keyframes, repeat, repeatType, repeatDelay, type, onUpdate, finalKeyframe, } = this.options;
|
|
7973
7125
|
/**
|
|
7974
7126
|
* requestAnimationFrame timestamps can come through as lower than
|
|
7975
7127
|
* the startTime as set by performance.now(). Here we prevent this,
|
|
@@ -7982,23 +7134,15 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
7982
7134
|
else if (this.speed < 0) {
|
|
7983
7135
|
this.startTime = Math.min(timestamp - totalDuration / this.speed, this.startTime);
|
|
7984
7136
|
}
|
|
7985
|
-
// Update currentTime
|
|
7986
7137
|
if (sample) {
|
|
7987
7138
|
this.currentTime = timestamp;
|
|
7988
7139
|
}
|
|
7989
|
-
else if (this.holdTime !== null) {
|
|
7990
|
-
this.currentTime = this.holdTime;
|
|
7991
|
-
}
|
|
7992
7140
|
else {
|
|
7993
|
-
|
|
7994
|
-
// 2000.0000000000002. This is a problem when we are comparing the currentTime with the duration, for
|
|
7995
|
-
// example.
|
|
7996
|
-
this.currentTime =
|
|
7997
|
-
Math.round(timestamp - this.startTime) * this.speed;
|
|
7141
|
+
this.updateTime(timestamp);
|
|
7998
7142
|
}
|
|
7999
7143
|
// Rebase on delay
|
|
8000
|
-
const timeWithoutDelay = this.currentTime - delay * (this.
|
|
8001
|
-
const isInDelayPhase = this.
|
|
7144
|
+
const timeWithoutDelay = this.currentTime - delay * (this.playbackSpeed >= 0 ? 1 : -1);
|
|
7145
|
+
const isInDelayPhase = this.playbackSpeed >= 0
|
|
8002
7146
|
? timeWithoutDelay < 0
|
|
8003
7147
|
: timeWithoutDelay > totalDuration;
|
|
8004
7148
|
this.currentTime = Math.max(timeWithoutDelay, 0);
|
|
@@ -8059,20 +7203,21 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8059
7203
|
const state = isInDelayPhase
|
|
8060
7204
|
? { done: false, value: keyframes[0] }
|
|
8061
7205
|
: frameGenerator.next(elapsed);
|
|
8062
|
-
if (
|
|
8063
|
-
state.value =
|
|
7206
|
+
if (mixKeyframes) {
|
|
7207
|
+
state.value = mixKeyframes(state.value);
|
|
8064
7208
|
}
|
|
8065
7209
|
let { done } = state;
|
|
8066
7210
|
if (!isInDelayPhase && calculatedDuration !== null) {
|
|
8067
7211
|
done =
|
|
8068
|
-
this.
|
|
7212
|
+
this.playbackSpeed >= 0
|
|
8069
7213
|
? this.currentTime >= totalDuration
|
|
8070
7214
|
: this.currentTime <= 0;
|
|
8071
7215
|
}
|
|
8072
7216
|
const isAnimationFinished = this.holdTime === null &&
|
|
8073
7217
|
(this.state === "finished" || (this.state === "running" && done));
|
|
8074
|
-
|
|
8075
|
-
|
|
7218
|
+
// TODO: The exception for inertia could be cleaner here
|
|
7219
|
+
if (isAnimationFinished && type !== inertia) {
|
|
7220
|
+
state.value = getFinalKeyframe(keyframes, this.options, finalKeyframe, this.speed);
|
|
8076
7221
|
}
|
|
8077
7222
|
if (onUpdate) {
|
|
8078
7223
|
onUpdate(state.value);
|
|
@@ -8082,9 +7227,16 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8082
7227
|
}
|
|
8083
7228
|
return state;
|
|
8084
7229
|
}
|
|
7230
|
+
/**
|
|
7231
|
+
* Allows the returned animation to be awaited or promise-chained. Currently
|
|
7232
|
+
* resolves when the animation finishes at all but in a future update could/should
|
|
7233
|
+
* reject if its cancels.
|
|
7234
|
+
*/
|
|
7235
|
+
then(resolve, reject) {
|
|
7236
|
+
return this.finished.then(resolve, reject);
|
|
7237
|
+
}
|
|
8085
7238
|
get duration() {
|
|
8086
|
-
|
|
8087
|
-
return resolved ? millisecondsToSeconds(resolved.calculatedDuration) : 0;
|
|
7239
|
+
return millisecondsToSeconds(this.calculatedDuration);
|
|
8088
7240
|
}
|
|
8089
7241
|
get time() {
|
|
8090
7242
|
return millisecondsToSeconds(this.currentTime);
|
|
@@ -8092,125 +7244,417 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
8092
7244
|
set time(newTime) {
|
|
8093
7245
|
newTime = secondsToMilliseconds(newTime);
|
|
8094
7246
|
this.currentTime = newTime;
|
|
8095
|
-
if (this.
|
|
7247
|
+
if (this.startTime === null ||
|
|
7248
|
+
this.holdTime !== null ||
|
|
7249
|
+
this.playbackSpeed === 0) {
|
|
8096
7250
|
this.holdTime = newTime;
|
|
8097
7251
|
}
|
|
8098
7252
|
else if (this.driver) {
|
|
8099
|
-
this.startTime = this.driver.now() - newTime / this.
|
|
7253
|
+
this.startTime = this.driver.now() - newTime / this.playbackSpeed;
|
|
7254
|
+
}
|
|
7255
|
+
}
|
|
7256
|
+
get speed() {
|
|
7257
|
+
return this.playbackSpeed;
|
|
7258
|
+
}
|
|
7259
|
+
set speed(newSpeed) {
|
|
7260
|
+
this.updateTime(time.now());
|
|
7261
|
+
const hasChanged = this.playbackSpeed !== newSpeed;
|
|
7262
|
+
this.playbackSpeed = newSpeed;
|
|
7263
|
+
if (hasChanged) {
|
|
7264
|
+
this.time = millisecondsToSeconds(this.currentTime);
|
|
8100
7265
|
}
|
|
8101
7266
|
}
|
|
8102
|
-
|
|
8103
|
-
|
|
7267
|
+
play() {
|
|
7268
|
+
if (this.isStopped)
|
|
7269
|
+
return;
|
|
7270
|
+
const { driver = frameloopDriver, onPlay, startTime } = this.options;
|
|
7271
|
+
if (!this.driver) {
|
|
7272
|
+
this.driver = driver((timestamp) => this.tick(timestamp));
|
|
7273
|
+
}
|
|
7274
|
+
onPlay && onPlay();
|
|
7275
|
+
const now = this.driver.now();
|
|
7276
|
+
if (this.holdTime !== null) {
|
|
7277
|
+
this.startTime = now - this.holdTime;
|
|
7278
|
+
}
|
|
7279
|
+
else if (this.state === "finished") {
|
|
7280
|
+
this.updateFinished();
|
|
7281
|
+
this.startTime = now;
|
|
7282
|
+
}
|
|
7283
|
+
else if (!this.startTime) {
|
|
7284
|
+
this.startTime = startTime ?? now;
|
|
7285
|
+
}
|
|
7286
|
+
if (this.state === "finished" && this.speed < 0) {
|
|
7287
|
+
this.startTime += this.calculatedDuration;
|
|
7288
|
+
}
|
|
7289
|
+
this.holdTime = null;
|
|
7290
|
+
/**
|
|
7291
|
+
* Set playState to running only after we've used it in
|
|
7292
|
+
* the previous logic.
|
|
7293
|
+
*/
|
|
7294
|
+
this.state = "running";
|
|
7295
|
+
this.driver.start();
|
|
7296
|
+
}
|
|
7297
|
+
pause() {
|
|
7298
|
+
this.state = "paused";
|
|
7299
|
+
this.updateTime(time.now());
|
|
7300
|
+
this.holdTime = this.currentTime;
|
|
7301
|
+
}
|
|
7302
|
+
complete() {
|
|
7303
|
+
if (this.state !== "running") {
|
|
7304
|
+
this.play();
|
|
7305
|
+
}
|
|
7306
|
+
this.state = "finished";
|
|
7307
|
+
this.holdTime = null;
|
|
7308
|
+
}
|
|
7309
|
+
finish() {
|
|
7310
|
+
this.teardown();
|
|
7311
|
+
this.state = "finished";
|
|
7312
|
+
const { onComplete } = this.options;
|
|
7313
|
+
onComplete && onComplete();
|
|
7314
|
+
}
|
|
7315
|
+
cancel() {
|
|
7316
|
+
this.holdTime = null;
|
|
7317
|
+
this.startTime = 0;
|
|
7318
|
+
this.tick(0);
|
|
7319
|
+
this.teardown();
|
|
7320
|
+
}
|
|
7321
|
+
teardown() {
|
|
7322
|
+
this.notifyFinished();
|
|
7323
|
+
this.state = "idle";
|
|
7324
|
+
this.stopDriver();
|
|
7325
|
+
this.startTime = this.holdTime = null;
|
|
7326
|
+
}
|
|
7327
|
+
stopDriver() {
|
|
7328
|
+
if (!this.driver)
|
|
7329
|
+
return;
|
|
7330
|
+
this.driver.stop();
|
|
7331
|
+
this.driver = undefined;
|
|
7332
|
+
}
|
|
7333
|
+
sample(sampleTime) {
|
|
7334
|
+
this.startTime = 0;
|
|
7335
|
+
return this.tick(sampleTime, true);
|
|
7336
|
+
}
|
|
7337
|
+
attachTimeline(timeline) {
|
|
7338
|
+
if (this.options.allowFlatten) {
|
|
7339
|
+
this.options.type = "keyframes";
|
|
7340
|
+
this.options.ease = "linear";
|
|
7341
|
+
this.initAnimation();
|
|
7342
|
+
}
|
|
7343
|
+
return timeline.observe(this);
|
|
7344
|
+
}
|
|
7345
|
+
}
|
|
7346
|
+
|
|
7347
|
+
function fillWildcards(keyframes) {
|
|
7348
|
+
for (let i = 1; i < keyframes.length; i++) {
|
|
7349
|
+
keyframes[i] ?? (keyframes[i] = keyframes[i - 1]);
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
|
|
7353
|
+
const radToDeg = (rad) => (rad * 180) / Math.PI;
|
|
7354
|
+
const rotate = (v) => {
|
|
7355
|
+
const angle = radToDeg(Math.atan2(v[1], v[0]));
|
|
7356
|
+
return rebaseAngle(angle);
|
|
7357
|
+
};
|
|
7358
|
+
const matrix2dParsers = {
|
|
7359
|
+
x: 4,
|
|
7360
|
+
y: 5,
|
|
7361
|
+
translateX: 4,
|
|
7362
|
+
translateY: 5,
|
|
7363
|
+
scaleX: 0,
|
|
7364
|
+
scaleY: 3,
|
|
7365
|
+
scale: (v) => (Math.abs(v[0]) + Math.abs(v[3])) / 2,
|
|
7366
|
+
rotate,
|
|
7367
|
+
rotateZ: rotate,
|
|
7368
|
+
skewX: (v) => radToDeg(Math.atan(v[1])),
|
|
7369
|
+
skewY: (v) => radToDeg(Math.atan(v[2])),
|
|
7370
|
+
skew: (v) => (Math.abs(v[1]) + Math.abs(v[2])) / 2,
|
|
7371
|
+
};
|
|
7372
|
+
const rebaseAngle = (angle) => {
|
|
7373
|
+
angle = angle % 360;
|
|
7374
|
+
if (angle < 0)
|
|
7375
|
+
angle += 360;
|
|
7376
|
+
return angle;
|
|
7377
|
+
};
|
|
7378
|
+
const rotateZ = rotate;
|
|
7379
|
+
const scaleX = (v) => Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
|
7380
|
+
const scaleY = (v) => Math.sqrt(v[4] * v[4] + v[5] * v[5]);
|
|
7381
|
+
const matrix3dParsers = {
|
|
7382
|
+
x: 12,
|
|
7383
|
+
y: 13,
|
|
7384
|
+
z: 14,
|
|
7385
|
+
translateX: 12,
|
|
7386
|
+
translateY: 13,
|
|
7387
|
+
translateZ: 14,
|
|
7388
|
+
scaleX,
|
|
7389
|
+
scaleY,
|
|
7390
|
+
scale: (v) => (scaleX(v) + scaleY(v)) / 2,
|
|
7391
|
+
rotateX: (v) => rebaseAngle(radToDeg(Math.atan2(v[6], v[5]))),
|
|
7392
|
+
rotateY: (v) => rebaseAngle(radToDeg(Math.atan2(-v[2], v[0]))),
|
|
7393
|
+
rotateZ,
|
|
7394
|
+
rotate: rotateZ,
|
|
7395
|
+
skewX: (v) => radToDeg(Math.atan(v[4])),
|
|
7396
|
+
skewY: (v) => radToDeg(Math.atan(v[1])),
|
|
7397
|
+
skew: (v) => (Math.abs(v[1]) + Math.abs(v[4])) / 2,
|
|
7398
|
+
};
|
|
7399
|
+
function defaultTransformValue(name) {
|
|
7400
|
+
return name.includes("scale") ? 1 : 0;
|
|
7401
|
+
}
|
|
7402
|
+
function parseValueFromTransform(transform, name) {
|
|
7403
|
+
if (!transform || transform === "none") {
|
|
7404
|
+
return defaultTransformValue(name);
|
|
7405
|
+
}
|
|
7406
|
+
const matrix3dMatch = transform.match(/^matrix3d\(([-\d.e\s,]+)\)$/u);
|
|
7407
|
+
let parsers;
|
|
7408
|
+
let match;
|
|
7409
|
+
if (matrix3dMatch) {
|
|
7410
|
+
parsers = matrix3dParsers;
|
|
7411
|
+
match = matrix3dMatch;
|
|
7412
|
+
}
|
|
7413
|
+
else {
|
|
7414
|
+
const matrix2dMatch = transform.match(/^matrix\(([-\d.e\s,]+)\)$/u);
|
|
7415
|
+
parsers = matrix2dParsers;
|
|
7416
|
+
match = matrix2dMatch;
|
|
7417
|
+
}
|
|
7418
|
+
if (!match) {
|
|
7419
|
+
return defaultTransformValue(name);
|
|
8104
7420
|
}
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
7421
|
+
const valueParser = parsers[name];
|
|
7422
|
+
const values = match[1].split(",").map(convertTransformToNumber);
|
|
7423
|
+
return typeof valueParser === "function"
|
|
7424
|
+
? valueParser(values)
|
|
7425
|
+
: values[valueParser];
|
|
7426
|
+
}
|
|
7427
|
+
const readTransformValue = (instance, name) => {
|
|
7428
|
+
const { transform = "none" } = getComputedStyle(instance);
|
|
7429
|
+
return parseValueFromTransform(transform, name);
|
|
7430
|
+
};
|
|
7431
|
+
function convertTransformToNumber(value) {
|
|
7432
|
+
return parseFloat(value.trim());
|
|
7433
|
+
}
|
|
7434
|
+
|
|
7435
|
+
const isNumOrPxType = (v) => v === number || v === px;
|
|
7436
|
+
const transformKeys = new Set(["x", "y", "z"]);
|
|
7437
|
+
const nonTranslationalTransformKeys = transformPropOrder.filter((key) => !transformKeys.has(key));
|
|
7438
|
+
function removeNonTranslationalTransform(visualElement) {
|
|
7439
|
+
const removedTransforms = [];
|
|
7440
|
+
nonTranslationalTransformKeys.forEach((key) => {
|
|
7441
|
+
const value = visualElement.getValue(key);
|
|
7442
|
+
if (value !== undefined) {
|
|
7443
|
+
removedTransforms.push([key, value.get()]);
|
|
7444
|
+
value.set(key.startsWith("scale") ? 1 : 0);
|
|
8110
7445
|
}
|
|
7446
|
+
});
|
|
7447
|
+
return removedTransforms;
|
|
7448
|
+
}
|
|
7449
|
+
const positionalValues = {
|
|
7450
|
+
// Dimensions
|
|
7451
|
+
width: ({ x }, { paddingLeft = "0", paddingRight = "0" }) => x.max - x.min - parseFloat(paddingLeft) - parseFloat(paddingRight),
|
|
7452
|
+
height: ({ y }, { paddingTop = "0", paddingBottom = "0" }) => y.max - y.min - parseFloat(paddingTop) - parseFloat(paddingBottom),
|
|
7453
|
+
top: (_bbox, { top }) => parseFloat(top),
|
|
7454
|
+
left: (_bbox, { left }) => parseFloat(left),
|
|
7455
|
+
bottom: ({ y }, { top }) => parseFloat(top) + (y.max - y.min),
|
|
7456
|
+
right: ({ x }, { left }) => parseFloat(left) + (x.max - x.min),
|
|
7457
|
+
// Transform
|
|
7458
|
+
x: (_bbox, { transform }) => parseValueFromTransform(transform, "x"),
|
|
7459
|
+
y: (_bbox, { transform }) => parseValueFromTransform(transform, "y"),
|
|
7460
|
+
};
|
|
7461
|
+
// Alias translate longform names
|
|
7462
|
+
positionalValues.translateX = positionalValues.x;
|
|
7463
|
+
positionalValues.translateY = positionalValues.y;
|
|
7464
|
+
|
|
7465
|
+
const toResolve = new Set();
|
|
7466
|
+
let isScheduled = false;
|
|
7467
|
+
let anyNeedsMeasurement = false;
|
|
7468
|
+
let isForced = false;
|
|
7469
|
+
function measureAllKeyframes() {
|
|
7470
|
+
if (anyNeedsMeasurement) {
|
|
7471
|
+
const resolversToMeasure = Array.from(toResolve).filter((resolver) => resolver.needsMeasurement);
|
|
7472
|
+
const elementsToMeasure = new Set(resolversToMeasure.map((resolver) => resolver.element));
|
|
7473
|
+
const transformsToRestore = new Map();
|
|
7474
|
+
/**
|
|
7475
|
+
* Write pass
|
|
7476
|
+
* If we're measuring elements we want to remove bounding box-changing transforms.
|
|
7477
|
+
*/
|
|
7478
|
+
elementsToMeasure.forEach((element) => {
|
|
7479
|
+
const removedTransforms = removeNonTranslationalTransform(element);
|
|
7480
|
+
if (!removedTransforms.length)
|
|
7481
|
+
return;
|
|
7482
|
+
transformsToRestore.set(element, removedTransforms);
|
|
7483
|
+
element.render();
|
|
7484
|
+
});
|
|
7485
|
+
// Read
|
|
7486
|
+
resolversToMeasure.forEach((resolver) => resolver.measureInitialState());
|
|
7487
|
+
// Write
|
|
7488
|
+
elementsToMeasure.forEach((element) => {
|
|
7489
|
+
element.render();
|
|
7490
|
+
const restore = transformsToRestore.get(element);
|
|
7491
|
+
if (restore) {
|
|
7492
|
+
restore.forEach(([key, value]) => {
|
|
7493
|
+
element.getValue(key)?.set(value);
|
|
7494
|
+
});
|
|
7495
|
+
}
|
|
7496
|
+
});
|
|
7497
|
+
// Read
|
|
7498
|
+
resolversToMeasure.forEach((resolver) => resolver.measureEndState());
|
|
7499
|
+
// Write
|
|
7500
|
+
resolversToMeasure.forEach((resolver) => {
|
|
7501
|
+
if (resolver.suspendedScrollY !== undefined) {
|
|
7502
|
+
window.scrollTo(0, resolver.suspendedScrollY);
|
|
7503
|
+
}
|
|
7504
|
+
});
|
|
8111
7505
|
}
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
if (
|
|
8121
|
-
|
|
8122
|
-
const { driver = frameloopDriver, onPlay, startTime } = this.options;
|
|
8123
|
-
if (!this.driver) {
|
|
8124
|
-
this.driver = driver((timestamp) => this.tick(timestamp));
|
|
8125
|
-
}
|
|
8126
|
-
onPlay && onPlay();
|
|
8127
|
-
const now = this.driver.now();
|
|
8128
|
-
if (this.holdTime !== null) {
|
|
8129
|
-
this.startTime = now - this.holdTime;
|
|
8130
|
-
}
|
|
8131
|
-
else if (!this.startTime) {
|
|
8132
|
-
this.startTime = startTime ?? this.calcStartTime();
|
|
8133
|
-
}
|
|
8134
|
-
else if (this.state === "finished") {
|
|
8135
|
-
this.startTime = now;
|
|
8136
|
-
}
|
|
8137
|
-
if (this.state === "finished") {
|
|
8138
|
-
this.updateFinishedPromise();
|
|
7506
|
+
anyNeedsMeasurement = false;
|
|
7507
|
+
isScheduled = false;
|
|
7508
|
+
toResolve.forEach((resolver) => resolver.complete(isForced));
|
|
7509
|
+
toResolve.clear();
|
|
7510
|
+
}
|
|
7511
|
+
function readAllKeyframes() {
|
|
7512
|
+
toResolve.forEach((resolver) => {
|
|
7513
|
+
resolver.readKeyframes();
|
|
7514
|
+
if (resolver.needsMeasurement) {
|
|
7515
|
+
anyNeedsMeasurement = true;
|
|
8139
7516
|
}
|
|
8140
|
-
|
|
8141
|
-
|
|
7517
|
+
});
|
|
7518
|
+
}
|
|
7519
|
+
function flushKeyframeResolvers() {
|
|
7520
|
+
isForced = true;
|
|
7521
|
+
readAllKeyframes();
|
|
7522
|
+
measureAllKeyframes();
|
|
7523
|
+
isForced = false;
|
|
7524
|
+
}
|
|
7525
|
+
class KeyframeResolver {
|
|
7526
|
+
constructor(unresolvedKeyframes, onComplete, name, motionValue, element, isAsync = false) {
|
|
8142
7527
|
/**
|
|
8143
|
-
*
|
|
8144
|
-
*
|
|
7528
|
+
* Track whether this resolver has completed. Once complete, it never
|
|
7529
|
+
* needs to attempt keyframe resolution again.
|
|
8145
7530
|
*/
|
|
8146
|
-
this.
|
|
8147
|
-
|
|
7531
|
+
this.isComplete = false;
|
|
7532
|
+
/**
|
|
7533
|
+
* Track whether this resolver is async. If it is, it'll be added to the
|
|
7534
|
+
* resolver queue and flushed in the next frame. Resolvers that aren't going
|
|
7535
|
+
* to trigger read/write thrashing don't need to be async.
|
|
7536
|
+
*/
|
|
7537
|
+
this.isAsync = false;
|
|
7538
|
+
/**
|
|
7539
|
+
* Track whether this resolver needs to perform a measurement
|
|
7540
|
+
* to resolve its keyframes.
|
|
7541
|
+
*/
|
|
7542
|
+
this.needsMeasurement = false;
|
|
7543
|
+
/**
|
|
7544
|
+
* Track whether this resolver is currently scheduled to resolve
|
|
7545
|
+
* to allow it to be cancelled and resumed externally.
|
|
7546
|
+
*/
|
|
7547
|
+
this.isScheduled = false;
|
|
7548
|
+
this.unresolvedKeyframes = [...unresolvedKeyframes];
|
|
7549
|
+
this.onComplete = onComplete;
|
|
7550
|
+
this.name = name;
|
|
7551
|
+
this.motionValue = motionValue;
|
|
7552
|
+
this.element = element;
|
|
7553
|
+
this.isAsync = isAsync;
|
|
8148
7554
|
}
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
7555
|
+
scheduleResolve() {
|
|
7556
|
+
this.isScheduled = true;
|
|
7557
|
+
if (this.isAsync) {
|
|
7558
|
+
toResolve.add(this);
|
|
7559
|
+
if (!isScheduled) {
|
|
7560
|
+
isScheduled = true;
|
|
7561
|
+
frame.read(readAllKeyframes);
|
|
7562
|
+
frame.resolveKeyframes(measureAllKeyframes);
|
|
7563
|
+
}
|
|
7564
|
+
}
|
|
7565
|
+
else {
|
|
7566
|
+
this.readKeyframes();
|
|
7567
|
+
this.complete();
|
|
8153
7568
|
}
|
|
8154
|
-
this.state = "paused";
|
|
8155
|
-
this.holdTime = this.currentTime ?? 0;
|
|
8156
7569
|
}
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
7570
|
+
readKeyframes() {
|
|
7571
|
+
const { unresolvedKeyframes, name, element, motionValue } = this;
|
|
7572
|
+
// If initial keyframe is null we need to read it from the DOM
|
|
7573
|
+
if (unresolvedKeyframes[0] === null) {
|
|
7574
|
+
const currentValue = motionValue?.get();
|
|
7575
|
+
// TODO: This doesn't work if the final keyframe is a wildcard
|
|
7576
|
+
const finalKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
7577
|
+
if (currentValue !== undefined) {
|
|
7578
|
+
unresolvedKeyframes[0] = currentValue;
|
|
7579
|
+
}
|
|
7580
|
+
else if (element && name) {
|
|
7581
|
+
const valueAsRead = element.readValue(name, finalKeyframe);
|
|
7582
|
+
if (valueAsRead !== undefined && valueAsRead !== null) {
|
|
7583
|
+
unresolvedKeyframes[0] = valueAsRead;
|
|
7584
|
+
}
|
|
7585
|
+
}
|
|
7586
|
+
if (unresolvedKeyframes[0] === undefined) {
|
|
7587
|
+
unresolvedKeyframes[0] = finalKeyframe;
|
|
7588
|
+
}
|
|
7589
|
+
if (motionValue && currentValue === undefined) {
|
|
7590
|
+
motionValue.set(unresolvedKeyframes[0]);
|
|
7591
|
+
}
|
|
8160
7592
|
}
|
|
8161
|
-
|
|
8162
|
-
this.holdTime = null;
|
|
7593
|
+
fillWildcards(unresolvedKeyframes);
|
|
8163
7594
|
}
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
7595
|
+
setFinalKeyframe() { }
|
|
7596
|
+
measureInitialState() { }
|
|
7597
|
+
renderEndStyles() { }
|
|
7598
|
+
measureEndState() { }
|
|
7599
|
+
complete(isForced = false) {
|
|
7600
|
+
this.isComplete = true;
|
|
7601
|
+
this.onComplete(this.unresolvedKeyframes, this.finalKeyframe, isForced);
|
|
7602
|
+
toResolve.delete(this);
|
|
8169
7603
|
}
|
|
8170
7604
|
cancel() {
|
|
8171
|
-
if (this.
|
|
8172
|
-
this.
|
|
7605
|
+
if (!this.isComplete) {
|
|
7606
|
+
this.isScheduled = false;
|
|
7607
|
+
toResolve.delete(this);
|
|
8173
7608
|
}
|
|
8174
|
-
this.teardown();
|
|
8175
|
-
this.updateFinishedPromise();
|
|
8176
|
-
}
|
|
8177
|
-
teardown() {
|
|
8178
|
-
this.state = "idle";
|
|
8179
|
-
this.stopDriver();
|
|
8180
|
-
this.resolveFinishedPromise();
|
|
8181
|
-
this.updateFinishedPromise();
|
|
8182
|
-
this.startTime = this.cancelTime = null;
|
|
8183
|
-
this.resolver.cancel();
|
|
8184
7609
|
}
|
|
8185
|
-
|
|
8186
|
-
if (!this.
|
|
8187
|
-
|
|
8188
|
-
this.driver.stop();
|
|
8189
|
-
this.driver = undefined;
|
|
8190
|
-
}
|
|
8191
|
-
sample(time) {
|
|
8192
|
-
this.startTime = 0;
|
|
8193
|
-
return this.tick(time, true);
|
|
8194
|
-
}
|
|
8195
|
-
get finished() {
|
|
8196
|
-
return this.currentFinishedPromise;
|
|
7610
|
+
resume() {
|
|
7611
|
+
if (!this.isComplete)
|
|
7612
|
+
this.scheduleResolve();
|
|
8197
7613
|
}
|
|
8198
7614
|
}
|
|
8199
7615
|
|
|
7616
|
+
const isCSSVar = (name) => name.startsWith("--");
|
|
7617
|
+
|
|
7618
|
+
function setStyle(element, name, value) {
|
|
7619
|
+
isCSSVar(name)
|
|
7620
|
+
? element.style.setProperty(name, value)
|
|
7621
|
+
: (element.style[name] = value);
|
|
7622
|
+
}
|
|
7623
|
+
|
|
7624
|
+
/*#__NO_SIDE_EFFECTS__*/
|
|
7625
|
+
function memo(callback) {
|
|
7626
|
+
let result;
|
|
7627
|
+
return () => {
|
|
7628
|
+
if (result === undefined)
|
|
7629
|
+
result = callback();
|
|
7630
|
+
return result;
|
|
7631
|
+
};
|
|
7632
|
+
}
|
|
7633
|
+
|
|
7634
|
+
const supportsScrollTimeline = /* @__PURE__ */ memo(() => window.ScrollTimeline !== undefined);
|
|
7635
|
+
|
|
8200
7636
|
/**
|
|
8201
|
-
*
|
|
7637
|
+
* Add the ability for test suites to manually set support flags
|
|
7638
|
+
* to better test more environments.
|
|
8202
7639
|
*/
|
|
8203
|
-
const
|
|
8204
|
-
"opacity",
|
|
8205
|
-
"clipPath",
|
|
8206
|
-
"filter",
|
|
8207
|
-
"transform",
|
|
8208
|
-
// TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
|
|
8209
|
-
// or until we implement support for linear() easing.
|
|
8210
|
-
// "background-color"
|
|
8211
|
-
]);
|
|
7640
|
+
const supportsFlags = {};
|
|
8212
7641
|
|
|
8213
|
-
|
|
7642
|
+
function memoSupports(callback, supportsFlag) {
|
|
7643
|
+
const memoized = memo(callback);
|
|
7644
|
+
return () => supportsFlags[supportsFlag] ?? memoized();
|
|
7645
|
+
}
|
|
7646
|
+
|
|
7647
|
+
const supportsLinearEasing = /*@__PURE__*/ memoSupports(() => {
|
|
7648
|
+
try {
|
|
7649
|
+
document
|
|
7650
|
+
.createElement("div")
|
|
7651
|
+
.animate({ opacity: 0 }, { easing: "linear(0, 1)" });
|
|
7652
|
+
}
|
|
7653
|
+
catch (e) {
|
|
7654
|
+
return false;
|
|
7655
|
+
}
|
|
7656
|
+
return true;
|
|
7657
|
+
}, "linearEasing");
|
|
8214
7658
|
|
|
8215
7659
|
const cubicBezierAsString = ([a, b, c, d]) => `cubic-bezier(${a}, ${b}, ${c}, ${d})`;
|
|
8216
7660
|
|
|
@@ -8230,8 +7674,10 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
8230
7674
|
if (!easing) {
|
|
8231
7675
|
return undefined;
|
|
8232
7676
|
}
|
|
8233
|
-
else if (typeof easing === "function"
|
|
8234
|
-
return
|
|
7677
|
+
else if (typeof easing === "function") {
|
|
7678
|
+
return supportsLinearEasing()
|
|
7679
|
+
? generateLinearEasing(easing, duration)
|
|
7680
|
+
: "ease-out";
|
|
8235
7681
|
}
|
|
8236
7682
|
else if (isBezierDefinition(easing)) {
|
|
8237
7683
|
return cubicBezierAsString(easing);
|
|
@@ -8245,7 +7691,7 @@ function mapEasingToNativeEasing(easing, duration) {
|
|
|
8245
7691
|
}
|
|
8246
7692
|
}
|
|
8247
7693
|
|
|
8248
|
-
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "
|
|
7694
|
+
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeOut", times, } = {}, pseudoElement = undefined) {
|
|
8249
7695
|
const keyframeOptions = {
|
|
8250
7696
|
[valueName]: keyframes,
|
|
8251
7697
|
};
|
|
@@ -8257,473 +7703,517 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
8257
7703
|
*/
|
|
8258
7704
|
if (Array.isArray(easing))
|
|
8259
7705
|
keyframeOptions.easing = easing;
|
|
8260
|
-
const
|
|
7706
|
+
const options = {
|
|
8261
7707
|
delay,
|
|
8262
7708
|
duration,
|
|
8263
7709
|
easing: !Array.isArray(easing) ? easing : "linear",
|
|
8264
7710
|
fill: "both",
|
|
8265
7711
|
iterations: repeat + 1,
|
|
8266
7712
|
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
8267
|
-
|
|
8268
|
-
|
|
7713
|
+
};
|
|
7714
|
+
if (pseudoElement)
|
|
7715
|
+
options.pseudoElement = pseudoElement;
|
|
7716
|
+
const animation = element.animate(keyframeOptions, options);
|
|
8269
7717
|
return animation;
|
|
8270
7718
|
}
|
|
8271
7719
|
|
|
8272
|
-
function
|
|
8273
|
-
|
|
8274
|
-
animation.onfinish = null;
|
|
7720
|
+
function isGenerator(type) {
|
|
7721
|
+
return typeof type === "function" && "applyToOptions" in type;
|
|
8275
7722
|
}
|
|
8276
7723
|
|
|
8277
|
-
function
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
(
|
|
7724
|
+
function applyGeneratorOptions({ type, ...options }) {
|
|
7725
|
+
if (isGenerator(type) && supportsLinearEasing()) {
|
|
7726
|
+
return type.applyToOptions(options);
|
|
7727
|
+
}
|
|
7728
|
+
else {
|
|
7729
|
+
options.duration ?? (options.duration = 300);
|
|
7730
|
+
options.ease ?? (options.ease = "easeOut");
|
|
7731
|
+
}
|
|
7732
|
+
return options;
|
|
8284
7733
|
}
|
|
8285
7734
|
|
|
8286
7735
|
/**
|
|
8287
|
-
*
|
|
8288
|
-
* results (more than one keyframe per frame at 60fps) and
|
|
8289
|
-
* keyframe quantity.
|
|
8290
|
-
*/
|
|
8291
|
-
const sampleDelta = 10; //ms
|
|
8292
|
-
/**
|
|
8293
|
-
* Implement a practical max duration for keyframe generation
|
|
8294
|
-
* to prevent infinite loops
|
|
8295
|
-
*/
|
|
8296
|
-
const maxDuration = 20000;
|
|
8297
|
-
/**
|
|
8298
|
-
* Check if an animation can run natively via WAAPI or requires pregenerated keyframes.
|
|
8299
|
-
* WAAPI doesn't support spring or function easings so we run these as JS animation before
|
|
8300
|
-
* handing off.
|
|
7736
|
+
* NativeAnimation implements AnimationPlaybackControls for the browser's Web Animations API.
|
|
8301
7737
|
*/
|
|
8302
|
-
|
|
8303
|
-
return (isGenerator(options.type) ||
|
|
8304
|
-
options.type === "spring" ||
|
|
8305
|
-
!isWaapiSupportedEasing(options.ease));
|
|
8306
|
-
}
|
|
8307
|
-
function pregenerateKeyframes(keyframes, options) {
|
|
8308
|
-
/**
|
|
8309
|
-
* Create a main-thread animation to pregenerate keyframes.
|
|
8310
|
-
* We sample this at regular intervals to generate keyframes that we then
|
|
8311
|
-
* linearly interpolate between.
|
|
8312
|
-
*/
|
|
8313
|
-
const sampleAnimation = new MainThreadAnimation({
|
|
8314
|
-
...options,
|
|
8315
|
-
keyframes,
|
|
8316
|
-
repeat: 0,
|
|
8317
|
-
delay: 0,
|
|
8318
|
-
isGenerator: true,
|
|
8319
|
-
});
|
|
8320
|
-
let state = { done: false, value: keyframes[0] };
|
|
8321
|
-
const pregeneratedKeyframes = [];
|
|
8322
|
-
/**
|
|
8323
|
-
* Bail after 20 seconds of pre-generated keyframes as it's likely
|
|
8324
|
-
* we're heading for an infinite loop.
|
|
8325
|
-
*/
|
|
8326
|
-
let t = 0;
|
|
8327
|
-
while (!state.done && t < maxDuration) {
|
|
8328
|
-
state = sampleAnimation.sample(t);
|
|
8329
|
-
pregeneratedKeyframes.push(state.value);
|
|
8330
|
-
t += sampleDelta;
|
|
8331
|
-
}
|
|
8332
|
-
return {
|
|
8333
|
-
times: undefined,
|
|
8334
|
-
keyframes: pregeneratedKeyframes,
|
|
8335
|
-
duration: t - sampleDelta,
|
|
8336
|
-
ease: "linear",
|
|
8337
|
-
};
|
|
8338
|
-
}
|
|
8339
|
-
const unsupportedEasingFunctions = {
|
|
8340
|
-
anticipate,
|
|
8341
|
-
backInOut,
|
|
8342
|
-
circInOut,
|
|
8343
|
-
};
|
|
8344
|
-
function isUnsupportedEase(key) {
|
|
8345
|
-
return key in unsupportedEasingFunctions;
|
|
8346
|
-
}
|
|
8347
|
-
class AcceleratedAnimation extends BaseAnimation {
|
|
7738
|
+
class NativeAnimation extends WithPromise {
|
|
8348
7739
|
constructor(options) {
|
|
8349
|
-
super(
|
|
8350
|
-
|
|
8351
|
-
this.
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
7740
|
+
super();
|
|
7741
|
+
this.finishedTime = null;
|
|
7742
|
+
this.isStopped = false;
|
|
7743
|
+
if (!options)
|
|
7744
|
+
return;
|
|
7745
|
+
const { element, name, keyframes, pseudoElement, allowFlatten = false, finalKeyframe, onComplete, } = options;
|
|
7746
|
+
this.isPseudoElement = Boolean(pseudoElement);
|
|
7747
|
+
this.allowFlatten = allowFlatten;
|
|
7748
|
+
this.options = options;
|
|
7749
|
+
invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "motion"?`);
|
|
7750
|
+
const transition = applyGeneratorOptions(options);
|
|
7751
|
+
this.animation = startWaapiAnimation(element, name, keyframes, transition, pseudoElement);
|
|
7752
|
+
if (transition.autoplay === false) {
|
|
7753
|
+
this.animation.pause();
|
|
7754
|
+
}
|
|
7755
|
+
this.animation.onfinish = () => {
|
|
7756
|
+
this.finishedTime = this.time;
|
|
7757
|
+
if (!pseudoElement) {
|
|
7758
|
+
const keyframe = getFinalKeyframe(keyframes, this.options, finalKeyframe, this.speed);
|
|
7759
|
+
if (this.updateMotionValue) {
|
|
7760
|
+
this.updateMotionValue(keyframe);
|
|
7761
|
+
}
|
|
7762
|
+
else {
|
|
7763
|
+
/**
|
|
7764
|
+
* If we can, we want to commit the final style as set by the user,
|
|
7765
|
+
* rather than the computed keyframe value supplied by the animation.
|
|
7766
|
+
*/
|
|
7767
|
+
setStyle(element, name, keyframe);
|
|
7768
|
+
}
|
|
7769
|
+
this.animation.cancel();
|
|
7770
|
+
}
|
|
7771
|
+
onComplete?.();
|
|
7772
|
+
this.notifyFinished();
|
|
7773
|
+
};
|
|
8356
7774
|
/**
|
|
8357
|
-
*
|
|
8358
|
-
* the animation failed to initialised.
|
|
7775
|
+
* TODO: In a breaking change, we should replace this with `.notifyCancel()`
|
|
8359
7776
|
*/
|
|
8360
|
-
|
|
8361
|
-
|
|
7777
|
+
this.animation.oncancel = () => this.notifyFinished();
|
|
7778
|
+
}
|
|
7779
|
+
play() {
|
|
7780
|
+
if (this.isStopped)
|
|
7781
|
+
return;
|
|
7782
|
+
this.animation.play();
|
|
7783
|
+
if (this.state === "finished") {
|
|
7784
|
+
this.updateFinished();
|
|
8362
7785
|
}
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
7786
|
+
}
|
|
7787
|
+
pause() {
|
|
7788
|
+
this.animation.pause();
|
|
7789
|
+
}
|
|
7790
|
+
complete() {
|
|
7791
|
+
this.animation.finish?.();
|
|
7792
|
+
}
|
|
7793
|
+
cancel() {
|
|
7794
|
+
try {
|
|
7795
|
+
this.animation.cancel();
|
|
8372
7796
|
}
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
if (
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
}
|
|
8386
|
-
duration = pregeneratedAnimation.duration;
|
|
8387
|
-
times = pregeneratedAnimation.times;
|
|
8388
|
-
ease = pregeneratedAnimation.ease;
|
|
8389
|
-
type = "keyframes";
|
|
8390
|
-
}
|
|
8391
|
-
const animation = startWaapiAnimation(motionValue.owner.current, name, keyframes, { ...this.options, duration, times, ease });
|
|
8392
|
-
// Override the browser calculated startTime with one synchronised to other JS
|
|
8393
|
-
// and WAAPI animations starting this event loop.
|
|
8394
|
-
animation.startTime = startTime ?? this.calcStartTime();
|
|
8395
|
-
if (this.pendingTimeline) {
|
|
8396
|
-
attachTimeline(animation, this.pendingTimeline);
|
|
8397
|
-
this.pendingTimeline = undefined;
|
|
7797
|
+
catch (e) { }
|
|
7798
|
+
}
|
|
7799
|
+
stop() {
|
|
7800
|
+
if (this.isStopped)
|
|
7801
|
+
return;
|
|
7802
|
+
this.isStopped = true;
|
|
7803
|
+
const { state } = this;
|
|
7804
|
+
if (state === "idle" || state === "finished") {
|
|
7805
|
+
return;
|
|
7806
|
+
}
|
|
7807
|
+
if (this.updateMotionValue) {
|
|
7808
|
+
this.updateMotionValue();
|
|
8398
7809
|
}
|
|
8399
7810
|
else {
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
7811
|
+
this.commitStyles();
|
|
7812
|
+
}
|
|
7813
|
+
if (!this.isPseudoElement)
|
|
7814
|
+
this.cancel();
|
|
7815
|
+
}
|
|
7816
|
+
/**
|
|
7817
|
+
* WAAPI doesn't natively have any interruption capabilities.
|
|
7818
|
+
*
|
|
7819
|
+
* In this method, we commit styles back to the DOM before cancelling
|
|
7820
|
+
* the animation.
|
|
7821
|
+
*
|
|
7822
|
+
* This is designed to be overridden by NativeAnimationExtended, which
|
|
7823
|
+
* will create a renderless JS animation and sample it twice to calculate
|
|
7824
|
+
* its current value, "previous" value, and therefore allow
|
|
7825
|
+
* Motion to also correctly calculate velocity for any subsequent animation
|
|
7826
|
+
* while deferring the commit until the next animation frame.
|
|
7827
|
+
*/
|
|
7828
|
+
commitStyles() {
|
|
7829
|
+
if (!this.isPseudoElement) {
|
|
7830
|
+
this.animation.commitStyles?.();
|
|
8415
7831
|
}
|
|
8416
|
-
return {
|
|
8417
|
-
animation,
|
|
8418
|
-
duration,
|
|
8419
|
-
times,
|
|
8420
|
-
type,
|
|
8421
|
-
ease,
|
|
8422
|
-
keyframes: keyframes,
|
|
8423
|
-
};
|
|
8424
7832
|
}
|
|
8425
7833
|
get duration() {
|
|
8426
|
-
const
|
|
8427
|
-
|
|
8428
|
-
return 0;
|
|
8429
|
-
const { duration } = resolved;
|
|
8430
|
-
return millisecondsToSeconds(duration);
|
|
7834
|
+
const duration = this.animation.effect?.getComputedTiming?.().duration || 0;
|
|
7835
|
+
return millisecondsToSeconds(Number(duration));
|
|
8431
7836
|
}
|
|
8432
7837
|
get time() {
|
|
8433
|
-
|
|
8434
|
-
if (!resolved)
|
|
8435
|
-
return 0;
|
|
8436
|
-
const { animation } = resolved;
|
|
8437
|
-
return millisecondsToSeconds(animation.currentTime || 0);
|
|
7838
|
+
return millisecondsToSeconds(Number(this.animation.currentTime) || 0);
|
|
8438
7839
|
}
|
|
8439
7840
|
set time(newTime) {
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
return;
|
|
8443
|
-
const { animation } = resolved;
|
|
8444
|
-
animation.currentTime = secondsToMilliseconds(newTime);
|
|
7841
|
+
this.finishedTime = null;
|
|
7842
|
+
this.animation.currentTime = secondsToMilliseconds(newTime);
|
|
8445
7843
|
}
|
|
7844
|
+
/**
|
|
7845
|
+
* The playback speed of the animation.
|
|
7846
|
+
* 1 = normal speed, 2 = double speed, 0.5 = half speed.
|
|
7847
|
+
*/
|
|
8446
7848
|
get speed() {
|
|
8447
|
-
|
|
8448
|
-
if (!resolved)
|
|
8449
|
-
return 1;
|
|
8450
|
-
const { animation } = resolved;
|
|
8451
|
-
return animation.playbackRate;
|
|
8452
|
-
}
|
|
8453
|
-
get finished() {
|
|
8454
|
-
return this.resolved.animation.finished;
|
|
7849
|
+
return this.animation.playbackRate;
|
|
8455
7850
|
}
|
|
8456
7851
|
set speed(newSpeed) {
|
|
8457
|
-
|
|
8458
|
-
if (
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
animation.playbackRate = newSpeed;
|
|
7852
|
+
// Allow backwards playback after finishing
|
|
7853
|
+
if (newSpeed < 0)
|
|
7854
|
+
this.finishedTime = null;
|
|
7855
|
+
this.animation.playbackRate = newSpeed;
|
|
8462
7856
|
}
|
|
8463
7857
|
get state() {
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
const { animation } = resolved;
|
|
8468
|
-
return animation.playState;
|
|
7858
|
+
return this.finishedTime !== null
|
|
7859
|
+
? "finished"
|
|
7860
|
+
: this.animation.playState;
|
|
8469
7861
|
}
|
|
8470
7862
|
get startTime() {
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
// Coerce to number as TypeScript incorrectly types this
|
|
8476
|
-
// as CSSNumberish
|
|
8477
|
-
return animation.startTime;
|
|
7863
|
+
return Number(this.animation.startTime);
|
|
7864
|
+
}
|
|
7865
|
+
set startTime(newStartTime) {
|
|
7866
|
+
this.animation.startTime = newStartTime;
|
|
8478
7867
|
}
|
|
8479
7868
|
/**
|
|
8480
|
-
*
|
|
8481
|
-
* Currently used for scroll animations.
|
|
7869
|
+
* Attaches a timeline to the animation, for instance the `ScrollTimeline`.
|
|
8482
7870
|
*/
|
|
8483
|
-
attachTimeline(timeline) {
|
|
8484
|
-
if (
|
|
8485
|
-
this.
|
|
7871
|
+
attachTimeline({ timeline, observe }) {
|
|
7872
|
+
if (this.allowFlatten) {
|
|
7873
|
+
this.animation.effect?.updateTiming({ easing: "linear" });
|
|
8486
7874
|
}
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
const { animation } = resolved;
|
|
8492
|
-
attachTimeline(animation, timeline);
|
|
7875
|
+
this.animation.onfinish = null;
|
|
7876
|
+
if (timeline && supportsScrollTimeline()) {
|
|
7877
|
+
this.animation.timeline = timeline;
|
|
7878
|
+
return noop;
|
|
8493
7879
|
}
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
play() {
|
|
8497
|
-
if (this.isStopped)
|
|
8498
|
-
return;
|
|
8499
|
-
const { resolved } = this;
|
|
8500
|
-
if (!resolved)
|
|
8501
|
-
return;
|
|
8502
|
-
const { animation } = resolved;
|
|
8503
|
-
if (animation.playState === "finished") {
|
|
8504
|
-
this.updateFinishedPromise();
|
|
7880
|
+
else {
|
|
7881
|
+
return observe(this);
|
|
8505
7882
|
}
|
|
8506
|
-
animation.play();
|
|
8507
7883
|
}
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
7884
|
+
}
|
|
7885
|
+
|
|
7886
|
+
const unsupportedEasingFunctions = {
|
|
7887
|
+
anticipate,
|
|
7888
|
+
backInOut,
|
|
7889
|
+
circInOut,
|
|
7890
|
+
};
|
|
7891
|
+
function isUnsupportedEase(key) {
|
|
7892
|
+
return key in unsupportedEasingFunctions;
|
|
7893
|
+
}
|
|
7894
|
+
function replaceStringEasing(transition) {
|
|
7895
|
+
if (typeof transition.ease === "string" &&
|
|
7896
|
+
isUnsupportedEase(transition.ease)) {
|
|
7897
|
+
transition.ease = unsupportedEasingFunctions[transition.ease];
|
|
8514
7898
|
}
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
8521
|
-
|
|
8522
|
-
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
const { animation, keyframes, duration, type, ease, times } = resolved;
|
|
8526
|
-
if (animation.playState === "idle" ||
|
|
8527
|
-
animation.playState === "finished") {
|
|
8528
|
-
return;
|
|
8529
|
-
}
|
|
7899
|
+
}
|
|
7900
|
+
|
|
7901
|
+
/**
|
|
7902
|
+
* 10ms is chosen here as it strikes a balance between smooth
|
|
7903
|
+
* results (more than one keyframe per frame at 60fps) and
|
|
7904
|
+
* keyframe quantity.
|
|
7905
|
+
*/
|
|
7906
|
+
const sampleDelta = 10; //ms
|
|
7907
|
+
class NativeAnimationExtended extends NativeAnimation {
|
|
7908
|
+
constructor(options) {
|
|
8530
7909
|
/**
|
|
8531
|
-
*
|
|
7910
|
+
* The base NativeAnimation function only supports a subset
|
|
7911
|
+
* of Motion easings, and WAAPI also only supports some
|
|
7912
|
+
* easing functions via string/cubic-bezier definitions.
|
|
8532
7913
|
*
|
|
8533
|
-
*
|
|
8534
|
-
*
|
|
8535
|
-
*
|
|
8536
|
-
* Motion to calculate velocity for any subsequent animation.
|
|
7914
|
+
* This function replaces those unsupported easing functions
|
|
7915
|
+
* with a JS easing function. This will later get compiled
|
|
7916
|
+
* to a linear() easing function.
|
|
8537
7917
|
*/
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);
|
|
7918
|
+
replaceStringEasing(options);
|
|
7919
|
+
/**
|
|
7920
|
+
* Ensure we replace the transition type with a generator function
|
|
7921
|
+
* before passing to WAAPI.
|
|
7922
|
+
*
|
|
7923
|
+
* TODO: Does this have a better home? It could be shared with
|
|
7924
|
+
* JSAnimation.
|
|
7925
|
+
*/
|
|
7926
|
+
replaceTransitionType(options);
|
|
7927
|
+
super(options);
|
|
7928
|
+
if (options.startTime) {
|
|
7929
|
+
this.startTime = options.startTime;
|
|
8551
7930
|
}
|
|
8552
|
-
|
|
8553
|
-
onStop && onStop();
|
|
8554
|
-
this.cancel();
|
|
7931
|
+
this.options = options;
|
|
8555
7932
|
}
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
7933
|
+
/**
|
|
7934
|
+
* WAAPI doesn't natively have any interruption capabilities.
|
|
7935
|
+
*
|
|
7936
|
+
* Rather than read commited styles back out of the DOM, we can
|
|
7937
|
+
* create a renderless JS animation and sample it twice to calculate
|
|
7938
|
+
* its current value, "previous" value, and therefore allow
|
|
7939
|
+
* Motion to calculate velocity for any subsequent animation.
|
|
7940
|
+
*/
|
|
7941
|
+
updateMotionValue(value) {
|
|
7942
|
+
const { motionValue, onUpdate, onComplete, element, ...options } = this.options;
|
|
7943
|
+
if (!motionValue)
|
|
8559
7944
|
return;
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
cancel() {
|
|
8563
|
-
const { resolved } = this;
|
|
8564
|
-
if (!resolved)
|
|
7945
|
+
if (value !== undefined) {
|
|
7946
|
+
motionValue.set(value);
|
|
8565
7947
|
return;
|
|
8566
|
-
resolved.animation.cancel();
|
|
8567
|
-
}
|
|
8568
|
-
static supports(options) {
|
|
8569
|
-
const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
|
|
8570
|
-
if (!motionValue ||
|
|
8571
|
-
!motionValue.owner ||
|
|
8572
|
-
!(motionValue.owner.current instanceof HTMLElement)) {
|
|
8573
|
-
return false;
|
|
8574
7948
|
}
|
|
8575
|
-
const
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
* no way to read the value from WAAPI every frame.
|
|
8583
|
-
*/
|
|
8584
|
-
!onUpdate &&
|
|
8585
|
-
!repeatDelay &&
|
|
8586
|
-
repeatType !== "mirror" &&
|
|
8587
|
-
damping !== 0 &&
|
|
8588
|
-
type !== "inertia");
|
|
7949
|
+
const sampleAnimation = new JSAnimation({
|
|
7950
|
+
...options,
|
|
7951
|
+
autoplay: false,
|
|
7952
|
+
});
|
|
7953
|
+
const sampleTime = secondsToMilliseconds(this.finishedTime ?? this.time);
|
|
7954
|
+
motionValue.setWithVelocity(sampleAnimation.sample(sampleTime - sampleDelta).value, sampleAnimation.sample(sampleTime).value, sampleDelta);
|
|
7955
|
+
sampleAnimation.stop();
|
|
8589
7956
|
}
|
|
8590
7957
|
}
|
|
8591
7958
|
|
|
8592
|
-
const underDampedSpring = {
|
|
8593
|
-
type: "spring",
|
|
8594
|
-
stiffness: 500,
|
|
8595
|
-
damping: 25,
|
|
8596
|
-
restSpeed: 10,
|
|
8597
|
-
};
|
|
8598
|
-
const criticallyDampedSpring = (target) => ({
|
|
8599
|
-
type: "spring",
|
|
8600
|
-
stiffness: 550,
|
|
8601
|
-
damping: target === 0 ? 2 * Math.sqrt(550) : 30,
|
|
8602
|
-
restSpeed: 10,
|
|
8603
|
-
});
|
|
8604
|
-
const keyframesTransition = {
|
|
8605
|
-
type: "keyframes",
|
|
8606
|
-
duration: 0.8,
|
|
8607
|
-
};
|
|
8608
7959
|
/**
|
|
8609
|
-
*
|
|
8610
|
-
*
|
|
7960
|
+
* Check if a value is animatable. Examples:
|
|
7961
|
+
*
|
|
7962
|
+
* ✅: 100, "100px", "#fff"
|
|
7963
|
+
* ❌: "block", "url(2.jpg)"
|
|
7964
|
+
* @param value
|
|
7965
|
+
*
|
|
7966
|
+
* @internal
|
|
8611
7967
|
*/
|
|
8612
|
-
const
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
7968
|
+
const isAnimatable = (value, name) => {
|
|
7969
|
+
// If the list of keys tat might be non-animatable grows, replace with Set
|
|
7970
|
+
if (name === "zIndex")
|
|
7971
|
+
return false;
|
|
7972
|
+
// If it's a number or a keyframes array, we can animate it. We might at some point
|
|
7973
|
+
// need to do a deep isAnimatable check of keyframes, or let Popmotion handle this,
|
|
7974
|
+
// but for now lets leave it like this for performance reasons
|
|
7975
|
+
if (typeof value === "number" || Array.isArray(value))
|
|
7976
|
+
return true;
|
|
7977
|
+
if (typeof value === "string" && // It's animatable if we have a string
|
|
7978
|
+
(complex.test(value) || value === "0") && // And it contains numbers and/or colors
|
|
7979
|
+
!value.startsWith("url(") // Unless it starts with "url("
|
|
7980
|
+
) {
|
|
7981
|
+
return true;
|
|
8625
7982
|
}
|
|
8626
|
-
return
|
|
7983
|
+
return false;
|
|
8627
7984
|
};
|
|
8628
7985
|
|
|
7986
|
+
function hasKeyframesChanged(keyframes) {
|
|
7987
|
+
const current = keyframes[0];
|
|
7988
|
+
if (keyframes.length === 1)
|
|
7989
|
+
return true;
|
|
7990
|
+
for (let i = 0; i < keyframes.length; i++) {
|
|
7991
|
+
if (keyframes[i] !== current)
|
|
7992
|
+
return true;
|
|
7993
|
+
}
|
|
7994
|
+
}
|
|
7995
|
+
function canAnimate(keyframes, name, type, velocity) {
|
|
7996
|
+
/**
|
|
7997
|
+
* Check if we're able to animate between the start and end keyframes,
|
|
7998
|
+
* and throw a warning if we're attempting to animate between one that's
|
|
7999
|
+
* animatable and another that isn't.
|
|
8000
|
+
*/
|
|
8001
|
+
const originKeyframe = keyframes[0];
|
|
8002
|
+
if (originKeyframe === null)
|
|
8003
|
+
return false;
|
|
8004
|
+
/**
|
|
8005
|
+
* These aren't traditionally animatable but we do support them.
|
|
8006
|
+
* In future we could look into making this more generic or replacing
|
|
8007
|
+
* this function with mix() === mixImmediate
|
|
8008
|
+
*/
|
|
8009
|
+
if (name === "display" || name === "visibility")
|
|
8010
|
+
return true;
|
|
8011
|
+
const targetKeyframe = keyframes[keyframes.length - 1];
|
|
8012
|
+
const isOriginAnimatable = isAnimatable(originKeyframe, name);
|
|
8013
|
+
const isTargetAnimatable = isAnimatable(targetKeyframe, name);
|
|
8014
|
+
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.`);
|
|
8015
|
+
// Always skip if any of these are true
|
|
8016
|
+
if (!isOriginAnimatable || !isTargetAnimatable) {
|
|
8017
|
+
return false;
|
|
8018
|
+
}
|
|
8019
|
+
return (hasKeyframesChanged(keyframes) ||
|
|
8020
|
+
((type === "spring" || isGenerator(type)) && velocity));
|
|
8021
|
+
}
|
|
8022
|
+
|
|
8629
8023
|
/**
|
|
8630
|
-
*
|
|
8631
|
-
* This filters out orchestration options and returns true
|
|
8632
|
-
* if any options are left.
|
|
8024
|
+
* A list of values that can be hardware-accelerated.
|
|
8633
8025
|
*/
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
|
|
8637
|
-
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
8641
|
-
|
|
8026
|
+
const acceleratedValues = new Set([
|
|
8027
|
+
"opacity",
|
|
8028
|
+
"clipPath",
|
|
8029
|
+
"filter",
|
|
8030
|
+
"transform",
|
|
8031
|
+
// TODO: Can be accelerated but currently disabled until https://issues.chromium.org/issues/41491098 is resolved
|
|
8032
|
+
// or until we implement support for linear() easing.
|
|
8033
|
+
// "background-color"
|
|
8034
|
+
]);
|
|
8035
|
+
const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
|
|
8036
|
+
function supportsBrowserAnimation(options) {
|
|
8037
|
+
const { motionValue, name, repeatDelay, repeatType, damping, type } = options;
|
|
8038
|
+
if (!motionValue ||
|
|
8039
|
+
!motionValue.owner ||
|
|
8040
|
+
!(motionValue.owner.current instanceof HTMLElement)) {
|
|
8041
|
+
return false;
|
|
8042
|
+
}
|
|
8043
|
+
const { onUpdate, transformTemplate } = motionValue.owner.getProps();
|
|
8044
|
+
return (supportsWaapi() &&
|
|
8045
|
+
name &&
|
|
8046
|
+
acceleratedValues.has(name) &&
|
|
8047
|
+
(name !== "transform" || !transformTemplate) &&
|
|
8048
|
+
/**
|
|
8049
|
+
* If we're outputting values to onUpdate then we can't use WAAPI as there's
|
|
8050
|
+
* no way to read the value from WAAPI every frame.
|
|
8051
|
+
*/
|
|
8052
|
+
!onUpdate &&
|
|
8053
|
+
!repeatDelay &&
|
|
8054
|
+
repeatType !== "mirror" &&
|
|
8055
|
+
damping !== 0 &&
|
|
8056
|
+
type !== "inertia");
|
|
8642
8057
|
}
|
|
8643
8058
|
|
|
8644
|
-
|
|
8645
|
-
|
|
8646
|
-
|
|
8647
|
-
|
|
8648
|
-
|
|
8649
|
-
|
|
8650
|
-
|
|
8059
|
+
/**
|
|
8060
|
+
* Maximum time allowed between an animation being created and it being
|
|
8061
|
+
* resolved for us to use the latter as the start time.
|
|
8062
|
+
*
|
|
8063
|
+
* This is to ensure that while we prefer to "start" an animation as soon
|
|
8064
|
+
* as it's triggered, we also want to avoid a visual jump if there's a big delay
|
|
8065
|
+
* between these two moments.
|
|
8066
|
+
*/
|
|
8067
|
+
const MAX_RESOLVE_DELAY = 40;
|
|
8068
|
+
class AsyncMotionValueAnimation extends WithPromise {
|
|
8069
|
+
constructor({ autoplay = true, delay = 0, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", keyframes, name, motionValue, element, ...options }) {
|
|
8070
|
+
super();
|
|
8071
|
+
/**
|
|
8072
|
+
* Bound to support return animation.stop pattern
|
|
8073
|
+
*/
|
|
8074
|
+
this.stop = () => {
|
|
8075
|
+
if (this._animation) {
|
|
8076
|
+
this._animation.stop();
|
|
8077
|
+
this.stopTimeline?.();
|
|
8078
|
+
}
|
|
8079
|
+
else {
|
|
8080
|
+
this.keyframeResolver?.cancel();
|
|
8081
|
+
}
|
|
8082
|
+
};
|
|
8083
|
+
this.createdAt = time.now();
|
|
8084
|
+
const optionsWithDefaults = {
|
|
8085
|
+
autoplay,
|
|
8086
|
+
delay,
|
|
8087
|
+
type,
|
|
8088
|
+
repeat,
|
|
8089
|
+
repeatDelay,
|
|
8090
|
+
repeatType,
|
|
8091
|
+
name,
|
|
8092
|
+
motionValue,
|
|
8093
|
+
element,
|
|
8094
|
+
...options,
|
|
8095
|
+
};
|
|
8096
|
+
const KeyframeResolver$1 = element?.KeyframeResolver || KeyframeResolver;
|
|
8097
|
+
this.keyframeResolver = new KeyframeResolver$1(keyframes, (resolvedKeyframes, finalKeyframe, forced) => this.onKeyframesResolved(resolvedKeyframes, finalKeyframe, optionsWithDefaults, !forced), name, motionValue, element);
|
|
8098
|
+
this.keyframeResolver?.scheduleResolve();
|
|
8099
|
+
}
|
|
8100
|
+
onKeyframesResolved(keyframes, finalKeyframe, options, sync) {
|
|
8101
|
+
this.keyframeResolver = undefined;
|
|
8102
|
+
const { name, type, velocity, delay, isHandoff, onUpdate } = options;
|
|
8103
|
+
this.resolvedAt = time.now();
|
|
8104
|
+
/**
|
|
8105
|
+
* If we can't animate this value with the resolved keyframes
|
|
8106
|
+
* then we should complete it immediately.
|
|
8107
|
+
*/
|
|
8108
|
+
if (!canAnimate(keyframes, name, type, velocity)) {
|
|
8109
|
+
if (MotionGlobalConfig.instantAnimations || !delay) {
|
|
8110
|
+
onUpdate?.(getFinalKeyframe(keyframes, options, finalKeyframe));
|
|
8111
|
+
}
|
|
8112
|
+
keyframes[0] = keyframes[keyframes.length - 1];
|
|
8113
|
+
options.duration = 0;
|
|
8114
|
+
options.repeat = 0;
|
|
8115
|
+
}
|
|
8116
|
+
/**
|
|
8117
|
+
* Resolve startTime for the animation.
|
|
8118
|
+
*
|
|
8119
|
+
* This method uses the createdAt and resolvedAt to calculate the
|
|
8120
|
+
* animation startTime. *Ideally*, we would use the createdAt time as t=0
|
|
8121
|
+
* as the following frame would then be the first frame of the animation in
|
|
8122
|
+
* progress, which would feel snappier.
|
|
8123
|
+
*
|
|
8124
|
+
* However, if there's a delay (main thread work) between the creation of
|
|
8125
|
+
* the animation and the first commited frame, we prefer to use resolvedAt
|
|
8126
|
+
* to avoid a sudden jump into the animation.
|
|
8127
|
+
*/
|
|
8128
|
+
const startTime = sync
|
|
8129
|
+
? !this.resolvedAt
|
|
8130
|
+
? this.createdAt
|
|
8131
|
+
: this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY
|
|
8132
|
+
? this.resolvedAt
|
|
8133
|
+
: this.createdAt
|
|
8134
|
+
: undefined;
|
|
8135
|
+
const resolvedOptions = {
|
|
8136
|
+
startTime,
|
|
8137
|
+
finalKeyframe,
|
|
8138
|
+
...options,
|
|
8139
|
+
keyframes,
|
|
8140
|
+
};
|
|
8141
|
+
/**
|
|
8142
|
+
* Animate via WAAPI if possible. If this is a handoff animation, the optimised animation will be running via
|
|
8143
|
+
* WAAPI. Therefore, this animation must be JS to ensure it runs "under" the
|
|
8144
|
+
* optimised animation.
|
|
8145
|
+
*/
|
|
8146
|
+
const animation = !isHandoff && supportsBrowserAnimation(resolvedOptions)
|
|
8147
|
+
? new NativeAnimationExtended({
|
|
8148
|
+
...resolvedOptions,
|
|
8149
|
+
element: resolvedOptions.motionValue.owner.current,
|
|
8150
|
+
})
|
|
8151
|
+
: new JSAnimation(resolvedOptions);
|
|
8152
|
+
animation.finished.then(() => this.notifyFinished()).catch(noop);
|
|
8153
|
+
if (this.pendingTimeline) {
|
|
8154
|
+
this.stopTimeline = animation.attachTimeline(this.pendingTimeline);
|
|
8155
|
+
this.pendingTimeline = undefined;
|
|
8156
|
+
}
|
|
8157
|
+
this._animation = animation;
|
|
8651
8158
|
}
|
|
8652
8159
|
get finished() {
|
|
8653
|
-
|
|
8160
|
+
if (!this._animation) {
|
|
8161
|
+
return this._finished;
|
|
8162
|
+
}
|
|
8163
|
+
else {
|
|
8164
|
+
return this.animation.finished;
|
|
8165
|
+
}
|
|
8654
8166
|
}
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
*/
|
|
8658
|
-
getAll(propName) {
|
|
8659
|
-
return this.animations[0][propName];
|
|
8167
|
+
then(onResolve, _onReject) {
|
|
8168
|
+
return this.finished.finally(onResolve).then(() => { });
|
|
8660
8169
|
}
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8170
|
+
get animation() {
|
|
8171
|
+
if (!this._animation) {
|
|
8172
|
+
flushKeyframeResolvers();
|
|
8664
8173
|
}
|
|
8174
|
+
return this._animation;
|
|
8665
8175
|
}
|
|
8666
|
-
|
|
8667
|
-
|
|
8668
|
-
if (supportsScrollTimeline() && animation.attachTimeline) {
|
|
8669
|
-
return animation.attachTimeline(timeline);
|
|
8670
|
-
}
|
|
8671
|
-
else if (typeof fallback === "function") {
|
|
8672
|
-
return fallback(animation);
|
|
8673
|
-
}
|
|
8674
|
-
});
|
|
8675
|
-
return () => {
|
|
8676
|
-
subscriptions.forEach((cancel, i) => {
|
|
8677
|
-
cancel && cancel();
|
|
8678
|
-
this.animations[i].stop();
|
|
8679
|
-
});
|
|
8680
|
-
};
|
|
8176
|
+
get duration() {
|
|
8177
|
+
return this.animation.duration;
|
|
8681
8178
|
}
|
|
8682
8179
|
get time() {
|
|
8683
|
-
return this.
|
|
8180
|
+
return this.animation.time;
|
|
8684
8181
|
}
|
|
8685
|
-
set time(
|
|
8686
|
-
this.
|
|
8182
|
+
set time(newTime) {
|
|
8183
|
+
this.animation.time = newTime;
|
|
8687
8184
|
}
|
|
8688
8185
|
get speed() {
|
|
8689
|
-
return this.
|
|
8186
|
+
return this.animation.speed;
|
|
8690
8187
|
}
|
|
8691
|
-
|
|
8692
|
-
this.
|
|
8188
|
+
get state() {
|
|
8189
|
+
return this.animation.state;
|
|
8190
|
+
}
|
|
8191
|
+
set speed(newSpeed) {
|
|
8192
|
+
this.animation.speed = newSpeed;
|
|
8693
8193
|
}
|
|
8694
8194
|
get startTime() {
|
|
8695
|
-
return this.
|
|
8195
|
+
return this.animation.startTime;
|
|
8696
8196
|
}
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
max = Math.max(max, this.animations[i].duration);
|
|
8197
|
+
attachTimeline(timeline) {
|
|
8198
|
+
if (this._animation) {
|
|
8199
|
+
this.stopTimeline = this.animation.attachTimeline(timeline);
|
|
8701
8200
|
}
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
}
|
|
8707
|
-
flatten() {
|
|
8708
|
-
this.runAll("flatten");
|
|
8201
|
+
else {
|
|
8202
|
+
this.pendingTimeline = timeline;
|
|
8203
|
+
}
|
|
8204
|
+
return () => this.stop();
|
|
8709
8205
|
}
|
|
8710
8206
|
play() {
|
|
8711
|
-
this.
|
|
8207
|
+
this.animation.play();
|
|
8712
8208
|
}
|
|
8713
8209
|
pause() {
|
|
8714
|
-
this.
|
|
8715
|
-
}
|
|
8716
|
-
cancel() {
|
|
8717
|
-
this.runAll("cancel");
|
|
8210
|
+
this.animation.pause();
|
|
8718
8211
|
}
|
|
8719
8212
|
complete() {
|
|
8720
|
-
this.
|
|
8213
|
+
this.animation.complete();
|
|
8721
8214
|
}
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
class GroupAnimationWithThen extends GroupAnimation {
|
|
8725
|
-
then(onResolve, _onReject) {
|
|
8726
|
-
return this.finished.finally(onResolve).then(() => { });
|
|
8215
|
+
cancel() {
|
|
8216
|
+
this.animation.cancel();
|
|
8727
8217
|
}
|
|
8728
8218
|
}
|
|
8729
8219
|
|
|
@@ -8741,7 +8231,7 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8741
8231
|
*/
|
|
8742
8232
|
let { elapsed = 0 } = transition;
|
|
8743
8233
|
elapsed = elapsed - secondsToMilliseconds(delay);
|
|
8744
|
-
|
|
8234
|
+
const options = {
|
|
8745
8235
|
keyframes: Array.isArray(target) ? target : [null, target],
|
|
8746
8236
|
ease: "easeOut",
|
|
8747
8237
|
velocity: value.getVelocity(),
|
|
@@ -8764,22 +8254,18 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8764
8254
|
* unique transition settings for this value.
|
|
8765
8255
|
*/
|
|
8766
8256
|
if (!isTransitionDefined(valueTransition)) {
|
|
8767
|
-
options
|
|
8768
|
-
...options,
|
|
8769
|
-
...getDefaultTransition(name, options),
|
|
8770
|
-
};
|
|
8257
|
+
Object.assign(options, getDefaultTransition(name, options));
|
|
8771
8258
|
}
|
|
8772
8259
|
/**
|
|
8773
8260
|
* Both WAAPI and our internal animation functions use durations
|
|
8774
8261
|
* as defined by milliseconds, while our external API defines them
|
|
8775
8262
|
* as seconds.
|
|
8776
8263
|
*/
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
}
|
|
8264
|
+
options.duration && (options.duration = secondsToMilliseconds(options.duration));
|
|
8265
|
+
options.repeatDelay && (options.repeatDelay = secondsToMilliseconds(options.repeatDelay));
|
|
8266
|
+
/**
|
|
8267
|
+
* Support deprecated way to set initial value. Prefer keyframe syntax.
|
|
8268
|
+
*/
|
|
8783
8269
|
if (options.from !== undefined) {
|
|
8784
8270
|
options.keyframes[0] = options.from;
|
|
8785
8271
|
}
|
|
@@ -8791,6 +8277,12 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8791
8277
|
shouldSkip = true;
|
|
8792
8278
|
}
|
|
8793
8279
|
}
|
|
8280
|
+
if (MotionGlobalConfig.instantAnimations ||
|
|
8281
|
+
MotionGlobalConfig.skipAnimations) {
|
|
8282
|
+
shouldSkip = true;
|
|
8283
|
+
options.duration = 0;
|
|
8284
|
+
options.delay = 0;
|
|
8285
|
+
}
|
|
8794
8286
|
/**
|
|
8795
8287
|
* If the transition type or easing has been explicitly set by the user
|
|
8796
8288
|
* then we don't want to allow flattening the animation.
|
|
@@ -8802,30 +8294,28 @@ const animateMotionValue = (name, value, target, transition = {}, element, isHan
|
|
|
8802
8294
|
* this early check prevents the need to create an animation at all.
|
|
8803
8295
|
*/
|
|
8804
8296
|
if (shouldSkip && !isHandoff && value.get() !== undefined) {
|
|
8805
|
-
const finalKeyframe = getFinalKeyframe(options.keyframes, valueTransition);
|
|
8297
|
+
const finalKeyframe = getFinalKeyframe$1(options.keyframes, valueTransition);
|
|
8806
8298
|
if (finalKeyframe !== undefined) {
|
|
8807
8299
|
frame.update(() => {
|
|
8808
8300
|
options.onUpdate(finalKeyframe);
|
|
8809
8301
|
options.onComplete();
|
|
8810
8302
|
});
|
|
8811
|
-
|
|
8812
|
-
// than returning undefined
|
|
8813
|
-
return new GroupAnimationWithThen([]);
|
|
8303
|
+
return;
|
|
8814
8304
|
}
|
|
8815
8305
|
}
|
|
8816
|
-
|
|
8817
|
-
* Animate via WAAPI if possible. If this is a handoff animation, the optimised animation will be running via
|
|
8818
|
-
* WAAPI. Therefore, this animation must be JS to ensure it runs "under" the
|
|
8819
|
-
* optimised animation.
|
|
8820
|
-
*/
|
|
8821
|
-
if (!isHandoff && AcceleratedAnimation.supports(options)) {
|
|
8822
|
-
return new AcceleratedAnimation(options);
|
|
8823
|
-
}
|
|
8824
|
-
else {
|
|
8825
|
-
return new MainThreadAnimation(options);
|
|
8826
|
-
}
|
|
8306
|
+
return new AsyncMotionValueAnimation(options);
|
|
8827
8307
|
};
|
|
8828
8308
|
|
|
8309
|
+
const positionalKeys = new Set([
|
|
8310
|
+
"width",
|
|
8311
|
+
"height",
|
|
8312
|
+
"top",
|
|
8313
|
+
"left",
|
|
8314
|
+
"right",
|
|
8315
|
+
"bottom",
|
|
8316
|
+
...transformPropOrder,
|
|
8317
|
+
]);
|
|
8318
|
+
|
|
8829
8319
|
/**
|
|
8830
8320
|
* Decide whether we should block this animation. Previously, we achieved this
|
|
8831
8321
|
* just by checking whether the key was listed in protectedKeys, but this
|
|
@@ -8857,6 +8347,17 @@ function animateTarget(visualElement, targetAndTransition, { delay = 0, transiti
|
|
|
8857
8347
|
delay,
|
|
8858
8348
|
...getValueTransition(transition || {}, key),
|
|
8859
8349
|
};
|
|
8350
|
+
/**
|
|
8351
|
+
* If the value is already at the defined target, skip the animation.
|
|
8352
|
+
*/
|
|
8353
|
+
const currentValue = value.get();
|
|
8354
|
+
if (currentValue !== undefined &&
|
|
8355
|
+
!value.isAnimating &&
|
|
8356
|
+
!Array.isArray(valueTarget) &&
|
|
8357
|
+
valueTarget === currentValue &&
|
|
8358
|
+
!valueTransition.velocity) {
|
|
8359
|
+
continue;
|
|
8360
|
+
}
|
|
8860
8361
|
/**
|
|
8861
8362
|
* If this is the first time a value is being animated, check
|
|
8862
8363
|
* to see if we're handling off from an existing animation.
|
|
@@ -10809,7 +10310,7 @@ function delay(callback, timeout) {
|
|
|
10809
10310
|
callback(elapsed - timeout);
|
|
10810
10311
|
}
|
|
10811
10312
|
};
|
|
10812
|
-
frame.
|
|
10313
|
+
frame.setup(checkElapsed, true);
|
|
10813
10314
|
return () => cancelFrame(checkElapsed);
|
|
10814
10315
|
}
|
|
10815
10316
|
|
|
@@ -12103,9 +11604,7 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
12103
11604
|
}
|
|
12104
11605
|
setAnimationOrigin(delta, hasOnlyRelativeTargetChanged = false) {
|
|
12105
11606
|
const snapshot = this.snapshot;
|
|
12106
|
-
const snapshotLatestValues = snapshot
|
|
12107
|
-
? snapshot.latestValues
|
|
12108
|
-
: {};
|
|
11607
|
+
const snapshotLatestValues = snapshot ? snapshot.latestValues : {};
|
|
12109
11608
|
const mixedValues = { ...this.latestValues };
|
|
12110
11609
|
const targetDelta = createDelta();
|
|
12111
11610
|
if (!this.relativeParent ||
|
|
@@ -13173,15 +12672,6 @@ function initPrefersReducedMotion() {
|
|
|
13173
12672
|
}
|
|
13174
12673
|
}
|
|
13175
12674
|
|
|
13176
|
-
/**
|
|
13177
|
-
* A list of all ValueTypes
|
|
13178
|
-
*/
|
|
13179
|
-
const valueTypes = [...dimensionValueTypes, color, complex];
|
|
13180
|
-
/**
|
|
13181
|
-
* Tests a value against the list of ValueTypes
|
|
13182
|
-
*/
|
|
13183
|
-
const findValueType = (v) => valueTypes.find(testValueType(v));
|
|
13184
|
-
|
|
13185
12675
|
const visualElementStore = new WeakMap();
|
|
13186
12676
|
|
|
13187
12677
|
function updateMotionValuesFromProps(element, next, prev) {
|
|
@@ -13199,7 +12689,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
13199
12689
|
* and warn against mismatches.
|
|
13200
12690
|
*/
|
|
13201
12691
|
if (process.env.NODE_ENV === "development") {
|
|
13202
|
-
warnOnce(nextValue.version === "12.
|
|
12692
|
+
warnOnce(nextValue.version === "12.9.0", `Attempting to mix Motion versions ${nextValue.version} with 12.9.0 may not work as expected.`);
|
|
13203
12693
|
}
|
|
13204
12694
|
}
|
|
13205
12695
|
else if (isMotionValue(prevValue)) {
|
|
@@ -13238,6 +12728,108 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
13238
12728
|
return next;
|
|
13239
12729
|
}
|
|
13240
12730
|
|
|
12731
|
+
/**
|
|
12732
|
+
* Check if value is a numerical string, ie a string that is purely a number eg "100" or "-100.1"
|
|
12733
|
+
*/
|
|
12734
|
+
const isNumericalString = (v) => /^-?(?:\d+(?:\.\d+)?|\.\d+)$/u.test(v);
|
|
12735
|
+
|
|
12736
|
+
/**
|
|
12737
|
+
* Check if the value is a zero value string like "0px" or "0%"
|
|
12738
|
+
*/
|
|
12739
|
+
const isZeroValueString = (v) => /^0[^.\s]+$/u.test(v);
|
|
12740
|
+
|
|
12741
|
+
/**
|
|
12742
|
+
* ValueType for "auto"
|
|
12743
|
+
*/
|
|
12744
|
+
const auto = {
|
|
12745
|
+
test: (v) => v === "auto",
|
|
12746
|
+
parse: (v) => v,
|
|
12747
|
+
};
|
|
12748
|
+
|
|
12749
|
+
/**
|
|
12750
|
+
* Tests a provided value against a ValueType
|
|
12751
|
+
*/
|
|
12752
|
+
const testValueType = (v) => (type) => type.test(v);
|
|
12753
|
+
|
|
12754
|
+
/**
|
|
12755
|
+
* A list of value types commonly used for dimensions
|
|
12756
|
+
*/
|
|
12757
|
+
const dimensionValueTypes = [number, px, percent, degrees, vw, vh, auto];
|
|
12758
|
+
/**
|
|
12759
|
+
* Tests a dimensional value against the list of dimension ValueTypes
|
|
12760
|
+
*/
|
|
12761
|
+
const findDimensionValueType = (v) => dimensionValueTypes.find(testValueType(v));
|
|
12762
|
+
|
|
12763
|
+
/**
|
|
12764
|
+
* A list of all ValueTypes
|
|
12765
|
+
*/
|
|
12766
|
+
const valueTypes = [...dimensionValueTypes, color, complex];
|
|
12767
|
+
/**
|
|
12768
|
+
* Tests a value against the list of ValueTypes
|
|
12769
|
+
*/
|
|
12770
|
+
const findValueType = (v) => valueTypes.find(testValueType(v));
|
|
12771
|
+
|
|
12772
|
+
/**
|
|
12773
|
+
* Properties that should default to 1 or 100%
|
|
12774
|
+
*/
|
|
12775
|
+
const maxDefaults = new Set(["brightness", "contrast", "saturate", "opacity"]);
|
|
12776
|
+
function applyDefaultFilter(v) {
|
|
12777
|
+
const [name, value] = v.slice(0, -1).split("(");
|
|
12778
|
+
if (name === "drop-shadow")
|
|
12779
|
+
return v;
|
|
12780
|
+
const [number] = value.match(floatRegex) || [];
|
|
12781
|
+
if (!number)
|
|
12782
|
+
return v;
|
|
12783
|
+
const unit = value.replace(number, "");
|
|
12784
|
+
let defaultValue = maxDefaults.has(name) ? 1 : 0;
|
|
12785
|
+
if (number !== value)
|
|
12786
|
+
defaultValue *= 100;
|
|
12787
|
+
return name + "(" + defaultValue + unit + ")";
|
|
12788
|
+
}
|
|
12789
|
+
const functionRegex = /\b([a-z-]*)\(.*?\)/gu;
|
|
12790
|
+
const filter = {
|
|
12791
|
+
...complex,
|
|
12792
|
+
getAnimatableNone: (v) => {
|
|
12793
|
+
const functions = v.match(functionRegex);
|
|
12794
|
+
return functions ? functions.map(applyDefaultFilter).join(" ") : v;
|
|
12795
|
+
},
|
|
12796
|
+
};
|
|
12797
|
+
|
|
12798
|
+
/**
|
|
12799
|
+
* A map of default value types for common values
|
|
12800
|
+
*/
|
|
12801
|
+
const defaultValueTypes = {
|
|
12802
|
+
...numberValueTypes,
|
|
12803
|
+
// Color props
|
|
12804
|
+
color,
|
|
12805
|
+
backgroundColor: color,
|
|
12806
|
+
outlineColor: color,
|
|
12807
|
+
fill: color,
|
|
12808
|
+
stroke: color,
|
|
12809
|
+
// Border props
|
|
12810
|
+
borderColor: color,
|
|
12811
|
+
borderTopColor: color,
|
|
12812
|
+
borderRightColor: color,
|
|
12813
|
+
borderBottomColor: color,
|
|
12814
|
+
borderLeftColor: color,
|
|
12815
|
+
filter,
|
|
12816
|
+
WebkitFilter: filter,
|
|
12817
|
+
};
|
|
12818
|
+
/**
|
|
12819
|
+
* Gets the default ValueType for the provided value key
|
|
12820
|
+
*/
|
|
12821
|
+
const getDefaultValueType = (key) => defaultValueTypes[key];
|
|
12822
|
+
|
|
12823
|
+
function getAnimatableNone(key, value) {
|
|
12824
|
+
let defaultValueType = getDefaultValueType(key);
|
|
12825
|
+
if (defaultValueType !== filter)
|
|
12826
|
+
defaultValueType = complex;
|
|
12827
|
+
// If value is not recognised as animatable, ie "none", create an animatable version origin based on the target
|
|
12828
|
+
return defaultValueType.getAnimatableNone
|
|
12829
|
+
? defaultValueType.getAnimatableNone(value)
|
|
12830
|
+
: undefined;
|
|
12831
|
+
}
|
|
12832
|
+
|
|
13241
12833
|
const propEventHandlers = [
|
|
13242
12834
|
"AnimationStart",
|
|
13243
12835
|
"AnimationComplete",
|
|
@@ -13332,8 +12924,7 @@ class VisualElement {
|
|
|
13332
12924
|
frame.render(this.render, false, true);
|
|
13333
12925
|
}
|
|
13334
12926
|
};
|
|
13335
|
-
const { latestValues, renderState
|
|
13336
|
-
this.onUpdate = onUpdate;
|
|
12927
|
+
const { latestValues, renderState } = visualState;
|
|
13337
12928
|
this.latestValues = latestValues;
|
|
13338
12929
|
this.baseTarget = { ...latestValues };
|
|
13339
12930
|
this.initialValues = props.initial ? { ...latestValues } : {};
|
|
@@ -13535,7 +13126,6 @@ class VisualElement {
|
|
|
13535
13126
|
if (this.handleChildMotionValue) {
|
|
13536
13127
|
this.handleChildMotionValue();
|
|
13537
13128
|
}
|
|
13538
|
-
this.onUpdate && this.onUpdate(this);
|
|
13539
13129
|
}
|
|
13540
13130
|
getProps() {
|
|
13541
13131
|
return this.props;
|
|
@@ -13695,6 +13285,202 @@ class VisualElement {
|
|
|
13695
13285
|
}
|
|
13696
13286
|
}
|
|
13697
13287
|
|
|
13288
|
+
/**
|
|
13289
|
+
* Parse Framer's special CSS variable format into a CSS token and a fallback.
|
|
13290
|
+
*
|
|
13291
|
+
* ```
|
|
13292
|
+
* `var(--foo, #fff)` => [`--foo`, '#fff']
|
|
13293
|
+
* ```
|
|
13294
|
+
*
|
|
13295
|
+
* @param current
|
|
13296
|
+
*/
|
|
13297
|
+
const splitCSSVariableRegex =
|
|
13298
|
+
// eslint-disable-next-line redos-detector/no-unsafe-regex -- false positive, as it can match a lot of words
|
|
13299
|
+
/^var\(--(?:([\w-]+)|([\w-]+), ?([a-zA-Z\d ()%#.,-]+))\)/u;
|
|
13300
|
+
function parseCSSVariable(current) {
|
|
13301
|
+
const match = splitCSSVariableRegex.exec(current);
|
|
13302
|
+
if (!match)
|
|
13303
|
+
return [,];
|
|
13304
|
+
const [, token1, token2, fallback] = match;
|
|
13305
|
+
return [`--${token1 ?? token2}`, fallback];
|
|
13306
|
+
}
|
|
13307
|
+
const maxDepth = 4;
|
|
13308
|
+
function getVariableValue(current, element, depth = 1) {
|
|
13309
|
+
invariant(depth <= maxDepth, `Max CSS variable fallback depth detected in property "${current}". This may indicate a circular fallback dependency.`);
|
|
13310
|
+
const [token, fallback] = parseCSSVariable(current);
|
|
13311
|
+
// No CSS variable detected
|
|
13312
|
+
if (!token)
|
|
13313
|
+
return;
|
|
13314
|
+
// Attempt to read this CSS variable off the element
|
|
13315
|
+
const resolved = window.getComputedStyle(element).getPropertyValue(token);
|
|
13316
|
+
if (resolved) {
|
|
13317
|
+
const trimmed = resolved.trim();
|
|
13318
|
+
return isNumericalString(trimmed) ? parseFloat(trimmed) : trimmed;
|
|
13319
|
+
}
|
|
13320
|
+
return isCSSVariableToken(fallback)
|
|
13321
|
+
? getVariableValue(fallback, element, depth + 1)
|
|
13322
|
+
: fallback;
|
|
13323
|
+
}
|
|
13324
|
+
|
|
13325
|
+
function isNone(value) {
|
|
13326
|
+
if (typeof value === "number") {
|
|
13327
|
+
return value === 0;
|
|
13328
|
+
}
|
|
13329
|
+
else if (value !== null) {
|
|
13330
|
+
return value === "none" || value === "0" || isZeroValueString(value);
|
|
13331
|
+
}
|
|
13332
|
+
else {
|
|
13333
|
+
return true;
|
|
13334
|
+
}
|
|
13335
|
+
}
|
|
13336
|
+
|
|
13337
|
+
/**
|
|
13338
|
+
* If we encounter keyframes like "none" or "0" and we also have keyframes like
|
|
13339
|
+
* "#fff" or "200px 200px" we want to find a keyframe to serve as a template for
|
|
13340
|
+
* the "none" keyframes. In this case "#fff" or "200px 200px" - then these get turned into
|
|
13341
|
+
* zero equivalents, i.e. "#fff0" or "0px 0px".
|
|
13342
|
+
*/
|
|
13343
|
+
const invalidTemplates = new Set(["auto", "none", "0"]);
|
|
13344
|
+
function makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name) {
|
|
13345
|
+
let i = 0;
|
|
13346
|
+
let animatableTemplate = undefined;
|
|
13347
|
+
while (i < unresolvedKeyframes.length && !animatableTemplate) {
|
|
13348
|
+
const keyframe = unresolvedKeyframes[i];
|
|
13349
|
+
if (typeof keyframe === "string" &&
|
|
13350
|
+
!invalidTemplates.has(keyframe) &&
|
|
13351
|
+
analyseComplexValue(keyframe).values.length) {
|
|
13352
|
+
animatableTemplate = unresolvedKeyframes[i];
|
|
13353
|
+
}
|
|
13354
|
+
i++;
|
|
13355
|
+
}
|
|
13356
|
+
if (animatableTemplate && name) {
|
|
13357
|
+
for (const noneIndex of noneKeyframeIndexes) {
|
|
13358
|
+
unresolvedKeyframes[noneIndex] = getAnimatableNone(name, animatableTemplate);
|
|
13359
|
+
}
|
|
13360
|
+
}
|
|
13361
|
+
}
|
|
13362
|
+
|
|
13363
|
+
class DOMKeyframesResolver extends KeyframeResolver {
|
|
13364
|
+
constructor(unresolvedKeyframes, onComplete, name, motionValue, element) {
|
|
13365
|
+
super(unresolvedKeyframes, onComplete, name, motionValue, element, true);
|
|
13366
|
+
}
|
|
13367
|
+
readKeyframes() {
|
|
13368
|
+
const { unresolvedKeyframes, element, name } = this;
|
|
13369
|
+
if (!element || !element.current)
|
|
13370
|
+
return;
|
|
13371
|
+
super.readKeyframes();
|
|
13372
|
+
/**
|
|
13373
|
+
* If any keyframe is a CSS variable, we need to find its value by sampling the element
|
|
13374
|
+
*/
|
|
13375
|
+
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
13376
|
+
let keyframe = unresolvedKeyframes[i];
|
|
13377
|
+
if (typeof keyframe === "string") {
|
|
13378
|
+
keyframe = keyframe.trim();
|
|
13379
|
+
if (isCSSVariableToken(keyframe)) {
|
|
13380
|
+
const resolved = getVariableValue(keyframe, element.current);
|
|
13381
|
+
if (resolved !== undefined) {
|
|
13382
|
+
unresolvedKeyframes[i] = resolved;
|
|
13383
|
+
}
|
|
13384
|
+
if (i === unresolvedKeyframes.length - 1) {
|
|
13385
|
+
this.finalKeyframe = keyframe;
|
|
13386
|
+
}
|
|
13387
|
+
}
|
|
13388
|
+
}
|
|
13389
|
+
}
|
|
13390
|
+
/**
|
|
13391
|
+
* Resolve "none" values. We do this potentially twice - once before and once after measuring keyframes.
|
|
13392
|
+
* This could be seen as inefficient but it's a trade-off to avoid measurements in more situations, which
|
|
13393
|
+
* have a far bigger performance impact.
|
|
13394
|
+
*/
|
|
13395
|
+
this.resolveNoneKeyframes();
|
|
13396
|
+
/**
|
|
13397
|
+
* Check to see if unit type has changed. If so schedule jobs that will
|
|
13398
|
+
* temporarily set styles to the destination keyframes.
|
|
13399
|
+
* Skip if we have more than two keyframes or this isn't a positional value.
|
|
13400
|
+
* TODO: We can throw if there are multiple keyframes and the value type changes.
|
|
13401
|
+
*/
|
|
13402
|
+
if (!positionalKeys.has(name) || unresolvedKeyframes.length !== 2) {
|
|
13403
|
+
return;
|
|
13404
|
+
}
|
|
13405
|
+
const [origin, target] = unresolvedKeyframes;
|
|
13406
|
+
const originType = findDimensionValueType(origin);
|
|
13407
|
+
const targetType = findDimensionValueType(target);
|
|
13408
|
+
/**
|
|
13409
|
+
* Either we don't recognise these value types or we can animate between them.
|
|
13410
|
+
*/
|
|
13411
|
+
if (originType === targetType)
|
|
13412
|
+
return;
|
|
13413
|
+
/**
|
|
13414
|
+
* If both values are numbers or pixels, we can animate between them by
|
|
13415
|
+
* converting them to numbers.
|
|
13416
|
+
*/
|
|
13417
|
+
if (isNumOrPxType(originType) && isNumOrPxType(targetType)) {
|
|
13418
|
+
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
13419
|
+
const value = unresolvedKeyframes[i];
|
|
13420
|
+
if (typeof value === "string") {
|
|
13421
|
+
unresolvedKeyframes[i] = parseFloat(value);
|
|
13422
|
+
}
|
|
13423
|
+
}
|
|
13424
|
+
}
|
|
13425
|
+
else {
|
|
13426
|
+
/**
|
|
13427
|
+
* Else, the only way to resolve this is by measuring the element.
|
|
13428
|
+
*/
|
|
13429
|
+
this.needsMeasurement = true;
|
|
13430
|
+
}
|
|
13431
|
+
}
|
|
13432
|
+
resolveNoneKeyframes() {
|
|
13433
|
+
const { unresolvedKeyframes, name } = this;
|
|
13434
|
+
const noneKeyframeIndexes = [];
|
|
13435
|
+
for (let i = 0; i < unresolvedKeyframes.length; i++) {
|
|
13436
|
+
if (unresolvedKeyframes[i] === null ||
|
|
13437
|
+
isNone(unresolvedKeyframes[i])) {
|
|
13438
|
+
noneKeyframeIndexes.push(i);
|
|
13439
|
+
}
|
|
13440
|
+
}
|
|
13441
|
+
if (noneKeyframeIndexes.length) {
|
|
13442
|
+
makeNoneKeyframesAnimatable(unresolvedKeyframes, noneKeyframeIndexes, name);
|
|
13443
|
+
}
|
|
13444
|
+
}
|
|
13445
|
+
measureInitialState() {
|
|
13446
|
+
const { element, unresolvedKeyframes, name } = this;
|
|
13447
|
+
if (!element || !element.current)
|
|
13448
|
+
return;
|
|
13449
|
+
if (name === "height") {
|
|
13450
|
+
this.suspendedScrollY = window.pageYOffset;
|
|
13451
|
+
}
|
|
13452
|
+
this.measuredOrigin = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
13453
|
+
unresolvedKeyframes[0] = this.measuredOrigin;
|
|
13454
|
+
// Set final key frame to measure after next render
|
|
13455
|
+
const measureKeyframe = unresolvedKeyframes[unresolvedKeyframes.length - 1];
|
|
13456
|
+
if (measureKeyframe !== undefined) {
|
|
13457
|
+
element.getValue(name, measureKeyframe).jump(measureKeyframe, false);
|
|
13458
|
+
}
|
|
13459
|
+
}
|
|
13460
|
+
measureEndState() {
|
|
13461
|
+
const { element, name, unresolvedKeyframes } = this;
|
|
13462
|
+
if (!element || !element.current)
|
|
13463
|
+
return;
|
|
13464
|
+
const value = element.getValue(name);
|
|
13465
|
+
value && value.jump(this.measuredOrigin, false);
|
|
13466
|
+
const finalKeyframeIndex = unresolvedKeyframes.length - 1;
|
|
13467
|
+
const finalKeyframe = unresolvedKeyframes[finalKeyframeIndex];
|
|
13468
|
+
unresolvedKeyframes[finalKeyframeIndex] = positionalValues[name](element.measureViewportBox(), window.getComputedStyle(element.current));
|
|
13469
|
+
if (finalKeyframe !== null && this.finalKeyframe === undefined) {
|
|
13470
|
+
this.finalKeyframe = finalKeyframe;
|
|
13471
|
+
}
|
|
13472
|
+
// If we removed transform values, reapply them before the next render
|
|
13473
|
+
if (this.removedTransforms?.length) {
|
|
13474
|
+
this.removedTransforms.forEach(([unsetTransformName, unsetTransformValue]) => {
|
|
13475
|
+
element
|
|
13476
|
+
.getValue(unsetTransformName)
|
|
13477
|
+
.set(unsetTransformValue);
|
|
13478
|
+
});
|
|
13479
|
+
}
|
|
13480
|
+
this.resolveNoneKeyframes();
|
|
13481
|
+
}
|
|
13482
|
+
}
|
|
13483
|
+
|
|
13698
13484
|
class DOMVisualElement extends VisualElement {
|
|
13699
13485
|
constructor() {
|
|
13700
13486
|
super(...arguments);
|
|
@@ -13733,6 +13519,14 @@ class DOMVisualElement extends VisualElement {
|
|
|
13733
13519
|
}
|
|
13734
13520
|
}
|
|
13735
13521
|
|
|
13522
|
+
function renderHTML(element, { style, vars }, styleProp, projection) {
|
|
13523
|
+
Object.assign(element.style, style, projection && projection.getProjectionStyles(styleProp));
|
|
13524
|
+
// Loop over any CSS variables and assign those.
|
|
13525
|
+
for (const key in vars) {
|
|
13526
|
+
element.style.setProperty(key, vars[key]);
|
|
13527
|
+
}
|
|
13528
|
+
}
|
|
13529
|
+
|
|
13736
13530
|
function getComputedStyle$1(element) {
|
|
13737
13531
|
return window.getComputedStyle(element);
|
|
13738
13532
|
}
|
|
@@ -13765,17 +13559,48 @@ class HTMLVisualElement extends DOMVisualElement {
|
|
|
13765
13559
|
}
|
|
13766
13560
|
}
|
|
13767
13561
|
|
|
13562
|
+
/**
|
|
13563
|
+
* A set of attribute names that are always read/written as camel case.
|
|
13564
|
+
*/
|
|
13565
|
+
const camelCaseAttributes = new Set([
|
|
13566
|
+
"baseFrequency",
|
|
13567
|
+
"diffuseConstant",
|
|
13568
|
+
"kernelMatrix",
|
|
13569
|
+
"kernelUnitLength",
|
|
13570
|
+
"keySplines",
|
|
13571
|
+
"keyTimes",
|
|
13572
|
+
"limitingConeAngle",
|
|
13573
|
+
"markerHeight",
|
|
13574
|
+
"markerWidth",
|
|
13575
|
+
"numOctaves",
|
|
13576
|
+
"targetX",
|
|
13577
|
+
"targetY",
|
|
13578
|
+
"surfaceScale",
|
|
13579
|
+
"specularConstant",
|
|
13580
|
+
"specularExponent",
|
|
13581
|
+
"stdDeviation",
|
|
13582
|
+
"tableValues",
|
|
13583
|
+
"viewBox",
|
|
13584
|
+
"gradientTransform",
|
|
13585
|
+
"pathLength",
|
|
13586
|
+
"startOffset",
|
|
13587
|
+
"textLength",
|
|
13588
|
+
"lengthAdjust",
|
|
13589
|
+
]);
|
|
13590
|
+
|
|
13591
|
+
function renderSVG(element, renderState, _styleProp, projection) {
|
|
13592
|
+
renderHTML(element, renderState, undefined, projection);
|
|
13593
|
+
for (const key in renderState.attrs) {
|
|
13594
|
+
element.setAttribute(!camelCaseAttributes.has(key) ? camelToDash(key) : key, renderState.attrs[key]);
|
|
13595
|
+
}
|
|
13596
|
+
}
|
|
13597
|
+
|
|
13768
13598
|
class SVGVisualElement extends DOMVisualElement {
|
|
13769
13599
|
constructor() {
|
|
13770
13600
|
super(...arguments);
|
|
13771
13601
|
this.type = "svg";
|
|
13772
13602
|
this.isSVGTag = false;
|
|
13773
13603
|
this.measureInstanceViewportBox = createBox;
|
|
13774
|
-
this.updateDimensions = () => {
|
|
13775
|
-
if (this.current && !this.renderState.dimensions) {
|
|
13776
|
-
updateSVGDimensions(this.current, this.renderState);
|
|
13777
|
-
}
|
|
13778
|
-
};
|
|
13779
13604
|
}
|
|
13780
13605
|
getBaseTargetFromProps(props, key) {
|
|
13781
13606
|
return props[key];
|
|
@@ -13791,11 +13616,6 @@ class SVGVisualElement extends DOMVisualElement {
|
|
|
13791
13616
|
scrapeMotionValuesFromProps(props, prevProps, visualElement) {
|
|
13792
13617
|
return scrapeMotionValuesFromProps(props, prevProps, visualElement);
|
|
13793
13618
|
}
|
|
13794
|
-
onBindTransform() {
|
|
13795
|
-
if (this.current && !this.renderState.dimensions) {
|
|
13796
|
-
frame.postRender(this.updateDimensions);
|
|
13797
|
-
}
|
|
13798
|
-
}
|
|
13799
13619
|
build(renderState, latestValues, props) {
|
|
13800
13620
|
buildSVGAttrs(renderState, latestValues, this.isSVGTag, props.transformTemplate);
|
|
13801
13621
|
}
|
|
@@ -34122,20 +33942,20 @@ var initStripe = function initStripe(maybeStripe, args, startTime) {
|
|
|
34122
33942
|
return stripe;
|
|
34123
33943
|
}; // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
34124
33944
|
|
|
34125
|
-
var stripePromise
|
|
33945
|
+
var stripePromise;
|
|
34126
33946
|
var loadCalled = false;
|
|
34127
33947
|
|
|
34128
33948
|
var getStripePromise = function getStripePromise() {
|
|
34129
|
-
if (stripePromise
|
|
34130
|
-
return stripePromise
|
|
33949
|
+
if (stripePromise) {
|
|
33950
|
+
return stripePromise;
|
|
34131
33951
|
}
|
|
34132
33952
|
|
|
34133
|
-
stripePromise
|
|
33953
|
+
stripePromise = loadScript(null)["catch"](function (error) {
|
|
34134
33954
|
// clear cache on error
|
|
34135
|
-
stripePromise
|
|
33955
|
+
stripePromise = null;
|
|
34136
33956
|
return Promise.reject(error);
|
|
34137
33957
|
});
|
|
34138
|
-
return stripePromise
|
|
33958
|
+
return stripePromise;
|
|
34139
33959
|
}; // Execute our own script injection after a tick to give users time to do their
|
|
34140
33960
|
// own script injection.
|
|
34141
33961
|
|
|
@@ -34205,9 +34025,8 @@ const CheckoutForm$1 = ({ onSuccess, onError, children, setSubmitting, }) => {
|
|
|
34205
34025
|
};
|
|
34206
34026
|
var CheckoutForm$2 = memo$1(CheckoutForm$1);
|
|
34207
34027
|
|
|
34208
|
-
|
|
34209
|
-
const stripePromise = loadStripe(
|
|
34210
|
-
function PaymentElement({ paymentSecret, checkoutAppearance, locale, fonts, onSuccess, onError, children, setSubmitting, }) {
|
|
34028
|
+
function PaymentElement({ paymentSecret, publicKey, checkoutAppearance, locale, fonts, onSuccess, onError, children, setSubmitting, }) {
|
|
34029
|
+
const stripePromise = loadStripe(publicKey !== null && publicKey !== void 0 ? publicKey : "");
|
|
34211
34030
|
const options = {
|
|
34212
34031
|
locale: locale !== null && locale !== void 0 ? locale : "en",
|
|
34213
34032
|
appearance: checkoutAppearance,
|
|
@@ -34219,7 +34038,7 @@ function PaymentElement({ paymentSecret, checkoutAppearance, locale, fonts, onSu
|
|
|
34219
34038
|
}
|
|
34220
34039
|
var PaymentElement$1 = memo$1(PaymentElement);
|
|
34221
34040
|
|
|
34222
|
-
function PaymentForm({ paymentSecret, onSuccess, onError, onBack, onDoubleBack, contactEmail, shippingAddress, shippingName, shippingPrice, checkoutAppearance, fonts, locale, }) {
|
|
34041
|
+
function PaymentForm({ paymentSecret, onSuccess, onError, onBack, onDoubleBack, contactEmail, shippingAddress, shippingName, shippingPrice, checkoutAppearance, fonts, locale, publicKey, }) {
|
|
34223
34042
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
34224
34043
|
const { t } = useTranslation();
|
|
34225
34044
|
return (React__default.createElement("div", { className: "space-y-6" },
|
|
@@ -34248,7 +34067,7 @@ function PaymentForm({ paymentSecret, onSuccess, onError, onBack, onDoubleBack,
|
|
|
34248
34067
|
" \u00B7 ",
|
|
34249
34068
|
shippingPrice)),
|
|
34250
34069
|
React__default.createElement(Button, { variant: "link", size: "link", onClick: onBack }, t("CheckoutEmbed.Shipping.change")))),
|
|
34251
|
-
React__default.createElement("div", { className: "mt-8" }, paymentSecret && (React__default.createElement(PaymentElement$1, { fonts: fonts, checkoutAppearance: convertCheckoutAppearanceToStripeAppearance(checkoutAppearance, fonts), locale: locale, paymentSecret: paymentSecret, onSuccess: onSuccess, onError: onError, setSubmitting: setIsSubmitting },
|
|
34070
|
+
React__default.createElement("div", { className: "mt-8" }, paymentSecret && (React__default.createElement(PaymentElement$1, { fonts: fonts, checkoutAppearance: convertCheckoutAppearanceToStripeAppearance(checkoutAppearance, fonts), locale: locale, paymentSecret: paymentSecret, onSuccess: onSuccess, onError: onError, setSubmitting: setIsSubmitting, publicKey: publicKey },
|
|
34252
34071
|
React__default.createElement("div", { className: "flex justify-between items-center pt-8" },
|
|
34253
34072
|
React__default.createElement(Button, { type: "button", variant: "ghost", onClick: onBack },
|
|
34254
34073
|
React__default.createElement(ChevronLeft, null),
|
|
@@ -34416,6 +34235,8 @@ const useFormStore = create()(persist((set) => ({
|
|
|
34416
34235
|
setFormData: (formData) => set({ formData }),
|
|
34417
34236
|
step: "customer",
|
|
34418
34237
|
setStep: (step) => set({ step }),
|
|
34238
|
+
checkoutId: "",
|
|
34239
|
+
setCheckoutId: (checkoutId) => set({ checkoutId }),
|
|
34419
34240
|
}), { name: `checkout` }));
|
|
34420
34241
|
|
|
34421
34242
|
const motionSettings = {
|
|
@@ -34425,8 +34246,9 @@ const motionSettings = {
|
|
|
34425
34246
|
transition: { duration: 0.2 },
|
|
34426
34247
|
};
|
|
34427
34248
|
function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl, clientSecret, customer, currency, checkoutAppearance, fonts, locale, setShippingCost, exchangeRate, }) {
|
|
34428
|
-
const { formData, setFormData, step, setStep } = useFormStore();
|
|
34249
|
+
const { formData, setFormData, step, setStep, checkoutId: storedCheckoutId, setCheckoutId, } = useFormStore();
|
|
34429
34250
|
const [paymentSecret, setPaymentSecret] = useState(null);
|
|
34251
|
+
const [publicKey, setPublicKey] = useState(null);
|
|
34430
34252
|
const [shippingRates, setShippingRates] = useState([]);
|
|
34431
34253
|
const validateStep = useCallback(() => {
|
|
34432
34254
|
if (step === "customer")
|
|
@@ -34448,21 +34270,53 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34448
34270
|
validateStep();
|
|
34449
34271
|
}, [step]);
|
|
34450
34272
|
useEffect(() => {
|
|
34451
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
|
|
34452
|
-
if (
|
|
34273
|
+
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;
|
|
34274
|
+
if (checkoutId !== storedCheckoutId) {
|
|
34275
|
+
setStep("customer");
|
|
34276
|
+
setCheckoutId(checkoutId);
|
|
34277
|
+
if (customer) {
|
|
34278
|
+
setFormData({
|
|
34279
|
+
customerId: customer.id,
|
|
34280
|
+
customer: {
|
|
34281
|
+
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 : "",
|
|
34282
|
+
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 : "",
|
|
34283
|
+
phone: (_h = (_g = customer.address) === null || _g === void 0 ? void 0 : _g.phone) !== null && _h !== void 0 ? _h : "",
|
|
34284
|
+
email: (_j = customer.email) !== null && _j !== void 0 ? _j : "",
|
|
34285
|
+
address: {
|
|
34286
|
+
line1: (_l = (_k = customer.address) === null || _k === void 0 ? void 0 : _k.line1) !== null && _l !== void 0 ? _l : "",
|
|
34287
|
+
line2: (_o = (_m = customer.address) === null || _m === void 0 ? void 0 : _m.line2) !== null && _o !== void 0 ? _o : "",
|
|
34288
|
+
city: (_q = (_p = customer.address) === null || _p === void 0 ? void 0 : _p.city) !== null && _q !== void 0 ? _q : "",
|
|
34289
|
+
zipCode: (_s = (_r = customer.address) === null || _r === void 0 ? void 0 : _r.zipCode) !== null && _s !== void 0 ? _s : "",
|
|
34290
|
+
country: (_u = (_t = customer.address) === null || _t === void 0 ? void 0 : _t.country) !== null && _u !== void 0 ? _u : "",
|
|
34291
|
+
countryCode: (_w = (_v = customer.address) === null || _v === void 0 ? void 0 : _v.countryCode) !== null && _w !== void 0 ? _w : "",
|
|
34292
|
+
},
|
|
34293
|
+
},
|
|
34294
|
+
});
|
|
34295
|
+
}
|
|
34296
|
+
else if ((_x = formData.customer) === null || _x === void 0 ? void 0 : _x.email) {
|
|
34297
|
+
setFormData({
|
|
34298
|
+
customer: formData.customer,
|
|
34299
|
+
});
|
|
34300
|
+
}
|
|
34301
|
+
else {
|
|
34302
|
+
setFormData({});
|
|
34303
|
+
}
|
|
34304
|
+
return;
|
|
34305
|
+
}
|
|
34306
|
+
if (customer && !((_y = formData.customer) === null || _y === void 0 ? void 0 : _y.email)) {
|
|
34453
34307
|
const step = customer.id ? "shipping" : "customer";
|
|
34454
34308
|
setFormData(Object.assign(Object.assign({}, formData), { customerId: customer.id, customer: {
|
|
34455
|
-
firstName: (
|
|
34456
|
-
lastName: (
|
|
34457
|
-
phone: (
|
|
34458
|
-
email: (
|
|
34309
|
+
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 : "",
|
|
34310
|
+
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 : "",
|
|
34311
|
+
phone: (_6 = (_5 = customer.address) === null || _5 === void 0 ? void 0 : _5.phone) !== null && _6 !== void 0 ? _6 : "",
|
|
34312
|
+
email: (_7 = customer.email) !== null && _7 !== void 0 ? _7 : "",
|
|
34459
34313
|
address: {
|
|
34460
|
-
line1: (
|
|
34461
|
-
line2: (
|
|
34462
|
-
city: (
|
|
34463
|
-
zipCode: (
|
|
34464
|
-
country: (
|
|
34465
|
-
countryCode: (
|
|
34314
|
+
line1: (_9 = (_8 = customer.address) === null || _8 === void 0 ? void 0 : _8.line1) !== null && _9 !== void 0 ? _9 : "",
|
|
34315
|
+
line2: (_11 = (_10 = customer.address) === null || _10 === void 0 ? void 0 : _10.line2) !== null && _11 !== void 0 ? _11 : "",
|
|
34316
|
+
city: (_13 = (_12 = customer.address) === null || _12 === void 0 ? void 0 : _12.city) !== null && _13 !== void 0 ? _13 : "",
|
|
34317
|
+
zipCode: (_15 = (_14 = customer.address) === null || _14 === void 0 ? void 0 : _14.zipCode) !== null && _15 !== void 0 ? _15 : "",
|
|
34318
|
+
country: (_17 = (_16 = customer.address) === null || _16 === void 0 ? void 0 : _16.country) !== null && _17 !== void 0 ? _17 : "",
|
|
34319
|
+
countryCode: (_19 = (_18 = customer.address) === null || _18 === void 0 ? void 0 : _18.countryCode) !== null && _19 !== void 0 ? _19 : "",
|
|
34466
34320
|
},
|
|
34467
34321
|
} }));
|
|
34468
34322
|
setStep(step);
|
|
@@ -34526,8 +34380,9 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34526
34380
|
pickupPointId: data.pickupPointId,
|
|
34527
34381
|
},
|
|
34528
34382
|
});
|
|
34529
|
-
const paymentSecret = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34383
|
+
const { paymentSecret, publicKey } = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34530
34384
|
setPaymentSecret(paymentSecret);
|
|
34385
|
+
setPublicKey(publicKey);
|
|
34531
34386
|
setShippingCost(data.price);
|
|
34532
34387
|
setStep("payment");
|
|
34533
34388
|
});
|
|
@@ -34546,8 +34401,9 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34546
34401
|
};
|
|
34547
34402
|
useEffect(() => {
|
|
34548
34403
|
const asyncFunc = () => __awaiter(this, void 0, void 0, function* () {
|
|
34549
|
-
const paymentSecret = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34404
|
+
const { paymentSecret, publicKey } = yield storeClient.generateCheckoutsPaymentSecret(clientSecret, checkoutId);
|
|
34550
34405
|
setPaymentSecret(paymentSecret);
|
|
34406
|
+
setPublicKey(publicKey);
|
|
34551
34407
|
});
|
|
34552
34408
|
if (!paymentSecret && step === "payment") {
|
|
34553
34409
|
asyncFunc();
|
|
@@ -34560,7 +34416,7 @@ function CheckoutForm({ storeClient, checkoutId, onSuccess, onError, cancelUrl,
|
|
|
34560
34416
|
step === "shipping" && formData.customer && (React__default.createElement(motion.div, Object.assign({ key: "shipping" }, motionSettings, { className: "absolute w-full" }),
|
|
34561
34417
|
React__default.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 }))),
|
|
34562
34418
|
step === "payment" && formData.customer && formData.shipping && (React__default.createElement(motion.div, Object.assign({ key: "payment" }, motionSettings, { className: "absolute w-full" }),
|
|
34563
|
-
React__default.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) }))))));
|
|
34419
|
+
React__default.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 }))))));
|
|
34564
34420
|
}
|
|
34565
34421
|
|
|
34566
34422
|
function CheckoutFormLoading() {
|