@wordpress/media-utils 5.44.0 → 5.45.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.
- package/CHANGELOG.md +2 -0
- package/README.md +4 -0
- package/build/components/media-upload-modal/index.cjs +20 -2
- package/build/components/media-upload-modal/index.cjs.map +2 -2
- package/build/index.cjs.map +1 -1
- package/build/utils/sideload-media.cjs +3 -3
- package/build/utils/sideload-media.cjs.map +2 -2
- package/build/utils/sideload-to-server.cjs +6 -9
- package/build/utils/sideload-to-server.cjs.map +2 -2
- package/build/utils/types.cjs.map +1 -1
- package/build/utils/upload-media.cjs.map +2 -2
- package/build-module/components/media-upload-modal/index.mjs +20 -2
- package/build-module/components/media-upload-modal/index.mjs.map +2 -2
- package/build-module/index.mjs.map +1 -1
- package/build-module/utils/sideload-media.mjs +3 -3
- package/build-module/utils/sideload-media.mjs.map +2 -2
- package/build-module/utils/sideload-to-server.mjs +6 -9
- package/build-module/utils/sideload-to-server.mjs.map +2 -2
- package/build-module/utils/upload-media.mjs.map +2 -2
- package/build-types/components/media-upload-modal/index.d.ts.map +1 -1
- package/build-types/index.d.ts +1 -1
- package/build-types/index.d.ts.map +1 -1
- package/build-types/utils/sideload-media.d.ts +8 -4
- package/build-types/utils/sideload-media.d.ts.map +1 -1
- package/build-types/utils/sideload-to-server.d.ts +7 -3
- package/build-types/utils/sideload-to-server.d.ts.map +1 -1
- package/build-types/utils/types.d.ts +17 -0
- package/build-types/utils/types.d.ts.map +1 -1
- package/build-types/utils/upload-media.d.ts +1 -0
- package/build-types/utils/upload-media.d.ts.map +1 -1
- package/package.json +17 -17
- package/src/components/media-upload-modal/index.tsx +28 -5
- package/src/index.ts +1 -1
- package/src/utils/sideload-media.ts +12 -7
- package/src/utils/sideload-to-server.ts +13 -12
- package/src/utils/test/sideload-media.ts +14 -4
- package/src/utils/types.ts +18 -0
- package/src/utils/upload-media.ts +1 -0
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -33,6 +33,10 @@ Private @wordpress/media-utils APIs.
|
|
|
33
33
|
|
|
34
34
|
Undocumented declaration.
|
|
35
35
|
|
|
36
|
+
### SubSizeData
|
|
37
|
+
|
|
38
|
+
Undocumented declaration.
|
|
39
|
+
|
|
36
40
|
### transformAttachment
|
|
37
41
|
|
|
38
42
|
Transforms an attachment object from the REST API shape into the shape expected by the block editor and other consumers.
|
|
@@ -145,8 +145,26 @@ function MediaUploadModal({
|
|
|
145
145
|
filters.mime_type = filter.value;
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
|
-
if (!filters.media_type) {
|
|
149
|
-
|
|
148
|
+
if (!filters.media_type && !filters.mime_type && allowedTypes && !allowedTypes.includes("*")) {
|
|
149
|
+
const { mediaTypes, mimeTypes } = allowedTypes.reduce(
|
|
150
|
+
(acc, type) => {
|
|
151
|
+
if (type.endsWith("/*")) {
|
|
152
|
+
acc.mediaTypes.push(type.replace("/*", ""));
|
|
153
|
+
} else if (type.includes("/")) {
|
|
154
|
+
acc.mimeTypes.push(type);
|
|
155
|
+
} else {
|
|
156
|
+
acc.mediaTypes.push(type);
|
|
157
|
+
}
|
|
158
|
+
return acc;
|
|
159
|
+
},
|
|
160
|
+
{ mediaTypes: [], mimeTypes: [] }
|
|
161
|
+
);
|
|
162
|
+
if (mediaTypes.length) {
|
|
163
|
+
filters.media_type = mediaTypes;
|
|
164
|
+
}
|
|
165
|
+
if (mimeTypes.length) {
|
|
166
|
+
filters.mime_type = mimeTypes;
|
|
167
|
+
}
|
|
150
168
|
}
|
|
151
169
|
return {
|
|
152
170
|
per_page: view.perPage || 20,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/media-upload-modal/index.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tcreatePortal,\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tuseEffect,\n} from '@wordpress/element';\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect, useDispatch } from '@wordpress/data';\nimport { Modal, DropZone, FormFileUpload, Button } from '@wordpress/components';\nimport { upload as uploadIcon } from '@wordpress/icons';\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type {\n\tField,\n\tActionButton,\n\tSupportedLayouts,\n\tView,\n} from '@wordpress/dataviews';\nimport { useView } from '@wordpress/views';\nimport { Stack } from '@wordpress/ui';\nimport {\n\taltTextField,\n\tattachedToField,\n\tauthorField,\n\tcaptionField,\n\tdateAddedField,\n\tdateModifiedField,\n\tdescriptionField,\n\tfilenameField,\n\tfilesizeField,\n\tmediaDimensionsField,\n\tmediaThumbnailField,\n\tmimeTypeField,\n} from '@wordpress/media-fields';\nimport { store as noticesStore, SnackbarNotices } from '@wordpress/notices';\n\n/**\n * Internal dependencies\n */\nimport type { Attachment, RestAttachment } from '../../utils/types';\nimport { transformAttachment } from '../../utils/transform-attachment';\nimport { uploadMedia } from '../../utils/upload-media';\nimport { unlock } from '../../lock-unlock';\nimport { UploadStatusPopover } from './upload-status-popover';\nimport { useInvalidateAttachmentResolutions } from './use-invalidate-attachment-resolutions';\nimport { useUploadStatus } from './use-upload-status';\n\nconst { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );\n\n// Layout constants - matching the picker layout types\nconst LAYOUT_PICKER_GRID = 'pickerGrid';\nconst LAYOUT_PICKER_TABLE = 'pickerTable';\n\n// Custom notices context for the media modal\nconst NOTICES_CONTEXT = 'media-modal';\n\n// Notice ID - reused for all upload-related notices to prevent flooding\nconst NOTICE_ID_UPLOAD_PROGRESS = 'media-modal-upload-progress';\n\nconst defaultView: View = {\n\ttype: LAYOUT_PICKER_GRID,\n\tfields: [],\n\tshowTitle: false,\n\ttitleField: 'title',\n\tmediaField: 'media_thumbnail',\n\tsearch: '',\n\tpage: 1,\n\tperPage: 50,\n\tfilters: [],\n\tlayout: {\n\t\tpreviewSize: 170,\n\t\tdensity: 'compact',\n\t},\n};\n\nconst defaultLayouts: SupportedLayouts = {\n\t[ LAYOUT_PICKER_GRID ]: {\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\tlayout: {\n\t\t\tpreviewSize: 170,\n\t\t\tdensity: 'compact',\n\t\t},\n\t},\n\t[ LAYOUT_PICKER_TABLE ]: {\n\t\tfields: [\n\t\t\t'filename',\n\t\t\t'filesize',\n\t\t\t'media_dimensions',\n\t\t\t'author',\n\t\t\t'date',\n\t\t],\n\t\tshowTitle: true,\n\t},\n};\n\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t */\n\tallowedTypes?: string[];\n\n\t/**\n\t * Whether multiple files can be selected.\n\t * @default false\n\t */\n\tmultiple?: boolean;\n\n\t/**\n\t * The currently selected media item(s).\n\t * Can be a single ID number or array of IDs for multiple selection.\n\t */\n\tvalue?: number | number[];\n\n\t/**\n\t * Function called when media is selected.\n\t * Receives single attachment object or array of attachments.\n\t */\n\tonSelect: ( media: Attachment | Attachment[] ) => void;\n\n\t/**\n\t * Function called when the modal is closed without selection.\n\t */\n\tonClose?: () => void;\n\n\t/**\n\t * Function to handle media uploads.\n\t * If not provided, drag and drop will be disabled.\n\t */\n\tonUpload?: ( args: {\n\t\tallowedTypes?: string[];\n\t\tfilesList: File[];\n\t\tonFileChange?: ( attachments: Partial< Attachment >[] ) => void;\n\t\tonError?: ( error: Error ) => void;\n\t\tmultiple?: boolean;\n\t} ) => void;\n\n\t/**\n\t * Title for the modal.\n\t * @default 'Select Media'\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Whether the modal is open.\n\t */\n\tisOpen: boolean;\n\n\t/**\n\t * Whether the modal can be closed by clicking outside or pressing escape.\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\n\t/**\n\t * Additional CSS class for the modal.\n\t */\n\tmodalClass?: string;\n\n\t/**\n\t * Whether to show a search input.\n\t * @default true\n\t */\n\tsearch?: boolean;\n\n\t/**\n\t * Label for the search input.\n\t */\n\tsearchLabel?: string;\n}\n\n/**\n * MediaUploadModal component that uses Modal and DataViewsPicker for media selection.\n *\n * This is a modern functional component alternative to the legacy MediaUpload class component.\n * It provides a cleaner API and better integration with the WordPress block editor.\n *\n * @param props Component props\n * @param props.allowedTypes Array of allowed media types\n * @param props.multiple Whether multiple files can be selected\n * @param props.value Currently selected media item(s)\n * @param props.onSelect Function called when media is selected\n * @param props.onClose Function called when modal is closed\n * @param props.onUpload Function to handle media uploads\n * @param props.title Title for the modal\n * @param props.isOpen Whether the modal is open\n * @param props.isDismissible Whether modal can be dismissed\n * @param props.modalClass Additional CSS class for modal\n * @param props.search Whether to show search input\n * @param props.searchLabel Label for search input\n * @return JSX element or null\n */\nexport function MediaUploadModal( {\n\tallowedTypes,\n\tmultiple = false,\n\tvalue,\n\tonSelect,\n\tonClose,\n\tonUpload,\n\ttitle = __( 'Select Media' ),\n\tisOpen,\n\tisDismissible = true,\n\tmodalClass,\n\tsearch = true,\n\tsearchLabel = __( 'Search media' ),\n}: MediaUploadModalProps ) {\n\tconst [ selection, setSelection ] = useState< string[] >( () => {\n\t\tif ( ! value ) {\n\t\t\treturn [];\n\t\t}\n\t\treturn Array.isArray( value )\n\t\t\t? value.map( String )\n\t\t\t: [ String( value ) ];\n\t} );\n\n\tconst { createSuccessNotice, removeAllNotices } =\n\t\tuseDispatch( noticesStore );\n\tconst invalidateAttachmentResolutions =\n\t\tuseInvalidateAttachmentResolutions();\n\n\t// Persist view configuration across sessions via the preferences store.\n\tconst { view, updateView, isModified, resetToDefault } = useView( {\n\t\tkind: 'postType',\n\t\tname: 'attachment',\n\t\tslug: 'media-modal',\n\t\tdefaultView,\n\t} );\n\n\t// Build query args based on view properties, similar to PostList\n\tconst queryArgs = useMemo( () => {\n\t\tconst filters: Record< string, any > = {};\n\n\t\tview.filters?.forEach( ( filter ) => {\n\t\t\t// Handle media type filters\n\t\t\tif ( filter.field === 'media_type' ) {\n\t\t\t\tfilters.media_type = filter.value;\n\t\t\t}\n\t\t\t// Handle author filters\n\t\t\tif ( filter.field === 'author' ) {\n\t\t\t\tif ( filter.operator === 'isAny' ) {\n\t\t\t\t\tfilters.author = filter.value;\n\t\t\t\t} else if ( filter.operator === 'isNone' ) {\n\t\t\t\t\tfilters.author_exclude = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle date filters\n\t\t\tif ( filter.field === 'date' || filter.field === 'modified' ) {\n\t\t\t\tif ( filter.operator === 'before' ) {\n\t\t\t\t\tfilters.before = filter.value;\n\t\t\t\t} else if ( filter.operator === 'after' ) {\n\t\t\t\t\tfilters.after = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle mime type filters\n\t\t\tif ( filter.field === 'mime_type' ) {\n\t\t\t\tfilters.mime_type = filter.value;\n\t\t\t}\n\t\t} );\n\n\t\t// Base media type on allowedTypes if no filter is set\n\t\tif ( ! filters.media_type ) {\n\t\t\tfilters.media_type = allowedTypes?.includes( '*' )\n\t\t\t\t? undefined\n\t\t\t\t: allowedTypes;\n\t\t}\n\n\t\treturn {\n\t\t\tper_page: view.perPage || 20,\n\t\t\tpage: view.page || 1,\n\t\t\tstatus: 'inherit',\n\t\t\torder: view.sort?.direction,\n\t\t\torderby: view.sort?.field,\n\t\t\tsearch: view.search,\n\t\t\t_embed: 'author,wp:attached-to',\n\t\t\t...filters,\n\t\t};\n\t}, [ view, allowedTypes ] );\n\n\t// Per-batch completion handler: auto-select uploaded items and refresh the grid.\n\tconst handleBatchComplete = useCallback(\n\t\t( attachments: Partial< Attachment >[] ) => {\n\t\t\tconst uploadedIds = attachments\n\t\t\t\t.map( ( attachment ) => String( attachment.id ) )\n\t\t\t\t.filter( Boolean );\n\n\t\t\tif ( multiple ) {\n\t\t\t\tsetSelection( ( prev ) => {\n\t\t\t\t\tconst existing = new Set( prev );\n\t\t\t\t\tconst newIds = uploadedIds.filter(\n\t\t\t\t\t\t( id ) => ! existing.has( id )\n\t\t\t\t\t);\n\t\t\t\t\treturn [ ...prev, ...newIds ];\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tsetSelection( uploadedIds.slice( 0, 1 ) );\n\t\t\t}\n\n\t\t\t// Invalidate all cached attachment queries so every page of\n\t\t\t// results refreshes \u2014 not just the page the user is viewing.\n\t\t\tinvalidateAttachmentResolutions();\n\t\t},\n\t\t[ multiple, invalidateAttachmentResolutions ]\n\t);\n\n\tconst {\n\t\tuploadingFiles,\n\t\tregisterBatch,\n\t\tdismissError,\n\t\tclearCompleted,\n\t\tallComplete,\n\t} = useUploadStatus( { onBatchComplete: handleBatchComplete } );\n\n\tconst isPopoverOpenRef = useRef( false );\n\tconst handlePopoverOpenChange = useCallback(\n\t\t( open: boolean ) => {\n\t\t\tisPopoverOpenRef.current = open;\n\t\t\tif ( ! open ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t},\n\t\t[ clearCompleted ]\n\t);\n\n\t// Fetch all media attachments using WordPress core data with permissions\n\tconst {\n\t\trecords: mediaRecords,\n\t\tisResolving: isLoading,\n\t\ttotalItems,\n\t\ttotalPages,\n\t} = useEntityRecordsWithPermissions( 'postType', 'attachment', queryArgs );\n\n\tconst fields: Field< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t// Media field definitions from @wordpress/media-fields\n\t\t\t// Cast is safe because RestAttachment has the same properties as Attachment\n\t\t\t{\n\t\t\t\t...( mediaThumbnailField as Field< RestAttachment > ),\n\t\t\t\tenableHiding: false, // Within the modal, the thumbnail should always be shown.\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'title',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Title' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) => {\n\t\t\t\t\tconst titleValue = item.title.raw || item.title.rendered;\n\t\t\t\t\treturn titleValue || __( '(no title)' );\n\t\t\t\t},\n\t\t\t},\n\t\t\taltTextField as Field< RestAttachment >,\n\t\t\tcaptionField as Field< RestAttachment >,\n\t\t\tdescriptionField as Field< RestAttachment >,\n\t\t\tdateAddedField as Field< RestAttachment >,\n\t\t\tdateModifiedField as Field< RestAttachment >,\n\t\t\tauthorField as Field< RestAttachment >,\n\t\t\tfilenameField as Field< RestAttachment >,\n\t\t\tfilesizeField as Field< RestAttachment >,\n\t\t\tmediaDimensionsField as Field< RestAttachment >,\n\t\t\tmimeTypeField as Field< RestAttachment >,\n\t\t\tattachedToField as Field< RestAttachment >,\n\t\t],\n\t\t[]\n\t);\n\n\tconst actions: ActionButton< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: __( 'Select' ),\n\t\t\t\tisPrimary: true,\n\t\t\t\tsupportsBulk: multiple,\n\t\t\t\tasync callback() {\n\t\t\t\t\tif ( selection.length === 0 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst selectedPostsQuery = {\n\t\t\t\t\t\tinclude: selection,\n\t\t\t\t\t\tper_page: -1,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst selectedPosts = await resolveSelect(\n\t\t\t\t\t\tcoreStore\n\t\t\t\t\t).getEntityRecords< RestAttachment >(\n\t\t\t\t\t\t'postType',\n\t\t\t\t\t\t'attachment',\n\t\t\t\t\t\tselectedPostsQuery\n\t\t\t\t\t);\n\n\t\t\t\t\t// Transform the selected posts to the expected Attachment format\n\t\t\t\t\tconst transformedPosts = ( selectedPosts ?? [] )\n\t\t\t\t\t\t.map( transformAttachment )\n\t\t\t\t\t\t.filter( Boolean );\n\n\t\t\t\t\tconst selectedItems = multiple\n\t\t\t\t\t\t? transformedPosts\n\t\t\t\t\t\t: transformedPosts?.[ 0 ];\n\n\t\t\t\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\t\t\t\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection, removeAllNotices ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\tonClose?.();\n\t}, [ removeAllNotices, onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\t// Show success notice and auto-clear completed entries when all batches finish.\n\tconst prevAllCompleteRef = useRef( false );\n\tuseEffect( () => {\n\t\tif ( allComplete && ! prevAllCompleteRef.current ) {\n\t\t\tconst completeCount = uploadingFiles.filter(\n\t\t\t\t( file ) => file.status === 'uploaded'\n\t\t\t).length;\n\t\t\tif ( completeCount > 0 ) {\n\t\t\t\tcreateSuccessNotice(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t// translators: %s: number of files\n\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t'Uploaded %s file',\n\t\t\t\t\t\t\t'Uploaded %s files',\n\t\t\t\t\t\t\tcompleteCount\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcompleteCount.toLocaleString()\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Auto-clear completed entries, unless the popover is\n\t\t\t// open \u2014 in that case, they'll be cleared on close.\n\t\t\tif ( ! isPopoverOpenRef.current ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t}\n\t\tprevAllCompleteRef.current = allComplete;\n\t}, [ allComplete, uploadingFiles, createSuccessNotice, clearCompleted ] );\n\n\tconst handleFileSelect = useCallback(\n\t\t( event: React.ChangeEvent< HTMLInputElement > ) => {\n\t\t\tconst files = event.target.files;\n\t\t\tif ( files && files.length > 0 ) {\n\t\t\t\tconst filesArray = Array.from( files );\n\t\t\t\tconst { onFileChange, onError } = registerBatch( filesArray );\n\n\t\t\t\thandleUpload( {\n\t\t\t\t\tallowedTypes,\n\t\t\t\t\tfilesList: filesArray,\n\t\t\t\t\tonFileChange,\n\t\t\t\t\tonError,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ allowedTypes, handleUpload, registerBatch ]\n\t);\n\n\tconst paginationInfo = useMemo(\n\t\t() => ( {\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t} ),\n\t\t[ totalItems, totalPages ]\n\t);\n\n\t// Build accept attribute from allowedTypes\n\tconst acceptTypes = useMemo( () => {\n\t\tif ( allowedTypes?.includes( '*' ) ) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn allowedTypes?.join( ',' );\n\t}, [ allowedTypes ] );\n\n\tif ( ! isOpen ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ title }\n\t\t\tonRequestClose={ handleModalClose }\n\t\t\tisDismissible={ isDismissible }\n\t\t\tclassName={ modalClass }\n\t\t\toverlayClassName=\"media-upload-modal\"\n\t\t\tsize=\"fill\"\n\t\t\theaderActions={\n\t\t\t\t<FormFileUpload\n\t\t\t\t\taccept={ acceptTypes }\n\t\t\t\t\tmultiple\n\t\t\t\t\tonChange={ handleFileSelect }\n\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\trender={ ( { openFileDialog } ) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tonClick={ openFileDialog }\n\t\t\t\t\t\t\ticon={ uploadIcon }\n\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Upload media' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) }\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t<DropZone\n\t\t\t\tonFilesDrop={ ( files ) => {\n\t\t\t\t\tlet filteredFiles = files;\n\t\t\t\t\t// Filter files by allowed types if specified\n\t\t\t\t\tif ( allowedTypes && ! allowedTypes.includes( '*' ) ) {\n\t\t\t\t\t\tfilteredFiles = files.filter( ( file ) =>\n\t\t\t\t\t\t\tallowedTypes.some( ( allowedType ) => {\n\t\t\t\t\t\t\t\t// Check if the file type matches the allowed MIME type\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tfile.type === allowedType ||\n\t\t\t\t\t\t\t\t\tfile.type.startsWith(\n\t\t\t\t\t\t\t\t\t\tallowedType.replace( '*', '' )\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( filteredFiles.length > 0 ) {\n\t\t\t\t\t\tconst { onFileChange, onError } =\n\t\t\t\t\t\t\tregisterBatch( filteredFiles );\n\n\t\t\t\t\t\thandleUpload( {\n\t\t\t\t\t\t\tallowedTypes,\n\t\t\t\t\t\t\tfilesList: filteredFiles,\n\t\t\t\t\t\t\tonFileChange,\n\t\t\t\t\t\t\tonError,\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tlabel={ __( 'Drop files to upload' ) }\n\t\t\t/>\n\t\t\t<DataViewsPicker\n\t\t\t\tdata={ mediaRecords || [] }\n\t\t\t\tfields={ fields }\n\t\t\t\tview={ view }\n\t\t\t\tonChangeView={ updateView }\n\t\t\t\tactions={ actions }\n\t\t\t\tselection={ selection }\n\t\t\t\tonChangeSelection={ setSelection }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tpaginationInfo={ paginationInfo }\n\t\t\t\tdefaultLayouts={ defaultLayouts }\n\t\t\t\tgetItemId={ ( item: RestAttachment ) => String( item.id ) }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t\tonReset={ isModified ? resetToDefault : false }\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talign=\"top\"\n\t\t\t\t\tjustify=\"space-between\"\n\t\t\t\t\tclassName=\"dataviews__view-actions\"\n\t\t\t\t\tgap=\"xs\"\n\t\t\t\t>\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\tgap=\"sm\"\n\t\t\t\t\t\tjustify=\"start\"\n\t\t\t\t\t\tclassName=\"dataviews__search\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{ search && (\n\t\t\t\t\t\t\t<DataViewsPicker.Search label={ searchLabel } />\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<DataViewsPicker.FiltersToggle />\n\t\t\t\t\t</Stack>\n\t\t\t\t\t<Stack direction=\"row\" gap=\"xs\" style={ { flexShrink: 0 } }>\n\t\t\t\t\t\t<DataViewsPicker.LayoutSwitcher />\n\t\t\t\t\t\t<DataViewsPicker.ViewConfig />\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t\t<DataViewsPicker.FiltersToggled className=\"dataviews-filters__container\" />\n\t\t\t\t<DataViewsPicker.Layout />\n\t\t\t\t<div\n\t\t\t\t\tclassName={ clsx( 'media-upload-modal__footer', {\n\t\t\t\t\t\t'is-uploading': uploadingFiles.length > 0,\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t<UploadStatusPopover\n\t\t\t\t\t\tuploadingFiles={ uploadingFiles }\n\t\t\t\t\t\tonDismissError={ dismissError }\n\t\t\t\t\t\tonOpenChange={ handlePopoverOpenChange }\n\t\t\t\t\t/>\n\t\t\t\t\t<DataViewsPicker.BulkActionToolbar />\n\t\t\t\t</div>\n\t\t\t</DataViewsPicker>\n\t\t\t{ createPortal(\n\t\t\t\t<SnackbarNotices\n\t\t\t\t\tclassName=\"media-upload-modal__snackbar\"\n\t\t\t\t\tcontext={ NOTICES_CONTEXT }\n\t\t\t\t/>,\n\t\t\t\tdocument.body\n\t\t\t) }\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAAiB;AAKjB,qBAOO;AACP,kBAAgC;AAChC,uBAGO;AACP,kBAA2C;AAC3C,wBAAwD;AACxD,mBAAqC;AACrC,uBAAgC;AAOhC,mBAAwB;AACxB,gBAAsB;AACtB,0BAaO;AACP,qBAAuD;AAMvD,kCAAoC;AACpC,0BAA4B;AAC5B,yBAAuB;AACvB,mCAAoC;AACpC,mDAAmD;AACnD,+BAAgC;
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tcreatePortal,\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tuseEffect,\n} from '@wordpress/element';\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect, useDispatch } from '@wordpress/data';\nimport { Modal, DropZone, FormFileUpload, Button } from '@wordpress/components';\nimport { upload as uploadIcon } from '@wordpress/icons';\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type {\n\tField,\n\tActionButton,\n\tSupportedLayouts,\n\tView,\n} from '@wordpress/dataviews';\nimport { useView } from '@wordpress/views';\nimport { Stack } from '@wordpress/ui';\nimport {\n\taltTextField,\n\tattachedToField,\n\tauthorField,\n\tcaptionField,\n\tdateAddedField,\n\tdateModifiedField,\n\tdescriptionField,\n\tfilenameField,\n\tfilesizeField,\n\tmediaDimensionsField,\n\tmediaThumbnailField,\n\tmimeTypeField,\n} from '@wordpress/media-fields';\nimport { store as noticesStore, SnackbarNotices } from '@wordpress/notices';\n\n/**\n * Internal dependencies\n */\nimport type { Attachment, RestAttachment } from '../../utils/types';\nimport { transformAttachment } from '../../utils/transform-attachment';\nimport { uploadMedia } from '../../utils/upload-media';\nimport { unlock } from '../../lock-unlock';\nimport { UploadStatusPopover } from './upload-status-popover';\nimport { useInvalidateAttachmentResolutions } from './use-invalidate-attachment-resolutions';\nimport { useUploadStatus } from './use-upload-status';\n\nconst { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );\n\n// Layout constants - matching the picker layout types\nconst LAYOUT_PICKER_GRID = 'pickerGrid';\nconst LAYOUT_PICKER_TABLE = 'pickerTable';\n\n// Custom notices context for the media modal\nconst NOTICES_CONTEXT = 'media-modal';\n\n// Notice ID - reused for all upload-related notices to prevent flooding\nconst NOTICE_ID_UPLOAD_PROGRESS = 'media-modal-upload-progress';\n\nconst defaultView: View = {\n\ttype: LAYOUT_PICKER_GRID,\n\tfields: [],\n\tshowTitle: false,\n\ttitleField: 'title',\n\tmediaField: 'media_thumbnail',\n\tsearch: '',\n\tpage: 1,\n\tperPage: 50,\n\tfilters: [],\n\tlayout: {\n\t\tpreviewSize: 170,\n\t\tdensity: 'compact',\n\t},\n};\n\nconst defaultLayouts: SupportedLayouts = {\n\t[ LAYOUT_PICKER_GRID ]: {\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\tlayout: {\n\t\t\tpreviewSize: 170,\n\t\t\tdensity: 'compact',\n\t\t},\n\t},\n\t[ LAYOUT_PICKER_TABLE ]: {\n\t\tfields: [\n\t\t\t'filename',\n\t\t\t'filesize',\n\t\t\t'media_dimensions',\n\t\t\t'author',\n\t\t\t'date',\n\t\t],\n\t\tshowTitle: true,\n\t},\n};\n\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t */\n\tallowedTypes?: string[];\n\n\t/**\n\t * Whether multiple files can be selected.\n\t * @default false\n\t */\n\tmultiple?: boolean;\n\n\t/**\n\t * The currently selected media item(s).\n\t * Can be a single ID number or array of IDs for multiple selection.\n\t */\n\tvalue?: number | number[];\n\n\t/**\n\t * Function called when media is selected.\n\t * Receives single attachment object or array of attachments.\n\t */\n\tonSelect: ( media: Attachment | Attachment[] ) => void;\n\n\t/**\n\t * Function called when the modal is closed without selection.\n\t */\n\tonClose?: () => void;\n\n\t/**\n\t * Function to handle media uploads.\n\t * If not provided, drag and drop will be disabled.\n\t */\n\tonUpload?: ( args: {\n\t\tallowedTypes?: string[];\n\t\tfilesList: File[];\n\t\tonFileChange?: ( attachments: Partial< Attachment >[] ) => void;\n\t\tonError?: ( error: Error ) => void;\n\t\tmultiple?: boolean;\n\t} ) => void;\n\n\t/**\n\t * Title for the modal.\n\t * @default 'Select Media'\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Whether the modal is open.\n\t */\n\tisOpen: boolean;\n\n\t/**\n\t * Whether the modal can be closed by clicking outside or pressing escape.\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\n\t/**\n\t * Additional CSS class for the modal.\n\t */\n\tmodalClass?: string;\n\n\t/**\n\t * Whether to show a search input.\n\t * @default true\n\t */\n\tsearch?: boolean;\n\n\t/**\n\t * Label for the search input.\n\t */\n\tsearchLabel?: string;\n}\n\n/**\n * MediaUploadModal component that uses Modal and DataViewsPicker for media selection.\n *\n * This is a modern functional component alternative to the legacy MediaUpload class component.\n * It provides a cleaner API and better integration with the WordPress block editor.\n *\n * @param props Component props\n * @param props.allowedTypes Array of allowed media types\n * @param props.multiple Whether multiple files can be selected\n * @param props.value Currently selected media item(s)\n * @param props.onSelect Function called when media is selected\n * @param props.onClose Function called when modal is closed\n * @param props.onUpload Function to handle media uploads\n * @param props.title Title for the modal\n * @param props.isOpen Whether the modal is open\n * @param props.isDismissible Whether modal can be dismissed\n * @param props.modalClass Additional CSS class for modal\n * @param props.search Whether to show search input\n * @param props.searchLabel Label for search input\n * @return JSX element or null\n */\nexport function MediaUploadModal( {\n\tallowedTypes,\n\tmultiple = false,\n\tvalue,\n\tonSelect,\n\tonClose,\n\tonUpload,\n\ttitle = __( 'Select Media' ),\n\tisOpen,\n\tisDismissible = true,\n\tmodalClass,\n\tsearch = true,\n\tsearchLabel = __( 'Search media' ),\n}: MediaUploadModalProps ) {\n\tconst [ selection, setSelection ] = useState< string[] >( () => {\n\t\tif ( ! value ) {\n\t\t\treturn [];\n\t\t}\n\t\treturn Array.isArray( value )\n\t\t\t? value.map( String )\n\t\t\t: [ String( value ) ];\n\t} );\n\n\tconst { createSuccessNotice, removeAllNotices } =\n\t\tuseDispatch( noticesStore );\n\tconst invalidateAttachmentResolutions =\n\t\tuseInvalidateAttachmentResolutions();\n\n\t// Persist view configuration across sessions via the preferences store.\n\tconst { view, updateView, isModified, resetToDefault } = useView( {\n\t\tkind: 'postType',\n\t\tname: 'attachment',\n\t\tslug: 'media-modal',\n\t\tdefaultView,\n\t} );\n\n\t// Build query args based on view properties, similar to PostList\n\tconst queryArgs = useMemo( () => {\n\t\tconst filters: Record< string, any > = {};\n\n\t\tview.filters?.forEach( ( filter ) => {\n\t\t\t// Handle media type filters\n\t\t\tif ( filter.field === 'media_type' ) {\n\t\t\t\tfilters.media_type = filter.value;\n\t\t\t}\n\t\t\t// Handle author filters\n\t\t\tif ( filter.field === 'author' ) {\n\t\t\t\tif ( filter.operator === 'isAny' ) {\n\t\t\t\t\tfilters.author = filter.value;\n\t\t\t\t} else if ( filter.operator === 'isNone' ) {\n\t\t\t\t\tfilters.author_exclude = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle date filters\n\t\t\tif ( filter.field === 'date' || filter.field === 'modified' ) {\n\t\t\t\tif ( filter.operator === 'before' ) {\n\t\t\t\t\tfilters.before = filter.value;\n\t\t\t\t} else if ( filter.operator === 'after' ) {\n\t\t\t\t\tfilters.after = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle mime type filters\n\t\t\tif ( filter.field === 'mime_type' ) {\n\t\t\t\tfilters.mime_type = filter.value;\n\t\t\t}\n\t\t} );\n\n\t\t// Base media and mime type on allowedTypes if no filter is set\n\t\tif (\n\t\t\t! filters.media_type &&\n\t\t\t! filters.mime_type &&\n\t\t\tallowedTypes &&\n\t\t\t! allowedTypes.includes( '*' )\n\t\t) {\n\t\t\tconst { mediaTypes, mimeTypes } = allowedTypes.reduce(\n\t\t\t\t( acc, type ) => {\n\t\t\t\t\tif ( type.endsWith( '/*' ) ) {\n\t\t\t\t\t\tacc.mediaTypes.push( type.replace( '/*', '' ) );\n\t\t\t\t\t} else if ( type.includes( '/' ) ) {\n\t\t\t\t\t\tacc.mimeTypes.push( type );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tacc.mediaTypes.push( type );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{ mediaTypes: [] as string[], mimeTypes: [] as string[] }\n\t\t\t);\n\n\t\t\tif ( mediaTypes.length ) {\n\t\t\t\tfilters.media_type = mediaTypes;\n\t\t\t}\n\t\t\tif ( mimeTypes.length ) {\n\t\t\t\tfilters.mime_type = mimeTypes;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tper_page: view.perPage || 20,\n\t\t\tpage: view.page || 1,\n\t\t\tstatus: 'inherit',\n\t\t\torder: view.sort?.direction,\n\t\t\torderby: view.sort?.field,\n\t\t\tsearch: view.search,\n\t\t\t_embed: 'author,wp:attached-to',\n\t\t\t...filters,\n\t\t};\n\t}, [ view, allowedTypes ] );\n\n\t// Per-batch completion handler: auto-select uploaded items and refresh the grid.\n\tconst handleBatchComplete = useCallback(\n\t\t( attachments: Partial< Attachment >[] ) => {\n\t\t\tconst uploadedIds = attachments\n\t\t\t\t.map( ( attachment ) => String( attachment.id ) )\n\t\t\t\t.filter( Boolean );\n\n\t\t\tif ( multiple ) {\n\t\t\t\tsetSelection( ( prev ) => {\n\t\t\t\t\tconst existing = new Set( prev );\n\t\t\t\t\tconst newIds = uploadedIds.filter(\n\t\t\t\t\t\t( id ) => ! existing.has( id )\n\t\t\t\t\t);\n\t\t\t\t\treturn [ ...prev, ...newIds ];\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tsetSelection( uploadedIds.slice( 0, 1 ) );\n\t\t\t}\n\n\t\t\t// Invalidate all cached attachment queries so every page of\n\t\t\t// results refreshes \u2014 not just the page the user is viewing.\n\t\t\tinvalidateAttachmentResolutions();\n\t\t},\n\t\t[ multiple, invalidateAttachmentResolutions ]\n\t);\n\n\tconst {\n\t\tuploadingFiles,\n\t\tregisterBatch,\n\t\tdismissError,\n\t\tclearCompleted,\n\t\tallComplete,\n\t} = useUploadStatus( { onBatchComplete: handleBatchComplete } );\n\n\tconst isPopoverOpenRef = useRef( false );\n\tconst handlePopoverOpenChange = useCallback(\n\t\t( open: boolean ) => {\n\t\t\tisPopoverOpenRef.current = open;\n\t\t\tif ( ! open ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t},\n\t\t[ clearCompleted ]\n\t);\n\n\t// Fetch all media attachments using WordPress core data with permissions\n\tconst {\n\t\trecords: mediaRecords,\n\t\tisResolving: isLoading,\n\t\ttotalItems,\n\t\ttotalPages,\n\t} = useEntityRecordsWithPermissions( 'postType', 'attachment', queryArgs );\n\n\tconst fields: Field< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t// Media field definitions from @wordpress/media-fields\n\t\t\t// Cast is safe because RestAttachment has the same properties as Attachment\n\t\t\t{\n\t\t\t\t...( mediaThumbnailField as Field< RestAttachment > ),\n\t\t\t\tenableHiding: false, // Within the modal, the thumbnail should always be shown.\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'title',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Title' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) => {\n\t\t\t\t\tconst titleValue = item.title.raw || item.title.rendered;\n\t\t\t\t\treturn titleValue || __( '(no title)' );\n\t\t\t\t},\n\t\t\t},\n\t\t\taltTextField as Field< RestAttachment >,\n\t\t\tcaptionField as Field< RestAttachment >,\n\t\t\tdescriptionField as Field< RestAttachment >,\n\t\t\tdateAddedField as Field< RestAttachment >,\n\t\t\tdateModifiedField as Field< RestAttachment >,\n\t\t\tauthorField as Field< RestAttachment >,\n\t\t\tfilenameField as Field< RestAttachment >,\n\t\t\tfilesizeField as Field< RestAttachment >,\n\t\t\tmediaDimensionsField as Field< RestAttachment >,\n\t\t\tmimeTypeField as Field< RestAttachment >,\n\t\t\tattachedToField as Field< RestAttachment >,\n\t\t],\n\t\t[]\n\t);\n\n\tconst actions: ActionButton< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: __( 'Select' ),\n\t\t\t\tisPrimary: true,\n\t\t\t\tsupportsBulk: multiple,\n\t\t\t\tasync callback() {\n\t\t\t\t\tif ( selection.length === 0 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst selectedPostsQuery = {\n\t\t\t\t\t\tinclude: selection,\n\t\t\t\t\t\tper_page: -1,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst selectedPosts = await resolveSelect(\n\t\t\t\t\t\tcoreStore\n\t\t\t\t\t).getEntityRecords< RestAttachment >(\n\t\t\t\t\t\t'postType',\n\t\t\t\t\t\t'attachment',\n\t\t\t\t\t\tselectedPostsQuery\n\t\t\t\t\t);\n\n\t\t\t\t\t// Transform the selected posts to the expected Attachment format\n\t\t\t\t\tconst transformedPosts = ( selectedPosts ?? [] )\n\t\t\t\t\t\t.map( transformAttachment )\n\t\t\t\t\t\t.filter( Boolean );\n\n\t\t\t\t\tconst selectedItems = multiple\n\t\t\t\t\t\t? transformedPosts\n\t\t\t\t\t\t: transformedPosts?.[ 0 ];\n\n\t\t\t\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\t\t\t\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection, removeAllNotices ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\tonClose?.();\n\t}, [ removeAllNotices, onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\t// Show success notice and auto-clear completed entries when all batches finish.\n\tconst prevAllCompleteRef = useRef( false );\n\tuseEffect( () => {\n\t\tif ( allComplete && ! prevAllCompleteRef.current ) {\n\t\t\tconst completeCount = uploadingFiles.filter(\n\t\t\t\t( file ) => file.status === 'uploaded'\n\t\t\t).length;\n\t\t\tif ( completeCount > 0 ) {\n\t\t\t\tcreateSuccessNotice(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t// translators: %s: number of files\n\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t'Uploaded %s file',\n\t\t\t\t\t\t\t'Uploaded %s files',\n\t\t\t\t\t\t\tcompleteCount\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcompleteCount.toLocaleString()\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Auto-clear completed entries, unless the popover is\n\t\t\t// open \u2014 in that case, they'll be cleared on close.\n\t\t\tif ( ! isPopoverOpenRef.current ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t}\n\t\tprevAllCompleteRef.current = allComplete;\n\t}, [ allComplete, uploadingFiles, createSuccessNotice, clearCompleted ] );\n\n\tconst handleFileSelect = useCallback(\n\t\t( event: React.ChangeEvent< HTMLInputElement > ) => {\n\t\t\tconst files = event.target.files;\n\t\t\tif ( files && files.length > 0 ) {\n\t\t\t\tconst filesArray = Array.from( files );\n\t\t\t\tconst { onFileChange, onError } = registerBatch( filesArray );\n\n\t\t\t\thandleUpload( {\n\t\t\t\t\tallowedTypes,\n\t\t\t\t\tfilesList: filesArray,\n\t\t\t\t\tonFileChange,\n\t\t\t\t\tonError,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ allowedTypes, handleUpload, registerBatch ]\n\t);\n\n\tconst paginationInfo = useMemo(\n\t\t() => ( {\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t} ),\n\t\t[ totalItems, totalPages ]\n\t);\n\n\t// Build accept attribute from allowedTypes\n\tconst acceptTypes = useMemo( () => {\n\t\tif ( allowedTypes?.includes( '*' ) ) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn allowedTypes?.join( ',' );\n\t}, [ allowedTypes ] );\n\n\tif ( ! isOpen ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ title }\n\t\t\tonRequestClose={ handleModalClose }\n\t\t\tisDismissible={ isDismissible }\n\t\t\tclassName={ modalClass }\n\t\t\toverlayClassName=\"media-upload-modal\"\n\t\t\tsize=\"fill\"\n\t\t\theaderActions={\n\t\t\t\t<FormFileUpload\n\t\t\t\t\taccept={ acceptTypes }\n\t\t\t\t\tmultiple\n\t\t\t\t\tonChange={ handleFileSelect }\n\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\trender={ ( { openFileDialog } ) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tonClick={ openFileDialog }\n\t\t\t\t\t\t\ticon={ uploadIcon }\n\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Upload media' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) }\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t<DropZone\n\t\t\t\tonFilesDrop={ ( files ) => {\n\t\t\t\t\tlet filteredFiles = files;\n\t\t\t\t\t// Filter files by allowed types if specified\n\t\t\t\t\tif ( allowedTypes && ! allowedTypes.includes( '*' ) ) {\n\t\t\t\t\t\tfilteredFiles = files.filter( ( file ) =>\n\t\t\t\t\t\t\tallowedTypes.some( ( allowedType ) => {\n\t\t\t\t\t\t\t\t// Check if the file type matches the allowed MIME type\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tfile.type === allowedType ||\n\t\t\t\t\t\t\t\t\tfile.type.startsWith(\n\t\t\t\t\t\t\t\t\t\tallowedType.replace( '*', '' )\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( filteredFiles.length > 0 ) {\n\t\t\t\t\t\tconst { onFileChange, onError } =\n\t\t\t\t\t\t\tregisterBatch( filteredFiles );\n\n\t\t\t\t\t\thandleUpload( {\n\t\t\t\t\t\t\tallowedTypes,\n\t\t\t\t\t\t\tfilesList: filteredFiles,\n\t\t\t\t\t\t\tonFileChange,\n\t\t\t\t\t\t\tonError,\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tlabel={ __( 'Drop files to upload' ) }\n\t\t\t/>\n\t\t\t<DataViewsPicker\n\t\t\t\tdata={ mediaRecords || [] }\n\t\t\t\tfields={ fields }\n\t\t\t\tview={ view }\n\t\t\t\tonChangeView={ updateView }\n\t\t\t\tactions={ actions }\n\t\t\t\tselection={ selection }\n\t\t\t\tonChangeSelection={ setSelection }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tpaginationInfo={ paginationInfo }\n\t\t\t\tdefaultLayouts={ defaultLayouts }\n\t\t\t\tgetItemId={ ( item: RestAttachment ) => String( item.id ) }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t\tonReset={ isModified ? resetToDefault : false }\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talign=\"top\"\n\t\t\t\t\tjustify=\"space-between\"\n\t\t\t\t\tclassName=\"dataviews__view-actions\"\n\t\t\t\t\tgap=\"xs\"\n\t\t\t\t>\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\tgap=\"sm\"\n\t\t\t\t\t\tjustify=\"start\"\n\t\t\t\t\t\tclassName=\"dataviews__search\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{ search && (\n\t\t\t\t\t\t\t<DataViewsPicker.Search label={ searchLabel } />\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<DataViewsPicker.FiltersToggle />\n\t\t\t\t\t</Stack>\n\t\t\t\t\t<Stack direction=\"row\" gap=\"xs\" style={ { flexShrink: 0 } }>\n\t\t\t\t\t\t<DataViewsPicker.LayoutSwitcher />\n\t\t\t\t\t\t<DataViewsPicker.ViewConfig />\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t\t<DataViewsPicker.FiltersToggled className=\"dataviews-filters__container\" />\n\t\t\t\t<DataViewsPicker.Layout />\n\t\t\t\t<div\n\t\t\t\t\tclassName={ clsx( 'media-upload-modal__footer', {\n\t\t\t\t\t\t'is-uploading': uploadingFiles.length > 0,\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t<UploadStatusPopover\n\t\t\t\t\t\tuploadingFiles={ uploadingFiles }\n\t\t\t\t\t\tonDismissError={ dismissError }\n\t\t\t\t\t\tonOpenChange={ handlePopoverOpenChange }\n\t\t\t\t\t/>\n\t\t\t\t\t<DataViewsPicker.BulkActionToolbar />\n\t\t\t\t</div>\n\t\t\t</DataViewsPicker>\n\t\t\t{ createPortal(\n\t\t\t\t<SnackbarNotices\n\t\t\t\t\tclassName=\"media-upload-modal__snackbar\"\n\t\t\t\t\tcontext={ NOTICES_CONTEXT }\n\t\t\t\t/>,\n\t\t\t\tdocument.body\n\t\t\t) }\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["coreDataPrivateApis", "noticesStore", "coreStore", "uploadIcon", "clsx"]
|
|
7
7
|
}
|
package/build/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './components';\n\nexport { uploadMedia } from './utils/upload-media';\nexport { transformAttachment } from './utils/transform-attachment';\nexport { validateFileSize } from './utils/validate-file-size';\nexport { validateMimeType } from './utils/validate-mime-type';\nexport { validateMimeTypeForUser } from './utils/validate-mime-type-for-user';\n\nexport type { Attachment, RestAttachment } from './utils/types';\n\nexport { privateApis } from './private-apis';\n"],
|
|
4
|
+
"sourcesContent": ["export * from './components';\n\nexport { uploadMedia } from './utils/upload-media';\nexport { transformAttachment } from './utils/transform-attachment';\nexport { validateFileSize } from './utils/validate-file-size';\nexport { validateMimeType } from './utils/validate-mime-type';\nexport { validateMimeTypeForUser } from './utils/validate-mime-type-for-user';\n\nexport type { Attachment, RestAttachment, SubSizeData } from './utils/types';\n\nexport { privateApis } from './private-apis';\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAc,mCAAd;AAEA,0BAA4B;AAC5B,kCAAoC;AACpC,gCAAiC;AACjC,gCAAiC;AACjC,yCAAwC;AAIxC,0BAA4B;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -33,17 +33,17 @@ async function sideloadMedia({
|
|
|
33
33
|
attachmentId,
|
|
34
34
|
additionalData = {},
|
|
35
35
|
signal,
|
|
36
|
-
|
|
36
|
+
onSuccess,
|
|
37
37
|
onError = noop
|
|
38
38
|
}) {
|
|
39
39
|
try {
|
|
40
|
-
const
|
|
40
|
+
const subSizeData = await (0, import_sideload_to_server.sideloadToServer)(
|
|
41
41
|
file,
|
|
42
42
|
attachmentId,
|
|
43
43
|
additionalData,
|
|
44
44
|
signal
|
|
45
45
|
);
|
|
46
|
-
|
|
46
|
+
onSuccess?.(subSizeData);
|
|
47
47
|
} catch (error) {
|
|
48
48
|
let message;
|
|
49
49
|
if (error instanceof Error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/sideload-media.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport type {\n\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA4B;AAW5B,gCAAiC;AACjC,0BAA4B;AAE5B,IAAM,OAAO,MAAM;AAAC;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tOnErrorHandler,\n\tCreateSideloadFile,\n\tRestAttachment,\n\tSubSizeData,\n} from './types';\nimport { sideloadToServer } from './sideload-to-server';\nimport { UploadError } from './upload-error';\n\nconst noop = () => {};\n\ntype OnSubSizeHandler = ( subSize: SubSizeData ) => void;\n\ninterface SideloadMediaArgs {\n\t// Additional data to include in the request.\n\tadditionalData?: CreateSideloadFile;\n\t// File to sideload.\n\tfile: File;\n\t// Attachment ID.\n\tattachmentId: RestAttachment[ 'id' ];\n\t// Function called when an error happens.\n\tonError?: OnErrorHandler;\n\t// Function called when the sideload completes with sub-size data.\n\tonSuccess?: OnSubSizeHandler;\n\t// Abort signal.\n\tsignal?: AbortSignal;\n}\n\n/**\n * Uploads a file to the server without creating an attachment.\n *\n * Returns sub-size data instead of a full attachment. The client\n * accumulates this data and sends it to the finalize endpoint.\n *\n * @param $0 Parameters object passed to the function.\n * @param $0.file Media File to Save.\n * @param $0.attachmentId Parent attachment ID.\n * @param $0.additionalData Additional data to include in the request.\n * @param $0.signal Abort signal.\n * @param $0.onSuccess Function called when the sideload completes with sub-size data.\n * @param $0.onError Function called when an error happens.\n */\nexport async function sideloadMedia( {\n\tfile,\n\tattachmentId,\n\tadditionalData = {},\n\tsignal,\n\tonSuccess,\n\tonError = noop,\n}: SideloadMediaArgs ) {\n\ttry {\n\t\tconst subSizeData = await sideloadToServer(\n\t\t\tfile,\n\t\t\tattachmentId,\n\t\t\tadditionalData,\n\t\t\tsignal\n\t\t);\n\t\tonSuccess?.( subSizeData );\n\t} catch ( error ) {\n\t\tlet message;\n\t\tif ( error instanceof Error ) {\n\t\t\tmessage = error.message;\n\t\t} else {\n\t\t\tmessage = sprintf(\n\t\t\t\t// translators: %s: file name\n\t\t\t\t__( 'Error while sideloading file %s to the server.' ),\n\t\t\t\tfile.name\n\t\t\t);\n\t\t}\n\t\tonError(\n\t\t\tnew UploadError( {\n\t\t\t\tcode: 'GENERAL',\n\t\t\t\tmessage,\n\t\t\t\tfile,\n\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t} )\n\t\t);\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA4B;AAW5B,gCAAiC;AACjC,0BAA4B;AAE5B,IAAM,OAAO,MAAM;AAAC;AAiCpB,eAAsB,cAAe;AAAA,EACpC;AAAA,EACA;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA,UAAU;AACX,GAAuB;AACtB,MAAI;AACH,UAAM,cAAc,UAAM;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,gBAAa,WAAY;AAAA,EAC1B,SAAU,OAAQ;AACjB,QAAI;AACJ,QAAK,iBAAiB,OAAQ;AAC7B,gBAAU,MAAM;AAAA,IACjB,OAAO;AACN,oBAAU;AAAA;AAAA,YAET,gBAAI,gDAAiD;AAAA,QACrD,KAAK;AAAA,MACN;AAAA,IACD;AACA;AAAA,MACC,IAAI,gCAAa;AAAA,QAChB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,MACzC,CAAE;AAAA,IACH;AAAA,EACD;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -35,7 +35,6 @@ __export(sideload_to_server_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(sideload_to_server_exports);
|
|
36
36
|
var import_api_fetch = __toESM(require("@wordpress/api-fetch"));
|
|
37
37
|
var import_flatten_form_data = require("./flatten-form-data.cjs");
|
|
38
|
-
var import_transform_attachment = require("./transform-attachment.cjs");
|
|
39
38
|
async function sideloadToServer(file, attachmentId, additionalData = {}, signal) {
|
|
40
39
|
const data = new FormData();
|
|
41
40
|
data.append("file", file, file.name || file.type.replace("/", "."));
|
|
@@ -46,14 +45,12 @@ async function sideloadToServer(file, attachmentId, additionalData = {}, signal)
|
|
|
46
45
|
value
|
|
47
46
|
);
|
|
48
47
|
}
|
|
49
|
-
return (0,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
})
|
|
56
|
-
);
|
|
48
|
+
return (0, import_api_fetch.default)({
|
|
49
|
+
path: `/wp/v2/media/${attachmentId}/sideload`,
|
|
50
|
+
body: data,
|
|
51
|
+
method: "POST",
|
|
52
|
+
signal
|
|
53
|
+
});
|
|
57
54
|
}
|
|
58
55
|
// Annotate the CommonJS export names for ESM import in node:
|
|
59
56
|
0 && (module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/sideload-to-server.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport apiFetch from '@wordpress/api-fetch';\n\n/**\n * Internal dependencies\n */\nimport type { CreateSideloadFile, RestAttachment } from './types';\nimport { flattenFormData } from './flatten-form-data';\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,uBAAqB;AAMrB,+BAAgC;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport apiFetch from '@wordpress/api-fetch';\n\n/**\n * Internal dependencies\n */\nimport type { CreateSideloadFile, RestAttachment, SubSizeData } from './types';\nimport { flattenFormData } from './flatten-form-data';\n\n/**\n * Uploads a file to the server without creating an attachment.\n *\n * Returns lightweight sub-size data instead of a full attachment.\n * The client accumulates these responses and sends them to the\n * finalize endpoint.\n *\n * @param file Media File to Save.\n * @param attachmentId Parent attachment ID.\n * @param additionalData Additional data to include in the request.\n * @param signal Abort signal.\n *\n * @return Sub-size data for the uploaded file.\n */\nexport async function sideloadToServer(\n\tfile: File,\n\tattachmentId: RestAttachment[ 'id' ],\n\tadditionalData: CreateSideloadFile = {},\n\tsignal?: AbortSignal\n): Promise< SubSizeData > {\n\t// Create upload payload.\n\tconst data = new FormData();\n\tdata.append( 'file', file, file.name || file.type.replace( '/', '.' ) );\n\tfor ( const [ key, value ] of Object.entries( additionalData ) ) {\n\t\tflattenFormData(\n\t\t\tdata,\n\t\t\tkey,\n\t\t\tvalue as string | Record< string, string > | undefined\n\t\t);\n\t}\n\n\treturn apiFetch< SubSizeData >( {\n\t\tpath: `/wp/v2/media/${ attachmentId }/sideload`,\n\t\tbody: data,\n\t\tmethod: 'POST',\n\t\tsignal,\n\t} );\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,uBAAqB;AAMrB,+BAAgC;AAgBhC,eAAsB,iBACrB,MACA,cACA,iBAAqC,CAAC,GACtC,QACyB;AAEzB,QAAM,OAAO,IAAI,SAAS;AAC1B,OAAK,OAAQ,QAAQ,MAAM,KAAK,QAAQ,KAAK,KAAK,QAAS,KAAK,GAAI,CAAE;AACtE,aAAY,CAAE,KAAK,KAAM,KAAK,OAAO,QAAS,cAAe,GAAI;AAChE;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAEA,aAAO,iBAAAA,SAAyB;AAAA,IAC/B,MAAM,gBAAiB,YAAa;AAAA,IACpC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,EACD,CAAE;AACH;",
|
|
6
6
|
"names": ["apiFetch"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/types.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * A media attachment object in a REST API context.\n *\n * Simplified version of what's defined in the wp-types package.\n *\n * @see https://www.npmjs.com/package/wp-types\n */\ninterface WP_REST_API_Attachment {\n\t/**\n\t * Unique identifier for the attachment.\n\t */\n\tid: number;\n\t/**\n\t * The ID of the featured media for the post.\n\t */\n\tfeatured_media: number;\n\t/**\n\t * URL to the attachment.\n\t */\n\tlink: string;\n\t/**\n\t * The date the attachment was published, in the site's timezone.\n\t */\n\tdate: string;\n\t/**\n\t * The date the attachment was published, as GMT.\n\t */\n\tdate_gmt: string;\n\t/**\n\t * The date the attachment was last modified, in the site's timezone.\n\t */\n\tmodified: string;\n\t/**\n\t * The date the attachment was last modified, as GMT.\n\t */\n\tmodified_gmt: string;\n\t/**\n\t * An alphanumeric identifier for the attachment unique to its type.\n\t */\n\tslug: string;\n\t/**\n\t * A named status for the attachment.\n\t */\n\tstatus: string;\n\t/**\n\t * Type of Post for the attachment.\n\t */\n\ttype: 'attachment';\n\t/**\n\t * Alternative text to display when attachment is not displayed.\n\t */\n\talt_text: string;\n\t/**\n\t * The attachment caption.\n\t */\n\tcaption: {\n\t\t/**\n\t\t * Caption for the attachment, as it exists in the database. Only present when using the 'edit' context.\n\t\t */\n\t\traw?: string;\n\t\t/**\n\t\t * HTML caption for the attachment, transformed for display.\n\t\t */\n\t\trendered: string;\n\t};\n\t/**\n\t * The attachment description.\n\t */\n\tdescription: {\n\t\t/**\n\t\t * Description for the attachment, as it exists in the database. Only present when using the 'edit' context.\n\t\t */\n\t\traw?: string;\n\t\t/**\n\t\t * HTML description for the attachment, transformed for display.\n\t\t */\n\t\trendered: string;\n\t};\n\t/**\n\t * Attachment type.\n\t */\n\tmedia_type: 'image' | 'file';\n\t/**\n\t * The attachment MIME type.\n\t */\n\tmime_type: string;\n\t/**\n\t * Details about the media file, specific to its type.\n\t */\n\tmedia_details: {\n\t\t[ k: string ]: unknown;\n\t};\n\t/**\n\t * The ID for the associated post of the attachment.\n\t */\n\tpost: number | null;\n\t/**\n\t * URL to the original attachment file.\n\t */\n\tsource_url: string;\n\t/**\n\t * List of the missing image sizes of the attachment. Only present when using the 'edit' context.\n\t */\n\tmissing_image_sizes?: string[];\n\t/**\n\t * Permalink template for the attachment. Only present when using the 'edit' context and the post type is public.\n\t */\n\tpermalink_template?: string;\n\t/**\n\t * Slug automatically generated from the attachment title. Only present when using the 'edit' context and the post type is public.\n\t */\n\tgenerated_slug?: string;\n\t/**\n\t * An array of the class names for the post container element.\n\t */\n\tclass_list: string[];\n\t/**\n\t * The title for the attachment.\n\t */\n\ttitle: {\n\t\t/**\n\t\t * Title for the attachment, as it exists in the database. Only present when using the 'edit' context.\n\t\t */\n\t\traw?: string;\n\t\t/**\n\t\t * HTML title for the attachment, transformed for display.\n\t\t */\n\t\trendered: string;\n\t};\n\t/**\n\t * The ID for the author of the attachment.\n\t */\n\tauthor: number;\n\t/**\n\t * Whether or not comments are open on the attachment.\n\t */\n\tcomment_status: string;\n\t/**\n\t * Whether or not the attachment can be pinged.\n\t */\n\tping_status: string;\n\t/**\n\t * Meta fields.\n\t */\n\tmeta:\n\t\t| []\n\t\t| {\n\t\t\t\t[ k: string ]: unknown;\n\t\t };\n\t/**\n\t * The theme file to use to display the attachment.\n\t */\n\ttemplate: string;\n\t_links: {\n\t\t[ k: string ]: {\n\t\t\thref: string;\n\t\t\tembeddable?: boolean;\n\t\t\t[ k: string ]: unknown;\n\t\t}[];\n\t};\n\t/**\n\t * The embedded representation of relations. Only present when the '_embed' query parameter is set.\n\t */\n\t_embedded?: {\n\t\t/**\n\t\t * The author of the post.\n\t\t */\n\t\tauthor: unknown[];\n\t\t/**\n\t\t * The featured image post.\n\t\t */\n\t\t'wp:featuredmedia'?: WP_REST_API_Attachment[];\n\t\t[ k: string ]: unknown;\n\t};\n\t[ k: string ]: unknown;\n}\n\n/**\n * REST API attachment object with additional fields added by this project.\n */\nexport interface RestAttachment extends WP_REST_API_Attachment {}\n\ntype BetterOmit< T, K extends PropertyKey > = {\n\t[ P in keyof T as P extends K ? never : P ]: T[ P ];\n};\n\n/**\n * Transformed attachment object.\n */\nexport type Attachment = BetterOmit<\n\tRestAttachment,\n\t'alt_text' | 'source_url' | 'caption' | 'title'\n> & {\n\talt: WP_REST_API_Attachment[ 'alt_text' ];\n\tcaption: WP_REST_API_Attachment[ 'caption' ][ 'raw' ] & string;\n\ttitle: WP_REST_API_Attachment[ 'title' ][ 'raw' ];\n\turl: WP_REST_API_Attachment[ 'source_url' ];\n\tposter?: WP_REST_API_Attachment[ 'source_url' ];\n};\n\nexport type OnChangeHandler = ( attachments: Partial< Attachment >[] ) => void;\nexport type OnErrorHandler = ( error: Error ) => void;\n\nexport type CreateRestAttachment = Partial< RestAttachment >;\n\nexport type AdditionalData = BetterOmit< CreateRestAttachment, 'meta' >;\n\nexport interface CreateSideloadFile {\n\timage_size?: string;\n\tupload_request?: string;\n}\n\nexport interface SideloadAdditionalData {\n\tpost: RestAttachment[ 'id' ];\n\timage_size?: string;\n}\n"],
|
|
4
|
+
"sourcesContent": ["/**\n * A media attachment object in a REST API context.\n *\n * Simplified version of what's defined in the wp-types package.\n *\n * @see https://www.npmjs.com/package/wp-types\n */\ninterface WP_REST_API_Attachment {\n\t/**\n\t * Unique identifier for the attachment.\n\t */\n\tid: number;\n\t/**\n\t * The ID of the featured media for the post.\n\t */\n\tfeatured_media: number;\n\t/**\n\t * URL to the attachment.\n\t */\n\tlink: string;\n\t/**\n\t * The date the attachment was published, in the site's timezone.\n\t */\n\tdate: string;\n\t/**\n\t * The date the attachment was published, as GMT.\n\t */\n\tdate_gmt: string;\n\t/**\n\t * The date the attachment was last modified, in the site's timezone.\n\t */\n\tmodified: string;\n\t/**\n\t * The date the attachment was last modified, as GMT.\n\t */\n\tmodified_gmt: string;\n\t/**\n\t * An alphanumeric identifier for the attachment unique to its type.\n\t */\n\tslug: string;\n\t/**\n\t * A named status for the attachment.\n\t */\n\tstatus: string;\n\t/**\n\t * Type of Post for the attachment.\n\t */\n\ttype: 'attachment';\n\t/**\n\t * Alternative text to display when attachment is not displayed.\n\t */\n\talt_text: string;\n\t/**\n\t * The attachment caption.\n\t */\n\tcaption: {\n\t\t/**\n\t\t * Caption for the attachment, as it exists in the database. Only present when using the 'edit' context.\n\t\t */\n\t\traw?: string;\n\t\t/**\n\t\t * HTML caption for the attachment, transformed for display.\n\t\t */\n\t\trendered: string;\n\t};\n\t/**\n\t * The attachment description.\n\t */\n\tdescription: {\n\t\t/**\n\t\t * Description for the attachment, as it exists in the database. Only present when using the 'edit' context.\n\t\t */\n\t\traw?: string;\n\t\t/**\n\t\t * HTML description for the attachment, transformed for display.\n\t\t */\n\t\trendered: string;\n\t};\n\t/**\n\t * Attachment type.\n\t */\n\tmedia_type: 'image' | 'file';\n\t/**\n\t * The attachment MIME type.\n\t */\n\tmime_type: string;\n\t/**\n\t * Details about the media file, specific to its type.\n\t */\n\tmedia_details: {\n\t\t[ k: string ]: unknown;\n\t};\n\t/**\n\t * The ID for the associated post of the attachment.\n\t */\n\tpost: number | null;\n\t/**\n\t * URL to the original attachment file.\n\t */\n\tsource_url: string;\n\t/**\n\t * List of the missing image sizes of the attachment. Only present when using the 'edit' context.\n\t */\n\tmissing_image_sizes?: string[];\n\t/**\n\t * Permalink template for the attachment. Only present when using the 'edit' context and the post type is public.\n\t */\n\tpermalink_template?: string;\n\t/**\n\t * Slug automatically generated from the attachment title. Only present when using the 'edit' context and the post type is public.\n\t */\n\tgenerated_slug?: string;\n\t/**\n\t * An array of the class names for the post container element.\n\t */\n\tclass_list: string[];\n\t/**\n\t * The title for the attachment.\n\t */\n\ttitle: {\n\t\t/**\n\t\t * Title for the attachment, as it exists in the database. Only present when using the 'edit' context.\n\t\t */\n\t\traw?: string;\n\t\t/**\n\t\t * HTML title for the attachment, transformed for display.\n\t\t */\n\t\trendered: string;\n\t};\n\t/**\n\t * The ID for the author of the attachment.\n\t */\n\tauthor: number;\n\t/**\n\t * Whether or not comments are open on the attachment.\n\t */\n\tcomment_status: string;\n\t/**\n\t * Whether or not the attachment can be pinged.\n\t */\n\tping_status: string;\n\t/**\n\t * Meta fields.\n\t */\n\tmeta:\n\t\t| []\n\t\t| {\n\t\t\t\t[ k: string ]: unknown;\n\t\t };\n\t/**\n\t * The theme file to use to display the attachment.\n\t */\n\ttemplate: string;\n\t_links: {\n\t\t[ k: string ]: {\n\t\t\thref: string;\n\t\t\tembeddable?: boolean;\n\t\t\t[ k: string ]: unknown;\n\t\t}[];\n\t};\n\t/**\n\t * The embedded representation of relations. Only present when the '_embed' query parameter is set.\n\t */\n\t_embedded?: {\n\t\t/**\n\t\t * The author of the post.\n\t\t */\n\t\tauthor: unknown[];\n\t\t/**\n\t\t * The featured image post.\n\t\t */\n\t\t'wp:featuredmedia'?: WP_REST_API_Attachment[];\n\t\t[ k: string ]: unknown;\n\t};\n\t[ k: string ]: unknown;\n}\n\n/**\n * REST API attachment object with additional fields added by this project.\n */\nexport interface RestAttachment extends WP_REST_API_Attachment {}\n\ntype BetterOmit< T, K extends PropertyKey > = {\n\t[ P in keyof T as P extends K ? never : P ]: T[ P ];\n};\n\n/**\n * Transformed attachment object.\n */\nexport type Attachment = BetterOmit<\n\tRestAttachment,\n\t'alt_text' | 'source_url' | 'caption' | 'title'\n> & {\n\talt: WP_REST_API_Attachment[ 'alt_text' ];\n\tcaption: WP_REST_API_Attachment[ 'caption' ][ 'raw' ] & string;\n\ttitle: WP_REST_API_Attachment[ 'title' ][ 'raw' ];\n\turl: WP_REST_API_Attachment[ 'source_url' ];\n\tposter?: WP_REST_API_Attachment[ 'source_url' ];\n};\n\nexport type OnChangeHandler = ( attachments: Partial< Attachment >[] ) => void;\nexport type OnErrorHandler = ( error: Error ) => void;\n\nexport type CreateRestAttachment = Partial< RestAttachment >;\n\nexport type AdditionalData = BetterOmit< CreateRestAttachment, 'meta' >;\n\nexport interface CreateSideloadFile {\n\timage_size?: string;\n\tupload_request?: string;\n\tgenerate_sub_sizes?: boolean;\n\tconvert_format?: boolean;\n}\n\nexport interface SideloadAdditionalData {\n\tpost: RestAttachment[ 'id' ];\n\timage_size?: string;\n}\n\n/**\n * Sub-size data returned by the sideload endpoint.\n *\n * Each sideload returns this lightweight object instead of a full attachment.\n * The client accumulates these and sends them all to the finalize endpoint.\n */\nexport interface SubSizeData {\n\timage_size: string;\n\twidth?: number;\n\theight?: number;\n\tfile: string;\n\tmime_type?: string;\n\tfilesize?: number;\n\toriginal_image?: string;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/upload-media.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\nimport { createBlobURL, revokeBlobURL } from '@wordpress/blob';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tAdditionalData,\n\tAttachment,\n\tOnChangeHandler,\n\tOnErrorHandler,\n} from './types';\nimport { uploadToServer } from './upload-to-server';\nimport { validateMimeType } from './validate-mime-type';\nimport { validateMimeTypeForUser } from './validate-mime-type-for-user';\nimport { validateFileSize } from './validate-file-size';\nimport { UploadError } from './upload-error';\n\ndeclare global {\n\tinterface Window {\n\t\t__clientSideMediaProcessing?: boolean;\n\t}\n}\n\ninterface UploadMediaArgs {\n\t// Additional data to include in the request.\n\tadditionalData?: AdditionalData;\n\t// Array with the types of media that can be uploaded, if unset all types are allowed.\n\tallowedTypes?: string[];\n\t// List of files.\n\tfilesList: File[];\n\t// Maximum upload size in bytes allowed for the site.\n\tmaxUploadFileSize?: number;\n\t// Function called when an error happens.\n\tonError?: OnErrorHandler;\n\t// Function called each time a file or a temporary representation of the file is available.\n\tonFileChange?: OnChangeHandler;\n\t// List of allowed mime types and file extensions.\n\twpAllowedMimeTypes?: Record< string, string > | null;\n\t// Abort signal.\n\tsignal?: AbortSignal;\n\t// Whether to allow multiple files to be uploaded.\n\tmultiple?: boolean;\n}\n\n/**\n * Upload a media file when the file upload button is activated\n * or when adding a file to the editor via drag & drop.\n *\n * @param $0 Parameters object passed to the function.\n * @param $0.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.\n * @param $0.additionalData Additional data to include in the request.\n * @param $0.filesList List of files.\n * @param $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.\n * @param $0.onError Function called when an error happens.\n * @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.\n * @param $0.wpAllowedMimeTypes List of allowed mime types and file extensions.\n * @param $0.signal Abort signal.\n * @param $0.multiple Whether to allow multiple files to be uploaded.\n */\nexport function uploadMedia( {\n\twpAllowedMimeTypes,\n\tallowedTypes,\n\tadditionalData = {},\n\tfilesList,\n\tmaxUploadFileSize,\n\tonError,\n\tonFileChange,\n\tsignal,\n\tmultiple = true,\n}: UploadMediaArgs ) {\n\tif ( ! multiple && filesList.length > 1 ) {\n\t\tonError?.( new Error( __( 'Only one file can be used here.' ) ) );\n\t\treturn;\n\t}\n\n\tconst validFiles = [];\n\n\tconst filesSet: Array< Partial< Attachment > | null > = [];\n\tconst setAndUpdateFiles = ( index: number, value: Attachment | null ) => {\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\tif ( filesSet[ index ]?.url ) {\n\t\t\t\trevokeBlobURL( filesSet[ index ].url );\n\t\t\t}\n\t\t}\n\t\tfilesSet[ index ] = value;\n\t\tonFileChange?.(\n\t\t\tfilesSet.filter( ( attachment ) => attachment !== null )\n\t\t);\n\t};\n\n\tfor ( const mediaFile of filesList ) {\n\t\t// Verify if user is allowed to upload this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeTypeForUser( mediaFile, wpAllowedMimeTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if the caller (e.g. a block) supports this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeType( mediaFile, allowedTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Verify if file is greater than the maximum file upload size allowed for the site.\n\t\ttry {\n\t\t\tvalidateFileSize( mediaFile, maxUploadFileSize );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalidFiles.push( mediaFile );\n\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\t// Set temporary URL to create placeholder media file, this is replaced\n\t\t\t// with final file from media gallery when upload is `done` below.\n\t\t\tfilesSet.push( { url: createBlobURL( mediaFile ) } );\n\t\t\tonFileChange?.( filesSet as Array< Partial< Attachment > > );\n\t\t}\n\t}\n\n\tvalidFiles.map( async ( file, index ) => {\n\t\ttry {\n\t\t\tconst attachment = await uploadToServer(\n\t\t\t\tfile,\n\t\t\t\tadditionalData,\n\t\t\t\tsignal\n\t\t\t);\n\t\t\tsetAndUpdateFiles( index, attachment );\n\t\t} catch ( error ) {\n\t\t\t// Reset to empty on failure.\n\t\t\tsetAndUpdateFiles( index, null );\n\n\t\t\t// @wordpress/api-fetch throws any response that isn't in the 200 range as-is.\n\t\t\tlet message: string;\n\t\t\tif (\n\t\t\t\ttypeof error === 'object' &&\n\t\t\t\terror !== null &&\n\t\t\t\t'message' in error\n\t\t\t) {\n\t\t\t\tmessage =\n\t\t\t\t\ttypeof error.message === 'string'\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: String( error.message );\n\t\t\t} else {\n\t\t\t\tmessage = sprintf(\n\t\t\t\t\t// translators: %s: file name\n\t\t\t\t\t__( 'Error while uploading file %s to the media library.' ),\n\t\t\t\t\tfile.name\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tonError?.(\n\t\t\t\tnew UploadError( {\n\t\t\t\t\tcode: 'GENERAL',\n\t\t\t\t\tmessage,\n\t\t\t\t\tfile,\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t} )\n\t\t\t);\n\t\t}\n\t} );\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA4B;AAC5B,kBAA6C;AAW7C,8BAA+B;AAC/B,gCAAiC;AACjC,yCAAwC;AACxC,gCAAiC;AACjC,0BAA4B;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\nimport { createBlobURL, revokeBlobURL } from '@wordpress/blob';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tAdditionalData,\n\tAttachment,\n\tOnChangeHandler,\n\tOnErrorHandler,\n} from './types';\nimport { uploadToServer } from './upload-to-server';\nimport { validateMimeType } from './validate-mime-type';\nimport { validateMimeTypeForUser } from './validate-mime-type-for-user';\nimport { validateFileSize } from './validate-file-size';\nimport { UploadError } from './upload-error';\n\ndeclare global {\n\tinterface Window {\n\t\t__clientSideMediaProcessing?: boolean;\n\t\t__heicUploadSupport?: boolean;\n\t}\n}\n\ninterface UploadMediaArgs {\n\t// Additional data to include in the request.\n\tadditionalData?: AdditionalData;\n\t// Array with the types of media that can be uploaded, if unset all types are allowed.\n\tallowedTypes?: string[];\n\t// List of files.\n\tfilesList: File[];\n\t// Maximum upload size in bytes allowed for the site.\n\tmaxUploadFileSize?: number;\n\t// Function called when an error happens.\n\tonError?: OnErrorHandler;\n\t// Function called each time a file or a temporary representation of the file is available.\n\tonFileChange?: OnChangeHandler;\n\t// List of allowed mime types and file extensions.\n\twpAllowedMimeTypes?: Record< string, string > | null;\n\t// Abort signal.\n\tsignal?: AbortSignal;\n\t// Whether to allow multiple files to be uploaded.\n\tmultiple?: boolean;\n}\n\n/**\n * Upload a media file when the file upload button is activated\n * or when adding a file to the editor via drag & drop.\n *\n * @param $0 Parameters object passed to the function.\n * @param $0.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.\n * @param $0.additionalData Additional data to include in the request.\n * @param $0.filesList List of files.\n * @param $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.\n * @param $0.onError Function called when an error happens.\n * @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.\n * @param $0.wpAllowedMimeTypes List of allowed mime types and file extensions.\n * @param $0.signal Abort signal.\n * @param $0.multiple Whether to allow multiple files to be uploaded.\n */\nexport function uploadMedia( {\n\twpAllowedMimeTypes,\n\tallowedTypes,\n\tadditionalData = {},\n\tfilesList,\n\tmaxUploadFileSize,\n\tonError,\n\tonFileChange,\n\tsignal,\n\tmultiple = true,\n}: UploadMediaArgs ) {\n\tif ( ! multiple && filesList.length > 1 ) {\n\t\tonError?.( new Error( __( 'Only one file can be used here.' ) ) );\n\t\treturn;\n\t}\n\n\tconst validFiles = [];\n\n\tconst filesSet: Array< Partial< Attachment > | null > = [];\n\tconst setAndUpdateFiles = ( index: number, value: Attachment | null ) => {\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\tif ( filesSet[ index ]?.url ) {\n\t\t\t\trevokeBlobURL( filesSet[ index ].url );\n\t\t\t}\n\t\t}\n\t\tfilesSet[ index ] = value;\n\t\tonFileChange?.(\n\t\t\tfilesSet.filter( ( attachment ) => attachment !== null )\n\t\t);\n\t};\n\n\tfor ( const mediaFile of filesList ) {\n\t\t// Verify if user is allowed to upload this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeTypeForUser( mediaFile, wpAllowedMimeTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if the caller (e.g. a block) supports this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeType( mediaFile, allowedTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Verify if file is greater than the maximum file upload size allowed for the site.\n\t\ttry {\n\t\t\tvalidateFileSize( mediaFile, maxUploadFileSize );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalidFiles.push( mediaFile );\n\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\t// Set temporary URL to create placeholder media file, this is replaced\n\t\t\t// with final file from media gallery when upload is `done` below.\n\t\t\tfilesSet.push( { url: createBlobURL( mediaFile ) } );\n\t\t\tonFileChange?.( filesSet as Array< Partial< Attachment > > );\n\t\t}\n\t}\n\n\tvalidFiles.map( async ( file, index ) => {\n\t\ttry {\n\t\t\tconst attachment = await uploadToServer(\n\t\t\t\tfile,\n\t\t\t\tadditionalData,\n\t\t\t\tsignal\n\t\t\t);\n\t\t\tsetAndUpdateFiles( index, attachment );\n\t\t} catch ( error ) {\n\t\t\t// Reset to empty on failure.\n\t\t\tsetAndUpdateFiles( index, null );\n\n\t\t\t// @wordpress/api-fetch throws any response that isn't in the 200 range as-is.\n\t\t\tlet message: string;\n\t\t\tif (\n\t\t\t\ttypeof error === 'object' &&\n\t\t\t\terror !== null &&\n\t\t\t\t'message' in error\n\t\t\t) {\n\t\t\t\tmessage =\n\t\t\t\t\ttypeof error.message === 'string'\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: String( error.message );\n\t\t\t} else {\n\t\t\t\tmessage = sprintf(\n\t\t\t\t\t// translators: %s: file name\n\t\t\t\t\t__( 'Error while uploading file %s to the media library.' ),\n\t\t\t\t\tfile.name\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tonError?.(\n\t\t\t\tnew UploadError( {\n\t\t\t\t\tcode: 'GENERAL',\n\t\t\t\t\tmessage,\n\t\t\t\t\tfile,\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t} )\n\t\t\t);\n\t\t}\n\t} );\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,kBAA4B;AAC5B,kBAA6C;AAW7C,8BAA+B;AAC/B,gCAAiC;AACjC,yCAAwC;AACxC,gCAAiC;AACjC,0BAA4B;AA6CrB,SAAS,YAAa;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AACZ,GAAqB;AACpB,MAAK,CAAE,YAAY,UAAU,SAAS,GAAI;AACzC,cAAW,IAAI,UAAO,gBAAI,iCAAkC,CAAE,CAAE;AAChE;AAAA,EACD;AAEA,QAAM,aAAa,CAAC;AAEpB,QAAM,WAAkD,CAAC;AACzD,QAAM,oBAAoB,CAAE,OAAe,UAA8B;AAExE,QAAK,CAAE,OAAO,6BAA8B;AAC3C,UAAK,SAAU,KAAM,GAAG,KAAM;AAC7B,uCAAe,SAAU,KAAM,EAAE,GAAI;AAAA,MACtC;AAAA,IACD;AACA,aAAU,KAAM,IAAI;AACpB;AAAA,MACC,SAAS,OAAQ,CAAE,eAAgB,eAAe,IAAK;AAAA,IACxD;AAAA,EACD;AAEA,aAAY,aAAa,WAAY;AAGpC,QAAI;AACH,sEAAyB,WAAW,kBAAmB;AAAA,IACxD,SAAU,OAAiB;AAC1B,gBAAW,KAAe;AAC1B;AAAA,IACD;AAIA,QAAI;AACH,sDAAkB,WAAW,YAAa;AAAA,IAC3C,SAAU,OAAiB;AAC1B,gBAAW,KAAe;AAC1B;AAAA,IACD;AAGA,QAAI;AACH,sDAAkB,WAAW,iBAAkB;AAAA,IAChD,SAAU,OAAiB;AAC1B,gBAAW,KAAe;AAC1B;AAAA,IACD;AAEA,eAAW,KAAM,SAAU;AAG3B,QAAK,CAAE,OAAO,6BAA8B;AAG3C,eAAS,KAAM,EAAE,SAAK,2BAAe,SAAU,EAAE,CAAE;AACnD,qBAAgB,QAA2C;AAAA,IAC5D;AAAA,EACD;AAEA,aAAW,IAAK,OAAQ,MAAM,UAAW;AACxC,QAAI;AACH,YAAM,aAAa,UAAM;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MACD;AACA,wBAAmB,OAAO,UAAW;AAAA,IACtC,SAAU,OAAQ;AAEjB,wBAAmB,OAAO,IAAK;AAG/B,UAAI;AACJ,UACC,OAAO,UAAU,YACjB,UAAU,QACV,aAAa,OACZ;AACD,kBACC,OAAO,MAAM,YAAY,WACtB,MAAM,UACN,OAAQ,MAAM,OAAQ;AAAA,MAC3B,OAAO;AACN,sBAAU;AAAA;AAAA,cAET,gBAAI,qDAAsD;AAAA,UAC1D,KAAK;AAAA,QACN;AAAA,MACD;AAEA;AAAA,QACC,IAAI,gCAAa;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,QACzC,CAAE;AAAA,MACH;AAAA,IACD;AAAA,EACD,CAAE;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -133,8 +133,26 @@ function MediaUploadModal({
|
|
|
133
133
|
filters.mime_type = filter.value;
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
|
-
if (!filters.media_type) {
|
|
137
|
-
|
|
136
|
+
if (!filters.media_type && !filters.mime_type && allowedTypes && !allowedTypes.includes("*")) {
|
|
137
|
+
const { mediaTypes, mimeTypes } = allowedTypes.reduce(
|
|
138
|
+
(acc, type) => {
|
|
139
|
+
if (type.endsWith("/*")) {
|
|
140
|
+
acc.mediaTypes.push(type.replace("/*", ""));
|
|
141
|
+
} else if (type.includes("/")) {
|
|
142
|
+
acc.mimeTypes.push(type);
|
|
143
|
+
} else {
|
|
144
|
+
acc.mediaTypes.push(type);
|
|
145
|
+
}
|
|
146
|
+
return acc;
|
|
147
|
+
},
|
|
148
|
+
{ mediaTypes: [], mimeTypes: [] }
|
|
149
|
+
);
|
|
150
|
+
if (mediaTypes.length) {
|
|
151
|
+
filters.media_type = mediaTypes;
|
|
152
|
+
}
|
|
153
|
+
if (mimeTypes.length) {
|
|
154
|
+
filters.mime_type = mimeTypes;
|
|
155
|
+
}
|
|
138
156
|
}
|
|
139
157
|
return {
|
|
140
158
|
per_page: view.perPage || 20,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/components/media-upload-modal/index.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tcreatePortal,\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tuseEffect,\n} from '@wordpress/element';\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect, useDispatch } from '@wordpress/data';\nimport { Modal, DropZone, FormFileUpload, Button } from '@wordpress/components';\nimport { upload as uploadIcon } from '@wordpress/icons';\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type {\n\tField,\n\tActionButton,\n\tSupportedLayouts,\n\tView,\n} from '@wordpress/dataviews';\nimport { useView } from '@wordpress/views';\nimport { Stack } from '@wordpress/ui';\nimport {\n\taltTextField,\n\tattachedToField,\n\tauthorField,\n\tcaptionField,\n\tdateAddedField,\n\tdateModifiedField,\n\tdescriptionField,\n\tfilenameField,\n\tfilesizeField,\n\tmediaDimensionsField,\n\tmediaThumbnailField,\n\tmimeTypeField,\n} from '@wordpress/media-fields';\nimport { store as noticesStore, SnackbarNotices } from '@wordpress/notices';\n\n/**\n * Internal dependencies\n */\nimport type { Attachment, RestAttachment } from '../../utils/types';\nimport { transformAttachment } from '../../utils/transform-attachment';\nimport { uploadMedia } from '../../utils/upload-media';\nimport { unlock } from '../../lock-unlock';\nimport { UploadStatusPopover } from './upload-status-popover';\nimport { useInvalidateAttachmentResolutions } from './use-invalidate-attachment-resolutions';\nimport { useUploadStatus } from './use-upload-status';\n\nconst { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );\n\n// Layout constants - matching the picker layout types\nconst LAYOUT_PICKER_GRID = 'pickerGrid';\nconst LAYOUT_PICKER_TABLE = 'pickerTable';\n\n// Custom notices context for the media modal\nconst NOTICES_CONTEXT = 'media-modal';\n\n// Notice ID - reused for all upload-related notices to prevent flooding\nconst NOTICE_ID_UPLOAD_PROGRESS = 'media-modal-upload-progress';\n\nconst defaultView: View = {\n\ttype: LAYOUT_PICKER_GRID,\n\tfields: [],\n\tshowTitle: false,\n\ttitleField: 'title',\n\tmediaField: 'media_thumbnail',\n\tsearch: '',\n\tpage: 1,\n\tperPage: 50,\n\tfilters: [],\n\tlayout: {\n\t\tpreviewSize: 170,\n\t\tdensity: 'compact',\n\t},\n};\n\nconst defaultLayouts: SupportedLayouts = {\n\t[ LAYOUT_PICKER_GRID ]: {\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\tlayout: {\n\t\t\tpreviewSize: 170,\n\t\t\tdensity: 'compact',\n\t\t},\n\t},\n\t[ LAYOUT_PICKER_TABLE ]: {\n\t\tfields: [\n\t\t\t'filename',\n\t\t\t'filesize',\n\t\t\t'media_dimensions',\n\t\t\t'author',\n\t\t\t'date',\n\t\t],\n\t\tshowTitle: true,\n\t},\n};\n\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t */\n\tallowedTypes?: string[];\n\n\t/**\n\t * Whether multiple files can be selected.\n\t * @default false\n\t */\n\tmultiple?: boolean;\n\n\t/**\n\t * The currently selected media item(s).\n\t * Can be a single ID number or array of IDs for multiple selection.\n\t */\n\tvalue?: number | number[];\n\n\t/**\n\t * Function called when media is selected.\n\t * Receives single attachment object or array of attachments.\n\t */\n\tonSelect: ( media: Attachment | Attachment[] ) => void;\n\n\t/**\n\t * Function called when the modal is closed without selection.\n\t */\n\tonClose?: () => void;\n\n\t/**\n\t * Function to handle media uploads.\n\t * If not provided, drag and drop will be disabled.\n\t */\n\tonUpload?: ( args: {\n\t\tallowedTypes?: string[];\n\t\tfilesList: File[];\n\t\tonFileChange?: ( attachments: Partial< Attachment >[] ) => void;\n\t\tonError?: ( error: Error ) => void;\n\t\tmultiple?: boolean;\n\t} ) => void;\n\n\t/**\n\t * Title for the modal.\n\t * @default 'Select Media'\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Whether the modal is open.\n\t */\n\tisOpen: boolean;\n\n\t/**\n\t * Whether the modal can be closed by clicking outside or pressing escape.\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\n\t/**\n\t * Additional CSS class for the modal.\n\t */\n\tmodalClass?: string;\n\n\t/**\n\t * Whether to show a search input.\n\t * @default true\n\t */\n\tsearch?: boolean;\n\n\t/**\n\t * Label for the search input.\n\t */\n\tsearchLabel?: string;\n}\n\n/**\n * MediaUploadModal component that uses Modal and DataViewsPicker for media selection.\n *\n * This is a modern functional component alternative to the legacy MediaUpload class component.\n * It provides a cleaner API and better integration with the WordPress block editor.\n *\n * @param props Component props\n * @param props.allowedTypes Array of allowed media types\n * @param props.multiple Whether multiple files can be selected\n * @param props.value Currently selected media item(s)\n * @param props.onSelect Function called when media is selected\n * @param props.onClose Function called when modal is closed\n * @param props.onUpload Function to handle media uploads\n * @param props.title Title for the modal\n * @param props.isOpen Whether the modal is open\n * @param props.isDismissible Whether modal can be dismissed\n * @param props.modalClass Additional CSS class for modal\n * @param props.search Whether to show search input\n * @param props.searchLabel Label for search input\n * @return JSX element or null\n */\nexport function MediaUploadModal( {\n\tallowedTypes,\n\tmultiple = false,\n\tvalue,\n\tonSelect,\n\tonClose,\n\tonUpload,\n\ttitle = __( 'Select Media' ),\n\tisOpen,\n\tisDismissible = true,\n\tmodalClass,\n\tsearch = true,\n\tsearchLabel = __( 'Search media' ),\n}: MediaUploadModalProps ) {\n\tconst [ selection, setSelection ] = useState< string[] >( () => {\n\t\tif ( ! value ) {\n\t\t\treturn [];\n\t\t}\n\t\treturn Array.isArray( value )\n\t\t\t? value.map( String )\n\t\t\t: [ String( value ) ];\n\t} );\n\n\tconst { createSuccessNotice, removeAllNotices } =\n\t\tuseDispatch( noticesStore );\n\tconst invalidateAttachmentResolutions =\n\t\tuseInvalidateAttachmentResolutions();\n\n\t// Persist view configuration across sessions via the preferences store.\n\tconst { view, updateView, isModified, resetToDefault } = useView( {\n\t\tkind: 'postType',\n\t\tname: 'attachment',\n\t\tslug: 'media-modal',\n\t\tdefaultView,\n\t} );\n\n\t// Build query args based on view properties, similar to PostList\n\tconst queryArgs = useMemo( () => {\n\t\tconst filters: Record< string, any > = {};\n\n\t\tview.filters?.forEach( ( filter ) => {\n\t\t\t// Handle media type filters\n\t\t\tif ( filter.field === 'media_type' ) {\n\t\t\t\tfilters.media_type = filter.value;\n\t\t\t}\n\t\t\t// Handle author filters\n\t\t\tif ( filter.field === 'author' ) {\n\t\t\t\tif ( filter.operator === 'isAny' ) {\n\t\t\t\t\tfilters.author = filter.value;\n\t\t\t\t} else if ( filter.operator === 'isNone' ) {\n\t\t\t\t\tfilters.author_exclude = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle date filters\n\t\t\tif ( filter.field === 'date' || filter.field === 'modified' ) {\n\t\t\t\tif ( filter.operator === 'before' ) {\n\t\t\t\t\tfilters.before = filter.value;\n\t\t\t\t} else if ( filter.operator === 'after' ) {\n\t\t\t\t\tfilters.after = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle mime type filters\n\t\t\tif ( filter.field === 'mime_type' ) {\n\t\t\t\tfilters.mime_type = filter.value;\n\t\t\t}\n\t\t} );\n\n\t\t// Base media type on allowedTypes if no filter is set\n\t\tif ( ! filters.media_type ) {\n\t\t\tfilters.media_type = allowedTypes?.includes( '*' )\n\t\t\t\t? undefined\n\t\t\t\t: allowedTypes;\n\t\t}\n\n\t\treturn {\n\t\t\tper_page: view.perPage || 20,\n\t\t\tpage: view.page || 1,\n\t\t\tstatus: 'inherit',\n\t\t\torder: view.sort?.direction,\n\t\t\torderby: view.sort?.field,\n\t\t\tsearch: view.search,\n\t\t\t_embed: 'author,wp:attached-to',\n\t\t\t...filters,\n\t\t};\n\t}, [ view, allowedTypes ] );\n\n\t// Per-batch completion handler: auto-select uploaded items and refresh the grid.\n\tconst handleBatchComplete = useCallback(\n\t\t( attachments: Partial< Attachment >[] ) => {\n\t\t\tconst uploadedIds = attachments\n\t\t\t\t.map( ( attachment ) => String( attachment.id ) )\n\t\t\t\t.filter( Boolean );\n\n\t\t\tif ( multiple ) {\n\t\t\t\tsetSelection( ( prev ) => {\n\t\t\t\t\tconst existing = new Set( prev );\n\t\t\t\t\tconst newIds = uploadedIds.filter(\n\t\t\t\t\t\t( id ) => ! existing.has( id )\n\t\t\t\t\t);\n\t\t\t\t\treturn [ ...prev, ...newIds ];\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tsetSelection( uploadedIds.slice( 0, 1 ) );\n\t\t\t}\n\n\t\t\t// Invalidate all cached attachment queries so every page of\n\t\t\t// results refreshes \u2014 not just the page the user is viewing.\n\t\t\tinvalidateAttachmentResolutions();\n\t\t},\n\t\t[ multiple, invalidateAttachmentResolutions ]\n\t);\n\n\tconst {\n\t\tuploadingFiles,\n\t\tregisterBatch,\n\t\tdismissError,\n\t\tclearCompleted,\n\t\tallComplete,\n\t} = useUploadStatus( { onBatchComplete: handleBatchComplete } );\n\n\tconst isPopoverOpenRef = useRef( false );\n\tconst handlePopoverOpenChange = useCallback(\n\t\t( open: boolean ) => {\n\t\t\tisPopoverOpenRef.current = open;\n\t\t\tif ( ! open ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t},\n\t\t[ clearCompleted ]\n\t);\n\n\t// Fetch all media attachments using WordPress core data with permissions\n\tconst {\n\t\trecords: mediaRecords,\n\t\tisResolving: isLoading,\n\t\ttotalItems,\n\t\ttotalPages,\n\t} = useEntityRecordsWithPermissions( 'postType', 'attachment', queryArgs );\n\n\tconst fields: Field< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t// Media field definitions from @wordpress/media-fields\n\t\t\t// Cast is safe because RestAttachment has the same properties as Attachment\n\t\t\t{\n\t\t\t\t...( mediaThumbnailField as Field< RestAttachment > ),\n\t\t\t\tenableHiding: false, // Within the modal, the thumbnail should always be shown.\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'title',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Title' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) => {\n\t\t\t\t\tconst titleValue = item.title.raw || item.title.rendered;\n\t\t\t\t\treturn titleValue || __( '(no title)' );\n\t\t\t\t},\n\t\t\t},\n\t\t\taltTextField as Field< RestAttachment >,\n\t\t\tcaptionField as Field< RestAttachment >,\n\t\t\tdescriptionField as Field< RestAttachment >,\n\t\t\tdateAddedField as Field< RestAttachment >,\n\t\t\tdateModifiedField as Field< RestAttachment >,\n\t\t\tauthorField as Field< RestAttachment >,\n\t\t\tfilenameField as Field< RestAttachment >,\n\t\t\tfilesizeField as Field< RestAttachment >,\n\t\t\tmediaDimensionsField as Field< RestAttachment >,\n\t\t\tmimeTypeField as Field< RestAttachment >,\n\t\t\tattachedToField as Field< RestAttachment >,\n\t\t],\n\t\t[]\n\t);\n\n\tconst actions: ActionButton< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: __( 'Select' ),\n\t\t\t\tisPrimary: true,\n\t\t\t\tsupportsBulk: multiple,\n\t\t\t\tasync callback() {\n\t\t\t\t\tif ( selection.length === 0 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst selectedPostsQuery = {\n\t\t\t\t\t\tinclude: selection,\n\t\t\t\t\t\tper_page: -1,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst selectedPosts = await resolveSelect(\n\t\t\t\t\t\tcoreStore\n\t\t\t\t\t).getEntityRecords< RestAttachment >(\n\t\t\t\t\t\t'postType',\n\t\t\t\t\t\t'attachment',\n\t\t\t\t\t\tselectedPostsQuery\n\t\t\t\t\t);\n\n\t\t\t\t\t// Transform the selected posts to the expected Attachment format\n\t\t\t\t\tconst transformedPosts = ( selectedPosts ?? [] )\n\t\t\t\t\t\t.map( transformAttachment )\n\t\t\t\t\t\t.filter( Boolean );\n\n\t\t\t\t\tconst selectedItems = multiple\n\t\t\t\t\t\t? transformedPosts\n\t\t\t\t\t\t: transformedPosts?.[ 0 ];\n\n\t\t\t\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\t\t\t\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection, removeAllNotices ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\tonClose?.();\n\t}, [ removeAllNotices, onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\t// Show success notice and auto-clear completed entries when all batches finish.\n\tconst prevAllCompleteRef = useRef( false );\n\tuseEffect( () => {\n\t\tif ( allComplete && ! prevAllCompleteRef.current ) {\n\t\t\tconst completeCount = uploadingFiles.filter(\n\t\t\t\t( file ) => file.status === 'uploaded'\n\t\t\t).length;\n\t\t\tif ( completeCount > 0 ) {\n\t\t\t\tcreateSuccessNotice(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t// translators: %s: number of files\n\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t'Uploaded %s file',\n\t\t\t\t\t\t\t'Uploaded %s files',\n\t\t\t\t\t\t\tcompleteCount\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcompleteCount.toLocaleString()\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Auto-clear completed entries, unless the popover is\n\t\t\t// open \u2014 in that case, they'll be cleared on close.\n\t\t\tif ( ! isPopoverOpenRef.current ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t}\n\t\tprevAllCompleteRef.current = allComplete;\n\t}, [ allComplete, uploadingFiles, createSuccessNotice, clearCompleted ] );\n\n\tconst handleFileSelect = useCallback(\n\t\t( event: React.ChangeEvent< HTMLInputElement > ) => {\n\t\t\tconst files = event.target.files;\n\t\t\tif ( files && files.length > 0 ) {\n\t\t\t\tconst filesArray = Array.from( files );\n\t\t\t\tconst { onFileChange, onError } = registerBatch( filesArray );\n\n\t\t\t\thandleUpload( {\n\t\t\t\t\tallowedTypes,\n\t\t\t\t\tfilesList: filesArray,\n\t\t\t\t\tonFileChange,\n\t\t\t\t\tonError,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ allowedTypes, handleUpload, registerBatch ]\n\t);\n\n\tconst paginationInfo = useMemo(\n\t\t() => ( {\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t} ),\n\t\t[ totalItems, totalPages ]\n\t);\n\n\t// Build accept attribute from allowedTypes\n\tconst acceptTypes = useMemo( () => {\n\t\tif ( allowedTypes?.includes( '*' ) ) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn allowedTypes?.join( ',' );\n\t}, [ allowedTypes ] );\n\n\tif ( ! isOpen ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ title }\n\t\t\tonRequestClose={ handleModalClose }\n\t\t\tisDismissible={ isDismissible }\n\t\t\tclassName={ modalClass }\n\t\t\toverlayClassName=\"media-upload-modal\"\n\t\t\tsize=\"fill\"\n\t\t\theaderActions={\n\t\t\t\t<FormFileUpload\n\t\t\t\t\taccept={ acceptTypes }\n\t\t\t\t\tmultiple\n\t\t\t\t\tonChange={ handleFileSelect }\n\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\trender={ ( { openFileDialog } ) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tonClick={ openFileDialog }\n\t\t\t\t\t\t\ticon={ uploadIcon }\n\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Upload media' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) }\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t<DropZone\n\t\t\t\tonFilesDrop={ ( files ) => {\n\t\t\t\t\tlet filteredFiles = files;\n\t\t\t\t\t// Filter files by allowed types if specified\n\t\t\t\t\tif ( allowedTypes && ! allowedTypes.includes( '*' ) ) {\n\t\t\t\t\t\tfilteredFiles = files.filter( ( file ) =>\n\t\t\t\t\t\t\tallowedTypes.some( ( allowedType ) => {\n\t\t\t\t\t\t\t\t// Check if the file type matches the allowed MIME type\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tfile.type === allowedType ||\n\t\t\t\t\t\t\t\t\tfile.type.startsWith(\n\t\t\t\t\t\t\t\t\t\tallowedType.replace( '*', '' )\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( filteredFiles.length > 0 ) {\n\t\t\t\t\t\tconst { onFileChange, onError } =\n\t\t\t\t\t\t\tregisterBatch( filteredFiles );\n\n\t\t\t\t\t\thandleUpload( {\n\t\t\t\t\t\t\tallowedTypes,\n\t\t\t\t\t\t\tfilesList: filteredFiles,\n\t\t\t\t\t\t\tonFileChange,\n\t\t\t\t\t\t\tonError,\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tlabel={ __( 'Drop files to upload' ) }\n\t\t\t/>\n\t\t\t<DataViewsPicker\n\t\t\t\tdata={ mediaRecords || [] }\n\t\t\t\tfields={ fields }\n\t\t\t\tview={ view }\n\t\t\t\tonChangeView={ updateView }\n\t\t\t\tactions={ actions }\n\t\t\t\tselection={ selection }\n\t\t\t\tonChangeSelection={ setSelection }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tpaginationInfo={ paginationInfo }\n\t\t\t\tdefaultLayouts={ defaultLayouts }\n\t\t\t\tgetItemId={ ( item: RestAttachment ) => String( item.id ) }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t\tonReset={ isModified ? resetToDefault : false }\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talign=\"top\"\n\t\t\t\t\tjustify=\"space-between\"\n\t\t\t\t\tclassName=\"dataviews__view-actions\"\n\t\t\t\t\tgap=\"xs\"\n\t\t\t\t>\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\tgap=\"sm\"\n\t\t\t\t\t\tjustify=\"start\"\n\t\t\t\t\t\tclassName=\"dataviews__search\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{ search && (\n\t\t\t\t\t\t\t<DataViewsPicker.Search label={ searchLabel } />\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<DataViewsPicker.FiltersToggle />\n\t\t\t\t\t</Stack>\n\t\t\t\t\t<Stack direction=\"row\" gap=\"xs\" style={ { flexShrink: 0 } }>\n\t\t\t\t\t\t<DataViewsPicker.LayoutSwitcher />\n\t\t\t\t\t\t<DataViewsPicker.ViewConfig />\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t\t<DataViewsPicker.FiltersToggled className=\"dataviews-filters__container\" />\n\t\t\t\t<DataViewsPicker.Layout />\n\t\t\t\t<div\n\t\t\t\t\tclassName={ clsx( 'media-upload-modal__footer', {\n\t\t\t\t\t\t'is-uploading': uploadingFiles.length > 0,\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t<UploadStatusPopover\n\t\t\t\t\t\tuploadingFiles={ uploadingFiles }\n\t\t\t\t\t\tonDismissError={ dismissError }\n\t\t\t\t\t\tonOpenChange={ handlePopoverOpenChange }\n\t\t\t\t\t/>\n\t\t\t\t\t<DataViewsPicker.BulkActionToolbar />\n\t\t\t\t</div>\n\t\t\t</DataViewsPicker>\n\t\t\t{ createPortal(\n\t\t\t\t<SnackbarNotices\n\t\t\t\t\tclassName=\"media-upload-modal__snackbar\"\n\t\t\t\t\tcontext={ NOTICES_CONTEXT }\n\t\t\t\t/>,\n\t\t\t\tdocument.body\n\t\t\t) }\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
|
|
5
|
-
"mappings": ";AAGA,OAAO,UAAU;AAKjB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,IAAI,SAAS,UAAU;AAChC;AAAA,EACC,eAAe;AAAA,EACf,SAAS;AAAA,OACH;AACP,SAAS,eAAe,mBAAmB;AAC3C,SAAS,OAAO,UAAU,gBAAgB,cAAc;AACxD,SAAS,UAAU,kBAAkB;AACrC,SAAS,uBAAuB;AAOhC,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,SAAS,cAAc,uBAAuB;AAMvD,SAAS,2BAA2B;AACpC,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AACvB,SAAS,2BAA2B;AACpC,SAAS,0CAA0C;AACnD,SAAS,uBAAuB;
|
|
4
|
+
"sourcesContent": ["/**\n * External dependencies\n */\nimport clsx from 'clsx';\n\n/**\n * WordPress dependencies\n */\nimport {\n\tcreatePortal,\n\tuseState,\n\tuseCallback,\n\tuseMemo,\n\tuseRef,\n\tuseEffect,\n} from '@wordpress/element';\nimport { __, sprintf, _n } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect, useDispatch } from '@wordpress/data';\nimport { Modal, DropZone, FormFileUpload, Button } from '@wordpress/components';\nimport { upload as uploadIcon } from '@wordpress/icons';\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type {\n\tField,\n\tActionButton,\n\tSupportedLayouts,\n\tView,\n} from '@wordpress/dataviews';\nimport { useView } from '@wordpress/views';\nimport { Stack } from '@wordpress/ui';\nimport {\n\taltTextField,\n\tattachedToField,\n\tauthorField,\n\tcaptionField,\n\tdateAddedField,\n\tdateModifiedField,\n\tdescriptionField,\n\tfilenameField,\n\tfilesizeField,\n\tmediaDimensionsField,\n\tmediaThumbnailField,\n\tmimeTypeField,\n} from '@wordpress/media-fields';\nimport { store as noticesStore, SnackbarNotices } from '@wordpress/notices';\n\n/**\n * Internal dependencies\n */\nimport type { Attachment, RestAttachment } from '../../utils/types';\nimport { transformAttachment } from '../../utils/transform-attachment';\nimport { uploadMedia } from '../../utils/upload-media';\nimport { unlock } from '../../lock-unlock';\nimport { UploadStatusPopover } from './upload-status-popover';\nimport { useInvalidateAttachmentResolutions } from './use-invalidate-attachment-resolutions';\nimport { useUploadStatus } from './use-upload-status';\n\nconst { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );\n\n// Layout constants - matching the picker layout types\nconst LAYOUT_PICKER_GRID = 'pickerGrid';\nconst LAYOUT_PICKER_TABLE = 'pickerTable';\n\n// Custom notices context for the media modal\nconst NOTICES_CONTEXT = 'media-modal';\n\n// Notice ID - reused for all upload-related notices to prevent flooding\nconst NOTICE_ID_UPLOAD_PROGRESS = 'media-modal-upload-progress';\n\nconst defaultView: View = {\n\ttype: LAYOUT_PICKER_GRID,\n\tfields: [],\n\tshowTitle: false,\n\ttitleField: 'title',\n\tmediaField: 'media_thumbnail',\n\tsearch: '',\n\tpage: 1,\n\tperPage: 50,\n\tfilters: [],\n\tlayout: {\n\t\tpreviewSize: 170,\n\t\tdensity: 'compact',\n\t},\n};\n\nconst defaultLayouts: SupportedLayouts = {\n\t[ LAYOUT_PICKER_GRID ]: {\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\tlayout: {\n\t\t\tpreviewSize: 170,\n\t\t\tdensity: 'compact',\n\t\t},\n\t},\n\t[ LAYOUT_PICKER_TABLE ]: {\n\t\tfields: [\n\t\t\t'filename',\n\t\t\t'filesize',\n\t\t\t'media_dimensions',\n\t\t\t'author',\n\t\t\t'date',\n\t\t],\n\t\tshowTitle: true,\n\t},\n};\n\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t */\n\tallowedTypes?: string[];\n\n\t/**\n\t * Whether multiple files can be selected.\n\t * @default false\n\t */\n\tmultiple?: boolean;\n\n\t/**\n\t * The currently selected media item(s).\n\t * Can be a single ID number or array of IDs for multiple selection.\n\t */\n\tvalue?: number | number[];\n\n\t/**\n\t * Function called when media is selected.\n\t * Receives single attachment object or array of attachments.\n\t */\n\tonSelect: ( media: Attachment | Attachment[] ) => void;\n\n\t/**\n\t * Function called when the modal is closed without selection.\n\t */\n\tonClose?: () => void;\n\n\t/**\n\t * Function to handle media uploads.\n\t * If not provided, drag and drop will be disabled.\n\t */\n\tonUpload?: ( args: {\n\t\tallowedTypes?: string[];\n\t\tfilesList: File[];\n\t\tonFileChange?: ( attachments: Partial< Attachment >[] ) => void;\n\t\tonError?: ( error: Error ) => void;\n\t\tmultiple?: boolean;\n\t} ) => void;\n\n\t/**\n\t * Title for the modal.\n\t * @default 'Select Media'\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Whether the modal is open.\n\t */\n\tisOpen: boolean;\n\n\t/**\n\t * Whether the modal can be closed by clicking outside or pressing escape.\n\t * @default true\n\t */\n\tisDismissible?: boolean;\n\n\t/**\n\t * Additional CSS class for the modal.\n\t */\n\tmodalClass?: string;\n\n\t/**\n\t * Whether to show a search input.\n\t * @default true\n\t */\n\tsearch?: boolean;\n\n\t/**\n\t * Label for the search input.\n\t */\n\tsearchLabel?: string;\n}\n\n/**\n * MediaUploadModal component that uses Modal and DataViewsPicker for media selection.\n *\n * This is a modern functional component alternative to the legacy MediaUpload class component.\n * It provides a cleaner API and better integration with the WordPress block editor.\n *\n * @param props Component props\n * @param props.allowedTypes Array of allowed media types\n * @param props.multiple Whether multiple files can be selected\n * @param props.value Currently selected media item(s)\n * @param props.onSelect Function called when media is selected\n * @param props.onClose Function called when modal is closed\n * @param props.onUpload Function to handle media uploads\n * @param props.title Title for the modal\n * @param props.isOpen Whether the modal is open\n * @param props.isDismissible Whether modal can be dismissed\n * @param props.modalClass Additional CSS class for modal\n * @param props.search Whether to show search input\n * @param props.searchLabel Label for search input\n * @return JSX element or null\n */\nexport function MediaUploadModal( {\n\tallowedTypes,\n\tmultiple = false,\n\tvalue,\n\tonSelect,\n\tonClose,\n\tonUpload,\n\ttitle = __( 'Select Media' ),\n\tisOpen,\n\tisDismissible = true,\n\tmodalClass,\n\tsearch = true,\n\tsearchLabel = __( 'Search media' ),\n}: MediaUploadModalProps ) {\n\tconst [ selection, setSelection ] = useState< string[] >( () => {\n\t\tif ( ! value ) {\n\t\t\treturn [];\n\t\t}\n\t\treturn Array.isArray( value )\n\t\t\t? value.map( String )\n\t\t\t: [ String( value ) ];\n\t} );\n\n\tconst { createSuccessNotice, removeAllNotices } =\n\t\tuseDispatch( noticesStore );\n\tconst invalidateAttachmentResolutions =\n\t\tuseInvalidateAttachmentResolutions();\n\n\t// Persist view configuration across sessions via the preferences store.\n\tconst { view, updateView, isModified, resetToDefault } = useView( {\n\t\tkind: 'postType',\n\t\tname: 'attachment',\n\t\tslug: 'media-modal',\n\t\tdefaultView,\n\t} );\n\n\t// Build query args based on view properties, similar to PostList\n\tconst queryArgs = useMemo( () => {\n\t\tconst filters: Record< string, any > = {};\n\n\t\tview.filters?.forEach( ( filter ) => {\n\t\t\t// Handle media type filters\n\t\t\tif ( filter.field === 'media_type' ) {\n\t\t\t\tfilters.media_type = filter.value;\n\t\t\t}\n\t\t\t// Handle author filters\n\t\t\tif ( filter.field === 'author' ) {\n\t\t\t\tif ( filter.operator === 'isAny' ) {\n\t\t\t\t\tfilters.author = filter.value;\n\t\t\t\t} else if ( filter.operator === 'isNone' ) {\n\t\t\t\t\tfilters.author_exclude = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle date filters\n\t\t\tif ( filter.field === 'date' || filter.field === 'modified' ) {\n\t\t\t\tif ( filter.operator === 'before' ) {\n\t\t\t\t\tfilters.before = filter.value;\n\t\t\t\t} else if ( filter.operator === 'after' ) {\n\t\t\t\t\tfilters.after = filter.value;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Handle mime type filters\n\t\t\tif ( filter.field === 'mime_type' ) {\n\t\t\t\tfilters.mime_type = filter.value;\n\t\t\t}\n\t\t} );\n\n\t\t// Base media and mime type on allowedTypes if no filter is set\n\t\tif (\n\t\t\t! filters.media_type &&\n\t\t\t! filters.mime_type &&\n\t\t\tallowedTypes &&\n\t\t\t! allowedTypes.includes( '*' )\n\t\t) {\n\t\t\tconst { mediaTypes, mimeTypes } = allowedTypes.reduce(\n\t\t\t\t( acc, type ) => {\n\t\t\t\t\tif ( type.endsWith( '/*' ) ) {\n\t\t\t\t\t\tacc.mediaTypes.push( type.replace( '/*', '' ) );\n\t\t\t\t\t} else if ( type.includes( '/' ) ) {\n\t\t\t\t\t\tacc.mimeTypes.push( type );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tacc.mediaTypes.push( type );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{ mediaTypes: [] as string[], mimeTypes: [] as string[] }\n\t\t\t);\n\n\t\t\tif ( mediaTypes.length ) {\n\t\t\t\tfilters.media_type = mediaTypes;\n\t\t\t}\n\t\t\tif ( mimeTypes.length ) {\n\t\t\t\tfilters.mime_type = mimeTypes;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tper_page: view.perPage || 20,\n\t\t\tpage: view.page || 1,\n\t\t\tstatus: 'inherit',\n\t\t\torder: view.sort?.direction,\n\t\t\torderby: view.sort?.field,\n\t\t\tsearch: view.search,\n\t\t\t_embed: 'author,wp:attached-to',\n\t\t\t...filters,\n\t\t};\n\t}, [ view, allowedTypes ] );\n\n\t// Per-batch completion handler: auto-select uploaded items and refresh the grid.\n\tconst handleBatchComplete = useCallback(\n\t\t( attachments: Partial< Attachment >[] ) => {\n\t\t\tconst uploadedIds = attachments\n\t\t\t\t.map( ( attachment ) => String( attachment.id ) )\n\t\t\t\t.filter( Boolean );\n\n\t\t\tif ( multiple ) {\n\t\t\t\tsetSelection( ( prev ) => {\n\t\t\t\t\tconst existing = new Set( prev );\n\t\t\t\t\tconst newIds = uploadedIds.filter(\n\t\t\t\t\t\t( id ) => ! existing.has( id )\n\t\t\t\t\t);\n\t\t\t\t\treturn [ ...prev, ...newIds ];\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tsetSelection( uploadedIds.slice( 0, 1 ) );\n\t\t\t}\n\n\t\t\t// Invalidate all cached attachment queries so every page of\n\t\t\t// results refreshes \u2014 not just the page the user is viewing.\n\t\t\tinvalidateAttachmentResolutions();\n\t\t},\n\t\t[ multiple, invalidateAttachmentResolutions ]\n\t);\n\n\tconst {\n\t\tuploadingFiles,\n\t\tregisterBatch,\n\t\tdismissError,\n\t\tclearCompleted,\n\t\tallComplete,\n\t} = useUploadStatus( { onBatchComplete: handleBatchComplete } );\n\n\tconst isPopoverOpenRef = useRef( false );\n\tconst handlePopoverOpenChange = useCallback(\n\t\t( open: boolean ) => {\n\t\t\tisPopoverOpenRef.current = open;\n\t\t\tif ( ! open ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t},\n\t\t[ clearCompleted ]\n\t);\n\n\t// Fetch all media attachments using WordPress core data with permissions\n\tconst {\n\t\trecords: mediaRecords,\n\t\tisResolving: isLoading,\n\t\ttotalItems,\n\t\ttotalPages,\n\t} = useEntityRecordsWithPermissions( 'postType', 'attachment', queryArgs );\n\n\tconst fields: Field< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t// Media field definitions from @wordpress/media-fields\n\t\t\t// Cast is safe because RestAttachment has the same properties as Attachment\n\t\t\t{\n\t\t\t\t...( mediaThumbnailField as Field< RestAttachment > ),\n\t\t\t\tenableHiding: false, // Within the modal, the thumbnail should always be shown.\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'title',\n\t\t\t\ttype: 'text' as const,\n\t\t\t\tlabel: __( 'Title' ),\n\t\t\t\tgetValue: ( { item }: { item: RestAttachment } ) => {\n\t\t\t\t\tconst titleValue = item.title.raw || item.title.rendered;\n\t\t\t\t\treturn titleValue || __( '(no title)' );\n\t\t\t\t},\n\t\t\t},\n\t\t\taltTextField as Field< RestAttachment >,\n\t\t\tcaptionField as Field< RestAttachment >,\n\t\t\tdescriptionField as Field< RestAttachment >,\n\t\t\tdateAddedField as Field< RestAttachment >,\n\t\t\tdateModifiedField as Field< RestAttachment >,\n\t\t\tauthorField as Field< RestAttachment >,\n\t\t\tfilenameField as Field< RestAttachment >,\n\t\t\tfilesizeField as Field< RestAttachment >,\n\t\t\tmediaDimensionsField as Field< RestAttachment >,\n\t\t\tmimeTypeField as Field< RestAttachment >,\n\t\t\tattachedToField as Field< RestAttachment >,\n\t\t],\n\t\t[]\n\t);\n\n\tconst actions: ActionButton< RestAttachment >[] = useMemo(\n\t\t() => [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: __( 'Select' ),\n\t\t\t\tisPrimary: true,\n\t\t\t\tsupportsBulk: multiple,\n\t\t\t\tasync callback() {\n\t\t\t\t\tif ( selection.length === 0 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst selectedPostsQuery = {\n\t\t\t\t\t\tinclude: selection,\n\t\t\t\t\t\tper_page: -1,\n\t\t\t\t\t};\n\n\t\t\t\t\tconst selectedPosts = await resolveSelect(\n\t\t\t\t\t\tcoreStore\n\t\t\t\t\t).getEntityRecords< RestAttachment >(\n\t\t\t\t\t\t'postType',\n\t\t\t\t\t\t'attachment',\n\t\t\t\t\t\tselectedPostsQuery\n\t\t\t\t\t);\n\n\t\t\t\t\t// Transform the selected posts to the expected Attachment format\n\t\t\t\t\tconst transformedPosts = ( selectedPosts ?? [] )\n\t\t\t\t\t\t.map( transformAttachment )\n\t\t\t\t\t\t.filter( Boolean );\n\n\t\t\t\t\tconst selectedItems = multiple\n\t\t\t\t\t\t? transformedPosts\n\t\t\t\t\t\t: transformedPosts?.[ 0 ];\n\n\t\t\t\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\t\t\t\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection, removeAllNotices ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tremoveAllNotices( 'snackbar', NOTICES_CONTEXT );\n\t\tonClose?.();\n\t}, [ removeAllNotices, onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\t// Show success notice and auto-clear completed entries when all batches finish.\n\tconst prevAllCompleteRef = useRef( false );\n\tuseEffect( () => {\n\t\tif ( allComplete && ! prevAllCompleteRef.current ) {\n\t\t\tconst completeCount = uploadingFiles.filter(\n\t\t\t\t( file ) => file.status === 'uploaded'\n\t\t\t).length;\n\t\t\tif ( completeCount > 0 ) {\n\t\t\t\tcreateSuccessNotice(\n\t\t\t\t\tsprintf(\n\t\t\t\t\t\t// translators: %s: number of files\n\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t'Uploaded %s file',\n\t\t\t\t\t\t\t'Uploaded %s files',\n\t\t\t\t\t\t\tcompleteCount\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcompleteCount.toLocaleString()\n\t\t\t\t\t),\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Auto-clear completed entries, unless the popover is\n\t\t\t// open \u2014 in that case, they'll be cleared on close.\n\t\t\tif ( ! isPopoverOpenRef.current ) {\n\t\t\t\tclearCompleted();\n\t\t\t}\n\t\t}\n\t\tprevAllCompleteRef.current = allComplete;\n\t}, [ allComplete, uploadingFiles, createSuccessNotice, clearCompleted ] );\n\n\tconst handleFileSelect = useCallback(\n\t\t( event: React.ChangeEvent< HTMLInputElement > ) => {\n\t\t\tconst files = event.target.files;\n\t\t\tif ( files && files.length > 0 ) {\n\t\t\t\tconst filesArray = Array.from( files );\n\t\t\t\tconst { onFileChange, onError } = registerBatch( filesArray );\n\n\t\t\t\thandleUpload( {\n\t\t\t\t\tallowedTypes,\n\t\t\t\t\tfilesList: filesArray,\n\t\t\t\t\tonFileChange,\n\t\t\t\t\tonError,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ allowedTypes, handleUpload, registerBatch ]\n\t);\n\n\tconst paginationInfo = useMemo(\n\t\t() => ( {\n\t\t\ttotalItems,\n\t\t\ttotalPages,\n\t\t} ),\n\t\t[ totalItems, totalPages ]\n\t);\n\n\t// Build accept attribute from allowedTypes\n\tconst acceptTypes = useMemo( () => {\n\t\tif ( allowedTypes?.includes( '*' ) ) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn allowedTypes?.join( ',' );\n\t}, [ allowedTypes ] );\n\n\tif ( ! isOpen ) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<Modal\n\t\t\ttitle={ title }\n\t\t\tonRequestClose={ handleModalClose }\n\t\t\tisDismissible={ isDismissible }\n\t\t\tclassName={ modalClass }\n\t\t\toverlayClassName=\"media-upload-modal\"\n\t\t\tsize=\"fill\"\n\t\t\theaderActions={\n\t\t\t\t<FormFileUpload\n\t\t\t\t\taccept={ acceptTypes }\n\t\t\t\t\tmultiple\n\t\t\t\t\tonChange={ handleFileSelect }\n\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\trender={ ( { openFileDialog } ) => (\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tonClick={ openFileDialog }\n\t\t\t\t\t\t\ticon={ uploadIcon }\n\t\t\t\t\t\t\t__next40pxDefaultSize\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{ __( 'Upload media' ) }\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t) }\n\t\t\t\t/>\n\t\t\t}\n\t\t>\n\t\t\t<DropZone\n\t\t\t\tonFilesDrop={ ( files ) => {\n\t\t\t\t\tlet filteredFiles = files;\n\t\t\t\t\t// Filter files by allowed types if specified\n\t\t\t\t\tif ( allowedTypes && ! allowedTypes.includes( '*' ) ) {\n\t\t\t\t\t\tfilteredFiles = files.filter( ( file ) =>\n\t\t\t\t\t\t\tallowedTypes.some( ( allowedType ) => {\n\t\t\t\t\t\t\t\t// Check if the file type matches the allowed MIME type\n\t\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t\tfile.type === allowedType ||\n\t\t\t\t\t\t\t\t\tfile.type.startsWith(\n\t\t\t\t\t\t\t\t\t\tallowedType.replace( '*', '' )\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( filteredFiles.length > 0 ) {\n\t\t\t\t\t\tconst { onFileChange, onError } =\n\t\t\t\t\t\t\tregisterBatch( filteredFiles );\n\n\t\t\t\t\t\thandleUpload( {\n\t\t\t\t\t\t\tallowedTypes,\n\t\t\t\t\t\t\tfilesList: filteredFiles,\n\t\t\t\t\t\t\tonFileChange,\n\t\t\t\t\t\t\tonError,\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} }\n\t\t\t\tlabel={ __( 'Drop files to upload' ) }\n\t\t\t/>\n\t\t\t<DataViewsPicker\n\t\t\t\tdata={ mediaRecords || [] }\n\t\t\t\tfields={ fields }\n\t\t\t\tview={ view }\n\t\t\t\tonChangeView={ updateView }\n\t\t\t\tactions={ actions }\n\t\t\t\tselection={ selection }\n\t\t\t\tonChangeSelection={ setSelection }\n\t\t\t\tisLoading={ isLoading }\n\t\t\t\tpaginationInfo={ paginationInfo }\n\t\t\t\tdefaultLayouts={ defaultLayouts }\n\t\t\t\tgetItemId={ ( item: RestAttachment ) => String( item.id ) }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t\tonReset={ isModified ? resetToDefault : false }\n\t\t\t>\n\t\t\t\t<Stack\n\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\talign=\"top\"\n\t\t\t\t\tjustify=\"space-between\"\n\t\t\t\t\tclassName=\"dataviews__view-actions\"\n\t\t\t\t\tgap=\"xs\"\n\t\t\t\t>\n\t\t\t\t\t<Stack\n\t\t\t\t\t\tdirection=\"row\"\n\t\t\t\t\t\tgap=\"sm\"\n\t\t\t\t\t\tjustify=\"start\"\n\t\t\t\t\t\tclassName=\"dataviews__search\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{ search && (\n\t\t\t\t\t\t\t<DataViewsPicker.Search label={ searchLabel } />\n\t\t\t\t\t\t) }\n\t\t\t\t\t\t<DataViewsPicker.FiltersToggle />\n\t\t\t\t\t</Stack>\n\t\t\t\t\t<Stack direction=\"row\" gap=\"xs\" style={ { flexShrink: 0 } }>\n\t\t\t\t\t\t<DataViewsPicker.LayoutSwitcher />\n\t\t\t\t\t\t<DataViewsPicker.ViewConfig />\n\t\t\t\t\t</Stack>\n\t\t\t\t</Stack>\n\t\t\t\t<DataViewsPicker.FiltersToggled className=\"dataviews-filters__container\" />\n\t\t\t\t<DataViewsPicker.Layout />\n\t\t\t\t<div\n\t\t\t\t\tclassName={ clsx( 'media-upload-modal__footer', {\n\t\t\t\t\t\t'is-uploading': uploadingFiles.length > 0,\n\t\t\t\t\t} ) }\n\t\t\t\t>\n\t\t\t\t\t<UploadStatusPopover\n\t\t\t\t\t\tuploadingFiles={ uploadingFiles }\n\t\t\t\t\t\tonDismissError={ dismissError }\n\t\t\t\t\t\tonOpenChange={ handlePopoverOpenChange }\n\t\t\t\t\t/>\n\t\t\t\t\t<DataViewsPicker.BulkActionToolbar />\n\t\t\t\t</div>\n\t\t\t</DataViewsPicker>\n\t\t\t{ createPortal(\n\t\t\t\t<SnackbarNotices\n\t\t\t\t\tclassName=\"media-upload-modal__snackbar\"\n\t\t\t\t\tcontext={ NOTICES_CONTEXT }\n\t\t\t\t/>,\n\t\t\t\tdocument.body\n\t\t\t) }\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from './components';\n\nexport { uploadMedia } from './utils/upload-media';\nexport { transformAttachment } from './utils/transform-attachment';\nexport { validateFileSize } from './utils/validate-file-size';\nexport { validateMimeType } from './utils/validate-mime-type';\nexport { validateMimeTypeForUser } from './utils/validate-mime-type-for-user';\n\nexport type { Attachment, RestAttachment } from './utils/types';\n\nexport { privateApis } from './private-apis';\n"],
|
|
4
|
+
"sourcesContent": ["export * from './components';\n\nexport { uploadMedia } from './utils/upload-media';\nexport { transformAttachment } from './utils/transform-attachment';\nexport { validateFileSize } from './utils/validate-file-size';\nexport { validateMimeType } from './utils/validate-mime-type';\nexport { validateMimeTypeForUser } from './utils/validate-mime-type-for-user';\n\nexport type { Attachment, RestAttachment, SubSizeData } from './utils/types';\n\nexport { privateApis } from './private-apis';\n"],
|
|
5
5
|
"mappings": ";AAAA,cAAc;AAEd,SAAS,mBAAmB;AAC5B,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AACjC,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AAIxC,SAAS,mBAAmB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -9,17 +9,17 @@ async function sideloadMedia({
|
|
|
9
9
|
attachmentId,
|
|
10
10
|
additionalData = {},
|
|
11
11
|
signal,
|
|
12
|
-
|
|
12
|
+
onSuccess,
|
|
13
13
|
onError = noop
|
|
14
14
|
}) {
|
|
15
15
|
try {
|
|
16
|
-
const
|
|
16
|
+
const subSizeData = await sideloadToServer(
|
|
17
17
|
file,
|
|
18
18
|
attachmentId,
|
|
19
19
|
additionalData,
|
|
20
20
|
signal
|
|
21
21
|
);
|
|
22
|
-
|
|
22
|
+
onSuccess?.(subSizeData);
|
|
23
23
|
} catch (error) {
|
|
24
24
|
let message;
|
|
25
25
|
if (error instanceof Error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/sideload-media.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport type {\n\
|
|
5
|
-
"mappings": ";AAGA,SAAS,IAAI,eAAe;AAW5B,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAE5B,IAAM,OAAO,MAAM;AAAC;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tOnErrorHandler,\n\tCreateSideloadFile,\n\tRestAttachment,\n\tSubSizeData,\n} from './types';\nimport { sideloadToServer } from './sideload-to-server';\nimport { UploadError } from './upload-error';\n\nconst noop = () => {};\n\ntype OnSubSizeHandler = ( subSize: SubSizeData ) => void;\n\ninterface SideloadMediaArgs {\n\t// Additional data to include in the request.\n\tadditionalData?: CreateSideloadFile;\n\t// File to sideload.\n\tfile: File;\n\t// Attachment ID.\n\tattachmentId: RestAttachment[ 'id' ];\n\t// Function called when an error happens.\n\tonError?: OnErrorHandler;\n\t// Function called when the sideload completes with sub-size data.\n\tonSuccess?: OnSubSizeHandler;\n\t// Abort signal.\n\tsignal?: AbortSignal;\n}\n\n/**\n * Uploads a file to the server without creating an attachment.\n *\n * Returns sub-size data instead of a full attachment. The client\n * accumulates this data and sends it to the finalize endpoint.\n *\n * @param $0 Parameters object passed to the function.\n * @param $0.file Media File to Save.\n * @param $0.attachmentId Parent attachment ID.\n * @param $0.additionalData Additional data to include in the request.\n * @param $0.signal Abort signal.\n * @param $0.onSuccess Function called when the sideload completes with sub-size data.\n * @param $0.onError Function called when an error happens.\n */\nexport async function sideloadMedia( {\n\tfile,\n\tattachmentId,\n\tadditionalData = {},\n\tsignal,\n\tonSuccess,\n\tonError = noop,\n}: SideloadMediaArgs ) {\n\ttry {\n\t\tconst subSizeData = await sideloadToServer(\n\t\t\tfile,\n\t\t\tattachmentId,\n\t\t\tadditionalData,\n\t\t\tsignal\n\t\t);\n\t\tonSuccess?.( subSizeData );\n\t} catch ( error ) {\n\t\tlet message;\n\t\tif ( error instanceof Error ) {\n\t\t\tmessage = error.message;\n\t\t} else {\n\t\t\tmessage = sprintf(\n\t\t\t\t// translators: %s: file name\n\t\t\t\t__( 'Error while sideloading file %s to the server.' ),\n\t\t\t\tfile.name\n\t\t\t);\n\t\t}\n\t\tonError(\n\t\t\tnew UploadError( {\n\t\t\t\tcode: 'GENERAL',\n\t\t\t\tmessage,\n\t\t\t\tfile,\n\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t} )\n\t\t);\n\t}\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,IAAI,eAAe;AAW5B,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAE5B,IAAM,OAAO,MAAM;AAAC;AAiCpB,eAAsB,cAAe;AAAA,EACpC;AAAA,EACA;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA,UAAU;AACX,GAAuB;AACtB,MAAI;AACH,UAAM,cAAc,MAAM;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AACA,gBAAa,WAAY;AAAA,EAC1B,SAAU,OAAQ;AACjB,QAAI;AACJ,QAAK,iBAAiB,OAAQ;AAC7B,gBAAU,MAAM;AAAA,IACjB,OAAO;AACN,gBAAU;AAAA;AAAA,QAET,GAAI,gDAAiD;AAAA,QACrD,KAAK;AAAA,MACN;AAAA,IACD;AACA;AAAA,MACC,IAAI,YAAa;AAAA,QAChB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,MACzC,CAAE;AAAA,IACH;AAAA,EACD;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// packages/media-utils/src/utils/sideload-to-server.ts
|
|
2
2
|
import apiFetch from "@wordpress/api-fetch";
|
|
3
3
|
import { flattenFormData } from "./flatten-form-data.mjs";
|
|
4
|
-
import { transformAttachment } from "./transform-attachment.mjs";
|
|
5
4
|
async function sideloadToServer(file, attachmentId, additionalData = {}, signal) {
|
|
6
5
|
const data = new FormData();
|
|
7
6
|
data.append("file", file, file.name || file.type.replace("/", "."));
|
|
@@ -12,14 +11,12 @@ async function sideloadToServer(file, attachmentId, additionalData = {}, signal)
|
|
|
12
11
|
value
|
|
13
12
|
);
|
|
14
13
|
}
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
22
|
-
);
|
|
14
|
+
return apiFetch({
|
|
15
|
+
path: `/wp/v2/media/${attachmentId}/sideload`,
|
|
16
|
+
body: data,
|
|
17
|
+
method: "POST",
|
|
18
|
+
signal
|
|
19
|
+
});
|
|
23
20
|
}
|
|
24
21
|
export {
|
|
25
22
|
sideloadToServer
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/sideload-to-server.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport apiFetch from '@wordpress/api-fetch';\n\n/**\n * Internal dependencies\n */\nimport type { CreateSideloadFile, RestAttachment } from './types';\nimport { flattenFormData } from './flatten-form-data';\
|
|
5
|
-
"mappings": ";AAGA,OAAO,cAAc;AAMrB,SAAS,uBAAuB;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport apiFetch from '@wordpress/api-fetch';\n\n/**\n * Internal dependencies\n */\nimport type { CreateSideloadFile, RestAttachment, SubSizeData } from './types';\nimport { flattenFormData } from './flatten-form-data';\n\n/**\n * Uploads a file to the server without creating an attachment.\n *\n * Returns lightweight sub-size data instead of a full attachment.\n * The client accumulates these responses and sends them to the\n * finalize endpoint.\n *\n * @param file Media File to Save.\n * @param attachmentId Parent attachment ID.\n * @param additionalData Additional data to include in the request.\n * @param signal Abort signal.\n *\n * @return Sub-size data for the uploaded file.\n */\nexport async function sideloadToServer(\n\tfile: File,\n\tattachmentId: RestAttachment[ 'id' ],\n\tadditionalData: CreateSideloadFile = {},\n\tsignal?: AbortSignal\n): Promise< SubSizeData > {\n\t// Create upload payload.\n\tconst data = new FormData();\n\tdata.append( 'file', file, file.name || file.type.replace( '/', '.' ) );\n\tfor ( const [ key, value ] of Object.entries( additionalData ) ) {\n\t\tflattenFormData(\n\t\t\tdata,\n\t\t\tkey,\n\t\t\tvalue as string | Record< string, string > | undefined\n\t\t);\n\t}\n\n\treturn apiFetch< SubSizeData >( {\n\t\tpath: `/wp/v2/media/${ attachmentId }/sideload`,\n\t\tbody: data,\n\t\tmethod: 'POST',\n\t\tsignal,\n\t} );\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,OAAO,cAAc;AAMrB,SAAS,uBAAuB;AAgBhC,eAAsB,iBACrB,MACA,cACA,iBAAqC,CAAC,GACtC,QACyB;AAEzB,QAAM,OAAO,IAAI,SAAS;AAC1B,OAAK,OAAQ,QAAQ,MAAM,KAAK,QAAQ,KAAK,KAAK,QAAS,KAAK,GAAI,CAAE;AACtE,aAAY,CAAE,KAAK,KAAM,KAAK,OAAO,QAAS,cAAe,GAAI;AAChE;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAEA,SAAO,SAAyB;AAAA,IAC/B,MAAM,gBAAiB,YAAa;AAAA,IACpC,MAAM;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,EACD,CAAE;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/upload-media.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\nimport { createBlobURL, revokeBlobURL } from '@wordpress/blob';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tAdditionalData,\n\tAttachment,\n\tOnChangeHandler,\n\tOnErrorHandler,\n} from './types';\nimport { uploadToServer } from './upload-to-server';\nimport { validateMimeType } from './validate-mime-type';\nimport { validateMimeTypeForUser } from './validate-mime-type-for-user';\nimport { validateFileSize } from './validate-file-size';\nimport { UploadError } from './upload-error';\n\ndeclare global {\n\tinterface Window {\n\t\t__clientSideMediaProcessing?: boolean;\n\t}\n}\n\ninterface UploadMediaArgs {\n\t// Additional data to include in the request.\n\tadditionalData?: AdditionalData;\n\t// Array with the types of media that can be uploaded, if unset all types are allowed.\n\tallowedTypes?: string[];\n\t// List of files.\n\tfilesList: File[];\n\t// Maximum upload size in bytes allowed for the site.\n\tmaxUploadFileSize?: number;\n\t// Function called when an error happens.\n\tonError?: OnErrorHandler;\n\t// Function called each time a file or a temporary representation of the file is available.\n\tonFileChange?: OnChangeHandler;\n\t// List of allowed mime types and file extensions.\n\twpAllowedMimeTypes?: Record< string, string > | null;\n\t// Abort signal.\n\tsignal?: AbortSignal;\n\t// Whether to allow multiple files to be uploaded.\n\tmultiple?: boolean;\n}\n\n/**\n * Upload a media file when the file upload button is activated\n * or when adding a file to the editor via drag & drop.\n *\n * @param $0 Parameters object passed to the function.\n * @param $0.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.\n * @param $0.additionalData Additional data to include in the request.\n * @param $0.filesList List of files.\n * @param $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.\n * @param $0.onError Function called when an error happens.\n * @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.\n * @param $0.wpAllowedMimeTypes List of allowed mime types and file extensions.\n * @param $0.signal Abort signal.\n * @param $0.multiple Whether to allow multiple files to be uploaded.\n */\nexport function uploadMedia( {\n\twpAllowedMimeTypes,\n\tallowedTypes,\n\tadditionalData = {},\n\tfilesList,\n\tmaxUploadFileSize,\n\tonError,\n\tonFileChange,\n\tsignal,\n\tmultiple = true,\n}: UploadMediaArgs ) {\n\tif ( ! multiple && filesList.length > 1 ) {\n\t\tonError?.( new Error( __( 'Only one file can be used here.' ) ) );\n\t\treturn;\n\t}\n\n\tconst validFiles = [];\n\n\tconst filesSet: Array< Partial< Attachment > | null > = [];\n\tconst setAndUpdateFiles = ( index: number, value: Attachment | null ) => {\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\tif ( filesSet[ index ]?.url ) {\n\t\t\t\trevokeBlobURL( filesSet[ index ].url );\n\t\t\t}\n\t\t}\n\t\tfilesSet[ index ] = value;\n\t\tonFileChange?.(\n\t\t\tfilesSet.filter( ( attachment ) => attachment !== null )\n\t\t);\n\t};\n\n\tfor ( const mediaFile of filesList ) {\n\t\t// Verify if user is allowed to upload this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeTypeForUser( mediaFile, wpAllowedMimeTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if the caller (e.g. a block) supports this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeType( mediaFile, allowedTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Verify if file is greater than the maximum file upload size allowed for the site.\n\t\ttry {\n\t\t\tvalidateFileSize( mediaFile, maxUploadFileSize );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalidFiles.push( mediaFile );\n\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\t// Set temporary URL to create placeholder media file, this is replaced\n\t\t\t// with final file from media gallery when upload is `done` below.\n\t\t\tfilesSet.push( { url: createBlobURL( mediaFile ) } );\n\t\t\tonFileChange?.( filesSet as Array< Partial< Attachment > > );\n\t\t}\n\t}\n\n\tvalidFiles.map( async ( file, index ) => {\n\t\ttry {\n\t\t\tconst attachment = await uploadToServer(\n\t\t\t\tfile,\n\t\t\t\tadditionalData,\n\t\t\t\tsignal\n\t\t\t);\n\t\t\tsetAndUpdateFiles( index, attachment );\n\t\t} catch ( error ) {\n\t\t\t// Reset to empty on failure.\n\t\t\tsetAndUpdateFiles( index, null );\n\n\t\t\t// @wordpress/api-fetch throws any response that isn't in the 200 range as-is.\n\t\t\tlet message: string;\n\t\t\tif (\n\t\t\t\ttypeof error === 'object' &&\n\t\t\t\terror !== null &&\n\t\t\t\t'message' in error\n\t\t\t) {\n\t\t\t\tmessage =\n\t\t\t\t\ttypeof error.message === 'string'\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: String( error.message );\n\t\t\t} else {\n\t\t\t\tmessage = sprintf(\n\t\t\t\t\t// translators: %s: file name\n\t\t\t\t\t__( 'Error while uploading file %s to the media library.' ),\n\t\t\t\t\tfile.name\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tonError?.(\n\t\t\t\tnew UploadError( {\n\t\t\t\t\tcode: 'GENERAL',\n\t\t\t\t\tmessage,\n\t\t\t\t\tfile,\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t} )\n\t\t\t);\n\t\t}\n\t} );\n}\n"],
|
|
5
|
-
"mappings": ";AAGA,SAAS,IAAI,eAAe;AAC5B,SAAS,eAAe,qBAAqB;AAW7C,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;
|
|
4
|
+
"sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { __, sprintf } from '@wordpress/i18n';\nimport { createBlobURL, revokeBlobURL } from '@wordpress/blob';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tAdditionalData,\n\tAttachment,\n\tOnChangeHandler,\n\tOnErrorHandler,\n} from './types';\nimport { uploadToServer } from './upload-to-server';\nimport { validateMimeType } from './validate-mime-type';\nimport { validateMimeTypeForUser } from './validate-mime-type-for-user';\nimport { validateFileSize } from './validate-file-size';\nimport { UploadError } from './upload-error';\n\ndeclare global {\n\tinterface Window {\n\t\t__clientSideMediaProcessing?: boolean;\n\t\t__heicUploadSupport?: boolean;\n\t}\n}\n\ninterface UploadMediaArgs {\n\t// Additional data to include in the request.\n\tadditionalData?: AdditionalData;\n\t// Array with the types of media that can be uploaded, if unset all types are allowed.\n\tallowedTypes?: string[];\n\t// List of files.\n\tfilesList: File[];\n\t// Maximum upload size in bytes allowed for the site.\n\tmaxUploadFileSize?: number;\n\t// Function called when an error happens.\n\tonError?: OnErrorHandler;\n\t// Function called each time a file or a temporary representation of the file is available.\n\tonFileChange?: OnChangeHandler;\n\t// List of allowed mime types and file extensions.\n\twpAllowedMimeTypes?: Record< string, string > | null;\n\t// Abort signal.\n\tsignal?: AbortSignal;\n\t// Whether to allow multiple files to be uploaded.\n\tmultiple?: boolean;\n}\n\n/**\n * Upload a media file when the file upload button is activated\n * or when adding a file to the editor via drag & drop.\n *\n * @param $0 Parameters object passed to the function.\n * @param $0.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.\n * @param $0.additionalData Additional data to include in the request.\n * @param $0.filesList List of files.\n * @param $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.\n * @param $0.onError Function called when an error happens.\n * @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.\n * @param $0.wpAllowedMimeTypes List of allowed mime types and file extensions.\n * @param $0.signal Abort signal.\n * @param $0.multiple Whether to allow multiple files to be uploaded.\n */\nexport function uploadMedia( {\n\twpAllowedMimeTypes,\n\tallowedTypes,\n\tadditionalData = {},\n\tfilesList,\n\tmaxUploadFileSize,\n\tonError,\n\tonFileChange,\n\tsignal,\n\tmultiple = true,\n}: UploadMediaArgs ) {\n\tif ( ! multiple && filesList.length > 1 ) {\n\t\tonError?.( new Error( __( 'Only one file can be used here.' ) ) );\n\t\treturn;\n\t}\n\n\tconst validFiles = [];\n\n\tconst filesSet: Array< Partial< Attachment > | null > = [];\n\tconst setAndUpdateFiles = ( index: number, value: Attachment | null ) => {\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\tif ( filesSet[ index ]?.url ) {\n\t\t\t\trevokeBlobURL( filesSet[ index ].url );\n\t\t\t}\n\t\t}\n\t\tfilesSet[ index ] = value;\n\t\tonFileChange?.(\n\t\t\tfilesSet.filter( ( attachment ) => attachment !== null )\n\t\t);\n\t};\n\n\tfor ( const mediaFile of filesList ) {\n\t\t// Verify if user is allowed to upload this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeTypeForUser( mediaFile, wpAllowedMimeTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if the caller (e.g. a block) supports this mime type.\n\t\t// Defer to the server when type not detected.\n\t\ttry {\n\t\t\tvalidateMimeType( mediaFile, allowedTypes );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Verify if file is greater than the maximum file upload size allowed for the site.\n\t\ttry {\n\t\t\tvalidateFileSize( mediaFile, maxUploadFileSize );\n\t\t} catch ( error: unknown ) {\n\t\t\tonError?.( error as Error );\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalidFiles.push( mediaFile );\n\n\t\t// For client-side media processing, this is handled by the upload-media package.\n\t\tif ( ! window.__clientSideMediaProcessing ) {\n\t\t\t// Set temporary URL to create placeholder media file, this is replaced\n\t\t\t// with final file from media gallery when upload is `done` below.\n\t\t\tfilesSet.push( { url: createBlobURL( mediaFile ) } );\n\t\t\tonFileChange?.( filesSet as Array< Partial< Attachment > > );\n\t\t}\n\t}\n\n\tvalidFiles.map( async ( file, index ) => {\n\t\ttry {\n\t\t\tconst attachment = await uploadToServer(\n\t\t\t\tfile,\n\t\t\t\tadditionalData,\n\t\t\t\tsignal\n\t\t\t);\n\t\t\tsetAndUpdateFiles( index, attachment );\n\t\t} catch ( error ) {\n\t\t\t// Reset to empty on failure.\n\t\t\tsetAndUpdateFiles( index, null );\n\n\t\t\t// @wordpress/api-fetch throws any response that isn't in the 200 range as-is.\n\t\t\tlet message: string;\n\t\t\tif (\n\t\t\t\ttypeof error === 'object' &&\n\t\t\t\terror !== null &&\n\t\t\t\t'message' in error\n\t\t\t) {\n\t\t\t\tmessage =\n\t\t\t\t\ttypeof error.message === 'string'\n\t\t\t\t\t\t? error.message\n\t\t\t\t\t\t: String( error.message );\n\t\t\t} else {\n\t\t\t\tmessage = sprintf(\n\t\t\t\t\t// translators: %s: file name\n\t\t\t\t\t__( 'Error while uploading file %s to the media library.' ),\n\t\t\t\t\tfile.name\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tonError?.(\n\t\t\t\tnew UploadError( {\n\t\t\t\t\tcode: 'GENERAL',\n\t\t\t\t\tmessage,\n\t\t\t\t\tfile,\n\t\t\t\t\tcause: error instanceof Error ? error : undefined,\n\t\t\t\t} )\n\t\t\t);\n\t\t}\n\t} );\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,SAAS,IAAI,eAAe;AAC5B,SAAS,eAAe,qBAAqB;AAW7C,SAAS,sBAAsB;AAC/B,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AA6CrB,SAAS,YAAa;AAAA,EAC5B;AAAA,EACA;AAAA,EACA,iBAAiB,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AACZ,GAAqB;AACpB,MAAK,CAAE,YAAY,UAAU,SAAS,GAAI;AACzC,cAAW,IAAI,MAAO,GAAI,iCAAkC,CAAE,CAAE;AAChE;AAAA,EACD;AAEA,QAAM,aAAa,CAAC;AAEpB,QAAM,WAAkD,CAAC;AACzD,QAAM,oBAAoB,CAAE,OAAe,UAA8B;AAExE,QAAK,CAAE,OAAO,6BAA8B;AAC3C,UAAK,SAAU,KAAM,GAAG,KAAM;AAC7B,sBAAe,SAAU,KAAM,EAAE,GAAI;AAAA,MACtC;AAAA,IACD;AACA,aAAU,KAAM,IAAI;AACpB;AAAA,MACC,SAAS,OAAQ,CAAE,eAAgB,eAAe,IAAK;AAAA,IACxD;AAAA,EACD;AAEA,aAAY,aAAa,WAAY;AAGpC,QAAI;AACH,8BAAyB,WAAW,kBAAmB;AAAA,IACxD,SAAU,OAAiB;AAC1B,gBAAW,KAAe;AAC1B;AAAA,IACD;AAIA,QAAI;AACH,uBAAkB,WAAW,YAAa;AAAA,IAC3C,SAAU,OAAiB;AAC1B,gBAAW,KAAe;AAC1B;AAAA,IACD;AAGA,QAAI;AACH,uBAAkB,WAAW,iBAAkB;AAAA,IAChD,SAAU,OAAiB;AAC1B,gBAAW,KAAe;AAC1B;AAAA,IACD;AAEA,eAAW,KAAM,SAAU;AAG3B,QAAK,CAAE,OAAO,6BAA8B;AAG3C,eAAS,KAAM,EAAE,KAAK,cAAe,SAAU,EAAE,CAAE;AACnD,qBAAgB,QAA2C;AAAA,IAC5D;AAAA,EACD;AAEA,aAAW,IAAK,OAAQ,MAAM,UAAW;AACxC,QAAI;AACH,YAAM,aAAa,MAAM;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,MACD;AACA,wBAAmB,OAAO,UAAW;AAAA,IACtC,SAAU,OAAQ;AAEjB,wBAAmB,OAAO,IAAK;AAG/B,UAAI;AACJ,UACC,OAAO,UAAU,YACjB,UAAU,QACV,aAAa,OACZ;AACD,kBACC,OAAO,MAAM,YAAY,WACtB,MAAM,UACN,OAAQ,MAAM,OAAQ;AAAA,MAC3B,OAAO;AACN,kBAAU;AAAA;AAAA,UAET,GAAI,qDAAsD;AAAA,UAC1D,KAAK;AAAA,QACN;AAAA,MACD;AAEA;AAAA,QACC,IAAI,YAAa;AAAA,UAChB,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,QACzC,CAAE;AAAA,MACH;AAAA,IACD;AAAA,EACD,CAAE;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media-upload-modal/index.tsx"],"names":[],"mappings":"AAiDA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAyDpE,UAAU,qBAAqB;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,QAAQ,EAAE,CAAE,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,KAAM,IAAI,CAAC;IAEvD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAE,IAAI,EAAE;QAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,EAAE,IAAI,EAAE,CAAC;QAClB,YAAY,CAAC,EAAE,CAAE,WAAW,EAAE,OAAO,CAAE,UAAU,CAAE,EAAE,KAAM,IAAI,CAAC;QAChE,OAAO,CAAC,EAAE,CAAE,KAAK,EAAE,KAAK,KAAM,IAAI,CAAC;QACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;KACnB,KAAM,IAAI,CAAC;IAEZ;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAE,EACjC,YAAY,EACZ,QAAgB,EAChB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,KAA4B,EAC5B,MAAM,EACN,aAAoB,EACpB,UAAU,EACV,MAAa,EACb,WAAkC,GAClC,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media-upload-modal/index.tsx"],"names":[],"mappings":"AAiDA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAyDpE,UAAU,qBAAqB;IAC9B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAE1B;;;OAGG;IACH,QAAQ,EAAE,CAAE,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,KAAM,IAAI,CAAC;IAEvD;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAE,IAAI,EAAE;QAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,SAAS,EAAE,IAAI,EAAE,CAAC;QAClB,YAAY,CAAC,EAAE,CAAE,WAAW,EAAE,OAAO,CAAE,UAAU,CAAE,EAAE,KAAM,IAAI,CAAC;QAChE,OAAO,CAAC,EAAE,CAAE,KAAK,EAAE,KAAK,KAAM,IAAI,CAAC;QACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;KACnB,KAAM,IAAI,CAAC;IAEZ;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAE,EACjC,YAAY,EACZ,QAAgB,EAChB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,KAA4B,EAC5B,MAAM,EACN,aAAoB,EACpB,UAAU,EACV,MAAa,EACb,WAAkC,GAClC,EAAE,qBAAqB,sCAuavB;AAED,eAAe,gBAAgB,CAAC"}
|
package/build-types/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export { transformAttachment } from './utils/transform-attachment';
|
|
|
4
4
|
export { validateFileSize } from './utils/validate-file-size';
|
|
5
5
|
export { validateMimeType } from './utils/validate-mime-type';
|
|
6
6
|
export { validateMimeTypeForUser } from './utils/validate-mime-type-for-user';
|
|
7
|
-
export type { Attachment, RestAttachment } from './utils/types';
|
|
7
|
+
export type { Attachment, RestAttachment, SubSizeData } from './utils/types';
|
|
8
8
|
export { privateApis } from './private-apis';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE9E,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE9E,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE7E,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal dependencies
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
4
|
+
import type { OnErrorHandler, CreateSideloadFile, RestAttachment, SubSizeData } from './types';
|
|
5
|
+
type OnSubSizeHandler = (subSize: SubSizeData) => void;
|
|
5
6
|
interface SideloadMediaArgs {
|
|
6
7
|
additionalData?: CreateSideloadFile;
|
|
7
8
|
file: File;
|
|
8
9
|
attachmentId: RestAttachment['id'];
|
|
9
10
|
onError?: OnErrorHandler;
|
|
10
|
-
|
|
11
|
+
onSuccess?: OnSubSizeHandler;
|
|
11
12
|
signal?: AbortSignal;
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* Uploads a file to the server without creating an attachment.
|
|
15
16
|
*
|
|
17
|
+
* Returns sub-size data instead of a full attachment. The client
|
|
18
|
+
* accumulates this data and sends it to the finalize endpoint.
|
|
19
|
+
*
|
|
16
20
|
* @param $0 Parameters object passed to the function.
|
|
17
21
|
* @param $0.file Media File to Save.
|
|
18
22
|
* @param $0.attachmentId Parent attachment ID.
|
|
19
23
|
* @param $0.additionalData Additional data to include in the request.
|
|
20
24
|
* @param $0.signal Abort signal.
|
|
21
|
-
* @param $0.
|
|
25
|
+
* @param $0.onSuccess Function called when the sideload completes with sub-size data.
|
|
22
26
|
* @param $0.onError Function called when an error happens.
|
|
23
27
|
*/
|
|
24
|
-
export declare function sideloadMedia({ file, attachmentId, additionalData, signal,
|
|
28
|
+
export declare function sideloadMedia({ file, attachmentId, additionalData, signal, onSuccess, onError, }: SideloadMediaArgs): Promise<void>;
|
|
25
29
|
export {};
|
|
26
30
|
//# sourceMappingURL=sideload-media.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sideload-media.d.ts","sourceRoot":"","sources":["../../src/utils/sideload-media.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EACX,
|
|
1
|
+
{"version":3,"file":"sideload-media.d.ts","sourceRoot":"","sources":["../../src/utils/sideload-media.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EACX,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,MAAM,SAAS,CAAC;AAMjB,KAAK,gBAAgB,GAAG,CAAE,OAAO,EAAE,WAAW,KAAM,IAAI,CAAC;AAEzD,UAAU,iBAAiB;IAE1B,cAAc,CAAC,EAAE,kBAAkB,CAAC;IAEpC,IAAI,EAAE,IAAI,CAAC;IAEX,YAAY,EAAE,cAAc,CAAE,IAAI,CAAE,CAAC;IAErC,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAE7B,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,aAAa,CAAE,EACpC,IAAI,EACJ,YAAY,EACZ,cAAmB,EACnB,MAAM,EACN,SAAS,EACT,OAAc,GACd,EAAE,iBAAiB,iBA6BnB"}
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Internal dependencies
|
|
3
3
|
*/
|
|
4
|
-
import type { CreateSideloadFile, RestAttachment } from './types';
|
|
4
|
+
import type { CreateSideloadFile, RestAttachment, SubSizeData } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Uploads a file to the server without creating an attachment.
|
|
7
7
|
*
|
|
8
|
+
* Returns lightweight sub-size data instead of a full attachment.
|
|
9
|
+
* The client accumulates these responses and sends them to the
|
|
10
|
+
* finalize endpoint.
|
|
11
|
+
*
|
|
8
12
|
* @param file Media File to Save.
|
|
9
13
|
* @param attachmentId Parent attachment ID.
|
|
10
14
|
* @param additionalData Additional data to include in the request.
|
|
11
15
|
* @param signal Abort signal.
|
|
12
16
|
*
|
|
13
|
-
* @return
|
|
17
|
+
* @return Sub-size data for the uploaded file.
|
|
14
18
|
*/
|
|
15
|
-
export declare function sideloadToServer(file: File, attachmentId: RestAttachment['id'], additionalData?: CreateSideloadFile, signal?: AbortSignal): Promise<
|
|
19
|
+
export declare function sideloadToServer(file: File, attachmentId: RestAttachment['id'], additionalData?: CreateSideloadFile, signal?: AbortSignal): Promise<SubSizeData>;
|
|
16
20
|
//# sourceMappingURL=sideload-to-server.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sideload-to-server.d.ts","sourceRoot":"","sources":["../../src/utils/sideload-to-server.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"sideload-to-server.d.ts","sourceRoot":"","sources":["../../src/utils/sideload-to-server.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG/E;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACrC,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,cAAc,CAAE,IAAI,CAAE,EACpC,cAAc,GAAE,kBAAuB,EACvC,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAE,WAAW,CAAE,CAkBxB"}
|
|
@@ -197,10 +197,27 @@ export type AdditionalData = BetterOmit<CreateRestAttachment, 'meta'>;
|
|
|
197
197
|
export interface CreateSideloadFile {
|
|
198
198
|
image_size?: string;
|
|
199
199
|
upload_request?: string;
|
|
200
|
+
generate_sub_sizes?: boolean;
|
|
201
|
+
convert_format?: boolean;
|
|
200
202
|
}
|
|
201
203
|
export interface SideloadAdditionalData {
|
|
202
204
|
post: RestAttachment['id'];
|
|
203
205
|
image_size?: string;
|
|
204
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Sub-size data returned by the sideload endpoint.
|
|
209
|
+
*
|
|
210
|
+
* Each sideload returns this lightweight object instead of a full attachment.
|
|
211
|
+
* The client accumulates these and sends them all to the finalize endpoint.
|
|
212
|
+
*/
|
|
213
|
+
export interface SubSizeData {
|
|
214
|
+
image_size: string;
|
|
215
|
+
width?: number;
|
|
216
|
+
height?: number;
|
|
217
|
+
file: string;
|
|
218
|
+
mime_type?: string;
|
|
219
|
+
filesize?: number;
|
|
220
|
+
original_image?: string;
|
|
221
|
+
}
|
|
205
222
|
export {};
|
|
206
223
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,UAAU,sBAAsB;IAC/B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,OAAO,EAAE;QACR;;WAEG;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QACb;;WAEG;QACH,QAAQ,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;OAEG;IACH,WAAW,EAAE;QACZ;;WAEG;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QACb;;WAEG;QACH,QAAQ,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;OAEG;IACH,UAAU,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,aAAa,EAAE;QACd,CAAE,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;KACvB,CAAC;IACF;;OAEG;IACH,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB;;OAEG;IACH,KAAK,EAAE;QACN;;WAEG;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QACb;;WAEG;QACH,QAAQ,EAAE,MAAM,CAAC;KACjB,CAAC;IACF;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,IAAI,EACD,EAAE,GACF;QACA,CAAE,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;KACtB,CAAC;IACL;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QACP,CAAE,CAAC,EAAE,MAAM,GAAI;YACd,IAAI,EAAE,MAAM,CAAC;YACb,UAAU,CAAC,EAAE,OAAO,CAAC;YACrB,CAAE,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;SACvB,EAAE,CAAC;KACJ,CAAC;IACF;;OAEG;IACH,SAAS,CAAC,EAAE;QACX;;WAEG;QACH,MAAM,EAAE,OAAO,EAAE,CAAC;QAClB;;WAEG;QACH,kBAAkB,CAAC,EAAE,sBAAsB,EAAE,CAAC;QAC9C,CAAE,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;KACvB,CAAC;IACF,CAAE,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,sBAAsB;CAAG;AAEjE,KAAK,UAAU,CAAE,CAAC,EAAE,CAAC,SAAS,WAAW,IAAK;KAC3C,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,KAAK,GAAG,CAAC,GAAI,CAAC,CAAE,CAAC,CAAE;CACnD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,UAAU,CAClC,cAAc,EACd,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAC/C,GAAG;IACH,GAAG,EAAE,sBAAsB,CAAE,UAAU,CAAE,CAAC;IAC1C,OAAO,EAAE,sBAAsB,CAAE,SAAS,CAAE,CAAE,KAAK,CAAE,GAAG,MAAM,CAAC;IAC/D,KAAK,EAAE,sBAAsB,CAAE,OAAO,CAAE,CAAE,KAAK,CAAE,CAAC;IAClD,GAAG,EAAE,sBAAsB,CAAE,YAAY,CAAE,CAAC;IAC5C,MAAM,CAAC,EAAE,sBAAsB,CAAE,YAAY,CAAE,CAAC;CAChD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,CAAE,WAAW,EAAE,OAAO,CAAE,UAAU,CAAE,EAAE,KAAM,IAAI,CAAC;AAC/E,MAAM,MAAM,cAAc,GAAG,CAAE,KAAK,EAAE,KAAK,KAAM,IAAI,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAE,cAAc,CAAE,CAAC;AAE7D,MAAM,MAAM,cAAc,GAAG,UAAU,CAAE,oBAAoB,EAAE,MAAM,CAAE,CAAC;AAExE,MAAM,WAAW,kBAAkB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,cAAc,CAAE,IAAI,CAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-media.d.ts","sourceRoot":"","sources":["../../src/utils/upload-media.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,OAAO,KAAK,EACX,cAAc,EAEd,eAAe,EACf,cAAc,EACd,MAAM,SAAS,CAAC;AAOjB,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,2BAA2B,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"upload-media.d.ts","sourceRoot":"","sources":["../../src/utils/upload-media.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,OAAO,KAAK,EACX,cAAc,EAEd,eAAe,EACf,cAAc,EACd,MAAM,SAAS,CAAC;AAOjB,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,2BAA2B,CAAC,EAAE,OAAO,CAAC;QACtC,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC9B;CACD;AAED,UAAU,eAAe;IAExB,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB,SAAS,EAAE,IAAI,EAAE,CAAC;IAElB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAE3B,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB,YAAY,CAAC,EAAE,eAAe,CAAC;IAE/B,kBAAkB,CAAC,EAAE,MAAM,CAAE,MAAM,EAAE,MAAM,CAAE,GAAG,IAAI,CAAC;IAErD,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAE,EAC5B,kBAAkB,EAClB,YAAY,EACZ,cAAmB,EACnB,SAAS,EACT,iBAAiB,EACjB,OAAO,EACP,YAAY,EACZ,MAAM,EACN,QAAe,GACf,EAAE,eAAe,QAqGjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/media-utils",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.45.0",
|
|
4
4
|
"description": "WordPress Media Upload Utils.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -47,21 +47,21 @@
|
|
|
47
47
|
"build-style/**"
|
|
48
48
|
],
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@wordpress/api-fetch": "^7.
|
|
51
|
-
"@wordpress/base-styles": "^
|
|
52
|
-
"@wordpress/blob": "^4.
|
|
53
|
-
"@wordpress/components": "^
|
|
54
|
-
"@wordpress/core-data": "^7.
|
|
55
|
-
"@wordpress/data": "^10.
|
|
56
|
-
"@wordpress/dataviews": "^14.
|
|
57
|
-
"@wordpress/element": "^6.
|
|
58
|
-
"@wordpress/i18n": "^6.
|
|
59
|
-
"@wordpress/icons": "^
|
|
60
|
-
"@wordpress/media-fields": "^0.
|
|
61
|
-
"@wordpress/notices": "^5.
|
|
62
|
-
"@wordpress/private-apis": "^1.
|
|
63
|
-
"@wordpress/ui": "^0.
|
|
64
|
-
"@wordpress/views": "^1.
|
|
50
|
+
"@wordpress/api-fetch": "^7.45.0",
|
|
51
|
+
"@wordpress/base-styles": "^7.0.0",
|
|
52
|
+
"@wordpress/blob": "^4.45.0",
|
|
53
|
+
"@wordpress/components": "^33.0.0",
|
|
54
|
+
"@wordpress/core-data": "^7.45.0",
|
|
55
|
+
"@wordpress/data": "^10.45.0",
|
|
56
|
+
"@wordpress/dataviews": "^14.2.0",
|
|
57
|
+
"@wordpress/element": "^6.45.0",
|
|
58
|
+
"@wordpress/i18n": "^6.18.0",
|
|
59
|
+
"@wordpress/icons": "^13.0.0",
|
|
60
|
+
"@wordpress/media-fields": "^0.10.0",
|
|
61
|
+
"@wordpress/notices": "^5.45.0",
|
|
62
|
+
"@wordpress/private-apis": "^1.45.0",
|
|
63
|
+
"@wordpress/ui": "^0.12.0",
|
|
64
|
+
"@wordpress/views": "^1.12.0",
|
|
65
65
|
"clsx": "^2.1.1"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"publishConfig": {
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "8c229eaed0e88c9827e2da3d73a78f9ddd77714b"
|
|
74
74
|
}
|
|
@@ -270,11 +270,34 @@ export function MediaUploadModal( {
|
|
|
270
270
|
}
|
|
271
271
|
} );
|
|
272
272
|
|
|
273
|
-
// Base media type on allowedTypes if no filter is set
|
|
274
|
-
if (
|
|
275
|
-
filters.media_type
|
|
276
|
-
|
|
277
|
-
|
|
273
|
+
// Base media and mime type on allowedTypes if no filter is set
|
|
274
|
+
if (
|
|
275
|
+
! filters.media_type &&
|
|
276
|
+
! filters.mime_type &&
|
|
277
|
+
allowedTypes &&
|
|
278
|
+
! allowedTypes.includes( '*' )
|
|
279
|
+
) {
|
|
280
|
+
const { mediaTypes, mimeTypes } = allowedTypes.reduce(
|
|
281
|
+
( acc, type ) => {
|
|
282
|
+
if ( type.endsWith( '/*' ) ) {
|
|
283
|
+
acc.mediaTypes.push( type.replace( '/*', '' ) );
|
|
284
|
+
} else if ( type.includes( '/' ) ) {
|
|
285
|
+
acc.mimeTypes.push( type );
|
|
286
|
+
} else {
|
|
287
|
+
acc.mediaTypes.push( type );
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return acc;
|
|
291
|
+
},
|
|
292
|
+
{ mediaTypes: [] as string[], mimeTypes: [] as string[] }
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
if ( mediaTypes.length ) {
|
|
296
|
+
filters.media_type = mediaTypes;
|
|
297
|
+
}
|
|
298
|
+
if ( mimeTypes.length ) {
|
|
299
|
+
filters.mime_type = mimeTypes;
|
|
300
|
+
}
|
|
278
301
|
}
|
|
279
302
|
|
|
280
303
|
return {
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,6 @@ export { validateFileSize } from './utils/validate-file-size';
|
|
|
6
6
|
export { validateMimeType } from './utils/validate-mime-type';
|
|
7
7
|
export { validateMimeTypeForUser } from './utils/validate-mime-type-for-user';
|
|
8
8
|
|
|
9
|
-
export type { Attachment, RestAttachment } from './utils/types';
|
|
9
|
+
export type { Attachment, RestAttachment, SubSizeData } from './utils/types';
|
|
10
10
|
|
|
11
11
|
export { privateApis } from './private-apis';
|
|
@@ -7,16 +7,18 @@ import { __, sprintf } from '@wordpress/i18n';
|
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
9
|
import type {
|
|
10
|
-
OnChangeHandler,
|
|
11
10
|
OnErrorHandler,
|
|
12
11
|
CreateSideloadFile,
|
|
13
12
|
RestAttachment,
|
|
13
|
+
SubSizeData,
|
|
14
14
|
} from './types';
|
|
15
15
|
import { sideloadToServer } from './sideload-to-server';
|
|
16
16
|
import { UploadError } from './upload-error';
|
|
17
17
|
|
|
18
18
|
const noop = () => {};
|
|
19
19
|
|
|
20
|
+
type OnSubSizeHandler = ( subSize: SubSizeData ) => void;
|
|
21
|
+
|
|
20
22
|
interface SideloadMediaArgs {
|
|
21
23
|
// Additional data to include in the request.
|
|
22
24
|
additionalData?: CreateSideloadFile;
|
|
@@ -26,8 +28,8 @@ interface SideloadMediaArgs {
|
|
|
26
28
|
attachmentId: RestAttachment[ 'id' ];
|
|
27
29
|
// Function called when an error happens.
|
|
28
30
|
onError?: OnErrorHandler;
|
|
29
|
-
// Function called
|
|
30
|
-
|
|
31
|
+
// Function called when the sideload completes with sub-size data.
|
|
32
|
+
onSuccess?: OnSubSizeHandler;
|
|
31
33
|
// Abort signal.
|
|
32
34
|
signal?: AbortSignal;
|
|
33
35
|
}
|
|
@@ -35,12 +37,15 @@ interface SideloadMediaArgs {
|
|
|
35
37
|
/**
|
|
36
38
|
* Uploads a file to the server without creating an attachment.
|
|
37
39
|
*
|
|
40
|
+
* Returns sub-size data instead of a full attachment. The client
|
|
41
|
+
* accumulates this data and sends it to the finalize endpoint.
|
|
42
|
+
*
|
|
38
43
|
* @param $0 Parameters object passed to the function.
|
|
39
44
|
* @param $0.file Media File to Save.
|
|
40
45
|
* @param $0.attachmentId Parent attachment ID.
|
|
41
46
|
* @param $0.additionalData Additional data to include in the request.
|
|
42
47
|
* @param $0.signal Abort signal.
|
|
43
|
-
* @param $0.
|
|
48
|
+
* @param $0.onSuccess Function called when the sideload completes with sub-size data.
|
|
44
49
|
* @param $0.onError Function called when an error happens.
|
|
45
50
|
*/
|
|
46
51
|
export async function sideloadMedia( {
|
|
@@ -48,17 +53,17 @@ export async function sideloadMedia( {
|
|
|
48
53
|
attachmentId,
|
|
49
54
|
additionalData = {},
|
|
50
55
|
signal,
|
|
51
|
-
|
|
56
|
+
onSuccess,
|
|
52
57
|
onError = noop,
|
|
53
58
|
}: SideloadMediaArgs ) {
|
|
54
59
|
try {
|
|
55
|
-
const
|
|
60
|
+
const subSizeData = await sideloadToServer(
|
|
56
61
|
file,
|
|
57
62
|
attachmentId,
|
|
58
63
|
additionalData,
|
|
59
64
|
signal
|
|
60
65
|
);
|
|
61
|
-
|
|
66
|
+
onSuccess?.( subSizeData );
|
|
62
67
|
} catch ( error ) {
|
|
63
68
|
let message;
|
|
64
69
|
if ( error instanceof Error ) {
|
|
@@ -6,26 +6,29 @@ import apiFetch from '@wordpress/api-fetch';
|
|
|
6
6
|
/**
|
|
7
7
|
* Internal dependencies
|
|
8
8
|
*/
|
|
9
|
-
import type { CreateSideloadFile, RestAttachment } from './types';
|
|
9
|
+
import type { CreateSideloadFile, RestAttachment, SubSizeData } from './types';
|
|
10
10
|
import { flattenFormData } from './flatten-form-data';
|
|
11
|
-
import { transformAttachment } from './transform-attachment';
|
|
12
11
|
|
|
13
12
|
/**
|
|
14
13
|
* Uploads a file to the server without creating an attachment.
|
|
15
14
|
*
|
|
15
|
+
* Returns lightweight sub-size data instead of a full attachment.
|
|
16
|
+
* The client accumulates these responses and sends them to the
|
|
17
|
+
* finalize endpoint.
|
|
18
|
+
*
|
|
16
19
|
* @param file Media File to Save.
|
|
17
20
|
* @param attachmentId Parent attachment ID.
|
|
18
21
|
* @param additionalData Additional data to include in the request.
|
|
19
22
|
* @param signal Abort signal.
|
|
20
23
|
*
|
|
21
|
-
* @return
|
|
24
|
+
* @return Sub-size data for the uploaded file.
|
|
22
25
|
*/
|
|
23
26
|
export async function sideloadToServer(
|
|
24
27
|
file: File,
|
|
25
28
|
attachmentId: RestAttachment[ 'id' ],
|
|
26
29
|
additionalData: CreateSideloadFile = {},
|
|
27
30
|
signal?: AbortSignal
|
|
28
|
-
) {
|
|
31
|
+
): Promise< SubSizeData > {
|
|
29
32
|
// Create upload payload.
|
|
30
33
|
const data = new FormData();
|
|
31
34
|
data.append( 'file', file, file.name || file.type.replace( '/', '.' ) );
|
|
@@ -37,12 +40,10 @@ export async function sideloadToServer(
|
|
|
37
40
|
);
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
} )
|
|
47
|
-
);
|
|
43
|
+
return apiFetch< SubSizeData >( {
|
|
44
|
+
path: `/wp/v2/media/${ attachmentId }/sideload`,
|
|
45
|
+
body: data,
|
|
46
|
+
method: 'POST',
|
|
47
|
+
signal,
|
|
48
|
+
} );
|
|
48
49
|
}
|
|
@@ -17,17 +17,27 @@ describe( 'sideloadMedia', () => {
|
|
|
17
17
|
jest.clearAllMocks();
|
|
18
18
|
} );
|
|
19
19
|
|
|
20
|
-
it( 'should sideload to server', async () => {
|
|
20
|
+
it( 'should sideload to server and call onSuccess with sub-size data', async () => {
|
|
21
|
+
const mockSubSizeData = {
|
|
22
|
+
image_size: 'thumbnail',
|
|
23
|
+
width: 150,
|
|
24
|
+
height: 150,
|
|
25
|
+
file: 'test-150x150.jpeg',
|
|
26
|
+
mime_type: 'image/jpeg',
|
|
27
|
+
filesize: 5000,
|
|
28
|
+
};
|
|
29
|
+
( sideloadToServer as jest.Mock ).mockResolvedValue( mockSubSizeData );
|
|
30
|
+
|
|
21
31
|
const onError = jest.fn();
|
|
22
|
-
const
|
|
32
|
+
const onSuccess = jest.fn();
|
|
23
33
|
await sideloadMedia( {
|
|
24
34
|
file: imageFile,
|
|
25
35
|
attachmentId: 1,
|
|
26
36
|
onError,
|
|
27
|
-
|
|
37
|
+
onSuccess,
|
|
28
38
|
} );
|
|
29
39
|
|
|
30
40
|
expect( sideloadToServer ).toHaveBeenCalled();
|
|
31
|
-
expect(
|
|
41
|
+
expect( onSuccess ).toHaveBeenCalledWith( mockSubSizeData );
|
|
32
42
|
} );
|
|
33
43
|
} );
|
package/src/utils/types.ts
CHANGED
|
@@ -208,9 +208,27 @@ export type AdditionalData = BetterOmit< CreateRestAttachment, 'meta' >;
|
|
|
208
208
|
export interface CreateSideloadFile {
|
|
209
209
|
image_size?: string;
|
|
210
210
|
upload_request?: string;
|
|
211
|
+
generate_sub_sizes?: boolean;
|
|
212
|
+
convert_format?: boolean;
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
export interface SideloadAdditionalData {
|
|
214
216
|
post: RestAttachment[ 'id' ];
|
|
215
217
|
image_size?: string;
|
|
216
218
|
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Sub-size data returned by the sideload endpoint.
|
|
222
|
+
*
|
|
223
|
+
* Each sideload returns this lightweight object instead of a full attachment.
|
|
224
|
+
* The client accumulates these and sends them all to the finalize endpoint.
|
|
225
|
+
*/
|
|
226
|
+
export interface SubSizeData {
|
|
227
|
+
image_size: string;
|
|
228
|
+
width?: number;
|
|
229
|
+
height?: number;
|
|
230
|
+
file: string;
|
|
231
|
+
mime_type?: string;
|
|
232
|
+
filesize?: number;
|
|
233
|
+
original_image?: string;
|
|
234
|
+
}
|