feat(snippet): migrated

This commit is contained in:
Junior Garcia 2023-02-21 15:26:12 -03:00
parent 27f2ae1fab
commit 3789144e63
26 changed files with 726 additions and 79 deletions

View File

@ -9,5 +9,8 @@ export type {AvatarGroupProps} from "./avatar-group";
export {useAvatar} from "./use-avatar";
export {useAvatarGroup} from "./use-avatar-group";
// export misc
export {AvatarIcon} from "./avatar-icon";
// export component
export {Avatar, AvatarGroup};

View File

@ -54,7 +54,7 @@ export function useButtonGroup(originalProps: UseButtonGroupProps) {
...variantProps,
className,
}),
[variantProps, className],
[...Object.values(variantProps), className],
);
const context = useMemo<ContextType>(

View File

@ -28,7 +28,7 @@ export function useCode(originalProps: UseCodeProps) {
...variantProps,
className,
}),
[variantProps, className],
[...Object.values(variantProps), className],
);
return {Component, as, styles, domRef, ...otherProps};

View File

@ -1,9 +1,13 @@
import Link from "./link";
// export types
export type {LinkProps} from "./link";
// export hooks
export {useLink} from "./use-link";
// export component
// export misc
export {LinkIcon} from "./link-icon";
export {default as Link} from "./link";
// export component
export {Link};

View File

@ -58,7 +58,7 @@ export function useLink(originalProps: UseLinkProps) {
...variantProps,
className,
}),
[variantProps, className],
[...Object.values(variantProps), className],
);
return {Component, as, styles, domRef, linkProps, showAnchorIcon, ...otherProps};

View File

