@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.
- package/dist/es6/lib/docs.js +55 -16
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.js +5 -5
- package/dist/es6/lib/stackblitzFiles/packageJSONFile.ts +5 -5
- package/dist/mdx/styling/mdx/CreateStyles.mdx +111 -0
- package/dist/mdx/styling/mdx/CustomizingStyles.mdx +179 -0
- package/dist/mdx/styling/mdx/FromEmotion.mdx +178 -0
- package/dist/mdx/styling/mdx/MergingStyles.mdx +164 -0
- package/dist/mdx/styling/mdx/Overview.mdx +254 -0
- package/dist/mdx/styling/mdx/Stencils.mdx +459 -0
- package/dist/mdx/styling/mdx/Utilities.mdx +246 -0
- package/dist/mdx/styling/mdx/WhyCanvasStyling.mdx +136 -0
- package/dist/mdx/styling/mdx/examples/CSProp.tsx +36 -0
- package/dist/mdx/styling/mdx/examples/CreateModifiers.tsx +27 -0
- package/dist/mdx/styling/mdx/examples/CreateStencil.tsx +63 -0
- package/dist/mdx/styling/mdx/examples/CreateStyles.tsx +13 -0
- package/dist/mdx/styling/mdx/examples/CreateVars.tsx +20 -0
- package/dist/mdx/styling/mdx/examples/CustomButton.tsx +69 -0
- package/dist/mdx/styling/mdx/examples/CustomIcon.tsx +23 -0
- package/dist/mdx/styling/mdx/examples/EmotionButton.tsx +111 -0
- package/dist/mdx/styling/mdx/examples/ManualStylesButton.tsx +107 -0
- package/dist/mdx/styling/mdx/examples/StyledButton.tsx +31 -0
- package/dist/mdx/styling/mdx/examples/StylingButton.tsx +107 -0
- package/dist/mdx/styling/mdx/examples/StylingOverrides.tsx +158 -0
- package/package.json +6 -6
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import {ExampleCodeBlock} from '@workday/canvas-kit-docs';
|
|
2
|
+
import EmotionButton from './examples/EmotionButton';
|
|
3
|
+
import ManualStylesButton from './examples/ManualStylesButton';
|
|
4
|
+
import StylingButton from './examples/StylingButton';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Converting from @emotion/styled
|
|
8
|
+
|
|
9
|
+
The most difficult part of understanding styling without Emotion's runtime is the mindset shift. You
|
|
10
|
+
are using CSS to merge properties instead of JavaScript. This is essential to remove the runtime of
|
|
11
|
+
Emotion. We'll use a contrived button example using `@emotion/styled` and our styling solution to
|
|
12
|
+
step through the differences.
|
|
13
|
+
|
|
14
|
+
## Button using `@emotion/styled`
|
|
15
|
+
|
|
16
|
+
<ExampleCodeBlock code={EmotionButton} />
|
|
17
|
+
|
|
18
|
+
If we inspect each button, we'll notice each has a different class name. They all look like
|
|
19
|
+
`css-{hash}`:
|
|
20
|
+
|
|
21
|
+
For example, the Primary buttons:
|
|
22
|
+
|
|
23
|
+
- Primary Large: `css-oqv33j`
|
|
24
|
+
- Primary Medium: `css-1nhzlx`
|
|
25
|
+
- Primary Small: `css-1ygk6q`
|
|
26
|
+
|
|
27
|
+
This means each button is a unique style sheet insert by Emotion. If we render each permutation at
|
|
28
|
+
once, there will only be one expensive
|
|
29
|
+
[style recalculation](https://microsoftedge.github.io/DevTools/explainers/StyleTracing/explainer.html)
|
|
30
|
+
|
|
31
|
+
Converting to use the Canvas Kit Styling solution means organizing a little different. In our
|
|
32
|
+
example, it is already organized well, but conditionals might be anywhere in the style functions and
|
|
33
|
+
will need to be organized in groups.
|
|
34
|
+
|
|
35
|
+
## Button using only `createStyles`
|
|
36
|
+
|
|
37
|
+
What are we really trying to accomplish? [BEM](https://getbem.com/introduction) fits well with
|
|
38
|
+
compound components. BEM stands for Block, Element, Modifer. In compound components, "Block" refers
|
|
39
|
+
to a container component while "Element" refers to subcomponets. The "Modifer" refers to changing
|
|
40
|
+
the appearance of a block.
|
|
41
|
+
|
|
42
|
+
In our example, all styles that are common to all appearances of our button. It might be
|
|
43
|
+
`borderRadius`, `fontFamily`. We can use `createStyles` to define these styles:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
const baseStyles = createStyles({
|
|
47
|
+
fontSize: '1rem',
|
|
48
|
+
display: 'flex',
|
|
49
|
+
borderRadius: '1rem',
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The `variant` modifiers use a variable prop called `backgroundColor` which cannot be variable at
|
|
54
|
+
runtime. We need to use a CSS Variable for this.
|
|
55
|
+
|
|
56
|
+
We can create modifers using `createStyles` and organize them in an object:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const modifierStyles = {
|
|
60
|
+
variant: {
|
|
61
|
+
primary: createStyles({
|
|
62
|
+
background: `var(--background-color-button, blue)`,
|
|
63
|
+
color: 'white',
|
|
64
|
+
}),
|
|
65
|
+
secondary: createStyles({
|
|
66
|
+
background: `var(--background-color-button, gray)`,
|
|
67
|
+
}),
|
|
68
|
+
danger: createStyles({
|
|
69
|
+
background: `var(--background-color-button, red)`,
|
|
70
|
+
}),
|
|
71
|
+
},
|
|
72
|
+
size: {
|
|
73
|
+
large: createStyles({
|
|
74
|
+
fontSize: '1.4rem',
|
|
75
|
+
height: '2rem',
|
|
76
|
+
}),
|
|
77
|
+
medium: createStyles({
|
|
78
|
+
fontSize: '1rem',
|
|
79
|
+
height: '1.5rem',
|
|
80
|
+
}),
|
|
81
|
+
small: createStyles({
|
|
82
|
+
fontSize: '0.8rem',
|
|
83
|
+
height: '1.2rem',
|
|
84
|
+
}),
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Each modifier value uses `createStyles` which returns a different class name. This means we can
|
|
90
|
+
create a "Primary Large" button by applying these modifiers to the `className` prop of a React
|
|
91
|
+
element:
|
|
92
|
+
|
|
93
|
+
```jsx
|
|
94
|
+
<button className={`${baseStyles} ${modifierStyles.variant.primary} ${modifierStyles.size.large}`}>
|
|
95
|
+
Primary Large
|
|
96
|
+
</button>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This will create a button with 3 separate class names applied. `@emotion/styled` only applies a
|
|
100
|
+
single css class name.
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<!-- @emotion/styled -->
|
|
104
|
+
<button class="css-108wq52">Primary Large</button>
|
|
105
|
+
|
|
106
|
+
<!-- createStyles -->
|
|
107
|
+
<button class="css-puxv12 css-puxv13 css-puxv16">Primary Large</button>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If you want to change the background color, you'll have to pass it using `style`:
|
|
111
|
+
|
|
112
|
+
```jsx
|
|
113
|
+
<button
|
|
114
|
+
className={`${baseStyles} ${modifierStyles.size.large}`}
|
|
115
|
+
style={{'--color-background-button': 'orange'}}
|
|
116
|
+
>
|
|
117
|
+
Orange Large
|
|
118
|
+
</button>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The output HTML will look like:
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<button class="css-puxv12 css-puxv16" style="--color-background-button: orange;">
|
|
125
|
+
Orange Large
|
|
126
|
+
</button>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This works because CSS Custom Properties cascade values. The `style` attribute defines styles on the
|
|
130
|
+
element directly. This is a runtime in React that allows us to change a style without a new style
|
|
131
|
+
block - the styles can be static, but we can still have variable property values.
|
|
132
|
+
|
|
133
|
+
<ExampleCodeBlock code={ManualStylesButton} />
|
|
134
|
+
|
|
135
|
+
## Button using all utilities
|
|
136
|
+
|
|
137
|
+
If we want variables that are hashed and make it easier to define and use, we have `createVars`.
|
|
138
|
+
There are also edge cases for modifiers like allowing `undefined`, so we made a `createModifiers`
|
|
139
|
+
function as well. Both `createModifiers` and `createVars` return a function that makes it easier to
|
|
140
|
+
call with inputs and will return the correct output.
|
|
141
|
+
|
|
142
|
+
For example, `createModifiers`:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
const myModifiers = createModifiers({
|
|
146
|
+
size: {
|
|
147
|
+
large: 'button-large',
|
|
148
|
+
small: 'button-small'
|
|
149
|
+
}
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
myModifiers.size.large // 'button-large'
|
|
153
|
+
|
|
154
|
+
// the function knows what config can be passed
|
|
155
|
+
// and what restrictions each value has
|
|
156
|
+
myModifiers({size: 'large'}) // 'button-large'
|
|
157
|
+
myModifiers({size: 'small'}) // 'button-small'
|
|
158
|
+
myModifiers() // ''
|
|
159
|
+
|
|
160
|
+
// in a component
|
|
161
|
+
<div className={myModifiers({size: 'large'})} /> // <div class="button-large" />
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`createVars`:
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
const myVars = createVars('background', 'color')
|
|
168
|
+
|
|
169
|
+
myVars.color // something like `--color-{hash}`
|
|
170
|
+
|
|
171
|
+
// the function knows what keys are allowed
|
|
172
|
+
myVars({color: 'red'}) // {'--color-{hash}': 'red'}
|
|
173
|
+
|
|
174
|
+
// in a component
|
|
175
|
+
<div style={myVars({color: 'red'})} /> // <div style="--color-{hash}: red;">
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
<ExampleCodeBlock code={StylingButton} />
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {ExampleCodeBlock, SymbolDoc} 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
|
+
import StylingOverrides from './examples/StylingOverrides';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Merging Styles
|
|
8
|
+
|
|
9
|
+
## mergeStyles
|
|
10
|
+
|
|
11
|
+
In v9, we used `@emotion/styled` or `@emotion/react` for all styling which is a runtime styling
|
|
12
|
+
solution. Starting in v10, we're migrating our styling to a more static solution using
|
|
13
|
+
`createStyles` and the `cs` prop.
|
|
14
|
+
|
|
15
|
+
For a transition period, we're opting for backwards compatibility. If style props are present,
|
|
16
|
+
[styled components](https://emotion.sh/docs/styled) are used, or the
|
|
17
|
+
[css prop](https://emotion.sh/docs/css-prop) is used in a component, Emotion's style merging will be
|
|
18
|
+
invoked to make sure the following style precedence:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
createStyles > CSS Prop > Styled Component > Style props
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This will mean that any `css` prop or use of `styled` within the component tree _per element_ will
|
|
25
|
+
cause style class merging. For example:
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import styled from '@emotion/styled';
|
|
29
|
+
import {createStyles} from '@workday/canvas-kit-styling';
|
|
30
|
+
import {mergeStyles} from '@workday/canvas-kit-react/layout';
|
|
31
|
+
|
|
32
|
+
const styles1 = createStyles({
|
|
33
|
+
padding: 4,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const styles2 = createStyles({
|
|
37
|
+
padding: 12,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const Component1 = props => {
|
|
41
|
+
return <div {...mergeStyles(props, [styles1])} />;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const Component2 = props => {
|
|
45
|
+
return <Component1 cs={styles2} />;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const Component3 = styled(Component1)({
|
|
49
|
+
padding: 8,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const Component4 = props => {
|
|
53
|
+
return <Component3 cs={styles2} />;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default () => (
|
|
57
|
+
<>
|
|
58
|
+
<Component1 />
|
|
59
|
+
<Component2 />
|
|
60
|
+
<Component3 />
|
|
61
|
+
<Component4 />
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The `styled` component API is forcing `mergeStyles` to go into Emotion merge mode, which removes the
|
|
67
|
+
`style1` class name and creates a new class based on all the merged style properties. So
|
|
68
|
+
`.component3` is a new class created by Emotion at render time that merges `.style1` and
|
|
69
|
+
`{padding: 8px}`. `Component4` renders `Component3` with a `cs` prop, but `Component3` is already in
|
|
70
|
+
merge mode and so `Component4` will also merge all styles into a new class name of `.component4`
|
|
71
|
+
that has the styles from `.style1`, `.component3`, and `{padding: 12px}`:
|
|
72
|
+
|
|
73
|
+
```html
|
|
74
|
+
<head>
|
|
75
|
+
<style>
|
|
76
|
+
.styles1 {
|
|
77
|
+
padding: 4px;
|
|
78
|
+
}
|
|
79
|
+
.styles2 {
|
|
80
|
+
padding: 8px;
|
|
81
|
+
}
|
|
82
|
+
.component3 {
|
|
83
|
+
padding: 4px;
|
|
84
|
+
padding: 8px;
|
|
85
|
+
}
|
|
86
|
+
.component4 {
|
|
87
|
+
padding: 4px;
|
|
88
|
+
padding: 8px;
|
|
89
|
+
padding: 12px;
|
|
90
|
+
}
|
|
91
|
+
</style>
|
|
92
|
+
</head>
|
|
93
|
+
|
|
94
|
+
<div class="styles1"></div>
|
|
95
|
+
<div class="styles1 styles2"></div>
|
|
96
|
+
<div class="component3"></div>
|
|
97
|
+
<div class="component4"></div>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The `css` prop and `styled` component APIs will rewrite the `className` React prop by iterating over
|
|
101
|
+
all class names and seeing if any exist within the cache. If a class name does exist in the cache,
|
|
102
|
+
the CSS properties are copied to a new style property map until all the class names are evaluated
|
|
103
|
+
and removed from the `className` prop. Emotion will then combine all the CSS properties and inject a
|
|
104
|
+
new `StyleSheet` with a new class name and add that class name to the element.
|
|
105
|
+
|
|
106
|
+
The following example shows this style merging.
|
|
107
|
+
|
|
108
|
+
<ExampleCodeBlock code={StylingOverrides} />
|
|
109
|
+
|
|
110
|
+
CSS style property merging works by
|
|
111
|
+
[CSS specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity). If two matching
|
|
112
|
+
selectors have the same specificity, the last defined property wins. Stencils take advantage of this
|
|
113
|
+
by making all styles have the same specificity of `0-1-0` and inserting `base` styles, then
|
|
114
|
+
`modifiers` (in order), then `compound` modifiers (in order). This means if a property was defined
|
|
115
|
+
in `base`, a `modifier`, and a `compound` modifier, the `compound` modifier would win because it is
|
|
116
|
+
the last defined. This should be the expected order.
|
|
117
|
+
|
|
118
|
+
<InformationHighlight className="sb-unstyled" variant="caution" cs={{marginBlock: system.space.x4}}>
|
|
119
|
+
<InformationHighlight.Icon />
|
|
120
|
+
<InformationHighlight.Heading>Caution</InformationHighlight.Heading>
|
|
121
|
+
<InformationHighlight.Body>
|
|
122
|
+
While we support `mergeStyles` we'd advise against using this in your components so that users
|
|
123
|
+
can get the performance benefit of static styling using utilities like `createStyles` and
|
|
124
|
+
`createStencil` in tandem with the `cs` prop.
|
|
125
|
+
</InformationHighlight.Body>
|
|
126
|
+
</InformationHighlight>
|
|
127
|
+
|
|
128
|
+
### mergeStyles API
|
|
129
|
+
|
|
130
|
+
<SymbolDoc hideHeading name="mergeStyles" />
|
|
131
|
+
|
|
132
|
+
## handleCsProp
|
|
133
|
+
|
|
134
|
+
But what about when using components that use `@emotion/react` or `@emotion/styled`? Those libraries
|
|
135
|
+
use a different approach. Instead of multiple class names, they use a single, merged class name.
|
|
136
|
+
|
|
137
|
+
`handleCsProp` was created to handle integration with existing components that use the `css` prop
|
|
138
|
+
from `@emotion/react` or the `styled` components from `@emotion/styled`. If a class name from one of
|
|
139
|
+
those libraries is detected, style merging will follow the same rules as those libraries. Instead of
|
|
140
|
+
multiple class names, a single class name with all matching properties is created. The
|
|
141
|
+
`handleCsProp` also takes care of merging `style` props, `className` props, and can handle the `cs`
|
|
142
|
+
prop:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
const myStencil = createStencil({
|
|
146
|
+
// ...
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const MyComponent = elemProps => {
|
|
150
|
+
return <div {...handleProps(elemProps, myStencil({}))} />;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// All props will be merged for you
|
|
154
|
+
<MyComponent style={{color: 'red'}} className="my-classname" cs={{position: 'relative'}} />;
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`handleCsProp` will make sure the `style` prop is passed to the `div` and that the `my-classname`
|
|
158
|
+
CSS class name appears on the `div`'s class list. Also the `cs` prop will add the appropriate styles
|
|
159
|
+
to the element via a CSS class name. If your component needs to handle being passed a `className`,
|
|
160
|
+
`style`, or `cs` prop, use `handleCsProp`.
|
|
161
|
+
|
|
162
|
+
### handleCsProp API
|
|
163
|
+
|
|
164
|
+
<SymbolDoc hideHeading name="handleCsProp" />
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import {InformationHighlight} from '@workday/canvas-kit-preview-react/information-highlight';
|
|
2
|
+
import {Hyperlink} from '@workday/canvas-kit-react/button';
|
|
3
|
+
import {system} from '@workday/canvas-tokens-web'
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Canvas Kit Styling
|
|
7
|
+
|
|
8
|
+
## Introduction
|
|
9
|
+
|
|
10
|
+
Canvas Kit styling is a custom CSS-in-JS solution that provides both a runtime for development and a
|
|
11
|
+
static parsing process for build time. This system offers several key benefits:
|
|
12
|
+
|
|
13
|
+
- TypeScript autocomplete for enhanced developer experience
|
|
14
|
+
- Low runtime overhead for better performance
|
|
15
|
+
- Static CSS compilation for optimized builds
|
|
16
|
+
- Dynamic styling with CSS Variables for flexible design
|
|
17
|
+
|
|
18
|
+
The motivation behind this custom styling solution stems from the need to move beyond IE11 support
|
|
19
|
+
and implement performance improvements using static styling methods. For more details, refer to the
|
|
20
|
+
[Why Canvas Kit Styling](https://workday.github.io/canvas-kit/?path=/docs/styling-why-canvas-styling--docs)
|
|
21
|
+
section.
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
The Canvas Kit styling system consists of two main packages:
|
|
26
|
+
|
|
27
|
+
- `@workday/canvas-kit-styling` - Core styling utilities for runtime use
|
|
28
|
+
- `@workday/canvas-kit-styling-transform` - Build-time optimization tools
|
|
29
|
+
|
|
30
|
+
These packages work together to provide a CSS-in-JS experience during development while enabling optimized static CSS in production.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
yarn add @workday/canvas-kit-styling
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import React from 'react';
|
|
42
|
+
import {createRoot} from 'react-dom/client';
|
|
43
|
+
|
|
44
|
+
import {createStyles} from '@workday/canvas-kit-styling';
|
|
45
|
+
|
|
46
|
+
const myStyles = createStyles({
|
|
47
|
+
backgroundColor: 'red',
|
|
48
|
+
}); // returns the CSS class name created for this style
|
|
49
|
+
|
|
50
|
+
myStyles; // something like "css-{hash}"
|
|
51
|
+
|
|
52
|
+
const domNode = document.getElementById('root');
|
|
53
|
+
const root = createRoot(domNode);
|
|
54
|
+
|
|
55
|
+
root.render(<div className={myStyles}>Hello!</div>);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Development
|
|
59
|
+
|
|
60
|
+
Canvas Kit Styling comes with a runtime that doesn't need anything special for developement. The
|
|
61
|
+
runtime uses `@emotion/css` to include your styles on the page.
|
|
62
|
+
|
|
63
|
+
## Production
|
|
64
|
+
|
|
65
|
+
If you wish to use the static compilation, you must use the `@workday/canvas-kit-styling-transform`
|
|
66
|
+
package. Add the following to your project's `tsconfig.json` file:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"compilerOptions": {
|
|
71
|
+
// other options
|
|
72
|
+
"plugins": [
|
|
73
|
+
{
|
|
74
|
+
"transform": "@workday/canvas-kit-styling-transform",
|
|
75
|
+
"prefix": "css",
|
|
76
|
+
"fallbackFiles": [""]
|
|
77
|
+
}
|
|
78
|
+
]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
This adds a list of plugins to use when transforming TypeScript files into JavaScript files. The
|
|
84
|
+
[ts-patch](https://www.npmjs.com/package/ts-patch) projects uses the `plugins` when running
|
|
85
|
+
transforms.
|
|
86
|
+
|
|
87
|
+
### Webpack
|
|
88
|
+
|
|
89
|
+
You will need to transform TypeScript files using the `ts-patch` which is the same as the TypeScript
|
|
90
|
+
tanspiler except it uses TypeScript's
|
|
91
|
+
[transform API](https://levelup.gitconnected.com/writing-a-custom-typescript-ast-transformer-731e2b0b66e6)
|
|
92
|
+
to transform code during compilation.
|
|
93
|
+
|
|
94
|
+
In your webpack config, you add the following:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
{
|
|
98
|
+
rules: [
|
|
99
|
+
//...
|
|
100
|
+
{
|
|
101
|
+
test: /.\.tsx?$/,
|
|
102
|
+
loaders: [
|
|
103
|
+
// ts-loader
|
|
104
|
+
{
|
|
105
|
+
loader: require.resolve('ts-loader'),
|
|
106
|
+
options: {
|
|
107
|
+
compiler: 'ts-patch/compiler',
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
// OR awesome-typescript-loader
|
|
111
|
+
{
|
|
112
|
+
loader: require.resolve('awesome-typescript-loader'),
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Core Styling Approaches for Static Styling
|
|
121
|
+
For proper static styling there's two methods that you can use to apply styles.
|
|
122
|
+
1. Using `createStyles` for simple object base styles.
|
|
123
|
+
2. Using `createStencil` for dynamic styles and reusable components.
|
|
124
|
+
|
|
125
|
+
Both approaches are intended to be used in tandem with the `cs` prop when applying styles to our components.
|
|
126
|
+
|
|
127
|
+
### `cs` Prop
|
|
128
|
+
|
|
129
|
+
The `cs` prop takes in a single, or an array of values that are created by the `cs` function, a
|
|
130
|
+
string representing a CSS class name, or the return of the `createVars` function. It merges
|
|
131
|
+
everything together and applies `className` and `style` attributes to a React element. Most of our
|
|
132
|
+
components extend the `cs` prop so that you can statically apply styles to them.
|
|
133
|
+
|
|
134
|
+
> **Important**: While the `cs` prop accepts a style object, **this will not** be considered
|
|
135
|
+
> statically styling an element and you will lose the performance benefits. We plan on providing a babel plugin to extract these styles statically in a future version.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
import {system} from '@workday/canvas-tokens-webs';
|
|
139
|
+
import {PrimaryButton} from '@workday/canvas-kit-react/button';
|
|
140
|
+
|
|
141
|
+
const styles = createStyles({color: system.color.static.red.default});
|
|
142
|
+
|
|
143
|
+
function MyComponent() {
|
|
144
|
+
return <PrimaryButton cs={styles}>Text</PrimaryButton>;
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### `createStyles`
|
|
149
|
+
|
|
150
|
+
The primary utility function is the `createStyles` function. It makes a call to the `css` function
|
|
151
|
+
from `@emotion/css`. Emotion still does most of the heavy lifting by handling the serialization,
|
|
152
|
+
hashing, caching, and style injection.
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
// Bad example (inside render function)
|
|
156
|
+
import {system} from '@workday/canvas-tokens-webs';
|
|
157
|
+
import {PrimaryButton} from '@workday/canvas-kit-react/button';
|
|
158
|
+
|
|
159
|
+
function MyComponent() {
|
|
160
|
+
const styles = createStyles({color: system.color.static.red.default}); // Don't do this
|
|
161
|
+
return <PrimaryButton cs={styles}>Text</PrimaryButton>;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Good example (outside render function)
|
|
165
|
+
import {system} from '@workday/canvas-tokens-webs';
|
|
166
|
+
import {PrimaryButton} from '@workday/canvas-kit-react/button';
|
|
167
|
+
|
|
168
|
+
const styles = createStyles({color: system.color.static.red.default});
|
|
169
|
+
|
|
170
|
+
function MyComponent() {
|
|
171
|
+
return <PrimaryButton cs={styles}>Text</PrimaryButton>;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Most of our components support using the `cs` prop to apply the static styles. It merges
|
|
176
|
+
everything together and applies `className` and `style` attributes to a React element.
|
|
177
|
+
|
|
178
|
+
<InformationHighlight className="sb-unstyled" cs={{marginBlock: system.space.x4,}}>
|
|
179
|
+
<InformationHighlight.Icon />
|
|
180
|
+
<InformationHighlight.Heading>Information</InformationHighlight.Heading>
|
|
181
|
+
<InformationHighlight.Body>
|
|
182
|
+
For a more in depth overview, please view our <Hyperlink src="https://workday.github.io/canvas-kit/?path=/docs/styling-getting-started-create-styles--docs">Create Styles</Hyperlink> docs.
|
|
183
|
+
</InformationHighlight.Body>
|
|
184
|
+
</InformationHighlight>
|
|
185
|
+
|
|
186
|
+
### `createStencil`
|
|
187
|
+
|
|
188
|
+
`createStencil` is a function for creating reusable, complex component styling systems. It manages
|
|
189
|
+
`base` styles, `parts`, `modifiers`, `variables`, and `compound` modifiers. Most of our components
|
|
190
|
+
also export their own Stencil that might expose CSS variables in order to modify the component.
|
|
191
|
+
|
|
192
|
+
In the example below, we leverage `parts`, `vars`, `base` and `modifiers` to create a reusable
|
|
193
|
+
`Card` component. The Stencil allows us to dynamic style the component based on the props.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
import {createStencil}from '@workday/canvas-kit-styling';
|
|
197
|
+
import {Card} from '@workday/canvas-kit-react/card';
|
|
198
|
+
import {system} from '@workday/canvas-tokens-webs';
|
|
199
|
+
|
|
200
|
+
const themedCardStencil = createStencil({
|
|
201
|
+
vars: {
|
|
202
|
+
// Create CSS variables for the color of the header
|
|
203
|
+
headerColor: ''
|
|
204
|
+
},
|
|
205
|
+
parts: {
|
|
206
|
+
// Allows for styling a sub element of the component that may not be exposed through the API
|
|
207
|
+
header: 'themed-card-header'
|
|
208
|
+
},
|
|
209
|
+
base: ({headerPart, headerColor}) => ({
|
|
210
|
+
padding: system.space.x4,
|
|
211
|
+
boxShadow: system.depth[2],
|
|
212
|
+
backgroundColor: system.color.bg.default,
|
|
213
|
+
color: system.color.text.default,
|
|
214
|
+
// Targets the header part via [data-part="themed-card-header"]"]
|
|
215
|
+
[headerPart]: {
|
|
216
|
+
color: headerColor
|
|
217
|
+
}
|
|
218
|
+
}),
|
|
219
|
+
modifiers: {
|
|
220
|
+
isDarkTheme: {
|
|
221
|
+
// If the prop `isDarkTheme` is true, style the component and it's parts
|
|
222
|
+
true: ({headerPart}) => ({
|
|
223
|
+
backgroundColor: system.color.bg.contrast.default,
|
|
224
|
+
color: system.color.text.inverse
|
|
225
|
+
[headerPart]: {
|
|
226
|
+
color: system.color.text.inverse
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
const ThemedCard = ({isDarkTheme, headerColor, elemProps}) => {
|
|
234
|
+
return (
|
|
235
|
+
/* Use the `cs` prop to apply the stencil and pass it the dynamic properties it needs to style accordingly */
|
|
236
|
+
<Card cs={themedCardStencil({isDarkTheme, headerColor})} {...elemProps}>
|
|
237
|
+
/* Apply the data part selector to the header */
|
|
238
|
+
<Card.Heading {...themedCardStencil.parts.header}>Canvas Supreme</Card.Heading>
|
|
239
|
+
<Card.Body>
|
|
240
|
+
Our house special supreme pizza includes pepperoni, sausage, bell peppers, mushrooms,
|
|
241
|
+
onions, and oregano.
|
|
242
|
+
</Card.Body>
|
|
243
|
+
</Card>
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
<InformationHighlight className="sb-unstyled" cs={{marginBlock: system.space.x4,}}>
|
|
249
|
+
<InformationHighlight.Icon />
|
|
250
|
+
<InformationHighlight.Heading>Information</InformationHighlight.Heading>
|
|
251
|
+
<InformationHighlight.Body>
|
|
252
|
+
For a more in depth overview, please view our <Hyperlink src="https://workday.github.io/canvas-kit/?path=/docs/styling-getting-started-stencils--docs">Create Stencil</Hyperlink> docs.
|
|
253
|
+
</InformationHighlight.Body>
|
|
254
|
+
</InformationHighlight>
|