From ff5065f323381920151a802545ca08b9c1b5b468 Mon Sep 17 00:00:00 2001 From: Vadim Nicolai Date: Sun, 31 Mar 2019 21:22:35 +0300 Subject: [PATCH 001/132] Wrapped HTMLedit with ResizableBox. --- packages/block-library/src/html/edit.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 99df666bb55ec8..167a8520e7738b 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -5,7 +5,7 @@ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { BlockControls, PlainText } from '@wordpress/block-editor'; import { transformStyles } from '@wordpress/editor'; -import { Disabled, SandBox } from '@wordpress/components'; +import { Disabled, SandBox, ResizableBox } from '@wordpress/components'; import { withSelect } from '@wordpress/data'; class HTMLEdit extends Component { @@ -47,7 +47,7 @@ class HTMLEdit extends Component { this.setState( { isPreview: false } ); } - render() { + renderHTML() { const { attributes, setAttributes } = this.props; const { isPreview, styles } = this.state; @@ -86,6 +86,18 @@ class HTMLEdit extends Component { ); } + + render() { + return ( + + { this.renderHTML() } + + ); + } } export default withSelect( ( select ) => { const { getSettings } = select( 'core/block-editor' ); From 3ef563e44cc41f37aa624b5ed70908adc5968342 Mon Sep 17 00:00:00 2001 From: Matthew Kevins Date: Thu, 30 May 2019 17:40:18 +1000 Subject: [PATCH 002/132] [Mobile] Fix caret position after inline paste - after selection refactor (#15701) * Rename variables for clarity in inline paste * Update selection via onSelectionUpdate after inline paste * Remove unused forceSelectionUpdate function --- .../src/components/rich-text/index.native.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 13fcc41771e1c7..5779e6459db14d 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -552,14 +552,14 @@ export class RichText extends Component { if ( typeof pastedContent === 'string' ) { const recordToInsert = create( { html: pastedContent } ); - const insertedContent = insert( currentRecord, recordToInsert ); - const newContent = this.valueToFormat( insertedContent ); + const resultingRecord = insert( currentRecord, recordToInsert ); + const resultingContent = this.valueToFormat( resultingRecord ); this.lastEventCount = undefined; - this.value = newContent; + this.value = resultingContent; // explicitly set selection after inline paste - this.forceSelectionUpdate( insertedContent.start, insertedContent.end ); + this.onSelectionChange( resultingRecord.start, resultingRecord.end ); this.props.onChange( this.value ); } else if ( onSplit ) { @@ -673,15 +673,6 @@ export class RichText extends Component { return value; } - forceSelectionUpdate( start, end ) { - if ( ! this.needsSelectionUpdate ) { - this.needsSelectionUpdate = true; - this.selectionStart = start; - this.selectionEnd = end; - this.forceUpdate(); - } - } - shouldComponentUpdate( nextProps ) { if ( nextProps.tagName !== this.props.tagName ) { this.lastEventCount = undefined; From 942028460965f272b28d2298be52f19c8f73532c Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 30 May 2019 10:44:32 +0100 Subject: [PATCH 003/132] Add end 2 end test heading color (#15784) --- .../blocks/__snapshots__/heading.test.js.snap | 24 ++++++++ .../e2e-tests/specs/blocks/heading.test.js | 60 ++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap b/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap index 71bb261abc29a8..184fb44ef12bc2 100644 --- a/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap +++ b/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap @@ -12,6 +12,30 @@ exports[`Heading can be created by prefixing number sign and a space 1`] = ` " `; +exports[`Heading it should correctly apply custom colors 1`] = ` +" +

Heading

+" +`; + +exports[`Heading it should correctly apply custom colors 2`] = ` +" +

Heading

+" +`; + +exports[`Heading it should correctly apply named colors 1`] = ` +" +

Heading

+" +`; + +exports[`Heading it should correctly apply named colors 2`] = ` +" +

Heading

+" +`; + exports[`Heading should create a paragraph block above when pressing enter at the start 1`] = ` "

diff --git a/packages/e2e-tests/specs/blocks/heading.test.js b/packages/e2e-tests/specs/blocks/heading.test.js index 2690ad4690b5b6..c895538b97671d 100644 --- a/packages/e2e-tests/specs/blocks/heading.test.js +++ b/packages/e2e-tests/specs/blocks/heading.test.js @@ -3,11 +3,21 @@ */ import { clickBlockAppender, - getEditedPostContent, createNewPost, + getEditedPostContent, + pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; describe( 'Heading', () => { + const BACKGROUND_COLOR_TEXT = 'Background Color'; + const TEXT_COLOR_TEXT = 'Text Color'; + const CUSTOM_COLOR_TEXT = 'Custom Color'; + const BACKGROUND_COLOR_UI_X_SELECTOR = `//div[./span[contains(text(),'${ BACKGROUND_COLOR_TEXT }')]]`; + const TEXT_COLOR_UI_X_SELECTOR = `//div[./span[contains(text(),'${ TEXT_COLOR_TEXT }')]]`; + const CUSTOM_COLOR_BUTTON_X_SELECTOR = `//button[contains(text(),'${ CUSTOM_COLOR_TEXT }')]`; + const COLOR_INPUT_FIELD_SELECTOR = '.components-color-palette__picker .components-text-control__input'; + const COLOR_PANEL_TOGGLE_X_SELECTOR = '//button[./span[contains(text(),\'Color Settings\')]]'; + beforeEach( async () => { await createNewPost(); } ); @@ -44,4 +54,52 @@ describe( 'Heading', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'it should correctly apply custom colors', async () => { + await clickBlockAppender(); + await page.keyboard.type( '### Heading' ); + const [ colorPanelToggle ] = await page.$x( COLOR_PANEL_TOGGLE_X_SELECTOR ); + await colorPanelToggle.click(); + const [ customBackgroundColorButton ] = await page.$x( + `${ BACKGROUND_COLOR_UI_X_SELECTOR }${ CUSTOM_COLOR_BUTTON_X_SELECTOR }` + ); + await customBackgroundColorButton.click(); + await page.click( COLOR_INPUT_FIELD_SELECTOR ); + await pressKeyWithModifier( 'primary', 'A' ); + await page.keyboard.type( '#ab4567' ); + await page.click( '.wp-block-heading' ); + await page.waitForSelector( '.component-color-indicator[aria-label="(background color: #ab4567)"]' ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + + const [ customTextColorButton ] = await page.$x( + `${ TEXT_COLOR_UI_X_SELECTOR }${ CUSTOM_COLOR_BUTTON_X_SELECTOR }` + ); + await customTextColorButton.click(); + await page.click( COLOR_INPUT_FIELD_SELECTOR ); + await pressKeyWithModifier( 'primary', 'A' ); + await page.keyboard.type( '#181717' ); + await page.click( '.wp-block-heading' ); + await page.waitForSelector( '.component-color-indicator[aria-label="(text color: #181717)"]' ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'it should correctly apply named colors', async () => { + await clickBlockAppender(); + await page.keyboard.type( '## Heading' ); + const [ colorPanelToggle ] = await page.$x( COLOR_PANEL_TOGGLE_X_SELECTOR ); + await colorPanelToggle.click(); + const primaryColorButtonSelector = `${ BACKGROUND_COLOR_UI_X_SELECTOR }//button[@aria-label='Color: Primary']`; + const [ primaryColorButton ] = await page.$x( primaryColorButtonSelector ); + await primaryColorButton.click(); + await page.click( '.wp-block-heading' ); + await page.waitForXPath( `${ primaryColorButtonSelector }[@aria-pressed='true']` ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + + const whiteColorButtonSelector = `${ TEXT_COLOR_UI_X_SELECTOR }//button[@aria-label='Color: White']`; + const [ whiteColorButton ] = await page.$x( whiteColorButtonSelector ); + await whiteColorButton.click(); + await page.click( '.wp-block-heading' ); + await page.waitForXPath( `${ whiteColorButtonSelector }[@aria-pressed='true']` ); + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } ); From 6e2c30b546a3df391911f7cc3a0622c3829c51bd Mon Sep 17 00:00:00 2001 From: Stefanos Togoulidis Date: Thu, 30 May 2019 15:00:42 +0300 Subject: [PATCH 004/132] [RNMobile] Focus RichText on mount if block is selected and says so (#15878) * Focus RichText on mount if block is selected and says so Some blocks have multiple RichText or a RichText among other children. Example: Quote blocks has 2 RichTexts and Image block has a RichText for the caption. We want to control when and which of those RichTexts will request focus. On the web side, the DOM is used to search for a inputbox to focus but on RN, we don't have a DOM to search. Instead, this commit makes the assumption that a RichText always request focus if its parent has passed `true` in `isSelected` and only if the parent hasn't inhibited that behavior by using the `noFocusOnMount` prop. * Simplify the passing of noFocusOnMount * Fix grammar in comment * Rename prop to mark it as unstable --- .../src/components/rich-text/index.native.js | 15 +++++++++------ packages/block-library/src/image/edit.native.js | 1 + packages/block-library/src/quote/edit.js | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 5779e6459db14d..a89f293ff8efba 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -716,7 +716,11 @@ export class RichText extends Component { } componentDidMount() { - if ( this.props.isSelected ) { + // Request focus if wrapping block is selected and parent hasn't inhibited the focus request. This method of focusing + // is trying to implement the web-side counterpart of BlockList's `focusTabbable` where the BlockList is focusing an + // inputbox by searching the DOM. We don't have the DOM in RN so, using the combination of blockIsSelected and __unstableMobileNoFocusOnMount + // to determine if we should focus the RichText. + if ( this.props.blockIsSelected && ! this.props.__unstableMobileNoFocusOnMount ) { this._editor.focus(); this.onSelectionChange( this.props.selectionStart || 0, this.props.selectionEnd || 0 ); } @@ -880,16 +884,13 @@ RichText.defaultProps = { const RichTextContainer = compose( [ withInstanceId, withBlockEditContext( ( { clientId, onFocus, onCaretVerticalPositionChange, isSelected }, ownProps ) => { - // ownProps.onFocus and isSelected needs precedence over the block edit context - if ( ownProps.isSelected !== undefined ) { - isSelected = ownProps.isSelected; - } + // ownProps.onFocus needs precedence over the block edit context if ( ownProps.onFocus !== undefined ) { onFocus = ownProps.onFocus; } return { - isSelected, clientId, + blockIsSelected: ownProps.isSelected !== undefined ? ownProps.isSelected : isSelected, onFocus, onCaretVerticalPositionChange, }; @@ -899,6 +900,7 @@ const RichTextContainer = compose( [ instanceId, identifier = instanceId, isSelected, + blockIsSelected, } ) => { const { getFormatTypes } = select( 'core/rich-text' ); const { @@ -921,6 +923,7 @@ const RichTextContainer = compose( [ selectionStart: isSelected ? selectionStart.offset : undefined, selectionEnd: isSelected ? selectionEnd.offset : undefined, isSelected, + blockIsSelected, }; } ), withDispatch( ( dispatch, { diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 7ef23a0b0f9b89..0869ca4fd2a52e 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -370,6 +370,7 @@ class ImageEdit extends React.Component { onFocus={ this.onFocusCaption } onBlur={ this.props.onBlur } // always assign onBlur as props isSelected={ this.state.isCaptionSelected } + __unstableMobileNoFocusOnMount fontSize={ 14 } underlineColorAndroid="transparent" textAlign={ 'center' } diff --git a/packages/block-library/src/quote/edit.js b/packages/block-library/src/quote/edit.js index 8955b78588bc3f..079db78e86493e 100644 --- a/packages/block-library/src/quote/edit.js +++ b/packages/block-library/src/quote/edit.js @@ -48,6 +48,7 @@ export default function QuoteEdit( { attributes, setAttributes, isSelected, merg citation: nextCitation, } ) } + __unstableMobileNoFocusOnMount placeholder={ // translators: placeholder text used for the citation __( 'Write citation…' ) From 19f9610a08fb8cc623c50efff854097f9668ef9d Mon Sep 17 00:00:00 2001 From: Arun Sathiya Date: Thu, 30 May 2019 17:40:34 +0530 Subject: [PATCH 005/132] Update link on the Gutenberg build files notice (#15697) --- gutenberg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gutenberg.php b/gutenberg.php index e1f216512fceac..1cef2b3380e4bf 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -89,7 +89,7 @@ function gutenberg_wordpress_version_notice() { */ function gutenberg_build_files_notice() { echo '

'; - _e( 'Gutenberg development mode requires files to be built. Run npm install to install dependencies, npm run build to build the files or npm run dev to build the files and watch for changes. Read the contributing file for more information.', 'gutenberg' ); + _e( 'Gutenberg development mode requires files to be built. Run npm install to install dependencies, npm run build to build the files or npm run dev to build the files and watch for changes. Read the contributing file for more information.', 'gutenberg' ); echo '

'; } From d47334fae063dbcac6aa040afe2fa40d81c92922 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 30 May 2019 13:33:04 +0100 Subject: [PATCH 006/132] Remove background color text from heading; Fix end to end tests; (#15917) --- .../blocks/__snapshots__/heading.test.js.snap | 20 ++++--------------- .../e2e-tests/specs/blocks/heading.test.js | 18 ----------------- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap b/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap index 184fb44ef12bc2..093ceb0da4e9d5 100644 --- a/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap +++ b/packages/e2e-tests/specs/blocks/__snapshots__/heading.test.js.snap @@ -13,26 +13,14 @@ exports[`Heading can be created by prefixing number sign and a space 1`] = ` `; exports[`Heading it should correctly apply custom colors 1`] = ` -" -

Heading

-" -`; - -exports[`Heading it should correctly apply custom colors 2`] = ` -" -

Heading

+" +

Heading

" `; exports[`Heading it should correctly apply named colors 1`] = ` -" -

Heading

-" -`; - -exports[`Heading it should correctly apply named colors 2`] = ` -" -

Heading

+" +

Heading

" `; diff --git a/packages/e2e-tests/specs/blocks/heading.test.js b/packages/e2e-tests/specs/blocks/heading.test.js index c895538b97671d..cb46f7072b0688 100644 --- a/packages/e2e-tests/specs/blocks/heading.test.js +++ b/packages/e2e-tests/specs/blocks/heading.test.js @@ -9,10 +9,8 @@ import { } from '@wordpress/e2e-test-utils'; describe( 'Heading', () => { - const BACKGROUND_COLOR_TEXT = 'Background Color'; const TEXT_COLOR_TEXT = 'Text Color'; const CUSTOM_COLOR_TEXT = 'Custom Color'; - const BACKGROUND_COLOR_UI_X_SELECTOR = `//div[./span[contains(text(),'${ BACKGROUND_COLOR_TEXT }')]]`; const TEXT_COLOR_UI_X_SELECTOR = `//div[./span[contains(text(),'${ TEXT_COLOR_TEXT }')]]`; const CUSTOM_COLOR_BUTTON_X_SELECTOR = `//button[contains(text(),'${ CUSTOM_COLOR_TEXT }')]`; const COLOR_INPUT_FIELD_SELECTOR = '.components-color-palette__picker .components-text-control__input'; @@ -60,16 +58,6 @@ describe( 'Heading', () => { await page.keyboard.type( '### Heading' ); const [ colorPanelToggle ] = await page.$x( COLOR_PANEL_TOGGLE_X_SELECTOR ); await colorPanelToggle.click(); - const [ customBackgroundColorButton ] = await page.$x( - `${ BACKGROUND_COLOR_UI_X_SELECTOR }${ CUSTOM_COLOR_BUTTON_X_SELECTOR }` - ); - await customBackgroundColorButton.click(); - await page.click( COLOR_INPUT_FIELD_SELECTOR ); - await pressKeyWithModifier( 'primary', 'A' ); - await page.keyboard.type( '#ab4567' ); - await page.click( '.wp-block-heading' ); - await page.waitForSelector( '.component-color-indicator[aria-label="(background color: #ab4567)"]' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); const [ customTextColorButton ] = await page.$x( `${ TEXT_COLOR_UI_X_SELECTOR }${ CUSTOM_COLOR_BUTTON_X_SELECTOR }` @@ -88,12 +76,6 @@ describe( 'Heading', () => { await page.keyboard.type( '## Heading' ); const [ colorPanelToggle ] = await page.$x( COLOR_PANEL_TOGGLE_X_SELECTOR ); await colorPanelToggle.click(); - const primaryColorButtonSelector = `${ BACKGROUND_COLOR_UI_X_SELECTOR }//button[@aria-label='Color: Primary']`; - const [ primaryColorButton ] = await page.$x( primaryColorButtonSelector ); - await primaryColorButton.click(); - await page.click( '.wp-block-heading' ); - await page.waitForXPath( `${ primaryColorButtonSelector }[@aria-pressed='true']` ); - expect( await getEditedPostContent() ).toMatchSnapshot(); const whiteColorButtonSelector = `${ TEXT_COLOR_UI_X_SELECTOR }//button[@aria-label='Color: White']`; const [ whiteColorButton ] = await page.$x( whiteColorButtonSelector ); From 2c29b1977f85ae0b6ad240200cd55eeb0b5040bc Mon Sep 17 00:00:00 2001 From: Joen Asmussen Date: Thu, 30 May 2019 14:58:26 +0200 Subject: [PATCH 007/132] Fix menu item colors (#15531) * Fix menu item colors Fixes #15387 This PR fixes an inconsistency in menu item colors. There were some redundant CSS that had not been cleaned up properly with the move to the color mixins. Additionally it replaces the use of opacity for the lighter text in the menus, and uses the color variables instead, as those colors do not need to work on differently colored backgrounds, just white. * Address feedback. --- .../src/components/block-settings-menu/style.scss | 2 +- packages/components/src/menu-item/style.scss | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/block-settings-menu/style.scss b/packages/block-editor/src/components/block-settings-menu/style.scss index 39b62ec34b59de..197303805352e6 100644 --- a/packages/block-editor/src/components/block-settings-menu/style.scss +++ b/packages/block-editor/src/components/block-settings-menu/style.scss @@ -39,9 +39,9 @@ background: none; outline: none; border-radius: 0; - color: $dark-gray-500; text-align: left; cursor: pointer; + color: $dark-gray-600; @include menu-style__neutral; &:hover:not(:disabled):not([aria-disabled="true"]) { diff --git a/packages/components/src/menu-item/style.scss b/packages/components/src/menu-item/style.scss index 8f750618c2a159..7ef38dfc8c3036 100644 --- a/packages/components/src/menu-item/style.scss +++ b/packages/components/src/menu-item/style.scss @@ -4,6 +4,7 @@ padding: $grid-size ($grid-size-large - $border-width); text-align: left; color: $dark-gray-600; + @include menu-style__neutral; // Target plugin icons that can have arbitrary classes by using an aggressive selector. .dashicon, @@ -18,7 +19,6 @@ } &:hover:not(:disabled):not([aria-disabled="true"]) { - color: $dark-gray-500; // Disable hover style on mobile to prevent odd scroll behaviour. // See: https://github.com/WordPress/gutenberg/pull/10333 @include break-medium() { @@ -26,7 +26,7 @@ } .components-menu-item__shortcut { - opacity: 1; + color: $dark-gray-600; } } @@ -43,12 +43,12 @@ .components-menu-item__info { margin-top: $grid-size-small; font-size: $default-font-size - 1px; - opacity: 0.84; + color: $dark-gray-300; } .components-menu-item__shortcut { align-self: center; - opacity: 0.84; + color: $dark-gray-300; margin-right: 0; margin-left: auto; padding-left: $grid-size; From 81dcc8d45d569308d6a53da974e9d2be0728b092 Mon Sep 17 00:00:00 2001 From: Yorick Brown Date: Thu, 30 May 2019 16:18:13 +0200 Subject: [PATCH 008/132] Update extending-the-block-editor.md (#14841) --- .../tutorials/javascript/extending-the-block-editor.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/designers-developers/developers/tutorials/javascript/extending-the-block-editor.md b/docs/designers-developers/developers/tutorials/javascript/extending-the-block-editor.md index 8a451c3d72361f..19a18057187629 100644 --- a/docs/designers-developers/developers/tutorials/javascript/extending-the-block-editor.md +++ b/docs/designers-developers/developers/tutorials/javascript/extending-the-block-editor.md @@ -22,7 +22,7 @@ Plugin Name: Fancy Quote function myguten_enqueue() { wp_enqueue_script( 'myguten-script', plugins_url( 'myguten.js', __FILE__ ), - array( 'wp-blocks') + array( 'wp-blocks' ) ); } add_action( 'enqueue_block_editor_assets', 'myguten_enqueue' ); @@ -34,7 +34,9 @@ See [Packages](/docs/designers-developers/developers/packages.md) for list of av After you have updated both JavaScript and PHP files, go to the block editor and create a new post. -Add a quote block, and in the right sidebar under Styles, you will see your new Fancy Quote style listed. Click the Fancy Quote to select and apply that style to your quote block: +Add a quote block, and in the right sidebar under Styles, you will see your new Fancy Quote style listed. + +Click the Fancy Quote to select and apply that style to your quote block: ![Fancy Quote Style in Inspector](https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/assets/fancy-quote-in-inspector.png) @@ -42,7 +44,7 @@ Add a quote block, and in the right sidebar under Styles, you will see your new Even if you Preview or Publish the post you will not see a visible change. However, if you look at the source, you will see the `is-style-fancy-quote` class name is now attached to your quote block. -Let's add some style. Go ahead and create a `style.css` file with: +Let's add some style. In your plugin folder, create a `style.css` file with: ```css .is-style-fancy-quote { @@ -59,7 +61,7 @@ function myguten_stylesheet() { add_action( 'enqueue_block_assets', 'myguten_stylesheet' ); ``` -Now when you view in the editor and published, you will see your Fancy Quote style, a delicious tomato color text: +Now when you view in the editor and publish, you will see your Fancy Quote style, a delicious tomato color text: ![Fancy Quote with Style](https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/assets/fancy-quote-with-style.png) From 5cfd596b782ae3d5213ee6bbbc88b6c11365b6f6 Mon Sep 17 00:00:00 2001 From: Marty Helmick Date: Thu, 30 May 2019 10:18:55 -0400 Subject: [PATCH 009/132] Move misplaced style imports to editor.css (#14607) * Move misplaced editor styles to editor.css * Add comment & rename files. --- .../src/block/edit-panel/{style.scss => editor.scss} | 0 .../src/block/indicator/{style.scss => editor.scss} | 0 packages/block-library/src/editor.scss | 5 +++++ packages/block-library/src/style.scss | 2 -- 4 files changed, 5 insertions(+), 2 deletions(-) rename packages/block-library/src/block/edit-panel/{style.scss => editor.scss} (100%) rename packages/block-library/src/block/indicator/{style.scss => editor.scss} (100%) diff --git a/packages/block-library/src/block/edit-panel/style.scss b/packages/block-library/src/block/edit-panel/editor.scss similarity index 100% rename from packages/block-library/src/block/edit-panel/style.scss rename to packages/block-library/src/block/edit-panel/editor.scss diff --git a/packages/block-library/src/block/indicator/style.scss b/packages/block-library/src/block/indicator/editor.scss similarity index 100% rename from packages/block-library/src/block/indicator/style.scss rename to packages/block-library/src/block/indicator/editor.scss diff --git a/packages/block-library/src/editor.scss b/packages/block-library/src/editor.scss index c0c465d33ffbf3..99493394ed43f4 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -34,6 +34,11 @@ @import "./verse/editor.scss"; @import "./video/editor.scss"; +/** + * Import styles from internal editor components used by the blocks. + */ +@import "./block/edit-panel/editor.scss"; +@import "./block/indicator/editor.scss"; /** * Editor Normalization Styles diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index 73325d5d9167c1..7ebad4a855135e 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -1,6 +1,4 @@ @import "./audio/style.scss"; -@import "./block/edit-panel/style.scss"; -@import "./block/indicator/style.scss"; @import "./button/style.scss"; @import "./calendar/style.scss"; @import "./categories/style.scss"; From cb8e5d95e883f201c9c1ba57811c42e2453c5b7c Mon Sep 17 00:00:00 2001 From: Kjell Reigstad Date: Thu, 30 May 2019 10:35:56 -0400 Subject: [PATCH 010/132] Correct default appender insertter jumpiness in Safari (#15892) --- .../src/components/default-block-appender/style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/components/default-block-appender/style.scss b/packages/block-editor/src/components/default-block-appender/style.scss index c5cb3ac744571b..565d12230d0be5 100644 --- a/packages/block-editor/src/components/default-block-appender/style.scss +++ b/packages/block-editor/src/components/default-block-appender/style.scss @@ -32,6 +32,7 @@ .block-editor-inserter__toggle:not([aria-expanded="true"]) { opacity: 0; transition: opacity 0.2s; + will-change: opacity; } &:hover { From d52664c79fd6af8779806e995cebd3b8fc6b53e9 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 30 May 2019 10:50:17 -0400 Subject: [PATCH 011/132] Build Tooling: Optimize build by spawning worker pool (#15230) * Build Tooling: Create worker pool for build * Build Tooling: Define build concurrency explicitly * Revert "Build Tooling: Define build concurrency explicitly" This reverts commit 4338f9e09d9d502409fee00ea1062ea369d0f8c6. * Build Tooling: Implement build files sourcing as stream * Build Tooling: Reinstate error handling to build script * Build Tooling: Log build error to stderr Co-Authored-By: Daniel Richards * Build: Assign non-zero exit code on build error Co-Authored-By: Daniel Richards --- bin/packages/build-worker.js | 159 +++++++++++++++++++++ bin/packages/build.js | 261 +++++++++-------------------------- package-lock.json | 114 ++++++++++++--- package.json | 7 +- 4 files changed, 327 insertions(+), 214 deletions(-) create mode 100644 bin/packages/build-worker.js diff --git a/bin/packages/build-worker.js b/bin/packages/build-worker.js new file mode 100644 index 00000000000000..7e3e636c013a1d --- /dev/null +++ b/bin/packages/build-worker.js @@ -0,0 +1,159 @@ +/** + * External dependencies + */ +const { promisify } = require( 'util' ); +const fs = require( 'fs' ); +const path = require( 'path' ); +const babel = require( '@babel/core' ); +const makeDir = require( 'make-dir' ); +const sass = require( 'node-sass' ); +const postcss = require( 'postcss' ); + +/** + * Internal dependencies + */ +const getBabelConfig = require( './get-babel-config' ); + +/** + * Path to packages directory. + * + * @type {string} + */ +const PACKAGES_DIR = path.resolve( __dirname, '../../packages' ); + +/** + * Mapping of JavaScript environments to corresponding build output. + * + * @type {Object} + */ +const JS_ENVIRONMENTS = { + main: 'build', + module: 'build-module', +}; + +/** + * Promisified fs.readFile. + * + * @type {Function} + */ +const readFile = promisify( fs.readFile ); + +/** + * Promisified fs.writeFile. + * + * @type {Function} + */ +const writeFile = promisify( fs.writeFile ); + +/** + * Promisified sass.render. + * + * @type {Function} + */ +const renderSass = promisify( sass.render ); + +/** + * Get the package name for a specified file + * + * @param {string} file File name + * @return {string} Package name + */ +function getPackageName( file ) { + return path.relative( PACKAGES_DIR, file ).split( path.sep )[ 0 ]; +} + +/** + * Get Build Path for a specified file. + * + * @param {string} file File to build + * @param {string} buildFolder Output folder + * @return {string} Build path + */ +function getBuildPath( file, buildFolder ) { + const pkgName = getPackageName( file ); + const pkgSrcPath = path.resolve( PACKAGES_DIR, pkgName, 'src' ); + const pkgBuildPath = path.resolve( PACKAGES_DIR, pkgName, buildFolder ); + const relativeToSrcPath = path.relative( pkgSrcPath, file ); + return path.resolve( pkgBuildPath, relativeToSrcPath ); +} + +/** + * Object of build tasks per file extension. + * + * @type {Object} + */ +const BUILD_TASK_BY_EXTENSION = { + async '.scss'( file ) { + const outputFile = getBuildPath( file.replace( '.scss', '.css' ), 'build-style' ); + const outputFileRTL = getBuildPath( file.replace( '.scss', '-rtl.css' ), 'build-style' ); + + const [ , contents ] = await Promise.all( [ + makeDir( path.dirname( outputFile ) ), + readFile( file, 'utf8' ), + ] ); + + const builtSass = await renderSass( { + file, + includePaths: [ path.resolve( __dirname, '../../assets/stylesheets' ) ], + data: ( + [ + 'colors', + 'breakpoints', + 'variables', + 'mixins', + 'animations', + 'z-index', + ].map( ( imported ) => `@import "${ imported }";` ).join( ' ' ) + + contents + ), + } ); + + const result = await postcss( require( './post-css-config' ) ).process( builtSass.css, { + from: 'src/app.css', + to: 'dest/app.css', + } ); + + const resultRTL = await postcss( [ require( 'rtlcss' )() ] ).process( result.css, { + from: 'src/app.css', + to: 'dest/app.css', + } ); + + await Promise.all( [ + writeFile( outputFile, result.css ), + writeFile( outputFileRTL, resultRTL.css ), + ] ); + }, + + async '.js'( file ) { + for ( const [ environment, buildDir ] of Object.entries( JS_ENVIRONMENTS ) ) { + const destPath = getBuildPath( file, buildDir ); + const babelOptions = getBabelConfig( environment, file.replace( PACKAGES_DIR, '@wordpress' ) ); + + const [ , transformed ] = await Promise.all( [ + makeDir( path.dirname( destPath ) ), + babel.transformFileAsync( file, babelOptions ), + ] ); + + await Promise.all( [ + writeFile( destPath + '.map', JSON.stringify( transformed.map ) ), + writeFile( destPath, transformed.code + '\n//# sourceMappingURL=' + path.basename( destPath ) + '.map' ), + ] ); + } + }, +}; + +module.exports = async ( file, callback ) => { + const extension = path.extname( file ); + const task = BUILD_TASK_BY_EXTENSION[ extension ]; + + if ( ! task ) { + return; + } + + try { + await task( file ); + callback(); + } catch ( error ) { + callback( error ); + } +}; diff --git a/bin/packages/build.js b/bin/packages/build.js index bb6954b4102e7c..0f77d13ff06df3 100755 --- a/bin/packages/build.js +++ b/bin/packages/build.js @@ -1,220 +1,91 @@ -/** - * script to build WordPress packages into `build/` directory. - * - * Example: - * node ./scripts/build.js - */ +/* eslint-disable no-console */ /** * External dependencies */ -const fs = require( 'fs' ); const path = require( 'path' ); -const glob = require( 'glob' ); -const babel = require( '@babel/core' ); -const chalk = require( 'chalk' ); -const mkdirp = require( 'mkdirp' ); -const sass = require( 'node-sass' ); -const postcss = require( 'postcss' ); -const deasync = require( 'deasync' ); - -/** - * Internal dependencies - */ -const getPackages = require( './get-packages' ); -const getBabelConfig = require( './get-babel-config' ); - -/** - * Module Constants - */ -const PACKAGES_DIR = path.resolve( __dirname, '../../packages' ); -const SRC_DIR = 'src'; -const BUILD_DIR = { - main: 'build', - module: 'build-module', - style: 'build-style', -}; -const DONE = chalk.reset.inverse.bold.green( ' DONE ' ); - -/** - * Get the package name for a specified file - * - * @param {string} file File name - * @return {string} Package name - */ -function getPackageName( file ) { - return path.relative( PACKAGES_DIR, file ).split( path.sep )[ 0 ]; -} - -const isJsFile = ( filepath ) => { - return /.\.js$/.test( filepath ); -}; +const glob = require( 'fast-glob' ); +const ProgressBar = require( 'progress' ); +const workerFarm = require( 'worker-farm' ); +const { Readable } = require( 'stream' ); -const isScssFile = ( filepath ) => { - return /.\.scss$/.test( filepath ); -}; +const files = process.argv.slice( 2 ); /** - * Get Build Path for a specified file + * Path to packages directory. * - * @param {string} file File to build - * @param {string} buildFolder Output folder - * @return {string} Build path + * @type {string} */ -function getBuildPath( file, buildFolder ) { - const pkgName = getPackageName( file ); - const pkgSrcPath = path.resolve( PACKAGES_DIR, pkgName, SRC_DIR ); - const pkgBuildPath = path.resolve( PACKAGES_DIR, pkgName, buildFolder ); - const relativeToSrcPath = path.relative( pkgSrcPath, file ); - return path.resolve( pkgBuildPath, relativeToSrcPath ); -} +const PACKAGES_DIR = path.resolve( __dirname, '../../packages' ); -/** - * Given a list of scss and js filepaths, divide them into sets them and rebuild. - * - * @param {Array} files list of files to rebuild - */ -function buildFiles( files ) { - // Reduce files into a unique sets of javaScript files and scss packages. - const buildPaths = files.reduce( ( accumulator, filePath ) => { - if ( isJsFile( filePath ) ) { - accumulator.jsFiles.add( filePath ); - } else if ( isScssFile( filePath ) ) { - const pkgName = getPackageName( filePath ); - const pkgPath = path.resolve( PACKAGES_DIR, pkgName ); - accumulator.scssPackagePaths.add( pkgPath ); - } - return accumulator; - }, { jsFiles: new Set(), scssPackagePaths: new Set() } ); +let onFileComplete = () => {}; - buildPaths.jsFiles.forEach( buildJsFile ); - buildPaths.scssPackagePaths.forEach( buildPackageScss ); -} +let stream; -/** - * Build a javaScript file for the required environments (node and ES5) - * - * @param {string} file File path to build - * @param {boolean} silent Show logs - */ -function buildJsFile( file, silent ) { - buildJsFileFor( file, silent, 'main' ); - buildJsFileFor( file, silent, 'module' ); -} - -/** - * Build a package's scss styles - * - * @param {string} packagePath The path to the package. - */ -function buildPackageScss( packagePath ) { - const srcDir = path.resolve( packagePath, SRC_DIR ); - const scssFiles = glob.sync( `${ srcDir }/*.scss` ); - - // Build scss files individually. - scssFiles.forEach( buildScssFile ); -} - -function buildScssFile( styleFile ) { - const outputFile = getBuildPath( styleFile.replace( '.scss', '.css' ), BUILD_DIR.style ); - const outputFileRTL = getBuildPath( styleFile.replace( '.scss', '-rtl.css' ), BUILD_DIR.style ); - mkdirp.sync( path.dirname( outputFile ) ); - const builtSass = sass.renderSync( { - file: styleFile, - includePaths: [ path.resolve( __dirname, '../../assets/stylesheets' ) ], - data: ( - [ - 'colors', - 'breakpoints', - 'variables', - 'mixins', - 'animations', - 'z-index', - ].map( ( imported ) => `@import "${ imported }";` ).join( ' ' ) + - fs.readFileSync( styleFile, 'utf8' ) - ), +if ( files.length ) { + stream = new Readable( { encoding: 'utf8' } ); + files.forEach( ( file ) => stream.push( file ) ); + stream.push( null ); +} else { + const bar = new ProgressBar( 'Build Progress: [:bar] :percent', { + width: 30, + incomplete: ' ', + total: 1, } ); - const postCSSSync = ( callback ) => { - postcss( require( './post-css-config' ) ) - .process( builtSass.css, { from: 'src/app.css', to: 'dest/app.css' } ) - .then( ( result ) => callback( null, result ) ); - }; - - const postCSSRTLSync = ( ltrCSS, callback ) => { - postcss( [ require( 'rtlcss' )() ] ) - .process( ltrCSS, { from: 'src/app.css', to: 'dest/app.css' } ) - .then( ( result ) => callback( null, result ) ); - }; - - const result = deasync( postCSSSync )(); - fs.writeFileSync( outputFile, result.css ); - - const resultRTL = deasync( postCSSRTLSync )( result ); - fs.writeFileSync( outputFileRTL, resultRTL ); -} - -/** - * Build a file for a specific environment - * - * @param {string} file File path to build - * @param {boolean} silent Show logs - * @param {string} environment Dist environment (node or es5) - */ -function buildJsFileFor( file, silent, environment ) { - const buildDir = BUILD_DIR[ environment ]; - const destPath = getBuildPath( file, buildDir ); - const babelOptions = getBabelConfig( environment, file.replace( PACKAGES_DIR, '@wordpress' ) ); - - mkdirp.sync( path.dirname( destPath ) ); - const transformed = babel.transformFileSync( file, babelOptions ); - fs.writeFileSync( destPath + '.map', JSON.stringify( transformed.map ) ); - fs.writeFileSync( destPath, transformed.code + '\n//# sourceMappingURL=' + path.basename( destPath ) + '.map' ); - - if ( ! silent ) { - process.stdout.write( - chalk.green( ' \u2022 ' ) + - path.relative( PACKAGES_DIR, file ) + - chalk.green( ' \u21D2 ' ) + - path.relative( PACKAGES_DIR, destPath ) + - '\n' - ); - } -} + bar.tick( 0 ); -/** - * Build the provided package path - * - * @param {string} packagePath absolute package path - */ -function buildPackage( packagePath ) { - const srcDir = path.resolve( packagePath, SRC_DIR ); - const jsFiles = glob.sync( `${ srcDir }/**/*.js`, { + stream = glob.stream( [ + `${ PACKAGES_DIR }/*/src/**/*.js`, + `${ PACKAGES_DIR }/*/src/*.scss`, + ], { ignore: [ - `${ srcDir }/**/test/**/*.js`, - `${ srcDir }/**/__mocks__/**/*.js`, + `**/test/**`, + `**/__mocks__/**`, ], - nodir: true, + onlyFiles: true, } ); - process.stdout.write( `${ path.basename( packagePath ) }\n` ); + // Pause to avoid data flow which would begin on the `data` event binding, + // but should wait until worker processing below. + // + // See: https://nodejs.org/api/stream.html#stream_two_reading_modes + stream + .pause() + .on( 'data', ( file ) => { + bar.total = files.push( file ); + } ); + + onFileComplete = () => { + bar.tick(); + }; +} - // Build js files individually. - jsFiles.forEach( ( file ) => buildJsFile( file, true ) ); +const worker = workerFarm( require.resolve( './build-worker' ) ); - // Build package CSS files - buildPackageScss( packagePath ); +let ended = false, + complete = 0; - process.stdout.write( `${ DONE }\n` ); -} +stream + .on( 'data', ( file ) => worker( file, ( error ) => { + onFileComplete(); -const files = process.argv.slice( 2 ); + if ( error ) { + // If an error occurs, the process can't be ended immediately since + // other workers are likely pending. Optimally, it would end at the + // earliest opportunity (after the current round of workers has had + // the chance to complete), but this is not made directly possible + // through `worker-farm`. Instead, ensure at least that when the + // process does exit, it exits with a non-zero code to reflect the + // fact that an error had occurred. + process.exitCode = 1; -if ( files.length ) { - buildFiles( files ); -} else { - process.stdout.write( chalk.inverse( '>> Building packages \n' ) ); - getPackages() - .forEach( buildPackage ); - process.stdout.write( '\n' ); -} + console.error( error ); + } + + if ( ended && ++complete === files.length ) { + workerFarm.end( worker ); + } + } ) ) + .on( 'end', () => ended = true ) + .resume(); diff --git a/package-lock.json b/package-lock.json index 0ad23808055801..00d2e2b1810a07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9352,9 +9352,9 @@ "dev": true }, "fast-glob": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz", - "integrity": "sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "dev": true, "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", @@ -9520,6 +9520,23 @@ "commondir": "^1.0.1", "make-dir": "^1.0.0", "pkg-dir": "^2.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "find-file-up": { @@ -12129,6 +12146,21 @@ "dev": true } } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, @@ -12181,6 +12213,21 @@ "supports-color": "^6.0.0" }, "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, "supports-color": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", @@ -12214,12 +12261,27 @@ "ms": "^2.1.1" } }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -14239,18 +14301,18 @@ } }, "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz", + "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==", "dev": true, "requires": { - "pify": "^3.0.0" + "semver": "^6.0.0" }, "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", "dev": true } } @@ -18023,9 +18085,9 @@ "dev": true }, "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "promise": { @@ -21164,6 +21226,15 @@ "uuid": "^3.0.1" }, "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -22821,9 +22892,9 @@ "dev": true }, "worker-farm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "dev": true, "requires": { "errno": "~0.1.7" @@ -22902,6 +22973,15 @@ "write-file-atomic": "^2.0.0" }, "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", diff --git a/package.json b/package.json index 527d358b982b37..1270e1adde7bd3 100644 --- a/package.json +++ b/package.json @@ -90,12 +90,12 @@ "core-js": "3.0.1", "cross-env": "3.2.4", "cssnano": "4.1.10", - "deasync": "0.1.14", "deep-freeze": "0.0.1", "doctrine": "2.1.0", "enzyme": "3.9.0", "eslint-plugin-jest": "21.5.0", "espree": "4.0.0", + "fast-glob": "2.2.7", "fbjs": "0.8.17", "fs-extra": "8.0.1", "glob": "7.1.2", @@ -106,6 +106,7 @@ "lerna": "3.14.1", "lint-staged": "8.1.5", "lodash": "4.17.11", + "make-dir": "3.0.0", "mkdirp": "0.5.1", "node-sass": "4.12.0", "node-watch": "0.6.0", @@ -113,6 +114,7 @@ "pegjs": "0.10.0", "phpegjs": "1.0.0-beta7", "postcss": "7.0.13", + "progress": "2.0.3", "react": "16.8.4", "react-dom": "16.8.4", "react-test-renderer": "16.8.4", @@ -128,7 +130,8 @@ "sprintf-js": "1.1.1", "stylelint-config-wordpress": "13.1.0", "uuid": "3.3.2", - "webpack": "4.8.3" + "webpack": "4.8.3", + "worker-farm": "1.7.0" }, "npmPackageJsonLintConfig": { "extends": "@wordpress/npm-package-json-lint-config", From 580511198c1b1d15fa3eb6f609ef20d25009e5bc Mon Sep 17 00:00:00 2001 From: Kjell Reigstad Date: Thu, 30 May 2019 10:52:06 -0400 Subject: [PATCH 012/132] Only apply appender margins when the appender is inside of a block (#15888) * Only apply appender margins when the appender exists within a block. * Add code comment to explain the extra specificity. --- .../src/components/block-list-appender/style.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-list-appender/style.scss b/packages/block-editor/src/components/block-list-appender/style.scss index e1725aa00873a6..5f83d4b44b290b 100644 --- a/packages/block-editor/src/components/block-list-appender/style.scss +++ b/packages/block-editor/src/components/block-list-appender/style.scss @@ -1,4 +1,6 @@ -.block-list-appender { +// These styles are only applied to the appender when it appears inside of a block. +// Otherwise the default appender may be improperly positioned in some themes. +.block-editor-block-list__block .block-list-appender { margin: $block-padding; // Add additional margin to the appender when inside a group with a background color. From 2acb7d5491888f2913207b01043e7bb85d2241f6 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Thu, 30 May 2019 10:53:58 -0400 Subject: [PATCH 013/132] Framework: Remove packages build from build, dev scripts (#15226) * Framework: Omit Babel processing from Webpack configuration * Framework: Remove packages build from build, dev scripts * Build Tooling: Update Webpack config to operate on source files * Revert "Build Tooling: Update Webpack config to operate on source files" This reverts commit 8ca8c18d813cdac1d783cc87dbe006b4595214e0. * Revert "Framework: Remove packages build from build, dev scripts" This reverts commit 0021e5ceecadcc28c46cb4388c68fdc199d392ca. * Scripts: Add flag `--no-babel` for excluding Babel processing * Framework: Exclude Babel processing by build script flag * Framework: Avoid extending default configuration in Webpack build --- package.json | 1 + webpack.config.js | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1270e1adde7bd3..54a3034abafc94 100644 --- a/package.json +++ b/package.json @@ -127,6 +127,7 @@ "shallow-equals": "1.0.0", "shallowequal": "1.1.0", "simple-git": "1.113.0", + "source-map-loader": "0.2.4", "sprintf-js": "1.1.1", "stylelint-config-wordpress": "13.1.0", "uuid": "3.3.2", diff --git a/webpack.config.js b/webpack.config.js index ba130ce0992d4a..3de56a819e0de8 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,7 +4,7 @@ const { DefinePlugin } = require( 'webpack' ); const CopyWebpackPlugin = require( 'copy-webpack-plugin' ); const postcss = require( 'postcss' ); -const { get, escapeRegExp } = require( 'lodash' ); +const { get, escapeRegExp, compact } = require( 'lodash' ); const { basename, sep } = require( 'path' ); /** @@ -12,7 +12,7 @@ const { basename, sep } = require( 'path' ); */ const CustomTemplatedPathPlugin = require( '@wordpress/custom-templated-path-webpack-plugin' ); const LibraryExportDefaultPlugin = require( '@wordpress/library-export-default-webpack-plugin' ); -const defaultConfig = require( '@wordpress/scripts/config/webpack.config' ); +const DependencyExtractionWebpackPlugin = require( '@wordpress/dependency-extraction-webpack-plugin' ); const { camelCaseDash } = require( '@wordpress/scripts/utils' ); /** @@ -20,6 +20,11 @@ const { camelCaseDash } = require( '@wordpress/scripts/utils' ); */ const { dependencies } = require( './package' ); +const { + NODE_ENV: mode = 'development', + WP_DEVTOOL: devtool = ( mode === 'production' ? false : 'source-map' ), +} = process.env; + const WORDPRESS_NAMESPACE = '@wordpress/'; const gutenbergPackages = Object.keys( dependencies ) @@ -27,7 +32,7 @@ const gutenbergPackages = Object.keys( dependencies ) .map( ( packageName ) => packageName.replace( WORDPRESS_NAMESPACE, '' ) ); module.exports = { - ...defaultConfig, + mode, entry: gutenbergPackages.reduce( ( memo, packageName ) => { const name = camelCaseDash( packageName ); memo[ name ] = `./packages/${ packageName }`; @@ -39,8 +44,16 @@ module.exports = { library: [ 'wp', '[name]' ], libraryTarget: 'this', }, + module: { + rules: compact( [ + mode !== 'production' && { + test: /\.js$/, + use: require.resolve( 'source-map-loader' ), + enforce: 'pre', + }, + ] ), + }, plugins: [ - ...defaultConfig.plugins, new DefinePlugin( { // Inject the `GUTENBERG_PHASE` global, used for feature flagging. // eslint-disable-next-line @wordpress/gutenberg-phase @@ -82,7 +95,7 @@ module.exports = { to: `./build/${ packageName }/`, flatten: true, transform: ( content ) => { - if ( defaultConfig.mode === 'production' ) { + if ( mode === 'production' ) { return postcss( [ require( 'cssnano' )( { preset: [ 'default', { @@ -134,5 +147,7 @@ module.exports = { }, }, ] ), + new DependencyExtractionWebpackPlugin( { injectPolyfill: true } ), ], + devtool, }; From 500a17d05045a22e42196d27eecf7d098eceaee9 Mon Sep 17 00:00:00 2001 From: Andrew Duthie Date: Fri, 31 May 2019 02:05:41 -0400 Subject: [PATCH 014/132] Build: Rebuild package stylesheet entrypoints for file updates (#15920) --- bin/packages/build.js | 49 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/bin/packages/build.js b/bin/packages/build.js index 0f77d13ff06df3..9639f8b232f70e 100755 --- a/bin/packages/build.js +++ b/bin/packages/build.js @@ -7,7 +7,7 @@ const path = require( 'path' ); const glob = require( 'fast-glob' ); const ProgressBar = require( 'progress' ); const workerFarm = require( 'worker-farm' ); -const { Readable } = require( 'stream' ); +const { Readable, Transform } = require( 'stream' ); const files = process.argv.slice( 2 ); @@ -18,6 +18,52 @@ const files = process.argv.slice( 2 ); */ const PACKAGES_DIR = path.resolve( __dirname, '../../packages' ); +/** + * Get the package name for a specified file + * + * @param {string} file File name + * @return {string} Package name + */ +function getPackageName( file ) { + return path.relative( PACKAGES_DIR, file ).split( path.sep )[ 0 ]; +} + +/** + * Returns a stream transform which maps an individual stylesheet to its + * package entrypoint. Unlike JavaScript which uses an external bundler to + * efficiently manage rebuilds by entrypoints, stylesheets are rebuilt fresh + * in their entirety from the build script. + * + * @return {Transform} Stream transform instance. + */ +function createStyleEntryTransform() { + const packages = new Set; + + return new Transform( { + objectMode: true, + async transform( file, encoding, callback ) { + // Only stylesheets are subject to this transform. + if ( path.extname( file ) !== '.scss' ) { + this.push( file ); + callback(); + return; + } + + // Only operate once per package, assuming entries are common. + const packageName = getPackageName( file ); + if ( packages.has( packageName ) ) { + callback(); + return; + } + + packages.add( packageName ); + const entries = await glob( path.resolve( PACKAGES_DIR, packageName, 'src/*.scss' ) ); + entries.forEach( ( entry ) => this.push( entry ) ); + callback(); + }, + } ); +} + let onFileComplete = () => {}; let stream; @@ -26,6 +72,7 @@ if ( files.length ) { stream = new Readable( { encoding: 'utf8' } ); files.forEach( ( file ) => stream.push( file ) ); stream.push( null ); + stream = stream.pipe( createStyleEntryTransform() ); } else { const bar = new ProgressBar( 'Build Progress: [:bar] :percent', { width: 30, From dfa137fe052553ba150fc5cb3fe2144d10072079 Mon Sep 17 00:00:00 2001 From: Truong Giang Date: Fri, 31 May 2019 13:28:59 +0700 Subject: [PATCH 015/132] Update writing-your-first-block-type.md (#15717) Fix some wrong strings in writing-your-first-block-type.md --- .../block-tutorial/writing-your-first-block-type.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md b/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md index c959b4cd5aec58..a4ac0f7a33de9b 100644 --- a/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md +++ b/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md @@ -90,16 +90,16 @@ registerBlockType( 'gutenberg-examples/example-01-basic-esnext', { icon: 'universal-access-alt', category: 'layout', edit() { - return
Basic example with JSX! (editor)
; + return
Hello World, step 1 (from the editor).
; }, save() { - return
Basic example with JSX! (front)
; + return
Hello World, step 1 (from the frontend).
; }, } ); ``` {% end %} -_By now you should be able to see `Hello editor` in the admin side and `Hello saved content` on the frontend side._ +_By now you should be able to see `Hello World, step 1 (from the editor).` in the admin side and `Hello World, step 1 (from the frontend).` on the frontend side._ Once a block is registered, you should immediately see that it becomes available as an option in the editor inserter dialog, using values from `title`, `icon`, and `category` to organize its display. You can choose an icon from any included in the built-in [Dashicons icon set](https://developer.wordpress.org/resource/dashicons/), or provide a [custom svg element](/docs/designers-developers/developers/block-api/block-registration.md#icon-optional). From 37b3517662e0fba9f4f0a678514b589f80229e3c Mon Sep 17 00:00:00 2001 From: Kjell Reigstad Date: Fri, 31 May 2019 04:47:17 -0400 Subject: [PATCH 016/132] Stack consecutive buttons in the featured image area at all times. (#15928) --- packages/editor/src/components/post-featured-image/style.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/components/post-featured-image/style.scss b/packages/editor/src/components/post-featured-image/style.scss index 3258e6191124b2..ccdbafe2e34e35 100644 --- a/packages/editor/src/components/post-featured-image/style.scss +++ b/packages/editor/src/components/post-featured-image/style.scss @@ -5,10 +5,10 @@ margin: 0; } - // Space consecutive buttons evenly. + // Stack consecutive buttons. .components-button + .components-button { + display: block; margin-top: 1em; - margin-right: 8px; } // This keeps images at their intrinsic size (eg. a 50px From 5dda5fa5ac252f149246582bccff082831a0d2e5 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 31 May 2019 10:59:39 +0100 Subject: [PATCH 017/132] Allow core widgets to be used in the legacy widgets block (#15396) * Allow core widgets to be used in the legacy widgets block (although not selectable). * Extract the placeholder. * Don't show 'Change widget' button when displaying a core widget * Move LegacyWidgetPlaceholder to its own file --- lib/widgets.php | 23 ++++--- .../src/legacy-widget/edit/index.js | 66 +++++-------------- .../src/legacy-widget/edit/placeholder.js | 57 ++++++++++++++++ 3 files changed, 86 insertions(+), 60 deletions(-) create mode 100644 packages/block-library/src/legacy-widget/edit/placeholder.js diff --git a/lib/widgets.php b/lib/widgets.php index 28ebc003674759..7ea5d3a5e770dd 100644 --- a/lib/widgets.php +++ b/lib/widgets.php @@ -102,18 +102,17 @@ function gutenberg_get_legacy_widget_settings() { $available_legacy_widgets = array(); global $wp_widget_factory, $wp_registered_widgets; foreach ( $wp_widget_factory->widgets as $class => $widget_obj ) { - if ( ! in_array( $class, $core_widgets ) ) { - $available_legacy_widgets[ $class ] = array( - 'name' => html_entity_decode( $widget_obj->name ), - // wp_widget_description is not being used because its input parameter is a Widget Id. - // Widgets id's reference to a specific widget instance. - // Here we are iterating on all the available widget classes even if no widget instance exists for them. - 'description' => isset( $widget_obj->widget_options['description'] ) ? - html_entity_decode( $widget_obj->widget_options['description'] ) : - null, - 'isCallbackWidget' => false, - ); - } + $available_legacy_widgets[ $class ] = array( + 'name' => html_entity_decode( $widget_obj->name ), + // wp_widget_description is not being used because its input parameter is a Widget Id. + // Widgets id's reference to a specific widget instance. + // Here we are iterating on all the available widget classes even if no widget instance exists for them. + 'description' => isset( $widget_obj->widget_options['description'] ) ? + html_entity_decode( $widget_obj->widget_options['description'] ) : + null, + 'isCallbackWidget' => false, + 'isHidden' => in_array( $class, $core_widgets, true ), + ); } foreach ( $wp_registered_widgets as $widget_id => $widget_obj ) { if ( diff --git a/packages/block-library/src/legacy-widget/edit/index.js b/packages/block-library/src/legacy-widget/edit/index.js index 4b645318eb2277..ac38184d22989b 100644 --- a/packages/block-library/src/legacy-widget/edit/index.js +++ b/packages/block-library/src/legacy-widget/edit/index.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { map } from 'lodash'; - /** * WordPress dependencies */ @@ -11,15 +6,12 @@ import { Button, IconButton, PanelBody, - Placeholder, - SelectControl, Toolbar, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { withSelect } from '@wordpress/data'; import { BlockControls, - BlockIcon, InspectorControls, } from '@wordpress/block-editor'; import { ServerSideRender } from '@wordpress/editor'; @@ -28,6 +20,7 @@ import { ServerSideRender } from '@wordpress/editor'; * Internal dependencies */ import LegacyWidgetEditHandler from './handler'; +import LegacyWidgetPlaceholder from './placeholder'; class LegacyWidgetEdit extends Component { constructor() { @@ -51,41 +44,17 @@ class LegacyWidgetEdit extends Component { const { identifier, isCallbackWidget } = attributes; const widgetObject = identifier && availableLegacyWidgets[ identifier ]; if ( ! widgetObject ) { - let placeholderContent; - - if ( ! hasPermissionsToManageWidgets ) { - placeholderContent = __( 'You don\'t have permissions to use widgets on this site.' ); - } else if ( availableLegacyWidgets.length === 0 ) { - placeholderContent = __( 'There are no widgets available.' ); - } else { - placeholderContent = ( - setAttributes( { - instance: {}, - identifier: value, - isCallbackWidget: availableLegacyWidgets[ value ].isCallbackWidget, - } ) } - options={ [ { value: 'none', label: 'Select widget' } ].concat( - map( availableLegacyWidgets, ( widget, key ) => { - return { - value: key, - label: widget.name, - }; - } ) - ) } - /> - ); - } - return ( - } - label={ __( 'Legacy Widget' ) } - > - { placeholderContent } - + setAttributes( { + instance: {}, + identifier: newWidget, + isCallbackWidget: availableLegacyWidgets[ newWidget ].isCallbackWidget, + } ) } + /> ); } @@ -109,12 +78,13 @@ class LegacyWidgetEdit extends Component { <> - - + { ! widgetObject.isHidden && ( + + ) } { ! isCallbackWidget && ( <> - - - - - + > + + + + + + + + + + + + `; diff --git a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap index 6e395b2e7ebae9..0a2564900eda2e 100644 --- a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap @@ -5,6 +5,7 @@ exports[`PluginMoreMenuItem renders menu item as button properly 1`] = ` className="components-menu-group" >
+} + +const SaleButton = ( { children } ) => { + const { stockNumber } = useSelect( + ( select ) => select( 'my-shop' ).getStockNumber() + ); + const { startSale } = useDispatch( 'my-shop' ); + const onClick = useCallback( () => { + const discountPercent = stockNumber > 50 ? 10: 20; + startSale( discountPercent ); + }, [ stockNumber ] ); + return +} + +// Rendered somewhere in the application: +// +// Start Sale! +``` + +_Parameters_ + +- _storeName_ `[string]`: Optionally provide the name of the store from which to retrieve action creators. If not provided, the registry.dispatch function is returned instead. + +_Returns_ + +- `Function`: A custom react hook. + # **useRegistry** A custom react hook exposing the registry context for use. @@ -573,53 +619,64 @@ _Returns_ # **withDispatch** -Higher-order component used to add dispatch props using registered action creators. +Higher-order component used to add dispatch props using registered action +creators. _Usage_ ```jsx function Button( { onClick, children } ) { - return ; + return ; } const { withDispatch } = wp.data; const SaleButton = withDispatch( ( dispatch, ownProps ) => { - const { startSale } = dispatch( 'my-shop' ); - const { discountPercent } = ownProps; - - return { - onClick() { - startSale( discountPercent ); - }, - }; + const { startSale } = dispatch( 'my-shop' ); + const { discountPercent } = ownProps; + + return { + onClick() { + startSale( discountPercent ); + }, + }; } )( Button ); // Rendered in the application: // -// Start Sale! +// Start Sale! ``` -In the majority of cases, it will be sufficient to use only two first params passed to `mapDispatchToProps` as illustrated in the previous example. However, there might be some very advanced use cases where using the `registry` object might be used as a tool to optimize the performance of your component. Using `select` function from the registry might be useful when you need to fetch some dynamic data from the store at the time when the event is fired, but at the same time, you never use it to render your component. In such scenario, you can avoid using the `withSelect` higher order component to compute such prop, which might lead to unnecessary re-renders of your component caused by its frequent value change. Keep in mind, that `mapDispatchToProps` must return an object with functions only. +In the majority of cases, it will be sufficient to use only two first params +passed to `mapDispatchToProps` as illustrated in the previous example. +However, there might be some very advanced use cases where using the +`registry` object might be used as a tool to optimize the performance of +your component. Using `select` function from the registry might be useful +when you need to fetch some dynamic data from the store at the time when the +event is fired, but at the same time, you never use it to render your +component. In such scenario, you can avoid using the `withSelect` higher +order component to compute such prop, which might lead to unnecessary +re-renders of your component caused by its frequent value change. +Keep in mind, that `mapDispatchToProps` must return an object with functions +only. ```jsx function Button( { onClick, children } ) { - return ; + return ; } const { withDispatch } = wp.data; const SaleButton = withDispatch( ( dispatch, ownProps, { select } ) => { - // Stock number changes frequently. - const { getStockNumber } = select( 'my-shop' ); - const { startSale } = dispatch( 'my-shop' ); - - return { - onClick() { - const dicountPercent = getStockNumber() > 50 ? 10 : 20; - startSale( discountPercent ); - }, - }; + // Stock number changes frequently. + const { getStockNumber } = select( 'my-shop' ); + const { startSale } = dispatch( 'my-shop' ); + return { + onClick() { + const discountPercent = getStockNumber() > 50 ? 10 : 20; + startSale( discountPercent ); + }, + }; } )( Button ); // Rendered in the application: @@ -627,11 +684,9 @@ const SaleButton = withDispatch( ( dispatch, ownProps, { select } ) => { // Start Sale! ``` -_Note:_ It is important that the `mapDispatchToProps` function always returns an object with the same keys. For example, it should not contain conditions under which a different value would be returned. - _Parameters_ -- _mapDispatchToProps_ `Object`: Object of prop names where value is a dispatch-bound action creator, or a function to be called with the component's props and returning an action creator. +- _mapDispatchToProps_ `Function`: A function of returning an object of prop names where value is a dispatch-bound action creator, or a function to be called with the component's props and returning an action creator. _Returns_ diff --git a/packages/data/src/components/use-dispatch/index.js b/packages/data/src/components/use-dispatch/index.js new file mode 100644 index 00000000000000..f4f4fed37d38ca --- /dev/null +++ b/packages/data/src/components/use-dispatch/index.js @@ -0,0 +1,2 @@ +export { default as useDispatch } from './use-dispatch'; +export { default as useDispatchWithMap } from './use-dispatch-with-map'; diff --git a/packages/data/src/components/use-dispatch/test/use-dispatch.js b/packages/data/src/components/use-dispatch/test/use-dispatch.js new file mode 100644 index 00000000000000..8770d04144b06d --- /dev/null +++ b/packages/data/src/components/use-dispatch/test/use-dispatch.js @@ -0,0 +1,137 @@ +/** + * External dependencies + */ +import TestRenderer, { act } from 'react-test-renderer'; + +/** + * Internal dependencies + */ +import useDispatch from '../use-dispatch'; +import { createRegistry } from '../../../registry'; +import { RegistryProvider } from '../../registry-provider'; + +describe( 'useDispatch', () => { + let registry; + beforeEach( () => { + registry = createRegistry(); + } ); + + it( 'returns dispatch function from store with no store name provided', () => { + registry.registerStore( 'demoStore', { + reducer: ( state ) => state, + actions: { + foo: () => 'bar', + }, + } ); + const TestComponent = () => { + return
; + }; + const Component = () => { + const dispatch = useDispatch(); + return ; + }; + + let testRenderer; + act( () => { + testRenderer = TestRenderer.create( + + + + ); + } ); + + const testInstance = testRenderer.root; + + expect( testInstance.findByType( TestComponent ).props.dispatch ) + .toBe( registry.dispatch ); + } ); + it( 'returns expected action creators from store for given storeName', () => { + const noop = () => ( { type: '__INERT__' } ); + const testAction = jest.fn().mockImplementation( noop ); + registry.registerStore( 'demoStore', { + reducer: ( state ) => state, + actions: { + foo: testAction, + }, + } ); + const TestComponent = () => { + const { foo } = useDispatch( 'demoStore' ); + return + * } + * + * const SaleButton = ( { children } ) => { + * const { stockNumber } = useSelect( + * ( select ) => select( 'my-shop' ).getStockNumber() + * ); + * const { startSale } = useDispatch( 'my-shop' ); + * const onClick = useCallback( () => { + * const discountPercent = stockNumber > 50 ? 10: 20; + * startSale( discountPercent ); + * }, [ stockNumber ] ); + * return + * } + * + * // Rendered somewhere in the application: + * // + * // Start Sale! + * ``` + * @return {Function} A custom react hook. + */ +const useDispatch = ( storeName ) => { + const { dispatch } = useRegistry(); + return storeName === void 0 ? dispatch : dispatch( storeName ); +}; + +export default useDispatch; diff --git a/packages/data/src/components/with-dispatch/index.js b/packages/data/src/components/with-dispatch/index.js index 1da0aa95f3de7a..117edd1f598293 100644 --- a/packages/data/src/components/with-dispatch/index.js +++ b/packages/data/src/components/with-dispatch/index.js @@ -1,138 +1,97 @@ -/** - * External dependencies - */ -import { mapValues } from 'lodash'; - /** * WordPress dependencies */ -import { Component } from '@wordpress/element'; import { createHigherOrderComponent } from '@wordpress/compose'; /** * Internal dependencies */ -import { RegistryConsumer } from '../registry-provider'; +import { useDispatchWithMap } from '../use-dispatch'; /** - * Higher-order component used to add dispatch props using registered action creators. + * Higher-order component used to add dispatch props using registered action + * creators. * - * @param {Object} mapDispatchToProps Object of prop names where value is a - * dispatch-bound action creator, or a - * function to be called with the - * component's props and returning an - * action creator. + * @param {Function} mapDispatchToProps A function of returning an object of + * prop names where value is a + * dispatch-bound action creator, or a + * function to be called with the + * component's props and returning an + * action creator. * * @example * ```jsx * function Button( { onClick, children } ) { - * return ; + * return ; * } * * const { withDispatch } = wp.data; * * const SaleButton = withDispatch( ( dispatch, ownProps ) => { - * const { startSale } = dispatch( 'my-shop' ); - * const { discountPercent } = ownProps; + * const { startSale } = dispatch( 'my-shop' ); + * const { discountPercent } = ownProps; * - * return { - * onClick() { - * startSale( discountPercent ); - * }, - * }; + * return { + * onClick() { + * startSale( discountPercent ); + * }, + * }; * } )( Button ); * * // Rendered in the application: * // - * // Start Sale! + * // Start Sale! * ``` * * @example - * In the majority of cases, it will be sufficient to use only two first params passed to `mapDispatchToProps` as illustrated in the previous example. However, there might be some very advanced use cases where using the `registry` object might be used as a tool to optimize the performance of your component. Using `select` function from the registry might be useful when you need to fetch some dynamic data from the store at the time when the event is fired, but at the same time, you never use it to render your component. In such scenario, you can avoid using the `withSelect` higher order component to compute such prop, which might lead to unnecessary re-renders of your component caused by its frequent value change. Keep in mind, that `mapDispatchToProps` must return an object with functions only. + * In the majority of cases, it will be sufficient to use only two first params + * passed to `mapDispatchToProps` as illustrated in the previous example. + * However, there might be some very advanced use cases where using the + * `registry` object might be used as a tool to optimize the performance of + * your component. Using `select` function from the registry might be useful + * when you need to fetch some dynamic data from the store at the time when the + * event is fired, but at the same time, you never use it to render your + * component. In such scenario, you can avoid using the `withSelect` higher + * order component to compute such prop, which might lead to unnecessary + * re-renders of your component caused by its frequent value change. + * Keep in mind, that `mapDispatchToProps` must return an object with functions + * only. * * ```jsx * function Button( { onClick, children } ) { - * return ; + * return ; * } * * const { withDispatch } = wp.data; * * const SaleButton = withDispatch( ( dispatch, ownProps, { select } ) => { - * // Stock number changes frequently. - * const { getStockNumber } = select( 'my-shop' ); - * const { startSale } = dispatch( 'my-shop' ); - * - * return { - * onClick() { - * const dicountPercent = getStockNumber() > 50 ? 10 : 20; - * startSale( discountPercent ); - * }, - * }; + * // Stock number changes frequently. + * const { getStockNumber } = select( 'my-shop' ); + * const { startSale } = dispatch( 'my-shop' ); + * return { + * onClick() { + * const discountPercent = getStockNumber() > 50 ? 10 : 20; + * startSale( discountPercent ); + * }, + * }; * } )( Button ); * * // Rendered in the application: * // * // Start Sale! * ``` - * _Note:_ It is important that the `mapDispatchToProps` function always returns an object with the same keys. For example, it should not contain conditions under which a different value would be returned. * * @return {Component} Enhanced component with merged dispatcher props. */ const withDispatch = ( mapDispatchToProps ) => createHigherOrderComponent( - ( WrappedComponent ) => { - class ComponentWithDispatch extends Component { - constructor( props ) { - super( ...arguments ); - - this.proxyProps = {}; - - this.setProxyProps( props ); - } - - proxyDispatch( propName, ...args ) { - // Original dispatcher is a pre-bound (dispatching) action creator. - mapDispatchToProps( this.props.registry.dispatch, this.props.ownProps, this.props.registry )[ propName ]( ...args ); - } - - setProxyProps( props ) { - // Assign as instance property so that in subsequent render - // reconciliation, the prop values are referentially equal. - // Importantly, note that while `mapDispatchToProps` is - // called, it is done only to determine the keys for which - // proxy functions should be created. The actual registry - // dispatch does not occur until the function is called. - const propsToDispatchers = mapDispatchToProps( this.props.registry.dispatch, props.ownProps, this.props.registry ); - this.proxyProps = mapValues( propsToDispatchers, ( dispatcher, propName ) => { - if ( typeof dispatcher !== 'function' ) { - // eslint-disable-next-line no-console - console.warn( `Property ${ propName } returned from mapDispatchToProps in withDispatch must be a function.` ); - } - // Prebind with prop name so we have reference to the original - // dispatcher to invoke. Track between re-renders to avoid - // creating new function references every render. - if ( this.proxyProps.hasOwnProperty( propName ) ) { - return this.proxyProps[ propName ]; - } - - return this.proxyDispatch.bind( this, propName ); - } ); - } - - render() { - return ; - } - } - - return ( ownProps ) => ( - - { ( registry ) => ( - - ) } - + ( WrappedComponent ) => ( ownProps ) => { + const mapDispatch = ( dispatch, registry ) => mapDispatchToProps( + dispatch, + ownProps, + registry ); + const dispatchProps = useDispatchWithMap( mapDispatch, [] ); + return ; }, 'withDispatch' ); diff --git a/packages/data/src/components/with-dispatch/test/index.js b/packages/data/src/components/with-dispatch/test/index.js index 4bde9b30810ac1..66fba4028e84f8 100644 --- a/packages/data/src/components/with-dispatch/test/index.js +++ b/packages/data/src/components/with-dispatch/test/index.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import TestRenderer from 'react-test-renderer'; +import TestRenderer, { act } from 'react-test-renderer'; /** * Internal dependencies @@ -45,27 +45,34 @@ describe( 'withDispatch', () => { }; } )( ( props ) => - + } + instructions={ __( 'Insert a table for sharing data.' ) } + isColumnLayout + > +
+ + + + +
); } diff --git a/packages/block-library/src/table/editor.scss b/packages/block-library/src/table/editor.scss index 52f6a60e545d15..46ae863c31a0d9 100644 --- a/packages/block-library/src/table/editor.scss +++ b/packages/block-library/src/table/editor.scss @@ -40,4 +40,16 @@ &__cell-content { padding: 0.5em; } + // Extra specificity to override default Placeholder styles. + &__placeholder-form.wp-block-table__placeholder-form { + text-align: left; + align-items: center; + } + &__placeholder-input { + width: 100px; + } + &__placeholder-button { + min-width: 100px; + justify-content: center; + } } diff --git a/packages/components/src/placeholder/README.md b/packages/components/src/placeholder/README.md index 5d4c64a7f64f19..2a12363e7fde01 100644 --- a/packages/components/src/placeholder/README.md +++ b/packages/components/src/placeholder/README.md @@ -11,3 +11,12 @@ const MyPlaceholder = () => ( /> ); ``` + +### Props + +Name | Type | Default | Description +--- | --- | --- | --- +`icon` | `string, ReactElement` | `undefined` | If provided, renders an icon next to the label. +`label` | `string` | `undefined` | Renders a label for the placeholder. +`instructions` | `string` | `undefined` | Renders instruction text below label. +`isColumnLayout` | `bool` | `false` | Changes placeholder children layout from flex-row to flex-column. diff --git a/packages/components/src/placeholder/index.js b/packages/components/src/placeholder/index.js index e5a5b323f60c7d..8e49b70d5226ec 100644 --- a/packages/components/src/placeholder/index.js +++ b/packages/components/src/placeholder/index.js @@ -15,9 +15,9 @@ import Dashicon from '../dashicon'; * @param {Object} props The component props. * @return {Object} The rendered placeholder. */ -function Placeholder( { icon, children, label, instructions, className, notices, preview, ...additionalProps } ) { +function Placeholder( { icon, children, label, instructions, className, notices, preview, isColumnLayout, ...additionalProps } ) { const classes = classnames( 'components-placeholder', className ); - + const fieldsetClasses = classnames( 'components-placeholder__fieldset', { 'is-column-layout': isColumnLayout } ); return (
{ notices } @@ -31,7 +31,7 @@ function Placeholder( { icon, children, label, instructions, className, notices, { label }
{ !! instructions &&
{ instructions }
} -
+
{ children }
diff --git a/packages/components/src/placeholder/style.scss b/packages/components/src/placeholder/style.scss index 63938e69498e95..50e1da3d93af56 100644 --- a/packages/components/src/placeholder/style.scss +++ b/packages/components/src/placeholder/style.scss @@ -54,6 +54,11 @@ } } +.components-placeholder__fieldset.is-column-layout, +.components-placeholder__fieldset.is-column-layout form { + flex-direction: column; +} + .components-placeholder__input { margin-right: 8px; flex: 1 1 auto; diff --git a/packages/e2e-tests/specs/blocks/table.test.js b/packages/e2e-tests/specs/blocks/table.test.js index 3a61f5e5eda594..0e3dd0bf5cad42 100644 --- a/packages/e2e-tests/specs/blocks/table.test.js +++ b/packages/e2e-tests/specs/blocks/table.test.js @@ -3,6 +3,8 @@ */ import { createNewPost, insertBlock, getEditedPostContent } from '@wordpress/e2e-test-utils'; +const createButtonSelector = "//div[@data-type='core/table']//button[text()='Create Table']"; + describe( 'Table', () => { beforeEach( async () => { await createNewPost(); @@ -34,7 +36,7 @@ describe( 'Table', () => { await page.keyboard.type( '10' ); // // Create the table. - const createButton = await page.$x( "//div[@data-type='core/table']//button[text()='Create']" ); + const createButton = await page.$x( createButtonSelector ); await createButton[ 0 ].click(); // // Expect the post content to have a correctly sized table. @@ -45,7 +47,7 @@ describe( 'Table', () => { await insertBlock( 'Table' ); // Create the table. - const createButton = await page.$x( "//div[@data-type='core/table']//button[text()='Create']" ); + const createButton = await page.$x( createButtonSelector ); await createButton[ 0 ].click(); // Click the first cell and add some text. @@ -81,7 +83,7 @@ describe( 'Table', () => { expect( footerSwitch ).toHaveLength( 0 ); // Create the table. - const createButton = await page.$x( "//div[@data-type='core/table']//button[text()='Create']" ); + const createButton = await page.$x( createButtonSelector ); await createButton[ 0 ].click(); // Expect the header and footer switches to be present now that the table has been created. From b2c768f302b4b4c4962837c901652ef2f40a93fa Mon Sep 17 00:00:00 2001 From: Mark Uraine Date: Tue, 4 Jun 2019 15:58:42 -0700 Subject: [PATCH 041/132] Fixes #15870. Removes the from the editor.scss file allowing it to break at the word. (#15871) --- packages/block-library/src/media-text/editor.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-library/src/media-text/editor.scss b/packages/block-library/src/media-text/editor.scss index fe6a552526971b..3d0ad0361bd947 100644 --- a/packages/block-library/src/media-text/editor.scss +++ b/packages/block-library/src/media-text/editor.scss @@ -3,7 +3,6 @@ "media-text-media media-text-content" "resizer resizer"; align-items: center; - word-break: break-all; } .wp-block-media-text.has-media-on-the-right { From c2578bd92ee486aec1e0bb5665827fed7fd54eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= Date: Wed, 5 Jun 2019 10:39:41 +0200 Subject: [PATCH 042/132] Scripts: Ignore linting files located in build folders by default (#15977) * Scripts: Ignore linting files located in build folders by default * Add CHANGELOG entry --- packages/scripts/CHANGELOG.md | 6 ++++++ packages/scripts/README.md | 7 +++++++ packages/scripts/config/.eslintignore | 2 ++ packages/scripts/config/.npmpackagejsonlintignore | 3 +++ packages/scripts/config/.stylelintignore | 3 +++ packages/scripts/scripts/lint-js.js | 11 ++++++++++- packages/scripts/scripts/lint-pkg-json.js | 11 ++++++++++- packages/scripts/scripts/lint-style.js | 15 ++++++++++++--- 8 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 packages/scripts/config/.eslintignore create mode 100644 packages/scripts/config/.npmpackagejsonlintignore create mode 100644 packages/scripts/config/.stylelintignore diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 30aed0c902b09b..e7e408e8b0166f 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -1,3 +1,9 @@ +## Master + +### New Features + +- The `lint-js`, `lint-pkg-json` and `lint-style` commands ignore now files located in `build` and `node_modules` folders by default ([15977](https://github.com/WordPress/gutenberg/pull/15977)). + ## 3.2.0 (2019-05-21) ### New Feature diff --git a/packages/scripts/README.md b/packages/scripts/README.md index b21c7078a61d56..0e394ad71f23a2 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -123,6 +123,9 @@ This is how you execute the script with presented setup: * `npm run lint:js` - lints JavaScript files in the entire project's directories. + +By default, files located in `build` and `node_modules` folders are ignored. + #### Advanced information It uses [eslint](https://eslint.org/) with the set of recommended rules defined in [@wordpress/eslint-plugin](https://www.npmjs.com/package/@wordpress/eslint-plugin) npm package. You can override default rules with your own as described in [eslint docs](https://eslint.org/docs/rules/). Learn more in the [Advanced Usage](#advanced-usage) section. @@ -145,6 +148,8 @@ This is how you execute those scripts using the presented setup: * `npm run lint:pkg-json` - lints `package.json` file in the project's root folder. +By default, files located in `build` and `node_modules` folders are ignored. + #### Advanced information It uses [npm-package-json-lint](https://www.npmjs.com/package/npm-package-json-lint) with the set of recommended rules defined in [@wordpress/npm-package-json-lint-config](https://www.npmjs.com/package/@wordpress/npm-package-json-lint-config) npm package. You can override default rules with your own as described in [npm-package-json-lint wiki](https://github.com/tclindner/npm-package-json-lint/wiki). Learn more in the [Advanced Usage](#advanced-usage) section. @@ -167,6 +172,8 @@ This is how you execute the script with presented setup: * `npm run lint:css` - lints CSS files in the whole project's directory. +By default, files located in `build` and `node_modules` folders are ignored. + #### Advanced information It uses [stylelint](https://github.com/stylelint/stylelint) with the [stylelint-config-wordpress](https://github.com/WordPress-Coding-Standards/stylelint-config-wordpress) configuration per the [WordPress CSS Coding Standards](https://make.wordpress.org/core/handbook/best-practices/coding-standards/css/). You can override them with your own rules as described in [stylelint user guide](https://github.com/stylelint/stylelint/docs/user-guide.md). Learn more in the [Advanced Usage](#advanced-usage) section. diff --git a/packages/scripts/config/.eslintignore b/packages/scripts/config/.eslintignore new file mode 100644 index 00000000000000..e3fbd98336eafe --- /dev/null +++ b/packages/scripts/config/.eslintignore @@ -0,0 +1,2 @@ +build +node_modules diff --git a/packages/scripts/config/.npmpackagejsonlintignore b/packages/scripts/config/.npmpackagejsonlintignore new file mode 100644 index 00000000000000..ae6cdbfb623bb1 --- /dev/null +++ b/packages/scripts/config/.npmpackagejsonlintignore @@ -0,0 +1,3 @@ +# By default, all `node_modules` are ignored. + +build diff --git a/packages/scripts/config/.stylelintignore b/packages/scripts/config/.stylelintignore new file mode 100644 index 00000000000000..ae6cdbfb623bb1 --- /dev/null +++ b/packages/scripts/config/.stylelintignore @@ -0,0 +1,3 @@ +# By default, all `node_modules` are ignored. + +build diff --git a/packages/scripts/scripts/lint-js.js b/packages/scripts/scripts/lint-js.js index c7346fb76ad88c..33bcdf83e5f897 100644 --- a/packages/scripts/scripts/lint-js.js +++ b/packages/scripts/scripts/lint-js.js @@ -17,6 +17,7 @@ const { const args = getCliArgs(); +// See: https://eslint.org/docs/user-guide/configuring#using-configuration-files-1. const hasLintConfig = hasCliArg( '-c' ) || hasCliArg( '--config' ) || hasProjectFile( '.eslintrc.js' ) || @@ -33,9 +34,17 @@ const config = ! hasLintConfig ? [ '--no-eslintrc', '--config', fromConfigRoot( '.eslintrc.js' ) ] : []; +// See: https://eslint.org/docs/user-guide/configuring#ignoring-files-and-directories. +const hasIgnoredFiles = hasCliArg( '--ignore-path' ) || + hasProjectFile( '.eslintignore' ); + +const defaultIgnoreArgs = ! hasIgnoredFiles ? + [ '--ignore-path', fromConfigRoot( '.eslintignore' ) ] : + []; + const result = spawn( resolveBin( 'eslint' ), - [ ...config, ...args ], + [ ...config, ...defaultIgnoreArgs, ...args ], { stdio: 'inherit' } ); diff --git a/packages/scripts/scripts/lint-pkg-json.js b/packages/scripts/scripts/lint-pkg-json.js index b37e0a07bc75bf..c3cbd4f429c680 100644 --- a/packages/scripts/scripts/lint-pkg-json.js +++ b/packages/scripts/scripts/lint-pkg-json.js @@ -17,6 +17,7 @@ const { const args = getCliArgs(); +// See: https://github.com/tclindner/npm-package-json-lint/wiki/configuration#configuration. const hasLintConfig = hasCliArg( '-c' ) || hasCliArg( '--configFile' ) || hasProjectFile( '.npmpackagejsonlintrc.json' ) || @@ -27,9 +28,17 @@ const config = ! hasLintConfig ? [ '--configFile', fromConfigRoot( 'npmpackagejsonlint.json' ) ] : []; +// See: https://github.com/tclindner/npm-package-json-lint/#cli-commands-and-configuration. +const hasIgnoredFiles = hasCliArg( '--ignorePath' ) || + hasProjectFile( '.npmpackagejsonlintignore' ); + +const defaultIgnoreArgs = ! hasIgnoredFiles ? + [ '--ignorePath', fromConfigRoot( '.npmpackagejsonlintignore' ) ] : + []; + const result = spawn( resolveBin( 'npm-package-json-lint', { executable: 'npmPkgJsonLint' } ), - [ ...config, ...args ], + [ ...config, ...defaultIgnoreArgs, ...args ], { stdio: 'inherit' } ); diff --git a/packages/scripts/scripts/lint-style.js b/packages/scripts/scripts/lint-style.js index d72a877fa93702..32783a97f4eb2b 100644 --- a/packages/scripts/scripts/lint-style.js +++ b/packages/scripts/scripts/lint-style.js @@ -17,7 +17,8 @@ const { const args = getCliArgs(); -const hasStylelintConfig = hasCliArg( '--config' ) || +// See: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#loading-the-configuration-object. +const hasLintConfig = hasCliArg( '--config' ) || hasProjectFile( '.stylelintrc' ) || hasProjectFile( '.stylelintrc.js' ) || hasProjectFile( '.stylelintrc.json' ) || @@ -26,13 +27,21 @@ const hasStylelintConfig = hasCliArg( '--config' ) || hasProjectFile( '.stylelint.config.js' ) || hasPackageProp( 'stylelint' ); -const config = ! hasStylelintConfig ? +const config = ! hasLintConfig ? [ '--config', fromConfigRoot( '.stylelintrc.json' ) ] : []; +// See: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#stylelintignore. +const hasIgnoredFiles = hasCliArg( '--ignore-path' ) || + hasProjectFile( '.stylelintignore' ); + +const defaultIgnoreArgs = ! hasIgnoredFiles ? + [ '--ignore-path', fromConfigRoot( '.stylelintignore' ) ] : + []; + const result = spawn( resolveBin( 'stylelint' ), - [ ...config, ...args ], + [ ...config, ...defaultIgnoreArgs, ...args ], { stdio: 'inherit' } ); From af5fd92f37b836c8e711c00dc62611c09aad535d Mon Sep 17 00:00:00 2001 From: andrei draganescu Date: Wed, 5 Jun 2019 12:51:20 +0300 Subject: [PATCH 043/132] adds selection persistence on sidebar tab switch (#15583) * adds selection persistence on sidebar tab switch * autogen doc for the new restoreSelectedBlock action * removed useless spread operator and used lodash omit for a more declarative construction * wip: updating the test for better readability * small updates to make the tests pass * fixed the failing session persistence test * adds a destructive way to clear selection * adds destructive selection clearer and clears on visual edititng toggle and manual deselection * autogen docs * removes unused documentation * Docs: Rengenerate after API docs has changed * better docs and unit tests for new actions * updated the selection persistence test for better readability --- .../developers/data/data-core-block-editor.md | 21 +++++++- .../block-selection-clearer/index.js | 8 +-- packages/block-editor/src/store/actions.js | 27 +++++++++- packages/block-editor/src/store/reducer.js | 15 +++++- .../block-editor/src/store/test/actions.js | 18 +++++++ .../block-editor/src/store/test/reducer.js | 1 + packages/e2e-tests/specs/a11y.test.js | 51 +++++++++++++++++++ .../sidebar/settings-header/index.js | 4 +- packages/edit-post/src/store/effects.js | 2 +- 9 files changed, 138 insertions(+), 9 deletions(-) diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md index 6e496446d6be20..f765454e948878 100644 --- a/docs/designers-developers/developers/data/data-core-block-editor.md +++ b/docs/designers-developers/developers/data/data-core-block-editor.md @@ -824,7 +824,9 @@ _Returns_ # **clearSelectedBlock** -Returns an action object used in signalling that the block selection is cleared. +Returns an action object used in signaling that the block selection is cleared. +This will save the current selection in a state called `previousSelection` and +`restoreSelectedBlock` will be able to restore the selection. _Returns_ @@ -1039,6 +1041,14 @@ _Returns_ - `Object`: Action object. +# **restoreSelectedBlock** + +Returns an action object used in restoring the previously cleared selected blocks. + +_Returns_ + +- `Object`: Action object. + # **selectBlock** Returns an action object used in signalling that the block with the @@ -1225,4 +1235,13 @@ _Returns_ Undocumented declaration. +# **wipeSelectedBlock** + +Returns an action object used in signaling that the block selection is wiped. +This will remove block selection so that `restoreSelectedBlock` will have no effect. + +_Returns_ + +- `Object`: Action object. + diff --git a/packages/block-editor/src/components/block-selection-clearer/index.js b/packages/block-editor/src/components/block-selection-clearer/index.js index be39e5df9e7de5..cc2e27944e06bd 100644 --- a/packages/block-editor/src/components/block-selection-clearer/index.js +++ b/packages/block-editor/src/components/block-selection-clearer/index.js @@ -33,12 +33,12 @@ class BlockSelectionClearer extends Component { const { hasSelectedBlock, hasMultiSelection, - clearSelectedBlock, + wipeSelectedBlock, } = this.props; const hasSelection = ( hasSelectedBlock || hasMultiSelection ); if ( event.target === this.container && hasSelection ) { - clearSelectedBlock(); + wipeSelectedBlock(); } } @@ -68,7 +68,7 @@ export default compose( [ }; } ), withDispatch( ( dispatch ) => { - const { clearSelectedBlock } = dispatch( 'core/block-editor' ); - return { clearSelectedBlock }; + const { wipeSelectedBlock } = dispatch( 'core/block-editor' ); + return { wipeSelectedBlock }; } ), ] )( BlockSelectionClearer ); diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index 4dafaa291fcf31..e1e4c1f69ed040 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -193,7 +193,21 @@ export function multiSelect( start, end ) { } /** - * Returns an action object used in signalling that the block selection is cleared. + * Returns an action object used in signaling that the block selection is wiped. + * This will remove block selection so that `restoreSelectedBlock` will have no effect. + * + * @return {Object} Action object. + */ +export function wipeSelectedBlock() { + return { + type: 'WIPE_SELECTED_BLOCK', + }; +} + +/** + * Returns an action object used in signaling that the block selection is cleared. + * This will save the current selection in a state called `previousSelection` and + * `restoreSelectedBlock` will be able to restore the selection. * * @return {Object} Action object. */ @@ -203,6 +217,17 @@ export function clearSelectedBlock() { }; } +/** + * Returns an action object used in restoring the previously cleared selected blocks. + * + * @return {Object} Action object. + */ +export function restoreSelectedBlock() { + return { + type: 'RESTORE_SELECTED_BLOCK', + }; +} + /** * Returns an action object that enables or disables block selection. * diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index d9d0ecbdd28b64..e62734d0412e2c 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -717,8 +717,21 @@ const BLOCK_SELECTION_INITIAL_STATE = { */ export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) { switch ( action.type ) { - case 'CLEAR_SELECTED_BLOCK': + case 'WIPE_SELECTED_BLOCK': return BLOCK_SELECTION_INITIAL_STATE; + case 'CLEAR_SELECTED_BLOCK': + if ( isEqual( state, BLOCK_SELECTION_INITIAL_STATE ) ) { + return BLOCK_SELECTION_INITIAL_STATE; + } + return { + ...BLOCK_SELECTION_INITIAL_STATE, + previousSelection: omit( state, [ 'previousSelection' ] ), + }; + case 'RESTORE_SELECTED_BLOCK': + return { + ...BLOCK_SELECTION_INITIAL_STATE, + ...state.previousSelection, + }; case 'START_MULTI_SELECT': if ( state.isMultiSelecting ) { return state; diff --git a/packages/block-editor/src/store/test/actions.js b/packages/block-editor/src/store/test/actions.js index 1fb97cd38d9bde..93123c17bf987b 100644 --- a/packages/block-editor/src/store/test/actions.js +++ b/packages/block-editor/src/store/test/actions.js @@ -3,6 +3,8 @@ */ import { clearSelectedBlock, + wipeSelectedBlock, + restoreSelectedBlock, enterFormattedText, exitFormattedText, hideInsertionPoint, @@ -116,6 +118,22 @@ describe( 'actions', () => { } ); } ); + describe( 'wipeSelectedBlock', () => { + it( 'should return WIPE_SELECTED_BLOCK action', () => { + expect( wipeSelectedBlock() ).toEqual( { + type: 'WIPE_SELECTED_BLOCK', + } ); + } ); + } ); + + describe( 'restoreSelectedBlock', () => { + it( 'should return RESTORE_SELECTED_BLOCK action', () => { + expect( restoreSelectedBlock() ).toEqual( { + type: 'RESTORE_SELECTED_BLOCK', + } ); + } ); + } ); + describe( 'replaceBlock', () => { it( 'should yield the REPLACE_BLOCKS action if the new block can be inserted in the destination root block', () => { const block = { diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index 7543fdad57dd8b..b0d79d8911292e 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -1740,6 +1740,7 @@ describe( 'state', () => { initialPosition: null, isMultiSelecting: false, isEnabled: true, + previousSelection: original, } ); } ); diff --git a/packages/e2e-tests/specs/a11y.test.js b/packages/e2e-tests/specs/a11y.test.js index 6f6cc960f204aa..784ee4dc556743 100644 --- a/packages/e2e-tests/specs/a11y.test.js +++ b/packages/e2e-tests/specs/a11y.test.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { + clickBlockAppender, createNewPost, pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; @@ -29,6 +30,56 @@ describe( 'a11y', () => { expect( isFocusedToggle ).toBe( true ); } ); + it( 'checks persistent selection', async () => { + await clickBlockAppender(); + + // adding one Paragraph block which contains a focusable RichText + await page.keyboard.type( 'Testing editor selection persistence' ); + + let isFocusedRichText = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); + } ); + + expect( isFocusedRichText ).toBe( true ); + + // moving focus backwards using keyboard shortcuts + // twice to get to the inspector tabs + await pressKeyWithModifier( 'ctrlShift', '`' ); + await pressKeyWithModifier( 'ctrlShift', '`' ); + + await page.keyboard.press( 'Tab' ); + + const isFocusedInspectorDocumentTab = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.getAttribute( 'data-label' ); + } ); + + expect( isFocusedInspectorDocumentTab ).toEqual( 'Document' ); + + await page.keyboard.press( 'Space' ); + + isFocusedRichText = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); + } ); + + expect( isFocusedRichText ).toBe( false ); + + await page.keyboard.press( 'Tab' ); + + const isFocusedInspectorBlockTab = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.getAttribute( 'data-label' ); + } ); + + expect( isFocusedInspectorBlockTab ).toEqual( 'Block' ); + + await page.keyboard.press( 'Space' ); + + isFocusedRichText = await page.$eval( ':focus', ( focusedElement ) => { + return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); + } ); + + expect( isFocusedRichText ).toBe( true ); + } ); + it( 'constrains focus to a modal when tabbing', async () => { // Open keyboard help modal. await pressKeyWithModifier( 'access', 'h' ); diff --git a/packages/edit-post/src/components/sidebar/settings-header/index.js b/packages/edit-post/src/components/sidebar/settings-header/index.js index eeb95a872166f5..47d00bce72048a 100644 --- a/packages/edit-post/src/components/sidebar/settings-header/index.js +++ b/packages/edit-post/src/components/sidebar/settings-header/index.js @@ -57,7 +57,8 @@ const SettingsHeader = ( { openDocumentSettings, openBlockSettings, sidebarName export default withDispatch( ( dispatch ) => { const { openGeneralSidebar } = dispatch( 'core/edit-post' ); - const { clearSelectedBlock } = dispatch( 'core/block-editor' ); + const { clearSelectedBlock, restoreSelectedBlock } = dispatch( 'core/block-editor' ); + return { openDocumentSettings() { openGeneralSidebar( 'edit-post/document' ); @@ -65,6 +66,7 @@ export default withDispatch( ( dispatch ) => { }, openBlockSettings() { openGeneralSidebar( 'edit-post/block' ); + restoreSelectedBlock(); }, }; } )( SettingsHeader ); diff --git a/packages/edit-post/src/store/effects.js b/packages/edit-post/src/store/effects.js index 54bfe07fbd67b5..36d3c2b501369c 100644 --- a/packages/edit-post/src/store/effects.js +++ b/packages/edit-post/src/store/effects.js @@ -109,7 +109,7 @@ const effects = { SWITCH_MODE( action ) { // Unselect blocks when we switch to the code editor. if ( action.mode !== 'visual' ) { - dispatch( 'core/block-editor' ).clearSelectedBlock(); + dispatch( 'core/block-editor' ).wipeSelectedBlock(); } const message = action.mode === 'visual' ? __( 'Visual editor selected' ) : __( 'Code editor selected' ); From ba6a8afe61bc63494000080bbc2a1220debe39cc Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Wed, 5 Jun 2019 11:51:02 +0100 Subject: [PATCH 044/132] Enables Block Grouping/UnGrouping using core/group (#14908) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Experiment with rudity mentory mechanic to allow Block Grouping Tried a few approaches via `insertBlock/removeBlocks` and even `replaceBlocks` but nothing preserved the undo history apart from this rather brute force method. * Migrate to `core/group` due to renaming of container Block from `core/section` * Adds conditionals to hide Group btn if selection is only a single `core/group` Block * Adds transform and updates Group button implementation to mirror Adds a `from` transform to the `core/group` Block. Currently this only works for `core/paragraph` but will need to work for all Block types. Updates the convert button to utilise `switchToBlockType` which invokes the same functionality as used in Block transform thereby unifiying the two methods of grouping. * Adds and applies Group icon As provided here https://github.com/WordPress/gutenberg/pull/14908#issuecomment-482196334 * Adds editor shortcut for Grouping Blocks * Add test to check for blocks before attempting replace * Adds wildcard Block transforms A major update to the transforms logic to enable wildcard Block transforms. * Pass Block names into transform callback function - enables dynamic Block creation in wildcard transforms (see `core/group`) * Add edge cases to Block transformation logic to account for specifying `*` (all) Block types as valid for a transformation * Remove unwanted test that checks all Blocks are of the same type before allowing a transform on a Multi Block selection * Reinstate missing createBlock dep after rebase * Fix to avoid allowing single Group Block to be Grouped * Update to use more appropriate logical negation operator for comparison Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r279828282 * Extracts key transform test logic into dedicated methods Previously hard coded values and difficult to follow logic were making the `switchToBlockType` overly complex. Extracted to well name methods to improve readability and allow to further refactoring. * Extract method to test for wildcard block transforms DRYs up code by extracting a function to test for the presence of a wildcard block transform * Moves logic to allow for wildcard transform into central transform checking method Previously test to allow wildcard transform to be valid were manually added as edge cases in conditions in predicate functions. This update centralises all logic to test whether a given transform is possible but including the logic that allows wildcard transforms within the main method `isPossibleTransformForSource` which determines whether a given transform is possible. * Adds UnGrouping mechanic * Adds UnGroup Icon * Adds e2e test to cover basic grouping for single and multiple blocks * Fix edge case with test to detect a single group container Block * Adds UnGroup keyboard shortcut * Adds more e2e test coverage Includes testing grouping via transforms, options menu and keyboard shortcuts * Adds check for group block availability before displaying grouping UI Also adds e2e tests to cover this. * Updates misnamned components Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r280851925 * Updates to preserve widest width alignment of child block on group container Previously if one of the child blocks being grouped had a width alignment (eg: wide or full) then the group block did not respect this. This meant that layouts weren’t preserved when grouping. Adds functionality and tests to ensure that when a group is created the widest alignment setting of the child blocks is set on the group block. * Updates to DRY out tests * Updates to simplify test setup Previously API calls were cleaning up blocks. This can be removed because all posts are auto removed before each test is run. Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281445117 * Updates to simplify test assertion Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281452179 * Combines test cases to simplify and reduce number of test required Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281450978 * Updates to combine test for grouping and ungrouping via options menu Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r281450690 * Adds keyboard shortcut to global keyboard shortcuts modal * Ensure correct case for group shortcut (ie: lower) * Add shortcut to Block settings menu dropdown items * Adds translation context to Group actions in menus Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r283683456 * Update Block Transforms fixtures to show all Blocks can transform to Group Block * Updates Keyboard Shortcut test snapshot to include Group/UnGroup * Fix to ensure Group block accounted for * Fix Block deletion test failure via keyboard workaround Due to the addition of the “Group” item into the Block Options toolbar the “Remove Block” item had been removed outside the viewable portion of the Popover (not the popover has a restricted height and allows scrolling to see the additional items if there is insufficient space to display them all). Pupeteer isn’t able to click on items that are not visible. The simplest work around is to us the keyboard to select the “Remove Block” menu item rather. Trying to scroll a div within Pupeteer is fraught with problems and inconsistencies. * Fixes Remove Block button helper to be more resilient to change Previously we relied on the number of tab stops to locate the correct button in the menu. This change uses the actual text of the button to identify it and uses an assertion to ensure that the correct button is explicitly required. * Rename function to better convey intent Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r286106077 * Fixes to catch transforms which are invalid for blocks of different types A check was accidentally removed in `b2af0f2611e2a2bc66c62959dbf483abcbe103a9` which allowed multiple blocks of different types to be considered valid even if they were not. Adds conditional to ensure that unless the transform is a wildcard then we test that all the blocks are of the same type as the first block’s type before considering the transform to be valid. * Removes redundant snapshots * Fixes Transforms test to not over-test Group transforms Previously we tested every block transforming into the Group Block. This was unwanted overhead. Fixed to only test 1 single Block transforming into Group. Removed redundant snapshots as a result of removing it. * Fixes e2e test by reinstating helper lost during rebase * Fix to make Group transform snapshot tests more resilient to change Now explicity selects paragraph and image blocks to test the Group transform rather than simply testing the first block that transform into a Group. This ensures that if the order of transforms changes in the fixtures the test won’t be accidentally invalidated. Resolves: https://github.com/WordPress/gutenberg/pull/14908/#discussion_r287315363 * Updates to DRY out test and reduce test redundancy and performance Through use of smarter filtering we can get away with a single `it.each()` block which improves perf and removes redundant tests. Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287342432 * Adds unit tests to cover new conditionals added for wildcard blocks transforms * Fixes capitalisation of UnGroup to Ungroup Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r287415190 * Updates doc block to reflect possible nullable return type Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287416745 * Updates Readme with doc update * Updates to remove unwanted comments * Updates capitalisatoin of “wildcard” Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287435420 * Update comment with more context for future maintainers Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r287436023 * Updates to remove unwanted level of context on the translation Co-Authored-By: Andrew Duthie * Adds tests to cover isWildcardBlockTransform * Adds tests for isContainerGroupBlock function Note these test will need updating when we land https://github.com/WordPress/gutenberg/pull/15774 * Fixes logic around multi blocks of same type and adds tests Prevously we had 1 function attempting to test for multiple block selection and checking that the selection was all of the same block type. This caused bugs within `switchToBlockType` because the logic was confusing. For example, if a selection isn’t a multi block then we don’t need to test that all the blocks are the same. Separated the two functions and updated conditions in switchToBlockType to reflect this. Added unit tests to cover two new functions. * Adds new generator based API signature to Block transforms Previously the transforms function was pased two arguments 1. attributes 2. innerblocks This wasn’t extensible and more advanced transformations require more information about the block (eg: name). To avoid bloating the signature, a progressive enhancement approach is applied whereby if a generator function is passed as the transform then we pass the entire block object to the generator. This is opt-in only and is backwards compatible with all existing transform functions. * Adds new apply option method to transform API Previously we were modifying the existing transform function to conform to the requirements of a new API (ie: receiving the entire block object rather than the individual arguments). It was decided that introducing a new `apply` option and soft deprecating the old transform option would be preferable. The apply option if provided now takes precedence over the transform option. This is fully backwards compatible. See https://wordpress.slack.com/archives/C02QB2JS7/p1559567845087000 * Updates Block Reg docs to cover wildcard transforms * Updates changelog to document wildcards and transform apply option * Fix linting error introduce in rebase * Fixes test util to avoid infinite loops Previously if the button wasn’t found then the loop would continue forever looking for the button. This would have caused timeouts. Limits the loop to the number of buttons in the document. Also bails out immediately having found the button. Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r290022464 * Renames apply to convert to avoid confusion with Func.apply To avoid potential confusion and overlap with Function.apply, rename to `convert`. Slack discussion: https://wordpress.slack.com/archives/C02QB2JS7/p1559593099150300?thread_ts=1559571243.134500&cid=C02QB2JS7 MDN Function apply docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply Resolves: https://github.com/WordPress/gutenberg/pull/14908#discussion_r290021073 * Fixes unecessary additional var introduced during debugging * Fix convert API to match established patterns for consistency Previously `convert` always passed an array of block objects even if there was only a single block. This is inconsistent with the implementation of the existing `transform` method which passes only a block’s attributes/innerBlocks pair when it is not a multi block. To retain consistency with the existing `isMultiBlock` paradiagm this updates the API of `convert` to pass a single block object when not in multiblock mode. * Fixes error in docs Co-Authored-By: Andrew Duthie * Fixes doc blocks to match coding style Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r290024877 * Fixes icon size and color in dropdown for Group/Ungroup * Updates to remove keyboard shortcuts Following a discussion it was not possible to achieve a consensus on which shortcuts was most suitable (or indeed whether keyboard shortcuts for this were even a good idea). As a result this has been descoped from this PR and will be addressed elsewhere. Once merged I will push a new placeholder PR with the foundation for shortcuts in place and others can then amend it. * Updates snapshot to account for removing keyboard shortcuts * Removes e2e tests covering keyboard shortcuts * Fixes unwanted check introduced during debugging Test for existence of transform is not required and was introduced during debugging. Can be removed. * Updates to collapse spaces in doc blocks Co-Authored-By: Andrew Duthie * Fixes isWildcardBlockTransform to test for Array-ness Resolves https://github.com/WordPress/gutenberg/pull/14908#discussion_r290459410 * Fixes incorrect capitalisation of “UnGroup” to “Ungroup” Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r290461528 * Updates to remove redundant isMultiBlockSelection util function Addresses https://github.com/WordPress/gutenberg/pull/14908#discussion_r290463266 * Reinstate missing Ungroup icon Accidentally got lost during renaming of “UnGroup” to “Ungroup”! --- .../block-api/block-registration.md | 34 +++ .../src/components/block-actions/index.js | 40 ++- packages/block-library/src/group/index.js | 40 +++ packages/blocks/CHANGELOG.md | 2 + packages/blocks/README.md | 2 +- packages/blocks/src/api/factory.js | 104 +++++-- packages/blocks/src/api/test/factory.js | 271 +++++++++++++++++- .../e2e-tests/fixtures/block-transforms.js | 138 +++++++-- .../__snapshots__/block-grouping.test.js.snap | 99 +++++++ .../block-transforms.test.js.snap | 16 ++ .../e2e-tests/specs/block-deletion.test.js | 39 ++- .../e2e-tests/specs/block-grouping.test.js | 176 ++++++++++++ .../e2e-tests/specs/block-switcher.test.js | 3 + .../e2e-tests/specs/block-transforms.test.js | 7 +- .../convert-button.js | 127 ++++++++ .../convert-to-group-buttons/icons.js | 19 ++ .../convert-to-group-buttons/index.js | 33 +++ .../editor/src/components/provider/index.js | 2 + 18 files changed, 1097 insertions(+), 55 deletions(-) create mode 100644 packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap create mode 100644 packages/e2e-tests/specs/block-grouping.test.js create mode 100644 packages/editor/src/components/convert-to-group-buttons/convert-button.js create mode 100644 packages/editor/src/components/convert-to-group-buttons/icons.js create mode 100644 packages/editor/src/components/convert-to-group-buttons/index.js diff --git a/docs/designers-developers/developers/block-api/block-registration.md b/docs/designers-developers/developers/block-api/block-registration.md index 8a2d6c26a7dabf..7986be28bee4bc 100644 --- a/docs/designers-developers/developers/block-api/block-registration.md +++ b/docs/designers-developers/developers/block-api/block-registration.md @@ -311,6 +311,40 @@ transforms: { ``` {% end %} +In addition to accepting an array of known block types, the `blocks` option also accepts a "wildcard" (`"*"`). This allows for transformations which apply to _all_ block types (eg: all blocks can transform into `core/group`): + +{% codetabs %} +{% ES5 %} +```js +transforms: { + from: [ + { + type: 'block', + blocks: [ '*' ], // wildcard - match any block + transform: function( attributes, innerBlocks ) { + // transform logic here + }, + }, + ], +}, +``` +{% ESNext %} +```js +transforms: { + from: [ + { + type: 'block', + blocks: [ '*' ], // wildcard - match any block + transform: ( attributes, innerBlocks ) => { + // transform logic here + }, + }, + ], +}, +``` +{% end %} + + A block with innerBlocks can also be transformed from and to another block with innerBlocks. {% codetabs %} diff --git a/packages/block-editor/src/components/block-actions/index.js b/packages/block-editor/src/components/block-actions/index.js index 3b3f8032432e8b..c10d03a5c060f0 100644 --- a/packages/block-editor/src/components/block-actions/index.js +++ b/packages/block-editor/src/components/block-actions/index.js @@ -8,13 +8,15 @@ import { castArray, first, last, every } from 'lodash'; */ import { compose } from '@wordpress/compose'; import { withSelect, withDispatch } from '@wordpress/data'; -import { cloneBlock, hasBlockSupport } from '@wordpress/blocks'; +import { cloneBlock, hasBlockSupport, switchToBlockType } from '@wordpress/blocks'; function BlockActions( { onDuplicate, onRemove, onInsertBefore, onInsertAfter, + onGroup, + onUngroup, isLocked, canDuplicate, children, @@ -24,6 +26,8 @@ function BlockActions( { onRemove, onInsertAfter, onInsertBefore, + onGroup, + onUngroup, isLocked, canDuplicate, } ); @@ -65,6 +69,7 @@ export default compose( [ multiSelect, removeBlocks, insertDefaultBlock, + replaceBlocks, } = dispatch( 'core/block-editor' ); return { @@ -107,6 +112,39 @@ export default compose( [ insertDefaultBlock( {}, rootClientId, lastSelectedIndex + 1 ); } }, + onGroup() { + if ( ! blocks.length ) { + return; + } + + // Activate the `transform` on `core/group` which does the conversion + const newBlocks = switchToBlockType( blocks, 'core/group' ); + + if ( ! newBlocks ) { + return; + } + replaceBlocks( + clientIds, + newBlocks + ); + }, + + onUngroup() { + if ( ! blocks.length ) { + return; + } + + const innerBlocks = blocks[ 0 ].innerBlocks; + + if ( ! innerBlocks.length ) { + return; + } + + replaceBlocks( + clientIds, + innerBlocks + ); + }, }; } ), ] )( BlockActions ); diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 9bab779f5863b5..386ab20a80955c 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies @@ -25,6 +26,45 @@ export const settings = { anchor: true, html: false, }, + + transforms: { + from: [ + { + type: 'block', + isMultiBlock: true, + blocks: [ '*' ], + convert( blocks ) { + // Avoid transforming a single `core/group` Block + if ( blocks.length === 1 && blocks[ 0 ].name === 'core/group' ) { + return; + } + + const alignments = [ 'wide', 'full' ]; + + // Determine the widest setting of all the blocks to be grouped + const widestAlignment = blocks.reduce( ( result, block ) => { + const { align } = block.attributes; + return alignments.indexOf( align ) > alignments.indexOf( result ) ? align : result; + }, undefined ); + + // Clone the Blocks to be Grouped + // Failing to create new block references causes the original blocks + // to be replaced in the switchToBlockType call thereby meaning they + // are removed both from their original location and within the + // new group block. + const groupInnerBlocks = blocks.map( ( block ) => { + return createBlock( block.name, block.attributes, block.innerBlocks ); + } ); + + return createBlock( 'core/group', { + align: widestAlignment, + }, groupInnerBlocks ); + }, + }, + + ], + }, + edit, save, }; diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index b13c58601e1e99..df5b183e688d45 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -3,6 +3,8 @@ ### New Feature - Added a default implementation for `save` setting in `registerBlockType` which saves no markup in the post content. +- Added wildcard block transforms which allows for transforming all/any blocks in another block. +- Added `convert()` method option to `transforms` definition. It receives complete block object(s) as it's argument(s). It is now preferred over the older `transform()` (note that `transform()` is still fully supported). ## 6.1.0 (2019-03-06) diff --git a/packages/blocks/README.md b/packages/blocks/README.md index 9bc199a54452f2..b7a8e5fd70c9dd 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -679,7 +679,7 @@ _Parameters_ _Returns_ -- `Array`: Array of blocks. +- `?Array`: Array of blocks or null. # **synchronizeBlocksWithTemplate** diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index c7bd01f2c699c4..304329d0be657f 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -11,6 +11,7 @@ import { filter, first, flatMap, + has, uniq, isFunction, isEmpty, @@ -117,26 +118,41 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { return false; } - // If multiple blocks are selected, only multi block transforms are allowed. + // If multiple blocks are selected, only multi block transforms + // or wildcard transforms are allowed. const isMultiBlock = blocks.length > 1; - const isValidForMultiBlocks = ! isMultiBlock || transform.isMultiBlock; + const firstBlockName = first( blocks ).name; + const isValidForMultiBlocks = isWildcardBlockTransform( transform ) || ! isMultiBlock || transform.isMultiBlock; if ( ! isValidForMultiBlocks ) { return false; } + // Check non-wildcard transforms to ensure that transform is valid + // for a block selection of multiple blocks of different types + if ( ! isWildcardBlockTransform( transform ) && ! every( blocks, { name: firstBlockName } ) ) { + return false; + } + // Only consider 'block' type transforms as valid. const isBlockType = transform.type === 'block'; if ( ! isBlockType ) { return false; } - // Check if the transform's block name matches the source block only if this is a transform 'from'. + // Check if the transform's block name matches the source block (or is a wildcard) + // only if this is a transform 'from'. const sourceBlock = first( blocks ); - const hasMatchingName = direction !== 'from' || transform.blocks.indexOf( sourceBlock.name ) !== -1; + const hasMatchingName = direction !== 'from' || transform.blocks.indexOf( sourceBlock.name ) !== -1 || isWildcardBlockTransform( transform ); if ( ! hasMatchingName ) { return false; } + // Don't allow single 'core/group' blocks to be transformed into + // a 'core/group' block. + if ( ! isMultiBlock && isContainerGroupBlock( sourceBlock.name ) && isContainerGroupBlock( transform.blockName ) ) { + return false; + } + // If the transform has a `isMatch` function specified, check that it returns true. if ( isFunction( transform.isMatch ) ) { const attributes = transform.isMultiBlock ? blocks.map( ( block ) => block.attributes ) : sourceBlock.attributes; @@ -171,7 +187,9 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => { return !! findTransform( fromTransforms, - ( transform ) => isPossibleTransformForSource( transform, 'from', blocks ) + ( transform ) => { + return isPossibleTransformForSource( transform, 'from', blocks ); + } ); }, ); @@ -199,7 +217,9 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { // filter all 'to' transforms to find those that are possible. const possibleTransforms = filter( transformsTo, - ( transform ) => isPossibleTransformForSource( transform, 'to', blocks ) + ( transform ) => { + return transform && isPossibleTransformForSource( transform, 'to', blocks ); + } ); // Build a list of block names using the possible 'to' transforms. @@ -212,6 +232,45 @@ const getBlockTypesForPossibleToTransforms = ( blocks ) => { return blockNames.map( ( name ) => getBlockType( name ) ); }; +/** + * Determines whether transform is a "block" type + * and if so whether it is a "wildcard" transform + * ie: targets "any" block type + * + * @param {Object} t the Block transform object + * + * @return {boolean} whether transform is a wildcard transform + */ +export const isWildcardBlockTransform = ( t ) => t && t.type === 'block' && Array.isArray( t.blocks ) && t.blocks.includes( '*' ); + +/** + * Determines whether the given Block is the core Block which + * acts as a container Block for other Blocks as part of the + * Grouping mechanics + * + * @param {string} name the name of the Block to test against + * + * @return {boolean} whether or not the Block is the container Block type + */ +export const isContainerGroupBlock = ( name ) => name === 'core/group'; + +/** + * Determines whether the provided Blocks are of the same type + * (eg: all `core/paragraph`). + * + * @param {Array} blocksArray the Block definitions + * + * @return {boolean} whether or not the given Blocks pass the criteria + */ +export const isBlockSelectionOfSameType = ( blocksArray = [] ) => { + if ( ! blocksArray.length ) { + return false; + } + const sourceName = blocksArray[ 0 ].name; + + return every( blocksArray, [ 'name', sourceName ] ); +}; + /** * Returns an array of block types that the set of blocks received as argument * can be transformed into. @@ -225,12 +284,6 @@ export function getPossibleBlockTransformations( blocks ) { return []; } - const sourceBlock = first( blocks ); - const isMultiBlock = blocks.length > 1; - if ( isMultiBlock && ! every( blocks, { name: sourceBlock.name } ) ) { - return []; - } - const blockTypesForFromTransforms = getBlockTypesForPossibleFromTransforms( blocks ); const blockTypesForToTransforms = getBlockTypesForPossibleToTransforms( blocks ); @@ -313,7 +366,7 @@ export function getBlockTransforms( direction, blockTypeOrName ) { * @param {Array|Object} blocks Blocks array or block object. * @param {string} name Block name. * - * @return {Array} Array of blocks. + * @return {?Array} Array of blocks or null. */ export function switchToBlockType( blocks, name ) { const blocksArray = castArray( blocks ); @@ -321,7 +374,10 @@ export function switchToBlockType( blocks, name ) { const firstBlock = blocksArray[ 0 ]; const sourceName = firstBlock.name; - if ( isMultiBlock && ! every( blocksArray, ( block ) => ( block.name === sourceName ) ) ) { + // Unless it's a `core/group` Block then for multi block selections + // check that all Blocks are of the same type otherwise + // we can't run a conversion + if ( ! isContainerGroupBlock( name ) && isMultiBlock && ! isBlockSelectionOfSameType( blocksArray ) ) { return null; } @@ -329,14 +385,15 @@ export function switchToBlockType( blocks, name ) { // transformation. const transformationsFrom = getBlockTransforms( 'from', name ); const transformationsTo = getBlockTransforms( 'to', sourceName ); + const transformation = findTransform( transformationsTo, - ( t ) => t.type === 'block' && t.blocks.indexOf( name ) !== -1 && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( isWildcardBlockTransform( t ) ) || t.blocks.indexOf( name ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ) || findTransform( transformationsFrom, - ( t ) => t.type === 'block' && t.blocks.indexOf( sourceName ) !== -1 && ( ! isMultiBlock || t.isMultiBlock ) + ( t ) => t.type === 'block' && ( ( isWildcardBlockTransform( t ) ) || t.blocks.indexOf( sourceName ) !== -1 ) && ( ! isMultiBlock || t.isMultiBlock ) ); // Stop if there is no valid transformation. @@ -345,11 +402,18 @@ export function switchToBlockType( blocks, name ) { } let transformationResults; + if ( transformation.isMultiBlock ) { - transformationResults = transformation.transform( - blocksArray.map( ( currentBlock ) => currentBlock.attributes ), - blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ) - ); + if ( has( transformation, 'convert' ) ) { + transformationResults = transformation.convert( blocksArray ); + } else { + transformationResults = transformation.transform( + blocksArray.map( ( currentBlock ) => currentBlock.attributes ), + blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), + ); + } + } else if ( has( transformation, 'convert' ) ) { + transformationResults = transformation.convert( firstBlock ); } else { transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 11249b08d36ced..3e0d42c103bb9a 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -2,7 +2,7 @@ * External dependencies */ import deepFreeze from 'deep-freeze'; -import { noop } from 'lodash'; +import { noop, times } from 'lodash'; /** * Internal dependencies @@ -14,6 +14,9 @@ import { switchToBlockType, getBlockTransforms, findTransform, + isWildcardBlockTransform, + isContainerGroupBlock, + isBlockSelectionOfSameType, } from '../factory'; import { getBlockType, @@ -776,6 +779,81 @@ describe( 'block factory', () => { expect( isMatch ).toHaveBeenCalledWith( [ { value: 'ribs' }, { value: 'halloumi' } ] ); } ); + + describe( 'wildcard block transforms', () => { + beforeEach( () => { + registerBlockType( 'core/group', { + attributes: { + value: { + type: 'string', + }, + }, + transforms: { + from: [ { + type: 'block', + blocks: [ '*' ], + transform: noop, + } ], + }, + save: noop, + category: 'common', + title: 'A block that groups other blocks.', + } ); + } ); + + it( 'should should show wildcard "from" transformation as available for multiple blocks of the same type', () => { + registerBlockType( 'core/text-block', defaultBlockSettings ); + registerBlockType( 'core/image-block', defaultBlockSettings ); + + const textBlocks = times( 4, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const availableBlocks = getPossibleBlockTransformations( textBlocks ); + + expect( availableBlocks ).toHaveLength( 1 ); + expect( availableBlocks[ 0 ].name ).toBe( 'core/group' ); + } ); + + it( 'should should show wildcard "from" transformation as available for multiple blocks of different types', () => { + registerBlockType( 'core/text-block', defaultBlockSettings ); + registerBlockType( 'core/image-block', defaultBlockSettings ); + + const textBlocks = times( 2, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const imageBlocks = times( 2, ( index ) => { + return createBlock( 'core/image-block', { + value: `imageBlock${ index + 1 }`, + } ); + } ); + + const availableBlocks = getPossibleBlockTransformations( [ ...textBlocks, ...imageBlocks ] ); + + expect( availableBlocks ).toHaveLength( 1 ); + expect( availableBlocks[ 0 ].name ).toBe( 'core/group' ); + } ); + + it( 'should should show wildcard "from" transformation as available for single blocks', () => { + registerBlockType( 'core/text-block', defaultBlockSettings ); + + const blocks = times( 1, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const availableBlocks = getPossibleBlockTransformations( blocks ); + + expect( availableBlocks ).toHaveLength( 1 ); + expect( availableBlocks[ 0 ].name ).toBe( 'core/group' ); + } ); + } ); } ); describe( 'switchToBlockType()', () => { @@ -1222,6 +1300,94 @@ describe( 'block factory', () => { expect( transformedBlocks[ 1 ].innerBlocks ).toHaveLength( 1 ); expect( transformedBlocks[ 1 ].innerBlocks[ 0 ].attributes.value ).toBe( 'after1' ); } ); + + it( 'should pass entire block object(s) to the "convert" method if defined', () => { + registerBlockType( 'core/test-group-block', { + attributes: { + value: { + type: 'string', + }, + }, + transforms: { + from: [ { + type: 'block', + blocks: [ '*' ], + isMultiBlock: true, + convert( blocks ) { + const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { + return createBlock( name, attributes, innerBlocks ); + } ); + + return createBlock( 'core/test-group-block', {}, groupInnerBlocks ); + }, + } ], + }, + save: noop, + category: 'common', + title: 'Test Group Block', + } ); + + registerBlockType( 'core/text-block', defaultBlockSettings ); + + const numOfBlocksToGroup = 4; + const blocks = times( numOfBlocksToGroup, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const transformedBlocks = switchToBlockType( blocks, 'core/test-group-block' ); + + expect( transformedBlocks ).toHaveLength( 1 ); + expect( transformedBlocks[ 0 ].name ).toBe( 'core/test-group-block' ); + expect( transformedBlocks[ 0 ].innerBlocks ).toHaveLength( numOfBlocksToGroup ); + } ); + + it( 'should prefer "convert" method over "transform" method when running a transformation', () => { + const convertSpy = jest.fn( ( blocks ) => { + const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { + return createBlock( name, attributes, innerBlocks ); + } ); + + return createBlock( 'core/test-group-block', {}, groupInnerBlocks ); + } ); + const transformSpy = jest.fn(); + + registerBlockType( 'core/test-group-block', { + attributes: { + value: { + type: 'string', + }, + }, + transforms: { + from: [ { + type: 'block', + blocks: [ '*' ], + isMultiBlock: true, + convert: convertSpy, + transform: transformSpy, + } ], + }, + save: noop, + category: 'common', + title: 'Test Group Block', + } ); + + registerBlockType( 'core/text-block', defaultBlockSettings ); + + const numOfBlocksToGroup = 4; + const blocks = times( numOfBlocksToGroup, ( index ) => { + return createBlock( 'core/text-block', { + value: `textBlock${ index + 1 }`, + } ); + } ); + + const transformedBlocks = switchToBlockType( blocks, 'core/test-group-block' ); + + expect( transformedBlocks ).toHaveLength( 1 ); + expect( convertSpy.mock.calls ).toHaveLength( 1 ); + expect( transformSpy.mock.calls ).toHaveLength( 0 ); + } ); } ); describe( 'getBlockTransforms', () => { @@ -1336,4 +1502,107 @@ describe( 'block factory', () => { expect( transform ).toBe( null ); } ); } ); + + describe( 'isWildcardBlockTransform', () => { + it( 'should return true for transforms with type of block and "*" alias as blocks', () => { + const validWildcardBlockTransform = { + type: 'block', + blocks: [ + 'core/some-other-block-first', // unlikely to happen but... + '*', + ], + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( validWildcardBlockTransform ) ).toBe( true ); + } ); + + it( 'should return false for transforms with a type which is not "block"', () => { + const invalidWildcardBlockTransform = { + type: 'file', + blocks: [ + '*', + ], + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); + } ); + + it( 'should return false for transforms which do not include "*" alias in "block" array', () => { + const invalidWildcardBlockTransform = { + type: 'block', + blocks: [ + 'core/some-block', + 'core/another-block', + ], + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); + } ); + + it( 'should return false for transforms which do not provide an array as the "blocks" option', () => { + const invalidWildcardBlockTransform = { + type: 'block', + blocks: noop, + blockName: 'core/test-block', + }; + + expect( isWildcardBlockTransform( invalidWildcardBlockTransform ) ).toBe( false ); + } ); + } ); + + describe( 'isContainerGroupBlock', () => { + it( 'should return true when passed block name matches "core/group"', () => { + expect( isContainerGroupBlock( 'core/group' ) ).toBe( true ); + } ); + + it( 'should return false when passed block name does not match "core/group"', () => { + expect( isContainerGroupBlock( 'core/some-test-name' ) ).toBe( false ); + } ); + } ); + + describe( 'isBlockSelectionOfSameType', () => { + it( 'should return false when all blocks do not match the name of the first block', () => { + const blocks = [ + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/another-block', + }, + { + name: 'core/test-block', + }, + ]; + + expect( isBlockSelectionOfSameType( blocks ) ).toBe( false ); + } ); + + it( 'should return true when all blocks match the name of the first block', () => { + const blocks = [ + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + { + name: 'core/test-block', + }, + ]; + + expect( isBlockSelectionOfSameType( blocks ) ).toBe( true ); + } ); + } ); } ); diff --git a/packages/e2e-tests/fixtures/block-transforms.js b/packages/e2e-tests/fixtures/block-transforms.js index 79d4d7bc804566..913953d69d2b3e 100644 --- a/packages/e2e-tests/fixtures/block-transforms.js +++ b/packages/e2e-tests/fixtures/block-transforms.js @@ -1,131 +1,166 @@ export const EXPECTED_TRANSFORMS = { core__archives: { originalBlock: 'Archives', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__archives__showPostCounts: { originalBlock: 'Archives', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__audio: { originalBlock: 'Audio', availableTransforms: [ 'File', + 'Group', ], }, core__button__center: { originalBlock: 'Button', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__calendar: { originalBlock: 'Calendar', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__media-text': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__image-alt-no-align': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__image-fill-no-focal-point-selected': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__image-fill-with-focal-point-selected': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__is-stacked-on-mobile': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Video', ], }, 'core__media-text__media-right-custom-width': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Video', ], }, 'core__media-text__vertical-align-bottom': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Image', ], }, 'core__media-text__video': { originalBlock: 'Media & Text', availableTransforms: [ + 'Group', 'Video', ], }, core__categories: { originalBlock: 'Categories', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__code: { originalBlock: 'Code', availableTransforms: [ + 'Group', 'Preformatted', ], }, core__columns: { originalBlock: 'Columns', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__cover: { availableTransforms: [ + 'Group', 'Image', ], originalBlock: 'Cover', }, core__cover__video: { availableTransforms: [ + 'Group', 'Video', ], originalBlock: 'Cover', }, 'core__cover__video-overlay': { availableTransforms: [ + 'Group', 'Video', ], originalBlock: 'Cover', }, core__embed: { originalBlock: 'Embed', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__file__new-window': { originalBlock: 'File', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__file__no-download-button': { originalBlock: 'File', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__file__no-text-link': { originalBlock: 'File', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__gallery: { originalBlock: 'Gallery', availableTransforms: [ + 'Group', 'Image', ], }, core__gallery__columns: { originalBlock: 'Gallery', availableTransforms: [ + 'Group', 'Image', ], }, @@ -137,6 +172,7 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Heading', availableTransforms: [ 'Quote', + 'Group', 'Paragraph', ], }, @@ -144,12 +180,15 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Heading', availableTransforms: [ 'Quote', + 'Group', 'Paragraph', ], }, core__html: { originalBlock: 'Custom HTML', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__image: { originalBlock: 'Image', @@ -157,6 +196,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -166,6 +206,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -175,6 +216,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -184,6 +226,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -193,6 +236,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -202,6 +246,7 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, @@ -211,43 +256,59 @@ export const EXPECTED_TRANSFORMS = { 'Gallery', 'Cover', 'File', + 'Group', 'Media & Text', ], }, 'core__latest-comments': { originalBlock: 'Latest Comments', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__latest-posts': { originalBlock: 'Latest Posts', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__latest-posts__displayPostDate': { originalBlock: 'Latest Posts', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__legacy-widget': { originalBlock: 'Legacy Widget (Experimental)', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__list__ul: { originalBlock: 'List', availableTransforms: [ + 'Group', 'Paragraph', 'Quote', ], }, core__more: { originalBlock: 'More', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__more__custom-text-teaser': { originalBlock: 'More', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__nextpage: { originalBlock: 'Page Break', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__paragraph__align-right': { originalBlock: 'Paragraph', @@ -255,6 +316,7 @@ export const EXPECTED_TRANSFORMS = { 'Heading', 'List', 'Quote', + 'Group', 'Preformatted', 'Verse', ], @@ -262,6 +324,7 @@ export const EXPECTED_TRANSFORMS = { core__preformatted: { originalBlock: 'Preformatted', availableTransforms: [ + 'Group', 'Paragraph', ], }, @@ -269,18 +332,21 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Pullquote', availableTransforms: [ 'Quote', + 'Group', ], }, 'core__pullquote__multi-paragraph': { originalBlock: 'Pullquote', availableTransforms: [ 'Quote', + 'Group', ], }, 'core__quote__style-1': { originalBlock: 'Quote', availableTransforms: [ 'List', + 'Group', 'Paragraph', 'Heading', 'Pullquote', @@ -290,6 +356,7 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Quote', availableTransforms: [ 'List', + 'Group', 'Paragraph', 'Heading', 'Pullquote', @@ -297,44 +364,62 @@ export const EXPECTED_TRANSFORMS = { }, core__rss: { originalBlock: 'RSS', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__search: { originalBlock: 'Search', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__search__custom-text': { originalBlock: 'Search', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__separator: { originalBlock: 'Separator', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__shortcode: { originalBlock: 'Shortcode', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__spacer: { originalBlock: 'Spacer', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, core__table: { originalBlock: 'Table', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__tag-cloud': { originalBlock: 'Tag Cloud', - availableTransforms: [], + availableTransforms: [ + 'Group', + ], }, 'core__tag-cloud__showTagCounts': { originalBlock: 'Tag Cloud', availableTransforms: [ + 'Group', ], }, core__verse: { originalBlock: 'Verse', availableTransforms: [ + 'Group', 'Paragraph', ], }, @@ -343,6 +428,7 @@ export const EXPECTED_TRANSFORMS = { availableTransforms: [ 'Cover', 'File', + 'Group', 'Media & Text', ], }, diff --git a/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap new file mode 100644 index 00000000000000..af571b2010ed25 --- /dev/null +++ b/packages/e2e-tests/specs/__snapshots__/block-grouping.test.js.snap @@ -0,0 +1,99 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Block Grouping Group creation creates a group from multiple blocks of different types via block transforms 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via block transforms 1`] = ` +" +
+

First Paragraph

+ + + +

Second Paragraph

+ + + +

Third Paragraph

+
+" +`; + +exports[`Block Grouping Group creation creates a group from multiple blocks of the same type via options toolbar 1`] = ` +" +
+

First Paragraph

+ + + +

Second Paragraph

+ + + +

Third Paragraph

+
+" +`; + +exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; + +exports[`Block Grouping Group creation groups and ungroups multiple blocks of different types via options toolbar 2`] = ` +" +

Group Heading

+ + + +
\\"\\"/
+ + + +

Some paragraph

+" +`; + +exports[`Block Grouping Preserving selected blocks attributes preserves width alignment settings of selected blocks 1`] = ` +" +
+

Group Heading

+ + + +
\\"\\"/
+ + + +
\\"\\"/
+ + + +

Some paragraph

+
+" +`; diff --git a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap index ce9dfc0be7e555..25e50d75416a43 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap @@ -96,6 +96,14 @@ exports[`Block transforms correctly transform block Image in fixture core__image " `; +exports[`Block transforms correctly transform block Image in fixture core__image into the Group block 1`] = ` +" +
+
\\"\\"/
+
+" +`; + exports[`Block transforms correctly transform block Image in fixture core__image into the Media & Text block 1`] = ` "
\\"\\"/
@@ -352,6 +360,14 @@ exports[`Block transforms correctly transform block Media & Text in fixture core " `; +exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Group block 1`] = ` +" +
+

... like this one, which is separate from the above and right aligned.

+
+" +`; + exports[`Block transforms correctly transform block Paragraph in fixture core__paragraph__align-right into the Heading block 1`] = ` "

... like this one, which is separate from the above and right aligned.

diff --git a/packages/e2e-tests/specs/block-deletion.test.js b/packages/e2e-tests/specs/block-deletion.test.js index 194ff847328c18..02cc0a0f5720ee 100644 --- a/packages/e2e-tests/specs/block-deletion.test.js +++ b/packages/e2e-tests/specs/block-deletion.test.js @@ -8,6 +8,7 @@ import { createNewPost, isInDefaultBlock, pressKeyWithModifier, + pressKeyTimes, insertBlock, } from '@wordpress/e2e-test-utils'; @@ -22,10 +23,37 @@ const addThreeParagraphsToNewPost = async () => { await page.keyboard.press( 'Enter' ); }; -const clickOnBlockSettingsMenuItem = async ( buttonLabel ) => { +/** + * Due to an issue with the Popover component not being scrollable + * under certain conditions, Pupeteer cannot "see" the "Remove Block" + * button. This is a workaround until that issue is resolved. + * + * see: https://github.com/WordPress/gutenberg/pull/14908#discussion_r284725956 + */ +const clickOnBlockSettingsMenuRemoveBlockButton = async () => { await clickBlockToolbarButton( 'More options' ); - const itemButton = ( await page.$x( `//*[contains(@class, "block-editor-block-settings-menu__popover")]//button[contains(text(), '${ buttonLabel }')]` ) )[ 0 ]; - await itemButton.click(); + + let isRemoveButton = false; + + let numButtons = await page.$$eval( '.block-editor-block-toolbar button', ( btns ) => btns.length ); + + // Limit by the number of buttons available + while ( --numButtons ) { + await page.keyboard.press( 'Tab' ); + + isRemoveButton = await page.evaluate( () => { + return document.activeElement.innerText.includes( 'Remove Block' ); + } ); + + // Stop looping once we find the button + if ( isRemoveButton ) { + await pressKeyTimes( 'Enter', 1 ); + break; + } + } + + // Makes failures more explicit + await expect( isRemoveButton ).toBe( true ); }; describe( 'block deletion -', () => { @@ -39,7 +67,8 @@ describe( 'block deletion -', () => { // Press Escape to show the block toolbar await page.keyboard.press( 'Escape' ); - await clickOnBlockSettingsMenuItem( 'Remove Block' ); + await clickOnBlockSettingsMenuRemoveBlockButton(); + expect( await getEditedPostContent() ).toMatchSnapshot(); // Type additional text and assert that caret position is correct by comparing to snapshot. @@ -121,7 +150,7 @@ describe( 'deleting all blocks', () => { await page.keyboard.press( 'Escape' ); - await clickOnBlockSettingsMenuItem( 'Remove Block' ); + await clickOnBlockSettingsMenuRemoveBlockButton(); // There is a default block: expect( await page.$$( '.block-editor-block-list__block' ) ).toHaveLength( 1 ); diff --git a/packages/e2e-tests/specs/block-grouping.test.js b/packages/e2e-tests/specs/block-grouping.test.js new file mode 100644 index 00000000000000..57300ec2b9de66 --- /dev/null +++ b/packages/e2e-tests/specs/block-grouping.test.js @@ -0,0 +1,176 @@ +/** + * WordPress dependencies + */ +import { + insertBlock, + createNewPost, + clickBlockToolbarButton, + pressKeyWithModifier, + getEditedPostContent, + transformBlockTo, + getAllBlocks, + getAvailableBlockTransforms, +} from '@wordpress/e2e-test-utils'; + +async function insertBlocksOfSameType() { + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'First Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Second Paragraph' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Third Paragraph' ); +} + +async function insertBlocksOfMultipleTypes() { + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + + await insertBlock( 'Image' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); +} + +describe( 'Block Grouping', () => { + beforeEach( async () => { + // Posts are auto-removed at the end of each test run + await createNewPost(); + } ); + + describe( 'Group creation', () => { + it( 'creates a group from multiple blocks of the same type via block transforms', async () => { + // Creating test blocks + await insertBlocksOfSameType(); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await transformBlockTo( 'Group' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'creates a group from multiple blocks of different types via block transforms', async () => { + // Creating test blocks + await insertBlocksOfMultipleTypes(); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await transformBlockTo( 'Group' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'creates a group from multiple blocks of the same type via options toolbar', async () => { + // Creating test blocks + await insertBlocksOfSameType(); + + // Multiselect via keyboard. + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await clickBlockToolbarButton( 'More options' ); + + const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); + await groupButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'groups and ungroups multiple blocks of different types via options toolbar', async () => { + // Creating test blocks + await insertBlocksOfMultipleTypes(); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + // Group + await clickBlockToolbarButton( 'More options' ); + const groupButton = await page.waitForXPath( '//button[text()="Group"]' ); + await groupButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + + // UnGroup + await clickBlockToolbarButton( 'More options' ); + const unGroupButton = await page.waitForXPath( '//button[text()="Ungroup"]' ); + await unGroupButton.click(); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + } ); + + describe( 'Container Block availability', () => { + beforeEach( async () => { + // Disable the Group block + await page.evaluate( () => { + const { dispatch } = wp.data; + dispatch( 'core/edit-post' ).hideBlockTypes( [ 'core/group' ] ); + } ); + + // Create a Group + await insertBlocksOfMultipleTypes(); + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + } ); + + afterAll( async () => { + // Re-enable the Group block + await page.evaluate( () => { + const { dispatch } = wp.data; + dispatch( 'core/edit-post' ).showBlockTypes( [ 'core/group' ] ); + } ); + } ); + + it( 'does not show group transform if container block is disabled', async () => { + const availableTransforms = await getAvailableBlockTransforms(); + + expect( + availableTransforms + ).not.toContain( 'Group' ); + } ); + + it( 'does not show group option in the options toolbar if container block is disabled ', async () => { + await clickBlockToolbarButton( 'More options' ); + + const blockOptionsDropdownHTML = await page.evaluate( () => document.querySelector( '.block-editor-block-settings-menu__content' ).innerHTML ); + + expect( blockOptionsDropdownHTML ).not.toContain( 'Group' ); + } ); + } ); + + describe( 'Preserving selected blocks attributes', () => { + it( 'preserves width alignment settings of selected blocks', async () => { + await insertBlock( 'Heading' ); + await page.keyboard.type( 'Group Heading' ); + + // Full width image + await insertBlock( 'Image' ); + await clickBlockToolbarButton( 'Full width' ); + + // Wide width image) + await insertBlock( 'Image' ); + await clickBlockToolbarButton( 'Wide width' ); + + await insertBlock( 'Paragraph' ); + await page.keyboard.type( 'Some paragraph' ); + + await pressKeyWithModifier( 'primary', 'a' ); + await pressKeyWithModifier( 'primary', 'a' ); + + await transformBlockTo( 'Group' ); + + const allBlocks = await getAllBlocks(); + + // We expect Group block align setting to match that + // of the widest of it's "child" innerBlocks + expect( allBlocks[ 0 ].attributes.align ).toBe( 'full' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + } ); +} ); diff --git a/packages/e2e-tests/specs/block-switcher.test.js b/packages/e2e-tests/specs/block-switcher.test.js index 0d2fcf2adfe9e3..9282e83dc855f1 100644 --- a/packages/e2e-tests/specs/block-switcher.test.js +++ b/packages/e2e-tests/specs/block-switcher.test.js @@ -27,6 +27,7 @@ describe( 'adding blocks', () => { expect( await getAvailableBlockTransforms() ).toEqual( [ + 'Group', 'Paragraph', 'Quote', ] ); @@ -50,6 +51,7 @@ describe( 'adding blocks', () => { expect( await getAvailableBlockTransforms() ).toEqual( [ + 'Group', 'Paragraph', ] ); } ); @@ -60,6 +62,7 @@ describe( 'adding blocks', () => { ( [ 'core/quote', 'core/paragraph', + 'core/group', ] ).map( ( block ) => wp.blocks.unregisterBlockType( block ) ); } ); diff --git a/packages/e2e-tests/specs/block-transforms.test.js b/packages/e2e-tests/specs/block-transforms.test.js index a16a7a1ec10035..89d14bf524491f 100644 --- a/packages/e2e-tests/specs/block-transforms.test.js +++ b/packages/e2e-tests/specs/block-transforms.test.js @@ -153,7 +153,12 @@ describe( 'Block transforms', () => { ) ); - it.each( testTable )( + // As Group is available as a transform on *all* blocks this would create a lot of + // tests which would impact on the performance of the e2e test suite. + // To avoid this, we remove `core/group` from test table for all but 2 block types. + const testTableWithSomeGroupsFiltered = testTable.filter( ( transform ) => ( transform[ 2 ] !== 'Group' || transform[ 1 ] === 'core__paragraph__align-right' || transform[ 1 ] === 'core__image' ) ); + + it.each( testTableWithSomeGroupsFiltered )( 'block %s in fixture %s into the %s block', async ( originalBlock, fixture, destinationBlock ) => { const { content } = transformStructure[ fixture ]; diff --git a/packages/editor/src/components/convert-to-group-buttons/convert-button.js b/packages/editor/src/components/convert-to-group-buttons/convert-button.js new file mode 100644 index 00000000000000..6a7299ed259c98 --- /dev/null +++ b/packages/editor/src/components/convert-to-group-buttons/convert-button.js @@ -0,0 +1,127 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Fragment } from '@wordpress/element'; +import { MenuItem } from '@wordpress/components'; +import { _x } from '@wordpress/i18n'; +import { switchToBlockType } from '@wordpress/blocks'; +import { withSelect, withDispatch } from '@wordpress/data'; +import { compose } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { Group, Ungroup } from './icons'; + +export function ConvertToGroupButton( { + onConvertToGroup, + onConvertFromGroup, + isGroupable = false, + isUngroupable = false, +} ) { + return ( + + { isGroupable && ( + + { _x( 'Group', 'verb' ) } + + ) } + { isUngroupable && ( + + { _x( 'Ungroup', 'Ungrouping blocks from within a Group block back into individual blocks within the Editor ' ) } + + ) } + + ); +} + +export default compose( [ + withSelect( ( select, { clientIds } ) => { + const { + getBlocksByClientId, + canInsertBlockType, + } = select( 'core/block-editor' ); + + const containerBlockAvailable = canInsertBlockType( 'core/group' ); + + const blocksSelection = getBlocksByClientId( clientIds ); + + const isSingleContainerBlock = blocksSelection.length === 1 && blocksSelection[ 0 ] && blocksSelection[ 0 ].name === 'core/group'; + + // Do we have + // 1. Container block available to be inserted? + // 2. One or more blocks selected + // (we allow single Blocks to become groups unless + // they are a soltiary group block themselves) + const isGroupable = ( + containerBlockAvailable && + blocksSelection.length && + ! isSingleContainerBlock + ); + + // Do we have a single Group Block selected? + const isUngroupable = isSingleContainerBlock; + + return { + isGroupable, + isUngroupable, + blocksSelection, + }; + } ), + withDispatch( ( dispatch, { clientIds, onToggle = noop, blocksSelection = [] } ) => { + const { + replaceBlocks, + } = dispatch( 'core/block-editor' ); + + return { + onConvertToGroup() { + if ( ! blocksSelection.length ) { + return; + } + + // Activate the `transform` on `core/group` which does the conversion + const newBlocks = switchToBlockType( blocksSelection, 'core/group' ); + + if ( newBlocks ) { + replaceBlocks( + clientIds, + newBlocks + ); + } + + onToggle(); + }, + onConvertFromGroup() { + if ( ! blocksSelection.length ) { + return; + } + + const innerBlocks = blocksSelection[ 0 ].innerBlocks; + + if ( ! innerBlocks.length ) { + return; + } + + replaceBlocks( + clientIds, + innerBlocks + ); + + onToggle(); + }, + }; + } ), +] )( ConvertToGroupButton ); diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js new file mode 100644 index 00000000000000..8ca249c2fa7ee6 --- /dev/null +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -0,0 +1,19 @@ +/** + * WordPress dependencies + */ +import { Icon, SVG, Path } from '@wordpress/components'; + +const GroupSVG = + + +; + +export const Group = ; + +const UngroupSVG = + + +; + +export const Ungroup = ; + diff --git a/packages/editor/src/components/convert-to-group-buttons/index.js b/packages/editor/src/components/convert-to-group-buttons/index.js new file mode 100644 index 00000000000000..a276ed4434bcab --- /dev/null +++ b/packages/editor/src/components/convert-to-group-buttons/index.js @@ -0,0 +1,33 @@ +/** + * WordPress dependencies + */ +import { Fragment } from '@wordpress/element'; +import { __experimentalBlockSettingsMenuPluginsExtension } from '@wordpress/block-editor'; +import { withSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import ConvertToGroupButton from './convert-button'; + +function ConvertToGroupButtons( { clientIds } ) { + return ( + <__experimentalBlockSettingsMenuPluginsExtension> + { ( { onClose } ) => ( + + + + ) } + + ); +} + +export default withSelect( ( select ) => { + const { getSelectedBlockClientIds } = select( 'core/block-editor' ); + return { + clientIds: getSelectedBlockClientIds(), + }; +} )( ConvertToGroupButtons ); diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 601a44c0260cfe..e897931daf6c42 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -21,6 +21,7 @@ import { decodeEntities } from '@wordpress/html-entities'; */ import { mediaUpload } from '../../utils'; import ReusableBlocksButtons from '../reusable-blocks-buttons'; +import ConvertToGroupButtons from '../convert-to-group-buttons'; const fetchLinkSuggestions = async ( search ) => { const posts = await apiFetch( { @@ -159,6 +160,7 @@ class EditorProvider extends Component { > { children } + ); } From 3817f476f8ce8c8a55a8ce3b61ec30cb8a9cc431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= Date: Wed, 5 Jun 2019 13:07:15 +0200 Subject: [PATCH 045/132] Scripts: Add default file patterns for linting scripts (#15890) * Scripts: Add default file patterns for linting scripts * Add CHANGELOG entry --- package-lock.json | 123 ++++------------------ package.json | 10 +- packages/scripts/CHANGELOG.md | 3 + packages/scripts/README.md | 31 ++++-- packages/scripts/package.json | 1 + packages/scripts/scripts/lint-js.js | 7 +- packages/scripts/scripts/lint-pkg-json.js | 7 +- packages/scripts/scripts/lint-style.js | 7 +- packages/scripts/utils/cli.js | 4 + packages/scripts/utils/index.js | 4 +- 10 files changed, 75 insertions(+), 122 deletions(-) diff --git a/package-lock.json b/package-lock.json index f2ec975d616b57..8632bb2c43cde7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,12 +53,6 @@ "minimist": "^1.2.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -937,14 +931,6 @@ "requires": { "exec-sh": "^0.3.2", "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } } }, "@iarna/toml": { @@ -3825,6 +3811,7 @@ "eslint": "^5.16.0", "jest": "^24.7.1", "jest-puppeteer": "^4.0.0", + "minimist": "^1.2.0", "npm-package-json-lint": "^3.6.0", "puppeteer": "1.6.1", "read-pkg-up": "^1.0.1", @@ -5479,12 +5466,6 @@ "semver": "^5.0.3" }, "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "semver": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", @@ -5936,7 +5917,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -6827,12 +6809,6 @@ "trim-newlines": "^2.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -6941,12 +6917,6 @@ "trim-newlines": "^2.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -7058,12 +7028,6 @@ "trim-newlines": "^2.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -10224,7 +10188,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": false, + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -10554,12 +10519,6 @@ "trim-newlines": "^1.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", @@ -10670,12 +10629,6 @@ "trim-newlines": "^2.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -10770,12 +10723,6 @@ "trim-newlines": "^2.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -14879,9 +14826,9 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, "minimist-options": { @@ -14985,6 +14932,14 @@ "dev": true, "requires": { "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } } }, "modify-values": { @@ -15444,12 +15399,6 @@ "mime-db": "1.40.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "nan": { "version": "2.13.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", @@ -16100,6 +16049,12 @@ "wordwrap": "~0.0.2" }, "dependencies": { + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", @@ -16759,12 +16714,6 @@ "minimist": "^1.2.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -17521,12 +17470,6 @@ "minimist": "^1.2.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -18331,14 +18274,6 @@ "buffer-equal": "0.0.1", "minimist": "^1.1.3", "through2": "^2.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } } }, "raf": { @@ -19496,12 +19431,6 @@ "pump": "^3.0.0" } }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -20616,14 +20545,6 @@ "duplexer": "^0.1.1", "minimist": "^1.2.0", "through": "^2.3.4" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } } }, "style-search": { diff --git a/package.json b/package.json index 7b5d744f8d347c..790c5db1328d9c 100644 --- a/package.json +++ b/package.json @@ -2,14 +2,18 @@ "name": "gutenberg", "version": "5.8.0", "private": true, - "description": "A new WordPress editor experience", - "repository": "git+https://github.com/WordPress/gutenberg.git", + "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ "WordPress", "editor" ], + "homepage": "https://github.com/WordPress/gutenberg/", + "repository": "git+https://github.com/WordPress/gutenberg.git", + "bugs": { + "url": "https://github.com/WordPress/gutenberg/issues" + }, "config": { "GUTENBERG_PHASE": 2 }, @@ -182,7 +186,7 @@ "fixtures:generate": "npm run fixtures:server-registered && cross-env GENERATE_MISSING_FIXTURES=y npm run test-unit", "fixtures:regenerate": "npm run fixtures:clean && npm run fixtures:generate", "lint": "concurrently \"npm run lint-js\" \"npm run lint-pkg-json\" \"npm run lint-css\"", - "lint-js": "wp-scripts lint-js .", + "lint-js": "wp-scripts lint-js", "lint-js:fix": "npm run lint-js -- --fix", "lint-php": "docker-compose run --rm composer run-script lint", "lint-pkg-json": "wp-scripts lint-pkg-json ./packages", diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index e7e408e8b0166f..1183fa6bd736d4 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,9 @@ ### New Features +- The `lint-js` command lints now JS files in the entire project's directories by default ([15890](https://github.com/WordPress/gutenberg/pull/15890)). +- The `lint-pkg-json` command lints now `package.json` files in the entire project's directories by default ([15890](https://github.com/WordPress/gutenberg/pull/15890)). +- The `lint-style` command lints now CSS and SCSS files in the entire project's directories by default ([15890](https://github.com/WordPress/gutenberg/pull/15890)). - The `lint-js`, `lint-pkg-json` and `lint-style` commands ignore now files located in `build` and `node_modules` folders by default ([15977](https://github.com/WordPress/gutenberg/pull/15977)). ## 3.2.0 (2019-05-21) diff --git a/packages/scripts/README.md b/packages/scripts/README.md index 0e394ad71f23a2..7ee723ce817047 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -25,10 +25,10 @@ _Example:_ "scripts": { "build": "wp-scripts build", "check-engines": "wp-scripts check-engines", - "check-licenses": "wp-scripts check-licenses --production", - "lint:css": "wp-scripts lint-style '**/*.css'", - "lint:js": "wp-scripts lint-js .", - "lint:pkg-json": "wp-scripts lint-pkg-json .", + "check-licenses": "wp-scripts check-licenses", + "lint:css": "wp-scripts lint-style", + "lint:js": "wp-scripts lint-js", + "lint:pkg-json": "wp-scripts lint-pkg-json", "start": "wp-scripts start", "test:e2e": "wp-scripts test-e2e", "test:unit": "wp-scripts test-unit-js" @@ -101,7 +101,7 @@ _Example:_ _Flags_: - `--prod` (or `--production`): When present, validates only `dependencies` and not `devDependencies` -- `--dev` (or `--development`): When present, validates both `dependencies` and `devDependencies` +- `--dev` (or `--development`): When present, validates only `devDependencies` and not `dependencies` - `--gpl2`: Validates against [GPLv2 license compatibility](https://www.gnu.org/licenses/license-list.en.html) - `--ignore=a,b,c`: A comma-separated set of package names to ignore for validation. This is intended to be used primarily in cases where a dependency's `license` field is malformed. It's assumed that any `ignored` package argument would be manually vetted for compatibility by the project owner. @@ -114,7 +114,8 @@ _Example:_ ```json { "scripts": { - "lint:js": "wp-scripts lint-js ." + "lint:js": "wp-scripts lint-js", + "lint:js:src": "wp-scripts lint-js ./src" } } ``` @@ -122,7 +123,9 @@ _Example:_ This is how you execute the script with presented setup: * `npm run lint:js` - lints JavaScript files in the entire project's directories. +* `npm run lint:js:src` - lints JavaScript files in the project's `src` subfolder's directories. +When you run commands similar to the `npm run lint:js:src` example above, you can provide a file, a directory, or `glob` syntax or any combination of them. See [more examples](https://eslint.org/docs/user-guide/command-line-interface). By default, files located in `build` and `node_modules` folders are ignored. @@ -139,14 +142,18 @@ _Example:_ ```json { "scripts": { - "lint:pkg-json": "wp-scripts lint-pkg-json ." + "lint:pkg-json": "wp-scripts lint-pkg-json", + "lint:pkg-json:src": "wp-scripts lint-pkg-json ./src" } } ``` This is how you execute those scripts using the presented setup: -* `npm run lint:pkg-json` - lints `package.json` file in the project's root folder. +* `npm run lint:pkg-json` - lints `package.json` file in the entire project's directories. +* `npm run lint:pkg-json:src` - lints `package.json` file in the project's `src` subfolder's directories. + +When you run commands similar to the `npm run lint:pkg-json:src` example above, you can provide one or multiple directories to scan as well. See [more examples](https://github.com/tclindner/npm-package-json-lint/blob/HEAD/README.md#examples). By default, files located in `build` and `node_modules` folders are ignored. @@ -163,14 +170,18 @@ _Example:_ ```json { "scripts": { - "lint:css": "wp-scripts lint-style '**/*.css'" + "lint:style": "wp-scripts lint-style", + "lint:css:src": "wp-scripts lint-style 'src/**/*.css'" } } ``` This is how you execute the script with presented setup: -* `npm run lint:css` - lints CSS files in the whole project's directory. +* `npm run lint:style` - lints CSS and SCSS files in the entire project's directories. +* `npm run lint:css:src` - lints only CSS files in the project's `src` subfolder's directories. + +When you run commands similar to the `npm run lint:css:src` example above, be sure to include the quotation marks around file globs. This ensures that you can use the powers of [globby](https://github.com/sindresorhus/globby) (like the `**` globstar) regardless of your shell. See [more examples](https://github.com/stylelint/stylelint/blob/HEAD/docs/user-guide/cli.md#examples). By default, files located in `build` and `node_modules` folders are ignored. diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 712b5edde2b3f5..c8d503efb886c6 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -44,6 +44,7 @@ "eslint": "^5.16.0", "jest": "^24.7.1", "jest-puppeteer": "^4.0.0", + "minimist": "^1.2.0", "npm-package-json-lint": "^3.6.0", "puppeteer": "1.6.1", "read-pkg-up": "^1.0.1", diff --git a/packages/scripts/scripts/lint-js.js b/packages/scripts/scripts/lint-js.js index 33bcdf83e5f897..04d24cd538fcb2 100644 --- a/packages/scripts/scripts/lint-js.js +++ b/packages/scripts/scripts/lint-js.js @@ -11,12 +11,15 @@ const { fromConfigRoot, getCliArgs, hasCliArg, + hasFileInCliArgs, hasPackageProp, hasProjectFile, } = require( '../utils' ); const args = getCliArgs(); +const defaultFilesArgs = ! hasFileInCliArgs ? [ '.' ] : []; + // See: https://eslint.org/docs/user-guide/configuring#using-configuration-files-1. const hasLintConfig = hasCliArg( '-c' ) || hasCliArg( '--config' ) || @@ -30,7 +33,7 @@ const hasLintConfig = hasCliArg( '-c' ) || // When a configuration is not provided by the project, use from the default // provided with the scripts module. Instruct ESLint to avoid discovering via // the `--no-eslintrc` flag, as otherwise it will still merge with inherited. -const config = ! hasLintConfig ? +const defaultConfigArgs = ! hasLintConfig ? [ '--no-eslintrc', '--config', fromConfigRoot( '.eslintrc.js' ) ] : []; @@ -44,7 +47,7 @@ const defaultIgnoreArgs = ! hasIgnoredFiles ? const result = spawn( resolveBin( 'eslint' ), - [ ...config, ...defaultIgnoreArgs, ...args ], + [ ...defaultConfigArgs, ...defaultIgnoreArgs, ...args, ...defaultFilesArgs ], { stdio: 'inherit' } ); diff --git a/packages/scripts/scripts/lint-pkg-json.js b/packages/scripts/scripts/lint-pkg-json.js index c3cbd4f429c680..3d15b2bddb1d07 100644 --- a/packages/scripts/scripts/lint-pkg-json.js +++ b/packages/scripts/scripts/lint-pkg-json.js @@ -11,12 +11,15 @@ const { fromConfigRoot, getCliArgs, hasCliArg, + hasFileInCliArgs, hasProjectFile, hasPackageProp, } = require( '../utils' ); const args = getCliArgs(); +const defaultFilesArgs = ! hasFileInCliArgs ? [ '.' ] : []; + // See: https://github.com/tclindner/npm-package-json-lint/wiki/configuration#configuration. const hasLintConfig = hasCliArg( '-c' ) || hasCliArg( '--configFile' ) || @@ -24,7 +27,7 @@ const hasLintConfig = hasCliArg( '-c' ) || hasProjectFile( 'npmpackagejsonlint.config.js' ) || hasPackageProp( 'npmPackageJsonLintConfig' ); -const config = ! hasLintConfig ? +const defaultConfigArgs = ! hasLintConfig ? [ '--configFile', fromConfigRoot( 'npmpackagejsonlint.json' ) ] : []; @@ -38,7 +41,7 @@ const defaultIgnoreArgs = ! hasIgnoredFiles ? const result = spawn( resolveBin( 'npm-package-json-lint', { executable: 'npmPkgJsonLint' } ), - [ ...config, ...defaultIgnoreArgs, ...args ], + [ ...defaultConfigArgs, ...defaultIgnoreArgs, ...args, defaultFilesArgs ], { stdio: 'inherit' } ); diff --git a/packages/scripts/scripts/lint-style.js b/packages/scripts/scripts/lint-style.js index 32783a97f4eb2b..024e04983ca8b1 100644 --- a/packages/scripts/scripts/lint-style.js +++ b/packages/scripts/scripts/lint-style.js @@ -11,12 +11,15 @@ const { fromConfigRoot, getCliArgs, hasCliArg, + hasFileInCliArgs, hasProjectFile, hasPackageProp, } = require( '../utils' ); const args = getCliArgs(); +const defaultFilesArgs = ! hasFileInCliArgs ? [ '**/*.{css,scss}' ] : []; + // See: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#loading-the-configuration-object. const hasLintConfig = hasCliArg( '--config' ) || hasProjectFile( '.stylelintrc' ) || @@ -27,7 +30,7 @@ const hasLintConfig = hasCliArg( '--config' ) || hasProjectFile( '.stylelint.config.js' ) || hasPackageProp( 'stylelint' ); -const config = ! hasLintConfig ? +const defaultConfigArgs = ! hasLintConfig ? [ '--config', fromConfigRoot( '.stylelintrc.json' ) ] : []; @@ -41,7 +44,7 @@ const defaultIgnoreArgs = ! hasIgnoredFiles ? const result = spawn( resolveBin( 'stylelint' ), - [ ...config, ...defaultIgnoreArgs, ...args ], + [ ...defaultConfigArgs, ...defaultIgnoreArgs, ...args, ...defaultFilesArgs ], { stdio: 'inherit' } ); diff --git a/packages/scripts/utils/cli.js b/packages/scripts/utils/cli.js index 3778379ced1920..db4ce5fcef2d49 100644 --- a/packages/scripts/utils/cli.js +++ b/packages/scripts/utils/cli.js @@ -1,6 +1,7 @@ /** * External dependencies */ +const minimist = require( 'minimist' ); const spawn = require( 'cross-spawn' ); /** @@ -26,6 +27,8 @@ const getCliArg = ( arg ) => { const hasCliArg = ( arg ) => getCliArg( arg ) !== undefined; +const hasFileInCliArgs = () => minimist( getCliArgs() )._.length > 0; + const handleSignal = ( signal ) => { if ( signal === 'SIGKILL' ) { // eslint-disable-next-line no-console @@ -81,5 +84,6 @@ module.exports = { getCliArg, getCliArgs, hasCliArg, + hasFileInCliArgs, spawnScript, }; diff --git a/packages/scripts/utils/index.js b/packages/scripts/utils/index.js index aebbcdca718007..2912c9aee22bbb 100644 --- a/packages/scripts/utils/index.js +++ b/packages/scripts/utils/index.js @@ -5,8 +5,8 @@ const { getCliArg, getCliArgs, hasCliArg, + hasFileInCliArgs, spawnScript, - cleanUpArgs, } = require( './cli' ); const { getWebpackArgs, @@ -32,9 +32,9 @@ module.exports = { getWebpackArgs, hasBabelConfig, hasCliArg, + hasFileInCliArgs, hasJestConfig, hasPackageProp, hasProjectFile, spawnScript, - cleanUpArgs, }; From 350984d74dc3e22891fe9c22f81bd8b264924466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Est=C3=AAv=C3=A3o?= Date: Wed, 5 Jun 2019 13:06:01 +0100 Subject: [PATCH 046/132] Style quotes in the mobile app (#15990) * Add spacer between BlockQuotation elements. * Use citation identifier to style rich-text * Remove margin on quote bar. --- .../src/components/rich-text/index.native.js | 2 +- .../src/primitives/block-quotation/index.native.js | 12 +++++++++++- .../src/primitives/block-quotation/style.native.scss | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index a89f293ff8efba..5adcbd23054122 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -862,7 +862,7 @@ export class RichText extends Component { color={ 'black' } maxImagesWidth={ 200 } fontFamily={ this.props.fontFamily || styles[ 'block-editor-rich-text' ].fontFamily } - fontSize={ this.props.fontSize } + fontSize={ this.props.fontSize || ( style && style.fontSize ) } fontWeight={ this.props.fontWeight } fontStyle={ this.props.fontStyle } disableEditingMenu={ this.props.disableEditingMenu } diff --git a/packages/components/src/primitives/block-quotation/index.native.js b/packages/components/src/primitives/block-quotation/index.native.js index eea86435b5ebcd..dbcc249fe1bff5 100644 --- a/packages/components/src/primitives/block-quotation/index.native.js +++ b/packages/components/src/primitives/block-quotation/index.native.js @@ -2,15 +2,25 @@ * External dependencies */ import { View } from 'react-native'; +/** + * WordPress dependencies + */ +import { Children, cloneElement } from '@wordpress/element'; /** * Internal dependencies */ import styles from './style.scss'; export const BlockQuotation = ( props ) => { + const newChildren = Children.map( props.children, ( child ) => { + if ( child && child.props.identifier === 'citation' ) { + return cloneElement( child, { style: styles.wpBlockQuoteCitation } ); + } + return child; + } ); return ( - { props.children } + { newChildren } ); }; diff --git a/packages/components/src/primitives/block-quotation/style.native.scss b/packages/components/src/primitives/block-quotation/style.native.scss index 02d315e1560b6b..2e88c68cf26fa9 100644 --- a/packages/components/src/primitives/block-quotation/style.native.scss +++ b/packages/components/src/primitives/block-quotation/style.native.scss @@ -3,5 +3,10 @@ border-left-color: $black; border-left-style: solid; padding-left: 8px; - margin-left: 8px; + margin-left: 0; +} + +.wpBlockQuoteCitation { + margin-top: 16px; + font-size: 14px; } From e77879b46ec2d8a6b5854557503db0e7cd301dfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Est=C3=AAv=C3=A3o?= Date: Wed, 5 Jun 2019 13:51:18 +0100 Subject: [PATCH 047/132] Refactor remove line separator to method in the rich-text package. (#15946) * Refactor remove line separator to method in the rich-text package. * Address review comments. --- .../src/components/rich-text/index.js | 56 +------------------ .../src/components/rich-text/index.native.js | 55 +----------------- packages/rich-text/src/index.js | 1 + .../rich-text/src/remove-line-separator.js | 56 +++++++++++++++++++ 4 files changed, 63 insertions(+), 105 deletions(-) create mode 100644 packages/rich-text/src/remove-line-separator.js diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js index 0b03bcca6a490d..40f758f064e081 100644 --- a/packages/block-editor/src/components/rich-text/index.js +++ b/packages/block-editor/src/components/rich-text/index.js @@ -30,6 +30,7 @@ import { getTextContent, insert, __unstableInsertLineSeparator as insertLineSeparator, + __unstableRemoveLineSeparator as removeLineSeparator, __unstableIsEmptyLine as isEmptyLine, __unstableToDom as toDom, remove, @@ -639,7 +640,7 @@ export class RichText extends Component { if ( keyCode === DELETE || keyCode === BACKSPACE ) { const value = this.createRecord(); - const { replacements, text, start, end } = value; + const { start, end } = value; // Always handle full content deletion ourselves. if ( start === 0 && end !== 0 && end === value.text.length ) { @@ -649,58 +650,7 @@ export class RichText extends Component { } if ( this.multilineTag ) { - let newValue; - - if ( keyCode === BACKSPACE ) { - const index = start - 1; - - if ( text[ index ] === LINE_SEPARATOR ) { - const collapsed = isCollapsed( value ); - - // If the line separator that is about te be removed - // contains wrappers, remove the wrappers first. - if ( collapsed && replacements[ index ] && replacements[ index ].length ) { - const newReplacements = replacements.slice(); - - newReplacements[ index ] = replacements[ index ].slice( 0, -1 ); - newValue = { - ...value, - replacements: newReplacements, - }; - } else { - newValue = remove( - value, - // Only remove the line if the selection is - // collapsed, otherwise remove the selection. - collapsed ? start - 1 : start, - end - ); - } - } - } else if ( text[ end ] === LINE_SEPARATOR ) { - const collapsed = isCollapsed( value ); - - // If the line separator that is about te be removed - // contains wrappers, remove the wrappers first. - if ( collapsed && replacements[ end ] && replacements[ end ].length ) { - const newReplacements = replacements.slice(); - - newReplacements[ end ] = replacements[ end ].slice( 0, -1 ); - newValue = { - ...value, - replacements: newReplacements, - }; - } else { - newValue = remove( - value, - start, - // Only remove the line if the selection is - // collapsed, otherwise remove the selection. - collapsed ? end + 1 : end, - ); - } - } - + const newValue = removeLineSeparator( value, keyCode === BACKSPACE ); if ( newValue ) { this.onChange( newValue ); event.preventDefault(); diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 5adcbd23054122..92143f16b10697 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -26,9 +26,9 @@ import { split, toHTMLString, insert, - __UNSTABLE_LINE_SEPARATOR as LINE_SEPARATOR, __unstableInsertLineSeparator as insertLineSeparator, __unstableIsEmptyLine as isEmptyLine, + __unstableRemoveLineSeparator as removeLineSeparator, isCollapsed, remove, } from '@wordpress/rich-text'; @@ -386,7 +386,7 @@ export class RichText extends Component { this.comesFromAztec = true; this.firedAfterTextChanged = event.nativeEvent.firedAfterTextChanged; const value = this.createRecord(); - const { replacements, text, start, end } = value; + const { start, end } = value; let newValue; // Always handle full content deletion ourselves. @@ -398,56 +398,7 @@ export class RichText extends Component { } if ( this.multilineTag ) { - if ( keyCode === BACKSPACE ) { - const index = start - 1; - - if ( text[ index ] === LINE_SEPARATOR ) { - const collapsed = isCollapsed( value ); - - // If the line separator that is about te be removed - // contains wrappers, remove the wrappers first. - if ( collapsed && replacements[ index ] && replacements[ index ].length ) { - const newReplacements = replacements.slice(); - - newReplacements[ index ] = replacements[ index ].slice( 0, -1 ); - newValue = { - ...value, - replacements: newReplacements, - }; - } else { - newValue = remove( - value, - // Only remove the line if the selection is - // collapsed, otherwise remove the selection. - collapsed ? start - 1 : start, - end - ); - } - } - } else if ( text[ end ] === LINE_SEPARATOR ) { - const collapsed = isCollapsed( value ); - - // If the line separator that is about te be removed - // contains wrappers, remove the wrappers first. - if ( collapsed && replacements[ end ] && replacements[ end ].length ) { - const newReplacements = replacements.slice(); - - newReplacements[ end ] = replacements[ end ].slice( 0, -1 ); - newValue = { - ...value, - replacements: newReplacements, - }; - } else { - newValue = remove( - value, - start, - // Only remove the line if the selection is - // collapsed, otherwise remove the selection. - collapsed ? end + 1 : end, - ); - } - } - + newValue = removeLineSeparator( value, keyCode === BACKSPACE ); if ( newValue ) { this.onFormatChange( newValue ); return; diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js index 6dbfe46b6d93b4..8f57a21e4ddf34 100644 --- a/packages/rich-text/src/index.js +++ b/packages/rich-text/src/index.js @@ -20,6 +20,7 @@ export { remove } from './remove'; export { replace } from './replace'; export { insert } from './insert'; export { insertLineSeparator as __unstableInsertLineSeparator } from './insert-line-separator'; +export { removeLineSeparator as __unstableRemoveLineSeparator } from './remove-line-separator'; export { insertObject } from './insert-object'; export { slice } from './slice'; export { split } from './split'; diff --git a/packages/rich-text/src/remove-line-separator.js b/packages/rich-text/src/remove-line-separator.js new file mode 100644 index 00000000000000..f9e6dfb157952e --- /dev/null +++ b/packages/rich-text/src/remove-line-separator.js @@ -0,0 +1,56 @@ +/** + * Internal dependencies + */ + +import { LINE_SEPARATOR } from './special-characters'; +import { isCollapsed } from './is-collapsed'; +import { remove } from './remove'; + +/** + * Removes a line separator character, if existing, from a Rich Text value at the current + * indices. If no line separator exists on the indices it will return undefined. + * + * @param {Object} value Value to modify. + * @param {boolean} backward indicates if are removing from the start index or the end index. + * + * @return {Object|undefined} A new value with the line separator removed. Or undefined if no line separator is found on the position. + */ +export function removeLineSeparator( + value, + backward = true, +) { + const { replacements, text, start, end } = value; + const collapsed = isCollapsed( value ); + let index = start - 1; + let removeStart = collapsed ? start - 1 : start; + let removeEnd = end; + if ( ! backward ) { + index = end; + removeStart = start; + removeEnd = collapsed ? end + 1 : end; + } + + if ( text[ index ] !== LINE_SEPARATOR ) { + return; + } + + let newValue; + // If the line separator that is about te be removed + // contains wrappers, remove the wrappers first. + if ( collapsed && replacements[ index ] && replacements[ index ].length ) { + const newReplacements = replacements.slice(); + + newReplacements[ index ] = replacements[ index ].slice( 0, -1 ); + newValue = { + ...value, + replacements: newReplacements, + }; + } else { + newValue = remove( + value, + removeStart, + removeEnd + ); + } + return newValue; +} From 6e9e1f7eddc660ac205f81542f55709a70790801 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Wed, 5 Jun 2019 16:56:08 +0100 Subject: [PATCH 048/132] Extract ServerSideRender component to an independent package (#15635) --- docs/manifest-devhub.json | 12 ++--- lib/client-assets.php | 15 ++++++ package-lock.json | 14 +++++- package.json | 1 + packages/block-library/package.json | 1 + packages/block-library/src/archives/edit.js | 2 +- .../block-library/src/latest-comments/edit.js | 2 +- .../src/legacy-widget/edit/index.js | 2 +- packages/components/CHANGELOG.md | 4 ++ packages/components/package.json | 1 - packages/components/src/index.js | 1 - packages/editor/CHANGELOG.md | 3 ++ packages/editor/src/components/deprecated.js | 1 + packages/editor/src/components/index.js | 1 - .../components/server-side-render/README.md | 3 -- .../components/server-side-render/index.js | 18 -------- packages/server-side-render/.npmrc | 1 + packages/server-side-render/CHANGELOG.md | 5 ++ .../src => }/server-side-render/README.md | 19 +++++++- packages/server-side-render/package.json | 37 +++++++++++++++ packages/server-side-render/src/index.js | 46 +++++++++++++++++++ .../src/server-side-render.js} | 10 ++-- .../src}/test/index.js | 2 +- webpack.config.js | 1 + 24 files changed, 160 insertions(+), 42 deletions(-) delete mode 100644 packages/editor/src/components/server-side-render/README.md delete mode 100644 packages/editor/src/components/server-side-render/index.js create mode 100644 packages/server-side-render/.npmrc create mode 100644 packages/server-side-render/CHANGELOG.md rename packages/{components/src => }/server-side-render/README.md (76%) create mode 100644 packages/server-side-render/package.json create mode 100644 packages/server-side-render/src/index.js rename packages/{components/src/server-side-render/index.js => server-side-render/src/server-side-render.js} (96%) rename packages/{components/src/server-side-render => server-side-render/src}/test/index.js (97%) diff --git a/docs/manifest-devhub.json b/docs/manifest-devhub.json index 14b29c43ddb989..94f21727035536 100644 --- a/docs/manifest-devhub.json +++ b/docs/manifest-devhub.json @@ -899,12 +899,6 @@ "markdown_source": "../packages/components/src/select-control/README.md", "parent": "components" }, - { - "title": "ServerSideRender", - "slug": "server-side-render", - "markdown_source": "../packages/components/src/server-side-render/README.md", - "parent": "components" - }, { "title": "SlotFill", "slug": "slot-fill", @@ -1361,6 +1355,12 @@ "markdown_source": "../packages/scripts/README.md", "parent": "packages" }, + { + "title": "@wordpress/server-side-render", + "slug": "packages-server-side-render", + "markdown_source": "../packages/server-side-render/README.md", + "parent": "packages" + }, { "title": "@wordpress/shortcode", "slug": "packages-shortcode", diff --git a/lib/client-assets.php b/lib/client-assets.php index 4611cadab1172a..5e4d2651bb603d 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -289,6 +289,21 @@ function gutenberg_register_scripts_and_styles() { ) ); + // Add back compatibility for calls to wp.components.ServerSideRender. + wp_add_inline_script( + 'wp-server-side-render', + implode( + "\n", + array( + '( function() {', + ' if ( wp && wp.components && wp.serverSideRender && ! wp.components.ServerSideRender ) {', + ' wp.components.ServerSideRender = wp.serverSideRender;', + ' };', + '} )();', + ) + ) + ); + // Editor Styles. // This empty stylesheet is defined to ensure backward compatibility. gutenberg_override_style( 'wp-blocks', false ); diff --git a/package-lock.json b/package-lock.json index 8632bb2c43cde7..e21b8504db5a29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3309,6 +3309,7 @@ "@wordpress/html-entities": "file:packages/html-entities", "@wordpress/i18n": "file:packages/i18n", "@wordpress/keycodes": "file:packages/keycodes", + "@wordpress/server-side-render": "file:packages/server-side-render", "@wordpress/viewport": "file:packages/viewport", "classnames": "^2.2.5", "fast-average-color": "4.3.0", @@ -3363,7 +3364,6 @@ "requires": { "@babel/runtime": "^7.4.4", "@wordpress/a11y": "file:packages/a11y", - "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/compose": "file:packages/compose", "@wordpress/dom": "file:packages/dom", "@wordpress/element": "file:packages/element", @@ -3826,6 +3826,18 @@ "webpack-livereload-plugin": "^2.2.0" } }, + "@wordpress/server-side-render": { + "version": "file:packages/server-side-render", + "requires": { + "@babel/runtime": "^7.4.4", + "@wordpress/components": "file:packages/components", + "@wordpress/data": "file:packages/data", + "@wordpress/element": "file:packages/element", + "@wordpress/i18n": "file:packages/i18n", + "@wordpress/url": "file:packages/url", + "lodash": "^4.17.11" + } + }, "@wordpress/shortcode": { "version": "file:packages/shortcode", "requires": { diff --git a/package.json b/package.json index 790c5db1328d9c..62de2dba7741d3 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "@wordpress/priority-queue": "file:packages/priority-queue", "@wordpress/redux-routine": "file:packages/redux-routine", "@wordpress/rich-text": "file:packages/rich-text", + "@wordpress/server-side-render": "file:packages/server-side-render", "@wordpress/shortcode": "file:packages/shortcode", "@wordpress/token-list": "file:packages/token-list", "@wordpress/url": "file:packages/url", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 4465a8dfefc496..daa427cffd4a94 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -36,6 +36,7 @@ "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", "@wordpress/keycodes": "file:../keycodes", + "@wordpress/server-side-render": "file:../server-side-render", "@wordpress/viewport": "file:../viewport", "classnames": "^2.2.5", "fast-average-color": "4.3.0", diff --git a/packages/block-library/src/archives/edit.js b/packages/block-library/src/archives/edit.js index c67cdc912e5260..6909b70ccc4271 100644 --- a/packages/block-library/src/archives/edit.js +++ b/packages/block-library/src/archives/edit.js @@ -8,7 +8,7 @@ import { } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { InspectorControls } from '@wordpress/block-editor'; -import { ServerSideRender } from '@wordpress/editor'; +import ServerSideRender from '@wordpress/server-side-render'; export default function ArchivesEdit( { attributes, setAttributes } ) { const { showPostCounts, displayAsDropdown } = attributes; diff --git a/packages/block-library/src/latest-comments/edit.js b/packages/block-library/src/latest-comments/edit.js index 61e7ec3e3aaabb..029778e24f2c59 100644 --- a/packages/block-library/src/latest-comments/edit.js +++ b/packages/block-library/src/latest-comments/edit.js @@ -8,7 +8,7 @@ import { RangeControl, ToggleControl, } from '@wordpress/components'; -import { ServerSideRender } from '@wordpress/editor'; +import ServerSideRender from '@wordpress/server-side-render'; import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; diff --git a/packages/block-library/src/legacy-widget/edit/index.js b/packages/block-library/src/legacy-widget/edit/index.js index ac38184d22989b..31f36c2f7fac94 100644 --- a/packages/block-library/src/legacy-widget/edit/index.js +++ b/packages/block-library/src/legacy-widget/edit/index.js @@ -14,7 +14,7 @@ import { BlockControls, InspectorControls, } from '@wordpress/block-editor'; -import { ServerSideRender } from '@wordpress/editor'; +import ServerSideRender from '@wordpress/server-side-render'; /** * Internal dependencies diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index e6db0bcd0c8ff4..5fc3cba4b28b46 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -13,6 +13,10 @@ - Added missing documentation for `DropdownMenu` props `menuLabel`, `position`, `className`. +### Breaking Change + +- `ServerSideRender` is no longer part of components. It was extracted to an independent package `@wordpress/server-side-render`. + ## 7.4.0 (2019-05-21) diff --git a/packages/components/package.json b/packages/components/package.json index d2aa5957d36a83..df7d8afa76457f 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -23,7 +23,6 @@ "dependencies": { "@babel/runtime": "^7.4.4", "@wordpress/a11y": "file:../a11y", - "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/compose": "file:../compose", "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", diff --git a/packages/components/src/index.js b/packages/components/src/index.js index ab0540fa2f232f..6395ea3d843a42 100644 --- a/packages/components/src/index.js +++ b/packages/components/src/index.js @@ -53,7 +53,6 @@ export { default as SelectControl } from './select-control'; export { default as Snackbar } from './snackbar'; export { default as SnackbarList } from './snackbar/list'; export { default as Spinner } from './spinner'; -export { default as ServerSideRender } from './server-side-render'; export { default as TabPanel } from './tab-panel'; export { default as TextControl } from './text-control'; export { default as TextareaControl } from './textarea-control'; diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md index 3840d850ed599a..921a2b53fdb4a1 100644 --- a/packages/editor/CHANGELOG.md +++ b/packages/editor/CHANGELOG.md @@ -3,6 +3,9 @@ ### Deprecations - The `getAutosave`, `getAutosaveAttribute`, and `hasAutosave` selectors are deprecated. Please use the `getAutosave` selector in the `@wordpress/core-data` package. - The `resetAutosave` action is deprecated. An equivalent action `receiveAutosaves` has been added to the `@wordpress/core-data` package. +- `ServerSideRender` component was deprecated. The component is now available in `@wordpress/server-side-render`. + + ### Internal diff --git a/packages/editor/src/components/deprecated.js b/packages/editor/src/components/deprecated.js index 8468f254c2dccf..330116fabec58e 100644 --- a/packages/editor/src/components/deprecated.js +++ b/packages/editor/src/components/deprecated.js @@ -117,3 +117,4 @@ export { withColors, withFontSizes, }; +export { default as ServerSideRender } from '@wordpress/server-side-render'; diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index 9d12344c50dc2a..f8999c7868042f 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -1,6 +1,5 @@ // Block Creation Components export * from './autocompleters'; -export { default as ServerSideRender } from './server-side-render'; // Post Related Components export { default as AutosaveMonitor } from './autosave-monitor'; diff --git a/packages/editor/src/components/server-side-render/README.md b/packages/editor/src/components/server-side-render/README.md deleted file mode 100644 index 3ef53b188e644f..00000000000000 --- a/packages/editor/src/components/server-side-render/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ServerSideRender - -This utility component is a wrapper for the generic ServerSideRender in `@wordpress/components`. It adds the `post_id` parameter to the `urlQueryArgs` prop of the wrapped component. Use this component to ensure that the global `$post` object is set up properly in the server-side `render_callback` when rendering within the editor. diff --git a/packages/editor/src/components/server-side-render/index.js b/packages/editor/src/components/server-side-render/index.js deleted file mode 100644 index 5830612ebcc36b..00000000000000 --- a/packages/editor/src/components/server-side-render/index.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * WordPress dependencies - */ -import { ServerSideRender } from '@wordpress/components'; -import { select } from '@wordpress/data'; - -export default function( { urlQueryArgs = {}, ...props } ) { - const { getCurrentPostId } = select( 'core/editor' ); - - urlQueryArgs = { - post_id: getCurrentPostId(), - ...urlQueryArgs, - }; - - return ( - - ); -} diff --git a/packages/server-side-render/.npmrc b/packages/server-side-render/.npmrc new file mode 100644 index 00000000000000..43c97e719a5a82 --- /dev/null +++ b/packages/server-side-render/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/packages/server-side-render/CHANGELOG.md b/packages/server-side-render/CHANGELOG.md new file mode 100644 index 00000000000000..04ea9fe434a6fb --- /dev/null +++ b/packages/server-side-render/CHANGELOG.md @@ -0,0 +1,5 @@ +## Unreleased + +### Enhancements + +- Extracted the package from `@wordpress/components` and `@wordpress/editor`; diff --git a/packages/components/src/server-side-render/README.md b/packages/server-side-render/README.md similarity index 76% rename from packages/components/src/server-side-render/README.md rename to packages/server-side-render/README.md index df9d75dec8fa4f..a975cd36f19d10 100644 --- a/packages/components/src/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -8,6 +8,23 @@ ServerSideRender should be regarded as a fallback or legacy mechanism, it is not New blocks should be built in conjunction with any necessary REST API endpoints, so that JavaScript can be used for rendering client-side in the `edit` function. This gives the best user experience, instead of relying on using the PHP `render_callback`. The logic necessary for rendering should be included in the endpoint, so that both the client-side JavaScript and server-side PHP logic should require a minimal amount of differences. +> This package is meant to be used only with WordPress core. Feel free to use it in your own project but please keep in mind that it might never get fully documented. + +## Installation + +Install the module + +```bash +npm install @wordpress/server-side-render --save +``` + +_This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._ + +## Usage + +The props accepted by the component are described below. + + ## Props ### attributes @@ -43,7 +60,7 @@ E.g: `{ post_id: 12 }`. Render core/archives preview. ```jsx -import { ServerSideRender } from '@wordpress/components'; +import { ServerSideRender } from '@wordpress/server-side-render'; const MyServerSideRender = () => ( { + const coreEditorSelect = select( 'core/editor' ); + if ( coreEditorSelect ) { + const currentPostId = coreEditorSelect.getCurrentPostId(); + if ( currentPostId ) { + return { + currentPostId, + }; + } + } + return EMPTY_OBJECT; + } +)( + ( { urlQueryArgs = EMPTY_OBJECT, currentPostId, ...props } ) => { + const newUrlQueryArgs = useMemo( () => { + if ( ! currentPostId ) { + return urlQueryArgs; + } + return { + post_id: currentPostId, + ...urlQueryArgs, + }; + }, [ currentPostId, urlQueryArgs ] ); + + return ( + + ); + } +); diff --git a/packages/components/src/server-side-render/index.js b/packages/server-side-render/src/server-side-render.js similarity index 96% rename from packages/components/src/server-side-render/index.js rename to packages/server-side-render/src/server-side-render.js index d58564d2cd82eb..a0c6a915efae55 100644 --- a/packages/components/src/server-side-render/index.js +++ b/packages/server-side-render/src/server-side-render.js @@ -13,12 +13,10 @@ import { import { __, sprintf } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; import { addQueryArgs } from '@wordpress/url'; - -/** - * Internal dependencies - */ -import Placeholder from '../placeholder'; -import Spinner from '../spinner'; +import { + Placeholder, + Spinner, +} from '@wordpress/components'; export function rendererPath( block, attributes = null, urlQueryArgs = {} ) { return addQueryArgs( `/wp/v2/block-renderer/${ block }`, { diff --git a/packages/components/src/server-side-render/test/index.js b/packages/server-side-render/src/test/index.js similarity index 97% rename from packages/components/src/server-side-render/test/index.js rename to packages/server-side-render/src/test/index.js index c09814771f7a75..b97a80aa91b2b8 100644 --- a/packages/components/src/server-side-render/test/index.js +++ b/packages/server-side-render/src/test/index.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { rendererPath } from '../index'; +import { rendererPath } from '../server-side-render'; describe( 'rendererPath', function() { test( 'should return an base path for empty input', function() { diff --git a/webpack.config.js b/webpack.config.js index 0c0748fb684062..8a8348bb494d52 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -88,6 +88,7 @@ module.exports = { 'dom-ready', 'redux-routine', 'token-list', + 'server-side-render', 'shortcode', ].map( camelCaseDash ) ), new CopyWebpackPlugin( From 79ba27d1836d59127af0e7807697c95b9e0a11fd Mon Sep 17 00:00:00 2001 From: Marko Savic Date: Wed, 5 Jun 2019 12:53:05 -0400 Subject: [PATCH 049/132] Video block has black background when upload is in progress or upload has failed (#15991) * Fixed issue with a black background when the upload is in progress or upload has failed --- .../block-library/src/video/edit.native.js | 18 ++++++++++-------- .../block-library/src/video/style.ios.scss | 8 -------- .../block-library/src/video/style.native.scss | 5 +++++ 3 files changed, 15 insertions(+), 16 deletions(-) delete mode 100644 packages/block-library/src/video/style.ios.scss diff --git a/packages/block-library/src/video/edit.native.js b/packages/block-library/src/video/edit.native.js index 17b6c416f016d9..c37302902e1f0c 100644 --- a/packages/block-library/src/video/edit.native.js +++ b/packages/block-library/src/video/edit.native.js @@ -212,16 +212,18 @@ class VideoEdit extends React.Component { return ( { showVideo && isURL( src ) && - ); diff --git a/packages/block-library/src/video/video-player.ios.js b/packages/block-library/src/video/video-player.ios.js index 0713afc404b1a3..846b79844c107c 100644 --- a/packages/block-library/src/video/video-player.ios.js +++ b/packages/block-library/src/video/video-player.ios.js @@ -57,6 +57,7 @@ class Video extends Component { controls={ false } onLoad={ this.onLoad } onLoadStart={ this.onLoadStart } + ignoreSilentSwitch={ 'ignore' } /> { isLoaded && From f58da98dfd5c56a56e5f34cdaa56b4f98eb04e42 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Thu, 6 Jun 2019 10:36:10 +0200 Subject: [PATCH 054/132] Update package-lock.json wiht missing entry for server-side-render --- package-lock.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package-lock.json b/package-lock.json index e21b8504db5a29..7352bce3c4f67c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3830,6 +3830,7 @@ "version": "file:packages/server-side-render", "requires": { "@babel/runtime": "^7.4.4", + "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/components": "file:packages/components", "@wordpress/data": "file:packages/data", "@wordpress/element": "file:packages/element", From 07ed4b811576f240f0f023db84aa7bdcb5d94162 Mon Sep 17 00:00:00 2001 From: Pinar Olguc Date: Thu, 6 Jun 2019 11:47:04 +0300 Subject: [PATCH 055/132] Start playback immediately after we go full screen (#15998) Otherwise we need user to tap play again --- packages/block-library/src/video/video-player.ios.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/video/video-player.ios.js b/packages/block-library/src/video/video-player.ios.js index 846b79844c107c..53d88380207080 100644 --- a/packages/block-library/src/video/video-player.ios.js +++ b/packages/block-library/src/video/video-player.ios.js @@ -20,6 +20,7 @@ class Video extends Component { super( ...arguments ); this.state = { isLoaded: false, + isFullScreen: false, }; this.onPressPlay = this.onPressPlay.bind( this ); this.onLoad = this.onLoad.bind( this ); @@ -42,7 +43,7 @@ class Video extends Component { render() { const { isSelected, style } = this.props; - const { isLoaded } = this.state; + const { isLoaded, isFullScreen } = this.state; return ( @@ -58,6 +59,13 @@ class Video extends Component { onLoad={ this.onLoad } onLoadStart={ this.onLoadStart } ignoreSilentSwitch={ 'ignore' } + paused={ ! isFullScreen } + onFullscreenPlayerWillPresent={ () => { + this.setState( { isFullScreen: true } ); + } } + onFullscreenPlayerDidDismiss={ () => { + this.setState( { isFullScreen: false } ); + } } /> { isLoaded && From 0ccabeaa460521d85c3df59a8d8d422e689ff639 Mon Sep 17 00:00:00 2001 From: Seghir Nadir Date: Thu, 6 Jun 2019 11:39:26 +0100 Subject: [PATCH 056/132] Fix: When adding a button block, Button receives focus first #15859 (#15951) --- packages/block-library/src/button/edit.js | 4 +++ .../blocks/__snapshots__/button.test.js.snap | 13 ++++++++ .../e2e-tests/specs/blocks/button.test.js | 30 +++++++++++++++++++ 3 files changed, 47 insertions(+) create mode 100644 packages/e2e-tests/specs/blocks/__snapshots__/button.test.js.snap create mode 100644 packages/e2e-tests/specs/blocks/button.test.js diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 6d3f279542e009..142f9b0a06835f 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -130,6 +130,10 @@ class ButtonEdit extends Component { setAttributes( { url: value } ) } /> diff --git a/packages/e2e-tests/specs/blocks/__snapshots__/button.test.js.snap b/packages/e2e-tests/specs/blocks/__snapshots__/button.test.js.snap new file mode 100644 index 00000000000000..82fca76a8fb04d --- /dev/null +++ b/packages/e2e-tests/specs/blocks/__snapshots__/button.test.js.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Button can jump focus back & forth 1`] = ` +" + +" +`; + +exports[`Button has focus on button content 1`] = ` +" + +" +`; diff --git a/packages/e2e-tests/specs/blocks/button.test.js b/packages/e2e-tests/specs/blocks/button.test.js new file mode 100644 index 00000000000000..69343633f4247f --- /dev/null +++ b/packages/e2e-tests/specs/blocks/button.test.js @@ -0,0 +1,30 @@ +/** + * WordPress dependencies + */ +import { + insertBlock, + getEditedPostContent, + createNewPost, +} from '@wordpress/e2e-test-utils'; + +describe( 'Button', () => { + beforeEach( async () => { + await createNewPost(); + } ); + + it( 'has focus on button content', async () => { + await insertBlock( 'Button' ); + await page.keyboard.type( 'Content' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); + + it( 'can jump focus back & forth', async () => { + await insertBlock( 'Button' ); + await page.keyboard.type( 'WordPress' ); + await page.keyboard.press( 'Tab' ); + await page.keyboard.type( 'https://wordpress.org' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); +} ); From 768a13aa7cd21e50fa604671f4e2dc25a738de6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Est=C3=AAv=C3=A3o?= Date: Thu, 6 Jun 2019 11:41:42 +0100 Subject: [PATCH 057/132] Fix mobile quotes insertion and removal of empty lines (#16013) * Make sure selection is not over length of text. * Replicate web behaviour for onSplit detection. --- .../src/components/rich-text/index.native.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 92143f16b10697..d2d3df25b5f253 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -165,7 +165,7 @@ export class RichText extends Component { * @return {Object} A RichText value with formats and selection. */ createRecord() { - return { + const value = { start: this.selectionStart, end: this.selectionEnd, ...create( { @@ -175,6 +175,9 @@ export class RichText extends Component { multilineWrapperTags: this.multilineWrapperTags, } ), }; + const start = Math.min( this.selectionStart, value.text.length ); + const end = Math.min( this.selectionEnd, value.text.length ); + return { ...value, start, end }; } /** @@ -347,15 +350,15 @@ export class RichText extends Component { this.lastEventCount = event.nativeEvent.eventCount; this.comesFromAztec = true; this.firedAfterTextChanged = event.nativeEvent.firedAfterTextChanged; - + const { onReplace, onSplit } = this.props; + const canSplit = onReplace && onSplit; const currentRecord = this.createRecord(); - if ( this.multilineTag ) { if ( event.shiftKey ) { this.needsSelectionUpdate = true; const insertedLineBreak = { ...insert( currentRecord, '\n' ) }; this.onFormatChange( insertedLineBreak ); - } else if ( this.onSplit && isEmptyLine( currentRecord ) ) { + } else if ( canSplit && isEmptyLine( currentRecord ) ) { this.onSplit( currentRecord ); } else { this.needsSelectionUpdate = true; From 992ea0a9efcf53ae34f7ae5a7086ff9c6e4743ef Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 6 Jun 2019 12:10:03 +0100 Subject: [PATCH 058/132] Always show side inserter on the last empty paragraph (#15864) --- .../src/components/block-list/block.js | 45 ++++++++++--------- .../src/components/block-list/style.scss | 2 - .../default-block-appender/style.scss | 12 ----- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index a9b28f618daf5f..b9f3c02ed30ead 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -79,6 +79,7 @@ function BlockListBlock( { className, name, isValid, + isLast, attributes, initialPosition, wrapperProps, @@ -343,8 +344,8 @@ function BlockListBlock( { // If the block is selected and we're typing the block should not appear. // Empty paragraph blocks should always show up as unselected. - const showEmptyBlockSideInserter = - ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; + const showInserterShortcuts = ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; + const showEmptyBlockSideInserter = ( isSelected || isHovered || isLast ) && isEmptyDefaultBlock && isValid; const shouldAppearSelected = ! isFocusMode && ! showEmptyBlockSideInserter && @@ -538,24 +539,24 @@ function BlockListBlock( { { !! hasError && }
+ { showInserterShortcuts && ( +
+ +
+ ) } { showEmptyBlockSideInserter && ( - <> -
- -
-
- -
- +
+ +
) } ); @@ -580,6 +581,8 @@ const applyWithSelect = withSelect( getSettings, hasSelectedInnerBlock, getTemplateLock, + getBlockIndex, + getBlockOrder, __unstableGetBlockWithoutInnerBlocks, } = select( 'core/block-editor' ); const block = __unstableGetBlockWithoutInnerBlocks( clientId ); @@ -587,6 +590,8 @@ const applyWithSelect = withSelect( const { hasFixedToolbar, focusMode } = getSettings(); const templateLock = getTemplateLock( rootClientId ); const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true ); + const index = getBlockIndex( clientId, rootClientId ); + const blockOrder = getBlockOrder( rootClientId ); // The fallback to `{}` is a temporary fix. // This function should never be called when a block is not present in the state. @@ -611,6 +616,7 @@ const applyWithSelect = withSelect( isLocked: !! templateLock, isFocusMode: focusMode && isLargeViewport, hasFixedToolbar: hasFixedToolbar && isLargeViewport, + isLast: index === blockOrder.length - 1, // Users of the editor.BlockListBlock filter used to be able to access the block prop // Ideally these blocks would rely on the clientId prop only. @@ -637,7 +643,6 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, { select } ) => { mergeBlocks, replaceBlocks, toggleSelection, - } = dispatch( 'core/block-editor' ); return { diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index 4aaf4e3f2c4490..02df5d8e80068d 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -274,13 +274,11 @@ } // Appender - &.is-typing .block-editor-block-list__empty-block-inserter, &.is-typing .block-editor-block-list__side-inserter { opacity: 0; animation: none; } - .block-editor-block-list__empty-block-inserter, .block-editor-block-list__side-inserter { @include edit-post__fade-in-animation; } diff --git a/packages/block-editor/src/components/default-block-appender/style.scss b/packages/block-editor/src/components/default-block-appender/style.scss index 831b844627062b..6f6c28da6aa8c8 100644 --- a/packages/block-editor/src/components/default-block-appender/style.scss +++ b/packages/block-editor/src/components/default-block-appender/style.scss @@ -29,22 +29,10 @@ } } - // Don't show the inserter until mousing over. - .block-editor-inserter__toggle:not([aria-expanded="true"]) { - opacity: 0; - transition: opacity 0.2s; - @include reduce-motion("transition"); - will-change: opacity; - } - &:hover { .block-editor-inserter-with-shortcuts { @include edit-post__fade-in-animation; } - - .block-editor-inserter__toggle { - opacity: 1; - } } // Dropzone. From f4ad60845222ebdda50a7800f8ffc8ae64d32343 Mon Sep 17 00:00:00 2001 From: Joen Asmussen Date: Thu, 6 Jun 2019 13:16:52 +0200 Subject: [PATCH 059/132] Selecting Parent Blocks: Try clickthrough (#15537) * Selecting parents: Try clickthrough. Clickthrough has you select the parent before you can select the child. This is already in place on the mobile breakpoints, this just expands it to desktop as well. It is a work in progress, right now it is not working as intended: once you have "unlocked" the deepest level, it becomes immediately locked and you have to click through the layers again to unlock it again. The deepest layer should always be unlocked until you deselect all blocks again. * Render overlay on top of inner block only when none of the nested blocks is selected * Fix overlay, fix breadcrumb, polish. * Remove click-overlay. * Fix the selection of inner blocks for reusable blocks template * Disable async mode for parent blocks when nested block selected * Refactor BlockListBlock to use AsyncModeProvider * Make the reusable blocks save button clickable. i At least this means you can edit and save reusable blocks. * Fix so reusable blocks with nesting are editable. * Fix movers. The z-index was too low. It had to be higher to accommodate the other z-index changes. * Bring the behavior closer to what we have as of today --- assets/stylesheets/_z-index.scss | 17 ++++++++------ .../block-list/block-async-mode-provider.js | 23 +++++++++++++++++++ .../src/components/block-list/block.js | 5 +++- .../src/components/block-list/index.js | 8 ++++--- .../src/components/block-list/style.scss | 14 +++++++++++ .../src/components/inner-blocks/index.js | 12 ++++------ .../src/components/inner-blocks/style.scss | 18 ++++++++------- .../src/block/edit-panel/editor.scss | 4 ++++ .../block-library/src/columns/editor.scss | 18 ++++++--------- .../e2e-tests/specs/reusable-blocks.test.js | 12 ++++------ 10 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 packages/block-editor/src/components/block-list/block-async-mode-provider.js diff --git a/assets/stylesheets/_z-index.scss b/assets/stylesheets/_z-index.scss index 92a044a7b899a3..12f9b16de20037 100644 --- a/assets/stylesheets/_z-index.scss +++ b/assets/stylesheets/_z-index.scss @@ -9,7 +9,6 @@ $z-layers: ( ".block-library-classic__toolbar": 10, ".block-editor-block-list__layout .reusable-block-indicator": 1, ".block-editor-block-list__breadcrumb": 2, - ".editor-inner-blocks .block-editor-block-list__breadcrumb": 22, ".components-form-toggle__input": 1, ".components-panel__header.edit-post-sidebar__panel-tabs": -1, ".edit-post-sidebar .components-panel": -2, @@ -19,7 +18,6 @@ $z-layers: ( ".components-modal__header": 10, ".edit-post-meta-boxes-area.is-loading::before": 1, ".edit-post-meta-boxes-area .spinner": 5, - ".block-editor-block-contextual-toolbar": 21, ".components-popover__close": 5, ".block-editor-block-list__insertion-point": 6, ".block-editor-inserter-with-shortcuts": 5, @@ -51,16 +49,21 @@ $z-layers: ( ".components-drop-zone": 100, ".components-drop-zone__content": 110, - // The block mover, particularly in nested contexts, - // should overlap most block content. - ".block-editor-block-list__block.is-{selected,hovered} .block-editor-block-mover": 80, - // The block mover for floats should overlap the controls of adjacent blocks. ".block-editor-block-list__block {core/image aligned left or right}": 81, // Small screen inner blocks overlay must be displayed above drop zone, // settings menu, and movers. - ".block-editor-inner-blocks__small-screen-overlay:after": 120, + ".block-editor-inner-blocks.has-overlay::after": 120, + + // The toolbar, when contextual, should be above any adjacent nested block click overlays. + ".block-editor-block-list__layout .reusable-block-edit-panel": 121, + ".block-editor-block-contextual-toolbar": 121, + ".editor-inner-blocks .block-editor-block-list__breadcrumb": 122, + + // The block mover, particularly in nested contexts, + // should overlap most block content. + ".block-editor-block-list__block.is-{selected,hovered} .block-editor-block-mover": 121, // Show sidebar above wp-admin navigation bar for mobile viewports: // #wpadminbar { z-index: 99999 } diff --git a/packages/block-editor/src/components/block-list/block-async-mode-provider.js b/packages/block-editor/src/components/block-list/block-async-mode-provider.js new file mode 100644 index 00000000000000..aaa2e709db92c6 --- /dev/null +++ b/packages/block-editor/src/components/block-list/block-async-mode-provider.js @@ -0,0 +1,23 @@ +/** + * WordPress dependencies + */ +import { + __experimentalAsyncModeProvider as AsyncModeProvider, + useSelect, +} from '@wordpress/data'; + +const BlockAsyncModeProvider = ( { children, clientId, isBlockInSelection } ) => { + const isParentOfSelectedBlock = useSelect( ( select ) => { + return select( 'core/block-editor' ).hasSelectedInnerBlock( clientId, true ); + } ); + + const isSyncModeForced = isBlockInSelection || isParentOfSelectedBlock; + + return ( + + { children } + + ); +}; + +export default BlockAsyncModeProvider; diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index b9f3c02ed30ead..82a237625e6a77 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -23,7 +23,10 @@ import { } from '@wordpress/blocks'; import { KeyboardShortcuts, withFilters } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; -import { withDispatch, withSelect } from '@wordpress/data'; +import { + withDispatch, + withSelect, +} from '@wordpress/data'; import { withViewportMatch } from '@wordpress/viewport'; import { compose, pure } from '@wordpress/compose'; diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index 2da9071693d5fa..79cc1b29273375 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -24,6 +24,7 @@ import { compose } from '@wordpress/compose'; /** * Internal dependencies */ +import BlockAsyncModeProvider from './block-async-mode-provider'; import BlockListBlock from './block'; import BlockListAppender from '../block-list-appender'; import { getBlockDOMNode } from '../../utils/dom'; @@ -207,9 +208,10 @@ class BlockList extends Component { selectedBlockClientId === clientId; return ( - - + ); } ) } diff --git a/packages/block-editor/src/components/block-list/style.scss b/packages/block-editor/src/components/block-list/style.scss index 02df5d8e80068d..8ee3558ddf6398 100644 --- a/packages/block-editor/src/components/block-list/style.scss +++ b/packages/block-editor/src/components/block-list/style.scss @@ -303,6 +303,20 @@ } } + // Reusable Blocks clickthrough overlays + &.is-reusable > .block-editor-block-list__block-edit .block-editor-inner-blocks.has-overlay { + // Remove only the top click overlay. + &::after { + display: none; + } + + // Restore it for subsequent. + .block-editor-inner-blocks.has-overlay::after { + display: block; + } + } + + // Alignments &[data-align="left"], &[data-align="right"] { diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index 2a69e5305fc3fa..75a6731f42db57 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -7,7 +7,6 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { withViewportMatch } from '@wordpress/viewport'; import { Component } from '@wordpress/element'; import { withSelect, withDispatch } from '@wordpress/data'; import { synchronizeBlocksWithTemplate, withBlockContentContext } from '@wordpress/blocks'; @@ -106,14 +105,13 @@ class InnerBlocks extends Component { render() { const { clientId, - isSmallScreen, - isSelectedBlockInRoot, + hasOverlay, renderAppender, } = this.props; const { templateInProcess } = this.state; const classes = classnames( 'editor-inner-blocks block-editor-inner-blocks', { - 'has-overlay': isSmallScreen && ! isSelectedBlockInRoot, + 'has-overlay': hasOverlay, } ); return ( @@ -131,7 +129,6 @@ class InnerBlocks extends Component { InnerBlocks = compose( [ withBlockEditContext( ( context ) => pick( context, [ 'clientId' ] ) ), - withViewportMatch( { isSmallScreen: '< medium' } ), withSelect( ( select, ownProps ) => { const { isBlockSelected, @@ -142,12 +139,13 @@ InnerBlocks = compose( [ getTemplateLock, } = select( 'core/block-editor' ); const { clientId } = ownProps; + const block = getBlock( clientId ); const rootClientId = getBlockRootClientId( clientId ); return { - isSelectedBlockInRoot: isBlockSelected( clientId ) || hasSelectedInnerBlock( clientId ), - block: getBlock( clientId ), + block, blockListSettings: getBlockListSettings( clientId ), + hasOverlay: block.name !== 'core/template' && ! isBlockSelected( clientId ) && ! hasSelectedInnerBlock( clientId, true ), parentLock: getTemplateLock( rootClientId ), }; } ), diff --git a/packages/block-editor/src/components/inner-blocks/style.scss b/packages/block-editor/src/components/inner-blocks/style.scss index f4218ef0667ebe..61ed91c42ac02f 100644 --- a/packages/block-editor/src/components/inner-blocks/style.scss +++ b/packages/block-editor/src/components/inner-blocks/style.scss @@ -1,9 +1,11 @@ -.block-editor-inner-blocks.has-overlay::after { - content: ""; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: z-index(".block-editor-inner-blocks__small-screen-overlay:after"); +.block-editor-inner-blocks.has-overlay { + &::after { + content: ""; + position: absolute; + top: -$block-padding; + right: -$block-padding; + bottom: -$block-padding; + left: -$block-padding; + z-index: z-index(".block-editor-inner-blocks.has-overlay::after"); + } } diff --git a/packages/block-library/src/block/edit-panel/editor.scss b/packages/block-library/src/block/edit-panel/editor.scss index 6c11e19d5e227c..d5b5c81fd7e714 100644 --- a/packages/block-library/src/block/edit-panel/editor.scss +++ b/packages/block-library/src/block/edit-panel/editor.scss @@ -11,6 +11,10 @@ margin: 0 (-$block-padding); padding: $grid-size $block-padding; + // Elevate the reusable blocks toolbar above the clickthrough overlay. + position: relative; + z-index: z-index(".block-editor-block-list__layout .reusable-block-edit-panel"); + // Use opacity to work in various editor styles. border: $border-width dashed $dark-opacity-light-500; border-bottom: none; diff --git a/packages/block-library/src/columns/editor.scss b/packages/block-library/src/columns/editor.scss index c771c79f5f9d3c..f8780b91ebab53 100644 --- a/packages/block-library/src/columns/editor.scss +++ b/packages/block-library/src/columns/editor.scss @@ -164,17 +164,13 @@ div.block-core-columns.is-vertically-aligned-bottom { */ [data-type="core/column"] > .editor-block-list__block-edit > .editor-block-list__breadcrumb { right: 0; + left: auto; } -// The empty state of a columns block has the default appenders. -// Since those appenders are not blocks, the parent, actual block, appears "hovered" when hovering the appenders. -// Because the column shouldn't be hovered as part of this temporary passthrough, we unset the hover style. -.wp-block-columns [data-type="core/column"].is-hovered { - > .block-editor-block-list__block-edit::before { - content: none; - } - - .block-editor-block-list__breadcrumb { - display: none; - } +/** + * Make single Column overlay not extend past boundaries of parent + */ +.block-core-columns > .block-editor-inner-blocks.has-overlay::after { + left: 0; + right: 0; } diff --git a/packages/e2e-tests/specs/reusable-blocks.test.js b/packages/e2e-tests/specs/reusable-blocks.test.js index 7a9174f5b6246a..1eb25f41735e11 100644 --- a/packages/e2e-tests/specs/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/reusable-blocks.test.js @@ -45,10 +45,8 @@ describe( 'Reusable Blocks', () => { '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' ); - // Select all of the text in the title field by triple-clicking on it. We - // triple-click because, on Mac, Mod+A doesn't work. This step can be removed - // when https://github.com/WordPress/gutenberg/issues/7972 is fixed - await page.click( '.reusable-block-edit-panel__title', { clickCount: 3 } ); + // Select all of the text in the title field. + await pressKeyWithModifier( 'primary', 'a' ); // Give the reusable block a title await page.keyboard.type( 'Greeting block' ); @@ -223,10 +221,8 @@ describe( 'Reusable Blocks', () => { '//*[contains(@class, "components-snackbar")]/*[text()="Block created."]' ); - // Select all of the text in the title field by triple-clicking on it. We - // triple-click because, on Mac, Mod+A doesn't work. This step can be removed - // when https://github.com/WordPress/gutenberg/issues/7972 is fixed - await page.click( '.reusable-block-edit-panel__title', { clickCount: 3 } ); + // Select all of the text in the title field. + await pressKeyWithModifier( 'primary', 'a' ); // Give the reusable block a title await page.keyboard.type( 'Multi-selection reusable block' ); From ccc65f84c7d557cc7990ae050f20a4ba49ce72a0 Mon Sep 17 00:00:00 2001 From: Tugdual de Kerviler Date: Thu, 6 Jun 2019 14:13:34 +0200 Subject: [PATCH 060/132] [Mobile] Move unselected block accessibility handling to block-holder (v2) (#15225) * Update paragraph block accessibility label * Move block unselected state accessibility handling to block-holder * Add getAccessibilityLabel to block settings * Rename getAccessibilityLabel into __experimentalGetAccessibilityLabel * Make __experimentalGetAccessibilityLabel only available for native mobile * Handle not alt and a caption case * Handle no caption case * Fix merge mistake in prop names * Handle setting UnrecognizedBlock accessibility label in BlockHolder * Fix lint errors --- .../block-library/src/heading/edit.native.js | 129 +++++++----------- .../block-library/src/heading/index.native.js | 39 ++++++ .../block-library/src/image/edit.native.js | 7 - .../block-library/src/image/index.native.js | 30 ++++ .../block-library/src/missing/edit.native.js | 17 +-- .../src/paragraph/edit.native.js | 27 +--- .../src/paragraph/index.native.js | 28 ++++ 7 files changed, 149 insertions(+), 128 deletions(-) create mode 100644 packages/block-library/src/heading/index.native.js create mode 100644 packages/block-library/src/image/index.native.js create mode 100644 packages/block-library/src/paragraph/index.native.js diff --git a/packages/block-library/src/heading/edit.native.js b/packages/block-library/src/heading/edit.native.js index 97d2228346466a..e7d295402c92e1 100644 --- a/packages/block-library/src/heading/edit.native.js +++ b/packages/block-library/src/heading/edit.native.js @@ -8,94 +8,61 @@ import styles from './editor.scss'; * External dependencies */ import { View } from 'react-native'; -import { isEmpty } from 'lodash'; /** * WordPress dependencies */ -import { __, sprintf } from '@wordpress/i18n'; -import { Component } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; import { RichText, BlockControls } from '@wordpress/block-editor'; import { createBlock } from '@wordpress/blocks'; -import { create } from '@wordpress/rich-text'; -class HeadingEdit extends Component { - plainTextContent( html ) { - const result = create( { html } ); - if ( result ) { - return result.text; - } - return ''; - } - - render() { - const { - attributes, - setAttributes, - mergeBlocks, - style, - onReplace, - } = this.props; - - const { - level, - placeholder, - content, - } = attributes; - - const tagName = 'h' + level; - - return ( - ( + + + setAttributes( { level: newLevel } ) } + /> + + setAttributes( { content: value } ) } + onMerge={ mergeBlocks } + onSplit={ ( value ) => { + if ( ! value ) { + return createBlock( 'core/paragraph' ); } - onAccessibilityTap={ this.props.onFocus } - > - - setAttributes( { level: newLevel } ) } /> - - setAttributes( { content: value } ) } - onMerge={ mergeBlocks } - onSplit={ ( value ) => { - if ( ! value ) { - return createBlock( 'core/paragraph' ); - } - return createBlock( 'core/heading', { - ...attributes, - content: value, - } ); - } } - onReplace={ onReplace } - onRemove={ () => onReplace( [] ) } - placeholder={ placeholder || __( 'Write heading…' ) } - /> - - ); - } -} + return createBlock( 'core/heading', { + ...attributes, + content: value, + } ); + } } + onReplace={ onReplace } + onRemove={ () => onReplace( [] ) } + placeholder={ attributes.placeholder || __( 'Write heading…' ) } + /> + +); + export default HeadingEdit; diff --git a/packages/block-library/src/heading/index.native.js b/packages/block-library/src/heading/index.native.js new file mode 100644 index 00000000000000..67a6d2d91ded01 --- /dev/null +++ b/packages/block-library/src/heading/index.native.js @@ -0,0 +1,39 @@ +/** + * External dependencies + */ +import { isEmpty } from 'lodash'; + +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { create } from '@wordpress/rich-text'; + +/** + * Internal dependencies + */ +import { settings as webSettings } from './index.js'; + +export { metadata, name } from './index.js'; + +export const settings = { + ...webSettings, + __experimentalGetAccessibilityLabel( attributes ) { + const { content, level } = attributes; + + const plainTextContent = ( html ) => create( { html } ).text || ''; + + return isEmpty( content ) ? + sprintf( + /* translators: accessibility text. %s: heading level. */ + __( 'Level %s. Empty.' ), + level + ) : + sprintf( + /* translators: accessibility text. 1: heading level. 2: heading content. */ + __( 'Level %1$s. %2$s' ), + level, + plainTextContent( content ) + ); + }, +}; diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 479f82a2df7754..61a0adf3635ce2 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -274,13 +274,6 @@ class ImageEdit extends React.Component { const getImageComponent = ( openMediaOptions, getMediaOptions ) => ( + { title } diff --git a/packages/block-library/src/paragraph/edit.native.js b/packages/block-library/src/paragraph/edit.native.js index a97885c213c3a0..717677658e5a15 100644 --- a/packages/block-library/src/paragraph/edit.native.js +++ b/packages/block-library/src/paragraph/edit.native.js @@ -2,16 +2,14 @@ * External dependencies */ import { View } from 'react-native'; -import { isEmpty } from 'lodash'; /** * WordPress dependencies */ -import { __, sprintf } from '@wordpress/i18n'; +import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { createBlock } from '@wordpress/blocks'; import { RichText } from '@wordpress/block-editor'; -import { create } from '@wordpress/rich-text'; /** * Internal dependencies @@ -39,14 +37,6 @@ class ParagraphEdit extends Component { ) ) ); } - plainTextContent( html ) { - const result = create( { html } ); - if ( result ) { - return result.text; - } - return ''; - } - render() { const { attributes, @@ -62,20 +52,7 @@ class ParagraphEdit extends Component { } = attributes; return ( - + create( { html } ).text || ''; + + return isEmpty( content ) ? __( 'Empty' ) : plainTextContent( content ); + }, +}; From e019b5520c56b103a86fa0f2c0ef88dd1db60cfe Mon Sep 17 00:00:00 2001 From: etoledom Date: Thu, 6 Jun 2019 16:04:14 +0200 Subject: [PATCH 061/132] [Mobile] Modified More block to be read-only (#16005) * Update More block to be read-only. Copying style from Page Break block * Using sans-serif on more and nextpage blocks * Extend borders of HR component on more and nextpage blocks * Update accessibility configuration of More block --- .../block-library/src/more/edit.native.js | 62 +++---------------- .../block-library/src/more/editor.native.scss | 18 ++---- .../block-library/src/more/index.native.js | 13 ++++ .../block-library/src/nextpage/edit.native.js | 2 + .../src/nextpage/editor.native.scss | 1 - 5 files changed, 29 insertions(+), 67 deletions(-) create mode 100644 packages/block-library/src/more/index.native.js diff --git a/packages/block-library/src/more/edit.native.js b/packages/block-library/src/more/edit.native.js index e6d519c26b3042..8b369284cb5962 100644 --- a/packages/block-library/src/more/edit.native.js +++ b/packages/block-library/src/more/edit.native.js @@ -2,85 +2,43 @@ * External dependencies */ import { View } from 'react-native'; +import Hr from 'react-native-hr'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; -import { - getDefaultBlockName, - createBlock, -} from '@wordpress/blocks'; /** * Internal dependencies */ -import { PlainText } from '@wordpress/block-editor'; import styles from './editor.scss'; export default class MoreEdit extends Component { constructor() { super( ...arguments ); - this.onChangeInput = this.onChangeInput.bind( this ); this.state = { defaultText: __( 'Read more' ), }; } - onChangeInput( newValue ) { - // Detect Enter.key and add new empty block after. - // Note: This is detected after the fact, and the newline could be visible on the block - // for a very small time. This is OK for the alpha, we will revisit the logic later. - // See https://github.com/wordpress-mobile/gutenberg-mobile/issues/324 - if ( newValue.indexOf( '\n' ) !== -1 ) { - const { insertBlocksAfter } = this.props; - insertBlocksAfter( [ createBlock( getDefaultBlockName() ) ] ); - return; - } - // Set defaultText to an empty string, allowing the user to clear/replace the input field's text - this.setState( { - defaultText: '', - } ); - const value = newValue.length === 0 ? undefined : newValue; - this.props.setAttributes( { customText: value } ); - } - - renderLine() { - return ; - } - - renderText() { - const { attributes, onFocus, onBlur } = this.props; - const { customText } = attributes; + render() { + const { customText } = this.props.attributes; const { defaultText } = this.state; - const value = customText !== undefined ? customText : defaultText; + const content = customText || defaultText; return ( - </View> ); } - - render() { - return ( - <View style={ styles[ 'block-library-more__container' ] }> - { this.renderLine() } - { this.renderText() } - { this.renderLine() } - </View> - ); - } } diff --git a/packages/block-library/src/more/editor.native.scss b/packages/block-library/src/more/editor.native.scss index beb5ef423776ff..eb4a1d60d9431f 100644 --- a/packages/block-library/src/more/editor.native.scss +++ b/packages/block-library/src/more/editor.native.scss @@ -1,23 +1,13 @@ // @format -.block-library-more__container { - align-items: center; - padding: 4px; - flex-direction: row; -} - .block-library-more__line { - background-color: #555d66; + background-color: $gray-lighten-20; height: 2; - flex: 1; } .block-library-more__text { + color: $gray; text-decoration-style: solid; - flex: 0; - width: 200; - text-align: center; - margin-left: 15; - margin-right: 15; - margin-bottom: 5; + text-transform: uppercase; } + diff --git a/packages/block-library/src/more/index.native.js b/packages/block-library/src/more/index.native.js new file mode 100644 index 00000000000000..1525b6694abe52 --- /dev/null +++ b/packages/block-library/src/more/index.native.js @@ -0,0 +1,13 @@ +/** + * Internal dependencies + */ +import { settings as webSettings } from './index.js'; + +export { metadata, name } from './index.js'; + +export const settings = { + ...webSettings, + __experimentalGetAccessibilityLabel( attributes ) { + return attributes.customText; + }, +}; diff --git a/packages/block-library/src/nextpage/edit.native.js b/packages/block-library/src/nextpage/edit.native.js index ae887204538769..e3aa69b15e5e41 100644 --- a/packages/block-library/src/nextpage/edit.native.js +++ b/packages/block-library/src/nextpage/edit.native.js @@ -33,6 +33,8 @@ export default function NextPageEdit( { attributes, isSelected, onFocus } ) { onAccessibilityTap={ onFocus } > <Hr text={ customText } + marginLeft={ 0 } + marginRight={ 0 } textStyle={ styles[ 'block-library-nextpage__text' ] } lineStyle={ styles[ 'block-library-nextpage__line' ] } /> </View> diff --git a/packages/block-library/src/nextpage/editor.native.scss b/packages/block-library/src/nextpage/editor.native.scss index ae6f1f3788df3b..869851fdd37c63 100644 --- a/packages/block-library/src/nextpage/editor.native.scss +++ b/packages/block-library/src/nextpage/editor.native.scss @@ -7,7 +7,6 @@ .block-library-nextpage__text { color: $gray; - font-family: $default-regular-font; text-decoration-style: solid; text-transform: uppercase; } From 9343c0c964ddd12aec07f652d836cb3d20a08f9f Mon Sep 17 00:00:00 2001 From: etoledom <etoledom@icloud.com> Date: Thu, 6 Jun 2019 17:55:16 +0200 Subject: [PATCH 062/132] Remove a call to a removed function. (#16018) This function is not needed anymore since selection is handed in the store --- packages/block-editor/src/components/rich-text/index.native.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index d2d3df25b5f253..1430702991dbdd 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -396,7 +396,6 @@ export class RichText extends Component { if ( start === 0 && end !== 0 && end >= value.text.length ) { newValue = remove( value, start, end ); this.props.onChange( newValue ); - this.forceSelectionUpdate( 0, 0 ); return; } From 010a6be42bdc0caa2a2631885d485e75dabbe902 Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Thu, 6 Jun 2019 18:27:01 +0100 Subject: [PATCH 063/132] Refactor the hovered area component to a hook (#15038) --- .../src/components/block-list/block.js | 461 +++++++++--------- .../src/components/block-list/hover-area.js | 99 ++-- 2 files changed, 259 insertions(+), 301 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 82a237625e6a77..aac68e2e6faa88 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -48,7 +48,7 @@ import BlockInsertionPoint from './insertion-point'; import IgnoreNestedEvents from '../ignore-nested-events'; import InserterWithShortcuts from '../inserter-with-shortcuts'; import Inserter from '../inserter'; -import HoverArea from './hover-area'; +import useHoveredArea from './hover-area'; import { isInsideRootBlock } from '../../utils/dom'; /** @@ -79,6 +79,7 @@ function BlockListBlock( { isParentOfSelectedBlock, isDraggable, isSelectionEnabled, + isRTL, className, name, isValid, @@ -105,13 +106,14 @@ function BlockListBlock( { const wrapper = useRef( null ); useEffect( () => { blockRef( wrapper.current, clientId ); - // We need to rerender to trigger a rerendering of HoverArea. - rerender(); }, [] ); // Reference to the block edit node const blockNodeRef = useRef(); + // Hovered area of the block + const hoverArea = useHoveredArea( wrapper ); + // Keep track of touchstart to disable hover on iOS const hadTouchStart = useRef( false ); const onTouchStart = () => { @@ -333,240 +335,236 @@ function BlockListBlock( { } }; + // Rendering the output + const isHovered = isBlockHovered && ! isPartOfMultiSelection; + const blockType = getBlockType( name ); + // translators: %s: Type of block (i.e. Text, Image etc) + const blockLabel = sprintf( __( 'Block: %s' ), blockType.title ); + // The block as rendered in the editor is composed of general block UI + // (mover, toolbar, wrapper) and the display of the block content. + + const isUnregisteredBlock = name === getUnregisteredTypeHandlerName(); + + // If the block is selected and we're typing the block should not appear. + // Empty paragraph blocks should always show up as unselected. + const showInserterShortcuts = ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; + const showEmptyBlockSideInserter = ( isSelected || isHovered || isLast ) && isEmptyDefaultBlock && isValid; + const shouldAppearSelected = + ! isFocusMode && + ! showEmptyBlockSideInserter && + isSelected && + ! isTypingWithinBlock; + const shouldAppearHovered = + ! isFocusMode && + ! hasFixedToolbar && + isHovered && + ! isEmptyDefaultBlock; + // We render block movers and block settings to keep them tabbale even if hidden + const shouldRenderMovers = + ( isSelected || hoverArea === ( isRTL ? 'right' : 'left' ) ) && + ! showEmptyBlockSideInserter && + ! isPartOfMultiSelection && + ! isTypingWithinBlock; + const shouldShowBreadcrumb = + ! isFocusMode && isHovered && ! isEmptyDefaultBlock; + const shouldShowContextualToolbar = + ! hasFixedToolbar && + ! showEmptyBlockSideInserter && + ( + ( isSelected && ( ! isTypingWithinBlock || isCaretWithinFormattedText ) ) || + isFirstMultiSelected + ); + const shouldShowMobileToolbar = shouldAppearSelected; + + // Insertion point can only be made visible if the block is at the + // the extent of a multi-selection, or not in a multi-selection. + const shouldShowInsertionPoint = + ( isPartOfMultiSelection && isFirstMultiSelected ) || + ! isPartOfMultiSelection; + + // The wp-block className is important for editor styles. + // Generate the wrapper class names handling the different states of the block. + const wrapperClassName = classnames( + 'wp-block editor-block-list__block block-editor-block-list__block', + { + 'has-warning': ! isValid || !! hasError || isUnregisteredBlock, + 'is-selected': shouldAppearSelected, + 'is-multi-selected': isPartOfMultiSelection, + 'is-hovered': shouldAppearHovered, + 'is-reusable': isReusableBlock( blockType ), + 'is-dragging': isDragging, + 'is-typing': isTypingWithinBlock, + 'is-focused': isFocusMode && ( isSelected || isParentOfSelectedBlock ), + 'is-focus-mode': isFocusMode, + }, + className + ); + + // Determine whether the block has props to apply to the wrapper. + let blockWrapperProps = wrapperProps; + if ( blockType.getEditWrapperProps ) { + blockWrapperProps = { + ...blockWrapperProps, + ...blockType.getEditWrapperProps( attributes ), + }; + } + const blockElementId = `block-${ clientId }`; + + // We wrap the BlockEdit component in a div that hides it when editing in + // HTML mode. This allows us to render all of the ancillary pieces + // (InspectorControls, etc.) which are inside `BlockEdit` but not + // `BlockHTML`, even in HTML mode. + let blockEdit = ( + <BlockEdit + name={ name } + isSelected={ isSelected } + attributes={ attributes } + setAttributes={ setAttributes } + insertBlocksAfter={ isLocked ? undefined : onInsertBlocksAfter } + onReplace={ isLocked ? undefined : onReplace } + mergeBlocks={ isLocked ? undefined : onMerge } + clientId={ clientId } + isSelectionEnabled={ isSelectionEnabled } + toggleSelection={ toggleSelection } + /> + ); + if ( mode !== 'visual' ) { + blockEdit = <div style={ { display: 'none' } }>{ blockEdit }</div>; + } + + // Disable reasons: + // + // jsx-a11y/mouse-events-have-key-events: + // - onMouseOver is explicitly handling hover effects + // + // jsx-a11y/no-static-element-interactions: + // - Each block can be selected by clicking on it + + /* eslint-disable jsx-a11y/mouse-events-have-key-events, jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ + return ( - <HoverArea container={ wrapper.current }> - { ( { hoverArea } ) => { - const isHovered = isBlockHovered && ! isPartOfMultiSelection; - const blockType = getBlockType( name ); - // translators: %s: Type of block (i.e. Text, Image etc) - const blockLabel = sprintf( __( 'Block: %s' ), blockType.title ); - // The block as rendered in the editor is composed of general block UI - // (mover, toolbar, wrapper) and the display of the block content. - - const isUnregisteredBlock = name === getUnregisteredTypeHandlerName(); - - // If the block is selected and we're typing the block should not appear. - // Empty paragraph blocks should always show up as unselected. - const showInserterShortcuts = ( isSelected || isHovered ) && isEmptyDefaultBlock && isValid; - const showEmptyBlockSideInserter = ( isSelected || isHovered || isLast ) && isEmptyDefaultBlock && isValid; - const shouldAppearSelected = - ! isFocusMode && - ! showEmptyBlockSideInserter && + <IgnoreNestedEvents + id={ blockElementId } + ref={ wrapper } + onMouseOver={ maybeHover } + onMouseOverHandled={ hideHoverEffects } + onMouseLeave={ hideHoverEffects } + className={ wrapperClassName } + data-type={ name } + onTouchStart={ onTouchStart } + onFocus={ onFocus } + onClick={ onTouchStop } + onKeyDown={ deleteOrInsertAfterWrapper } + tabIndex="0" + aria-label={ blockLabel } + childHandledEvents={ [ 'onDragStart', 'onMouseDown' ] } + { ...blockWrapperProps } + > + { shouldShowInsertionPoint && ( + <BlockInsertionPoint + clientId={ clientId } + rootClientId={ rootClientId } + /> + ) } + <BlockDropZone + clientId={ clientId } + rootClientId={ rootClientId } + /> + { isFirstMultiSelected && ( + <BlockMultiControls rootClientId={ rootClientId } /> + ) } + <div className="editor-block-list__block-edit block-editor-block-list__block-edit"> + { shouldRenderMovers && ( + <BlockMover + clientIds={ clientId } + blockElementId={ blockElementId } + isHidden={ ! ( isHovered || isSelected ) || hoverArea !== ( isRTL ? 'right' : 'left' ) } + isDraggable={ + isDraggable !== false && + ( ! isPartOfMultiSelection && isMovable ) + } + onDragStart={ onDragStart } + onDragEnd={ onDragEnd } + /> + ) } + { shouldShowBreadcrumb && ( + <BlockBreadcrumb + clientId={ clientId } + isHidden={ + ! ( isHovered || isSelected ) || hoverArea !== ( isRTL ? 'right' : 'left' ) + } + /> + ) } + { ( shouldShowContextualToolbar || isForcingContextualToolbar.current ) && ( + <BlockContextualToolbar + // If the toolbar is being shown because of being forced + // it should focus the toolbar right after the mount. + focusOnMount={ isForcingContextualToolbar.current } + /> + ) } + { + ! shouldShowContextualToolbar && isSelected && - ! isTypingWithinBlock; - const shouldAppearHovered = - ! isFocusMode && - ! hasFixedToolbar && - isHovered && - ! isEmptyDefaultBlock; - // We render block movers and block settings to keep them tabbale even if hidden - const shouldRenderMovers = - ( isSelected || hoverArea === 'left' ) && - ! showEmptyBlockSideInserter && - ! isPartOfMultiSelection && - ! isTypingWithinBlock; - const shouldShowBreadcrumb = - ! isFocusMode && isHovered && ! isEmptyDefaultBlock; - const shouldShowContextualToolbar = ! hasFixedToolbar && - ! showEmptyBlockSideInserter && - ( ( isSelected && - ( ! isTypingWithinBlock || isCaretWithinFormattedText ) ) || - isFirstMultiSelected ); - const shouldShowMobileToolbar = shouldAppearSelected; - - // Insertion point can only be made visible if the block is at the - // the extent of a multi-selection, or not in a multi-selection. - const shouldShowInsertionPoint = - ( isPartOfMultiSelection && isFirstMultiSelected ) || - ! isPartOfMultiSelection; - - // The wp-block className is important for editor styles. - // Generate the wrapper class names handling the different states of the block. - const wrapperClassName = classnames( - 'wp-block editor-block-list__block block-editor-block-list__block', - { - 'has-warning': ! isValid || !! hasError || isUnregisteredBlock, - 'is-selected': shouldAppearSelected, - 'is-multi-selected': isPartOfMultiSelection, - 'is-hovered': shouldAppearHovered, - 'is-reusable': isReusableBlock( blockType ), - 'is-dragging': isDragging, - 'is-typing': isTypingWithinBlock, - 'is-focused': - isFocusMode && ( isSelected || isParentOfSelectedBlock ), - 'is-focus-mode': isFocusMode, - }, - className - ); - - // Determine whether the block has props to apply to the wrapper. - let blockWrapperProps = wrapperProps; - if ( blockType.getEditWrapperProps ) { - blockWrapperProps = { - ...blockWrapperProps, - ...blockType.getEditWrapperProps( attributes ), - }; + ! isEmptyDefaultBlock && ( + <KeyboardShortcuts + bindGlobal + eventName="keydown" + shortcuts={ { + 'alt+f10': forceFocusedContextualToolbar, + } } + /> + ) } - const blockElementId = `block-${ clientId }`; - - // We wrap the BlockEdit component in a div that hides it when editing in - // HTML mode. This allows us to render all of the ancillary pieces - // (InspectorControls, etc.) which are inside `BlockEdit` but not - // `BlockHTML`, even in HTML mode. - let blockEdit = ( - <BlockEdit - name={ name } - isSelected={ isSelected } - attributes={ attributes } - setAttributes={ setAttributes } - insertBlocksAfter={ isLocked ? undefined : onInsertBlocksAfter } - onReplace={ isLocked ? undefined : onReplace } - mergeBlocks={ isLocked ? undefined : onMerge } + <IgnoreNestedEvents + ref={ blockNodeRef } + onDragStart={ preventDrag } + onMouseDown={ onPointerDown } + data-block={ clientId } + > + <BlockCrashBoundary onError={ onBlockError }> + { isValid && blockEdit } + { isValid && mode === 'html' && ( + <BlockHtml clientId={ clientId } /> + ) } + { ! isValid && [ + <BlockInvalidWarning + key="invalid-warning" + clientId={ clientId } + />, + <div key="invalid-preview"> + { getSaveElement( blockType, attributes ) } + </div>, + ] } + </BlockCrashBoundary> + { shouldShowMobileToolbar && ( + <BlockMobileToolbar clientId={ clientId } /> + ) } + { !! hasError && <BlockCrashWarning /> } + </IgnoreNestedEvents> + </div> + { showInserterShortcuts && ( + <div className="editor-block-list__side-inserter block-editor-block-list__side-inserter"> + <InserterWithShortcuts clientId={ clientId } - isSelectionEnabled={ isSelectionEnabled } - toggleSelection={ toggleSelection } + rootClientId={ rootClientId } + onToggle={ selectOnOpen } /> - ); - if ( mode !== 'visual' ) { - blockEdit = <div style={ { display: 'none' } }>{ blockEdit }</div>; - } - - // Disable reasons: - // - // jsx-a11y/mouse-events-have-key-events: - // - onMouseOver is explicitly handling hover effects - // - // jsx-a11y/no-static-element-interactions: - // - Each block can be selected by clicking on it - - /* eslint-disable jsx-a11y/mouse-events-have-key-events, jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ - - return ( - <IgnoreNestedEvents - id={ blockElementId } - ref={ wrapper } - onMouseOver={ maybeHover } - onMouseOverHandled={ hideHoverEffects } - onMouseLeave={ hideHoverEffects } - className={ wrapperClassName } - data-type={ name } - onTouchStart={ onTouchStart } - onFocus={ onFocus } - onClick={ onTouchStop } - onKeyDown={ deleteOrInsertAfterWrapper } - tabIndex="0" - aria-label={ blockLabel } - childHandledEvents={ [ 'onDragStart', 'onMouseDown' ] } - { ...blockWrapperProps } - > - { shouldShowInsertionPoint && ( - <BlockInsertionPoint - clientId={ clientId } - rootClientId={ rootClientId } - /> - ) } - <BlockDropZone - clientId={ clientId } - rootClientId={ rootClientId } - /> - { isFirstMultiSelected && ( - <BlockMultiControls rootClientId={ rootClientId } /> - ) } - <div className="editor-block-list__block-edit block-editor-block-list__block-edit"> - { shouldRenderMovers && ( - <BlockMover - clientIds={ clientId } - blockElementId={ blockElementId } - isHidden={ ! ( isHovered || isSelected ) || hoverArea !== 'left' } - isDraggable={ - isDraggable !== false && - ( ! isPartOfMultiSelection && isMovable ) - } - onDragStart={ onDragStart } - onDragEnd={ onDragEnd } - /> - ) } - { shouldShowBreadcrumb && ( - <BlockBreadcrumb - clientId={ clientId } - isHidden={ - ! ( isHovered || isSelected ) || hoverArea !== 'left' - } - /> - ) } - { ( shouldShowContextualToolbar || - isForcingContextualToolbar.current ) && ( - <BlockContextualToolbar - // If the toolbar is being shown because of being forced - // it should focus the toolbar right after the mount. - focusOnMount={ isForcingContextualToolbar.current } - /> - ) } - { ! shouldShowContextualToolbar && - isSelected && - ! hasFixedToolbar && - ! isEmptyDefaultBlock && ( - <KeyboardShortcuts - bindGlobal - eventName="keydown" - shortcuts={ { - 'alt+f10': forceFocusedContextualToolbar, - } } - /> - ) } - <IgnoreNestedEvents - ref={ blockNodeRef } - onDragStart={ preventDrag } - onMouseDown={ onPointerDown } - data-block={ clientId } - > - <BlockCrashBoundary onError={ onBlockError }> - { isValid && blockEdit } - { isValid && mode === 'html' && ( - <BlockHtml clientId={ clientId } /> - ) } - { ! isValid && [ - <BlockInvalidWarning - key="invalid-warning" - clientId={ clientId } - />, - <div key="invalid-preview"> - { getSaveElement( blockType, attributes ) } - </div>, - ] } - </BlockCrashBoundary> - { shouldShowMobileToolbar && ( - <BlockMobileToolbar clientId={ clientId } /> - ) } - { !! hasError && <BlockCrashWarning /> } - </IgnoreNestedEvents> - </div> - { showInserterShortcuts && ( - <div className="editor-block-list__side-inserter block-editor-block-list__side-inserter"> - <InserterWithShortcuts - clientId={ clientId } - rootClientId={ rootClientId } - onToggle={ selectOnOpen } - /> - </div> - ) } - { showEmptyBlockSideInserter && ( - <div className="editor-block-list__empty-block-inserter block-editor-block-list__empty-block-inserter"> - <Inserter - position="top right" - onToggle={ selectOnOpen } - rootClientId={ rootClientId } - clientId={ clientId } - /> - </div> - ) } - </IgnoreNestedEvents> - ); - /* eslint-enable jsx-a11y/mouse-events-have-key-events, jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ - } } - </HoverArea> + </div> + ) } + { showEmptyBlockSideInserter && ( + <div className="editor-block-list__empty-block-inserter block-editor-block-list__empty-block-inserter"> + <Inserter + position="top right" + onToggle={ selectOnOpen } + rootClientId={ rootClientId } + clientId={ clientId } + /> + </div> + ) } + </IgnoreNestedEvents> ); + /* eslint-enable jsx-a11y/mouse-events-have-key-events, jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ } const applyWithSelect = withSelect( @@ -590,7 +588,7 @@ const applyWithSelect = withSelect( } = select( 'core/block-editor' ); const block = __unstableGetBlockWithoutInnerBlocks( clientId ); const isSelected = isBlockSelected( clientId ); - const { hasFixedToolbar, focusMode } = getSettings(); + const { hasFixedToolbar, focusMode, isRTL } = getSettings(); const templateLock = getTemplateLock( rootClientId ); const isParentOfSelectedBlock = hasSelectedInnerBlock( clientId, true ); const index = getBlockIndex( clientId, rootClientId ); @@ -620,6 +618,7 @@ const applyWithSelect = withSelect( isFocusMode: focusMode && isLargeViewport, hasFixedToolbar: hasFixedToolbar && isLargeViewport, isLast: index === blockOrder.length - 1, + isRTL, // Users of the editor.BlockListBlock filter used to be able to access the block prop // Ideally these blocks would rely on the clientId prop only. diff --git a/packages/block-editor/src/components/block-list/hover-area.js b/packages/block-editor/src/components/block-list/hover-area.js index a79b0bcd9b088b..36664e3c9d797c 100644 --- a/packages/block-editor/src/components/block-list/hover-area.js +++ b/packages/block-editor/src/components/block-list/hover-area.js @@ -1,82 +1,41 @@ /** * WordPress dependencies */ -import { Component } from '@wordpress/element'; -import { withSelect } from '@wordpress/data'; +import { useState, useEffect } from '@wordpress/element'; -class HoverArea extends Component { - constructor() { - super( ...arguments ); - this.state = { - hoverArea: null, - }; - this.onMouseLeave = this.onMouseLeave.bind( this ); - this.onMouseMove = this.onMouseMove.bind( this ); - } - - componentWillUnmount() { - if ( this.props.container ) { - this.toggleListeners( this.props.container, false ); - } - } - - componentDidMount() { - if ( this.props.container ) { - this.toggleListeners( this.props.container ); - } - } - - componentDidUpdate( prevProps ) { - if ( prevProps.container === this.props.container ) { - return; - } - if ( prevProps.container ) { - this.toggleListeners( prevProps.container, false ); - } - if ( this.props.container ) { - this.toggleListeners( this.props.container, true ); - } - } +const useHoveredArea = ( wrapper ) => { + const [ hoveredArea, setHoveredArea ] = useState( null ); - toggleListeners( container, shouldListnerToEvents = true ) { - const method = shouldListnerToEvents ? 'addEventListener' : 'removeEventListener'; - container[ method ]( 'mousemove', this.onMouseMove ); - container[ method ]( 'mouseleave', this.onMouseLeave ); - } - - onMouseLeave() { - if ( this.state.hoverArea ) { - this.setState( { hoverArea: null } ); - } - } + useEffect( () => { + const onMouseLeave = () => { + if ( hoveredArea ) { + setHoveredArea( null ); + } + }; - onMouseMove( event ) { - const { isRTL, container } = this.props; - const { width, left, right } = container.getBoundingClientRect(); + const onMouseMove = ( event ) => { + const { width, left, right } = wrapper.current.getBoundingClientRect(); - let hoverArea = null; - if ( ( event.clientX - left ) < width / 3 ) { - hoverArea = isRTL ? 'right' : 'left'; - } else if ( ( right - event.clientX ) < width / 3 ) { - hoverArea = isRTL ? 'left' : 'right'; - } + let newHoveredArea = null; + if ( ( event.clientX - left ) < width / 3 ) { + newHoveredArea = 'left'; + } else if ( ( right - event.clientX ) < width / 3 ) { + newHoveredArea = 'right'; + } - if ( hoverArea !== this.state.hoverArea ) { - this.setState( { hoverArea } ); - } - } + setHoveredArea( newHoveredArea ); + }; - render() { - const { hoverArea } = this.state; - const { children } = this.props; + wrapper.current.addEventListener( 'mousemove', onMouseMove ); + wrapper.current.addEventListener( 'mouseleave', onMouseLeave ); - return children( { hoverArea } ); - } -} + return () => { + wrapper.current.removeEventListener( 'mousemove', onMouseMove ); + wrapper.current.removeEventListener( 'mouseleave', onMouseLeave ); + }; + }, [] ); -export default withSelect( ( select ) => { - return { - isRTL: select( 'core/block-editor' ).getSettings().isRTL, - }; -} )( HoverArea ); + return hoveredArea; +}; +export default useHoveredArea; From de965f9fa621efc93a680f19b58124333376d3b7 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Thu, 6 Jun 2019 15:09:23 -0400 Subject: [PATCH 064/132] Framework: Introduce "Milestone It" GitHub action (#15826) * Framework: Introduce "Milestone It" GitHub action * Framework: Send milestone request result to the abyss * Framework: Reset minor to zero at next major * Framework: Include milestone description text * Framework: Abort milestone assignment if one is applied * Framework: Ensure entrypoint is executable * Framework: Install ca-certificates to avoid cURL errors * Framework: Use bash shell to avoid redirect error https://stackoverflow.com/questions/2462317/bash-syntax-error-redirection-unexpected * Framework: Compute due date for milestone * Framework: Remove debugging output * Framework: Search all milestone array members for title --- .github/actions/milestone-it/Dockerfile | 18 +++++ .github/actions/milestone-it/entrypoint.sh | 81 ++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 .github/actions/milestone-it/Dockerfile create mode 100755 .github/actions/milestone-it/entrypoint.sh diff --git a/.github/actions/milestone-it/Dockerfile b/.github/actions/milestone-it/Dockerfile new file mode 100644 index 00000000000000..af20456bcc34e5 --- /dev/null +++ b/.github/actions/milestone-it/Dockerfile @@ -0,0 +1,18 @@ +FROM debian:stable-slim + +LABEL "name"="Milestone It" +LABEL "maintainer"="The WordPress Contributors" +LABEL "version"="1.0.0" + +LABEL "com.github.actions.name"="Milestone It" +LABEL "com.github.actions.description"="Assigns a pull request to the next milestone" +LABEL "com.github.actions.icon"="flag" +LABEL "com.github.actions.color"="green" + +RUN apt-get update && \ + apt-get install --no-install-recommends -y jq curl ca-certificates && \ + apt-get clean -y + +COPY entrypoint.sh /entrypoint.sh + +ENTRYPOINT [ "/entrypoint.sh" ] diff --git a/.github/actions/milestone-it/entrypoint.sh b/.github/actions/milestone-it/entrypoint.sh new file mode 100755 index 00000000000000..a0b94110f532a2 --- /dev/null +++ b/.github/actions/milestone-it/entrypoint.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -e + +# 1. Determine if milestone already exists (don't replace one which has already +# been assigned). + +pr=$(jq -r '.number' $GITHUB_EVENT_PATH) + +current_milestone=$( + curl \ + --silent \ + -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$GITHUB_REPOSITORY/issues/$pr" \ + | jq '.milestone' +) + +if [ "$current_milestone" != 'null' ]; then + echo 'Milestone already applied. Aborting.' + exit 1; +fi + +# 2. Read current version. + +version=$(jq -r '.version' package.json) + +IFS='.' read -ra parts <<< "$version" +major=${parts[0]} +minor=${parts[1]} + +# 3. Determine next milestone. + +if [ minor == '9' ]; then + major=$((major+1)) + minor="0" +else + minor=$((minor+1)) +fi + +milestone="Gutenberg $major.$minor" + +# 4. Calculate next milestone due date, using a static reference of an earlier +# release (v5.0) as a reference point for the biweekly release schedule. + +reference_major=5 +reference_minor=0 +reference_date=1549238400 +num_versions_elapsed=$(((major-reference_major)*10+(minor-reference_minor))) +weeks=$((num_versions_elapsed*2)) +due=$(date -u --iso-8601=seconds -d "$(date -d @$(echo $reference_date)) + $(echo $weeks) weeks") + +# 5. Create milestone. This may fail for duplicates, which is expected and +# ignored. + +curl \ + --silent \ + -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"title\":\"$milestone\",\"due_on\":\"$due\",\"description\":\"Tasks to be included in the $milestone plugin release.\"}" \ + "https://api.github.com/repos/$GITHUB_REPOSITORY/milestones" > /dev/null + +# 6. Find milestone number. This could be improved to allow for non-open status +# or paginated results. + +number=$( + curl \ + --silent \ + -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/$GITHUB_REPOSITORY/milestones" \ + | jq ".[] | select(.title == \"$milestone\") | .number" +) + +# 7. Assign pull request to milestone. + +curl \ + --silent \ + -X POST \ + -H "Authorization: token $GITHUB_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"milestone\":$number}" \ + "https://api.github.com/repos/$GITHUB_REPOSITORY/issues/$pr" > /dev/null From 73a305183805f299d9bb38695bf28500bce79fc3 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Thu, 6 Jun 2019 15:14:31 -0400 Subject: [PATCH 065/132] Add workflow "Milestone merged pull requests" --- .github/main.workflow | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/main.workflow diff --git a/.github/main.workflow b/.github/main.workflow new file mode 100644 index 00000000000000..885e4e0bcf69dc --- /dev/null +++ b/.github/main.workflow @@ -0,0 +1,15 @@ +workflow "Milestone merged pull requests" { + on = "pull_request" + resolves = ["Milestone It"] +} + +action "Filter merged" { + uses = "actions/bin/filter@3c0b4f0e63ea54ea5df2914b4fabf383368cd0da" + args = "merged true" +} + +action "Milestone It" { + uses = "./actions/milestone-it/Dockerfile" + needs = ["Filter merged"] + secrets = ["GITHUB_TOKEN"] +} From 7037708655173d5109b34b7968da8ca116c2f5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= <wp@iseulde.com> Date: Fri, 7 Jun 2019 09:06:28 +0200 Subject: [PATCH 066/132] Format Library: Remove secondary (access) shortcuts (#15191) * Format Library: Remove secondary (access) shortcuts * Update help modal * Fix tests --- .../__snapshots__/rich-text.test.js.snap | 6 ----- packages/e2e-tests/specs/rich-text.test.js | 9 ------- .../keyboard-shortcut-help-modal/config.js | 12 ++------- .../test/__snapshots__/index.js.snap | 26 +++---------------- packages/format-library/src/code/index.js | 23 +++++----------- packages/format-library/src/link/index.js | 10 ------- .../format-library/src/strikethrough/index.js | 23 +++++----------- 7 files changed, 19 insertions(+), 90 deletions(-) diff --git a/packages/e2e-tests/specs/__snapshots__/rich-text.test.js.snap b/packages/e2e-tests/specs/__snapshots__/rich-text.test.js.snap index 8aab0dcd5b734b..3c7044b5fb8053 100644 --- a/packages/e2e-tests/specs/__snapshots__/rich-text.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/rich-text.test.js.snap @@ -6,12 +6,6 @@ exports[`RichText should apply formatting when selection is collapsed 1`] = ` <!-- /wp:paragraph -->" `; -exports[`RichText should apply formatting with access shortcut 1`] = ` -"<!-- wp:paragraph --> -<p><s>test</s></p> -<!-- /wp:paragraph -->" -`; - exports[`RichText should apply formatting with primary shortcut 1`] = ` "<!-- wp:paragraph --> <p><strong>test</strong></p> diff --git a/packages/e2e-tests/specs/rich-text.test.js b/packages/e2e-tests/specs/rich-text.test.js index 1bd6d79c1b10fc..6dce07f78146ca 100644 --- a/packages/e2e-tests/specs/rich-text.test.js +++ b/packages/e2e-tests/specs/rich-text.test.js @@ -27,15 +27,6 @@ describe( 'RichText', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'should apply formatting with access shortcut', async () => { - await clickBlockAppender(); - await page.keyboard.type( 'test' ); - await pressKeyWithModifier( 'primary', 'a' ); - await pressKeyWithModifier( 'access', 'd' ); - - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - it( 'should apply formatting with primary shortcut', async () => { await clickBlockAppender(); await page.keyboard.type( 'test' ); diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js index 5c6037c0467f4b..340efee1c5d55d 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/config.js @@ -132,10 +132,6 @@ const textFormattingShortcuts = { keyCombination: primary( 'i' ), description: __( 'Make the selected text italic.' ), }, - { - keyCombination: primary( 'u' ), - description: __( 'Underline the selected text.' ), - }, { keyCombination: primary( 'k' ), description: __( 'Convert the selected text into a link.' ), @@ -145,12 +141,8 @@ const textFormattingShortcuts = { description: __( 'Remove a link.' ), }, { - keyCombination: access( 'd' ), - description: __( 'Add a strikethrough to the selected text.' ), - }, - { - keyCombination: access( 'x' ), - description: __( 'Display the selected text in a monospaced font.' ), + keyCombination: primary( 'u' ), + description: __( 'Underline the selected text.' ), }, ], }; diff --git a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap index fe522a985d3b9a..e08b7e6501cdcb 100644 --- a/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap +++ b/packages/edit-post/src/components/keyboard-shortcut-help-modal/test/__snapshots__/index.js.snap @@ -235,14 +235,6 @@ exports[`KeyboardShortcutHelpModal should match snapshot when the modal is activ "I", ], }, - Object { - "description": "Underline the selected text.", - "keyCombination": Array [ - "Ctrl", - "+", - "U", - ], - }, Object { "description": "Convert the selected text into a link.", "keyCombination": Array [ @@ -262,23 +254,11 @@ exports[`KeyboardShortcutHelpModal should match snapshot when the modal is activ ], }, Object { - "description": "Add a strikethrough to the selected text.", - "keyCombination": Array [ - "Shift", - "+", - "Alt", - "+", - "D", - ], - }, - Object { - "description": "Display the selected text in a monospaced font.", + "description": "Underline the selected text.", "keyCombination": Array [ - "Shift", - "+", - "Alt", + "Ctrl", "+", - "X", + "U", ], }, ] diff --git a/packages/format-library/src/code/index.js b/packages/format-library/src/code/index.js index aaccbde3946f49..4eb3cfb1118ef8 100644 --- a/packages/format-library/src/code/index.js +++ b/packages/format-library/src/code/index.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { toggleFormat } from '@wordpress/rich-text'; -import { RichTextShortcut, RichTextToolbarButton } from '@wordpress/block-editor'; +import { RichTextToolbarButton } from '@wordpress/block-editor'; const name = 'core/code'; const title = __( 'Inline Code' ); @@ -17,21 +17,12 @@ export const code = { const onToggle = () => onChange( toggleFormat( value, { type: name } ) ); return ( - <> - <RichTextShortcut - type="access" - character="x" - onUse={ onToggle } - /> - <RichTextToolbarButton - icon="editor-code" - title={ title } - onClick={ onToggle } - isActive={ isActive } - shortcutType="access" - shortcutCharacter="x" - /> - </> + <RichTextToolbarButton + icon="editor-code" + title={ title } + onClick={ onToggle } + isActive={ isActive } + /> ); }, }; diff --git a/packages/format-library/src/link/index.js b/packages/format-library/src/link/index.js index 913285f2e8b0f3..f68d4932f62420 100644 --- a/packages/format-library/src/link/index.js +++ b/packages/format-library/src/link/index.js @@ -71,16 +71,6 @@ export const link = { return ( <> - <RichTextShortcut - type="access" - character="a" - onUse={ this.addLink } - /> - <RichTextShortcut - type="access" - character="s" - onUse={ this.onRemoveFormat } - /> <RichTextShortcut type="primary" character="k" diff --git a/packages/format-library/src/strikethrough/index.js b/packages/format-library/src/strikethrough/index.js index 244b2787fb4d04..23c17f1fea4a8d 100644 --- a/packages/format-library/src/strikethrough/index.js +++ b/packages/format-library/src/strikethrough/index.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { toggleFormat } from '@wordpress/rich-text'; -import { RichTextToolbarButton, RichTextShortcut } from '@wordpress/block-editor'; +import { RichTextToolbarButton } from '@wordpress/block-editor'; const name = 'core/strikethrough'; const title = __( 'Strikethrough' ); @@ -17,21 +17,12 @@ export const strikethrough = { const onToggle = () => onChange( toggleFormat( value, { type: name } ) ); return ( - <> - <RichTextShortcut - type="access" - character="d" - onUse={ onToggle } - /> - <RichTextToolbarButton - icon="editor-strikethrough" - title={ title } - onClick={ onToggle } - isActive={ isActive } - shortcutType="access" - shortcutCharacter="d" - /> - </> + <RichTextToolbarButton + icon="editor-strikethrough" + title={ title } + onClick={ onToggle } + isActive={ isActive } + /> ); }, }; From 32bff1aa13186493413b4efa646ae1530992886e Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Fri, 7 Jun 2019 09:09:39 +0100 Subject: [PATCH 067/132] Adds an is-busy state to the save button of the widgets page (#16019) --- .../src/components/header/index.js | 24 +++++--------- .../src/components/save-button/index.js | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 16 deletions(-) create mode 100644 packages/edit-widgets/src/components/save-button/index.js diff --git a/packages/edit-widgets/src/components/header/index.js b/packages/edit-widgets/src/components/header/index.js index 3dc3f650e9d8ea..f18519fc3d5fcc 100644 --- a/packages/edit-widgets/src/components/header/index.js +++ b/packages/edit-widgets/src/components/header/index.js @@ -1,12 +1,14 @@ /** * WordPress dependencies */ -import { compose } from '@wordpress/compose'; -import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { withDispatch } from '@wordpress/data'; -function Header( { saveWidgetAreas } ) { +/** + * Internal dependencies + */ +import SaveButton from '../save-button'; + +function Header() { return ( <div className="edit-widgets-header" @@ -19,20 +21,10 @@ function Header( { saveWidgetAreas } ) { </h1> <div className="edit-widgets-header__actions"> - <Button isPrimary isLarge onClick={ saveWidgetAreas }> - { __( 'Update' ) } - </Button> + <SaveButton /> </div> </div> ); } -export default compose( [ - withDispatch( ( dispatch ) => { - const { saveWidgetAreas } = dispatch( 'core/edit-widgets' ); - return { - saveWidgetAreas, - }; - } ), -] )( Header ); - +export default Header; diff --git a/packages/edit-widgets/src/components/save-button/index.js b/packages/edit-widgets/src/components/save-button/index.js new file mode 100644 index 00000000000000..dd9040356d95ee --- /dev/null +++ b/packages/edit-widgets/src/components/save-button/index.js @@ -0,0 +1,31 @@ +/** + * WordPress dependencies + */ +import { Button } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { useDispatch } from '@wordpress/data'; +import { useState, useCallback } from '@wordpress/element'; + +function SaveButton() { + const [ isSaving, setIsSaving ] = useState( false ); + const { saveWidgetAreas } = useDispatch( 'core/edit-widgets' ); + const onClick = useCallback( async () => { + setIsSaving( true ); + await saveWidgetAreas(); + setIsSaving( false ); + }, [] ); + + return ( + <Button + isPrimary + isLarge + isBusy={ isSaving } + aria-disabled={ isSaving } + onClick={ isSaving ? undefined : onClick } + > + { __( 'Update' ) } + </Button> + ); +} + +export default SaveButton; From 0e864baecbd64f093683dd367872bb9f9f93086d Mon Sep 17 00:00:00 2001 From: Danilo Ercoli <ercoli@gmail.com> Date: Fri, 7 Jun 2019 12:23:19 +0200 Subject: [PATCH 068/132] [RNMobile] Fix for extra BR tag on Title field on Android (#16021) * Remove extra BR tag that may happen at the end of the Title field on Android when pressing Enter.key * Make sure to set `deleteEnter={ true }` so that Android does delete the new line / BR tag on enter pressed --- packages/editor/src/components/post-title/index.native.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 0bb3591fa52ecc..07e6fe1be2c6c4 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -95,6 +95,7 @@ class PostTitle extends Component { style={ style } fontSize={ 24 } fontWeight={ 'bold' } + deleteEnter={ true } onChange={ ( value ) => { this.props.onUpdate( value ); } } From 1128afbb2bd34aa8aa02aeab5160691d2fb1dfdf Mon Sep 17 00:00:00 2001 From: Pinar Olguc <pinarolguc@gmail.com> Date: Fri, 7 Jun 2019 13:31:02 +0300 Subject: [PATCH 069/132] [Mobile]Open video/quote/more blocks to public (#16031) * Remove unregistration of video, more, quote blocks * Update code comment --- packages/edit-post/src/index.native.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/edit-post/src/index.native.js b/packages/edit-post/src/index.native.js index cc5dfaec90ae1d..1abd926f26bc8c 100644 --- a/packages/edit-post/src/index.native.js +++ b/packages/edit-post/src/index.native.js @@ -18,13 +18,10 @@ export function initializeEditor() { // register and setup blocks registerCoreBlocks(); - // disable Code and More blocks for the release + // disable Code block for the release // eslint-disable-next-line no-undef if ( typeof __DEV__ === 'undefined' || ! __DEV__ ) { unregisterBlockType( 'core/code' ); - unregisterBlockType( 'core/more' ); - unregisterBlockType( 'core/video' ); - unregisterBlockType( 'core/quote' ); } } From 66c9b1823bffde67a143e8e9273b0a1c88d21927 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Fri, 7 Jun 2019 11:31:30 +0100 Subject: [PATCH 070/132] Add: Format library to the widget screen. (#15948) --- lib/widgets-page.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/widgets-page.php b/lib/widgets-page.php index 858866c02f1755..f790e60d24b7a1 100644 --- a/lib/widgets-page.php +++ b/lib/widgets-page.php @@ -68,6 +68,8 @@ function gutenberg_widgets_init( $hook ) { 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');' ); wp_enqueue_script( 'wp-edit-widgets' ); + wp_enqueue_script( 'wp-format-library' ); wp_enqueue_style( 'wp-edit-widgets' ); + wp_enqueue_style( 'wp-format-library' ); } add_action( 'admin_enqueue_scripts', 'gutenberg_widgets_init' ); From 0ee264f0a6ae9d196bdae4a300985b8871c5b425 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Fri, 7 Jun 2019 12:16:13 +0100 Subject: [PATCH 071/132] Fix: DateTimePicker passes current seconds as the selected seconds value (#15495) DateTimePicker does not allow users to pick a value for seconds, so when the user changes a time/date, it should look like a value of 0 was selected as the seconds value. Currently, the seconds of the current date are passed as the selected seconds, which may make it look like a "random" value was selected as the seconds value. This causes a regression where WP_CRON missed some scheduled posts. --- packages/components/CHANGELOG.md | 3 ++ packages/components/src/date-time/date.js | 2 +- packages/components/src/date-time/time.js | 37 ++++++++++++----------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 5fc3cba4b28b46..c1a4e6fef2b5f7 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -17,6 +17,9 @@ - `ServerSideRender` is no longer part of components. It was extracted to an independent package `@wordpress/server-side-render`. +### Bug Fix + +- Although `DateTimePicker` does not allow picking the seconds, passed the current seconds as the selected value for seconds when calling `onChange`. Now it passes zero. ## 7.4.0 (2019-05-21) diff --git a/packages/components/src/date-time/date.js b/packages/components/src/date-time/date.js index a8e4130e739c8c..0d5058789f17f6 100644 --- a/packages/components/src/date-time/date.js +++ b/packages/components/src/date-time/date.js @@ -30,7 +30,7 @@ class DatePicker extends Component { const momentTime = { hours: momentDate.hours(), minutes: momentDate.minutes(), - seconds: momentDate.seconds(), + seconds: 0, }; onChange( newDate.set( momentTime ).format( TIMEZONELESS_FORMAT ) ); diff --git a/packages/components/src/date-time/time.js b/packages/components/src/date-time/time.js index 55937b10170319..0cfc8c7dc8ea68 100644 --- a/packages/components/src/date-time/time.js +++ b/packages/components/src/date-time/time.js @@ -33,6 +33,7 @@ class TimePicker extends Component { am: true, date: null, }; + this.changeDate = this.changeDate.bind( this ); this.updateMonth = this.updateMonth.bind( this ); this.onChangeMonth = this.onChangeMonth.bind( this ); this.updateDay = this.updateDay.bind( this ); @@ -61,6 +62,17 @@ class TimePicker extends Component { this.syncState( this.props ); } } + /** + * Function that sets the date state and calls the onChange with a new date. + * The date is truncated at the minutes. + * + * @param {Object} newDate The date object. + */ + changeDate( newDate ) { + const dateWithStartOfMinutes = newDate.clone().startOf( 'minute' ); + this.setState( { date: dateWithStartOfMinutes } ); + this.props.onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + } getMaxHours() { return this.props.is12Hour ? 12 : 23; @@ -83,7 +95,7 @@ class TimePicker extends Component { } updateHours() { - const { is12Hour, onChange } = this.props; + const { is12Hour } = this.props; const { am, hours, date } = this.state; const value = parseInt( hours, 10 ); if ( @@ -98,12 +110,10 @@ class TimePicker extends Component { const newDate = is12Hour ? date.clone().hours( am === 'AM' ? value % 12 : ( ( ( value % 12 ) + 12 ) % 24 ) ) : date.clone().hours( value ); - this.setState( { date: newDate } ); - onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + this.changeDate( newDate ); } updateMinutes() { - const { onChange } = this.props; const { minutes, date } = this.state; const value = parseInt( minutes, 10 ); if ( ! isInteger( value ) || value < 0 || value > 59 ) { @@ -111,12 +121,10 @@ class TimePicker extends Component { return; } const newDate = date.clone().minutes( value ); - this.setState( { date: newDate } ); - onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + this.changeDate( newDate ); } updateDay() { - const { onChange } = this.props; const { day, date } = this.state; const value = parseInt( day, 10 ); if ( ! isInteger( value ) || value < 1 || value > 31 ) { @@ -124,12 +132,10 @@ class TimePicker extends Component { return; } const newDate = date.clone().date( value ); - this.setState( { date: newDate } ); - onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + this.changeDate( newDate ); } updateMonth() { - const { onChange } = this.props; const { month, date } = this.state; const value = parseInt( month, 10 ); if ( ! isInteger( value ) || value < 1 || value > 12 ) { @@ -137,12 +143,10 @@ class TimePicker extends Component { return; } const newDate = date.clone().month( value - 1 ); - this.setState( { date: newDate } ); - onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + this.changeDate( newDate ); } updateYear() { - const { onChange } = this.props; const { year, date } = this.state; const value = parseInt( year, 10 ); if ( ! isInteger( value ) || value < 0 || value > 9999 ) { @@ -150,13 +154,11 @@ class TimePicker extends Component { return; } const newDate = date.clone().year( value ); - this.setState( { date: newDate } ); - onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + this.changeDate( newDate ); } updateAmPm( value ) { return () => { - const { onChange } = this.props; const { am, date, hours } = this.state; if ( am === value ) { return; @@ -167,8 +169,7 @@ class TimePicker extends Component { } else { newDate = date.clone().hours( parseInt( hours, 10 ) % 12 ); } - this.setState( { date: newDate } ); - onChange( newDate.format( TIMEZONELESS_FORMAT ) ); + this.changeDate( newDate ); }; } From a516f501436888ac696c2bf1e3ff006e13c71d25 Mon Sep 17 00:00:00 2001 From: Kjell Reigstad <kjell.reigstad@automattic.com> Date: Fri, 7 Jun 2019 08:08:38 -0400 Subject: [PATCH 072/132] Add improved "Group" and "Ungroup" icons (#16001) * Update Group block icon * Update Group/Ungroup action icons --- packages/block-library/src/group/icon.js | 2 +- .../src/components/convert-to-group-buttons/icons.js | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/group/icon.js b/packages/block-library/src/group/icon.js index 959b844350615f..e1b36f7f72cadb 100644 --- a/packages/block-library/src/group/icon.js +++ b/packages/block-library/src/group/icon.js @@ -4,5 +4,5 @@ import { Path, SVG } from '@wordpress/components'; export default ( - <SVG xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><Path d="M19 12h-2v3h-3v2h5v-5zM7 9h3V7H5v5h2V9zm14-6H3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16.01H3V4.99h18v14.02z" /><Path d="M0 0h24v24H0z" fill="none" /></SVG> + <SVG width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><Path fill-rule="evenodd" clip-rule="evenodd" d="M9 8a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-1v3a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm2 3h4V9h-4v2zm2 2H9v2h4v-2z" /><Path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.732A2 2 0 1 1 4.732 2h14.536A2 2 0 1 1 22 4.732v14.536A2 2 0 1 1 19.268 22H4.732A2 2 0 1 1 2 19.268V4.732zM4.732 4h14.536c.175.304.428.557.732.732v14.536a2.01 2.01 0 0 0-.732.732H4.732A2.01 2.01 0 0 0 4 19.268V4.732A2.01 2.01 0 0 0 4.732 4z" /></SVG> ); diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js index 8ca249c2fa7ee6..d1ee497662cd49 100644 --- a/packages/editor/src/components/convert-to-group-buttons/icons.js +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -3,17 +3,11 @@ */ import { Icon, SVG, Path } from '@wordpress/components'; -const GroupSVG = <SVG width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> - <Path fillRule="evenodd" clipRule="evenodd" d="M10 4H18C19.1 4 20 4.9 20 6V14C20 15.1 19.1 16 18 16H10C8.9 16 8 15.1 8 14V6C8 4.9 8.9 4 10 4ZM10 14H18V6H10V14Z" /> - <Path d="M6 8C4.9 8 4 8.9 4 10V18C4 19.1 4.9 20 6 20H14C15.1 20 16 19.1 16 18H6V8Z" /> -</SVG>; +const GroupSVG = <SVG width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><Path fill-rule="evenodd" clip-rule="evenodd" d="M8 5a1 1 0 0 0-1 1v3H6a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-3h1a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H8zm3 6H7v2h4v-2zM9 9V7h4v2H9z" /><Path fill-rule="evenodd" clip-rule="evenodd" d="M1 3a2 2 0 0 0 1 1.732v10.536A2 2 0 1 0 4.732 18h10.536A2 2 0 1 0 18 15.268V4.732A2 2 0 1 0 15.268 2H4.732A2 2 0 0 0 1 3zm14.268 1H4.732A2.01 2.01 0 0 1 4 4.732v10.536c.304.175.557.428.732.732h10.536a2.01 2.01 0 0 1 .732-.732V4.732A2.01 2.01 0 0 1 15.268 4z" /></SVG>; export const Group = <Icon icon={ GroupSVG } />; -const UngroupSVG = <SVG width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> - <Path fillRule="evenodd" clipRule="evenodd" d="M12 2H20C21.1 2 22 2.9 22 4V12C22 13.1 21.1 14 20 14H12C10.9 14 10 13.1 10 12V4C10 2.9 10.9 2 12 2ZM12 12H20V4H12V12Z" /> - <Path d="M4 10H8V12H4V20H12V16H14V20C14 21.1 13.1 22 12 22H4C2.9 22 2 21.1 2 20V12C2 10.9 2.9 10 4 10Z" /> -</SVG>; +const UngroupSVG = <SVG width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><Path fill-rule="evenodd" clip-rule="evenodd" d="M9 2H15C16.1 2 17 2.9 17 4V7C17 8.1 16.1 9 15 9H9C7.9 9 7 8.1 7 7V4C7 2.9 7.9 2 9 2ZM9 7H15V4H9V7Z" /><Path fill-rule="evenodd" clip-rule="evenodd" d="M5 11H11C12.1 11 13 11.9 13 13V16C13 17.1 12.1 18 11 18H5C3.9 18 3 17.1 3 16V13C3 11.9 3.9 11 5 11ZM5 16H11V13H5V16Z" /></SVG>; export const Ungroup = <Icon icon={ UngroupSVG } />; From eae298a4da2b8f51f23e1509aec00dbb42c86f84 Mon Sep 17 00:00:00 2001 From: Mark Uraine <uraine@gmail.com> Date: Fri, 7 Jun 2019 05:15:05 -0700 Subject: [PATCH 073/132] Spacer block: Add clear:both; to clear any floats around it (#15874) * Fixes #15099. Adds a to the Spacer block so that it clears any floated blocks and functions as a Spacer block should. * Minor lint-style fix. * Moved the import file into alphabetical position. --- packages/block-library/src/spacer/editor.scss | 1 + packages/block-library/src/spacer/style.scss | 3 +++ packages/block-library/src/style.scss | 1 + 3 files changed, 5 insertions(+) create mode 100644 packages/block-library/src/spacer/style.scss diff --git a/packages/block-library/src/spacer/editor.scss b/packages/block-library/src/spacer/editor.scss index 77fba2118222a7..b20657931c97ef 100644 --- a/packages/block-library/src/spacer/editor.scss +++ b/packages/block-library/src/spacer/editor.scss @@ -3,5 +3,6 @@ } .block-library-spacer__resize-container { + clear: both; margin-bottom: $default-block-margin; } diff --git a/packages/block-library/src/spacer/style.scss b/packages/block-library/src/spacer/style.scss new file mode 100644 index 00000000000000..e6b5ee9d5085bd --- /dev/null +++ b/packages/block-library/src/spacer/style.scss @@ -0,0 +1,3 @@ +.wp-block-spacer { + clear: both; +} diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index 7ebad4a855135e..d33dd3c393c3b1 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -17,6 +17,7 @@ @import "./rss/style.scss"; @import "./search/style.scss"; @import "./separator/style.scss"; +@import "./spacer/style.scss"; @import "./subhead/style.scss"; @import "./table/style.scss"; @import "./text-columns/style.scss"; From 939332c0af938afcff2fabf4b7261bb90f9d9097 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Fri, 7 Jun 2019 08:29:53 -0400 Subject: [PATCH 074/132] Fix "Milestone It" workflow container path --- .github/main.workflow | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/main.workflow b/.github/main.workflow index 885e4e0bcf69dc..a714ca269ada60 100644 --- a/.github/main.workflow +++ b/.github/main.workflow @@ -9,7 +9,7 @@ action "Filter merged" { } action "Milestone It" { - uses = "./actions/milestone-it/Dockerfile" + uses = "./.github/actions/milestone-it" needs = ["Filter merged"] secrets = ["GITHUB_TOKEN"] } From 2e7161cf6cc54013fd17870e88ceb16c3866b5b1 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Fri, 7 Jun 2019 15:03:57 +0100 Subject: [PATCH 075/132] Remove @wordpress/format-library dependency from edit-post (#16034) The edit-post does not use the format-library package. The package is loaded by core and calls the correct mechanism to register the formats being used, but the edit-post package does not directly depend on format-library. --- packages/edit-post/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index 74a706fffc4dc1..a2566dd750a75f 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -33,7 +33,6 @@ "@wordpress/data": "file:../data", "@wordpress/editor": "file:../editor", "@wordpress/element": "file:../element", - "@wordpress/format-library": "file:../format-library", "@wordpress/hooks": "file:../hooks", "@wordpress/i18n": "file:../i18n", "@wordpress/keycodes": "file:../keycodes", From 6c67c96475568d7b24ef2c85b321ba77e8ddb20f Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Fri, 7 Jun 2019 11:57:26 -0400 Subject: [PATCH 076/132] Framework: Update package-lock.json per #16034 --- package-lock.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 7352bce3c4f67c..c8943767a50d28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3528,7 +3528,6 @@ "@wordpress/data": "file:packages/data", "@wordpress/editor": "file:packages/editor", "@wordpress/element": "file:packages/element", - "@wordpress/format-library": "file:packages/format-library", "@wordpress/hooks": "file:packages/hooks", "@wordpress/i18n": "file:packages/i18n", "@wordpress/keycodes": "file:packages/keycodes", From 6fad854e4a37c46fe959d9b854641953e225c5e5 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Fri, 7 Jun 2019 17:44:06 +0100 Subject: [PATCH 077/132] Update increase tooltip selector specificity (#16043) --- packages/components/src/tooltip/style.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/tooltip/style.scss b/packages/components/src/tooltip/style.scss index 79739693294c30..93642af8cf2052 100644 --- a/packages/components/src/tooltip/style.scss +++ b/packages/components/src/tooltip/style.scss @@ -12,6 +12,10 @@ &.is-bottom::after { border-bottom-color: $dark-gray-900; } + + &:not(.is-mobile) .components-popover__content { + min-width: 0; + } } .components-tooltip .components-popover__content { @@ -23,10 +27,6 @@ text-align: center; } -.components-tooltip:not(.is-mobile) .components-popover__content { - min-width: 0; -} - .components-tooltip__shortcut { display: block; color: $dark-gray-200; From a4bd1d099d8f03334ae7b221dde4c0d94266681d Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Fri, 7 Jun 2019 13:46:02 -0400 Subject: [PATCH 078/132] Block API: Downgrade `convert` API to experimental (#16047) --- packages/block-library/src/group/index.js | 2 +- packages/blocks/CHANGELOG.md | 1 - packages/blocks/src/api/factory.js | 8 ++++---- packages/blocks/src/api/test/factory.js | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/group/index.js b/packages/block-library/src/group/index.js index 386ab20a80955c..844ddd8c821600 100644 --- a/packages/block-library/src/group/index.js +++ b/packages/block-library/src/group/index.js @@ -33,7 +33,7 @@ export const settings = { type: 'block', isMultiBlock: true, blocks: [ '*' ], - convert( blocks ) { + __experimentalConvert( blocks ) { // Avoid transforming a single `core/group` Block if ( blocks.length === 1 && blocks[ 0 ].name === 'core/group' ) { return; diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index df5b183e688d45..8f50c3899591da 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -4,7 +4,6 @@ - Added a default implementation for `save` setting in `registerBlockType` which saves no markup in the post content. - Added wildcard block transforms which allows for transforming all/any blocks in another block. -- Added `convert()` method option to `transforms` definition. It receives complete block object(s) as it's argument(s). It is now preferred over the older `transform()` (note that `transform()` is still fully supported). ## 6.1.0 (2019-03-06) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 304329d0be657f..92074c35a6bafd 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -404,16 +404,16 @@ export function switchToBlockType( blocks, name ) { let transformationResults; if ( transformation.isMultiBlock ) { - if ( has( transformation, 'convert' ) ) { - transformationResults = transformation.convert( blocksArray ); + if ( has( transformation, '__experimentalConvert' ) ) { + transformationResults = transformation.__experimentalConvert( blocksArray ); } else { transformationResults = transformation.transform( blocksArray.map( ( currentBlock ) => currentBlock.attributes ), blocksArray.map( ( currentBlock ) => currentBlock.innerBlocks ), ); } - } else if ( has( transformation, 'convert' ) ) { - transformationResults = transformation.convert( firstBlock ); + } else if ( has( transformation, '__experimentalConvert' ) ) { + transformationResults = transformation.__experimentalConvert( firstBlock ); } else { transformationResults = transformation.transform( firstBlock.attributes, firstBlock.innerBlocks ); } diff --git a/packages/blocks/src/api/test/factory.js b/packages/blocks/src/api/test/factory.js index 3e0d42c103bb9a..973964bfe05bae 100644 --- a/packages/blocks/src/api/test/factory.js +++ b/packages/blocks/src/api/test/factory.js @@ -1301,7 +1301,7 @@ describe( 'block factory', () => { expect( transformedBlocks[ 1 ].innerBlocks[ 0 ].attributes.value ).toBe( 'after1' ); } ); - it( 'should pass entire block object(s) to the "convert" method if defined', () => { + it( 'should pass entire block object(s) to the "__experimentalConvert" method if defined', () => { registerBlockType( 'core/test-group-block', { attributes: { value: { @@ -1313,7 +1313,7 @@ describe( 'block factory', () => { type: 'block', blocks: [ '*' ], isMultiBlock: true, - convert( blocks ) { + __experimentalConvert( blocks ) { const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { return createBlock( name, attributes, innerBlocks ); } ); @@ -1343,7 +1343,7 @@ describe( 'block factory', () => { expect( transformedBlocks[ 0 ].innerBlocks ).toHaveLength( numOfBlocksToGroup ); } ); - it( 'should prefer "convert" method over "transform" method when running a transformation', () => { + it( 'should prefer "__experimentalConvert" method over "transform" method when running a transformation', () => { const convertSpy = jest.fn( ( blocks ) => { const groupInnerBlocks = blocks.map( ( { name, attributes, innerBlocks } ) => { return createBlock( name, attributes, innerBlocks ); @@ -1364,7 +1364,7 @@ describe( 'block factory', () => { type: 'block', blocks: [ '*' ], isMultiBlock: true, - convert: convertSpy, + __experimentalConvert: convertSpy, transform: transformSpy, } ], }, From 936e8fab7dd28ff6095b93760e9bd13fcf2f03c7 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Fri, 7 Jun 2019 14:06:36 -0400 Subject: [PATCH 079/132] Revert "adds selection persistence on sidebar tab switch (#15583)" (#16042) This reverts commit 4d5998d7b8558c94c6030d167111c11f92c5b46a. --- .../developers/data/data-core-block-editor.md | 21 +------- .../block-selection-clearer/index.js | 8 +-- packages/block-editor/src/store/actions.js | 27 +--------- packages/block-editor/src/store/reducer.js | 15 +----- .../block-editor/src/store/test/actions.js | 18 ------- .../block-editor/src/store/test/reducer.js | 1 - packages/e2e-tests/specs/a11y.test.js | 51 ------------------- .../sidebar/settings-header/index.js | 4 +- packages/edit-post/src/store/effects.js | 2 +- 9 files changed, 9 insertions(+), 138 deletions(-) diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md index f765454e948878..6e496446d6be20 100644 --- a/docs/designers-developers/developers/data/data-core-block-editor.md +++ b/docs/designers-developers/developers/data/data-core-block-editor.md @@ -824,9 +824,7 @@ _Returns_ <a name="clearSelectedBlock" href="#clearSelectedBlock">#</a> **clearSelectedBlock** -Returns an action object used in signaling that the block selection is cleared. -This will save the current selection in a state called `previousSelection` and -`restoreSelectedBlock` will be able to restore the selection. +Returns an action object used in signalling that the block selection is cleared. _Returns_ @@ -1041,14 +1039,6 @@ _Returns_ - `Object`: Action object. -<a name="restoreSelectedBlock" href="#restoreSelectedBlock">#</a> **restoreSelectedBlock** - -Returns an action object used in restoring the previously cleared selected blocks. - -_Returns_ - -- `Object`: Action object. - <a name="selectBlock" href="#selectBlock">#</a> **selectBlock** Returns an action object used in signalling that the block with the @@ -1235,13 +1225,4 @@ _Returns_ Undocumented declaration. -<a name="wipeSelectedBlock" href="#wipeSelectedBlock">#</a> **wipeSelectedBlock** - -Returns an action object used in signaling that the block selection is wiped. -This will remove block selection so that `restoreSelectedBlock` will have no effect. - -_Returns_ - -- `Object`: Action object. - <!-- END TOKEN(Autogenerated actions) --> diff --git a/packages/block-editor/src/components/block-selection-clearer/index.js b/packages/block-editor/src/components/block-selection-clearer/index.js index cc2e27944e06bd..be39e5df9e7de5 100644 --- a/packages/block-editor/src/components/block-selection-clearer/index.js +++ b/packages/block-editor/src/components/block-selection-clearer/index.js @@ -33,12 +33,12 @@ class BlockSelectionClearer extends Component { const { hasSelectedBlock, hasMultiSelection, - wipeSelectedBlock, + clearSelectedBlock, } = this.props; const hasSelection = ( hasSelectedBlock || hasMultiSelection ); if ( event.target === this.container && hasSelection ) { - wipeSelectedBlock(); + clearSelectedBlock(); } } @@ -68,7 +68,7 @@ export default compose( [ }; } ), withDispatch( ( dispatch ) => { - const { wipeSelectedBlock } = dispatch( 'core/block-editor' ); - return { wipeSelectedBlock }; + const { clearSelectedBlock } = dispatch( 'core/block-editor' ); + return { clearSelectedBlock }; } ), ] )( BlockSelectionClearer ); diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js index e1e4c1f69ed040..4dafaa291fcf31 100644 --- a/packages/block-editor/src/store/actions.js +++ b/packages/block-editor/src/store/actions.js @@ -193,21 +193,7 @@ export function multiSelect( start, end ) { } /** - * Returns an action object used in signaling that the block selection is wiped. - * This will remove block selection so that `restoreSelectedBlock` will have no effect. - * - * @return {Object} Action object. - */ -export function wipeSelectedBlock() { - return { - type: 'WIPE_SELECTED_BLOCK', - }; -} - -/** - * Returns an action object used in signaling that the block selection is cleared. - * This will save the current selection in a state called `previousSelection` and - * `restoreSelectedBlock` will be able to restore the selection. + * Returns an action object used in signalling that the block selection is cleared. * * @return {Object} Action object. */ @@ -217,17 +203,6 @@ export function clearSelectedBlock() { }; } -/** - * Returns an action object used in restoring the previously cleared selected blocks. - * - * @return {Object} Action object. - */ -export function restoreSelectedBlock() { - return { - type: 'RESTORE_SELECTED_BLOCK', - }; -} - /** * Returns an action object that enables or disables block selection. * diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js index e62734d0412e2c..d9d0ecbdd28b64 100644 --- a/packages/block-editor/src/store/reducer.js +++ b/packages/block-editor/src/store/reducer.js @@ -717,21 +717,8 @@ const BLOCK_SELECTION_INITIAL_STATE = { */ export function blockSelection( state = BLOCK_SELECTION_INITIAL_STATE, action ) { switch ( action.type ) { - case 'WIPE_SELECTED_BLOCK': - return BLOCK_SELECTION_INITIAL_STATE; case 'CLEAR_SELECTED_BLOCK': - if ( isEqual( state, BLOCK_SELECTION_INITIAL_STATE ) ) { - return BLOCK_SELECTION_INITIAL_STATE; - } - return { - ...BLOCK_SELECTION_INITIAL_STATE, - previousSelection: omit( state, [ 'previousSelection' ] ), - }; - case 'RESTORE_SELECTED_BLOCK': - return { - ...BLOCK_SELECTION_INITIAL_STATE, - ...state.previousSelection, - }; + return BLOCK_SELECTION_INITIAL_STATE; case 'START_MULTI_SELECT': if ( state.isMultiSelecting ) { return state; diff --git a/packages/block-editor/src/store/test/actions.js b/packages/block-editor/src/store/test/actions.js index 93123c17bf987b..1fb97cd38d9bde 100644 --- a/packages/block-editor/src/store/test/actions.js +++ b/packages/block-editor/src/store/test/actions.js @@ -3,8 +3,6 @@ */ import { clearSelectedBlock, - wipeSelectedBlock, - restoreSelectedBlock, enterFormattedText, exitFormattedText, hideInsertionPoint, @@ -118,22 +116,6 @@ describe( 'actions', () => { } ); } ); - describe( 'wipeSelectedBlock', () => { - it( 'should return WIPE_SELECTED_BLOCK action', () => { - expect( wipeSelectedBlock() ).toEqual( { - type: 'WIPE_SELECTED_BLOCK', - } ); - } ); - } ); - - describe( 'restoreSelectedBlock', () => { - it( 'should return RESTORE_SELECTED_BLOCK action', () => { - expect( restoreSelectedBlock() ).toEqual( { - type: 'RESTORE_SELECTED_BLOCK', - } ); - } ); - } ); - describe( 'replaceBlock', () => { it( 'should yield the REPLACE_BLOCKS action if the new block can be inserted in the destination root block', () => { const block = { diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js index b0d79d8911292e..7543fdad57dd8b 100644 --- a/packages/block-editor/src/store/test/reducer.js +++ b/packages/block-editor/src/store/test/reducer.js @@ -1740,7 +1740,6 @@ describe( 'state', () => { initialPosition: null, isMultiSelecting: false, isEnabled: true, - previousSelection: original, } ); } ); diff --git a/packages/e2e-tests/specs/a11y.test.js b/packages/e2e-tests/specs/a11y.test.js index 784ee4dc556743..6f6cc960f204aa 100644 --- a/packages/e2e-tests/specs/a11y.test.js +++ b/packages/e2e-tests/specs/a11y.test.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { - clickBlockAppender, createNewPost, pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; @@ -30,56 +29,6 @@ describe( 'a11y', () => { expect( isFocusedToggle ).toBe( true ); } ); - it( 'checks persistent selection', async () => { - await clickBlockAppender(); - - // adding one Paragraph block which contains a focusable RichText - await page.keyboard.type( 'Testing editor selection persistence' ); - - let isFocusedRichText = await page.$eval( ':focus', ( focusedElement ) => { - return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); - } ); - - expect( isFocusedRichText ).toBe( true ); - - // moving focus backwards using keyboard shortcuts - // twice to get to the inspector tabs - await pressKeyWithModifier( 'ctrlShift', '`' ); - await pressKeyWithModifier( 'ctrlShift', '`' ); - - await page.keyboard.press( 'Tab' ); - - const isFocusedInspectorDocumentTab = await page.$eval( ':focus', ( focusedElement ) => { - return focusedElement.getAttribute( 'data-label' ); - } ); - - expect( isFocusedInspectorDocumentTab ).toEqual( 'Document' ); - - await page.keyboard.press( 'Space' ); - - isFocusedRichText = await page.$eval( ':focus', ( focusedElement ) => { - return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); - } ); - - expect( isFocusedRichText ).toBe( false ); - - await page.keyboard.press( 'Tab' ); - - const isFocusedInspectorBlockTab = await page.$eval( ':focus', ( focusedElement ) => { - return focusedElement.getAttribute( 'data-label' ); - } ); - - expect( isFocusedInspectorBlockTab ).toEqual( 'Block' ); - - await page.keyboard.press( 'Space' ); - - isFocusedRichText = await page.$eval( ':focus', ( focusedElement ) => { - return focusedElement.classList.contains( 'block-editor-rich-text__editable' ); - } ); - - expect( isFocusedRichText ).toBe( true ); - } ); - it( 'constrains focus to a modal when tabbing', async () => { // Open keyboard help modal. await pressKeyWithModifier( 'access', 'h' ); diff --git a/packages/edit-post/src/components/sidebar/settings-header/index.js b/packages/edit-post/src/components/sidebar/settings-header/index.js index 47d00bce72048a..eeb95a872166f5 100644 --- a/packages/edit-post/src/components/sidebar/settings-header/index.js +++ b/packages/edit-post/src/components/sidebar/settings-header/index.js @@ -57,8 +57,7 @@ const SettingsHeader = ( { openDocumentSettings, openBlockSettings, sidebarName export default withDispatch( ( dispatch ) => { const { openGeneralSidebar } = dispatch( 'core/edit-post' ); - const { clearSelectedBlock, restoreSelectedBlock } = dispatch( 'core/block-editor' ); - + const { clearSelectedBlock } = dispatch( 'core/block-editor' ); return { openDocumentSettings() { openGeneralSidebar( 'edit-post/document' ); @@ -66,7 +65,6 @@ export default withDispatch( ( dispatch ) => { }, openBlockSettings() { openGeneralSidebar( 'edit-post/block' ); - restoreSelectedBlock(); }, }; } )( SettingsHeader ); diff --git a/packages/edit-post/src/store/effects.js b/packages/edit-post/src/store/effects.js index 36d3c2b501369c..54bfe07fbd67b5 100644 --- a/packages/edit-post/src/store/effects.js +++ b/packages/edit-post/src/store/effects.js @@ -109,7 +109,7 @@ const effects = { SWITCH_MODE( action ) { // Unselect blocks when we switch to the code editor. if ( action.mode !== 'visual' ) { - dispatch( 'core/block-editor' ).wipeSelectedBlock(); + dispatch( 'core/block-editor' ).clearSelectedBlock(); } const message = action.mode === 'visual' ? __( 'Visual editor selected' ) : __( 'Code editor selected' ); From 4b12721bee08ee649e238fe20198b872e4f7f488 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Sat, 8 Jun 2019 00:09:56 +0100 Subject: [PATCH 080/132] Add availability checks to widget related code (#15983) This commit adds availability checks for the function get_current_screen and for the globals wp_widget_factory, wp_registered_widgets. The function get_current_screen should only be called in admin pages, but according to the docs, we may have admin pages without the function so I think a check should be added. For example, I guess it may be possible to have an admin page with admin_footer but without the function defined. Regarding the globals wp_widget_factory, wp_registered_widgets used in gutenberg_get_legacy_widget_settings function, the function is called as part of the filter block_editor_settings, I guess the filter may be executed in a situation where the widget globals are not initialized e.g: in a custom plugin page with a custom block editor. I think it is better to check the availability of the globals. If the globals are not available we will not pass available legacy widgets to the front end. --- lib/widgets.php | 60 ++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/lib/widgets.php b/lib/widgets.php index 7ea5d3a5e770dd..3c528b14469271 100644 --- a/lib/widgets.php +++ b/lib/widgets.php @@ -11,6 +11,11 @@ * @return boolean True if a screen containing the block editor is being loaded. */ function gutenberg_is_block_editor() { + // If get_current_screen does not exist, we are neither in the standard block editor for posts, or the widget block editor. + // We can safely return false. + if ( ! function_exists( 'get_current_screen' ) ) { + return false; + } $screen = get_current_screen(); return $screen->is_block_editor() || 'gutenberg_page_gutenberg-widgets' === $screen->id; } @@ -100,33 +105,38 @@ function gutenberg_get_legacy_widget_settings() { $has_permissions_to_manage_widgets = current_user_can( 'edit_theme_options' ); $available_legacy_widgets = array(); - global $wp_widget_factory, $wp_registered_widgets; - foreach ( $wp_widget_factory->widgets as $class => $widget_obj ) { - $available_legacy_widgets[ $class ] = array( - 'name' => html_entity_decode( $widget_obj->name ), - // wp_widget_description is not being used because its input parameter is a Widget Id. - // Widgets id's reference to a specific widget instance. - // Here we are iterating on all the available widget classes even if no widget instance exists for them. - 'description' => isset( $widget_obj->widget_options['description'] ) ? - html_entity_decode( $widget_obj->widget_options['description'] ) : - null, - 'isCallbackWidget' => false, - 'isHidden' => in_array( $class, $core_widgets, true ), - ); + global $wp_widget_factory; + if ( ! empty( $wp_widget_factory ) ) { + foreach ( $wp_widget_factory->widgets as $class => $widget_obj ) { + $available_legacy_widgets[ $class ] = array( + 'name' => html_entity_decode( $widget_obj->name ), + // wp_widget_description is not being used because its input parameter is a Widget Id. + // Widgets id's reference to a specific widget instance. + // Here we are iterating on all the available widget classes even if no widget instance exists for them. + 'description' => isset( $widget_obj->widget_options['description'] ) ? + html_entity_decode( $widget_obj->widget_options['description'] ) : + null, + 'isCallbackWidget' => false, + 'isHidden' => in_array( $class, $core_widgets, true ), + ); + } } - foreach ( $wp_registered_widgets as $widget_id => $widget_obj ) { - if ( - is_array( $widget_obj['callback'] ) && - isset( $widget_obj['callback'][0] ) && - ( $widget_obj['callback'][0] instanceof WP_Widget ) - ) { - continue; + global $wp_registered_widgets; + if ( ! empty( $wp_registered_widgets ) ) { + foreach ( $wp_registered_widgets as $widget_id => $widget_obj ) { + if ( + is_array( $widget_obj['callback'] ) && + isset( $widget_obj['callback'][0] ) && + ( $widget_obj['callback'][0] instanceof WP_Widget ) + ) { + continue; + } + $available_legacy_widgets[ $widget_id ] = array( + 'name' => html_entity_decode( $widget_obj['name'] ), + 'description' => html_entity_decode( wp_widget_description( $widget_id ) ), + 'isCallbackWidget' => true, + ); } - $available_legacy_widgets[ $widget_id ] = array( - 'name' => html_entity_decode( $widget_obj['name'] ), - 'description' => html_entity_decode( wp_widget_description( $widget_id ) ), - 'isCallbackWidget' => true, - ); } $settings['hasPermissionsToManageWidgets'] = $has_permissions_to_manage_widgets; From 24daf82f309d547aa3a10bd8174e94d515332843 Mon Sep 17 00:00:00 2001 From: Stefanos Togoulidis <stefanostogoulidis@gmail.com> Date: Sat, 8 Jun 2019 02:43:42 +0300 Subject: [PATCH 081/132] [RNMobile] keyboard focus issues (#15999) * Focus RichText on mount if block is selected and says so Some blocks have multiple RichText or a RichText among other children. Example: Quote blocks has 2 RichTexts and Image block has a RichText for the caption. We want to control when and which of those RichTexts will request focus. On the web side, the DOM is used to search for a inputbox to focus but on RN, we don't have a DOM to search. Instead, this commit makes the assumption that a RichText always request focus if its parent has passed `true` in `isSelected` and only if the parent hasn't inhibited that behavior by using the `noFocusOnMount` prop. * Simplify the passing of noFocusOnMount * Focus and selection logic closer to GB web's * RichText's API uses unstableOnFocus at the moment * Don't force selection update if position is unset That can happen when the RichText based block gets tapped somewhere and the caret position is not updated yet from Aztec. --- .../src/components/rich-text/index.native.js | 28 +++++++++++-------- .../block-library/src/heading/edit.native.js | 3 -- .../block-library/src/image/edit.native.js | 2 +- .../src/paragraph/edit.native.js | 3 -- .../src/components/post-title/index.native.js | 2 +- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 1430702991dbdd..d9fc545e8fa9f1 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -531,10 +531,18 @@ export class RichText extends Component { onFocus() { this.isTouched = true; - if ( this.props.onFocus ) { - this.props.onFocus(); + const { unstableOnFocus } = this.props; + + if ( unstableOnFocus ) { + unstableOnFocus(); } + // We know for certain that on focus, the old selection is invalid. It + // will be recalculated on `selectionchange`. + const index = undefined; + + this.props.onSelectionChange( index, index ); + this.lastAztecEventType = 'focus'; } @@ -657,7 +665,9 @@ export class RichText extends Component { } if ( ! this.comesFromAztec ) { - if ( nextProps.selectionStart !== this.props.selectionStart && + if ( ( typeof nextProps.selectionStart !== 'undefined' ) && + ( typeof nextProps.selectionEnd !== 'undefined' ) && + nextProps.selectionStart !== this.props.selectionStart && nextProps.selectionStart !== this.selectionStart && nextProps.isSelected ) { this.needsSelectionUpdate = true; @@ -681,7 +691,7 @@ export class RichText extends Component { componentWillUnmount() { if ( this._editor.isFocused() ) { - this._editor.blur(); + // this._editor.blur(); } } @@ -695,7 +705,7 @@ export class RichText extends Component { // Update selection props explicitly when component is selected as Aztec won't call onSelectionChange // if its internal value hasn't change. When created, default value is 0, 0 this.onSelectionChange( this.props.selectionStart || 0, this.props.selectionEnd || 0 ); - } else if ( ! this.props.isSelected && prevProps.isSelected && this.isIOS ) { + } else if ( ! this.props.isSelected && prevProps.isSelected ) { this._editor.blur(); } } @@ -810,7 +820,6 @@ export class RichText extends Component { onContentSizeChange={ this.onContentSizeChange } onCaretVerticalPositionChange={ this.props.onCaretVerticalPositionChange } onSelectionChange={ this.onSelectionChangeFromAztec } - isSelected={ isSelected } blockType={ { tag: tagName } } color={ 'black' } maxImagesWidth={ 200 } @@ -836,15 +845,10 @@ RichText.defaultProps = { const RichTextContainer = compose( [ withInstanceId, - withBlockEditContext( ( { clientId, onFocus, onCaretVerticalPositionChange, isSelected }, ownProps ) => { - // ownProps.onFocus needs precedence over the block edit context - if ( ownProps.onFocus !== undefined ) { - onFocus = ownProps.onFocus; - } + withBlockEditContext( ( { clientId, onCaretVerticalPositionChange, isSelected }, ownProps ) => { return { clientId, blockIsSelected: ownProps.isSelected !== undefined ? ownProps.isSelected : isSelected, - onFocus, onCaretVerticalPositionChange, }; } ), diff --git a/packages/block-library/src/heading/edit.native.js b/packages/block-library/src/heading/edit.native.js index e7d295402c92e1..1f409356b12a1f 100644 --- a/packages/block-library/src/heading/edit.native.js +++ b/packages/block-library/src/heading/edit.native.js @@ -39,13 +39,10 @@ const HeadingEdit = ( { identifier="content" tagName={ 'h' + attributes.level } value={ attributes.content } - isSelected={ isSelected } style={ { ...style, minHeight: styles[ 'wp-block-heading' ].minHeight, } } - onFocus={ onFocus } // always assign onFocus as a props - onBlur={ onBlur } // always assign onBlur as a props onChange={ ( value ) => setAttributes( { content: value } ) } onMerge={ mergeBlocks } onSplit={ ( value ) => { diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 61a0adf3635ce2..cb0cc5a9302630 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -361,7 +361,7 @@ class ImageEdit extends React.Component { placeholder={ __( 'Write caption…' ) } value={ caption } onChange={ ( newCaption ) => setAttributes( { caption: newCaption } ) } - onFocus={ this.onFocusCaption } + unstableOnFocus={ this.onFocusCaption } onBlur={ this.props.onBlur } // always assign onBlur as props isSelected={ this.state.isCaptionSelected } __unstableMobileNoFocusOnMount diff --git a/packages/block-library/src/paragraph/edit.native.js b/packages/block-library/src/paragraph/edit.native.js index 717677658e5a15..6dbcaf8a1459dd 100644 --- a/packages/block-library/src/paragraph/edit.native.js +++ b/packages/block-library/src/paragraph/edit.native.js @@ -57,9 +57,6 @@ class ParagraphEdit extends Component { identifier="content" tagName="p" value={ content } - isSelected={ this.props.isSelected } - onFocus={ this.props.onFocus } // always assign onFocus as a props - onBlur={ this.props.onBlur } // always assign onBlur as a props deleteEnter={ true } style={ style } onChange={ ( nextContent ) => { diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index 07e6fe1be2c6c4..c895abcbebc108 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -89,7 +89,7 @@ class PostTitle extends Component { <RichText tagName={ 'p' } rootTagsToEliminate={ [ 'strong' ] } - onFocus={ this.onSelect } + unstableOnFocus={ this.onSelect } onBlur={ this.props.onBlur } // always assign onBlur as a props multiline={ false } style={ style } From 283ec19af11e5db27bc140ad937619ba50ee613f Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Mon, 10 Jun 2019 03:31:46 -0400 Subject: [PATCH 082/132] [docs] document missing prop in MenuItem (#16061) --- packages/components/src/menu-item/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/components/src/menu-item/README.md b/packages/components/src/menu-item/README.md index 38251ccedf2614..1741f8102992f3 100644 --- a/packages/components/src/menu-item/README.md +++ b/packages/components/src/menu-item/README.md @@ -32,8 +32,6 @@ MenuItem supports the following props. Any additional props are passed through t Element to render as child of button. -Element - ### `info` - Type: `string` @@ -50,6 +48,13 @@ Refer to documentation for [`label`](#label). Refer to documentation for [IconButton's `icon` prop](/packages/components/src/icon-button/README.md#icon). +### `isSelected` + +- Type: `boolean` +- Required: No + +Whether or not the menu item is currently selected. + ### `shortcut` - Type: `string` From a86ca6275de7ce6ca174b939c82375043c824c51 Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Mon, 10 Jun 2019 06:36:53 -0400 Subject: [PATCH 083/132] [docs] fix incorect prop name in KeyboardShortcuts (#16059) * [docs] fix incorect prop name in KeyboardShortcuts * [docs] KeyboardShortcuts - shortcuts prop is required --- packages/components/src/keyboard-shortcuts/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/components/src/keyboard-shortcuts/README.md b/packages/components/src/keyboard-shortcuts/README.md index 4e1bb1a9dd73f3..7c1046087d9b38 100644 --- a/packages/components/src/keyboard-shortcuts/README.md +++ b/packages/components/src/keyboard-shortcuts/README.md @@ -48,13 +48,13 @@ Elements to render, upon whom key events are to be monitored. An object of shortcut bindings, where each key is a keyboard combination, the value of which is the callback to be invoked when the key combination is pressed. - Type: `Object` -- Required: No +- Required: Yes __Note:__ The value of each shortcut should be a consistent function reference, not an anonymous function. Otherwise, the callback will not be correctly unbound when the component unmounts. __Note:__ The `KeyboardShortcuts` component will not update to reflect a changed `shortcuts` prop. If you need to change shortcuts, mount a separate `KeyboardShortcuts` element, which can be achieved by assigning a unique `key` prop. -## bindGlobal +### bindGlobal By default, a callback will not be invoked if the key combination occurs in an editable field. Pass `bindGlobal` as `true` if the key events should be observed globally, including within editable fields. @@ -63,9 +63,9 @@ By default, a callback will not be invoked if the key combination occurs in an e _Tip:_ If you need some but not all keyboard events to be observed globally, simply render two distinct `KeyboardShortcuts` elements, one with and one without the `bindGlobal` prop. -## event +### eventName -By default, a callback is invoked in response to the `keydown` event. To override this, pass `event` with the name of a specific keyboard event. +By default, a callback is invoked in response to the `keydown` event. To override this, pass `eventName` with the name of a specific keyboard event. - Type: `String` - Required: No From bdf3826ae2e214625d6bb259cf1ccf064165af6d Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Mon, 10 Jun 2019 11:42:51 +0100 Subject: [PATCH 084/132] Deprecated the selectors/actions and components that moved to the block editor module (#15770) --- packages/e2e-test-utils/README.md | 2 +- packages/e2e-test-utils/src/get-all-blocks.js | 4 +- .../src/select-block-by-client-id.js | 2 +- .../e2e-test-utils/src/set-post-content.js | 2 +- packages/e2e-tests/plugins/align-hook.php | 2 +- .../e2e-tests/plugins/align-hook/index.js | 2 +- packages/e2e-tests/plugins/block-icons.php | 2 +- .../e2e-tests/plugins/block-icons/index.js | 2 +- .../plugins/container-without-paragraph.php | 2 +- .../container-without-paragraph/index.js | 4 +- .../plugins/deprecated-node-matcher.php | 2 +- .../plugins/deprecated-node-matcher/index.js | 2 +- packages/e2e-tests/plugins/format-api.php | 2 +- .../e2e-tests/plugins/format-api/index.js | 2 +- packages/e2e-tests/plugins/hooks-api.php | 2 +- packages/e2e-tests/plugins/hooks-api/index.js | 2 +- .../plugins/inner-blocks-allowed-blocks.php | 2 +- .../inner-blocks-allowed-blocks/index.js | 4 +- .../plugins/inner-blocks-templates.php | 2 +- .../plugins/inner-blocks-templates/index.js | 2 +- packages/e2e-tests/plugins/plugins-api.php | 3 +- .../plugins-api/annotations-sidebar.js | 4 +- .../e2e-tests/plugins/plugins-api/sidebar.js | 2 +- .../e2e-tests/specs/reusable-blocks.test.js | 4 +- packages/editor/CHANGELOG.md | 147 ++++++++++- packages/editor/src/components/deprecated.js | 246 ++++++++++-------- packages/editor/src/store/actions.js | 3 + packages/editor/src/store/selectors.js | 4 + 28 files changed, 316 insertions(+), 143 deletions(-) diff --git a/packages/e2e-test-utils/README.md b/packages/e2e-test-utils/README.md index 2a3954c47e4b9b..d8f14e5e6c343b 100644 --- a/packages/e2e-test-utils/README.md +++ b/packages/e2e-test-utils/README.md @@ -207,7 +207,7 @@ _Returns_ <a name="getAllBlocks" href="#getAllBlocks">#</a> **getAllBlocks** -Returns an array with all blocks; Equivalent to calling wp.data.select( 'core/editor' ).getBlocks(); +Returns an array with all blocks; Equivalent to calling wp.data.select( 'core/block-editor' ).getBlocks(); _Returns_ diff --git a/packages/e2e-test-utils/src/get-all-blocks.js b/packages/e2e-test-utils/src/get-all-blocks.js index 6f87f827615cba..7aca29bbdcecc2 100644 --- a/packages/e2e-test-utils/src/get-all-blocks.js +++ b/packages/e2e-test-utils/src/get-all-blocks.js @@ -4,10 +4,10 @@ import { wpDataSelect } from './wp-data-select'; /** - * Returns an array with all blocks; Equivalent to calling wp.data.select( 'core/editor' ).getBlocks(); + * Returns an array with all blocks; Equivalent to calling wp.data.select( 'core/block-editor' ).getBlocks(); * * @return {Promise} Promise resolving with an array containing all blocks in the document. */ export function getAllBlocks() { - return wpDataSelect( 'core/editor', 'getBlocks' ); + return wpDataSelect( 'core/block-editor', 'getBlocks' ); } diff --git a/packages/e2e-test-utils/src/select-block-by-client-id.js b/packages/e2e-test-utils/src/select-block-by-client-id.js index cf7e4624d621fc..cfcf8b2bc54d5f 100644 --- a/packages/e2e-test-utils/src/select-block-by-client-id.js +++ b/packages/e2e-test-utils/src/select-block-by-client-id.js @@ -5,6 +5,6 @@ */ export async function selectBlockByClientId( clientId ) { await page.evaluate( ( id ) => { - wp.data.dispatch( 'core/editor' ).selectBlock( id ); + wp.data.dispatch( 'core/block-editor' ).selectBlock( id ); }, clientId ); } diff --git a/packages/e2e-test-utils/src/set-post-content.js b/packages/e2e-test-utils/src/set-post-content.js index 62398b646fc532..18e47c55820033 100644 --- a/packages/e2e-test-utils/src/set-post-content.js +++ b/packages/e2e-test-utils/src/set-post-content.js @@ -8,6 +8,6 @@ export async function setPostContent( content ) { return await page.evaluate( ( _content ) => { const { dispatch } = window.wp.data; const blocks = wp.blocks.parse( _content ); - dispatch( 'core/editor' ).resetBlocks( blocks ); + dispatch( 'core/block-editor' ).resetBlocks( blocks ); }, content ); } diff --git a/packages/e2e-tests/plugins/align-hook.php b/packages/e2e-tests/plugins/align-hook.php index 89435541e3d2ce..dbf5a3cb83a681 100644 --- a/packages/e2e-tests/plugins/align-hook.php +++ b/packages/e2e-tests/plugins/align-hook.php @@ -17,7 +17,7 @@ function enqueue_align_plugin_script() { array( 'wp-blocks', 'wp-element', - 'wp-editor', + 'wp-block-editor', 'wp-i18n', ), filemtime( plugin_dir_path( __FILE__ ) . 'align-hook/index.js' ), diff --git a/packages/e2e-tests/plugins/align-hook/index.js b/packages/e2e-tests/plugins/align-hook/index.js index 927c491e843717..0380758fbaaf05 100644 --- a/packages/e2e-tests/plugins/align-hook/index.js +++ b/packages/e2e-tests/plugins/align-hook/index.js @@ -1,7 +1,7 @@ ( function() { var registerBlockType = wp.blocks.registerBlockType; var el = wp.element.createElement; - var InnerBlocks = wp.editor.InnerBlocks; + var InnerBlocks = wp.blockEditor.InnerBlocks; var __ = wp.i18n.__; var TEMPLATE = [ [ 'core/paragraph', { fontSize: 'large', content: __( 'Content…' ) } ], diff --git a/packages/e2e-tests/plugins/block-icons.php b/packages/e2e-tests/plugins/block-icons.php index 6f79bf7d7e1d6a..ce1013f041c889 100644 --- a/packages/e2e-tests/plugins/block-icons.php +++ b/packages/e2e-tests/plugins/block-icons.php @@ -18,7 +18,7 @@ function enqueue_block_icons_plugin_script() { 'wp-blocks', 'wp-components', 'wp-element', - 'wp-editor', + 'wp-block-editor', 'wp-hooks', 'wp-i18n', ), diff --git a/packages/e2e-tests/plugins/block-icons/index.js b/packages/e2e-tests/plugins/block-icons/index.js index 705b03ebfbc91b..fe05c1d23dcb33 100644 --- a/packages/e2e-tests/plugins/block-icons/index.js +++ b/packages/e2e-tests/plugins/block-icons/index.js @@ -1,7 +1,7 @@ ( function() { var registerBlockType = wp.blocks.registerBlockType; var el = wp.element.createElement; - var InnerBlocks = wp.editor.InnerBlocks; + var InnerBlocks = wp.blockEditor.InnerBlocks; var circle = el( 'circle', { cx: 10, cy: 10, r: 10, fill: 'red', stroke: 'blue', strokeWidth: '10' } ); var svg = el( 'svg', { width: 20, height: 20, viewBox: '0 0 20 20' }, circle ); diff --git a/packages/e2e-tests/plugins/container-without-paragraph.php b/packages/e2e-tests/plugins/container-without-paragraph.php index 315e3eb4258e41..59c06641ce0419 100644 --- a/packages/e2e-tests/plugins/container-without-paragraph.php +++ b/packages/e2e-tests/plugins/container-without-paragraph.php @@ -17,7 +17,7 @@ function enqueue_container_without_paragraph_plugin_script() { array( 'wp-blocks', 'wp-element', - 'wp-editor', + 'wp-block-editor', ), filemtime( plugin_dir_path( __FILE__ ) . 'container-without-paragraph/index.js' ), true diff --git a/packages/e2e-tests/plugins/container-without-paragraph/index.js b/packages/e2e-tests/plugins/container-without-paragraph/index.js index 03eec8105a10aa..7ec20eef893ace 100644 --- a/packages/e2e-tests/plugins/container-without-paragraph/index.js +++ b/packages/e2e-tests/plugins/container-without-paragraph/index.js @@ -5,13 +5,13 @@ icon: 'yes', edit() { - return wp.element.createElement(wp.editor.InnerBlocks, { + return wp.element.createElement(wp.blockEditor.InnerBlocks, { allowedBlocks: ['core/image', 'core/gallery'] }); }, save() { - return wp.element.createElement(wp.editor.InnerBlocks.Content); + return wp.element.createElement(wp.blockEditor.InnerBlocks.Content); }, }) } )(); diff --git a/packages/e2e-tests/plugins/deprecated-node-matcher.php b/packages/e2e-tests/plugins/deprecated-node-matcher.php index 964cc7eec9c362..7e0a6e3d2c5578 100644 --- a/packages/e2e-tests/plugins/deprecated-node-matcher.php +++ b/packages/e2e-tests/plugins/deprecated-node-matcher.php @@ -18,7 +18,7 @@ function enqueue_deprecated_node_matcher_plugin_script() { 'lodash', 'wp-blocks', 'wp-element', - 'wp-editor', + 'wp-block-editor', ), filemtime( plugin_dir_path( __FILE__ ) . 'deprecated-node-matcher/index.js' ), true diff --git a/packages/e2e-tests/plugins/deprecated-node-matcher/index.js b/packages/e2e-tests/plugins/deprecated-node-matcher/index.js index 5f41ed3325afd9..c49c1df95b8360 100644 --- a/packages/e2e-tests/plugins/deprecated-node-matcher/index.js +++ b/packages/e2e-tests/plugins/deprecated-node-matcher/index.js @@ -1,6 +1,6 @@ ( function() { var registerBlockType = wp.blocks.registerBlockType; - var RichText = wp.editor.RichText; + var RichText = wp.blockEditor.RichText; var el = wp.element.createElement; var el = wp.element.createElement; diff --git a/packages/e2e-tests/plugins/format-api.php b/packages/e2e-tests/plugins/format-api.php index dc33462affbc89..cd03a89e76aa48 100644 --- a/packages/e2e-tests/plugins/format-api.php +++ b/packages/e2e-tests/plugins/format-api.php @@ -14,7 +14,7 @@ function gutenberg_test_format_api_scripts() { wp_enqueue_script( 'gutenberg-test-format-api', plugins_url( 'format-api/index.js', __FILE__ ), - array( 'wp-editor', 'wp-element', 'wp-rich-text' ), + array( 'wp-block-editor', 'wp-element', 'wp-rich-text' ), filemtime( plugin_dir_path( __FILE__ ) . 'format-api/index.js' ), true ); diff --git a/packages/e2e-tests/plugins/format-api/index.js b/packages/e2e-tests/plugins/format-api/index.js index 671767e2049269..d22f696737ecdc 100644 --- a/packages/e2e-tests/plugins/format-api/index.js +++ b/packages/e2e-tests/plugins/format-api/index.js @@ -9,7 +9,7 @@ className: 'my-plugin-link', edit: function( props ) { return wp.element.createElement( - wp.editor.RichTextToolbarButton, { + wp.blockEditor.RichTextToolbarButton, { icon: 'admin-links', title: 'Custom Link', onClick: function() { diff --git a/packages/e2e-tests/plugins/hooks-api.php b/packages/e2e-tests/plugins/hooks-api.php index f3533d8d86748c..c4b6d70b95f182 100644 --- a/packages/e2e-tests/plugins/hooks-api.php +++ b/packages/e2e-tests/plugins/hooks-api.php @@ -18,7 +18,7 @@ function enqueue_hooks_plugin_script() { 'wp-blocks', 'wp-components', 'wp-element', - 'wp-editor', + 'wp-block-editor', 'wp-hooks', 'wp-i18n', ), diff --git a/packages/e2e-tests/plugins/hooks-api/index.js b/packages/e2e-tests/plugins/hooks-api/index.js index eb45316565f386..3cfe4ca1590322 100644 --- a/packages/e2e-tests/plugins/hooks-api/index.js +++ b/packages/e2e-tests/plugins/hooks-api/index.js @@ -3,7 +3,7 @@ var Fragment = wp.element.Fragment; var Button = wp.components.Button; var PanelBody = wp.components.PanelBody; - var InspectorControls = wp.editor.InspectorControls; + var InspectorControls = wp.blockEditor.InspectorControls; var addFilter = wp.hooks.addFilter; var createBlock = wp.blocks.createBlock; var __ = wp.i18n.__; diff --git a/packages/e2e-tests/plugins/inner-blocks-allowed-blocks.php b/packages/e2e-tests/plugins/inner-blocks-allowed-blocks.php index 8dcf752ba7df44..a8a0e6ee9a254c 100644 --- a/packages/e2e-tests/plugins/inner-blocks-allowed-blocks.php +++ b/packages/e2e-tests/plugins/inner-blocks-allowed-blocks.php @@ -16,7 +16,7 @@ function enqueue_inner_blocks_allowed_blocks_script() { plugins_url( 'inner-blocks-allowed-blocks/index.js', __FILE__ ), array( 'wp-blocks', - 'wp-editor', + 'wp-block-editor', 'wp-element', 'wp-i18n', ), diff --git a/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js b/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js index 2b1ba6eadd2c1b..f6f61c27d5c82c 100644 --- a/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js +++ b/packages/e2e-tests/plugins/inner-blocks-allowed-blocks/index.js @@ -2,7 +2,7 @@ const { withSelect } = wp.data; const { registerBlockType } = wp.blocks; const { createElement: el } = wp.element; - const { InnerBlocks } = wp.editor; + const { InnerBlocks } = wp.blockEditor; const __ = wp.i18n.__; const divProps = { className: 'product', style: { outline: '1px solid gray', padding: 5 } }; const template = [ @@ -64,7 +64,7 @@ category: 'common', edit: withSelect( function( select, ownProps ) { - var getBlockOrder = select( 'core/editor' ).getBlockOrder; + var getBlockOrder = select( 'core/block-editor' ).getBlockOrder; return { numberOfChildren: getBlockOrder( ownProps.clientId ).length, }; diff --git a/packages/e2e-tests/plugins/inner-blocks-templates.php b/packages/e2e-tests/plugins/inner-blocks-templates.php index 792a2dc0234d15..212992e3619623 100644 --- a/packages/e2e-tests/plugins/inner-blocks-templates.php +++ b/packages/e2e-tests/plugins/inner-blocks-templates.php @@ -18,7 +18,7 @@ function enqueue_container_without_paragraph_plugin_script() { 'wp-blocks', 'wp-components', 'wp-element', - 'wp-editor', + 'wp-block-editor', 'wp-hooks', 'wp-i18n', ), diff --git a/packages/e2e-tests/plugins/inner-blocks-templates/index.js b/packages/e2e-tests/plugins/inner-blocks-templates/index.js index 6c0b62c51fea4e..7d3662f17dbfc4 100644 --- a/packages/e2e-tests/plugins/inner-blocks-templates/index.js +++ b/packages/e2e-tests/plugins/inner-blocks-templates/index.js @@ -2,7 +2,7 @@ var registerBlockType = wp.blocks.registerBlockType; var createBlock = wp.blocks.createBlock; var el = wp.element.createElement; - var InnerBlocks = wp.editor.InnerBlocks; + var InnerBlocks = wp.blockEditor.InnerBlocks; var __ = wp.i18n.__; var TEMPLATE = [ [ 'core/paragraph', { diff --git a/packages/e2e-tests/plugins/plugins-api.php b/packages/e2e-tests/plugins/plugins-api.php index 75c1180e44afc6..a1c91596faea52 100644 --- a/packages/e2e-tests/plugins/plugins-api.php +++ b/packages/e2e-tests/plugins/plugins-api.php @@ -45,6 +45,7 @@ function enqueue_plugins_api_plugin_scripts() { 'wp-compose', 'wp-data', 'wp-edit-post', + 'wp-block-editor', 'wp-editor', 'wp-element', 'wp-i18n', @@ -63,7 +64,7 @@ function enqueue_plugins_api_plugin_scripts() { 'wp-compose', 'wp-data', 'wp-edit-post', - 'wp-editor', + 'wp-block-editor', 'wp-element', 'wp-i18n', 'wp-plugins', diff --git a/packages/e2e-tests/plugins/plugins-api/annotations-sidebar.js b/packages/e2e-tests/plugins/plugins-api/annotations-sidebar.js index 5dfa0e6a52888b..88ff01965f9762 100644 --- a/packages/e2e-tests/plugins/plugins-api/annotations-sidebar.js +++ b/packages/e2e-tests/plugins/plugins-api/annotations-sidebar.js @@ -7,7 +7,7 @@ var withSelect = wp.data.withSelect; var select = wp.data.select; var dispatch = wp.data.dispatch; - var PlainText = wp.editor.PlainText; + var PlainText = wp.blockEditor.PlainText; var Fragment = wp.element.Fragment; var el = wp.element.createElement; var Component = wp.element.Component; @@ -63,7 +63,7 @@ onClick: () => { dispatch( 'core/annotations' ).__experimentalAddAnnotation( { source: 'e2e-tests', - blockClientId: select( 'core/editor' ).getBlockOrder()[ 0 ], + blockClientId: select( 'core/block-editor' ).getBlockOrder()[ 0 ], richTextIdentifier: 'content', range: { start: parseInt( this.state.start, 10 ), diff --git a/packages/e2e-tests/plugins/plugins-api/sidebar.js b/packages/e2e-tests/plugins/plugins-api/sidebar.js index 22038c81c4c928..5ce92bcd4e09a2 100644 --- a/packages/e2e-tests/plugins/plugins-api/sidebar.js +++ b/packages/e2e-tests/plugins/plugins-api/sidebar.js @@ -7,7 +7,7 @@ var withSelect = wp.data.withSelect; var select = wp.data.select; var dispatch = wp.data.dispatch; - var PlainText = wp.editor.PlainText; + var PlainText = wp.blockEditor.PlainText; var Fragment = wp.element.Fragment; var el = wp.element.createElement; var __ = wp.i18n.__; diff --git a/packages/e2e-tests/specs/reusable-blocks.test.js b/packages/e2e-tests/specs/reusable-blocks.test.js index 1eb25f41735e11..81f8db73d48629 100644 --- a/packages/e2e-tests/specs/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/reusable-blocks.test.js @@ -24,9 +24,9 @@ describe( 'Reusable Blocks', () => { beforeEach( async () => { // Remove all blocks from the post so that we're working with a clean slate await page.evaluate( () => { - const blocks = wp.data.select( 'core/editor' ).getBlocks(); + const blocks = wp.data.select( 'core/block-editor' ).getBlocks(); const clientIds = blocks.map( ( block ) => block.clientId ); - wp.data.dispatch( 'core/editor' ).removeBlocks( clientIds ); + wp.data.dispatch( 'core/block-editor' ).removeBlocks( clientIds ); } ); } ); diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md index 921a2b53fdb4a1..2bac55e10ac2e6 100644 --- a/packages/editor/CHANGELOG.md +++ b/packages/editor/CHANGELOG.md @@ -1,3 +1,148 @@ +## Master + +### Deprecations + +- The following components are deprecated as moved to the `@wordpress/block-editor` package: + - Autocomplete, + - AlignmentToolbar, + - BlockAlignmentToolbar, + - BlockControls, + - BlockEdit, + - BlockEditorKeyboardShortcuts, + - BlockFormatControls, + - BlockIcon, + - BlockInspector, + - BlockList, + - BlockMover, + - BlockNavigationDropdown, + - BlockSelectionClearer, + - BlockSettingsMenu, + - BlockTitle, + - BlockToolbar, + - ColorPalette, + - ContrastChecker, + - CopyHandler, + - createCustomColorsHOC, + - DefaultBlockAppender, + - FontSizePicker, + - getColorClassName, + - getColorObjectByAttributeValues, + - getColorObjectByColorValue, + - getFontSize, + - getFontSizeClass, + - Inserter, + - InnerBlocks, + - InspectorAdvancedControls, + - InspectorControls, + - PanelColorSettings, + - PlainText, + - RichText, + - RichTextShortcut, + - RichTextToolbarButton, + - RichTextInserterItem, + - MediaPlaceholder, + - MediaUpload, + - MediaUploadCheck, + - MultiBlocksSwitcher, + - MultiSelectScrollIntoView, + - NavigableToolbar, + - ObserveTyping, + - PreserveScrollInReorder, + - SkipToSelectedBlock, + - URLInput, + - URLInputButton, + - URLPopover, + - Warning, + - WritingFlow, + - withColorContext, + - withColors, + - withFontSizes. +- The following actions are deprecated as moved to the `core/block-editor` store: + - resetBlocks, + - receiveBlocks, + - updateBlock, + - updateBlockAttributes, + - selectBlock, + - startMultiSelect, + - stopMultiSelect, + - multiSelect, + - clearSelectedBlock, + - toggleSelection, + - replaceBlocks, + - replaceBlock, + - moveBlocksDown, + - moveBlocksUp, + - moveBlockToPosition, + - insertBlock, + - insertBlocks, + - showInsertionPoint, + - hideInsertionPoint, + - setTemplateValidity, + - synchronizeTemplate, + - mergeBlocks, + - removeBlocks, + - removeBlock, + - toggleBlockMode, + - startTyping, + - stopTyping, + - enterFormattedText, + - exitFormattedText, + - insertDefaultBlock, + - updateBlockListSettings. +- The following selectors are deprecated as moved to the `core/block-editor` store: + - getBlockDependantsCacheBust, + - getBlockName, + - isBlockValid, + - getBlockAttributes, + - getBlock, + - getBlocks, + - getClientIdsOfDescendants, + - getClientIdsWithDescendants, + - getGlobalBlockCount, + - getBlocksByClientId, + - getBlockCount, + - getBlockSelectionStart, + - getBlockSelectionEnd, + - getSelectedBlockCount, + - hasSelectedBlock, + - getSelectedBlockClientId, + - getSelectedBlock, + - getBlockRootClientId, + - getBlockHierarchyRootClientId, + - getAdjacentBlockClientId, + - getPreviousBlockClientId, + - getNextBlockClientId, + - getSelectedBlocksInitialCaretPosition, + - getMultiSelectedBlockClientIds, + - getMultiSelectedBlocks, + - getFirstMultiSelectedBlockClientId, + - getLastMultiSelectedBlockClientId, + - isFirstMultiSelectedBlock, + - isBlockMultiSelected, + - isAncestorMultiSelected, + - getMultiSelectedBlocksStartClientId, + - getMultiSelectedBlocksEndClientId, + - getBlockOrder, + - getBlockIndex, + - isBlockSelected, + - hasSelectedInnerBlock, + - isBlockWithinSelection, + - hasMultiSelection, + - isMultiSelecting, + - isSelectionEnabled, + - getBlockMode =, + - isTyping, + - isCaretWithinFormattedText, + - getBlockInsertionPoint, + - isBlockInsertionPointVisible, + - isValidTemplate, + - getTemplate, + - getTemplateLock, + - canInsertBlockType, + - getInserterItems, + - hasInserterItems, + - getBlockListSettings. + ## 9.3.0 (2019-05-21) ### Deprecations @@ -5,8 +150,6 @@ - The `resetAutosave` action is deprecated. An equivalent action `receiveAutosaves` has been added to the `@wordpress/core-data` package. - `ServerSideRender` component was deprecated. The component is now available in `@wordpress/server-side-render`. - - ### Internal - Refactor setupEditor effects to action-generator using controls ([#14513](https://github.com/WordPress/gutenberg/pull/14513)) diff --git a/packages/editor/src/components/deprecated.js b/packages/editor/src/components/deprecated.js index 330116fabec58e..44758b2ea29a4e 100644 --- a/packages/editor/src/components/deprecated.js +++ b/packages/editor/src/components/deprecated.js @@ -2,119 +2,141 @@ /** * WordPress dependencies */ +import deprecated from '@wordpress/deprecated'; +import { forwardRef } from '@wordpress/element'; import { - Autocomplete, - AlignmentToolbar, - BlockAlignmentToolbar, - BlockControls, - BlockEdit, - BlockEditorKeyboardShortcuts, - BlockFormatControls, - BlockIcon, - BlockInspector, - BlockList, - BlockMover, - BlockNavigationDropdown, - BlockSelectionClearer, - BlockSettingsMenu, - BlockTitle, - BlockToolbar, - ColorPalette, - ContrastChecker, - CopyHandler, - createCustomColorsHOC, - DefaultBlockAppender, - FontSizePicker, - getColorClassName, - getColorObjectByAttributeValues, - getColorObjectByColorValue, - getFontSize, - getFontSizeClass, - Inserter, - InnerBlocks, - InspectorAdvancedControls, - InspectorControls, - PanelColorSettings, - PlainText, - RichText, - RichTextShortcut, - RichTextToolbarButton, - RichTextInserterItem, - __unstableRichTextInputEvent, - MediaPlaceholder, - MediaUpload, - MediaUploadCheck, - MultiBlocksSwitcher, - MultiSelectScrollIntoView, - NavigableToolbar, - ObserveTyping, - PreserveScrollInReorder, - SkipToSelectedBlock, - URLInput, - URLInputButton, - URLPopover, - Warning, - WritingFlow, - withColorContext, - withColors, - withFontSizes, + Autocomplete as RootAutocomplete, + AlignmentToolbar as RootAlignmentToolbar, + BlockAlignmentToolbar as RootBlockAlignmentToolbar, + BlockControls as RootBlockControls, + BlockEdit as RootBlockEdit, + BlockEditorKeyboardShortcuts as RootBlockEditorKeyboardShortcuts, + BlockFormatControls as RootBlockFormatControls, + BlockIcon as RootBlockIcon, + BlockInspector as RootBlockInspector, + BlockList as RootBlockList, + BlockMover as RootBlockMover, + BlockNavigationDropdown as RootBlockNavigationDropdown, + BlockSelectionClearer as RootBlockSelectionClearer, + BlockSettingsMenu as RootBlockSettingsMenu, + BlockTitle as RootBlockTitle, + BlockToolbar as RootBlockToolbar, + ColorPalette as RootColorPalette, + ContrastChecker as RootContrastChecker, + CopyHandler as RootCopyHandler, + createCustomColorsHOC as rootCreateCustomColorsHOC, + DefaultBlockAppender as RootDefaultBlockAppender, + FontSizePicker as RootFontSizePicker, + getColorClassName as rootGetColorClassName, + getColorObjectByAttributeValues as rootGetColorObjectByAttributeValues, + getColorObjectByColorValue as rootGetColorObjectByColorValue, + getFontSize as rootGetFontSize, + getFontSizeClass as rootGetFontSizeClass, + Inserter as RootInserter, + InnerBlocks as RootInnerBlocks, + InspectorAdvancedControls as RootInspectorAdvancedControls, + InspectorControls as RootInspectorControls, + PanelColorSettings as RootPanelColorSettings, + PlainText as RootPlainText, + RichText as RootRichText, + RichTextShortcut as RootRichTextShortcut, + RichTextToolbarButton as RootRichTextToolbarButton, + RichTextInserterItem as RootRichTextInserterItem, + __unstableRichTextInputEvent as __unstableRootRichTextInputEvent, + MediaPlaceholder as RootMediaPlaceholder, + MediaUpload as RootMediaUpload, + MediaUploadCheck as RootMediaUploadCheck, + MultiBlocksSwitcher as RootMultiBlocksSwitcher, + MultiSelectScrollIntoView as RootMultiSelectScrollIntoView, + NavigableToolbar as RootNavigableToolbar, + ObserveTyping as RootObserveTyping, + PreserveScrollInReorder as RootPreserveScrollInReorder, + SkipToSelectedBlock as RootSkipToSelectedBlock, + URLInput as RootURLInput, + URLInputButton as RootURLInputButton, + URLPopover as RootURLPopover, + Warning as RootWarning, + WritingFlow as RootWritingFlow, + withColorContext as rootWithColorContext, + withColors as rootWithColors, + withFontSizes as rootWithFontSizes, } from '@wordpress/block-editor'; -export { - Autocomplete, - AlignmentToolbar, - BlockAlignmentToolbar, - BlockControls, - BlockEdit, - BlockEditorKeyboardShortcuts, - BlockFormatControls, - BlockIcon, - BlockInspector, - BlockList, - BlockMover, - BlockNavigationDropdown, - BlockSelectionClearer, - BlockSettingsMenu, - BlockTitle, - BlockToolbar, - ColorPalette, - ContrastChecker, - CopyHandler, - createCustomColorsHOC, - DefaultBlockAppender, - FontSizePicker, - getColorClassName, - getColorObjectByAttributeValues, - getColorObjectByColorValue, - getFontSize, - getFontSizeClass, - Inserter, - InnerBlocks, - InspectorAdvancedControls, - InspectorControls, - PanelColorSettings, - PlainText, - RichText, - RichTextShortcut, - RichTextToolbarButton, - RichTextInserterItem, - __unstableRichTextInputEvent, - MediaPlaceholder, - MediaUpload, - MediaUploadCheck, - MultiBlocksSwitcher, - MultiSelectScrollIntoView, - NavigableToolbar, - ObserveTyping, - PreserveScrollInReorder, - SkipToSelectedBlock, - URLInput, - URLInputButton, - URLPopover, - Warning, - WritingFlow, - withColorContext, - withColors, - withFontSizes, -}; export { default as ServerSideRender } from '@wordpress/server-side-render'; + +function deprecateComponent( name, Wrapped ) { + return forwardRef( ( props, ref ) => { + deprecated( 'wp.editor.' + name, { + alternative: 'wp.blockEditor.' + name, + } ); + + return <Wrapped ref={ ref }{ ...props } />; + } ); +} + +function deprecateFunction( name, func ) { + return ( ...args ) => { + deprecated( 'wp.editor.' + name, { + alternative: 'wp.blockEditor.' + name, + } ); + + return func( ...args ); + }; +} + +export const Autocomplete = deprecateComponent( 'Autocomplete', RootAutocomplete ); +export const AlignmentToolbar = deprecateComponent( 'AlignmentToolbar', RootAlignmentToolbar ); +export const BlockAlignmentToolbar = deprecateComponent( 'BlockAlignmentToolbar', RootBlockAlignmentToolbar ); +export const BlockControls = deprecateComponent( 'BlockControls', RootBlockControls ); +export const BlockEdit = deprecateComponent( 'BlockEdit', RootBlockEdit ); +export const BlockEditorKeyboardShortcuts = deprecateComponent( 'BlockEditorKeyboardShortcuts', RootBlockEditorKeyboardShortcuts ); +export const BlockFormatControls = deprecateComponent( 'BlockFormatControls', RootBlockFormatControls ); +export const BlockIcon = deprecateComponent( 'BlockIcon', RootBlockIcon ); +export const BlockInspector = deprecateComponent( 'BlockInspector', RootBlockInspector ); +export const BlockList = deprecateComponent( 'BlockList', RootBlockList ); +export const BlockMover = deprecateComponent( 'BlockMover', RootBlockMover ); +export const BlockNavigationDropdown = deprecateComponent( 'BlockNavigationDropdown', RootBlockNavigationDropdown ); +export const BlockSelectionClearer = deprecateComponent( 'BlockSelectionClearer', RootBlockSelectionClearer ); +export const BlockSettingsMenu = deprecateComponent( 'BlockSettingsMenu', RootBlockSettingsMenu ); +export const BlockTitle = deprecateComponent( 'BlockTitle', RootBlockTitle ); +export const BlockToolbar = deprecateComponent( 'BlockToolbar', RootBlockToolbar ); +export const ColorPalette = deprecateComponent( 'ColorPalette', RootColorPalette ); +export const ContrastChecker = deprecateComponent( 'ContrastChecker', RootContrastChecker ); +export const CopyHandler = deprecateComponent( 'CopyHandler', RootCopyHandler ); +export const DefaultBlockAppender = deprecateComponent( 'DefaultBlockAppender', RootDefaultBlockAppender ); +export const FontSizePicker = deprecateComponent( 'FontSizePicker', RootFontSizePicker ); +export const Inserter = deprecateComponent( 'Inserter', RootInserter ); +export const InnerBlocks = deprecateComponent( 'InnerBlocks', RootInnerBlocks ); +export const InspectorAdvancedControls = deprecateComponent( 'InspectorAdvancedControls', RootInspectorAdvancedControls ); +export const InspectorControls = deprecateComponent( 'InspectorControls', RootInspectorControls ); +export const PanelColorSettings = deprecateComponent( 'PanelColorSettings', RootPanelColorSettings ); +export const PlainText = deprecateComponent( 'PlainText', RootPlainText ); +export const RichText = deprecateComponent( 'RichText', RootRichText ); +export const RichTextShortcut = deprecateComponent( 'RichTextShortcut', RootRichTextShortcut ); +export const RichTextToolbarButton = deprecateComponent( 'RichTextToolbarButton', RootRichTextToolbarButton ); +export const RichTextInserterItem = deprecateComponent( 'RichTextInserterItem', RootRichTextInserterItem ); +export const __unstableRichTextInputEvent = deprecateComponent( '__unstableRichTextInputEvent', __unstableRootRichTextInputEvent ); +export const MediaPlaceholder = deprecateComponent( 'MediaPlaceholder', RootMediaPlaceholder ); +export const MediaUpload = deprecateComponent( 'MediaUpload', RootMediaUpload ); +export const MediaUploadCheck = deprecateComponent( 'MediaUploadCheck', RootMediaUploadCheck ); +export const MultiBlocksSwitcher = deprecateComponent( 'MultiBlocksSwitcher', RootMultiBlocksSwitcher ); +export const MultiSelectScrollIntoView = deprecateComponent( 'MultiSelectScrollIntoView', RootMultiSelectScrollIntoView ); +export const NavigableToolbar = deprecateComponent( 'NavigableToolbar', RootNavigableToolbar ); +export const ObserveTyping = deprecateComponent( 'ObserveTyping', RootObserveTyping ); +export const PreserveScrollInReorder = deprecateComponent( 'PreserveScrollInReorder', RootPreserveScrollInReorder ); +export const SkipToSelectedBlock = deprecateComponent( 'SkipToSelectedBlock', RootSkipToSelectedBlock ); +export const URLInput = deprecateComponent( 'URLInput', RootURLInput ); +export const URLInputButton = deprecateComponent( 'URLInputButton', RootURLInputButton ); +export const URLPopover = deprecateComponent( 'URLPopover', RootURLPopover ); +export const Warning = deprecateComponent( 'Warning', RootWarning ); +export const WritingFlow = deprecateComponent( 'WritingFlow', RootWritingFlow ); + +export const createCustomColorsHOC = deprecateFunction( 'createCustomColorsHOC', rootCreateCustomColorsHOC ); +export const getColorClassName = deprecateFunction( 'getColorClassName', rootGetColorClassName ); +export const getColorObjectByAttributeValues = deprecateFunction( 'getColorObjectByAttributeValues', rootGetColorObjectByAttributeValues ); +export const getColorObjectByColorValue = deprecateFunction( 'getColorObjectByColorValue', rootGetColorObjectByColorValue ); +export const getFontSize = deprecateFunction( 'getFontSize', rootGetFontSize ); +export const getFontSizeClass = deprecateFunction( 'getFontSizeClass', rootGetFontSizeClass ); +export const withColorContext = deprecateFunction( 'withColorContext', rootWithColorContext ); +export const withColors = deprecateFunction( 'withColors', rootWithColors ); +export const withFontSizes = deprecateFunction( 'withFontSizes', rootWithFontSizes ); diff --git a/packages/editor/src/store/actions.js b/packages/editor/src/store/actions.js index 03548de3f93abc..073887663bd1b9 100644 --- a/packages/editor/src/store/actions.js +++ b/packages/editor/src/store/actions.js @@ -757,6 +757,9 @@ export function updateEditorSettings( settings ) { */ const getBlockEditorAction = ( name ) => function* ( ...args ) { + deprecated( '`wp.data.dispatch( \'core/editor\' ).' + name + '`', { + alternative: '`wp.data.dispatch( \'core/block-editor\' ).' + name + '`', + } ); yield dispatch( 'core/block-editor', name, ...args ); }; diff --git a/packages/editor/src/store/selectors.js b/packages/editor/src/store/selectors.js index 094b47bc716774..7570e8b7848de6 100644 --- a/packages/editor/src/store/selectors.js +++ b/packages/editor/src/store/selectors.js @@ -1160,6 +1160,10 @@ export function getEditorSettings( state ) { function getBlockEditorSelector( name ) { return createRegistrySelector( ( select ) => ( state, ...args ) => { + deprecated( '`wp.data.select( \'core/editor\' ).' + name + '`', { + alternative: '`wp.data.select( \'core/block-editor\' ).' + name + '`', + } ); + return select( 'core/block-editor' )[ name ]( ...args ); } ); } From 6c6e86ce2f5a0b05ed77abe7a2afdcd898fda47b Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Mon, 10 Jun 2019 12:09:13 +0100 Subject: [PATCH 085/132] Update browserslist dependency to fix unit tests (#16066) --- package-lock.json | 50 +++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index c8943767a50d28..efb7105ba3676e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5146,44 +5146,36 @@ } }, "browserslist": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.1.tgz", - "integrity": "sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.2.tgz", + "integrity": "sha512-2neU/V0giQy9h3XMPwLhEY3+Ao0uHSwHvU8Q1Ea6AgLVL1sXbX3dzPrJ8NWe5Hi4PoTkCYXOtVR9rfRLI0J/8Q==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000929", - "electron-to-chromium": "^1.3.103", - "node-releases": "^1.1.3" + "caniuse-lite": "^1.0.30000974", + "electron-to-chromium": "^1.3.150", + "node-releases": "^1.1.23" }, "dependencies": { "caniuse-lite": { - "version": "1.0.30000929", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000929.tgz", - "integrity": "sha512-n2w1gPQSsYyorSVYqPMqbSaz1w7o9ZC8VhOEGI9T5MfGDzp7sbopQxG6GaQmYsaq13Xfx/mkxJUWC1Dz3oZfzw==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.103", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.103.tgz", - "integrity": "sha512-tObPqGmY9X8MUM8i3MEimYmbnLLf05/QV5gPlkR8MQ3Uj8G8B2govE1U4cQcBYtv3ymck9Y8cIOu4waoiykMZQ==", + "version": "1.0.30000974", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000974.tgz", + "integrity": "sha512-xc3rkNS/Zc3CmpMKuczWEdY2sZgx09BkAxfvkxlAEBTqcMHeL8QnPqhKse+5sRTi3nrw2pJwToD2WvKn1Uhvww==", "dev": true }, "node-releases": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.3.tgz", - "integrity": "sha512-6VrvH7z6jqqNFY200kdB6HdzkgM96Oaj9v3dqGfgp6mF+cHmU4wyQKZ2/WPDRVoR0Jz9KqbamaBN0ZhdUaysUQ==", + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.23.tgz", + "integrity": "sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==", "dev": true, "requires": { "semver": "^5.3.0" - }, - "dependencies": { - "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true - } } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true } } }, @@ -8256,6 +8248,12 @@ "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==", "dev": true }, + "electron-to-chromium": { + "version": "1.3.155", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.155.tgz", + "integrity": "sha512-/ci/XgZG8jkLYOgOe3mpJY1onxPPTDY17y7scldhnSjjZqV6VvREG/LvwhRuV7BJbnENFfuDWZkSqlTh4x9ZjQ==", + "dev": true + }, "elegant-spinner": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", diff --git a/package.json b/package.json index 62de2dba7741d3..eec8121079e2e9 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "@wordpress/scripts": "file:packages/scripts", "babel-plugin-inline-json-import": "0.3.2", "benchmark": "2.1.4", - "browserslist": "4.4.1", + "browserslist": "4.6.2", "chalk": "2.4.1", "commander": "2.20.0", "concurrently": "3.5.0", From b62fc876f857b337211d79743f7867e4da1bad6f Mon Sep 17 00:00:00 2001 From: Darren Ethier <darren@roughsmootheng.in> Date: Mon, 10 Jun 2019 08:44:34 -0400 Subject: [PATCH 086/132] Bump plugin version to 5.9.0-rc.1 --- gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 1cef2b3380e4bf..d9c384353ca202 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -3,7 +3,7 @@ * Plugin Name: Gutenberg * Plugin URI: https://github.com/WordPress/gutenberg * Description: Printing since 1440. This is the development plugin for the new block editor in core. - * Version: 5.8.0 + * Version: 5.9.0-rc.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index efb7105ba3676e..aa639527442e65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.8.0", + "version": "5.9.0-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index eec8121079e2e9..4ff2130f820687 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.8.0", + "version": "5.9.0-rc.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From df09f3ea0ad54f9c0244a58ea6632e362cfcfeba Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Mon, 10 Jun 2019 14:14:21 +0100 Subject: [PATCH 087/132] Explicitely push to the release branch (#16070) --- bin/commander.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bin/commander.js b/bin/commander.js index 3412492ce062f4..9eeae01834ac55 100755 --- a/bin/commander.js +++ b/bin/commander.js @@ -278,6 +278,7 @@ async function runReleaseBranchCreationStep( abortMessage ) { return { version, versionLabel, + releaseBranch, }; } @@ -320,6 +321,7 @@ async function runReleaseBranchCheckoutStep( abortMessage ) { return { version, versionLabel: version, + releaseBranch, }; } @@ -415,9 +417,10 @@ async function runCreateGitTagStep( version, abortMessage ) { /** * Push the local Git Changes and Tags to the remote repository. * - * @param {string} abortMessage Abort message. + * @param {string} releaseBranch Release branch name. + * @param {string} abortMessage Abort message. */ -async function runPushGitChangesStep( abortMessage ) { +async function runPushGitChangesStep( releaseBranch, abortMessage ) { await runStep( 'Pushing the release branch and the tag', abortMessage, async () => { const simpleGit = SimpleGit( gitWorkingDirectoryPath ); await askForConfirmationToContinue( @@ -425,7 +428,7 @@ async function runPushGitChangesStep( abortMessage ) { true, abortMessage ); - await simpleGit.push( 'origin' ); + await simpleGit.push( 'origin', releaseBranch ); await simpleGit.pushTags( 'origin' ); } ); } @@ -539,7 +542,7 @@ async function releasePlugin( isRC = true ) { await runGitRepositoryCloneStep( abortMessage ); // Creating the release branch - const { version, versionLabel } = isRC ? + const { version, versionLabel, releaseBranch } = isRC ? await runReleaseBranchCreationStep( abortMessage ) : await runReleaseBranchCheckoutStep( abortMessage ); @@ -553,7 +556,7 @@ async function releasePlugin( isRC = true ) { await runCreateGitTagStep( version, abortMessage ); // Push the local changes - await runPushGitChangesStep( abortMessage ); + await runPushGitChangesStep( releaseBranch, abortMessage ); abortMessage = 'Aborting! Make sure to ' + isRC ? 'remove' : 'reset' + ' the remote release branch and remove the git tag.'; // Creating the GitHub Release From 74e950ab5d920489b18626ec7deaeba0851cfe6f Mon Sep 17 00:00:00 2001 From: Vadim Nicolai <vadim.nicolai@moduscreate.com> Date: Mon, 10 Jun 2019 17:53:22 +0300 Subject: [PATCH 088/132] Update for MediaPlaceholder component: don't stack error messages when re-uploading (#14721) * Used removeAllNotices in onUploadError. * Updated GalleryEdit. * Updated MediaTextEdit. * Updated VideoEdit. * Updated CoverEdit. * Updated FileEdit. * Fixed tab spaces. --- packages/block-library/src/audio/edit.js | 11 +++++++++-- packages/block-library/src/cover/edit.js | 10 ++++++++-- packages/block-library/src/file/edit.js | 10 ++++++++-- packages/block-library/src/gallery/edit.js | 11 +++++++++-- packages/block-library/src/image/edit.js | 1 + .../src/media-text/media-container.js | 19 ++++++++++++++++--- packages/block-library/src/video/edit.js | 10 ++++++++-- 7 files changed, 59 insertions(+), 13 deletions(-) diff --git a/packages/block-library/src/audio/edit.js b/packages/block-library/src/audio/edit.js index 1545378ddc0c74..a518f077011e6a 100644 --- a/packages/block-library/src/audio/edit.js +++ b/packages/block-library/src/audio/edit.js @@ -45,6 +45,7 @@ class AudioEdit extends Component { this.toggleAttribute = this.toggleAttribute.bind( this ); this.onSelectURL = this.onSelectURL.bind( this ); + this.onUploadError = this.onUploadError.bind( this ); } componentDidMount() { @@ -98,13 +99,19 @@ class AudioEdit extends Component { this.setState( { editing: false } ); } + onUploadError( message ) { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + getAutoplayHelp( checked ) { return checked ? __( 'Note: Autoplaying audio may cause usability issues for some visitors.' ) : null; } render() { const { autoplay, caption, loop, preload, src } = this.props.attributes; - const { setAttributes, isSelected, className, noticeOperations, noticeUI } = this.props; + const { setAttributes, isSelected, className, noticeUI } = this.props; const { editing } = this.state; const switchToEditing = () => { this.setState( { editing: true } ); @@ -133,7 +140,7 @@ class AudioEdit extends Component { allowedTypes={ ALLOWED_MEDIA_TYPES } value={ this.props.attributes } notices={ noticeUI } - onError={ noticeOperations.createErrorNotice } + onError={ this.onUploadError } /> ); } diff --git a/packages/block-library/src/cover/edit.js b/packages/block-library/src/cover/edit.js index b7cb4ea6984eb1..05bb57786332df 100644 --- a/packages/block-library/src/cover/edit.js +++ b/packages/block-library/src/cover/edit.js @@ -72,6 +72,7 @@ class CoverEdit extends Component { this.imageRef = createRef(); this.videoRef = createRef(); this.changeIsDarkIfRequired = this.changeIsDarkIfRequired.bind( this ); + this.onUploadError = this.onUploadError.bind( this ); } componentDidMount() { @@ -82,12 +83,17 @@ class CoverEdit extends Component { this.handleBackgroundMode( prevProps ); } + onUploadError( message ) { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + render() { const { attributes, setAttributes, className, - noticeOperations, noticeUI, overlayColor, setOverlayColor, @@ -243,7 +249,7 @@ class CoverEdit extends Component { accept="image/*,video/*" allowedTypes={ ALLOWED_MEDIA_TYPES } notices={ noticeUI } - onError={ noticeOperations.createErrorNotice } + onError={ this.onUploadError } /> </> ); diff --git a/packages/block-library/src/file/edit.js b/packages/block-library/src/file/edit.js index efa93424a5a9e6..f06d2be38c98a7 100644 --- a/packages/block-library/src/file/edit.js +++ b/packages/block-library/src/file/edit.js @@ -47,6 +47,7 @@ class FileEdit extends Component { this.changeLinkDestinationOption = this.changeLinkDestinationOption.bind( this ); this.changeOpenInNewWindow = this.changeOpenInNewWindow.bind( this ); this.changeShowDownloadButton = this.changeShowDownloadButton.bind( this ); + this.onUploadError = this.onUploadError.bind( this ); this.state = { hasError: false, @@ -100,6 +101,12 @@ class FileEdit extends Component { } } + onUploadError( message ) { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + confirmCopyURL() { this.setState( { showCopyConfirmation: true } ); } @@ -130,7 +137,6 @@ class FileEdit extends Component { attributes, setAttributes, noticeUI, - noticeOperations, media, } = this.props; const { @@ -155,7 +161,7 @@ class FileEdit extends Component { } } onSelect={ this.onSelectFile } notices={ noticeUI } - onError={ noticeOperations.createErrorNotice } + onError={ this.onUploadError } accept="*" /> ); diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index cb1188c010ba1b..c5aebed551849f 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -54,6 +54,7 @@ class GalleryEdit extends Component { this.onMoveForward = this.onMoveForward.bind( this ); this.onMoveBackward = this.onMoveBackward.bind( this ); this.onRemoveImage = this.onRemoveImage.bind( this ); + this.onUploadError = this.onUploadError.bind( this ); this.setImageAttributes = this.setImageAttributes.bind( this ); this.setAttributes = this.setAttributes.bind( this ); @@ -133,6 +134,12 @@ class GalleryEdit extends Component { } ); } + onUploadError( message ) { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + setLinkTo( value ) { this.setAttributes( { linkTo: value } ); } @@ -178,7 +185,7 @@ class GalleryEdit extends Component { } render() { - const { attributes, isSelected, className, noticeOperations, noticeUI } = this.props; + const { attributes, isSelected, className, noticeUI } = this.props; const { images, columns = defaultColumnsNumber( attributes ), align, imageCrop, linkTo } = attributes; const hasImages = !! images.length; @@ -223,7 +230,7 @@ class GalleryEdit extends Component { allowedTypes={ ALLOWED_MEDIA_TYPES } multiple value={ hasImages ? images : undefined } - onError={ noticeOperations.createErrorNotice } + onError={ this.onUploadError } notices={ hasImages ? undefined : noticeUI } /> ); diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 645248bc702414..ecc498e2988fc9 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -165,6 +165,7 @@ class ImageEdit extends Component { onUploadError( message ) { const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); noticeOperations.createErrorNotice( message ); this.setState( { isEditing: true, diff --git a/packages/block-library/src/media-text/media-container.js b/packages/block-library/src/media-text/media-container.js index 9afc28c58b3a7c..74d2062d524d9c 100644 --- a/packages/block-library/src/media-text/media-container.js +++ b/packages/block-library/src/media-text/media-container.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { IconButton, ResizableBox, Toolbar } from '@wordpress/components'; +import { IconButton, ResizableBox, Toolbar, withNotices } from '@wordpress/components'; import { BlockControls, BlockIcon, @@ -31,6 +31,17 @@ export function imageFillStyles( url, focalPoint ) { } class MediaContainer extends Component { + constructor() { + super( ...arguments ); + this.onUploadError = this.onUploadError.bind( this ); + } + + onUploadError( message ) { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + renderToolbarEditButton() { const { mediaId, onSelectMedia } = this.props; return ( @@ -80,7 +91,7 @@ class MediaContainer extends Component { } renderPlaceholder() { - const { onSelectMedia, className } = this.props; + const { onSelectMedia, className, noticeUI } = this.props; return ( <MediaPlaceholder icon={ <BlockIcon icon={ icon } /> } @@ -91,6 +102,8 @@ class MediaContainer extends Component { onSelect={ onSelectMedia } accept="image/*,video/*" allowedTypes={ ALLOWED_MEDIA_TYPES } + notices={ noticeUI } + onError={ this.onUploadError } /> ); } @@ -137,4 +150,4 @@ class MediaContainer extends Component { } } -export default MediaContainer; +export default withNotices( MediaContainer ); diff --git a/packages/block-library/src/video/edit.js b/packages/block-library/src/video/edit.js index 0f2939fe1f6a5e..f8380b7edeafc6 100644 --- a/packages/block-library/src/video/edit.js +++ b/packages/block-library/src/video/edit.js @@ -57,6 +57,7 @@ class VideoEdit extends Component { this.onSelectURL = this.onSelectURL.bind( this ); this.onSelectPoster = this.onSelectPoster.bind( this ); this.onRemovePoster = this.onRemovePoster.bind( this ); + this.onUploadError = this.onUploadError.bind( this ); } componentDidMount() { @@ -126,6 +127,12 @@ class VideoEdit extends Component { this.posterImageButton.current.focus(); } + onUploadError( message ) { + const { noticeOperations } = this.props; + noticeOperations.removeAllNotices(); + noticeOperations.createErrorNotice( message ); + } + getAutoplayHelp( checked ) { return checked ? __( 'Note: Autoplaying videos may cause usability issues for some visitors.' ) : null; } @@ -146,7 +153,6 @@ class VideoEdit extends Component { className, instanceId, isSelected, - noticeOperations, noticeUI, setAttributes, } = this.props; @@ -179,7 +185,7 @@ class VideoEdit extends Component { allowedTypes={ ALLOWED_MEDIA_TYPES } value={ this.props.attributes } notices={ noticeUI } - onError={ noticeOperations.createErrorNotice } + onError={ this.onUploadError } /> ); } From 0dafd4de778175aaef08de6b3ab1128e21063301 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Mon, 10 Jun 2019 11:52:59 -0400 Subject: [PATCH 089/132] Editor: Create own sub-registry in default EditorProvider use (#15989) --- packages/block-editor/README.md | 12 +++++ packages/block-editor/src/index.js | 2 +- packages/block-editor/src/store/index.js | 7 +++ packages/edit-post/src/editor.js | 1 + .../editor/src/components/provider/index.js | 2 + .../provider/with-registry-provider.js | 46 +++++++++++++++++++ packages/editor/src/index.js | 1 + packages/editor/src/store/index.js | 13 +++++- 8 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 packages/editor/src/components/provider/with-registry-provider.js diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 6467b59284706f..ff1a8579a0b016 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -375,6 +375,18 @@ The default editor settings Undocumented declaration. +<a name="storeConfig" href="#storeConfig">#</a> **storeConfig** + +Block editor data store configuration. + +_Related_ + +- <https://github.com/WordPress/gutenberg/blob/master/packages/data/README.md#registerStore> + +_Type_ + +- `Object` + <a name="URLInput" href="#URLInput">#</a> **URLInput** _Related_ diff --git a/packages/block-editor/src/index.js b/packages/block-editor/src/index.js index 1d8827e2a33b49..d554e6e577a385 100644 --- a/packages/block-editor/src/index.js +++ b/packages/block-editor/src/index.js @@ -14,5 +14,5 @@ import './hooks'; export * from './components'; export * from './utils'; - +export { storeConfig } from './store'; export { SETTINGS_DEFAULTS } from './store/defaults'; diff --git a/packages/block-editor/src/store/index.js b/packages/block-editor/src/store/index.js index 485238f46f606d..bfc7766a508762 100644 --- a/packages/block-editor/src/store/index.js +++ b/packages/block-editor/src/store/index.js @@ -17,6 +17,13 @@ import controls from './controls'; */ const MODULE_KEY = 'core/block-editor'; +/** + * Block editor data store configuration. + * + * @see https://github.com/WordPress/gutenberg/blob/master/packages/data/README.md#registerStore + * + * @type {Object} + */ export const storeConfig = { reducer, selectors, diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js index 28e55b08d6cbf6..ea48a3a1d8e358 100644 --- a/packages/edit-post/src/editor.js +++ b/packages/edit-post/src/editor.js @@ -91,6 +91,7 @@ class Editor extends Component { settings={ editorSettings } post={ post } initialEdits={ initialEdits } + useSubRegistry={ false } { ...props } > <ErrorBoundary onError={ onError }> diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index e897931daf6c42..0e959f80c7b866 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -19,6 +19,7 @@ import { decodeEntities } from '@wordpress/html-entities'; /** * Internal dependencies */ +import withRegistryProvider from './with-registry-provider'; import { mediaUpload } from '../../utils'; import ReusableBlocksButtons from '../reusable-blocks-buttons'; import ConvertToGroupButtons from '../convert-to-group-buttons'; @@ -167,6 +168,7 @@ class EditorProvider extends Component { } export default compose( [ + withRegistryProvider, withSelect( ( select ) => { const { __unstableIsEditorReady: isEditorReady, diff --git a/packages/editor/src/components/provider/with-registry-provider.js b/packages/editor/src/components/provider/with-registry-provider.js new file mode 100644 index 00000000000000..367782a82b4a42 --- /dev/null +++ b/packages/editor/src/components/provider/with-registry-provider.js @@ -0,0 +1,46 @@ +/** + * WordPress dependencies + */ +import { useState, useEffect } from '@wordpress/element'; +import { withRegistry, createRegistry, RegistryProvider } from '@wordpress/data'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { storeConfig as blockEditorStoreConfig } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { storeConfig } from '../../store'; +import applyMiddlewares from '../../store/middlewares'; + +const withRegistryProvider = createHigherOrderComponent( + ( WrappedComponent ) => withRegistry( ( props ) => { + const { useSubRegistry = true, registry, ...additionalProps } = props; + if ( ! useSubRegistry ) { + return <WrappedComponent { ...additionalProps } />; + } + + const [ subRegistry, setSubRegistry ] = useState( null ); + useEffect( () => { + const newRegistry = createRegistry( { + 'core/block-editor': blockEditorStoreConfig, + }, registry ); + const store = newRegistry.registerStore( 'core/editor', storeConfig ); + // This should be removed after the refactoring of the effects to controls. + applyMiddlewares( store ); + setSubRegistry( newRegistry ); + }, [ registry ] ); + + if ( ! subRegistry ) { + return null; + } + + return ( + <RegistryProvider value={ subRegistry }> + <WrappedComponent { ...additionalProps } /> + </RegistryProvider> + ); + } ), + 'withRegistryProvider' +); + +export default withRegistryProvider; diff --git a/packages/editor/src/index.js b/packages/editor/src/index.js index a55a7b1c0bfc1b..eb54a38859b135 100644 --- a/packages/editor/src/index.js +++ b/packages/editor/src/index.js @@ -17,6 +17,7 @@ import './hooks'; export * from './components'; export * from './utils'; +export { storeConfig } from './store'; /* * Backward compatibility diff --git a/packages/editor/src/store/index.js b/packages/editor/src/store/index.js index 1ba136aaab7226..33c5686396097e 100644 --- a/packages/editor/src/store/index.js +++ b/packages/editor/src/store/index.js @@ -13,11 +13,22 @@ import * as selectors from './selectors'; import * as actions from './actions'; import { STORE_KEY } from './constants'; -const store = registerStore( STORE_KEY, { +/** + * Post editor data store configuration. + * + * @see https://github.com/WordPress/gutenberg/blob/master/packages/data/README.md#registerStore + * + * @type {Object} + */ +export const storeConfig = { reducer, selectors, actions, controls, +}; + +const store = registerStore( STORE_KEY, { + ...storeConfig, persist: [ 'preferences' ], } ); applyMiddlewares( store ); From 7529160e19694b830c9fbaaceb33ffcd574f3ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= <soerenwrede@gmail.com> Date: Mon, 10 Jun 2019 18:33:20 +0200 Subject: [PATCH 090/132] Docs: Change register_meta to register_post_meta (#16032) * Change register_meta to register_post_meta * Change register_meta to register_post_meta --- .../developers/block-api/block-attributes.md | 6 +++--- .../tutorials/metabox/meta-block-2-register-meta.md | 12 ++++++------ .../plugin-sidebar-3-register-meta.md | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/designers-developers/developers/block-api/block-attributes.md b/docs/designers-developers/developers/block-api/block-attributes.md index 203113b06f5f97..2355fbc4356558 100644 --- a/docs/designers-developers/developers/block-api/block-attributes.md +++ b/docs/designers-developers/developers/block-api/block-attributes.md @@ -172,7 +172,7 @@ By default, a meta field will be excluded from a post object's meta. This can be ```php function gutenberg_my_block_init() { - register_meta( 'post', 'author', array( + register_post_meta( 'post', 'author', array( 'show_in_rest' => true, ) ); } @@ -184,11 +184,11 @@ Furthermore, be aware that WordPress defaults to: - not treating a meta datum as being unique, instead returning an array of values; - treating that datum as a string. -If either behavior is not desired, the same `register_meta` call can be complemented with the `single` and/or `type` parameters as follows: +If either behavior is not desired, the same `register_post_meta` call can be complemented with the `single` and/or `type` parameters as follows: ```php function gutenberg_my_block_init() { - register_meta( 'post', 'author_count', array( + register_post_meta( 'post', 'author_count', array( 'show_in_rest' => true, 'single' => true, 'type' => 'integer', diff --git a/docs/designers-developers/developers/tutorials/metabox/meta-block-2-register-meta.md b/docs/designers-developers/developers/tutorials/metabox/meta-block-2-register-meta.md index 795bd722ece293..744e50dfae5341 100644 --- a/docs/designers-developers/developers/tutorials/metabox/meta-block-2-register-meta.md +++ b/docs/designers-developers/developers/tutorials/metabox/meta-block-2-register-meta.md @@ -2,7 +2,7 @@ A post meta field is a WordPress object used to store extra data about a post. You need to first register a new meta field prior to use. See Managing [Post Metadata](https://developer.wordpress.org/plugins/metadata/managing-post-metadata/) to learn more about post meta. -When registering the field, note the `show_in_rest` parameter. This ensures the data will be included in the REST API, which the block editor uses to load and save meta data. See the [`register_meta`](https://developer.wordpress.org/reference/functions/register_meta/) function definition for extra information. +When registering the field, note the `show_in_rest` parameter. This ensures the data will be included in the REST API, which the block editor uses to load and save meta data. See the [`register_post_meta`](https://developer.wordpress.org/reference/functions/register_post_meta/) function definition for extra information. To register the field, create a PHP plugin file called `myguten-meta-block.php` including: @@ -13,20 +13,20 @@ To register the field, create a PHP plugin file called `myguten-meta-block.php` */ // register custom meta tag field -function myguten_register_meta() { - register_meta( 'post', 'myguten_meta_block_field', array( +function myguten_register_post_meta() { + register_post_meta( 'post', 'myguten_meta_block_field', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', ) ); } -add_action( 'init', 'myguten_register_meta' ); +add_action( 'init', 'myguten_register_post_meta' ); ``` -**Note:** If the meta key name starts with an underscore WordPress considers it a protected field. Editing this field requires passing a permission check, which is set as the `auth_callback` in the `register_meta` function. Here is an example: +**Note:** If the meta key name starts with an underscore WordPress considers it a protected field. Editing this field requires passing a permission check, which is set as the `auth_callback` in the `register_post_meta` function. Here is an example: ```php -register_meta( 'post', '_myguten_protected_key', array( +register_post_meta( 'post', '_myguten_protected_key', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', diff --git a/docs/designers-developers/developers/tutorials/sidebar-tutorial/plugin-sidebar-3-register-meta.md b/docs/designers-developers/developers/tutorials/sidebar-tutorial/plugin-sidebar-3-register-meta.md index da1717c8817f2b..999194e972bae7 100644 --- a/docs/designers-developers/developers/tutorials/sidebar-tutorial/plugin-sidebar-3-register-meta.md +++ b/docs/designers-developers/developers/tutorials/sidebar-tutorial/plugin-sidebar-3-register-meta.md @@ -1,11 +1,11 @@ # Register the Meta Field -To work with fields in the `post_meta` table, WordPress has a function called [register_meta](https://developer.wordpress.org/reference/functions/register_meta/). You're going to use it to register a new field called `sidebar_plugin_meta_block_field`, which will be a single string. Note that this field needs to be available through the [REST API](https://developer.wordpress.org/rest-api/) because that's how the block editor access data. +To work with fields in the `post_meta` table, WordPress has a function called [register_post_meta](https://developer.wordpress.org/reference/functions/register_post_meta/). You're going to use it to register a new field called `sidebar_plugin_meta_block_field`, which will be a single string. Note that this field needs to be available through the [REST API](https://developer.wordpress.org/rest-api/) because that's how the block editor access data. Add this to the PHP code, within the `init` callback function: ```php -register_meta( 'post', 'sidebar_plugin_meta_block_field', array( +register_post_meta( 'post', 'sidebar_plugin_meta_block_field', array( 'show_in_rest' => true, 'single' => true, 'type' => 'string', @@ -18,4 +18,4 @@ To make sure the field has been loaded, query the block editor [internal data st wp.data.select( 'core/editor' ).getCurrentPost().meta; ``` -Before adding the `register_meta` function to the plugin, this code returns a void array, because WordPress hasn't been told to load any meta field yet. After registering the field, the same code will return an object containing the registered meta field you registered. +Before adding the `register_post_meta` function to the plugin, this code returns a void array, because WordPress hasn't been told to load any meta field yet. After registering the field, the same code will return an object containing the registered meta field you registered. From 3188fe05c3e70fe7f07c6400b68e83d97167b297 Mon Sep 17 00:00:00 2001 From: etoledom <etoledom@icloud.com> Date: Mon, 10 Jun 2019 18:57:30 +0200 Subject: [PATCH 091/132] [RNMobile] iOS Image block caption multiline fix (#16071) * Add unit test to cover multiline rich-text onEnter appends br tag * Fix iOS issue where pressing Enter on image caption won't create a new line --- .../src/components/rich-text/index.native.js | 2 +- .../components/rich-text/test/index.native.js | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index d9fc545e8fa9f1..b63d193a962c60 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -365,7 +365,7 @@ export class RichText extends Component { const insertedLineSeparator = { ...insertLineSeparator( currentRecord ) }; this.onFormatChange( insertedLineSeparator ); } - } else if ( event.shiftKey || ! this.onSplit ) { + } else if ( event.shiftKey || ! onSplit ) { this.needsSelectionUpdate = true; const insertedLineBreak = { ...insert( currentRecord, '\n' ) }; this.onFormatChange( insertedLineBreak ); diff --git a/packages/block-editor/src/components/rich-text/test/index.native.js b/packages/block-editor/src/components/rich-text/test/index.native.js index 22ee6b118bb2d2..399e627308f65e 100644 --- a/packages/block-editor/src/components/rich-text/test/index.native.js +++ b/packages/block-editor/src/components/rich-text/test/index.native.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { shallow } from 'enzyme'; + /** * Internal dependencies */ @@ -24,4 +29,28 @@ describe( 'RichText Native', () => { expect( richText.willTrimSpaces( html ) ).toBe( false ); } ); } ); + + describe( 'Adds new line on Enter', () => { + let newValue; + const wrapper = shallow( <RichText + rootTagsToEliminate={ [ 'p' ] } + value={ "" } + onChange={ ( value ) => { + newValue = value + } } + formatTypes={ [] } + onSelectionChange={ jest.fn() } + /> ); + + const event = { + nativeEvent: { + eventCount: 0, + } + }; + wrapper.instance().onEnter(event); + + it( ' Adds <br> tag to content after pressing Enter key', () => { + expect( newValue ).toEqual( "<br>" ); + }); + } ); } ); From 1d560c82265d868df563a98dee58bf1e9753e672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Est=C3=AAv=C3=A3o?= <sergioestevao@gmail.com> Date: Mon, 10 Jun 2019 18:29:27 +0100 Subject: [PATCH 092/132] Make sure no div elements get in the content of quotes. (#16072) * Make sure no div elements get in the content. * Remove tags in content. --- .../src/components/rich-text/index.native.js | 11 +++++++++++ .../src/primitives/block-quotation/index.native.js | 3 +++ 2 files changed, 14 insertions(+) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index b63d193a962c60..f9eeb33caac677 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -299,6 +299,12 @@ export class RichText extends Component { result = this.removeRootTag( element, result ); } ); } + + if ( this.props.tagsToEliminate ) { + this.props.tagsToEliminate.forEach( ( element ) => { + result = this.removeTag( element, result ); + } ); + } return result; } @@ -307,6 +313,11 @@ export class RichText extends Component { const closingTagRegexp = RegExp( '</' + tag + '>$', 'gim' ); return html.replace( openingTagRegexp, '' ).replace( closingTagRegexp, '' ); } + removeTag( tag, html ) { + const openingTagRegexp = RegExp( '<' + tag + '>', 'gim' ); + const closingTagRegexp = RegExp( '</' + tag + '>', 'gim' ); + return html.replace( openingTagRegexp, '' ).replace( closingTagRegexp, '' ); + } /* * Handles any case where the content of the AztecRN instance has changed diff --git a/packages/components/src/primitives/block-quotation/index.native.js b/packages/components/src/primitives/block-quotation/index.native.js index dbcc249fe1bff5..abbafa09cae949 100644 --- a/packages/components/src/primitives/block-quotation/index.native.js +++ b/packages/components/src/primitives/block-quotation/index.native.js @@ -16,6 +16,9 @@ export const BlockQuotation = ( props ) => { if ( child && child.props.identifier === 'citation' ) { return cloneElement( child, { style: styles.wpBlockQuoteCitation } ); } + if ( child && child.props.identifier === 'value' ) { + return cloneElement( child, { tagsToEliminate: [ 'div' ] } ); + } return child; } ); return ( From 945de604563389eb4cc5a6fa870c7bb11e2eaa95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Est=C3=AAv=C3=A3o?= <sergioestevao@gmail.com> Date: Mon, 10 Jun 2019 20:50:01 +0100 Subject: [PATCH 093/132] Rnmobile/change colors on rich text mobile (#16016) * Set text in rich text to gray 900 color. * Update links color to be blue 500. * Use specific color for placeholder text. * Use standard property for placeholder colours. --- .../block-editor/src/components/rich-text/index.native.js | 5 +++-- .../src/components/rich-text/style.native.scss | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index f9eeb33caac677..0a33ebd32b491a 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -819,7 +819,7 @@ export class RichText extends Component { } } text={ { text: html, eventCount: this.lastEventCount, selection } } placeholder={ this.props.placeholder } - placeholderTextColor={ this.props.placeholderTextColor || styles[ 'block-editor-rich-text' ].textDecorationColor } + placeholderTextColor={ this.props.placeholderTextColor || styles[ 'block-editor-rich-text-placeholder' ].color } deleteEnter={ this.props.deleteEnter } onChange={ this.onChange } onFocus={ this.onFocus } @@ -832,7 +832,8 @@ export class RichText extends Component { onCaretVerticalPositionChange={ this.props.onCaretVerticalPositionChange } onSelectionChange={ this.onSelectionChangeFromAztec } blockType={ { tag: tagName } } - color={ 'black' } + color={ styles[ 'block-editor-rich-text' ].color } + linkTextColor={ styles[ 'block-editor-rich-text' ].textDecorationColor } maxImagesWidth={ 200 } fontFamily={ this.props.fontFamily || styles[ 'block-editor-rich-text' ].fontFamily } fontSize={ this.props.fontSize || ( style && style.fontSize ) } diff --git a/packages/block-editor/src/components/rich-text/style.native.scss b/packages/block-editor/src/components/rich-text/style.native.scss index ef530f4d3c7817..77413c5be1f9e4 100644 --- a/packages/block-editor/src/components/rich-text/style.native.scss +++ b/packages/block-editor/src/components/rich-text/style.native.scss @@ -1,6 +1,11 @@ .block-editor-rich-text { font-family: $default-regular-font; - text-decoration-color: $gray; min-height: $min-height-paragraph; + color: $gray-900; + text-decoration-color: $blue-500; +} + +.block-editor-rich-text-placeholder { + color: $gray; } From 73fd352957427fa038c89003e2af3214de7b25e2 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Tue, 11 Jun 2019 00:41:10 -0400 Subject: [PATCH 094/132] Scripts: Fix default use of lint-js file patterns (#16079) * Scripts: Call hasFileInCliArgs as function * Scripts: Apply default file arguments as spread array * Fix lint issues found --- .../components/media-upload/test/index.native.js | 4 ++-- .../src/components/rich-text/test/index.native.js | 14 +++++++------- packages/block-library/src/heading/edit.native.js | 2 -- .../src/video/video-player.android.js | 2 +- packages/scripts/scripts/lint-js.js | 2 +- packages/scripts/scripts/lint-pkg-json.js | 4 ++-- packages/scripts/scripts/lint-style.js | 2 +- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/block-editor/src/components/media-upload/test/index.native.js b/packages/block-editor/src/components/media-upload/test/index.native.js index 76acd6132f4dbb..72a2015277e4df 100644 --- a/packages/block-editor/src/components/media-upload/test/index.native.js +++ b/packages/block-editor/src/components/media-upload/test/index.native.js @@ -52,7 +52,7 @@ describe( 'MediaUpload component', () => { ); } } /> ); - expect( wrapper.find( 'Picker' ).length ).toEqual( 1 ); + expect( wrapper.find( 'Picker' ) ).toHaveLength( 1 ); } ); it( 'shows right media capture option for media type', () => { @@ -68,7 +68,7 @@ describe( 'MediaUpload component', () => { ); } } /> ); - expect( wrapper.find( 'Picker' ).props().options.filter( ( item ) => item.label === expectedOption ).length ).toEqual( 1 ); + expect( wrapper.find( 'Picker' ).props().options.filter( ( item ) => item.label === expectedOption ) ).toHaveLength( 1 ); }; expectOptionForMediaType( MEDIA_TYPE_IMAGE, OPTION_TAKE_PHOTO ); expectOptionForMediaType( MEDIA_TYPE_VIDEO, OPTION_TAKE_VIDEO ); diff --git a/packages/block-editor/src/components/rich-text/test/index.native.js b/packages/block-editor/src/components/rich-text/test/index.native.js index 399e627308f65e..ec0cbb77195244 100644 --- a/packages/block-editor/src/components/rich-text/test/index.native.js +++ b/packages/block-editor/src/components/rich-text/test/index.native.js @@ -32,11 +32,11 @@ describe( 'RichText Native', () => { describe( 'Adds new line on Enter', () => { let newValue; - const wrapper = shallow( <RichText + const wrapper = shallow( <RichText rootTagsToEliminate={ [ 'p' ] } - value={ "" } + value="" onChange={ ( value ) => { - newValue = value + newValue = value; } } formatTypes={ [] } onSelectionChange={ jest.fn() } @@ -45,12 +45,12 @@ describe( 'RichText Native', () => { const event = { nativeEvent: { eventCount: 0, - } + }, }; - wrapper.instance().onEnter(event); + wrapper.instance().onEnter( event ); it( ' Adds <br> tag to content after pressing Enter key', () => { - expect( newValue ).toEqual( "<br>" ); - }); + expect( newValue ).toEqual( '<br>' ); + } ); } ); } ); diff --git a/packages/block-library/src/heading/edit.native.js b/packages/block-library/src/heading/edit.native.js index 1f409356b12a1f..389791663b0541 100644 --- a/packages/block-library/src/heading/edit.native.js +++ b/packages/block-library/src/heading/edit.native.js @@ -18,9 +18,7 @@ import { createBlock } from '@wordpress/blocks'; const HeadingEdit = ( { attributes, - isSelected, mergeBlocks, - onBlur, onFocus, onReplace, setAttributes, diff --git a/packages/block-library/src/video/video-player.android.js b/packages/block-library/src/video/video-player.android.js index b1ccc057ba03c3..669948bbdd2d3b 100644 --- a/packages/block-library/src/video/video-player.android.js +++ b/packages/block-library/src/video/video-player.android.js @@ -19,7 +19,7 @@ const Video = ( props ) => { // We are using built-in player controls becasue manually // calling presentFullscreenPlayer() is not working for android controls={ isSelected } - muted={ !isSelected } + muted={ ! isSelected } /> </View> ); diff --git a/packages/scripts/scripts/lint-js.js b/packages/scripts/scripts/lint-js.js index 04d24cd538fcb2..af2e450037b397 100644 --- a/packages/scripts/scripts/lint-js.js +++ b/packages/scripts/scripts/lint-js.js @@ -18,7 +18,7 @@ const { const args = getCliArgs(); -const defaultFilesArgs = ! hasFileInCliArgs ? [ '.' ] : []; +const defaultFilesArgs = hasFileInCliArgs() ? [] : [ '.' ]; // See: https://eslint.org/docs/user-guide/configuring#using-configuration-files-1. const hasLintConfig = hasCliArg( '-c' ) || diff --git a/packages/scripts/scripts/lint-pkg-json.js b/packages/scripts/scripts/lint-pkg-json.js index 3d15b2bddb1d07..6c328cb0169bff 100644 --- a/packages/scripts/scripts/lint-pkg-json.js +++ b/packages/scripts/scripts/lint-pkg-json.js @@ -18,7 +18,7 @@ const { const args = getCliArgs(); -const defaultFilesArgs = ! hasFileInCliArgs ? [ '.' ] : []; +const defaultFilesArgs = hasFileInCliArgs() ? [] : [ '.' ]; // See: https://github.com/tclindner/npm-package-json-lint/wiki/configuration#configuration. const hasLintConfig = hasCliArg( '-c' ) || @@ -41,7 +41,7 @@ const defaultIgnoreArgs = ! hasIgnoredFiles ? const result = spawn( resolveBin( 'npm-package-json-lint', { executable: 'npmPkgJsonLint' } ), - [ ...defaultConfigArgs, ...defaultIgnoreArgs, ...args, defaultFilesArgs ], + [ ...defaultConfigArgs, ...defaultIgnoreArgs, ...args, ...defaultFilesArgs ], { stdio: 'inherit' } ); diff --git a/packages/scripts/scripts/lint-style.js b/packages/scripts/scripts/lint-style.js index 024e04983ca8b1..9d22a81c96ba25 100644 --- a/packages/scripts/scripts/lint-style.js +++ b/packages/scripts/scripts/lint-style.js @@ -18,7 +18,7 @@ const { const args = getCliArgs(); -const defaultFilesArgs = ! hasFileInCliArgs ? [ '**/*.{css,scss}' ] : []; +const defaultFilesArgs = hasFileInCliArgs() ? [] : [ '**/*.{css,scss}' ]; // See: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#loading-the-configuration-object. const hasLintConfig = hasCliArg( '--config' ) || From 36f1a5db7eeb47ca799f1e2dd103725847999683 Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Tue, 11 Jun 2019 00:46:42 -0400 Subject: [PATCH 095/132] fix(components/tab-panel): improve className safety by using classNames (#16081) This commit does two things: 1. Improves safety of the interpolation of className for `tab`s (currently the string `undefined` will show up if the `tab` doesn't have the `className` property defined). 2. Relaxes the strictness and makes the `className` property of `tab` optional. --- packages/components/src/tab-panel/README.md | 12 ++++++------ packages/components/src/tab-panel/index.js | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/components/src/tab-panel/README.md b/packages/components/src/tab-panel/README.md index 89c6b095722505..def626516b3a39 100644 --- a/packages/components/src/tab-panel/README.md +++ b/packages/components/src/tab-panel/README.md @@ -114,15 +114,15 @@ The function called when a tab has been selected. It is passed the `tabName` as #### tabs -A list of tabs where each tab is defined by an object with the following fields: +An array of objects containing the following properties: -1. name: String. Defines the key for the tab -2. title: String. Defines the translated text for the tab -3. className: String. Defines the class to put on the tab. +- `name`: `(string)` Defines the key for the tab. +- `title`:`(string)` Defines the translated text for the tab. +- `className`:`(string)` Optional. Defines the class to put on the tab. -Other fields may be added to the object and accessed from the child function if desired. +>> **Note:** Other fields may be added to the object and accessed from the child function if desired. -- Type: Array +- Type: `Array` - Required: Yes #### activeClass diff --git a/packages/components/src/tab-panel/index.js b/packages/components/src/tab-panel/index.js index 5558272f2ffc4a..71f4683bcbef80 100644 --- a/packages/components/src/tab-panel/index.js +++ b/packages/components/src/tab-panel/index.js @@ -1,6 +1,7 @@ /** * External dependencies */ +import classnames from 'classnames'; import { partial, noop, find } from 'lodash'; /** @@ -74,7 +75,7 @@ class TabPanel extends Component { className="components-tab-panel__tabs" > { tabs.map( ( tab ) => ( - <TabButton className={ `${ tab.className } ${ tab.name === selected ? activeClass : '' }` } + <TabButton className={ classnames( tab.className, { [ activeClass ]: tab.name === selected } ) } tabId={ instanceId + '-' + tab.name } aria-controls={ instanceId + '-' + tab.name + '-view' } selected={ tab.name === selected } From c3e473ef780991284af81e67ec6364113a785ab9 Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Tue, 11 Jun 2019 00:49:39 -0400 Subject: [PATCH 096/132] remove defaultProp from required property in components/modal (#16074) closes #16062 --- packages/components/src/modal/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/components/src/modal/index.js b/packages/components/src/modal/index.js index d82c6928a1073c..ff35faf9222f99 100644 --- a/packages/components/src/modal/index.js +++ b/packages/components/src/modal/index.js @@ -2,7 +2,6 @@ * External dependencies */ import classnames from 'classnames'; -import { noop } from 'lodash'; /** * WordPress dependencies @@ -166,7 +165,6 @@ Modal.defaultProps = { bodyOpenClassName: 'modal-open', role: 'dialog', title: null, - onRequestClose: noop, focusOnMount: true, shouldCloseOnEsc: true, shouldCloseOnClickOutside: true, From bc77745063fd3ed68261c79dbdc0af3148699be7 Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Tue, 11 Jun 2019 01:20:56 -0400 Subject: [PATCH 097/132] docs(components/text-control): Fix incorrectly documented "value" prop (#16083) --- packages/components/src/text-control/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/text-control/README.md b/packages/components/src/text-control/README.md index 49066ad3cf86ba..2fa725b3c3e88b 100644 --- a/packages/components/src/text-control/README.md +++ b/packages/components/src/text-control/README.md @@ -96,7 +96,7 @@ Type of the input element to render. Defaults to "text". #### value The current value of the input. -- Type: `Number` +- Type: `String | Number` - Required: Yes #### className From a4c97bbaddd80f039cd407d7b1c54024bc85eda2 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Tue, 11 Jun 2019 13:43:38 +0100 Subject: [PATCH 098/132] Fix: Remove editor usage from media blocks. (#15548) --- packages/block-library/src/audio/edit.js | 22 ++++++++++--- packages/block-library/src/file/edit.js | 11 +++++-- packages/block-library/src/gallery/edit.js | 32 +++++++++++++++++-- .../block-library/src/gallery/transforms.js | 18 ++--------- packages/block-library/src/image/edit.js | 16 ++++++++-- packages/block-library/src/video/edit.js | 18 +++++++++-- 6 files changed, 88 insertions(+), 29 deletions(-) diff --git a/packages/block-library/src/audio/edit.js b/packages/block-library/src/audio/edit.js index a518f077011e6a..164b8c22c9a7ba 100644 --- a/packages/block-library/src/audio/edit.js +++ b/packages/block-library/src/audio/edit.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { getBlobByURL, isBlobURL } from '@wordpress/blob'; +import { compose } from '@wordpress/compose'; import { Disabled, IconButton, @@ -18,9 +19,9 @@ import { MediaPlaceholder, RichText, } from '@wordpress/block-editor'; -import { mediaUpload } from '@wordpress/editor'; import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { withSelect } from '@wordpress/data'; /** * Internal dependencies @@ -49,7 +50,12 @@ class AudioEdit extends Component { } componentDidMount() { - const { attributes, noticeOperations, setAttributes } = this.props; + const { + attributes, + mediaUpload, + noticeOperations, + setAttributes, + } = this.props; const { id, src = '' } = attributes; if ( ! id && isBlobURL( src ) ) { @@ -207,5 +213,13 @@ class AudioEdit extends Component { /* eslint-enable jsx-a11y/no-static-element-interactions, jsx-a11y/onclick-has-role, jsx-a11y/click-events-have-key-events */ } } - -export default withNotices( AudioEdit ); +export default compose( [ + withSelect( ( select ) => { + const { getSettings } = select( 'core/block-editor' ); + const { __experimentalMediaUpload } = getSettings(); + return { + mediaUpload: __experimentalMediaUpload, + }; + } ), + withNotices, +] )( AudioEdit ); diff --git a/packages/block-library/src/file/edit.js b/packages/block-library/src/file/edit.js index f06d2be38c98a7..a27d22a326f474 100644 --- a/packages/block-library/src/file/edit.js +++ b/packages/block-library/src/file/edit.js @@ -27,7 +27,6 @@ import { MediaPlaceholder, RichText, } from '@wordpress/block-editor'; -import { mediaUpload } from '@wordpress/editor'; import { Component } from '@wordpress/element'; import { __, _x } from '@wordpress/i18n'; @@ -56,7 +55,12 @@ class FileEdit extends Component { } componentDidMount() { - const { attributes, noticeOperations, setAttributes } = this.props; + const { + attributes, + mediaUpload, + noticeOperations, + setAttributes, + } = this.props; const { downloadButtonText, href } = attributes; // Upload a file drag-and-dropped into the editor @@ -248,9 +252,12 @@ class FileEdit extends Component { export default compose( [ withSelect( ( select, props ) => { const { getMedia } = select( 'core' ); + const { getSettings } = select( 'core/block-editor' ); + const { __experimentalMediaUpload } = getSettings(); const { id } = props.attributes; return { media: id === undefined ? undefined : getMedia( id ), + mediaUpload: __experimentalMediaUpload, }; } ), withNotices, diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index c5aebed551849f..f8d1db665208f0 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -2,11 +2,12 @@ * External dependencies */ import classnames from 'classnames'; -import { filter, map } from 'lodash'; +import { every, filter, forEach, map } from 'lodash'; /** * WordPress dependencies */ +import { compose } from '@wordpress/compose'; import { IconButton, PanelBody, @@ -25,6 +26,8 @@ import { } from '@wordpress/block-editor'; import { Component } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; +import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob'; +import { withSelect } from '@wordpress/data'; /** * Internal dependencies @@ -174,6 +177,20 @@ class GalleryEdit extends Component { } ); } + componentDidMount() { + const { attributes, mediaUpload } = this.props; + const { images } = attributes; + if ( every( images, ( { url } ) => isBlobURL( url ) ) ) { + const filesList = map( images, ( { url } ) => getBlobByURL( url ) ); + forEach( images, ( { url } ) => revokeBlobURL( url ) ); + mediaUpload( { + filesList, + onFileChange: this.onSelectImages, + allowedTypes: [ 'image' ], + } ); + } + } + componentDidUpdate( prevProps ) { // Deselect images when deselecting the block if ( ! this.props.isSelected && prevProps.isSelected ) { @@ -312,5 +329,16 @@ class GalleryEdit extends Component { ); } } +export default compose( [ + withSelect( ( select ) => { + const { getSettings } = select( 'core/block-editor' ); + const { + __experimentalMediaUpload, + } = getSettings(); -export default withNotices( GalleryEdit ); + return { + mediaUpload: __experimentalMediaUpload, + }; + } ), + withNotices, +] )( GalleryEdit ); diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js index af8d5d164c10e0..ea752fe296bd9e 100644 --- a/packages/block-library/src/gallery/transforms.js +++ b/packages/block-library/src/gallery/transforms.js @@ -1,13 +1,12 @@ /** * External dependencies */ -import { filter, every, map } from 'lodash'; +import { filter, every } from 'lodash'; /** * WordPress dependencies */ import { createBlock } from '@wordpress/blocks'; -import { mediaUpload } from '@wordpress/editor'; import { createBlobURL } from '@wordpress/blob'; /** @@ -89,25 +88,12 @@ const transforms = { isMatch( files ) { return files.length !== 1 && every( files, ( file ) => file.type.indexOf( 'image/' ) === 0 ); }, - transform( files, onChange ) { + transform( files ) { const block = createBlock( 'core/gallery', { images: files.map( ( file ) => pickRelevantMediaFiles( { url: createBlobURL( file ), } ) ), } ); - mediaUpload( { - filesList: files, - onFileChange: ( images ) => { - const imagesAttr = images.map( - pickRelevantMediaFiles, - ); - onChange( block.clientId, { - ids: map( imagesAttr, 'id' ), - images: imagesAttr, - } ); - }, - allowedTypes: [ 'image' ], - } ); return block; }, }, diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index ecc498e2988fc9..42b271903fe049 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -43,7 +43,6 @@ import { MediaPlaceholder, RichText, } from '@wordpress/block-editor'; -import { mediaUpload } from '@wordpress/editor'; import { Component } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; import { getPath } from '@wordpress/url'; @@ -126,7 +125,12 @@ class ImageEdit extends Component { } componentDidMount() { - const { attributes, setAttributes, noticeOperations } = this.props; + const { + attributes, + mediaUpload, + noticeOperations, + setAttributes, + } = this.props; const { id, url = '' } = attributes; if ( isTemporaryImage( id, url ) ) { @@ -721,13 +725,19 @@ export default compose( [ const { getMedia } = select( 'core' ); const { getSettings } = select( 'core/block-editor' ); const { id } = props.attributes; - const { maxWidth, isRTL, imageSizes } = getSettings(); + const { + __experimentalMediaUpload, + imageSizes, + isRTL, + maxWidth, + } = getSettings(); return { image: id ? getMedia( id ) : null, maxWidth, isRTL, imageSizes, + mediaUpload: __experimentalMediaUpload, }; } ), withViewportMatch( { isLargeViewport: 'medium' } ), diff --git a/packages/block-library/src/video/edit.js b/packages/block-library/src/video/edit.js index f8380b7edeafc6..9931508d2c6c3f 100644 --- a/packages/block-library/src/video/edit.js +++ b/packages/block-library/src/video/edit.js @@ -22,7 +22,6 @@ import { MediaUploadCheck, RichText, } from '@wordpress/block-editor'; -import { mediaUpload } from '@wordpress/editor'; import { Component, createRef } from '@wordpress/element'; import { __, @@ -32,6 +31,9 @@ import { compose, withInstanceId, } from '@wordpress/compose'; +import { + withSelect, +} from '@wordpress/data'; /** * Internal dependencies @@ -61,7 +63,12 @@ class VideoEdit extends Component { } componentDidMount() { - const { attributes, noticeOperations, setAttributes } = this.props; + const { + attributes, + mediaUpload, + noticeOperations, + setAttributes, + } = this.props; const { id, src = '' } = attributes; if ( ! id && isBlobURL( src ) ) { const file = getBlobByURL( src ); @@ -312,6 +319,13 @@ class VideoEdit extends Component { } export default compose( [ + withSelect( ( select ) => { + const { getSettings } = select( 'core/block-editor' ); + const { __experimentalMediaUpload } = getSettings(); + return { + mediaUpload: __experimentalMediaUpload, + }; + } ), withNotices, withInstanceId, ] )( VideoEdit ); From 9714aef4a6f0c20c9385fe98f96a750c46987653 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Tue, 11 Jun 2019 14:42:21 +0100 Subject: [PATCH 099/132] Fix: Playground build; Remove @babel/polyfill import from the playground (#15947) --- playground/src/index.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/playground/src/index.js b/playground/src/index.js index 0e0bc6a87f8d84..3f125282c49090 100644 --- a/playground/src/index.js +++ b/playground/src/index.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import '@babel/polyfill'; - /** * WordPress dependencies */ From 29e39c709f82a3b4964d0d70bc618cd4e7414516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= <grzegorz@gziolo.pl> Date: Tue, 11 Jun 2019 20:58:04 +0200 Subject: [PATCH 100/132] Project management: Fix milestone version selection when RC is included in version (#16084) --- .github/actions/milestone-it/entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/milestone-it/entrypoint.sh b/.github/actions/milestone-it/entrypoint.sh index a0b94110f532a2..835875dc61a1b4 100755 --- a/.github/actions/milestone-it/entrypoint.sh +++ b/.github/actions/milestone-it/entrypoint.sh @@ -29,7 +29,7 @@ minor=${parts[1]} # 3. Determine next milestone. -if [ minor == '9' ]; then +if [[ $minor == 9* ]]; then major=$((major+1)) minor="0" else From 4a4cbdbb65382b3af1f7e1fadfd4c358fefc9281 Mon Sep 17 00:00:00 2001 From: Kjell Reigstad <kjell.reigstad@automattic.com> Date: Tue, 11 Jun 2019 17:10:04 -0400 Subject: [PATCH 101/132] Update fill-rule and clip-rule to fillRule and clipRule (#16096) --- packages/block-library/src/group/icon.js | 2 +- .../editor/src/components/convert-to-group-buttons/icons.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/group/icon.js b/packages/block-library/src/group/icon.js index e1b36f7f72cadb..f9d9dc7790ba95 100644 --- a/packages/block-library/src/group/icon.js +++ b/packages/block-library/src/group/icon.js @@ -4,5 +4,5 @@ import { Path, SVG } from '@wordpress/components'; export default ( - <SVG width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><Path fill-rule="evenodd" clip-rule="evenodd" d="M9 8a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-1v3a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm2 3h4V9h-4v2zm2 2H9v2h4v-2z" /><Path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.732A2 2 0 1 1 4.732 2h14.536A2 2 0 1 1 22 4.732v14.536A2 2 0 1 1 19.268 22H4.732A2 2 0 1 1 2 19.268V4.732zM4.732 4h14.536c.175.304.428.557.732.732v14.536a2.01 2.01 0 0 0-.732.732H4.732A2.01 2.01 0 0 0 4 19.268V4.732A2.01 2.01 0 0 0 4.732 4z" /></SVG> + <SVG width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><Path fillRule="evenodd" clipRule="evenodd" d="M9 8a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v4a1 1 0 0 1-1 1h-1v3a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1v-4a1 1 0 0 1 1-1h1V8zm2 3h4V9h-4v2zm2 2H9v2h4v-2z" /><Path fillRule="evenodd" clipRule="evenodd" d="M2 4.732A2 2 0 1 1 4.732 2h14.536A2 2 0 1 1 22 4.732v14.536A2 2 0 1 1 19.268 22H4.732A2 2 0 1 1 2 19.268V4.732zM4.732 4h14.536c.175.304.428.557.732.732v14.536a2.01 2.01 0 0 0-.732.732H4.732A2.01 2.01 0 0 0 4 19.268V4.732A2.01 2.01 0 0 0 4.732 4z" /></SVG> ); diff --git a/packages/editor/src/components/convert-to-group-buttons/icons.js b/packages/editor/src/components/convert-to-group-buttons/icons.js index d1ee497662cd49..990d15dd5ac1cd 100644 --- a/packages/editor/src/components/convert-to-group-buttons/icons.js +++ b/packages/editor/src/components/convert-to-group-buttons/icons.js @@ -3,11 +3,11 @@ */ import { Icon, SVG, Path } from '@wordpress/components'; -const GroupSVG = <SVG width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><Path fill-rule="evenodd" clip-rule="evenodd" d="M8 5a1 1 0 0 0-1 1v3H6a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-3h1a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H8zm3 6H7v2h4v-2zM9 9V7h4v2H9z" /><Path fill-rule="evenodd" clip-rule="evenodd" d="M1 3a2 2 0 0 0 1 1.732v10.536A2 2 0 1 0 4.732 18h10.536A2 2 0 1 0 18 15.268V4.732A2 2 0 1 0 15.268 2H4.732A2 2 0 0 0 1 3zm14.268 1H4.732A2.01 2.01 0 0 1 4 4.732v10.536c.304.175.557.428.732.732h10.536a2.01 2.01 0 0 1 .732-.732V4.732A2.01 2.01 0 0 1 15.268 4z" /></SVG>; +const GroupSVG = <SVG width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><Path fillRule="evenodd" clipRule="evenodd" d="M8 5a1 1 0 0 0-1 1v3H6a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-3h1a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1H8zm3 6H7v2h4v-2zM9 9V7h4v2H9z" /><Path fillRule="evenodd" clipRule="evenodd" d="M1 3a2 2 0 0 0 1 1.732v10.536A2 2 0 1 0 4.732 18h10.536A2 2 0 1 0 18 15.268V4.732A2 2 0 1 0 15.268 2H4.732A2 2 0 0 0 1 3zm14.268 1H4.732A2.01 2.01 0 0 1 4 4.732v10.536c.304.175.557.428.732.732h10.536a2.01 2.01 0 0 1 .732-.732V4.732A2.01 2.01 0 0 1 15.268 4z" /></SVG>; export const Group = <Icon icon={ GroupSVG } />; -const UngroupSVG = <SVG width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><Path fill-rule="evenodd" clip-rule="evenodd" d="M9 2H15C16.1 2 17 2.9 17 4V7C17 8.1 16.1 9 15 9H9C7.9 9 7 8.1 7 7V4C7 2.9 7.9 2 9 2ZM9 7H15V4H9V7Z" /><Path fill-rule="evenodd" clip-rule="evenodd" d="M5 11H11C12.1 11 13 11.9 13 13V16C13 17.1 12.1 18 11 18H5C3.9 18 3 17.1 3 16V13C3 11.9 3.9 11 5 11ZM5 16H11V13H5V16Z" /></SVG>; +const UngroupSVG = <SVG width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><Path fillRule="evenodd" clipRule="evenodd" d="M9 2H15C16.1 2 17 2.9 17 4V7C17 8.1 16.1 9 15 9H9C7.9 9 7 8.1 7 7V4C7 2.9 7.9 2 9 2ZM9 7H15V4H9V7Z" /><Path fillRule="evenodd" clipRule="evenodd" d="M5 11H11C12.1 11 13 11.9 13 13V16C13 17.1 12.1 18 11 18H5C3.9 18 3 17.1 3 16V13C3 11.9 3.9 11 5 11ZM5 16H11V13H5V16Z" /></SVG>; export const Ungroup = <Icon icon={ UngroupSVG } />; From fdbe9dfcd36ac578d2921e67c9c249bf652fbbf1 Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Tue, 11 Jun 2019 17:30:00 -0400 Subject: [PATCH 102/132] [docs] fix incorrect prop documentation for components/date-time (#16073) closes #16057 --- packages/components/src/date-time/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/components/src/date-time/README.md b/packages/components/src/date-time/README.md index f0fa63c69b6ce4..530a67e0e8e576 100644 --- a/packages/components/src/date-time/README.md +++ b/packages/components/src/date-time/README.md @@ -52,8 +52,7 @@ The current date and time at initialization. Optionally pass in a `null` value t The function called when a new date or time has been selected. It is passed the `currentDate` as an argument. - Type: `Function` -- Required: No -- Default: `noop` +- Required: Yes ### is12Hour From e9ff314777c435e259d8a78bbbcc24c32cbd6705 Mon Sep 17 00:00:00 2001 From: Tammie Lister <tammie@automattic.com> Date: Tue, 11 Jun 2019 23:35:55 +0100 Subject: [PATCH 103/132] Adjust margins on datepicker to balance (#16097) Fixes #15653 --- packages/components/src/date-time/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/date-time/style.scss b/packages/components/src/date-time/style.scss index 02b2686f4f8821..d25d923dd24d94 100644 --- a/packages/components/src/date-time/style.scss +++ b/packages/components/src/date-time/style.scss @@ -211,7 +211,7 @@ // Hack to center the datepicker component within the popover. // It sets its own styles so centering is tricky. .components-popover .components-datetime__date { - padding-left: 6px; + padding-left: 4px; } // Used to prevent z-index issues on mobile. From d7991f2fc5a9ae12c978628c10e15ff0c54a4339 Mon Sep 17 00:00:00 2001 From: Mel Choyce <melchoyce@users.noreply.github.com> Date: Tue, 11 Jun 2019 15:40:27 -0700 Subject: [PATCH 104/132] Update Tag Cloud copy when no terms are found (#16098) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before: "No terms found." After: "Your site doesn’t have any tags, so there’s nothing to display here at the moment." It updates based on the chosen taxonomy. Props @ryelle for writing the logic and @michelleweber for brainstorming copy with me. --- packages/block-library/src/tag-cloud/index.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/tag-cloud/index.php b/packages/block-library/src/tag-cloud/index.php index 6786e076b80f1d..b5095a2998fab1 100644 --- a/packages/block-library/src/tag-cloud/index.php +++ b/packages/block-library/src/tag-cloud/index.php @@ -30,7 +30,8 @@ function render_block_core_tag_cloud( $attributes ) { $tag_cloud = wp_tag_cloud( $args ); if ( ! $tag_cloud ) { - $tag_cloud = esc_html( __( 'No terms to show.' ) ); + $labels = get_taxonomy_labels( get_taxonomy( $attributes['taxonomy'] ) ); + $tag_cloud = esc_html( sprintf( __( 'Your site doesn&#8217;t have any %s, so there&#8217;s nothing to display here at the moment.' ), strtolower( $labels->name ) ) ); } return sprintf( From 874fa8b08f83205d44acc07e123f02a34491a994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= <soerenwrede@gmail.com> Date: Wed, 12 Jun 2019 08:50:55 +0200 Subject: [PATCH 105/132] Update link to permalink documentation. (#16087) --- packages/edit-post/src/components/sidebar/post-link/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-post/src/components/sidebar/post-link/index.js b/packages/edit-post/src/components/sidebar/post-link/index.js index 71f20775034ff5..674c14b8615f9b 100644 --- a/packages/edit-post/src/components/sidebar/post-link/index.js +++ b/packages/edit-post/src/components/sidebar/post-link/index.js @@ -88,7 +88,7 @@ function PostLink( { /> <p> { __( 'The last part of the URL. ' ) } - <ExternalLink href="https://codex.wordpress.org/Posts_Add_New_Screen"> + <ExternalLink href="https://wordpress.org/support/article/writing-posts/#post-field-descriptions"> { __( 'Read about permalinks' ) } </ExternalLink> </p> From 198bba2605da257c36af264a875c2f33661ca291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= <soerenwrede@gmail.com> Date: Wed, 12 Jun 2019 10:54:14 +0200 Subject: [PATCH 106/132] Fix: For passing the PHP Coding Standards (#16107) * Fix PHP CS * Add translator comment --- packages/block-library/src/rss/index.php | 3 ++- packages/block-library/src/tag-cloud/index.php | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/rss/index.php b/packages/block-library/src/rss/index.php index 92406d09b6b1d6..1bf217be3a9b59 100644 --- a/packages/block-library/src/rss/index.php +++ b/packages/block-library/src/rss/index.php @@ -109,7 +109,8 @@ function render_block_core_rss( $attributes ) { * Registers the `core/rss` block on server. */ function register_block_core_rss() { - register_block_type( 'core/rss', + register_block_type( + 'core/rss', array( 'attributes' => array( 'align' => array( diff --git a/packages/block-library/src/tag-cloud/index.php b/packages/block-library/src/tag-cloud/index.php index b5095a2998fab1..cf9c4d24537dbd 100644 --- a/packages/block-library/src/tag-cloud/index.php +++ b/packages/block-library/src/tag-cloud/index.php @@ -30,8 +30,14 @@ function render_block_core_tag_cloud( $attributes ) { $tag_cloud = wp_tag_cloud( $args ); if ( ! $tag_cloud ) { - $labels = get_taxonomy_labels( get_taxonomy( $attributes['taxonomy'] ) ); - $tag_cloud = esc_html( sprintf( __( 'Your site doesn&#8217;t have any %s, so there&#8217;s nothing to display here at the moment.' ), strtolower( $labels->name ) ) ); + $labels = get_taxonomy_labels( get_taxonomy( $attributes['taxonomy'] ) ); + $tag_cloud = esc_html( + sprintf( + /* translators: %s: taxonomy name */ + __( 'Your site doesn&#8217;t have any %s, so there&#8217;s nothing to display here at the moment.' ), + strtolower( $labels->name ) + ) + ); } return sprintf( From 91da6692db8e7ab8cff55d3d9d0cef806c3c4322 Mon Sep 17 00:00:00 2001 From: Joen Asmussen <asmussen@gmail.com> Date: Wed, 12 Jun 2019 11:10:24 +0200 Subject: [PATCH 107/132] Fix horizontal scrollbar on full-wide blocks with nesting. (#16085) This fixes #15192. This PR fixes two issues: 1. There was an issue, probably rebase related, where the columns block had CSS to prevent horizontal scrollbars when fullwide, but which didn't work anymore. I simply fixed the selector again. 2. The recent merge of the clickthrough PR failed to take into account fullwide blocks with nesting, and caused a horizontal scrollbar due to the overlay extending beyond the canvas. To test this PR, please verify that full wide alignments work as intended. You can test columns, image, embed, media & text. Please also verify that blocks with nesting work as intended, both in fullwide and not wide situations. --- .../block-editor/src/components/inner-blocks/style.scss | 8 ++++++++ packages/block-library/src/columns/editor.scss | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/inner-blocks/style.scss b/packages/block-editor/src/components/inner-blocks/style.scss index 61ed91c42ac02f..ff8e4b9adbe96a 100644 --- a/packages/block-editor/src/components/inner-blocks/style.scss +++ b/packages/block-editor/src/components/inner-blocks/style.scss @@ -1,3 +1,5 @@ +// Add clickable overlay to blocks with nesting. +// This makes it easy to select all layers of the block. .block-editor-inner-blocks.has-overlay { &::after { content: ""; @@ -9,3 +11,9 @@ z-index: z-index(".block-editor-inner-blocks.has-overlay::after"); } } + +// On fullwide blocks, don't go beyond the canvas. +[data-align="full"] > .editor-block-list__block-edit > [data-block] .has-overlay::after { + right: 0; + left: 0; +} diff --git a/packages/block-library/src/columns/editor.scss b/packages/block-library/src/columns/editor.scss index f8780b91ebab53..6e9e2e60659114 100644 --- a/packages/block-library/src/columns/editor.scss +++ b/packages/block-library/src/columns/editor.scss @@ -21,7 +21,7 @@ // Fullwide: show margin left/right to ensure there's room for the side UI. // This is not a 1:1 preview with the front-end where these margins would presumably be zero. -.editor-block-list__block[data-align="full"] [data-type="core/columns"][data-align="full"] .wp-block-columns > .editor-inner-blocks { +[data-type="core/columns"][data-align="full"] .wp-block-columns > .editor-inner-blocks { padding-left: $block-padding; padding-right: $block-padding; From 61d4d51958997244d01ada6d10d90825cc194ffb Mon Sep 17 00:00:00 2001 From: Darren Ethier <darren@roughsmootheng.in> Date: Wed, 12 Jun 2019 08:40:59 -0400 Subject: [PATCH 108/132] Bump plugin version to 5.9.0 --- gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index d9c384353ca202..1450aa20c4b750 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -3,7 +3,7 @@ * Plugin Name: Gutenberg * Plugin URI: https://github.com/WordPress/gutenberg * Description: Printing since 1440. This is the development plugin for the new block editor in core. - * Version: 5.9.0-rc.1 + * Version: 5.9.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index aa639527442e65..c2c500f9773775 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.9.0-rc.1", + "version": "5.9.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 4ff2130f820687..0ce754a7d4579c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.9.0-rc.1", + "version": "5.9.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From f99e42b2ad7f175614e691917e144c0c3bc7809d Mon Sep 17 00:00:00 2001 From: etoledom <etoledom@icloud.com> Date: Wed, 12 Jun 2019 18:37:51 +0200 Subject: [PATCH 109/132] [RNMobile] Fix pasting text on Post Title (#16116) * Add onEnter prop to RichText to allow custom handling of onEnter * Remove reduntant line --- .../block-editor/src/components/rich-text/index.native.js | 5 +++++ packages/editor/src/components/post-title/index.native.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 0a33ebd32b491a..489d0a5fbeaa95 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -358,6 +358,11 @@ export class RichText extends Component { // eslint-disable-next-line no-unused-vars onEnter( event ) { + if ( this.props.onEnter ) { + this.props.onEnter(); + return; + } + this.lastEventCount = event.nativeEvent.eventCount; this.comesFromAztec = true; this.firedAfterTextChanged = event.nativeEvent.firedAfterTextChanged; diff --git a/packages/editor/src/components/post-title/index.native.js b/packages/editor/src/components/post-title/index.native.js index c895abcbebc108..2c9435e1ef6b36 100644 --- a/packages/editor/src/components/post-title/index.native.js +++ b/packages/editor/src/components/post-title/index.native.js @@ -102,7 +102,7 @@ class PostTitle extends Component { placeholder={ decodedPlaceholder } value={ title } onSplit={ () => { } } - onReplace={ this.props.onEnterPress } + onEnter={ this.props.onEnterPress } disableEditingMenu={ true } setRef={ ( ref ) => { this.titleViewRef = ref; From 590cfb53f970ab98af9c84446e4141d35b8ad92a Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Wed, 12 Jun 2019 18:00:52 +0100 Subject: [PATCH 110/132] chore(release): publish - @wordpress/a11y@2.4.0 - @wordpress/annotations@1.4.0 - @wordpress/api-fetch@3.3.0 - @wordpress/babel-preset-default@4.3.0 - @wordpress/block-editor@2.2.0 - @wordpress/block-library@2.6.0 - @wordpress/blocks@6.4.0 - @wordpress/browserslist-config@2.5.0 - @wordpress/components@8.0.0 - @wordpress/compose@3.4.0 - @wordpress/core-data@2.4.0 - @wordpress/custom-templated-path-webpack-plugin@1.4.0 - @wordpress/data-controls@1.0.0 - @wordpress/data@4.6.0 - @wordpress/deprecated@2.4.0 - @wordpress/dom-ready@2.4.0 - @wordpress/e2e-test-utils@2.1.0 - @wordpress/e2e-tests@1.3.0 - @wordpress/edit-post@3.5.0 - @wordpress/edit-widgets@0.4.0 - @wordpress/editor@9.4.0 - @wordpress/element@2.5.0 - @wordpress/escape-html@1.4.0 - @wordpress/eslint-plugin@2.3.0 - @wordpress/format-library@1.6.0 - @wordpress/hooks@2.4.0 - @wordpress/html-entities@2.4.0 - @wordpress/i18n@3.5.0 - @wordpress/is-shallow-equal@1.4.0 - @wordpress/jest-preset-default@4.2.0 - @wordpress/keycodes@2.4.0 - @wordpress/library-export-default-webpack-plugin@1.3.0 - @wordpress/list-reusable-blocks@1.5.0 - @wordpress/media-utils@0.2.0 - @wordpress/notices@1.5.0 - @wordpress/npm-package-json-lint-config@2.0.0 - @wordpress/nux@3.4.0 - @wordpress/plugins@2.4.0 - @wordpress/redux-routine@3.4.0 - @wordpress/rich-text@3.4.0 - @wordpress/scripts@3.3.0 - @wordpress/server-side-render@1.0.0 - @wordpress/token-list@1.4.0 - @wordpress/viewport@2.5.0 - @wordpress/wordcount@2.4.0 --- packages/a11y/package.json | 2 +- packages/annotations/package.json | 2 +- packages/api-fetch/package.json | 2 +- packages/babel-preset-default/package.json | 2 +- packages/block-editor/package.json | 2 +- packages/block-library/package.json | 2 +- packages/blocks/package.json | 2 +- packages/browserslist-config/package.json | 2 +- packages/components/package.json | 2 +- packages/compose/package.json | 2 +- packages/core-data/package.json | 2 +- packages/custom-templated-path-webpack-plugin/package.json | 2 +- packages/data-controls/package.json | 2 +- packages/data/package.json | 2 +- packages/deprecated/package.json | 2 +- packages/dom-ready/package.json | 2 +- packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/package.json | 2 +- packages/edit-post/package.json | 2 +- packages/edit-widgets/package.json | 2 +- packages/editor/package.json | 2 +- packages/element/package.json | 2 +- packages/escape-html/package.json | 2 +- packages/eslint-plugin/package.json | 2 +- packages/format-library/package.json | 2 +- packages/hooks/package.json | 2 +- packages/html-entities/package.json | 2 +- packages/i18n/package.json | 2 +- packages/is-shallow-equal/package.json | 2 +- packages/jest-preset-default/package.json | 2 +- packages/keycodes/package.json | 2 +- packages/library-export-default-webpack-plugin/package.json | 2 +- packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/package.json | 2 +- packages/notices/package.json | 2 +- packages/npm-package-json-lint-config/package.json | 2 +- packages/nux/package.json | 2 +- packages/plugins/package.json | 2 +- packages/redux-routine/package.json | 2 +- packages/rich-text/package.json | 2 +- packages/scripts/package.json | 2 +- packages/server-side-render/package.json | 2 +- packages/token-list/package.json | 2 +- packages/viewport/package.json | 2 +- packages/wordcount/package.json | 2 +- 45 files changed, 45 insertions(+), 45 deletions(-) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index fc3561a2bef4b8..1621eb97643289 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "2.3.0", + "version": "2.4.0", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 4f0c9165ff4edc..16bec17d283ed8 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "1.3.0", + "version": "1.4.0", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index 1c647d817bbf02..0221ac0a1e8a37 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "3.2.0", + "version": "3.3.0", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index 22c29f779e529e..e0ce0c0f2a3cd1 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "4.2.0", + "version": "4.3.0", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index d8b9d21b64dd4e..da701fc0c08669 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "2.1.0", + "version": "2.2.0", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index daa427cffd4a94..f57f2988524cee 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "2.5.0", + "version": "2.6.0", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/package.json b/packages/blocks/package.json index a00b6b505ab298..72f5fc9e3af87d 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "6.3.0", + "version": "6.4.0", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index 331b74b323fadd..9e70302edeb817 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "2.4.0", + "version": "2.5.0", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/package.json b/packages/components/package.json index df7d8afa76457f..99c44a249b7e42 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "7.4.0", + "version": "8.0.0", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/package.json b/packages/compose/package.json index f04e6d753ce11b..57eac024c3f47a 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "3.3.0", + "version": "3.4.0", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/package.json b/packages/core-data/package.json index 96b18edd614019..55f219865f0e69 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "2.3.0", + "version": "2.4.0", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/custom-templated-path-webpack-plugin/package.json b/packages/custom-templated-path-webpack-plugin/package.json index bf7af1e6a461f3..463e59991aa46b 100644 --- a/packages/custom-templated-path-webpack-plugin/package.json +++ b/packages/custom-templated-path-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/custom-templated-path-webpack-plugin", - "version": "1.3.0", + "version": "1.4.0", "description": "Webpack plugin for creating custom path template tags.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index 9ffbf80cd5165e..e54574c9eec93b 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "1.0.0-beta.1", + "version": "1.0.0", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/package.json b/packages/data/package.json index d0f2d74f354fc6..30d331281569c7 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "4.5.0", + "version": "4.6.0", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index 033c6ae472cf83..4315c6d81039aa 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "2.3.0", + "version": "2.4.0", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index d390d8db4ea3b0..827accd9b47dd7 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "2.3.0", + "version": "2.4.0", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index 4ab119dbc0557c..ab69632a58f6ee 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "2.0.0", + "version": "2.1.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 33943fda4cc2fe..d7b75699be7f83 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "1.2.1", + "version": "1.3.0", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index a2566dd750a75f..b6c85e26311ece 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "3.4.0", + "version": "3.5.0", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index d92d4a66c78068..1acce755f85426 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "0.3.0", + "version": "0.4.0", "private": true, "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", diff --git a/packages/editor/package.json b/packages/editor/package.json index 9578fdf41caf10..ed99bfb65a924e 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "9.3.0", + "version": "9.4.0", "description": "Building blocks for WordPress editors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/element/package.json b/packages/element/package.json index e67347a38cf9a3..4e4a096b31fe24 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "2.4.0", + "version": "2.5.0", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index a6687ebeb34a5a..4d2b81bd73259b 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "1.3.0", + "version": "1.4.0", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 9d009fd22b1b3f..9bcd60b15de867 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "2.2.0", + "version": "2.3.0", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/format-library/package.json b/packages/format-library/package.json index 66969a279a6e45..8b84cae37cf00f 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "1.5.0", + "version": "1.6.0", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 4f8a280c48dd87..bac2718aceb28a 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "2.3.0", + "version": "2.4.0", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 85c504daaad1c3..a6f449b3e2aaf0 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "2.3.0", + "version": "2.4.0", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index bdf92ce2757d52..721061946e221b 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "3.4.0", + "version": "3.5.0", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index 5e1effc9c00767..3850ff5e8f7d4e 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "1.3.0", + "version": "1.4.0", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index fa4e413adbfeeb..cb5de531080c01 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "4.1.0", + "version": "4.2.0", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index 5e6aa798c0aa85..695528df254808 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "2.3.0", + "version": "2.4.0", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/library-export-default-webpack-plugin/package.json b/packages/library-export-default-webpack-plugin/package.json index fcaf8a3de299e5..60daa21a7c288b 100644 --- a/packages/library-export-default-webpack-plugin/package.json +++ b/packages/library-export-default-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/library-export-default-webpack-plugin", - "version": "1.2.0", + "version": "1.3.0", "description": "Webpack plugin for exporting default property for selected libraries.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index 97efa2fbdf6552..2810b989b7fd01 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "1.4.0", + "version": "1.5.0", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index b56795b5d65975..8f6ff15ae9420b 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "0.1.0", + "version": "0.2.0", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/notices/package.json b/packages/notices/package.json index 237966556163a0..250ffed2398b0c 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "1.4.0", + "version": "1.5.0", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index e9af2edfa81ce9..c05441fbf88adc 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "1.3.0", + "version": "2.0.0", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/package.json b/packages/nux/package.json index 4102efd88c26b3..9768b542bc534c 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "3.3.0", + "version": "3.4.0", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index f0859bb278f4fe..86a1f40b8d5658 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "2.3.0", + "version": "2.4.0", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index a8cdace21091e8..3f6fea2c863b62 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "3.3.0", + "version": "3.4.0", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 304d7fdb78b6de..2422f20a872611 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "3.3.0", + "version": "3.4.0", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index c8d503efb886c6..681b40742999c5 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "3.2.1", + "version": "3.3.0", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 1f81f0be515781..3cb0ace0109874 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "1.0.0-alpha.1", + "version": "1.0.0", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/token-list/package.json b/packages/token-list/package.json index 206bb71eef2987..d7ca4747b7ad69 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "1.3.0", + "version": "1.4.0", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/viewport/package.json b/packages/viewport/package.json index 495f6bb81fafc4..334d7a834a112c 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "2.4.0", + "version": "2.5.0", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index a8f74123873112..f3bac4a49be8ef 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "2.3.0", + "version": "2.4.0", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From 6436f4cbe771b72149717f9eb8a6d201eae71ed7 Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Wed, 12 Jun 2019 18:11:09 +0100 Subject: [PATCH 111/132] Updating changelogs for the Gutenberg 5.9 packages release --- packages/block-editor/CHANGELOG.md | 2 +- packages/block-library/CHANGELOG.md | 2 +- packages/components/CHANGELOG.md | 2 +- packages/compose/CHANGELOG.md | 2 +- packages/custom-templated-path-webpack-plugin/CHANGELOG.md | 2 +- packages/data/CHANGELOG.md | 2 +- packages/editor/CHANGELOG.md | 2 +- packages/eslint-plugin/CHANGELOG.md | 2 +- packages/hooks/CHANGELOG.md | 2 +- packages/library-export-default-webpack-plugin/CHANGELOG.md | 2 +- packages/notices/CHANGELOG.md | 2 +- packages/npm-package-json-lint-config/CHANGELOG.md | 2 +- packages/scripts/CHANGELOG.md | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index f8f88cb313e74b..15e4a9de6b0a80 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 2.2.0 (2019-06-12) ### Internal diff --git a/packages/block-library/CHANGELOG.md b/packages/block-library/CHANGELOG.md index 4df19d8dee8ca9..d33c0a1ec92767 100644 --- a/packages/block-library/CHANGELOG.md +++ b/packages/block-library/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## ## 2.6.0 (2019-06-12) - Fixed an issue with creating upgraded embed blocks that are not registered ([#15883](https://github.com/WordPress/gutenberg/issues/15883)). diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index c1a4e6fef2b5f7..38e44d1c10cfba 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 8.0.0 (2019-06-12) ### New Feature diff --git a/packages/compose/CHANGELOG.md b/packages/compose/CHANGELOG.md index 30e39e3a50596c..af8f112ac8cdda 100644 --- a/packages/compose/CHANGELOG.md +++ b/packages/compose/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 3.4.0 (2019-06-12) ### New Features diff --git a/packages/custom-templated-path-webpack-plugin/CHANGELOG.md b/packages/custom-templated-path-webpack-plugin/CHANGELOG.md index 7b34a52f1071ad..d5bb664a3bfe58 100644 --- a/packages/custom-templated-path-webpack-plugin/CHANGELOG.md +++ b/packages/custom-templated-path-webpack-plugin/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 1.4.0 (2019-06-12) ### Bug Fixes diff --git a/packages/data/CHANGELOG.md b/packages/data/CHANGELOG.md index 6851e89823c6ac..a7a342725906e2 100644 --- a/packages/data/CHANGELOG.md +++ b/packages/data/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 4.6.0 (2019-06-12) ### New Feature diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md index 2bac55e10ac2e6..dd4389226720c5 100644 --- a/packages/editor/CHANGELOG.md +++ b/packages/editor/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 9.4.0 (2019-06-12) ### Deprecations diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index a88430165222ef..28de7846b5f212 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 2.3.0 (2019-06-12) ### Bug Fix diff --git a/packages/hooks/CHANGELOG.md b/packages/hooks/CHANGELOG.md index 0b070a6d3c0dbc..cb1625c912898f 100644 --- a/packages/hooks/CHANGELOG.md +++ b/packages/hooks/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 2.4.0 (2019-06-12) ### New Feature diff --git a/packages/library-export-default-webpack-plugin/CHANGELOG.md b/packages/library-export-default-webpack-plugin/CHANGELOG.md index 66b9261df4a8bc..dec500a334ca23 100644 --- a/packages/library-export-default-webpack-plugin/CHANGELOG.md +++ b/packages/library-export-default-webpack-plugin/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 1.3.0 (2019-06-12) ### Internal diff --git a/packages/notices/CHANGELOG.md b/packages/notices/CHANGELOG.md index 7a6fde4663c907..16695a45dd0122 100644 --- a/packages/notices/CHANGELOG.md +++ b/packages/notices/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 1.5.0 (2019-06-12) ### New Features diff --git a/packages/npm-package-json-lint-config/CHANGELOG.md b/packages/npm-package-json-lint-config/CHANGELOG.md index 2fbfc480934313..945e31866bbe8e 100644 --- a/packages/npm-package-json-lint-config/CHANGELOG.md +++ b/packages/npm-package-json-lint-config/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 2.0.0 (2019-06-12) ### Braking Change diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 1183fa6bd736d4..239314b3a61415 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -1,4 +1,4 @@ -## Master +## 3.3.0 (2019-06-12) ### New Features From a13c79d1d8854c69c7a52f3a3579cd2a3d33e085 Mon Sep 17 00:00:00 2001 From: Tammie Lister <tammie@automattic.com> Date: Wed, 12 Jun 2019 15:31:24 -0700 Subject: [PATCH 112/132] Update toolbar-text.png (#16102) Fixes #15026 --- .../assets/toolbar-text.png | Bin 22683 -> 2684 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/designers-developers/assets/toolbar-text.png b/docs/designers-developers/assets/toolbar-text.png index 76b18c6b8f368f3abd5d2559e5a6f71c75913ed4..8dbf503d503919ce80af90e3e704d833385c7404 100644 GIT binary patch literal 2684 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 A0{{R3 literal 22683 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 From 7ad33cb9a06792919e0a9e52274f5e41ebb2f4e5 Mon Sep 17 00:00:00 2001 From: Mel Choyce <melchoyce@users.noreply.github.com> Date: Wed, 12 Jun 2019 15:49:55 -0700 Subject: [PATCH 113/132] Add descriptive text and a link to embed documentation in embed blocks (#16101) * Add descriptive text and a link to embed documentation in embed blocks * Restructure placeholder to add instructions * Update tests * Standardize margin sizing --- packages/block-library/src/embed/editor.scss | 4 +++ .../src/embed/embed-placeholder.js | 14 ++++++-- .../embed/test/__snapshots__/index.js.snap | 36 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/embed/editor.scss b/packages/block-library/src/embed/editor.scss index 507d38c256688f..342b4fe1b116b2 100644 --- a/packages/block-library/src/embed/editor.scss +++ b/packages/block-library/src/embed/editor.scss @@ -37,6 +37,10 @@ .components-placeholder__error { word-break: break-word; } + + .components-placeholder__learn-more { + margin-top: 1em; + } } .block-library-embed__interactive-overlay { diff --git a/packages/block-library/src/embed/embed-placeholder.js b/packages/block-library/src/embed/embed-placeholder.js index b532d7b1a84a78..7a2a6f000a01f6 100644 --- a/packages/block-library/src/embed/embed-placeholder.js +++ b/packages/block-library/src/embed/embed-placeholder.js @@ -2,13 +2,18 @@ * WordPress dependencies */ import { __, _x } from '@wordpress/i18n'; -import { Button, Placeholder } from '@wordpress/components'; +import { Button, Placeholder, ExternalLink } from '@wordpress/components'; import { BlockIcon } from '@wordpress/block-editor'; const EmbedPlaceholder = ( props ) => { const { icon, label, value, onSubmit, onChange, cannotEmbed, fallback, tryAgain } = props; return ( - <Placeholder icon={ <BlockIcon icon={ icon } showColors /> } label={ label } className="wp-block-embed"> + <Placeholder + icon={ <BlockIcon icon={ icon } showColors /> } + label={ label } + className="wp-block-embed" + instructions={ __( 'Paste a link to the content you want to display on your site.' ) } + > <form onSubmit={ onSubmit }> <input type="url" @@ -29,6 +34,11 @@ const EmbedPlaceholder = ( props ) => { </p> } </form> + <div className="components-placeholder__learn-more"> + <ExternalLink href={ __( 'https://wordpress.org/support/article/embeds/' ) }> + { __( 'Learn more about embeds' ) } + </ExternalLink> + </div> </Placeholder> ); }; diff --git a/packages/block-library/src/embed/test/__snapshots__/index.js.snap b/packages/block-library/src/embed/test/__snapshots__/index.js.snap index 4b9c1f4de7f0e3..78923aa24c5f6b 100644 --- a/packages/block-library/src/embed/test/__snapshots__/index.js.snap +++ b/packages/block-library/src/embed/test/__snapshots__/index.js.snap @@ -27,6 +27,11 @@ exports[`core/embed block edit matches snapshot 1`] = ` </span> Embed URL </div> + <div + class="components-placeholder__instructions" + > + Paste a link to the content you want to display on your site. + </div> <div class="components-placeholder__fieldset" > @@ -45,6 +50,37 @@ exports[`core/embed block edit matches snapshot 1`] = ` Embed </button> </form> + <div + class="components-placeholder__learn-more" + > + <a + class="components-external-link" + href="https://wordpress.org/support/article/embeds/" + rel="external noreferrer noopener" + target="_blank" + > + Learn more about embeds + <span + class="screen-reader-text" + > + (opens in a new tab) + </span> + <svg + aria-hidden="true" + class="dashicon dashicons-external components-external-link__icon" + focusable="false" + height="20" + role="img" + viewBox="0 0 20 20" + width="20" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M9 3h8v8l-2-1V6.92l-5.6 5.59-1.41-1.41L14.08 5H10zm3 12v-3l2-2v7H3V6h8L9 8H5v7h7z" + /> + </svg> + </a> + </div> </div> </div> `; From 1f1dee35f8a94280c3d2754ec6cc73b2dcbf4a1f Mon Sep 17 00:00:00 2001 From: Kjell Reigstad <kjell.reigstad@automattic.com> Date: Wed, 12 Jun 2019 19:40:53 -0400 Subject: [PATCH 114/132] Bring greater consistency to placeholder text for media blocks. (#16135) --- .../src/components/media-placeholder/index.js | 8 ++++---- packages/block-library/src/cover/edit.js | 2 +- packages/block-library/src/file/edit.js | 2 +- packages/block-library/src/image/edit.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/components/media-placeholder/index.js b/packages/block-editor/src/components/media-placeholder/index.js index 07daa4d8f813eb..efad860f586e7a 100644 --- a/packages/block-editor/src/components/media-placeholder/index.js +++ b/packages/block-editor/src/components/media-placeholder/index.js @@ -175,14 +175,14 @@ export class MediaPlaceholder extends Component { const isVideo = isOneType && 'video' === allowedTypes[ 0 ]; if ( instructions === undefined && mediaUpload ) { - instructions = __( 'Drag a media file, upload a new one or select a file from your library.' ); + instructions = __( 'Upload a media file or pick one from your media library.' ); if ( isAudio ) { - instructions = __( 'Drag an audio, upload a new one or select a file from your library.' ); + instructions = __( 'Upload an audio file, pick one from your media library, or add one with a URL.' ); } else if ( isImage ) { - instructions = __( 'Drag an image, upload a new one or select a file from your library.' ); + instructions = __( 'Upload an image file, pick one from your media library, or add one with a URL.' ); } else if ( isVideo ) { - instructions = __( 'Drag a video, upload a new one or select a file from your library.' ); + instructions = __( 'Upload a video file, pick one from your media library, or add one with a URL.' ); } } diff --git a/packages/block-library/src/cover/edit.js b/packages/block-library/src/cover/edit.js index 05bb57786332df..7de37e53f3fc39 100644 --- a/packages/block-library/src/cover/edit.js +++ b/packages/block-library/src/cover/edit.js @@ -243,7 +243,7 @@ class CoverEdit extends Component { className={ className } labels={ { title: label, - instructions: __( 'Drag an image or a video, upload a new one or select a file from your library.' ), + instructions: __( 'Upload an image or video file, or pick one from your media library.' ), } } onSelect={ onSelectMedia } accept="image/*,video/*" diff --git a/packages/block-library/src/file/edit.js b/packages/block-library/src/file/edit.js index a27d22a326f474..2ab0baaa08f8bf 100644 --- a/packages/block-library/src/file/edit.js +++ b/packages/block-library/src/file/edit.js @@ -161,7 +161,7 @@ class FileEdit extends Component { icon={ <BlockIcon icon={ icon } /> } labels={ { title: __( 'File' ), - instructions: __( 'Drag a file, upload a new one or select a file from your library.' ), + instructions: __( 'Upload a file or pick one from your media library.' ), } } onSelect={ this.onSelectFile } notices={ noticeUI } diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index 42b271903fe049..7103c495e7a230 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -408,7 +408,7 @@ class ImageEdit extends Component { const src = isExternal ? url : undefined; const labels = { title: ! url ? __( 'Image' ) : __( 'Edit image' ), - instructions: __( 'Drag an image to upload, select a file from your library or add one from an URL.' ), + instructions: __( 'Upload an image, pick one from your media library, or add one with a URL.' ), }; const mediaPreview = ( !! url && <img alt={ __( 'Edit image' ) } From 6c453164cb11f5db22292cac9ddb9e8639dcc2ee Mon Sep 17 00:00:00 2001 From: Kjell Reigstad <kjell.reigstad@automattic.com> Date: Wed, 12 Jun 2019 22:46:59 -0400 Subject: [PATCH 115/132] Add mention of on Figma to CONTRIBUTING.md (#16140) * Add mention of on Figma to CONTRIBUTING.md * Clearly state that Figma is the "official" design app. * Minor updates. * Clarify the process to request Figma team membership --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 521f17e5b90798..001086875af3c8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Please see the [Developer Contributions section](/docs/contributors/develop.md) ## How Can Designers Contribute? -If you'd like to contribute to the design or front-end, feel free to contribute to tickets labelled [Needs Design](https://github.com/WordPress/gutenberg/issues?q=is%3Aissue+is%3Aopen+label%3A%22Needs+Design%22) or [Needs Design Feedback](https://github.com/WordPress/gutenberg/issues?q=is%3Aissue+is%3Aopen+label%3A"Needs+Design+Feedback%22). We could use your thoughtful replies, mockups, animatics, sketches, doodles. Proposed changes are best done as minimal and specific iterations on the work that precedes it so we can compare. If you use <a href="https://www.sketchapp.com/">Sketch</a>, you can grab <a href="https://cloudup.com/cMPXM8Va2cy">the source file for the mockups</a> (updated April 6th). +If you'd like to contribute to the design or front-end, feel free to contribute to tickets labelled [Needs Design](https://github.com/WordPress/gutenberg/issues?q=is%3Aissue+is%3Aopen+label%3A%22Needs+Design%22) or [Needs Design Feedback](https://github.com/WordPress/gutenberg/issues?q=is%3Aissue+is%3Aopen+label%3A"Needs+Design+Feedback%22). We could use your thoughtful replies, mockups, animatics, sketches, doodles. Proposed changes are best done as minimal and specific iterations on the work that precedes it so we can compare. The [WordPress Design team](http://make.wordpress.org/design/) uses [Figma](https://www.figma.com/) to collaborate and share work. If you'd like to contribute, join the [#design channel](http://wordpress.slack.com/messages/design/) in [Slack](https://make.wordpress.org/chat/) and ask the team to set you up with a free Figma account. This will give you access to a helpful [library of components](https://www.figma.com/file/ZtN5xslEVYgzU7Dd5CxgGZwq/WordPress-Components?node-id=0%3A1) used in WordPress. ## Contribute to the Documentation From 66fbbc33993d5130ae0018780b04b17dc6748370 Mon Sep 17 00:00:00 2001 From: Technote <technote.space@gmail.com> Date: Thu, 13 Jun 2019 16:29:26 +0900 Subject: [PATCH 116/132] docs(block-editor/components/inspector-controls): fix image path in README.md (#16145) --- .../block-editor/src/components/inspector-controls/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/inspector-controls/README.md b/packages/block-editor/src/components/inspector-controls/README.md index f8b19593fbf976..2c6a21d59dbaf5 100644 --- a/packages/block-editor/src/components/inspector-controls/README.md +++ b/packages/block-editor/src/components/inspector-controls/README.md @@ -1,6 +1,6 @@ # Inspector Controls -<img src="https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/blocks/inspector.png" with="281" height="527" alt="inspector"> +<img src="https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/assets/inspector.png" with="281" height="527" alt="inspector"> Inspector Controls appear in the post settings sidebar when a block is being edited. The controls appear in both HTML and visual editing modes, and thus should contain settings that affect the entire block. From bd4363dc63d9e4d457e89cb87597c06e18fdefdf Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Thu, 13 Jun 2019 04:02:33 -0400 Subject: [PATCH 117/132] docs(components/with-focus-return): fix typo in README.md (#16143) --- .../components/src/higher-order/with-focus-return/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/higher-order/with-focus-return/README.md b/packages/components/src/higher-order/with-focus-return/README.md index 15ec5ef09ef258..f0872f15600f3d 100644 --- a/packages/components/src/higher-order/with-focus-return/README.md +++ b/packages/components/src/higher-order/with-focus-return/README.md @@ -2,7 +2,7 @@ `withFocusReturn` is a higher-order component used typically in scenarios of short-lived elements (modals, dropdowns) where, upon the element's unmounting, focus should be restored to the focused element which had initiated it being rendered. -Optionally, it can be used in combination with a `FocusRenderProvider` which, when rendered toward the top of an application, will remember a history of elements focused during a session. This can provide safeguards for scenarios where one short-lived element triggers the creation of another (e.g. a dropdown menu triggering a modal display). The combined effect of `FocusRenderProvider` and `withFocusReturn` is that focus will be returned to the most recent focused element which is still present in the document. +Optionally, it can be used in combination with a `FocusReturnProvider` which, when rendered toward the top of an application, will remember a history of elements focused during a session. This can provide safeguards for scenarios where one short-lived element triggers the creation of another (e.g. a dropdown menu triggering a modal display). The combined effect of `FocusReturnProvider` and `withFocusReturn` is that focus will be returned to the most recent focused element which is still present in the document. ## Usage From a58bcdb0b5b8020c62e2632556ab79b658f746a9 Mon Sep 17 00:00:00 2001 From: Derek Sifford <dereksifford@gmail.com> Date: Thu, 13 Jun 2019 06:07:01 -0400 Subject: [PATCH 118/132] docs(components/higher-order/with-spoken-messages): fix issue in example code (#16144) --- .../src/higher-order/with-spoken-messages/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/higher-order/with-spoken-messages/README.md b/packages/components/src/higher-order/with-spoken-messages/README.md index 1cb09651b7919d..5e539b3f3d5725 100644 --- a/packages/components/src/higher-order/with-spoken-messages/README.md +++ b/packages/components/src/higher-order/with-spoken-messages/README.md @@ -7,8 +7,8 @@ import { withSpokenMessages, Button } from '@wordpress/components'; const MyComponentWithSpokenMessages = withSpokenMessages( ( { speak, debouncedSpeak } ) => ( <div> - <Button isDefault onClick={ speak( 'Spoken message' ) }>Speak</Button> - <Button isDefault onClick={ debouncedSpeak( 'Delayed message' ) }>Debounced Speak</Button> + <Button isDefault onClick={ () => speak( 'Spoken message' ) }>Speak</Button> + <Button isDefault onClick={ () => debouncedSpeak( 'Delayed message' ) }>Debounced Speak</Button> </div> ) ); ``` From 7a5fd5543147981ca650a753ac3e2110fe2dbadf Mon Sep 17 00:00:00 2001 From: Tugdual de Kerviler <dekervit@gmail.com> Date: Thu, 13 Jun 2019 13:00:53 +0200 Subject: [PATCH 119/132] Add native support for Inserter (Ported from gutenberg-mobile) (#16114) --- .../src/components/index.native.js | 1 + .../src/components/inserter/index.native.js | 96 +++++++++++++++++++ .../src/components/inserter/style.native.scss | 57 +++++++++++ packages/blocks/src/api/index.native.js | 4 + 4 files changed, 158 insertions(+) create mode 100644 packages/block-editor/src/components/inserter/index.native.js create mode 100644 packages/block-editor/src/components/inserter/style.native.scss diff --git a/packages/block-editor/src/components/index.native.js b/packages/block-editor/src/components/index.native.js index df605eb54da3f2..5b3249e1f1a8a9 100644 --- a/packages/block-editor/src/components/index.native.js +++ b/packages/block-editor/src/components/index.native.js @@ -20,6 +20,7 @@ export { default as BlockInvalidWarning } from './block-list/block-invalid-warni // Content Related Components export { default as DefaultBlockAppender } from './default-block-appender'; +export { default as Inserter } from './inserter'; // State Related Components export { default as BlockEditorProvider } from './provider'; diff --git a/packages/block-editor/src/components/inserter/index.native.js b/packages/block-editor/src/components/inserter/index.native.js new file mode 100644 index 00000000000000..2985d61c7811c4 --- /dev/null +++ b/packages/block-editor/src/components/inserter/index.native.js @@ -0,0 +1,96 @@ +/** + * External dependencies + */ +import { FlatList, Text, TouchableHighlight, View } from 'react-native'; + +/** + * WordPress dependencies + */ +import { BottomSheet, Icon } from '@wordpress/components'; +import { Component } from '@wordpress/element'; +import { withSelect } from '@wordpress/data'; +import { compose } from '@wordpress/compose'; +import { getUnregisteredTypeHandlerName } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import styles from './style.scss'; + +class Inserter extends Component { + calculateNumberOfColumns() { + const bottomSheetWidth = BottomSheet.getWidth(); + const { paddingLeft: itemPaddingLeft, paddingRight: itemPaddingRight } = styles.modalItem; + const { paddingLeft: containerPaddingLeft, paddingRight: containerPaddingRight } = styles.content; + const { width: itemWidth } = styles.modalIconWrapper; + const itemTotalWidth = itemWidth + itemPaddingLeft + itemPaddingRight; + const containerTotalWidth = bottomSheetWidth - ( containerPaddingLeft + containerPaddingRight ); + return Math.floor( containerTotalWidth / itemTotalWidth ); + } + + render() { + const numberOfColumns = this.calculateNumberOfColumns(); + const bottomPadding = this.props.addExtraBottomPadding && styles.contentBottomPadding; + + return ( + <BottomSheet + isVisible={ true } + onClose={ this.props.onDismiss } + contentStyle={ [ styles.content, bottomPadding ] } + hideHeader + > + <FlatList + scrollEnabled={ false } + key={ `InserterUI-${ numberOfColumns }` } //re-render when numberOfColumns changes + keyboardShouldPersistTaps="always" + numColumns={ numberOfColumns } + data={ this.props.items } + ItemSeparatorComponent={ () => + <View style={ styles.rowSeparator } /> + } + keyExtractor={ ( item ) => item.name } + renderItem={ ( { item } ) => + <TouchableHighlight + style={ styles.touchableArea } + underlayColor="transparent" + activeOpacity={ .5 } + accessibilityLabel={ item.title } + onPress={ () => this.props.onValueSelected( item.name ) }> + <View style={ styles.modalItem }> + <View style={ styles.modalIconWrapper }> + <View style={ styles.modalIcon }> + <Icon icon={ item.icon.src } fill={ styles.modalIcon.fill } size={ styles.modalIcon.width } /> + </View> + </View> + <Text style={ styles.modalItemLabel }>{ item.title }</Text> + </View> + </TouchableHighlight> + } + /> + </BottomSheet> + ); + } +} + +export default compose( [ + withSelect( ( select, { clientId, isAppender, rootClientId } ) => { + const { + getInserterItems, + getBlockRootClientId, + getBlockSelectionEnd, + } = select( 'core/block-editor' ); + + let destinationRootClientId = rootClientId; + if ( ! destinationRootClientId && ! clientId && ! isAppender ) { + const end = getBlockSelectionEnd(); + if ( end ) { + destinationRootClientId = getBlockRootClientId( end ) || undefined; + } + } + const inserterItems = getInserterItems( destinationRootClientId ); + + return { + items: inserterItems.filter( ( { name } ) => name !== getUnregisteredTypeHandlerName() ), + }; + } ), +] )( Inserter ); diff --git a/packages/block-editor/src/components/inserter/style.native.scss b/packages/block-editor/src/components/inserter/style.native.scss new file mode 100644 index 00000000000000..82d5fa58226504 --- /dev/null +++ b/packages/block-editor/src/components/inserter/style.native.scss @@ -0,0 +1,57 @@ +/** @format */ + +.touchableArea { + border-radius: 8px 8px 8px 8px; +} + +.content { + padding: 0 0 0 0; + align-items: center; + justify-content: space-evenly; +} + +.contentBottomPadding { + padding-bottom: 20px; +} + +.rowSeparator { + height: 12px; +} + +.modalItem { + flex-direction: column; + justify-content: center; + align-items: center; + padding-left: 8; + padding-right: 8; + padding-top: 0; + padding-bottom: 0; +} + +.modalIconWrapper { + width: 104px; + height: 64px; + background-color: $gray-light; //#f3f6f8 + border-radius: 8px 8px 8px 8px; + justify-content: center; + align-items: center; +} + +.modalIcon { + width: 32px; + height: 32px; + justify-content: center; + align-items: center; + fill: $gray-dark; +} + +.modalItemLabel { + background-color: transparent; + padding-left: 2; + padding-right: 2; + padding-top: 4; + padding-bottom: 0; + justify-content: center; + font-size: 12; + color: $gray-dark; +} diff --git a/packages/blocks/src/api/index.native.js b/packages/blocks/src/api/index.native.js index 123be1e132a992..b99fccc531c217 100644 --- a/packages/blocks/src/api/index.native.js +++ b/packages/blocks/src/api/index.native.js @@ -21,8 +21,12 @@ export { getUnregisteredTypeHandlerName, getBlockType, getBlockTypes, + getBlockSupport, hasBlockSupport, isReusableBlock, + getChildBlockNames, + hasChildBlocks, + hasChildBlocksWithInserterSupport, setDefaultBlockName, getDefaultBlockName, } from './registration'; From 30e3fae499833be176ea4ed92b08c01b1559d074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= <grzegorz@gziolo.pl> Date: Fri, 14 Jun 2019 07:51:09 +0200 Subject: [PATCH 120/132] Scripts: Fix naming conventions for function containing CLI keyword (#16091) --- packages/scripts/bin/wp-scripts.js | 4 ++-- packages/scripts/scripts/check-engines.js | 14 ++++++------- packages/scripts/scripts/check-licenses.js | 12 +++++------ packages/scripts/scripts/lint-js.js | 16 +++++++-------- packages/scripts/scripts/lint-pkg-json.js | 16 +++++++-------- packages/scripts/scripts/lint-style.js | 14 ++++++------- packages/scripts/scripts/test-e2e.js | 20 +++++++++--------- packages/scripts/scripts/test-unit-jest.js | 4 ++-- packages/scripts/utils/cli.js | 18 ++++++++-------- packages/scripts/utils/config.js | 10 ++++----- packages/scripts/utils/index.js | 16 +++++++-------- packages/scripts/utils/process.js | 4 ++-- packages/scripts/utils/test/index.js | 24 +++++++++++----------- 13 files changed, 86 insertions(+), 86 deletions(-) diff --git a/packages/scripts/bin/wp-scripts.js b/packages/scripts/bin/wp-scripts.js index 05e9154da4a9b9..a74076ead7f85f 100755 --- a/packages/scripts/bin/wp-scripts.js +++ b/packages/scripts/bin/wp-scripts.js @@ -3,8 +3,8 @@ /** * Internal dependencies */ -const { getCliArgs, spawnScript } = require( '../utils' ); +const { getArgsFromCLI, spawnScript } = require( '../utils' ); -const [ scriptName, ...nodesArgs ] = getCliArgs(); +const [ scriptName, ...nodesArgs ] = getArgsFromCLI(); spawnScript( scriptName, nodesArgs ); diff --git a/packages/scripts/scripts/check-engines.js b/packages/scripts/scripts/check-engines.js index 5440e27ccaffba..aba446313e5a93 100644 --- a/packages/scripts/scripts/check-engines.js +++ b/packages/scripts/scripts/check-engines.js @@ -8,16 +8,16 @@ const { sync: resolveBin } = require( 'resolve-bin' ); * Internal dependencies */ const { - getCliArgs, - hasCliArg, + getArgsFromCLI, + hasArgInCLI, } = require( '../utils' ); -const args = getCliArgs(); +const args = getArgsFromCLI(); -const hasConfig = hasCliArg( '--package' ) || - hasCliArg( '--node' ) || - hasCliArg( '--npm' ) || - hasCliArg( '--yarn' ); +const hasConfig = hasArgInCLI( '--package' ) || + hasArgInCLI( '--node' ) || + hasArgInCLI( '--npm' ) || + hasArgInCLI( '--yarn' ); const config = ! hasConfig ? [ '--node', '>=10.0.0', diff --git a/packages/scripts/scripts/check-licenses.js b/packages/scripts/scripts/check-licenses.js index 7670ae3b0d2140..1b1d46b9befbce 100644 --- a/packages/scripts/scripts/check-licenses.js +++ b/packages/scripts/scripts/check-licenses.js @@ -9,7 +9,7 @@ const chalk = require( 'chalk' ); /** * Internal dependencies */ -const { getCliArg, hasCliArg } = require( '../utils' ); +const { getArgFromCLI, hasArgInCLI } = require( '../utils' ); /* * WARNING: Changes to this file may inadvertently cause us to distribute code that @@ -22,11 +22,11 @@ const { getCliArg, hasCliArg } = require( '../utils' ); const ERROR = chalk.reset.inverse.bold.red( ' ERROR ' ); -const prod = hasCliArg( '--prod' ) || hasCliArg( '--production' ); -const dev = hasCliArg( '--dev' ) || hasCliArg( '--development' ); -const gpl2 = hasCliArg( '--gpl2' ); -const ignored = hasCliArg( '--ignore' ) ? - getCliArg( '--ignore' ) +const prod = hasArgInCLI( '--prod' ) || hasArgInCLI( '--production' ); +const dev = hasArgInCLI( '--dev' ) || hasArgInCLI( '--development' ); +const gpl2 = hasArgInCLI( '--gpl2' ); +const ignored = hasArgInCLI( '--ignore' ) ? + getArgFromCLI( '--ignore' ) // "--ignore=a, b" -> "[ 'a', ' b' ]" .split( ',' ) // "[ 'a', ' b' ]" -> "[ 'a', 'b' ]" diff --git a/packages/scripts/scripts/lint-js.js b/packages/scripts/scripts/lint-js.js index af2e450037b397..dc55a358c3e158 100644 --- a/packages/scripts/scripts/lint-js.js +++ b/packages/scripts/scripts/lint-js.js @@ -9,20 +9,20 @@ const { sync: resolveBin } = require( 'resolve-bin' ); */ const { fromConfigRoot, - getCliArgs, - hasCliArg, - hasFileInCliArgs, + getArgsFromCLI, + hasArgInCLI, + hasFileArgInCLI, hasPackageProp, hasProjectFile, } = require( '../utils' ); -const args = getCliArgs(); +const args = getArgsFromCLI(); -const defaultFilesArgs = hasFileInCliArgs() ? [] : [ '.' ]; +const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '.' ]; // See: https://eslint.org/docs/user-guide/configuring#using-configuration-files-1. -const hasLintConfig = hasCliArg( '-c' ) || - hasCliArg( '--config' ) || +const hasLintConfig = hasArgInCLI( '-c' ) || + hasArgInCLI( '--config' ) || hasProjectFile( '.eslintrc.js' ) || hasProjectFile( '.eslintrc.yaml' ) || hasProjectFile( '.eslintrc.yml' ) || @@ -38,7 +38,7 @@ const defaultConfigArgs = ! hasLintConfig ? []; // See: https://eslint.org/docs/user-guide/configuring#ignoring-files-and-directories. -const hasIgnoredFiles = hasCliArg( '--ignore-path' ) || +const hasIgnoredFiles = hasArgInCLI( '--ignore-path' ) || hasProjectFile( '.eslintignore' ); const defaultIgnoreArgs = ! hasIgnoredFiles ? diff --git a/packages/scripts/scripts/lint-pkg-json.js b/packages/scripts/scripts/lint-pkg-json.js index 6c328cb0169bff..487a8191067dbc 100644 --- a/packages/scripts/scripts/lint-pkg-json.js +++ b/packages/scripts/scripts/lint-pkg-json.js @@ -9,20 +9,20 @@ const { sync: resolveBin } = require( 'resolve-bin' ); */ const { fromConfigRoot, - getCliArgs, - hasCliArg, - hasFileInCliArgs, + getArgsFromCLI, + hasArgInCLI, + hasFileArgInCLI, hasProjectFile, hasPackageProp, } = require( '../utils' ); -const args = getCliArgs(); +const args = getArgsFromCLI(); -const defaultFilesArgs = hasFileInCliArgs() ? [] : [ '.' ]; +const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '.' ]; // See: https://github.com/tclindner/npm-package-json-lint/wiki/configuration#configuration. -const hasLintConfig = hasCliArg( '-c' ) || - hasCliArg( '--configFile' ) || +const hasLintConfig = hasArgInCLI( '-c' ) || + hasArgInCLI( '--configFile' ) || hasProjectFile( '.npmpackagejsonlintrc.json' ) || hasProjectFile( 'npmpackagejsonlint.config.js' ) || hasPackageProp( 'npmPackageJsonLintConfig' ); @@ -32,7 +32,7 @@ const defaultConfigArgs = ! hasLintConfig ? []; // See: https://github.com/tclindner/npm-package-json-lint/#cli-commands-and-configuration. -const hasIgnoredFiles = hasCliArg( '--ignorePath' ) || +const hasIgnoredFiles = hasArgInCLI( '--ignorePath' ) || hasProjectFile( '.npmpackagejsonlintignore' ); const defaultIgnoreArgs = ! hasIgnoredFiles ? diff --git a/packages/scripts/scripts/lint-style.js b/packages/scripts/scripts/lint-style.js index 9d22a81c96ba25..3f7e86fc43277f 100644 --- a/packages/scripts/scripts/lint-style.js +++ b/packages/scripts/scripts/lint-style.js @@ -9,19 +9,19 @@ const { sync: resolveBin } = require( 'resolve-bin' ); */ const { fromConfigRoot, - getCliArgs, - hasCliArg, - hasFileInCliArgs, + getArgsFromCLI, + hasArgInCLI, + hasFileArgInCLI, hasProjectFile, hasPackageProp, } = require( '../utils' ); -const args = getCliArgs(); +const args = getArgsFromCLI(); -const defaultFilesArgs = hasFileInCliArgs() ? [] : [ '**/*.{css,scss}' ]; +const defaultFilesArgs = hasFileArgInCLI() ? [] : [ '**/*.{css,scss}' ]; // See: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#loading-the-configuration-object. -const hasLintConfig = hasCliArg( '--config' ) || +const hasLintConfig = hasArgInCLI( '--config' ) || hasProjectFile( '.stylelintrc' ) || hasProjectFile( '.stylelintrc.js' ) || hasProjectFile( '.stylelintrc.json' ) || @@ -35,7 +35,7 @@ const defaultConfigArgs = ! hasLintConfig ? []; // See: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/configuration.md#stylelintignore. -const hasIgnoredFiles = hasCliArg( '--ignore-path' ) || +const hasIgnoredFiles = hasArgInCLI( '--ignore-path' ) || hasProjectFile( '.stylelintignore' ); const defaultIgnoreArgs = ! hasIgnoredFiles ? diff --git a/packages/scripts/scripts/test-e2e.js b/packages/scripts/scripts/test-e2e.js index 374ebc59f6fbe5..efa0c834df2394 100644 --- a/packages/scripts/scripts/test-e2e.js +++ b/packages/scripts/scripts/test-e2e.js @@ -19,9 +19,9 @@ const jest = require( 'jest' ); */ const { fromConfigRoot, - getCliArg, - getCliArgs, - hasCliArg, + getArgFromCLI, + getArgsFromCLI, + hasArgInCLI, hasProjectFile, hasJestConfig, } = require( '../utils' ); @@ -37,15 +37,15 @@ const config = ! hasJestConfig() ? [ '--config', JSON.stringify( require( fromConfigRoot( 'jest-e2e.config.js' ) ) ) ] : []; -const hasRunInBand = hasCliArg( '--runInBand' ) || - hasCliArg( '-i' ); +const hasRunInBand = hasArgInCLI( '--runInBand' ) || + hasArgInCLI( '-i' ); const runInBand = ! hasRunInBand ? [ '--runInBand' ] : []; -if ( hasCliArg( '--puppeteer-interactive' ) ) { +if ( hasArgInCLI( '--puppeteer-interactive' ) ) { process.env.PUPPETEER_HEADLESS = 'false'; - process.env.PUPPETEER_SLOWMO = getCliArg( '--puppeteer-slowmo' ) || 80; + process.env.PUPPETEER_SLOWMO = getArgFromCLI( '--puppeteer-slowmo' ) || 80; } const configsMapping = { @@ -55,11 +55,11 @@ const configsMapping = { }; Object.entries( configsMapping ).forEach( ( [ envKey, argName ] ) => { - if ( hasCliArg( argName ) ) { - process.env[ envKey ] = getCliArg( argName ); + if ( hasArgInCLI( argName ) ) { + process.env[ envKey ] = getArgFromCLI( argName ); } } ); const cleanUpPrefixes = [ '--puppeteer-', '--wordpress-' ]; -jest.run( [ ...config, ...runInBand, ...getCliArgs( cleanUpPrefixes ) ] ); +jest.run( [ ...config, ...runInBand, ...getArgsFromCLI( cleanUpPrefixes ) ] ); diff --git a/packages/scripts/scripts/test-unit-jest.js b/packages/scripts/scripts/test-unit-jest.js index 1fb5743ac861c0..e7edf3c69ccdb4 100644 --- a/packages/scripts/scripts/test-unit-jest.js +++ b/packages/scripts/scripts/test-unit-jest.js @@ -19,7 +19,7 @@ const jest = require( 'jest' ); */ const { fromConfigRoot, - getCliArgs, + getArgsFromCLI, hasJestConfig, } = require( '../utils' ); @@ -27,4 +27,4 @@ const config = ! hasJestConfig() ? [ '--config', JSON.stringify( require( fromConfigRoot( 'jest-unit.config.js' ) ) ) ] : []; -jest.run( [ ...config, ...getCliArgs() ] ); +jest.run( [ ...config, ...getArgsFromCLI() ] ); diff --git a/packages/scripts/utils/cli.js b/packages/scripts/utils/cli.js index db4ce5fcef2d49..ab29ad4fa769e3 100644 --- a/packages/scripts/utils/cli.js +++ b/packages/scripts/utils/cli.js @@ -13,11 +13,11 @@ const { } = require( './file' ); const { exit, - getCliArgs, + getArgsFromCLI, } = require( './process' ); -const getCliArg = ( arg ) => { - for ( const cliArg of getCliArgs() ) { +const getArgFromCLI = ( arg ) => { + for ( const cliArg of getArgsFromCLI() ) { const [ name, value ] = cliArg.split( '=' ); if ( name === arg ) { return value || null; @@ -25,9 +25,9 @@ const getCliArg = ( arg ) => { } }; -const hasCliArg = ( arg ) => getCliArg( arg ) !== undefined; +const hasArgInCLI = ( arg ) => getArgFromCLI( arg ) !== undefined; -const hasFileInCliArgs = () => minimist( getCliArgs() )._.length > 0; +const hasFileArgInCLI = () => minimist( getArgsFromCLI() )._.length > 0; const handleSignal = ( signal ) => { if ( signal === 'SIGKILL' ) { @@ -81,9 +81,9 @@ const spawnScript = ( scriptName, args = [] ) => { }; module.exports = { - getCliArg, - getCliArgs, - hasCliArg, - hasFileInCliArgs, + getArgFromCLI, + getArgsFromCLI, + hasArgInCLI, + hasFileArgInCLI, spawnScript, }; diff --git a/packages/scripts/utils/config.js b/packages/scripts/utils/config.js index 3ae98725e5fbc7..9247f93a941717 100644 --- a/packages/scripts/utils/config.js +++ b/packages/scripts/utils/config.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -const { hasCliArg, getCliArgs } = require( './cli' ); +const { hasArgInCLI, getArgsFromCLI } = require( './cli' ); const { fromConfigRoot, hasProjectFile } = require( './file' ); const { hasPackageProp } = require( './package' ); @@ -12,18 +12,18 @@ const hasBabelConfig = () => hasPackageProp( 'babel' ); const hasJestConfig = () => - hasCliArg( '-c' ) || - hasCliArg( '--config' ) || + hasArgInCLI( '-c' ) || + hasArgInCLI( '--config' ) || hasProjectFile( 'jest.config.js' ) || hasProjectFile( 'jest.config.json' ) || hasPackageProp( 'jest' ); -const hasWebpackConfig = () => hasCliArg( '--config' ) || +const hasWebpackConfig = () => hasArgInCLI( '--config' ) || hasProjectFile( 'webpack.config.js' ) || hasProjectFile( 'webpack.config.babel.js' ); const getWebpackArgs = ( additionalArgs = [] ) => { - const webpackArgs = getCliArgs(); + const webpackArgs = getArgsFromCLI(); if ( ! hasWebpackConfig() ) { webpackArgs.push( '--config', fromConfigRoot( 'webpack.config.js' ) ); } diff --git a/packages/scripts/utils/index.js b/packages/scripts/utils/index.js index 2912c9aee22bbb..f356d401356cd1 100644 --- a/packages/scripts/utils/index.js +++ b/packages/scripts/utils/index.js @@ -2,10 +2,10 @@ * Internal dependencies */ const { - getCliArg, - getCliArgs, - hasCliArg, - hasFileInCliArgs, + getArgFromCLI, + getArgsFromCLI, + hasArgInCLI, + hasFileArgInCLI, spawnScript, } = require( './cli' ); const { @@ -27,12 +27,12 @@ const { module.exports = { camelCaseDash, fromConfigRoot, - getCliArg, - getCliArgs, + getArgFromCLI, + getArgsFromCLI, getWebpackArgs, hasBabelConfig, - hasCliArg, - hasFileInCliArgs, + hasArgInCLI, + hasFileArgInCLI, hasJestConfig, hasPackageProp, hasProjectFile, diff --git a/packages/scripts/utils/process.js b/packages/scripts/utils/process.js index cfa38afa26aa94..4996190d21e539 100644 --- a/packages/scripts/utils/process.js +++ b/packages/scripts/utils/process.js @@ -1,4 +1,4 @@ -const getCliArgs = ( excludePrefixes ) => { +const getArgsFromCLI = ( excludePrefixes ) => { const args = process.argv.slice( 2 ); if ( excludePrefixes ) { return args.filter( ( arg ) => { @@ -10,6 +10,6 @@ const getCliArgs = ( excludePrefixes ) => { module.exports = { exit: process.exit, - getCliArgs, + getArgsFromCLI, getCurrentWorkingDirectory: process.cwd, }; diff --git a/packages/scripts/utils/test/index.js b/packages/scripts/utils/test/index.js index d451a7540411dc..778c51dedb6e9f 100644 --- a/packages/scripts/utils/test/index.js +++ b/packages/scripts/utils/test/index.js @@ -7,7 +7,7 @@ import crossSpawn from 'cross-spawn'; * Internal dependencies */ import { - hasCliArg, + hasArgInCLI, hasProjectFile, spawnScript, } from '../'; @@ -16,7 +16,7 @@ import { } from '../package'; import { exit as exitMock, - getCliArgs as getCliArgsMock, + getArgsFromCLI as getArgsFromCLIMock, } from '../process'; jest.mock( '../package', () => { @@ -30,7 +30,7 @@ jest.mock( '../process', () => { const module = require.requireActual( '../process' ); jest.spyOn( module, 'exit' ); - jest.spyOn( module, 'getCliArgs' ); + jest.spyOn( module, 'getArgsFromCLI' ); return module; } ); @@ -38,29 +38,29 @@ jest.mock( '../process', () => { describe( 'utils', () => { const crossSpawnMock = jest.spyOn( crossSpawn, 'sync' ); - describe( 'hasCliArg', () => { + describe( 'hasArgInCLI', () => { beforeAll( () => { - getCliArgsMock.mockReturnValue( [ '-a', '--b', '--config=test' ] ); + getArgsFromCLIMock.mockReturnValue( [ '-a', '--b', '--config=test' ] ); } ); afterAll( () => { - getCliArgsMock.mockReset(); + getArgsFromCLIMock.mockReset(); } ); test( 'should return false when no args passed', () => { - getCliArgsMock.mockReturnValueOnce( [] ); + getArgsFromCLIMock.mockReturnValueOnce( [] ); - expect( hasCliArg( '--no-args' ) ).toBe( false ); + expect( hasArgInCLI( '--no-args' ) ).toBe( false ); } ); test( 'should return false when checking for unrecognized arg', () => { - expect( hasCliArg( '--non-existent' ) ).toBe( false ); + expect( hasArgInCLI( '--non-existent' ) ).toBe( false ); } ); test( 'should return true when CLI arg found', () => { - expect( hasCliArg( '-a' ) ).toBe( true ); - expect( hasCliArg( '--b' ) ).toBe( true ); - expect( hasCliArg( '--config' ) ).toBe( true ); + expect( hasArgInCLI( '-a' ) ).toBe( true ); + expect( hasArgInCLI( '--b' ) ).toBe( true ); + expect( hasArgInCLI( '--config' ) ).toBe( true ); } ); } ); From 0bc7aea2a2c0902ffc42d5950f731bbc1de9ce44 Mon Sep 17 00:00:00 2001 From: Andrew Duthie <andrew@andrewduthie.com> Date: Fri, 14 Jun 2019 01:54:17 -0400 Subject: [PATCH 121/132] Build Tooling: Use "full" `npm install` for Build Artifacts Travis task (#16166) --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 8d1046f2104d1d..60a40cec454eb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,11 @@ jobs: - name: Build artifacts install: - - npm ci + # A "full" install is executed, since `npm ci` does not always exit + # with an error status code if the lock file is inaccurate. + # + # See: https://github.com/WordPress/gutenberg/issues/16157 + - npm install script: - npm run check-local-changes From 0d242890179b836921bb1c92748239308506a2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= <grzegorz@gziolo.pl> Date: Fri, 14 Jun 2019 08:42:42 +0200 Subject: [PATCH 122/132] Editor: Fix the issue where statics for deprecated components were not hoisted (#16152) --- packages/editor/src/components/deprecated.js | 30 +++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/editor/src/components/deprecated.js b/packages/editor/src/components/deprecated.js index 44758b2ea29a4e..022da5c4023fa2 100644 --- a/packages/editor/src/components/deprecated.js +++ b/packages/editor/src/components/deprecated.js @@ -41,7 +41,6 @@ import { RichText as RootRichText, RichTextShortcut as RootRichTextShortcut, RichTextToolbarButton as RootRichTextToolbarButton, - RichTextInserterItem as RootRichTextInserterItem, __unstableRichTextInputEvent as __unstableRootRichTextInputEvent, MediaPlaceholder as RootMediaPlaceholder, MediaUpload as RootMediaUpload, @@ -64,14 +63,23 @@ import { export { default as ServerSideRender } from '@wordpress/server-side-render'; -function deprecateComponent( name, Wrapped ) { - return forwardRef( ( props, ref ) => { +function deprecateComponent( name, Wrapped, staticsToHoist = [] ) { + const Component = forwardRef( ( props, ref ) => { deprecated( 'wp.editor.' + name, { alternative: 'wp.blockEditor.' + name, } ); return <Wrapped ref={ ref }{ ...props } />; } ); + + staticsToHoist.forEach( ( staticName ) => { + Component[ staticName ] = deprecateComponent( + name + '.' + staticName, + Wrapped[ staticName ] + ); + } ); + + return Component; } function deprecateFunction( name, func ) { @@ -84,13 +92,17 @@ function deprecateFunction( name, func ) { }; } +const RichText = deprecateComponent( 'RichText', RootRichText, [ 'Content' ] ); +RichText.isEmpty = deprecateFunction( 'RichText.isEmpty', RootRichText.isEmpty ); + +export { RichText }; export const Autocomplete = deprecateComponent( 'Autocomplete', RootAutocomplete ); export const AlignmentToolbar = deprecateComponent( 'AlignmentToolbar', RootAlignmentToolbar ); export const BlockAlignmentToolbar = deprecateComponent( 'BlockAlignmentToolbar', RootBlockAlignmentToolbar ); -export const BlockControls = deprecateComponent( 'BlockControls', RootBlockControls ); +export const BlockControls = deprecateComponent( 'BlockControls', RootBlockControls, [ 'Slot' ] ); export const BlockEdit = deprecateComponent( 'BlockEdit', RootBlockEdit ); export const BlockEditorKeyboardShortcuts = deprecateComponent( 'BlockEditorKeyboardShortcuts', RootBlockEditorKeyboardShortcuts ); -export const BlockFormatControls = deprecateComponent( 'BlockFormatControls', RootBlockFormatControls ); +export const BlockFormatControls = deprecateComponent( 'BlockFormatControls', RootBlockFormatControls, [ 'Slot' ] ); export const BlockIcon = deprecateComponent( 'BlockIcon', RootBlockIcon ); export const BlockInspector = deprecateComponent( 'BlockInspector', RootBlockInspector ); export const BlockList = deprecateComponent( 'BlockList', RootBlockList ); @@ -106,15 +118,13 @@ export const CopyHandler = deprecateComponent( 'CopyHandler', RootCopyHandler ); export const DefaultBlockAppender = deprecateComponent( 'DefaultBlockAppender', RootDefaultBlockAppender ); export const FontSizePicker = deprecateComponent( 'FontSizePicker', RootFontSizePicker ); export const Inserter = deprecateComponent( 'Inserter', RootInserter ); -export const InnerBlocks = deprecateComponent( 'InnerBlocks', RootInnerBlocks ); -export const InspectorAdvancedControls = deprecateComponent( 'InspectorAdvancedControls', RootInspectorAdvancedControls ); -export const InspectorControls = deprecateComponent( 'InspectorControls', RootInspectorControls ); +export const InnerBlocks = deprecateComponent( 'InnerBlocks', RootInnerBlocks, [ 'ButtonBlockAppender', 'DefaultBlockAppender', 'Content' ] ); +export const InspectorAdvancedControls = deprecateComponent( 'InspectorAdvancedControls', RootInspectorAdvancedControls, [ 'Slot' ] ); +export const InspectorControls = deprecateComponent( 'InspectorControls', RootInspectorControls, [ 'Slot' ] ); export const PanelColorSettings = deprecateComponent( 'PanelColorSettings', RootPanelColorSettings ); export const PlainText = deprecateComponent( 'PlainText', RootPlainText ); -export const RichText = deprecateComponent( 'RichText', RootRichText ); export const RichTextShortcut = deprecateComponent( 'RichTextShortcut', RootRichTextShortcut ); export const RichTextToolbarButton = deprecateComponent( 'RichTextToolbarButton', RootRichTextToolbarButton ); -export const RichTextInserterItem = deprecateComponent( 'RichTextInserterItem', RootRichTextInserterItem ); export const __unstableRichTextInputEvent = deprecateComponent( '__unstableRichTextInputEvent', __unstableRootRichTextInputEvent ); export const MediaPlaceholder = deprecateComponent( 'MediaPlaceholder', RootMediaPlaceholder ); export const MediaUpload = deprecateComponent( 'MediaUpload', RootMediaUpload ); From 33f6a6dfb31b1d81246d058c6bb36eefb2fa4715 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski <grzegorz@gziolo.pl> Date: Fri, 14 Jun 2019 09:44:58 +0200 Subject: [PATCH 123/132] Bump plugin version to 5.9.1 --- gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 1450aa20c4b750..e762ee4326aeca 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -3,7 +3,7 @@ * Plugin Name: Gutenberg * Plugin URI: https://github.com/WordPress/gutenberg * Description: Printing since 1440. This is the development plugin for the new block editor in core. - * Version: 5.9.0 + * Version: 5.9.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index c2c500f9773775..a767b27c99ab50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.9.0", + "version": "5.9.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 0ce754a7d4579c..2afdd8eccedfd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.9.0", + "version": "5.9.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From 8b391be1181c0bab1161c5abc4d72f0340f58865 Mon Sep 17 00:00:00 2001 From: Jorge Costa <jorge.costa@developer.pt> Date: Fri, 14 Jun 2019 11:57:06 +0100 Subject: [PATCH 124/132] Make calendar block resilient against editor module not being present (#16161) --- packages/block-library/src/calendar/edit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/calendar/edit.js b/packages/block-library/src/calendar/edit.js index f884490ec38c80..19027eecf099f7 100644 --- a/packages/block-library/src/calendar/edit.js +++ b/packages/block-library/src/calendar/edit.js @@ -61,9 +61,13 @@ class CalendarEdit extends Component { } export default withSelect( ( select ) => { + const coreEditorSelect = select( 'core/editor' ); + if ( ! coreEditorSelect ) { + return; + } const { getEditedPostAttribute, - } = select( 'core/editor' ); + } = coreEditorSelect; const postType = getEditedPostAttribute( 'type' ); // Dates are used to overwrite year and month used on the calendar. // This overwrite should only happen for 'post' post types. From 7978022fc191a2053b00c505147002a28c43fa86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= <grzegorz@gziolo.pl> Date: Fri, 14 Jun 2019 12:59:22 +0200 Subject: [PATCH 125/132] Block library: Refactor Heading block to use class names for text align (#16035) * Block library: Refactor Heading block to use class names for text align * Fix Heading icon in the collapsed mode * Add missing label for the level dropdown menu * Block library: Revert attribute name change for text align * Remove code which moves text alignment control to the block toolbar --- .../block-library/src/heading/deprecated.js | 79 +++++++++++++++++++ packages/block-library/src/heading/edit.js | 2 +- packages/block-library/src/heading/index.js | 2 + packages/block-library/src/heading/save.js | 6 +- packages/block-library/src/style.scss | 12 +++ .../e2e-tests/fixtures/block-transforms.js | 2 +- .../blocks/core__heading__deprecated-1.html | 3 + .../blocks/core__heading__deprecated-1.json | 14 ++++ .../core__heading__deprecated-1.parsed.json | 23 ++++++ ...ore__heading__deprecated-1.serialized.html | 3 + .../fixtures/blocks/core__heading__h2-em.html | 3 - .../core__heading__h2-em.serialized.html | 3 - .../fixtures/blocks/core__heading__h4-em.html | 3 + ...__h2-em.json => core__heading__h4-em.json} | 4 +- ....json => core__heading__h4-em.parsed.json} | 8 +- .../core__heading__h4-em.serialized.html | 3 + .../block-transforms.test.js.snap | 4 +- 17 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 packages/block-library/src/heading/deprecated.js create mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.html create mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.json create mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.parsed.json create mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.serialized.html delete mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__h2-em.html delete mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__h2-em.serialized.html create mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__h4-em.html rename packages/e2e-tests/fixtures/blocks/{core__heading__h2-em.json => core__heading__h4-em.json} (72%) rename packages/e2e-tests/fixtures/blocks/{core__heading__h2-em.parsed.json => core__heading__h4-em.parsed.json} (62%) create mode 100644 packages/e2e-tests/fixtures/blocks/core__heading__h4-em.serialized.html diff --git a/packages/block-library/src/heading/deprecated.js b/packages/block-library/src/heading/deprecated.js new file mode 100644 index 00000000000000..4a3a7d2f6d3653 --- /dev/null +++ b/packages/block-library/src/heading/deprecated.js @@ -0,0 +1,79 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { + getColorClassName, + RichText, +} from '@wordpress/block-editor'; + +const blockSupports = { + className: false, + anchor: true, +}; + +const blockAttributes = { + align: { + type: 'string', + }, + content: { + type: 'string', + source: 'html', + selector: 'h1,h2,h3,h4,h5,h6', + default: '', + }, + level: { + type: 'number', + default: 2, + }, + placeholder: { + type: 'string', + }, + textColor: { + type: 'string', + }, + customTextColor: { + type: 'string', + }, +}; + +const deprecated = [ + { + supports: blockSupports, + attributes: blockAttributes, + save( { attributes } ) { + const { + align, + level, + content, + textColor, + customTextColor, + } = attributes; + const tagName = 'h' + level; + + const textClass = getColorClassName( 'color', textColor ); + + const className = classnames( { + [ textClass ]: textClass, + } ); + + return ( + <RichText.Content + className={ className ? className : undefined } + tagName={ tagName } + style={ { + textAlign: align, + color: textClass ? undefined : customTextColor, + } } + value={ content } + /> + ); + }, + }, +]; + +export default deprecated; diff --git a/packages/block-library/src/heading/edit.js b/packages/block-library/src/heading/edit.js index e8a396a147df57..7fc4721c9169ab 100644 --- a/packages/block-library/src/heading/edit.js +++ b/packages/block-library/src/heading/edit.js @@ -100,13 +100,13 @@ function HeadingEdit( { onReplace={ onReplace } onRemove={ () => onReplace( [] ) } className={ classnames( className, { + [ `has-text-align-${ align }` ]: align, 'has-text-color': textColor.color, [ textColor.class ]: textColor.class, } ) } placeholder={ placeholder || __( 'Write heading…' ) } style={ { color: textColor.color, - textAlign: align, } } /> </> diff --git a/packages/block-library/src/heading/index.js b/packages/block-library/src/heading/index.js index 7706f44bb54ce6..1dc024193e4a76 100644 --- a/packages/block-library/src/heading/index.js +++ b/packages/block-library/src/heading/index.js @@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ +import deprecated from './deprecated'; import edit from './edit'; import metadata from './block.json'; import save from './save'; @@ -25,6 +26,7 @@ export const settings = { anchor: true, }, transforms, + deprecated, merge( attributes, attributesToMerge ) { return { content: ( attributes.content || '' ) + ( attributesToMerge.content || '' ), diff --git a/packages/block-library/src/heading/save.js b/packages/block-library/src/heading/save.js index f554ff815a121a..7cf0de59884828 100644 --- a/packages/block-library/src/heading/save.js +++ b/packages/block-library/src/heading/save.js @@ -14,10 +14,10 @@ import { export default function save( { attributes } ) { const { align, - level, content, - textColor, customTextColor, + level, + textColor, } = attributes; const tagName = 'h' + level; @@ -25,6 +25,7 @@ export default function save( { attributes } ) { const className = classnames( { [ textClass ]: textClass, + [ `has-text-align-${ align }` ]: align, } ); return ( @@ -32,7 +33,6 @@ export default function save( { attributes } ) { className={ className ? className : undefined } tagName={ tagName } style={ { - textAlign: align, color: textClass ? undefined : customTextColor, } } value={ content } diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index d33dd3c393c3b1..f9a2909ff360a8 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -147,6 +147,18 @@ font-size: 42px; } +// Text alignments. +.has-text-align-center { + text-align: center; +} + +.has-text-align-left { + text-align: left; +} + +.has-text-align-right { + text-align: right; +} /** * Vanilla Block Styles diff --git a/packages/e2e-tests/fixtures/block-transforms.js b/packages/e2e-tests/fixtures/block-transforms.js index 913953d69d2b3e..723552c024b545 100644 --- a/packages/e2e-tests/fixtures/block-transforms.js +++ b/packages/e2e-tests/fixtures/block-transforms.js @@ -168,7 +168,7 @@ export const EXPECTED_TRANSFORMS = { originalBlock: 'Group', availableTransforms: [], }, - 'core__heading__h2-em': { + 'core__heading__h4-em': { originalBlock: 'Heading', availableTransforms: [ 'Quote', diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.html b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.html new file mode 100644 index 00000000000000..b0fc3807468356 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.html @@ -0,0 +1,3 @@ +<!-- wp:core/heading {"align":"right","level":3} --> +<h3 style="text-align:right">A picture is worth a thousand words, or so the saying goes</h3> +<!-- /wp:core/heading --> diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.json b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.json new file mode 100644 index 00000000000000..0553075b8e24d6 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.json @@ -0,0 +1,14 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/heading", + "isValid": true, + "attributes": { + "align": "right", + "content": "A picture is worth a thousand words, or so the saying goes", + "level": 3 + }, + "innerBlocks": [], + "originalContent": "<h3 style=\"text-align:right\">A picture is worth a thousand words, or so the saying goes</h3>" + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.parsed.json b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.parsed.json new file mode 100644 index 00000000000000..abb13458d09aa7 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.parsed.json @@ -0,0 +1,23 @@ +[ + { + "blockName": "core/heading", + "attrs": { + "align": "right", + "level": 3 + }, + "innerBlocks": [], + "innerHTML": "\n<h3 style=\"text-align:right\">A picture is worth a thousand words, or so the saying goes</h3>\n", + "innerContent": [ + "\n<h3 style=\"text-align:right\">A picture is worth a thousand words, or so the saying goes</h3>\n" + ] + }, + { + "blockName": null, + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n", + "innerContent": [ + "\n" + ] + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.serialized.html b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.serialized.html new file mode 100644 index 00000000000000..140a1929ad38c8 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__heading__deprecated-1.serialized.html @@ -0,0 +1,3 @@ +<!-- wp:heading {"align":"right","level":3} --> +<h3 class="has-text-align-right">A picture is worth a thousand words, or so the saying goes</h3> +<!-- /wp:heading --> diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.html b/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.html deleted file mode 100644 index 7755d1dcf4eae2..00000000000000 --- a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.html +++ /dev/null @@ -1,3 +0,0 @@ -<!-- wp:core/heading --> -<h2>The <em>Inserter</em> Tool</h2> -<!-- /wp:core/heading --> diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.serialized.html b/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.serialized.html deleted file mode 100644 index 55ce73502b6185..00000000000000 --- a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.serialized.html +++ /dev/null @@ -1,3 +0,0 @@ -<!-- wp:heading --> -<h2>The <em>Inserter</em> Tool</h2> -<!-- /wp:heading --> diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.html b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.html new file mode 100644 index 00000000000000..bd13c30bb968d1 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.html @@ -0,0 +1,3 @@ +<!-- wp:core/heading {"level":4} --> +<h4>The <em>Inserter</em> Tool</h4> +<!-- /wp:core/heading --> diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.json b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.json similarity index 72% rename from packages/e2e-tests/fixtures/blocks/core__heading__h2-em.json rename to packages/e2e-tests/fixtures/blocks/core__heading__h4-em.json index b72785dd6d8c2a..32985e4bb53c85 100644 --- a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.json +++ b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.json @@ -5,9 +5,9 @@ "isValid": true, "attributes": { "content": "The <em>Inserter</em> Tool", - "level": 2 + "level": 4 }, "innerBlocks": [], - "originalContent": "<h2>The <em>Inserter</em> Tool</h2>" + "originalContent": "<h4>The <em>Inserter</em> Tool</h4>" } ] diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.parsed.json b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.parsed.json similarity index 62% rename from packages/e2e-tests/fixtures/blocks/core__heading__h2-em.parsed.json rename to packages/e2e-tests/fixtures/blocks/core__heading__h4-em.parsed.json index e10209f2270c98..302248c57f6311 100644 --- a/packages/e2e-tests/fixtures/blocks/core__heading__h2-em.parsed.json +++ b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.parsed.json @@ -1,11 +1,13 @@ [ { "blockName": "core/heading", - "attrs": {}, + "attrs": { + "level": 4 + }, "innerBlocks": [], - "innerHTML": "\n<h2>The <em>Inserter</em> Tool</h2>\n", + "innerHTML": "\n<h4>The <em>Inserter</em> Tool</h4>\n", "innerContent": [ - "\n<h2>The <em>Inserter</em> Tool</h2>\n" + "\n<h4>The <em>Inserter</em> Tool</h4>\n" ] }, { diff --git a/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.serialized.html b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.serialized.html new file mode 100644 index 00000000000000..051e1c9f39b273 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__heading__h4-em.serialized.html @@ -0,0 +1,3 @@ +<!-- wp:heading {"level":4} --> +<h4>The <em>Inserter</em> Tool</h4> +<!-- /wp:heading --> diff --git a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap index 25e50d75416a43..678dc348b496fd 100644 --- a/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap +++ b/packages/e2e-tests/specs/__snapshots__/block-transforms.test.js.snap @@ -64,13 +64,13 @@ exports[`Block transforms correctly transform block Heading in fixture core__hea <!-- /wp:quote -->" `; -exports[`Block transforms correctly transform block Heading in fixture core__heading__h2-em into the Paragraph block 1`] = ` +exports[`Block transforms correctly transform block Heading in fixture core__heading__h4-em into the Paragraph block 1`] = ` "<!-- wp:paragraph --> <p>The <em>Inserter</em> Tool</p> <!-- /wp:paragraph -->" `; -exports[`Block transforms correctly transform block Heading in fixture core__heading__h2-em into the Quote block 1`] = ` +exports[`Block transforms correctly transform block Heading in fixture core__heading__h4-em into the Quote block 1`] = ` "<!-- wp:quote --> <blockquote class=\\"wp-block-quote\\"><p>The <em>Inserter</em> Tool</p></blockquote> <!-- /wp:quote -->" From 3dc3ca894a75b3c28f5e3301d5287e870e143efc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20=28Greg=29=20Zi=C3=B3=C5=82kowski?= <grzegorz@gziolo.pl> Date: Fri, 14 Jun 2019 13:08:38 +0200 Subject: [PATCH 126/132] Scripts: Document and simplify changing file entry and output of build scripts (#15982) --- packages/scripts/CHANGELOG.md | 6 ++++ packages/scripts/README.md | 8 +++-- packages/scripts/utils/cli.js | 5 ++- packages/scripts/utils/config.js | 54 ++++++++++++++++++++++++++++++-- packages/scripts/utils/index.js | 2 ++ 5 files changed, 70 insertions(+), 5 deletions(-) diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 239314b3a61415..5fb6c959d8c14c 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -1,3 +1,9 @@ +## Master + +### New Features + +- The `build` and `start` commands supports simplified syntax for multiple entry points: `wp-scripts build entry-one.js entry-two.js` ([15982](https://github.com/WordPress/gutenberg/pull/15982)). + ## 3.3.0 (2019-06-12) ### New Features diff --git a/packages/scripts/README.md b/packages/scripts/README.md index 7ee723ce817047..531def5b59d22e 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -49,7 +49,8 @@ _Example:_ ```json { "scripts": { - "build": "wp-scripts build" + "build": "wp-scripts build", + "build:custom": "wp-scripts build entry-one.js entry-two.js --output-path=custom" } } ``` @@ -57,6 +58,7 @@ _Example:_ This is how you execute the script with presented setup: * `npm run build` - builds the code for production. +* `npm run build:custom` - builds the code for production with two entry points and a custom output folder. Paths for custom entry points are relative to the project root. #### Advanced information @@ -198,7 +200,8 @@ _Example:_ ```json { "scripts": { - "start": "wp-scripts start" + "start": "wp-scripts start", + "start:custom": "wp-scripts start entry-one.js entry-two.js --output-path=custom" } } ``` @@ -206,6 +209,7 @@ _Example:_ This is how you execute the script with presented setup: * `npm start` - starts the build for development. +* `npm run start:custom` - starts the build for development which contains two entry points and a custom output folder. Paths for custom entry points are relative to the project root. #### Advanced information diff --git a/packages/scripts/utils/cli.js b/packages/scripts/utils/cli.js index ab29ad4fa769e3..9b3bbd0dd1ca3d 100644 --- a/packages/scripts/utils/cli.js +++ b/packages/scripts/utils/cli.js @@ -27,7 +27,9 @@ const getArgFromCLI = ( arg ) => { const hasArgInCLI = ( arg ) => getArgFromCLI( arg ) !== undefined; -const hasFileArgInCLI = () => minimist( getArgsFromCLI() )._.length > 0; +const getFileArgsFromCLI = () => minimist( getArgsFromCLI() )._; + +const hasFileArgInCLI = () => getFileArgsFromCLI().length > 0; const handleSignal = ( signal ) => { if ( signal === 'SIGKILL' ) { @@ -83,6 +85,7 @@ const spawnScript = ( scriptName, args = [] ) => { module.exports = { getArgFromCLI, getArgsFromCLI, + getFileArgsFromCLI, hasArgInCLI, hasFileArgInCLI, spawnScript, diff --git a/packages/scripts/utils/config.js b/packages/scripts/utils/config.js index 9247f93a941717..a34895230af704 100644 --- a/packages/scripts/utils/config.js +++ b/packages/scripts/utils/config.js @@ -1,7 +1,12 @@ +/** + * External dependencies + */ +const { basename } = require( 'path' ); + /** * Internal dependencies */ -const { hasArgInCLI, getArgsFromCLI } = require( './cli' ); +const { getArgsFromCLI, getFileArgsFromCLI, hasArgInCLI, hasFileArgInCLI } = require( './cli' ); const { fromConfigRoot, hasProjectFile } = require( './file' ); const { hasPackageProp } = require( './package' ); @@ -22,12 +27,57 @@ const hasWebpackConfig = () => hasArgInCLI( '--config' ) || hasProjectFile( 'webpack.config.js' ) || hasProjectFile( 'webpack.config.babel.js' ); +/** + * Converts CLI arguments to the format which webpack understands. + * It allows to optionally pass some additional webpack CLI arguments. + * + * @see https://webpack.js.org/api/cli/#usage-with-config-file + * + * @param {?Array} additionalArgs The list of additional CLI arguments. + * + * @return {Array} The list of CLI arguments to pass to webpack CLI. + */ const getWebpackArgs = ( additionalArgs = [] ) => { - const webpackArgs = getArgsFromCLI(); + let webpackArgs = getArgsFromCLI(); + + const hasWebpackOutputOption = hasArgInCLI( '-o' ) || hasArgInCLI( '--output' ); + if ( hasFileArgInCLI() && ! hasWebpackOutputOption ) { + /** + * Converts a path to the entry format supported by webpack, e.g.: + * `./entry-one.js` -> `entry-one=./entry-one.js` + * `entry-two.js` -> `entry-two=./entry-two.js` + * + * @param {string} path The path provided. + * + * @return {string} The entry format supported by webpack. + */ + const pathToEntry = ( path ) => { + const entry = basename( path, '.js' ); + + if ( ! path.startsWith( './' ) ) { + path = './' + path; + } + + return [ entry, path ].join( '=' ); + }; + + // The following handles the support for multiple entry points in webpack, e.g.: + // `wp-scripts build one.js custom=./two.js` -> `webpack one=./one.js custom=./two.js` + webpackArgs = webpackArgs.map( ( cliArg ) => { + if ( getFileArgsFromCLI().includes( cliArg ) && ! cliArg.includes( '=' ) ) { + return pathToEntry( cliArg ); + } + + return cliArg; + } ); + } + if ( ! hasWebpackConfig() ) { webpackArgs.push( '--config', fromConfigRoot( 'webpack.config.js' ) ); } + webpackArgs.push( ...additionalArgs ); + return webpackArgs; }; diff --git a/packages/scripts/utils/index.js b/packages/scripts/utils/index.js index f356d401356cd1..c45b1b6abbee1e 100644 --- a/packages/scripts/utils/index.js +++ b/packages/scripts/utils/index.js @@ -4,6 +4,7 @@ const { getArgFromCLI, getArgsFromCLI, + getFileArgsFromCLI, hasArgInCLI, hasFileArgInCLI, spawnScript, @@ -29,6 +30,7 @@ module.exports = { fromConfigRoot, getArgFromCLI, getArgsFromCLI, + getFileArgsFromCLI, getWebpackArgs, hasBabelConfig, hasArgInCLI, From b30835770c040186aecff1cd0bfee39ce80794b6 Mon Sep 17 00:00:00 2001 From: Stefanos Togoulidis <stefanostogoulidis@gmail.com> Date: Fri, 14 Jun 2019 15:12:04 +0300 Subject: [PATCH 127/132] [RNMobile] Native mobile release v1.7.0 (#16156) * [Mobile] Disable Video block on Android for v1.7.0 release (#16149) * Disable Video block on Android for v1.7.0 release * Add import statement to check platform * [RNMobile] Narrow down blur on unmount to replaceable only (#16151) * Remove focus from RichText when unmounting In #15999 this behavior was changed to prevent the keyboard from disappearing when you press Enter to create a new paragraph. This worked in that case, but had the side effect of TextInputState still thinking a dead view had focus, and causing a crash in some scenarios. * Only blur a RichText in replaceable block That RichText won't have the chance to blur earlier so, we need to do it on unmount. But, non replaceable blocks wont need to blur their RichText on unmount because that will happen normally in componentDidUpdate(). * Rename to an unstable, very goal-named name * Compute shouldBlurOnUnmount inside RichText * Fix no-duplicate-imports lint issue * Fix comma-dangle lint error * Remove trailing space from comment --- .../src/components/rich-text/index.native.js | 18 +++++++++++++++--- packages/edit-post/src/index.native.js | 10 ++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js index 489d0a5fbeaa95..7d8cfe2b737df5 100644 --- a/packages/block-editor/src/components/rich-text/index.native.js +++ b/packages/block-editor/src/components/rich-text/index.native.js @@ -34,7 +34,11 @@ import { } from '@wordpress/rich-text'; import { decodeEntities } from '@wordpress/html-entities'; import { BACKSPACE } from '@wordpress/keycodes'; -import { pasteHandler, children } from '@wordpress/blocks'; +import { + children, + isUnmodifiedDefaultBlock, + pasteHandler, +} from '@wordpress/blocks'; import { isURL } from '@wordpress/url'; /** @@ -706,8 +710,8 @@ export class RichText extends Component { } componentWillUnmount() { - if ( this._editor.isFocused() ) { - // this._editor.blur(); + if ( this._editor.isFocused() && this.props.shouldBlurOnUnmount ) { + this._editor.blur(); } } @@ -880,6 +884,7 @@ const RichTextContainer = compose( [ const { getSelectionStart, getSelectionEnd, + __unstableGetBlockWithoutInnerBlocks, } = select( 'core/block-editor' ); const selectionStart = getSelectionStart(); @@ -892,12 +897,19 @@ const RichTextContainer = compose( [ ); } + // If the block of this RichText is unmodified then it's a candidate for replacing when adding a new block. + // In order to fix https://github.com/wordpress-mobile/gutenberg-mobile/issues/1126, let's blur on unmount in that case. + // This apparently assumes functionality the BlockHlder actually + const block = clientId && __unstableGetBlockWithoutInnerBlocks( clientId ); + const shouldBlurOnUnmount = block && isSelected && isUnmodifiedDefaultBlock( block ); + return { formatTypes: getFormatTypes(), selectionStart: isSelected ? selectionStart.offset : undefined, selectionEnd: isSelected ? selectionEnd.offset : undefined, isSelected, blockIsSelected, + shouldBlurOnUnmount, }; } ), withDispatch( ( dispatch, { diff --git a/packages/edit-post/src/index.native.js b/packages/edit-post/src/index.native.js index 1abd926f26bc8c..5854c991101955 100644 --- a/packages/edit-post/src/index.native.js +++ b/packages/edit-post/src/index.native.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { Platform } from 'react-native'; + /** * WordPress dependencies */ @@ -22,6 +27,11 @@ export function initializeEditor() { // eslint-disable-next-line no-undef if ( typeof __DEV__ === 'undefined' || ! __DEV__ ) { unregisterBlockType( 'core/code' ); + + // Disable Video block except for iOS for now. + if ( Platform.OS !== 'ios' ) { + unregisterBlockType( 'core/video' ); + } } } From 2f63a6ee02c4302310cfe06b4fe3969397406f77 Mon Sep 17 00:00:00 2001 From: Seghir Nadir <nadir.seghir@gmail.com> Date: Fri, 14 Jun 2019 15:20:55 +0100 Subject: [PATCH 128/132] refactor snackbar to follow spec while keeping compatibility with notice (#16095) --- packages/components/src/snackbar/index.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/components/src/snackbar/index.js b/packages/components/src/snackbar/index.js index afca0dd162d8df..a62924219a9b5c 100644 --- a/packages/components/src/snackbar/index.js +++ b/packages/components/src/snackbar/index.js @@ -34,6 +34,13 @@ function Snackbar( { }, [] ); const classes = classnames( className, 'components-snackbar' ); + if ( actions && actions.length > 1 ) { + // we need to inform developers that snackbar only accepts 1 action + // eslint-disable-next-line no-console + console.warn( 'Snackbar can only have 1 action, use Notice if your message require many messages' ); + // return first element only while keeping it inside an array + actions = [ actions[ 0 ] ]; + } return ( <div @@ -50,7 +57,6 @@ function Snackbar( { { actions.map( ( { - className: buttonCustomClasses, label, onClick, url, @@ -68,10 +74,8 @@ function Snackbar( { onClick( event ); } } } - className={ classnames( - 'components-snackbar__action', - buttonCustomClasses - ) } + className="components-snackbar__action" + > { label } </Button> From 0a4fbd5b7c28c1e2d1235e7bc1bbd27c74d28044 Mon Sep 17 00:00:00 2001 From: Pinar Olguc <pinarolguc@gmail.com> Date: Fri, 14 Jun 2019 17:34:08 +0300 Subject: [PATCH 129/132] [Mobile]Update video player to open the URL by browser on Android (#16089) * Update video player to open the URL by browser * Render play button even if video is not ready to play yet * Add/update alert messages * Revert back warn to error * Do not show play button until video player has a height * Resolve merge conflicts that re-introduced a removed file --- .../src/video/video-player.android.js | 28 ----- .../src/video/video-player.ios.js | 82 -------------- .../src/video/video-player.native.js | 106 ++++++++++++++++++ .../src/video/video-player.native.scss | 2 +- 4 files changed, 107 insertions(+), 111 deletions(-) delete mode 100644 packages/block-library/src/video/video-player.android.js delete mode 100644 packages/block-library/src/video/video-player.ios.js create mode 100644 packages/block-library/src/video/video-player.native.js diff --git a/packages/block-library/src/video/video-player.android.js b/packages/block-library/src/video/video-player.android.js deleted file mode 100644 index 669948bbdd2d3b..00000000000000 --- a/packages/block-library/src/video/video-player.android.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * External dependencies - */ -import { View } from 'react-native'; -import { default as VideoPlayer } from 'react-native-video'; - -/** - * Internal dependencies - */ -import styles from './video-player.scss'; - -const Video = ( props ) => { - const { isSelected, ...videoProps } = props; - - return ( - <View style={ styles.videoContainer }> - <VideoPlayer - { ...videoProps } - // We are using built-in player controls becasue manually - // calling presentFullscreenPlayer() is not working for android - controls={ isSelected } - muted={ ! isSelected } - /> - </View> - ); -}; - -export default Video; diff --git a/packages/block-library/src/video/video-player.ios.js b/packages/block-library/src/video/video-player.ios.js deleted file mode 100644 index 53d88380207080..00000000000000 --- a/packages/block-library/src/video/video-player.ios.js +++ /dev/null @@ -1,82 +0,0 @@ -/** - * WordPress dependencies - */ -import { Component } from '@wordpress/element'; -import { Dashicon } from '@wordpress/components'; - -/** - * External dependencies - */ -import { View, TouchableOpacity } from 'react-native'; -import { default as VideoPlayer } from 'react-native-video'; - -/** - * Internal dependencies - */ -import styles from './video-player.scss'; - -class Video extends Component { - constructor() { - super( ...arguments ); - this.state = { - isLoaded: false, - isFullScreen: false, - }; - this.onPressPlay = this.onPressPlay.bind( this ); - this.onLoad = this.onLoad.bind( this ); - this.onLoadStart = this.onLoadStart.bind( this ); - } - - onLoad() { - this.setState( { isLoaded: true } ); - } - - onLoadStart() { - this.setState( { isLoaded: false } ); - } - - onPressPlay() { - if ( this.player ) { - this.player.presentFullscreenPlayer(); - } - } - - render() { - const { isSelected, style } = this.props; - const { isLoaded, isFullScreen } = this.state; - - return ( - <View style={ styles.videoContainer }> - <VideoPlayer - { ...this.props } - ref={ ( ref ) => { - this.player = ref; - } } - // Using built-in player controls is messing up the layout on iOS. - // So we are setting controls=false and adding a play button that - // will trigger presentFullscreenPlayer() - controls={ false } - onLoad={ this.onLoad } - onLoadStart={ this.onLoadStart } - ignoreSilentSwitch={ 'ignore' } - paused={ ! isFullScreen } - onFullscreenPlayerWillPresent={ () => { - this.setState( { isFullScreen: true } ); - } } - onFullscreenPlayerDidDismiss={ () => { - this.setState( { isFullScreen: false } ); - } } - /> - { isLoaded && - <TouchableOpacity disabled={ ! isSelected } onPress={ this.onPressPlay } style={ [ style, styles.overlay ] }> - <View style={ styles.playIcon }> - <Dashicon icon={ 'controls-play' } ariaPressed={ 'dashicon-active' } size={ styles.playIcon.width } /> - </View> - </TouchableOpacity> - } - </View> - ); - } -} - -export default Video; diff --git a/packages/block-library/src/video/video-player.native.js b/packages/block-library/src/video/video-player.native.js new file mode 100644 index 00000000000000..5b67d4673b4192 --- /dev/null +++ b/packages/block-library/src/video/video-player.native.js @@ -0,0 +1,106 @@ +/** + * WordPress dependencies + */ +import { Component } from '@wordpress/element'; +import { Dashicon } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * External dependencies + */ +import { View, TouchableOpacity, Platform, Linking, Alert } from 'react-native'; +import { default as VideoPlayer } from 'react-native-video'; + +/** + * Internal dependencies + */ +import styles from './video-player.scss'; + +class Video extends Component { + constructor() { + super( ...arguments ); + this.isIOS = Platform.OS === 'ios'; + this.state = { + isFullScreen: false, + videoContainerHeight: 0, + }; + this.onPressPlay = this.onPressPlay.bind( this ); + this.onVideoLayout = this.onVideoLayout.bind( this ); + } + + onVideoLayout( event ) { + const { height } = event.nativeEvent.layout; + if ( height !== this.state.videoContainerHeight ) { + this.setState( { videoContainerHeight: height } ); + } + } + + onPressPlay() { + if ( this.isIOS ) { + if ( this.player ) { + this.player.presentFullscreenPlayer(); + } + } else { + const { source } = this.props; + if ( source && source.uri ) { + this.openURL( source.uri ); + } + } + } + + // Tries opening the URL outside of the app + openURL( url ) { + Linking.canOpenURL( url ).then( ( supported ) => { + if ( ! supported ) { + Alert.alert( __( 'Problem opening the video' ), __( 'No application can handle this request. Please install a Web browser.' ) ); + window.console.warn( 'No application found that can open the video with URL: ' + url ); + } else { + return Linking.openURL( url ); + } + } ).catch( ( err ) => { + Alert.alert( __( 'Problem opening the video' ), __( 'An unknown error occurred. Please try again.' ) ); + window.console.error( 'An error occurred while opening the video URL: ' + url, err ); + } ); + } + + render() { + const { isSelected, style } = this.props; + const { isFullScreen, videoContainerHeight } = this.state; + const showPlayButton = videoContainerHeight > 0; + + return ( + <View style={ styles.videoContainer }> + <VideoPlayer + { ...this.props } + ref={ ( ref ) => { + this.player = ref; + } } + // Using built-in player controls is messing up the layout on iOS. + // So we are setting controls=false and adding a play button that + // will trigger presentFullscreenPlayer() + controls={ false } + ignoreSilentSwitch={ 'ignore' } + paused={ ! isFullScreen } + onLayout={ this.onVideoLayout } + onFullscreenPlayerWillPresent={ () => { + this.setState( { isFullScreen: true } ); + } } + onFullscreenPlayerDidDismiss={ () => { + this.setState( { isFullScreen: false } ); + } } + /> + { showPlayButton && + // If we add the play icon as a subview to VideoPlayer then react-native-video decides to show control buttons + // even if we set controls={ false }, so we are adding our play button as a sibling overlay view. + <TouchableOpacity disabled={ ! isSelected } onPress={ this.onPressPlay } style={ [ style, styles.overlay ] }> + <View style={ styles.playIcon }> + <Dashicon icon={ 'controls-play' } ariaPressed={ 'dashicon-active' } size={ styles.playIcon.width } /> + </View> + </TouchableOpacity> + } + </View> + ); + } +} + +export default Video; diff --git a/packages/block-library/src/video/video-player.native.scss b/packages/block-library/src/video/video-player.native.scss index ec746de8288916..ae0dc6382f91f9 100644 --- a/packages/block-library/src/video/video-player.native.scss +++ b/packages/block-library/src/video/video-player.native.scss @@ -13,7 +13,7 @@ $play-icon-size: 50; align-items: center; align-self: center; position: absolute; - background-color: #e9eff3; + background-color: transparent; opacity: 0.3; } From 259bec15ca4de0963a235af368da13d792d106da Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Fri, 14 Jun 2019 16:24:01 +0100 Subject: [PATCH 130/132] Support forwardRef components in save functions (#16180) --- packages/element/src/serialize.js | 7 +++++++ packages/element/src/test/serialize.js | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/element/src/serialize.js b/packages/element/src/serialize.js index 5c2c2a8011d2a7..b700831f1dccd0 100644 --- a/packages/element/src/serialize.js +++ b/packages/element/src/serialize.js @@ -49,10 +49,14 @@ import { createContext, Fragment, StrictMode, + forwardRef, } from './react'; import RawHTML from './raw-html'; const { Provider, Consumer } = createContext(); +const ForwardRef = forwardRef( () => { + return null; +} ); /** * Valid attribute types. @@ -406,6 +410,9 @@ export function renderElement( element, context, legacyContext = {} ) { case Consumer.$$typeof: return renderElement( props.children( context || type._currentValue ), context, legacyContext ); + + case ForwardRef.$$typeof: + return renderElement( type.render( props ), context, legacyContext ); } return ''; diff --git a/packages/element/src/test/serialize.js b/packages/element/src/test/serialize.js index 7fe4251666decd..b6a8c906751d97 100644 --- a/packages/element/src/test/serialize.js +++ b/packages/element/src/test/serialize.js @@ -12,6 +12,7 @@ import { createElement, Fragment, StrictMode, + forwardRef, } from '../react'; import RawHTML from '../raw-html'; import serialize, { @@ -84,6 +85,20 @@ describe( 'serialize()', () => { ); } ); + it( 'should render with forwardRef', () => { + const ForwardedComponent = forwardRef( () => { + return <div>test</div>; + } ); + + const result = serialize( + <ForwardedComponent /> + ); + + expect( result ).toBe( + '<div>test</div>' + ); + } ); + describe( 'empty attributes', () => { it( 'should not render a null attribute value', () => { const result = serialize( <video src={ undefined } /> ); From 1b8a0838ba12d493faf8d746d1b91e3c10f2f1cb Mon Sep 17 00:00:00 2001 From: Riad Benguella <benguella@gmail.com> Date: Fri, 14 Jun 2019 16:32:56 +0100 Subject: [PATCH 131/132] Bump plugin version to 5.9.2 --- gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index e762ee4326aeca..ed0eb8e6c0f508 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -3,7 +3,7 @@ * Plugin Name: Gutenberg * Plugin URI: https://github.com/WordPress/gutenberg * Description: Printing since 1440. This is the development plugin for the new block editor in core. - * Version: 5.9.1 + * Version: 5.9.2 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index a767b27c99ab50..659cba78d7fb3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.9.1", + "version": "5.9.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2afdd8eccedfd5..c74000d2a1f86d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "5.9.1", + "version": "5.9.2", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From 2aef484f89d8326ebe94460eaac9e5e6da8b2f64 Mon Sep 17 00:00:00 2001 From: Mark Uraine <uraine@gmail.com> Date: Fri, 14 Jun 2019 15:36:46 -0700 Subject: [PATCH 132/132] Try making the Inserter category icons grayscale. (#16163) * Fixes #14180. Makes the icons grayscale. * Added an important to the style to increase strictness. Applied max height to html block. --- packages/block-library/src/html/edit.js | 18 ++++-------------- packages/block-library/src/html/editor.scss | 2 ++ packages/components/src/panel/style.scss | 1 + 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/block-library/src/html/edit.js b/packages/block-library/src/html/edit.js index 897a4bf7332747..4a8ddf014c8542 100644 --- a/packages/block-library/src/html/edit.js +++ b/packages/block-library/src/html/edit.js @@ -8,7 +8,7 @@ import { PlainText, __experimentalTransformStyles, } from '@wordpress/block-editor'; -import { Disabled, SandBox, ResizableBox } from '@wordpress/components'; +import { Disabled, SandBox } from '@wordpress/components'; import { withSelect } from '@wordpress/data'; class HTMLEdit extends Component { @@ -50,7 +50,7 @@ class HTMLEdit extends Component { this.setState( { isPreview: false } ); } - renderHTML() { + render() { const { attributes, setAttributes } = this.props; const { isPreview, styles } = this.state; @@ -82,6 +82,7 @@ class HTMLEdit extends Component { onChange={ ( content ) => setAttributes( { content } ) } placeholder={ __( 'Write HTML…' ) } aria-label={ __( 'HTML' ) } + rows={ 3 } /> ) ) } @@ -89,19 +90,8 @@ class HTMLEdit extends Component { </div> ); } - - render() { - return ( - <ResizableBox - minWidth="10%" - maxWidth="100%" - axis="x" - > - { this.renderHTML() } - </ResizableBox> - ); - } } + export default withSelect( ( select ) => { const { getSettings } = select( 'core/block-editor' ); return { diff --git a/packages/block-library/src/html/editor.scss b/packages/block-library/src/html/editor.scss index 2990803cb8eaae..3457c0c98f1768 100644 --- a/packages/block-library/src/html/editor.scss +++ b/packages/block-library/src/html/editor.scss @@ -5,9 +5,11 @@ font-family: $editor-html-font; color: $dark-gray-800; padding: 0.8em 1em; + max-height: 250px; border: 1px solid $light-gray-500; border-radius: 4px; + /* Fonts smaller than 16px causes mobile safari to zoom. */ font-size: $mobile-text-min-font-size; @include break-small { diff --git a/packages/components/src/panel/style.scss b/packages/components/src/panel/style.scss index 828af037a724f4..220249d69e942a 100644 --- a/packages/components/src/panel/style.scss +++ b/packages/components/src/panel/style.scss @@ -117,6 +117,7 @@ .components-panel__icon { color: $dark-gray-500; + filter: grayscale(1) !important; margin: -2px 0 -2px 6px; }