@tailorkit/react 0.1.0-beta.3 → 0.1.0-beta.33

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.
Files changed (50) hide show
  1. package/LICENSE.md +74 -0
  2. package/README.md +3 -0
  3. package/dist/components/context.d.ts +7 -10
  4. package/dist/components/index.d.ts +1 -2
  5. package/dist/components/render-slot.d.ts +9 -0
  6. package/dist/hooks/use-apps.d.ts +6 -13
  7. package/dist/hooks/use-query-result.d.ts +9 -0
  8. package/dist/hooks/use-view-context.d.ts +6 -0
  9. package/dist/hooks/use-views.d.ts +7 -0
  10. package/dist/index.d.ts +7 -3
  11. package/dist/index.js +362 -839
  12. package/dist/primitives.d.ts +11 -21
  13. package/dist/remote-view.d.ts +12 -6
  14. package/dist/tailorkit.d.ts +45 -0
  15. package/package.json +42 -24
  16. package/LICENSE +0 -674
  17. package/dist/components/context.d.ts.map +0 -1
  18. package/dist/components/index.d.ts.map +0 -1
  19. package/dist/components/render.d.ts +0 -20
  20. package/dist/components/render.d.ts.map +0 -1
  21. package/dist/components/root.d.ts +0 -11
  22. package/dist/components/root.d.ts.map +0 -1
  23. package/dist/hooks/use-apps.d.ts.map +0 -1
  24. package/dist/hooks/use-current-screen.d.ts +0 -24
  25. package/dist/hooks/use-current-screen.d.ts.map +0 -1
  26. package/dist/index.d.ts.map +0 -1
  27. package/dist/node-store.d.ts +0 -17
  28. package/dist/node-store.d.ts.map +0 -1
  29. package/dist/primitives.d.ts.map +0 -1
  30. package/dist/remote-context.d.ts +0 -9
  31. package/dist/remote-context.d.ts.map +0 -1
  32. package/dist/remote-view.d.ts.map +0 -1
  33. package/dist/tailor-kit.d.ts +0 -117
  34. package/dist/tailor-kit.d.ts.map +0 -1
  35. package/src/__tests__/node-store.test.ts +0 -206
  36. package/src/__tests__/primitives.test.tsx +0 -85
  37. package/src/__tests__/tailor-kit.test.tsx +0 -424
  38. package/src/__tests__/tailor-kit.types.tsx +0 -151
  39. package/src/components/context.ts +0 -21
  40. package/src/components/index.ts +0 -1
  41. package/src/components/render.tsx +0 -116
  42. package/src/components/root.tsx +0 -37
  43. package/src/hooks/use-apps.ts +0 -47
  44. package/src/hooks/use-current-screen.ts +0 -81
  45. package/src/index.ts +0 -8
  46. package/src/node-store.ts +0 -131
  47. package/src/primitives.tsx +0 -261
  48. package/src/remote-context.ts +0 -11
  49. package/src/remote-view.tsx +0 -232
  50. package/src/tailor-kit.tsx +0 -501
