UNPKG

@wordpress/block-editor

Version:
285 lines (282 loc) 9.25 kB
/** * External dependencies */ import { Platform } from 'react-native'; /** * WordPress dependencies */ import { Component, React } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { BottomSheet, PanelBody, Picker, TextControl } from '@wordpress/components'; import { getOtherMediaOptions, requestMediaPicker, mediaSources } from '@wordpress/react-native-bridge'; import { capturePhoto, captureVideo, image, wordpress, mobile, globe } from '@wordpress/icons'; import { store as blockEditorStore } from '@wordpress/block-editor'; import { compose } from '@wordpress/compose'; import { withSelect } from '@wordpress/data'; /** * Internal dependencies */ import { MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, MEDIA_TYPE_AUDIO, MEDIA_TYPE_ANY, OPTION_TAKE_VIDEO, OPTION_TAKE_PHOTO, OPTION_INSERT_FROM_URL, OPTION_WORDPRESS_MEDIA_LIBRARY } from './constants'; import styles from './style.scss'; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; const URL_MEDIA_SOURCE = 'URL'; const PICKER_OPENING_DELAY = 200; export class MediaUpload extends Component { pickerTimeout; constructor(props) { super(props); this.onPickerPresent = this.onPickerPresent.bind(this); this.onPickerSelect = this.onPickerSelect.bind(this); this.getAllSources = this.getAllSources.bind(this); this.state = { url: '', showURLInput: false, otherMediaOptions: [] }; } componentDidMount() { const { allowedTypes = [], autoOpen } = this.props; getOtherMediaOptions(allowedTypes, otherMediaOptions => { const otherMediaOptionsWithIcons = otherMediaOptions.map(option => { return { ...option, requiresModal: true, types: allowedTypes, id: option.value }; }); this.setState({ otherMediaOptions: otherMediaOptionsWithIcons }); }); if (autoOpen) { this.onPickerPresent(); } } componentWillUnmount() { clearTimeout(this.pickerTimeout); } getAllSources() { const { onSelectURL } = this.props; const cameraImageSource = { id: mediaSources.deviceCamera, // ID is the value sent to native. value: mediaSources.deviceCamera + '-IMAGE', // This is needed to diferenciate image-camera from video-camera sources. label: OPTION_TAKE_PHOTO, requiresModal: true, types: [MEDIA_TYPE_IMAGE], icon: capturePhoto }; const cameraVideoSource = { id: mediaSources.deviceCamera, value: mediaSources.deviceCamera, label: OPTION_TAKE_VIDEO, requiresModal: true, types: [MEDIA_TYPE_VIDEO], icon: captureVideo }; const deviceLibrarySource = { id: mediaSources.deviceLibrary, value: mediaSources.deviceLibrary, label: __('Choose from device'), requiresModal: true, types: [MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO], icon: image }; const siteLibrarySource = { id: mediaSources.siteMediaLibrary, value: mediaSources.siteMediaLibrary, label: OPTION_WORDPRESS_MEDIA_LIBRARY, requiresModal: true, types: [MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, MEDIA_TYPE_AUDIO, MEDIA_TYPE_ANY], icon: wordpress, mediaLibrary: true }; const urlSource = { id: URL_MEDIA_SOURCE, value: URL_MEDIA_SOURCE, label: OPTION_INSERT_FROM_URL, types: [MEDIA_TYPE_AUDIO, MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO], icon: globe }; // Only include `urlSource` option if `onSelectURL` prop is present, in order to match the web behavior. const internalSources = [deviceLibrarySource, cameraImageSource, cameraVideoSource, siteLibrarySource, ...(onSelectURL ? [urlSource] : [])]; return internalSources.concat(this.state.otherMediaOptions); } getMediaOptionsItems() { const { allowedTypes = [], __experimentalOnlyMediaLibrary, isAudioBlockMediaUploadEnabled } = this.props; return this.getAllSources().filter(source => { if (__experimentalOnlyMediaLibrary) { return source.mediaLibrary; } else if (allowedTypes.every(allowedType => allowedType === MEDIA_TYPE_AUDIO && source.types.includes(allowedType)) && source.id !== URL_MEDIA_SOURCE) { return isAudioBlockMediaUploadEnabled === true; } return allowedTypes.some(allowedType => source.types.includes(allowedType)); }).map(source => { return { ...source, icon: source.icon || this.getChooseFromDeviceIcon() }; }); } getChooseFromDeviceIcon() { return mobile; } onPickerPresent() { const { autoOpen } = this.props; const isIOS = Platform.OS === 'ios'; if (this.picker) { // the delay below is required because on iOS this action sheet gets dismissed by the close event of the Inserter // so this delay allows the Inserter to be closed fully before presenting action sheet. if (autoOpen && isIOS) { this.pickerTimeout = setTimeout(() => this.picker.presentPicker(), PICKER_OPENING_DELAY); } else { this.picker.presentPicker(); } } } onPickerSelect(value) { const { allowedTypes = [], onSelect, multiple = false } = this.props; if (value === URL_MEDIA_SOURCE) { this.setState({ showURLInput: true }); return; } const mediaSource = this.getAllSources().filter(source => source.value === value).shift(); const types = allowedTypes.filter(type => mediaSource.types.includes(type)); requestMediaPicker(mediaSource.id, types, multiple, media => { if (multiple && media || media && media.id) { onSelect(media); } }); } render() { const { allowedTypes = [], isReplacingMedia, multiple } = this.props; const isOneType = allowedTypes.length === 1; const isImage = isOneType && allowedTypes.includes(MEDIA_TYPE_IMAGE); const isVideo = isOneType && allowedTypes.includes(MEDIA_TYPE_VIDEO); const isAudio = isOneType && allowedTypes.includes(MEDIA_TYPE_AUDIO); const isAnyType = isOneType && allowedTypes.includes(MEDIA_TYPE_ANY); const isImageOrVideo = allowedTypes.length === 2 && allowedTypes.includes(MEDIA_TYPE_IMAGE) && allowedTypes.includes(MEDIA_TYPE_VIDEO); let pickerTitle; if (isImage) { if (isReplacingMedia) { pickerTitle = __('Replace image'); } else { pickerTitle = multiple ? __('Choose images') : __('Choose image'); } } else if (isVideo) { if (isReplacingMedia) { pickerTitle = __('Replace video'); } else { pickerTitle = __('Choose video'); } } else if (isImageOrVideo) { if (isReplacingMedia) { pickerTitle = __('Replace image or video'); } else { pickerTitle = __('Choose image or video'); } } else if (isAudio) { if (isReplacingMedia) { pickerTitle = __('Replace audio'); } else { pickerTitle = __('Choose audio'); } } else if (isAnyType) { pickerTitle = __('Choose file'); if (isReplacingMedia) { pickerTitle = __('Replace file'); } else { pickerTitle = __('Choose file'); } } const getMediaOptions = () => /*#__PURE__*/_jsx(Picker, { title: pickerTitle, hideCancelButton: true, ref: instance => this.picker = instance, options: this.getMediaOptionsItems(), onChange: this.onPickerSelect, testID: "media-options-picker" }); return /*#__PURE__*/_jsxs(_Fragment, { children: [/*#__PURE__*/_jsx(URLInput, { isVisible: this.state.showURLInput, onClose: () => { if (this.state.url !== '') { this.props.onSelectURL(this.state.url); } this.setState({ showURLInput: false, url: '' }); }, onChange: url => { this.setState({ url }); }, value: this.state.url }), this.props.render({ open: this.onPickerPresent, getMediaOptions })] }); } } function URLInput(props) { return /*#__PURE__*/_jsx(BottomSheet, { hideHeader: true, isVisible: props.isVisible, onClose: props.onClose, children: /*#__PURE__*/_jsx(PanelBody, { style: styles['media-upload__link-input'], children: /*#__PURE__*/_jsx(TextControl // TODO: Switch to `true` (40px size) if possible , { __next40pxDefaultSize: false // eslint-disable-next-line jsx-a11y/no-autofocus , autoFocus: true, autoCapitalize: "none", autoCorrect: false, autoComplete: Platform.isIOS ? 'url' : 'off', keyboardType: "url", label: OPTION_INSERT_FROM_URL, onChange: props.onChange, placeholder: __('Type a URL'), value: props.value }) }) }); } export default compose([withSelect(select => { const { capabilities } = select(blockEditorStore).getSettings(); return { isAudioBlockMediaUploadEnabled: capabilities?.isAudioBlockMediaUploadEnabled === true }; })])(MediaUpload); //# sourceMappingURL=index.native.js.map