@bitbitpress/client 1.1.0-alpha.0 → 1.1.0-alpha.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/README.md +224 -0
- package/dist/react/index.d.ts +25 -6
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +26 -9
- package/dist/react/index.js.map +1 -1
- package/dist/react-native-expo/index.d.ts +20 -9
- package/dist/react-native-expo/index.d.ts.map +1 -1
- package/dist/react-native-expo/index.js +25 -11
- package/dist/react-native-expo/index.js.map +1 -1
- package/dist/synthesisView/devLog.d.ts +10 -0
- package/dist/synthesisView/devLog.d.ts.map +1 -0
- package/dist/synthesisView/devLog.js +23 -0
- package/dist/synthesisView/devLog.js.map +1 -0
- package/dist/synthesisView/engine.js +27 -1
- package/dist/synthesisView/engine.js.map +1 -1
- package/dist/synthesisView/types.d.ts +50 -1
- package/dist/synthesisView/types.d.ts.map +1 -1
- package/dist/synthesisView/useEventDrivenView.d.ts +32 -0
- package/dist/synthesisView/useEventDrivenView.d.ts.map +1 -0
- package/dist/synthesisView/useEventDrivenView.js +157 -0
- package/dist/synthesisView/useEventDrivenView.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1141,3 +1141,227 @@ type InteractionResponseResponse = {
|
|
|
1141
1141
|
appUserResponse: Record<string, unknown>;
|
|
1142
1142
|
}
|
|
1143
1143
|
```
|
|
1144
|
+
|
|
1145
|
+
## Synthesis Views
|
|
1146
|
+
|
|
1147
|
+
A **synthesis view** is a UI that BitBit Press generates on the server for a
|
|
1148
|
+
named placement in your app (a feed card, a detail panel, a settings
|
|
1149
|
+
screen, etc.). You set up the view once in the BitBit CMS — choose a key
|
|
1150
|
+
name, write a prompt, point it at a synthesis config. Then in your app you
|
|
1151
|
+
mount it like this:
|
|
1152
|
+
|
|
1153
|
+
```tsx
|
|
1154
|
+
<BitBitView client={client} keyName="story-card" />
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
The SDK fetches the generated UI, renders it using a small library of
|
|
1158
|
+
built-in primitives (`Row`, `Column`, `Text`, `Image`, `Button`, etc.), and
|
|
1159
|
+
splices in any of your own React components you've registered. As the user
|
|
1160
|
+
interacts with the UI, the SDK either routes the event to you (so your app
|
|
1161
|
+
handles navigation, mutations, etc.) or sends it back to the server so the
|
|
1162
|
+
agent can generate the next UI.
|
|
1163
|
+
|
|
1164
|
+
The same surface is exported from both `@bitbitpress/client/react` and
|
|
1165
|
+
`@bitbitpress/client/react-native-expo`. This section uses the web names;
|
|
1166
|
+
the Expo entry is identical.
|
|
1167
|
+
|
|
1168
|
+
### Quick start
|
|
1169
|
+
|
|
1170
|
+
```tsx
|
|
1171
|
+
import { BitBitView } from '@bitbitpress/client/react';
|
|
1172
|
+
import client from '@/lib/bitbit-client';
|
|
1173
|
+
import { MyCard } from '@/components/my-card';
|
|
1174
|
+
|
|
1175
|
+
export function Feed({ keyName }: { keyName: string }) {
|
|
1176
|
+
return (
|
|
1177
|
+
<BitBitView
|
|
1178
|
+
client={client}
|
|
1179
|
+
keyName={keyName}
|
|
1180
|
+
components={{ MyCard }}
|
|
1181
|
+
onEvent={(event) => console.log('host event', event)}
|
|
1182
|
+
/>
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
That's enough to render any view whose generated UI uses only the SDK's
|
|
1188
|
+
built-in primitives, plus your `MyCard`.
|
|
1189
|
+
|
|
1190
|
+
### Registering your own components
|
|
1191
|
+
|
|
1192
|
+
In the CMS you can register a component as **"provided by your app"** —
|
|
1193
|
+
the server then refers to it by a name like `MyCard` in the generated UI,
|
|
1194
|
+
and the SDK looks it up in your registry to render it. The mapping from
|
|
1195
|
+
name to React component is what you pass in `components`:
|
|
1196
|
+
|
|
1197
|
+
```tsx
|
|
1198
|
+
<BitBitView
|
|
1199
|
+
client={client}
|
|
1200
|
+
keyName="story-card"
|
|
1201
|
+
components={{ MyCard, MyButton, MyAvatar }}
|
|
1202
|
+
/>
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
If you'll use the same component map across many views, register them
|
|
1206
|
+
once at the top of your app with `BitBitProvider` instead. Per-view
|
|
1207
|
+
`components` overrides still apply:
|
|
1208
|
+
|
|
1209
|
+
```tsx
|
|
1210
|
+
import { BitBitProvider } from '@bitbitpress/client/react';
|
|
1211
|
+
|
|
1212
|
+
<BitBitProvider components={{ MyCard, MyButton, MyAvatar }}>
|
|
1213
|
+
<App />
|
|
1214
|
+
</BitBitProvider>
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
Components receive their bound props from the CMS contract you set up,
|
|
1218
|
+
plus a `children` prop when the view nested other components inside
|
|
1219
|
+
them. See [Handling events](#handling-events) below for how to also
|
|
1220
|
+
accept event callbacks.
|
|
1221
|
+
|
|
1222
|
+
### Rendering pre-fetched UI
|
|
1223
|
+
|
|
1224
|
+
If you already have the generated UI as a `uiData` array (for example,
|
|
1225
|
+
you cached the most recent response, or you're rendering a gallery of
|
|
1226
|
+
tiles fetched in one shot), use `BitBitViewRenderer` to skip the fetch:
|
|
1227
|
+
|
|
1228
|
+
```tsx
|
|
1229
|
+
import { BitBitViewRenderer, type FlatUiNode } from '@bitbitpress/client/react';
|
|
1230
|
+
|
|
1231
|
+
export function StaticTile({ uiData }: { uiData: FlatUiNode[] }) {
|
|
1232
|
+
return <BitBitViewRenderer uiData={uiData} components={{ MyCard }} />;
|
|
1233
|
+
}
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
### Handling events
|
|
1237
|
+
|
|
1238
|
+
Each event the view emits has a `handleWith` setting (chosen in the CMS):
|
|
1239
|
+
|
|
1240
|
+
- **`HOST`** — the SDK forwards the event to your `onEvent` callback and
|
|
1241
|
+
does nothing else. Use this for navigation, mutations, anything where
|
|
1242
|
+
your app owns the consequence.
|
|
1243
|
+
- **`AGENT`** — the SDK sends the event back to the synthesis endpoint
|
|
1244
|
+
with the prior UI as context, the agent returns a new UI, and the SDK
|
|
1245
|
+
re-renders with it. Your `onEvent` is **not** called for AGENT events
|
|
1246
|
+
(the handling is internal); they show up in the dev log if you need to
|
|
1247
|
+
observe them. Nodes whose ids appear in both the old and new tree
|
|
1248
|
+
preserve their React state, so a well-behaved view feels like a
|
|
1249
|
+
partial update rather than a full reload.
|
|
1250
|
+
|
|
1251
|
+
```tsx
|
|
1252
|
+
<BitBitView
|
|
1253
|
+
client={client}
|
|
1254
|
+
keyName="story-card"
|
|
1255
|
+
onEvent={(event) => {
|
|
1256
|
+
if (event.name === 'open-detail') {
|
|
1257
|
+
navigation.push('Detail', { id: event.payload.id });
|
|
1258
|
+
}
|
|
1259
|
+
}}
|
|
1260
|
+
/>
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
The event object you receive is:
|
|
1264
|
+
|
|
1265
|
+
```ts
|
|
1266
|
+
{
|
|
1267
|
+
name: string; // identifier from the CMS event binding
|
|
1268
|
+
componentName: string; // name of the component that fired
|
|
1269
|
+
slot: string; // which slot on the component (e.g. 'onClick')
|
|
1270
|
+
payload: object; // anything the binding declared + anything the host passed
|
|
1271
|
+
}
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
The runtime also includes a `nodeId` (the internal id of the rendered
|
|
1275
|
+
instance) and `handleWith` (always `'HOST'` by the time your callback
|
|
1276
|
+
runs). Both are present for debugging and rarely need to be consumed.
|
|
1277
|
+
|
|
1278
|
+
#### Events on your components
|
|
1279
|
+
|
|
1280
|
+
If you registered a component with events in its CMS contract (e.g. an
|
|
1281
|
+
`onClick` slot), the SDK passes a callback for that slot as a prop. Call
|
|
1282
|
+
it from inside your component to fire the event through the BB pipeline,
|
|
1283
|
+
exactly as if it had come from a built-in primitive:
|
|
1284
|
+
|
|
1285
|
+
```tsx
|
|
1286
|
+
function MyCard({
|
|
1287
|
+
title,
|
|
1288
|
+
onClick,
|
|
1289
|
+
}: {
|
|
1290
|
+
title: string;
|
|
1291
|
+
onClick?: (payload?: unknown) => void;
|
|
1292
|
+
}) {
|
|
1293
|
+
return <Pressable onPress={() => onClick?.()}>{title}</Pressable>;
|
|
1294
|
+
}
|
|
1295
|
+
```
|
|
1296
|
+
|
|
1297
|
+
Anything you pass (a plain object) is merged with the payload the CMS
|
|
1298
|
+
binding declared before the event fires.
|
|
1299
|
+
|
|
1300
|
+
### When a component name isn't registered
|
|
1301
|
+
|
|
1302
|
+
If the generated UI references a component name you haven't registered,
|
|
1303
|
+
the SDK falls back to a placeholder. The default behavior depends on
|
|
1304
|
+
your environment:
|
|
1305
|
+
|
|
1306
|
+
- **Development** (`process.env.NODE_ENV !== 'production'`) — renders a
|
|
1307
|
+
labeled marker (`⚠ Unknown component: X`) so you can see what's
|
|
1308
|
+
missing.
|
|
1309
|
+
- **Production** — renders nothing. Avoids visible debug artifacts in
|
|
1310
|
+
real user UIs as you grow the registry over time.
|
|
1311
|
+
|
|
1312
|
+
Override with `renderUnknown`, or set `dev` to force development behavior
|
|
1313
|
+
in environments where `NODE_ENV` doesn't reflect what you want (for
|
|
1314
|
+
example, a CMS preview tool that ships as a production build but should
|
|
1315
|
+
still surface missing components):
|
|
1316
|
+
|
|
1317
|
+
```tsx
|
|
1318
|
+
<BitBitView client={client} keyName={keyName} dev /> // always show warnings
|
|
1319
|
+
<BitBitView
|
|
1320
|
+
client={client}
|
|
1321
|
+
keyName={keyName}
|
|
1322
|
+
renderUnknown={(name) => <YourPlaceholder name={name} />}
|
|
1323
|
+
/>
|
|
1324
|
+
```
|
|
1325
|
+
|
|
1326
|
+
### Performance: speculative preloading
|
|
1327
|
+
|
|
1328
|
+
The SDK can prefetch the next UI for AGENT events whose payload it can
|
|
1329
|
+
predict ahead of time, so the user's click lands on a cached response
|
|
1330
|
+
with no server roundtrip. This is on by default. To disable:
|
|
1331
|
+
|
|
1332
|
+
```tsx
|
|
1333
|
+
<BitBitView client={client} keyName={keyName} preloadNextUi={false} />
|
|
1334
|
+
```
|
|
1335
|
+
|
|
1336
|
+
### Dev diagnostics
|
|
1337
|
+
|
|
1338
|
+
In dev mode (or when you pass `dev={true}`), the SDK prints every event
|
|
1339
|
+
to the console, prefixed with `[BB]`:
|
|
1340
|
+
|
|
1341
|
+
```
|
|
1342
|
+
[BB] event MyCard.onClick → AGENT { name: 'open-detail', payload: { id: '…' }, ... }
|
|
1343
|
+
```
|
|
1344
|
+
|
|
1345
|
+
These logs are completely stripped in production builds — no SDK chatter
|
|
1346
|
+
in real user devices.
|
|
1347
|
+
|
|
1348
|
+
### Custom rendering (advanced)
|
|
1349
|
+
|
|
1350
|
+
If you want to render the UI tree yourself but still use the SDK's fetch +
|
|
1351
|
+
AGENT continuation + preload cache, use the hook directly:
|
|
1352
|
+
|
|
1353
|
+
```tsx
|
|
1354
|
+
import { useEventDrivenView } from '@bitbitpress/client/react';
|
|
1355
|
+
|
|
1356
|
+
const { uiData, loading, error, handleEvent } = useEventDrivenView(
|
|
1357
|
+
client,
|
|
1358
|
+
keyName,
|
|
1359
|
+
onHostEvent,
|
|
1360
|
+
contentInputs,
|
|
1361
|
+
viewInputs,
|
|
1362
|
+
);
|
|
1363
|
+
```
|
|
1364
|
+
|
|
1365
|
+
`uiData` is the same array `BitBitViewRenderer` consumes; wire
|
|
1366
|
+
`handleEvent` as your custom renderer's event callback to keep AGENT
|
|
1367
|
+
events flowing through the SDK.
|
package/dist/react/index.d.ts
CHANGED
|
@@ -2,35 +2,54 @@ import { type RenderUnknown, type SynthesisViewTreeProps } from '../synthesisVie
|
|
|
2
2
|
import type { ComponentMap, ContentInput, SynthesisViewEvent, SynthesizeViewFetcher } from '../synthesisView/types.js';
|
|
3
3
|
export { type BitBitContextValue, BitBitProvider } from '../synthesisView/context.js';
|
|
4
4
|
export { createComponentMap, type GlobModules, type RequireContext, } from '../synthesisView/createComponentMap.js';
|
|
5
|
-
export type { ComponentMap, ContentInput, FlatUiKeyNameNode, FlatUiNode, FlatUiPrimitiveNode, SynthesisViewEvent, SynthesizeViewFetcher, ViewInputs, } from '../synthesisView/types.js';
|
|
5
|
+
export type { ComponentMap, ContentInput, FlatUiKeyNameNode, FlatUiNode, FlatUiPrimitiveNode, SynthesisViewEvent, SynthesisViewEventInput, SynthesizeViewFetcher, ViewEventHandleWith, ViewInputs, } from '../synthesisView/types.js';
|
|
6
|
+
export { type UseEventDrivenViewOptions, type UseEventDrivenViewResult, useEventDrivenView, } from '../synthesisView/useEventDrivenView.js';
|
|
6
7
|
export { bitBitBuiltins } from './primitives.js';
|
|
7
8
|
export type BitBitViewRendererProps = Omit<SynthesisViewTreeProps, 'renderUnknown' | 'defaultComponents'> & {
|
|
8
|
-
/** Override how unregistered components render. Defaults to a
|
|
9
|
+
/** Override how unregistered components render. Defaults to a dev-only
|
|
10
|
+
* marker (see {@link isDevEnvironment}). */
|
|
9
11
|
renderUnknown?: RenderUnknown;
|
|
12
|
+
/** Force the in-dev warning behavior regardless of `process.env.NODE_ENV`.
|
|
13
|
+
* Set true in CMS / preview hosts (e.g. BitBitPress's own admin UI) so
|
|
14
|
+
* unknown components stay visible even when those hosts are built in
|
|
15
|
+
* production mode. Defaults to env-derived. */
|
|
16
|
+
dev?: boolean;
|
|
10
17
|
};
|
|
11
18
|
/** Web renderer for a pre-fetched `uiData` array. BB built-in primitives are
|
|
12
19
|
* registered automatically; pass `components` to add or override entries by
|
|
13
20
|
* name. Use `<BitBitView>` if you want it to fetch for you. */
|
|
14
|
-
export declare function BitBitViewRenderer({ renderUnknown, ...rest }: BitBitViewRendererProps): import("react").FunctionComponentElement<SynthesisViewTreeProps>;
|
|
21
|
+
export declare function BitBitViewRenderer({ renderUnknown, dev, onEvent, ...rest }: BitBitViewRendererProps): import("react").FunctionComponentElement<SynthesisViewTreeProps>;
|
|
15
22
|
export type BitBitViewProps = {
|
|
16
23
|
/** A BitBitPressClient (or anything with `user.synthesizeViewItem`). */
|
|
17
24
|
client: SynthesizeViewFetcher;
|
|
18
25
|
keyName: string;
|
|
19
26
|
contentInputs?: ContentInput[];
|
|
20
27
|
components?: ComponentMap;
|
|
28
|
+
/** Fires for `HOST` events the component contract declared. `AGENT`
|
|
29
|
+
* events are handled internally — the SDK rounds-trips to the synthesis
|
|
30
|
+
* endpoint and swaps the UI in place; customers don't see them unless
|
|
31
|
+
* they explicitly opt in via the contract. */
|
|
21
32
|
onEvent?: (event: SynthesisViewEvent) => void;
|
|
22
33
|
renderUnknown?: RenderUnknown;
|
|
34
|
+
/** Force the in-dev warning behavior regardless of `process.env.NODE_ENV`.
|
|
35
|
+
* See {@link BitBitViewRendererProps.dev}. */
|
|
36
|
+
dev?: boolean;
|
|
23
37
|
/** Force a dark/light mode. Defaults to the browser's
|
|
24
38
|
* `prefers-color-scheme` (live-updates if the user toggles their OS
|
|
25
39
|
* theme). */
|
|
26
40
|
darkMode?: boolean;
|
|
41
|
+
/** When true (default), speculatively prefetches the agent's next-UI for
|
|
42
|
+
* AGENT events whose payloads don't need runtime input. Real clicks land
|
|
43
|
+
* on the cached response with zero server roundtrip. Set false to
|
|
44
|
+
* disable. */
|
|
45
|
+
preloadNextUi?: boolean;
|
|
27
46
|
};
|
|
28
47
|
/**
|
|
29
48
|
* Web view: fetches a synthesis view by `keyName` and renders it in place.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
49
|
+
* AGENT-handled events drive the next UI back through the agent
|
|
50
|
+
* (preloaded when possible). HOST events fire to `onEvent`.
|
|
32
51
|
*/
|
|
33
|
-
export declare function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, darkMode, }: BitBitViewProps): import("react").DetailedReactHTMLElement<{
|
|
52
|
+
export declare function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, dev, darkMode, preloadNextUi, }: BitBitViewProps): import("react").DetailedReactHTMLElement<{
|
|
34
53
|
'data-bitbit-error': boolean;
|
|
35
54
|
style: {
|
|
36
55
|
color: "#b00020";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAAE,KAAK,kBAAkB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EACL,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,wCAAwC,CAAC;AAChD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,EACnB,UAAU,GACX,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,kBAAkB,GACnB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAsBjD,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,sBAAsB,EACtB,eAAe,GAAG,mBAAmB,CACtC,GAAG;IACF;iDAC6C;IAC7C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;oDAGgD;IAChD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AA6BF;;gEAEgE;AAChE,wBAAgB,kBAAkB,CAAC,EACjC,aAAa,EACb,GAAG,EACH,OAAO,EACP,GAAG,IAAI,EACR,EAAE,uBAAuB,oEAQzB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,wEAAwE;IACxE,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B;;;mDAG+C;IAC/C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;mDAC+C;IAC/C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;kBAEc;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;mBAGe;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,OAAO,EACP,aAAa,EACb,UAAU,EACV,OAAO,EACP,aAAa,EACb,GAAG,EACH,QAAQ,EACR,aAAa,GACd,EAAE,eAAe;;;;;;;2FAgCjB"}
|
package/dist/react/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createElement, useEffect, useState } from 'react';
|
|
2
|
+
import { devLog, isDevEnvironment } from '../synthesisView/devLog.js';
|
|
2
3
|
import { SynthesisViewTree, } from '../synthesisView/engine.js';
|
|
3
|
-
import {
|
|
4
|
+
import { useEventDrivenView } from '../synthesisView/useEventDrivenView.js';
|
|
4
5
|
import { bitBitBuiltins } from './primitives.js';
|
|
5
6
|
export { BitBitProvider } from '../synthesisView/context.js';
|
|
6
7
|
export { createComponentMap, } from '../synthesisView/createComponentMap.js';
|
|
8
|
+
export { useEventDrivenView, } from '../synthesisView/useEventDrivenView.js';
|
|
7
9
|
export { bitBitBuiltins } from './primitives.js';
|
|
8
10
|
/** Track the browser's `prefers-color-scheme` and re-render on change. Returns
|
|
9
11
|
* `null` during SSR or when the API isn't available — callers fall back to
|
|
@@ -24,30 +26,44 @@ function useSystemDarkMode() {
|
|
|
24
26
|
}, []);
|
|
25
27
|
return isDark;
|
|
26
28
|
}
|
|
27
|
-
const
|
|
29
|
+
const renderUnknownWarning = (name) => createElement('span', {
|
|
28
30
|
'data-bitbit-unknown': name,
|
|
29
31
|
style: { color: '#b00020', fontFamily: 'monospace', fontSize: 12 },
|
|
30
32
|
}, `⚠ Unknown component: ${name}`);
|
|
33
|
+
/** Silent in production: an unknown name renders nothing rather than splashing
|
|
34
|
+
* a debug marker in the customer's real app. */
|
|
35
|
+
const renderUnknownSilent = () => null;
|
|
36
|
+
/** Wrap `onEvent` so each emission prints to the console with the dispatch
|
|
37
|
+
* routing inline. Routed through {@link devLog} so the message is auto-
|
|
38
|
+
* prefixed with `[BB]` and stripped to a no-op outside dev. */
|
|
39
|
+
function withDevEventLog(dev, onEvent) {
|
|
40
|
+
return (event) => {
|
|
41
|
+
devLog(dev, `event ${event.componentName}.${event.slot} → ${event.handleWith}`, event);
|
|
42
|
+
onEvent?.(event);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
31
45
|
/** Web renderer for a pre-fetched `uiData` array. BB built-in primitives are
|
|
32
46
|
* registered automatically; pass `components` to add or override entries by
|
|
33
47
|
* name. Use `<BitBitView>` if you want it to fetch for you. */
|
|
34
|
-
export function BitBitViewRenderer({ renderUnknown, ...rest }) {
|
|
48
|
+
export function BitBitViewRenderer({ renderUnknown, dev, onEvent, ...rest }) {
|
|
49
|
+
const isDev = dev ?? isDevEnvironment();
|
|
35
50
|
return createElement(SynthesisViewTree, {
|
|
36
51
|
...rest,
|
|
37
52
|
defaultComponents: bitBitBuiltins,
|
|
38
|
-
renderUnknown: renderUnknown ??
|
|
53
|
+
renderUnknown: renderUnknown ?? (isDev ? renderUnknownWarning : renderUnknownSilent),
|
|
54
|
+
onEvent: isDev ? withDevEventLog(dev, onEvent) : onEvent,
|
|
39
55
|
});
|
|
40
56
|
}
|
|
41
57
|
/**
|
|
42
58
|
* Web view: fetches a synthesis view by `keyName` and renders it in place.
|
|
43
|
-
*
|
|
44
|
-
*
|
|
59
|
+
* AGENT-handled events drive the next UI back through the agent
|
|
60
|
+
* (preloaded when possible). HOST events fire to `onEvent`.
|
|
45
61
|
*/
|
|
46
|
-
export function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, darkMode, }) {
|
|
62
|
+
export function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, dev, darkMode, preloadNextUi, }) {
|
|
47
63
|
const systemDark = useSystemDarkMode();
|
|
48
64
|
const resolvedDark = darkMode ?? systemDark ?? undefined;
|
|
49
65
|
const viewInputs = resolvedDark !== undefined ? { darkMode: resolvedDark } : undefined;
|
|
50
|
-
const { uiData, loading, error } =
|
|
66
|
+
const { uiData, loading, error, handleEvent } = useEventDrivenView(client, keyName, onEvent, contentInputs, viewInputs, { preloadNextUi });
|
|
51
67
|
if (loading)
|
|
52
68
|
return null;
|
|
53
69
|
if (error) {
|
|
@@ -61,8 +77,9 @@ export function BitBitView({ client, keyName, contentInputs, components, onEvent
|
|
|
61
77
|
return createElement(BitBitViewRenderer, {
|
|
62
78
|
uiData,
|
|
63
79
|
components,
|
|
64
|
-
onEvent,
|
|
80
|
+
onEvent: handleEvent,
|
|
65
81
|
renderUnknown,
|
|
82
|
+
dev,
|
|
66
83
|
});
|
|
67
84
|
}
|
|
68
85
|
//# sourceMappingURL=index.js.map
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAEL,iBAAiB,GAElB,MAAM,4BAA4B,CAAC;AAQpC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAEL,iBAAiB,GAElB,MAAM,4BAA4B,CAAC;AAQpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAA2B,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EACL,kBAAkB,GAGnB,MAAM,wCAAwC,CAAC;AAahD,OAAO,EAGL,kBAAkB,GACnB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;4BAE4B;AAC5B,SAAS,iBAAiB;IACxB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAiB,GAAG,EAAE;QACxD,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QACrE,OAAO,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC,OAAO,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;YAAE,OAAO;QAChE,MAAM,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAG,CAAC,CAAsB,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAClE,EAAE,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC1D,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,MAAM,CAAC;AAChB,CAAC;AAgBD,MAAM,oBAAoB,GAAkB,CAAC,IAAI,EAAE,EAAE,CACnD,aAAa,CACX,MAAM,EACN;IACE,qBAAqB,EAAE,IAAI;IAC3B,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE;CACnE,EACD,wBAAwB,IAAI,EAAE,CAC/B,CAAC;AAEJ;iDACiD;AACjD,MAAM,mBAAmB,GAAkB,GAAG,EAAE,CAAC,IAAI,CAAC;AAEtD;;gEAEgE;AAChE,SAAS,eAAe,CACtB,GAAwB,EACxB,OAA0C;IAE1C,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED;;gEAEgE;AAChE,MAAM,UAAU,kBAAkB,CAAC,EACjC,aAAa,EACb,GAAG,EACH,OAAO,EACP,GAAG,IAAI,EACiB;IACxB,MAAM,KAAK,GAAG,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACxC,OAAO,aAAa,CAAC,iBAAiB,EAAE;QACtC,GAAG,IAAI;QACP,iBAAiB,EAAE,cAAc;QACjC,aAAa,EAAE,aAAa,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACpF,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO;KACzD,CAAC,CAAC;AACL,CAAC;AA4BD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,MAAM,EACN,OAAO,EACP,aAAa,EACb,UAAU,EACV,OAAO,EACP,aAAa,EACb,GAAG,EACH,QAAQ,EACR,aAAa,GACG;IAChB,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,MAAM,YAAY,GAAG,QAAQ,IAAI,UAAU,IAAI,SAAS,CAAC;IACzD,MAAM,UAAU,GACd,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,kBAAkB,CAChE,MAAM,EACN,OAAO,EACP,OAAO,EACP,aAAa,EACb,UAAU,EACV,EAAE,aAAa,EAAE,CAClB,CAAC;IACF,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,aAAa,CAClB,KAAK,EACL;YACE,mBAAmB,EAAE,IAAI;YACzB,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE;SACnE,EACD,KAAK,CACN,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,aAAa,CAAC,kBAAkB,EAAE;QACvC,MAAM;QACN,UAAU;QACV,OAAO,EAAE,WAAW;QACpB,aAAa;QACb,GAAG;KACJ,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -2,15 +2,18 @@ import { type RenderUnknown, type SynthesisViewTreeProps } from '../synthesisVie
|
|
|
2
2
|
import type { ComponentMap, ContentInput, SynthesisViewEvent, SynthesizeViewFetcher } from '../synthesisView/types.js';
|
|
3
3
|
export { type BitBitContextValue, BitBitProvider } from '../synthesisView/context.js';
|
|
4
4
|
export { createComponentMap, type GlobModules, type RequireContext, } from '../synthesisView/createComponentMap.js';
|
|
5
|
-
export type { ComponentMap, ContentInput, FlatUiKeyNameNode, FlatUiNode, FlatUiPrimitiveNode, SynthesisViewEvent, SynthesizeViewFetcher, ViewInputs, } from '../synthesisView/types.js';
|
|
5
|
+
export type { ComponentMap, ContentInput, FlatUiKeyNameNode, FlatUiNode, FlatUiPrimitiveNode, SynthesisViewEvent, SynthesisViewEventInput, SynthesizeViewFetcher, ViewEventHandleWith, ViewInputs, } from '../synthesisView/types.js';
|
|
6
|
+
export { type UseEventDrivenViewOptions, type UseEventDrivenViewResult, useEventDrivenView, } from '../synthesisView/useEventDrivenView.js';
|
|
6
7
|
export { bitBitBuiltins } from './primitives.js';
|
|
7
8
|
export type BitBitViewRendererProps = Omit<SynthesisViewTreeProps, 'renderUnknown' | 'defaultComponents'> & {
|
|
8
9
|
/**
|
|
9
|
-
* Override how unregistered components render. Defaults
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Override how unregistered components render. Defaults are env-derived:
|
|
11
|
+
* a dev-only warning marker when `process.env.NODE_ENV !== 'production'`,
|
|
12
|
+
* silent in production builds. Set `dev` to force the warning behavior.
|
|
12
13
|
*/
|
|
13
14
|
renderUnknown?: RenderUnknown;
|
|
15
|
+
/** Force the in-dev warning behavior regardless of `process.env.NODE_ENV`. */
|
|
16
|
+
dev?: boolean;
|
|
14
17
|
};
|
|
15
18
|
/**
|
|
16
19
|
* React Native (Expo) renderer for a pre-fetched `uiData` array. BB built-in
|
|
@@ -19,24 +22,32 @@ export type BitBitViewRendererProps = Omit<SynthesisViewTreeProps, 'renderUnknow
|
|
|
19
22
|
* on Expo packages (`expo-linear-gradient`, etc.). Use `<BitBitView>` if you
|
|
20
23
|
* want it to fetch for you.
|
|
21
24
|
*/
|
|
22
|
-
export declare function BitBitViewRenderer({ renderUnknown, ...rest }: BitBitViewRendererProps): import("react").FunctionComponentElement<SynthesisViewTreeProps>;
|
|
25
|
+
export declare function BitBitViewRenderer({ renderUnknown, dev, onEvent, ...rest }: BitBitViewRendererProps): import("react").FunctionComponentElement<SynthesisViewTreeProps>;
|
|
23
26
|
export type BitBitViewProps = {
|
|
24
27
|
/** A BitBitPressClient (or anything with `user.synthesizeViewItem`). */
|
|
25
28
|
client: SynthesizeViewFetcher;
|
|
26
29
|
keyName: string;
|
|
27
30
|
contentInputs?: ContentInput[];
|
|
28
31
|
components?: ComponentMap;
|
|
32
|
+
/** Fires for `HOST` events the component contract declared. `AGENT`
|
|
33
|
+
* events are handled internally — the SDK round-trips to the synthesis
|
|
34
|
+
* endpoint and swaps the UI in place. */
|
|
29
35
|
onEvent?: (event: SynthesisViewEvent) => void;
|
|
30
36
|
renderUnknown?: RenderUnknown;
|
|
37
|
+
/** Force the in-dev warning behavior regardless of `process.env.NODE_ENV`.
|
|
38
|
+
* See {@link BitBitViewRendererProps.dev}. */
|
|
39
|
+
dev?: boolean;
|
|
31
40
|
/** Force a dark/light mode. Defaults to the system appearance via RN's
|
|
32
41
|
* `useColorScheme` (re-renders when the user toggles their OS theme). */
|
|
33
42
|
darkMode?: boolean;
|
|
43
|
+
/** When true (default), speculatively prefetches AGENT events with
|
|
44
|
+
* payload-less contracts so real clicks render with zero roundtrip. */
|
|
45
|
+
preloadNextUi?: boolean;
|
|
34
46
|
};
|
|
35
47
|
/**
|
|
36
48
|
* React Native (Expo) view: fetches a synthesis view by `keyName` and renders
|
|
37
|
-
* it in place.
|
|
38
|
-
*
|
|
39
|
-
* into a single batched request.
|
|
49
|
+
* it in place. AGENT events drive next UIs back through the agent (preloaded
|
|
50
|
+
* when possible). HOST events fire `onEvent`.
|
|
40
51
|
*/
|
|
41
|
-
export declare function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, darkMode, }: BitBitViewProps): import("react").FunctionComponentElement<BitBitViewRendererProps> | null;
|
|
52
|
+
export declare function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, dev, darkMode, preloadNextUi, }: BitBitViewProps): import("react").FunctionComponentElement<BitBitViewRendererProps> | null;
|
|
42
53
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-native-expo/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react-native-expo/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,sBAAsB,EAC5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EACV,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EAEtB,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAAE,KAAK,kBAAkB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EACL,kBAAkB,EAClB,KAAK,WAAW,EAChB,KAAK,cAAc,GACpB,MAAM,wCAAwC,CAAC;AAChD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,EACnB,UAAU,GACX,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,kBAAkB,GACnB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,sBAAsB,EACtB,eAAe,GAAG,mBAAmB,CACtC,GAAG;IACF;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,8EAA8E;IAC9E,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AA6DF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,aAAa,EACb,GAAG,EACH,OAAO,EACP,GAAG,IAAI,EACR,EAAE,uBAAuB,oEASzB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,wEAAwE;IACxE,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B;;8CAE0C;IAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;mDAC+C;IAC/C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;8EAC0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;4EACwE;IACxE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,MAAM,EACN,OAAO,EACP,aAAa,EACb,UAAU,EACV,OAAO,EACP,aAAa,EACb,GAAG,EACH,QAAQ,EACR,aAAa,GACd,EAAE,eAAe,4EAsBjB"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { createElement } from 'react';
|
|
2
|
-
import { useColorScheme } from 'react-native';
|
|
2
|
+
import { Text, useColorScheme } from 'react-native';
|
|
3
|
+
import { devLog, isDevEnvironment } from '../synthesisView/devLog.js';
|
|
3
4
|
import { SynthesisViewTree, } from '../synthesisView/engine.js';
|
|
4
|
-
import {
|
|
5
|
+
import { useEventDrivenView } from '../synthesisView/useEventDrivenView.js';
|
|
5
6
|
import { bitBitBuiltins } from './primitives.js';
|
|
6
7
|
export { BitBitProvider } from '../synthesisView/context.js';
|
|
7
8
|
export { createComponentMap, } from '../synthesisView/createComponentMap.js';
|
|
9
|
+
export { useEventDrivenView, } from '../synthesisView/useEventDrivenView.js';
|
|
8
10
|
export { bitBitBuiltins } from './primitives.js';
|
|
9
|
-
const
|
|
11
|
+
const renderUnknownWarning = (name) => createElement(Text, { style: { color: '#b00020', fontFamily: 'monospace', fontSize: 12 } }, `⚠ Unknown component: ${name}`);
|
|
12
|
+
const renderUnknownSilent = () => null;
|
|
10
13
|
const DEFAULT_FONT_SIZE = 16;
|
|
11
14
|
/** Extract the primary family name from a CSS-shape `fontFamily` value.
|
|
12
15
|
* Web takes the full fallback chain (`'"Inter-Regular", "Inter", ...'`);
|
|
@@ -40,6 +43,15 @@ function normalizeRNStyle(value) {
|
|
|
40
43
|
}
|
|
41
44
|
return changed ? out : value;
|
|
42
45
|
}
|
|
46
|
+
/** Wrap `onEvent` so each emission prints to the console with the dispatch
|
|
47
|
+
* routing inline. Routed through {@link devLog} so the message is auto-
|
|
48
|
+
* prefixed with `[BB]` and stripped to a no-op outside dev. */
|
|
49
|
+
function withDevEventLog(dev, onEvent) {
|
|
50
|
+
return (event) => {
|
|
51
|
+
devLog(dev, `event ${event.componentName}.${event.slot} → ${event.handleWith}`, event);
|
|
52
|
+
onEvent?.(event);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
43
55
|
/**
|
|
44
56
|
* React Native (Expo) renderer for a pre-fetched `uiData` array. BB built-in
|
|
45
57
|
* primitives are registered automatically; pass `components` to add or
|
|
@@ -47,32 +59,34 @@ function normalizeRNStyle(value) {
|
|
|
47
59
|
* on Expo packages (`expo-linear-gradient`, etc.). Use `<BitBitView>` if you
|
|
48
60
|
* want it to fetch for you.
|
|
49
61
|
*/
|
|
50
|
-
export function BitBitViewRenderer({ renderUnknown, ...rest }) {
|
|
62
|
+
export function BitBitViewRenderer({ renderUnknown, dev, onEvent, ...rest }) {
|
|
63
|
+
const isDev = dev ?? isDevEnvironment();
|
|
51
64
|
return createElement(SynthesisViewTree, {
|
|
52
65
|
...rest,
|
|
53
66
|
defaultComponents: bitBitBuiltins,
|
|
54
67
|
normalizeStyle: normalizeRNStyle,
|
|
55
|
-
renderUnknown: renderUnknown ??
|
|
68
|
+
renderUnknown: renderUnknown ?? (isDev ? renderUnknownWarning : renderUnknownSilent),
|
|
69
|
+
onEvent: isDev ? withDevEventLog(dev, onEvent) : onEvent,
|
|
56
70
|
});
|
|
57
71
|
}
|
|
58
72
|
/**
|
|
59
73
|
* React Native (Expo) view: fetches a synthesis view by `keyName` and renders
|
|
60
|
-
* it in place.
|
|
61
|
-
*
|
|
62
|
-
* into a single batched request.
|
|
74
|
+
* it in place. AGENT events drive next UIs back through the agent (preloaded
|
|
75
|
+
* when possible). HOST events fire `onEvent`.
|
|
63
76
|
*/
|
|
64
|
-
export function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, darkMode, }) {
|
|
77
|
+
export function BitBitView({ client, keyName, contentInputs, components, onEvent, renderUnknown, dev, darkMode, preloadNextUi, }) {
|
|
65
78
|
const systemScheme = useColorScheme();
|
|
66
79
|
const resolvedDark = darkMode ?? (systemScheme === 'dark' ? true : systemScheme === 'light' ? false : undefined);
|
|
67
80
|
const viewInputs = resolvedDark !== undefined ? { darkMode: resolvedDark } : undefined;
|
|
68
|
-
const { uiData, loading, error } =
|
|
81
|
+
const { uiData, loading, error, handleEvent } = useEventDrivenView(client, keyName, onEvent, contentInputs, viewInputs, { preloadNextUi });
|
|
69
82
|
if (loading || error || !uiData.length)
|
|
70
83
|
return null;
|
|
71
84
|
return createElement(BitBitViewRenderer, {
|
|
72
85
|
uiData,
|
|
73
86
|
components,
|
|
74
|
-
onEvent,
|
|
87
|
+
onEvent: handleEvent,
|
|
75
88
|
renderUnknown,
|
|
89
|
+
dev,
|
|
76
90
|
});
|
|
77
91
|
}
|
|
78
92
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react-native-expo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react-native-expo/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAEL,iBAAiB,GAElB,MAAM,4BAA4B,CAAC;AAQpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAA2B,cAAc,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EACL,kBAAkB,GAGnB,MAAM,wCAAwC,CAAC;AAahD,OAAO,EAGL,kBAAkB,GACnB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAgBjD,MAAM,oBAAoB,GAAkB,CAAC,IAAI,EAAE,EAAE,CACnD,aAAa,CACX,IAAI,EACJ,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,EACtE,wBAAwB,IAAI,EAAE,CAC/B,CAAC;AAEJ,MAAM,mBAAmB,GAAkB,GAAG,EAAE,CAAC,IAAI,CAAC;AAEtD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;0DAG0D;AAC1D,SAAS,gBAAgB,CAAC,KAAa;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,KAAK,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;;+BAI+B;AAC/B,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,MAAM,GAAG,GAAG,KAAgC,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,GAAG,GAA4B,EAAE,GAAG,GAAG,EAAE,CAAC;IAEhD,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAC7D,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC;QACrF,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC;QAC3C,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,UAAU,GAAG,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClD,OAAO,GAAG,IAAI,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;AAC/B,CAAC;AAED;;gEAEgE;AAChE,SAAS,eAAe,CACtB,GAAwB,EACxB,OAA0C;IAE1C,OAAO,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,CAAC,GAAG,EAAE,SAAS,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC;QACvF,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,aAAa,EACb,GAAG,EACH,OAAO,EACP,GAAG,IAAI,EACiB;IACxB,MAAM,KAAK,GAAG,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACxC,OAAO,aAAa,CAAC,iBAAiB,EAAE;QACtC,GAAG,IAAI;QACP,iBAAiB,EAAE,cAAc;QACjC,cAAc,EAAE,gBAAgB;QAChC,aAAa,EAAE,aAAa,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACpF,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO;KACzD,CAAC,CAAC;AACL,CAAC;AAwBD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,MAAM,EACN,OAAO,EACP,aAAa,EACb,UAAU,EACV,OAAO,EACP,aAAa,EACb,GAAG,EACH,QAAQ,EACR,aAAa,GACG;IAChB,MAAM,YAAY,GAAG,cAAc,EAAE,CAAC;IACtC,MAAM,YAAY,GAChB,QAAQ,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC9F,MAAM,UAAU,GACd,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,kBAAkB,CAChE,MAAM,EACN,OAAO,EACP,OAAO,EACP,aAAa,EACb,UAAU,EACV,EAAE,aAAa,EAAE,CAClB,CAAC;IACF,IAAI,OAAO,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACpD,OAAO,aAAa,CAAC,kBAAkB,EAAE;QACvC,MAAM;QACN,UAAU;QACV,OAAO,EAAE,WAAW;QACpB,aAAa;QACb,GAAG;KACJ,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** True when the bundle was built outside production. Read at runtime so
|
|
2
|
+
* bundlers can DCE the dev-log path during minification. Guarded for
|
|
3
|
+
* environments where `process` is undefined (some edge runtimes). */
|
|
4
|
+
export declare function isDevEnvironment(): boolean;
|
|
5
|
+
/** Single sink for every diagnostic log shipped from the SDK. Auto-prefixes
|
|
6
|
+
* with `[BB]` and silently no-ops outside dev so customer production builds
|
|
7
|
+
* don't carry SDK chatter. Pass `dev` explicitly to override env detection
|
|
8
|
+
* (e.g. CMS preview hosts that ship as prod bundles but want diagnostics). */
|
|
9
|
+
export declare function devLog(dev: boolean | undefined, ...args: unknown[]): void;
|
|
10
|
+
//# sourceMappingURL=devLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devLog.d.ts","sourceRoot":"","sources":["../../src/synthesisView/devLog.ts"],"names":[],"mappings":"AAAA;;sEAEsE;AACtE,wBAAgB,gBAAgB,IAAI,OAAO,CAM1C;AAED;;;+EAG+E;AAC/E,wBAAgB,MAAM,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAKzE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** True when the bundle was built outside production. Read at runtime so
|
|
2
|
+
* bundlers can DCE the dev-log path during minification. Guarded for
|
|
3
|
+
* environments where `process` is undefined (some edge runtimes). */
|
|
4
|
+
export function isDevEnvironment() {
|
|
5
|
+
try {
|
|
6
|
+
return typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/** Single sink for every diagnostic log shipped from the SDK. Auto-prefixes
|
|
13
|
+
* with `[BB]` and silently no-ops outside dev so customer production builds
|
|
14
|
+
* don't carry SDK chatter. Pass `dev` explicitly to override env detection
|
|
15
|
+
* (e.g. CMS preview hosts that ship as prod bundles but want diagnostics). */
|
|
16
|
+
export function devLog(dev, ...args) {
|
|
17
|
+
const isDev = dev ?? isDevEnvironment();
|
|
18
|
+
if (!isDev)
|
|
19
|
+
return;
|
|
20
|
+
// eslint-disable-next-line no-console
|
|
21
|
+
console.log('[BB]', ...args);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=devLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devLog.js","sourceRoot":"","sources":["../../src/synthesisView/devLog.ts"],"names":[],"mappings":"AAAA;;sEAEsE;AACtE,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC;QACH,OAAO,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,QAAQ,KAAK,YAAY,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;+EAG+E;AAC/E,MAAM,UAAU,MAAM,CAAC,GAAwB,EAAE,GAAG,IAAe;IACjE,MAAM,KAAK,GAAG,GAAG,IAAI,gBAAgB,EAAE,CAAC;IACxC,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -81,7 +81,14 @@ function renderPrimitiveNode(node, context) {
|
|
|
81
81
|
if (componentPayload && typeof componentPayload === 'object') {
|
|
82
82
|
Object.assign(payload, componentPayload);
|
|
83
83
|
}
|
|
84
|
-
emit({
|
|
84
|
+
emit({
|
|
85
|
+
name: event.name,
|
|
86
|
+
payload,
|
|
87
|
+
slot,
|
|
88
|
+
nodeId: node.id,
|
|
89
|
+
componentName: node.component,
|
|
90
|
+
handleWith: event.handleWith ?? 'AGENT',
|
|
91
|
+
});
|
|
85
92
|
};
|
|
86
93
|
}
|
|
87
94
|
}
|
|
@@ -101,6 +108,25 @@ function renderPrimitiveNode(node, context) {
|
|
|
101
108
|
function renderKeyNameNode(node, context) {
|
|
102
109
|
const Component = context.components[node.component];
|
|
103
110
|
const props = { ...(node.props ?? {}) };
|
|
111
|
+
if (node.events && context.onEvent) {
|
|
112
|
+
const emit = context.onEvent;
|
|
113
|
+
for (const [slot, event] of Object.entries(node.events)) {
|
|
114
|
+
props[slot] = (componentPayload) => {
|
|
115
|
+
const payload = { ...(event.payload ?? {}) };
|
|
116
|
+
if (componentPayload && typeof componentPayload === 'object') {
|
|
117
|
+
Object.assign(payload, componentPayload);
|
|
118
|
+
}
|
|
119
|
+
emit({
|
|
120
|
+
name: event.name,
|
|
121
|
+
payload,
|
|
122
|
+
slot,
|
|
123
|
+
nodeId: node.id,
|
|
124
|
+
componentName: node.component,
|
|
125
|
+
handleWith: event.handleWith ?? 'AGENT',
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
104
130
|
const childIds = nodeChildIds(node);
|
|
105
131
|
if (childIds) {
|
|
106
132
|
props.children = childIds.map((childId) => renderNode(childId, context));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/synthesisView/engine.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/synthesisView/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,10 +19,20 @@ export type FlatUiPrimitiveNode = {
|
|
|
19
19
|
/** Single nested-node id shorthand. */
|
|
20
20
|
child?: string;
|
|
21
21
|
/** Host-facing event bindings. Component-emitted payloads (e.g.
|
|
22
|
-
* `TextField` `{value}`) merge over the static payload at fire time.
|
|
22
|
+
* `TextField` `{value}`) merge over the static payload at fire time.
|
|
23
|
+
* `handleWith` is lifted from the component contract by the flattener so
|
|
24
|
+
* the SDK can route the event without re-fetching the catalog:
|
|
25
|
+
* - `HOST` — fires `onEvent` to the customer.
|
|
26
|
+
* - `AGENT` (default) — `<BitBitView>` round-trips to the synthesis
|
|
27
|
+
* endpoint with the event as continuation context; the agent emits
|
|
28
|
+
* the next UI. The customer's `onEvent` still fires for observability.
|
|
29
|
+
* - `payloadSchema` (when present) opts the event out of speculative
|
|
30
|
+
* preload — the payload requires runtime input. */
|
|
23
31
|
events?: Record<string, {
|
|
24
32
|
name: string;
|
|
25
33
|
payload?: Record<string, unknown>;
|
|
34
|
+
handleWith?: ViewEventHandleWith;
|
|
35
|
+
payloadSchema?: unknown;
|
|
26
36
|
}>;
|
|
27
37
|
/** Other fields (`text`, `src`, `title`, …) are static props on the node. */
|
|
28
38
|
[prop: string]: unknown;
|
|
@@ -36,12 +46,46 @@ export type FlatUiKeyNameNode = {
|
|
|
36
46
|
/** Projected children (ids in the same array). */
|
|
37
47
|
children?: string[];
|
|
38
48
|
child?: string;
|
|
49
|
+
/** Host-facing event bindings — same shape and semantics as on
|
|
50
|
+
* {@link FlatUiPrimitiveNode}. The SDK wires each slot into a prop
|
|
51
|
+
* callback on the host component so customer code can fire BB events
|
|
52
|
+
* (`AGENT` continuations, `HOST` dispatches) without grabbing the
|
|
53
|
+
* provider context manually. */
|
|
54
|
+
events?: Record<string, {
|
|
55
|
+
name: string;
|
|
56
|
+
payload?: Record<string, unknown>;
|
|
57
|
+
handleWith?: ViewEventHandleWith;
|
|
58
|
+
payloadSchema?: unknown;
|
|
59
|
+
}>;
|
|
39
60
|
};
|
|
40
61
|
export type FlatUiNode = FlatUiPrimitiveNode | FlatUiKeyNameNode;
|
|
62
|
+
export type ViewEventHandleWith = 'AGENT' | 'HOST';
|
|
41
63
|
export type SynthesisViewEvent = {
|
|
64
|
+
/** Host-facing event name — what the view-author bound the slot to. */
|
|
42
65
|
name: string;
|
|
66
|
+
/** Resolved payload — static `payload` from the binding merged with any
|
|
67
|
+
* runtime payload the primitive emitted (e.g. `TextField` `{value}`). */
|
|
43
68
|
payload: Record<string, unknown>;
|
|
69
|
+
/** Slot that fired (e.g. `onPress`). Useful when several slots are bound
|
|
70
|
+
* to the same host event name. */
|
|
71
|
+
slot: string;
|
|
72
|
+
/** The flat-uid of the node that fired. SDK-internal mostly; useful for
|
|
73
|
+
* the CMS preview to disambiguate multiple instances. */
|
|
44
74
|
nodeId: string;
|
|
75
|
+
/** Catalog name of the component the event was fired from. */
|
|
76
|
+
componentName: string;
|
|
77
|
+
/** Routing the component contract declared. `null` defaults to `AGENT`. */
|
|
78
|
+
handleWith: ViewEventHandleWith;
|
|
79
|
+
};
|
|
80
|
+
/** Sent to the synthesis endpoint as `viewInputs.event` when an `AGENT` event
|
|
81
|
+
* fires. The agent gets the prior UI + event as continuation context and
|
|
82
|
+
* emits the next UI in response. */
|
|
83
|
+
export type SynthesisViewEventInput = {
|
|
84
|
+
name: string;
|
|
85
|
+
componentName: string;
|
|
86
|
+
payload?: Record<string, unknown>;
|
|
87
|
+
sourceNodeId?: string;
|
|
88
|
+
priorUiData: FlatUiNode[];
|
|
45
89
|
};
|
|
46
90
|
/** Maps component names → React implementations. Used both for BB
|
|
47
91
|
* primitives and for the host-registered `KEY_NAME` components. */
|
|
@@ -53,6 +97,11 @@ export type ContentInput = {
|
|
|
53
97
|
export type ViewInputs = {
|
|
54
98
|
/** Provide the dark mode setting of the current UI to the agent. */
|
|
55
99
|
darkMode?: boolean;
|
|
100
|
+
/** Event continuation. Set by the SDK on AGENT-handled events (and on
|
|
101
|
+
* speculative preload calls); the agent re-renders given the prior UI
|
|
102
|
+
* plus this event. Customers don't pass this — `<BitBitView>` manages it
|
|
103
|
+
* internally. */
|
|
104
|
+
event?: SynthesisViewEventInput;
|
|
56
105
|
};
|
|
57
106
|
/**
|
|
58
107
|
* Minimal structural shape `<BitBitView>` needs to fetch a view. A
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/synthesisView/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/synthesisView/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ContentInput, FlatUiNode, SynthesisViewEvent, SynthesizeViewFetcher, ViewInputs } from './types.js';
|
|
2
|
+
export type UseEventDrivenViewOptions = {
|
|
3
|
+
/** When true (default), speculatively prefetches the agent's next-UI for
|
|
4
|
+
* every AGENT event whose payload is fully derivable from the rendered
|
|
5
|
+
* tree (i.e. the contract declared no `payloadSchema`). On the real
|
|
6
|
+
* click, the SDK swaps in the prefetched response without a server hop. */
|
|
7
|
+
preloadNextUi?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type UseEventDrivenViewResult = {
|
|
10
|
+
uiData: FlatUiNode[];
|
|
11
|
+
loading: boolean;
|
|
12
|
+
error: string | null;
|
|
13
|
+
/** Wire this to `<BitBitViewRenderer onEvent={...}>`. Routes the event
|
|
14
|
+
* based on its `handleWith`:
|
|
15
|
+
* - `HOST` — fires the supplied `onHostEvent` callback.
|
|
16
|
+
* - `AGENT` — re-fetches with the event as continuation context (cache
|
|
17
|
+
* hit if a speculative preload landed first), swaps `uiData` in
|
|
18
|
+
* place. The customer's `onHostEvent` is NOT fired for AGENT events. */
|
|
19
|
+
handleEvent: (event: SynthesisViewEvent) => void;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Live-view hook on top of `useSynthesisView`. Owns:
|
|
23
|
+
* - the live `uiData` (swaps in place on AGENT events),
|
|
24
|
+
* - a per-tree preload cache so deterministic event sequences are 0ms,
|
|
25
|
+
* - an event dispatcher the renderer calls back into.
|
|
26
|
+
*
|
|
27
|
+
* Resets state whenever the underlying view (keyName / contentInputs)
|
|
28
|
+
* changes — speculative entries from a stale tree aren't relevant to a
|
|
29
|
+
* different view.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useEventDrivenView(client: SynthesizeViewFetcher, keyName: string, onHostEvent: ((event: SynthesisViewEvent) => void) | undefined, contentInputs?: ContentInput[], baseViewInputs?: ViewInputs, options?: UseEventDrivenViewOptions): UseEventDrivenViewResult;
|
|
32
|
+
//# sourceMappingURL=useEventDrivenView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEventDrivenView.d.ts","sourceRoot":"","sources":["../../src/synthesisView/useEventDrivenView.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EAEV,kBAAkB,EAElB,qBAAqB,EACrB,UAAU,EACX,MAAM,YAAY,CAAC;AAGpB,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;gFAG4E;IAC5E,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB;;;;;gFAK4E;IAC5E,WAAW,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAClD,CAAC;AA4DF;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,qBAAqB,EAC7B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,CAAC,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC,GAAG,SAAS,EAC9D,aAAa,CAAC,EAAE,YAAY,EAAE,EAC9B,cAAc,CAAC,EAAE,UAAU,EAC3B,OAAO,CAAC,EAAE,yBAAyB,GAClC,wBAAwB,CAuG1B"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useSynthesisView } from './useSynthesisView.js';
|
|
3
|
+
function isPrimitive(node) {
|
|
4
|
+
return node.kind === 'PRIMITIVE';
|
|
5
|
+
}
|
|
6
|
+
/** Stable string key for an event's cache entry. Speculation + real fire
|
|
7
|
+
* produce the same key when the runtime payload matches the declared one. */
|
|
8
|
+
function buildEventKey(componentName, eventName, sourceNodeId, payload) {
|
|
9
|
+
// Sort keys so payload order doesn't matter.
|
|
10
|
+
const payloadStr = payload
|
|
11
|
+
? JSON.stringify(Object.keys(payload)
|
|
12
|
+
.sort()
|
|
13
|
+
.reduce((acc, k) => {
|
|
14
|
+
acc[k] = payload[k];
|
|
15
|
+
return acc;
|
|
16
|
+
}, {}))
|
|
17
|
+
: '';
|
|
18
|
+
return `${componentName}:${eventName}:${sourceNodeId}:${payloadStr}`;
|
|
19
|
+
}
|
|
20
|
+
/** Walks the rendered tree and pulls out AGENT events with empty
|
|
21
|
+
* `payloadSchema` — those have payloads that don't depend on user input,
|
|
22
|
+
* so the SDK can fabricate the request and prefetch the agent's response. */
|
|
23
|
+
function findPreloadCandidates(uiData) {
|
|
24
|
+
const out = [];
|
|
25
|
+
for (const node of uiData) {
|
|
26
|
+
if (!isPrimitive(node) || !node.events)
|
|
27
|
+
continue;
|
|
28
|
+
for (const [, event] of Object.entries(node.events)) {
|
|
29
|
+
const handleWith = event.handleWith ?? 'AGENT';
|
|
30
|
+
if (handleWith !== 'AGENT')
|
|
31
|
+
continue;
|
|
32
|
+
// Skip events that need runtime payload — we can't fabricate the value.
|
|
33
|
+
if (event.payloadSchema)
|
|
34
|
+
continue;
|
|
35
|
+
out.push({
|
|
36
|
+
key: buildEventKey(node.component, event.name, node.id, event.payload),
|
|
37
|
+
event: {
|
|
38
|
+
name: event.name,
|
|
39
|
+
componentName: node.component,
|
|
40
|
+
payload: event.payload,
|
|
41
|
+
sourceNodeId: node.id,
|
|
42
|
+
priorUiData: uiData,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Live-view hook on top of `useSynthesisView`. Owns:
|
|
51
|
+
* - the live `uiData` (swaps in place on AGENT events),
|
|
52
|
+
* - a per-tree preload cache so deterministic event sequences are 0ms,
|
|
53
|
+
* - an event dispatcher the renderer calls back into.
|
|
54
|
+
*
|
|
55
|
+
* Resets state whenever the underlying view (keyName / contentInputs)
|
|
56
|
+
* changes — speculative entries from a stale tree aren't relevant to a
|
|
57
|
+
* different view.
|
|
58
|
+
*/
|
|
59
|
+
export function useEventDrivenView(client, keyName, onHostEvent, contentInputs, baseViewInputs, options) {
|
|
60
|
+
const fetched = useSynthesisView(client, keyName, contentInputs, baseViewInputs);
|
|
61
|
+
// Live tree: starts as the fetched one, replaced on AGENT events.
|
|
62
|
+
const [liveUiData, setLiveUiData] = useState(fetched.uiData);
|
|
63
|
+
// Preload cache scoped to the current view; reset on every base refetch.
|
|
64
|
+
const preloadCacheRef = useRef(new Map());
|
|
65
|
+
const inFlightRef = useRef(new Map());
|
|
66
|
+
// Keep `onHostEvent` reachable inside the stable `handleEvent` callback
|
|
67
|
+
// without making the callback identity churn on every render.
|
|
68
|
+
const onHostEventRef = useRef(onHostEvent);
|
|
69
|
+
onHostEventRef.current = onHostEvent;
|
|
70
|
+
const baseViewInputsRef = useRef(baseViewInputs);
|
|
71
|
+
baseViewInputsRef.current = baseViewInputs;
|
|
72
|
+
// When the base fetch produces new uiData (initial load, or a view change),
|
|
73
|
+
// adopt it and drop any stale speculations.
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
setLiveUiData(fetched.uiData);
|
|
76
|
+
preloadCacheRef.current = new Map();
|
|
77
|
+
inFlightRef.current = new Map();
|
|
78
|
+
}, [fetched.uiData]);
|
|
79
|
+
const preload = options?.preloadNextUi ?? true;
|
|
80
|
+
/** Fire one speculative event lookup and stash the result. Idempotent on
|
|
81
|
+
* the cache key — concurrent triggers share the in-flight promise. */
|
|
82
|
+
const speculate = useCallback(async (candidate) => {
|
|
83
|
+
if (preloadCacheRef.current.has(candidate.key)) {
|
|
84
|
+
return preloadCacheRef.current.get(candidate.key) ?? [];
|
|
85
|
+
}
|
|
86
|
+
const existing = inFlightRef.current.get(candidate.key);
|
|
87
|
+
if (existing)
|
|
88
|
+
return existing;
|
|
89
|
+
const promise = client.user
|
|
90
|
+
.synthesizeViewItem({
|
|
91
|
+
keyName,
|
|
92
|
+
contentInputs,
|
|
93
|
+
viewInputs: { ...baseViewInputsRef.current, event: candidate.event },
|
|
94
|
+
})
|
|
95
|
+
.then((res) => {
|
|
96
|
+
const next = Array.isArray(res.uiData) ? res.uiData : [];
|
|
97
|
+
preloadCacheRef.current.set(candidate.key, next);
|
|
98
|
+
inFlightRef.current.delete(candidate.key);
|
|
99
|
+
return next;
|
|
100
|
+
})
|
|
101
|
+
.catch(() => {
|
|
102
|
+
inFlightRef.current.delete(candidate.key);
|
|
103
|
+
return [];
|
|
104
|
+
});
|
|
105
|
+
inFlightRef.current.set(candidate.key, promise);
|
|
106
|
+
return promise;
|
|
107
|
+
},
|
|
108
|
+
// contentInputs object identity changes are tolerated by the
|
|
109
|
+
// fetch path; we only need a fresh `keyName` to invalidate.
|
|
110
|
+
[client, keyName, contentInputs]);
|
|
111
|
+
// Preload pump: whenever the live tree changes, look up speculatable
|
|
112
|
+
// events and prefetch them in the background. Cap so a giant gallery
|
|
113
|
+
// doesn't blow up the LLM budget.
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
if (!preload)
|
|
116
|
+
return;
|
|
117
|
+
const candidates = findPreloadCandidates(liveUiData).slice(0, MAX_SPECULATIONS);
|
|
118
|
+
for (const candidate of candidates)
|
|
119
|
+
void speculate(candidate);
|
|
120
|
+
}, [liveUiData, preload, speculate]);
|
|
121
|
+
const handleEvent = useCallback((event) => {
|
|
122
|
+
if (event.handleWith === 'HOST') {
|
|
123
|
+
onHostEventRef.current?.(event);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const key = buildEventKey(event.componentName, event.name, event.nodeId, event.payload);
|
|
127
|
+
const cached = preloadCacheRef.current.get(key);
|
|
128
|
+
if (cached) {
|
|
129
|
+
setLiveUiData(cached);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// Cache miss → live call. The result joins the cache so a repeat
|
|
133
|
+
// event-sequence step is 0ms.
|
|
134
|
+
const candidate = {
|
|
135
|
+
key,
|
|
136
|
+
event: {
|
|
137
|
+
name: event.name,
|
|
138
|
+
componentName: event.componentName,
|
|
139
|
+
payload: event.payload,
|
|
140
|
+
sourceNodeId: event.nodeId,
|
|
141
|
+
priorUiData: liveUiData,
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
void speculate(candidate).then((next) => {
|
|
145
|
+
if (next.length > 0)
|
|
146
|
+
setLiveUiData(next);
|
|
147
|
+
});
|
|
148
|
+
}, [liveUiData, speculate]);
|
|
149
|
+
return {
|
|
150
|
+
uiData: liveUiData,
|
|
151
|
+
loading: fetched.loading,
|
|
152
|
+
error: fetched.error,
|
|
153
|
+
handleEvent,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const MAX_SPECULATIONS = 8;
|
|
157
|
+
//# sourceMappingURL=useEventDrivenView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEventDrivenView.js","sourceRoot":"","sources":["../../src/synthesisView/useEventDrivenView.ts"],"names":[],"mappings":"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"}
|