@a2ui-sdk/react 0.3.0 → 0.4.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @a2ui-sdk/react
2
2
 
3
- React implementation for rendering A2UI protocol. This package provides React components and hooks for integrating A2UI surfaces into your application.
3
+ React implementation for rendering A2UI protocol. This package provides React components and hooks for integrating A2UI renderer into your application.
4
4
 
5
5
  ## Installation
6
6
 
@@ -220,6 +220,7 @@ import {
220
220
  useSurfaceContext,
221
221
  useScope,
222
222
  useScopeBasePath,
223
+ useA2UIMessageHandler,
223
224
 
224
225
  // Context Providers & Hooks
225
226
  ActionProvider,
@@ -245,6 +246,7 @@ import {
245
246
  type ValidationResult,
246
247
  type ScopeValue,
247
248
  type DataModel,
249
+ type A2UIMessageHandler,
248
250
  } from '@a2ui-sdk/react/0.9'
249
251
  ```
250
252
 
@@ -268,6 +270,7 @@ import {
268
270
  useDataModelContext,
269
271
  useScope,
270
272
  useScopeBasePath,
273
+ useA2UIMessageHandler,
271
274
 
272
275
  // Context Providers & Hooks
273
276
  ActionProvider,
@@ -282,6 +285,7 @@ import {
282
285
  type Action,
283
286
  type ValueSource,
284
287
  type ScopeValue,
288
+ type A2UIMessageHandler,
285
289
  } from '@a2ui-sdk/react/0.8'
286
290
  ```
287
291
 
@@ -294,8 +298,92 @@ import { v0_8, v0_9 } from '@a2ui-sdk/react'
294
298
  const { A2UIProvider, A2UIRenderer } = v0_9
295
299
  ```
296
300
 
301
+ ## Incremental Message Handling
302
+
303
+ **New in v0.8 & v0.9**: For applications that receive messages incrementally (e.g., via WebSocket or SSE), you can use the `useA2UIMessageHandler` hook to push new messages without clearing state. This preserves user edits.
304
+
305
+ ### Problem
306
+
307
+ When using the `messages` prop on `A2UIProvider`, changing the messages array causes the provider to clear all state and reprocess from scratch. This loses user edits:
308
+
309
+ ```tsx
310
+ // ❌ This loses user edits when new messages arrive
311
+ function App() {
312
+ const [messages, setMessages] = useState<A2UIMessage[]>([])
313
+
314
+ useEffect(() => {
315
+ const ws = new WebSocket('ws://example.com')
316
+ ws.onmessage = (event) => {
317
+ const newMessage = JSON.parse(event.data)
318
+ setMessages((prev) => [...prev, newMessage]) // Triggers full clear & reprocess!
319
+ }
320
+ }, [])
321
+
322
+ return (
323
+ <A2UIProvider messages={messages}>
324
+ <A2UIRenderer onAction={handleAction} />
325
+ </A2UIProvider>
326
+ )
327
+ }
328
+ ```
329
+
330
+ ### Solution
331
+
332
+ Use `useA2UIMessageHandler` hook to process messages incrementally:
333
+
334
+ ```tsx
335
+ import {
336
+ A2UIProvider,
337
+ A2UIRenderer,
338
+ useA2UIMessageHandler,
339
+ type A2UIMessage,
340
+ type A2UIAction,
341
+ } from '@a2ui-sdk/react/0.8' // or '@a2ui-sdk/react/0.9'
342
+
343
+ function App() {
344
+ const handleAction = (action: A2UIAction) => {
345
+ console.log('Action:', action)
346
+ }
347
+
348
+ return (
349
+ <A2UIProvider>
350
+ <MessageHandler>
351
+ <A2UIRenderer onAction={handleAction} />
352
+ </MessageHandler>
353
+ </A2UIProvider>
354
+ )
355
+ }
356
+
357
+ function MessageHandler({ children }: { children: React.ReactNode }) {
358
+ const { processMessage } = useA2UIMessageHandler()
359
+
360
+ useEffect(() => {
361
+ // Listen for incremental updates
362
+ const ws = new WebSocket('ws://example.com')
363
+ ws.onmessage = (event) => {
364
+ const newMessage = JSON.parse(event.data)
365
+ processMessage(newMessage) // Incremental - preserves user edits!
366
+ }
367
+
368
+ return () => ws.close()
369
+ }, [processMessage])
370
+
371
+ return <>{children}</>
372
+ }
373
+ ```
374
+
375
+ The `useA2UIMessageHandler` hook returns:
376
+
377
+ - **`processMessage(message: A2UIMessage)`**: Process a single message incrementally
378
+ - **`processMessages(messages: A2UIMessage[])`**: Process multiple messages in order
379
+ - **`clear()`**: Clear all surfaces and state (rarely needed)
380
+
297
381
  ## Hooks
298
382
 
383
+ ### useA2UIMessageHandler
384
+
385
+ See [Incremental Message Handling](#incremental-message-handling) above for usage details.
386
+
299
387
  ### useDataBinding
300
388
 
301
389
  Resolves a dynamic value from the data model:
@@ -1,27 +1,28 @@
1
- import { jsxs as l, jsx as t } from "react/jsx-runtime";
2
- import { memo as p, useCallback as C } from "react";
3
- import { useDataBinding as d, useFormBinding as x } from "../../hooks/useDataBinding.js";
4
- import { Checkbox as k } from "../../../components/ui/checkbox.js";
5
- import { Label as f } from "../../../components/ui/label.js";
6
- import { cn as b } from "../../../lib/utils.js";
7
- const g = p(function({
1
+ import { jsxs as p, jsx as m } from "react/jsx-runtime";
2
+ import { memo as x, useCallback as C } from "react";
3
+ import { useDataBinding as k, useFormBinding as d } from "../../hooks/useDataBinding.js";
4
+ import { useScopeBasePath as f } from "../../contexts/ScopeContext.js";
5
+ import { Checkbox as b } from "../../../components/ui/checkbox.js";
6
+ import { Label as g } from "../../../components/ui/label.js";
7
+ import { cn as u } from "../../../lib/utils.js";
8
+ const B = x(function({
8
9
  surfaceId: e,
9
- componentId: m,
10
- label: r,
11
- value: s
10
+ componentId: o,
11
+ label: s,
12
+ value: a
12
13
  }) {
13
- const o = d(e, r, ""), [i, n] = x(e, s, !1), a = C(
14
- (h) => {
15
- n(h);
14
+ const c = k(e, s, ""), [i, t] = d(e, a, !1), r = f(), h = C(
15
+ (l) => {
16
+ t(l);
16
17
  },
17
- [n]
18
- ), c = `checkbox-${m}`;
19
- return /* @__PURE__ */ l("div", { className: b("flex items-center gap-3"), children: [
20
- /* @__PURE__ */ t(k, { id: c, checked: i, onCheckedChange: a }),
21
- o && /* @__PURE__ */ t(f, { htmlFor: c, className: "cursor-pointer", children: o })
18
+ [t]
19
+ ), n = r ? `checkbox-${o}-${r.replace(/\//g, "-")}` : `checkbox-${o}`;
20
+ return /* @__PURE__ */ p("div", { className: u("flex items-center gap-3"), children: [
21
+ /* @__PURE__ */ m(b, { id: n, checked: i, onCheckedChange: h }),
22
+ c && /* @__PURE__ */ m(g, { htmlFor: n, className: "cursor-pointer", children: c })
22
23
  ] });
23
24
  });
24
- g.displayName = "A2UI.CheckBox";
25
+ B.displayName = "A2UI.CheckBox";
25
26
  export {
26
- g as CheckBoxComponent
27
+ B as CheckBoxComponent
27
28
  };
@@ -5,8 +5,12 @@ import { Catalog } from '../standard-catalog';
5
5
  * Props for A2UIProvider.
6
6
  */
7
7
  export interface A2UIProviderProps {
8
- /** Array of A2UI messages to render */
9
- messages: A2UIMessage[];
8
+ /**
9
+ * Array of A2UI messages to render.
10
+ * When this prop changes, all state is cleared and messages are reprocessed.
11
+ * For incremental updates, use useA2UIMessageHandler hook inside the provider.
12
+ */
13
+ messages?: A2UIMessage[];
10
14
  /**
11
15
  * Catalog containing components and functions.
12
16
  * Use `standardCatalog` from '@a2ui-sdk/react/0.8/standard-catalog' as base.
@@ -1,27 +1,26 @@
1
- import { jsx as o, Fragment as i } from "react/jsx-runtime";
2
- import { useEffect as s } from "react";
3
- import { SurfaceProvider as a } from "./SurfaceContext.js";
4
- import { DataModelProvider as f } from "./DataModelContext.js";
5
- import { ComponentsMapProvider as c } from "./ComponentsMapContext.js";
6
- import { useA2UIMessageHandler as m } from "../hooks/useA2UIMessageHandler.js";
7
- import { standardCatalog as p } from "../standard-catalog/index.js";
8
- function d({
1
+ import { jsx as o, Fragment as n } from "react/jsx-runtime";
2
+ import { useEffect as f } from "react";
3
+ import { SurfaceProvider as c } from "./SurfaceContext.js";
4
+ import { DataModelProvider as a } from "./DataModelContext.js";
5
+ import { ComponentsMapProvider as m } from "./ComponentsMapContext.js";
6
+ import { useA2UIMessageHandler as p } from "../hooks/useA2UIMessageHandler.js";
7
+ import { standardCatalog as d } from "../standard-catalog/index.js";
8
+ function l({
9
9
  messages: r,
10
- children: n
10
+ children: t
11
11
  }) {
12
- const { processMessages: e, clear: t } = m();
13
- return s(() => {
14
- t(), r && r.length > 0 && e(r);
15
- }, [r, e, t]), /* @__PURE__ */ o(i, { children: n });
12
+ const { processMessages: e, clear: i } = p();
13
+ return f(() => {
14
+ r !== void 0 && (i(), r && r.length > 0 && e(r));
15
+ }, [r, i, e]), /* @__PURE__ */ o(n, { children: t });
16
16
  }
17
- function A({
17
+ function C({
18
18
  messages: r,
19
- catalog: n,
19
+ catalog: t,
20
20
  children: e
21
21
  }) {
22
- const t = r ?? [];
23
- return /* @__PURE__ */ o(a, { children: /* @__PURE__ */ o(f, { children: /* @__PURE__ */ o(c, { components: (n ?? p).components, children: /* @__PURE__ */ o(d, { messages: t, children: e }) }) }) });
22
+ return /* @__PURE__ */ o(c, { children: /* @__PURE__ */ o(a, { children: /* @__PURE__ */ o(m, { components: (t ?? d).components, children: /* @__PURE__ */ o(l, { messages: r, children: e }) }) }) });
24
23
  }
25
24
  export {
26
- A as A2UIProvider
25
+ C as A2UIProvider
27
26
  };
@@ -21,9 +21,6 @@ export interface A2UIMessageHandler {
21
21
  * const { processMessage, processMessages, clear } = useA2UIMessageHandler();
22
22
  *
23
23
  * useEffect(() => {
24
- * // Process initial messages
25
- * processMessages(initialMessages);
26
- *
27
24
  * // Listen for SSE updates
28
25
  * const handler = (event) => {
29
26
  * processMessage(event.detail.message);
@@ -45,3 +45,5 @@ export { useDataBinding, useFormBinding } from './hooks/useDataBinding';
45
45
  export { useSurfaceContext } from './contexts/SurfaceContext';
46
46
  export { useDataModelContext } from './contexts/DataModelContext';
47
47
  export { ActionProvider, useActionContext } from './contexts/ActionContext';
48
+ export { useA2UIMessageHandler } from './hooks/useA2UIMessageHandler';
49
+ export type { A2UIMessageHandler } from './hooks/useA2UIMessageHandler';
package/dist/0.8/index.js CHANGED
@@ -1,22 +1,24 @@
1
1
  import { A2UIProvider as r } from "./contexts/A2UIProvider.js";
2
2
  import { A2UIRenderer as n } from "./A2UIRenderer.js";
3
- import { ComponentRenderer as m } from "./components/ComponentRenderer.js";
4
- import { standardCatalog as a } from "./standard-catalog/index.js";
5
- import { useDispatchAction as i } from "./hooks/useDispatchAction.js";
6
- import { useDataBinding as s, useFormBinding as u } from "./hooks/useDataBinding.js";
7
- import { useSurfaceContext as A } from "./contexts/SurfaceContext.js";
3
+ import { ComponentRenderer as a } from "./components/ComponentRenderer.js";
4
+ import { standardCatalog as p } from "./standard-catalog/index.js";
5
+ import { useDispatchAction as s } from "./hooks/useDispatchAction.js";
6
+ import { useDataBinding as i, useFormBinding as u } from "./hooks/useDataBinding.js";
7
+ import { useSurfaceContext as c } from "./contexts/SurfaceContext.js";
8
8
  import { useDataModelContext as g } from "./contexts/DataModelContext.js";
9
- import { ActionProvider as l, useActionContext as v } from "./contexts/ActionContext.js";
9
+ import { ActionProvider as D, useActionContext as I } from "./contexts/ActionContext.js";
10
+ import { useA2UIMessageHandler as v } from "./hooks/useA2UIMessageHandler.js";
10
11
  export {
11
12
  r as A2UIProvider,
12
13
  n as A2UIRenderer,
13
- l as ActionProvider,
14
- m as ComponentRenderer,
15
- a as standardCatalog,
16
- v as useActionContext,
17
- s as useDataBinding,
14
+ D as ActionProvider,
15
+ a as ComponentRenderer,
16
+ p as standardCatalog,
17
+ v as useA2UIMessageHandler,
18
+ I as useActionContext,
19
+ i as useDataBinding,
18
20
  g as useDataModelContext,
19
- i as useDispatchAction,
21
+ s as useDispatchAction,
20
22
  u as useFormBinding,
21
- A as useSurfaceContext
23
+ c as useSurfaceContext
22
24
  };
@@ -1,45 +1,46 @@
1
1
  import { jsxs as m, jsx as e } from "react/jsx-runtime";
2
- import { memo as v, useCallback as g } from "react";
3
- import { useStringBinding as u, useFormBinding as b } from "../../hooks/useDataBinding.js";
4
- import { useValidation as B } from "../../hooks/useValidation.js";
5
- import { Checkbox as N } from "../../../components/ui/checkbox.js";
6
- import { Label as j } from "../../../components/ui/label.js";
7
- import { cn as y } from "../../../lib/utils.js";
8
- const F = v(function({
2
+ import { memo as u, useCallback as v } from "react";
3
+ import { useStringBinding as b, useFormBinding as B } from "../../hooks/useDataBinding.js";
4
+ import { useValidation as N } from "../../hooks/useValidation.js";
5
+ import { useScopeBasePath as $ } from "../../contexts/ScopeContext.js";
6
+ import { Checkbox as j } from "../../../components/ui/checkbox.js";
7
+ import { Label as y } from "../../../components/ui/label.js";
8
+ import { cn as F } from "../../../lib/utils.js";
9
+ const P = u(function({
9
10
  surfaceId: o,
10
- componentId: s,
11
- label: a,
11
+ componentId: r,
12
+ label: h,
12
13
  value: d,
13
- checks: h,
14
- weight: t
14
+ checks: p,
15
+ weight: c
15
16
  }) {
16
- const r = u(o, a, ""), [p, i] = b(
17
+ const i = b(o, h, ""), [x, n] = B(
17
18
  o,
18
19
  d,
19
20
  !1
20
- ), { valid: x, errors: c } = B(o, h), f = g(
21
- (n) => {
22
- i(n);
21
+ ), { valid: f, errors: s } = N(o, p), a = $(), C = v(
22
+ (t) => {
23
+ n(t);
23
24
  },
24
- [i]
25
- ), l = `checkbox-${s}`, C = t ? { flexGrow: t } : void 0;
26
- return /* @__PURE__ */ m("div", { className: y("flex flex-col gap-1"), style: C, children: [
25
+ [n]
26
+ ), l = a ? `checkbox-${r}-${a.replace(/\//g, "-")}` : `checkbox-${r}`, k = c ? { flexGrow: c } : void 0;
27
+ return /* @__PURE__ */ m("div", { className: F("flex flex-col gap-1"), style: k, children: [
27
28
  /* @__PURE__ */ m("div", { className: "flex items-center gap-3", children: [
28
29
  /* @__PURE__ */ e(
29
- N,
30
+ j,
30
31
  {
31
32
  id: l,
32
- checked: p,
33
- onCheckedChange: f,
34
- "aria-invalid": !x
33
+ checked: x,
34
+ onCheckedChange: C,
35
+ "aria-invalid": !f
35
36
  }
36
37
  ),
37
- r && /* @__PURE__ */ e(j, { htmlFor: l, className: "cursor-pointer", children: r })
38
+ i && /* @__PURE__ */ e(y, { htmlFor: l, className: "cursor-pointer", children: i })
38
39
  ] }),
39
- c.length > 0 && /* @__PURE__ */ e("div", { className: "text-sm text-destructive ml-6", children: c.map((n, k) => /* @__PURE__ */ e("p", { children: n }, k)) })
40
+ s.length > 0 && /* @__PURE__ */ e("div", { className: "text-sm text-destructive ml-6", children: s.map((t, g) => /* @__PURE__ */ e("p", { children: t }, g)) })
40
41
  ] });
41
42
  });
42
- F.displayName = "A2UI.CheckBox";
43
+ P.displayName = "A2UI.CheckBox";
43
44
  export {
44
- F as CheckBoxComponent
45
+ P as CheckBoxComponent
45
46
  };
@@ -5,8 +5,12 @@ import { Catalog } from '../standard-catalog';
5
5
  * Props for A2UIProvider.
6
6
  */
7
7
  export interface A2UIProviderProps {
8
- /** Array of A2UI messages to render */
9
- messages: A2UIMessage[];
8
+ /**
9
+ * Array of A2UI messages to render.
10
+ * When this prop changes, all state is cleared and messages are reprocessed.
11
+ * For incremental updates, use useA2UIMessageHandler hook inside the provider.
12
+ */
13
+ messages?: A2UIMessage[];
10
14
  /**
11
15
  * Catalog containing components and functions.
12
16
  * Use `standardCatalog` from '@a2ui-sdk/react/0.9/standard-catalog' as base.
@@ -1,26 +1,25 @@
1
- import { jsx as t, Fragment as s } from "react/jsx-runtime";
1
+ import { jsx as e, Fragment as i } from "react/jsx-runtime";
2
2
  import { useEffect as f } from "react";
3
- import { SurfaceProvider as a } from "./SurfaceContext.js";
4
- import { ComponentsMapProvider as c } from "./ComponentsMapContext.js";
5
- import { useA2UIMessageHandler as i } from "../hooks/useA2UIMessageHandler.js";
6
- import { standardCatalog as m } from "../standard-catalog/index.js";
7
- function p({
3
+ import { SurfaceProvider as c } from "./SurfaceContext.js";
4
+ import { ComponentsMapProvider as a } from "./ComponentsMapContext.js";
5
+ import { useA2UIMessageHandler as m } from "../hooks/useA2UIMessageHandler.js";
6
+ import { standardCatalog as p } from "../standard-catalog/index.js";
7
+ function d({
8
8
  messages: o,
9
- children: n
9
+ children: t
10
10
  }) {
11
- const { processMessages: r, clear: e } = i();
11
+ const { processMessages: r, clear: n } = m();
12
12
  return f(() => {
13
- e(), o && o.length > 0 && r(o);
14
- }, [o, r, e]), /* @__PURE__ */ t(s, { children: n });
13
+ o !== void 0 && (n(), o && o.length > 0 && r(o));
14
+ }, [o, n, r]), /* @__PURE__ */ e(i, { children: t });
15
15
  }
16
- function P({
16
+ function M({
17
17
  messages: o,
18
- catalog: n,
18
+ catalog: t,
19
19
  children: r
20
20
  }) {
21
- const e = o ?? [];
22
- return /* @__PURE__ */ t(a, { children: /* @__PURE__ */ t(c, { components: (n ?? m).components, children: /* @__PURE__ */ t(p, { messages: e, children: r }) }) });
21
+ return /* @__PURE__ */ e(c, { children: /* @__PURE__ */ e(a, { components: (t ?? p).components, children: /* @__PURE__ */ e(d, { messages: o, children: r }) }) });
23
22
  }
24
23
  export {
25
- P as A2UIProvider
24
+ M as A2UIProvider
26
25
  };
@@ -24,9 +24,6 @@ export interface A2UIMessageHandler {
24
24
  * const { processMessage, processMessages, clear } = useA2UIMessageHandler();
25
25
  *
26
26
  * useEffect(() => {
27
- * // Process initial messages
28
- * processMessages(initialMessages);
29
- *
30
27
  * // Listen for SSE updates
31
28
  * const handler = (event) => {
32
29
  * processMessage(JSON.parse(event.data));
@@ -35,3 +35,5 @@ export { useValidation } from './hooks/useValidation';
35
35
  export { useSurfaceContext } from './contexts/SurfaceContext';
36
36
  export { useScope, useScopeBasePath } from './contexts/ScopeContext';
37
37
  export { ActionProvider, useActionContext } from './contexts/ActionContext';
38
+ export { useA2UIMessageHandler } from './hooks/useA2UIMessageHandler';
39
+ export type { A2UIMessageHandler } from './hooks/useA2UIMessageHandler';
package/dist/0.9/index.js CHANGED
@@ -1,27 +1,29 @@
1
1
  import { A2UIProvider as r } from "./contexts/A2UIProvider.js";
2
2
  import { A2UIRenderer as n } from "./A2UIRenderer.js";
3
- import { ComponentRenderer as a } from "./components/ComponentRenderer.js";
4
- import { standardCatalog as s } from "./standard-catalog/index.js";
3
+ import { ComponentRenderer as s } from "./components/ComponentRenderer.js";
4
+ import { standardCatalog as p } from "./standard-catalog/index.js";
5
5
  import { useDispatchAction as x } from "./hooks/useDispatchAction.js";
6
6
  import { useDataBinding as f, useDataModel as u, useFormBinding as c, useStringBinding as g } from "./hooks/useDataBinding.js";
7
- import { useValidation as B } from "./hooks/useValidation.js";
8
- import { useSurfaceContext as S } from "./contexts/SurfaceContext.js";
9
- import { useScope as D, useScopeBasePath as P } from "./contexts/ScopeContext.js";
10
- import { ActionProvider as v, useActionContext as I } from "./contexts/ActionContext.js";
7
+ import { useValidation as l } from "./hooks/useValidation.js";
8
+ import { useSurfaceContext as C } from "./contexts/SurfaceContext.js";
9
+ import { useScope as D, useScopeBasePath as I } from "./contexts/ScopeContext.js";
10
+ import { ActionProvider as U, useActionContext as h } from "./contexts/ActionContext.js";
11
+ import { useA2UIMessageHandler as M } from "./hooks/useA2UIMessageHandler.js";
11
12
  export {
12
13
  r as A2UIProvider,
13
14
  n as A2UIRenderer,
14
- v as ActionProvider,
15
- a as ComponentRenderer,
16
- s as standardCatalog,
17
- I as useActionContext,
15
+ U as ActionProvider,
16
+ s as ComponentRenderer,
17
+ p as standardCatalog,
18
+ M as useA2UIMessageHandler,
19
+ h as useActionContext,
18
20
  f as useDataBinding,
19
21
  u as useDataModel,
20
22
  x as useDispatchAction,
21
23
  c as useFormBinding,
22
24
  D as useScope,
23
- P as useScopeBasePath,
25
+ I as useScopeBasePath,
24
26
  g as useStringBinding,
25
- S as useSurfaceContext,
26
- B as useValidation
27
+ C as useSurfaceContext,
28
+ l as useValidation
27
29
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a2ui-sdk/react",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "A2UI SDK for React",
5
5
  "homepage": "https://a2ui-sdk.js.org/",
6
6
  "repository": {
@@ -66,8 +66,8 @@
66
66
  "vitest": "^4.0.16"
67
67
  },
68
68
  "dependencies": {
69
- "@a2ui-sdk/types": "0.3.0",
70
- "@a2ui-sdk/utils": "0.3.0",
69
+ "@a2ui-sdk/types": "0.4.0",
70
+ "@a2ui-sdk/utils": "0.4.0",
71
71
  "@radix-ui/react-checkbox": "^1.3.3",
72
72
  "@radix-ui/react-dialog": "^1.1.15",
73
73
  "@radix-ui/react-label": "^2.1.8",