Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a53e274d5b | |||
| 425a034bca | |||
| a5a1ea5ade | |||
| f6531c5f60 | |||
| 37d5f12162 | |||
| dd97fc3c4f | |||
| ceddd0d1d9 | |||
| bb8ed58749 | |||
| bbbdcbdfdf | |||
| bc424948c7 | |||
| cdc30db14c | |||
| 3aa86423aa | |||
| 59ed34b3de | |||
| f58fc9bb69 | |||
| 9a478b6c1f | |||
| 7fd0327657 | |||
| 05c966e8a4 | |||
| 5b014b76ff | |||
| cf32b5ae8b | |||
| 4452ed66c0 | |||
| b1b30b7976 | |||
| 97ef2d7250 | |||
| 8b39989090 | |||
| 8363a3ecfc | |||
| 5c30e04811 | |||
| 8606fbe0b9 | |||
| 1612532eee | |||
| a3be419cb3 | |||
| 72a7f71377 | |||
| 7c8341035d | |||
| 6ca0ce309a | |||
| acc2ff3913 | |||
| 4db10a47e9 | |||
| a9c4fab011 | |||
| d61428d9e6 | |||
| 455b788924 | |||
| 79cfdbd8ff | |||
| 7d294e3a04 | |||
| 43906f639e | |||
| 8fcc8b3767 | |||
| 28477447d3 | |||
| fc3c6b9431 | |||
| 59fda3772f | |||
| d8d2b87cb8 | |||
| 64571e468c | |||
| faf26acd23 | |||
| cac56faf29 | |||
| 09fe1d3141 | |||
| a9e324b351 | |||
| 043b8420cf | |||
| 57909accde | |||
| 7a17256268 | |||
| bf2bc265ee | |||
| cf6bf749a1 | |||
| 641bf0885b | |||
| 40b42001f9 | |||
| 789a7209a2 | |||
| 021aa16d96 | |||
| eb8a1fcc01 | |||
| 9b42a2fca1 | |||
| 5702287e56 | |||
| 290cce15be | |||
| 27bde30839 | |||
| 6be3bc3516 | |||
| e4113b05ce | |||
| a3a95e7196 | |||
| 8731159702 | |||
| b6adb2ae8c | |||
| cd2d9b70a9 | |||
| a371e1a5fa | |||
| 5cdc4d1d87 | |||
| 22c6e070dd | |||
| 0714192838 | |||
| ae9f300d45 | |||
| a16dac04c8 | |||
| 94db001961 | |||
| d77cf7658b | |||
| 46c47f7e6e | |||
| 35b9741663 | |||
| 2b82ba86eb | |||
| 904f538779 | |||
| 609e9f4c11 |
+1
-1
@@ -182,7 +182,7 @@ pnpm test:update src/button # or npm run test:update src/button
|
||||
pnpm build # or npm run build
|
||||
```
|
||||
|
||||
> Note: ensure your version of Node is 14 or higher to run scripts
|
||||
> Note: ensure your version of Node is 16 or higher to run scripts
|
||||
|
||||
6. Send your pull request:
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
Spinner,
|
||||
Pagination,
|
||||
} from "@nextui-org/react";
|
||||
import {useAsyncList} from "@react-stately/data";
|
||||
import {useCallback, useMemo, useState} from "react";
|
||||
import {useMemo, useState} from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
type SWCharacter = {
|
||||
name: string;
|
||||
@@ -21,50 +21,23 @@ type SWCharacter = {
|
||||
birth_year: string;
|
||||
};
|
||||
|
||||
const fetcher = (...args: Parameters<typeof fetch>) => fetch(...args).then((res) => res.json());
|
||||
|
||||
export default function Page() {
|
||||
const [page, setPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const {data, isLoading} = useSWR<{
|
||||
count: number;
|
||||
results: SWCharacter[];
|
||||
}>(`https://swapi.py4e.com/api/people?page=${page}`, fetcher, {
|
||||
keepPreviousData: true,
|
||||
});
|
||||
|
||||
const rowsPerPage = 10;
|
||||
|
||||
let list = useAsyncList<SWCharacter>({
|
||||
async load({signal, cursor}) {
|
||||
// If no cursor is available, then we're loading the first page.
|
||||
// Otherwise, the cursor is the next URL to load, as returned from the previous page.
|
||||
const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
|
||||
let json = await res.json();
|
||||
|
||||
setTotal(json.count);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
return {
|
||||
items: json.results,
|
||||
cursor: json.next,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const pages = Math.ceil(total / rowsPerPage);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const start = (page - 1) * rowsPerPage;
|
||||
const end = start + rowsPerPage;
|
||||
|
||||
return list.items.slice(start, end);
|
||||
}, [page, list.items?.length]);
|
||||
|
||||
const onPaginationChange = useCallback(
|
||||
(page: number) => {
|
||||
setIsLoading(true);
|
||||
if (page >= list.items.length / rowsPerPage) {
|
||||
list.loadMore();
|
||||
}
|
||||
setPage(page);
|
||||
},
|
||||
[list.items.length],
|
||||
);
|
||||
const pages = useMemo(() => {
|
||||
return data?.count ? Math.ceil(data.count / rowsPerPage) : 0;
|
||||
}, [data?.count, rowsPerPage]);
|
||||
|
||||
return (
|
||||
<div className="p-6">
|
||||
@@ -80,7 +53,7 @@ export default function Page() {
|
||||
color="primary"
|
||||
page={page}
|
||||
total={pages}
|
||||
onChange={onPaginationChange}
|
||||
onChange={(page) => setPage(page)}
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
@@ -96,8 +69,8 @@ export default function Page() {
|
||||
<TableColumn key="birth_year">Birth year</TableColumn>
|
||||
</TableHeader>
|
||||
<TableBody
|
||||
isLoading={isLoading && !items.length}
|
||||
items={items}
|
||||
isLoading={isLoading || data?.results.length === 0}
|
||||
items={data?.results ?? []}
|
||||
loadingContent={<Spinner />}
|
||||
>
|
||||
{(item) => (
|
||||
|
||||
@@ -256,7 +256,7 @@ const users = [
|
||||
},
|
||||
];
|
||||
|
||||
type User = typeof users[0];
|
||||
type User = (typeof users)[number];
|
||||
|
||||
export default function Page() {
|
||||
const [filterValue, setFilterValue] = useState("");
|
||||
|
||||
@@ -256,7 +256,7 @@ const users = [
|
||||
},
|
||||
];
|
||||
|
||||
type User = typeof users[0];
|
||||
type User = (typeof users)[number];
|
||||
|
||||
export default function Page() {
|
||||
const [filterValue, setFilterValue] = useState("");
|
||||
|
||||
@@ -24,7 +24,8 @@ export async function GET() {
|
||||
url: `${siteConfig.siteUrl}/blog/${post.slug}`,
|
||||
guid: `${siteConfig.siteUrl}/blog/${post.slug}`,
|
||||
date: post.date,
|
||||
author: `${author} <${siteConfig.email}>`,
|
||||
// @ts-ignore - name does exist
|
||||
author: `${author.name} <${siteConfig.email}>`,
|
||||
categories: post.tags ?? [],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {Button, Image, Link} from "@nextui-org/react";
|
||||
import {Image} from "@nextui-org/react";
|
||||
|
||||
import {Blockquote} from "@/components/docs/components/blockquote";
|
||||
import {FigmaButton} from "@/components/figma-button";
|
||||
|
||||
export default function FigmaPage() {
|
||||
return (
|
||||
@@ -23,16 +24,7 @@ export default function FigmaPage() {
|
||||
width="800"
|
||||
/>
|
||||
<div className="text-center max-w-2xl m-auto">
|
||||
<Button className="max-w-fit" color="default" variant="bordered">
|
||||
<Link
|
||||
isExternal
|
||||
showAnchorIcon
|
||||
className="text-current"
|
||||
href="https://www.figma.com/community/file/1267584376234254760"
|
||||
>
|
||||
Open in Figma
|
||||
</Link>
|
||||
</Button>
|
||||
<FigmaButton />
|
||||
<Blockquote color="warning">
|
||||
This file is still in development and will be continuously updated.
|
||||
</Blockquote>
|
||||
|
||||
@@ -53,6 +53,12 @@ export const metadata: Metadata = {
|
||||
},
|
||||
],
|
||||
creator: "jrgarciadev",
|
||||
alternates: {
|
||||
canonical: "https://nextui.org",
|
||||
types: {
|
||||
"application/rss+xml": [{url: "https://nextui.org/feed.xml", title: "NextUI RSS Feed"}],
|
||||
},
|
||||
},
|
||||
viewport:
|
||||
"viewport-fit=cover, width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0",
|
||||
};
|
||||
|
||||
@@ -8,10 +8,20 @@ import NextLink from "next/link";
|
||||
import {AnimatePresence, motion} from "framer-motion";
|
||||
|
||||
import {useIsMounted} from "@/hooks/use-is-mounted";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const BlogPostCard = (post: BlogPost) => {
|
||||
const isMounted = useIsMounted();
|
||||
|
||||
const handlePress = () => {
|
||||
trackEvent("BlogPostCard - Selection", {
|
||||
name: post.title,
|
||||
action: "click",
|
||||
category: "blog",
|
||||
data: post.url ?? "",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isMounted && (
|
||||
@@ -27,6 +37,7 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
className="p-2 h-full border-transparent text-start bg-white/5 dark:bg-default-400/10 backdrop-blur-lg backdrop-saturate-[1.8]"
|
||||
href={post.url}
|
||||
isPressable={!!post.url}
|
||||
onPress={handlePress}
|
||||
>
|
||||
<CardHeader>
|
||||
<Link
|
||||
@@ -35,6 +46,7 @@ const BlogPostCard = (post: BlogPost) => {
|
||||
href={post.url}
|
||||
size="lg"
|
||||
underline="hover"
|
||||
onPress={handlePress}
|
||||
>
|
||||
<Balancer>{post.title}</Balancer>
|
||||
</Link>
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
|
||||
import searchData from "@/config/search-meta.json";
|
||||
import {useUpdateEffect} from "@/hooks/use-update-effect";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const hideOnPaths = ["examples"];
|
||||
|
||||
@@ -175,6 +176,13 @@ export const Cmdk: FC<{}> = () => {
|
||||
|
||||
const matches = intersectionBy(...matchesForEachWord, "objectID").slice(0, MAX_RESULTS);
|
||||
|
||||
trackEvent("Cmdk - Search", {
|
||||
name: "cmdk - search",
|
||||
action: "search",
|
||||
category: "cmdk",
|
||||
data: {query, words, matches: matches?.map((match) => match.url).join(", ")},
|
||||
});
|
||||
|
||||
return matches;
|
||||
},
|
||||
[query],
|
||||
@@ -190,10 +198,21 @@ export const Cmdk: FC<{}> = () => {
|
||||
if (e?.key?.toLowerCase() === "k" && e[hotkey]) {
|
||||
e.preventDefault();
|
||||
isOpen ? onClose() : onOpen();
|
||||
|
||||
trackEvent("Cmdk - Open/Close", {
|
||||
name: "cmdk - open/close",
|
||||
action: "keydown",
|
||||
category: "cmdk",
|
||||
data: isOpen ? "close" : "open",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
const onItemSelect = useCallback(
|
||||
@@ -201,6 +220,13 @@ export const Cmdk: FC<{}> = () => {
|
||||
onClose();
|
||||
router.push(item.url);
|
||||
addToRecentSearches(item);
|
||||
|
||||
trackEvent("Cmdk - ItemSelect", {
|
||||
name: item.content,
|
||||
action: "click",
|
||||
category: "cmdk",
|
||||
data: item.url,
|
||||
});
|
||||
},
|
||||
[router, recentSearches],
|
||||
);
|
||||
|
||||
@@ -108,9 +108,9 @@ function CodeTypewriter({value, className, css, ...props}: any) {
|
||||
return (
|
||||
<Pre className={className} css={css} {...props}>
|
||||
<code
|
||||
dangerouslySetInnerHTML={{__html: value}}
|
||||
ref={wrapperRef}
|
||||
className={className}
|
||||
dangerouslySetInnerHTML={{__html: value}}
|
||||
style={{opacity: 0}}
|
||||
/>
|
||||
</Pre>
|
||||
@@ -155,7 +155,7 @@ const CodeBlock = React.forwardRef<HTMLPreElement, CodeBlockProps>((_props, forw
|
||||
{...props}
|
||||
>
|
||||
{showWindowIcons && <WindowActions title={title} />}
|
||||
<code className={clsx(classes, codeClasses)} dangerouslySetInnerHTML={{__html: result}} />
|
||||
<code dangerouslySetInnerHTML={{__html: result}} className={clsx(classes, codeClasses)} />
|
||||
</Pre>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import {useRef} from "react";
|
||||
import {Button} from "@nextui-org/react";
|
||||
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export const CustomButton = () => {
|
||||
const buttonRef = useRef<HTMLButtonElement | null>(null);
|
||||
|
||||
@@ -26,6 +28,11 @@ export const CustomButton = () => {
|
||||
x: targetCenterX / clientWidth,
|
||||
},
|
||||
});
|
||||
|
||||
trackEvent("LandingPage - Confetti Button", {
|
||||
action: "press",
|
||||
category: "landing-page",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -9,6 +9,7 @@ import {useCodeDemo, UseCodeDemoProps} from "./use-code-demo";
|
||||
import WindowResizer, {WindowResizerProps} from "./window-resizer";
|
||||
|
||||
import {GradientBoxProps} from "@/components/gradient-box";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const DynamicReactLiveDemo = dynamic(
|
||||
() => import("./react-live-demo").then((m) => m.ReactLiveDemo),
|
||||
@@ -180,6 +181,14 @@ export const CodeDemo: React.FC<CodeDemoProps> = ({
|
||||
panel: "pt-0",
|
||||
}}
|
||||
variant="underlined"
|
||||
onSelectionChange={(tabKey) => {
|
||||
trackEvent("CodeDemo - Selection", {
|
||||
name: tabKey as string,
|
||||
action: "tabChange",
|
||||
category: "docs",
|
||||
data: tabKey ?? "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Tab key="preview" title="Preview">
|
||||
{previewContent}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React, {forwardRef} from "react";
|
||||
import React, {forwardRef, useEffect} from "react";
|
||||
import {clsx, getUniqueID} from "@nextui-org/shared-utils";
|
||||
import BaseHighlight, {Language, PrismTheme, defaultProps} from "prism-react-renderer";
|
||||
import {debounce} from "lodash";
|
||||
|
||||
import defaultTheme from "@/libs/prism-theme";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
interface CodeblockProps {
|
||||
language: Language;
|
||||
@@ -60,6 +62,45 @@ const Codeblock = forwardRef<HTMLPreElement, CodeblockProps>(
|
||||
const shouldHighlightLine = calculateLinesToHighlight(metastring);
|
||||
const isMultiLine = codeString.split("\n").length > 2;
|
||||
|
||||
const lastSelectionText = React.useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleSelectionChange = () => {
|
||||
if (!window.getSelection) return;
|
||||
|
||||
const el = window.getSelection()?.anchorNode?.parentNode;
|
||||
|
||||
if (!el) return;
|
||||
|
||||
const selectionText = window.getSelection()?.toString();
|
||||
|
||||
if (!selectionText) return;
|
||||
|
||||
if (
|
||||
!selectionText ||
|
||||
selectionText === lastSelectionText.current ||
|
||||
!codeString.includes(selectionText)
|
||||
)
|
||||
return;
|
||||
|
||||
lastSelectionText.current = selectionText;
|
||||
|
||||
trackEvent("Codeblock - Selection", {
|
||||
action: "selectText",
|
||||
category: "docs",
|
||||
data: selectionText,
|
||||
});
|
||||
};
|
||||
|
||||
const debouncedHandleSelectionChange = debounce(handleSelectionChange, 1000);
|
||||
|
||||
document.addEventListener("selectionchange", debouncedHandleSelectionChange);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("selectionchange", debouncedHandleSelectionChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<BaseHighlight
|
||||
{...defaultProps}
|
||||
|
||||
@@ -4,6 +4,7 @@ import Balancer from "react-wrap-balancer";
|
||||
|
||||
import {GithubIcon, NpmIcon, AdobeIcon, StorybookIcon, NextJsIcon} from "@/components/icons";
|
||||
import {COMPONENT_PATH, COMPONENT_THEME_PATH} from "@/libs/github/constants";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export interface ComponentLinksProps {
|
||||
component: string;
|
||||
@@ -23,6 +24,16 @@ const ButtonLink = ({
|
||||
href: string;
|
||||
tooltip?: string | ReactNode;
|
||||
}) => {
|
||||
const handlePress = () => {
|
||||
if (!href) return;
|
||||
|
||||
trackEvent("ComponentLinks - Click", {
|
||||
category: "docs",
|
||||
action: "click",
|
||||
data: href || "",
|
||||
});
|
||||
};
|
||||
|
||||
const button = (
|
||||
<Button
|
||||
isExternal
|
||||
@@ -31,6 +42,7 @@ const ButtonLink = ({
|
||||
href={href}
|
||||
size="sm"
|
||||
startContent={startContent}
|
||||
onPress={handlePress}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
@@ -81,7 +93,7 @@ export const ComponentLinks = ({
|
||||
)}
|
||||
{rscCompatible && (
|
||||
<ButtonLink
|
||||
href="https://nextjs.org/docs/getting-started/react-essentials#server-components"
|
||||
href="https://nextjs.org/docs/app/building-your-application/rendering/server-components"
|
||||
startContent={<NextJsIcon size={18} />}
|
||||
tooltip={
|
||||
<p>
|
||||
|
||||
@@ -2,6 +2,8 @@ import {Tabs, Tab, Snippet} from "@nextui-org/react";
|
||||
|
||||
import Codeblock from "./codeblock";
|
||||
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
type PackageManager = {
|
||||
key: string;
|
||||
name: string;
|
||||
@@ -32,6 +34,14 @@ export const ImportTabs = ({commands}: ImportTabsProps) => {
|
||||
tabList: "relative h-10",
|
||||
}}
|
||||
variant="underlined"
|
||||
onSelectionChange={(tabKey) => {
|
||||
trackEvent("ImportTabs - Selection", {
|
||||
name: tabKey as string,
|
||||
action: "tabChange",
|
||||
category: "docs",
|
||||
data: commands[tabKey] ?? "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{importTabs.map(({key, name}) => {
|
||||
if (!commands[key]) return null;
|
||||
@@ -47,6 +57,14 @@ export const ImportTabs = ({commands}: ImportTabsProps) => {
|
||||
pre: "font-light text-base",
|
||||
copyButton: "text-lg text-default-400",
|
||||
}}
|
||||
onCopy={() => {
|
||||
trackEvent("ImportTabs - Copy", {
|
||||
name,
|
||||
action: "copyInstallScript",
|
||||
category: "docs",
|
||||
data: commands[name] ?? "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Codeblock
|
||||
hideScrollBar
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Tabs, Tab, Snippet} from "@nextui-org/react";
|
||||
import Codeblock from "./codeblock";
|
||||
|
||||
import {YarnIcon, NpmSmallIcon, PnpmIcon} from "@/components/icons";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
type PackageManagerName = "npm" | "yarn" | "pnpm";
|
||||
|
||||
@@ -27,7 +28,7 @@ const packageManagers: PackageManager[] = [
|
||||
];
|
||||
|
||||
export interface PackageManagersProps {
|
||||
commands: Partial<Record<PackageManagerName, string>>;
|
||||
commands: Partial<Record<PackageManagerName, React.Key>>;
|
||||
}
|
||||
|
||||
export const PackageManagers = ({commands}: PackageManagersProps) => {
|
||||
@@ -39,6 +40,14 @@ export const PackageManagers = ({commands}: PackageManagersProps) => {
|
||||
tabList: "h-10",
|
||||
}}
|
||||
variant="underlined"
|
||||
onSelectionChange={(tabKey) => {
|
||||
trackEvent("PackageManagers - Selection", {
|
||||
name: tabKey as string,
|
||||
action: "tabChange",
|
||||
category: "docs",
|
||||
data: commands[tabKey as unknown as PackageManagerName] ?? "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
{packageManagers.map(({name, icon}) => {
|
||||
if (!commands[name]) return null;
|
||||
@@ -62,6 +71,14 @@ export const PackageManagers = ({commands}: PackageManagersProps) => {
|
||||
pre: "font-light text-base",
|
||||
copyButton: "text-lg text-zinc-500 mr-2",
|
||||
}}
|
||||
onCopy={() => {
|
||||
trackEvent("PackageManagers - Copy", {
|
||||
name,
|
||||
action: "copyScript",
|
||||
category: "docs",
|
||||
data: commands[name] ?? "",
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Codeblock removeIndent codeString={commands[name] as string} language="bash" />
|
||||
</Snippet>
|
||||
|
||||
@@ -1,31 +1,43 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import NextLink from "next/link";
|
||||
import {Link} from "@nextui-org/react";
|
||||
import {useRouter} from "next/navigation";
|
||||
import {ChevronIcon} from "@nextui-org/shared-icons";
|
||||
|
||||
import manifest from "@/config/routes.json";
|
||||
import {removeFromLast} from "@/utils";
|
||||
import {Route} from "@/libs/docs/page";
|
||||
import {useDocsRoute} from "@/hooks/use-docs-route";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export interface FooterNavProps {
|
||||
currentRoute?: Route;
|
||||
}
|
||||
|
||||
export const DocsPager: React.FC<FooterNavProps> = ({currentRoute}) => {
|
||||
const router = useRouter();
|
||||
|
||||
const {prevRoute, nextRoute} = useDocsRoute(manifest.routes, currentRoute);
|
||||
|
||||
const handlePress = (path: string) => {
|
||||
trackEvent("DocsPager - Click", {
|
||||
category: "docs",
|
||||
action: "click",
|
||||
data: path || "",
|
||||
});
|
||||
|
||||
router.push(removeFromLast(path || "", "."));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex w-full justify-between py-20">
|
||||
{prevRoute ? (
|
||||
<Link
|
||||
isBlock
|
||||
as={NextLink}
|
||||
className="flex gap-2"
|
||||
className="cursor-pointer flex gap-2"
|
||||
color="foreground"
|
||||
href={removeFromLast(prevRoute.path || "", ".")}
|
||||
onPress={() => handlePress(prevRoute.path || "")}
|
||||
>
|
||||
<ChevronIcon className="text-primary" height={20} width={20} />
|
||||
{prevRoute.title}
|
||||
@@ -36,10 +48,9 @@ export const DocsPager: React.FC<FooterNavProps> = ({currentRoute}) => {
|
||||
{nextRoute && (
|
||||
<Link
|
||||
isBlock
|
||||
as={NextLink}
|
||||
className="flex gap-1 items-center"
|
||||
className="cursor-pointer flex gap-1 items-center"
|
||||
color="foreground"
|
||||
href={removeFromLast(nextRoute.path || "", ".")}
|
||||
onPress={() => handlePress(nextRoute.path || "")}
|
||||
>
|
||||
{nextRoute.title}
|
||||
<ChevronIcon className="rotate-180 text-primary" height={20} width={20} />
|
||||
|
||||
@@ -26,6 +26,7 @@ import {getRoutePaths} from "./utils";
|
||||
import {Route} from "@/libs/docs/page";
|
||||
import {TreeKeyboardDelegate} from "@/utils/tree-keyboard-delegate";
|
||||
import {useScrollPosition} from "@/hooks/use-scroll-position";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export interface Props<T> extends Omit<ItemProps<T>, "title">, Route {
|
||||
slug?: string;
|
||||
@@ -88,6 +89,12 @@ function TreeItem<T>(props: TreeItemProps<T>) {
|
||||
state.toggleKey(item.key);
|
||||
} else {
|
||||
router.push(paths.pathname);
|
||||
|
||||
trackEvent("SidebarDocs", {
|
||||
category: "docs",
|
||||
action: "click",
|
||||
data: paths.pathname || "",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import {Button, Link} from "@nextui-org/react";
|
||||
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export const FigmaButton = () => (
|
||||
<Button
|
||||
isExternal
|
||||
showAnchorIcon
|
||||
as={Link}
|
||||
className="max-w-fit text-current"
|
||||
color="default"
|
||||
href="https://www.figma.com/community/file/1267584376234254760"
|
||||
variant="bordered"
|
||||
onPress={() => {
|
||||
trackEvent("FigmaPage - Open Figma Link", {
|
||||
action: "click",
|
||||
category: "figma",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Open in Figma
|
||||
</Button>
|
||||
);
|
||||
@@ -14,6 +14,7 @@ import {PaletteIcon, MagicIcon, GamingConsoleIcon, StarIcon} from "@/components/
|
||||
import {NextUILogo, CodeWindow} from "@/components";
|
||||
import landingContent from "@/content/landing";
|
||||
import {useIsMobile} from "@/hooks/use-media-query";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const themesTabs = (isMobile: boolean) => [
|
||||
{
|
||||
@@ -87,6 +88,12 @@ const CustomThemesExample = ({
|
||||
|
||||
const onSelectionChange = (value: React.Key) => {
|
||||
onChangeTheme(value as Theme);
|
||||
|
||||
trackEvent("CustomThemes - Selection", {
|
||||
action: "change_theme",
|
||||
category: "landing-page",
|
||||
data: value,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,6 +6,8 @@ import {Card, CardHeader, CardBody, LinkProps, SlotsToClasses} from "@nextui-org
|
||||
import {useRouter} from "next/navigation";
|
||||
import {LinkIcon} from "@nextui-org/shared-icons";
|
||||
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const styles = tv({
|
||||
slots: {
|
||||
base: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4",
|
||||
@@ -38,6 +40,13 @@ export const FeaturesGrid: React.FC<FeaturesGridProps> = ({features, classNames,
|
||||
const slots = styles();
|
||||
|
||||
const handleClick = (feat: Feature) => {
|
||||
trackEvent("FeaturesGrid - Click", {
|
||||
name: feat.title,
|
||||
action: "click",
|
||||
category: "docs",
|
||||
data: feat.href ?? "",
|
||||
});
|
||||
|
||||
if (!feat.href) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,6 @@ export const FloatingComponents: React.FC<{}> = () => {
|
||||
|
||||
{isMounted && (
|
||||
<Tooltip
|
||||
showArrow
|
||||
className="text-sm animate-[levitate_14s_ease_infinite]"
|
||||
color="secondary"
|
||||
content="Developers love Next.js"
|
||||
|
||||
@@ -9,6 +9,7 @@ import {FloatingComponents} from "./floating-components";
|
||||
|
||||
import {title, subtitle} from "@/components/primitives";
|
||||
import {GithubIcon} from "@/components/icons";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const BgLooper = dynamic(() => import("./bg-looper").then((mod) => mod.BgLooper), {
|
||||
ssr: false,
|
||||
@@ -42,6 +43,14 @@ export const Hero = () => {
|
||||
href="/docs/guide/introduction"
|
||||
radius="full"
|
||||
size="lg"
|
||||
onPress={() => {
|
||||
trackEvent("Hero - Get Started", {
|
||||
name: "Get Started",
|
||||
action: "click",
|
||||
category: "landing-page",
|
||||
data: "/docs/guide/introduction",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
@@ -56,6 +65,14 @@ export const Hero = () => {
|
||||
size="lg"
|
||||
startContent={<GithubIcon />}
|
||||
variant="bordered"
|
||||
onPress={() => {
|
||||
trackEvent("Hero - Github", {
|
||||
name: "Github",
|
||||
action: "click",
|
||||
category: "landing-page",
|
||||
data: "https://github.com/nextui-org/nextui",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Github
|
||||
</Button>
|
||||
|
||||
@@ -11,6 +11,7 @@ import {FeaturesGrid} from "./features-grid";
|
||||
import {sectionWrapper, subtitle, title} from "@/components/primitives";
|
||||
import {GithubIcon, NoteLinearIcon, NextJsIcon} from "@/components/icons";
|
||||
import {useIsMounted} from "@/hooks/use-is-mounted";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const bannerSuggestions = [
|
||||
{
|
||||
@@ -69,6 +70,13 @@ export const InstallBanner = () => {
|
||||
href="/docs/guide/installation"
|
||||
radius="full"
|
||||
size="md"
|
||||
onClick={() => {
|
||||
trackEvent("InstallBanner - Get Started", {
|
||||
action: "press",
|
||||
category: "landing-page",
|
||||
data: "/docs/guide/installation",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Get Started
|
||||
</Button>
|
||||
@@ -81,6 +89,13 @@ export const InstallBanner = () => {
|
||||
size="md"
|
||||
startContent={<GithubIcon />}
|
||||
variant="bordered"
|
||||
onClick={() => {
|
||||
trackEvent("InstallBanner - Github", {
|
||||
action: "press",
|
||||
category: "landing-page",
|
||||
data: "https://github.com/nextui-org/nextui",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Github
|
||||
</Button>
|
||||
|
||||
@@ -12,6 +12,7 @@ import {OpenCollectiveIcon, PatreonIcon, HeartBoldIcon, PlusLinearIcon} from "@/
|
||||
import {Sponsor, SPONSOR_TIERS, SPONSOR_COLORS, getTier} from "@/libs/docs/sponsors";
|
||||
import {SonarPulse} from "@/components/sonar-pulse";
|
||||
import {useIsMobile} from "@/hooks/use-media-query";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export interface SupportProps {
|
||||
sponsors: Sponsor[];
|
||||
@@ -100,6 +101,14 @@ export const Support: FC<SupportProps> = ({sponsors = []}) => {
|
||||
window.open(href, "_blank");
|
||||
};
|
||||
|
||||
const handleBecomeSponsor = () => {
|
||||
trackEvent("Support - Become a sponsor", {
|
||||
action: "click",
|
||||
category: "landing-page",
|
||||
});
|
||||
|
||||
handleExternalLinkClick(supportAccounts[0].href);
|
||||
};
|
||||
const renderSponsors = useMemo(() => {
|
||||
if (!sponsors.length) return null;
|
||||
|
||||
@@ -181,7 +190,7 @@ export const Support: FC<SupportProps> = ({sponsors = []}) => {
|
||||
aria-label="Become a sponsor"
|
||||
className="z-50 w-auto h-auto bg-gradient-to-b from-[#FF1CF7] to-[#7928CA]"
|
||||
radius="full"
|
||||
onPress={() => handleExternalLinkClick(supportAccounts[0].href)}
|
||||
onPress={handleBecomeSponsor}
|
||||
>
|
||||
<PlusLinearIcon
|
||||
className="flex items-center justify-center rounded-full text-white"
|
||||
|
||||
@@ -12,6 +12,7 @@ import * as DocsComponents from "@/components/docs/components";
|
||||
import * as BlogComponents from "@/components/blog/components";
|
||||
import {Codeblock} from "@/components/docs/components";
|
||||
import {VirtualAnchor, virtualAnchorEncode} from "@/components";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
const Table: React.FC<{children?: React.ReactNode}> = ({children}) => {
|
||||
return (
|
||||
@@ -144,6 +145,13 @@ const Code = ({
|
||||
copyButton: "text-lg text-zinc-500 mr-2",
|
||||
}}
|
||||
codeString={codeString}
|
||||
onCopy={() => {
|
||||
trackEvent("MDXComponents - Copy", {
|
||||
category: "docs",
|
||||
action: "copyCode",
|
||||
data: codeString,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Codeblock codeString={codeString} language={language} metastring={meta} />
|
||||
</Components.Snippet>
|
||||
@@ -153,8 +161,21 @@ const Code = ({
|
||||
const Link = ({href, children}: {href?: string; children?: React.ReactNode}) => {
|
||||
const isExternal = href?.startsWith("http");
|
||||
|
||||
const handlePress = () => {
|
||||
trackEvent("MDXComponents - Click", {
|
||||
category: "docs",
|
||||
action: "click",
|
||||
data: href || "",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Components.Link href={href} isExternal={isExternal} showAnchorIcon={isExternal}>
|
||||
<Components.Link
|
||||
href={href}
|
||||
isExternal={isExternal}
|
||||
showAnchorIcon={isExternal}
|
||||
onPress={handlePress}
|
||||
>
|
||||
{children}
|
||||
</Components.Link>
|
||||
);
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
import {useIsMounted} from "@/hooks/use-is-mounted";
|
||||
import {DocsSidebar} from "@/components/docs/sidebar";
|
||||
import {useCmdkStore} from "@/components/cmdk";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export interface NavbarProps {
|
||||
routes: Route[];
|
||||
@@ -74,8 +75,17 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
setCommandKey(isAppleDevice() ? "command" : "ctrl");
|
||||
}, []);
|
||||
|
||||
const handleOpenCmdk = () => {
|
||||
cmdkStore.onOpen();
|
||||
trackEvent("Navbar - Search", {
|
||||
name: "navbar - search",
|
||||
action: "press",
|
||||
category: "cmdk",
|
||||
});
|
||||
};
|
||||
|
||||
const {pressProps} = usePress({
|
||||
onPress: () => cmdkStore.onOpen(),
|
||||
onPress: handleOpenCmdk,
|
||||
});
|
||||
const {focusProps, isFocusVisible} = useFocusRing();
|
||||
|
||||
@@ -101,7 +111,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
strokeWidth={2}
|
||||
/>
|
||||
}
|
||||
onPress={() => cmdkStore.onOpen()}
|
||||
onPress={handleOpenCmdk}
|
||||
>
|
||||
Quick Search...
|
||||
</Button>
|
||||
@@ -121,6 +131,15 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
}
|
||||
};
|
||||
|
||||
const handlePressNavbarItem = (name: string, url: string) => {
|
||||
trackEvent("NavbarItem", {
|
||||
name,
|
||||
action: "press",
|
||||
category: "navbar",
|
||||
data: url,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<NextUINavbar
|
||||
ref={ref}
|
||||
@@ -138,6 +157,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
aria-label="Home"
|
||||
className="flex justify-start items-center gap-2 tap-highlight-transparent transition-opacity active:opacity-50"
|
||||
href="/"
|
||||
onClick={() => handlePressNavbarItem("Home", "/")}
|
||||
>
|
||||
<SmallLogo className="w-6 h-6 md:hidden" />
|
||||
<LargeLogo className="h-5 md:h-6" />
|
||||
@@ -184,6 +204,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
color="foreground"
|
||||
data-active={includes(docsPaths, pathname)}
|
||||
href="/docs/guide/introduction"
|
||||
onClick={() => handlePressNavbarItem("Docs", "/docs/guide/introduction")}
|
||||
>
|
||||
Docs
|
||||
</NextLink>
|
||||
@@ -194,6 +215,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "components")}
|
||||
href="/docs/components/avatar"
|
||||
onClick={() => handlePressNavbarItem("Components", "/docs/components/avatar")}
|
||||
>
|
||||
Components
|
||||
</NextLink>
|
||||
@@ -204,6 +226,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "blog")}
|
||||
href="/blog"
|
||||
onClick={() => handlePressNavbarItem("Blog", "/blog")}
|
||||
>
|
||||
Blog
|
||||
</NextLink>
|
||||
@@ -214,6 +237,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
color="foreground"
|
||||
data-active={includes(pathname, "figma")}
|
||||
href="/figma"
|
||||
onClick={() => handlePressNavbarItem("Figma", "/figma")}
|
||||
>
|
||||
Figma
|
||||
</NextLink>
|
||||
@@ -225,6 +249,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
color="secondary"
|
||||
href="/blog/v2.1.0"
|
||||
variant="dot"
|
||||
onClick={() => handlePressNavbarItem("New components v2.1.0", "/blog/v2.1.0")}
|
||||
>
|
||||
New components v2.1.0
|
||||
<span aria-label="party emoji" role="img">
|
||||
@@ -242,6 +267,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
aria-label="Github"
|
||||
className="p-1"
|
||||
href="https://github.com/nextui-org/nextui"
|
||||
onClick={() => handlePressNavbarItem("Github", "https://github.com/nextui-org/nextui")}
|
||||
>
|
||||
<GithubIcon className="text-default-600 dark:text-default-500" />
|
||||
</Link>
|
||||
@@ -273,13 +299,31 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
|
||||
<NavbarContent className="hidden sm:flex basis-1/5 sm:basis-full" justify="end">
|
||||
<NavbarItem className="hidden sm:flex">
|
||||
<Link isExternal aria-label="Twitter" className="p-1" href={siteConfig.links.twitter}>
|
||||
<Link
|
||||
isExternal
|
||||
aria-label="Twitter"
|
||||
className="p-1"
|
||||
href={siteConfig.links.twitter}
|
||||
onPress={() => handlePressNavbarItem("Twitter", siteConfig.links.twitter)}
|
||||
>
|
||||
<TwitterIcon className="text-default-600 dark:text-default-500" />
|
||||
</Link>
|
||||
<Link isExternal aria-label="Discord" className="p-1" href={siteConfig.links.discord}>
|
||||
<Link
|
||||
isExternal
|
||||
aria-label="Discord"
|
||||
className="p-1"
|
||||
href={siteConfig.links.discord}
|
||||
onPress={() => handlePressNavbarItem("Discord", siteConfig.links.discord)}
|
||||
>
|
||||
<DiscordIcon className="text-default-600 dark:text-default-500" />
|
||||
</Link>
|
||||
<Link isExternal aria-label="Github" className="p-1" href={siteConfig.links.github}>
|
||||
<Link
|
||||
isExternal
|
||||
aria-label="Github"
|
||||
className="p-1"
|
||||
href={siteConfig.links.github}
|
||||
onPress={() => handlePressNavbarItem("Github", siteConfig.links.github)}
|
||||
>
|
||||
<GithubIcon className="text-default-600 dark:text-default-500" />
|
||||
</Link>
|
||||
<ThemeSwitch />
|
||||
@@ -295,6 +339,7 @@ export const Navbar: FC<NavbarProps> = ({children, routes, mobileRoutes = [], sl
|
||||
<HeartFilledIcon className="text-danger group-data-[hover=true]:animate-heartbeat" />
|
||||
}
|
||||
variant="flat"
|
||||
onPress={() => handlePressNavbarItem("Sponsor", siteConfig.links.sponsor)}
|
||||
>
|
||||
Sponsor
|
||||
</Button>
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
import React from "react";
|
||||
import {usePathname} from "next/navigation";
|
||||
import {Tooltip, Link, Button} from "@nextui-org/react";
|
||||
import {Tooltip, Button} from "@nextui-org/react";
|
||||
import {capitalize, last} from "lodash";
|
||||
|
||||
import {BugIcon} from "@/components/icons";
|
||||
import {ISSUE_REPORT_URL} from "@/libs/github/constants";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export const BugReportButton = () => {
|
||||
const pathname = usePathname();
|
||||
|
||||
const componentTitle = capitalize(last(pathname?.split("/")));
|
||||
|
||||
const handlePress = () => {
|
||||
trackEvent("BugReportButton - Sandpack", {
|
||||
name: "sandpack - bug report",
|
||||
action: "press",
|
||||
category: "docs",
|
||||
data: `${ISSUE_REPORT_URL}${componentTitle}`,
|
||||
});
|
||||
|
||||
window.open(`${ISSUE_REPORT_URL}${componentTitle}`, "_blank");
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
className="text-xs px-2"
|
||||
@@ -19,15 +31,7 @@ export const BugReportButton = () => {
|
||||
placement="top"
|
||||
radius="md"
|
||||
>
|
||||
<Button
|
||||
isExternal
|
||||
isIconOnly
|
||||
as={Link}
|
||||
href={`${ISSUE_REPORT_URL}${componentTitle}`}
|
||||
size="sm"
|
||||
title="Report a bug"
|
||||
variant="light"
|
||||
>
|
||||
<Button isIconOnly size="sm" title="Report a bug" variant="light" onPress={handlePress}>
|
||||
<BugIcon className="text-white dark:text-zinc-500" height={16} width={16} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import React from "react";
|
||||
import {UnstyledOpenInCodeSandboxButton} from "@codesandbox/sandpack-react";
|
||||
import {Tooltip, Button} from "@nextui-org/react";
|
||||
import {useSandpack} from "@codesandbox/sandpack-react";
|
||||
|
||||
import {CodeSandboxIcon} from "@/components/icons";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export const CodeSandboxButton = () => {
|
||||
const {sandpack} = useSandpack();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
className="text-xs px-2"
|
||||
@@ -13,7 +17,20 @@ export const CodeSandboxButton = () => {
|
||||
placement="top"
|
||||
radius="md"
|
||||
>
|
||||
<Button isIconOnly as="span" size="sm" title="Open in CodeSandbox" variant="light">
|
||||
<Button
|
||||
isIconOnly
|
||||
as="span"
|
||||
size="sm"
|
||||
title="Open in CodeSandbox"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
trackEvent("CodeSandboxButton - Sandpack", {
|
||||
action: "press",
|
||||
category: "docs",
|
||||
data: sandpack.files[sandpack.activeFile],
|
||||
});
|
||||
}}
|
||||
>
|
||||
<UnstyledOpenInCodeSandboxButton
|
||||
style={{
|
||||
width: "100%",
|
||||
|
||||
@@ -3,6 +3,7 @@ import {useSandpack} from "@codesandbox/sandpack-react";
|
||||
import {Tooltip, Button} from "@nextui-org/react";
|
||||
import {useClipboard} from "@nextui-org/use-clipboard";
|
||||
|
||||
import {trackEvent} from "@/utils/va";
|
||||
import {CopyLinearIcon} from "@/components/icons";
|
||||
|
||||
export const CopyButton = () => {
|
||||
@@ -14,6 +15,13 @@ export const CopyButton = () => {
|
||||
const code = sandpack.files[sandpack.activeFile].code;
|
||||
|
||||
copy(code);
|
||||
|
||||
trackEvent("CopyButton - Sandpack", {
|
||||
name: "sandpack - copy code",
|
||||
action: "press",
|
||||
category: "docs",
|
||||
data: sandpack.activeFile,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,6 +3,7 @@ import {Tabs, Tab} from "@nextui-org/react";
|
||||
import {SandpackPredefinedTemplate} from "@codesandbox/sandpack-react";
|
||||
|
||||
import {TypescriptIcon, JavascriptIcon} from "@/components/icons";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
interface Props {
|
||||
template: SandpackPredefinedTemplate;
|
||||
@@ -20,6 +21,12 @@ export const LanguageSelector: React.FC<LanguageSelectorProps> = ({template, onC
|
||||
setSelectedTemplate(newTemplate);
|
||||
|
||||
setTimeout(() => {
|
||||
trackEvent("LanguageSelector - Selection", {
|
||||
name: "template",
|
||||
action: "tabChange",
|
||||
category: "docs",
|
||||
data: newTemplate ?? "",
|
||||
});
|
||||
onChange?.(newTemplate);
|
||||
}, 250);
|
||||
}, [template, onChange]);
|
||||
|
||||
@@ -59,7 +59,10 @@ export const useSandpack = ({
|
||||
if (key.includes("App") && !key.includes(mimeType)) {
|
||||
return acc;
|
||||
}
|
||||
if (typescriptStrict && key.includes("js")) {
|
||||
if (typescriptStrict && currentTemplate === "vite-react-ts" && key.includes(".js")) {
|
||||
return acc;
|
||||
}
|
||||
if (currentTemplate === "vite-react" && key.includes(".ts")) {
|
||||
return acc;
|
||||
}
|
||||
// @ts-ignore
|
||||
@@ -100,7 +103,7 @@ export const useSandpack = ({
|
||||
|
||||
// Check if the file content includes 'React' import statements, if not, add it
|
||||
if (!fileContent.includes(importReact) && !fileContent.includes(importAllReact)) {
|
||||
fileContent = `${importReact}\n${fileContent}\n`;
|
||||
fileContent = `${importReact}\n\n${fileContent}\n`;
|
||||
}
|
||||
|
||||
// Check if file content includes any other dependencies, if yes, add it to dependencies
|
||||
|
||||
@@ -8,6 +8,7 @@ import {clsx} from "@nextui-org/shared-utils";
|
||||
import {useIsSSR} from "@react-aria/ssr";
|
||||
|
||||
import {SunFilledIcon, MoonFilledIcon} from "@/components/icons";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export interface ThemeSwitchProps {
|
||||
className?: string;
|
||||
@@ -20,6 +21,12 @@ export const ThemeSwitch: FC<ThemeSwitchProps> = ({className, classNames}) => {
|
||||
|
||||
const onChange = () => {
|
||||
theme === "light" ? setTheme("dark") : setTheme("light");
|
||||
|
||||
trackEvent("ThemeChange", {
|
||||
action: "click",
|
||||
category: "theme",
|
||||
data: theme === "light" ? "dark" : "light",
|
||||
});
|
||||
};
|
||||
|
||||
const {Component, slots, isSelected, getBaseProps, getInputProps, getWrapperProps} = useSwitch({
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import {Link} from "@nextui-org/react";
|
||||
|
||||
import {VercelIcon} from "@/components/icons";
|
||||
import {trackEvent} from "@/utils/va";
|
||||
|
||||
export const VercelCallout: React.FC<unknown> = () => {
|
||||
return (
|
||||
@@ -9,6 +12,13 @@ export const VercelCallout: React.FC<unknown> = () => {
|
||||
isExternal
|
||||
className="flex justify-end items-center gap-2 text-foreground"
|
||||
href="https://www.vercel.com?utm_source=nextui&utm_marketing=oss"
|
||||
onClick={() => {
|
||||
trackEvent("VercelCallout", {
|
||||
name: "vercel callout",
|
||||
action: "click",
|
||||
category: "footer",
|
||||
});
|
||||
}}
|
||||
>
|
||||
<p className="font-normal">Deployed on</p>
|
||||
<VercelIcon className="text-black dark:text-white" height={18} />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {DM_Sans} from "next/font/google";
|
||||
import {Inter} from "next/font/google";
|
||||
|
||||
export const fontSans = DM_Sans({
|
||||
export const fontSans = Inter({
|
||||
variable: "--font-sans",
|
||||
adjustFontFallback: true,
|
||||
display: "optional",
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
const App = `import {forwardRef} from "react";
|
||||
import {useButton, Ripple, Spinner} from "@nextui-org/react";
|
||||
|
||||
import {useButton, Drip, Spinner} from "@nextui-org/react";
|
||||
|
||||
const MyButton = forwardRef((props, ref) => {
|
||||
const {
|
||||
domRef,
|
||||
children,
|
||||
classNames,
|
||||
drips,
|
||||
spinnerSize,
|
||||
spinner = <Spinner color="current" size={spinnerSize} />,
|
||||
spinnerPlacement,
|
||||
@@ -16,19 +14,22 @@ const MyButton = forwardRef((props, ref) => {
|
||||
isLoading,
|
||||
disableRipple,
|
||||
getButtonProps,
|
||||
getRippleProps,
|
||||
} = useButton({
|
||||
ref,
|
||||
...props,
|
||||
});
|
||||
|
||||
const {ripples} = getRippleProps();
|
||||
|
||||
return (
|
||||
<button ref={domRef} className={classNames} {...getButtonProps()}>
|
||||
<button ref={domRef} {...getButtonProps()}>
|
||||
{startContent}
|
||||
{isLoading && spinnerPlacement === "start" && spinner}
|
||||
{children}
|
||||
{isLoading && spinnerPlacement === "end" && spinner}
|
||||
{endContent}
|
||||
{!disableRipple && <Drip drips={drips} />}
|
||||
{!disableRipple && <Ripple ripples={ripples} />}
|
||||
</button>
|
||||
);
|
||||
});
|
||||
@@ -38,8 +39,7 @@ MyButton.displayName = "MyButton";
|
||||
export default MyButton;`;
|
||||
|
||||
const AppTs = `import {forwardRef} from "react";
|
||||
|
||||
import {useButton, Drip, Spinner, ButtonProps as BaseButtonProps} from "@nextui-org/react";
|
||||
import {useButton, Ripple, Spinner, ButtonProps as BaseButtonProps} from "@nextui-org/react";
|
||||
|
||||
export interface ButtonProps extends BaseButtonProps {}
|
||||
|
||||
@@ -47,8 +47,6 @@ const MyButton = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||
const {
|
||||
domRef,
|
||||
children,
|
||||
classNames,
|
||||
drips,
|
||||
spinnerSize,
|
||||
spinner = <Spinner color="current" size={spinnerSize} />,
|
||||
spinnerPlacement,
|
||||
@@ -57,19 +55,22 @@ const MyButton = forwardRef<HTMLButtonElement, ButtonProps>((props, ref) => {
|
||||
isLoading,
|
||||
disableRipple,
|
||||
getButtonProps,
|
||||
getRippleProps,
|
||||
} = useButton({
|
||||
ref,
|
||||
...props,
|
||||
});
|
||||
|
||||
const {ripples} = getRippleProps();
|
||||
|
||||
return (
|
||||
<button ref={domRef} className={classNames} {...getButtonProps()}>
|
||||
<button ref={domRef} {...getButtonProps()}>
|
||||
{startContent}
|
||||
{isLoading && spinnerPlacement === "start" && spinner}
|
||||
{children}
|
||||
{isLoading && spinnerPlacement === "end" && spinner}
|
||||
{endContent}
|
||||
{!disableRipple && <Drip drips={drips} />}
|
||||
{!disableRipple && <Ripple ripples={ripples} />}
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function App() {
|
||||
/>
|
||||
<CardFooter className="absolute bg-black/40 bottom-0 z-10 border-t-1 border-default-600 dark:border-default-100">
|
||||
<div className="flex flex-grow gap-2 items-center">
|
||||
<img
|
||||
<Image
|
||||
alt="Breathing app icon"
|
||||
className="rounded-full w-10 h-11 bg-black"
|
||||
src="/images/breathing-app-icon.jpeg"
|
||||
|
||||
@@ -4,6 +4,7 @@ import horizontal from "./horizontal";
|
||||
import controlled from "./controlled";
|
||||
import customStyles from "./custom-styles";
|
||||
import customImplementation from "./custom-implementation";
|
||||
import invalid from "./invalid";
|
||||
|
||||
export const checkboxGroupContent = {
|
||||
usage,
|
||||
@@ -11,5 +12,6 @@ export const checkboxGroupContent = {
|
||||
horizontal,
|
||||
controlled,
|
||||
customStyles,
|
||||
invalid,
|
||||
customImplementation,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
const App = `import {CheckboxGroup, Checkbox} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
const [isInvalid, setIsInvalid] = React.useState(true);
|
||||
|
||||
return (
|
||||
<CheckboxGroup
|
||||
isRequired
|
||||
description="Select the cities you want to visit"
|
||||
isInvalid={isInvalid}
|
||||
label="Select cities"
|
||||
onValueChange={(value) => {
|
||||
setIsInvalid(value.length < 1);
|
||||
}}
|
||||
>
|
||||
<Checkbox value="buenos-aires">Buenos Aires</Checkbox>
|
||||
<Checkbox value="sydney">Sydney</Checkbox>
|
||||
<Checkbox value="san-francisco">San Francisco</Checkbox>
|
||||
<Checkbox value="london">London</Checkbox>
|
||||
<Checkbox value="tokyo">Tokyo</Checkbox>
|
||||
</CheckboxGroup>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
const App = `import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button, Avatar, User} from "@nextui-org/react";
|
||||
const App = `import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Avatar, User} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
|
||||
@@ -100,7 +100,7 @@ const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const App = `import {Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, Button, cn} from "@nextui-org/react";
|
||||
const App = `import {Dropdown, DropdownTrigger, DropdownMenu, DropdownSection, DropdownItem, Button, cn} from "@nextui-org/react";
|
||||
import {AddNoteIcon} from "./AddNoteIcon.jsx";
|
||||
import {CopyDocumentIcon} from "./CopyDocumentIcon.jsx";
|
||||
import {EditDocumentIcon} from "./EditDocumentIcon.jsx";
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function App() {
|
||||
label="Email"
|
||||
variant="bordered"
|
||||
defaultValue="junior2nextui.org"
|
||||
validationState="invalid"
|
||||
isInvalid={true}
|
||||
errorMessage="Please enter a valid email"
|
||||
className="max-w-xs"
|
||||
/>
|
||||
|
||||
@@ -5,10 +5,10 @@ export default function App() {
|
||||
|
||||
const validateEmail = (value) => value.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$/i);
|
||||
|
||||
const validationState = React.useMemo(() => {
|
||||
if (value === "") return undefined;
|
||||
const isInvalid = React.useMemo(() => {
|
||||
if (value === "") return false;
|
||||
|
||||
return validateEmail(value) ? "valid" : "invalid";
|
||||
return validateEmail(value) ? false : true;
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
@@ -17,9 +17,9 @@ export default function App() {
|
||||
type="email"
|
||||
label="Email"
|
||||
variant="bordered"
|
||||
color={validationState === "invalid" ? "danger" : "success"}
|
||||
errorMessage={validationState === "invalid" && "Please enter a valid email"}
|
||||
validationState={validationState}
|
||||
isInvalid={isInvalid}
|
||||
color={isInvalid ? "danger" : "success"}
|
||||
errorMessage={isInvalid && "Please enter a valid email"}
|
||||
onValueChange={setValue}
|
||||
className="max-w-xs"
|
||||
/>
|
||||
|
||||
@@ -100,7 +100,7 @@ const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -100,7 +100,7 @@ const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -100,7 +100,7 @@ const DeleteDocumentIcon = `export const DeleteDocumentIcon = (props) => (
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const ListboxWrapper = `const ListboxWrapper = ({children}) => (
|
||||
const ListboxWrapper = `export const ListboxWrapper = ({children}) => (
|
||||
<div className="w-full max-w-[260px] border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -119,10 +119,136 @@ export default function App() {
|
||||
);
|
||||
}`;
|
||||
|
||||
const AppTs = `import {Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, ModalProps, Button, useDisclosure, RadioGroup, Radio} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
const {isOpen, onOpen, onOpenChange} = useDisclosure();
|
||||
const [scrollBehavior, setScrollBehavior] = React.useState<ModalProps["scrollBehavior"]>("inside");
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button onPress={onOpen}>Open Modal</Button>
|
||||
<RadioGroup
|
||||
label="Select scroll behavior"
|
||||
orientation="horizontal"
|
||||
value={scrollBehavior}
|
||||
onValueChange={setScrollBehavior}
|
||||
>
|
||||
<Radio value="inside">inside</Radio>
|
||||
<Radio value="outside">outside</Radio>
|
||||
</RadioGroup>
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onOpenChange={onOpenChange}
|
||||
scrollBehavior={scrollBehavior}
|
||||
>
|
||||
<ModalContent>
|
||||
{(onClose) => (
|
||||
<>
|
||||
<ModalHeader className="flex flex-col gap-1">
|
||||
Modal Title
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Nullam pulvinar risus non risus hendrerit venenatis.
|
||||
Pellentesque sit amet hendrerit risus, sed porttitor quam.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Nullam pulvinar risus non risus hendrerit venenatis.
|
||||
Pellentesque sit amet hendrerit risus, sed porttitor quam.
|
||||
</p>
|
||||
<p>
|
||||
Magna exercitation reprehenderit magna aute tempor cupidatat
|
||||
consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
|
||||
incididunt cillum quis. Velit duis sit officia eiusmod Lorem
|
||||
aliqua enim laboris do dolor eiusmod. Et mollit incididunt
|
||||
nisi consectetur esse laborum eiusmod pariatur proident Lorem
|
||||
eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Nullam pulvinar risus non risus hendrerit venenatis.
|
||||
Pellentesque sit amet hendrerit risus, sed porttitor quam.
|
||||
Magna exercitation reprehenderit magna aute tempor cupidatat
|
||||
consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
|
||||
incididunt cillum quis. Velit duis sit officia eiusmod Lorem
|
||||
aliqua enim laboris do dolor eiusmod. Et mollit incididunt
|
||||
nisi consectetur esse laborum eiusmod pariatur proident Lorem
|
||||
eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit
|
||||
duis sit officia eiusmod Lorem aliqua enim laboris do dolor
|
||||
eiusmod. Et mollit incididunt nisi consectetur esse laborum
|
||||
eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt
|
||||
nostrud ad veniam. Lorem ipsum dolor sit amet, consectetur
|
||||
adipiscing elit. Nullam pulvinar risus non risus hendrerit
|
||||
venenatis. Pellentesque sit amet hendrerit risus, sed
|
||||
porttitor quam. Magna exercitation reprehenderit magna aute
|
||||
tempor cupidatat consequat elit dolor adipisicing. Mollit
|
||||
dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit
|
||||
officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et
|
||||
mollit incididunt nisi consectetur esse laborum eiusmod
|
||||
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad
|
||||
veniam.
|
||||
</p>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Nullam pulvinar risus non risus hendrerit venenatis.
|
||||
Pellentesque sit amet hendrerit risus, sed porttitor quam.
|
||||
</p>
|
||||
<p>
|
||||
Magna exercitation reprehenderit magna aute tempor cupidatat
|
||||
consequat elit dolor adipisicing. Mollit dolor eiusmod sunt ex
|
||||
incididunt cillum quis. Velit duis sit officia eiusmod Lorem
|
||||
aliqua enim laboris do dolor eiusmod. Et mollit incididunt
|
||||
nisi consectetur esse laborum eiusmod pariatur proident Lorem
|
||||
eiusmod et. Culpa deserunt nostrud ad veniam.
|
||||
</p>
|
||||
<p>
|
||||
Mollit dolor eiusmod sunt ex incididunt cillum quis. Velit
|
||||
duis sit officia eiusmod Lorem aliqua enim laboris do dolor
|
||||
eiusmod. Et mollit incididunt nisi consectetur esse laborum
|
||||
eiusmod pariatur proident Lorem eiusmod et. Culpa deserunt
|
||||
nostrud ad veniam. Lorem ipsum dolor sit amet, consectetur
|
||||
adipiscing elit. Nullam pulvinar risus non risus hendrerit
|
||||
venenatis. Pellentesque sit amet hendrerit risus, sed
|
||||
porttitor quam. Magna exercitation reprehenderit magna aute
|
||||
tempor cupidatat consequat elit dolor adipisicing. Mollit
|
||||
dolor eiusmod sunt ex incididunt cillum quis. Velit duis sit
|
||||
officia eiusmod Lorem aliqua enim laboris do dolor eiusmod. Et
|
||||
mollit incididunt nisi consectetur esse laborum eiusmod
|
||||
pariatur proident Lorem eiusmod et. Culpa deserunt nostrud ad
|
||||
veniam.
|
||||
</p>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button color="danger" variant="light" onPress={onClose}>
|
||||
Close
|
||||
</Button>
|
||||
<Button color="primary" onPress={onClose}>
|
||||
Action
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</>
|
||||
)}
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
};
|
||||
|
||||
const reactTs = {
|
||||
"/App.tsx": AppTs,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
...reactTs,
|
||||
};
|
||||
|
||||
@@ -6,12 +6,14 @@ import defaultValue from "./default-value";
|
||||
import withDescription from "./with-description";
|
||||
import customStyles from "./custom-styles";
|
||||
import customImpl from "./custom-impl";
|
||||
import invalid from "./invalid";
|
||||
|
||||
export const radioGroupContent = {
|
||||
usage,
|
||||
disabled,
|
||||
horizontal,
|
||||
controlled,
|
||||
invalid,
|
||||
defaultValue,
|
||||
withDescription,
|
||||
customStyles,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
const App = `import {RadioGroup, Radio} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
const [selected, setSelected] = React.useState("london");
|
||||
|
||||
const validOptions = ["buenos-aires", "san-francisco", "tokyo"];
|
||||
|
||||
const isInvalid = !validOptions.includes(selected);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-3">
|
||||
<RadioGroup
|
||||
label="Select your favorite city"
|
||||
value={selected}
|
||||
isInvalid={isInvalid}
|
||||
onValueChange={setSelected}
|
||||
>
|
||||
<Radio value="buenos-aires">Buenos Aires</Radio>
|
||||
<Radio value="sydney">Sydney</Radio>
|
||||
<Radio value="san-francisco">San Francisco</Radio>
|
||||
<Radio value="london">London</Radio>
|
||||
<Radio value="tokyo">Tokyo</Radio>
|
||||
</RadioGroup>
|
||||
<p className="text-default-500 text-small">Selected: {selected}</p>
|
||||
</div>
|
||||
);
|
||||
}`;
|
||||
|
||||
const react = {
|
||||
"/App.jsx": App,
|
||||
};
|
||||
|
||||
export default {
|
||||
...react,
|
||||
};
|
||||
@@ -137,7 +137,7 @@ const usePokemonList = `export function usePokemonList({fetchDelay = 0} = {}) {
|
||||
};`;
|
||||
|
||||
const App = `import {Select, SelectItem} from "@nextui-org/react";
|
||||
import {useInfiniteScroll} from "@nextui-org/use-infinity-scroll";
|
||||
import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
|
||||
import {usePokemonList} from "./usePokemonList";
|
||||
|
||||
export default function App() {
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function App() {
|
||||
placeholder="Select an animal"
|
||||
description="The second most popular pet in the world"
|
||||
errorMessage={isValid || !touched ? "" : "You must select a cat"}
|
||||
validationState={isValid || !touched ? "valid" : "invalid"}
|
||||
isInvalid={isValid || !touched ? false : true}
|
||||
selectedKeys={value}
|
||||
className="max-w-xs"
|
||||
onSelectionChange={setValue}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const App = `import {Card, Skeleton} from "@nextui-org/react";
|
||||
const App = `import {Skeleton} from "@nextui-org/react";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
|
||||
@@ -1,50 +1,22 @@
|
||||
const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Pagination, Spinner, getKeyValue} from "@nextui-org/react";
|
||||
import {useAsyncList} from "@react-stately/data";
|
||||
import useSWR from "swr";
|
||||
|
||||
const fetcher = (...args) => fetch(...args).then((res) => res.json());
|
||||
|
||||
export default function App() {
|
||||
const [page, setPage] = React.useState(1);
|
||||
const [total, setTotal] = React.useState(0);
|
||||
const [isLoading, setIsLoading] = React.useState(true);
|
||||
|
||||
const {data, isLoading} = useSWR(\`https://swapi.py4e.com/api/people?page=\$\{page\}\`, fetcher, {
|
||||
keepPreviousData: true,
|
||||
});
|
||||
|
||||
const rowsPerPage = 10;
|
||||
|
||||
let list = useAsyncList({
|
||||
async load({signal, cursor}) {
|
||||
// If no cursor is available, then we're loading the first page.
|
||||
// Otherwise, the cursor is the next URL to load, as returned from the previous page.
|
||||
const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
|
||||
let json = await res.json();
|
||||
const pages = useMemo(() => {
|
||||
return data?.count ? Math.ceil(data.count / rowsPerPage) : 0;
|
||||
}, [data?.count, rowsPerPage]);
|
||||
|
||||
setTotal(json.count);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
return {
|
||||
items: json.results,
|
||||
cursor: json.next,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const pages = Math.ceil(total / rowsPerPage);
|
||||
|
||||
const items = React.useMemo(() => {
|
||||
const start = (page - 1) * rowsPerPage;
|
||||
const end = start + rowsPerPage;
|
||||
|
||||
return list.items.slice(start, end);
|
||||
}, [page, list.items?.length]);
|
||||
|
||||
const onPaginationChange = React.useCallback(
|
||||
(page) => {
|
||||
setIsLoading(true);
|
||||
if (page >= list.items.length / rowsPerPage) {
|
||||
list.loadMore();
|
||||
}
|
||||
setPage(page);
|
||||
},
|
||||
[list.items.length],
|
||||
);
|
||||
const loadingState = isLoading || data?.results.length === 0 ? "loading" : "idle";
|
||||
|
||||
return (
|
||||
<Table
|
||||
@@ -59,14 +31,12 @@ export default function App() {
|
||||
color="primary"
|
||||
page={page}
|
||||
total={pages}
|
||||
onChange={onPaginationChange}
|
||||
onChange={(page) => setPage(page)}
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
classNames={{
|
||||
table: "min-h-[400px]",
|
||||
}}
|
||||
{...args}
|
||||
>
|
||||
<TableHeader>
|
||||
<TableColumn key="name">Name</TableColumn>
|
||||
@@ -75,12 +45,12 @@ export default function App() {
|
||||
<TableColumn key="birth_year">Birth year</TableColumn>
|
||||
</TableHeader>
|
||||
<TableBody
|
||||
isLoading={isLoading && !items.length}
|
||||
items={items}
|
||||
items={data?.results ?? []}
|
||||
loadingContent={<Spinner />}
|
||||
loadingState={loadingState}
|
||||
>
|
||||
{(item) => (
|
||||
<TableRow key={item.name}>
|
||||
<TableRow key={item?.name}>
|
||||
{(columnKey) => <TableCell>{getKeyValue(item, columnKey)}</TableCell>}
|
||||
</TableRow>
|
||||
)}
|
||||
|
||||
@@ -220,6 +220,234 @@ const users = [
|
||||
|
||||
export {columns, users, statusOptions};`;
|
||||
|
||||
const dataTs = `const columns = [
|
||||
{name: "ID", uid: "id", sortable: true},
|
||||
{name: "NAME", uid: "name", sortable: true},
|
||||
{name: "AGE", uid: "age", sortable: true},
|
||||
{name: "ROLE", uid: "role", sortable: true},
|
||||
{name: "TEAM", uid: "team"},
|
||||
{name: "EMAIL", uid: "email"},
|
||||
{name: "STATUS", uid: "status", sortable: true},
|
||||
{name: "ACTIONS", uid: "actions"},
|
||||
];
|
||||
|
||||
const statusOptions = [
|
||||
{name: "Active", uid: "active"},
|
||||
{name: "Paused", uid: "paused"},
|
||||
{name: "Vacation", uid: "vacation"},
|
||||
];
|
||||
|
||||
const users = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Tony Reichert",
|
||||
role: "CEO",
|
||||
team: "Management",
|
||||
status: "active",
|
||||
age: "29",
|
||||
avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
|
||||
email: "tony.reichert@example.com",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Zoey Lang",
|
||||
role: "Tech Lead",
|
||||
team: "Development",
|
||||
status: "paused",
|
||||
age: "25",
|
||||
avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
|
||||
email: "zoey.lang@example.com",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Jane Fisher",
|
||||
role: "Sr. Dev",
|
||||
team: "Development",
|
||||
status: "active",
|
||||
age: "22",
|
||||
avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
|
||||
email: "jane.fisher@example.com",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "William Howard",
|
||||
role: "C.M.",
|
||||
team: "Marketing",
|
||||
status: "vacation",
|
||||
age: "28",
|
||||
avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
|
||||
email: "william.howard@example.com",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Kristen Copper",
|
||||
role: "S. Manager",
|
||||
team: "Sales",
|
||||
status: "active",
|
||||
age: "24",
|
||||
avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
|
||||
email: "kristen.cooper@example.com",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Brian Kim",
|
||||
role: "P. Manager",
|
||||
team: "Management",
|
||||
age: "29",
|
||||
avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
|
||||
email: "brian.kim@example.com",
|
||||
status: "Active",
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Michael Hunt",
|
||||
role: "Designer",
|
||||
team: "Design",
|
||||
status: "paused",
|
||||
age: "27",
|
||||
avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
|
||||
email: "michael.hunt@example.com",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: "Samantha Brooks",
|
||||
role: "HR Manager",
|
||||
team: "HR",
|
||||
status: "active",
|
||||
age: "31",
|
||||
avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
|
||||
email: "samantha.brooks@example.com",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: "Frank Harrison",
|
||||
role: "F. Manager",
|
||||
team: "Finance",
|
||||
status: "vacation",
|
||||
age: "33",
|
||||
avatar: "https://i.pravatar.cc/150?img=4",
|
||||
email: "frank.harrison@example.com",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
name: "Emma Adams",
|
||||
role: "Ops Manager",
|
||||
team: "Operations",
|
||||
status: "active",
|
||||
age: "35",
|
||||
avatar: "https://i.pravatar.cc/150?img=5",
|
||||
email: "emma.adams@example.com",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: "Brandon Stevens",
|
||||
role: "Jr. Dev",
|
||||
team: "Development",
|
||||
status: "active",
|
||||
age: "22",
|
||||
avatar: "https://i.pravatar.cc/150?img=8",
|
||||
email: "brandon.stevens@example.com",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
name: "Megan Richards",
|
||||
role: "P. Manager",
|
||||
team: "Product",
|
||||
status: "paused",
|
||||
age: "28",
|
||||
avatar: "https://i.pravatar.cc/150?img=10",
|
||||
email: "megan.richards@example.com",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
name: "Oliver Scott",
|
||||
role: "S. Manager",
|
||||
team: "Security",
|
||||
status: "active",
|
||||
age: "37",
|
||||
avatar: "https://i.pravatar.cc/150?img=12",
|
||||
email: "oliver.scott@example.com",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
name: "Grace Allen",
|
||||
role: "M. Specialist",
|
||||
team: "Marketing",
|
||||
status: "active",
|
||||
age: "30",
|
||||
avatar: "https://i.pravatar.cc/150?img=16",
|
||||
email: "grace.allen@example.com",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
name: "Noah Carter",
|
||||
role: "IT Specialist",
|
||||
team: "I. Technology",
|
||||
status: "paused",
|
||||
age: "31",
|
||||
avatar: "https://i.pravatar.cc/150?img=15",
|
||||
email: "noah.carter@example.com",
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
name: "Ava Perez",
|
||||
role: "Manager",
|
||||
team: "Sales",
|
||||
status: "active",
|
||||
age: "29",
|
||||
avatar: "https://i.pravatar.cc/150?img=20",
|
||||
email: "ava.perez@example.com",
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
name: "Liam Johnson",
|
||||
role: "Data Analyst",
|
||||
team: "Analysis",
|
||||
status: "active",
|
||||
age: "28",
|
||||
avatar: "https://i.pravatar.cc/150?img=33",
|
||||
email: "liam.johnson@example.com",
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
name: "Sophia Taylor",
|
||||
role: "QA Analyst",
|
||||
team: "Testing",
|
||||
status: "active",
|
||||
age: "27",
|
||||
avatar: "https://i.pravatar.cc/150?img=29",
|
||||
email: "sophia.taylor@example.com",
|
||||
},
|
||||
{
|
||||
id: 19,
|
||||
name: "Lucas Harris",
|
||||
role: "Administrator",
|
||||
team: "Information Technology",
|
||||
status: "paused",
|
||||
age: "32",
|
||||
avatar: "https://i.pravatar.cc/150?img=50",
|
||||
email: "lucas.harris@example.com",
|
||||
},
|
||||
{
|
||||
id: 20,
|
||||
name: "Mia Robinson",
|
||||
role: "Coordinator",
|
||||
team: "Operations",
|
||||
status: "active",
|
||||
age: "26",
|
||||
avatar: "https://i.pravatar.cc/150?img=45",
|
||||
email: "mia.robinson@example.com",
|
||||
},
|
||||
];
|
||||
|
||||
export {columns, users, statusOptions};`;
|
||||
|
||||
const types = `import {SVGProps} from "react";
|
||||
|
||||
export type IconSvgProps = SVGProps<SVGSVGElement> & {
|
||||
size?: number;
|
||||
};`;
|
||||
|
||||
const utils = `export function capitalize(str) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}`;
|
||||
@@ -316,6 +544,110 @@ const ChevronDownIcon = `export const ChevronDownIcon = ({strokeWidth = 1.5, ...
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const utilsTs = `export function capitalize(str: string) {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||
}`;
|
||||
|
||||
const PlusIconTs = `import {IconSvgProps} from "./types";
|
||||
|
||||
export const PlusIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={1.5}
|
||||
>
|
||||
<path d="M6 12h12" />
|
||||
<path d="M12 18V6" />
|
||||
</g>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const VerticalDotsIconTs = `import {IconSvgProps} from "./types";
|
||||
|
||||
export const VerticalDotsIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height={size || height}
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width={size || width}
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M12 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 12c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const SearchIconTs = `import {IconSvgProps} from "./types";
|
||||
|
||||
export const SearchIcon = (props: IconSvgProps) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M11.5 21C16.7467 21 21 16.7467 21 11.5C21 6.25329 16.7467 2 11.5 2C6.25329 2 2 6.25329 2 11.5C2 16.7467 6.25329 21 11.5 21Z"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
<path
|
||||
d="M22 22L20 20"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const ChevronDownIconTs = `import {IconSvgProps} from "./types";
|
||||
|
||||
export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}: IconSvgProps) => (
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="none"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
role="presentation"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
{...otherProps}
|
||||
>
|
||||
<path
|
||||
d="m19.92 8.95-6.52 6.52c-.77.77-2.03.77-2.8 0L4.08 8.95"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeMiterlimit={10}
|
||||
strokeWidth={strokeWidth}
|
||||
/>
|
||||
</svg>
|
||||
);`;
|
||||
|
||||
const App = `import {
|
||||
Table,
|
||||
TableHeader,
|
||||
@@ -479,7 +811,7 @@ export default function App() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onClear = useCallback(()=>{
|
||||
const onClear = React.useCallback(()=>{
|
||||
setFilterValue("")
|
||||
setPage(1)
|
||||
},[])
|
||||
@@ -687,7 +1019,7 @@ export default function App() {
|
||||
direction: "ascending",
|
||||
});
|
||||
|
||||
const [page, setPage] = useState(1);
|
||||
const [page, setPage] = React.useState(1);
|
||||
|
||||
const hasSearchFilter = Boolean(filterValue);
|
||||
|
||||
@@ -734,7 +1066,7 @@ export default function App() {
|
||||
}, [sortDescriptor, items]);
|
||||
|
||||
const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
|
||||
const cellValue = user[columnKey];
|
||||
const cellValue = user[columnKey as keyof User];
|
||||
|
||||
switch (columnKey) {
|
||||
case "name":
|
||||
@@ -808,7 +1140,7 @@ export default function App() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onClear = useCallback(()=>{
|
||||
const onClear = React.useCallback(()=>{
|
||||
setFilterValue("")
|
||||
setPage(1)
|
||||
},[])
|
||||
@@ -973,13 +1305,20 @@ const react = {
|
||||
"/data.js": data,
|
||||
"/utils.js": utils,
|
||||
"/PlusIcon.jsx": PlusIcon,
|
||||
"/VerticalDotsIcon.jsx": VerticalDotsIcon,
|
||||
"/SearchIcon.jsx": SearchIcon,
|
||||
"/ChevronDownIcon.jsx": ChevronDownIcon,
|
||||
"/VerticalDotsIcon.jsx": VerticalDotsIcon,
|
||||
};
|
||||
|
||||
const reactTs = {
|
||||
"/App.tsx": AppTs,
|
||||
"/types.ts": types,
|
||||
"/data.ts": dataTs,
|
||||
"/utils.ts": utilsTs,
|
||||
"/PlusIcon.tsx": PlusIconTs,
|
||||
"/VerticalDotsIcon.tsx": VerticalDotsIconTs,
|
||||
"/SearchIcon.tsx": SearchIconTs,
|
||||
"/ChevronDownIcon.tsx": ChevronDownIconTs,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -3,12 +3,12 @@ const App = `import {Textarea} from "@nextui-org/react";
|
||||
export default function App() {
|
||||
return (
|
||||
<Textarea
|
||||
isInvalid={true}
|
||||
variant="bordered"
|
||||
label="Description"
|
||||
labelPlacement="outside"
|
||||
placeholder="Enter your description"
|
||||
defaultValue="NextUI is a React UI library with..."
|
||||
validationState="invalid"
|
||||
errorMessage="The description should be at least 255 characters long."
|
||||
className="max-w-xs"
|
||||
/>
|
||||
|
||||
@@ -194,7 +194,7 @@ Here's an example of how to customize the accordion styles:
|
||||
| fullWidth | `boolean` | Whether the accordion should take up the full width of its parent container. | `true` |
|
||||
| motionProps | `MotionProps` | The motion properties of the Accordion. | |
|
||||
| disabledKeys | `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | |
|
||||
| itemClasses | [Classnames](#accordiom-item-classnames) | The accordion items classNames. | |
|
||||
| itemClasses | [Classnames](#accordion-item-classnames) | The accordion items classNames. | |
|
||||
| selectedKeys | `all` \| `React.Key[]` | The currently selected keys in the collection (controlled). | |
|
||||
| defaultSelectedKeys | `all` \| `React.Key[]` | The initial selected keys in the collection (uncontrolled). | |
|
||||
| disabledKeys | `React.Key[]` | The currently disabled keys in the collection (controlled). | |
|
||||
@@ -221,7 +221,7 @@ Here's an example of how to customize the accordion styles:
|
||||
| hideIndicator | `boolean` | Whether the AccordionItem indicator is hidden. | `false` |
|
||||
| disableAnimation | `boolean` | Whether the AccordionItem animation is disabled. | `false` |
|
||||
| disableIndicatorAnimation | `boolean` | Whether the AccordionItem indicator animation is disabled. | `false` |
|
||||
| classNames | [Classnames](#accordiom-item-classnames) | Allows to set custom class names for the accordion item slots. | - |
|
||||
| classNames | [Classnames](#accordion-item-classnames) | Allows to set custom class names for the accordion item slots. | - |
|
||||
|
||||
### Accordion Item Events
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ A CheckboxGroup allows users to select one or more items from a list of choices.
|
||||
|
||||
---
|
||||
|
||||
<CarbonAd/>
|
||||
<CarbonAd />
|
||||
|
||||
## Import
|
||||
|
||||
@@ -47,6 +47,10 @@ You can use the `value` and `onValueChange` properties to control the checkbox i
|
||||
|
||||
<CodeDemo title="Controlled" files={checkboxGroupContent.controlled} />
|
||||
|
||||
### Invalid
|
||||
|
||||
<CodeDemo title="Invalid" files={checkboxGroupContent.invalid} />
|
||||
|
||||
## Slots
|
||||
|
||||
- **base**: Checkbox group root wrapper, it wraps the label and the wrapper.
|
||||
@@ -57,7 +61,6 @@ You can use the `value` and `onValueChange` properties to control the checkbox i
|
||||
|
||||
### Custom Styles
|
||||
|
||||
|
||||
You can customize the `CheckboxGroup` component by passing custom Tailwind CSS classes to the component slots.
|
||||
|
||||
<CodeDemo title="Custom Styles" files={checkboxGroupContent.customStyles} />
|
||||
@@ -76,25 +79,26 @@ In case you need to customize the checkbox even further, you can use the `useChe
|
||||
|
||||
### Checkbox Group Props
|
||||
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------- | ---------- |
|
||||
| children | `ReactNode[]` \| `ReactNode[]` | The checkboxes items. | - |
|
||||
| orientation | `vertical` \| `horizontal` | The axis the checkbox group items should align with. | `vertical` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the checkboxes. | `primary` |
|
||||
| size | `xs` \| `sm` \| `md` \| `lg` \| `xl` | The size of the checkboxes. | `md` |
|
||||
| radius | `none` \| `base` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `full` | The radius of the checkboxes. | `md` |
|
||||
| name | `string` | The name of the CheckboxGroup, used when submitting an HTML form. | - |
|
||||
| value | `string[]` | The current selected values. (controlled). | - |
|
||||
| lineThrough | `boolean` | Whether the checkboxes label should be crossed out. | `false` |
|
||||
| defaultValue | `string[]` | The default selected values. (uncontrolled). | - |
|
||||
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. | `false` |
|
||||
| description | `ReactNode` | The checkbox group description. | - |
|
||||
| errorMessage | `ReactNode` | The checkbox group error message. | - |
|
||||
| isDisabled | `boolean` | Whether the checkbox group is disabled. | `false` |
|
||||
| isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - |
|
||||
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
|
||||
| classNames | `Record<"base"| "wrapper"| "label", string>` | Allows to set custom class names for the checkbox group slots. | - |
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ---------- |
|
||||
| children | `ReactNode[]` \| `ReactNode[]` | The checkboxes items. | - |
|
||||
| orientation | `vertical` \| `horizontal` | The axis the checkbox group items should align with. | `vertical` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the checkboxes. | `primary` |
|
||||
| size | `xs` \| `sm` \| `md` \| `lg` \| `xl` | The size of the checkboxes. | `md` |
|
||||
| radius | `none` \| `base` \| `xs` \| `sm` \| `md` \| `lg` \| `xl` \| `full` | The radius of the checkboxes. | `md` |
|
||||
| name | `string` | The name of the CheckboxGroup, used when submitting an HTML form. | - |
|
||||
| value | `string[]` | The current selected values. (controlled). | - |
|
||||
| lineThrough | `boolean` | Whether the checkboxes label should be crossed out. | `false` |
|
||||
| defaultValue | `string[]` | The default selected values. (uncontrolled). | - |
|
||||
| isInvalid | `boolean` | Whether the checkbox group is invalid. | `false` |
|
||||
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
|
||||
| description | `ReactNode` | The checkbox group description. | - |
|
||||
| errorMessage | `ReactNode` | The checkbox group error message. | - |
|
||||
| isDisabled | `boolean` | Whether the checkbox group is disabled. | `false` |
|
||||
| isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - |
|
||||
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
|
||||
| classNames | `Record<"base"| "wrapper"| "label", string>` | Allows to set custom class names for the checkbox group slots. | - |
|
||||
|
||||
### Checkbox Group Events
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Checkboxes allow users to select multiple items from a list of individual items,
|
||||
|
||||
---
|
||||
|
||||
<CarbonAd/>
|
||||
<CarbonAd />
|
||||
|
||||
## Import
|
||||
|
||||
@@ -134,19 +134,20 @@ In case you need to customize the checkbox even further, you can use the `useChe
|
||||
| ---------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------- |
|
||||
| children | `ReactNode` | The label of the checkbox. | - |
|
||||
| icon | [CheckboxIconProps](#checkbox-icon-props) | The icon to be displayed when the checkbox is checked. | - |
|
||||
| value | `string` | The value of the input element, used when submitting an HTML form. | |
|
||||
| name | `string` | The name of the input element, used when submitting an HTML form. | |
|
||||
| value | `string` | The value of the checkbox element, used when submitting an HTML form. | |
|
||||
| name | `string` | The name of the checkbox element, used when submitting an HTML form. | |
|
||||
| size | `sm` \| `md` \| `lg` | The size of the checkbox. | `md` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the checkbox. | `primary` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the checkbox. | - |
|
||||
| lineThrough | `boolean` | Whether the label should be crossed out. | `false` |
|
||||
| isSelected | `boolean` | Whether the element should be selected (controlled). | |
|
||||
| defaultSelected | `boolean` | Whether the element should be selected (uncontrolled). | |
|
||||
| validationState | `valid` \| `invalid` | Whether the input should display its "valid" or "invalid" visual styling. | - |
|
||||
| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | |
|
||||
| isRequired | `boolean` | Whether user checkbox is required on the checkbox before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the checkbox can be selected but not changed by the user. | |
|
||||
| isDisabled | `boolean` | Whether the checkbox is disabled. | `false` |
|
||||
| isIndeterminate | `boolean` | Indeterminism is presentational only. The indeterminate visual representation remains regardless of user interaction. | |
|
||||
| isInvalid | `boolean` | Whether the checkbox is invalid. | `false` |
|
||||
| validationState | `valid` \| `invalid` | Whether the checkbox should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
|
||||
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
|
||||
| classNames | `Record<"base"| "wrapper"| "icon"| "label", string>` | Allows to set custom class names for the checkbox slots. | - |
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ It is possible to add icons to the dropdown items using the `startContent` / `en
|
||||
|
||||
<CodeDemo title="With Icons" highlightedLines="23,30,37,47" files={dropdownContent.icons} />
|
||||
|
||||
> **Note**: Note: If you use `currentColor` as the icon color, the icon will have the same color as the item text.
|
||||
> **Note**: If you use `currentColor` as the icon color, the icon will have the same color as the item text.
|
||||
|
||||
### With Description
|
||||
|
||||
@@ -156,7 +156,7 @@ Dropdown has 2 components with slots the `DropdownItem` and `DropdownSection` co
|
||||
- **wrapper**: The `title` and `description` wrapper.
|
||||
- **title**: The title of the dropdown item.
|
||||
- **description**: The description of the dropdown item.
|
||||
- **shortcut**: The shorcut slot.
|
||||
- **shortcut**: The shortcut slot.
|
||||
- **selectedIcon**: The selected icon slot. This is only visible when the item is selected.
|
||||
|
||||
### DropdownSection
|
||||
|
||||
@@ -13,7 +13,7 @@ Input is a component that allows users to enter text. It can be used to get user
|
||||
|
||||
---
|
||||
|
||||
<CarbonAd/>
|
||||
<CarbonAd />
|
||||
|
||||
## Import
|
||||
|
||||
@@ -180,30 +180,31 @@ In case you need to customize the input even further, you can use the `useInput`
|
||||
|
||||
### Input Props
|
||||
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | --------- |
|
||||
| children | `ReactNode` | The content of the input. | - |
|
||||
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the input. | `flat` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the input. | `default` |
|
||||
| size | `sm` \| `md` \| `lg` | The size of the input. | `md` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the input. | - |
|
||||
| label | `ReactNode` | The content to display as the label. | - |
|
||||
| value | `string` | The current value of the input (controlled). | - |
|
||||
| defaultValue | `string` | The default value of the input (uncontrolled). | - |
|
||||
| placeholder | `string` | The placeholder of the input. | - |
|
||||
| description | `ReactNode` | A description for the input. Provides a hint such as specific requirements for what to choose. | - |
|
||||
| errorMessage | `ReactNode` | An error message for the input. | - |
|
||||
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
|
||||
| fullWidth | `boolean` | Whether the input should take up the width of its parent. | `true` |
|
||||
| validationState | `valid` \| `invalid` | Whether the input should display its "valid" or "invalid" visual styling. | - |
|
||||
| isClearable | `boolean` | Whether the input should have a clear button. | `false` |
|
||||
| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | |
|
||||
| isDisabled | `boolean` | Whether the input is disabled. | `false` |
|
||||
| startContent | `ReactNode` | Element to be rendered in the left side of the input. | - |
|
||||
| endContent | `ReactNode` | Element to be rendered in the right side of the input. | - |
|
||||
| disableAnimation | `boolean` | Whether the input should be animated. | `false` |
|
||||
| classNames | `Record<"base"| "label"| "inputWrapper"| "innerWrapper"| "mainWrapper" | "input" | "clearButton" | "helperWrapper" | "description" | "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------- |
|
||||
| children | `ReactNode` | The content of the input. | - |
|
||||
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the input. | `flat` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the input. | `default` |
|
||||
| size | `sm` \| `md` \| `lg` | The size of the input. | `md` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the input. | - |
|
||||
| label | `ReactNode` | The content to display as the label. | - |
|
||||
| value | `string` | The current value of the input (controlled). | - |
|
||||
| defaultValue | `string` | The default value of the input (uncontrolled). | - |
|
||||
| placeholder | `string` | The placeholder of the input. | - |
|
||||
| description | `ReactNode` | A description for the input. Provides a hint such as specific requirements for what to choose. | - |
|
||||
| errorMessage | `ReactNode` | An error message for the input. | - |
|
||||
| startContent | `ReactNode` | Element to be rendered in the left side of the input. | - |
|
||||
| endContent | `ReactNode` | Element to be rendered in the right side of the input. | - |
|
||||
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
|
||||
| fullWidth | `boolean` | Whether the input should take up the width of its parent. | `true` |
|
||||
| isClearable | `boolean` | Whether the input should have a clear button. | `false` |
|
||||
| isRequired | `boolean` | Whether user input is required on the input before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the input can be selected but not changed by the user. | |
|
||||
| isDisabled | `boolean` | Whether the input is disabled. | `false` |
|
||||
| isInvalid | `boolean` | Whether the input is invalid. | `false` |
|
||||
| validationState | `valid` \| `invalid` | Whether the input should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
|
||||
| disableAnimation | `boolean` | Whether the input should be animated. | `false` |
|
||||
| classNames | `Record<"base"| "label"| "inputWrapper"| "innerWrapper"| "mainWrapper" | "input" | "clearButton" | "helperWrapper" | "description" | "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
|
||||
|
||||
### Input Events
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ It is possible to add icons to the listbox items using the `startContent` / `end
|
||||
|
||||
<CodeDemo title="With Icons" highlightedLines="23,30,38" files={listboxContent.icons} />
|
||||
|
||||
> **Note**: Note: If you use `currentColor` as the icon color, the icon will have the same color as the item text.
|
||||
> **Note**: If you use `currentColor` as the icon color, the icon will have the same color as the item text.
|
||||
|
||||
### With Description
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ NextUI exports 3 pagination-related components:
|
||||
### Colors
|
||||
|
||||
<CodeDemo title="Radius" files={paginationContent.colors} />
|
||||
{/*
|
||||
|
||||
### Variants
|
||||
|
||||
You can use the `variant` property to change the pagination items style.
|
||||
@@ -129,7 +129,7 @@ You can customize the `Pagination` component by passing custom Tailwind CSS clas
|
||||
In case you need to customize the pagination even further, you can use the `usePagination` hook to create
|
||||
your own implementation.
|
||||
|
||||
<CodeDemo title="Custom Implementation" files={paginationContent.customImpl} /> */}
|
||||
<CodeDemo title="Custom Implementation" files={paginationContent.customImpl} />
|
||||
|
||||
<Spacer y={4} />
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Radio Group allow users to select a single option from a list of mutually exclus
|
||||
|
||||
---
|
||||
|
||||
<CarbonAd/>
|
||||
<CarbonAd />
|
||||
|
||||
## Import
|
||||
|
||||
@@ -53,6 +53,10 @@ You can use the `value` and `onValueChange` properties to control the radio inpu
|
||||
> **Note**: NextUI `Radio` also supports native events like `onChange`, useful for form libraries
|
||||
> such as [Formik](https://formik.org/) and [React Hook Form](https://react-hook-form.com/).
|
||||
|
||||
### Invalid
|
||||
|
||||
<CodeDemo title="Invalid" files={radioGroupContent.invalid} />
|
||||
|
||||
## Slots
|
||||
|
||||
- RadioGroup Slots
|
||||
@@ -140,12 +144,13 @@ In case you need to customize the radio group even further, you can use the `use
|
||||
| name | `string` | The name of the RadioGroup, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#name_and_radio_buttons). | - |
|
||||
| value | `string[]` | The current selected value. (controlled). | - |
|
||||
| defaultValue | `string[]` | The default selected value. (uncontrolled). | - |
|
||||
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. | `false` |
|
||||
| description | `ReactNode` | Radio group description . | - |
|
||||
| errorMessage | `ReactNode` | Radio group error message. | - |
|
||||
| isDisabled | `boolean` | Whether the radio group is disabled. | `false` |
|
||||
| isRequired | `boolean` | Whether user checkboxes are required on the input before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the checkboxes can be selected but not changed by the user. | - |
|
||||
| isInvalid | `boolean` | Whether the radio group is invalid. | `false` |
|
||||
| validationState | `valid` \| `invalid` | Whether the inputs should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | `false` |
|
||||
| disableAnimation | `boolean` | Whether the animation should be disabled. | `false` |
|
||||
| classNames | `Record<"base"| "wrapper"| "label", string>` | Allows to set custom class names for the radio group slots. | - |
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ the select.
|
||||
|
||||
<CodeDemo title="Start Content" highlightedLines="9" files={selectContent.startContent} />
|
||||
|
||||
### Item Start Content
|
||||
### Item Start & End Content
|
||||
|
||||
Since the `Select` component uses the [Listbox](/docs/components/listbox) component under the hood, you can
|
||||
use the `startContent` and `endContent` properties of the `SelectItem` component to add content to the start
|
||||
@@ -101,7 +101,7 @@ and end of the select item.
|
||||
|
||||
### Custom Selector Icon
|
||||
|
||||
By default the select uses a `crevron-down` icon as the selector icon which rotates when the select is open. You can
|
||||
By default the select uses a `chevron-down` icon as the selector icon which rotates when the select is open. You can
|
||||
customize this icon by passing a custom one to the `selectorIcon` property.
|
||||
|
||||
<CodeDemo title="Custom Selector Icon" files={selectContent.customSelectorIcon} />
|
||||
@@ -174,22 +174,22 @@ You can customize the sections style by using the `classNames` property of the `
|
||||
|
||||
<CodeDemo title="Custom Sections Style" files={selectContent.customSectionsStyle} />
|
||||
|
||||
### Asyncronous Loading
|
||||
### Asynchronous Loading
|
||||
|
||||
Select supports asyncronous loading, in the example below we are using a custom hook to fetch the [Pokemon API](https://pokeapi.co/api/v2/pokemon) data in combination with the `useInfinityScroll` hook to load more data when the user reaches the end of the list.
|
||||
Select supports asynchronous loading, in the example below we are using a custom hook to fetch the [Pokemon API](https://pokeapi.co/api/v2/pokemon) data in combination with the `useInfiniteScroll` hook to load more data when the user reaches the end of the list.
|
||||
|
||||
The `isLoading` prop is used to show a loading indicator intead of the selector icon when the data is being fetched.
|
||||
The `isLoading` prop is used to show a loading indicator instead of the selector icon when the data is being fetched.
|
||||
|
||||
<PackageManagers
|
||||
commands={{
|
||||
npm: "npm install @nextui-org/use-infinity-scroll",
|
||||
yarn: "yarn add @nextui-org/use-infinity-scroll",
|
||||
pnpm: "pnpm add @nextui-org/use-infinity-scroll",
|
||||
npm: "npm install @nextui-org/use-infinite-scroll",
|
||||
yarn: "yarn add @nextui-org/use-infinite-scroll",
|
||||
pnpm: "pnpm add @nextui-org/use-infinite-scroll",
|
||||
}}
|
||||
/>
|
||||
|
||||
```jsx
|
||||
import {useInfinityScroll} from "@nextui-org/use-infinity-scroll";
|
||||
import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
|
||||
```
|
||||
|
||||
<Spacer y={2} />
|
||||
@@ -197,7 +197,7 @@ import {useInfinityScroll} from "@nextui-org/use-infinity-scroll";
|
||||
<CodeDemo
|
||||
asIframe
|
||||
typescriptStrict={true}
|
||||
title="Asyncronous Loading"
|
||||
title="Asynchronous Loading"
|
||||
hideWindowActions={true}
|
||||
resizeEnabled={false}
|
||||
displayMode="always"
|
||||
@@ -230,7 +230,7 @@ Using `onChange`:
|
||||
files={selectContent.multipleControlledOnChange}
|
||||
/>
|
||||
|
||||
### Mutliple With Chips
|
||||
### Multiple With Chips
|
||||
|
||||
You can render any component as the select value by using the `renderValue` property. In this example we are
|
||||
using the [Chip](/docs/components/chip) component to render the selected items.
|
||||
@@ -254,6 +254,7 @@ the popover and listbox components.
|
||||
|
||||
- **base**: The main wrapper of the select. This wraps the rest of the slots.
|
||||
- **label**: The label of the select.
|
||||
- **mainWrapper**: Wraps the `helperWrapper` and the `trigger` slots.
|
||||
- **trigger**: The trigger of the select. This wraps the label the inner wrapper and the selector icon.
|
||||
- **innerWrapper**: The wrapper of the select content. This wraps the start/end content and the select value.
|
||||
- **selectorIcon**: The selector icon of the select. This is the icon that rotates when the select is open (`data-open`).
|
||||
@@ -332,44 +333,45 @@ the popover and listbox components.
|
||||
|
||||
### Select Props
|
||||
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------ |
|
||||
| children\* | `ReactNode[]` | The children to render. Usually a list of `SelectItem` and `SelectSection` elements. | - |
|
||||
| items | [`Iterable<T>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) | Item objects in the select. (dynamic) | - |
|
||||
| selectionMode | `single` \| `multiple` | The type of selection that is allowed in the collection. | - |
|
||||
| selectedKeys | `all` \| `React.Key[]` | The currently selected keys in the collection (controlled). | - |
|
||||
| disabledKeys | `all` \| `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | - |
|
||||
| defaultSelectedKeys | `all` \| `React.Key[]` | The initial selected keys in the collection (uncontrolled). | - |
|
||||
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the select. | `flat` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the select. | `default` |
|
||||
| size | `sm` \| `md` \| `lg` | The size of the select. | `md` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the select. | - |
|
||||
| placeholder | `string` | The placeholder of the select. | `Select an option` |
|
||||
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
|
||||
| validationState | `valid` \| `invalid` | Whether the select should display its "valid" or "invalid" visual styling. | - |
|
||||
| label | `ReactNode` | The content to display as the label. | - |
|
||||
| description | `ReactNode` | A description for the select. Provides a hint such as specific requirements for what to choose. | - |
|
||||
| errorMessage | `ReactNode` | An error message for the select. | - |
|
||||
| startContent | `ReactNode` | Element to be rendered in the left side of the select. | - |
|
||||
| endContent | `ReactNode` | Element to be rendered in the right side of the select. | - |
|
||||
| selectorIcon | `ReactNode` | Element to be rendered as the selector icon. | - |
|
||||
| scrollRef | `React.RefObject<HTMLElement>` | A ref to the scrollable element. | - |
|
||||
| spinnerRef | `React.RefObject<HTMLElement>` | A ref to the spinner element. | - |
|
||||
| fullWidth | `boolean` | Whether the select should take up the width of its parent. | `true` |
|
||||
| isOpen | `boolean` | Whether the select is open by default (controlled). | - |
|
||||
| defaultOpen | `boolean` | Whether the select is open by default (uncontrolled). | - |
|
||||
| isRequired | `boolean` | Whether user select is required on the select before form submission. | `false` |
|
||||
| isDisabled | `boolean` | Whether the select is disabled. | `false` |
|
||||
| isMultiline | `boolean` | Whether the select should allow multiple lines of text. | `false` |
|
||||
| showScrollIndicators | `boolean` | Whether the select should show scroll indicators when the listbox is scrollable. | `true` |
|
||||
| autoFocus | `boolean` | Whether the select should be focused on the first mount. | `false` |
|
||||
| disallowEmptySelection | `boolean` | Whether the collection allows empty selection. | `false` |
|
||||
| disableAnimation | `boolean` | Whether the select should be animated. | `true` |
|
||||
| disableSelectionIconRotation | `boolean` | Whether the select should disable the rotation of the selector icon. | `false` |
|
||||
| popoverProps | [PopoverProps](/docs/components/popover#api) | Props to be passed to the popover component. | - |
|
||||
| listboxProps | [ListboxProps](/docs/components/listbox#api) | Props to be passed to the listbox component. | - |
|
||||
| scrollShadowProps | [ScrollShadowProps](/docs/components/scroll-shadow#api) | Props to be passed to the scroll shadow component. | - |
|
||||
| classNames | `Record<"base"| "label"| "trigger"| "innerWrapper"| "selectorIcon" | "value" | "listboxWrapper"| "listbox" | "popover" | "helperWrapper" | "description" | "errorMessage", string>` | Allows to set custom class names for the dropdown item slots. | - |
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------ |
|
||||
| children\* | `ReactNode[]` | The children to render. Usually a list of `SelectItem` and `SelectSection` elements. | - |
|
||||
| items | [`Iterable<T>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) | Item objects in the select. (dynamic) | - |
|
||||
| selectionMode | `single` \| `multiple` | The type of selection that is allowed in the collection. | - |
|
||||
| selectedKeys | `all` \| `React.Key[]` | The currently selected keys in the collection (controlled). | - |
|
||||
| disabledKeys | `all` \| `React.Key[]` | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | - |
|
||||
| defaultSelectedKeys | `all` \| `React.Key[]` | The initial selected keys in the collection (uncontrolled). | - |
|
||||
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the select. | `flat` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the select. | `default` |
|
||||
| size | `sm` \| `md` \| `lg` | The size of the select. | `md` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the select. | - |
|
||||
| placeholder | `string` | The placeholder of the select. | `Select an option` |
|
||||
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
|
||||
| label | `ReactNode` | The content to display as the label. | - |
|
||||
| description | `ReactNode` | A description for the select. Provides a hint such as specific requirements for what to choose. | - |
|
||||
| errorMessage | `ReactNode` | An error message for the select. | - |
|
||||
| startContent | `ReactNode` | Element to be rendered in the left side of the select. | - |
|
||||
| endContent | `ReactNode` | Element to be rendered in the right side of the select. | - |
|
||||
| selectorIcon | `ReactNode` | Element to be rendered as the selector icon. | - |
|
||||
| scrollRef | `React.RefObject<HTMLElement>` | A ref to the scrollable element. | - |
|
||||
| spinnerRef | `React.RefObject<HTMLElement>` | A ref to the spinner element. | - |
|
||||
| fullWidth | `boolean` | Whether the select should take up the width of its parent. | `true` |
|
||||
| isOpen | `boolean` | Whether the select is open by default (controlled). | - |
|
||||
| defaultOpen | `boolean` | Whether the select is open by default (uncontrolled). | - |
|
||||
| isRequired | `boolean` | Whether user select is required on the select before form submission. | `false` |
|
||||
| isDisabled | `boolean` | Whether the select is disabled. | `false` |
|
||||
| isMultiline | `boolean` | Whether the select should allow multiple lines of text. | `false` |
|
||||
| isInvalid | `boolean` | Whether the select is invalid. | `false` |
|
||||
| validationState | `valid` \| `invalid` | Whether the select should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
|
||||
| showScrollIndicators | `boolean` | Whether the select should show scroll indicators when the listbox is scrollable. | `true` |
|
||||
| autoFocus | `boolean` | Whether the select should be focused on the first mount. | `false` |
|
||||
| disallowEmptySelection | `boolean` | Whether the collection allows empty selection. | `false` |
|
||||
| disableAnimation | `boolean` | Whether the select should be animated. | `true` |
|
||||
| disableSelectionIconRotation | `boolean` | Whether the select should disable the rotation of the selector icon. | `false` |
|
||||
| popoverProps | [PopoverProps](/docs/components/popover#api) | Props to be passed to the popover component. | - |
|
||||
| listboxProps | [ListboxProps](/docs/components/listbox#api) | Props to be passed to the listbox component. | - |
|
||||
| scrollShadowProps | [ScrollShadowProps](/docs/components/scroll-shadow#api) | Props to be passed to the scroll shadow component. | - |
|
||||
| classNames | `Record<"base"| "label"| "trigger"| "mainWrapper" | "innerWrapper"| "selectorIcon" | "value" | "listboxWrapper"| "listbox" | "popover" | "helperWrapper" | "description" | "errorMessage", string>` | Allows to set custom class names for the dropdown item slots. | - |
|
||||
|
||||
### Select Events
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ You can also add icons to start and end of the switch by using `startContent` an
|
||||
- **wrapper**: The wrapper of the start icon, end icon and thumb.
|
||||
- **thumb**: The thumb element of the switch. It is the circle element.
|
||||
- **label**: The label slot of the switch.
|
||||
- **startContent**:The icon slot at the start of the switch.
|
||||
- **startContent**: The icon slot at the start of the switch.
|
||||
- **endContent**: The icon slot at the end of the switch.
|
||||
- **thumbIcon**: The icon slot inside the thumb.
|
||||
|
||||
|
||||
@@ -257,8 +257,7 @@ You can use the [Pagination](/components/pagination) component to paginate the t
|
||||
|
||||
### Async Pagination
|
||||
|
||||
It is also possible to use the [Pagination](/components/pagination) component to paginate the table asynchronously. To fetch the data, we are using the `useAsyncList` hook from [@react-stately/data](https://react-spectrum.adobe.com/react-stately/useAsyncList.html).
|
||||
Please check the installation instructions in the [Sorting Rows](#sorting-rows) section.
|
||||
It is also possible to use the [Pagination](/components/pagination) component to paginate the table asynchronously. To fetch the data, we are using the `useSWR` hook from [SWR](https://swr.vercel.app/docs/pagination).
|
||||
|
||||
<CodeDemo
|
||||
asIframe
|
||||
@@ -292,6 +291,7 @@ example below, we combined all these functionalities to create a complete table.
|
||||
|
||||
<CodeDemo
|
||||
asIframe
|
||||
typescriptStrict={true}
|
||||
title="Table use Case Example"
|
||||
resizeEnabled={false}
|
||||
files={tableContent.useCase}
|
||||
|
||||
@@ -13,7 +13,7 @@ Tabs organize content into multiple sections and allow users to navigate between
|
||||
|
||||
---
|
||||
|
||||
<CarbonAd/>
|
||||
<CarbonAd />
|
||||
|
||||
## Import
|
||||
|
||||
@@ -157,10 +157,11 @@ You can customize the `Tabs` component by passing custom Tailwind CSS classes to
|
||||
|
||||
### Tab Props
|
||||
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------- | ----------- | ----------------------- | ------- |
|
||||
| children\* | `ReactNode` | The content of the tab. | - |
|
||||
| title | `ReactNode` | The title of the tab. | - |
|
||||
| Attribute | Type | Description | Default |
|
||||
| ---------- | ----------- | ------------------------------------------------------------------------------------------ | ------- |
|
||||
| children\* | `ReactNode` | The content of the tab. | - |
|
||||
| title | `ReactNode` | The title of the tab. | - |
|
||||
| titleValue | `string` | A string representation of the item's contents. Use this when the `title` is not readable. | - |
|
||||
|
||||
#### Motion Props
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ Textarea component is a multi-line Input which allows you to write large texts.
|
||||
|
||||
---
|
||||
|
||||
<CarbonAd/>
|
||||
<CarbonAd />
|
||||
|
||||
## Import
|
||||
|
||||
@@ -32,7 +32,7 @@ Textarea component is a multi-line Input which allows you to write large texts.
|
||||
|
||||
<CodeDemo title="Disabled" files={textareaContent.disabled} />
|
||||
|
||||
### Readonly
|
||||
### Read Only
|
||||
|
||||
<CodeDemo title="Readonly" files={textareaContent.readonly} />
|
||||
|
||||
@@ -119,30 +119,31 @@ You can use the `value` and `onValueChange` properties to control the input valu
|
||||
|
||||
### Textarea Props
|
||||
|
||||
| Attribute | Type | Description | Default |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------- | --------- |
|
||||
| children | `ReactNode` | The content of the textarea. | - |
|
||||
| minRows | `number` | The minimum number of rows to display. | `3` |
|
||||
| maxRows | `number` | Maximum number of rows up to which the textarea can grow. | `8` |
|
||||
| cacheMeasurements | `boolean` | Reuse previously computed measurements when computing height of textarea. | `false` |
|
||||
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the textarea. | `flat` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the textarea. | `default` |
|
||||
| size | `sm`\|`md`\|`lg` | The size of the textarea. | `md` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the textarea. | - |
|
||||
| label | `ReactNode` | The content to display as the label. | - |
|
||||
| value | `string` | The current value of the textarea (controlled). | - |
|
||||
| defaultValue | `string` | The default value of the textarea (uncontrolled). | - |
|
||||
| placeholder | `string` | The placeholder of the textarea. | - |
|
||||
| description | `ReactNode` | A description for the textarea. Provides a hint such as specific requirements for what to choose. | - |
|
||||
| errorMessage | `ReactNode` | An error message for the textarea. | - |
|
||||
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
|
||||
| fullWidth | `boolean` | Whether the textarea should take up the width of its parent. | `true` |
|
||||
| validationState | `valid` \| `invalid` | Whether the textarea should display its "valid" or "invalid" visual styling. | - |
|
||||
| isRequired | `boolean` | Whether user input is required on the textarea before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the textarea can be selected but not changed by the user. | |
|
||||
| isDisabled | `boolean` | Whether the textarea is disabled. | `false` |
|
||||
| disableAnimation | `boolean` | Whether the textarea should be animated. | `false` |
|
||||
| classNames | `Record<"base"| "label"| "inputWrapper"| "input" | "description" | "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
|
||||
| Attribute | Type | Description | Default |
|
||||
| ----------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | --------- |
|
||||
| children | `ReactNode` | The content of the textarea. | - |
|
||||
| minRows | `number` | The minimum number of rows to display. | `3` |
|
||||
| maxRows | `number` | Maximum number of rows up to which the textarea can grow. | `8` |
|
||||
| cacheMeasurements | `boolean` | Reuse previously computed measurements when computing height of textarea. | `false` |
|
||||
| variant | `flat` \| `bordered` \| `faded` \| `underlined` | The variant of the textarea. | `flat` |
|
||||
| color | `default` \| `primary` \| `secondary` \| `success` \| `warning` \| `danger` | The color of the textarea. | `default` |
|
||||
| size | `sm`\|`md`\|`lg` | The size of the textarea. | `md` |
|
||||
| radius | `none` \| `sm` \| `md` \| `lg` \| `full` | The radius of the textarea. | - |
|
||||
| label | `ReactNode` | The content to display as the label. | - |
|
||||
| value | `string` | The current value of the textarea (controlled). | - |
|
||||
| defaultValue | `string` | The default value of the textarea (uncontrolled). | - |
|
||||
| placeholder | `string` | The placeholder of the textarea. | - |
|
||||
| description | `ReactNode` | A description for the textarea. Provides a hint such as specific requirements for what to choose. | - |
|
||||
| errorMessage | `ReactNode` | An error message for the textarea. | - |
|
||||
| labelPlacement | `inside` \| `outside` \| `outside-left` | The position of the label. | `inside` |
|
||||
| fullWidth | `boolean` | Whether the textarea should take up the width of its parent. | `true` |
|
||||
| isRequired | `boolean` | Whether user input is required on the textarea before form submission. | `false` |
|
||||
| isReadOnly | `boolean` | Whether the textarea can be selected but not changed by the user. | |
|
||||
| isDisabled | `boolean` | Whether the textarea is disabled. | `false` |
|
||||
| isInvalid | `boolean` | Whether the textarea is invalid. | `false` |
|
||||
| validationState | `valid` \| `invalid` | Whether the textarea should display its "valid" or "invalid" visual styling. (**Deprecated**) use **isInvalid** instead. | - |
|
||||
| disableAnimation | `boolean` | Whether the textarea should be animated. | `false` |
|
||||
| classNames | `Record<"base"| "label"| "inputWrapper"| "input" | "description" | "errorMessage", string>` | Allows to set custom class names for the checkbox slots. | - |
|
||||
|
||||
### Input Events
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ description: NextUI offers a set of layout options to customize the theme.
|
||||
# Layout
|
||||
|
||||
NextUI's plugin provides a variety of layout customization options. Alter spacing units,
|
||||
font sizes, line heights, radii and more to personalize each theme to your liking.
|
||||
font sizes, line heights, radius and more to personalize each theme to your liking.
|
||||
|
||||
<CarbonAd />
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ const { nextui } = require("@nextui-org/react");
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -85,7 +85,7 @@ some functionalities of NextUI components may not work properly.
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
@@ -62,13 +62,13 @@ the following code to your `tailwind.config.js` file:
|
||||
|
||||
```js {8,13-14}
|
||||
// tailwind.config.js
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
import {nextui} from "@nextui-org/react";
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
const config = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -76,6 +76,8 @@ module.exports = {
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
}
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### Setup Provider
|
||||
@@ -146,7 +148,7 @@ export default function Page() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
@@ -197,13 +199,13 @@ the following code to your `tailwind.config.js` file:
|
||||
|
||||
```js {8,13-14}
|
||||
// tailwind.config.js
|
||||
const { nextui } = require("@nextui-org/react");
|
||||
import {nextui} from "@nextui-org/react";
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
const config = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -211,6 +213,8 @@ module.exports = {
|
||||
darkMode: "class",
|
||||
plugins: [nextui()]
|
||||
}
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### Setup Provider
|
||||
@@ -253,7 +257,7 @@ export default function Page() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
@@ -48,7 +48,7 @@ import type { Config} from 'tailwindcss'
|
||||
export default {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -100,7 +100,7 @@ export default function App() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
@@ -47,7 +47,7 @@ const { nextui } = require("@nextui-org/react");
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -85,7 +85,7 @@ ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
@@ -87,7 +87,7 @@ function App() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
@@ -203,7 +203,7 @@ function App() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
@@ -57,7 +57,7 @@ const { nextui } = require("@nextui-org/react");
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -136,7 +136,7 @@ export default function Page() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
@@ -177,7 +177,7 @@ const { nextui } = require("@nextui-org/react");
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -227,7 +227,7 @@ export default function Page() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
@@ -275,7 +275,7 @@ const { nextui } = require("@nextui-org/react");
|
||||
module.exports = {
|
||||
content: [
|
||||
// ...
|
||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||
"./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
@@ -327,7 +327,7 @@ export default function Page() {
|
||||
If you are using pnpm, you need to add the following code to your `.npmrc` file:
|
||||
|
||||
```bash
|
||||
public-hoist-pattern[]=*@nextui-org/theme*
|
||||
public-hoist-pattern[]=*@nextui-org/*
|
||||
```
|
||||
|
||||
After modfiying the `.npmrc` file, you need to run `pnpm install` again to ensure that the dependencies are installed correctly.
|
||||
|
||||
@@ -18,17 +18,17 @@
|
||||
"@codesandbox/sandpack-react": "^2.6.4",
|
||||
"@mapbox/rehype-prism": "^0.6.0",
|
||||
"@nextui-org/aria-utils": "workspace:*",
|
||||
"@nextui-org/badge": "workspace:*",
|
||||
"@nextui-org/code": "workspace:*",
|
||||
"@nextui-org/divider": "workspace:*",
|
||||
"@nextui-org/kbd": "workspace:*",
|
||||
"@nextui-org/react": "workspace:*",
|
||||
"@nextui-org/shared-icons": "workspace:*",
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"@nextui-org/kbd": "workspace:*",
|
||||
"@nextui-org/code": "workspace:*",
|
||||
"@nextui-org/badge": "workspace:*",
|
||||
"@nextui-org/skeleton": "workspace:*",
|
||||
"@nextui-org/spacer": "workspace:*",
|
||||
"@nextui-org/spinner": "workspace:*",
|
||||
"@nextui-org/divider": "workspace:*",
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/use-clipboard": "workspace:*",
|
||||
"@nextui-org/use-infinite-scroll": "workspace:*",
|
||||
"@nextui-org/use-is-mobile": "workspace:*",
|
||||
@@ -84,7 +84,8 @@
|
||||
"scroll-into-view-if-needed": "3.0.10",
|
||||
"sharp": "^0.32.1",
|
||||
"shelljs": "^0.8.4",
|
||||
"tailwind-variants": "^0.1.13",
|
||||
"swr": "^2.2.1",
|
||||
"tailwind-variants": "^0.1.14",
|
||||
"unified": "^9.2.2",
|
||||
"unist-util-visit": "^4.1.2",
|
||||
"zustand": "^4.3.8"
|
||||
|
||||
@@ -39,6 +39,10 @@
|
||||
.cm-scroller::-webkit-scrollbar {
|
||||
width: 0px
|
||||
}
|
||||
.sp-tabs {
|
||||
padding-right: 110px;
|
||||
}
|
||||
|
||||
.sp-tab-button {
|
||||
@apply block !font-sans bg-transparent appearance-none;
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ module.exports = {
|
||||
highlighted: `${commonColors.purple[500]} 1px 0 0, ${commonColors.purple[500]} -1px 0 0`,
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["DM Sans", ...defaultTheme.fontFamily.sans],
|
||||
sans: ["var(--font-sans)", ...defaultTheme.fontFamily.sans],
|
||||
serif: defaultTheme.fontFamily.serif,
|
||||
mono: defaultTheme.fontFamily.mono,
|
||||
},
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import va from "@vercel/analytics";
|
||||
|
||||
import {__PROD__} from "./env";
|
||||
|
||||
export function getUniqueID(prefix: string) {
|
||||
return `${prefix}-${new Date().getTime()}`;
|
||||
}
|
||||
|
||||
export type TrackEvent = {
|
||||
category: string;
|
||||
action: string;
|
||||
name?: string;
|
||||
data?: any;
|
||||
};
|
||||
|
||||
const getSessionId = () => {
|
||||
let sessionId = getUniqueID("session");
|
||||
|
||||
// save session id in local storage if it doesn't exist
|
||||
if (!localStorage.getItem("sessionId")) {
|
||||
localStorage.setItem("sessionId", sessionId);
|
||||
|
||||
return sessionId;
|
||||
} else {
|
||||
return localStorage.getItem("sessionId") ?? sessionId;
|
||||
}
|
||||
};
|
||||
|
||||
export const trackEvent = (label: string, event: TrackEvent) => {
|
||||
if (!__PROD__) return;
|
||||
|
||||
const sessionId = getSessionId();
|
||||
|
||||
va.track(label, {
|
||||
...event,
|
||||
sessionId,
|
||||
});
|
||||
};
|
||||
+7
-2
@@ -31,6 +31,7 @@
|
||||
"lint:docs": "eslint -c .eslintrc.json ./apps/docs/**/*.{ts,tsx}",
|
||||
"lint:fix": "eslint --fix -c .eslintrc.json ./packages/**/**/*.{ts,tsx}",
|
||||
"lint:docs-fix": "eslint --fix -c .eslintrc.json ./apps/docs/**/*.{ts,tsx}",
|
||||
"check:rap": "tsx scripts/check-rap-updates.ts",
|
||||
"format:check": "prettier --check packages/**/**/src --cache",
|
||||
"format:write": "prettier --write packages/**/**/src --cache",
|
||||
"turbo:clean": "turbo clean && rimraf ./node_modules/.cache/turbo",
|
||||
@@ -52,6 +53,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.14.5",
|
||||
"@babel/core": "^7.16.7",
|
||||
"tsx": "^3.8.2",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.15.6",
|
||||
"@babel/plugin-transform-runtime": "^7.14.5",
|
||||
"@babel/preset-env": "^7.14.5",
|
||||
@@ -103,6 +105,7 @@
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"npm-check-updates": "^16.10.18",
|
||||
"intl-messageformat": "^10.1.0",
|
||||
"execa": "^5.1.1",
|
||||
"find-up": "^6.3.0",
|
||||
@@ -141,6 +144,8 @@
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.x"
|
||||
}
|
||||
"node": ">=16.x",
|
||||
"pnpm": ">=8.x"
|
||||
},
|
||||
"packageManager": "pnpm@8.7.0"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,91 @@
|
||||
# @nextui-org/accordion
|
||||
|
||||
## 2.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1630](https://github.com/nextui-org/nextui/pull/1630) [`bc424948c`](https://github.com/nextui-org/nextui/commit/bc424948c70ddbc5b00a9d732dafcd5008c78b1f) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix #1405 and #1608 accordion is no longer preventing spacebar key for Input/Textarea components
|
||||
|
||||
- [#1639](https://github.com/nextui-org/nextui/pull/1639) [`bb8ed5874`](https://github.com/nextui-org/nextui/commit/bb8ed58749fa50666a1c8a5fa005376fec185710) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix #1402 controlled accordion
|
||||
|
||||
- Updated dependencies [[`bc424948c`](https://github.com/nextui-org/nextui/commit/bc424948c70ddbc5b00a9d732dafcd5008c78b1f), [`425a034bc`](https://github.com/nextui-org/nextui/commit/425a034bca4aa5a86cfe4bc47c084366a7ad7e87)]:
|
||||
- @nextui-org/use-aria-accordion@2.0.1
|
||||
- @nextui-org/theme@2.1.9
|
||||
- @nextui-org/divider@2.0.20
|
||||
- @nextui-org/system@2.0.10
|
||||
- @nextui-org/react-utils@2.0.9
|
||||
- @nextui-org/aria-utils@2.0.10
|
||||
- @nextui-org/framer-transitions@2.0.10
|
||||
|
||||
## 2.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1600](https://github.com/nextui-org/nextui/pull/1600) [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix npm deploy
|
||||
|
||||
- Updated dependencies [[`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572)]:
|
||||
- @nextui-org/divider@2.0.19
|
||||
- @nextui-org/system@2.0.9
|
||||
- @nextui-org/theme@2.1.8
|
||||
- @nextui-org/use-aria-accordion-item@2.0.5
|
||||
- @nextui-org/aria-utils@2.0.9
|
||||
- @nextui-org/framer-transitions@2.0.9
|
||||
- @nextui-org/react-utils@2.0.8
|
||||
- @nextui-org/shared-icons@2.0.4
|
||||
- @nextui-org/shared-utils@2.0.3
|
||||
|
||||
## 2.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1589](https://github.com/nextui-org/nextui/pull/1589) [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - React aria packages upgraded
|
||||
|
||||
- Updated dependencies [[`a3be419cb`](https://github.com/nextui-org/nextui/commit/a3be419cb3c693ae8cace15f9a863274d759ddb1), [`5c30e0481`](https://github.com/nextui-org/nextui/commit/5c30e04811ef9f973d6b59107c909db72d9876b5), [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2)]:
|
||||
- @nextui-org/theme@2.1.7
|
||||
- @nextui-org/use-aria-accordion-item@2.0.4
|
||||
- @nextui-org/aria-utils@2.0.8
|
||||
- @nextui-org/divider@2.0.18
|
||||
- @nextui-org/system@2.0.8
|
||||
- @nextui-org/framer-transitions@2.0.8
|
||||
|
||||
## 2.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7c8341035`](https://github.com/nextui-org/nextui/commit/7c8341035dbdd120cd78221b3cabab2e40e7478d)]:
|
||||
- @nextui-org/theme@2.1.6
|
||||
- @nextui-org/divider@2.0.17
|
||||
|
||||
## 2.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d61428d9e`](https://github.com/nextui-org/nextui/commit/d61428d9e6c1c0590593fb1f0136e226051b7e23), [`4db10a47e`](https://github.com/nextui-org/nextui/commit/4db10a47e96ad8315b5b96c2ff15574ac0fdeecc)]:
|
||||
- @nextui-org/theme@2.1.5
|
||||
- @nextui-org/divider@2.0.16
|
||||
- @nextui-org/system@2.0.7
|
||||
- @nextui-org/aria-utils@2.0.7
|
||||
- @nextui-org/framer-transitions@2.0.7
|
||||
|
||||
## 2.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`043b8420c`](https://github.com/nextui-org/nextui/commit/043b8420cfb659cbb6bb36404807ec3cc8ac8592), [`641bf0885`](https://github.com/nextui-org/nextui/commit/641bf0885b6af2d7f36f27d83716a441975a5ca5)]:
|
||||
- @nextui-org/theme@2.1.4
|
||||
- @nextui-org/system@2.0.6
|
||||
- @nextui-org/divider@2.0.15
|
||||
- @nextui-org/aria-utils@2.0.6
|
||||
- @nextui-org/framer-transitions@2.0.6
|
||||
|
||||
## 2.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5702287e5`](https://github.com/nextui-org/nextui/commit/5702287e5622a8f0a0326c7cc0c200808c7971a8)]:
|
||||
- @nextui-org/theme@2.1.3
|
||||
- @nextui-org/divider@2.0.14
|
||||
|
||||
## 2.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nextui-org/accordion",
|
||||
"version": "2.0.16",
|
||||
"version": "2.0.23",
|
||||
"description": "Collapse display a list of high-level options that can expand/collapse to reveal more information.",
|
||||
"keywords": [
|
||||
"react",
|
||||
@@ -49,20 +49,22 @@
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/react-utils": "workspace:*",
|
||||
"@nextui-org/framer-transitions": "workspace:*",
|
||||
"@nextui-org/use-aria-accordion-item": "workspace:*",
|
||||
"@nextui-org/system": "workspace:*",
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/divider": "workspace:*",
|
||||
"@react-aria/accordion": "3.0.0-alpha.20",
|
||||
"@react-aria/interactions": "^3.17.0",
|
||||
"@react-aria/focus": "^3.14.0",
|
||||
"@react-aria/utils": "^3.19.0",
|
||||
"@react-stately/tree": "^3.7.1",
|
||||
"@react-types/accordion": "3.0.0-alpha.15",
|
||||
"@react-types/shared": "^3.19.0"
|
||||
"@nextui-org/use-aria-accordion": "workspace:*",
|
||||
"@react-aria/interactions": "^3.18.0",
|
||||
"@react-aria/focus": "^3.14.1",
|
||||
"@react-aria/utils": "^3.20.0",
|
||||
"@react-stately/tree": "^3.7.2",
|
||||
"@react-aria/button": "^3.8.2",
|
||||
"@react-types/accordion": "3.0.0-alpha.16",
|
||||
"@react-types/shared": "^3.20.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/button": "workspace:*",
|
||||
"@nextui-org/avatar": "workspace:*",
|
||||
"@nextui-org/input": "workspace:*",
|
||||
"@nextui-org/test-utils": "workspace:*",
|
||||
"framer-motion": "^10.15.1",
|
||||
"clean-package": "2.2.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ import {accordionItem} from "@nextui-org/theme";
|
||||
import {clsx, callAllHandlers, dataAttr} from "@nextui-org/shared-utils";
|
||||
import {ReactRef, useDOMRef, filterDOMProps} from "@nextui-org/react-utils";
|
||||
import {NodeWithProps} from "@nextui-org/aria-utils";
|
||||
import {useAriaAccordionItem} from "@nextui-org/use-aria-accordion-item";
|
||||
import {useReactAriaAccordionItem} from "@nextui-org/use-aria-accordion";
|
||||
import {useCallback, useMemo} from "react";
|
||||
import {chain, mergeProps} from "@react-aria/utils";
|
||||
import {useHover, usePress} from "@react-aria/interactions";
|
||||
@@ -75,7 +75,7 @@ export function useAccordionItem<T extends object = {}>(props: UseAccordionItemP
|
||||
const isDisabled = state.disabledKeys.has(item.key) || isDisabledProp;
|
||||
const isOpen = state.selectionManager.isSelected(item.key);
|
||||
|
||||
const {buttonProps: buttonCompleteProps, regionProps} = useAriaAccordionItem(
|
||||
const {buttonProps: buttonCompleteProps, regionProps} = useReactAriaAccordionItem(
|
||||
{item, isDisabled},
|
||||
{...state, focusedKey: focusedKey},
|
||||
domRef,
|
||||
|
||||
@@ -6,12 +6,12 @@ import type {AccordionGroupVariantProps} from "@nextui-org/theme";
|
||||
import {ReactRef, filterDOMProps} from "@nextui-org/react-utils";
|
||||
import React, {Key, useCallback} from "react";
|
||||
import {TreeState, useTreeState} from "@react-stately/tree";
|
||||
import {useAccordion as useReactAriaAccordion} from "@react-aria/accordion";
|
||||
import {mergeProps} from "@react-aria/utils";
|
||||
import {accordion} from "@nextui-org/theme";
|
||||
import {useDOMRef} from "@nextui-org/react-utils";
|
||||
import {useMemo, useState} from "react";
|
||||
import {DividerProps} from "@nextui-org/divider";
|
||||
import {useReactAriaAccordion} from "@nextui-org/use-aria-accordion";
|
||||
|
||||
import {AccordionItemProps} from "./accordion-item";
|
||||
|
||||
@@ -198,6 +198,7 @@ export function useAccordion<T extends object>(props: UseAccordionProps<T>) {
|
||||
isCompact,
|
||||
isDisabled,
|
||||
hideIndicator,
|
||||
selectedKeys,
|
||||
disableAnimation,
|
||||
keepContentMounted,
|
||||
state?.expandedKeys.values,
|
||||
|
||||
@@ -2,7 +2,7 @@ import type {Selection} from "@react-types/shared";
|
||||
|
||||
import React from "react";
|
||||
import {Meta} from "@storybook/react";
|
||||
import {accordionItem} from "@nextui-org/theme";
|
||||
import {accordionItem, button} from "@nextui-org/theme";
|
||||
import {
|
||||
AnchorIcon,
|
||||
MoonIcon,
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
InvalidCardIcon,
|
||||
} from "@nextui-org/shared-icons";
|
||||
import {Avatar} from "@nextui-org/avatar";
|
||||
import {Input} from "@nextui-org/input";
|
||||
import {Button} from "@nextui-org/button";
|
||||
|
||||
import {Accordion, AccordionProps, AccordionItem} from "../src";
|
||||
import {AccordionItemProps} from "../src";
|
||||
@@ -230,17 +232,43 @@ const ControlledTemplate = (args: AccordionProps) => {
|
||||
console.log(selectedKeys);
|
||||
|
||||
return (
|
||||
<Accordion {...args} selectedKeys={selectedKeys} onSelectionChange={setSelectedKeys}>
|
||||
<AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
<AccordionItem key="2" aria-label="Accordion 2" title="Accordion 2">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
<AccordionItem key="3" aria-label="Accordion 3" title="Accordion 3">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
<div className="flex flex-col gap-4">
|
||||
<Accordion {...args} selectedKeys={selectedKeys}>
|
||||
<AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
<AccordionItem key="2" aria-label="Accordion 2" title="Accordion 2">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
<AccordionItem key="3" aria-label="Accordion 3" title="Accordion 3">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
onPress={() => {
|
||||
setSelectedKeys(new Set(["1"]));
|
||||
}}
|
||||
>
|
||||
Open 1
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setSelectedKeys(new Set(["2"]));
|
||||
}}
|
||||
>
|
||||
Open 2
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => {
|
||||
setSelectedKeys(new Set(["3"]));
|
||||
}}
|
||||
>
|
||||
Open 3
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -313,6 +341,42 @@ const CustomWithClassNamesTemplate = (args: AccordionProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
const WithFormTemplate = (args: AccordionProps) => {
|
||||
const form = (
|
||||
<form className="flex flex-col gap-4">
|
||||
<Input
|
||||
isRequired
|
||||
label="Email"
|
||||
placeholder="Enter your email"
|
||||
type="email"
|
||||
onValueChange={(value) =>
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(value)
|
||||
}
|
||||
/>
|
||||
<Input isRequired label="Password" placeholder="Enter your password" type="password" />
|
||||
|
||||
<div className="flex gap-2 justify-end">
|
||||
<button className={button({color: "primary"})}>Login</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
|
||||
return (
|
||||
<Accordion {...args}>
|
||||
<AccordionItem key="1" aria-label="Accordion 1" title="Accordion 1">
|
||||
{form}
|
||||
</AccordionItem>
|
||||
<AccordionItem key="2" aria-label="Accordion 2" title="Accordion 2">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
<AccordionItem key="3" aria-label="Accordion 3" title="Accordion 3">
|
||||
{defaultContent}
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default = {
|
||||
render: Template,
|
||||
|
||||
@@ -390,6 +454,14 @@ export const Variants = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithForm = {
|
||||
render: WithFormTemplate,
|
||||
|
||||
args: {
|
||||
...defaultProps,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomMotion = {
|
||||
render: Template,
|
||||
|
||||
|
||||
@@ -1,5 +1,67 @@
|
||||
# @nextui-org/avatar
|
||||
|
||||
## 2.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`425a034bc`](https://github.com/nextui-org/nextui/commit/425a034bca4aa5a86cfe4bc47c084366a7ad7e87)]:
|
||||
- @nextui-org/theme@2.1.9
|
||||
- @nextui-org/system@2.0.10
|
||||
- @nextui-org/react-utils@2.0.9
|
||||
|
||||
## 2.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1600](https://github.com/nextui-org/nextui/pull/1600) [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix npm deploy
|
||||
|
||||
- Updated dependencies [[`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572)]:
|
||||
- @nextui-org/system@2.0.9
|
||||
- @nextui-org/theme@2.1.8
|
||||
- @nextui-org/use-image@2.0.3
|
||||
- @nextui-org/react-utils@2.0.8
|
||||
- @nextui-org/shared-utils@2.0.3
|
||||
|
||||
## 2.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1589](https://github.com/nextui-org/nextui/pull/1589) [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - React aria packages upgraded
|
||||
|
||||
- Updated dependencies [[`a3be419cb`](https://github.com/nextui-org/nextui/commit/a3be419cb3c693ae8cace15f9a863274d759ddb1), [`5c30e0481`](https://github.com/nextui-org/nextui/commit/5c30e04811ef9f973d6b59107c909db72d9876b5), [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2)]:
|
||||
- @nextui-org/theme@2.1.7
|
||||
- @nextui-org/system@2.0.8
|
||||
|
||||
## 2.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7c8341035`](https://github.com/nextui-org/nextui/commit/7c8341035dbdd120cd78221b3cabab2e40e7478d)]:
|
||||
- @nextui-org/theme@2.1.6
|
||||
|
||||
## 2.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d61428d9e`](https://github.com/nextui-org/nextui/commit/d61428d9e6c1c0590593fb1f0136e226051b7e23), [`4db10a47e`](https://github.com/nextui-org/nextui/commit/4db10a47e96ad8315b5b96c2ff15574ac0fdeecc)]:
|
||||
- @nextui-org/theme@2.1.5
|
||||
- @nextui-org/system@2.0.7
|
||||
|
||||
## 2.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`043b8420c`](https://github.com/nextui-org/nextui/commit/043b8420cfb659cbb6bb36404807ec3cc8ac8592), [`641bf0885`](https://github.com/nextui-org/nextui/commit/641bf0885b6af2d7f36f27d83716a441975a5ca5)]:
|
||||
- @nextui-org/theme@2.1.4
|
||||
- @nextui-org/system@2.0.6
|
||||
|
||||
## 2.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5702287e5`](https://github.com/nextui-org/nextui/commit/5702287e5622a8f0a0326c7cc0c200808c7971a8)]:
|
||||
- @nextui-org/theme@2.1.3
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nextui-org/avatar",
|
||||
"version": "2.0.14",
|
||||
"version": "2.0.21",
|
||||
"description": "The Avatar component is used to represent a user, and displays the profile picture, initials or fallback icon.",
|
||||
"keywords": [
|
||||
"avatar"
|
||||
@@ -42,9 +42,9 @@
|
||||
"@nextui-org/shared-utils": "workspace:*",
|
||||
"@nextui-org/react-utils": "workspace:*",
|
||||
"@nextui-org/use-image": "workspace:*",
|
||||
"@react-aria/interactions": "^3.17.0",
|
||||
"@react-aria/focus": "^3.14.0",
|
||||
"@react-aria/utils": "^3.19.0"
|
||||
"@react-aria/interactions": "^3.18.0",
|
||||
"@react-aria/focus": "^3.14.1",
|
||||
"@react-aria/utils": "^3.20.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/shared-icons": "workspace:*",
|
||||
|
||||
@@ -1,5 +1,66 @@
|
||||
# @nextui-org/badge
|
||||
|
||||
## 2.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`f6531c5f6`](https://github.com/nextui-org/nextui/commit/f6531c5f603d7f6308a597962ec6fab62c92fa93), [`425a034bc`](https://github.com/nextui-org/nextui/commit/425a034bca4aa5a86cfe4bc47c084366a7ad7e87)]:
|
||||
- @nextui-org/system-rsc@2.0.6
|
||||
- @nextui-org/theme@2.1.9
|
||||
- @nextui-org/react-utils@2.0.9
|
||||
|
||||
## 2.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1600](https://github.com/nextui-org/nextui/pull/1600) [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix npm deploy
|
||||
|
||||
- Updated dependencies [[`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572)]:
|
||||
- @nextui-org/system-rsc@2.0.5
|
||||
- @nextui-org/theme@2.1.8
|
||||
- @nextui-org/react-utils@2.0.8
|
||||
- @nextui-org/shared-utils@2.0.3
|
||||
|
||||
## 2.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`a3be419cb`](https://github.com/nextui-org/nextui/commit/a3be419cb3c693ae8cace15f9a863274d759ddb1), [`5c30e0481`](https://github.com/nextui-org/nextui/commit/5c30e04811ef9f973d6b59107c909db72d9876b5)]:
|
||||
- @nextui-org/theme@2.1.7
|
||||
- @nextui-org/system-rsc@2.0.4
|
||||
|
||||
## 2.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7c8341035`](https://github.com/nextui-org/nextui/commit/7c8341035dbdd120cd78221b3cabab2e40e7478d)]:
|
||||
- @nextui-org/theme@2.1.6
|
||||
- @nextui-org/system-rsc@2.0.4
|
||||
|
||||
## 2.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d61428d9e`](https://github.com/nextui-org/nextui/commit/d61428d9e6c1c0590593fb1f0136e226051b7e23), [`4db10a47e`](https://github.com/nextui-org/nextui/commit/4db10a47e96ad8315b5b96c2ff15574ac0fdeecc)]:
|
||||
- @nextui-org/system-rsc@2.0.4
|
||||
- @nextui-org/theme@2.1.5
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`043b8420c`](https://github.com/nextui-org/nextui/commit/043b8420cfb659cbb6bb36404807ec3cc8ac8592)]:
|
||||
- @nextui-org/theme@2.1.4
|
||||
- @nextui-org/system-rsc@2.0.3
|
||||
|
||||
## 2.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5702287e5`](https://github.com/nextui-org/nextui/commit/5702287e5622a8f0a0326c7cc0c200808c7971a8)]:
|
||||
- @nextui-org/theme@2.1.3
|
||||
- @nextui-org/system-rsc@2.0.3
|
||||
|
||||
## 2.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nextui-org/badge",
|
||||
"version": "2.0.12",
|
||||
"version": "2.0.19",
|
||||
"description": "Badges are used as a small numerical value or status descriptor for UI elements.",
|
||||
"keywords": [
|
||||
"badge"
|
||||
|
||||
@@ -1,5 +1,84 @@
|
||||
# @nextui-org/button
|
||||
|
||||
## 2.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1635](https://github.com/nextui-org/nextui/pull/1635) [`ceddd0d1d`](https://github.com/nextui-org/nextui/commit/ceddd0d1d941a669bab78ef7439a29531cff99a2) Thanks [@li-jia-nan](https://github.com/li-jia-nan)! - refactor: optimize the time of ripple destroy
|
||||
|
||||
- Updated dependencies [[`ceddd0d1d`](https://github.com/nextui-org/nextui/commit/ceddd0d1d941a669bab78ef7439a29531cff99a2), [`425a034bc`](https://github.com/nextui-org/nextui/commit/425a034bca4aa5a86cfe4bc47c084366a7ad7e87)]:
|
||||
- @nextui-org/ripple@2.0.21
|
||||
- @nextui-org/theme@2.1.9
|
||||
- @nextui-org/spinner@2.0.19
|
||||
- @nextui-org/system@2.0.10
|
||||
- @nextui-org/react-utils@2.0.9
|
||||
|
||||
## 2.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1600](https://github.com/nextui-org/nextui/pull/1600) [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix npm deploy
|
||||
|
||||
- Updated dependencies [[`8b3998909`](https://github.com/nextui-org/nextui/commit/8b39989090d9cd577e886edde01b081d37e65bb7), [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572)]:
|
||||
- @nextui-org/ripple@2.0.20
|
||||
- @nextui-org/spinner@2.0.18
|
||||
- @nextui-org/system@2.0.9
|
||||
- @nextui-org/theme@2.1.8
|
||||
- @nextui-org/use-aria-button@2.0.5
|
||||
- @nextui-org/react-utils@2.0.8
|
||||
- @nextui-org/shared-utils@2.0.3
|
||||
|
||||
## 2.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1589](https://github.com/nextui-org/nextui/pull/1589) [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - React aria packages upgraded
|
||||
|
||||
- Updated dependencies [[`a3be419cb`](https://github.com/nextui-org/nextui/commit/a3be419cb3c693ae8cace15f9a863274d759ddb1), [`5c30e0481`](https://github.com/nextui-org/nextui/commit/5c30e04811ef9f973d6b59107c909db72d9876b5), [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2)]:
|
||||
- @nextui-org/theme@2.1.7
|
||||
- @nextui-org/use-aria-button@2.0.4
|
||||
- @nextui-org/system@2.0.8
|
||||
- @nextui-org/ripple@2.0.19
|
||||
- @nextui-org/spinner@2.0.17
|
||||
|
||||
## 2.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7c8341035`](https://github.com/nextui-org/nextui/commit/7c8341035dbdd120cd78221b3cabab2e40e7478d)]:
|
||||
- @nextui-org/theme@2.1.6
|
||||
- @nextui-org/ripple@2.0.18
|
||||
- @nextui-org/spinner@2.0.16
|
||||
|
||||
## 2.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d61428d9e`](https://github.com/nextui-org/nextui/commit/d61428d9e6c1c0590593fb1f0136e226051b7e23), [`4db10a47e`](https://github.com/nextui-org/nextui/commit/4db10a47e96ad8315b5b96c2ff15574ac0fdeecc)]:
|
||||
- @nextui-org/theme@2.1.5
|
||||
- @nextui-org/spinner@2.0.15
|
||||
- @nextui-org/system@2.0.7
|
||||
- @nextui-org/ripple@2.0.17
|
||||
|
||||
## 2.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`043b8420c`](https://github.com/nextui-org/nextui/commit/043b8420cfb659cbb6bb36404807ec3cc8ac8592), [`641bf0885`](https://github.com/nextui-org/nextui/commit/641bf0885b6af2d7f36f27d83716a441975a5ca5)]:
|
||||
- @nextui-org/theme@2.1.4
|
||||
- @nextui-org/system@2.0.6
|
||||
- @nextui-org/ripple@2.0.16
|
||||
- @nextui-org/spinner@2.0.14
|
||||
|
||||
## 2.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5702287e5`](https://github.com/nextui-org/nextui/commit/5702287e5622a8f0a0326c7cc0c200808c7971a8)]:
|
||||
- @nextui-org/theme@2.1.3
|
||||
- @nextui-org/ripple@2.0.15
|
||||
- @nextui-org/spinner@2.0.13
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@nextui-org/button",
|
||||
"version": "2.0.14",
|
||||
"version": "2.0.21",
|
||||
"description": "Buttons allow users to perform actions and choose with a single tap.",
|
||||
"keywords": [
|
||||
"button"
|
||||
@@ -44,12 +44,12 @@
|
||||
"@nextui-org/theme": "workspace:*",
|
||||
"@nextui-org/ripple": "workspace:*",
|
||||
"@nextui-org/spinner": "workspace:*",
|
||||
"@react-aria/button": "^3.8.1",
|
||||
"@react-aria/interactions": "^3.17.0",
|
||||
"@react-aria/utils": "^3.19.0",
|
||||
"@react-aria/focus": "^3.14.0",
|
||||
"@react-types/shared": "^3.19.0",
|
||||
"@react-types/button": "^3.7.4"
|
||||
"@react-aria/button": "^3.8.2",
|
||||
"@react-aria/interactions": "^3.18.0",
|
||||
"@react-aria/utils": "^3.20.0",
|
||||
"@react-aria/focus": "^3.14.1",
|
||||
"@react-types/shared": "^3.20.0",
|
||||
"@react-types/button": "^3.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nextui-org/shared-icons": "workspace:*",
|
||||
|
||||
@@ -12,7 +12,6 @@ const Button = forwardRef<"button", ButtonProps>((props, ref) => {
|
||||
domRef,
|
||||
children,
|
||||
styles,
|
||||
ripples,
|
||||
spinnerSize,
|
||||
spinner = <Spinner color="current" size={spinnerSize} />,
|
||||
spinnerPlacement,
|
||||
@@ -21,10 +20,8 @@ const Button = forwardRef<"button", ButtonProps>((props, ref) => {
|
||||
isLoading,
|
||||
disableRipple,
|
||||
getButtonProps,
|
||||
} = useButton({
|
||||
...props,
|
||||
ref,
|
||||
});
|
||||
getRippleProps,
|
||||
} = useButton({...props, ref});
|
||||
|
||||
return (
|
||||
<Component ref={domRef} className={styles} {...getButtonProps()}>
|
||||
@@ -33,7 +30,7 @@ const Button = forwardRef<"button", ButtonProps>((props, ref) => {
|
||||
{children}
|
||||
{isLoading && spinnerPlacement === "end" && spinner}
|
||||
{endContent}
|
||||
{!disableRipple && <Ripple ripples={ripples} />}
|
||||
{!disableRipple && <Ripple {...getRippleProps()} />}
|
||||
</Component>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {ButtonVariantProps} from "@nextui-org/theme";
|
||||
import type {AriaButtonProps} from "@nextui-org/use-aria-button";
|
||||
import type {HTMLNextUIProps, PropGetter} from "@nextui-org/system";
|
||||
import type {ReactNode} from "react";
|
||||
import type {RippleProps} from "@nextui-org/ripple";
|
||||
|
||||
import {dataAttr} from "@nextui-org/shared-utils";
|
||||
import {ReactRef} from "@nextui-org/react-utils";
|
||||
@@ -130,7 +131,7 @@ export function useButton(props: UseButtonProps) {
|
||||
],
|
||||
);
|
||||
|
||||
const {onClick: onRippleClickHandler, ripples} = useRipple();
|
||||
const {onClick: onRippleClickHandler, onClear: onClearRipple, ripples} = useRipple();
|
||||
|
||||
const handleClick = useCallback(
|
||||
(e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
@@ -209,11 +210,15 @@ export function useButton(props: UseButtonProps) {
|
||||
return buttonSpinnerSizeMap[size];
|
||||
}, [size]);
|
||||
|
||||
const getRippleProps = useCallback<() => RippleProps>(
|
||||
() => ({ripples, onClear: onClearRipple}),
|
||||
[ripples, onClearRipple],
|
||||
);
|
||||
|
||||
return {
|
||||
Component,
|
||||
children,
|
||||
domRef,
|
||||
ripples,
|
||||
spinner,
|
||||
styles,
|
||||
startContent,
|
||||
@@ -223,6 +228,7 @@ export function useButton(props: UseButtonProps) {
|
||||
spinnerSize,
|
||||
disableRipple,
|
||||
getButtonProps,
|
||||
getRippleProps,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,79 @@
|
||||
# @nextui-org/card
|
||||
|
||||
## 2.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1635](https://github.com/nextui-org/nextui/pull/1635) [`ceddd0d1d`](https://github.com/nextui-org/nextui/commit/ceddd0d1d941a669bab78ef7439a29531cff99a2) Thanks [@li-jia-nan](https://github.com/li-jia-nan)! - refactor: optimize the time of ripple destroy
|
||||
|
||||
- [#1611](https://github.com/nextui-org/nextui/pull/1611) [`05c966e8a`](https://github.com/nextui-org/nextui/commit/05c966e8a46accff1fa271d50a3161f10d1e203d) Thanks [@bobbychan](https://github.com/bobbychan)! - fix: corrected footerStyles in card footer
|
||||
|
||||
- Updated dependencies [[`ceddd0d1d`](https://github.com/nextui-org/nextui/commit/ceddd0d1d941a669bab78ef7439a29531cff99a2), [`425a034bc`](https://github.com/nextui-org/nextui/commit/425a034bca4aa5a86cfe4bc47c084366a7ad7e87)]:
|
||||
- @nextui-org/ripple@2.0.21
|
||||
- @nextui-org/theme@2.1.9
|
||||
- @nextui-org/system@2.0.10
|
||||
- @nextui-org/react-utils@2.0.9
|
||||
|
||||
## 2.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1600](https://github.com/nextui-org/nextui/pull/1600) [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - Fix npm deploy
|
||||
|
||||
- Updated dependencies [[`8b3998909`](https://github.com/nextui-org/nextui/commit/8b39989090d9cd577e886edde01b081d37e65bb7), [`b1b30b797`](https://github.com/nextui-org/nextui/commit/b1b30b7976f1d6652808fbf12ffde044f0861572)]:
|
||||
- @nextui-org/ripple@2.0.20
|
||||
- @nextui-org/system@2.0.9
|
||||
- @nextui-org/theme@2.1.8
|
||||
- @nextui-org/use-aria-button@2.0.5
|
||||
- @nextui-org/react-utils@2.0.8
|
||||
- @nextui-org/shared-utils@2.0.3
|
||||
|
||||
## 2.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1589](https://github.com/nextui-org/nextui/pull/1589) [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2) Thanks [@jrgarciadev](https://github.com/jrgarciadev)! - React aria packages upgraded
|
||||
|
||||
- Updated dependencies [[`a3be419cb`](https://github.com/nextui-org/nextui/commit/a3be419cb3c693ae8cace15f9a863274d759ddb1), [`5c30e0481`](https://github.com/nextui-org/nextui/commit/5c30e04811ef9f973d6b59107c909db72d9876b5), [`1612532ee`](https://github.com/nextui-org/nextui/commit/1612532eeeabbc49165546b1a2e7aebf89e7a1c2)]:
|
||||
- @nextui-org/theme@2.1.7
|
||||
- @nextui-org/use-aria-button@2.0.4
|
||||
- @nextui-org/system@2.0.8
|
||||
- @nextui-org/ripple@2.0.19
|
||||
|
||||
## 2.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7c8341035`](https://github.com/nextui-org/nextui/commit/7c8341035dbdd120cd78221b3cabab2e40e7478d)]:
|
||||
- @nextui-org/theme@2.1.6
|
||||
- @nextui-org/ripple@2.0.18
|
||||
|
||||
## 2.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d61428d9e`](https://github.com/nextui-org/nextui/commit/d61428d9e6c1c0590593fb1f0136e226051b7e23), [`4db10a47e`](https://github.com/nextui-org/nextui/commit/4db10a47e96ad8315b5b96c2ff15574ac0fdeecc)]:
|
||||
- @nextui-org/theme@2.1.5
|
||||
- @nextui-org/system@2.0.7
|
||||
- @nextui-org/ripple@2.0.17
|
||||
|
||||
## 2.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`043b8420c`](https://github.com/nextui-org/nextui/commit/043b8420cfb659cbb6bb36404807ec3cc8ac8592), [`641bf0885`](https://github.com/nextui-org/nextui/commit/641bf0885b6af2d7f36f27d83716a441975a5ca5)]:
|
||||
- @nextui-org/theme@2.1.4
|
||||
- @nextui-org/system@2.0.6
|
||||
- @nextui-org/ripple@2.0.16
|
||||
|
||||
## 2.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5702287e5`](https://github.com/nextui-org/nextui/commit/5702287e5622a8f0a0326c7cc0c200808c7971a8)]:
|
||||
- @nextui-org/theme@2.1.3
|
||||
- @nextui-org/ripple@2.0.15
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user