@ -29,17 +29,16 @@ export default {
},
} as ComponentMeta<typeof Link>;
const text = `"First solve the problem. Then, write the code." - Jon Johnson.`;
const children = `"First solve the problem. Then, write the code." - Jon Johnson.`;
const defaultProps = {
...link.defaultVariants,
isDisabled: false,
showAnchorIcon: true,
children,
};
const Template: ComponentStory<typeof Link> = (args: LinkProps) => (
<Link {...args} href="#">
{text}
</Link>
);
const Template: ComponentStory<typeof Link> = (args: LinkProps) => <Link {...args} href="#" />;
export const Default = Template.bind({});
Default.args = {
@ -79,9 +78,11 @@ export const isExternal = Template.bind({}) as any;
isExternal.args = {
...defaultProps,
isExternal: true,
isDisabled: false,
showAnchorIcon: true,
size: "md",
};
export const CustomAchor = Template.bind({}) as any;
CustomAchor.args = {
...defaultProps,
anchorIcon: <CustomLink />,
};

View File

@ -41,7 +41,10 @@
"@nextui-org/theme": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/shared-css": "workspace:*",
"@nextui-org/dom-utils": "workspace:*"
"@nextui-org/dom-utils": "workspace:*",
"@nextui-org/use-clipboard": "workspace:*",
"@nextui-org/tooltip": "workspace:*",
"@react-aria/focus": "^3.9.0"
},
"devDependencies": {
"clean-package": "2.1.1",

View File

@ -1,5 +1,12 @@
// export types
export type {SnippetProps} from "./snippet";
// export hooks
export {useSnippet} from "./use-snippet";
// export misc
export {SnippetCheckIcon} from "./snippet-check-icon";
export {SnippetCopyIcon} from "./snippet-copy-icon";
// export component
export {default as Snippet} from "./snippet";

View File

@ -0,0 +1,14 @@
export const SnippetCheckIcon = () => (
<svg
fill="none"
height="1em"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
viewBox="0 0 24 24"
width="1em"
>
<polyline points="20 6 9 17 4 12" />
</svg>
);

View File

@ -0,0 +1,8 @@
export const SnippetCopyIcon = () => (
<svg aria-hidden="true" height="1em" role="presentation" viewBox="0 0 24 24" width="1em">
<path
d="M20 2H10c-1.103 0-2 .897-2 2v4H4c-1.103 0-2 .897-2 2v10c0 1.103.897 2 2 2h10c1.103 0 2-.897 2-2v-4h4c1.103 0 2-.897 2-2V4c0-1.103-.897-2-2-2zM4 20V10h10l.002 10H4zm16-6h-4v-4c0-1.103-.897-2-2-2h-4V4h10v10z"
fill="currentColor"
/>
</svg>
);

View File

@ -1,23 +0,0 @@
import {NextUI, forwardRef, HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
export interface SnippetIconProps extends HTMLNextUIProps<"svg"> {}
const SnippetIcon = forwardRef<SnippetIconProps, "div">((props, ref) => {
const {className, ...otherProps} = props;
const domRef = useDOMRef(ref);
return (
<NextUI.Svg ref={domRef} className={clsx("nextui-snippet-icon", className)} {...otherProps} />
);
});
if (__DEV__) {
SnippetIcon.displayName = "NextUI.SnippetIcon";
}
SnippetIcon.toString = () => ".nextui-SnippetIcon";
export default SnippetIcon;

View File

@ -1,19 +1,103 @@
import {forwardRef} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {Tooltip} from "@nextui-org/tooltip";
import {ReactNode, useCallback, useMemo} from "react";
import {StyledSnippet} from "./snippet.styles";
import {UseSnippetProps, useSnippet} from "./use-snippet";
import {useSnippet, UseSnippetProps} from "./use-snippet";
import {SnippetCopyIcon} from "./snippet-copy-icon";
import {SnippetCheckIcon} from "./snippet-check-icon";
export interface SnippetProps extends UseSnippetProps {}
export interface SnippetProps extends Omit<UseSnippetProps, "ref"> {}
const Snippet = forwardRef<SnippetProps, "div">((props, ref) => {
const {className, ...otherProps} = useSnippet(props);
const {
Component,
domRef,
children,
slots,
styles,
copied,
copyIcon = <SnippetCopyIcon />,
checkIcon = <SnippetCheckIcon />,
symbolBefore,
disableCopy,
disableTooltip,
hideSymbol,
hideCopyButton,
tooltipProps,
isMultiLine,
getSnippetProps,
focusProps,
onCopy,
} = useSnippet({ref, ...props});
const domRef = useDOMRef(ref);
const TooltipContent = useCallback(
({children}: {children?: ReactNode}) => <Tooltip {...tooltipProps}>{children}</Tooltip>,
[...Object.values(tooltipProps)],
);
const contents = useMemo(() => {
if (hideCopyButton) {
return null;
}
const copyButton = (
<button
className={slots.copy({
class: clsx(disableCopy && "opacity-50 cursor-not-allowed", styles?.copy),
})}
onClick={onCopy}
{...focusProps}
>
{copied ? checkIcon : copyIcon}
</button>
);
if (disableTooltip) {
return copyButton;
}
return <TooltipContent>{copyButton}</TooltipContent>;
}, [
slots,
styles?.copy,
copied,
checkIcon,
copyIcon,
onCopy,
TooltipContent,
disableCopy,
disableTooltip,
hideCopyButton,
]);
const preContent = useMemo(() => {
if (isMultiLine && children && Array.isArray(children)) {
return (
<div className="flex flex-col">
{children.map((t, index) => (
<pre key={`${index}-${t}`} className={slots.pre({class: styles?.pre})}>
{!hideSymbol && <span className="select-none">{symbolBefore}</span>}
{t}
</pre>
))}
</div>
);
}
return (
<pre className={slots.pre({class: styles?.pre})}>
{!hideSymbol && <span className="select-none">{symbolBefore}</span>}
{children}
</pre>
);
}, [children, hideSymbol, isMultiLine, symbolBefore, styles?.pre, slots]);
return (
<StyledSnippet ref={domRef} className={clsx("nextui-snippet", className)} {...otherProps} />
<Component ref={domRef} {...getSnippetProps()}>
{preContent}
{contents}
</Component>
);
});
@ -21,6 +105,4 @@ if (__DEV__) {
Snippet.displayName = "NextUI.Snippet";
}
Snippet.toString = () => ".nextui-snippet";
export default Snippet;

View File

@ -1,11 +1,199 @@
import {HTMLNextUIProps} from "@nextui-org/system";
import type {SnippetVariantProps, SnippetSlots, SlotsToClasses} from "@nextui-org/theme";
export interface UseSnippetProps extends HTMLNextUIProps<"div"> {}
import {snippet} from "@nextui-org/theme";
import {HTMLNextUIProps, mapPropsVariants} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, ReactRef} from "@nextui-org/shared-utils";
import {useClipboard} from "@nextui-org/use-clipboard";
import {useFocusRing} from "@react-aria/focus";
import {useMemo, useCallback} from "react";
import {TooltipProps} from "@nextui-org/tooltip";
export interface UseSnippetProps
extends Omit<HTMLNextUIProps<"div">, "onCopy">,
SnippetVariantProps {
/**
* Ref to the DOM node.
*/
ref?: ReactRef<HTMLDivElement | null>;
/**
* The content of the snippet.
* if `string[]` is passed, it will be rendered as a multi-line snippet.
*/
children?: React.ReactNode | string | string[];
/**
* The symbol to show before the snippet.
* @default "$"
*/
symbol?: string | React.ReactNode;
/**
* The time in milliseconds to wait before resetting the clipboard.
* @default 2000
*/
timeout?: number;
/*
* Snippet copy icon.
*/
copyIcon?: React.ReactNode;
/*
* Snippet copy icon. This icon will be shown when the text is copied.
*/
checkIcon?: React.ReactNode;
/**
* 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
* <Snippet styles={{
* base:"base-classes",
* pre: "pre-classes",
* copy: "copy-classes",
* }} />
* ```
*/
styles?: SlotsToClasses<SnippetSlots>;
/**
* Whether the copy button should receive focus on render.
* @default false
*/
autoFocus?: boolean;
/**
* Whether to hide the tooltip.
* @default false
*/
disableTooltip?: boolean;
/**
* Whether to disable the copy functionality.
* @default false
*/
disableCopy?: boolean;
/**
* Whether to hide the copy button.
* @default false
*/
hideCopyButton?: boolean;
/**
* Whether to hide the symbol.
* @default false
*/
hideSymbol?: boolean;
/**
* Tooltip props.
*/
tooltipProps?: TooltipProps;
/**
* Callback when the text is copied.
*/
onCopy?: (value: string | string[]) => void;
}
export function useSnippet(props: UseSnippetProps) {
const {...otherProps} = props;
export function useSnippet(originalProps: UseSnippetProps) {
const [props, variantProps] = mapPropsVariants(originalProps, snippet.variantKeys);
return {...otherProps};
const {
ref,
as,
children,
symbol = "$",
styles,
timeout,
copyIcon,
checkIcon,
disableCopy = false,
disableTooltip = false,
hideCopyButton = false,
autoFocus = false,
hideSymbol = false,
onCopy: onCopyProp,
tooltipProps = {
offset: 12,
content: "Copy to clipboard",
size: originalProps?.size as TooltipProps["size"],
variant: originalProps?.variant as TooltipProps["variant"],
color: originalProps?.color as TooltipProps["color"],
isDisabled: disableCopy,
},
className,
...otherProps
} = props;
const Component = as || "div";
const domRef = useDOMRef(ref);
const {copy, copied} = useClipboard({timeout});
const isMultiLine = children && Array.isArray(children);
const {isFocusVisible, focusProps} = useFocusRing({
autoFocus,
});
const slots = useMemo(
() =>
snippet({
...variantProps,
isFocusVisible,
}),
[...Object.values(variantProps), isFocusVisible],
);
const symbolBefore = useMemo(() => {
if (!symbol || typeof symbol !== "string") return symbol;
const str = symbol.trim();
return str ? `${str} ` : "";
}, [symbol]);
const baseStyles = clsx(styles?.base, className);
const getSnippetProps = useCallback(
() => ({
className: slots.base({
class: baseStyles,
}),
...otherProps,
}),
[slots, baseStyles, isMultiLine, otherProps],
);
const onCopy = useCallback(() => {
if (disableCopy) {
return;
}
let value = "";
if (typeof children === "string") {
value = children;
} else if (Array.isArray(children)) {
value = children.join("\n");
}
copy(value);
onCopyProp?.(value);
}, [copy, disableCopy, onCopyProp, children]);
return {
Component,
as,
domRef,
children,
slots,
styles,
copied,
onCopy,
copyIcon,
checkIcon,
symbolBefore,
isMultiLine,
isFocusVisible,
focusProps,
hideCopyButton,
disableCopy,
disableTooltip,
hideSymbol,
tooltipProps,
getSnippetProps,
};
}
export type UseSnippetReturn = ReturnType<typeof useSnippet>;

View File

@ -1,11 +1,87 @@
import React from "react";
import {Meta} from "@storybook/react";
import {ComponentStory, ComponentMeta} from "@storybook/react";
import {snippet} from "@nextui-org/theme";
import {Snippet} from "../src";
import {Snippet, SnippetProps} from "../src";
export default {
title: "Snippet",
title: "Display/Snippet",
component: Snippet,
} as Meta;
argTypes: {
variant: {
control: {
type: "select",
options: ["flat", "solid", "bordered", "shadow"],
},
},
color: {
control: {
type: "select",
options: ["neutral", "primary", "secondary", "success", "warning", "danger"],
},
},
radius: {
control: {
type: "select",
options: ["none", "base", "sm", "md", "lg", "xl", "full"],
},
},
size: {
control: {
type: "select",
options: ["xs", "sm", "md", "lg", "xl"],
},
},
fullWidth: {
control: {
type: "boolean",
},
},
disableCopy: {
control: {
type: "boolean",
},
},
disableTooltip: {
control: {
type: "boolean",
},
},
hideCopyButton: {
control: {
type: "boolean",
},
},
hideSymbol: {
control: {
type: "boolean",
},
},
},
} as ComponentMeta<typeof Snippet>;
export const Default = () => <Snippet />;
const defaultProps = {
children: "npm install @nextui-org/react",
disableCopy: false,
disableTooltip: false,
hideCopyButton: false,
hideSymbol: false,
...snippet.defaultVariants,
};
const Template: ComponentStory<typeof Snippet> = (args: SnippetProps) => <Snippet {...args} />;
export const Default = Template.bind({});
Default.args = {
...defaultProps,
};
export const MultiLine = Template.bind({});
MultiLine.args = {
...defaultProps,
children: [
"npm install @nextui-org/react",
"yarn add @nextui-org/react",
"pnpm add @nextui-org/react",
],
};

View File

@ -16,7 +16,7 @@ export interface UseSpinnerProps extends HTMLNextUIProps<"div", SpinnerVariantPr
*/
label?: string;
/**
* Classname or List of classes to change the styles of the avatar.
* 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
@ -39,7 +39,7 @@ export function useSpinner(originalProps: UseSpinnerProps) {
const domRef = useDOMRef(ref);
const slots = useMemo(() => spinner({...variantProps}), [variantProps]);
const slots = useMemo(() => spinner({...variantProps}), [...Object.values(variantProps)]);
const baseStyles = clsx(styles?.base, className);

View File

@ -7,6 +7,7 @@ module.exports = {
"../../spinner/stories/*.stories.@(js|jsx|ts|tsx)",
"../../code/stories/*.stories.@(js|jsx|ts|tsx)",
"../../tooltip/stories/*.stories.@(js|jsx|ts|tsx)",
"../../snippet/stories/*.stories.@(js|jsx|ts|tsx)",
],
staticDirs: ["../public"],
addons: [
@ -14,7 +15,17 @@ module.exports = {
"@storybook/addon-essentials",
"storybook-dark-mode",
"@storybook/addon-a11y",
"@storybook/addon-storysource",
{
name: '@storybook/addon-storysource',
options: {
rule: {
test: [/\.stories\.(js|jsx|ts|tsx)$/],
},
loaderOptions: {
prettierConfig: { printWidth: 80, singleQuote: false },
},
},
},
{
name: "@storybook/addon-postcss",
options: {

View File

@ -48,7 +48,7 @@
"@storybook/addon-interactions": "^6.5.10",
"@storybook/addon-links": "^6.5.12",
"@storybook/addon-postcss": "^2.0.0",
"@storybook/addon-storysource": "^6.5.12",
"@storybook/addon-storysource": "^6.5.16",
"@storybook/addons": "^6.5.16",
"@storybook/builder-webpack5": "^6.5.12",
"@storybook/manager-webpack5": "^6.5.12",
@ -56,9 +56,9 @@
"@storybook/theming": "^6.5.16",
"autoprefixer": "^10.4.13",
"babel-loader": "^8.2.3",
"concurrently": "^7.6.0",
"postcss": "^8.4.21",
"storybook-dark-mode": "^1.1.2",
"concurrently": "^7.6.0",
"tailwindcss": "^3.2.4"
},
"tsup": {

View File

@ -159,9 +159,9 @@ export function useTooltip(originalProps: UseTooltipProps) {
const transitionProps = useMemo<CSSTransitionProps>(
() => ({
clearTime: originalProps?.disableAnimation ? 0 : 100,
enterTime: originalProps?.disableAnimation ? 0 : 250,
leaveTime: originalProps?.disableAnimation ? 0 : 60,
clearTime: originalProps?.disableAnimation ? 0 : 60,
isVisible: state.isOpen,
onEntered: onEntered,
onExited: onExited,
@ -175,7 +175,7 @@ export function useTooltip(originalProps: UseTooltipProps) {
...variantProps,
className,
}),
[variantProps, className],
[...Object.values(variantProps), className],
);
const getTriggerProps = useCallback(
@ -183,7 +183,7 @@ export function useTooltip(originalProps: UseTooltipProps) {
...mergeProps(triggerProps, props),
ref: mergeRefs(triggerRef, _ref),
onPointerEnter: () => state.open(),
onPointerLeave: () => !isDismissable && state.close(),
onPointerLeave: () => isDismissable && state.close(),
}),
[isDismissable, triggerRef, triggerProps],
);

View File

@ -101,6 +101,30 @@ export function rootStyled<T extends As, P = {}>(component: T) {
return Component as NextUIComponent<T, P>;
}
export const toIterator = (obj: any) => {
return {
...obj,
[Symbol.iterator]: function () {
const keys = Object.keys(this);
let index = 0;
return {
next: () => {
if (index >= keys.length) {
return {done: true};
}
const key = keys[index];
const value = this[key];
index++;
return {value: {key, value}, done: false};
},
};
},
};
};
export const mapPropsVariants = <T extends Record<string, any>, K extends keyof T>(
props: T,
variantKeys?: K[],

View File

@ -8,3 +8,4 @@ export * from "./drip";
export * from "./spinner";
export * from "./code";
export * from "./tooltip";
export * from "./snippet";

View File

@ -1,22 +1,253 @@
import {tv, type VariantProps} from "tailwind-variants";
import {ringClasses} from "../../utils";
/**
* Snippet wrapper **Tailwind Variants** component
*
* const {base, svg} = snippet({...})
* const {base, pre, copy} = snippet({...})
*
* @example
* <div className={base())}>
* <svg className={svg()}>
* // drip svg content
* </svg>
* <pre className={pre()}>
* // code snippet
* </pre>
* <button className={copy()}>
* <svg>
* // copy icon
* </svg>
* </button>
* </div>
*/
const snippet = tv({
slots: {
base: "",
svg: "",
base: "inline-flex items-center justify-between space-x-3 rounded-md",
pre: "bg-transparent text-inherit font-mono whitespace-pre-wrap",
copy: "z-10 apparance-none outline-none select-none",
},
variants: {
variant: {
flat: "",
solid: "",
bordered: "border-2 !bg-transparent",
shadow: "",
},
color: {
neutral: {
base: "text-neutral-800 bg-neutral-100 dark:text-neutral-100 dark:bg-neutral-800",
},
primary: {
base: "bg-primary-50 dark:bg-primary-900 text-primary",
},
secondary: {
base: "bg-secondary-50 dark:bg-secondary-900 text-secondary dark:text-secondary-400",
},
success: {
base: "bg-success-50 dark:bg-success-900 text-success-600 dark:text-success",
},
warning: {
base: "bg-warning-50 dark:bg-warning-900 text-warning-600 dark:text-warning",
},
danger: {
base: "bg-danger-50 dark:bg-danger-900 text-danger",
},
},
size: {
xs: {
base: "px-2 py-1 text-xs",
},
sm: {
base: "px-2 py-1 text-sm",
},
md: {
base: "px-3 py-1.5 text-base",
},
lg: {
base: "px-4 py-2 text-lg",
},
xl: {
base: "px-4 py-2 text-xl",
},
},
radius: {
none: {
base: "rounded-none",
},
base: {
base: "rounded-base",
},
sm: {
base: "rounded-sm",
},
md: {
base: "rounded-md",
},
lg: {
base: "rounded-lg",
},
xl: {
base: "rounded-xl",
},
full: {
base: "rounded-full",
},
},
fullWidth: {
true: {
base: "w-full",
},
},
isFocusVisible: {
true: {
copy: [
...ringClasses,
"ring-1",
"rounded-sm",
"ring-offset-transparent",
"dark:ring-offset-transparent",
],
},
},
},
defaultVariants: {
color: "neutral",
variant: "flat",
size: "md",
radius: "lg",
fullWidth: false,
isFocusVisible: false,
},
compoundVariants: [
// solid & shadow / color
{
variant: ["solid", "shadow"],
color: "neutral",
class: {
base: "bg-neutral-300 dark:bg-neutral-700 text-neutral-800 dark:text-neutral-100",
},
},
{
variant: ["solid", "shadow"],
color: "primary",
class: {
base: "bg-primary text-white",
},
},
{
variant: ["solid", "shadow"],
color: "secondary",
class: {
base: "bg-secondary text-white",
},
},
{
variant: ["solid", "shadow"],
color: "success",
class: {
base: "bg-success text-success-800",
},
},
{
variant: ["solid", "shadow"],
color: "warning",
class: {
base: "bg-warning text-warning-800",
},
},
{
variant: ["solid", "shadow"],
color: "danger",
class: {
base: "bg-danger text-white",
},
},
// shadow / color
{
variant: "shadow",
color: "neutral",
class: {
base: "shadow-lg shadow-neutral/40",
},
},
{
variant: "shadow",
color: "primary",
class: {
base: "shadow-lg shadow-primary/40",
},
},
{
variant: "shadow",
color: "secondary",
class: {
base: "shadow-lg shadow-secondary/40",
},
},
{
variant: "shadow",
color: "success",
class: {
base: "shadow-lg shadow-success/40",
},
},
{
variant: "shadow",
color: "warning",
class: {
base: "shadow-lg shadow-warning/40",
},
},
{
variant: "shadow",
color: "danger",
class: {
base: "shadow-lg shadow-danger/40",
},
},
// bordered / color
{
variant: "bordered",
color: "neutral",
class: {
base: "border-neutral-300 dark:border-neutral-700 text-neutral-700 dark:text-neutral-100",
},
},
{
variant: "bordered",
color: "primary",
class: {
base: "border-primary text-primary",
},
},
{
variant: "bordered",
color: "secondary",
class: {
base: "border-secondary text-secondary",
},
},
{
variant: "bordered",
color: "success",
class: {
base: "border-success text-success",
},
},
{
variant: "bordered",
color: "warning",
class: {
base: "border-warning text-warning",
},
},
{
variant: "bordered",
color: "danger",
class: {
base: "border-danger text-danger",
},
},
],
});
export type SnippetVariantProps = VariantProps<typeof snippet>;

View File

@ -46,8 +46,8 @@ const spinner = tv({
size: {
xs: {
base: "w-4 h-4",
circle1: "border-2",
circle2: "border-2",
circle1: "border-1.5",
circle2: "border-1.5",
label: "translate-y-6 text-xs",
},
sm: {
@ -58,14 +58,14 @@ const spinner = tv({
},
md: {
base: "w-8 h-8",
circle1: "border-[3px]",
circle2: "border-[3px]",
circle1: "border-3",
circle2: "border-3",
label: "translate-y-8 text-sm",
},
lg: {
base: "w-10 h-10",
circle1: "border-[3px]",
circle2: "border-[3px]",
circle1: "border-3",
circle2: "border-3",
label: "translate-y-10 text-base",
},
xl: {

View File

@ -212,6 +212,12 @@ const tooltip = tv({
color: "danger",
class: "text-danger",
},
// size (xs) / bordered
{
size: "xs",
variant: "bordered",
class: "border-1.5",
},
],
});

View File

@ -151,6 +151,11 @@ module.exports = plugin(
DEFAULT: colors.pink[500],
},
},
borderWidth: {
1.5: "1.5px",
3: "3px",
5: "5px",
},
animation: {
"drip-expand": "drip-expand 350ms linear",
"spinner-ease-spin": "spinner-spin 0.8s ease infinite",

View File

@ -29,7 +29,7 @@ export function use{{capitalize componentName}}(originalProps: Use{{capitalize c
...variantProps,
className,
}),
[variantProps, className],
[...Object.values(variantProps), className],
);
return {Component, styles, domRef, ...otherProps};

8
pnpm-lock.yaml generated
View File

@ -658,6 +658,9 @@ importers:
'@nextui-org/shared-utils': workspace:*
'@nextui-org/system': workspace:*
'@nextui-org/theme': workspace:*
'@nextui-org/tooltip': workspace:*
'@nextui-org/use-clipboard': workspace:*
'@react-aria/focus': ^3.9.0
clean-package: 2.1.1
react: ^17.0.2
dependencies:
@ -666,6 +669,9 @@ importers:
'@nextui-org/shared-utils': link:../../utilities/shared-utils
'@nextui-org/system': link:../../core/system
'@nextui-org/theme': link:../../core/theme
'@nextui-org/tooltip': link:../tooltip
'@nextui-org/use-clipboard': link:../../hooks/use-clipboard
'@react-aria/focus': 3.10.1_react@17.0.2
devDependencies:
clean-package: 2.1.1
react: 17.0.2
@ -701,7 +707,7 @@ importers:
'@storybook/addon-interactions': ^6.5.10
'@storybook/addon-links': ^6.5.12
'@storybook/addon-postcss': ^2.0.0
'@storybook/addon-storysource': ^6.5.12
'@storybook/addon-storysource': ^6.5.16
'@storybook/addons': ^6.5.16
'@storybook/builder-webpack5': ^6.5.12
'@storybook/manager-webpack5': ^6.5.12