Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Add nonce support to styling (#2629)
Add a way to create an Emotion instance with initialization options, including a `nonce` or custom `stylis` plugins. Before, the Emotion instance created by `@emotion/css` was used. Now `@emotion/css` is used as a fallback if an instance hasn't been created by the time a style utility is called. Fixes: #2628 This change adds the following opt-in features: - Change the default Emotion cache instance used by Canvas Kit and the application - Allow use of `injectGlobal` from `@workday/canvas-kit-styling` that uses the shared instance. [category:Infrastructure] Release Note: This change does not introduce any breaking changes, but creating a custom Emotion instance can introduce a breaking change. A custom instance should only be used if all instances of Canvas Kit on the page are above the version this change is released in and no application code is imported directly from `@emotion/css`. This change updates all internal Canvas Kit styling to use the Emotion instance created in `@workday/canvas-kit-styling`. If no custom instance is created, the one created by `@emotion/css` will be used. If the default instance is used, there should be no breaking changes, but everyone should update their application code to use styling functions from `@workday/canvas-kit-styling` and not `@emotion/css`. SSR using `@emotion/css` is unaffected since server to client hydration only cares about the cache key ("css") and the style's hash, which should be the same even with a custom cache instance.
- Loading branch information
1 parent
8f32464
commit 75fe178
Showing
12 changed files
with
282 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import ts from 'typescript'; | ||
|
||
import {isImportedFromStyling} from './isImportedFromStyling'; | ||
import {parseObjectToStaticValue} from './parseObjectToStaticValue'; | ||
import {compileCSS, createStyleObjectNode, serializeStyles} from './createStyleObjectNode'; | ||
import {NestedStyleObject, NodeTransformer, TransformerContext} from './types'; | ||
import {parseNodeToStaticValue} from './parseNodeToStaticValue'; | ||
|
||
export const handleInjectGlobal: NodeTransformer = (node, context) => { | ||
const {checker, getFileName} = context; | ||
|
||
if ( | ||
ts.isTaggedTemplateExpression(node) && | ||
ts.isIdentifier(node.tag) && | ||
node.tag.text === 'injectGlobal' && | ||
isImportedFromStyling(node.tag, checker) | ||
) { | ||
const fileName = getFileName(node.getSourceFile()?.fileName || context.fileName); | ||
const styleObj = parseNodeToStaticValue(node.template, context).toString(); //? | ||
|
||
return ts.factory.createCallExpression(node.tag, undefined, [ | ||
createStyleReplacementNode(styleObj, fileName, context), | ||
]); | ||
} | ||
|
||
if ( | ||
ts.isCallExpression(node) && | ||
ts.isIdentifier(node.expression) && | ||
node.expression.text === 'injectGlobal' && | ||
isImportedFromStyling(node.expression, checker) | ||
) { | ||
if (ts.isObjectLiteralExpression(node.arguments[0])) { | ||
const fileName = getFileName(node.expression.getSourceFile()?.fileName || context.fileName); | ||
const styleObj = parseObjectToStaticValue(node.arguments[0], context); | ||
|
||
return ts.factory.updateCallExpression(node, node.expression, undefined, [ | ||
createStyleReplacementNode(styleObj, fileName, context), | ||
]); | ||
} | ||
} | ||
|
||
return; | ||
}; | ||
|
||
function createStyleReplacementNode( | ||
styleObj: NestedStyleObject | string, | ||
fileName: string, | ||
{styles}: TransformerContext | ||
) { | ||
const serialized = serializeStyles(styleObj); //? | ||
const styleOutput = compileCSS(serialized.styles); | ||
styles[fileName] = styles[fileName] || []; | ||
styles[fileName].push(styleOutput); | ||
|
||
return createStyleObjectNode(serialized.styles, serialized.name); | ||
} |
76 changes: 76 additions & 0 deletions
76
modules/styling-transform/spec/utils/handleInjectGlobal.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { | ||
createProgramFromSource, | ||
withDefaultContext, | ||
transform, | ||
} from '@workday/canvas-kit-styling-transform/testing'; | ||
import {compileCSS} from '../../lib/utils/createStyleObjectNode'; | ||
|
||
describe('handleInjectGlobal', () => { | ||
it('should transform an object using injectGlobal', () => { | ||
const program = createProgramFromSource(` | ||
import {injectGlobal} from '@workday/canvas-kit-styling'; | ||
injectGlobal({ | ||
'*': { | ||
padding: 10 | ||
} | ||
}) | ||
`); | ||
|
||
const result = transform(program, 'test.ts'); | ||
|
||
expect(result).toContain('styles: "*{padding:10px;}'); | ||
}); | ||
|
||
it('should transform a TemplateString using injectGlobal', () => { | ||
const program = createProgramFromSource(` | ||
import {injectGlobal} from '@workday/canvas-kit-styling'; | ||
injectGlobal\` | ||
* { | ||
padding: 10px; | ||
} | ||
\` | ||
`); | ||
|
||
const result = transform(program, 'test.ts'); | ||
|
||
expect(result).toMatch( | ||
/injectGlobal\({ name: "[a-z0-9]+", styles: ".+\*.+{.+padding: 10px;.+}/ | ||
); | ||
}); | ||
|
||
it('should add global styles to the compiled CSS from an object', () => { | ||
const program = createProgramFromSource(` | ||
import {injectGlobal} from '@workday/canvas-kit-styling'; | ||
injectGlobal({ | ||
'*': { | ||
padding: 10 | ||
} | ||
}) | ||
`); | ||
|
||
const styles = {}; | ||
transform(program, 'test.ts', withDefaultContext(program.getTypeChecker(), {styles})); | ||
|
||
expect(styles['test.css']).toContainEqual(compileCSS('* { padding: 10px; }')); | ||
}); | ||
|
||
it('should add global styles to the compiled CSS from a template string', () => { | ||
const program = createProgramFromSource(` | ||
import {injectGlobal} from '@workday/canvas-kit-styling'; | ||
injectGlobal\` | ||
* { | ||
padding: 10px; | ||
} | ||
\` | ||
`); | ||
|
||
const styles = {}; | ||
transform(program, 'test.ts', withDefaultContext(program.getTypeChecker(), {styles})); | ||
|
||
expect(styles['test.css']).toContainEqual(compileCSS('* { padding: 10px; }')); | ||
}); | ||
}); |
Oops, something went wrong.