@byline/admin 3.19.0 → 3.20.1

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.
@@ -24,6 +24,13 @@ const ArrayField = ({ field, defaultValue, path, disableSorting = false, collect
24
24
  getFieldValue,
25
25
  path
26
26
  ]);
27
+ const patchItemId = (item, index)=>{
28
+ if (item && 'object' == typeof item) {
29
+ if ('_id' in item) return String(item._id);
30
+ if ('id' in item) return String(item.id);
31
+ }
32
+ return String(index);
33
+ };
27
34
  const handleDragEnd = ({ moveFromIndex, moveToIndex })=>{
28
35
  setItems((prev)=>moveItem(prev, moveFromIndex, moveToIndex));
29
36
  const currentArray = getFieldValue(path) ?? defaultValue;
@@ -32,11 +39,10 @@ const ArrayField = ({ field, defaultValue, path, disableSorting = false, collect
32
39
  const clampedTo = Math.max(0, Math.min(moveToIndex, currentArray.length - 1));
33
40
  if (clampedFrom === clampedTo) return;
34
41
  const item = currentArray[clampedFrom];
35
- const itemId = item && 'object' == typeof item && 'id' in item ? String(item.id) : String(clampedFrom);
36
42
  appendPatch({
37
43
  kind: 'array.move',
38
44
  path: path,
39
- itemId,
45
+ itemId: patchItemId(item, clampedFrom),
40
46
  toIndex: clampedTo
41
47
  });
42
48
  }
@@ -45,7 +51,9 @@ const ArrayField = ({ field, defaultValue, path, disableSorting = false, collect
45
51
  const childFields = field.fields ?? [];
46
52
  if (0 === childFields.length) return;
47
53
  const newId = crypto.randomUUID();
48
- const newItem = {};
54
+ const newItem = {
55
+ _id: newId
56
+ };
49
57
  for (const childField of childFields)if ('group' === childField.type && childField.fields && childField.fields.length > 0) {
50
58
  const groupObj = {};
51
59
  for (const innerField of childField.fields)groupObj[innerField.name] = await defaultScalarForField(innerField, getFieldValues);
@@ -80,12 +88,11 @@ const ArrayField = ({ field, defaultValue, path, disableSorting = false, collect
80
88
  const currentArray = getFieldValue(path) ?? defaultValue;
81
89
  if (!Array.isArray(currentArray) || index < 0 || index >= currentArray.length) return;
82
90
  const item = currentArray[index];
83
- const itemId = item && 'object' == typeof item && 'id' in item ? String(item.id) : String(index);
84
91
  setItems((prev)=>prev.filter((_, i)=>i !== index));
85
92
  appendPatch({
86
93
  kind: 'array.remove',
87
94
  path: path,
88
- itemId
95
+ itemId: patchItemId(item, index)
89
96
  });
90
97
  const newArrayValue = [
91
98
  ...currentArray
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@byline/admin",
3
3
  "private": false,
4
4
  "license": "MPL-2.0",
5
- "version": "3.19.0",
5
+ "version": "3.20.1",
6
6
  "engines": {
7
7
  "node": ">=20.9.0"
8
8
  },
@@ -155,10 +155,10 @@
155
155
  "react-diff-viewer-continued": "^4.2.2",
156
156
  "uuid": "^14.0.1",
157
157
  "zod": "^4.4.3",
158
- "@byline/auth": "3.19.0",
159
- "@byline/ui": "3.19.0",
160
- "@byline/core": "3.19.0",
161
- "@byline/i18n": "3.19.0"
158
+ "@byline/auth": "3.20.1",
159
+ "@byline/i18n": "3.20.1",
160
+ "@byline/ui": "3.20.1",
161
+ "@byline/core": "3.20.1"
162
162
  },
163
163
  "peerDependencies": {
164
164
  "react": "^19.0.0",
@@ -80,6 +80,23 @@ export const ArrayField = ({
80
80
  }
81
81
  }, [defaultValue, getFieldValue, path])
82
82
 
83
+ /**
84
+ * Stable patch identity for an array item. Persisted items carry `_id`
85
+ * (the array-item identity from `store_meta`) — that is what the server's
86
+ * patch engine matches on (`applyArrayPatch`: `item._id === patch.itemId`),
87
+ * so it MUST be preferred here. `id` is accepted as a legacy/seed-data
88
+ * alias. Items added this session have neither (the storage layer assigns
89
+ * `_id` at write time), so fall back to the item's current index — the
90
+ * patch engine resolves a pure-integer itemId as an index fallback.
91
+ */
92
+ const patchItemId = (item: unknown, index: number): string => {
93
+ if (item && typeof item === 'object') {
94
+ if ('_id' in item) return String((item as { _id: string })._id)
95
+ if ('id' in item) return String((item as { id: string }).id)
96
+ }
97
+ return String(index)
98
+ }
99
+
83
100
  const handleDragEnd = ({
84
101
  moveFromIndex,
85
102
  moveToIndex,
@@ -96,15 +113,11 @@ export const ArrayField = ({
96
113
  if (clampedFrom === clampedTo) return
97
114
 
98
115
  const item = currentArray[clampedFrom]
99
- const itemId =
100
- item && typeof item === 'object' && 'id' in item
101
- ? String((item as { id: string }).id)
102
- : String(clampedFrom)
103
116
 
104
117
  appendPatch({
105
118
  kind: 'array.move',
106
119
  path: path,
107
- itemId,
120
+ itemId: patchItemId(item, clampedFrom),
108
121
  toIndex: clampedTo,
109
122
  })
110
123
  }
@@ -116,8 +129,12 @@ export const ArrayField = ({
116
129
 
117
130
  const newId = crypto.randomUUID()
118
131
 
119
- // Build a new item with default values for ALL child fields
120
- const newItem: Record<string, any> = {}
132
+ // Build a new item with default values for ALL child fields.
133
+ // Assign the stable `_id` client-side — exactly like BlocksField's
134
+ // handleAddItem — so the item is patch-addressable (move / remove by
135
+ // `_id`) within the same editing session, before any server write has
136
+ // assigned identity. The storage layer persists `_id` via store_meta.
137
+ const newItem: Record<string, any> = { _id: newId }
121
138
  for (const childField of childFields) {
122
139
  if (childField.type === 'group' && childField.fields && childField.fields.length > 0) {
123
140
  // Group child — build a nested object with defaults for each inner field
@@ -158,17 +175,13 @@ export const ArrayField = ({
158
175
  if (!Array.isArray(currentArray) || index < 0 || index >= currentArray.length) return
159
176
 
160
177
  const item = currentArray[index]
161
- const itemId =
162
- item && typeof item === 'object' && 'id' in item
163
- ? String((item as { id: string }).id)
164
- : String(index)
165
178
 
166
179
  setItems((prev) => prev.filter((_, i) => i !== index))
167
180
 
168
181
  appendPatch({
169
182
  kind: 'array.remove',
170
183
  path: path,
171
- itemId,
184
+ itemId: patchItemId(item, index),
172
185
  })
173
186
 
174
187
  const newArrayValue = [...currentArray]