@assistant-ui/react-generative-ui 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/LICENSE +1 -1
  2. package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
  3. package/dist/JSONGenerativeUI.client.js +30 -13
  4. package/dist/JSONGenerativeUI.client.js.map +1 -1
  5. package/dist/RadioGroupScope.d.ts +6 -0
  6. package/dist/RadioGroupScope.d.ts.map +1 -0
  7. package/dist/RadioGroupScope.js +25 -0
  8. package/dist/RadioGroupScope.js.map +1 -0
  9. package/dist/a2ui/BindingContext.d.ts +11 -0
  10. package/dist/a2ui/BindingContext.d.ts.map +1 -0
  11. package/dist/a2ui/BindingContext.js +12 -0
  12. package/dist/a2ui/BindingContext.js.map +1 -0
  13. package/dist/a2ui/PresentRenderer.d.ts +11 -0
  14. package/dist/a2ui/PresentRenderer.d.ts.map +1 -0
  15. package/dist/a2ui/PresentRenderer.js +39 -0
  16. package/dist/a2ui/PresentRenderer.js.map +1 -0
  17. package/dist/a2ui/convert.d.ts +6 -0
  18. package/dist/a2ui/convert.d.ts.map +1 -1
  19. package/dist/a2ui/convert.js +344 -83
  20. package/dist/a2ui/convert.js.map +1 -1
  21. package/dist/a2ui/dataModel.d.ts +9 -0
  22. package/dist/a2ui/dataModel.d.ts.map +1 -0
  23. package/dist/a2ui/dataModel.js +44 -0
  24. package/dist/a2ui/dataModel.js.map +1 -0
  25. package/dist/a2ui/reducer.d.ts +5 -0
  26. package/dist/a2ui/reducer.d.ts.map +1 -1
  27. package/dist/a2ui/reducer.js +3 -3
  28. package/dist/a2ui/reducer.js.map +1 -1
  29. package/dist/a2ui/types.d.ts +8 -2
  30. package/dist/a2ui/types.d.ts.map +1 -1
  31. package/dist/a2ui/types.js.map +1 -1
  32. package/dist/a2ui/valueFunctions.d.ts +16 -0
  33. package/dist/a2ui/valueFunctions.d.ts.map +1 -0
  34. package/dist/a2ui/valueFunctions.js +332 -0
  35. package/dist/a2ui/valueFunctions.js.map +1 -0
  36. package/dist/actionRegistry.d.ts +1 -1
  37. package/dist/actionRegistry.js.map +1 -1
  38. package/dist/answeredValues.d.ts +16 -0
  39. package/dist/answeredValues.d.ts.map +1 -0
  40. package/dist/answeredValues.js +37 -0
  41. package/dist/answeredValues.js.map +1 -0
  42. package/dist/constants.d.ts +2 -0
  43. package/dist/constants.d.ts.map +1 -1
  44. package/dist/constants.js +3 -1
  45. package/dist/constants.js.map +1 -1
  46. package/dist/fieldReferences.d.ts +9 -0
  47. package/dist/fieldReferences.d.ts.map +1 -0
  48. package/dist/fieldReferences.js +53 -0
  49. package/dist/fieldReferences.js.map +1 -0
  50. package/dist/generativeUIToJSX.js +3 -3
  51. package/dist/generativeUIToJSX.js.map +1 -1
  52. package/dist/index.js +2 -2
  53. package/dist/index.server.js +2 -2
  54. package/dist/index.shared.js +2 -2
  55. package/dist/ir.d.ts +1 -1
  56. package/dist/ir.js.map +1 -1
  57. package/dist/renderGenerativeUI.d.ts.map +1 -1
  58. package/dist/renderGenerativeUI.js +12 -1
  59. package/dist/renderGenerativeUI.js.map +1 -1
  60. package/dist/slack/constants.d.ts +2 -0
  61. package/dist/slack/constants.d.ts.map +1 -1
  62. package/dist/slack/constants.js +3 -1
  63. package/dist/slack/constants.js.map +1 -1
  64. package/dist/slack/decodeBlockAction.d.ts +3 -1
  65. package/dist/slack/decodeBlockAction.d.ts.map +1 -1
  66. package/dist/slack/decodeBlockAction.js +58 -7
  67. package/dist/slack/decodeBlockAction.js.map +1 -1
  68. package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
  69. package/dist/slack/fromSlackBlocks.js +20 -3
  70. package/dist/slack/fromSlackBlocks.js.map +1 -1
  71. package/dist/slack/toSlackBlocks.d.ts.map +1 -1
  72. package/dist/slack/toSlackBlocks.js +187 -19
  73. package/dist/slack/toSlackBlocks.js.map +1 -1
  74. package/dist/slack/types.d.ts +4 -0
  75. package/dist/slack/types.d.ts.map +1 -1
  76. package/dist/teams/constants.d.ts +1 -1
  77. package/dist/teams/constants.d.ts.map +1 -1
  78. package/dist/teams/constants.js +1 -1
  79. package/dist/teams/constants.js.map +1 -1
  80. package/dist/teams/decodeSubmitData.d.ts +4 -0
  81. package/dist/teams/decodeSubmitData.d.ts.map +1 -1
  82. package/dist/teams/decodeSubmitData.js +6 -1
  83. package/dist/teams/decodeSubmitData.js.map +1 -1
  84. package/dist/teams/toAdaptiveCard.d.ts +5 -4
  85. package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
  86. package/dist/teams/toAdaptiveCard.js +56 -17
  87. package/dist/teams/toAdaptiveCard.js.map +1 -1
  88. package/dist/teams/types.d.ts +4 -1
  89. package/dist/teams/types.d.ts.map +1 -1
  90. package/dist/vocabulary/alert.d.ts +9 -2
  91. package/dist/vocabulary/alert.d.ts.map +1 -1
  92. package/dist/vocabulary/alert.js +116 -19
  93. package/dist/vocabulary/alert.js.map +1 -1
  94. package/dist/vocabulary/collectFormValues.d.ts +2 -1
  95. package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
  96. package/dist/vocabulary/collectFormValues.js +10 -3
  97. package/dist/vocabulary/collectFormValues.js.map +1 -1
  98. package/dist/vocabulary/data.d.ts +22 -5
  99. package/dist/vocabulary/data.d.ts.map +1 -1
  100. package/dist/vocabulary/data.js +278 -83
  101. package/dist/vocabulary/data.js.map +1 -1
  102. package/dist/vocabulary/dispatch.d.ts +3 -2
  103. package/dist/vocabulary/dispatch.d.ts.map +1 -1
  104. package/dist/vocabulary/dispatch.js +33 -4
  105. package/dist/vocabulary/dispatch.js.map +1 -1
  106. package/dist/vocabulary/fact.d.ts +8 -1
  107. package/dist/vocabulary/fact.d.ts.map +1 -1
  108. package/dist/vocabulary/fact.js +37 -11
  109. package/dist/vocabulary/fact.js.map +1 -1
  110. package/dist/vocabulary/form.d.ts.map +1 -1
  111. package/dist/vocabulary/form.js +3 -3
  112. package/dist/vocabulary/form.js.map +1 -1
  113. package/dist/vocabulary/formatValue.d.ts +7 -0
  114. package/dist/vocabulary/formatValue.d.ts.map +1 -0
  115. package/dist/vocabulary/formatValue.js +76 -0
  116. package/dist/vocabulary/formatValue.js.map +1 -0
  117. package/dist/vocabulary/icon.d.ts +1 -1
  118. package/dist/vocabulary/interactive.d.ts +137 -8
  119. package/dist/vocabulary/interactive.d.ts.map +1 -1
  120. package/dist/vocabulary/interactive.js +404 -103
  121. package/dist/vocabulary/interactive.js.map +1 -1
  122. package/dist/vocabulary/layout.d.ts.map +1 -1
  123. package/dist/vocabulary/layout.js +4 -4
  124. package/dist/vocabulary/layout.js.map +1 -1
  125. package/dist/vocabulary/list.js +2 -2
  126. package/dist/vocabulary/list.js.map +1 -1
  127. package/dist/vocabulary/text.d.ts +1 -1
  128. package/package.json +6 -3
  129. package/src/JSONGenerativeUI.client.tsx +84 -40
  130. package/src/JSONGenerativeUI.test.tsx +964 -68
  131. package/src/RadioGroupScope.server.test.tsx +24 -0
  132. package/src/RadioGroupScope.tsx +34 -0
  133. package/src/a2ui/BindingContext.ts +26 -0
  134. package/src/a2ui/PresentRenderer.tsx +83 -0
  135. package/src/a2ui/convert.test.ts +1795 -179
  136. package/src/a2ui/convert.ts +629 -132
  137. package/src/a2ui/dataModel.ts +69 -0
  138. package/src/a2ui/reducer.test.ts +35 -0
  139. package/src/a2ui/reducer.ts +5 -4
  140. package/src/a2ui/types.ts +9 -2
  141. package/src/a2ui/valueFunctions.test.ts +271 -0
  142. package/src/a2ui/valueFunctions.ts +523 -0
  143. package/src/actionRegistry.ts +1 -1
  144. package/src/answeredValues.test.ts +33 -0
  145. package/src/answeredValues.tsx +70 -0
  146. package/src/constants.ts +4 -0
  147. package/src/fieldReferences.test.ts +66 -0
  148. package/src/fieldReferences.ts +83 -0
  149. package/src/generativeUIToJSX.test.ts +18 -0
  150. package/src/generativeUIToJSX.ts +4 -6
  151. package/src/index.server.test.ts +106 -0
  152. package/src/ir.ts +1 -1
  153. package/src/renderGenerativeUI.test.tsx +14 -5
  154. package/src/renderGenerativeUI.tsx +30 -1
  155. package/src/slack/a2uiSlack.test.ts +198 -0
  156. package/src/slack/constants.ts +3 -0
  157. package/src/slack/decodeBlockAction.test.ts +98 -0
  158. package/src/slack/decodeBlockAction.ts +110 -17
  159. package/src/slack/fromSlackBlocks.test.ts +222 -3
  160. package/src/slack/fromSlackBlocks.ts +53 -2
  161. package/src/slack/toSlackBlocks.test.ts +682 -3
  162. package/src/slack/toSlackBlocks.ts +374 -23
  163. package/src/slack/types.ts +4 -0
  164. package/src/teams/constants.ts +1 -1
  165. package/src/teams/decodeSubmitData.test.ts +33 -0
  166. package/src/teams/decodeSubmitData.ts +9 -1
  167. package/src/teams/toAdaptiveCard.test.ts +219 -0
  168. package/src/teams/toAdaptiveCard.ts +93 -19
  169. package/src/teams/types.ts +4 -1
  170. package/src/vocabulary/alert.test.tsx +288 -7
  171. package/src/vocabulary/alert.tsx +168 -26
  172. package/src/vocabulary/collectFormValues.test.ts +28 -1
  173. package/src/vocabulary/collectFormValues.ts +25 -5
  174. package/src/vocabulary/data.test.tsx +248 -6
  175. package/src/vocabulary/data.tsx +398 -100
  176. package/src/vocabulary/dispatch.ts +63 -2
  177. package/src/vocabulary/fact.test.tsx +67 -0
  178. package/src/vocabulary/fact.tsx +40 -9
  179. package/src/vocabulary/form.tsx +7 -2
  180. package/src/vocabulary/formatValue.test.ts +72 -0
  181. package/src/vocabulary/formatValue.ts +127 -0
  182. package/src/vocabulary/index.test.ts +2 -0
  183. package/src/vocabulary/interactive.dispatch.test.tsx +167 -79
  184. package/src/vocabulary/interactive.dom.test.tsx +1699 -0
  185. package/src/vocabulary/interactive.test.tsx +60 -4
  186. package/src/vocabulary/interactive.tsx +770 -151
  187. package/src/vocabulary/layout.test.tsx +6 -4
  188. package/src/vocabulary/layout.tsx +13 -2
  189. package/src/vocabulary/list.tsx +2 -2
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { RadioGroupScope, useRadioGroupName } from "./RadioGroupScope";
3
+
4
+ const { useId } = vi.hoisted(() => ({ useId: vi.fn(() => "server-id") }));
5
+
6
+ vi.mock("react", async (importOriginal) => ({
7
+ ...(await importOriginal()),
8
+ createContext: undefined,
9
+ useContext: undefined,
10
+ useId,
11
+ }));
12
+
13
+ describe("radio scoping without React context APIs", () => {
14
+ it("passes display content through without calling client hooks", () => {
15
+ const children = <p>Hello</p>;
16
+ expect(RadioGroupScope({ children })).toBe(children);
17
+ expect(useId).not.toHaveBeenCalled();
18
+ });
19
+
20
+ it("preserves unscoped logical names and generates unnamed ones", () => {
21
+ expect(useRadioGroupName("choice")).toBe("choice");
22
+ expect(useRadioGroupName(undefined)).toBe("server-id");
23
+ });
24
+ });
@@ -0,0 +1,34 @@
1
+ import * as React from "react";
2
+
3
+ let radioGroupContext: React.Context<string | undefined> | undefined;
4
+ const supportsContext = typeof React.createContext === "function";
5
+ const useScopeId = supportsContext ? React.useId : () => undefined;
6
+ const useScopeContext = supportsContext ? React.useContext : () => undefined;
7
+
8
+ // Vocabulary schemas are also imported under React's server condition.
9
+ const getRadioGroupContext = () =>
10
+ supportsContext
11
+ ? (radioGroupContext ??= React.createContext<string | undefined>(undefined))
12
+ : undefined;
13
+
14
+ export const RadioGroupScope = ({
15
+ children,
16
+ }: {
17
+ children: React.ReactNode;
18
+ }) => {
19
+ const scopeId = useScopeId();
20
+ const Context = getRadioGroupContext();
21
+ return Context ? (
22
+ <Context.Provider value={scopeId}>{children}</Context.Provider>
23
+ ) : (
24
+ children
25
+ );
26
+ };
27
+
28
+ export const useRadioGroupName = (name: string | undefined) => {
29
+ const scopeId = useScopeContext(getRadioGroupContext()!);
30
+ const groupId = React.useId();
31
+ return scopeId !== undefined && name != null
32
+ ? JSON.stringify([scopeId, name])
33
+ : (name ?? groupId);
34
+ };
@@ -0,0 +1,26 @@
1
+ import * as React from "react";
2
+
3
+ export type A2uiBinding = {
4
+ readonly value: unknown;
5
+ readonly arrayValue: boolean;
6
+ };
7
+
8
+ export const A2uiBindingContext =
9
+ typeof React.createContext === "function"
10
+ ? React.createContext<
11
+ | {
12
+ readonly fields: ReadonlyMap<string, A2uiBinding>;
13
+ readonly update: (path: string, value: unknown) => void;
14
+ }
15
+ | undefined
16
+ >(undefined)
17
+ : undefined;
18
+
19
+ export const useA2uiBinding = (name: string | undefined) => {
20
+ const context = React.useContext(A2uiBindingContext!);
21
+ const binding = name === undefined ? undefined : context?.fields.get(name);
22
+ return context && binding && name !== undefined
23
+ ? (value: unknown) =>
24
+ context.update(name, binding.arrayValue ? [value] : value)
25
+ : undefined;
26
+ };
@@ -0,0 +1,83 @@
1
+ import * as React from "react";
2
+ import { renderGenerativeUI } from "../renderGenerativeUI";
3
+ import type {
4
+ GenerativeUIDispatch,
5
+ GenerativeUILibrary,
6
+ GenerativeUIStatus,
7
+ } from "../types";
8
+ import { A2uiBindingContext } from "./BindingContext";
9
+ import { equalData, reconcileDataModel, resolvePointer } from "./dataModel";
10
+ import { applyA2uiOperations, setAtPointer } from "./reducer";
11
+ import { createLiveSurfaceConverter } from "./convert";
12
+
13
+ export function A2uiPresentRenderer({
14
+ surfaceId,
15
+ operations,
16
+ fallback,
17
+ library,
18
+ status,
19
+ dispatch,
20
+ }: {
21
+ surfaceId: string;
22
+ operations: unknown;
23
+ fallback: unknown;
24
+ library: GenerativeUILibrary;
25
+ status: GenerativeUIStatus;
26
+ dispatch?: GenerativeUIDispatch;
27
+ }) {
28
+ const surface = React.useMemo(
29
+ () => applyA2uiOperations(new Map(), operations).state.get(surfaceId),
30
+ [operations, surfaceId],
31
+ );
32
+ const incoming = surface?.dataModel;
33
+ const [local, setLocal] = React.useState(() => ({
34
+ incoming,
35
+ value: incoming,
36
+ editedPaths: new Set<string>(),
37
+ }));
38
+ const model = Object.is(incoming, local.incoming)
39
+ ? local
40
+ : reconcileDataModel(
41
+ local.incoming,
42
+ incoming,
43
+ local.value,
44
+ local.editedPaths,
45
+ );
46
+ if (model !== local) setLocal(model);
47
+ const convert = React.useMemo(
48
+ () => surface && createLiveSurfaceConverter(surface),
49
+ [surface],
50
+ );
51
+ const converted = React.useMemo(
52
+ () => convert?.(model.value),
53
+ [convert, model.value],
54
+ );
55
+ const BindingContext = A2uiBindingContext!;
56
+ return (
57
+ <BindingContext.Provider
58
+ value={
59
+ converted
60
+ ? {
61
+ fields: converted.bindings,
62
+ update: (path, value) =>
63
+ setLocal((current) =>
64
+ equalData(resolvePointer(current.value, path), value)
65
+ ? current
66
+ : {
67
+ ...current,
68
+ value: setAtPointer(current.value, path, value, false)
69
+ .value,
70
+ editedPaths: new Set([...current.editedPaths, path]),
71
+ },
72
+ ),
73
+ }
74
+ : undefined
75
+ }
76
+ >
77
+ {renderGenerativeUI(converted?.spec ?? fallback, library, {
78
+ status,
79
+ ...(dispatch ? { dispatch } : {}),
80
+ })}
81
+ </BindingContext.Provider>
82
+ );
83
+ }