From bd5e806c13766dcf57e5cedf9a63e12b0f13b037 Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Wed, 7 Sep 2022 13:27:10 +0700 Subject: [PATCH] [Joy] Miscellaneous fixes (#34193) --- .../components/list/ExampleCollapsibleList.js | 8 +- .../{VariantsColorsList.js => ListUsage.js} | 2 +- docs/data/joy/components/list/list.md | 2 +- .../data/joy/components/menu/MenuListGroup.js | 3 +- .../joy/components/tabs/TabsPageExample.js | 4 +- .../joy/components/tabs/TabsPageExample.tsx | 4 +- packages/mui-joy/src/Checkbox/Checkbox.tsx | 2 +- packages/mui-joy/src/Input/Input.tsx | 2 +- packages/mui-joy/src/List/List.test.js | 5 ++ packages/mui-joy/src/List/List.tsx | 6 +- packages/mui-joy/src/List/ListProps.ts | 2 +- .../mui-joy/src/ListItem/ListItem.test.js | 14 +++- packages/mui-joy/src/ListItem/ListItem.tsx | 33 ++++---- .../mui-joy/src/ListItem/ListItemProps.ts | 5 -- .../mui-joy/src/ListItem/listItemClasses.ts | 30 +++++++ .../src/ListItemButton/ListItemButton.tsx | 4 +- packages/mui-joy/src/MenuList/MenuList.tsx | 1 - packages/mui-joy/src/Radio/Radio.tsx | 2 +- .../fixtures/ListJoy/Flexibility.js | 78 +++++++++++++++++++ 19 files changed, 168 insertions(+), 39 deletions(-) rename docs/data/joy/components/list/{VariantsColorsList.js => ListUsage.js} (96%) create mode 100644 test/regressions/fixtures/ListJoy/Flexibility.js diff --git a/docs/data/joy/components/list/ExampleCollapsibleList.js b/docs/data/joy/components/list/ExampleCollapsibleList.js index d5e477687f4e36..b219e38b76ef3f 100644 --- a/docs/data/joy/components/list/ExampleCollapsibleList.js +++ b/docs/data/joy/components/list/ExampleCollapsibleList.js @@ -85,7 +85,7 @@ export default function ExampleCollapsibleList() { } > - + 9 - + {open && ( @@ -136,7 +136,7 @@ export default function ExampleCollapsibleList() { } > - + 39 - + {open2 && ( diff --git a/docs/data/joy/components/list/VariantsColorsList.js b/docs/data/joy/components/list/ListUsage.js similarity index 96% rename from docs/data/joy/components/list/VariantsColorsList.js rename to docs/data/joy/components/list/ListUsage.js index 989226eef6d3f5..9a8afdef4e91c1 100644 --- a/docs/data/joy/components/list/VariantsColorsList.js +++ b/docs/data/joy/components/list/ListUsage.js @@ -8,7 +8,7 @@ import Home from '@mui/icons-material/Home'; import KeyboardArrowRight from '@mui/icons-material/KeyboardArrowRight'; import JoyUsageDemo from 'docs/src/modules/components/JoyUsageDemo'; -export default function VariantsColorsList() { +export default function ListUsage() { return ( {[...Array(5)].map((_, categoryIndex) => ( - + } - sx={{ bgcolor: 'background.body', mb: 0.75 }} /> diff --git a/docs/data/joy/components/tabs/TabsPageExample.tsx b/docs/data/joy/components/tabs/TabsPageExample.tsx index 24a2b1d880f405..c49cafc73b4c30 100644 --- a/docs/data/joy/components/tabs/TabsPageExample.tsx +++ b/docs/data/joy/components/tabs/TabsPageExample.tsx @@ -9,7 +9,7 @@ import Typography from '@mui/joy/Typography'; import Input from '@mui/joy/Input'; import SearchRounded from '@mui/icons-material/SearchRounded'; -export default function TabsBasic() { +export default function TabsPageExample() { const [index, setIndex] = React.useState(0); return ( } - sx={{ bgcolor: 'background.body', mb: 0.75 }} /> diff --git a/packages/mui-joy/src/Checkbox/Checkbox.tsx b/packages/mui-joy/src/Checkbox/Checkbox.tsx index 7e51b527a5c101..85fcb735e010d7 100644 --- a/packages/mui-joy/src/Checkbox/Checkbox.tsx +++ b/packages/mui-joy/src/Checkbox/Checkbox.tsx @@ -25,7 +25,7 @@ const useUtilityClasses = (ownerState: CheckboxOwnerState) => { color && `color${capitalize(color)}`, size && `size${capitalize(size)}`, ], - checkbox: ['checkbox', disabled && 'disabled'], // disabled class is necessary for displaying global variant + checkbox: ['checkbox', checked && 'checked', disabled && 'disabled'], // disabled class is necessary for displaying global variant action: [ 'action', checked && 'checked', diff --git a/packages/mui-joy/src/Input/Input.tsx b/packages/mui-joy/src/Input/Input.tsx index eb74edd37e2903..d61c7aefdb09f1 100644 --- a/packages/mui-joy/src/Input/Input.tsx +++ b/packages/mui-joy/src/Input/Input.tsx @@ -151,6 +151,7 @@ const InputInput = styled('input', { fontStyle: 'inherit', fontWeight: 'inherit', lineHeight: 'inherit', + textOverflow: 'ellipsis', '&:-webkit-autofill': { WebkitBackgroundClip: 'text', // remove autofill background WebkitTextFillColor: theme.vars.palette[ownerState.color!]?.overrideTextPrimary, @@ -169,7 +170,6 @@ const InputStartDecorator = styled('span', { '--Button-margin': '0 0 0 calc(var(--Input-decorator-childOffset) * -1)', '--IconButton-margin': '0 0 0 calc(var(--Input-decorator-childOffset) * -1)', '--Icon-margin': '0 0 0 calc(var(--Input-paddingInline) / -4)', - pointerEvents: 'none', // to make the input focused when click on the element because start element usually is an icon display: 'inherit', alignItems: 'center', marginInlineEnd: 'var(--Input-gap)', diff --git a/packages/mui-joy/src/List/List.test.js b/packages/mui-joy/src/List/List.test.js index a5753a6ced11f1..dd4af73110c074 100644 --- a/packages/mui-joy/src/List/List.test.js +++ b/packages/mui-joy/src/List/List.test.js @@ -44,6 +44,11 @@ describe('Joy ', () => { expect(container.firstChild).to.have.class(classes.sizeLg); }); + it('should have default size="md" classes', () => { + const { container } = render(); + expect(container.firstChild).to.have.class(classes.sizeMd); + }); + it('should have nesting classes', () => { const { getByRole } = render( diff --git a/packages/mui-joy/src/List/List.tsx b/packages/mui-joy/src/List/List.tsx index 107609bb32ce84..cb0daf1d87270f 100644 --- a/packages/mui-joy/src/List/List.tsx +++ b/packages/mui-joy/src/List/List.tsx @@ -109,7 +109,7 @@ export const ListRoot = styled('ul', { ? { ...(ownerState.wrap ? { - padding: 'var(--List-padding)', + padding: 'var(--List-padding)', // Fallback is not needed for row-wrap List marginInlineStart: 'calc(-1 * var(--List-gap))', marginBlockStart: 'calc(-1 * var(--List-gap))', } @@ -151,7 +151,7 @@ const List = React.forwardRef(function List(inProps, ref) { component, className, children, - size = 'md', + size = inProps.size ?? 'md', row = false, wrap = false, variant = 'plain', @@ -163,6 +163,7 @@ const List = React.forwardRef(function List(inProps, ref) { const role = roleProp ?? (menuContext || selectContext ? 'group' : undefined); const ownerState = { + ...props, instanceSize: inProps.size, size, nesting, @@ -171,7 +172,6 @@ const List = React.forwardRef(function List(inProps, ref) { variant, color, role, - ...props, }; const classes = useUtilityClasses(ownerState); diff --git a/packages/mui-joy/src/List/ListProps.ts b/packages/mui-joy/src/List/ListProps.ts index 5615c2c2a91bc3..4d46279cf7724b 100644 --- a/packages/mui-joy/src/List/ListProps.ts +++ b/packages/mui-joy/src/List/ListProps.ts @@ -63,7 +63,7 @@ export interface ListOwnerState extends ListProps { * @internal * The explicit size specified on the element instance. */ - instanceSize: ListProps['size']; + instanceSize?: ListProps['size']; /** * @internal * If `true`, the element is rendered in a nested list item. diff --git a/packages/mui-joy/src/ListItem/ListItem.test.js b/packages/mui-joy/src/ListItem/ListItem.test.js index a1d0d91e10ae02..b213e70760dd96 100644 --- a/packages/mui-joy/src/ListItem/ListItem.test.js +++ b/packages/mui-joy/src/ListItem/ListItem.test.js @@ -18,7 +18,7 @@ describe('Joy ', () => { refInstanceof: window.HTMLLIElement, testVariantProps: { variant: 'solid' }, testCustomVariant: true, - skip: ['componentsProp', 'classesRoot', 'themeVariants'], + skip: ['componentsProp', 'classesRoot'], })); it('should have root className', () => { @@ -78,6 +78,18 @@ describe('Joy ', () => { expect(screen.getByText('Foo')).to.have.attribute('role', 'none'); }); + + it('should have role presentation for grouped options', () => { + render( + + + Foo + + , + ); + + expect(screen.getByRole('group').firstChild).to.have.attribute('role', 'presentation'); + }); }); describe('Semantics - List', () => { diff --git a/packages/mui-joy/src/ListItem/ListItem.tsx b/packages/mui-joy/src/ListItem/ListItem.tsx index a6369bdbb8fed7..444e608483c124 100644 --- a/packages/mui-joy/src/ListItem/ListItem.tsx +++ b/packages/mui-joy/src/ListItem/ListItem.tsx @@ -72,6 +72,7 @@ const ListItemRoot = styled('li', { boxSizing: 'border-box', borderRadius: 'var(--List-item-radius)', display: 'flex', + flex: 'none', position: 'relative', paddingBlockStart: ownerState.nested ? 0 : 'var(--List-item-paddingY)', paddingBlockEnd: ownerState.nested ? 0 : 'var(--List-item-paddingY)', @@ -159,13 +160,17 @@ const ListItem = React.forwardRef(function ListItem(inProps, ref) { const [listElement, listRole] = listComponent?.split(':') || ['', '']; const component = componentProp || (listElement && !listElement.match(/^(ul|ol|menu)$/) ? 'div' : undefined); - const role = - roleProp ?? - (menuContext - ? // ListItem can be used inside Menu to create nested menus, so it should have role="none" - // https://www.w3.org/WAI/ARIA/apg/example-index/menubar/menubar-navigation.html - 'none' - : { menu: 'none', menubar: 'none', group: 'presentation' }[listRole]); + + let role = menuContext ? 'none' : undefined; + + if (listComponent) { + // ListItem can be used inside Menu to create nested menus, so it should have role="none" + // https://www.w3.org/WAI/ARIA/apg/example-index/menubar/menubar-navigation.html + role = { menu: 'none', menubar: 'none', group: 'presentation' }[listRole]; + } + if (roleProp) { + role = roleProp; + } const ownerState = { sticky, @@ -231,10 +236,6 @@ ListItem.propTypes /* remove-proptypes */ = { * The content of the component. */ children: PropTypes.node, - /** - * Override or extend the styles applied to the component. - */ - classes: PropTypes.object, /** * @ignore */ @@ -243,7 +244,10 @@ ListItem.propTypes /* remove-proptypes */ = { * The color of the component. It supports those theme colors that make sense for this component. * @default 'neutral' */ - color: PropTypes.oneOf(['danger', 'info', 'neutral', 'primary', 'success', 'warning']), + color: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([ + PropTypes.oneOf(['danger', 'info', 'neutral', 'primary', 'success', 'warning']), + PropTypes.string, + ]), /** * The component used for the root node. * Either a string to use a HTML element or a component. @@ -283,7 +287,10 @@ ListItem.propTypes /* remove-proptypes */ = { * The variant to use. * @default 'plain' */ - variant: PropTypes.oneOf(['outlined', 'plain', 'soft', 'solid']), + variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([ + PropTypes.oneOf(['outlined', 'plain', 'soft', 'solid']), + PropTypes.string, + ]), } as any; // @ts-ignore internal logic to prevent
  • in
  • diff --git a/packages/mui-joy/src/ListItem/ListItemProps.ts b/packages/mui-joy/src/ListItem/ListItemProps.ts index 3cea240b5f36e5..a4000f0a213122 100644 --- a/packages/mui-joy/src/ListItem/ListItemProps.ts +++ b/packages/mui-joy/src/ListItem/ListItemProps.ts @@ -1,7 +1,6 @@ import * as React from 'react'; import { OverridableStringUnion, OverrideProps } from '@mui/types'; import { ColorPaletteProp, VariantProp, SxProps } from '../styles/types'; -import { ListItemClasses } from './listItemClasses'; export type ListItemSlot = 'root' | 'startAction' | 'endAction'; @@ -20,10 +19,6 @@ export interface ListItemTypeMap

    { * The content of the component. */ children?: React.ReactNode; - /** - * Override or extend the styles applied to the component. - */ - classes?: Partial; /** * The element to display at the start of ListItem. */ diff --git a/packages/mui-joy/src/ListItem/listItemClasses.ts b/packages/mui-joy/src/ListItem/listItemClasses.ts index 5d7049737e097f..f5feeaebd3fdb7 100644 --- a/packages/mui-joy/src/ListItem/listItemClasses.ts +++ b/packages/mui-joy/src/ListItem/listItemClasses.ts @@ -13,6 +13,26 @@ export interface ListItemClasses { nesting: string; /** Styles applied to the root element, if sticky={true}. */ sticky: string; + /** Styles applied to the root element if `color="primary"`. */ + colorPrimary: string; + /** Styles applied to the root element if `color="neutral"`. */ + colorNeutral: string; + /** Styles applied to the root element if `color="danger"`. */ + colorDanger: string; + /** Styles applied to the root element if `color="info"`. */ + colorInfo: string; + /** Styles applied to the root element if `color="success"`. */ + colorSuccess: string; + /** Styles applied to the root element if `color="warning"`. */ + colorWarning: string; + /** State class applied to the root element if `variant="plain"`. */ + variantPlain: string; + /** State class applied to the root element if `variant="soft"`. */ + variantSoft: string; + /** State class applied to the root element if `variant="outlined"`. */ + variantOutlined: string; + /** State class applied to the root element if `variant="solid"`. */ + variantSolid: string; } export type ListItemClassKey = keyof ListItemClasses; @@ -28,6 +48,16 @@ const listItemClasses: ListItemClasses = generateUtilityClasses('JoyListItem', [ 'nested', 'nesting', 'sticky', + 'colorPrimary', + 'colorNeutral', + 'colorDanger', + 'colorInfo', + 'colorSuccess', + 'colorWarning', + 'variantPlain', + 'variantSoft', + 'variantOutlined', + 'variantSolid', ]); export default listItemClasses; diff --git a/packages/mui-joy/src/ListItemButton/ListItemButton.tsx b/packages/mui-joy/src/ListItemButton/ListItemButton.tsx index 5cc4df776293bc..f73b8fd4fcc0f2 100644 --- a/packages/mui-joy/src/ListItemButton/ListItemButton.tsx +++ b/packages/mui-joy/src/ListItemButton/ListItemButton.tsx @@ -72,7 +72,9 @@ export const ListItemButtonRoot = styled('div', { minBlockSize: 'var(--List-item-minHeight)', border: 'none', borderRadius: 'var(--List-item-radius)', - flex: ownerState.row ? 'none' : 1, + flexGrow: ownerState.row ? 0 : 1, + flexBasis: ownerState.row ? 'auto' : '0%', // for long text (in vertical), displays in multiple lines. + flexShrink: 0, minInlineSize: 0, // TODO: discuss the transition approach in a separate PR. This value is copied from mui-material Button. transition: diff --git a/packages/mui-joy/src/MenuList/MenuList.tsx b/packages/mui-joy/src/MenuList/MenuList.tsx index 5ca00a3621eb87..03f24130d50cf2 100644 --- a/packages/mui-joy/src/MenuList/MenuList.tsx +++ b/packages/mui-joy/src/MenuList/MenuList.tsx @@ -90,7 +90,6 @@ const MenuList = React.forwardRef(function MenuList(inProps, ref) { variant, color, size, - instanceSize: size, nesting: false, row: false, }; diff --git a/packages/mui-joy/src/Radio/Radio.tsx b/packages/mui-joy/src/Radio/Radio.tsx index 1523de2269fe3b..f81762d2be3182 100644 --- a/packages/mui-joy/src/Radio/Radio.tsx +++ b/packages/mui-joy/src/Radio/Radio.tsx @@ -24,7 +24,7 @@ const useUtilityClasses = (ownerState: RadioOwnerState) => { color && `color${capitalize(color)}`, size && `size${capitalize(size)}`, ], - radio: ['radio', disabled && 'disabled'], // disabled class is necessary for displaying global variant + radio: ['radio', checked && 'checked', disabled && 'disabled'], // disabled class is necessary for displaying global variant icon: ['icon'], action: [ 'action', diff --git a/test/regressions/fixtures/ListJoy/Flexibility.js b/test/regressions/fixtures/ListJoy/Flexibility.js new file mode 100644 index 00000000000000..4db7e8a25ccc00 --- /dev/null +++ b/test/regressions/fixtures/ListJoy/Flexibility.js @@ -0,0 +1,78 @@ +import * as React from 'react'; +import Box from '@mui/joy/Box'; +import List from '@mui/joy/List'; +import ListItem from '@mui/joy/ListItem'; +import ListDivider from '@mui/joy/ListDivider'; +import ListItemButton from '@mui/joy/ListItemButton'; + +export default function Flexibility() { + return ( + + + This is a very long text that should scale by its content. + Item 2 + Item 3 + Item 4 + + + This is a very long text that should scale by its content. + Item 2 + Item 3 + Item 4 + + + + + This is a very long text that should scale by its content. + + + + Item 2 + + + Item 3 + + + Item 4 + + + + + + Home + + + + + + Products + + + + + + Blog + + + + + Account + + + + + ); +}