feat(card): stories added and tests passing

This commit is contained in:
Junior Garcia 2023-03-25 18:32:25 -03:00
parent 0eaf34994a
commit d7dfa1995e
8 changed files with 380 additions and 588 deletions

View File

@ -1,6 +1,5 @@
import * as React from "react";
import {render} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {act, render} from "@testing-library/react";
import {Card} from "../src";
@ -26,10 +25,13 @@ describe("Card", () => {
it("should be clicked when is pressable", () => {
const onPress = jest.fn();
const {container} = render(<Card isPressable onPress={onPress} />);
const {getByRole} = render(<Card isPressable onPress={onPress} />);
userEvent.click(container.firstChild as HTMLElement);
expect(onPress).toBeCalledTimes(1);
act(() => {
getByRole("button").click();
});
expect(onPress).toHaveBeenCalled();
});
it("should render correctly when nested", () => {

View File

@ -52,6 +52,8 @@
"@react-types/shared": "^3.17.0",
"@nextui-org/code": "workspace:*",
"@nextui-org/link": "workspace:*",
"@nextui-org/button": "workspace:*",
"@nextui-org/avatar": "workspace:*",
"clean-package": "2.2.0",
"react": "^18.0.0"
},

View File

@ -17,7 +17,7 @@ const CardFooter = forwardRef<CardFooterProps, "div">((props, ref) => {
const {slots, styles} = useCardContext();
const footerStyles = clsx(styles?.body, className, {
"backdrop-blur-md backdrop-saturate-[1.8]": isBlurred,
"backdrop-blur-xl backdrop-saturate-200": isBlurred,
});
return (

View File

@ -52,7 +52,6 @@ export type ContextType = {
slots: CardReturnType;
styles?: SlotsToClasses<CardSlots>;
isDisabled?: CardVariantProps["isDisabled"];
isBordered?: CardVariantProps["isBordered"];
isFooterBlurred?: CardVariantProps["isFooterBlurred"];
disableAnimation?: CardVariantProps["disableAnimation"];
fullWidth?: CardVariantProps["fullWidth"];
@ -120,7 +119,6 @@ export function useCard(originalProps: UseCardProps) {
const context = useMemo<ContextType>(
() => ({
isBordered: originalProps.isBordered,
isDisabled: originalProps.isDisabled,
isFooterBlurred: originalProps.isFooterBlurred,
disableAnimation: originalProps.disableAnimation,
@ -131,7 +129,6 @@ export function useCard(originalProps: UseCardProps) {
[
slots,
styles,
originalProps.isBordered,
originalProps.isDisabled,
originalProps.isFooterBlurred,
originalProps.disableAnimation,

View File

@ -1,8 +1,11 @@
import React from "react";
import {ComponentStory, ComponentMeta} from "@storybook/react";
import {card} from "@nextui-org/theme";
import {Link} from "@nextui-org/link";
import {Button} from "@nextui-org/button";
import {Code} from "@nextui-org/code";
import {Card, CardBody, CardProps} from "../src";
import {Card, CardBody, CardHeader, CardFooter, CardProps} from "../src";
export default {
title: "Components/Card",
@ -20,11 +23,6 @@ export default {
options: ["none", "base", "sm", "md", "lg", "xl", "2xl", "3xl", "full"],
},
},
isBordered: {
control: {
type: "boolean",
},
},
fullWidth: {
control: {
type: "boolean",
@ -64,9 +62,7 @@ export default {
decorators: [
(Story) => (
<div className="flex items-center justify-center w-screen h-screen">
<div className="max-w-md w-full">
<Story />
</div>
<Story />
</div>
),
],
@ -78,12 +74,348 @@ const defaultProps = {
};
const Template: ComponentStory<typeof Card> = (args: CardProps) => (
<Card {...args}>
<CardBody>A basic card</CardBody>
<Card {...args} className="max-w-md">
<CardBody>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed</p>
</CardBody>
</Card>
);
const WithDividerTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
<Card {...args} isBordered className="max-w-md">
<CardHeader className="border-b border-border dark:border-border-dark">
<strong>Description</strong>
</CardHeader>
<CardBody className="py-8">
<p>The Object constructor creates an object wrapper for the given value.</p>
</CardBody>
<CardFooter className="border-t border-border dark:border-border-dark">
<p>
When called in a non-constructor context, Object behaves identically to{" "}
<Code color="primary">new Object()</Code>.
</p>
</CardFooter>
</Card>
);
const WithFooterTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
<Card {...args} className="p-4 max-w-md">
<CardHeader className="flex gap-3">
<img
alt="nextui logo"
height="34px"
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
width="34px"
/>
<div className="flex flex-col">
<b className="text-lg">NextUI</b>
<p className="text-neutral-500">nextui.org</p>
</div>
</CardHeader>
<CardBody className="py-2">
<p>Make beautiful websites regardless of your design experience.</p>
</CardBody>
<CardFooter>
<Link isExternal showAnchorIcon href="https://github.com/nextui-org/nextui">
Visit source code on GitHub.
</Link>
</CardFooter>
</Card>
);
const WithAbsImageHeaderTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
<Card {...args} className="max-w-[330px]">
<CardHeader className="absolute top-2 z-10">
<div className="flex flex-col">
<p className="text-white/60 text-xs uppercase font-bold">What to watch</p>
<p className="text-white text-2xl">Stream the Apple event</p>
</div>
</CardHeader>
<img
alt="Apple event background"
className="w-full h-[440px] object-cover"
src={require("./assets/apple-event.jpeg")}
/>
</Card>
);
const WithAbsImgHeaderFooterTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
<Card className="w-[330px] bg-zinc-100 dark:bg-zinc-100" {...args}>
<CardHeader className="absolute top-2 z-10">
<div className="flex flex-col gap-2">
<p className="text-xs text-black/40 uppercase font-bold">New</p>
<h4 className="text-3xl font-medium text-black">HomePod mini</h4>
<p className="text-sm text-black/80 pr-1.5">
Room-filling sound, Intelligent assistant. Smart home control. Works seamlessly with
iPhone. Check it out
</p>
</div>
</CardHeader>
<img
alt="Apple homepods background"
className="w-full h-[440px] pt-10 object-contain"
src={require("./assets/homepod.jpeg")}
/>
<CardFooter className="justify-between absolute bottom-0">
<div>
<p className="text-xs text-black/80">Available soon.</p>
<p className="text-xs text-black/80">Get notified.</p>
</div>
<Button radius="full">Notify Me</Button>
</CardFooter>
</Card>
);
const CoverImgTemplate: ComponentStory<typeof Card> = (args: CardProps) => (
<div className="max-w-[900px] gap-2 grid grid-cols-12 grid-rows-2 px-8">
<Card {...args} className="col-span-12 sm:col-span-4">
<CardHeader className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/60 uppercase font-bold">What to watch</p>
<h4 className="text-white font-medium text-lg">Stream the Acme event</h4>
</CardHeader>
<img
alt="Card background"
className="w-full h-full object-cover"
src="https://nextui.org/images/card-example-4.jpeg"
/>
</Card>
<Card {...args} className="col-span-12 sm:col-span-4">
<CardHeader className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/60 uppercase font-bold">Plant a tree</p>
<h4 className="text-white font-medium text-lg">Contribute to the planet</h4>
</CardHeader>
<img
alt="Card background"
className="w-full h-full object-cover"
src="https://nextui.org/images/card-example-3.jpeg"
/>
</Card>
<Card {...args} className="col-span-12 sm:col-span-4">
<CardHeader className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/60 uppercase font-bold">Supercharged</p>
<h4 className="text-white font-medium text-lg">Creates beauty like a beast</h4>
</CardHeader>
<img
alt="Card background"
className="w-full h-full object-cover"
src="https://nextui.org/images/card-example-2.jpeg"
/>
</Card>
<Card {...args} isFooterBlurred className="w-full h-[400px] col-span-12 sm:col-span-5">
<CardHeader className="absolute z-10 top-1 flex-col items-start">
<p className="text-xs text-white/60 uppercase font-bold">New</p>
<h4 className="text-black font-medium text-2xl">Acme camera</h4>
</CardHeader>
<img
alt="Card example background"
className="w-full h-full scale-125 -translate-y-10 object-cover"
src="https://nextui.org/images/card-example-6.jpeg"
/>
<CardFooter className="absolute bg-white/30 bottom-0 border-t border-slate-300 z-10 justify-between">
<div>
<p className="text-black text-xs">Available soon.</p>
<p className="text-black text-xs">Get notified.</p>
</div>
<Button color="secondary" radius="full" size="sm" variant="flat">
Notify Me
</Button>
</CardFooter>
</Card>
<Card {...args} isFooterBlurred className="w-full h-[400px] col-span-12 sm:col-span-7">
<CardHeader className="absolute z-10 top-1 flex-col items-start">
<p className="text-xs text-white/60 uppercase font-bold">Your day your way</p>
<h4 className="text-white/90 font-medium text-2xl">Your checklist for better sleep</h4>
</CardHeader>
<img
alt="Relaxing app background"
className="w-full h-full object-cover"
src="https://nextui.org/images/card-example-5.jpeg"
/>
<CardFooter className="absolute bg-black/40 bottom-0 z-10 border-t border-neutral-600 dark:border-neutral-100">
<div className="flex flex-grow gap-2 items-center">
<img
alt="Breathing app icon"
className="rounded-full w-10 h-11 bg-black"
src={require("./assets/breathing-app-icon.jpeg")}
/>
<div className="flex flex-col">
<p className="text-xs text-white/60">Breathing App</p>
<p className="text-xs text-white/60">Get a good night&apos;s sleep.</p>
</div>
</div>
<Button radius="full">Get App</Button>
</CardFooter>
</Card>
</div>
);
const PrimaryActionTemplate: ComponentStory<typeof Card> = (args: CardProps) => {
const list = [
{
title: "Orange",
img: "/images/fruit-1.jpeg",
price: "$5.50",
},
{
title: "Tangerine",
img: "/images/fruit-2.jpeg",
price: "$3.00",
},
{
title: "Raspberry",
img: "/images/fruit-3.jpeg",
price: "$10.00",
},
{
title: "Lemon",
img: "/images/fruit-4.jpeg",
price: "$5.30",
},
{
title: "Avocado",
img: "/images/fruit-5.jpeg",
price: "$15.70",
},
{
title: "Lemon 2",
img: "/images/fruit-6.jpeg",
price: "$8.00",
},
{
title: "Banana",
img: "/images/fruit-7.jpeg",
price: "$7.50",
},
{
title: "Watermelon",
img: "/images/fruit-8.jpeg",
price: "$12.20",
},
];
type ListItem = (typeof list)[number];
const handlePress = (item: ListItem) => {
// eslint-disable-next-line no-console
console.log("item pressed", item);
};
return (
<div className="gap-2 grid grid-cols-2 sm:grid-cols-4">
{list.map((item, index) => (
// eslint-disable-next-line no-console
<Card {...args} key={index} isPressable onPress={() => handlePress(item)}>
<CardBody className="p-0">
<img
alt={item.title}
className="w-full h-[140px] object-cover"
src={"https://nextui.org" + item.img}
/>
</CardBody>
<CardFooter className="justify-between">
<b>{item.title}</b>
<p className="text-neutral-500">{item.price}</p>
</CardFooter>
</Card>
))}
</div>
);
};
const CenterImgWithHeaderTemplate: ComponentStory<typeof Card> = (args: CardProps) => {
const list = [
{
title: "Mac",
img: require("./assets/mac.png"),
},
{
title: "iPhone",
img: require("./assets/iphone.png"),
},
{
title: "iPad",
img: require("./assets/ipad.png"),
},
{
title: "Apple Watch",
img: require("./assets/apple-watch.png"),
},
{
title: "AirPods",
img: require("./assets/airpods.png"),
},
{
title: "AirTag",
img: require("./assets/airtag.png"),
},
{
title: "Apple TV",
img: require("./assets/appletv.png"),
},
{
title: "HomePod mini",
img: require("./assets/homepod-mini.png"),
},
{
title: "Accessories",
img: require("./assets/accessories.png"),
},
];
return (
<div className="flex gap-2 justify-center flex-wrap">
{list.map((item, index) => (
<div key={index}>
<Card {...args} isPressable className="w-[200px] h-[200px]">
<CardHeader className="p-0">
<h5 className="pl-6 pt-3">{item.title}</h5>
</CardHeader>
<CardBody className="h-full justify-center">
<img alt={item.title} className="w-[180px]" src={item.img} />
</CardBody>
</Card>
</div>
))}
</div>
);
};
export const Default = Template.bind({});
Default.args = {
...defaultProps,
};
export const WithDivider = WithDividerTemplate.bind({});
WithDivider.args = {
...defaultProps,
};
export const WithFooter = WithFooterTemplate.bind({});
WithFooter.args = {
...defaultProps,
};
export const WithAbsImageHeader = WithAbsImageHeaderTemplate.bind({});
WithAbsImageHeader.args = {
...defaultProps,
};
export const WithAbsImgHeaderFooter = WithAbsImgHeaderFooterTemplate.bind({});
WithAbsImgHeaderFooter.args = {
...defaultProps,
};
export const CoverImg = CoverImgTemplate.bind({});
CoverImg.args = {
...defaultProps,
};
export const PrimaryAction = PrimaryActionTemplate.bind({});
PrimaryAction.args = {
...defaultProps,
};
export const CenterImgWithHeader = CenterImgWithHeaderTemplate.bind({});
CenterImgWithHeader.args = {
...defaultProps,
};

View File

@ -1,556 +0,0 @@
import React from "react";
import {ComponentMeta, ComponentStory} from "@storybook/react";
import {Link} from "@nextui-org/link";
import {Code} from "@nextui-org/code";
import {styled} from "@nextui-org/system";
import {Card, CardProps} from "../src";
export default {
title: "General/Card",
component: Card,
argTypes: {
variant: {
control: {
type: "radio",
options: ["shadow", "bordered", "flat"],
},
},
borderWeight: {
control: {
type: "radio",
options: ["light", "normal", "bold", "extrabold", "black"],
},
},
isPressable: {
control: {
type: "boolean",
},
},
disableAnimation: {
control: {
type: "boolean",
},
},
isHoverable: {
control: {
type: "boolean",
},
},
},
} as ComponentMeta<typeof Card>;
const Template: ComponentStory<typeof Card> = (args: CardProps) => (
<Card {...args} className="max-w-[50%]">
<Card.Body>A basic card</Card.Body>
</Card>
);
export const Default = Template.bind({});
Default.args = {
variant: "shadow",
};
export const Hoverable = Template.bind({});
Hoverable.args = {
variant: "bordered",
isHoverable: true,
};
export const Variants = () => (
<div className="container flex gap-2">
<div className="w-4/12">
<Card>
<Card.Body>
<p>Default card. (shadow)</p>
</Card.Body>
</Card>
</div>
<div className="w-4/12">
<Card variant="flat">
<Card.Body>
<p>Flat card.</p>
</Card.Body>
</Card>
</div>
<div className="w-4/12">
<Card variant="bordered">
<Card.Body>
<p>Bordered card.</p>
</Card.Body>
</Card>
</div>
</div>
);
export const WithFooter = () => (
<Card className="p-3 max-w-[400px]">
<Card.Header>
<img
alt="nextui logo"
height="34px"
src="https://avatars.githubusercontent.com/u/86160567?s=200&v=4"
width="34px"
/>
<div className="flex flex-col pl-3">
<h4 className="pb-2">Next UI</h4>
<p>nextui.org</p>
</div>
</Card.Header>
<Card.Body className="py-2">
<p>Make beautiful websites regardless of your design experience.</p>
</Card.Body>
<Card.Footer>
<Link isExternal color="primary" href="https://github.com/nextui-org/nextui" target="_blank">
Visit source code on GitHub.
</Link>
</Card.Footer>
</Card>
);
export const AbsImageWithHeader = () => {
return (
<div className="flex justify-center gap-2">
<Card className="w-[330px]">
<Card.Header className="absolute top-5 z-10">
<div className="grid-cols-2">
<p className="text-white/75 text-sm uppercase font-bold">What to watch</p>
<h3 className="text-white text-xl">Stream the Apple event</h3>
</div>
</Card.Header>
<Card.Image
alt="Apple event background"
autoResize={false}
height={440}
src={require("./assets/apple-event.jpeg")}
style={{objectFit: "cover"}}
width="100%"
/>
</Card>
</div>
);
};
export const AbsImgWithHeaderFooter = () => {
return (
<div className="flex justify-center items-start gap-2">
<Card className="w-[330px] bg-neutral-100">
<Card.Header className="absolute top-5 z-10">
<div className="flex flex-col">
<p className="text-xs text-neutral-400 upper font-bold">New</p>
<h2 className="text-lg text-black">HomePod mini</h2>
<p className="text-xs text-foreground pr-1.5">
Room-filling sound, Intelligent assistant. Smart home control. Works seamlessly with
iPhone. Check it out
</p>
</div>
</Card.Header>
<Card.Image
alt="Apple homedpods background"
autoResize={false}
height={440}
src={require("./assets/homepod.jpeg")}
style={{objectFit: "cover", paddingTop: "100px"}}
width="100%"
/>
<Card.Footer className="justify-between">
<div>
<p className="text-xs">Available soon.</p>
<p className="text-xs">Get notified.</p>
</div>
<div>
<div className="flex flex-wrap justify-end">
<p className="text-xs upper font-bold">Notify Me</p>
</div>
</div>
</Card.Footer>
</Card>
<Card className="w-[630px]">
<Card.Header className="absolute top-5 z-10">
<div className="flex flex-col">
<p className="text-neutral-300 upper font-bold">Your day your way</p>
<h3 className="text-white text-xl">Your checklist for better sleep</h3>
</div>
</Card.Header>
<Card.Image
alt="Apple homedpods background"
autoResize={false}
height={440}
src={require("./assets/relaxing.jpeg")}
style={{objectFit: "cover"}}
width="100%"
/>
<Card.Footer isBlurred className="absolute bottom-0 z-10 border-t border-border-dark">
<div className="flex flex-grow items-start">
<div className="w-[40px] mr-2">
<Card.Image
alt="Breathing app icon"
autoResize={false}
height={40}
src={require("./assets/breathing-app-icon.jpeg")}
style={{background: "black"}}
width={40}
/>
</div>
<div className="flex flex-col">
<p className="text-xs text-neutral-400">Breathing App</p>
<p className="text-xs text-neutral-400">Get a good night&apos;s sleep.</p>
</div>
</div>
<p className="text-white upper font-bold">Get App</p>
</Card.Footer>
</Card>
</div>
);
};
export const CoverImage = () => (
<div className="gap-2 grid grid-cols-12">
<div className="col-span-12 sm:col-span-4">
<Card>
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/75 upper font-bold">What to watch</p>
<h4 className="text-white font-medium text-lg">Stream the Acme event</h4>
</Card.Header>
<Card.Image
alt="Card image background"
height={340}
objectFit="cover"
src="https://nextui.org/images/card-example-4.jpeg"
width="100%"
/>
</Card>
</div>
<div className="col-span-12 sm:col-span-4">
<Card>
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/75 upper font-bold">Plant a tree</p>
<h4 className="text-white font-medium text-lg">Contribute to the planet</h4>
</Card.Header>
<Card.Image
alt="Card image background"
height={340}
objectFit="cover"
src="https://nextui.org/images/card-example-3.jpeg"
width="100%"
/>
</Card>
</div>
<div className="col-span-12 sm:col-span-4">
<Card className="bg-black">
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/75 upper font-bold">Supercharged</p>
<h4 className="text-white font-medium text-lg">Creates beauty like a beast</h4>
</Card.Header>
<Card.Image
alt="Card image background"
height={340}
objectFit="cover"
src="https://nextui.org/images/card-example-2.jpeg"
width="100%"
/>
</Card>
</div>
<div className="col-span-12 sm:col-span-5">
<Card className="w-full h-[400px]">
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/75 upper font-bold">New</p>
<h3 className="text-black font-medium text-2xl">Acme camera</h3>
</Card.Header>
<Card.Image
alt="Card example background"
height="100%"
objectFit="cover"
src="https://nextui.org/images/card-example-6.jpeg"
width="100%"
/>
<Card.Footer
isBlurred
className="absolute bg-white/50 bottom-0 border-t border-border-dark z-10"
>
<div>
<p className="text-black text-xs">Available soon.</p>
<p className="text-black text-xs">Get notified.</p>
</div>
<p className="text-xs upper font-bold text-inherit ml-auto">Notify Me</p>
</Card.Footer>
</Card>
</div>
<div className="col-span-12 sm:col-span-7">
<Card className="w-full h-[400px]">
<Card.Header className="absolute z-10 top-1 flex-col !items-start">
<p className="text-xs text-white/75 upper font-bold">Your day your way</p>
<h3 className="text-white font-medium text-2xl">Your checklist for better sleep</h3>
</Card.Header>
<Card.Image
alt="Relaxing app background"
height="100%"
objectFit="cover"
src="https://nextui.org/images/card-example-5.jpeg"
width="100%"
/>
<Card.Footer
isBlurred
className="absolute bottom-0 z-10 bg-black/50 border-t border-border-dark"
>
<div className="flex flex-grow items-center">
<div className="w-[40px] mr-2">
<Card.Image
alt="Breathing app icon"
autoResize={false}
height={40}
src={require("./assets/breathing-app-icon.jpeg")}
style={{background: "black"}}
width={40}
/>
</div>
<div className="flex flex-col">
<p className="text-xs text-neutral-400">Breathing App</p>
<p className="text-xs text-neutral-400">Get a good night&apos;s sleep.</p>
</div>
</div>
<p className="text-white upper font-bold">Get App</p>
</Card.Footer>
</Card>
</div>
</div>
);
export const PrimaryAction = () => {
const list = [
{
title: "Orange",
img: "/images/fruit-1.jpeg",
price: "$5.50",
},
{
title: "Tangerine",
img: "/images/fruit-2.jpeg",
price: "$3.00",
},
{
title: "Raspberry",
img: "/images/fruit-3.jpeg",
price: "$10.00",
},
{
title: "Lemon",
img: "/images/fruit-4.jpeg",
price: "$5.30",
},
{
title: "Advocato",
img: "/images/fruit-5.jpeg",
price: "$15.70",
},
{
title: "Lemon 2",
img: "/images/fruit-6.jpeg",
price: "$8.00",
},
{
title: "Banana",
img: "/images/fruit-7.jpeg",
price: "$7.50",
},
{
title: "Watermelon",
img: "/images/fruit-8.jpeg",
price: "$12.20",
},
];
return (
<div className="gap-2 grid grid-cols-2 sm:grid-cols-4">
{list.map((item, index) => (
// eslint-disable-next-line no-console
<Card key={index} isPressable onPress={() => console.log("item pressed", item)}>
<Card.Body className="!p-0">
<Card.Image
alt={item.title}
height={140}
src={"https://nextui.org" + item.img}
style={{objectFit: "cover"}}
width="100%"
/>
</Card.Body>
<Card.Footer className="justify-between">
<strong>{item.title}</strong>
<p className="font-medium text-neutral-500">{item.price}</p>
</Card.Footer>
</Card>
))}
</div>
);
};
export const CenterImgWithHeader = () => {
const list = [
{
title: "Mac",
img: require("./assets/mac.png"),
},
{
title: "iPhone",
img: require("./assets/iphone.png"),
},
{
title: "iPad",
img: require("./assets/ipad.png"),
},
{
title: "Apple Watch",
img: require("./assets/apple-watch.png"),
},
{
title: "AirPods",
img: require("./assets/airpods.png"),
},
{
title: "AirTag",
img: require("./assets/airtag.png"),
},
{
title: "Apple TV",
img: require("./assets/appletv.png"),
},
{
title: "HomePod mini",
img: require("./assets/homepod-mini.png"),
},
{
title: "Accessories",
img: require("./assets/accessories.png"),
},
];
return (
<div className="flex gap-2 justify-center flex-wrap">
{list.map((item, index) => (
<div key={index}>
<Card isHoverable isPressable className="w-[200px] h-[200px]">
<Card.Header className="!p-0">
<h5 className="pl-6 pt-2.5">{item.title}</h5>
</Card.Header>
<Card.Body className="h-full justify-center">
<Card.Image alt={item.title} autoResize={false} src={item.img} width={180} />
</Card.Body>
</Card>
</div>
))}
</div>
);
};
export const WithDivider = () => (
<Card className="w-max-[400px]" variant="bordered">
<Card.Header className="border-b border-border dark:border-border-dark">
<strong>Description</strong>
</Card.Header>
<Card.Body>
<p>The Object constructor creates an object wrapper for the given value.</p>
</Card.Body>
<Card.Footer className="border-t border-border dark:border-border-dark">
<p>
When called in a non-constructor context, Object behaves identically to{" "}
<Code>new Object()</Code>.
</p>
</Card.Footer>
</Card>
);
export const Shadows = () => {
const Box = styled("div", {
size: "120px",
dflex: "center",
bg: "$backgroundContrast",
br: "$md",
});
const shadows = ["$xs", "$sm", "$md", "$lg", "$xl"];
return (
<div className="grid grid-cols-2 sm:grid-cols-5 gap-2 justify-center">
<div className="flex justify-center col-span-2 sm:col-span-5">
<strong>Drop shadows</strong>
</div>
{shadows.map((shadow, index) => (
<div key={`${shadow}_${index}`}>
<Box css={{dropShadow: shadow}}>
<p>Shadow: {shadow}</p>
</Box>
</div>
))}
<div className="flex justify-center col-span-2 sm:col-span-5">
<strong>Box shadows</strong>
</div>
{shadows.map((shadow, index) => (
<div key={`${shadow}_${index}`}>
<Box css={{boxShadow: shadow}}>
<p>Shadow: {shadow}</p>
</Box>
</div>
))}
</div>
);
};
//TODO: Input & Button still missing
// export const withForm = () => {
// return (
// <Card css={{mw: "400px"}}>
// <Card.Header css={{justifyContent: "center"}}>
// <Text size={18}>
// Welcome to&nbsp;
// <Text b size={18}>
// NextUI
// </Text>
// </Text>
// </Card.Header>
// <Card.Body css={{px: "$10", pt: "$1", ov: "visible"}}>
// <Input
// bordered
// clearable
// fullWidth
// color="primary"
// contentLeft={<Mail fill="currentColor" />}
// placeholder="Email"
// size="lg"
// />
// <Spacer y={0.5} />
// <Input
// bordered
// clearable
// fullWidth
// color="primary"
// contentLeft={<Password />}
// placeholder="Password"
// size="lg"
// />
// <Spacer y={0.5} />
// <Row align="center" justify="space-between">
// <Checkbox>
// <Text css={{color: "$accents8"}} size={14}>
// Remember me
// </Text>
// </Checkbox>
// <Link css={{color: "$link", fontSize: "$sm"}} href="#">
// Forgot password?
// </Link>
// </Row>
// </Card.Body>
// <Card.Footer css={{pt: 0}}>
// <Grid.Container gap={1} justify="flex-end">
// <Grid>
// <Button auto flat>
// Sign Up
// </Button>
// </Grid>
// <Grid>
// <Button auto>Login</Button>
// </Grid>
// </Grid.Container>
// </Card.Footer>
// </Card>
// );
// };

View File

@ -25,6 +25,7 @@ const card = tv({
"overflow-hidden",
"w-full",
"height-auto",
"outline-none",
"text-foreground",
"box-border",
"dark:bg-content1",
@ -53,6 +54,7 @@ const card = tv({
"h-auto",
"py-5",
"px-3",
"break-words",
"text-left",
"overflow-y-auto",
"subpixel-antialiased",
@ -65,7 +67,6 @@ const card = tv({
"items-center",
"overflow-hidden",
"color-inherit",
"rounded-b-xl",
"subpixel-antialiased",
],
},
@ -96,30 +97,48 @@ const card = tv({
radius: {
none: {
base: "rounded-none",
header: "rounded-t-none",
footer: "rounded-b-none",
},
base: {
base: "rounded",
header: "rounded-t",
footer: "rounded-b",
},
sm: {
base: "rounded-sm",
header: "rounded-t-sm",
footer: "rounded-b-sm",
},
md: {
base: "rounded-md",
header: "rounded-t-md",
footer: "rounded-b-md",
},
lg: {
base: "rounded-lg",
header: "rounded-t-lg",
footer: "rounded-b-lg",
},
xl: {
base: "rounded-xl",
header: "rounded-t-xl",
footer: "rounded-b-xl",
},
"2xl": {
base: "rounded-2xl",
header: "rounded-t-2xl",
footer: "rounded-b-2xl",
},
"3xl": {
base: "rounded-3xl",
header: "rounded-t-3xl",
footer: "rounded-b-3xl",
},
full: {
base: "rounded-full",
header: "rounded-t-full",
footer: "rounded-b-full",
},
},
fullWidth: {
@ -127,15 +146,8 @@ const card = tv({
base: "w-full",
},
},
isBordered: {
true: {
base: "border-2 border-neutral",
},
},
isHoverable: {
true: {
base: "hover:drop-shadow-lg",
},
true: {},
},
isPressable: {
true: {base: "cursor-pointer"},
@ -147,7 +159,7 @@ const card = tv({
},
isFooterBlurred: {
true: {
footer: "backdrop-blur-md backdrop-saturate-[1.8]",
footer: "backdrop-blur-xl backdrop-saturate-200",
},
},
isDisabled: {
@ -164,7 +176,7 @@ const card = tv({
{
isHoverable: true,
disableAnimation: false,
class: "hover:-translate-y-2",
class: "hover:-translate-y-1.5",
},
{
isPressable: true,
@ -179,7 +191,6 @@ const card = tv({
isHoverable: false,
isPressable: false,
isFocusVisible: false,
isBordered: false,
isDisabled: false,
disableAnimation: false,
isFooterBlurred: false,

4
pnpm-lock.yaml generated
View File

@ -429,6 +429,8 @@ importers:
packages/components/card:
specifiers:
'@nextui-org/avatar': workspace:*
'@nextui-org/button': workspace:*
'@nextui-org/code': workspace:*
'@nextui-org/dom-utils': workspace:*
'@nextui-org/drip': workspace:*
@ -456,6 +458,8 @@ importers:
'@react-aria/interactions': 3.14.0_react@18.2.0
'@react-aria/utils': 3.15.0_react@18.2.0
devDependencies:
'@nextui-org/avatar': link:../avatar
'@nextui-org/button': link:../button
'@nextui-org/code': link:../code
'@nextui-org/link': link:../link
'@react-types/shared': 3.17.0_react@18.2.0