Skip to content

Commit

Permalink
Parse full animation-range syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
johannesodland committed Feb 20, 2024
1 parent 398b1f6 commit 0ffa330
Show file tree
Hide file tree
Showing 8 changed files with 2,679 additions and 253 deletions.
2,213 changes: 2,100 additions & 113 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
},
"homepage": "https://github.com/flackr/scroll-timeline#readme",
"devDependencies": {
"jsdom": "^24.0.0",
"terser": "^5.27.0",
"vite": "^5.0.12"
"vite": "^5.0.12",
"vitest": "^1.3.0"
}
}
124 changes: 106 additions & 18 deletions src/numeric-values.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {simplifyCalculation} from './simplify-calculation';
* @typedef {[number, UnitMap]} SumValueItem
* @typedef {SumValueItem[]} SumValue
* @typedef {null} Failure
* @typedef {{[string]: integer} & {percentHint: string | undefined}} Type
* @typedef {{[string]: integer} & {percentHint: string | undefined}} CSSNumericType
* @typedef {{type: 'ADDITION'}|{type: 'MULTIPLICATION'}|{type: 'NEGATE'}|{type: 'INVERT'}} ASTNode
*/

Expand All @@ -40,11 +40,11 @@ const unitGroups = {
},
// https://www.w3.org/TR/css-values-4/#absolute-lengths
absoluteLengths: {
units: new Set(["cm", "mm", "Q", "in", "pt", "pc", "px"]),
units: new Set(["cm", "mm", "q", "in", "pt", "pc", "px"]),
compatible: true,
canonicalUnit: "px",
ratios: {
"cm": 96 / 2.54, "mm": (96 / 2.54) / 10, "Q": (96 / 2.54) / 40, "in": 96, "pc": 96 / 6, "pt": 96 / 72, "px": 1
"cm": 96 / 2.54, "mm": (96 / 2.54) / 10, "q": (96 / 2.54) / 40, "in": 96, "pc": 96 / 6, "pt": 96 / 72, "px": 1
}
},
// https://www.w3.org/TR/css-values-4/#angles
Expand Down Expand Up @@ -124,30 +124,61 @@ function productOfTwoUnitMaps(units1, units2) {
return result;
}

/**
* Perform the steps necessary for converting a type
* to a result that can be returned from `type()`
* https://www.w3.org/TR/css-typed-om-1/#dom-cssnumericvalue-type
*
* @param {CSSNumericType} type
* return {CSSNumericType}
*/
export function rectifyType(type) {
// 1. Let result be a new CSSNumericType.
const result = {}
// 2. For each baseType → power in the type of this,
for (const baseType of baseTypes) {
// 2. 1. If power is not 0, set result[baseType] to power.
if (type[baseType] && type[baseType] !== 0) {
result[baseType] = type[baseType];
}
}

// 3. If the percent hint of this is not null,
if (type.percentHint) {
// 3. 1. Set percentHint to the percent hint of this.
result.percentHint = type.percentHint;
}

// 4. Return result.
return result;
}

