Skip to content

Commit

Permalink
[base-ui] Fix mergeSlotProps className join order (#39616)
Browse files Browse the repository at this point in the history
  • Loading branch information
mj12albert authored Oct 31, 2023
1 parent e74a4f5 commit 8ab0e65
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 25 deletions.
75 changes: 52 additions & 23 deletions packages/mui-base/src/utils/mergeSlotProps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,36 +40,65 @@ describe('mergeSlotProps', () => {
expect(merged.props.prop4).to.equal('internal');
});

it('joins all the class names in order from internal to external', () => {
const getSlotProps = () => ({
className: 'internal',
describe('it joins all class names in order from least to most important', () => {
it('when internal classNames from getSlotProps are included', () => {
const getSlotProps = () => ({
className: 'internal',
});

const additionalProps = {
className: 'additional',
};

const externalForwardedProps = {
className: 'externalForwarded',
};

const externalSlotProps = {
className: 'externalSlot',
};

const className = ['class1', 'class2'];

const merged = mergeSlotProps({
getSlotProps,
additionalProps,
externalForwardedProps,
externalSlotProps,
className,
});

expect(merged.props.className).to.equal(
'internal additional class1 class2 externalForwarded externalSlot',
);
});

const additionalProps = {
className: 'additional',
};
it('when getSlotProps is not present', () => {
const additionalProps = {
className: 'additional',
};

const externalForwardedProps = {
className: 'externalForwarded',
};
const externalForwardedProps = {
className: 'externalForwarded',
};

const externalSlotProps = {
className: 'externalSlot',
};
const externalSlotProps = {
className: 'externalSlot',
};

const className = ['class1', 'class2'];
const className = ['class1', 'class2'];

const merged = mergeSlotProps({
getSlotProps,
additionalProps,
externalForwardedProps,
externalSlotProps,
className,
});
const merged = mergeSlotProps({
additionalProps,
externalForwardedProps,
externalSlotProps,
className,
});

expect(merged.props.className).to.equal(
'internal additional class1 class2 externalForwarded externalSlot',
);
expect(merged.props.className).to.equal(
'additional class1 class2 externalForwarded externalSlot',
);
});
});

it('merges the style props', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/mui-base/src/utils/mergeSlotProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ export function mergeSlotProps<
// The simpler case - getSlotProps is not defined, so no internal event handlers are defined,
// so we can simply merge all the props without having to worry about extracting event handlers.
const joinedClasses = clsx(
additionalProps?.className,
className,
externalForwardedProps?.className,
externalSlotProps?.className,
className,
additionalProps?.className,
);

const mergedStyle = {
Expand Down
33 changes: 33 additions & 0 deletions packages/mui-material-next/src/FilledInput/FilledInput.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { expect } from 'chai';
import { ClassNames } from '@emotion/react';
import { createRenderer, describeConformance } from '@mui-internal/test-utils';
import { CssVarsProvider, extendTheme } from '@mui/material-next/styles';
import FilledInput, { filledInputClasses as classes } from '@mui/material-next/FilledInput';
Expand Down Expand Up @@ -65,4 +66,36 @@ describe('<FilledInput />', () => {
const root = getByTestId('test-input');
expect(root).toHaveComputedStyle({ marginTop: '10px' });
});

describe('Emotion compatibility', () => {
it('classes.root should overwrite built-in styles.', () => {
const { getByTestId } = render(
<ClassNames>
{({ css }) => (
<FilledInput data-testid="root" classes={{ root: css({ position: 'static' }) }} />
)}
</ClassNames>,
);
const input = getByTestId('root');

expect(getComputedStyle(input).position).to.equal('static');
});

it('className should overwrite classes.root and built-in styles.', () => {
const { getByTestId } = render(
<ClassNames>
{({ css }) => (
<FilledInput
data-testid="root"
className={css({ position: 'sticky' })}
classes={{ root: css({ position: 'static' }) }}
/>
)}
</ClassNames>,
);
const input = getByTestId('root');

expect(getComputedStyle(input).position).to.equal('sticky');
});
});
});
33 changes: 33 additions & 0 deletions packages/mui-material-next/src/FormControl/FormControl.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import { expect } from 'chai';
import { spy } from 'sinon';
import { ClassNames } from '@emotion/react';
import { describeConformance, act, createRenderer, fireEvent } from '@mui-internal/test-utils';
import FormControl, { formControlClasses as classes } from '@mui/material-next/FormControl';
import FilledInput from '@mui/material-next/FilledInput';
Expand Down Expand Up @@ -444,4 +445,36 @@ describe('<FormControl />', () => {
});
});
});

describe('Emotion compatibility', () => {
it('classes.root should overwrite built-in styles.', () => {
const { getByTestId } = render(
<ClassNames>
{({ css }) => (
<FormControl data-testid="root" classes={{ root: css({ display: 'inline' }) }} />
)}
</ClassNames>,
);
const root = getByTestId('root');

expect(getComputedStyle(root).display).to.equal('inline');
});

it('className should overwrite classes.root and built-in styles.', () => {
const { getByTestId } = render(
<ClassNames>
{({ css }) => (
<FormControl
data-testid="root"
className={css({ display: 'inline-block' })}
classes={{ root: css({ display: 'inline' }) }}
/>
)}
</ClassNames>,
);
const root = getByTestId('root');

expect(getComputedStyle(root).display).to.equal('inline-block');
});
});
});

0 comments on commit 8ab0e65

Please sign in to comment.