Move file picker by clicking card into the MediaUploader component (#35738)
* Fix `MediaUploader` component * Fix storybook * Fix image section * Add changelogs * Fix code comment * Fix text Co-authored-by: Fernando Marichal <contacto@fernandomarichal.com>
This commit is contained in:
parent
f16cfbc9d6
commit
716d5ab322
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Move file picker by clicking card into the MediaUploader component
|
|
@ -2,7 +2,7 @@
|
|||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Button, DropZone } from '@wordpress/components';
|
||||
import { Button, DropZone, FormFileUpload } from '@wordpress/components';
|
||||
import { createElement } from 'react';
|
||||
import {
|
||||
MediaItem,
|
||||
|
@ -32,6 +32,7 @@ type MediaUploaderProps = {
|
|||
file: File;
|
||||
} ) => void;
|
||||
onUpload?: ( files: MediaItem[] ) => void;
|
||||
onFileUploadChange?: ( files: MediaItem[] ) => void;
|
||||
uploadMedia?: ( options: UploadMediaOptions ) => Promise< void >;
|
||||
};
|
||||
|
||||
|
@ -43,36 +44,74 @@ export const MediaUploader = ( {
|
|||
maxUploadFileSize = 10000000,
|
||||
MediaUploadComponent = MediaUpload,
|
||||
onError = () => null,
|
||||
onFileUploadChange = () => null,
|
||||
onUpload = () => null,
|
||||
onSelect = () => null,
|
||||
uploadMedia = wpUploadMedia,
|
||||
}: MediaUploaderProps ) => {
|
||||
const getFormFileUploadAcceptedFiles = () =>
|
||||
allowedMediaTypes.map( ( type ) => `${ type }/*` );
|
||||
|
||||
return (
|
||||
<div className="woocommerce-media-uploader">
|
||||
<div className="woocommerce-media-uploader__label">{ label }</div>
|
||||
<FormFileUpload
|
||||
accept={ getFormFileUploadAcceptedFiles().toString() }
|
||||
multiple={ true }
|
||||
onChange={ ( { currentTarget } ) => {
|
||||
uploadMedia( {
|
||||
filesList: currentTarget.files as FileList,
|
||||
onError,
|
||||
onFileChange: onFileUploadChange,
|
||||
maxUploadFileSize,
|
||||
} );
|
||||
} }
|
||||
render={ ( { openFileDialog } ) => (
|
||||
<div
|
||||
className="woocommerce-form-file-upload"
|
||||
onKeyPress={ () => {} }
|
||||
tabIndex={ 0 }
|
||||
role="button"
|
||||
onClick={ (
|
||||
event: React.MouseEvent< HTMLDivElement, MouseEvent >
|
||||
) => {
|
||||
const { target } = event;
|
||||
if (
|
||||
( target as HTMLButtonElement )?.type !== 'button'
|
||||
) {
|
||||
openFileDialog();
|
||||
}
|
||||
} }
|
||||
onBlur={ () => {} }
|
||||
>
|
||||
<div className="woocommerce-media-uploader">
|
||||
<div className="woocommerce-media-uploader__label">
|
||||
{ label }
|
||||
</div>
|
||||
|
||||
<MediaUploadComponent
|
||||
onSelect={ onSelect }
|
||||
allowedTypes={ allowedMediaTypes }
|
||||
render={ ( { open } ) => (
|
||||
<Button variant="secondary" onClick={ open }>
|
||||
{ buttonText }
|
||||
</Button>
|
||||
) }
|
||||
/>
|
||||
<MediaUploadComponent
|
||||
onSelect={ onSelect }
|
||||
allowedTypes={ allowedMediaTypes }
|
||||
render={ ( { open } ) => (
|
||||
<Button variant="secondary" onClick={ open }>
|
||||
{ buttonText }
|
||||
</Button>
|
||||
) }
|
||||
/>
|
||||
|
||||
{ hasDropZone && (
|
||||
<DropZone
|
||||
onFilesDrop={ ( files ) =>
|
||||
uploadMedia( {
|
||||
filesList: files,
|
||||
onError,
|
||||
onFileChange: onUpload,
|
||||
maxUploadFileSize,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
{ hasDropZone && (
|
||||
<DropZone
|
||||
onFilesDrop={ ( files ) =>
|
||||
uploadMedia( {
|
||||
filesList: files,
|
||||
onError,
|
||||
onFileChange: onUpload,
|
||||
maxUploadFileSize,
|
||||
} )
|
||||
}
|
||||
/>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ declare let Blob: {
|
|||
new (): Blob;
|
||||
};
|
||||
|
||||
export const MockMediaUpload = ( { onSelect, render } ) => {
|
||||
const MockMediaUpload = ( { onSelect, render } ) => {
|
||||
const [ isOpen, setOpen ] = useState( false );
|
||||
|
||||
return (
|
||||
|
@ -28,7 +28,10 @@ export const MockMediaUpload = ( { onSelect, render } ) => {
|
|||
{ isOpen && (
|
||||
<Modal
|
||||
title="Media Modal"
|
||||
onRequestClose={ () => setOpen( false ) }
|
||||
onRequestClose={ ( event ) => {
|
||||
setOpen( false );
|
||||
event.stopPropagation();
|
||||
} }
|
||||
>
|
||||
<p>
|
||||
Use the default built-in{ ' ' }
|
||||
|
@ -39,12 +42,13 @@ export const MockMediaUpload = ( { onSelect, render } ) => {
|
|||
return (
|
||||
<button
|
||||
key={ i }
|
||||
onClick={ () => {
|
||||
onClick={ ( event ) => {
|
||||
onSelect( {
|
||||
alt: 'Random',
|
||||
url: `https://picsum.photos/200?i=${ i }`,
|
||||
} );
|
||||
setOpen( false );
|
||||
event.stopPropagation();
|
||||
} }
|
||||
style={ {
|
||||
marginRight: '16px',
|
||||
|
@ -101,8 +105,19 @@ const readImage = ( file: Blob ) => {
|
|||
};
|
||||
|
||||
const mockUploadMedia = async ( { filesList, onFileChange } ) => {
|
||||
// The values sent by the FormFileUpload and the DropZone components are different.
|
||||
// This is why we need to transform everything into an array.
|
||||
const list = await Object.keys( filesList ).map(
|
||||
( key ) => filesList[ key ]
|
||||
);
|
||||
|
||||
const images = await Promise.all(
|
||||
filesList.map( ( file ) => readImage( file ) )
|
||||
list.map( ( file ) => {
|
||||
if ( typeof file === 'object' ) {
|
||||
return readImage( file );
|
||||
}
|
||||
return {};
|
||||
} )
|
||||
);
|
||||
onFileChange( images );
|
||||
};
|
||||
|
@ -118,6 +133,9 @@ export const Basic: React.FC = () => {
|
|||
MediaUploadComponent={ MockMediaUpload }
|
||||
onSelect={ ( file ) => setImages( [ ...images, file ] ) }
|
||||
onError={ () => null }
|
||||
onFileUploadChange={ ( files ) =>
|
||||
setImages( [ ...images, ...files ] )
|
||||
}
|
||||
onUpload={ ( files ) =>
|
||||
setImages( [ ...images, ...files ] )
|
||||
}
|
||||
|
@ -139,6 +157,9 @@ export const DisabledDropZone: React.FC = () => {
|
|||
hasDropZone={ false }
|
||||
label={ 'Click the button below to upload' }
|
||||
MediaUploadComponent={ MockMediaUpload }
|
||||
onFileUploadChange={ ( files ) =>
|
||||
setImages( [ ...images, ...files ] )
|
||||
}
|
||||
onSelect={ ( file ) => setImages( [ ...images, file ] ) }
|
||||
onError={ () => null }
|
||||
uploadMedia={ mockUploadMedia }
|
||||
|
|
|
@ -9,18 +9,13 @@ import {
|
|||
ImageGallery,
|
||||
ImageGalleryItem,
|
||||
} from '@woocommerce/components';
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
DropZone,
|
||||
FormFileUpload,
|
||||
} from '@wordpress/components';
|
||||
import { Card, CardBody, DropZone } from '@wordpress/components';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { useState } from '@wordpress/element';
|
||||
import { Product } from '@woocommerce/data';
|
||||
import classnames from 'classnames';
|
||||
import { Icon, trash } from '@wordpress/icons';
|
||||
import { MediaItem, uploadMedia } from '@wordpress/media-utils';
|
||||
import { MediaItem } from '@wordpress/media-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
|
@ -42,7 +37,6 @@ export const ImagesSection: React.FC = () => {
|
|||
const [ draggedImageId, setDraggedImageId ] = useState< number | null >(
|
||||
null
|
||||
);
|
||||
const ALLOWED_MEDIA_TYPES = 'image';
|
||||
|
||||
const toggleRemoveZone = () => {
|
||||
setIsRemovingZoneVisible( ! isRemovingZoneVisible );
|
||||
|
@ -185,89 +179,53 @@ export const ImagesSection: React.FC = () => {
|
|||
</CardBody>
|
||||
) : (
|
||||
<CardBody>
|
||||
<FormFileUpload
|
||||
accept={ ALLOWED_MEDIA_TYPES }
|
||||
multiple={ true }
|
||||
onChange={ ( { currentTarget } ) => {
|
||||
uploadMedia( {
|
||||
filesList:
|
||||
currentTarget.files as FileList,
|
||||
onError: () => null,
|
||||
onFileChange: onFileUpload,
|
||||
maxUploadFileSize: 10000000,
|
||||
} );
|
||||
<MediaUploader
|
||||
onError={ () => null }
|
||||
onFileUploadChange={ onFileUpload }
|
||||
onSelect={ ( file ) => {
|
||||
if (
|
||||
images.find(
|
||||
( img ) => file.id === img.id
|
||||
) === undefined
|
||||
) {
|
||||
recordEvent(
|
||||
'product_images_add_via_media_library'
|
||||
);
|
||||
setValue( 'images', [
|
||||
...images,
|
||||
file,
|
||||
] );
|
||||
}
|
||||
} }
|
||||
render={ ( { openFileDialog } ) => (
|
||||
<div
|
||||
className="woocommerce-form-file-upload"
|
||||
onKeyPress={ () => {} }
|
||||
tabIndex={ 0 }
|
||||
role="button"
|
||||
onClick={ (
|
||||
event: React.MouseEvent<
|
||||
HTMLDivElement,
|
||||
MouseEvent
|
||||
>
|
||||
) => {
|
||||
const { target } = event;
|
||||
if (
|
||||
(
|
||||
target as HTMLButtonElement
|
||||
)?.type !== 'button'
|
||||
) {
|
||||
openFileDialog();
|
||||
}
|
||||
} }
|
||||
onBlur={ () => {} }
|
||||
>
|
||||
<MediaUploader
|
||||
onError={ () => null }
|
||||
onSelect={ ( file ) => {
|
||||
if (
|
||||
images.find(
|
||||
( img ) =>
|
||||
file.id ===
|
||||
img.id
|
||||
) === undefined
|
||||
) {
|
||||
recordEvent(
|
||||
'product_images_add_via_media_library'
|
||||
);
|
||||
setValue( 'images', [
|
||||
...images,
|
||||
file,
|
||||
] );
|
||||
}
|
||||
} }
|
||||
onUpload={ ( files ) => {
|
||||
if ( files[ 0 ].id ) {
|
||||
recordEvent(
|
||||
'product_images_add_via_drag_and_drop_upload'
|
||||
);
|
||||
setValue( 'images', [
|
||||
...images,
|
||||
...files,
|
||||
] );
|
||||
}
|
||||
} }
|
||||
label={
|
||||
<>
|
||||
<img
|
||||
src={ DragAndDrop }
|
||||
alt="Completed"
|
||||
className="woocommerce-product-form__drag-and-drop-image"
|
||||
/>
|
||||
<span>
|
||||
{ __(
|
||||
'Drag images here or click to upload',
|
||||
'woocommerce'
|
||||
) }
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
onUpload={ ( files ) => {
|
||||
if ( files[ 0 ].id ) {
|
||||
recordEvent(
|
||||
'product_images_add_via_drag_and_drop_upload'
|
||||
);
|
||||
setValue( 'images', [
|
||||
...images,
|
||||
...files,
|
||||
] );
|
||||
}
|
||||
} }
|
||||
label={
|
||||
<>
|
||||
<img
|
||||
src={ DragAndDrop }
|
||||
alt={ __(
|
||||
'Completed',
|
||||
'woocommerce'
|
||||
) }
|
||||
className="woocommerce-product-form__drag-and-drop-image"
|
||||
/>
|
||||
</div>
|
||||
) }
|
||||
<span>
|
||||
{ __(
|
||||
'Drag images here or click to upload',
|
||||
'woocommerce'
|
||||
) }
|
||||
</span>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</CardBody>
|
||||
) }
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Move file picker by clicking card into the MediaUploader component
|
Loading…
Reference in New Issue