diff --git a/docs/data/joy/components/aspect-ratio/BasicRatio.js b/docs/data/joy/components/aspect-ratio/BasicRatio.js index 9c10fa103820a7..c2ae28be1840d5 100644 --- a/docs/data/joy/components/aspect-ratio/BasicRatio.js +++ b/docs/data/joy/components/aspect-ratio/BasicRatio.js @@ -10,12 +10,7 @@ export default function BasicRatio() { sx={{ width: 300, borderRadius: 'md', overflow: 'auto' }} > - - 16 : 9 - + 16 : 9 ); diff --git a/docs/data/joy/components/aspect-ratio/BasicRatio.tsx b/docs/data/joy/components/aspect-ratio/BasicRatio.tsx new file mode 100644 index 00000000000000..c2ae28be1840d5 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/BasicRatio.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Sheet from '@mui/joy/Sheet'; +import Typography from '@mui/joy/Typography'; + +export default function BasicRatio() { + return ( + + + 16 : 9 + + + ); +} diff --git a/docs/data/joy/components/aspect-ratio/BasicRatio.tsx.preview b/docs/data/joy/components/aspect-ratio/BasicRatio.tsx.preview new file mode 100644 index 00000000000000..99d41fc16606d2 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/BasicRatio.tsx.preview @@ -0,0 +1,8 @@ + + + 16 : 9 + + \ No newline at end of file diff --git a/docs/data/joy/components/aspect-ratio/CarouselRatio.js b/docs/data/joy/components/aspect-ratio/CarouselRatio.js index eb6fcb42bca6fa..ab891b9c0a5e77 100644 --- a/docs/data/joy/components/aspect-ratio/CarouselRatio.js +++ b/docs/data/joy/components/aspect-ratio/CarouselRatio.js @@ -2,7 +2,7 @@ import * as React from 'react'; import AspectRatio from '@mui/joy/AspectRatio'; import Box from '@mui/joy/Box'; import Typography from '@mui/joy/Typography'; -import Sheet from '@mui/joy/Sheet'; +import Card from '@mui/joy/Card'; const data = [ { @@ -28,6 +28,7 @@ export default function FlexRowRatio() { sx={{ display: 'flex', gap: 1, + py: 1, overflow: 'auto', width: 343, scrollSnapType: 'x mandatory', @@ -38,15 +39,13 @@ export default function FlexRowRatio() { }} > {data.map((item) => ( - theme.spacing(2), }} > {item.title} {item.description} - + ))} ); diff --git a/docs/data/joy/components/aspect-ratio/CarouselRatio.tsx b/docs/data/joy/components/aspect-ratio/CarouselRatio.tsx new file mode 100644 index 00000000000000..ab891b9c0a5e77 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/CarouselRatio.tsx @@ -0,0 +1,65 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Box from '@mui/joy/Box'; +import Typography from '@mui/joy/Typography'; +import Card from '@mui/joy/Card'; + +const data = [ + { + src: 'https://images.unsplash.com/photo-1502657877623-f66bf489d236?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2369', + title: 'Night view', + description: '4.21M views', + }, + { + src: 'https://images.unsplash.com/photo-1527549993586-dff825b37782?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3270', + title: 'Lake view', + description: '4.74M views', + }, + { + src: 'https://images.unsplash.com/photo-1532614338840-ab30cf10ed36?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3270', + title: 'Mountain view', + description: '3.98M views', + }, +]; + +export default function FlexRowRatio() { + return ( + *': { + scrollSnapAlign: 'center', + }, + '::-webkit-scrollbar': { display: 'none' }, + }} + > + {data.map((item) => ( + theme.spacing(2), + }} + > + + {item.title} + + + {item.title} + {item.description} + + + ))} + + ); +} diff --git a/docs/data/joy/components/aspect-ratio/CustomRatio.js b/docs/data/joy/components/aspect-ratio/CustomRatio.js index 97bfcd129ecc7e..38c9b727cf3533 100644 --- a/docs/data/joy/components/aspect-ratio/CustomRatio.js +++ b/docs/data/joy/components/aspect-ratio/CustomRatio.js @@ -10,12 +10,7 @@ export default function CustomRatio() { sx={{ width: 300, borderRadius: 'md', overflow: 'auto' }} > - - 4 : 3 - + 4 : 3 ); diff --git a/docs/data/joy/components/aspect-ratio/CustomRatio.tsx b/docs/data/joy/components/aspect-ratio/CustomRatio.tsx new file mode 100644 index 00000000000000..38c9b727cf3533 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/CustomRatio.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Sheet from '@mui/joy/Sheet'; +import Typography from '@mui/joy/Typography'; + +export default function CustomRatio() { + return ( + + + 4 : 3 + + + ); +} diff --git a/docs/data/joy/components/aspect-ratio/CustomRatio.tsx.preview b/docs/data/joy/components/aspect-ratio/CustomRatio.tsx.preview new file mode 100644 index 00000000000000..2b2b4405e41aaa --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/CustomRatio.tsx.preview @@ -0,0 +1,8 @@ + + + 4 : 3 + + \ No newline at end of file diff --git a/docs/data/joy/components/aspect-ratio/FlexRowRatio.js b/docs/data/joy/components/aspect-ratio/FlexRowRatio.js index 79b4b81e7fdaba..bcd4dba8bedec4 100644 --- a/docs/data/joy/components/aspect-ratio/FlexRowRatio.js +++ b/docs/data/joy/components/aspect-ratio/FlexRowRatio.js @@ -44,7 +44,7 @@ export default function FlexRowRatio() { endDecorator="px" type="number" value={flexBasis} - onChange={(event) => setFlexBasis(event.target.value)} + onChange={(event) => setFlexBasis(event.target.valueAsNumber)} sx={{ mx: 'auto', width: '100%' }} /> diff --git a/docs/data/joy/components/aspect-ratio/FlexRowRatio.tsx b/docs/data/joy/components/aspect-ratio/FlexRowRatio.tsx new file mode 100644 index 00000000000000..bcd4dba8bedec4 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/FlexRowRatio.tsx @@ -0,0 +1,52 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Box from '@mui/joy/Box'; +import TextField from '@mui/joy/TextField'; +import Typography from '@mui/joy/Typography'; +import Sheet from '@mui/joy/Sheet'; + +export default function FlexRowRatio() { + const [flexBasis, setFlexBasis] = React.useState(200); + return ( + + + + + + + Yosemite National Park + California, USA + + +
+ setFlexBasis(event.target.valueAsNumber)} + sx={{ mx: 'auto', width: '100%' }} + /> +
+ ); +} diff --git a/docs/data/joy/components/aspect-ratio/ListStackRatio.js b/docs/data/joy/components/aspect-ratio/ListStackRatio.js index 00b53852af1832..f6fd806102bba3 100644 --- a/docs/data/joy/components/aspect-ratio/ListStackRatio.js +++ b/docs/data/joy/components/aspect-ratio/ListStackRatio.js @@ -7,7 +7,6 @@ import ListDivider from '@mui/joy/ListDivider'; import ListItem from '@mui/joy/ListItem'; import ListItemContent from '@mui/joy/ListItemContent'; import ListItemButton from '@mui/joy/ListItemButton'; -import ListItemDecorator from '@mui/joy/ListItemDecorator'; const data = [ { @@ -39,23 +38,16 @@ export default function FlexRowRatio() { borderRadius: 'sm', }} > - + {data.map((item, index) => ( - - - {item.title} - - + + {item.title} + {item.title} {item.description} diff --git a/docs/data/joy/components/aspect-ratio/ListStackRatio.tsx b/docs/data/joy/components/aspect-ratio/ListStackRatio.tsx new file mode 100644 index 00000000000000..f6fd806102bba3 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/ListStackRatio.tsx @@ -0,0 +1,63 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Typography from '@mui/joy/Typography'; +import Sheet from '@mui/joy/Sheet'; +import List from '@mui/joy/List'; +import ListDivider from '@mui/joy/ListDivider'; +import ListItem from '@mui/joy/ListItem'; +import ListItemContent from '@mui/joy/ListItemContent'; +import ListItemButton from '@mui/joy/ListItemButton'; + +const data = [ + { + src: 'https://images.unsplash.com/photo-1502657877623-f66bf489d236?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2369', + title: 'Night view', + description: '4.21M views', + }, + { + src: 'https://images.unsplash.com/photo-1527549993586-dff825b37782?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3270', + title: 'Lake view', + description: '4.74M views', + }, + { + src: 'https://images.unsplash.com/photo-1532614338840-ab30cf10ed36?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=3270', + title: 'Mountain view', + description: '3.98M views', + }, +]; + +export default function FlexRowRatio() { + return ( + + + {data.map((item, index) => ( + + + + + {item.title} + + + {item.title} + {item.description} + + + + {index !== data.length - 1 && } + + ))} + + + ); +} diff --git a/docs/data/joy/components/aspect-ratio/MediaRatio.tsx b/docs/data/joy/components/aspect-ratio/MediaRatio.tsx new file mode 100644 index 00000000000000..d956c9376f3b52 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/MediaRatio.tsx @@ -0,0 +1,20 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Box from '@mui/joy/Box'; +import Typography from '@mui/joy/Typography'; + +export default function MediaRatio() { + return ( + + + + + + An example of using contain value + + + ); +} diff --git a/docs/data/joy/components/aspect-ratio/MediaRatio.tsx.preview b/docs/data/joy/components/aspect-ratio/MediaRatio.tsx.preview new file mode 100644 index 00000000000000..e5e2bb1ec21d08 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/MediaRatio.tsx.preview @@ -0,0 +1,9 @@ + + + + + An example of using contain value + \ No newline at end of file diff --git a/docs/data/joy/components/aspect-ratio/MinMaxRatio.tsx b/docs/data/joy/components/aspect-ratio/MinMaxRatio.tsx new file mode 100644 index 00000000000000..9fc4ecbc2ba325 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/MinMaxRatio.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Box from '@mui/joy/Box'; + +export default function MinMaxRatio() { + return ( + + + + + + ); +} diff --git a/docs/data/joy/components/aspect-ratio/MinMaxRatio.tsx.preview b/docs/data/joy/components/aspect-ratio/MinMaxRatio.tsx.preview new file mode 100644 index 00000000000000..d5360c914165a2 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/MinMaxRatio.tsx.preview @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.js b/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.js new file mode 100644 index 00000000000000..c2d400d6524f7e --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.js @@ -0,0 +1,19 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Card from '@mui/joy/Card'; +import Typography from '@mui/joy/Typography'; +import ImageIcon from '@mui/icons-material/Image'; + +export default function BasicRatio() { + return ( + + +
+ +
+
+ Title + Description of the card. +
+ ); +} diff --git a/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.tsx b/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.tsx new file mode 100644 index 00000000000000..c2d400d6524f7e --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import AspectRatio from '@mui/joy/AspectRatio'; +import Card from '@mui/joy/Card'; +import Typography from '@mui/joy/Typography'; +import ImageIcon from '@mui/icons-material/Image'; + +export default function BasicRatio() { + return ( + + +
+ +
+
+ Title + Description of the card. +
+ ); +} diff --git a/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.tsx.preview b/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.tsx.preview new file mode 100644 index 00000000000000..8223dc3397f104 --- /dev/null +++ b/docs/data/joy/components/aspect-ratio/PlaceholderAspectRatio.tsx.preview @@ -0,0 +1,9 @@ + + +
+ +
+
+ Title + Description of the card. +
\ No newline at end of file diff --git a/docs/data/joy/components/aspect-ratio/aspect-ratio.md b/docs/data/joy/components/aspect-ratio/aspect-ratio.md index 1017539399b287..343975ae5c98ff 100644 --- a/docs/data/joy/components/aspect-ratio/aspect-ratio.md +++ b/docs/data/joy/components/aspect-ratio/aspect-ratio.md @@ -35,6 +35,12 @@ It has `object-fit: cover` by default. {{"demo": "MediaRatio.js"}} +## Placeholder + +When the media does not exist, you can render a placeholder inside an aspect ratio component. Wrap the placeholder with a `
` or `Box` component to center the content. + +{{"demo": "PlaceholderAspectRatio.js"}} + ## Controlling the height Use `minHeight` and `maxHeight` to set the lower and upper bound of the component's height. @@ -48,6 +54,31 @@ When the aspect ratio component is placed as a child of a flexbox `row` containe {{"demo": "FlexRowRatio.js"}} +## Integration + +### Next.js Image + +The `AspectRatio` component can be used with [Next.js Image](https://nextjs.org/docs/basic-features/image-optimization) component. + +```js +import Image from 'next/image'; +import AspectRatio from '@mui/joy/AspectRatio'; +import mountains from '../public/mountains.jpg'; + +function App() { + return ( + + {/* only layout="fill" makes sense for using with AspectRatio */} + Mountains + + ); +} +``` + +:::info +Always use `layout="fill"` on the image component, otherwise you don't need to use aspect ratio because the height is based on the image. +::: + ## Common examples ### Mobile Carousel diff --git a/packages/mui-joy/src/AspectRatio/AspectRatio.tsx b/packages/mui-joy/src/AspectRatio/AspectRatio.tsx index a291861e1a0864..bac509a49835f6 100644 --- a/packages/mui-joy/src/AspectRatio/AspectRatio.tsx +++ b/packages/mui-joy/src/AspectRatio/AspectRatio.tsx @@ -59,7 +59,11 @@ const AspectRatioContent = styled('div', { paddingBottom: 'var(--AspectRatio-paddingBottom)', overflow: 'hidden', // use data-attribute instead of :first-child to support zero config SSR (emotion) - '& > [data-first-child]': { + // use nested selector for integrating with nextjs image (spans are inserted on top of the img) + '& [data-first-child]': { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', boxSizing: 'border-box', position: 'absolute', width: '100%',