UNPKG

6.04 kBTypeScriptView Raw
1import { code, md } from '@kalamazoo/docs';
2
3export default md`
4
5## Theming
6
7Button now supports the updated Theming API. With this API, components can be passed a custom theming function which has access to all of Button's props, as well as the to the original ADG theme.
8
9This means that the custom theme can change appearance based on different props, and even ignore the ADG styling completely. Custom
10themes can modify any CSS prop on the button body or the loading spinner.
11
12#### ⚡️ Theming API TLDR:
13- **\`Button\`** can take a **\`theme\`** prop, a function called by the theming API to generate and return custom styling. It recieves all of Button's props, as well as the built-in ADG theme for button.
14- The **\`theme\` function** can choose to ignore the ADG theme completely, or spread custom styling on top.
15- How the custom styling is retrieved is left up to the user, but a common approach is to define the styling in an **object structure** and fetch using custom logic.
16- In use, buttons can be wrapped by a **\`ThemeProvider\`** that has the \`theme\` function passed in, or a component that wraps \`Button\` can be used in place of Button.
17
18### Building a Custom Themed Button
19
20There are two approaches to defining a custom button. The first is to wrap buttons in a ThemeProvider:
21
22${code`
23// CustomButton.js
24import React from 'react';
25import Button, { Theme as ButtonTheme } from '@kalamazoo/button';
26
27<ButtonTheme.Provider value={customTheme}>
28 <Button> both of these buttons </Button>
29 <Button> will recieve custom styling </Button>
30</ButtonTheme.Provider>
31`}
32
33The second approach is to create a wrapped Button component that passes in all existing props, as well as a custom \`theme\` prop:
34
35${code`
36// CustomButton.js
37import React from 'react';
38import Button from '@kalamazoo/button';
39
40export default (props) => (
41 <Button
42 {...props}
43 theme={customTheme}
44 }}
45 />
46);
47`}
48
49### Building the theming function
50
51In both cases, Button's \`theme\` prop expects a **theming function**, which is called by the theming API to style Button. \`theme\` should have the following footprint:
52
53${code`
54customTheme = (adgTheme, props) => styling
55`}
56
57The output of the function, \`styling\`, is an object containing a pair of style objects:
58- **\`ButtonStyles\`**, which contains styles for the body of Button.
59- **\`SpinnerStyles\`**, which contains styles for the loading spinner.
60
61Button applies these styles directly using Emotion's \`css\` prop - so you have complete control over how these components in Button are rendered.
62
63An example of how the theming function can be implemented is below:
64
65${code`
66customTheme = (currentTheme, themeProps) => {
67 const { buttonStyles, spinnerStyles } = currentTheme(themeProps);
68 return {
69 buttonStyles: {
70 ...buttonStyles,
71 ...extract(buttonTheme, themeProps),
72 },
73 spinnerStyles,
74 };
75`}
76
77In most cases, the props of interest will include \`appearance\`, \`state\` and \`mode\` - though any prop in Button can be used (including custom props, if you want to add any to your Button wrapper.).
78
79The \`extract\` function is an arbitrary function that takes Button's props, and generates the required styling. This is up to what your implementation requires.
80
81### Creating styling for Button with an object structure
82
83How the custom styles are determined based on Button's props can vary - for simple changes to Button, the \`theme\` function can return a static object. If defining multiple appearances, or changing something dependent on state, the styles will need to be computed in some function (\`extract\` in this example).
84
85When programmatically defining the styling, a common approach is to use an object structure similar to that listed below:
86
87${code`
88import { colors } from '@kalamazoo/theme';
89
90const buttonTheme = {
91 toolbar: {
92 background: {
93 default: { light: 'transparent' },
94 hover: { light: colors.DN60 },
95 active: { light: colors.B75 },
96 },
97 boxShadowColor: {
98 focus: { light: colors.B75 },
99 },
100 color: {
101 default: { light: colors.DN400 },
102 hover: { light: colors.DN400 },
103 active: { light: colors.B400 },
104 disabled: { light: colors.DN100 },
105 },
106 },
107 primary: {
108 background: {
109 default: { light: colors.B100 },
110 hover: { light: colors.B75 },
111 active: { light: colors.B200 },
112 disabled: { light: colors.DN70 },
113 },
114 boxShadowColor: {
115 focus: { light: colors.B75 },
116 },
117 color: {
118 default: { light: colors.DN30 },
119 },
120 },
121};`}
122
123#### Parsing the object structure
124
125An example of how this structure can be traversed to get the styles for the current combination of props is shown below:
126
127${code`
128function extract(newTheme, appearance, state, mode) {
129 if (!newTheme[appearance]) return;
130 const root = newTheme[appearance];
131 return Object.keys(root).reduce((acc, val) => {
132 let node = root;
133 [val, state, mode].forEach(item => {
134 if (!node[item]) return;
135 if (typeof node[item] !== 'object') {
136 acc[val] = node[item];
137 return;
138 }
139 node = node[item];
140 return;
141 });
142 return acc;
143 }, {});
144}`}
145
146This example function will explore the tree, and return all styling props with their correct values for the props provided. Note that if a value is not found, no value is returned for that styling prop - and therefore the ADG styling, or no styling, depending on how the \`theme\` function is defined.
147
148## Other theming guidelines
149### Dark Mode support
150
151Dark mode support can be added using the API as follows:
152
153${code`
154<Button theme={(theme, props) => theme({ ...props, mode: 'dark' })}
155 Dark Button
156</Button>
157`}
158
159### Styled-components support
160
161With the shift to Emotion in \`v12\`, styled-components' \`styled\` function is no longer supported. Emotion's \‘styled\’ function can be used in-place, but as this is not explicitly supported by Button, we recommend using the new theming API instead.
162
163More details on migration can be found in the \`v11\` to \`v12\` upgrade guide.
164
165`;