diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 3f00674f85d4d..927308b6a9d02 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -2,6 +2,7 @@ * External dependencies */ import classnames from 'classnames'; +import { escape } from 'lodash'; /** * WordPress dependencies @@ -9,27 +10,42 @@ import classnames from 'classnames'; import { __ } from '@wordpress/i18n'; import { useCallback, + useEffect, + useState, } from '@wordpress/element'; import { compose, - withInstanceId, } from '@wordpress/compose'; import { + KeyboardShortcuts, PanelBody, RangeControl, TextControl, ToggleControl, withFallbackStyles, + ToolbarButton, + ToolbarGroup, } from '@wordpress/components'; import { + BlockControls, __experimentalUseGradient, ContrastChecker, InspectorControls, __experimentalPanelColorGradientSettings as PanelColorGradientSettings, RichText, - URLInput, withColors, + __experimentalLinkControl as LinkControl, } from '@wordpress/block-editor'; +import { + LEFT, + RIGHT, + UP, + DOWN, + BACKSPACE, + ENTER, + rawShortcut, + displayShortcut, +} from '@wordpress/keycodes'; const { getComputedStyle } = window; @@ -72,6 +88,85 @@ function BorderPanel( { borderRadius = '', setAttributes } ) { ); } +const handleLinkControlOnKeyDown = ( event ) => { + const { keyCode } = event; + + if ( [ LEFT, DOWN, RIGHT, UP, BACKSPACE, ENTER ].indexOf( keyCode ) > -1 ) { + // Stop the key event from propagating up to ObserveTyping.startTypingInTextField. + event.stopPropagation(); + } +}; + +const handleLinkControlOnKeyPress = ( event ) => { + event.stopPropagation(); +}; + +function URLPicker( { isSelected, url, title, setAttributes, opensInNewTab, onToggleOpenInNewTab } ) { + const [ isURLPickerOpen, setIsURLPickerOpen ] = useState( false ); + useEffect( + () => { + if ( ! isSelected ) { + setIsURLPickerOpen( false ); + } + }, + [ isSelected ] + ); + const openLinkControl = () => { + setIsURLPickerOpen( true ); + }; + const linkControl = isURLPickerOpen && ( + { + setAttributes( { + title: escape( newTitle ), + url: newURL, + } ); + } } + currentSettings={ [ + { + id: 'opensInNewTab', + title: __( 'Open in new tab' ), + checked: opensInNewTab, + }, + ] } + onSettingsChange={ ( setting, value ) => { + if ( setting === 'opensInNewTab' ) { + onToggleOpenInNewTab( value ); + } + } } + onClose={ () => { + setIsURLPickerOpen( false ); + } } + /> + ); + return ( + <> + + + + + + + { linkControl } + + ); +} + function ButtonEdit( { attributes, backgroundColor, @@ -150,18 +245,13 @@ function ButtonEdit( { borderRadius: borderRadius ? borderRadius + 'px' : undefined, } } /> - setAttributes( { url: value } ) } - disableSuggestions={ ! isSelected } - isFullWidth - hasBorder + + + + ); +} + +export default ButtonsEdit; diff --git a/packages/block-library/src/buttons/editor.scss b/packages/block-library/src/buttons/editor.scss new file mode 100644 index 0000000000000..fe8ca07d4ad6b --- /dev/null +++ b/packages/block-library/src/buttons/editor.scss @@ -0,0 +1,36 @@ +.wp-block-buttons .wp-block.block-editor-block-list__block[data-type="core/button"] { + display: inline-block; + width: auto; +} + +.wp-block-buttons { + div[data-type="core/button"] div[data-block] { + display: block; + } + + &[data-align="center"] .block-editor-block-list__layout { + display: flex; + align-items: center; + flex-wrap: wrap; + justify-content: center; + } + + &[data-align="right"] .block-editor-block-list__layout { + display: flex; + justify-content: flex-end; + } + + .block-list-appender { + display: inline-block !important; + margin: 0; + } + + .block-editor-block-list__layout > div:last-child { + display: inline-block; + } + + .block-editor-button-block-appender { + background: none; + outline: none; + } +} diff --git a/packages/block-library/src/buttons/icon.js b/packages/block-library/src/buttons/icon.js new file mode 100644 index 0000000000000..6e18a60a648fe --- /dev/null +++ b/packages/block-library/src/buttons/icon.js @@ -0,0 +1,8 @@ +/** + * WordPress dependencies + */ +import { G, Path, SVG } from '@wordpress/components'; + +export default ( + +); diff --git a/packages/block-library/src/buttons/index.js b/packages/block-library/src/buttons/index.js new file mode 100644 index 0000000000000..5bc16c94b1536 --- /dev/null +++ b/packages/block-library/src/buttons/index.js @@ -0,0 +1,29 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import edit from './edit'; +import icon from './icon'; +import metadata from './block.json'; +import save from './save'; + +const { name } = metadata; + +export { metadata, name }; + +export const settings = { + title: __( 'Buttons' ), + description: __( 'Prompt visitors to take action with a group of button-style links.' ), + icon, + keywords: [ __( 'link' ) ], + supports: { + align: true, + alignWide: false, + }, + edit, + save, +}; diff --git a/packages/block-library/src/buttons/save.js b/packages/block-library/src/buttons/save.js new file mode 100644 index 0000000000000..91cb804231d05 --- /dev/null +++ b/packages/block-library/src/buttons/save.js @@ -0,0 +1,12 @@ +/** + * WordPress dependencies + */ +import { InnerBlocks } from '@wordpress/block-editor'; + +export default function save() { + return ( +
+ +
+ ); +} diff --git a/packages/block-library/src/buttons/style.scss b/packages/block-library/src/buttons/style.scss new file mode 100644 index 0000000000000..47fb245ec0024 --- /dev/null +++ b/packages/block-library/src/buttons/style.scss @@ -0,0 +1,7 @@ +.wp-block-buttons .wp-block-button { + display: inline-block; + margin: $grid-size-small; +} +.wp-block-buttons.aligncenter { + text-align: center; +} diff --git a/packages/block-library/src/editor.scss b/packages/block-library/src/editor.scss index 719723db2e13b..80486c92d11e3 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -2,6 +2,7 @@ @import "./audio/editor.scss"; @import "./block/editor.scss"; @import "./button/editor.scss"; +@import "./buttons/editor.scss"; @import "./categories/editor.scss"; @import "./code/editor.scss"; @import "./columns/editor.scss"; diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index c9cc4378a5e39..15c200636626d 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -23,6 +23,7 @@ import * as quote from './quote'; import * as gallery from './gallery'; import * as archives from './archives'; import * as audio from './audio'; +import * as buttons from './buttons'; import * as button from './button'; import * as calendar from './calendar'; import * as categories from './categories'; @@ -111,6 +112,7 @@ export const registerCoreBlocks = () => { archives, audio, button, + buttons, calendar, categories, code, diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index d6355fa439c9a..6a0547c9e2de9 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -1,5 +1,6 @@ @import "./audio/style.scss"; @import "./button/style.scss"; +@import "./buttons/style.scss"; @import "./calendar/style.scss"; @import "./categories/style.scss"; @import "./columns/style.scss"; diff --git a/packages/e2e-tests/fixtures/block-transforms.js b/packages/e2e-tests/fixtures/block-transforms.js index 380d8f86cdf4c..3677373fbeb30 100644 --- a/packages/e2e-tests/fixtures/block-transforms.js +++ b/packages/e2e-tests/fixtures/block-transforms.js @@ -30,6 +30,12 @@ export const EXPECTED_TRANSFORMS = { 'Group', ], }, + core__buttons: { + originalBlock: 'Buttons', + availableTransforms: [ + 'Group', + ], + }, core__calendar: { originalBlock: 'Calendar', availableTransforms: [ diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.html b/packages/e2e-tests/fixtures/blocks/core__buttons.html new file mode 100644 index 0000000000000..e70af7acc72ad --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.html @@ -0,0 +1,11 @@ + +
+ + + + + + + +
+ diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.json b/packages/e2e-tests/fixtures/blocks/core__buttons.json new file mode 100644 index 0000000000000..044daeb82101a --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.json @@ -0,0 +1,31 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/buttons", + "isValid": true, + "attributes": {}, + "innerBlocks": [ + { + "clientId": "_clientId_0", + "name": "core/button", + "isValid": true, + "attributes": { + "text": "My button 1" + }, + "innerBlocks": [], + "originalContent": "" + }, + { + "clientId": "_clientId_1", + "name": "core/button", + "isValid": true, + "attributes": { + "text": "My button 2" + }, + "innerBlocks": [], + "originalContent": "" + } + ], + "originalContent": "
\n\t\n\n\t\n
" + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json b/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json new file mode 100644 index 0000000000000..b96b1f50db1fc --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.parsed.json @@ -0,0 +1,43 @@ +[ + { + "blockName": "core/buttons", + "attrs": {}, + "innerBlocks": [ + { + "blockName": "core/button", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\n\t", + "innerContent": [ + "\n\t\n\t" + ] + }, + { + "blockName": "core/button", + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n\t\n\t", + "innerContent": [ + "\n\t\n\t" + ] + } + ], + "innerHTML": "\n
\n\t\n\n\t\n
\n", + "innerContent": [ + "\n
\n\t", + null, + "\n\n\t", + null, + "\n
\n" + ] + }, + { + "blockName": null, + "attrs": {}, + "innerBlocks": [], + "innerHTML": "\n", + "innerContent": [ + "\n" + ] + } +] diff --git a/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html b/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html new file mode 100644 index 0000000000000..baf0a0226c066 --- /dev/null +++ b/packages/e2e-tests/fixtures/blocks/core__buttons.serialized.html @@ -0,0 +1,9 @@ + + + diff --git a/packages/e2e-tests/specs/editor/blocks/__snapshots__/button.test.js.snap b/packages/e2e-tests/specs/editor/blocks/__snapshots__/button.test.js.snap deleted file mode 100644 index 82fca76a8fb04..0000000000000 --- a/packages/e2e-tests/specs/editor/blocks/__snapshots__/button.test.js.snap +++ /dev/null @@ -1,13 +0,0 @@ -// 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/editor/blocks/__snapshots__/buttons.test.js.snap b/packages/e2e-tests/specs/editor/blocks/__snapshots__/buttons.test.js.snap new file mode 100644 index 0000000000000..4b27f486f66f1 --- /dev/null +++ b/packages/e2e-tests/specs/editor/blocks/__snapshots__/buttons.test.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Buttons can jump to the link editor using the keyboard shortcut 1`] = ` +" + +" +`; + +exports[`Buttons has focus on button content 1`] = ` +" + +" +`; diff --git a/packages/e2e-tests/specs/editor/blocks/button.test.js b/packages/e2e-tests/specs/editor/blocks/buttons.test.js similarity index 57% rename from packages/e2e-tests/specs/editor/blocks/button.test.js rename to packages/e2e-tests/specs/editor/blocks/buttons.test.js index 69343633f4247..a7b97bc18a9fa 100644 --- a/packages/e2e-tests/specs/editor/blocks/button.test.js +++ b/packages/e2e-tests/specs/editor/blocks/buttons.test.js @@ -5,25 +5,27 @@ import { insertBlock, getEditedPostContent, createNewPost, + pressKeyWithModifier, } from '@wordpress/e2e-test-utils'; -describe( 'Button', () => { +describe( 'Buttons', () => { beforeEach( async () => { await createNewPost(); } ); it( 'has focus on button content', async () => { - await insertBlock( 'Button' ); + await insertBlock( 'Buttons' ); await page.keyboard.type( 'Content' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); - it( 'can jump focus back & forth', async () => { - await insertBlock( 'Button' ); + it( 'can jump to the link editor using the keyboard shortcut', async () => { + await insertBlock( 'Buttons' ); await page.keyboard.type( 'WordPress' ); - await page.keyboard.press( 'Tab' ); - await page.keyboard.type( 'https://wordpress.org' ); + await pressKeyWithModifier( 'primary', 'k' ); + await page.keyboard.type( 'https://wwww.wordpress.org/' ); + await page.keyboard.press( 'Enter' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } );