Skip to content

Commit 9ac1859

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

27 files changed

+1558
-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: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,31 @@ 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+
Accepts two command line arguments:
243+
244+
- `--with-transition=<bool>`: (_default: `true`_) Migrate `transition`
245+
declarations.
246+
- `--with-animation=<bool>`: (_default: `true`_) Migrate `animation`
247+
declarations.
248+
249+
Declarations targeted:
250+
251+
```
252+
transition
253+
transition-duration
254+
transition-delay
255+
transition-timing-function
256+
animation
257+
animation-duration
258+
animation-delay
259+
animation-timing-function
260+
```
261+
262+
Example changes:
241263

242264
```diff
243265
- transition-duration: 100ms;
@@ -263,7 +285,7 @@ Replace timings (`ms`, `s`) and legacy Sass functions (`duration()`,`easing()`)
263285
```
264286

265287
```sh
266-
npx @shopify/polaris-migrator replace-sass-transition <path>
288+
npx @shopify/polaris-migrator replace-sass-animatable <path>
267289
```
268290

269291
## Creating Migrations

polaris-migrator/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"dependencies": {
3636
"@shopify/polaris-tokens": "^6.2.1",
3737
"chalk": "^4.1.0",
38+
"falsey": "^1.0.0",
3839
"globby": "11.0.1",
3940
"is-git-clean": "^1.1.0",
4041
"jscodeshift": "^0.13.1",

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: 112 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import valueParser, {
44
Node,
55
FunctionNode,
66
} from 'postcss-value-parser';
7+
import falsey from 'falsey';
78

89
import {
910
namespace,
@@ -13,6 +14,7 @@ import {
1314
isTransformableDuration,
1415
isPolarisVar,
1516
createSassMigrator,
17+
PolarisMigrator,
1618
} from '../../utilities/sass';
1719
import {isKeyOf} from '../../utilities/type-guards';
1820

@@ -71,7 +73,7 @@ const easingFuncConstantsMap = {
7173

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

74-
// Per the spec for transition easing functions:
76+
// Per the spec for easing functions:
7577
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
7678
const cssEasingBuiltinFuncs = [
7779
'linear',
@@ -100,10 +102,36 @@ function setNodeValue(node: Node, value: string): void {
100102
node.sourceEndIndex += sourceIndex;
101103
}
102104

105+
interface Options {
106+
namespace?: string;
107+
// later cooerced by falsey()
108+
withTransition?: string;
109+
// later cooerced by falsey()
110+
withAnimation?: string;
111+
}
112+
103113
export default createSassMigrator(
104-
'replace-sass-transition',
105-
(_, {methods, options}, context) => {
114+
'replace-sass-animatable',
115+
(
116+
_,
117+
{
118+
methods,
119+
options,
120+
}: {
121+
methods: Parameters<PolarisMigrator>[1]['methods'];
122+
options: Options;
123+
},
124+
context,
125+
) => {
106126
const durationFunc = namespace('duration', options);
127+
const withTransition =
128+
typeof options.withTransition === 'undefined'
129+
? true
130+
: !falsey(options.withTransition);
131+
const withAnimation =
132+
typeof options.withAnimation === 'undefined'
133+
? true
134+
: !falsey(options.withAnimation);
107135

108136
function migrateLegacySassEasingFunction(
109137
node: FunctionNode,
@@ -150,10 +178,7 @@ export default createSassMigrator(
150178
});
151179
}
152180

153-
function mutateTransitionDurationValue(
154-
node: Node,
155-
decl: Declaration,
156-
): void {
181+
function mutateDurationValue(node: Node, decl: Declaration): void {
157182
if (isPolarisVar(node)) {
158183
return;
159184
}
@@ -226,9 +251,10 @@ export default createSassMigrator(
226251
}
227252
}
228253

229-
function mutateTransitionFunctionValue(
254+
function mutateTimingFunctionValue(
230255
node: Node,
231256
decl: Declaration,
257+
{ignoreUnknownFunctions}: {ignoreUnknownFunctions: boolean},
232258
): void {
233259
if (isPolarisVar(node)) {
234260
return;
@@ -244,17 +270,27 @@ export default createSassMigrator(
244270
}
245271

246272
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-
};
273+
if (node.value === namespace('easing', options)) {
274+
migrateLegacySassEasingFunction(node, decl);
275+
return;
276+
}
255277

256-
if (isKeyOf(easingFuncHandlers, node.value)) {
257-
easingFuncHandlers[node.value](node, decl);
278+
if (ignoreUnknownFunctions) {
279+
const easingFuncHandlers = {
280+
[namespace('easing', options)]: migrateLegacySassEasingFunction,
281+
// Per the spec, these can all be functions:
282+
// https://w3c.github.io/csswg-drafts/css-easing/#easing-functions
283+
linear: insertUnexpectedEasingFunctionComment,
284+
'cubic-bezier': insertUnexpectedEasingFunctionComment,
285+
steps: insertUnexpectedEasingFunctionComment,
286+
};
287+
288+
if (isKeyOf(easingFuncHandlers, node.value)) {
289+
easingFuncHandlers[node.value](node, decl);
290+
return;
291+
}
292+
} else {
293+
insertUnexpectedEasingFunctionComment(node, decl);
258294
return;
259295
}
260296
}
@@ -276,18 +312,21 @@ export default createSassMigrator(
276312
return;
277313
}
278314

279-
if (cssEasingBuiltinFuncs.includes(node.value)) {
315+
if (
316+
!ignoreUnknownFunctions ||
317+
cssEasingBuiltinFuncs.includes(node.value)
318+
) {
280319
insertUnexpectedEasingFunctionComment(node, decl);
281320
}
282321
}
283322
}
284323

285-
function mutateTransitionDelayValue(node: Node, decl: Declaration): void {
324+
function mutateDelayValue(node: Node, decl: Declaration): void {
286325
// For now, we treat delays like durations
287-
return mutateTransitionDurationValue(node, decl);
326+
return mutateDurationValue(node, decl);
288327
}
289328

290-
function mutateTransitionShorthandValue(
329+
function mutateAnimatableShorthandValue(
291330
decl: Declaration,
292331
parsedValue: ParsedValue,
293332
): void {
@@ -309,8 +348,8 @@ export default createSassMigrator(
309348
//
310349
// Note that order is important within the items in this property: the
311350
// 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.
351+
// transition-duration/animation-duration, and the second value that can
352+
// be parsed as a time is assigned to transition-delay/animation-delay.
314353
// https://w3c.github.io/csswg-drafts/css-transitions-1/#transition-shorthand-property
315354
//
316355
// That sounds like an array to me! [0] is duration, [1] is delay.
@@ -327,41 +366,69 @@ export default createSassMigrator(
327366
// This node could be either the property to animate, or an easing
328367
// function. We try mutate the easing function, but if not we assume
329368
// it's the property to animate and therefore do not leave a comment.
330-
mutateTransitionFunctionValue(node, decl);
369+
mutateTimingFunctionValue(node, decl, {
370+
ignoreUnknownFunctions: true,
371+
});
331372
}
332373
});
333374

334375
if (timings[0]) {
335-
mutateTransitionDurationValue(timings[0], decl);
376+
mutateDurationValue(timings[0], decl);
336377
}
337378

338379
if (timings[1]) {
339-
mutateTransitionDelayValue(timings[1], decl);
380+
mutateDelayValue(timings[1], decl);
340381
}
341382
});
342383
}
343384

344385
return (root) => {
345386
methods.walkDecls(root, (decl) => {
346387
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-
},
388+
...(withTransition && {
389+
'transition-duration': () => {
390+
parsedValue.nodes.forEach((node) => {
391+
mutateDurationValue(node, decl);
392+
});
393+
},
394+
'transition-delay': () => {
395+
parsedValue.nodes.forEach((node) => {
396+
mutateDelayValue(node, decl);
397+
});
398+
},
399+
'transition-timing-function': () => {
400+
parsedValue.nodes.forEach((node) => {
401+
mutateTimingFunctionValue(node, decl, {
402+
ignoreUnknownFunctions: false,
403+
});
404+
});
405+
},
406+
transition: () => {
407+
mutateAnimatableShorthandValue(decl, parsedValue);
408+
},
409+
}),
410+
...(withAnimation && {
411+
'animation-duration': () => {
412+
parsedValue.nodes.forEach((node) => {
413+
mutateDurationValue(node, decl);
414+
});
415+
},
416+
'animation-delay': () => {
417+
parsedValue.nodes.forEach((node) => {
418+
mutateDelayValue(node, decl);
419+
});
420+
},
421+
'animation-timing-function': () => {
422+
parsedValue.nodes.forEach((node) => {
423+
mutateTimingFunctionValue(node, decl, {
424+
ignoreUnknownFunctions: false,
425+
});
426+
});
427+
},
428+
animation: () => {
429+
mutateAnimatableShorthandValue(decl, parsedValue);
430+
},
431+
}),
365432
};
366433

367434
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)