@workday/canvas-kit-docs 14.0.0-alpha.1149-next.0 → 14.0.0-alpha.1153-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,459 @@
1
+ import {ExampleCodeBlock} from '@workday/canvas-kit-docs';
2
+ import {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';
3
+ import {system} from '@workday/canvas-tokens-web'
4
+
5
+ import CreateStencil from './examples/CreateStencil';
6
+
7
+
8
+ # Stencils
9
+
10
+ Stencils are a reusable function that returns `style` and `className` props in an object. A Stencil
11
+ should apply to a single element. If your component has nested elements, you can youse `parts` to
12
+ targer those elements in the Stencil. If your component is a compound component, a stencil should be
13
+ created for each subcomponent. If your component is a config component, a stencil can have nested
14
+ styles.
15
+
16
+ We created Stencils as the reusable primitive of components. Stencils provide:
17
+
18
+ - `vars`: CSS variables for dynamic properties
19
+ - `base`: base styles to any component
20
+ - `modifier`: modifiers like “size = small,medium,large” or “color=red,blue,etc”
21
+ - `parts`: matching sub-elements that are part of a component
22
+ - `compound`: compound modifiers - styles that match multiple modifiers
23
+
24
+ ## Basic Example
25
+ In the example below, Stencils allow you to dynamically style elements or components based on properties.
26
+
27
+ <ExampleCodeBlock code={CreateStencil} />
28
+
29
+ ## When to Use `createStencil`
30
+ - When you're styling parts of a component that rely on dynamic properties.
31
+ - When you want to create a reusable component with dynamic styles.
32
+
33
+
34
+ Use a Stencil when building reusable components that have dynamic styles and properties.
35
+
36
+ ## Concepts
37
+
38
+ ### Base styles
39
+
40
+ Base styles are always applied to a Stencil. All your default styles should go here. Base styles
41
+ support psuedo selectors like `:focus-visible` or `:hover` as well as child selectors. Any selector
42
+ supported by `@emotion/css` is valid here. All styles must be static and statically analyzable by
43
+ the tranformer. If you need dynamic styling, look at Variables and Modifiers.
44
+
45
+ ### Variables
46
+
47
+ Variables allow some properties to be dynamic. They work by creating
48
+ [CSS Variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) with
49
+ unique names and are applied using the
50
+ [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) property of an element
51
+ to locally scope an override. Since we don't have access to those names, we need a function wrapper
52
+ around our style objects. This includes `base`, `modifiers`, and `compound` modifiers.
53
+
54
+ Here's a simplified example:
55
+
56
+ ```tsx
57
+ const myStencil = createStencil({
58
+ vars: {
59
+ defaultColor: 'red' // default value
60
+ nonDefaultedColor: '', // will allow for uninitialization
61
+ },
62
+ base: ({defaultColor}) => {
63
+ color: defaultColor // `defaultColor` is '--defaultColor-abc123', not 'red'
64
+ }
65
+ })
66
+
67
+ const elemProps = myStencil({color: 'blue'}) // {style: {'--defaultColor-abc123': 'blue'}}
68
+
69
+ <div {...elemProps} />
70
+ ```
71
+
72
+ This will produce the following HTML:
73
+
74
+ ```html
75
+ <style>
76
+ .css-abc123 {
77
+ --defaultColor-abc123: red;
78
+ color: var(--defaultColor-abc123);
79
+ }
80
+ </style>
81
+ <div class="css-123abc" style="--defaultColor-abc123: blue;"></div>
82
+ ```
83
+
84
+ The element will have a `color` property of `'blue'` because the element style is the highest
85
+ specificity and wins over a local class name. In the "Styles" tab of developer tools, it will look
86
+ like the following:
87
+
88
+ ```
89
+ element.style {
90
+ --defaultColor-abc123: blue;
91
+ }
92
+
93
+ .css-abc123 {
94
+ --defaultColor-abc123: red;
95
+ color: var(--defaultColor-abc123); // blue
96
+ }
97
+ ```
98
+
99
+ Variables are automatically added to the config of a Stencil. They share the same namespace as
100
+ modifiers, so **do not have a modifier with the same name as a variable**.
101
+
102
+ <InformationHighlight className="sb-unstyled" cs={{marginBlock: system.space.x4,}}>
103
+ <InformationHighlight.Icon />
104
+ <InformationHighlight.Heading>Note</InformationHighlight.Heading>
105
+ <InformationHighlight.Body>
106
+ Variables should be used sparingly. Style properties can be easily overridden without
107
+ variables. Variables are useful if you want to expose changing properties regardless of selectors.
108
+ For example, Buttons use variables for colors of all states (hover, active, focus, disabled, and
109
+ nested icons). Without variables, overriding the focus color would require deeply nested selector
110
+ overrides.
111
+ </InformationHighlight.Body>
112
+ </InformationHighlight>
113
+
114
+ #### Cascading Variables
115
+
116
+ Notice the `nonDefaultedColor` is not included in the base styles like `defaultColor` was. If a
117
+ variable has an empty string, it will can be uninitialized. Stencil variables with a default value
118
+ will create a "cascade barrier". A cascade barrier prevents the variable from "leaking" into the
119
+ component. For example, if a `Card` component was rendered within another `Card` component, the
120
+ variables from the parent `Card` would not leak into the child `Card` component. But there are times
121
+ where a component expects a parent component to set a CSS variable and that it should cascade to the
122
+ component. An example of this is the relationship between `SystemIcon` and `Button`. The `Button`
123
+ components set the `SystemIcon` variables and they should cascade into the `SystemIcon` component.
124
+
125
+ <InformationHighlight className="sb-unstyled" cs={{marginBlock: system.space.x4,}}>
126
+ <InformationHighlight.Icon />
127
+ <InformationHighlight.Heading>Note</InformationHighlight.Heading>
128
+ <InformationHighlight.Body>
129
+ Non-cascade variables _could_ be initialized. If you use uninitialized variables, be sure
130
+ to use a fallback in your styles.
131
+ </InformationHighlight.Body>
132
+ </InformationHighlight>
133
+
134
+ ```tsx
135
+ const myStencil = createStencil({
136
+ vars: {
137
+ color: '', // uninitialized
138
+ },
139
+ base({color}) {
140
+ return {
141
+ // provide a fallback. A uninitialized CSS variable will fall back to `initial`.
142
+ // for the `color` CSS property, that's most likely black (default text color)
143
+ color: cssVar(color, 'red'),
144
+ };
145
+ },
146
+ });
147
+ ```
148
+
149
+ #### Nested Variables
150
+
151
+ Variables can be nested one level. This can be useful for colors with different psuedo selectors
152
+ like `:hover` or `:focus`. Here's an example:
153
+
154
+ ```tsx
155
+ const myStencil = createStencil({
156
+ vars: {
157
+ default: {
158
+ color: 'red'
159
+ },
160
+ hover: {
161
+ color: 'blue'
162
+ },
163
+ focus: {
164
+ color: 'orange'
165
+ }
166
+ },
167
+ base: ({default, hover, focus}) => {
168
+ color: default.color,
169
+ '&:hover': {
170
+ color: hover.color
171
+ },
172
+ '&:focus': {
173
+ color: focus.color
174
+ }
175
+ }
176
+ })
177
+ ```
178
+
179
+ ### Modifiers
180
+
181
+ Modifiers are modifications to base styles. It should be used to change the appearance of a base
182
+ style. For example, a button may have a modifier for "primary" or "secondary" which may change the
183
+ visual emphasis of the button. Each modifier has its own CSS class name and the stencil will return
184
+ the correct CSS classes to apply to an element based on what modifiers are active.
185
+
186
+ ```tsx
187
+ const buttonStencil = createStencil({
188
+ base: {
189
+ padding: 5
190
+ // base styles
191
+ },
192
+ modifiers: {
193
+ variant: { // modifier name
194
+ primary: {
195
+ background: 'blue'
196
+ },
197
+ secondary: {
198
+ background: 'gray'
199
+ }
200
+ }
201
+ },
202
+ defaultModifiers: {
203
+ variant: 'secondary'
204
+ }
205
+ })
206
+
207
+ const elemProps = myStencil({variant: 'primary'}) // {className: "css-a0 css-a1"}
208
+
209
+ <div {...elemProps} />
210
+ ```
211
+
212
+ The HTML may look something like this:
213
+
214
+ ```html
215
+ <style>
216
+ .css-a0 {
217
+ padding: 5px;
218
+ }
219
+ .css-a1 {
220
+ background: 'blue';
221
+ }
222
+ .css-a2 {
223
+ background: 'gray';
224
+ }
225
+ </style>
226
+ <div class="css-a0 css-a1"></div>
227
+ ```
228
+
229
+ The optional `defaultModifiers` config property will default modifiers to a value. If a modifier is
230
+ not passed to the stencil, the default will be used.
231
+
232
+ ```tsx
233
+ myStencil(); // className will be `'css-a0 css-a2'`
234
+ ```
235
+
236
+ ### Compound Modifiers
237
+
238
+ A compound modifier creates a new CSS class for the intersection of two or more modifiers. Each
239
+ modifier can have its own separate CSS class while the intersection is a different CSS class.
240
+
241
+ For example:
242
+
243
+ ```tsx
244
+ const buttonStencil = createStencil({
245
+ base: {
246
+ padding: 10,
247
+ // base styles
248
+ },
249
+ modifiers: {
250
+ size: {
251
+ // modifier name
252
+ large: {
253
+ padding: 20,
254
+ },
255
+ small: {
256
+ padding: 5,
257
+ },
258
+ },
259
+ iconPosition: {
260
+ start: {
261
+ paddingInlineStart: 5,
262
+ },
263
+ end: {
264
+ paddingInlineEnd: 5,
265
+ },
266
+ },
267
+ },
268
+ compound: [
269
+ {
270
+ modifiers: {size: 'large', position: 'start'},
271
+ styles: {
272
+ paddingInlineStart: 15,
273
+ },
274
+ },
275
+ {
276
+ modifiers: {size: 'small', position: 'end'},
277
+ styles: {
278
+ paddingInlineEnd: 0,
279
+ },
280
+ },
281
+ ],
282
+ });
283
+
284
+ <div {...buttonStencil()} />
285
+ <div {...buttonStencil({size: 'small'})} />
286
+ <div {...buttonStencil({size: 'small', iconPosition: 'end'})} />
287
+ ```
288
+
289
+ The HTML will look something like this:
290
+
291
+ ```html
292
+ <style>
293
+ .a0 {
294
+ padding: 10px;
295
+ }
296
+ .a1 {
297
+ padding: 20px;
298
+ }
299
+ .a2 {
300
+ padding: 5px;
301
+ }
302
+ .a3 {
303
+ padding-inline-start: 5px;
304
+ }
305
+ .a4 {
306
+ padding-inline-end: 5px;
307
+ }
308
+ .a5 {
309
+ padding-inline-start: 15px;
310
+ }
311
+ .a6 {
312
+ padding-inline-start: 0px;
313
+ }
314
+ </style>
315
+ <div class="a0"></div>
316
+ <div class="a0 a2"></div>
317
+ <div class="a0 a2 a4 a6"></div>
318
+ ```
319
+
320
+ Notice the stencil adds all the class names that match the base, modifiers, and compound modifiers.
321
+
322
+ ### Variables and Modifiers with same keys
323
+
324
+ It is possible to have a variable and modifier sharing the same key. The Stencil will accept either
325
+ the modifier option or a string. The value will be sent as a variable regardless while the modifer
326
+ will only match if it is a valid modifer key.
327
+
328
+ ```tsx
329
+ const buttonStencil = createStencil({
330
+ vars: {
331
+ width: '10px',
332
+ },
333
+ base({width}) {
334
+ return {
335
+ width: width,
336
+ };
337
+ },
338
+ modifiers: {
339
+ width: {
340
+ zero: {
341
+ width: '0', // overrides base styles
342
+ },
343
+ },
344
+ },
345
+ });
346
+
347
+ // `'zero'` is part of autocomplete
348
+ myStencil({width: 'zero'});
349
+ // returns {className: 'css-button css-button--width-zero', styles: { '--button-width': 'zero'}}
350
+
351
+ // width also accepts a string
352
+ myStencil({width: '10px'});
353
+ // returns {className: 'css-button', styles: { '--button-width': '10px'}}
354
+ ```
355
+
356
+ ## Styling Elements via Component Parts
357
+
358
+ The goal of compound components is to expose one component per semantic element. Most of the time
359
+ this means a 1:1 relationship of a component and DOM element. Sometimes a semantic element contains
360
+ non-semantic elements for styling. An example might be a `<button>` with a icon for visual
361
+ reinforcement, and a label for a semantic label. The semantic element is the `<button>` while the
362
+ icon has no semantic value and the label automatically provides the semantic button with an
363
+ accessible name. In order to style the icon and label elements, you have to know the DOM structure
364
+ to target those specific elements in order to style it.
365
+
366
+ ```jsx
367
+ import {createStencil} from '@workday/canvas-kit-styling';
368
+
369
+ const myButtonStencil = createStencil({
370
+ base: {
371
+ background: 'transparent',
372
+ i: {
373
+ // ...icon styles
374
+ },
375
+ span: {
376
+ // ...label styles
377
+ },
378
+ ':hover': {
379
+ // ...hover button styles
380
+ i: {
381
+ // ...hover icon styles
382
+ },
383
+ span: {
384
+ // ...hover label styles
385
+ },
386
+ },
387
+ },
388
+ });
389
+
390
+ const MyButton = ({children, ...elemProps}) => {
391
+ return (
392
+ <button {...handleCsProp(elemProps, myButtonStencil())}>
393
+ <i />
394
+ <span>{children}</span>
395
+ </button>
396
+ );
397
+ };
398
+ ```
399
+
400
+ ### Using Component Parts to Style Elements
401
+
402
+ To style elements in the render function, we'll need to choose what elements to add the parts to. In
403
+ the example below, we're able to spread the parts directly to elements. The Stencil will generate
404
+ the type and value most appropriate for the context the part is used. In the Stencil, the part is
405
+ represented by a string that looks like `[data-part="{partValue}"]` and in the render function, it
406
+ is an object that looks like `{'data-part': partValue}`.
407
+
408
+ ```jsx
409
+ import {createStencil, handleCsProp} from '@workday/canvas-kit-styling';
410
+
411
+ const myButtonStencil = createStencil({
412
+ parts: {
413
+ icon: 'my-button-icon',
414
+ label: 'my-button-label',
415
+ },
416
+ base: ({iconPart, labelPart}) => ({
417
+ background: 'transparent',
418
+ [iconPart]: {
419
+ // `[data-part="my-button-icon"]`
420
+ // ...icon styles
421
+ },
422
+ [labelPart]: {
423
+ // `[data-part="my-button-label"]`
424
+ // ...label styles
425
+ },
426
+ '&:hover': {
427
+ // ...hover styles for button element
428
+ [iconPart]: {
429
+ // ...hover styles for icon part
430
+ },
431
+ },
432
+ }),
433
+ });
434
+
435
+ const MyButton = ({children, ...elemProps}) => {
436
+ return (
437
+ <button {...handleCsProp(elemProps, myButtonStencil())}>
438
+ <i {...myButtonStencil.parts.icon} /> {/* data-part={my-button-icon} */}
439
+ <span {...myButtonStencil.parts.label}>{children}</span> {/* data-part={my-button-label} */}
440
+ </button>
441
+ );
442
+ };
443
+ ```
444
+
445
+ As a reusable component, you can use component parts to style elements that are not exposed in the
446
+ API. Consumers can also use the type safe Stencil to target that element to style it as well. As a
447
+ general rule, a Stencil maps to a component. Multiple Stencils per component usually means nested
448
+ elements that are not targets for style overrides.
449
+
450
+ <InformationHighlight className="sb-unstyled" cs={{marginBlock: system.space.x4,}}>
451
+ <InformationHighlight.Icon />
452
+ <InformationHighlight.Heading>Note</InformationHighlight.Heading>
453
+ <InformationHighlight.Body>
454
+ While component parts are a way to give access to elements in order to style, they
455
+ should be used sparingly. Using component parts increases CSS specificity. A component part should
456
+ not be used on a nested component that has its own Stencil. The result will be any style
457
+ properties defined with a component part will have a higher specificity than other styles.
458
+ </InformationHighlight.Body>
459
+ </InformationHighlight>
@@ -0,0 +1,246 @@
1
+ import {ExampleCodeBlock, SymbolDoc} from '@workday/canvas-kit-docs';
2
+ import CreateStyles from './examples/CreateStyles';
3
+ import CreateVars from './examples/CreateVars';
4
+
5
+
6
+ # Canvas Kit Styling Utilities
7
+
8
+ A collection of helpful functions for styling with `@workday/canvas-kit-styling`. While they're
9
+ fairly simple, they make styling much nicer.
10
+
11
+ ## Pixels to Rem
12
+
13
+ This function converts a `px` value (number) to `rem` (string). This keeps you from having to do any
14
+ tricky mental division or write irrational numbers.
15
+
16
+ ```ts
17
+ import {px2rem} from '@workday/canvas-kit-styling';
18
+ import {system} from '@workday/canvas-tokens-web';
19
+
20
+ const styles = {
21
+ // returns '0.0625rem'
22
+ margin: px2rem(1),
23
+ };
24
+ ```
25
+
26
+ ## Calc Functions
27
+
28
+ Calc functions are useful for doing basic math operations with CSS `calc()` and variables. They will
29
+ also wrap variables automatically in `var()`.
30
+
31
+ ### Add
32
+
33
+ This function returns a CSS `calc()` addition string.
34
+
35
+ ```ts
36
+ import {calc} from '@workday/canvas-kit-styling';
37
+ import {system} from '@workday/canvas-tokens-web';
38
+
39
+ const styles = {
40
+ // returns 'calc(var(--cnvs-sys-space-x1) + 0.125rem)'
41
+ padding: calc.add(system.space.x1, '0.125rem'),
42
+ };
43
+ ```
44
+
45
+ ### Subtract
46
+
47
+ This function returns a CSS `calc()` subtraction string.
48
+
49
+ ```ts
50
+ import {calc} from '@workday/canvas-kit-styling';
51
+ import {system} from '@workday/canvas-tokens-web';
52
+
53
+ const styles = {
54
+ // returns 'calc(var(--cnvs-sys-space-x1) - 0.125rem)'
55
+ padding: calc.subtract(system.space.x1, '0.125rem'),
56
+ };
57
+ ```
58
+
59
+ ### Multiply
60
+
61
+ This function returns a CSS `calc()` multiplication string.
62
+
63
+ ```ts
64
+ import {calc} from '@workday/canvas-kit-styling';
65
+ import {system} from '@workday/canvas-tokens-web';
66
+
67
+ const styles = {
68
+ // returns 'calc(var(--cnvs-sys-space-x1) * 3)'
69
+ padding: calc.multiply(system.space.x1, 3),
70
+ };
71
+ ```
72
+
73
+ ### Divide
74
+
75
+ This function returns a CSS `calc()` division string
76
+
77
+ ```ts
78
+ import {calc} from '@workday/canvas-kit-styling';
79
+ import {system} from '@workday/canvas-tokens-web';
80
+
81
+ const styles = {
82
+ // returns 'calc(var(--cnvs-sys-space-x1) / 2)'
83
+ padding: calc.divide(system.space.x1, 2),
84
+ };
85
+ ```
86
+
87
+ ### Negate
88
+
89
+ This function negates a CSS variable to give you the opposite value. This keeps you from having to
90
+ wrap the variable in `calc()` and multiplying by `-1`.
91
+
92
+ ```ts
93
+ import {calc} from '@workday/canvas-kit-styling';
94
+ import {system} from '@workday/canvas-tokens-web';
95
+
96
+ const styles = {
97
+ // returns 'calc(var(--cnvs-sys-space-x4) * -1)'
98
+ margin: calc.negate(system.space.x4),
99
+ };
100
+ ```
101
+
102
+ ## keyframes
103
+
104
+ The `keyframes` function re-exports the [Emotion CSS keyframes](https://emotion.sh/docs/keyframes)
105
+ function, but is compatible with a custom Emotion instance and is understood by the Static style
106
+ transformer.
107
+
108
+ ### Usage Example
109
+
110
+ ```tsx
111
+ import {system} from '@workday/canvas-tokens-web';
112
+ import {createComponent} from '@workday/canvas-kit-react/common';
113
+ import {
114
+ handleCsProp,
115
+ keyframes,
116
+ createStencil,
117
+ calc,
118
+ px2rem,
119
+ CSProps,
120
+ } from '@workday/canvas-kit-styling';
121
+
122
+ /**
123
+ * Keyframe for the dots loading animation.
124
+ */
125
+ const keyframesLoading = keyframes({
126
+ '0%, 80%, 100%': {
127
+ transform: 'scale(0)',
128
+ },
129
+ '40%': {
130
+ transform: 'scale(1)',
131
+ },
132
+ });
133
+
134
+ export const loadingStencil = createStencil({
135
+ base: {
136
+ display: 'inline-flex',
137
+ gap: system.space.x2,
138
+ width: system.space.x4,
139
+ height: system.space.x4,
140
+ fontSize: system.space.zero,
141
+ borderRadius: system.shape.round,
142
+ backgroundColor: system.color.bg.muted.softer,
143
+ outline: `${px2rem(2)} solid transparent`,
144
+ transform: 'scale(0)',
145
+ animationName: keyframesLoading,
146
+ animationDuration: calc.multiply('150ms', 35),
147
+ animationIterationCount: 'infinite',
148
+ animationTimingFunction: 'ease-in-out',
149
+ animationFillMode: 'both',
150
+ },
151
+ });
152
+
153
+ /**
154
+ * A simple component that displays three horizontal dots, to be used when some data is loading.
155
+ */
156
+ export const LoadingDot = createComponent('div')({
157
+ displayName: 'LoadingDots',
158
+ Component: ({...elemProps}: CSProps, ref, Element) => {
159
+ return <Element ref={ref} {...handleCsProp(elemProps, loadingStencil())}></Element>;
160
+ },
161
+ });
162
+ ```
163
+
164
+ ## injectGlobal
165
+
166
+ The `injectGlobal` function re-exports the
167
+ [Emotion CSS injectGlobal](https://emotion.sh/docs/@emotion/css#global-styles) function, but is
168
+ compatible with a custom Emotion instance and is understood by the Static style transformer.
169
+
170
+ ### Usage Example
171
+
172
+ ```tsx
173
+ import {createRoot} from 'react-dom/client';
174
+ import {fonts} from '@workday/canvas-kit-react-fonts';
175
+ import {system} from '@workday/canvas-tokens-web';
176
+ import {cssVar, injectGlobal} from '@workday/canvas-kit-styling';
177
+ import {App} from './App';
178
+
179
+ import '@workday/canvas-tokens-web/css/base/_variables.css';
180
+ import '@workday/canvas-tokens-web/css/brand/_variables.css';
181
+ import '@workday/canvas-tokens-web/css/system/_variables.css';
182
+
183
+ //@ts-ignore
184
+ injectGlobal({
185
+ ...fonts,
186
+ 'html, body': {
187
+ fontFamily: cssVar(system.fontFamily.default),
188
+ margin: 0,
189
+ minHeight: '100vh',
190
+ },
191
+ '#root, #root < div': {
192
+ minHeight: '100vh',
193
+ ...system.type.body.small,
194
+ },
195
+ });
196
+
197
+ const container = document.getElementById('root')!;
198
+ const root = createRoot(container);
199
+ root.render(<App />);
200
+ ```
201
+
202
+ ## Custom Emotion Instance
203
+
204
+ Static style injection happens during the parsing stages of the files. This means when you `import`
205
+ a component that uses static styling, the styles are injected immediately. This happens way before
206
+ rendering, so using the Emotion [CacheProvider](https://emotion.sh/docs/cache-provider) does not
207
+ work. A custom instance must be created _before_ any style utilities are called - during the
208
+ bootstrapping phase of an application. We don't have a working example because it requires an
209
+ isolated application, but here's an example adding a `nonce` to an application:
210
+
211
+ ```tsx
212
+ // bootstrap-styles.ts
213
+ import {createInstance} from '@workday/canvas-kit-styling';
214
+
215
+ // assuming this file is being called via a `script` tag and that
216
+ // script tag has a `nonce` attribute set from the server
217
+ createInstance({nonce: document.currentScript.nonce});
218
+
219
+ // index.ts
220
+ import React from 'react';
221
+ import ReactDOM from 'react-dom';
222
+
223
+ // call the bootstrap in the import list. This has the side-effect
224
+ // of creating an instance
225
+ import './bootstrap-styles';
226
+
227
+ import App from './App';
228
+
229
+ const root = ReactDOM.createRoot(document.querySelector('#root'));
230
+
231
+ root.render(<App />);
232
+
233
+ // App.tsx
234
+ import React from 'react';
235
+
236
+ // The following will create and inject styles. We cannot adjust
237
+ // the Emotion instance after this import
238
+ import {PrimaryButton} from '@workday/canvas-kit-react/button';
239
+
240
+ // if we call `createInstance` here, we'll get a warning in
241
+ // development mode
242
+
243
+ export default () => {
244
+ return <PrimaryButton>Button</PrimaryButton>;
245
+ };
246
+ ```