Skip to content

Commit

Permalink
Migrate SASS easing functions
Browse files Browse the repository at this point in the history
  • Loading branch information
jesstelford committed Oct 21, 2022
1 parent cf6fedf commit e559f7d
Show file tree
Hide file tree
Showing 5 changed files with 403 additions and 187 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import type {FileInfo, API, Options} from 'jscodeshift';
import postcss, {Plugin, Declaration, Helpers} from 'postcss';
import valueParser, {ParsedValue, Node} from 'postcss-value-parser';
import valueParser, {
ParsedValue,
Node,
FunctionNode,
} from 'postcss-value-parser';

import {POLARIS_MIGRATOR_COMMENT} from '../../constants';
import {
Expand All @@ -15,6 +19,7 @@ import {isKeyOf} from '../../utilities/type-guards';

const processed = Symbol('processed');
const DEFAULT_DURATION = 'base';
const DEFAULT_FUNCTION = 'base';

const durationFuncMap = {
none: '--p-duration-0',
Expand Down Expand Up @@ -52,6 +57,36 @@ const durationConstantsMap = {
'5s': '--p-duration-5000',
};

const easingFuncMap = {
base: '--p-ease',
in: '--p-ease-in',
out: '--p-ease-out',
};

const easingFuncConstantsMap = {
linear: '--p-linear',
ease: '--p-ease',
'ease-in': '--p-ease-in',
'ease-out': '--p-ease-out',
'ease-in-out': '--p-ease-in-out',
};

const deprecatedEasingFuncs = ['anticipate', 'excite', 'overshoot'];

// Per the spec for transition easing functions:
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
const cssEasingBuiltinFuncs = [
'linear',
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'cubic-bezier',
'step-start',
'step-end',
'steps',
];

function normaliseStringifiedNumber(number: string): string {
return Number(number).toString();
}
Expand Down Expand Up @@ -99,11 +134,52 @@ function withParsedValue(
}) as DeclarationProcessor;
}

function insertUnexpectedEasingFunctionComment(
node: Node,
decl: ParsedValueDeclaration,
) {
decl.before(
postcss.comment({
text: `${POLARIS_MIGRATOR_COMMENT} Unexpected easing function '${node.value}'. See https://polaris.shopify.com/tokens/motion for possible values.`,
}),
);
}

function migrateLegacySassEasingFunction(
node: FunctionNode,
decl: ParsedValueDeclaration,
) {
const easingFunc = node.nodes[0]?.value ?? DEFAULT_FUNCTION;

if (isKeyOf(easingFuncMap, easingFunc)) {
const easingCustomProperty = easingFuncMap[easingFunc];
setNodeValue(node, `var(${easingCustomProperty})`);
} else {
const comment = deprecatedEasingFuncs.includes(easingFunc)
? `The ${easingFunc} easing function is no longer available in Polaris. See https://polaris.shopify.com/tokens/motion for possible values.`
: `Unexpected easing function '${easingFunc}'.`;
decl.before(
postcss.comment({
text: `${POLARIS_MIGRATOR_COMMENT} ${comment}`,
}),
);
}
}

interface PluginOptions extends Options, NamespaceOptions {}

const plugin = (options: PluginOptions = {}): Plugin => {
const durationFunc = namespace('duration', options);

const easingFuncHandlers = {
[namespace('easing', options)]: migrateLegacySassEasingFunction,
// Per the spec, these can all be functions:
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
linear: insertUnexpectedEasingFunctionComment,
'cubic-bezier': insertUnexpectedEasingFunctionComment,
steps: insertUnexpectedEasingFunctionComment,
};

function mutateTransitionDurationValue(
node: Node,
decl: ParsedValueDeclaration,
Expand Down Expand Up @@ -153,6 +229,32 @@ const plugin = (options: PluginOptions = {}): Plugin => {
return false;
}

function mutateTransitionFunctionValue(
node: Node,
decl: ParsedValueDeclaration,
): boolean {
if (isPolarisVar(node)) {
return true;
}

if (node.type === 'function' && isKeyOf(easingFuncHandlers, node.value)) {
easingFuncHandlers[node.value](node, decl);
return true;
}

if (node.type === 'word') {
if (isKeyOf(easingFuncConstantsMap, node.value)) {
setNodeValue(node, `var(${easingFuncConstantsMap[node.value]})`);
return true;
} else if (cssEasingBuiltinFuncs.includes(node.value)) {
insertUnexpectedEasingFunctionComment(node, decl);
return true;
}
}

return false;
}

function mutateTransitionDelayValue(
node: Node,
decl: ParsedValueDeclaration,
Expand Down Expand Up @@ -200,7 +302,10 @@ const plugin = (options: PluginOptions = {}): Plugin => {
if (isTransformableDuration(unit) || isSassFunction(durationFunc, node)) {
timings.push(node);
} else {
// TODO: Try process it as an easing function
// This node could be either the property to animate, or an easing
// function. We try mutate the easing function, but if not we assume
// it's the property to animate and therefore do not leave a comment.
mutateTransitionFunctionValue(node, decl);
}
});

Expand Down Expand Up @@ -270,6 +375,18 @@ const plugin = (options: PluginOptions = {}): Plugin => {
});
}),

'transition-timing-function': withParsedValue((decl) => {
decl.parsedValue.nodes.forEach((node) => {
if (!mutateTransitionFunctionValue(node, decl)) {
decl.before(
postcss.comment({
text: POLARIS_MIGRATOR_COMMENT,
}),
);
}
});
}),

transition: withParsedValue((decl) => {
if (hasNumericOperator(decl.parsedValue)) {
decl.before(
Expand Down
Loading

0 comments on commit e559f7d

Please sign in to comment.