@assistant-ui/react-generative-ui 0.0.23 → 0.1.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.
Files changed (338) hide show
  1. package/README.md +2 -0
  2. package/dist/a2ui.d.ts +1 -4
  3. package/dist/a2ui.d.ts.map +1 -1
  4. package/dist/a2ui.js +1 -4
  5. package/dist/index.d.ts +1 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -10
  8. package/dist/index.server.d.ts +1 -2
  9. package/dist/index.server.d.ts.map +1 -1
  10. package/dist/index.server.js +1 -10
  11. package/dist/ir.d.ts +1 -111
  12. package/dist/ir.d.ts.map +1 -1
  13. package/dist/ir.js +1 -175
  14. package/dist/slack.d.ts +1 -4
  15. package/dist/slack.d.ts.map +1 -1
  16. package/dist/slack.js +1 -4
  17. package/dist/teams.d.ts +1 -4
  18. package/dist/teams.d.ts.map +1 -1
  19. package/dist/teams.js +1 -4
  20. package/package.json +5 -5
  21. package/src/a2ui.ts +1 -22
  22. package/src/index.server.ts +1 -2
  23. package/src/index.test.ts +75 -0
  24. package/src/index.ts +1 -2
  25. package/src/ir.ts +1 -279
  26. package/src/slack.ts +1 -39
  27. package/src/teams.ts +1 -35
  28. package/dist/JSONGenerativeUI.client.d.ts +0 -28
  29. package/dist/JSONGenerativeUI.client.d.ts.map +0 -1
  30. package/dist/JSONGenerativeUI.client.js +0 -101
  31. package/dist/JSONGenerativeUI.client.js.map +0 -1
  32. package/dist/JSONGenerativeUI.server.d.ts +0 -21
  33. package/dist/JSONGenerativeUI.server.d.ts.map +0 -1
  34. package/dist/JSONGenerativeUI.server.js +0 -32
  35. package/dist/JSONGenerativeUI.server.js.map +0 -1
  36. package/dist/JSONGenerativeUI.shared.d.ts +0 -63
  37. package/dist/JSONGenerativeUI.shared.d.ts.map +0 -1
  38. package/dist/JSONGenerativeUI.shared.js +0 -31
  39. package/dist/JSONGenerativeUI.shared.js.map +0 -1
  40. package/dist/RadioGroupScope.d.ts +0 -6
  41. package/dist/RadioGroupScope.d.ts.map +0 -1
  42. package/dist/RadioGroupScope.js +0 -25
  43. package/dist/RadioGroupScope.js.map +0 -1
  44. package/dist/a2ui/BindingContext.d.ts +0 -11
  45. package/dist/a2ui/BindingContext.d.ts.map +0 -1
  46. package/dist/a2ui/BindingContext.js +0 -12
  47. package/dist/a2ui/BindingContext.js.map +0 -1
  48. package/dist/a2ui/PresentRenderer.d.ts +0 -11
  49. package/dist/a2ui/PresentRenderer.d.ts.map +0 -1
  50. package/dist/a2ui/PresentRenderer.js +0 -39
  51. package/dist/a2ui/PresentRenderer.js.map +0 -1
  52. package/dist/a2ui/convert.d.ts +0 -15
  53. package/dist/a2ui/convert.d.ts.map +0 -1
  54. package/dist/a2ui/convert.js +0 -728
  55. package/dist/a2ui/convert.js.map +0 -1
  56. package/dist/a2ui/dataModel.d.ts +0 -9
  57. package/dist/a2ui/dataModel.d.ts.map +0 -1
  58. package/dist/a2ui/dataModel.js +0 -44
  59. package/dist/a2ui/dataModel.js.map +0 -1
  60. package/dist/a2ui/reducer.d.ts +0 -8
  61. package/dist/a2ui/reducer.d.ts.map +0 -1
  62. package/dist/a2ui/reducer.js +0 -242
  63. package/dist/a2ui/reducer.js.map +0 -1
  64. package/dist/a2ui/snapshot.d.ts +0 -3
  65. package/dist/a2ui/snapshot.d.ts.map +0 -1
  66. package/dist/a2ui/snapshot.js +0 -33
  67. package/dist/a2ui/snapshot.js.map +0 -1
  68. package/dist/a2ui/types.d.ts +0 -88
  69. package/dist/a2ui/types.d.ts.map +0 -1
  70. package/dist/a2ui/types.js +0 -6
  71. package/dist/a2ui/types.js.map +0 -1
  72. package/dist/a2ui/valueFunctions.d.ts +0 -16
  73. package/dist/a2ui/valueFunctions.d.ts.map +0 -1
  74. package/dist/a2ui/valueFunctions.js +0 -332
  75. package/dist/a2ui/valueFunctions.js.map +0 -1
  76. package/dist/actionRegistry.d.ts +0 -29
  77. package/dist/actionRegistry.d.ts.map +0 -1
  78. package/dist/actionRegistry.js +0 -41
  79. package/dist/actionRegistry.js.map +0 -1
  80. package/dist/answeredValues.d.ts +0 -16
  81. package/dist/answeredValues.d.ts.map +0 -1
  82. package/dist/answeredValues.js +0 -37
  83. package/dist/answeredValues.js.map +0 -1
  84. package/dist/buildPresentParameters.d.ts +0 -21
  85. package/dist/buildPresentParameters.d.ts.map +0 -1
  86. package/dist/buildPresentParameters.js +0 -95
  87. package/dist/buildPresentParameters.js.map +0 -1
  88. package/dist/constants.d.ts +0 -15
  89. package/dist/constants.d.ts.map +0 -1
  90. package/dist/constants.js +0 -19
  91. package/dist/constants.js.map +0 -1
  92. package/dist/convert/boundSpec.d.ts +0 -48
  93. package/dist/convert/boundSpec.d.ts.map +0 -1
  94. package/dist/convert/boundSpec.js +0 -108
  95. package/dist/convert/boundSpec.js.map +0 -1
  96. package/dist/convert/copyBounded.d.ts +0 -25
  97. package/dist/convert/copyBounded.d.ts.map +0 -1
  98. package/dist/convert/copyBounded.js +0 -38
  99. package/dist/convert/copyBounded.js.map +0 -1
  100. package/dist/convert/isElement.d.ts +0 -3
  101. package/dist/convert/isElement.d.ts.map +0 -1
  102. package/dist/convert/isElement.js +0 -6
  103. package/dist/convert/isElement.js.map +0 -1
  104. package/dist/convert/takeRun.d.ts +0 -6
  105. package/dist/convert/takeRun.d.ts.map +0 -1
  106. package/dist/convert/takeRun.js +0 -20
  107. package/dist/convert/takeRun.js.map +0 -1
  108. package/dist/defineGenerativeComponents.d.ts +0 -29
  109. package/dist/defineGenerativeComponents.d.ts.map +0 -1
  110. package/dist/defineGenerativeComponents.js +0 -34
  111. package/dist/defineGenerativeComponents.js.map +0 -1
  112. package/dist/fieldReferences.d.ts +0 -9
  113. package/dist/fieldReferences.d.ts.map +0 -1
  114. package/dist/fieldReferences.js +0 -53
  115. package/dist/fieldReferences.js.map +0 -1
  116. package/dist/generativeUIToJSX.d.ts +0 -18
  117. package/dist/generativeUIToJSX.d.ts.map +0 -1
  118. package/dist/generativeUIToJSX.js +0 -76
  119. package/dist/generativeUIToJSX.js.map +0 -1
  120. package/dist/index.shared.d.ts +0 -15
  121. package/dist/index.shared.d.ts.map +0 -1
  122. package/dist/index.shared.js +0 -9
  123. package/dist/ir.js.map +0 -1
  124. package/dist/renderGenerativeUI.d.ts +0 -14
  125. package/dist/renderGenerativeUI.d.ts.map +0 -1
  126. package/dist/renderGenerativeUI.js +0 -83
  127. package/dist/renderGenerativeUI.js.map +0 -1
  128. package/dist/scopeSchema.d.ts +0 -6
  129. package/dist/scopeSchema.d.ts.map +0 -1
  130. package/dist/scopeSchema.js +0 -56
  131. package/dist/scopeSchema.js.map +0 -1
  132. package/dist/slack/constants.d.ts +0 -93
  133. package/dist/slack/constants.d.ts.map +0 -1
  134. package/dist/slack/constants.js +0 -146
  135. package/dist/slack/constants.js.map +0 -1
  136. package/dist/slack/decodeBlockAction.d.ts +0 -10
  137. package/dist/slack/decodeBlockAction.d.ts.map +0 -1
  138. package/dist/slack/decodeBlockAction.js +0 -129
  139. package/dist/slack/decodeBlockAction.js.map +0 -1
  140. package/dist/slack/fromSlackBlocks.d.ts +0 -27
  141. package/dist/slack/fromSlackBlocks.d.ts.map +0 -1
  142. package/dist/slack/fromSlackBlocks.js +0 -483
  143. package/dist/slack/fromSlackBlocks.js.map +0 -1
  144. package/dist/slack/toSlackBlocks.d.ts +0 -4
  145. package/dist/slack/toSlackBlocks.d.ts.map +0 -1
  146. package/dist/slack/toSlackBlocks.js +0 -901
  147. package/dist/slack/toSlackBlocks.js.map +0 -1
  148. package/dist/slack/types.d.ts +0 -204
  149. package/dist/slack/types.d.ts.map +0 -1
  150. package/dist/slack/types.js +0 -0
  151. package/dist/teams/constants.d.ts +0 -34
  152. package/dist/teams/constants.d.ts.map +0 -1
  153. package/dist/teams/constants.js +0 -68
  154. package/dist/teams/constants.js.map +0 -1
  155. package/dist/teams/decodeSubmitData.d.ts +0 -26
  156. package/dist/teams/decodeSubmitData.d.ts.map +0 -1
  157. package/dist/teams/decodeSubmitData.js +0 -70
  158. package/dist/teams/decodeSubmitData.js.map +0 -1
  159. package/dist/teams/temporalId.d.ts +0 -5
  160. package/dist/teams/temporalId.d.ts.map +0 -1
  161. package/dist/teams/temporalId.js +0 -28
  162. package/dist/teams/temporalId.js.map +0 -1
  163. package/dist/teams/toAdaptiveCard.d.ts +0 -45
  164. package/dist/teams/toAdaptiveCard.d.ts.map +0 -1
  165. package/dist/teams/toAdaptiveCard.js +0 -642
  166. package/dist/teams/toAdaptiveCard.js.map +0 -1
  167. package/dist/teams/toTeamsAttachments.d.ts +0 -10
  168. package/dist/teams/toTeamsAttachments.d.ts.map +0 -1
  169. package/dist/teams/toTeamsAttachments.js +0 -99
  170. package/dist/teams/toTeamsAttachments.js.map +0 -1
  171. package/dist/teams/types.d.ts +0 -224
  172. package/dist/teams/types.d.ts.map +0 -1
  173. package/dist/teams/types.js +0 -0
  174. package/dist/temporal.d.ts +0 -33
  175. package/dist/temporal.d.ts.map +0 -1
  176. package/dist/temporal.js +0 -152
  177. package/dist/temporal.js.map +0 -1
  178. package/dist/types.d.ts +0 -99
  179. package/dist/types.d.ts.map +0 -1
  180. package/dist/types.js +0 -0
  181. package/dist/vocabulary/alert.d.ts +0 -32
  182. package/dist/vocabulary/alert.d.ts.map +0 -1
  183. package/dist/vocabulary/alert.js +0 -160
  184. package/dist/vocabulary/alert.js.map +0 -1
  185. package/dist/vocabulary/collectFormValues.d.ts +0 -23
  186. package/dist/vocabulary/collectFormValues.d.ts.map +0 -1
  187. package/dist/vocabulary/collectFormValues.js +0 -44
  188. package/dist/vocabulary/collectFormValues.js.map +0 -1
  189. package/dist/vocabulary/data.d.ts +0 -66
  190. package/dist/vocabulary/data.d.ts.map +0 -1
  191. package/dist/vocabulary/data.js +0 -503
  192. package/dist/vocabulary/data.js.map +0 -1
  193. package/dist/vocabulary/dispatch.d.ts +0 -9
  194. package/dist/vocabulary/dispatch.d.ts.map +0 -1
  195. package/dist/vocabulary/dispatch.js +0 -50
  196. package/dist/vocabulary/dispatch.js.map +0 -1
  197. package/dist/vocabulary/fact.d.ts +0 -19
  198. package/dist/vocabulary/fact.d.ts.map +0 -1
  199. package/dist/vocabulary/fact.js +0 -51
  200. package/dist/vocabulary/fact.js.map +0 -1
  201. package/dist/vocabulary/form.d.ts +0 -11
  202. package/dist/vocabulary/form.d.ts.map +0 -1
  203. package/dist/vocabulary/form.js +0 -23
  204. package/dist/vocabulary/form.js.map +0 -1
  205. package/dist/vocabulary/formatValue.d.ts +0 -7
  206. package/dist/vocabulary/formatValue.d.ts.map +0 -1
  207. package/dist/vocabulary/formatValue.js +0 -76
  208. package/dist/vocabulary/formatValue.js.map +0 -1
  209. package/dist/vocabulary/icon.d.ts +0 -41
  210. package/dist/vocabulary/icon.d.ts.map +0 -1
  211. package/dist/vocabulary/icon.js +0 -272
  212. package/dist/vocabulary/icon.js.map +0 -1
  213. package/dist/vocabulary/index.d.ts +0 -12
  214. package/dist/vocabulary/index.d.ts.map +0 -1
  215. package/dist/vocabulary/index.js +0 -36
  216. package/dist/vocabulary/index.js.map +0 -1
  217. package/dist/vocabulary/interactive.d.ts +0 -230
  218. package/dist/vocabulary/interactive.d.ts.map +0 -1
  219. package/dist/vocabulary/interactive.js +0 -530
  220. package/dist/vocabulary/interactive.js.map +0 -1
  221. package/dist/vocabulary/layout.d.ts +0 -79
  222. package/dist/vocabulary/layout.d.ts.map +0 -1
  223. package/dist/vocabulary/layout.js +0 -139
  224. package/dist/vocabulary/layout.js.map +0 -1
  225. package/dist/vocabulary/list.d.ts +0 -14
  226. package/dist/vocabulary/list.d.ts.map +0 -1
  227. package/dist/vocabulary/list.js +0 -50
  228. package/dist/vocabulary/list.js.map +0 -1
  229. package/dist/vocabulary/media.d.ts +0 -25
  230. package/dist/vocabulary/media.d.ts.map +0 -1
  231. package/dist/vocabulary/media.js +0 -42
  232. package/dist/vocabulary/media.js.map +0 -1
  233. package/dist/vocabulary/text.d.ts +0 -57
  234. package/dist/vocabulary/text.d.ts.map +0 -1
  235. package/dist/vocabulary/text.js +0 -49
  236. package/dist/vocabulary/text.js.map +0 -1
  237. package/dist/vocabulary/toTextContent.d.ts +0 -2
  238. package/dist/vocabulary/toTextContent.d.ts.map +0 -1
  239. package/dist/vocabulary/toTextContent.js +0 -6
  240. package/dist/vocabulary/toTextContent.js.map +0 -1
  241. package/src/JSONGenerativeUI.client.tsx +0 -168
  242. package/src/JSONGenerativeUI.server.tsx +0 -39
  243. package/src/JSONGenerativeUI.shared.ts +0 -90
  244. package/src/JSONGenerativeUI.test.tsx +0 -1298
  245. package/src/RadioGroupScope.server.test.tsx +0 -24
  246. package/src/RadioGroupScope.tsx +0 -34
  247. package/src/a2ui/BindingContext.ts +0 -26
  248. package/src/a2ui/PresentRenderer.tsx +0 -83
  249. package/src/a2ui/convert.test.ts +0 -2923
  250. package/src/a2ui/convert.ts +0 -1207
  251. package/src/a2ui/dataModel.ts +0 -69
  252. package/src/a2ui/reducer.test.ts +0 -422
  253. package/src/a2ui/reducer.ts +0 -363
  254. package/src/a2ui/snapshot.test.ts +0 -52
  255. package/src/a2ui/snapshot.ts +0 -52
  256. package/src/a2ui/types.ts +0 -114
  257. package/src/a2ui/valueFunctions.test.ts +0 -271
  258. package/src/a2ui/valueFunctions.ts +0 -523
  259. package/src/actionRegistry.test.ts +0 -90
  260. package/src/actionRegistry.ts +0 -88
  261. package/src/answeredValues.test.ts +0 -33
  262. package/src/answeredValues.tsx +0 -70
  263. package/src/buildPresentParameters.test.ts +0 -246
  264. package/src/buildPresentParameters.ts +0 -130
  265. package/src/constants.ts +0 -17
  266. package/src/convert/boundSpec.test.ts +0 -192
  267. package/src/convert/boundSpec.ts +0 -134
  268. package/src/convert/copyBounded.test.ts +0 -131
  269. package/src/convert/copyBounded.ts +0 -38
  270. package/src/convert/isElement.ts +0 -6
  271. package/src/convert/takeRun.test.ts +0 -64
  272. package/src/convert/takeRun.ts +0 -19
  273. package/src/defineGenerativeComponents.ts +0 -38
  274. package/src/fieldReferences.test.ts +0 -66
  275. package/src/fieldReferences.ts +0 -83
  276. package/src/generativeUIToJSX.test.ts +0 -268
  277. package/src/generativeUIToJSX.ts +0 -152
  278. package/src/index.server.test.ts +0 -106
  279. package/src/index.shared.ts +0 -61
  280. package/src/ir.test.ts +0 -203
  281. package/src/renderGenerativeUI.test.tsx +0 -373
  282. package/src/renderGenerativeUI.tsx +0 -165
  283. package/src/scopeSchema.test.ts +0 -72
  284. package/src/scopeSchema.ts +0 -71
  285. package/src/slack/a2uiSlack.test.ts +0 -198
  286. package/src/slack/constants.ts +0 -194
  287. package/src/slack/datePicker.test.ts +0 -612
  288. package/src/slack/decodeBlockAction.test.ts +0 -233
  289. package/src/slack/decodeBlockAction.ts +0 -232
  290. package/src/slack/fromSlackBlocks.test.ts +0 -1465
  291. package/src/slack/fromSlackBlocks.ts +0 -789
  292. package/src/slack/toSlackBlocks.test.ts +0 -3065
  293. package/src/slack/toSlackBlocks.ts +0 -1818
  294. package/src/slack/types.ts +0 -264
  295. package/src/teams/constants.ts +0 -93
  296. package/src/teams/decodeSubmitData.test.ts +0 -397
  297. package/src/teams/decodeSubmitData.ts +0 -110
  298. package/src/teams/temporal.test.ts +0 -766
  299. package/src/teams/temporalId.ts +0 -56
  300. package/src/teams/toAdaptiveCard.test.ts +0 -1897
  301. package/src/teams/toAdaptiveCard.ts +0 -1057
  302. package/src/teams/toTeamsAttachments.test.ts +0 -74
  303. package/src/teams/toTeamsAttachments.ts +0 -133
  304. package/src/teams/types.ts +0 -266
  305. package/src/temporal.test.ts +0 -319
  306. package/src/temporal.ts +0 -259
  307. package/src/types.ts +0 -119
  308. package/src/vocabulary/alert.test.tsx +0 -427
  309. package/src/vocabulary/alert.tsx +0 -217
  310. package/src/vocabulary/collectFormValues.test.ts +0 -389
  311. package/src/vocabulary/collectFormValues.ts +0 -116
  312. package/src/vocabulary/data.test.tsx +0 -858
  313. package/src/vocabulary/data.tsx +0 -819
  314. package/src/vocabulary/datepicker.dom.test.tsx +0 -1148
  315. package/src/vocabulary/dispatch.ts +0 -83
  316. package/src/vocabulary/fact.test.tsx +0 -94
  317. package/src/vocabulary/fact.tsx +0 -54
  318. package/src/vocabulary/form.test.tsx +0 -113
  319. package/src/vocabulary/form.tsx +0 -39
  320. package/src/vocabulary/formatValue.test.ts +0 -72
  321. package/src/vocabulary/formatValue.ts +0 -127
  322. package/src/vocabulary/icon.test.tsx +0 -64
  323. package/src/vocabulary/icon.tsx +0 -174
  324. package/src/vocabulary/index.test.ts +0 -65
  325. package/src/vocabulary/index.ts +0 -33
  326. package/src/vocabulary/interactive.dispatch.test.tsx +0 -454
  327. package/src/vocabulary/interactive.dom.test.tsx +0 -1747
  328. package/src/vocabulary/interactive.test.tsx +0 -377
  329. package/src/vocabulary/interactive.tsx +0 -1048
  330. package/src/vocabulary/layout.test.tsx +0 -323
  331. package/src/vocabulary/layout.tsx +0 -247
  332. package/src/vocabulary/list.test.tsx +0 -222
  333. package/src/vocabulary/list.tsx +0 -50
  334. package/src/vocabulary/media.test.tsx +0 -85
  335. package/src/vocabulary/media.tsx +0 -56
  336. package/src/vocabulary/text.test.tsx +0 -102
  337. package/src/vocabulary/text.tsx +0 -60
  338. package/src/vocabulary/toTextContent.ts +0 -2
