@tambo-ai/react 0.37.3 → 0.38.1
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/hooks/__tests__/use-tambo-threads.test.js +1 -0
- package/dist/hooks/__tests__/use-tambo-threads.test.js.map +1 -1
- package/dist/hooks/use-tambo-threads.d.ts +5 -0
- package/dist/hooks/use-tambo-threads.d.ts.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/model/tambo-interactable.d.ts +24 -0
- package/dist/model/tambo-interactable.d.ts.map +1 -0
- package/dist/model/tambo-interactable.js +3 -0
- package/dist/model/tambo-interactable.js.map +1 -0
- package/dist/providers/__tests__/tambo-prop-stream-provider.test.d.ts +2 -0
- package/dist/providers/__tests__/tambo-prop-stream-provider.test.d.ts.map +1 -0
- package/dist/providers/__tests__/tambo-prop-stream-provider.test.js +278 -0
- package/dist/providers/__tests__/tambo-prop-stream-provider.test.js.map +1 -0
- package/dist/providers/hoc/with-tambo-interactable.d.ts +34 -0
- package/dist/providers/hoc/with-tambo-interactable.d.ts.map +1 -0
- package/dist/providers/hoc/with-tambo-interactable.js +119 -0
- package/dist/providers/hoc/with-tambo-interactable.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +4 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/tambo-interactable-provider.d.ts +20 -0
- package/dist/providers/tambo-interactable-provider.d.ts.map +1 -0
- package/dist/providers/tambo-interactable-provider.js +243 -0
- package/dist/providers/tambo-interactable-provider.js.map +1 -0
- package/dist/providers/tambo-prop-stream-provider.d.ts +96 -0
- package/dist/providers/tambo-prop-stream-provider.d.ts.map +1 -0
- package/dist/providers/tambo-prop-stream-provider.js +185 -0
- package/dist/providers/tambo-prop-stream-provider.js.map +1 -0
- package/dist/providers/tambo-provider.d.ts +6 -4
- package/dist/providers/tambo-provider.d.ts.map +1 -1
- package/dist/providers/tambo-provider.js +9 -4
- package/dist/providers/tambo-provider.js.map +1 -1
- package/dist/util/query-utils.d.ts.map +1 -1
- package/dist/util/query-utils.js +1 -0
- package/dist/util/query-utils.js.map +1 -1
- package/esm/hooks/__tests__/use-tambo-threads.test.js +1 -0
- package/esm/hooks/__tests__/use-tambo-threads.test.js.map +1 -1
- package/esm/hooks/use-tambo-threads.d.ts +5 -0
- package/esm/hooks/use-tambo-threads.d.ts.map +1 -1
- package/esm/index.d.ts +5 -2
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +4 -2
- package/esm/index.js.map +1 -1
- package/esm/model/tambo-interactable.d.ts +24 -0
- package/esm/model/tambo-interactable.d.ts.map +1 -0
- package/esm/model/tambo-interactable.js +2 -0
- package/esm/model/tambo-interactable.js.map +1 -0
- package/esm/providers/__tests__/tambo-prop-stream-provider.test.d.ts +2 -0
- package/esm/providers/__tests__/tambo-prop-stream-provider.test.d.ts.map +1 -0
- package/esm/providers/__tests__/tambo-prop-stream-provider.test.js +273 -0
- package/esm/providers/__tests__/tambo-prop-stream-provider.test.js.map +1 -0
- package/esm/providers/hoc/with-tambo-interactable.d.ts +34 -0
- package/esm/providers/hoc/with-tambo-interactable.d.ts.map +1 -0
- package/esm/providers/hoc/with-tambo-interactable.js +83 -0
- package/esm/providers/hoc/with-tambo-interactable.js.map +1 -0
- package/esm/providers/index.d.ts +2 -0
- package/esm/providers/index.d.ts.map +1 -1
- package/esm/providers/index.js +1 -0
- package/esm/providers/index.js.map +1 -1
- package/esm/providers/tambo-interactable-provider.d.ts +20 -0
- package/esm/providers/tambo-interactable-provider.d.ts.map +1 -0
- package/esm/providers/tambo-interactable-provider.js +205 -0
- package/esm/providers/tambo-interactable-provider.js.map +1 -0
- package/esm/providers/tambo-prop-stream-provider.d.ts +96 -0
- package/esm/providers/tambo-prop-stream-provider.d.ts.map +1 -0
- package/esm/providers/tambo-prop-stream-provider.js +148 -0
- package/esm/providers/tambo-prop-stream-provider.js.map +1 -0
- package/esm/providers/tambo-provider.d.ts +6 -4
- package/esm/providers/tambo-provider.d.ts.map +1 -1
- package/esm/providers/tambo-provider.js +9 -4
- package/esm/providers/tambo-provider.js.map +1 -1
- package/esm/util/query-utils.d.ts.map +1 -1
- package/esm/util/query-utils.js +1 -0
- package/esm/util/query-utils.js.map +1 -1
- package/package.json +8 -8
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TamboComponent } from "./component-metadata";
|
|
2
|
+
export interface TamboInteractableComponent extends TamboComponent {
|
|
3
|
+
/** Unique identifier for this component instance */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Current props for the component */
|
|
6
|
+
props: Record<string, any>;
|
|
7
|
+
}
|
|
8
|
+
export interface TamboInteractableContext {
|
|
9
|
+
/** List of all interactable components */
|
|
10
|
+
interactableComponents: TamboInteractableComponent[];
|
|
11
|
+
/** Add a new interactable component */
|
|
12
|
+
addInteractableComponent: (component: Omit<TamboInteractableComponent, "id" | "createdAt">) => string;
|
|
13
|
+
/** Remove an interactable component by ID */
|
|
14
|
+
removeInteractableComponent: (id: string) => void;
|
|
15
|
+
/** Update an interactable component's props */
|
|
16
|
+
updateInteractableComponentProps: (id: string, newProps: Record<string, any>) => void;
|
|
17
|
+
/** Get an interactable component by ID */
|
|
18
|
+
getInteractableComponent: (id: string) => TamboInteractableComponent | undefined;
|
|
19
|
+
/** Get all interactable components by component name */
|
|
20
|
+
getInteractableComponentsByName: (componentName: string) => TamboInteractableComponent[];
|
|
21
|
+
/** Clear all interactable components */
|
|
22
|
+
clearAllInteractableComponents: () => void;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=tambo-interactable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-interactable.d.ts","sourceRoot":"","sources":["../../src/model/tambo-interactable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,0BAA2B,SAAQ,cAAc;IAChE,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,sBAAsB,EAAE,0BAA0B,EAAE,CAAC;IACrD,uCAAuC;IACvC,wBAAwB,EAAE,CACxB,SAAS,EAAE,IAAI,CAAC,0BAA0B,EAAE,IAAI,GAAG,WAAW,CAAC,KAC5D,MAAM,CAAC;IACZ,6CAA6C;IAC7C,2BAA2B,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,+CAA+C;IAC/C,gCAAgC,EAAE,CAChC,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAC1B,IAAI,CAAC;IACV,0CAA0C;IAC1C,wBAAwB,EAAE,CACxB,EAAE,EAAE,MAAM,KACP,0BAA0B,GAAG,SAAS,CAAC;IAC5C,wDAAwD;IACxD,+BAA+B,EAAE,CAC/B,aAAa,EAAE,MAAM,KAClB,0BAA0B,EAAE,CAAC;IAClC,wCAAwC;IACxC,8BAA8B,EAAE,MAAM,IAAI,CAAC;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-interactable.js","sourceRoot":"","sources":["../../src/model/tambo-interactable.ts"],"names":[],"mappings":"","sourcesContent":["import { TamboComponent } from \"./component-metadata\";\n\nexport interface TamboInteractableComponent extends TamboComponent {\n /** Unique identifier for this component instance */\n id: string;\n /** Current props for the component */\n props: Record<string, any>;\n}\n\nexport interface TamboInteractableContext {\n /** List of all interactable components */\n interactableComponents: TamboInteractableComponent[];\n /** Add a new interactable component */\n addInteractableComponent: (\n component: Omit<TamboInteractableComponent, \"id\" | \"createdAt\">,\n ) => string;\n /** Remove an interactable component by ID */\n removeInteractableComponent: (id: string) => void;\n /** Update an interactable component's props */\n updateInteractableComponentProps: (\n id: string,\n newProps: Record<string, any>,\n ) => void;\n /** Get an interactable component by ID */\n getInteractableComponent: (\n id: string,\n ) => TamboInteractableComponent | undefined;\n /** Get all interactable components by component name */\n getInteractableComponentsByName: (\n componentName: string,\n ) => TamboInteractableComponent[];\n /** Clear all interactable components */\n clearAllInteractableComponents: () => void;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-prop-stream-provider.test.d.ts","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-prop-stream-provider.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { TamboPropStreamProvider, useTamboStream, } from "../tambo-prop-stream-provider";
|
|
4
|
+
// Helper component to test hook usage
|
|
5
|
+
const TestHookComponent = ({ testKey = "default", }) => {
|
|
6
|
+
const { data, streamStatus, getStatusForKey } = useTamboStream();
|
|
7
|
+
const status = getStatusForKey(testKey);
|
|
8
|
+
return (React.createElement("div", null,
|
|
9
|
+
React.createElement("div", { "data-testid": "data" }, JSON.stringify(data)),
|
|
10
|
+
React.createElement("div", { "data-testid": "stream-status" }, JSON.stringify(streamStatus)),
|
|
11
|
+
React.createElement("div", { "data-testid": "key-status" }, JSON.stringify(status))));
|
|
12
|
+
};
|
|
13
|
+
describe("TamboPropStreamProvider", () => {
|
|
14
|
+
describe("Hook Error Handling", () => {
|
|
15
|
+
it("should throw error when useTamboStream is used outside provider", () => {
|
|
16
|
+
// Suppress console.error for this test
|
|
17
|
+
const originalError = console.error;
|
|
18
|
+
console.error = jest.fn();
|
|
19
|
+
expect(() => {
|
|
20
|
+
render(React.createElement(TestHookComponent, null));
|
|
21
|
+
}).toThrow("useTamboStream must be used within a TamboPropStreamProvider");
|
|
22
|
+
console.error = originalError;
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("Basic Functionality", () => {
|
|
26
|
+
it("should provide data and stream status through context", () => {
|
|
27
|
+
const testData = { message: "Hello World" };
|
|
28
|
+
const testStreamStatus = {
|
|
29
|
+
isPending: false,
|
|
30
|
+
isStreaming: false,
|
|
31
|
+
isSuccess: true,
|
|
32
|
+
isError: false,
|
|
33
|
+
streamError: undefined,
|
|
34
|
+
};
|
|
35
|
+
render(React.createElement(TamboPropStreamProvider, { data: testData, streamStatus: testStreamStatus },
|
|
36
|
+
React.createElement(TestHookComponent, null)));
|
|
37
|
+
expect(screen.getByTestId("data")).toHaveTextContent(JSON.stringify(testData));
|
|
38
|
+
expect(screen.getByTestId("stream-status")).toHaveTextContent(JSON.stringify(testStreamStatus));
|
|
39
|
+
});
|
|
40
|
+
it("should use default stream status when none provided", () => {
|
|
41
|
+
const testData = { message: "Hello World" };
|
|
42
|
+
const expectedDefaultStatus = {
|
|
43
|
+
isPending: false,
|
|
44
|
+
isStreaming: false,
|
|
45
|
+
isSuccess: true,
|
|
46
|
+
isError: false,
|
|
47
|
+
streamError: undefined,
|
|
48
|
+
};
|
|
49
|
+
render(React.createElement(TamboPropStreamProvider, { data: testData },
|
|
50
|
+
React.createElement(TestHookComponent, null)));
|
|
51
|
+
expect(screen.getByTestId("stream-status")).toHaveTextContent(JSON.stringify(expectedDefaultStatus));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
describe("Compound Components", () => {
|
|
55
|
+
describe("Loading Component", () => {
|
|
56
|
+
it("should render loading when isPending is true", () => {
|
|
57
|
+
const streamStatus = {
|
|
58
|
+
isPending: true,
|
|
59
|
+
isStreaming: false,
|
|
60
|
+
isSuccess: false,
|
|
61
|
+
isError: false,
|
|
62
|
+
};
|
|
63
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
64
|
+
React.createElement(TamboPropStreamProvider.Loading, null,
|
|
65
|
+
React.createElement("div", { "data-testid": "loading" }, "Loading..."))));
|
|
66
|
+
expect(screen.getByTestId("loading")).toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
it("should render loading when isStreaming is true", () => {
|
|
69
|
+
const streamStatus = {
|
|
70
|
+
isPending: false,
|
|
71
|
+
isStreaming: true,
|
|
72
|
+
isSuccess: false,
|
|
73
|
+
isError: false,
|
|
74
|
+
};
|
|
75
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
76
|
+
React.createElement(TamboPropStreamProvider.Loading, null,
|
|
77
|
+
React.createElement("div", { "data-testid": "loading" }, "Loading..."))));
|
|
78
|
+
expect(screen.getByTestId("loading")).toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
it("should not render loading when not pending or streaming", () => {
|
|
81
|
+
const streamStatus = {
|
|
82
|
+
isPending: false,
|
|
83
|
+
isStreaming: false,
|
|
84
|
+
isSuccess: true,
|
|
85
|
+
isError: false,
|
|
86
|
+
};
|
|
87
|
+
render(React.createElement(TamboPropStreamProvider, { data: "test", streamStatus: streamStatus },
|
|
88
|
+
React.createElement(TamboPropStreamProvider.Loading, null,
|
|
89
|
+
React.createElement("div", { "data-testid": "loading" }, "Loading..."))));
|
|
90
|
+
expect(screen.queryByTestId("loading")).not.toBeInTheDocument();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe("Complete Component", () => {
|
|
94
|
+
it("should render complete when isSuccess is true and data exists", () => {
|
|
95
|
+
const streamStatus = {
|
|
96
|
+
isPending: false,
|
|
97
|
+
isStreaming: false,
|
|
98
|
+
isSuccess: true,
|
|
99
|
+
isError: false,
|
|
100
|
+
};
|
|
101
|
+
render(React.createElement(TamboPropStreamProvider, { data: "test data", streamStatus: streamStatus },
|
|
102
|
+
React.createElement(TamboPropStreamProvider.Complete, null,
|
|
103
|
+
React.createElement("div", { "data-testid": "complete" }, "Complete!"))));
|
|
104
|
+
expect(screen.getByTestId("complete")).toBeInTheDocument();
|
|
105
|
+
});
|
|
106
|
+
it("should not render complete when data is null", () => {
|
|
107
|
+
const streamStatus = {
|
|
108
|
+
isPending: false,
|
|
109
|
+
isStreaming: false,
|
|
110
|
+
isSuccess: true,
|
|
111
|
+
isError: false,
|
|
112
|
+
};
|
|
113
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
114
|
+
React.createElement(TamboPropStreamProvider.Complete, null,
|
|
115
|
+
React.createElement("div", { "data-testid": "complete" }, "Complete!"))));
|
|
116
|
+
expect(screen.queryByTestId("complete")).not.toBeInTheDocument();
|
|
117
|
+
});
|
|
118
|
+
it("should not render complete when data is undefined", () => {
|
|
119
|
+
const streamStatus = {
|
|
120
|
+
isPending: false,
|
|
121
|
+
isStreaming: false,
|
|
122
|
+
isSuccess: true,
|
|
123
|
+
isError: false,
|
|
124
|
+
};
|
|
125
|
+
render(React.createElement(TamboPropStreamProvider, { data: undefined, streamStatus: streamStatus },
|
|
126
|
+
React.createElement(TamboPropStreamProvider.Complete, null,
|
|
127
|
+
React.createElement("div", { "data-testid": "complete" }, "Complete!"))));
|
|
128
|
+
expect(screen.queryByTestId("complete")).not.toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe("Empty Component", () => {
|
|
132
|
+
it("should render empty when no data and not loading/streaming/success/error", () => {
|
|
133
|
+
const streamStatus = {
|
|
134
|
+
isPending: false,
|
|
135
|
+
isStreaming: false,
|
|
136
|
+
isSuccess: false,
|
|
137
|
+
isError: false,
|
|
138
|
+
};
|
|
139
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
140
|
+
React.createElement(TamboPropStreamProvider.Empty, null,
|
|
141
|
+
React.createElement("div", { "data-testid": "empty" }, "No data"))));
|
|
142
|
+
expect(screen.getByTestId("empty")).toBeInTheDocument();
|
|
143
|
+
});
|
|
144
|
+
it("should render empty when data is empty string", () => {
|
|
145
|
+
const streamStatus = {
|
|
146
|
+
isPending: false,
|
|
147
|
+
isStreaming: false,
|
|
148
|
+
isSuccess: false,
|
|
149
|
+
isError: false,
|
|
150
|
+
};
|
|
151
|
+
render(React.createElement(TamboPropStreamProvider, { data: "", streamStatus: streamStatus },
|
|
152
|
+
React.createElement(TamboPropStreamProvider.Empty, null,
|
|
153
|
+
React.createElement("div", { "data-testid": "empty" }, "No data"))));
|
|
154
|
+
expect(screen.getByTestId("empty")).toBeInTheDocument();
|
|
155
|
+
});
|
|
156
|
+
it("should not render empty when loading", () => {
|
|
157
|
+
const streamStatus = {
|
|
158
|
+
isPending: true,
|
|
159
|
+
isStreaming: false,
|
|
160
|
+
isSuccess: false,
|
|
161
|
+
isError: false,
|
|
162
|
+
};
|
|
163
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
164
|
+
React.createElement(TamboPropStreamProvider.Empty, null,
|
|
165
|
+
React.createElement("div", { "data-testid": "empty" }, "No data"))));
|
|
166
|
+
expect(screen.queryByTestId("empty")).not.toBeInTheDocument();
|
|
167
|
+
});
|
|
168
|
+
it("should not render empty when successful", () => {
|
|
169
|
+
const streamStatus = {
|
|
170
|
+
isPending: false,
|
|
171
|
+
isStreaming: false,
|
|
172
|
+
isSuccess: true,
|
|
173
|
+
isError: false,
|
|
174
|
+
};
|
|
175
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
176
|
+
React.createElement(TamboPropStreamProvider.Empty, null,
|
|
177
|
+
React.createElement("div", { "data-testid": "empty" }, "No data"))));
|
|
178
|
+
expect(screen.queryByTestId("empty")).not.toBeInTheDocument();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
describe("Per-Key Status Tracking", () => {
|
|
183
|
+
it("should track status for object keys", () => {
|
|
184
|
+
const testData = { name: "John", age: null };
|
|
185
|
+
const streamStatus = {
|
|
186
|
+
isPending: false,
|
|
187
|
+
isStreaming: false,
|
|
188
|
+
isSuccess: true,
|
|
189
|
+
isError: false,
|
|
190
|
+
};
|
|
191
|
+
render(React.createElement(TamboPropStreamProvider, { data: testData, streamStatus: streamStatus },
|
|
192
|
+
React.createElement(TestHookComponent, { testKey: "name" })));
|
|
193
|
+
const keyStatus = JSON.parse(screen.getByTestId("key-status").textContent ?? "{}");
|
|
194
|
+
expect(keyStatus.isSuccess).toBe(true); // name has data
|
|
195
|
+
});
|
|
196
|
+
it("should show loading for keys without data", () => {
|
|
197
|
+
const testData = { name: "John", age: null };
|
|
198
|
+
const streamStatus = {
|
|
199
|
+
isPending: false,
|
|
200
|
+
isStreaming: false,
|
|
201
|
+
isSuccess: true,
|
|
202
|
+
isError: false,
|
|
203
|
+
};
|
|
204
|
+
render(React.createElement(TamboPropStreamProvider, { data: testData, streamStatus: streamStatus },
|
|
205
|
+
React.createElement(TestHookComponent, { testKey: "age" })));
|
|
206
|
+
const keyStatus = JSON.parse(screen.getByTestId("key-status").textContent ?? "{}");
|
|
207
|
+
expect(keyStatus.isPending).toBe(true); // age has no data
|
|
208
|
+
});
|
|
209
|
+
it("should handle per-key loading states", () => {
|
|
210
|
+
render(React.createElement(TamboPropStreamProvider, { data: { name: "John", age: null } },
|
|
211
|
+
React.createElement(TamboPropStreamProvider.Loading, { streamKey: "name" },
|
|
212
|
+
React.createElement("div", { "data-testid": "name-loading" }, "Name loading...")),
|
|
213
|
+
React.createElement(TamboPropStreamProvider.Loading, { streamKey: "age" },
|
|
214
|
+
React.createElement("div", { "data-testid": "age-loading" }, "Age loading...")),
|
|
215
|
+
React.createElement(TamboPropStreamProvider.Complete, { streamKey: "name" },
|
|
216
|
+
React.createElement("div", { "data-testid": "name-complete" }, "Name: John"))));
|
|
217
|
+
// Name should be complete (has data)
|
|
218
|
+
expect(screen.getByTestId("name-complete")).toBeInTheDocument();
|
|
219
|
+
expect(screen.queryByTestId("name-loading")).not.toBeInTheDocument();
|
|
220
|
+
// Age should be loading (no data)
|
|
221
|
+
expect(screen.getByTestId("age-loading")).toBeInTheDocument();
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
describe("Edge Cases", () => {
|
|
225
|
+
it("should handle null data gracefully", () => {
|
|
226
|
+
render(React.createElement(TamboPropStreamProvider, { data: null },
|
|
227
|
+
React.createElement(TestHookComponent, null)));
|
|
228
|
+
expect(screen.getByTestId("data")).toHaveTextContent("null");
|
|
229
|
+
});
|
|
230
|
+
it("should handle undefined data gracefully", () => {
|
|
231
|
+
render(React.createElement(TamboPropStreamProvider, { data: undefined },
|
|
232
|
+
React.createElement(TestHookComponent, null)));
|
|
233
|
+
expect(screen.getByTestId("data")).toHaveTextContent("");
|
|
234
|
+
});
|
|
235
|
+
it("should handle array data", () => {
|
|
236
|
+
const arrayData = ["item1", "item2"];
|
|
237
|
+
render(React.createElement(TamboPropStreamProvider, { data: arrayData },
|
|
238
|
+
React.createElement(TestHookComponent, null)));
|
|
239
|
+
expect(screen.getByTestId("data")).toHaveTextContent(JSON.stringify(arrayData));
|
|
240
|
+
});
|
|
241
|
+
it("should handle primitive data types", () => {
|
|
242
|
+
render(React.createElement(TamboPropStreamProvider, { data: "string data" },
|
|
243
|
+
React.createElement(TestHookComponent, null)));
|
|
244
|
+
expect(screen.getByTestId("data")).toHaveTextContent('"string data"');
|
|
245
|
+
});
|
|
246
|
+
it("should fallback to default status for unknown keys", () => {
|
|
247
|
+
const testData = { name: "John" };
|
|
248
|
+
render(React.createElement(TamboPropStreamProvider, { data: testData },
|
|
249
|
+
React.createElement(TestHookComponent, { testKey: "unknown-key" })));
|
|
250
|
+
const keyStatus = JSON.parse(screen.getByTestId("key-status").textContent ?? "{}");
|
|
251
|
+
// Should fallback to default status
|
|
252
|
+
expect(keyStatus.isSuccess).toBe(true);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
describe("Component Attributes", () => {
|
|
256
|
+
it("should add correct data attributes to components", () => {
|
|
257
|
+
const streamStatus = {
|
|
258
|
+
isPending: true,
|
|
259
|
+
isStreaming: false,
|
|
260
|
+
isSuccess: false,
|
|
261
|
+
isError: false,
|
|
262
|
+
};
|
|
263
|
+
render(React.createElement(TamboPropStreamProvider, { data: null, streamStatus: streamStatus },
|
|
264
|
+
React.createElement(TamboPropStreamProvider.Loading, { className: "loading-class" },
|
|
265
|
+
React.createElement("div", null, "Loading..."))));
|
|
266
|
+
const loadingElement = screen.getByText("Loading...").parentElement;
|
|
267
|
+
expect(loadingElement).toHaveAttribute("data-stream-key", "default");
|
|
268
|
+
expect(loadingElement).toHaveAttribute("data-stream-state", "loading");
|
|
269
|
+
expect(loadingElement).toHaveClass("loading-class");
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
//# sourceMappingURL=tambo-prop-stream-provider.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-prop-stream-provider.test.js","sourceRoot":"","sources":["../../../src/providers/__tests__/tambo-prop-stream-provider.test.tsx"],"names":[],"mappings":"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","sourcesContent":["import { render, screen } from \"@testing-library/react\";\nimport React from \"react\";\nimport { StreamStatus } from \"../../hooks/use-tambo-stream-status\";\nimport {\n TamboPropStreamProvider,\n useTamboStream,\n} from \"../tambo-prop-stream-provider\";\n\n// Helper component to test hook usage\nconst TestHookComponent: React.FC<{ testKey?: string }> = ({\n testKey = \"default\",\n}) => {\n const { data, streamStatus, getStatusForKey } = useTamboStream();\n const status = getStatusForKey(testKey);\n\n return (\n <div>\n <div data-testid=\"data\">{JSON.stringify(data)}</div>\n <div data-testid=\"stream-status\">{JSON.stringify(streamStatus)}</div>\n <div data-testid=\"key-status\">{JSON.stringify(status)}</div>\n </div>\n );\n};\n\ndescribe(\"TamboPropStreamProvider\", () => {\n describe(\"Hook Error Handling\", () => {\n it(\"should throw error when useTamboStream is used outside provider\", () => {\n // Suppress console.error for this test\n const originalError = console.error;\n console.error = jest.fn();\n\n expect(() => {\n render(<TestHookComponent />);\n }).toThrow(\n \"useTamboStream must be used within a TamboPropStreamProvider\",\n );\n\n console.error = originalError;\n });\n });\n\n describe(\"Basic Functionality\", () => {\n it(\"should provide data and stream status through context\", () => {\n const testData = { message: \"Hello World\" };\n const testStreamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n streamError: undefined,\n };\n\n render(\n <TamboPropStreamProvider\n data={testData}\n streamStatus={testStreamStatus}\n >\n <TestHookComponent />\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"data\")).toHaveTextContent(\n JSON.stringify(testData),\n );\n expect(screen.getByTestId(\"stream-status\")).toHaveTextContent(\n JSON.stringify(testStreamStatus),\n );\n });\n\n it(\"should use default stream status when none provided\", () => {\n const testData = { message: \"Hello World\" };\n const expectedDefaultStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n streamError: undefined,\n };\n\n render(\n <TamboPropStreamProvider data={testData}>\n <TestHookComponent />\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"stream-status\")).toHaveTextContent(\n JSON.stringify(expectedDefaultStatus),\n );\n });\n });\n\n describe(\"Compound Components\", () => {\n describe(\"Loading Component\", () => {\n it(\"should render loading when isPending is true\", () => {\n const streamStatus: StreamStatus = {\n isPending: true,\n isStreaming: false,\n isSuccess: false,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Loading>\n <div data-testid=\"loading\">Loading...</div>\n </TamboPropStreamProvider.Loading>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"loading\")).toBeInTheDocument();\n });\n\n it(\"should render loading when isStreaming is true\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: true,\n isSuccess: false,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Loading>\n <div data-testid=\"loading\">Loading...</div>\n </TamboPropStreamProvider.Loading>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"loading\")).toBeInTheDocument();\n });\n\n it(\"should not render loading when not pending or streaming\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data=\"test\" streamStatus={streamStatus}>\n <TamboPropStreamProvider.Loading>\n <div data-testid=\"loading\">Loading...</div>\n </TamboPropStreamProvider.Loading>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.queryByTestId(\"loading\")).not.toBeInTheDocument();\n });\n });\n\n describe(\"Complete Component\", () => {\n it(\"should render complete when isSuccess is true and data exists\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data=\"test data\" streamStatus={streamStatus}>\n <TamboPropStreamProvider.Complete>\n <div data-testid=\"complete\">Complete!</div>\n </TamboPropStreamProvider.Complete>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"complete\")).toBeInTheDocument();\n });\n\n it(\"should not render complete when data is null\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Complete>\n <div data-testid=\"complete\">Complete!</div>\n </TamboPropStreamProvider.Complete>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.queryByTestId(\"complete\")).not.toBeInTheDocument();\n });\n\n it(\"should not render complete when data is undefined\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={undefined} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Complete>\n <div data-testid=\"complete\">Complete!</div>\n </TamboPropStreamProvider.Complete>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.queryByTestId(\"complete\")).not.toBeInTheDocument();\n });\n });\n\n describe(\"Empty Component\", () => {\n it(\"should render empty when no data and not loading/streaming/success/error\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: false,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Empty>\n <div data-testid=\"empty\">No data</div>\n </TamboPropStreamProvider.Empty>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"empty\")).toBeInTheDocument();\n });\n\n it(\"should render empty when data is empty string\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: false,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data=\"\" streamStatus={streamStatus}>\n <TamboPropStreamProvider.Empty>\n <div data-testid=\"empty\">No data</div>\n </TamboPropStreamProvider.Empty>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"empty\")).toBeInTheDocument();\n });\n\n it(\"should not render empty when loading\", () => {\n const streamStatus: StreamStatus = {\n isPending: true,\n isStreaming: false,\n isSuccess: false,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Empty>\n <div data-testid=\"empty\">No data</div>\n </TamboPropStreamProvider.Empty>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.queryByTestId(\"empty\")).not.toBeInTheDocument();\n });\n\n it(\"should not render empty when successful\", () => {\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Empty>\n <div data-testid=\"empty\">No data</div>\n </TamboPropStreamProvider.Empty>\n </TamboPropStreamProvider>,\n );\n\n expect(screen.queryByTestId(\"empty\")).not.toBeInTheDocument();\n });\n });\n });\n\n describe(\"Per-Key Status Tracking\", () => {\n it(\"should track status for object keys\", () => {\n const testData = { name: \"John\", age: null };\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={testData} streamStatus={streamStatus}>\n <TestHookComponent testKey=\"name\" />\n </TamboPropStreamProvider>,\n );\n\n const keyStatus = JSON.parse(\n screen.getByTestId(\"key-status\").textContent ?? \"{}\",\n );\n expect(keyStatus.isSuccess).toBe(true); // name has data\n });\n\n it(\"should show loading for keys without data\", () => {\n const testData = { name: \"John\", age: null };\n const streamStatus: StreamStatus = {\n isPending: false,\n isStreaming: false,\n isSuccess: true,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={testData} streamStatus={streamStatus}>\n <TestHookComponent testKey=\"age\" />\n </TamboPropStreamProvider>,\n );\n\n const keyStatus = JSON.parse(\n screen.getByTestId(\"key-status\").textContent ?? \"{}\",\n );\n expect(keyStatus.isPending).toBe(true); // age has no data\n });\n\n it(\"should handle per-key loading states\", () => {\n render(\n <TamboPropStreamProvider data={{ name: \"John\", age: null }}>\n <TamboPropStreamProvider.Loading streamKey=\"name\">\n <div data-testid=\"name-loading\">Name loading...</div>\n </TamboPropStreamProvider.Loading>\n <TamboPropStreamProvider.Loading streamKey=\"age\">\n <div data-testid=\"age-loading\">Age loading...</div>\n </TamboPropStreamProvider.Loading>\n <TamboPropStreamProvider.Complete streamKey=\"name\">\n <div data-testid=\"name-complete\">Name: John</div>\n </TamboPropStreamProvider.Complete>\n </TamboPropStreamProvider>,\n );\n\n // Name should be complete (has data)\n expect(screen.getByTestId(\"name-complete\")).toBeInTheDocument();\n expect(screen.queryByTestId(\"name-loading\")).not.toBeInTheDocument();\n\n // Age should be loading (no data)\n expect(screen.getByTestId(\"age-loading\")).toBeInTheDocument();\n });\n });\n\n describe(\"Edge Cases\", () => {\n it(\"should handle null data gracefully\", () => {\n render(\n <TamboPropStreamProvider data={null}>\n <TestHookComponent />\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"data\")).toHaveTextContent(\"null\");\n });\n\n it(\"should handle undefined data gracefully\", () => {\n render(\n <TamboPropStreamProvider data={undefined}>\n <TestHookComponent />\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"data\")).toHaveTextContent(\"\");\n });\n\n it(\"should handle array data\", () => {\n const arrayData = [\"item1\", \"item2\"];\n render(\n <TamboPropStreamProvider data={arrayData}>\n <TestHookComponent />\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"data\")).toHaveTextContent(\n JSON.stringify(arrayData),\n );\n });\n\n it(\"should handle primitive data types\", () => {\n render(\n <TamboPropStreamProvider data=\"string data\">\n <TestHookComponent />\n </TamboPropStreamProvider>,\n );\n\n expect(screen.getByTestId(\"data\")).toHaveTextContent('\"string data\"');\n });\n\n it(\"should fallback to default status for unknown keys\", () => {\n const testData = { name: \"John\" };\n\n render(\n <TamboPropStreamProvider data={testData}>\n <TestHookComponent testKey=\"unknown-key\" />\n </TamboPropStreamProvider>,\n );\n\n const keyStatus = JSON.parse(\n screen.getByTestId(\"key-status\").textContent ?? \"{}\",\n );\n // Should fallback to default status\n expect(keyStatus.isSuccess).toBe(true);\n });\n });\n\n describe(\"Component Attributes\", () => {\n it(\"should add correct data attributes to components\", () => {\n const streamStatus: StreamStatus = {\n isPending: true,\n isStreaming: false,\n isSuccess: false,\n isError: false,\n };\n\n render(\n <TamboPropStreamProvider data={null} streamStatus={streamStatus}>\n <TamboPropStreamProvider.Loading className=\"loading-class\">\n <div>Loading...</div>\n </TamboPropStreamProvider.Loading>\n </TamboPropStreamProvider>,\n );\n\n const loadingElement = screen.getByText(\"Loading...\").parentElement;\n expect(loadingElement).toHaveAttribute(\"data-stream-key\", \"default\");\n expect(loadingElement).toHaveAttribute(\"data-stream-state\", \"loading\");\n expect(loadingElement).toHaveClass(\"loading-class\");\n });\n });\n});\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export interface InteractableConfig {
|
|
4
|
+
componentName: string;
|
|
5
|
+
description: string;
|
|
6
|
+
propsSchema?: z.ZodTypeAny;
|
|
7
|
+
}
|
|
8
|
+
export interface WithTamboInteractableProps {
|
|
9
|
+
interactableId?: string;
|
|
10
|
+
onInteractableReady?: (id: string) => void;
|
|
11
|
+
onPropsUpdate?: (newProps: Record<string, any>) => void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Higher-Order Component that makes any component interactable by tambo.
|
|
15
|
+
* @param WrappedComponent - The component to make interactable
|
|
16
|
+
* @param config - Configuration for the interactable component
|
|
17
|
+
* @returns A new component that is automatically registered as interactable
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const MyInteractableNote = withTamboInteractable(MyNote, {
|
|
21
|
+
* componentName: "MyNote",
|
|
22
|
+
* description: "A note component",
|
|
23
|
+
* propsSchema: z.object({
|
|
24
|
+
* title: z.string(),
|
|
25
|
+
* content: z.string(),
|
|
26
|
+
* }),
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Usage
|
|
30
|
+
* <MyInteractableNote title="My Note" content="This is my note" />
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function withTamboInteractable<P extends object>(WrappedComponent: React.ComponentType<P>, config: InteractableConfig): React.FC<P & WithTamboInteractableProps>;
|
|
34
|
+
//# sourceMappingURL=with-tambo-interactable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tambo-interactable.d.ts","sourceRoot":"","sources":["../../../src/providers/hoc/with-tambo-interactable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CACzD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACpD,gBAAgB,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EACxC,MAAM,EAAE,kBAAkB,4CA+E3B"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// react-sdk/src/providers/with-interactable.tsx
|
|
2
|
+
"use client";
|
|
3
|
+
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useTamboInteractable } from "../tambo-interactable-provider";
|
|
5
|
+
/**
|
|
6
|
+
* Higher-Order Component that makes any component interactable by tambo.
|
|
7
|
+
* @param WrappedComponent - The component to make interactable
|
|
8
|
+
* @param config - Configuration for the interactable component
|
|
9
|
+
* @returns A new component that is automatically registered as interactable
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const MyInteractableNote = withTamboInteractable(MyNote, {
|
|
13
|
+
* componentName: "MyNote",
|
|
14
|
+
* description: "A note component",
|
|
15
|
+
* propsSchema: z.object({
|
|
16
|
+
* title: z.string(),
|
|
17
|
+
* content: z.string(),
|
|
18
|
+
* }),
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* // Usage
|
|
22
|
+
* <MyInteractableNote title="My Note" content="This is my note" />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function withTamboInteractable(WrappedComponent, config) {
|
|
26
|
+
const displayName = WrappedComponent.displayName ?? WrappedComponent.name ?? "Component";
|
|
27
|
+
const TamboInteractableWrapper = (props) => {
|
|
28
|
+
const { addInteractableComponent, updateInteractableComponentProps, getInteractableComponent, } = useTamboInteractable();
|
|
29
|
+
const [interactableId, setInteractableId] = useState(null);
|
|
30
|
+
const isInitialized = useRef(false);
|
|
31
|
+
const lastParentProps = useRef({});
|
|
32
|
+
// Extract interactable-specific props
|
|
33
|
+
const { onInteractableReady, onPropsUpdate, ...componentProps } = props;
|
|
34
|
+
// Get the current interactable component to track prop updates
|
|
35
|
+
const currentInteractable = interactableId
|
|
36
|
+
? getInteractableComponent(interactableId)
|
|
37
|
+
: null;
|
|
38
|
+
// Use the props from the interactable component if available, otherwise use the passed props
|
|
39
|
+
// We need to be careful not to create a loop, so we only use stored props if they're different from passed props
|
|
40
|
+
const effectiveProps = currentInteractable?.props ?? componentProps;
|
|
41
|
+
// Memoize the registration function
|
|
42
|
+
const registerComponent = useCallback(() => {
|
|
43
|
+
if (!isInitialized.current) {
|
|
44
|
+
const id = addInteractableComponent({
|
|
45
|
+
name: config.componentName,
|
|
46
|
+
description: config.description,
|
|
47
|
+
component: WrappedComponent,
|
|
48
|
+
props: componentProps,
|
|
49
|
+
propsSchema: config.propsSchema,
|
|
50
|
+
});
|
|
51
|
+
setInteractableId(id);
|
|
52
|
+
onInteractableReady?.(id);
|
|
53
|
+
isInitialized.current = true;
|
|
54
|
+
}
|
|
55
|
+
}, [addInteractableComponent, componentProps, onInteractableReady]);
|
|
56
|
+
// Register the component as interactable on mount (only once)
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
registerComponent();
|
|
59
|
+
}, [registerComponent]);
|
|
60
|
+
// Update the interactable component when props change from parent
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (interactableId && isInitialized.current) {
|
|
63
|
+
// Only update if the props are different from what we last sent
|
|
64
|
+
const lastPropsString = JSON.stringify(lastParentProps.current);
|
|
65
|
+
const currentPropsString = JSON.stringify(componentProps);
|
|
66
|
+
if (lastPropsString !== currentPropsString) {
|
|
67
|
+
updateInteractableComponentProps(interactableId, componentProps);
|
|
68
|
+
onPropsUpdate?.(componentProps);
|
|
69
|
+
lastParentProps.current = componentProps;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}, [
|
|
73
|
+
interactableId,
|
|
74
|
+
componentProps,
|
|
75
|
+
updateInteractableComponentProps,
|
|
76
|
+
onPropsUpdate,
|
|
77
|
+
]);
|
|
78
|
+
return React.createElement(WrappedComponent, { ...effectiveProps });
|
|
79
|
+
};
|
|
80
|
+
TamboInteractableWrapper.displayName = `withTamboInteractable(${displayName})`;
|
|
81
|
+
return TamboInteractableWrapper;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=with-tambo-interactable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"with-tambo-interactable.js","sourceRoot":"","sources":["../../../src/providers/hoc/with-tambo-interactable.tsx"],"names":[],"mappings":"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","sourcesContent":["// react-sdk/src/providers/with-interactable.tsx\n\"use client\";\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { z } from \"zod\";\nimport { useTamboInteractable } from \"../tambo-interactable-provider\";\n\nexport interface InteractableConfig {\n componentName: string;\n description: string;\n propsSchema?: z.ZodTypeAny;\n}\n\nexport interface WithTamboInteractableProps {\n interactableId?: string;\n onInteractableReady?: (id: string) => void;\n onPropsUpdate?: (newProps: Record<string, any>) => void;\n}\n\n/**\n * Higher-Order Component that makes any component interactable by tambo.\n * @param WrappedComponent - The component to make interactable\n * @param config - Configuration for the interactable component\n * @returns A new component that is automatically registered as interactable\n * @example\n * ```tsx\n * const MyInteractableNote = withTamboInteractable(MyNote, {\n * componentName: \"MyNote\",\n * description: \"A note component\",\n * propsSchema: z.object({\n * title: z.string(),\n * content: z.string(),\n * }),\n * });\n *\n * // Usage\n * <MyInteractableNote title=\"My Note\" content=\"This is my note\" />\n * ```\n */\nexport function withTamboInteractable<P extends object>(\n WrappedComponent: React.ComponentType<P>,\n config: InteractableConfig,\n) {\n const displayName =\n WrappedComponent.displayName ?? WrappedComponent.name ?? \"Component\";\n\n const TamboInteractableWrapper: React.FC<P & WithTamboInteractableProps> = (\n props,\n ) => {\n const {\n addInteractableComponent,\n updateInteractableComponentProps,\n getInteractableComponent,\n } = useTamboInteractable();\n\n const [interactableId, setInteractableId] = useState<string | null>(null);\n const isInitialized = useRef(false);\n const lastParentProps = useRef<Record<string, any>>({});\n\n // Extract interactable-specific props\n const { onInteractableReady, onPropsUpdate, ...componentProps } =\n props as P & WithTamboInteractableProps;\n\n // Get the current interactable component to track prop updates\n const currentInteractable = interactableId\n ? getInteractableComponent(interactableId)\n : null;\n\n // Use the props from the interactable component if available, otherwise use the passed props\n // We need to be careful not to create a loop, so we only use stored props if they're different from passed props\n const effectiveProps = currentInteractable?.props ?? componentProps;\n\n // Memoize the registration function\n const registerComponent = useCallback(() => {\n if (!isInitialized.current) {\n const id = addInteractableComponent({\n name: config.componentName,\n description: config.description,\n component: WrappedComponent,\n props: componentProps,\n propsSchema: config.propsSchema,\n });\n\n setInteractableId(id);\n onInteractableReady?.(id);\n isInitialized.current = true;\n }\n }, [addInteractableComponent, componentProps, onInteractableReady]);\n\n // Register the component as interactable on mount (only once)\n useEffect(() => {\n registerComponent();\n }, [registerComponent]);\n\n // Update the interactable component when props change from parent\n useEffect(() => {\n if (interactableId && isInitialized.current) {\n // Only update if the props are different from what we last sent\n const lastPropsString = JSON.stringify(lastParentProps.current);\n const currentPropsString = JSON.stringify(componentProps);\n\n if (lastPropsString !== currentPropsString) {\n updateInteractableComponentProps(interactableId, componentProps);\n onPropsUpdate?.(componentProps);\n lastParentProps.current = componentProps;\n }\n }\n }, [\n interactableId,\n componentProps,\n updateInteractableComponentProps,\n onPropsUpdate,\n ]);\n\n return <WrappedComponent {...(effectiveProps as P)} />;\n };\n\n TamboInteractableWrapper.displayName = `withTamboInteractable(${displayName})`;\n\n return TamboInteractableWrapper;\n}\n"]}
|
package/esm/providers/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type { TamboComponent, TamboTool } from "../model/component-metadata";
|
|
2
2
|
export { TamboClientProvider, useTamboClient } from "./tambo-client-provider";
|
|
3
3
|
export { TamboComponentProvider, useTamboComponent, } from "./tambo-component-provider";
|
|
4
|
+
export { TamboPropStreamProvider, useTamboStream, } from "./tambo-prop-stream-provider";
|
|
5
|
+
export type { TamboPropStreamProviderProps, LoadingProps, EmptyProps, CompleteProps, } from "./tambo-prop-stream-provider";
|
|
4
6
|
export { TamboContext, TamboProvider, useTambo } from "./tambo-provider";
|
|
5
7
|
export { TamboRegistryProvider, useTamboRegistry, type TamboRegistryContext, } from "./tambo-registry-provider";
|
|
6
8
|
export { TamboStubProvider, type TamboStubProviderProps } from "./tambo-stubs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,oBAAoB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,uBAAuB,EACvB,cAAc,GACf,MAAM,8BAA8B,CAAC;AACtC,YAAY,EACV,4BAA4B,EAC5B,YAAY,EACZ,UAAU,EACV,aAAa,GACd,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,KAAK,oBAAoB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,yBAAyB,CAAC"}
|
package/esm/providers/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { TamboClientProvider, useTamboClient } from "./tambo-client-provider";
|
|
2
2
|
export { TamboComponentProvider, useTamboComponent, } from "./tambo-component-provider";
|
|
3
|
+
export { TamboPropStreamProvider, useTamboStream, } from "./tambo-prop-stream-provider";
|
|
3
4
|
export { TamboContext, TamboProvider, useTambo } from "./tambo-provider";
|
|
4
5
|
export { TamboRegistryProvider, useTamboRegistry, } from "./tambo-registry-provider";
|
|
5
6
|
export { TamboStubProvider } from "./tambo-stubs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAA+B,MAAM,eAAe,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,yBAAyB,CAAC","sourcesContent":["export type { TamboComponent, TamboTool } from \"../model/component-metadata\";\nexport { TamboClientProvider, useTamboClient } from \"./tambo-client-provider\";\nexport {\n TamboComponentProvider,\n useTamboComponent,\n} from \"./tambo-component-provider\";\nexport { TamboContext, TamboProvider, useTambo } from \"./tambo-provider\";\nexport {\n TamboRegistryProvider,\n useTamboRegistry,\n type TamboRegistryContext,\n} from \"./tambo-registry-provider\";\nexport { TamboStubProvider, type TamboStubProviderProps } from \"./tambo-stubs\";\nexport {\n TamboThreadContext,\n TamboThreadProvider,\n useTamboThread,\n} from \"./tambo-thread-provider\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,uBAAuB,EACvB,cAAc,GACf,MAAM,8BAA8B,CAAC;AAOtC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAEjB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,iBAAiB,EAA+B,MAAM,eAAe,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,cAAc,GACf,MAAM,yBAAyB,CAAC","sourcesContent":["export type { TamboComponent, TamboTool } from \"../model/component-metadata\";\nexport { TamboClientProvider, useTamboClient } from \"./tambo-client-provider\";\nexport {\n TamboComponentProvider,\n useTamboComponent,\n} from \"./tambo-component-provider\";\nexport {\n TamboPropStreamProvider,\n useTamboStream,\n} from \"./tambo-prop-stream-provider\";\nexport type {\n TamboPropStreamProviderProps,\n LoadingProps,\n EmptyProps,\n CompleteProps,\n} from \"./tambo-prop-stream-provider\";\nexport { TamboContext, TamboProvider, useTambo } from \"./tambo-provider\";\nexport {\n TamboRegistryProvider,\n useTamboRegistry,\n type TamboRegistryContext,\n} from \"./tambo-registry-provider\";\nexport { TamboStubProvider, type TamboStubProviderProps } from \"./tambo-stubs\";\nexport {\n TamboThreadContext,\n TamboThreadProvider,\n useTamboThread,\n} from \"./tambo-thread-provider\";\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
|
+
import { type TamboInteractableContext } from "../model/tambo-interactable";
|
|
3
|
+
declare const TamboInteractableContext: React.Context<TamboInteractableContext>;
|
|
4
|
+
/**
|
|
5
|
+
* The TamboInteractableProvider manages a list of components that are currently
|
|
6
|
+
* interactable, allowing tambo to interact with them by updating their props. It also registers tools
|
|
7
|
+
* for Tambo to perform CRUD operations on the components list.
|
|
8
|
+
* @param props - The props for the TamboInteractableProvider
|
|
9
|
+
* @param props.children - The children to wrap
|
|
10
|
+
* @returns The TamboInteractableProvider component
|
|
11
|
+
*/
|
|
12
|
+
export declare const TamboInteractableProvider: React.FC<PropsWithChildren>;
|
|
13
|
+
/**
|
|
14
|
+
* The useTamboInteractable hook provides access to the interactable component
|
|
15
|
+
* management functions.
|
|
16
|
+
* @returns The interactable component management functions
|
|
17
|
+
*/
|
|
18
|
+
export declare const useTamboInteractable: () => TamboInteractableContext;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=tambo-interactable-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tambo-interactable-provider.d.ts","sourceRoot":"","sources":["../../src/providers/tambo-interactable-provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAEZ,iBAAiB,EAKlB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,6BAA6B,CAAC;AAGrC,QAAA,MAAM,wBAAwB,yCAQ5B,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4PjE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,gCAEhC,CAAC"}
|