@tailorkit/react 0.1.0-beta.23 → 0.1.0-beta.25
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/context.d.ts +3 -3
- package/dist/components/index.d.ts +1 -2
- package/dist/components/render-slot.d.ts +9 -0
- package/dist/hooks/use-apps.d.ts +4 -20
- package/dist/hooks/use-query-result.d.ts +9 -0
- package/dist/hooks/use-view-context.d.ts +2 -21
- package/dist/hooks/use-views.d.ts +6 -12
- package/dist/index.d.ts +3 -4
- package/dist/index.js +172 -764
- package/dist/primitives.d.ts +1 -2
- package/dist/tailorkit.d.ts +14 -58
- package/package.json +8 -6
- package/dist/components/render.d.ts +0 -19
- package/dist/components/root.d.ts +0 -9
- package/dist/components/slot.d.ts +0 -51
- package/dist/hooks/use-stable-context.d.ts +0 -2
- package/dist/remote-context.d.ts +0 -8
- package/dist/scope-query.d.ts +0 -1
- package/dist/slot-view.d.ts +0 -1
package/dist/index.js
CHANGED
|
@@ -1,326 +1,16 @@
|
|
|
1
|
-
// src/components/slot.tsx
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import { useRef } from "react";
|
|
6
|
-
function useStableContext(value) {
|
|
7
|
-
const key = JSON.stringify(value);
|
|
8
|
-
const ref = useRef({ key, value });
|
|
9
|
-
if (ref.current.key !== key) {
|
|
10
|
-
ref.current = { key, value };
|
|
11
|
-
}
|
|
12
|
-
return ref.current.value;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// src/hooks/use-views.ts
|
|
16
|
-
import { createSlotStore, matchesApp as matchesApp3, serializeCacheKey } from "@tailorkit/client-core";
|
|
17
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
18
|
-
|
|
19
|
-
// src/components/context.ts
|
|
20
|
-
import { createContext, useContext } from "react";
|
|
21
|
-
var TailorRootContext = createContext(null);
|
|
22
|
-
function useTailorRootContext(component, expectedClient) {
|
|
23
|
-
const context = useContext(TailorRootContext);
|
|
24
|
-
if (!context) {
|
|
25
|
-
throw new Error(`${component} must be rendered inside Root.`);
|
|
26
|
-
}
|
|
27
|
-
if (expectedClient && context.client !== expectedClient) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`${component} was created for a different TailorKit client than the one passed to Root.`
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
return context;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// src/hooks/use-apps.ts
|
|
36
|
-
import { useCallback, useEffect, useMemo, useSyncExternalStore } from "react";
|
|
37
|
-
import { matchesApp } from "@tailorkit/client-core";
|
|
38
|
-
|
|
39
|
-
// src/scope-query.ts
|
|
40
|
-
import { appendScopeSelection, normalizeScopeSelection } from "@tailorkit/client-core";
|
|
41
|
-
|
|
42
|
-
// src/hooks/use-apps.ts
|
|
43
|
-
import { matchesApp as matchesApp2 } from "@tailorkit/client-core";
|
|
44
|
-
function useApps(options = {}) {
|
|
45
|
-
return useAppsStore(useTailorRootContext("useApps").store, options);
|
|
46
|
-
}
|
|
47
|
-
function useAppsStore(store, options = {}) {
|
|
48
|
-
const snapshot = useAppsSnapshot(store);
|
|
49
|
-
const scopes = normalizeScopeSelection(options.scopes);
|
|
50
|
-
const appIds = normalizeScopeSelection(options.appIds);
|
|
51
|
-
const data = useMemo(
|
|
52
|
-
() => snapshot.status === "ready" ? snapshot.apps.filter((app) => matchesApp(app, scopes.scopes, appIds.scopes)) : void 0,
|
|
53
|
-
[snapshot, scopes.key, appIds.key]
|
|
54
|
-
);
|
|
55
|
-
const refetch = useCallback(() => store.fetchApps({ force: true }), [store]);
|
|
56
|
-
return { ...toUseAppsResult(snapshot, refetch), data };
|
|
57
|
-
}
|
|
58
|
-
function useAppsSnapshot(store) {
|
|
59
|
-
const snapshot = useSyncExternalStore(
|
|
60
|
-
store.subscribeApps,
|
|
61
|
-
store.getAppsSnapshot,
|
|
62
|
-
store.getAppsSnapshot
|
|
63
|
-
);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
void store.fetchApps();
|
|
66
|
-
}, [store]);
|
|
67
|
-
return snapshot;
|
|
68
|
-
}
|
|
69
|
-
function toUseAppsResult(snapshot, refetch) {
|
|
70
|
-
return {
|
|
71
|
-
data: snapshot.status === "ready" ? snapshot.apps : void 0,
|
|
72
|
-
error: snapshot.error,
|
|
73
|
-
isFetching: snapshot.isFetching,
|
|
74
|
-
isError: snapshot.status === "error",
|
|
75
|
-
isLoading: snapshot.status === "loading",
|
|
76
|
-
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
77
|
-
isSuccess: snapshot.status === "ready",
|
|
78
|
-
refetch,
|
|
79
|
-
status: snapshot.status
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// src/hooks/use-views.ts
|
|
84
|
-
function useViews({ slot, scopes, appIds }) {
|
|
85
|
-
const { store } = useTailorRootContext("useViews");
|
|
86
|
-
const apps = useApps({ scopes, appIds });
|
|
87
|
-
const items = useResolvedSlot(slot, apps.data, apps.status, apps.error);
|
|
88
|
-
const refetch = useCallback2(async () => {
|
|
89
|
-
const multiple = store.client.meta().getSnapshot().data?.schema.slots[slot]?.multiple;
|
|
90
|
-
if (apps.isSuccess && multiple === true) {
|
|
91
|
-
await items.refetch();
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
await apps.refetch();
|
|
95
|
-
let previousKey;
|
|
96
|
-
while (true) {
|
|
97
|
-
const discovery = store.getAppsSnapshot();
|
|
98
|
-
if (discovery.status !== "ready") return;
|
|
99
|
-
const schema = store.getMetaSnapshot().schema;
|
|
100
|
-
const options = {
|
|
101
|
-
apps: discovery.apps.filter((app) => matchesApp3(app, scopes, appIds)),
|
|
102
|
-
slot,
|
|
103
|
-
activeView: schema === null || schema.slots[slot]?.multiple === true ? store.views.getSnapshot() : null
|
|
104
|
-
};
|
|
105
|
-
const key = serializeCacheKey([options.apps, slot, options.activeView]);
|
|
106
|
-
if (key === previousKey) return;
|
|
107
|
-
previousKey = key;
|
|
108
|
-
await createSlotStore(store.client, options).fetch();
|
|
109
|
-
}
|
|
110
|
-
}, [store, slot, scopes, appIds, apps.isSuccess, apps.refetch, items.refetch]);
|
|
111
|
-
return { ...items, isFetching: apps.isFetching || items.isFetching, refetch };
|
|
112
|
-
}
|
|
113
|
-
function useAppSlot(app, slot) {
|
|
114
|
-
return useResolvedSlot(slot, [app], "ready", null);
|
|
115
|
-
}
|
|
116
|
-
function useResolvedSlot(slot, apps, appsStatus, appsError) {
|
|
117
|
-
const { store } = useTailorRootContext("useViews");
|
|
118
|
-
const activeView = useSyncExternalStore2(
|
|
119
|
-
store.views.subscribe,
|
|
120
|
-
store.views.getSnapshot,
|
|
121
|
-
store.views.getSnapshot
|
|
122
|
-
);
|
|
123
|
-
const meta = useSyncExternalStore2(store.subscribe, store.getMetaSnapshot, store.getMetaSnapshot);
|
|
124
|
-
const options = useStableContext({
|
|
125
|
-
apps: apps ?? [],
|
|
126
|
-
slot,
|
|
127
|
-
activeView: meta.schema === null || meta.schema.slots[slot]?.multiple === true ? activeView : null
|
|
128
|
-
});
|
|
129
|
-
const query = useMemo2(
|
|
130
|
-
() => createSlotStore(store.client, {
|
|
131
|
-
...options,
|
|
132
|
-
appsStatus,
|
|
133
|
-
appsError
|
|
134
|
-
}),
|
|
135
|
-
[store.client, options, appsStatus, appsError]
|
|
136
|
-
);
|
|
137
|
-
const snapshot = useSyncExternalStore2(query.subscribe, query.getSnapshot, query.getSnapshot);
|
|
138
|
-
useEffect2(() => {
|
|
139
|
-
void query.fetch();
|
|
140
|
-
}, [query]);
|
|
141
|
-
const refetch = useCallback2(() => query.fetch({ force: true }), [query]);
|
|
142
|
-
return {
|
|
143
|
-
...snapshot,
|
|
144
|
-
isError: snapshot.status === "error",
|
|
145
|
-
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
146
|
-
isLoading: snapshot.status === "loading",
|
|
147
|
-
isSuccess: snapshot.status === "ready",
|
|
148
|
-
refetch
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// src/slot-view.ts
|
|
153
|
-
import { resolveSlotView, selectSlotView } from "@tailorkit/client-core";
|
|
1
|
+
// src/components/render-slot.tsx
|
|
2
|
+
import { useStore as useStore2 } from "@nanostores/react";
|
|
3
|
+
import { createSlotRuntime, buildThemeCss } from "@tailorkit/client-core";
|
|
4
|
+
import { useEffect as useEffect2, useId as useId2, useMemo as useMemo3 } from "react";
|
|
154
5
|
|
|
155
6
|
// src/primitives.tsx
|
|
156
|
-
import { createContext
|
|
157
|
-
import {
|
|
7
|
+
import { createContext, useContext, useId, useMemo } from "react";
|
|
8
|
+
import { buildPrimitiveCss } from "@tailorkit/client-core";
|
|
158
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
159
|
-
var PrimitiveThemeContext =
|
|
160
|
-
var tokenGroups = [
|
|
161
|
-
"space",
|
|
162
|
-
"radius",
|
|
163
|
-
"background",
|
|
164
|
-
"border",
|
|
165
|
-
"borderColor",
|
|
166
|
-
"textColor"
|
|
167
|
-
];
|
|
168
|
-
var cssEscape = (value) => {
|
|
169
|
-
const css = globalThis.CSS;
|
|
170
|
-
if (typeof css?.escape === "function") {
|
|
171
|
-
return css.escape(value);
|
|
172
|
-
}
|
|
173
|
-
return value.replaceAll(/[^A-Za-z0-9_-]/gu, "\\$&");
|
|
174
|
-
};
|
|
175
|
-
var toCssValue = (group, value) => {
|
|
176
|
-
if (typeof value === "number") {
|
|
177
|
-
return `${value}px`;
|
|
178
|
-
}
|
|
179
|
-
if (group === "size" || group === "raw") {
|
|
180
|
-
return value;
|
|
181
|
-
}
|
|
182
|
-
return `var(--tailorkit-${group}-${cssEscape(value)})`;
|
|
183
|
-
};
|
|
184
|
-
var toResponsiveEntries = (value) => {
|
|
185
|
-
if (value === void 0) {
|
|
186
|
-
return [];
|
|
187
|
-
}
|
|
188
|
-
if (!(value && typeof value === "object") || Array.isArray(value)) {
|
|
189
|
-
return [["base", value]];
|
|
190
|
-
}
|
|
191
|
-
return Object.entries(value).filter(
|
|
192
|
-
(entry) => entry[1] !== void 0
|
|
193
|
-
);
|
|
194
|
-
};
|
|
195
|
-
var declarationsForProp = (prop, value) => {
|
|
196
|
-
if (prop === "columns") {
|
|
197
|
-
return [`grid-template-columns: repeat(${String(value)}, minmax(0, 1fr));`];
|
|
198
|
-
}
|
|
199
|
-
const tokenDeclarations = {
|
|
200
|
-
background: ["background", "background"],
|
|
201
|
-
border: ["border", "border"],
|
|
202
|
-
borderColor: ["borderColor", "border-color"],
|
|
203
|
-
textColor: ["textColor", "color"]
|
|
204
|
-
};
|
|
205
|
-
const tokenDeclaration = tokenDeclarations[prop];
|
|
206
|
-
if (tokenDeclaration) {
|
|
207
|
-
const [group, property] = tokenDeclaration;
|
|
208
|
-
if (prop === "border") {
|
|
209
|
-
return [`border-style: ${toCssValue(group, value)};`, "border-width: 1px;"];
|
|
210
|
-
}
|
|
211
|
-
return [`${property}: ${toCssValue(group, value)};`];
|
|
212
|
-
}
|
|
213
|
-
if (prop === "gap" || prop === "margin" || prop === "padding") {
|
|
214
|
-
return [`${prop}: ${toCssValue("space", value)};`];
|
|
215
|
-
}
|
|
216
|
-
if (prop === "height" || prop === "width") {
|
|
217
|
-
return [`${prop}: ${toCssValue("size", value)};`];
|
|
218
|
-
}
|
|
219
|
-
if (prop === "radius") {
|
|
220
|
-
return [`border-radius: ${toCssValue("radius", value)};`];
|
|
221
|
-
}
|
|
222
|
-
if (prop === "align") {
|
|
223
|
-
return [`align-items: ${toFlexAlignment(value)};`];
|
|
224
|
-
}
|
|
225
|
-
if (prop === "justify") {
|
|
226
|
-
return [`justify-content: ${toFlexJustification(value)};`];
|
|
227
|
-
}
|
|
228
|
-
if (prop === "direction") {
|
|
229
|
-
return [`flex-direction: ${toCssValue("raw", value)};`];
|
|
230
|
-
}
|
|
231
|
-
if (prop === "overflow") {
|
|
232
|
-
return [`overflow: ${toCssValue("raw", value)};`];
|
|
233
|
-
}
|
|
234
|
-
if (prop === "grow") {
|
|
235
|
-
return [`flex-grow: ${String(value)};`];
|
|
236
|
-
}
|
|
237
|
-
if (prop === "shrink") {
|
|
238
|
-
return [`flex-shrink: ${String(value)};`];
|
|
239
|
-
}
|
|
240
|
-
if (prop === "minHeight") {
|
|
241
|
-
return [`min-height: ${toCssValue("size", value)};`];
|
|
242
|
-
}
|
|
243
|
-
if (prop === "minWidth") {
|
|
244
|
-
return [`min-width: ${toCssValue("size", value)};`];
|
|
245
|
-
}
|
|
246
|
-
if (prop === "basis") {
|
|
247
|
-
return [`flex-basis: ${toCssValue("size", value)};`];
|
|
248
|
-
}
|
|
249
|
-
if (prop === "wrap") {
|
|
250
|
-
return [`flex-wrap: ${toCssValue("raw", value)};`];
|
|
251
|
-
}
|
|
252
|
-
return [];
|
|
253
|
-
};
|
|
254
|
-
var toFlexAlignment = (value) => {
|
|
255
|
-
if (value === "start") {
|
|
256
|
-
return "flex-start";
|
|
257
|
-
}
|
|
258
|
-
if (value === "end") {
|
|
259
|
-
return "flex-end";
|
|
260
|
-
}
|
|
261
|
-
return String(value);
|
|
262
|
-
};
|
|
263
|
-
var toFlexJustification = (value) => {
|
|
264
|
-
if (value === "start") {
|
|
265
|
-
return "flex-start";
|
|
266
|
-
}
|
|
267
|
-
if (value === "end") {
|
|
268
|
-
return "flex-end";
|
|
269
|
-
}
|
|
270
|
-
if (value === "between") {
|
|
271
|
-
return "space-between";
|
|
272
|
-
}
|
|
273
|
-
return String(value);
|
|
274
|
-
};
|
|
275
|
-
var buildPrimitiveCss = ({
|
|
276
|
-
display,
|
|
277
|
-
nodeId,
|
|
278
|
-
props,
|
|
279
|
-
viewId,
|
|
280
|
-
theme
|
|
281
|
-
}) => {
|
|
282
|
-
const selector = `[data-tailorkit-view="${cssEscape(viewId)}"] [data-tailorkit-node="${cssEscape(
|
|
283
|
-
nodeId
|
|
284
|
-
)}"]`;
|
|
285
|
-
const base = [`display: ${display};`];
|
|
286
|
-
const byBreakpoint = /* @__PURE__ */ new Map();
|
|
287
|
-
for (const [prop, rawValue] of Object.entries(props)) {
|
|
288
|
-
for (const [breakpoint, value] of toResponsiveEntries(rawValue)) {
|
|
289
|
-
const declarations = declarationsForProp(prop, value);
|
|
290
|
-
if (declarations.length === 0) {
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
const target = breakpoint === "base" ? base : byBreakpoint.get(breakpoint) ?? [];
|
|
294
|
-
target.push(...declarations);
|
|
295
|
-
if (breakpoint !== "base") {
|
|
296
|
-
byBreakpoint.set(breakpoint, target);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
const rules = [`${selector} { ${base.join(" ")} }`];
|
|
301
|
-
for (const [breakpoint, declarations] of byBreakpoint) {
|
|
302
|
-
const minWidth = theme.breakpoints?.[breakpoint];
|
|
303
|
-
if (!minWidth) {
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
rules.push(`@media (min-width: ${minWidth}) { ${selector} { ${declarations.join(" ")} } }`);
|
|
307
|
-
}
|
|
308
|
-
return rules.join("\n");
|
|
309
|
-
};
|
|
310
|
-
var buildThemeCss = (viewId, theme) => {
|
|
311
|
-
const selector = `[data-tailorkit-view="${cssEscape(viewId)}"]`;
|
|
312
|
-
const declarations = [];
|
|
313
|
-
const resolvedTheme = resolveTheme(theme);
|
|
314
|
-
for (const group of tokenGroups) {
|
|
315
|
-
for (const [name, value] of Object.entries(resolvedTheme.tokens?.[group] ?? {})) {
|
|
316
|
-
declarations.push(`--tailorkit-${group}-${cssEscape(name)}: ${value};`);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
return `${selector} { ${declarations.join(" ")} }`;
|
|
320
|
-
};
|
|
10
|
+
var PrimitiveThemeContext = createContext(null);
|
|
321
11
|
var usePrimitiveNodeId = () => {
|
|
322
12
|
const id = useId();
|
|
323
|
-
return
|
|
13
|
+
return useMemo(() => `tailorkit-${id.replaceAll(":", "")}`, [id]);
|
|
324
14
|
};
|
|
325
15
|
var Primitive = ({
|
|
326
16
|
children,
|
|
@@ -328,7 +18,7 @@ var Primitive = ({
|
|
|
328
18
|
element,
|
|
329
19
|
props
|
|
330
20
|
}) => {
|
|
331
|
-
const context =
|
|
21
|
+
const context = useContext(PrimitiveThemeContext);
|
|
332
22
|
const nodeId = usePrimitiveNodeId();
|
|
333
23
|
const Element = element;
|
|
334
24
|
const css = context ? buildPrimitiveCss({
|
|
@@ -351,28 +41,20 @@ var primitives = {
|
|
|
351
41
|
};
|
|
352
42
|
|
|
353
43
|
// src/remote-view.tsx
|
|
44
|
+
import { useStore } from "@nanostores/react";
|
|
354
45
|
import {
|
|
355
46
|
Component,
|
|
356
47
|
Fragment,
|
|
357
48
|
createElement,
|
|
49
|
+
createContext as createContext2,
|
|
358
50
|
memo,
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
useMemo as useMemo4,
|
|
363
|
-
useRef as useRef2,
|
|
364
|
-
useState,
|
|
365
|
-
useSyncExternalStore as useSyncExternalStore3
|
|
51
|
+
useContext as useContext2,
|
|
52
|
+
useEffect,
|
|
53
|
+
useMemo as useMemo2
|
|
366
54
|
} from "react";
|
|
367
|
-
import {
|
|
368
|
-
import { NodeStore } from "@tailorkit/client-core";
|
|
369
|
-
|
|
370
|
-
// src/remote-context.ts
|
|
371
|
-
import { createContext as createContext3 } from "react";
|
|
372
|
-
var RemoteUIContext = createContext3(null);
|
|
373
|
-
|
|
374
|
-
// src/remote-view.tsx
|
|
55
|
+
import { createRemoteViewStore, createRemoteElementProps } from "@tailorkit/client-core";
|
|
375
56
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
57
|
+
var RemoteUIContext = createContext2(null);
|
|
376
58
|
var formatError = (error) => error.message;
|
|
377
59
|
var RemoteErrorBoundary = class extends Component {
|
|
378
60
|
state = { error: null };
|
|
@@ -398,124 +80,44 @@ function RemoteViewHost({
|
|
|
398
80
|
props
|
|
399
81
|
}) {
|
|
400
82
|
const appKey = appUrl.toString();
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
hostRef.current?.setProps(props);
|
|
416
|
-
}, [props]);
|
|
417
|
-
const dispatchRef = useRef2(null);
|
|
418
|
-
const [error, setError] = useState(null);
|
|
419
|
-
const [status, setStatus] = useState("starting");
|
|
420
|
-
const ctxRef = useRef2({
|
|
421
|
-
components: components2,
|
|
422
|
-
dispatch: (payload) => dispatchRef.current?.(payload),
|
|
423
|
-
store
|
|
424
|
-
});
|
|
425
|
-
useEffect3(() => {
|
|
426
|
-
ctxRef.current.components = components2;
|
|
427
|
-
}, [components2]);
|
|
428
|
-
const ui = useMemo4(() => {
|
|
429
|
-
const ctx = ctxRef.current;
|
|
430
|
-
return createElement(
|
|
431
|
-
RemoteUIContext.Provider,
|
|
432
|
-
{ value: ctx },
|
|
433
|
-
createElement(
|
|
434
|
-
RemoteErrorBoundary,
|
|
435
|
-
{ key: appKey },
|
|
436
|
-
createElement(RemoteRoot, { store: ctx.store })
|
|
437
|
-
)
|
|
438
|
-
);
|
|
439
|
-
}, [appKey]);
|
|
440
|
-
useEffect3(() => {
|
|
441
|
-
const host = createIframeUiHost(appUrl, {
|
|
442
|
-
createIframe,
|
|
443
|
-
sourceText,
|
|
444
|
-
getBackendSession,
|
|
445
|
-
onError: (error2) => {
|
|
446
|
-
console.error("TailorKit remote app failed", error2);
|
|
447
|
-
setError(error2);
|
|
448
|
-
setStatus("error");
|
|
449
|
-
},
|
|
450
|
-
props: propsRef.current
|
|
451
|
-
});
|
|
452
|
-
hostRef.current = host;
|
|
453
|
-
dispatchRef.current = (payload) => host.dispatch(payload);
|
|
454
|
-
const unsubscribe = host.subscribe(() => {
|
|
455
|
-
const tree = host.getSnapshot();
|
|
456
|
-
if (tree !== null) {
|
|
457
|
-
store.setSnapshot(tree);
|
|
458
|
-
setStatus("ready");
|
|
459
|
-
}
|
|
460
|
-
});
|
|
461
|
-
setStatus("starting");
|
|
462
|
-
setError(null);
|
|
463
|
-
host.mount();
|
|
464
|
-
return () => {
|
|
465
|
-
unsubscribe();
|
|
466
|
-
dispatchRef.current = null;
|
|
467
|
-
hostRef.current = null;
|
|
468
|
-
host.destroy();
|
|
469
|
-
};
|
|
470
|
-
}, [appUrl, createIframe, sourceText, getBackendSession, store]);
|
|
471
|
-
if (status === "error" && error) {
|
|
472
|
-
return createElement("div", null, formatError(error));
|
|
83
|
+
const store = useMemo2(() => createRemoteViewStore({ components: components2, props }), [appKey]);
|
|
84
|
+
const snapshot = useStore(store.state);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
store.setComponents(components2);
|
|
87
|
+
}, [components2, store]);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
store.setProps(props);
|
|
90
|
+
}, [props, store]);
|
|
91
|
+
useEffect(
|
|
92
|
+
() => store.mount({ appUrl, sourceText, getBackendSession, createIframe }),
|
|
93
|
+
[appUrl, sourceText, getBackendSession, createIframe, store]
|
|
94
|
+
);
|
|
95
|
+
if (snapshot.status === "error" && snapshot.error) {
|
|
96
|
+
return createElement("div", null, formatError(snapshot.error));
|
|
473
97
|
}
|
|
474
|
-
return
|
|
98
|
+
return /* @__PURE__ */ jsx2(RemoteUIContext.Provider, { value: store, children: /* @__PURE__ */ jsx2(RemoteErrorBoundary, { children: /* @__PURE__ */ jsx2(RemoteRoot, { store }) }, `${appKey}:${snapshot.generation}`) });
|
|
475
99
|
}
|
|
476
100
|
function RemoteRoot({ store }) {
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
const rootId = useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
|
|
480
|
-
if (rootId === null) {
|
|
481
|
-
return null;
|
|
482
|
-
}
|
|
483
|
-
return /* @__PURE__ */ jsx2(RemoteView, { nodeId: rootId });
|
|
101
|
+
const rootId = useStore(store.nodes.root);
|
|
102
|
+
return rootId === null ? null : /* @__PURE__ */ jsx2(RemoteView, { nodeId: rootId });
|
|
484
103
|
}
|
|
485
104
|
var RemoteElementView = memo(({ ctx, node }) => {
|
|
486
|
-
const
|
|
105
|
+
const componentStore = useMemo2(() => ctx.selectComponent(node.type), [ctx, node.type]);
|
|
106
|
+
const component = useStore(componentStore);
|
|
487
107
|
const children = node.children.map((child) => /* @__PURE__ */ jsx2(RemoteView, { nodeId: child.id }, child.id));
|
|
488
|
-
const component = components2[node.type];
|
|
489
108
|
if (component === void 0) {
|
|
490
109
|
throw new Error(`TailorKit component "${node.type}" is not registered.`);
|
|
491
110
|
}
|
|
492
|
-
const props =
|
|
493
|
-
for (const binding of node.callbacks ?? []) {
|
|
494
|
-
props[binding.callback] = (...args) => {
|
|
495
|
-
dispatch({
|
|
496
|
-
data: {
|
|
497
|
-
args: args.slice(0, binding.inputCount),
|
|
498
|
-
event: binding.event,
|
|
499
|
-
nodeId: node.id
|
|
500
|
-
},
|
|
501
|
-
type: "dispatchCallback"
|
|
502
|
-
});
|
|
503
|
-
};
|
|
504
|
-
}
|
|
111
|
+
const props = createRemoteElementProps(node, ctx.dispatch);
|
|
505
112
|
return createElement(component, props, ...children);
|
|
506
113
|
});
|
|
507
114
|
function RemoteViewComponent({ nodeId }) {
|
|
508
|
-
const ctx =
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
const
|
|
513
|
-
const
|
|
514
|
-
(listener) => store.subscribe(nodeId, listener),
|
|
515
|
-
[store, nodeId]
|
|
516
|
-
);
|
|
517
|
-
const getSnapshot = useCallback3(() => store.getNode(nodeId), [store, nodeId]);
|
|
518
|
-
const node = useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
|
|
115
|
+
const ctx = useContext2(RemoteUIContext);
|
|
116
|
+
return ctx === null ? null : /* @__PURE__ */ jsx2(RemoteNodeView, { ctx, nodeId });
|
|
117
|
+
}
|
|
118
|
+
function RemoteNodeView({ ctx, nodeId }) {
|
|
119
|
+
const nodeStore = useMemo2(() => ctx.nodes.selectNode(nodeId), [ctx, nodeId]);
|
|
120
|
+
const node = useStore(nodeStore);
|
|
519
121
|
if (node === null) {
|
|
520
122
|
return null;
|
|
521
123
|
}
|
|
@@ -530,210 +132,128 @@ function RemoteViewComponent({ nodeId }) {
|
|
|
530
132
|
}
|
|
531
133
|
var RemoteView = memo(RemoteViewComponent);
|
|
532
134
|
|
|
533
|
-
// src/components/
|
|
534
|
-
import {
|
|
135
|
+
// src/components/context.ts
|
|
136
|
+
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
137
|
+
var TailorkitContext = createContext3(null);
|
|
138
|
+
function useTailorkitContext(component, expectedClient) {
|
|
139
|
+
const context = useContext3(TailorkitContext);
|
|
140
|
+
if (!context) {
|
|
141
|
+
throw new Error(`${component} must be rendered inside a TailorKit Provider.`);
|
|
142
|
+
}
|
|
143
|
+
if (expectedClient && context.client !== expectedClient) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`${component} was created for a different TailorKit client than the surrounding Provider.`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
return context;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/components/render-slot.tsx
|
|
535
152
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
536
|
-
function
|
|
537
|
-
|
|
538
|
-
const state = useSyncExternalStore4(
|
|
539
|
-
store.views.subscribe,
|
|
540
|
-
store.views.getSnapshot,
|
|
541
|
-
store.views.getSnapshot
|
|
542
|
-
);
|
|
543
|
-
if (state === null) return null;
|
|
544
|
-
return instanceKey === void 0 ? /* @__PURE__ */ jsx3(SlotRenderer, { app, name, state }) : /* @__PURE__ */ jsx3(InstanceSlot, { app, name, instanceKey, state });
|
|
153
|
+
function ManagedRenderSlot(props) {
|
|
154
|
+
return /* @__PURE__ */ jsx3(SlotRenderer, { mode: "managed", ...props });
|
|
545
155
|
}
|
|
546
|
-
function
|
|
547
|
-
|
|
548
|
-
name,
|
|
549
|
-
instanceKey,
|
|
550
|
-
state
|
|
551
|
-
}) {
|
|
552
|
-
const { store } = useTailorRootContext("Slot");
|
|
553
|
-
const instances = useAppSlot(app, name);
|
|
554
|
-
const meta = useSyncExternalStore4(store.subscribe, store.getMetaSnapshot, store.getMetaSnapshot);
|
|
555
|
-
const instance = instances.data?.find(
|
|
556
|
-
(item) => "key" in item && item.key === instanceKey
|
|
557
|
-
);
|
|
558
|
-
const resolved = instances.isSuccess && instance && meta.schema ? resolveSlotView(app.views ?? [], name, state, meta.schema) : null;
|
|
559
|
-
const view = resolved?.status === "ready" ? resolved.view : void 0;
|
|
560
|
-
const stableContext = useStableContext(resolved?.context);
|
|
561
|
-
const stableInstance = useStableContext(
|
|
562
|
-
instance ? { key: instance.key, metadata: instance.metadata, data: instance.data } : void 0
|
|
563
|
-
);
|
|
564
|
-
const readyState = useMemo5(
|
|
565
|
-
() => view === void 0 || !stableInstance ? null : {
|
|
566
|
-
controlled: true,
|
|
567
|
-
view,
|
|
568
|
-
context: stableContext,
|
|
569
|
-
status: "ready",
|
|
570
|
-
instance: stableInstance
|
|
571
|
-
},
|
|
572
|
-
[view, stableContext, stableInstance]
|
|
573
|
-
);
|
|
574
|
-
if (instances.isPending) return /* @__PURE__ */ jsx3("div", { role: "status", children: "Loading view\u2026" });
|
|
575
|
-
if (instances.error) return /* @__PURE__ */ jsx3("div", { role: "alert", children: instances.error.message });
|
|
576
|
-
if (meta.schema && meta.schema.slots[name]?.multiple !== true)
|
|
577
|
-
return /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
|
|
578
|
-
'Slot "',
|
|
579
|
-
name,
|
|
580
|
-
'" does not support instances.'
|
|
581
|
-
] });
|
|
582
|
-
if (!instance) return /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
|
|
583
|
-
'View instance "',
|
|
584
|
-
instanceKey,
|
|
585
|
-
'" is unavailable.'
|
|
586
|
-
] });
|
|
587
|
-
if (!readyState) return null;
|
|
588
|
-
return /* @__PURE__ */ jsx3(SlotRenderer, { app, name, state: readyState });
|
|
156
|
+
function ControlledRenderSlot(props) {
|
|
157
|
+
return /* @__PURE__ */ jsx3(SlotRenderer, { mode: "controlled", ...props });
|
|
589
158
|
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
instance
|
|
597
|
-
}) {
|
|
598
|
-
useTailorRootContext("Slot.Controlled");
|
|
599
|
-
const stableContext = useStableContext(context);
|
|
600
|
-
const stableInstance = useStableContext(instance);
|
|
601
|
-
const state = useMemo5(
|
|
602
|
-
() => ({
|
|
603
|
-
controlled: true,
|
|
604
|
-
view,
|
|
605
|
-
context: stableContext,
|
|
606
|
-
status,
|
|
607
|
-
...status === "ready" && stableInstance ? { instance: stableInstance } : {}
|
|
608
|
-
}),
|
|
609
|
-
[view, stableContext, status, stableInstance]
|
|
159
|
+
var RenderSlot = Object.assign(ManagedRenderSlot, {
|
|
160
|
+
Controlled: ControlledRenderSlot
|
|
161
|
+
});
|
|
162
|
+
function SlotRenderer(options) {
|
|
163
|
+
const { store, client } = useTailorkitContext(
|
|
164
|
+
options.mode === "managed" ? "RenderSlot" : "RenderSlot.Controlled"
|
|
610
165
|
);
|
|
611
|
-
if (status === "ready" && !instance && app.views?.some(
|
|
612
|
-
(entry) => entry.slot === name && entry.path === view && entry.instances && !entry.disabled
|
|
613
|
-
)) {
|
|
614
|
-
return /* @__PURE__ */ jsx3("div", { role: "alert", children: "A view instance is required. Pass instance to Slot.Controlled." });
|
|
615
|
-
}
|
|
616
|
-
return /* @__PURE__ */ jsx3(SlotRenderer, { app, name, state });
|
|
617
|
-
}
|
|
618
|
-
var Slot = Object.assign(ManagedSlot, { Controlled: ControlledSlot });
|
|
619
|
-
function SlotRenderer({ app, name, state }) {
|
|
620
|
-
const { store, client } = useTailorRootContext("Slot");
|
|
621
166
|
const reactId = useId2();
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
);
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const appRef = useRef3(app);
|
|
629
|
-
appRef.current = app;
|
|
630
|
-
const subscribePreview = useCallback4(
|
|
631
|
-
(listener) => {
|
|
632
|
-
const currentApp = appRef.current;
|
|
633
|
-
return currentApp.preview?.sessionId === previewSessionId ? store.previews.subscribe(currentApp, listener) : () => {
|
|
634
|
-
};
|
|
635
|
-
},
|
|
636
|
-
[store, previewSessionId]
|
|
637
|
-
);
|
|
638
|
-
const getPreviewSnapshot = useCallback4(
|
|
639
|
-
() => store.previews.getSnapshot(previewSessionId),
|
|
640
|
-
[store, previewSessionId]
|
|
641
|
-
);
|
|
642
|
-
const preview = useSyncExternalStore4(subscribePreview, getPreviewSnapshot, getPreviewSnapshot);
|
|
643
|
-
const props = useMemo5(
|
|
644
|
-
() => ({
|
|
645
|
-
...state,
|
|
646
|
-
slot: name,
|
|
647
|
-
declaredViews: Object.keys(meta.schema?.views ?? {}),
|
|
648
|
-
supportedViews: meta.schema?.slots[name]?.views ?? []
|
|
649
|
-
}),
|
|
650
|
-
[state, name, meta.schema]
|
|
651
|
-
);
|
|
652
|
-
const appUrl = useMemo5(() => {
|
|
653
|
-
if (app.clientPath) return new URL(app.clientPath, store.baseUrl);
|
|
654
|
-
if (!meta.assetsBaseUrl || !app.projectId || !app.currentDeployment?.id) return null;
|
|
655
|
-
return new URL(
|
|
656
|
-
`projects/${app.projectId}/apps/${app.id}/deployments/${app.currentDeployment.id}/client/client.js`,
|
|
657
|
-
toBaseUrl(meta.assetsBaseUrl)
|
|
658
|
-
);
|
|
659
|
-
}, [app, store.baseUrl, meta.assetsBaseUrl]);
|
|
660
|
-
useEffect4(() => {
|
|
661
|
-
void store.fetchMeta();
|
|
662
|
-
}, [store]);
|
|
663
|
-
useEffect4(() => {
|
|
664
|
-
store.previews.updateApp(app);
|
|
665
|
-
}, [store, app]);
|
|
666
|
-
if (meta.schema === null || appUrl === null && preview.source === null) return null;
|
|
667
|
-
const multiple = meta.schema.slots[name]?.multiple === true;
|
|
668
|
-
if ("controlled" in state && state.status === "ready") {
|
|
669
|
-
if (multiple && !state.instance)
|
|
670
|
-
return /* @__PURE__ */ jsx3("div", { role: "alert", children: "A view instance is required. Pass instance to Slot.Controlled." });
|
|
671
|
-
if (!multiple && state.instance)
|
|
672
|
-
return /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
|
|
673
|
-
'Slot "',
|
|
674
|
-
name,
|
|
675
|
-
'" does not support instances.'
|
|
676
|
-
] });
|
|
677
|
-
}
|
|
678
|
-
if (!("controlled" in state)) {
|
|
679
|
-
const selected = selectSlotView(app.views ?? [], name, state.view, meta.schema);
|
|
680
|
-
if (selected?.instances && !multiple)
|
|
681
|
-
return /* @__PURE__ */ jsxs2("div", { role: "alert", children: [
|
|
682
|
-
'Slot "',
|
|
683
|
-
name,
|
|
684
|
-
'" does not support instances.'
|
|
685
|
-
] });
|
|
686
|
-
if (multiple)
|
|
687
|
-
return /* @__PURE__ */ jsx3("div", { role: "alert", children: "A view instance key is required. Pass instanceKey to Slot." });
|
|
688
|
-
}
|
|
167
|
+
const runtime = useMemo3(() => createSlotRuntime(store, options), [store]);
|
|
168
|
+
useEffect2(() => runtime.setInput(options), [runtime, options]);
|
|
169
|
+
const snapshot = useStore2(runtime.state);
|
|
170
|
+
if (snapshot.status === "hidden") return null;
|
|
171
|
+
if (snapshot.status === "loading") return /* @__PURE__ */ jsx3("div", { role: "status", children: snapshot.message });
|
|
172
|
+
if (snapshot.status === "error") return /* @__PURE__ */ jsx3("div", { role: "alert", children: snapshot.error.message });
|
|
689
173
|
const viewId = `tailorkit-view-${reactId.replaceAll(":", "")}`;
|
|
690
174
|
return /* @__PURE__ */ jsx3(PrimitiveThemeContext.Provider, { value: { viewId, theme: client.theme }, children: /* @__PURE__ */ jsxs2("div", { "data-tailorkit-view": viewId, children: [
|
|
691
175
|
/* @__PURE__ */ jsx3("style", { "data-tailorkit-theme-style": viewId, children: buildThemeCss(viewId, client.theme) }),
|
|
692
176
|
/* @__PURE__ */ jsx3(
|
|
693
177
|
RemoteViewHost,
|
|
694
178
|
{
|
|
695
|
-
appUrl:
|
|
696
|
-
sourceText:
|
|
697
|
-
getBackendSession,
|
|
179
|
+
appUrl: snapshot.appUrl,
|
|
180
|
+
sourceText: snapshot.sourceText,
|
|
181
|
+
getBackendSession: snapshot.getBackendSession,
|
|
698
182
|
components: client.components,
|
|
699
|
-
props
|
|
183
|
+
props: snapshot.props
|
|
700
184
|
},
|
|
701
|
-
|
|
185
|
+
snapshot.hostKey
|
|
702
186
|
)
|
|
703
187
|
] }) });
|
|
704
188
|
}
|
|
705
189
|
|
|
706
190
|
// src/tailorkit.tsx
|
|
707
|
-
import {
|
|
708
|
-
|
|
191
|
+
import {
|
|
192
|
+
createTailorKitClientConfig,
|
|
193
|
+
createComponentRegistry,
|
|
194
|
+
createTailorKitStore
|
|
195
|
+
} from "@tailorkit/client-core";
|
|
196
|
+
import { createElement as createElement2, useEffect as useEffect4, useMemo as useMemo8, useState } from "react";
|
|
709
197
|
|
|
710
198
|
// src/hooks/use-view-context.ts
|
|
711
|
-
import { useEffect as
|
|
199
|
+
import { useEffect as useEffect3, useMemo as useMemo4 } from "react";
|
|
712
200
|
function useViewContext(view, options) {
|
|
713
|
-
const { store } =
|
|
714
|
-
const id =
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
const contextSnapshot = useStableContext(context);
|
|
718
|
-
useEffect5(
|
|
201
|
+
const { store } = useTailorkitContext("useViewContext");
|
|
202
|
+
const id = useMemo4(() => /* @__PURE__ */ Symbol("tailorkit-current-view"), []);
|
|
203
|
+
const { context, loading, error } = options;
|
|
204
|
+
useEffect3(
|
|
719
205
|
() => () => {
|
|
720
206
|
store.views.unregister(id);
|
|
721
207
|
},
|
|
722
208
|
[id, store]
|
|
723
209
|
);
|
|
724
|
-
|
|
725
|
-
store.views.register({
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
210
|
+
useEffect3(() => {
|
|
211
|
+
store.views.register({ id, view, context, loading, error });
|
|
212
|
+
}, [id, view, context, loading, error, store]);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/hooks/use-apps.ts
|
|
216
|
+
import { useMemo as useMemo6 } from "react";
|
|
217
|
+
import { appsQueryKey, createAppsQuery } from "@tailorkit/client-core";
|
|
218
|
+
|
|
219
|
+
// src/hooks/use-query-result.ts
|
|
220
|
+
import { useStore as useStore3 } from "@nanostores/react";
|
|
221
|
+
import { useMemo as useMemo5 } from "react";
|
|
222
|
+
function useQueryResult(state) {
|
|
223
|
+
const result = useStore3(state);
|
|
224
|
+
return useMemo5(
|
|
225
|
+
() => ({
|
|
226
|
+
data: result.data,
|
|
227
|
+
isPending: result.isPending,
|
|
228
|
+
error: result.error,
|
|
229
|
+
isRefetching: result.isFetching && !result.isPending,
|
|
230
|
+
fetch: result.refetch
|
|
231
|
+
}),
|
|
232
|
+
[result]
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/hooks/use-apps.ts
|
|
237
|
+
function useApps(options = {}) {
|
|
238
|
+
return useAppsStore(useTailorkitContext("useApps").store, options);
|
|
239
|
+
}
|
|
240
|
+
function useAppsStore(store, options = {}) {
|
|
241
|
+
const key = appsQueryKey(options);
|
|
242
|
+
const query = useMemo6(() => createAppsQuery(store, options), [store, key]);
|
|
243
|
+
return useQueryResult(query.state);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// src/hooks/use-views.ts
|
|
247
|
+
import { useMemo as useMemo7 } from "react";
|
|
248
|
+
import { appsQueryKey as appsQueryKey2, createViewsQuery } from "@tailorkit/client-core";
|
|
249
|
+
function useViews(options) {
|
|
250
|
+
const { store } = useTailorkitContext("useViews");
|
|
251
|
+
const key = appsQueryKey2(options);
|
|
252
|
+
const query = useMemo7(() => createViewsQuery(store, options), [store, key, options.slot]);
|
|
253
|
+
return useQueryResult(query.state);
|
|
732
254
|
}
|
|
733
255
|
|
|
734
256
|
// src/tailorkit.tsx
|
|
735
|
-
var componentTagPrefix = "tailorkit-";
|
|
736
|
-
var toComponentTagName = (name) => `${componentTagPrefix}${name.replaceAll(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[\s_]+/gu, "-").toLowerCase()}`;
|
|
737
257
|
function components(_schema, customComponents) {
|
|
738
258
|
return customComponents;
|
|
739
259
|
}
|
|
@@ -741,175 +261,63 @@ function createTailorKitClient(options) {
|
|
|
741
261
|
return createReactTailorKitClient(options);
|
|
742
262
|
}
|
|
743
263
|
function createReactTailorKitClient(options) {
|
|
744
|
-
const wrappedComponents = {}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
};
|
|
757
|
-
wrappedComponents[name] = TailorKitComponent;
|
|
758
|
-
wrappedComponents[toComponentTagName(name)] = TailorKitComponent;
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
const clientConfig = {
|
|
762
|
-
baseUrl: options.baseUrl,
|
|
763
|
-
fetchClient: createTailorKitFetchClient({
|
|
764
|
-
baseUrl: options.baseUrl,
|
|
765
|
-
cache: options.cache,
|
|
766
|
-
fetch: options.fetch
|
|
767
|
-
}),
|
|
768
|
-
components: wrappedComponents,
|
|
769
|
-
theme
|
|
770
|
-
};
|
|
264
|
+
const wrappedComponents = createComponentRegistry(options.components ?? {}, (renderer) => {
|
|
265
|
+
return function TailorKitComponent({
|
|
266
|
+
children,
|
|
267
|
+
...props
|
|
268
|
+
}) {
|
|
269
|
+
return renderer({
|
|
270
|
+
props,
|
|
271
|
+
children
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
});
|
|
275
|
+
const clientConfig = createTailorKitClientConfig({ ...options, components: wrappedComponents });
|
|
771
276
|
const client = {
|
|
772
277
|
...clientConfig,
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
278
|
+
Provider: function TailorKitProvider({ children, apps }) {
|
|
279
|
+
const [store] = useState(
|
|
280
|
+
() => createTailorKitStore(client.baseUrl, apps, client.fetchClient)
|
|
281
|
+
);
|
|
282
|
+
useEffect4(() => {
|
|
283
|
+
store.setProvidedApps(apps);
|
|
284
|
+
}, [store, apps]);
|
|
285
|
+
useEffect4(() => () => store.previews.dispose(), [store]);
|
|
286
|
+
const context = useMemo8(() => ({ store, client }), [store]);
|
|
287
|
+
return createElement2(TailorkitContext.Provider, { value: context }, children);
|
|
288
|
+
},
|
|
289
|
+
RenderSlot: Object.assign(
|
|
290
|
+
function ClientRenderSlot(props) {
|
|
291
|
+
useTailorkitContext("RenderSlot", client);
|
|
292
|
+
return createElement2(RenderSlot, props);
|
|
777
293
|
},
|
|
778
294
|
{
|
|
779
|
-
Controlled: function
|
|
780
|
-
|
|
781
|
-
return createElement2(
|
|
295
|
+
Controlled: function ClientControlledRenderSlot(props) {
|
|
296
|
+
useTailorkitContext("RenderSlot.Controlled", client);
|
|
297
|
+
return createElement2(
|
|
298
|
+
RenderSlot.Controlled,
|
|
299
|
+
props
|
|
300
|
+
);
|
|
782
301
|
}
|
|
783
302
|
}
|
|
784
303
|
),
|
|
785
304
|
useApps: function useClientApps(options2) {
|
|
786
|
-
|
|
305
|
+
useTailorkitContext("useApps", client);
|
|
787
306
|
return useApps(options2);
|
|
788
307
|
},
|
|
789
308
|
useViews: function useClientViews(options2) {
|
|
790
|
-
|
|
309
|
+
useTailorkitContext("useViews", client);
|
|
791
310
|
return useViews(options2);
|
|
792
311
|
},
|
|
793
312
|
useViewContext: function useClientViewContext(view, options2) {
|
|
794
|
-
|
|
313
|
+
useTailorkitContext("useViewContext", client);
|
|
795
314
|
useViewContext(view, options2);
|
|
796
315
|
}
|
|
797
316
|
};
|
|
798
317
|
return client;
|
|
799
318
|
}
|
|
800
|
-
|
|
801
|
-
// src/components/root.tsx
|
|
802
|
-
import { useEffect as useEffect6, useMemo as useMemo8, useState as useState2 } from "react";
|
|
803
|
-
import { createTailorKitStore, toBaseUrl as toBaseUrl2 } from "@tailorkit/client-core";
|
|
804
|
-
|
|
805
|
-
// src/components/render.tsx
|
|
806
|
-
import { cloneElement, createElement as createElement3, isValidElement, useMemo as useMemo7 } from "react";
|
|
807
|
-
function useRender({
|
|
808
|
-
defaultTagName,
|
|
809
|
-
props,
|
|
810
|
-
render
|
|
811
|
-
}) {
|
|
812
|
-
return useMemo7(() => {
|
|
813
|
-
if (render) {
|
|
814
|
-
if (!isValidElement(render)) {
|
|
815
|
-
throw new Error("The render prop must be a valid React element.");
|
|
816
|
-
}
|
|
817
|
-
return cloneElement(render, mergeProps(render.props, props));
|
|
818
|
-
}
|
|
819
|
-
return createElement3(defaultTagName, props);
|
|
820
|
-
}, [defaultTagName, props, render]);
|
|
821
|
-
}
|
|
822
|
-
function mergeProps(...propSets) {
|
|
823
|
-
const merged = {};
|
|
824
|
-
for (const props of propSets) {
|
|
825
|
-
if (!props) {
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
for (const [key, value] of Object.entries(props)) {
|
|
829
|
-
if (value === void 0) {
|
|
830
|
-
continue;
|
|
831
|
-
}
|
|
832
|
-
const existing = merged[key];
|
|
833
|
-
if (key === "className" && existing && value) {
|
|
834
|
-
merged[key] = `${existing} ${value}`;
|
|
835
|
-
continue;
|
|
836
|
-
}
|
|
837
|
-
if (key === "style" && existing && value) {
|
|
838
|
-
merged[key] = {
|
|
839
|
-
...existing,
|
|
840
|
-
...value
|
|
841
|
-
};
|
|
842
|
-
continue;
|
|
843
|
-
}
|
|
844
|
-
if (key === "ref" && existing && value) {
|
|
845
|
-
merged[key] = composeRefs(existing, value);
|
|
846
|
-
continue;
|
|
847
|
-
}
|
|
848
|
-
if (isEventHandler(key) && typeof existing === "function" && typeof value === "function") {
|
|
849
|
-
merged[key] = (...args) => {
|
|
850
|
-
existing(...args);
|
|
851
|
-
const event = args[0];
|
|
852
|
-
if (!event?.defaultPrevented) {
|
|
853
|
-
value(...args);
|
|
854
|
-
}
|
|
855
|
-
};
|
|
856
|
-
continue;
|
|
857
|
-
}
|
|
858
|
-
merged[key] = value;
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
return merged;
|
|
862
|
-
}
|
|
863
|
-
function composeRefs(...refs) {
|
|
864
|
-
return (node) => {
|
|
865
|
-
for (const ref of refs) {
|
|
866
|
-
if (typeof ref === "function") {
|
|
867
|
-
ref(node);
|
|
868
|
-
} else if (ref) {
|
|
869
|
-
ref.current = node;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
};
|
|
873
|
-
}
|
|
874
|
-
function isEventHandler(key) {
|
|
875
|
-
return /^on[A-Z]/u.test(key);
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// src/components/root.tsx
|
|
879
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
880
|
-
function Root({ apps: appsProp, children, render, client, ...props }) {
|
|
881
|
-
const baseUrl = toBaseUrl2(client.baseUrl).toString();
|
|
882
|
-
const [previous, setStore] = useState2(() => ({
|
|
883
|
-
store: createTailorKitStore(baseUrl, appsProp, client.fetchClient),
|
|
884
|
-
fetchClient: client.fetchClient
|
|
885
|
-
}));
|
|
886
|
-
const previousStore = previous.store;
|
|
887
|
-
let store = previousStore;
|
|
888
|
-
if (previousStore.baseUrl.toString() !== baseUrl || previous.fetchClient !== client.fetchClient) {
|
|
889
|
-
store = createTailorKitStore(baseUrl, appsProp, client.fetchClient);
|
|
890
|
-
setStore({ store, fetchClient: client.fetchClient });
|
|
891
|
-
}
|
|
892
|
-
useEffect6(() => {
|
|
893
|
-
store.setProvidedApps(appsProp);
|
|
894
|
-
}, [store, appsProp]);
|
|
895
|
-
useEffect6(() => () => store.previews.dispose(), [store]);
|
|
896
|
-
const context = useMemo8(
|
|
897
|
-
() => ({
|
|
898
|
-
store,
|
|
899
|
-
client
|
|
900
|
-
}),
|
|
901
|
-
[store, client]
|
|
902
|
-
);
|
|
903
|
-
const element = render ? useRender({
|
|
904
|
-
defaultTagName: "div",
|
|
905
|
-
props: mergeProps({ children }, props),
|
|
906
|
-
render
|
|
907
|
-
}) : children;
|
|
908
|
-
return /* @__PURE__ */ jsx4(TailorRootContext.Provider, { value: context, children: element });
|
|
909
|
-
}
|
|
910
319
|
export {
|
|
911
|
-
|
|
912
|
-
Slot,
|
|
320
|
+
RenderSlot,
|
|
913
321
|
components,
|
|
914
322
|
createTailorKitClient,
|
|
915
323
|
primitives
|