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

[SpeedDial] Rework part of the logic #17301

Merged
merged 6 commits into from
Sep 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions docs/pages/api/speed-dial-action.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ You can learn more about the difference by [reading this guide](/guides/minimizi

| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| <span class="prop-name">ButtonProps</span> | <span class="prop-type">object</span> | | Props applied to the [`Button`](/api/button/) component. |
| <span class="prop-name">classes</span> | <span class="prop-type">object</span> | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| <span class="prop-name">delay</span> | <span class="prop-type">number</span> | <span class="prop-default">0</span> | Adds a transition delay, to allow a series of SpeedDialActions to be animated. |
| <span class="prop-name">icon</span> | <span class="prop-type">node</span> | | The Icon to display in the SpeedDial Floating Action Button. |
| <span class="prop-name">FabProps</span> | <span class="prop-type">object</span> | | Props applied to the [`Fab`](/api/fab/) component. |
| <span class="prop-name">icon</span> | <span class="prop-type">node</span> | | The Icon to display in the SpeedDial Fab. |
| <span class="prop-name">TooltipClasses</span> | <span class="prop-type">object</span> | | Classes applied to the [`Tooltip`](/api/tooltip/) element. |
| <span class="prop-name">tooltipOpen</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | Make the tooltip always visible when the SpeedDial is open. |
| <span class="prop-name">tooltipPlacement</span> | <span class="prop-type">'bottom-end'<br>&#124;&nbsp;'bottom-start'<br>&#124;&nbsp;'bottom'<br>&#124;&nbsp;'left-end'<br>&#124;&nbsp;'left-start'<br>&#124;&nbsp;'left'<br>&#124;&nbsp;'right-end'<br>&#124;&nbsp;'right-start'<br>&#124;&nbsp;'right'<br>&#124;&nbsp;'top-end'<br>&#124;&nbsp;'top-start'<br>&#124;&nbsp;'top'</span> | <span class="prop-default">'left'</span> | Placement of the tooltip. |
| <span class="prop-name">tooltipTitle</span> | <span class="prop-type">node</span> | | Label to display in the tooltip. |

The component cannot hold a ref.
The `ref` is forwarded to the root element.

Any other props supplied will be provided to the root element ([Tooltip](/api/tooltip/)).

Expand All @@ -44,8 +44,13 @@ Any other props supplied will be provided to the root element ([Tooltip](/api/to

| Rule name | Global class | Description |
|:-----|:-------------|:------------|
| <span class="prop-name">button</span> | <span class="prop-name">MuiSpeedDialAction-button</span> | Styles applied to the `Button` component.
| <span class="prop-name">buttonClosed</span> | <span class="prop-name">MuiSpeedDialAction-buttonClosed</span> | Styles applied to the `Button` component if `open={false}`.
| <span class="prop-name">fab</span> | <span class="prop-name">MuiSpeedDialAction-fab</span> | Styles applied to the Fab component.
| <span class="prop-name">fabClosed</span> | <span class="prop-name">MuiSpeedDialAction-fabClosed</span> | Styles applied to the Fab component if `open={false}`.
| <span class="prop-name">staticTooltip</span> | <span class="prop-name">MuiSpeedDialAction-staticTooltip</span> | Styles applied to the root element if `tooltipOpen={true}`.
| <span class="prop-name">staticTooltipClosed</span> | <span class="prop-name">MuiSpeedDialAction-staticTooltipClosed</span> | Styles applied to the root element if `tooltipOpen={true}` and `open={false}`.
| <span class="prop-name">staticTooltipLabel</span> | <span class="prop-name">MuiSpeedDialAction-staticTooltipLabel</span> | Styles applied to the static tooltip label if `tooltipOpen={true}`.
| <span class="prop-name">tooltipPlacementLeft</span> | <span class="prop-name">MuiSpeedDialAction-tooltipPlacementLeft</span> | Styles applied to the root if `tooltipOpen={true}` and `tooltipPlacement="left"``
| <span class="prop-name">tooltipPlacementRight</span> | <span class="prop-name">MuiSpeedDialAction-tooltipPlacementRight</span> | Styles applied to the root if `tooltipOpen={true}` and `tooltipPlacement="right"``

You can override the style of the component thanks to one of these customization points:

Expand Down
2 changes: 1 addition & 1 deletion docs/pages/api/speed-dial-icon.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| <span class="prop-name">icon</span> | <span class="prop-type">node</span> | | The icon to display in the SpeedDial Floating Action Button. |
| <span class="prop-name">openIcon</span> | <span class="prop-type">node</span> | | The icon to display in the SpeedDial Floating Action Button when the SpeedDial is open. |

The component cannot hold a ref.
The `ref` is forwarded to the root element.

Any other props supplied will be provided to the root element (native element).

Expand Down
21 changes: 11 additions & 10 deletions docs/pages/api/speed-dial.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,22 @@ You can learn more about the difference by [reading this guide](/guides/minimizi

| Name | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| <span class="prop-name required">ariaLabel&nbsp;*</span> | <span class="prop-type">string</span> | | The aria-label of the `Button` element. Also used to provide the `id` for the `SpeedDial` element and its children. |
| <span class="prop-name">ButtonProps</span> | <span class="prop-type">object</span> | <span class="prop-default">{}</span> | Props applied to the [`Button`](/api/button/) element. |
| <span class="prop-name required">ariaLabel&nbsp;*</span> | <span class="prop-type">string</span> | | The aria-label of the button element. Also used to provide the `id` for the `SpeedDial` element and its children. |
| <span class="prop-name">children</span> | <span class="prop-type">node</span> | | SpeedDialActions to display when the SpeedDial is `open`. |
| <span class="prop-name">classes</span> | <span class="prop-type">object</span> | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| <span class="prop-name">direction</span> | <span class="prop-type">'down'<br>&#124;&nbsp;'left'<br>&#124;&nbsp;'right'<br>&#124;&nbsp;'up'</span> | <span class="prop-default">'up'</span> | The direction the actions open relative to the floating action button. |
| <span class="prop-name">FabProps</span> | <span class="prop-type">object</span> | <span class="prop-default">{}</span> | Props applied to the [`Fab`](/api/fab/) element. |
| <span class="prop-name">hidden</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the SpeedDial will be hidden. |
| <span class="prop-name">icon</span> | <span class="prop-type">node</span> | | The icon to display in the SpeedDial Floating Action Button. The `SpeedDialIcon` component provides a default Icon with animation. |
| <span class="prop-name">icon</span> | <span class="prop-type">node</span> | | The icon to display in the SpeedDial Fab. The `SpeedDialIcon` component provides a default Icon with animation. |
| <span class="prop-name">onClose</span> | <span class="prop-type">func</span> | | Callback fired when the component requests to be closed.<br><br>**Signature:**<br>`function(event: object, key: string) => void`<br>*event:* The event source of the callback.<br>*key:* The key pressed. |
| <span class="prop-name">onOpen</span> | <span class="prop-type">func</span> | | Callback fired when the component requests to be open.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name required">open&nbsp;*</span> | <span class="prop-type">bool</span> | | If `true`, the SpeedDial is open. |
| <span class="prop-name">openIcon</span> | <span class="prop-type">node</span> | | The icon to display in the SpeedDial Floating Action Button when the SpeedDial is open. |
| <span class="prop-name">openIcon</span> | <span class="prop-type">node</span> | | The icon to display in the SpeedDial Fab when the SpeedDial is open. |
| <span class="prop-name">TransitionComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">Zoom</span> | The component used for the transition. |
| <span class="prop-name">transitionDuration</span> | <span class="prop-type">number<br>&#124;&nbsp;{ appear?: number, enter?: number, exit?: number }</span> | <span class="prop-default">{ enter: duration.enteringScreen, exit: duration.leavingScreen,}</span> | The duration for the transition, in milliseconds. You may specify a single timeout for all transitions, or individually with an object. |
| <span class="prop-name">TransitionProps</span> | <span class="prop-type">object</span> | | Props applied to the `Transition` element. |

The component cannot hold a ref.
The `ref` is forwarded to the root element.

Any other props supplied will be provided to the root element (native element).

Expand All @@ -50,11 +51,11 @@ Any other props supplied will be provided to the root element (native element).
| Rule name | Global class | Description |
|:-----|:-------------|:------------|
| <span class="prop-name">root</span> | <span class="prop-name">MuiSpeedDial-root</span> | Styles applied to the root element.
| <span class="prop-name">fab</span> | <span class="prop-name">MuiSpeedDial-fab</span> | Styles applied to the Button component.
| <span class="prop-name">directionUp</span> | <span class="prop-name">MuiSpeedDial-directionUp</span> | Styles applied to the root and action container elements when direction="up"
| <span class="prop-name">directionDown</span> | <span class="prop-name">MuiSpeedDial-directionDown</span> | Styles applied to the root and action container elements when direction="down"
| <span class="prop-name">directionLeft</span> | <span class="prop-name">MuiSpeedDial-directionLeft</span> | Styles applied to the root and action container elements when direction="left"
| <span class="prop-name">directionRight</span> | <span class="prop-name">MuiSpeedDial-directionRight</span> | Styles applied to the root and action container elements when direction="right"
| <span class="prop-name">fab</span> | <span class="prop-name">MuiSpeedDial-fab</span> | Styles applied to the Fab component.
| <span class="prop-name">directionUp</span> | <span class="prop-name">MuiSpeedDial-directionUp</span> | Styles applied to the root if direction="up"
| <span class="prop-name">directionDown</span> | <span class="prop-name">MuiSpeedDial-directionDown</span> | Styles applied to the root if direction="down"
| <span class="prop-name">directionLeft</span> | <span class="prop-name">MuiSpeedDial-directionLeft</span> | Styles applied to the root if direction="left"
| <span class="prop-name">directionRight</span> | <span class="prop-name">MuiSpeedDial-directionRight</span> | Styles applied to the root if direction="right"
| <span class="prop-name">actions</span> | <span class="prop-name">MuiSpeedDial-actions</span> | Styles applied to the actions (`children` wrapper) element.
| <span class="prop-name">actionsClosed</span> | <span class="prop-name">MuiSpeedDial-actionsClosed</span> | Styles applied to the actions (`children` wrapper) element if `open={false}`.

Expand Down
6 changes: 3 additions & 3 deletions docs/pages/api/tooltip.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| <span class="prop-name">interactive</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | Makes a tooltip interactive, i.e. will not close when the user hovers over the tooltip before the `leaveDelay` is expired. |
| <span class="prop-name">leaveDelay</span> | <span class="prop-type">number</span> | <span class="prop-default">0</span> | The number of milliseconds to wait before hiding the tooltip. This prop won't impact the leave touch delay (`leaveTouchDelay`). |
| <span class="prop-name">leaveTouchDelay</span> | <span class="prop-type">number</span> | <span class="prop-default">1500</span> | The number of milliseconds after the user stops touching an element before hiding the tooltip. |
| <span class="prop-name">onClose</span> | <span class="prop-type">func</span> | | Callback fired when the tooltip requests to be closed.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name">onOpen</span> | <span class="prop-type">func</span> | | Callback fired when the tooltip requests to be open.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name">onClose</span> | <span class="prop-type">func</span> | | Callback fired when the component requests to be closed.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name">onOpen</span> | <span class="prop-type">func</span> | | Callback fired when the component requests to be open.<br><br>**Signature:**<br>`function(event: object) => void`<br>*event:* The event source of the callback. |
| <span class="prop-name">open</span> | <span class="prop-type">bool</span> | | If `true`, the tooltip is shown. |
| <span class="prop-name">placement</span> | <span class="prop-type">'bottom-end'<br>&#124;&nbsp;'bottom-start'<br>&#124;&nbsp;'bottom'<br>&#124;&nbsp;'left-end'<br>&#124;&nbsp;'left-start'<br>&#124;&nbsp;'left'<br>&#124;&nbsp;'right-end'<br>&#124;&nbsp;'right-start'<br>&#124;&nbsp;'right'<br>&#124;&nbsp;'top-end'<br>&#124;&nbsp;'top-start'<br>&#124;&nbsp;'top'</span> | <span class="prop-default">'bottom'</span> | Tooltip placement. |
| <span class="prop-name">PopperProps</span> | <span class="prop-type">object</span> | | Props applied to the [`Popper`](/api/popper/) element. |
| <span class="prop-name required">title&nbsp;*</span> | <span class="prop-type">node</span> | | Tooltip title. Zero-length titles string are never displayed. |
| <span class="prop-name">TransitionComponent</span> | <span class="prop-type">elementType</span> | <span class="prop-default">Grow</span> | The component used for the transition. |
| <span class="prop-name">TransitionProps</span> | <span class="prop-type">object</span> | | Props applied to the `Transition` element. |

The component cannot hold a ref.
The `ref` is forwarded to the root element.

Any other props supplied will be provided to the root element (native element).

Expand Down
21 changes: 6 additions & 15 deletions docs/src/pages/components/speed-dial/OpenIconSpeedDial.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import EditIcon from '@material-ui/icons/Edit';
const useStyles = makeStyles(theme => ({
root: {
height: 380,
transform: 'translateZ(0px)',
flexGrow: 1,
},
speedDial: {
position: 'absolute',
bottom: theme.spacing(2),
right: theme.spacing(3),
right: theme.spacing(2),
},
}));

Expand All @@ -36,18 +38,11 @@ export default function OpenIconSpeedDial() {
const [hidden, setHidden] = React.useState(false);

const handleVisibility = () => {
setOpen(false);
setHidden(prevHidden => !prevHidden);
};

const handleClick = () => {
setOpen(prevOpen => !prevOpen);
};

const handleOpen = () => {
if (!hidden) {
setOpen(true);
}
setOpen(true);
};

const handleClose = () => {
Expand All @@ -62,20 +57,16 @@ export default function OpenIconSpeedDial() {
className={classes.speedDial}
hidden={hidden}
icon={<SpeedDialIcon openIcon={<EditIcon />} />}
onBlur={handleClose}
onClick={handleClick}
onClose={handleClose}
onFocus={handleOpen}
onMouseEnter={handleOpen}
onMouseLeave={handleClose}
onOpen={handleOpen}
open={open}
>
{actions.map(action => (
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipTitle={action.name}
onClick={handleClick}
onClick={handleClose}
Copy link
Member

Choose a reason for hiding this comment

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

Might it be more helpful to have a click handler that shows how to identify which action has been clicked, before it calls onClose?

Copy link
Member

@oliviertassinari oliviertassinari Sep 11, 2019

Choose a reason for hiding this comment

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

It could help, it would make the demo a bit more verbose, but could teach people a valuable pattern.

Copy link
Member

@mbrookes mbrookes Sep 11, 2019

Choose a reason for hiding this comment

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

From (past) personal experience, it's the kind of thing React beginners struggle with. I think it might be worth a little verbosity.

Copy link
Member

@oliviertassinari oliviertassinari Sep 11, 2019

Choose a reason for hiding this comment

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

Yes, I think that people can leverage index based handler when displaying data from the server, for instance, in the case of inbox (R.I.P.), the most frequent contacts. Or in the case of Google Calendar, I would expect each action to have a named custom handler.

Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure how to action this comment. I would expect most people to have a fixed set of options (not using an array). However, our demo is using an array for the sake of minimizing the demo length. I believe these two objectives contradict themselves.

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 the point is that the click handler does not handle each action differently which should be the most common use case. Otherwise why have a speed dial if every action does the same (which only closes at the moment). I would expect that you want to dispatch some action. It would be nice if this demo would handle that case.

At least this is how I understood @mbrookes

Copy link
Member

Choose a reason for hiding this comment

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

Ok thanks, this sounds good 👍

Copy link
Member

Choose a reason for hiding this comment

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

@eps1lon Yeah, that's the crux of it. I took it from @oliviertassinari's comment that in real usage you wouldn't use a mapped array, but would compose each action component. If each then calls a different click handler, the issue goes away.

I had pictured a common handler that dispatches a different event according to the calling action.

Copy link
Member

Choose a reason for hiding this comment

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

Just use an inline handler that captures the action. A mapped array is the first iteration you would do. The rest is premature optimization.

Copy link
Member

Choose a reason for hiding this comment

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

I'm going to merge, I think that we can apply the handler changes in another pull request :).

/>
))}
</SpeedDial>
Expand Down
77 changes: 77 additions & 0 deletions docs/src/pages/components/speed-dial/OpenIconSpeedDial.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react';
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import SpeedDial from '@material-ui/lab/SpeedDial';
import SpeedDialIcon from '@material-ui/lab/SpeedDialIcon';
import SpeedDialAction from '@material-ui/lab/SpeedDialAction';
import FileCopyIcon from '@material-ui/icons/FileCopyOutlined';
import SaveIcon from '@material-ui/icons/Save';
import PrintIcon from '@material-ui/icons/Print';
import ShareIcon from '@material-ui/icons/Share';
import DeleteIcon from '@material-ui/icons/Delete';
import EditIcon from '@material-ui/icons/Edit';

const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
height: 380,
transform: 'translateZ(0px)',
flexGrow: 1,
},
speedDial: {
position: 'absolute',
bottom: theme.spacing(2),
right: theme.spacing(2),
},
}),
);

const actions = [
{ icon: <FileCopyIcon />, name: 'Copy' },
{ icon: <SaveIcon />, name: 'Save' },
{ icon: <PrintIcon />, name: 'Print' },
{ icon: <ShareIcon />, name: 'Share' },
{ icon: <DeleteIcon />, name: 'Delete' },
];

export default function OpenIconSpeedDial() {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const [hidden, setHidden] = React.useState(false);

const handleVisibility = () => {
setHidden(prevHidden => !prevHidden);
};

const handleOpen = () => {
setOpen(true);
};

const handleClose = () => {
setOpen(false);
};

return (
<div className={classes.root}>
<Button onClick={handleVisibility}>Toggle Speed Dial</Button>
<SpeedDial
ariaLabel="SpeedDial openIcon example"
className={classes.speedDial}
hidden={hidden}
icon={<SpeedDialIcon openIcon={<EditIcon />} />}
onClose={handleClose}
onOpen={handleOpen}
open={open}
>
{actions.map(action => (
<SpeedDialAction
key={action.name}
icon={action.icon}
tooltipTitle={action.name}
onClick={handleClose}
/>
))}
</SpeedDial>
</div>
);
}
23 changes: 8 additions & 15 deletions docs/src/pages/components/speed-dial/SpeedDialTooltipOpen.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Backdrop from '@material-ui/core/Backdrop';
import SpeedDial from '@material-ui/lab/SpeedDial';
import SpeedDialIcon from '@material-ui/lab/SpeedDialIcon';
import SpeedDialAction from '@material-ui/lab/SpeedDialAction';
Expand All @@ -13,11 +14,13 @@ import DeleteIcon from '@material-ui/icons/Delete';
const useStyles = makeStyles(theme => ({
root: {
height: 380,
transform: 'translateZ(0px)',
flexGrow: 1,
},
speedDial: {
position: 'absolute',
bottom: theme.spacing(2),
right: theme.spacing(3),
right: theme.spacing(2),
},
}));

Expand All @@ -35,18 +38,11 @@ export default function SpeedDialTooltipOpen() {
const [hidden, setHidden] = React.useState(false);

const handleVisibility = () => {
setOpen(false);
setHidden(prevHidden => !prevHidden);
};

const handleClick = () => {
setOpen(prevOpen => !prevOpen);
};

const handleOpen = () => {
if (!hidden) {
setOpen(true);
}
setOpen(true);
};

const handleClose = () => {
Expand All @@ -56,17 +52,14 @@ export default function SpeedDialTooltipOpen() {
return (
<div className={classes.root}>
<Button onClick={handleVisibility}>Toggle Speed Dial</Button>
<Backdrop open={open} />
<SpeedDial
ariaLabel="SpeedDial tooltip example"
className={classes.speedDial}
hidden={hidden}
icon={<SpeedDialIcon />}
onBlur={handleClose}
onClick={handleClick}
onClose={handleClose}
onFocus={handleOpen}
onMouseEnter={handleOpen}
onMouseLeave={handleClose}
onOpen={handleOpen}
open={open}
>
{actions.map(action => (
Expand All @@ -75,7 +68,7 @@ export default function SpeedDialTooltipOpen() {
icon={action.icon}
tooltipTitle={action.name}
tooltipOpen
onClick={handleClick}
onClick={handleClose}
/>
))}
</SpeedDial>
Expand Down
Loading