feat: storybook + tw setup, link migrated to tv

This commit is contained in:
Junior Garcia 2023-02-12 18:48:28 -03:00
parent 97451ae514
commit 7fe813c258
17 changed files with 2232 additions and 1896 deletions

View File

@ -1,17 +1,19 @@
const shell = require('shelljs');
const path = require('path');
const path = require("path");
const rootDir = path.join(__dirname, '.');
const contentDir = path.join(rootDir, 'content');
const docsDir = path.join(contentDir, 'docs');
const componentsDocsDir = path.join(docsDir, 'components');
const shell = require("shelljs");
const rootDir = path.join(__dirname, ".");
const contentDir = path.join(rootDir, "content");
const docsDir = path.join(contentDir, "docs");
const componentsDocsDir = path.join(docsDir, "components");
const getComponentsName = () => {
const names = shell
.ls('-R', componentsDocsDir)
.ls("-R", componentsDocsDir)
.map((file) => path.join(process.cwd(), componentsDocsDir, file))
.filter((file) => file.endsWith('.mdx'))
.map((file) => path.basename(file, '.mdx'));
.filter((file) => file.endsWith(".mdx"))
.map((file) => path.basename(file, ".mdx"));
return names;
};
const getComponentsRoute = (names = []) => {
@ -19,60 +21,61 @@ const getComponentsRoute = (names = []) => {
return {
source: `/${name}`,
destination: `/docs/components/${name}`,
permanent: true
permanent: true,
};
});
};
async function redirect() {
const componentsName = getComponentsName();
return [
...getComponentsRoute(componentsName),
{
source: '/docs',
destination: '/docs/guide/getting-started',
permanent: true
},
{
source: '/docs/getting-started',
destination: '/docs/guide/getting-started',
permanent: true
},
{
source: '/guide',
destination: '/docs/guide/getting-started',
permanent: true
},
{
source: '/learn',
destination: '/docs/guide/getting-started',
permanent: true
},
{
source: '/theme',
destination: '/docs/theme/default-theme',
permanent: true
},
{
source: '/docs/theme',
destination: '/docs/theme/default-theme',
permanent: true
},
{
source: '/components/:path*',
source: "/docs",
destination: "/docs/guide/getting-started",
permanent: true,
destination: '/docs/components/:path*'
},
{
source: '/docs/components',
destination: '/docs/components/button',
permanent: true
source: "/docs/getting-started",
destination: "/docs/guide/getting-started",
permanent: true,
},
{
source: '/components',
destination: '/docs/components/button',
permanent: true
}
source: "/guide",
destination: "/docs/guide/getting-started",
permanent: true,
},
{
source: "/learn",
destination: "/docs/guide/getting-started",
permanent: true,
},
{
source: "/theme",
destination: "/docs/theme/default-theme",
permanent: true,
},
{
source: "/docs/theme",
destination: "/docs/theme/default-theme",
permanent: true,
},
{
source: "/components/:path*",
permanent: true,
destination: "/docs/components/:path*",
},
{
source: "/docs/components",
destination: "/docs/components/button",
permanent: true,
},
{
source: "/components",
destination: "/docs/components/button",
permanent: true,
},
];
}

View File

