@ukiahinsure/a2ui-react-adapter 0.1.11 → 0.1.13

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,5 +1,5 @@
1
- import { A as A2UIClientAdapter, a as A2UISurfaceMetadata, b as A2UISessionController, c as A2UIRoomLike } from './session-Ckvifx8K.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 A2UIFieldValue, r as A2UIPendingAction, s as A2UIRendererActionEvent, t as A2UIServerEnvelope, u as A2UISessionControllerOptions, v as A2UISessionSnapshot, w as A2UISessionStatus, x as A2UIStreamParticipant, y as A2UISurfaceStructure, z as A2UITabDescriptor, B as A2UITrustedServerParticipant, C as A2UI_CAPABILITIES_TOPIC, D as A2UI_CLIENT_TOPIC, E as A2UI_PROTOCOL_VERSION, F as A2UI_SERVER_TOPIC, G as AckEnvelope, H as AckFieldError, I as AdapterSurface, J as CLIENT_ACTIONS, K as CLIENT_ERROR_CODES, L as ClientAction, M as ClientErrorCode, N as ENVELOPE_VERSION, O as MAX_ENVELOPE_BYTES, P as ParticipantRole, S as SectionNavigation, Q as SnapshotEnvelope, R as SurfaceUpdateEnvelope } from './session-Ckvifx8K.js';
1
+ import { A as A2UIClientAdapter, a as A2UISurfaceMetadata, b as A2UISessionController, c as A2UIRoomLike } from './session-BcHSjUlD.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 A2UIFieldValue, r as A2UIPendingAction, s as A2UIRendererActionEvent, t as A2UIServerEnvelope, u as A2UISessionControllerOptions, v as A2UISessionSnapshot, w as A2UISessionStatus, x as A2UIStreamParticipant, y as A2UISurfaceStructure, z as A2UITabDescriptor, B as A2UITrustedServerParticipant, C as A2UI_CAPABILITIES_TOPIC, D as A2UI_CLIENT_TOPIC, E as A2UI_PROTOCOL_VERSION, F as A2UI_SERVER_TOPIC, G as AckEnvelope, H as AckFieldError, I as AdapterSurface, J as CLIENT_ACTIONS, K as CLIENT_ERROR_CODES, L as ClientAction, M as ClientErrorCode, N as ENVELOPE_VERSION, O as MAX_ENVELOPE_BYTES, P as ParticipantRole, S as SectionNavigation, Q as SnapshotEnvelope, R as SurfaceUpdateEnvelope } from './session-BcHSjUlD.js';
3
3
  import { ReactNode } from 'react';
4
4
 
5
5
  /** Accessible host around the official A2UI v0.9.1 React surface. */
package/dist/index.js CHANGED
@@ -30,6 +30,9 @@ var A2UIClientAdapter = class {
30
30
  #structureBySurface = /* @__PURE__ */ new Map();
31
31
  #persistedListRowsByPath = /* @__PURE__ */ new Map();
32
32
  #deletedListItemIdsByPath = /* @__PURE__ */ new Map();
33
+ #stagedListRowUpdatesBySurface = /* @__PURE__ */ new Map();
34
+ #activeListRowEditsBySurface = /* @__PURE__ */ new Map();
35
+ #optimisticListRowsByPath = /* @__PURE__ */ new Map();
33
36
  #version = 0;
34
37
  #lastSeq = 0;
35
38
  #disposed = false;
@@ -105,6 +108,38 @@ var A2UIClientAdapter = class {
105
108
  }
106
109
  return true;
107
110
  }
