@player-devtools/client-react 0.13.1--canary.17.955

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.
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ Panel: () => Panel
34
+ });
35
+ module.exports = __toCommonJS(src_exports);
36
+
37
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx
38
+ var import_react3 = __toESM(require("react"));
39
+ var import_react4 = require("@player-ui/react");
40
+ var import_react5 = require("react");
41
+ var import_react_error_boundary = require("react-error-boundary");
42
+ var import_react6 = require("@chakra-ui/react");
43
+ var import_themes = require("@devtools-ds/themes");
44
+
45
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/plugins/index.ts
46
+ var import_plugin = __toESM(require("@devtools-ui/plugin"));
47
+ var import_pubsub_plugin = require("@player-ui/pubsub-plugin");
48
+ var import_common_expressions_plugin = require("@player-ui/common-expressions-plugin");
49
+ var import_common_types_plugin = require("@player-ui/common-types-plugin");
50
+ var import_data_change_listener_plugin = require("@player-ui/data-change-listener-plugin");
51
+ var import_react = require("@player-ui/react");
52
+ var LogForwarder = class {
53
+ constructor() {
54
+ this.name = "Log";
55
+ }
56
+ apply(player) {
57
+ player.logger.addHandler(new import_react.ConsoleLogger("trace", console));
58
+ }
59
+ applyReact(reactPlayer) {
60
+ this.apply(reactPlayer.player);
61
+ }
62
+ };
63
+ var PUBSUB_PLUGIN = new import_pubsub_plugin.PubSubPlugin();
64
+ var PLAYER_PLUGINS = [
65
+ new import_common_types_plugin.CommonTypesPlugin(),
66
+ new import_common_expressions_plugin.CommonExpressionsPlugin(),
67
+ new import_data_change_listener_plugin.DataChangeListenerPlugin(),
68
+ new import_plugin.default(),
69
+ new LogForwarder(),
70
+ PUBSUB_PLUGIN
71
+ ];
72
+
73
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/state/index.ts
74
+ var import_react2 = require("react");
75
+ var import_client = require("@player-devtools/client");
76
+ var useExtensionState = ({
77
+ communicationLayer
78
+ }) => {
79
+ const client = (0, import_react2.useMemo)(
80
+ () => (0, import_client.createExtensionClient)(communicationLayer),
81
+ [communicationLayer]
82
+ );
83
+ (0, import_react2.useEffect)(() => () => client.destroy(), [client]);
84
+ const state = (0, import_react2.useSyncExternalStore)(client.subscribe, client.getState);
85
+ return {
86
+ state,
87
+ selectPlayer: client.selectPlayer,
88
+ selectPlugin: client.selectPlugin,
89
+ handleInteraction: client.handleInteraction
90
+ };
91
+ };
92
+
93
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/helpers/flowDiff.ts
94
+ var import_dequal = require("dequal");
95
+ var flowDiff = ({
96
+ curr,
97
+ next
98
+ }) => {
99
+ const currCopy = { ...curr, data: null };
100
+ const nextCopy = { ...next, data: null };
101
+ const baseFlowIsEqual = (0, import_dequal.dequal)(currCopy, nextCopy);
102
+ if (!baseFlowIsEqual) {
103
+ return { change: "flow", value: next };
104
+ }
105
+ const currData = curr.data;
106
+ const nextData = next.data;
107
+ const dataIsEqual = (0, import_dequal.dequal)(currData, nextData);
108
+ if (!dataIsEqual) {
109
+ return { change: "data", value: nextData };
110
+ }
111
+ return null;
112
+ };
113
+
114
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx
115
+ var INITIAL_FLOW = {
116
+ id: "initial-flow",
117
+ views: [
118
+ {
119
+ id: "view-1",
120
+ type: "text",
121
+ value: "connecting..."
122
+ }
123
+ ],
124
+ navigation: {
125
+ BEGIN: "FLOW_1",
126
+ FLOW_1: {
127
+ startState: "VIEW_1",
128
+ VIEW_1: {
129
+ state_type: "VIEW",
130
+ ref: "view-1",
131
+ transitions: {}
132
+ }
133
+ }
134
+ }
135
+ };
136
+ var fallbackRender = ({
137
+ error
138
+ }) => {
139
+ return /* @__PURE__ */ import_react3.default.createElement(import_react6.Container, { centerContent: true }, /* @__PURE__ */ import_react3.default.createElement(import_react6.Card, null, /* @__PURE__ */ import_react3.default.createElement(import_react6.CardHeader, null, /* @__PURE__ */ import_react3.default.createElement(import_react6.Heading, null, "Ops, something went wrong.")), /* @__PURE__ */ import_react3.default.createElement(import_react6.CardBody, null, /* @__PURE__ */ import_react3.default.createElement(import_react6.Text, { as: "pre" }, error.message))));
140
+ };
141
+ var Panel = ({ communicationLayer, baseTheme }) => {
142
+ const { state, selectPlayer, selectPlugin, handleInteraction } = useExtensionState({
143
+ communicationLayer
144
+ });
145
+ const { reactPlayer, playerState } = (0, import_react4.useReactPlayer)({
146
+ plugins: PLAYER_PLUGINS
147
+ });
148
+ const dataController = (0, import_react3.useRef)(null);
149
+ const currentFlow = (0, import_react3.useRef)(null);
150
+ (0, import_react5.useEffect)(() => {
151
+ reactPlayer.player.hooks.dataController.tap("devtools-panel", (d) => {
152
+ dataController.current = new WeakRef(d);
153
+ });
154
+ }, [reactPlayer]);
155
+ (0, import_react5.useEffect)(() => {
156
+ PUBSUB_PLUGIN.subscribe("*", (type, payload) => {
157
+ handleInteraction({
158
+ type,
159
+ payload
160
+ });
161
+ });
162
+ }, []);
163
+ (0, import_react5.useEffect)(() => {
164
+ const { player, plugin } = state.current;
165
+ const flow = player && plugin ? state.players[player]?.plugins?.[plugin]?.flow || INITIAL_FLOW : INITIAL_FLOW;
166
+ if (!currentFlow.current) {
167
+ currentFlow.current = flow;
168
+ reactPlayer.start(flow);
169
+ return;
170
+ }
171
+ const diff = flowDiff({
172
+ curr: currentFlow.current,
173
+ next: flow
174
+ });
175
+ if (diff) {
176
+ const { change, value } = diff;
177
+ if (change === "flow") {
178
+ currentFlow.current = value;
179
+ reactPlayer.start(value);
180
+ } else if (change === "data") {
181
+ if (dataController.current) {
182
+ dataController.current.deref()?.set(value);
183
+ } else {
184
+ reactPlayer.start(flow);
185
+ }
186
+ }
187
+ }
188
+ }, [reactPlayer, state]);
189
+ const isDarkMode = (0, import_themes.useDarkMode)();
190
+ const colorMode = isDarkMode ? "dark" : "light";
191
+ const config = {
192
+ initialColorMode: colorMode,
193
+ useSystemColorMode: true
194
+ };
195
+ const theme = (0, import_react6.extendTheme)({ config, ...baseTheme });
196
+ const Component = reactPlayer.Component;
197
+ return /* @__PURE__ */ import_react3.default.createElement(import_react6.ChakraProvider, { resetCSS: false, theme }, /* @__PURE__ */ import_react3.default.createElement(import_themes.ThemeProvider, { theme: "chrome", colorScheme: colorMode }, /* @__PURE__ */ import_react3.default.createElement(import_react_error_boundary.ErrorBoundary, { fallbackRender }, /* @__PURE__ */ import_react3.default.createElement(
198
+ import_react6.Flex,
199
+ {
200
+ direction: "column",
201
+ h: "100vh",
202
+ alignItems: "normal",
203
+ overflow: "scroll"
204
+ },
205
+ state.current.player ? /* @__PURE__ */ import_react3.default.createElement(import_react6.Flex, { direction: "column", gap: "20px" }, /* @__PURE__ */ import_react3.default.createElement(import_react6.Flex, { gap: "16px" }, /* @__PURE__ */ import_react3.default.createElement(import_react6.FormControl, null, /* @__PURE__ */ import_react3.default.createElement(import_react6.FormLabel, null, "Player"), /* @__PURE__ */ import_react3.default.createElement(
206
+ import_react6.Select,
207
+ {
208
+ id: "player",
209
+ value: state.current.player || "",
210
+ onChange: (event) => selectPlayer(event.target.value)
211
+ },
212
+ Object.keys(state.players).map((playerID) => /* @__PURE__ */ import_react3.default.createElement("option", { key: playerID, value: playerID }, playerID))
213
+ )), /* @__PURE__ */ import_react3.default.createElement(import_react6.FormControl, null, /* @__PURE__ */ import_react3.default.createElement(import_react6.FormLabel, null, "Plugin"), /* @__PURE__ */ import_react3.default.createElement(
214
+ import_react6.Select,
215
+ {
216
+ id: "plugin",
217
+ value: state.current.plugin || "",
218
+ onChange: (event) => selectPlugin(event.target.value)
219
+ },
220
+ Object.keys(
221
+ state.players[state.current.player]?.plugins ?? []
222
+ ).map((pluginID) => /* @__PURE__ */ import_react3.default.createElement("option", { key: pluginID, value: pluginID }, pluginID))
223
+ ))), /* @__PURE__ */ import_react3.default.createElement(import_react6.Flex, { width: "100%" }, playerState.status === "error" ? fallbackRender({
224
+ error: playerState.error,
225
+ resetErrorBoundary: () => {
226
+ }
227
+ }) : /* @__PURE__ */ import_react3.default.createElement(Component, null)), /* @__PURE__ */ import_react3.default.createElement("details", null, /* @__PURE__ */ import_react3.default.createElement("summary", null, "Debug"), /* @__PURE__ */ import_react3.default.createElement("pre", { style: { maxHeight: "30vh", overflow: "scroll" } }, JSON.stringify(state, null, 2)))) : /* @__PURE__ */ import_react3.default.createElement(import_react6.Flex, { justifyContent: "center", padding: "6" }, /* @__PURE__ */ import_react3.default.createElement(import_react6.Text, null, "No Player-UI instance or devtools plugin detected. Visit", " ", /* @__PURE__ */ import_react3.default.createElement("a", { href: "https://player-ui.github.io/" }, "https://player-ui.github.io/"), " ", "for more info."))
228
+ ))));
229
+ };
230
+ // Annotate the CommonJS export names for ESM import in node:
231
+ 0 && (module.exports = {
232
+ Panel
233
+ });
234
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/index.ts","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/plugins/index.ts","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/state/index.ts","../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/helpers/flowDiff.ts"],"sourcesContent":["export { Panel } from \"./panel\";\n","import React, { useRef } from \"react\";\nimport type {\n MessengerOptions,\n ExtensionSupportedEvents,\n} from \"@player-devtools/types\";\nimport { DataController, Flow, useReactPlayer } from \"@player-ui/react\";\nimport { useEffect } from \"react\";\nimport { ErrorBoundary } from \"react-error-boundary\";\nimport {\n Card,\n CardBody,\n CardHeader,\n ChakraProvider,\n Container,\n extendTheme,\n Flex,\n FormControl,\n FormLabel,\n Heading,\n Select,\n Text,\n type ThemeConfig,\n} from \"@chakra-ui/react\";\n\nimport { ThemeProvider, useDarkMode } from \"@devtools-ds/themes\";\n\nimport { PLAYER_PLUGINS, PUBSUB_PLUGIN } from \"../plugins\";\nimport { useExtensionState } from \"../state\";\nimport { flowDiff } from \"../helpers/flowDiff\";\n\n/** Placeholder flow rendered until a real Player flow arrives. */\nconst INITIAL_FLOW: Flow = {\n id: \"initial-flow\",\n views: [\n {\n id: \"view-1\",\n type: \"text\",\n value: \"connecting...\",\n },\n ],\n navigation: {\n BEGIN: \"FLOW_1\",\n FLOW_1: {\n startState: \"VIEW_1\",\n VIEW_1: {\n state_type: \"VIEW\",\n ref: \"view-1\",\n transitions: {},\n },\n },\n },\n};\n\nconst fallbackRender: ErrorBoundary[\"props\"][\"fallbackRender\"] = ({\n error,\n}) => {\n return (\n <Container centerContent>\n <Card>\n <CardHeader>\n <Heading>Ops, something went wrong.</Heading>\n </CardHeader>\n <CardBody>\n <Text as=\"pre\">{error.message}</Text>\n </CardBody>\n </Card>\n </Container>\n );\n};\n\n/**\n * Panel Component\n *\n * This component serves as the main container for the devtools plugin content defined by plugin authors using Player-UI DSL.\n *\n * Props:\n * - `communicationLayer`: An object that allows communication between the devtools and the Player-UI plugins,\n * enabling the exchange of data and events.\n *\n * Features:\n * - Error Handling: Utilizes the `ErrorBoundary` component from `react-error-boundary` to gracefully handle and display errors\n * that may occur during the rendering of the plugin's content.\n * - State Management: Integrates with custom hooks such as `useExtensionState` to manage the state of the plugin and its components.\n * - Player Integration: Uses the `useReactPlayer` hook from `player-ui/react` to render interactive player components based on the\n * DSL defined by the plugin authors.\n *\n * Example Usage:\n * ```tsx\n * <Panel communicationLayer={myCommunicationLayer} />\n * ```\n *\n * Note: The `communicationLayer` prop is essential for the proper functioning of the `Panel` component, as it enables the necessary\n * communication and data exchange with the player-ui/react library.\n */\nexport const Panel: React.FC<{\n /** the communication layer to use for the extension */\n readonly communicationLayer: Pick<\n MessengerOptions<ExtensionSupportedEvents>,\n \"sendMessage\" | \"addListener\" | \"removeListener\"\n >;\n baseTheme?: Record<string, unknown>;\n}> = ({ communicationLayer, baseTheme }) => {\n const { state, selectPlayer, selectPlugin, handleInteraction } =\n useExtensionState({\n communicationLayer,\n });\n\n const { reactPlayer, playerState } = useReactPlayer({\n plugins: PLAYER_PLUGINS,\n });\n\n const dataController = useRef<WeakRef<DataController> | null>(null);\n\n const currentFlow = useRef<Flow | null>(null);\n\n useEffect(() => {\n reactPlayer.player.hooks.dataController.tap(\"devtools-panel\", (d) => {\n dataController.current = new WeakRef(d);\n });\n }, [reactPlayer]);\n\n useEffect(() => {\n // we subscribe to all messages from the devtools plugin\n // so the plugin author can define their own events\n PUBSUB_PLUGIN.subscribe(\"*\", (type: string, payload: string) => {\n handleInteraction({\n type,\n payload,\n });\n });\n }, []);\n\n useEffect(() => {\n const { player, plugin } = state.current;\n\n const flow =\n player && plugin\n ? state.players[player]?.plugins?.[plugin]?.flow || INITIAL_FLOW\n : INITIAL_FLOW;\n\n if (!currentFlow.current) {\n currentFlow.current = flow;\n reactPlayer.start(flow);\n return;\n }\n\n const diff = flowDiff({\n curr: currentFlow.current as Flow,\n next: flow,\n });\n\n if (diff) {\n const { change, value } = diff;\n\n if (change === \"flow\") {\n currentFlow.current = value;\n reactPlayer.start(value);\n } else if (change === \"data\") {\n if (dataController.current) {\n dataController.current.deref()?.set(value as Record<string, unknown>);\n } else {\n reactPlayer.start(flow);\n }\n }\n }\n }, [reactPlayer, state]);\n\n const isDarkMode = useDarkMode();\n const colorMode = isDarkMode ? \"dark\" : \"light\";\n\n const config: ThemeConfig = {\n initialColorMode: colorMode,\n useSystemColorMode: true,\n };\n const theme = extendTheme({ config, ...baseTheme });\n\n const Component = reactPlayer.Component as React.FC;\n\n return (\n <ChakraProvider resetCSS={false} theme={theme}>\n <ThemeProvider theme=\"chrome\" colorScheme={colorMode}>\n <ErrorBoundary fallbackRender={fallbackRender}>\n <Flex\n direction=\"column\"\n h=\"100vh\"\n alignItems={\"normal\"}\n overflow=\"scroll\"\n >\n {state.current.player ? (\n <Flex direction=\"column\" gap=\"20px\">\n <Flex gap=\"16px\">\n <FormControl>\n <FormLabel>Player</FormLabel>\n <Select\n id=\"player\"\n value={state.current.player || \"\"}\n onChange={(event) => selectPlayer(event.target.value)}\n >\n {Object.keys(state.players).map((playerID) => (\n <option key={playerID} value={playerID}>\n {playerID}\n </option>\n ))}\n </Select>\n </FormControl>\n <FormControl>\n <FormLabel>Plugin</FormLabel>\n <Select\n id=\"plugin\"\n value={state.current.plugin || \"\"}\n onChange={(event) => selectPlugin(event.target.value)}\n >\n {Object.keys(\n state.players[state.current.player]?.plugins ?? [],\n ).map((pluginID) => (\n <option key={pluginID} value={pluginID}>\n {pluginID}\n </option>\n ))}\n </Select>\n </FormControl>\n </Flex>\n <Flex width=\"100%\">\n {playerState.status === \"error\" ? (\n fallbackRender({\n error: playerState.error,\n resetErrorBoundary: () => {},\n })\n ) : (\n <Component />\n )}\n </Flex>\n <details>\n <summary>Debug</summary>\n <pre style={{ maxHeight: \"30vh\", overflow: \"scroll\" }}>\n {JSON.stringify(state, null, 2)}\n </pre>\n </details>\n </Flex>\n ) : (\n <Flex justifyContent=\"center\" padding=\"6\">\n <Text>\n No Player-UI instance or devtools plugin detected. Visit{\" \"}\n <a href=\"https://player-ui.github.io/\">\n https://player-ui.github.io/\n </a>{\" \"}\n for more info.\n </Text>\n </Flex>\n )}\n </Flex>\n </ErrorBoundary>\n </ThemeProvider>\n </ChakraProvider>\n );\n};\n","import DevtoolsUIAssetsPlugin from \"@devtools-ui/plugin\";\nimport { PubSubPlugin } from \"@player-ui/pubsub-plugin\";\nimport { CommonExpressionsPlugin } from \"@player-ui/common-expressions-plugin\";\nimport { CommonTypesPlugin } from \"@player-ui/common-types-plugin\";\nimport { DataChangeListenerPlugin } from \"@player-ui/data-change-listener-plugin\";\nimport {\n ConsoleLogger,\n Player,\n PlayerPlugin,\n ReactPlayer,\n type ReactPlayerPlugin,\n} from \"@player-ui/react\";\n\nclass LogForwarder implements PlayerPlugin, ReactPlayerPlugin {\n name = \"Log\";\n apply(player: Player) {\n player.logger.addHandler(new ConsoleLogger(\"trace\", console));\n }\n\n applyReact(reactPlayer: ReactPlayer) {\n this.apply(reactPlayer.player);\n }\n}\n\nexport const PUBSUB_PLUGIN = new PubSubPlugin();\n\nexport const PLAYER_PLUGINS: ReactPlayerPlugin[] = [\n new CommonTypesPlugin(),\n new CommonExpressionsPlugin(),\n new DataChangeListenerPlugin(),\n new DevtoolsUIAssetsPlugin(),\n new LogForwarder(),\n PUBSUB_PLUGIN,\n];\n","import type { CommunicationLayerMethods } from \"@player-devtools/types\";\nimport { useEffect, useMemo, useSyncExternalStore } from \"react\";\n\nimport { createExtensionClient } from \"@player-devtools/client\";\n\n/**\n * Thin React adapter over `createExtensionClient`.\n *\n * Creates the client once per `communicationLayer` identity, subscribes to\n * state via `useSyncExternalStore`, and tears down the Messenger on unmount.\n */\nexport const useExtensionState = ({\n communicationLayer,\n}: {\n /** the communication layer to use for the extension */\n communicationLayer: CommunicationLayerMethods;\n}) => {\n const client = useMemo(\n () => createExtensionClient(communicationLayer),\n [communicationLayer],\n );\n\n useEffect(() => () => client.destroy(), [client]);\n\n const state = useSyncExternalStore(client.subscribe, client.getState);\n\n return {\n state,\n selectPlayer: client.selectPlayer,\n selectPlugin: client.selectPlugin,\n handleInteraction: client.handleInteraction,\n };\n};\n","import type { Flow } from \"@player-ui/react\";\nimport { dequal } from \"dequal\";\n\n/**\n * Compares two Flow objects and identifies if there's a change in their structure or data.\n *\n * This function takes two Flow objects as input, `curr` (current) and `next` (next), and compares them\n * to determine if there's a change in the flow's structure or its data. If there's a change in the flow's\n * structure (excluding the `data` property), it returns an object indicating a \"flow\" change along with the\n * new flow. If there's a change in the `data` property, it returns an object indicating a \"data\" change along\n * with the new data. If there are no changes, it returns null.\n */\nexport const flowDiff = ({\n curr,\n next,\n}: {\n curr: Flow;\n next: Flow;\n}):\n | { change: \"data\"; value: Flow[\"data\"] }\n | { change: \"flow\"; value: Flow }\n | null => {\n // compare flows except for the `data` property\n const currCopy = { ...curr, data: null };\n const nextCopy = { ...next, data: null };\n\n const baseFlowIsEqual = dequal(currCopy, nextCopy);\n\n if (!baseFlowIsEqual) {\n return { change: \"flow\", value: next };\n }\n\n // compare data\n const currData = curr.data;\n const nextData = next.data;\n\n const dataIsEqual = dequal(currData, nextData);\n\n if (!dataIsEqual) {\n return { change: \"data\", value: nextData };\n }\n\n return null;\n};\n"],"mappings":"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","names":["import_react","DevtoolsUIAssetsPlugin","import_react","React"]}
@@ -0,0 +1,212 @@
1
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx
2
+ import React, { useRef } from "react";
3
+ import { useReactPlayer } from "@player-ui/react";
4
+ import { useEffect as useEffect2 } from "react";
5
+ import { ErrorBoundary } from "react-error-boundary";
6
+ import {
7
+ Card,
8
+ CardBody,
9
+ CardHeader,
10
+ ChakraProvider,
11
+ Container,
12
+ extendTheme,
13
+ Flex,
14
+ FormControl,
15
+ FormLabel,
16
+ Heading,
17
+ Select,
18
+ Text
19
+ } from "@chakra-ui/react";
20
+ import { ThemeProvider, useDarkMode } from "@devtools-ds/themes";
21
+
22
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/plugins/index.ts
23
+ import DevtoolsUIAssetsPlugin from "@devtools-ui/plugin";
24
+ import { PubSubPlugin } from "@player-ui/pubsub-plugin";
25
+ import { CommonExpressionsPlugin } from "@player-ui/common-expressions-plugin";
26
+ import { CommonTypesPlugin } from "@player-ui/common-types-plugin";
27
+ import { DataChangeListenerPlugin } from "@player-ui/data-change-listener-plugin";
28
+ import {
29
+ ConsoleLogger
30
+ } from "@player-ui/react";
31
+ var LogForwarder = class {
32
+ constructor() {
33
+ this.name = "Log";
34
+ }
35
+ apply(player) {
36
+ player.logger.addHandler(new ConsoleLogger("trace", console));
37
+ }
38
+ applyReact(reactPlayer) {
39
+ this.apply(reactPlayer.player);
40
+ }
41
+ };
42
+ var PUBSUB_PLUGIN = new PubSubPlugin();
43
+ var PLAYER_PLUGINS = [
44
+ new CommonTypesPlugin(),
45
+ new CommonExpressionsPlugin(),
46
+ new DataChangeListenerPlugin(),
47
+ new DevtoolsUIAssetsPlugin(),
48
+ new LogForwarder(),
49
+ PUBSUB_PLUGIN
50
+ ];
51
+
52
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/state/index.ts
53
+ import { useEffect, useMemo, useSyncExternalStore } from "react";
54
+ import { createExtensionClient } from "@player-devtools/client";
55
+ var useExtensionState = ({
56
+ communicationLayer
57
+ }) => {
58
+ const client = useMemo(
59
+ () => createExtensionClient(communicationLayer),
60
+ [communicationLayer]
61
+ );
62
+ useEffect(() => () => client.destroy(), [client]);
63
+ const state = useSyncExternalStore(client.subscribe, client.getState);
64
+ return {
65
+ state,
66
+ selectPlayer: client.selectPlayer,
67
+ selectPlugin: client.selectPlugin,
68
+ handleInteraction: client.handleInteraction
69
+ };
70
+ };
71
+
72
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/helpers/flowDiff.ts
73
+ import { dequal } from "dequal";
74
+ var flowDiff = ({
75
+ curr,
76
+ next
77
+ }) => {
78
+ const currCopy = { ...curr, data: null };
79
+ const nextCopy = { ...next, data: null };
80
+ const baseFlowIsEqual = dequal(currCopy, nextCopy);
81
+ if (!baseFlowIsEqual) {
82
+ return { change: "flow", value: next };
83
+ }
84
+ const currData = curr.data;
85
+ const nextData = next.data;
86
+ const dataIsEqual = dequal(currData, nextData);
87
+ if (!dataIsEqual) {
88
+ return { change: "data", value: nextData };
89
+ }
90
+ return null;
91
+ };
92
+
93
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx
94
+ var INITIAL_FLOW = {
95
+ id: "initial-flow",
96
+ views: [
97
+ {
98
+ id: "view-1",
99
+ type: "text",
100
+ value: "connecting..."
101
+ }
102
+ ],
103
+ navigation: {
104
+ BEGIN: "FLOW_1",
105
+ FLOW_1: {
106
+ startState: "VIEW_1",
107
+ VIEW_1: {
108
+ state_type: "VIEW",
109
+ ref: "view-1",
110
+ transitions: {}
111
+ }
112
+ }
113
+ }
114
+ };
115
+ var fallbackRender = ({
116
+ error
117
+ }) => {
118
+ return /* @__PURE__ */ React.createElement(Container, { centerContent: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, null, /* @__PURE__ */ React.createElement(Heading, null, "Ops, something went wrong.")), /* @__PURE__ */ React.createElement(CardBody, null, /* @__PURE__ */ React.createElement(Text, { as: "pre" }, error.message))));
119
+ };
120
+ var Panel = ({ communicationLayer, baseTheme }) => {
121
+ const { state, selectPlayer, selectPlugin, handleInteraction } = useExtensionState({
122
+ communicationLayer
123
+ });
124
+ const { reactPlayer, playerState } = useReactPlayer({
125
+ plugins: PLAYER_PLUGINS
126
+ });
127
+ const dataController = useRef(null);
128
+ const currentFlow = useRef(null);
129
+ useEffect2(() => {
130
+ reactPlayer.player.hooks.dataController.tap("devtools-panel", (d) => {
131
+ dataController.current = new WeakRef(d);
132
+ });
133
+ }, [reactPlayer]);
134
+ useEffect2(() => {
135
+ PUBSUB_PLUGIN.subscribe("*", (type, payload) => {
136
+ handleInteraction({
137
+ type,
138
+ payload
139
+ });
140
+ });
141
+ }, []);
142
+ useEffect2(() => {
143
+ const { player, plugin } = state.current;
144
+ const flow = player && plugin ? state.players[player]?.plugins?.[plugin]?.flow || INITIAL_FLOW : INITIAL_FLOW;
145
+ if (!currentFlow.current) {
146
+ currentFlow.current = flow;
147
+ reactPlayer.start(flow);
148
+ return;
149
+ }
150
+ const diff = flowDiff({
151
+ curr: currentFlow.current,
152
+ next: flow
153
+ });
154
+ if (diff) {
155
+ const { change, value } = diff;
156
+ if (change === "flow") {
157
+ currentFlow.current = value;
158
+ reactPlayer.start(value);
159
+ } else if (change === "data") {
160
+ if (dataController.current) {
161
+ dataController.current.deref()?.set(value);
162
+ } else {
163
+ reactPlayer.start(flow);
164
+ }
165
+ }
166
+ }
167
+ }, [reactPlayer, state]);
168
+ const isDarkMode = useDarkMode();
169
+ const colorMode = isDarkMode ? "dark" : "light";
170
+ const config = {
171
+ initialColorMode: colorMode,
172
+ useSystemColorMode: true
173
+ };
174
+ const theme = extendTheme({ config, ...baseTheme });
175
+ const Component = reactPlayer.Component;
176
+ return /* @__PURE__ */ React.createElement(ChakraProvider, { resetCSS: false, theme }, /* @__PURE__ */ React.createElement(ThemeProvider, { theme: "chrome", colorScheme: colorMode }, /* @__PURE__ */ React.createElement(ErrorBoundary, { fallbackRender }, /* @__PURE__ */ React.createElement(
177
+ Flex,
178
+ {
179
+ direction: "column",
180
+ h: "100vh",
181
+ alignItems: "normal",
182
+ overflow: "scroll"
183
+ },
184
+ state.current.player ? /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "20px" }, /* @__PURE__ */ React.createElement(Flex, { gap: "16px" }, /* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement(FormLabel, null, "Player"), /* @__PURE__ */ React.createElement(
185
+ Select,
186
+ {
187
+ id: "player",
188
+ value: state.current.player || "",
189
+ onChange: (event) => selectPlayer(event.target.value)
190
+ },
191
+ Object.keys(state.players).map((playerID) => /* @__PURE__ */ React.createElement("option", { key: playerID, value: playerID }, playerID))
192
+ )), /* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement(FormLabel, null, "Plugin"), /* @__PURE__ */ React.createElement(
193
+ Select,
194
+ {
195
+ id: "plugin",
196
+ value: state.current.plugin || "",
197
+ onChange: (event) => selectPlugin(event.target.value)
198
+ },
199
+ Object.keys(
200
+ state.players[state.current.player]?.plugins ?? []
201
+ ).map((pluginID) => /* @__PURE__ */ React.createElement("option", { key: pluginID, value: pluginID }, pluginID))
202
+ ))), /* @__PURE__ */ React.createElement(Flex, { width: "100%" }, playerState.status === "error" ? fallbackRender({
203
+ error: playerState.error,
204
+ resetErrorBoundary: () => {
205
+ }
206
+ }) : /* @__PURE__ */ React.createElement(Component, null)), /* @__PURE__ */ React.createElement("details", null, /* @__PURE__ */ React.createElement("summary", null, "Debug"), /* @__PURE__ */ React.createElement("pre", { style: { maxHeight: "30vh", overflow: "scroll" } }, JSON.stringify(state, null, 2)))) : /* @__PURE__ */ React.createElement(Flex, { justifyContent: "center", padding: "6" }, /* @__PURE__ */ React.createElement(Text, null, "No Player-UI instance or devtools plugin detected. Visit", " ", /* @__PURE__ */ React.createElement("a", { href: "https://player-ui.github.io/" }, "https://player-ui.github.io/"), " ", "for more info."))
207
+ ))));
208
+ };
209
+ export {
210
+ Panel
211
+ };
212
+ //# sourceMappingURL=index.mjs.map
package/dist/index.mjs ADDED
@@ -0,0 +1,212 @@
1
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx
2
+ import React, { useRef } from "react";
3
+ import { useReactPlayer } from "@player-ui/react";
4
+ import { useEffect as useEffect2 } from "react";
5
+ import { ErrorBoundary } from "react-error-boundary";
6
+ import {
7
+ Card,
8
+ CardBody,
9
+ CardHeader,
10
+ ChakraProvider,
11
+ Container,
12
+ extendTheme,
13
+ Flex,
14
+ FormControl,
15
+ FormLabel,
16
+ Heading,
17
+ Select,
18
+ Text
19
+ } from "@chakra-ui/react";
20
+ import { ThemeProvider, useDarkMode } from "@devtools-ds/themes";
21
+
22
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/plugins/index.ts
23
+ import DevtoolsUIAssetsPlugin from "@devtools-ui/plugin";
24
+ import { PubSubPlugin } from "@player-ui/pubsub-plugin";
25
+ import { CommonExpressionsPlugin } from "@player-ui/common-expressions-plugin";
26
+ import { CommonTypesPlugin } from "@player-ui/common-types-plugin";
27
+ import { DataChangeListenerPlugin } from "@player-ui/data-change-listener-plugin";
28
+ import {
29
+ ConsoleLogger
30
+ } from "@player-ui/react";
31
+ var LogForwarder = class {
32
+ constructor() {
33
+ this.name = "Log";
34
+ }
35
+ apply(player) {
36
+ player.logger.addHandler(new ConsoleLogger("trace", console));
37
+ }
38
+ applyReact(reactPlayer) {
39
+ this.apply(reactPlayer.player);
40
+ }
41
+ };
42
+ var PUBSUB_PLUGIN = new PubSubPlugin();
43
+ var PLAYER_PLUGINS = [
44
+ new CommonTypesPlugin(),
45
+ new CommonExpressionsPlugin(),
46
+ new DataChangeListenerPlugin(),
47
+ new DevtoolsUIAssetsPlugin(),
48
+ new LogForwarder(),
49
+ PUBSUB_PLUGIN
50
+ ];
51
+
52
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/state/index.ts
53
+ import { useEffect, useMemo, useSyncExternalStore } from "react";
54
+ import { createExtensionClient } from "@player-devtools/client";
55
+ var useExtensionState = ({
56
+ communicationLayer
57
+ }) => {
58
+ const client = useMemo(
59
+ () => createExtensionClient(communicationLayer),
60
+ [communicationLayer]
61
+ );
62
+ useEffect(() => () => client.destroy(), [client]);
63
+ const state = useSyncExternalStore(client.subscribe, client.getState);
64
+ return {
65
+ state,
66
+ selectPlayer: client.selectPlayer,
67
+ selectPlugin: client.selectPlugin,
68
+ handleInteraction: client.handleInteraction
69
+ };
70
+ };
71
+
72
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/helpers/flowDiff.ts
73
+ import { dequal } from "dequal";
74
+ var flowDiff = ({
75
+ curr,
76
+ next
77
+ }) => {
78
+ const currCopy = { ...curr, data: null };
79
+ const nextCopy = { ...next, data: null };
80
+ const baseFlowIsEqual = dequal(currCopy, nextCopy);
81
+ if (!baseFlowIsEqual) {
82
+ return { change: "flow", value: next };
83
+ }
84
+ const currData = curr.data;
85
+ const nextData = next.data;
86
+ const dataIsEqual = dequal(currData, nextData);
87
+ if (!dataIsEqual) {
88
+ return { change: "data", value: nextData };
89
+ }
90
+ return null;
91
+ };
92
+
93
+ // ../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx
94
+ var INITIAL_FLOW = {
95
+ id: "initial-flow",
96
+ views: [
97
+ {
98
+ id: "view-1",
99
+ type: "text",
100
+ value: "connecting..."
101
+ }
102
+ ],
103
+ navigation: {
104
+ BEGIN: "FLOW_1",
105
+ FLOW_1: {
106
+ startState: "VIEW_1",
107
+ VIEW_1: {
108
+ state_type: "VIEW",
109
+ ref: "view-1",
110
+ transitions: {}
111
+ }
112
+ }
113
+ }
114
+ };
115
+ var fallbackRender = ({
116
+ error
117
+ }) => {
118
+ return /* @__PURE__ */ React.createElement(Container, { centerContent: true }, /* @__PURE__ */ React.createElement(Card, null, /* @__PURE__ */ React.createElement(CardHeader, null, /* @__PURE__ */ React.createElement(Heading, null, "Ops, something went wrong.")), /* @__PURE__ */ React.createElement(CardBody, null, /* @__PURE__ */ React.createElement(Text, { as: "pre" }, error.message))));
119
+ };
120
+ var Panel = ({ communicationLayer, baseTheme }) => {
121
+ const { state, selectPlayer, selectPlugin, handleInteraction } = useExtensionState({
122
+ communicationLayer
123
+ });
124
+ const { reactPlayer, playerState } = useReactPlayer({
125
+ plugins: PLAYER_PLUGINS
126
+ });
127
+ const dataController = useRef(null);
128
+ const currentFlow = useRef(null);
129
+ useEffect2(() => {
130
+ reactPlayer.player.hooks.dataController.tap("devtools-panel", (d) => {
131
+ dataController.current = new WeakRef(d);
132
+ });
133
+ }, [reactPlayer]);
134
+ useEffect2(() => {
135
+ PUBSUB_PLUGIN.subscribe("*", (type, payload) => {
136
+ handleInteraction({
137
+ type,
138
+ payload
139
+ });
140
+ });
141
+ }, []);
142
+ useEffect2(() => {
143
+ const { player, plugin } = state.current;
144
+ const flow = player && plugin ? state.players[player]?.plugins?.[plugin]?.flow || INITIAL_FLOW : INITIAL_FLOW;
145
+ if (!currentFlow.current) {
146
+ currentFlow.current = flow;
147
+ reactPlayer.start(flow);
148
+ return;
149
+ }
150
+ const diff = flowDiff({
151
+ curr: currentFlow.current,
152
+ next: flow
153
+ });
154
+ if (diff) {
155
+ const { change, value } = diff;
156
+ if (change === "flow") {
157
+ currentFlow.current = value;
158
+ reactPlayer.start(value);
159
+ } else if (change === "data") {
160
+ if (dataController.current) {
161
+ dataController.current.deref()?.set(value);
162
+ } else {
163
+ reactPlayer.start(flow);
164
+ }
165
+ }
166
+ }
167
+ }, [reactPlayer, state]);
168
+ const isDarkMode = useDarkMode();
169
+ const colorMode = isDarkMode ? "dark" : "light";
170
+ const config = {
171
+ initialColorMode: colorMode,
172
+ useSystemColorMode: true
173
+ };
174
+ const theme = extendTheme({ config, ...baseTheme });
175
+ const Component = reactPlayer.Component;
176
+ return /* @__PURE__ */ React.createElement(ChakraProvider, { resetCSS: false, theme }, /* @__PURE__ */ React.createElement(ThemeProvider, { theme: "chrome", colorScheme: colorMode }, /* @__PURE__ */ React.createElement(ErrorBoundary, { fallbackRender }, /* @__PURE__ */ React.createElement(
177
+ Flex,
178
+ {
179
+ direction: "column",
180
+ h: "100vh",
181
+ alignItems: "normal",
182
+ overflow: "scroll"
183
+ },
184
+ state.current.player ? /* @__PURE__ */ React.createElement(Flex, { direction: "column", gap: "20px" }, /* @__PURE__ */ React.createElement(Flex, { gap: "16px" }, /* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement(FormLabel, null, "Player"), /* @__PURE__ */ React.createElement(
185
+ Select,
186
+ {
187
+ id: "player",
188
+ value: state.current.player || "",
189
+ onChange: (event) => selectPlayer(event.target.value)
190
+ },
191
+ Object.keys(state.players).map((playerID) => /* @__PURE__ */ React.createElement("option", { key: playerID, value: playerID }, playerID))
192
+ )), /* @__PURE__ */ React.createElement(FormControl, null, /* @__PURE__ */ React.createElement(FormLabel, null, "Plugin"), /* @__PURE__ */ React.createElement(
193
+ Select,
194
+ {
195
+ id: "plugin",
196
+ value: state.current.plugin || "",
197
+ onChange: (event) => selectPlugin(event.target.value)
198
+ },
199
+ Object.keys(
200
+ state.players[state.current.player]?.plugins ?? []
201
+ ).map((pluginID) => /* @__PURE__ */ React.createElement("option", { key: pluginID, value: pluginID }, pluginID))
202
+ ))), /* @__PURE__ */ React.createElement(Flex, { width: "100%" }, playerState.status === "error" ? fallbackRender({
203
+ error: playerState.error,
204
+ resetErrorBoundary: () => {
205
+ }
206
+ }) : /* @__PURE__ */ React.createElement(Component, null)), /* @__PURE__ */ React.createElement("details", null, /* @__PURE__ */ React.createElement("summary", null, "Debug"), /* @__PURE__ */ React.createElement("pre", { style: { maxHeight: "30vh", overflow: "scroll" } }, JSON.stringify(state, null, 2)))) : /* @__PURE__ */ React.createElement(Flex, { justifyContent: "center", padding: "6" }, /* @__PURE__ */ React.createElement(Text, null, "No Player-UI instance or devtools plugin detected. Visit", " ", /* @__PURE__ */ React.createElement("a", { href: "https://player-ui.github.io/" }, "https://player-ui.github.io/"), " ", "for more info."))
207
+ ))));
208
+ };
209
+ export {
210
+ Panel
211
+ };
212
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/panel/index.tsx","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/plugins/index.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/state/index.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/devtools/client/react/src/helpers/flowDiff.ts"],"sourcesContent":["import React, { useRef } from \"react\";\nimport type {\n MessengerOptions,\n ExtensionSupportedEvents,\n} from \"@player-devtools/types\";\nimport { DataController, Flow, useReactPlayer } from \"@player-ui/react\";\nimport { useEffect } from \"react\";\nimport { ErrorBoundary } from \"react-error-boundary\";\nimport {\n Card,\n CardBody,\n CardHeader,\n ChakraProvider,\n Container,\n extendTheme,\n Flex,\n FormControl,\n FormLabel,\n Heading,\n Select,\n Text,\n type ThemeConfig,\n} from \"@chakra-ui/react\";\n\nimport { ThemeProvider, useDarkMode } from \"@devtools-ds/themes\";\n\nimport { PLAYER_PLUGINS, PUBSUB_PLUGIN } from \"../plugins\";\nimport { useExtensionState } from \"../state\";\nimport { flowDiff } from \"../helpers/flowDiff\";\n\n/** Placeholder flow rendered until a real Player flow arrives. */\nconst INITIAL_FLOW: Flow = {\n id: \"initial-flow\",\n views: [\n {\n id: \"view-1\",\n type: \"text\",\n value: \"connecting...\",\n },\n ],\n navigation: {\n BEGIN: \"FLOW_1\",\n FLOW_1: {\n startState: \"VIEW_1\",\n VIEW_1: {\n state_type: \"VIEW\",\n ref: \"view-1\",\n transitions: {},\n },\n },\n },\n};\n\nconst fallbackRender: ErrorBoundary[\"props\"][\"fallbackRender\"] = ({\n error,\n}) => {\n return (\n <Container centerContent>\n <Card>\n <CardHeader>\n <Heading>Ops, something went wrong.</Heading>\n </CardHeader>\n <CardBody>\n <Text as=\"pre\">{error.message}</Text>\n </CardBody>\n </Card>\n </Container>\n );\n};\n\n/**\n * Panel Component\n *\n * This component serves as the main container for the devtools plugin content defined by plugin authors using Player-UI DSL.\n *\n * Props:\n * - `communicationLayer`: An object that allows communication between the devtools and the Player-UI plugins,\n * enabling the exchange of data and events.\n *\n * Features:\n * - Error Handling: Utilizes the `ErrorBoundary` component from `react-error-boundary` to gracefully handle and display errors\n * that may occur during the rendering of the plugin's content.\n * - State Management: Integrates with custom hooks such as `useExtensionState` to manage the state of the plugin and its components.\n * - Player Integration: Uses the `useReactPlayer` hook from `player-ui/react` to render interactive player components based on the\n * DSL defined by the plugin authors.\n *\n * Example Usage:\n * ```tsx\n * <Panel communicationLayer={myCommunicationLayer} />\n * ```\n *\n * Note: The `communicationLayer` prop is essential for the proper functioning of the `Panel` component, as it enables the necessary\n * communication and data exchange with the player-ui/react library.\n */\nexport const Panel: React.FC<{\n /** the communication layer to use for the extension */\n readonly communicationLayer: Pick<\n MessengerOptions<ExtensionSupportedEvents>,\n \"sendMessage\" | \"addListener\" | \"removeListener\"\n >;\n baseTheme?: Record<string, unknown>;\n}> = ({ communicationLayer, baseTheme }) => {\n const { state, selectPlayer, selectPlugin, handleInteraction } =\n useExtensionState({\n communicationLayer,\n });\n\n const { reactPlayer, playerState } = useReactPlayer({\n plugins: PLAYER_PLUGINS,\n });\n\n const dataController = useRef<WeakRef<DataController> | null>(null);\n\n const currentFlow = useRef<Flow | null>(null);\n\n useEffect(() => {\n reactPlayer.player.hooks.dataController.tap(\"devtools-panel\", (d) => {\n dataController.current = new WeakRef(d);\n });\n }, [reactPlayer]);\n\n useEffect(() => {\n // we subscribe to all messages from the devtools plugin\n // so the plugin author can define their own events\n PUBSUB_PLUGIN.subscribe(\"*\", (type: string, payload: string) => {\n handleInteraction({\n type,\n payload,\n });\n });\n }, []);\n\n useEffect(() => {\n const { player, plugin } = state.current;\n\n const flow =\n player && plugin\n ? state.players[player]?.plugins?.[plugin]?.flow || INITIAL_FLOW\n : INITIAL_FLOW;\n\n if (!currentFlow.current) {\n currentFlow.current = flow;\n reactPlayer.start(flow);\n return;\n }\n\n const diff = flowDiff({\n curr: currentFlow.current as Flow,\n next: flow,\n });\n\n if (diff) {\n const { change, value } = diff;\n\n if (change === \"flow\") {\n currentFlow.current = value;\n reactPlayer.start(value);\n } else if (change === \"data\") {\n if (dataController.current) {\n dataController.current.deref()?.set(value as Record<string, unknown>);\n } else {\n reactPlayer.start(flow);\n }\n }\n }\n }, [reactPlayer, state]);\n\n const isDarkMode = useDarkMode();\n const colorMode = isDarkMode ? \"dark\" : \"light\";\n\n const config: ThemeConfig = {\n initialColorMode: colorMode,\n useSystemColorMode: true,\n };\n const theme = extendTheme({ config, ...baseTheme });\n\n const Component = reactPlayer.Component as React.FC;\n\n return (\n <ChakraProvider resetCSS={false} theme={theme}>\n <ThemeProvider theme=\"chrome\" colorScheme={colorMode}>\n <ErrorBoundary fallbackRender={fallbackRender}>\n <Flex\n direction=\"column\"\n h=\"100vh\"\n alignItems={\"normal\"}\n overflow=\"scroll\"\n >\n {state.current.player ? (\n <Flex direction=\"column\" gap=\"20px\">\n <Flex gap=\"16px\">\n <FormControl>\n <FormLabel>Player</FormLabel>\n <Select\n id=\"player\"\n value={state.current.player || \"\"}\n onChange={(event) => selectPlayer(event.target.value)}\n >\n {Object.keys(state.players).map((playerID) => (\n <option key={playerID} value={playerID}>\n {playerID}\n </option>\n ))}\n </Select>\n </FormControl>\n <FormControl>\n <FormLabel>Plugin</FormLabel>\n <Select\n id=\"plugin\"\n value={state.current.plugin || \"\"}\n onChange={(event) => selectPlugin(event.target.value)}\n >\n {Object.keys(\n state.players[state.current.player]?.plugins ?? [],\n ).map((pluginID) => (\n <option key={pluginID} value={pluginID}>\n {pluginID}\n </option>\n ))}\n </Select>\n </FormControl>\n </Flex>\n <Flex width=\"100%\">\n {playerState.status === \"error\" ? (\n fallbackRender({\n error: playerState.error,\n resetErrorBoundary: () => {},\n })\n ) : (\n <Component />\n )}\n </Flex>\n <details>\n <summary>Debug</summary>\n <pre style={{ maxHeight: \"30vh\", overflow: \"scroll\" }}>\n {JSON.stringify(state, null, 2)}\n </pre>\n </details>\n </Flex>\n ) : (\n <Flex justifyContent=\"center\" padding=\"6\">\n <Text>\n No Player-UI instance or devtools plugin detected. Visit{\" \"}\n <a href=\"https://player-ui.github.io/\">\n https://player-ui.github.io/\n </a>{\" \"}\n for more info.\n </Text>\n </Flex>\n )}\n </Flex>\n </ErrorBoundary>\n </ThemeProvider>\n </ChakraProvider>\n );\n};\n","import DevtoolsUIAssetsPlugin from \"@devtools-ui/plugin\";\nimport { PubSubPlugin } from \"@player-ui/pubsub-plugin\";\nimport { CommonExpressionsPlugin } from \"@player-ui/common-expressions-plugin\";\nimport { CommonTypesPlugin } from \"@player-ui/common-types-plugin\";\nimport { DataChangeListenerPlugin } from \"@player-ui/data-change-listener-plugin\";\nimport {\n ConsoleLogger,\n Player,\n PlayerPlugin,\n ReactPlayer,\n type ReactPlayerPlugin,\n} from \"@player-ui/react\";\n\nclass LogForwarder implements PlayerPlugin, ReactPlayerPlugin {\n name = \"Log\";\n apply(player: Player) {\n player.logger.addHandler(new ConsoleLogger(\"trace\", console));\n }\n\n applyReact(reactPlayer: ReactPlayer) {\n this.apply(reactPlayer.player);\n }\n}\n\nexport const PUBSUB_PLUGIN = new PubSubPlugin();\n\nexport const PLAYER_PLUGINS: ReactPlayerPlugin[] = [\n new CommonTypesPlugin(),\n new CommonExpressionsPlugin(),\n new DataChangeListenerPlugin(),\n new DevtoolsUIAssetsPlugin(),\n new LogForwarder(),\n PUBSUB_PLUGIN,\n];\n","import type { CommunicationLayerMethods } from \"@player-devtools/types\";\nimport { useEffect, useMemo, useSyncExternalStore } from \"react\";\n\nimport { createExtensionClient } from \"@player-devtools/client\";\n\n/**\n * Thin React adapter over `createExtensionClient`.\n *\n * Creates the client once per `communicationLayer` identity, subscribes to\n * state via `useSyncExternalStore`, and tears down the Messenger on unmount.\n */\nexport const useExtensionState = ({\n communicationLayer,\n}: {\n /** the communication layer to use for the extension */\n communicationLayer: CommunicationLayerMethods;\n}) => {\n const client = useMemo(\n () => createExtensionClient(communicationLayer),\n [communicationLayer],\n );\n\n useEffect(() => () => client.destroy(), [client]);\n\n const state = useSyncExternalStore(client.subscribe, client.getState);\n\n return {\n state,\n selectPlayer: client.selectPlayer,\n selectPlugin: client.selectPlugin,\n handleInteraction: client.handleInteraction,\n };\n};\n","import type { Flow } from \"@player-ui/react\";\nimport { dequal } from \"dequal\";\n\n/**\n * Compares two Flow objects and identifies if there's a change in their structure or data.\n *\n * This function takes two Flow objects as input, `curr` (current) and `next` (next), and compares them\n * to determine if there's a change in the flow's structure or its data. If there's a change in the flow's\n * structure (excluding the `data` property), it returns an object indicating a \"flow\" change along with the\n * new flow. If there's a change in the `data` property, it returns an object indicating a \"data\" change along\n * with the new data. If there are no changes, it returns null.\n */\nexport const flowDiff = ({\n curr,\n next,\n}: {\n curr: Flow;\n next: Flow;\n}):\n | { change: \"data\"; value: Flow[\"data\"] }\n | { change: \"flow\"; value: Flow }\n | null => {\n // compare flows except for the `data` property\n const currCopy = { ...curr, data: null };\n const nextCopy = { ...next, data: null };\n\n const baseFlowIsEqual = dequal(currCopy, nextCopy);\n\n if (!baseFlowIsEqual) {\n return { change: \"flow\", value: next };\n }\n\n // compare data\n const currData = curr.data;\n const nextData = next.data;\n\n const dataIsEqual = dequal(currData, nextData);\n\n if (!dataIsEqual) {\n return { change: \"data\", value: nextData };\n }\n\n return null;\n};\n"],"mappings":"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","names":["useEffect","useEffect"]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "sideEffects": false,
3
+ "files": [
4
+ "dist",
5
+ "src",
6
+ "types"
7
+ ],
8
+ "name": "@player-devtools/client-react",
9
+ "version": "0.13.1--canary.17.955",
10
+ "main": "dist/cjs/index.cjs",
11
+ "dependencies": {
12
+ "@player-devtools/client": "0.13.1--canary.17.955",
13
+ "@player-devtools/messenger": "0.13.1--canary.17.955",
14
+ "@player-devtools/types": "0.13.1--canary.17.955",
15
+ "@player-devtools/utils": "0.13.1--canary.17.955",
16
+ "@chakra-ui/react": "2.8.2",
17
+ "@player-ui/pubsub-plugin": "0.12.0-next.1",
18
+ "@player-ui/player": "0.12.0-next.1",
19
+ "@player-ui/react": "0.12.0-next.1",
20
+ "@player-ui/common-expressions-plugin": "0.12.0-next.1",
21
+ "@player-ui/common-types-plugin": "0.12.0-next.1",
22
+ "@player-ui/data-change-listener-plugin": "0.12.0-next.1",
23
+ "@devtools-ui/plugin": "0.4.0",
24
+ "@types/react": "^18.2.51",
25
+ "immer": "^10.0.3",
26
+ "react": "^18.2.0",
27
+ "react-error-boundary": "^4.0.12",
28
+ "dequal": "^2.0.2",
29
+ "@devtools-ds/themes": "^1.2.1",
30
+ "tslib": "^2.6.2"
31
+ },
32
+ "module": "dist/index.legacy-esm.js",
33
+ "types": "types/index.d.ts",
34
+ "exports": {
35
+ "./package.json": "./package.json",
36
+ "./dist/index.css": "./dist/index.css",
37
+ ".": {
38
+ "types": "./types/index.d.ts",
39
+ "import": "./dist/index.mjs",
40
+ "default": "./dist/cjs/index.cjs"
41
+ }
42
+ },
43
+ "peerDependencies": {}
44
+ }
@@ -0,0 +1,72 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import type { Flow } from "@player-ui/react";
3
+ import { flowDiff } from "../flowDiff";
4
+
5
+ const mockFlow1: Flow = {
6
+ id: "flow",
7
+ views: [
8
+ {
9
+ id: "view",
10
+ type: "info",
11
+ },
12
+ ],
13
+ data: {
14
+ foo: "bar",
15
+ },
16
+ navigation: {
17
+ BEGIN: "BEGIN",
18
+ },
19
+ };
20
+
21
+ const mockFlow2: Flow = {
22
+ id: "flow",
23
+ views: [
24
+ {
25
+ id: "view",
26
+ type: "info",
27
+ },
28
+ ],
29
+ data: {
30
+ foo: "bar",
31
+ something: "else",
32
+ },
33
+ navigation: {
34
+ BEGIN: "BEGIN",
35
+ },
36
+ };
37
+
38
+ const mockFlow3: Flow = {
39
+ id: "another_flow",
40
+ views: [
41
+ {
42
+ id: "view",
43
+ type: "info",
44
+ },
45
+ ],
46
+ data: {
47
+ foo: "bar",
48
+ },
49
+ navigation: {
50
+ BEGIN: "BEGIN",
51
+ },
52
+ };
53
+
54
+ describe("flowDiff", () => {
55
+ test("returns null if no changes", () => {
56
+ const result = flowDiff({ curr: mockFlow1, next: mockFlow1 });
57
+
58
+ expect(result).toBeNull();
59
+ });
60
+
61
+ test("returns flow change if base flow is different", () => {
62
+ const result = flowDiff({ curr: mockFlow1, next: mockFlow3 });
63
+
64
+ expect(result).toEqual({ change: "flow", value: mockFlow3 });
65
+ });
66
+
67
+ test("returns data change if data is different", () => {
68
+ const result = flowDiff({ curr: mockFlow1, next: mockFlow2 });
69
+
70
+ expect(result).toEqual({ change: "data", value: mockFlow2.data });
71
+ });
72
+ });
@@ -0,0 +1,44 @@
1
+ import type { Flow } from "@player-ui/react";
2
+ import { dequal } from "dequal";
3
+
4
+ /**
5
+ * Compares two Flow objects and identifies if there's a change in their structure or data.
6
+ *
7
+ * This function takes two Flow objects as input, `curr` (current) and `next` (next), and compares them
8
+ * to determine if there's a change in the flow's structure or its data. If there's a change in the flow's
9
+ * structure (excluding the `data` property), it returns an object indicating a "flow" change along with the
10
+ * new flow. If there's a change in the `data` property, it returns an object indicating a "data" change along
11
+ * with the new data. If there are no changes, it returns null.
12
+ */
13
+ export const flowDiff = ({
14
+ curr,
15
+ next,
16
+ }: {
17
+ curr: Flow;
18
+ next: Flow;
19
+ }):
20
+ | { change: "data"; value: Flow["data"] }
21
+ | { change: "flow"; value: Flow }
22
+ | null => {
23
+ // compare flows except for the `data` property
24
+ const currCopy = { ...curr, data: null };
25
+ const nextCopy = { ...next, data: null };
26
+
27
+ const baseFlowIsEqual = dequal(currCopy, nextCopy);
28
+
29
+ if (!baseFlowIsEqual) {
30
+ return { change: "flow", value: next };
31
+ }
32
+
33
+ // compare data
34
+ const currData = curr.data;
35
+ const nextData = next.data;
36
+
37
+ const dataIsEqual = dequal(currData, nextData);
38
+
39
+ if (!dataIsEqual) {
40
+ return { change: "data", value: nextData };
41
+ }
42
+
43
+ return null;
44
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { Panel } from "./panel";
@@ -0,0 +1,256 @@
1
+ import React, { useRef } from "react";
2
+ import type {
3
+ MessengerOptions,
4
+ ExtensionSupportedEvents,
5
+ } from "@player-devtools/types";
6
+ import { DataController, Flow, useReactPlayer } from "@player-ui/react";
7
+ import { useEffect } from "react";
8
+ import { ErrorBoundary } from "react-error-boundary";
9
+ import {
10
+ Card,
11
+ CardBody,
12
+ CardHeader,
13
+ ChakraProvider,
14
+ Container,
15
+ extendTheme,
16
+ Flex,
17
+ FormControl,
18
+ FormLabel,
19
+ Heading,
20
+ Select,
21
+ Text,
22
+ type ThemeConfig,
23
+ } from "@chakra-ui/react";
24
+
25
+ import { ThemeProvider, useDarkMode } from "@devtools-ds/themes";
26
+
27
+ import { PLAYER_PLUGINS, PUBSUB_PLUGIN } from "../plugins";
28
+ import { useExtensionState } from "../state";
29
+ import { flowDiff } from "../helpers/flowDiff";
30
+
31
+ /** Placeholder flow rendered until a real Player flow arrives. */
32
+ const INITIAL_FLOW: Flow = {
33
+ id: "initial-flow",
34
+ views: [
35
+ {
36
+ id: "view-1",
37
+ type: "text",
38
+ value: "connecting...",
39
+ },
40
+ ],
41
+ navigation: {
42
+ BEGIN: "FLOW_1",
43
+ FLOW_1: {
44
+ startState: "VIEW_1",
45
+ VIEW_1: {
46
+ state_type: "VIEW",
47
+ ref: "view-1",
48
+ transitions: {},
49
+ },
50
+ },
51
+ },
52
+ };
53
+
54
+ const fallbackRender: ErrorBoundary["props"]["fallbackRender"] = ({
55
+ error,
56
+ }) => {
57
+ return (
58
+ <Container centerContent>
59
+ <Card>
60
+ <CardHeader>
61
+ <Heading>Ops, something went wrong.</Heading>
62
+ </CardHeader>
63
+ <CardBody>
64
+ <Text as="pre">{error.message}</Text>
65
+ </CardBody>
66
+ </Card>
67
+ </Container>
68
+ );
69
+ };
70
+
71
+ /**
72
+ * Panel Component
73
+ *
74
+ * This component serves as the main container for the devtools plugin content defined by plugin authors using Player-UI DSL.
75
+ *
76
+ * Props:
77
+ * - `communicationLayer`: An object that allows communication between the devtools and the Player-UI plugins,
78
+ * enabling the exchange of data and events.
79
+ *
80
+ * Features:
81
+ * - Error Handling: Utilizes the `ErrorBoundary` component from `react-error-boundary` to gracefully handle and display errors
82
+ * that may occur during the rendering of the plugin's content.
83
+ * - State Management: Integrates with custom hooks such as `useExtensionState` to manage the state of the plugin and its components.
84
+ * - Player Integration: Uses the `useReactPlayer` hook from `player-ui/react` to render interactive player components based on the
85
+ * DSL defined by the plugin authors.
86
+ *
87
+ * Example Usage:
88
+ * ```tsx
89
+ * <Panel communicationLayer={myCommunicationLayer} />
90
+ * ```
91
+ *
92
+ * Note: The `communicationLayer` prop is essential for the proper functioning of the `Panel` component, as it enables the necessary
93
+ * communication and data exchange with the player-ui/react library.
94
+ */
95
+ export const Panel: React.FC<{
96
+ /** the communication layer to use for the extension */
97
+ readonly communicationLayer: Pick<
98
+ MessengerOptions<ExtensionSupportedEvents>,
99
+ "sendMessage" | "addListener" | "removeListener"
100
+ >;
101
+ baseTheme?: Record<string, unknown>;
102
+ }> = ({ communicationLayer, baseTheme }) => {
103
+ const { state, selectPlayer, selectPlugin, handleInteraction } =
104
+ useExtensionState({
105
+ communicationLayer,
106
+ });
107
+
108
+ const { reactPlayer, playerState } = useReactPlayer({
109
+ plugins: PLAYER_PLUGINS,
110
+ });
111
+
112
+ const dataController = useRef<WeakRef<DataController> | null>(null);
113
+
114
+ const currentFlow = useRef<Flow | null>(null);
115
+
116
+ useEffect(() => {
117
+ reactPlayer.player.hooks.dataController.tap("devtools-panel", (d) => {
118
+ dataController.current = new WeakRef(d);
119
+ });
120
+ }, [reactPlayer]);
121
+
122
+ useEffect(() => {
123
+ // we subscribe to all messages from the devtools plugin
124
+ // so the plugin author can define their own events
125
+ PUBSUB_PLUGIN.subscribe("*", (type: string, payload: string) => {
126
+ handleInteraction({
127
+ type,
128
+ payload,
129
+ });
130
+ });
131
+ }, []);
132
+
133
+ useEffect(() => {
134
+ const { player, plugin } = state.current;
135
+
136
+ const flow =
137
+ player && plugin
138
+ ? state.players[player]?.plugins?.[plugin]?.flow || INITIAL_FLOW
139
+ : INITIAL_FLOW;
140
+
141
+ if (!currentFlow.current) {
142
+ currentFlow.current = flow;
143
+ reactPlayer.start(flow);
144
+ return;
145
+ }
146
+
147
+ const diff = flowDiff({
148
+ curr: currentFlow.current as Flow,
149
+ next: flow,
150
+ });
151
+
152
+ if (diff) {
153
+ const { change, value } = diff;
154
+
155
+ if (change === "flow") {
156
+ currentFlow.current = value;
157
+ reactPlayer.start(value);
158
+ } else if (change === "data") {
159
+ if (dataController.current) {
160
+ dataController.current.deref()?.set(value as Record<string, unknown>);
161
+ } else {
162
+ reactPlayer.start(flow);
163
+ }
164
+ }
165
+ }
166
+ }, [reactPlayer, state]);
167
+
168
+ const isDarkMode = useDarkMode();
169
+ const colorMode = isDarkMode ? "dark" : "light";
170
+
171
+ const config: ThemeConfig = {
172
+ initialColorMode: colorMode,
173
+ useSystemColorMode: true,
174
+ };
175
+ const theme = extendTheme({ config, ...baseTheme });
176
+
177
+ const Component = reactPlayer.Component as React.FC;
178
+
179
+ return (
180
+ <ChakraProvider resetCSS={false} theme={theme}>
181
+ <ThemeProvider theme="chrome" colorScheme={colorMode}>
182
+ <ErrorBoundary fallbackRender={fallbackRender}>
183
+ <Flex
184
+ direction="column"
185
+ h="100vh"
186
+ alignItems={"normal"}
187
+ overflow="scroll"
188
+ >
189
+ {state.current.player ? (
190
+ <Flex direction="column" gap="20px">
191
+ <Flex gap="16px">
192
+ <FormControl>
193
+ <FormLabel>Player</FormLabel>
194
+ <Select
195
+ id="player"
196
+ value={state.current.player || ""}
197
+ onChange={(event) => selectPlayer(event.target.value)}
198
+ >
199
+ {Object.keys(state.players).map((playerID) => (
200
+ <option key={playerID} value={playerID}>
201
+ {playerID}
202
+ </option>
203
+ ))}
204
+ </Select>
205
+ </FormControl>
206
+ <FormControl>
207
+ <FormLabel>Plugin</FormLabel>
208
+ <Select
209
+ id="plugin"
210
+ value={state.current.plugin || ""}
211
+ onChange={(event) => selectPlugin(event.target.value)}
212
+ >
213
+ {Object.keys(
214
+ state.players[state.current.player]?.plugins ?? [],
215
+ ).map((pluginID) => (
216
+ <option key={pluginID} value={pluginID}>
217
+ {pluginID}
218
+ </option>
219
+ ))}
220
+ </Select>
221
+ </FormControl>
222
+ </Flex>
223
+ <Flex width="100%">
224
+ {playerState.status === "error" ? (
225
+ fallbackRender({
226
+ error: playerState.error,
227
+ resetErrorBoundary: () => {},
228
+ })
229
+ ) : (
230
+ <Component />
231
+ )}
232
+ </Flex>
233
+ <details>
234
+ <summary>Debug</summary>
235
+ <pre style={{ maxHeight: "30vh", overflow: "scroll" }}>
236
+ {JSON.stringify(state, null, 2)}
237
+ </pre>
238
+ </details>
239
+ </Flex>
240
+ ) : (
241
+ <Flex justifyContent="center" padding="6">
242
+ <Text>
243
+ No Player-UI instance or devtools plugin detected. Visit{" "}
244
+ <a href="https://player-ui.github.io/">
245
+ https://player-ui.github.io/
246
+ </a>{" "}
247
+ for more info.
248
+ </Text>
249
+ </Flex>
250
+ )}
251
+ </Flex>
252
+ </ErrorBoundary>
253
+ </ThemeProvider>
254
+ </ChakraProvider>
255
+ );
256
+ };
@@ -0,0 +1,34 @@
1
+ import DevtoolsUIAssetsPlugin from "@devtools-ui/plugin";
2
+ import { PubSubPlugin } from "@player-ui/pubsub-plugin";
3
+ import { CommonExpressionsPlugin } from "@player-ui/common-expressions-plugin";
4
+ import { CommonTypesPlugin } from "@player-ui/common-types-plugin";
5
+ import { DataChangeListenerPlugin } from "@player-ui/data-change-listener-plugin";
6
+ import {
7
+ ConsoleLogger,
8
+ Player,
9
+ PlayerPlugin,
10
+ ReactPlayer,
11
+ type ReactPlayerPlugin,
12
+ } from "@player-ui/react";
13
+
14
+ class LogForwarder implements PlayerPlugin, ReactPlayerPlugin {
15
+ name = "Log";
16
+ apply(player: Player) {
17
+ player.logger.addHandler(new ConsoleLogger("trace", console));
18
+ }
19
+
20
+ applyReact(reactPlayer: ReactPlayer) {
21
+ this.apply(reactPlayer.player);
22
+ }
23
+ }
24
+
25
+ export const PUBSUB_PLUGIN = new PubSubPlugin();
26
+
27
+ export const PLAYER_PLUGINS: ReactPlayerPlugin[] = [
28
+ new CommonTypesPlugin(),
29
+ new CommonExpressionsPlugin(),
30
+ new DataChangeListenerPlugin(),
31
+ new DevtoolsUIAssetsPlugin(),
32
+ new LogForwarder(),
33
+ PUBSUB_PLUGIN,
34
+ ];
@@ -0,0 +1,33 @@
1
+ import type { CommunicationLayerMethods } from "@player-devtools/types";
2
+ import { useEffect, useMemo, useSyncExternalStore } from "react";
3
+
4
+ import { createExtensionClient } from "@player-devtools/client";
5
+
6
+ /**
7
+ * Thin React adapter over `createExtensionClient`.
8
+ *
9
+ * Creates the client once per `communicationLayer` identity, subscribes to
10
+ * state via `useSyncExternalStore`, and tears down the Messenger on unmount.
11
+ */
12
+ export const useExtensionState = ({
13
+ communicationLayer,
14
+ }: {
15
+ /** the communication layer to use for the extension */
16
+ communicationLayer: CommunicationLayerMethods;
17
+ }) => {
18
+ const client = useMemo(
19
+ () => createExtensionClient(communicationLayer),
20
+ [communicationLayer],
21
+ );
22
+
23
+ useEffect(() => () => client.destroy(), [client]);
24
+
25
+ const state = useSyncExternalStore(client.subscribe, client.getState);
26
+
27
+ return {
28
+ state,
29
+ selectPlayer: client.selectPlayer,
30
+ selectPlugin: client.selectPlugin,
31
+ handleInteraction: client.handleInteraction,
32
+ };
33
+ };
@@ -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
@@ -0,0 +1,2 @@
1
+ export { Panel } from "./panel";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,32 @@
1
+ import React from "react";
2
+ import type { MessengerOptions, ExtensionSupportedEvents } from "@player-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: React.FC<{
28
+ /** the communication layer to use for the extension */
29
+ readonly communicationLayer: Pick<MessengerOptions<ExtensionSupportedEvents>, "sendMessage" | "addListener" | "removeListener">;
30
+ baseTheme?: Record<string, unknown>;
31
+ }>;
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { PubSubPlugin } from "@player-ui/pubsub-plugin";
2
+ import { type ReactPlayerPlugin } from "@player-ui/react";
3
+ export declare const PUBSUB_PLUGIN: PubSubPlugin;
4
+ export declare const PLAYER_PLUGINS: ReactPlayerPlugin[];
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,21 @@
1
+ import type { CommunicationLayerMethods } from "@player-devtools/types";
2
+ /**
3
+ * Thin React adapter over `createExtensionClient`.
4
+ *
5
+ * Creates the client once per `communicationLayer` identity, subscribes to
6
+ * state via `useSyncExternalStore`, and tears down the Messenger on unmount.
7
+ */
8
+ export declare const useExtensionState: ({ communicationLayer, }: {
9
+ /** the communication layer to use for the extension */
10
+ communicationLayer: CommunicationLayerMethods;
11
+ }) => {
12
+ state: import("@player-devtools/types").ExtensionState;
13
+ selectPlayer: (playerID: string) => void;
14
+ selectPlugin: (pluginID: string) => void;
15
+ handleInteraction: (interaction: {
16
+ type: string;
17
+ payload?: string;
18
+ target?: string;
19
+ }) => void;
20
+ };
21
+ //# sourceMappingURL=index.d.ts.map