@ukiahinsure/a2ui-react-adapter 0.1.17 → 0.1.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/index.d.ts
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
|
-
import { A as A2UIClientAdapter, a as A2UISurfaceMetadata, b as A2UISessionController, c as A2UIRoomLike } from './session-
|
|
2
|
-
export { d as A2UIActionDeliveryStatus, e as A2UIActionResult, f as A2UIActionState, g as A2UICapabilityEnvelope, h as A2UIClientActionEnvelope, i as A2UIClientAdapterOptions, j as A2UIClientErrorEnvelope, k as A2UIClientErrorEvent, l as A2UIEditingSnapshot, m as A2UIFieldControl, n as A2UIFieldDescriptor, o as A2UIFieldInteractionField, p as A2UIFieldInteractionGroup, q as
|
|
1
|
+
import { A as A2UIClientAdapter, a as A2UISurfaceMetadata, b as A2UISessionController, c as A2UIRoomLike } from './session-BnvcVx-k.js';
|
|
2
|
+
export { d as A2UIActionDeliveryStatus, e as A2UIActionResult, f as A2UIActionState, g as A2UICapabilityEnvelope, h as A2UIClientActionEnvelope, i as A2UIClientAdapterOptions, j as A2UIClientErrorEnvelope, k as A2UIClientErrorEvent, l as A2UIEditingSnapshot, m as A2UIFieldControl, n as A2UIFieldDescriptor, o as A2UIFieldInteractionField, p as A2UIFieldInteractionGroup, q as A2UIFieldUpdateEvent, r as A2UIFieldValue, s as A2UIPendingAction, t as A2UIRendererActionEvent, u as A2UIServerEnvelope, v as A2UISessionControllerOptions, w as A2UISessionSnapshot, x as A2UISessionStatus, y as A2UIStreamParticipant, z as A2UISurfaceStructure, B as A2UITabDescriptor, C as A2UITrustedServerParticipant, D as A2UI_CAPABILITIES_TOPIC, E as A2UI_CLIENT_TOPIC, F as A2UI_PROTOCOL_VERSION, G as A2UI_SERVER_TOPIC, H as AckEnvelope, I as AckFieldError, J as AdapterSurface, K as CLIENT_ACTIONS, L as CLIENT_ERROR_CODES, M as ClientAction, N as ClientErrorCode, O as ENVELOPE_VERSION, P as MAX_ENVELOPE_BYTES, Q as ParticipantRole, S as SectionNavigation, R as SnapshotEnvelope, T as SurfaceUpdateEnvelope } from './session-BnvcVx-k.js';
|
|
3
3
|
import { ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
/** Accessible host around the official A2UI v0.9.1 React surface. */
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* The agent changed what the form shows: it filled or corrected field values
|
|
9
|
+
* (`field-value`), or moved the conversation to a new current field group
|
|
10
|
+
* (`current-group`). `element` is the rendered container for the first
|
|
11
|
+
* affected field (the whole choice group or date editor, not one option), so
|
|
12
|
+
* hosts can scroll to it for any control type.
|
|
13
|
+
*/
|
|
14
|
+
interface A2UIAgentUpdateEvent {
|
|
15
|
+
reason: "field-value" | "current-group";
|
|
16
|
+
surfaceId: string;
|
|
17
|
+
fields: readonly string[];
|
|
18
|
+
groupId?: string;
|
|
19
|
+
element?: HTMLElement;
|
|
20
|
+
}
|
|
7
21
|
interface A2UISurfaceHostProps {
|
|
8
22
|
adapter: A2UIClientAdapter;
|
|
9
23
|
/** Render a specific surface; defaults to the adapter's current surface. */
|
|
@@ -25,8 +39,10 @@ interface A2UISurfaceHostProps {
|
|
|
25
39
|
noSurfaceFallback?: ReactNode;
|
|
26
40
|
/** Shown when the surface fails to render. */
|
|
27
41
|
errorFallback?: ReactNode;
|
|
42
|
+
/** Called after the DOM reflects an agent-driven field or group change. */
|
|
43
|
+
onAgentUpdate?: (event: A2UIAgentUpdateEvent) => void;
|
|
28
44
|
}
|
|
29
|
-
declare function A2UISurfaceHost({ adapter, surfaceId, surfaceMetadata, sessionController, hostId, ariaLabel, disabled, busy, invalidFields, validationSummaryId, noSurfaceFallback, errorFallback, }: A2UISurfaceHostProps): ReactNode;
|
|
45
|
+
declare function A2UISurfaceHost({ adapter, surfaceId, surfaceMetadata, sessionController, hostId, ariaLabel, disabled, busy, invalidFields, validationSummaryId, noSurfaceFallback, errorFallback, onAgentUpdate, }: A2UISurfaceHostProps): ReactNode;
|
|
30
46
|
|
|
31
47
|
/** Explicit room-ownership helper backed by backend-issued runtime material. */
|
|
32
48
|
|
|
@@ -48,4 +64,4 @@ interface A2UIJoinedRoom {
|
|
|
48
64
|
*/
|
|
49
65
|
declare function joinA2UIRoom(tokenProvider: A2UITokenProvider): Promise<A2UIJoinedRoom>;
|
|
50
66
|
|
|
51
|
-
export { A2UIClientAdapter, type A2UIJoinedRoom, A2UIRoomLike, type A2UIRuntimeMaterial, A2UISessionController, A2UISurfaceHost, type A2UISurfaceHostProps, A2UISurfaceMetadata, type A2UITokenProvider, joinA2UIRoom };
|
|
67
|
+
export { type A2UIAgentUpdateEvent, A2UIClientAdapter, type A2UIJoinedRoom, A2UIRoomLike, type A2UIRuntimeMaterial, A2UISessionController, A2UISurfaceHost, type A2UISurfaceHostProps, A2UISurfaceMetadata, type A2UITokenProvider, joinA2UIRoom };
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-AOBRTDAU.js";
|
|
11
11
|
|
|
12
12
|
// src/adapter.ts
|
|
13
|
-
import { basicCatalog } from "@a2ui/react/v0_9";
|
|
13
|
+
import { basicCatalog as basicCatalog2 } from "@a2ui/react/v0_9";
|
|
14
14
|
import {
|
|
15
15
|
A2uiError,
|
|
16
16
|
Catalog,
|
|
@@ -18,11 +18,44 @@ import {
|
|
|
18
18
|
MessageProcessor
|
|
19
19
|
} from "@a2ui/web_core/v0_9";
|
|
20
20
|
|
|
21
|
+
// src/HospitalChoice.tsx
|
|
22
|
+
import { useId } from "react";
|
|
23
|
+
import { basicCatalog, createComponentImplementation } from "@a2ui/react/v0_9";
|
|
24
|
+
import { ChoicePickerApi } from "@a2ui/web_core/v0_9/basic_catalog";
|
|
25
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
26
|
+
var OriginalChoice = basicCatalog.components.get("ChoicePicker").render;
|
|
27
|
+
var HospitalChoice = createComponentImplementation(ChoicePickerApi, ({ props, context, buildChild }) => {
|
|
28
|
+
const id = useId();
|
|
29
|
+
if (props.label !== "hospital_preference") {
|
|
30
|
+
return /* @__PURE__ */ jsx(OriginalChoice, { context, buildChild });
|
|
31
|
+
}
|
|
32
|
+
const selected = Array.isArray(props.value) ? props.value[0] ?? "" : "";
|
|
33
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
|
|
34
|
+
/* @__PURE__ */ jsx("label", { htmlFor: id, children: "Hospital preference" }),
|
|
35
|
+
/* @__PURE__ */ jsxs(
|
|
36
|
+
"select",
|
|
37
|
+
{
|
|
38
|
+
id,
|
|
39
|
+
"data-a2ui-field": "hospital_preference",
|
|
40
|
+
value: selected,
|
|
41
|
+
required: true,
|
|
42
|
+
style: { padding: "0.5rem", border: "var(--a2ui-border)", borderRadius: "var(--a2ui-border-radius)" },
|
|
43
|
+
onChange: (event) => props.setValue(event.currentTarget.value ? [event.currentTarget.value] : []),
|
|
44
|
+
children: [
|
|
45
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Choose Prefer or Avoid" }),
|
|
46
|
+
/* @__PURE__ */ jsx("option", { value: "Prefer", children: "Prefer" }),
|
|
47
|
+
/* @__PURE__ */ jsx("option", { value: "Avoid", children: "Avoid" })
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
)
|
|
51
|
+
] });
|
|
52
|
+
});
|
|
53
|
+
|
|
21
54
|
// src/DateTimeInput.tsx
|
|
22
|
-
import { useId, useLayoutEffect, useRef, useState } from "react";
|
|
23
|
-
import { createComponentImplementation } from "@a2ui/react/v0_9";
|
|
55
|
+
import { useId as useId2, useLayoutEffect, useRef, useState } from "react";
|
|
56
|
+
import { createComponentImplementation as createComponentImplementation2 } from "@a2ui/react/v0_9";
|
|
24
57
|
import { DateTimeInputApi } from "@a2ui/web_core/v0_9/basic_catalog";
|
|
25
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
58
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
26
59
|
var inputStyle = {
|
|
27
60
|
backgroundColor: "var(--a2ui-datetimeinput-background, var(--a2ui-color-input, #fff))",
|
|
28
61
|
color: "var(--a2ui-datetimeinput-color, var(--a2ui-color-on-input, #333))",
|
|
@@ -50,7 +83,7 @@ function displayDate(value) {
|
|
|
50
83
|
return iso ? `${iso.slice(5, 7)}/${iso.slice(8, 10)}/${iso.slice(0, 4)}` : value;
|
|
51
84
|
}
|
|
52
85
|
function DateOnlyInput(props) {
|
|
53
|
-
const id =
|
|
86
|
+
const id = useId2();
|
|
54
87
|
const [draft, setDraft] = useState(() => displayDate(props.value || ""));
|
|
55
88
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
56
89
|
const published = useRef(props.value || "");
|
|
@@ -76,10 +109,10 @@ function DateOnlyInput(props) {
|
|
|
76
109
|
published.current = value;
|
|
77
110
|
props.setValue(value);
|
|
78
111
|
};
|
|
79
|
-
return /* @__PURE__ */
|
|
80
|
-
props.label && /* @__PURE__ */
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
112
|
+
return /* @__PURE__ */ jsxs2("div", { "data-a2ui-date-editor": "true", style: { display: "flex", flexDirection: "column", gap: "var(--a2ui-spacing-xs, 0.25rem)" }, children: [
|
|
113
|
+
props.label && /* @__PURE__ */ jsx2("label", { htmlFor: id, style: labelStyle, children: props.label }),
|
|
114
|
+
/* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "0.25rem", position: "relative" }, children: [
|
|
115
|
+
/* @__PURE__ */ jsx2(
|
|
83
116
|
"input",
|
|
84
117
|
{
|
|
85
118
|
ref: inputRef,
|
|
@@ -97,7 +130,7 @@ function DateOnlyInput(props) {
|
|
|
97
130
|
style: { ...inputStyle, minWidth: 0, flex: 1 }
|
|
98
131
|
}
|
|
99
132
|
),
|
|
100
|
-
/* @__PURE__ */
|
|
133
|
+
/* @__PURE__ */ jsx2(
|
|
101
134
|
"button",
|
|
102
135
|
{
|
|
103
136
|
type: "button",
|
|
@@ -117,7 +150,7 @@ function DateOnlyInput(props) {
|
|
|
117
150
|
children: "\u25A6"
|
|
118
151
|
}
|
|
119
152
|
),
|
|
120
|
-
/* @__PURE__ */
|
|
153
|
+
/* @__PURE__ */ jsx2(
|
|
121
154
|
"input",
|
|
122
155
|
{
|
|
123
156
|
ref: pickerRef,
|
|
@@ -140,15 +173,15 @@ function DateOnlyInput(props) {
|
|
|
140
173
|
] });
|
|
141
174
|
}
|
|
142
175
|
function NativeTimeInput(props) {
|
|
143
|
-
const id =
|
|
176
|
+
const id = useId2();
|
|
144
177
|
const inputRef = useRef(null);
|
|
145
178
|
const initialValue = useRef(props.value || "");
|
|
146
179
|
useLayoutEffect(() => {
|
|
147
180
|
if (inputRef.current && inputRef.current.value !== (props.value || "")) inputRef.current.value = props.value || "";
|
|
148
181
|
}, [props.value]);
|
|
149
|
-
return /* @__PURE__ */
|
|
150
|
-
props.label && /* @__PURE__ */
|
|
151
|
-
/* @__PURE__ */
|
|
182
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
183
|
+
props.label && /* @__PURE__ */ jsx2("label", { htmlFor: id, style: labelStyle, children: props.label }),
|
|
184
|
+
/* @__PURE__ */ jsx2(
|
|
152
185
|
"input",
|
|
153
186
|
{
|
|
154
187
|
ref: inputRef,
|
|
@@ -163,19 +196,19 @@ function NativeTimeInput(props) {
|
|
|
163
196
|
)
|
|
164
197
|
] });
|
|
165
198
|
}
|
|
166
|
-
var DateTimeInput =
|
|
199
|
+
var DateTimeInput = createComponentImplementation2(
|
|
167
200
|
DateTimeInputApi,
|
|
168
|
-
({ props }) => props.enableDate && !props.enableTime ? /* @__PURE__ */
|
|
201
|
+
({ props }) => props.enableDate && !props.enableTime ? /* @__PURE__ */ jsx2(DateOnlyInput, { ...props }) : /* @__PURE__ */ jsx2(NativeTimeInput, { ...props })
|
|
169
202
|
);
|
|
170
203
|
|
|
171
204
|
// src/adapter.ts
|
|
172
205
|
var editableDateCatalog = new Catalog(
|
|
173
|
-
|
|
174
|
-
[...
|
|
175
|
-
(component) => component.name === DateTimeInput.name ? DateTimeInput : component
|
|
206
|
+
basicCatalog2.id,
|
|
207
|
+
[...basicCatalog2.components.values()].map(
|
|
208
|
+
(component) => component.name === DateTimeInput.name ? DateTimeInput : component.name === HospitalChoice.name ? HospitalChoice : component
|
|
176
209
|
),
|
|
177
|
-
[...
|
|
178
|
-
|
|
210
|
+
[...basicCatalog2.functions.values()],
|
|
211
|
+
basicCatalog2.themeSchema
|
|
179
212
|
);
|
|
180
213
|
var RENDERER_NAME = "a2ui_react_adapter";
|
|
181
214
|
var RENDERER_VERSION = "0.1.0";
|
|
@@ -187,6 +220,7 @@ var A2UIClientAdapter = class {
|
|
|
187
220
|
#listeners = /* @__PURE__ */ new Set();
|
|
188
221
|
#actionListeners = /* @__PURE__ */ new Set();
|
|
189
222
|
#errorListeners = /* @__PURE__ */ new Set();
|
|
223
|
+
#fieldUpdateListeners = /* @__PURE__ */ new Set();
|
|
190
224
|
#surfaceOrder = [];
|
|
191
225
|
#structureBySurface = /* @__PURE__ */ new Map();
|
|
192
226
|
#persistedListRowsByPath = /* @__PURE__ */ new Map();
|
|
@@ -203,7 +237,7 @@ var A2UIClientAdapter = class {
|
|
|
203
237
|
}
|
|
204
238
|
/** Catalog ids this adapter will announce in capability envelopes. */
|
|
205
239
|
get supportedCatalogIds() {
|
|
206
|
-
return [
|
|
240
|
+
return [basicCatalog2.id];
|
|
207
241
|
}
|
|
208
242
|
get lastSeq() {
|
|
209
243
|
return this.#lastSeq;
|
|
@@ -387,6 +421,10 @@ var A2UIClientAdapter = class {
|
|
|
387
421
|
this.#errorListeners.add(listener);
|
|
388
422
|
return () => this.#errorListeners.delete(listener);
|
|
389
423
|
};
|
|
424
|
+
subscribeFieldUpdates = (listener) => {
|
|
425
|
+
this.#fieldUpdateListeners.add(listener);
|
|
426
|
+
return () => this.#fieldUpdateListeners.delete(listener);
|
|
427
|
+
};
|
|
390
428
|
/** Monotonic change counter for `useSyncExternalStore`. */
|
|
391
429
|
getVersion = () => this.#version;
|
|
392
430
|
dispose() {
|
|
@@ -403,6 +441,7 @@ var A2UIClientAdapter = class {
|
|
|
403
441
|
this.#listeners.clear();
|
|
404
442
|
this.#actionListeners.clear();
|
|
405
443
|
this.#errorListeners.clear();
|
|
444
|
+
this.#fieldUpdateListeners.clear();
|
|
406
445
|
}
|
|
407
446
|
#applySurfaceEnvelope(envelope) {
|
|
408
447
|
const validated = A2uiMessageListSchema.safeParse(envelope.messages);
|
|
@@ -469,6 +508,12 @@ var A2UIClientAdapter = class {
|
|
|
469
508
|
);
|
|
470
509
|
return false;
|
|
471
510
|
}
|
|
511
|
+
const changedFields = envelope.kind === "snapshot" ? [] : changedFieldNames(
|
|
512
|
+
previous,
|
|
513
|
+
candidate,
|
|
514
|
+
envelope.surfaceId,
|
|
515
|
+
nextStructure.get(envelope.surfaceId)
|
|
516
|
+
);
|
|
472
517
|
this.#processor = candidate;
|
|
473
518
|
this.#surfaceOrder = [...candidate.model.surfacesMap.keys()];
|
|
474
519
|
this.#structureBySurface = nextStructure;
|
|
@@ -485,8 +530,20 @@ var A2UIClientAdapter = class {
|
|
|
485
530
|
);
|
|
486
531
|
previous.model.dispose();
|
|
487
532
|
this.#notify();
|
|
533
|
+
if (changedFields.length > 0) {
|
|
534
|
+
this.#emitFieldUpdate({
|
|
535
|
+
surfaceId: envelope.surfaceId,
|
|
536
|
+
fields: changedFields
|
|
537
|
+
});
|
|
538
|
+
}
|
|
488
539
|
return true;
|
|
489
540
|
}
|
|
541
|
+
#emitFieldUpdate(event) {
|
|
542
|
+
this.#options.onFieldUpdate?.(event);
|
|
543
|
+
for (const listener of this.#fieldUpdateListeners) {
|
|
544
|
+
listener(event);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
490
547
|
#createProcessor() {
|
|
491
548
|
return new MessageProcessor(
|
|
492
549
|
[editableDateCatalog],
|
|
@@ -1676,6 +1733,25 @@ function cloneJsonArray(value) {
|
|
|
1676
1733
|
function isFieldValue(value) {
|
|
1677
1734
|
return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
1678
1735
|
}
|
|
1736
|
+
function changedFieldNames(previous, candidate, surfaceId, structure) {
|
|
1737
|
+
const before = previous.model.getSurface(surfaceId);
|
|
1738
|
+
const after = candidate.model.getSurface(surfaceId);
|
|
1739
|
+
if (before === void 0 || after === void 0 || structure === void 0) {
|
|
1740
|
+
return [];
|
|
1741
|
+
}
|
|
1742
|
+
const fields = /* @__PURE__ */ new Set();
|
|
1743
|
+
for (const { field } of structure.fieldsByComponent.values()) {
|
|
1744
|
+
const path = fieldPointer(field);
|
|
1745
|
+
const next = after.dataModel.get(path);
|
|
1746
|
+
if (hasFieldValue(next) && !fieldValueEquivalent(before.dataModel.get(path), next)) {
|
|
1747
|
+
fields.add(field);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
return [...fields];
|
|
1751
|
+
}
|
|
1752
|
+
function hasFieldValue(value) {
|
|
1753
|
+
return Array.isArray(value) ? value.length > 0 : value !== void 0 && value !== null && value !== "";
|
|
1754
|
+
}
|
|
1679
1755
|
function fieldValueEquivalent(left, right) {
|
|
1680
1756
|
if (Array.isArray(left) && Array.isArray(right)) {
|
|
1681
1757
|
return left.length === right.length && left.every((value, index) => Object.is(value, right[index]));
|
|
@@ -1714,13 +1790,14 @@ function classifyProcessingError(error) {
|
|
|
1714
1790
|
// src/SurfaceHost.tsx
|
|
1715
1791
|
import {
|
|
1716
1792
|
Component,
|
|
1717
|
-
|
|
1793
|
+
useEffect,
|
|
1794
|
+
useId as useId3,
|
|
1718
1795
|
useLayoutEffect as useLayoutEffect2,
|
|
1719
1796
|
useRef as useRef2,
|
|
1720
1797
|
useSyncExternalStore
|
|
1721
1798
|
} from "react";
|
|
1722
1799
|
import { A2uiSurface } from "@a2ui/react/v0_9";
|
|
1723
|
-
import { jsx as
|
|
1800
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1724
1801
|
function A2UISurfaceHost({
|
|
1725
1802
|
adapter,
|
|
1726
1803
|
surfaceId,
|
|
@@ -1733,7 +1810,8 @@ function A2UISurfaceHost({
|
|
|
1733
1810
|
invalidFields = [],
|
|
1734
1811
|
validationSummaryId,
|
|
1735
1812
|
noSurfaceFallback,
|
|
1736
|
-
errorFallback
|
|
1813
|
+
errorFallback,
|
|
1814
|
+
onAgentUpdate
|
|
1737
1815
|
}) {
|
|
1738
1816
|
const version = useSyncExternalStore(
|
|
1739
1817
|
adapter.subscribe,
|
|
@@ -1747,17 +1825,31 @@ function A2UISurfaceHost({
|
|
|
1747
1825
|
readSessionSnapshot,
|
|
1748
1826
|
readSessionSnapshot
|
|
1749
1827
|
);
|
|
1750
|
-
const generatedId =
|
|
1828
|
+
const generatedId = useId3().replaceAll(":", "");
|
|
1751
1829
|
const rootRef = useRef2(null);
|
|
1752
1830
|
const lastFocusedState = useRef2(void 0);
|
|
1753
1831
|
const lastViewedSection = useRef2(void 0);
|
|
1754
1832
|
const lastValidationKey = useRef2("");
|
|
1833
|
+
const pendingFieldUpdates = useRef2(/* @__PURE__ */ new Map());
|
|
1834
|
+
const lastCurrentGroupId = useRef2(void 0);
|
|
1835
|
+
const onAgentUpdateRef = useRef2(onAgentUpdate);
|
|
1836
|
+
onAgentUpdateRef.current = onAgentUpdate;
|
|
1755
1837
|
const resolvedSurfaceMetadata = surfaceMetadata ?? controllerSnapshot?.surface ?? null;
|
|
1756
1838
|
const editing = controllerSnapshot?.editing ?? editingForSurface(resolvedSurfaceMetadata);
|
|
1757
1839
|
const surface = surfaceId === void 0 ? adapter.currentSurface : adapter.getSurface(surfaceId);
|
|
1758
1840
|
const structure = surface === void 0 ? EMPTY_STRUCTURE : adapter.getSurfaceStructure(surface.id);
|
|
1759
1841
|
const focusKey = surface === void 0 ? void 0 : `${surface.id}:${resolvedSurfaceMetadata?.activeStateId ?? "surface"}`;
|
|
1760
1842
|
const frameId = hostId ?? `a2ui-surface-${generatedId}`;
|
|
1843
|
+
useEffect(
|
|
1844
|
+
() => adapter.subscribeFieldUpdates((event) => {
|
|
1845
|
+
const pending = pendingFieldUpdates.current.get(event.surfaceId) ?? /* @__PURE__ */ new Set();
|
|
1846
|
+
for (const field of event.fields) {
|
|
1847
|
+
pending.add(field);
|
|
1848
|
+
}
|
|
1849
|
+
pendingFieldUpdates.current.set(event.surfaceId, pending);
|
|
1850
|
+
}),
|
|
1851
|
+
[adapter]
|
|
1852
|
+
);
|
|
1761
1853
|
useLayoutEffect2(() => {
|
|
1762
1854
|
const root = rootRef.current;
|
|
1763
1855
|
if (root === null || surface === void 0) {
|
|
@@ -1800,6 +1892,42 @@ function A2UISurfaceHost({
|
|
|
1800
1892
|
),
|
|
1801
1893
|
setInteractionDisabled(root, disabled || busy)
|
|
1802
1894
|
];
|
|
1895
|
+
reportAgentUpdates();
|
|
1896
|
+
};
|
|
1897
|
+
const reportAgentUpdates = () => {
|
|
1898
|
+
const changedFields = [
|
|
1899
|
+
...pendingFieldUpdates.current.get(surface.id) ?? []
|
|
1900
|
+
];
|
|
1901
|
+
pendingFieldUpdates.current.clear();
|
|
1902
|
+
const currentGroup = resolvedSurfaceMetadata?.fieldInteractions.find(
|
|
1903
|
+
(group) => group.mode === "current"
|
|
1904
|
+
);
|
|
1905
|
+
const previousGroupId = lastCurrentGroupId.current;
|
|
1906
|
+
if (currentGroup !== void 0) {
|
|
1907
|
+
lastCurrentGroupId.current = currentGroup.groupId;
|
|
1908
|
+
}
|
|
1909
|
+
const report = onAgentUpdateRef.current;
|
|
1910
|
+
if (report === void 0) {
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1913
|
+
if (changedFields.length > 0) {
|
|
1914
|
+
report({
|
|
1915
|
+
reason: "field-value",
|
|
1916
|
+
surfaceId: surface.id,
|
|
1917
|
+
fields: changedFields,
|
|
1918
|
+
element: agentUpdateElement(root, changedFields, structure.fields)
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1921
|
+
if (currentGroup !== void 0 && previousGroupId !== void 0 && currentGroup.groupId !== previousGroupId) {
|
|
1922
|
+
const fields = currentGroup.fields.map((binding) => binding.field);
|
|
1923
|
+
report({
|
|
1924
|
+
reason: "current-group",
|
|
1925
|
+
surfaceId: surface.id,
|
|
1926
|
+
fields,
|
|
1927
|
+
groupId: currentGroup.groupId,
|
|
1928
|
+
element: agentUpdateElement(root, fields, structure.fields)
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1803
1931
|
};
|
|
1804
1932
|
const scheduleControlRefresh = () => {
|
|
1805
1933
|
queueMicrotask(refreshControls);
|
|
@@ -1860,9 +1988,9 @@ function A2UISurfaceHost({
|
|
|
1860
1988
|
version
|
|
1861
1989
|
]);
|
|
1862
1990
|
if (surface === void 0) {
|
|
1863
|
-
return noSurfaceFallback ?? /* @__PURE__ */
|
|
1991
|
+
return noSurfaceFallback ?? /* @__PURE__ */ jsx3("div", { "data-a2ui-host": "no-surface", role: "status", "aria-live": "polite", children: "Your conversation continues by voice." });
|
|
1864
1992
|
}
|
|
1865
|
-
return /* @__PURE__ */
|
|
1993
|
+
return /* @__PURE__ */ jsx3(
|
|
1866
1994
|
"div",
|
|
1867
1995
|
{
|
|
1868
1996
|
ref: rootRef,
|
|
@@ -1875,13 +2003,13 @@ function A2UISurfaceHost({
|
|
|
1875
2003
|
"aria-busy": busy || void 0,
|
|
1876
2004
|
"aria-disabled": disabled || busy || void 0,
|
|
1877
2005
|
tabIndex: -1,
|
|
1878
|
-
children: /* @__PURE__ */
|
|
2006
|
+
children: /* @__PURE__ */ jsx3(
|
|
1879
2007
|
SurfaceErrorBoundary,
|
|
1880
2008
|
{
|
|
1881
2009
|
adapter,
|
|
1882
2010
|
surface,
|
|
1883
|
-
fallback: errorFallback ?? /* @__PURE__ */
|
|
1884
|
-
children: /* @__PURE__ */
|
|
2011
|
+
fallback: errorFallback ?? /* @__PURE__ */ jsx3("div", { "data-a2ui-host": "render-error", role: "alert", children: "This step can't be shown right now. Please continue by voice." }),
|
|
2012
|
+
children: /* @__PURE__ */ jsx3(A2uiSurface, { surface })
|
|
1885
2013
|
},
|
|
1886
2014
|
surface.id
|
|
1887
2015
|
)
|
|
@@ -1924,6 +2052,33 @@ function focusProgressTarget(root, metadata, invalidFields) {
|
|
|
1924
2052
|
});
|
|
1925
2053
|
}
|
|
1926
2054
|
}
|
|
2055
|
+
function agentUpdateElement(root, fields, descriptors) {
|
|
2056
|
+
const controls = [
|
|
2057
|
+
...root.querySelectorAll("[data-a2ui-field]")
|
|
2058
|
+
];
|
|
2059
|
+
for (const field of fields) {
|
|
2060
|
+
const control = controls.find(
|
|
2061
|
+
(candidate) => candidate.dataset.a2uiField === field
|
|
2062
|
+
);
|
|
2063
|
+
if (control !== void 0) {
|
|
2064
|
+
return control.closest("[data-a2ui-date-editor]") ?? control.closest('[role="radiogroup"]') ?? control;
|
|
2065
|
+
}
|
|
2066
|
+
const descriptor = descriptors.find(
|
|
2067
|
+
(candidate) => candidate.field === field
|
|
2068
|
+
);
|
|
2069
|
+
const labels = /* @__PURE__ */ new Set([displayFieldLabel(field)]);
|
|
2070
|
+
if (descriptor !== void 0) {
|
|
2071
|
+
labels.add(descriptor.label);
|
|
2072
|
+
}
|
|
2073
|
+
const label = [
|
|
2074
|
+
...root.querySelectorAll("label, strong, legend")
|
|
2075
|
+
].find((candidate) => labels.has(candidate.textContent?.trim() ?? ""));
|
|
2076
|
+
if (label?.parentElement != null && root.contains(label.parentElement)) {
|
|
2077
|
+
return label.parentElement;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
return void 0;
|
|
2081
|
+
}
|
|
1927
2082
|
function isControlDisabled(control) {
|
|
1928
2083
|
return control.getAttribute("aria-disabled") === "true" || "disabled" in control && control.disabled === true;
|
|
1929
2084
|
}
|
|
@@ -2175,7 +2330,7 @@ var SurfaceErrorBoundary = class extends Component {
|
|
|
2175
2330
|
}
|
|
2176
2331
|
render() {
|
|
2177
2332
|
if (this.state.failedSurfaceId !== void 0) {
|
|
2178
|
-
return /* @__PURE__ */
|
|
2333
|
+
return /* @__PURE__ */ jsx3(
|
|
2179
2334
|
"div",
|
|
2180
2335
|
{
|
|
2181
2336
|
"data-a2ui-error-boundary": "true",
|
|
@@ -2393,7 +2548,7 @@ function blockInvalidActionControls(root) {
|
|
|
2393
2548
|
};
|
|
2394
2549
|
}
|
|
2395
2550
|
function firstInvalidInput(root) {
|
|
2396
|
-
return [...root.querySelectorAll("input[data-a2ui-field]")].filter((input) => input.type !== "radio" && !isControlDisabled(input)).find((input) => !input.checkValidity());
|
|
2551
|
+
return [...root.querySelectorAll("input[data-a2ui-field], select[data-a2ui-field]")].filter((input) => input.type !== "radio" && !isControlDisabled(input)).find((input) => !input.checkValidity());
|
|
2397
2552
|
}
|
|
2398
2553
|
function findFieldControls(root, field) {
|
|
2399
2554
|
const labels = [...root.querySelectorAll("label")];
|
|
@@ -2867,11 +3022,23 @@ function renderSavedLoopEditInputs(editButton, row, orderedFields, summaryFields
|
|
|
2867
3022
|
continue;
|
|
2868
3023
|
}
|
|
2869
3024
|
let input = value.querySelector(
|
|
2870
|
-
"
|
|
3025
|
+
"[data-a2ui-loop-edit-input='true']"
|
|
2871
3026
|
);
|
|
2872
3027
|
if (input === null) {
|
|
2873
|
-
|
|
2874
|
-
|
|
3028
|
+
if (fieldName === "hospital_preference") {
|
|
3029
|
+
const select = row.ownerDocument.createElement("select");
|
|
3030
|
+
for (const choice of ["", "Prefer", "Avoid"]) {
|
|
3031
|
+
const option = row.ownerDocument.createElement("option");
|
|
3032
|
+
option.value = choice;
|
|
3033
|
+
option.textContent = choice || "Choose Prefer or Avoid";
|
|
3034
|
+
select.appendChild(option);
|
|
3035
|
+
}
|
|
3036
|
+
select.required = true;
|
|
3037
|
+
input = select;
|
|
3038
|
+
} else {
|
|
3039
|
+
input = row.ownerDocument.createElement("input");
|
|
3040
|
+
input.type = "text";
|
|
3041
|
+
}
|
|
2875
3042
|
input.name = fieldName;
|
|
2876
3043
|
input.setAttribute("aria-label", displayFieldLabel(fieldName));
|
|
2877
3044
|
input.dataset.a2uiLoopEditInput = "true";
|
|
@@ -2897,7 +3064,7 @@ function renderSavedLoopEditInputs(editButton, row, orderedFields, summaryFields
|
|
|
2897
3064
|
setText(editButton, "Save");
|
|
2898
3065
|
if (focusFirstInput) {
|
|
2899
3066
|
row.querySelector(
|
|
2900
|
-
"
|
|
3067
|
+
"[data-a2ui-loop-edit-input='true']"
|
|
2901
3068
|
)?.focus();
|
|
2902
3069
|
}
|
|
2903
3070
|
}
|
|
@@ -2919,7 +3086,7 @@ function savedLoopRowInputValues(orderedFields, summaryFields) {
|
|
|
2919
3086
|
orderedFields.forEach((field, index) => {
|
|
2920
3087
|
const fieldName = summaryFields[index];
|
|
2921
3088
|
const input = field.querySelector(
|
|
2922
|
-
"
|
|
3089
|
+
"[data-a2ui-loop-edit-input='true']"
|
|
2923
3090
|
);
|
|
2924
3091
|
const value = field.querySelector(
|
|
2925
3092
|
"[data-a2ui-loop-cell='value']"
|
|
@@ -3001,7 +3168,7 @@ function normalizedLoopSummaryFields(fields) {
|
|
|
3001
3168
|
if (hasPharmacyFields) {
|
|
3002
3169
|
return pharmacyFields.filter((field) => withoutInternal.includes(field));
|
|
3003
3170
|
}
|
|
3004
|
-
const hospitalFields = ["hospital_name", "hospital_city_state"];
|
|
3171
|
+
const hospitalFields = ["hospital_name", "hospital_city_state", "hospital_preference"];
|
|
3005
3172
|
const hasHospitalFields = hospitalFields.some(
|
|
3006
3173
|
(field) => withoutInternal.includes(field)
|
|
3007
3174
|
);
|
|
@@ -3117,7 +3284,8 @@ var LOOP_FIELD_LABELS = /* @__PURE__ */ new Map([
|
|
|
3117
3284
|
["pharmacy type", "pharmacy_type"],
|
|
3118
3285
|
["pharmacy address", "pharmacy_address"],
|
|
3119
3286
|
["hospital name", "hospital_name"],
|
|
3120
|
-
["hospital city state", "hospital_city_state"]
|
|
3287
|
+
["hospital city state", "hospital_city_state"],
|
|
3288
|
+
["hospital preference", "hospital_preference"]
|
|
3121
3289
|
]);
|
|
3122
3290
|
function isSavedLoopSummary(element) {
|
|
3123
3291
|
if (element.children.length > 0) {
|