111
+ stageListRowUpdate(surfaceId, values) {
112
+ this.#stagedListRowUpdatesBySurface.set(surfaceId, { ...values });
113
+ }
114
+ beginListRowEdit(surfaceId, rowKey, values) {
115
+ let edits = this.#activeListRowEditsBySurface.get(surfaceId);
116
+ if (edits === void 0) {
117
+ edits = /* @__PURE__ */ new Map();
118
+ this.#activeListRowEditsBySurface.set(surfaceId, edits);
119
+ }
120
+ edits.set(rowKey, { ...values });
121
+ }
122
+ updateListRowEdit(surfaceId, rowKey, values) {
123
+ const edits = this.#activeListRowEditsBySurface.get(surfaceId);
124
+ if (edits?.has(rowKey) !== true) {
125
+ return;
126
+ }
127
+ edits.set(rowKey, { ...values });
128
+ }
129
+ getListRowEdit(surfaceId, rowKey) {
130
+ const values = this.#activeListRowEditsBySurface.get(surfaceId)?.get(rowKey);
131
+ return values === void 0 ? void 0 : { ...values };
132
+ }
133
+ clearListRowEdit(surfaceId, rowKey) {
134
+ const edits = this.#activeListRowEditsBySurface.get(surfaceId);
135
+ if (edits === void 0) {
136
+ return;
137
+ }
138
+ edits.delete(rowKey);
139
+ if (edits.size === 0) {
140
+ this.#activeListRowEditsBySurface.delete(surfaceId);
141
+ }
142
+ }
108
143
  #dataModelValueForField(surfaceId, field, value) {
109
144
  const descriptor = this.#fieldDescriptor(surfaceId, field);
