@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 +2 -0
- package/build/components/media-upload/index.cjs.map +1 -1
- package/build/components/media-upload-modal/index.cjs +113 -3
- package/build/components/media-upload-modal/index.cjs.map +3 -3
- package/build-module/components/media-upload/index.mjs.map +1 -1
- package/build-module/components/media-upload-modal/index.mjs +122 -6
- package/build-module/components/media-upload-modal/index.mjs.map +2 -2
- package/build-style/style-rtl.css +7 -0
- package/build-style/style.css +7 -0
- package/build-types/components/media-upload-modal/index.d.ts.map +1 -1
- package/package.json +15 -14
- package/src/components/media-upload/index.js +1 -1
- package/src/components/media-upload-modal/index.tsx +143 -4
- package/src/components/media-upload-modal/style.scss +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -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
|
-
[
|
|
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": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA+C;AAC/C,
|
|
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": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,qBAA+C;AAC/C,kBAAgC;AAChC,uBAGO;AACP,kBAAsD;AACtD,wBAMO;AACP,mBAAqC;AACrC,uBAAgC;AAEhC,0BAaO;AACP,qBAAsC;AACtC,kBAA0B;AAM1B,kCAAoC;AACpC,0BAA4B;AAC5B,yBAAuB;AAqbrB;AAnbF,IAAM,EAAE,gCAAgC,QAAI,2BAAQ,iBAAAA,WAAoB;AAGxE,IAAM,qBAAqB;AAC3B,IAAM,sBAAsB;AAG5B,IAAM,kBAAkB;AAGxB,IAAM,4BAA4B;AAmG3B,SAAS,iBAAkB;AAAA,EACjC,eAAe,CAAE,OAAQ;AAAA,EACzB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAQ,gBAAI,cAAe;AAAA,EAC3B;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA,SAAS;AAAA,EACT,kBAAc,gBAAI,cAAe;AAClC,GAA2B;AAC1B,QAAM,CAAE,WAAW,YAAa,QAAI,yBAAsB,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;AAEF,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,QAAI,yBAAa,eAAAC,KAAa;AAE9B,QAAM,EAAE,qBAAqB,QAAI,yBAAa,iBAAAC,KAAU;AAGxD,QAAM,cAAU;AAAA,IACf,CAAE,WAAY,OAAQ,eAAAD,KAAa,EAAE,WAAY,eAAgB;AAAA,IACjE,CAAC;AAAA,EACF;AAGA,QAAM,CAAE,MAAM,OAAQ,QAAI,yBAAkB,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,gBAAY,wBAAS,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,aAAoC;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,WAAO,gBAAI,OAAQ;AAAA,QACnB,UAAU,CAAE,EAAE,KAAK,MAAiC;AACnD,gBAAM,aAAa,KAAK,MAAM,OAAO,KAAK,MAAM;AAChD,iBAAO,kBAAc,gBAAI,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,cAA4C;AAAA,IACjD,MAAM;AAAA,MACL;AAAA,QACC,IAAI;AAAA,QACJ,OAAO,eAAW,gBAAI,QAAS,QAAI,gBAAI,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,UAAM;AAAA,YAC3B,iBAAAC;AAAA,UACD,EAAE;AAAA,YACD;AAAA,YACA;AAAA,YACA;AAAA,UACD;AAGA,gBAAM,oBAAqB,iBAAiB,CAAC,GAC3C,IAAK,+CAAoB,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,uBAAmB,4BAAa,MAAM;AAC3C,cAAU;AAAA,EACX,GAAG,CAAE,OAAQ,CAAE;AAGf,QAAM,eAAe,YAAY;AAGjC,QAAM,2BAAuB;AAAA,IAC5B,CAAE,gBAA0C;AAE3C,YAAM,cAAc,YAAY;AAAA,QAC/B,CAAE,eACD,WAAW,MACX,WAAW,OACX,KAAE,uBAAW,WAAW,GAAI;AAAA,MAC9B;AAEA,UAAK,eAAe,YAAY,SAAS,GAAI;AAE5C;AAAA,cACC;AAAA;AAAA,gBAEC;AAAA,cACC;AAAA,cACA;AAAA,cACA,YAAY;AAAA,YACb;AAAA,YACA,YAAY,OAAO,eAAe;AAAA,UACnC;AAAA,UACA;AAAA,YACC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,IAAI;AAAA,UACL;AAAA,QACD;AAGA,6BAAsB,oBAAoB;AAAA,UACzC;AAAA,UACA;AAAA,UACA;AAAA,QACD,CAAE;AAAA,MACH;AAAA,IACD;AAAA,IACA,CAAE,qBAAqB,sBAAsB,SAAU;AAAA,EACxD;AAGA,QAAM,wBAAoB;AAAA,IACzB,CAAE,UAAkB;AAEnB,wBAAmB,MAAM,SAAS;AAAA,QACjC,MAAM;AAAA,QACN,SAAS;AAAA,QACT,IAAI;AAAA,MACL,CAAE;AAAA,IACH;AAAA,IACA,CAAE,iBAAkB;AAAA,EACrB;AAEA,QAAM,uBAAmB;AAAA,IACxB,CAAE,UAAkD;AACnD,YAAM,QAAQ,MAAM,OAAO;AAC3B,UAAK,SAAS,MAAM,SAAS,GAAI;AAChC,cAAM,aAAa,MAAM,KAAM,KAAM;AAGrC;AAAA,cACC;AAAA;AAAA,gBAEC;AAAA,cACC;AAAA,cACA;AAAA,cACA,WAAW;AAAA,YACZ;AAAA,YACA,WAAW,OAAO,eAAe;AAAA,UAClC;AAAA,UACA;AAAA,YACC,MAAM;AAAA,YACN,SAAS;AAAA,YACT,IAAI;AAAA,YACJ,iBAAiB;AAAA,UAClB;AAAA,QACD;AAEA,qBAAc;AAAA,UACb;AAAA,UACA,WAAW;AAAA,UACX,cAAc;AAAA,UACd,SAAS;AAAA,QACV,CAAE;AAAA,MACH;AAAA,IACD;AAAA,IACA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAEA,QAAM,qBAAiB;AAAA,IACtB,OAAQ;AAAA,MACP;AAAA,MACA;AAAA,IACD;AAAA,IACA,CAAE,YAAY,UAAW;AAAA,EAC1B;AAEA,QAAM,qBAAiB;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,kBAAc,wBAAS,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,aAAAC;AAAA,cACP,uBAAqB;AAAA,cAEnB,8BAAI,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;AAE/B;AAAA,sBACC;AAAA;AAAA,wBAEC;AAAA,sBACC;AAAA,sBACA;AAAA,sBACA,cAAc;AAAA,oBACf;AAAA,oBACA,cAAc,OAAO,eAAe;AAAA,kBACrC;AAAA,kBACA;AAAA,oBACC,MAAM;AAAA,oBACN,SAAS;AAAA,oBACT,IAAI;AAAA,oBACJ,iBAAiB;AAAA,kBAClB;AAAA,gBACD;AAEA,6BAAc;AAAA,kBACb;AAAA,kBACA,WAAW;AAAA,kBACX,cAAc;AAAA,kBACd,SAAS;AAAA,gBACV,CAAE;AAAA,cACH;AAAA,YACD;AAAA,YACA,WAAQ,gBAAI,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,mBAAgB,gBAAI,aAAc;AAAA;AAAA,QACnC;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACA,SAAU,QAAQ;AAAA,cACjB,CAAE,EAAE,KAAK,MAAO,SAAS;AAAA,YAC1B;AAAA,YACA,WAAU;AAAA,YACV,UAAW,CAAE,OAAQ,aAAc,IAAI,eAAgB;AAAA;AAAA,QACxD;AAAA;AAAA;AAAA,EACD;AAEF;AAEA,IAAO,6BAAQ;",
|
|
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 {
|
|
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
|
-
[
|
|
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;
|
|
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
|
}
|
package/build-style/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/media-upload-modal/index.tsx"],"names":[],"mappings":"
|
|
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.
|
|
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.
|
|
51
|
-
"@wordpress/base-styles": "^6.
|
|
52
|
-
"@wordpress/blob": "^4.
|
|
53
|
-
"@wordpress/components": "^32.
|
|
54
|
-
"@wordpress/core-data": "^7.
|
|
55
|
-
"@wordpress/data": "^10.
|
|
56
|
-
"@wordpress/dataviews": "^11.
|
|
57
|
-
"@wordpress/element": "^6.
|
|
58
|
-
"@wordpress/i18n": "^6.
|
|
59
|
-
"@wordpress/icons": "^11.
|
|
60
|
-
"@wordpress/media-fields": "^0.
|
|
61
|
-
"@wordpress/
|
|
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": "
|
|
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
|
|
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 {
|
|
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
|
-
[
|
|
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
|
}
|