feat: remove css animations support for ionic animations (#29123)

Issue number: Internal

---------

<!-- 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. -->

Ionic Framework provides a small utility wrapper around the Web
Animations API. Historically not all browsers that Ionic Framework
supported, had support for the Web Animations API. To offer backwards
compatibility, Ionic Framework provided fallback behaviors for the
different wrapped APIs.


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

- Removes the legacy CSS animations fallback behavior from the Web
Animations API animation utility. Maintaining a few no-op behaviors for
test environments.
- Resolved a few internal type usages that were casting to any
- Removed spec tests that were testing the fallback CSS animations
behavior and/or already had test coverage from other unit tests.

## Does this introduce a breaking change?

- [x] Yes
- [ ] No

<!--
  If this introduces a breaking change:
1. Describe the impact and migration path for existing applications
below.
  2. Update the BREAKING.md file with the breaking change.
3. Add "BREAKING CHANGE: [...]" to the commit description when merging.
See
https://github.com/ionic-team/ionic-framework/blob/main/.github/CONTRIBUTING.md#footer
for more information.
-->

All modern browsers support the Web Animations API today. If a developer
needs to target an older browser that does not support Web Animations,
they should either use [a
polyfill](https://github.com/web-animations/web-animations-js), or
implement the fallback behavior themselves.

## Other information

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

---------

Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
This commit is contained in:
Sean Perkins
2024-03-20 11:23:00 -04:00
committed by GitHub
parent bb1402e71e
commit 892594de06
15 changed files with 13 additions and 468 deletions

View File

@@ -60,8 +60,11 @@ This section details the desktop browser, JavaScript framework, and mobile platf
| iOS | 15+ | | iOS | 15+ |
| Android | 5.1+ with Chromium 89+ | | Android | 5.1+ with Chromium 89+ |
Ionic Framework v8 removes backwards support for CSS Animations in favor of the [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API). All minimum browser versions listed above support the Web Animations API.
<h2 id="version-8x-dark-mode">Dark Mode</h2> <h2 id="version-8x-dark-mode">Dark Mode</h2>
In previous versions, it was recommended to define the dark palette in the following way: In previous versions, it was recommended to define the dark palette in the following way:
```css ```css

View File

@@ -1,41 +1,5 @@
import type { AnimationKeyFrames } from './animation-interface';
let animationPrefix: string | undefined; let animationPrefix: string | undefined;
/**
* Web Animations requires hyphenated CSS properties
* to be written in camelCase when animating
*/
export const processKeyframes = (keyframes: AnimationKeyFrames) => {
keyframes.forEach((keyframe) => {
for (const key in keyframe) {
// eslint-disable-next-line no-prototype-builtins
if (keyframe.hasOwnProperty(key)) {
const value = keyframe[key];
if (key === 'easing') {
const newKey = 'animation-timing-function';
keyframe[newKey] = value;
delete keyframe[key];
} else {
const newKey = convertCamelCaseToHypen(key);
if (newKey !== key) {
keyframe[newKey] = value;
delete keyframe[key];
}
}
}
}
});
return keyframes;
};
const convertCamelCaseToHypen = (str: string) => {
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
};
export const getAnimationPrefix = (el: HTMLElement): string => { export const getAnimationPrefix = (el: HTMLElement): string => {
if (animationPrefix === undefined) { if (animationPrefix === undefined) {
const supportsUnprefixed = el.style.animationName !== undefined; const supportsUnprefixed = el.style.animationName !== undefined;
@@ -50,99 +14,6 @@ export const setStyleProperty = (element: HTMLElement, propertyName: string, val
element.style.setProperty(prefix + propertyName, value); element.style.setProperty(prefix + propertyName, value);
}; };
export const removeStyleProperty = (element: HTMLElement, propertyName: string) => {
const prefix = propertyName.startsWith('animation') ? getAnimationPrefix(element) : '';
element.style.removeProperty(prefix + propertyName);
};
export const animationEnd = (el: HTMLElement | null, callback: (ev?: TransitionEvent) => void) => {
let unRegTrans: (() => void) | undefined;
const opts: AddEventListenerOptions = { passive: true };
const unregister = () => {
if (unRegTrans) {
unRegTrans();
}
};
const onTransitionEnd = (ev: Event) => {
if (el === ev.target) {
unregister();
callback(ev as TransitionEvent);
}
};
if (el) {
el.addEventListener('webkitAnimationEnd', onTransitionEnd, opts);
el.addEventListener('animationend', onTransitionEnd, opts);
unRegTrans = () => {
el.removeEventListener('webkitAnimationEnd', onTransitionEnd, opts);
el.removeEventListener('animationend', onTransitionEnd, opts);
};
}
return unregister;
};
// TODO(FW-2832): type
export const generateKeyframeRules = (keyframes: any[] = []) => {
return keyframes
.map((keyframe) => {
const offset = keyframe.offset;
const frameString = [];
for (const property in keyframe) {
// eslint-disable-next-line no-prototype-builtins
if (keyframe.hasOwnProperty(property) && property !== 'offset') {
frameString.push(`${property}: ${keyframe[property]};`);
}
}
return `${offset * 100}% { ${frameString.join(' ')} }`;
})
.join(' ');
};
const keyframeIds: string[] = [];
export const generateKeyframeName = (keyframeRules: string) => {
let index = keyframeIds.indexOf(keyframeRules);
if (index < 0) {
index = keyframeIds.push(keyframeRules) - 1;
}
return `ion-animation-${index}`;
};
export const getStyleContainer = (element: HTMLElement) => {
// getRootNode is not always available in SSR environments.
// TODO(FW-2832): types
const rootNode = element.getRootNode !== undefined ? (element.getRootNode() as any) : element;
return rootNode.head || rootNode;
};
export const createKeyframeStylesheet = (
keyframeName: string,
keyframeRules: string,
element: HTMLElement
): HTMLElement => {
const styleContainer = getStyleContainer(element);
const keyframePrefix = getAnimationPrefix(element);
const existingStylesheet = styleContainer.querySelector('#' + keyframeName);
if (existingStylesheet) {
return existingStylesheet;
}
const stylesheet = (element.ownerDocument ?? document).createElement('style');
stylesheet.id = keyframeName;
stylesheet.textContent = `@${keyframePrefix}keyframes ${keyframeName} { ${keyframeRules} } @${keyframePrefix}keyframes ${keyframeName}-alt { ${keyframeRules} }`;
styleContainer.appendChild(stylesheet);
return stylesheet;
};
export const addClassToArray = (classes: string[] = [], className: string | string[] | undefined): string[] => { export const addClassToArray = (classes: string[] = [], className: string | string[] | undefined): string[] => {
if (className !== undefined) { if (className !== undefined) {
const classNameToAppend = Array.isArray(className) ? className : [className]; const classNameToAppend = Array.isArray(className) ? className : [className];

View File

@@ -1,5 +1,4 @@
import { win } from '../browser'; import { win } from '../browser';
import { raf } from '../helpers';
import type { import type {
Animation, Animation,
@@ -12,16 +11,7 @@ import type {
AnimationLifecycle, AnimationLifecycle,
AnimationPlayOptions, AnimationPlayOptions,
} from './animation-interface'; } from './animation-interface';
import { import { addClassToArray, setStyleProperty } from './animation-utils';
addClassToArray,
animationEnd,
createKeyframeStylesheet,
generateKeyframeName,
generateKeyframeRules,
processKeyframes,
removeStyleProperty,
setStyleProperty,
} from './animation-utils';
// TODO(FW-2832): types // TODO(FW-2832): types
@@ -64,7 +54,6 @@ export const createAnimation = (animationId?: string): Animation => {
let willComplete = true; let willComplete = true;
let finished = false; let finished = false;
let shouldCalculateNumAnimations = true; let shouldCalculateNumAnimations = true;
let keyframeName: string | undefined;
let ani: Animation; let ani: Animation;
let paused = false; let paused = false;
@@ -83,11 +72,17 @@ export const createAnimation = (animationId?: string): Animation => {
const supportsAnimationEffect = const supportsAnimationEffect =
typeof (AnimationEffect as any) === 'function' || typeof (AnimationEffect as any) === 'function' ||
(win !== undefined && typeof (win as any).AnimationEffect === 'function'); (win !== undefined && typeof (win as any).AnimationEffect === 'function');
/**
* This is a feature detection for Web Animations.
*
* Certain environments such as emulated browser environments for testing,
* do not support Web Animations. As a result, we need to check for support
* and provide a fallback to test certain functionality related to Web Animations.
*/
const supportsWebAnimations = const supportsWebAnimations =
typeof (Element as any) === 'function' && typeof (Element as any) === 'function' &&
typeof (Element as any).prototype!.animate === 'function' && typeof (Element as any).prototype!.animate === 'function' &&
supportsAnimationEffect; supportsAnimationEffect;
const ANIMATION_END_FALLBACK_PADDING_MS = 100;
const getWebAnimations = () => { const getWebAnimations = () => {
return webAnimations; return webAnimations;
@@ -198,21 +193,6 @@ export const createAnimation = (animationId?: string): Animation => {
}); });
webAnimations.length = 0; webAnimations.length = 0;
} else {
const elementsArray = elements.slice();
raf(() => {
elementsArray.forEach((element) => {
removeStyleProperty(element, 'animation-name');
removeStyleProperty(element, 'animation-duration');
removeStyleProperty(element, 'animation-timing-function');
removeStyleProperty(element, 'animation-iteration-count');
removeStyleProperty(element, 'animation-delay');
removeStyleProperty(element, 'animation-play-state');
removeStyleProperty(element, 'animation-fill-mode');
removeStyleProperty(element, 'animation-direction');
});
});
} }
}; };
@@ -533,8 +513,6 @@ export const createAnimation = (animationId?: string): Animation => {
animation.effect = newEffect; animation.effect = newEffect;
} }
}); });
} else {
initializeCSSAnimation();
} }
}; };
@@ -643,39 +621,6 @@ export const createAnimation = (animationId?: string): Animation => {
} }
}; };
const initializeCSSAnimation = (toggleAnimationName = true) => {
cleanUpStyleSheets();
const processedKeyframes = processKeyframes(_keyframes);
elements.forEach((element) => {
if (processedKeyframes.length > 0) {
const keyframeRules = generateKeyframeRules(processedKeyframes);
keyframeName = animationId !== undefined ? animationId : generateKeyframeName(keyframeRules);
const stylesheet = createKeyframeStylesheet(keyframeName, keyframeRules, element);
stylesheets.push(stylesheet);
setStyleProperty(element, 'animation-duration', `${getDuration()}ms`);
setStyleProperty(element, 'animation-timing-function', getEasing());
setStyleProperty(element, 'animation-delay', `${getDelay()}ms`);
setStyleProperty(element, 'animation-fill-mode', getFill());
setStyleProperty(element, 'animation-direction', getDirection());
const iterationsCount = getIterations() === Infinity ? 'infinite' : getIterations().toString();
setStyleProperty(element, 'animation-iteration-count', iterationsCount);
setStyleProperty(element, 'animation-play-state', 'paused');
if (toggleAnimationName) {
setStyleProperty(element, 'animation-name', `${stylesheet.id}-alt`);
}
raf(() => {
setStyleProperty(element, 'animation-name', stylesheet.id || null);
});
}
});
};
const initializeWebAnimation = () => { const initializeWebAnimation = () => {
elements.forEach((element) => { elements.forEach((element) => {
const animation = element.animate(_keyframes, { const animation = element.animate(_keyframes, {
@@ -700,14 +645,12 @@ export const createAnimation = (animationId?: string): Animation => {
} }
}; };
const initializeAnimation = (toggleAnimationName = true) => { const initializeAnimation = () => {
beforeAnimation(); beforeAnimation();
if (_keyframes.length > 0) { if (_keyframes.length > 0) {
if (supportsWebAnimations) { if (supportsWebAnimations) {
initializeWebAnimation(); initializeWebAnimation();
} else {
initializeCSSAnimation(toggleAnimationName);
} }
} }
@@ -722,15 +665,6 @@ export const createAnimation = (animationId?: string): Animation => {
animation.currentTime = animation.effect!.getComputedTiming().delay! + getDuration() * step; animation.currentTime = animation.effect!.getComputedTiming().delay! + getDuration() * step;
animation.pause(); animation.pause();
}); });
} else {
const animationDuration = `-${getDuration() * step}ms`;
elements.forEach((element) => {
if (_keyframes.length > 0) {
setStyleProperty(element, 'animation-delay', animationDuration);
setStyleProperty(element, 'animation-play-state', 'paused');
}
});
} }
}; };
@@ -751,35 +685,6 @@ export const createAnimation = (animationId?: string): Animation => {
} }
}; };
const updateCSSAnimation = (toggleAnimationName = true, step?: number) => {
raf(() => {
elements.forEach((element) => {
setStyleProperty(element, 'animation-name', keyframeName || null);
setStyleProperty(element, 'animation-duration', `${getDuration()}ms`);
setStyleProperty(element, 'animation-timing-function', getEasing());
setStyleProperty(
element,
'animation-delay',
step !== undefined ? `-${step! * getDuration()}ms` : `${getDelay()}ms`
);
setStyleProperty(element, 'animation-fill-mode', getFill() || null);
setStyleProperty(element, 'animation-direction', getDirection() || null);
const iterationsCount = getIterations() === Infinity ? 'infinite' : getIterations().toString();
setStyleProperty(element, 'animation-iteration-count', iterationsCount);
if (toggleAnimationName) {
setStyleProperty(element, 'animation-name', `${keyframeName}-alt`);
}
raf(() => {
setStyleProperty(element, 'animation-name', keyframeName || null);
});
});
});
};
const update = (deep = false, toggleAnimationName = true, step?: number) => { const update = (deep = false, toggleAnimationName = true, step?: number) => {
if (deep) { if (deep) {
childAnimations.forEach((animation) => { childAnimations.forEach((animation) => {
@@ -789,8 +694,6 @@ export const createAnimation = (animationId?: string): Animation => {
if (supportsWebAnimations) { if (supportsWebAnimations) {
updateWebAnimation(step); updateWebAnimation(step);
} else {
updateCSSAnimation(toggleAnimationName, step);
} }
return ani; return ani;
@@ -892,11 +795,6 @@ export const createAnimation = (animationId?: string): Animation => {
return ani; return ani;
}; };
const onAnimationEndFallback = () => {
cssAnimationsTimerFallback = undefined;
animationFinish();
};
const clearCSSAnimationsTimeout = () => { const clearCSSAnimationsTimeout = () => {
if (cssAnimationsTimerFallback) { if (cssAnimationsTimerFallback) {
clearTimeout(cssAnimationsTimerFallback); clearTimeout(cssAnimationsTimerFallback);
@@ -906,63 +804,7 @@ export const createAnimation = (animationId?: string): Animation => {
const playCSSAnimations = () => { const playCSSAnimations = () => {
clearCSSAnimationsTimeout(); clearCSSAnimationsTimeout();
raf(() => { animationFinish();
elements.forEach((element) => {
if (_keyframes.length > 0) {
setStyleProperty(element, 'animation-play-state', 'running');
}
});
});
if (_keyframes.length === 0 || elements.length === 0) {
animationFinish();
} else {
/**
* This is a catchall in the event that a CSS Animation did not finish.
* The Web Animations API has mechanisms in place for preventing this.
* CSS Animations will not fire an `animationend` event
* for elements with `display: none`. The Web Animations API
* accounts for this, but using raw CSS Animations requires
* this workaround.
*/
const animationDelay = getDelay() || 0;
const animationDuration = getDuration() || 0;
const animationIterations = getIterations() || 1;
// No need to set a timeout when animation has infinite iterations
if (isFinite(animationIterations)) {
cssAnimationsTimerFallback = setTimeout(
onAnimationEndFallback,
animationDelay + animationDuration * animationIterations + ANIMATION_END_FALLBACK_PADDING_MS
);
}
animationEnd(elements[0], () => {
clearCSSAnimationsTimeout();
/**
* Ensure that clean up
* is always done a frame
* before the onFinish handlers
* are fired. Otherwise, there
* may be flickering if a new
* animation is started on the same
* element too quickly
*/
raf(() => {
clearCSSAnimationPlayState();
raf(animationFinish);
});
});
}
};
const clearCSSAnimationPlayState = () => {
elements.forEach((element) => {
removeStyleProperty(element, 'animation-duration');
removeStyleProperty(element, 'animation-delay');
removeStyleProperty(element, 'animation-play-state');
});
}; };
const playWebAnimations = () => { const playWebAnimations = () => {
@@ -979,8 +821,6 @@ export const createAnimation = (animationId?: string): Animation => {
if (supportsWebAnimations) { if (supportsWebAnimations) {
setAnimationStep(0); setAnimationStep(0);
updateWebAnimation(); updateWebAnimation();
} else {
updateCSSAnimation();
} }
}; };

View File

@@ -1,6 +1,5 @@
import { createAnimation } from '../animation'; import { createAnimation } from '../animation';
import type { Animation } from '../animation-interface'; import type { Animation } from '../animation-interface';
import { processKeyframes } from '../animation-utils';
import { getTimeGivenProgression } from '../cubic-bezier'; import { getTimeGivenProgression } from '../cubic-bezier';
describe('Animation Class', () => { describe('Animation Class', () => {
@@ -53,104 +52,6 @@ describe('Animation Class', () => {
animation.play(); animation.play();
expect(animation.isRunning()).toEqual(false); expect(animation.isRunning()).toEqual(false);
}); });
it('should be running', () => {
const el = document.createElement('div');
animation.addElement(el);
animation.keyframes([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(0)', opacity: 0, offset: 1 },
]);
animation.duration(250);
animation.play();
expect(animation.isRunning()).toEqual(true);
});
it('should not be running after finishing the animation', async () => {
const el = document.createElement('div');
animation.addElement(el);
animation.keyframes([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(0)', opacity: 0, offset: 1 },
]);
animation.duration(250);
await animation.play();
expect(animation.isRunning()).toEqual(false);
});
it('should not be running after calling pause', () => {
const el = document.createElement('div');
animation.addElement(el);
animation.keyframes([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(0)', opacity: 0, offset: 1 },
]);
animation.duration(250);
animation.play();
expect(animation.isRunning()).toEqual(true);
animation.pause();
expect(animation.isRunning()).toEqual(false);
});
it('should not be running when doing progress steps', () => {
const el = document.createElement('div');
animation.addElement(el);
animation.keyframes([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(0)', opacity: 0, offset: 1 },
]);
animation.duration(250);
animation.play();
animation.progressStart();
expect(animation.isRunning()).toEqual(false);
});
it('should be running after calling progressEnd', () => {
const el = document.createElement('div');
animation.addElement(el);
animation.keyframes([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(0)', opacity: 0, offset: 1 },
]);
animation.duration(250);
animation.play();
animation.progressStart();
animation.progressEnd(1, 0);
expect(animation.isRunning()).toEqual(true);
});
it('should not be running after playing to beginning', async () => {
const el = document.createElement('div');
animation.addElement(el);
animation.keyframes([
{ transform: 'scale(1)', opacity: 1, offset: 0 },
{ transform: 'scale(0)', opacity: 0, offset: 1 },
]);
animation.duration(250);
await animation.play();
animation.progressStart();
animation.progressEnd(0, 0);
await new Promise<void>((resolve) => {
animation.onFinish(() => {
expect(animation.isRunning()).toEqual(false);
resolve();
});
});
});
}); });
describe('addElement()', () => { describe('addElement()', () => {
@@ -228,18 +129,6 @@ describe('Animation Class', () => {
expect(animation.getKeyframes().length).toEqual(3); expect(animation.getKeyframes().length).toEqual(3);
}); });
it('should convert properties for CSS Animations', () => {
const processedKeyframes = processKeyframes([
{ borderRadius: '0px', easing: 'ease-in', offset: 0 },
{ borderRadius: '4px', easing: 'ease-out', offset: 1 },
]);
expect(processedKeyframes).toEqual([
{ 'border-radius': '0px', 'animation-timing-function': 'ease-in', offset: 0 },
{ 'border-radius': '4px', 'animation-timing-function': 'ease-out', offset: 1 },
]);
});
it('should set the from keyframe properly', () => { it('should set the from keyframe properly', () => {
animation.from('opacity', 0).from('background', 'red').from('color', 'purple'); animation.from('opacity', 0).from('background', 'red').from('color', 'purple');

View File

@@ -12,11 +12,6 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await page.goto('/src/utils/animation/test/animationbuilder', config); await page.goto('/src/utils/animation/test/animationbuilder', config);
await testNavigation(page); await testNavigation(page);
}); });
test('ios-transition css', async ({ page }) => {
await page.goto('/src/utils/animation/test/animationbuilder?ionic:_forceCSSAnimations=true', config);
await testNavigation(page);
});
}); });
}); });

View File

@@ -13,11 +13,6 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script> <script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script> <script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<script> <script>
const forceCSSAnimations = new URLSearchParams(window.location.search).get('ionic:_forceCSSAnimations');
if (forceCSSAnimations) {
Element.prototype.animate = null;
}
class PageRoot extends HTMLElement { class PageRoot extends HTMLElement {
connectedCallback() { connectedCallback() {
this.innerHTML = ` this.innerHTML = `

View File

@@ -7,11 +7,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
await page.goto('/src/utils/animation/test/basic', config); await page.goto('/src/utils/animation/test/basic', config);
await testPage(page); await testPage(page);
}); });
test(`should resolve using css animations`, async ({ page }) => {
await page.goto('/src/utils/animation/test/basic?ionic:_forceCSSAnimations=true', config);
await testPage(page);
});
}); });
}); });

