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