feat(chip): dot variant added, tests added

This commit is contained in:
Junior Garcia 2023-03-03 15:59:09 -03:00
parent c45109c8f4
commit 417ccc8c0b
9 changed files with 145 additions and 36 deletions

View File

@ -1,5 +1,6 @@
import * as React from "react";
import {render} from "@testing-library/react";
import {Avatar} from "@nextui-org/avatar";
import {Chip} from "../src";
@ -16,4 +17,43 @@ describe("Chip", () => {
render(<Chip ref={ref} />);
expect(ref.current).not.toBeNull();
});
it("should render with dot variant", () => {
const wrapper = render(<Chip variant="dot" />);
expect(wrapper.container.querySelector("span")).not.toBeNull();
});
it("should support avatar", () => {
const wrapper = render(<Chip avatar={<Avatar data-testid="avatar" />} />);
expect(wrapper.getByTestId("avatar")).not.toBeNull();
});
it("should support leftContent", () => {
const wrapper = render(<Chip leftContent={<span data-testid="left-icon" />} />);
expect(wrapper.getByTestId("left-icon")).not.toBeNull();
});
it("should support rightContent", () => {
const wrapper = render(<Chip avatar={<span data-testid="close-icon" />} />);
expect(wrapper.getByTestId("close-icon")).not.toBeNull();
});
it("should display a close button if onClose is passed", () => {
const wrapper = render(<Chip onClose={() => {}} />);
expect(wrapper.getByRole("button")).not.toBeNull();
});
it("should call onClose when close button is clicked", () => {
const onClose = jest.fn();
const {getByRole} = render(<Chip onClose={onClose} />);
getByRole("button").click();
expect(onClose).toHaveBeenCalled();
});
});

View File

