fix(animation): progressEnd coercion is reset before onFinish (#28394)

Issue number: resolves #28393

---------

<!-- Please do not submit updates to dependencies unless it fixes an
issue. -->

<!-- Please try to limit your pull request to one type (bugfix, feature,
etc). Submit multiple pull requests if needed. -->

## What is the current behavior?
<!-- Please describe the current behavior that you are modifying. -->

Our animation library's value coercion is not reset before developer
`onFinish` callbacks fire. This can lead to developers getting incorrect
state when querying for `getDuration` or `getDirection`

## What is the new behavior?
<!-- Please describe the behavior or changes that are being added by
this PR. -->

- Internal value coercion is reset before developer `onFinish` callbacks
fire.

## Does this introduce a breaking change?

- [ ] Yes
- [x] No

I'm putting this in a minor release to minimize risk. This is not a
breaking change, but there may be developers relying on this broken
behavior to implement a workaround.

<!-- If this introduces a breaking change, please describe the impact
and migration path for existing applications below. -->


## Other information

<!-- Any other information that is important to this PR such as
screenshots of how the component looks before and after the change. -->

Note: This change is needed for the toast swipe to dismiss feature
(FW-2004)
This commit is contained in:
Liam DeBeasi
2023-10-23 12:28:03 -04:00
committed by GitHub
parent 0e2797bd33
commit eae8162d0d
2 changed files with 30 additions and 15 deletions

View File

@@ -579,6 +579,17 @@ export const createAnimation = (animationId?: string): Animation => {
}
});
/**
* Clean up any value coercion before
* the user callbacks fire otherwise
* they may get stale values. For example,
* if someone calls progressStart(0) the
* animation may still be reversed.
*/
forceDurationValue = undefined;
forceDirectionValue = undefined;
forceDelayValue = undefined;
onFinishCallbacks.forEach((onFinishCallback) => {
return onFinishCallback.c(currentStep, ani);
});
@@ -826,21 +837,8 @@ export const createAnimation = (animationId?: string): Animation => {
}
}
if (playTo !== undefined) {
onFinish(
() => {
forceDurationValue = undefined;
forceDirectionValue = undefined;
forceDelayValue = undefined;
},
{
oneTimeCallback: true,
}
);
if (!parentAnimation) {
play();
}
if (playTo !== undefined && !parentAnimation) {
play();
}
return ani;

View File

@@ -4,6 +4,23 @@ import { processKeyframes } from '../animation-utils';
import { getTimeGivenProgression } from '../cubic-bezier';
describe('Animation Class', () => {
describe('progressEnd callbacks', () => {
test('coerced state should be reset before onFinish runs', (done) => {
const el = document.createElement('div');
const animation = createAnimation()
.addElement(el)
.fromTo('transform', 'translateX(0px)', 'translateX(100px)')
.duration(50);
animation
.onFinish(() => {
expect(animation.getDirection()).toBe('normal');
expect(animation.getDuration()).toBe(50);
done();
})
.progressEnd(0, 0.5, 10);
});
});
describe('play()', () => {
it('should resolve when the animation is cancelled', async () => {
// Tell Jest to expect 1 assertion for async code