|
| 1 | +# Create a Custom Component Mapping |
| 2 | + |
| 3 | +Creation mapping for a custom component is a very similar process to [Mapping Customization](design-system/customize-mapping). Only in this case, we suggest the following simple but very important rules so that we can minimize the number of necessary changes and avoid repeated code. |
| 4 | + |
| 5 | +Before we start, let's pretend we want to create a `CircleButton` component. |
| 6 | + |
| 7 | +<hr> |
| 8 | + |
| 9 | +## Prepare the boilerplate |
| 10 | + |
| 11 | +In this step, we'll create a component and it's initial mapping. |
| 12 | + |
| 13 | +Create a component: |
| 14 | +```js |
| 15 | +import * as React from 'react'; |
| 16 | +import { TouchableOpacity } from 'react-native'; |
| 17 | +import { styled } from 'react-native-ui-kitten'; |
| 18 | + |
| 19 | +class CircleButton extends React.Component { |
| 20 | + static styledComponentName = 'CircleButton'; // <-- This is important! |
| 21 | + |
| 22 | + render() { |
| 23 | + const { themedStyle, style, ...restProps } = this.props; |
| 24 | + |
| 25 | + return ( |
| 26 | + <TouchableOpacity style={[themedStyle, style]} {...restProps} /> |
| 27 | + ); |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +export default styled(CircleButton); |
| 32 | +``` |
| 33 | + |
| 34 | +Create a custom mapping: |
| 35 | + |
| 36 | +```json |
| 37 | +{ |
| 38 | + "components": { |
| 39 | + "CircleButton": { |
| 40 | + "meta": { |
| 41 | + "parameters": {}, |
| 42 | + "variantGroups": {}, |
| 43 | + "states": {}, |
| 44 | + "appearances": { |
| 45 | + "filled": { |
| 46 | + "default": true |
| 47 | + } |
| 48 | + } |
| 49 | + }, |
| 50 | + "appearances": { |
| 51 | + "filled": { |
| 52 | + "mapping": {} |
| 53 | + } |
| 54 | + } |
| 55 | + } |
| 56 | + } |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +And pass it to an `ApplicationProvider` component: |
| 61 | + |
| 62 | +```js |
| 63 | +import * as React from 'react'; |
| 64 | +import { ApplicationProvider, Layout } from 'react-native-ui-kitten'; |
| 65 | +import { mapping, light as lightTheme } from '@eva-design/eva'; |
| 66 | +import { default as customMapping } from './path-to/custom-mapping.json'; // <-- Import custom mapping |
| 67 | +import CircleButton from './path-to/CircleButton'; // <-- Import custom component |
| 68 | + |
| 69 | +const App = () => ( |
| 70 | + <ApplicationProvider |
| 71 | + mapping={mapping} |
| 72 | + customMapping={customMapping} |
| 73 | + theme={lightTheme}> |
| 74 | + <Layout style={{padding: 64, alignItems: 'center'}}> |
| 75 | + <CircleButton /> |
| 76 | + </Layout> |
| 77 | + </ApplicationProvider> |
| 78 | +); |
| 79 | + |
| 80 | +export default App; |
| 81 | +``` |
| 82 | + |
| 83 | +<hr> |
| 84 | + |
| 85 | +## Start with an idea |
| 86 | + |
| 87 | +The main idea of `CircleButton` component is that is going to be a circle. This means we need to provide some dimension styles and a `borderRadius` to make it round. Go back to `custom-mapping.json` and paste the following: |
| 88 | + |
| 89 | +```json |
| 90 | +{ |
| 91 | + "components": { |
| 92 | + "CircleButton": { |
| 93 | + "meta": { |
| 94 | + "parameters": { // <-- Register parameters |
| 95 | + "width": { |
| 96 | + "type": "number" |
| 97 | + }, |
| 98 | + "height": { |
| 99 | + "type": "number" |
| 100 | + }, |
| 101 | + "borderRadius": { |
| 102 | + "type": "number" |
| 103 | + }, |
| 104 | + "backgroundColor": { |
| 105 | + "type": "number" |
| 106 | + } |
| 107 | + }, |
| 108 | + "variantGroups": {}, |
| 109 | + "states": {}, |
| 110 | + "appearances": { |
| 111 | + "filled": { |
| 112 | + "default": true |
| 113 | + } |
| 114 | + } |
| 115 | + }, |
| 116 | + "appearances": { |
| 117 | + "filled": { |
| 118 | + "mapping": { // <-- Parameters applied by a component |
| 119 | + "width": 64, |
| 120 | + "height": 64, |
| 121 | + "borderRadius": 32, |
| 122 | + "backgroundColor": "color-primary-default" |
| 123 | + } |
| 124 | + } |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | +} |
| 129 | +``` |
| 130 | + |
| 131 | +This is an initial look: |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | +<hr> |
| 136 | + |
| 137 | +## Expand with a variants |
| 138 | + |
| 139 | +The example above demonstrates how you can create a really simple configuration. And on this step you might think that it is over-engineering. Let's now do some magic now. |
| 140 | + |
| 141 | +```json |
| 142 | +{ |
| 143 | + "components": { |
| 144 | + "CircleButton": { |
| 145 | + "meta": { |
| 146 | + // ... |
| 147 | + "variantGroups": { |
| 148 | + "shape": { |
| 149 | + "rounded": { // <-- Register a `rounded` variant |
| 150 | + "default": false |
| 151 | + } |
| 152 | + } |
| 153 | + } |
| 154 | + }, |
| 155 | + "appearances": { |
| 156 | + "filled": { |
| 157 | + "mapping": { |
| 158 | + // ... |
| 159 | + } |
| 160 | + }, |
| 161 | + "variantGroups": { |
| 162 | + "shape": { |
| 163 | + "rounded": { // <-- Describes a `rounded` variant parameters |
| 164 | + "borderRadius": 16 |
| 165 | + } |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | + } |
| 170 | + } |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +What we did is that we added a rounded [variant](design-system/design-system-glossary#variant) which will make our `CircleButton` not such circle. And this is how it looks: |
| 175 | + |
| 176 | + |
| 177 | + |
| 178 | +<hr> |
| 179 | + |
| 180 | +## Add states |
| 181 | + |
| 182 | +The other great example of the flexibility of using mappings is that you can provide styles to your component for a particular state. Let's say we've pressed this Button and we won't to see the default feedback of `TouchableOpacity`, but make our Button a shade darker. |
| 183 | + |
| 184 | +```json |
| 185 | +{ |
| 186 | + "components": { |
| 187 | + "CircleButton": { |
| 188 | + "meta": { |
| 189 | + // ... |
| 190 | + "states": { |
| 191 | + "active": { // <-- Registers an `active` state |
| 192 | + "default": false |
| 193 | + } |
| 194 | + } |
| 195 | + }, |
| 196 | + "appearances": { |
| 197 | + "filled": { |
| 198 | + "mapping": { |
| 199 | + // ... |
| 200 | + "state": { |
| 201 | + "active": { // <-- Describes an `active` state parameters |
| 202 | + "backgroundColor": "color-primary-active" |
| 203 | + } |
| 204 | + } |
| 205 | + } |
| 206 | + }, |
| 207 | + "variantGroups": { |
| 208 | + // ... |
| 209 | + } |
| 210 | + } |
| 211 | + } |
| 212 | + } |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +And dispatch this state from a component. |
| 217 | + |
| 218 | +```js |
| 219 | +// ... |
| 220 | +import { styled, Interaction } from 'react-native-ui-kitten'; |
| 221 | + |
| 222 | +class CircleButton extends React.Component { |
| 223 | + static styledComponentName = 'CircleButton'; |
| 224 | + |
| 225 | + onPressIn = () => { |
| 226 | + // Dispatch an `active` state to High Order Component |
| 227 | + this.props.dispatch([Interaction.ACTIVE]); |
| 228 | + }; |
| 229 | + |
| 230 | + onPressOut = () => { |
| 231 | + // Go back to the default state |
| 232 | + this.props.dispatch([]); |
| 233 | + }; |
| 234 | + |
| 235 | + render() { |
| 236 | + const { themedStyle, style, ...restProps } = this.props; |
| 237 | + |
| 238 | + return ( |
| 239 | + <TouchableOpacity |
| 240 | + style={[themedStyle, style]} |
| 241 | + onPressIn={this.onPressIn} |
| 242 | + {...restProps} |
| 243 | + /> |
| 244 | + ); |
| 245 | + } |
| 246 | +} |
| 247 | +``` |
| 248 | + |
| 249 | +What we have done here is we used `dispatch` prop provided from by a `styled` HOC we previously wrapped our component. And now, when we press a Button, it will be re-rendered with a new color. But when we release it, it will be filled with a default color. |
| 250 | + |
| 251 | +That's it. Here is the result: |
| 252 | + |
| 253 | +<p align="center"> |
| 254 | + |
| 255 | +</p> |
| 256 | + |
| 257 | +<hr> |
| 258 | + |
| 259 | +## Conclusion |
| 260 | + |
| 261 | +Using this way of styling components, you can also declare more [semantic parameters](design-system/design-system-glossary#semantic-properties) to get more flexibility. Try adding one more variant or appearance following the steps described above to feel the real power of UI Kitten theme system. |
| 262 | + |
| 263 | +<hr> |
| 264 | + |
| 265 | +## Related Articles |
| 266 | + |
| 267 | +- [Customize mapping](design-system/custom-component-mapping) |
0 commit comments