mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
150 lines
5.9 KiB
TypeScript
150 lines
5.9 KiB
TypeScript
import { CssAnimationProperty } from "../core/properties";
|
|
|
|
import {
|
|
KeyframeAnimationInfo,
|
|
KeyframeDeclaration,
|
|
KeyframeInfo,
|
|
UnparsedKeyframe,
|
|
} from "../animation/keyframe-animation";
|
|
import { timeConverter, animationTimingFunctionConverter } from "../styling/converters";
|
|
|
|
import { transformConverter } from "../styling/style-properties";
|
|
|
|
const ANIMATION_PROPERTY_HANDLERS = Object.freeze({
|
|
"animation-name": (info, value) => info.name = value,
|
|
"animation-duration": (info, value) => info.duration = timeConverter(value),
|
|
"animation-delay": (info, value) => info.delay = timeConverter(value),
|
|
"animation-timing-function": (info, value) => info.curve = animationTimingFunctionConverter(value),
|
|
"animation-iteration-count": (info, value) => info.iterations = value === "infinite" ? Number.MAX_VALUE : parseFloat(value),
|
|
"animation-direction": (info, value) => info.isReverse = value === "reverse",
|
|
"animation-fill-mode": (info, value) => info.isForwards = value === "forwards"
|
|
});
|
|
|
|
export class CssAnimationParser {
|
|
public static keyframeAnimationsFromCSSDeclarations(
|
|
declarations: Array<KeyframeDeclaration>)
|
|
: Array<KeyframeAnimationInfo> {
|
|
|
|
if (declarations === null || declarations === undefined) {
|
|
return undefined;
|
|
}
|
|
|
|
let animations = new Array<KeyframeAnimationInfo>();
|
|
let animationInfo: KeyframeAnimationInfo = undefined;
|
|
|
|
declarations.forEach(({ property, value }) => {
|
|
if (property === "animation") {
|
|
keyframeAnimationsFromCSSProperty(value, animations);
|
|
} else {
|
|
const propertyHandler = ANIMATION_PROPERTY_HANDLERS[property];
|
|
if (propertyHandler) {
|
|
if (animationInfo === undefined) {
|
|
animationInfo = new KeyframeAnimationInfo();
|
|
animations.push(animationInfo);
|
|
}
|
|
propertyHandler(animationInfo, value);
|
|
}
|
|
}
|
|
});
|
|
|
|
return animations.length === 0 ? undefined : animations;
|
|
}
|
|
|
|
public static keyframesArrayFromCSS(keyframes: Array<UnparsedKeyframe>): Array<KeyframeInfo> {
|
|
let parsedKeyframes = new Array<KeyframeInfo>();
|
|
for (let keyframe of keyframes) {
|
|
let declarations = parseKeyframeDeclarations(keyframe.declarations);
|
|
for (let time of keyframe.values) {
|
|
if (time === "from") {
|
|
time = 0;
|
|
} else if (time === "to") {
|
|
time = 1;
|
|
} else {
|
|
time = parseFloat(time) / 100;
|
|
if (time < 0) {
|
|
time = 0;
|
|
}
|
|
if (time > 100) {
|
|
time = 100;
|
|
}
|
|
}
|
|
let current = parsedKeyframes[time];
|
|
if (current === undefined) {
|
|
current = <KeyframeInfo>{};
|
|
current.duration = time;
|
|
parsedKeyframes[time] = current;
|
|
}
|
|
for (let declaration of keyframe.declarations) {
|
|
if (declaration.property === "animation-timing-function") {
|
|
current.curve = animationTimingFunctionConverter(declaration.value);
|
|
}
|
|
}
|
|
current.declarations = declarations;
|
|
}
|
|
}
|
|
let array = new Array();
|
|
for (let parsedKeyframe in parsedKeyframes) {
|
|
array.push(parsedKeyframes[parsedKeyframe]);
|
|
}
|
|
array.sort(function (a, b) { return a.duration - b.duration; });
|
|
|
|
return array;
|
|
}
|
|
}
|
|
|
|
function keyframeAnimationsFromCSSProperty(value: any, animations: Array<KeyframeAnimationInfo>) {
|
|
if (typeof value === "string") {
|
|
let values = value.split(/[,]+/);
|
|
for (let parsedValue of values) {
|
|
let animationInfo = new KeyframeAnimationInfo();
|
|
let arr = (<string>parsedValue).trim().split(/[ ]+/);
|
|
|
|
if (arr.length > 0) {
|
|
animationInfo.name = arr[0];
|
|
}
|
|
if (arr.length > 1) {
|
|
animationInfo.duration = timeConverter(arr[1]);
|
|
}
|
|
if (arr.length > 2) {
|
|
animationInfo.curve = animationTimingFunctionConverter(arr[2]);
|
|
}
|
|
if (arr.length > 3) {
|
|
animationInfo.delay = timeConverter(arr[3]);
|
|
}
|
|
if (arr.length > 4) {
|
|
animationInfo.iterations = parseInt(arr[4]);
|
|
}
|
|
if (arr.length > 5) {
|
|
animationInfo.isReverse = arr[4] === "reverse";
|
|
}
|
|
if (arr.length > 6) {
|
|
animationInfo.isForwards = arr[5] === "forwards";
|
|
}
|
|
if (arr.length > 7) {
|
|
throw new Error("Invalid value for animation: " + value);
|
|
}
|
|
animations.push(animationInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function parseKeyframeDeclarations(unparsedKeyframeDeclarations: Array<KeyframeDeclaration>)
|
|
: Array<KeyframeDeclaration> {
|
|
|
|
const declarations = unparsedKeyframeDeclarations
|
|
.reduce((declarations, { property: unparsedProperty, value: unparsedValue }) => {
|
|
const property = CssAnimationProperty._getByCssName(unparsedProperty);
|
|
|
|
if (typeof unparsedProperty === "string" && property && property._valueConverter) {
|
|
declarations[property.name] = property._valueConverter(<string>unparsedValue);
|
|
} else if (typeof unparsedValue === "string" && unparsedProperty === "transform") {
|
|
const transformations = transformConverter(unparsedValue);
|
|
Object.assign(declarations, transformations);
|
|
}
|
|
|
|
return declarations;
|
|
}, {});
|
|
|
|
return Object.keys(declarations).map(property => ({ property, value: declarations[property] }));
|
|
}
|