Skip to content

Commit 892594d

Browse files
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 <[email protected]>
1 parent bb1402e commit 892594d

File tree

15 files changed

+13
-468
lines changed

15 files changed

+13
-468
lines changed

BREAKING.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ This section details the desktop browser, JavaScript framework, and mobile platf
6060
| iOS | 15+ |
6161
| Android | 5.1+ with Chromium 89+ |
6262

63+
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.
64+
6365
<h2 id="version-8x-dark-mode">Dark Mode</h2>
6466

67+
6568
In previous versions, it was recommended to define the dark palette in the following way:
6669

6770
```css

core/src/utils/animation/animation-utils.ts

Lines changed: 0 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,5 @@
1-
import type { AnimationKeyFrames } from './animation-interface';
2-
31
let animationPrefix: string | undefined;
42

5-
/**
6-
* Web Animations requires hyphenated CSS properties
7-
* to be written in camelCase when animating
8-
*/
9-
export const processKeyframes = (keyframes: AnimationKeyFrames) => {
10-
keyframes.forEach((keyframe) => {
11-
for (const key in keyframe) {
12-
// eslint-disable-next-line no-prototype-builtins
13-
if (keyframe.hasOwnProperty(key)) {
14-
const value = keyframe[key];
15-
16-
if (key === 'easing') {
17-
const newKey = 'animation-timing-function';
18-
keyframe[newKey] = value;
19-
delete keyframe[key];
20-
} else {
21-
const newKey = convertCamelCaseToHypen(key);
22-
23-
if (newKey !== key) {
24-
keyframe[newKey] = value;
25-
delete keyframe[key];
26-
}
27-
}
28-
}
29-
}
30-
});
31-
32-
return keyframes;
33-
};
34-
35-
const convertCamelCaseToHypen = (str: string) => {
36-
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
37-
};
38-
393
export const getAnimationPrefix = (el: HTMLElement): string => {
404
if (animationPrefix === undefined) {
415
const supportsUnprefixed = el.style.animationName !== undefined;
@@ -50,99 +14,6 @@ export const setStyleProperty = (element: HTMLElement, propertyName: string, val
5014
element.style.setProperty(prefix + propertyName, value);
5115
};
5216

53-
export const removeStyleProperty = (element: HTMLElement, propertyName: string) => {
54-
const prefix = propertyName.startsWith('animation') ? getAnimationPrefix(element) : '';
55-
element.style.removeProperty(prefix + propertyName);
56-
};
57-
58-
export const animationEnd = (el: HTMLElement | null, callback: (ev?: TransitionEvent) => void) => {
59-
let unRegTrans: (() => void) | undefined;
60-
const opts: AddEventListenerOptions = { passive: true };
61-
62-
const unregister = () => {
63-
if (unRegTrans) {
64-
unRegTrans();
65-
}
66-
};
67-
68-
const onTransitionEnd = (ev: Event) => {
69-
if (el === ev.target) {
70-
unregister();
71-
callback(ev as TransitionEvent);
72-
}
73-
};
74-
75-
if (el) {
76-
el.addEventListener('webkitAnimationEnd', onTransitionEnd, opts);
77-
el.addEventListener('animationend', onTransitionEnd, opts);
78-
79-
unRegTrans = () => {
80-
el.removeEventListener('webkitAnimationEnd', onTransitionEnd, opts);
81-
el.removeEventListener('animationend', onTransitionEnd, opts);
82-
};
83-
}
84-
85-
return unregister;
86-
};
87-
88-
// TODO(FW-2832): type
89-
export const generateKeyframeRules = (keyframes: any[] = []) => {
90-
return keyframes
91-
.map((keyframe) => {
92-
const offset = keyframe.offset;
93-
94-
const frameString = [];
95-
for (const property in keyframe) {
96-
// eslint-disable-next-line no-prototype-builtins
97-
if (keyframe.hasOwnProperty(property) && property !== 'offset') {
98-
frameString.push(`${property}: ${keyframe[property]};`);
99-
}
100-
}
101-
102-
return `${offset * 100}% { ${frameString.join(' ')} }`;
103-
})
104-
.join(' ');
105-
};
106-
107-
const keyframeIds: string[] = [];
108-
109-
export const generateKeyframeName = (keyframeRules: string) => {
110-
let index = keyframeIds.indexOf(keyframeRules);
111-
if (index < 0) {
112-
index = keyframeIds.push(keyframeRules) - 1;
113-
}
114-
return `ion-animation-${index}`;
115-
};
116-
117-
export const getStyleContainer = (element: HTMLElement) => {
118-
// getRootNode is not always available in SSR environments.
119-
// TODO(FW-2832): types
120-
const rootNode = element.getRootNode !== undefined ? (element.getRootNode() as any) : element;
121-
return rootNode.head || rootNode;
122-
};
123-
124-
export const createKeyframeStylesheet = (
125-
keyframeName: string,
126-
keyframeRules: string,
127-
element: HTMLElement
128-
): HTMLElement => {
129-
const styleContainer = getStyleContainer(element);
130-
const keyframePrefix = getAnimationPrefix(element);
131-
132-
const existingStylesheet = styleContainer.querySelector('#' + keyframeName);
133-
if (existingStylesheet) {
134-
return existingStylesheet;
135-
}
136-
137-
const stylesheet = (element.ownerDocument ?? document).createElement('style');
138-
stylesheet.id = keyframeName;
139-
stylesheet.textContent = `@${keyframePrefix}keyframes ${keyframeName} { ${keyframeRules} } @${keyframePrefix}keyframes ${keyframeName}-alt { ${keyframeRules} }`;
140-
141-
styleContainer.appendChild(stylesheet);
142-
143-
return stylesheet;
144-
};
145-
14617
export const addClassToArray = (classes: string[] = [], className: string | string[] | undefined): string[] => {
14718
if (className !== undefined) {
14819
const classNameToAppend = Array.isArray(className) ? className : [className];

0 commit comments

Comments
 (0)