diff --git a/packages/block-library/src/editor.scss b/packages/block-library/src/editor.scss index 58c8803144a31..31c6eccaf829c 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -14,6 +14,7 @@ @import "./image/editor.scss"; @import "./latest-comments/editor.scss"; @import "./latest-posts/editor.scss"; +@import "./media-text/editor.scss"; @import "./list/editor.scss"; @import "./more/editor.scss"; @import "./nextpage/editor.scss"; diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 01644d7bd20d6..ecb354f8c373e 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -28,6 +28,7 @@ import * as cover from './cover'; import * as embed from './embed'; import * as file from './file'; import * as html from './html'; +import * as mediaText from './media-text'; import * as latestComments from './latest-comments'; import * as latestPosts from './latest-posts'; import * as list from './list'; @@ -76,6 +77,7 @@ export const registerCoreBlocks = () => { file, window.wp && window.wp.oldEditor ? classic : null, // Only add the classic block in WP Context html, + mediaText, latestComments, latestPosts, missing, diff --git a/packages/block-library/src/media-text/edit.js b/packages/block-library/src/media-text/edit.js new file mode 100644 index 0000000000000..7570b2cc7b053 --- /dev/null +++ b/packages/block-library/src/media-text/edit.js @@ -0,0 +1,163 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { + BlockControls, + InnerBlocks, + InspectorControls, + PanelColorSettings, + withColors, +} from '@wordpress/editor'; +import { Component, Fragment } from '@wordpress/element'; +import { Toolbar } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import MediaContainer from './media-container'; + +/** + * Constants + */ +const ALLOWED_BLOCKS = [ 'core/button', 'core/paragraph', 'core/heading', 'core/list' ]; +const TEMPLATE = [ + [ 'core/paragraph', { fontSize: 'large', placeholder: 'Content…' } ], +]; + +class MediaTextEdit extends Component { + constructor() { + super( ...arguments ); + + this.onSelectMedia = this.onSelectMedia.bind( this ); + this.onWidthChange = this.onWidthChange.bind( this ); + this.commitWidthChange = this.commitWidthChange.bind( this ); + this.state = { + mediaWidth: null, + }; + } + + onSelectMedia( media ) { + const { setAttributes } = this.props; + + let mediaType; + // 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; + } + + setAttributes( { + mediaAlt: media.alt, + mediaId: media.id, + mediaType, + mediaUrl: media.url, + } ); + } + + onWidthChange( width ) { + this.setState( { + mediaWidth: width, + } ); + } + + commitWidthChange( width ) { + const { setAttributes } = this.props; + + setAttributes( { + mediaWidth: width, + } ); + this.setState( { + mediaWidth: null, + } ); + } + + renderMediaArea() { + const { attributes } = this.props; + const { mediaAlt, mediaId, mediaPosition, mediaType, mediaUrl, mediaWidth } = attributes; + + return ( + + ); + } + + render() { + const { + attributes, + className, + backgroundColor, + setAttributes, + setBackgroundColor, + } = this.props; + const { mediaPosition, mediaWidth } = attributes; + const temporaryMediaWidth = this.state.mediaWidth; + const classNames = classnames( className, { + 'has-media-on-the-right': 'right' === mediaPosition, + [ backgroundColor.class ]: backgroundColor.class, + } ); + const widthString = `${ temporaryMediaWidth || mediaWidth }%`; + const style = { + gridTemplateColumns: 'right' === mediaPosition ? `auto ${ widthString }` : `${ widthString } auto`, + backgroundColor: backgroundColor.color, + }; + const colorSettings = [ { + value: backgroundColor.color, + onChange: setBackgroundColor, + label: __( 'Background Color' ), + } ]; + const toolbarControls = [ { + icon: 'align-pull-left', + title: __( 'Show media on left' ), + isActive: mediaPosition === 'left', + onClick: () => setAttributes( { mediaPosition: 'left' } ), + }, { + icon: 'align-pull-right', + title: __( 'Show media on right' ), + isActive: mediaPosition === 'right', + onClick: () => setAttributes( { mediaPosition: 'right' } ), + } ]; + return ( + + + + + + + +
+ { this.renderMediaArea() } + +
+
+ ); + } +} + +export default withColors( 'backgroundColor' )( MediaTextEdit ); diff --git a/packages/block-library/src/media-text/editor.scss b/packages/block-library/src/media-text/editor.scss new file mode 100644 index 0000000000000..b0eccc5aace15 --- /dev/null +++ b/packages/block-library/src/media-text/editor.scss @@ -0,0 +1,59 @@ +.wp-block-media-text, +.wp-block-media-text.aligncenter { + grid-template-areas: + "media-text-media media-text-content" + "resizer resizer"; +} + +.wp-block-media-text.has-media-on-the-right, +.wp-block-media-text.has-media-on-the-right.aligncenter { + grid-template-areas: + "media-text-content media-text-media" + "resizer resizer"; +} + +.wp-block-media-text .__resizable_base__ { + grid-area: resizer; +} + +.wp-block-media-text .editor-media-container__resizer { + grid-area: media-text-media; + align-self: center; + // The resizer sets a inline width but as we are using a grid layout, + // we set the width on container. + width: 100% !important; +} + +.wp-block-media-text .editor-inner-blocks { + word-break: break-word; + grid-area: media-text-content; + text-align: initial; + padding: 0 8% 0 8%; +} + +.wp-block-media-text > .editor-inner-blocks > .editor-block-list__layout > .editor-block-list__block { + max-width: unset; +} + +figure.block-library-media-text__media-container { + margin: 0; + height: 100%; + width: 100%; +} + +.wp-block-media-text .block-library-media-text__media-container img, +.wp-block-media-text .block-library-media-text__media-container video { + margin-bottom: -8px; + width: 100%; +} + +.editor-media-container__resizer .components-resizable-box__handle { + display: none; +} + +.editor-block-list__block.is-selected, +.editor-block-list__block.is-focused { + .editor-media-container__resizer .components-resizable-box__handle { + display: block; + } +} diff --git a/packages/block-library/src/media-text/index.js b/packages/block-library/src/media-text/index.js new file mode 100644 index 0000000000000..ed08b7b551c29 --- /dev/null +++ b/packages/block-library/src/media-text/index.js @@ -0,0 +1,120 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { + InnerBlocks, + getColorClassName, +} from '@wordpress/editor'; + +/** + * Internal dependencies + */ +import edit from './edit'; + +const DEFAULT_MEDIA_WIDTH = 50; + +export const name = 'core/media-text'; + +export const settings = { + title: __( 'Media & Text' ), + + icon: , + + category: 'layout', + + keywords: [ __( 'image' ), __( 'video' ), __( 'half' ) ], + + attributes: { + align: { + type: 'string', + default: 'wide', + }, + backgroundColor: { + type: 'string', + }, + customBackgroundColor: { + type: 'string', + }, + mediaAlt: { + type: 'string', + source: 'attribute', + selector: 'figure img', + attribute: 'alt', + default: '', + }, + mediaPosition: { + type: 'string', + default: 'left', + }, + mediaId: { + type: 'number', + }, + mediaUrl: { + type: 'string', + source: 'attribute', + selector: 'figure video,figure img', + attribute: 'src', + }, + mediaType: { + type: 'string', + }, + mediaWidth: { + type: 'number', + default: 50, + }, + }, + + supports: { + align: [ 'wide', 'full' ], + }, + + edit, + + save( { attributes } ) { + const { + backgroundColor, + customBackgroundColor, + mediaAlt, + mediaPosition, + mediaType, + mediaUrl, + mediaWidth, + } = attributes; + const mediaTypeRenders = { + image: () => {, + video: () =>