@assistant-ui/react-generative-ui 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/JSONGenerativeUI.client.d.ts +1 -2
- package/dist/JSONGenerativeUI.client.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.server.d.ts +1 -2
- package/dist/JSONGenerativeUI.server.d.ts.map +1 -1
- package/dist/JSONGenerativeUI.shared.d.ts +8 -9
- package/dist/JSONGenerativeUI.shared.d.ts.map +1 -1
- package/dist/a2ui/convert.d.ts +1 -2
- package/dist/a2ui/convert.d.ts.map +1 -1
- package/dist/a2ui/convert.js +11 -2
- package/dist/a2ui/convert.js.map +1 -1
- package/dist/a2ui/reducer.d.ts +1 -2
- package/dist/a2ui/reducer.d.ts.map +1 -1
- package/dist/a2ui/reducer.js +63 -10
- package/dist/a2ui/reducer.js.map +1 -1
- package/dist/a2ui/types.d.ts +17 -18
- package/dist/a2ui/types.d.ts.map +1 -1
- package/dist/actionRegistry.d.ts +5 -6
- package/dist/actionRegistry.d.ts.map +1 -1
- package/dist/buildPresentParameters.d.ts +2 -3
- package/dist/buildPresentParameters.d.ts.map +1 -1
- package/dist/buildPresentParameters.js +4 -3
- package/dist/buildPresentParameters.js.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/constants.js.map +1 -1
- package/dist/convert/boundSpec.d.ts +7 -8
- package/dist/convert/boundSpec.d.ts.map +1 -1
- package/dist/convert/copyBounded.d.ts +1 -2
- package/dist/convert/copyBounded.d.ts.map +1 -1
- package/dist/convert/isElement.d.ts +1 -2
- package/dist/convert/isElement.d.ts.map +1 -1
- package/dist/convert/takeRun.d.ts +1 -2
- package/dist/convert/takeRun.d.ts.map +1 -1
- package/dist/defineGenerativeComponents.d.ts +1 -2
- package/dist/defineGenerativeComponents.d.ts.map +1 -1
- package/dist/generativeUIToJSX.d.ts +2 -3
- package/dist/generativeUIToJSX.d.ts.map +1 -1
- package/dist/ir.d.ts +28 -29
- package/dist/ir.d.ts.map +1 -1
- package/dist/renderGenerativeUI.d.ts +1 -2
- package/dist/renderGenerativeUI.d.ts.map +1 -1
- package/dist/renderGenerativeUI.js +1 -1
- package/dist/renderGenerativeUI.js.map +1 -1
- package/dist/slack/constants.d.ts +35 -36
- package/dist/slack/constants.d.ts.map +1 -1
- package/dist/slack/decodeBlockAction.d.ts +1 -2
- package/dist/slack/decodeBlockAction.d.ts.map +1 -1
- package/dist/slack/fromSlackBlocks.d.ts +1 -2
- package/dist/slack/fromSlackBlocks.d.ts.map +1 -1
- package/dist/slack/toSlackBlocks.d.ts +1 -2
- package/dist/slack/toSlackBlocks.d.ts.map +1 -1
- package/dist/slack/types.d.ts +32 -33
- package/dist/slack/types.d.ts.map +1 -1
- package/dist/teams/constants.d.ts +14 -15
- package/dist/teams/constants.d.ts.map +1 -1
- package/dist/teams/decodeSubmitData.d.ts +1 -2
- package/dist/teams/decodeSubmitData.d.ts.map +1 -1
- package/dist/teams/toAdaptiveCard.d.ts +6 -7
- package/dist/teams/toAdaptiveCard.d.ts.map +1 -1
- package/dist/teams/toTeamsAttachments.d.ts +1 -2
- package/dist/teams/toTeamsAttachments.d.ts.map +1 -1
- package/dist/teams/types.d.ts +29 -30
- package/dist/teams/types.d.ts.map +1 -1
- package/dist/types.d.ts +9 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/vocabulary/alert.d.ts +2 -3
- package/dist/vocabulary/alert.d.ts.map +1 -1
- package/dist/vocabulary/alert.js +21 -16
- package/dist/vocabulary/alert.js.map +1 -1
- package/dist/vocabulary/collectFormValues.d.ts +6 -5
- package/dist/vocabulary/collectFormValues.d.ts.map +1 -1
- package/dist/vocabulary/collectFormValues.js +3 -2
- package/dist/vocabulary/collectFormValues.js.map +1 -1
- package/dist/vocabulary/data.d.ts +1 -2
- package/dist/vocabulary/data.d.ts.map +1 -1
- package/dist/vocabulary/data.js +20 -12
- package/dist/vocabulary/data.js.map +1 -1
- package/dist/vocabulary/dispatch.d.ts +2 -3
- package/dist/vocabulary/dispatch.d.ts.map +1 -1
- package/dist/vocabulary/fact.d.ts +1 -2
- package/dist/vocabulary/fact.d.ts.map +1 -1
- package/dist/vocabulary/fact.js +3 -2
- package/dist/vocabulary/fact.js.map +1 -1
- package/dist/vocabulary/form.d.ts +1 -2
- package/dist/vocabulary/form.d.ts.map +1 -1
- package/dist/vocabulary/icon.d.ts +1 -2
- package/dist/vocabulary/icon.d.ts.map +1 -1
- package/dist/vocabulary/index.d.ts +1 -2
- package/dist/vocabulary/index.d.ts.map +1 -1
- package/dist/vocabulary/interactive.d.ts +10 -9
- package/dist/vocabulary/interactive.d.ts.map +1 -1
- package/dist/vocabulary/interactive.js +30 -23
- package/dist/vocabulary/interactive.js.map +1 -1
- package/dist/vocabulary/layout.d.ts +1 -2
- package/dist/vocabulary/layout.d.ts.map +1 -1
- package/dist/vocabulary/layout.js +7 -5
- package/dist/vocabulary/layout.js.map +1 -1
- package/dist/vocabulary/list.d.ts +1 -2
- package/dist/vocabulary/list.d.ts.map +1 -1
- package/dist/vocabulary/media.d.ts +1 -2
- package/dist/vocabulary/media.d.ts.map +1 -1
- package/dist/vocabulary/text.d.ts +2 -3
- package/dist/vocabulary/text.d.ts.map +1 -1
- package/dist/vocabulary/text.js +4 -3
- package/dist/vocabulary/text.js.map +1 -1
- package/dist/vocabulary/toTextContent.d.ts +4 -0
- package/dist/vocabulary/toTextContent.d.ts.map +1 -0
- package/dist/vocabulary/toTextContent.js +6 -0
- package/dist/vocabulary/toTextContent.js.map +1 -0
- package/package.json +12 -10
- package/src/a2ui/convert.test.ts +36 -0
- package/src/a2ui/convert.ts +21 -2
- package/src/a2ui/reducer.test.ts +223 -0
- package/src/a2ui/reducer.ts +76 -12
- package/src/buildPresentParameters.ts +7 -4
- package/src/constants.ts +2 -0
- package/src/renderGenerativeUI.test.tsx +57 -0
- package/src/renderGenerativeUI.tsx +3 -1
- package/src/slack/fromSlackBlocks.test.ts +4 -1
- package/src/slack/toSlackBlocks.test.ts +8 -4
- package/src/teams/toAdaptiveCard.test.ts +5 -3
- package/src/vocabulary/alert.test.tsx +10 -0
- package/src/vocabulary/alert.tsx +16 -7
- package/src/vocabulary/collectFormValues.test.ts +38 -0
- package/src/vocabulary/collectFormValues.ts +11 -2
- package/src/vocabulary/data.test.tsx +40 -0
- package/src/vocabulary/data.tsx +47 -26
- package/src/vocabulary/fact.test.tsx +12 -0
- package/src/vocabulary/fact.tsx +3 -2
- package/src/vocabulary/form.test.tsx +1 -0
- package/src/vocabulary/interactive.test.tsx +55 -1
- package/src/vocabulary/interactive.tsx +50 -29
- package/src/vocabulary/layout.test.tsx +17 -0
- package/src/vocabulary/layout.tsx +8 -4
- package/src/vocabulary/list.test.tsx +5 -4
- package/src/vocabulary/text.test.tsx +29 -0
- package/src/vocabulary/text.tsx +4 -3
- package/src/vocabulary/toTextContent.ts +2 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +0 -141
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +0 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { GENERATED_NAME_ATTR } from "../constants.js";
|
|
1
2
|
import { BUTTON_STYLES } from "../ir.js";
|
|
3
|
+
import { toTextContent } from "./toTextContent.js";
|
|
2
4
|
import { actionAttr, fire } from "./dispatch.js";
|
|
3
5
|
import { useId } from "react";
|
|
4
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -8,6 +10,7 @@ const optionSchema = z.object({
|
|
|
8
10
|
label: z.string(),
|
|
9
11
|
value: z.string()
|
|
10
12
|
});
|
|
13
|
+
const isOption = (option) => option !== null && typeof option === "object" && "label" in option && typeof option.label === "string" && "value" in option && typeof option.value === "string";
|
|
11
14
|
function RadioGroupRender({ options, name, label, defaultValue, $action, $dispatch }) {
|
|
12
15
|
const generatedName = useId();
|
|
13
16
|
const fieldName = name ?? generatedName;
|
|
@@ -16,11 +19,12 @@ function RadioGroupRender({ options, name, label, defaultValue, $action, $dispat
|
|
|
16
19
|
"data-aui": "radiogroup",
|
|
17
20
|
"data-aui-action": actionAttr($action),
|
|
18
21
|
"aria-label": label,
|
|
19
|
-
children: safeOptions.map((option, i) => option
|
|
22
|
+
children: safeOptions.map((option, i) => isOption(option) ? /* @__PURE__ */ jsxs("label", {
|
|
20
23
|
"data-aui": "radiogroup-option",
|
|
21
24
|
children: [/* @__PURE__ */ jsx("input", {
|
|
22
25
|
type: "radio",
|
|
23
26
|
name: fieldName,
|
|
27
|
+
...name == null ? { [GENERATED_NAME_ATTR]: "" } : {},
|
|
24
28
|
value: option.value,
|
|
25
29
|
defaultChecked: defaultValue === option.value,
|
|
26
30
|
onChange: () => fire($action, $dispatch, option.value)
|
|
@@ -45,7 +49,7 @@ const interactiveVocabulary = {
|
|
|
45
49
|
"data-aui-submit": submit || void 0,
|
|
46
50
|
"data-aui-action": actionAttr($action),
|
|
47
51
|
onClick: submit ? void 0 : () => fire($action, $dispatch),
|
|
48
|
-
children: [label, children]
|
|
52
|
+
children: [toTextContent(label), children]
|
|
49
53
|
})
|
|
50
54
|
},
|
|
51
55
|
Select: {
|
|
@@ -56,26 +60,29 @@ const interactiveVocabulary = {
|
|
|
56
60
|
label: z.string().optional().describe("Accessible label for the control."),
|
|
57
61
|
name: z.string().optional().describe("Field name used inside a Form.")
|
|
58
62
|
}),
|
|
59
|
-
render: ({ options, placeholder, label, name, $action, $dispatch, children }) =>
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
63
|
+
render: ({ options, placeholder, label, name, $action, $dispatch, children }) => {
|
|
64
|
+
const placeholderText = toTextContent(placeholder);
|
|
65
|
+
return /* @__PURE__ */ jsxs("select", {
|
|
66
|
+
"data-aui": "select",
|
|
67
|
+
"data-aui-action": actionAttr($action),
|
|
68
|
+
name,
|
|
69
|
+
"aria-label": label,
|
|
70
|
+
defaultValue: "",
|
|
71
|
+
onChange: (e) => fire($action, $dispatch, e.currentTarget.value),
|
|
72
|
+
children: [
|
|
73
|
+
placeholderText ? /* @__PURE__ */ jsx("option", {
|
|
74
|
+
value: "",
|
|
75
|
+
disabled: true,
|
|
76
|
+
children: placeholderText
|
|
77
|
+
}) : null,
|
|
78
|
+
(Array.isArray(options) ? options : []).map((option, i) => isOption(option) ? /* @__PURE__ */ jsx("option", {
|
|
79
|
+
value: option.value,
|
|
80
|
+
children: option.label
|
|
81
|
+
}, i) : null),
|
|
82
|
+
children
|
|
83
|
+
]
|
|
84
|
+
});
|
|
85
|
+
}
|
|
79
86
|
},
|
|
80
87
|
Input: {
|
|
81
88
|
description: "A text input. Carries `$action` describing the on-submit behavior.",
|
|
@@ -151,7 +158,7 @@ const interactiveVocabulary = {
|
|
|
151
158
|
onChange: (e) => fire($action, $dispatch, e.currentTarget.checked)
|
|
152
159
|
}), /* @__PURE__ */ jsx("span", {
|
|
153
160
|
"data-aui": "checkbox-label",
|
|
154
|
-
children: label
|
|
161
|
+
children: toTextContent(label)
|
|
155
162
|
})]
|
|
156
163
|
})
|
|
157
164
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive.js","names":[],"sources":["../../src/vocabulary/interactive.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport { z } from \"zod\";\nimport type { Action } from \"../ir\";\nimport { BUTTON_STYLES } from \"../ir\";\nimport type { GenerativeUIDispatch, GenerativeUILibrary } from \"../types\";\nimport { actionAttr, fire } from \"./dispatch\";\n\nconst optionSchema = z.object({\n label: z.string(),\n value: z.string(),\n});\n\ntype RadioGroupRenderProps = {\n options: { label: string; value: string }[];\n name?: string;\n label?: string;\n defaultValue?: string;\n $action?: Action;\n $dispatch?: GenerativeUIDispatch;\n};\n\nfunction RadioGroupRender({\n options,\n name,\n label,\n defaultValue,\n $action,\n $dispatch,\n}: RadioGroupRenderProps) {\n const generatedName = useId();\n const fieldName = name ?? generatedName;\n const safeOptions = Array.isArray(options) ? options : [];\n return (\n <fieldset\n data-aui=\"radiogroup\"\n data-aui-action={actionAttr($action)}\n aria-label={label}\n >\n {safeOptions.map((option, i) =>\n option &&\n typeof option.label === \"string\" &&\n typeof option.value === \"string\" ? (\n <label key={i} data-aui=\"radiogroup-option\">\n <input\n type=\"radio\"\n name={fieldName}\n value={option.value}\n defaultChecked={defaultValue === option.value}\n onChange={() => fire($action, $dispatch, option.value)}\n />\n {option.label}\n </label>\n ) : null,\n )}\n </fieldset>\n );\n}\n\nexport const interactiveVocabulary = {\n Button: {\n description:\n \"A clickable button. Carries `$action` describing the side effect or resume value. Set `submit` to submit an ancestor Form/Card instead of firing `$action` on click.\",\n properties: z.object({\n label: z.string().describe(\"Button label.\"),\n buttonStyle: z.enum(BUTTON_STYLES).optional().describe(\"Visual style.\"),\n block: z\n .boolean()\n .optional()\n .describe(\"Whether the button spans the full width.\"),\n submit: z\n .boolean()\n .optional()\n .describe(\n \"Render as a submit button for an ancestor Form/Card instead of a click button.\",\n ),\n }),\n render: ({\n label,\n buttonStyle,\n block,\n submit,\n $action,\n $dispatch,\n children,\n }) => (\n <button\n type={submit ? \"submit\" : \"button\"}\n data-aui=\"button\"\n data-aui-style={buttonStyle}\n data-aui-block={block || undefined}\n data-aui-submit={submit || undefined}\n data-aui-action={actionAttr($action)}\n onClick={submit ? undefined : () => fire($action, $dispatch)}\n >\n {label}\n {children}\n </button>\n ),\n },\n Select: {\n description:\n \"A dropdown selector. Carries `$action` describing the on-select behavior.\",\n properties: z.object({\n options: z.array(optionSchema).describe(\"Selectable options.\"),\n placeholder: z\n .string()\n .optional()\n .describe(\"Placeholder shown when nothing is selected.\"),\n label: z\n .string()\n .optional()\n .describe(\"Accessible label for the control.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n }),\n render: ({\n options,\n placeholder,\n label,\n name,\n $action,\n $dispatch,\n children,\n }) => (\n <select\n data-aui=\"select\"\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n defaultValue=\"\"\n onChange={(e) => fire($action, $dispatch, e.currentTarget.value)}\n >\n {placeholder ? (\n <option value=\"\" disabled>\n {placeholder}\n </option>\n ) : null}\n {options.map((o: { label: string; value: string }, i: number) => (\n <option key={i} value={o.value}>\n {o.label}\n </option>\n ))}\n {children}\n </select>\n ),\n },\n Input: {\n description:\n \"A text input. Carries `$action` describing the on-submit behavior.\",\n properties: z.object({\n placeholder: z.string().optional().describe(\"Placeholder text.\"),\n multiline: z\n .boolean()\n .optional()\n .describe(\"Render a textarea instead of a single-line input.\"),\n label: z\n .string()\n .optional()\n .describe(\"Accessible label for the control.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n }),\n render: ({ placeholder, multiline, label, name, $action, $dispatch }) => {\n const submit = (v: string) => fire($action, $dispatch, v);\n return multiline ? (\n <textarea\n data-aui=\"input\"\n data-aui-multiline\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n placeholder={placeholder}\n onKeyDown={(e) => {\n if (\n e.key !== \"Enter\" ||\n !(e.ctrlKey || e.metaKey) ||\n e.nativeEvent.isComposing\n )\n return;\n if (e.currentTarget.form) {\n e.preventDefault();\n HTMLFormElement.prototype.requestSubmit.call(\n e.currentTarget.form,\n );\n } else {\n submit(e.currentTarget.value);\n }\n }}\n />\n ) : (\n <input\n data-aui=\"input\"\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n placeholder={placeholder}\n onKeyDown={(e) => {\n if (\n e.key === \"Enter\" &&\n !e.nativeEvent.isComposing &&\n !e.currentTarget.form\n )\n submit(e.currentTarget.value);\n }}\n />\n );\n },\n },\n DatePicker: {\n description:\n \"A date input. Carries `$action` describing the on-select behavior.\",\n properties: z.object({\n value: z.string().optional().describe(\"Initial date (YYYY-MM-DD).\"),\n min: z.string().optional().describe(\"Minimum date (YYYY-MM-DD).\"),\n max: z.string().optional().describe(\"Maximum date (YYYY-MM-DD).\"),\n label: z\n .string()\n .optional()\n .describe(\"Accessible label for the control.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n }),\n render: ({ value, min, max, label, name, $action, $dispatch }) => (\n <input\n type=\"date\"\n data-aui=\"datepicker\"\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n defaultValue={value}\n min={min}\n max={max}\n onChange={(e) => fire($action, $dispatch, e.currentTarget.value)}\n />\n ),\n },\n Checkbox: {\n description:\n \"A checkbox with a label. Carries `$action` describing the on-change behavior.\",\n properties: z.object({\n label: z.string().describe(\"Label text next to the checkbox.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n defaultChecked: z\n .boolean()\n .optional()\n .describe(\"Whether the checkbox starts checked.\"),\n }),\n render: ({ label, name, defaultChecked, $action, $dispatch }) => (\n <label data-aui=\"checkbox\">\n <input\n type=\"checkbox\"\n data-aui-action={actionAttr($action)}\n name={name}\n defaultChecked={defaultChecked}\n onChange={(e) => fire($action, $dispatch, e.currentTarget.checked)}\n />\n <span data-aui=\"checkbox-label\">{label}</span>\n </label>\n ),\n },\n RadioGroup: {\n description:\n \"A group of mutually exclusive radio options. Carries `$action` describing the on-change behavior.\",\n properties: z.object({\n options: z.array(optionSchema).describe(\"Selectable options.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n label: z.string().optional().describe(\"Accessible name for the group.\"),\n defaultValue: z.string().optional().describe(\"Initially selected value.\"),\n }),\n render: RadioGroupRender,\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"interactive.js","names":[],"sources":["../../src/vocabulary/interactive.tsx"],"sourcesContent":["import { useId } from \"react\";\nimport { z } from \"zod\";\nimport { GENERATED_NAME_ATTR } from \"../constants\";\nimport type { Action } from \"../ir\";\nimport { BUTTON_STYLES } from \"../ir\";\nimport type {\n GenerativeUIDispatch,\n GenerativeUILibrary,\n GenerativeUIStatus,\n} from \"../types\";\nimport { actionAttr, fire } from \"./dispatch\";\nimport { toTextContent } from \"./toTextContent\";\n\nconst optionSchema = z.object({\n label: z.string(),\n value: z.string(),\n});\n\ntype Option = { label: string; value: string };\n\nconst isOption = (option: unknown): option is Option =>\n option !== null &&\n typeof option === \"object\" &&\n \"label\" in option &&\n typeof option.label === \"string\" &&\n \"value\" in option &&\n typeof option.value === \"string\";\n\ntype RadioGroupRenderProps = {\n options: Option[];\n name?: string;\n label?: string;\n defaultValue?: string;\n $status: GenerativeUIStatus;\n $action?: Action;\n $dispatch?: GenerativeUIDispatch;\n};\n\nfunction RadioGroupRender({\n options,\n name,\n label,\n defaultValue,\n $action,\n $dispatch,\n}: RadioGroupRenderProps) {\n const generatedName = useId();\n const fieldName = name ?? generatedName;\n const safeOptions = Array.isArray(options) ? options : [];\n return (\n <fieldset\n data-aui=\"radiogroup\"\n data-aui-action={actionAttr($action)}\n aria-label={label}\n >\n {safeOptions.map((option, i) =>\n isOption(option) ? (\n <label key={i} data-aui=\"radiogroup-option\">\n <input\n type=\"radio\"\n name={fieldName}\n {...(name == null ? { [GENERATED_NAME_ATTR]: \"\" } : {})}\n value={option.value}\n defaultChecked={defaultValue === option.value}\n onChange={() => fire($action, $dispatch, option.value)}\n />\n {option.label}\n </label>\n ) : null,\n )}\n </fieldset>\n );\n}\n\nexport const interactiveVocabulary = {\n Button: {\n description:\n \"A clickable button. Carries `$action` describing the side effect or resume value. Set `submit` to submit an ancestor Form/Card instead of firing `$action` on click.\",\n properties: z.object({\n label: z.string().describe(\"Button label.\"),\n buttonStyle: z.enum(BUTTON_STYLES).optional().describe(\"Visual style.\"),\n block: z\n .boolean()\n .optional()\n .describe(\"Whether the button spans the full width.\"),\n submit: z\n .boolean()\n .optional()\n .describe(\n \"Render as a submit button for an ancestor Form/Card instead of a click button.\",\n ),\n }),\n render: ({\n label,\n buttonStyle,\n block,\n submit,\n $action,\n $dispatch,\n children,\n }) => (\n <button\n type={submit ? \"submit\" : \"button\"}\n data-aui=\"button\"\n data-aui-style={buttonStyle}\n data-aui-block={block || undefined}\n data-aui-submit={submit || undefined}\n data-aui-action={actionAttr($action)}\n onClick={submit ? undefined : () => fire($action, $dispatch)}\n >\n {toTextContent(label)}\n {children}\n </button>\n ),\n },\n Select: {\n description:\n \"A dropdown selector. Carries `$action` describing the on-select behavior.\",\n properties: z.object({\n options: z.array(optionSchema).describe(\"Selectable options.\"),\n placeholder: z\n .string()\n .optional()\n .describe(\"Placeholder shown when nothing is selected.\"),\n label: z\n .string()\n .optional()\n .describe(\"Accessible label for the control.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n }),\n render: ({\n options,\n placeholder,\n label,\n name,\n $action,\n $dispatch,\n children,\n }) => {\n const placeholderText = toTextContent(placeholder);\n return (\n <select\n data-aui=\"select\"\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n defaultValue=\"\"\n onChange={(e) => fire($action, $dispatch, e.currentTarget.value)}\n >\n {placeholderText ? (\n <option value=\"\" disabled>\n {placeholderText}\n </option>\n ) : null}\n {(Array.isArray(options) ? options : []).map((option, i) =>\n isOption(option) ? (\n <option key={i} value={option.value}>\n {option.label}\n </option>\n ) : null,\n )}\n {children}\n </select>\n );\n },\n },\n Input: {\n description:\n \"A text input. Carries `$action` describing the on-submit behavior.\",\n properties: z.object({\n placeholder: z.string().optional().describe(\"Placeholder text.\"),\n multiline: z\n .boolean()\n .optional()\n .describe(\"Render a textarea instead of a single-line input.\"),\n label: z\n .string()\n .optional()\n .describe(\"Accessible label for the control.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n }),\n render: ({ placeholder, multiline, label, name, $action, $dispatch }) => {\n const submit = (v: string) => fire($action, $dispatch, v);\n return multiline ? (\n <textarea\n data-aui=\"input\"\n data-aui-multiline\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n placeholder={placeholder}\n onKeyDown={(e) => {\n if (\n e.key !== \"Enter\" ||\n !(e.ctrlKey || e.metaKey) ||\n e.nativeEvent.isComposing\n )\n return;\n if (e.currentTarget.form) {\n e.preventDefault();\n HTMLFormElement.prototype.requestSubmit.call(\n e.currentTarget.form,\n );\n } else {\n submit(e.currentTarget.value);\n }\n }}\n />\n ) : (\n <input\n data-aui=\"input\"\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n placeholder={placeholder}\n onKeyDown={(e) => {\n if (\n e.key === \"Enter\" &&\n !e.nativeEvent.isComposing &&\n !e.currentTarget.form\n )\n submit(e.currentTarget.value);\n }}\n />\n );\n },\n },\n DatePicker: {\n description:\n \"A date input. Carries `$action` describing the on-select behavior.\",\n properties: z.object({\n value: z.string().optional().describe(\"Initial date (YYYY-MM-DD).\"),\n min: z.string().optional().describe(\"Minimum date (YYYY-MM-DD).\"),\n max: z.string().optional().describe(\"Maximum date (YYYY-MM-DD).\"),\n label: z\n .string()\n .optional()\n .describe(\"Accessible label for the control.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n }),\n render: ({ value, min, max, label, name, $action, $dispatch }) => (\n <input\n type=\"date\"\n data-aui=\"datepicker\"\n data-aui-action={actionAttr($action)}\n name={name}\n aria-label={label}\n defaultValue={value}\n min={min}\n max={max}\n onChange={(e) => fire($action, $dispatch, e.currentTarget.value)}\n />\n ),\n },\n Checkbox: {\n description:\n \"A checkbox with a label. Carries `$action` describing the on-change behavior.\",\n properties: z.object({\n label: z.string().describe(\"Label text next to the checkbox.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n defaultChecked: z\n .boolean()\n .optional()\n .describe(\"Whether the checkbox starts checked.\"),\n }),\n render: ({ label, name, defaultChecked, $action, $dispatch }) => (\n <label data-aui=\"checkbox\">\n <input\n type=\"checkbox\"\n data-aui-action={actionAttr($action)}\n name={name}\n defaultChecked={defaultChecked}\n onChange={(e) => fire($action, $dispatch, e.currentTarget.checked)}\n />\n <span data-aui=\"checkbox-label\">{toTextContent(label)}</span>\n </label>\n ),\n },\n RadioGroup: {\n description:\n \"A group of mutually exclusive radio options. Carries `$action` describing the on-change behavior.\",\n properties: z.object({\n options: z.array(optionSchema).describe(\"Selectable options.\"),\n name: z.string().optional().describe(\"Field name used inside a Form.\"),\n label: z.string().optional().describe(\"Accessible name for the group.\"),\n defaultValue: z.string().optional().describe(\"Initially selected value.\"),\n }),\n render: RadioGroupRender,\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":";;;;;;;;AAaA,MAAM,eAAe,EAAE,OAAO;CAC5B,OAAO,EAAE,OAAO;CAChB,OAAO,EAAE,OAAO;AAClB,CAAC;AAID,MAAM,YAAY,WAChB,WAAW,QACX,OAAO,WAAW,YAClB,WAAW,UACX,OAAO,OAAO,UAAU,YACxB,WAAW,UACX,OAAO,OAAO,UAAU;AAY1B,SAAS,iBAAiB,EACxB,SACA,MACA,OACA,cACA,SACA,aACwB;CACxB,MAAM,gBAAgB,MAAM;CAC5B,MAAM,YAAY,QAAQ;CAC1B,MAAM,cAAc,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC;CACxD,OACE,oBAAC,YAAD;EACE,YAAS;EACT,mBAAiB,WAAW,OAAO;EACnC,cAAY;EAEX,UAAA,YAAY,KAAK,QAAQ,MACxB,SAAS,MAAM,IACb,qBAAC,SAAD;GAAe,YAAS;GAAxB,UAAA,CACE,oBAAC,SAAD;IACE,MAAK;IACL,MAAM;IACN,GAAK,QAAQ,OAAO,GAAG,sBAAsB,GAAG,IAAI,CAAC;IACrD,OAAO,OAAO;IACd,gBAAgB,iBAAiB,OAAO;IACxC,gBAAgB,KAAK,SAAS,WAAW,OAAO,KAAK;GACtD,CAAA,GACA,OAAO,KACH;EAVK,GAAA,CAUL,IACL,IACN;CACQ,CAAA;AAEd;AAEA,MAAa,wBAAwB;CACnC,QAAQ;EACN,aACE;EACF,YAAY,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,eAAe;GAC1C,aAAa,EAAE,KAAK,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,eAAe;GACtE,OAAO,EACJ,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SAAS,0CAA0C;GACtD,QAAQ,EACL,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SACC,gFACF;EACJ,CAAC;EACD,SAAS,EACP,OACA,aACA,OACA,QACA,SACA,WACA,eAEA,qBAAC,UAAD;GACE,MAAM,SAAS,WAAW;GAC1B,YAAS;GACT,kBAAgB;GAChB,kBAAgB,SAAS,KAAA;GACzB,mBAAiB,UAAU,KAAA;GAC3B,mBAAiB,WAAW,OAAO;GACnC,SAAS,SAAS,KAAA,UAAkB,KAAK,SAAS,SAAS;GAP7D,UAAA,CASG,cAAc,KAAK,GACnB,QACK;;CAEZ;CACA,QAAQ;EACN,aACE;EACF,YAAY,EAAE,OAAO;GACnB,SAAS,EAAE,MAAM,YAAY,CAAC,CAAC,SAAS,qBAAqB;GAC7D,aAAa,EACV,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,6CAA6C;GACzD,OAAO,EACJ,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,mCAAmC;GAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gCAAgC;EACvE,CAAC;EACD,SAAS,EACP,SACA,aACA,OACA,MACA,SACA,WACA,eACI;GACJ,MAAM,kBAAkB,cAAc,WAAW;GACjD,OACE,qBAAC,UAAD;IACE,YAAS;IACT,mBAAiB,WAAW,OAAO;IAC7B;IACN,cAAY;IACZ,cAAa;IACb,WAAW,MAAM,KAAK,SAAS,WAAW,EAAE,cAAc,KAAK;IANjE,UAAA;KAQG,kBACC,oBAAC,UAAD;MAAQ,OAAM;MAAG,UAAA;MACd,UAAA;KACK,CAAA,IACN;MACF,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,EAAA,CAAG,KAAK,QAAQ,MACpD,SAAS,MAAM,IACb,oBAAC,UAAD;MAAgB,OAAO,OAAO;MAC3B,UAAA,OAAO;KACF,GAFK,CAEL,IACN,IACN;KACC;IACK;;EAEZ;CACF;CACA,OAAO;EACL,aACE;EACF,YAAY,EAAE,OAAO;GACnB,aAAa,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,mBAAmB;GAC/D,WAAW,EACR,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SAAS,mDAAmD;GAC/D,OAAO,EACJ,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,mCAAmC;GAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gCAAgC;EACvE,CAAC;EACD,SAAS,EAAE,aAAa,WAAW,OAAO,MAAM,SAAS,gBAAgB;GACvE,MAAM,UAAU,MAAc,KAAK,SAAS,WAAW,CAAC;GACxD,OAAO,YACL,oBAAC,YAAD;IACE,YAAS;IACT,sBAAA;IACA,mBAAiB,WAAW,OAAO;IAC7B;IACN,cAAY;IACC;IACb,YAAY,MAAM;KAChB,IACE,EAAE,QAAQ,WACV,EAAE,EAAE,WAAW,EAAE,YACjB,EAAE,YAAY,aAEd;KACF,IAAI,EAAE,cAAc,MAAM;MACxB,EAAE,eAAe;MACjB,gBAAgB,UAAU,cAAc,KACtC,EAAE,cAAc,IAClB;KACF,OACE,OAAO,EAAE,cAAc,KAAK;IAEhC;GACD,CAAA,IAED,oBAAC,SAAD;IACE,YAAS;IACT,mBAAiB,WAAW,OAAO;IAC7B;IACN,cAAY;IACC;IACb,YAAY,MAAM;KAChB,IACE,EAAE,QAAQ,WACV,CAAC,EAAE,YAAY,eACf,CAAC,EAAE,cAAc,MAEjB,OAAO,EAAE,cAAc,KAAK;IAChC;GACD,CAAA;EAEL;CACF;CACA,YAAY;EACV,aACE;EACF,YAAY,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,4BAA4B;GAClE,KAAK,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,4BAA4B;GAChE,KAAK,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,4BAA4B;GAChE,OAAO,EACJ,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,mCAAmC;GAC/C,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gCAAgC;EACvE,CAAC;EACD,SAAS,EAAE,OAAO,KAAK,KAAK,OAAO,MAAM,SAAS,gBAChD,oBAAC,SAAD;GACE,MAAK;GACL,YAAS;GACT,mBAAiB,WAAW,OAAO;GAC7B;GACN,cAAY;GACZ,cAAc;GACT;GACA;GACL,WAAW,MAAM,KAAK,SAAS,WAAW,EAAE,cAAc,KAAK;EAChE,CAAA;CAEL;CACA,UAAU;EACR,aACE;EACF,YAAY,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,kCAAkC;GAC7D,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gCAAgC;GACrE,gBAAgB,EACb,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SAAS,sCAAsC;EACpD,CAAC;EACD,SAAS,EAAE,OAAO,MAAM,gBAAgB,SAAS,gBAC/C,qBAAC,SAAD;GAAO,YAAS;GAAhB,UAAA,CACE,oBAAC,SAAD;IACE,MAAK;IACL,mBAAiB,WAAW,OAAO;IAC7B;IACU;IAChB,WAAW,MAAM,KAAK,SAAS,WAAW,EAAE,cAAc,OAAO;GAClE,CAAA,GACD,oBAAC,QAAD;IAAM,YAAS;IAAkB,UAAA,cAAc,KAAK;GAAQ,CAAA,CACvD;;CAEX;CACA,YAAY;EACV,aACE;EACF,YAAY,EAAE,OAAO;GACnB,SAAS,EAAE,MAAM,YAAY,CAAC,CAAC,SAAS,qBAAqB;GAC7D,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gCAAgC;GACrE,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,gCAAgC;GACtE,cAAc,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,2BAA2B;EAC1E,CAAC;EACD,QAAQ;CACV;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/vocabulary/layout.d.ts
|
|
3
|
-
declare const layoutVocabulary: {
|
|
3
|
+
export declare const layoutVocabulary: {
|
|
4
4
|
Card: {
|
|
5
5
|
description: string;
|
|
6
6
|
properties: z.ZodObject<{
|
|
@@ -78,5 +78,4 @@ declare const layoutVocabulary: {
|
|
|
78
78
|
};
|
|
79
79
|
};
|
|
80
80
|
//#endregion
|
|
81
|
-
export { layoutVocabulary };
|
|
82
81
|
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","names":[],"sources":["../../src/vocabulary/layout.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"layout.d.ts","names":[],"sources":["../../src/vocabulary/layout.tsx"],"mappings":";;qBAwBa"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ALIGNS, JUSTIFIES } from "../ir.js";
|
|
2
|
+
import { toTextContent } from "./toTextContent.js";
|
|
2
3
|
import { fire } from "./dispatch.js";
|
|
3
4
|
import { collectFormValuesFromEvent } from "./collectFormValues.js";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -23,18 +24,19 @@ const layoutVocabulary = {
|
|
|
23
24
|
}),
|
|
24
25
|
render: ({ title, padding, background, asForm, confirm, cancel, $dispatch, children }) => {
|
|
25
26
|
const Root = asForm ? "form" : "section";
|
|
27
|
+
const cardTitle = toTextContent(title);
|
|
26
28
|
const footer = confirm || cancel ? /* @__PURE__ */ jsxs("footer", {
|
|
27
29
|
"data-aui": "card-footer",
|
|
28
30
|
children: [confirm ? /* @__PURE__ */ jsx("button", {
|
|
29
31
|
type: asForm ? "submit" : "button",
|
|
30
32
|
"data-aui": "card-confirm",
|
|
31
33
|
onClick: asForm ? void 0 : () => fire(confirm.$action, $dispatch),
|
|
32
|
-
children: confirm.label
|
|
34
|
+
children: toTextContent(confirm.label)
|
|
33
35
|
}) : null, cancel ? /* @__PURE__ */ jsx("button", {
|
|
34
36
|
type: "button",
|
|
35
37
|
"data-aui": "card-cancel",
|
|
36
38
|
onClick: () => fire(cancel.$action, $dispatch),
|
|
37
|
-
children: cancel.label
|
|
39
|
+
children: toTextContent(cancel.label)
|
|
38
40
|
}) : null]
|
|
39
41
|
}) : null;
|
|
40
42
|
return /* @__PURE__ */ jsxs(Root, {
|
|
@@ -52,9 +54,9 @@ const layoutVocabulary = {
|
|
|
52
54
|
fire(confirm?.$action, $dispatch, collectFormValuesFromEvent(event));
|
|
53
55
|
} : void 0,
|
|
54
56
|
children: [
|
|
55
|
-
|
|
57
|
+
cardTitle ? /* @__PURE__ */ jsx("header", {
|
|
56
58
|
"data-aui": "card-title",
|
|
57
|
-
children:
|
|
59
|
+
children: cardTitle
|
|
58
60
|
}) : null,
|
|
59
61
|
children,
|
|
60
62
|
footer
|
|
@@ -104,7 +106,7 @@ const layoutVocabulary = {
|
|
|
104
106
|
render: ({ value, variant, children }) => /* @__PURE__ */ jsxs("span", {
|
|
105
107
|
"data-aui": "badge",
|
|
106
108
|
"data-aui-variant": variant,
|
|
107
|
-
children: [value, children]
|
|
109
|
+
children: [toTextContent(value), children]
|
|
108
110
|
})
|
|
109
111
|
},
|
|
110
112
|
Box: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","names":[],"sources":["../../src/vocabulary/layout.tsx"],"sourcesContent":["import type { CSSProperties, FormEvent } from \"react\";\nimport { z } from \"zod\";\nimport type { GenerativeUILibrary } from \"../types\";\nimport { ALIGNS, JUSTIFIES } from \"../ir\";\nimport { fire } from \"./dispatch\";\nimport { collectFormValuesFromEvent } from \"./collectFormValues\";\n\nconst toCssLength = (value: string | number): string =>\n typeof value === \"number\" ? `${value}px` : value;\n\nconst cardActionSchema = z.looseObject({\n type: z\n .string()\n .describe(\"The action type, resolved by the host's action registry.\"),\n});\n\nconst cardFooterButtonSchema = z.object({\n label: z.string().describe(\"Footer button label.\"),\n $action: cardActionSchema\n .optional()\n .describe(\"Action fired when the button is activated.\"),\n});\n\nexport const layoutVocabulary = {\n Card: {\n description:\n \"A titled section of related content, the default way to break a response into parts. It renders as plain content, so several in a row read as one answer rather than a stack of boxes; it takes on a framed surface only when `background` is set, when `confirm`/`cancel` add a footer, or when it is a slot in a `Carousel`. Set `asForm` to collect named child control values on submit.\",\n properties: z.object({\n title: z.string().optional().describe(\"Optional card title.\"),\n padding: z\n .number()\n .min(0)\n .max(8)\n .optional()\n .describe(\n \"Padding in 4px units (e.g. 2 = 8px). 0 to 8 is the supported range.\",\n ),\n background: z\n .string()\n .optional()\n .describe(\n \"Background color or gradient (any CSS background value). Setting this also switches the card's own text to white, since a custom background makes the card a tinted surface; children can still opt into a different color explicitly.\",\n ),\n asForm: z\n .boolean()\n .optional()\n .describe(\n \"Render as a form; submitting it fires `confirm.$action` with every named child control's value, keyed by `name`.\",\n ),\n confirm: cardFooterButtonSchema\n .optional()\n .describe(\"Confirm button shown in the footer.\"),\n cancel: cardFooterButtonSchema\n .optional()\n .describe(\"Cancel button shown in the footer.\"),\n }),\n render: ({\n title,\n padding,\n background,\n asForm,\n confirm,\n cancel,\n $dispatch,\n children,\n }) => {\n const Root = asForm ? \"form\" : \"section\";\n const footer =\n confirm || cancel ? (\n <footer data-aui=\"card-footer\">\n {confirm ? (\n <button\n type={asForm ? \"submit\" : \"button\"}\n data-aui=\"card-confirm\"\n onClick={\n asForm ? undefined : () => fire(confirm.$action, $dispatch)\n }\n >\n {confirm.label}\n </button>\n ) : null}\n {cancel ? (\n <button\n type=\"button\"\n data-aui=\"card-cancel\"\n onClick={() => fire(cancel.$action, $dispatch)}\n >\n {cancel.label}\n </button>\n ) : null}\n </footer>\n ) : null;\n\n return (\n <Root\n data-aui=\"card\"\n data-aui-padding={padding}\n data-aui-background={background}\n data-aui-surface={\n background !== undefined || footer !== null ? \"\" : undefined\n }\n style={\n background !== undefined\n ? { background, color: \"white\" }\n : undefined\n }\n data-aui-asform={asForm || undefined}\n onSubmit={\n asForm\n ? (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n fire(\n confirm?.$action,\n $dispatch,\n collectFormValuesFromEvent(event),\n );\n }\n : undefined\n }\n >\n {title ? <header data-aui=\"card-title\">{title}</header> : null}\n {children}\n {footer}\n </Root>\n );\n },\n },\n Col: {\n description: \"A vertical stack; children laid out top to bottom.\",\n properties: z.object({\n gap: z\n .number()\n .min(0)\n .max(8)\n .optional()\n .describe(\n \"Gap between children in 4px units. 0 to 8 is the supported range.\",\n ),\n align: z.enum(ALIGNS).optional().describe(\"Cross-axis alignment.\"),\n }),\n render: ({ gap, align, children }) => (\n <div data-aui=\"col\" data-aui-gap={gap} data-aui-align={align}>\n {children}\n </div>\n ),\n },\n Row: {\n description: \"A horizontal row; children laid out left to right.\",\n properties: z.object({\n gap: z\n .number()\n .min(0)\n .max(8)\n .optional()\n .describe(\n \"Gap between children in 4px units. 0 to 8 is the supported range.\",\n ),\n align: z.enum(ALIGNS).optional().describe(\"Cross-axis alignment.\"),\n justify: z.enum(JUSTIFIES).optional().describe(\"Main-axis distribution.\"),\n }),\n render: ({ gap, align, justify, children }) => (\n <div\n data-aui=\"row\"\n data-aui-gap={gap}\n data-aui-align={align}\n data-aui-justify={justify}\n >\n {children}\n </div>\n ),\n },\n Spacer: {\n description: \"Empty space that pushes neighbors apart.\",\n properties: z.object({}),\n render: () => <div data-aui=\"spacer\" />,\n },\n Badge: {\n description: \"A small labeled tag, e.g. for status or category.\",\n properties: z.object({\n value: z.string().describe(\"Badge text.\"),\n variant: z.string().optional().describe(\"Visual variant token.\"),\n }),\n render: ({ value, variant, children }) => (\n <span data-aui=\"badge\" data-aui-variant={variant}>\n {value}\n {children}\n </span>\n ),\n },\n Box: {\n description:\n \"A generic container for composition, e.g. a progress bar built from an outer track Box containing a partial-width fill Box. Size, radius, and background accept arbitrary values, so they render as inline styles rather than data-attribute hooks.\",\n properties: z.object({\n width: z\n .union([z.string(), z.number()])\n .optional()\n .describe(\"Width; a number is pixels.\"),\n height: z\n .union([z.string(), z.number()])\n .optional()\n .describe(\"Height; a number is pixels.\"),\n radius: z\n .union([z.literal(\"full\"), z.number()])\n .optional()\n .describe(\n 'Corner radius; \"full\" is a pill/circle, a number is pixels.',\n ),\n background: z\n .string()\n .optional()\n .describe(\"Background color or gradient (any CSS background value).\"),\n }),\n render: ({ width, height, radius, background, children }) => {\n const style: CSSProperties = {};\n if (width !== undefined) style.width = toCssLength(width);\n if (height !== undefined) style.height = toCssLength(height);\n if (background !== undefined) style.background = background;\n if (radius === \"full\") style.borderRadius = \"9999px\";\n else if (typeof radius === \"number\") style.borderRadius = `${radius}px`;\n\n return (\n <div\n data-aui=\"box\"\n data-aui-radius={radius === \"full\" ? \"full\" : undefined}\n style={style}\n >\n {children}\n </div>\n );\n },\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"layout.js","names":[],"sources":["../../src/vocabulary/layout.tsx"],"sourcesContent":["import type { CSSProperties, FormEvent } from \"react\";\nimport { z } from \"zod\";\nimport type { GenerativeUILibrary } from \"../types\";\nimport { ALIGNS, JUSTIFIES } from \"../ir\";\nimport { fire } from \"./dispatch\";\nimport { collectFormValuesFromEvent } from \"./collectFormValues\";\nimport { toTextContent } from \"./toTextContent\";\n\nconst toCssLength = (value: string | number): string =>\n typeof value === \"number\" ? `${value}px` : value;\n\nconst cardActionSchema = z.looseObject({\n type: z\n .string()\n .describe(\"The action type, resolved by the host's action registry.\"),\n});\n\nconst cardFooterButtonSchema = z.object({\n label: z.string().describe(\"Footer button label.\"),\n $action: cardActionSchema\n .optional()\n .describe(\"Action fired when the button is activated.\"),\n});\n\nexport const layoutVocabulary = {\n Card: {\n description:\n \"A titled section of related content, the default way to break a response into parts. It renders as plain content, so several in a row read as one answer rather than a stack of boxes; it takes on a framed surface only when `background` is set, when `confirm`/`cancel` add a footer, or when it is a slot in a `Carousel`. Set `asForm` to collect named child control values on submit.\",\n properties: z.object({\n title: z.string().optional().describe(\"Optional card title.\"),\n padding: z\n .number()\n .min(0)\n .max(8)\n .optional()\n .describe(\n \"Padding in 4px units (e.g. 2 = 8px). 0 to 8 is the supported range.\",\n ),\n background: z\n .string()\n .optional()\n .describe(\n \"Background color or gradient (any CSS background value). Setting this also switches the card's own text to white, since a custom background makes the card a tinted surface; children can still opt into a different color explicitly.\",\n ),\n asForm: z\n .boolean()\n .optional()\n .describe(\n \"Render as a form; submitting it fires `confirm.$action` with every named child control's value, keyed by `name`.\",\n ),\n confirm: cardFooterButtonSchema\n .optional()\n .describe(\"Confirm button shown in the footer.\"),\n cancel: cardFooterButtonSchema\n .optional()\n .describe(\"Cancel button shown in the footer.\"),\n }),\n render: ({\n title,\n padding,\n background,\n asForm,\n confirm,\n cancel,\n $dispatch,\n children,\n }) => {\n const Root = asForm ? \"form\" : \"section\";\n const cardTitle = toTextContent(title);\n const footer =\n confirm || cancel ? (\n <footer data-aui=\"card-footer\">\n {confirm ? (\n <button\n type={asForm ? \"submit\" : \"button\"}\n data-aui=\"card-confirm\"\n onClick={\n asForm ? undefined : () => fire(confirm.$action, $dispatch)\n }\n >\n {toTextContent(confirm.label)}\n </button>\n ) : null}\n {cancel ? (\n <button\n type=\"button\"\n data-aui=\"card-cancel\"\n onClick={() => fire(cancel.$action, $dispatch)}\n >\n {toTextContent(cancel.label)}\n </button>\n ) : null}\n </footer>\n ) : null;\n\n return (\n <Root\n data-aui=\"card\"\n data-aui-padding={padding}\n data-aui-background={background}\n data-aui-surface={\n background !== undefined || footer !== null ? \"\" : undefined\n }\n style={\n background !== undefined\n ? { background, color: \"white\" }\n : undefined\n }\n data-aui-asform={asForm || undefined}\n onSubmit={\n asForm\n ? (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault();\n fire(\n confirm?.$action,\n $dispatch,\n collectFormValuesFromEvent(event),\n );\n }\n : undefined\n }\n >\n {cardTitle ? (\n <header data-aui=\"card-title\">{cardTitle}</header>\n ) : null}\n {children}\n {footer}\n </Root>\n );\n },\n },\n Col: {\n description: \"A vertical stack; children laid out top to bottom.\",\n properties: z.object({\n gap: z\n .number()\n .min(0)\n .max(8)\n .optional()\n .describe(\n \"Gap between children in 4px units. 0 to 8 is the supported range.\",\n ),\n align: z.enum(ALIGNS).optional().describe(\"Cross-axis alignment.\"),\n }),\n render: ({ gap, align, children }) => (\n <div data-aui=\"col\" data-aui-gap={gap} data-aui-align={align}>\n {children}\n </div>\n ),\n },\n Row: {\n description: \"A horizontal row; children laid out left to right.\",\n properties: z.object({\n gap: z\n .number()\n .min(0)\n .max(8)\n .optional()\n .describe(\n \"Gap between children in 4px units. 0 to 8 is the supported range.\",\n ),\n align: z.enum(ALIGNS).optional().describe(\"Cross-axis alignment.\"),\n justify: z.enum(JUSTIFIES).optional().describe(\"Main-axis distribution.\"),\n }),\n render: ({ gap, align, justify, children }) => (\n <div\n data-aui=\"row\"\n data-aui-gap={gap}\n data-aui-align={align}\n data-aui-justify={justify}\n >\n {children}\n </div>\n ),\n },\n Spacer: {\n description: \"Empty space that pushes neighbors apart.\",\n properties: z.object({}),\n render: () => <div data-aui=\"spacer\" />,\n },\n Badge: {\n description: \"A small labeled tag, e.g. for status or category.\",\n properties: z.object({\n value: z.string().describe(\"Badge text.\"),\n variant: z.string().optional().describe(\"Visual variant token.\"),\n }),\n render: ({ value, variant, children }) => (\n <span data-aui=\"badge\" data-aui-variant={variant}>\n {toTextContent(value)}\n {children}\n </span>\n ),\n },\n Box: {\n description:\n \"A generic container for composition, e.g. a progress bar built from an outer track Box containing a partial-width fill Box. Size, radius, and background accept arbitrary values, so they render as inline styles rather than data-attribute hooks.\",\n properties: z.object({\n width: z\n .union([z.string(), z.number()])\n .optional()\n .describe(\"Width; a number is pixels.\"),\n height: z\n .union([z.string(), z.number()])\n .optional()\n .describe(\"Height; a number is pixels.\"),\n radius: z\n .union([z.literal(\"full\"), z.number()])\n .optional()\n .describe(\n 'Corner radius; \"full\" is a pill/circle, a number is pixels.',\n ),\n background: z\n .string()\n .optional()\n .describe(\"Background color or gradient (any CSS background value).\"),\n }),\n render: ({ width, height, radius, background, children }) => {\n const style: CSSProperties = {};\n if (width !== undefined) style.width = toCssLength(width);\n if (height !== undefined) style.height = toCssLength(height);\n if (background !== undefined) style.background = background;\n if (radius === \"full\") style.borderRadius = \"9999px\";\n else if (typeof radius === \"number\") style.borderRadius = `${radius}px`;\n\n return (\n <div\n data-aui=\"box\"\n data-aui-radius={radius === \"full\" ? \"full\" : undefined}\n style={style}\n >\n {children}\n </div>\n );\n },\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":";;;;;;;AAQA,MAAM,eAAe,UACnB,OAAO,UAAU,WAAW,GAAG,MAAM,MAAM;AAE7C,MAAM,mBAAmB,EAAE,YAAY,EACrC,MAAM,EACH,OAAO,CAAC,CACR,SAAS,0DAA0D,EACxE,CAAC;AAED,MAAM,yBAAyB,EAAE,OAAO;CACtC,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,sBAAsB;CACjD,SAAS,iBACN,SAAS,CAAC,CACV,SAAS,4CAA4C;AAC1D,CAAC;AAED,MAAa,mBAAmB;CAC9B,MAAM;EACJ,aACE;EACF,YAAY,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,sBAAsB;GAC5D,SAAS,EACN,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SACC,qEACF;GACF,YAAY,EACT,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SACC,wOACF;GACF,QAAQ,EACL,QAAQ,CAAC,CACT,SAAS,CAAC,CACV,SACC,kHACF;GACF,SAAS,uBACN,SAAS,CAAC,CACV,SAAS,qCAAqC;GACjD,QAAQ,uBACL,SAAS,CAAC,CACV,SAAS,oCAAoC;EAClD,CAAC;EACD,SAAS,EACP,OACA,SACA,YACA,QACA,SACA,QACA,WACA,eACI;GACJ,MAAM,OAAO,SAAS,SAAS;GAC/B,MAAM,YAAY,cAAc,KAAK;GACrC,MAAM,SACJ,WAAW,SACT,qBAAC,UAAD;IAAQ,YAAS;IAAjB,UAAA,CACG,UACC,oBAAC,UAAD;KACE,MAAM,SAAS,WAAW;KAC1B,YAAS;KACT,SACE,SAAS,KAAA,UAAkB,KAAK,QAAQ,SAAS,SAAS;KAG3D,UAAA,cAAc,QAAQ,KAAK;IACtB,CAAA,IACN,MACH,SACC,oBAAC,UAAD;KACE,MAAK;KACL,YAAS;KACT,eAAe,KAAK,OAAO,SAAS,SAAS;KAE5C,UAAA,cAAc,OAAO,KAAK;IACrB,CAAA,IACN,IACE;GACN,CAAA,IAAA;GAEN,OACE,qBAAC,MAAD;IACE,YAAS;IACT,oBAAkB;IAClB,uBAAqB;IACrB,oBACE,eAAe,KAAA,KAAa,WAAW,OAAO,KAAK,KAAA;IAErD,OACE,eAAe,KAAA,IACX;KAAE;KAAY,OAAO;IAAQ,IAC7B,KAAA;IAEN,mBAAiB,UAAU,KAAA;IAC3B,UACE,UACK,UAAsC;KACrC,MAAM,eAAe;KACrB,KACE,SAAS,SACT,WACA,2BAA2B,KAAK,CAClC;IACF,IACA,KAAA;IAvBR,UAAA;KA0BG,YACC,oBAAC,UAAD;MAAQ,YAAS;MAAc,UAAA;KAAkB,CAAA,IAC/C;KACH;KACA;IACG;;EAEV;CACF;CACA,KAAK;EACH,aAAa;EACb,YAAY,EAAE,OAAO;GACnB,KAAK,EACF,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SACC,mEACF;GACF,OAAO,EAAE,KAAK,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,uBAAuB;EACnE,CAAC;EACD,SAAS,EAAE,KAAK,OAAO,eACrB,oBAAC,OAAD;GAAK,YAAS;GAAM,gBAAc;GAAK,kBAAgB;GACpD;EACE,CAAA;CAET;CACA,KAAK;EACH,aAAa;EACb,YAAY,EAAE,OAAO;GACnB,KAAK,EACF,OAAO,CAAC,CACR,IAAI,CAAC,CAAC,CACN,IAAI,CAAC,CAAC,CACN,SAAS,CAAC,CACV,SACC,mEACF;GACF,OAAO,EAAE,KAAK,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,uBAAuB;GACjE,SAAS,EAAE,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,yBAAyB;EAC1E,CAAC;EACD,SAAS,EAAE,KAAK,OAAO,SAAS,eAC9B,oBAAC,OAAD;GACE,YAAS;GACT,gBAAc;GACd,kBAAgB;GAChB,oBAAkB;GAEjB;EACE,CAAA;CAET;CACA,QAAQ;EACN,aAAa;EACb,YAAY,EAAE,OAAO,CAAC,CAAC;EACvB,cAAc,oBAAC,OAAD,EAAK,YAAS,SAAU,CAAA;CACxC;CACA,OAAO;EACL,aAAa;EACb,YAAY,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,aAAa;GACxC,SAAS,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,uBAAuB;EACjE,CAAC;EACD,SAAS,EAAE,OAAO,SAAS,eACzB,qBAAC,QAAD;GAAM,YAAS;GAAQ,oBAAkB;GAAzC,UAAA,CACG,cAAc,KAAK,GACnB,QACG;;CAEV;CACA,KAAK;EACH,aACE;EACF,YAAY,EAAE,OAAO;GACnB,OAAO,EACJ,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAC/B,SAAS,CAAC,CACV,SAAS,4BAA4B;GACxC,QAAQ,EACL,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CAC/B,SAAS,CAAC,CACV,SAAS,6BAA6B;GACzC,QAAQ,EACL,MAAM,CAAC,EAAE,QAAQ,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,CACtC,SAAS,CAAC,CACV,SACC,+DACF;GACF,YAAY,EACT,OAAO,CAAC,CACR,SAAS,CAAC,CACV,SAAS,0DAA0D;EACxE,CAAC;EACD,SAAS,EAAE,OAAO,QAAQ,QAAQ,YAAY,eAAe;GAC3D,MAAM,QAAuB,CAAC;GAC9B,IAAI,UAAU,KAAA,GAAW,MAAM,QAAQ,YAAY,KAAK;GACxD,IAAI,WAAW,KAAA,GAAW,MAAM,SAAS,YAAY,MAAM;GAC3D,IAAI,eAAe,KAAA,GAAW,MAAM,aAAa;GACjD,IAAI,WAAW,QAAQ,MAAM,eAAe;QACvC,IAAI,OAAO,WAAW,UAAU,MAAM,eAAe,GAAG,OAAO;GAEpE,OACE,oBAAC,OAAD;IACE,YAAS;IACT,mBAAiB,WAAW,SAAS,SAAS,KAAA;IACvC;IAEN;GACE,CAAA;EAET;CACF;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/vocabulary/list.d.ts
|
|
3
|
-
declare const listVocabulary: {
|
|
3
|
+
export declare const listVocabulary: {
|
|
4
4
|
ListView: {
|
|
5
5
|
description: string;
|
|
6
6
|
properties: z.ZodObject<{}, z.core.$strip>;
|
|
@@ -13,5 +13,4 @@ declare const listVocabulary: {
|
|
|
13
13
|
};
|
|
14
14
|
};
|
|
15
15
|
//#endregion
|
|
16
|
-
export { listVocabulary };
|
|
17
16
|
//# sourceMappingURL=list.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","names":[],"sources":["../../src/vocabulary/list.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"list.d.ts","names":[],"sources":["../../src/vocabulary/list.tsx"],"mappings":";;qBAOa"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/vocabulary/media.d.ts
|
|
3
|
-
declare const mediaVocabulary: {
|
|
3
|
+
export declare const mediaVocabulary: {
|
|
4
4
|
Image: {
|
|
5
5
|
description: string;
|
|
6
6
|
properties: z.ZodObject<{
|
|
@@ -24,5 +24,4 @@ declare const mediaVocabulary: {
|
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
26
|
//#endregion
|
|
27
|
-
export { mediaVocabulary };
|
|
28
27
|
//# sourceMappingURL=media.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.d.ts","names":[],"sources":["../../src/vocabulary/media.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"media.d.ts","names":[],"sources":["../../src/vocabulary/media.tsx"],"mappings":";;qBAKa"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
//#region src/vocabulary/text.d.ts
|
|
3
|
-
declare const textVocabulary: {
|
|
3
|
+
export declare const textVocabulary: {
|
|
4
4
|
Header: {
|
|
5
5
|
description: string;
|
|
6
6
|
properties: z.ZodObject<{
|
|
@@ -35,8 +35,8 @@ declare const textVocabulary: {
|
|
|
35
35
|
semibold: "semibold";
|
|
36
36
|
}>>;
|
|
37
37
|
color: z.ZodOptional<z.ZodEnum<{
|
|
38
|
-
emphasis: "emphasis";
|
|
39
38
|
secondary: "secondary";
|
|
39
|
+
emphasis: "emphasis";
|
|
40
40
|
"alpha-70": "alpha-70";
|
|
41
41
|
white: "white";
|
|
42
42
|
"white-70": "white-70";
|
|
@@ -56,5 +56,4 @@ declare const textVocabulary: {
|
|
|
56
56
|
};
|
|
57
57
|
};
|
|
58
58
|
//#endregion
|
|
59
|
-
export { textVocabulary };
|
|
60
59
|
//# sourceMappingURL=text.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.d.ts","names":[],"sources":["../../src/vocabulary/text.tsx"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"text.d.ts","names":[],"sources":["../../src/vocabulary/text.tsx"],"mappings":";;qBAKa"}
|
package/dist/vocabulary/text.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { COLORS, TEXT_SIZES, WEIGHTS } from "../ir.js";
|
|
2
|
+
import { toTextContent } from "./toTextContent.js";
|
|
2
3
|
import { jsxs } from "react/jsx-runtime";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
//#region src/vocabulary/text.tsx
|
|
@@ -12,7 +13,7 @@ const textVocabulary = {
|
|
|
12
13
|
render: ({ text, size, children }) => /* @__PURE__ */ jsxs("h2", {
|
|
13
14
|
"data-aui": "header",
|
|
14
15
|
"data-aui-size": size ?? "lg",
|
|
15
|
-
children: [text, children]
|
|
16
|
+
children: [toTextContent(text), children]
|
|
16
17
|
})
|
|
17
18
|
},
|
|
18
19
|
Text: {
|
|
@@ -29,7 +30,7 @@ const textVocabulary = {
|
|
|
29
30
|
"data-aui-size": size ?? "md",
|
|
30
31
|
"data-aui-weight": weight,
|
|
31
32
|
"data-aui-color": color,
|
|
32
|
-
children: [value, children]
|
|
33
|
+
children: [toTextContent(value), children]
|
|
33
34
|
})
|
|
34
35
|
},
|
|
35
36
|
Caption: {
|
|
@@ -38,7 +39,7 @@ const textVocabulary = {
|
|
|
38
39
|
streamProperties: true,
|
|
39
40
|
render: ({ value, children }) => /* @__PURE__ */ jsxs("p", {
|
|
40
41
|
"data-aui": "caption",
|
|
41
|
-
children: [value, children]
|
|
42
|
+
children: [toTextContent(value), children]
|
|
42
43
|
})
|
|
43
44
|
}
|
|
44
45
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","names":[],"sources":["../../src/vocabulary/text.tsx"],"sourcesContent":["import { z } from \"zod\";\nimport type { GenerativeUILibrary } from \"../types\";\nimport { COLORS, TEXT_SIZES, WEIGHTS } from \"../ir\";\n\nexport const textVocabulary = {\n Header: {\n description: \"A section heading. Renders as a bold title.\",\n properties: z.object({\n text: z.string().describe(\"The heading text.\"),\n size: z\n .enum(TEXT_SIZES)\n .optional()\n .describe(\"Heading size; defaults to `lg`.\"),\n }),\n render: ({ text, size, children }) => (\n <h2 data-aui=\"header\" data-aui-size={size ?? \"lg\"}>\n {text}\n {children}\n </h2>\n ),\n },\n Text: {\n description: \"A run of text. Use for paragraphs, labels, or inline copy.\",\n properties: z.object({\n value: z.string().describe(\"The text content.\"),\n size: z\n .enum(TEXT_SIZES)\n .optional()\n .describe(\"Text size; defaults to `md`.\"),\n weight: z.enum(WEIGHTS).optional().describe(\"Font weight.\"),\n color: z.enum(COLORS).optional().describe(\"Foreground color token.\"),\n }),\n streamProperties: true,\n render: ({ value, size, weight, color, children }) => (\n <span\n data-aui=\"text\"\n data-aui-size={size ?? \"md\"}\n data-aui-weight={weight}\n data-aui-color={color}\n >\n {value}\n {children}\n </span>\n ),\n },\n Caption: {\n description: \"Secondary, de-emphasized text under a primary element.\",\n properties: z.object({\n value: z.string().describe(\"The caption text.\"),\n }),\n streamProperties: true,\n render: ({ value, children }) => (\n <p data-aui=\"caption\">\n {value}\n {children}\n </p>\n ),\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"text.js","names":[],"sources":["../../src/vocabulary/text.tsx"],"sourcesContent":["import { z } from \"zod\";\nimport type { GenerativeUILibrary } from \"../types\";\nimport { COLORS, TEXT_SIZES, WEIGHTS } from \"../ir\";\nimport { toTextContent } from \"./toTextContent\";\n\nexport const textVocabulary = {\n Header: {\n description: \"A section heading. Renders as a bold title.\",\n properties: z.object({\n text: z.string().describe(\"The heading text.\"),\n size: z\n .enum(TEXT_SIZES)\n .optional()\n .describe(\"Heading size; defaults to `lg`.\"),\n }),\n render: ({ text, size, children }) => (\n <h2 data-aui=\"header\" data-aui-size={size ?? \"lg\"}>\n {toTextContent(text)}\n {children}\n </h2>\n ),\n },\n Text: {\n description: \"A run of text. Use for paragraphs, labels, or inline copy.\",\n properties: z.object({\n value: z.string().describe(\"The text content.\"),\n size: z\n .enum(TEXT_SIZES)\n .optional()\n .describe(\"Text size; defaults to `md`.\"),\n weight: z.enum(WEIGHTS).optional().describe(\"Font weight.\"),\n color: z.enum(COLORS).optional().describe(\"Foreground color token.\"),\n }),\n streamProperties: true,\n render: ({ value, size, weight, color, children }) => (\n <span\n data-aui=\"text\"\n data-aui-size={size ?? \"md\"}\n data-aui-weight={weight}\n data-aui-color={color}\n >\n {toTextContent(value)}\n {children}\n </span>\n ),\n },\n Caption: {\n description: \"Secondary, de-emphasized text under a primary element.\",\n properties: z.object({\n value: z.string().describe(\"The caption text.\"),\n }),\n streamProperties: true,\n render: ({ value, children }) => (\n <p data-aui=\"caption\">\n {toTextContent(value)}\n {children}\n </p>\n ),\n },\n} satisfies GenerativeUILibrary;\n"],"mappings":";;;;;AAKA,MAAa,iBAAiB;CAC5B,QAAQ;EACN,aAAa;EACb,YAAY,EAAE,OAAO;GACnB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,mBAAmB;GAC7C,MAAM,EACH,KAAK,UAAU,CAAC,CAChB,SAAS,CAAC,CACV,SAAS,iCAAiC;EAC/C,CAAC;EACD,SAAS,EAAE,MAAM,MAAM,eACrB,qBAAC,MAAD;GAAI,YAAS;GAAS,iBAAe,QAAQ;GAA7C,UAAA,CACG,cAAc,IAAI,GAClB,QACC;;CAER;CACA,MAAM;EACJ,aAAa;EACb,YAAY,EAAE,OAAO;GACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,mBAAmB;GAC9C,MAAM,EACH,KAAK,UAAU,CAAC,CAChB,SAAS,CAAC,CACV,SAAS,8BAA8B;GAC1C,QAAQ,EAAE,KAAK,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,cAAc;GAC1D,OAAO,EAAE,KAAK,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,SAAS,yBAAyB;EACrE,CAAC;EACD,kBAAkB;EAClB,SAAS,EAAE,OAAO,MAAM,QAAQ,OAAO,eACrC,qBAAC,QAAD;GACE,YAAS;GACT,iBAAe,QAAQ;GACvB,mBAAiB;GACjB,kBAAgB;GAJlB,UAAA,CAMG,cAAc,KAAK,GACnB,QACG;;CAEV;CACA,SAAS;EACP,aAAa;EACb,YAAY,EAAE,OAAO,EACnB,OAAO,EAAE,OAAO,CAAC,CAAC,SAAS,mBAAmB,EAChD,CAAC;EACD,kBAAkB;EAClB,SAAS,EAAE,OAAO,eAChB,qBAAC,KAAD;GAAG,YAAS;GAAZ,UAAA,CACG,cAAc,KAAK,GACnB,QACA;;CAEP;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toTextContent.d.ts","names":[],"sources":["../../src/vocabulary/toTextContent.ts"],"mappings":";qBAAa,gBAAiB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toTextContent.js","names":[],"sources":["../../src/vocabulary/toTextContent.ts"],"sourcesContent":["export const toTextContent = (value: unknown): string | number | null =>\n typeof value === \"string\" || typeof value === \"number\" ? value : null;\n"],"mappings":";AAAA,MAAa,iBAAiB,UAC5B,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW,QAAQ"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-generative-ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"description": "Generative UI components for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"generative-ui",
|
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
],
|
|
51
51
|
"sideEffects": false,
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"
|
|
53
|
+
"@types/json-schema": "^7.0.15",
|
|
54
|
+
"assistant-stream": "^0.3.44"
|
|
54
55
|
},
|
|
55
56
|
"peerDependencies": {
|
|
56
57
|
"@assistant-ui/react": "^0.15.0",
|
|
@@ -64,14 +65,14 @@
|
|
|
64
65
|
}
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
|
-
"@assistant-ui/react": "0.15.
|
|
68
|
-
"@assistant-ui/x-buildutils": "0.0.
|
|
69
|
-
"@types/
|
|
70
|
-
"
|
|
71
|
-
"react": "^19.
|
|
72
|
-
"react-dom": "^19.
|
|
73
|
-
"vitest": "^
|
|
74
|
-
"zod": "^4.5
|
|
68
|
+
"@assistant-ui/react": "0.15.21",
|
|
69
|
+
"@assistant-ui/x-buildutils": "0.0.28",
|
|
70
|
+
"@types/react": "^19.3.0",
|
|
71
|
+
"jsdom": "^30.0.1",
|
|
72
|
+
"react": "^19.3.0",
|
|
73
|
+
"react-dom": "^19.3.0",
|
|
74
|
+
"vitest": "^5.0.1",
|
|
75
|
+
"zod": "^4.6.5"
|
|
75
76
|
},
|
|
76
77
|
"publishConfig": {
|
|
77
78
|
"access": "public",
|
|
@@ -89,6 +90,7 @@
|
|
|
89
90
|
"scripts": {
|
|
90
91
|
"build": "aui-build",
|
|
91
92
|
"test": "vitest run",
|
|
93
|
+
"typecheck": "tsc --noEmit",
|
|
92
94
|
"test:watch": "vitest"
|
|
93
95
|
}
|
|
94
96
|
}
|
package/src/a2ui/convert.test.ts
CHANGED
|
@@ -201,6 +201,42 @@ describe("convertSurfaceToUISpec", () => {
|
|
|
201
201
|
});
|
|
202
202
|
});
|
|
203
203
|
|
|
204
|
+
it("preserves prototype-named action context fields", () => {
|
|
205
|
+
const context = JSON.parse(
|
|
206
|
+
'{"__proto__":{"admin":true},"literal":"kept"}',
|
|
207
|
+
) as Record<string, unknown>;
|
|
208
|
+
const surface = surfaceFrom([
|
|
209
|
+
{
|
|
210
|
+
id: "root",
|
|
211
|
+
component: "Button",
|
|
212
|
+
label: "Run",
|
|
213
|
+
action: { name: "run", context },
|
|
214
|
+
},
|
|
215
|
+
]);
|
|
216
|
+
|
|
217
|
+
const result = convertSurfaceToUISpec(surface);
|
|
218
|
+
const convertedContext = (result.spec as UIElement).$action
|
|
219
|
+
?.context as Record<string, unknown>;
|
|
220
|
+
|
|
221
|
+
expect(Object.getPrototypeOf(convertedContext)).toBe(Object.prototype);
|
|
222
|
+
expect(Object.hasOwn(convertedContext, "__proto__")).toBe(true);
|
|
223
|
+
expect(convertedContext["__proto__"]).toEqual({ admin: true });
|
|
224
|
+
expect(JSON.stringify(convertedContext)).toBe(
|
|
225
|
+
'{"__proto__":{"admin":true},"literal":"kept"}',
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it("does not read component fields through a prototype-named prop", () => {
|
|
230
|
+
const component = JSON.parse(
|
|
231
|
+
'{"id":"root","component":"Text","__proto__":{"text":"injected"}}',
|
|
232
|
+
) as Record<string, unknown>;
|
|
233
|
+
|
|
234
|
+
expect(convertSurfaceToUISpec(surfaceFrom([component]))).toEqual({
|
|
235
|
+
spec: { $type: "Markdown" },
|
|
236
|
+
warnings: [],
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
204
240
|
it("expands template children relative to each bound item", () => {
|
|
205
241
|
const surface = surfaceFrom(
|
|
206
242
|
[
|
package/src/a2ui/convert.ts
CHANGED
|
@@ -30,6 +30,23 @@ const isPlainObject = (value: unknown): value is Record<string, unknown> => {
|
|
|
30
30
|
return prototype === Object.prototype || prototype === null;
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
+
const setOwnProperty = (
|
|
34
|
+
target: Record<string, unknown>,
|
|
35
|
+
key: string,
|
|
36
|
+
value: unknown,
|
|
37
|
+
) => {
|
|
38
|
+
if (key === "__proto__") {
|
|
39
|
+
Object.defineProperty(target, key, {
|
|
40
|
+
value,
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
writable: true,
|
|
44
|
+
});
|
|
45
|
+
} else {
|
|
46
|
+
target[key] = value;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
33
50
|
const isBinding = (value: unknown): value is { readonly path: string } =>
|
|
34
51
|
isPlainObject(value) &&
|
|
35
52
|
Object.keys(value).length === 1 &&
|
|
@@ -90,7 +107,9 @@ const materialize = (value: unknown, source: unknown): unknown => {
|
|
|
90
107
|
const result: Record<string, unknown> = {};
|
|
91
108
|
for (const [key, entry] of Object.entries(value)) {
|
|
92
109
|
const resolved = materialize(entry, source);
|
|
93
|
-
if (resolved !== undefined)
|
|
110
|
+
if (resolved !== undefined) {
|
|
111
|
+
setOwnProperty(result, key, resolved);
|
|
112
|
+
}
|
|
94
113
|
}
|
|
95
114
|
return result;
|
|
96
115
|
};
|
|
@@ -419,7 +438,7 @@ function convertComponent(
|
|
|
419
438
|
for (const [key, value] of Object.entries(node)) {
|
|
420
439
|
if (key === "id" || key === "component" || key === "children") continue;
|
|
421
440
|
const resolved = materialize(value, dataSource);
|
|
422
|
-
if (resolved !== undefined) props
|
|
441
|
+
if (resolved !== undefined) setOwnProperty(props, key, resolved);
|
|
423
442
|
}
|
|
424
443
|
const mapped = mappedProps(node, props, dataSource, context);
|
|
425
444
|
if (!mapped) return null;
|