From 63b246b25f6af8ed9f26a4ac9c17fceaa53d968b Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 10:16:29 +0100 Subject: [PATCH 01/18] copy files to material next --- .../src/ButtonGroup/ButtonGroup.d.ts | 108 +++++ .../src/ButtonGroup/ButtonGroup.js | 393 ++++++++++++++++++ .../src/ButtonGroup/ButtonGroup.test.js | 254 +++++++++++ .../ButtonGroup/ButtonGroupButtonContext.ts | 16 + .../src/ButtonGroup/ButtonGroupContext.ts | 25 ++ .../src/ButtonGroup/buttonGroupClasses.ts | 103 +++++ .../src/ButtonGroup/index.d.ts | 4 + .../src/ButtonGroup/index.js | 4 + 8 files changed, 907 insertions(+) create mode 100644 packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts create mode 100644 packages/mui-material-next/src/ButtonGroup/ButtonGroup.js create mode 100644 packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js create mode 100644 packages/mui-material-next/src/ButtonGroup/ButtonGroupButtonContext.ts create mode 100644 packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts create mode 100644 packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts create mode 100644 packages/mui-material-next/src/ButtonGroup/index.d.ts create mode 100644 packages/mui-material-next/src/ButtonGroup/index.js diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts new file mode 100644 index 00000000000000..77cc7f128db348 --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts @@ -0,0 +1,108 @@ +import * as React from 'react'; +import { SxProps } from '@mui/system'; +import { OverridableStringUnion } from '@mui/types'; +import { OverridableComponent, OverrideProps } from '../OverridableComponent'; +import { Theme } from '..'; +import { ButtonGroupClasses } from './buttonGroupClasses'; + +export interface ButtonGroupPropsColorOverrides {} +export interface ButtonGroupPropsVariantOverrides {} +export interface ButtonGroupPropsSizeOverrides {} + +export interface ButtonGroupOwnProps { + /** + * The content of the component. + */ + children?: React.ReactNode; + /** + * Override or extend the styles applied to the component. + */ + classes?: Partial; + /** + * 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?: OverridableStringUnion< + 'inherit' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning', + ButtonGroupPropsColorOverrides + >; + /** + * If `true`, the component is disabled. + * @default false + */ + disabled?: boolean; + /** + * If `true`, no elevation is used. + * @default false + */ + disableElevation?: boolean; + /** + * If `true`, the button keyboard focus ripple is disabled. + * @default false + */ + disableFocusRipple?: boolean; + /** + * If `true`, the button ripple effect is disabled. + * @default false + */ + disableRipple?: boolean; + /** + * If `true`, the buttons will take up the full width of its container. + * @default false + */ + fullWidth?: boolean; + /** + * The component orientation (layout flow direction). + * @default 'horizontal' + */ + orientation?: 'vertical' | 'horizontal'; + /** + * The size of the component. + * `small` is equivalent to the dense button styling. + * @default 'medium' + */ + size?: OverridableStringUnion<'small' | 'medium' | 'large', ButtonGroupPropsSizeOverrides>; + /** + * The variant to use. + * @default 'outlined' + */ + variant?: OverridableStringUnion< + 'text' | 'outlined' | 'contained', + ButtonGroupPropsVariantOverrides + >; + /** + * The system prop that allows defining system overrides as well as additional CSS styles. + */ + sx?: SxProps; +} + +export interface ButtonGroupTypeMap< + AdditionalProps = {}, + RootComponent extends React.ElementType = 'div', +> { + props: AdditionalProps & ButtonGroupOwnProps; + defaultComponent: RootComponent; +} + +/** + * + * Demos: + * + * - [Button Group](https://mui.com/material-ui/react-button-group/) + * + * API: + * + * - [ButtonGroup API](https://mui.com/material-ui/api/button-group/) + */ +declare const ButtonGroup: OverridableComponent; + +export type ButtonGroupProps< + RootComponent extends React.ElementType = ButtonGroupTypeMap['defaultComponent'], + AdditionalProps = {}, +> = OverrideProps, RootComponent> & { + component?: React.ElementType; +}; + +export default ButtonGroup; diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js new file mode 100644 index 00000000000000..697ed7e2590f2e --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js @@ -0,0 +1,393 @@ +'use client'; +import * as React from 'react'; +import PropTypes from 'prop-types'; +import clsx from 'clsx'; +import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses'; +import { alpha } from '@mui/system'; +import { getValidReactChildren } from '@mui/utils'; +import capitalize from '../utils/capitalize'; +import styled from '../styles/styled'; +import useThemeProps from '../styles/useThemeProps'; +import buttonGroupClasses, { getButtonGroupUtilityClass } from './buttonGroupClasses'; +import ButtonGroupContext from './ButtonGroupContext'; +import ButtonGroupButtonContext from './ButtonGroupButtonContext'; + +const overridesResolver = (props, styles) => { + const { ownerState } = props; + + return [ + { [`& .${buttonGroupClasses.grouped}`]: styles.grouped }, + { + [`& .${buttonGroupClasses.grouped}`]: styles[`grouped${capitalize(ownerState.orientation)}`], + }, + { [`& .${buttonGroupClasses.grouped}`]: styles[`grouped${capitalize(ownerState.variant)}`] }, + { + [`& .${buttonGroupClasses.grouped}`]: + styles[`grouped${capitalize(ownerState.variant)}${capitalize(ownerState.orientation)}`], + }, + { + [`& .${buttonGroupClasses.grouped}`]: + styles[`grouped${capitalize(ownerState.variant)}${capitalize(ownerState.color)}`], + }, + { + [`& .${buttonGroupClasses.firstButton}`]: styles.firstButton, + }, + { + [`& .${buttonGroupClasses.lastButton}`]: styles.lastButton, + }, + { + [`& .${buttonGroupClasses.middleButton}`]: styles.middleButton, + }, + styles.root, + styles[ownerState.variant], + ownerState.disableElevation === true && styles.disableElevation, + ownerState.fullWidth && styles.fullWidth, + ownerState.orientation === 'vertical' && styles.vertical, + ]; +}; + +const useUtilityClasses = (ownerState) => { + const { classes, color, disabled, disableElevation, fullWidth, orientation, variant } = + ownerState; + + const slots = { + root: [ + 'root', + variant, + orientation === 'vertical' && 'vertical', + fullWidth && 'fullWidth', + disableElevation && 'disableElevation', + ], + grouped: [ + 'grouped', + `grouped${capitalize(orientation)}`, + `grouped${capitalize(variant)}`, + `grouped${capitalize(variant)}${capitalize(orientation)}`, + `grouped${capitalize(variant)}${capitalize(color)}`, + disabled && 'disabled', + ], + firstButton: ['firstButton'], + lastButton: ['lastButton'], + middleButton: ['middleButton'], + }; + + return composeClasses(slots, getButtonGroupUtilityClass, classes); +}; + +const ButtonGroupRoot = styled('div', { + name: 'MuiButtonGroup', + slot: 'Root', + overridesResolver, +})(({ theme, ownerState }) => ({ + display: 'inline-flex', + borderRadius: (theme.vars || theme).shape.borderRadius, + ...(ownerState.variant === 'contained' && { + boxShadow: (theme.vars || theme).shadows[2], + }), + ...(ownerState.disableElevation && { + boxShadow: 'none', + }), + ...(ownerState.fullWidth && { + width: '100%', + }), + ...(ownerState.orientation === 'vertical' && { + flexDirection: 'column', + }), + [`& .${buttonGroupClasses.grouped}`]: { + minWidth: 40, + '&:hover': { + ...(ownerState.variant === 'contained' && { + boxShadow: 'none', + }), + }, + ...(ownerState.variant === 'contained' && { + boxShadow: 'none', + }), + }, + [`& .${buttonGroupClasses.firstButton},& .${buttonGroupClasses.middleButton}`]: { + ...(ownerState.orientation === 'horizontal' && { + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + }), + ...(ownerState.orientation === 'vertical' && { + borderBottomRightRadius: 0, + borderBottomLeftRadius: 0, + }), + ...(ownerState.variant === 'text' && + ownerState.orientation === 'horizontal' && { + borderRight: theme.vars + ? `1px solid rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.23)` + : `1px solid ${ + theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)' + }`, + [`&.${buttonGroupClasses.disabled}`]: { + borderRight: `1px solid ${(theme.vars || theme).palette.action.disabled}`, + }, + }), + ...(ownerState.variant === 'text' && + ownerState.orientation === 'vertical' && { + borderBottom: theme.vars + ? `1px solid rgba(${theme.vars.palette.common.onBackgroundChannel} / 0.23)` + : `1px solid ${ + theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)' + }`, + [`&.${buttonGroupClasses.disabled}`]: { + borderBottom: `1px solid ${(theme.vars || theme).palette.action.disabled}`, + }, + }), + ...(ownerState.variant === 'text' && + ownerState.color !== 'inherit' && { + borderColor: theme.vars + ? `rgba(${theme.vars.palette[ownerState.color].mainChannel} / 0.5)` + : alpha(theme.palette[ownerState.color].main, 0.5), + }), + ...(ownerState.variant === 'outlined' && + ownerState.orientation === 'horizontal' && { + borderRightColor: 'transparent', + }), + ...(ownerState.variant === 'outlined' && + ownerState.orientation === 'vertical' && { + borderBottomColor: 'transparent', + }), + ...(ownerState.variant === 'contained' && + ownerState.orientation === 'horizontal' && { + borderRight: `1px solid ${(theme.vars || theme).palette.grey[400]}`, + [`&.${buttonGroupClasses.disabled}`]: { + borderRight: `1px solid ${(theme.vars || theme).palette.action.disabled}`, + }, + }), + ...(ownerState.variant === 'contained' && + ownerState.orientation === 'vertical' && { + borderBottom: `1px solid ${(theme.vars || theme).palette.grey[400]}`, + [`&.${buttonGroupClasses.disabled}`]: { + borderBottom: `1px solid ${(theme.vars || theme).palette.action.disabled}`, + }, + }), + ...(ownerState.variant === 'contained' && + ownerState.color !== 'inherit' && { + borderColor: (theme.vars || theme).palette[ownerState.color].dark, + }), + '&:hover': { + ...(ownerState.variant === 'outlined' && + ownerState.orientation === 'horizontal' && { + borderRightColor: 'currentColor', + }), + ...(ownerState.variant === 'outlined' && + ownerState.orientation === 'vertical' && { + borderBottomColor: 'currentColor', + }), + }, + }, + [`& .${buttonGroupClasses.lastButton},& .${buttonGroupClasses.middleButton}`]: { + ...(ownerState.orientation === 'horizontal' && { + borderTopLeftRadius: 0, + borderBottomLeftRadius: 0, + }), + ...(ownerState.orientation === 'vertical' && { + borderTopRightRadius: 0, + borderTopLeftRadius: 0, + }), + ...(ownerState.variant === 'outlined' && + ownerState.orientation === 'horizontal' && { + marginLeft: -1, + }), + ...(ownerState.variant === 'outlined' && + ownerState.orientation === 'vertical' && { + marginTop: -1, + }), + }, +})); + +const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) { + const props = useThemeProps({ props: inProps, name: 'MuiButtonGroup' }); + const { + children, + className, + color = 'primary', + component = 'div', + disabled = false, + disableElevation = false, + disableFocusRipple = false, + disableRipple = false, + fullWidth = false, + orientation = 'horizontal', + size = 'medium', + variant = 'outlined', + ...other + } = props; + + const ownerState = { + ...props, + color, + component, + disabled, + disableElevation, + disableFocusRipple, + disableRipple, + fullWidth, + orientation, + size, + variant, + }; + + const classes = useUtilityClasses(ownerState); + + const context = React.useMemo( + () => ({ + className: classes.grouped, + color, + disabled, + disableElevation, + disableFocusRipple, + disableRipple, + fullWidth, + size, + variant, + }), + [ + color, + disabled, + disableElevation, + disableFocusRipple, + disableRipple, + fullWidth, + size, + variant, + classes.grouped, + ], + ); + + const validChildren = getValidReactChildren(children); + const childrenCount = validChildren.length; + + const getButtonPositionClassName = (index) => { + const isFirstButton = index === 0; + const isLastButton = index === childrenCount - 1; + + if (isFirstButton && isLastButton) { + return ''; + } + if (isFirstButton) { + return classes.firstButton; + } + if (isLastButton) { + return classes.lastButton; + } + return classes.middleButton; + }; + + return ( + + + {validChildren.map((child, index) => { + return ( + + {child} + + ); + })} + + + ); +}); + +ButtonGroup.propTypes /* remove-proptypes */ = { + // ----------------------------- Warning -------------------------------- + // | These PropTypes are generated from the TypeScript type definitions | + // | To update them edit the d.ts file and run "yarn proptypes" | + // ---------------------------------------------------------------------- + /** + * The content of the component. + */ + children: PropTypes.node, + /** + * Override or extend the styles applied to the component. + */ + classes: PropTypes.object, + /** + * @ignore + */ + className: PropTypes.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 /* @typescript-to-proptypes-ignore */.oneOfType([ + PropTypes.oneOf(['inherit', 'primary', 'secondary', 'error', 'info', '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, + /** + * If `true`, the component is disabled. + * @default false + */ + disabled: PropTypes.bool, + /** + * If `true`, no elevation is used. + * @default false + */ + disableElevation: PropTypes.bool, + /** + * If `true`, the button keyboard focus ripple is disabled. + * @default false + */ + disableFocusRipple: PropTypes.bool, + /** + * If `true`, the button ripple effect is disabled. + * @default false + */ + disableRipple: PropTypes.bool, + /** + * If `true`, the buttons will take up the full width of its container. + * @default false + */ + fullWidth: PropTypes.bool, + /** + * The component orientation (layout flow direction). + * @default 'horizontal' + */ + orientation: PropTypes.oneOf(['horizontal', 'vertical']), + /** + * The size of the component. + * `small` is equivalent to the dense button styling. + * @default 'medium' + */ + size: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([ + PropTypes.oneOf(['small', 'medium', 'large']), + PropTypes.string, + ]), + /** + * 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 variant to use. + * @default 'outlined' + */ + variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([ + PropTypes.oneOf(['contained', 'outlined', 'text']), + PropTypes.string, + ]), +}; + +export default ButtonGroup; diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js new file mode 100644 index 00000000000000..1e30bcdad74ff5 --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -0,0 +1,254 @@ +import * as React from 'react'; +import { expect } from 'chai'; +import { createRenderer, describeConformance, screen } from '@mui-internal/test-utils'; +import ButtonGroup, { buttonGroupClasses as classes } from '@mui/material/ButtonGroup'; +import { ThemeProvider, createTheme } from '@mui/material/styles'; +import Button, { buttonClasses } from '@mui/material/Button'; +import ButtonGroupContext from './ButtonGroupContext'; + +describe('', () => { + const { render } = createRenderer(); + + describeConformance( + + + , + () => ({ + classes, + inheritComponent: 'div', + render, + refInstanceof: window.HTMLDivElement, + testComponentPropWith: 'span', + muiName: 'MuiButtonGroup', + testVariantProps: { variant: 'contained' }, + skip: ['componentsProp'], + }), + ); + + it('should render with the root class but no others', () => { + const { container } = render( + + + , + ); + const buttonGroup = container.firstChild; + expect(buttonGroup).to.have.class(classes.root); + expect(buttonGroup).not.to.have.class(classes.contained); + expect(buttonGroup).not.to.have.class(classes.fullWidth); + }); + + it('should render an outlined button', () => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + expect(button).to.have.class('MuiButton-outlined'); + expect(button).to.have.class(classes.grouped); + expect(button).to.have.class(classes.groupedOutlined); + expect(button).to.have.class(classes.groupedOutlinedPrimary); + expect(button).not.to.have.class(classes.groupedOutlinedSecondary); + }); + + it('can render an outlined primary button', () => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + expect(button).to.have.class('MuiButton-outlinedPrimary'); + expect(button).to.have.class(classes.grouped); + expect(button).to.have.class(classes.groupedOutlined); + expect(button).to.have.class(classes.groupedOutlinedPrimary); + expect(button).not.to.have.class(classes.groupedOutlinedSecondary); + }); + + it('can render a contained button', () => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + expect(button).to.have.class('MuiButton-contained'); + expect(button).to.have.class(classes.grouped); + expect(button).to.have.class(classes.groupedContained); + expect(button).to.have.class(classes.groupedContainedPrimary); + expect(button).not.to.have.class(classes.groupedContainedSecondary); + }); + + it('can render a small button', () => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + expect(button).to.have.class('MuiButton-outlinedSizeSmall'); + }); + + it('can render a large button', () => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + expect(button).to.have.class('MuiButton-outlinedSizeLarge'); + }); + + it('should have a ripple by default', () => { + const { container } = render( + + + , + ); + expect(container.querySelector('.touchRipple')).not.to.equal(null); + }); + + it('can disable the elevation', () => { + const { getByRole } = render( + + + , + ); + const button = getByRole('button'); + expect(button).to.have.class('MuiButton-disableElevation'); + }); + + it('can disable the ripple', () => { + const { container } = render( + + + , + ); + expect(container.querySelector('.touchRipple')).to.equal(null); + }); + + it('should not be fullWidth by default', () => { + const { container, getByRole } = render( + + + , + ); + const button = getByRole('button'); + const buttonGroup = container.firstChild; + expect(buttonGroup).not.to.have.class(classes.fullWidth); + expect(button).not.to.have.class(buttonClasses.fullWidth); + }); + + it('can pass fullWidth to Button', () => { + const { container, getByRole } = render( + + + , + ); + const buttonGroup = container.firstChild; + const button = getByRole('button'); + expect(buttonGroup).to.have.class(classes.fullWidth); + expect(button).to.have.class(buttonClasses.fullWidth); + }); + + it('classes.grouped should be merged with Button className', () => { + render( + + + , + ); + expect(screen.getByRole('button')).to.have.class(classes.grouped); + expect(screen.getByRole('button')).to.have.class('foo-bar'); + }); + + it('should forward the context to children', () => { + let context; + render( + + + {(value) => { + context = value; + }} + + , + ); + expect(context.variant).to.equal('contained'); + expect(context.size).to.equal('large'); + expect(context.fullWidth).to.equal(false); + expect(context.disableRipple).to.equal(false); + expect(context.disableFocusRipple).to.equal(false); + expect(context.disableElevation).to.equal(false); + expect(context.disabled).to.equal(false); + expect(context.color).to.equal('primary'); + }); + + describe('theme default props on Button', () => { + it('should override default variant prop', () => { + render( + + + + + , + ); + + expect(screen.getByRole('button')).to.have.class(buttonClasses.outlined); + expect(screen.getByRole('button')).to.have.class(buttonClasses.sizeSmall); + expect(screen.getByRole('button')).to.have.class(buttonClasses.outlinedSecondary); + }); + }); + + describe('position classes', () => { + it('correctly applies position classes to buttons', () => { + render( + + + + + , + ); + + const firstButton = screen.getAllByRole('button')[0]; + const middleButton = screen.getAllByRole('button')[1]; + const lastButton = screen.getAllByRole('button')[2]; + + expect(firstButton).to.have.class(classes.firstButton); + expect(firstButton).not.to.have.class(classes.middleButton); + expect(firstButton).not.to.have.class(classes.lastButton); + + expect(middleButton).to.have.class(classes.middleButton); + expect(middleButton).not.to.have.class(classes.firstButton); + expect(middleButton).not.to.have.class(classes.lastButton); + + expect(lastButton).to.have.class(classes.lastButton); + expect(lastButton).not.to.have.class(classes.middleButton); + expect(lastButton).not.to.have.class(classes.firstButton); + }); + + it('does not apply any position classes to a single button', () => { + render( + + + , + ); + + const button = screen.getByRole('button'); + + expect(button).not.to.have.class(classes.firstButton); + expect(button).not.to.have.class(classes.middleButton); + expect(button).not.to.have.class(classes.lastButton); + }); + }); +}); diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroupButtonContext.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroupButtonContext.ts new file mode 100644 index 00000000000000..8a93fe171954ef --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroupButtonContext.ts @@ -0,0 +1,16 @@ +import * as React from 'react'; + +type ButtonPositionClassName = string; + +/** + * @ignore - internal component. + */ +const ButtonGroupButtonContext = React.createContext( + undefined, +); + +if (process.env.NODE_ENV !== 'production') { + ButtonGroupButtonContext.displayName = 'ButtonGroupButtonContext'; +} + +export default ButtonGroupButtonContext; diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts new file mode 100644 index 00000000000000..63352996156cc5 --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts @@ -0,0 +1,25 @@ +import * as React from 'react'; +import type { ButtonGroupProps } from './ButtonGroup'; + +interface IButtonGroupContext { + className?: string; + color?: ButtonGroupProps['color']; + disabled?: boolean; + disableElevation?: boolean; + disableFocusRipple?: boolean; + disableRipple?: boolean; + fullWidth?: boolean; + size?: ButtonGroupProps['size']; + variant?: ButtonGroupProps['variant']; +} + +/** + * @ignore - internal component. + */ +const ButtonGroupContext = React.createContext({}); + +if (process.env.NODE_ENV !== 'production') { + ButtonGroupContext.displayName = 'ButtonGroupContext'; +} + +export default ButtonGroupContext; diff --git a/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts b/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts new file mode 100644 index 00000000000000..433083e3ae20f9 --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts @@ -0,0 +1,103 @@ +import { unstable_generateUtilityClasses as generateUtilityClasses } from '@mui/utils'; +import generateUtilityClass from '../generateUtilityClass'; + +export interface ButtonGroupClasses { + /** Styles applied to the root element. */ + root: string; + /** Styles applied to the root element if `variant="contained"`. */ + contained: string; + /** Styles applied to the root element if `variant="outlined"`. */ + outlined: string; + /** Styles applied to the root element if `variant="text"`. */ + text: string; + /** Styles applied to the root element if `disableElevation={true}`. */ + disableElevation: string; + /** State class applied to the child elements if `disabled={true}`. */ + disabled: string; + /** Styles applied to the first button in the button group. */ + firstButton: string; + /** Styles applied to the root element if `fullWidth={true}`. */ + fullWidth: string; + /** Styles applied to the root element if `orientation="vertical"`. */ + vertical: string; + /** Styles applied to the children. */ + grouped: string; + /** Styles applied to the children if `orientation="horizontal"`. */ + groupedHorizontal: string; + /** Styles applied to the children if `orientation="vertical"`. */ + groupedVertical: string; + /** Styles applied to the children if `variant="text"`. */ + groupedText: string; + /** Styles applied to the children if `variant="text"` and `orientation="horizontal"`. */ + groupedTextHorizontal: string; + /** Styles applied to the children if `variant="text"` and `orientation="vertical"`. */ + groupedTextVertical: string; + /** Styles applied to the children if `variant="text"` and `color="primary"`. */ + groupedTextPrimary: string; + /** Styles applied to the children if `variant="text"` and `color="secondary"`. */ + groupedTextSecondary: string; + /** Styles applied to the children if `variant="outlined"`. */ + groupedOutlined: string; + /** Styles applied to the children if `variant="outlined"` and `orientation="horizontal"`. */ + groupedOutlinedHorizontal: string; + /** Styles applied to the children if `variant="outlined"` and `orientation="vertical"`. */ + groupedOutlinedVertical: string; + /** Styles applied to the children if `variant="outlined"` and `color="primary"`. */ + groupedOutlinedPrimary: string; + /** Styles applied to the children if `variant="outlined"` and `color="secondary"`. */ + groupedOutlinedSecondary: string; + /** Styles applied to the children if `variant="contained"`. */ + groupedContained: string; + /** Styles applied to the children if `variant="contained"` and `orientation="horizontal"`. */ + groupedContainedHorizontal: string; + /** Styles applied to the children if `variant="contained"` and `orientation="vertical"`. */ + groupedContainedVertical: string; + /** Styles applied to the children if `variant="contained"` and `color="primary"`. */ + groupedContainedPrimary: string; + /** Styles applied to the children if `variant="contained"` and `color="secondary"`. */ + groupedContainedSecondary: string; + /** Styles applied to the last button in the button group. */ + lastButton: string; + /** Styles applied to buttons in the middle of the button group. */ + middleButton: string; +} + +export type ButtonGroupClassKey = keyof ButtonGroupClasses; + +export function getButtonGroupUtilityClass(slot: string): string { + return generateUtilityClass('MuiButtonGroup', slot); +} + +const buttonGroupClasses: ButtonGroupClasses = generateUtilityClasses('MuiButtonGroup', [ + 'root', + 'contained', + 'outlined', + 'text', + 'disableElevation', + 'disabled', + 'firstButton', + 'fullWidth', + 'vertical', + 'grouped', + 'groupedHorizontal', + 'groupedVertical', + 'groupedText', + 'groupedTextHorizontal', + 'groupedTextVertical', + 'groupedTextPrimary', + 'groupedTextSecondary', + 'groupedOutlined', + 'groupedOutlinedHorizontal', + 'groupedOutlinedVertical', + 'groupedOutlinedPrimary', + 'groupedOutlinedSecondary', + 'groupedContained', + 'groupedContainedHorizontal', + 'groupedContainedVertical', + 'groupedContainedPrimary', + 'groupedContainedSecondary', + 'lastButton', + 'middleButton', +]); + +export default buttonGroupClasses; diff --git a/packages/mui-material-next/src/ButtonGroup/index.d.ts b/packages/mui-material-next/src/ButtonGroup/index.d.ts new file mode 100644 index 00000000000000..cb8b2e7907c4b4 --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/index.d.ts @@ -0,0 +1,4 @@ +export { default } from './ButtonGroup'; +export * from './ButtonGroup'; +export { default as buttonGroupClasses } from './buttonGroupClasses'; +export * from './buttonGroupClasses'; diff --git a/packages/mui-material-next/src/ButtonGroup/index.js b/packages/mui-material-next/src/ButtonGroup/index.js new file mode 100644 index 00000000000000..3a585146bc9596 --- /dev/null +++ b/packages/mui-material-next/src/ButtonGroup/index.js @@ -0,0 +1,4 @@ +'use client'; +export { default } from './ButtonGroup'; +export { default as buttonGroupClasses } from './buttonGroupClasses'; +export * from './buttonGroupClasses'; From c770c833ebb73bfe401a77b7b2069e32a4586730 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 11:57:49 +0100 Subject: [PATCH 02/18] fix capitalize import in button group --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js index 697ed7e2590f2e..ae3a6e7ba27e83 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js @@ -4,8 +4,7 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses'; import { alpha } from '@mui/system'; -import { getValidReactChildren } from '@mui/utils'; -import capitalize from '../utils/capitalize'; +import { getValidReactChildren, unstable_capitalize as capitalize } from '@mui/utils'; import styled from '../styles/styled'; import useThemeProps from '../styles/useThemeProps'; import buttonGroupClasses, { getButtonGroupUtilityClass } from './buttonGroupClasses'; From ccfd5522775dbc844db42b9b05a1c654fc447275 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 12:00:21 +0100 Subject: [PATCH 03/18] fix generateUltilityClass import --- .../mui-material-next/src/ButtonGroup/buttonGroupClasses.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts b/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts index 433083e3ae20f9..c824685b07fa57 100644 --- a/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts +++ b/packages/mui-material-next/src/ButtonGroup/buttonGroupClasses.ts @@ -1,5 +1,7 @@ -import { unstable_generateUtilityClasses as generateUtilityClasses } from '@mui/utils'; -import generateUtilityClass from '../generateUtilityClass'; +import { + unstable_generateUtilityClass as generateUtilityClass, + unstable_generateUtilityClasses as generateUtilityClasses, +} from '@mui/utils'; export interface ButtonGroupClasses { /** Styles applied to the root element. */ From e5bf43dd56ae2e51e61f402c95ea32648fa85ddd Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 12:03:08 +0100 Subject: [PATCH 04/18] fix ButtonGroup.d.ts OverridableComponent import --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts index 77cc7f128db348..c14eb89814720e 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts @@ -1,7 +1,6 @@ import * as React from 'react'; import { SxProps } from '@mui/system'; -import { OverridableStringUnion } from '@mui/types'; -import { OverridableComponent, OverrideProps } from '../OverridableComponent'; +import { OverridableComponent, OverridableStringUnion, OverrideProps } from '@mui/types'; import { Theme } from '..'; import { ButtonGroupClasses } from './buttonGroupClasses'; From b6e20858528ba993977cbeb8fa69269ad092b44d Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 12:44:20 +0100 Subject: [PATCH 05/18] fix Theme import in ButtonGroup.d.ts --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts index c14eb89814720e..b8300a2105057a 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import { SxProps } from '@mui/system'; import { OverridableComponent, OverridableStringUnion, OverrideProps } from '@mui/types'; -import { Theme } from '..'; +import { Theme } from '../styles'; import { ButtonGroupClasses } from './buttonGroupClasses'; export interface ButtonGroupPropsColorOverrides {} From 21dd8e81dc984e4173a52ef14a9f553da78c6ca2 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 13:43:59 +0100 Subject: [PATCH 06/18] [material-next][Button] add ButtonGroup logic --- packages/mui-material-next/src/Button/Button.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/mui-material-next/src/Button/Button.tsx b/packages/mui-material-next/src/Button/Button.tsx index d44b739fa40cde..7bf0426db78d00 100644 --- a/packages/mui-material-next/src/Button/Button.tsx +++ b/packages/mui-material-next/src/Button/Button.tsx @@ -1,7 +1,11 @@ 'use client'; import * as React from 'react'; import PropTypes from 'prop-types'; -import { unstable_capitalize as capitalize } from '@mui/utils'; +import clsx from 'clsx'; +import { + unstable_capitalize as capitalize, + internal_resolveProps as resolveProps, +} from '@mui/utils'; import { useSlotProps } from '@mui/base/utils'; import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses'; import { useThemeProps, alpha, shouldForwardProp } from '@mui/system'; @@ -10,6 +14,8 @@ import { getButtonUtilityClass } from './buttonClasses'; import buttonBaseClasses from '../ButtonBase/buttonBaseClasses'; import { ButtonProps, ExtendButton, ButtonTypeMap, ButtonOwnerState } from './Button.types'; import ButtonBase from '../ButtonBase'; +import ButtonGroupButtonContext from '../ButtonGroup/ButtonGroupButtonContext'; +import ButtonGroupContext from '../ButtonGroup/ButtonGroupContext'; const useUtilityClasses = (ownerState: ButtonOwnerState) => { const { classes, color, disableElevation, fullWidth, size, variant } = ownerState; @@ -366,7 +372,10 @@ const ButtonEndIcon = styled('span', { const Button = React.forwardRef(function Button< BaseComponentType extends React.ElementType = ButtonTypeMap['defaultComponent'], >(inProps: ButtonProps, ref: React.ForwardedRef) { - const props = useThemeProps({ props: inProps, name: 'MuiButton' }); + const contextProps = React.useContext(ButtonGroupContext); + const buttonGroupButtonContextPositionClassName = React.useContext(ButtonGroupButtonContext); + const resolvedProps = resolveProps(contextProps as ButtonProps, inProps); + const props = useThemeProps({ props: resolvedProps, name: 'MuiButton' }); const { children, classes: classesProp, @@ -392,6 +401,8 @@ const Button = React.forwardRef(function Button< const classes = useUtilityClasses(ownerState); + const postionClassName = buttonGroupButtonContextPositionClassName ?? ''; + const rootProps = useSlotProps({ elementType: ButtonRoot, externalForwardedProps: other, @@ -401,6 +412,7 @@ const Button = React.forwardRef(function Button< ref, }, ownerState, + className: clsx(contextProps.className, postionClassName), }); const startIcon = startIconProp && ( From 42d3272cbae3f7a0a8e48c2f0213edcc491fb7cf Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 14:35:36 +0100 Subject: [PATCH 07/18] fix imports in .test file --- .../mui-material-next/src/ButtonGroup/ButtonGroup.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index 1e30bcdad74ff5..0ce5e304598ac2 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -1,9 +1,9 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer, describeConformance, screen } from '@mui-internal/test-utils'; -import ButtonGroup, { buttonGroupClasses as classes } from '@mui/material/ButtonGroup'; -import { ThemeProvider, createTheme } from '@mui/material/styles'; -import Button, { buttonClasses } from '@mui/material/Button'; +import ButtonGroup, { buttonGroupClasses as classes } from '@mui/material-next/ButtonGroup'; +import { ThemeProvider, createTheme } from '@mui/material-next/styles'; +import Button, { buttonClasses } from '@mui/material-next/Button'; import ButtonGroupContext from './ButtonGroupContext'; describe('', () => { From 801c6b694de43c3fdfec6c599b82713b1c36d889 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 14:50:04 +0100 Subject: [PATCH 08/18] change disableFocusRipple to disableTouchRipple --- .../src/ButtonGroup/ButtonGroup.d.ts | 8 ++++---- .../src/ButtonGroup/ButtonGroup.js | 16 ++++++++-------- .../src/ButtonGroup/ButtonGroup.test.js | 2 +- .../src/ButtonGroup/ButtonGroupContext.ts | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts index b8300a2105057a..2215539bb411c6 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.d.ts @@ -38,15 +38,15 @@ export interface ButtonGroupOwnProps { */ disableElevation?: boolean; /** - * If `true`, the button keyboard focus ripple is disabled. + * If `true`, the button ripple effect is disabled. * @default false */ - disableFocusRipple?: boolean; + disableRipple?: boolean; /** - * If `true`, the button ripple effect is disabled. + * If `true`, the touch ripple effect is disabled. * @default false */ - disableRipple?: boolean; + disableTouchRipple?: boolean; /** * If `true`, the buttons will take up the full width of its container. * @default false diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js index ae3a6e7ba27e83..b22bd12819c49a 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.js @@ -206,7 +206,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) { component = 'div', disabled = false, disableElevation = false, - disableFocusRipple = false, + disableTouchRipple = false, disableRipple = false, fullWidth = false, orientation = 'horizontal', @@ -221,7 +221,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) { component, disabled, disableElevation, - disableFocusRipple, + disableTouchRipple, disableRipple, fullWidth, orientation, @@ -237,7 +237,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) { color, disabled, disableElevation, - disableFocusRipple, + disableTouchRipple, disableRipple, fullWidth, size, @@ -247,7 +247,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(inProps, ref) { color, disabled, disableElevation, - disableFocusRipple, + disableTouchRipple, disableRipple, fullWidth, size, @@ -343,15 +343,15 @@ ButtonGroup.propTypes /* remove-proptypes */ = { */ disableElevation: PropTypes.bool, /** - * If `true`, the button keyboard focus ripple is disabled. + * If `true`, the button ripple effect is disabled. * @default false */ - disableFocusRipple: PropTypes.bool, + disableRipple: PropTypes.bool, /** - * If `true`, the button ripple effect is disabled. + * If `true`, the touch ripple effect is disabled. * @default false */ - disableRipple: PropTypes.bool, + disableTouchRipple: PropTypes.bool, /** * If `true`, the buttons will take up the full width of its container. * @default false diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index 0ce5e304598ac2..7d468599fe614c 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -176,7 +176,7 @@ describe('', () => { expect(context.size).to.equal('large'); expect(context.fullWidth).to.equal(false); expect(context.disableRipple).to.equal(false); - expect(context.disableFocusRipple).to.equal(false); + expect(context.disableTouchRipple).to.equal(false); expect(context.disableElevation).to.equal(false); expect(context.disabled).to.equal(false); expect(context.color).to.equal('primary'); diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts index 63352996156cc5..23b6cfd323940f 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts @@ -6,7 +6,7 @@ interface IButtonGroupContext { color?: ButtonGroupProps['color']; disabled?: boolean; disableElevation?: boolean; - disableFocusRipple?: boolean; + disableTouchRipple?: boolean; disableRipple?: boolean; fullWidth?: boolean; size?: ButtonGroupProps['size']; From 78231e71b0b5c6cc14263f8f998ec76b9cfc052e Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 15:02:46 +0100 Subject: [PATCH 09/18] fix CssVarsProvider and extendTheme in .test --- .../src/ButtonGroup/ButtonGroup.test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index 7d468599fe614c..b3149adea43a52 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -2,7 +2,7 @@ import * as React from 'react'; import { expect } from 'chai'; import { createRenderer, describeConformance, screen } from '@mui-internal/test-utils'; import ButtonGroup, { buttonGroupClasses as classes } from '@mui/material-next/ButtonGroup'; -import { ThemeProvider, createTheme } from '@mui/material-next/styles'; +import { CssVarsProvider, extendTheme } from '@mui/material-next/styles'; import Button, { buttonClasses } from '@mui/material-next/Button'; import ButtonGroupContext from './ButtonGroupContext'; @@ -22,6 +22,8 @@ describe('', () => { muiName: 'MuiButtonGroup', testVariantProps: { variant: 'contained' }, skip: ['componentsProp'], + ThemeProvider: CssVarsProvider, + createTheme: extendTheme }), ); @@ -185,8 +187,8 @@ describe('', () => { describe('theme default props on Button', () => { it('should override default variant prop', () => { render( - ', () => { - , + , ); expect(screen.getByRole('button')).to.have.class(buttonClasses.outlined); From 69a38298d56543c54c1b7b1cbe46188aa5ec05b4 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 15:08:56 +0100 Subject: [PATCH 10/18] prettify .test file --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index b3149adea43a52..c2bf9cd6d84818 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -23,7 +23,7 @@ describe('', () => { testVariantProps: { variant: 'contained' }, skip: ['componentsProp'], ThemeProvider: CssVarsProvider, - createTheme: extendTheme + createTheme: extendTheme, }), ); From f9118e9ecabd024d8a760b7f05130b8bbe013e20 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 15:19:02 +0100 Subject: [PATCH 11/18] fix button colorClass in .test file --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index c2bf9cd6d84818..94fb70f7d9c1a9 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -208,7 +208,7 @@ describe('', () => { expect(screen.getByRole('button')).to.have.class(buttonClasses.outlined); expect(screen.getByRole('button')).to.have.class(buttonClasses.sizeSmall); - expect(screen.getByRole('button')).to.have.class(buttonClasses.outlinedSecondary); + expect(screen.getByRole('button')).to.have.class(buttonClasses.colorSecondary); }); }); From 222bcca593f5e6ed282f2f55d031e930d42eaadc Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 15:31:43 +0100 Subject: [PATCH 12/18] change hard typed classNames to classes in .test --- .../src/ButtonGroup/ButtonGroup.test.js | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index 94fb70f7d9c1a9..bccd622f72b02b 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -46,7 +46,7 @@ describe('', () => { , ); const button = getByRole('button'); - expect(button).to.have.class('MuiButton-outlined'); + expect(button).to.have.class(buttonClasses.outlined); expect(button).to.have.class(classes.grouped); expect(button).to.have.class(classes.groupedOutlined); expect(button).to.have.class(classes.groupedOutlinedPrimary); @@ -60,25 +60,26 @@ describe('', () => { , ); const button = getByRole('button'); - expect(button).to.have.class('MuiButton-outlinedPrimary'); + expect(button).to.have.class(buttonClasses.outlined); + expect(button).to.have.class(buttonClasses.colorPrimary); expect(button).to.have.class(classes.grouped); expect(button).to.have.class(classes.groupedOutlined); expect(button).to.have.class(classes.groupedOutlinedPrimary); expect(button).not.to.have.class(classes.groupedOutlinedSecondary); }); - it('can render a contained button', () => { + it('can render a text button', () => { const { getByRole } = render( , ); const button = getByRole('button'); - expect(button).to.have.class('MuiButton-contained'); + expect(button).to.have.class(buttonClasses.text); expect(button).to.have.class(classes.grouped); - expect(button).to.have.class(classes.groupedContained); - expect(button).to.have.class(classes.groupedContainedPrimary); - expect(button).not.to.have.class(classes.groupedContainedSecondary); + expect(button).to.have.class(classes.groupedText); + expect(button).to.have.class(classes.groupedTextPrimary); + expect(button).not.to.have.class(classes.groupedTextSecondary); }); it('can render a small button', () => { @@ -88,7 +89,8 @@ describe('', () => { , ); const button = getByRole('button'); - expect(button).to.have.class('MuiButton-outlinedSizeSmall'); + expect(button).to.have.class(buttonClasses.outlined); + expect(button).to.have.class(buttonClasses.sizeSmall); }); it('can render a large button', () => { @@ -98,7 +100,8 @@ describe('', () => { , ); const button = getByRole('button'); - expect(button).to.have.class('MuiButton-outlinedSizeLarge'); + expect(button).to.have.class(buttonClasses.outlined); + expect(button).to.have.class(buttonClasses.sizeLarge); }); it('should have a ripple by default', () => { @@ -117,7 +120,7 @@ describe('', () => { , ); const button = getByRole('button'); - expect(button).to.have.class('MuiButton-disableElevation'); + expect(button).to.have.class(buttonClasses.disableElevation); }); it('can disable the ripple', () => { From f9023335b77882e2069cabb65c75c0ac7dd25471 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 15:35:37 +0100 Subject: [PATCH 13/18] fix matchMedia error in unit test --- .../src/ButtonGroup/ButtonGroup.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index bccd622f72b02b..e19addd88183b0 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -9,6 +9,19 @@ import ButtonGroupContext from './ButtonGroupContext'; describe('', () => { const { render } = createRenderer(); + let originalMatchmedia; + + beforeEach(() => { + originalMatchmedia = window.matchMedia; + window.matchMedia = () => ({ + addListener: () => {}, + removeListener: () => {}, + }); + }); + afterEach(() => { + window.matchMedia = originalMatchmedia; + }); + describeConformance( From b07330b6a574092e5810e968c1838bcfcc512515 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Sat, 4 Nov 2023 21:06:12 +0100 Subject: [PATCH 14/18] fix render text button in .test --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index e19addd88183b0..7ce4f47821ccce 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -81,9 +81,10 @@ describe('', () => { expect(button).not.to.have.class(classes.groupedOutlinedSecondary); }); + // TODO change to filled when MD3 styles are applied it('can render a text button', () => { const { getByRole } = render( - + , ); From ce5b00f77bb5a9d5896b8b8dfde7949843e4fd41 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert <77863078+lhilgert9@users.noreply.github.com> Date: Tue, 7 Nov 2023 09:55:58 +0100 Subject: [PATCH 15/18] fix ButtonGroupContext naming Co-authored-by: Albert Yu Signed-off-by: Lucas Hilgert <77863078+lhilgert9@users.noreply.github.com> --- .../mui-material-next/src/ButtonGroup/ButtonGroupContext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts index 23b6cfd323940f..e25c7ae601e6b5 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import type { ButtonGroupProps } from './ButtonGroup'; -interface IButtonGroupContext { +interface ButtonGroupContext { className?: string; color?: ButtonGroupProps['color']; disabled?: boolean; From 257881110d5d9a9fdd91d8b17c22e65df5cfe8a6 Mon Sep 17 00:00:00 2001 From: Lucas Hilgert <77863078+lhilgert9@users.noreply.github.com> Date: Tue, 7 Nov 2023 10:00:18 +0100 Subject: [PATCH 16/18] fix comment naming Co-authored-by: Albert Yu Signed-off-by: Lucas Hilgert <77863078+lhilgert9@users.noreply.github.com> --- packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js index 7ce4f47821ccce..74c70dabaeabe6 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroup.test.js @@ -81,7 +81,7 @@ describe('', () => { expect(button).not.to.have.class(classes.groupedOutlinedSecondary); }); - // TODO change to filled when MD3 styles are applied + // TODO v6: change to filled when MD3 styles are applied it('can render a text button', () => { const { getByRole } = render( From 85c4db1b79a32dbcd8c725eb9f950b4e1887c9bb Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Tue, 7 Nov 2023 10:02:54 +0100 Subject: [PATCH 17/18] fix positionClassName naming --- packages/mui-material-next/src/Button/Button.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mui-material-next/src/Button/Button.tsx b/packages/mui-material-next/src/Button/Button.tsx index 7bf0426db78d00..9782e03f54e6c6 100644 --- a/packages/mui-material-next/src/Button/Button.tsx +++ b/packages/mui-material-next/src/Button/Button.tsx @@ -401,7 +401,7 @@ const Button = React.forwardRef(function Button< const classes = useUtilityClasses(ownerState); - const postionClassName = buttonGroupButtonContextPositionClassName ?? ''; + const positionClassName = buttonGroupButtonContextPositionClassName ?? ''; const rootProps = useSlotProps({ elementType: ButtonRoot, @@ -412,7 +412,7 @@ const Button = React.forwardRef(function Button< ref, }, ownerState, - className: clsx(contextProps.className, postionClassName), + className: clsx(contextProps.className, positionClassName), }); const startIcon = startIconProp && ( From 5697536d1dbe8d1e0428d3e381f5a5c0d8924cbc Mon Sep 17 00:00:00 2001 From: Lucas Hilgert Date: Tue, 7 Nov 2023 10:13:59 +0100 Subject: [PATCH 18/18] fix ButtonGroupContextType --- .../mui-material-next/src/ButtonGroup/ButtonGroupContext.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts index e25c7ae601e6b5..25cea93815c950 100644 --- a/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts +++ b/packages/mui-material-next/src/ButtonGroup/ButtonGroupContext.ts @@ -1,7 +1,7 @@ import * as React from 'react'; import type { ButtonGroupProps } from './ButtonGroup'; -interface ButtonGroupContext { +interface ButtonGroupContextType { className?: string; color?: ButtonGroupProps['color']; disabled?: boolean; @@ -16,7 +16,7 @@ interface ButtonGroupContext { /** * @ignore - internal component. */ -const ButtonGroupContext = React.createContext({}); +const ButtonGroupContext = React.createContext({}); if (process.env.NODE_ENV !== 'production') { ButtonGroupContext.displayName = 'ButtonGroupContext';