Skip to content

Commit

Permalink
Add new private upload-media package (#66290)
Browse files Browse the repository at this point in the history
Co-authored-by: ndiego <[email protected]>
Co-authored-by: fabiankaegy <[email protected]>
Co-authored-by: carolinan <[email protected]>
Co-authored-by: Jon Surrell <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: sirreal <[email protected]>
Co-authored-by: Andrew Serong <[email protected]>
Co-authored-by: stokesman <[email protected]>
Co-authored-by: andrewserong <[email protected]>
Co-authored-by: ramonjd <[email protected]>
Co-authored-by: ntsekouras <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: youknowriad <[email protected]>
Co-authored-by: Nick Diego <[email protected]>
Co-authored-by: Ella <[email protected]>
Co-authored-by: Aki Hamano <[email protected]>
Co-authored-by: Mitchell Austin <[email protected]>
Co-authored-by: Nik Tsekouras <[email protected]>
Co-authored-by: George Mamadashvili <[email protected]>
  • Loading branch information
20 people authored Dec 16, 2024
1 parent 7244968 commit 2d7f2d8
Show file tree
Hide file tree
Showing 50 changed files with 2,813 additions and 16 deletions.
2 changes: 1 addition & 1 deletion bin/check-licenses.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { spawnSync } from 'node:child_process';
*/
import { checkDepsInTree } from '../packages/scripts/utils/license.js';

const ignored = [ '@ampproject/remapping' ];
const ignored = [ '@ampproject/remapping', 'webpack' ];

/*
* `wp-scripts check-licenses` uses prod and dev dependencies of the package to scan for dependencies. With npm workspaces, workspace packages (the @wordpress/* packages) are not listed in the main package json and this approach does not work.
Expand Down
60 changes: 60 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 81 additions & 4 deletions packages/block-editor/src/components/provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
* WordPress dependencies
*/
import { useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { useEffect, useMemo } from '@wordpress/element';
import { SlotFillProvider } from '@wordpress/components';
//eslint-disable-next-line import/no-extraneous-dependencies -- Experimental package, not published.
import {
MediaUploadProvider,
store as uploadStore,
} from '@wordpress/upload-media';

/**
* Internal dependencies
Expand All @@ -14,12 +19,71 @@ import { store as blockEditorStore } from '../../store';
import { BlockRefsProvider } from './block-refs-provider';
import { unlock } from '../../lock-unlock';
import KeyboardShortcuts from '../keyboard-shortcuts';
import useMediaUploadSettings from './use-media-upload-settings';

/** @typedef {import('@wordpress/data').WPDataRegistry} WPDataRegistry */

const noop = () => {};

/**
* Upload a media file when the file upload button is activated
* or when adding a file to the editor via drag & drop.
*
* @param {WPDataRegistry} registry
* @param {Object} $3 Parameters object passed to the function.
* @param {Array} $3.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.
* @param {Object} $3.additionalData Additional data to include in the request.
* @param {Array<File>} $3.filesList List of files.
* @param {Function} $3.onError Function called when an error happens.
* @param {Function} $3.onFileChange Function called each time a file or a temporary representation of the file is available.
* @param {Function} $3.onSuccess Function called once a file has completely finished uploading, including thumbnails.
* @param {Function} $3.onBatchSuccess Function called once all files in a group have completely finished uploading, including thumbnails.
*/
function mediaUpload(
registry,
{
allowedTypes,
additionalData = {},
filesList,
onError = noop,
onFileChange,
onSuccess,
onBatchSuccess,
}
) {
void registry.dispatch( uploadStore ).addItems( {
files: filesList,
onChange: onFileChange,
onSuccess,
onBatchSuccess,
onError: ( { message } ) => onError( message ),
additionalData,
allowedTypes,
} );
}

export const ExperimentalBlockEditorProvider = withRegistryProvider(
( props ) => {
const { children, settings, stripExperimentalSettings = false } = props;
const {
settings: _settings,
registry,
stripExperimentalSettings = false,
} = props;

const mediaUploadSettings = useMediaUploadSettings( _settings );

let settings = _settings;

if ( window.__experimentalMediaProcessing && _settings.mediaUpload ) {
// Create a new variable so that the original props.settings.mediaUpload is not modified.
settings = useMemo(
() => ( {
..._settings,
mediaUpload: mediaUpload.bind( null, registry ),
} ),
[ _settings, registry ]
);
}

const { __experimentalUpdateSettings } = unlock(
useDispatch( blockEditorStore )
Expand All @@ -44,12 +108,25 @@ export const ExperimentalBlockEditorProvider = withRegistryProvider(
// Syncs the entity provider with changes in the block-editor store.
useBlockSync( props );

return (
const children = (
<SlotFillProvider passthrough>
{ ! settings?.isPreviewMode && <KeyboardShortcuts.Register /> }
<BlockRefsProvider>{ children }</BlockRefsProvider>
<BlockRefsProvider>{ props.children }</BlockRefsProvider>
</SlotFillProvider>
);

if ( window.__experimentalMediaProcessing ) {
return (
<MediaUploadProvider
settings={ mediaUploadSettings }
useSubRegistry={ false }
>
{ children }
</MediaUploadProvider>
);
}

return children;
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';

/**
* React hook used to compute the media upload settings to use in the post editor.
*
* @param {Object} settings Media upload settings prop.
*
* @return {Object} Media upload settings.
*/
function useMediaUploadSettings( settings ) {
return useMemo(
() => ( {
mediaUpload: settings.mediaUpload,
mediaSideload: settings.mediaSideload,
maxUploadFileSize: settings.maxUploadFileSize,
allowedMimeTypes: settings.allowedMimeTypes,
} ),
[ settings ]
);
}

export default useMediaUploadSettings;
1 change: 1 addition & 0 deletions packages/block-editor/src/store/private-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const castArray = ( maybeArray ) =>
const privateSettings = [
'inserterMediaCategories',
'blockInspectorAnimation',
'mediaSideload',
];

/**
Expand Down
1 change: 1 addition & 0 deletions packages/editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ _Parameters_
- _$0.maxUploadFileSize_ `?number`: Maximum upload size in bytes allowed for the site.
- _$0.onError_ `Function`: Function called when an error happens.
- _$0.onFileChange_ `Function`: Function called each time a file or a temporary representation of the file is available.
- _$0.onSuccess_ `Function`: Function called after the final representation of the file is available.

### MediaUploadCheck

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
*/
import inserterMediaCategories from '../media-categories';
import { mediaUpload } from '../../utils';
import { default as mediaSideload } from '../../utils/media-sideload';
import { store as editorStore } from '../../store';
import { unlock } from '../../lock-unlock';
import { useGlobalStylesContext } from '../global-styles-provider';
Expand All @@ -45,6 +46,7 @@ const BLOCK_EDITOR_SETTINGS = [
'__experimentalGlobalStylesBaseStyles',
'alignWide',
'blockInspectorTabs',
'maxUploadFileSize',
'allowedMimeTypes',
'bodyPlaceholder',
'canLockBlocks',
Expand Down Expand Up @@ -290,6 +292,7 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
isDistractionFree,
keepCaretInsideBlock,
mediaUpload: hasUploadPermissions ? mediaUpload : undefined,
mediaSideload: hasUploadPermissions ? mediaSideload : undefined,
__experimentalBlockPatterns: blockPatterns,
[ selectBlockPatternsKey ]: ( select ) => {
const { hasFinishedResolution, getBlockPatternsForPostType } =
Expand Down
13 changes: 13 additions & 0 deletions packages/editor/src/utils/media-sideload/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* WordPress dependencies
*/
import { privateApis } from '@wordpress/media-utils';

/**
* Internal dependencies
*/
import { unlock } from '../../lock-unlock';

const { sideloadMedia: mediaSideload } = unlock( privateApis );

export default mediaSideload;
1 change: 1 addition & 0 deletions packages/editor/src/utils/media-sideload/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default function mediaSideload() {}
5 changes: 4 additions & 1 deletion packages/editor/src/utils/media-upload/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const noop = () => {};
* @param {?number} $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.
* @param {Function} $0.onError Function called when an error happens.
* @param {Function} $0.onFileChange Function called each time a file or a temporary representation of the file is available.
* @param {Function} $0.onSuccess Function called after the final representation of the file is available.
*/
export default function mediaUpload( {
additionalData = {},
Expand All @@ -35,6 +36,7 @@ export default function mediaUpload( {
maxUploadFileSize,
onError = noop,
onFileChange,
onSuccess,
} ) {
const { getCurrentPost, getEditorSettings } = select( editorStore );
const {
Expand Down Expand Up @@ -77,8 +79,9 @@ export default function mediaUpload( {
} else {
clearSaveLock();
}
onFileChange( file );
onFileChange?.( file );
},
onSuccess,
additionalData: {
...postData,
...additionalData,
Expand Down
1 change: 0 additions & 1 deletion packages/media-utils/src/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ export type Attachment = BetterOmit<
};

export type OnChangeHandler = ( attachments: Partial< Attachment >[] ) => void;
export type OnSuccessHandler = ( attachments: Partial< Attachment >[] ) => void;
export type OnErrorHandler = ( error: Error ) => void;

export type CreateRestAttachment = Partial< RestAttachment >;
Expand Down
27 changes: 18 additions & 9 deletions packages/media-utils/src/utils/upload-media.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ import type {
Attachment,
OnChangeHandler,
OnErrorHandler,
OnSuccessHandler,
} from './types';
import { uploadToServer } from './upload-to-server';
import { validateMimeType } from './validate-mime-type';
import { validateMimeTypeForUser } from './validate-mime-type-for-user';
import { validateFileSize } from './validate-file-size';
import { UploadError } from './upload-error';

declare global {
interface Window {
__experimentalMediaProcessing?: boolean;
}
}

interface UploadMediaArgs {
// Additional data to include in the request.
additionalData?: AdditionalData;
Expand All @@ -33,8 +38,6 @@ interface UploadMediaArgs {
onError?: OnErrorHandler;
// Function called each time a file or a temporary representation of the file is available.
onFileChange?: OnChangeHandler;
// Function called once a file has completely finished uploading, including thumbnails.
onSuccess?: OnSuccessHandler;
// List of allowed mime types and file extensions.
wpAllowedMimeTypes?: Record< string, string > | null;
// Abort signal.
Expand Down Expand Up @@ -69,8 +72,11 @@ export function uploadMedia( {

const filesSet: Array< Partial< Attachment > | null > = [];
const setAndUpdateFiles = ( index: number, value: Attachment | null ) => {
if ( filesSet[ index ]?.url ) {
revokeBlobURL( filesSet[ index ].url );
// For client-side media processing, this is handled by the upload-media package.
if ( ! window.__experimentalMediaProcessing ) {
if ( filesSet[ index ]?.url ) {
revokeBlobURL( filesSet[ index ].url );
}
}
filesSet[ index ] = value;
onFileChange?.(
Expand Down Expand Up @@ -107,10 +113,13 @@ export function uploadMedia( {

validFiles.push( mediaFile );

// Set temporary URL to create placeholder media file, this is replaced
// with final file from media gallery when upload is `done` below.
filesSet.push( { url: createBlobURL( mediaFile ) } );
onFileChange?.( filesSet as Array< Partial< Attachment > > );
// For client-side media processing, this is handled by the upload-media package.
if ( ! window.__experimentalMediaProcessing ) {
// Set temporary URL to create placeholder media file, this is replaced
// with final file from media gallery when upload is `done` below.
filesSet.push( { url: createBlobURL( mediaFile ) } );
onFileChange?.( filesSet as Array< Partial< Attachment > > );
}
}

validFiles.map( async ( file, index ) => {
Expand Down
1 change: 1 addition & 0 deletions packages/private-apis/src/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const CORE_MODULES_USING_PRIVATE_APIS = [
'@wordpress/dataviews',
'@wordpress/fields',
'@wordpress/media-utils',
'@wordpress/upload-media',
];

/**
Expand Down
Loading

0 comments on commit 2d7f2d8

Please sign in to comment.