@ -30,7 +30,7 @@ const Chip = forwardRef<ChipProps, "div">((props, ref) => {
}
return leftContent;
}, [leftContent, variant]);
}, [slots, leftContent, variant]);
const right = useMemo(() => {
if (isCloseable) {

View File

@ -15,8 +15,13 @@ export interface UseChipProps extends HTMLNextUIProps<"div">, ChipVariantProps {
* Ref to the DOM node.
*/
ref?: ReactRef<HTMLDivElement | null>;
/**
* Avatar to be rendered in the left side of the chip.
*/
avatar?: React.ReactNode;
/**
* Element to be rendered in the left side of the chip.
* this props overrides the `avatar` prop.
*/
leftContent?: React.ReactNode;
/**
@ -33,6 +38,7 @@ export interface UseChipProps extends HTMLNextUIProps<"div">, ChipVariantProps {
* base:"base-classes",
* dot: "dot-classes",
* label: "label-classes",
* avatar: "avatar-classes",
* closeButton: "close-button-classes",
* }} />
* ```
@ -48,8 +54,18 @@ export interface UseChipProps extends HTMLNextUIProps<"div">, ChipVariantProps {
export function useChip(originalProps: UseChipProps) {
const [props, variantProps] = mapPropsVariants(originalProps, chip.variantKeys);
const {ref, as, children, leftContent, rightContent, onClose, styles, className, ...otherProps} =
props;
const {
ref,
as,
children,
avatar,
leftContent,
rightContent,
onClose,
styles,
className,
...otherProps
} = props;
const Component = as || "div";
@ -98,11 +114,20 @@ export function useChip(originalProps: UseChipProps) {
};
};
const getAvatarClone = (avatar: ReactNode) => {
if (!isValidElement(avatar)) return null;
return cloneElement(avatar, {
// @ts-ignore
className: slots.avatar({class: styles?.avatar}),
});
};
const getContentClone = (content: ReactNode) =>
isValidElement(content)
? cloneElement(content, {
// @ts-ignore
className: clsx("w-full h-4/5", content.props.className),
className: clsx("max-h-[80%]", content.props.className),
})
: null;
@ -112,7 +137,7 @@ export function useChip(originalProps: UseChipProps) {
slots,
styles,
variant: originalProps.variant,
leftContent: getContentClone(leftContent),
leftContent: getAvatarClone(avatar) || getContentClone(leftContent),
rightContent: getContentClone(rightContent),
isCloseable,
getCloseButtonProps,

View File

@ -34,11 +34,6 @@ export default {
options: ["xs", "sm", "md", "lg", "xl"],
},
},
fullWidth: {
control: {
type: "boolean",
},
},
isDisabled: {
control: {
type: "boolean",
@ -79,5 +74,5 @@ WithAvatar.args = {
...defaultProps,
variant: "flat",
color: "secondary",
leftContent: <Avatar name="JW" src="https://i.pravatar.cc/300?u=a042581f4e29026709d" />,
avatar: <Avatar name="JW" src="https://i.pravatar.cc/300?u=a042581f4e29026709d" />,
};

View File

@ -40,7 +40,7 @@ const badge = tv({
solid: {},
flat: {},
faded: {
badge: "border-2",
badge: "border-1.5",
},
shadow: {},
},

View File

@ -31,12 +31,12 @@ const button = tv({
variants: {
variant: {
solid: "",
bordered: "border-2 !bg-transparent",
bordered: "border-1.5 !bg-transparent",
light: "!bg-transparent",
flat: "",
faded: "border-2",
faded: "border-1.5",
shadow: "",
ghost: "border-2 !bg-transparent",
ghost: "border-1.5 !bg-transparent",
},
size: {
xs: "px-2 h-6 text-xs",

View File

@ -5,21 +5,24 @@ import {ringClasses, colorVariants} from "../utils";
/**
* Chip wrapper **Tailwind Variants** component
*
* const {base, label, dot, closeButton} = chip({...})
* const {base, label, dot, avatar, closeButton} = chip({...})
*
* @example
* <div className={base())}>
* // left content
* <span className={avatar()}/>
* <svg className={dot()}/>
* <label className={label()}>Default</label>
* <svg className={closeButton()}>close button</svg>
* // right content
* </div>
*/
const chip = tv({
slots: {
base: ["relative", "inline-flex", "items-center", "justify-between", "box-border"],
label: "flex-1 text-inherit select-none font-regular",
dot: ["w-2", "h-2", "mr-2", "rounded-full"],
dot: ["w-2", "h-2", "mx-1", "rounded-full"],
avatar: "flex-shrink-0",
closeButton: [
"z-10",
"apparance-none",
@ -35,36 +38,38 @@ const chip = tv({
variant: {
solid: {},
bordered: {
base: "border-2 !bg-transparent",
base: "border-1.5 !bg-transparent",
},
light: {
base: "!bg-transparent",
},
flat: {},
faded: {
base: "border-2",
base: "border-1.5",
},
shadow: {},
dot: {},
dot: {
base: "border-1.5 border-neutral text-foreground !bg-transparent",
},
},
color: {
neutral: {
base: colorVariants.solid.neutral,
dot: "bg-neutral-400",
},
primary: {
base: colorVariants.solid.primary,
dot: "bg-primary",
},
secondary: {
base: colorVariants.solid.secondary,
dot: "bg-secondary",
},
success: {
base: colorVariants.solid.success,
dot: "bg-success",
},
warning: {
base: colorVariants.solid.warning,
dot: "bg-warning",
},
danger: {
base: colorVariants.solid.danger,
dot: "bg-danger",
},
},
size: {
@ -72,26 +77,31 @@ const chip = tv({
base: "px-0.5 h-5 text-xs",
label: "px-0.5",
closeButton: "text-sm",
avatar: "w-3.5 h-3.5",
},
sm: {
base: "px-1 h-6 text-sm",
label: "px-1",
closeButton: "text-base",
avatar: "w-4 h-4",
},
md: {
base: "px-1 h-7 text-base",
label: "px-1",
closeButton: "text-lg",
avatar: "w-5 h-5",
},
lg: {
base: "px-1 h-8 text-lg",
base: "px-2 h-8 text-lg",
label: "px-1",
closeButton: "text-xl",
avatar: "w-6 h-6",
},
xl: {
base: "px-1 h-9 text-xl",
base: "px-2 h-9 text-xl",
label: "px-1",
closeButton: "text-2xl",
avatar: "w-7 h-7",
},
},
radius: {
@ -114,9 +124,6 @@ const chip = tv({
isDisabled: {
true: {base: "opacity-50 pointer-events-none"},
},
fullWidth: {
true: {base: "w-full"},
},
isCloseButtonFocusVisible: {
true: {
closeButton: [...ringClasses, "ring-1", "rounded-full"],
@ -128,10 +135,52 @@ const chip = tv({
color: "neutral",
size: "md",
radius: "full",
fullWidth: false,
isDisabled: false,
},
compoundVariants: [
// solid / color
{
variant: "solid",
color: "neutral",
class: {
base: colorVariants.solid.neutral,
},
},
{
variant: "solid",
color: "primary",
class: {
base: colorVariants.solid.primary,
},
},
{
variant: "solid",
color: "secondary",
class: {
base: colorVariants.solid.secondary,
},
},
{
variant: "solid",
color: "success",
class: {
base: colorVariants.solid.success,
},
},
{
variant: "solid",
color: "warning",
class: {
base: colorVariants.solid.warning,
},
},
{
variant: "solid",
color: "danger",
class: {
base: colorVariants.solid.danger,
},
},
// shadow / color
{
variant: "shadow",

View File

@ -29,7 +29,7 @@ const snippet = tv({
variant: {
flat: "",
solid: "",
bordered: "border-2 !bg-transparent",
bordered: "border-1.5 !bg-transparent",
shadow: "",
},
color: {

View File

@ -27,9 +27,9 @@ const tooltip = tv({
variants: {
variant: {
solid: "",
bordered: "border-2 !bg-transparent",
bordered: "border-1.5 !bg-transparent",
light: "!bg-transparent",
faded: "border-2",
faded: "border-1.5",
flat: "",
shadow: "",
},
@ -253,7 +253,7 @@ const tooltip = tv({
{
size: "xs",
variant: "bordered",
class: "border-2",
class: "border-1",
},
],
});