@player-ui/react 0.8.0--canary.307.9621 → 0.8.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 +664 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/index.legacy-esm.js +611 -0
- package/dist/index.mjs +611 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +30 -64
- package/src/__tests__/__snapshots__/app.test.tsx.snap +139 -0
- package/src/__tests__/app.test.tsx +244 -0
- package/src/__tests__/helpers/simple-asset-plugin.tsx +114 -0
- package/src/__tests__/hooks.test.tsx +8 -0
- package/src/app.tsx +3 -3
- package/src/asset/__tests__/index.test.tsx +129 -0
- package/src/asset/index.tsx +10 -10
- package/src/hooks.tsx +7 -8
- package/src/index.tsx +8 -8
- package/src/manager/__tests__/managed-player.test.tsx +454 -0
- package/src/manager/managed-player.tsx +31 -36
- package/src/manager/request-time.tsx +8 -8
- package/src/manager/types.ts +12 -12
- package/src/player.tsx +24 -43
- package/src/plugins/onupdate-plugin.ts +3 -3
- package/src/plugins/tapstate-plugin.ts +4 -4
- package/src/utils/__tests__/helpers.test.ts +39 -0
- package/src/utils/__tests__/url.test.ts +14 -0
- package/src/utils/helpers.ts +15 -12
- package/src/utils/index.tsx +6 -6
- package/src/utils/player-context.ts +2 -2
- package/src/utils/shared-constants.tsx +2 -2
- package/src/utils/url.ts +2 -2
- package/src/utils/use-asset-props.tsx +2 -2
- package/src/utils/use-logger.ts +3 -3
- package/types/app.d.ts +14 -0
- package/types/asset/index.d.ts +16 -0
- package/types/hooks.d.ts +17 -0
- package/types/index.d.ts +9 -0
- package/types/manager/managed-player.d.ts +93 -0
- package/types/manager/request-time.d.ts +7 -0
- package/types/manager/types.d.ts +125 -0
- package/types/player.d.ts +86 -0
- package/types/plugins/onupdate-plugin.d.ts +12 -0
- package/types/plugins/tapstate-plugin.d.ts +12 -0
- package/types/utils/helpers.d.ts +17 -0
- package/types/utils/index.d.ts +7 -0
- package/types/utils/player-context.d.ts +16 -0
- package/types/utils/shared-constants.d.ts +5 -0
- package/types/utils/url.d.ts +5 -0
- package/types/utils/use-asset-props.d.ts +7 -0
- package/types/utils/use-logger.d.ts +6 -0
- package/dist/index.cjs.js +0 -690
- package/dist/index.d.ts +0 -397
- package/dist/index.esm.js +0 -658
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ReactAsset, usePlayer } from "../..";
|
|
3
|
+
import type {
|
|
4
|
+
ReactPlayer,
|
|
5
|
+
ReactPlayerPlugin,
|
|
6
|
+
Asset,
|
|
7
|
+
AssetWrapper,
|
|
8
|
+
Flow,
|
|
9
|
+
} from "../..";
|
|
10
|
+
|
|
11
|
+
interface SimpleAsset extends Asset<"simple"> {
|
|
12
|
+
/** text value of the asset */
|
|
13
|
+
value?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** basic aset */
|
|
17
|
+
const SimpleAsset = (props: SimpleAsset) => (
|
|
18
|
+
<div id={props.id}>{props.value}</div>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
interface ActionAsset extends Asset<"action"> {
|
|
22
|
+
/** label of the action */
|
|
23
|
+
label: string;
|
|
24
|
+
|
|
25
|
+
/** value of the action */
|
|
26
|
+
value: string;
|
|
27
|
+
|
|
28
|
+
/** expression of the action */
|
|
29
|
+
exp: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** basic action asset */
|
|
33
|
+
const Action = (props: ActionAsset) => {
|
|
34
|
+
const player = usePlayer();
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
id={props.id}
|
|
40
|
+
onClick={() => {
|
|
41
|
+
const state = player?.getState();
|
|
42
|
+
|
|
43
|
+
if (state?.status === "in-progress") {
|
|
44
|
+
if (props.exp) {
|
|
45
|
+
state.controllers.expression.evaluate(props.exp);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (props.value) {
|
|
49
|
+
state.controllers.flow.transition(props.value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
{props.label}
|
|
55
|
+
</button>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
interface CollectionAsset extends Asset<"collection"> {
|
|
60
|
+
/** values in a collection */
|
|
61
|
+
values: Array<AssetWrapper<any>>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** basic collection asset */
|
|
65
|
+
const Collection = (props: CollectionAsset) => {
|
|
66
|
+
return (
|
|
67
|
+
<div id={props.id}>
|
|
68
|
+
{props.values.map((a) => (
|
|
69
|
+
<ReactAsset key={a.asset.id} {...a.asset} />
|
|
70
|
+
))}
|
|
71
|
+
</div>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const simpleFlow: Flow<any> = {
|
|
76
|
+
id: "flow_1",
|
|
77
|
+
views: [
|
|
78
|
+
{
|
|
79
|
+
id: "first_view",
|
|
80
|
+
type: "simple",
|
|
81
|
+
value: "{{foo.bar}}",
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
navigation: {
|
|
85
|
+
BEGIN: "flow_1",
|
|
86
|
+
flow_1: {
|
|
87
|
+
startState: "view_1",
|
|
88
|
+
view_1: {
|
|
89
|
+
state_type: "VIEW",
|
|
90
|
+
ref: "first_view",
|
|
91
|
+
transitions: {
|
|
92
|
+
"*": "end_1",
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
end_1: {
|
|
96
|
+
state_type: "END",
|
|
97
|
+
outcome: "end",
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Registers a simple asset as a react comp
|
|
105
|
+
*/
|
|
106
|
+
export class SimpleAssetPlugin implements ReactPlayerPlugin {
|
|
107
|
+
name = "simple-asset-plugin";
|
|
108
|
+
|
|
109
|
+
applyReact(rp: ReactPlayer) {
|
|
110
|
+
rp.assetRegistry.set({ type: "simple" }, SimpleAsset);
|
|
111
|
+
rp.assetRegistry.set({ type: "action" }, Action);
|
|
112
|
+
rp.assetRegistry.set({ type: "collection" }, Collection);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { test, expect } from "vitest";
|
|
2
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
3
|
+
import { useReactPlayer } from "..";
|
|
4
|
+
|
|
5
|
+
test("reactPlayer hook", () => {
|
|
6
|
+
const { result } = renderHook(() => useReactPlayer());
|
|
7
|
+
expect(result.current.reactPlayer).toBeDefined();
|
|
8
|
+
});
|
package/src/app.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import type { View } from
|
|
3
|
-
import { ReactAsset } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { View } from "@player-ui/player";
|
|
3
|
+
import { ReactAsset } from "./asset";
|
|
4
4
|
|
|
5
5
|
export interface ReactPlayerProps {
|
|
6
6
|
/**
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { test, expect } from "vitest";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import { Registry } from "@player-ui/partial-match-registry";
|
|
5
|
+
import type { Asset as AssetType } from "@player-ui/player";
|
|
6
|
+
import type { AssetRegistryType } from "..";
|
|
7
|
+
import { ReactAsset, AssetContext } from "..";
|
|
8
|
+
|
|
9
|
+
test("it prioritizes local type and id", () => {
|
|
10
|
+
const assetDef = {
|
|
11
|
+
id: "foo",
|
|
12
|
+
type: "foo",
|
|
13
|
+
asset: {
|
|
14
|
+
id: "bar",
|
|
15
|
+
type: "bar",
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const registry: AssetRegistryType = new Registry([
|
|
20
|
+
[{ type: "foo" }, () => <div>foo</div>],
|
|
21
|
+
[{ type: "bar" }, () => <div>bar</div>],
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
const asset = render(
|
|
25
|
+
<AssetContext.Provider value={{ registry }}>
|
|
26
|
+
<ReactAsset {...assetDef} />
|
|
27
|
+
</AssetContext.Provider>,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
expect(asset.getByText("foo")).not.toBeUndefined();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("throws an error for an asset missing implementation", () => {
|
|
34
|
+
const assetDef = {
|
|
35
|
+
asset: {
|
|
36
|
+
id: "bar-id",
|
|
37
|
+
type: "bar",
|
|
38
|
+
},
|
|
39
|
+
} as unknown as AssetType;
|
|
40
|
+
|
|
41
|
+
const registry: AssetRegistryType = new Registry([
|
|
42
|
+
[{ type: "foo" }, () => <div>foo</div>],
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
expect(() =>
|
|
46
|
+
render(
|
|
47
|
+
<AssetContext.Provider value={{ registry }}>
|
|
48
|
+
<ReactAsset {...assetDef} />
|
|
49
|
+
</AssetContext.Provider>,
|
|
50
|
+
),
|
|
51
|
+
).toThrowError("No implementation found for id: bar-id type: bar");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("throws an error for an asset missing type", () => {
|
|
55
|
+
const assetDef = {
|
|
56
|
+
asset: {
|
|
57
|
+
id: "bar-id",
|
|
58
|
+
},
|
|
59
|
+
} as unknown as AssetType;
|
|
60
|
+
|
|
61
|
+
const registry: AssetRegistryType = new Registry([
|
|
62
|
+
[{ type: "foo" }, () => <div>foo</div>],
|
|
63
|
+
[{ type: "bar" }, () => <div>bar</div>],
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
expect(() =>
|
|
67
|
+
render(
|
|
68
|
+
<AssetContext.Provider value={{ registry }}>
|
|
69
|
+
<ReactAsset {...assetDef} />
|
|
70
|
+
</AssetContext.Provider>,
|
|
71
|
+
),
|
|
72
|
+
).toThrowError("Asset is missing type for id: bar-id");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("throws an error for an asset that isnt an object", () => {
|
|
76
|
+
const assetDef = {
|
|
77
|
+
asset: "bar",
|
|
78
|
+
} as unknown as AssetType;
|
|
79
|
+
|
|
80
|
+
const registry: AssetRegistryType = new Registry([
|
|
81
|
+
[{ type: "foo" }, () => <div>foo</div>],
|
|
82
|
+
[{ type: "bar" }, () => <div>bar</div>],
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
expect(() =>
|
|
86
|
+
render(
|
|
87
|
+
<AssetContext.Provider value={{ registry }}>
|
|
88
|
+
<ReactAsset {...assetDef} />
|
|
89
|
+
</AssetContext.Provider>,
|
|
90
|
+
),
|
|
91
|
+
).toThrowError("Asset was not an object got (string) instead: bar");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("throws an error for an asset that is an object but not valid", () => {
|
|
95
|
+
const assetDef = {
|
|
96
|
+
asset: ["a"],
|
|
97
|
+
} as unknown as AssetType;
|
|
98
|
+
|
|
99
|
+
const registry: AssetRegistryType = new Registry([
|
|
100
|
+
[{ type: "foo" }, () => <div>foo</div>],
|
|
101
|
+
[{ type: "bar" }, () => <div>bar</div>],
|
|
102
|
+
]);
|
|
103
|
+
|
|
104
|
+
expect(() =>
|
|
105
|
+
render(
|
|
106
|
+
<AssetContext.Provider value={{ registry }}>
|
|
107
|
+
<ReactAsset {...assetDef} />
|
|
108
|
+
</AssetContext.Provider>,
|
|
109
|
+
),
|
|
110
|
+
).toThrowError('Asset is missing type for {"asset":["a"]}');
|
|
111
|
+
});
|
|
112
|
+
test("throws an error for an asset that unwraps nothing", () => {
|
|
113
|
+
const assetDef = {
|
|
114
|
+
asset: undefined,
|
|
115
|
+
} as unknown as AssetType;
|
|
116
|
+
|
|
117
|
+
const registry: AssetRegistryType = new Registry([
|
|
118
|
+
[{ type: "foo" }, () => <div>foo</div>],
|
|
119
|
+
[{ type: "bar" }, () => <div>bar</div>],
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
expect(() =>
|
|
123
|
+
render(
|
|
124
|
+
<AssetContext.Provider value={{ registry }}>
|
|
125
|
+
<ReactAsset {...assetDef} />
|
|
126
|
+
</AssetContext.Provider>,
|
|
127
|
+
),
|
|
128
|
+
).toThrowError("Cannot determine asset type for props: {}");
|
|
129
|
+
});
|
package/src/asset/index.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import type { Asset as AssetType, AssetWrapper } from
|
|
3
|
-
import type { Registry } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Asset as AssetType, AssetWrapper } from "@player-ui/player";
|
|
3
|
+
import type { Registry } from "@player-ui/partial-match-registry";
|
|
4
4
|
|
|
5
5
|
export type AssetRegistryType = Registry<React.ComponentType<any>>;
|
|
6
6
|
|
|
@@ -17,27 +17,27 @@ export const AssetContext = React.createContext<ContextType>({});
|
|
|
17
17
|
* A React Component that looks up an implementation from a registry
|
|
18
18
|
*/
|
|
19
19
|
export const ReactAsset = (
|
|
20
|
-
props: AssetType<string> | AssetWrapper<AssetType<string
|
|
20
|
+
props: AssetType<string> | AssetWrapper<AssetType<string>>,
|
|
21
21
|
) => {
|
|
22
22
|
const { registry } = React.useContext(AssetContext);
|
|
23
23
|
|
|
24
24
|
let unwrapped;
|
|
25
25
|
|
|
26
|
-
if (
|
|
26
|
+
if ("type" in props && "id" in props) {
|
|
27
27
|
unwrapped = props;
|
|
28
|
-
} else if (
|
|
28
|
+
} else if ("asset" in props) {
|
|
29
29
|
unwrapped = (props as unknown as AssetWrapper).asset;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (!unwrapped) {
|
|
33
33
|
throw Error(
|
|
34
|
-
`Cannot determine asset type for props: ${JSON.stringify(props)}
|
|
34
|
+
`Cannot determine asset type for props: ${JSON.stringify(props)}`,
|
|
35
35
|
);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
if (typeof unwrapped !==
|
|
38
|
+
if (typeof unwrapped !== "object") {
|
|
39
39
|
throw Error(
|
|
40
|
-
`Asset was not an object got (${typeof unwrapped}) instead: ${unwrapped}
|
|
40
|
+
`Asset was not an object got (${typeof unwrapped}) instead: ${unwrapped}`,
|
|
41
41
|
);
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -53,7 +53,7 @@ export const ReactAsset = (
|
|
|
53
53
|
|
|
54
54
|
if (!Impl) {
|
|
55
55
|
throw Error(
|
|
56
|
-
`No implementation found for id: ${unwrapped.id} type: ${unwrapped.type}
|
|
56
|
+
`No implementation found for id: ${unwrapped.id} type: ${unwrapped.type}`,
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
59
|
|
package/src/hooks.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Player, PlayerFlowState } from
|
|
2
|
-
import { NOT_STARTED_STATE } from
|
|
3
|
-
import React from
|
|
4
|
-
import type { ReactPlayerOptions } from
|
|
5
|
-
import { ReactPlayer } from
|
|
6
|
-
import { StateTapPlugin } from
|
|
1
|
+
import type { Player, PlayerFlowState } from "@player-ui/player";
|
|
2
|
+
import { NOT_STARTED_STATE } from "@player-ui/player";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import type { ReactPlayerOptions } from "./player";
|
|
5
|
+
import { ReactPlayer } from "./player";
|
|
6
|
+
import { StateTapPlugin } from "./plugins/tapstate-plugin";
|
|
7
7
|
|
|
8
8
|
export interface UseReactPlayerReturn {
|
|
9
9
|
/** The web-player instance */
|
|
@@ -19,7 +19,7 @@ export interface UseReactPlayerReturn {
|
|
|
19
19
|
* Simply supply your config, plugins, and an optional flow, which will be automatically started for you when changed.
|
|
20
20
|
*/
|
|
21
21
|
export const useReactPlayer = (
|
|
22
|
-
options?: ReactPlayerOptions
|
|
22
|
+
options?: ReactPlayerOptions,
|
|
23
23
|
): UseReactPlayerReturn => {
|
|
24
24
|
const [playerState, setPlayerState] =
|
|
25
25
|
React.useState<PlayerFlowState>(NOT_STARTED_STATE);
|
|
@@ -31,7 +31,6 @@ export const useReactPlayer = (
|
|
|
31
31
|
...(options?.plugins ?? []),
|
|
32
32
|
new StateTapPlugin(setPlayerState),
|
|
33
33
|
],
|
|
34
|
-
suspend: options?.suspend,
|
|
35
34
|
});
|
|
36
35
|
|
|
37
36
|
return rp;
|
package/src/index.tsx
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
1
|
+
export * from "@player-ui/player";
|
|
2
|
+
export * from "./player";
|
|
3
|
+
export * from "./hooks";
|
|
4
|
+
export * from "./manager/managed-player";
|
|
5
|
+
export * from "./manager/request-time";
|
|
6
|
+
export * from "./manager/types";
|
|
7
|
+
export * from "./asset";
|
|
8
|
+
export * from "./utils";
|