@tailorkit/react 0.1.0-beta.21 → 0.1.0-beta.22

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.
@@ -1,6 +1,6 @@
1
1
  import type { TailorKitApp } from "../tailorkit";
2
- import type { FetchCacheOptions, TailorKitAppsSnapshot, TailorKitStore } from "@tailorkit/client-core";
3
- export interface UseAppsOptions<TScopeNames extends string = string> extends Pick<FetchCacheOptions, "staleTime"> {
2
+ import type { TailorKitAppsSnapshot, TailorKitStore } from "@tailorkit/client-core";
3
+ export interface UseAppsOptions<TScopeNames extends string = string> {
4
4
  scopes?: readonly TScopeNames[];
5
5
  appIds?: readonly string[];
6
6
  }
@@ -18,5 +18,5 @@ export interface UseAppsResult {
18
18
  export declare function useApps(options?: UseAppsOptions): UseAppsResult;
19
19
  export declare function useAppsStore(store: TailorKitStore, options?: UseAppsOptions): UseAppsResult;
20
20
  export { matchesApp } from "@tailorkit/client-core";
21
- export declare function useAppsSnapshot(store: TailorKitStore, options?: Pick<FetchCacheOptions, "staleTime">): TailorKitAppsSnapshot;
21
+ export declare function useAppsSnapshot(store: TailorKitStore): TailorKitAppsSnapshot;
22
22
  export declare function toUseAppsResult(snapshot: TailorKitAppsSnapshot, refetch: () => Promise<void>): UseAppsResult;
@@ -0,0 +1,13 @@
1
+ import type { TailorKitApp, SlotItem } from "@tailorkit/client-core";
2
+ import type { UseAppsOptions, UseAppsResult } from "./use-apps";
3
+ export type { SlotItem } from "@tailorkit/client-core";
4
+ export interface UseSlotOptions<TScopeNames extends string = string, TSlot extends string = string> extends UseAppsOptions<TScopeNames> {
5
+ slot: TSlot;
6
+ }
7
+ export interface UseSlotResult<TMultiple extends boolean = boolean> extends Omit<UseAppsResult, "data"> {
8
+ data: SlotItem<TMultiple>[] | undefined;
9
+ }
10
+ /** List apps for single-view slots or resolve instances for multiple-view slots. */
11
+ export declare function useSlot({ slot, scopes, appIds }: UseSlotOptions): UseSlotResult;
12
+ /** Managed Slot resolves only its explicitly supplied app. */
13
+ export declare function useAppSlot(app: TailorKitApp, slot: string): UseSlotResult;
package/dist/index.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  export { Slot } from "./components/slot";
2
2
  export type { ControlledSlotProps, SlotComponent, SlotContext, SlotProps } from "./components/slot";
3
3
  export { components, createTailorKitClient } from "./tailorkit";
4
- export type { TailorKitApp, TailorKitView, TailorKitClientConfig, TailorKitInstance, } from "./tailorkit";
4
+ export type { TailorKitApp, TailorKitClientConfig, TailorKitInstance } from "./tailorkit";
5
5
  export { Root } from "./components/root";
6
6
  export type { UseAppsOptions, UseAppsResult } from "./hooks/use-apps";
7
- export type { UseViewsOptions, UseViewsResult } from "./hooks/use-views";
8
- export type { SlotInstance, UseSlotInstancesOptions, UseSlotInstancesResult, } from "./hooks/use-slot-instances";
7
+ export type { SlotItem, UseSlotOptions, UseSlotResult } from "./hooks/use-slot";
9
8
  export type { UseRegisterView, ViewOptions, ViewState } from "./hooks/use-register-view";
10
9
  export { primitives } from "./primitives";
package/dist/index.js CHANGED
@@ -12,8 +12,8 @@ function useStableContext(value) {
12
12
  return ref.current.value;
13
13
  }
14
14
 
15
- // src/hooks/use-slot-instances.ts
16
- import { createSlotInstancesStore } from "@tailorkit/client-core";
15
+ // src/hooks/use-slot.ts
16
+ import { createSlotStore, matchesApp as matchesApp3, serializeCacheKey } from "@tailorkit/client-core";
17
17
  import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useSyncExternalStore as useSyncExternalStore2 } from "react";
18
18
 
19
19
  // src/components/context.ts
@@ -45,28 +45,25 @@ function useApps(options = {}) {
45
45
  return useAppsStore(useTailorRootContext("useApps").store, options);
46
46
  }
47
47
  function useAppsStore(store, options = {}) {
48
- const snapshot = useAppsSnapshot(store, options);
48
+ const snapshot = useAppsSnapshot(store);
49
49
  const scopes = normalizeScopeSelection(options.scopes);
50
50
  const appIds = normalizeScopeSelection(options.appIds);
51
51
  const data = useMemo(
52
52
  () => snapshot.status === "ready" ? snapshot.apps.filter((app) => matchesApp(app, scopes.scopes, appIds.scopes)) : void 0,
53
53
  [snapshot, scopes.key, appIds.key]
54
54
  );
55
- const refetch = useCallback(
56
- () => store.fetchApps({ force: true, staleTime: options.staleTime }),
57
- [store, options.staleTime]
58
- );
55
+ const refetch = useCallback(() => store.fetchApps({ force: true }), [store]);
59
56
  return { ...toUseAppsResult(snapshot, refetch), data };
60
57
  }
61
- function useAppsSnapshot(store, options = {}) {
58
+ function useAppsSnapshot(store) {
62
59
  const snapshot = useSyncExternalStore(
63
60
  store.subscribeApps,
64
61
  store.getAppsSnapshot,
65
62
  store.getAppsSnapshot
66
63
  );
67
64
  useEffect(() => {
68
- void store.fetchApps(options);
69
- }, [store, options.staleTime]);
65
+ void store.fetchApps();
66
+ }, [store]);
70
67
  return snapshot;
71
68
  }
