@omnitend/dashboard-for-laravel 0.47.1 → 0.47.2
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/components/extended/DXField.vue.d.ts +10 -5
- package/dist/components/extended/DXForm.vue.d.ts +5 -1
- package/dist/components/extended/DXFormErrorSummary.vue.d.ts +3 -1
- package/dist/composables/useForm.d.ts +13 -5
- package/dist/dashboard-for-laravel.js +6062 -6030
- package/dist/dashboard-for-laravel.js.map +1 -1
- package/dist/dashboard-for-laravel.umd.cjs +7 -7
- package/dist/dashboard-for-laravel.umd.cjs.map +1 -1
- package/dist/style.css +1 -1
- package/dist/types/index.d.ts +3 -1
- package/dist/utils/formErrorTargets.d.ts +4 -2
- package/docs/public/api-reference.json +4 -4
- package/docs/public/docs-map.md +1 -1
- package/package.json +1 -1
- package/resources/js/components/extended/DXField.vue +43 -7
- package/resources/js/components/extended/DXForm.vue +40 -1
- package/resources/js/components/extended/DXFormErrorSummary.vue +3 -1
- package/resources/js/composables/useForm.ts +34 -16
- package/resources/js/types/index.ts +3 -1
- package/resources/js/utils/formErrorTargets.ts +18 -6
package/dist/types/index.d.ts
CHANGED
|
@@ -219,7 +219,9 @@ export interface FieldDefinition {
|
|
|
219
219
|
* For a field whose value is a list of rows (a `repeater`, or a span
|
|
220
220
|
* field that renders its own rows and owns `key.N.*` error keys): the
|
|
221
221
|
* row's own name, called with the row (`model[key][index]`, or `{}` when
|
|
222
|
-
* the model has no such row) and its 0-based index
|
|
222
|
+
* the model has no such row) and its 0-based index (for a failure's row
|
|
223
|
+
* that has since moved, its current index; once removed, the index it
|
|
224
|
+
* failed at: the index "(line N)" counts). When it returns a
|
|
223
225
|
* non-empty string, the error summary lists that row's errors under it
|
|
224
226
|
* alone ("Chaucer Ale (Pint): Enter a price.") instead of
|
|
225
227
|
* "<sub-field label> (line N)". Returning `undefined`, `null` or `""`
|
|
@@ -8,8 +8,10 @@ export interface ErrorTarget {
|
|
|
8
8
|
* Where to take the user for this error now. The same as `errorKey`,
|
|
9
9
|
* except for a row error resolved with `failedRows`: the key at the
|
|
10
10
|
* failed row's CURRENT index (`lines.1.price` once row 0 is removed),
|
|
11
|
-
* or the owning field's key when that row is gone
|
|
12
|
-
*
|
|
11
|
+
* or the owning field's key when that row is gone (removed, replaced, or
|
|
12
|
+
* flagged by the field's `softDeleteKey`); DXForm then focuses the
|
|
13
|
+
* field's container, not a row. Always set by `resolveErrorTargets`;
|
|
14
|
+
* optional so targets built by hand still type.
|
|
13
15
|
*/
|
|
14
16
|
focusKey?: string;
|
|
15
17
|
/** The server's messages for that key, as sent. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-10-21T13:
|
|
2
|
+
"generated": "2026-10-21T13:19:32.045Z",
|
|
3
3
|
"package": {
|
|
4
4
|
"name": "@omnitend/dashboard-for-laravel",
|
|
5
|
-
"version": "0.47.
|
|
5
|
+
"version": "0.47.2"
|
|
6
6
|
},
|
|
7
7
|
"components": {
|
|
8
8
|
"base": [
|
|
@@ -2205,7 +2205,7 @@
|
|
|
2205
2205
|
"name": "(value: any) => void"
|
|
2206
2206
|
},
|
|
2207
2207
|
"name": "update",
|
|
2208
|
-
"description": "Setter that writes the value back and clears the field's validation error, and
|
|
2208
|
+
"description": "Setter that writes the value back and clears the field's validation error, and every error under `<key>.` when the value is an array whose rows were added, removed, replaced or reordered (rows the slot draws itself)."
|
|
2209
2209
|
}
|
|
2210
2210
|
]
|
|
2211
2211
|
},
|
|
@@ -2287,7 +2287,7 @@
|
|
|
2287
2287
|
"name": "(value: any) => void"
|
|
2288
2288
|
},
|
|
2289
2289
|
"name": "update",
|
|
2290
|
-
"description": "Setter that writes the value back and clears the field's validation error, and
|
|
2290
|
+
"description": "Setter that writes the value back and clears the field's validation error, and every error under `<key>.` when the value is an array whose rows were added, removed, replaced or reordered (rows the slot draws itself)."
|
|
2291
2291
|
}
|
|
2292
2292
|
]
|
|
2293
2293
|
},
|
package/docs/public/docs-map.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Documentation Map
|
|
2
2
|
|
|
3
3
|
> Auto-generated hierarchical overview of all documentation
|
|
4
|
-
> Last updated: 2026-10-21T13:
|
|
4
|
+
> Last updated: 2026-10-21T13:19:32.105Z
|
|
5
5
|
|
|
6
6
|
This file provides a complete map of all available documentation for AI agents and developers.
|
|
7
7
|
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
@binding {FieldDefinition} field The field definition being rendered.
|
|
23
23
|
@binding {any} model The model passed to field predicates (defaults to the live form data).
|
|
24
24
|
@binding {any} value The current field value.
|
|
25
|
-
@binding {(value: any) => void} update Setter that writes the value back and clears the field's validation error, and
|
|
25
|
+
@binding {(value: any) => void} update Setter that writes the value back and clears the field's validation error, and every error under `<key>.` when the value is an array whose rows were added, removed, replaced or reordered (rows the slot draws itself).
|
|
26
26
|
-->
|
|
27
27
|
<slot
|
|
28
28
|
name="span"
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
@binding {FieldDefinition} field The field definition being rendered.
|
|
94
94
|
@binding {any} model The model passed to field predicates (defaults to the live form data).
|
|
95
95
|
@binding {any} value The current field value.
|
|
96
|
-
@binding {(value: any) => void} update Setter that writes the value back and clears the field's validation error, and
|
|
96
|
+
@binding {(value: any) => void} update Setter that writes the value back and clears the field's validation error, and every error under `<key>.` when the value is an array whose rows were added, removed, replaced or reordered (rows the slot draws itself).
|
|
97
97
|
-->
|
|
98
98
|
<slot
|
|
99
99
|
v-else-if="showValueSlot && $slots.value"
|
|
@@ -420,6 +420,7 @@ import {
|
|
|
420
420
|
onBeforeUnmount,
|
|
421
421
|
provide,
|
|
422
422
|
ref,
|
|
423
|
+
toRaw,
|
|
423
424
|
useId,
|
|
424
425
|
useSlots,
|
|
425
426
|
watch,
|
|
@@ -744,16 +745,51 @@ function setValue(value: any): void {
|
|
|
744
745
|
props.form.clearError(errorKey.value);
|
|
745
746
|
}
|
|
746
747
|
|
|
748
|
+
/** The raw rows of an array value, in order, or null for any other value. */
|
|
749
|
+
function rowIdentitiesOf(value: unknown): unknown[] | null {
|
|
750
|
+
return Array.isArray(value) ? value.map((row) => toRaw(row)) : null;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* The field's rows as last seen: refreshed by the watcher below whenever the
|
|
755
|
+
* array or its membership changes (not on edits inside a row), and by each
|
|
756
|
+
* slot `update`. The watcher runs before the next render, so a slot that
|
|
757
|
+
* changes the rows in place and calls `update` in the same handler is still
|
|
758
|
+
* compared against the rows from before the change.
|
|
759
|
+
*/
|
|
760
|
+
let lastSeenRows: unknown[] | null = null;
|
|
761
|
+
watch(
|
|
762
|
+
() => rowIdentitiesOf(fieldValue.value),
|
|
763
|
+
(rows) => {
|
|
764
|
+
lastSeenRows = rows;
|
|
765
|
+
},
|
|
766
|
+
{ immediate: true },
|
|
767
|
+
);
|
|
768
|
+
|
|
769
|
+
function haveRowsMoved(previous: unknown[] | null, next: unknown[]): boolean {
|
|
770
|
+
if (previous === null || previous.length !== next.length) return true;
|
|
771
|
+
return next.some((row, index) => row !== previous[index]);
|
|
772
|
+
}
|
|
773
|
+
|
|
747
774
|
/**
|
|
748
775
|
* `update` for the `span` and `value` slots (and so DXTable's `edit-span` /
|
|
749
|
-
* `edit-value`).
|
|
750
|
-
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
*
|
|
776
|
+
* `edit-value`). Like a plain set, it clears the field's own error. When the
|
|
777
|
+
* value is an array whose rows changed (added, removed, replaced or
|
|
778
|
+
* reordered, compared by identity with the rows as last seen), it also
|
|
779
|
+
* clears every error under `<key>.` (`lines.3.price`), as the repeater's add
|
|
780
|
+
* and remove do: a per-row error would otherwise stay under whichever row
|
|
781
|
+
* now sits at its index. An update that keeps the same rows in the same
|
|
782
|
+
* order (a row editor writing the array back on each keystroke), or a
|
|
783
|
+
* value that is not an array (an `address` object), keeps the nested
|
|
784
|
+
* errors: they still name the right place. They come back on the next
|
|
785
|
+
* submit either way.
|
|
754
786
|
*/
|
|
755
787
|
function setValueFromSlot(value: any): void {
|
|
788
|
+
const nextRows = rowIdentitiesOf(value);
|
|
789
|
+
const rowsMoved = nextRows !== null && haveRowsMoved(lastSeenRows, nextRows);
|
|
756
790
|
setValue(value);
|
|
791
|
+
if (nextRows !== null) lastSeenRows = nextRows;
|
|
792
|
+
if (!rowsMoved) return;
|
|
757
793
|
const prefix = `${errorKey.value}.`;
|
|
758
794
|
for (const key of Object.keys(props.form.errors)) {
|
|
759
795
|
if (key.startsWith(prefix)) {
|
|
@@ -1085,6 +1085,33 @@ function focusSelectedTab(): void {
|
|
|
1085
1085
|
document.getElementById(buttonIdFor(selectedKey))?.focus();
|
|
1086
1086
|
}
|
|
1087
1087
|
|
|
1088
|
+
/**
|
|
1089
|
+
* Focus a field's container rather than any control inside it: the field's
|
|
1090
|
+
* labelled group when it has one (a repeater's `fieldset`, announced by its
|
|
1091
|
+
* legend), else the marked element itself. It is made focusable for this
|
|
1092
|
+
* focus only (`tabindex="-1"`, removed again on blur), so the Tab order is
|
|
1093
|
+
* unchanged. Used when the row an error named is gone: every control inside
|
|
1094
|
+
* the field belongs to some other row. True once it holds focus.
|
|
1095
|
+
*/
|
|
1096
|
+
function focusFieldContainer(element: HTMLElement): boolean {
|
|
1097
|
+
const container =
|
|
1098
|
+
element.querySelector<HTMLElement>(':scope > fieldset, :scope > [role="group"]') ??
|
|
1099
|
+
element;
|
|
1100
|
+
if (!container.hasAttribute("tabindex")) {
|
|
1101
|
+
container.setAttribute("tabindex", "-1");
|
|
1102
|
+
container.addEventListener(
|
|
1103
|
+
"blur",
|
|
1104
|
+
() => container.removeAttribute("tabindex"),
|
|
1105
|
+
{ once: true },
|
|
1106
|
+
);
|
|
1107
|
+
}
|
|
1108
|
+
element.scrollIntoView({ block: "nearest" });
|
|
1109
|
+
container.focus({ preventScroll: true });
|
|
1110
|
+
if (document.activeElement === container) return true;
|
|
1111
|
+
if (container.getAttribute("tabindex") === "-1") container.removeAttribute("tabindex");
|
|
1112
|
+
return false;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1088
1115
|
/**
|
|
1089
1116
|
* Take the user to an error a summary lists: select its tab, wait for the
|
|
1090
1117
|
* pane to render, look the field up in the form (its marker, anywhere
|
|
@@ -1097,7 +1124,11 @@ function focusSelectedTab(): void {
|
|
|
1097
1124
|
* its key whenever its element leaves the DOM (a re-render replacing it),
|
|
1098
1125
|
* and a moment with none at all is waited out. When no marker renders
|
|
1099
1126
|
* within the field's render frames, or nothing in it takes focus, focus
|
|
1100
|
-
* moves to the selected tab's button.
|
|
1127
|
+
* moves to the selected tab's button. When the row the error named is gone
|
|
1128
|
+
* (`focusKey` is the field's key while `errorKey` names something under it:
|
|
1129
|
+
* the row was removed, replaced or soft-deleted), the field's container
|
|
1130
|
+
* takes focus instead of a control, since every control in it belongs to
|
|
1131
|
+
* another row (`focusFieldContainer`). Exposed so a summary rendered OUTSIDE
|
|
1101
1132
|
* the form (DXTable's modal footer) can drive it.
|
|
1102
1133
|
*/
|
|
1103
1134
|
async function focusErrorTarget(target: ErrorSummarySelection): Promise<void> {
|
|
@@ -1105,6 +1136,10 @@ async function focusErrorTarget(target: ErrorSummarySelection): Promise<void> {
|
|
|
1105
1136
|
commitTabKey(target.tabKey);
|
|
1106
1137
|
}
|
|
1107
1138
|
const token = ++revealToken;
|
|
1139
|
+
const isTargetGone =
|
|
1140
|
+
target.focusKey === target.fieldKey &&
|
|
1141
|
+
target.errorKey !== undefined &&
|
|
1142
|
+
target.errorKey !== target.fieldKey;
|
|
1108
1143
|
let element = await renderedErrorElement(
|
|
1109
1144
|
target.focusKey ?? target.errorKey ?? target.fieldKey,
|
|
1110
1145
|
target.fieldKey,
|
|
@@ -1114,6 +1149,10 @@ async function focusErrorTarget(target: ErrorSummarySelection): Promise<void> {
|
|
|
1114
1149
|
focusSelectedTab();
|
|
1115
1150
|
return;
|
|
1116
1151
|
}
|
|
1152
|
+
if (isTargetGone) {
|
|
1153
|
+
if (!focusFieldContainer(element)) focusSelectedTab();
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1117
1156
|
const path = element.getAttribute("data-dx-field-key") ?? target.fieldKey;
|
|
1118
1157
|
scrollFieldIntoView(element);
|
|
1119
1158
|
|
|
@@ -78,7 +78,9 @@ export interface ErrorSummarySelection {
|
|
|
78
78
|
/**
|
|
79
79
|
* Where to take the user: the error key at the failed row's current
|
|
80
80
|
* index, or the field's key when that row is gone (see
|
|
81
|
-
* `ErrorTarget.focusKey`)
|
|
81
|
+
* `ErrorTarget.focusKey`), when DXForm's `focusErrorTarget` focuses the
|
|
82
|
+
* field's container rather than any row's control. Equal to `errorKey`
|
|
83
|
+
* for everything else.
|
|
82
84
|
* Always emitted; optional so a selection built by hand for DXForm's
|
|
83
85
|
* exposed `focusErrorTarget` still types (it then uses `errorKey`).
|
|
84
86
|
*/
|
|
@@ -27,11 +27,19 @@ export interface SubmitFailure {
|
|
|
27
27
|
/** The validation errors the submit returned (`{}` when none). */
|
|
28
28
|
errors: ValidationErrors;
|
|
29
29
|
/**
|
|
30
|
-
* The rows the errors named,
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
30
|
+
* The rows the errors named, keyed by row path: the path up to the
|
|
31
|
+
* key's FIRST numeric segment (`lines.2` for `lines.2.price` and for
|
|
32
|
+
* `lines.2.options.0.name`; a row nested inside a row is not recorded,
|
|
33
|
+
* since the summary follows the outer row). Absent when no error key
|
|
34
|
+
* names a row that exists in the form data. The error summary uses it
|
|
35
|
+
* to keep naming and finding the row that failed after rows are removed
|
|
36
|
+
* or reordered.
|
|
37
|
+
*
|
|
38
|
+
* The rows are read from the form data when the failure response
|
|
39
|
+
* ARRIVES, not when the request was sent. Rows added, removed or
|
|
40
|
+
* reordered while the request was in flight, or a submit `transform`
|
|
41
|
+
* that drops or reorders rows, can attach an error to the wrong row
|
|
42
|
+
* here, exactly as a bare index key always could.
|
|
35
43
|
*/
|
|
36
44
|
failedRows?: Record<string, FailedRow>;
|
|
37
45
|
}
|
|
@@ -249,8 +257,14 @@ function submitFailureFrom(error: unknown): SubmitFailure | null {
|
|
|
249
257
|
|
|
250
258
|
/**
|
|
251
259
|
* A copy of a row for `FailedRow.snapshot`: a deep clone when the row allows
|
|
252
|
-
* one
|
|
253
|
-
* `structuredClone` refuses still gets a name
|
|
260
|
+
* one (`File`, `Blob` and `Date` values clone fine), else a shallow copy, so
|
|
261
|
+
* a row `structuredClone` refuses still gets a name. It refuses a row
|
|
262
|
+
* holding a function, a symbol, a DOM node or a proxy (a reactive object
|
|
263
|
+
* nested in the row: the row itself is raw, the objects inside it may not
|
|
264
|
+
* be). A class instance does NOT make it throw: it is cloned as a plain
|
|
265
|
+
* object, losing its prototype, getters and private fields, so a `rowLabel`
|
|
266
|
+
* reading a getter on such a value reads `undefined` (and falls back to the
|
|
267
|
+
* line form).
|
|
254
268
|
*/
|
|
255
269
|
function snapshotRow(row: object): Record<string, any> {
|
|
256
270
|
try {
|
|
@@ -262,7 +276,10 @@ function snapshotRow(row: object): Record<string, any> {
|
|
|
262
276
|
|
|
263
277
|
/**
|
|
264
278
|
* The `failedRows` for a failure's error keys, read from the form data as it
|
|
265
|
-
* is when the failure is recorded.
|
|
279
|
+
* is when the failure is recorded. Only the row at a key's first numeric
|
|
280
|
+
* segment is recorded: that is the only one the error summary reads
|
|
281
|
+
* (`<field key>.<index>`), so deeper rows would be cloned for nothing.
|
|
282
|
+
* Undefined when no key names a row.
|
|
266
283
|
*/
|
|
267
284
|
function failedRowsFor(
|
|
268
285
|
errors: ValidationErrors,
|
|
@@ -271,14 +288,15 @@ function failedRowsFor(
|
|
|
271
288
|
const rows: Record<string, FailedRow> = {};
|
|
272
289
|
for (const errorKey of Object.keys(errors)) {
|
|
273
290
|
const segments = errorKey.split(".");
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
291
|
+
const firstRowSegment = segments.findIndex(
|
|
292
|
+
(segment, index) => index > 0 && /^\d+$/.test(segment),
|
|
293
|
+
);
|
|
294
|
+
if (firstRowSegment < 0) continue;
|
|
295
|
+
const rowPath = segments.slice(0, firstRowSegment + 1).join(".");
|
|
296
|
+
if (rows[rowPath] !== undefined) continue;
|
|
297
|
+
const row = toRaw(getByPath(data, rowPath));
|
|
298
|
+
if (row === null || typeof row !== "object") continue;
|
|
299
|
+
rows[rowPath] = markRaw({ row, snapshot: snapshotRow(row) });
|
|
282
300
|
}
|
|
283
301
|
return Object.keys(rows).length > 0 ? rows : undefined;
|
|
284
302
|
}
|
|
@@ -278,7 +278,9 @@ export interface FieldDefinition {
|
|
|
278
278
|
* For a field whose value is a list of rows (a `repeater`, or a span
|
|
279
279
|
* field that renders its own rows and owns `key.N.*` error keys): the
|
|
280
280
|
* row's own name, called with the row (`model[key][index]`, or `{}` when
|
|
281
|
-
* the model has no such row) and its 0-based index
|
|
281
|
+
* the model has no such row) and its 0-based index (for a failure's row
|
|
282
|
+
* that has since moved, its current index; once removed, the index it
|
|
283
|
+
* failed at: the index "(line N)" counts). When it returns a
|
|
282
284
|
* non-empty string, the error summary lists that row's errors under it
|
|
283
285
|
* alone ("Chaucer Ale (Pint): Enter a price.") instead of
|
|
284
286
|
* "<sub-field label> (line N)". Returning `undefined`, `null` or `""`
|
|
@@ -24,8 +24,10 @@ export interface ErrorTarget {
|
|
|
24
24
|
* Where to take the user for this error now. The same as `errorKey`,
|
|
25
25
|
* except for a row error resolved with `failedRows`: the key at the
|
|
26
26
|
* failed row's CURRENT index (`lines.1.price` once row 0 is removed),
|
|
27
|
-
* or the owning field's key when that row is gone
|
|
28
|
-
*
|
|
27
|
+
* or the owning field's key when that row is gone (removed, replaced, or
|
|
28
|
+
* flagged by the field's `softDeleteKey`); DXForm then focuses the
|
|
29
|
+
* field's container, not a row. Always set by `resolveErrorTargets`;
|
|
30
|
+
* optional so targets built by hand still type.
|
|
29
31
|
*/
|
|
30
32
|
focusKey?: string;
|
|
31
33
|
/** The server's messages for that key, as sent. */
|
|
@@ -288,12 +290,21 @@ export function resolveErrorTargets(
|
|
|
288
290
|
|
|
289
291
|
/**
|
|
290
292
|
* Where a failed row is now: its index in the field's live rows, found by
|
|
291
|
-
* identity, or -1 when it is gone (removed,
|
|
293
|
+
* identity, or -1 when it is gone (removed, the rows were replaced, or
|
|
294
|
+
* the row carries the field's `softDeleteKey` flag: DXRepeater keeps
|
|
295
|
+
* such a row in the array, so it is submitted, but no longer renders it).
|
|
292
296
|
*/
|
|
293
297
|
const currentIndexOf = (field: FieldDefinition, failedRow: FailedRow): number => {
|
|
294
298
|
const liveRows = getByPath(model, field.key);
|
|
295
299
|
if (!Array.isArray(liveRows)) return -1;
|
|
296
|
-
|
|
300
|
+
const index = liveRows.findIndex((row) => toRaw(row) === failedRow.row);
|
|
301
|
+
if (index < 0) return -1;
|
|
302
|
+
// Read the flag through the LIVE row (a reactive proxy in a form),
|
|
303
|
+
// not the raw `failedRow.row`, so a caller's computed re-resolves
|
|
304
|
+
// when the row is flagged.
|
|
305
|
+
const softDeleteKey = field.softDeleteKey;
|
|
306
|
+
if (softDeleteKey && Boolean(liveRows[index]?.[softDeleteKey])) return -1;
|
|
307
|
+
return index;
|
|
297
308
|
};
|
|
298
309
|
|
|
299
310
|
/**
|
|
@@ -303,7 +314,8 @@ export function resolveErrorTargets(
|
|
|
303
314
|
* focus key uses the row's current index, or is the field's key when the
|
|
304
315
|
* row is gone. "(line N)" then counts the row's CURRENT position while it
|
|
305
316
|
* exists (the line a click takes the user to), and the position it failed
|
|
306
|
-
* at once it is gone.
|
|
317
|
+
* at once it is gone. `rowLabel(row, index)` is given that same index, so
|
|
318
|
+
* a name built from the index agrees with the line form.
|
|
307
319
|
*/
|
|
308
320
|
const ownedTarget = (
|
|
309
321
|
errorKey: string,
|
|
@@ -344,7 +356,7 @@ export function resolveErrorTargets(
|
|
|
344
356
|
const row = getByPath(model, `${field.key}.${first}`);
|
|
345
357
|
rowModel = row !== null && typeof row === "object" ? row : {};
|
|
346
358
|
}
|
|
347
|
-
const rowName = rowLabelFor(field, rowModel,
|
|
359
|
+
const rowName = rowLabelFor(field, rowModel, lineIndex);
|
|
348
360
|
if (rowName !== null) return { label: rowName, focusKey };
|
|
349
361
|
const base = subField ? labelFor(subField, rowModel) : labelFor(field);
|
|
350
362
|
return { label: `${base} (line ${lineIndex + 1})`, focusKey };
|