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

[Radio] Migrate to emotion #25152

Merged
merged 10 commits into from
Mar 3, 2021
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
3 changes: 2 additions & 1 deletion docs/pages/api-docs/radio.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"type": { "name": "enum", "description": "'medium'<br>&#124;&nbsp;'small'" },
"default": "'medium'"
},
"sx": { "type": { "name": "object" } },
"value": { "type": { "name": "any" } }
},
"name": "Radio",
Expand All @@ -36,6 +37,6 @@
"filename": "/packages/material-ui/src/Radio/Radio.js",
"inheritance": { "component": "IconButton", "pathname": "/api/icon-button/" },
"demos": "<ul><li><a href=\"/components/radio-buttons/\">Radio Buttons</a></li></ul>",
"styledComponent": false,
"styledComponent": true,
"cssComponent": false
}
15 changes: 6 additions & 9 deletions docs/src/pages/components/radio-buttons/RadioButtons.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import * as React from 'react';
import { withStyles } from '@material-ui/core/styles';
import { experimentalStyled as styled } from '@material-ui/core/styles';
import { green } from '@material-ui/core/colors';
import Radio from '@material-ui/core/Radio';

const GreenRadio = withStyles({
root: {
color: green[400],
'&$checked': {
color: green[600],
},
const GreenRadio = styled(Radio)({
color: green[400],
'&.Mui-checked': {
color: green[600],
},
checked: {},
})((props) => <Radio color="default" {...props} />);
});

export default function RadioButtons() {
const [selectedValue, setSelectedValue] = React.useState('a');
Expand Down
17 changes: 7 additions & 10 deletions docs/src/pages/components/radio-buttons/RadioButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import * as React from 'react';
import { withStyles } from '@material-ui/core/styles';
import { experimentalStyled as styled } from '@material-ui/core/styles';
import { green } from '@material-ui/core/colors';
import Radio, { RadioProps } from '@material-ui/core/Radio';
import Radio from '@material-ui/core/Radio';

const GreenRadio = withStyles({
root: {
color: green[400],
'&$checked': {
color: green[600],
},
const GreenRadio = styled(Radio)({
color: green[400],
'&.Mui-checked': {
color: green[600],
},
checked: {},
})((props: RadioProps) => <Radio color="default" {...props} />);
});

export default function RadioButtons() {
const [selectedValue, setSelectedValue] = React.useState('a');
Expand Down
1 change: 1 addition & 0 deletions docs/translations/api-docs/radio/radio.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"onChange": "Callback fired when the state is changed.<br><br><strong>Signature:</strong><br><code>function(event: object) =&gt; void</code><br><em>event:</em> The event source of the callback. You can pull out the new value by accessing <code>event.target.value</code> (string). You can pull out the new checked state by accessing <code>event.target.checked</code> (boolean).",
"required": "If <code>true</code>, the <code>input</code> element is required.",
"size": "The size of the component. <code>small</code> is equivalent to the dense radio styling.",
"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": "The value of the component. The DOM API casts this to a string."
},
"classDescriptions": {
Expand Down
2 changes: 1 addition & 1 deletion framer/scripts/framerConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ export const componentSettings = {
template: 'paper.txt',
},
Radio: {
ignoredProps: ['checked', 'checkedIcon', 'icon', 'onChange', 'required', 'type', 'value'],
ignoredProps: ['checked', 'checkedIcon', 'icon', 'onChange', 'required', 'sx', 'type', 'value'],
propValues: {
label: "'Radio'",
width: "'100%'",
Expand Down
7 changes: 6 additions & 1 deletion packages/material-ui/src/Radio/Radio.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { InternalStandardProps as StandardProps } from '..';
import { SxProps } from '@material-ui/system';
import { InternalStandardProps as StandardProps, Theme } from '..';
import { SwitchBaseProps } from '../internal/SwitchBase';

export interface RadioProps
Expand Down Expand Up @@ -42,6 +43,10 @@ export interface RadioProps
* @default 'medium'
*/
size?: 'small' | 'medium';
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme>;
}

export type RadioClassKey = keyof NonNullable<RadioProps['classes']>;
Expand Down
108 changes: 63 additions & 45 deletions packages/material-ui/src/Radio/Radio.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,88 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { refType } from '@material-ui/utils';
import { deepmerge, refType } from '@material-ui/utils';
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled';
import SwitchBase from '../internal/SwitchBase';
import useThemeProps from '../styles/useThemeProps';
import RadioButtonIcon from './RadioButtonIcon';
import { alpha } from '../styles/colorManipulator';
import capitalize from '../utils/capitalize';
import createChainedFunction from '../utils/createChainedFunction';
import withStyles from '../styles/withStyles';
import useRadioGroup from '../RadioGroup/useRadioGroup';
import { getRadioUtilityClass } from './radioClasses';
import experimentalStyled, { shouldForwardProp } from '../styles/experimentalStyled';

export const styles = (theme) => ({
/* Styles applied to the root element. */
root: {
color: theme.palette.text.secondary,
},
/* Pseudo-class applied to the root element if `checked={true}`. */
checked: {},
/* Pseudo-class applied to the root element if `disabled={true}`. */
disabled: {},
/* Styles applied to the root element if `color="primary"`. */
colorPrimary: {
'&$checked': {
color: theme.palette.primary.main,
'&:hover': {
backgroundColor: alpha(theme.palette.primary.main, theme.palette.action.hoverOpacity),
// Reset on touch devices, it doesn't add specificity
'@media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
'&$disabled': {
color: theme.palette.action.disabled,
},
const overridesResolver = (props, styles) => {
const { styleProps } = props;

return deepmerge(styles.root || {}, styles[`color${capitalize(styleProps.color)}`]);
};

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

const slots = {
root: ['root', `color${capitalize(color)}`],
};

return {
...classes,
...composeClasses(slots, getRadioUtilityClass, classes),
};
};

const RadioRoot = experimentalStyled(
SwitchBase,
{ shouldForwardProp: (prop) => shouldForwardProp(prop) || prop === 'classes' },
{
name: 'MuiRadio',
slot: 'Root',
overridesResolver,
},
/* Styles applied to the root element if `color="secondary"`. */
colorSecondary: {
'&$checked': {
color: theme.palette.secondary.main,
)(({ theme, styleProps }) => ({
/* Styles applied to the root element. */
color: theme.palette.text.secondary,
/* Styles applied to the root element unless `color="default"`. */
...(styleProps.color !== 'default' && {
'&.Mui-checked': {
color: theme.palette[styleProps.color].main,
'&:hover': {
backgroundColor: alpha(theme.palette.secondary.main, theme.palette.action.hoverOpacity),
backgroundColor: alpha(
theme.palette[styleProps.color].main,
theme.palette.action.hoverOpacity,
),
// Reset on touch devices, it doesn't add specificity
'@media (hover: none)': {
backgroundColor: 'transparent',
},
},
},
'&$disabled': {
color: theme.palette.action.disabled,
},
}),
'&.Mui-disabled': {
color: theme.palette.action.disabled,
},
});
}));

const defaultCheckedIcon = <RadioButtonIcon checked />;
const defaultIcon = <RadioButtonIcon />;

const Radio = React.forwardRef(function Radio(props, ref) {
const Radio = React.forwardRef(function Radio(inProps, ref) {
const props = useThemeProps({ props: inProps, name: 'MuiRadio' });
const {
checked: checkedProp,
classes,
color = 'secondary',
name: nameProp,
onChange: onChangeProp,
size = 'medium',
...other
} = props;
const styleProps = {
...props,
color,
size,
};

const classes = useUtilityClasses(styleProps);
const radioGroup = useRadioGroup();

let checked = checkedProp;
Expand All @@ -82,18 +99,15 @@ const Radio = React.forwardRef(function Radio(props, ref) {
}

return (
<SwitchBase
<RadioRoot
color={color}
type="radio"
icon={React.cloneElement(defaultIcon, { fontSize: size === 'small' ? 'small' : 'medium' })}
checkedIcon={React.cloneElement(defaultCheckedIcon, {
fontSize: size === 'small' ? 'small' : 'medium',
})}
classes={{
root: clsx(classes.root, classes[`color${capitalize(color)}`]),
checked: classes.checked,
disabled: classes.disabled,
}}
styleProps={styleProps}
classes={classes}
name={name}
checked={checked}
onChange={onChange}
Expand Down Expand Up @@ -171,10 +185,14 @@ Radio.propTypes = {
* @default 'medium'
*/
size: PropTypes.oneOf(['medium', 'small']),
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: PropTypes.object,
/**
* The value of the component. The DOM API casts this to a string.
*/
value: PropTypes.any,
};

export default withStyles(styles, { name: 'MuiRadio' })(Radio);
export default Radio;
20 changes: 9 additions & 11 deletions packages/material-ui/src/Radio/Radio.test.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
import * as React from 'react';
import { expect } from 'chai';
import { getClasses, createMount, describeConformance, createClientRender } from 'test/utils';
import FormControl from '../FormControl';
import IconButton from '../IconButton';
import Radio from './Radio';
import { createMount, describeConformanceV5, createClientRender } from 'test/utils';
import Radio, { radioClasses as classes } from '@material-ui/core/Radio';
import FormControl from '@material-ui/core/FormControl';
import IconButton from '@material-ui/core/IconButton';

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

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

describeConformance(<Radio />, () => ({
describeConformanceV5(<Radio />, () => ({
classes,
inheritComponent: IconButton,
render,
mount,
muiName: 'MuiRadio',
testVariantProps: { color: 'primary' },
refInstanceof: window.HTMLSpanElement,
skip: ['componentProp'],
skip: ['componentProp', 'componentsProp'],
}));

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

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

export { default as radioClasses } from './radioClasses';
export * from './radioClasses';
9 changes: 9 additions & 0 deletions packages/material-ui/src/Radio/radioClasses.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { RadioClassKey } from './Radio';

export type RadioClasses = Record<RadioClassKey, string>;

declare const radioClasses: RadioClasses;

export function getRadioUtilityClass(slot: string): string;

export default radioClasses;
15 changes: 15 additions & 0 deletions packages/material-ui/src/Radio/radioClasses.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled';

export function getRadioUtilityClass(slot) {
return generateUtilityClass('MuiRadio', slot);
}

const radioClasses = generateUtilityClasses('MuiRadio', [
'root',
'checked',
'disabled',
'colorPrimary',
'colorSecondary',
]);

export default radioClasses;