mirror of
https://github.com/nextui-org/nextui.git
synced 2025-12-08 19:26:11 +00:00
feat(docs): installations and frameworks guides added
This commit is contained in:
parent
0df8b26697
commit
48667d9444
@ -6,12 +6,12 @@ const blockquote = tv({
|
||||
|
||||
variants: {
|
||||
color: {
|
||||
neutral: "border-neutral-100 bg-neutral-50",
|
||||
primary: "border-primary-200 bg-primary-50",
|
||||
secondary: "border-secondary-200 bg-secondary-50",
|
||||
success: "border-success-200 bg-success-50",
|
||||
warning: "border-warning-200 bg-warning-50",
|
||||
danger: "border-danger-200 bg-danger-50",
|
||||
neutral: "border-neutral-100 bg-neutral-50/20",
|
||||
primary: "border-primary-100 bg-primary-50/20",
|
||||
secondary: "border-secondary-100 bg-secondary-50/20",
|
||||
success: "border-success-100 bg-success-50/20",
|
||||
warning: "border-warning-100 bg-warning-50/20",
|
||||
danger: "border-danger-100 bg-danger-50/20",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
||||
@ -5,36 +5,88 @@ import BaseHighlight, {Language, PrismTheme, defaultProps} from "prism-react-ren
|
||||
import defaultTheme from "@/libs/prism-theme";
|
||||
|
||||
interface CodeblockProps {
|
||||
codeString: string;
|
||||
language: Language;
|
||||
codeString: string;
|
||||
metastring?: string;
|
||||
theme?: PrismTheme;
|
||||
showLines?: boolean;
|
||||
className?: string;
|
||||
children?: (props: any) => React.ReactNode;
|
||||
}
|
||||
|
||||
const RE = /{([\d,-]+)}/;
|
||||
|
||||
const calculateLinesToHighlight = (meta?: string) => {
|
||||
if (!meta) {
|
||||
return () => false;
|
||||
}
|
||||
|
||||
if (!RE.test(meta)) {
|
||||
return () => false;
|
||||
}
|
||||
// @ts-ignore
|
||||
const lineNumbers = RE.exec(meta)[1]
|
||||
.split(`,`)
|
||||
.map((v) => v.split(`-`).map((x) => parseInt(x, 10)));
|
||||
|
||||
return (index: number) => {
|
||||
const lineNumber = index + 1;
|
||||
const inRange = lineNumbers.some(([start, end]) =>
|
||||
end ? lineNumber >= start && lineNumber <= end : lineNumber === start,
|
||||
);
|
||||
|
||||
return inRange;
|
||||
};
|
||||
};
|
||||
|
||||
export function Codeblock({
|
||||
codeString,
|
||||
language,
|
||||
showLines,
|
||||
theme: themeProp,
|
||||
metastring,
|
||||
className: classNameProp,
|
||||
...props
|
||||
}: CodeblockProps) {
|
||||
const theme = themeProp || defaultTheme;
|
||||
const shouldHighlightLine = calculateLinesToHighlight(metastring);
|
||||
const isMultiLine = codeString.split("\n").length > 2;
|
||||
|
||||
return (
|
||||
<BaseHighlight {...defaultProps} code={codeString} language={language} theme={theme} {...props}>
|
||||
{({className, style, tokens, getLineProps, getTokenProps}) => (
|
||||
<div data-language={language}>
|
||||
<pre className={className} style={style}>
|
||||
<div className="w-full" data-language={language}>
|
||||
<pre
|
||||
className={clsx(className, classNameProp, "flex max-w-full", {
|
||||
"flex-col": isMultiLine,
|
||||
})}
|
||||
style={style}
|
||||
>
|
||||
{tokens.map((line, i) => {
|
||||
const lineProps = getLineProps({line, key: i});
|
||||
|
||||
return (
|
||||
<div key={i} {...lineProps} className={clsx(lineProps.className, "px-2")}>
|
||||
<div
|
||||
key={i}
|
||||
{...lineProps}
|
||||
className={clsx(
|
||||
lineProps.className,
|
||||
"px-4 relative [&>span]:relative [&>span]:z-10",
|
||||
{
|
||||
"px-2": showLines,
|
||||
},
|
||||
{
|
||||
"before:content-[''] before:w-full before:h-full before:absolute before:z-0 before:left-0 before:bg-gradient-to-r before:from-white/10 before:to-code-background before:border-l-2 border-l-white/80 dark:before:border-l-white/50": shouldHighlightLine(
|
||||
i,
|
||||
),
|
||||
},
|
||||
)}
|
||||
>
|
||||
{showLines && (
|
||||
<span className="select-none text-sm mr-6 opacity-30">{i + 1}</span>
|
||||
<span className="select-none text-xs mr-6 opacity-30">{i + 1}</span>
|
||||
)}
|
||||
{line.map((token, key) => (
|
||||
<span key={key} {...getTokenProps({token, key})} />
|
||||
<span key={key} {...getTokenProps({token, key})} className={className} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {Button, Link} from "@nextui-org/react";
|
||||
|
||||
import {GithubIcon, NpmIcon, AdobeIcon} from "@/components/icons";
|
||||
import {GithubIcon, NpmIcon, AdobeIcon, StorybookIcon} from "@/components/icons";
|
||||
import {COMPONENT_PATH, COMPONENT_THEME_PATH} from "@/libs/github/constants";
|
||||
|
||||
export interface ComponentLinksProps {
|
||||
@ -49,6 +49,18 @@ export const ComponentLinks = ({component, reactAria}: ComponentLinksProps) => {
|
||||
{`@nextui-org/${component}`}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
isExternal
|
||||
as={Link}
|
||||
className="text-neutral-700 font-normal"
|
||||
href={`https://storiesv2.nextui.org/?path=/story/components-${component}`}
|
||||
size="sm"
|
||||
startIcon={<StorybookIcon className="text-lg text-[#ff4785]" />}
|
||||
variant="flat"
|
||||
>
|
||||
Storybook
|
||||
</Button>
|
||||
|
||||
{reactAria && (
|
||||
<Button
|
||||
isExternal
|
||||
|
||||
42
apps/docs/components/docs/components/frameworks.tsx
Normal file
42
apps/docs/components/docs/components/frameworks.tsx
Normal file
@ -0,0 +1,42 @@
|
||||
import {NewNextJSIcon, ViteIcon, RemixIcon, AstroIcon} from "@/components/icons";
|
||||
import {FeaturesGrid} from "@/components/marketing";
|
||||
|
||||
const frameworks = [
|
||||
{
|
||||
title: "Next.js",
|
||||
description: "Full-featured React framework with great developer experience.",
|
||||
icon: <NewNextJSIcon height={40} width={40} />,
|
||||
href: "/docs/frameworks/nextjs",
|
||||
},
|
||||
{
|
||||
title: "Vite",
|
||||
description: "Fast and modern development server and build tool.",
|
||||
icon: <ViteIcon height={40} width={40} />,
|
||||
href: "/docs/frameworks/vite",
|
||||
},
|
||||
{
|
||||
title: "Remix",
|
||||
description: "Full stack framework focused on web fundamentals and modern UX.",
|
||||
icon: <RemixIcon className="text-foreground" height={40} width={40} />,
|
||||
href: "/docs/frameworks/remix",
|
||||
},
|
||||
{
|
||||
title: "Astro",
|
||||
description: "The all-in-one web framework designed for speed.",
|
||||
icon: <AstroIcon className="text-foreground" height={40} width={40} />,
|
||||
href: "/docs/frameworks/astro",
|
||||
},
|
||||
];
|
||||
|
||||
export const Frameworks = () => {
|
||||
return (
|
||||
<FeaturesGrid
|
||||
classNames={{
|
||||
base: "mt-8 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4",
|
||||
iconWrapper: "bg-neutral-300/20",
|
||||
body: "py-0",
|
||||
}}
|
||||
features={frameworks}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -2,3 +2,4 @@ export * from "./component-links";
|
||||
export * from "./package-managers";
|
||||
export * from "./blockquote";
|
||||
export * from "./community";
|
||||
export * from "./frameworks";
|
||||
|
||||
@ -35,7 +35,8 @@ export const PackageManagers = ({commands}: PackageManagersProps) => {
|
||||
<Tabs
|
||||
aria-label="NextUI installation commands"
|
||||
classNames={{
|
||||
base: "mt-4",
|
||||
base: "group mt-4",
|
||||
tabList: "h-10",
|
||||
}}
|
||||
variant="underlined"
|
||||
>
|
||||
|
||||
@ -12,9 +12,9 @@ export interface DocsTocProps {
|
||||
|
||||
const paddingLeftByLevel: Record<string, string> = {
|
||||
1: "pl-0",
|
||||
2: "pl-4",
|
||||
3: "pl-8",
|
||||
4: "pl-12",
|
||||
2: "pl-3",
|
||||
3: "pl-6",
|
||||
4: "pl-9",
|
||||
};
|
||||
|
||||
export const DocsToc: FC<DocsTocProps> = ({headings}) => {
|
||||
|
||||
@ -175,6 +175,7 @@ export const AdobeIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em"
|
||||
const YarnIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height={height}
|
||||
@ -192,6 +193,7 @@ const YarnIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...pro
|
||||
const PnpmIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height={height}
|
||||
@ -208,6 +210,171 @@ const PnpmIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...pro
|
||||
);
|
||||
};
|
||||
|
||||
const AstroIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg aria-hidden="true" fill="none" focusable="false" height={height} width={width} {...props}>
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M16.986 23.22c-3.498 0-6.986 1.694-6.986 1.694s5.924-16.1 5.937-16.131c.181-.476.457-.783.844-.783h7.11c.386 0 .673.307.843.783l5.936 16.131s-2.843-1.695-6.985-1.695l-2.637-8.14c-.1-.395-.387-.662-.713-.662-.325 0-.614.268-.712.661l-2.637 8.141zm-.572 6.477h.001-.001zM15.3 24.378c-.532 1.751-.16 4.168 1.115 5.319l.017-.061a1.42 1.42 0 00.03-.116c.16-.73.762-1.195 1.524-1.173.741.021 1.135.392 1.25 1.22.042.307.046.62.05.933l.001.098c.01.707.195 1.361.585 1.952a3.4 3.4 0 001.515 1.279l-.018-.06a4.332 4.332 0 00-.03-.1c-.488-1.476-.137-2.49 1.16-3.356l.398-.261c.293-.19.585-.38.867-.586 1.022-.747 1.665-1.732 1.817-3.007a3.404 3.404 0 00-.162-1.547c-.076.045-.148.09-.218.134-.15.094-.29.182-.437.253-1.897.921-3.902 1.035-5.944.73-1.322-.197-2.599-.547-3.52-1.651z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const NewNextJSIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg aria-hidden="true" fill="none" focusable="false" height={height} width={width} {...props}>
|
||||
<mask
|
||||
height="26"
|
||||
id="nextjs-white_svg__a"
|
||||
maskUnits="userSpaceOnUse"
|
||||
style={{
|
||||
maskType: "alpha",
|
||||
}}
|
||||
width="26"
|
||||
x="7"
|
||||
y="7"
|
||||
>
|
||||
<path
|
||||
d="M20 33c7.18 0 13-5.82 13-13S27.18 7 20 7 7 12.82 7 20s5.82 13 13 13z"
|
||||
fill="#000"
|
||||
/>
|
||||
</mask>
|
||||
<g mask="url(#nextjs-white_svg__a)">
|
||||
<path
|
||||
d="M20 32.567c6.94 0 12.567-5.627 12.567-12.567S26.94 7.433 20 7.433 7.433 13.06 7.433 20 13.06 32.567 20 32.567z"
|
||||
fill="#000"
|
||||
stroke="#fff"
|
||||
strokeWidth="0.867"
|
||||
/>
|
||||
<path
|
||||
d="M28.596 29.753L16.987 14.8H14.8v10.396h1.75v-8.174l10.672 13.789c.482-.322.94-.676 1.374-1.058z"
|
||||
fill="url(#nextjs-white_svg__b)"
|
||||
/>
|
||||
<path d="M25.344 14.8h-1.733v10.4h1.733V14.8z" fill="url(#nextjs-white_svg__c)" />
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="nextjs-white_svg__b"
|
||||
x1="22.744"
|
||||
x2="27.872"
|
||||
y1="23.828"
|
||||
y2="30.183"
|
||||
>
|
||||
<stop stopColor="#fff" />
|
||||
<stop offset="1" stopColor="#fff" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="nextjs-white_svg__c"
|
||||
x1="24.478"
|
||||
x2="24.449"
|
||||
y1="14.8"
|
||||
y2="22.438"
|
||||
>
|
||||
<stop stopColor="#fff" />
|
||||
<stop offset="1" stopColor="#fff" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const RemixIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={height}
|
||||
viewBox="0 0 40 40"
|
||||
width={width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M29.397 26.388c.213 2.733.213 4.014.213 5.412h-6.322c0-.305.005-.583.01-.866.018-.878.036-1.794-.107-3.643-.188-2.708-1.354-3.31-3.497-3.31H9.75v-4.926h10.244c2.708 0 4.063-.823 4.063-3.005 0-1.917-1.355-3.08-4.063-3.08H9.75V8.15h11.373c6.13 0 9.177 2.896 9.177 7.521 0 3.46-2.144 5.716-5.04 6.092 2.445.489 3.874 1.88 4.137 4.625z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M9.75 31.8v-3.672h6.685c1.116 0 1.359.828 1.359 1.322v2.35H9.75z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const ViteIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={height}
|
||||
viewBox="0 0 40 40"
|
||||
width={width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M31.881 11.61L20.886 31.563a.593.593 0 01-1.04.004L8.633 11.611c-.251-.446.125-.987.624-.897l11.007 1.997a.59.59 0 00.212 0l10.777-1.994c.497-.092.875.445.628.893z"
|
||||
fill="url(#vite_svg__paint0_linear_41_6732)"
|
||||
/>
|
||||
<path
|
||||
d="M25.506 8.096l-8.137 1.618a.302.302 0 00-.241.28l-.5 8.578a.3.3 0 00.365.314l2.265-.531c.212-.05.404.14.36.356l-.673 3.345a.3.3 0 00.38.35l1.399-.43a.3.3 0 01.38.35l-1.07 5.255c-.067.328.364.507.543.226l.12-.189 6.63-13.428c.111-.225-.08-.481-.323-.433l-2.332.456a.301.301 0 01-.344-.381l1.522-5.355a.301.301 0 00-.345-.381z"
|
||||
fill="url(#vite_svg__paint1_linear_41_6732)"
|
||||
/>
|
||||
<defs>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="vite_svg__paint0_linear_41_6732"
|
||||
x1="8.359"
|
||||
x2="22.306"
|
||||
y1="10.001"
|
||||
y2="28.665"
|
||||
>
|
||||
<stop stopColor="#41D1FF" />
|
||||
<stop offset="1" stopColor="#BD34FE" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="vite_svg__paint1_linear_41_6732"
|
||||
x1="19.631"
|
||||
x2="22.178"
|
||||
y1="8.535"
|
||||
y2="25.757"
|
||||
>
|
||||
<stop stopColor="#FFEA83" />
|
||||
<stop offset="0.083" stopColor="#FFDD35" />
|
||||
<stop offset="1" stopColor="#FFA800" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const StorybookIcon: React.FC<IconSvgProps> = ({width = "1em", height = "1em", ...props}) => {
|
||||
return (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={height}
|
||||
viewBox="0 0 512 512"
|
||||
width={width}
|
||||
{...props}
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M356.5,5.2L353.9,63c-0.1,3.2,3.7,5.2,6.3,3.2l22.6-17.1L401.9,64c2.5,1.7,5.8,0,6-3l-2.2-58.8l28.4-2.2 c14.7-1,27.3,10.8,27.3,25.6v460.8c0,14.7-12.3,26.3-26.9,25.6L91.1,496.6c-13.3-0.6-24.1-11.3-24.5-24.7l-16-422.3 c-0.8-14.2,9.9-26.3,24.1-27.1L356.2,4.7L356.5,5.2z M291,198.4c0,10,67.4,5.1,76.6-1.7c0-68.2-36.7-104.3-103.6-104.3 c-67.2,0-104.5,36.8-104.5,91.6c0,94.9,128,96.6,128,148.4c0,15-6.8,23.5-22.4,23.5c-20.5,0-28.8-10.4-27.7-46.1 c0-7.7-77.8-10.3-80.4,0c-5.7,86,47.6,110.9,108.7,110.9c59.6,0,106.1-31.7,106.1-89.1c0-101.7-130.1-99-130.1-149.3 c0-20.7,15.4-23.4,24.1-23.4c9.7,0,26.7,1.5,25.4,39.8L291,198.4z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
TwitterIcon,
|
||||
DiscordIcon,
|
||||
@ -220,4 +387,9 @@ export {
|
||||
NpmSmallIcon,
|
||||
PnpmIcon,
|
||||
YarnIcon,
|
||||
AstroIcon,
|
||||
RemixIcon,
|
||||
ViteIcon,
|
||||
NewNextJSIcon,
|
||||
StorybookIcon,
|
||||
};
|
||||
|
||||
@ -70,12 +70,15 @@ export const A11yOtb = () => {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const ref = useRef<any>(null);
|
||||
const isInView = useInView(ref, {
|
||||
margin: "-300px",
|
||||
});
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(() => !isMobile);
|
||||
|
||||
const isInView = useInView(ref, {
|
||||
margin: isMobile ? "0px" : "-300px",
|
||||
});
|
||||
|
||||
return (
|
||||
<section className={sectionWrapper({class: "z-20 mt-16 lg:mt-44"})}>
|
||||
<div className="flex flex-col gap-8">
|
||||
@ -139,14 +142,16 @@ export const A11yOtb = () => {
|
||||
<InfoBoldIcon className="rotate-180" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{isInView && ref.current && (
|
||||
{ref.current && (
|
||||
<Dropdown
|
||||
className="shadow-xl"
|
||||
defaultOpen={!isMobile}
|
||||
closeOnSelect={true}
|
||||
isOpen={isDropdownOpen && isInView}
|
||||
placement="bottom"
|
||||
portalContainer={ref.current}
|
||||
shouldBlockScroll={isMobile}
|
||||
shouldFlip={isMobile}
|
||||
onOpenChange={(open) => setIsDropdownOpen(open)}
|
||||
>
|
||||
<DropdownTrigger>
|
||||
<Button color="success" variant="flat">
|
||||
|
||||
@ -14,14 +14,14 @@ const bannerSuggestions = [
|
||||
description:
|
||||
"Make beautiful, modern, and fast websites/applications regardless of your design experience.",
|
||||
icon: <NoteLinearIcon className="text-pink-500" />,
|
||||
href: "/docs/guide/getting-started",
|
||||
href: "/docs/guide/installation",
|
||||
},
|
||||
{
|
||||
title: "NextUI + Next.js",
|
||||
description:
|
||||
"NextUI is totally compatible with Next.js you just need to customize the _app.jsx entry file to load the provider.",
|
||||
icon: <NextJsIcon className="text-pink-500" />,
|
||||
href: "/docs/guide/nextui-plus-nextjs",
|
||||
href: "/docs/frameworks/nextjs",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@ -10,9 +10,11 @@
|
||||
// import Block from "../templates/example-block";
|
||||
import {clsx} from "@nextui-org/shared-utils";
|
||||
import * as Components from "@nextui-org/react";
|
||||
import {Language} from "prism-react-renderer";
|
||||
|
||||
import * as DocsComponents from "@/components/docs/components";
|
||||
import {VirtualAnchor} from "@/components";
|
||||
import {Codeblock} from "@/components/docs/components/codeblock";
|
||||
import {VirtualAnchor, virtualAnchorEncode} from "@/components";
|
||||
|
||||
const Table: React.FC<{children?: React.ReactNode}> = ({children}) => {
|
||||
return (
|
||||
@ -24,7 +26,17 @@ const Table: React.FC<{children?: React.ReactNode}> = ({children}) => {
|
||||
|
||||
const Thead: React.FC<{children?: React.ReactNode}> = ({children}) => {
|
||||
return (
|
||||
<thead className="[&>tr]:h-12 [&>tr>th]:bg-neutral-300 [&>tr>th]:text-neutral-400 [&>tr>th]:text-sm [&>tr>th]:text-left [&>tr>th]:px-4">
|
||||
<thead
|
||||
className={clsx(
|
||||
"[&>tr]:h-12 [&>tr>th]:bg-neutral-100/50",
|
||||
"[&>tr>th]:align-middle",
|
||||
"[&>tr>th]:py-0",
|
||||
"[&>tr>th]:text-neutral-500 [&>tr>th]:text-xs",
|
||||
"[&>tr>th]:text-left [&>tr>th]:pl-2",
|
||||
"[&>tr>th:first-child]:rounded-l-lg",
|
||||
"[&>tr>th:last-child]:rounded-r-lg",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
@ -56,11 +68,15 @@ const LinkedHeading: React.FC<LinkedHeadingProps> = ({as, linked = true, classNa
|
||||
|
||||
const level = linkedLevels[as] || 1;
|
||||
|
||||
const id = virtualAnchorEncode(props.children as string);
|
||||
|
||||
return (
|
||||
<Component
|
||||
className={clsx({"linked-heading": linked}, linked ? {} : className)}
|
||||
data-id={id}
|
||||
data-level={level}
|
||||
data-name={props.children}
|
||||
id={id}
|
||||
{...props}
|
||||
>
|
||||
{linked ? <VirtualAnchor>{props.children}</VirtualAnchor> : <>{props.children}</>}
|
||||
@ -76,9 +92,18 @@ const List: React.FC<{children?: React.ReactNode}> = ({children}) => {
|
||||
);
|
||||
};
|
||||
|
||||
const Code = ({children, className}: {children?: React.ReactNode; className?: string}) => {
|
||||
const isMultiline =
|
||||
Array.isArray(children) && !!children.find((child) => String(child).includes("\n\n"));
|
||||
const Code = ({
|
||||
className,
|
||||
children,
|
||||
metastring,
|
||||
}: {
|
||||
children?: React.ReactNode;
|
||||
metastring?: string;
|
||||
className?: string;
|
||||
}) => {
|
||||
const isMultiLine = (children as string).split("\n").length > 2;
|
||||
const language = (className?.replace(/language-/, "") ?? "jsx") as Language;
|
||||
const codeString = String(children).trim();
|
||||
|
||||
return (
|
||||
<Components.Snippet
|
||||
@ -87,17 +112,18 @@ const Code = ({children, className}: {children?: React.ReactNode; className?: st
|
||||
hideSymbol
|
||||
classNames={{
|
||||
base: clsx(
|
||||
"bg-code-background text-code-foreground",
|
||||
"px-0 bg-code-background text-code-foreground",
|
||||
{
|
||||
"items-start": isMultiline,
|
||||
"items-start": isMultiLine,
|
||||
},
|
||||
className,
|
||||
),
|
||||
pre: "font-light text-sm",
|
||||
copyButton: "text-lg text-code-foreground/50 -mr-2",
|
||||
pre: "font-light w-full text-sm",
|
||||
copyButton: "text-lg text-code-foreground/50 mr-2",
|
||||
}}
|
||||
codeString={codeString}
|
||||
>
|
||||
<div>{children}</div>
|
||||
<Codeblock codeString={codeString} language={language} metastring={metastring} />
|
||||
</Components.Snippet>
|
||||
);
|
||||
};
|
||||
@ -112,6 +138,14 @@ const Link = ({href, children}: {href?: string; children?: React.ReactNode}) =>
|
||||
);
|
||||
};
|
||||
|
||||
const InlineCode = ({children}: {children?: React.ReactNode}) => {
|
||||
return (
|
||||
<Components.Code className="font-normal bg-transparent px-0 py-0 text-code-mdx">
|
||||
{children}
|
||||
</Components.Code>
|
||||
);
|
||||
};
|
||||
|
||||
export const MDXComponents = ({
|
||||
/**
|
||||
* NextUI components
|
||||
@ -146,8 +180,7 @@ export const MDXComponents = ({
|
||||
blockquote: (props: Omit<React.HTMLAttributes<HTMLElement>, "color">) => (
|
||||
<DocsComponents.Blockquote {...props} />
|
||||
),
|
||||
inlineCode: (props: Omit<React.HTMLAttributes<HTMLElement>, "color">) => (
|
||||
<Components.Code className="font-normal bg-transparent px-0 py-0 text-code-mdx" {...props} />
|
||||
),
|
||||
inlineCode: InlineCode,
|
||||
InlineCode,
|
||||
// Block,
|
||||
} as unknown) as Record<string, React.ReactNode>;
|
||||
|
||||
@ -8,11 +8,9 @@ url: https://nextui.org/docs/components/avatar
|
||||
|
||||
The Avatar component is used to represent a user, and displays the profile picture, initials or fallback icon.
|
||||
|
||||
<ComponentLinks
|
||||
component="avatar"
|
||||
/>
|
||||
<ComponentLinks component="avatar" />
|
||||
|
||||
## Import
|
||||
## Import
|
||||
|
||||
NextUI exports 3 avatar-related components:
|
||||
|
||||
@ -21,7 +19,7 @@ NextUI exports 3 avatar-related components:
|
||||
- **AvatarIcon**: The default icon used as fallback when the image fails to load.
|
||||
|
||||
```jsx
|
||||
import { Avatar, AvatarGroup, AvatarIcon } from "@nextui-org/react";
|
||||
import {Avatar, AvatarGroup, AvatarIcon} from "@nextui-org/react";
|
||||
```
|
||||
|
||||
## Usage
|
||||
@ -72,17 +70,17 @@ import { Avatar, AvatarGroup, AvatarIcon } from "@nextui-org/react";
|
||||
|
||||
## Props
|
||||
|
||||
| Attribute | Type | Description | Default |
|
||||
| ------------ | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | --------- |
|
||||
| color | "neutral" \| "primary" \| "secondary" \| "success" \| "warning" \| "danger" | Sets the avatar background color. | "neutral" |
|
||||
| radius | "none" \| "base" \| "sm" \| "md" \| "lg" \| "xl" \| "2xl" \| "3xl" \| "full" | Sets the avatar border radius. | "full" |
|
||||
| size | "xs" \| "sm" \| "md" \| "lg" \| "xl" | Sets the avatar size. | "md" |
|
||||
| name | string | Displays the initials if the image is not provided or fails to load. | - |
|
||||
| src | string | The source URL of the image to be displayed. | - |
|
||||
| isBordered | boolean | If `true`, adds a border around the avatar. | false |
|
||||
| isDisabled | boolean | If `true`, disables the avatar and applies a disabled styling. | false |
|
||||
| isFocusable | boolean | If `true`, makes the avatar focusable for keyboard navigation. | false |
|
||||
| icon | node | Displays a custom icon inside the avatar. | - |
|
||||
| classNames | object | Allows to set custom class names for the avatar base, icon, or text. | - |
|
||||
| showFallback | boolean | If `true`, shows the fallback icon or initials when the image fails to load. | false |
|
||||
| fallback | node | A custom fallback component to display when the image fails to load. | - |
|
||||
| Attribute | Type | Description | Default |
|
||||
| ------------ | ------------------------------------------------------------ | ---------------------------------------------------------------------------- | --------- |
|
||||
| src | `string` | The source URL of the image to be displayed. | - |
|
||||
| color | `neutral` `primary` `secondary` `success` `warning` `danger` | Sets the avatar background color. | `neutral` |
|
||||
| radius | `none` `base` `sm` `md` `lg` `xl` `2xl` `3xl` `full` | Sets the avatar border radius. | `full` |
|
||||
| size | `xs` `sm` `md` `lg` `xl` | Sets the avatar size. | `md` |
|
||||
| name | `string` | Displays the initials if the image is not provided or fails to load. | - |
|
||||
| icon | `ReactNode` | Displays a custom icon inside the avatar. | - |
|
||||
| isBordered | `boolean` | If `true`, adds a border around the avatar. | `false` |
|
||||
| isDisabled | `boolean` | If `true`, disables the avatar and applies a disabled styling. | `false` |
|
||||
| isFocusable | `boolean` | If `true`, makes the avatar focusable for keyboard navigation. | `false` |
|
||||
| showFallback | `boolean` | If `true`, shows the fallback icon or initials when the image fails to load. | `false` |
|
||||
| fallback | `ReactNode` | A custom fallback component to display when the image fails to load. | - |
|
||||
| classNames | `base` `img` `fallback` `name` `icon` | Allows to set custom class names for the avatar slots. | - |
|
||||
|
||||
96
apps/docs/content/docs/frameworks/astro.mdx
Normal file
96
apps/docs/content/docs/frameworks/astro.mdx
Normal file
@ -0,0 +1,96 @@
|
||||
---
|
||||
title: Astro
|
||||
description: How to use NextUI with Astro
|
||||
url: https://nextui.org/docs/frameworks/astro
|
||||
---
|
||||
|
||||
# Astro
|
||||
|
||||
Requirements:
|
||||
|
||||
- [React 18](https://reactjs.org/) or later
|
||||
- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/astro) or later
|
||||
- [Framer Motion 4](https://www.framer.com/motion/) or later
|
||||
|
||||
------
|
||||
|
||||
## Installation
|
||||
|
||||
In your Astro project, run one of the following command to install NextUI:
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: 'npm i @nextui-org/react framer-motion',
|
||||
yarn: 'yarn add @nextui-org/react framer-motion',
|
||||
pnpm: 'pnpm add @nextui-org/react framer-motion',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<Spacer y={4}/>
|
||||
|
||||
### Tailwind CSS Setup
|
||||
|
||||
NextUI is built on top of Tailwind CSS, so you need to install Tailwind CSS first. You can follow the official
|
||||
[installation guide](https://tailwindcss.com/docs/guides/astro) to install Tailwind CSS. Then you need to add
|
||||
the following code to your `tailwind.config.cjs` file:
|
||||
|
||||
|
||||
```js {8,13-14}
|
||||
// tailwind.config.cjs
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
}
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
Now you can import NextUI components and use them in your Astro project:
|
||||
|
||||
```markdown
|
||||
---
|
||||
import Layout from '../layouts/Layout.astro';
|
||||
import { Button } from '@nextui-org/react';
|
||||
---
|
||||
|
||||
<Layout title="Welcome to Astro.">
|
||||
<main>
|
||||
<Button color="primary" client:visible>My button</Button>
|
||||
</main>
|
||||
</Layout>
|
||||
```
|
||||
|
||||
Note that you have to add `client:visible` to the component to make it visible only on the client side. Otherwise
|
||||
some functionalities of NextUI components may not work properly.
|
||||
|
||||
|
||||
### Setup pnpm (optional)
|
||||
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
# .npmrc
|
||||
strict-peer-dependencies=false
|
||||
enable-pre-post-scripts=true
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
|
||||
<Blockquote
|
||||
color="warning"
|
||||
>
|
||||
Version 2 is only compatible with React 18 or later. If you are using React 17 or earlier, please use <Link href="https://v1.nextui.org/docs/getting-started" isExternal>version 1 of NextUI</Link>.
|
||||
</Blockquote>
|
||||
156
apps/docs/content/docs/frameworks/nextjs.mdx
Normal file
156
apps/docs/content/docs/frameworks/nextjs.mdx
Normal file
@ -0,0 +1,156 @@
|
||||
---
|
||||
title: Next.js
|
||||
description: How to use NextUI with Next.js
|
||||
url: https://nextui.org/docs/frameworks/nextjs
|
||||
---
|
||||
|
||||
# Next.js
|
||||
|
||||
|
||||
Requirements:
|
||||
|
||||
- [Next.js 12](https://nextjs.org/) or later
|
||||
- [React 18](https://reactjs.org/) or later
|
||||
- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/nextjs) or later
|
||||
- [Framer Motion 4](https://www.framer.com/motion/) or later
|
||||
|
||||
------
|
||||
|
||||
## Installation
|
||||
|
||||
In your Next.js project, run one of the following command to install NextUI:
|
||||
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: 'npm i @nextui-org/react framer-motion',
|
||||
yarn: 'yarn add @nextui-org/react framer-motion',
|
||||
pnpm: 'pnpm add @nextui-org/react framer-motion',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<Spacer y={4}/>
|
||||
|
||||
### Tailwind CSS Setup
|
||||
|
||||
NextUI is built on top of Tailwind CSS, so you need to install Tailwind CSS first. You can follow the official
|
||||
[installation guide](https://tailwindcss.com/docs/guides/nextjs) to install Tailwind CSS. Then you need to add
|
||||
the following code to your `tailwind.config.js` file:
|
||||
|
||||
|
||||
```js {8,13-14}
|
||||
// tailwind.config.js
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
}
|
||||
```
|
||||
|
||||
After installing NextUI, you need to set up the `NextUIProvider` at the `root` of your application.
|
||||
|
||||
### Pages Directory Setup
|
||||
|
||||
Go to pages`/_app.js` or `pages/_app.tsx` (create it if it doesn't exist) and wrap the Component with the `NextUIProvider`:
|
||||
|
||||
```jsx
|
||||
// pages/_app.js
|
||||
import { NextUIProvider } from '@nextui-org/react'
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<NextUIProvider>
|
||||
<Component {...pageProps} />
|
||||
</NextUIProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
```
|
||||
|
||||
### App directory Setup
|
||||
|
||||
Next.js 13 introduces a new `app/` directory structure. By default it uses Server Components.
|
||||
As NextUI components use React hooks, we added the `use client;` at build time, so you can import them
|
||||
directly in your React Server Components (RSC).
|
||||
|
||||
Go to your `app/providers.tsx` or `app/providers.jsx` (create it if it doesn't exist) and wrap the Component with the `NextUIProvider`:
|
||||
|
||||
```jsx
|
||||
// app/providers.tsx
|
||||
'use client'
|
||||
|
||||
import { NextUIProvider } from '@nextui-org/react'
|
||||
|
||||
export function Providers({children}: { children: React.ReactNode }) {
|
||||
return (
|
||||
<NextUIProvider>
|
||||
{children}
|
||||
</NextUIProvider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Now, Go to your `root` layout page and wrap it with the `NextUIProvider`:
|
||||
|
||||
```jsx
|
||||
// app/layout.tsx
|
||||
import { Providers } from "./providers";
|
||||
|
||||
export default function RootLayout({children}: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Now you can import any NextUI component directly in your Server Components without needing to use
|
||||
the `use client;` directive:
|
||||
|
||||
```jsx
|
||||
// app/page.tsx
|
||||
import { Button } from '@nextui-org/react'
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<div>
|
||||
<Button>Click me</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Setup pnpm (optional)
|
||||
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
# .npmrc
|
||||
strict-peer-dependencies=false
|
||||
enable-pre-post-scripts=true
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
<Blockquote
|
||||
color="warning"
|
||||
>
|
||||
Version 2 is only compatible with React 18 or later. If you are using React 17 or earlier, please use <Link href="https://v1.nextui.org/docs/getting-started" isExternal>version 1 of NextUI</Link>.
|
||||
</Blockquote>
|
||||
114
apps/docs/content/docs/frameworks/remix.mdx
Normal file
114
apps/docs/content/docs/frameworks/remix.mdx
Normal file
@ -0,0 +1,114 @@
|
||||
---
|
||||
title: Remix
|
||||
description: How to use NextUI with Remix
|
||||
url: https://nextui.org/docs/frameworks/remix
|
||||
---
|
||||
|
||||
# Remix
|
||||
|
||||
Requirements:
|
||||
|
||||
- [React 18](https://reactjs.org/) or later
|
||||
- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/remix) or later
|
||||
- [Framer Motion 4](https://www.framer.com/motion/) or later
|
||||
|
||||
------
|
||||
|
||||
## Installation
|
||||
|
||||
In your Remix project, run one of the following command to install NextUI:
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: 'npm i @nextui-org/react framer-motion',
|
||||
yarn: 'yarn add @nextui-org/react framer-motion',
|
||||
pnpm: 'pnpm add @nextui-org/react framer-motion',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<Spacer y={4}/>
|
||||
|
||||
### Tailwind CSS Setup
|
||||
|
||||
NextUI is built on top of Tailwind CSS, so you need to install Tailwind CSS first. You can follow the official
|
||||
[installation guide](https://tailwindcss.com/docs/guides/remix) to install Tailwind CSS. Then you need to add
|
||||
the following code to your `tailwind.config.js` file:
|
||||
|
||||
|
||||
```ts {9,14-15}
|
||||
// tailwind.config.ts
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
export default {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
} satisfies Config
|
||||
```
|
||||
|
||||
### Provider Setup
|
||||
|
||||
After installing NextUI, you need to set up the `NextUIProvider` at the `root` of your application.
|
||||
|
||||
Go to the src directory and inside `root.tsx`, wrap `NextUIProvider` around App:
|
||||
|
||||
```tsx {9,19,24}
|
||||
import {
|
||||
Links,
|
||||
LiveReload,
|
||||
Meta,
|
||||
Outlet,
|
||||
Scripts,
|
||||
ScrollRestoration,
|
||||
} from "@remix-run/react";
|
||||
import { NextUIProvider } from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<Meta />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
<NextUIProvider>
|
||||
<Outlet />
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
<LiveReload />
|
||||
</NextUIProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Setup pnpm (optional)
|
||||
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
# .npmrc
|
||||
strict-peer-dependencies=false
|
||||
enable-pre-post-scripts=true
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
|
||||
<Blockquote
|
||||
color="warning"
|
||||
>
|
||||
Version 2 is only compatible with React 18 or later. If you are using React 17 or earlier, please use <Link href="https://v1.nextui.org/docs/getting-started" isExternal>version 1 of NextUI</Link>.
|
||||
</Blockquote>
|
||||
|
||||
102
apps/docs/content/docs/frameworks/vite.mdx
Normal file
102
apps/docs/content/docs/frameworks/vite.mdx
Normal file
@ -0,0 +1,102 @@
|
||||
---
|
||||
title: Vite
|
||||
description: How to use NextUI with Vite
|
||||
url: https://nextui.org/docs/frameworks/vite
|
||||
---
|
||||
|
||||
# Vite
|
||||
|
||||
Requirements:
|
||||
|
||||
- [Vite 2](https://vitejs.dev/) or later
|
||||
- [React 18](https://reactjs.org/) or later
|
||||
- [Tailwind CSS 3](https://tailwindcss.com/docs/guides/vite#react) or later
|
||||
- [Framer Motion 4](https://www.framer.com/motion/) or later
|
||||
|
||||
------
|
||||
|
||||
## Installation
|
||||
|
||||
In your Vite React project, run one of the following command to install NextUI:
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: 'npm i @nextui-org/react framer-motion',
|
||||
yarn: 'yarn add @nextui-org/react framer-motion',
|
||||
pnpm: 'pnpm add @nextui-org/react framer-motion',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
<Spacer y={4}/>
|
||||
|
||||
After installing NextUI, you need do the following steps to complete the installation:
|
||||
|
||||
|
||||
### Tailwind CSS Setup
|
||||
|
||||
NextUI is built on top of Tailwind CSS, so you need to install Tailwind CSS first. You can follow the official
|
||||
[installation guide](https://tailwindcss.com/docs/guides/vite#react) to install Tailwind CSS. Then you need to add
|
||||
the following code to your `tailwind.config.js` file:
|
||||
|
||||
|
||||
```js {8,13-14}
|
||||
// tailwind.config.js
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
}
|
||||
```
|
||||
|
||||
### Provider Setup
|
||||
|
||||
After installing NextUI, you need to set up the `NextUIProvider` at the `root` of your application.
|
||||
|
||||
Go to the src directory and inside `main.jsx` or `main.tsx`, wrap `NextUIProvider` around App:
|
||||
|
||||
```jsx
|
||||
// main.tsx or main.jsx
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import { NextUIProvider } from '@nextui-org/react'
|
||||
import App from './App'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
<NextUIProvider>
|
||||
<App />
|
||||
</NextUIProvider>
|
||||
</React.StrictMode>,
|
||||
)
|
||||
```
|
||||
|
||||
### Setup pnpm (optional)
|
||||
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
# .npmrc
|
||||
strict-peer-dependencies=false
|
||||
enable-pre-post-scripts=true
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
|
||||
<Blockquote
|
||||
color="warning"
|
||||
>
|
||||
Version 2 is only compatible with React 18 or later. If you are using React 17 or earlier, please use <Link href="https://v1.nextui.org/docs/getting-started" isExternal>version 1 of NextUI</Link>.
|
||||
</Blockquote>
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Installation
|
||||
description: Get started with NextUI in the official documentation, and learn more about all our features!
|
||||
url: https://nextui.org/docs/getting-started
|
||||
url: https://nextui.org/docs/guide/installation
|
||||
---
|
||||
|
||||
# Installation
|
||||
@ -12,7 +12,7 @@ Requirements:
|
||||
- [Tailwind CSS 3](https://tailwindcss.com/) or later
|
||||
- [Framer Motion 4](https://www.framer.com/motion/) or later
|
||||
|
||||
<Divider />
|
||||
------
|
||||
|
||||
<Spacer y={4}/>
|
||||
|
||||
@ -31,16 +31,16 @@ To install NextUI, run one of the following commands in your terminal:
|
||||
After installing NextUI, you need do the following steps to complete the installation:
|
||||
|
||||
|
||||
### 1. Setup Tailwind CSS
|
||||
## Tailwind CSS Setup
|
||||
|
||||
NextUI is built on top of Tailwind CSS, so you need to install Tailwind CSS first. You can follow the official
|
||||
[installation guide](https://tailwindcss.com/docs/installation) to install Tailwind CSS. Then you need to add
|
||||
the following code to your `tailwind.config.js` file:
|
||||
|
||||
```js
|
||||
// tailwind.config.js
|
||||
|
||||
const {nextui} = require("@nextui-org/react");
|
||||
```js {8,13-14}
|
||||
// tailwind.config.js
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
@ -56,7 +56,7 @@ module.exports = {
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Setup Provider
|
||||
## Provider Setup
|
||||
|
||||
To ensure proper functioning of React Aria, NextUI utilizes the [React Aria SSRProvider](https://react-spectrum.adobe.com/react-aria/SSRProvider.html) and [Overlay provider](https://react-spectrum.adobe.com/react-aria/useOverlayTrigger.html#example) internally.
|
||||
Therefore, it is essential to incorporate the `NextUIProvider` at the `root` of your application.
|
||||
@ -77,6 +77,20 @@ function App() {
|
||||
}
|
||||
```
|
||||
|
||||
## Setup pnpm (optional)
|
||||
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
# .npmrc
|
||||
strict-peer-dependencies=false
|
||||
enable-pre-post-scripts=true
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
|
||||
<Blockquote
|
||||
color="warning"
|
||||
>
|
||||
@ -86,3 +100,5 @@ function App() {
|
||||
## Framework Guides
|
||||
|
||||
NextUI UI is compatible with your preferred framework. We have compiled comprehensive, step-by-step tutorials for the following frameworks:
|
||||
|
||||
<Frameworks />
|
||||
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Introduction
|
||||
description: NextUI is a UI library for React that helps you build beautiful and accessible user interfaces. Created on top of Tailwind CSS and React Aria.
|
||||
url: https://nextui.org/docs/introduction
|
||||
url: https://nextui.org/docs/guide/introduction
|
||||
---
|
||||
|
||||
# Introduction
|
||||
@ -16,6 +16,8 @@ NextUI is a UI library for React that helps you build beautiful and accessible u
|
||||
|
||||
NextUI's primary goal is to streamline the development process, offering a beautiful and adaptable system design for an enhanced user experience.
|
||||
|
||||
------
|
||||
|
||||
## FAQ
|
||||
|
||||
### Is NextUI a Vercel related project?
|
||||
@ -32,6 +34,12 @@ style overrides, etc.
|
||||
a complete solution for building accessible and customizable user interfaces. Since NextUI is built upon TailwindCSS,
|
||||
you can utilize all TailwindCSS classes within your NextUI components, ensuring optimal compiled CSS size.
|
||||
|
||||
### How NextUI deals with TailwindCSS classes conflicts?
|
||||
|
||||
We created a TailwindCSS utility library called [tailwind-variants](https://www.tailwind-variants.org/) that automatically
|
||||
handle TailwindCSS class conflicts. This ensures your custom classes will consistently override the default ones, eliminating any duplication.
|
||||
|
||||
|
||||
### Does NextUI use runtime CSS?
|
||||
|
||||
No, NextUI version 2 employs TailwindCSS JIT, which generates CSS at build time, eliminating the need for
|
||||
@ -47,7 +55,7 @@ NextUI is specifically designed for React and is built on top of React Aria. As
|
||||
tailored for React applications. However, you can still use the CSS part of NextUI with other frameworks or
|
||||
libraries, but you will lose the benefits of React Aria and pre-built accessible components that come with NextUI.
|
||||
|
||||
<Divider />
|
||||
------
|
||||
|
||||
## Community
|
||||
|
||||
|
||||
158
apps/docs/content/docs/guide/upgrade-to-v2.mdx
Normal file
158
apps/docs/content/docs/guide/upgrade-to-v2.mdx
Normal file
@ -0,0 +1,158 @@
|
||||
---
|
||||
title: Upgrade to v2
|
||||
description: Upgrade from NextUI v1 to v2
|
||||
url: https://nextui.org/docs/guide/upgrade-to-v2
|
||||
---
|
||||
|
||||
|
||||
# Upgrade to v2
|
||||
|
||||
## Installation
|
||||
|
||||
Requirements:
|
||||
|
||||
- [React 18](https://reactjs.org/) or later
|
||||
- [Tailwind CSS 3](https://tailwindcss.com/) or later
|
||||
- [Framer Motion 4](https://www.framer.com/motion/) or later
|
||||
|
||||
-----
|
||||
|
||||
### Upgrade React version
|
||||
|
||||
NextUI v2 requires React 18 or later. To upgrade React, run the following command:
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: 'npm i react@latest react-dom@latest',
|
||||
yarn: 'yarn add react@latest react-dom@latest',
|
||||
pnpm: 'pnpm add react@latest react-dom@latest',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
### Install Framer motion
|
||||
|
||||
In v2, NextUI now requires `framer-motion` as a dependency. To install both, use the following command:
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: 'npm i framer-motion',
|
||||
yarn: 'yarn add framer-motion',
|
||||
pnpm: 'pnpm add framer-motion',
|
||||
}}
|
||||
/>
|
||||
|
||||
### TailwindCSS Setup
|
||||
|
||||
NextUI v2 now uses Tailwind CSS. Add the NextUI plugin to your `tailwind.config.js` file:
|
||||
|
||||
```js {9, 13-14}
|
||||
// tailwind.config.js
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
}
|
||||
```
|
||||
|
||||
### Provider Setup
|
||||
|
||||
The provider setup is essentially the same as v1.
|
||||
|
||||
### Setup pnpm (optional)
|
||||
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
# .npmrc
|
||||
strict-peer-dependencies=false
|
||||
enable-pre-post-scripts=true
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
|
||||
## Next.js upgrade steps
|
||||
|
||||
Make sure to follow the previous steps since they are required to upgrade to v2.
|
||||
|
||||
### Pages Directory Setup
|
||||
|
||||
Go to pages`/_app.js` or `pages/_app.tsx` (create it if it doesn't exist) and wrap the Component with the `NextUIProvider`:
|
||||
|
||||
```jsx
|
||||
// pages/_app.js
|
||||
import { NextUIProvider } from '@nextui-org/react'
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<NextUIProvider>
|
||||
<Component {...pageProps} />
|
||||
</NextUIProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
```
|
||||
|
||||
<Blockquote
|
||||
color="neutral"
|
||||
>
|
||||
Make sure to remove all properties from the previous <InlineCode>NextUIProvider</InlineCode> component. Since now the <InlineCode>theme</InlineCode> is handled by the <InlineCode>nextui</InlineCode> Tailwind plugin.
|
||||
</Blockquote>
|
||||
|
||||
### App Directory Setup
|
||||
|
||||
Go to your `app/providers.tsx` or `app/providers.jsx` (create it if it doesn't exist) and wrap the Component with the `NextUIProvider`:
|
||||
|
||||
```jsx
|
||||
// app/providers.tsx
|
||||
'use client'
|
||||
|
||||
import { NextUIProvider } from '@nextui-org/react'
|
||||
|
||||
export function Providers({children}: { children: React.ReactNode }) {
|
||||
return (
|
||||
<NextUIProvider>
|
||||
{children}
|
||||
</NextUIProvider>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Now, Go to your `root` layout page and wrap it with the `NextUIProvider`:
|
||||
|
||||
```jsx
|
||||
// app/layout.tsx
|
||||
import { Providers } from "./providers";
|
||||
|
||||
export default function RootLayout({children}: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Providers>
|
||||
{children}
|
||||
</Providers>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
<Blockquote
|
||||
color="neutral"
|
||||
>
|
||||
Please visit the <Link href="https://github.com/nextui-org/nextui/releases/tag/v2.0.0" showAnchorIcon isExternal>Release Notes</Link> for more information about the new features and breaking changes.
|
||||
</Blockquote>
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
---
|
||||
title: Container
|
||||
description: A component for fixing an elements width to the current breakpoint.
|
||||
url: https://nextui.org/docs/layout/container
|
||||
---
|
||||
|
||||
# Container
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
---
|
||||
title: Grid
|
||||
description: The layout grid adapts to screen size and orientation, ensuring consistency across layouts.
|
||||
url: https://nextui.org/docs/layout/grid
|
||||
---
|
||||
|
||||
# Grid
|
||||
@ -1,8 +0,0 @@
|
||||
---
|
||||
title: Spacer
|
||||
description: Provide empty space.
|
||||
url: https://nextui.org/docs/layout/spacer
|
||||
---
|
||||
|
||||
# Spacer
|
||||
|
||||
@ -17,6 +17,44 @@
|
||||
"title": "Installation",
|
||||
"keywords": "getting started, installation, start, nextui",
|
||||
"path": "/docs/guide/installation.mdx"
|
||||
},
|
||||
{
|
||||
"key": "upgrade-to-v2",
|
||||
"title": "Upgrade to v2",
|
||||
"keywords": "upgrade, v2, nextui",
|
||||
"path": "/docs/guide/upgrade-to-v2.mdx"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "frameworks",
|
||||
"title": "Frameworks",
|
||||
"defaultOpen": true,
|
||||
"keywords": "frameworks, nextjs + nextui, vite + nextui, remix + nextui, astro + nextui",
|
||||
"routes": [
|
||||
{
|
||||
"key": "nextjs",
|
||||
"title": "Next.js",
|
||||
"keywords": "nextjs, nextui, next.js",
|
||||
"path": "/docs/frameworks/nextjs.mdx"
|
||||
},
|
||||
{
|
||||
"key": "vite",
|
||||
"title": "Vite",
|
||||
"keywords": "vite, nextui",
|
||||
"path": "/docs/frameworks/vite.mdx"
|
||||
},
|
||||
{
|
||||
"key": "remix",
|
||||
"title": "Remix",
|
||||
"keywords": "remix, nextui",
|
||||
"path": "/docs/frameworks/remix.mdx"
|
||||
},
|
||||
{
|
||||
"key": "astro",
|
||||
"title": "Astro",
|
||||
"keywords": "astro, nextui",
|
||||
"path": "/docs/frameworks/astro.mdx"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -59,32 +97,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "layout",
|
||||
"title": "Layout",
|
||||
"keywords": "layout, container, grid, spacer, flex",
|
||||
"defaultOpen": true,
|
||||
"routes": [
|
||||
{
|
||||
"key": "container",
|
||||
"title": "Container",
|
||||
"keywords": "cont, container, flex, media query",
|
||||
"path": "/docs/layout/container.mdx"
|
||||
},
|
||||
{
|
||||
"key": "grid",
|
||||
"title": "Grid",
|
||||
"keywords": "grid, container, media query",
|
||||
"path": "/docs/layout/grid.mdx"
|
||||
},
|
||||
{
|
||||
"key": "spacer",
|
||||
"title": "Spacer",
|
||||
"keywords": "space, spacer, gap",
|
||||
"path": "/docs/layout/spacer.mdx"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "components",
|
||||
"title": "Components",
|
||||
|
||||
@ -52,11 +52,11 @@ export const DocsLayout: FC<DocsLayoutProps> = ({
|
||||
<Head {...meta} />
|
||||
<Navbar />
|
||||
<main className="container mx-auto max-w-7xl min-h-[calc(100dvh_-_64px_-_108px)] px-6 mb-12">
|
||||
<div className="flex">
|
||||
<div className="hidden relative lg:block lg:w-[30%] mt-8 pr-4">
|
||||
<div className="flex xl:gap-12">
|
||||
<div className="hidden relative lg:block lg:w-[30%] mt-8 pr-8">
|
||||
<DocsSidebar routes={routes} slug={slug} tag={tag} />
|
||||
</div>
|
||||
<div className="w-full xl:px-12 mt-10">
|
||||
<div className="w-full mt-10">
|
||||
<div className="w-full prose prose-neutral">{children}</div>
|
||||
<FooterNav nextRoute={nextRoute} prevRoute={prevRoute} tag={tag} />
|
||||
<footer>
|
||||
@ -92,7 +92,7 @@ export const DocsLayout: FC<DocsLayoutProps> = ({
|
||||
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="fixed hidden dark:md:block dark:opacity-70 -top-[60%] -right-[45%] z-[-10] rotate-12"
|
||||
className="fixed hidden dark:md:block dark:opacity-70 -top-[80%] -right-[60%] 2xl:-top-[60%] 2xl:-right-[45%] z-[-10] rotate-12"
|
||||
>
|
||||
<Image
|
||||
removeWrapper
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import NextHead from "next/head";
|
||||
import {useTheme} from "next-themes";
|
||||
import capitalize from "lodash/capitalize";
|
||||
|
||||
import {TWITTER_USER_NAME, SITE_URL} from "@/libs/constants";
|
||||
|
||||
@ -30,7 +29,7 @@ export const Head: React.FC<HeaderProps> = ({
|
||||
const {theme} = useTheme();
|
||||
|
||||
const isDark = theme === "dark";
|
||||
let pageTitle = title ? `${capitalize(title)} | ` : "";
|
||||
let pageTitle = title ? `${title} | ` : "";
|
||||
|
||||
pageTitle += "NextUI - Beautiful, fast and modern React UI Library";
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ export const Navbar = () => {
|
||||
<NextLink href="/">
|
||||
<NextUILogo auto />
|
||||
</NextLink>
|
||||
{isMounted && ref.current && (
|
||||
{isMounted && ref.current ? (
|
||||
<Dropdown placement="bottom-start" portalContainer={ref.current}>
|
||||
<DropdownTrigger>
|
||||
<Button
|
||||
@ -100,6 +100,8 @@ export const Navbar = () => {
|
||||
<DropdownItem key="v1">v1.0.0</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
) : (
|
||||
<div className="w-[66px]" />
|
||||
)}
|
||||
</NavbarBrand>
|
||||
<div className="hidden lg:flex gap-4 ml-10 justify-start">
|
||||
|
||||
@ -4,7 +4,8 @@ const codeTheme: PrismTheme = {
|
||||
plain: {
|
||||
backgroundColor: "hsl(var(--nextui-code-background))",
|
||||
color: "#F4F4F4",
|
||||
fontWeight: "500",
|
||||
fontWeight: "400",
|
||||
fontSize: "14px",
|
||||
fontStyle: "normal",
|
||||
textRendering: "geometricPrecision",
|
||||
},
|
||||
@ -24,13 +25,7 @@ const codeTheme: PrismTheme = {
|
||||
{
|
||||
types: ["punctuation"],
|
||||
style: {
|
||||
color: "#17c964",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["property"],
|
||||
style: {
|
||||
color: "#17c964",
|
||||
color: "#a2e9c1",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -51,6 +46,12 @@ const codeTheme: PrismTheme = {
|
||||
color: "#E5C07B",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["property", "function"],
|
||||
style: {
|
||||
color: "#61AFEF",
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["tag-id", "selector", "atrule-id"],
|
||||
style: {
|
||||
@ -60,7 +61,7 @@ const codeTheme: PrismTheme = {
|
||||
{
|
||||
types: ["attr-name"],
|
||||
style: {
|
||||
color: "#c4841d",
|
||||
color: "#f9c97c",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -70,7 +71,6 @@ const codeTheme: PrismTheme = {
|
||||
"entity",
|
||||
"url",
|
||||
"attr-value",
|
||||
"keyword",
|
||||
"control",
|
||||
"directive",
|
||||
"unit",
|
||||
@ -93,7 +93,7 @@ const codeTheme: PrismTheme = {
|
||||
{
|
||||
types: ["language-javascript", "script"],
|
||||
style: {
|
||||
color: "#17c964",
|
||||
color: "#a2e9c1",
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -115,7 +115,7 @@ const codeTheme: PrismTheme = {
|
||||
},
|
||||
},
|
||||
{
|
||||
types: ["important", "primitive"],
|
||||
types: ["important", "primitive", "keyword"],
|
||||
style: {
|
||||
color: "#c678dd",
|
||||
},
|
||||
|
||||
@ -99,12 +99,8 @@ export const getStaticProps: GetStaticProps = async ({params}) => {
|
||||
doc = content.toString();
|
||||
meta = data;
|
||||
}
|
||||
const mdxSource = await serialize(doc, {
|
||||
mdxOptions: {
|
||||
remarkPlugins: [require("remark-autolink-headings"), require("remark-slug")],
|
||||
rehypePlugins: [require("@mapbox/rehype-prism")],
|
||||
},
|
||||
});
|
||||
|
||||
const mdxSource = await serialize(doc);
|
||||
|
||||
const routes = manifest.routes.map((route: any) => {
|
||||
if (route.icon) {
|
||||
|
||||
@ -7,13 +7,16 @@
|
||||
@apply text-code-foreground;
|
||||
}
|
||||
|
||||
.code-block .token.tag,
|
||||
.code-block .token.selector,
|
||||
.code-block .token.selector .class,
|
||||
.code-block .token.function {
|
||||
@apply text-code-syntax1;
|
||||
}
|
||||
|
||||
.code-block .token.tag {
|
||||
@apply text-code-tag
|
||||
}
|
||||
|
||||
.code-block .token.script.language-javascript {
|
||||
@apply text-code-foreground;
|
||||
}
|
||||
|
||||
@ -19,35 +19,35 @@ module.exports = {
|
||||
extend: {
|
||||
colors: {
|
||||
"code-foreground": "#F4F4F4",
|
||||
"code-syntax1": "#ADD7FF",
|
||||
"code-syntax2": "#5DE4C7",
|
||||
"code-syntax1": "#61AFEF",
|
||||
"code-syntax2": "#98C379",
|
||||
"code-syntax3": "#c678dd",
|
||||
"code-syntax4": "#91B4D5",
|
||||
"code-syntax5": "#5DE4C7",
|
||||
"code-syntax6": "#91B4D5",
|
||||
"code-removed": commonColors.red[300],
|
||||
"code-string": "#5DE4C7",
|
||||
"code-syntax4": "#d4d4d8",
|
||||
"code-syntax5": "#E5C07B",
|
||||
"code-syntax6": "#F5A524",
|
||||
"code-removed": '#f871a0',
|
||||
"code-string": "#98C379",
|
||||
"code-class": "#91B4D5",
|
||||
"code-punctuation": commonColors.green[200],
|
||||
"code-number": "#91B4D5",
|
||||
"code-added": commonColors.green[300],
|
||||
"code-line-number": twColors.zinc[300],
|
||||
"code-faded-line": twColors.zinc[500],
|
||||
"code-comment": twColors.zinc[500],
|
||||
"code-punctuation": '#a2e9c1',
|
||||
"code-number": "#E5C07B",
|
||||
"code-added": '#74dfa2',
|
||||
"code-line-number": '#d4d4d8',
|
||||
"code-faded-line": '#71717a',
|
||||
"code-comment": '#71717a',
|
||||
"code-keyword": "#c678dd",
|
||||
"code-function": "#ADD7FF",
|
||||
"code-function": "#61AFEF",
|
||||
"code-tag": "#E06C75",
|
||||
"code-attr-name": "#91B4D5",
|
||||
"code-language-javascript": "#91B4D5",
|
||||
"code-highlighted-word1-bg": commonColors.purple[500],
|
||||
"code-highlighted-word1-bg-active": commonColors.purple[600],
|
||||
"code-highlighted-word1-text": commonColors.purple[800],
|
||||
"code-highlighted-word2-bg": commonColors.red[100],
|
||||
"code-highlighted-word2-bg-active": commonColors.red[500],
|
||||
"code-highlighted-word2-text": commonColors.red[200],
|
||||
"code-highlighted-word3-bg": commonColors.green[300],
|
||||
"code-highlighted-word3-bg-active": commonColors.green[300],
|
||||
"code-highlighted-word3-text": commonColors.green[100],
|
||||
"code-highlighted-word1-bg": '#7828c8',
|
||||
"code-highlighted-word1-bg-active": '#6020a0',
|
||||
"code-highlighted-word1-text": '#301050',
|
||||
"code-highlighted-word2-bg": '#fdd0df',
|
||||
"code-highlighted-word2-bg-active": '#f31260',
|
||||
"code-highlighted-word2-text": '#faa0bf',
|
||||
"code-highlighted-word3-bg": '#74dfa2',
|
||||
"code-highlighted-word3-bg-active": '#74dfa2',
|
||||
"code-highlighted-word3-text": '#d1f4e0',
|
||||
},
|
||||
boxShadow: {
|
||||
highlighted: `${commonColors.purple[500]} 1px 0 0, ${commonColors.purple[500]} -1px 0 0`,
|
||||
@ -180,21 +180,17 @@ module.exports = {
|
||||
lineHeight: theme("fontSize.sm")[1].lineHeight,
|
||||
},
|
||||
thead: {
|
||||
color: theme("colors.slate.700"),
|
||||
borderBottomColor: theme("colors.slate.200"),
|
||||
border: 'none',
|
||||
},
|
||||
"thead th": {
|
||||
paddingTop: 0,
|
||||
fontWeight: theme("fontWeight.semibold"),
|
||||
},
|
||||
"tbody tr": {
|
||||
borderBottomColor: theme("colors.slate.100"),
|
||||
border: 'none',
|
||||
},
|
||||
"tbody tr:last-child": {
|
||||
borderBottomWidth: "1px",
|
||||
},
|
||||
"tbody code": {
|
||||
fontSize: theme("fontSize.xs")[0],
|
||||
border: 'none',
|
||||
},
|
||||
"figure figcaption": {
|
||||
textAlign: "center",
|
||||
@ -314,7 +310,7 @@ module.exports = {
|
||||
},
|
||||
dark: {
|
||||
"code-background": "#111111",
|
||||
"code-mdx": "#c678dd",
|
||||
"code-mdx": "#06B7DB",
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
@ -15,7 +15,7 @@ export function getHeadings(): Heading[] {
|
||||
|
||||
return Array.from(headings).map((h) => {
|
||||
return {
|
||||
id: h.id,
|
||||
id: h.getAttribute("data-id"),
|
||||
text: h.getAttribute("data-name"),
|
||||
level: h.getAttribute("data-level"),
|
||||
};
|
||||
|
||||
26
examples/with-tailwindcss/.gitignore
vendored
26
examples/with-tailwindcss/.gitignore
vendored
@ -1,26 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
@ -1,70 +0,0 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "with-tailwindcss",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@nextui-org/react": "^2.0.0-beta.1",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.1.1",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^17.0.2,
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.5",
|
||||
"postcss": "^8.4.12",
|
||||
"tailwindcss": "^3.0.24"
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.8 KiB |
@ -1,43 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.4 KiB |
@ -1,25 +0,0 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@ -1,38 +0,0 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
import './App.css';
|
||||
import { Container, Link, Button } from '@nextui-org/react';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Container className="flex flex-col h-screen justify-center items-center">
|
||||
<h1 className="text-7xl mb-10 font-bold">
|
||||
Welcome to
|
||||
<Link href="https://tailwindcss.com/" rel="noreferer" target="_blank">
|
||||
tailwindcss
|
||||
</Link>
|
||||
+
|
||||
<Link
|
||||
href="https://nextui.org?utm_source=with-tailwindcss-example"
|
||||
target="_blank"
|
||||
>
|
||||
NextUI
|
||||
</Link>
|
||||
</h1>
|
||||
<Button
|
||||
href="https://nextui.org?utm_source=with-tailwindcss-example"
|
||||
target="_blank"
|
||||
as="a"
|
||||
>
|
||||
Go to NextUI
|
||||
</Button>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@ -1,8 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
@ -1,16 +0,0 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { NextUIProvider } from '@nextui-org/react';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<NextUIProvider>
|
||||
<App />
|
||||
</NextUIProvider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB |
@ -1,13 +0,0 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
@ -1,5 +0,0 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
@ -1,7 +0,0 @@
|
||||
module.exports = {
|
||||
content: ['./src/**/*.{js,jsx,ts,tsx}'],
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
plugins: []
|
||||
};
|
||||
@ -50,6 +50,7 @@ export function useDropdown(props: UseDropdownProps) {
|
||||
closeOnSelect = true,
|
||||
classNames: classNamesProp,
|
||||
disableAnimation = false,
|
||||
onClose,
|
||||
className,
|
||||
...otherProps
|
||||
} = props;
|
||||
@ -64,7 +65,17 @@ export function useDropdown(props: UseDropdownProps) {
|
||||
const triggerId = useId();
|
||||
const menuId = useId();
|
||||
|
||||
const state = useMenuTriggerState({trigger, isOpen, defaultOpen, onOpenChange});
|
||||
const state = useMenuTriggerState({
|
||||
trigger,
|
||||
isOpen,
|
||||
defaultOpen,
|
||||
onOpenChange: (isOpen) => {
|
||||
onOpenChange?.(isOpen);
|
||||
if (!isOpen) {
|
||||
onClose?.();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const {menuTriggerProps, menuProps} = useMenuTrigger(
|
||||
{type, trigger, isDisabled},
|
||||
|
||||
@ -494,7 +494,7 @@ const CustomTriggerTemplate: ComponentStory<any> = ({variant, ...args}) => {
|
||||
<DropdownTrigger>
|
||||
<Avatar
|
||||
isBordered
|
||||
as="button"
|
||||
isFocusable
|
||||
className="transition-transform"
|
||||
color="secondary"
|
||||
size="lg"
|
||||
@ -526,7 +526,7 @@ const CustomTriggerTemplate: ComponentStory<any> = ({variant, ...args}) => {
|
||||
<Dropdown {...args} placement="bottom-start">
|
||||
<DropdownTrigger>
|
||||
<User
|
||||
as="button"
|
||||
isFocusable
|
||||
avatarProps={{
|
||||
isBordered: true,
|
||||
color: "primary",
|
||||
|
||||
105
packages/components/popover/src/use-aria-popover.ts
Normal file
105
packages/components/popover/src/use-aria-popover.ts
Normal file
@ -0,0 +1,105 @@
|
||||
import {RefObject, useLayoutEffect} from "react";
|
||||
import {
|
||||
AriaPopoverProps,
|
||||
useOverlay,
|
||||
PopoverAria,
|
||||
usePreventScroll,
|
||||
useOverlayPosition,
|
||||
} from "@react-aria/overlays";
|
||||
import {OverlayPlacement, toReactAriaPlacement, ariaHideOutside} from "@nextui-org/aria-utils";
|
||||
import {OverlayTriggerState} from "@react-stately/overlays";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
|
||||
export interface Props {
|
||||
/**
|
||||
* Whether the element should render an arrow.
|
||||
* @default false
|
||||
*/
|
||||
showArrow?: boolean;
|
||||
/**
|
||||
* The placement of the element with respect to its anchor element.
|
||||
* @default 'top'
|
||||
*/
|
||||
placement?: OverlayPlacement;
|
||||
/**
|
||||
* A ref for the scrollable region within the overlay.
|
||||
* @default popoverRef
|
||||
*/
|
||||
scrollRef?: RefObject<HTMLElement>;
|
||||
}
|
||||
|
||||
export type ReactAriaPopoverProps = Props & Omit<AriaPopoverProps, "placement">;
|
||||
|
||||
/**
|
||||
* Provides the behavior and accessibility implementation for a popover component.
|
||||
* A popover is an overlay element positioned relative to a trigger.
|
||||
*/
|
||||
export function useReactAriaPopover(
|
||||
props: ReactAriaPopoverProps,
|
||||
state: OverlayTriggerState,
|
||||
): PopoverAria {
|
||||
const {
|
||||
triggerRef,
|
||||
popoverRef,
|
||||
showArrow,
|
||||
offset = 7,
|
||||
crossOffset = 0,
|
||||
scrollRef,
|
||||
shouldFlip,
|
||||
placement: placementProp = "top",
|
||||
containerPadding,
|
||||
isNonModal: isNonModalProp,
|
||||
isKeyboardDismissDisabled,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
const isNonModal = isNonModalProp || true;
|
||||
|
||||
const {overlayProps, underlayProps} = useOverlay(
|
||||
{
|
||||
isOpen: state.isOpen,
|
||||
onClose: state.close,
|
||||
shouldCloseOnBlur: true,
|
||||
isDismissable: !isNonModal,
|
||||
isKeyboardDismissDisabled,
|
||||
shouldCloseOnInteractOutside(element) {
|
||||
// Don't close if the click is within the trigger or the popover itself
|
||||
let trigger = triggerRef?.current;
|
||||
|
||||
return !trigger || !trigger.contains(element);
|
||||
},
|
||||
},
|
||||
popoverRef,
|
||||
);
|
||||
|
||||
const {overlayProps: positionProps, arrowProps, placement} = useOverlayPosition({
|
||||
...otherProps,
|
||||
scrollRef,
|
||||
crossOffset,
|
||||
shouldFlip,
|
||||
containerPadding,
|
||||
targetRef: triggerRef,
|
||||
overlayRef: popoverRef,
|
||||
isOpen: state.isOpen,
|
||||
placement: toReactAriaPlacement(placementProp),
|
||||
offset: showArrow ? offset + 3 : offset,
|
||||
onClose: () => {},
|
||||
});
|
||||
|
||||
usePreventScroll({
|
||||
isDisabled: isNonModal,
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (state.isOpen && !isNonModal && popoverRef.current) {
|
||||
return ariaHideOutside([popoverRef.current]);
|
||||
}
|
||||
}, [isNonModal, state.isOpen, popoverRef]);
|
||||
|
||||
return {
|
||||
popoverProps: mergeProps(overlayProps, positionProps),
|
||||
arrowProps,
|
||||
underlayProps,
|
||||
placement,
|
||||
};
|
||||
}
|
||||
@ -1,29 +1,21 @@
|
||||
import type {PopoverVariantProps, SlotsToClasses, PopoverSlots} from "@nextui-org/theme";
|
||||
import type {HTMLMotionProps} from "framer-motion";
|
||||
import type {RefObject, Ref} from "react";
|
||||
import type {OverlayPlacement} from "@nextui-org/aria-utils";
|
||||
|
||||
import {OverlayTriggerState, useOverlayTriggerState} from "@react-stately/overlays";
|
||||
import {useFocusRing} from "@react-aria/focus";
|
||||
import {
|
||||
AriaPopoverProps,
|
||||
useOverlayTrigger,
|
||||
usePopover as useReactAriaPopover,
|
||||
usePreventScroll,
|
||||
} from "@react-aria/overlays";
|
||||
import {useOverlayTrigger, usePreventScroll} from "@react-aria/overlays";
|
||||
import {OverlayTriggerProps} from "@react-types/overlays";
|
||||
import {HTMLNextUIProps, mapPropsVariants, PropGetter} from "@nextui-org/system";
|
||||
import {
|
||||
toReactAriaPlacement,
|
||||
getArrowPlacement,
|
||||
getShouldUseAxisPlacement,
|
||||
} from "@nextui-org/aria-utils";
|
||||
import {getArrowPlacement, getShouldUseAxisPlacement} from "@nextui-org/aria-utils";
|
||||
import {popover} from "@nextui-org/theme";
|
||||
import {mergeProps, mergeRefs} from "@react-aria/utils";
|
||||
import {createDOMRef} from "@nextui-org/dom-utils";
|
||||
import {ReactRef, clsx, dataAttr} from "@nextui-org/shared-utils";
|
||||
import {useId, useMemo, useCallback, useImperativeHandle, useRef} from "react";
|
||||
|
||||
import {useReactAriaPopover, ReactAriaPopoverProps} from "./use-aria-popover";
|
||||
|
||||
export interface Props extends HTMLNextUIProps<"div"> {
|
||||
/**
|
||||
* Ref to the DOM node.
|
||||
@ -33,25 +25,10 @@ export interface Props extends HTMLNextUIProps<"div"> {
|
||||
* The controlled state of the popover.
|
||||
*/
|
||||
state?: OverlayTriggerState;
|
||||
/**
|
||||
* A ref for the scrollable region within the overlay.
|
||||
* @default popoverRef
|
||||
*/
|
||||
scrollRef?: RefObject<HTMLElement>;
|
||||
/**
|
||||
* The ref for the element which the overlay positions itself with respect to.
|
||||
*/
|
||||
triggerRef?: RefObject<HTMLElement>;
|
||||
/**
|
||||
* The placement of the element with respect to its anchor element.
|
||||
* @default 'top'
|
||||
*/
|
||||
placement?: OverlayPlacement;
|
||||
/**
|
||||
* Whether the element should render an arrow.
|
||||
* @default false
|
||||
*/
|
||||
showArrow?: boolean;
|
||||
/**
|
||||
* Whether the scroll event should be blocked when the overlay is open.
|
||||
* @default true
|
||||
@ -91,7 +68,7 @@ export interface Props extends HTMLNextUIProps<"div"> {
|
||||
}
|
||||
|
||||
export type UsePopoverProps = Props &
|
||||
Omit<AriaPopoverProps, "placement" | "triggerRef" | "popoverRef"> &
|
||||
Omit<ReactAriaPopoverProps, "triggerRef" | "popoverRef"> &
|
||||
OverlayTriggerProps &
|
||||
PopoverVariantProps;
|
||||
|
||||
@ -162,9 +139,8 @@ export function usePopover(originalProps: UsePopoverProps) {
|
||||
{
|
||||
triggerRef,
|
||||
popoverRef,
|
||||
isNonModal: true,
|
||||
placement: toReactAriaPlacement(placementProp),
|
||||
offset: showArrow ? offset + 3 : offset,
|
||||
placement: placementProp,
|
||||
offset: offset,
|
||||
scrollRef,
|
||||
crossOffset,
|
||||
shouldFlip,
|
||||
|
||||
@ -62,6 +62,10 @@ export interface UseSnippetProps
|
||||
* @default false
|
||||
*/
|
||||
autoFocus?: boolean;
|
||||
/**
|
||||
* The code string to copy. if `codeString` is passed, it will be copied instead of the children.
|
||||
*/
|
||||
codeString?: string;
|
||||
/**
|
||||
* Whether to hide the tooltip.
|
||||
* @default false
|
||||
@ -126,6 +130,7 @@ export function useSnippet(originalProps: UseSnippetProps) {
|
||||
timeout,
|
||||
copyIcon,
|
||||
checkIcon,
|
||||
codeString,
|
||||
disableCopy = false,
|
||||
disableTooltip = false,
|
||||
hideCopyButton = false,
|
||||
@ -198,11 +203,11 @@ export function useSnippet(originalProps: UseSnippetProps) {
|
||||
value = children.join("\n");
|
||||
}
|
||||
|
||||
const valueToCopy = value || preRef.current?.textContent || "";
|
||||
const valueToCopy = codeString || value || preRef.current?.textContent || "";
|
||||
|
||||
copy(valueToCopy);
|
||||
onCopyProp?.(valueToCopy);
|
||||
}, [copy, disableCopy, onCopyProp, children]);
|
||||
}, [copy, codeString, disableCopy, onCopyProp, children]);
|
||||
|
||||
const defaultCopyButtonProps: ButtonProps = {
|
||||
"aria-label": "Copy to clipboard",
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/aria-utils": "workspace:*",
|
||||
"@nextui-org/framer-transitions": "workspace:*",
|
||||
"@nextui-org/use-is-mounted": "workspace:*",
|
||||
"@react-aria/focus": "^3.12.0",
|
||||
"@react-aria/interactions": "^3.15.0",
|
||||
"@react-aria/tabs": "^3.5.0",
|
||||
|
||||
@ -8,6 +8,7 @@ import {useTab} from "@react-aria/tabs";
|
||||
import {useHover} from "@react-aria/interactions";
|
||||
import {motion} from "framer-motion";
|
||||
import {TRANSITION_EASINGS} from "@nextui-org/framer-transitions";
|
||||
import {useIsMounted} from "@nextui-org/use-is-mounted";
|
||||
|
||||
import {useTabsContext} from "./tabs-context";
|
||||
|
||||
@ -57,6 +58,10 @@ const TabItem = forwardRef<TabItemProps, "div">((props, ref) => {
|
||||
|
||||
const ariaControls = item?.props.children ? `${tabPanelId}-${key}` : undefined;
|
||||
|
||||
const [, isMounted] = useIsMounted({
|
||||
rerender: true,
|
||||
});
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={domRef}
|
||||
@ -86,11 +91,11 @@ const TabItem = forwardRef<TabItemProps, "div">((props, ref) => {
|
||||
}}
|
||||
onClick={chain(onClick, tabProps.onClick)}
|
||||
>
|
||||
{isSelected && !disableAnimation && !disableCursor ? (
|
||||
{isSelected && !disableAnimation && !disableCursor && isMounted ? (
|
||||
<motion.span
|
||||
className={slots.cursor({class: classNames?.cursor})}
|
||||
layoutDependency={false}
|
||||
layoutId="tab-item-cursor"
|
||||
layoutId="cursor"
|
||||
transition={{
|
||||
ease: TRANSITION_EASINGS.softSpring,
|
||||
duration: 0.6,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {forwardRef, ForwardedRef, ReactElement, Ref} from "react";
|
||||
import {forwardRef, ForwardedRef, ReactElement, Ref, useId} from "react";
|
||||
import {LayoutGroup} from "framer-motion";
|
||||
|
||||
import {TabsProvider} from "./tabs-context";
|
||||
import {UseTabsProps, useTabs} from "./use-tabs";
|
||||
@ -10,13 +11,25 @@ interface Props<T> extends Omit<UseTabsProps<T>, "ref"> {}
|
||||
function Tabs<T extends object>(props: Props<T>, ref: ForwardedRef<HTMLDivElement>) {
|
||||
const {Component, state, context, getBaseProps, getTabListProps} = useTabs<T>({ref, ...props});
|
||||
|
||||
const layoutId = useId();
|
||||
|
||||
const layoutGroupEnabled = !props.disableAnimation && !props.disableCursor;
|
||||
|
||||
return (
|
||||
<TabsProvider value={context}>
|
||||
<div {...getBaseProps()}>
|
||||
<Component {...getTabListProps()}>
|
||||
{[...state.collection].map((item) => (
|
||||
<TabItem key={item.key} item={item} {...item.props} />
|
||||
))}
|
||||
{layoutGroupEnabled ? (
|
||||
<LayoutGroup id={layoutId}>
|
||||
{[...state.collection].map((item) => (
|
||||
<TabItem key={item.key} item={item} {...item.props} />
|
||||
))}
|
||||
</LayoutGroup>
|
||||
) : (
|
||||
[...state.collection].map((item) => (
|
||||
<TabItem key={item.key} item={item} {...item.props} />
|
||||
))
|
||||
)}
|
||||
</Component>
|
||||
</div>
|
||||
<TabPanel key={state.selectedItem?.key} />
|
||||
|
||||
170
packages/utilities/aria-utils/src/overlays/ariaHideOutside.ts
Normal file
170
packages/utilities/aria-utils/src/overlays/ariaHideOutside.ts
Normal file
@ -0,0 +1,170 @@
|
||||
/**
|
||||
* This code comes from @react-aria/overlays
|
||||
*/
|
||||
|
||||
// Keeps a ref count of all hidden elements. Added to when hiding an element, and
|
||||
// subtracted from when showing it again. When it reaches zero, aria-hidden is removed.
|
||||
let refCountMap = new WeakMap<Element, number>();
|
||||
let observerStack: any = [];
|
||||
|
||||
/**
|
||||
* Hides all elements in the DOM outside the given targets from screen readers using aria-hidden,
|
||||
* and returns a function to revert these changes. In addition, changes to the DOM are watched
|
||||
* and new elements outside the targets are automatically hidden.
|
||||
* @param targets - The elements that should remain visible.
|
||||
* @param root - Nothing will be hidden above this element.
|
||||
* @returns - A function to restore all hidden elements.
|
||||
*/
|
||||
export function ariaHideOutside(targets: Element[], root = document.body) {
|
||||
let visibleNodes = new Set<Element>(targets);
|
||||
let hiddenNodes = new Set<Element>();
|
||||
|
||||
let walk = (root: Element) => {
|
||||
// Keep live announcer and top layer elements (e.g. toasts) visible.
|
||||
// @ts-ignore
|
||||
for (let element of root.querySelectorAll(
|
||||
"[data-live-announcer], [data-react-aria-top-layer]",
|
||||
)) {
|
||||
visibleNodes.add(element);
|
||||
}
|
||||
|
||||
let acceptNode = (node: Element) => {
|
||||
const parentElement = node.parentElement as HTMLElement;
|
||||
|
||||
// Skip this node and its children if it is one of the target nodes, or a live announcer.
|
||||
// Also skip children of already hidden nodes, as aria-hidden is recursive. An exception is
|
||||
// made for elements with role="row" since VoiceOver on iOS has issues hiding elements with role="row".
|
||||
// For that case we want to hide the cells inside as well (https://bugs.webkit.org/show_bug.cgi?id=222623).
|
||||
if (
|
||||
visibleNodes.has(node) ||
|
||||
(hiddenNodes.has(parentElement) && parentElement.getAttribute("role") !== "row")
|
||||
) {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
|
||||
// Skip this node but continue to children if one of the targets is inside the node.
|
||||
for (let target of visibleNodes) {
|
||||
if (node.contains(target)) {
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
}
|
||||
}
|
||||
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
};
|
||||
|
||||
let walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, {acceptNode});
|
||||
|
||||
// TreeWalker does not include the root.
|
||||
let acceptRoot = acceptNode(root);
|
||||
|
||||
if (acceptRoot === NodeFilter.FILTER_ACCEPT) {
|
||||
hide(root);
|
||||
}
|
||||
|
||||
if (acceptRoot !== NodeFilter.FILTER_REJECT) {
|
||||
let node = walker.nextNode() as Element;
|
||||
|
||||
while (node != null) {
|
||||
hide(node);
|
||||
node = walker.nextNode() as Element;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let hide = (node: Element) => {
|
||||
let refCount = refCountMap.get(node) ?? 0;
|
||||
|
||||
// If already aria-hidden, and the ref count is zero, then this element
|
||||
// was already hidden and there's nothing for us to do.
|
||||
if (node.getAttribute("aria-hidden") === "true" && refCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (refCount === 0) {
|
||||
node.setAttribute("aria-hidden", "true");
|
||||
}
|
||||
|
||||
hiddenNodes.add(node);
|
||||
refCountMap.set(node, refCount + 1);
|
||||
};
|
||||
|
||||
// If there is already a MutationObserver listening from a previous call,
|
||||
// disconnect it so the new on takes over.
|
||||
if (observerStack.length) {
|
||||
observerStack[observerStack.length - 1].disconnect();
|
||||
}
|
||||
|
||||
walk(root);
|
||||
|
||||
let observer = new MutationObserver((changes: any) => {
|
||||
for (let change of changes) {
|
||||
if (change.type !== "childList" || change.addedNodes.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the parent element of the added nodes is not within one of the targets,
|
||||
// and not already inside a hidden node, hide all of the new children.
|
||||
if (![...visibleNodes, ...hiddenNodes].some((node) => node.contains(change.target))) {
|
||||
for (let node of change.removedNodes) {
|
||||
if (node instanceof Element) {
|
||||
visibleNodes.delete(node);
|
||||
hiddenNodes.delete(node);
|
||||
}
|
||||
}
|
||||
|
||||
for (let node of change.addedNodes) {
|
||||
if (
|
||||
(node instanceof HTMLElement || node instanceof SVGElement) &&
|
||||
(node.dataset.liveAnnouncer === "true" || node.dataset.reactAriaTopLayer === "true")
|
||||
) {
|
||||
visibleNodes.add(node);
|
||||
} else if (node instanceof Element) {
|
||||
walk(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(root, {childList: true, subtree: true});
|
||||
|
||||
let observerWrapper = {
|
||||
observe() {
|
||||
observer.observe(root, {childList: true, subtree: true});
|
||||
},
|
||||
disconnect() {
|
||||
observer.disconnect();
|
||||
},
|
||||
};
|
||||
|
||||
observerStack.push(observerWrapper);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
|
||||
for (let node of hiddenNodes) {
|
||||
let count = refCountMap.get(node);
|
||||
|
||||
if (count == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count === 1) {
|
||||
node.removeAttribute("aria-hidden");
|
||||
refCountMap.delete(node);
|
||||
} else {
|
||||
refCountMap.set(node, count - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove this observer from the stack, and start the previous one.
|
||||
if (observerWrapper === observerStack[observerStack.length - 1]) {
|
||||
observerStack.pop();
|
||||
if (observerStack.length) {
|
||||
observerStack[observerStack.length - 1].observe();
|
||||
}
|
||||
} else {
|
||||
observerStack.splice(observerStack.indexOf(observerWrapper), 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,2 +1,3 @@
|
||||
export * from "./types";
|
||||
export * from "./utils";
|
||||
export * from "./ariaHideOutside";
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@ -1647,6 +1647,9 @@ importers:
|
||||
'@nextui-org/theme':
|
||||
specifier: workspace:*
|
||||
version: link:../../core/theme
|
||||
'@nextui-org/use-is-mounted':
|
||||
specifier: workspace:*
|
||||
version: link:../../hooks/use-is-mounted
|
||||
'@react-aria/focus':
|
||||
specifier: ^3.12.0
|
||||
version: 3.12.0(react@18.2.0)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user