Skip to content

Commit 42df0be

Browse files
authored
makeStyles: finish up keyframes implementation (#16757)
* support multiple keyframes * support RTL for keyframes * prefix * cleanups * Change files * fixes * resolve comments
1 parent 888a1f5 commit 42df0be

7 files changed

Lines changed: 283 additions & 45 deletions

File tree

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"type": "minor",
3+
"comment": "makeStyles: finish up keyframes implementation",
4+
"packageName": "@fluentui/make-styles",
5+
"email": "xgao@microsoft.com",
6+
"dependentChangeType": "patch",
7+
"date": "2021-02-02T04:10:06.714Z"
8+
}

packages/make-styles/src/makeStyles.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,25 @@ describe('makeStyles', () => {
1313
const computeClasses = makeStyles([[null, { color: 'red', position: 'absolute' }]]);
1414
expect(computeClasses({}, { renderer, tokens: {} })).toBe('__1fslksb fe3e8s90 f1euv43f');
1515
});
16+
17+
it('handles RTL for keyframes', () => {
18+
const computeClasses = makeStyles([
19+
[
20+
null,
21+
{
22+
animationName: {
23+
from: {
24+
transform: 'rotate(0deg)',
25+
},
26+
to: {
27+
transform: 'rotate(360deg)',
28+
},
29+
},
30+
animationIterationCount: 'infinite',
31+
animationDuration: '5s',
32+
},
33+
],
34+
]);
35+
expect(computeClasses({}, { renderer, tokens: {}, rtl: true })).toBe('__la4fka0 rfkf6eed0 f1cpbl36 f1t9cprh');
36+
});
1637
});

packages/make-styles/src/renderer/createDOMRenderer.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,22 @@ export function createDOMRenderer(targetDocument: Document = document): MakeStyl
4141
const className = definition[0];
4242
const rtlCSS = definition[2];
4343

44-
const ruleClassName = rtl ? (rtlCSS ? RTL_PREFIX + className : className) : className;
44+
const ruleClassName = className && (rtl && rtlCSS ? RTL_PREFIX + className : className);
4545

46-
// Should be done always to return classes
47-
classes += ruleClassName + ' ';
46+
if (ruleClassName) {
47+
// Should be done always to return classes even if they have been already inserted to DOM
48+
classes += ruleClassName + ' ';
49+
}
4850

