@player-tools/devtools-client 0.5.3-next.0 → 0.6.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.cjs +293 -197
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +295 -198
- package/dist/index.mjs +295 -198
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -4
- package/src/constants/index.ts +32 -0
- package/src/helpers/__tests__/flowDiff.test.ts +72 -0
- package/src/helpers/flowDiff.ts +44 -0
- package/src/index.ts +1 -3
- package/src/panel/index.tsx +212 -0
- package/src/panel/theme.ts +8 -0
- package/src/plugins/index.ts +10 -0
- package/src/state/__tests__/reducer.test.ts +362 -0
- package/src/state/index.ts +117 -0
- package/src/state/reducer.ts +80 -0
- package/types/constants/index.d.ts +5 -0
- package/types/helpers/flowDiff.d.ts +21 -0
- package/types/index.d.ts +1 -3
- package/types/panel/index.d.ts +31 -0
- package/types/panel/theme.d.ts +2 -0
- package/types/plugins/index.d.ts +5 -0
- package/types/state/index.d.ts +24 -0
- package/types/state/reducer.d.ts +4 -0
- package/src/redux/actions.ts +0 -36
- package/src/redux/aliases.ts +0 -45
- package/src/redux/index.ts +0 -70
- package/src/redux/reducers.ts +0 -118
- package/src/rpc/index.ts +0 -21
- package/types/redux/actions.d.ts +0 -12
- package/types/redux/aliases.d.ts +0 -10
- package/types/redux/index.d.ts +0 -7
- package/types/redux/reducers.d.ts +0 -10
- package/types/rpc/index.d.ts +0 -6
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import type {
|
|
3
|
+
Transaction,
|
|
4
|
+
DevtoolsDataChangeEvent,
|
|
5
|
+
PlayerInitEvent,
|
|
6
|
+
DevtoolsFlowChangeEvent,
|
|
7
|
+
DevtoolsEventsBatchEvent,
|
|
8
|
+
PlayerStoppedEvent,
|
|
9
|
+
ExtensionSelectedPlayerEvent,
|
|
10
|
+
ExtensionSelectedPluginEvent,
|
|
11
|
+
} from "@player-tools/devtools-types";
|
|
12
|
+
import { reducer } from "../reducer";
|
|
13
|
+
import { INITIAL_EXTENSION_STATE, INITIAL_FLOW } from "../../constants";
|
|
14
|
+
|
|
15
|
+
const mockPlayerInitTransaction: Transaction<PlayerInitEvent> = {
|
|
16
|
+
id: 1,
|
|
17
|
+
timestamp: Date.now(),
|
|
18
|
+
sender: "sender-id",
|
|
19
|
+
target: "target-id",
|
|
20
|
+
context: "player",
|
|
21
|
+
_messenger_: true,
|
|
22
|
+
type: "PLAYER_DEVTOOLS_PLAYER_INIT",
|
|
23
|
+
payload: {
|
|
24
|
+
plugins: {
|
|
25
|
+
"plugin-id": {
|
|
26
|
+
id: "plugin-id",
|
|
27
|
+
description: "Plugin Description",
|
|
28
|
+
flow: INITIAL_FLOW,
|
|
29
|
+
name: "Plugin Name",
|
|
30
|
+
version: "1.0.0",
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const mockPlayerFlowChangeTransaction: Transaction<DevtoolsFlowChangeEvent> = {
|
|
37
|
+
id: 2,
|
|
38
|
+
timestamp: Date.now(),
|
|
39
|
+
sender: "sender-id",
|
|
40
|
+
target: "target-id",
|
|
41
|
+
context: "player",
|
|
42
|
+
_messenger_: true,
|
|
43
|
+
type: "PLAYER_DEVTOOLS_PLUGIN_FLOW_CHANGE",
|
|
44
|
+
payload: {
|
|
45
|
+
flow: {
|
|
46
|
+
...INITIAL_FLOW,
|
|
47
|
+
data: {
|
|
48
|
+
key: "value",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
pluginID: "plugin-id",
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const mockPluginDataChangeTransaction: Transaction<DevtoolsDataChangeEvent> = {
|
|
56
|
+
id: 2,
|
|
57
|
+
timestamp: Date.now(),
|
|
58
|
+
sender: "sender-id",
|
|
59
|
+
target: "target-id",
|
|
60
|
+
context: "player",
|
|
61
|
+
_messenger_: true,
|
|
62
|
+
type: "PLAYER_DEVTOOLS_PLUGIN_DATA_CHANGE",
|
|
63
|
+
payload: {
|
|
64
|
+
data: {
|
|
65
|
+
key: "value",
|
|
66
|
+
},
|
|
67
|
+
pluginID: "plugin-id",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const mockEventBatchTransaction: Transaction<DevtoolsEventsBatchEvent> = {
|
|
72
|
+
id: 4,
|
|
73
|
+
timestamp: Date.now(),
|
|
74
|
+
sender: "sender-id",
|
|
75
|
+
target: "target-id",
|
|
76
|
+
context: "player",
|
|
77
|
+
_messenger_: true,
|
|
78
|
+
type: "MESSENGER_EVENT_BATCH",
|
|
79
|
+
payload: {
|
|
80
|
+
events: [
|
|
81
|
+
mockPlayerInitTransaction,
|
|
82
|
+
mockPlayerFlowChangeTransaction,
|
|
83
|
+
mockPluginDataChangeTransaction,
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const mockPlayerStoppedTransaction: Transaction<PlayerStoppedEvent> = {
|
|
89
|
+
id: 5,
|
|
90
|
+
timestamp: Date.now(),
|
|
91
|
+
sender: "sender-id",
|
|
92
|
+
target: "target-id",
|
|
93
|
+
context: "player",
|
|
94
|
+
_messenger_: true,
|
|
95
|
+
type: "PLAYER_DEVTOOLS_PLAYER_STOPPED",
|
|
96
|
+
payload: null,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const mockPlayerSelectedTransaction: Transaction<ExtensionSelectedPlayerEvent> =
|
|
100
|
+
{
|
|
101
|
+
id: 6,
|
|
102
|
+
timestamp: Date.now(),
|
|
103
|
+
sender: "sender-id",
|
|
104
|
+
target: "target-id",
|
|
105
|
+
context: "player",
|
|
106
|
+
_messenger_: true,
|
|
107
|
+
type: "PLAYER_DEVTOOLS_PLAYER_SELECTED",
|
|
108
|
+
payload: {
|
|
109
|
+
playerID: "player-id",
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const mockPluginSelectedTransaction: Transaction<ExtensionSelectedPluginEvent> =
|
|
114
|
+
{
|
|
115
|
+
id: 7,
|
|
116
|
+
timestamp: Date.now(),
|
|
117
|
+
sender: "sender-id",
|
|
118
|
+
target: "target-id",
|
|
119
|
+
context: "player",
|
|
120
|
+
_messenger_: true,
|
|
121
|
+
type: "PLAYER_DEVTOOLS_PLUGIN_SELECTED",
|
|
122
|
+
payload: {
|
|
123
|
+
pluginID: "plugin-id",
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
describe("reducer", () => {
|
|
128
|
+
test("PLAYER_DEVTOOLS_PLAYER_INIT", () => {
|
|
129
|
+
const newState = reducer(
|
|
130
|
+
INITIAL_EXTENSION_STATE,
|
|
131
|
+
mockPlayerInitTransaction
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
135
|
+
{
|
|
136
|
+
"current": {
|
|
137
|
+
"player": "sender-id",
|
|
138
|
+
"plugin": "plugin-id",
|
|
139
|
+
},
|
|
140
|
+
"players": {
|
|
141
|
+
"sender-id": {
|
|
142
|
+
"active": true,
|
|
143
|
+
"plugins": {
|
|
144
|
+
"plugin-id": {
|
|
145
|
+
"description": "Plugin Description",
|
|
146
|
+
"flow": {
|
|
147
|
+
"id": "initial-flow",
|
|
148
|
+
"navigation": {
|
|
149
|
+
"BEGIN": "FLOW_1",
|
|
150
|
+
"FLOW_1": {
|
|
151
|
+
"VIEW_1": {
|
|
152
|
+
"ref": "view-1",
|
|
153
|
+
"state_type": "VIEW",
|
|
154
|
+
"transitions": {},
|
|
155
|
+
},
|
|
156
|
+
"startState": "VIEW_1",
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
"views": [
|
|
160
|
+
{
|
|
161
|
+
"id": "view-1",
|
|
162
|
+
"type": "text",
|
|
163
|
+
"value": "connecting...",
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
"id": "plugin-id",
|
|
168
|
+
"name": "Plugin Name",
|
|
169
|
+
"version": "1.0.0",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
`);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("PLAYER_DEVTOOLS_PLUGIN_FLOW_CHANGE", () => {
|
|
179
|
+
const newState = reducer(
|
|
180
|
+
INITIAL_EXTENSION_STATE,
|
|
181
|
+
mockPlayerFlowChangeTransaction
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
185
|
+
{
|
|
186
|
+
"current": {
|
|
187
|
+
"player": null,
|
|
188
|
+
"plugin": null,
|
|
189
|
+
},
|
|
190
|
+
"players": {
|
|
191
|
+
"sender-id": {
|
|
192
|
+
"plugins": {
|
|
193
|
+
"plugin-id": {
|
|
194
|
+
"flow": {
|
|
195
|
+
"data": {
|
|
196
|
+
"key": "value",
|
|
197
|
+
},
|
|
198
|
+
"id": "initial-flow",
|
|
199
|
+
"navigation": {
|
|
200
|
+
"BEGIN": "FLOW_1",
|
|
201
|
+
"FLOW_1": {
|
|
202
|
+
"VIEW_1": {
|
|
203
|
+
"ref": "view-1",
|
|
204
|
+
"state_type": "VIEW",
|
|
205
|
+
"transitions": {},
|
|
206
|
+
},
|
|
207
|
+
"startState": "VIEW_1",
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
"views": [
|
|
211
|
+
{
|
|
212
|
+
"id": "view-1",
|
|
213
|
+
"type": "text",
|
|
214
|
+
"value": "connecting...",
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
}
|
|
223
|
+
`);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("PLAYER_DEVTOOLS_PLUGIN_DATA_CHANGE", () => {
|
|
227
|
+
const newState = reducer(
|
|
228
|
+
INITIAL_EXTENSION_STATE,
|
|
229
|
+
mockPluginDataChangeTransaction
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
233
|
+
{
|
|
234
|
+
"current": {
|
|
235
|
+
"player": null,
|
|
236
|
+
"plugin": null,
|
|
237
|
+
},
|
|
238
|
+
"players": {
|
|
239
|
+
"sender-id": {
|
|
240
|
+
"plugins": {
|
|
241
|
+
"plugin-id": {
|
|
242
|
+
"flow": {
|
|
243
|
+
"data": {
|
|
244
|
+
"key": "value",
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
`);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("MESSENGER_EVENT_BATCH", () => {
|
|
256
|
+
const newState = reducer(
|
|
257
|
+
INITIAL_EXTENSION_STATE,
|
|
258
|
+
mockEventBatchTransaction
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
262
|
+
{
|
|
263
|
+
"current": {
|
|
264
|
+
"player": "sender-id",
|
|
265
|
+
"plugin": "plugin-id",
|
|
266
|
+
},
|
|
267
|
+
"players": {
|
|
268
|
+
"sender-id": {
|
|
269
|
+
"active": true,
|
|
270
|
+
"plugins": {
|
|
271
|
+
"plugin-id": {
|
|
272
|
+
"description": "Plugin Description",
|
|
273
|
+
"flow": {
|
|
274
|
+
"data": {
|
|
275
|
+
"key": "value",
|
|
276
|
+
},
|
|
277
|
+
"id": "initial-flow",
|
|
278
|
+
"navigation": {
|
|
279
|
+
"BEGIN": "FLOW_1",
|
|
280
|
+
"FLOW_1": {
|
|
281
|
+
"VIEW_1": {
|
|
282
|
+
"ref": "view-1",
|
|
283
|
+
"state_type": "VIEW",
|
|
284
|
+
"transitions": {},
|
|
285
|
+
},
|
|
286
|
+
"startState": "VIEW_1",
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
"views": [
|
|
290
|
+
{
|
|
291
|
+
"id": "view-1",
|
|
292
|
+
"type": "text",
|
|
293
|
+
"value": "connecting...",
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
},
|
|
297
|
+
"id": "plugin-id",
|
|
298
|
+
"name": "Plugin Name",
|
|
299
|
+
"version": "1.0.0",
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
}
|
|
305
|
+
`);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("PLAYER_DEVTOOLS_PLAYER_STOPPED", () => {
|
|
309
|
+
const newState = reducer(
|
|
310
|
+
INITIAL_EXTENSION_STATE,
|
|
311
|
+
mockPlayerStoppedTransaction
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
315
|
+
{
|
|
316
|
+
"current": {
|
|
317
|
+
"player": null,
|
|
318
|
+
"plugin": null,
|
|
319
|
+
},
|
|
320
|
+
"players": {
|
|
321
|
+
"sender-id": {
|
|
322
|
+
"active": false,
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
}
|
|
326
|
+
`);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("PLAYER_DEVTOOLS_PLAYER_SELECTED", () => {
|
|
330
|
+
const newState = reducer(
|
|
331
|
+
INITIAL_EXTENSION_STATE,
|
|
332
|
+
mockPlayerSelectedTransaction
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
336
|
+
{
|
|
337
|
+
"current": {
|
|
338
|
+
"player": "player-id",
|
|
339
|
+
"plugin": null,
|
|
340
|
+
},
|
|
341
|
+
"players": {},
|
|
342
|
+
}
|
|
343
|
+
`);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("PLAYER_DEVTOOLS_PLUGIN_SELECTED", () => {
|
|
347
|
+
const newState = reducer(
|
|
348
|
+
INITIAL_EXTENSION_STATE,
|
|
349
|
+
mockPluginSelectedTransaction
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
expect(newState).toMatchInlineSnapshot(`
|
|
353
|
+
{
|
|
354
|
+
"current": {
|
|
355
|
+
"player": null,
|
|
356
|
+
"plugin": "plugin-id",
|
|
357
|
+
},
|
|
358
|
+
"players": {},
|
|
359
|
+
}
|
|
360
|
+
`);
|
|
361
|
+
});
|
|
362
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { Messenger } from "@player-tools/devtools-messenger";
|
|
2
|
+
import type {
|
|
3
|
+
ExtensionSupportedEvents,
|
|
4
|
+
MessengerOptions,
|
|
5
|
+
} from "@player-tools/devtools-types";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useReducer } from "react";
|
|
7
|
+
|
|
8
|
+
import { INITIAL_EXTENSION_STATE } from "../constants";
|
|
9
|
+
import { reducer } from "./reducer";
|
|
10
|
+
|
|
11
|
+
const NOOP_ID = -1;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Custom React hook for managing the state of the devtools extension.
|
|
15
|
+
*
|
|
16
|
+
* This hook initializes the extension's state and sets up a communication layer
|
|
17
|
+
* using the `Messenger` class. It provides methods to select a player or plugin,
|
|
18
|
+
* and handle interactions, which dispatch actions to update the state accordingly.
|
|
19
|
+
*
|
|
20
|
+
*/
|
|
21
|
+
export const useExtensionState = ({
|
|
22
|
+
communicationLayer,
|
|
23
|
+
}: {
|
|
24
|
+
/** the communication layer to use for the extension */
|
|
25
|
+
communicationLayer: Pick<
|
|
26
|
+
MessengerOptions<ExtensionSupportedEvents>,
|
|
27
|
+
"sendMessage" | "addListener" | "removeListener"
|
|
28
|
+
>;
|
|
29
|
+
}) => {
|
|
30
|
+
const [state, dispatch] = useReducer(reducer, INITIAL_EXTENSION_STATE);
|
|
31
|
+
|
|
32
|
+
const messengerOptions = useMemo<MessengerOptions<ExtensionSupportedEvents>>(
|
|
33
|
+
() => ({
|
|
34
|
+
context: "devtools",
|
|
35
|
+
target: "player",
|
|
36
|
+
messageCallback: (message) => {
|
|
37
|
+
dispatch(message);
|
|
38
|
+
},
|
|
39
|
+
...communicationLayer,
|
|
40
|
+
logger: console,
|
|
41
|
+
}),
|
|
42
|
+
[dispatch, communicationLayer]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const messenger = useMemo(
|
|
46
|
+
() => new Messenger(messengerOptions),
|
|
47
|
+
[messengerOptions]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
return () => {
|
|
52
|
+
messenger.destroy();
|
|
53
|
+
};
|
|
54
|
+
}, []);
|
|
55
|
+
|
|
56
|
+
const selectPlayer = useCallback(
|
|
57
|
+
(playerID: string) => {
|
|
58
|
+
dispatch({
|
|
59
|
+
id: NOOP_ID,
|
|
60
|
+
sender: "internal",
|
|
61
|
+
context: "devtools",
|
|
62
|
+
_messenger_: false,
|
|
63
|
+
timestamp: Date.now(),
|
|
64
|
+
type: "PLAYER_DEVTOOLS_PLAYER_SELECTED",
|
|
65
|
+
payload: {
|
|
66
|
+
playerID,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
[dispatch]
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const selectPlugin = useCallback(
|
|
74
|
+
(pluginID: string) => {
|
|
75
|
+
dispatch({
|
|
76
|
+
id: NOOP_ID,
|
|
77
|
+
sender: "internal",
|
|
78
|
+
context: "devtools",
|
|
79
|
+
_messenger_: false,
|
|
80
|
+
timestamp: Date.now(),
|
|
81
|
+
type: "PLAYER_DEVTOOLS_PLUGIN_SELECTED",
|
|
82
|
+
payload: {
|
|
83
|
+
pluginID,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
[dispatch]
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Plugin authors can add interactive elements to the Player-UI content by leveraging
|
|
92
|
+
* the pub-sub plugin and having the handle interaction proxy the message to the inspected
|
|
93
|
+
* Player-UI instance.
|
|
94
|
+
*/
|
|
95
|
+
const handleInteraction = useCallback(
|
|
96
|
+
({
|
|
97
|
+
type,
|
|
98
|
+
payload,
|
|
99
|
+
}: {
|
|
100
|
+
/** interaction type */
|
|
101
|
+
type: string;
|
|
102
|
+
/** interaction payload */
|
|
103
|
+
payload?: string;
|
|
104
|
+
}) => {
|
|
105
|
+
messenger.sendMessage({
|
|
106
|
+
type: "PLAYER_DEVTOOLS_PLUGIN_INTERACTION",
|
|
107
|
+
payload: {
|
|
108
|
+
type,
|
|
109
|
+
payload,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
[messenger]
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return { state, selectPlayer, selectPlugin, handleInteraction };
|
|
117
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExtensionState,
|
|
3
|
+
ExtensionSupportedEvents,
|
|
4
|
+
Transaction,
|
|
5
|
+
} from "@player-tools/devtools-types";
|
|
6
|
+
import { dset } from "dset/merge";
|
|
7
|
+
import { produce } from "immer";
|
|
8
|
+
|
|
9
|
+
/** Extension state reducer */
|
|
10
|
+
export const reducer = (
|
|
11
|
+
state: ExtensionState,
|
|
12
|
+
transaction: Transaction<ExtensionSupportedEvents>
|
|
13
|
+
): ExtensionState => {
|
|
14
|
+
switch (transaction.type) {
|
|
15
|
+
case "PLAYER_DEVTOOLS_PLAYER_INIT":
|
|
16
|
+
return produce(state, (draft) => {
|
|
17
|
+
const {
|
|
18
|
+
sender,
|
|
19
|
+
payload: { plugins },
|
|
20
|
+
} = transaction;
|
|
21
|
+
const { player, plugin } = draft.current;
|
|
22
|
+
|
|
23
|
+
if (!player && !plugin) {
|
|
24
|
+
// if there is no player and plugin selected, select the first one:
|
|
25
|
+
dset(draft, ["current", "player"], sender);
|
|
26
|
+
dset(
|
|
27
|
+
draft,
|
|
28
|
+
["current", "plugin"],
|
|
29
|
+
plugins[Object.keys(plugins)[0]].id
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
dset(draft, ["players", sender, "plugins"], plugins);
|
|
34
|
+
dset(draft, ["players", sender, "active"], true);
|
|
35
|
+
});
|
|
36
|
+
case "PLAYER_DEVTOOLS_PLUGIN_FLOW_CHANGE":
|
|
37
|
+
return produce(state, (draft) => {
|
|
38
|
+
const {
|
|
39
|
+
sender,
|
|
40
|
+
payload: { flow, pluginID },
|
|
41
|
+
} = transaction;
|
|
42
|
+
|
|
43
|
+
dset(draft, ["players", sender, "plugins", pluginID, "flow"], flow);
|
|
44
|
+
});
|
|
45
|
+
case "PLAYER_DEVTOOLS_PLUGIN_DATA_CHANGE":
|
|
46
|
+
return produce(state, (draft) => {
|
|
47
|
+
const {
|
|
48
|
+
sender,
|
|
49
|
+
payload: { data, pluginID },
|
|
50
|
+
} = transaction;
|
|
51
|
+
dset(
|
|
52
|
+
draft,
|
|
53
|
+
["players", sender, "plugins", pluginID, "flow", "data"],
|
|
54
|
+
data
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
case "MESSENGER_EVENT_BATCH":
|
|
58
|
+
return produce(state, (draft) => {
|
|
59
|
+
return transaction.payload.events.reduce(reducer, draft);
|
|
60
|
+
});
|
|
61
|
+
case "PLAYER_DEVTOOLS_PLAYER_STOPPED":
|
|
62
|
+
return produce(state, (draft) => {
|
|
63
|
+
const { sender } = transaction;
|
|
64
|
+
|
|
65
|
+
dset(draft, ["players", sender, "active"], false);
|
|
66
|
+
});
|
|
67
|
+
case "PLAYER_DEVTOOLS_PLAYER_SELECTED":
|
|
68
|
+
return produce(state, (draft) => {
|
|
69
|
+
const { playerID } = transaction.payload;
|
|
70
|
+
dset(draft, ["current", "player"], playerID);
|
|
71
|
+
});
|
|
72
|
+
case "PLAYER_DEVTOOLS_PLUGIN_SELECTED":
|
|
73
|
+
return produce(state, (draft) => {
|
|
74
|
+
const { pluginID } = transaction.payload;
|
|
75
|
+
dset(draft, ["current", "plugin"], pluginID);
|
|
76
|
+
});
|
|
77
|
+
default:
|
|
78
|
+
return state;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Flow } from "@player-ui/react";
|
|
2
|
+
/**
|
|
3
|
+
* Compares two Flow objects and identifies if there's a change in their structure or data.
|
|
4
|
+
*
|
|
5
|
+
* This function takes two Flow objects as input, `curr` (current) and `next` (next), and compares them
|
|
6
|
+
* to determine if there's a change in the flow's structure or its data. If there's a change in the flow's
|
|
7
|
+
* structure (excluding the `data` property), it returns an object indicating a "flow" change along with the
|
|
8
|
+
* new flow. If there's a change in the `data` property, it returns an object indicating a "data" change along
|
|
9
|
+
* with the new data. If there are no changes, it returns null.
|
|
10
|
+
*/
|
|
11
|
+
export declare const flowDiff: ({ curr, next, }: {
|
|
12
|
+
curr: Flow;
|
|
13
|
+
next: Flow;
|
|
14
|
+
}) => {
|
|
15
|
+
change: "data";
|
|
16
|
+
value: Flow["data"];
|
|
17
|
+
} | {
|
|
18
|
+
change: "flow";
|
|
19
|
+
value: Flow;
|
|
20
|
+
} | null;
|
|
21
|
+
//# sourceMappingURL=flowDiff.d.ts.map
|
package/types/index.d.ts
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { MessengerOptions, ExtensionSupportedEvents } from "@player-tools/devtools-types";
|
|
3
|
+
/**
|
|
4
|
+
* Panel Component
|
|
5
|
+
*
|
|
6
|
+
* This component serves as the main container for the devtools plugin content defined by plugin authors using Player-UI DSL.
|
|
7
|
+
*
|
|
8
|
+
* Props:
|
|
9
|
+
* - `communicationLayer`: An object that allows communication between the devtools and the Player-UI plugins,
|
|
10
|
+
* enabling the exchange of data and events.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Error Handling: Utilizes the `ErrorBoundary` component from `react-error-boundary` to gracefully handle and display errors
|
|
14
|
+
* that may occur during the rendering of the plugin's content.
|
|
15
|
+
* - State Management: Integrates with custom hooks such as `useExtensionState` to manage the state of the plugin and its components.
|
|
16
|
+
* - Player Integration: Uses the `useReactPlayer` hook from `player-ui/react` to render interactive player components based on the
|
|
17
|
+
* DSL defined by the plugin authors.
|
|
18
|
+
*
|
|
19
|
+
* Example Usage:
|
|
20
|
+
* ```tsx
|
|
21
|
+
* <Panel communicationLayer={myCommunicationLayer} />
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Note: The `communicationLayer` prop is essential for the proper functioning of the `Panel` component, as it enables the necessary
|
|
25
|
+
* communication and data exchange with the player-ui/react library.
|
|
26
|
+
*/
|
|
27
|
+
export declare const Panel: ({ communicationLayer, }: {
|
|
28
|
+
/** the communication layer to use for the extension */
|
|
29
|
+
readonly communicationLayer: Pick<MessengerOptions<ExtensionSupportedEvents>, "sendMessage" | "addListener" | "removeListener">;
|
|
30
|
+
}) => React.JSX.Element;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ExtensionSupportedEvents, MessengerOptions } from "@player-tools/devtools-types";
|
|
2
|
+
/**
|
|
3
|
+
* Custom React hook for managing the state of the devtools extension.
|
|
4
|
+
*
|
|
5
|
+
* This hook initializes the extension's state and sets up a communication layer
|
|
6
|
+
* using the `Messenger` class. It provides methods to select a player or plugin,
|
|
7
|
+
* and handle interactions, which dispatch actions to update the state accordingly.
|
|
8
|
+
*
|
|
9
|
+
*/
|
|
10
|
+
export declare const useExtensionState: ({ communicationLayer, }: {
|
|
11
|
+
/** the communication layer to use for the extension */
|
|
12
|
+
communicationLayer: Pick<MessengerOptions<ExtensionSupportedEvents>, "sendMessage" | "addListener" | "removeListener">;
|
|
13
|
+
}) => {
|
|
14
|
+
state: import("@player-tools/devtools-types").ExtensionState;
|
|
15
|
+
selectPlayer: (playerID: string) => void;
|
|
16
|
+
selectPlugin: (pluginID: string) => void;
|
|
17
|
+
handleInteraction: ({ type, payload, }: {
|
|
18
|
+
/** interaction type */
|
|
19
|
+
type: string;
|
|
20
|
+
/** interaction payload */
|
|
21
|
+
payload?: string | undefined;
|
|
22
|
+
}) => void;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ExtensionState, ExtensionSupportedEvents, Transaction } from "@player-tools/devtools-types";
|
|
2
|
+
/** Extension state reducer */
|
|
3
|
+
export declare const reducer: (state: ExtensionState, transaction: Transaction<ExtensionSupportedEvents>) => ExtensionState;
|
|
4
|
+
//# sourceMappingURL=reducer.d.ts.map
|