72
69
  function toUseAppsResult(snapshot, refetch) {
@@ -83,43 +80,59 @@ function toUseAppsResult(snapshot, refetch) {
83
80
  };
84
81
  }
85
82
 
86
- // src/hooks/use-slot-instances.ts
87
- function useSlotInstances({
88
- slot,
89
- staleTime,
90
- gcTime
91
- }) {
92
- const apps = useApps();
93
- const instances = useResolvedSlotInstances(slot, apps.data, apps.status, apps.error, {
94
- staleTime,
95
- gcTime
96
- });
83
+ // src/hooks/use-slot.ts
84
+ function useSlot({ slot, scopes, appIds }) {
85
+ const { store } = useTailorRootContext("useSlot");
86
+ const apps = useApps({ scopes, appIds });
87
+ const items = useResolvedSlot(slot, apps.data, apps.status, apps.error);
97
88
  const refetch = useCallback2(async () => {
98
- if (apps.isSuccess) await instances.refetch();
99
- else await apps.refetch();
100
- }, [apps.isSuccess, apps.refetch, instances.refetch]);
101
- return { ...instances, isFetching: apps.isFetching || instances.isFetching, refetch };
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 };
102
112
  }
103
- function useAppSlotInstances(app, slot) {
104
- return useResolvedSlotInstances(slot, [app], "ready", null);
113
+ function useAppSlot(app, slot) {
114
+ return useResolvedSlot(slot, [app], "ready", null);
105
115
  }
106
- function useResolvedSlotInstances(slot, apps, appsStatus, appsError, { staleTime, gcTime } = {}) {
107
- const { store } = useTailorRootContext("useSlotInstances");
116
+ function useResolvedSlot(slot, apps, appsStatus, appsError) {
117
+ const { store } = useTailorRootContext("useSlot");
108
118
  const activeView = useSyncExternalStore2(
109
119
  store.views.subscribe,
110
120
  store.views.getSnapshot,
111
121
  store.views.getSnapshot
112
122
  );
113
- const options = useStableContext({ apps: apps ?? [], slot, activeView });
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
+ });
114
129
  const query = useMemo2(
115
- () => createSlotInstancesStore(store.client, {
130
+ () => createSlotStore(store.client, {
116
131
  ...options,
117
132
  appsStatus,
118
- appsError,
119
- staleTime,
120
- gcTime
133
+ appsError
121
134
  }),
122
- [store.client, options, appsStatus, appsError, staleTime, gcTime]
135
+ [store.client, options, appsStatus, appsError]
123
136
  );
124
137
  const snapshot = useSyncExternalStore2(query.subscribe, query.getSnapshot, query.getSnapshot);
125
138
  useEffect2(() => {
@@ -537,9 +550,11 @@ function InstanceSlot({
537
550
  state
538
551
  }) {
539
552
  const { store } = useTailorRootContext("Slot");
540
- const instances = useAppSlotInstances(app, name);
553
+ const instances = useAppSlot(app, name);
541
554
  const meta = useSyncExternalStore4(store.subscribe, store.getMetaSnapshot, store.getMetaSnapshot);
542
- const instance = instances.data?.find((instance2) => instance2.key === instanceKey);
555
+ const instance = instances.data?.find(
556
+ (item) => "key" in item && item.key === instanceKey
557
+ );
543
558
  const resolved = instances.isSuccess && instance && meta.schema ? resolveSlotView(app.views ?? [], name, state, meta.schema) : null;
544
559
  const view = resolved?.status === "ready" ? resolved.view : void 0;
545
560
  const stableContext = useStableContext(resolved?.context);
@@ -716,23 +731,6 @@ function useRegisterView(view, options) {
716
731
  }, [contextSnapshot, id, view, status, store]);
717
732
  }
718
733
 
719
- // src/hooks/use-views.ts
720
- import { useCallback as useCallback5, useMemo as useMemo7 } from "react";
721
- function useViews(options = {}) {
722
- const { store } = useTailorRootContext("useViews");
723
- const snapshot = useAppsSnapshot(store, options);
724
- const scopes = normalizeScopeSelection(options.scopes);
725
- const appIds = normalizeScopeSelection(options.appIds);
726
- const data = useMemo7(
727
- () => snapshot.status === "ready" ? snapshot.views.filter(
728
- (view) => (options.slot === void 0 || view.slot === options.slot) && matchesApp2(view.app, scopes.scopes, appIds.scopes)
729
- ) : void 0,
730
- [snapshot, scopes.key, appIds.key, options.slot]
731
- );
732
- const refetch = useCallback5(() => store.fetchApps({ force: true }), [store]);
733
- return { ...toUseAppsResult(snapshot, refetch), data };
734
- }
735
-
736
734
  // src/tailorkit.tsx
737
735
  var componentTagPrefix = "tailorkit-";
738
736
  var toComponentTagName = (name) => `${componentTagPrefix}${name.replaceAll(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[\s_]+/gu, "-").toLowerCase()}`;
@@ -788,13 +786,9 @@ function createReactTailorKitClient(options) {
788
786
  useTailorRootContext("useApps", client);
789
787
  return useApps(options2);
790
788
  },
791
- useViews: function useClientViews(options2) {
792
- useTailorRootContext("useViews", client);
793
- return useViews(options2);
794
- },
795
- useSlotInstances: function useClientSlotInstances(options2) {
796
- useTailorRootContext("useSlotInstances", client);
797
- return useSlotInstances(options2);
789
+ useSlot: function useClientSlot(options2) {
790
+ useTailorRootContext("useSlot", client);
791
+ return useSlot(options2);
798
792
  },
799
793
  useRegisterView: function useClientRegisterView(view, options2) {
800
794
  useTailorRootContext("useRegisterView", client);
@@ -805,17 +799,17 @@ function createReactTailorKitClient(options) {
805
799
  }
806
800
 
807
801
  // src/components/root.tsx
808
- import { useEffect as useEffect6, useMemo as useMemo9, useState as useState2 } from "react";
802
+ import { useEffect as useEffect6, useMemo as useMemo8, useState as useState2 } from "react";
809
803
  import { createTailorKitStore, toBaseUrl as toBaseUrl2 } from "@tailorkit/client-core";
810
804
 
811
805
  // src/components/render.tsx
812
- import { cloneElement, createElement as createElement3, isValidElement, useMemo as useMemo8 } from "react";
806
+ import { cloneElement, createElement as createElement3, isValidElement, useMemo as useMemo7 } from "react";
813
807
  function useRender({
814
808
  defaultTagName,
815
809
  props,
816
810
  render
817
811
  }) {
818
- return useMemo8(() => {
812
+ return useMemo7(() => {
819
813
  if (render) {
820
814
  if (!isValidElement(render)) {
821
815
  throw new Error("The render prop must be a valid React element.");
@@ -899,7 +893,7 @@ function Root({ apps: appsProp, children, render, client, ...props }) {
899
893
  store.setProvidedApps(appsProp);
900
894
  }, [store, appsProp]);
901
895
  useEffect6(() => () => store.previews.dispose(), [store]);
902
- const context = useMemo9(
896
+ const context = useMemo8(
903
897
  () => ({
904
898
  store,
905
899
  client
@@ -4,8 +4,7 @@ import type { TailorKitTheme, CallbackMap, ComponentDefinition, ComponentProps,
4
4
  import type { primitives } from "./primitives";
5
5
  import type { UseRegisterView } from "./hooks/use-register-view";
6
6
  import type { UseAppsOptions, UseAppsResult } from "./hooks/use-apps";
7
- import type { UseViewsOptions, UseViewsResult } from "./hooks/use-views";
8
- import type { UseSlotInstancesOptions, UseSlotInstancesResult } from "./hooks/use-slot-instances";
7
+ import type { UseSlotOptions, UseSlotResult } from "./hooks/use-slot";
9
8
  import type { SlotComponent } from "./components/slot";
10
9
  type AnyComponentDefinition = ComponentDefinition<Schema | undefined, CallbackMap, boolean | undefined>;
11
10
  type ComponentRenderer<TComponent extends AnyComponentDefinition> = (args: {
@@ -20,7 +19,7 @@ type ComponentRenderers<TComponents extends Record<string, AnyComponentDefinitio
20
19
  type CompleteComponentRenderers<TComponents extends Record<string, AnyComponentDefinition>> = {
21
20
  [TName in keyof TComponents]-?: ComponentRenderer<TComponents[TName]>;
22
21
  };
23
- export type { TailorKitApp, TailorKitView } from "@tailorkit/client-core";
22
+ export type { TailorKitApp } from "@tailorkit/client-core";
24
23
  export interface TailorKitClientConfig {
25
24
  readonly baseUrl: string | URL;
26
25
  readonly fetchClient?: TailorKitFetchClient;
@@ -32,10 +31,14 @@ export interface TailorKitInstance<TViews extends Record<string, ViewDefinition>
32
31
  readonly $views?: TViews;
33
32
  readonly Slot: SlotComponent<TViews, TSlots>;
34
33
  readonly useApps: (options?: UseAppsOptions<TScopeNames>) => UseAppsResult;
35
- readonly useViews: (options?: UseViewsOptions<TScopeNames, keyof TSlots & string>) => UseViewsResult;
36
- readonly useSlotInstances: (options: UseSlotInstancesOptions<keyof TSlots & string>) => UseSlotInstancesResult;
34
+ readonly useSlot: <TSlot extends keyof TSlots & string>(options: UseSlotOptions<TScopeNames, TSlot>) => UseSlotResult<SlotMultiple<TSlots[TSlot]>>;
37
35
  readonly useRegisterView: UseRegisterView<TViews>;
38
36
  }
37
+ type SlotMultiple<TSlot> = TSlot extends {
38
+ multiple: infer TMultiple extends boolean;
39
+ } ? TMultiple : TSlot extends {
40
+ multiple?: infer TMultiple extends boolean;
41
+ } ? TMultiple | false : false;
39
42
  type PrimitiveRenderers = typeof primitives;
40
43
  type CustomComponentRenderers<TComponents extends Record<string, AnyComponentDefinition>> = {
41
44
  [TName in Exclude<keyof TComponents, keyof PrimitiveRenderers>]?: ComponentRenderer<TComponents[TName]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailorkit/react",
3
- "version": "0.1.0-beta.21",
3
+ "version": "0.1.0-beta.22",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -23,11 +23,11 @@
23
23
  "dependencies": {
24
24
  "@floating-ui/react-dom": "^2.1.9",
25
25
  "@standard-schema/spec": "^1.1.0",
26
- "@tailorkit/app": "0.1.0-beta.21",
27
- "@tailorkit/client-core": "0.1.0-beta.21",
28
- "@tailorkit/client-platform": "0.1.0-beta.21",
29
- "@tailorkit/core": "0.1.0-beta.21",
30
- "@tailorkit/sandbox": "0.1.0-beta.21"
26
+ "@tailorkit/app": "0.1.0-beta.22",
27
+ "@tailorkit/client-core": "0.1.0-beta.22",
28
+ "@tailorkit/client-platform": "0.1.0-beta.22",
29
+ "@tailorkit/core": "0.1.0-beta.22",
30
+ "@tailorkit/sandbox": "0.1.0-beta.22"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@tailorkit/config": "0.0.0",
@@ -1,13 +0,0 @@
1
- import type { FetchCacheOptions, TailorKitApp, SlotInstance } from "@tailorkit/client-core";
2
- import type { UseAppsResult } from "./use-apps";
3
- export type { SlotInstance } from "@tailorkit/client-core";
4
- export interface UseSlotInstancesOptions<TSlot extends string = string> extends FetchCacheOptions {
5
- slot: TSlot;
6
- }
7
- export interface UseSlotInstancesResult extends Omit<UseAppsResult, "data"> {
8
- data: SlotInstance[] | undefined;
9
- }
10
- /** Resolve instances across discovered apps while sharing endpoint state in client-core. */
11
- export declare function useSlotInstances({ slot, staleTime, gcTime, }: UseSlotInstancesOptions): UseSlotInstancesResult;
12
- /** Managed Slot resolves only its explicitly supplied app. */
13
- export declare function useAppSlotInstances(app: TailorKitApp, slot: string): UseSlotInstancesResult;
@@ -1,9 +0,0 @@
1
- import type { TailorKitView } from "../tailorkit";
2
- import type { UseAppsOptions, UseAppsResult } from "./use-apps";
3
- export interface UseViewsOptions<TScopeNames extends string = string, TSlot extends string = string> extends UseAppsOptions<TScopeNames> {
4
- slot?: TSlot;
5
- }
6
- export interface UseViewsResult extends Omit<UseAppsResult, "data"> {
7
- data: TailorKitView[] | undefined;
8
- }
9
- export declare function useViews(options?: UseViewsOptions): UseViewsResult;