From 88959ff2d636b6371eb52b63aee5cfe1b48d31ed Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 18 May 2021 23:00:31 +0300 Subject: [PATCH 01/13] Ignore data-no-store-string-literals rule for native files (#31936) --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index 5360d8117321fd..1d6183a5d5a4c6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -168,6 +168,7 @@ module.exports = { 'import/no-extraneous-dependencies': 'off', 'import/no-unresolved': 'off', 'import/named': 'off', + '@wordpress/data-no-store-string-literals': 'off', }, }, { From fdb4da7133dd65dda7d118076a4509a36ec2bb3b Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Wed, 19 May 2021 12:37:53 +0800 Subject: [PATCH 02/13] Add widgets editor more menu (#31926) * Implement basic features framework * Implement top toolbar mode * Persist preferences * Implement keyboard shortcut help modal and help option * Implement keep caret inside block option * Fix shortcut for keyboard shortcut modal * Remove showIconLabels * Remove hidden block types * Add missing import for more menu styles * Replace edit-post references with edit-widgets * Hide undo redo and block navigation on mobile viewports * Switch to isMedium viewport --- package-lock.json | 1 + packages/base-styles/_z-index.scss | 1 + packages/edit-widgets/package.json | 1 + .../src/components/header/index.js | 32 +++- .../keyboard-shortcut-help-modal/config.js | 27 ++++ .../dynamic-shortcut.js | 40 +++++ .../keyboard-shortcut-help-modal/index.js | 142 ++++++++++++++++++ .../keyboard-shortcut-help-modal/shortcut.js | 70 +++++++++ .../keyboard-shortcut-help-modal/style.scss | 66 ++++++++ .../components/keyboard-shortcuts/index.js | 10 ++ .../components/more-menu/feature-toggle.js | 54 +++++++ .../src/components/more-menu/index.js | 130 ++++++++++++++++ .../src/components/more-menu/style.scss | 35 +++++ .../index.js | 17 ++- packages/edit-widgets/src/store/actions.js | 18 +++ packages/edit-widgets/src/store/defaults.js | 6 + packages/edit-widgets/src/store/index.js | 7 +- packages/edit-widgets/src/store/reducer.js | 47 ++++++ packages/edit-widgets/src/store/selectors.js | 18 ++- packages/edit-widgets/src/style.scss | 2 + 20 files changed, 713 insertions(+), 11 deletions(-) create mode 100644 packages/edit-widgets/src/components/keyboard-shortcut-help-modal/config.js create mode 100644 packages/edit-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js create mode 100644 packages/edit-widgets/src/components/keyboard-shortcut-help-modal/index.js create mode 100644 packages/edit-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js create mode 100644 packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss create mode 100644 packages/edit-widgets/src/components/more-menu/feature-toggle.js create mode 100644 packages/edit-widgets/src/components/more-menu/index.js create mode 100644 packages/edit-widgets/src/components/more-menu/style.scss create mode 100644 packages/edit-widgets/src/store/defaults.js diff --git a/package-lock.json b/package-lock.json index 4368775fc13523..fb39fee02ed88b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13786,6 +13786,7 @@ "version": "file:packages/edit-widgets", "requires": { "@babel/runtime": "^7.13.10", + "@wordpress/a11y": "file:packages/a11y", "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/block-editor": "file:packages/block-editor", "@wordpress/block-library": "file:packages/block-library", diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 9bd4afd3249738..8131aa86dfdf02 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -143,6 +143,7 @@ $z-layers: ( ".components-popover.block-editor-block-navigation__popover": 99998, ".components-popover.edit-post-more-menu__content": 99998, ".components-popover.edit-site-more-menu__content": 99998, + ".components-popover.edit-widgets-more-menu__content": 99998, ".components-popover.block-editor-rich-text__inline-format-toolbar": 99998, ".components-popover.block-editor-warning__dropdown": 99998, ".components-popover.edit-navigation-header__menu-switcher-dropdown": 99998, diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index d81bd78a696863..73fc2e797c2180 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -27,6 +27,7 @@ "react-native": "src/index", "dependencies": { "@babel/runtime": "^7.13.10", + "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", diff --git a/packages/edit-widgets/src/components/header/index.js b/packages/edit-widgets/src/components/header/index.js index 992d710db03088..c0475441002a25 100644 --- a/packages/edit-widgets/src/components/header/index.js +++ b/packages/edit-widgets/src/components/header/index.js @@ -3,7 +3,7 @@ */ import { useSelect, useDispatch } from '@wordpress/data'; import { __, _x } from '@wordpress/i18n'; -import { Button, ToolbarItem } from '@wordpress/components'; +import { Button, ToolbarItem, VisuallyHidden } from '@wordpress/components'; import { BlockNavigationDropdown, NavigableToolbar, @@ -12,6 +12,7 @@ import { import { PinnedItems } from '@wordpress/interface'; import { plus } from '@wordpress/icons'; import { useRef } from '@wordpress/element'; +import { useViewportMatch } from '@wordpress/compose'; /** * Internal dependencies @@ -19,10 +20,12 @@ import { useRef } from '@wordpress/element'; import SaveButton from '../save-button'; import UndoButton from './undo-redo/undo'; import RedoButton from './undo-redo/redo'; +import MoreMenu from '../more-menu'; import useLastSelectedWidgetArea from '../../hooks/use-last-selected-widget-area'; import { store as editWidgetsStore } from '../../store'; function Header() { + const isMediumViewport = useViewportMatch( 'medium' ); const inserterButton = useRef(); const widgetAreaClientId = useLastSelectedWidgetArea(); const isLastSelectedWidgetAreaOpen = useSelect( @@ -63,9 +66,19 @@ function Header() { <>
-

- { __( 'Widgets' ) } -

+ { isMediumViewport && ( +

+ { __( 'Widgets' ) } +

+ ) } + { ! isMediumViewport && ( + + { __( 'Widgets' ) } + + ) } - - - + { isMediumViewport && ( + <> + + + + + ) }
+
diff --git a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/config.js b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/config.js new file mode 100644 index 00000000000000..7b420cabfebb2a --- /dev/null +++ b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/config.js @@ -0,0 +1,27 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +export const textFormattingShortcuts = [ + { + keyCombination: { modifier: 'primary', character: 'b' }, + description: __( 'Make the selected text bold.' ), + }, + { + keyCombination: { modifier: 'primary', character: 'i' }, + description: __( 'Make the selected text italic.' ), + }, + { + keyCombination: { modifier: 'primary', character: 'k' }, + description: __( 'Convert the selected text into a link.' ), + }, + { + keyCombination: { modifier: 'primaryShift', character: 'k' }, + description: __( 'Remove a link.' ), + }, + { + keyCombination: { modifier: 'primary', character: 'u' }, + description: __( 'Underline the selected text.' ), + }, +]; diff --git a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js new file mode 100644 index 00000000000000..fe97fba37e14ac --- /dev/null +++ b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; + +/** + * Internal dependencies + */ +import Shortcut from './shortcut'; + +function DynamicShortcut( { name } ) { + const { keyCombination, description, aliases } = useSelect( ( select ) => { + const { + getShortcutKeyCombination, + getShortcutDescription, + getShortcutAliases, + } = select( keyboardShortcutsStore ); + + return { + keyCombination: getShortcutKeyCombination( name ), + aliases: getShortcutAliases( name ), + description: getShortcutDescription( name ), + }; + } ); + + if ( ! keyCombination ) { + return null; + } + + return ( + + ); +} + +export default DynamicShortcut; diff --git a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/index.js b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/index.js new file mode 100644 index 00000000000000..51b2a47e5f127b --- /dev/null +++ b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/index.js @@ -0,0 +1,142 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; +import { isString } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Modal } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { + useShortcut, + store as keyboardShortcutsStore, +} from '@wordpress/keyboard-shortcuts'; +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { textFormattingShortcuts } from './config'; +import Shortcut from './shortcut'; +import DynamicShortcut from './dynamic-shortcut'; + +const ShortcutList = ( { shortcuts } ) => ( + /* + * Disable reason: The `list` ARIA role is redundant but + * Safari+VoiceOver won't announce the list otherwise. + */ + /* eslint-disable jsx-a11y/no-redundant-roles */ +
    + { shortcuts.map( ( shortcut, index ) => ( +
  • + { isString( shortcut ) ? ( + + ) : ( + + ) } +
  • + ) ) } +
+ /* eslint-enable jsx-a11y/no-redundant-roles */ +); + +const ShortcutSection = ( { title, shortcuts, className } ) => ( +
+ { !! title && ( +

+ { title } +

+ ) } + +
+); + +const ShortcutCategorySection = ( { + title, + categoryName, + additionalShortcuts = [], +} ) => { + const categoryShortcuts = useSelect( + ( select ) => { + return select( keyboardShortcutsStore ).getCategoryShortcuts( + categoryName + ); + }, + [ categoryName ] + ); + + return ( + + ); +}; + +export default function KeyboardShortcutHelpModal( { + isModalActive, + toggleModal, +} ) { + useShortcut( 'core/edit-widgets/keyboard-shortcuts', toggleModal, { + bindGlobal: true, + } ); + + if ( ! isModalActive ) { + return null; + } + + return ( + + + + + + + + + + ); +} diff --git a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js new file mode 100644 index 00000000000000..8270a36a3ccceb --- /dev/null +++ b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js @@ -0,0 +1,70 @@ +/** + * External dependencies + */ +import { castArray } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Fragment } from '@wordpress/element'; +import { displayShortcutList, shortcutAriaLabel } from '@wordpress/keycodes'; + +function KeyCombination( { keyCombination, forceAriaLabel } ) { + const shortcut = keyCombination.modifier + ? displayShortcutList[ keyCombination.modifier ]( + keyCombination.character + ) + : keyCombination.character; + const ariaLabel = keyCombination.modifier + ? shortcutAriaLabel[ keyCombination.modifier ]( + keyCombination.character + ) + : keyCombination.character; + + return ( + + { castArray( shortcut ).map( ( character, index ) => { + if ( character === '+' ) { + return { character }; + } + + return ( + + { character } + + ); + } ) } + + ); +} + +function Shortcut( { description, keyCombination, aliases = [], ariaLabel } ) { + return ( + <> +
+ { description } +
+
+ + { aliases.map( ( alias, index ) => ( + + ) ) } +
+ + ); +} + +export default Shortcut; diff --git a/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss new file mode 100644 index 00000000000000..425a53fb23a635 --- /dev/null +++ b/packages/edit-widgets/src/components/keyboard-shortcut-help-modal/style.scss @@ -0,0 +1,66 @@ +.edit-widgets-keyboard-shortcut-help-modal { + &__section { + margin: 0 0 2rem 0; + } + + &__main-shortcuts .edit-widgets-keyboard-shortcut-help-modal__shortcut-list { + // Push the shortcut to be flush with top modal header. + margin-top: -$grid-unit-30 -$border-width; + } + + &__section-title { + font-size: 0.9rem; + font-weight: 600; + } + + &__shortcut { + display: flex; + align-items: baseline; + padding: 0.6rem 0; + border-top: 1px solid $gray-300; + margin-bottom: 0; + + &:last-child { + border-bottom: 1px solid $gray-300; + } + + &:empty { + display: none; + } + } + + &__shortcut-term { + font-weight: 600; + margin: 0 0 0 1rem; + text-align: right; + } + + &__shortcut-description { + flex: 1; + margin: 0; + + // IE 11 flex item fix - ensure the item does not collapse. + flex-basis: auto; + } + + &__shortcut-key-combination { + display: block; + background: none; + margin: 0; + padding: 0; + + & + .edit-widgets-keyboard-shortcut-help-modal__shortcut-key-combination { + margin-top: 10px; + } + } + + &__shortcut-key { + padding: 0.25rem 0.5rem; + border-radius: 8%; + margin: 0 0.2rem 0 0.2rem; + + &:last-child { + margin: 0 0 0 0.2rem; + } + } +} diff --git a/packages/edit-widgets/src/components/keyboard-shortcuts/index.js b/packages/edit-widgets/src/components/keyboard-shortcuts/index.js index eeb39b6ff9f494..8147a5b1d45583 100644 --- a/packages/edit-widgets/src/components/keyboard-shortcuts/index.js +++ b/packages/edit-widgets/src/components/keyboard-shortcuts/index.js @@ -81,6 +81,16 @@ function KeyboardShortcutsRegister() { character: 's', }, } ); + + registerShortcut( { + name: 'core/edit-widgets/keyboard-shortcuts', + category: 'main', + description: __( 'Display these keyboard shortcuts.' ), + keyCombination: { + modifier: 'access', + character: 'h', + }, + } ); }, [ registerShortcut ] ); return null; diff --git a/packages/edit-widgets/src/components/more-menu/feature-toggle.js b/packages/edit-widgets/src/components/more-menu/feature-toggle.js new file mode 100644 index 00000000000000..472ffd9e3cd4d3 --- /dev/null +++ b/packages/edit-widgets/src/components/more-menu/feature-toggle.js @@ -0,0 +1,54 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { MenuItem } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { check } from '@wordpress/icons'; +import { speak } from '@wordpress/a11y'; + +/** + * Internal dependencies + */ +import { store as editWidgetsStore } from '../../store'; + +export default function FeatureToggle( { + label, + info, + messageActivated, + messageDeactivated, + shortcut, + feature, +} ) { + const isActive = useSelect( + ( select ) => + select( editWidgetsStore ).__unstableIsFeatureActive( feature ), + [ feature ] + ); + const { __unstableToggleFeature: toggleFeature } = useDispatch( + editWidgetsStore + ); + const speakMessage = () => { + if ( isActive ) { + speak( messageDeactivated || __( 'Feature deactivated' ) ); + } else { + speak( messageActivated || __( 'Feature activated' ) ); + } + }; + + return ( + { + toggleFeature( feature ); + speakMessage(); + } } + role="menuitemcheckbox" + info={ info } + shortcut={ shortcut } + > + { label } + + ); +} diff --git a/packages/edit-widgets/src/components/more-menu/index.js b/packages/edit-widgets/src/components/more-menu/index.js new file mode 100644 index 00000000000000..0fad9a23259aa2 --- /dev/null +++ b/packages/edit-widgets/src/components/more-menu/index.js @@ -0,0 +1,130 @@ +/** + * WordPress dependencies + */ +import { + DropdownMenu, + MenuGroup, + MenuItem, + VisuallyHidden, +} from '@wordpress/components'; +import { useState } from '@wordpress/element'; +import { __, _x } from '@wordpress/i18n'; +import { external, moreVertical } from '@wordpress/icons'; +import { displayShortcut } from '@wordpress/keycodes'; +import { useShortcut } from '@wordpress/keyboard-shortcuts'; + +/** + * Internal dependencies + */ +import FeatureToggle from './feature-toggle'; +import KeyboardShortcutHelpModal from '../keyboard-shortcut-help-modal'; + +const POPOVER_PROPS = { + className: 'edit-widgets-more-menu__content', + position: 'bottom left', +}; +const TOGGLE_PROPS = { + tooltipPosition: 'bottom', +}; + +export default function MoreMenu() { + const [ + isKeyboardShortcutsModalActive, + setIsKeyboardShortcutsModalVisible, + ] = useState( false ); + const toggleKeyboardShortcutsModal = () => + setIsKeyboardShortcutsModalVisible( ! isKeyboardShortcutsModalActive ); + + useShortcut( + 'core/edit-widgets/keyboard-shortcuts', + toggleKeyboardShortcutsModal, + { + bindGlobal: true, + } + ); + + return ( + <> + + { () => ( + <> + + + + + { + setIsKeyboardShortcutsModalVisible( true ); + } } + shortcut={ displayShortcut.access( 'h' ) } + > + { __( 'Keyboard shortcuts' ) } + + + + { __( 'Help' ) } + + { + /* translators: accessibility text */ + __( '(opens in a new tab)' ) + } + + + + + + + + ) } + + + + ); +} diff --git a/packages/edit-widgets/src/components/more-menu/style.scss b/packages/edit-widgets/src/components/more-menu/style.scss new file mode 100644 index 00000000000000..1881067daf8e37 --- /dev/null +++ b/packages/edit-widgets/src/components/more-menu/style.scss @@ -0,0 +1,35 @@ +.edit-widgets-more-menu { + margin-left: -4px; + + // the padding and margin of the more menu is intentionally non-standard + .components-button { + width: auto; + padding: 0 2px; + } + + @include break-small() { + margin-left: 0; + + .components-button { + padding: 0 4px; + } + } +} + +.edit-widgets-more-menu__content .components-popover__content { + min-width: 280px; + + // Let the menu scale to fit items. + @include break-mobile() { + width: auto; + max-width: $break-mobile; + } + + .components-dropdown-menu__menu { + padding: 0; + } +} + +.components-popover.edit-widgets-more-menu__content { + z-index: z-index(".components-popover.edit-widgets-more-menu__content"); +} diff --git a/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js b/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js index 632fcd362a900f..63244ffaf9be3a 100644 --- a/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js +++ b/packages/edit-widgets/src/components/widget-areas-block-editor-provider/index.js @@ -30,7 +30,12 @@ export default function WidgetAreasBlockEditorProvider( { children, ...props } ) { - const { hasUploadPermissions, reusableBlocks } = useSelect( + const { + hasUploadPermissions, + reusableBlocks, + isFixedToolbarActive, + keepCaretInsideBlock, + } = useSelect( ( select ) => ( { hasUploadPermissions: defaultTo( select( 'core' ).canUser( 'create', 'media' ), @@ -42,6 +47,12 @@ export default function WidgetAreasBlockEditorProvider( { 'postType', 'wp_block' ), + isFixedToolbarActive: select( + editWidgetsStore + ).__unstableIsFeatureActive( 'fixedToolbar' ), + keepCaretInsideBlock: select( + editWidgetsStore + ).__unstableIsFeatureActive( 'keepCaretInsideBlock' ), } ), [] ); @@ -61,12 +72,16 @@ export default function WidgetAreasBlockEditorProvider( { return { ...blockEditorSettings, __experimentalReusableBlocks: reusableBlocks, + hasFixedToolbar: isFixedToolbarActive, + keepCaretInsideBlock, mediaUpload: mediaUploadBlockEditor, templateLock: 'all', __experimentalSetIsInserterOpened: setIsInserterOpened, }; }, [ blockEditorSettings, + isFixedToolbarActive, + keepCaretInsideBlock, hasUploadPermissions, reusableBlocks, setIsInserterOpened, diff --git a/packages/edit-widgets/src/store/actions.js b/packages/edit-widgets/src/store/actions.js index b850100da02af2..7ae0bb06d65324 100644 --- a/packages/edit-widgets/src/store/actions.js +++ b/packages/edit-widgets/src/store/actions.js @@ -416,3 +416,21 @@ export function* moveBlockToWidgetArea( clientId, widgetAreaId ) { destinationIndex ); } + +/** + * Returns an action object used to toggle a feature flag. + * + * This function is unstable, as it is mostly copied from the edit-post + * package. Editor features and preferences have a lot of scope for + * being generalized and refactored. + * + * @param {string} feature Feature name. + * + * @return {Object} Action object. + */ +export function __unstableToggleFeature( feature ) { + return { + type: 'TOGGLE_FEATURE', + feature, + }; +} diff --git a/packages/edit-widgets/src/store/defaults.js b/packages/edit-widgets/src/store/defaults.js new file mode 100644 index 00000000000000..61227800b91f72 --- /dev/null +++ b/packages/edit-widgets/src/store/defaults.js @@ -0,0 +1,6 @@ +export const PREFERENCES_DEFAULTS = { + features: { + fixedToolbar: false, + welcomeGuide: true, + }, +}; diff --git a/packages/edit-widgets/src/store/index.js b/packages/edit-widgets/src/store/index.js index cf294eb493f1c1..329bd71fdc18cb 100644 --- a/packages/edit-widgets/src/store/index.js +++ b/packages/edit-widgets/src/store/index.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import apiFetch from '@wordpress/api-fetch'; -import { createReduxStore, register } from '@wordpress/data'; +import { createReduxStore, registerStore } from '@wordpress/data'; /** * Internal dependencies @@ -27,6 +27,7 @@ const storeConfig = { selectors, resolvers, actions, + persist: [ 'preferences' ], }; /** @@ -38,7 +39,9 @@ const storeConfig = { */ export const store = createReduxStore( STORE_NAME, storeConfig ); -register( store ); +// Once we build a more generic persistence plugin that works across types of stores +// we'd be able to replace this with a register call. +registerStore( STORE_NAME, storeConfig ); // This package uses a few in-memory post types as wrappers for convenience. // This middleware prevents any network requests related to these types as they are diff --git a/packages/edit-widgets/src/store/reducer.js b/packages/edit-widgets/src/store/reducer.js index d6af45e6112091..7494bd5b497242 100644 --- a/packages/edit-widgets/src/store/reducer.js +++ b/packages/edit-widgets/src/store/reducer.js @@ -1,8 +1,30 @@ +/** + * External dependencies + */ +import { flow } from 'lodash'; + /** * WordPress dependencies */ import { combineReducers } from '@wordpress/data'; +/** + * Internal dependencies + */ +import { PREFERENCES_DEFAULTS } from './defaults'; + +/** + * Higher-order reducer creator which provides the given initial state for the + * original reducer. + * + * @param {*} initialState Initial state to provide to reducer. + * + * @return {Function} Higher-order reducer. + */ +const createWithInitialState = ( initialState ) => ( reducer ) => { + return ( state = initialState, action ) => reducer( state, action ); +}; + /** * Controls the open state of the widget areas. * @@ -43,7 +65,32 @@ function blockInserterPanel( state = false, action ) { return state; } +/** + * Reducer returning the user preferences. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Object} Updated state. + */ +export const preferences = flow( [ + combineReducers, + createWithInitialState( PREFERENCES_DEFAULTS ), +] )( { + features( state, action ) { + if ( action.type === 'TOGGLE_FEATURE' ) { + return { + ...state, + [ action.feature ]: ! state[ action.feature ], + }; + } + + return state; + }, +} ); + export default combineReducers( { blockInserterPanel, widgetAreasOpenState, + preferences, } ); diff --git a/packages/edit-widgets/src/store/selectors.js b/packages/edit-widgets/src/store/selectors.js index 485f6bb719ee93..7e30ed3f81f0cf 100644 --- a/packages/edit-widgets/src/store/selectors.js +++ b/packages/edit-widgets/src/store/selectors.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { keyBy } from 'lodash'; +import { get, keyBy } from 'lodash'; /** * WordPress dependencies @@ -220,3 +220,19 @@ export const canInsertBlockInWidgetArea = createRegistrySelector( ); } ); + +/** + * Returns whether the given feature is enabled or not. + * + * This function is unstable, as it is mostly copied from the edit-post + * package. Editor features and preferences have a lot of scope for + * being generalized and refactored. + * + * @param {Object} state Global application state. + * @param {string} feature Feature slug. + * + * @return {boolean} Is active. + */ +export function __unstableIsFeatureActive( state, feature ) { + return get( state.preferences.features, [ feature ], false ); +} diff --git a/packages/edit-widgets/src/style.scss b/packages/edit-widgets/src/style.scss index 525930ae66794b..7a87bd977f71d8 100644 --- a/packages/edit-widgets/src/style.scss +++ b/packages/edit-widgets/src/style.scss @@ -2,6 +2,8 @@ @import "./blocks/widget-area/editor.scss"; @import "./components/header/style.scss"; +@import "./components/keyboard-shortcut-help-modal/style.scss"; +@import "./components/more-menu/style.scss"; @import "./components/sidebar/style.scss"; @import "./components/notices/style.scss"; @import "./components/layout/style.scss"; From ee3d24b684c07783de5c07549144113a68f60afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20S=C3=A8gb=C3=A9dji=20Ahinon?= Date: Wed, 19 May 2021 06:50:22 +0100 Subject: [PATCH 03/13] Widget screen: Remove widget screen empty link in admin (#31408) * Remove widget screen empty link in admin * On admin, check if the widget screen menu link exists in the admin bar * Update lib/init.php Co-authored-by: Koen Van den Wijngaert Co-authored-by: Koen Van den Wijngaert --- lib/init.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/init.php b/lib/init.php index 880fe852c6fadb..e22542766f87ed 100644 --- a/lib/init.php +++ b/lib/init.php @@ -113,7 +113,7 @@ function gutenberg_site_editor_menu() { * @param WP_Admin_Bar $wp_admin_bar Core class used to implement the Toolbar API. */ function modify_admin_bar( $wp_admin_bar ) { - if ( gutenberg_use_widgets_block_editor() ) { + if ( gutenberg_use_widgets_block_editor() && $wp_admin_bar->get_node( 'widgets' ) !== null ) { $wp_admin_bar->add_menu( array( 'id' => 'widgets', From 524df510b8a7920f13ca08ac005c3ec2234ea189 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 19 May 2021 16:04:55 +1000 Subject: [PATCH 04/13] Widgets: Add Welcome Guide (#31925) * Widgets: Add Welcome Guide component * Widgets: Show different Welcome Guide message when all widgets are block widgets * Widgets: Hook Welcome Guide up to welcomeGuide feature * Disable welcome guide in Widgets E2E tests --- .../specs/widgets/adding-widgets.test.js | 15 ++ .../src/components/layout/index.js | 2 + .../src/components/welcome-guide/images.js | 80 ++++++++ .../src/components/welcome-guide/index.js | 173 ++++++++++++++++++ .../src/components/welcome-guide/style.scss | 45 +++++ packages/edit-widgets/src/style.scss | 1 + 6 files changed, 316 insertions(+) create mode 100644 packages/edit-widgets/src/components/welcome-guide/images.js create mode 100644 packages/edit-widgets/src/components/welcome-guide/index.js create mode 100644 packages/edit-widgets/src/components/welcome-guide/style.scss diff --git a/packages/e2e-tests/specs/widgets/adding-widgets.test.js b/packages/e2e-tests/specs/widgets/adding-widgets.test.js index 412e433ae32477..867069e7fea27a 100644 --- a/packages/e2e-tests/specs/widgets/adding-widgets.test.js +++ b/packages/e2e-tests/specs/widgets/adding-widgets.test.js @@ -22,6 +22,21 @@ import { groupBy, mapValues } from 'lodash'; describe( 'Widgets screen', () => { beforeEach( async () => { await visitAdminPage( 'themes.php', 'page=gutenberg-widgets' ); + + // Disable welcome guide if it is enabled. + const isWelcomeGuideActive = await page.evaluate( () => + wp.data + .select( 'core/edit-widgets' ) + .__unstableIsFeatureActive( 'welcomeGuide' ) + ); + if ( isWelcomeGuideActive ) { + await page.evaluate( () => + wp.data + .dispatch( 'core/edit-widgets' ) + .__unstableToggleFeature( 'welcomeGuide' ) + ); + } + // Wait for the widget areas to load. await findAll( { role: 'group', diff --git a/packages/edit-widgets/src/components/layout/index.js b/packages/edit-widgets/src/components/layout/index.js index 8ce67108fef819..2be16bd91a3dfc 100644 --- a/packages/edit-widgets/src/components/layout/index.js +++ b/packages/edit-widgets/src/components/layout/index.js @@ -11,6 +11,7 @@ import WidgetAreasBlockEditorProvider from '../widget-areas-block-editor-provide import Sidebar from '../sidebar'; import Interface from './interface'; import UnsavedChangesWarning from './unsaved-changes-warning'; +import WelcomeGuide from '../welcome-guide'; function Layout( { blockEditorSettings } ) { return ( @@ -22,6 +23,7 @@ function Layout( { blockEditorSettings } ) { + ); } diff --git a/packages/edit-widgets/src/components/welcome-guide/images.js b/packages/edit-widgets/src/components/welcome-guide/images.js new file mode 100644 index 00000000000000..9c3f42a139928a --- /dev/null +++ b/packages/edit-widgets/src/components/welcome-guide/images.js @@ -0,0 +1,80 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +export const CanvasImage = ( props ) => ( + <> + + + +); + +export const EditorImage = ( props ) => ( + <> + + + +); + +export const BlockLibraryImage = ( props ) => ( + <> + + + +); + +export const DocumentationImage = ( props ) => ( + <> + + + +); + +export const InserterIconImage = ( props ) => ( + { +); diff --git a/packages/edit-widgets/src/components/welcome-guide/index.js b/packages/edit-widgets/src/components/welcome-guide/index.js new file mode 100644 index 00000000000000..28b76cfc7a5f9e --- /dev/null +++ b/packages/edit-widgets/src/components/welcome-guide/index.js @@ -0,0 +1,173 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { ExternalLink, Guide } from '@wordpress/components'; +import { __, sprintf, _n } from '@wordpress/i18n'; +import { createInterpolateElement } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { + CanvasImage, + EditorImage, + BlockLibraryImage, + DocumentationImage, + InserterIconImage, +} from './images'; +import { store as editWidgetsStore } from '../../store'; + +export default function WelcomeGuide() { + const isActive = useSelect( + ( select ) => + select( editWidgetsStore ).__unstableIsFeatureActive( + 'welcomeGuide' + ), + [] + ); + + const { __unstableToggleFeature: toggleFeature } = useDispatch( + editWidgetsStore + ); + + const widgetAreas = useSelect( ( select ) => + select( editWidgetsStore ).getWidgetAreas( { per_page: -1 } ) + ); + + if ( ! isActive ) { + return null; + } + + const isEntirelyBlockWidgets = widgetAreas?.every( + ( widgetArea ) => + widgetArea.id === 'wp_inactive_widgets' || + widgetArea.widgets.every( ( widgetId ) => + widgetId.startsWith( 'block-' ) + ) + ); + + const numWidgetAreas = + widgetAreas?.filter( + ( widgetArea ) => widgetArea.id !== 'wp_inactive_widgets' + ).length ?? 0; + + return ( + toggleFeature( 'welcomeGuide' ) } + pages={ [ + { + image: , + content: ( + <> +

+ { __( 'Welcome to block Widgets' ) } +

+ { isEntirelyBlockWidgets ? ( + <> +

+ { sprintf( + // Translators: %s: Number of block areas in the current theme. + _n( + 'Your theme provides %s “block” area for you to add and edit content. Try adding a search bar, social icons, or other types of blocks here and see how they’ll look on your site.', + 'Your theme provides %s different “block” areas for you to add and edit content. Try adding a search bar, social icons, or other types of blocks here and see how they’ll look on your site.', + numWidgetAreas + ), + numWidgetAreas + ) } +

+ + ) : ( + <> +

+ { __( + 'You can now add any block to your site’s widget areas. Don’t worry, all of your favorite widgets still work flawlessly.' + ) } +

+

+ + { __( + 'Want to stick with the old widgets?' + ) } + { ' ' } + + { __( + 'Get the Classic Widgets plugin.' + ) } + +

+ + ) } + + ), + }, + { + image: , + content: ( + <> +

+ { __( 'Make each block your own' ) } +

+

+ { __( + 'Each block comes with its own set of controls for changing things like color, width, and alignment. These will show and hide automatically when you have a block selected.' + ) } +

+ + ), + }, + { + image: , + content: ( + <> +

+ { __( 'Get to know the block library' ) } +

+

+ { createInterpolateElement( + __( + 'All of the blocks available to you live in the block library. You’ll find it wherever you see the icon.' + ), + { + InserterIconImage: ( + + ), + } + ) } +

+ + ), + }, + { + image: , + content: ( + <> +

+ { __( 'Learn how to use the block editor' ) } +

+

+ { __( + 'New to the block editor? Want to learn more about using it? ' + ) } + + { __( "Here's a detailed guide." ) } + +

+ + ), + }, + ] } + /> + ); +} diff --git a/packages/edit-widgets/src/components/welcome-guide/style.scss b/packages/edit-widgets/src/components/welcome-guide/style.scss new file mode 100644 index 00000000000000..f05b921db35510 --- /dev/null +++ b/packages/edit-widgets/src/components/welcome-guide/style.scss @@ -0,0 +1,45 @@ +.edit-widgets-welcome-guide { + $image-height: 240px; + $image-width: 312px; + width: 312px; + + &__image { + background: #00a0d2; + height: 240px; + margin: 0 0 $grid-unit-20; + + &__prm-r { + display: none; + } + + @media (prefers-reduced-motion: reduce) { + &__prm-r { + display: block; + } + + &__prm-np { + display: none; + } + } + } + + &__heading { + font-family: $default-font; + font-size: 24px; + line-height: 1.4; + margin: $grid-unit-20 0 $grid-unit-20 0; + padding: 0 $grid-unit-40; + } + + &__text { + font-size: $default-font-size; + line-height: 1.4; + margin: 0 0 $grid-unit-30 0; + padding: 0 $grid-unit-40; + } + + &__inserter-icon { + margin: 0 4px; + vertical-align: text-top; + } +} diff --git a/packages/edit-widgets/src/style.scss b/packages/edit-widgets/src/style.scss index 7a87bd977f71d8..fc661e9e950688 100644 --- a/packages/edit-widgets/src/style.scss +++ b/packages/edit-widgets/src/style.scss @@ -7,6 +7,7 @@ @import "./components/sidebar/style.scss"; @import "./components/notices/style.scss"; @import "./components/layout/style.scss"; +@import "./components/welcome-guide/style.scss"; @import "./components/widget-areas-block-editor-content/style.scss"; // In order to use mix-blend-mode, this element needs to have an explicitly set background-color From 9264b9af31048ff8fc1b58e14fa6e3347ca7fe09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Wed, 19 May 2021 08:58:17 +0200 Subject: [PATCH 05/13] Font-family: fix typo in supports for dynamic blocks (#31974) --- lib/block-supports/typography.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index f2babdc7e6c969..746ab9eff24e3a 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -99,7 +99,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { $font_family_name = substr( $font_family, $index_to_splice ); $styles[] = sprintf( 'font-family: var(--wp--preset--font-family--%s);', $font_family_name ); } else { - $styles[] = sprintf( 'font-family: %s;', $block_attributes['style']['color']['fontFamily'] ); + $styles[] = sprintf( 'font-family: %s;', $block_attributes['style']['typography']['fontFamily'] ); } } } From 1103f7ba9f20fada5af22cb6d86bd26e75defea6 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Wed, 19 May 2021 14:59:44 +0800 Subject: [PATCH 06/13] Add more menu to customize widgets (#31970) * Add basic more menu framework * Hook up top toolbar and contain caret inside blocks preferences to editor settings * Introduce keyboard shortcut modal * Fix modal styles * Add shortcut for modal itself * Tidy up bottom margin when top toolbar is active * Toolbar adjustments * Update package lock --- package-lock.json | 1 + packages/base-styles/_z-index.scss | 1 + packages/customize-widgets/package.json | 1 + .../src/components/header/index.js | 25 ++- .../src/components/header/style.scss | 15 +- .../keyboard-shortcut-help-modal/config.js | 27 ++++ .../dynamic-shortcut.js | 40 +++++ .../keyboard-shortcut-help-modal/index.js | 153 ++++++++++++++++++ .../keyboard-shortcut-help-modal/shortcut.js | 70 ++++++++ .../keyboard-shortcut-help-modal/style.scss | 66 ++++++++ .../components/more-menu/feature-toggle.js | 56 +++++++ .../src/components/more-menu/index.js | 130 +++++++++++++++ .../src/components/more-menu/style.scss | 35 ++++ .../components/sidebar-block-editor/index.js | 34 +++- .../customize-widgets/src/store/actions.js | 17 ++ .../customize-widgets/src/store/constants.js | 4 + .../customize-widgets/src/store/defaults.js | 6 + packages/customize-widgets/src/store/index.js | 39 +++++ .../customize-widgets/src/store/reducer.js | 54 +++++++ .../customize-widgets/src/store/selectors.js | 20 +++ packages/customize-widgets/src/style.scss | 7 + 21 files changed, 786 insertions(+), 15 deletions(-) create mode 100644 packages/customize-widgets/src/components/keyboard-shortcut-help-modal/config.js create mode 100644 packages/customize-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js create mode 100644 packages/customize-widgets/src/components/keyboard-shortcut-help-modal/index.js create mode 100644 packages/customize-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js create mode 100644 packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss create mode 100644 packages/customize-widgets/src/components/more-menu/feature-toggle.js create mode 100644 packages/customize-widgets/src/components/more-menu/index.js create mode 100644 packages/customize-widgets/src/components/more-menu/style.scss create mode 100644 packages/customize-widgets/src/store/actions.js create mode 100644 packages/customize-widgets/src/store/constants.js create mode 100644 packages/customize-widgets/src/store/defaults.js create mode 100644 packages/customize-widgets/src/store/index.js create mode 100644 packages/customize-widgets/src/store/reducer.js create mode 100644 packages/customize-widgets/src/store/selectors.js diff --git a/package-lock.json b/package-lock.json index fb39fee02ed88b..f1d4ce702a8c7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13493,6 +13493,7 @@ "@wordpress/i18n": "file:packages/i18n", "@wordpress/icons": "file:packages/icons", "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", + "@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts", "@wordpress/keycodes": "file:packages/keycodes", "@wordpress/media-utils": "file:packages/media-utils", "@wordpress/widgets": "file:packages/widgets", diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 8131aa86dfdf02..fd5fc778cab6b3 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -141,6 +141,7 @@ $z-layers: ( ".components-popover.block-editor-inserter__popover": 99999, ".components-popover.table-of-contents__popover": 99998, ".components-popover.block-editor-block-navigation__popover": 99998, + ".components-popover.customize-widgets-more-menu__content": 99998, ".components-popover.edit-post-more-menu__content": 99998, ".components-popover.edit-site-more-menu__content": 99998, ".components-popover.edit-widgets-more-menu__content": 99998, diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json index 3324ab6c992102..63b977fd8006cb 100644 --- a/packages/customize-widgets/package.json +++ b/packages/customize-widgets/package.json @@ -39,6 +39,7 @@ "@wordpress/i18n": "file:../i18n", "@wordpress/icons": "file:../icons", "@wordpress/is-shallow-equal": "file:../is-shallow-equal", + "@wordpress/keyboard-shortcuts": "file:../keyboard-shortcuts", "@wordpress/keycodes": "file:../keycodes", "@wordpress/media-utils": "file:../media-utils", "@wordpress/widgets": "file:../widgets", diff --git a/packages/customize-widgets/src/components/header/index.js b/packages/customize-widgets/src/components/header/index.js index 11b5353a474ef5..3a2eb883f6798a 100644 --- a/packages/customize-widgets/src/components/header/index.js +++ b/packages/customize-widgets/src/components/header/index.js @@ -1,9 +1,14 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { createPortal } from '@wordpress/element'; import { __, _x } from '@wordpress/i18n'; -import { Button, ToolbarItem } from '@wordpress/components'; +import { ToolbarButton } from '@wordpress/components'; import { NavigableToolbar } from '@wordpress/block-editor'; import { plus } from '@wordpress/icons'; @@ -11,17 +16,26 @@ import { plus } from '@wordpress/icons'; * Internal dependencies */ import Inserter from '../inserter'; +import MoreMenu from '../more-menu'; -function Header( { inserter, isInserterOpened, setIsInserterOpened } ) { +function Header( { + inserter, + isInserterOpened, + setIsInserterOpened, + isFixedToolbarActive, +} ) { return ( <> -
+
- ! isOpen ); } } /> +
diff --git a/packages/customize-widgets/src/components/header/style.scss b/packages/customize-widgets/src/components/header/style.scss index ae829441cb6777..106631cd742f36 100644 --- a/packages/customize-widgets/src/components/header/style.scss +++ b/packages/customize-widgets/src/components/header/style.scss @@ -1,13 +1,20 @@ .customize-widgets-header { @include break-medium() { - // The mobile fixed block toolbar should be snug under the header. + // Make space for the floating toolbar. margin-bottom: $grid-unit-60 + $default-block-margin; } + &.is-fixed-toolbar-active { + // Top toolbar mode toolbar should be right under the header. + margin-bottom: 0; + } + + display: flex; + justify-content: flex-end; + // Offset the customizer's sidebar padding. - // Provide enough bottom margin to ensure the floating block toolbar isn't overlapped. + // Zero bottom margin so that the fixed toolbar is right under the header. margin: -15px ( -$grid-unit-15 ) ( 0 ) ( -$grid-unit-15 ); - padding: $grid-unit-15; // Match the customizer grey background. background: #f0f0f1; @@ -26,7 +33,7 @@ padding: 0; min-width: $grid-unit-30; height: $grid-unit-30; - margin-left: auto; + margin: $grid-unit-15 0 $grid-unit-15; &::before { content: none; diff --git a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/config.js b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/config.js new file mode 100644 index 00000000000000..7b420cabfebb2a --- /dev/null +++ b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/config.js @@ -0,0 +1,27 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +export const textFormattingShortcuts = [ + { + keyCombination: { modifier: 'primary', character: 'b' }, + description: __( 'Make the selected text bold.' ), + }, + { + keyCombination: { modifier: 'primary', character: 'i' }, + description: __( 'Make the selected text italic.' ), + }, + { + keyCombination: { modifier: 'primary', character: 'k' }, + description: __( 'Convert the selected text into a link.' ), + }, + { + keyCombination: { modifier: 'primaryShift', character: 'k' }, + description: __( 'Remove a link.' ), + }, + { + keyCombination: { modifier: 'primary', character: 'u' }, + description: __( 'Underline the selected text.' ), + }, +]; diff --git a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js new file mode 100644 index 00000000000000..fe97fba37e14ac --- /dev/null +++ b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/dynamic-shortcut.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; + +/** + * Internal dependencies + */ +import Shortcut from './shortcut'; + +function DynamicShortcut( { name } ) { + const { keyCombination, description, aliases } = useSelect( ( select ) => { + const { + getShortcutKeyCombination, + getShortcutDescription, + getShortcutAliases, + } = select( keyboardShortcutsStore ); + + return { + keyCombination: getShortcutKeyCombination( name ), + aliases: getShortcutAliases( name ), + description: getShortcutDescription( name ), + }; + } ); + + if ( ! keyCombination ) { + return null; + } + + return ( + + ); +} + +export default DynamicShortcut; diff --git a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/index.js b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/index.js new file mode 100644 index 00000000000000..e600474a933cb8 --- /dev/null +++ b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/index.js @@ -0,0 +1,153 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; +import { isString } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Modal } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { + useShortcut, + store as keyboardShortcutsStore, +} from '@wordpress/keyboard-shortcuts'; +import { useDispatch, useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { textFormattingShortcuts } from './config'; +import Shortcut from './shortcut'; +import DynamicShortcut from './dynamic-shortcut'; + +const ShortcutList = ( { shortcuts } ) => ( + /* + * Disable reason: The `list` ARIA role is redundant but + * Safari+VoiceOver won't announce the list otherwise. + */ + /* eslint-disable jsx-a11y/no-redundant-roles */ +
    + { shortcuts.map( ( shortcut, index ) => ( +
  • + { isString( shortcut ) ? ( + + ) : ( + + ) } +
  • + ) ) } +
+ /* eslint-enable jsx-a11y/no-redundant-roles */ +); + +const ShortcutSection = ( { title, shortcuts, className } ) => ( +
+ { !! title && ( +

+ { title } +

+ ) } + +
+); + +const ShortcutCategorySection = ( { + title, + categoryName, + additionalShortcuts = [], +} ) => { + const categoryShortcuts = useSelect( + ( select ) => { + return select( keyboardShortcutsStore ).getCategoryShortcuts( + categoryName + ); + }, + [ categoryName ] + ); + + return ( + + ); +}; + +export default function KeyboardShortcutHelpModal( { + isModalActive, + toggleModal, +} ) { + const { registerShortcut } = useDispatch( keyboardShortcutsStore ); + registerShortcut( { + name: 'core/customize-widgets/keyboard-shortcuts', + category: 'main', + description: __( 'Display these keyboard shortcuts.' ), + keyCombination: { + modifier: 'access', + character: 'h', + }, + } ); + + useShortcut( 'core/customize-widgets/keyboard-shortcuts', toggleModal, { + bindGlobal: true, + } ); + + if ( ! isModalActive ) { + return null; + } + + return ( + + + + + + + + + + ); +} diff --git a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js new file mode 100644 index 00000000000000..c25bdbb20e6725 --- /dev/null +++ b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/shortcut.js @@ -0,0 +1,70 @@ +/** + * External dependencies + */ +import { castArray } from 'lodash'; + +/** + * WordPress dependencies + */ +import { Fragment } from '@wordpress/element'; +import { displayShortcutList, shortcutAriaLabel } from '@wordpress/keycodes'; + +function KeyCombination( { keyCombination, forceAriaLabel } ) { + const shortcut = keyCombination.modifier + ? displayShortcutList[ keyCombination.modifier ]( + keyCombination.character + ) + : keyCombination.character; + const ariaLabel = keyCombination.modifier + ? shortcutAriaLabel[ keyCombination.modifier ]( + keyCombination.character + ) + : keyCombination.character; + + return ( + + { castArray( shortcut ).map( ( character, index ) => { + if ( character === '+' ) { + return { character }; + } + + return ( + + { character } + + ); + } ) } + + ); +} + +function Shortcut( { description, keyCombination, aliases = [], ariaLabel } ) { + return ( + <> +
+ { description } +
+
+ + { aliases.map( ( alias, index ) => ( + + ) ) } +
+ + ); +} + +export default Shortcut; diff --git a/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss new file mode 100644 index 00000000000000..507935a561d433 --- /dev/null +++ b/packages/customize-widgets/src/components/keyboard-shortcut-help-modal/style.scss @@ -0,0 +1,66 @@ +.customize-widgets-keyboard-shortcut-help-modal { + &__section { + margin: 0 0 2rem 0; + } + + &__main-shortcuts .customize-widgets-keyboard-shortcut-help-modal__shortcut-list { + // Push the shortcut to be flush with top modal header. + margin-top: -$grid-unit-30 -$border-width; + } + + &__section-title { + font-size: 0.9rem; + font-weight: 600; + } + + &__shortcut { + display: flex; + align-items: baseline; + padding: 0.6rem 0; + border-top: 1px solid $gray-300; + margin-bottom: 0; + + &:last-child { + border-bottom: 1px solid $gray-300; + } + + &:empty { + display: none; + } + } + + &__shortcut-term { + font-weight: 600; + margin: 0 0 0 1rem; + text-align: right; + } + + &__shortcut-description { + flex: 1; + margin: 0; + + // IE 11 flex item fix - ensure the item does not collapse. + flex-basis: auto; + } + + &__shortcut-key-combination { + display: block; + background: none; + margin: 0; + padding: 0; + + & + .customize-widgets-keyboard-shortcut-help-modal__shortcut-key-combination { + margin-top: 10px; + } + } + + &__shortcut-key { + padding: 0.25rem 0.5rem; + border-radius: 8%; + margin: 0 0.2rem 0 0.2rem; + + &:last-child { + margin: 0 0 0 0.2rem; + } + } +} diff --git a/packages/customize-widgets/src/components/more-menu/feature-toggle.js b/packages/customize-widgets/src/components/more-menu/feature-toggle.js new file mode 100644 index 00000000000000..6235a0171814a0 --- /dev/null +++ b/packages/customize-widgets/src/components/more-menu/feature-toggle.js @@ -0,0 +1,56 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { MenuItem } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { check } from '@wordpress/icons'; +import { speak } from '@wordpress/a11y'; + +/** + * Internal dependencies + */ +import { store as customizeWidgetsStore } from '../../store'; + +export default function FeatureToggle( { + label, + info, + messageActivated, + messageDeactivated, + shortcut, + feature, +} ) { + const isActive = useSelect( + ( select ) => + select( customizeWidgetsStore ).__unstableIsFeatureActive( + feature + ), + [ feature ] + ); + const { __unstableToggleFeature: toggleFeature } = useDispatch( + customizeWidgetsStore + ); + const speakMessage = () => { + if ( isActive ) { + speak( messageDeactivated || __( 'Feature deactivated' ) ); + } else { + speak( messageActivated || __( 'Feature activated' ) ); + } + }; + + return ( + { + toggleFeature( feature ); + speakMessage(); + } } + role="menuitemcheckbox" + info={ info } + shortcut={ shortcut } + > + { label } + + ); +} diff --git a/packages/customize-widgets/src/components/more-menu/index.js b/packages/customize-widgets/src/components/more-menu/index.js new file mode 100644 index 00000000000000..ebbb673bbd22fe --- /dev/null +++ b/packages/customize-widgets/src/components/more-menu/index.js @@ -0,0 +1,130 @@ +/** + * WordPress dependencies + */ +import { + ToolbarDropdownMenu, + MenuGroup, + MenuItem, + VisuallyHidden, +} from '@wordpress/components'; +import { useState } from '@wordpress/element'; +import { __, _x } from '@wordpress/i18n'; +import { external, moreVertical } from '@wordpress/icons'; +import { displayShortcut } from '@wordpress/keycodes'; +import { useShortcut } from '@wordpress/keyboard-shortcuts'; + +/** + * Internal dependencies + */ +import FeatureToggle from './feature-toggle'; +import KeyboardShortcutHelpModal from '../keyboard-shortcut-help-modal'; + +const POPOVER_PROPS = { + className: 'customize-widgets-more-menu__content', + position: 'bottom left', +}; +const TOGGLE_PROPS = { + tooltipPosition: 'bottom', +}; + +export default function MoreMenu() { + const [ + isKeyboardShortcutsModalActive, + setIsKeyboardShortcutsModalVisible, + ] = useState( false ); + const toggleKeyboardShortcutsModal = () => + setIsKeyboardShortcutsModalVisible( ! isKeyboardShortcutsModalActive ); + + useShortcut( + 'core/customize-widgets/keyboard-shortcuts', + toggleKeyboardShortcutsModal, + { + bindGlobal: true, + } + ); + + return ( + <> + + { () => ( + <> + + + + + { + setIsKeyboardShortcutsModalVisible( true ); + } } + shortcut={ displayShortcut.access( 'h' ) } + > + { __( 'Keyboard shortcuts' ) } + + + + { __( 'Help' ) } + + { + /* translators: accessibility text */ + __( '(opens in a new tab)' ) + } + + + + + + + + ) } + + + + ); +} diff --git a/packages/customize-widgets/src/components/more-menu/style.scss b/packages/customize-widgets/src/components/more-menu/style.scss new file mode 100644 index 00000000000000..e38068f7ec7470 --- /dev/null +++ b/packages/customize-widgets/src/components/more-menu/style.scss @@ -0,0 +1,35 @@ +.customize-widgets-more-menu { + margin-left: -4px; + + // the padding and margin of the more menu is intentionally non-standard + .components-button { + width: auto; + padding: 0 2px; + } + + @include break-small() { + margin-left: 0; + + .components-button { + padding: 0 4px; + } + } +} + +.customize-widgets-more-menu__content .components-popover__content { + min-width: 280px; + + // Let the menu scale to fit items. + @include break-mobile() { + width: auto; + max-width: $break-mobile; + } + + .components-dropdown-menu__menu { + padding: 0; + } +} + +.components-popover.customize-widgets-more-menu__content { + z-index: z-index(".components-popover.customize-widgets-more-menu__content"); +} diff --git a/packages/customize-widgets/src/components/sidebar-block-editor/index.js b/packages/customize-widgets/src/components/sidebar-block-editor/index.js index c20f57a486db4b..bbca644880a949 100644 --- a/packages/customize-widgets/src/components/sidebar-block-editor/index.js +++ b/packages/customize-widgets/src/components/sidebar-block-editor/index.js @@ -28,6 +28,7 @@ import BlockInspectorButton from '../block-inspector-button'; import Header from '../header'; import useInserter from '../inserter/use-inserter'; import SidebarEditorProvider from './sidebar-editor-provider'; +import { store as customizeWidgetsStore } from '../../store'; export default function SidebarBlockEditor( { blockEditorSettings, @@ -36,11 +37,24 @@ export default function SidebarBlockEditor( { inspector, } ) { const [ isInserterOpened, setIsInserterOpened ] = useInserter( inserter ); - const hasUploadPermissions = useSelect( - ( select ) => - defaultTo( select( coreStore ).canUser( 'create', 'media' ), true ), - [] - ); + const { + hasUploadPermissions, + isFixedToolbarActive, + keepCaretInsideBlock, + } = useSelect( ( select ) => { + return { + hasUploadPermissions: defaultTo( + select( coreStore ).canUser( 'create', 'media' ), + true + ), + isFixedToolbarActive: select( + customizeWidgetsStore + ).__unstableIsFeatureActive( 'fixedToolbar' ), + keepCaretInsideBlock: select( + customizeWidgetsStore + ).__unstableIsFeatureActive( 'keepCaretInsideBlock' ), + }; + }, [] ); const settings = useMemo( () => { let mediaUploadBlockEditor; if ( hasUploadPermissions ) { @@ -57,8 +71,15 @@ export default function SidebarBlockEditor( { ...blockEditorSettings, __experimentalSetIsInserterOpened: setIsInserterOpened, mediaUpload: mediaUploadBlockEditor, + hasFixedToolbar: isFixedToolbarActive, + keepCaretInsideBlock, }; - }, [ hasUploadPermissions, blockEditorSettings ] ); + }, [ + hasUploadPermissions, + blockEditorSettings, + isFixedToolbarActive, + keepCaretInsideBlock, + ] ); return ( <> @@ -68,6 +89,7 @@ export default function SidebarBlockEditor( {
( reducer ) => { + return ( state = initialState, action ) => reducer( state, action ); +}; + +/** + * Reducer returning the user preferences. + * + * @param {Object} state Current state. + * @param {Object} action Dispatched action. + * + * @return {Object} Updated state. + */ +export const preferences = flow( [ + combineReducers, + createWithInitialState( PREFERENCES_DEFAULTS ), +] )( { + features( state, action ) { + if ( action.type === 'TOGGLE_FEATURE' ) { + return { + ...state, + [ action.feature ]: ! state[ action.feature ], + }; + } + + return state; + }, +} ); + +export default combineReducers( { + preferences, +} ); diff --git a/packages/customize-widgets/src/store/selectors.js b/packages/customize-widgets/src/store/selectors.js new file mode 100644 index 00000000000000..cc546ec6e5a7e8 --- /dev/null +++ b/packages/customize-widgets/src/store/selectors.js @@ -0,0 +1,20 @@ +/** + * External dependencies + */ +import { get } from 'lodash'; + +/** + * Returns whether the given feature is enabled or not. + * + * This function is unstable, as it is mostly copied from the edit-post + * package. Editor features and preferences have a lot of scope for + * being generalized and refactored. + * + * @param {Object} state Global application state. + * @param {string} feature Feature slug. + * + * @return {boolean} Is active. + */ +export function __unstableIsFeatureActive( state, feature ) { + return get( state.preferences.features, [ feature ], false ); +} diff --git a/packages/customize-widgets/src/style.scss b/packages/customize-widgets/src/style.scss index c75380757e8c10..a96c7ec0558933 100644 --- a/packages/customize-widgets/src/style.scss +++ b/packages/customize-widgets/src/style.scss @@ -2,4 +2,11 @@ @import "./components/block-inspector-button/style.scss"; @import "./components/header/style.scss"; @import "./components/inserter/style.scss"; +@import "./components/keyboard-shortcut-help-modal/style.scss"; +@import "./components/more-menu/style.scss"; @import "./controls/style.scss"; + +// Modals need a higher z-index in the customizer. +.components-modal__screen-overlay { + z-index: 999999; +} From 4e42e00183e3e1b12eb48a8ebc4d47f4d7287a27 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 19 May 2021 17:59:05 +1000 Subject: [PATCH 07/13] Widgets Customizer: Add Welcome messaging (#31968) * Widgets Customizer: Add Welcome component * Widgets Customizer: Show different message when new user and area contains entirely blocks * Widgets Customizer: Rename Welcome to WelcomeGuide and hook it up to welcomeGuide setting * Disable welcome guide in Widgets Customizer E2E tests * Adjust line heights and margins in Customizer WelcomeGuide --- .../components/sidebar-block-editor/index.js | 9 +++ .../src/components/welcome-guide/images.js | 16 +++++ .../src/components/welcome-guide/index.js | 72 +++++++++++++++++++ .../src/components/welcome-guide/style.scss | 45 ++++++++++++ packages/customize-widgets/src/style.scss | 3 +- .../experiments/customizing-widgets.test.js | 14 ++++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 packages/customize-widgets/src/components/welcome-guide/images.js create mode 100644 packages/customize-widgets/src/components/welcome-guide/index.js create mode 100644 packages/customize-widgets/src/components/welcome-guide/style.scss diff --git a/packages/customize-widgets/src/components/sidebar-block-editor/index.js b/packages/customize-widgets/src/components/sidebar-block-editor/index.js index bbca644880a949..b3441dcab4b7cd 100644 --- a/packages/customize-widgets/src/components/sidebar-block-editor/index.js +++ b/packages/customize-widgets/src/components/sidebar-block-editor/index.js @@ -29,6 +29,7 @@ import Header from '../header'; import useInserter from '../inserter/use-inserter'; import SidebarEditorProvider from './sidebar-editor-provider'; import { store as customizeWidgetsStore } from '../../store'; +import WelcomeGuide from '../welcome-guide'; export default function SidebarBlockEditor( { blockEditorSettings, @@ -41,6 +42,7 @@ export default function SidebarBlockEditor( { hasUploadPermissions, isFixedToolbarActive, keepCaretInsideBlock, + isWelcomeGuideActive, } = useSelect( ( select ) => { return { hasUploadPermissions: defaultTo( @@ -53,6 +55,9 @@ export default function SidebarBlockEditor( { keepCaretInsideBlock: select( customizeWidgetsStore ).__unstableIsFeatureActive( 'keepCaretInsideBlock' ), + isWelcomeGuideActive: select( + customizeWidgetsStore + ).__unstableIsFeatureActive( 'welcomeGuide' ), }; }, [] ); const settings = useMemo( () => { @@ -81,6 +86,10 @@ export default function SidebarBlockEditor( { keepCaretInsideBlock, ] ); + if ( isWelcomeGuideActive ) { + return ; + } + return ( <> diff --git a/packages/customize-widgets/src/components/welcome-guide/images.js b/packages/customize-widgets/src/components/welcome-guide/images.js new file mode 100644 index 00000000000000..31aa04d994a4a2 --- /dev/null +++ b/packages/customize-widgets/src/components/welcome-guide/images.js @@ -0,0 +1,16 @@ +export const EditorImage = ( props ) => ( + <> + + + +); diff --git a/packages/customize-widgets/src/components/welcome-guide/index.js b/packages/customize-widgets/src/components/welcome-guide/index.js new file mode 100644 index 00000000000000..da07909e705ab9 --- /dev/null +++ b/packages/customize-widgets/src/components/welcome-guide/index.js @@ -0,0 +1,72 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Button, ExternalLink } from '@wordpress/components'; +import { useDispatch } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import { EditorImage } from './images'; +import { store as customizeWidgetsStore } from '../../store'; + +export default function WelcomeGuide( { sidebar } ) { + const { __unstableToggleFeature: toggleFeature } = useDispatch( + customizeWidgetsStore + ); + + const isEntirelyBlockWidgets = sidebar + .getWidgets() + .every( ( widget ) => widget.id.startsWith( 'block-' ) ); + + return ( +
+ +

+ { __( 'Welcome to block Widgets' ) } +

+

+ { isEntirelyBlockWidgets + ? __( + 'Your theme provides different “block” areas for you to add and edit content. Try adding a search bar, social icons, or other types of blocks here and see how they’ll look on your site.' + ) + : __( + 'You can now add any block to your site’s widget areas. Don’t worry, all of your favorite widgets still work flawlessly.' + ) } +

+ +
+ { ! isEntirelyBlockWidgets && ( +

+ { __( 'Want to stick with the old widgets?' ) } +
+ + { __( 'Get the Classic Widgets plugin.' ) } + +

+ ) } +

+ { __( 'New to the block editor?' ) } +
+ + { __( "Here's a detailed guide." ) } + +

+
+ ); +} diff --git a/packages/customize-widgets/src/components/welcome-guide/style.scss b/packages/customize-widgets/src/components/welcome-guide/style.scss new file mode 100644 index 00000000000000..7372cc438158e7 --- /dev/null +++ b/packages/customize-widgets/src/components/welcome-guide/style.scss @@ -0,0 +1,45 @@ +.customize-widgets-welcome-guide { + &__image { + background: #00a0d2; + height: 240px; + margin: 0 0 $grid-unit-10; + + &__prm-r { + display: none; + } + + @media (prefers-reduced-motion: reduce) { + &__prm-r { + display: block; + } + + &__prm-np { + display: none; + } + } + } + + // Extra specificity to override `.wrap h1` styles. + .wrap &__heading { + font-size: 18px; + font-weight: 600; + } + + &__text { + line-height: 1.7; + } + + &__button { + justify-content: center; + margin: 1em 0; + width: 100%; + } + + &__separator { + margin: 1em 0; + } + + &__more-info { + line-height: 1.4; + } +} diff --git a/packages/customize-widgets/src/style.scss b/packages/customize-widgets/src/style.scss index a96c7ec0558933..5fca995e322c57 100644 --- a/packages/customize-widgets/src/style.scss +++ b/packages/customize-widgets/src/style.scss @@ -1,9 +1,10 @@ -@import "./components/sidebar-block-editor/style.scss"; @import "./components/block-inspector-button/style.scss"; @import "./components/header/style.scss"; @import "./components/inserter/style.scss"; @import "./components/keyboard-shortcut-help-modal/style.scss"; @import "./components/more-menu/style.scss"; +@import "./components/sidebar-block-editor/style.scss"; +@import "./components/welcome-guide/style.scss"; @import "./controls/style.scss"; // Modals need a higher z-index in the customizer. diff --git a/packages/e2e-tests/specs/experiments/customizing-widgets.test.js b/packages/e2e-tests/specs/experiments/customizing-widgets.test.js index 6f9fb9784bb1dc..e3e03a44a41e25 100644 --- a/packages/e2e-tests/specs/experiments/customizing-widgets.test.js +++ b/packages/e2e-tests/specs/experiments/customizing-widgets.test.js @@ -20,6 +20,20 @@ describe( 'Widgets Customizer', () => { beforeEach( async () => { await cleanupWidgets(); await visitAdminPage( 'customize.php' ); + + // Disable welcome guide if it is enabled. + const isWelcomeGuideActive = await page.evaluate( () => + wp.data + .select( 'core/customize-widgets' ) + .__unstableIsFeatureActive( 'welcomeGuide' ) + ); + if ( isWelcomeGuideActive ) { + await page.evaluate( () => + wp.data + .dispatch( 'core/customize-widgets' ) + .__unstableToggleFeature( 'welcomeGuide' ) + ); + } } ); beforeAll( async () => { From 55bef6e80f94a9b98df198e783f7f7fbccf95b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Wed, 19 May 2021 12:26:00 +0300 Subject: [PATCH 08/13] Revert "Replace string literals with store definitions in block-library (#31933)" (#31977) This reverts commit b122f241589ed20c5f1cb888ff770b6604816e00. --- packages/block-library/src/categories/edit.js | 4 ++-- packages/block-library/src/embed/edit.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/categories/edit.js b/packages/block-library/src/categories/edit.js index efb499ddef1a2e..12adf03e1ffcee 100644 --- a/packages/block-library/src/categories/edit.js +++ b/packages/block-library/src/categories/edit.js @@ -14,7 +14,7 @@ import { VisuallyHidden, } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; -import { useSelect, store as dataStore } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; import { pin } from '@wordpress/icons'; @@ -27,7 +27,7 @@ export default function CategoriesEdit( { const selectId = useInstanceId( CategoriesEdit, 'blocks-category-select' ); const { categories, isRequesting } = useSelect( ( select ) => { const { getEntityRecords } = select( coreStore ); - const { isResolving } = select( dataStore ); + const { isResolving } = select( 'core/data' ); const query = { per_page: -1, hide_empty: true }; return { categories: getEntityRecords( 'taxonomy', 'category', query ), diff --git a/packages/block-library/src/embed/edit.js b/packages/block-library/src/embed/edit.js index 0bcabc5cf57c25..a02371c0d4c637 100644 --- a/packages/block-library/src/embed/edit.js +++ b/packages/block-library/src/embed/edit.js @@ -24,7 +24,7 @@ import classnames from 'classnames'; */ import { __, _x, sprintf } from '@wordpress/i18n'; import { useState, useEffect, Platform } from '@wordpress/element'; -import { useDispatch, useSelect, store as dataStore } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; import { store as coreStore } from '@wordpress/core-data'; import { View } from '@wordpress/primitives'; @@ -64,7 +64,7 @@ const EmbedEdit = ( props ) => { const [ url, setURL ] = useState( attributesUrl ); const [ isEditingURL, setIsEditingURL ] = useState( false ); - const { invalidateResolution } = useDispatch( dataStore ); + const { invalidateResolution } = useDispatch( 'core/data' ); const { preview, From 76d2e69db52b642bb4a5de8b354f7533ea19c583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Wed, 19 May 2021 12:09:03 +0200 Subject: [PATCH 09/13] Update tests for changes in core logic (#31982) --- phpunit/class-wp-theme-json-test.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 06b4a7365eec38..81ab493724332d 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -576,7 +576,7 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() 'padding' => array( 'top' => '1px', 'right' => '1px', - 'bottom' => 'var(--unsafe-var-toplevel)', + 'bottom' => 'var(--bottom, var(--unsafe-fallback))', 'left' => '1px', ), ), @@ -586,7 +586,7 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() 'padding' => array( 'top' => '2px', 'right' => '2px', - 'bottom' => 'var(--unsafe-var-elements)', + 'bottom' => 'var(--bottom, var(--unsafe-fallback))', 'left' => '2px', ), ), @@ -598,7 +598,7 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() 'padding' => array( 'top' => '3px', 'right' => '3px', - 'bottom' => 'var(--unsafe-var-block)', + 'bottom' => 'var(bottom, var(--unsafe-fallback))', 'left' => '3px', ), ), @@ -608,7 +608,7 @@ function test_remove_insecure_properties_removes_unsafe_styles_sub_properties() 'padding' => array( 'top' => '4px', 'right' => '4px', - 'bottom' => 'var(--unsafe-var-block-elements)', + 'bottom' => 'var(--bottom, var(--unsafe-fallback))', 'left' => '4px', ), ), @@ -801,7 +801,7 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { array( 'name' => 'Blue', 'slug' => 'blue', - 'color' => 'var(--custom-v1)', + 'color' => 'var(--color, var(--unsafe-fallback))', ), array( 'name' => 'Pink', @@ -830,7 +830,7 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { array( 'name' => 'Helvetica Arial', 'slug' => 'helvetica-arial', - 'fontFamily' => 'var(--custom-var-1)', + 'fontFamily' => 'var(--fontFamily, var(--unsafe-fallback))', ), ), ), @@ -851,7 +851,7 @@ function test_remove_insecure_properties_removes_unsafe_preset_settings() { array( 'name' => 'Blue', 'slug' => 'blue', - 'color' => 'var(--custom-v1)', + 'color' => 'var(--color, var(--unsafe--falback))', ), array( 'name' => 'Pink', From 0cde339626f76726d7f5ceb9af8f6ccb0d81e10c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Mon, 17 May 2021 20:19:58 +0300 Subject: [PATCH 10/13] Non editable blocks: fix selection --- .../components/block-list/use-block-props/use-focus-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js b/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js index ac9e0f8c6d1bdf..6d5c670d075bd1 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js +++ b/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js @@ -42,7 +42,7 @@ export function useFocusHandler( clientId ) { // If an inner block is focussed, that block is resposible for // setting the selected block. - if ( ! isInsideRootBlock( node, event.target ) ) { + if ( isInsideRootBlock( node, event.target ) ) { return; } From aef7222317858e70a002a115e07e769dfef8f534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Mon, 17 May 2021 20:32:58 +0300 Subject: [PATCH 11/13] Avoid class used for alignment wrappers --- .../block-list/use-block-props/use-focus-handler.js | 2 +- packages/block-editor/src/utils/dom.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js b/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js index 6d5c670d075bd1..ac9e0f8c6d1bdf 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js +++ b/packages/block-editor/src/components/block-list/use-block-props/use-focus-handler.js @@ -42,7 +42,7 @@ export function useFocusHandler( clientId ) { // If an inner block is focussed, that block is resposible for // setting the selected block. - if ( isInsideRootBlock( node, event.target ) ) { + if ( ! isInsideRootBlock( node, event.target ) ) { return; } diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js index 3a6db1685aebb1..ee1d04fb9004e1 100644 --- a/packages/block-editor/src/utils/dom.js +++ b/packages/block-editor/src/utils/dom.js @@ -1,6 +1,6 @@ // Consider the block appender to be a child block of its own, which also has -// this class. -const BLOCK_SELECTOR = '.wp-block'; +// this class. Cannot be `.wp-block` because it is used for alignment wrappers. +const BLOCK_SELECTOR = '.block-editor-block-list__block'; /** * Returns true if two elements are contained within the same block. From c3e1221aaa4b2b4e4c5891f9b3d7f879008c208a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 18 May 2021 16:17:09 +0300 Subject: [PATCH 12/13] Always set wp-block class on block --- packages/block-editor/src/components/block-list/block.js | 2 +- .../src/components/block-list/use-block-props/index.js | 1 + packages/block-editor/src/utils/dom.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index d9f24ea630dbf5..53d2d3994c0c08 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -160,7 +160,7 @@ function BlockListBlock( { const value = { clientId, // The wp-block className is important for editor styles. - className: classnames( className, { 'wp-block': ! isAligned } ), + className, wrapperProps: omit( wrapperProps, [ 'data-align' ] ), }; const memoizedValue = useMemo( () => value, Object.values( value ) ); diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js index 479e543da5bc17..eda8fbc2156cf2 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/index.js +++ b/packages/block-editor/src/components/block-list/use-block-props/index.js @@ -138,6 +138,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { 'data-type': name, 'data-title': blockTitle, className: classnames( + 'wp-block', className, props.className, wrapperProps.className, diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js index ee1d04fb9004e1..4ded0f37a26ec4 100644 --- a/packages/block-editor/src/utils/dom.js +++ b/packages/block-editor/src/utils/dom.js @@ -1,6 +1,6 @@ // Consider the block appender to be a child block of its own, which also has // this class. Cannot be `.wp-block` because it is used for alignment wrappers. -const BLOCK_SELECTOR = '.block-editor-block-list__block'; +const BLOCK_SELECTOR = '.wp-block'; /** * Returns true if two elements are contained within the same block. From 0db868d9df98a5a2553f62ea500a73482179edb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Tue, 18 May 2021 22:29:41 +0300 Subject: [PATCH 13/13] Move comment --- packages/block-editor/src/components/block-list/block.js | 1 - .../src/components/block-list/use-block-props/index.js | 3 ++- .../block-list/use-block-props/use-block-class-names.js | 2 +- packages/block-editor/src/utils/dom.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/components/block-list/block.js b/packages/block-editor/src/components/block-list/block.js index 53d2d3994c0c08..0923dcb99adcc0 100644 --- a/packages/block-editor/src/components/block-list/block.js +++ b/packages/block-editor/src/components/block-list/block.js @@ -159,7 +159,6 @@ function BlockListBlock( { const value = { clientId, - // The wp-block className is important for editor styles. className, wrapperProps: omit( wrapperProps, [ 'data-align' ] ), }; diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js index eda8fbc2156cf2..256c73cd0279ac 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/index.js +++ b/packages/block-editor/src/components/block-list/use-block-props/index.js @@ -138,7 +138,8 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { 'data-type': name, 'data-title': blockTitle, className: classnames( - 'wp-block', + // The wp-block className is important for editor styles. + 'wp-block block-editor-block-list__block', className, props.className, wrapperProps.className, diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-block-class-names.js b/packages/block-editor/src/components/block-list/use-block-props/use-block-class-names.js index a7adc7205a408f..c3a99b4ec5e04c 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/use-block-class-names.js +++ b/packages/block-editor/src/components/block-list/use-block-props/use-block-class-names.js @@ -49,7 +49,7 @@ export function useBlockClassNames( clientId ) { const activeEntityBlockId = getActiveBlockIdByBlockNames( spotlightEntityBlocks ); - return classnames( 'block-editor-block-list__block', { + return classnames( { 'is-selected': isSelected, 'is-highlighted': isBlockHighlighted( clientId ), 'is-multi-selected': isBlockMultiSelected( clientId ), diff --git a/packages/block-editor/src/utils/dom.js b/packages/block-editor/src/utils/dom.js index 4ded0f37a26ec4..3a6db1685aebb1 100644 --- a/packages/block-editor/src/utils/dom.js +++ b/packages/block-editor/src/utils/dom.js @@ -1,5 +1,5 @@ // Consider the block appender to be a child block of its own, which also has -// this class. Cannot be `.wp-block` because it is used for alignment wrappers. +// this class. const BLOCK_SELECTOR = '.wp-block'; /**