-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
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
[Select] Migrate NativeSelect to emotion #24698
Changes from all commits
429a887
ca115b7
a0bd515
3299123
871870e
12d3570
54eb6e3
f3a2966
ab9ffd5
e09f641
e80316c
f21473e
c2bbdc9
0808efb
5b4a4fe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,45 +1,145 @@ | ||||||
import * as React from 'react'; | ||||||
import PropTypes from 'prop-types'; | ||||||
import clsx from 'clsx'; | ||||||
import { refType } from '@material-ui/utils'; | ||||||
import { refType, deepmerge } from '@material-ui/utils'; | ||||||
import { unstable_composeClasses as composeClasses } from '@material-ui/unstyled'; | ||||||
import capitalize from '../utils/capitalize'; | ||||||
import nativeSelectClasses, { getNativeSelectUtilitiyClasses } from './nativeSelectClasses'; | ||||||
import experimentalStyled from '../styles/experimentalStyled'; | ||||||
|
||||||
export const overridesResolver = (props, styles) => { | ||||||
const { styleProps } = props; | ||||||
return deepmerge(styles.root, { | ||||||
...styles.select, | ||||||
...styles[styleProps.variant], | ||||||
[`& .${nativeSelectClasses.icon}`]: { | ||||||
...styles.icon, | ||||||
...(styleProps.variant && styles[`icon${capitalize(styleProps.variant)}`]), | ||||||
...(styleProps.open && styles.iconOpen), | ||||||
}, | ||||||
}); | ||||||
}; | ||||||
|
||||||
const useUtilityClasses = (styleProps) => { | ||||||
const { classes, variant, disabled, open } = styleProps; | ||||||
|
||||||
const slots = { | ||||||
root: ['root', 'select', variant, disabled && 'disabled'], | ||||||
icon: ['icon', `icon${capitalize(variant)}`, open && 'iconOpen', disabled && 'disabled'], | ||||||
}; | ||||||
|
||||||
return composeClasses(slots, getNativeSelectUtilitiyClasses, classes); | ||||||
}; | ||||||
|
||||||
const SelectRoot = experimentalStyled( | ||||||
'select', | ||||||
{}, | ||||||
{ name: 'MuiNativeSelect', slot: 'Root', overridesResolver }, | ||||||
)(({ styleProps, theme }) => ({ | ||||||
MozAppearance: 'none', // Reset | ||||||
WebkitAppearance: 'none', // Reset | ||||||
// When interacting quickly, the text can end up selected. | ||||||
// Native select can't be selected either. | ||||||
userSelect: 'none', | ||||||
borderRadius: 0, // Reset | ||||||
minWidth: 16, // So it doesn't collapse. | ||||||
cursor: 'pointer', | ||||||
'&:focus': { | ||||||
// Show that it's not an text input | ||||||
backgroundColor: | ||||||
theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.05)' : 'rgba(255, 255, 255, 0.05)', | ||||||
borderRadius: 0, // Reset Chrome style | ||||||
}, | ||||||
// Remove IE11 arrow | ||||||
'&::-ms-expand': { | ||||||
display: 'none', | ||||||
}, | ||||||
'&.Mui-disabled': { | ||||||
cursor: 'default', | ||||||
}, | ||||||
'&[multiple]': { | ||||||
height: 'auto', | ||||||
}, | ||||||
'&:not([multiple]) option, &:not([multiple]) optgroup': { | ||||||
backgroundColor: theme.palette.background.paper, | ||||||
}, | ||||||
// Bump specificity to allow extending custom inputs | ||||||
'&&': { | ||||||
paddingRight: 24, | ||||||
}, | ||||||
...(styleProps.variant === 'filled' && { | ||||||
'&&': { | ||||||
paddingRight: 32, | ||||||
}, | ||||||
}), | ||||||
...(styleProps.variant === 'outlined' && { | ||||||
borderRadius: theme.shape.borderRadius, | ||||||
'&:focus': { | ||||||
borderRadius: theme.shape.borderRadius, // Reset the reset for Chrome style | ||||||
}, | ||||||
'&&': { | ||||||
paddingRight: 32, | ||||||
}, | ||||||
}), | ||||||
...(styleProps.selectMenu && { | ||||||
height: 'auto', // Resets for multpile select with chips | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
minHeight: '1.4375em', // Required for select\text-field height consistency | ||||||
textOverflow: 'ellipsis', | ||||||
whiteSpace: 'nowrap', | ||||||
overflow: 'hidden', | ||||||
}), | ||||||
})); | ||||||
|
||||||
const IconRoot = experimentalStyled( | ||||||
'svg', | ||||||
{}, | ||||||
{ name: 'MuiNativeSelect', slot: 'Icon' }, | ||||||
)(({ styleProps, theme }) => ({ | ||||||
// We use a position absolute over a flexbox in order to forward the pointer events | ||||||
// to the input and to support wrapping tags.. | ||||||
position: 'absolute', | ||||||
right: 0, | ||||||
top: 'calc(50% - 12px)', // Center vertically | ||||||
pointerEvents: 'none', // Don't block pointer events on the select under the icon. | ||||||
color: theme.palette.action.active, | ||||||
'&.Mui-disabled': { | ||||||
color: theme.palette.action.disabled, | ||||||
}, | ||||||
...(styleProps.open && { | ||||||
right: 7, | ||||||
}), | ||||||
...(styleProps.variant === 'filled' && { | ||||||
right: 7, | ||||||
}), | ||||||
...(styleProps.variant === 'outlined' && { | ||||||
right: 7, | ||||||
}), | ||||||
})); | ||||||
|
||||||
/** | ||||||
* @ignore - internal component. | ||||||
*/ | ||||||
const NativeSelectInput = React.forwardRef(function NativeSelectInput(props, ref) { | ||||||
const { | ||||||
classes, | ||||||
className, | ||||||
const { className, disabled, IconComponent, inputRef, variant = 'standard', ...other } = props; | ||||||
|
||||||
const styleProps = { | ||||||
...props, | ||||||
disabled, | ||||||
IconComponent, | ||||||
inputRef, | ||||||
variant = 'standard', | ||||||
...other | ||||||
} = props; | ||||||
variant, | ||||||
}; | ||||||
|
||||||
const classes = useUtilityClasses(styleProps); | ||||||
return ( | ||||||
<React.Fragment> | ||||||
<select | ||||||
className={clsx( | ||||||
classes.root, // TODO v5: merge root and select | ||||||
classes.select, | ||||||
classes[variant], | ||||||
{ | ||||||
[classes.disabled]: disabled, | ||||||
}, | ||||||
className, | ||||||
)} | ||||||
<SelectRoot | ||||||
styleProps={styleProps} | ||||||
className={clsx(classes.root, className)} | ||||||
disabled={disabled} | ||||||
ref={inputRef || ref} | ||||||
{...other} | ||||||
/> | ||||||
{props.multiple ? null : ( | ||||||
<IconComponent | ||||||
className={clsx(classes.icon, classes[`icon${capitalize(variant)}`], { | ||||||
[classes.disabled]: disabled, | ||||||
})} | ||||||
/> | ||||||
<IconRoot as={IconComponent} styleProps={styleProps} className={classes.icon} /> | ||||||
)} | ||||||
</React.Fragment> | ||||||
); | ||||||
|
@@ -55,7 +155,7 @@ NativeSelectInput.propTypes = { | |||||
* Override or extend the styles applied to the component. | ||||||
* See [CSS API](#css) below for more details. | ||||||
*/ | ||||||
classes: PropTypes.object.isRequired, | ||||||
classes: PropTypes.object, | ||||||
/** | ||||||
* The CSS class name of the select element. | ||||||
*/ | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -1,2 +1,4 @@ | ||||||||
export { default } from './NativeSelect'; | ||||||||
export * from './NativeSelect'; | ||||||||
export { default as nativeSelectClasses } from './nativeSelectClasses'; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Convention with the other files
Suggested change
|
||||||||
export * from './nativeSelectClasses'; |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -1 +1,3 @@ | ||||||||
export { default } from './NativeSelect'; | ||||||||
export { default as nativeSelectClasses } from './nativeSelectClasses'; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Convention with the other files
Suggested change
|
||||||||
export * from './nativeSelectClasses'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { NativeSelectClassKey } from './NativeSelect'; | ||
|
||
declare const nativeSelectClasses: Record<NativeSelectClassKey, string>; | ||
|
||
export function getNativeSelectUtilityClasses(slot: string): string; | ||
|
||
export default nativeSelectClasses; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { generateUtilityClass, generateUtilityClasses } from '@material-ui/unstyled'; | ||
|
||
export function getNativeSelectUtilitiyClasses(slot) { | ||
return generateUtilityClass('MuiNativeSelect', slot); | ||
} | ||
|
||
const nativeSelectClasses = generateUtilityClasses('MuiNativeSelect', [ | ||
'root', | ||
'select', | ||
'filled', | ||
'outlined', | ||
'selectMenu', | ||
'disabled', | ||
'icon', | ||
'iconOpen', | ||
'iconFilled', | ||
'iconOutlined', | ||
'nativeInput', | ||
]); | ||
|
||
export default nativeSelectClasses; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.