@@ -1,377 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { renderToStaticMarkup } from "react-dom/server";
3
- import {
4
- CHECKBOX_GROUP_ATTR,
5
- FIELD_NAME_ATTR,
6
- GENERATED_NAME_ATTR,
7
- } from "../constants";
8
- import { renderGenerativeUI } from "../renderGenerativeUI";
9
- import { interactiveVocabulary } from "./interactive";
10
- import { defaultGenerativeUILibrary } from "./index";
11
-
12
- const render = (node: unknown) =>
13
- renderToStaticMarkup(<>{renderGenerativeUI(node, interactiveVocabulary)}</>);
14
-
15
- describe("interactiveVocabulary", () => {
16
- it("Button renders a button with style/block hooks and the label", () => {
17
- expect(
18
- render({
19
- $type: "Button",
20
- label: "Go",
21
- buttonStyle: "primary",
22
- block: true,
23
- }),
24
- ).toBe(
25
- '<button type="button" data-aui="button" data-aui-style="primary" data-aui-block="true">Go</button>',
26
- );
27
- });
28
-
29
- it("Button omits data-aui-block when block is false or omitted", () => {
30
- expect(render({ $type: "Button", label: "Go", block: false })).toBe(
31
- '<button type="button" data-aui="button">Go</button>',
32
- );
33
- });
34
-
35
- it('Button renders type="button" by default and type="submit" with the submit prop', () => {
36
- expect(render({ $type: "Button", label: "Go" })).toContain('type="button"');
37
- const html = render({ $type: "Button", label: "Go", submit: true });
38
- expect(html).toContain('type="submit"');
39
- expect(html).toContain("data-aui-submit");
40
- });
41
-
42
- it("Button omits data-aui-submit when submit is false or omitted", () => {
43
- expect(
44
- render({ $type: "Button", label: "Go", submit: false }),
45
- ).not.toContain("data-aui-submit");
46
- });
47
-
48
- it("Select renders an aria-label when label is provided", () => {
49
- const html = render({
50
- $type: "Select",
51
- label: "Choose",
52
- options: [{ label: "A", value: "a" }],
53
- });
54
- expect(html).toContain('aria-label="Choose"');
55
- });
56
-
57
- it("Select renders every option when values are duplicated", () => {
58
- const html = render({
59
- $type: "Select",
60
- options: [
61
- { label: "A", value: "x" },
62
- { label: "B", value: "x" },
63
- ],
64
- });
65
- expect(html).toContain('<option value="x">A</option>');
66
- expect(html).toContain('<option value="x">B</option>');
67
- });
68
-
69
- it("Select renders a name attribute when provided", () => {
70
- const html = render({
71
- $type: "Select",
72
- name: "role",
73
- options: [{ label: "A", value: "a" }],
74
- });
75
- expect(html).toContain('name="role"');
76
- });
77
-
78
- it("Button stashes $action on a data-aui-action attribute", () => {
79
- const html = render({
80
- $type: "Button",
81
- label: "Buy",
82
- $action: { type: "purchase", itemId: "sku-1" },
83
- });
84
- expect(html).toContain('data-aui-action="');
85
- expect(html).toContain("&quot;type&quot;:&quot;purchase&quot;");
86
- expect(html).toContain("&quot;itemId&quot;:&quot;sku-1&quot;");
87
- });
88
-
89
- it("Button without $action omits the data-aui-action attribute", () => {
90
- expect(render({ $type: "Button", label: "Go" })).toBe(
91
- '<button type="button" data-aui="button">Go</button>',
92
- );
93
- });
94
-
95
- it("Select renders options with values and a placeholder", () => {
96
- const html = render({
97
- $type: "Select",
98
- placeholder: "Pick one",
99
- options: [
100
- { label: "A", value: "a" },
101
- { label: "B", value: "b" },
102
- ],
103
- });
104
- expect(html).toContain('data-aui="select"');
105
- expect(html).toContain(
106
- 'value="" disabled="" selected="">Pick one</option>',
107
- );
108
- expect(html).toContain('<option value="a">A</option>');
109
- expect(html).toContain('<option value="b">B</option>');
110
- });
111
-
112
- it("Select ignores malformed options instead of throwing", () => {
113
- expect(render({ $type: "Select" })).toBe(
114
- '<select data-aui="select"></select>',
115
- );
116
- expect(render({ $type: "Select", options: "not-an-array" })).toBe(
117
- '<select data-aui="select"></select>',
118
- );
119
- expect(
120
- render({
121
- $type: "Select",
122
- options: [
123
- null,
124
- { label: "Missing value" },
125
- { value: "Missing label" },
126
- { label: "A", value: "a" },
127
- ],
128
- }),
129
- ).toBe('<select data-aui="select"><option value="a">A</option></select>');
130
- });
131
-
132
- it("Input renders a single-line input by default", () => {
133
- expect(render({ $type: "Input", placeholder: "type here" })).toBe(
134
- '<input data-aui="input" placeholder="type here"/>',
135
- );
136
- });
137
-
138
- it("Input renders a name attribute when provided", () => {
139
- expect(render({ $type: "Input", name: "email" })).toContain('name="email"');
140
- });
141
-
142
- it("Input multiline renders a textarea with the multiline hook", () => {
143
- const html = render({ $type: "Input", multiline: true });
144
- expect(html).toContain("data-aui-multiline");
145
- expect(html).toContain("<textarea");
146
- });
147
-
148
- it("DatePicker renders a date input with min/max", () => {
149
- const html = render({
150
- $type: "DatePicker",
151
- value: "2026-01-01",
152
- min: "2025-01-01",
153
- max: "2027-01-01",
154
- });
155
- expect(html).toContain('type="date"');
156
- expect(html).toContain('value="2026-01-01"');
157
- expect(html).toContain('min="2025-01-01"');
158
- expect(html).toContain('max="2027-01-01"');
159
- });
160
-
161
- it("DatePicker renders a name attribute when provided", () => {
162
- expect(render({ $type: "DatePicker", name: "dob" })).toContain(
163
- 'name="dob"',
164
- );
165
- });
166
-
167
- it("Checkbox renders a label wrapping the input and a checkbox-label span", () => {
168
- const html = render({ $type: "Checkbox", label: "Accept terms" });
169
- expect(html).toContain('data-aui="checkbox"');
170
- expect(html).toContain('type="checkbox"');
171
- expect(html).toContain('data-aui="checkbox-label"');
172
- expect(html).toContain("Accept terms");
173
- });
174
-
175
- it("Checkbox renders name and defaultChecked when provided", () => {
176
- const html = render({
177
- $type: "Checkbox",
178
- label: "Accept",
179
- name: "agree",
180
- defaultChecked: true,
181
- });
182
- expect(html).toContain('name="agree"');
183
- expect(html).toContain('checked=""');
184
- });
185
-
186
- it.each([
187
- [
188
- { $type: "Button", label: { unexpected: true } },
189
- '<button type="button" data-aui="button"></button>',
190
- ],
191
- [
192
- {
193
- $type: "Select",
194
- placeholder: { unexpected: true },
195
- options: [],
196
- },
197
- '<select data-aui="select"></select>',
198
- ],
199
- [
200
- { $type: "Checkbox", label: { unexpected: true } },
201
- '<label data-aui="checkbox"><input type="checkbox"/><span data-aui="checkbox-label"></span></label>',
202
- ],
203
- ])("ignores malformed control text properties", (node, expected) => {
204
- expect(render(node)).toBe(expected);
205
- });
206
-
207
- it("RadioGroup renders a fieldset with one radio per option", () => {
208
- const html = render({
209
- $type: "RadioGroup",
210
- options: [
211
- { label: "Small", value: "sm" },
212
- { label: "Large", value: "lg" },
213
- ],
214
- });
215
- expect(html).toContain('data-aui="radiogroup"');
216
- expect((html.match(/type="radio"/g) ?? []).length).toBe(2);
217
- expect(html).toContain('data-aui="radiogroup-option"');
218
- expect(html).toContain("Small");
219
- expect(html).toContain("Large");
220
- });
221
-
222
- it("RadioGroup renders model-provided children after the options inside the fieldset", () => {
223
- const html = renderToStaticMarkup(
224
- <>
225
- {renderGenerativeUI(
226
- {
227
- $type: "RadioGroup",
228
- options: [{ label: "Small", value: "sm" }],
229
- children: { $type: "Text", value: "Additional context" },
230
- },
231
- defaultGenerativeUILibrary,
232
- )}
233
- </>,
234
- );
235
- expect(html).toMatch(
236
- /^<fieldset data-aui="radiogroup">.*data-aui="radiogroup-option".*Small<\/label>.*Additional context.*<\/fieldset>$/,
237
- );
238
- });
239
-
240
- it("RadioGroup renders an aria-label from the label prop", () => {
241
- const html = render({
242
- $type: "RadioGroup",
243
- label: "Size",
244
- options: [{ label: "Small", value: "sm" }],
245
- });
246
- expect(html).toContain('aria-label="Size"');
247
- });
248
-
249
- it("RadioGroup uses a shared native name and preserves the logical field name", () => {
250
- const html = render({
251
- $type: "RadioGroup",
252
- name: "size",
253
- options: [
254
- { label: "Small", value: "sm" },
255
- { label: "Large", value: "lg" },
256
- ],
257
- });
258
- const names = [...html.matchAll(/ name="([^"]*)"/g)].map((m) => m[1]);
259
- expect(names).toHaveLength(2);
260
- expect(names[0]).toBe(names[1]);
261
- expect(names[0]).not.toBe("size");
262
- expect(html.split(`${FIELD_NAME_ATTR}="size"`).length - 1).toBe(2);
263
- expect(html).not.toContain(GENERATED_NAME_ATTR);
264
- });
265
-
266
- it("RadioGroup falls back to a generated shared name when name is omitted", () => {
267
- const html = render({
268
- $type: "RadioGroup",
269
- options: [
270
- { label: "Small", value: "sm" },
271
- { label: "Large", value: "lg" },
272
- ],
273
- });
274
- const names = [...html.matchAll(/ name="([^"]*)"/g)].map((m) => m[1]);
275
- expect(names.length).toBe(2);
276
- expect(names[0]).toBe(names[1]);
277
- expect(names[0]).toBeTruthy();
278
- expect(html.split(`${GENERATED_NAME_ATTR}=""`).length - 1).toBe(2);
279
- });
280
-
281
- it("RadioGroup marks a generated shared name when name is null", () => {
282
- const html = render({
283
- $type: "RadioGroup",
284
- name: null,
285
- options: [{ label: "Small", value: "sm" }],
286
- });
287
-
288
- expect(html).toContain(`${GENERATED_NAME_ATTR}=""`);
289
- });
290
-
291
- it("RadioGroup marks the option matching defaultValue as checked", () => {
292
- const html = render({
293
- $type: "RadioGroup",
294
- defaultValue: "lg",
295
- options: [
296
- { label: "Small", value: "sm" },
297
- { label: "Large", value: "lg" },
298
- ],
299
- });
300
- expect(html.match(/checked=""/g)?.length).toBe(1);
301
- });
302
-
303
- it("RadioGroup renders nothing for malformed entries without throwing", () => {
304
- expect(() =>
305
- render({
306
- $type: "RadioGroup",
307
- options: [
308
- { label: "Small", value: "sm" },
309
- null,
310
- { value: "no-label" },
311
- { label: "no-value" },
312
- "not-an-object",
313
- ],
314
- }),
315
- ).not.toThrow();
316
- const html = render({
317
- $type: "RadioGroup",
318
- options: [{ label: "Small", value: "sm" }, null],
319
- });
320
- expect((html.match(/type="radio"/g) ?? []).length).toBe(1);
321
- });
322
-
323
- it("RadioGroup with missing options renders an empty fieldset without throwing", () => {
324
- expect(() => render({ $type: "RadioGroup" })).not.toThrow();
325
- expect(render({ $type: "RadioGroup" })).toBe(
326
- '<fieldset data-aui="radiogroup"></fieldset>',
327
- );
328
- });
329
-
330
- it("CheckboxGroup renders one named checkbox per option and checks each defaultValue", () => {
331
- const html = render({
332
- $type: "CheckboxGroup",
333
- name: "toppings",
334
- label: "Toppings",
335
- defaultValue: ["olives"],
336
- options: [
337
- { label: "Basil", value: "basil" },
338
- null,
339
- { label: "Olives", value: "olives" },
340
- ],
341
- });
342
- const inputs = html.match(/<input[^>]*>/g) ?? [];
343
- expect(html).toMatch(
344
- /^<fieldset data-aui="checkboxgroup" aria-label="Toppings">.*Basil<\/label>.*Olives<\/label><\/fieldset>$/,
345
- );
346
- expect(inputs).toHaveLength(2);
347
- for (const input of inputs) {
348
- expect(input).toContain('type="checkbox"');
349
- expect(input).toContain('name="toppings"');
350
- expect(input).toContain(`${CHECKBOX_GROUP_ATTR}=""`);
351
- }
352
- expect(inputs.filter((input) => input.includes('checked=""'))).toEqual([
353
- expect.stringContaining('value="olives"'),
354
- ]);
355
- });
356
-
357
- it("CheckboxGroup falls back to a generated shared name when name is omitted", () => {
358
- const html = render({
359
- $type: "CheckboxGroup",
360
- options: [
361
- { label: "Basil", value: "basil" },
362
- { label: "Olives", value: "olives" },
363
- ],
364
- });
365
- const names = [...html.matchAll(/ name="([^"]*)"/g)].map((m) => m[1]);
366
- expect(names.length).toBe(2);
367
- expect(names[0]).toBeTruthy();
368
- expect(names[0]).toBe(names[1]);
369
- expect(html.split(`${GENERATED_NAME_ATTR}=""`).length - 1).toBe(2);
370
- });
371
-
372
- it("CheckboxGroup with missing options renders an empty fieldset without throwing", () => {
373
- expect(render({ $type: "CheckboxGroup" })).toBe(
374
- '<fieldset data-aui="checkboxgroup"></fieldset>',
375
- );
376
- });
377
- });