Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit Post: Refactor More (Ellipsis) Menu #5161

Merged
merged 10 commits into from
Feb 22, 2018
Merged

Conversation

gziolo
Copy link
Member

@gziolo gziolo commented Feb 20, 2018

Description

This PR adds a couple of refactorings to make More Menu extensible:

  • Renames EllipsisMenu to MoreMenu to align with what was discussed on Slack some time ago.
  • Removes div separators for the groups in the menu and replaces them with more flexible plain CSS solution.
  • Moves CopyContentButton and hooks from editor folder to editPost folder.
  • Makes all groups of menu items extensible by exposing filters that follow the same pattern: editPost.MoreMenu.${ groupName ).
  • Extracts MenuItemsChoice component to be able to pass it down to the menu group.

How to test?

Make sure all existing menu items display and work as before.

You can dynamically add new menu items by executing the following code:

wp.hooks.addFilter( 'editPost.MoreMenu.editor', 'core/edit-post/editor-callback', ( items ) => [ ...items, 'Editor item' ] );
wp.hooks.addFilter( 'editPost.MoreMenu.settings', 'core/edit-post/editor-callback', ( items ) => [ ...items, 'Settings item' ] );
wp.hooks.addFilter( 'editPost.MoreMenu.tools', 'core/edit-post/editor-callback', ( items ) => [ ...items, 'Tools item' ] );

You might need to reopen More Menu to see the changes applied. We can fix that in the follow-up PR if we decide to have it dynamically re-render when new filters gets added or removed. It can be achieved by extracting most of the logic or even updating withFilters HOC: https://github.com/WordPress/gutenberg/blob/master/components/higher-order/with-filters/index.js#L26.

Screenshots (jpeg or gifs if applicable):

More Menu with filters applied:

screen shot 2018-02-20 at 12 57 27

In the screenshot I added plain text, that’s why it doesn’t look perfect. We would rather expose a few components to consume there to make sure it looks properly.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code has proper inline documentation.

@gziolo gziolo added [Feature] Extensibility The ability to extend blocks or the editing experience [Feature] UI Components Impacts or related to the UI component system labels Feb 20, 2018
@gziolo gziolo self-assigned this Feb 20, 2018
@gziolo gziolo changed the title Edit Post: Refactor Ellipsis Menu Edit Post: Refactor More (Ellipsis) Menu Feb 20, 2018
@@ -22,17 +21,9 @@ function CopyContentButton( { editedPostContent, hasCopied, setState } ) {
);
}