View File

@@ -13,11 +13,6 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script> <script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script> <script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<script type="module"> <script type="module">
const forceCSSAnimations = new URLSearchParams(window.location.search).get('ionic:_forceCSSAnimations');
if (forceCSSAnimations) {
Element.prototype.animate = null;
}
import { createAnimation } from '../../../../dist/ionic/index.esm.js'; import { createAnimation } from '../../../../dist/ionic/index.esm.js';
const squareA = document.querySelector('.square-a'); const squareA = document.querySelector('.square-a');

View File

@@ -8,11 +8,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
await page.goto('/src/utils/animation/test/display', config); await page.goto('/src/utils/animation/test/display', config);
await testDisplay(page); await testDisplay(page);
}); });
test(`should resolve using css animations`, async ({ page }) => {
await page.goto('/src/utils/animation/test/display?ionic:_forceCSSAnimations=true', config);
await testDisplay(page);
});
}); });
}); });

View File

@@ -13,11 +13,6 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script> <script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script> <script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<script type="module"> <script type="module">
const forceCSSAnimations = new URLSearchParams(window.location.search).get('ionic:_forceCSSAnimations');
if (forceCSSAnimations) {
Element.prototype.animate = null;
}
import { createAnimation } from '../../../../dist/ionic/index.esm.js'; import { createAnimation } from '../../../../dist/ionic/index.esm.js';
const squareA = document.querySelector('.square-a'); const squareA = document.querySelector('.square-a');