110
145
  if (descriptor?.control === "choice" && typeof value === "string" && value.length > 0) {
@@ -159,6 +194,8 @@ var A2UIClientAdapter = class {
159
194
  this.#structureBySurface.clear();
160
195
  this.#persistedListRowsByPath.clear();
161
196
  this.#deletedListItemIdsByPath.clear();
197
+ this.#activeListRowEditsBySurface.clear();
198
+ this.#optimisticListRowsByPath.clear();
162
199
  previous.model.dispose();
163
200
  this.#notify();
164
201
  }
@@ -198,6 +235,10 @@ var A2UIClientAdapter = class {
198
235
  this.#disposed = true;
199
236
  this.#processor.model.dispose();
200
237
  this.#structureBySurface.clear();
238
+ this.#persistedListRowsByPath.clear();
239
+ this.#deletedListItemIdsByPath.clear();
240
+ this.#activeListRowEditsBySurface.clear();
241
+ this.#optimisticListRowsByPath.clear();
201
242
  this.#listeners.clear();
202
243
  this.#actionListeners.clear();
203
244
  this.#errorListeners.clear();
@@ -216,7 +257,8 @@ var A2UIClientAdapter = class {
216
257
  validated.data,
217
258
  envelope.surfaceId,
218
259
  this.#persistedListRowsByPath,
219
- this.#deletedListItemIdsByPath
260
+ this.#deletedListItemIdsByPath,
261
+ this.#optimisticListRowsByPath
220
262
  );
221
263
  const listAddFreeMessages = removeListAddActionMessages(
222
264
  rawMessages,
@@ -272,6 +314,8 @@ var A2UIClientAdapter = class {
272
314
  if (envelope.kind === "snapshot") {
273
315
  this.#persistedListRowsByPath.clear();
274
316
  this.#deletedListItemIdsByPath.clear();
317
+ this.#activeListRowEditsBySurface.clear();
318
+ this.#optimisticListRowsByPath.clear();
275
319
  }
276
320
  rememberPersistedListRows(
277
321
  this.#persistedListRowsByPath,
@@ -297,11 +341,18 @@ var A2UIClientAdapter = class {
297
341
  );
298
342
  return;
299
343
  }
344
+ const stagedListRowUpdate = action.name === "flow.list.update" ? this.#stagedListRowUpdatesBySurface.get(action.surfaceId) : void 0;
345
+ if (stagedListRowUpdate !== void 0) {
346
+ this.#stagedListRowUpdatesBySurface.delete(action.surfaceId);
347
+ }
300
348
  const event = {
301
349
  actionName: action.name,
302
350
  surfaceId: action.surfaceId,
303
351
  sourceComponentId: action.sourceComponentId,
304
- context: { ...action.context }
352
+ context: {
353
+ ...action.context,
354
+ ...stagedListRowUpdate ?? {}
355
+ }
305
356
  };
306
357
  const submittedProviderRow = submittedProviderRowFromEvent(event);
307
358
  if (submittedProviderRow !== void 0) {
@@ -314,6 +365,9 @@ var A2UIClientAdapter = class {
314
365
  if (event.actionName === "flow.list.delete") {
315
366
  this.#removeDeletedListRow(event.surfaceId, event.context);
316
367
  }
368
+ if (event.actionName === "flow.list.update") {
369
+ this.#updateListRow(event.surfaceId, event.context);
370
+ }
317
371
  this.#options.onAction?.(event);
318
372
  for (const listener of this.#actionListeners) {
319
373
  listener(event);
@@ -348,6 +402,7 @@ var A2UIClientAdapter = class {
348
402
  const cachedRows = this.#persistedListRowsByPath.get(listPath) ?? [];
349
403
  const nextRows = removeListRowByItemId(cachedRows, itemId);
350
404
  this.#persistedListRowsByPath.set(listPath, nextRows);
405
+ this.#optimisticListRowsByPath.get(listPath)?.delete(itemId);
351
406
  rememberDeletedListItemId(this.#deletedListItemIdsByPath, listPath, itemId);
352
407
  const surface = this.#processor.model.getSurface(surfaceId);
353
408
  if (surface === void 0) {
@@ -360,6 +415,39 @@ var A2UIClientAdapter = class {
360
415
  );
361
416
  this.#notify();
362
417
  }
418
+ #updateListRow(surfaceId, context) {
419
+ const listPath = context.listPath;
420
+ const itemId = context.itemId;
421
+ if (typeof listPath !== "string" || listPath.length === 0 || typeof itemId !== "string" || itemId.length === 0) {
422
+ return;
423
+ }
424
+ const cachedRows = this.#persistedListRowsByPath.get(listPath) ?? [];
425
+ const existingRow = cachedRows.find(
426
+ (candidate) => isRecord(candidate) && candidate.itemId === itemId
427
+ );
428
+ const row = updateListRowFromContext(context, existingRow);
429
+ if (row === void 0) {
430
+ return;
431
+ }
432
+ const rows = normalizeListRows(listPath, upsertListRow(cachedRows, row));
433
+ this.#persistedListRowsByPath.set(listPath, rows);
434
+ let optimisticRows = this.#optimisticListRowsByPath.get(listPath);
435
+ if (optimisticRows === void 0) {
436
+ optimisticRows = /* @__PURE__ */ new Map();
437
+ this.#optimisticListRowsByPath.set(listPath, optimisticRows);
438
+ }
439
+ optimisticRows.set(itemId, cloneJsonRecord(row));
440
+ const surface = this.#processor.model.getSurface(surfaceId);
441
+ if (surface === void 0) {
442
+ return;
443
+ }
444
+ surface.dataModel.set(`/${listPath}`, cloneJsonArray(rows));
445
+ surface.dataModel.set(
446
+ `/${listPath.replaceAll(".", "/")}`,
447
+ cloneJsonArray(rows)
448
+ );
449
+ this.#notify();
450
+ }
363
451
  #snapshotMessages() {
364
452
  const messages = [];
365
453
  for (const surface of this.#processor.model.surfacesMap.values()) {
@@ -859,8 +947,8 @@ function fieldFromPointer(path) {
859
947
  function fieldPointer(field) {
860
948
  return `/${field.replaceAll("~", "~0").replaceAll("/", "~1")}`;
861
949
  }
862
- function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsByPath, deletedItemIdsByPath) {
863
- if (persistedRowsByPath.size === 0 && deletedItemIdsByPath.size === 0) {
950
+ function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsByPath, deletedItemIdsByPath, optimisticRowsByPath) {
951
+ if (persistedRowsByPath.size === 0 && deletedItemIdsByPath.size === 0 && optimisticRowsByPath.size === 0) {
864
952
  return [...messages];
865
953
  }
866
954
  let mergedRoot = false;
@@ -876,7 +964,8 @@ function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsBy
876
964
  value: mergePersistedListRowsIntoRoot(
877
965
  message.updateDataModel.value,
878
966
  persistedRowsByPath,
879
- deletedItemIdsByPath
967
+ deletedItemIdsByPath,
968
+ optimisticRowsByPath
880
969
  )
881
970
  }
882
971
  };
@@ -894,26 +983,33 @@ function mergePersistedListRowsIntoMessages(messages, surfaceId, persistedRowsBy
894
983
  value: mergePersistedListRowsIntoRoot(
895
984
  {},
896
985
  persistedRowsByPath,
897
- deletedItemIdsByPath
986
+ deletedItemIdsByPath,
987
+ optimisticRowsByPath
898
988
  )
899
989
  }
900
990
  }
901
991
  ];
902
992
  }
903
- function mergePersistedListRowsIntoRoot(root, persistedRowsByPath, deletedItemIdsByPath) {
993
+ function mergePersistedListRowsIntoRoot(root, persistedRowsByPath, deletedItemIdsByPath, optimisticRowsByPath) {
904
994
  const merged = cloneJsonRecord(root);
905
995
  for (const listPath of /* @__PURE__ */ new Set([
906
996
  ...persistedRowsByPath.keys(),
907
- ...deletedItemIdsByPath.keys()
997
+ ...deletedItemIdsByPath.keys(),
998
+ ...optimisticRowsByPath.keys()
908
999
  ])) {
909
1000
  const rows = persistedRowsByPath.get(listPath) ?? [];
1001
+ const optimisticRows = optimisticRowsByPath.get(listPath);
910
1002
  const dottedRows = merged[listPath];
911
1003
  const nestedRows = getNestedValue(merged, listPath);
912
1004
  const incomingRows = Array.isArray(dottedRows) ? dottedRows : Array.isArray(nestedRows) ? nestedRows : void 0;
913
1005
  const shouldPreserveCachedRows = rows.length > 0 && (incomingRows === void 0 || incomingRows.length === 0 && (!hasListDraft(merged, listPath) || hasBlankListDraft(merged, listPath)));
914
1006
  const effectiveRows = shouldPreserveCachedRows ? rows : incomingRows ?? rows;
915
- const visibleRows = filterDeletedListRows(
1007
+ const optimisticEffectiveRows = mergeOptimisticListRows(
916
1008
  effectiveRows,
1009
+ optimisticRows
1010
+ );
1011
+ const visibleRows = filterDeletedListRows(
1012
+ optimisticEffectiveRows,
917
1013
  deletedItemIdsByPath.get(listPath)
918
1014
  );
919
1015
  const normalizedRows = normalizeListRows(listPath, visibleRows, merged);
@@ -949,6 +1045,16 @@ function isBlankDraftValue(value) {
949
1045
  }
950
1046
  return false;
951
1047
  }
1048
+ function mergeOptimisticListRows(rows, optimisticRows) {
1049
+ if (optimisticRows === void 0 || optimisticRows.size === 0) {
1050
+ return cloneJsonArray(rows);
1051
+ }
1052
+ let merged = cloneJsonArray(rows);
1053
+ for (const row of optimisticRows.values()) {
1054
+ merged = upsertListRow(merged, cloneJsonRecord(row));
1055
+ }
1056
+ return merged;
1057
+ }
952
1058
  function rememberPersistedListRows(persistedRowsByPath, deletedItemIdsByPath, root) {
953
1059
  if (!isRecord(root)) {
954
1060
  return;
@@ -1192,6 +1298,35 @@ function isProviderSubmitLabel(label) {
1192
1298
  function normalizeFieldKey(key) {
1193
1299
  return key.trim().toLowerCase().replaceAll(/[^a-z0-9]+/g, "_").replaceAll(/^_+|_+$/g, "");
1194
1300
  }
1301
+ function updateListRowFromContext(context, existingRow) {
1302
+ const itemId = context.itemId;
1303
+ if (typeof itemId !== "string" || itemId.length === 0) {
1304
+ return void 0;
1305
+ }
1306
+ const row = isRecord(existingRow) ? cloneJsonRecord(existingRow) : {};
1307
+ row.itemId = itemId;
1308
+ let hasUpdate = false;
1309
+ for (const [key, value] of Object.entries(context)) {
1310
+ if (key === "listPath" || key === "itemId" || !isFieldValue(value)) {
1311
+ continue;
1312
+ }
1313
+ row[key] = value;
1314
+ hasUpdate = true;
1315
+ }
1316
+ if (!hasUpdate) {
1317
+ return void 0;
1318
+ }
1319
+ row.__displayText = listRowDisplayText(row);
1320
+ return row;
1321
+ }
1322
+ function listRowDisplayText(row) {
1323
+ return Object.entries(row).filter(([key, value]) => {
1324
+ if (key === "itemId" || key === "__displayText" || value === null) {
1325
+ return false;
1326
+ }
1327
+ return isFieldValue(value) && String(value).trim().length > 0;
1328
+ }).map(([key, value]) => `${key}: ${String(value).trim()}`).join(" | ");
1329
+ }
1195
1330
  function upsertListRow(rows, row) {
1196
1331
  const itemId = row.itemId;
1197
1332
  if (typeof itemId !== "string" || itemId.length === 0) {
@@ -1500,7 +1635,7 @@ function A2UISurfaceHost({
1500
1635
  validationSummaryId
1501
1636
  ),
1502
1637
  formatFieldLabels(root),
1503
- annotateSavedLoopTables(root),
1638
+ annotateSavedLoopTables(root, adapter, surface.id),
1504
1639
  bindFieldInteractionGroups(
1505
1640
  root,
1506
1641
  resolvedSurfaceMetadata?.fieldInteractions ?? [],
@@ -2188,9 +2323,10 @@ function generatedFieldLabelName(text) {
2188
2323
  const unwrapped = trimmed.startsWith("*") && trimmed.endsWith("*") ? trimmed.slice(1, -1).trim() : trimmed;
2189
2324
  return /^[A-Za-z][A-Za-z0-9_]*$/.test(unwrapped) && /[_A-Z]/.test(unwrapped) ? unwrapped : void 0;
2190
2325
  }
2191
- function annotateSavedLoopTables(root) {
2326
+ function annotateSavedLoopTables(root, adapter, surfaceId) {
2192
2327
  const originals = /* @__PURE__ */ new Map();
2193
2328
  const textOriginals = /* @__PURE__ */ new Map();
2329
+ const listeners = [];
2194
2330
  const remember = (element) => {
2195
2331
  if (originals.has(element)) {
2196
2332
  return;
@@ -2205,6 +2341,7 @@ function annotateSavedLoopTables(root) {
2205
2341
  loopColumnCount: element.dataset.a2uiLoopColumnCount,
2206
2342
  loopLabel: element.dataset.a2uiLoopLabel,
2207
2343
  generatedHeader: element.dataset.a2uiLoopGeneratedHeader,
2344
+ actionControl: element.dataset.a2uiLoopActionControl,
2208
2345
  hidden: element.getAttribute("hidden"),
2209
2346
  ariaHidden: element.getAttribute("aria-hidden")
2210
2347
  });
@@ -2215,6 +2352,10 @@ function annotateSavedLoopTables(root) {
2215
2352
  }
2216
2353
  element.textContent = text;
2217
2354
  };
2355
+ const commitText = (element, text) => {
2356
+ textOriginals.set(element, text);
2357
+ element.textContent = text;
2358
+ };
2218
2359
  const generatedElements = [];
2219
2360
  const rows = [...root.querySelectorAll("div, section, article, li")].filter(
2220
2361
  (row) => getSavedLoopRowFields(row).length > 0 && normalizedLoopSummaryFields(getSavedLoopSummaryFields(row)).length >= 2
@@ -2294,10 +2435,23 @@ function annotateSavedLoopTables(root) {
2294
2435
  child.dataset.a2uiLoopColumn = String(Math.floor(columnIndex / 2) + 1);
2295
2436
  columnIndex += 1;
2296
2437
  }
2297
- normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElements);
2438
+ normalizeSavedLoopRow(
2439
+ row,
2440
+ rowIndex,
2441
+ remember,
2442
+ setText,
2443
+ commitText,
2444
+ generatedElements,
2445
+ listeners,
2446
+ adapter,
2447
+ surfaceId
2448
+ );
2298
2449
  });
2299
2450
  }
2300
2451
  return () => {
2452
+ for (const remove of listeners.reverse()) {
2453
+ remove();
2454
+ }
2301
2455
  for (const [element, original] of originals) {
2302
2456
  restoreDataset(element, "a2uiLoopTable", original.loopTable);
2303
2457
  restoreDataset(element, "a2uiLoopRow", original.loopRow);
@@ -2312,6 +2466,7 @@ function annotateSavedLoopTables(root) {
2312
2466
  "a2uiLoopGeneratedHeader",
2313
2467
  original.generatedHeader
2314
2468
  );
2469
+ restoreDataset(element, "a2uiLoopActionControl", original.actionControl);
2315
2470
  restoreAttribute(element, "hidden", original.hidden);
2316
2471
  restoreAttribute(element, "aria-hidden", original.ariaHidden);
2317
2472
  }
@@ -2319,6 +2474,14 @@ function annotateSavedLoopTables(root) {
2319
2474
  element.textContent = text;
2320
2475
  }
2321
2476
  for (const element of generatedElements) {
2477
+ if (element.dataset.a2uiGeneratedLoopActionCell === "true") {
2478
+ const parent = element.parentElement;
2479
+ if (parent !== null) {
2480
+ while (element.firstChild !== null) {
2481
+ parent.insertBefore(element.firstChild, element);
2482
+ }
2483
+ }
2484
+ }
2322
2485
  element.remove();
2323
2486
  }
2324
2487
  };
@@ -2346,7 +2509,7 @@ function buildSavedLoopHeader(parent, firstRow) {
2346
2509
  header.appendChild(action);
2347
2510
  return header;
2348
2511
  }
2349
- function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElements) {
2512
+ function normalizeSavedLoopRow(row, rowIndex, remember, setText, commitText, generatedElements, listeners, adapter, surfaceId) {
2350
2513
  const summaryFields = normalizedLoopSummaryFields(getSavedLoopSummaryFields(row));
2351
2514
  if (summaryFields.length < 2) {
2352
2515
  return;
@@ -2356,6 +2519,7 @@ function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElemen
2356
2519
  const fields = [...row.querySelectorAll("[data-a2ui-loop-field='true']")];
2357
2520
  const summaryValues = getSavedLoopSummaryValues(row);
2358
2521
  const action = row.querySelector("[data-a2ui-loop-cell='action']");
2522
+ const save = row.querySelector("[data-a2ui-loop-cell='save']");
2359
2523
  const orderedFields = summaryFields.slice(0, columnCount).map((fieldName) => {
2360
2524
  const field = findSavedLoopField(fields, fieldName);
2361
2525
  if (field !== void 0) {
@@ -2394,9 +2558,27 @@ function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElemen
2394
2558
  value.dataset.a2uiLoopCell = "value";
2395
2559
  }
2396
2560
  });
2561
+ const rowEditValues = savedLoopRowEditValues(orderedFields, summaryFields);
2562
+ const rowKey = savedLoopRowEditKey(rowIndex, summaryFields, rowEditValues);
2397
2563
  if (action !== null) {
2398
2564
  remember(action);
2399
2565
  action.dataset.a2uiLoopColumn = String(columnCount + 1);
2566
+ createSavedLoopActionCell(
2567
+ row,
2568
+ save,
2569
+ action,
2570
+ columnCount + 1,
2571
+ remember,
2572
+ setText,
2573
+ commitText,
2574
+ generatedElements,
2575
+ listeners,
2576
+ adapter,
2577
+ surfaceId,
2578
+ rowKey,
2579
+ orderedFields,
2580
+ summaryFields.slice(0, columnCount)
2581
+ );
2400
2582
  }
2401
2583
  for (const field of fields) {
2402
2584
  if (orderedFields.includes(field)) {
@@ -2408,6 +2590,202 @@ function normalizeSavedLoopRow(row, rowIndex, remember, setText, generatedElemen
2408
2590
  field.setAttribute("aria-hidden", "true");
2409
2591
  }
2410
2592
  }
2593
+ function createSavedLoopActionCell(row, save, action, column, remember, setText, commitText, generatedElements, listeners, adapter, surfaceId, rowKey, orderedFields, summaryFields) {
2594
+ if (save === null) {
2595
+ return void 0;
2596
+ }
2597
+ remember(save);
2598
+ remember(action);
2599
+ const actionCell = row.ownerDocument.createElement("div");
2600
+ const editButton = row.ownerDocument.createElement("button");
2601
+ editButton.type = "button";
2602
+ actionCell.dataset.a2uiLoopCell = "action";
2603
+ actionCell.dataset.a2uiLoopColumn = String(column);
2604
+ actionCell.dataset.a2uiLoopActionGroup = "true";
2605
+ actionCell.dataset.a2uiGeneratedLoopActionCell = "true";
2606
+ editButton.dataset.a2uiLoopCell = "edit";
2607
+ editButton.dataset.a2uiLoopColumn = String(column);
2608
+ editButton.dataset.a2uiGeneratedLoopEditButton = "true";
2609
+ editButton.textContent = "Edit";
2610
+ row.insertBefore(actionCell, action);
2611
+ actionCell.append(editButton, save, action);
2612
+ save.dataset.a2uiLoopCell = "save";
2613
+ save.dataset.a2uiLoopColumn = String(column);
2614
+ save.setAttribute("hidden", "");
2615
+ save.setAttribute("aria-hidden", "true");
2616
+ action.dataset.a2uiLoopColumn = String(column);
2617
+ listeners.push(
2618
+ bindSavedLoopEditAction(
2619
+ editButton,
2620
+ save,
2621
+ row,
2622
+ orderedFields,
2623
+ summaryFields,
2624
+ adapter,
2625
+ surfaceId,
2626
+ rowKey,
2627
+ setText,
2628
+ commitText,
2629
+ generatedElements,
2630
+ listeners
2631
+ )
2632
+ );
2633
+ const activeEditValues = adapter.getListRowEdit(surfaceId, rowKey);
2634
+ if (activeEditValues !== void 0) {
2635
+ renderSavedLoopEditInputs(
2636
+ editButton,
2637
+ row,
2638
+ orderedFields,
2639
+ summaryFields,
2640
+ adapter,
2641
+ surfaceId,
2642
+ rowKey,
2643
+ setText,
2644
+ generatedElements,
2645
+ listeners,
2646
+ activeEditValues,
2647
+ false
2648
+ );
2649
+ }
2650
+ generatedElements.push(editButton);
2651
+ generatedElements.push(actionCell);
2652
+ delete action.dataset.a2uiLoopCell;
2653
+ delete action.dataset.a2uiLoopColumn;
2654
+ action.dataset.a2uiLoopActionControl = "true";
2655
+ return actionCell;
2656
+ }
2657
+ function bindSavedLoopEditAction(editButton, submitButton, row, orderedFields, summaryFields, adapter, surfaceId, rowKey, setText, commitText, generatedElements, listeners) {
2658
+ const onClick = (event) => {
2659
+ if (adapter.getListRowEdit(surfaceId, rowKey) === void 0) {
2660
+ event.preventDefault();
2661
+ event.stopImmediatePropagation();
2662
+ const values2 = savedLoopRowEditValues(orderedFields, summaryFields);
2663
+ adapter.beginListRowEdit(surfaceId, rowKey, values2);
2664
+ renderSavedLoopEditInputs(
2665
+ editButton,
2666
+ row,
2667
+ orderedFields,
2668
+ summaryFields,
2669
+ adapter,
2670
+ surfaceId,
2671
+ rowKey,
2672
+ setText,
2673
+ generatedElements,
2674
+ listeners,
2675
+ values2,
2676
+ true
2677
+ );
2678
+ return;
2679
+ }
2680
+ event.preventDefault();
2681
+ event.stopImmediatePropagation();
2682
+ const values = savedLoopRowInputValues(orderedFields, summaryFields);
2683
+ adapter.clearListRowEdit(surfaceId, rowKey);
2684
+ delete row.dataset.a2uiLoopEditing;
2685
+ setText(editButton, "Edit");
2686
+ orderedFields.forEach((field, index) => {
2687
+ const fieldName = summaryFields[index];
2688
+ const value = field.querySelector(
2689
+ "[data-a2ui-loop-cell='value']"
2690
+ );
2691
+ if (fieldName !== void 0 && value !== null) {
2692
+ commitText(value, stringEditValue(values[fieldName]));
2693
+ }
2694
+ });
2695
+ adapter.stageListRowUpdate(surfaceId, values);
2696
+ window.setTimeout(() => {
2697
+ const clickable = submitButton instanceof HTMLButtonElement ? submitButton : submitButton.querySelector("button");
2698
+ (clickable ?? submitButton).click();
2699
+ }, 0);
2700
+ };
2701
+ editButton.addEventListener("click", onClick, { capture: true });
2702
+ return () => {
2703
+ editButton.removeEventListener("click", onClick, { capture: true });
2704
+ };
2705
+ }
2706
+ function renderSavedLoopEditInputs(editButton, row, orderedFields, summaryFields, adapter, surfaceId, rowKey, setText, generatedElements, listeners, values, focusFirstInput) {
2707
+ row.dataset.a2uiLoopEditing = "true";
2708
+ for (const [index, field] of orderedFields.entries()) {
2709
+ const fieldName = summaryFields[index];
2710
+ const value = field.querySelector(
2711
+ "[data-a2ui-loop-cell='value']"
2712
+ );
2713
+ if (fieldName === void 0 || value === null) {
2714
+ continue;
2715
+ }
2716
+ let input = value.querySelector(
2717
+ "input[data-a2ui-loop-edit-input='true']"
2718
+ );
2719
+ if (input === null) {
2720
+ input = row.ownerDocument.createElement("input");
2721
+ input.type = "text";
2722
+ input.name = fieldName;
2723
+ input.setAttribute("aria-label", displayFieldLabel(fieldName));
2724
+ input.dataset.a2uiLoopEditInput = "true";
2725
+ setText(value, "");
2726
+ value.appendChild(input);
2727
+ generatedElements.push(input);
2728
+ }
2729
+ input.value = stringEditValue(values[fieldName]);
2730
+ const syncEditValue = () => {
2731
+ adapter.updateListRowEdit(
2732
+ surfaceId,
2733
+ rowKey,
2734
+ savedLoopRowInputValues(orderedFields, summaryFields)
2735
+ );
2736
+ };
2737
+ input.addEventListener("input", syncEditValue);
2738
+ input.addEventListener("change", syncEditValue);
2739
+ listeners.push(() => {
2740
+ input.removeEventListener("input", syncEditValue);
2741
+ input.removeEventListener("change", syncEditValue);
2742
+ });
2743
+ }
2744
+ setText(editButton, "Save");
2745
+ if (focusFirstInput) {
2746
+ row.querySelector(
2747
+ "input[data-a2ui-loop-edit-input='true']"
2748
+ )?.focus();
2749
+ }
2750
+ }
2751
+ function savedLoopRowEditValues(orderedFields, summaryFields) {
2752
+ const values = {};
2753
+ orderedFields.forEach((field, index) => {
2754
+ const fieldName = summaryFields[index];
2755
+ const value = field.querySelector(
2756
+ "[data-a2ui-loop-cell='value']"
2757
+ );
2758
+ if (fieldName !== void 0) {
2759
+ values[fieldName] = value?.textContent?.trim() ?? "";
2760
+ }
2761
+ });
2762
+ return values;
2763
+ }
2764
+ function savedLoopRowInputValues(orderedFields, summaryFields) {
2765
+ const values = {};
2766
+ orderedFields.forEach((field, index) => {
2767
+ const fieldName = summaryFields[index];
2768
+ const input = field.querySelector(
2769
+ "input[data-a2ui-loop-edit-input='true']"
2770
+ );
2771
+ const value = field.querySelector(
2772
+ "[data-a2ui-loop-cell='value']"
2773
+ );
2774
+ if (fieldName !== void 0) {
2775
+ values[fieldName] = input?.value ?? value?.textContent?.trim() ?? "";
2776
+ }
2777
+ });
2778
+ return values;
2779
+ }
2780
+ function savedLoopRowEditKey(rowIndex, summaryFields, values) {
2781
+ return `${rowIndex}:${summaryFields.map((field) => `${field}=${stringEditValue(values[field])}`).join("|")}`;
2782
+ }
2783
+ function stringEditValue(value) {
2784
+ if (value === null || value === void 0) {
2785
+ return "";
2786
+ }
2787
+ return String(value);
2788
+ }
2411
2789
  function findSavedLoopField(fields, summaryField) {
2412
2790
  const expectedName = canonicalLoopFieldName(summaryField).toLowerCase();
2413
2791
  const expectedLabel = displayFieldLabel(expectedName).toLowerCase();