├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .vscode
└── tasks.json
├── README.md
├── package-lock.json
├── package.json
├── tsconfig.json
└── useLiveState.ts
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: push
4 |
5 | jobs:
6 | test:
7 | name: Build and run tests
8 | runs-on: ubuntu-20.04
9 |
10 | steps:
11 | - name: Checkout project
12 | uses: actions/checkout@v3
13 | - name: Install dependencies
14 | run: npm install
15 | - name: Build
16 | run: npm run build
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | build
3 | node_modules
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "mix test",
6 | "type": "shell",
7 | "command": "mix",
8 | "args": [
9 | "test",
10 | "--color"
11 | ],
12 | "options": {
13 | "cwd": "${workspaceRoot}",
14 | "requireFiles": [
15 | "test/**/test_helper.exs",
16 | "test/**/*_test.exs"
17 | ]
18 | },
19 | "problemMatcher": "$mixTestFailure"
20 | },
21 | {
22 | "label": "mix test failed",
23 | "type": "shell",
24 | "command": "mix",
25 | "args": [
26 | "test",
27 | "--color",
28 | "--failed",
29 | "--trace"
30 | ],
31 | "options": {
32 | "cwd": "${workspaceRoot}",
33 | "requireFiles": [
34 | "test/**/test_helper.exs",
35 | "test/**/*_test.exs"
36 | ]
37 | },
38 | "problemMatcher": "$mixTestFailure"
39 | },
40 | {
41 | "label": "mix test file",
42 | "type": "shell",
43 | "command": "mix",
44 | "args": [
45 | "test",
46 | "${relativeFile}",
47 | "--color",
48 | "--trace"
49 | ],
50 | "options": {
51 | "cwd": "${workspaceRoot}",
52 | "requireFiles": [
53 | "test/**/test_helper.exs",
54 | "test/**/*_test.exs"
55 | ]
56 | },
57 | "problemMatcher": "$mixTestFailure"
58 | },
59 | {
60 | "label": "run testbed test at cursor",
61 | "type": "shell",
62 | "command": "mix",
63 | "args": [
64 | "test",
65 | "../${relativeFile}:${lineNumber}",
66 | "--color",
67 | "--trace"
68 | ],
69 | "options": {
70 | "cwd": "${workspaceRoot}/testbed",
71 | "requireFiles": [
72 | "test/**/test_helper.exs",
73 | "test/**/*_test.exs"
74 | ],
75 | "env": {
76 | "GCP_CREDENTIALS": "{\"stuff\": \"foo\"}"
77 | }
78 | },
79 | "problemMatcher": "$mixTestFailure",
80 | "group": {
81 | "kind": "test",
82 | "isDefault": true
83 | }
84 | },
85 | {
86 | "label": "Initial Setup",
87 | "type": "process",
88 | "command": "mix",
89 | "args": [
90 | "setup"
91 | ],
92 | "options": {
93 | "cwd": "${workspaceRoot}"
94 | },
95 | "problemMatcher": [
96 | "$mixCompileError"
97 | ]
98 | },
99 | {
100 | "label": "mix compile",
101 | "type": "process",
102 | "command": "mix",
103 | "args": [
104 | "test",
105 | "--exclude",
106 | "test",
107 | "--warnings-as-errors"
108 | ],
109 | "options": {
110 | "cwd": "${workspaceRoot}"
111 | },
112 | "problemMatcher": [
113 | "$mixCompileWarning",
114 | "$mixCompileError"
115 | ],
116 | "group": {
117 | "kind": "build",
118 | "isDefault": true
119 | }
120 | },
121 | {
122 | "label": "mix format",
123 | "type": "process",
124 | "command": "mix",
125 | "args": [
126 | "format"
127 | ],
128 | "options": {
129 | "cwd": "${workspaceRoot}"
130 | },
131 | "problemMatcher": [
132 | "$mixCompileWarning",
133 | "$mixCompileError"
134 | ],
135 | "group": {
136 | "kind": "build",
137 | "isDefault": true
138 | }
139 | },
140 | {
141 | "label": "mix check",
142 | "type": "process",
143 | "command": "mix",
144 | "args": [
145 | "check"
146 | ],
147 | "options": {
148 | "cwd": "${workspaceRoot}"
149 | },
150 | "problemMatcher": [
151 | "$mixCompileWarning",
152 | "$mixCompileError"
153 | ],
154 | "group": {
155 | "kind": "build",
156 | "isDefault": true
157 | }
158 | }
159 | ]
160 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # use-lives-state
2 |
3 | This package provides a lil tiny react hook to facilitate React components that have their state managed by LiveState.
4 |
5 | ## Usage
6 |
7 | Add it just like any npm:
8 |
9 | ```
10 | npm install use-live-state
11 | ```
12 |
13 | Make a LiveState instance:
14 |
15 | ```typescript
16 | import LiveState from "phx-live-state";
17 |
18 | export const liveState = new LiveState('ws://localhost:4002/socket', 'todo:all');
19 | ```
20 |
21 | Then, in your components:
22 |
23 | ```typescript
24 | import React, { Component } from 'react';
25 | import { liveState } from './live_state';
26 | import useLiveState from 'use-live-state';
27 |
28 |
29 | export const TodoList = () => {
30 |
31 | const [state, _pushEvent] = useLiveState(liveState, {});
32 |
33 | return (
34 |
35 | {(state as any).todos && (state as any).todos.map((todo) => - {todo}
)}
36 |
37 | );
38 | }
39 | ```
40 |
41 | ```typescript
42 | import React, { Component, useRef } from 'react';
43 | import { liveState } from './live_state_react';
44 | import useLiveState from 'use-live-state';
45 |
46 | export const TodoForm = () => {
47 |
48 | const input = useRef(null);
49 |
50 | const [_state, pushEvent] = useLiveState(liveState, {});
51 |
52 | const onButtonClick = () => {
53 | pushEvent('add_todo', {todo: input.current.value});
54 | input.current.value = '';
55 | };
56 |
57 | return (
58 |
59 |
60 |
61 |
62 | );
63 | }
64 | ```
65 |
66 | To see an example project of how all this fits together, check out https://github.com/launchscout/live_state/tree/main/testbed
67 |
68 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "use-live-state",
3 | "version": "0.0.2",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "use-live-state",
9 | "version": "0.0.2",
10 | "license": "ISC",
11 | "dependencies": {
12 | "phx-live-state": ">= 0.9.0"
13 | },
14 | "devDependencies": {
15 | "react": ">= 16.8.0",
16 | "typescript": "^4.8.4"
17 | },
18 | "peerDependencies": {
19 | "react": ">= 16.8.0"
20 | }
21 | },
22 | "../phx-live-state": {
23 | "version": "0.8.0",
24 | "extraneous": true,
25 | "license": "MIT",
26 | "dependencies": {
27 | "json-joy": "^1.18.1",
28 | "lit": "^2.2.6",
29 | "phoenix": "1.6.15",
30 | "reflect-metadata": "^0.1.13",
31 | "wc-context": "launchscout/wc-context"
32 | },
33 | "devDependencies": {
34 | "@esm-bundle/chai": "^4.3.4-fix.0",
35 | "@open-wc/testing": "^3.1.6",
36 | "@types/sinon-chai": "^3.2.8",
37 | "@web/test-runner": "^0.13.31",
38 | "@web/test-runner-puppeteer": "^0.10.5",
39 | "fast-json-patch": "^3.1.1",
40 | "quibble": "^0.6.12",
41 | "sinon": "^14.0.0",
42 | "sinon-chai": "^3.7.0",
43 | "testdouble": "^3.16.6",
44 | "typedoc": "^0.23.24",
45 | "typescript": "^4.2.2"
46 | }
47 | },
48 | "node_modules/@lit-labs/ssr-dom-shim": {
49 | "version": "1.0.0",
50 | "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.0.0.tgz",
51 | "integrity": "sha512-ic93MBXfApIFTrup4a70M/+ddD8xdt2zxxj9sRwHQzhS9ag/syqkD8JPdTXsc1gUy2K8TTirhlCqyTEM/sifNw=="
52 | },
53 | "node_modules/@lit/reactive-element": {
54 | "version": "1.6.1",
55 | "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.1.tgz",
56 | "integrity": "sha512-va15kYZr7KZNNPZdxONGQzpUr+4sxVu7V/VG7a8mRfPPXUyhEYj5RzXCQmGrlP3tAh0L3HHm5AjBMFYRqlM9SA==",
57 | "dependencies": {
58 | "@lit-labs/ssr-dom-shim": "^1.0.0"
59 | }
60 | },
61 | "node_modules/@types/trusted-types": {
62 | "version": "2.0.2",
63 | "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
64 | "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
65 | },
66 | "node_modules/arg": {
67 | "version": "5.0.2",
68 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
69 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
70 | },
71 | "node_modules/fast-diff": {
72 | "version": "1.2.0",
73 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
74 | "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
75 | "peer": true
76 | },
77 | "node_modules/hyperdyperid": {
78 | "version": "1.2.0",
79 | "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz",
80 | "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==",
81 | "engines": {
82 | "node": ">=10.18"
83 | }
84 | },
85 | "node_modules/js-tokens": {
86 | "version": "4.0.0",
87 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
88 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
89 | "dev": true
90 | },
91 | "node_modules/json-joy": {
92 | "version": "1.19.0",
93 | "resolved": "https://registry.npmjs.org/json-joy/-/json-joy-1.19.0.tgz",
94 | "integrity": "sha512-oILIyxHJu52hQ9BFs1yFMXVKrP2cTYOdljRiNRElHzpcSnA03sSf+VKzwqEE2hGKKL1Zvml71b1wPTAQUl8CHQ==",
95 | "dependencies": {
96 | "arg": "^5.0.2",
97 | "hyperdyperid": "^1.2.0"
98 | },
99 | "bin": {
100 | "json-pack": "bin/json-pack.js",
101 | "json-pack-test": "bin/json-pack-test.js",
102 | "json-patch": "bin/json-patch.js",
103 | "json-patch-test": "bin/json-patch-test.js",
104 | "json-pointer": "bin/json-pointer.js",
105 | "json-pointer-test": "bin/json-pointer-test.js",
106 | "json-unpack": "bin/json-unpack.js"
107 | },
108 | "engines": {
109 | "node": ">=10.0"
110 | },
111 | "peerDependencies": {
112 | "quill-delta": "^5",
113 | "rxjs": "7",
114 | "tslib": "2"
115 | }
116 | },
117 | "node_modules/lit": {
118 | "version": "2.6.1",
119 | "resolved": "https://registry.npmjs.org/lit/-/lit-2.6.1.tgz",
120 | "integrity": "sha512-DT87LD64f8acR7uVp7kZfhLRrHkfC/N4BVzAtnw9Yg8087mbBJ//qedwdwX0kzDbxgPccWRW6mFwGbRQIxy0pw==",
121 | "dependencies": {
122 | "@lit/reactive-element": "^1.6.0",
123 | "lit-element": "^3.2.0",
124 | "lit-html": "^2.6.0"
125 | }
126 | },
127 | "node_modules/lit-element": {
128 | "version": "3.2.2",
129 | "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.2.2.tgz",
130 | "integrity": "sha512-6ZgxBR9KNroqKb6+htkyBwD90XGRiqKDHVrW/Eh0EZ+l+iC+u+v+w3/BA5NGi4nizAVHGYvQBHUDuSmLjPp7NQ==",
131 | "dependencies": {
132 | "@lit/reactive-element": "^1.3.0",
133 | "lit-html": "^2.2.0"
134 | }
135 | },
136 | "node_modules/lit-html": {
137 | "version": "2.6.1",
138 | "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.6.1.tgz",
139 | "integrity": "sha512-Z3iw+E+3KKFn9t2YKNjsXNEu/LRLI98mtH/C6lnFg7kvaqPIzPn124Yd4eT/43lyqrejpc5Wb6BHq3fdv4S8Rw==",
140 | "dependencies": {
141 | "@types/trusted-types": "^2.0.2"
142 | }
143 | },
144 | "node_modules/lodash.clonedeep": {
145 | "version": "4.5.0",
146 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
147 | "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
148 | "peer": true
149 | },
150 | "node_modules/lodash.isequal": {
151 | "version": "4.5.0",
152 | "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
153 | "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
154 | "peer": true
155 | },
156 | "node_modules/loose-envify": {
157 | "version": "1.4.0",
158 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
159 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
160 | "dev": true,
161 | "dependencies": {
162 | "js-tokens": "^3.0.0 || ^4.0.0"
163 | },
164 | "bin": {
165 | "loose-envify": "cli.js"
166 | }
167 | },
168 | "node_modules/phoenix": {
169 | "version": "1.6.15",
170 | "resolved": "https://registry.npmjs.org/phoenix/-/phoenix-1.6.15.tgz",
171 | "integrity": "sha512-O6AG5jTkZOOkdd/GOSCsM4v3bzBoyRnC5bEi57KhX/Daba6FvnBRzt0nhEeRRiVQGLSxDlyb0dUe9CkYWMZd8g=="
172 | },
173 | "node_modules/phx-live-state": {
174 | "version": "0.9.0",
175 | "resolved": "https://registry.npmjs.org/phx-live-state/-/phx-live-state-0.9.0.tgz",
176 | "integrity": "sha512-X9VppKb5tpXswdRn8qnEALueRSDYT/fQRIqdYCnLn9Q7C8jkTHs2Q4QRZ9HHS42KX7cQib3CmRDo6uORPzzZJQ==",
177 | "dependencies": {
178 | "json-joy": "^1.18.1",
179 | "lit": "^2.2.6",
180 | "phoenix": "1.6.15",
181 | "reflect-metadata": "^0.1.13",
182 | "wc-context": "github:launchscout/wc-context"
183 | }
184 | },
185 | "node_modules/quill-delta": {
186 | "version": "5.0.0",
187 | "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.0.0.tgz",
188 | "integrity": "sha512-lVORU8dBPJdxPmwtdGhfRcz2cekn8Osuj5kwHoPMQ3MNlDT/IZ0CGUnQ/tLsAaTn31LWcDC1KyL+gkiGbBlBBw==",
189 | "peer": true,
190 | "dependencies": {
191 | "fast-diff": "1.2.0",
192 | "lodash.clonedeep": "^4.5.0",
193 | "lodash.isequal": "^4.5.0"
194 | },
195 | "engines": {
196 | "node": ">= 12.0.0"
197 | }
198 | },
199 | "node_modules/react": {
200 | "version": "18.2.0",
201 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
202 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
203 | "dev": true,
204 | "dependencies": {
205 | "loose-envify": "^1.1.0"
206 | },
207 | "engines": {
208 | "node": ">=0.10.0"
209 | }
210 | },
211 | "node_modules/reflect-metadata": {
212 | "version": "0.1.13",
213 | "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
214 | "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
215 | },
216 | "node_modules/rxjs": {
217 | "version": "7.8.0",
218 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
219 | "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
220 | "peer": true,
221 | "dependencies": {
222 | "tslib": "^2.1.0"
223 | }
224 | },
225 | "node_modules/tslib": {
226 | "version": "2.4.1",
227 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
228 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
229 | "peer": true
230 | },
231 | "node_modules/typescript": {
232 | "version": "4.8.4",
233 | "dev": true,
234 | "license": "Apache-2.0",
235 | "bin": {
236 | "tsc": "bin/tsc",
237 | "tsserver": "bin/tsserver"
238 | },
239 | "engines": {
240 | "node": ">=4.2.0"
241 | }
242 | },
243 | "node_modules/wc-context": {
244 | "version": "0.11.0",
245 | "resolved": "git+ssh://git@github.com/launchscout/wc-context.git#ef9bb50d85f7e997295ef17fecd192f0bea61a9d",
246 | "license": "MIT"
247 | }
248 | },
249 | "dependencies": {
250 | "@lit-labs/ssr-dom-shim": {
251 | "version": "1.0.0",
252 | "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.0.0.tgz",
253 | "integrity": "sha512-ic93MBXfApIFTrup4a70M/+ddD8xdt2zxxj9sRwHQzhS9ag/syqkD8JPdTXsc1gUy2K8TTirhlCqyTEM/sifNw=="
254 | },
255 | "@lit/reactive-element": {
256 | "version": "1.6.1",
257 | "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.1.tgz",
258 | "integrity": "sha512-va15kYZr7KZNNPZdxONGQzpUr+4sxVu7V/VG7a8mRfPPXUyhEYj5RzXCQmGrlP3tAh0L3HHm5AjBMFYRqlM9SA==",
259 | "requires": {
260 | "@lit-labs/ssr-dom-shim": "^1.0.0"
261 | }
262 | },
263 | "@types/trusted-types": {
264 | "version": "2.0.2",
265 | "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
266 | "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
267 | },
268 | "arg": {
269 | "version": "5.0.2",
270 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
271 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
272 | },
273 | "fast-diff": {
274 | "version": "1.2.0",
275 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
276 | "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
277 | "peer": true
278 | },
279 | "hyperdyperid": {
280 | "version": "1.2.0",
281 | "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz",
282 | "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A=="
283 | },
284 | "js-tokens": {
285 | "version": "4.0.0",
286 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
287 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
288 | "dev": true
289 | },
290 | "json-joy": {
291 | "version": "1.19.0",
292 | "resolved": "https://registry.npmjs.org/json-joy/-/json-joy-1.19.0.tgz",
293 | "integrity": "sha512-oILIyxHJu52hQ9BFs1yFMXVKrP2cTYOdljRiNRElHzpcSnA03sSf+VKzwqEE2hGKKL1Zvml71b1wPTAQUl8CHQ==",
294 | "requires": {
295 | "arg": "^5.0.2",
296 | "hyperdyperid": "^1.2.0"
297 | }
298 | },
299 | "lit": {
300 | "version": "2.6.1",
301 | "resolved": "https://registry.npmjs.org/lit/-/lit-2.6.1.tgz",
302 | "integrity": "sha512-DT87LD64f8acR7uVp7kZfhLRrHkfC/N4BVzAtnw9Yg8087mbBJ//qedwdwX0kzDbxgPccWRW6mFwGbRQIxy0pw==",
303 | "requires": {
304 | "@lit/reactive-element": "^1.6.0",
305 | "lit-element": "^3.2.0",
306 | "lit-html": "^2.6.0"
307 | }
308 | },
309 | "lit-element": {
310 | "version": "3.2.2",
311 | "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.2.2.tgz",
312 | "integrity": "sha512-6ZgxBR9KNroqKb6+htkyBwD90XGRiqKDHVrW/Eh0EZ+l+iC+u+v+w3/BA5NGi4nizAVHGYvQBHUDuSmLjPp7NQ==",
313 | "requires": {
314 | "@lit/reactive-element": "^1.3.0",
315 | "lit-html": "^2.2.0"
316 | }
317 | },
318 | "lit-html": {
319 | "version": "2.6.1",
320 | "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.6.1.tgz",
321 | "integrity": "sha512-Z3iw+E+3KKFn9t2YKNjsXNEu/LRLI98mtH/C6lnFg7kvaqPIzPn124Yd4eT/43lyqrejpc5Wb6BHq3fdv4S8Rw==",
322 | "requires": {
323 | "@types/trusted-types": "^2.0.2"
324 | }
325 | },
326 | "lodash.clonedeep": {
327 | "version": "4.5.0",
328 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
329 | "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==",
330 | "peer": true
331 | },
332 | "lodash.isequal": {
333 | "version": "4.5.0",
334 | "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
335 | "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
336 | "peer": true
337 | },
338 | "loose-envify": {
339 | "version": "1.4.0",
340 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
341 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
342 | "dev": true,
343 | "requires": {
344 | "js-tokens": "^3.0.0 || ^4.0.0"
345 | }
346 | },
347 | "phoenix": {
348 | "version": "1.6.15",
349 | "resolved": "https://registry.npmjs.org/phoenix/-/phoenix-1.6.15.tgz",
350 | "integrity": "sha512-O6AG5jTkZOOkdd/GOSCsM4v3bzBoyRnC5bEi57KhX/Daba6FvnBRzt0nhEeRRiVQGLSxDlyb0dUe9CkYWMZd8g=="
351 | },
352 | "phx-live-state": {
353 | "version": "0.9.0",
354 | "resolved": "https://registry.npmjs.org/phx-live-state/-/phx-live-state-0.9.0.tgz",
355 | "integrity": "sha512-X9VppKb5tpXswdRn8qnEALueRSDYT/fQRIqdYCnLn9Q7C8jkTHs2Q4QRZ9HHS42KX7cQib3CmRDo6uORPzzZJQ==",
356 | "requires": {
357 | "json-joy": "^1.18.1",
358 | "lit": "^2.2.6",
359 | "phoenix": "1.6.15",
360 | "reflect-metadata": "^0.1.13",
361 | "wc-context": "github:launchscout/wc-context"
362 | }
363 | },
364 | "quill-delta": {
365 | "version": "5.0.0",
366 | "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.0.0.tgz",
367 | "integrity": "sha512-lVORU8dBPJdxPmwtdGhfRcz2cekn8Osuj5kwHoPMQ3MNlDT/IZ0CGUnQ/tLsAaTn31LWcDC1KyL+gkiGbBlBBw==",
368 | "peer": true,
369 | "requires": {
370 | "fast-diff": "1.2.0",
371 | "lodash.clonedeep": "^4.5.0",
372 | "lodash.isequal": "^4.5.0"
373 | }
374 | },
375 | "react": {
376 | "version": "18.2.0",
377 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
378 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
379 | "dev": true,
380 | "requires": {
381 | "loose-envify": "^1.1.0"
382 | }
383 | },
384 | "reflect-metadata": {
385 | "version": "0.1.13",
386 | "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
387 | "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
388 | },
389 | "rxjs": {
390 | "version": "7.8.0",
391 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
392 | "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
393 | "peer": true,
394 | "requires": {
395 | "tslib": "^2.1.0"
396 | }
397 | },
398 | "tslib": {
399 | "version": "2.4.1",
400 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
401 | "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
402 | "peer": true
403 | },
404 | "typescript": {
405 | "version": "4.8.4",
406 | "dev": true
407 | },
408 | "wc-context": {
409 | "version": "git+ssh://git@github.com/launchscout/wc-context.git#ef9bb50d85f7e997295ef17fecd192f0bea61a9d",
410 | "from": "wc-context@github:launchscout/wc-context"
411 | }
412 | }
413 | }
414 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "use-live-state",
3 | "version": "0.0.2",
4 | "description": "A react hook for LiveState",
5 | "module": "build/useLiveState.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "tsc",
9 | "setup": "npm install && npm run build"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/launchscout/live_state.git"
14 | },
15 | "keywords": [
16 | "elixir",
17 | "typescript",
18 | "react",
19 | "phoenix",
20 | "LiveState"
21 | ],
22 | "author": "Chris Nelson",
23 | "license": "ISC",
24 | "bugs": {
25 | "url": "https://github.com/launchscout/live_state/issues"
26 | },
27 | "homepage": "https://github.com/launchscout/live_state/tree/main/use-live-state#readme",
28 | "peerDependencies": {
29 | "react": ">= 16.8.0"
30 | },
31 | "dependencies": {
32 | "phx-live-state": ">= 0.9.0"
33 | },
34 | "devDependencies": {
35 | "typescript": "^4.8.4",
36 | "react": ">= 16.8.0"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "outDir": "build",
5 | "moduleResolution": "node",
6 | "declaration": true,
7 | "allowSyntheticDefaultImports": true,
8 | "experimentalDecorators": true
9 | },
10 | "include": ["useLiveState.ts"]
11 | }
--------------------------------------------------------------------------------
/useLiveState.ts:
--------------------------------------------------------------------------------
1 | import LiveState from 'phx-live-state';
2 | import { useState, useEffect } from 'react';
3 |
4 | const useLiveState = (liveState: LiveState, intialState: any) => {
5 | const [state, setState] = useState(intialState);
6 | useEffect(() => {
7 | liveState.connect();
8 | const handleStateChange = ({detail: {state}}) => setState(state);
9 | liveState.addEventListener('livestate-change', handleStateChange);
10 | return () => {
11 | liveState.removeEventListener('livestate-change', handleStateChange);
12 | };
13 | });
14 |
15 | const pushEvent = (event, payload) => {
16 | liveState.pushEvent(event, payload);
17 | }
18 |
19 | return [state, pushEvent];
20 | }
21 |
22 | export default useLiveState
--------------------------------------------------------------------------------