View File

@@ -8,11 +8,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
await page.goto('/src/utils/animation/test/hooks', config); await page.goto('/src/utils/animation/test/hooks', config);
await testHooks(page); await testHooks(page);
}); });
test(`should fire hooks using css animations`, async ({ page }) => {
await page.goto('/src/utils/animation/test/hooks?ionic:_forceCSSAnimations=true', config);
await testHooks(page);
});
}); });
}); });

View File

@@ -13,11 +13,6 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script> <script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script> <script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<script type="module"> <script type="module">
const forceCSSAnimations = new URLSearchParams(window.location.search).get('ionic:_forceCSSAnimations');
if (forceCSSAnimations) {
Element.prototype.animate = null;
}
import { createAnimation } from '../../../../dist/ionic/index.esm.js'; import { createAnimation } from '../../../../dist/ionic/index.esm.js';
const squareA = document.querySelector('.square-a'); const squareA = document.querySelector('.square-a');

View File

@@ -8,14 +8,6 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
await page.goto('/src/utils/animation/test/multiple', config); await page.goto('/src/utils/animation/test/multiple', config);
await testMultiple(page); await testMultiple(page);
}); });
/**
* CSS animations will occasionally resolve out of order, so we skip for now
*/
test.skip(`should resolve grouped animations using css animations`, async ({ page }) => {
await page.goto('/src/utils/animation/test/multiple?ionic:_forceCSSAnimations=true', config);
await testMultiple(page);
});
}); });
}); });

View File

@@ -13,11 +13,6 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script> <script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script> <script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<script type="module"> <script type="module">
const forceCSSAnimations = new URLSearchParams(window.location.search).get('ionic:_forceCSSAnimations');
if (forceCSSAnimations) {
Element.prototype.animate = null;
}
import { createAnimation } from '../../../../dist/ionic/index.esm.js'; import { createAnimation } from '../../../../dist/ionic/index.esm.js';
const squareA = document.querySelector('.square-a'); const squareA = document.querySelector('.square-a');

View File

@@ -13,11 +13,6 @@
<script nomodule src="../../../../../dist/ionic/ionic.js"></script> <script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script> <script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<script type="module"> <script type="module">
const forceCSSAnimations = new URLSearchParams(window.location.search).get('ionic:_forceCSSAnimations');
if (forceCSSAnimations) {
Element.prototype.animate = null;
}
import { createAnimation } from '../../../../dist/ionic/index.esm.js'; import { createAnimation } from '../../../../dist/ionic/index.esm.js';
createAnimation() createAnimation()