From e4172c51581cd20ba8151176482debbcd6c4d08d Mon Sep 17 00:00:00 2001 From: Siriwat K Date: Thu, 4 Aug 2022 18:16:34 +0700 Subject: [PATCH] [Joy] Miscellaneous fixes (#33796) --- .../joy/components/link/LinkAndTypography.js | 3 +- .../data/joy/components/list/DecoratedList.js | 2 +- docs/data/joy/components/list/DividedList.js | 2 +- docs/data/joy/components/list/EllipsisList.js | 2 +- .../joy/components/list/ExampleGmailList.js | 2 +- .../joy/components/list/ExampleIOSList.js | 2 +- .../components/list/ExampleNavigationMenu.js | 2 +- .../components/list/HorizontalDividedList.js | 2 +- .../data/joy/components/list/ListVariables.js | 2 +- docs/data/joy/components/list/list.md | 2 +- docs/data/joy/components/menu/GroupMenu.js | 2 +- .../joy/components/radio/RadioPositionEnd.js | 2 +- .../components/select/SelectCustomOption.js | 4 +- .../select/SelectCustomValueAppearance.js | 2 +- .../components/select/SelectGroupedOptions.js | 2 +- .../components/tabs/TabsBottomNavExample.js | 33 ++++++--- .../components/tabs/TabsBottomNavExample.tsx | 33 ++++++--- .../joy/components/tabs/TabsIconWithText.js | 68 +++++++++++++------ .../joy/components/tabs/TabsIconWithText.tsx | 68 +++++++++++++------ .../templates/email/components/Navigation.tsx | 2 +- .../templates/files/components/Navigation.tsx | 2 +- .../getting-started/templates/team/App.tsx | 2 +- .../automatic-adjustment/ListThemes.js | 4 +- docs/src/modules/components/JoyUsageDemo.tsx | 2 +- packages/mui-joy/src/Link/Link.tsx | 6 +- packages/mui-joy/src/List/List.tsx | 6 +- .../mui-joy/src/ListDivider/ListDivider.tsx | 22 +++--- .../src/ListItemButton/ListItemButton.tsx | 43 ++++++++---- .../ListItemButtonOrientationContext.ts | 7 ++ .../src/ListItemButton/ListItemButtonProps.ts | 5 ++ .../ListItemButton/listItemButtonClasses.ts | 6 ++ .../ListItemDecorator/ListItemDecorator.tsx | 25 +++++-- packages/mui-joy/src/MenuItem/MenuItem.tsx | 4 +- packages/mui-joy/src/Option/Option.tsx | 4 +- packages/mui-joy/src/Tab/Tab.tsx | 21 ++++-- packages/mui-joy/src/Tab/TabProps.ts | 5 ++ 36 files changed, 266 insertions(+), 135 deletions(-) create mode 100644 packages/mui-joy/src/ListItemButton/ListItemButtonOrientationContext.ts diff --git a/docs/data/joy/components/link/LinkAndTypography.js b/docs/data/joy/components/link/LinkAndTypography.js index f20336373798d5..3e1727c8a91b7c 100644 --- a/docs/data/joy/components/link/LinkAndTypography.js +++ b/docs/data/joy/components/link/LinkAndTypography.js @@ -5,7 +5,7 @@ import Typography from '@mui/joy/Typography'; import CallMade from '@mui/icons-material/CallMade'; import LinkIcon from '@mui/icons-material/Link'; -export default function Links() { +export default function LinkAndTypography() { return ( diff --git a/docs/data/joy/components/list/DecoratedList.js b/docs/data/joy/components/list/DecoratedList.js index 51184be1f5fa1c..41daf2412f1bed 100644 --- a/docs/data/joy/components/list/DecoratedList.js +++ b/docs/data/joy/components/list/DecoratedList.js @@ -18,7 +18,7 @@ export default function DecoratedList() { 🧅 1 red onion diff --git a/docs/data/joy/components/list/DividedList.js b/docs/data/joy/components/list/DividedList.js index ac57a419f82746..651c04358d1cff 100644 --- a/docs/data/joy/components/list/DividedList.js +++ b/docs/data/joy/components/list/DividedList.js @@ -27,7 +27,7 @@ export default function DividedList() { sx={{ minWidth: 240, borderRadius: 'sm', - '--List-decorator-width': '48px', + '--List-decorator-size': '48px', '--List-item-paddingLeft': '1.5rem', '--List-item-paddingRight': '1rem', }} diff --git a/docs/data/joy/components/list/EllipsisList.js b/docs/data/joy/components/list/EllipsisList.js index d4f494583ce177..108ca29d936cef 100644 --- a/docs/data/joy/components/list/EllipsisList.js +++ b/docs/data/joy/components/list/EllipsisList.js @@ -22,7 +22,7 @@ export default function EllipsisList() { diff --git a/docs/data/joy/components/list/ExampleGmailList.js b/docs/data/joy/components/list/ExampleGmailList.js index db63dd77aaa62e..6471e638be79f4 100644 --- a/docs/data/joy/components/list/ExampleGmailList.js +++ b/docs/data/joy/components/list/ExampleGmailList.js @@ -24,7 +24,7 @@ export default function ExampleGmailList() { sx={{ // ...applyRadiusOnEdges({ target: 'deepest' | 'nested' }), '--List-item-paddingLeft': '0px', - '--List-decorator-width': '64px', + '--List-decorator-size': '64px', '--List-decorator-color': (theme) => theme.vars.palette.text.secondary, '--List-item-minHeight': '32px', '--List-nestedInsetStart': '13px', diff --git a/docs/data/joy/components/list/ExampleIOSList.js b/docs/data/joy/components/list/ExampleIOSList.js index ae5145c211458d..631840bf22c6ac 100644 --- a/docs/data/joy/components/list/ExampleIOSList.js +++ b/docs/data/joy/components/list/ExampleIOSList.js @@ -59,7 +59,7 @@ export default function ExampleIOSList() { })} > - + diff --git a/docs/data/joy/components/list/ExampleNavigationMenu.js b/docs/data/joy/components/list/ExampleNavigationMenu.js index 4e4d9fd5a8bd5b..060870dbffe894 100644 --- a/docs/data/joy/components/list/ExampleNavigationMenu.js +++ b/docs/data/joy/components/list/ExampleNavigationMenu.js @@ -147,7 +147,7 @@ const AboutMenu = React.forwardRef(({ focusNext, focusPrevious, ...props }, ref) '--List-radius': '8px', '--List-padding': '4px', '--List-divider-gap': '4px', - '--List-decorator-width': '32px', + '--List-decorator-size': '32px', }} > diff --git a/docs/data/joy/components/list/HorizontalDividedList.js b/docs/data/joy/components/list/HorizontalDividedList.js index e4e1d503de797b..93a4b33f3e4f23 100644 --- a/docs/data/joy/components/list/HorizontalDividedList.js +++ b/docs/data/joy/components/list/HorizontalDividedList.js @@ -14,7 +14,7 @@ export default function HorizontalDividedList() { borderRadius: 'sm', flexGrow: 0, mx: 'auto', - '--List-decorator-width': '48px', + '--List-decorator-size': '48px', '--List-item-paddingY': '1rem', }} > diff --git a/docs/data/joy/components/list/ListVariables.js b/docs/data/joy/components/list/ListVariables.js index 13121bfb185001..b0f34a0a1a1776 100644 --- a/docs/data/joy/components/list/ListVariables.js +++ b/docs/data/joy/components/list/ListVariables.js @@ -25,7 +25,7 @@ export default function ListVariables() { { var: '--List-item-minHeight', defaultValue: '40px' }, { var: '--List-item-paddingY', defaultValue: '6px' }, { var: '--List-item-paddingX', defaultValue: '12px' }, - { var: '--List-decorator-width', defaultValue: '40px' }, + { var: '--List-decorator-size', defaultValue: '40px' }, { var: '--List-divider-gap', defaultValue: '6px' }, ]} renderDemo={(sx) => ( diff --git a/docs/data/joy/components/list/list.md b/docs/data/joy/components/list/list.md index 847f61b8a8052a..79aa13ea35c574 100644 --- a/docs/data/joy/components/list/list.md +++ b/docs/data/joy/components/list/list.md @@ -56,7 +56,7 @@ Use the `size` prop to control font-size and general list density. Use the `ListItemDecorator` component to add supporting icons or elements to the list item. -It comes with a minimum set width that you can adjust via the `--List-decorator-width` CSS variable within the `List` component. +It comes with a minimum set width that you can adjust via the `--List-decorator-size` CSS variable within the `List` component. {{"demo": "DecoratedList.js"}} diff --git a/docs/data/joy/components/menu/GroupMenu.js b/docs/data/joy/components/menu/GroupMenu.js index 9153948d003c02..5f07e08038a32d 100644 --- a/docs/data/joy/components/menu/GroupMenu.js +++ b/docs/data/joy/components/menu/GroupMenu.js @@ -41,7 +41,7 @@ export default function BasicMenu() { open={open} onClose={handleClose} aria-labelledby="group-demo-button" - sx={{ minWidth: 160, '--List-decorator-width': '24px' }} + sx={{ minWidth: 160, '--List-decorator-size': '24px' }} > { diff --git a/docs/data/joy/components/radio/RadioPositionEnd.js b/docs/data/joy/components/radio/RadioPositionEnd.js index e1a11471836171..03b087942570f6 100644 --- a/docs/data/joy/components/radio/RadioPositionEnd.js +++ b/docs/data/joy/components/radio/RadioPositionEnd.js @@ -17,7 +17,7 @@ export default function RadioPositionEnd() { '--List-gap': '0.5rem', '--List-item-paddingY': '1rem', '--List-item-radius': '8px', - '--List-decorator-width': '32px', + '--List-decorator-size': '32px', [`& .${radioClasses.root}`]: { flexGrow: 1, flexDirection: 'row-reverse', diff --git a/docs/data/joy/components/select/SelectCustomOption.js b/docs/data/joy/components/select/SelectCustomOption.js index 398095d1316ca4..fa6d4582c70fb6 100644 --- a/docs/data/joy/components/select/SelectCustomOption.js +++ b/docs/data/joy/components/select/SelectCustomOption.js @@ -12,12 +12,12 @@ export default function SelectCustomOption() { componentsProps={{ listbox: { sx: { - '--List-decorator-width': '44px', + '--List-decorator-size': '44px', }, }, }} sx={{ - '--List-decorator-width': '44px', + '--List-decorator-size': '44px', minWidth: 240, }} > diff --git a/docs/data/joy/components/select/SelectCustomValueAppearance.js b/docs/data/joy/components/select/SelectCustomValueAppearance.js index 9b3775b9d43dc3..b829eb7b1b0903 100644 --- a/docs/data/joy/components/select/SelectCustomValueAppearance.js +++ b/docs/data/joy/components/select/SelectCustomValueAppearance.js @@ -24,7 +24,7 @@ export default function SelectCustomValueAppearance() { componentsProps={{ listbox: { sx: { - '--List-decorator-width': '48px', + '--List-decorator-size': '48px', }, }, }} diff --git a/docs/data/joy/components/select/SelectGroupedOptions.js b/docs/data/joy/components/select/SelectGroupedOptions.js index 90e53edacd29f1..5ad34fd4494d01 100644 --- a/docs/data/joy/components/select/SelectGroupedOptions.js +++ b/docs/data/joy/components/select/SelectGroupedOptions.js @@ -43,7 +43,7 @@ export default function SelectGroupedOptions() { diff --git a/docs/data/joy/components/tabs/TabsBottomNavExample.js b/docs/data/joy/components/tabs/TabsBottomNavExample.js index dc9ccfb0984b58..96cea58e69afe7 100644 --- a/docs/data/joy/components/tabs/TabsBottomNavExample.js +++ b/docs/data/joy/components/tabs/TabsBottomNavExample.js @@ -9,7 +9,7 @@ import FavoriteBorder from '@mui/icons-material/FavoriteBorder'; import Search from '@mui/icons-material/Search'; import Person from '@mui/icons-material/Person'; -export default function TabsBasic() { +export default function TabsBottomNavExample() { const [index, setIndex] = React.useState(0); const colors = ['primary', 'info', 'danger', 'success']; return ( @@ -43,34 +43,45 @@ export default function TabsBasic() { transition: '0.3s', fontWeight: 'lg', flex: 1, - flexDirection: 'column', [`&:not(.${tabClasses.selected}):not(:hover)`]: { opacity: 0.72, }, }, })} > - - - + + + Home - - + + Likes - - + + Search - - + + Profile diff --git a/docs/data/joy/components/tabs/TabsBottomNavExample.tsx b/docs/data/joy/components/tabs/TabsBottomNavExample.tsx index 139fc32fcb9650..7b0a080e6a2253 100644 --- a/docs/data/joy/components/tabs/TabsBottomNavExample.tsx +++ b/docs/data/joy/components/tabs/TabsBottomNavExample.tsx @@ -9,7 +9,7 @@ import FavoriteBorder from '@mui/icons-material/FavoriteBorder'; import Search from '@mui/icons-material/Search'; import Person from '@mui/icons-material/Person'; -export default function TabsBasic() { +export default function TabsBottomNavExample() { const [index, setIndex] = React.useState(0); const colors = ['primary', 'info', 'danger', 'success'] as const; return ( @@ -43,34 +43,45 @@ export default function TabsBasic() { transition: '0.3s', fontWeight: 'lg', flex: 1, - flexDirection: 'column', [`&:not(.${tabClasses.selected}):not(:hover)`]: { opacity: 0.72, }, }, })} > - - - + + + Home - - + + Likes - - + + Search - - + + Profile diff --git a/docs/data/joy/components/tabs/TabsIconWithText.js b/docs/data/joy/components/tabs/TabsIconWithText.js index 503f818dddf439..d797bf3cc799f9 100644 --- a/docs/data/joy/components/tabs/TabsIconWithText.js +++ b/docs/data/joy/components/tabs/TabsIconWithText.js @@ -9,27 +9,51 @@ import PersonPinIcon from '@mui/icons-material/PersonPin'; export default function TabsIconWithText() { return ( - - - - - - - Recents - - - - - - Favorite - - - - - - Nearby - - - +
+ + + + + + + Recents + + + + + + Favorite + + + + + + Nearby + + + + + + + + + + Recents + + + + + + Favorite + + + + + + Nearby + + + +
); } diff --git a/docs/data/joy/components/tabs/TabsIconWithText.tsx b/docs/data/joy/components/tabs/TabsIconWithText.tsx index 503f818dddf439..d797bf3cc799f9 100644 --- a/docs/data/joy/components/tabs/TabsIconWithText.tsx +++ b/docs/data/joy/components/tabs/TabsIconWithText.tsx @@ -9,27 +9,51 @@ import PersonPinIcon from '@mui/icons-material/PersonPin'; export default function TabsIconWithText() { return ( - - - - - - - Recents - - - - - - Favorite - - - - - - Nearby - - - +
+ + + + + + + Recents + + + + + + Favorite + + + + + + Nearby + + + + + + + + + + Recents + + + + + + Favorite + + + + + + Nearby + + + +
); } diff --git a/docs/data/joy/getting-started/templates/email/components/Navigation.tsx b/docs/data/joy/getting-started/templates/email/components/Navigation.tsx index 96f7552f84afe4..eeb03876d6ae7b 100644 --- a/docs/data/joy/getting-started/templates/email/components/Navigation.tsx +++ b/docs/data/joy/getting-started/templates/email/components/Navigation.tsx @@ -132,7 +132,7 @@ export default function EmailNav() { aria-labelledby="nav-list-tags" size="sm" sx={{ - '--List-decorator-width': '32px', + '--List-decorator-size': '32px', '& .JoyListItemButton-root': { p: '8px' }, }} > diff --git a/docs/data/joy/getting-started/templates/files/components/Navigation.tsx b/docs/data/joy/getting-started/templates/files/components/Navigation.tsx index 5433eda307be2b..2bffd5bf5358d1 100644 --- a/docs/data/joy/getting-started/templates/files/components/Navigation.tsx +++ b/docs/data/joy/getting-started/templates/files/components/Navigation.tsx @@ -114,7 +114,7 @@ export default function Navigation() { aria-labelledby="nav-list-tags" size="sm" sx={{ - '--List-decorator-width': '32px', + '--List-decorator-size': '32px', '& .JoyListItemButton-root': { p: '8px' }, }} > diff --git a/docs/data/joy/getting-started/templates/team/App.tsx b/docs/data/joy/getting-started/templates/team/App.tsx index 7eed217858b6cf..2aaf832ec1935e 100644 --- a/docs/data/joy/getting-started/templates/team/App.tsx +++ b/docs/data/joy/getting-started/templates/team/App.tsx @@ -443,7 +443,7 @@ export default function TeamExample() {
- + ({ }, listbox: { sx: { - '--List-decorator-width': '24px', + '--List-decorator-size': '24px', }, }, }} diff --git a/packages/mui-joy/src/Link/Link.tsx b/packages/mui-joy/src/Link/Link.tsx index 30e88ba4003d15..0a37b099c35423 100644 --- a/packages/mui-joy/src/Link/Link.tsx +++ b/packages/mui-joy/src/Link/Link.tsx @@ -57,7 +57,7 @@ const LinkRoot = styled('a', { name: 'JoyLink', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: LinkProps }>(({ theme, ownerState }) => { +})<{ ownerState: LinkProps & { nested: boolean } }>(({ theme, ownerState }) => { return [ { '--Icon-fontSize': '1.25em', @@ -98,7 +98,9 @@ const LinkRoot = styled('a', { ...(ownerState.variant ? { paddingInline: '0.25em', // better than left, right because it also works with writing mode. - marginInline: '-0.25em', + ...(!ownerState.nested && { + marginInline: '-0.25em', + }), } : { color: `rgba(${theme.vars.palette[ownerState.color!]?.mainChannel} / 1)`, diff --git a/packages/mui-joy/src/List/List.tsx b/packages/mui-joy/src/List/List.tsx index 2565e431ddb2d1..c94a99a7980f64 100644 --- a/packages/mui-joy/src/List/List.tsx +++ b/packages/mui-joy/src/List/List.tsx @@ -46,7 +46,7 @@ export const ListRoot = styled('ul', { '--List-item-paddingY': '0.25rem', '--List-item-paddingX': '0.5rem', '--List-item-fontSize': theme.vars.fontSize.sm, - '--List-decorator-width': ownerState.orientation === 'horizontal' ? '1.5rem' : '2rem', + '--List-decorator-size': ownerState.orientation === 'horizontal' ? '1.5rem' : '2rem', '--Icon-fontSize': '1.125rem', }; } @@ -57,7 +57,7 @@ export const ListRoot = styled('ul', { '--List-item-paddingY': '0.375rem', '--List-item-paddingX': '0.75rem', '--List-item-fontSize': theme.vars.fontSize.md, - '--List-decorator-width': ownerState.orientation === 'horizontal' ? '1.75rem' : '2.5rem', + '--List-decorator-size': ownerState.orientation === 'horizontal' ? '1.75rem' : '2.5rem', '--Icon-fontSize': '1.25rem', }; } @@ -68,7 +68,7 @@ export const ListRoot = styled('ul', { '--List-item-paddingY': '0.5rem', '--List-item-paddingX': '1rem', '--List-item-fontSize': theme.vars.fontSize.md, - '--List-decorator-width': ownerState.orientation === 'horizontal' ? '2.25rem' : '3rem', + '--List-decorator-size': ownerState.orientation === 'horizontal' ? '2.25rem' : '3rem', '--Icon-fontSize': '1.5rem', }; } diff --git a/packages/mui-joy/src/ListDivider/ListDivider.tsx b/packages/mui-joy/src/ListDivider/ListDivider.tsx index 812f0164b8b97d..42bfaeb3109b31 100644 --- a/packages/mui-joy/src/ListDivider/ListDivider.tsx +++ b/packages/mui-joy/src/ListDivider/ListDivider.tsx @@ -23,13 +23,15 @@ const ListDividerRoot = styled('li', { overridesResolver: (props, styles) => styles.root, })<{ ownerState: ListDividerProps & { - orientation: 'horizontal' | 'vertical'; + parentOrientation: 'horizontal' | 'vertical'; 'data-first-child'?: boolean; }; }>(({ theme, ownerState }) => ({ border: 'none', // reset the border for `hr` tag - ...(ownerState.orientation === 'horizontal' && { - borderInlineStart: '1px solid', + listStyle: 'none', + backgroundColor: theme.vars.palette.divider, // use logical size + background is better than border because they work with gradient. + ...(ownerState.parentOrientation === 'horizontal' && { + inlineSize: 'var(--ListDivider-thickness, 1px)', marginBlock: ownerState.inset === 'gutter' ? 'var(--List-item-paddingY)' : 0, marginInline: 'var(--List-divider-gap)', ...(ownerState['data-first-child'] === undefined && { @@ -37,7 +39,7 @@ const ListDividerRoot = styled('li', { marginInlineStart: 'calc(var(--List-gap) + var(--List-divider-gap))', }), }), - ...(ownerState.orientation !== 'horizontal' && { + ...(ownerState.parentOrientation !== 'horizontal' && { // by default, the divider line is stretched from edge-to-edge of the List // spacing between ListItem can be controlled by `--List-divider-gap` on the List ...(ownerState['data-first-child'] === undefined && { @@ -54,12 +56,10 @@ const ListDividerRoot = styled('li', { marginInlineStart: 'var(--List-item-paddingLeft)', }), ...(ownerState.inset === 'startContent' && { - marginInlineStart: 'calc(var(--List-item-paddingLeft) + var(--List-decorator-width))', + marginInlineStart: 'calc(var(--List-item-paddingLeft) + var(--List-decorator-size))', }), - borderBlockEnd: '1px solid', + blockSize: 'var(--ListDivider-thickness, 1px)', }), - borderColor: theme.vars.palette.divider, - listStyle: 'none', })); const ListDivider = React.forwardRef(function ListDivider(inProps, ref) { @@ -68,13 +68,13 @@ const ListDivider = React.forwardRef(function ListDivider(inProps, ref) { name: 'JoyListDivider', }); - const orientation = React.useContext(ListOrientationContext); + const parentOrientation = React.useContext(ListOrientationContext); const { component, className, children, inset, role = 'separator', ...other } = props; const ownerState = { inset, - orientation, + parentOrientation, ...props, }; @@ -88,7 +88,7 @@ const ListDivider = React.forwardRef(function ListDivider(inProps, ref) { ownerState={ownerState} role={role} {...(role === 'separator' && - orientation === 'horizontal' && { + parentOrientation === 'horizontal' && { // The implicit aria-orientation of separator is 'horizontal' // https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/separator_role 'aria-orientation': 'vertical', diff --git a/packages/mui-joy/src/ListItemButton/ListItemButton.tsx b/packages/mui-joy/src/ListItemButton/ListItemButton.tsx index 4edc7c5335f77e..0eab34edeb3116 100644 --- a/packages/mui-joy/src/ListItemButton/ListItemButton.tsx +++ b/packages/mui-joy/src/ListItemButton/ListItemButton.tsx @@ -12,6 +12,7 @@ import { } from './ListItemButtonProps'; import listItemButtonClasses, { getListItemButtonUtilityClass } from './listItemButtonClasses'; import ListOrientationContext from '../List/ListOrientationContext'; +import ListItemButtonOrientationContext from './ListItemButtonOrientationContext'; const useUtilityClasses = (ownerState: ListItemButtonProps & { focusVisible: boolean }) => { const { color, disabled, focusVisible, focusVisibleClassName, selected, variant } = ownerState; @@ -43,7 +44,7 @@ export const ListItemButtonRoot = styled('div', { overridesResolver: (props, styles) => styles.root, })<{ ownerState: ListItemButtonProps & { - orientation: 'horizontal' | 'vertical'; + parentOrientation: 'horizontal' | 'vertical'; 'data-first-child'?: string; }; }>(({ theme, ownerState }) => [ @@ -54,6 +55,7 @@ export const ListItemButtonRoot = styled('div', { boxSizing: 'border-box', position: 'relative', display: 'flex', + flexDirection: ownerState.orientation === 'vertical' ? 'column' : 'row', alignItems: 'center', textAlign: 'initial', textDecoration: 'initial', // reset native anchor tag @@ -62,8 +64,10 @@ export const ListItemButtonRoot = styled('div', { marginInline: 'var(--List-itemButton-marginInline)', marginBlock: 'var(--List-itemButton-marginBlock)', ...(ownerState['data-first-child'] === undefined && { - marginInlineStart: ownerState.orientation === 'horizontal' ? 'var(--List-gap)' : undefined, - marginBlockStart: ownerState.orientation === 'horizontal' ? undefined : 'var(--List-gap)', + marginInlineStart: + ownerState.parentOrientation === 'horizontal' ? 'var(--List-gap)' : undefined, + marginBlockStart: + ownerState.parentOrientation === 'horizontal' ? undefined : 'var(--List-gap)', }), // account for the border width, so that all of the ListItemButtons content aligned horizontally paddingBlock: 'calc(var(--List-item-paddingY) - var(--variant-borderWidth))', @@ -75,7 +79,7 @@ export const ListItemButtonRoot = styled('div', { minBlockSize: 'var(--List-item-minHeight)', border: 'none', borderRadius: 'var(--List-item-radius)', - flex: ownerState.orientation === 'horizontal' ? 'none' : 1, + flex: ownerState.parentOrientation === 'horizontal' ? 'none' : 1, minInlineSize: 0, // TODO: discuss the transition approach in a separate PR. This value is copied from mui-material Button. transition: @@ -102,13 +106,14 @@ const ListItemButton = React.forwardRef(function ListItemButton(inProps, ref) { name: 'JoyListItemButton', }); - const orientation = React.useContext(ListOrientationContext); + const parentOrientation = React.useContext(ListOrientationContext); const { children, className, action, component = 'div', + orientation = 'horizontal', role, selected = false, color = selected ? 'primary' : 'neutral', @@ -141,6 +146,7 @@ const ListItemButton = React.forwardRef(function ListItemButton(inProps, ref) { color, focusVisible, orientation, + parentOrientation, selected, variant, }; @@ -150,16 +156,18 @@ const ListItemButton = React.forwardRef(function ListItemButton(inProps, ref) { const rootProps = getRootProps(); return ( - - {children} - + + + {children} + + ); }) as ExtendListItemButton; @@ -224,6 +232,11 @@ ListItemButton.propTypes /* remove-proptypes */ = { * if needed. */ focusVisibleClassName: PropTypes.string, + /** + * The content direction flow. + * @default 'horizontal' + */ + orientation: PropTypes.oneOf(['horizontal', 'vertical']), /** * @ignore */ diff --git a/packages/mui-joy/src/ListItemButton/ListItemButtonOrientationContext.ts b/packages/mui-joy/src/ListItemButton/ListItemButtonOrientationContext.ts new file mode 100644 index 00000000000000..94065dbc891508 --- /dev/null +++ b/packages/mui-joy/src/ListItemButton/ListItemButtonOrientationContext.ts @@ -0,0 +1,7 @@ +import * as React from 'react'; + +const ListItemButtonOrientationContext = React.createContext<'horizontal' | 'vertical'>( + 'horizontal', +); + +export default ListItemButtonOrientationContext; diff --git a/packages/mui-joy/src/ListItemButton/ListItemButtonProps.ts b/packages/mui-joy/src/ListItemButton/ListItemButtonProps.ts index e178b9014127fa..87c2cdc95ad1f8 100644 --- a/packages/mui-joy/src/ListItemButton/ListItemButtonProps.ts +++ b/packages/mui-joy/src/ListItemButton/ListItemButtonProps.ts @@ -55,6 +55,11 @@ export interface ListItemButtonTypeMap

{ const slots = { @@ -19,13 +20,21 @@ const ListItemDecoratorRoot = styled('span', { name: 'JoyListItemDecorator', slot: 'Root', overridesResolver: (props, styles) => styles.root, -})<{ ownerState: ListItemDecoratorProps }>({ - boxSizing: 'border-box', - display: 'inline-flex', - alignItems: 'center', - color: `var(--List-decorator-color)`, - minInlineSize: 'var(--List-decorator-width)', -}); +})<{ ownerState: ListItemDecoratorProps & { parentOrientation?: 'horizontal' | 'vertical' } }>( + ({ ownerState }) => ({ + boxSizing: 'border-box', + display: 'inline-flex', + alignItems: 'center', + color: `var(--List-decorator-color)`, + ...(ownerState.parentOrientation === 'horizontal' + ? { + minInlineSize: 'var(--List-decorator-size)', + } + : { + minBlockSize: 'var(--List-decorator-size)', + }), + }), +); const ListItemDecorator = React.forwardRef(function ListItemDecorator(inProps, ref) { const props = useThemeProps({ @@ -34,8 +43,10 @@ const ListItemDecorator = React.forwardRef(function ListItemDecorator(inProps, r }); const { component, className, children, ...other } = props; + const parentOrientation = React.useContext(ListItemButtonOrientationContext); const ownerState = { + parentOrientation, ...props, }; diff --git a/packages/mui-joy/src/MenuItem/MenuItem.tsx b/packages/mui-joy/src/MenuItem/MenuItem.tsx index bc578e9b3545b3..24d0997a53c320 100644 --- a/packages/mui-joy/src/MenuItem/MenuItem.tsx +++ b/packages/mui-joy/src/MenuItem/MenuItem.tsx @@ -34,7 +34,7 @@ const MenuItem = React.forwardRef(function MenuItem(inProps, ref) { name: 'JoyMenuItem', }); - const orientation = React.useContext(ListOrientationContext); + const parentOrientation = React.useContext(ListOrientationContext); const { children, @@ -58,7 +58,7 @@ const MenuItem = React.forwardRef(function MenuItem(inProps, ref) { disabled, focusVisible, selected, - orientation, + parentOrientation, variant, }; diff --git a/packages/mui-joy/src/Option/Option.tsx b/packages/mui-joy/src/Option/Option.tsx index ef85789e4a2d67..b23f5057ac3219 100644 --- a/packages/mui-joy/src/Option/Option.tsx +++ b/packages/mui-joy/src/Option/Option.tsx @@ -49,7 +49,7 @@ const Option = React.forwardRef(function Option(inProps, ref) { ...other } = props; - const orientation = React.useContext(ListOrientationContext); + const parentOrientation = React.useContext(ListOrientationContext); const selectContext = React.useContext(SelectUnstyledContext) as SelectUnstyledContextType & { color: ColorPaletteProp; }; @@ -81,7 +81,7 @@ const Option = React.forwardRef(function Option(inProps, ref) { component, variant, color, - orientation, + parentOrientation, }; const optionRef = React.useRef(null); diff --git a/packages/mui-joy/src/Tab/Tab.tsx b/packages/mui-joy/src/Tab/Tab.tsx index 14cfe7f5006a2a..0e4f26b234ed55 100644 --- a/packages/mui-joy/src/Tab/Tab.tsx +++ b/packages/mui-joy/src/Tab/Tab.tsx @@ -11,13 +11,15 @@ import styled from '../styles/styled'; import { getTabUtilityClass } from './tabClasses'; import { TabOwnerState, TabTypeMap } from './TabProps'; import ListOrientationContext from '../List/ListOrientationContext'; +import ListItemButtonOrientationContext from '../ListItemButton/ListItemButtonOrientationContext'; const useUtilityClasses = (ownerState: TabOwnerState) => { - const { selected, disabled, focusVisible, variant, color } = ownerState; + const { selected, disabled, focusVisible, variant, color, orientation } = ownerState; const slots = { root: [ 'root', + orientation, disabled && 'disabled', focusVisible && 'focusVisible', selected && 'selected', @@ -57,7 +59,7 @@ const Tab = React.forwardRef(function Tab(inProps, ref) { name: 'JoyTab', }); - const orientation = React.useContext(ListOrientationContext); + const parentOrientation = React.useContext(ListOrientationContext); const { action, @@ -68,6 +70,7 @@ const Tab = React.forwardRef(function Tab(inProps, ref) { onClick, onFocus, component = 'button', + orientation = 'horizontal', variant = 'plain', color = 'neutral', ...other @@ -95,6 +98,7 @@ const Tab = React.forwardRef(function Tab(inProps, ref) { const ownerState = { ...props, orientation, + parentOrientation, active, focusVisible, disabled, @@ -118,8 +122,12 @@ const Tab = React.forwardRef(function Tab(inProps, ref) { className: classes.root, }); - // @ts-ignore `onChange` is conflicted - return {children}; + return ( + + {/* @ts-ignore ListItemButton base is div which conflict with TabProps 'button' */} + {children} + + ); }) as OverridableComponent; Tab.propTypes /* remove-proptypes */ = { @@ -172,6 +180,11 @@ Tab.propTypes /* remove-proptypes */ = { * @ignore */ onFocus: PropTypes.func, + /** + * The content direction flow. + * @default 'horizontal' + */ + orientation: PropTypes.oneOf(['horizontal', 'vertical']), /** * The system prop that allows defining system overrides as well as additional CSS styles. */ diff --git a/packages/mui-joy/src/Tab/TabProps.ts b/packages/mui-joy/src/Tab/TabProps.ts index ade4a64a30c1a1..41ef321cdc1aa7 100644 --- a/packages/mui-joy/src/Tab/TabProps.ts +++ b/packages/mui-joy/src/Tab/TabProps.ts @@ -26,6 +26,11 @@ export interface TabTypeMap

{ * @default false */ disabled?: boolean; + /** + * The content direction flow. + * @default 'horizontal' + */ + orientation?: 'horizontal' | 'vertical'; /** * The system prop that allows defining system overrides as well as additional CSS styles. */