@ukiahinsure/a2ui-react-adapter 0.1.12 → 0.1.14
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.js
CHANGED
|
@@ -13,9 +13,65 @@ import {
|
|
|
13
13
|
import { basicCatalog } from "@a2ui/react/v0_9";
|
|
14
14
|
import {
|
|
15
15
|
A2uiError,
|
|
16
|
+
Catalog,
|
|
16
17
|
A2uiMessageListSchema,
|
|
17
18
|
MessageProcessor
|
|
18
19
|
} from "@a2ui/web_core/v0_9";
|
|
20
|
+
|
|
21
|
+
// src/DateTimeInput.tsx
|
|
22
|
+
import { useId, useLayoutEffect, useRef } from "react";
|
|
23
|
+
import { createComponentImplementation } from "@a2ui/react/v0_9";
|
|
24
|
+
import { DateTimeInputApi } from "@a2ui/web_core/v0_9/basic_catalog";
|
|
25
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
26
|
+
var DateTimeInput = createComponentImplementation(
|
|
27
|
+
DateTimeInputApi,
|
|
28
|
+
({ props }) => {
|
|
29
|
+
const id = useId();
|
|
30
|
+
const inputRef = useRef(null);
|
|
31
|
+
const initialValue = useRef(props.value || "");
|
|
32
|
+
const type = props.enableDate && !props.enableTime ? "date" : !props.enableDate && props.enableTime ? "time" : "datetime-local";
|
|
33
|
+
useLayoutEffect(() => {
|
|
34
|
+
const input = inputRef.current;
|
|
35
|
+
if (input && input.ownerDocument.activeElement !== input && input.value !== (props.value || "")) {
|
|
36
|
+
input.value = props.value || "";
|
|
37
|
+
}
|
|
38
|
+
}, [props.value]);
|
|
39
|
+
return /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--a2ui-spacing-xs, 0.25rem)" }, children: [
|
|
40
|
+
props.label && /* @__PURE__ */ jsx("label", { htmlFor: id, style: { fontSize: "var(--a2ui-label-font-size, var(--a2ui-font-size-s))", fontWeight: "bold" }, children: props.label }),
|
|
41
|
+
/* @__PURE__ */ jsx(
|
|
42
|
+
"input",
|
|
43
|
+
{
|
|
44
|
+
ref: inputRef,
|
|
45
|
+
id,
|
|
46
|
+
type,
|
|
47
|
+
"data-a2ui-native-date-draft": "true",
|
|
48
|
+
defaultValue: initialValue.current,
|
|
49
|
+
onChange: (event) => props.setValue(event.currentTarget.value),
|
|
50
|
+
min: typeof props.min === "string" ? props.min : void 0,
|
|
51
|
+
max: typeof props.max === "string" ? props.max : void 0,
|
|
52
|
+
style: {
|
|
53
|
+
backgroundColor: "var(--a2ui-datetimeinput-background, var(--a2ui-color-input, #fff))",
|
|
54
|
+
color: "var(--a2ui-datetimeinput-color, var(--a2ui-color-on-input, #333))",
|
|
55
|
+
border: "var(--a2ui-datetimeinput-border, var(--a2ui-border))",
|
|
56
|
+
borderRadius: "var(--a2ui-datetimeinput-border-radius, var(--a2ui-border-radius))",
|
|
57
|
+
padding: "var(--a2ui-datetimeinput-padding, var(--a2ui-spacing-s))",
|
|
58
|
+
boxSizing: "border-box"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] });
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// src/adapter.ts
|
|
67
|
+
var editableDateCatalog = new Catalog(
|
|
68
|
+
basicCatalog.id,
|
|
69
|
+
[...basicCatalog.components.values()].map(
|
|
70
|
+
(component) => component.name === DateTimeInput.name ? DateTimeInput : component
|
|
71
|
+
),
|
|
72
|
+
[...basicCatalog.functions.values()],
|
|
73
|
+
basicCatalog.themeSchema
|
|
74
|
+
);
|
|
19
75
|
var RENDERER_NAME = "a2ui_react_adapter";
|
|
20
76
|
var RENDERER_VERSION = "0.1.0";
|
|
21
77
|
var A2UIClientAdapter = class {
|
|
@@ -30,6 +86,9 @@ var A2UIClientAdapter = class {
|
|
|
30
86
|
#structureBySurface = /* @__PURE__ */ new Map();
|
|
31
87
|
#persistedListRowsByPath = /* @__PURE__ */ new Map();
|
|
32
88
|
#deletedListItemIdsByPath = /* @__PURE__ */ new Map();
|
|
89
|
+
#stagedListRowUpdatesBySurface = /* @__PURE__ */ new Map();
|
|
90
|
+
#activeListRowEditsBySurface = /* @__PURE__ */ new Map();
|
|
91
|
+
#optimisticListRowsByPath = /* @__PURE__ */ new Map();
|
|
33
92
|
#version = 0;
|
|
34
93
|
#lastSeq = 0;
|
|
35
94
|
#disposed = false;
|
|
@@ -105,6 +164,38 @@ var A2UIClientAdapter = class {
|
|
|
105
164
|
}
|
|
106
165
|
return true;
|
|
107
166
|
}
|
|
167
|
+
stageListRowUpdate(surfaceId, values) {
|
|
168
|
+
this.#stagedListRowUpdatesBySurface.set(surfaceId, { ...values });
|
|
169
|
+
}
|
|
170
|
+
beginListRowEdit(surfaceId, rowKey, values) {
|
|
171
|
+
let edits = this.#activeListRowEditsBySurface.get(surfaceId);
|
|
172
|
+
if (edits === void 0) {
|
|
173
|
+
edits = /* @__PURE__ */ new Map();
|
|
174
|
+
this.#activeListRowEditsBySurface.set(surfaceId, edits);
|
|
175
|
+
}
|
|
176
|
+
edits.set(rowKey, { ...values });
|
|
177
|
+
}
|
|
178
|
+
updateListRowEdit(surfaceId, rowKey, values) {
|
|
179
|
+
const edits = this.#activeListRowEditsBySurface.get(surfaceId);
|
|
180
|
+
if (edits?.has(rowKey) !== true) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
edits.set(rowKey, { ...values });
|
|
184
|
+
}
|
|
185
|
+
getListRowEdit(surfaceId, rowKey) {
|
|
186
|
+
const values = this.#activeListRowEditsBySurface.get(surfaceId)?.get(rowKey);
|
|
187
|
+
return values === void 0 ? void 0 : { ...values };
|
|
188
|
+
}
|
|
189
|
+
clearListRowEdit(surfaceId, rowKey) {
|
|
190
|
+
const edits = this.#activeListRowEditsBySurface.get(surfaceId);
|
|
191
|
+
if (edits === void 0) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
edits.delete(rowKey);
|
|
195
|
+
if (edits.size === 0) {
|
|
196
|
+
this.#activeListRowEditsBySurface.delete(surfaceId);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
108
199
|
#dataModelValueForField(surfaceId, field, value) {
|
|
109
200
|
const descriptor = this.#fieldDescriptor(surfaceId, field);
|
|
110
201
|
if (descriptor?.control === "choice" && typeof value === "string" && value.length > 0) {
|
|
@@ -159,6 +250,8 @@ var A2UIClientAdapter = class {
|
|
|
159
250
|
this.#structureBySurface.clear();
|
|
160
251
|
this.#persistedListRowsByPath.clear();
|
|
161
252
|
this.#deletedListItemIdsByPath.clear();
|
|
253
|
+
this.#activeListRowEditsBySurface.clear();
|
|
254
|
+
this.#optimisticListRowsByPath.clear();
|
|
162
255
|
previous.model.dispose();
|
|
163
256
|
this.#notify();
|
|
164
257
|
}
|
|
@@ -198,6 +291,10 @@ var A2UIClientAdapter = class {
|
|
|
198
291
|
this.#disposed = true;
|
|
199
292
|
this.#processor.model.dispose();
|
|
200
293
|
this.#structureBySurface.clear();
|
|
294
|
+
this.#persistedListRowsByPath.clear();
|
|
295
|
+
this.#deletedListItemIdsByPath.clear();
|
|
296
|
+
this.#activeListRowEditsBySurface.clear();
|
|
297
|
+
this.#optimisticListRowsByPath.clear();
|
|
201
298
|
this.#listeners.clear();
|
|
202
299
|
this.#actionListeners.clear();
|
|
203
300
|
this.#errorListeners.clear();
|
|
@@ -216,7 +313,8 @@ var A2UIClientAdapter = class {
|
|
|
216
313
|
validated.data,
|
|
217
314
|
envelope.surfaceId,
|
|
218
315
|
this.#persistedListRowsByPath,
|
|
219
|
-
this.#deletedListItemIdsByPath
|
|
316
|
+
this.#deletedListItemIdsByPath,
|
|
317
|
+
this.#optimisticListRowsByPath
|
|
220
318
|
);
|
|
221
319
|
const listAddFreeMessages = removeListAddActionMessages(
|
|
222
320
|
rawMessages,
|
|
@@ -272,6 +370,8 @@ var A2UIClientAdapter = class {
|
|
|
272
370
|
if (envelope.kind === "snapshot") {
|
|
273
371
|
this.#persistedListRowsByPath.clear();
|
|
274
372
|
this.#deletedListItemIdsByPath.clear();
|
|
373
|
+
this.#activeListRowEditsBySurface.clear();
|
|
374
|
+
this.#optimisticListRowsByPath.clear();
|
|
275
375
|
}
|
|
276
376
|
rememberPersistedListRows(
|
|
277
377
|
this.#persistedListRowsByPath,
|
|
@@ -284,7 +384,7 @@ var A2UIClientAdapter = class {
|
|
|
284
384
|
}
|
|
285
385
|
#createProcessor() {
|
|
286
386
|
return new MessageProcessor(
|
|
287
|
-
[
|
|
387
|
+
[editableDateCatalog],
|
|
288
388
|
(action) => this.#emitAction(action)
|
|
289
389
|
);
|
|
290
390
|
}
|
|
@@ -297,11 +397,18 @@ var A2UIClientAdapter = class {
|
|
|
297
397
|
);
|
|
298
398
|
return;
|
|
299
399
|
}
|
|
400
|
+
const stagedListRowUpdate = action.name === "flow.list.update" ? this.#stagedListRowUpdatesBySurface.get(action.surfaceId) : void 0;
|
|
401
|
+
if (stagedListRowUpdate !== void 0) {
|
|
402
|
+
this.#stagedListRowUpdatesBySurface.delete(action.surfaceId);
|
|
403
|
+
}
|
|
300
404
|
const event = {
|
|
301
405
|
actionName: action.name,
|
|
302
406
|
surfaceId: action.surfaceId,
|
|
303
407
|
sourceComponentId: action.sourceComponentId,
|
|
304
|
-
context: {
|
|
408
|
+
context: {
|
|
409
|
+
...action.context,
|
|
410
|
+
...stagedListRowUpdate ?? {}
|
|
411
|
+
}
|
|
305
412
|
};
|
|
306
413
|
const submittedProviderRow = submittedProviderRowFromEvent(event);
|
|
307
414
|
if (submittedProviderRow !== void 0) {
|
|
@@ -314,6 +421,9 @@ var A2UIClientAdapter = class {
|
|
|
314
421
|
if (event.actionName === "flow.list.delete") {
|
|
315
422
|
this.#removeDeletedListRow(event.surfaceId, event.context);
|
|
316
423
|
}
|
|
424
|
+
if (event.actionName === "flow.list.update") {
|
|
425
|
+
this.#updateListRow(event.surfaceId, event.context);
|
|
426
|
+
}
|
|
317
427
|
this.#options.onAction?.(event);
|
|
318
428
|
for (const listener of this.#actionListeners) {
|
|
319
429
|
listener(event);
|
|
@@ -348,6 +458,7 @@ var A2UIClientAdapter = class {
|
|
|
348
458
|
const cachedRows = this.#persistedListRowsByPath.get(listPath) ?? [];
|
|
349
459
|
const nextRows = removeListRowByItemId(cachedRows, itemId);
|
|
350
460
|
this.#persistedListRowsByPath.set(listPath, nextRows);
|
|
461
|
+
this.#optimisticListRowsByPath.get(listPath)?.delete(itemId);
|
|
351
462
|
rememberDeletedListItemId(this.#deletedListItemIdsByPath, listPath, itemId);
|
|
352
463
|
const surface = this.#processor.model.getSurface(surfaceId);
|
|
353
464
|
if (surface === void 0) {
|
|
@@ -360,6 +471,39 @@ var A2UIClientAdapter = class {
|
|
|
360
471
|
);
|
|
361
472
|
this.#notify();
|
|
362
473
|
}
|
|
474
|
+
#updateListRow(surfaceId, context) {
|
|
475
|
+
const listPath = context.listPath;
|
|
476
|
+
const itemId = context.itemId;
|
|
477
|
+
if (typeof listPath !== "string" || listPath.length === 0 || typeof itemId !== "string" || itemId.length === 0) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
const cachedRows = this.#persistedListRowsByPath.get(listPath) ?? [];
|
|
481
|
+
const existingRow = cachedRows.find(
|
|
482
|
+
(candidate) => isRecord(candidate) && candidate.itemId === itemId
|
|
483
|
+
);
|
|
484
|
+
const row = updateListRowFromContext(context, existingRow);
|
|
485
|
+
if (row === void 0) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const rows = normalizeListRows(listPath, upsertListRow(cachedRows, row));
|
|
489
|
+
this.#persistedListRowsByPath.set(listPath, rows);
|
|
490
|
+
let optimisticRows = this.#optimisticListRowsByPath.get(listPath);
|
|
491
|
+
if (optimisticRows === void 0) {
|
|
492
|
+
optimisticRows = /* @__PURE__ */ new Map();
|
|
493
|
+
this.#optimisticListRowsByPath.set(listPath, optimisticRows);
|
|
494
|
+
}
|
|
495
|
+
optimisticRows.set(itemId, cloneJsonRecord(row));
|
|
496
|
+
const surface = this.#processor.model.getSurface(surfaceId);
|
|
497
|
+
if (surface === void 0) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
surface.dataModel.set(`/${listPath}`, cloneJsonArray(rows));
|
|
501
|
+
surface.dataModel.set(
|
|
502
|
+
`/${listPath.replaceAll(".", "/")}`,
|
|
503
|
+
cloneJsonArray(rows)
|
|
504
|
+
);
|
|
505
|
+
this.#notify();
|
|
506
|
+
}
|
|
363
507
|
#snapshotMessages() {
|
|
364
508
|
const messages = [];
|
|
365
509
|
for (const surface of this.#processor.model.surfacesMap.values()) {
|
|
@@ -859,8 +1003,8 @@ function fieldFromPointer(path) {
|
|
|
859
1003
|
function fieldPointer(field) {
|
|
860
1004
|
return `/${field.replaceAll("~", "~0").replaceAll("/", "~1")}`;
|
|
861
1005
|
}
|
|
862
|
-
function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsByPath, deletedItemIdsByPath) {
|
|
863
|
-
if (persistedRowsByPath.size === 0 && deletedItemIdsByPath.size === 0) {
|
|
1006
|
+
function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsByPath, deletedItemIdsByPath, optimisticRowsByPath) {
|
|
1007
|
+
if (persistedRowsByPath.size === 0 && deletedItemIdsByPath.size === 0 && optimisticRowsByPath.size === 0) {
|
|
864
1008
|
return [...messages];
|
|
865
1009
|
}
|
|
866
1010
|
let mergedRoot = false;
|
|
@@ -876,7 +1020,8 @@ function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsBy
|
|
|
876
1020
|
value: mergePersistedListRowsIntoRoot(
|
|
877
1021
|
message.updateDataModel.value,
|
|
878
1022
|
persistedRowsByPath,
|
|
879
|
-
deletedItemIdsByPath
|
|
1023
|
+
deletedItemIdsByPath,
|
|
1024
|
+
optimisticRowsByPath
|
|
880
1025
|
)
|
|
881
1026
|
}
|
|
882
1027
|
};
|
|
@@ -894,26 +1039,33 @@ function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsBy
|
|
|
894
1039
|
value: mergePersistedListRowsIntoRoot(
|
|
895
1040
|
{},
|
|
896
1041
|
persistedRowsByPath,
|
|
897
|
-
deletedItemIdsByPath
|
|
1042
|
+
deletedItemIdsByPath,
|
|
1043
|
+
optimisticRowsByPath
|
|
898
1044
|
)
|
|
899
1045
|
}
|
|
900
1046
|
}
|
|
901
1047
|
];
|
|
902
1048
|
}
|
|
903
|
-
function mergePersistedListRowsIntoRoot(root, persistedRowsByPath, deletedItemIdsByPath) {
|
|
1049
|
+
function mergePersistedListRowsIntoRoot(root, persistedRowsByPath, deletedItemIdsByPath, optimisticRowsByPath) {
|
|
904
1050
|
const merged = cloneJsonRecord(root);
|
|
905
1051
|
for (const listPath of /* @__PURE__ */ new Set([
|
|
906
1052
|
...persistedRowsByPath.keys(),
|
|
907
|
-
...deletedItemIdsByPath.keys()
|
|
1053
|
+
...deletedItemIdsByPath.keys(),
|
|
1054
|
+
...optimisticRowsByPath.keys()
|
|
908
1055
|
])) {
|
|
909
1056
|
const rows = persistedRowsByPath.get(listPath) ?? [];
|
|
1057
|
+
const optimisticRows = optimisticRowsByPath.get(listPath);
|
|
910
1058
|
const dottedRows = merged[listPath];
|
|
911
1059
|
const nestedRows = getNestedValue(merged, listPath);
|
|
912
1060
|
const incomingRows = Array.isArray(dottedRows) ? dottedRows : Array.isArray(nestedRows) ? nestedRows : void 0;
|
|
913
1061
|
const shouldPreserveCachedRows = rows.length > 0 && (incomingRows === void 0 || incomingRows.length === 0 && (!hasListDraft(merged, listPath) || hasBlankListDraft(merged, listPath)));
|
|
914
1062
|
const effectiveRows = shouldPreserveCachedRows ? rows : incomingRows ?? rows;
|
|
915
|
-
const
|
|
1063
|
+
const optimisticEffectiveRows = mergeOptimisticListRows(
|
|
916
1064
|
effectiveRows,
|
|
1065
|
+
optimisticRows
|
|
1066
|
+
);
|
|
1067
|
+
const visibleRows = filterDeletedListRows(
|
|
1068
|
+
optimisticEffectiveRows,
|
|
917
1069
|
deletedItemIdsByPath.get(listPath)
|
|
918
1070
|
);
|
|
919
1071
|
const normalizedRows = normalizeListRows(listPath, visibleRows, merged);
|
|
@@ -949,6 +1101,16 @@ function isBlankDraftValue(value) {
|
|
|
949
1101
|
}
|
|
950
1102
|
return false;
|
|
951
1103
|
}
|
|
1104
|
+
function mergeOptimisticListRows(rows, optimisticRows) {
|
|
1105
|
+
if (optimisticRows === void 0 || optimisticRows.size === 0) {
|
|
1106
|
+
return cloneJsonArray(rows);
|
|
1107
|
+
}
|
|
1108
|
+
let merged = cloneJsonArray(rows);
|
|
1109
|
+
for (const row of optimisticRows.values()) {
|
|
1110
|
+
merged = upsertListRow(merged, cloneJsonRecord(row));
|
|
1111
|
+
}
|
|
1112
|
+
return merged;
|
|
1113
|
+
}
|
|
952
1114
|
function rememberPersistedListRows(persistedRowsByPath, deletedItemIdsByPath, root) {
|
|
953
1115
|
if (!isRecord(root)) {
|
|
954
1116
|
return;
|
|
@@ -1192,6 +1354,35 @@ function isProviderSubmitLabel(label) {
|
|
|
1192
1354
|
function normalizeFieldKey(key) {
|
|
1193
1355
|
return key.trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "_").replaceAll(/^_+|_+$/g, "");
|
|
1194
1356
|
}
|
|
1357
|
+
function updateListRowFromContext(context, existingRow) {
|
|
1358
|
+
const itemId = context.itemId;
|
|
1359
|
+
if (typeof itemId !== "string" || itemId.length === 0) {
|
|
1360
|
+
return void 0;
|
|
1361
|
+
}
|
|
1362
|
+
const row = isRecord(existingRow) ? cloneJsonRecord(existingRow) : {};
|
|
1363
|
+
row.itemId = itemId;
|
|
1364
|
+
let hasUpdate = false;
|
|
1365
|
+
for (const [key, value] of Object.entries(context)) {
|
|
1366
|
+
if (key === "listPath" || key === "itemId" || !isFieldValue(value)) {
|
|
1367
|
+
continue;
|
|
1368
|
+
}
|
|
1369
|
+
row[key] = value;
|
|
1370
|
+
hasUpdate = true;
|
|
1371
|
+
}
|
|
1372
|
+
if (!hasUpdate) {
|
|
1373
|
+
return void 0;
|
|
1374
|
+
}
|
|
1375
|
+
row.__displayText = listRowDisplayText(row);
|
|
1376
|
+
return row;
|
|
1377
|
+
}
|
|
1378
|
+
function listRowDisplayText(row) {
|
|
1379
|
+
return Object.entries(row).filter(([key, value]) => {
|
|
1380
|
+
if (key === "itemId" || key === "__displayText" || value === null) {
|
|
1381
|
+
return false;
|
|
1382
|
+
}
|
|
1383
|
+
return isFieldValue(value) && String(value).trim().length > 0;
|
|
1384
|
+
}).map(([key, value]) => `${key}: ${String(value).trim()}`).join(" | ");
|
|
1385
|
+
}
|
|
1195
1386
|
function upsertListRow(rows, row) {
|
|
1196
1387
|
const itemId = row.itemId;
|
|
1197
1388
|
if (typeof itemId !== "string" || itemId.length === 0) {
|
|
@@ -1434,13 +1625,13 @@ function classifyProcessingError(error) {
|
|
|
1434
1625
|
// src/SurfaceHost.tsx
|
|
1435
1626
|
import {
|
|
1436
1627
|
Component,
|
|
1437
|
-
useId,
|
|
1438
|
-
useLayoutEffect,
|
|
1439
|
-
useRef,
|
|
1628
|
+
useId as useId2,
|
|
1629
|
+
useLayoutEffect as useLayoutEffect2,
|
|
1630
|
+
useRef as useRef2,
|
|
1440
1631
|
useSyncExternalStore
|
|
1441
1632
|
} from "react";
|
|
1442
1633
|
import { A2uiSurface } from "@a2ui/react/v0_9";
|
|
1443
|
-
import { jsx } from "react/jsx-runtime";
|
|
1634
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1444
1635
|
function A2UISurfaceHost({
|
|
1445
1636
|
adapter,
|
|
1446
1637
|
surfaceId,
|
|
@@ -1467,18 +1658,18 @@ function A2UISurfaceHost({
|
|
|
1467
1658
|
readSessionSnapshot,
|
|
1468
1659
|
readSessionSnapshot
|
|
1469
1660
|
);
|
|
1470
|
-
const generatedId =
|
|
1471
|
-
const rootRef =
|
|
1472
|
-
const lastFocusedState =
|
|
1473
|
-
const lastViewedSection =
|
|
1474
|
-
const lastValidationKey =
|
|
1661
|
+
const generatedId = useId2().replaceAll(":", "");
|
|
1662
|
+
const rootRef = useRef2(null);
|
|
1663
|
+
const lastFocusedState = useRef2(void 0);
|
|
1664
|
+
const lastViewedSection = useRef2(void 0);
|
|
1665
|
+
const lastValidationKey = useRef2("");
|
|
1475
1666
|
const resolvedSurfaceMetadata = surfaceMetadata ?? controllerSnapshot?.surface ?? null;
|
|
1476
1667
|
const editing = controllerSnapshot?.editing ?? editingForSurface(resolvedSurfaceMetadata);
|
|
1477
1668
|
const surface = surfaceId === void 0 ? adapter.currentSurface : adapter.getSurface(surfaceId);
|
|
1478
1669
|
const structure = surface === void 0 ? EMPTY_STRUCTURE : adapter.getSurfaceStructure(surface.id);
|
|
1479
1670
|
const focusKey = surface === void 0 ? void 0 : `${surface.id}:${resolvedSurfaceMetadata?.activeStateId ?? "surface"}`;
|
|
1480
1671
|
const frameId = hostId ?? `a2ui-surface-${generatedId}`;
|
|
1481
|
-
|
|
1672
|
+
useLayoutEffect2(() => {
|
|
1482
1673
|
const root = rootRef.current;
|
|
1483
1674
|
if (root === null || surface === void 0) {
|
|
1484
1675
|
return;
|
|
@@ -1500,7 +1691,7 @@ function A2UISurfaceHost({
|
|
|
1500
1691
|
validationSummaryId
|
|
1501
1692
|
),
|
|
1502
1693
|
formatFieldLabels(root),
|
|
1503
|
-
annotateSavedLoopTables(root),
|
|
1694
|
+
annotateSavedLoopTables(root, adapter, surface.id),
|
|
1504
1695
|
bindFieldInteractionGroups(
|
|
1505
1696
|
root,
|
|
1506
1697
|
resolvedSurfaceMetadata?.fieldInteractions ?? [],
|
|
@@ -1580,9 +1771,9 @@ function A2UISurfaceHost({
|
|
|
1580
1771
|
version
|
|
1581
1772
|
]);
|
|
1582
1773
|
if (surface === void 0) {
|
|
1583
|
-
return noSurfaceFallback ?? /* @__PURE__ */
|
|
1774
|
+
return noSurfaceFallback ?? /* @__PURE__ */ jsx2("div", { "data-a2ui-host": "no-surface", role: "status", "aria-live": "polite", children: "Your conversation continues by voice." });
|
|
1584
1775
|
}
|
|
1585
|
-
return /* @__PURE__ */
|
|
1776
|
+
return /* @__PURE__ */ jsx2(
|
|
1586
1777
|
"div",
|
|
1587
1778
|
{
|
|
1588
1779
|
ref: rootRef,
|
|
@@ -1595,13 +1786,13 @@ function A2UISurfaceHost({
|
|
|
1595
1786
|
"aria-busy": busy || void 0,
|
|
1596
1787
|
"aria-disabled": disabled || busy || void 0,
|
|
1597
1788
|
tabIndex: -1,
|
|
1598
|
-
children: /* @__PURE__ */
|
|
1789
|
+
children: /* @__PURE__ */ jsx2(
|
|
1599
1790
|
SurfaceErrorBoundary,
|
|
1600
1791
|
{
|
|
1601
1792
|
adapter,
|
|
1602
1793
|
surface,
|
|
1603
|
-
fallback: errorFallback ?? /* @__PURE__ */
|
|
1604
|
-
children: /* @__PURE__ */
|
|
1794
|
+
fallback: errorFallback ?? /* @__PURE__ */ jsx2("div", { "data-a2ui-host": "render-error", role: "alert", children: "This step can't be shown right now. Please continue by voice." }),
|
|
1795
|
+
children: /* @__PURE__ */ jsx2(A2uiSurface, { surface })
|
|
1605
1796
|
},
|
|
1606
1797
|
surface.id
|
|
1607
1798
|
)
|
|
@@ -1887,7 +2078,7 @@ var SurfaceErrorBoundary = class extends Component {
|
|
|
1887
2078
|
}
|
|
1888
2079
|
render() {
|
|
1889
2080
|
if (this.state.failedSurfaceId !== void 0) {
|
|
1890
|
-
return /* @__PURE__ */
|
|
2081
|
+
return /* @__PURE__ */ jsx2(
|
|
1891
2082
|
"div",
|
|
1892
2083
|
{
|
|
1893
2084
|
"data-a2ui-error-boundary": "true",
|
|
@@ -2188,9 +2379,10 @@ function generatedFieldLabelName(text) {
|
|
|
2188
2379
|
const unwrapped = trimmed.startsWith("*") && trimmed.endsWith("*") ? trimmed.slice(1, -1).trim() : trimmed;
|
|
2189
2380
|
return /^[A-Za-z][A-Za-z0-9_]*$/.test(unwrapped) && /[_A-Z]/.test(unwrapped) ? unwrapped : void 0;
|
|
2190
2381
|
}
|
|
2191
|
-
function annotateSavedLoopTables(root) {
|
|
2382
|
+
function annotateSavedLoopTables(root, adapter, surfaceId) {
|
|
2192
2383
|
const originals = /* @__PURE__ */ new Map();
|
|
2193
2384
|
const textOriginals = /* @__PURE__ */ new Map();
|
|
2385
|
+
const listeners = [];
|
|
2194
2386
|
const remember = (element) => {
|
|
2195
2387
|
if (originals.has(element)) {
|
|
2196
2388
|
return;
|
|
@@ -2205,6 +2397,7 @@ function annotateSavedLoopTables(root) {
|
|
|
2205
2397
|
loopColumnCount: element.dataset.a2uiLoopColumnCount,
|
|
2206
2398
|
loopLabel: element.dataset.a2uiLoopLabel,
|
|
2207
2399
|
generatedHeader: element.dataset.a2uiLoopGeneratedHeader,
|
|
2400
|
+
actionControl: element.dataset.a2uiLoopActionControl,
|
|
2208
2401
|
hidden: element.getAttribute("hidden"),
|
|
2209
2402
|
ariaHidden: element.getAttribute("aria-hidden")
|
|
2210
2403
|
});
|
|
@@ -2215,6 +2408,10 @@ function annotateSavedLoopTables(root) {
|
|
|
2215
2408
|
}
|
|
2216
2409
|
element.textContent = text;
|
|
2217
2410
|
};
|
|
2411
|
+
const commitText = (element, text) => {
|
|
2412
|
+
textOriginals.set(element, text);
|
|
2413
|
+
element.textContent = text;
|
|
2414
|
+
};
|
|
2218
2415
|
const generatedElements = [];
|
|
2219
2416
|
const rows = [...root.querySelectorAll("div, section, article, li")].filter(
|
|
2220
2417
|
(row) => getSavedLoopRowFields(row).length > 0 && normalizedLoopSummaryFields(getSavedLoopSummaryFields(row)).length >= 2
|
|
@@ -2294,10 +2491,23 @@ function annotateSavedLoopTables(root) {
|
|
|
2294
2491
|
child.dataset.a2uiLoopColumn = String(Math.floor(columnIndex / 2) + 1);
|
|
2295
2492
|
columnIndex += 1;
|
|
2296
2493
|
}
|
|
2297
|
-
normalizeSavedLoopRow(
|
|
2494
|
+
normalizeSavedLoopRow(
|
|
2495
|
+
row,
|
|
2496
|
+
rowIndex,
|
|
2497
|
+
remember,
|
|
2498
|
+
setText,
|
|
2499
|
+
commitText,
|
|
2500
|
+
generatedElements,
|
|
2501
|
+
listeners,
|
|
2502
|
+
adapter,
|
|
2503
|
+
surfaceId
|
|
2504
|
+
);
|
|
2298
2505
|
});
|
|
2299
2506
|
}
|
|
2300
2507
|
return () => {
|
|
2508
|
+
for (const remove of listeners.reverse()) {
|
|
2509
|
+
remove();
|
|
2510
|
+
}
|
|
2301
2511
|
for (const [element, original] of originals) {
|
|
2302
2512
|
restoreDataset(element, "a2uiLoopTable", original.loopTable);
|
|
2303
2513
|
restoreDataset(element, "a2uiLoopRow", original.loopRow);
|
|
@@ -2312,6 +2522,7 @@ function annotateSavedLoopTables(root) {
|
|
|
2312
2522
|
"a2uiLoopGeneratedHeader",
|
|
2313
2523
|
original.generatedHeader
|
|
2314
2524
|
);
|
|
2525
|
+
restoreDataset(element, "a2uiLoopActionControl", original.actionControl);
|
|
2315
2526
|
restoreAttribute(element, "hidden", original.hidden);
|
|
2316
2527
|
restoreAttribute(element, "aria-hidden", original.ariaHidden);
|
|
2317
2528
|
}
|
|
@@ -2319,6 +2530,14 @@ function annotateSavedLoopTables(root) {
|
|
|
2319
2530
|
element.textContent = text;
|
|
2320
2531
|
}
|
|
2321
2532
|
for (const element of generatedElements) {
|
|
2533
|
+
if (element.dataset.a2uiGeneratedLoopActionCell === "true") {
|
|
2534
|
+
const parent = element.parentElement;
|
|
2535
|
+
if (parent !== null) {
|
|
2536
|
+
while (element.firstChild !== null) {
|
|
2537
|
+
parent.insertBefore(element.firstChild, element);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2322
2541
|
element.remove();
|
|
2323
2542
|
}
|
|
2324
2543
|
};
|
|
@@ -2346,7 +2565,7 @@ function buildSavedLoopHeader(parent, firstRow) {
|
|
|
2346
2565
|
header.appendChild(action);
|
|
2347
2566
|
return header;
|
|
2348
2567
|
}
|
|
2349
|
-
function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElements) {
|
|
2568
|
+
function normalizeSavedLoopRow(row, rowIndex, remember, setText, commitText, generatedElements, listeners, adapter, surfaceId) {
|
|
2350
2569
|
const summaryFields = normalizedLoopSummaryFields(getSavedLoopSummaryFields(row));
|
|
2351
2570
|
if (summaryFields.length < 2) {
|
|
2352
2571
|
return;
|
|
@@ -2356,6 +2575,7 @@ function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElemen
|
|
|
2356
2575
|
const fields = [...row.querySelectorAll("[data-a2ui-loop-field='true']")];
|
|
2357
2576
|
const summaryValues = getSavedLoopSummaryValues(row);
|
|
2358
2577
|
const action = row.querySelector("[data-a2ui-loop-cell='action']");
|
|
2578
|
+
const save = row.querySelector("[data-a2ui-loop-cell='save']");
|
|
2359
2579
|
const orderedFields = summaryFields.slice(0, columnCount).map((fieldName) => {
|
|
2360
2580
|
const field = findSavedLoopField(fields, fieldName);
|
|
2361
2581
|
if (field !== void 0) {
|
|
@@ -2394,9 +2614,27 @@ function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElemen
|
|
|
2394
2614
|
value.dataset.a2uiLoopCell = "value";
|
|
2395
2615
|
}
|
|
2396
2616
|
});
|
|
2617
|
+
const rowEditValues = savedLoopRowEditValues(orderedFields, summaryFields);
|
|
2618
|
+
const rowKey = savedLoopRowEditKey(rowIndex, summaryFields, rowEditValues);
|
|
2397
2619
|
if (action !== null) {
|
|
2398
2620
|
remember(action);
|
|
2399
2621
|
action.dataset.a2uiLoopColumn = String(columnCount + 1);
|
|
2622
|
+
createSavedLoopActionCell(
|
|
2623
|
+
row,
|
|
2624
|
+
save,
|
|
2625
|
+
action,
|
|
2626
|
+
columnCount + 1,
|
|
2627
|
+
remember,
|
|
2628
|
+
setText,
|
|
2629
|
+
commitText,
|
|
2630
|
+
generatedElements,
|
|
2631
|
+
listeners,
|
|
2632
|
+
adapter,
|
|
2633
|
+
surfaceId,
|
|
2634
|
+
rowKey,
|
|
2635
|
+
orderedFields,
|
|
2636
|
+
summaryFields.slice(0, columnCount)
|
|
2637
|
+
);
|
|
2400
2638
|
}
|
|
2401
2639
|
for (const field of fields) {
|
|
2402
2640
|
if (orderedFields.includes(field)) {
|
|
@@ -2408,6 +2646,202 @@ function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElemen
|
|
|
2408
2646
|
field.setAttribute("aria-hidden", "true");
|
|
2409
2647
|
}
|
|
2410
2648
|
}
|
|
2649
|
+
function createSavedLoopActionCell(row, save, action, column, remember, setText, commitText, generatedElements, listeners, adapter, surfaceId, rowKey, orderedFields, summaryFields) {
|
|
2650
|
+
if (save === null) {
|
|
2651
|
+
return void 0;
|
|
2652
|
+
}
|
|
2653
|
+
remember(save);
|
|
2654
|
+
remember(action);
|
|
2655
|
+
const actionCell = row.ownerDocument.createElement("div");
|
|
2656
|
+
const editButton = row.ownerDocument.createElement("button");
|
|
2657
|
+
editButton.type = "button";
|
|
2658
|
+
actionCell.dataset.a2uiLoopCell = "action";
|
|
2659
|
+
actionCell.dataset.a2uiLoopColumn = String(column);
|
|
2660
|
+
actionCell.dataset.a2uiLoopActionGroup = "true";
|
|
2661
|
+
actionCell.dataset.a2uiGeneratedLoopActionCell = "true";
|
|
2662
|
+
editButton.dataset.a2uiLoopCell = "edit";
|
|
2663
|
+
editButton.dataset.a2uiLoopColumn = String(column);
|
|
2664
|
+
editButton.dataset.a2uiGeneratedLoopEditButton = "true";
|
|
2665
|
+
editButton.textContent = "Edit";
|
|
2666
|
+
row.insertBefore(actionCell, action);
|
|
2667
|
+
actionCell.append(editButton, save, action);
|
|
2668
|
+
save.dataset.a2uiLoopCell = "save";
|
|
2669
|
+
save.dataset.a2uiLoopColumn = String(column);
|
|
2670
|
+
save.setAttribute("hidden", "");
|
|
2671
|
+
save.setAttribute("aria-hidden", "true");
|
|
2672
|
+
action.dataset.a2uiLoopColumn = String(column);
|
|
2673
|
+
listeners.push(
|
|
2674
|
+
bindSavedLoopEditAction(
|
|
2675
|
+
editButton,
|
|
2676
|
+
save,
|
|
2677
|
+
row,
|
|
2678
|
+
orderedFields,
|
|
2679
|
+
summaryFields,
|
|
2680
|
+
adapter,
|
|
2681
|
+
surfaceId,
|
|
2682
|
+
rowKey,
|
|
2683
|
+
setText,
|
|
2684
|
+
commitText,
|
|
2685
|
+
generatedElements,
|
|
2686
|
+
listeners
|
|
2687
|
+
)
|
|
2688
|
+
);
|
|
2689
|
+
const activeEditValues = adapter.getListRowEdit(surfaceId, rowKey);
|
|
2690
|
+
if (activeEditValues !== void 0) {
|
|
2691
|
+
renderSavedLoopEditInputs(
|
|
2692
|
+
editButton,
|
|
2693
|
+
row,
|
|
2694
|
+
orderedFields,
|
|
2695
|
+
summaryFields,
|
|
2696
|
+
adapter,
|
|
2697
|
+
surfaceId,
|
|
2698
|
+
rowKey,
|
|
2699
|
+
setText,
|
|
2700
|
+
generatedElements,
|
|
2701
|
+
listeners,
|
|
2702
|
+
activeEditValues,
|
|
2703
|
+
false
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2706
|
+
generatedElements.push(editButton);
|
|
2707
|
+
generatedElements.push(actionCell);
|
|
2708
|
+
delete action.dataset.a2uiLoopCell;
|
|
2709
|
+
delete action.dataset.a2uiLoopColumn;
|
|
2710
|
+
action.dataset.a2uiLoopActionControl = "true";
|
|
2711
|
+
return actionCell;
|
|
2712
|
+
}
|
|
2713
|
+
function bindSavedLoopEditAction(editButton, submitButton, row, orderedFields, summaryFields, adapter, surfaceId, rowKey, setText, commitText, generatedElements, listeners) {
|
|
2714
|
+
const onClick = (event) => {
|
|
2715
|
+
if (adapter.getListRowEdit(surfaceId, rowKey) === void 0) {
|
|
2716
|
+
event.preventDefault();
|
|
2717
|
+
event.stopImmediatePropagation();
|
|
2718
|
+
const values2 = savedLoopRowEditValues(orderedFields, summaryFields);
|
|
2719
|
+
adapter.beginListRowEdit(surfaceId, rowKey, values2);
|
|
2720
|
+
renderSavedLoopEditInputs(
|
|
2721
|
+
editButton,
|
|
2722
|
+
row,
|
|
2723
|
+
orderedFields,
|
|
2724
|
+
summaryFields,
|
|
2725
|
+
adapter,
|
|
2726
|
+
surfaceId,
|
|
2727
|
+
rowKey,
|
|
2728
|
+
setText,
|
|
2729
|
+
generatedElements,
|
|
2730
|
+
listeners,
|
|
2731
|
+
values2,
|
|
2732
|
+
true
|
|
2733
|
+
);
|
|
2734
|
+
return;
|
|
2735
|
+
}
|
|
2736
|
+
event.preventDefault();
|
|
2737
|
+
event.stopImmediatePropagation();
|
|
2738
|
+
const values = savedLoopRowInputValues(orderedFields, summaryFields);
|
|
2739
|
+
adapter.clearListRowEdit(surfaceId, rowKey);
|
|
2740
|
+
delete row.dataset.a2uiLoopEditing;
|
|
2741
|
+
setText(editButton, "Edit");
|
|
2742
|
+
orderedFields.forEach((field, index) => {
|
|
2743
|
+
const fieldName = summaryFields[index];
|
|
2744
|
+
const value = field.querySelector(
|
|
2745
|
+
"[data-a2ui-loop-cell='value']"
|
|
2746
|
+
);
|
|
2747
|
+
if (fieldName !== void 0 && value !== null) {
|
|
2748
|
+
commitText(value, stringEditValue(values[fieldName]));
|
|
2749
|
+
}
|
|
2750
|
+
});
|
|
2751
|
+
adapter.stageListRowUpdate(surfaceId, values);
|
|
2752
|
+
window.setTimeout(() => {
|
|
2753
|
+
const clickable = submitButton instanceof HTMLButtonElement ? submitButton : submitButton.querySelector("button");
|
|
2754
|
+
(clickable ?? submitButton).click();
|
|
2755
|
+
}, 0);
|
|
2756
|
+
};
|
|
2757
|
+
editButton.addEventListener("click", onClick, { capture: true });
|
|
2758
|
+
return () => {
|
|
2759
|
+
editButton.removeEventListener("click", onClick, { capture: true });
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
function renderSavedLoopEditInputs(editButton, row, orderedFields, summaryFields, adapter, surfaceId, rowKey, setText, generatedElements, listeners, values, focusFirstInput) {
|
|
2763
|
+
row.dataset.a2uiLoopEditing = "true";
|
|
2764
|
+
for (const [index, field] of orderedFields.entries()) {
|
|
2765
|
+
const fieldName = summaryFields[index];
|
|
2766
|
+
const value = field.querySelector(
|
|
2767
|
+
"[data-a2ui-loop-cell='value']"
|
|
2768
|
+
);
|
|
2769
|
+
if (fieldName === void 0 || value === null) {
|
|
2770
|
+
continue;
|
|
2771
|
+
}
|
|
2772
|
+
let input = value.querySelector(
|
|
2773
|
+
"input[data-a2ui-loop-edit-input='true']"
|
|
2774
|
+
);
|
|
2775
|
+
if (input === null) {
|
|
2776
|
+
input = row.ownerDocument.createElement("input");
|
|
2777
|
+
input.type = "text";
|
|
2778
|
+
input.name = fieldName;
|
|
2779
|
+
input.setAttribute("aria-label", displayFieldLabel(fieldName));
|
|
2780
|
+
input.dataset.a2uiLoopEditInput = "true";
|
|
2781
|
+
setText(value, "");
|
|
2782
|
+
value.appendChild(input);
|
|
2783
|
+
generatedElements.push(input);
|
|
2784
|
+
}
|
|
2785
|
+
input.value = stringEditValue(values[fieldName]);
|
|
2786
|
+
const syncEditValue = () => {
|
|
2787
|
+
adapter.updateListRowEdit(
|
|
2788
|
+
surfaceId,
|
|
2789
|
+
rowKey,
|
|
2790
|
+
savedLoopRowInputValues(orderedFields, summaryFields)
|
|
2791
|
+
);
|
|
2792
|
+
};
|
|
2793
|
+
input.addEventListener("input", syncEditValue);
|
|
2794
|
+
input.addEventListener("change", syncEditValue);
|
|
2795
|
+
listeners.push(() => {
|
|
2796
|
+
input.removeEventListener("input", syncEditValue);
|
|
2797
|
+
input.removeEventListener("change", syncEditValue);
|
|
2798
|
+
});
|
|
2799
|
+
}
|
|
2800
|
+
setText(editButton, "Save");
|
|
2801
|
+
if (focusFirstInput) {
|
|
2802
|
+
row.querySelector(
|
|
2803
|
+
"input[data-a2ui-loop-edit-input='true']"
|
|
2804
|
+
)?.focus();
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
function savedLoopRowEditValues(orderedFields, summaryFields) {
|
|
2808
|
+
const values = {};
|
|
2809
|
+
orderedFields.forEach((field, index) => {
|
|
2810
|
+
const fieldName = summaryFields[index];
|
|
2811
|
+
const value = field.querySelector(
|
|
2812
|
+
"[data-a2ui-loop-cell='value']"
|
|
2813
|
+
);
|
|
2814
|
+
if (fieldName !== void 0) {
|
|
2815
|
+
values[fieldName] = value?.textContent?.trim() ?? "";
|
|
2816
|
+
}
|
|
2817
|
+
});
|
|
2818
|
+
return values;
|
|
2819
|
+
}
|
|
2820
|
+
function savedLoopRowInputValues(orderedFields, summaryFields) {
|
|
2821
|
+
const values = {};
|
|
2822
|
+
orderedFields.forEach((field, index) => {
|
|
2823
|
+
const fieldName = summaryFields[index];
|
|
2824
|
+
const input = field.querySelector(
|
|
2825
|
+
"input[data-a2ui-loop-edit-input='true']"
|
|
2826
|
+
);
|
|
2827
|
+
const value = field.querySelector(
|
|
2828
|
+
"[data-a2ui-loop-cell='value']"
|
|
2829
|
+
);
|
|
2830
|
+
if (fieldName !== void 0) {
|
|
2831
|
+
values[fieldName] = input?.value ?? value?.textContent?.trim() ?? "";
|
|
2832
|
+
}
|
|
2833
|
+
});
|
|
2834
|
+
return values;
|
|
2835
|
+
}
|
|
2836
|
+
function savedLoopRowEditKey(rowIndex, summaryFields, values) {
|
|
2837
|
+
return `${rowIndex}:${summaryFields.map((field) => `${field}=${stringEditValue(values[field])}`).join("|")}`;
|
|
2838
|
+
}
|
|
2839
|
+
function stringEditValue(value) {
|
|
2840
|
+
if (value === null || value === void 0) {
|
|
2841
|
+
return "";
|
|
2842
|
+
}
|
|
2843
|
+
return String(value);
|
|
2844
|
+
}
|
|
2411
2845
|
function findSavedLoopField(fields, summaryField) {
|
|
2412
2846
|
const expectedName = canonicalLoopFieldName(summaryField).toLowerCase();
|
|
2413
2847
|
const expectedLabel = displayFieldLabel(expectedName).toLowerCase();
|