UNPKG

@mui/material

Version:

Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box.

695 lines (694 loc) 22.4 kB
"use strict"; 'use client'; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _clsx = _interopRequireDefault(require("clsx")); var _resolveProps = _interopRequireDefault(require("@mui/utils/resolveProps")); var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses")); var _colorManipulator = require("@mui/system/colorManipulator"); var _utils = require("../utils"); var _rootShouldForwardProp = _interopRequireDefault(require("../styles/rootShouldForwardProp")); var _zeroStyled = require("../zero-styled"); var _memoTheme = _interopRequireDefault(require("../utils/memoTheme")); var _DefaultPropsProvider = require("../DefaultPropsProvider"); var _ButtonBase = _interopRequireDefault(require("../ButtonBase")); var _CircularProgress = _interopRequireDefault(require("../CircularProgress")); var _capitalize = _interopRequireDefault(require("../utils/capitalize")); var _createSimplePaletteValueFilter = _interopRequireDefault(require("../utils/createSimplePaletteValueFilter")); var _buttonClasses = _interopRequireWildcard(require("./buttonClasses")); var _ButtonGroupContext = _interopRequireDefault(require("../ButtonGroup/ButtonGroupContext")); var _ButtonGroupButtonContext = _interopRequireDefault(require("../ButtonGroup/ButtonGroupButtonContext")); var _jsxRuntime = require("react/jsx-runtime"); const useUtilityClasses = ownerState => { const { color, disableElevation, fullWidth, size, variant, loading, loadingPosition, classes } = ownerState; const slots = { root: ['root', loading && 'loading', variant, `${variant}${(0, _capitalize.default)(color)}`, `size${(0, _capitalize.default)(size)}`, `${variant}Size${(0, _capitalize.default)(size)}`, `color${(0, _capitalize.default)(color)}`, disableElevation && 'disableElevation', fullWidth && 'fullWidth', loading && `loadingPosition${(0, _capitalize.default)(loadingPosition)}`], startIcon: ['icon', 'startIcon', `iconSize${(0, _capitalize.default)(size)}`], endIcon: ['icon', 'endIcon', `iconSize${(0, _capitalize.default)(size)}`], loadingIndicator: ['loadingIndicator'], loadingWrapper: ['loadingWrapper'] }; const composedClasses = (0, _composeClasses.default)(slots, _buttonClasses.getButtonUtilityClass, classes); return { ...classes, // forward the focused, disabled, etc. classes to the ButtonBase ...composedClasses }; }; const commonIconStyles = [{ props: { size: 'small' }, style: { '& > *:nth-of-type(1)': { fontSize: 18 } } }, { props: { size: 'medium' }, style: { '& > *:nth-of-type(1)': { fontSize: 20 } } }, { props: { size: 'large' }, style: { '& > *:nth-of-type(1)': { fontSize: 22 } } }]; const ButtonRoot = (0, _zeroStyled.styled)(_ButtonBase.default, { shouldForwardProp: prop => (0, _rootShouldForwardProp.default)(prop) || prop === 'classes', name: 'MuiButton', slot: 'Root', overridesResolver: (props, styles) => { const { ownerState } = props; return [styles.root, styles[ownerState.variant], styles[`${ownerState.variant}${(0, _capitalize.default)(ownerState.color)}`], styles[`size${(0, _capitalize.default)(ownerState.size)}`], styles[`${ownerState.variant}Size${(0, _capitalize.default)(ownerState.size)}`], ownerState.color === 'inherit' && styles.colorInherit, ownerState.disableElevation && styles.disableElevation, ownerState.fullWidth && styles.fullWidth, ownerState.loading && styles.loading]; } })((0, _memoTheme.default)(({ theme }) => { const inheritContainedBackgroundColor = theme.palette.mode === 'light' ? theme.palette.grey[300] : theme.palette.grey[800]; const inheritContainedHoverBackgroundColor = theme.palette.mode === 'light' ? theme.palette.grey.A100 : theme.palette.grey[700]; return { ...theme.typography.button, minWidth: 64, padding: '6px 16px', border: 0, borderRadius: (theme.vars || theme).shape.borderRadius, transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], { duration: theme.transitions.duration.short }), '&:hover': { textDecoration: 'none' }, [`&.${_buttonClasses.default.disabled}`]: { color: (theme.vars || theme).palette.action.disabled }, variants: [{ props: { variant: 'contained' }, style: { color: `var(--variant-containedColor)`, backgroundColor: `var(--variant-containedBg)`, boxShadow: (theme.vars || theme).shadows[2], '&:hover': { boxShadow: (theme.vars || theme).shadows[4], // Reset on touch devices, it doesn't add specificity '@media (hover: none)': { boxShadow: (theme.vars || theme).shadows[2] } }, '&:active': { boxShadow: (theme.vars || theme).shadows[8] }, [`&.${_buttonClasses.default.focusVisible}`]: { boxShadow: (theme.vars || theme).shadows[6] }, [`&.${_buttonClasses.default.disabled}`]: { color: (theme.vars || theme).palette.action.disabled, boxShadow: (theme.vars || theme).shadows[0], backgroundColor: (theme.vars || theme).palette.action.disabledBackground } } }, { props: { variant: 'outlined' }, style: { padding: '5px 15px', border: '1px solid currentColor', borderColor: `var(--variant-outlinedBorder, currentColor)`, backgroundColor: `var(--variant-outlinedBg)`, color: `var(--variant-outlinedColor)`, [`&.${_buttonClasses.default.disabled}`]: { border: `1px solid ${(theme.vars || theme).palette.action.disabledBackground}` } } }, { props: { variant: 'text' }, style: { padding: '6px 8px', color: `var(--variant-textColor)`, backgroundColor: `var(--variant-textBg)` } }, ...Object.entries(theme.palette).filter((0, _createSimplePaletteValueFilter.default)()).map(([color]) => ({ props: { color }, style: { '--variant-textColor': (theme.vars || theme).palette[color].main, '--variant-outlinedColor': (theme.vars || theme).palette[color].main, '--variant-outlinedBorder': theme.vars ? `rgba(${theme.vars.palette[color].mainChannel} / 0.5)` : (0, _colorManipulator.alpha)(theme.palette[color].main, 0.5), '--variant-containedColor': (theme.vars || theme).palette[color].contrastText, '--variant-containedBg': (theme.vars || theme).palette[color].main, '@media (hover: hover)': { '&:hover': { '--variant-containedBg': (theme.vars || theme).palette[color].dark, '--variant-textBg': theme.vars ? `rgba(${theme.vars.palette[color].mainChannel} / ${theme.vars.palette.action.hoverOpacity})` : (0, _colorManipulator.alpha)(theme.palette[color].main, theme.palette.action.hoverOpacity), '--variant-outlinedBorder': (theme.vars || theme).palette[color].main, '--variant-outlinedBg': theme.vars ? `rgba(${theme.vars.palette[color].mainChannel} / ${theme.vars.palette.action.hoverOpacity})` : (0, _colorManipulator.alpha)(theme.palette[color].main, theme.palette.action.hoverOpacity) } } } })), { props: { color: 'inherit' }, style: { color: 'inherit', borderColor: 'currentColor', '--variant-containedBg': theme.vars ? theme.vars.palette.Button.inheritContainedBg : inheritContainedBackgroundColor, '@media (hover: hover)': { '&:hover': { '--variant-containedBg': theme.vars ? theme.vars.palette.Button.inheritContainedHoverBg : inheritContainedHoverBackgroundColor, '--variant-textBg': theme.vars ? `rgba(${theme.vars.palette.text.primaryChannel} / ${theme.vars.palette.action.hoverOpacity})` : (0, _colorManipulator.alpha)(theme.palette.text.primary, theme.palette.action.hoverOpacity), '--variant-outlinedBg': theme.vars ? `rgba(${theme.vars.palette.text.primaryChannel} / ${theme.vars.palette.action.hoverOpacity})` : (0, _colorManipulator.alpha)(theme.palette.text.primary, theme.palette.action.hoverOpacity) } } } }, { props: { size: 'small', variant: 'text' }, style: { padding: '4px 5px', fontSize: theme.typography.pxToRem(13) } }, { props: { size: 'large', variant: 'text' }, style: { padding: '8px 11px', fontSize: theme.typography.pxToRem(15) } }, { props: { size: 'small', variant: 'outlined' }, style: { padding: '3px 9px', fontSize: theme.typography.pxToRem(13) } }, { props: { size: 'large', variant: 'outlined' }, style: { padding: '7px 21px', fontSize: theme.typography.pxToRem(15) } }, { props: { size: 'small', variant: 'contained' }, style: { padding: '4px 10px', fontSize: theme.typography.pxToRem(13) } }, { props: { size: 'large', variant: 'contained' }, style: { padding: '8px 22px', fontSize: theme.typography.pxToRem(15) } }, { props: { disableElevation: true }, style: { boxShadow: 'none', '&:hover': { boxShadow: 'none' }, [`&.${_buttonClasses.default.focusVisible}`]: { boxShadow: 'none' }, '&:active': { boxShadow: 'none' }, [`&.${_buttonClasses.default.disabled}`]: { boxShadow: 'none' } } }, { props: { fullWidth: true }, style: { width: '100%' } }, { props: { loadingPosition: 'center' }, style: { transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color'], { duration: theme.transitions.duration.short }), [`&.${_buttonClasses.default.loading}`]: { color: 'transparent' } } }] }; })); const ButtonStartIcon = (0, _zeroStyled.styled)('span', { name: 'MuiButton', slot: 'StartIcon', overridesResolver: (props, styles) => { const { ownerState } = props; return [styles.startIcon, ownerState.loading && styles.startIconLoadingStart, styles[`iconSize${(0, _capitalize.default)(ownerState.size)}`]]; } })(({ theme }) => ({ display: 'inherit', marginRight: 8, marginLeft: -4, variants: [{ props: { size: 'small' }, style: { marginLeft: -2 } }, { props: { loadingPosition: 'start', loading: true }, style: { transition: theme.transitions.create(['opacity'], { duration: theme.transitions.duration.short }), opacity: 0 } }, { props: { loadingPosition: 'start', loading: true, fullWidth: true }, style: { marginRight: -8 } }, ...commonIconStyles] })); const ButtonEndIcon = (0, _zeroStyled.styled)('span', { name: 'MuiButton', slot: 'EndIcon', overridesResolver: (props, styles) => { const { ownerState } = props; return [styles.endIcon, ownerState.loading && styles.endIconLoadingEnd, styles[`iconSize${(0, _capitalize.default)(ownerState.size)}`]]; } })(({ theme }) => ({ display: 'inherit', marginRight: -4, marginLeft: 8, variants: [{ props: { size: 'small' }, style: { marginRight: -2 } }, { props: { loadingPosition: 'end', loading: true }, style: { transition: theme.transitions.create(['opacity'], { duration: theme.transitions.duration.short }), opacity: 0 } }, { props: { loadingPosition: 'end', loading: true, fullWidth: true }, style: { marginLeft: -8 } }, ...commonIconStyles] })); const ButtonLoadingIndicator = (0, _zeroStyled.styled)('span', { name: 'MuiButton', slot: 'LoadingIndicator', overridesResolver: (props, styles) => styles.loadingIndicator })(({ theme }) => ({ display: 'none', position: 'absolute', visibility: 'visible', variants: [{ props: { loading: true }, style: { display: 'flex' } }, { props: { loadingPosition: 'start' }, style: { left: 14 } }, { props: { loadingPosition: 'start', size: 'small' }, style: { left: 10 } }, { props: { variant: 'text', loadingPosition: 'start' }, style: { left: 6 } }, { props: { loadingPosition: 'center' }, style: { left: '50%', transform: 'translate(-50%)', color: (theme.vars || theme).palette.action.disabled } }, { props: { loadingPosition: 'end' }, style: { right: 14 } }, { props: { loadingPosition: 'end', size: 'small' }, style: { right: 10 } }, { props: { variant: 'text', loadingPosition: 'end' }, style: { right: 6 } }, { props: { loadingPosition: 'start', fullWidth: true }, style: { position: 'relative', left: -10 } }, { props: { loadingPosition: 'end', fullWidth: true }, style: { position: 'relative', right: -10 } }] })); const ButtonLoadingIconPlaceholder = (0, _zeroStyled.styled)('span', { name: 'MuiButton', slot: 'LoadingIconPlaceholder', overridesResolver: (props, styles) => styles.loadingIconPlaceholder })({ display: 'inline-block', width: '1em', height: '1em' }); const Button = /*#__PURE__*/React.forwardRef(function Button(inProps, ref) { // props priority: `inProps` > `contextProps` > `themeDefaultProps` const contextProps = React.useContext(_ButtonGroupContext.default); const buttonGroupButtonContextPositionClassName = React.useContext(_ButtonGroupButtonContext.default); const resolvedProps = (0, _resolveProps.default)(contextProps, inProps); const props = (0, _DefaultPropsProvider.useDefaultProps)({ props: resolvedProps, name: 'MuiButton' }); const { children, color = 'primary', component = 'button', className, disabled = false, disableElevation = false, disableFocusRipple = false, endIcon: endIconProp, focusVisibleClassName, fullWidth = false, id: idProp, loading = null, loadingIndicator: loadingIndicatorProp, loadingPosition = 'center', size = 'medium', startIcon: startIconProp, type, variant = 'text', ...other } = props; const loadingId = (0, _utils.unstable_useId)(idProp); const loadingIndicator = loadingIndicatorProp ?? /*#__PURE__*/(0, _jsxRuntime.jsx)(_CircularProgress.default, { "aria-labelledby": loadingId, color: "inherit", size: 16 }); const ownerState = { ...props, color, component, disabled, disableElevation, disableFocusRipple, fullWidth, loading, loadingIndicator, loadingPosition, size, type, variant }; const classes = useUtilityClasses(ownerState); const startIcon = (startIconProp || loading && loadingPosition === 'start') && /*#__PURE__*/(0, _jsxRuntime.jsx)(ButtonStartIcon, { className: classes.startIcon, ownerState: ownerState, children: startIconProp || /*#__PURE__*/(0, _jsxRuntime.jsx)(ButtonLoadingIconPlaceholder, { className: classes.loadingIconPlaceholder, ownerState: ownerState }) }); const endIcon = (endIconProp || loading && loadingPosition === 'end') && /*#__PURE__*/(0, _jsxRuntime.jsx)(ButtonEndIcon, { className: classes.endIcon, ownerState: ownerState, children: endIconProp || /*#__PURE__*/(0, _jsxRuntime.jsx)(ButtonLoadingIconPlaceholder, { className: classes.loadingIconPlaceholder, ownerState: ownerState }) }); const positionClassName = buttonGroupButtonContextPositionClassName || ''; const loader = typeof loading === 'boolean' ? /*#__PURE__*/ // use plain HTML span to minimize the runtime overhead (0, _jsxRuntime.jsx)("span", { className: classes.loadingWrapper, style: { display: 'contents' }, children: loading && /*#__PURE__*/(0, _jsxRuntime.jsx)(ButtonLoadingIndicator, { className: classes.loadingIndicator, ownerState: ownerState, children: loadingIndicator }) }) : null; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(ButtonRoot, { ownerState: ownerState, className: (0, _clsx.default)(contextProps.className, classes.root, className, positionClassName), component: component, disabled: disabled || loading, focusRipple: !disableFocusRipple, focusVisibleClassName: (0, _clsx.default)(classes.focusVisible, focusVisibleClassName), ref: ref, type: type, id: loading ? loadingId : idProp, ...other, classes: classes, children: [startIcon, loadingPosition !== 'end' && loader, children, loadingPosition === 'end' && loader, endIcon] }); }); process.env.NODE_ENV !== "production" ? Button.propTypes /* remove-proptypes */ = { // ┌────────────────────────────── Warning ──────────────────────────────┐ // │ These PropTypes are generated from the TypeScript type definitions. │ // │ To update them, edit the d.ts file and run `pnpm proptypes`. │ // └─────────────────────────────────────────────────────────────────────┘ /** * The content of the component. */ children: _propTypes.default.node, /** * Override or extend the styles applied to the component. */ classes: _propTypes.default.object, /** * @ignore */ className: _propTypes.default.string, /** * The color of the component. * It supports both default and custom theme colors, which can be added as shown in the * [palette customization guide](https://mui.com/material-ui/customization/palette/#custom-colors). * @default 'primary' */ color: _propTypes.default /* @typescript-to-proptypes-ignore */.oneOfType([_propTypes.default.oneOf(['inherit', 'primary', 'secondary', 'success', 'error', 'info', 'warning']), _propTypes.default.string]), /** * The component used for the root node. * Either a string to use a HTML element or a component. */ component: _propTypes.default.elementType, /** * If `true`, the component is disabled. * @default false */ disabled: _propTypes.default.bool, /** * If `true`, no elevation is used. * @default false */ disableElevation: _propTypes.default.bool, /** * If `true`, the keyboard focus ripple is disabled. * @default false */ disableFocusRipple: _propTypes.default.bool, /** * If `true`, the ripple effect is disabled. * * ⚠️ Without a ripple there is no styling for :focus-visible by default. Be sure * to highlight the element by applying separate styles with the `.Mui-focusVisible` class. * @default false */ disableRipple: _propTypes.default.bool, /** * Element placed after the children. */ endIcon: _propTypes.default.node, /** * @ignore */ focusVisibleClassName: _propTypes.default.string, /** * If `true`, the button will take up the full width of its container. * @default false */ fullWidth: _propTypes.default.bool, /** * The URL to link to when the button is clicked. * If defined, an `a` element will be used as the root node. */ href: _propTypes.default.string, /** * @ignore */ id: _propTypes.default.string, /** * If `true`, the loading indicator is visible and the button is disabled. * If `true | false`, the loading wrapper is always rendered before the children to prevent [Google Translation Crash](https://github.com/mui/material-ui/issues/27853). * @default null */ loading: _propTypes.default.bool, /** * Element placed before the children if the button is in loading state. * The node should contain an element with `role="progressbar"` with an accessible name. * By default, it renders a `CircularProgress` that is labeled by the button itself. * @default <CircularProgress color="inherit" size={16} /> */ loadingIndicator: _propTypes.default.node, /** * The loading indicator can be positioned on the start, end, or the center of the button. * @default 'center' */ loadingPosition: _propTypes.default.oneOf(['center', 'end', 'start']), /** * The size of the component. * `small` is equivalent to the dense button styling. * @default 'medium' */ size: _propTypes.default /* @typescript-to-proptypes-ignore */.oneOfType([_propTypes.default.oneOf(['small', 'medium', 'large']), _propTypes.default.string]), /** * Element placed before the children. */ startIcon: _propTypes.default.node, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object]), /** * @ignore */ type: _propTypes.default.oneOfType([_propTypes.default.oneOf(['button', 'reset', 'submit']), _propTypes.default.string]), /** * The variant to use. * @default 'text' */ variant: _propTypes.default /* @typescript-to-proptypes-ignore */.oneOfType([_propTypes.default.oneOf(['contained', 'outlined', 'text']), _propTypes.default.string]) } : void 0; var _default = exports.default = Button;