Skip to content

Commit

Permalink
[Joy] Refine componentsProps for all components (mui#34077)
Browse files Browse the repository at this point in the history
  • Loading branch information
siriwatknp authored and Daniel Rabe committed Nov 29, 2022
1 parent b26c1e5 commit 4803370
Show file tree
Hide file tree
Showing 114 changed files with 2,917 additions and 1,189 deletions.
20 changes: 10 additions & 10 deletions docs/data/joy/components/checkbox/ExampleButtonCheckbox.js
@@ -1,5 +1,5 @@
import * as React from 'react';
import Checkbox, { checkboxClasses } from '@mui/joy/Checkbox';
import Checkbox from '@mui/joy/Checkbox';
import List from '@mui/joy/List';
import ListItem from '@mui/joy/ListItem';
import ListItemDecorator from '@mui/joy/ListItemDecorator';
Expand Down Expand Up @@ -53,16 +53,16 @@ export default function ExampleButtonCheckbox() {
setValue((val) => val.filter((text) => text !== item));
}
}}
sx={{
[`& .${checkboxClasses.action}`]: {
bgcolor: value.includes(item) ? 'background.surface' : 'transparent',
boxShadow: value.includes(item) ? 'sm' : 'none',
'&:hover': {
bgcolor: value.includes(item)
? 'background.surface'
: 'transparent',
componentsProps={{
action: ({ checked }) => ({
sx: {
bgcolor: checked ? 'background.surface' : 'transparent',
boxShadow: checked ? 'sm' : 'none',
'&:hover': {
bgcolor: checked ? 'background.surface' : 'transparent',
},
},
},
}),
}}
/>
</ListItem>
Expand Down
18 changes: 10 additions & 8 deletions docs/data/joy/components/checkbox/ExampleChoiceChipCheckbox.js
@@ -1,6 +1,6 @@
import * as React from 'react';
import Box from '@mui/joy/Box';
import Checkbox, { checkboxClasses } from '@mui/joy/Checkbox';
import Checkbox from '@mui/joy/Checkbox';
import List from '@mui/joy/List';
import ListItem from '@mui/joy/ListItem';
import Typography from '@mui/joy/Typography';
Expand Down Expand Up @@ -49,13 +49,15 @@ export default function ExampleChoiceChipCheckbox() {
setValue((val) => val.filter((text) => text !== item));
}
}}
sx={{
[`&.${checkboxClasses.checked}`]: {
[`& .${checkboxClasses.action}`]: {
border: '1px solid',
borderColor: 'primary.500',
},
},
componentsProps={{
action: ({ checked }) => ({
sx: checked
? {
border: '1px solid',
borderColor: 'primary.500',
}
: {},
}),
}}
/>
</ListItem>
Expand Down
18 changes: 12 additions & 6 deletions docs/data/joy/components/checkbox/HoverCheckbox.js
@@ -1,17 +1,23 @@
import * as React from 'react';
import Checkbox, { checkboxClasses } from '@mui/joy/Checkbox';
import Checkbox from '@mui/joy/Checkbox';
import Done from '@mui/icons-material/Done';

export default function HoverCheckbox() {
return (
<Checkbox
uncheckedIcon={<Done />}
label="Label"
sx={{
[`&:not(.${checkboxClasses.checked})`]: {
'& svg': { opacity: 0 },
[`&:hover svg, &.${checkboxClasses.focusVisible} svg`]: { opacity: 1 },
},
componentsProps={{
root: ({ checked, focusVisible }) => ({
sx: !checked
? {
'& svg': { opacity: focusVisible ? 0.32 : 0 },
'&:hover svg': {
opacity: 0.32,
},
}
: {},
}),
}}
/>
);
Expand Down
1 change: 1 addition & 0 deletions packages/mui-joy/src/AspectRatio/AspectRatio.test.js
Expand Up @@ -17,6 +17,7 @@ describe('<AspectRatio />', () => {
refInstanceof: window.HTMLDivElement,
testComponentPropWith: 'span',
testVariantProps: { variant: 'solid' },
testCustomVariant: true,
skip: ['classesRoot', 'componentsProp'],
}));

Expand Down
55 changes: 30 additions & 25 deletions packages/mui-joy/src/AspectRatio/AspectRatio.tsx
@@ -1,15 +1,15 @@
import * as React from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { unstable_composeClasses as composeClasses } from '@mui/base';
import { useSlotProps } from '@mui/base/utils';
import { OverridableComponent } from '@mui/types';
import { unstable_capitalize as capitalize } from '@mui/utils';
import { useThemeProps } from '../styles';
import styled from '../styles/styled';
import { getAspectRatioUtilityClass } from './aspectRatioClasses';
import { AspectRatioProps, AspectRatioTypeMap } from './AspectRatioProps';
import { AspectRatioProps, AspectRatioOwnerState, AspectRatioTypeMap } from './AspectRatioProps';

const useUtilityClasses = (ownerState: AspectRatioProps) => {
const useUtilityClasses = (ownerState: AspectRatioOwnerState) => {
const { variant, color } = ownerState;
const slots = {
root: ['root'],
Expand All @@ -28,7 +28,7 @@ const AspectRatioRoot = styled('div', {
name: 'JoyAspectRatio',
slot: 'Root',
overridesResolver: (props, styles) => styles.root,
})<{ ownerState: AspectRatioProps }>(({ ownerState }) => {
})<{ ownerState: AspectRatioOwnerState }>(({ ownerState }) => {
const minHeight =
typeof ownerState.minHeight === 'number' ? `${ownerState.minHeight}px` : ownerState.minHeight;
const maxHeight =
Expand All @@ -49,8 +49,8 @@ const AspectRatioRoot = styled('div', {
const AspectRatioContent = styled('div', {
name: 'JoyAspectRatio',
slot: 'Content',
overridesResolver: (props, styles) => styles.root,
})<{ ownerState: AspectRatioProps }>(({ theme, ownerState }) => [
overridesResolver: (props, styles) => styles.content,
})<{ ownerState: AspectRatioOwnerState }>(({ theme, ownerState }) => [
{
flex: 1,
position: 'relative',
Expand Down Expand Up @@ -89,10 +89,9 @@ const AspectRatio = React.forwardRef(function AspectRatio(inProps, ref) {
});

const {
className,
component = 'div',
children,
componentsProps,
componentsProps = {},
ratio = '16 / 9',
minHeight,
maxHeight,
Expand All @@ -115,19 +114,28 @@ const AspectRatio = React.forwardRef(function AspectRatio(inProps, ref) {

const classes = useUtilityClasses(ownerState);

const rootProps = useSlotProps({
elementType: AspectRatioRoot,
ownerState,
externalSlotProps: componentsProps.root,
externalForwardedProps: other,
additionalProps: {
ref,
as: component,
},
className: classes.root,
});

const contentProps = useSlotProps({
elementType: AspectRatioContent,
ownerState,
externalSlotProps: componentsProps.content,
className: classes.content,
});

return (
<AspectRatioRoot
as={component}
ownerState={ownerState}
className={clsx(classes.root, className)}
ref={ref}
{...other}
>
<AspectRatioContent
ownerState={ownerState}
{...componentsProps?.content}
className={clsx(classes.content, componentsProps?.content?.className, className)}
>
<AspectRatioRoot {...rootProps}>
<AspectRatioContent {...contentProps}>
{React.Children.map(children, (child, index) =>
index === 0 && React.isValidElement(child)
? React.cloneElement(child, { 'data-first-child': '' })
Expand All @@ -148,10 +156,6 @@ AspectRatio.propTypes /* remove-proptypes */ = {
* This can be an element, or just a string.
*/
children: PropTypes.node,
/**
* @ignore
*/
className: PropTypes.string,
/**
* The color of the component. It supports those theme colors that make sense for this component.
* @default 'neutral'
Expand All @@ -167,7 +171,8 @@ AspectRatio.propTypes /* remove-proptypes */ = {
* @default {}
*/
componentsProps: PropTypes.shape({
content: PropTypes.object.isRequired,
content: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
}),
/**
* The maximum calculated height of the element (not the CSS height).
Expand Down
12 changes: 9 additions & 3 deletions packages/mui-joy/src/AspectRatio/AspectRatioProps.ts
@@ -1,12 +1,18 @@
import * as React from 'react';
import { OverridableStringUnion, OverrideProps } from '@mui/types';
import { SlotComponentProps } from '@mui/base/utils';
import { ColorPaletteProp, VariantProp, SxProps } from '../styles/types';

export type AspectRatioSlot = 'root' | 'content';

export interface AspectRatioPropsColorOverrides {}
export interface AspectRatioPropsVariantOverrides {}

interface ComponentsProps {
root?: SlotComponentProps<'div', { sx?: SxProps }, AspectRatioOwnerState>;
content?: SlotComponentProps<'div', { sx?: SxProps }, AspectRatioOwnerState>;
}

export interface AspectRatioTypeMap<P = {}, D extends React.ElementType = 'div'> {
props: P & {
/**
Expand All @@ -23,9 +29,7 @@ export interface AspectRatioTypeMap<P = {}, D extends React.ElementType = 'div'>
* The props used for each slot inside the AspectRatio.
* @default {}
*/
componentsProps?: {
content: React.HTMLAttributes<HTMLDivElement> & { sx: SxProps };
};
componentsProps?: ComponentsProps;
/**
* The minimum calculated height of the element (not the CSS height).
*/
Expand Down Expand Up @@ -61,3 +65,5 @@ export type AspectRatioProps<
D extends React.ElementType = AspectRatioTypeMap['defaultComponent'],
P = { component?: React.ElementType },
> = OverrideProps<AspectRatioTypeMap<P, D>, D>;

export interface AspectRatioOwnerState extends AspectRatioProps {}
9 changes: 7 additions & 2 deletions packages/mui-joy/src/Avatar/Avatar.test.js
Expand Up @@ -20,6 +20,7 @@ describe('<Avatar />', () => {
testComponentPropWith: 'span',
testDeepOverrides: { slotName: 'fallback', slotClassName: classes.fallback },
testVariantProps: { variant: 'solid' },
testCustomVariant: true,
skip: ['classesRoot', 'componentsProp'],
}));

Expand Down Expand Up @@ -95,7 +96,9 @@ describe('<Avatar />', () => {

it('should be able to add more props to the image', () => {
const onError = spy();
const { container } = render(<Avatar src="/fake.png" imgProps={{ onError }} />);
const { container } = render(
<Avatar src="/fake.png" componentsProps={{ img: { onError } }} />,
);
const img = container.querySelector('img');
fireEvent.error(img);
expect(onError.callCount).to.equal(1);
Expand All @@ -113,7 +116,9 @@ describe('<Avatar />', () => {

it('should be able to add more props to the image', () => {
const onError = spy();
const { container } = render(<Avatar src="/fake.png" imgProps={{ onError }} />);
const { container } = render(
<Avatar src="/fake.png" componentsProps={{ img: { onError } }} />,
);
const img = container.querySelector('img');
fireEvent.error(img);
expect(onError.callCount).to.equal(1);
Expand Down

0 comments on commit 4803370

Please sign in to comment.