feat(root): link is disabled variant added

This commit is contained in:
Junior Garcia 2023-01-10 23:28:15 -03:00
parent 22fa4fab6f
commit 71d34dad48
24 changed files with 2722 additions and 4917 deletions

View File

@ -71,19 +71,21 @@ import {Link} from "@nextui-org/react";
#### Link Props
| Attribute | Type | Description | Default |
| -------------------- | -------------------------------------------------------------- | --------------------------------------- | -------------- |
| **color** | `foreground` `primary` `secondary` `success` `warning` `error` | Change link color | `primary` |
| **href** | `string` | Link url | - |
| **size** | `xs` `sm` `md` `lg` `xl` | Change link size | `md` |
| **isUnderline** | `boolean` | Display underline | `false` |
| **isBlock** | `boolean` | Display as a separate block | `false` |
| **isExternal** | `boolean` | Show link icon | `false` |
| **externalIcon** | `React.ReactNode` | Suffix link icon when `isExternal=true` | `<LinkIcon />` |
| **disableAnimation** | `boolean` | Disable link hover animation | `false` |
| **ref** | <Code>Ref<HTMLAnchorElement &#124; null></Code> | forwardRef | - |
| **as** | `keyof JSX.IntrinsicElements` | Changes which tag component outputs | `a` |
| ... | `AnchorHTMLAttributes` | Native props | - |
| Attribute | Type | Description | Default |
| -------------------- | -------------------------------------------------------------- | --------------------------------------------------- | -------------- |
| **color** | `foreground` `primary` `secondary` `success` `warning` `error` | Change link color | `primary` |
| **href** | `string` | Link url | - |
| **size** | `xs` `sm` `md` `lg` `xl` | Change link size | `md` |
| **isUnderline** | `boolean` | Display underline | `false` |
| **isBlock** | `boolean` | Display as a separate block | `false` |
| **isExternal** | `boolean` | Show link icon | `false` |
| **showAnchorIcon** | `boolean` | Whether to show the icon when the link is external. | `false` |
| **anchorIcon** | `React.ReactNode` | The icon to display right after the link. | `<LinkIcon />` |
| **isDisabled** | `boolean` | Whether the link is diasbled. | `false` |
| **disableAnimation** | `boolean` | Disable link hover animation | `false` |
| **ref** | <Code>Ref<HTMLAnchorElement &#124; null></Code> | forwardRef | - |
| **as** | `keyof JSX.IntrinsicElements` | Changes which tag component outputs | `a` |
| ... | `AnchorHTMLAttributes` | Native props | - |
<Spacer y={2} />

View File

@ -43,7 +43,6 @@
},
"devDependencies": {
"@nextui-org/avatar": "workspace:*",
"@nextui-org/text": "workspace:*",
"@nextui-org/shared-icons": "workspace:*",
"clean-package": "2.1.1",
"react": "^17.0.2"

View File

@ -49,7 +49,6 @@
},
"devDependencies": {
"@react-types/shared": "^3.15.0",
"@nextui-org/text": "workspace:*",
"@nextui-org/code": "workspace:*",
"@nextui-org/link": "workspace:*",
"clean-package": "2.1.1",

View File

@ -49,7 +49,6 @@
},
"devDependencies": {
"@react-types/link": "^3.3.3",
"@nextui-org/text": "workspace:*",
"clean-package": "2.1.1",
"react": "^17.0.2"
},

View File

