@wordpress/media-utils 5.38.0 → 5.39.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 CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 5.39.0 (2026-01-29)
6
+
5
7
  ## 5.38.0 (2026-01-16)
6
8
 
7
9
  ## 5.36.0 (2025-11-26)
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/media-upload/index.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { Component } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n\nconst DEFAULT_EMPTY_GALLERY = [];\n\n/**\n * Prepares the Featured Image toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getFeaturedImageMediaFrame = () => {\n\tconst { wp } = window;\n\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Enables the Set Featured Image Button.\n\t\t *\n\t\t * @param {Object} toolbar toolbar for featured image state\n\t\t * @return {void}\n\t\t */\n\t\tfeaturedImageToolbar( toolbar ) {\n\t\t\tthis.createSelectToolbar( toolbar, {\n\t\t\t\ttext: wp.media.view.l10n.setFeaturedImage,\n\t\t\t\tstate: this.options.state,\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'featured-image' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on(\n\t\t\t\t'toolbar:create:featured-image',\n\t\t\t\tthis.featuredImageToolbar,\n\t\t\t\tthis\n\t\t\t);\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.FeaturedImage(),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the default frame for selecting a single media item.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getSingleMediaFrame = () => {\n\tconst { wp } = window;\n\n\t// Extend the default Select frame, and use the same `createStates` method as in core,\n\t// but with the addition of `filterable: 'uploaded'` to the Library state, so that\n\t// the user can filter the media library by uploaded media.\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Create the default states on the frame.\n\t\t */\n\t\tcreateStates() {\n\t\t\tconst options = this.options;\n\n\t\t\tif ( this.options.states ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add the default states.\n\t\t\tthis.states.add( [\n\t\t\t\t// Main states.\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tlibrary: wp.media.query( options.library ),\n\t\t\t\t\tmultiple: options.multiple,\n\t\t\t\t\ttitle: options.title,\n\t\t\t\t\tpriority: 20,\n\t\t\t\t\tfilterable: 'uploaded', // Allow filtering by uploaded images.\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the Gallery toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Post} The default media workflow.\n */\nconst getGalleryDetailsMediaFrame = () => {\n\tconst { wp } = window;\n\t/**\n\t * Custom gallery details frame.\n\t *\n\t * @see https://github.com/xwp/wp-core-media-widgets/blob/905edbccfc2a623b73a93dac803c5335519d7837/wp-admin/js/widgets/media-gallery-widget.js\n\t * @class GalleryDetailsMediaFrame\n\t * @class\n\t */\n\treturn wp.media.view.MediaFrame.Post.extend( {\n\t\t/**\n\t\t * Set up gallery toolbar.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgalleryToolbar() {\n\t\t\tconst editing = this.state().get( 'editing' );\n\t\t\tthis.toolbar.set(\n\t\t\t\tnew wp.media.view.Toolbar( {\n\t\t\t\t\tcontroller: this,\n\t\t\t\t\titems: {\n\t\t\t\t\t\tinsert: {\n\t\t\t\t\t\t\tstyle: 'primary',\n\t\t\t\t\t\t\ttext: editing\n\t\t\t\t\t\t\t\t? wp.media.view.l10n.updateGallery\n\t\t\t\t\t\t\t\t: wp.media.view.l10n.insertGallery,\n\t\t\t\t\t\t\tpriority: 80,\n\t\t\t\t\t\t\trequires: { library: true },\n\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * @fires wp.media.controller.State#update\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tclick() {\n\t\t\t\t\t\t\t\tconst controller = this.controller,\n\t\t\t\t\t\t\t\t\tstate = controller.state();\n\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\tstate.trigger(\n\t\t\t\t\t\t\t\t\t'update',\n\t\t\t\t\t\t\t\t\tstate.get( 'library' )\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Restore and reset the default state.\n\t\t\t\t\t\t\t\tcontroller.setState( controller.options.state );\n\t\t\t\t\t\t\t\tcontroller.reset();\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} )\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'gallery' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on( 'toolbar:create:main-gallery', this.galleryToolbar, this );\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tid: 'gallery',\n\t\t\t\t\ttitle: wp.media.view.l10n.createGalleryTitle,\n\t\t\t\t\tpriority: 40,\n\t\t\t\t\ttoolbar: 'main-gallery',\n\t\t\t\t\tfilterable: 'uploaded',\n\t\t\t\t\tmultiple: 'add',\n\t\t\t\t\teditable: false,\n\n\t\t\t\t\tlibrary: wp.media.query( {\n\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t...this.options.library,\n\t\t\t\t\t} ),\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryEdit( {\n\t\t\t\t\tlibrary: this.options.selection,\n\t\t\t\t\tediting: this.options.editing,\n\t\t\t\t\tmenu: 'gallery',\n\t\t\t\t\tdisplaySettings: false,\n\t\t\t\t\tmultiple: true,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryAdd(),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n// The media library image object contains numerous attributes\n// we only need this set to display the image in the library.\nconst slimImageObject = ( img ) => {\n\tconst attrSet = [\n\t\t'sizes',\n\t\t'mime',\n\t\t'type',\n\t\t'subtype',\n\t\t'id',\n\t\t'url',\n\t\t'alt',\n\t\t'link',\n\t\t'caption',\n\t];\n\treturn attrSet.reduce( ( result, key ) => {\n\t\tif ( img?.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = img[ key ];\n\t\t}\n\t\treturn result;\n\t}, {} );\n};\n\nconst getAttachmentsCollection = ( ids ) => {\n\tconst { wp } = window;\n\n\treturn wp.media.query( {\n\t\torder: 'ASC',\n\t\torderby: 'post__in',\n\t\tpost__in: ids,\n\t\tposts_per_page: -1,\n\t\tquery: true,\n\t\ttype: 'image',\n\t} );\n};\n\nclass MediaUpload extends Component {\n\tconstructor() {\n\t\tsuper( ...arguments );\n\t\tthis.openModal = this.openModal.bind( this );\n\t\tthis.onOpen = this.onOpen.bind( this );\n\t\tthis.onSelect = this.onSelect.bind( this );\n\t\tthis.onUpdate = this.onUpdate.bind( this );\n\t\tthis.onClose = this.onClose.bind( this );\n\t}\n\n\tinitializeListeners() {\n\t\t// When an image is selected in the media frame...\n\t\tthis.frame.on( 'select', this.onSelect );\n\t\tthis.frame.on( 'update', this.onUpdate );\n\t\tthis.frame.on( 'open', this.onOpen );\n\t\tthis.frame.on( 'close', this.onClose );\n\t}\n\n\t/**\n\t * Sets the Gallery frame and initializes listeners.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetGalleryFrame() {\n\t\tconst {\n\t\t\taddToGallery = false,\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\tvalue = DEFAULT_EMPTY_GALLERY,\n\t\t} = this.props;\n\n\t\t// If the value did not changed there is no need to rebuild the frame,\n\t\t// we can continue to use the existing one.\n\t\tif ( value === this.lastGalleryValue ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { wp } = window;\n\n\t\tthis.lastGalleryValue = value;\n\n\t\t// If a frame already existed remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\t\tlet currentState;\n\t\tif ( addToGallery ) {\n\t\t\tcurrentState = 'gallery-library';\n\t\t} else {\n\t\t\tcurrentState = value && value.length ? 'gallery-edit' : 'gallery';\n\t\t}\n\t\tif ( ! this.GalleryDetailsMediaFrame ) {\n\t\t\tthis.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame();\n\t\t}\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t\tmultiple,\n\t\t} );\n\t\tthis.frame = new this.GalleryDetailsMediaFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: currentState,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: !! value?.length,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\tthis.initializeListeners();\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the featured image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetFeatureImageFrame() {\n\t\tconst { wp } = window;\n\t\tconst { value: featuredImageId, multiple, allowedTypes } = this.props;\n\t\tconst featuredImageFrame = getFeaturedImageMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( featuredImageId );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new featuredImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: 'featured-image',\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: featuredImageId,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\t// In order to select the current featured image when opening\n\t\t// the media library we have to set the appropriate settings.\n\t\t// Currently they are set in php for the post editor, but\n\t\t// not for site editor.\n\t\twp.media.view.settings.post = {\n\t\t\t...wp.media.view.settings.post,\n\t\t\tfeaturedImageId: featuredImageId || -1,\n\t\t};\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the single image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetSingleMediaFrame() {\n\t\tconst { wp } = window;\n\t\tconst {\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\ttitle = __( 'Select or Upload Media' ),\n\t\t\tvalue,\n\t\t} = this.props;\n\n\t\tconst frameConfig = {\n\t\t\ttitle,\n\t\t\tmultiple,\n\t\t};\n\t\tif ( !! allowedTypes ) {\n\t\t\tframeConfig.library = { type: allowedTypes };\n\t\t}\n\n\t\t// If a frame already exists, remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\n\t\tconst singleImageFrame = getSingleMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new singleImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\t...frameConfig,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t}\n\n\tcomponentWillUnmount() {\n\t\tthis.frame?.remove();\n\t}\n\n\tonUpdate( selections ) {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\tconst state = this.frame.state();\n\t\tconst selectedImages = selections || state.get( 'selection' );\n\n\t\tif ( ! selectedImages || ! selectedImages.models.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( multiple ) {\n\t\t\tonSelect(\n\t\t\t\tselectedImages.models.map( ( model ) =>\n\t\t\t\t\tslimImageObject( model.toJSON() )\n\t\t\t\t)\n\t\t\t);\n\t\t} else {\n\t\t\tonSelect( slimImageObject( selectedImages.models[ 0 ].toJSON() ) );\n\t\t}\n\t}\n\n\tonSelect() {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\t// Get media attachment details from the frame state.\n\t\tconst attachment = this.frame.state().get( 'selection' ).toJSON();\n\t\tonSelect( multiple ? attachment : attachment[ 0 ] );\n\t}\n\n\tonOpen() {\n\t\tconst { wp } = window;\n\t\tconst { value } = this.props;\n\t\tthis.updateCollection();\n\n\t\t//Handle active tab in media model on model open.\n\t\tif ( this.props.mode ) {\n\t\t\tthis.frame.content.mode( this.props.mode );\n\t\t}\n\n\t\t// Handle both this.props.value being either (number[]) multiple ids\n\t\t// (for galleries) or a (number) singular id (e.g. image block).\n\t\tconst hasMedia = Array.isArray( value ) ? !! value?.length : !! value;\n\n\t\tif ( ! hasMedia ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isGallery = this.props.gallery;\n\t\tconst selection = this.frame.state().get( 'selection' );\n\t\tconst valueArray = Array.isArray( value ) ? value : [ value ];\n\n\t\tif ( ! isGallery ) {\n\t\t\tvalueArray.forEach( ( id ) => {\n\t\t\t\tselection.add( wp.media.attachment( id ) );\n\t\t\t} );\n\t\t}\n\n\t\t// Load the images so they are available in the media modal.\n\t\tconst attachments = getAttachmentsCollection( valueArray );\n\n\t\t// Once attachments are loaded, set the current selection.\n\t\tattachments.more().done( function () {\n\t\t\tif ( isGallery && attachments?.models?.length ) {\n\t\t\t\tselection.add( attachments.models );\n\t\t\t}\n\t\t} );\n\t}\n\n\tonClose() {\n\t\tconst { onClose } = this.props;\n\n\t\tif ( onClose ) {\n\t\t\tonClose();\n\t\t}\n\n\t\tthis.frame.detach();\n\t}\n\n\tupdateCollection() {\n\t\tconst frameContent = this.frame.content.get();\n\t\tif ( frameContent && frameContent.collection ) {\n\t\t\tconst collection = frameContent.collection;\n\n\t\t\t// Clean all attachments we have in memory.\n\t\t\tcollection\n\t\t\t\t.toArray()\n\t\t\t\t.forEach( ( model ) => model.trigger( 'destroy', model ) );\n\n\t\t\t// Reset has more flag, if library had small amount of items all items may have been loaded before.\n\t\t\tcollection.mirroring._hasMore = true;\n\n\t\t\t// Request items.\n\t\t\tcollection.more();\n\t\t}\n\t}\n\n\topenModal() {\n\t\tconst {\n\t\t\tgallery = false,\n\t\t\tunstableFeaturedImageFlow = false,\n\t\t\tmodalClass,\n\t\t} = this.props;\n\n\t\tif ( gallery ) {\n\t\t\tthis.buildAndSetGalleryFrame();\n\t\t} else {\n\t\t\tthis.buildAndSetSingleMediaFrame();\n\t\t}\n\n\t\tif ( modalClass ) {\n\t\t\tthis.frame.$el.addClass( modalClass );\n\t\t}\n\n\t\tif ( unstableFeaturedImageFlow ) {\n\t\t\tthis.buildAndSetFeatureImageFrame();\n\t\t}\n\t\tthis.initializeListeners();\n\t\tthis.frame.open();\n\t}\n\n\trender() {\n\t\treturn this.props.render( { open: this.openModal } );\n\t}\n}\n\nexport default MediaUpload;\n"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { Component } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n\nconst DEFAULT_EMPTY_GALLERY = [];\n\n/**\n * Prepares the Featured Image toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getFeaturedImageMediaFrame = () => {\n\tconst { wp } = window;\n\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Enables the Set Featured Image Button.\n\t\t *\n\t\t * @param {Object} toolbar toolbar for featured image state\n\t\t * @return {void}\n\t\t */\n\t\tfeaturedImageToolbar( toolbar ) {\n\t\t\tthis.createSelectToolbar( toolbar, {\n\t\t\t\ttext: wp.media.view.l10n.setFeaturedImage,\n\t\t\t\tstate: this.options.state,\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'featured-image' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on(\n\t\t\t\t'toolbar:create:featured-image',\n\t\t\t\tthis.featuredImageToolbar,\n\t\t\t\tthis\n\t\t\t);\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.FeaturedImage(),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the default frame for selecting a single media item.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getSingleMediaFrame = () => {\n\tconst { wp } = window;\n\n\t// Extend the default Select frame, and use the same `createStates` method as in core,\n\t// but with the addition of `filterable: 'uploaded'` to the Library state, so that\n\t// the user can filter the media library by uploaded media.\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Create the default states on the frame.\n\t\t */\n\t\tcreateStates() {\n\t\t\tconst options = this.options;\n\n\t\t\tif ( this.options.states ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add the default states.\n\t\t\tthis.states.add( [\n\t\t\t\t// Main states.\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tlibrary: wp.media.query( options.library ),\n\t\t\t\t\tmultiple: options.multiple,\n\t\t\t\t\ttitle: options.title,\n\t\t\t\t\tpriority: 20,\n\t\t\t\t\tfilterable: 'uploaded', // Allow filtering by uploaded images.\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the Gallery toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Post} The default media workflow.\n */\nconst getGalleryDetailsMediaFrame = () => {\n\tconst { wp } = window;\n\t/**\n\t * Custom gallery details frame.\n\t *\n\t * @see https://github.com/xwp/wp-core-media-widgets/blob/905edbccfc2a623b73a93dac803c5335519d7837/wp-admin/js/widgets/media-gallery-widget.js\n\t * @class GalleryDetailsMediaFrame\n\t * @class\n\t */\n\treturn wp.media.view.MediaFrame.Post.extend( {\n\t\t/**\n\t\t * Set up gallery toolbar.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgalleryToolbar() {\n\t\t\tconst editing = this.state().get( 'editing' );\n\t\t\tthis.toolbar.set(\n\t\t\t\tnew wp.media.view.Toolbar( {\n\t\t\t\t\tcontroller: this,\n\t\t\t\t\titems: {\n\t\t\t\t\t\tinsert: {\n\t\t\t\t\t\t\tstyle: 'primary',\n\t\t\t\t\t\t\ttext: editing\n\t\t\t\t\t\t\t\t? wp.media.view.l10n.updateGallery\n\t\t\t\t\t\t\t\t: wp.media.view.l10n.insertGallery,\n\t\t\t\t\t\t\tpriority: 80,\n\t\t\t\t\t\t\trequires: { library: true },\n\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * @fires wp.media.controller.State#update\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tclick() {\n\t\t\t\t\t\t\t\tconst controller = this.controller,\n\t\t\t\t\t\t\t\t\tstate = controller.state();\n\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\tstate.trigger(\n\t\t\t\t\t\t\t\t\t'update',\n\t\t\t\t\t\t\t\t\tstate.get( 'library' )\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Restore and reset the default state.\n\t\t\t\t\t\t\t\tcontroller.setState( controller.options.state );\n\t\t\t\t\t\t\t\tcontroller.reset();\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} )\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'gallery' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on( 'toolbar:create:main-gallery', this.galleryToolbar, this );\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tid: 'gallery',\n\t\t\t\t\ttitle: wp.media.view.l10n.createGalleryTitle,\n\t\t\t\t\tpriority: 40,\n\t\t\t\t\ttoolbar: 'main-gallery',\n\t\t\t\t\tfilterable: 'uploaded',\n\t\t\t\t\tmultiple: 'add',\n\t\t\t\t\teditable: false,\n\n\t\t\t\t\tlibrary: wp.media.query( {\n\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t...this.options.library,\n\t\t\t\t\t} ),\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryEdit( {\n\t\t\t\t\tlibrary: this.options.selection,\n\t\t\t\t\tediting: this.options.editing,\n\t\t\t\t\tmenu: 'gallery',\n\t\t\t\t\tdisplaySettings: false,\n\t\t\t\t\tmultiple: true,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryAdd(),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n// The media library image object contains numerous attributes\n// we only need this set to display the image in the library.\nconst slimImageObject = ( img ) => {\n\tconst attrSet = [\n\t\t'sizes',\n\t\t'mime',\n\t\t'type',\n\t\t'subtype',\n\t\t'id',\n\t\t'url',\n\t\t'alt',\n\t\t'link',\n\t\t'caption',\n\t];\n\treturn attrSet.reduce( ( result, key ) => {\n\t\tif ( img?.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = img[ key ];\n\t\t}\n\t\treturn result;\n\t}, {} );\n};\n\nconst getAttachmentsCollection = ( ids ) => {\n\tconst { wp } = window;\n\n\treturn wp.media.query( {\n\t\torder: 'ASC',\n\t\torderby: 'post__in',\n\t\tpost__in: ids,\n\t\tposts_per_page: -1,\n\t\tquery: true,\n\t\ttype: 'image',\n\t} );\n};\n\nclass MediaUpload extends Component {\n\tconstructor() {\n\t\tsuper( ...arguments );\n\t\tthis.openModal = this.openModal.bind( this );\n\t\tthis.onOpen = this.onOpen.bind( this );\n\t\tthis.onSelect = this.onSelect.bind( this );\n\t\tthis.onUpdate = this.onUpdate.bind( this );\n\t\tthis.onClose = this.onClose.bind( this );\n\t}\n\n\tinitializeListeners() {\n\t\t// When an image is selected in the media frame...\n\t\tthis.frame.on( 'select', this.onSelect );\n\t\tthis.frame.on( 'update', this.onUpdate );\n\t\tthis.frame.on( 'open', this.onOpen );\n\t\tthis.frame.on( 'close', this.onClose );\n\t}\n\n\t/**\n\t * Sets the Gallery frame and initializes listeners.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetGalleryFrame() {\n\t\tconst {\n\t\t\taddToGallery = false,\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\tvalue = DEFAULT_EMPTY_GALLERY,\n\t\t} = this.props;\n\n\t\t// If the value did not change there is no need to rebuild the frame,\n\t\t// we can continue to use the existing one.\n\t\tif ( value === this.lastGalleryValue ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { wp } = window;\n\n\t\tthis.lastGalleryValue = value;\n\n\t\t// If a frame already existed remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\t\tlet currentState;\n\t\tif ( addToGallery ) {\n\t\t\tcurrentState = 'gallery-library';\n\t\t} else {\n\t\t\tcurrentState = value && value.length ? 'gallery-edit' : 'gallery';\n\t\t}\n\t\tif ( ! this.GalleryDetailsMediaFrame ) {\n\t\t\tthis.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame();\n\t\t}\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t\tmultiple,\n\t\t} );\n\t\tthis.frame = new this.GalleryDetailsMediaFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: currentState,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: !! value?.length,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\tthis.initializeListeners();\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the featured image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetFeatureImageFrame() {\n\t\tconst { wp } = window;\n\t\tconst { value: featuredImageId, multiple, allowedTypes } = this.props;\n\t\tconst featuredImageFrame = getFeaturedImageMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( featuredImageId );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new featuredImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: 'featured-image',\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: featuredImageId,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\t// In order to select the current featured image when opening\n\t\t// the media library we have to set the appropriate settings.\n\t\t// Currently they are set in php for the post editor, but\n\t\t// not for site editor.\n\t\twp.media.view.settings.post = {\n\t\t\t...wp.media.view.settings.post,\n\t\t\tfeaturedImageId: featuredImageId || -1,\n\t\t};\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the single image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetSingleMediaFrame() {\n\t\tconst { wp } = window;\n\t\tconst {\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\ttitle = __( 'Select or Upload Media' ),\n\t\t\tvalue,\n\t\t} = this.props;\n\n\t\tconst frameConfig = {\n\t\t\ttitle,\n\t\t\tmultiple,\n\t\t};\n\t\tif ( !! allowedTypes ) {\n\t\t\tframeConfig.library = { type: allowedTypes };\n\t\t}\n\n\t\t// If a frame already exists, remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\n\t\tconst singleImageFrame = getSingleMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new singleImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\t...frameConfig,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t}\n\n\tcomponentWillUnmount() {\n\t\tthis.frame?.remove();\n\t}\n\n\tonUpdate( selections ) {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\tconst state = this.frame.state();\n\t\tconst selectedImages = selections || state.get( 'selection' );\n\n\t\tif ( ! selectedImages || ! selectedImages.models.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( multiple ) {\n\t\t\tonSelect(\n\t\t\t\tselectedImages.models.map( ( model ) =>\n\t\t\t\t\tslimImageObject( model.toJSON() )\n\t\t\t\t)\n\t\t\t);\n\t\t} else {\n\t\t\tonSelect( slimImageObject( selectedImages.models[ 0 ].toJSON() ) );\n\t\t}\n\t}\n\n\tonSelect() {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\t// Get media attachment details from the frame state.\n\t\tconst attachment = this.frame.state().get( 'selection' ).toJSON();\n\t\tonSelect( multiple ? attachment : attachment[ 0 ] );\n\t}\n\n\tonOpen() {\n\t\tconst { wp } = window;\n\t\tconst { value } = this.props;\n\t\tthis.updateCollection();\n\n\t\t//Handle active tab in media model on model open.\n\t\tif ( this.props.mode ) {\n\t\t\tthis.frame.content.mode( this.props.mode );\n\t\t}\n\n\t\t// Handle both this.props.value being either (number[]) multiple ids\n\t\t// (for galleries) or a (number) singular id (e.g. image block).\n\t\tconst hasMedia = Array.isArray( value ) ? !! value?.length : !! value;\n\n\t\tif ( ! hasMedia ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isGallery = this.props.gallery;\n\t\tconst selection = this.frame.state().get( 'selection' );\n\t\tconst valueArray = Array.isArray( value ) ? value : [ value ];\n\n\t\tif ( ! isGallery ) {\n\t\t\tvalueArray.forEach( ( id ) => {\n\t\t\t\tselection.add( wp.media.attachment( id ) );\n\t\t\t} );\n\t\t}\n\n\t\t// Load the images so they are available in the media modal.\n\t\tconst attachments = getAttachmentsCollection( valueArray );\n\n\t\t// Once attachments are loaded, set the current selection.\n\t\tattachments.more().done( function () {\n\t\t\tif ( isGallery && attachments?.models?.length ) {\n\t\t\t\tselection.add( attachments.models );\n\t\t\t}\n\t\t} );\n\t}\n\n\tonClose() {\n\t\tconst { onClose } = this.props;\n\n\t\tif ( onClose ) {\n\t\t\tonClose();\n\t\t}\n\n\t\tthis.frame.detach();\n\t}\n\n\tupdateCollection() {\n\t\tconst frameContent = this.frame.content.get();\n\t\tif ( frameContent && frameContent.collection ) {\n\t\t\tconst collection = frameContent.collection;\n\n\t\t\t// Clean all attachments we have in memory.\n\t\t\tcollection\n\t\t\t\t.toArray()\n\t\t\t\t.forEach( ( model ) => model.trigger( 'destroy', model ) );\n\n\t\t\t// Reset has more flag, if library had small amount of items all items may have been loaded before.\n\t\t\tcollection.mirroring._hasMore = true;\n\n\t\t\t// Request items.\n\t\t\tcollection.more();\n\t\t}\n\t}\n\n\topenModal() {\n\t\tconst {\n\t\t\tgallery = false,\n\t\t\tunstableFeaturedImageFlow = false,\n\t\t\tmodalClass,\n\t\t} = this.props;\n\n\t\tif ( gallery ) {\n\t\t\tthis.buildAndSetGalleryFrame();\n\t\t} else {\n\t\t\tthis.buildAndSetSingleMediaFrame();\n\t\t}\n\n\t\tif ( modalClass ) {\n\t\t\tthis.frame.$el.addClass( modalClass );\n\t\t}\n\n\t\tif ( unstableFeaturedImageFlow ) {\n\t\t\tthis.buildAndSetFeatureImageFrame();\n\t\t}\n\t\tthis.initializeListeners();\n\t\tthis.frame.open();\n\t}\n\n\trender() {\n\t\treturn this.props.render( { open: this.openModal } );\n\t}\n}\n\nexport default MediaUpload;\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -32,6 +32,8 @@ var import_components = require("@wordpress/components");
32
32
  var import_icons = require("@wordpress/icons");
33
33
  var import_dataviews = require("@wordpress/dataviews");
34
34
  var import_media_fields = require("@wordpress/media-fields");
35
+ var import_notices = require("@wordpress/notices");
36
+ var import_blob = require("@wordpress/blob");
35
37
  var import_transform_attachment = require("../../utils/transform-attachment.cjs");
36
38
  var import_upload_media = require("../../utils/upload-media.cjs");
37
39
  var import_lock_unlock = require("../../lock-unlock.cjs");
@@ -39,6 +41,8 @@ var import_jsx_runtime = require("react/jsx-runtime");
39
41
  var { useEntityRecordsWithPermissions } = (0, import_lock_unlock.unlock)(import_core_data.privateApis);
40
42
  var LAYOUT_PICKER_GRID = "pickerGrid";
41
43
  var LAYOUT_PICKER_TABLE = "pickerTable";
44
+ var NOTICES_CONTEXT = "media-modal";
45
+ var NOTICE_ID_UPLOAD_PROGRESS = "media-modal-upload-progress";
42
46
  function MediaUploadModal({
43
47
  allowedTypes = ["image"],
44
48
  multiple = false,
@@ -59,6 +63,17 @@ function MediaUploadModal({
59
63
  }
60
64
  return Array.isArray(value) ? value.map(String) : [String(value)];
61
65
  });
66
+ const {
67
+ createSuccessNotice,
68
+ createErrorNotice,
69
+ createInfoNotice,
70
+ removeNotice
71
+ } = (0, import_data.useDispatch)(import_notices.store);
72
+ const { invalidateResolution } = (0, import_data.useDispatch)(import_core_data.store);
73
+ const notices = (0, import_data.useSelect)(
74
+ (select) => select(import_notices.store).getNotices(NOTICES_CONTEXT),
75
+ []
76
+ );
62
77
  const [view, setView] = (0, import_element.useState)(() => ({
63
78
  type: LAYOUT_PICKER_GRID,
64
79
  fields: [],
@@ -180,18 +195,84 @@ function MediaUploadModal({
180
195
  onClose?.();
181
196
  }, [onClose]);
182
197
  const handleUpload = onUpload || import_upload_media.uploadMedia;
198
+ const handleUploadComplete = (0, import_element.useCallback)(
199
+ (attachments) => {
200
+ const allComplete = attachments.every(
201
+ (attachment) => attachment.id && attachment.url && !(0, import_blob.isBlobURL)(attachment.url)
202
+ );
203
+ if (allComplete && attachments.length > 0) {
204
+ createSuccessNotice(
205
+ (0, import_i18n.sprintf)(
206
+ // translators: %s: number of files
207
+ (0, import_i18n._n)(
208
+ "Uploaded %s file",
209
+ "Uploaded %s files",
210
+ attachments.length
211
+ ),
212
+ attachments.length.toLocaleString()
213
+ ),
214
+ {
215
+ type: "snackbar",
216
+ context: NOTICES_CONTEXT,
217
+ id: NOTICE_ID_UPLOAD_PROGRESS
218
+ }
219
+ );
220
+ invalidateResolution("getEntityRecords", [
221
+ "postType",
222
+ "attachment",
223
+ queryArgs
224
+ ]);
225
+ }
226
+ },
227
+ [createSuccessNotice, invalidateResolution, queryArgs]
228
+ );
229
+ const handleUploadError = (0, import_element.useCallback)(
230
+ (error) => {
231
+ createErrorNotice(error.message, {
232
+ type: "snackbar",
233
+ context: NOTICES_CONTEXT,
234
+ id: NOTICE_ID_UPLOAD_PROGRESS
235
+ });
236
+ },
237
+ [createErrorNotice]
238
+ );
183
239
  const handleFileSelect = (0, import_element.useCallback)(
184
240
  (event) => {
185
241
  const files = event.target.files;
186
242
  if (files && files.length > 0) {
187
243
  const filesArray = Array.from(files);
244
+ createInfoNotice(
245
+ (0, import_i18n.sprintf)(
246
+ // translators: %s: number of files
247
+ (0, import_i18n._n)(
248
+ "Uploading %s file",
249
+ "Uploading %s files",
250
+ filesArray.length
251
+ ),
252
+ filesArray.length.toLocaleString()
253
+ ),
254
+ {
255
+ type: "snackbar",
256
+ context: NOTICES_CONTEXT,
257
+ id: NOTICE_ID_UPLOAD_PROGRESS,
258
+ explicitDismiss: true
259
+ }
260
+ );
188
261
  handleUpload({
189
262
  allowedTypes,
190
- filesList: filesArray
263
+ filesList: filesArray,
264
+ onFileChange: handleUploadComplete,
265
+ onError: handleUploadError
191
266
  });
192
267
  }
193
268
  },
194
- [allowedTypes, handleUpload]
269
+ [
270
+ allowedTypes,
271
+ handleUpload,
272
+ createInfoNotice,
273
+ handleUploadComplete,
274
+ handleUploadError
275
+ ]
195
276
  );
196
277
  const paginationInfo = (0, import_element.useMemo)(
197
278
  () => ({
@@ -271,9 +352,28 @@ function MediaUploadModal({
271
352
  );
272
353
  }
273
354
  if (filteredFiles.length > 0) {
355
+ createInfoNotice(
356
+ (0, import_i18n.sprintf)(
357
+ // translators: %s: number of files
358
+ (0, import_i18n._n)(
359
+ "Uploading %s file",
360
+ "Uploading %s files",
361
+ filteredFiles.length
362
+ ),
363
+ filteredFiles.length.toLocaleString()
364
+ ),
365
+ {
366
+ type: "snackbar",
367
+ context: NOTICES_CONTEXT,
368
+ id: NOTICE_ID_UPLOAD_PROGRESS,
369
+ explicitDismiss: true
370
+ }
371
+ );
274
372
  handleUpload({
275
373
  allowedTypes,
276
- filesList: filteredFiles
374
+ filesList: filteredFiles,
375
+ onFileChange: handleUploadComplete,
376
+ onError: handleUploadError
277
377
  });
278
378
  }
279
379
  },
@@ -298,6 +398,16 @@ function MediaUploadModal({
298
398
  searchLabel,
299
399
  itemListLabel: (0, import_i18n.__)("Media items")
300
400
  }
401
+ ),
402
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
403
+ import_components.SnackbarList,
404
+ {
405
+ notices: notices.filter(
406
+ ({ type }) => type === "snackbar"
407
+ ),
408
+ className: "media-upload-modal__snackbar",
409
+ onRemove: (id) => removeNotice(id, NOTICES_CONTEXT)
410
+ }
301
411
  )
302
412
  ]
303
413
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/media-upload-modal/index.tsx"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useCallback, useMemo } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect } 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 { View, Field, ActionButton } from '@wordpress/dataviews';\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';\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';\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\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t * @default ['image']\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 = [ 'image' ],\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\t// DataViews configuration - allow view updates\n\tconst [ view, setView ] = useState< View >( () => ( {\n\t\ttype: LAYOUT_PICKER_GRID,\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\ttitleField: 'title',\n\t\tmediaField: 'media_thumbnail',\n\t\tsearch: '',\n\t\tpage: 1,\n\t\tperPage: 20,\n\t\tfilters: [],\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// 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: multiple ? __( 'Select' ) : __( '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\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tonClose?.();\n\t}, [ onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\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\thandleUpload( {\n\t\t\t\t\tallowedTypes,\n\t\t\t\t\tfilesList: filesArray,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ allowedTypes, handleUpload ]\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\tconst defaultLayouts = useMemo(\n\t\t() => ( {\n\t\t\t[ LAYOUT_PICKER_GRID ]: {\n\t\t\t\tfields: [],\n\t\t\t\tshowTitle: false,\n\t\t\t},\n\t\t\t[ LAYOUT_PICKER_TABLE ]: {\n\t\t\t\tfields: [\n\t\t\t\t\t'filename',\n\t\t\t\t\t'filesize',\n\t\t\t\t\t'media_dimensions',\n\t\t\t\t\t'author',\n\t\t\t\t\t'date',\n\t\t\t\t],\n\t\t\t\tshowTitle: true,\n\t\t\t},\n\t\t} ),\n\t\t[]\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\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} );\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={ setView }\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\tsearch={ search }\n\t\t\t\tsearchLabel={ searchLabel }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t/>\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
5
- "mappings": "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",
6
- "names": ["coreDataPrivateApis", "coreStore", "uploadIcon"]
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useCallback, useMemo } 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, useSelect } from '@wordpress/data';\nimport {\n\tModal,\n\tDropZone,\n\tFormFileUpload,\n\tButton,\n\tSnackbarList,\n} from '@wordpress/components';\nimport { upload as uploadIcon } from '@wordpress/icons';\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type { View, Field, ActionButton } from '@wordpress/dataviews';\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 } from '@wordpress/notices';\nimport { isBlobURL } from '@wordpress/blob';\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';\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\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t * @default ['image']\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 = [ 'image' ],\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 {\n\t\tcreateSuccessNotice,\n\t\tcreateErrorNotice,\n\t\tcreateInfoNotice,\n\t\tremoveNotice,\n\t} = useDispatch( noticesStore );\n\t// @ts-expect-error - invalidateResolution is not in the typed actions but is available at runtime\n\tconst { invalidateResolution } = useDispatch( coreStore );\n\n\t// Get notices for this modal context\n\tconst notices = useSelect(\n\t\t( select ) => select( noticesStore ).getNotices( NOTICES_CONTEXT ),\n\t\t[]\n\t);\n\n\t// DataViews configuration - allow view updates\n\tconst [ view, setView ] = useState< View >( () => ( {\n\t\ttype: LAYOUT_PICKER_GRID,\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\ttitleField: 'title',\n\t\tmediaField: 'media_thumbnail',\n\t\tsearch: '',\n\t\tpage: 1,\n\t\tperPage: 20,\n\t\tfilters: [],\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// 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: multiple ? __( 'Select' ) : __( '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\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tonClose?.();\n\t}, [ onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\t// Shared upload success handler\n\tconst handleUploadComplete = useCallback(\n\t\t( attachments: Partial< Attachment >[] ) => {\n\t\t\t// Check if all uploads are complete (no blob URLs)\n\t\t\tconst allComplete = attachments.every(\n\t\t\t\t( attachment ) =>\n\t\t\t\t\tattachment.id &&\n\t\t\t\t\tattachment.url &&\n\t\t\t\t\t! isBlobURL( attachment.url )\n\t\t\t);\n\n\t\t\tif ( allComplete && attachments.length > 0 ) {\n\t\t\t\t// Show success notice (replaces progress notice via ID)\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\tattachments.length\n\t\t\t\t\t\t),\n\t\t\t\t\t\tattachments.length.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\n\t\t\t\t// Invalidate the entity records resolution to refresh the view\n\t\t\t\tinvalidateResolution( 'getEntityRecords', [\n\t\t\t\t\t'postType',\n\t\t\t\t\t'attachment',\n\t\t\t\t\tqueryArgs,\n\t\t\t\t] );\n\t\t\t}\n\t\t},\n\t\t[ createSuccessNotice, invalidateResolution, queryArgs ]\n\t);\n\n\t// Shared upload error handler\n\tconst handleUploadError = useCallback(\n\t\t( error: Error ) => {\n\t\t\t// Show error notice (replaces progress notice via ID)\n\t\t\tcreateErrorNotice( error.message, {\n\t\t\t\ttype: 'snackbar',\n\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t} );\n\t\t},\n\t\t[ createErrorNotice ]\n\t);\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\n\t\t\t\t// Show upload start notice\n\t\t\t\tcreateInfoNotice(\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'Uploading %s file',\n\t\t\t\t\t\t\t'Uploading %s files',\n\t\t\t\t\t\t\tfilesArray.length\n\t\t\t\t\t\t),\n\t\t\t\t\t\tfilesArray.length.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\texplicitDismiss: true,\n\t\t\t\t\t}\n\t\t\t\t);\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: handleUploadComplete,\n\t\t\t\t\tonError: handleUploadError,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tallowedTypes,\n\t\t\thandleUpload,\n\t\t\tcreateInfoNotice,\n\t\t\thandleUploadComplete,\n\t\t\thandleUploadError,\n\t\t]\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\tconst defaultLayouts = useMemo(\n\t\t() => ( {\n\t\t\t[ LAYOUT_PICKER_GRID ]: {\n\t\t\t\tfields: [],\n\t\t\t\tshowTitle: false,\n\t\t\t},\n\t\t\t[ LAYOUT_PICKER_TABLE ]: {\n\t\t\t\tfields: [\n\t\t\t\t\t'filename',\n\t\t\t\t\t'filesize',\n\t\t\t\t\t'media_dimensions',\n\t\t\t\t\t'author',\n\t\t\t\t\t'date',\n\t\t\t\t],\n\t\t\t\tshowTitle: true,\n\t\t\t},\n\t\t} ),\n\t\t[]\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\t// Show upload start notice\n\t\t\t\t\t\tcreateInfoNotice(\n\t\t\t\t\t\t\tsprintf(\n\t\t\t\t\t\t\t\t// translators: %s: number of files\n\t\t\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t\t\t'Uploading %s file',\n\t\t\t\t\t\t\t\t\t'Uploading %s files',\n\t\t\t\t\t\t\t\t\tfilteredFiles.length\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tfilteredFiles.length.toLocaleString()\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\t\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t\t\t\t\t\texplicitDismiss: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\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: handleUploadComplete,\n\t\t\t\t\t\t\tonError: handleUploadError,\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={ setView }\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\tsearch={ search }\n\t\t\t\tsearchLabel={ searchLabel }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t/>\n\t\t\t<SnackbarList\n\t\t\t\tnotices={ notices.filter(\n\t\t\t\t\t( { type } ) => type === 'snackbar'\n\t\t\t\t) }\n\t\t\t\tclassName=\"media-upload-modal__snackbar\"\n\t\t\t\tonRemove={ ( id ) => removeNotice( id, NOTICES_CONTEXT ) }\n\t\t\t/>\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
5
+ "mappings": "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",
6
+ "names": ["coreDataPrivateApis", "noticesStore", "coreStore", "uploadIcon"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/media-upload/index.js"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { Component } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n\nconst DEFAULT_EMPTY_GALLERY = [];\n\n/**\n * Prepares the Featured Image toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getFeaturedImageMediaFrame = () => {\n\tconst { wp } = window;\n\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Enables the Set Featured Image Button.\n\t\t *\n\t\t * @param {Object} toolbar toolbar for featured image state\n\t\t * @return {void}\n\t\t */\n\t\tfeaturedImageToolbar( toolbar ) {\n\t\t\tthis.createSelectToolbar( toolbar, {\n\t\t\t\ttext: wp.media.view.l10n.setFeaturedImage,\n\t\t\t\tstate: this.options.state,\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'featured-image' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on(\n\t\t\t\t'toolbar:create:featured-image',\n\t\t\t\tthis.featuredImageToolbar,\n\t\t\t\tthis\n\t\t\t);\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.FeaturedImage(),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the default frame for selecting a single media item.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getSingleMediaFrame = () => {\n\tconst { wp } = window;\n\n\t// Extend the default Select frame, and use the same `createStates` method as in core,\n\t// but with the addition of `filterable: 'uploaded'` to the Library state, so that\n\t// the user can filter the media library by uploaded media.\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Create the default states on the frame.\n\t\t */\n\t\tcreateStates() {\n\t\t\tconst options = this.options;\n\n\t\t\tif ( this.options.states ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add the default states.\n\t\t\tthis.states.add( [\n\t\t\t\t// Main states.\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tlibrary: wp.media.query( options.library ),\n\t\t\t\t\tmultiple: options.multiple,\n\t\t\t\t\ttitle: options.title,\n\t\t\t\t\tpriority: 20,\n\t\t\t\t\tfilterable: 'uploaded', // Allow filtering by uploaded images.\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the Gallery toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Post} The default media workflow.\n */\nconst getGalleryDetailsMediaFrame = () => {\n\tconst { wp } = window;\n\t/**\n\t * Custom gallery details frame.\n\t *\n\t * @see https://github.com/xwp/wp-core-media-widgets/blob/905edbccfc2a623b73a93dac803c5335519d7837/wp-admin/js/widgets/media-gallery-widget.js\n\t * @class GalleryDetailsMediaFrame\n\t * @class\n\t */\n\treturn wp.media.view.MediaFrame.Post.extend( {\n\t\t/**\n\t\t * Set up gallery toolbar.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgalleryToolbar() {\n\t\t\tconst editing = this.state().get( 'editing' );\n\t\t\tthis.toolbar.set(\n\t\t\t\tnew wp.media.view.Toolbar( {\n\t\t\t\t\tcontroller: this,\n\t\t\t\t\titems: {\n\t\t\t\t\t\tinsert: {\n\t\t\t\t\t\t\tstyle: 'primary',\n\t\t\t\t\t\t\ttext: editing\n\t\t\t\t\t\t\t\t? wp.media.view.l10n.updateGallery\n\t\t\t\t\t\t\t\t: wp.media.view.l10n.insertGallery,\n\t\t\t\t\t\t\tpriority: 80,\n\t\t\t\t\t\t\trequires: { library: true },\n\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * @fires wp.media.controller.State#update\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tclick() {\n\t\t\t\t\t\t\t\tconst controller = this.controller,\n\t\t\t\t\t\t\t\t\tstate = controller.state();\n\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\tstate.trigger(\n\t\t\t\t\t\t\t\t\t'update',\n\t\t\t\t\t\t\t\t\tstate.get( 'library' )\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Restore and reset the default state.\n\t\t\t\t\t\t\t\tcontroller.setState( controller.options.state );\n\t\t\t\t\t\t\t\tcontroller.reset();\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} )\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'gallery' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on( 'toolbar:create:main-gallery', this.galleryToolbar, this );\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tid: 'gallery',\n\t\t\t\t\ttitle: wp.media.view.l10n.createGalleryTitle,\n\t\t\t\t\tpriority: 40,\n\t\t\t\t\ttoolbar: 'main-gallery',\n\t\t\t\t\tfilterable: 'uploaded',\n\t\t\t\t\tmultiple: 'add',\n\t\t\t\t\teditable: false,\n\n\t\t\t\t\tlibrary: wp.media.query( {\n\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t...this.options.library,\n\t\t\t\t\t} ),\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryEdit( {\n\t\t\t\t\tlibrary: this.options.selection,\n\t\t\t\t\tediting: this.options.editing,\n\t\t\t\t\tmenu: 'gallery',\n\t\t\t\t\tdisplaySettings: false,\n\t\t\t\t\tmultiple: true,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryAdd(),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n// The media library image object contains numerous attributes\n// we only need this set to display the image in the library.\nconst slimImageObject = ( img ) => {\n\tconst attrSet = [\n\t\t'sizes',\n\t\t'mime',\n\t\t'type',\n\t\t'subtype',\n\t\t'id',\n\t\t'url',\n\t\t'alt',\n\t\t'link',\n\t\t'caption',\n\t];\n\treturn attrSet.reduce( ( result, key ) => {\n\t\tif ( img?.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = img[ key ];\n\t\t}\n\t\treturn result;\n\t}, {} );\n};\n\nconst getAttachmentsCollection = ( ids ) => {\n\tconst { wp } = window;\n\n\treturn wp.media.query( {\n\t\torder: 'ASC',\n\t\torderby: 'post__in',\n\t\tpost__in: ids,\n\t\tposts_per_page: -1,\n\t\tquery: true,\n\t\ttype: 'image',\n\t} );\n};\n\nclass MediaUpload extends Component {\n\tconstructor() {\n\t\tsuper( ...arguments );\n\t\tthis.openModal = this.openModal.bind( this );\n\t\tthis.onOpen = this.onOpen.bind( this );\n\t\tthis.onSelect = this.onSelect.bind( this );\n\t\tthis.onUpdate = this.onUpdate.bind( this );\n\t\tthis.onClose = this.onClose.bind( this );\n\t}\n\n\tinitializeListeners() {\n\t\t// When an image is selected in the media frame...\n\t\tthis.frame.on( 'select', this.onSelect );\n\t\tthis.frame.on( 'update', this.onUpdate );\n\t\tthis.frame.on( 'open', this.onOpen );\n\t\tthis.frame.on( 'close', this.onClose );\n\t}\n\n\t/**\n\t * Sets the Gallery frame and initializes listeners.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetGalleryFrame() {\n\t\tconst {\n\t\t\taddToGallery = false,\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\tvalue = DEFAULT_EMPTY_GALLERY,\n\t\t} = this.props;\n\n\t\t// If the value did not changed there is no need to rebuild the frame,\n\t\t// we can continue to use the existing one.\n\t\tif ( value === this.lastGalleryValue ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { wp } = window;\n\n\t\tthis.lastGalleryValue = value;\n\n\t\t// If a frame already existed remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\t\tlet currentState;\n\t\tif ( addToGallery ) {\n\t\t\tcurrentState = 'gallery-library';\n\t\t} else {\n\t\t\tcurrentState = value && value.length ? 'gallery-edit' : 'gallery';\n\t\t}\n\t\tif ( ! this.GalleryDetailsMediaFrame ) {\n\t\t\tthis.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame();\n\t\t}\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t\tmultiple,\n\t\t} );\n\t\tthis.frame = new this.GalleryDetailsMediaFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: currentState,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: !! value?.length,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\tthis.initializeListeners();\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the featured image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetFeatureImageFrame() {\n\t\tconst { wp } = window;\n\t\tconst { value: featuredImageId, multiple, allowedTypes } = this.props;\n\t\tconst featuredImageFrame = getFeaturedImageMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( featuredImageId );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new featuredImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: 'featured-image',\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: featuredImageId,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\t// In order to select the current featured image when opening\n\t\t// the media library we have to set the appropriate settings.\n\t\t// Currently they are set in php for the post editor, but\n\t\t// not for site editor.\n\t\twp.media.view.settings.post = {\n\t\t\t...wp.media.view.settings.post,\n\t\t\tfeaturedImageId: featuredImageId || -1,\n\t\t};\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the single image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetSingleMediaFrame() {\n\t\tconst { wp } = window;\n\t\tconst {\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\ttitle = __( 'Select or Upload Media' ),\n\t\t\tvalue,\n\t\t} = this.props;\n\n\t\tconst frameConfig = {\n\t\t\ttitle,\n\t\t\tmultiple,\n\t\t};\n\t\tif ( !! allowedTypes ) {\n\t\t\tframeConfig.library = { type: allowedTypes };\n\t\t}\n\n\t\t// If a frame already exists, remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\n\t\tconst singleImageFrame = getSingleMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new singleImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\t...frameConfig,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t}\n\n\tcomponentWillUnmount() {\n\t\tthis.frame?.remove();\n\t}\n\n\tonUpdate( selections ) {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\tconst state = this.frame.state();\n\t\tconst selectedImages = selections || state.get( 'selection' );\n\n\t\tif ( ! selectedImages || ! selectedImages.models.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( multiple ) {\n\t\t\tonSelect(\n\t\t\t\tselectedImages.models.map( ( model ) =>\n\t\t\t\t\tslimImageObject( model.toJSON() )\n\t\t\t\t)\n\t\t\t);\n\t\t} else {\n\t\t\tonSelect( slimImageObject( selectedImages.models[ 0 ].toJSON() ) );\n\t\t}\n\t}\n\n\tonSelect() {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\t// Get media attachment details from the frame state.\n\t\tconst attachment = this.frame.state().get( 'selection' ).toJSON();\n\t\tonSelect( multiple ? attachment : attachment[ 0 ] );\n\t}\n\n\tonOpen() {\n\t\tconst { wp } = window;\n\t\tconst { value } = this.props;\n\t\tthis.updateCollection();\n\n\t\t//Handle active tab in media model on model open.\n\t\tif ( this.props.mode ) {\n\t\t\tthis.frame.content.mode( this.props.mode );\n\t\t}\n\n\t\t// Handle both this.props.value being either (number[]) multiple ids\n\t\t// (for galleries) or a (number) singular id (e.g. image block).\n\t\tconst hasMedia = Array.isArray( value ) ? !! value?.length : !! value;\n\n\t\tif ( ! hasMedia ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isGallery = this.props.gallery;\n\t\tconst selection = this.frame.state().get( 'selection' );\n\t\tconst valueArray = Array.isArray( value ) ? value : [ value ];\n\n\t\tif ( ! isGallery ) {\n\t\t\tvalueArray.forEach( ( id ) => {\n\t\t\t\tselection.add( wp.media.attachment( id ) );\n\t\t\t} );\n\t\t}\n\n\t\t// Load the images so they are available in the media modal.\n\t\tconst attachments = getAttachmentsCollection( valueArray );\n\n\t\t// Once attachments are loaded, set the current selection.\n\t\tattachments.more().done( function () {\n\t\t\tif ( isGallery && attachments?.models?.length ) {\n\t\t\t\tselection.add( attachments.models );\n\t\t\t}\n\t\t} );\n\t}\n\n\tonClose() {\n\t\tconst { onClose } = this.props;\n\n\t\tif ( onClose ) {\n\t\t\tonClose();\n\t\t}\n\n\t\tthis.frame.detach();\n\t}\n\n\tupdateCollection() {\n\t\tconst frameContent = this.frame.content.get();\n\t\tif ( frameContent && frameContent.collection ) {\n\t\t\tconst collection = frameContent.collection;\n\n\t\t\t// Clean all attachments we have in memory.\n\t\t\tcollection\n\t\t\t\t.toArray()\n\t\t\t\t.forEach( ( model ) => model.trigger( 'destroy', model ) );\n\n\t\t\t// Reset has more flag, if library had small amount of items all items may have been loaded before.\n\t\t\tcollection.mirroring._hasMore = true;\n\n\t\t\t// Request items.\n\t\t\tcollection.more();\n\t\t}\n\t}\n\n\topenModal() {\n\t\tconst {\n\t\t\tgallery = false,\n\t\t\tunstableFeaturedImageFlow = false,\n\t\t\tmodalClass,\n\t\t} = this.props;\n\n\t\tif ( gallery ) {\n\t\t\tthis.buildAndSetGalleryFrame();\n\t\t} else {\n\t\t\tthis.buildAndSetSingleMediaFrame();\n\t\t}\n\n\t\tif ( modalClass ) {\n\t\t\tthis.frame.$el.addClass( modalClass );\n\t\t}\n\n\t\tif ( unstableFeaturedImageFlow ) {\n\t\t\tthis.buildAndSetFeatureImageFrame();\n\t\t}\n\t\tthis.initializeListeners();\n\t\tthis.frame.open();\n\t}\n\n\trender() {\n\t\treturn this.props.render( { open: this.openModal } );\n\t}\n}\n\nexport default MediaUpload;\n"],
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { Component } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\n\nconst DEFAULT_EMPTY_GALLERY = [];\n\n/**\n * Prepares the Featured Image toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getFeaturedImageMediaFrame = () => {\n\tconst { wp } = window;\n\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Enables the Set Featured Image Button.\n\t\t *\n\t\t * @param {Object} toolbar toolbar for featured image state\n\t\t * @return {void}\n\t\t */\n\t\tfeaturedImageToolbar( toolbar ) {\n\t\t\tthis.createSelectToolbar( toolbar, {\n\t\t\t\ttext: wp.media.view.l10n.setFeaturedImage,\n\t\t\t\tstate: this.options.state,\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'featured-image' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on(\n\t\t\t\t'toolbar:create:featured-image',\n\t\t\t\tthis.featuredImageToolbar,\n\t\t\t\tthis\n\t\t\t);\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.FeaturedImage(),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the default frame for selecting a single media item.\n *\n * @return {window.wp.media.view.MediaFrame.Select} The default media workflow.\n */\nconst getSingleMediaFrame = () => {\n\tconst { wp } = window;\n\n\t// Extend the default Select frame, and use the same `createStates` method as in core,\n\t// but with the addition of `filterable: 'uploaded'` to the Library state, so that\n\t// the user can filter the media library by uploaded media.\n\treturn wp.media.view.MediaFrame.Select.extend( {\n\t\t/**\n\t\t * Create the default states on the frame.\n\t\t */\n\t\tcreateStates() {\n\t\t\tconst options = this.options;\n\n\t\t\tif ( this.options.states ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add the default states.\n\t\t\tthis.states.add( [\n\t\t\t\t// Main states.\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tlibrary: wp.media.query( options.library ),\n\t\t\t\t\tmultiple: options.multiple,\n\t\t\t\t\ttitle: options.title,\n\t\t\t\t\tpriority: 20,\n\t\t\t\t\tfilterable: 'uploaded', // Allow filtering by uploaded images.\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: options.editImage,\n\t\t\t\t} ),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n/**\n * Prepares the Gallery toolbars and frames.\n *\n * @return {window.wp.media.view.MediaFrame.Post} The default media workflow.\n */\nconst getGalleryDetailsMediaFrame = () => {\n\tconst { wp } = window;\n\t/**\n\t * Custom gallery details frame.\n\t *\n\t * @see https://github.com/xwp/wp-core-media-widgets/blob/905edbccfc2a623b73a93dac803c5335519d7837/wp-admin/js/widgets/media-gallery-widget.js\n\t * @class GalleryDetailsMediaFrame\n\t * @class\n\t */\n\treturn wp.media.view.MediaFrame.Post.extend( {\n\t\t/**\n\t\t * Set up gallery toolbar.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tgalleryToolbar() {\n\t\t\tconst editing = this.state().get( 'editing' );\n\t\t\tthis.toolbar.set(\n\t\t\t\tnew wp.media.view.Toolbar( {\n\t\t\t\t\tcontroller: this,\n\t\t\t\t\titems: {\n\t\t\t\t\t\tinsert: {\n\t\t\t\t\t\t\tstyle: 'primary',\n\t\t\t\t\t\t\ttext: editing\n\t\t\t\t\t\t\t\t? wp.media.view.l10n.updateGallery\n\t\t\t\t\t\t\t\t: wp.media.view.l10n.insertGallery,\n\t\t\t\t\t\t\tpriority: 80,\n\t\t\t\t\t\t\trequires: { library: true },\n\n\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t * @fires wp.media.controller.State#update\n\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\tclick() {\n\t\t\t\t\t\t\t\tconst controller = this.controller,\n\t\t\t\t\t\t\t\t\tstate = controller.state();\n\n\t\t\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\t\t\tstate.trigger(\n\t\t\t\t\t\t\t\t\t'update',\n\t\t\t\t\t\t\t\t\tstate.get( 'library' )\n\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t// Restore and reset the default state.\n\t\t\t\t\t\t\t\tcontroller.setState( controller.options.state );\n\t\t\t\t\t\t\t\tcontroller.reset();\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} )\n\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Handle the edit state requirements of selected media item.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\teditState() {\n\t\t\tconst selection = this.state( 'gallery' ).get( 'selection' );\n\t\t\tconst view = new wp.media.view.EditImage( {\n\t\t\t\tmodel: selection.single(),\n\t\t\t\tcontroller: this,\n\t\t\t} ).render();\n\n\t\t\t// Set the view to the EditImage frame using the selected image.\n\t\t\tthis.content.set( view );\n\n\t\t\t// After bringing in the frame, load the actual editor via an ajax call.\n\t\t\tview.loadEditor();\n\t\t},\n\n\t\t/**\n\t\t * Create the default states.\n\t\t *\n\t\t * @return {void}\n\t\t */\n\t\tcreateStates: function createStates() {\n\t\t\tthis.on( 'toolbar:create:main-gallery', this.galleryToolbar, this );\n\t\t\tthis.on( 'content:render:edit-image', this.editState, this );\n\n\t\t\tthis.states.add( [\n\t\t\t\tnew wp.media.controller.Library( {\n\t\t\t\t\tid: 'gallery',\n\t\t\t\t\ttitle: wp.media.view.l10n.createGalleryTitle,\n\t\t\t\t\tpriority: 40,\n\t\t\t\t\ttoolbar: 'main-gallery',\n\t\t\t\t\tfilterable: 'uploaded',\n\t\t\t\t\tmultiple: 'add',\n\t\t\t\t\teditable: false,\n\n\t\t\t\t\tlibrary: wp.media.query( {\n\t\t\t\t\t\ttype: 'image',\n\t\t\t\t\t\t...this.options.library,\n\t\t\t\t\t} ),\n\t\t\t\t} ),\n\t\t\t\tnew wp.media.controller.EditImage( {\n\t\t\t\t\tmodel: this.options.editImage,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryEdit( {\n\t\t\t\t\tlibrary: this.options.selection,\n\t\t\t\t\tediting: this.options.editing,\n\t\t\t\t\tmenu: 'gallery',\n\t\t\t\t\tdisplaySettings: false,\n\t\t\t\t\tmultiple: true,\n\t\t\t\t} ),\n\n\t\t\t\tnew wp.media.controller.GalleryAdd(),\n\t\t\t] );\n\t\t},\n\t} );\n};\n\n// The media library image object contains numerous attributes\n// we only need this set to display the image in the library.\nconst slimImageObject = ( img ) => {\n\tconst attrSet = [\n\t\t'sizes',\n\t\t'mime',\n\t\t'type',\n\t\t'subtype',\n\t\t'id',\n\t\t'url',\n\t\t'alt',\n\t\t'link',\n\t\t'caption',\n\t];\n\treturn attrSet.reduce( ( result, key ) => {\n\t\tif ( img?.hasOwnProperty( key ) ) {\n\t\t\tresult[ key ] = img[ key ];\n\t\t}\n\t\treturn result;\n\t}, {} );\n};\n\nconst getAttachmentsCollection = ( ids ) => {\n\tconst { wp } = window;\n\n\treturn wp.media.query( {\n\t\torder: 'ASC',\n\t\torderby: 'post__in',\n\t\tpost__in: ids,\n\t\tposts_per_page: -1,\n\t\tquery: true,\n\t\ttype: 'image',\n\t} );\n};\n\nclass MediaUpload extends Component {\n\tconstructor() {\n\t\tsuper( ...arguments );\n\t\tthis.openModal = this.openModal.bind( this );\n\t\tthis.onOpen = this.onOpen.bind( this );\n\t\tthis.onSelect = this.onSelect.bind( this );\n\t\tthis.onUpdate = this.onUpdate.bind( this );\n\t\tthis.onClose = this.onClose.bind( this );\n\t}\n\n\tinitializeListeners() {\n\t\t// When an image is selected in the media frame...\n\t\tthis.frame.on( 'select', this.onSelect );\n\t\tthis.frame.on( 'update', this.onUpdate );\n\t\tthis.frame.on( 'open', this.onOpen );\n\t\tthis.frame.on( 'close', this.onClose );\n\t}\n\n\t/**\n\t * Sets the Gallery frame and initializes listeners.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetGalleryFrame() {\n\t\tconst {\n\t\t\taddToGallery = false,\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\tvalue = DEFAULT_EMPTY_GALLERY,\n\t\t} = this.props;\n\n\t\t// If the value did not change there is no need to rebuild the frame,\n\t\t// we can continue to use the existing one.\n\t\tif ( value === this.lastGalleryValue ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { wp } = window;\n\n\t\tthis.lastGalleryValue = value;\n\n\t\t// If a frame already existed remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\t\tlet currentState;\n\t\tif ( addToGallery ) {\n\t\t\tcurrentState = 'gallery-library';\n\t\t} else {\n\t\t\tcurrentState = value && value.length ? 'gallery-edit' : 'gallery';\n\t\t}\n\t\tif ( ! this.GalleryDetailsMediaFrame ) {\n\t\t\tthis.GalleryDetailsMediaFrame = getGalleryDetailsMediaFrame();\n\t\t}\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t\tmultiple,\n\t\t} );\n\t\tthis.frame = new this.GalleryDetailsMediaFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: currentState,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: !! value?.length,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\tthis.initializeListeners();\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the featured image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetFeatureImageFrame() {\n\t\tconst { wp } = window;\n\t\tconst { value: featuredImageId, multiple, allowedTypes } = this.props;\n\t\tconst featuredImageFrame = getFeaturedImageMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( featuredImageId );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new featuredImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tstate: 'featured-image',\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\tediting: featuredImageId,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t\t// In order to select the current featured image when opening\n\t\t// the media library we have to set the appropriate settings.\n\t\t// Currently they are set in php for the post editor, but\n\t\t// not for site editor.\n\t\twp.media.view.settings.post = {\n\t\t\t...wp.media.view.settings.post,\n\t\t\tfeaturedImageId: featuredImageId || -1,\n\t\t};\n\t}\n\n\t/**\n\t * Initializes the Media Library requirements for the single image flow.\n\t *\n\t * @return {void}\n\t */\n\tbuildAndSetSingleMediaFrame() {\n\t\tconst { wp } = window;\n\t\tconst {\n\t\t\tallowedTypes,\n\t\t\tmultiple = false,\n\t\t\ttitle = __( 'Select or Upload Media' ),\n\t\t\tvalue,\n\t\t} = this.props;\n\n\t\tconst frameConfig = {\n\t\t\ttitle,\n\t\t\tmultiple,\n\t\t};\n\t\tif ( !! allowedTypes ) {\n\t\t\tframeConfig.library = { type: allowedTypes };\n\t\t}\n\n\t\t// If a frame already exists, remove it.\n\t\tif ( this.frame ) {\n\t\t\tthis.frame.remove();\n\t\t}\n\n\t\tconst singleImageFrame = getSingleMediaFrame();\n\t\tconst attachments = getAttachmentsCollection( value );\n\t\tconst selection = new wp.media.model.Selection( attachments.models, {\n\t\t\tprops: attachments.props.toJSON(),\n\t\t} );\n\t\tthis.frame = new singleImageFrame( {\n\t\t\tmimeType: allowedTypes,\n\t\t\tmultiple,\n\t\t\tselection,\n\t\t\t...frameConfig,\n\t\t} );\n\t\twp.media.frame = this.frame;\n\t}\n\n\tcomponentWillUnmount() {\n\t\tthis.frame?.remove();\n\t}\n\n\tonUpdate( selections ) {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\tconst state = this.frame.state();\n\t\tconst selectedImages = selections || state.get( 'selection' );\n\n\t\tif ( ! selectedImages || ! selectedImages.models.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( multiple ) {\n\t\t\tonSelect(\n\t\t\t\tselectedImages.models.map( ( model ) =>\n\t\t\t\t\tslimImageObject( model.toJSON() )\n\t\t\t\t)\n\t\t\t);\n\t\t} else {\n\t\t\tonSelect( slimImageObject( selectedImages.models[ 0 ].toJSON() ) );\n\t\t}\n\t}\n\n\tonSelect() {\n\t\tconst { onSelect, multiple = false } = this.props;\n\t\t// Get media attachment details from the frame state.\n\t\tconst attachment = this.frame.state().get( 'selection' ).toJSON();\n\t\tonSelect( multiple ? attachment : attachment[ 0 ] );\n\t}\n\n\tonOpen() {\n\t\tconst { wp } = window;\n\t\tconst { value } = this.props;\n\t\tthis.updateCollection();\n\n\t\t//Handle active tab in media model on model open.\n\t\tif ( this.props.mode ) {\n\t\t\tthis.frame.content.mode( this.props.mode );\n\t\t}\n\n\t\t// Handle both this.props.value being either (number[]) multiple ids\n\t\t// (for galleries) or a (number) singular id (e.g. image block).\n\t\tconst hasMedia = Array.isArray( value ) ? !! value?.length : !! value;\n\n\t\tif ( ! hasMedia ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isGallery = this.props.gallery;\n\t\tconst selection = this.frame.state().get( 'selection' );\n\t\tconst valueArray = Array.isArray( value ) ? value : [ value ];\n\n\t\tif ( ! isGallery ) {\n\t\t\tvalueArray.forEach( ( id ) => {\n\t\t\t\tselection.add( wp.media.attachment( id ) );\n\t\t\t} );\n\t\t}\n\n\t\t// Load the images so they are available in the media modal.\n\t\tconst attachments = getAttachmentsCollection( valueArray );\n\n\t\t// Once attachments are loaded, set the current selection.\n\t\tattachments.more().done( function () {\n\t\t\tif ( isGallery && attachments?.models?.length ) {\n\t\t\t\tselection.add( attachments.models );\n\t\t\t}\n\t\t} );\n\t}\n\n\tonClose() {\n\t\tconst { onClose } = this.props;\n\n\t\tif ( onClose ) {\n\t\t\tonClose();\n\t\t}\n\n\t\tthis.frame.detach();\n\t}\n\n\tupdateCollection() {\n\t\tconst frameContent = this.frame.content.get();\n\t\tif ( frameContent && frameContent.collection ) {\n\t\t\tconst collection = frameContent.collection;\n\n\t\t\t// Clean all attachments we have in memory.\n\t\t\tcollection\n\t\t\t\t.toArray()\n\t\t\t\t.forEach( ( model ) => model.trigger( 'destroy', model ) );\n\n\t\t\t// Reset has more flag, if library had small amount of items all items may have been loaded before.\n\t\t\tcollection.mirroring._hasMore = true;\n\n\t\t\t// Request items.\n\t\t\tcollection.more();\n\t\t}\n\t}\n\n\topenModal() {\n\t\tconst {\n\t\t\tgallery = false,\n\t\t\tunstableFeaturedImageFlow = false,\n\t\t\tmodalClass,\n\t\t} = this.props;\n\n\t\tif ( gallery ) {\n\t\t\tthis.buildAndSetGalleryFrame();\n\t\t} else {\n\t\t\tthis.buildAndSetSingleMediaFrame();\n\t\t}\n\n\t\tif ( modalClass ) {\n\t\t\tthis.frame.$el.addClass( modalClass );\n\t\t}\n\n\t\tif ( unstableFeaturedImageFlow ) {\n\t\t\tthis.buildAndSetFeatureImageFrame();\n\t\t}\n\t\tthis.initializeListeners();\n\t\tthis.frame.open();\n\t}\n\n\trender() {\n\t\treturn this.props.render( { open: this.openModal } );\n\t}\n}\n\nexport default MediaUpload;\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,12 +1,18 @@
1
1
  // packages/media-utils/src/components/media-upload-modal/index.tsx
2
2
  import { useState, useCallback, useMemo } from "@wordpress/element";
3
- import { __ } from "@wordpress/i18n";
3
+ import { __, sprintf, _n } from "@wordpress/i18n";
4
4
  import {
5
5
  privateApis as coreDataPrivateApis,
6
6
  store as coreStore
7
7
  } from "@wordpress/core-data";
8
- import { resolveSelect } from "@wordpress/data";
9
- import { Modal, DropZone, FormFileUpload, Button } from "@wordpress/components";
8
+ import { resolveSelect, useDispatch, useSelect } from "@wordpress/data";
9
+ import {
10
+ Modal,
11
+ DropZone,
12
+ FormFileUpload,
13
+ Button,
14
+ SnackbarList
15
+ } from "@wordpress/components";
10
16
  import { upload as uploadIcon } from "@wordpress/icons";
11
17
  import { DataViewsPicker } from "@wordpress/dataviews";
12
18
  import {
@@ -23,6 +29,8 @@ import {
23
29
  mediaThumbnailField,
24
30
  mimeTypeField
25
31
  } from "@wordpress/media-fields";
32
+ import { store as noticesStore } from "@wordpress/notices";
33
+ import { isBlobURL } from "@wordpress/blob";
26
34
  import { transformAttachment } from "../../utils/transform-attachment.mjs";
27
35
  import { uploadMedia } from "../../utils/upload-media.mjs";
28
36
  import { unlock } from "../../lock-unlock.mjs";
@@ -30,6 +38,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
30
38
  var { useEntityRecordsWithPermissions } = unlock(coreDataPrivateApis);
31
39
  var LAYOUT_PICKER_GRID = "pickerGrid";
32
40
  var LAYOUT_PICKER_TABLE = "pickerTable";
41
+ var NOTICES_CONTEXT = "media-modal";
42
+ var NOTICE_ID_UPLOAD_PROGRESS = "media-modal-upload-progress";
33
43
  function MediaUploadModal({
34
44
  allowedTypes = ["image"],
35
45
  multiple = false,
@@ -50,6 +60,17 @@ function MediaUploadModal({
50
60
  }
51
61
  return Array.isArray(value) ? value.map(String) : [String(value)];
52
62
  });
63
+ const {
64
+ createSuccessNotice,
65
+ createErrorNotice,
66
+ createInfoNotice,
67
+ removeNotice
68
+ } = useDispatch(noticesStore);
69
+ const { invalidateResolution } = useDispatch(coreStore);
70
+ const notices = useSelect(
71
+ (select) => select(noticesStore).getNotices(NOTICES_CONTEXT),
72
+ []
73
+ );
53
74
  const [view, setView] = useState(() => ({
54
75
  type: LAYOUT_PICKER_GRID,
55
76
  fields: [],
@@ -171,18 +192,84 @@ function MediaUploadModal({
171
192
  onClose?.();
172
193
  }, [onClose]);
173
194
  const handleUpload = onUpload || uploadMedia;
195
+ const handleUploadComplete = useCallback(
196
+ (attachments) => {
197
+ const allComplete = attachments.every(
198
+ (attachment) => attachment.id && attachment.url && !isBlobURL(attachment.url)
199
+ );
200
+ if (allComplete && attachments.length > 0) {
201
+ createSuccessNotice(
202
+ sprintf(
203
+ // translators: %s: number of files
204
+ _n(
205
+ "Uploaded %s file",
206
+ "Uploaded %s files",
207
+ attachments.length
208
+ ),
209
+ attachments.length.toLocaleString()
210
+ ),
211
+ {
212
+ type: "snackbar",
213
+ context: NOTICES_CONTEXT,
214
+ id: NOTICE_ID_UPLOAD_PROGRESS
215
+ }
216
+ );
217
+ invalidateResolution("getEntityRecords", [
218
+ "postType",
219
+ "attachment",
220
+ queryArgs
221
+ ]);
222
+ }
223
+ },
224
+ [createSuccessNotice, invalidateResolution, queryArgs]
225
+ );
226
+ const handleUploadError = useCallback(
227
+ (error) => {
228
+ createErrorNotice(error.message, {
229
+ type: "snackbar",
230
+ context: NOTICES_CONTEXT,
231
+ id: NOTICE_ID_UPLOAD_PROGRESS
232
+ });
233
+ },
234
+ [createErrorNotice]
235
+ );
174
236
  const handleFileSelect = useCallback(
175
237
  (event) => {
176
238
  const files = event.target.files;
177
239
  if (files && files.length > 0) {
178
240
  const filesArray = Array.from(files);
241
+ createInfoNotice(
242
+ sprintf(
243
+ // translators: %s: number of files
244
+ _n(
245
+ "Uploading %s file",
246
+ "Uploading %s files",
247
+ filesArray.length
248
+ ),
249
+ filesArray.length.toLocaleString()
250
+ ),
251
+ {
252
+ type: "snackbar",
253
+ context: NOTICES_CONTEXT,
254
+ id: NOTICE_ID_UPLOAD_PROGRESS,
255
+ explicitDismiss: true
256
+ }
257
+ );
179
258
  handleUpload({
180
259
  allowedTypes,
181
- filesList: filesArray
260
+ filesList: filesArray,
261
+ onFileChange: handleUploadComplete,
262
+ onError: handleUploadError
182
263
  });
183
264
  }
184
265
  },
185
- [allowedTypes, handleUpload]
266
+ [
267
+ allowedTypes,
268
+ handleUpload,
269
+ createInfoNotice,
270
+ handleUploadComplete,
271
+ handleUploadError
272
+ ]
186
273
  );
187
274
  const paginationInfo = useMemo(
188
275
  () => ({
@@ -262,9 +349,28 @@ function MediaUploadModal({
262
349
  );
263
350
  }
264
351
  if (filteredFiles.length > 0) {
352
+ createInfoNotice(
353
+ sprintf(
354
+ // translators: %s: number of files
355
+ _n(
356
+ "Uploading %s file",
357
+ "Uploading %s files",
358
+ filteredFiles.length
359
+ ),
360
+ filteredFiles.length.toLocaleString()
361
+ ),
362
+ {
363
+ type: "snackbar",
364
+ context: NOTICES_CONTEXT,
365
+ id: NOTICE_ID_UPLOAD_PROGRESS,
366
+ explicitDismiss: true
367
+ }
368
+ );
265
369
  handleUpload({
266
370
  allowedTypes,
267
- filesList: filteredFiles
371
+ filesList: filteredFiles,
372
+ onFileChange: handleUploadComplete,
373
+ onError: handleUploadError
268
374
  });
269
375
  }
270
376
  },
@@ -289,6 +395,16 @@ function MediaUploadModal({
289
395
  searchLabel,
290
396
  itemListLabel: __("Media items")
291
397
  }
398
+ ),
399
+ /* @__PURE__ */ jsx(
400
+ SnackbarList,
401
+ {
402
+ notices: notices.filter(
403
+ ({ type }) => type === "snackbar"
404
+ ),
405
+ className: "media-upload-modal__snackbar",
406
+ onRemove: (id) => removeNotice(id, NOTICES_CONTEXT)
407
+ }
292
408
  )
293
409
  ]
294
410
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/components/media-upload-modal/index.tsx"],
4
- "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useCallback, useMemo } from '@wordpress/element';\nimport { __ } from '@wordpress/i18n';\nimport {\n\tprivateApis as coreDataPrivateApis,\n\tstore as coreStore,\n} from '@wordpress/core-data';\nimport { resolveSelect } 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 { View, Field, ActionButton } from '@wordpress/dataviews';\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';\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';\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\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t * @default ['image']\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 = [ 'image' ],\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\t// DataViews configuration - allow view updates\n\tconst [ view, setView ] = useState< View >( () => ( {\n\t\ttype: LAYOUT_PICKER_GRID,\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\ttitleField: 'title',\n\t\tmediaField: 'media_thumbnail',\n\t\tsearch: '',\n\t\tpage: 1,\n\t\tperPage: 20,\n\t\tfilters: [],\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// 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: multiple ? __( 'Select' ) : __( '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\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tonClose?.();\n\t}, [ onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\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\thandleUpload( {\n\t\t\t\t\tallowedTypes,\n\t\t\t\t\tfilesList: filesArray,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[ allowedTypes, handleUpload ]\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\tconst defaultLayouts = useMemo(\n\t\t() => ( {\n\t\t\t[ LAYOUT_PICKER_GRID ]: {\n\t\t\t\tfields: [],\n\t\t\t\tshowTitle: false,\n\t\t\t},\n\t\t\t[ LAYOUT_PICKER_TABLE ]: {\n\t\t\t\tfields: [\n\t\t\t\t\t'filename',\n\t\t\t\t\t'filesize',\n\t\t\t\t\t'media_dimensions',\n\t\t\t\t\t'author',\n\t\t\t\t\t'date',\n\t\t\t\t],\n\t\t\t\tshowTitle: true,\n\t\t\t},\n\t\t} ),\n\t\t[]\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\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} );\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={ setView }\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\tsearch={ search }\n\t\t\t\tsearchLabel={ searchLabel }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t/>\n\t\t</Modal>\n\t);\n}\n\nexport default MediaUploadModal;\n"],
5
- "mappings": ";AAGA,SAAS,UAAU,aAAa,eAAe;AAC/C,SAAS,UAAU;AACnB;AAAA,EACC,eAAe;AAAA,EACf,SAAS;AAAA,OACH;AACP,SAAS,qBAAqB;AAC9B,SAAS,OAAO,UAAU,gBAAgB,cAAc;AACxD,SAAS,UAAU,kBAAkB;AACrC,SAAS,uBAAuB;AAEhC;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;AAMP,SAAS,2BAA2B;AACpC,SAAS,mBAAmB;AAC5B,SAAS,cAAc;AA8UrB,SAcI,KAdJ;AA5UF,IAAM,EAAE,gCAAgC,IAAI,OAAQ,mBAAoB;AAGxE,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAmGrB,SAAS,iBAAkB;AAAA,EACjC,eAAe,CAAE,OAAQ;AAAA,EACzB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ,GAAI,cAAe;AAAA,EAC3B;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,EACT,cAAc,GAAI,cAAe;AAClC,GAA2B;AAC1B,QAAM,CAAE,WAAW,YAAa,IAAI,SAAsB,MAAM;AAC/D,QAAK,CAAE,OAAQ;AACd,aAAO,CAAC;AAAA,IACT;AACA,WAAO,MAAM,QAAS,KAAM,IACzB,MAAM,IAAK,MAAO,IAClB,CAAE,OAAQ,KAAM,CAAE;AAAA,EACtB,CAAE;AAGF,QAAM,CAAE,MAAM,OAAQ,IAAI,SAAkB,OAAQ;AAAA,IACnD,MAAM;AAAA,IACN,QAAQ,CAAC;AAAA,IACT,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACX,EAAI;AAGJ,QAAM,YAAY,QAAS,MAAM;AAChC,UAAM,UAAiC,CAAC;AAExC,SAAK,SAAS,QAAS,CAAE,WAAY;AAEpC,UAAK,OAAO,UAAU,cAAe;AACpC,gBAAQ,aAAa,OAAO;AAAA,MAC7B;AAEA,UAAK,OAAO,UAAU,UAAW;AAChC,YAAK,OAAO,aAAa,SAAU;AAClC,kBAAQ,SAAS,OAAO;AAAA,QACzB,WAAY,OAAO,aAAa,UAAW;AAC1C,kBAAQ,iBAAiB,OAAO;AAAA,QACjC;AAAA,MACD;AAEA,UAAK,OAAO,UAAU,UAAU,OAAO,UAAU,YAAa;AAC7D,YAAK,OAAO,aAAa,UAAW;AACnC,kBAAQ,SAAS,OAAO;AAAA,QACzB,WAAY,OAAO,aAAa,SAAU;AACzC,kBAAQ,QAAQ,OAAO;AAAA,QACxB;AAAA,MACD;AAEA,UAAK,OAAO,UAAU,aAAc;AACnC,gBAAQ,YAAY,OAAO;AAAA,MAC5B;AAAA,IACD,CAAE;AAGF,QAAK,CAAE,QAAQ,YAAa;AAC3B,cAAQ,aAAa,aAAa,SAAU,GAAI,IAC7C,SACA;AAAA,IACJ;AAEA,WAAO;AAAA,MACN,UAAU,KAAK,WAAW;AAAA,MAC1B,MAAM,KAAK,QAAQ;AAAA,MACnB,QAAQ;AAAA,MACR,OAAO,KAAK,MAAM;AAAA,MAClB,SAAS,KAAK,MAAM;AAAA,MACpB,QAAQ,KAAK;AAAA,MACb,QAAQ;AAAA,MACR,GAAG;AAAA,IACJ;AAAA,EACD,GAAG,CAAE,MAAM,YAAa,CAAE;AAG1B,QAAM;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,IACb;AAAA,IACA;AAAA,EACD,IAAI,gCAAiC,YAAY,cAAc,SAAU;AAEzE,QAAM,SAAoC;AAAA,IACzC,MAAM;AAAA;AAAA;AAAA,MAGL;AAAA,QACC,GAAK;AAAA,QACL,cAAc;AAAA;AAAA,MACf;AAAA,MACA;AAAA,QACC,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,OAAO,GAAI,OAAQ;AAAA,QACnB,UAAU,CAAE,EAAE,KAAK,MAAiC;AACnD,gBAAM,aAAa,KAAK,MAAM,OAAO,KAAK,MAAM;AAChD,iBAAO,cAAc,GAAI,YAAa;AAAA,QACvC;AAAA,MACD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAEA,QAAM,UAA4C;AAAA,IACjD,MAAM;AAAA,MACL;AAAA,QACC,IAAI;AAAA,QACJ,OAAO,WAAW,GAAI,QAAS,IAAI,GAAI,QAAS;AAAA,QAChD,WAAW;AAAA,QACX,cAAc;AAAA,QACd,MAAM,WAAW;AAChB,cAAK,UAAU,WAAW,GAAI;AAC7B;AAAA,UACD;AAEA,gBAAM,qBAAqB;AAAA,YAC1B,SAAS;AAAA,YACT,UAAU;AAAA,UACX;AAEA,gBAAM,gBAAgB,MAAM;AAAA,YAC3B;AAAA,UACD,EAAE;AAAA,YACD;AAAA,YACA;AAAA,YACA;AAAA,UACD;AAGA,gBAAM,oBAAqB,iBAAiB,CAAC,GAC3C,IAAK,mBAAoB,EACzB,OAAQ,OAAQ;AAElB,gBAAM,gBAAgB,WACnB,mBACA,mBAAoB,CAAE;AAEzB,mBAAU,aAAc;AAAA,QACzB;AAAA,MACD;AAAA,IACD;AAAA,IACA,CAAE,UAAU,UAAU,SAAU;AAAA,EACjC;AAEA,QAAM,mBAAmB,YAAa,MAAM;AAC3C,cAAU;AAAA,EACX,GAAG,CAAE,OAAQ,CAAE;AAGf,QAAM,eAAe,YAAY;AAEjC,QAAM,mBAAmB;AAAA,IACxB,CAAE,UAAkD;AACnD,YAAM,QAAQ,MAAM,OAAO;AAC3B,UAAK,SAAS,MAAM,SAAS,GAAI;AAChC,cAAM,aAAa,MAAM,KAAM,KAAM;AACrC,qBAAc;AAAA,UACb;AAAA,UACA,WAAW;AAAA,QACZ,CAAE;AAAA,MACH;AAAA,IACD;AAAA,IACA,CAAE,cAAc,YAAa;AAAA,EAC9B;AAEA,QAAM,iBAAiB;AAAA,IACtB,OAAQ;AAAA,MACP;AAAA,MACA;AAAA,IACD;AAAA,IACA,CAAE,YAAY,UAAW;AAAA,EAC1B;AAEA,QAAM,iBAAiB;AAAA,IACtB,OAAQ;AAAA,MACP,CAAE,kBAAmB,GAAG;AAAA,QACvB,QAAQ,CAAC;AAAA,QACT,WAAW;AAAA,MACZ;AAAA,MACA,CAAE,mBAAoB,GAAG;AAAA,QACxB,QAAQ;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAAA,QACA,WAAW;AAAA,MACZ;AAAA,IACD;AAAA,IACA,CAAC;AAAA,EACF;AAGA,QAAM,cAAc,QAAS,MAAM;AAClC,QAAK,aAAa,SAAU,GAAI,GAAI;AACnC,aAAO;AAAA,IACR;AACA,WAAO,aAAa,KAAM,GAAI;AAAA,EAC/B,GAAG,CAAE,YAAa,CAAE;AAEpB,MAAK,CAAE,QAAS;AACf,WAAO;AAAA,EACR;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,gBAAiB;AAAA,MACjB;AAAA,MACA,WAAY;AAAA,MACZ,kBAAiB;AAAA,MACjB,MAAK;AAAA,MACL,eACC;AAAA,QAAC;AAAA;AAAA,UACA,QAAS;AAAA,UACT,UAAQ;AAAA,UACR,UAAW;AAAA,UACX,uBAAqB;AAAA,UACrB,QAAS,CAAE,EAAE,eAAe,MAC3B;AAAA,YAAC;AAAA;AAAA,cACA,SAAU;AAAA,cACV,MAAO;AAAA,cACP,uBAAqB;AAAA,cAEnB,aAAI,cAAe;AAAA;AAAA,UACtB;AAAA;AAAA,MAEF;AAAA,MAGD;AAAA;AAAA,UAAC;AAAA;AAAA,YACA,aAAc,CAAE,UAAW;AAC1B,kBAAI,gBAAgB;AAEpB,kBAAK,gBAAgB,CAAE,aAAa,SAAU,GAAI,GAAI;AACrD,gCAAgB,MAAM;AAAA,kBAAQ,CAAE,SAC/B,aAAa,KAAM,CAAE,gBAAiB;AAErC,2BACC,KAAK,SAAS,eACd,KAAK,KAAK;AAAA,sBACT,YAAY,QAAS,KAAK,EAAG;AAAA,oBAC9B;AAAA,kBAEF,CAAE;AAAA,gBACH;AAAA,cACD;AACA,kBAAK,cAAc,SAAS,GAAI;AAC/B,6BAAc;AAAA,kBACb;AAAA,kBACA,WAAW;AAAA,gBACZ,CAAE;AAAA,cACH;AAAA,YACD;AAAA,YACA,OAAQ,GAAI,sBAAuB;AAAA;AAAA,QACpC;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACA,MAAO,gBAAgB,CAAC;AAAA,YACxB;AAAA,YACA;AAAA,YACA,cAAe;AAAA,YACf;AAAA,YACA;AAAA,YACA,mBAAoB;AAAA,YACpB;AAAA,YACA;AAAA,YACA;AAAA,YACA,WAAY,CAAE,SAA0B,OAAQ,KAAK,EAAG;AAAA,YACxD;AAAA,YACA;AAAA,YACA,eAAgB,GAAI,aAAc;AAAA;AAAA,QACnC;AAAA;AAAA;AAAA,EACD;AAEF;AAEA,IAAO,6BAAQ;",
4
+ "sourcesContent": ["/**\n * WordPress dependencies\n */\nimport { useState, useCallback, useMemo } 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, useSelect } from '@wordpress/data';\nimport {\n\tModal,\n\tDropZone,\n\tFormFileUpload,\n\tButton,\n\tSnackbarList,\n} from '@wordpress/components';\nimport { upload as uploadIcon } from '@wordpress/icons';\nimport { DataViewsPicker } from '@wordpress/dataviews';\nimport type { View, Field, ActionButton } from '@wordpress/dataviews';\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 } from '@wordpress/notices';\nimport { isBlobURL } from '@wordpress/blob';\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';\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\ninterface MediaUploadModalProps {\n\t/**\n\t * Array of allowed media types.\n\t * @default ['image']\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 = [ 'image' ],\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 {\n\t\tcreateSuccessNotice,\n\t\tcreateErrorNotice,\n\t\tcreateInfoNotice,\n\t\tremoveNotice,\n\t} = useDispatch( noticesStore );\n\t// @ts-expect-error - invalidateResolution is not in the typed actions but is available at runtime\n\tconst { invalidateResolution } = useDispatch( coreStore );\n\n\t// Get notices for this modal context\n\tconst notices = useSelect(\n\t\t( select ) => select( noticesStore ).getNotices( NOTICES_CONTEXT ),\n\t\t[]\n\t);\n\n\t// DataViews configuration - allow view updates\n\tconst [ view, setView ] = useState< View >( () => ( {\n\t\ttype: LAYOUT_PICKER_GRID,\n\t\tfields: [],\n\t\tshowTitle: false,\n\t\ttitleField: 'title',\n\t\tmediaField: 'media_thumbnail',\n\t\tsearch: '',\n\t\tpage: 1,\n\t\tperPage: 20,\n\t\tfilters: [],\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// 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: multiple ? __( 'Select' ) : __( '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\tonSelect( selectedItems );\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t[ multiple, onSelect, selection ]\n\t);\n\n\tconst handleModalClose = useCallback( () => {\n\t\tonClose?.();\n\t}, [ onClose ] );\n\n\t// Use onUpload if provided, otherwise fall back to uploadMedia\n\tconst handleUpload = onUpload || uploadMedia;\n\n\t// Shared upload success handler\n\tconst handleUploadComplete = useCallback(\n\t\t( attachments: Partial< Attachment >[] ) => {\n\t\t\t// Check if all uploads are complete (no blob URLs)\n\t\t\tconst allComplete = attachments.every(\n\t\t\t\t( attachment ) =>\n\t\t\t\t\tattachment.id &&\n\t\t\t\t\tattachment.url &&\n\t\t\t\t\t! isBlobURL( attachment.url )\n\t\t\t);\n\n\t\t\tif ( allComplete && attachments.length > 0 ) {\n\t\t\t\t// Show success notice (replaces progress notice via ID)\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\tattachments.length\n\t\t\t\t\t\t),\n\t\t\t\t\t\tattachments.length.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\n\t\t\t\t// Invalidate the entity records resolution to refresh the view\n\t\t\t\tinvalidateResolution( 'getEntityRecords', [\n\t\t\t\t\t'postType',\n\t\t\t\t\t'attachment',\n\t\t\t\t\tqueryArgs,\n\t\t\t\t] );\n\t\t\t}\n\t\t},\n\t\t[ createSuccessNotice, invalidateResolution, queryArgs ]\n\t);\n\n\t// Shared upload error handler\n\tconst handleUploadError = useCallback(\n\t\t( error: Error ) => {\n\t\t\t// Show error notice (replaces progress notice via ID)\n\t\t\tcreateErrorNotice( error.message, {\n\t\t\t\ttype: 'snackbar',\n\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t} );\n\t\t},\n\t\t[ createErrorNotice ]\n\t);\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\n\t\t\t\t// Show upload start notice\n\t\t\t\tcreateInfoNotice(\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'Uploading %s file',\n\t\t\t\t\t\t\t'Uploading %s files',\n\t\t\t\t\t\t\tfilesArray.length\n\t\t\t\t\t\t),\n\t\t\t\t\t\tfilesArray.length.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\texplicitDismiss: true,\n\t\t\t\t\t}\n\t\t\t\t);\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: handleUploadComplete,\n\t\t\t\t\tonError: handleUploadError,\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\t\t[\n\t\t\tallowedTypes,\n\t\t\thandleUpload,\n\t\t\tcreateInfoNotice,\n\t\t\thandleUploadComplete,\n\t\t\thandleUploadError,\n\t\t]\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\tconst defaultLayouts = useMemo(\n\t\t() => ( {\n\t\t\t[ LAYOUT_PICKER_GRID ]: {\n\t\t\t\tfields: [],\n\t\t\t\tshowTitle: false,\n\t\t\t},\n\t\t\t[ LAYOUT_PICKER_TABLE ]: {\n\t\t\t\tfields: [\n\t\t\t\t\t'filename',\n\t\t\t\t\t'filesize',\n\t\t\t\t\t'media_dimensions',\n\t\t\t\t\t'author',\n\t\t\t\t\t'date',\n\t\t\t\t],\n\t\t\t\tshowTitle: true,\n\t\t\t},\n\t\t} ),\n\t\t[]\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\t// Show upload start notice\n\t\t\t\t\t\tcreateInfoNotice(\n\t\t\t\t\t\t\tsprintf(\n\t\t\t\t\t\t\t\t// translators: %s: number of files\n\t\t\t\t\t\t\t\t_n(\n\t\t\t\t\t\t\t\t\t'Uploading %s file',\n\t\t\t\t\t\t\t\t\t'Uploading %s files',\n\t\t\t\t\t\t\t\t\tfilteredFiles.length\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tfilteredFiles.length.toLocaleString()\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: 'snackbar',\n\t\t\t\t\t\t\t\tcontext: NOTICES_CONTEXT,\n\t\t\t\t\t\t\t\tid: NOTICE_ID_UPLOAD_PROGRESS,\n\t\t\t\t\t\t\t\texplicitDismiss: true,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\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: handleUploadComplete,\n\t\t\t\t\t\t\tonError: handleUploadError,\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={ setView }\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\tsearch={ search }\n\t\t\t\tsearchLabel={ searchLabel }\n\t\t\t\titemListLabel={ __( 'Media items' ) }\n\t\t\t/>\n\t\t\t<SnackbarList\n\t\t\t\tnotices={ notices.filter(\n\t\t\t\t\t( { type } ) => type === 'snackbar'\n\t\t\t\t) }\n\t\t\t\tclassName=\"media-upload-modal__snackbar\"\n\t\t\t\tonRemove={ ( id ) => removeNotice( id, NOTICES_CONTEXT ) }\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
  }
@@ -241,4 +241,11 @@
241
241
  }
242
242
  .media-upload-modal .dataviews-footer {
243
243
  padding-bottom: 8px;
244
+ }
245
+ .media-upload-modal .media-upload-modal__snackbar {
246
+ position: absolute;
247
+ right: 0;
248
+ bottom: 16px;
249
+ padding-right: 16px;
250
+ padding-left: 16px;
244
251
  }
@@ -241,4 +241,11 @@
241
241
  }
242
242
  .media-upload-modal .dataviews-footer {
243
243
  padding-bottom: 8px;
244
+ }
245
+ .media-upload-modal .media-upload-modal__snackbar {
246
+ position: absolute;
247
+ left: 0;
248
+ bottom: 16px;
249
+ padding-left: 16px;
250
+ padding-right: 16px;
244
251
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media-upload-modal/index.tsx"],"names":[],"mappings":"AA6BA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAWpE,UAAU,qBAAqB;IAC9B;;;OAGG;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,YAA0B,EAC1B,QAAgB,EAChB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,KAA4B,EAC5B,MAAM,EACN,aAAoB,EACpB,UAAU,EACV,MAAa,EACb,WAAkC,GAClC,EAAE,qBAAqB,sCA6RvB;AAED,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media-upload-modal/index.tsx"],"names":[],"mappings":"AAqCA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAkB,MAAM,mBAAmB,CAAC;AAiBpE,UAAU,qBAAqB;IAC9B;;;OAGG;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,YAA0B,EAC1B,QAAgB,EAChB,KAAK,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,KAA4B,EAC5B,MAAM,EACN,aAAoB,EACpB,UAAU,EACV,MAAa,EACb,WAAkC,GAClC,EAAE,qBAAqB,sCA0ZvB;AAED,eAAe,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/media-utils",
3
- "version": "5.38.0",
3
+ "version": "5.39.0",
4
4
  "description": "WordPress Media Upload Utils.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -47,18 +47,19 @@
47
47
  "build-style/**"
48
48
  ],
49
49
  "dependencies": {
50
- "@wordpress/api-fetch": "^7.38.0",
51
- "@wordpress/base-styles": "^6.14.0",
52
- "@wordpress/blob": "^4.38.0",
53
- "@wordpress/components": "^32.0.0",
54
- "@wordpress/core-data": "^7.38.0",
55
- "@wordpress/data": "^10.38.0",
56
- "@wordpress/dataviews": "^11.2.0",
57
- "@wordpress/element": "^6.38.0",
58
- "@wordpress/i18n": "^6.11.0",
59
- "@wordpress/icons": "^11.5.0",
60
- "@wordpress/media-fields": "^0.3.0",
61
- "@wordpress/private-apis": "^1.38.0"
50
+ "@wordpress/api-fetch": "^7.39.0",
51
+ "@wordpress/base-styles": "^6.15.0",
52
+ "@wordpress/blob": "^4.39.0",
53
+ "@wordpress/components": "^32.1.0",
54
+ "@wordpress/core-data": "^7.39.0",
55
+ "@wordpress/data": "^10.39.0",
56
+ "@wordpress/dataviews": "^11.3.0",
57
+ "@wordpress/element": "^6.39.0",
58
+ "@wordpress/i18n": "^6.12.0",
59
+ "@wordpress/icons": "^11.6.0",
60
+ "@wordpress/media-fields": "^0.4.0",
61
+ "@wordpress/notices": "^5.39.0",
62
+ "@wordpress/private-apis": "^1.39.0"
62
63
  },
63
64
  "peerDependencies": {
64
65
  "react": "^18.0.0"
@@ -66,5 +67,5 @@
66
67
  "publishConfig": {
67
68
  "access": "public"
68
69
  },
69
- "gitHead": "50c4c0f51e4797c217946ce42adfaa5eb026f33f"
70
+ "gitHead": "eee1cfb1472f11183e40fb77465a5f13145df7ad"
70
71
  }
@@ -294,7 +294,7 @@ class MediaUpload extends Component {
294
294
  value = DEFAULT_EMPTY_GALLERY,
295
295
  } = this.props;
296
296
 
297
- // If the value did not changed there is no need to rebuild the frame,
297
+ // If the value did not change there is no need to rebuild the frame,
298
298
  // we can continue to use the existing one.
299
299
  if ( value === this.lastGalleryValue ) {
300
300
  return;
@@ -2,13 +2,19 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useState, useCallback, useMemo } from '@wordpress/element';
5
- import { __ } from '@wordpress/i18n';
5
+ import { __, sprintf, _n } from '@wordpress/i18n';
6
6
  import {
7
7
  privateApis as coreDataPrivateApis,
8
8
  store as coreStore,
9
9
  } from '@wordpress/core-data';
10
- import { resolveSelect } from '@wordpress/data';
11
- import { Modal, DropZone, FormFileUpload, Button } from '@wordpress/components';
10
+ import { resolveSelect, useDispatch, useSelect } from '@wordpress/data';
11
+ import {
12
+ Modal,
13
+ DropZone,
14
+ FormFileUpload,
15
+ Button,
16
+ SnackbarList,
17
+ } from '@wordpress/components';
12
18
  import { upload as uploadIcon } from '@wordpress/icons';
13
19
  import { DataViewsPicker } from '@wordpress/dataviews';
14
20
  import type { View, Field, ActionButton } from '@wordpress/dataviews';
@@ -26,6 +32,8 @@ import {
26
32
  mediaThumbnailField,
27
33
  mimeTypeField,
28
34
  } from '@wordpress/media-fields';
35
+ import { store as noticesStore } from '@wordpress/notices';
36
+ import { isBlobURL } from '@wordpress/blob';
29
37
 
30
38
  /**
31
39
  * Internal dependencies
@@ -41,6 +49,12 @@ const { useEntityRecordsWithPermissions } = unlock( coreDataPrivateApis );
41
49
  const LAYOUT_PICKER_GRID = 'pickerGrid';
42
50
  const LAYOUT_PICKER_TABLE = 'pickerTable';
43
51
 
52
+ // Custom notices context for the media modal
53
+ const NOTICES_CONTEXT = 'media-modal';
54
+
55
+ // Notice ID - reused for all upload-related notices to prevent flooding
56
+ const NOTICE_ID_UPLOAD_PROGRESS = 'media-modal-upload-progress';
57
+
44
58
  interface MediaUploadModalProps {
45
59
  /**
46
60
  * Array of allowed media types.
@@ -161,6 +175,21 @@ export function MediaUploadModal( {
161
175
  : [ String( value ) ];
162
176
  } );
163
177
 
178
+ const {
179
+ createSuccessNotice,
180
+ createErrorNotice,
181
+ createInfoNotice,
182
+ removeNotice,
183
+ } = useDispatch( noticesStore );
184
+ // @ts-expect-error - invalidateResolution is not in the typed actions but is available at runtime
185
+ const { invalidateResolution } = useDispatch( coreStore );
186
+
187
+ // Get notices for this modal context
188
+ const notices = useSelect(
189
+ ( select ) => select( noticesStore ).getNotices( NOTICES_CONTEXT ),
190
+ []
191
+ );
192
+
164
193
  // DataViews configuration - allow view updates
165
194
  const [ view, setView ] = useState< View >( () => ( {
166
195
  type: LAYOUT_PICKER_GRID,
@@ -312,18 +341,100 @@ export function MediaUploadModal( {
312
341
  // Use onUpload if provided, otherwise fall back to uploadMedia
313
342
  const handleUpload = onUpload || uploadMedia;
314
343
 
344
+ // Shared upload success handler
345
+ const handleUploadComplete = useCallback(
346
+ ( attachments: Partial< Attachment >[] ) => {
347
+ // Check if all uploads are complete (no blob URLs)
348
+ const allComplete = attachments.every(
349
+ ( attachment ) =>
350
+ attachment.id &&
351
+ attachment.url &&
352
+ ! isBlobURL( attachment.url )
353
+ );
354
+
355
+ if ( allComplete && attachments.length > 0 ) {
356
+ // Show success notice (replaces progress notice via ID)
357
+ createSuccessNotice(
358
+ sprintf(
359
+ // translators: %s: number of files
360
+ _n(
361
+ 'Uploaded %s file',
362
+ 'Uploaded %s files',
363
+ attachments.length
364
+ ),
365
+ attachments.length.toLocaleString()
366
+ ),
367
+ {
368
+ type: 'snackbar',
369
+ context: NOTICES_CONTEXT,
370
+ id: NOTICE_ID_UPLOAD_PROGRESS,
371
+ }
372
+ );
373
+
374
+ // Invalidate the entity records resolution to refresh the view
375
+ invalidateResolution( 'getEntityRecords', [
376
+ 'postType',
377
+ 'attachment',
378
+ queryArgs,
379
+ ] );
380
+ }
381
+ },
382
+ [ createSuccessNotice, invalidateResolution, queryArgs ]
383
+ );
384
+
385
+ // Shared upload error handler
386
+ const handleUploadError = useCallback(
387
+ ( error: Error ) => {
388
+ // Show error notice (replaces progress notice via ID)
389
+ createErrorNotice( error.message, {
390
+ type: 'snackbar',
391
+ context: NOTICES_CONTEXT,
392
+ id: NOTICE_ID_UPLOAD_PROGRESS,
393
+ } );
394
+ },
395
+ [ createErrorNotice ]
396
+ );
397
+
315
398
  const handleFileSelect = useCallback(
316
399
  ( event: React.ChangeEvent< HTMLInputElement > ) => {
317
400
  const files = event.target.files;
318
401
  if ( files && files.length > 0 ) {
319
402
  const filesArray = Array.from( files );
403
+
404
+ // Show upload start notice
405
+ createInfoNotice(
406
+ sprintf(
407
+ // translators: %s: number of files
408
+ _n(
409
+ 'Uploading %s file',
410
+ 'Uploading %s files',
411
+ filesArray.length
412
+ ),
413
+ filesArray.length.toLocaleString()
414
+ ),
415
+ {
416
+ type: 'snackbar',
417
+ context: NOTICES_CONTEXT,
418
+ id: NOTICE_ID_UPLOAD_PROGRESS,
419
+ explicitDismiss: true,
420
+ }
421
+ );
422
+
320
423
  handleUpload( {
321
424
  allowedTypes,
322
425
  filesList: filesArray,
426
+ onFileChange: handleUploadComplete,
427
+ onError: handleUploadError,
323
428
  } );
324
429
  }
325
430
  },
326
- [ allowedTypes, handleUpload ]
431
+ [
432
+ allowedTypes,
433
+ handleUpload,
434
+ createInfoNotice,
435
+ handleUploadComplete,
436
+ handleUploadError,
437
+ ]
327
438
  );
328
439
 
329
440
  const paginationInfo = useMemo(
@@ -410,9 +521,30 @@ export function MediaUploadModal( {
410
521
  );
411
522
  }
412
523
  if ( filteredFiles.length > 0 ) {
524
+ // Show upload start notice
525
+ createInfoNotice(
526
+ sprintf(
527
+ // translators: %s: number of files
528
+ _n(
529
+ 'Uploading %s file',
530
+ 'Uploading %s files',
531
+ filteredFiles.length
532
+ ),
533
+ filteredFiles.length.toLocaleString()
534
+ ),
535
+ {
536
+ type: 'snackbar',
537
+ context: NOTICES_CONTEXT,
538
+ id: NOTICE_ID_UPLOAD_PROGRESS,
539
+ explicitDismiss: true,
540
+ }
541
+ );
542
+
413
543
  handleUpload( {
414
544
  allowedTypes,
415
545
  filesList: filteredFiles,
546
+ onFileChange: handleUploadComplete,
547
+ onError: handleUploadError,
416
548
  } );
417
549
  }
418
550
  } }
@@ -434,6 +566,13 @@ export function MediaUploadModal( {
434
566
  searchLabel={ searchLabel }
435
567
  itemListLabel={ __( 'Media items' ) }
436
568
  />
569
+ <SnackbarList
570
+ notices={ notices.filter(
571
+ ( { type } ) => type === 'snackbar'
572
+ ) }
573
+ className="media-upload-modal__snackbar"
574
+ onRemove={ ( id ) => removeNotice( id, NOTICES_CONTEXT ) }
575
+ />
437
576
  </Modal>
438
577
  );
439
578
  }
@@ -20,4 +20,12 @@
20
20
  .dataviews-footer {
21
21
  padding-bottom: $grid-unit-10;
22
22
  }
23
+
24
+ .media-upload-modal__snackbar {
25
+ position: absolute;
26
+ left: 0;
27
+ bottom: 16px;
28
+ padding-left: 16px;
29
+ padding-right: 16px;
30
+ }
23
31
  }