/
githubmirror
/
material-ui
Обзор
Документация
Войти
/
githubmirror
/
material-ui
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
packages/mui-material/src/internal/SwitchBase.js
357 строк
8 KB
Olivier Tassinari
[internal] Fix outdated links to the React repository
27 июн 2026, 23:42
Не верифицирован
27 июн 2026, 23:42
3ccff75
Код
Авторство
О чём код?
'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; import composeClasses from '@mui/utils/composeClasses'; import capitalize from '../utils/capitalize'; import rootShouldForwardProp from '../styles/rootShouldForwardProp'; import { styled } from '../zero-styled'; import useControlled from '../utils/useControlled'; import useFormControl from '../FormControl/useFormControl'; import ButtonBase from '../ButtonBase'; import { getSwitchBaseUtilityClass } from './switchBaseClasses'; import useSlot from '../utils/useSlot'; const useUtilityClasses = (ownerState) => { const { classes, checked, disabled, edge } = ownerState; const slots = { root: ['root', checked && 'checked', disabled && 'disabled', edge && `edge${capitalize(edge)}`], input: ['input'], }; return composeClasses(slots, getSwitchBaseUtilityClass, classes); }; const SwitchBaseRoot = styled(ButtonBase, { name: 'MuiSwitchBase', })({ padding: 9, borderRadius: '50%', variants: [ { props: { edge: 'start', size: 'small', }, style: { marginLeft: -3, }, }, { props: ({ edge, ownerState }) => edge === 'start' && ownerState.size !== 'small', style: { marginLeft: -12, }, }, { props: { edge: 'end', size: 'small', }, style: { marginRight: -3, }, }, { props: ({ edge, ownerState }) => edge === 'end' && ownerState.size !== 'small', style: { marginRight: -12, }, }, ], }); const SwitchBaseInput = styled('input', { name: 'MuiSwitchBase', shouldForwardProp: rootShouldForwardProp, })({ cursor: 'inherit', position: 'absolute', opacity: 0, width: '100%', height: '100%', top: 0, left: 0, margin: 0, padding: 0, zIndex: 1, }); /** * @ignore - internal component. */ const SwitchBase = React.forwardRef(function SwitchBase(props, ref) { const { autoFocus, checked: checkedProp, checkedIcon, defaultChecked, disabled: disabledProp, disableFocusRipple = false, edge = false, icon, id, name, onBlur, onChange, onFocus, readOnly, required = false, tabIndex, type, value, slots = {}, slotProps = {}, ...other } = props; const { nativeButton, ...buttonBaseProps } = other; const [checked, setCheckedState] = useControlled({ controlled: checkedProp, default: Boolean(defaultChecked), name: 'SwitchBase', state: 'checked', }); const muiFormControl = useFormControl(); const handleFocus = (event) => { if (onFocus) { onFocus(event); } if (muiFormControl && muiFormControl.onFocus) { muiFormControl.onFocus(event); } }; const handleBlur = (event) => { if (onBlur) { onBlur(event); } if (muiFormControl && muiFormControl.onBlur) { muiFormControl.onBlur(event); } }; const handleInputChange = (event) => { // Workaround for https://github.com/react/react/issues/9023 if (event.nativeEvent.defaultPrevented || readOnly) { return; } const newChecked = event.target.checked; setCheckedState(newChecked); if (onChange) { // TODO v6: remove the second argument. onChange(event, newChecked); } }; let disabled = disabledProp; if (muiFormControl) { if (typeof disabled === 'undefined') { disabled = muiFormControl.disabled; } } const hasLabelFor = type === 'checkbox' || type === 'radio'; const ownerState = { ...props, checked, disabled, disableFocusRipple, edge, }; const classes = useUtilityClasses(ownerState); const externalForwardedProps = { slots, slotProps, }; const [RootSlot, rootSlotProps] = useSlot('root', { ref, elementType: SwitchBaseRoot, className: classes.root, shouldForwardComponentProp: true, externalForwardedProps: { ...externalForwardedProps, component: 'span', ...buttonBaseProps, }, getSlotProps: (handlers) => ({ ...handlers, onFocus: (event) => { handlers.onFocus?.(event); handleFocus(event); }, onBlur: (event) => { handlers.onBlur?.(event); handleBlur(event); }, }), ownerState, additionalProps: { centerRipple: true, focusRipple: !disableFocusRipple, role: undefined, tabIndex: null, }, }); const [InputSlot, inputSlotProps] = useSlot('input', { elementType: SwitchBaseInput, className: classes.input, externalForwardedProps, getSlotProps: (handlers) => ({ ...handlers, onChange: (event) => { handlers.onChange?.(event); handleInputChange(event); }, }), ownerState, additionalProps: { autoFocus, checked: checkedProp, defaultChecked, disabled, id: hasLabelFor ? id : undefined, name, readOnly, required, tabIndex, type, ...(type === 'checkbox' && value === undefined ? {} : { value }), }, }); return ( <RootSlot {...rootSlotProps}> <InputSlot {...inputSlotProps} /> {checked ? checkedIcon : icon} </RootSlot> ); }); // NB: If changed, please update Checkbox, Switch and Radio // so that the API documentation is updated. SwitchBase.propTypes = { /** * If `true`, the `input` element is focused during the first mount. */ autoFocus: PropTypes.bool, /** * If `true`, the component is checked. */ checked: PropTypes.bool, /** * The icon to display when the component is checked. */ checkedIcon: PropTypes.node.isRequired, /** * Override or extend the styles applied to the component. */ classes: PropTypes.object, /** * @ignore */ className: PropTypes.string, /** * @ignore */ defaultChecked: PropTypes.bool, /** * If `true`, the component is disabled. */ disabled: PropTypes.bool, /** * If `true`, the keyboard focus ripple is disabled. * @default false */ disableFocusRipple: PropTypes.bool, /** * If given, uses a negative margin to counteract the padding on one * side (this is often helpful for aligning the left or right * side of the icon with content above or below, without ruining the border * size and shape). * @default false */ edge: PropTypes.oneOf(['end', 'start', false]), /** * The icon to display when the component is unchecked. */ icon: PropTypes.node.isRequired, /** * The id of the `input` element. */ id: PropTypes.string, /* * @ignore */ name: PropTypes.string, /** * @ignore */ onBlur: PropTypes.func, /** * Callback fired when the state is changed. * * @param {object} event The event source of the callback. * You can pull out the new checked state by accessing `event.target.checked` (boolean). */ onChange: PropTypes.func, /** * @ignore */ onFocus: PropTypes.func, /** * It prevents the user from changing the value of the field * (not from interacting with the field). */ readOnly: PropTypes.bool, /** * If `true`, the `input` element is required. */ required: PropTypes.bool, /** * The props used for each slot inside. * @default {} */ slotProps: PropTypes.shape({ input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), }), /** * The components used for each slot inside. * @default {} */ slots: PropTypes.shape({ input: PropTypes.elementType, root: PropTypes.elementType, }), /** * The system prop that allows defining system overrides as well as additional CSS styles. */ sx: PropTypes.object, /** * @ignore */ tabIndex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), /** * The input component prop `type`. */ type: PropTypes.string.isRequired, /** * The value of the component. */ value: PropTypes.any, }; export default SwitchBase;