@wordpress/fields 0.31.1-next.v.202602091733.0 → 0.32.0

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.
Files changed (76) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +1 -1
  3. package/build/actions/duplicate-post.cjs.map +1 -1
  4. package/build/actions/reorder-page.cjs.map +1 -1
  5. package/build/components/create-template-part-modal/index.cjs +2 -5
  6. package/build/components/create-template-part-modal/index.cjs.map +3 -3
  7. package/build/components/media-edit/index.cjs +372 -157
  8. package/build/components/media-edit/index.cjs.map +3 -3
  9. package/build/components/media-edit/use-moving-animation.cjs +75 -0
  10. package/build/components/media-edit/use-moving-animation.cjs.map +7 -0
  11. package/build/fields/featured-image/index.cjs +2 -1
  12. package/build/fields/featured-image/index.cjs.map +2 -2
  13. package/build/fields/template/hooks.cjs +96 -0
  14. package/build/fields/template/hooks.cjs.map +7 -0
  15. package/build/fields/template/index.cjs +2 -0
  16. package/build/fields/template/index.cjs.map +2 -2
  17. package/build/fields/template/template-edit.cjs +33 -114
  18. package/build/fields/template/template-edit.cjs.map +3 -3
  19. package/build/fields/template/template-view.cjs +68 -0
  20. package/build/fields/template/template-view.cjs.map +7 -0
  21. package/build/fields/template/utils.cjs +91 -0
  22. package/build/fields/template/utils.cjs.map +7 -0
  23. package/build-module/actions/duplicate-post.mjs.map +1 -1
  24. package/build-module/actions/reorder-page.mjs.map +1 -1
  25. package/build-module/components/create-template-part-modal/index.mjs +3 -6
  26. package/build-module/components/create-template-part-modal/index.mjs.map +2 -2
  27. package/build-module/components/media-edit/index.mjs +379 -159
  28. package/build-module/components/media-edit/index.mjs.map +2 -2
  29. package/build-module/components/media-edit/use-moving-animation.mjs +54 -0
  30. package/build-module/components/media-edit/use-moving-animation.mjs.map +7 -0
  31. package/build-module/fields/featured-image/index.mjs +2 -1
  32. package/build-module/fields/featured-image/index.mjs.map +2 -2
  33. package/build-module/fields/template/hooks.mjs +71 -0
  34. package/build-module/fields/template/hooks.mjs.map +7 -0
  35. package/build-module/fields/template/index.mjs +2 -0
  36. package/build-module/fields/template/index.mjs.map +2 -2
  37. package/build-module/fields/template/template-edit.mjs +36 -123
  38. package/build-module/fields/template/template-edit.mjs.map +2 -2
  39. package/build-module/fields/template/template-view.mjs +43 -0
  40. package/build-module/fields/template/template-view.mjs.map +7 -0
  41. package/build-module/fields/template/utils.mjs +65 -0
  42. package/build-module/fields/template/utils.mjs.map +7 -0
  43. package/build-style/style-rtl.css +69 -61
  44. package/build-style/style.css +69 -61
  45. package/build-types/actions/duplicate-post.d.ts +1 -1
  46. package/build-types/actions/duplicate-post.d.ts.map +1 -1
  47. package/build-types/actions/reorder-page.d.ts +1 -1
  48. package/build-types/actions/reorder-page.d.ts.map +1 -1
  49. package/build-types/components/create-template-part-modal/index.d.ts.map +1 -1
  50. package/build-types/components/media-edit/index.d.ts +1 -1
  51. package/build-types/components/media-edit/index.d.ts.map +1 -1
  52. package/build-types/components/media-edit/use-moving-animation.d.ts +13 -0
  53. package/build-types/components/media-edit/use-moving-animation.d.ts.map +1 -0
  54. package/build-types/fields/template/hooks.d.ts +10 -0
  55. package/build-types/fields/template/hooks.d.ts.map +1 -0
  56. package/build-types/fields/template/index.d.ts.map +1 -1
  57. package/build-types/fields/template/template-edit.d.ts.map +1 -1
  58. package/build-types/fields/template/template-view.d.ts +4 -0
  59. package/build-types/fields/template/template-view.d.ts.map +1 -0
  60. package/build-types/fields/template/utils.d.ts +28 -0
  61. package/build-types/fields/template/utils.d.ts.map +1 -0
  62. package/package.json +27 -26
  63. package/src/actions/duplicate-post.tsx +1 -1
  64. package/src/actions/reorder-page.tsx +1 -1
  65. package/src/components/create-template-part-modal/index.tsx +5 -14
  66. package/src/components/media-edit/index.tsx +420 -163
  67. package/src/components/media-edit/style.scss +83 -30
  68. package/src/components/media-edit/use-moving-animation.ts +77 -0
  69. package/src/fields/featured-image/index.tsx +1 -1
  70. package/src/fields/template/hooks.ts +121 -0
  71. package/src/fields/template/index.ts +2 -0
  72. package/src/fields/template/template-edit.tsx +38 -149
  73. package/src/fields/template/template-view.tsx +52 -0
  74. package/src/fields/template/utils.ts +119 -0
  75. package/src/style.scss +0 -1
  76. package/src/fields/template/style.scss +0 -34
@@ -8,6 +8,7 @@ import {
8
8
  __experimentalText as Text,
9
9
  __experimentalTruncate as Truncate,
10
10
  __experimentalVStack as VStack,
11
+ __experimentalHStack as HStack,
11
12
  BaseControl,
12
13
  Tooltip,
13
14
  VisuallyHidden
@@ -22,14 +23,18 @@ import {
22
23
  useRef,
23
24
  useState
24
25
  } from "@wordpress/element";
25
- import { __ } from "@wordpress/i18n";
26
+ import { __, sprintf } from "@wordpress/i18n";
26
27
  import {
27
28
  archive,
28
29
  audio,
29
30
  video,
30
31
  file,
31
32
  closeSmall,
32
- error as errorIcon
33
+ error as errorIcon,
34
+ chevronUp,
35
+ chevronDown,
36
+ chevronLeft,
37
+ chevronRight
33
38
  } from "@wordpress/icons";
34
39
  import {
35
40
  MediaUpload,
@@ -38,8 +43,23 @@ import {
38
43
  } from "@wordpress/media-utils";
39
44
  import { store as noticesStore } from "@wordpress/notices";
40
45
  import { unlock } from "../../lock-unlock.mjs";
46
+ import useMovingAnimation from "./use-moving-animation.mjs";
41
47
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
42
48
  var { MediaUploadModal } = unlock(mediaUtilsPrivateApis);
49
+ function AnimatedMediaItem({
50
+ children,
51
+ index,
52
+ className
53
+ }) {
54
+ const ref = useMovingAnimation(index);
55
+ return /* @__PURE__ */ jsx("div", { ref, className, children });
56
+ }
57
+ function normalizeValue(value) {
58
+ if (Array.isArray(value)) {
59
+ return value;
60
+ }
61
+ return value ? [value] : [];
62
+ }
43
63
  function ConditionalMediaUpload({ render, multiple, ...props }) {
44
64
  const [isModalOpen, setIsModalOpen] = useState(false);
45
65
  if (window.__experimentalDataViewsMediaModal) {
@@ -85,7 +105,9 @@ function MediaPickerButton({
85
105
  const mediaPickerButton = /* @__PURE__ */ jsxs(
86
106
  "div",
87
107
  {
88
- className: "fields__media-edit-picker-button",
108
+ className: clsx("fields__media-edit-picker-button", {
109
+ "has-attachment": attachment
110
+ }),
89
111
  role: "button",
90
112
  tabIndex: 0,
91
113
  onClick: () => {
@@ -119,7 +141,7 @@ function MediaPickerButton({
119
141
  if (!showTooltip) {
120
142
  return mediaPickerButton;
121
143
  }
122
- return /* @__PURE__ */ jsx(Tooltip, { text: label, children: mediaPickerButton });
144
+ return /* @__PURE__ */ jsx(Tooltip, { text: label, placement: "top", children: mediaPickerButton });
123
145
  }
124
146
  var archiveMimeTypes = [
125
147
  "application/zip",
@@ -135,6 +157,50 @@ function MediaTitle({ attachment }) {
135
157
  function MediaEditPlaceholder(props) {
136
158
  return /* @__PURE__ */ jsx(MediaPickerButton, { ...props, children: /* @__PURE__ */ jsx("span", { className: "fields__media-edit-placeholder", children: props.label }) });
137
159
  }
160
+ function MoveButtons({
161
+ itemId,
162
+ index,
163
+ totalItems,
164
+ isUploading,
165
+ moveItem,
166
+ orientation = "vertical"
167
+ }) {
168
+ const isHorizontal = orientation === "horizontal";
169
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
170
+ /* @__PURE__ */ jsx(
171
+ Button,
172
+ {
173
+ __next40pxDefaultSize: true,
174
+ icon: isHorizontal ? chevronLeft : chevronUp,
175
+ label: isHorizontal ? __("Move left") : __("Move up"),
176
+ size: "small",
177
+ disabled: isUploading || index === 0,
178
+ accessibleWhenDisabled: true,
179
+ tooltipPosition: "top",
180
+ onClick: (event) => {
181
+ event.stopPropagation();
182
+ moveItem(itemId, "up");
183
+ }
184
+ }
185
+ ),
186
+ /* @__PURE__ */ jsx(
187
+ Button,
188
+ {
189
+ __next40pxDefaultSize: true,
190
+ icon: isHorizontal ? chevronRight : chevronDown,
191
+ label: isHorizontal ? __("Move right") : __("Move down"),
192
+ size: "small",
193
+ disabled: isUploading || index === totalItems - 1,
194
+ accessibleWhenDisabled: true,
195
+ tooltipPosition: "top",
196
+ onClick: (event) => {
197
+ event.stopPropagation();
198
+ moveItem(itemId, "down");
199
+ }
200
+ }
201
+ )
202
+ ] });
203
+ }
138
204
  function MediaPreview({ attachment }) {
139
205
  const url = attachment.source_url;
140
206
  const mimeType = attachment.mime_type || "";
@@ -161,9 +227,11 @@ function ExpandedMediaEditAttachments({
161
227
  addButtonLabel,
162
228
  multiple,
163
229
  removeItem,
230
+ moveItem,
164
231
  open,
165
232
  onFilesDrop,
166
- isUploading
233
+ isUploading,
234
+ setTargetItemId
167
235
  }) {
168
236
  return /* @__PURE__ */ jsxs(
169
237
  "div",
@@ -174,12 +242,14 @@ function ExpandedMediaEditAttachments({
174
242
  "is-empty": !allItems?.length
175
243
  }),
176
244
  children: [
177
- allItems?.map((attachment) => {
245
+ allItems?.map((attachment, index) => {
178
246
  const hasPreviewImage = attachment.mime_type?.startsWith("image");
179
247
  const isBlob = isBlobURL(attachment.source_url);
248
+ const attachmentNumericId = attachment.id;
180
249
  return /* @__PURE__ */ jsxs(
181
- "div",
250
+ AnimatedMediaItem,
182
251
  {
252
+ index,
183
253
  className: clsx("fields__media-edit-expanded-item", {
184
254
  "has-preview-image": hasPreviewImage
185
255
  }),
@@ -187,56 +257,72 @@ function ExpandedMediaEditAttachments({
187
257
  /* @__PURE__ */ jsx(
188
258
  MediaPickerButton,
189
259
  {
190
- open,
191
- label: __("Replace"),
260
+ open: () => {
261
+ setTargetItemId(attachmentNumericId);
262
+ open();
263
+ },
264
+ label: !isBlob ? sprintf(
265
+ /* translators: %s: The title of the media item. */
266
+ __("Replace %s"),
267
+ attachment.title.rendered
268
+ ) : __("Replace"),
192
269
  showTooltip: true,
193
270
  onFilesDrop,
194
271
  attachment,
195
272
  isUploading,
196
- children: /* @__PURE__ */ jsx("div", { className: "fields__media-edit-expanded-preview", children: /* @__PURE__ */ jsxs(
273
+ children: /* @__PURE__ */ jsx("div", { className: "fields__media-edit-expanded-preview", children: /* @__PURE__ */ jsx(
197
274
  VStack,
198
275
  {
199
276
  spacing: 0,
200
277
  alignment: "center",
201
278
  justify: "center",
202
279
  className: "fields__media-edit-expanded-preview-stack",
203
- children: [
204
- (!isBlob || hasPreviewImage) && /* @__PURE__ */ jsx(
205
- MediaPreview,
206
- {
207
- attachment
208
- }
209
- ),
210
- !isBlob && (!hasPreviewImage ? /* @__PURE__ */ jsx(
211
- MediaTitle,
212
- {
213
- attachment
214
- }
215
- ) : /* @__PURE__ */ jsx("div", { className: "fields__media-edit-expanded-overlay", children: /* @__PURE__ */ jsx("div", { className: "fields__media-edit-expanded-title", children: /* @__PURE__ */ jsx(
216
- MediaTitle,
217
- {
218
- attachment
219
- }
220
- ) }) }))
221
- ]
280
+ children: (!isBlob || hasPreviewImage) && /* @__PURE__ */ jsx(
281
+ MediaPreview,
282
+ {
283
+ attachment
284
+ }
285
+ )
222
286
  }
223
287
  ) })
224
288
  }
225
289
  ),
226
- !isBlob && /* @__PURE__ */ jsx("div", { className: "fields__media-edit-expanded-overlay", children: /* @__PURE__ */ jsx(
227
- Button,
290
+ !isBlob && /* @__PURE__ */ jsx("div", { className: "fields__media-edit-expanded-overlay", children: /* @__PURE__ */ jsxs(
291
+ HStack,
228
292
  {
229
- __next40pxDefaultSize: true,
230
- className: "fields__media-edit-expanded-remove",
231
- icon: closeSmall,
232
- label: __("Remove"),
233
- size: "small",
234
- disabled: isUploading,
235
- accessibleWhenDisabled: true,
236
- onClick: (event) => {
237
- event.stopPropagation();
238
- removeItem(attachment.id);
239
- }
293
+ className: "fields__media-edit-expanded-actions",
294
+ spacing: 0,
295
+ alignment: "flex-end",
296
+ expanded: false,
297
+ children: [
298
+ multiple && allItems.length > 1 && /* @__PURE__ */ jsx(
299
+ MoveButtons,
300
+ {
301
+ itemId: attachmentNumericId,
302
+ index,
303
+ totalItems: allItems.length,
304
+ isUploading,
305
+ moveItem,
306
+ orientation: "horizontal"
307
+ }
308
+ ),
309
+ /* @__PURE__ */ jsx(
310
+ Button,
311
+ {
312
+ __next40pxDefaultSize: true,
313
+ icon: closeSmall,
314
+ label: __("Remove"),
315
+ size: "small",
316
+ disabled: isUploading,
317
+ accessibleWhenDisabled: true,
318
+ tooltipPosition: "top",
319
+ onClick: (event) => {
320
+ event.stopPropagation();
321
+ removeItem(attachmentNumericId);
322
+ }
323
+ }
324
+ )
325
+ ]
240
326
  }
241
327
  ) })
242
328
  ]
@@ -247,7 +333,10 @@ function ExpandedMediaEditAttachments({
247
333
  (multiple || !allItems?.length) && /* @__PURE__ */ jsx(
248
334
  MediaEditPlaceholder,
249
335
  {
250
- open,
336
+ open: () => {
337
+ setTargetItemId(void 0);
338
+ open();
339
+ },
251
340
  label: addButtonLabel,
252
341
  onFilesDrop,
253
342
  isUploading
@@ -262,69 +351,113 @@ function CompactMediaEditAttachments({
262
351
  addButtonLabel,
263
352
  multiple,
264
353
  removeItem,
354
+ moveItem,
265
355
  open,
266
356
  onFilesDrop,
267
- isUploading
357
+ isUploading,
358
+ setTargetItemId
268
359
  }) {
269
360
  return /* @__PURE__ */ jsxs(Fragment, { children: [
270
- !!allItems?.length && /* @__PURE__ */ jsx(VStack, { spacing: 2, children: allItems.map((attachment) => {
271
- const isBlob = isBlobURL(attachment.source_url);
272
- return /* @__PURE__ */ jsxs(
273
- "div",
274
- {
275
- className: "fields__media-edit-compact",
276
- children: [
277
- /* @__PURE__ */ jsx(
278
- MediaPickerButton,
279
- {
280
- open,
281
- label: __("Replace"),
282
- showTooltip: true,
283
- onFilesDrop,
284
- attachment,
285
- isUploading,
286
- children: /* @__PURE__ */ jsxs(Fragment, { children: [
287
- /* @__PURE__ */ jsx(
288
- MediaPreview,
289
- {
290
- attachment
291
- }
292
- ),
293
- !isBlob && /* @__PURE__ */ jsx(
294
- MediaTitle,
295
- {
296
- attachment
297
- }
298
- )
299
- ] })
300
- }
301
- ),
302
- /* @__PURE__ */ jsx(
303
- Button,
304
- {
305
- __next40pxDefaultSize: true,
306
- className: "fields__media-edit-remove",
307
- text: __("Remove"),
308
- variant: "secondary",
309
- disabled: isUploading,
310
- accessibleWhenDisabled: true,
311
- onClick: (event) => {
312
- event.stopPropagation();
313
- if (typeof attachment.id === "number") {
314
- removeItem(attachment.id);
361
+ !!allItems?.length && /* @__PURE__ */ jsx(
362
+ "div",
363
+ {
364
+ className: clsx("fields__media-edit-compact-group", {
365
+ "is-single": allItems.length === 1
366
+ }),
367
+ children: /* @__PURE__ */ jsx(VStack, { spacing: 0, children: allItems.map((attachment, index) => {
368
+ const isBlob = isBlobURL(attachment.source_url);
369
+ const showMoveButtons = multiple && allItems.length > 1;
370
+ const attachmentNumericId = attachment.id;
371
+ return /* @__PURE__ */ jsxs(
372
+ AnimatedMediaItem,
373
+ {
374
+ index,
375
+ className: "fields__media-edit-compact",
376
+ children: [
377
+ /* @__PURE__ */ jsx(
378
+ MediaPickerButton,
379
+ {
380
+ open: () => {
381
+ setTargetItemId(
382
+ attachmentNumericId
383
+ );
384
+ open();
385
+ },
386
+ label: __("Replace"),
387
+ showTooltip: true,
388
+ onFilesDrop,
389
+ attachment,
390
+ isUploading,
391
+ children: /* @__PURE__ */ jsxs(Fragment, { children: [
392
+ /* @__PURE__ */ jsx(
393
+ MediaPreview,
394
+ {
395
+ attachment
396
+ }
397
+ ),
398
+ !isBlob && /* @__PURE__ */ jsx(
399
+ MediaTitle,
400
+ {
401
+ attachment
402
+ }
403
+ )
404
+ ] })
315
405
  }
316
- }
317
- }
318
- )
319
- ]
320
- },
321
- attachment.id
322
- );
323
- }) }),
406
+ ),
407
+ !isBlob && /* @__PURE__ */ jsxs(
408
+ HStack,
409
+ {
410
+ className: "fields__media-edit-compact-movers",
411
+ spacing: 0,
412
+ alignment: "flex-end",
413
+ expanded: false,
414
+ children: [
415
+ showMoveButtons && /* @__PURE__ */ jsx(
416
+ MoveButtons,
417
+ {
418
+ itemId: attachmentNumericId,
419
+ index,
420
+ totalItems: allItems.length,
421
+ isUploading,
422
+ moveItem,
423
+ orientation: "vertical"
424
+ }
425
+ ),
426
+ /* @__PURE__ */ jsx(
427
+ Button,
428
+ {
429
+ __next40pxDefaultSize: true,
430
+ icon: closeSmall,
431
+ label: __("Remove"),
432
+ size: "small",
433
+ disabled: isUploading,
434
+ accessibleWhenDisabled: true,
435
+ tooltipPosition: "top",
436
+ onClick: (event) => {
437
+ event.stopPropagation();
438
+ removeItem(
439
+ attachmentNumericId
440
+ );
441
+ }
442
+ }
443
+ )
444
+ ]
445
+ }
446
+ )
447
+ ]
448
+ },
449
+ attachment.id
450
+ );
451
+ }) })
452
+ }
453
+ ),
324
454
  (multiple || !allItems?.length) && /* @__PURE__ */ jsx(
325
455
  MediaEditPlaceholder,
326
456
  {
327
- open,
457
+ open: () => {
458
+ setTargetItemId(void 0);
459
+ open();
460
+ },
328
461
  label: addButtonLabel,
329
462
  onFilesDrop,
330
463
  isUploading
@@ -359,111 +492,162 @@ function MediaEdit({
359
492
  if (!value) {
360
493
  return null;
361
494
  }
362
- const normalizedValue = Array.isArray(value) ? value : [value];
495
+ const normalizedValue = normalizeValue(value);
496
+ const sortedIds = [...normalizedValue].sort((a, b) => a - b);
363
497
  const { getEntityRecords } = select(coreStore);
364
498
  return getEntityRecords("postType", "attachment", {
365
- include: normalizedValue
499
+ include: sortedIds
366
500
  });
367
501
  },
368
502
  [value]
369
503
  );
504
+ const stableAttachmentsRef = useRef(
505
+ null
506
+ );
507
+ if (attachments !== null) {
508
+ stableAttachmentsRef.current = attachments;
509
+ }
510
+ let stableAttachments = attachments;
511
+ if (attachments === null && stableAttachmentsRef.current && value) {
512
+ const stableIds = new Set(
513
+ stableAttachmentsRef.current.map((a) => a.id)
514
+ );
515
+ if (normalizeValue(value).every((id) => stableIds.has(id))) {
516
+ stableAttachments = stableAttachmentsRef.current;
517
+ }
518
+ }
519
+ const orderedAttachments = useMemo(() => {
520
+ if (!stableAttachments) {
521
+ return null;
522
+ }
523
+ const normalizedValue = normalizeValue(value);
524
+ const attachmentMap = new Map(
525
+ stableAttachments.map((a) => [a.id, a])
526
+ );
527
+ return normalizedValue.map((id) => attachmentMap.get(id)).filter((a) => a !== void 0);
528
+ }, [stableAttachments, value]);
370
529
  const { createErrorNotice } = useDispatch(noticesStore);
371
- const [replacementId, setReplacementId] = useState();
530
+ const { receiveEntityRecords } = useDispatch(coreStore);
531
+ const [targetItemId, setTargetItemId] = useState();
532
+ const openModalRef = useRef(void 0);
533
+ const [pendingOpen, setPendingOpen] = useState(false);
372
534
  const [blobs, setBlobs] = useState([]);
535
+ useEffect(() => {
536
+ if (pendingOpen) {
537
+ setPendingOpen(false);
538
+ openModalRef.current?.();
539
+ }
540
+ }, [pendingOpen]);
373
541
  const onChangeControl = useCallback(
374
542
  (newValue) => onChange(field.setValue({ item: data, value: newValue })),
375
543
  [data, field, onChange]
376
544
  );
377
545
  const removeItem = useCallback(
378
546
  (itemId) => {
379
- const currentIds = Array.isArray(value) ? value : [value];
547
+ const currentIds = normalizeValue(value);
380
548
  const newIds = currentIds.filter((id) => id !== itemId);
381
549
  setIsTouched(true);
382
550
  onChangeControl(newIds.length ? newIds : void 0);
383
551
  },
384
552
  [value, onChangeControl]
385
553
  );
554
+ const moveItem = useCallback(
555
+ (itemId, direction) => {
556
+ if (!orderedAttachments) {
557
+ return;
558
+ }
559
+ const currentIds = orderedAttachments.map((a) => a.id);
560
+ const index = currentIds.indexOf(itemId);
561
+ const newIndex = direction === "up" ? index - 1 : index + 1;
562
+ [currentIds[index], currentIds[newIndex]] = [
563
+ currentIds[newIndex],
564
+ currentIds[index]
565
+ ];
566
+ onChangeControl(currentIds);
567
+ },
568
+ [orderedAttachments, onChangeControl]
569
+ );
386
570
  const onFilesDrop = useCallback(
387
- (files, _replacementId) => {
571
+ (files, _targetItemId) => {
572
+ setTargetItemId(_targetItemId);
388
573
  uploadMedia({
389
574
  allowedTypes: allowedTypes?.length ? allowedTypes : void 0,
390
575
  filesList: files,
391
576
  onFileChange(uploadedMedia) {
392
- setReplacementId(_replacementId);
393
- const { blobItems, uploadedItems } = uploadedMedia.reduce(
394
- (accumulator, item) => {
395
- if (isBlobURL(item.url)) {
396
- accumulator.blobItems.push(item.url);
397
- } else {
398
- accumulator.uploadedItems.push(item.id);
399
- }
400
- return accumulator;
401
- },
402
- {
403
- blobItems: [],
404
- uploadedItems: []
405
- }
406
- );
407
- setBlobs(blobItems);
408
- if (uploadedItems.length === uploadedMedia.length) {
409
- setReplacementId(void 0);
410
- }
411
- if (!uploadedItems.length) {
577
+ const blobUrls = uploadedMedia.filter((item) => isBlobURL(item.url)).map((item) => item.url);
578
+ setBlobs(blobUrls);
579
+ if (!!blobUrls.length) {
412
580
  return;
413
581
  }
582
+ receiveEntityRecords(
583
+ "postType",
584
+ "attachment",
585
+ [],
586
+ void 0,
587
+ true
588
+ );
589
+ const uploadedIds = uploadedMedia.map(
590
+ (item) => item.id
591
+ );
414
592
  if (!multiple) {
415
- onChangeControl(uploadedItems[0]);
593
+ onChangeControl(uploadedIds[0]);
594
+ setTargetItemId(void 0);
416
595
  return;
417
596
  }
418
- if (!value) {
419
- onChangeControl(uploadedItems);
420
- return;
597
+ const currentValue = normalizeValue(value);
598
+ if (_targetItemId === void 0) {
599
+ onChangeControl([...currentValue, ...uploadedIds]);
600
+ } else {
601
+ const newValue = [...currentValue];
602
+ newValue.splice(
603
+ currentValue.indexOf(_targetItemId),
604
+ 1,
605
+ ...uploadedIds
606
+ );
607
+ onChangeControl(newValue);
421
608
  }
422
- const normalizedValue = Array.isArray(value) ? value : [value];
423
- const newIds = [
424
- ..._replacementId ? normalizedValue.filter(
425
- (id) => id !== _replacementId
426
- ) : normalizedValue,
427
- ...uploadedItems
428
- ];
429
- onChangeControl(newIds);
609
+ setTargetItemId(void 0);
430
610
  },
431
611
  onError(error) {
432
- setReplacementId(void 0);
612
+ setTargetItemId(void 0);
433
613
  setBlobs([]);
434
614
  createErrorNotice(error.message, { type: "snackbar" });
435
615
  },
436
616
  multiple: !!multiple
437
617
  });
438
618
  },
439
- [allowedTypes, value, multiple, createErrorNotice, onChangeControl]
619
+ [
620
+ allowedTypes,
621
+ value,
622
+ multiple,
623
+ createErrorNotice,
624
+ onChangeControl,
625
+ receiveEntityRecords
626
+ ]
440
627
  );
441
628
  const addButtonLabel = field.placeholder || (multiple ? __("Choose files") : __("Choose file"));
442
629
  const allItems = useMemo(() => {
443
630
  if (!blobs.length) {
444
- return attachments;
631
+ return orderedAttachments;
445
632
  }
446
633
  const items = [
447
- ...attachments || []
634
+ ...orderedAttachments || []
448
635
  ];
449
636
  const blobItems = blobs.map((url) => ({
450
637
  id: url,
451
638
  source_url: url,
452
639
  mime_type: getBlobTypeByURL(url)
453
640
  }));
454
- const replacementIndex = items.findIndex(
455
- (a) => a.id === replacementId
456
- );
457
- if (replacementIndex !== -1) {
458
- return [
459
- ...items.slice(0, replacementIndex),
460
- ...blobItems,
461
- ...items.slice(replacementIndex + 1)
462
- ];
641
+ if (targetItemId !== void 0) {
642
+ const targetIndex = items.findIndex(
643
+ (a) => a.id === targetItemId
644
+ );
645
+ items.splice(targetIndex, 1, ...blobItems);
646
+ } else {
647
+ items.push(...blobItems);
463
648
  }
464
- items.push(...blobItems);
465
649
  return items;
466
- }, [attachments, replacementId, blobs]);
650
+ }, [orderedAttachments, targetItemId, blobs]);
467
651
  useEffect(() => {
468
652
  if (!isTouched) {
469
653
  return;
@@ -503,21 +687,55 @@ function MediaEdit({
503
687
  ConditionalMediaUpload,
504
688
  {
505
689
  onSelect: (selectedMedia) => {
506
- if (multiple) {
507
- const newIds = Array.isArray(selectedMedia) ? selectedMedia.map((m) => m.id) : [selectedMedia.id];
508
- onChangeControl(newIds);
509
- } else {
690
+ if (!multiple) {
510
691
  onChangeControl(selectedMedia.id);
692
+ setTargetItemId(void 0);
693
+ return;
694
+ }
695
+ const newIds = Array.isArray(selectedMedia) ? selectedMedia.map((m) => m.id) : [selectedMedia.id];
696
+ const currentValue = normalizeValue(value);
697
+ if (!currentValue.length) {
698
+ onChangeControl(newIds);
699
+ } else if (targetItemId === void 0) {
700
+ const existingItems = currentValue.filter(
701
+ (id) => newIds.includes(id)
702
+ );
703
+ const newItems = newIds.filter(
704
+ (id) => !currentValue.includes(id)
705
+ );
706
+ onChangeControl([
707
+ ...existingItems,
708
+ ...newItems
709
+ ]);
710
+ } else if (selectedMedia.id !== targetItemId) {
711
+ const filtered = currentValue.filter(
712
+ (id) => id !== selectedMedia.id
713
+ );
714
+ onChangeControl(
715
+ filtered.map(
716
+ (id) => id === targetItemId ? selectedMedia.id : id
717
+ )
718
+ );
511
719
  }
720
+ setTargetItemId(void 0);
512
721
  },
722
+ onClose: () => setTargetItemId(void 0),
513
723
  allowedTypes,
514
- value,
515
- multiple,
724
+ value: targetItemId !== void 0 ? targetItemId : value,
725
+ multiple: multiple && targetItemId === void 0,
516
726
  title: field.label,
517
727
  render: ({ open }) => {
728
+ openModalRef.current = open;
518
729
  const AttachmentsComponent = isExpanded ? ExpandedMediaEditAttachments : CompactMediaEditAttachments;
519
730
  return /* @__PURE__ */ jsxs(VStack, { spacing: 2, children: [
520
- field.label && (hideLabelFromVision ? /* @__PURE__ */ jsx(VisuallyHidden, { as: "legend", children: field.label }) : /* @__PURE__ */ jsx(BaseControl.VisualLabel, { as: "legend", children: field.label })),
731
+ field.label && (hideLabelFromVision ? /* @__PURE__ */ jsx(VisuallyHidden, { as: "legend", children: field.label }) : /* @__PURE__ */ jsx(
732
+ BaseControl.VisualLabel,
733
+ {
734
+ as: "legend",
735
+ style: { marginBottom: 0 },
736
+ children: field.label
737
+ }
738
+ )),
521
739
  /* @__PURE__ */ jsx(
522
740
  AttachmentsComponent,
523
741
  {
@@ -525,9 +743,11 @@ function MediaEdit({
525
743
  addButtonLabel,
526
744
  multiple,
527
745
  removeItem,
528
- open,
746
+ moveItem,
747
+ open: () => setPendingOpen(true),
529
748
  onFilesDrop,
530
- isUploading: !!blobs.length
749
+ isUploading: !!blobs.length,
750
+ setTargetItemId
531
751
  }
532
752
  ),
533
753
  field.description && /* @__PURE__ */ jsx(Text, { variant: "muted", children: field.description })