@tailorkit/react 0.1.0-beta.14 → 0.1.0-beta.16
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 +1 -1
- package/dist/components/context.d.ts +3 -3
- package/dist/components/root.d.ts +2 -2
- package/dist/hooks/use-apps.d.ts +6 -3
- package/dist/hooks/use-view.d.ts +5 -4
- package/dist/index.d.ts +4 -5
- package/dist/index.js +195 -89
- package/dist/preview-manager.d.ts +1 -1
- package/dist/remote-view.d.ts +5 -1
- package/dist/scope-query.d.ts +5 -0
- package/dist/store.d.ts +4 -2
- package/dist/{tailor-kit.d.ts → tailorkit.d.ts} +25 -21
- package/package.json +9 -9
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { TailorKitStore } from "../store";
|
|
2
|
-
import type {
|
|
2
|
+
import type { TailorKitClientConfig } from "../tailorkit";
|
|
3
3
|
export interface TailorRootContextValue {
|
|
4
4
|
store: TailorKitStore;
|
|
5
|
-
client:
|
|
5
|
+
client: TailorKitClientConfig;
|
|
6
6
|
}
|
|
7
7
|
export declare const TailorRootContext: import("react").Context<TailorRootContextValue | null>;
|
|
8
|
-
export declare function useTailorRootContext(component: string): TailorRootContextValue;
|
|
8
|
+
export declare function useTailorRootContext(component: string, expectedClient?: TailorKitClientConfig): TailorRootContextValue;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
-
import type { TailorKitApp,
|
|
2
|
+
import type { TailorKitApp, TailorKitClientConfig } from "../tailorkit";
|
|
3
3
|
import type { ComponentProps } from "./render";
|
|
4
4
|
export interface RootProps extends ComponentProps<"div"> {
|
|
5
5
|
apps?: TailorKitApp[];
|
|
6
6
|
children?: ReactNode;
|
|
7
|
-
client:
|
|
7
|
+
client: TailorKitClientConfig;
|
|
8
8
|
}
|
|
9
9
|
export declare function Root({ apps: appsProp, children, render, client, ...props }: RootProps): ReactNode;
|
package/dist/hooks/use-apps.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import type { TailorKitApp } from "../
|
|
1
|
+
import type { TailorKitApp } from "../tailorkit";
|
|
2
2
|
import type { TailorKitStore } from "../store";
|
|
3
|
+
export interface UseAppsOptions<TScopeNames extends string = string> {
|
|
4
|
+
scopes?: readonly TScopeNames[];
|
|
5
|
+
}
|
|
3
6
|
export interface UseAppsResult {
|
|
4
7
|
data: TailorKitApp[] | undefined;
|
|
5
8
|
error: Error | null;
|
|
@@ -10,5 +13,5 @@ export interface UseAppsResult {
|
|
|
10
13
|
refetch: () => Promise<void>;
|
|
11
14
|
status: "error" | "idle" | "loading" | "ready";
|
|
12
15
|
}
|
|
13
|
-
export declare function useApps(): UseAppsResult;
|
|
14
|
-
export declare function useAppsStore(store: TailorKitStore): UseAppsResult;
|
|
16
|
+
export declare function useApps(options?: UseAppsOptions): UseAppsResult;
|
|
17
|
+
export declare function useAppsStore(store: TailorKitStore, options?: UseAppsOptions): UseAppsResult;
|
package/dist/hooks/use-view.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { StandardJSONSchemaV1 } from "@standard-schema/spec";
|
|
2
2
|
import type { ViewDefinition } from "@tailorkit/core/schema";
|
|
3
|
-
|
|
3
|
+
type DefaultViews = Record<`/${string}`, ViewDefinition>;
|
|
4
4
|
export type ViewName<TViews extends Record<string, ViewDefinition>> = keyof TViews & string;
|
|
5
5
|
export type ViewContext<TView> = TView extends StandardJSONSchemaV1 ? StandardJSONSchemaV1.InferOutput<TView> : Record<string, never>;
|
|
6
6
|
interface ReadyViewOptions<TViews extends Record<string, ViewDefinition>, TView extends ViewName<TViews>> {
|
|
@@ -18,7 +18,8 @@ interface ErrorViewOptions<TView extends string> {
|
|
|
18
18
|
view: TView;
|
|
19
19
|
status: "error";
|
|
20
20
|
}
|
|
21
|
-
export type ViewOptions<TViews extends Record<string, ViewDefinition> =
|
|
22
|
-
export type ViewState<TViews extends Record<string, ViewDefinition> =
|
|
23
|
-
export
|
|
21
|
+
export type ViewOptions<TViews extends Record<string, ViewDefinition> = DefaultViews, TView extends ViewName<TViews> = ViewName<TViews>> = TView extends ViewName<TViews> ? ReadyViewOptions<TViews, TView> | LoadingViewOptions<TView> | ErrorViewOptions<TView> : never;
|
|
22
|
+
export type ViewState<TViews extends Record<string, ViewDefinition> = DefaultViews, TView extends ViewName<TViews> = ViewName<TViews>> = Omit<ReadyViewOptions<TViews, TView>, "view"> | Omit<LoadingViewOptions<TView>, "view"> | Omit<ErrorViewOptions<TView>, "view">;
|
|
23
|
+
export type UseView<TViews extends Record<string, ViewDefinition>> = <TView extends ViewName<TViews>>(view: TView, options: ViewState<TViews, NoInfer<TView>>) => void;
|
|
24
|
+
export declare function useView<TViews extends Record<string, ViewDefinition> = DefaultViews, TView extends ViewName<TViews> = ViewName<TViews>>(view: TView, options: ViewState<TViews, NoInfer<TView>>): void;
|
|
24
25
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export { AppView } from "./components/app-view";
|
|
2
|
-
export { components, createTailorKitClient } from "./
|
|
3
|
-
export type { AppViewProps, TailorKitApp, TailorKitInstance,
|
|
2
|
+
export { components, createTailorKitClient } from "./tailorkit";
|
|
3
|
+
export type { AppViewProps, TailorKitApp, TailorKitClientConfig, TailorKitInstance, } from "./tailorkit";
|
|
4
4
|
export { Root } from "./components/root";
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export type { ViewOptions, ViewState } from "./hooks/use-view";
|
|
5
|
+
export type { UseAppsOptions, UseAppsResult } from "./hooks/use-apps";
|
|
6
|
+
export type { UseView, ViewOptions, ViewState } from "./hooks/use-view";
|
|
8
7
|
export { primitives } from "./primitives";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/components/app-view.tsx
|
|
2
|
+
import { createSessionProvider } from "@tailorkit/app/client";
|
|
2
3
|
import { useCallback as useCallback2, useEffect as useEffect2, useId as useId2, useMemo as useMemo3, useRef as useRef3, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
3
4
|
import { isViewAncestor as isViewAncestor2 } from "@tailorkit/core/views";
|
|
4
5
|
|
|
@@ -289,25 +290,61 @@ function createPreviewManager(baseUrl, onEnded) {
|
|
|
289
290
|
};
|
|
290
291
|
}
|
|
291
292
|
|
|
293
|
+
// src/scope-query.ts
|
|
294
|
+
function appendScopeSelection(url, scopes) {
|
|
295
|
+
if (scopes === void 0) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (scopes.length === 0) {
|
|
299
|
+
url.searchParams.append("scopes", "");
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
for (const scope of scopes) {
|
|
303
|
+
url.searchParams.append("scopes", scope);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
function normalizeScopeSelection(scopes) {
|
|
307
|
+
if (scopes === void 0) {
|
|
308
|
+
return { key: "*" };
|
|
309
|
+
}
|
|
310
|
+
const names = [...new Set(scopes)].sort();
|
|
311
|
+
return { key: JSON.stringify(names), scopes: names };
|
|
312
|
+
}
|
|
313
|
+
|
|
292
314
|
// src/store.ts
|
|
293
315
|
function createTailorKitStore(baseUrlInput, initialApps) {
|
|
294
316
|
const baseUrl = toBaseUrl(baseUrlInput);
|
|
295
317
|
const listeners = /* @__PURE__ */ new Set();
|
|
296
318
|
let providedApps = initialApps;
|
|
297
|
-
let
|
|
319
|
+
let unrequestedSnapshot = {
|
|
298
320
|
apps: initialApps ?? [],
|
|
299
321
|
error: null,
|
|
300
322
|
status: initialApps === void 0 ? "idle" : "ready"
|
|
301
323
|
};
|
|
324
|
+
const appsEntries = /* @__PURE__ */ new Map();
|
|
302
325
|
let metaSnapshot = {
|
|
303
326
|
assetsBaseUrl: null,
|
|
304
327
|
error: null,
|
|
305
328
|
schema: null,
|
|
306
329
|
status: "idle"
|
|
307
330
|
};
|
|
308
|
-
let fetchAppsPromise = null;
|
|
309
331
|
let fetchMetaPromise = null;
|
|
310
|
-
|
|
332
|
+
const getAppsEntry = (scopes) => {
|
|
333
|
+
const selection = normalizeScopeSelection(scopes);
|
|
334
|
+
let entry = appsEntries.get(selection.key);
|
|
335
|
+
if (!entry) {
|
|
336
|
+
entry = {
|
|
337
|
+
scopes: selection.scopes,
|
|
338
|
+
snapshot: unrequestedSnapshot,
|
|
339
|
+
promise: null,
|
|
340
|
+
requestId: 0,
|
|
341
|
+
requested: false,
|
|
342
|
+
subscribers: 0
|
|
343
|
+
};
|
|
344
|
+
appsEntries.set(selection.key, entry);
|
|
345
|
+
}
|
|
346
|
+
return entry;
|
|
347
|
+
};
|
|
311
348
|
const emit = () => {
|
|
312
349
|
for (const listener of listeners) {
|
|
313
350
|
listener();
|
|
@@ -321,55 +358,65 @@ function createTailorKitStore(baseUrlInput, initialApps) {
|
|
|
321
358
|
return;
|
|
322
359
|
}
|
|
323
360
|
providedApps = apps;
|
|
324
|
-
|
|
325
|
-
fetchAppsPromise = null;
|
|
326
|
-
appsSnapshot = {
|
|
361
|
+
unrequestedSnapshot = {
|
|
327
362
|
apps: apps ?? [],
|
|
328
363
|
error: null,
|
|
329
364
|
status: apps === void 0 ? "idle" : "ready"
|
|
330
365
|
};
|
|
366
|
+
for (const entry of appsEntries.values()) {
|
|
367
|
+
entry.requestId += 1;
|
|
368
|
+
entry.promise = null;
|
|
369
|
+
entry.snapshot = unrequestedSnapshot;
|
|
370
|
+
}
|
|
331
371
|
emit();
|
|
332
372
|
if (apps === void 0) {
|
|
333
|
-
|
|
373
|
+
for (const entry of appsEntries.values()) {
|
|
374
|
+
if (entry.requested && entry.subscribers > 0) {
|
|
375
|
+
void store.fetchApps({ scopes: entry.scopes });
|
|
376
|
+
}
|
|
377
|
+
}
|
|
334
378
|
}
|
|
335
379
|
},
|
|
336
380
|
fetchApps: (options = {}) => {
|
|
381
|
+
const entry = getAppsEntry(options.scopes);
|
|
382
|
+
entry.requested = true;
|
|
337
383
|
if (providedApps !== void 0) {
|
|
338
384
|
return Promise.resolve();
|
|
339
385
|
}
|
|
340
|
-
if (
|
|
341
|
-
return
|
|
386
|
+
if (entry.promise && !options.force) {
|
|
387
|
+
return entry.promise;
|
|
342
388
|
}
|
|
343
|
-
|
|
389
|
+
entry.snapshot = { ...entry.snapshot, status: "loading" };
|
|
344
390
|
emit();
|
|
345
|
-
const requestId = ++
|
|
391
|
+
const requestId = ++entry.requestId;
|
|
346
392
|
const appsUrl = new URL("apps", baseUrl);
|
|
347
|
-
|
|
393
|
+
appendScopeSelection(appsUrl, entry.scopes);
|
|
394
|
+
entry.promise = fetch(appsUrl).then(async (response) => {
|
|
348
395
|
if (!response.ok) {
|
|
349
396
|
throw new Error(`Unable to fetch TailorKit apps from ${baseUrl.toString()}.`);
|
|
350
397
|
}
|
|
351
398
|
const apps = await response.json();
|
|
352
|
-
if (requestId !==
|
|
399
|
+
if (requestId !== entry.requestId) {
|
|
353
400
|
return;
|
|
354
401
|
}
|
|
355
|
-
|
|
402
|
+
entry.snapshot = {
|
|
356
403
|
apps,
|
|
357
404
|
error: null,
|
|
358
405
|
status: "ready"
|
|
359
406
|
};
|
|
360
407
|
emit();
|
|
361
408
|
}).catch((error) => {
|
|
362
|
-
if (requestId !==
|
|
409
|
+
if (requestId !== entry.requestId) {
|
|
363
410
|
return;
|
|
364
411
|
}
|
|
365
|
-
|
|
366
|
-
...
|
|
412
|
+
entry.snapshot = {
|
|
413
|
+
...entry.snapshot,
|
|
367
414
|
error: error instanceof Error ? error : new Error(String(error)),
|
|
368
415
|
status: "error"
|
|
369
416
|
};
|
|
370
417
|
emit();
|
|
371
418
|
});
|
|
372
|
-
return
|
|
419
|
+
return entry.promise;
|
|
373
420
|
},
|
|
374
421
|
fetchMeta: () => {
|
|
375
422
|
if (fetchMetaPromise) {
|
|
@@ -399,19 +446,37 @@ function createTailorKitStore(baseUrlInput, initialApps) {
|
|
|
399
446
|
});
|
|
400
447
|
return fetchMetaPromise;
|
|
401
448
|
},
|
|
402
|
-
getAppsSnapshot: () =>
|
|
449
|
+
getAppsSnapshot: (scopes) => appsEntries.get(normalizeScopeSelection(scopes).key)?.snapshot ?? unrequestedSnapshot,
|
|
403
450
|
getMetaSnapshot: () => metaSnapshot,
|
|
404
451
|
subscribe: (listener) => {
|
|
405
452
|
listeners.add(listener);
|
|
406
453
|
return () => {
|
|
407
454
|
listeners.delete(listener);
|
|
408
455
|
};
|
|
456
|
+
},
|
|
457
|
+
subscribeApps: (scopes, listener) => {
|
|
458
|
+
const selection = normalizeScopeSelection(scopes);
|
|
459
|
+
const entry = getAppsEntry(selection.scopes);
|
|
460
|
+
entry.subscribers += 1;
|
|
461
|
+
listeners.add(listener);
|
|
462
|
+
return () => {
|
|
463
|
+
listeners.delete(listener);
|
|
464
|
+
entry.subscribers -= 1;
|
|
465
|
+
if (entry.subscribers === 0) {
|
|
466
|
+
entry.requestId += 1;
|
|
467
|
+
appsEntries.delete(selection.key);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
409
470
|
}
|
|
410
471
|
};
|
|
411
472
|
return {
|
|
412
473
|
...store,
|
|
413
474
|
previews: createPreviewManager(baseUrl, () => {
|
|
414
|
-
|
|
475
|
+
for (const entry of appsEntries.values()) {
|
|
476
|
+
if (entry.requested && entry.subscribers > 0) {
|
|
477
|
+
void store.fetchApps({ force: true, scopes: entry.scopes });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
415
480
|
})
|
|
416
481
|
};
|
|
417
482
|
}
|
|
@@ -437,11 +502,16 @@ function useStableContext(value) {
|
|
|
437
502
|
// src/components/context.ts
|
|
438
503
|
import { createContext, useContext } from "react";
|
|
439
504
|
var TailorRootContext = createContext(null);
|
|
440
|
-
function useTailorRootContext(component) {
|
|
505
|
+
function useTailorRootContext(component, expectedClient) {
|
|
441
506
|
const context = useContext(TailorRootContext);
|
|
442
507
|
if (!context) {
|
|
443
508
|
throw new Error(`${component} must be rendered inside Root.`);
|
|
444
509
|
}
|
|
510
|
+
if (expectedClient && context.client !== expectedClient) {
|
|
511
|
+
throw new Error(
|
|
512
|
+
`${component} was created for a different TailorKit client than the one passed to Root.`
|
|
513
|
+
);
|
|
514
|
+
}
|
|
445
515
|
return context;
|
|
446
516
|
}
|
|
447
517
|
|
|
@@ -791,6 +861,7 @@ var RemoteErrorBoundary = class extends Component {
|
|
|
791
861
|
function RemoteViewHost({
|
|
792
862
|
appUrl,
|
|
793
863
|
sourceText,
|
|
864
|
+
getBackendSession,
|
|
794
865
|
components: components2,
|
|
795
866
|
createIframe,
|
|
796
867
|
props
|
|
@@ -839,6 +910,7 @@ function RemoteViewHost({
|
|
|
839
910
|
const host = createIframeUiHost(appUrl, {
|
|
840
911
|
createIframe,
|
|
841
912
|
sourceText,
|
|
913
|
+
getBackendSession,
|
|
842
914
|
onError: (error2) => {
|
|
843
915
|
console.error("TailorKit remote app failed", error2);
|
|
844
916
|
setError(error2);
|
|
@@ -864,7 +936,7 @@ function RemoteViewHost({
|
|
|
864
936
|
hostRef.current = null;
|
|
865
937
|
host.destroy();
|
|
866
938
|
};
|
|
867
|
-
}, [appUrl, createIframe, sourceText, store]);
|
|
939
|
+
}, [appUrl, createIframe, sourceText, getBackendSession, store]);
|
|
868
940
|
if (status === "error" && error) {
|
|
869
941
|
return createElement("div", null, formatError(error));
|
|
870
942
|
}
|
|
@@ -939,6 +1011,10 @@ var AppView = ({
|
|
|
939
1011
|
const { store, client } = useTailorRootContext("AppView");
|
|
940
1012
|
const { theme, components: wrappedComponents } = client;
|
|
941
1013
|
const reactId = useId2();
|
|
1014
|
+
const getBackendSession = useMemo3(
|
|
1015
|
+
() => createSessionProvider({ baseUrl: store.baseUrl, appId: app.id }),
|
|
1016
|
+
[store.baseUrl, app.id]
|
|
1017
|
+
);
|
|
942
1018
|
const currentView = useSyncExternalStore2(
|
|
943
1019
|
store.views.subscribe,
|
|
944
1020
|
store.views.getSnapshot,
|
|
@@ -1014,6 +1090,7 @@ var AppView = ({
|
|
|
1014
1090
|
{
|
|
1015
1091
|
appUrl: (appUrl ?? new URL(`preview/${previewSessionId}/client.js`, store.baseUrl)).toString(),
|
|
1016
1092
|
sourceText: previewSnapshot.source ?? void 0,
|
|
1093
|
+
getBackendSession,
|
|
1017
1094
|
components: wrappedComponents,
|
|
1018
1095
|
createIframe,
|
|
1019
1096
|
props: runtimeProps
|
|
@@ -1030,12 +1107,77 @@ function resolveAppUrl(app, baseUrl, assetsBaseUrl) {
|
|
|
1030
1107
|
return null;
|
|
1031
1108
|
}
|
|
1032
1109
|
return new URL(
|
|
1033
|
-
`projects/${app.projectId}/apps/${app.id}/deployments/${app.currentDeployment.id}/
|
|
1110
|
+
`projects/${app.projectId}/apps/${app.id}/deployments/${app.currentDeployment.id}/client/client.js`,
|
|
1034
1111
|
toBaseUrl(assetsBaseUrl)
|
|
1035
1112
|
);
|
|
1036
1113
|
}
|
|
1037
1114
|
|
|
1038
|
-
// src/
|
|
1115
|
+
// src/tailorkit.tsx
|
|
1116
|
+
import { createElement as createElement2 } from "react";
|
|
1117
|
+
|
|
1118
|
+
// src/hooks/use-view.ts
|
|
1119
|
+
import { useEffect as useEffect3, useMemo as useMemo4 } from "react";
|
|
1120
|
+
function useView(view, options) {
|
|
1121
|
+
const { store } = useTailorRootContext("useView");
|
|
1122
|
+
const id = useMemo4(() => /* @__PURE__ */ Symbol("tailorkit-current-view"), []);
|
|
1123
|
+
const status = options.status ?? "ready";
|
|
1124
|
+
const context = "context" in options ? options.context : void 0;
|
|
1125
|
+
const contextSnapshot = useStableContext(context);
|
|
1126
|
+
useEffect3(
|
|
1127
|
+
() => () => {
|
|
1128
|
+
store.views.unregister(id);
|
|
1129
|
+
},
|
|
1130
|
+
[id, store]
|
|
1131
|
+
);
|
|
1132
|
+
useEffect3(() => {
|
|
1133
|
+
store.views.register({
|
|
1134
|
+
context: contextSnapshot,
|
|
1135
|
+
id,
|
|
1136
|
+
view,
|
|
1137
|
+
status
|
|
1138
|
+
});
|
|
1139
|
+
}, [contextSnapshot, id, view, status, store]);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// src/hooks/use-apps.ts
|
|
1143
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1144
|
+
function useApps(options = {}) {
|
|
1145
|
+
return useAppsStore(useTailorRootContext("useApps").store, options);
|
|
1146
|
+
}
|
|
1147
|
+
function useAppsStore(store, options = {}) {
|
|
1148
|
+
const selection = normalizeScopeSelection(options.scopes);
|
|
1149
|
+
const subscribe = useCallback3(
|
|
1150
|
+
(listener) => store.subscribeApps(selection.scopes, listener),
|
|
1151
|
+
[store, selection.key]
|
|
1152
|
+
);
|
|
1153
|
+
const snapshot = useSyncExternalStore3(
|
|
1154
|
+
subscribe,
|
|
1155
|
+
() => store.getAppsSnapshot(selection.scopes),
|
|
1156
|
+
() => store.getAppsSnapshot(selection.scopes)
|
|
1157
|
+
);
|
|
1158
|
+
useEffect4(() => {
|
|
1159
|
+
void store.fetchApps({ scopes: selection.scopes });
|
|
1160
|
+
}, [store, selection.key]);
|
|
1161
|
+
const refetch = useCallback3(
|
|
1162
|
+
() => store.fetchApps({ force: true, scopes: selection.scopes }),
|
|
1163
|
+
[store, selection.key]
|
|
1164
|
+
);
|
|
1165
|
+
return toUseAppsResult(snapshot, refetch);
|
|
1166
|
+
}
|
|
1167
|
+
function toUseAppsResult(snapshot, refetch) {
|
|
1168
|
+
return {
|
|
1169
|
+
data: snapshot.status === "ready" ? snapshot.apps : void 0,
|
|
1170
|
+
error: snapshot.error,
|
|
1171
|
+
isError: snapshot.status === "error",
|
|
1172
|
+
isLoading: snapshot.status === "loading",
|
|
1173
|
+
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
1174
|
+
isSuccess: snapshot.status === "ready",
|
|
1175
|
+
refetch,
|
|
1176
|
+
status: snapshot.status
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// src/tailorkit.tsx
|
|
1039
1181
|
var componentTagPrefix = "tailorkit-";
|
|
1040
1182
|
var toComponentTagName = (name) => `${componentTagPrefix}${name.replaceAll(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[\s_]+/gu, "-").toLowerCase()}`;
|
|
1041
1183
|
function components(_schema, customComponents) {
|
|
@@ -1062,31 +1204,51 @@ function createReactTailorKitClient(options) {
|
|
|
1062
1204
|
wrappedComponents[toComponentTagName(name)] = TailorKitComponent;
|
|
1063
1205
|
}
|
|
1064
1206
|
}
|
|
1065
|
-
|
|
1207
|
+
const clientConfig = {
|
|
1066
1208
|
baseUrl: options.baseUrl,
|
|
1067
1209
|
components: wrappedComponents,
|
|
1068
1210
|
theme
|
|
1069
1211
|
};
|
|
1212
|
+
const client = {
|
|
1213
|
+
...clientConfig,
|
|
1214
|
+
AppView: function ClientAppView(props) {
|
|
1215
|
+
useTailorRootContext("AppView", client);
|
|
1216
|
+
const TypedReactAppView = AppView;
|
|
1217
|
+
return createElement2(
|
|
1218
|
+
TypedReactAppView,
|
|
1219
|
+
props
|
|
1220
|
+
);
|
|
1221
|
+
},
|
|
1222
|
+
useApps: function useClientApps(options2) {
|
|
1223
|
+
useTailorRootContext("useApps", client);
|
|
1224
|
+
return useApps(options2);
|
|
1225
|
+
},
|
|
1226
|
+
useView: function useClientView(view, options2) {
|
|
1227
|
+
useTailorRootContext("useView", client);
|
|
1228
|
+
useView(view, options2);
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
return client;
|
|
1070
1232
|
}
|
|
1071
1233
|
|
|
1072
1234
|
// src/components/root.tsx
|
|
1073
|
-
import { useEffect as
|
|
1235
|
+
import { useEffect as useEffect5, useMemo as useMemo6, useState as useState2 } from "react";
|
|
1074
1236
|
|
|
1075
1237
|
// src/components/render.tsx
|
|
1076
|
-
import { cloneElement, createElement as
|
|
1238
|
+
import { cloneElement, createElement as createElement3, isValidElement, useMemo as useMemo5 } from "react";
|
|
1077
1239
|
function useRender({
|
|
1078
1240
|
defaultTagName,
|
|
1079
1241
|
props,
|
|
1080
1242
|
render
|
|
1081
1243
|
}) {
|
|
1082
|
-
return
|
|
1244
|
+
return useMemo5(() => {
|
|
1083
1245
|
if (render) {
|
|
1084
1246
|
if (!isValidElement(render)) {
|
|
1085
1247
|
throw new Error("The render prop must be a valid React element.");
|
|
1086
1248
|
}
|
|
1087
1249
|
return cloneElement(render, mergeProps(render.props, props));
|
|
1088
1250
|
}
|
|
1089
|
-
return
|
|
1251
|
+
return createElement3(defaultTagName, props);
|
|
1090
1252
|
}, [defaultTagName, props, render]);
|
|
1091
1253
|
}
|
|
1092
1254
|
function mergeProps(...propSets) {
|
|
@@ -1155,11 +1317,11 @@ function Root({ apps: appsProp, children, render, client, ...props }) {
|
|
|
1155
1317
|
store = createTailorKitStore(baseUrl, appsProp);
|
|
1156
1318
|
setStore(store);
|
|
1157
1319
|
}
|
|
1158
|
-
|
|
1320
|
+
useEffect5(() => {
|
|
1159
1321
|
store.setProvidedApps(appsProp);
|
|
1160
1322
|
}, [store, appsProp]);
|
|
1161
|
-
|
|
1162
|
-
const context =
|
|
1323
|
+
useEffect5(() => () => store.previews.dispose(), [store]);
|
|
1324
|
+
const context = useMemo6(
|
|
1163
1325
|
() => ({
|
|
1164
1326
|
store,
|
|
1165
1327
|
client
|
|
@@ -1173,66 +1335,10 @@ function Root({ apps: appsProp, children, render, client, ...props }) {
|
|
|
1173
1335
|
}) : children;
|
|
1174
1336
|
return /* @__PURE__ */ jsx4(TailorRootContext.Provider, { value: context, children: element });
|
|
1175
1337
|
}
|
|
1176
|
-
|
|
1177
|
-
// src/hooks/use-apps.ts
|
|
1178
|
-
import { useCallback as useCallback3, useEffect as useEffect4, useSyncExternalStore as useSyncExternalStore3 } from "react";
|
|
1179
|
-
function useApps() {
|
|
1180
|
-
return useAppsStore(useTailorRootContext("useApps").store);
|
|
1181
|
-
}
|
|
1182
|
-
function useAppsStore(store) {
|
|
1183
|
-
const snapshot = useSyncExternalStore3(
|
|
1184
|
-
store.subscribe,
|
|
1185
|
-
store.getAppsSnapshot,
|
|
1186
|
-
store.getAppsSnapshot
|
|
1187
|
-
);
|
|
1188
|
-
useEffect4(() => {
|
|
1189
|
-
void store.fetchApps();
|
|
1190
|
-
}, [store]);
|
|
1191
|
-
const refetch = useCallback3(() => store.fetchApps({ force: true }), [store]);
|
|
1192
|
-
return toUseAppsResult(snapshot, refetch);
|
|
1193
|
-
}
|
|
1194
|
-
function toUseAppsResult(snapshot, refetch) {
|
|
1195
|
-
return {
|
|
1196
|
-
data: snapshot.status === "ready" ? snapshot.apps : void 0,
|
|
1197
|
-
error: snapshot.error,
|
|
1198
|
-
isError: snapshot.status === "error",
|
|
1199
|
-
isLoading: snapshot.status === "loading",
|
|
1200
|
-
isPending: snapshot.status === "idle" || snapshot.status === "loading",
|
|
1201
|
-
isSuccess: snapshot.status === "ready",
|
|
1202
|
-
refetch,
|
|
1203
|
-
status: snapshot.status
|
|
1204
|
-
};
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
// src/hooks/use-view.ts
|
|
1208
|
-
import { useEffect as useEffect5, useMemo as useMemo6 } from "react";
|
|
1209
|
-
function useView(view, options) {
|
|
1210
|
-
const { store } = useTailorRootContext("useView");
|
|
1211
|
-
const id = useMemo6(() => /* @__PURE__ */ Symbol("tailorkit-current-view"), []);
|
|
1212
|
-
const status = options.status ?? "ready";
|
|
1213
|
-
const context = "context" in options ? options.context : void 0;
|
|
1214
|
-
const contextSnapshot = useStableContext(context);
|
|
1215
|
-
useEffect5(
|
|
1216
|
-
() => () => {
|
|
1217
|
-
store.views.unregister(id);
|
|
1218
|
-
},
|
|
1219
|
-
[id, store]
|
|
1220
|
-
);
|
|
1221
|
-
useEffect5(() => {
|
|
1222
|
-
store.views.register({
|
|
1223
|
-
context: contextSnapshot,
|
|
1224
|
-
id,
|
|
1225
|
-
view,
|
|
1226
|
-
status
|
|
1227
|
-
});
|
|
1228
|
-
}, [contextSnapshot, id, view, status, store]);
|
|
1229
|
-
}
|
|
1230
1338
|
export {
|
|
1231
1339
|
AppView,
|
|
1232
1340
|
Root,
|
|
1233
1341
|
components,
|
|
1234
1342
|
createTailorKitClient,
|
|
1235
|
-
primitives
|
|
1236
|
-
useApps,
|
|
1237
|
-
useView
|
|
1343
|
+
primitives
|
|
1238
1344
|
};
|
package/dist/remote-view.d.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import type { Session } from "@tailorkit/app/client";
|
|
1
2
|
import type { ReactNode } from "react";
|
|
2
3
|
interface RemoteViewHostProps {
|
|
3
4
|
appUrl: string | URL;
|
|
4
5
|
sourceText?: string;
|
|
6
|
+
getBackendSession?: (options: {
|
|
7
|
+
refresh: boolean;
|
|
8
|
+
}) => Promise<Session>;
|
|
5
9
|
components: Record<string, unknown>;
|
|
6
10
|
createIframe?: () => HTMLIFrameElement;
|
|
7
11
|
props?: Record<string, unknown>;
|
|
8
12
|
}
|
|
9
|
-
export declare function RemoteViewHost({ appUrl, sourceText, components, createIframe, props, }: RemoteViewHostProps): ReactNode;
|
|
13
|
+
export declare function RemoteViewHost({ appUrl, sourceText, getBackendSession, components, createIframe, props, }: RemoteViewHostProps): ReactNode;
|
|
10
14
|
interface RemoteViewProps {
|
|
11
15
|
nodeId: string;
|
|
12
16
|
}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TailorKitSchemaSpecType } from "@tailorkit/core/spec";
|
|
2
|
-
import type { TailorKitApp } from "./
|
|
2
|
+
import type { TailorKitApp } from "./tailorkit";
|
|
3
3
|
export interface TailorKitAppsSnapshot {
|
|
4
4
|
apps: TailorKitApp[];
|
|
5
5
|
error: Error | null;
|
|
@@ -23,11 +23,13 @@ export declare function createTailorKitStore(baseUrlInput: string | URL, initial
|
|
|
23
23
|
setProvidedApps(apps: TailorKitApp[] | undefined): void;
|
|
24
24
|
fetchApps: (options?: {
|
|
25
25
|
force?: boolean;
|
|
26
|
+
scopes?: readonly string[];
|
|
26
27
|
}) => Promise<void>;
|
|
27
28
|
fetchMeta: () => Promise<void>;
|
|
28
|
-
getAppsSnapshot: () => TailorKitAppsSnapshot;
|
|
29
|
+
getAppsSnapshot: (scopes?: readonly string[]) => TailorKitAppsSnapshot;
|
|
29
30
|
getMetaSnapshot: () => TailorKitMetaSnapshot;
|
|
30
31
|
subscribe: (listener: () => void) => (() => void);
|
|
32
|
+
subscribeApps: (scopes: readonly string[] | undefined, listener: () => void) => (() => void);
|
|
31
33
|
previews: {
|
|
32
34
|
getSnapshot: (sessionId: string) => import("./preview-manager").PreviewSnapshot;
|
|
33
35
|
updateApp: (app: TailorKitApp) => void;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { TailorKitTheme, CallbackMap, ComponentDefinition, ComponentProps, Schema, ViewDefinition, SlotDefinitions, TailorKitSchema } from "@tailorkit/core/schema";
|
|
3
3
|
import type { primitives } from "./primitives";
|
|
4
|
-
import type {
|
|
4
|
+
import type { UseView, ViewName, ViewOptions } from "./hooks/use-view";
|
|
5
|
+
import type { UseAppsOptions, UseAppsResult } from "./hooks/use-apps";
|
|
5
6
|
type AnyComponentDefinition = ComponentDefinition<Schema | undefined, CallbackMap, boolean | undefined>;
|
|
6
7
|
type ComponentRenderer<TComponent extends AnyComponentDefinition> = (args: {
|
|
7
8
|
props: ComponentProps<TComponent>;
|
|
@@ -49,32 +50,26 @@ type AppViewViewProps<TViews extends Record<string, ViewDefinition>, TView exten
|
|
|
49
50
|
view?: never;
|
|
50
51
|
status?: never;
|
|
51
52
|
} | ViewOptions<TViews, TView>;
|
|
52
|
-
export type AppViewProps<TViews extends Record<string, ViewDefinition> =
|
|
53
|
-
[V in
|
|
53
|
+
export type AppViewProps<TViews extends Record<string, ViewDefinition> = Record<`/${string}`, ViewDefinition>, TView extends ViewName<TViews> = ViewName<TViews>, TSlots extends SlotDefinitions = SlotDefinitions> = {
|
|
54
|
+
[V in keyof TSlots & string]: AppViewBaseProps & {
|
|
54
55
|
slot: V;
|
|
55
|
-
} & AppViewViewProps<TViews, Extract<TView, SlotView<V>>>;
|
|
56
|
-
}[
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
export type RegisteredViews = Register extends {
|
|
60
|
-
client: TailorKitInstance<infer S>;
|
|
61
|
-
} ? S : Record<`/${string}`, ViewDefinition>;
|
|
62
|
-
type RegisteredSlotMap = Register extends {
|
|
63
|
-
client: {
|
|
64
|
-
readonly $slots?: infer V;
|
|
65
|
-
};
|
|
66
|
-
} ? V : SlotDefinitions;
|
|
67
|
-
export type RegisteredSlots = keyof RegisteredSlotMap & string;
|
|
68
|
-
type SlotView<V extends RegisteredSlots> = RegisteredSlotMap[V] extends {
|
|
56
|
+
} & AppViewViewProps<TViews, Extract<TView, SlotView<TSlots, V>>>;
|
|
57
|
+
}[keyof TSlots & string];
|
|
58
|
+
type SlotView<TSlots extends SlotDefinitions, V extends keyof TSlots & string> = TSlots[V] extends {
|
|
69
59
|
views: readonly (infer P)[];
|
|
70
60
|
} ? Extract<P, string> : never;
|
|
71
|
-
export interface
|
|
72
|
-
readonly $slots?: TSlots;
|
|
73
|
-
readonly $views?: TViews;
|
|
61
|
+
export interface TailorKitClientConfig {
|
|
74
62
|
readonly baseUrl: string | URL;
|
|
75
63
|
readonly components: Record<string, unknown>;
|
|
76
64
|
readonly theme: TailorKitTheme;
|
|
77
65
|
}
|
|
66
|
+
export interface TailorKitInstance<TViews extends Record<string, ViewDefinition> = Record<string, ViewDefinition>, TSlots extends SlotDefinitions = SlotDefinitions, TScopeNames extends string = string> extends TailorKitClientConfig {
|
|
67
|
+
readonly $slots?: TSlots;
|
|
68
|
+
readonly $views?: TViews;
|
|
69
|
+
readonly AppView: (props: AppViewProps<TViews, ViewName<TViews>, TSlots>) => ReactNode;
|
|
70
|
+
readonly useApps: (options?: UseAppsOptions<TScopeNames>) => UseAppsResult;
|
|
71
|
+
readonly useView: UseView<TViews>;
|
|
72
|
+
}
|
|
78
73
|
type PrimitiveRenderers = typeof primitives;
|
|
79
74
|
type CustomComponentRenderers<TComponents extends Record<string, AnyComponentDefinition>> = {
|
|
80
75
|
[TName in Exclude<keyof TComponents, keyof PrimitiveRenderers>]?: ComponentRenderer<TComponents[TName]>;
|
|
@@ -93,6 +88,15 @@ type ServerComponents<TTailor extends TailorKitServerShape> = {
|
|
|
93
88
|
[TName in keyof ServerComponentMap<TTailor>]: ServerComponentMap<TTailor>[TName] extends AnyComponentDefinition ? ServerComponentMap<TTailor>[TName] : never;
|
|
94
89
|
};
|
|
95
90
|
type ServerViewMap<TTailor extends TailorKitServerShape> = TTailor["$internal"]["schema"]["contexts"];
|
|
91
|
+
type ServerScopeNames<TTailor extends TailorKitServerShape> = TTailor extends {
|
|
92
|
+
handler: (request: Request, options: infer TOptions) => unknown;
|
|
93
|
+
} ? TOptions extends {
|
|
94
|
+
authenticate: infer TAuthenticate;
|
|
95
|
+
} ? TAuthenticate extends (...args: infer _TArgs) => infer TResult ? Extract<Awaited<TResult>, {
|
|
96
|
+
scopes: unknown;
|
|
97
|
+
}> extends {
|
|
98
|
+
scopes: infer TScopes;
|
|
99
|
+
} ? keyof TScopes & string : never : never : never : never;
|
|
96
100
|
type ServerViews<TTailor extends TailorKitServerShape> = {
|
|
97
101
|
[TName in keyof ServerViewMap<TTailor>]: ServerViewMap<TTailor>[TName] extends ViewDefinition ? ServerViewMap<TTailor>[TName] : never;
|
|
98
102
|
};
|
|
@@ -102,5 +106,5 @@ export declare function createTailorKitClient<TTailor extends TailorKitServerSha
|
|
|
102
106
|
theme?: TailorKitTheme;
|
|
103
107
|
}): TailorKitInstance<ServerViews<TTailor>, TTailor extends {
|
|
104
108
|
readonly $slots?: infer V extends SlotDefinitions;
|
|
105
|
-
} ? V : SlotDefinitions
|
|
109
|
+
} ? V : SlotDefinitions, ServerScopeNames<TTailor>>;
|
|
106
110
|
export type { ViewOptions } from "./hooks/use-view";
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailorkit/react",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.16",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "git+https://github.com/
|
|
7
|
+
"url": "git+https://github.com/tailorkit-labs/TailorKit.git",
|
|
8
8
|
"directory": "packages/react"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
@@ -23,21 +23,21 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@floating-ui/react-dom": "^2.1.9",
|
|
25
25
|
"@standard-schema/spec": "^1.1.0",
|
|
26
|
-
"@tailorkit/
|
|
27
|
-
"@tailorkit/
|
|
28
|
-
"@tailorkit/
|
|
26
|
+
"@tailorkit/app": "0.1.0-beta.16",
|
|
27
|
+
"@tailorkit/client-platform": "0.1.0-beta.16",
|
|
28
|
+
"@tailorkit/core": "0.1.0-beta.16",
|
|
29
|
+
"@tailorkit/sandbox": "0.1.0-beta.16"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@tailorkit/config": "0.0.0",
|
|
32
33
|
"@testing-library/react": "^16.3.3",
|
|
33
|
-
"@types/node": "26.
|
|
34
|
+
"@types/node": "26.6.3",
|
|
34
35
|
"@types/react": "^19.3.0",
|
|
35
36
|
"happy-dom": "^20.14.5",
|
|
36
37
|
"react": "^19.3.0",
|
|
37
38
|
"react-dom": "^19.3.0",
|
|
38
39
|
"tsup": "^8.5.1",
|
|
39
|
-
"typescript": "^7.0.2"
|
|
40
|
-
"vitest": "^5.0.0"
|
|
40
|
+
"typescript": "^7.0.2"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"react": ">=19.2.6"
|
|
@@ -45,6 +45,6 @@
|
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsup src/index.ts --format esm --target node20 --clean && tsc -p tsconfig.build.json",
|
|
47
47
|
"check-types": "tsc --noEmit",
|
|
48
|
-
"test": "
|
|
48
|
+
"test": "vp test run"
|
|
49
49
|
}
|
|
50
50
|
}
|