UNPKG

@mui/joy

Version:

Joy UI is an open-source React component library that implements MUI's own design principles. It's comprehensive and can be used in production out of the box.

462 lines (461 loc) 16.9 kB
'use client'; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; import _extends from "@babel/runtime/helpers/esm/extends"; const _excluded = ["checked", "defaultChecked", "disabled", "onBlur", "onChange", "onFocus", "onFocusVisible", "readOnly", "required", "id", "color", "variant", "size", "startDecorator", "endDecorator", "component", "slots", "slotProps"]; import * as React from 'react'; import PropTypes from 'prop-types'; import { unstable_capitalize as capitalize } from '@mui/utils'; import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses'; import { useSwitch } from '@mui/base/useSwitch'; import { styled, useThemeProps } from '../styles'; import useSlot from '../utils/useSlot'; import switchClasses, { getSwitchUtilityClass } from './switchClasses'; import FormControlContext from '../FormControl/FormControlContext'; import { jsx as _jsx } from "react/jsx-runtime"; import { jsxs as _jsxs } from "react/jsx-runtime"; const useUtilityClasses = ownerState => { const { checked, disabled, focusVisible, readOnly, color, variant, size } = ownerState; const slots = { root: ['root', checked && 'checked', disabled && 'disabled', focusVisible && 'focusVisible', readOnly && 'readOnly', variant && `variant${capitalize(variant)}`, color && `color${capitalize(color)}`, size && `size${capitalize(size)}`], thumb: ['thumb', checked && 'checked'], track: ['track', checked && 'checked'], action: ['action', focusVisible && 'focusVisible'], input: ['input'], startDecorator: ['startDecorator'], endDecorator: ['endDecorator'] }; return composeClasses(slots, getSwitchUtilityClass, {}); }; const switchColorVariables = ({ theme, ownerState }) => (data = {}) => { var _theme$variants, _styles$backgroundCol, _styles$backgroundCol2; const styles = ((_theme$variants = theme.variants[`${ownerState.variant}${data.state || ''}`]) == null ? void 0 : _theme$variants[ownerState.color]) || {}; return { '--Switch-trackBackground': (_styles$backgroundCol = styles.backgroundColor) != null ? _styles$backgroundCol : theme.vars.palette.background.surface, '--Switch-trackColor': styles.color, '--Switch-trackBorderColor': ownerState.variant === 'outlined' ? styles.borderColor : 'currentColor', '--Switch-thumbBackground': styles.color, '--Switch-thumbColor': (_styles$backgroundCol2 = styles.backgroundColor) != null ? _styles$backgroundCol2 : theme.vars.palette.background.surface }; }; const SwitchRoot = styled('div', { name: 'JoySwitch', slot: 'Root', overridesResolver: (props, styles) => styles.root })(({ theme, ownerState }) => { var _theme$variants2; const getColorVariables = switchColorVariables({ theme, ownerState }); return _extends({ '--Icon-color': 'currentColor', '--variant-borderWidth': (_theme$variants2 = theme.variants[ownerState.variant]) == null || (_theme$variants2 = _theme$variants2[ownerState.color]) == null ? void 0 : _theme$variants2['--variant-borderWidth'], '--Switch-trackRadius': theme.vars.radius.xl, '--Switch-thumbShadow': ownerState.variant === 'soft' ? 'none' : '0 0 0 1px var(--Switch-trackBackground)' }, ownerState.size === 'sm' && { '--Switch-trackWidth': '26px', '--Switch-trackHeight': '16px', '--Switch-thumbSize': '10px', fontSize: theme.vars.fontSize.sm, gap: 'var(--Switch-gap, 6px)' }, ownerState.size === 'md' && { '--Switch-trackWidth': '32px', '--Switch-trackHeight': '20px', '--Switch-thumbSize': '14px', fontSize: theme.vars.fontSize.md, gap: 'var(--Switch-gap, 8px)' }, ownerState.size === 'lg' && { '--Switch-trackWidth': '40px', '--Switch-trackHeight': '24px', '--Switch-thumbSize': '18px', gap: 'var(--Switch-gap, 12px)' }, { '--unstable_paddingBlock': `max((var(--Switch-trackHeight) - 2 * var(--variant-borderWidth, 0px) - var(--Switch-thumbSize)) / 2, 0px)`, '--Switch-thumbRadius': `max(var(--Switch-trackRadius) - var(--unstable_paddingBlock), min(var(--unstable_paddingBlock) / 2, var(--Switch-trackRadius) / 2))`, '--Switch-thumbWidth': 'var(--Switch-thumbSize)', '--Switch-thumbOffset': `max((var(--Switch-trackHeight) - var(--Switch-thumbSize)) / 2, 0px)` }, getColorVariables(), { '&:hover': { '@media (hover: hover)': _extends({}, getColorVariables({ state: 'Hover' })) }, [`&.${switchClasses.checked}`]: _extends({}, getColorVariables(), { '&:hover': { '@media (hover: hover)': _extends({}, getColorVariables({ state: 'Hover' })) } }), [`&.${switchClasses.disabled}`]: _extends({ pointerEvents: 'none', color: theme.vars.palette.text.tertiary }, getColorVariables({ state: 'Disabled' })), display: 'inline-flex', alignItems: 'center', alignSelf: 'center', fontFamily: theme.vars.fontFamily.body, position: 'relative', padding: 'calc((var(--Switch-thumbSize) / 2) - (var(--Switch-trackHeight) / 2)) calc(-1 * var(--Switch-thumbOffset))', backgroundColor: 'initial', // clear background in case `outlined` variant contain background. border: 'none', margin: 'var(--unstable_Switch-margin)' }); }); const SwitchAction = styled('div', { name: 'JoySwitch', slot: 'Action', overridesResolver: (props, styles) => styles.action })(({ theme }) => ({ borderRadius: 'var(--Switch-trackRadius)', position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, [theme.focus.selector]: theme.focus.default })); const SwitchInput = styled('input', { name: 'JoySwitch', slot: 'Input', overridesResolver: (props, styles) => styles.input })({ margin: 0, height: '100%', width: '100%', opacity: 0, position: 'absolute', cursor: 'pointer' }); const SwitchTrack = styled('span', { name: 'JoySwitch', slot: 'Track', overridesResolver: (props, styles) => styles.track })(({ theme, ownerState }) => _extends({ position: 'relative', color: 'var(--Switch-trackColor)', height: 'var(--Switch-trackHeight)', width: 'var(--Switch-trackWidth)', display: 'flex', flexShrink: 0, justifyContent: 'space-between', alignItems: 'center', boxSizing: 'border-box', border: 'var(--variant-borderWidth, 0px) solid', borderColor: 'var(--Switch-trackBorderColor)', backgroundColor: 'var(--Switch-trackBackground)', borderRadius: 'var(--Switch-trackRadius)', fontFamily: theme.vars.fontFamily.body }, ownerState.size === 'sm' && { fontSize: theme.vars.fontSize.xs }, ownerState.size === 'md' && { fontSize: theme.vars.fontSize.sm }, ownerState.size === 'lg' && { fontSize: theme.vars.fontSize.md })); const SwitchThumb = styled('span', { name: 'JoySwitch', slot: 'Thumb', overridesResolver: (props, styles) => styles.thumb })({ '--Icon-fontSize': 'calc(var(--Switch-thumbSize) * 0.75)', display: 'inline-flex', justifyContent: 'center', alignItems: 'center', position: 'absolute', top: '50%', left: 'calc(50% - var(--Switch-trackWidth) / 2 + var(--Switch-thumbWidth) / 2 + var(--Switch-thumbOffset))', transform: 'translate(-50%, -50%)', width: 'var(--Switch-thumbWidth)', height: 'var(--Switch-thumbSize)', borderRadius: 'var(--Switch-thumbRadius)', boxShadow: 'var(--Switch-thumbShadow)', color: 'var(--Switch-thumbColor)', backgroundColor: 'var(--Switch-thumbBackground)', [`&.${switchClasses.checked}`]: { left: 'calc(50% + var(--Switch-trackWidth) / 2 - var(--Switch-thumbWidth) / 2 - var(--Switch-thumbOffset))' } }); const SwitchStartDecorator = styled('span', { name: 'JoySwitch', slot: 'StartDecorator', overridesResolver: (props, styles) => styles.startDecorator })({ display: 'inline-flex' }); const SwitchEndDecorator = styled('span', { name: 'JoySwitch', slot: 'EndDecorator', overridesResolver: (props, styles) => styles.endDecorator })({ display: 'inline-flex' }); /** * * Demos: * * - [Switch](https://mui.com/joy-ui/react-switch/) * * API: * * - [Switch API](https://mui.com/joy-ui/api/switch/) */ const Switch = /*#__PURE__*/React.forwardRef(function Switch(inProps, ref) { var _ref, _inProps$size, _inProps$color, _formControl$color, _ref2, _inProps$disabled; const props = useThemeProps({ props: inProps, name: 'JoySwitch' }); const { disabled: disabledExternalProp, id, color: colorProp, variant = 'solid', size: sizeProp = 'md', startDecorator, endDecorator, component, slots = {}, slotProps = {} } = props, other = _objectWithoutPropertiesLoose(props, _excluded); const formControl = React.useContext(FormControlContext); if (process.env.NODE_ENV !== 'production') { const registerEffect = formControl == null ? void 0 : formControl.registerEffect; // eslint-disable-next-line react-hooks/rules-of-hooks React.useEffect(() => { if (registerEffect) { return registerEffect(); } return undefined; }, [registerEffect]); } const size = (_ref = (_inProps$size = inProps.size) != null ? _inProps$size : formControl == null ? void 0 : formControl.size) != null ? _ref : sizeProp; const color = (_inProps$color = inProps.color) != null ? _inProps$color : formControl != null && formControl.error ? 'danger' : (_formControl$color = formControl == null ? void 0 : formControl.color) != null ? _formControl$color : colorProp; const useSwitchProps = _extends({ disabled: (_ref2 = (_inProps$disabled = inProps.disabled) != null ? _inProps$disabled : formControl == null ? void 0 : formControl.disabled) != null ? _ref2 : disabledExternalProp }, props); const { getInputProps, checked, disabled, focusVisible, readOnly } = useSwitch(useSwitchProps); const ownerState = _extends({}, props, { id, checked, disabled, focusVisible, readOnly, color: checked ? color || 'primary' : color || 'neutral', variant, size }); const classes = useUtilityClasses(ownerState); const externalForwardedProps = _extends({}, other, { component, slots, slotProps }); const [SlotRoot, rootProps] = useSlot('root', { ref, className: classes.root, elementType: SwitchRoot, externalForwardedProps, ownerState }); const [SlotStartDecorator, startDecoratorProps] = useSlot('startDecorator', { additionalProps: { 'aria-hidden': true // hide the decorator from assistive technology }, className: classes.startDecorator, elementType: SwitchStartDecorator, externalForwardedProps, ownerState }); const [SlotEndDecorator, endDecoratorProps] = useSlot('endDecorator', { additionalProps: { 'aria-hidden': true // hide the decorator from assistive technology }, className: classes.endDecorator, elementType: SwitchEndDecorator, externalForwardedProps, ownerState }); const [SlotTrack, trackProps] = useSlot('track', { className: classes.track, elementType: SwitchTrack, externalForwardedProps, ownerState }); const [SlotThumb, thumbProps] = useSlot('thumb', { className: classes.thumb, elementType: SwitchThumb, externalForwardedProps, ownerState }); const [SlotAction, actionProps] = useSlot('action', { className: classes.action, elementType: SwitchAction, externalForwardedProps, ownerState }); const [SlotInput, inputProps] = useSlot('input', { additionalProps: { id: id != null ? id : formControl == null ? void 0 : formControl.htmlFor, 'aria-describedby': formControl == null ? void 0 : formControl['aria-describedby'] }, className: classes.input, elementType: SwitchInput, externalForwardedProps, getSlotProps: getInputProps, ownerState }); return /*#__PURE__*/_jsxs(SlotRoot, _extends({}, rootProps, { children: [startDecorator && /*#__PURE__*/_jsx(SlotStartDecorator, _extends({}, startDecoratorProps, { children: typeof startDecorator === 'function' ? startDecorator(ownerState) : startDecorator })), /*#__PURE__*/_jsxs(SlotTrack, _extends({}, trackProps, { children: [trackProps == null ? void 0 : trackProps.children, /*#__PURE__*/_jsx(SlotThumb, _extends({}, thumbProps))] })), /*#__PURE__*/_jsx(SlotAction, _extends({}, actionProps, { children: /*#__PURE__*/_jsx(SlotInput, _extends({}, inputProps)) })), endDecorator && /*#__PURE__*/_jsx(SlotEndDecorator, _extends({}, endDecoratorProps, { children: typeof endDecorator === 'function' ? endDecorator(ownerState) : endDecorator }))] })); }); process.env.NODE_ENV !== "production" ? Switch.propTypes /* remove-proptypes */ = { // ┌────────────────────────────── Warning ──────────────────────────────┐ // │ These PropTypes are generated from the TypeScript type definitions. │ // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │ // └─────────────────────────────────────────────────────────────────────┘ /** * If `true`, the component is checked. */ checked: PropTypes.bool, /** * @ignore */ children: PropTypes.node, /** * The color of the component. It supports those theme colors that make sense for this component. * @default 'neutral' */ color: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.oneOf(['danger', 'primary', 'success', 'warning']), PropTypes.string]), /** * The component used for the root node. * Either a string to use a HTML element or a component. */ component: PropTypes.elementType, /** * The default checked state. Use when the component is not controlled. */ defaultChecked: PropTypes.bool, /** * If `true`, the component is disabled. */ disabled: PropTypes.bool, /** * The element that appears at the end of the switch. */ endDecorator: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.node, PropTypes.func]), /** * @ignore */ id: PropTypes.string, /** * @ignore */ onBlur: PropTypes.func, /** * Callback fired when the state is changed. * * @param {React.ChangeEvent<HTMLInputElement>} event The event source of the callback. * You can pull out the new value by accessing `event.target.value` (string). * You can pull out the new checked state by accessing `event.target.checked` (boolean). */ onChange: PropTypes.func, /** * @ignore */ onFocus: PropTypes.func, /** * @ignore */ onFocusVisible: PropTypes.func, /** * If `true`, the component is read only. */ readOnly: PropTypes.bool, /** * If `true`, the `input` element is required. */ required: PropTypes.bool, /** * The size of the component. * @default 'md' */ size: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.oneOf(['sm', 'md', 'lg']), PropTypes.string]), /** * The props used for each slot inside. * @default {} */ slotProps: PropTypes.shape({ action: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), endDecorator: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), input: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), startDecorator: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), thumb: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), track: PropTypes.oneOfType([PropTypes.func, PropTypes.object]) }), /** * The components used for each slot inside. * @default {} */ slots: PropTypes.shape({ action: PropTypes.elementType, endDecorator: PropTypes.elementType, input: PropTypes.elementType, root: PropTypes.elementType, startDecorator: PropTypes.elementType, thumb: PropTypes.elementType, track: PropTypes.elementType }), /** * The element that appears at the end of the switch. */ startDecorator: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.node, PropTypes.func]), /** * The system prop that allows defining system overrides as well as additional CSS styles. */ sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]), /** * The [global variant](https://mui.com/joy-ui/main-features/global-variants/) to use. * @default 'solid' */ variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.oneOf(['outlined', 'plain', 'soft', 'solid']), PropTypes.string]) } : void 0; export default Switch;