/**
* Implementation of `create a type` from css-typed-om-1:
* https://www.w3.org/TR/css-typed-om-1/#create-a-type
*
* @param {string} unit
* @return {Type|Failure}
* @return {CSSNumericType|Failure}
*/
export function createAType(unit) {
if (unit === "number") {
const lowerCaseUnit = unit.toLowerCase();
if (lowerCaseUnit === "number") {
return {};
} else if (unit === "percent") {
} else if (lowerCaseUnit === "percent") {
return {"percent": 1};
} else if (unitGroups.absoluteLengths.units.has(unit) || unitGroups.fontRelativeLengths.units.has(unit) ||
unitGroups.viewportRelativeLengths.units.has(unit)) {
} else if (unitGroups.absoluteLengths.units.has(lowerCaseUnit) ||
unitGroups.fontRelativeLengths.units.has(lowerCaseUnit) ||
unitGroups.viewportRelativeLengths.units.has(lowerCaseUnit)) {
return {"length": 1};
} else if (unitGroups.angle.units.has(unit)) {
} else if (unitGroups.angle.units.has(lowerCaseUnit)) {
return {"angle": 1};
} else if (unitGroups.time.units.has(unit)) {
} else if (unitGroups.time.units.has(lowerCaseUnit)) {
return {"time": 1};
} else if (unitGroups.frequency.units.has(unit)) {
} else if (unitGroups.frequency.units.has(lowerCaseUnit)) {
return {"frequency": 1};
} else if (unitGroups.resolution.units.has(unit)) {
} else if (unitGroups.resolution.units.has(lowerCaseUnit)) {
return {"resolution": 1};
} else if (unit === "fr") {
} else if (lowerCaseUnit === "fr") {
return {"flex": 1};
} else {
return failure;
Expand Down Expand Up @@ -384,8 +415,8 @@ export function toSum(cssNumericValue, ...units) {
* Implementation of `invert a type` from css-typed-om-1 Editors Draft:
* https://drafts.css-houdini.org/css-typed-om/
*
* @param {Type} type
* @return {Type}
* @param {CSSNumericType} type
* @return {CSSNumericType}
*/
export function invertType(type) {
// To invert a type type, perform the following steps:
Expand All @@ -399,13 +430,70 @@ export function invertType(type) {
return result;
}

/**
* Implementation of `apply the percent hint` from css-typed-om-1 Editor's Draft:
* https://drafts.css-houdini.org/css-typed-om/#apply-the-percent-hint
* @param {CSSNumericType} type
* @param {string} hint
*/
function applyPercentHint(type, hint) {
// 1. If type doesn’t contain hint, set type[hint] to 0.
type[hint] ??= 0;
// 2. If type contains "percent", add type["percent"] to type[hint], then set type["percent"] to 0.
if (type.percent) {
type[hint] += type.percent;
type.percent = 0;
}
// 3. Set type’s percent hint to hint.
type.percentHint = hint;
}

/**
* Implementation of `add two types` from css-typed-om-1 Editor's Draft:
* https://drafts.css-houdini.org/css-typed-om/#cssnumericvalue-add-two-types
*
* @param {CSSNumericType} type1 a map of base types to integers and an associated percent hint
* @param {CSSNumericType} type2 a map of base types to integers and an associated percent hint
* @return {CSSNumericType|Failure}
*/
export function addTypes(type1, type2) {
if (type1.percentHint && type2.percentHint && type1.percentHint !== type2.percentHint) {
return failure;
}

if (!baseTypes.some(baseType => (type1[baseType] || type2[baseType]) && type1[baseType] !== type2[baseType])) {
return {
...type2,
...type1,
percentHint: type1.percentHint
}
}

if (type1.percent || type2.percent) {
for (const hint of baseTypes.filter(baseType => baseType !== 'percent')) {
const tempType1 = {...type1};
const tempType2 = {...type2};

applyPercentHint(tempType1, hint);
applyPercentHint(tempType2, hint);

if (!baseTypes.some(baseType => (tempType1[baseType] || tempType2[baseType]) && tempType1[baseType] !== tempType2[baseType])) {
return {
...tempType2, ...tempType1, percentHint: hint
};
}
}
}
return failure;
}

/**
* Implementation of `multiply two types` from css-typed-om-1 Editor's Draft:
* https://drafts.css-houdini.org/css-typed-om/#cssnumericvalue-multiply-two-types
*
* @param {Type} type1 a map of base types to integers and an associated percent hint
* @param {Type} type2 a map of base types to integers and an associated percent hint
* @return {Type|Failure}
* @param {CSSNumericType} type1 a map of base types to integers and an associated percent hint
* @param {CSSNumericType} type2 a map of base types to integers and an associated percent hint
* @return {CSSNumericType|Failure}
*/
export function multiplyTypes(type1, type2) {
if (type1.percentHint && type2.percentHint && type1.percentHint !== type2.percentHint) {
Expand Down
Loading

0 comments on commit 0ffa330

Please sign in to comment.