@tailorkit/react 0.1.0-beta.1 → 0.1.0-beta.10
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/LICENSE.md +201 -0
- package/dist/components/app-view.d.ts +3 -0
- package/dist/components/context.d.ts +4 -7
- package/dist/components/index.d.ts +0 -1
- package/dist/components/render.d.ts +0 -1
- package/dist/components/root.d.ts +3 -5
- package/dist/hooks/use-apps.d.ts +4 -3
- package/dist/hooks/use-stable-context.d.ts +2 -0
- package/dist/hooks/use-view.d.ts +24 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +483 -418
- package/dist/node-store.d.ts +0 -1
- package/dist/primitives.d.ts +10 -19
- package/dist/remote-context.d.ts +2 -3
- package/dist/remote-view.d.ts +3 -4
- package/dist/store.d.ts +33 -0
- package/dist/tailor-kit.d.ts +58 -65
- package/dist/view-registry.d.ts +14 -0
- package/package.json +10 -20
- package/LICENSE +0 -674
- package/dist/components/context.d.ts.map +0 -1
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/render.d.ts.map +0 -1
- package/dist/components/root.d.ts.map +0 -1
- package/dist/hooks/use-apps.d.ts.map +0 -1
- package/dist/hooks/use-current-screen.d.ts +0 -24
- package/dist/hooks/use-current-screen.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/node-store.d.ts.map +0 -1
- package/dist/primitives.d.ts.map +0 -1
- package/dist/remote-context.d.ts.map +0 -1
- package/dist/remote-view.d.ts.map +0 -1
- package/dist/tailor-kit.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,80 +1,209 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import { useEffect as
|
|
3
|
-
|
|
4
|
-
// src/components/root.tsx
|
|
5
|
-
import { useMemo as useMemo2 } from "react";
|
|
1
|
+
// src/components/app-view.tsx
|
|
2
|
+
import { useEffect as useEffect2, useId as useId2, useMemo as useMemo3, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
3
|
+
import { isViewAncestor as isViewAncestor2 } from "@tailorkit/core/views";
|
|
6
4
|
|
|
7
|
-
// src/
|
|
8
|
-
import {
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
// src/view-registry.ts
|
|
6
|
+
import { getViewDepth, isViewAncestor } from "@tailorkit/core/views";
|
|
7
|
+
function createViewRegistry() {
|
|
8
|
+
const entries = /* @__PURE__ */ new Map();
|
|
9
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
10
|
+
let snapshot = null;
|
|
11
|
+
let nextOrder = 0;
|
|
12
|
+
let scheduled = false;
|
|
13
|
+
const publish = () => {
|
|
14
|
+
if (scheduled) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
scheduled = true;
|
|
18
|
+
queueMicrotask(() => {
|
|
19
|
+
scheduled = false;
|
|
20
|
+
const ordered = [...entries.values()].toSorted(
|
|
21
|
+
(a, b) => getViewDepth(b.view) - getViewDepth(a.view) || b.order - a.order
|
|
22
|
+
);
|
|
23
|
+
const selected = ordered[0];
|
|
24
|
+
if (selected) {
|
|
25
|
+
const peers = ordered.filter(
|
|
26
|
+
(entry) => getViewDepth(entry.view) === getViewDepth(selected.view)
|
|
27
|
+
);
|
|
28
|
+
if (peers.length > 1) {
|
|
29
|
+
console.warn(
|
|
30
|
+
`TailorKit found multiple active views at the same hierarchy depth: ${peers.toReversed().map((entry) => `"${entry.view}"`).join(
|
|
31
|
+
", "
|
|
32
|
+
)}. TailorKit selected "${selected.view}" by mount order. Only one route at a hierarchy depth should call useView.`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
snapshot = {
|
|
36
|
+
view: selected.view,
|
|
37
|
+
layers: ordered.filter((entry) => isViewAncestor(entry.view, selected.view)).toReversed().map((entry) => ({ path: entry.view, context: entry.context, status: entry.status }))
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
snapshot = null;
|
|
18
41
|
}
|
|
19
|
-
|
|
42
|
+
for (const listener of listeners) {
|
|
43
|
+
listener();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
getSnapshot: () => snapshot,
|
|
49
|
+
subscribe(listener) {
|
|
50
|
+
listeners.add(listener);
|
|
51
|
+
return () => {
|
|
52
|
+
listeners.delete(listener);
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
register(entry) {
|
|
56
|
+
entries.set(entry.id, { ...entry, order: entries.get(entry.id)?.order ?? nextOrder++ });
|
|
57
|
+
publish();
|
|
58
|
+
},
|
|
59
|
+
unregister(id) {
|
|
60
|
+
entries.delete(id);
|
|
61
|
+
publish();
|
|
20
62
|
}
|
|
21
|
-
|
|
22
|
-
}, [defaultTagName, props, render]);
|
|
63
|
+
};
|
|
23
64
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
65
|
+
|
|
66
|
+
// src/store.ts
|
|
67
|
+
function createTailorKitStore(baseUrlInput, initialApps, previewSessionId) {
|
|
68
|
+
const baseUrl = toBaseUrl(baseUrlInput);
|
|
69
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
70
|
+
let providedApps = initialApps;
|
|
71
|
+
let appsSnapshot = {
|
|
72
|
+
apps: initialApps ?? [],
|
|
73
|
+
error: null,
|
|
74
|
+
status: initialApps === void 0 ? "idle" : "ready"
|
|
75
|
+
};
|
|
76
|
+
let metaSnapshot = {
|
|
77
|
+
assetsBaseUrl: null,
|
|
78
|
+
error: null,
|
|
79
|
+
schema: null,
|
|
80
|
+
status: "idle"
|
|
81
|
+
};
|
|
82
|
+
let fetchAppsPromise = null;
|
|
83
|
+
let fetchMetaPromise = null;
|
|
84
|
+
let fetchAppsRequestId = 0;
|
|
85
|
+
const emit = () => {
|
|
86
|
+
for (const listener of listeners) {
|
|
87
|
+
listener();
|
|
29
88
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
89
|
+
};
|
|
90
|
+
const store = {
|
|
91
|
+
baseUrl,
|
|
92
|
+
views: createViewRegistry(),
|
|
93
|
+
setProvidedApps(apps) {
|
|
94
|
+
if (providedApps === apps) {
|
|
95
|
+
return;
|
|
33
96
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
97
|
+
providedApps = apps;
|
|
98
|
+
fetchAppsRequestId += 1;
|
|
99
|
+
fetchAppsPromise = null;
|
|
100
|
+
appsSnapshot = {
|
|
101
|
+
apps: apps ?? [],
|
|
102
|
+
error: null,
|
|
103
|
+
status: apps === void 0 ? "idle" : "ready"
|
|
104
|
+
};
|
|
105
|
+
emit();
|
|
106
|
+
if (apps === void 0) {
|
|
107
|
+
void store.fetchApps();
|
|
38
108
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
};
|
|
44
|
-
continue;
|
|
109
|
+
},
|
|
110
|
+
fetchApps: (options = {}) => {
|
|
111
|
+
if (providedApps !== void 0) {
|
|
112
|
+
return Promise.resolve();
|
|
45
113
|
}
|
|
46
|
-
if (
|
|
47
|
-
|
|
48
|
-
continue;
|
|
114
|
+
if (fetchAppsPromise && !options.force) {
|
|
115
|
+
return fetchAppsPromise;
|
|
49
116
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
continue;
|
|
117
|
+
appsSnapshot = { ...appsSnapshot, status: "loading" };
|
|
118
|
+
emit();
|
|
119
|
+
const requestId = ++fetchAppsRequestId;
|
|
120
|
+
const appsUrl = new URL("apps", baseUrl);
|
|
121
|
+
if (previewSessionId) {
|
|
122
|
+
appsUrl.searchParams.set("previewSessionId", previewSessionId);
|
|
59
123
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
124
|
+
fetchAppsPromise = fetch(appsUrl).then(async (response) => {
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
throw new Error(`Unable to fetch TailorKit apps from ${baseUrl.toString()}.`);
|
|
127
|
+
}
|
|
128
|
+
const apps = await response.json();
|
|
129
|
+
if (requestId !== fetchAppsRequestId) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
appsSnapshot = {
|
|
133
|
+
apps,
|
|
134
|
+
error: null,
|
|
135
|
+
status: "ready"
|
|
136
|
+
};
|
|
137
|
+
emit();
|
|
138
|
+
}).catch((error) => {
|
|
139
|
+
if (requestId !== fetchAppsRequestId) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
appsSnapshot = {
|
|
143
|
+
...appsSnapshot,
|
|
144
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
145
|
+
status: "error"
|
|
146
|
+
};
|
|
147
|
+
emit();
|
|
148
|
+
});
|
|
149
|
+
return fetchAppsPromise;
|
|
150
|
+
},
|
|
151
|
+
fetchMeta: () => {
|
|
152
|
+
if (fetchMetaPromise) {
|
|
153
|
+
return fetchMetaPromise;
|
|
72
154
|
}
|
|
155
|
+
metaSnapshot = { ...metaSnapshot, status: "loading" };
|
|
156
|
+
emit();
|
|
157
|
+
fetchMetaPromise = fetch(new URL("meta", baseUrl)).then(async (response) => {
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
throw new Error(`Unable to fetch TailorKit metadata from ${baseUrl.toString()}.`);
|
|
160
|
+
}
|
|
161
|
+
const meta = await response.json();
|
|
162
|
+
metaSnapshot = {
|
|
163
|
+
assetsBaseUrl: meta.assetsBaseUrl ?? null,
|
|
164
|
+
error: null,
|
|
165
|
+
schema: meta.schema,
|
|
166
|
+
status: "ready"
|
|
167
|
+
};
|
|
168
|
+
emit();
|
|
169
|
+
}).catch((error) => {
|
|
170
|
+
metaSnapshot = {
|
|
171
|
+
...metaSnapshot,
|
|
172
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
173
|
+
status: "error"
|
|
174
|
+
};
|
|
175
|
+
emit();
|
|
176
|
+
});
|
|
177
|
+
return fetchMetaPromise;
|
|
178
|
+
},
|
|
179
|
+
getAppsSnapshot: () => appsSnapshot,
|
|
180
|
+
getMetaSnapshot: () => metaSnapshot,
|
|
181
|
+
subscribe: (listener) => {
|
|
182
|
+
listeners.add(listener);
|
|
183
|
+
return () => {
|
|
184
|
+
listeners.delete(listener);
|
|
185
|
+
};
|
|
73
186
|
}
|
|
74
187
|
};
|
|
188
|
+
return store;
|
|
75
189
|
}
|
|
76
|
-
function
|
|
77
|
-
|
|
190
|
+
function toBaseUrl(value) {
|
|
191
|
+
const url = value instanceof URL ? new URL(value) : new URL(value);
|
|
192
|
+
if (!url.pathname.endsWith("/")) {
|
|
193
|
+
url.pathname = `${url.pathname}/`;
|
|
194
|
+
}
|
|
195
|
+
return url;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// src/hooks/use-stable-context.ts
|
|
199
|
+
import { useRef } from "react";
|
|
200
|
+
function useStableContext(value) {
|
|
201
|
+
const key = JSON.stringify(value);
|
|
202
|
+
const ref = useRef({ key, value });
|
|
203
|
+
if (ref.current.key !== key) {
|
|
204
|
+
ref.current = { key, value };
|
|
205
|
+
}
|
|
206
|
+
return ref.current.value;
|
|
78
207
|
}
|
|
79
208
|
|
|
80
209
|
// src/components/context.ts
|
|
@@ -83,95 +212,15 @@ var TailorRootContext = createContext(null);
|
|
|
83
212
|
function useTailorRootContext(component) {
|
|
84
213
|
const context = useContext(TailorRootContext);
|
|
85
214
|
if (!context) {
|
|
86
|
-
throw new Error(`${component} must be rendered inside
|
|
215
|
+
throw new Error(`${component} must be rendered inside Root.`);
|
|
87
216
|
}
|
|
88
217
|
return context;
|
|
89
218
|
}
|
|
90
219
|
|
|
91
|
-
// src/components/root.tsx
|
|
92
|
-
import { jsx } from "react/jsx-runtime";
|
|
93
|
-
var EMPTY_APPS = [];
|
|
94
|
-
function Root({ apps: appsProp, children, render, tailor, ...props }) {
|
|
95
|
-
const appsResult = tailor.useApps();
|
|
96
|
-
const apps = appsProp ?? appsResult.data ?? EMPTY_APPS;
|
|
97
|
-
const context = useMemo2(
|
|
98
|
-
() => ({
|
|
99
|
-
apps
|
|
100
|
-
}),
|
|
101
|
-
[apps]
|
|
102
|
-
);
|
|
103
|
-
const element = render ? useRender({
|
|
104
|
-
defaultTagName: "div",
|
|
105
|
-
props: mergeProps({ children }, props),
|
|
106
|
-
render
|
|
107
|
-
}) : children;
|
|
108
|
-
return /* @__PURE__ */ jsx(TailorRootContext.Provider, { value: context, children: element });
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// src/hooks/use-apps.ts
|
|
112
|
-
import { useCallback, useEffect, useSyncExternalStore } from "react";
|
|
113
|
-
function createUseApps(store) {
|
|
114
|
-
return function useApps() {
|
|
115
|
-
const snapshot = useSyncExternalStore(
|
|
116
|
-
store.subscribe,
|
|
117
|
-
store.getAppsSnapshot,
|
|
118
|
-
store.getAppsSnapshot
|
|
119
|
-
);
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
void store.fetchApps();
|
|
122
|
-
}, []);
|
|
123
|
-
const refetch = useCallback(() => store.fetchApps({ force: true }), []);
|
|
124
|
-
return toUseAppsResult(snapshot, refetch);
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
function toUseAppsResult(snapshot, refetch) {
|
|
128
|
-
return {
|
|
129
|
-
data: snapshot.status === "ready" ? snapshot.apps : void 0,
|
|
130
|
-
error: snapshot.error,
|
|
131
|
-
isError: snapshot.status === "error",
|
|
132
|
-
isLoading: snapshot.status === "loading",
|
|
133
|
-
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
134
|
-
isSuccess: snapshot.status === "ready",
|
|
135
|
-
refetch,
|
|
136
|
-
status: snapshot.status
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// src/hooks/use-current-screen.ts
|
|
141
|
-
import { useEffect as useEffect2, useMemo as useMemo3, useRef } from "react";
|
|
142
|
-
function createUseCurrentScreen(store) {
|
|
143
|
-
return function useCurrentScreen(options) {
|
|
144
|
-
useTailorRootContext("tailor.useCurrentScreen");
|
|
145
|
-
const id = useMemo3(() => /* @__PURE__ */ Symbol("tailorkit-current-screen"), []);
|
|
146
|
-
const status = options.status ?? "ready";
|
|
147
|
-
const context = "context" in options ? options.context : void 0;
|
|
148
|
-
const contextKey = JSON.stringify(context);
|
|
149
|
-
const contextRef = useRef({ key: contextKey, value: context });
|
|
150
|
-
if (contextRef.current.key !== contextKey) {
|
|
151
|
-
contextRef.current = { key: contextKey, value: context };
|
|
152
|
-
}
|
|
153
|
-
const contextSnapshot = contextRef.current.value;
|
|
154
|
-
useEffect2(
|
|
155
|
-
() => () => {
|
|
156
|
-
store.unregisterScreen(id);
|
|
157
|
-
},
|
|
158
|
-
[id]
|
|
159
|
-
);
|
|
160
|
-
useEffect2(() => {
|
|
161
|
-
store.registerScreen({
|
|
162
|
-
context: contextSnapshot,
|
|
163
|
-
id,
|
|
164
|
-
screen: options.screen,
|
|
165
|
-
status
|
|
166
|
-
});
|
|
167
|
-
}, [contextSnapshot, id, options.screen, status]);
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
220
|
// src/primitives.tsx
|
|
172
|
-
import { createContext as createContext2, useContext as useContext2, useId, useMemo
|
|
221
|
+
import { createContext as createContext2, useContext as useContext2, useId, useMemo } from "react";
|
|
173
222
|
import { resolveTheme } from "@tailorkit/core/primitives/theme";
|
|
174
|
-
import { jsx
|
|
223
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
175
224
|
var PrimitiveThemeContext = createContext2(null);
|
|
176
225
|
var tokenGroups = [
|
|
177
226
|
"space",
|
|
@@ -292,10 +341,10 @@ var buildPrimitiveCss = ({
|
|
|
292
341
|
display,
|
|
293
342
|
nodeId,
|
|
294
343
|
props,
|
|
295
|
-
|
|
344
|
+
viewId,
|
|
296
345
|
theme
|
|
297
346
|
}) => {
|
|
298
|
-
const selector = `[data-tailorkit-
|
|
347
|
+
const selector = `[data-tailorkit-view="${cssEscape(viewId)}"] [data-tailorkit-node="${cssEscape(
|
|
299
348
|
nodeId
|
|
300
349
|
)}"]`;
|
|
301
350
|
const base = [`display: ${display};`];
|
|
@@ -323,8 +372,8 @@ var buildPrimitiveCss = ({
|
|
|
323
372
|
}
|
|
324
373
|
return rules.join("\n");
|
|
325
374
|
};
|
|
326
|
-
var buildThemeCss = (
|
|
327
|
-
const selector = `[data-tailorkit-
|
|
375
|
+
var buildThemeCss = (viewId, theme) => {
|
|
376
|
+
const selector = `[data-tailorkit-view="${cssEscape(viewId)}"]`;
|
|
328
377
|
const declarations = [];
|
|
329
378
|
const resolvedTheme = resolveTheme(theme);
|
|
330
379
|
for (const group of tokenGroups) {
|
|
@@ -336,7 +385,7 @@ var buildThemeCss = (screenId, theme) => {
|
|
|
336
385
|
};
|
|
337
386
|
var usePrimitiveNodeId = () => {
|
|
338
387
|
const id = useId();
|
|
339
|
-
return
|
|
388
|
+
return useMemo(() => `tailorkit-${id.replaceAll(":", "")}`, [id]);
|
|
340
389
|
};
|
|
341
390
|
var Primitive = ({
|
|
342
391
|
children,
|
|
@@ -351,34 +400,34 @@ var Primitive = ({
|
|
|
351
400
|
display,
|
|
352
401
|
nodeId,
|
|
353
402
|
props,
|
|
354
|
-
|
|
403
|
+
viewId: context.viewId,
|
|
355
404
|
theme: context.theme
|
|
356
405
|
}) : "";
|
|
357
406
|
return /* @__PURE__ */ jsxs(Element, { "data-tailorkit-node": nodeId, children: [
|
|
358
|
-
css === "" ? null : /* @__PURE__ */
|
|
407
|
+
css === "" ? null : /* @__PURE__ */ jsx("style", { "data-tailorkit-node-style": nodeId, children: css }),
|
|
359
408
|
children
|
|
360
409
|
] });
|
|
361
410
|
};
|
|
362
411
|
var primitives = {
|
|
363
|
-
Box: ({ props,
|
|
364
|
-
Flex: ({ props,
|
|
365
|
-
Grid: ({ props,
|
|
366
|
-
Inline: ({ props,
|
|
412
|
+
Box: ({ props, children }) => /* @__PURE__ */ jsx(Primitive, { display: "block", element: "div", props, children }),
|
|
413
|
+
Flex: ({ props, children }) => /* @__PURE__ */ jsx(Primitive, { display: "flex", element: "div", props, children }),
|
|
414
|
+
Grid: ({ props, children }) => /* @__PURE__ */ jsx(Primitive, { display: "grid", element: "div", props, children }),
|
|
415
|
+
Inline: ({ props, children }) => /* @__PURE__ */ jsx(Primitive, { display: "inline", element: "span", props, children })
|
|
367
416
|
};
|
|
368
417
|
|
|
369
418
|
// src/remote-view.tsx
|
|
370
419
|
import {
|
|
371
420
|
Component,
|
|
372
421
|
Fragment,
|
|
373
|
-
createElement
|
|
422
|
+
createElement,
|
|
374
423
|
memo,
|
|
375
|
-
useCallback
|
|
424
|
+
useCallback,
|
|
376
425
|
useContext as useContext3,
|
|
377
|
-
useEffect
|
|
378
|
-
useMemo as
|
|
426
|
+
useEffect,
|
|
427
|
+
useMemo as useMemo2,
|
|
379
428
|
useRef as useRef2,
|
|
380
429
|
useState,
|
|
381
|
-
useSyncExternalStore
|
|
430
|
+
useSyncExternalStore
|
|
382
431
|
} from "react";
|
|
383
432
|
import { createIframeUiHost } from "@tailorkit/sandbox/host";
|
|
384
433
|
|
|
@@ -494,7 +543,7 @@ import { createContext as createContext3 } from "react";
|
|
|
494
543
|
var RemoteUIContext = createContext3(null);
|
|
495
544
|
|
|
496
545
|
// src/remote-view.tsx
|
|
497
|
-
import { jsx as
|
|
546
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
498
547
|
var formatError = (error) => error.message;
|
|
499
548
|
var RemoteErrorBoundary = class extends Component {
|
|
500
549
|
state = { error: null };
|
|
@@ -506,7 +555,7 @@ var RemoteErrorBoundary = class extends Component {
|
|
|
506
555
|
}
|
|
507
556
|
render() {
|
|
508
557
|
if (this.state.error) {
|
|
509
|
-
return
|
|
558
|
+
return createElement("div", null, formatError(this.state.error));
|
|
510
559
|
}
|
|
511
560
|
return this.props.children;
|
|
512
561
|
}
|
|
@@ -515,8 +564,7 @@ function RemoteViewHost({
|
|
|
515
564
|
appUrl,
|
|
516
565
|
components: components2,
|
|
517
566
|
createIframe,
|
|
518
|
-
props
|
|
519
|
-
runtimeUrl
|
|
567
|
+
props
|
|
520
568
|
}) {
|
|
521
569
|
const appKey = appUrl.toString();
|
|
522
570
|
const storeRef = useRef2(null);
|
|
@@ -529,6 +577,12 @@ function RemoteViewHost({
|
|
|
529
577
|
appKeyRef.current = appKey;
|
|
530
578
|
store.clear();
|
|
531
579
|
}
|
|
580
|
+
const hostRef = useRef2(null);
|
|
581
|
+
const propsRef = useRef2(props);
|
|
582
|
+
useEffect(() => {
|
|
583
|
+
propsRef.current = props;
|
|
584
|
+
hostRef.current?.setProps(props);
|
|
585
|
+
}, [props]);
|
|
532
586
|
const dispatchRef = useRef2(null);
|
|
533
587
|
const [error, setError] = useState(null);
|
|
534
588
|
const [status, setStatus] = useState("starting");
|
|
@@ -537,22 +591,22 @@ function RemoteViewHost({
|
|
|
537
591
|
dispatch: (payload) => dispatchRef.current?.(payload),
|
|
538
592
|
store
|
|
539
593
|
});
|
|
540
|
-
|
|
594
|
+
useEffect(() => {
|
|
541
595
|
ctxRef.current.components = components2;
|
|
542
596
|
}, [components2]);
|
|
543
|
-
const ui =
|
|
597
|
+
const ui = useMemo2(() => {
|
|
544
598
|
const ctx = ctxRef.current;
|
|
545
|
-
return
|
|
599
|
+
return createElement(
|
|
546
600
|
RemoteUIContext.Provider,
|
|
547
601
|
{ value: ctx },
|
|
548
|
-
|
|
602
|
+
createElement(
|
|
549
603
|
RemoteErrorBoundary,
|
|
550
604
|
{ key: appKey },
|
|
551
|
-
|
|
605
|
+
createElement(RemoteRoot, { store: ctx.store })
|
|
552
606
|
)
|
|
553
607
|
);
|
|
554
608
|
}, [appKey]);
|
|
555
|
-
|
|
609
|
+
useEffect(() => {
|
|
556
610
|
const host = createIframeUiHost(appUrl, {
|
|
557
611
|
createIframe,
|
|
558
612
|
onError: (error2) => {
|
|
@@ -560,9 +614,9 @@ function RemoteViewHost({
|
|
|
560
614
|
setError(error2);
|
|
561
615
|
setStatus("error");
|
|
562
616
|
},
|
|
563
|
-
props
|
|
564
|
-
runtimeUrl
|
|
617
|
+
props: propsRef.current
|
|
565
618
|
});
|
|
619
|
+
hostRef.current = host;
|
|
566
620
|
dispatchRef.current = (payload) => host.dispatch(payload);
|
|
567
621
|
const unsubscribe = host.subscribe(() => {
|
|
568
622
|
const tree = host.getSnapshot();
|
|
@@ -577,26 +631,27 @@ function RemoteViewHost({
|
|
|
577
631
|
return () => {
|
|
578
632
|
unsubscribe();
|
|
579
633
|
dispatchRef.current = null;
|
|
634
|
+
hostRef.current = null;
|
|
580
635
|
host.destroy();
|
|
581
636
|
};
|
|
582
|
-
}, [appUrl, createIframe,
|
|
637
|
+
}, [appUrl, createIframe, store]);
|
|
583
638
|
if (status === "error" && error) {
|
|
584
|
-
return
|
|
639
|
+
return createElement("div", null, formatError(error));
|
|
585
640
|
}
|
|
586
641
|
return ui;
|
|
587
642
|
}
|
|
588
643
|
function RemoteRoot({ store }) {
|
|
589
|
-
const subscribe =
|
|
590
|
-
const getSnapshot =
|
|
591
|
-
const rootId =
|
|
644
|
+
const subscribe = useCallback((listener) => store.subscribeRoot(listener), [store]);
|
|
645
|
+
const getSnapshot = useCallback(() => store.getRootId(), [store]);
|
|
646
|
+
const rootId = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
592
647
|
if (rootId === null) {
|
|
593
648
|
return null;
|
|
594
649
|
}
|
|
595
|
-
return /* @__PURE__ */
|
|
650
|
+
return /* @__PURE__ */ jsx2(RemoteView, { nodeId: rootId });
|
|
596
651
|
}
|
|
597
652
|
var RemoteElementView = memo(({ ctx, node }) => {
|
|
598
653
|
const { dispatch, components: components2 } = ctx;
|
|
599
|
-
const children = node.children.map((child) => /* @__PURE__ */
|
|
654
|
+
const children = node.children.map((child) => /* @__PURE__ */ jsx2(RemoteView, { nodeId: child.id }, child.id));
|
|
600
655
|
const component = components2[node.type];
|
|
601
656
|
if (component === void 0) {
|
|
602
657
|
throw new Error(`TailorKit component "${node.type}" is not registered.`);
|
|
@@ -614,35 +669,118 @@ var RemoteElementView = memo(({ ctx, node }) => {
|
|
|
614
669
|
});
|
|
615
670
|
};
|
|
616
671
|
}
|
|
617
|
-
return
|
|
672
|
+
return createElement(component, props, ...children);
|
|
618
673
|
});
|
|
619
|
-
|
|
674
|
+
function RemoteViewComponent({ nodeId }) {
|
|
620
675
|
const ctx = useContext3(RemoteUIContext);
|
|
621
676
|
if (ctx === null) {
|
|
622
677
|
return null;
|
|
623
678
|
}
|
|
624
679
|
const { store } = ctx;
|
|
625
|
-
const subscribe =
|
|
680
|
+
const subscribe = useCallback(
|
|
626
681
|
(listener) => store.subscribe(nodeId, listener),
|
|
627
682
|
[store, nodeId]
|
|
628
683
|
);
|
|
629
|
-
const getSnapshot =
|
|
630
|
-
const node =
|
|
684
|
+
const getSnapshot = useCallback(() => store.getNode(nodeId), [store, nodeId]);
|
|
685
|
+
const node = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
631
686
|
if (node === null) {
|
|
632
687
|
return null;
|
|
633
688
|
}
|
|
634
689
|
if (node.kind === "text") {
|
|
635
690
|
return node.text;
|
|
636
691
|
}
|
|
637
|
-
const childElements = node.children.map((child) => /* @__PURE__ */
|
|
692
|
+
const childElements = node.children.map((child) => /* @__PURE__ */ jsx2(RemoteView, { nodeId: child.id }, child.id));
|
|
638
693
|
if (node.kind === "fragment") {
|
|
639
|
-
return
|
|
694
|
+
return createElement(Fragment, { key: node.id }, ...childElements);
|
|
640
695
|
}
|
|
641
|
-
return /* @__PURE__ */
|
|
642
|
-
}
|
|
696
|
+
return /* @__PURE__ */ jsx2(RemoteElementView, { node, ctx });
|
|
697
|
+
}
|
|
698
|
+
var RemoteView = memo(RemoteViewComponent);
|
|
699
|
+
|
|
700
|
+
// src/components/app-view.tsx
|
|
701
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
702
|
+
var AppView = ({
|
|
703
|
+
app,
|
|
704
|
+
slot,
|
|
705
|
+
createIframe,
|
|
706
|
+
fallback = null,
|
|
707
|
+
...viewProps
|
|
708
|
+
}) => {
|
|
709
|
+
const { store, client } = useTailorRootContext("AppView");
|
|
710
|
+
const { theme, components: wrappedComponents } = client;
|
|
711
|
+
const reactId = useId2();
|
|
712
|
+
const currentView = useSyncExternalStore2(
|
|
713
|
+
store.views.subscribe,
|
|
714
|
+
store.views.getSnapshot,
|
|
715
|
+
store.views.getSnapshot
|
|
716
|
+
);
|
|
717
|
+
const view = viewProps.view;
|
|
718
|
+
const suppliedContext = viewProps.context;
|
|
719
|
+
const context = useStableContext(suppliedContext);
|
|
720
|
+
const status = viewProps.status ?? "ready";
|
|
721
|
+
const props = useMemo3(() => {
|
|
722
|
+
if (view !== void 0) {
|
|
723
|
+
return {
|
|
724
|
+
slot,
|
|
725
|
+
view,
|
|
726
|
+
layers: [
|
|
727
|
+
...(currentView?.layers ?? []).filter(
|
|
728
|
+
(layer) => layer.path !== view && isViewAncestor2(layer.path, view)
|
|
729
|
+
),
|
|
730
|
+
{ path: view, context, status }
|
|
731
|
+
]
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
return currentView === null ? void 0 : { slot, ...currentView };
|
|
735
|
+
}, [context, currentView, view, status, slot]);
|
|
736
|
+
const meta = useSyncExternalStore2(store.subscribe, store.getMetaSnapshot, store.getMetaSnapshot);
|
|
737
|
+
const runtimeProps = useMemo3(
|
|
738
|
+
() => props === void 0 ? void 0 : {
|
|
739
|
+
...props,
|
|
740
|
+
declaredViews: Object.keys(meta.schema?.views ?? {}),
|
|
741
|
+
supportedViews: meta.schema?.slots[slot]?.views ?? []
|
|
742
|
+
},
|
|
743
|
+
[props, meta.schema, slot]
|
|
744
|
+
);
|
|
745
|
+
const assetsBaseUrl = app.clientPath ? null : meta.assetsBaseUrl;
|
|
746
|
+
const appUrl = useMemo3(
|
|
747
|
+
() => resolveAppUrl(app, store.baseUrl, assetsBaseUrl),
|
|
748
|
+
[app, assetsBaseUrl, store.baseUrl]
|
|
749
|
+
);
|
|
750
|
+
useEffect2(() => {
|
|
751
|
+
void store.fetchMeta();
|
|
752
|
+
}, [store]);
|
|
753
|
+
if (props === void 0 || appUrl === null || meta.schema === null) {
|
|
754
|
+
return fallback;
|
|
755
|
+
}
|
|
756
|
+
const viewId = `tailorkit-view-${reactId.replaceAll(":", "")}`;
|
|
757
|
+
return /* @__PURE__ */ jsx3(PrimitiveThemeContext.Provider, { value: { viewId, theme }, children: /* @__PURE__ */ jsxs2("div", { "data-tailorkit-view": viewId, children: [
|
|
758
|
+
/* @__PURE__ */ jsx3("style", { "data-tailorkit-theme-style": viewId, children: buildThemeCss(viewId, theme) }),
|
|
759
|
+
/* @__PURE__ */ jsx3(
|
|
760
|
+
RemoteViewHost,
|
|
761
|
+
{
|
|
762
|
+
appUrl: appUrl.toString(),
|
|
763
|
+
components: wrappedComponents,
|
|
764
|
+
createIframe,
|
|
765
|
+
props: runtimeProps
|
|
766
|
+
}
|
|
767
|
+
)
|
|
768
|
+
] }) });
|
|
769
|
+
};
|
|
770
|
+
function resolveAppUrl(app, baseUrl, assetsBaseUrl) {
|
|
771
|
+
if (app.clientPath) {
|
|
772
|
+
return new URL(app.clientPath, baseUrl);
|
|
773
|
+
}
|
|
774
|
+
if (!assetsBaseUrl || !app.projectId || !app.currentDeployment?.id) {
|
|
775
|
+
return null;
|
|
776
|
+
}
|
|
777
|
+
return new URL(
|
|
778
|
+
`projects/${app.projectId}/apps/${app.id}/deployments/${app.currentDeployment.id}/files/client.js`,
|
|
779
|
+
toBaseUrl(assetsBaseUrl)
|
|
780
|
+
);
|
|
781
|
+
}
|
|
643
782
|
|
|
644
783
|
// src/tailor-kit.tsx
|
|
645
|
-
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
646
784
|
var componentTagPrefix = "tailorkit-";
|
|
647
785
|
var toComponentTagName = (name) => `${componentTagPrefix}${name.replaceAll(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[\s_]+/gu, "-").toLowerCase()}`;
|
|
648
786
|
function components(_schema, customComponents) {
|
|
@@ -653,7 +791,6 @@ function createTailorKitClient(options) {
|
|
|
653
791
|
}
|
|
654
792
|
function createReactTailorKitClient(options) {
|
|
655
793
|
const wrappedComponents = {};
|
|
656
|
-
const store = createTailorKitStore(options.baseUrl);
|
|
657
794
|
const theme = options.theme ?? {};
|
|
658
795
|
for (const [name, renderer] of Object.entries(options.components ?? {})) {
|
|
659
796
|
if (renderer) {
|
|
@@ -663,258 +800,186 @@ function createReactTailorKitClient(options) {
|
|
|
663
800
|
}) {
|
|
664
801
|
return renderer({
|
|
665
802
|
props,
|
|
666
|
-
|
|
803
|
+
children
|
|
667
804
|
});
|
|
668
805
|
};
|
|
669
806
|
wrappedComponents[name] = TailorKitComponent;
|
|
670
807
|
wrappedComponents[toComponentTagName(name)] = TailorKitComponent;
|
|
671
808
|
}
|
|
672
809
|
}
|
|
673
|
-
const useApps = createUseApps(store);
|
|
674
|
-
const useCurrentScreen = createUseCurrentScreen(store);
|
|
675
|
-
const AppView = ({
|
|
676
|
-
app,
|
|
677
|
-
createIframe,
|
|
678
|
-
fallback = null,
|
|
679
|
-
runtimeUrl,
|
|
680
|
-
...screenProps
|
|
681
|
-
}) => {
|
|
682
|
-
const reactId = useId2();
|
|
683
|
-
const currentScreen = useSyncExternalStore3(
|
|
684
|
-
store.subscribe,
|
|
685
|
-
store.getCurrentScreen,
|
|
686
|
-
store.getCurrentScreen
|
|
687
|
-
);
|
|
688
|
-
const screen = screenProps.screen;
|
|
689
|
-
const context = screenProps.context;
|
|
690
|
-
const status = screenProps.status ?? "ready";
|
|
691
|
-
const props = useMemo6(() => {
|
|
692
|
-
if (screen !== void 0) {
|
|
693
|
-
return {
|
|
694
|
-
screen: {
|
|
695
|
-
context,
|
|
696
|
-
path: screen,
|
|
697
|
-
status
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
}
|
|
701
|
-
return currentScreen === null ? void 0 : {
|
|
702
|
-
screen: {
|
|
703
|
-
context: currentScreen.context,
|
|
704
|
-
path: currentScreen.screen,
|
|
705
|
-
status: currentScreen.status
|
|
706
|
-
}
|
|
707
|
-
};
|
|
708
|
-
}, [context, currentScreen, screen, status]);
|
|
709
|
-
const meta = useSyncExternalStore3(
|
|
710
|
-
store.subscribe,
|
|
711
|
-
store.getMetaSnapshot,
|
|
712
|
-
store.getMetaSnapshot
|
|
713
|
-
);
|
|
714
|
-
const assetsBaseUrl = app.clientPath ? null : meta.assetsBaseUrl;
|
|
715
|
-
const appUrl = useMemo6(
|
|
716
|
-
() => resolveAppUrl(app, store.baseUrl, assetsBaseUrl),
|
|
717
|
-
[app, assetsBaseUrl]
|
|
718
|
-
);
|
|
719
|
-
useEffect4(() => {
|
|
720
|
-
void store.fetchMeta();
|
|
721
|
-
}, []);
|
|
722
|
-
if (props === void 0 || appUrl === null) {
|
|
723
|
-
return fallback;
|
|
724
|
-
}
|
|
725
|
-
const screenId = `tailorkit-screen-${reactId.replaceAll(":", "")}`;
|
|
726
|
-
return /* @__PURE__ */ jsx4(PrimitiveThemeContext.Provider, { value: { screenId, theme }, children: /* @__PURE__ */ jsxs2("div", { "data-tailorkit-screen": screenId, children: [
|
|
727
|
-
/* @__PURE__ */ jsx4("style", { "data-tailorkit-theme-style": screenId, children: buildThemeCss(screenId, theme) }),
|
|
728
|
-
/* @__PURE__ */ jsx4(
|
|
729
|
-
RemoteViewHost,
|
|
730
|
-
{
|
|
731
|
-
appUrl,
|
|
732
|
-
components: wrappedComponents,
|
|
733
|
-
createIframe,
|
|
734
|
-
props,
|
|
735
|
-
runtimeUrl
|
|
736
|
-
}
|
|
737
|
-
)
|
|
738
|
-
] }) });
|
|
739
|
-
};
|
|
740
|
-
const client = {
|
|
741
|
-
AppView,
|
|
742
|
-
Root: (props) => /* @__PURE__ */ jsx4(Root, { ...props, tailor: client }),
|
|
743
|
-
getApp: store.getApp,
|
|
744
|
-
getApps: store.getApps,
|
|
745
|
-
useApps,
|
|
746
|
-
useCurrentScreen
|
|
747
|
-
};
|
|
748
810
|
return {
|
|
749
|
-
|
|
811
|
+
baseUrl: options.baseUrl,
|
|
812
|
+
components: wrappedComponents,
|
|
813
|
+
previewSessionId: options.previewSessionId,
|
|
814
|
+
theme
|
|
750
815
|
};
|
|
751
816
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
let currentScreen = null;
|
|
768
|
-
let fetchAppsPromise = null;
|
|
769
|
-
let fetchMetaPromise = null;
|
|
770
|
-
let fetchAppsRequestId = 0;
|
|
771
|
-
let nextOrder = 0;
|
|
772
|
-
const emit = () => {
|
|
773
|
-
for (const listener of listeners) {
|
|
774
|
-
listener();
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
const selectCurrentScreen = () => {
|
|
778
|
-
let selected = null;
|
|
779
|
-
for (const screen of screens.values()) {
|
|
780
|
-
const depth = getScreenDepth(screen.screen);
|
|
781
|
-
const selectedDepth = selected === null ? -1 : getScreenDepth(selected.screen);
|
|
782
|
-
if (selected === null || depth > selectedDepth) {
|
|
783
|
-
selected = screen;
|
|
784
|
-
}
|
|
785
|
-
if (selected !== null && depth === selectedDepth && screen.order > selected.order) {
|
|
786
|
-
selected = screen;
|
|
817
|
+
|
|
818
|
+
// src/components/root.tsx
|
|
819
|
+
import { useEffect as useEffect3, useMemo as useMemo5, useState as useState2 } from "react";
|
|
820
|
+
|
|
821
|
+
// src/components/render.tsx
|
|
822
|
+
import { cloneElement, createElement as createElement2, isValidElement, useMemo as useMemo4 } from "react";
|
|
823
|
+
function useRender({
|
|
824
|
+
defaultTagName,
|
|
825
|
+
props,
|
|
826
|
+
render
|
|
827
|
+
}) {
|
|
828
|
+
return useMemo4(() => {
|
|
829
|
+
if (render) {
|
|
830
|
+
if (!isValidElement(render)) {
|
|
831
|
+
throw new Error("The render prop must be a valid React element.");
|
|
787
832
|
}
|
|
833
|
+
return cloneElement(render, mergeProps(render.props, props));
|
|
788
834
|
}
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
835
|
+
return createElement2(defaultTagName, props);
|
|
836
|
+
}, [defaultTagName, props, render]);
|
|
837
|
+
}
|
|
838
|
+
function mergeProps(...propSets) {
|
|
839
|
+
const merged = {};
|
|
840
|
+
for (const props of propSets) {
|
|
841
|
+
if (!props) {
|
|
842
|
+
continue;
|
|
797
843
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
baseUrl,
|
|
802
|
-
fetchApps: (options = {}) => {
|
|
803
|
-
if (fetchAppsPromise && !options.force) {
|
|
804
|
-
return fetchAppsPromise;
|
|
844
|
+
for (const [key, value] of Object.entries(props)) {
|
|
845
|
+
if (value === void 0) {
|
|
846
|
+
continue;
|
|
805
847
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
if (!response.ok) {
|
|
811
|
-
throw new Error(`Unable to fetch TailorKit apps from ${baseUrl.toString()}.`);
|
|
812
|
-
}
|
|
813
|
-
const apps = await response.json();
|
|
814
|
-
if (requestId !== fetchAppsRequestId) {
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
appsSnapshot = {
|
|
818
|
-
apps,
|
|
819
|
-
error: null,
|
|
820
|
-
status: "ready"
|
|
821
|
-
};
|
|
822
|
-
emit();
|
|
823
|
-
}).catch((error) => {
|
|
824
|
-
if (requestId !== fetchAppsRequestId) {
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
|
-
appsSnapshot = {
|
|
828
|
-
...appsSnapshot,
|
|
829
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
830
|
-
status: "error"
|
|
831
|
-
};
|
|
832
|
-
emit();
|
|
833
|
-
});
|
|
834
|
-
return fetchAppsPromise;
|
|
835
|
-
},
|
|
836
|
-
fetchMeta: () => {
|
|
837
|
-
if (fetchMetaPromise) {
|
|
838
|
-
return fetchMetaPromise;
|
|
848
|
+
const existing = merged[key];
|
|
849
|
+
if (key === "className" && existing && value) {
|
|
850
|
+
merged[key] = `${existing} ${value}`;
|
|
851
|
+
continue;
|
|
839
852
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
throw new Error(`Unable to fetch TailorKit metadata from ${baseUrl.toString()}.`);
|
|
845
|
-
}
|
|
846
|
-
const meta = await response.json();
|
|
847
|
-
metaSnapshot = {
|
|
848
|
-
assetsBaseUrl: meta.assetsBaseUrl ?? null,
|
|
849
|
-
error: null,
|
|
850
|
-
schema: meta.schema,
|
|
851
|
-
status: "ready"
|
|
853
|
+
if (key === "style" && existing && value) {
|
|
854
|
+
merged[key] = {
|
|
855
|
+
...existing,
|
|
856
|
+
...value
|
|
852
857
|
};
|
|
853
|
-
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
if (key === "ref" && existing && value) {
|
|
861
|
+
merged[key] = composeRefs(existing, value);
|
|
862
|
+
continue;
|
|
863
|
+
}
|
|
864
|
+
if (isEventHandler(key) && typeof existing === "function" && typeof value === "function") {
|
|
865
|
+
merged[key] = (...args) => {
|
|
866
|
+
existing(...args);
|
|
867
|
+
const event = args[0];
|
|
868
|
+
if (!event?.defaultPrevented) {
|
|
869
|
+
value(...args);
|
|
870
|
+
}
|
|
859
871
|
};
|
|
860
|
-
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
});
|
|
875
|
-
if (!existing) {
|
|
876
|
-
nextOrder += 1;
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
merged[key] = value;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
return merged;
|
|
878
|
+
}
|
|
879
|
+
function composeRefs(...refs) {
|
|
880
|
+
return (node) => {
|
|
881
|
+
for (const ref of refs) {
|
|
882
|
+
if (typeof ref === "function") {
|
|
883
|
+
ref(node);
|
|
884
|
+
} else if (ref) {
|
|
885
|
+
ref.current = node;
|
|
877
886
|
}
|
|
878
|
-
selectCurrentScreen();
|
|
879
|
-
emit();
|
|
880
|
-
},
|
|
881
|
-
subscribe: (listener) => {
|
|
882
|
-
listeners.add(listener);
|
|
883
|
-
return () => {
|
|
884
|
-
listeners.delete(listener);
|
|
885
|
-
};
|
|
886
|
-
},
|
|
887
|
-
unregisterScreen: (id) => {
|
|
888
|
-
screens.delete(id);
|
|
889
|
-
selectCurrentScreen();
|
|
890
|
-
emit();
|
|
891
887
|
}
|
|
892
888
|
};
|
|
893
889
|
}
|
|
894
|
-
function
|
|
895
|
-
return
|
|
890
|
+
function isEventHandler(key) {
|
|
891
|
+
return /^on[A-Z]/u.test(key);
|
|
896
892
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
893
|
+
|
|
894
|
+
// src/components/root.tsx
|
|
895
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
896
|
+
function Root({ apps: appsProp, children, render, client, ...props }) {
|
|
897
|
+
const baseUrl = toBaseUrl(client.baseUrl).toString();
|
|
898
|
+
const [previousStore, setStore] = useState2(
|
|
899
|
+
() => createTailorKitStore(baseUrl, appsProp, client.previewSessionId)
|
|
900
|
+
);
|
|
901
|
+
let store = previousStore;
|
|
902
|
+
if (previousStore.baseUrl.toString() !== baseUrl) {
|
|
903
|
+
store = createTailorKitStore(baseUrl, appsProp, client.previewSessionId);
|
|
904
|
+
setStore(store);
|
|
903
905
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
906
|
+
useEffect3(() => {
|
|
907
|
+
store.setProvidedApps(appsProp);
|
|
908
|
+
}, [store, appsProp]);
|
|
909
|
+
const context = useMemo5(
|
|
910
|
+
() => ({
|
|
911
|
+
store,
|
|
912
|
+
client
|
|
913
|
+
}),
|
|
914
|
+
[store, client]
|
|
915
|
+
);
|
|
916
|
+
const element = render ? useRender({
|
|
917
|
+
defaultTagName: "div",
|
|
918
|
+
props: mergeProps({ children }, props),
|
|
919
|
+
render
|
|
920
|
+
}) : children;
|
|
921
|
+
return /* @__PURE__ */ jsx4(TailorRootContext.Provider, { value: context, children: element });
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// src/hooks/use-apps.ts
|
|
925
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
926
|
+
function useApps() {
|
|
927
|
+
return useAppsStore(useTailorRootContext("useApps").store);
|
|
928
|
+
}
|
|
929
|
+
function useAppsStore(store) {
|
|
930
|
+
const snapshot = useSyncExternalStore3(
|
|
931
|
+
store.subscribe,
|
|
932
|
+
store.getAppsSnapshot,
|
|
933
|
+
store.getAppsSnapshot
|
|
907
934
|
);
|
|
935
|
+
useEffect4(() => {
|
|
936
|
+
void store.fetchApps();
|
|
937
|
+
}, [store]);
|
|
938
|
+
const refetch = useCallback2(() => store.fetchApps({ force: true }), [store]);
|
|
939
|
+
return toUseAppsResult(snapshot, refetch);
|
|
908
940
|
}
|
|
909
|
-
function
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
941
|
+
function toUseAppsResult(snapshot, refetch) {
|
|
942
|
+
return {
|
|
943
|
+
data: snapshot.status === "ready" ? snapshot.apps : void 0,
|
|
944
|
+
error: snapshot.error,
|
|
945
|
+
isError: snapshot.status === "error",
|
|
946
|
+
isLoading: snapshot.status === "loading",
|
|
947
|
+
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
948
|
+
isSuccess: snapshot.status === "ready",
|
|
949
|
+
refetch,
|
|
950
|
+
status: snapshot.status
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// src/hooks/use-view.ts
|
|
955
|
+
import { useEffect as useEffect5, useMemo as useMemo6 } from "react";
|
|
956
|
+
function useView(view, options) {
|
|
957
|
+
const { store } = useTailorRootContext("useView");
|
|
958
|
+
const id = useMemo6(() => /* @__PURE__ */ Symbol("tailorkit-current-view"), []);
|
|
959
|
+
const status = options.status ?? "ready";
|
|
960
|
+
const context = "context" in options ? options.context : void 0;
|
|
961
|
+
const contextSnapshot = useStableContext(context);
|
|
962
|
+
useEffect5(
|
|
963
|
+
() => () => {
|
|
964
|
+
store.views.unregister(id);
|
|
965
|
+
},
|
|
966
|
+
[id, store]
|
|
967
|
+
);
|
|
968
|
+
useEffect5(() => {
|
|
969
|
+
store.views.register({
|
|
970
|
+
context: contextSnapshot,
|
|
971
|
+
id,
|
|
972
|
+
view,
|
|
973
|
+
status
|
|
974
|
+
});
|
|
975
|
+
}, [contextSnapshot, id, view, status, store]);
|
|
915
976
|
}
|
|
916
977
|
export {
|
|
978
|
+
AppView,
|
|
979
|
+
Root,
|
|
917
980
|
components,
|
|
918
981
|
createTailorKitClient,
|
|
919
|
-
primitives
|
|
982
|
+
primitives,
|
|
983
|
+
useApps,
|
|
984
|
+
useView
|
|
920
985
|
};
|