@ukiahinsure/a2ui-react-adapter 0.1.18 → 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
|
@@ -220,6 +220,7 @@ var A2UIClientAdapter = class {
|
|
|
220
220
|
#listeners = /* @__PURE__ */ new Set();
|
|
221
221
|
#actionListeners = /* @__PURE__ */ new Set();
|
|
222
222
|
#errorListeners = /* @__PURE__ */ new Set();
|
|
223
|
+
#fieldUpdateListeners = /* @__PURE__ */ new Set();
|
|
223
224
|
#surfaceOrder = [];
|
|
224
225
|
#structureBySurface = /* @__PURE__ */ new Map();
|
|
225
226
|
#persistedListRowsByPath = /* @__PURE__ */ new Map();
|
|
@@ -420,6 +421,10 @@ var A2UIClientAdapter = class {
|
|
|
420
421
|
this.#errorListeners.add(listener);
|
|
421
422
|
return () => this.#errorListeners.delete(listener);
|
|
422
423
|
};
|
|
424
|
+
subscribeFieldUpdates = (listener) => {
|
|
425
|
+
this.#fieldUpdateListeners.add(listener);
|
|
426
|
+
return () => this.#fieldUpdateListeners.delete(listener);
|
|
427
|
+
};
|
|
423
428
|
/** Monotonic change counter for `useSyncExternalStore`. */
|
|
424
429
|
getVersion = () => this.#version;
|
|
425
430
|
dispose() {
|
|
@@ -436,6 +441,7 @@ var A2UIClientAdapter = class {
|
|
|
436
441
|
this.#listeners.clear();
|
|
437
442
|
this.#actionListeners.clear();
|
|
438
443
|
this.#errorListeners.clear();
|
|
444
|
+
this.#fieldUpdateListeners.clear();
|
|
439
445
|
}
|
|
440
446
|
#applySurfaceEnvelope(envelope) {
|
|
441
447
|
const validated = A2uiMessageListSchema.safeParse(envelope.messages);
|
|
@@ -502,6 +508,12 @@ var A2UIClientAdapter = class {
|
|
|
502
508
|
);
|
|
503
509
|
return false;
|
|
504
510
|
}
|
|
511
|
+
const changedFields = envelope.kind === "snapshot" ? [] : changedFieldNames(
|
|
512
|
+
previous,
|
|
513
|
+
candidate,
|
|
514
|
+
envelope.surfaceId,
|
|
515
|
+
nextStructure.get(envelope.surfaceId)
|
|
516
|
+
);
|
|
505
517
|
this.#processor = candidate;
|
|
506
518
|
this.#surfaceOrder = [...candidate.model.surfacesMap.keys()];
|
|
507
519
|
this.#structureBySurface = nextStructure;
|
|
@@ -518,8 +530,20 @@ var A2UIClientAdapter = class {
|
|
|
518
530
|
);
|
|
519
531
|
previous.model.dispose();
|
|
520
532
|
this.#notify();
|
|
533
|
+
if (changedFields.length > 0) {
|
|
534
|
+
this.#emitFieldUpdate({
|
|
535
|
+
surfaceId: envelope.surfaceId,
|
|
536
|
+
fields: changedFields
|
|
537
|
+
});
|
|
538
|
+
}
|
|
521
539
|
return true;
|
|
522
540
|
}
|
|
541
|
+
#emitFieldUpdate(event) {
|
|
542
|
+
this.#options.onFieldUpdate?.(event);
|
|
543
|
+
for (const listener of this.#fieldUpdateListeners) {
|
|
544
|
+
listener(event);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
523
547
|
#createProcessor() {
|
|
524
548
|
return new MessageProcessor(
|
|
525
549
|
[editableDateCatalog],
|
|
@@ -1709,6 +1733,25 @@ function cloneJsonArray(value) {
|
|
|
1709
1733
|
function isFieldValue(value) {
|
|
1710
1734
|
return value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
1711
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
|
+
}
|
|
1712
1755
|
function fieldValueEquivalent(left, right) {
|
|
1713
1756
|
if (Array.isArray(left) && Array.isArray(right)) {
|
|
1714
1757
|
return left.length === right.length && left.every((value, index) => Object.is(value, right[index]));
|
|
@@ -1747,6 +1790,7 @@ function classifyProcessingError(error) {
|
|
|
1747
1790
|
// src/SurfaceHost.tsx
|
|
1748
1791
|
import {
|
|
1749
1792
|
Component,
|
|
1793
|
+
useEffect,
|
|
1750
1794
|
useId as useId3,
|
|
1751
1795
|
useLayoutEffect as useLayoutEffect2,
|
|
1752
1796
|
useRef as useRef2,
|
|
@@ -1766,7 +1810,8 @@ function A2UISurfaceHost({
|
|
|
1766
1810
|
invalidFields = [],
|
|
1767
1811
|
validationSummaryId,
|
|
1768
1812
|
noSurfaceFallback,
|
|
1769
|
-
errorFallback
|
|
1813
|
+
errorFallback,
|
|
1814
|
+
onAgentUpdate
|
|
1770
1815
|
}) {
|
|
1771
1816
|
const version = useSyncExternalStore(
|
|
1772
1817
|
adapter.subscribe,
|
|
@@ -1785,12 +1830,26 @@ function A2UISurfaceHost({
|
|
|
1785
1830
|
const lastFocusedState = useRef2(void 0);
|
|
1786
1831
|
const lastViewedSection = useRef2(void 0);
|
|
1787
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;
|
|
1788
1837
|
const resolvedSurfaceMetadata = surfaceMetadata ?? controllerSnapshot?.surface ?? null;
|
|
1789
1838
|
const editing = controllerSnapshot?.editing ?? editingForSurface(resolvedSurfaceMetadata);
|
|
1790
1839
|
const surface = surfaceId === void 0 ? adapter.currentSurface : adapter.getSurface(surfaceId);
|
|
1791
1840
|
const structure = surface === void 0 ? EMPTY_STRUCTURE : adapter.getSurfaceStructure(surface.id);
|
|
1792
1841
|
const focusKey = surface === void 0 ? void 0 : `${surface.id}:${resolvedSurfaceMetadata?.activeStateId ?? "surface"}`;
|
|
1793
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
|
+
);
|
|
1794
1853
|
useLayoutEffect2(() => {
|
|
1795
1854
|
const root = rootRef.current;
|
|
1796
1855
|
if (root === null || surface === void 0) {
|
|
@@ -1833,6 +1892,42 @@ function A2UISurfaceHost({
|
|
|
1833
1892
|
),
|
|
1834
1893
|
setInteractionDisabled(root, disabled || busy)
|
|
1835
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
|
+
}
|
|
1836
1931
|
};
|
|
1837
1932
|
const scheduleControlRefresh = () => {
|
|
1838
1933
|
queueMicrotask(refreshControls);
|
|
@@ -1957,6 +2052,33 @@ function focusProgressTarget(root, metadata, invalidFields) {
|
|
|
1957
2052
|
});
|
|
1958
2053
|
}
|
|
1959
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
|
+
}
|
|
1960
2082
|
function isControlDisabled(control) {
|
|
1961
2083
|
return control.getAttribute("aria-disabled") === "true" || "disabled" in control && control.disabled === true;
|
|
1962
2084
|
}
|