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

feat(vertical-navigation): Add the Vertical Navigation pattern #88

Merged

Conversation

mturley
Copy link
Collaborator

@mturley mturley commented Nov 27, 2017

What:

Creating the new Vertical Navigation component.

Why:

To bring patternfly-react one step closer to feature parity with patternfly-ng

How:

New components, factoring things to be as reusable as possible

Storybook: https://mturley.github.io/patternfly-react/?selectedKind=Vertical%20Navigation&selectedStory=Items%20as%20JSX&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybooks%2Fstorybook-addon-knobs

@mturley mturley self-assigned this Nov 27, 2017
@mturley mturley requested a review from priley86 November 27, 2017 23:11
@mturley
Copy link
Collaborator Author

mturley commented Nov 27, 2017

@ohadlevy, Serena told me that I should ping you when I had this pushed up. It's not quite done yet, i'm still in the process of refactoring things. I pushed my partial code so I can head home, but I plan to wrap up most of this tonight.

@priley86
Copy link
Member

@mturley It looks like it's still a bit early, but I think this is the right idea. I.m.o. the only component state we’ll need is the state which indicates whether the secondary/tertiary nav drawers are open, everything else can be indicated by props from the application/redux store (including what nav items are active). I like the approach w/ rendering the nav items as lists.

Look forward to reviewing it further once you are ready here...

@ohadlevy
Copy link
Member

/cc @amirfefer

@mturley mturley force-pushed the feature/vertical-navigation branch from f41321b to 07a0358 Compare December 1, 2017 16:47
@mturley
Copy link
Collaborator Author

mturley commented Dec 2, 2017

Sorry for the delay on this, I've had a few distractions. I just pushed a few more commits that complete the basic structure of this and include some refactoring I did to make the primary/secondary/tertiary levels all driven by one VerticalNavigationItem (the markup was similar enough at each level that the differences are logically laid out in the render function without foo much fuss). I think it's pretty clean.

Now I just need to finish getting any react-specific CSS tuned up, and address my last few TODO comments. Should be good to go on Monday.

My next PR will be at a faster pace-- I've had some new-hire tasks and other one-time distractions these first few weeks.

activeSecondary,
children,
topBannerContents,
notificationDrawer /* TODO notification drawer components? */,
Copy link
Member

Choose a reason for hiding this comment

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

I would leave this out and allow the application to add it separately. The drawer trigger should be added to the topBannerContents and notification drawer would be part of the app content.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well, that is sort of what I'm doing here already. The notification drawer is a child of the top banner, so it has to be rendered by this component (React doesn't allow external DOM modifications). So we just accept a prop notificationDrawer that is just the entire node tree to be rendered in that container. The application can pass a whole other component as that prop.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll remove my TODO though, I was wondering whether we wanted to drive it any more directly here. Sounds like we don't.

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 believe notificationDrawer needs to be a child of the top banner.

Copy link
Member

Choose a reason for hiding this comment

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

If it is part of the vertical navigation, it does buy you the correct top positioning and height otherwise it is not necessary, the application would then need to specify those values. We could handle that in the notification drawer component.

Just seems better to keep them separated to me. I'm OK either way though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I see. Okay. It was a child of the top banner in the pf-ng code and the PF core example markup. If we don't do that, I feel like we should make that change upstream maybe?

Copy link
Member

Choose a reason for hiding this comment

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

there is no upstream change necessary though. You can have it either way. There is just the preset position and height setting gained by having the drawer-pf a child of navbar-pf-vertical

const { hideTopBanner } = this.state;
this.setState({
hideTopBanner: !hideTopBanner,
});
Copy link
Member

Choose a reason for hiding this comment

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

This will need to notify the application as well. The main body content needs to respond to the collapse as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point. I'll add a handler that can be passed in for that.

// This class is confusingly named, but the logic is more readable.
'mobile-secondary-item-pf':
mobileItem && depth === 'primary' && showMobileTertiary,
// I don't know, that's just how this stuff was in patternfly-ng...
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, could have been named better but basically it is used to handle mobile navigation where only one of the menus (primary, secondary, or tertiary) are shown at a time (the navigation is drill down in mobile mode).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Makes sense. I'll change this comment to be a little less confused, haha.

/>
<span>{title}</span>
</div>
<ListGroup>
Copy link
Collaborator Author

@mturley mturley Dec 7, 2017

Choose a reason for hiding this comment

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

@priley86 , here is the cause of the <li>-inside-<li> warnings we are getting. This ListGroup sits inside a ListGroupItem, and renders ListGroupItem children.

Copy link
Member

Choose a reason for hiding this comment

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

I think you need to add componentClass="ul" here.

@priley86
Copy link
Member

priley86 commented Dec 7, 2017

@mturley do you mind rebasing w/ current master? I think something in index.js is misaligned. Getting the following:

ERROR in ./src/index.js
Module not found: Error: Can't resolve './components/VerticalNavigation' in 

@jeff-phillips-18
Copy link
Member

@mturley Looks like we need index.js in components/VerticalNavigation

'show-mobile-nav': showMobileNav,
})}
>
<ListGroup>
Copy link
Member

Choose a reason for hiding this comment

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

I think you need to add componentClass="ul" here.

/>
<span>{title}</span>
</div>
<ListGroup>
Copy link
Member

Choose a reason for hiding this comment

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

I think you need to add componentClass="ul" here.


VerticalNavigationItem.defaultProps = {
trackActiveState: true,
trackHoverState: true,
Copy link
Member

Choose a reason for hiding this comment

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

why are the defaults true here? Aren't these indicating the item is active or hovered on? Only one item at most should ever be active, same as hover.

[`${nextDepth}-nav-item-pf`]:
depth !== 'tertiary' && children && children.length > 0,
active: trackActiveState, // This is the only class we have at the tertiary depth.
'visible-xs-block': trackActiveState, // TODO is trackActiveState the right thing here, and is it named right?
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why 'visible-xs-block' set on active items (or ever).

handleTertiaryBlur,
handlePrimaryClick,
handleSecondaryClick,
handleTertiaryClick,
Copy link
Member

Choose a reason for hiding this comment

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

Why would an item have 3 levels of click handlers? Any one item would only ever be at one level right? Shouldn't it just have a handleClick, handleHover, handleBlur?

Not really sure why any item needs the handleHover or handleBlur callbacks. Shouldn't the hover state be maintained here? Also, you will find the need to have delays for the hover/blur handling when showing/hiding submenus.

@mturley mturley force-pushed the feature/vertical-navigation branch 2 times, most recently from d435940 to 2d2467e Compare December 10, 2017 19:49
@mturley
Copy link
Collaborator Author

mturley commented Dec 10, 2017

I'm almost done with this, I squashed all the commits so far and I'll squash again after I push the rest.

@jeff-phillips-18
Copy link
Member

@mturley Would it make sense to create this component w/o secondary or tertiary navigation support to begin with? This gets us partially there (and enough of the way for those w/o secondary menus) and able to try this out before adding the hover/pinned features.

Thoughts?

collapsedSecondaryNav: false,
collapsedTertiaryNav: false,
};
this.handleNavBarToggleClick = this.handleNavBarToggleClick.bind(this);
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

Choose a reason for hiding this comment

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

(see Wizard examples)

() => {
return (
<VerticalNavigation secondaryCollapsed={false} tertiaryCollapsed>
<VerticalNavigationItem title="Item 1" />
Copy link
Member

@priley86 priley86 Dec 12, 2017

Choose a reason for hiding this comment

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

This is a nit but can we expose the API as VerticalNavigation.Item ... see Wizard examples...it's just a consistency thing with the other complex components (both in PF React and React Bootstrap) where we have a lots of sub components.

@priley86
Copy link
Member

priley86 commented Dec 12, 2017

@mturley apologies - ignore my last comment about mockNavitems - I misread the code ;). I think it's nice providing both API surfaces like you have done.

@priley86
Copy link
Member

priley86 commented Dec 12, 2017

@mturley once you get closer on this, you may want to test w/ React Router. I don't know that we should necessarily assume that VerticalNavigationItem will be a direct child of VerticalNavigation (depending on how we set up the React Router Dom). Reason being is - typically you will see <Route> as a wrapper to any routable component which accepts a match property (as a function). The match property typically determines active state (based on the active route).

I started some examples of this here prior, but this is missing all of the other vert. nav features you've started in the implementation here. I would say just test this sooner than later ;->

https://github.com/patternfly/patternfly-react-demo-app/blob/flowjs/src/components/Nav/VerticalNav.js

https://github.com/patternfly/patternfly-react-demo-app/blob/flowjs/src/components/Nav/RouteNavItem.js

The React Router Dom is of course optional too... you can simply inject the current route state in a parent level wrapper (this might be easier). This would enable you to still use VerticalNavigationItems as direct children...
https://github.com/ReactTraining/react-router/blob/v3/docs/Introduction.md#getting-url-parameters

If the downstream product is not using React Router - then this is likely not an issue though...


const handleHover = {
primary: handlePrimaryHover,
secondary: handleSecondaryHover,
Copy link
Member

@priley86 priley86 Dec 13, 2017

Choose a reason for hiding this comment

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

Re-reading this bit... I almost wonder if splitting out Secondary and Tertiary into their own components makes more sense (as it seems it would split the components a bit better as far as props/handlers/etc, i.e.:

<VerticalNavigation >
   <VerticalNavigation.Item title="Item 1" secondaryCollapsed={false}>
      <VerticalNavigation.SecondaryItem title="Item 1-A" tertiaryCollapsed> 
         <VerticalNavigation.TertiaryItem title="Item 1-A-i">
      </VerticalNavigation.SecondaryItem> 
   <VerticalNavigation.Item>
</VerticalNavigation>         

It seems like this may split the logic a bit better and make it a bit easier to compose...
@jeff-phillips-18 @mturley thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

I may be over simplifying a bit though... not sure.

@mturley mturley force-pushed the feature/vertical-navigation branch 2 times, most recently from 666aa86 to d0bc6c9 Compare December 18, 2017 02:52
@mturley
Copy link
Collaborator Author

mturley commented Dec 18, 2017

@jeff-phillips-18 , sorry I didn't notice your comment earlier about doing primary-only. I think I will have everything working shortly, but if there are any further issues with secondary/tertiary stuff I will disable them for now and get this merged.

@mturley
Copy link
Collaborator Author

mturley commented Jan 30, 2018

Thanks @priley86. I pushed a few more minor tweaks from discussions with @jeff-phillips-18 (fixed corner cases around hover/blur timers). I guess that invalidated your approval. If you could re-approve when you get a chance that'd be great!

Copy link
Member

@jeff-phillips-18 jeff-phillips-18 left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for all the hard work that went into this @mturley !

@priley86
Copy link
Member

@mturley nice job on the fixes. Again I am OK to merge here. Another thing I noted with the controlled pattern here - we may be able to connect that to a redux-session or a redux local storage as an enhancement in the future. This works great for now though!

https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage

priley86
priley86 previously approved these changes Jan 31, 2018
@mturley
Copy link
Collaborator Author

mturley commented Jan 31, 2018

Thanks for the reviews guys. @priley86 I like the idea of using redux patterns for local storage, I do think though that even if we add that support, it should still be able to fall back on window.sessionStorage to support users who aren't using redux.

@priley86
Copy link
Member

@mturley sure - i think redux is an optional replacement for the consumer. valid point 👍

@serenamarie125
Copy link
Member

@jeff-phillips-18 @mturley just want to confirm that the strategy for this component was to match the core implementation, which can be found here: https://rawgit.com/patternfly/patternfly/master-dist/dist/tests/vertical-navigation-with-tertiary-pins.html

There is a difference between the Pinning implementation between core & angular. This PR matches the core implementation. Just noting here :)

serenamarie125
serenamarie125 previously approved these changes Feb 1, 2018
Copy link
Member

@serenamarie125 serenamarie125 left a comment

Choose a reason for hiding this comment

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

@mturley this looks great! Nice to see the different examples as well. I tried a number of different combinations and all looks good 👍

@jeff-phillips-18
Copy link
Member

Found a few issues with mobile mode.

  1. if I collapse (only icons) then go into mobile mode, the primary menu should show both icons and text
  2. if I collapse (only icons) then go into mobile mode, the tertiary menu gets displayed incorrectly
    image
  3. In mobile mode, the body content should have no left margin.

Copy link
Member

@jeff-phillips-18 jeff-phillips-18 left a comment

Choose a reason for hiding this comment

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

Seeing some issues in mobile

@mturley mturley force-pushed the feature/vertical-navigation branch from ae513f9 to 279a64b Compare February 2, 2018 19:14
@mturley
Copy link
Collaborator Author

mturley commented Feb 2, 2018

Fixed the mobile issues @jeff-phillips-18 was seeing.

@mturley
Copy link
Collaborator Author

mturley commented Feb 2, 2018

Aww every time I rebase on upstream master it dismisses all my shiny green approvals... @priley86 @serenamarie125 :)

@jeff-phillips-18 jeff-phillips-18 merged commit d0795c3 into patternfly:master Feb 2, 2018
@jeff-phillips-18
Copy link
Member

🎉

@mturley
Copy link
Collaborator Author

mturley commented Feb 2, 2018

avoskic

@mturley mturley deleted the feature/vertical-navigation branch February 2, 2018 21:39
HarikrishnanBalagopal pushed a commit to HarikrishnanBalagopal/patternfly-react that referenced this pull request Sep 29, 2021
* feat(deps): apply v4 updates

* [cleanup] add back missed storybook type pkgs

* [cleanup] make storybook work again
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.

9 participants