UNPKG

@wordpress/block-library

Version:
347 lines (319 loc) 10.3 kB
import { createElement, Fragment } from "@wordpress/element"; /** * External dependencies */ import { get } from 'lodash'; import { View } from 'react-native'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { BlockControls, BlockVerticalAlignmentToolbar, InnerBlocks, InspectorControls, withColors, MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, store as blockEditorStore } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; import { Button, ToolbarGroup, PanelBody, ToggleControl } from '@wordpress/components'; import { withSelect } from '@wordpress/data'; import { compose } from '@wordpress/compose'; import { pullLeft, pullRight, replace } from '@wordpress/icons'; /** * Internal dependencies */ import MediaContainer from './media-container'; import styles from './style.scss'; const TEMPLATE = [['core/paragraph']]; // this limits the resize to a safe zone to avoid making broken layouts const WIDTH_CONSTRAINT_PERCENTAGE = 15; const BREAKPOINTS = { mobile: 480 }; const applyWidthConstraints = width => Math.max(WIDTH_CONSTRAINT_PERCENTAGE, Math.min(width, 100 - WIDTH_CONSTRAINT_PERCENTAGE)); class MediaTextEdit extends Component { constructor() { super(...arguments); this.onSelectMedia = this.onSelectMedia.bind(this); this.onMediaUpdate = this.onMediaUpdate.bind(this); this.onWidthChange = this.onWidthChange.bind(this); this.commitWidthChange = this.commitWidthChange.bind(this); this.onLayoutChange = this.onLayoutChange.bind(this); this.onMediaSelected = this.onMediaSelected.bind(this); this.onReplaceMedia = this.onReplaceMedia.bind(this); this.onSetOpenPickerRef = this.onSetOpenPickerRef.bind(this); this.onSetImageFill = this.onSetImageFill.bind(this); this.state = { mediaWidth: null, containerWidth: 0, isMediaSelected: false }; } static getDerivedStateFromProps(props, state) { return { isMediaSelected: state.isMediaSelected && props.isSelected && !props.isAncestorSelected }; } onSelectMedia(media) { const { setAttributes } = this.props; let mediaType; let src; // For media selections originated from a file upload. if (media.media_type) { if (media.media_type === 'image') { mediaType = 'image'; } else { // only images and videos are accepted so if the media_type is not an image we can assume it is a video. // video contain the media type of 'file' in the object returned from the rest api. mediaType = 'video'; } } else { // For media selections originated from existing files in the media library. mediaType = media.type; } if (mediaType === 'image' && media.sizes) { // Try the "large" size URL, falling back to the "full" size URL below. src = get(media, ['sizes', 'large', 'url']) || get(media, ['media_details', 'sizes', 'large', 'source_url']); } setAttributes({ mediaAlt: media.alt, mediaId: media.id, mediaType, mediaUrl: src || media.url, imageFill: undefined, focalPoint: undefined }); } onMediaUpdate(media) { const { setAttributes } = this.props; setAttributes({ mediaId: media.id, mediaUrl: media.url }); } onWidthChange(width) { this.setState({ mediaWidth: applyWidthConstraints(width) }); } commitWidthChange(width) { const { setAttributes } = this.props; setAttributes({ mediaWidth: applyWidthConstraints(width) }); this.setState({ mediaWidth: null }); } onLayoutChange(_ref) { let { nativeEvent } = _ref; const { width } = nativeEvent.layout; const { containerWidth } = this.state; if (containerWidth === width) { return null; } this.setState({ containerWidth: width }); } onMediaSelected() { this.setState({ isMediaSelected: true }); } onReplaceMedia() { if (this.openPickerRef) { this.openPickerRef(); } } onSetOpenPickerRef(openPicker) { this.openPickerRef = openPicker; } onSetImageFill() { const { attributes, setAttributes } = this.props; const { imageFill } = attributes; setAttributes({ imageFill: !imageFill }); } getControls() { const { attributes } = this.props; const { imageFill } = attributes; return createElement(InspectorControls, null, createElement(PanelBody, { title: __('Settings') }, createElement(ToggleControl, { label: __('Crop image to fill entire column'), checked: imageFill, onChange: this.onSetImageFill }))); } renderMediaArea(shouldStack) { const { isMediaSelected, containerWidth } = this.state; const { attributes, isSelected } = this.props; const { mediaAlt, mediaId, mediaPosition, mediaType, mediaUrl, mediaWidth, imageFill, focalPoint, verticalAlignment } = attributes; const mediaAreaWidth = mediaWidth && !shouldStack ? containerWidth * mediaWidth / 100 - styles.mediaAreaPadding.width : containerWidth; const aligmentStyles = styles[`is-vertically-aligned-${verticalAlignment || 'center'}`]; return createElement(MediaContainer, { commitWidthChange: this.commitWidthChange, isMediaSelected: isMediaSelected, onFocus: this.props.onFocus, onMediaSelected: this.onMediaSelected, onMediaUpdate: this.onMediaUpdate, onSelectMedia: this.onSelectMedia, onSetOpenPickerRef: this.onSetOpenPickerRef, onWidthChange: this.onWidthChange, mediaWidth: mediaAreaWidth, mediaAlt, mediaId, mediaType, mediaUrl, mediaPosition, imageFill, focalPoint, isSelected, aligmentStyles, shouldStack }); } render() { const { attributes, backgroundColor, setAttributes, isSelected, isRTL, style, blockWidth } = this.props; const { isStackedOnMobile, imageFill, mediaPosition, mediaWidth, mediaType, verticalAlignment } = attributes; const { containerWidth, isMediaSelected } = this.state; const isMobile = containerWidth < BREAKPOINTS.mobile; const shouldStack = isStackedOnMobile && isMobile; const temporaryMediaWidth = shouldStack ? 100 : this.state.mediaWidth || mediaWidth; const widthString = `${temporaryMediaWidth}%`; const innerBlockWidth = shouldStack ? 100 : 100 - temporaryMediaWidth; const innerBlockWidthString = `${innerBlockWidth}%`; const hasMedia = mediaType === MEDIA_TYPE_IMAGE || mediaType === MEDIA_TYPE_VIDEO; const innerBlockContainerStyle = [{ width: innerBlockWidthString }, !shouldStack ? styles.innerBlock : { ...(mediaPosition === 'left' ? styles.innerBlockStackMediaLeft : styles.innerBlockStackMediaRight) }, ((style === null || style === void 0 ? void 0 : style.backgroundColor) || backgroundColor.color) && styles.innerBlockPaddings]; const containerStyles = { ...styles['wp-block-media-text'], ...styles[`is-vertically-aligned-${verticalAlignment || 'center'}`], ...(mediaPosition === 'right' ? styles['has-media-on-the-right'] : {}), ...(shouldStack && styles['is-stacked-on-mobile']), ...(shouldStack && mediaPosition === 'right' ? styles['is-stacked-on-mobile.has-media-on-the-right'] : {}), ...(isSelected && styles['is-selected']), backgroundColor: (style === null || style === void 0 ? void 0 : style.backgroundColor) || backgroundColor.color, paddingBottom: 0 }; const mediaContainerStyle = [{ flex: 1 }, shouldStack ? { ...(mediaPosition === 'left' && styles.mediaStackLeft), ...(mediaPosition === 'right' && styles.mediaStackRight) } : { ...(mediaPosition === 'left' && styles.mediaLeft), ...(mediaPosition === 'right' && styles.mediaRight) }]; const toolbarControls = [{ icon: isRTL ? pullRight : pullLeft, title: __('Show media on left'), isActive: mediaPosition === 'left', onClick: () => setAttributes({ mediaPosition: 'left' }) }, { icon: isRTL ? pullLeft : pullRight, title: __('Show media on right'), isActive: mediaPosition === 'right', onClick: () => setAttributes({ mediaPosition: 'right' }) }]; const onVerticalAlignmentChange = alignment => { setAttributes({ verticalAlignment: alignment }); }; return createElement(Fragment, null, mediaType === MEDIA_TYPE_IMAGE && this.getControls(), createElement(BlockControls, null, hasMedia && createElement(ToolbarGroup, null, createElement(Button, { label: __('Edit media'), icon: replace, onClick: this.onReplaceMedia })), (!isMediaSelected || mediaType === MEDIA_TYPE_VIDEO) && createElement(Fragment, null, createElement(ToolbarGroup, { controls: toolbarControls }), createElement(BlockVerticalAlignmentToolbar, { onChange: onVerticalAlignmentChange, value: verticalAlignment }))), createElement(View, { style: containerStyles, onLayout: this.onLayoutChange }, createElement(View, { style: [(shouldStack || !imageFill) && { width: widthString }, mediaContainerStyle] }, this.renderMediaArea(shouldStack)), createElement(View, { style: innerBlockContainerStyle }, createElement(InnerBlocks, { template: TEMPLATE, blockWidth: blockWidth })))); } } export default compose(withColors('backgroundColor'), withSelect((select, _ref2) => { let { clientId } = _ref2; const { getSelectedBlockClientId, getBlockParents, getSettings } = select(blockEditorStore); const parents = getBlockParents(clientId, true); const selectedBlockClientId = getSelectedBlockClientId(); const isAncestorSelected = selectedBlockClientId && parents.includes(selectedBlockClientId); return { isSelected: selectedBlockClientId === clientId, isAncestorSelected, isRTL: getSettings().isRTL }; }))(MediaTextEdit); //# sourceMappingURL=edit.native.js.map