Skip to content

Commit

Permalink
[SpeedDial] Migrate to emotion (#25166)
Browse files Browse the repository at this point in the history
  • Loading branch information
m4theushw authored Mar 4, 2021
1 parent 888fd22 commit 11478a8
Show file tree
Hide file tree
Showing 27 changed files with 456 additions and 196 deletions.
3 changes: 2 additions & 1 deletion docs/pages/api-docs/speed-dial-action.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"icon": { "type": { "name": "node" } },
"id": { "type": { "name": "string" } },
"open": { "type": { "name": "bool" } },
"sx": { "type": { "name": "object" } },
"TooltipClasses": { "type": { "name": "object" } },
"tooltipOpen": { "type": { "name": "bool" } },
"tooltipPlacement": {
Expand Down Expand Up @@ -36,6 +37,6 @@
"filename": "/packages/material-ui/src/SpeedDialAction/SpeedDialAction.js",
"inheritance": { "component": "Tooltip", "pathname": "/api/tooltip/" },
"demos": "<ul><li><a href=\"/components/speed-dial/\">Speed Dial</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
5 changes: 3 additions & 2 deletions docs/pages/api-docs/speed-dial-icon.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"props": {
"classes": { "type": { "name": "object" } },
"icon": { "type": { "name": "node" } },
"openIcon": { "type": { "name": "node" } }
"openIcon": { "type": { "name": "node" } },
"sx": { "type": { "name": "object" } }
},
"name": "SpeedDialIcon",
"styles": {
Expand All @@ -15,6 +16,6 @@
"filename": "/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.js",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/speed-dial/\">Speed Dial</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
3 changes: 2 additions & 1 deletion docs/pages/api-docs/speed-dial.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"onOpen": { "type": { "name": "func" } },
"open": { "type": { "name": "bool" } },
"openIcon": { "type": { "name": "node" } },
"sx": { "type": { "name": "object" } },
"TransitionComponent": { "type": { "name": "elementType" }, "default": "Zoom" },
"transitionDuration": {
"type": {
Expand Down Expand Up @@ -47,6 +48,6 @@
"filename": "/packages/material-ui/src/SpeedDial/SpeedDial.js",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/speed-dial/\">Speed Dial</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"icon": "The icon to display in the SpeedDial Fab.",
"id": "This prop is used to help implement the accessibility logic. If you don&#39;t provide this prop. It falls back to a randomly generated id.",
"open": "If <code>true</code>, the component is shown.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/basics/#the-sx-prop\">`sx` page</a> for more details.",
"TooltipClasses": "<code>classes</code> prop applied to the <a href=\"/api/tooltip/\"><code>Tooltip</code></a> element.",
"tooltipOpen": "Make the tooltip always visible when the SpeedDial is open.",
"tooltipPlacement": "Placement of the tooltip.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"propDescriptions": {
"classes": "Override or extend the styles applied to the component. See <a href=\"#css\">CSS API</a> below for more details.",
"icon": "The icon to display.",
"openIcon": "The icon to display in the SpeedDial Floating Action Button when the SpeedDial is open."
"openIcon": "The icon to display in the SpeedDial Floating Action Button when the SpeedDial is open.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/basics/#the-sx-prop\">`sx` page</a> for more details."
},
"classDescriptions": {
"root": { "description": "Styles applied to the root element." },
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/speed-dial/speed-dial.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"onOpen": "Callback fired when the component requests to be open.<br><br><strong>Signature:</strong><br><code>function(event: object, reason: string) =&gt; void</code><br><em>event:</em> The event source of the callback.<br><em>reason:</em> Can be: <code>&quot;toggle&quot;</code>, <code>&quot;focus&quot;</code>, <code>&quot;mouseEnter&quot;</code>.",
"open": "If <code>true</code>, the component is shown.",
"openIcon": "The icon to display in the SpeedDial Fab when the SpeedDial is open.",
"sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the <a href=\"/system/basics/#the-sx-prop\">`sx` page</a> for more details.",
"TransitionComponent": "The component used for the transition. <a href=\"/components/transitions/#transitioncomponent-prop\">Follow this guide</a> to learn more about the requirements for this component.",
"transitionDuration": "The duration for the transition, in milliseconds. You may specify a single timeout for all transitions, or individually with an object.",
"TransitionProps": "Props applied to the transition element. By default, the element is based on this <a href=\"http://reactcommunity.org/react-transition-group/transition\"><code>Transition</code></a> component."
Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui/src/SpeedDial/SpeedDial.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as React from 'react';
import { SxProps } from '@material-ui/system';
import { Theme } from '../styles';
import { InternalStandardProps as StandardProps } from '..';
import { FabProps } from '../Fab';
import { TransitionHandlerProps, TransitionProps } from '../transitions';
Expand Down Expand Up @@ -83,6 +85,10 @@ export interface SpeedDialProps
* The icon to display in the SpeedDial Fab when the SpeedDial is open.
*/
openIcon?: React.ReactNode;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* The component used for the transition.
* [Follow this guide](/components/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
Expand Down
144 changes: 97 additions & 47 deletions packages/material-ui/src/SpeedDial/SpeedDial.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,46 @@ import * as React from 'react';
import { isFragment } from 'react-is';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { deepmerge } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import experimentalStyled from '../styles/experimentalStyled';
import useThemeProps from '../styles/useThemeProps';
import { duration } from '../styles/transitions';
import withStyles from '../styles/withStyles';
import Zoom from '../Zoom';
import Fab from '../Fab';
import capitalize from '../utils/capitalize';
import isMuiElement from '../utils/isMuiElement';
import useForkRef from '../utils/useForkRef';
import useControlled from '../utils/useControlled';
import speedDialClasses, { getSpeedDialUtilityClass } from './speedDialClasses';

const overridesResolver = (props, styles) => {
const { styleProps } = props;

return deepmerge(
{
...styles[`direction${capitalize(styleProps.direction)}`],
[`& .${speedDialClasses.fab}`]: styles.fab,
[`& .${speedDialClasses.actions}`]: {
...styles.actions,
...(!styleProps.open && styles.actionsClosed),
},
},
styles.root || {},
);
};

const useUtilityClasses = (styleProps) => {
const { classes, open, direction } = styleProps;

const slots = {
root: ['root', `direction${capitalize(direction)}`],
fab: ['fab'],
actions: ['actions', !open && 'actionsClosed'],
};

return composeClasses(slots, getSpeedDialUtilityClass, classes);
};

function getOrientation(direction) {
if (direction === 'up' || direction === 'down') {
Expand All @@ -34,72 +66,80 @@ function clamp(value, min, max) {
const dialRadius = 32;
const spacingActions = 16;

export const styles = (theme) => ({
/* Styles applied to the root element. */
root: {
zIndex: theme.zIndex.speedDial,
display: 'flex',
alignItems: 'center',
pointerEvents: 'none',
},
/* Styles applied to the Fab component. */
fab: {
pointerEvents: 'auto',
const SpeedDialRoot = experimentalStyled(
'div',
{},
{
name: 'MuiSpeedDial',
slot: 'Root',
overridesResolver,
},
/* Styles applied to the root element if direction="up" */
directionUp: {
)(({ theme, styleProps }) => ({
zIndex: theme.zIndex.speedDial,
display: 'flex',
alignItems: 'center',
pointerEvents: 'none',
...(styleProps.direction === 'up' && {
flexDirection: 'column-reverse',
'& $actions': {
[`& .${speedDialClasses.actions}`]: {
flexDirection: 'column-reverse',
marginBottom: -dialRadius,
paddingBottom: spacingActions + dialRadius,
},
},
/* Styles applied to the root element if direction="down" */
directionDown: {
}),
...(styleProps.direction === 'down' && {
flexDirection: 'column',
'& $actions': {
[`& .${speedDialClasses.actions}`]: {
flexDirection: 'column',
marginTop: -dialRadius,
paddingTop: spacingActions + dialRadius,
},
},
/* Styles applied to the root element if direction="left" */
directionLeft: {
}),
...(styleProps.direction === 'left' && {
flexDirection: 'row-reverse',
'& $actions': {
[`& .${speedDialClasses.actions}`]: {
flexDirection: 'row-reverse',
marginRight: -dialRadius,
paddingRight: spacingActions + dialRadius,
},
},
/* Styles applied to the root element if direction="right" */
directionRight: {
}),
...(styleProps.direction === 'right' && {
flexDirection: 'row',
'& $actions': {
[`& .${speedDialClasses.actions}`]: {
flexDirection: 'row',
marginLeft: -dialRadius,
paddingLeft: spacingActions + dialRadius,
},
},
/* Styles applied to the actions (`children` wrapper) element. */
actions: {
display: 'flex',
pointerEvents: 'auto',
},
/* Styles applied to the actions (`children` wrapper) element if `open={false}`. */
actionsClosed: {
}),
}));

const SpeedDialFab = experimentalStyled(
Fab,
{},
{ name: 'MuiSpeedDial', slot: 'Fab' },
)(() => ({
pointerEvents: 'auto',
}));

const SpeedDialActions = experimentalStyled(
'div',
{},
{ name: 'MuiSpeedDial', slot: 'Actions' },
)(({ styleProps }) => ({
display: 'flex',
pointerEvents: 'auto',
...(!styleProps.open && {
transition: 'top 0s linear 0.2s',
pointerEvents: 'none',
},
});
}),
}));

const SpeedDial = React.forwardRef(function SpeedDial(props, ref) {
const SpeedDial = React.forwardRef(function SpeedDial(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiSpeedDial' });
const {
ariaLabel,
FabProps: { ref: origDialButtonRef, ...FabProps } = {},
children: childrenProp,
classes,
className,
direction = 'up',
hidden = false,
Expand Down Expand Up @@ -129,6 +169,9 @@ const SpeedDial = React.forwardRef(function SpeedDial(props, ref) {
state: 'open',
});

const styleProps = { ...props, open, direction };
const classes = useUtilityClasses(styleProps);

const eventTimer = React.useRef();

React.useEffect(() => {
Expand Down Expand Up @@ -331,15 +374,16 @@ const SpeedDial = React.forwardRef(function SpeedDial(props, ref) {
});

return (
<div
className={clsx(classes.root, classes[`direction${capitalize(direction)}`], className)}
<SpeedDialRoot
className={clsx(classes.root, className)}
ref={ref}
role="presentation"
onKeyDown={handleKeyDown}
onBlur={handleClose}
onFocus={handleOpen}
onMouseEnter={handleOpen}
onMouseLeave={handleClose}
styleProps={styleProps}
{...other}
>
<TransitionComponent
Expand All @@ -348,7 +392,7 @@ const SpeedDial = React.forwardRef(function SpeedDial(props, ref) {
unmountOnExit
{...TransitionProps}
>
<Fab
<SpeedDialFab
color="primary"
aria-label={ariaLabel}
aria-haspopup="true"
Expand All @@ -358,21 +402,23 @@ const SpeedDial = React.forwardRef(function SpeedDial(props, ref) {
onClick={handleClick}
className={clsx(classes.fab, FabProps.className)}
ref={handleFabRef}
styleProps={styleProps}
>
{React.isValidElement(icon) && isMuiElement(icon, ['SpeedDialIcon'])
? React.cloneElement(icon, { open })
: icon}
</Fab>
</SpeedDialFab>
</TransitionComponent>
<div
<SpeedDialActions
id={`${id}-actions`}
role="menu"
aria-orientation={getOrientation(direction)}
className={clsx(classes.actions, { [classes.actionsClosed]: !open })}
styleProps={styleProps}
>
{children}
</div>
</div>
</SpeedDialActions>
</SpeedDialRoot>
);
});

Expand Down Expand Up @@ -460,6 +506,10 @@ SpeedDial.propTypes = {
* The icon to display in the SpeedDial Fab when the SpeedDial is open.
*/
openIcon: PropTypes.node,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* The component used for the transition.
* [Follow this guide](/components/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
Expand Down Expand Up @@ -489,4 +539,4 @@ SpeedDial.propTypes = {
TransitionProps: PropTypes.object,
};

export default withStyles(styles, { name: 'MuiSpeedDial' })(SpeedDial);
export default SpeedDial;
22 changes: 8 additions & 14 deletions packages/material-ui/src/SpeedDial/SpeedDial.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@ import * as React from 'react';
import { expect } from 'chai';
import { spy, useFakeTimers } from 'sinon';
import {
getClasses,
createMount,
createClientRender,
act,
fireEvent,
screen,
describeConformance,
describeConformanceV5,
} from 'test/utils';
import Icon from '@material-ui/core/Icon';
import SpeedDial from './SpeedDial';
import SpeedDialAction from '../SpeedDialAction';
import SpeedDial, { speedDialClasses as classes } from '@material-ui/core/SpeedDial';
import SpeedDialAction from '@material-ui/core/SpeedDialAction';

describe('<SpeedDial />', () => {
// StrictModeViolation: not using act(), prefer test/utils/createClientRender
const mount = createMount({ strict: false });
const render = createClientRender({ strict: false });
let classes;

const icon = <Icon>font_icon</Icon>;
const FakeAction = () => <div />;
Expand All @@ -28,21 +26,17 @@ describe('<SpeedDial />', () => {
ariaLabel: 'mySpeedDial',
};

before(() => {
classes = getClasses(
<SpeedDial {...defaultProps}>
<div />
</SpeedDial>,
);
});

describeConformance(<SpeedDial {...defaultProps} />, () => ({
describeConformanceV5(<SpeedDial {...defaultProps} />, () => ({
classes,
inheritComponent: 'div',
mount,
render,
refInstanceof: window.HTMLDivElement,
muiName: 'MuiSpeedDial',
testVariantProps: { direction: 'right' },
skip: [
'componentProp', // react-transition-group issue
'componentsProp',
'reactTestRenderer',
],
}));
Expand Down
Loading

0 comments on commit 11478a8

Please sign in to comment.