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