From 2d1f90e73873fa51b85cad60d0779456640ce301 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 30 Jul 2021 17:59:14 +1000 Subject: [PATCH 01/40] Add a Dropdown block for use in Navigation --- lib/blocks.php | 2 + .../block-library/src/dropdown/block.json | 64 ++ packages/block-library/src/dropdown/edit.js | 644 ++++++++++++++++++ .../block-library/src/dropdown/editor.scss | 11 + packages/block-library/src/dropdown/icons.js | 16 + packages/block-library/src/dropdown/index.js | 24 + packages/block-library/src/dropdown/index.php | 297 ++++++++ packages/block-library/src/dropdown/save.js | 8 + .../block-library/src/dropdown/style.scss | 22 + packages/block-library/src/editor.scss | 1 + packages/block-library/src/index.js | 2 + .../block-library/src/navigation-link/edit.js | 34 +- packages/block-library/src/navigation/edit.js | 1 + .../block-library/src/navigation/editor.scss | 37 +- .../block-library/src/navigation/style.scss | 20 +- packages/block-library/src/style.scss | 1 + 16 files changed, 1130 insertions(+), 54 deletions(-) create mode 100644 packages/block-library/src/dropdown/block.json create mode 100644 packages/block-library/src/dropdown/edit.js create mode 100644 packages/block-library/src/dropdown/editor.scss create mode 100644 packages/block-library/src/dropdown/icons.js create mode 100644 packages/block-library/src/dropdown/index.js create mode 100644 packages/block-library/src/dropdown/index.php create mode 100644 packages/block-library/src/dropdown/save.js create mode 100644 packages/block-library/src/dropdown/style.scss diff --git a/lib/blocks.php b/lib/blocks.php index 77dcaae989b556..08746fcd20af85 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -22,6 +22,7 @@ function gutenberg_reregister_core_block_types() { 'column', 'columns', 'cover', + 'dropdown', 'gallery', 'group', 'heading', @@ -53,6 +54,7 @@ function gutenberg_reregister_core_block_types() { 'block.php' => 'core/block', 'calendar.php' => 'core/calendar', 'categories.php' => 'core/categories', + 'dropdown.php' => 'core/dropdown', 'file.php' => 'core/file', 'latest-comments.php' => 'core/latest-comments', 'latest-posts.php' => 'core/latest-posts', diff --git a/packages/block-library/src/dropdown/block.json b/packages/block-library/src/dropdown/block.json new file mode 100644 index 00000000000000..79b3eec7679f8e --- /dev/null +++ b/packages/block-library/src/dropdown/block.json @@ -0,0 +1,64 @@ +{ + "apiVersion": 2, + "name": "core/dropdown", + "title": "Dropdown", + "category": "design", + "parent": [ + "core/navigation" + ], + "description": "Add a submenu dropdown to your navigation.", + "textdomain": "default", + "attributes": { + "label": { + "type": "string" + }, + "type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "rel": { + "type": "string" + }, + "id": { + "type": "number" + }, + "opensInNewTab": { + "type": "boolean", + "default": false + }, + "url": { + "type": "string" + }, + "title": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "isTopLevelItem": { + "type": "boolean" + } + }, + "usesContext": [ + "textColor", + "customTextColor", + "backgroundColor", + "customBackgroundColor", + "overlayTextColor", + "customOverlayTextColor", + "overlayBackgroundColor", + "customOverlayBackgroundColor", + "fontSize", + "customFontSize", + "showSubmenuIcon", + "style" + ], + "supports": { + "reusable": false, + "html": false + }, + "editorStyle": "wp-block-dropdown-editor", + "style": "wp-block-dropdown" +} diff --git a/packages/block-library/src/dropdown/edit.js b/packages/block-library/src/dropdown/edit.js new file mode 100644 index 00000000000000..bd0ef0be129e88 --- /dev/null +++ b/packages/block-library/src/dropdown/edit.js @@ -0,0 +1,644 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; +import { escape, pull } from 'lodash'; + +/** + * WordPress dependencies + */ +import { createBlock } from '@wordpress/blocks'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { + KeyboardShortcuts, + PanelBody, + Popover, + TextControl, + TextareaControl, + ToolbarButton, + ToolbarGroup, +} from '@wordpress/components'; +import { rawShortcut, displayShortcut } from '@wordpress/keycodes'; +import { __, sprintf } from '@wordpress/i18n'; +import { + BlockControls, + InnerBlocks, + __experimentalUseInnerBlocksProps as useInnerBlocksProps, + InspectorControls, + RichText, + __experimentalLinkControl as LinkControl, + useBlockProps, + store as blockEditorStore, + getColorClassName, +} from '@wordpress/block-editor'; +import { isURL, prependHTTP, safeDecodeURI } from '@wordpress/url'; +import { + Fragment, + useState, + useEffect, + useRef, + createInterpolateElement, +} from '@wordpress/element'; +import { placeCaretAtHorizontalEdge } from '@wordpress/dom'; +import { link as linkIcon } from '@wordpress/icons'; +import { store as coreStore } from '@wordpress/core-data'; +import { speak } from '@wordpress/a11y'; + +/** + * Internal dependencies + */ +import { ItemSubmenuIcon } from './icons'; +import { name } from './block.json'; + +const ALLOWED_BLOCKS = [ 'core/navigation-link', 'core/dropdown' ]; + +const MAX_NESTING = 5; + +/** + * A React hook to determine if it's dragging within the target element. + * + * @typedef {import('@wordpress/element').RefObject} RefObject + * + * @param {RefObject} elementRef The target elementRef object. + * + * @return {boolean} Is dragging within the target element. + */ +const useIsDraggingWithin = ( elementRef ) => { + const [ isDraggingWithin, setIsDraggingWithin ] = useState( false ); + + useEffect( () => { + const { ownerDocument } = elementRef.current; + + function handleDragStart( event ) { + // Check the first time when the dragging starts. + handleDragEnter( event ); + } + + // Set to false whenever the user cancel the drag event by either releasing the mouse or press Escape. + function handleDragEnd() { + setIsDraggingWithin( false ); + } + + function handleDragEnter( event ) { + // Check if the current target is inside the item element. + if ( elementRef.current.contains( event.target ) ) { + setIsDraggingWithin( true ); + } else { + setIsDraggingWithin( false ); + } + } + + // Bind these events to the document to catch all drag events. + // Ideally, we can also use `event.relatedTarget`, but sadly that + // doesn't work in Safari. + ownerDocument.addEventListener( 'dragstart', handleDragStart ); + ownerDocument.addEventListener( 'dragend', handleDragEnd ); + ownerDocument.addEventListener( 'dragenter', handleDragEnter ); + + return () => { + ownerDocument.removeEventListener( 'dragstart', handleDragStart ); + ownerDocument.removeEventListener( 'dragend', handleDragEnd ); + ownerDocument.removeEventListener( 'dragenter', handleDragEnter ); + }; + }, [] ); + + return isDraggingWithin; +}; + +/** + * Given the Link block's type attribute, return the query params to give to + * /wp/v2/search. + * + * @param {string} type Link block's type attribute. + * @param {string} kind Link block's entity of kind (post-type|taxonomy) + * @return {{ type?: string, subtype?: string }} Search query params. + */ +function getSuggestionsQuery( type, kind ) { + switch ( type ) { + case 'post': + case 'page': + return { type: 'post', subtype: type }; + case 'category': + return { type: 'term', subtype: 'category' }; + case 'tag': + return { type: 'term', subtype: 'post_tag' }; + case 'post_format': + return { type: 'post-format' }; + default: + if ( kind === 'taxonomy' ) { + return { type: 'term', subtype: type }; + } + if ( kind === 'post-type' ) { + return { type: 'post', subtype: type }; + } + return {}; + } +} + +/** + * Determine the colors for a menu. + * + * Order of priority is: + * 1: Overlay custom colors (if submenu) + * 2: Overlay theme colors (if submenu) + * 3: Custom colors + * 4: Theme colors + * 5: Global styles + * + * @param {Object} context + * @param {boolean} isSubMenu + */ +function getColors( context, isSubMenu ) { + const { + textColor, + customTextColor, + backgroundColor, + customBackgroundColor, + overlayTextColor, + customOverlayTextColor, + overlayBackgroundColor, + customOverlayBackgroundColor, + style, + } = context; + + const colors = {}; + + if ( isSubMenu && !! customOverlayTextColor ) { + colors.customTextColor = customOverlayTextColor; + } else if ( isSubMenu && !! overlayTextColor ) { + colors.textColor = overlayTextColor; + } else if ( !! customTextColor ) { + colors.customTextColor = customTextColor; + } else if ( !! textColor ) { + colors.textColor = textColor; + } else if ( !! style?.color?.text ) { + colors.customTextColor = style.color.text; + } + + if ( isSubMenu && !! customOverlayBackgroundColor ) { + colors.customBackgroundColor = customOverlayBackgroundColor; + } else if ( isSubMenu && !! overlayBackgroundColor ) { + colors.backgroundColor = overlayBackgroundColor; + } else if ( !! customBackgroundColor ) { + colors.customBackgroundColor = customBackgroundColor; + } else if ( !! backgroundColor ) { + colors.backgroundColor = backgroundColor; + } else if ( !! style?.color?.background ) { + colors.customTextColor = style.color.background; + } + + return colors; +} + +/** + * @typedef {'post-type'|'custom'|'taxonomy'|'post-type-archive'} WPNavigationLinkKind + */ + +/** + * Navigation Link Block Attributes + * + * @typedef {Object} WPNavigationLinkBlockAttributes + * + * @property {string} [label] Link text. + * @property {WPNavigationLinkKind} [kind] Kind is used to differentiate between term and post ids to check post draft status. + * @property {string} [type] The type such as post, page, tag, category and other custom types. + * @property {string} [rel] The relationship of the linked URL. + * @property {number} [id] A post or term id. + * @property {boolean} [opensInNewTab] Sets link target to _blank when true. + * @property {string} [url] Link href. + * @property {string} [title] Link title attribute. + */ + +/** + * Link Control onChange handler that updates block attributes when a setting is changed. + * + * @param {Object} updatedValue New block attributes to update. + * @param {Function} setAttributes Block attribute update function. + * @param {WPNavigationLinkBlockAttributes} blockAttributes Current block attributes. + * + */ +export const updateNavigationLinkBlockAttributes = ( + updatedValue = {}, + setAttributes, + blockAttributes = {} +) => { + const { + label: originalLabel = '', + kind: originalKind = '', + type: originalType = '', + } = blockAttributes; + const { + title = '', + url = '', + opensInNewTab, + id, + kind: newKind = originalKind, + type: newType = originalType, + } = updatedValue; + + const normalizedTitle = title.replace( /http(s?):\/\//gi, '' ); + const normalizedURL = url.replace( /http(s?):\/\//gi, '' ); + const escapeTitle = + title !== '' && + normalizedTitle !== normalizedURL && + originalLabel !== title; + const label = escapeTitle + ? escape( title ) + : originalLabel || escape( normalizedURL ); + + // In https://github.com/WordPress/gutenberg/pull/24670 we decided to use "tag" in favor of "post_tag" + const type = newType === 'post_tag' ? 'tag' : newType.replace( '-', '_' ); + + const isBuiltInType = + [ 'post', 'page', 'tag', 'category' ].indexOf( type ) > -1; + + const isCustomLink = + ( ! newKind && ! isBuiltInType ) || newKind === 'custom'; + const kind = isCustomLink ? 'custom' : newKind; + + setAttributes( { + // Passed `url` may already be encoded. To prevent double encoding, decodeURI is executed to revert to the original string. + ...( url && { url: encodeURI( safeDecodeURI( url ) ) } ), + ...( label && { label } ), + ...( undefined !== opensInNewTab && { opensInNewTab } ), + ...( id && Number.isInteger( id ) && { id } ), + ...( kind && { kind } ), + ...( type && type !== 'URL' && { type } ), + } ); +}; + +export default function DropdownEdit( { + attributes, + isSelected, + setAttributes, + insertBlocksAfter, + mergeBlocks, + onReplace, + context, + clientId, +} ) { + const { + label, + type, + opensInNewTab, + url, + description, + rel, + title, + kind, + } = attributes; + const link = { + url, + opensInNewTab, + }; + const { showSubmenuIcon } = context; + const { saveEntityRecord } = useDispatch( coreStore ); + const [ isLinkOpen, setIsLinkOpen ] = useState( false ); + const listItemRef = useRef( null ); + const isDraggingWithin = useIsDraggingWithin( listItemRef ); + const itemLabelPlaceholder = __( 'Add text…' ); + const ref = useRef(); + + const { + isAtMaxNesting, + isTopLevelItem, + isParentOfSelectedBlock, + isImmediateParentOfSelectedBlock, + hasDescendants, + selectedBlockHasDescendants, + userCanCreatePages, + userCanCreatePosts, + } = useSelect( + ( select ) => { + const { + getClientIdsOfDescendants, + hasSelectedInnerBlock, + getSelectedBlockClientId, + getBlockParentsByBlockName, + } = select( blockEditorStore ); + + const selectedBlockId = getSelectedBlockClientId(); + + const descendants = getClientIdsOfDescendants( [ clientId ] ) + .length; + + return { + isAtMaxNesting: + getBlockParentsByBlockName( clientId, name ).length >= + MAX_NESTING, + isTopLevelItem: + getBlockParentsByBlockName( clientId, name ).length === 0, + isParentOfSelectedBlock: hasSelectedInnerBlock( + clientId, + true + ), + isImmediateParentOfSelectedBlock: hasSelectedInnerBlock( + clientId, + false + ), + hasDescendants: !! descendants, + selectedBlockHasDescendants: !! getClientIdsOfDescendants( [ + selectedBlockId, + ] )?.length, + userCanCreatePages: select( coreStore ).canUser( + 'create', + 'pages' + ), + userCanCreatePosts: select( coreStore ).canUser( + 'create', + 'posts' + ), + }; + }, + [ clientId ] + ); + + // Store the colors from context as attributes for rendering + useEffect( () => setAttributes( { isTopLevelItem } ), [ isTopLevelItem ] ); + + /** + * The hook shouldn't be necessary but due to a focus loss happening + * when selecting a suggestion in the link popover, we force close on block unselection. + */ + useEffect( () => { + if ( ! isSelected ) { + setIsLinkOpen( false ); + } + }, [ isSelected ] ); + + // If the LinkControl popover is open and the URL has changed, close the LinkControl and focus the label text. + useEffect( () => { + if ( isLinkOpen && url ) { + // Does this look like a URL and have something TLD-ish? + if ( + isURL( prependHTTP( label ) ) && + /^.+\.[a-z]+/.test( label ) + ) { + // Focus and select the label text. + selectLabelText(); + } else { + // Focus it (but do not select). + placeCaretAtHorizontalEdge( ref.current, true ); + } + } + }, [ url ] ); + + /** + * Focus the Link label text and select it. + */ + function selectLabelText() { + ref.current.focus(); + const { ownerDocument } = ref.current; + const { defaultView } = ownerDocument; + const selection = defaultView.getSelection(); + const range = ownerDocument.createRange(); + // Get the range of the current ref contents so we can add this range to the selection. + range.selectNodeContents( ref.current ); + selection.removeAllRanges(); + selection.addRange( range ); + } + + let userCanCreate = false; + if ( ! type || type === 'page' ) { + userCanCreate = userCanCreatePages; + } else if ( type === 'post' ) { + userCanCreate = userCanCreatePosts; + } + + async function handleCreate( pageTitle ) { + const postType = type || 'page'; + + const page = await saveEntityRecord( 'postType', postType, { + title: pageTitle, + status: 'draft', + } ); + + return { + id: page.id, + type: postType, + title: page.title.rendered, + url: page.link, + kind: 'post-type', + }; + } + + const { + textColor, + customTextColor, + backgroundColor, + customBackgroundColor, + } = getColors( context, ! isTopLevelItem ); + + const blockProps = useBlockProps( { + ref: listItemRef, + className: classnames( { + 'is-editing': isSelected || isParentOfSelectedBlock, + 'is-dragging-within': isDraggingWithin, + 'has-link': !! url, + 'has-child': hasDescendants, + 'has-text-color': !! textColor || !! customTextColor, + [ getColorClassName( 'color', textColor ) ]: !! textColor, + 'has-background': !! backgroundColor || customBackgroundColor, + [ getColorClassName( + 'background-color', + backgroundColor + ) ]: !! backgroundColor, + } ), + style: { + color: ! textColor && customTextColor, + backgroundColor: ! backgroundColor && customBackgroundColor, + }, + } ); + + // Always use overlay colors for submenus + const innerBlocksColors = getColors( context, true ); + + if ( isAtMaxNesting ) { + pull( ALLOWED_BLOCKS, 'core/dropdown' ); + } + + const innerBlocksProps = useInnerBlocksProps( + { + className: classnames( 'wp-block-dropdown__container', { + 'is-parent-of-selected-block': isParentOfSelectedBlock, + 'has-text-color': !! ( + innerBlocksColors.textColor || + innerBlocksColors.customTextColor + ), + [ `has-${ innerBlocksColors.textColor }-color` ]: !! innerBlocksColors.textColor, + 'has-background': !! ( + innerBlocksColors.backgroundColor || + innerBlocksColors.customBackgroundColor + ), + [ `has-${ innerBlocksColors.backgroundColor }-background-color` ]: !! innerBlocksColors.backgroundColor, + } ), + style: { + color: innerBlocksColors.customTextColor, + backgroundColor: innerBlocksColors.customBackgroundColor, + }, + }, + { + allowedBlocks: ALLOWED_BLOCKS, + renderAppender: + isSelected || + ( isImmediateParentOfSelectedBlock && + ! selectedBlockHasDescendants ) || + // Show the appender while dragging to allow inserting element between item and the appender. + hasDescendants + ? InnerBlocks.DefaultAppender + : false, + } + ); + + const ParentElement = url ? 'a' : 'button'; + + return ( + + + + + setIsLinkOpen( true ), + } } + /> + setIsLinkOpen( true ) } + /> + + + + + { + setAttributes( { + description: descriptionValue, + } ); + } } + label={ __( 'Description' ) } + help={ __( + 'The description will be displayed in the menu if the current theme supports it.' + ) } + /> + { + setAttributes( { title: titleValue } ); + } } + label={ __( 'Link title' ) } + autoComplete="off" + /> + { + setAttributes( { rel: relValue } ); + } } + label={ __( 'Link rel' ) } + autoComplete="off" + /> + + +
+ { /* eslint-disable jsx-a11y/anchor-is-valid */ } + + { /* eslint-enable */ } + { + + setAttributes( { label: labelValue } ) + } + onMerge={ mergeBlocks } + onReplace={ onReplace } + __unstableOnSplitAtEnd={ () => + insertBlocksAfter( + createBlock( 'core/navigation-link' ) + ) + } + aria-label={ __( 'Navigation link text' ) } + placeholder={ itemLabelPlaceholder } + withoutInteractiveFormatting + allowedFormats={ [ + 'core/bold', + 'core/italic', + 'core/image', + 'core/strikethrough', + ] } + /> + } + { isLinkOpen && ( + setIsLinkOpen( false ) } + anchorRef={ listItemRef.current } + > + setIsLinkOpen( false ), + } } + /> + { + let format; + if ( type === 'post' ) { + /* translators: %s: search term. */ + format = __( + 'Create draft post: %s' + ); + } else { + /* translators: %s: search term. */ + format = __( + 'Create draft page: %s' + ); + } + return createInterpolateElement( + sprintf( format, searchTerm ), + { mark: } + ); + } } + noDirectEntry={ !! type } + noURLSuggestion={ !! type } + suggestionsQuery={ getSuggestionsQuery( + type, + kind + ) } + onChange={ ( updatedValue ) => + updateNavigationLinkBlockAttributes( + updatedValue, + setAttributes, + attributes + ) + } + onRemove={ () => { + setAttributes( { url: '' } ); + speak( __( 'Link removed.' ), 'assertive' ); + } } + /> + + ) } + { showSubmenuIcon && ( + + + + ) } + +
+
+ + ); +} diff --git a/packages/block-library/src/dropdown/editor.scss b/packages/block-library/src/dropdown/editor.scss new file mode 100644 index 00000000000000..b8159044009cc5 --- /dev/null +++ b/packages/block-library/src/dropdown/editor.scss @@ -0,0 +1,11 @@ +.wp-block-dropdown { + // Show on editor selected, even if on frontend it only stays open on focus-within. + &.is-selected, + &.has-child-selected { + > .wp-block-dropdown__container { + // We use important here because if the parent block is selected and submenus are present, they should always be visible. + visibility: visible !important; + opacity: 1 !important; + } + } +} diff --git a/packages/block-library/src/dropdown/icons.js b/packages/block-library/src/dropdown/icons.js new file mode 100644 index 00000000000000..3a44a250b084ef --- /dev/null +++ b/packages/block-library/src/dropdown/icons.js @@ -0,0 +1,16 @@ +/** + * WordPress dependencies + */ +import { Path, SVG } from '@wordpress/components'; + +export const ItemSubmenuIcon = () => ( + + + +); diff --git a/packages/block-library/src/dropdown/index.js b/packages/block-library/src/dropdown/index.js new file mode 100644 index 00000000000000..31bbe5517cc09a --- /dev/null +++ b/packages/block-library/src/dropdown/index.js @@ -0,0 +1,24 @@ +/** + * WordPress dependencies + */ +import { addSubmenu } from '@wordpress/icons'; + +/** + * Internal dependencies + */ + +import metadata from './block.json'; +import edit from './edit'; +import save from './save'; + +const { name } = metadata; + +export { metadata, name }; + +export const settings = { + icon: addSubmenu, + + edit, + + save, +}; diff --git a/packages/block-library/src/dropdown/index.php b/packages/block-library/src/dropdown/index.php new file mode 100644 index 00000000000000..303a1a88037978 --- /dev/null +++ b/packages/block-library/src/dropdown/index.php @@ -0,0 +1,297 @@ + array(), + 'inline_styles' => '', + ); + + $is_sub_menu = isset( $attributes['isTopLevelLink'] ) ? ( ! $attributes['isTopLevelLink'] ) : false; + + // Text color. + $named_text_color = null; + $custom_text_color = null; + + if ( $is_sub_menu && array_key_exists( 'customOverlayTextColor', $context ) ) { + $custom_text_color = $context['customOverlayTextColor']; + } elseif ( $is_sub_menu && array_key_exists( 'overlayTextColor', $context ) ) { + $named_text_color = $context['overlayTextColor']; + } elseif ( array_key_exists( 'customTextColor', $context ) ) { + $custom_text_color = $context['customTextColor']; + } elseif ( array_key_exists( 'textColor', $context ) ) { + $named_text_color = $context['textColor']; + } elseif ( isset( $context['style']['color']['text'] ) ) { + $custom_text_color = $context['style']['color']['text']; + } + + // If has text color. + if ( ! is_null( $named_text_color ) ) { + // Add the color class. + array_push( $colors['css_classes'], 'has-text-color', sprintf( 'has-%s-color', $named_text_color ) ); + } elseif ( ! is_null( $custom_text_color ) ) { + // Add the custom color inline style. + $colors['css_classes'][] = 'has-text-color'; + $colors['inline_styles'] .= sprintf( 'color: %s;', $custom_text_color ); + } + + // Background color. + $named_background_color = null; + $custom_background_color = null; + + if ( $is_sub_menu && array_key_exists( 'customOverlayBackgroundColor', $context ) ) { + $custom_background_color = $context['customOverlayBackgroundColor']; + } elseif ( $is_sub_menu && array_key_exists( 'overlayBackgroundColor', $context ) ) { + $named_background_color = $context['overlayBackgroundColor']; + } elseif ( array_key_exists( 'customBackgroundColor', $context ) ) { + $custom_background_color = $context['customBackgroundColor']; + } elseif ( array_key_exists( 'backgroundColor', $context ) ) { + $named_background_color = $context['backgroundColor']; + } elseif ( isset( $context['style']['color']['background'] ) ) { + $custom_background_color = $context['style']['color']['background']; + } + + // If has background color. + if ( ! is_null( $named_background_color ) ) { + // Add the background-color class. + array_push( $colors['css_classes'], 'has-background', sprintf( 'has-%s-background-color', $named_background_color ) ); + } elseif ( ! is_null( $custom_background_color ) ) { + // Add the custom background-color inline style. + $colors['css_classes'][] = 'has-background'; + $colors['inline_styles'] .= sprintf( 'background-color: %s;', $custom_background_color ); + } + + return $colors; +} + +/** + * Build an array with CSS classes and inline styles defining the font sizes + * which will be applied to the navigation markup in the front-end. + * + * @param array $context Navigation block context. + * @return array Font size CSS classes and inline styles. + */ +function block_core_dropdown_build_css_font_sizes( $context ) { + // CSS classes. + $font_sizes = array( + 'css_classes' => array(), + 'inline_styles' => '', + ); + + $has_named_font_size = array_key_exists( 'fontSize', $context ); + $has_custom_font_size = isset( $context['style']['typography']['fontSize'] ); + + if ( $has_named_font_size ) { + // Add the font size class. + $font_sizes['css_classes'][] = sprintf( 'has-%s-font-size', $context['fontSize'] ); + } elseif ( $has_custom_font_size ) { + // Add the custom font size inline style. + $font_sizes['inline_styles'] = sprintf( 'font-size: %spx;', $context['style']['typography']['fontSize'] ); + } + + return $font_sizes; +} + +/** + * Returns the top-level submenu SVG chevron icon. + * + * @return string + */ +function block_core_dropdown_render_submenu_icon() { + return ''; +} + +/** + * Renders the `core/dropdown` block. + * + * @param array $attributes The block attributes. + * @param array $content The saved content. + * @param array $block The parsed block. + * + * @return string Returns the post content with the legacy widget added. + */ +function render_block_core_dropdown( $attributes, $content, $block ) { + $navigation_link_has_id = isset( $attributes['id'] ) && is_numeric( $attributes['id'] ); + $is_post_type = isset( $attributes['kind'] ) && 'post-type' === $attributes['kind']; + $is_post_type = $is_post_type || isset( $attributes['type'] ) && ( 'post' === $attributes['type'] || 'page' === $attributes['type'] ); + + // Don't render the block's subtree if it is a draft. + if ( $is_post_type && $navigation_link_has_id ) { + $post = get_post( $attributes['id'] ); + if ( 'publish' !== $post->post_status ) { + return ''; + } + } + + // Don't render the block's subtree if it has no label. + if ( empty( $attributes['label'] ) ) { + return ''; + } + + $colors = block_core_dropdown_build_css_colors( $block->context, $attributes ); + $font_sizes = block_core_dropdown_build_css_font_sizes( $block->context ); + $classes = array_merge( + $colors['css_classes'], + $font_sizes['css_classes'] + ); + $style_attribute = ( $colors['inline_styles'] . $font_sizes['inline_styles'] ); + + $css_classes = trim( implode( ' ', $classes ) ); + $has_submenu = count( $block->inner_blocks ) > 0; + $is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === $attributes['id'] ); + + $class_name = ! empty( $attributes['className'] ) ? implode( ' ', (array) $attributes['className'] ) : false; + + if ( false !== $class_name ) { + $css_classes .= ' ' . $class_name; + } + + $wrapper_attributes = get_block_wrapper_attributes( + array( + 'class' => $css_classes . ( $has_submenu ? ' has-child' : '' ) . + ( $is_active ? ' current-menu-item' : '' ), + 'style' => $style_attribute, + ) + ); + $html = '
  • '; + + // If the Parent element is a link, we render an anchor tag with attributes. + // We also render a submenu button, so the submenu can be opened on click. + if ( isset( $attributes['url'] ) && '' !== $attributes['url'] ) { + // Start appending HTML attributes to anchor tag. + $html .= ' array(), + 'em' => array(), + 'img' => array( + 'scale' => array(), + 'class' => array(), + 'style' => array(), + 'src' => array(), + 'alt' => array(), + ), + 's' => array(), + 'span' => array( + 'style' => array(), + ), + 'strong' => array(), + ) + ); + } + + $html .= ''; + // End anchor tag content. + + // The submenu icon has to be rendered in a button here + // so that there's a clickable elment to open the submenu. + $html .= ''; + + } else { + // If the Parent element is not a link, we render the whole thing as a button. + $html .= ''; + + } + + + + + + if ( $has_submenu ) { + $inner_blocks_html = ''; + foreach ( $block->inner_blocks as $inner_block ) { + $inner_blocks_html .= $inner_block->render(); + } + + $html .= sprintf( + '
      %s
    ', + $inner_blocks_html + ); + } + + $html .= '
  • '; + + return $html; +} + +/** + * Register the dropdown block. + * + * @uses render_block_core_navigation() + * @throws WP_Error An WP_Error exception parsing the block definition. + */ +function register_block_core_dropdown() { + register_block_type_from_metadata( + __DIR__ . '/dropdown', + array( + 'render_callback' => 'render_block_core_dropdown', + ) + ); +} +add_action( 'init', 'register_block_core_dropdown' ); diff --git a/packages/block-library/src/dropdown/save.js b/packages/block-library/src/dropdown/save.js new file mode 100644 index 00000000000000..17571d8f30d2de --- /dev/null +++ b/packages/block-library/src/dropdown/save.js @@ -0,0 +1,8 @@ +/** + * WordPress dependencies + */ +import { InnerBlocks } from '@wordpress/block-editor'; + +export default function save() { + return ; +} diff --git a/packages/block-library/src/dropdown/style.scss b/packages/block-library/src/dropdown/style.scss new file mode 100644 index 00000000000000..7978e5163aa809 --- /dev/null +++ b/packages/block-library/src/dropdown/style.scss @@ -0,0 +1,22 @@ +.wp-block-dropdown { + position: relative; + display: flex; + + button.wp-block-dropdown__submenu-icon.wp-block-dropdown__submenu-icon.wp-block-dropdown__submenu-icon.wp-block-dropdown__submenu-icon { + padding: $grid-unit $grid-unit-20; + background-color: inherit; + color: currentColor; + border: none; + } + + .wp-block-dropdown__submenu-icon svg { + stroke: currentColor; + } + + // Custom menu items. + // Show submenus on hover. + &:hover > .wp-block-dropdown__container { + visibility: visible; + opacity: 1; + } +} diff --git a/packages/block-library/src/editor.scss b/packages/block-library/src/editor.scss index b1919397804a24..2a58a3e19c112d 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -6,6 +6,7 @@ @import "./categories/editor.scss"; @import "./columns/editor.scss"; @import "./cover/editor.scss"; +@import "./dropdown/editor.scss"; @import "./embed/editor.scss"; @import "./file/editor.scss"; @import "./freeform/editor.scss"; diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index da7fcacc8cadff..333fc1773c3948 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -27,6 +27,7 @@ import * as code from './code'; import * as columns from './columns'; import * as column from './column'; import * as cover from './cover'; +import * as dropdown from './dropdown'; import * as embed from './embed'; import * as file from './file'; import * as html from './html'; @@ -231,6 +232,7 @@ export const __experimentalRegisterExperimentalCoreBlocks = navigation, navigationLink, homeLink, + dropdown, // Register Full Site Editing Blocks. ...( enableFSEBlocks diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index fce0a339b2e252..fce6970ffb17a8 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -39,7 +39,7 @@ import { createInterpolateElement, } from '@wordpress/element'; import { placeCaretAtHorizontalEdge } from '@wordpress/dom'; -import { link as linkIcon, addSubmenu } from '@wordpress/icons'; +import { link as linkIcon } from '@wordpress/icons'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -50,8 +50,6 @@ import { name } from './block.json'; const ALLOWED_BLOCKS = [ 'core/navigation-link' ]; -const MAX_NESTING = 5; - /** * A React hook to determine if it's dragging within the target element. * @@ -291,10 +289,9 @@ export default function NavigationLinkEdit( { }; const { showSubmenuIcon } = context; const { saveEntityRecord } = useDispatch( coreStore ); - const { - insertBlock, - __unstableMarkNextChangeAsNotPersistent, - } = useDispatch( blockEditorStore ); + const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( + blockEditorStore + ); const [ isLinkOpen, setIsLinkOpen ] = useState( false ); const listItemRef = useRef( null ); const isDraggingWithin = useIsDraggingWithin( listItemRef ); @@ -302,13 +299,11 @@ export default function NavigationLinkEdit( { const ref = useRef(); const { - isAtMaxNesting, isTopLevelLink, isParentOfSelectedBlock, isImmediateParentOfSelectedBlock, hasDescendants, selectedBlockHasDescendants, - numberOfDescendants, userCanCreatePages, userCanCreatePosts, } = useSelect( @@ -326,9 +321,6 @@ export default function NavigationLinkEdit( { .length; return { - isAtMaxNesting: - getBlockParentsByBlockName( clientId, name ).length >= - MAX_NESTING, isTopLevelLink: getBlockParentsByBlockName( clientId, name ).length === 0, isParentOfSelectedBlock: hasSelectedInnerBlock( @@ -343,7 +335,6 @@ export default function NavigationLinkEdit( { selectedBlockHasDescendants: !! getClientIdsOfDescendants( [ selectedBlockId, ] )?.length, - numberOfDescendants: descendants, userCanCreatePages: select( coreStore ).canUser( 'create', 'pages' @@ -366,15 +357,6 @@ export default function NavigationLinkEdit( { setAttributes( { isTopLevelLink } ); }, [ isTopLevelLink ] ); - /** - * Insert a link block when submenu is added. - */ - function insertLinkBlock() { - const insertionPoint = numberOfDescendants; - const blockToInsert = createBlock( 'core/navigation-link' ); - insertBlock( blockToInsert, insertionPoint, clientId ); - } - // Show the LinkControl on mount if the URL is empty // ( When adding a new menu item) // This can't be done in the useState call because it conflicts @@ -591,14 +573,6 @@ export default function NavigationLinkEdit( { shortcut={ displayShortcut.primary( 'k' ) } onClick={ () => setIsLinkOpen( true ) } /> - { ! isAtMaxNesting && ( - - ) } diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index f5d7a1c44f6563..55258bc4d12123 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -48,6 +48,7 @@ const ALLOWED_BLOCKS = [ 'core/home-link', 'core/site-title', 'core/site-logo', + 'core/dropdown', ]; const LAYOUT = { diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index ba4212cf67777c..abbef77d9c3308 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -25,7 +25,6 @@ display: inline-block; } - /** * Submenus. */ @@ -43,7 +42,8 @@ } // Only show the flyout on hover if the parent menu item is selected. -.wp-block-navigation:not(.is-selected):not(.has-child-selected) .has-child:hover { +.wp-block-navigation:not(.is-selected):not(.has-child-selected) +.has-child:hover { > .wp-block-navigation__submenu-container { opacity: 0; visibility: hidden; @@ -79,7 +79,8 @@ flex-direction: column; } -.is-dragging-components-draggable .wp-block-navigation-link > .wp-block-navigation__container { +.is-dragging-components-draggable +.wp-block-navigation-link > .wp-block-navigation__container { // Set opacity to 1 to still be able to show the draggable chip. opacity: 1; visibility: hidden; @@ -173,7 +174,6 @@ $color-control-label-height: 20px; justify-content: flex-start; } - /** * Setup state */ @@ -243,7 +243,6 @@ $color-control-label-height: 20px; } } - .wp-block-navigation-item.wp-block-navigation-item, .wp-block-navigation-placeholder__preview-search-icon { opacity: 0.3; @@ -355,7 +354,9 @@ $color-control-label-height: 20px; .is-vertical .wp-block-navigation-placeholder, .is-vertical .wp-block-navigation-placeholder__preview, .is-vertical .wp-block-navigation-placeholder__controls { - min-height: $icon-size + ($grid-unit-20 + $grid-unit-05 + $grid-unit-15 + $grid-unit-15) * 3; + min-height: + $icon-size + + ( $grid-unit-20 + $grid-unit-05 + $grid-unit-15 + $grid-unit-15 ) * 3; } .is-vertical .wp-block-navigation-placeholder__preview, @@ -370,7 +371,9 @@ $color-control-label-height: 20px; font-family: $default-font; .components-button.components-dropdown-menu__toggle.has-icon { - padding: ($grid-unit-15 * 0.5) $grid-unit-05 ($grid-unit-15 * 0.5) $grid-unit-15; + padding: + ( $grid-unit-15 * 0.5 ) $grid-unit-05 ( $grid-unit-15 * 0.5 ) + $grid-unit-15; display: flex; flex-direction: row-reverse; // This puts the chevron, which is hidden from screen readers, on the right. } @@ -382,7 +385,6 @@ $color-control-label-height: 20px; } } - /** * Mobile menu. */ @@ -407,7 +409,9 @@ $color-control-label-height: 20px; // When not fullscreen. .wp-block-navigation__responsive-container.is-menu-open { position: fixed; - top: $admin-bar-height-big + $header-height + $block-toolbar-height + $border-width; + top: + $admin-bar-height-big + $header-height + $block-toolbar-height + + $border-width; @include break-medium() { top: $admin-bar-height + $header-height + $border-width; @@ -424,13 +428,17 @@ $color-control-label-height: 20px; .has-fixed-toolbar .wp-block-navigation__responsive-container.is-menu-open { @include break-medium() { - top: $admin-bar-height + $header-height + $block-toolbar-height + $border-width; + top: + $admin-bar-height + $header-height + $block-toolbar-height + + $border-width; } } .is-mobile-preview .wp-block-navigation__responsive-container.is-menu-open, .is-tablet-preview .wp-block-navigation__responsive-container.is-menu-open { - top: $admin-bar-height + $header-height + $block-toolbar-height + $border-width; + top: + $admin-bar-height + $header-height + $block-toolbar-height + + $border-width; } .is-sidebar-opened .wp-block-navigation__responsive-container.is-menu-open { @@ -441,7 +449,9 @@ $color-control-label-height: 20px; .is-fullscreen-mode { .wp-block-navigation__responsive-container.is-menu-open { left: 0; // Unset the value from non fullscreen mode. - top: $admin-bar-height-big + $header-height + $block-toolbar-height + $border-width; + top: + $admin-bar-height-big + $header-height + $block-toolbar-height + + $border-width; @include break-medium() { top: $header-height + $border-width; @@ -461,7 +471,8 @@ $color-control-label-height: 20px; } // The iframe makes these rules a lot simpler. -body.editor-styles-wrapper .wp-block-navigation__responsive-container.is-menu-open { +body.editor-styles-wrapper +.wp-block-navigation__responsive-container.is-menu-open { top: 0; right: 0; bottom: 0; diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss index 379ac1ee403e72..ad59a993e8768e 100644 --- a/packages/block-library/src/navigation/style.scss +++ b/packages/block-library/src/navigation/style.scss @@ -92,7 +92,6 @@ } } - // Styles for submenu flyout. // These are separated out with reduced specificity to allow better inheritance from Global Styles. .wp-block-navigation .has-child { @@ -167,7 +166,6 @@ } } - // Separating out hover and focus-within so hover works again on IE: https://davidwalsh.name/css-focus-within#comment-513401 // We will need to replace focus-within with a JS solution for IE keyboard support. @@ -192,7 +190,9 @@ } // Submenu indentation when there's a background. -.wp-block-navigation.has-background .has-child .wp-block-navigation__submenu-container { +.wp-block-navigation.has-background +.has-child +.wp-block-navigation__submenu-container { left: 0; top: 100%; @@ -205,7 +205,6 @@ } } - /** * Margins */ @@ -227,7 +226,6 @@ } } - /** * Paddings */ @@ -252,7 +250,6 @@ padding: 0.5em 1em; } - /** * Justifications. */ @@ -260,11 +257,12 @@ // When justified space-between, open submenus leftward for last menu item. // When justified right, open all submenus leftwards. // This needs high specificity. -.wp-block-navigation.items-justified-space-between .wp-block-page-list > .has-child:last-child, +.wp-block-navigation.items-justified-space-between +.wp-block-page-list > .has-child:last-child, .wp-block-navigation.items-justified-space-between > .wp-block-navigation__container > .has-child:last-child, .wp-block-navigation.items-justified-right .wp-block-page-list > .has-child, -.wp-block-navigation.items-justified-right > .wp-block-navigation__container .has-child { - +.wp-block-navigation.items-justified-right > .wp-block-navigation__container +.has-child { // First submenu. .wp-block-navigation__submenu-container { left: auto; @@ -348,7 +346,6 @@ } } - /** * Mobile menu. */ @@ -429,7 +426,8 @@ } // Default menu background and font color. -.wp-block-navigation:not(.has-background) .wp-block-navigation__responsive-container.is-menu-open { +.wp-block-navigation:not(.has-background) +.wp-block-navigation__responsive-container.is-menu-open { background-color: #fff; color: #000; } diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index 8c3b5dc1317491..c2415905e48df8 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -7,6 +7,7 @@ @import "./code/style.scss"; @import "./columns/style.scss"; @import "./cover/style.scss"; +@import "./dropdown/style.scss"; @import "./embed/style.scss"; @import "./file/style.scss"; @import "./gallery/style.scss"; From 78210841c4b291d1bdb842464f3d7d25a2bf66eb Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 30 Jul 2021 18:18:48 +1000 Subject: [PATCH 02/40] display dropdowns below buttons in editor --- packages/block-library/src/dropdown/editor.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-library/src/dropdown/editor.scss b/packages/block-library/src/dropdown/editor.scss index b8159044009cc5..7f85e377ecac49 100644 --- a/packages/block-library/src/dropdown/editor.scss +++ b/packages/block-library/src/dropdown/editor.scss @@ -1,4 +1,6 @@ .wp-block-dropdown { + display: block; + // Show on editor selected, even if on frontend it only stays open on focus-within. &.is-selected, &.has-child-selected { From ab180c9f95523983862f5274f738a154928ea67a Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 5 Aug 2021 17:35:25 +1000 Subject: [PATCH 03/40] Add open on click functionality. --- .../block-library/src/dropdown/block.json | 1 + packages/block-library/src/dropdown/index.php | 12 ++++---- .../block-library/src/dropdown/style.scss | 6 ++-- packages/block-library/src/dropdown/view.js | 29 +++++++++++++++++++ 4 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 packages/block-library/src/dropdown/view.js diff --git a/packages/block-library/src/dropdown/block.json b/packages/block-library/src/dropdown/block.json index 79b3eec7679f8e..b497426368cbd8 100644 --- a/packages/block-library/src/dropdown/block.json +++ b/packages/block-library/src/dropdown/block.json @@ -59,6 +59,7 @@ "reusable": false, "html": false }, + "viewScript": "file:./view.min.js", "editorStyle": "wp-block-dropdown-editor", "style": "wp-block-dropdown" } diff --git a/packages/block-library/src/dropdown/index.php b/packages/block-library/src/dropdown/index.php index 303a1a88037978..3d0a24df875e2a 100644 --- a/packages/block-library/src/dropdown/index.php +++ b/packages/block-library/src/dropdown/index.php @@ -123,6 +123,10 @@ function block_core_dropdown_render_submenu_icon() { * @return string Returns the post content with the legacy widget added. */ function render_block_core_dropdown( $attributes, $content, $block ) { + if ( ! wp_script_is( 'wp-block-dropdown-view' ) ) { + wp_enqueue_script( 'wp-block-dropdown-view' ); + } + $navigation_link_has_id = isset( $attributes['id'] ) && is_numeric( $attributes['id'] ); $is_post_type = isset( $attributes['kind'] ) && 'post-type' === $attributes['kind']; $is_post_type = $is_post_type || isset( $attributes['type'] ) && ( 'post' === $attributes['type'] || 'page' === $attributes['type'] ); @@ -217,11 +221,11 @@ function render_block_core_dropdown( $attributes, $content, $block ) { // The submenu icon has to be rendered in a button here // so that there's a clickable elment to open the submenu. - $html .= ''; + $html .= ''; } else { // If the Parent element is not a link, we render the whole thing as a button. - $html .= ''; } else { // If the Parent element is not a link, we render the whole thing as a button. - $html .= ''; @@ -270,7 +270,7 @@ function render_block_core_dropdown( $attributes, $content, $block ) { } $html .= sprintf( - '
      %s
    ', + '
      %s
    ', $inner_blocks_html ); } @@ -281,17 +281,17 @@ function render_block_core_dropdown( $attributes, $content, $block ) { } /** - * Register the dropdown block. + * Register the navigation submenu block. * - * @uses render_block_core_navigation() + * @uses render_block_core_navigation_submenu() * @throws WP_Error An WP_Error exception parsing the block definition. */ -function register_block_core_dropdown() { +function register_block_core_navigation_submenu() { register_block_type_from_metadata( - __DIR__ . '/dropdown', + __DIR__ . '/navigation-submenu', array( - 'render_callback' => 'render_block_core_dropdown', + 'render_callback' => 'render_block_core_navigation_submenu', ) ); } -add_action( 'init', 'register_block_core_dropdown' ); +add_action( 'init', 'register_block_core_navigation_submenu' ); diff --git a/packages/block-library/src/dropdown/save.js b/packages/block-library/src/navigation-submenu/save.js similarity index 100% rename from packages/block-library/src/dropdown/save.js rename to packages/block-library/src/navigation-submenu/save.js diff --git a/packages/block-library/src/navigation-submenu/style.scss b/packages/block-library/src/navigation-submenu/style.scss new file mode 100644 index 00000000000000..9a9aa9844f973d --- /dev/null +++ b/packages/block-library/src/navigation-submenu/style.scss @@ -0,0 +1,22 @@ +.wp-block-navigation-submenu { + position: relative; + display: flex; + + button.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon.wp-block-navigation__submenu-icon { + padding: $grid-unit $grid-unit-20; + background-color: inherit; + color: currentColor; + border: none; + } + + .wp-block-navigation__submenu-icon svg { + stroke: currentColor; + } + + // Show submenus on hover and on click. + &:hover > .wp-block-navigation__submenu-container, + .wp-block-navigation-submenu__toggle[aria-expanded="true"] + .wp-block-navigation__submenu-container { + visibility: visible; + opacity: 1; + } +} diff --git a/packages/block-library/src/dropdown/view.js b/packages/block-library/src/navigation-submenu/view.js similarity index 77% rename from packages/block-library/src/dropdown/view.js rename to packages/block-library/src/navigation-submenu/view.js index 3dfb7939913609..84edfe182feccf 100644 --- a/packages/block-library/src/dropdown/view.js +++ b/packages/block-library/src/navigation-submenu/view.js @@ -11,12 +11,14 @@ const toggleSubmenuOnClick = ( event ) => { const isSubmenuOpen = buttonToggle.getAttribute( 'aria-expanded' ); if ( isSubmenuOpen === 'true' ) { - closeSubmenus( buttonToggle.closest( '.wp-block-dropdown' ) ); + closeSubmenus( buttonToggle.closest( '.wp-block-navigation-submenu' ) ); } else { // Close all sibling submenus. - const parentElement = buttonToggle.closest( '.wp-block-dropdown' ); + const parentElement = buttonToggle.closest( + '.wp-block-navigation-submenu' + ); const parentList = - buttonToggle.closest( '.wp-block-dropdown__container' ) || + buttonToggle.closest( '.wp-block-navigation__submenu-container' ) || buttonToggle.closest( '.wp-block-navigation__container' ); Array.from( parentList.children ).forEach( ( child ) => { if ( child !== parentElement ) { @@ -28,11 +30,11 @@ const toggleSubmenuOnClick = ( event ) => { } }; -const dropdownButtons = document.querySelectorAll( - '.wp-block-dropdown__toggle' +const submenuButtons = document.querySelectorAll( + '.wp-block-navigation-submenu__toggle' ); -dropdownButtons.forEach( ( button ) => { +submenuButtons.forEach( ( button ) => { button.addEventListener( 'click', toggleSubmenuOnClick ); } ); diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index 55258bc4d12123..baa493e2317919 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -48,7 +48,7 @@ const ALLOWED_BLOCKS = [ 'core/home-link', 'core/site-title', 'core/site-logo', - 'core/dropdown', + 'core/navigation-submenu', ]; const LAYOUT = { diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index 68246111ffe0e4..e86b5d4e5805a3 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -256,11 +256,11 @@ function render_block_core_navigation( $attributes, $content, $block ) { $inner_blocks_html = ''; $is_list_open = false; foreach ( $inner_blocks as $inner_block ) { - if ( ( 'core/navigation-link' === $inner_block->name || 'core/home-link' === $inner_block->name || 'core/site-title' === $inner_block->name || 'core/site-logo' === $inner_block->name ) && ! $is_list_open ) { + if ( ( 'core/navigation-link' === $inner_block->name || 'core/home-link' === $inner_block->name || 'core/site-title' === $inner_block->name || 'core/site-logo' === $inner_block->name || 'core/navigation-submenu' === $inner_block->name ) && ! $is_list_open ) { $is_list_open = true; $inner_blocks_html .= '
      '; } - if ( 'core/navigation-link' !== $inner_block->name && 'core/home-link' !== $inner_block->name && 'core/site-title' !== $inner_block->name && 'core/site-logo' !== $inner_block->name && $is_list_open ) { + if ( 'core/navigation-link' !== $inner_block->name && 'core/home-link' !== $inner_block->name && 'core/site-title' !== $inner_block->name && 'core/site-logo' !== $inner_block->name && 'core/navigation-submenu' !== $inner_block->name && $is_list_open ) { $is_list_open = false; $inner_blocks_html .= '
    '; } diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index c2415905e48df8..2f64d28818e5af 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -7,7 +7,6 @@ @import "./code/style.scss"; @import "./columns/style.scss"; @import "./cover/style.scss"; -@import "./dropdown/style.scss"; @import "./embed/style.scss"; @import "./file/style.scss"; @import "./gallery/style.scss"; @@ -20,6 +19,7 @@ @import "./media-text/style.scss"; @import "./navigation/style.scss"; @import "./navigation-link/style.scss"; +@import "./navigation-submenu/style.scss"; @import "./home-link/style.scss"; @import "./page-list/style.scss"; @import "./paragraph/style.scss"; From 89f33e5e25ed6b747c116dcaf0e58a61c218f4ce Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 24 Aug 2021 14:22:41 +1000 Subject: [PATCH 08/40] Add submenu transform to navigation link. --- packages/block-library/src/navigation-link/index.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/block-library/src/navigation-link/index.js b/packages/block-library/src/navigation-link/index.js index a62a27bfa8b29c..3d38a74e8a0c7b 100644 --- a/packages/block-library/src/navigation-link/index.js +++ b/packages/block-library/src/navigation-link/index.js @@ -5,6 +5,7 @@ import { _x } from '@wordpress/i18n'; import { customLink as linkIcon } from '@wordpress/icons'; import { InnerBlocks } from '@wordpress/block-editor'; import { addFilter } from '@wordpress/hooks'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies @@ -84,6 +85,16 @@ export const settings = { }, }, ], + transforms: { + to: [ + { + type: 'block', + blocks: [ 'core/navigation-submenu' ], + transform: ( attributes ) => + createBlock( 'core/navigation-submenu', attributes ), + }, + ], + }, }; // importing this file includes side effects. This is whitelisted in block-library/package.json under sideEffects From 4fb07162b773d747a33dcbae86bdf59136e8a6c7 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 24 Aug 2021 15:21:47 +1000 Subject: [PATCH 09/40] Remove button default styling --- packages/block-library/src/navigation-submenu/style.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/block-library/src/navigation-submenu/style.scss b/packages/block-library/src/navigation-submenu/style.scss index 9a9aa9844f973d..18f37cd2aabe70 100644 --- a/packages/block-library/src/navigation-submenu/style.scss +++ b/packages/block-library/src/navigation-submenu/style.scss @@ -20,3 +20,9 @@ opacity: 1; } } + +button.wp-block-navigation-item__content { + background-color: transparent; + border: none; + color: currentColor; +} From 8ed3e1d92a3c4b19f460d7800f53ee25c4322e50 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 24 Aug 2021 15:23:19 +1000 Subject: [PATCH 10/40] Don't split at end. --- packages/block-library/src/navigation-submenu/edit.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index 99b38f8e7b611a..97f2c6f123f36e 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -7,7 +7,6 @@ import { escape, pull } from 'lodash'; /** * WordPress dependencies */ -import { createBlock } from '@wordpress/blocks'; import { useSelect, useDispatch } from '@wordpress/data'; import { KeyboardShortcuts, @@ -271,7 +270,6 @@ export default function NavigationSubmenuEdit( { attributes, isSelected, setAttributes, - insertBlocksAfter, mergeBlocks, onReplace, context, @@ -559,11 +557,6 @@ export default function NavigationSubmenuEdit( { } onMerge={ mergeBlocks } onReplace={ onReplace } - __unstableOnSplitAtEnd={ () => - insertBlocksAfter( - createBlock( 'core/navigation-link' ) - ) - } aria-label={ __( 'Navigation link text' ) } placeholder={ itemLabelPlaceholder } withoutInteractiveFormatting From fedffa3ef6ee572b37eb74886b8737436ba62e03 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 24 Aug 2021 15:53:59 +1000 Subject: [PATCH 11/40] Add block fixture. --- .../blocks/core__navigation-submenu.html | 4 +++ .../blocks/core__navigation-submenu.json | 27 +++++++++++++++++++ .../core__navigation-submenu.parsed.json | 23 ++++++++++++++++ .../core__navigation-submenu.serialized.html | 3 +++ 4 files changed, 57 insertions(+) create mode 100644 test/integration/fixtures/blocks/core__navigation-submenu.html create mode 100644 test/integration/fixtures/blocks/core__navigation-submenu.json create mode 100644 test/integration/fixtures/blocks/core__navigation-submenu.parsed.json create mode 100644 test/integration/fixtures/blocks/core__navigation-submenu.serialized.html diff --git a/test/integration/fixtures/blocks/core__navigation-submenu.html b/test/integration/fixtures/blocks/core__navigation-submenu.html new file mode 100644 index 00000000000000..ae652c313e822a --- /dev/null +++ b/test/integration/fixtures/blocks/core__navigation-submenu.html @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/integration/fixtures/blocks/core__navigation-submenu.json b/test/integration/fixtures/blocks/core__navigation-submenu.json new file mode 100644 index 00000000000000..a2889a39797ac3 --- /dev/null +++ b/test/integration/fixtures/blocks/core__navigation-submenu.json @@ -0,0 +1,27 @@ +[ + { + "clientId": "_clientId_0", + "name": "core/navigation-submenu", + "isValid": true, + "attributes": { + "label": "A fine submenu", + "opensInNewTab": false, + "isTopLevelItem": true + }, + "innerBlocks": [ + { + "clientId": "_clientId_0", + "name": "core/navigation-link", + "isValid": true, + "attributes": { + "label": "WordPress", + "opensInNewTab": false, + "url": "https://wordpress.org/" + }, + "innerBlocks": [], + "originalContent": "" + } + ], + "originalContent": "" + } +] diff --git a/test/integration/fixtures/blocks/core__navigation-submenu.parsed.json b/test/integration/fixtures/blocks/core__navigation-submenu.parsed.json new file mode 100644 index 00000000000000..dbc4ee68d54e94 --- /dev/null +++ b/test/integration/fixtures/blocks/core__navigation-submenu.parsed.json @@ -0,0 +1,23 @@ +[ + { + "blockName": "core/navigation-submenu", + "attrs": { + "label": "A fine submenu", + "isTopLevelItem": true + }, + "innerBlocks": [ + { + "blockName": "core/navigation-link", + "attrs": { + "label": "WordPress", + "url": "https://wordpress.org/" + }, + "innerBlocks": [], + "innerHTML": "\n", + "innerContent": [ "\n" ] + } + ], + "innerHTML": "\n\n", + "innerContent": [ "\n", null, "\n" ] + } +] diff --git a/test/integration/fixtures/blocks/core__navigation-submenu.serialized.html b/test/integration/fixtures/blocks/core__navigation-submenu.serialized.html new file mode 100644 index 00000000000000..bda4d67a75b24c --- /dev/null +++ b/test/integration/fixtures/blocks/core__navigation-submenu.serialized.html @@ -0,0 +1,3 @@ + + + From 451b70ff6aa6b4810bcb6aa364fd86c6006e045f Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 24 Aug 2021 16:53:28 +1000 Subject: [PATCH 12/40] Fix php lint errors. --- packages/block-library/src/navigation-submenu/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index 1e26b08b90a588..84e1da193b4543 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -170,7 +170,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { ) ); $html = '
  • '; - + // If the Parent element is a link, we render an anchor tag with attributes. // We also render a submenu button, so the submenu can be opened on click. if ( isset( $attributes['url'] ) && '' !== $attributes['url'] ) { @@ -180,13 +180,13 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { if ( isset( $attributes['opensInNewTab'] ) && true === $attributes['opensInNewTab'] ) { $html .= ' target="_blank" '; } - + if ( isset( $attributes['rel'] ) ) { $html .= ' rel="' . esc_attr( $attributes['rel'] ) . '"'; } elseif ( isset( $attributes['nofollow'] ) && $attributes['nofollow'] ) { $html .= ' rel="nofollow"'; } - + if ( isset( $attributes['title'] ) ) { $html .= ' title="' . esc_attr( $attributes['title'] ) . '"'; } From 0cb9fe680ce2cb1e9fac033c24998b46f2486701 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 25 Aug 2021 17:12:24 +1000 Subject: [PATCH 13/40] Update submenu icon classname. --- packages/block-library/src/navigation-submenu/edit.js | 2 +- packages/block-library/src/navigation-submenu/index.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index 97f2c6f123f36e..206fe9441e7af9 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -625,7 +625,7 @@ export default function NavigationSubmenuEdit( { ) } { showSubmenuIcon && ( - + ) } diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index 84e1da193b4543..7375dc4a257fb4 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -256,7 +256,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { if ( isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'] ) { // The submenu icon can be hidden by a CSS rule on the Navigation Block. - $html .= '' . block_core_navigation_submenu_render_submenu_icon() . ''; + $html .= '' . block_core_navigation_submenu_render_submenu_icon() . ''; } $html .= ''; From 520dac7e5719308f3e5c326f1df7c069a4247ba3 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 25 Aug 2021 17:57:47 +1000 Subject: [PATCH 14/40] Use Submenu in Page List conversion to blocks. --- .../block-library/src/page-list/convert-to-links-modal.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/page-list/convert-to-links-modal.js b/packages/block-library/src/page-list/convert-to-links-modal.js index e900a9ab94d380..557ce6aeb2df90 100644 --- a/packages/block-library/src/page-list/convert-to-links-modal.js +++ b/packages/block-library/src/page-list/convert-to-links-modal.js @@ -26,8 +26,11 @@ export const convertSelectedBlockToNavigationLinks = ( { pages.forEach( ( { id, title, link: url, type, parent } ) => { // See if a placeholder exists. This is created if children appear before parents in list const innerBlocks = linkMap[ id ]?.innerBlocks ?? []; + const blockType = linkMap[ id ]?.innerBlocks + ? 'core/navigation-submenu' + : 'core/navigation-link'; linkMap[ id ] = createBlock( - 'core/navigation-link', + blockType, { id, label: title.rendered, From c1f8bac3e1d15c6ecb5a290dc7b2d7e64469f0fb Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 27 Aug 2021 11:34:11 +1000 Subject: [PATCH 15/40] Don't lose children when transforming to Submenu. --- packages/block-library/src/navigation-link/edit.js | 9 ++++++++- packages/block-library/src/navigation-link/index.js | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index fc848d2ba3b589..732a6639ff6007 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -302,6 +302,7 @@ export default function NavigationLinkEdit( { const ref = useRef(); const { + innerBlocks, isAtMaxNesting, isTopLevelLink, isParentOfSelectedBlock, @@ -313,6 +314,7 @@ export default function NavigationLinkEdit( { } = useSelect( ( select ) => { const { + getBlocks, getClientIdsOfDescendants, hasSelectedInnerBlock, getSelectedBlockClientId, @@ -325,6 +327,7 @@ export default function NavigationLinkEdit( { .length; return { + innerBlocks: getBlocks( clientId ), isAtMaxNesting: getBlockParentsByBlockName( clientId, name ).length >= MAX_NESTING, @@ -368,7 +371,11 @@ export default function NavigationLinkEdit( { * Transform to submenu block. */ function transformToSubmenu() { - const newSubmenu = createBlock( 'core/navigation-submenu', attributes ); + const newSubmenu = createBlock( + 'core/navigation-submenu', + attributes, + innerBlocks + ); replaceBlock( clientId, newSubmenu ); } diff --git a/packages/block-library/src/navigation-link/index.js b/packages/block-library/src/navigation-link/index.js index 3d38a74e8a0c7b..4da4b2885e05fe 100644 --- a/packages/block-library/src/navigation-link/index.js +++ b/packages/block-library/src/navigation-link/index.js @@ -90,8 +90,12 @@ export const settings = { { type: 'block', blocks: [ 'core/navigation-submenu' ], - transform: ( attributes ) => - createBlock( 'core/navigation-submenu', attributes ), + transform: ( attributes, innerBlocks ) => + createBlock( + 'core/navigation-submenu', + attributes, + innerBlocks + ), }, ], }, From f0e00aaa2d5ba4249793d37968c060c05c007ea3 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 30 Aug 2021 10:54:53 +1000 Subject: [PATCH 16/40] Fix link conversion in Page List block. --- .../src/page-list/convert-to-links-modal.js | 25 ++++++++++++++++--- .../page-list/test/convert-to-links-modal.js | 12 ++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/block-library/src/page-list/convert-to-links-modal.js b/packages/block-library/src/page-list/convert-to-links-modal.js index 557ce6aeb2df90..80c735bff96859 100644 --- a/packages/block-library/src/page-list/convert-to-links-modal.js +++ b/packages/block-library/src/page-list/convert-to-links-modal.js @@ -26,11 +26,8 @@ export const convertSelectedBlockToNavigationLinks = ( { pages.forEach( ( { id, title, link: url, type, parent } ) => { // See if a placeholder exists. This is created if children appear before parents in list const innerBlocks = linkMap[ id ]?.innerBlocks ?? []; - const blockType = linkMap[ id ]?.innerBlocks - ? 'core/navigation-submenu' - : 'core/navigation-link'; linkMap[ id ] = createBlock( - blockType, + 'core/navigation-link', { id, label: title.rendered, @@ -53,6 +50,26 @@ export const convertSelectedBlockToNavigationLinks = ( { } } ); + // Transform all links with innerBlocks into Submenus. This can't be done + // sooner because page objects have no information on their children. + + const transformSubmenus = ( listOfLinks ) => { + listOfLinks.forEach( ( block, index, listOfLinksArray ) => { + const { attributes, innerBlocks } = block; + if ( innerBlocks.length !== 0 ) { + transformSubmenus( innerBlocks ); + const transformedBlock = createBlock( + 'core/navigation-submenu', + attributes, + innerBlocks + ); + listOfLinksArray[ index ] = transformedBlock; + } + } ); + }; + + transformSubmenus( navigationLinks ); + replaceBlock( clientId, navigationLinks ); }; diff --git a/packages/block-library/src/page-list/test/convert-to-links-modal.js b/packages/block-library/src/page-list/test/convert-to-links-modal.js index 930582e85aae4a..073766d70143e7 100644 --- a/packages/block-library/src/page-list/test/convert-to-links-modal.js +++ b/packages/block-library/src/page-list/test/convert-to-links-modal.js @@ -149,7 +149,7 @@ describe( 'page list convert to links', () => { name: 'core/navigation-link', }, ], - name: 'core/navigation-link', + name: 'core/navigation-submenu', }, { attributes: { @@ -193,10 +193,10 @@ describe( 'page list convert to links', () => { name: 'core/navigation-link', }, ], - name: 'core/navigation-link', + name: 'core/navigation-submenu', }, ], - name: 'core/navigation-link', + name: 'core/navigation-submenu', }, ] ); } ); @@ -344,7 +344,7 @@ describe( 'page list convert to links', () => { name: 'core/navigation-link', }, ], - name: 'core/navigation-link', + name: 'core/navigation-submenu', }, { attributes: { @@ -388,10 +388,10 @@ describe( 'page list convert to links', () => { name: 'core/navigation-link', }, ], - name: 'core/navigation-link', + name: 'core/navigation-submenu', }, ], - name: 'core/navigation-link', + name: 'core/navigation-submenu', }, ] ); } ); From 71122005cdc480446e41abc142b7a7f7fb667a38 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 30 Aug 2021 15:31:36 +1000 Subject: [PATCH 17/40] Add link to empty submenu and default navigation class. --- .../src/navigation-submenu/edit.js | 17 ++++++++++++++++- .../src/navigation-submenu/index.php | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index 206fe9441e7af9..d1faa6b6b99e98 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -42,6 +42,7 @@ import { placeCaretAtHorizontalEdge } from '@wordpress/dom'; import { link as linkIcon } from '@wordpress/icons'; import { store as coreStore } from '@wordpress/core-data'; import { speak } from '@wordpress/a11y'; +import { createBlock } from '@wordpress/blocks'; /** * Internal dependencies @@ -291,6 +292,7 @@ export default function NavigationSubmenuEdit( { }; const { showSubmenuIcon } = context; const { saveEntityRecord } = useDispatch( coreStore ); + const { insertBlock } = useDispatch( blockEditorStore ); const [ isLinkOpen, setIsLinkOpen ] = useState( false ); const listItemRef = useRef( null ); const isDraggingWithin = useIsDraggingWithin( listItemRef ); @@ -303,6 +305,7 @@ export default function NavigationSubmenuEdit( { isParentOfSelectedBlock, isImmediateParentOfSelectedBlock, hasDescendants, + numberOfDescendants, selectedBlockHasDescendants, userCanCreatePages, userCanCreatePosts, @@ -335,6 +338,7 @@ export default function NavigationSubmenuEdit( { false ), hasDescendants: !! descendants, + numberOfDescendants: descendants, selectedBlockHasDescendants: !! getClientIdsOfDescendants( [ selectedBlockId, ] )?.length, @@ -429,7 +433,7 @@ export default function NavigationSubmenuEdit( { const blockProps = useBlockProps( { ref: listItemRef, - className: classnames( { + className: classnames( 'wp-block-navigation-item', { 'is-editing': isSelected || isParentOfSelectedBlock, 'is-dragging-within': isDraggingWithin, 'has-link': !! url, @@ -455,6 +459,17 @@ export default function NavigationSubmenuEdit( { pull( ALLOWED_BLOCKS, 'core/navigation-submenu' ); } + // Add a link when creating a new Submenu. + useEffect( () => { + if ( ! hasDescendants ) { + insertBlock( + createBlock( 'core/navigation-link' ), + numberOfDescendants, + clientId + ); + } + }, [] ); + const innerBlocksProps = useInnerBlocksProps( { className: classnames( 'wp-block-navigation__submenu-container', { diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index 7375dc4a257fb4..96a5c31bca76b7 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -164,7 +164,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { $wrapper_attributes = get_block_wrapper_attributes( array( - 'class' => $css_classes . ( $has_submenu ? ' has-child' : '' ) . + 'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) . ( $is_active ? ' current-menu-item' : '' ), 'style' => $style_attribute, ) From 3e32cd402feb5fd57e55645d753e57aa8850083e Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 31 Aug 2021 14:18:03 +1000 Subject: [PATCH 18/40] Introduce hover/click toggle on Navigation. --- .../src/navigation-submenu/block.json | 1 + .../src/navigation-submenu/edit.js | 22 ++++++++------- .../src/navigation-submenu/index.php | 28 +++++++++++-------- .../src/navigation-submenu/style.scss | 7 +++-- .../src/navigation-submenu/view.js | 13 ++++++++- .../block-library/src/navigation/block.json | 5 ++++ packages/block-library/src/navigation/edit.js | 11 ++++++++ .../block-library/src/navigation/style.scss | 6 ++-- 8 files changed, 66 insertions(+), 27 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/block.json b/packages/block-library/src/navigation-submenu/block.json index 6c701d1d96733a..943e3c948d9692 100644 --- a/packages/block-library/src/navigation-submenu/block.json +++ b/packages/block-library/src/navigation-submenu/block.json @@ -53,6 +53,7 @@ "fontSize", "customFontSize", "showSubmenuIcon", + "openSubmenusOnClick", "style" ], "supports": { diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index d1faa6b6b99e98..739830fbd0bc6a 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -290,7 +290,7 @@ export default function NavigationSubmenuEdit( { url, opensInNewTab, }; - const { showSubmenuIcon } = context; + const { showSubmenuIcon, openSubmenusOnClick } = context; const { saveEntityRecord } = useDispatch( coreStore ); const { insertBlock } = useDispatch( blockEditorStore ); const [ isLinkOpen, setIsLinkOpen ] = useState( false ); @@ -503,7 +503,7 @@ export default function NavigationSubmenuEdit( { } ); - const ParentElement = url ? 'a' : 'button'; + const ParentElement = openSubmenusOnClick ? 'button' : 'a'; return ( @@ -516,13 +516,15 @@ export default function NavigationSubmenuEdit( { setIsLinkOpen( true ), } } /> - setIsLinkOpen( true ) } - /> + { ! openSubmenusOnClick && ( + setIsLinkOpen( true ) } + /> + ) } @@ -583,7 +585,7 @@ export default function NavigationSubmenuEdit( { ] } /> } - { isLinkOpen && ( + { ! openSubmenusOnClick && isLinkOpen && ( setIsLinkOpen( false ) } diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index 96a5c31bca76b7..40b72b9f843d7f 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -162,20 +162,26 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { $css_classes .= ' ' . $class_name; } + $open_on_click = isset( $block->context['openSubmenusOnClick'] ) && $block->context['openSubmenusOnClick']; + $open_on_hover_and_click = isset( $block->context['openSubmenusOnClick'] ) && ! $block->context['openSubmenusOnClick'] && + isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon']; + $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) . - ( $is_active ? ' current-menu-item' : '' ), + ( $open_on_click ? ' open-on-click' : '') . ( $open_on_hover_and_click ? ' open-on-hover-click' : '') . + ( $is_active ? ' current-menu-item' : '' ), 'style' => $style_attribute, ) ); $html = '
  • '; - // If the Parent element is a link, we render an anchor tag with attributes. - // We also render a submenu button, so the submenu can be opened on click. - if ( isset( $attributes['url'] ) && '' !== $attributes['url'] ) { + // If Submenus open on hover, we render an anchor tag with attributes. + // If submenu icons are set to show, we also render a submenu button, so the submenu can be opened on click. + if ( !$open_on_click ) { + $item_url = isset($attributes['url']) ? esc_url( $attributes['url'] ) : ''; // Start appending HTML attributes to anchor tag. - $html .= ''; - + if ( isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'] ) { + // The submenu icon is rendered in a button here + // so that there's a clickable elment to open the submenu. + $html .= ''; + } } else { - // If the Parent element is not a link, we render the whole thing as a button. + // If menus open on click, we render the parent as a button. $html .= ''; @@ -261,9 +262,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { $html .= ''; - if ( isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'] ) { - $html .= '' . block_core_navigation_submenu_render_submenu_icon() . ''; - } + $html .= '' . block_core_navigation_submenu_render_submenu_icon() . ''; $html .= ''; diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index d92d683e0d82c0..3400a2f3c2ba9e 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -248,15 +248,17 @@ function Navigation( { { hasSubmenuIndicatorSetting && ( - { - setAttributes( { - showSubmenuIcon: value, - } ); - } } - label={ __( 'Show submenu indicator icons' ) } - /> + { ! attributes.openSubmenusOnClick && ( + { + setAttributes( { + showSubmenuIcon: value, + } ); + } } + label={ __( 'Show submenu indicator icons' ) } + /> + ) } { From 1e39756d6a21d7d454de939a427b92b0b4fbd434 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 2 Sep 2021 13:58:35 +1000 Subject: [PATCH 22/40] Open submenus on click in the editor. --- packages/block-library/src/navigation-submenu/edit.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index 6bb1e5e6958224..e167844473cbf1 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -441,6 +441,7 @@ export default function NavigationSubmenuEdit( { 'background-color', backgroundColor ) ]: !! backgroundColor, + 'open-on-click': openSubmenusOnClick, } ), style: { color: ! textColor && customTextColor, From f1c9696b7ab105a6a2a06463179998d0bfeed7b7 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 3 Sep 2021 13:52:36 +1000 Subject: [PATCH 23/40] Fix button styles and change toggle label. --- packages/block-library/src/navigation-submenu/style.scss | 1 + packages/block-library/src/navigation/edit.js | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/style.scss b/packages/block-library/src/navigation-submenu/style.scss index 92140c62b7dcbf..077c0685acda9a 100644 --- a/packages/block-library/src/navigation-submenu/style.scss +++ b/packages/block-library/src/navigation-submenu/style.scss @@ -28,4 +28,5 @@ button.wp-block-navigation-item__content { border: none; color: currentColor; font-size: inherit; + font-family: inherit; } diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index 3400a2f3c2ba9e..f7900c4c441121 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -266,9 +266,7 @@ function Navigation( { openSubmenusOnClick: value, } ); } } - label={ __( - 'Open submenus on click instead of hover' - ) } + label={ __( 'Open submenus on click' ) } /> Date: Fri, 3 Sep 2021 14:27:36 +1000 Subject: [PATCH 24/40] Update navigation fixture and fix php lint errors. --- packages/block-library/src/navigation-submenu/index.php | 6 +++--- test/integration/fixtures/blocks/core__navigation.json | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index f4d468afeb9df9..9c587bccc1b800 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -170,7 +170,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $css_classes . ' wp-block-navigation-item' . ( $has_submenu ? ' has-child' : '' ) . - ( $open_on_click ? ' open-on-click' : '') . ( $open_on_hover_and_click ? ' open-on-hover-click' : '') . + ( $open_on_click ? ' open-on-click' : '' ) . ( $open_on_hover_and_click ? ' open-on-hover-click' : '' ) . ( $is_active ? ' current-menu-item' : '' ), 'style' => $style_attribute, ) @@ -179,8 +179,8 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { // If Submenus open on hover, we render an anchor tag with attributes. // If submenu icons are set to show, we also render a submenu button, so the submenu can be opened on click. - if ( !$open_on_click ) { - $item_url = isset($attributes['url']) ? esc_url( $attributes['url'] ) : ''; + if ( ! $open_on_click ) { + $item_url = isset( $attributes['url'] ) ? esc_url( $attributes['url'] ) : ''; // Start appending HTML attributes to anchor tag. $html .= ' Date: Fri, 3 Sep 2021 14:48:55 +1000 Subject: [PATCH 25/40] Fix php lint error. --- packages/block-library/src/navigation/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php index e86b5d4e5805a3..f2bd64737870a2 100644 --- a/packages/block-library/src/navigation/index.php +++ b/packages/block-library/src/navigation/index.php @@ -260,7 +260,7 @@ function render_block_core_navigation( $attributes, $content, $block ) { $is_list_open = true; $inner_blocks_html .= '
      '; } - if ( 'core/navigation-link' !== $inner_block->name && 'core/home-link' !== $inner_block->name && 'core/site-title' !== $inner_block->name && 'core/site-logo' !== $inner_block->name && 'core/navigation-submenu' !== $inner_block->name && $is_list_open ) { + if ( 'core/navigation-link' !== $inner_block->name && 'core/home-link' !== $inner_block->name && 'core/site-title' !== $inner_block->name && 'core/site-logo' !== $inner_block->name && 'core/navigation-submenu' !== $inner_block->name && $is_list_open ) { $is_list_open = false; $inner_blocks_html .= '
    '; } From c6f531e9d08450d92e563629fe76d5d734a0b7fa Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 3 Sep 2021 16:04:08 +1000 Subject: [PATCH 26/40] Fix php lint error. --- packages/block-library/src/navigation-submenu/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation-submenu/index.php b/packages/block-library/src/navigation-submenu/index.php index 9c587bccc1b800..0a12cb0e93e678 100644 --- a/packages/block-library/src/navigation-submenu/index.php +++ b/packages/block-library/src/navigation-submenu/index.php @@ -163,7 +163,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) { } $show_submenu_indicators = isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon']; - $open_on_click = isset( $block->context['openSubmenusOnClick'] ) && $block->context['openSubmenusOnClick']; + $open_on_click = isset( $block->context['openSubmenusOnClick'] ) && $block->context['openSubmenusOnClick']; $open_on_hover_and_click = isset( $block->context['openSubmenusOnClick'] ) && ! $block->context['openSubmenusOnClick'] && $show_submenu_indicators; From 19f9901f977e0af61d1178240a697dd3f01343d1 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 6 Sep 2021 13:30:15 +1000 Subject: [PATCH 27/40] Try hiding submenu in block inserter. --- packages/block-library/src/navigation-submenu/block.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation-submenu/block.json b/packages/block-library/src/navigation-submenu/block.json index 943e3c948d9692..f5f4d4b4ec92cd 100644 --- a/packages/block-library/src/navigation-submenu/block.json +++ b/packages/block-library/src/navigation-submenu/block.json @@ -58,7 +58,8 @@ ], "supports": { "reusable": false, - "html": false + "html": false, + "inserter": false }, "viewScript": "file:./view.min.js", "editorStyle": "wp-block-navigation-submenu-editor", From e8e7f04c05e6bb6410f3cf2325e2b6ae3050f5cc Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 6 Sep 2021 16:34:57 +1000 Subject: [PATCH 28/40] Update menu items to blocks conversion. --- .../src/navigation/menu-items-to-blocks.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/navigation/menu-items-to-blocks.js b/packages/block-library/src/navigation/menu-items-to-blocks.js index 024c267d67cefc..d079463e36eca6 100644 --- a/packages/block-library/src/navigation/menu-items-to-blocks.js +++ b/packages/block-library/src/navigation/menu-items-to-blocks.js @@ -65,12 +65,12 @@ function mapMenuItemsToBlocks( menuItems ) { ...nestedMapping, }; + const blockType = menuItem.children?.length + ? 'core/navigation-submenu' + : 'core/navigation-link'; + // Create block with nested "innerBlocks". - const block = createBlock( - 'core/navigation-link', - attributes, - nestedBlocks - ); + const block = createBlock( blockType, attributes, nestedBlocks ); // Create mapping for menuItem -> block mapping[ menuItem.id ] = block.clientId; From ea847adfd38f64f126c4f529b24b34cc196155ec Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 7 Sep 2021 14:16:03 +1000 Subject: [PATCH 29/40] Update menu items to blocks test. --- .../src/navigation/test/menu-items-to-blocks.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/navigation/test/menu-items-to-blocks.js b/packages/block-library/src/navigation/test/menu-items-to-blocks.js index 599b30e679ff55..ce89829d0188d0 100644 --- a/packages/block-library/src/navigation/test/menu-items-to-blocks.js +++ b/packages/block-library/src/navigation/test/menu-items-to-blocks.js @@ -84,7 +84,7 @@ describe( 'converting menu items to blocks', () => { attr_title: '', description: '', type: 'custom', - type_label: 'Custom Link', + type_label: 'Submenu', object: 'custom', parent: 0, menu_order: 1, @@ -120,7 +120,7 @@ describe( 'converting menu items to blocks', () => { attr_title: '', description: '', type: 'custom', - type_label: 'Custom Link', + type_label: 'Submenu', object: 'custom', parent: 1, menu_order: 2, @@ -138,7 +138,7 @@ describe( 'converting menu items to blocks', () => { attr_title: '', description: '', type: 'custom', - type_label: 'Custom Link', + type_label: 'Submenu', object: 'custom', parent: 3, menu_order: 1, @@ -186,7 +186,7 @@ describe( 'converting menu items to blocks', () => { expect( actual ).toEqual( [ expect.objectContaining( { - name: 'core/navigation-link', + name: 'core/navigation-submenu', attributes: expect.objectContaining( { label: 'Top Level', } ), @@ -199,13 +199,13 @@ describe( 'converting menu items to blocks', () => { innerBlocks: [], } ), expect.objectContaining( { - name: 'core/navigation-link', + name: 'core/navigation-submenu', attributes: expect.objectContaining( { label: 'Child 2', } ), innerBlocks: [ expect.objectContaining( { - name: 'core/navigation-link', + name: 'core/navigation-submenu', attributes: expect.objectContaining( { label: 'Sub Child', } ), From 71bbd83e12af4a6ea5ecd12a8745a83c6591b97e Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 7 Sep 2021 14:37:27 +1000 Subject: [PATCH 30/40] Fix navigation link top level item status. --- packages/block-library/src/navigation-link/edit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index 732a6639ff6007..fa2a14560d780b 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -331,8 +331,12 @@ export default function NavigationLinkEdit( { isAtMaxNesting: getBlockParentsByBlockName( clientId, name ).length >= MAX_NESTING, + // Temporary fix until navigation link submenus are properly deprecated. isTopLevelLink: - getBlockParentsByBlockName( clientId, name ).length === 0, + getBlockParentsByBlockName( clientId, [ + name, + 'core/navigation-submenu', + ] ).length === 0, isParentOfSelectedBlock: hasSelectedInnerBlock( clientId, true From 0738c4809366b33d27ce0a70500cd9ba18a77f59 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Tue, 7 Sep 2021 17:04:20 +1000 Subject: [PATCH 31/40] Update and add new e2e test for open on click. --- .../__snapshots__/navigation.test.js.snap | 36 +++++++------- .../experiments/blocks/navigation.test.js | 49 ++++++++++++++++++- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap b/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap index 40204d478b4af8..659c38359fa823 100644 --- a/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap +++ b/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap @@ -4,35 +4,35 @@ exports[`Navigation Creating from existing Menus allows a navigation block to be " - + - + - - - - + + + + - - - - + + + + - - - + + + - - - + + + - + - + " `; diff --git a/packages/e2e-tests/specs/experiments/blocks/navigation.test.js b/packages/e2e-tests/specs/experiments/blocks/navigation.test.js index c4a3ba9193c3ba..40449589463c67 100644 --- a/packages/e2e-tests/specs/experiments/blocks/navigation.test.js +++ b/packages/e2e-tests/specs/experiments/blocks/navigation.test.js @@ -346,7 +346,7 @@ describe( 'Navigation', () => { // Scope element selector to the Editor's "Content" region as otherwise it picks up on // block previews. const navLinkSelector = - '[aria-label="Editor content"][role="region"] div[aria-label="Block: Custom Link"]'; + '[aria-label="Editor content"][role="region"] .wp-block-navigation-item'; await page.waitForSelector( navLinkSelector ); @@ -595,6 +595,53 @@ describe( 'Navigation', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + it( 'allows navigation submenus to open on click instead of hover', async () => { + await mockAllMenusResponses(); + + // Add the navigation block. + await insertBlock( 'Navigation' ); + + await selectDropDownOption( 'Test Menu 2' ); + + // const blocks = await getAllBlocks(); + // await selectBlockByClientId( blocks[ 0 ].clientId ); + + await toggleSidebar(); + + const [ openOnClickButton ] = await page.$x( + '//label[contains(text(),"Open submenus on click")]' + ); + + await openOnClickButton.click(); + + await saveDraft(); + + // Scope element selector to the Editor's "Content" region as otherwise it picks up on + // block previews. + const navSubmenuSelector = + '[aria-label="Editor content"][role="region"] [aria-label="Block: Submenu"]'; + + await page.waitForSelector( navSubmenuSelector ); + + const navSubmenusLength = await page.$$eval( + navSubmenuSelector, + ( els ) => els.length + ); + + const navButtonTogglesSelector = + '[aria-label="Editor content"][role="region"] [aria-label="Block: Submenu"] button.wp-block-navigation-item__content'; + + await page.waitForSelector( navButtonTogglesSelector ); + + const navButtonTogglesLength = await page.$$eval( + navButtonTogglesSelector, + ( els ) => els.length + ); + + // Assert the correct number of button toggles are present. + expect( navSubmenusLength ).toEqual( navButtonTogglesLength ); + } ); + // The following tests are unstable, roughly around when https://github.com/WordPress/wordpress-develop/pull/1412 // landed. The block manually tests well, so let's skip to unblock other PRs and immediately follow up. cc @vcanales it.skip( 'loads frontend code only if the block is present', async () => { From aec69a23532713c95744fbc0f69fae950722984e Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 Sep 2021 11:19:43 +1000 Subject: [PATCH 32/40] Fix undo/redo trap. --- .../block-library/src/navigation-submenu/edit.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index e167844473cbf1..e852db3f6c3cc5 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -291,6 +291,9 @@ export default function NavigationSubmenuEdit( { }; const { showSubmenuIcon, openSubmenusOnClick } = context; const { saveEntityRecord } = useDispatch( coreStore ); + const { __unstableMarkNextChangeAsNotPersistent } = useDispatch( + blockEditorStore + ); const [ isLinkOpen, setIsLinkOpen ] = useState( false ); const listItemRef = useRef( null ); const isDraggingWithin = useIsDraggingWithin( listItemRef ); @@ -352,7 +355,14 @@ export default function NavigationSubmenuEdit( { ); // Store the colors from context as attributes for rendering - useEffect( () => setAttributes( { isTopLevelItem } ), [ isTopLevelItem ] ); + useEffect( () => { + // This side-effect should not create an undo level as those should + // only be created via user interactions. Mark this change as + // not persistent to avoid undo level creation. + // See https://github.com/WordPress/gutenberg/issues/34564. + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { isTopLevelItem } ); + }, [ isTopLevelItem ] ); /** * The hook shouldn't be necessary but due to a focus loss happening From 04f50f7567394f96b8a53e52cdb2cb2f7e21acd0 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 Sep 2021 13:02:06 +1000 Subject: [PATCH 33/40] Fix styling for nested submenus in the editor. --- .../src/navigation-submenu/editor.scss | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/block-library/src/navigation-submenu/editor.scss b/packages/block-library/src/navigation-submenu/editor.scss index db33072cfd81fa..341792158de728 100644 --- a/packages/block-library/src/navigation-submenu/editor.scss +++ b/packages/block-library/src/navigation-submenu/editor.scss @@ -15,6 +15,24 @@ position: absolute; left: -1em; top: 100%; + + @include break-medium { + .wp-block-navigation__submenu-container { + left: 100%; + top: -1px; // Border width. + + // Prevent the menu from disappearing when the mouse is over the gap + &::before { + content: ""; + position: absolute; + right: 100%; + height: 100%; + display: block; + width: 0.5em; + background: transparent; + } + } + } } } } From 55f7a0629128262d4792b8edb7d540a7068ca7ce Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 Sep 2021 13:06:35 +1000 Subject: [PATCH 34/40] Remove obsolete lint ignore --- packages/block-library/src/navigation-submenu/view.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/view.js b/packages/block-library/src/navigation-submenu/view.js index 0d5cc0c4155fd1..f990729f48af08 100644 --- a/packages/block-library/src/navigation-submenu/view.js +++ b/packages/block-library/src/navigation-submenu/view.js @@ -38,7 +38,6 @@ submenuButtons.forEach( ( button ) => { button.addEventListener( 'click', toggleSubmenuOnClick ); } ); -/* eslint-disable @wordpress/no-global-event-listener */ // Close on click outside. document.addEventListener( 'click', function ( event ) { const navigationBlocks = document.querySelectorAll( @@ -61,4 +60,3 @@ document.addEventListener( 'keyup', function ( event ) { } } ); } ); -/* eslint-enable @wordpress/no-global-event-listener */ From 2886cb7f02e2dd6f4df62964552a4b8b8ea507c7 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 Sep 2021 13:26:32 +1000 Subject: [PATCH 35/40] Display block label in list view. --- packages/block-library/src/navigation-submenu/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/block-library/src/navigation-submenu/index.js b/packages/block-library/src/navigation-submenu/index.js index 31bbe5517cc09a..a018cd6b31a953 100644 --- a/packages/block-library/src/navigation-submenu/index.js +++ b/packages/block-library/src/navigation-submenu/index.js @@ -18,6 +18,8 @@ export { metadata, name }; export const settings = { icon: addSubmenu, + __experimentalLabel: ( { label } ) => label, + edit, save, From 2d30be10b1e4107ea91cfabfa9f3843da29388ae Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 Sep 2021 15:58:23 +1000 Subject: [PATCH 36/40] Fix dropdown z-index --- packages/block-library/src/navigation-submenu/editor.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-library/src/navigation-submenu/editor.scss b/packages/block-library/src/navigation-submenu/editor.scss index 341792158de728..e53e11e4fdbf0c 100644 --- a/packages/block-library/src/navigation-submenu/editor.scss +++ b/packages/block-library/src/navigation-submenu/editor.scss @@ -1,6 +1,10 @@ .wp-block-navigation-submenu { display: block; + .wp-block-navigation__submenu-container { + z-index: 28; + } + // Show on editor selected, even if on frontend it only stays open on focus-within. &.is-selected, &.has-child-selected { From c4144177e8c5f3b8ca60c32d2de5acc4ec091d44 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 8 Sep 2021 16:01:12 +1000 Subject: [PATCH 37/40] Switch toggle position --- packages/block-library/src/navigation/edit.js | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/block-library/src/navigation/edit.js b/packages/block-library/src/navigation/edit.js index f7900c4c441121..03586d3c857045 100644 --- a/packages/block-library/src/navigation/edit.js +++ b/packages/block-library/src/navigation/edit.js @@ -248,35 +248,35 @@ function Navigation( { { hasSubmenuIndicatorSetting && ( - { ! attributes.openSubmenusOnClick && ( - { - setAttributes( { - showSubmenuIcon: value, - } ); - } } - label={ __( 'Show submenu indicator icons' ) } - /> - ) } { setAttributes( { - openSubmenusOnClick: value, + isResponsive: value, } ); } } - label={ __( 'Open submenus on click' ) } + label={ __( 'Enable responsive menu' ) } /> { setAttributes( { - isResponsive: value, + openSubmenusOnClick: value, } ); } } - label={ __( 'Enable responsive menu' ) } + label={ __( 'Open submenus on click' ) } /> + { ! attributes.openSubmenusOnClick && ( + { + setAttributes( { + showSubmenuIcon: value, + } ); + } } + label={ __( 'Show submenu indicator icons' ) } + /> + ) } ) } { hasColorSettings && ( From 530e32a5007fce2c45542a3d8fbfb20a63d55d9a Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 10 Sep 2021 11:38:24 +1000 Subject: [PATCH 38/40] Pointer cursor on button toggles. --- packages/block-library/src/navigation-submenu/style.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-library/src/navigation-submenu/style.scss b/packages/block-library/src/navigation-submenu/style.scss index 077c0685acda9a..46d68e2aeb8e52 100644 --- a/packages/block-library/src/navigation-submenu/style.scss +++ b/packages/block-library/src/navigation-submenu/style.scss @@ -30,3 +30,7 @@ button.wp-block-navigation-item__content { font-size: inherit; font-family: inherit; } + +.wp-block-navigation-submenu__toggle { + cursor: pointer; +} From fdde85d596770e7169e02f98fe925c9cc668342d Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 10 Sep 2021 12:01:53 +1000 Subject: [PATCH 39/40] Fix max nesting and top level link logic. --- packages/block-library/src/navigation-link/edit.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index fa2a14560d780b..d022817295a512 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -315,6 +315,8 @@ export default function NavigationLinkEdit( { ( select ) => { const { getBlocks, + getBlockName, + getBlockRootClientId, getClientIdsOfDescendants, hasSelectedInnerBlock, getSelectedBlockClientId, @@ -329,14 +331,13 @@ export default function NavigationLinkEdit( { return { innerBlocks: getBlocks( clientId ), isAtMaxNesting: - getBlockParentsByBlockName( clientId, name ).length >= - MAX_NESTING, - // Temporary fix until navigation link submenus are properly deprecated. - isTopLevelLink: getBlockParentsByBlockName( clientId, [ name, 'core/navigation-submenu', - ] ).length === 0, + ] ).length >= MAX_NESTING, + isTopLevelLink: + getBlockName( getBlockRootClientId( clientId ) ) === + 'core/navigation', isParentOfSelectedBlock: hasSelectedInnerBlock( clientId, true From 82d7ad7b27d891e9e31c4a1dfd9802e882edc0d3 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Mon, 13 Sep 2021 10:34:01 +1000 Subject: [PATCH 40/40] Show in inserter. --- packages/block-library/src/navigation-submenu/block.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-library/src/navigation-submenu/block.json b/packages/block-library/src/navigation-submenu/block.json index f5f4d4b4ec92cd..943e3c948d9692 100644 --- a/packages/block-library/src/navigation-submenu/block.json +++ b/packages/block-library/src/navigation-submenu/block.json @@ -58,8 +58,7 @@ ], "supports": { "reusable": false, - "html": false, - "inserter": false + "html": false }, "viewScript": "file:./view.min.js", "editorStyle": "wp-block-navigation-submenu-editor",