chore(card): initial sctructure changed

This commit is contained in:
Junior Garcia 2023-03-25 11:14:27 -03:00
parent 91cb12b8bd
commit e9bbf2e673
9 changed files with 130 additions and 149 deletions

View File

@ -3,11 +3,11 @@ import type {AriaButtonProps} from "@react-types/button";
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
import type {ReactNode} from "react";
import {dataAttr, ReactRef} from "@nextui-org/shared-utils";
import {callAllHandlers, dataAttr, ReactRef} from "@nextui-org/shared-utils";
import {MouseEventHandler, useCallback} from "react";
import {useButton as useAriaButton} from "@react-aria/button";
import {useFocusRing} from "@react-aria/focus";
import {chain, mergeProps} from "@react-aria/utils";
import {mergeProps} from "@react-aria/utils";
import {useDrip} from "@nextui-org/drip";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx} from "@nextui-org/shared-utils";
@ -117,7 +117,7 @@ export function useButton(props: UseButtonProps) {
elementType: as,
isDisabled,
onPress,
onClick: chain(onClick, handleDrip),
onClick: callAllHandlers(onClick, handleDrip),
...otherProps,
} as AriaButtonProps,
domRef,

View File

@ -45,7 +45,8 @@
"@nextui-org/drip": "workspace:*",
"@react-aria/focus": "^3.11.0",
"@react-aria/utils": "^3.15.0",
"@react-aria/interactions": "^3.14.0"
"@react-aria/interactions": "^3.14.0",
"@react-aria/button": "^3.7.0"
},
"devDependencies": {
"@react-types/shared": "^3.17.0",

View File

@ -1,69 +1,25 @@
import {forwardRef} from "@nextui-org/system";
import {__DEV__} from "@nextui-org/shared-utils";
import {Image} from "@nextui-org/image";
import {Drip} from "@nextui-org/drip";
import CardHeader from "./card-header";
import {useCard, UseCardProps} from "./use-card";
import CardBody from "./card-body";
import CardFooter from "./card-footer";
export interface CardProps extends Omit<UseCardProps, "ref"> {}
type CompoundCard = {
Header: typeof CardHeader;
Body: typeof CardBody;
Footer: typeof CardFooter;
Image: typeof Image;
};
const Card = forwardRef<CardProps, "div", CompoundCard>((props, ref) => {
const {
cardRef,
children,
className,
Component,
styles,
isPressable,
disableAnimation,
disableRipple,
dripBindings,
getCardProps,
} = useCard({ref, ...props});
const {base} = styles;
const Card = forwardRef<CardProps, "div">((props, ref) => {
const {children, Component, drips, isPressable, disableAnimation, disableRipple, getCardProps} =
useCard({
ref,
...props,
});
return (
<Component
ref={cardRef}
className={base({class: className})}
role={isPressable ? "button" : "section"}
tabIndex={isPressable ? 0 : -1}
{...getCardProps()}
>
{isPressable && !disableAnimation && !disableRipple && (
<Drip
{...dripBindings}
styles={{
base: "opacity-30 z-50",
svg: "text-inherit",
}}
/>
)}
<Component {...getCardProps()}>
{isPressable && !disableAnimation && !disableRipple && <Drip drips={drips} />}
{children}
</Component>
);
});
Card.Header = CardHeader;
Card.Body = CardBody;
Card.Footer = CardFooter;
Card.Image = Image;
if (__DEV__) {
Card.displayName = "NextUI.Card";
}
Card.toString = () => ".nextui-card";
Card.displayName = "NextUI.Card";
export default Card;

View File

@ -4,5 +4,5 @@ export type {CardProps} from "./card";
// export hooks
export {useCard} from "./use-card";
// export component
// export components
export {default as Card} from "./card";

View File

@ -1,111 +1,97 @@
import type {FocusableProps, PressEvent, PressEvents} from "@react-types/shared";
import type {FocusableProps, PressEvents} from "@react-types/shared";
import type {SlotsToClasses, CardSlots, CardVariantProps} from "@nextui-org/theme";
import {card} from "@nextui-org/theme";
import {MouseEvent, useCallback, useMemo} from "react";
import {mergeProps} from "@react-aria/utils";
import {useFocusRing} from "@react-aria/focus";
import {useHover, usePress} from "@react-aria/interactions";
import {HTMLNextUIProps} from "@nextui-org/system";
import {NormalWeights, ReactRef, warn} from "@nextui-org/shared-utils";
import {useHover} from "@react-aria/interactions";
import {useButton as useAriaButton} from "@react-aria/button";
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
import {callAllHandlers, clsx, ReactRef} from "@nextui-org/shared-utils";
import {useDOMRef} from "@nextui-org/dom-utils";
import {useDrip} from "@nextui-org/drip";
import {AriaButtonProps} from "@react-aria/button";
export interface UseCardProps extends HTMLNextUIProps<"div", PressEvents & FocusableProps> {
export interface Props extends HTMLNextUIProps<"div"> {
/**
* The card ref.
* Ref to the DOM node.
*/
ref: ReactRef<HTMLDivElement | null>;
/**
* The card variant style.
* @default "shadow"
*/
variant?: "shadow" | "flat" | "bordered";
/**
* The border weight of the `bordered` variant card.
* @default "normal"
*/
borderWeight?: NormalWeights;
/**
* Whether the card should allow users to interact with the card.
* @default false
*/
isPressable?: boolean;
/**
* Whether the card can be hovered by the user.
* @default false
*/
isHoverable?: boolean;
/**
* Whether the card should show a ripple animation on press
* @default false
*/
disableRipple?: boolean;
// @deprecated - use `onPress` instead
onClick?: React.MouseEventHandler<HTMLDivElement>;
/**
* Whether the card is animated.
* @default false
*/
disableAnimation?: boolean;
/**
* Whether the card should allow text selection on press. (only for pressable cards)
* @default true
*/
allowTextSelectionOnPress?: boolean;
/**
* Classname or List of classes to change the styles of the element.
* if `className` is passed, it will be added to the base slot.
*
* @example
* ```ts
* <Card styles={{
* base:"base-classes",
* header: "dot-classes",
* body: "content-classes",
* footer: "avatar-classes",
* }} />
* ```
*/
styles?: SlotsToClasses<CardSlots>;
}
export function useCard(props: UseCardProps) {
export type UseCardProps = Props & PressEvents & FocusableProps & CardVariantProps;
export function useCard(originalProps: UseCardProps) {
const [props, variantProps] = mapPropsVariants(originalProps, card.variantKeys);
const {
ref,
as,
children,
disableAnimation = false,
disableRipple = false,
variant = "shadow",
isHoverable = false,
borderWeight = "light",
isPressable = false,
onClick: deprecatedOnClick,
onClick,
onPress,
autoFocus,
className,
styles,
allowTextSelectionOnPress = true,
...otherProps
} = props;
const cardRef = useDOMRef<HTMLDivElement>(ref);
const Component = as || (isPressable ? "button" : "div");
const domRef = useDOMRef<HTMLDivElement>(ref);
const Component = as || (originalProps.isPressable ? "button" : "div");
const {onClick: onDripClickHandler, ...dripBindings} = useDrip(false, cardRef);
const baseStyles = clsx(styles?.base, className);
const handleDrip = (e: MouseEvent<HTMLDivElement> | PressEvent | Event) => {
if (!disableAnimation && !disableRipple && cardRef.current) {
const {onClick: onDripClickHandler, drips} = useDrip();
const handleDrip = (e: MouseEvent<HTMLDivElement>) => {
if (!originalProps.disableAnimation && !disableRipple && domRef.current) {
onDripClickHandler(e);
}
};
const handlePress = (e: PressEvent) => {
if (e.pointerType === "keyboard" || e.pointerType === "virtual") {
handleDrip(e);
} else if (typeof window !== "undefined" && window.event) {
handleDrip(window.event);
}
if (deprecatedOnClick) {
deprecatedOnClick(e as any);
warn("onClick is deprecated, please use onPress", "Card");
}
onPress?.(e);
};
const {isPressed, pressProps} = usePress({
isDisabled: !isPressable,
onPress: handlePress,
allowTextSelectionOnPress,
...otherProps,
});
const {buttonProps, isPressed} = useAriaButton(
{
elementType: as,
isDisabled: !originalProps.isPressable,
onPress,
onClick: callAllHandlers(onClick, handleDrip),
allowTextSelectionOnPress,
...otherProps,
} as AriaButtonProps,
domRef,
);
const {hoverProps, isHovered} = useHover({
isDisabled: !isHoverable,
isDisabled: !originalProps.isHoverable,
...otherProps,
});
@ -113,49 +99,57 @@ export function useCard(props: UseCardProps) {
autoFocus,
});
const styles = useMemo(
const slots = useMemo(
() =>
card({
borderWeight,
className,
disableAnimation,
isPressable,
isHoverable,
variant,
...variantProps,
isFocusVisible,
}),
[disableAnimation, variant, borderWeight, isPressable, isHoverable],
[...Object.values(variantProps), isFocusVisible],
);
const getCardProps = useCallback(
const getCardProps = useCallback<PropGetter>(
(props = {}) => {
return {
ref: domRef,
className: slots.base({class: baseStyles}),
role: originalProps.isPressable ? "button" : "section",
tabIndex: originalProps.isPressable ? 0 : -1,
...mergeProps(
isPressable ? {...pressProps, ...focusProps} : {},
isHoverable ? hoverProps : {},
originalProps.isPressable ? {...buttonProps, ...focusProps} : {},
originalProps.isHoverable ? hoverProps : {},
otherProps,
props,
),
};
},
[isPressable, isHoverable, pressProps, focusProps, hoverProps, otherProps],
[
domRef,
slots,
baseStyles,
originalProps.isPressable,
originalProps.isHoverable,
buttonProps,
focusProps,
hoverProps,
otherProps,
],
);
return {
cardRef,
domRef,
Component,
styles,
variant,
children,
borderWeight,
isPressable,
drips,
isHovered,
isPressed,
disableAnimation,
isPressable: originalProps.isPressable,
isHoverable: originalProps.isHoverable,
disableAnimation: originalProps.disableAnimation,
disableRipple,
dripBindings,
onDripClickHandler,
isFocusVisible,
className,
getCardProps,
};
}

View File

@ -24,7 +24,7 @@ const button = tv({
"outline-none",
"select-none",
"font-medium",
"antialiased",
"subpixel-antialiased",
"active:scale-95",
"overflow-hidden",
"gap-3",

View File

@ -1,22 +1,42 @@
import {tv, type VariantProps} from "tailwind-variants";
import {focusVisibleClasses} from "../../utils";
import {ringClasses} from "../utils";
/**
* Card **Tailwind Variants** component
*
* @example
* <div className={card()}>A basic card</div>
* ```js
* const {base, header, body, footer} = card({...})
*
* <div className={card()}>
* <div className={header()}>Header</div>
* <div className={body()}>Body</div>
* <div className={footer()}>Footer</div>
* </div>
* ```
*/
const card = tv({
slots: {
base: [
...focusVisibleClasses,
"flex flex-col m-0 p-0 relative overflow-hidden w-full height-auto bg-white text-foreground rounded-xl box-border dark:bg-neutral-900 dark:text-foreground-dark",
"flex",
"flex-col",
"m-0",
"p-0",
"relative",
"overflow-hidden",
"w-full",
"height-auto",
"bg-white",
"text-foreground",
"rounded-xl",
"box-border",
"dark:bg-neutral-900",
"dark:text-foreground-dark",
],
header: "",
body: "",
footer: "",
header: "",
},
variants: {
variant: {
@ -37,6 +57,11 @@ const card = tv({
isPressable: {
true: "cursor-pointer",
},
isFocusVisible: {
true: {
base: [...ringClasses],
},
},
disableAnimation: {
true: "",
false: "!transition motion-reduce:transition-none",
@ -82,6 +107,7 @@ const card = tv({
defaultVariants: {
variant: "shadow",
isHoverable: false,
isPressable: false,
},
});

View File

@ -5,9 +5,10 @@ import {ringClasses, colorVariants} from "../utils";
/**
* Chip wrapper **Tailwind Variants** component
*
* @example
* ```js
* const {base, content, dot, avatar, closeButton} = chip({...})
*
* @example
* <div className={base())}>
* // left content
* <span className={avatar()}/>
@ -16,6 +17,7 @@ import {ringClasses, colorVariants} from "../utils";
* <svg className={closeButton()}>close button</svg>
* // right content
* </div>
* ```
*/
const chip = tv({
slots: {

2
pnpm-lock.yaml generated
View File

@ -437,6 +437,7 @@ importers:
'@nextui-org/shared-utils': workspace:*
'@nextui-org/system': workspace:*
'@nextui-org/theme': workspace:*
'@react-aria/button': ^3.7.0
'@react-aria/focus': ^3.11.0
'@react-aria/interactions': ^3.14.0
'@react-aria/utils': ^3.15.0
@ -450,6 +451,7 @@ importers:
'@nextui-org/shared-utils': link:../../utilities/shared-utils
'@nextui-org/system': link:../../core/system
'@nextui-org/theme': link:../../core/theme
'@react-aria/button': 3.7.0_react@18.2.0
'@react-aria/focus': 3.11.0_react@18.2.0
'@react-aria/interactions': 3.14.0_react@18.2.0
'@react-aria/utils': 3.15.0_react@18.2.0