const Enhanced = compose(
export default compose(
query( ( select ) => ( {
editedPostContent: select( 'core/editor' ).getEditedPostAttribute( 'content' ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should perform this call only when clicking on the button. Serializing blocks can harm performance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you like to call it directly using wp.data.select or expose it as a function here?
@mcsf what's your take on this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought, maybe it's not that severe because it's only shown when you open the dropdown menu, it's probably run only once because you don't edit content when this menu is open.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, it doesn't render when you edit your post. It only renders once when you open the dropdown.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, ClipboardButton is flexible and accepts a function for text, so the following works:

diff --git a/edit-post/components/header/copy-content-menu-item/index.js b/edit-post/components/header/copy-content-menu-item/index.js
index 88561ae1..a55688ad 100644
--- a/edit-post/components/header/copy-content-menu-item/index.js
+++ b/edit-post/components/header/copy-content-menu-item/index.js
@@ -2,11 +2,13 @@
  * WordPress dependencies
  */
 import { ClipboardButton, withState } from '@wordpress/components';
-import { compose } from '@wordpress/element';
-import { query } from '@wordpress/data';
+import { select } from '@wordpress/data';
 import { __ } from '@wordpress/i18n';
 
-function CopyContentMenuItem( { editedPostContent, hasCopied, setState } ) {
+const editedPostContent = () =>
+	select( 'core/editor' ).getEditedPostAttribute( 'content' );
+
+function CopyContentMenuItem( { hasCopied, setState } ) {
 	return (
 		<ClipboardButton
 			text={ editedPostContent }
@@ -21,9 +23,6 @@ function CopyContentMenuItem( { editedPostContent, hasCopied, setState } ) {
 	);
 }
 
-export default compose(
-	query( ( select ) => ( {
-		editedPostContent: select( 'core/editor' ).getEditedPostAttribute( 'content' ),
-	} ) ),
-	withState( { hasCopied: false } )
+export default withState(
+	{ hasCopied: false }
 )( CopyContentMenuItem );

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure which is better. Probably can stay as it is.

@jasmussen
Copy link
Contributor

Nice, this seems to work great! 👍 👍

Copy link
Contributor

@mcsf mcsf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like!

@@ -22,17 +21,9 @@ function CopyContentButton( { editedPostContent, hasCopied, setState } ) {
);
}

const Enhanced = compose(
export default compose(
query( ( select ) => ( {
editedPostContent: select( 'core/editor' ).getEditedPostAttribute( 'content' ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, ClipboardButton is flexible and accepts a function for text, so the following works:

diff --git a/edit-post/components/header/copy-content-menu-item/index.js b/edit-post/components/header/copy-content-menu-item/index.js
index 88561ae1..a55688ad 100644
--- a/edit-post/components/header/copy-content-menu-item/index.js
+++ b/edit-post/components/header/copy-content-menu-item/index.js
@@ -2,11 +2,13 @@
  * WordPress dependencies
  */
 import { ClipboardButton, withState } from '@wordpress/components';
-import { compose } from '@wordpress/element';
-import { query } from '@wordpress/data';
+import { select } from '@wordpress/data';
 import { __ } from '@wordpress/i18n';
 
-function CopyContentMenuItem( { editedPostContent, hasCopied, setState } ) {
+const editedPostContent = () =>
+	select( 'core/editor' ).getEditedPostAttribute( 'content' );
+
+function CopyContentMenuItem( { hasCopied, setState } ) {
 	return (
 		<ClipboardButton
 			text={ editedPostContent }
@@ -21,9 +23,6 @@ function CopyContentMenuItem( { editedPostContent, hasCopied, setState } ) {
 	);
 }
 
-export default compose(
-	query( ( select ) => ( {
-		editedPostContent: select( 'core/editor' ).getEditedPostAttribute( 'content' ),
-	} ) ),
-	withState( { hasCopied: false } )
+export default withState(
+	{ hasCopied: false }
 )( CopyContentMenuItem );

/**
* Internal dependencies
*/
import CopyContentMenuItem from '../../components/header/copy-content-menu-item';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're hooking CopyContentMenuItem into Gutenberg but keeping its definition outside edit-post/hooks. That's interesting; could you explain why?

Copy link
Member Author

@gziolo gziolo Feb 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure where to put it. I guess you are right that it should stay as a subfolder inside edit-post/hooks/ :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved back

@gziolo gziolo merged commit 38be3c9 into master Feb 22, 2018
@gziolo gziolo deleted the update/menu-items-group branch February 22, 2018 06:55
@gziolo gziolo mentioned this pull request Feb 22, 2018
3 tasks
@@ -1,9 +1,9 @@
.components-choice-menu {
.components-menu-items-group {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened #5218 to address it.


const element = (
const MoreMenu = () => (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this need to be changed to a function?

See also an explanation of this type of optimization: https://babeljs.io/docs/plugins/transform-react-constant-elements/

Copy link
Member Author

@gziolo gziolo Feb 23, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting. I haven't seen it before in the React docs.

This transform should be enabled only in production (e.g., just before minifying your code) because although it improves runtime performance, it makes warning messages more cryptic.

Can we enable the transform instead and leave all the low-level optimizations to Babel?

<EditorActions />
<MenuItemsGroup
label={ __( 'Tools' ) }
filterName="editPost.MoreMenu.tools"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conceptually-speaking, why do we need two things - plugin slots and filterable menus - to express the same idea of "add to this menu" ? As of current master, we have both in this menu, and it's not clear why I would use one or the other, or why one can't be satisfied by the other.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

<PluginMoreMenuGroup.Slot fillProps={ { onClose } } />
<MenuGroup
label={ __( 'Tools' ) }
filterName="editPost.MoreMenu.tools"
>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My guess is filterable menus were some of the earlier experiments, partly motivated by the emergence of @wordpress/hooks. They also felt cheaper (perhaps deceptively simple?). I'd say by now slots have established themselves as the standard extension method, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @gziolo I think he was talking about removing those at some point?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should remove those filters and replace the only occurrence of hook based extension with slot and fill. As @mcsf already pointed out, this was an early exploration which turned out to be suboptimal from developer’s standpoint.

I had it planned to refactor on my todos list but it was never a priority. I will take care of it this week to avoid confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Extensibility The ability to extend blocks or the editing experience [Feature] UI Components Impacts or related to the UI component system
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants