From 969638fb94a0a14c64a667fa6e5689f79d9f1044 Mon Sep 17 00:00:00 2001 From: Niklas von Hertzen Date: Fri, 13 Aug 2021 18:15:55 +0800 Subject: [PATCH] fix: finish animation/transitions for elements (#2632) --- src/css/IPropertyDescriptor.ts | 4 +- src/css/index.ts | 8 ++ src/css/property-descriptors/duration.ts | 9 ++ src/css/property-descriptors/overflow-wrap.ts | 2 +- src/css/syntax/tokenizer.ts | 2 +- src/css/types/index.ts | 2 +- src/css/types/time.ts | 20 ++++ src/dom/element-container.ts | 17 +++- tests/reftests/animation.html | 96 +++++++++++++------ 9 files changed, 123 insertions(+), 37 deletions(-) create mode 100644 src/css/property-descriptors/duration.ts create mode 100644 src/css/types/time.ts diff --git a/src/css/IPropertyDescriptor.ts b/src/css/IPropertyDescriptor.ts index 8fc9e92..ff3438b 100644 --- a/src/css/IPropertyDescriptor.ts +++ b/src/css/IPropertyDescriptor.ts @@ -1,8 +1,8 @@ import {CSSValue} from './syntax/parser'; -import {CSSTypes} from './types/index'; +import {CSSTypes} from './types'; import {Context} from '../core/context'; -export enum PropertyDescriptorParsingType { +export const enum PropertyDescriptorParsingType { VALUE, LIST, IDENT_VALUE, diff --git a/src/css/index.ts b/src/css/index.ts index e1ab483..f81f692 100644 --- a/src/css/index.ts +++ b/src/css/index.ts @@ -57,6 +57,7 @@ import {Tokenizer} from './syntax/tokenizer'; import {Color, color as colorType, isTransparent} from './types/color'; import {angle} from './types/angle'; import {image} from './types/image'; +import {time} from './types/time'; import {opacity} from './property-descriptors/opacity'; import {textDecorationColor} from './property-descriptors/text-decoration-color'; import {textDecorationLine} from './property-descriptors/text-decoration-line'; @@ -71,6 +72,7 @@ import {contains} from '../core/bitwise'; import {content} from './property-descriptors/content'; import {counterIncrement} from './property-descriptors/counter-increment'; import {counterReset} from './property-descriptors/counter-reset'; +import {duration} from './property-descriptors/duration'; import {quotes} from './property-descriptors/quotes'; import {boxShadow} from './property-descriptors/box-shadow'; import {paintOrder} from './property-descriptors/paint-order'; @@ -79,6 +81,7 @@ import {webkitTextStrokeWidth} from './property-descriptors/webkit-text-stroke-w import {Context} from '../core/context'; export class CSSParsedDeclaration { + animationDuration: ReturnType; backgroundClip: ReturnType; backgroundColor: Color; backgroundImage: ReturnType; @@ -138,6 +141,7 @@ export class CSSParsedDeclaration { textTransform: ReturnType; transform: ReturnType; transformOrigin: ReturnType; + transitionDuration: ReturnType; visibility: ReturnType; webkitTextStrokeColor: Color; webkitTextStrokeWidth: ReturnType; @@ -145,6 +149,7 @@ export class CSSParsedDeclaration { zIndex: ReturnType; constructor(context: Context, declaration: CSSStyleDeclaration) { + this.animationDuration = parse(context, duration, declaration.animationDuration); this.backgroundClip = parse(context, backgroundClip, declaration.backgroundClip); this.backgroundColor = parse(context, backgroundColor, declaration.backgroundColor); this.backgroundImage = parse(context, backgroundImage, declaration.backgroundImage); @@ -213,6 +218,7 @@ export class CSSParsedDeclaration { this.textTransform = parse(context, textTransform, declaration.textTransform); this.transform = parse(context, transform, declaration.transform); this.transformOrigin = parse(context, transformOrigin, declaration.transformOrigin); + this.transitionDuration = parse(context, duration, declaration.transitionDuration); this.visibility = parse(context, visibility, declaration.visibility); this.webkitTextStrokeColor = parse(context, webkitTextStrokeColor, declaration.webkitTextStrokeColor); this.webkitTextStrokeWidth = parse(context, webkitTextStrokeWidth, declaration.webkitTextStrokeWidth); @@ -306,6 +312,8 @@ const parse = (context: Context, descriptor: CSSPropertyDescriptor, style?: case 'length-percentage': const value = parser.parseComponentValue(); return isLengthPercentage(value) ? value : ZERO_LENGTH; + case 'time': + return time.parse(context, parser.parseComponentValue()); } break; } diff --git a/src/css/property-descriptors/duration.ts b/src/css/property-descriptors/duration.ts new file mode 100644 index 0000000..2fa785a --- /dev/null +++ b/src/css/property-descriptors/duration.ts @@ -0,0 +1,9 @@ +import {IPropertyTypeValueDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor'; + +export const duration: IPropertyTypeValueDescriptor = { + name: 'duration', + initialValue: '0s', + prefix: false, + type: PropertyDescriptorParsingType.TYPE_VALUE, + format: 'time' +}; diff --git a/src/css/property-descriptors/overflow-wrap.ts b/src/css/property-descriptors/overflow-wrap.ts index e28887d..35ca43d 100644 --- a/src/css/property-descriptors/overflow-wrap.ts +++ b/src/css/property-descriptors/overflow-wrap.ts @@ -1,6 +1,6 @@ import {IPropertyIdentValueDescriptor, PropertyDescriptorParsingType} from '../IPropertyDescriptor'; import {Context} from '../../core/context'; -export enum OVERFLOW_WRAP { +export const enum OVERFLOW_WRAP { NORMAL = 'normal', BREAK_WORD = 'break-word' } diff --git a/src/css/syntax/tokenizer.ts b/src/css/syntax/tokenizer.ts index 7a1ba51..e050847 100644 --- a/src/css/syntax/tokenizer.ts +++ b/src/css/syntax/tokenizer.ts @@ -2,7 +2,7 @@ import {fromCodePoint, toCodePoints} from 'css-line-break'; -export enum TokenType { +export const enum TokenType { STRING_TOKEN, BAD_STRING_TOKEN, LEFT_PARENTHESIS_TOKEN, diff --git a/src/css/types/index.ts b/src/css/types/index.ts index 4279ff3..088e06e 100644 --- a/src/css/types/index.ts +++ b/src/css/types/index.ts @@ -1 +1 @@ -export type CSSTypes = 'angle' | 'color' | 'image' | 'length' | 'length-percentage'; +export type CSSTypes = 'angle' | 'color' | 'image' | 'length' | 'length-percentage' | 'time'; diff --git a/src/css/types/time.ts b/src/css/types/time.ts new file mode 100644 index 0000000..2b11a66 --- /dev/null +++ b/src/css/types/time.ts @@ -0,0 +1,20 @@ +import {CSSValue} from '../syntax/parser'; +import {TokenType} from '../syntax/tokenizer'; +import {ITypeDescriptor} from '../ITypeDescriptor'; +import {Context} from '../../core/context'; + +export const time: ITypeDescriptor = { + name: 'time', + parse: (_context: Context, value: CSSValue): number => { + if (value.type === TokenType.DIMENSION_TOKEN) { + switch (value.unit.toLowerCase()) { + case 's': + return 1000 * value.number; + case 'ms': + return value.number; + } + } + + throw new Error(`Unsupported time type`); + } +}; diff --git a/src/dom/element-container.ts b/src/dom/element-container.ts index 9928cc7..522cf2b 100644 --- a/src/dom/element-container.ts +++ b/src/dom/element-container.ts @@ -21,10 +21,21 @@ export class ElementContainer { this.styles = new CSSParsedDeclaration(context, window.getComputedStyle(element, null)); this.textNodes = []; this.elements = []; - if (this.styles.transform !== null && isHTMLElementNode(element)) { - // getBoundingClientRect takes transforms into account - element.style.transform = 'none'; + + if (isHTMLElementNode(element)) { + if (this.styles.animationDuration > 0) { + element.style.animationDuration = '0s'; + } + if (this.styles.transitionDuration > 0) { + element.style.transitionDuration = '0s'; + } + + if (this.styles.transform !== null) { + // getBoundingClientRect takes transforms into account + element.style.transform = 'none'; + } } + this.bounds = parseBounds(this.context, element); this.flags = 0; } diff --git a/tests/reftests/animation.html b/tests/reftests/animation.html index 55b3572..6986ffc 100644 --- a/tests/reftests/animation.html +++ b/tests/reftests/animation.html @@ -5,46 +5,84 @@ -
Some inline text followed by text in span followed by more inline text. -

Then a block level element.

- Then more inline text.
+
+

Hello

+
+ +
+

Hello

+
+ +
+

Hello

+
+ +
+

Hello

+