Skip to content

Commit

Permalink
feat: add variant: 'dialog' and bindDialog
Browse files Browse the repository at this point in the history
fix #90
  • Loading branch information
jedwards1211 committed May 11, 2022
1 parent 6533b92 commit e7ee393
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 118 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ For MUI v4 you'll need `material-ui-popup-state@^1.9.3`. Use `^2.0.0` and up for
<!-- toc -->

- [material-ui-popup-state](#material-ui-popup-state)
- [Using MUI v4?](#using-mui-v4)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Examples with React Hooks](#examples-with-react-hooks)
Expand All @@ -34,7 +35,7 @@ For MUI v4 you'll need `material-ui-popup-state@^1.9.3`. Use `^2.0.0` and up for
- [Bind Functions](#bind-functions)
- [`usePopupState`](#usepopupstate)
- [`usePopupState` Props](#usepopupstate-props)
- [`variant` (`'popover'` or `'popper'`, **required**)](#variant-popover-or-popper-required)
- [`variant` (`'popover'`, `'popper'`, or `'dialog'`, **required**)](#variant-popover-popper-or-dialog-required)
- [`popupId` (`string`, **optional** but strongly encouraged)](#popupid-string-optional-but-strongly-encouraged)
- [`disableAutoFocus` (`boolean`, **optional**)](#disableautofocus-boolean-optional)
- [`usePopupState` return value](#usepopupstate-return-value)
Expand All @@ -46,7 +47,7 @@ For MUI v4 you'll need `material-ui-popup-state@^1.9.3`. Use `^2.0.0` and up for
- [Render Props API](#render-props-api)
- [Bind Functions](#bind-functions-1)
- [`PopupState` Props](#popupstate-props)
- [`variant` (`'popover'` or `'popper'`, **required**)](#variant-popover-or-popper-required-1)
- [`variant` (`'popover'`, `'popper'`, or `'dialog'`, **required**)](#variant-popover-popper-or-dialog-required-1)
- [`popupId` (`string`, **optional** but strongly encouraged)](#popupid-string-optional-but-strongly-encouraged-1)
- [`disableAutoFocus` (`boolean`, **optional**)](#disableautofocus-boolean-optional-1)
- [`children` (`(popupState: InjectedProps) => ?React.Node`, **required**)](#children-popupstate-injectedprops--reactnode-required)
Expand Down Expand Up @@ -215,6 +216,7 @@ connect components easily:
- `bindMenu`: creates props to control a `Menu` component.
- `bindPopover`: creates props to control a `Popover` component.
- `bindPopper`: creates props to control a `Popper` component.
- `bindDialog`: creates props to control a `Dialog` component.
- `bindTrigger`: creates props for a component that opens the popup when clicked.
- `bindContextMenu`: creates props for a component that opens the popup on when right clicked (`contextmenu` event).
- `bindToggle`: creates props for a component that toggles the popup when clicked.
Expand Down Expand Up @@ -261,7 +263,7 @@ This is a [Custom Hook](https://reactjs.org/docs/hooks-custom.html) that uses `u

## `usePopupState` Props

### `variant` (`'popover'` or `'popper'`, **required**)
### `variant` (`'popover'`, `'popper'`, or `'dialog'`, **required**)

Use `'popover'` if your popup is a `Popover` or `Menu`; use `'popper'` if your
popup is a `Popper`.
Expand Down Expand Up @@ -493,6 +495,7 @@ connect components easily:
- `bindMenu`: creates props to control a `Menu` component.
- `bindPopover`: creates props to control a `Popover` component.
- `bindPopper`: creates props to control a `Popper` component.
- `bindDialog`: creates props to control a `Dialog` component.
- `bindTrigger`: creates props for a component that opens the popup when clicked.
- `bindContextMenu`: creates props for a component that opens the popup on when right clicked (`contextmenu` event).
- `bindToggle`: creates props for a component that toggles the popup when clicked.
Expand Down Expand Up @@ -532,7 +535,7 @@ export default MenuPopupState

## `PopupState` Props

### `variant` (`'popover'` or `'popper'`, **required**)
### `variant` (`'popover'`, `'popper'`, or `'dialog'`, **required**)

Use `'popover'` if your popup is a `Popover` or `Menu`; use `'popper'` if your
popup is a `Popper`.
Expand Down
12 changes: 12 additions & 0 deletions demo/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ import CascadingHoverMenus from './examples/CascadingHoverMenus'
import CascadingHoverMenusCode from '!!raw-loader!./examples/CascadingHoverMenus'
import CascadingHoverMenusHooks from './examples/CascadingHoverMenus.hooks'
import CascadingHoverMenusHooksCode from '!!raw-loader!./examples/CascadingHoverMenus.hooks'
import Dialog from './examples/Dialog'
import DialogCode from '!!raw-loader!./examples/Dialog'
import DialogHooks from './examples/Dialog.hooks'
import DialogHooksCode from '!!raw-loader!./examples/Dialog.hooks'
import Demo from './Demo'
import Typography from '@mui/material/Typography'
import { withStyles } from '@mui/styles'
Expand Down Expand Up @@ -133,6 +137,14 @@ const Root = ({ classes }) => (
hooksExample={<CascadingHoverMenusHooks />}
hooksCode={CascadingHoverMenusHooksCode}
/>
<Demo
title="Dialog"
headerId="dialog"
example={<Dialog />}
code={DialogCode}
hooksExample={<DialogHooks />}
hooksCode={DialogHooksCode}
/>
</div>
</ThemeProvider>
</StyledEngineProvider>
Expand Down
48 changes: 48 additions & 0 deletions demo/examples/Dialog.hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as React from 'react'
import Button from '@mui/material/Button'
import Dialog from '@mui/material/Dialog'
import DialogTitle from '@mui/material/DialogTitle'
import DialogContent from '@mui/material/DialogContent'
import DialogContentText from '@mui/material/DialogContentText'
import DialogActions from '@mui/material/DialogActions'
import {
usePopupState,
bindTrigger,
bindDialog,
} from 'material-ui-popup-state/hooks'

const DialogPopupState = () => {
const popupState = usePopupState({
variant: 'dialog',
})
return (
<React.Fragment>
<Button variant="contained" {...bindTrigger(popupState)}>
Open Dialog
</Button>
<Dialog
{...bindDialog(popupState)}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Use Google's location service?"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Let Google help apps determine location. This means sending
anonymous location data to Google, even when no apps are running.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={popupState.close}>Disagree</Button>
<Button onClick={popupState.close} autoFocus>
Agree
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
)
}

export default DialogPopupState
43 changes: 43 additions & 0 deletions demo/examples/Dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as React from 'react'
import Button from '@mui/material/Button'
import Dialog from '@mui/material/Dialog'
import DialogTitle from '@mui/material/DialogTitle'
import DialogContent from '@mui/material/DialogContent'
import DialogContentText from '@mui/material/DialogContentText'
import DialogActions from '@mui/material/DialogActions'
import PopupState, { bindTrigger, bindDialog } from 'material-ui-popup-state'

const DialogPopupState = () => (
<PopupState variant="dialog">
{(popupState) => (
<React.Fragment>
<Button variant="contained" {...bindTrigger(popupState)}>
Open Dialog
</Button>
<Dialog
{...bindDialog(popupState)}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Use Google's location service?"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Let Google help apps determine location. This means sending
anonymous location data to Google, even when no apps are running.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={popupState.close}>Disagree</Button>
<Button onClick={popupState.close} autoFocus>
Agree
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
)}
</PopupState>
)

export default DialogPopupState
73 changes: 39 additions & 34 deletions src/core.d.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { SyntheticEvent } from 'react'
import { SyntheticEvent, MouseEvent, TouchEvent, FocusEvent } from 'react'

export type Variant = 'popover' | 'popper'
export type Variant = 'popover' | 'popper' | 'dialog'

export type PopupState = {
open: (eventOrAnchorEl?: SyntheticEvent<any> | HTMLElement | null) => void
close: () => void
toggle: (eventOrAnchorEl?: SyntheticEvent<any> | HTMLElement | null) => void
onMouseLeave: (event: SyntheticEvent<any>) => void
onMouseLeave: (event: MouseEvent<any>) => void
setOpen: (
open: boolean,
eventOrAnchorEl?: SyntheticEvent<any> | HTMLElement
Expand Down Expand Up @@ -37,7 +37,7 @@ export const initCoreState: CoreState
export function createPopupState(options: {
state: CoreState
setState: (state: Partial<CoreState>) => any
popupId: string | undefined
popupId?: string | null
variant: Variant
parentPopupState?: PopupState | null
disableAutoFocus?: boolean | null
Expand All @@ -53,17 +53,21 @@ export function anchorRef<T = HTMLElement>(
popupState: PopupState
): (popupState: T | undefined) => void

type ControlAriaProps = {
'aria-controls'?: string
'aria-describedby'?: string
'aria-haspopup'?: true
}

/**
* Creates props for a component that opens the popup when clicked.
*
* @param {object} popupState the argument passed to the child function of
* `PopupState`
*/
export function bindTrigger(popupState: PopupState): {
'aria-controls'?: string | undefined
'aria-describedby'?: string | undefined
'aria-haspopup': true | undefined
onClick: (event: SyntheticEvent<any>) => void
export function bindTrigger(popupState: PopupState): ControlAriaProps & {
onClick: (event: MouseEvent<any>) => void
onTouchStart: (event: TouchEvent<any>) => void
}

/**
Expand All @@ -72,11 +76,9 @@ export function bindTrigger(popupState: PopupState): {
* @param {object} popupState the argument passed to the child function of
* `PopupState`
*/
export function bindToggle(popupState: PopupState): {
'aria-controls'?: string
'aria-describedby'?: string
'aria-haspopup': true | undefined
onClick: (event: SyntheticEvent<any>) => void
export function bindToggle(popupState: PopupState): ControlAriaProps & {
onClick: (event: MouseEvent<any>) => void
onTouchStart: (event: TouchEvent<any>) => void
}

/**
Expand All @@ -85,11 +87,8 @@ export function bindToggle(popupState: PopupState): {
* @param {object} popupState the argument passed to the child function of
* `PopupState`
*/
export function bindContextMenu(popupState: PopupState): {
'aria-controls'?: string | undefined
'aria-describedby'?: string | undefined
'aria-haspopup': true | undefined
onContextMenu: (event: SyntheticEvent<any>) => void
export function bindContextMenu(popupState: PopupState): ControlAriaProps & {
onContextMenu: (event: MouseEvent<any>) => void
}

/**
Expand All @@ -98,12 +97,10 @@ export function bindContextMenu(popupState: PopupState): {
* @param {object} popupState the argument passed to the child function of
* `PopupState`
*/
export function bindHover(popupState: PopupState): {
'aria-controls'?: string
'aria-describedby'?: string
'aria-haspopup': true | undefined
onMouseEnter: (event: SyntheticEvent<any>) => any
onMouseLeave: (event: SyntheticEvent<any>) => any
export function bindHover(popupState: PopupState): ControlAriaProps & {
onTouchStart: (event: TouchEvent<any>) => void
onMouseEnter: (event: MouseEvent<any>) => void
onMouseLeave: (event: MouseEvent<any>) => void
}

/**
Expand All @@ -112,12 +109,9 @@ export function bindHover(popupState: PopupState): {
* @param {object} popupState the argument passed to the child function of
* `PopupState`
*/
export function bindFocus(popupState: PopupState): {
'aria-controls'?: string
'aria-describedby'?: string
'aria-haspopup': true | undefined
onFocus: (event: SyntheticEvent<any>) => any
onBlur: (event: SyntheticEvent<any>) => any
export function bindFocus(popupState: PopupState): ControlAriaProps & {
onFocus: (event: FocusEvent<any>) => void
onBlur: (event: FocusEvent<any>) => void
}

/**
Expand All @@ -131,7 +125,7 @@ export function bindPopover(popupState: PopupState): {
anchorEl: HTMLElement | undefined
open: boolean
onClose: () => void
onMouseLeave: (event: SyntheticEvent<any>) => void
onMouseLeave: (event: MouseEvent<any>) => void
disableAutoFocus?: boolean
disableEnforceFocus?: boolean
disableRestoreFocus?: boolean
Expand All @@ -148,7 +142,7 @@ export function bindMenu(popupState: PopupState): {
anchorEl: HTMLElement | undefined
open: boolean
onClose: () => void
onMouseLeave: (event: SyntheticEvent<any>) => void
onMouseLeave: (event: MouseEvent<any>) => void
autoFocus?: boolean
disableAutoFocusItem?: boolean
disableAutoFocus?: boolean
Expand All @@ -166,5 +160,16 @@ export function bindPopper(popupState: PopupState): {
id: string | undefined
anchorEl: HTMLElement | undefined
open: boolean
onMouseLeave: (event: SyntheticEvent<any>) => void
onMouseLeave: (event: MouseEvent<any>) => void
}

/**
* Creates props for a `Dialog` component.
*
* @param {object} popupState the argument passed to the child function of
* `PopupState`
*/
export function bindDialog(popupState: PopupState): {
open: boolean
onClose: (event: SyntheticEvent<any>) => void
}
Loading

0 comments on commit e7ee393

Please sign in to comment.