Skip to content

Commit e5a271d

Browse files
committed
Rename 'transition' migration to 'animatable' + add tests for animation: decl
1 parent 8859f5d commit e5a271d

25 files changed

+1537
-531
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris-migrator': minor
3+
---
4+
5+
Add migrations for animation: declarations (and rename `replace-sass-transition` to the more generic `replace-sass-animatable`).

polaris-migrator/README.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,24 @@ Be aware that this may also create additional code changes in your codebase, we
235235
npx @shopify/polaris-migrator replace-sass-spacing <path>
236236
```
237237

238-
### `replace-sass-transition`
238+
### `replace-sass-animatable`
239239

240-
Replace timings (`ms`, `s`) and legacy Sass functions (`duration()`,`easing()`) in transition declarations (`transition`, `transition-duration`, `transition-delay`, and `transition-timing-function`) with the corresponding Polaris [motion](https://polaris.shopify.com/tokens/motion) token.
240+
Replace timings (`ms`, `s`) and legacy Sass functions (`duration()`,`easing()`) with the corresponding Polaris [motion](https://polaris.shopify.com/tokens/motion) token.
241+
242+
Declarations targeted:
243+
244+
```
245+
transition
246+
transition-duration
247+
transition-delay
248+
transition-timing-function
249+
animation
250+
animation-duration
251+
animation-delay
252+
animation-timing-function
253+
```
254+
255+
Example changes:
241256

242257
```diff
243258
- transition-duration: 100ms;
@@ -263,7 +278,7 @@ Replace timings (`ms`, `s`) and legacy Sass functions (`duration()`,`easing()`)
263278
```
264279

265280
```sh
266-
npx @shopify/polaris-migrator replace-sass-transition <path>
281+
npx @shopify/polaris-migrator replace-sass-animatable <path>
267282
```
268283

269284
## Creating Migrations

polaris-migrator/src/migrations/replace-sass-transition/replace-sass-transition.ts renamed to polaris-migrator/src/migrations/replace-sass-animatable/replace-sass-animatable.ts

Lines changed: 103 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
isTransformableDuration,
1414
isPolarisVar,
1515
createSassMigrator,
16+
PolarisMigrator,
1617
} from '../../utilities/sass';
1718
import {isKeyOf} from '../../utilities/type-guards';
1819

@@ -71,7 +72,7 @@ const easingFuncConstantsMap = {
7172

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

74-
// Per the spec for transition easing functions:
75+
// Per the spec for easing functions:
7576
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
7677
const cssEasingBuiltinFuncs = [
7778
'linear',
@@ -100,10 +101,28 @@ function setNodeValue(node: Node, value: string): void {
100101
node.sourceEndIndex += sourceIndex;
101102
}
102103

104+
interface Options {
105+
namespace?: string;
106+
withTransition?: boolean;
107+
withAnimation?: boolean;
108+
}
109+
103110
export default createSassMigrator(
104-
'replace-sass-transition',
105-
(_, {methods, options}, context) => {
111+
'replace-sass-animatable',
112+
(
113+
_,
114+
{
115+
methods,
116+
options,
117+
}: {
118+
methods: Parameters<PolarisMigrator>[1]['methods'];
119+
options: Options;
120+
},
121+
context,
122+
) => {
106123
const durationFunc = namespace('duration', options);
124+
const withTransition = options.withTransition ?? true;
125+
const withAnimation = options.withAnimation ?? true;
107126

108127
function migrateLegacySassEasingFunction(
109128
node: FunctionNode,
@@ -150,10 +169,7 @@ export default createSassMigrator(
150169
});
151170
}
152171

153-
function mutateTransitionDurationValue(
154-
node: Node,
155-
decl: Declaration,
156-
): void {
172+
function mutateDurationValue(node: Node, decl: Declaration): void {
157173
if (isPolarisVar(node)) {
158174
return;
159175
}
@@ -226,9 +242,10 @@ export default createSassMigrator(
226242
}
227243
}
228244

229-
function mutateTransitionFunctionValue(
245+
function mutateTimingFunctionValue(
230246
node: Node,
231247
decl: Declaration,
248+
{ignoreUnknownFunctions}: {ignoreUnknownFunctions: boolean},
232249
): void {
233250
if (isPolarisVar(node)) {
234251
return;
@@ -244,17 +261,27 @@ export default createSassMigrator(
244261
}
245262

246263
if (node.type === 'function') {
247-
const easingFuncHandlers = {
248-
[namespace('easing', options)]: migrateLegacySassEasingFunction,
249-
// Per the spec, these can all be functions:
250-
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
251-
linear: insertUnexpectedEasingFunctionComment,
252-
'cubic-bezier': insertUnexpectedEasingFunctionComment,
253-
steps: insertUnexpectedEasingFunctionComment,
254-
};
264+
if (node.value === namespace('easing', options)) {
265+
migrateLegacySassEasingFunction(node, decl);
266+
return;
267+
}
255268

256-
if (isKeyOf(easingFuncHandlers, node.value)) {
257-
easingFuncHandlers[node.value](node, decl);
269+
if (ignoreUnknownFunctions) {
270+
const easingFuncHandlers = {
271+
[namespace('easing', options)]: migrateLegacySassEasingFunction,
272+
// Per the spec, these can all be functions:
273+
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
274+
linear: insertUnexpectedEasingFunctionComment,
275+
'cubic-bezier': insertUnexpectedEasingFunctionComment,
276+
steps: insertUnexpectedEasingFunctionComment,
277+
};
278+
279+
if (isKeyOf(easingFuncHandlers, node.value)) {
280+
easingFuncHandlers[node.value](node, decl);
281+
return;
282+
}
283+
} else {
284+
insertUnexpectedEasingFunctionComment(node, decl);
258285
return;
259286
}
260287
}
@@ -276,18 +303,21 @@ export default createSassMigrator(
276303
return;
277304
}
278305

279-
if (cssEasingBuiltinFuncs.includes(node.value)) {
306+
if (
307+
!ignoreUnknownFunctions ||
308+
cssEasingBuiltinFuncs.includes(node.value)
309+
) {
280310
insertUnexpectedEasingFunctionComment(node, decl);
281311
}
282312
}
283313
}
284314

285-
function mutateTransitionDelayValue(node: Node, decl: Declaration): void {
315+
function mutateDelayValue(node: Node, decl: Declaration): void {
286316
// For now, we treat delays like durations
287-
return mutateTransitionDurationValue(node, decl);
317+
return mutateDurationValue(node, decl);
288318
}
289319

290-
function mutateTransitionShorthandValue(
320+
function mutateAnimatableShorthandValue(
291321
decl: Declaration,
292322
parsedValue: ParsedValue,
293323
): void {
@@ -309,8 +339,8 @@ export default createSassMigrator(
309339
//
310340
// Note that order is important within the items in this property: the
311341
// first value that can be parsed as a time is assigned to the
312-
// transition-duration, and the second value that can be parsed as a
313-
// time is assigned to transition-delay.
342+
// transition-duration/animation-duration, and the second value that can
343+
// be parsed as a time is assigned to transition-delay/animation-delay.
314344
// https://w3c.github.io/csswg-drafts/css-transitions-1/#transition-shorthand-property
315345
//
316346
// That sounds like an array to me! [0] is duration, [1] is delay.
@@ -327,41 +357,69 @@ export default createSassMigrator(
327357
// This node could be either the property to animate, or an easing
328358
// function. We try mutate the easing function, but if not we assume
329359
// it's the property to animate and therefore do not leave a comment.
330-
mutateTransitionFunctionValue(node, decl);
360+
mutateTimingFunctionValue(node, decl, {
361+
ignoreUnknownFunctions: true,
362+
});
331363
}
332364
});
333365

334366
if (timings[0]) {
335-
mutateTransitionDurationValue(timings[0], decl);
367+
mutateDurationValue(timings[0], decl);
336368
}
337369

338370
if (timings[1]) {
339-
mutateTransitionDelayValue(timings[1], decl);
371+
mutateDelayValue(timings[1], decl);
340372
}
341373
});
342374
}
343375

344376
return (root) => {
345377
methods.walkDecls(root, (decl) => {
346378
const handlers: {[key: string]: () => void} = {
347-
'transition-duration': () => {
348-
parsedValue.nodes.forEach((node) => {
349-
mutateTransitionDurationValue(node, decl);
350-
});
351-
},
352-
'transition-delay': () => {
353-
parsedValue.nodes.forEach((node) => {
354-
mutateTransitionDelayValue(node, decl);
355-
});
356-
},
357-
'transition-timing-function': () => {
358-
parsedValue.nodes.forEach((node) => {
359-
mutateTransitionFunctionValue(node, decl);
360-
});
361-
},
362-
transition: () => {
363-
mutateTransitionShorthandValue(decl, parsedValue);
364-
},
379+
...(withTransition && {
380+
'transition-duration': () => {
381+
parsedValue.nodes.forEach((node) => {
382+
mutateDurationValue(node, decl);
383+
});
384+
},
385+
'transition-delay': () => {
386+
parsedValue.nodes.forEach((node) => {
387+
mutateDelayValue(node, decl);
388+
});
389+
},
390+
'transition-timing-function': () => {
391+
parsedValue.nodes.forEach((node) => {
392+
mutateTimingFunctionValue(node, decl, {
393+
ignoreUnknownFunctions: false,
394+
});
395+
});
396+
},
397+
transition: () => {
398+
mutateAnimatableShorthandValue(decl, parsedValue);
399+
},
400+
}),
401+
...(withAnimation && {
402+
'animation-duration': () => {
403+
parsedValue.nodes.forEach((node) => {
404+
mutateDurationValue(node, decl);
405+
});
406+
},
407+
'animation-delay': () => {
408+
parsedValue.nodes.forEach((node) => {
409+
mutateDelayValue(node, decl);
410+
});
411+
},
412+
'animation-timing-function': () => {
413+
parsedValue.nodes.forEach((node) => {
414+
mutateTimingFunctionValue(node, decl, {
415+
ignoreUnknownFunctions: false,
416+
});
417+
});
418+
},
419+
animation: () => {
420+
mutateAnimatableShorthandValue(decl, parsedValue);
421+
},
422+
}),
365423
};
366424

367425
if (!handlers[decl.prop]) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
.duration-simple-string-arg {
2+
opacity: 1;
3+
animation-duration: legacy-polaris-v8.duration('none');
4+
animation-duration: legacy-polaris-v8.duration('fast');
5+
animation-duration: legacy-polaris-v8.duration('base');
6+
animation-duration: legacy-polaris-v8.duration('slow');
7+
animation-duration: legacy-polaris-v8.duration('slower');
8+
animation-duration: legacy-polaris-v8.duration('slowest');
9+
animation-duration: legacy-polaris-v8.duration('nonsense');
10+
}
11+
12+
.duration-simple-non-string-arg {
13+
opacity: 1;
14+
animation-duration: legacy-polaris-v8.duration();
15+
animation-duration: legacy-polaris-v8.duration(none);
16+
animation-duration: legacy-polaris-v8.duration(fast);
17+
animation-duration: legacy-polaris-v8.duration(base);
18+
animation-duration: legacy-polaris-v8.duration(slow);
19+
animation-duration: legacy-polaris-v8.duration(slower);
20+
animation-duration: legacy-polaris-v8.duration(slowest);
21+
animation-duration: legacy-polaris-v8.duration(nonsense);
22+
}
23+
24+
.duration-simple-constant {
25+
opacity: 1;
26+
animation-duration: 0;
27+
animation-duration: 0ms;
28+
animation-duration: 0s;
29+
animation-duration: 50ms;
30+
animation-duration: 0.05s;
31+
animation-duration: 100ms;
32+
animation-duration: 0.1s;
33+
animation-duration: 150ms;
34+
animation-duration: 0.15s;
35+
animation-duration: 200ms;
36+
animation-duration: 0.2s;
37+
animation-duration: 250ms;
38+
animation-duration: 0.25s;
39+
animation-duration: 300ms;
40+
animation-duration: 0.3s;
41+
animation-duration: 350ms;
42+
animation-duration: 0.35s;
43+
animation-duration: 400ms;
44+
animation-duration: 0.4s;
45+
animation-duration: 450ms;
46+
animation-duration: 0.45s;
47+
animation-duration: 500ms;
48+
animation-duration: 0.5s;
49+
animation-duration: 5s;
50+
animation-duration: 16.7s;
51+
}
52+
53+
.edges {
54+
// foobar isn't a valid duration key
55+
animation-duration: legacy-polaris-v8.duration(foobar);
56+
// can't process variables
57+
animation-duration: $foo;
58+
}

0 commit comments

Comments
 (0)