@@ -1,232 +0,0 @@
1
- import {
2
- Component,
3
- Fragment,
4
- createElement,
5
- memo,
6
- useCallback,
7
- useContext,
8
- useEffect,
9
- useMemo,
10
- useRef,
11
- useState,
12
- useSyncExternalStore,
13
- } from "react";
14
- import type { ReactNode } from "react";
15
- import { createIframeUiHost } from "@tailorkit/sandbox/host";
16
- import type { HostToWorkerPayload, RemoteElementNode } from "@tailorkit/sandbox/protocol";
17
- import { NodeStore } from "./node-store";
18
- import { RemoteUIContext } from "./remote-context";
19
- import type { RemoteViewContext } from "./remote-context";
20
-
21
- const formatError = (error: Error): string => error.message;
22
-
23
- interface RemoteErrorBoundaryProps {
24
- children?: ReactNode;
25
- }
26
-
27
- interface RemoteErrorBoundaryState {
28
- error: Error | null;
29
- }
30
-
31
- class RemoteErrorBoundary extends Component<RemoteErrorBoundaryProps, RemoteErrorBoundaryState> {
32
- state: RemoteErrorBoundaryState = { error: null };
33
-
34
- static getDerivedStateFromError(error: Error): RemoteErrorBoundaryState {
35
- return { error };
36
- }
37
-
38
- static componentDidCatch(error: Error): void {
39
- console.error("TailorKit remote app failed", error);
40
- }
41
-
42
- render(): ReactNode {
43
- if (this.state.error) {
44
- return createElement("div", null, formatError(this.state.error));
45
- }
46
-
47
- return this.props.children;
48
- }
49
- }
50
-
51
- interface RemoteViewHostProps {
52
- appUrl: string | URL;
53
- components: Record<string, unknown>;
54
- createIframe?: () => HTMLIFrameElement;
55
- props?: Record<string, unknown>;
56
- runtimeUrl?: string | URL;
57
- }
58
-
59
- export function RemoteViewHost({
60
- appUrl,
61
- components,
62
- createIframe,
63
- props,
64
- runtimeUrl,
65
- }: RemoteViewHostProps): ReactNode {
66
- const appKey = appUrl.toString();
67
- const storeRef = useRef<NodeStore | null>(null);
68
- if (storeRef.current === null) {
69
- storeRef.current = new NodeStore();
70
- }
71
- const store = storeRef.current;
72
- const appKeyRef = useRef(appKey);
73
- if (appKeyRef.current !== appKey) {
74
- appKeyRef.current = appKey;
75
- store.clear();
76
- }
77
-
78
- const dispatchRef = useRef<((payload: HostToWorkerPayload) => void) | null>(null);
79
- const [error, setError] = useState<Error | null>(null);
80
- const [status, setStatus] = useState<"error" | "ready" | "starting">("starting");
81
-
82
- const ctxRef = useRef<RemoteViewContext>({
83
- components,
84
- dispatch: (payload) => dispatchRef.current?.(payload),
85
- store,
86
- });
87
-
88
- useEffect(() => {
89
- ctxRef.current.components = components;
90
- }, [components]);
91
-
92
- const ui = useMemo(() => {
93
- const ctx = ctxRef.current;
94
- return createElement(
95
- RemoteUIContext.Provider,
96
- { value: ctx },
97
- createElement(
98
- RemoteErrorBoundary,
99
- { key: appKey },
100
- createElement(RemoteRoot, { store: ctx.store }),
101
- ),
102
- );
103
- }, [appKey]);
104
-
105
- useEffect(() => {
106
- const host = createIframeUiHost(appUrl, {
107
- createIframe,
108
- onError: (error) => {
109
- console.error("TailorKit remote app failed", error);
110
- setError(error);
111
- setStatus("error");
112
- },
113
- props,
114
- runtimeUrl,
115
- });
116
-
117
- dispatchRef.current = (payload) => host.dispatch(payload);
118
-
119
- const unsubscribe = host.subscribe(() => {
120
- const tree = host.getSnapshot();
121
- if (tree !== null) {
122
- store.setSnapshot(tree);
123
- setStatus("ready");
124
- }
125
- });
126
-
127
- setStatus("starting");
128
- setError(null);
129
- host.mount();
130
-
131
- return () => {
132
- unsubscribe();
133
- dispatchRef.current = null;
134
- host.destroy();
135
- };
136
- }, [appUrl, createIframe, props, runtimeUrl, store]);
137
-
138
- if (status === "error" && error) {
139
- return createElement("div", null, formatError(error));
140
- }
141
-
142
- return ui;
143
- }
144
-
145
- interface RemoteRootProps {
146
- store: RemoteViewContext["store"];
147
- }
148
-
149
- function RemoteRoot({ store }: RemoteRootProps): ReactNode {
150
- const subscribe = useCallback((listener: () => void) => store.subscribeRoot(listener), [store]);
151
- const getSnapshot = useCallback(() => store.getRootId(), [store]);
152
-
153
- const rootId = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
154
- if (rootId === null) {
155
- return null;
156
- }
157
-
158
- return <RemoteView nodeId={rootId} />;
159
- }
160
-
161
- interface RemoteElementViewProps {
162
- ctx: RemoteViewContext;
163
- node: RemoteElementNode;
164
- }
165
-
166
- const RemoteElementView = memo(({ ctx, node }: RemoteElementViewProps): ReactNode => {
167
- const { dispatch, components } = ctx;
168
-
169
- const children = node.children.map((child) => <RemoteView key={child.id} nodeId={child.id} />);
170
-
171
- const component = components[node.type];
172
-
173
- if (component === undefined) {
174
- throw new Error(`TailorKit component "${node.type}" is not registered.`);
175
- }
176
-
177
- const props: Record<string, unknown> = { ...node.props };
178
-
179
- for (const binding of node.callbacks ?? []) {
180
- props[binding.callback] = (...args: unknown[]) => {
181
- dispatch({
182
- data: {
183
- args: args.slice(0, binding.inputCount),
184
- event: binding.event,
185
- nodeId: node.id,
186
- },
187
- type: "dispatchCallback",
188
- });
189
- };
190
- }
191
-
192
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
193
- return createElement(component as any, props, ...children);
194
- });
195
-
196
- interface RemoteViewProps {
197
- nodeId: string;
198
- }
199
-
200
- export const RemoteView = memo(function RemoteView({ nodeId }: RemoteViewProps): ReactNode {
201
- const ctx = useContext(RemoteUIContext);
202
- if (ctx === null) {
203
- return null;
204
- }
205
-
206
- const { store } = ctx;
207
-
208
- const subscribe = useCallback(
209
- (listener: () => void) => store.subscribe(nodeId, listener),
210
- [store, nodeId],
211
- );
212
- const getSnapshot = useCallback(() => store.getNode(nodeId), [store, nodeId]);
213
-
214
- const node = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
215
- if (node === null) {
216
- return null;
217
- }
218
-
219
- if (node.kind === "text") {
220
- return node.text as unknown as ReactNode;
221
- }
222
-
223
- const childElements = node.children.map((child) => (
224
- <RemoteView key={child.id} nodeId={child.id} />
225
- ));
226
-
227
- if (node.kind === "fragment") {
228
- return createElement(Fragment, { key: node.id }, ...childElements);
229
- }
230
-
231
- return <RemoteElementView node={node} ctx={ctx} />;
232
- });