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

Site Editor: make close button replaceable #22001

Merged
merged 3 commits into from
May 4, 2020

Conversation

vindl
Copy link
Member

@vindl vindl commented Apr 30, 2020

Description

The aim of this is to address the first part of #20929, namely making it easy to extend and replace the existing close button (W Icon) in site and post editor. Currently the code is contained to site editor only, but if it makes sense I will extend this approach to post editor too.

In order to allow for adding custom components the slot area was added in place of the existing close button. If no fills are provided it will render the default Close button, otherwise it will replace it with available fills.

For example, that could be achieved with the following code in the plugins:

registerPlugin( 'edit-site', {
    render() {
        return (
            <MainDashboardButton>
	        <CustomCloseButton />
	    </MainDashboardButton>
        );
    },
} );

How has this been tested?

  1. Smoke testing with above POC code in site editor.
  2. There should be no visual changes if the PR is used as is.
  3. If you provide some custom fills, the default Close button should be replaced with you custom component.
  4. Make sure that the case with multiple fills/plugins also works as expected.

Screenshots

76769084-40539500-679c-11ea-9aa2-8829d2e80b82

Types of changes

Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.


__experimentalSiteEditorCloseArea.Slot = Slot;

export default __experimentalSiteEditorCloseArea;
Copy link
Member Author

Choose a reason for hiding this comment

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

I need to come up with a better name for this. :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah thats a tough one... should we replace Area with SlotFill ? or maybe there is a better term someone can suggest.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it's bad.

But, since this is the "home button", maybe __experimentalSiteEditorHomeButton?

Either one works IMO.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I'd avoid referring to "close" or any implicit action and try to be a bit more semantic (something like MainDashboardButton perhaps).

Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed to MainDashboardButton in 555b399532aa0e2a02bbc07d24ce9c3f22d0d868.

@github-actions
Copy link

github-actions bot commented Apr 30, 2020

Size Change: +105 B (0%)

Total Size: 819 kB

Filename Size Change
build/edit-site/index.js 11.5 kB +105 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.02 kB 0 B
build/annotations/index.js 3.62 kB 0 B
build/api-fetch/index.js 4.08 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 6.6 kB 0 B
build/block-directory/style-rtl.css 760 B 0 B
build/block-directory/style.css 761 B 0 B
build/block-editor/index.js 101 kB 0 B
build/block-editor/style-rtl.css 10.2 kB 0 B
build/block-editor/style.css 10.2 kB 0 B
build/block-library/editor-rtl.css 7.08 kB 0 B
build/block-library/editor.css 7.08 kB 0 B
build/block-library/index.js 115 kB 0 B
build/block-library/style-rtl.css 7.22 kB 0 B
build/block-library/style.css 7.23 kB 0 B
build/block-library/theme-rtl.css 683 B 0 B
build/block-library/theme.css 685 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 48.1 kB 0 B
build/components/index.js 179 kB 0 B
build/components/style-rtl.css 16.9 kB 0 B
build/components/style.css 16.9 kB 0 B
build/compose/index.js 6.66 kB 0 B
build/core-data/index.js 11.4 kB 0 B
build/data-controls/index.js 1.28 kB 0 B
build/data/index.js 8.44 kB 0 B
build/date/index.js 5.47 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 3.1 kB 0 B
build/edit-navigation/index.js 4.05 kB 0 B
build/edit-navigation/style-rtl.css 485 B 0 B
build/edit-navigation/style.css 485 B 0 B
build/edit-post/index.js 28.1 kB 0 B
build/edit-post/style-rtl.css 12.2 kB 0 B
build/edit-post/style.css 12.2 kB 0 B
build/edit-site/style-rtl.css 5.18 kB 0 B
build/edit-site/style.css 5.18 kB 0 B
build/edit-widgets/index.js 7.77 kB 0 B
build/edit-widgets/style-rtl.css 4.67 kB 0 B
build/edit-widgets/style.css 4.66 kB 0 B
build/editor/editor-styles-rtl.css 428 B 0 B
build/editor/editor-styles.css 431 B 0 B
build/editor/index.js 44.3 kB 0 B
build/editor/style-rtl.css 5.07 kB 0 B
build/editor/style.css 5.08 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.64 kB 0 B
build/format-library/style-rtl.css 502 B 0 B
build/format-library/style.css 502 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 712 B 0 B
build/keyboard-shortcuts/index.js 2.51 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.13 kB 0 B
build/list-reusable-blocks/style-rtl.css 226 B 0 B
build/list-reusable-blocks/style.css 226 B 0 B
build/media-utils/index.js 5.29 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 616 B 0 B
build/nux/style.css 613 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.5 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 14.8 kB 0 B
build/server-side-render/index.js 2.67 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.28 kB 0 B
build/url/index.js 4.02 kB 0 B
build/viewport/index.js 1.84 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.18 kB 0 B

compressed-size-action

Copy link
Contributor

@Addison-Stavlo Addison-Stavlo left a comment

Choose a reason for hiding this comment

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

From a functionality standpoint this seems to work well!

The button continues to work as expected without any additions. Then by adding the filter/registration like you mentioned, I am able to override the button:

Screen Shot 2020-04-30 at 3 56 40 PM

Yay slot fills! 🎉

Copy link
Contributor

@epiqueras epiqueras left a comment

Choose a reason for hiding this comment

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

I don't think we should register a new plugin and filter for this.

It would be more straightforward just to use a Slot that renders FullscreenModeClose if it doesn't have any fills.

I think @mtias and @youknowriad have more experience with this, so let's see what they think.


__experimentalSiteEditorCloseArea.Slot = Slot;

export default __experimentalSiteEditorCloseArea;
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think it's bad.

But, since this is the "home button", maybe __experimentalSiteEditorHomeButton?

Either one works IMO.

@@ -21,6 +22,10 @@ function FullscreenModeClose() {
return null;
}

if ( applyFilters( 'siteEditor.closeButton.remove', false ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the convention is to use the full function name.

siteEditor.fullscreenModeClose.remove

Copy link
Member Author

Choose a reason for hiding this comment

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

I removed the filter in the latest refactor so this is no longer relevant.

@@ -13,6 +13,7 @@ import { render } from '@wordpress/element';
*/
import './hooks';
import './store';
import './plugins';
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure it matters, but edit-post imports hooks, then plugins, then the store. We should probably mirror that just to be safe since these have side effects.

Copy link
Member Author

Choose a reason for hiding this comment

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

Also removed the plugins file in the refactor so this is no longer present.

@vindl
Copy link
Member Author

vindl commented Apr 30, 2020

It would be more straightforward just to use a Slot that renders FullscreenModeClose if it doesn't have any fills.

I was trying that option too but couldn't quite get to a satisfactory state with it, because FullscreenModeClose is also a fill, so the slot is never empty by default. Is there an existing example of that somewhere in the codebase?

Arguably the approach with optional removal is more versatile, because it also covers use-cases where someone might want to keep the button and add some other components next to it (not sure if this is desirable though?). Also in your case it's not clear what the expected behavior should be if multiple fills are provided by 3rd party plugins? Consistently with first operation, I'd expect only one fill will be shown, but that wouldn't be the case. And if we try to enforce it we end up needing something like priorities, which sounds very similar to a filters at that point. :)

@epiqueras
Copy link
Contributor

I was trying that option too but couldn't quite get to a satisfactory state with it, because FullscreenModeClose is also a fill, so the slot is never empty by default. Is there an existing example of that somewhere in the codebase?

Use the render prop:

function PostStatus( { isOpened, onTogglePanel } ) {
return (
<PanelBody
className="edit-post-post-status"
title={ __( 'Status & visibility' ) }
opened={ isOpened }
onToggle={ onTogglePanel }
>
<PluginPostStatusInfo.Slot>
{ ( fills ) => (
<>
<PostVisibility />
<PostSchedule />
<PostFormat />
<PostSticky />
<PostPendingStatus />
<PostSlug />
<PostAuthor />
{ fills }
<PostTrash />
</>
) }
</PluginPostStatusInfo.Slot>
</PanelBody>
);
}

it also covers use-cases where someone might want to keep the button and add some other components next to it (not sure if this is desirable though?)

I don't even think the space is big enough for that, but they can always import the component and compose it themselves. Leaving it there is also assuming that whatever they "add" should come after and not before/between/etc. In rendering order.

Also in your case it's not clear what the expected behavior should be if multiple fills are provided by 3rd party plugins?

They all render, like usually.

Consistently with first operation, I'd expect only one fill will be shown, but that wouldn't be the case. And if we try to enforce it we end up needing something like priorities, which sounds very similar to a filters at that point. :)

That's not consistent. Having a "default" fill does not imply that only one fill can show at a time.

To cater to multiple plugins like that, you would need to filter the whole fill/button, but relying on that pattern and "priorities" doesn't scale well, and I think we try to avoid it where possible.

@vindl
Copy link
Member Author

vindl commented May 1, 2020

Use the render prop:

Thanks! I'll look into this next.

@vindl vindl force-pushed the update/close-button-extensible branch from 146717f to 555b399 Compare May 4, 2020 15:56
@vindl
Copy link
Member Author

vindl commented May 4, 2020

@epiqueras I removed the filter in the latest update, now it only relies on the presence of Fills. I also updated the PR summary and testing instructions to reflect this.

@vindl vindl force-pushed the update/close-button-extensible branch from 555b399 to 566c91a Compare May 4, 2020 16:10
@gziolo
Copy link
Member

gziolo commented May 4, 2020

You could also use withFilters HOC that wraps the default button which would work essentially the same with less code. @mtias do you have any preference? We have several filters that are used in places where we allow customizations like this (taxonomy, featured image, media upload, BlockEdit, etc). The approach with SlotFill is also interesting and I don’t remember if it was ever considered.

@vindl
Copy link
Member Author

vindl commented May 4, 2020

You could also use withFilters HOC that wraps the default button which would work essentially the same with less code. @mtias do you have any preference? We have several filters that are used in places where we allow customizations like this (taxonomy, featured image, media upload, BlockEdit, etc).

Thanks! We discussed the option of going with filters before and decided against it. From what I understood we are trying to limit their usage (@youknowriad might be able to provide more context here). From a developer experience standpoint, I think SlotFills are easier to use.

The approach with SlotFill is also interesting and I don’t remember if it was ever considered.

Based on my search through the codebase I don't think it has been used exactly in this form. Still, I think it is a cool pattern for replacing default components that we could use more in the future. It might even make sense to modify createSlotFill so that it can accept an optional parameter which would be the default component to render when no fills are provided.

@vindl vindl merged commit 1766e13 into master May 4, 2020
@vindl vindl deleted the update/close-button-extensible branch May 4, 2020 18:42
@github-actions github-actions bot added this to the Gutenberg 8.1 milestone May 4, 2020
@mtias
Copy link
Member

mtias commented May 4, 2020

Would we want to make MainDashboardButton.Slot unstable for a release or two? Also maybe we should expose an icon prop on it to make it easier to just swap it while retaining behaviour.

@epiqueras
Copy link
Contributor

Would we want to make MainDashboardButton.Slot unstable for a release or two?

I don't think its warranted, but it doesn't hurt to be careful.

Also maybe we should expose an icon prop on it to make it easier to just swap it while retaining behaviour.

Great idea! @vindl do you want to follow up with that?

@gziolo
Copy link
Member

gziolo commented May 4, 2020

Would we want to make MainDashboardButton.Slot unstable for a release or two?

Documentation is highly appreciated as well.

@vindl
Copy link
Member Author

vindl commented May 4, 2020

@epiqueras @mtias sure, I'll handle both of these items in a follow-up.

@@ -62,7 +62,7 @@ export default function Header( { openEntitiesSavedStates } ) {

return (
<div className="edit-site-header">
<FullscreenModeClose />
<MainDashboardButton.Slot />
Copy link
Contributor

Choose a reason for hiding this comment

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

see #22027

We're moving away from regular slots. Would you mind doing a small refactor here (bubblesVirtually slots don't support children render function

Copy link
Member Author

Choose a reason for hiding this comment

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

@youknowriad Actually I'm not sure how to achieve the same effect with this, given that it relies on children render function to handle the default case when no fills are provided?

Copy link
Contributor

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.

Thanks, refactored this in #22179.

@gziolo gziolo added the Needs Dev Note Requires a developer note for a major WordPress release cycle label May 6, 2020
return <FullscreenModeClose />;
}

return <> { fills } </>;
Copy link
Member

Choose a reason for hiding this comment

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

These spaces are significant, and cause React to create two additional text node children.

https://codepen.io/aduth/pen/ZEbrOYY

Suggested change
return <> { fills } </>;
return <>{ fills }</>;

Copy link
Member

Choose a reason for hiding this comment

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

Good catch

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for pointing it out! I removed this code in #22179.

@vindl
Copy link
Member Author

vindl commented May 7, 2020

Refactored this in #22179 according to the suggestions above.

@youknowriad youknowriad mentioned this pull request May 14, 2020
53 tasks
@ellatrix ellatrix mentioned this pull request Jul 3, 2020
12 tasks
@cguntur cguntur mentioned this pull request Oct 14, 2020
17 tasks
@vindl vindl removed the Needs Dev Note Requires a developer note for a major WordPress release cycle label Oct 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants