Skip to content

Commit

Permalink
[Breadcrumbs] Migrate to emotion (mui#24522)
Browse files Browse the repository at this point in the history
  • Loading branch information
queengooborg authored Jan 25, 2021
1 parent 68f86c2 commit 27bbb5b
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 86 deletions.
5 changes: 3 additions & 2 deletions docs/pages/api-docs/breadcrumbs.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"itemsAfterCollapse": { "type": { "name": "number" }, "default": "1" },
"itemsBeforeCollapse": { "type": { "name": "number" }, "default": "1" },
"maxItems": { "type": { "name": "number" }, "default": "8" },
"separator": { "type": { "name": "node" }, "default": "'/'" }
"separator": { "type": { "name": "node" }, "default": "'/'" },
"sx": { "type": { "name": "object" } }
},
"name": "Breadcrumbs",
"styles": {
Expand All @@ -20,6 +21,6 @@
"filename": "/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js",
"inheritance": null,
"demos": "<ul><li><a href=\"/components/breadcrumbs/\">Breadcrumbs</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
3 changes: 2 additions & 1 deletion docs/translations/api-docs/breadcrumbs/breadcrumbs.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"itemsAfterCollapse": "If max items is exceeded, the number of items to show after the ellipsis.",
"itemsBeforeCollapse": "If max items is exceeded, the number of items to show before the ellipsis.",
"maxItems": "Specifies the maximum number of breadcrumbs to display. When there are more than the maximum number, only the first <code>itemsBeforeCollapse</code> and last <code>itemsAfterCollapse</code> will be shown, with an ellipsis in between.",
"separator": "Custom separator node."
"separator": "Custom separator node.",
"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
89 changes: 63 additions & 26 deletions packages/material-ui/src/Breadcrumbs/BreadcrumbCollapsed.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,89 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import withStyles from '../styles/withStyles';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import experimentalStyled from '../styles/experimentalStyled';
import { emphasize } from '../styles/colorManipulator';
import MoreHorizIcon from '../internal/svg-icons/MoreHoriz';
import ButtonBase from '../ButtonBase';
import { getBreadcrumbCollapsedUtilityClass } from './breadcrumbCollapsedClasses';

const styles = (theme) => ({
button: {
display: 'flex',
marginLeft: theme.spacing(0.5),
marginRight: theme.spacing(0.5),
backgroundColor: theme.palette.grey[100],
color: theme.palette.grey[700],
borderRadius: 2,
'&:hover, &:focus': {
backgroundColor: theme.palette.grey[200],
},
'&:active': {
boxShadow: theme.shadows[0],
backgroundColor: emphasize(theme.palette.grey[200], 0.12),
},
const useUtilityClasses = (styleProps) => {
const { classes } = styleProps;

const slots = {
button: ['button'],
icon: ['icon'],
};

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

const BreadcrumbCollapsedButton = experimentalStyled(
ButtonBase,
{},
{
name: 'PrivateBreadcrumbCollapsed',
slot: 'Button',
},
icon: {
width: 24,
height: 16,
)(({ theme }) => ({
display: 'flex',
marginLeft: theme.spacing(0.5),
marginRight: theme.spacing(0.5),
...(theme.palette.mode === 'light'
? { backgroundColor: theme.palette.grey[100], color: theme.palette.grey[700] }
: { backgroundColor: theme.palette.grey[700], color: theme.palette.grey[100] }),
borderRadius: 2,
'&:hover, &:focus': {
...(theme.palette.mode === 'light'
? { backgroundColor: theme.palette.grey[200] }
: { backgroundColor: theme.palette.grey[600] }),
},
'&:active': {
boxShadow: theme.shadows[0],
...(theme.palette.mode === 'light'
? { backgroundColor: emphasize(theme.palette.grey[200], 0.12) }
: { backgroundColor: emphasize(theme.palette.grey[600], 0.12) }),
},
}));

const BreadcrumbCollapsedIcon = experimentalStyled(
MoreHorizIcon,
{},
{
name: 'PrivateBreadcrumbCollapsed',
slot: 'Icon',
},
)({
width: 24,
height: 16,
});

/**
* @ignore - internal component.
*/
function BreadcrumbCollapsed(props) {
const { classes, ...other } = props;
const styleProps = props;
const classes = useUtilityClasses(styleProps);

return (
<li>
<ButtonBase className={classes.button} focusRipple {...other}>
<MoreHorizIcon className={classes.icon} />
</ButtonBase>
<BreadcrumbCollapsedButton
className={classes.button}
focusRipple
{...props}
styleProps={styleProps}
>
<BreadcrumbCollapsedIcon className={classes.icon} styleProps={styleProps} />
</BreadcrumbCollapsedButton>
</li>
);
}

BreadcrumbCollapsed.propTypes = {
/**
* @ignore
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
classes: PropTypes.object.isRequired,
sx: PropTypes.object,
};

export default withStyles(styles, { name: 'PrivateBreadcrumbCollapsed' })(BreadcrumbCollapsed);
export default BreadcrumbCollapsed;
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { getClasses, fireEvent, createClientRender } from 'test/utils';
import { fireEvent, createClientRender } from 'test/utils';
import BreadcrumbCollapsed from './BreadcrumbCollapsed';
import classes from './breadcrumbCollapsedClasses';

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

before(() => {
classes = getClasses(<BreadcrumbCollapsed />);
});

it('should render an icon', () => {
const { container, getByRole } = render(<BreadcrumbCollapsed />);

Expand Down
6 changes: 6 additions & 0 deletions packages/material-ui/src/Breadcrumbs/Breadcrumbs.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 '@material-ui/core/styles';
import { OverridableComponent, OverrideProps } from '../OverridableComponent';

export interface BreadcrumbsTypeMap<P = {}, D extends React.ElementType = 'nav'> {
Expand Down Expand Up @@ -49,6 +51,10 @@ export interface BreadcrumbsTypeMap<P = {}, D extends React.ElementType = 'nav'>
* @default '/'
*/
separator?: React.ReactNode;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
};
defaultComponent: D;
}
Expand Down
132 changes: 99 additions & 33 deletions packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,88 @@ import * as React from 'react';
import { isFragment } from 'react-is';
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 Typography from '../Typography';
import BreadcrumbCollapsed from './BreadcrumbCollapsed';
import breadcrumbsClasses, { getBreadcrumbsUtilityClass } from './breadcrumbsClasses';

export const styles = {
/* Styles applied to the root element. */
root: {},
/* Styles applied to the ol element. */
ol: {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
padding: 0,
margin: 0,
listStyle: 'none',
const overridesResolver = (props, styles) => {
return deepmerge(styles.root || {}, {
[`& .${breadcrumbsClasses.ol}`]: styles.ol,
[`& .${breadcrumbsClasses.li}`]: styles.li,
[`& .${breadcrumbsClasses.separator}`]: styles.separator,
});
};

const useUtilityClasses = (styleProps) => {
const { classes } = styleProps;

const slots = {
root: ['root'],
li: ['li'],
ol: ['ol'],
separator: ['separator'],
};

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

const BreadcrumbsRoot = experimentalStyled(
Typography,
{},
{
name: 'MuiBreadcrumbs',
slot: 'Root',
overridesResolver,
},
/* Styles applied to the li element. */
li: {},
/* Styles applied to the separator element. */
separator: {
display: 'flex',
userSelect: 'none',
marginLeft: 8,
marginRight: 8,
)({});

const BreadcrumbsOl = experimentalStyled(
'ol',
{},
{
name: 'MuiBreadcrumbs',
slot: 'Ol',
},
};
)({
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
padding: 0,
margin: 0,
listStyle: 'none',
});

function insertSeparators(items, className, separator) {
const BreadcrumbsSeparator = experimentalStyled(
'li',
{},
{
name: 'MuiBreadcrumbs',
slot: 'Separator',
},
)({
display: 'flex',
userSelect: 'none',
marginLeft: 8,
marginRight: 8,
});

function insertSeparators(items, className, separator, styleProps) {
return items.reduce((acc, current, index) => {
if (index < items.length - 1) {
acc = acc.concat(
current,
<li aria-hidden key={`separator-${index}`} className={className}>
<BreadcrumbsSeparator
aria-hidden
key={`separator-${index}`}
className={className}
styleProps={styleProps}
>
{separator}
</li>,
</BreadcrumbsSeparator>,
);
} else {
acc.push(current);
Expand All @@ -46,12 +93,12 @@ function insertSeparators(items, className, separator) {
}, []);
}

const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
const Breadcrumbs = React.forwardRef(function Breadcrumbs(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiBreadcrumbs' });
const {
children,
classes,
className,
component: Component = 'nav',
component = 'nav',
expandText = 'Show path',
itemsAfterCollapse = 1,
itemsBeforeCollapse = 1,
Expand All @@ -62,6 +109,19 @@ const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {

const [expanded, setExpanded] = React.useState(false);

const styleProps = {
...props,
component,
expanded,
expandText,
itemsAfterCollapse,
itemsBeforeCollapse,
maxItems,
separator,
};

const classes = useUtilityClasses(styleProps);

const listRef = React.useRef(null);
const renderItemsBeforeAndAfter = (allItems) => {
const handleClickExpand = () => {
Expand Down Expand Up @@ -120,23 +180,25 @@ const Breadcrumbs = React.forwardRef(function Breadcrumbs(props, ref) {
));

return (
<Typography
<BreadcrumbsRoot
ref={ref}
component={Component}
component={component}
color="textSecondary"
className={clsx(classes.root, className)}
styleProps={styleProps}
{...other}
>
<ol className={classes.ol} ref={listRef}>
<BreadcrumbsOl className={classes.ol} ref={listRef} styleProps={styleProps}>
{insertSeparators(
expanded || (maxItems && allItems.length <= maxItems)
? allItems
: renderItemsBeforeAndAfter(allItems),
classes.separator,
separator,
styleProps,
)}
</ol>
</Typography>
</BreadcrumbsOl>
</BreadcrumbsRoot>
);
});

Expand Down Expand Up @@ -191,6 +253,10 @@ Breadcrumbs.propTypes = {
* @default '/'
*/
separator: PropTypes.node,
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
};

export default withStyles(styles, { name: 'MuiBreadcrumbs' })(Breadcrumbs);
export default Breadcrumbs;
Loading

0 comments on commit 27bbb5b

Please sign in to comment.