From 9ade298d2647c7899d8ccab95b8cc68f4439e627 Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Wed, 13 Nov 2024 00:27:13 +0900 Subject: [PATCH 1/8] Write aspect ratio component document using joy ui component --- .../02-data-display/01-aspect-ratio.mdx | 225 ++++++++++++++++++ .../website/src/demos/aspect-ratio/Basics.tsx | 15 ++ .../demos/aspect-ratio/MediaPlaceholder.tsx | 26 ++ .../aspect-ratio/MinimumAndMaximumHeight.tsx | 19 ++ .../src/demos/aspect-ratio/ObjectFit.tsx | 19 ++ apps/website/src/demos/aspect-ratio/Ratio.tsx | 19 ++ .../src/demos/aspect-ratio/Variants.tsx | 45 ++++ apps/website/src/demos/aspect-ratio/index.ts | 6 + 8 files changed, 374 insertions(+) create mode 100644 apps/website/docs/components/02-data-display/01-aspect-ratio.mdx create mode 100644 apps/website/src/demos/aspect-ratio/Basics.tsx create mode 100644 apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx create mode 100644 apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx create mode 100644 apps/website/src/demos/aspect-ratio/ObjectFit.tsx create mode 100644 apps/website/src/demos/aspect-ratio/Ratio.tsx create mode 100644 apps/website/src/demos/aspect-ratio/Variants.tsx create mode 100644 apps/website/src/demos/aspect-ratio/index.ts diff --git a/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx b/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx new file mode 100644 index 0000000..7bf5dfc --- /dev/null +++ b/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx @@ -0,0 +1,225 @@ +--- +sidebar_position: 1 +slug: /components/aspect-ratio +--- + +import { + AspectRatioBasics, + AspectRatioVariants, + AspectRatioRatio, + AspectRatioObjectFit, + AspectRatioMediaPlaceholder, + AspectRatioMinimumAndMaximumHeight, +} from '@site/src/demos/aspect-ratio'; + +# AspectRatio + + + +The Aspect Ratio component resizes its contents to match the desired ratio. + +## Basics + +```tsx +import { AspectRatio } from 'tailwind-joy/components'; +``` + +The Aspect Ratio component wraps around the content that it resizes. +The element to be resized must be the first direct child. +The default ratio is `16/9`. + + + +```tsx +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Typography } from 'tailwind-joy/components'; + +export function AspectRatioBasics() { + return ( + + + 16/9 + + + ); +} +``` + +## Customization + +### Variants + +The Aspect Ratio component supports four variants: `solid`, `soft` (default), `outlined`, and `plain`. + + + +```tsx +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Box, Typography } from 'tailwind-joy/components'; + +export function AspectRatioVariants() { + return ( + + + + + Solid + + + + + + + Soft + + + + + + + Outlined + + + + + + + Plain + + + + + ); +} +``` + +### Ratio + +Use the `ratio` prop to change the aspect ratio, following the pattern `width/height`. +For example, the demo below uses a ratio of `4/3`, which is a common alternative to the default `16/9`: + + + +```tsx +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Typography } from 'tailwind-joy/components'; + +export function AspectRatioRatio() { + return ( + + + 4/3 + + + ); +} +``` + +### Object fit + +When the content inside the Aspect Ratio component is an image or a video, you can use the `objectFit` prop to control how it's resized. + +This prop gives you access to all of the values associated with the CSS `object-fit` property: `cover` (default), `contain`, `fill`, `scaleDown`, `initial`, `inherit`, and `none`. + + + +```tsx +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Box } from 'tailwind-joy/components'; + +export function AspectRatioObjectFit() { + return ( + + + A beautiful landscape. + + + ); +} +``` + +### Media placeholder + +Use a `
`, or a [Box](./box) component paired with an icon, as a fallback when there is no media content provided: + + + +```tsx +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import ImageIcon from '@mui/icons-material/Image'; +import { Box, Sheet, Typography } from 'tailwind-joy/components'; + +export function AspectRatioMediaPlaceholder() { + return ( + + +
+ +
+
+
+ Title + Description of the card. +
+
+ ); +} +``` + +### Minimum and maximum height + +Use the `minHeight` and `maxHeight` props to set the lower and upper bound for the height of the content. +This is useful when the Aspect Ratio component wraps dynamic-width content, as shown in the demo below: + + + +```tsx +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Box } from 'tailwind-joy/components'; + +export function AspectRatioMinimumAndMaximumHeight() { + return ( + + + + + + ); +} +``` + +## Anatomy + +The Aspect Ratio component is composed of a root `
` with a content `
` nested inside; the child component is given a `data-first-child` attribute for styling purposes: + +```html +
+
+ + + +
+
+``` + +## API + +- `` +- [``](../apis/box) +- [``](../apis/sheet) +- [``](../apis/typography) diff --git a/apps/website/src/demos/aspect-ratio/Basics.tsx b/apps/website/src/demos/aspect-ratio/Basics.tsx new file mode 100644 index 0000000..466f8a8 --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/Basics.tsx @@ -0,0 +1,15 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Typography } from 'tailwind-joy/components'; +import { DisplayStand } from '@site/src/components/docs/DisplayStand'; + +export function AspectRatioBasics() { + return ( + + + + 16/9 + + + + ); +} diff --git a/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx b/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx new file mode 100644 index 0000000..98160da --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx @@ -0,0 +1,26 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import ImageIcon from '@mui/icons-material/Image'; +import { Sheet, Typography } from 'tailwind-joy/components'; +import { DisplayStand } from '@site/src/components/docs/DisplayStand'; + +export function AspectRatioMediaPlaceholder() { + return ( + + {/* TODO: Replace Sheet with Card. */} + + +
+ +
+
+
+ Title + Description of the card. +
+
+
+ ); +} diff --git a/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx b/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx new file mode 100644 index 0000000..815fcd9 --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx @@ -0,0 +1,19 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Box } from 'tailwind-joy/components'; +import { DisplayStand } from '@site/src/components/docs/DisplayStand'; + +export function AspectRatioMinimumAndMaximumHeight() { + return ( + + + + + + + + ); +} diff --git a/apps/website/src/demos/aspect-ratio/ObjectFit.tsx b/apps/website/src/demos/aspect-ratio/ObjectFit.tsx new file mode 100644 index 0000000..047ce96 --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/ObjectFit.tsx @@ -0,0 +1,19 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Box } from 'tailwind-joy/components'; +import { DisplayStand } from '@site/src/components/docs/DisplayStand'; + +export function AspectRatioObjectFit() { + return ( + + + + A beautiful landscape. + + + + ); +} diff --git a/apps/website/src/demos/aspect-ratio/Ratio.tsx b/apps/website/src/demos/aspect-ratio/Ratio.tsx new file mode 100644 index 0000000..d2bf7a4 --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/Ratio.tsx @@ -0,0 +1,19 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Typography } from 'tailwind-joy/components'; +import { DisplayStand } from '@site/src/components/docs/DisplayStand'; + +export function AspectRatioRatio() { + return ( + + + + 4/3 + + + + ); +} diff --git a/apps/website/src/demos/aspect-ratio/Variants.tsx b/apps/website/src/demos/aspect-ratio/Variants.tsx new file mode 100644 index 0000000..7194d6b --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/Variants.tsx @@ -0,0 +1,45 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { Box, Typography } from 'tailwind-joy/components'; +import { DisplayStand } from '@site/src/components/docs/DisplayStand'; + +export function AspectRatioVariants() { + return ( + + {/* TODO: Replace Box with Grid. */} + + {/* TODO: Replace Box with Grid. */} + + + + Solid + + + + {/* TODO: Replace Box with Grid. */} + + + + Soft + + + + {/* TODO: Replace Box with Grid. */} + + + + Outlined + + + + {/* TODO: Replace Box with Grid. */} + + + + Plain + + + + + + ); +} diff --git a/apps/website/src/demos/aspect-ratio/index.ts b/apps/website/src/demos/aspect-ratio/index.ts new file mode 100644 index 0000000..6154dc2 --- /dev/null +++ b/apps/website/src/demos/aspect-ratio/index.ts @@ -0,0 +1,6 @@ +export { AspectRatioBasics } from './Basics'; +export { AspectRatioVariants } from './Variants'; +export { AspectRatioRatio } from './Ratio'; +export { AspectRatioObjectFit } from './ObjectFit'; +export { AspectRatioMediaPlaceholder } from './MediaPlaceholder'; +export { AspectRatioMinimumAndMaximumHeight } from './MinimumAndMaximumHeight'; From 256c02d58e62d0c7d760e6461583a8ac05ae5e8a Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Wed, 13 Nov 2024 23:49:26 +0900 Subject: [PATCH 2/8] Implements aspect ratio component --- packages/tailwind-joy/src/components.ts | 1 + .../src/components/AspectRatio.tsx | 240 ++++++++++++++++++ .../src/plugins/safelist-generator.ts | 2 + 3 files changed, 243 insertions(+) create mode 100644 packages/tailwind-joy/src/components/AspectRatio.tsx diff --git a/packages/tailwind-joy/src/components.ts b/packages/tailwind-joy/src/components.ts index 2417b6b..9d182ed 100644 --- a/packages/tailwind-joy/src/components.ts +++ b/packages/tailwind-joy/src/components.ts @@ -1,3 +1,4 @@ +export { AspectRatio } from './components/AspectRatio'; export { Box } from './components/Box'; export { Button } from './components/Button'; export { ButtonGroup } from './components/ButtonGroup'; diff --git a/packages/tailwind-joy/src/components/AspectRatio.tsx b/packages/tailwind-joy/src/components/AspectRatio.tsx new file mode 100644 index 0000000..dedada5 --- /dev/null +++ b/packages/tailwind-joy/src/components/AspectRatio.tsx @@ -0,0 +1,240 @@ +import { clsx } from 'clsx'; +import type { ComponentProps, ForwardedRef } from 'react'; +import { + forwardRef, + createElement, + cloneElement, + isValidElement, + Children, + useMemo, +} from 'react'; +import type { + BaseVariants, + GeneratorInput, + GenericComponentPropsWithVariants, +} from '@/base/types'; +import { twMerge } from '../base/alias'; +import { addPrefix, toVariableClass } from '../base/modifier'; +import { theme } from '../base/theme'; +import { baseTokens } from '../base/tokens'; +import { excludeClassName } from '../base/utils'; + +type AspectRatioObjectFit = + | '-moz-initial' + | 'contain' + | 'cover' + | 'fill' + | 'inherit' + | 'initial' + | 'none' + | 'revert-layer' + | 'revert' + | 'scale-down' + | 'unset'; + +function aspectRatioRootVariants( + props?: Pick & { + flex?: boolean; + }, +) { + const { color = 'neutral', variant = 'soft', flex = false } = props ?? {}; + + return twMerge( + clsx([ + 'tj-aspect-ratio-root group/tj-aspect-ratio', + '[--AspectRatio-paddingBottom:clamp(var(--AspectRatio-minHeight),calc(100%/var(--tj-AspectRatio-ratio)),var(--AspectRatio-maxHeight))]', + '[--AspectRatio-maxHeight:var(--tj-AspectRatio-maxHeight)]', + '[--AspectRatio-minHeight:var(--tj-AspectRatio-minHeight)]', + color !== 'neutral' || variant === 'solid' + ? '[--Icon-color:currentColor] dark:[--Icon-color:currentColor]' + : toVariableClass(baseTokens.text.icon, 'Icon-color'), + 'rounded-[var(--AspectRatio-radius)]', + flex ? 'flex' : 'block', + flex ? 'flex-1' : 'flex-[initial]', + 'flex-col', + 'm-[var(--AspectRatio-margin)]', + ]), + ); +} + +function aspectRatioContentVariants( + props?: Pick, +) { + const { color = 'neutral', variant = 'soft' } = props ?? {}; + + return twMerge( + clsx([ + 'tj-aspect-ratio-content', + 'flex-1', + 'relative', + 'rounded-[inherit]', + 'h-0', + 'pb-[calc(var(--AspectRatio-paddingBottom)-2*var(--variant-borderWidth,0px))]', + 'overflow-hidden', + '[transition:inherit]', + addPrefix( + clsx([ + 'flex', + 'justify-center', + 'items-center', + 'box-border', + 'absolute', + 'w-full', + 'h-full', + '[object-fit:var(--tj-AspectRatio-objectFit)]', + 'm-0', + 'p-0', + addPrefix( + clsx([ + 'w-full', + 'h-full', + '[object-fit:var(--tj-AspectRatio-objectFit)]', + ]), + '[&>img]:', + ), + ]), + '[&_[data-first-child]]:', + ), + theme.typography['body-md'].className, + theme.variants[variant][color].className, + ]), + ); +} + +type AspectRatioRootVariants = Pick & { + flex?: boolean; + maxHeight?: number | string; + minHeight?: number | string; + objectFit?: AspectRatioObjectFit; + ratio?: number | string; +} & { + slotProps?: { + root?: ComponentProps<'div'>; + content?: ComponentProps<'div'>; + }; +}; + +type AspectRatioRootProps = GenericComponentPropsWithVariants< + 'div', + AspectRatioRootVariants, + T +>; + +function AspectRatioRoot< + T extends keyof JSX.IntrinsicElements | undefined = undefined, +>( + { + // ---- non-passing props ---- + // base variants + color = 'neutral', + variant = 'soft', + + // non-base variants + className, + flex = false, + maxHeight, + minHeight, + objectFit = 'cover', + ratio = '16/9', + style, + + // slot props + slotProps = {}, + + // others + component = 'div', + children, + ...otherProps + // --------------------------- + }: AspectRatioRootProps, + ref: ForwardedRef, +) { + const slotPropsWithoutClassName = useMemo( + () => excludeClassName(slotProps), + [slotProps], + ); + + return createElement( + component, + { + ref, + className: twMerge( + aspectRatioRootVariants({ + color, + variant, + flex, + }), + className, + slotProps.root?.className ?? '', + ), + style: { + ...style, + ...(maxHeight === undefined + ? { + '--tj-AspectRatio-maxHeight': '9999px', + } + : { + '--tj-AspectRatio-maxHeight': + typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight, + }), + ...(minHeight === undefined + ? { + '--tj-AspectRatio-minHeight': '0px', + } + : { + '--tj-AspectRatio-minHeight': + typeof minHeight === 'number' ? `${minHeight}px` : minHeight, + }), + '--tj-AspectRatio-objectFit': objectFit, + '--tj-AspectRatio-ratio': ratio, + }, + ...otherProps, + ...(slotPropsWithoutClassName.root ?? {}), + }, +
+ {Children.map(children, (child, index) => { + if (!isValidElement(child)) { + return child; + } + + return cloneElement(child, { + // @ts-expect-error + 'data-first-child': index === 0 ? '' : undefined, + }); + })} +
, + ); +} + +export const AspectRatio = forwardRef(AspectRatioRoot) as < + T extends keyof JSX.IntrinsicElements | undefined = undefined, +>( + props: AspectRatioRootProps & { ref?: ForwardedRef }, +) => JSX.Element; + +export const generatorInputs: GeneratorInput[] = [ + { + generatorFn: aspectRatioRootVariants, + variants: { + color: ['primary', 'neutral', 'danger', 'success', 'warning'], + variant: ['solid', 'soft', 'outlined', 'plain'], + flex: [false, true], + }, + }, + { + generatorFn: aspectRatioContentVariants, + variants: { + color: ['primary', 'neutral', 'danger', 'success', 'warning'], + variant: ['solid', 'soft', 'outlined', 'plain'], + }, + }, +]; diff --git a/packages/tailwind-joy/src/plugins/safelist-generator.ts b/packages/tailwind-joy/src/plugins/safelist-generator.ts index 73159a1..74b9a05 100644 --- a/packages/tailwind-joy/src/plugins/safelist-generator.ts +++ b/packages/tailwind-joy/src/plugins/safelist-generator.ts @@ -1,4 +1,5 @@ import type { GeneratorInput } from '../base/types'; +import { generatorInputs as aspectRatioClassNameGeneratorInputs } from '../components/AspectRatio'; import { generatorInputs as boxClassNameGeneratorInputs } from '../components/Box'; import { generatorInputs as buttonClassNameGeneratorInputs } from '../components/Button'; import { generatorInputs as buttonGroupClassNameGeneratorInputs } from '../components/ButtonGroup'; @@ -20,6 +21,7 @@ import { generatorInputs as adaptedIconClassNameGeneratorInputs } from '../compo const SPACE = ' '; const inputs: GeneratorInput[] = [ + ...aspectRatioClassNameGeneratorInputs, ...boxClassNameGeneratorInputs, ...buttonClassNameGeneratorInputs, ...buttonGroupClassNameGeneratorInputs, From 3b34518e46f4a1c778e9c6034ce79b92bc86f7e7 Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Thu, 14 Nov 2024 23:47:47 +0900 Subject: [PATCH 3/8] Write aspect ratio test --- apps/tester/tests/06-aspect-ratio.spec.tsx | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 apps/tester/tests/06-aspect-ratio.spec.tsx diff --git a/apps/tester/tests/06-aspect-ratio.spec.tsx b/apps/tester/tests/06-aspect-ratio.spec.tsx new file mode 100644 index 0000000..ee6781b --- /dev/null +++ b/apps/tester/tests/06-aspect-ratio.spec.tsx @@ -0,0 +1,87 @@ +import { AspectRatio as JoyAspectRatio } from '@mui/joy'; +import { AspectRatio as TJAspectRatio } from 'tailwind-joy/components'; + +import type { Fixture } from '@/settings'; +import { testEach } from '@/settings'; + +const containerClassName = + 'flex h-[200px] w-[400px] items-center justify-center p-2'; + +const fixtures: Fixture[] = [ + { + title: 'basics', + alterSizes: ['md'], + alterColors: ['primary'], + renderJoyElement({ testId, size, variant, color }) { + return ( + +
Lorem ipsum
+
+ ); + }, + renderTjElement({ testId, size, variant, color }) { + return ( + +
Lorem ipsum
+
+ ); + }, + }, + { + title: 'ratio', + alterSizes: ['md'], + alterColors: ['primary'], + renderJoyElement({ testId, size, variant, color }) { + return ( + +
Lorem ipsum
+
+ ); + }, + renderTjElement({ testId, size, variant, color }) { + return ( + +
Lorem ipsum
+
+ ); + }, + }, + { + title: 'objectFit', + alterSizes: ['md'], + alterColors: ['primary'], + renderJoyElement({ testId, size, variant, color }) { + return ( + + A beautiful landscape. + + ); + }, + renderTjElement({ testId, size, variant, color }) { + return ( + + A beautiful landscape. + + ); + }, + }, +]; + +testEach(fixtures, { + containerClassName, + viewport: { width: 500, height: 500 }, +}); From a3ad7f7b0ac1fe908852c3953be6269de10c0285 Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Thu, 14 Nov 2024 23:51:55 +0900 Subject: [PATCH 4/8] Complements aspect ratio component --- packages/tailwind-joy/src/components/AspectRatio.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tailwind-joy/src/components/AspectRatio.tsx b/packages/tailwind-joy/src/components/AspectRatio.tsx index dedada5..158c55e 100644 --- a/packages/tailwind-joy/src/components/AspectRatio.tsx +++ b/packages/tailwind-joy/src/components/AspectRatio.tsx @@ -42,7 +42,7 @@ function aspectRatioRootVariants( return twMerge( clsx([ 'tj-aspect-ratio-root group/tj-aspect-ratio', - '[--AspectRatio-paddingBottom:clamp(var(--AspectRatio-minHeight),calc(100%/var(--tj-AspectRatio-ratio)),var(--AspectRatio-maxHeight))]', + '[--AspectRatio-paddingBottom:clamp(var(--AspectRatio-minHeight),calc(100%/(var(--tj-AspectRatio-ratio))),var(--AspectRatio-maxHeight))]', '[--AspectRatio-maxHeight:var(--tj-AspectRatio-maxHeight)]', '[--AspectRatio-minHeight:var(--tj-AspectRatio-minHeight)]', color !== 'neutral' || variant === 'solid' From d36278eed9f5969894ed421122912f7706f237e7 Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Fri, 15 Nov 2024 00:47:48 +0900 Subject: [PATCH 5/8] Add waiting time after mount --- apps/tester/src/settings.tsx | 8 ++++++++ apps/tester/tests/06-aspect-ratio.spec.tsx | 1 + 2 files changed, 9 insertions(+) diff --git a/apps/tester/src/settings.tsx b/apps/tester/src/settings.tsx index 3576403..60ab84b 100644 --- a/apps/tester/src/settings.tsx +++ b/apps/tester/src/settings.tsx @@ -25,6 +25,7 @@ export type Fixture = { alterVariants?: UIVariant[]; alterColors?: UIColor[]; alterStates?: UIState[]; + waitTime?: number; renderJoyElement: ElementRenderer; renderTjElement: ElementRenderer; }; @@ -63,6 +64,7 @@ export function testEach( alterVariants, alterColors, alterStates, + waitTime, renderJoyElement, renderTjElement, } of fixtures) { @@ -112,6 +114,9 @@ export function testEach(
, ); + if (waitTime) { + await sleep(waitTime); + } if (state === 'hover') { await page.getByTestId(elementTestId).hover(); } else if (state === 'focus-visible') { @@ -153,6 +158,9 @@ export function testEach(
, ); + if (waitTime) { + await sleep(waitTime); + } if (state === 'hover') { await page.getByTestId(elementTestId).hover(); } else if (state === 'focus-visible') { diff --git a/apps/tester/tests/06-aspect-ratio.spec.tsx b/apps/tester/tests/06-aspect-ratio.spec.tsx index ee6781b..c9097da 100644 --- a/apps/tester/tests/06-aspect-ratio.spec.tsx +++ b/apps/tester/tests/06-aspect-ratio.spec.tsx @@ -50,6 +50,7 @@ const fixtures: Fixture[] = [ title: 'objectFit', alterSizes: ['md'], alterColors: ['primary'], + waitTime: 3000, renderJoyElement({ testId, size, variant, color }) { return ( Date: Fri, 15 Nov 2024 09:14:00 +0900 Subject: [PATCH 6/8] Replace joy ui components --- .../02-data-display/01-aspect-ratio.mdx | 67 ++++++++++--------- .../website/src/demos/aspect-ratio/Basics.tsx | 7 +- .../demos/aspect-ratio/MediaPlaceholder.tsx | 18 +++-- .../aspect-ratio/MinimumAndMaximumHeight.tsx | 7 +- .../src/demos/aspect-ratio/ObjectFit.tsx | 7 +- apps/website/src/demos/aspect-ratio/Ratio.tsx | 9 ++- .../src/demos/aspect-ratio/Variants.tsx | 19 +++--- 7 files changed, 68 insertions(+), 66 deletions(-) diff --git a/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx b/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx index 7bf5dfc..e772045 100644 --- a/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx +++ b/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx @@ -31,16 +31,15 @@ The default ratio is `16/9`. ```tsx -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Typography } from 'tailwind-joy/components'; +import { AspectRatio, Typography } from 'tailwind-joy/components'; export function AspectRatioBasics() { return ( - + 16/9 - + ); } ``` @@ -54,39 +53,38 @@ The Aspect Ratio component supports four variants: `solid`, `soft` (default), `o ```tsx -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Box, Typography } from 'tailwind-joy/components'; +import { AspectRatio, Box, Typography } from 'tailwind-joy/components'; export function AspectRatioVariants() { return ( - + Solid - + - + Soft - + - + Outlined - + - + Plain - + ); @@ -101,20 +99,19 @@ For example, the demo below uses a ratio of `4/3`, which is a common alternative ```tsx -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Typography } from 'tailwind-joy/components'; +import { AspectRatio, Typography } from 'tailwind-joy/components'; export function AspectRatioRatio() { return ( - 4/3 - + ); } ``` @@ -128,19 +125,18 @@ This prop gives you access to all of the values associated with the CSS `object- ```tsx -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Box } from 'tailwind-joy/components'; +import { AspectRatio, Box } from 'tailwind-joy/components'; export function AspectRatioObjectFit() { return ( - + A beautiful landscape. - + ); } @@ -153,9 +149,10 @@ Use a `
`, or a [Box](./box) component paired with an icon, as a fallback wh ```tsx -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import ImageIcon from '@mui/icons-material/Image'; -import { Box, Sheet, Typography } from 'tailwind-joy/components'; +import { MdImage } from 'react-icons/md'; +import { AspectRatio, Sheet, Typography } from 'tailwind-joy/components'; +import { iconClass } from 'tailwind-joy/utils'; +import { twMerge } from 'tailwind-merge'; export function AspectRatioMediaPlaceholder() { return ( @@ -163,11 +160,16 @@ export function AspectRatioMediaPlaceholder() { variant="outlined" className="mx-auto flex w-full max-w-[300px] flex-col gap-y-3 rounded-lg p-4" > - +
- +
-
+
Title Description of the card. @@ -185,19 +187,18 @@ This is useful when the Aspect Ratio component wraps dynamic-width content, as s ```tsx -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Box } from 'tailwind-joy/components'; +import { AspectRatio, Box } from 'tailwind-joy/components'; export function AspectRatioMinimumAndMaximumHeight() { return ( - + - + ); } diff --git a/apps/website/src/demos/aspect-ratio/Basics.tsx b/apps/website/src/demos/aspect-ratio/Basics.tsx index 466f8a8..cd9d45c 100644 --- a/apps/website/src/demos/aspect-ratio/Basics.tsx +++ b/apps/website/src/demos/aspect-ratio/Basics.tsx @@ -1,15 +1,14 @@ -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Typography } from 'tailwind-joy/components'; +import { AspectRatio, Typography } from 'tailwind-joy/components'; import { DisplayStand } from '@site/src/components/docs/DisplayStand'; export function AspectRatioBasics() { return ( - + 16/9 - + ); } diff --git a/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx b/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx index 98160da..e0ccdf1 100644 --- a/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx +++ b/apps/website/src/demos/aspect-ratio/MediaPlaceholder.tsx @@ -1,6 +1,7 @@ -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import ImageIcon from '@mui/icons-material/Image'; -import { Sheet, Typography } from 'tailwind-joy/components'; +import { MdImage } from 'react-icons/md'; +import { AspectRatio, Sheet, Typography } from 'tailwind-joy/components'; +import { iconClass } from 'tailwind-joy/utils'; +import { twMerge } from 'tailwind-merge'; import { DisplayStand } from '@site/src/components/docs/DisplayStand'; export function AspectRatioMediaPlaceholder() { @@ -11,11 +12,16 @@ export function AspectRatioMediaPlaceholder() { variant="outlined" className="mx-auto flex w-full max-w-[300px] flex-col gap-y-3 rounded-lg p-4" > - +
- +
-
+
Title Description of the card. diff --git a/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx b/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx index 815fcd9..229eea1 100644 --- a/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx +++ b/apps/website/src/demos/aspect-ratio/MinimumAndMaximumHeight.tsx @@ -1,18 +1,17 @@ -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Box } from 'tailwind-joy/components'; +import { AspectRatio, Box } from 'tailwind-joy/components'; import { DisplayStand } from '@site/src/components/docs/DisplayStand'; export function AspectRatioMinimumAndMaximumHeight() { return ( - + - + ); diff --git a/apps/website/src/demos/aspect-ratio/ObjectFit.tsx b/apps/website/src/demos/aspect-ratio/ObjectFit.tsx index 047ce96..96ffd5f 100644 --- a/apps/website/src/demos/aspect-ratio/ObjectFit.tsx +++ b/apps/website/src/demos/aspect-ratio/ObjectFit.tsx @@ -1,18 +1,17 @@ -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Box } from 'tailwind-joy/components'; +import { AspectRatio, Box } from 'tailwind-joy/components'; import { DisplayStand } from '@site/src/components/docs/DisplayStand'; export function AspectRatioObjectFit() { return ( - + A beautiful landscape. - + ); diff --git a/apps/website/src/demos/aspect-ratio/Ratio.tsx b/apps/website/src/demos/aspect-ratio/Ratio.tsx index d2bf7a4..d5445e8 100644 --- a/apps/website/src/demos/aspect-ratio/Ratio.tsx +++ b/apps/website/src/demos/aspect-ratio/Ratio.tsx @@ -1,19 +1,18 @@ -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Typography } from 'tailwind-joy/components'; +import { AspectRatio, Typography } from 'tailwind-joy/components'; import { DisplayStand } from '@site/src/components/docs/DisplayStand'; export function AspectRatioRatio() { return ( - 4/3 - + ); } diff --git a/apps/website/src/demos/aspect-ratio/Variants.tsx b/apps/website/src/demos/aspect-ratio/Variants.tsx index 7194d6b..401e973 100644 --- a/apps/website/src/demos/aspect-ratio/Variants.tsx +++ b/apps/website/src/demos/aspect-ratio/Variants.tsx @@ -1,5 +1,4 @@ -import { AspectRatio as JoyAspectRatio } from '@mui/joy'; -import { Box, Typography } from 'tailwind-joy/components'; +import { AspectRatio, Box, Typography } from 'tailwind-joy/components'; import { DisplayStand } from '@site/src/components/docs/DisplayStand'; export function AspectRatioVariants() { @@ -9,35 +8,35 @@ export function AspectRatioVariants() { {/* TODO: Replace Box with Grid. */} - + Solid - + {/* TODO: Replace Box with Grid. */} - + Soft - + {/* TODO: Replace Box with Grid. */} - + Outlined - + {/* TODO: Replace Box with Grid. */} - + Plain - + From 40c04fd4420ff831a440e221c373822a14b8af76 Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Fri, 15 Nov 2024 23:04:18 +0900 Subject: [PATCH 7/8] Write aspect ratio component api document --- apps/website/docs/apis/06-aspect-ratio.md | 110 ++++++++++++++++++ .../02-data-display/01-aspect-ratio.mdx | 2 +- 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 apps/website/docs/apis/06-aspect-ratio.md diff --git a/apps/website/docs/apis/06-aspect-ratio.md b/apps/website/docs/apis/06-aspect-ratio.md new file mode 100644 index 0000000..7dc99a5 --- /dev/null +++ b/apps/website/docs/apis/06-aspect-ratio.md @@ -0,0 +1,110 @@ +--- +sidebar_position: 6 +title: +--- + +# AspectRatio API + + + +API reference docs for the React AspectRatio component. +Learn about the props of this exported module. + +## Demos + +:::tip + +For examples and details on the usage of this React component, visit the component demo pages: + +- [AspectRatio](../components/aspect-ratio) + +::: + +## Import + +```tsx +import { AspectRatio } from 'tailwind-joy/components'; +``` + +## Props + +:::info + +The `ref` is forwarded to the root element. + +::: + +### `className` + +Class name applied to the root element. + +- Type: `string` + +### `color` + +The color of the component. + +- Type: `'primary' | 'neutral' | 'danger' | 'success' | 'warning'` +- Default: `'neutral'` + +### `component` + +The component used for the root node. + +- Type: `keyof JSX.IntrinsicElements` +- Default: `'div'` + +### `flex` + +By default, the AspectRatio will maintain the aspect ratio of its content. +Set this prop to `true` when the container is a flex row and you want the AspectRatio to fill the height of its container. + +- Type: `boolean` +- Default: `false` + +### `maxHeight` + +The maximum calculated height of the element (not the CSS height). + +- Type: `number | string` + +### `minHeight` + +The minimum calculated height of the element (not the CSS height). + +- Type: `number | string` + +### `objectFit` + +The CSS object-fit value of the first-child. + +- Type: `'-moz-initial' | 'contain' | 'cover' | 'fill' | 'inherit' | 'initial' | 'none' | 'revert-layer' | 'revert' | 'scale-down' | 'unset'` +- Default: `'cover'` + +### `ratio` + +The aspect-ratio of the element. +The current implementation uses padding instead of the CSS aspect-ratio. + +- Type: `number | string` +- Default: `'16/9'` + +### `slotProps` + +The props used for each slot inside. + +- Type: + ```tsx + { + root?: ComponentProps<'div'>; + content?: ComponentProps<'div'>; + } + ``` +- Default: `{}` + +### `variant` + +The variant of the component. + +- Type: `'solid' | 'soft' | 'outlined' | 'plain'` +- Default: `'soft'` diff --git a/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx b/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx index e772045..e641a29 100644 --- a/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx +++ b/apps/website/docs/components/02-data-display/01-aspect-ratio.mdx @@ -220,7 +220,7 @@ The Aspect Ratio component is composed of a root `
` with a content `
` ## API -- `` +- [``](../apis/aspect-ratio) - [``](../apis/box) - [``](../apis/sheet) - [``](../apis/typography) From 9795abb6b030ee72a84ba1d64f74bf771e703e5c Mon Sep 17 00:00:00 2001 From: Hyeonjong Date: Fri, 15 Nov 2024 23:05:54 +0900 Subject: [PATCH 8/8] Update README.md --- packages/tailwind-joy/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/tailwind-joy/README.md b/packages/tailwind-joy/README.md index b05709c..32f7eaf 100644 --- a/packages/tailwind-joy/README.md +++ b/packages/tailwind-joy/README.md @@ -21,6 +21,7 @@ https://tailwind-joy.vercel.app ### Data display +- Aspect Ratio - Divider - Typography