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:
Fernando Marichal 2022-11-30 09:00:14 -03:00 committed by GitHub
parent f16cfbc9d6
commit 716d5ab322
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 143 additions and 117 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Move file picker by clicking card into the MediaUploader component

View File

@ -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>
/>
);
};

View File

@ -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 }

View File

@ -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>
) }

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Move file picker by clicking card into the MediaUploader component