49-
if (renderer.insertionCache[ruleClassName]) {
51+
const cacheKey = ruleClassName || propName;
52+
if (renderer.insertionCache[cacheKey]) {
5053
continue;
5154
}
5255

5356
const css = definition[1];
5457
const ruleCSS = rtl ? rtlCSS || css : css;
5558

56-
renderer.insertionCache[ruleClassName] = true;
59+
renderer.insertionCache[cacheKey] = true;
5760

5861
(renderer.styleElement.sheet as CSSStyleSheet).insertRule(ruleCSS, renderer.index);
5962
renderer.index++;

packages/make-styles/src/runtime/compileKeyframeRule.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { hyphenateProperty } from './utils/hyphenateProperty';
22
import { MakeStyles } from '../types';
3+
import { compile, middleware, serialize, stringify, prefixer } from 'stylis';
34

45
/* eslint-disable guard-for-in */
56

@@ -34,3 +35,8 @@ export function compileKeyframeRule(frames: MakeStyles): string {
3435

3536
return css;
3637
}
38+
39+
export function compileKeyframesCSS(animationName: string, framesCSS: string): string {
40+
const cssRule = `@keyframes ${animationName} {${framesCSS}}`;
41+
return serialize(compile(cssRule), middleware([prefixer, stringify]));
42+
}

packages/make-styles/src/runtime/resolveStyleRules.test.ts

Lines changed: 206 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ expect.addSnapshotSerializer({
2020
});
2121

2222
function getFirstClassName(resolvedStyles: Record<string, MakeStylesResolvedRule>): string {
23-
return resolvedStyles[Object.keys(resolvedStyles)[0]][0];
23+
return resolvedStyles[Object.keys(resolvedStyles)[0]][0] as string;
2424
}
2525

2626
describe('resolveStyleRules', () => {
@@ -367,32 +367,17 @@ describe('resolveStyleRules', () => {
367367
});
368368
});
369369

370-
describe('experimental', () => {
371-
it('allows to define keyframes', () => {
370+
describe('keyframes', () => {
371+
it('allows to define string as animationName', () => {
372372
expect(
373373
resolveStyleRules({
374-
animationName: {
375-
from: {
376-
transform: 'rotate(0deg)',
377-
},
378-
to: {
379-
transform: 'rotate(360deg)',
380-
},
381-
},
374+
animationName: 'fade-in slide-out',
382375
animationIterationCount: 'infinite',
383376
animationDuration: '5s',
384377
}),
385378
).toMatchInlineSnapshot(`
386-
@keyframes f13owpa8 {
387-
from {
388-
transform: rotate(0deg);
389-
}
390-
to {
391-
transform: rotate(360deg);
392-
}
393-
}
394-
.fkf6eed0 {
395-
animation-name: f13owpa8;
379+
.fc59ano0 {
380+
animation-name: fade-in slide-out;
396381
}
397382
.f1cpbl36 {
398383
animation-iteration-count: infinite;
@@ -403,6 +388,206 @@ describe('resolveStyleRules', () => {
403388
`);
404389
});
405390

391+
it('allows to define object as animationName', () => {
392+
expect(
393+
resolveStyleRules({
394+
animationName: {
395+
from: {
396+
transform: 'rotate(0deg)',
397+
},
398+
to: {
399+
transform: 'rotate(360deg)',
400+
},
401+
},
402+
animationIterationCount: 'infinite',
403+
animationDuration: '5s',
404+
}),
405+
).toMatchInlineSnapshot(`
406+
@-webkit-keyframes f13owpa8 {
407+
from {
408+
-webkit-transform: rotate(0deg);
409+
-moz-transform: rotate(0deg);
410+
-ms-transform: rotate(0deg);
411+
transform: rotate(0deg);
412+
}
413+
to {
414+
-webkit-transform: rotate(360deg);
415+
-moz-transform: rotate(360deg);
416+
-ms-transform: rotate(360deg);
417+
transform: rotate(360deg);
418+
}
419+
}
420+
@keyframes f13owpa8 {
421+
from {
422+
-webkit-transform: rotate(0deg);
423+
-moz-transform: rotate(0deg);
424+
-ms-transform: rotate(0deg);
425+
transform: rotate(0deg);
426+
}
427+
to {
428+
-webkit-transform: rotate(360deg);
429+
-moz-transform: rotate(360deg);
430+
-ms-transform: rotate(360deg);
431+
transform: rotate(360deg);
432+
}
433+
}
434+
@-webkit-keyframes rf13owpa8 {
435+
from {
436+
-webkit-transform: rotate(0deg);
437+
-moz-transform: rotate(0deg);
438+
-ms-transform: rotate(0deg);
439+
transform: rotate(0deg);
440+
}
441+
to {
442+
-webkit-transform: rotate(-360deg);
443+
-moz-transform: rotate(-360deg);
444+
-ms-transform: rotate(-360deg);
445+
transform: rotate(-360deg);
446+
}
447+
}
448+
@keyframes rf13owpa8 {
449+
from {
450+
-webkit-transform: rotate(0deg);
451+
-moz-transform: rotate(0deg);
452+
-ms-transform: rotate(0deg);
453+
transform: rotate(0deg);
454+
}
455+
to {
456+
-webkit-transform: rotate(-360deg);
457+
-moz-transform: rotate(-360deg);
458+
-ms-transform: rotate(-360deg);
459+
transform: rotate(-360deg);
460+
}
461+
}
462+
.fkf6eed0 {
463+
animation-name: f13owpa8;
464+
}
465+
.rfkf6eed0 {
466+
animation-name: rf13owpa8;
467+
}
468+
.f1cpbl36 {
469+
animation-iteration-count: infinite;
470+
}
471+
.f1t9cprh {
472+
animation-duration: 5s;
473+
}
474+
`);
475+
});
476+
477+
it('allows to define array as animationName', () => {
478+
expect(
479+
resolveStyleRules({
480+
animationName: [
481+
{
482+
from: {
483+
transform: 'rotate(0deg)',
484+
},
485+
to: {
486+
transform: 'rotate(360deg)',
487+
},
488+
},
489+
{
490+
from: {
491+
opacity: 0,
492+
},
493+
to: {
494+
opacity: 1,
495+
},
496+
},
497+
],
498+
animationIterationCount: 'infinite',
499+
animationDuration: '5s',
500+
}),
501+
).toMatchInlineSnapshot(`
502+
@-webkit-keyframes f13owpa8 {
503+
from {
504+
-webkit-transform: rotate(0deg);
505+
-moz-transform: rotate(0deg);
506+
-ms-transform: rotate(0deg);
507+
transform: rotate(0deg);
508+
}
509+
to {
510+
-webkit-transform: rotate(360deg);
511+
-moz-transform: rotate(360deg);
512+
-ms-transform: rotate(360deg);
513+
transform: rotate(360deg);
514+
}
515+
}
516+
@keyframes f13owpa8 {
517+
from {
518+
-webkit-transform: rotate(0deg);
519+
-moz-transform: rotate(0deg);
520+
-ms-transform: rotate(0deg);
521+
transform: rotate(0deg);
522+
}
523+
to {
524+
-webkit-transform: rotate(360deg);
525+
-moz-transform: rotate(360deg);
526+
-ms-transform: rotate(360deg);
527+
transform: rotate(360deg);
528+
}
529+
}
530+
@-webkit-keyframes f1qa61cu {
531+
from {
532+
opacity: 0;
533+
}
534+
to {
535+
opacity: 1;
536+
}
537+
}
538+
@keyframes f1qa61cu {
539+
from {
540+
opacity: 0;
541+
}
542+
to {
543+
opacity: 1;
544+
}
545+
}
546+
@-webkit-keyframes rf13owpa8 {
547+
from {
548+
-webkit-transform: rotate(0deg);
549+
-moz-transform: rotate(0deg);
550+
-ms-transform: rotate(0deg);
551+
transform: rotate(0deg);
552+
}
553+
to {
554+
-webkit-transform: rotate(-360deg);
555+
-moz-transform: rotate(-360deg);
556+
-ms-transform: rotate(-360deg);
557+
transform: rotate(-360deg);
558+
}
559+
}
560+
@keyframes rf13owpa8 {
561+
from {
562+
-webkit-transform: rotate(0deg);
563+
-moz-transform: rotate(0deg);
564+
-ms-transform: rotate(0deg);
565+
transform: rotate(0deg);
566+
}
567+
to {
568+
-webkit-transform: rotate(-360deg);
569+
-moz-transform: rotate(-360deg);
570+
-ms-transform: rotate(-360deg);
571+
transform: rotate(-360deg);
572+
}
573+
}
574+
.f18gdskf {
575+
animation-name: f13owpa8 f1qa61cu;
576+
}
577+
.rf18gdskf {
578+
animation-name: rf13owpa8 f1qa61cu;
579+
}
580+
.f1cpbl36 {
581+
animation-iteration-count: infinite;
582+
}
583+
.f1t9cprh {
584+
animation-duration: 5s;
585+
}
586+
`);
587+
});
588+
});
589+
590+
describe('experimental', () => {
406591
it('allows to increase specificity', () => {
407592
expect(resolveStyleRules({ color: 'red' }, 1)).toMatchInlineSnapshot(`
408593
.fe3e8s901.fe3e8s901 {

0 commit comments

Comments
 (0)