Skip to content

Commit

Permalink
[Tab] Migrate to emotion (mui#24651)
Browse files Browse the repository at this point in the history
  • Loading branch information
natac13 committed Jan 30, 2021
1 parent b9700b4 commit 7974435
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 84 deletions.
3 changes: 2 additions & 1 deletion docs/pages/api-docs/tab.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"disableRipple": { "type": { "name": "bool" } },
"icon": { "type": { "name": "union", "description": "element<br>&#124;&nbsp;string" } },
"label": { "type": { "name": "node" } },
"sx": { "type": { "name": "object" } },
"value": { "type": { "name": "any" } },
"wrapped": { "type": { "name": "bool" } }
},
Expand All @@ -32,6 +33,6 @@
"filename": "/packages/material-ui/src/Tab/Tab.js",
"inheritance": { "component": "ButtonBase", "pathname": "/api/button-base/" },
"demos": "<ul><li><a href=\"/components/tabs/\">Tabs</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
1 change: 1 addition & 0 deletions docs/translations/api-docs/tab/tab.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"disableRipple": "If <code>true</code>, the ripple effect is disabled.<br>⚠️ Without a ripple there is no styling for :focus-visible by default. Be sure to highlight the element by applying separate styles with the <code>.Mui-focusedVisible</code> class.",
"icon": "The icon to display.",
"label": "The label element.",
"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.",
"value": "You can provide your own value. Otherwise, we fallback to the child position index.",
"wrapped": "Tab labels appear in a single row. They can use a second line if needed."
},
Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui/src/Tab/Tab.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { SxProps } from '@material-ui/system';
import * as React from 'react';
import { Theme } from '..';
import { ExtendButtonBase, ExtendButtonBaseTypeMap } from '../ButtonBase';
import { OverrideProps } from '../OverridableComponent';

Expand Down Expand Up @@ -52,6 +54,10 @@ export type TabTypeMap<P = {}, D extends React.ElementType = 'div'> = ExtendButt
* The label element.
*/
label?: React.ReactNode;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
/**
* You can provide your own value. Otherwise, we fallback to the child position index.
*/
Expand Down
192 changes: 123 additions & 69 deletions packages/material-ui/src/Tab/Tab.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,142 @@
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 ButtonBase from '../ButtonBase';
import capitalize from '../utils/capitalize';
import useThemeProps from '../styles/useThemeProps';
import experimentalStyled from '../styles/experimentalStyled';
import unsupportedProp from '../utils/unsupportedProp';
import tabClasses, { getTabUtilityClass } from './tabClasses';

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

return deepmerge(styles.root || {}, {
...(styleProps.label && styleProps.icon && styles.labelIcon),
...styles[`textColor${capitalize(styleProps.textColor)}`],
...(styleProps.fullWidth && styles.fullWidth),
...(styleProps.wrapped && styles.wrapped),
[`& .${tabClasses.wrapper}`]: styles.wrapper,
});
};

