|
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