@ -38,6 +38,7 @@
},
"dependencies": {
"@nextui-org/system": "workspace:*",
"@nextui-org/theme": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/shared-css": "workspace:*",
"@nextui-org/dom-utils": "workspace:*",

View File

@ -0,0 +1,64 @@
import type {AriaLinkProps} from "@react-types/link";
import type {LinkVariantProps} from "@nextui-org/theme";
import {useLink as useAriaLink} from "@react-aria/link";
import {link, twMerge} from "@nextui-org/theme";
import {HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {ReactRef} from "@nextui-org/shared-utils";
import {useMemo} from "react";
export interface Props extends HTMLNextUIProps<"a">, LinkVariantProps {
/**
* Ref to the DOM node.
*/
ref?: ReactRef<HTMLAnchorElement | null>;
}
export type UseAvatarProps = Props & AriaLinkProps;
export function useAvatar(props: UseAvatarProps) {
const {
ref,
as = "a",
color,
size,
isUnderline,
isBlock,
disableAnimation,
isExternal = false,
showAnchorIcon = false,
isDisabled = false,
className,
...otherProps
} = props;
const domRef = useDOMRef(ref);
const {linkProps} = useAriaLink({...otherProps, elementType: `${as}`}, domRef);
if (isExternal) {
otherProps.rel = otherProps.rel ?? "noopener";
otherProps.target = otherProps.target ?? "_blank";
}
const classes = useMemo(
() =>
twMerge(
link({
color,
size,
isUnderline,
isBlock,
isDisabled,
disableAnimation,
}),
className,
),
[color, size, isUnderline, isBlock, isDisabled, disableAnimation, className],
);
return {as, classes, domRef, linkProps, showAnchorIcon, isDisabled, ...otherProps};
}
export type UseLinkReturn = ReturnType<typeof useLink>;

View File

@ -1,8 +1,8 @@
import type {AriaLinkProps} from "@react-types/link";
import type {LinkVariantProps} from "@nextui-org/theme";
import {link} from "@nextui-org/theme";
import {useLink as useAriaLink} from "@react-aria/link";
import {link, twMerge} from "@nextui-org/theme";
import {HTMLNextUIProps} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {ReactRef} from "@nextui-org/shared-utils";
@ -64,17 +64,15 @@ export function useLink(props: UseLinkProps) {
const classes = useMemo(
() =>
twMerge(
link({
color,
size,
isUnderline,
isBlock,
isDisabled,
disableAnimation,
}),
link({
color,
size,
isUnderline,
isBlock,
isDisabled,
disableAnimation,
className,
),
}),
[color, size, isUnderline, isBlock, isDisabled, disableAnimation, className],
);

View File

@ -1,8 +1,10 @@
import {ComponentStory, ComponentMeta} from "@storybook/react";
import React from "react";
// import {cva, linkVariants, type VariantProps, ExtendVariantProps} from "@nextui-org/theme";
import {Link, LinkProps} from "../src";
// const meta: Meta<typeof Link> = {
export default {
title: "Navigation/Link",
component: Link,
@ -25,17 +27,20 @@ export default {
},
},
},
};
} as ComponentMeta<typeof Link>;
// type Story = StoryObj<LinkProps>;
const text = `"First solve the problem. Then, write the code." - Jon Johnson.`;
const Template = (args: LinkProps) => (
const Template: ComponentStory<typeof Link> = (args: LinkProps) => (
<Link {...args} href="#">
{text}
</Link>
);
export const Default = Template.bind({}) as any;
export const Default = Template.bind({});
// More on args: https://storybook.js.org/docs/react/writing-stories/args
Default.args = {
isDisabled: false,
color: "foreground",

View File

@ -25,9 +25,16 @@
"url": "https://github.com/nextui-org/nextui/issues"
},
"scripts": {
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook -o storybook-static",
"start-storybook": "pnpx serve storybook-static"
"storybook": "concurrently \"pnpm:watch:*\"",
"build-storybook": "concurrently \"pnpm:build:*\"",
"build:css": "npx tailwindcss -i ./.storybook/style.css -o ./public/tailwind.css",
"build:storybook": "build-storybook build",
"watch:css": "npx tailwindcss -i ./.storybook/style.css -o ./public/tailwind.css --watch",
"watch:storybook": "start-storybook dev -p 6006",
"start:storybook": "pnpx serve storybook-static"
},
"dependencies": {
"@nextui-org/theme": "workspace:*"
},
"devDependencies": {
"@babel/core": "^7.16.7",
@ -51,6 +58,7 @@
"babel-loader": "^8.2.3",
"postcss": "^8.4.21",
"storybook-dark-mode": "^1.1.2",
"concurrently": "^7.6.0",
"tailwindcss": "^3.2.4"
},
"tsup": {

View File

@ -43,15 +43,14 @@
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"dependencies": {
"tailwind-variants": "^0.0.30"
},
"devDependencies": {
"@storybook/addon-storysource": "^6.5.12",
"clean-package": "2.1.1",
"tailwindcss": "^3.2.4"
},
"dependencies": {
"class-variance-authority": "0.4.0",
"tailwind-merge": "^1.8.1"
},
"tsup": {
"clean": true,
"target": "es2019",

View File

@ -0,0 +1,60 @@
// import type {DefaultVariants} from "../../utils";
// export const variants = {
// radius: {
// none: "",
// base: "",
// sm: "",
// md: "",
// lg: "",
// xl: "",
// },
// color: {
// neutral: "",
// primary: "",
// secondary: "",
// success: "",
// warning: "",
// error: "",
// },
// textColor: {
// neutral: "",
// primary: "",
// secondary: "",
// success: "",
// warning: "",
// error: "",
// },
// size: {
// xs: "",
// sm: "",
// md: "",
// lg: "",
// xl: "",
// },
// border: {
// none: "",
// light: "",
// normal: "",
// bold: "",
// extrabold: "",
// },
// isZoomed: {
// true: "",
// false: "",
// },
// isStacked: {
// true: "",
// false: "",
// },
// };
// export type Variants = typeof variants;
// export const defaultVariants: DefaultVariants<Variants> = {
// color: "neutral",
// textColor: "neutral",
// radius: "lg",
// };
export const avatarCommon = {};

View File

@ -0,0 +1,80 @@
// import {CompoundVariants, cva} from "../../utils";
// import {variants, defaultVariants, type Variants} from "./avatar-common";
// const avatarImgBase = [];
// const avatarImgVariants: Variants = {
// ...variants,
// radius: {
// none: "rounded-none",
// base: "rounded",
// sm: "rounded-sm",
// md: "rounded-md",
// lg: "rounded-lg",
// xl: "rounded-xl",
// },
// color: {
// neutral: "text-neutral dark:text-neutral-dark",
// primary: "text-primary",
// secondary: "text-secondary dark:text-secondary-dark",
// success: "text-success",
// warning: "text-warning",
// error: "text-error",
// },
// textColor: {
// neutral: "text-neutral dark:text-neutral-dark",
// primary: "text-primary",
// secondary: "text-secondary dark:text-secondary-dark",
// success: "text-success",
// warning: "text-warning",
// error: "text-error",
// },
// size: {
// xs: "text-xs",
// sm: "text-sm",
// md: "text-base",
// lg: "text-lg",
// xl: "text-xl",
// },
// border: {
// none: "border-0",
// light: "border",
// normal: "border-2",
// bold: "border-4",
// extrabold: "border-8",
// },
// isZoomed: {
// true: "",
// false: "",
// },
// isStacked: {
// true: "",
// false: "",
// },
// };
// const avatarImgCompoundVariants: CompoundVariants<Variants> = [
// {
// color: "neutral",
// textColor: "success",
// },
// ];
// /**
// * Avatar image cva component
// *
// * @example
// * <div className="avatar-wrapper">
// * <img className={avatarImg()} src="https://picsum.photos/200/300" alt="avatar" />
// * </div>
// */
// const avatarImg = cva(avatarImgBase, {
// variants: avatarImgVariants,
// compoundVariants: avatarImgCompoundVariants,
// defaultVariants,
// });
// export {avatarImgBase, avatarImgVariants, avatarImgCompoundVariants, avatarImg};
export const avatarImg = {};

View File

@ -0,0 +1,90 @@
// import {cva, type VariantProps, type CompoundVariants} from "../../utils";
// import {variants, defaultVariants, type Variants} from "./avatar-common";
// const avatarBase = [
// "flex",
// "relative",
// "justify-center",
// "items-center",
// "box-border",
// "overflow-hidden",
// "align-middle",
// ];
// const avatarVariants: Variants = {
// ...variants,
// radius: {
// none: "rounded-none",
// base: "rounded",
// sm: "rounded-sm",
// md: "rounded-md",
// lg: "rounded-lg",
// xl: "rounded-xl",
// },
// color: {
// neutral: "text-neutral dark:text-neutral-dark",
// primary: "text-primary",
// secondary: "text-secondary dark:text-secondary-dark",
// success: "text-success",
// warning: "text-warning",
// error: "text-error",
// },
// textColor: {
// neutral: "text-neutral dark:text-neutral-dark",
// primary: "text-primary",
// secondary: "text-secondary dark:text-secondary-dark",
// success: "text-success",
// warning: "text-warning",
// error: "text-error",
// },
// size: {
// xs: "text-xs",
// sm: "text-sm",
// md: "text-base",
// lg: "text-lg",
// xl: "text-xl",
// },
// border: {
// none: "border-0",
// light: "border",
// normal: "border-2",
// bold: "border-4",
// extrabold: "border-8",
// },
// isZoomed: {
// true: "",
// false: "",
// },
// isStacked: {
// true: "",
// false: "",
// },
// };
// const avatarCompoundVariants: CompoundVariants<Variants> = [
// {
// color: "neutral",
// textColor: "success",
// },
// ];
// /**
// * Avatar wrapper cva component
// *
// * @example
// * <div className={avatar({ color: "secondary", size: "lg" })}>
// * <img src="https://picsum.photos/200/300" alt="your avatar" />
// * </div>
// */
// const avatar = cva(avatarBase, {
// variants: avatarVariants,
// compoundVariants: avatarCompoundVariants,
// defaultVariants,
// });
// export {avatarBase, avatarVariants, avatarCompoundVariants, avatar};
// export type AvatarVariantProps = VariantProps<typeof avatar>;
export const avatarImg = {};

View File

@ -0,0 +1,4 @@
// export * from "./avatar-img";
// export * from "./avatar-wrapper";
export default {};

View File

@ -1,96 +1,87 @@
import {cva, withFocusVisible, type VariantProps} from "../../utils";
import {tv, type VariantProps} from "tailwind-variants";
const linkBase = withFocusVisible([
"inline-flex",
"relative",
"items-center",
"text-current",
"rounded-lg",
"w-fit",
]);
import {focusVisibleClasses} from "../../utils";
const linkVariants = {
size: {
xs: "text-xs",
sm: "text-sm",
md: "text-base",
lg: "text-lg",
xl: "text-xl",
/**
* Link **Tailwind Variants** component
*
* @example
* <a className={link({ color: "secondary", isBlock: true })} href="#" />
*/
const link = tv({
base: focusVisibleClasses,
variants: {
size: {
xs: "text-xs",
sm: "text-sm",
md: "text-base",
lg: "text-lg",
xl: "text-xl",
},
color: {
foreground: "text-foreground dark:text-foreground-dark",
primary: "text-primary",
secondary: "text-secondary dark:text-secondary-dark",
success: "text-success",
warning: "text-warning",
error: "text-error",
},
isUnderline: {
true: "hover:underline active:underline focus:underline underline-offset-4",
false: "no-underline",
},
isBlock: {
true: "px-2 py-1 hover:after:opacity-100 after:content-[' '] after:inset-0 after:opacity-0 after:w-full after:h-full after:rounded-xl after:transition-background after:absolute",
false: "hover:opacity-80 transition-opacity",
},
isDisabled: {
true: "opacity-50 cursor-default pointer-events-none",
},
disableAnimation: {
true: "after:transition-none transition-none",
},
},
color: {
foreground: "text-foreground dark:text-foreground-dark",
primary: "text-primary",
secondary: "text-secondary dark:text-secondary-dark",
success: "text-success",
warning: "text-warning",
error: "text-error",
},
isUnderline: {
true: "hover:underline active:underline focus:underline",
false: "no-underline",
},
isBlock: {
true: "px-2 py-1 hover:after:opacity-100 after:content-[' '] after:inset-0 after:opacity-0 after:w-full after:h-full after:rounded-xl after:transition-background after:absolute",
false: "hover:opacity-80 transition-opacity",
},
isDisabled: {
true: "opacity-50 cursor-default pointer-events-none",
},
disableAnimation: {
true: "after:transition-none transition-none",
},
};
const linkCompoundVariants = [
{
isBlock: true,
color: "foreground",
class: "hover:after:bg-foreground/25 dark:hover:after:bg-foreground-dark/25",
},
{
isBlock: true,
compoundVariants: [
{
isBlock: true,
color: "foreground",
class: "hover:after:bg-foreground/25 dark:hover:after:bg-foreground-dark/25",
},
{
isBlock: true,
color: "primary",
class: "hover:after:bg-primary/25",
},
{
isBlock: true,
color: "secondary",
class: "hover:after:bg-secondary/25 dark:hover:after:bg-secondary-dark/25",
},
{
isBlock: true,
color: "success",
class: "hover:after:bg-success/25",
},
{
isBlock: true,
color: "warning",
class: "hover:after:bg-warning/25",
},
{
isBlock: true,
color: "error",
class: "hover:after:bg-error/25",
},
],
defaultVariants: {
color: "primary",
class: "hover:after:bg-primary/25",
size: "md",
isBlock: false,
isUnderline: false,
disableAnimation: false,
},
{
isBlock: true,
color: "secondary",
class: "hover:after:bg-secondary/25 dark:hover:after:bg-secondary-dark/25",
},
{
isBlock: true,
color: "success",
class: "hover:after:bg-success/25",
},
{
isBlock: true,
color: "warning",
class: "hover:after:bg-warning/25",
},
{
isBlock: true,
color: "error",
class: "hover:after:bg-error/25",
},
];
const linkDefaultVariants = {
color: "primary",
size: "md",
isBlock: false,
isUnderline: false,
disableAnimation: false,
};
const linkStyles = {
variants: linkVariants,
compoundVariants: linkCompoundVariants,
defaultVariants: linkDefaultVariants,
};
// @ts-ignore
const link = cva(linkBase, linkStyles);
export {linkBase, linkVariants, linkCompoundVariants, linkDefaultVariants, linkStyles, link};
});
export type LinkVariantProps = VariantProps<typeof link>;
export {link};

View File

@ -1,3 +0,0 @@
export {cva, cx} from "class-variance-authority";
export {twMerge} from "tailwind-merge";
export * from "class-variance-authority";

View File

@ -1,3 +1 @@
export * from "./cva";
export * from "./styles";
export * from "./types";

View File

@ -1,5 +1,3 @@
import {cx} from "./cva";
/**
* focus styles when the element is focused by keyboard.
*/
@ -12,7 +10,3 @@ export const focusVisibleClasses = [
"focus-visible:ring-offset-background",
"dark:focus-visible:ring-offset-background-dark",
];
export const withFocusVisible = (classes: Array<string>) => {
return cx(classes, focusVisibleClasses);
};

View File

@ -1,27 +0,0 @@
import type {VariantProps} from "class-variance-authority";
/**
* This is a utility type that allows you to extend the props of a component and add variant props.
* @example
*
* import {cva, VariantProps, ExtendVariantProps} from "@nextui-org/theme";
*
* type ComponentProps = {
* foo: string;
* bar: string;
* }
*
* const myComponent = cva(["text-blue-500", "font-bold"], {
* variants: {
* isFoo: {
* true: "text-red-500",
* false: "text-green-500"
* }
* }
* })
*
* type MyVariantProps = VariantProps<typeof myComponent>;
*
* type MyComponentProps = ExtendVariantProps<ComponentProps, MyVariantProps>;
*/
export type ExtendVariantProps<P, T extends VariantProps<any>> = Omit<P, keyof T> & T;

3469
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff