|
1 | 1 | # Skinning
|
2 | 2 |
|
3 |
| -The react-sdk can be skinned to replace presentation components, CSS, or |
4 |
| -other relevant parts of the SDK. Typically consumers will replace entire |
5 |
| -components and get the ability for custom CSS as a result. |
6 |
| - |
7 |
| -This doc isn't exhaustive on how skinning works, though it should cover |
8 |
| -some of the more complicated parts such as component replacement. |
9 |
| - |
10 |
| -## Loading a skin |
11 |
| - |
12 |
| -1. Generate a `component-index.js` (preferably using the tools that the react-sdk |
13 |
| -exposes). This can typically be done with a npm script like `"reskindex -h src/header"`. |
14 |
| -2. In your app's entry point, add something like this code: |
15 |
| - ```javascript |
16 |
| - import {loadSkin} from "matrix-react-sdk"; |
17 |
| - loadSkin(import("component-index").components); |
18 |
| - // The rest of your imports go under this. |
19 |
| - ``` |
20 |
| -3. Import the remainder of the SDK and bootstrap your app. |
21 |
| - |
22 |
| -It is extremely important that you **do not** import anything else from the |
23 |
| -SDK prior to loading your skin as otherwise the skin might not work. Loading |
24 |
| -the skin should be one of the first things your app does, if not the very |
25 |
| -first thing. |
26 |
| - |
27 |
| -Additionally, **do not** provide `loadSkin` with the react-sdk components |
28 |
| -themselves otherwise the app might explode. The SDK is already aware of its |
29 |
| -components and doesn't need to be told. |
30 |
| - |
31 |
| -## Replacing components |
32 |
| - |
33 |
| -Components that replace the react-sdk ones MUST have a `replaces` static |
34 |
| -key on the component's class to describe which component it overrides. For |
35 |
| -example, if your `VectorAuthPage` component is meant to replace the react-sdk |
36 |
| -`AuthPage` component then you'd add `static replaces = 'views.auth.AuthPage';` |
37 |
| -to the `VectorAuthPage` class. |
38 |
| - |
39 |
| -Other than that, the skin just needs to be loaded normally as mentioned above. |
40 |
| -Consumers of the SDK likely will not be interested in the rest of this section. |
41 |
| - |
42 |
| -### SDK developer notes |
43 |
| - |
44 |
| -Components in the react-sdk MUST be decorated with the `@replaceableComponent` |
45 |
| -function. For components that can't use the decorator, they must use a |
46 |
| -variation that provides similar functionality. The decorator gives consumers |
47 |
| -an opportunity to load skinned components by abusing import ordering and |
48 |
| -behaviour. |
49 |
| - |
50 |
| -Decorators are executed at import time which is why we can abuse the import |
51 |
| -ordering behaviour: importing `loadSkin` doesn't trigger any components to |
52 |
| -be imported, allowing the consumer to specify a skin. When the consumer does |
53 |
| -import a component (for example, `MatrixChat`), it starts to pull in all the |
54 |
| -components via `import` statements. When the components get pulled in the |
55 |
| -decorator checks with the skinned components to see if it should be replacing |
56 |
| -the component being imported. The decorator then effectively replaces the |
57 |
| -components when needed by specifying the skinned component as an override for |
58 |
| -the SDK's component, which should in theory override critical functions like |
59 |
| -`render()` and lifecycle event handlers. |
60 |
| - |
61 |
| -The decorator also means that older usage of `getComponent()` is no longer |
62 |
| -required because components should be replaced by the decorator. Eventually |
63 |
| -the react-sdk should only have one usage of `getComponent()`: the decorator. |
64 |
| - |
65 |
| -The decorator assumes that if `getComponent()` returns null that there is |
66 |
| -no skinned version of the component and continues on using the SDK's component. |
67 |
| -In previous versions of the SDK, the function would throw an error instead |
68 |
| -because it also expected the skin to list the SDK's components as well, however |
69 |
| -that is no longer possible due to the above. |
70 |
| - |
71 |
| -In short, components should always be `import`ed. |
| 3 | +Skinning in the context of the react-sdk is component replacement rather than CSS. This means you can override (replace) |
| 4 | +any accessible component in the project to implement custom behaviour, look & feel, etc. Depending on your approach, |
| 5 | +overriding CSS classes to apply custom styling is also possible, though harder to do. |
| 6 | + |
| 7 | +At present, the react-sdk offers no stable interface for components - this means properties and state can and do change |
| 8 | +at any time without notice. Once we determine the react-sdk to be stable enough to use as a proper SDK, we will adjust |
| 9 | +this policy. In the meantime, skinning is done completely at your own risk. |
| 10 | + |
| 11 | +The approach you take is up to you - we suggest using a module replacement plugin, as found in |
| 12 | +[webpack](https://webpack.js.org/plugins/normal-module-replacement-plugin/), though you're free to use whichever build |
| 13 | +system works for you. The react-sdk does not have any particular functions to call to load skins, so simply replace or |
| 14 | +extend the components/stores/etc you're after and build. As a reminder though, this is done completely at your own risk |
| 15 | +as we cannot guarantee a stable interface at this time. |
| 16 | + |
| 17 | +Taking a look at [element-web](https://github.com/vector-im/element-web)'s approach to skinning may be worthwhile, as it |
| 18 | +overrides some relatively simple components. |
0 commit comments