const useUtilityClasses = (styleProps) => {
const { classes, textColor, fullWidth, wrapped, icon, label, selected, disabled } = styleProps;

const slots = {
root: [
'root',
icon && label && 'labelIcon',
`textColor${capitalize(textColor)}`,
fullWidth && 'fullWidth',
wrapped && 'wrapped',
selected && 'selected',
disabled && 'disabled',
],
wrapper: ['wrapper'],
};

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

const TabRoot = experimentalStyled(
ButtonBase,
{},
{
name: 'MuiTab',
slot: 'Root',
overridesResolver,
},
)(({ theme, styleProps }) => ({
/* Styles applied to the root element. */
root: {
...theme.typography.button,
maxWidth: 264,
minWidth: 72,
position: 'relative',
minHeight: 48,
flexShrink: 0,
padding: '6px 12px',
overflow: 'hidden',
whiteSpace: 'normal',
textAlign: 'center',
[theme.breakpoints.up('sm')]: {
minWidth: 160,
},
...theme.typography.button,
maxWidth: 264,
minWidth: 72,
position: 'relative',
minHeight: 48,
flexShrink: 0,
padding: '6px 12px',
overflow: 'hidden',
whiteSpace: 'normal',
textAlign: 'center',
[theme.breakpoints.up('sm')]: {
minWidth: 160,
},
/* Styles applied to the root element if both `icon` and `label` are provided. */
labelIcon: {
minHeight: 72,
paddingTop: 9,
'& $wrapper > *:first-child': {
marginBottom: 6,
},
},
...(styleProps.icon &&
styleProps.label && {
minHeight: 72,
paddingTop: 9,
[`& .${tabClasses.wrapper} > *:first-child`]: {
marginBottom: 6,
},
}),
/* Styles applied to the root element if the parent [`Tabs`](/api/tabs/) has `textColor="inherit"`. */
textColorInherit: {
...(styleProps.textColor === 'inherit' && {
color: 'inherit',
opacity: 0.7,
'&$selected': {
'&.Mui-selected': {
opacity: 1,
},
'&$disabled': {
'&.Mui-disabled': {
opacity: theme.palette.action.disabledOpacity,
},
},
}),
/* Styles applied to the root element if the parent [`Tabs`](/api/tabs/) has `textColor="primary"`. */
textColorPrimary: {
...(styleProps.textColor === 'primary' && {
color: theme.palette.text.secondary,
'&$selected': {
'&.Mui-selected': {
color: theme.palette.primary.main,
},
'&$disabled': {
'&.Mui-disabled': {
color: theme.palette.text.disabled,
},
},
}),
/* Styles applied to the root element if the parent [`Tabs`](/api/tabs/) has `textColor="secondary"`. */
textColorSecondary: {
...(styleProps.textColor === 'secondary' && {
color: theme.palette.text.secondary,
'&$selected': {
'&.Mui-selected': {
color: theme.palette.secondary.main,
},
'&$disabled': {
'&.Mui-disabled': {
color: theme.palette.text.disabled,
},
},
/* Pseudo-class applied to the root element if `selected={true}` (controlled by the Tabs component). */
selected: {},
/* Pseudo-class applied to the root element if `disabled={true}` (controlled by the Tabs component). */
disabled: {},
/* Styles applied to the root element if `fullWidth={true}` (controlled by the Tabs component). */
fullWidth: {
}),
/* Styles applied to the root element if `fullWidth={true}` */
...(styleProps.fullWidth && {
flexShrink: 1,
flexGrow: 1,
flexBasis: 0,
maxWidth: 'none',
},
}),
/* Styles applied to the root element if `wrapped={true}`. */
wrapped: {
...(styleProps.wrapped && {
fontSize: theme.typography.pxToRem(12),
lineHeight: 1.5,
}),
}));

const TabWrapper = experimentalStyled(
'span',
{},
{
name: 'MuiTab',
slot: 'Wrapper',
},
)({
/* Styles applied to the `icon` and `label`'s wrapper element. */
wrapper: {
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
flexDirection: 'column',
},
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
flexDirection: 'column',
});

const Tab = React.forwardRef(function Tab(props, ref) {
const Tab = React.forwardRef(function Tab(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiTab' });
const {
classes,
className,
disabled = false,
disableFocusRipple = false,
Expand All @@ -114,6 +160,20 @@ const Tab = React.forwardRef(function Tab(props, ref) {
...other
} = props;

const styleProps = {
...props,
disabled,
disableFocusRipple,
selected,
icon: !!icon,
label: !!label,
fullWidth,
textColor,
wrapped,
};

const classes = useUtilityClasses(styleProps);

const handleClick = (event) => {
if (!selected && onChange) {
onChange(event, value);
Expand All @@ -135,35 +195,25 @@ const Tab = React.forwardRef(function Tab(props, ref) {
};

return (
<ButtonBase
<TabRoot
focusRipple={!disableFocusRipple}
className={clsx(
classes.root,
classes[`textColor${capitalize(textColor)}`],
{
[classes.disabled]: disabled,
[classes.selected]: selected,
[classes.labelIcon]: label && icon,
[classes.fullWidth]: fullWidth,
[classes.wrapped]: wrapped,
},
className,
)}
className={clsx(classes.root, className)}
ref={ref}
role="tab"
aria-selected={selected}
disabled={disabled}
onClick={handleClick}
onFocus={handleFocus}
styleProps={styleProps}
tabIndex={selected ? 0 : -1}
{...other}
>
<span className={classes.wrapper}>
<TabWrapper className={classes.wrapper} styleProps={styleProps}>
{icon}
{label}
</span>
</TabWrapper>
{indicator}
</ButtonBase>
</TabRoot>
);
});

Expand Down Expand Up @@ -223,6 +273,10 @@ Tab.propTypes = {
* @ignore
*/
onFocus: PropTypes.func,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* You can provide your own value. Otherwise, we fallback to the child position index.
*/
Expand All @@ -235,4 +289,4 @@ Tab.propTypes = {
wrapped: PropTypes.bool,
};

export default withStyles(styles, { name: 'MuiTab' })(Tab);
export default Tab;
21 changes: 7 additions & 14 deletions packages/material-ui/src/Tab/Tab.test.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import {
getClasses,
createMount,
describeConformance,
act,
createClientRender,
fireEvent,
} from 'test/utils';
import { createMount, describeConformanceV5, act, createClientRender, fireEvent } from 'test/utils';
import Tab from './Tab';
import ButtonBase from '../ButtonBase';
import classes from './tabClasses';

describe('<Tab />', () => {
const mount = createMount();
const render = createClientRender();
let classes;

before(() => {
classes = getClasses(<Tab textColor="inherit" />);
});

describeConformance(<Tab textColor="inherit" />, () => ({
describeConformanceV5(<Tab textColor="inherit" />, () => ({
classes,
inheritComponent: ButtonBase,
mount,
muiName: 'MuiTab',
testDeepOverrides: { slotName: 'wrapper', slotClassName: classes.wrapper },
testVariantProps: { variant: 'foo' },
refInstanceof: window.HTMLButtonElement,
skip: ['componentProp', 'componentsProp'],
}));

it('should have a ripple by default', () => {
Expand Down
3 changes: 3 additions & 0 deletions packages/material-ui/src/Tab/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export { default } from './Tab';
export * from './Tab';

export { default as tabClasses } from './tabClasses';
export * from './tabClasses';
3 changes: 3 additions & 0 deletions packages/material-ui/src/Tab/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export { default } from './Tab';

export { default as tabClasses } from './tabClasses';
export * from './tabClasses';
18 changes: 18 additions & 0 deletions packages/material-ui/src/Tab/tabClasses.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface TabClasses {
root: string;
labelIcon: string;
textColorInherit: string;
textColorPrimary: string;
textColorSecondary: string;
selected: string;
disabled: string;
fullWidth: string;
wrapped: string;
wrapper: string;
}

declare const tabClasses: TabClasses;

export function getTabUtilityClass(slot: string): string;

export default tabClasses;

0 comments on commit 7974435

Please sign in to comment.