@ -1,6 +1,6 @@
export const LinkIcon = () => (
<svg
className="flex ml-1 text-current self-center"
className="flex mx-1 text-current self-center"
fill="none"
height="1em"
shapeRendering="geometricPrecision"

View File

@ -17,9 +17,10 @@ const Link = forwardRef<LinkProps, "a">((props, ref) => {
children,
isUnderline,
isBlock,
isDisabled,
disableAnimation,
externalIcon = <LinkIcon />,
isExternal,
showAnchorIcon,
anchorIcon = <LinkIcon />,
linkProps,
className,
...otherProps
@ -36,6 +37,7 @@ const Link = forwardRef<LinkProps, "a">((props, ref) => {
size,
isUnderline,
isBlock,
isDisabled,
disableAnimation,
}),
className,
@ -44,7 +46,7 @@ const Link = forwardRef<LinkProps, "a">((props, ref) => {
>
<>
{children}
{isExternal && externalIcon}
{showAnchorIcon && anchorIcon}
</>
</Component>
);

View File

@ -17,16 +17,33 @@ export interface Props extends HTMLNextUIProps<"a">, LinkVariantProps {
*/
isExternal?: boolean;
/**
* The icon to display when the link is external.
* Whether the link is disabled.
* @default false
*/
isDisabled?: boolean;
/**
* Whether to show the icon when the link is external.
* @default false
*/
showAnchorIcon?: boolean;
/**
* The icon to display right after the link.
* @default <LinkIcon />
*/
externalIcon?: React.ReactNode;
anchorIcon?: React.ReactNode;
}
export type UseLinkProps = Props & AriaLinkProps;
export function useLink(props: UseLinkProps) {
const {ref, as = "a", isExternal = false, ...otherProps} = props;
const {
ref,
as = "a",
isExternal = false,
showAnchorIcon = false,
isDisabled = false,
...otherProps
} = props;
const domRef = useDOMRef(ref);
@ -37,7 +54,7 @@ export function useLink(props: UseLinkProps) {
otherProps.target = otherProps.target ?? "_blank";
}
return {as, domRef, linkProps, isExternal, ...otherProps};
return {as, domRef, linkProps, showAnchorIcon, isDisabled, ...otherProps};
}
export type UseLinkReturn = ReturnType<typeof useLink>;

View File

@ -12,6 +12,12 @@ const text = `"First solve the problem. Then, write the code." - Jon Johnson.`;
export const Default = () => <Link href="#">{text}</Link>;
export const isDisabled = () => (
<Link isDisabled href="#">
{text}
</Link>
);
const customLink = cva(null, {
variants: {
color: {
@ -42,22 +48,22 @@ export const CustomVariant = () => {
export const Sizes = () => (
<div className="flex flex-wrap space-y-2">
<Link color="primary" href="#" size="xs">
<Link className="w-full" color="primary" href="#" size="xs">
{text}
</Link>
<Link color="secondary" href="#" size="sm">
<Link className="w-full" color="secondary" href="#" size="sm">
{text}
</Link>
<Link color="success" href="#" size="md">
<Link className="w-full" color="success" href="#" size="md">
{text}
</Link>
<Link color="warning" href="#" size="xl">
<Link className="w-full" color="warning" href="#" size="xl">
{text}
</Link>
<Link className="text-2xl" color="error" href="#">
<Link className="w-full text-2xl" color="error" href="#">
{text}
</Link>
<Link className="text-2xl text-pink-500" href="#">
<Link className="w-full text-2xl text-pink-500" href="#">
{text}
</Link>
</div>
@ -65,25 +71,25 @@ export const Sizes = () => (
export const Colors = () => (
<div className="flex flex-wrap space-y-2">
<Link color="foreground" href="#">
<Link className="w-full" color="foreground" href="#">
{text}
</Link>
<Link color="primary" href="#">
<Link className="w-full" color="primary" href="#">
{text}
</Link>
<Link color="secondary" href="#">
<Link className="w-full" color="secondary" href="#">
{text}
</Link>
<Link color="success" href="#">
<Link className="w-full" color="success" href="#">
{text}
</Link>
<Link color="warning" href="#">
<Link className="w-full" color="warning" href="#">
{text}
</Link>
<Link color="error" href="#">
<Link className="w-full" color="error" href="#">
{text}
</Link>
<Link className="text-teal-600" href="#">
<Link className="w-full text-teal-600" href="#">
{text}
</Link>
</div>
@ -118,13 +124,20 @@ export const isExternal = () => {
return (
<div className="flex flex-wrap space-y-2">
<Link isExternal href="#">
<Link isExternal showAnchorIcon className="w-full" href="#">
{text}
</Link>
<Link isExternal color="secondary" href="#">
<Link isExternal showAnchorIcon className="w-full" color="secondary" href="#">
{text}
</Link>
<Link isExternal color="success" externalIcon={<CustomLink />} href="#">
<Link
isExternal
showAnchorIcon
anchorIcon={<CustomLink />}
className="w-full"
color="success"
href="#"
>
{text}
</Link>
</div>

View File

@ -2,8 +2,12 @@
@tailwind components;
@tailwind utilities;
html[data-mode="light"] {
@apply bg-white text-black;
}
html[data-mode="dark"] {
@apply bg-black text-black;
@apply bg-black text-white;
}
body {

View File

@ -1,24 +0,0 @@
# @nextui-org/text
A Quick description of the component
> This is an internal utility, not intended for public usage.
## Installation
```sh
yarn add @nextui-org/text
# or
npm i @nextui-org/text
```
## Contribution
Yes please! See the
[contributing guidelines](https://github.com/nextui-org/nextui/blob/master/CONTRIBUTING.md)
for details.
## Licence
This project is licensed under the terms of the
[MIT license](https://github.com/nextui-org/nextui/blob/master/LICENSE).

View File

@ -1,49 +0,0 @@
import * as React from "react";
import {render} from "@testing-library/react";
import {Text} from "../src";
describe("Text", () => {
it("should render correctly", () => {
const wrapper = render(<Text />);
expect(() => wrapper.unmount()).not.toThrow();
});
it("ref should be forwarded", () => {
const ref = React.createRef<HTMLParagraphElement>();
render(<Text ref={ref} />);
expect(ref.current).not.toBeNull();
});
it("should render P element in the default", () => {
const {container} = render(<Text />);
expect(container.querySelector("p")).not.toBeNull();
});
it("should work with different colors", () => {
const {container} = render(<Text color="secondary" />);
expect(container.querySelector("p")).toHaveStyle("color: var(--nextui-colors-secondary)");
});
it("the specified element should be rendered", () => {
const {container} = render(<Text h1 />);
expect(container.querySelector("h1")).not.toBeNull();
});
it("should work with different sizes", () => {
const {container} = render(<Text size="$sm" />);
expect(container.querySelector("p")).toHaveStyle("font-size: var(--nextui-fontSizes-sm)");
});
it("should work with combined styles", () => {
const {container} = render(<Text b del />);
expect(container.querySelector("b")).toContainHTML("del");
});
});

View File

@ -1,11 +0,0 @@
{
"replace": {
"main": "dist/index.cjs.js",
"module": "dist/index.esm.js",
"types": "dist/index.d.ts",
"exports": {
".": {"import": "./dist/index.esm.js", "require": "./dist/index.cjs.js"},
"./package.json": "./package.json"
}
}
}

View File

@ -1,57 +0,0 @@
{
"name": "@nextui-org/text",
"version": "2.0.0-beta.1",
"description": "Text component is the used to render text and paragraphs within an interface using well-defined typographic styles. It renders a &lt;p&gt; tag by default.",
"keywords": [
"text"
],
"author": "Junior Garcia <jrgarciadev@gmail.com>",
"homepage": "https://nextui.org",
"license": "MIT",
"main": "src/index.ts",
"sideEffects": false,
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/nextui-org/nextui.git",
"directory": "packages/components/text"
},
"bugs": {
"url": "https://github.com/nextui-org/nextui/issues"
},
"scripts": {
"build": "tsup src --dts",
"dev": "yarn build:fast -- --watch",
"clean": "rimraf dist .turbo",
"typecheck": "tsc --noEmit",
"build:fast": "tsup src",
"prepack": "clean-package",
"postpack": "clean-package restore"
},
"peerDependencies": {
"react": ">=16.8.0"
},
"dependencies": {
"@nextui-org/system": "workspace:*",
"@nextui-org/shared-utils": "workspace:*",
"@nextui-org/shared-css": "workspace:*",
"@nextui-org/dom-utils": "workspace:*"
},
"devDependencies": {
"clean-package": "2.1.1",
"react": "^17.0.2"
},
"tsup": {
"clean": true,
"target": "es2019",
"format": [
"cjs",
"esm"
]
}
}

View File

@ -1,5 +0,0 @@
// export types
export type {TextProps} from "./text";
// export component
export {default as Text} from "./text";

View File

@ -1,92 +0,0 @@
import {useMemo} from "react";
import {HTMLNextUIProps, forwardRef, CSS} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__, isNormalColor} from "@nextui-org/shared-utils";
import {StyledText} from "./text.styles";
export interface TextChildProps extends HTMLNextUIProps<"p"> {
tag: keyof JSX.IntrinsicElements;
/**
* Text color.
* @default "default"
*/
color?: CSS["color"];
/**
* The **`font-size`** CSS property sets the size of the font. Changing the font size also updates the sizes of the font size-relative `<length>` units, such as `em`, `ex`, and so forth.
*
* **Syntax**: `<absolute-size> | <relative-size> | <length-percentage>`
*
* **Initial value**: `medium`
*
*/
size?: CSS["fontSize"];
/**
* The **`text-transform`** CSS property specifies how to capitalize an element's text. It can be used to make text appear in all-uppercase or all-lowercase, or with each word capitalized. It also can help improve legibility for ruby.
*
* **Syntax**: `none | capitalize | uppercase | lowercase | full-width | full-size-kana`
*
* **Initial value**: `none`
*
*/
transform?: CSS["textTransform"];
/**
* The **`font-weight`** CSS property specifies the weight (or boldness) of the font. The font weights available to you will depend on the `font-family` you are using. Some fonts are only available in `normal` and `bold`.
*/
weight?: CSS["fontWeight"];
}
const TextChild = forwardRef<TextChildProps, "p">((props, ref) => {
const {
tag,
css,
children,
color: userColor = "$text",
transform: textTransform,
size: fontSize,
weight: fontWeight,
className,
...otherProps
} = props;
const domRef = useDOMRef(ref);
const color = useMemo(() => {
if (isNormalColor(userColor as string)) {
switch (userColor) {
case "default":
return "$text";
default:
return `$${userColor}`;
}
}
return userColor;
}, [userColor]);
return (
<StyledText
ref={domRef}
as={tag}
className={clsx("nextui-text-child", className)}
css={{
color,
fontSize,
textTransform,
fontWeight,
...css,
}}
{...otherProps}
>
{children}
</StyledText>
);
});
if (__DEV__) {
TextChild.displayName = "NextUI.TextChild";
}
TextChild.toString = () => ".nextui-text-child";
export default TextChild;

View File

@ -1,4 +0,0 @@
import {styled} from "@nextui-org/system";
import {cssHideShowIn} from "@nextui-org/shared-css";
export const StyledText = styled("p", {}, cssHideShowIn);

View File

@ -1,59 +0,0 @@
import {ReactNode, useMemo} from "react";
import {forwardRef} from "@nextui-org/system";
import {useDOMRef} from "@nextui-org/dom-utils";
import {clsx, __DEV__} from "@nextui-org/shared-utils";
import {UseTextProps, TextRenderableElements, useText} from "./use-text";
import TextChild, {TextChildProps} from "./text-child";
export interface TextProps extends UseTextProps {}
const getModifierChild = (
tags: TextRenderableElements,
children: ReactNode,
size?: TextChildProps["size"],
transform?: TextChildProps["transform"],
) => {
if (!tags.length) return children;
const nextTag = tags.slice(1, tags.length);
return (
<TextChild size={size} tag={tags[0]} transform={transform}>
{getModifierChild(nextTag, children, size)}
</TextChild>
);
};
const Text = forwardRef<TextProps, "p">((props, ref) => {
const {children, size, transform, tag, renderableChildElements, className, ...otherProps} =
useText(props);
const domRef = useDOMRef(ref);
const modifers = useMemo(() => {
if (!renderableChildElements.length) return children;
return getModifierChild(renderableChildElements, children, size, transform);
}, [renderableChildElements, children, size, transform]);
return (
<TextChild
ref={domRef}
className={clsx("nextui-text", className)}
size={size}
tag={tag}
transform={transform}
{...otherProps}
>
{modifers}
</TextChild>
);
});
if (__DEV__) {
Text.displayName = "NextUI.Text";
}
Text.toString = () => ".nextui-text";
export default Text;

View File

@ -1,84 +0,0 @@
import {getKeyValue, TextTransforms} from "@nextui-org/shared-utils";
import {useMemo} from "react";
import {HTMLNextUIProps} from "@nextui-org/system";
import {HideShowInProps} from "@nextui-org/shared-css";
import {TextChildProps} from "./text-child";
export interface UseTextProps
extends HTMLNextUIProps<"p", Omit<TextChildProps, "tag">>,
HideShowInProps {
h1?: boolean;
h2?: boolean;
h3?: boolean;
h4?: boolean;
h5?: boolean;
h6?: boolean;
b?: boolean;
small?: boolean;
transform?: TextTransforms;
i?: boolean;
span?: boolean;
del?: boolean;
em?: boolean;
blockquote?: boolean;
}
type ElementMap = {[key in keyof JSX.IntrinsicElements]?: boolean};
export type TextRenderableElements = Array<keyof JSX.IntrinsicElements>;
export function useText(props: UseTextProps) {
const {
h1 = false,
h2 = false,
h3 = false,
h4 = false,
h5 = false,
h6 = false,
b = false,
small = false,
i = false,
span = false,
del = false,
em = false,
blockquote = false,
transform = "none",
size,
...otherProps
} = props;
const elements: ElementMap = {h1, h2, h3, h4, h5, h6, blockquote};
const inlineElements: ElementMap = {span, small, b, em, i, del};
const names = Object.keys(elements).filter((name: string) =>
getKeyValue(elements, name),
) as TextRenderableElements;
const inlineNames = Object.keys(inlineElements).filter((name: string) =>
getKeyValue(inlineElements, name),
) as TextRenderableElements;
/**
* Render element "p" only if no element is found.
* If there is only one modifier, just rendered one modifier element
* e.g.
* <Text /> => <p />
* <Text em /> => <em />
* <Text b em /> => <b><em>children</em></b>
*/
const tag = useMemo(() => {
if (names[0]) return names[0];
if (inlineNames[0]) return inlineNames[0];
return "p" as keyof JSX.IntrinsicElements;
}, [names, inlineNames]);
const renderableChildElements = inlineNames.filter(
(name: keyof JSX.IntrinsicElements) => name !== tag,
) as TextRenderableElements;
return {renderableChildElements, tag, transform, size, ...otherProps};
}
export type UseTextReturn = ReturnType<typeof useText>;

View File

@ -1,124 +0,0 @@
import React from "react";
import {Meta} from "@storybook/react";
import {Text} from "../src";
export default {
title: "General/Text",
component: Text,
decorators: [
(Story) => (
<div style={{maxWidth: "50%"}}>
<Story />
</div>
),
],
} as Meta;
const shortText = "Almost before we knew it, we had left the ground.";
const largeText =
"NextUI gives you the best developer experience with all the features you need for building beautiful and modern websites and applications.";
export const Headings = () => {
return (
<>
<Text h1>{shortText}</Text>
<Text h2>{shortText}</Text>
<Text h3>{shortText}</Text>
<Text h4>{shortText}</Text>
<Text h5>{shortText}</Text>
<Text h6>{shortText}</Text>
</>
);
};
export const Gradient = () => (
<>
<Text
h1
css={{
textGradient: "45deg, $blue600 0%, $cyan600 100%",
}}
weight="$bold"
>
Let&apos;s
</Text>
<Text
h1
css={{
textGradient: "45deg, $pink600 0%, $red600 100%",
}}
weight="$bold"
>
Make the web
</Text>
<Text
h1
css={{
textGradient: "45deg, $yellow600 0%, $red600 100%",
}}
weight="$bold"
>
Prettier
</Text>
</>
);
export const Paragraph = () => (
<>
<Text>{largeText}</Text>
<Text b>{largeText}</Text>
</>
);
export const Colors = () => (
<>
<Text>{shortText}</Text>
<Text color="primary">{shortText}</Text>
<Text color="secondary">{shortText}</Text>
<Text color="success">{shortText}</Text>
<Text color="warning">{shortText}</Text>
<Text color="error">{shortText}</Text>
<Text color="$pink500">{shortText}</Text>
<Text color="#ccc">{shortText}</Text>
</>
);
export const Small = () => (
<Text>
<Text small>{largeText}</Text>
<Text i small>
{largeText}
</Text>
</Text>
);
export const Blockquote = () => (
<>
<Text blockquote>{shortText}</Text>
</>
);
export const Sizes = () => (
<>
<Text size="$xs">Font Size: xs;</Text>
<Text size="$md">Font Size: md (base);</Text>
<Text size="$xl">Font Size: xl;</Text>
<Text size="$2xl">Font Size: 2xl;</Text>
<Text size="$3xl">Font Size: 3xl;</Text>
</>
);
export const Composed = () => (
<>
<Text weight="$hairline">{largeText}</Text>
<Text>
<Text del small>
{shortText}
</Text>
<Text b small>
{shortText}
</Text>
</Text>
</>
);

View File

@ -1,9 +0,0 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"paths": {
"@stitches/react": ["../../../node_modules/@stitches/react"]
}
},
"include": ["src", "index.ts"]
}

View File

@ -54,7 +54,6 @@
"@nextui-org/pagination": "workspace:*",
"@nextui-org/radio": "workspace:*",
"@nextui-org/snippet": "workspace:*",
"@nextui-org/text": "workspace:*",
"@nextui-org/user": "workspace:*"
},
"peerDependencies": {

View File

@ -1,7 +1,6 @@
export * from "@nextui-org/system";
export * from "@nextui-org/avatar";
export * from "@nextui-org/badge";
export * from "@nextui-org/text";
export * from "@nextui-org/link";
export * from "@nextui-org/code";
export * from "@nextui-org/pagination";

View File

@ -6,7 +6,6 @@ const linkBase = withFocusVisible([
"items-center",
"leading-inherit",
"text-current",
"w-fit",
"rounded-lg",
"bg-transparent",
"bg-img-inherit",
@ -38,6 +37,9 @@ const linkVariants = {
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",
},

6998
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff