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

[WIP] create PopupState component #12330

Closed
wants to merge 9 commits into from

Conversation

jedwards1211
Copy link
Contributor

@jedwards1211 jedwards1211 commented Jul 29, 2018

Closes #12325

* or children if both are used
*/

const renderProps = ({ children, render }, ...props) => {
Copy link
Member

Choose a reason for hiding this comment

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

Most of the libraries I have seen seems to abandon the render property. What about not supporting it? So we save people asking themselves the question, "What's better between a and b?". Answering the question only provides a marginal gain.

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 sure wouldn't mind removing it, I only put it in there because some libs like react-powerplug seem to include it to appease people who think passing a child function is some kind of blasphemy

Copy link
Member

Choose a reason for hiding this comment

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

Well, I'm happy about being as opinionated as React.createContext API.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh that's true. I'm glad the React folks decided to do that, because there were some really dogmatic people complaining that children should always be a React.Node.

It's about the same as how in all of the Angular vs. React vs. Vue type videos I've seen, people said they didn't like React because something about putting HTML in JavaScript didn't feel right to them. They didn't have any more substantive criticism than that.

@jedwards1211 jedwards1211 changed the title [WIP] create MenuState component [WIP] create PopupState component Jul 30, 2018
@oliviertassinari oliviertassinari added the new feature New feature or request label Jul 30, 2018
@oliviertassinari
Copy link
Member

oliviertassinari commented Jul 31, 2018

@jedwards1211 How do you want to move forward? I haven't given a close look at the pull request yet but it looks solid. I see two options:
Option 1. I continue the effort with the variant thing. do some tweak where I seem some potential for improvement, let you have a final look.
Option 2. I do a deep review of the pull request, comment on all the points I see missing, try to provide guidance on how I see the variant come to life.
Let me know.

@jedwards1211
Copy link
Contributor Author

@oliviertassinari I mainly just need to read about ARIA to see if we're missing any other props. Do you know of anything off the top of your head?

@jedwards1211
Copy link
Contributor Author

@oliviertassinari I went ahead and added a variant property.

I also injected a few more useful props to the child function:

  • toggle
  • setOpen
  • bindToggle

I haven't figured out if any more ARIA properties are needed yet. If you know of any well-organized ARIA guides for popups, let me know.

@jedwards1211
Copy link
Contributor Author

The CI failed in the "Should not have any git not staged" section...I'm not sure what that's talking about, I would never expect there to be unstaged files in a CI environment.

@jedwards1211
Copy link
Contributor Author

Also how can I prevent the generated API docs from saying "all other properties will be spread to the root element (native element)"? In this case there is no root element, and all other properties are simply ignored.

@oliviertassinari
Copy link
Member

oliviertassinari commented Aug 1, 2018

If you know of any well-organized ARIA guides for popups

@jedwards1211 Regarding the ARIA, I think that we can replicate what's documented on each variant documentation pages.

The CI failed in the

The markdown is automatically generated. The CI checks that it's up-to-date. You can run yarn docs:api.

In this case there is no root element, and all other properties are simply ignored.

We have the same problem with some other components. I think that you can add the exactProp proptype helper so people realize it at runtime. As for updating the description, well, it's a different story. We can ignore it for this pull request as it's a broader issue.

@jedwards1211
Copy link
Contributor Author

jedwards1211 commented Aug 1, 2018

Ah, maybe a better name for that CI section would be "All API docs should be up-to-date"?

I noticed in one of the menu demos, the trigger component uses aria-controls="lock-menu" instead of aria-owns when the menu is open. Seems like I should add aria-controls to bindTrigger and bindToggle?

I also noticed that the Popover demo doesn't use any relevant aria properties.

@jedwards1211
Copy link
Contributor Author

jedwards1211 commented Aug 1, 2018

@oliviertassinari don't merge this yet, I have a better idea about how to support a broader range of use cases like hover interaction. Instead of injecting bindTrigger/bindToggle, I would export helper functions as follows (note also that we don't need the variant prop). How should I generate docs for these exported functions?

export function bindTrigger({ isOpen, open, popupId }) {
  return {
    'aria-owns': isOpen ? popupId : null,
    'aria-haspopup': true,
    onClick: open,
  };
}

export function bindToggle({ isOpen, toggle, popupId }) {
  return {
    'aria-owns': isOpen ? popupId : null,
    'aria-haspopup': true,
    onClick: toggle,
  };
}

export function bindHover({ isOpen, open, close, popupId }) {
  return {
    'aria-owns': isOpen ? popupId : null,
    'aria-haspopup': true,
    onMouseEnter: open,
    onMouseLeave: close,
  };
}

export function bindPopover({ isOpen, anchorEl, close, popupId }) {
  return {
    id: popupId,
    anchorEl,
    open: isOpen,
    onClose: close,
  };
}

export const bindMenu = bindPopover;

export function bindPopper({ isOpen, anchorEl, popupId }) {
  return {
    id: popupId,
    anchorEl,
    open: isOpen,
  };
}

Then usage looks like this:

import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Popover from '@material-ui/core/Popover';
import PopupState, { bindHover, bindPopover } from '@material-ui/core/PopupState';

const styles = theme => ({
  popover: {
    pointerEvents: 'none',
  },
  paper: {
    padding: theme.spacing.unit,
  },
});

const PopoverPopupState = ({ classes }) => (
  <PopupState popupId="demoPopover">
    {(popupState) => (
      <div>
        <Typography {...bindHover(popupState)}>
          Open Popover
        </Typography>
        <Popover
          {...bindPopover(popupState)}
          className={classes.popover}
          classes={{
            paper: classes.paper,
          }}
          anchorOrigin={{
            vertical: 'bottom',
            horizontal: 'center',
          }}
          transformOrigin={{
            vertical: 'top',
            horizontal: 'center',
          }}
        >
          <Typography className={classes.typography}>The content of the Popover.</Typography>
        </Popover>
      </div>
    )}
  </PopupState>
);

PopoverPopupState.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(PopoverPopupState);

@jedwards1211
Copy link
Contributor Author

Not cool, eslint-plugin-react:

// Handler function for onClick prop key must begin with 'handle' (react/jsx-handler-names)
<MenuItem onClick={popupState.close}>Test</MenuItem>

@jedwards1211
Copy link
Contributor Author

jedwards1211 commented Aug 2, 2018

I'm going to go ahead and close this in favor of the new API design I made. If you guys disagree for whatever reason let me know. I see the following advantages to the new design:

  • Supports hover as well as click to open and click to toggle
  • Easier to type with TS or Flow
  • More tree-shakeable (unused bindX functions can be tree-shaken away)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants