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

✨ [bento][amp-sidebar] Add nav toolbar component on Preact side only #33244

Merged
merged 15 commits into from
Mar 24, 2021

Conversation

krdwan
Copy link
Contributor

@krdwan krdwan commented Mar 12, 2021

3/17
Updated the design to listen on the MediaQueryList returned from the window.matchMedia call instead of listening on the window (per review comments).


Amp-sidebar Tracker: #31366

Preact side of nav toolbar feature as discussed in Bento standup on 3/11
Design doc: Design Doc

To do:

  • update type file
  • add tests
  • update storybook
  • follow up PR with amp side (added to tracker for tracking)

toolbar,
'toolbar-target': toolbarTarget,
children,
...rest
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add an as prop when I do the AMP mode PR

@krdwan krdwan marked this pull request as ready for review March 12, 2021 21:04
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Outdated Show resolved Hide resolved
extensions/amp-sidebar/1.0/component.js Show resolved Hide resolved

return (
<>
<nav ref={ref} toolbar={toolbar} toolbar-target={toolbarTarget} {...rest}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
<nav ref={ref} toolbar={toolbar} toolbar-target={toolbarTarget} {...rest}>
<nav ref={ref} toolbar={toolbar} toolbarTarget={toolbarTarget} {...rest}>

Copy link
Contributor Author

@krdwan krdwan Mar 18, 2021

Choose a reason for hiding this comment

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

So I've updated the prop value from toolbar-target to toolbarTarget. This is the rendered output and should stay as toolbar-target (this is the actual HTML attribute) that gets rendered out. (Should be in kebab case).

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it important for it to be rendered out in kebab case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Html attributes are in kebab case? So the output would look like this:

<nav toolbar="(max-width: 500px)" toolbar-target="toolbar-target">...

whereas if we use camel case here it would output like this:

<nav toolbar="(max-width: 500px)" toolbartarget="toolbar-target">...

Also the first one is aligned with what our 0.1 code would look like :)

extensions/amp-sidebar/1.0/component.type.js Outdated Show resolved Hide resolved
Comment on lines 90 to 107

return (
<main>
<SidebarWithActions
side={side}
style={{color: foregroundColor, backgroundColor}}
backdropStyle={{backgroundColor: backdropColor}}
>
<SidebarToolbar toolbar={toolbarMedia} toolbar-target="toolbar-target">
<ul>
<li>Toolbar Item 1</li>
<li>Toolbar Item 2</li>
</ul>
</SidebarToolbar>
</SidebarWithActions>
<div id="toolbar-target"></div>
</main>
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is the toolbarTarget as ref idea:

Suggested change
return (
<main>
<SidebarWithActions
side={side}
style={{color: foregroundColor, backgroundColor}}
backdropStyle={{backgroundColor: backdropColor}}
>
<SidebarToolbar toolbar={toolbarMedia} toolbar-target="toolbar-target">
<ul>
<li>Toolbar Item 1</li>
<li>Toolbar Item 2</li>
</ul>
</SidebarToolbar>
</SidebarWithActions>
<div id="toolbar-target"></div>
</main>
);
const targetRef = useRef(null);
return (
<main>
<SidebarWithActions
side={side}
style={{color: foregroundColor, backgroundColor}}
backdropStyle={{backgroundColor: backdropColor}}
>
<SidebarToolbar toolbar={toolbarMedia} toolbarTarget={targetRef}>
<ul>
<li>Toolbar Item 1</li>
<li>Toolbar Item 2</li>
</ul>
</SidebarToolbar>
</SidebarWithActions>
<div ref={targetRef}></div>
</main>
);

Then your createPortal line would look like:
{matches && toolbarTarget.current && createPortal(children, toolbarTarget.current)}

I'm actually not sure if it's advisable to pass a ref like this, and usually indicates that some outer context may be helpful to manage things more explicitly... But the current approach of querying the document doesn't allow for updating the portalled parent i.e. if the same id gets reassigned to a different element between renders.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see, I'm open to it either way. Let's see if anyone else feels strongly about it. If not, we can table it for now and explore further as a follow up.

// Must also check mounted as of #33244. This is because previously
// sidebarElement and backdropElement would not be rendered when
// mounted is false. This is no longer the case.
if (!mounted || !sidebarElement || !backdropElement || !side) {
return;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a check for mounted here. Per the comment, we don't want animations running in an unmounted state. Previously checking sidebarElement and backdropElement refs were enough since they were never rendered in unmounted state.

const isOpened = (sidebarElement) => {
return !sidebarElement.className.includes('unmounted');
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How the unit tests check whether the sidebar is opened or not must be updated throughout the test.

extensions/amp-sidebar/1.0/component.js Show resolved Hide resolved
Comment on lines 166 to 170
className={objstr({
[backdropClassName]: backdropClassName,
[classes.backdrop]: true,
[classes.defaultBackdropStyles]: true,
})}
Copy link
Member

Choose a reason for hiding this comment

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

nit: Place constant true values at the beginning

Suggested change
className={objstr({
[backdropClassName]: backdropClassName,
[classes.backdrop]: true,
[classes.defaultBackdropStyles]: true,
})}
className={objstr({
[classes.backdrop]: true,
[classes.defaultBackdropStyles]: true,
[backdropClassName]: backdropClassName,
})}

Also: if backdrop and defaultBackdropStyles don't occur independently, merge them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Updated to put true values at the top. Regarding the backdrop and defaultBackdropStyles, the reason these are split out is because the default ones are meant to be overridable by the user, whereas the backdrop class has styles that are built in to the sidebar. I sort of like having them split out to emphasize the distinction, but let me know if you feel strongly about it!

Copy link
Member

Choose a reason for hiding this comment

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

I don't know if our JSS transform supports this (try it?) but how about exposing a single classname, but split them in definition anyhow?

// these can overridden
const defaultBackdropStyles = {
  ...
};

const backdrop = {
  // x: "... !important",
  ...defaultBackdropStyles,
};

export {..., backdrop, ...};

Copy link
Member

Choose a reason for hiding this comment

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

also, in backdrop: shouldn't this be !important?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmmm.. it doesn't seem to like it. See below -

image

You're right, I've moved zIndex to be configurable!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I went ahead and merged for now, but let me know if you think there should be any other changes and I can follow up!

</div>
</>
)
<div className={objstr({[classes.unmounted]: !mounted})} part="wrapper">
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not apply this class to ContainWrapper?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ContainWrapper does not contain the backdrop so I wanted the class to apply to everything. Is there something else I'm missing?


return (
<>
<nav ref={ref} toolbar={toolbar} toolbar-target={toolbarTarget} {...rest}>
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is it important for it to be rendered out in kebab case?

Copy link
Contributor

@jridgewell jridgewell left a comment

Choose a reason for hiding this comment

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

LGTM

extensions/amp-sidebar/1.0/component.js Show resolved Hide resolved
return;
}

const mediaQueryList = window.matchMedia(toolbar);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we rename toolbar to be more descriptive? It's a media query, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That works, I've updated it to mediaQueryProp internally (within the component). I think we should keep the prop name toolbar externally since it matches with the existing API for 0.1. (In 0.1 the user would specify a toolbar as such:)

<nav toolbar="(media-query)" toolbar-target="elementID">

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants