diff --git a/docs/pages/api-docs/speed-dial-action.json b/docs/pages/api-docs/speed-dial-action.json
index 6c7a508c90e1cb..6ea304af1311c9 100644
--- a/docs/pages/api-docs/speed-dial-action.json
+++ b/docs/pages/api-docs/speed-dial-action.json
@@ -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": {
@@ -36,6 +37,6 @@
"filename": "/packages/material-ui/src/SpeedDialAction/SpeedDialAction.js",
"inheritance": { "component": "Tooltip", "pathname": "/api/tooltip/" },
"demos": "
",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/pages/api-docs/speed-dial-icon.json b/docs/pages/api-docs/speed-dial-icon.json
index e477af61435bf1..72c28346b293e0 100644
--- a/docs/pages/api-docs/speed-dial-icon.json
+++ b/docs/pages/api-docs/speed-dial-icon.json
@@ -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": {
@@ -15,6 +16,6 @@
"filename": "/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.js",
"inheritance": null,
"demos": "",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/pages/api-docs/speed-dial.json b/docs/pages/api-docs/speed-dial.json
index 804c415d64e8dd..ab8e43aac6819a 100644
--- a/docs/pages/api-docs/speed-dial.json
+++ b/docs/pages/api-docs/speed-dial.json
@@ -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": {
@@ -47,6 +48,6 @@
"filename": "/packages/material-ui/src/SpeedDial/SpeedDial.js",
"inheritance": null,
"demos": "",
- "styledComponent": false,
+ "styledComponent": true,
"cssComponent": false
}
diff --git a/docs/translations/api-docs/speed-dial-action/speed-dial-action.json b/docs/translations/api-docs/speed-dial-action/speed-dial-action.json
index e72832fd29fe9d..9a276d7199877e 100644
--- a/docs/translations/api-docs/speed-dial-action/speed-dial-action.json
+++ b/docs/translations/api-docs/speed-dial-action/speed-dial-action.json
@@ -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't provide this prop. It falls back to a randomly generated id.",
"open": "If true
, the component is shown.",
+ "sx": "The system prop that allows defining system overrides as well as additional CSS styles. See the `sx` page for more details.",
"TooltipClasses": "classes
prop applied to the Tooltip
element.",
"tooltipOpen": "Make the tooltip always visible when the SpeedDial is open.",
"tooltipPlacement": "Placement of the tooltip.",
diff --git a/docs/translations/api-docs/speed-dial-icon/speed-dial-icon.json b/docs/translations/api-docs/speed-dial-icon/speed-dial-icon.json
index 3950ebb3809f15..e620a411ef6232 100644
--- a/docs/translations/api-docs/speed-dial-icon/speed-dial-icon.json
+++ b/docs/translations/api-docs/speed-dial-icon/speed-dial-icon.json
@@ -3,7 +3,8 @@
"propDescriptions": {
"classes": "Override or extend the styles applied to the component. See CSS API 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 `sx` page for more details."
},
"classDescriptions": {
"root": { "description": "Styles applied to the root element." },
diff --git a/docs/translations/api-docs/speed-dial/speed-dial.json b/docs/translations/api-docs/speed-dial/speed-dial.json
index c2ad427cce9584..226f09910dd595 100644
--- a/docs/translations/api-docs/speed-dial/speed-dial.json
+++ b/docs/translations/api-docs/speed-dial/speed-dial.json
@@ -12,6 +12,7 @@
"onOpen": "Callback fired when the component requests to be open.
Signature:
function(event: object, reason: string) => void
event: The event source of the callback.
reason: Can be: "toggle"
, "focus"
, "mouseEnter"
.",
"open": "If true
, 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 `sx` page for more details.",
"TransitionComponent": "The component used for the transition. Follow this guide 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 Transition
component."
diff --git a/packages/material-ui/src/SpeedDial/SpeedDial.d.ts b/packages/material-ui/src/SpeedDial/SpeedDial.d.ts
index a39bfb847053ff..e16ffb4b715a68 100644
--- a/packages/material-ui/src/SpeedDial/SpeedDial.d.ts
+++ b/packages/material-ui/src/SpeedDial/SpeedDial.d.ts
@@ -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';
@@ -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;
/**
* The component used for the transition.
* [Follow this guide](/components/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
diff --git a/packages/material-ui/src/SpeedDial/SpeedDial.js b/packages/material-ui/src/SpeedDial/SpeedDial.js
index 6451b0fb309cfb..3daec5a6535b2b 100644
--- a/packages/material-ui/src/SpeedDial/SpeedDial.js
+++ b/packages/material-ui/src/SpeedDial/SpeedDial.js
@@ -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') {
@@ -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,
@@ -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(() => {
@@ -331,8 +374,8 @@ const SpeedDial = React.forwardRef(function SpeedDial(props, ref) {
});
return (
-
-
{React.isValidElement(icon) && isMuiElement(icon, ['SpeedDialIcon'])
? React.cloneElement(icon, { open })
: icon}
-
+
-
{children}
-
-
+
+
);
});
@@ -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.
@@ -489,4 +539,4 @@ SpeedDial.propTypes = {
TransitionProps: PropTypes.object,
};
-export default withStyles(styles, { name: 'MuiSpeedDial' })(SpeedDial);
+export default SpeedDial;
diff --git a/packages/material-ui/src/SpeedDial/SpeedDial.test.js b/packages/material-ui/src/SpeedDial/SpeedDial.test.js
index 7a776fe23a83d3..85d787e4344ce7 100644
--- a/packages/material-ui/src/SpeedDial/SpeedDial.test.js
+++ b/packages/material-ui/src/SpeedDial/SpeedDial.test.js
@@ -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('', () => {
// StrictModeViolation: not using act(), prefer test/utils/createClientRender
const mount = createMount({ strict: false });
const render = createClientRender({ strict: false });
- let classes;
const icon = font_icon;
const FakeAction = () => ;
@@ -28,21 +26,17 @@ describe('', () => {
ariaLabel: 'mySpeedDial',
};
- before(() => {
- classes = getClasses(
-
-
- ,
- );
- });
-
- describeConformance(, () => ({
+ describeConformanceV5(, () => ({
classes,
inheritComponent: 'div',
mount,
+ render,
refInstanceof: window.HTMLDivElement,
+ muiName: 'MuiSpeedDial',
+ testVariantProps: { direction: 'right' },
skip: [
'componentProp', // react-transition-group issue
+ 'componentsProp',
'reactTestRenderer',
],
}));
diff --git a/packages/material-ui/src/SpeedDial/index.d.ts b/packages/material-ui/src/SpeedDial/index.d.ts
index 1d1c4c58f2e23d..66f605986245f9 100644
--- a/packages/material-ui/src/SpeedDial/index.d.ts
+++ b/packages/material-ui/src/SpeedDial/index.d.ts
@@ -1,2 +1,5 @@
export { default } from './SpeedDial';
export * from './SpeedDial';
+
+export { default as speedDialClasses } from './speedDialClasses';
+export * from './speedDialClasses';
diff --git a/packages/material-ui/src/SpeedDial/index.js b/packages/material-ui/src/SpeedDial/index.js
index d32154436367a9..22eeb5a48f0852 100644
--- a/packages/material-ui/src/SpeedDial/index.js
+++ b/packages/material-ui/src/SpeedDial/index.js
@@ -1 +1,4 @@
export { default } from './SpeedDial';
+
+export { default as speedDialClasses } from './speedDialClasses';
+export * from './speedDialClasses';
diff --git a/packages/material-ui/src/SpeedDial/speedDialClasses.d.ts b/packages/material-ui/src/SpeedDial/speedDialClasses.d.ts
new file mode 100644
index 00000000000000..4ba1e9b5a76e6e
--- /dev/null
+++ b/packages/material-ui/src/SpeedDial/speedDialClasses.d.ts
@@ -0,0 +1,9 @@
+import { SpeedDialClassKey } from './SpeedDial';
+
+export type SpeedDialClasses = Record;
+
+declare const speedDialClasses: SpeedDialClasses;
+
+export function getSpeedDialUtilityClass(slot: string): string;
+
+export default speedDialClasses;
diff --git a/packages/material-ui/src/SpeedDial/speedDialClasses.js b/packages/material-ui/src/SpeedDial/speedDialClasses.js
new file mode 100644
index 00000000000000..676609a9c8ee73
--- /dev/null
+++ b/packages/material-ui/src/SpeedDial/speedDialClasses.js
@@ -0,0 +1,18 @@
+import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';
+
+export function getSpeedDialUtilityClass(slot) {
+ return generateUtilityClass('MuiSpeedDial', slot);
+}
+
+const speedDialClasses = generateUtilityClasses('MuiSpeedDial', [
+ 'root',
+ 'fab',
+ 'directionUp',
+ 'directionDown',
+ 'directionLeft',
+ 'directionRight',
+ 'actions',
+ 'actionsClosed',
+]);
+
+export default speedDialClasses;
diff --git a/packages/material-ui/src/SpeedDialAction/SpeedDialAction.d.ts b/packages/material-ui/src/SpeedDialAction/SpeedDialAction.d.ts
index c2273bb2fc7525..e3661976b7a836 100644
--- a/packages/material-ui/src/SpeedDialAction/SpeedDialAction.d.ts
+++ b/packages/material-ui/src/SpeedDialAction/SpeedDialAction.d.ts
@@ -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 { TooltipProps } from '../Tooltip';
@@ -37,6 +39,10 @@ export interface SpeedDialActionProps extends StandardProps;
/**
* `classes` prop applied to the [`Tooltip`](/api/tooltip/) element.
*/
diff --git a/packages/material-ui/src/SpeedDialAction/SpeedDialAction.js b/packages/material-ui/src/SpeedDialAction/SpeedDialAction.js
index f1107c233e05a5..8557d632cee06c 100644
--- a/packages/material-ui/src/SpeedDialAction/SpeedDialAction.js
+++ b/packages/material-ui/src/SpeedDialAction/SpeedDialAction.js
@@ -3,83 +3,136 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
-import withStyles from '../styles/withStyles';
+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 { emphasize } from '../styles/colorManipulator';
import Fab from '../Fab';
import Tooltip from '../Tooltip';
import capitalize from '../utils/capitalize';
+import speedDialActionClasses, { getSpeedDialActionUtilityClass } from './speedDialActionClasses';
-export const styles = (theme) => ({
- /* Styles applied to the Fab component. */
- fab: {
- margin: 8,
- color: theme.palette.text.secondary,
- backgroundColor: theme.palette.background.paper,
- '&:hover': {
- backgroundColor: emphasize(theme.palette.background.paper, 0.15),
+const overridesResolverFab = (props, styles) => {
+ const { styleProps } = props;
+
+ return deepmerge(
+ {
+ ...(!styleProps.open && styles.fabClosed),
},
- transition: `${theme.transitions.create('transform', {
- duration: theme.transitions.duration.shorter,
- })}, opacity 0.8s`,
- opacity: 1,
+ styles.fab || {},
+ );
+};
+
+const overridesResolverStatic = (props, styles) => {
+ const { styleProps } = props;
+
+ return deepmerge(
+ {
+ ...(!styleProps.open && styles.staticTooltipClosed),
+ ...styles[`tooltipPlacement${capitalize(styleProps.tooltipPlacement)}`],
+ [`& .${speedDialActionClasses.staticTooltipLabel}`]: styles.staticTooltipLabel,
+ },
+ styles.staticTooltip || {},
+ );
+};
+
+const useUtilityClasses = (styleProps) => {
+ const { open, tooltipPlacement, classes } = styleProps;
+
+ const slots = {
+ fab: ['fab', !open && 'fabClosed'],
+ staticTooltip: [
+ 'staticTooltip',
+ `tooltipPlacement${capitalize(tooltipPlacement)}`,
+ !open && 'staticTooltipClosed',
+ ],
+ staticTooltipLabel: ['staticTooltipLabel'],
+ };
+
+ return composeClasses(slots, getSpeedDialActionUtilityClass, classes);
+};
+
+const SpeedDialActionFab = experimentalStyled(
+ Fab,
+ {},
+ {
+ name: 'MuiSpeedDialAction',
+ slot: 'Fab',
+ overridesResolver: overridesResolverFab,
+ },
+)(({ theme, styleProps }) => ({
+ margin: 8,
+ color: theme.palette.text.secondary,
+ backgroundColor: theme.palette.background.paper,
+ '&:hover': {
+ backgroundColor: emphasize(theme.palette.background.paper, 0.15),
},
- /* Styles applied to the Fab component if `open={false}`. */
- fabClosed: {
+ transition: `${theme.transitions.create('transform', {
+ duration: theme.transitions.duration.shorter,
+ })}, opacity 0.8s`,
+ opacity: 1,
+ ...(!styleProps.open && {
opacity: 0,
transform: 'scale(0)',
+ }),
+}));
+
+const SpeedDialActionStaticTooltip = experimentalStyled(
+ 'span',
+ {},
+ {
+ name: 'MuiSpeedDialAction',
+ slot: 'StaticTooltip',
+ overridesResolver: overridesResolverStatic,
},
- /* Styles applied to the root element if `tooltipOpen={true}`. */
- staticTooltip: {
- position: 'relative',
- display: 'flex',
- '& $staticTooltipLabel': {
- transition: theme.transitions.create(['transform', 'opacity'], {
- duration: theme.transitions.duration.shorter,
- }),
- opacity: 1,
- },
- },
- /* Styles applied to the root element if `tooltipOpen={true}` and `open={false}`. */
- staticTooltipClosed: {
- '& $staticTooltipLabel': {
+)(({ theme, styleProps }) => ({
+ position: 'relative',
+ display: 'flex',
+ alignItems: 'center',
+ [`& .${speedDialActionClasses.staticTooltipLabel}`]: {
+ transition: theme.transitions.create(['transform', 'opacity'], {
+ duration: theme.transitions.duration.shorter,
+ }),
+ opacity: 1,
+ ...(!styleProps.open && {
opacity: 0,
transform: 'scale(0.5)',
- },
- },
- /* Styles applied to the static tooltip label if `tooltipOpen={true}`. */
- staticTooltipLabel: {
- position: 'absolute',
- ...theme.typography.body1,
- backgroundColor: theme.palette.background.paper,
- borderRadius: theme.shape.borderRadius,
- boxShadow: theme.shadows[1],
- color: theme.palette.text.secondary,
- padding: '4px 16px',
- wordBreak: 'keep-all',
- },
- /* Styles applied to the root element if `tooltipOpen={true}` and `tooltipPlacement="left"`` */
- tooltipPlacementLeft: {
- alignItems: 'center',
- '& $staticTooltipLabel': {
+ }),
+ ...(styleProps.tooltipPlacement === 'left' && {
transformOrigin: '100% 50%',
right: '100%',
marginRight: 8,
- },
- },
- /* Styles applied to the root element if `tooltipOpen={true}` and `tooltipPlacement="right"`` */
- tooltipPlacementRight: {
- alignItems: 'center',
- '& $staticTooltipLabel': {
+ }),
+ ...(styleProps.tooltipPlacement === 'right' && {
transformOrigin: '0% 50%',
left: '100%',
marginLeft: 8,
- },
+ }),
},
-});
+}));
+
+const SpeedDialActionStaticTooltipLabel = experimentalStyled(
+ 'span',
+ {},
+ {
+ name: 'MuiSpeedDialAction',
+ slot: 'StaticTooltipLabel',
+ },
+)(({ theme }) => ({
+ position: 'absolute',
+ ...theme.typography.body1,
+ backgroundColor: theme.palette.background.paper,
+ borderRadius: theme.shape.borderRadius,
+ boxShadow: theme.shadows[1],
+ color: theme.palette.text.secondary,
+ padding: '4px 16px',
+ wordBreak: 'keep-all',
+}));
-const SpeedDialAction = React.forwardRef(function SpeedDialAction(props, ref) {
+const SpeedDialAction = React.forwardRef(function SpeedDialAction(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiSpeedDialAction' });
const {
- classes,
className,
delay = 0,
FabProps = {},
@@ -93,6 +146,9 @@ const SpeedDialAction = React.forwardRef(function SpeedDialAction(props, ref) {
...other
} = props;
+ const styleProps = { ...props, tooltipPlacement };
+ const classes = useUtilityClasses(styleProps);
+
const [tooltipOpen, setTooltipOpen] = React.useState(tooltipOpenProp);
const handleTooltipClose = () => {
@@ -106,12 +162,13 @@ const SpeedDialAction = React.forwardRef(function SpeedDialAction(props, ref) {
const transitionStyle = { transitionDelay: `${delay}ms` };
const fab = (
-
{icon}
-
+
);
if (tooltipOpenProp) {
return (
-
-
+
{tooltipTitle}
-
+
{fab}
-
+
);
}
@@ -195,6 +254,10 @@ SpeedDialAction.propTypes = {
* If `true`, the component is shown.
*/
open: PropTypes.bool,
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx: PropTypes.object,
/**
* `classes` prop applied to the [`Tooltip`](/api/tooltip/) element.
*/
@@ -228,4 +291,4 @@ SpeedDialAction.propTypes = {
tooltipTitle: PropTypes.node,
};
-export default withStyles(styles, { name: 'MuiSpeedDialAction' })(SpeedDialAction);
+export default SpeedDialAction;
diff --git a/packages/material-ui/src/SpeedDialAction/SpeedDialAction.test.js b/packages/material-ui/src/SpeedDialAction/SpeedDialAction.test.js
index 48f3c5bf253b82..4740cb8ffb2694 100644
--- a/packages/material-ui/src/SpeedDialAction/SpeedDialAction.test.js
+++ b/packages/material-ui/src/SpeedDialAction/SpeedDialAction.test.js
@@ -1,18 +1,13 @@
import * as React from 'react';
import { expect } from 'chai';
-import {
- getClasses,
- createMount,
- describeConformance,
- act,
- createClientRender,
- fireEvent,
-} from 'test/utils';
+import { createMount, describeConformanceV5, act, createClientRender, fireEvent } from 'test/utils';
import { useFakeTimers } from 'sinon';
import Icon from '@material-ui/core/Icon';
import Tooltip from '@material-ui/core/Tooltip';
import { fabClasses } from '@material-ui/core/Fab';
-import SpeedDialAction from './SpeedDialAction';
+import SpeedDialAction, {
+ speedDialActionClasses as classes,
+} from '@material-ui/core/SpeedDialAction';
describe('', () => {
let clock;
@@ -26,20 +21,19 @@ describe('', () => {
const mount = createMount({ strict: true });
const render = createClientRender();
- let classes;
- before(() => {
- classes = getClasses(add} tooltipTitle="placeholder" />);
- });
-
- describeConformance(
+ describeConformanceV5(
add} tooltipTitle="placeholder" />,
() => ({
classes,
inheritComponent: Tooltip,
mount,
+ render,
refInstanceof: window.HTMLButtonElement,
- skip: ['componentProp', 'reactTestRenderer'],
+ muiName: 'MuiSpeedDialAction',
+ testRootOverrides: { slotName: 'fab' },
+ testVariantProps: { tooltipPlacement: 'right' },
+ skip: ['componentProp', 'reactTestRenderer', 'componentsProp'],
}),
);
diff --git a/packages/material-ui/src/SpeedDialAction/index.d.ts b/packages/material-ui/src/SpeedDialAction/index.d.ts
index 0ac4379e2c64ea..26c65f4d8dfa06 100644
--- a/packages/material-ui/src/SpeedDialAction/index.d.ts
+++ b/packages/material-ui/src/SpeedDialAction/index.d.ts
@@ -1,2 +1,5 @@
export { default } from './SpeedDialAction';
export * from './SpeedDialAction';
+
+export { default as speedDialActionClasses } from './speedDialActionClasses';
+export * from './speedDialActionClasses';
diff --git a/packages/material-ui/src/SpeedDialAction/index.js b/packages/material-ui/src/SpeedDialAction/index.js
index ac364668754b26..6a6d8319ff1784 100644
--- a/packages/material-ui/src/SpeedDialAction/index.js
+++ b/packages/material-ui/src/SpeedDialAction/index.js
@@ -1 +1,4 @@
export { default } from './SpeedDialAction';
+
+export { default as speedDialActionClasses } from './speedDialActionClasses';
+export * from './speedDialActionClasses';
diff --git a/packages/material-ui/src/SpeedDialAction/speedDialActionClasses.d.ts b/packages/material-ui/src/SpeedDialAction/speedDialActionClasses.d.ts
new file mode 100644
index 00000000000000..32fd6281596c84
--- /dev/null
+++ b/packages/material-ui/src/SpeedDialAction/speedDialActionClasses.d.ts
@@ -0,0 +1,9 @@
+import { SpeedDialActionClassKey } from './SpeedDialAction';
+
+export type SpeedDialActionClasses = Record;
+
+declare const speedDialActionClasses: SpeedDialActionClasses;
+
+export function getSpeedDialActionUtilityClass(slot: string): string;
+
+export default speedDialActionClasses;
diff --git a/packages/material-ui/src/SpeedDialAction/speedDialActionClasses.js b/packages/material-ui/src/SpeedDialAction/speedDialActionClasses.js
new file mode 100644
index 00000000000000..6da34161a14564
--- /dev/null
+++ b/packages/material-ui/src/SpeedDialAction/speedDialActionClasses.js
@@ -0,0 +1,17 @@
+import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';
+
+export function getSpeedDialActionUtilityClass(slot) {
+ return generateUtilityClass('MuiSpeedDialAction', slot);
+}
+
+const speedDialActionClasses = generateUtilityClasses('MuiSpeedDialAction', [
+ 'fab',
+ 'fabClosed',
+ 'staticTooltip',
+ 'staticTooltipClosed',
+ 'staticTooltipLabel',
+ 'tooltipPlacementLeft',
+ 'tooltipPlacementRight',
+]);
+
+export default speedDialActionClasses;
diff --git a/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.d.ts b/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.d.ts
index e6490fb9b85865..d7ab93804c098c 100644
--- a/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.d.ts
+++ b/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.d.ts
@@ -1,4 +1,6 @@
import * as React from 'react';
+import { SxProps } from '@material-ui/system';
+import { Theme } from '../styles';
import { InternalStandardProps as StandardProps } from '..';
export interface SpeedDialIconProps
@@ -33,6 +35,10 @@ export interface SpeedDialIconProps
* If `true`, the component is shown.
*/
open?: boolean;
+ /**
+ * The system prop that allows defining system overrides as well as additional CSS styles.
+ */
+ sx?: SxProps;
}
export type SpeedDialIconClassKey = keyof NonNullable;
diff --git a/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.js b/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.js
index cf8ef6f20c88d7..0ca40903fcb476 100644
--- a/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.js
+++ b/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.js
@@ -1,53 +1,85 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
-import withStyles from '../styles/withStyles';
+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 AddIcon from '../internal/svg-icons/Add';
+import speedDialIconClasses, { getSpeedDialIconUtilityClass } from './speedDialIconClasses';
-export const styles = (theme) => ({
- /* Styles applied to the root element. */
- root: {
- height: 24,
+const overridesResolver = (props, styles) => {
+ const { styleProps } = props;
+
+ return deepmerge(
+ {
+ [`& .${speedDialIconClasses.icon}`]: {
+ ...styles.icon,
+ ...(styleProps.open && styles.iconOpen),
+ ...(styleProps.open && styleProps.openIcon && styles.iconWithOpenIconOpen),
+ },
+ [`& .${speedDialIconClasses.openIcon}`]: {
+ ...styles.openIcon,
+ ...(styleProps.open && styles.openIconOpen),
+ },
+ },
+ styles.root || {},
+ );
+};
+
+const useUtilityClasses = (styleProps) => {
+ const { classes, open, openIcon } = styleProps;
+
+ const slots = {
+ root: ['root'],
+ icon: ['icon', open && 'iconOpen', openIcon && open && 'iconWithOpenIconOpen'],
+ openIcon: ['openIcon', open && 'openIconOpen'],
+ };
+
+ return composeClasses(slots, getSpeedDialIconUtilityClass, classes);
+};
+
+const SpeedDialIconRoot = experimentalStyled(
+ 'span',
+ {},
+ {
+ name: 'MuiSpeedDialIcon',
+ slot: 'Root',
+ overridesResolver,
},
- /* Styles applied to the icon component. */
- icon: {
+)(({ theme, styleProps }) => ({
+ height: 24,
+ [`& .${speedDialIconClasses.icon}`]: {
transition: theme.transitions.create(['transform', 'opacity'], {
duration: theme.transitions.duration.short,
}),
+ ...(styleProps.open && {
+ transform: 'rotate(45deg)',
+ ...(styleProps.openIcon && {
+ opacity: 0,
+ }),
+ }),
},
- /* Styles applied to the icon component if `open={true}`. */
- iconOpen: {
- transform: 'rotate(45deg)',
- },
- /* Styles applied to the icon when an `openIcon` is provided and if `open={true}`. */
- iconWithOpenIconOpen: {
- opacity: 0,
- },
- /* Styles applied to the `openIcon` if provided. */
- openIcon: {
+ [`& .${speedDialIconClasses.openIcon}`]: {
position: 'absolute',
transition: theme.transitions.create(['transform', 'opacity'], {
duration: theme.transitions.duration.short,
}),
opacity: 0,
transform: 'rotate(-45deg)',
+ ...(styleProps.open && {
+ transform: 'rotate(0deg)',
+ opacity: 1,
+ }),
},
- /* Styles applied to the `openIcon` if provided and if `open={true}`. */
- openIconOpen: {
- transform: 'rotate(0deg)',
- opacity: 1,
- },
-});
-
-const SpeedDialIcon = React.forwardRef(function SpeedDialIcon(props, ref) {
- const { className, classes, icon: iconProp, open, openIcon: openIconProp, ...other } = props;
+}));
- const iconClassName = clsx(classes.icon, {
- [classes.iconOpen]: open,
- [classes.iconWithOpenIconOpen]: openIconProp && open,
- });
+const SpeedDialIcon = React.forwardRef(function SpeedDialIcon(inProps, ref) {
+ const props = useThemeProps({ props: inProps, name: 'MuiSpeedDialIcon' });
+ const { className, icon: iconProp, open, openIcon: openIconProp, ...other } = props;
- const openIconClassName = clsx(classes.openIcon, { [classes.openIconOpen]: open });
+ const styleProps = { ...props };
+ const classes = useUtilityClasses(styleProps);
function formatIcon(icon, newClassName) {
if (React.isValidElement(icon)) {
@@ -58,10 +90,15 @@ const SpeedDialIcon = React.forwardRef(function SpeedDialIcon(props, ref) {
}
return (
-
- {openIconProp ? formatIcon(openIconProp, openIconClassName) : null}
- {iconProp ? formatIcon(iconProp, iconClassName) : }
-
+
+ {openIconProp ? formatIcon(openIconProp, classes.openIcon) : null}
+ {iconProp ? formatIcon(iconProp, classes.icon) : }
+
);
});
@@ -91,8 +128,12 @@ SpeedDialIcon.propTypes = {
* The icon to display in the SpeedDial Floating Action Button 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,
};
SpeedDialIcon.muiName = 'SpeedDialIcon';
-export default withStyles(styles, { name: 'MuiSpeedDialIcon' })(SpeedDialIcon);
+export default SpeedDialIcon;
diff --git a/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.test.js b/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.test.js
index 1f164590afc55c..9692d0a49be85f 100644
--- a/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.test.js
+++ b/packages/material-ui/src/SpeedDialIcon/SpeedDialIcon.test.js
@@ -1,25 +1,23 @@
import * as React from 'react';
import { expect } from 'chai';
-import { getClasses, createMount, createClientRender, describeConformance } from 'test/utils';
+import { createMount, createClientRender, describeConformanceV5 } from 'test/utils';
import Icon from '@material-ui/core/Icon';
-import SpeedDialIcon from './SpeedDialIcon';
+import SpeedDialIcon, { speedDialIconClasses as classes } from '@material-ui/core/SpeedDialIcon';
describe('', () => {
const mount = createMount();
const render = createClientRender();
- let classes;
const icon = font_icon;
- before(() => {
- classes = getClasses();
- });
-
- describeConformance(, () => ({
+ describeConformanceV5(, () => ({
classes,
inheritComponent: 'span',
mount,
+ render,
refInstanceof: window.HTMLSpanElement,
- skip: ['componentProp'],
+ muiName: 'MuiSpeedDialIcon',
+ testVariantProps: { icon },
+ skip: ['componentProp', 'componentsProp'],
}));
it('should render the Add icon by default', () => {
diff --git a/packages/material-ui/src/SpeedDialIcon/index.d.ts b/packages/material-ui/src/SpeedDialIcon/index.d.ts
index b99978d5f24665..ffda1b4724462b 100644
--- a/packages/material-ui/src/SpeedDialIcon/index.d.ts
+++ b/packages/material-ui/src/SpeedDialIcon/index.d.ts
@@ -1,2 +1,5 @@
export { default } from './SpeedDialIcon';
export * from './SpeedDialIcon';
+
+export { default as speedDialIconClasses } from './speedDialIconClasses';
+export * from './speedDialIconClasses';
diff --git a/packages/material-ui/src/SpeedDialIcon/index.js b/packages/material-ui/src/SpeedDialIcon/index.js
index a76f5f6aa6dd94..19c450e2c69450 100644
--- a/packages/material-ui/src/SpeedDialIcon/index.js
+++ b/packages/material-ui/src/SpeedDialIcon/index.js
@@ -1 +1,4 @@
export { default } from './SpeedDialIcon';
+
+export { default as speedDialIconClasses } from './speedDialIconClasses';
+export * from './speedDialIconClasses';
diff --git a/packages/material-ui/src/SpeedDialIcon/speedDialIconClasses.d.ts b/packages/material-ui/src/SpeedDialIcon/speedDialIconClasses.d.ts
new file mode 100644
index 00000000000000..5022f5ab4f070a
--- /dev/null
+++ b/packages/material-ui/src/SpeedDialIcon/speedDialIconClasses.d.ts
@@ -0,0 +1,9 @@
+import { SpeedDialIconClassKey } from './SpeedDialIcon';
+
+export type SpeedDialIconClasses = Record;
+
+declare const speedDialIconClasses: SpeedDialIconClasses;
+
+export function getSpeedDialIconUtilityClass(slot: string): string;
+
+export default speedDialIconClasses;
diff --git a/packages/material-ui/src/SpeedDialIcon/speedDialIconClasses.js b/packages/material-ui/src/SpeedDialIcon/speedDialIconClasses.js
new file mode 100644
index 00000000000000..8145dbd98c0ccc
--- /dev/null
+++ b/packages/material-ui/src/SpeedDialIcon/speedDialIconClasses.js
@@ -0,0 +1,16 @@
+import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';
+
+export function getSpeedDialIconUtilityClass(slot) {
+ return generateUtilityClass('MuiSpeedDialIcon', slot);
+}
+
+const speedDialIconClasses = generateUtilityClasses('MuiSpeedDialIcon', [
+ 'root',
+ 'icon',
+ 'iconOpen',
+ 'iconWithOpenIconOpen',
+ 'openIcon',
+ 'openIconOpen',
+]);
+
+export default speedDialIconClasses;