1 | /**
|
2 | @license
|
3 | Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
|
4 | This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
5 | The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
6 | The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
7 | Code distributed by Google as part of the polymer project is also
|
8 | subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
9 | */
|
10 |
|
11 | import { Store, Unsubscribe } from 'redux';
|
12 |
|
13 | type Constructor<T> = new(...args: any[]) => T;
|
14 |
|
15 | /**
|
16 | By using this `CustomElement` interface instead of `HTMLElement`, we avoid
|
17 | having the generated typings include most DOM API already provided by
|
18 | TypeScript. This is particularly useful since different versions of
|
19 | TypeScript may have different DOM API typings (e.g. TS 3.0.3 and TS 3.1.1).
|
20 | The required `isConnected` property is included to avoid the following
|
21 | TypeScript error:
|
22 |
|
23 | Type 'HTMLElement' has no properties in common with type 'CustomElement'.
|
24 | */
|
25 | interface CustomElement {
|
26 | connectedCallback?(): void;
|
27 | disconnectedCallback?(): void;
|
28 | readonly isConnected: boolean;
|
29 | }
|
30 |
|
31 | /**
|
32 | This is a JavaScript mixin that you can use to connect a Custom Element base
|
33 | class to a Redux store. The `stateChanged(state)` method will be called when
|
34 | the state is updated.
|
35 |
|
36 | Example:
|
37 |
|
38 | import { connect } from 'pwa-helpers/connect-mixin.js';
|
39 |
|
40 | class MyElement extends connect(store)(HTMLElement) {
|
41 | stateChanged(state) {
|
42 | this.textContent = state.data.count.toString();
|
43 | }
|
44 | }
|
45 | */
|
46 | export const connect =
|
47 | <S>(store: Store<S>) =>
|
48 | <T extends Constructor<CustomElement>>(baseElement: T) =>
|
49 | class extends baseElement {
|
50 | _storeUnsubscribe!: Unsubscribe;
|
51 |
|
52 | connectedCallback() {
|
53 | if (super.connectedCallback) {
|
54 | super.connectedCallback();
|
55 | }
|
56 |
|
57 | this._storeUnsubscribe = store.subscribe(() => this.stateChanged(store.getState()));
|
58 | this.stateChanged(store.getState());
|
59 | }
|
60 |
|
61 | disconnectedCallback() {
|
62 | this._storeUnsubscribe();
|
63 |
|
64 | if (super.disconnectedCallback) {
|
65 | super.disconnectedCallback();
|
66 | }
|
67 | }
|
68 |
|
69 | /**
|
70 | * The `stateChanged(state)` method will be called when the state is updated.
|
71 | */
|
72 | stateChanged(_state: S) {}
|
73 | };
|