refactor: delete docs & make it dev environment

This commit is contained in:
Shinwoo PARK 2024-06-13 19:28:32 +00:00
parent fc5c5ba4f5
commit 643e607eb4
93 changed files with 1 additions and 3797 deletions

View File

@ -3,23 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<meta name="description" content="PSW/UI is a UI library with minimum dependency." />
<meta name="keywords" content="UI, library, PSW, React, components" />
<meta name="author" content="Shinwoo PARK" />
<meta property="og:title" content="PSW/UI" />
<meta property="og:description" content="PSW/UI is a UI library with minimum dependency." />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://ui.psw.kr" />
<meta property="og:image" content="https://ui.psw.kr/android-chrome-512x512.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="PSW/UI" />
<meta name="twitter:description" content="PSW/UI is a UI library with minimum dependency." />
<meta name="twitter:image" content="https://ui.psw.kr/android-chrome-512x512.png" />
<title>PSW/UI</title>
<title>Dev Environment</title>
</head>
<body>
<div id="root"></div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,20 +0,0 @@
{
"name": "PSW/UI",
"short_name": "PSWUI",
"description": "PSW/UI is a UI library with minimum dependency.",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

View File

@ -1,256 +0,0 @@
import {
Route,
createBrowserRouter,
createRoutesFromElements,
RouterProvider,
redirect,
} from "react-router-dom";
import MainLayout from "./MainLayout";
import Home from "./Home";
import DocsLayout from "./DocsLayout";
import ErrorBoundary from "./ErrorHandler";
import DynamicLayout from "./DynamicLayout";
import { Code } from "./components/LoadedCode";
import DocsIntroduction, {
tableOfContents as docsIntroductionToc,
} from "./docs/introduction.mdx";
import DocsInstallation, {
tableOfContents as docsInstallationToc,
} from "./docs/installation.mdx";
import DocsConfiguration, {
tableOfContents as docsConfigurationToc,
} from "./docs/configuration.mdx";
import { HeadingContext } from "./HeadingContext";
import React, {
ForwardedRef,
forwardRef,
useContext,
useEffect,
useRef,
useState,
} from "react";
import { Tooltip, TooltipContent } from "@components/Tooltip.tsx";
function buildThresholdList() {
const thresholds: number[] = [];
const numSteps = 20;
for (let i = 1.0; i <= numSteps; i++) {
const ratio = i / numSteps;
thresholds.push(ratio);
}
thresholds.push(0);
return thresholds;
}
function HashedHeaders(Level: `h${1 | 2 | 3 | 4 | 5 | 6}`) {
return (prop: any, ref: ForwardedRef<HTMLHeadingElement>) => {
const internalRef = useRef<HTMLHeadingElement | null>(null);
const [_, setActiveHeadings] = useContext(HeadingContext);
const { children, ...restProp } = prop;
useEffect(() => {
const observer = new IntersectionObserver(
([{ target, intersectionRatio }]) => {
if (intersectionRatio > 0.5) {
setActiveHeadings((prev) => [...prev, target.id]);
} else {
setActiveHeadings((prev) => prev.filter((id) => id !== target.id));
}
},
{
root: null,
rootMargin: "0px",
threshold: buildThresholdList(),
},
);
if (internalRef.current) {
observer.observe(internalRef.current);
}
return () => {
observer.disconnect();
};
}, [internalRef.current]);
const [status, setStatus] = useState<"normal" | "error" | "success">(
"normal",
);
const messages = {
normal: "Click to copy link",
success: "Copied link!",
error: "Failed to copy..",
};
useEffect(() => {
if (status !== "normal") {
const timeout = setTimeout(() => {
setStatus("normal");
}, 3000);
return () => {
clearTimeout(timeout);
};
}
}, [status]);
return (
<Tooltip asChild position={"right"}>
<Level
ref={(el) => {
internalRef.current = el;
if (typeof ref === "function") {
ref(el);
} else if (el && ref) {
ref.current = el;
}
}}
className={`${prop.className} cursor-pointer select-none`}
onClick={async (e) => {
try {
await navigator.clipboard.writeText(
window.location.href.split("#")[0] + "#" + e.currentTarget.id,
);
setStatus("success");
} catch (e) {
setStatus("error");
}
}}
{...restProp}
>
{children}
<TooltipContent status={status} offset={"lg"} delay={"early"}>
<p className={"text-base font-normal whitespace-nowrap not-prose"}>
{messages[status]}
</p>
</TooltipContent>
</Level>
</Tooltip>
);
};
}
const overrideComponents = {
pre: (props: any) => {
const {
props: { children, className },
} = React.cloneElement(React.Children.only(props.children));
const language =
(!className || !className.includes("language-")
? "typescript"
: /language-([a-z]+)/.exec(className)![1]) ?? "typescript";
return <Code language={language}>{children as string}</Code>;
},
code: forwardRef<HTMLElement, any>((props: any, ref) => (
<code
ref={ref}
{...props}
className={`${props.className} rounded-md bg-neutral-800 text-orange-500 font-light p-1 before:content-none after:content-none`}
/>
)),
table: forwardRef<HTMLTableElement, any>((props: any, ref) => (
<div className="overflow-auto">
<table ref={ref} {...props} className={`${props.className}`} />
</div>
)),
h1: forwardRef<HTMLHeadingElement, any>(HashedHeaders("h1")),
h2: forwardRef<HTMLHeadingElement, any>(HashedHeaders("h2")),
h3: forwardRef<HTMLHeadingElement, any>(HashedHeaders("h3")),
h4: forwardRef<HTMLHeadingElement, any>(HashedHeaders("h4")),
h5: forwardRef<HTMLHeadingElement, any>(HashedHeaders("h5")),
h6: forwardRef<HTMLHeadingElement, any>(HashedHeaders("h6")),
};
const docsModules = import.meta.glob("./docs/components/*.mdx");
const routes = Object.keys(docsModules).map((path) => {
const sfPath = path.split("/").pop()?.replace(".mdx", "");
return (
<Route
key={path}
path={sfPath}
lazy={async () => {
const { default: C, tableOfContents } = await import(
`./docs/components/${sfPath}.mdx`
);
return {
Component: () => (
<DynamicLayout toc={tableOfContents}>
<C components={overrideComponents} />
</DynamicLayout>
),
};
}}
/>
);
});
const REDIRECTED_404 = /^\?(\/([a-zA-Z0-9\-_]+\/?)+)(&.*)*$/;
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<MainLayout />} errorElement={<ErrorBoundary />}>
<Route
index
loader={() =>
REDIRECTED_404.test(window.location.search)
? redirect(REDIRECTED_404.exec(window.location.search)?.[1] ?? "/")
: true
}
element={<Home />}
/>
<Route path="docs" element={<DocsLayout />}>
<Route index loader={() => redirect("/docs/introduction")} />
<Route
path="introduction"
element={
<DynamicLayout toc={docsIntroductionToc}>
<DocsIntroduction components={overrideComponents} />
</DynamicLayout>
}
/>
<Route
path="installation"
element={
<DynamicLayout toc={docsInstallationToc}>
<DocsInstallation components={overrideComponents} />
</DynamicLayout>
}
/>
<Route
path="configuration"
element={
<DynamicLayout toc={docsConfigurationToc}>
<DocsConfiguration components={overrideComponents} />
</DynamicLayout>
}
/>
<Route path="components">
<Route
index
loader={() =>
redirect(
`/docs/components/${Object.keys(docsModules)[0]
.split("/")
.pop()
?.replace(".mdx", "")}`,
)
}
/>
{routes}
</Route>
</Route>
</Route>,
),
);
function App() {
return <RouterProvider router={router} />;
}
export default App;

View File

@ -1,43 +0,0 @@
import { Link, useLocation } from "react-router-dom";
import { Outlet } from "react-router-dom";
import RouteObject from "./RouteObject";
function SideNav() {
const location = useLocation();
return (
<nav className="sticky top-16 overflow-auto max-h-[calc(100vh-4rem)] md:flex flex-col justify-start items-start gap-8 p-8 hidden">
{Object.entries(RouteObject.sideNav).map(([categoryName, links]) => {
return (
<section
className="flex flex-col gap-2 justify-center items-start"
key={categoryName}
>
<span className="font-bold">{categoryName}</span>
{links.map((link) => (
<Link
to={link.path}
key={link.path}
className="text-sm text-neutral-500 hover:text-neutral-700 data-[active=true]:text-current"
data-active={link.eq(location.pathname)}
>
{link.name}
</Link>
))}
</section>
);
})}
</nav>
);
}
function DocsLayout() {
return (
<div className="flex-grow grid grid-cols-1 md:grid-cols-[12rem_1fr] lg:grid-cols-[12rem_1fr_10rem] w-full max-w-5xl mx-auto">
<SideNav />
<Outlet />
</div>
);
}
export default DocsLayout;

View File

@ -1,63 +0,0 @@
import { ReactNode, Fragment, useState, useContext } from "react";
import { type Toc } from "@stefanprobst/rehype-extract-toc";
import { useLocation } from "react-router-dom";
import { HeadingContext } from "./HeadingContext";
function RecursivelyToc({ toc }: { toc: Toc }) {
const location = useLocation();
const [activeHeadings] = useContext(HeadingContext);
return (
<ul>
{toc.map((tocEntry) => {
return (
<Fragment key={tocEntry.id}>
<li
key={tocEntry.id}
data-id={tocEntry.id}
className="text-neutral-500 data-[active='true']:text-black dark:data-[active='true']:text-white text-sm font-medium"
style={{ paddingLeft: `${tocEntry.depth - 1}rem` }}
data-active={
activeHeadings.includes(tocEntry.id ?? "")
? true
: location.hash.length > 0
? location.hash === `#${tocEntry.id}`
: false
}
>
<a href={`#${tocEntry.id}`}>{tocEntry.value}</a>
</li>
{Array.isArray(tocEntry.children) && (
<RecursivelyToc toc={tocEntry.children} />
)}
</Fragment>
);
})}
</ul>
);
}
export default function DynamicLayout({
children,
toc,
}: {
children: ReactNode;
toc: Toc;
}) {
const [activeHeadings, setActiveHeadings] = useState<string[]>([]);
return (
<HeadingContext.Provider value={[activeHeadings, setActiveHeadings]}>
<div className="w-full flex flex-col items-center">
<main className="w-full [:not(:where([class~='not-prose'],[class~='not-prose']_*))]:prose-sm prose lg:[:not(:where([class~='not-prose'],_[class~='not-prose']_*))]:prose-lg p-8 dark:prose-invert">
{children}
</main>
</div>
<nav className="hidden lg:flex flex-col gap-2 py-8 px-4 sticky top-16 overflow-auto max-h-[calc(100vh-4rem)]">
<span className="font-bold text-sm">On This Page</span>
<RecursivelyToc toc={toc} />
</nav>
</HeadingContext.Provider>
);
}

View File

@ -1,19 +0,0 @@
import { isRouteErrorResponse, useRouteError } from "react-router-dom";
import UnexpectedError from "./errors/Unexpected";
import PageNotFound from "./errors/PageNotFound";
function ErrorBoundary() {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
if (error.status === 404) {
return <PageNotFound />;
} else {
return <UnexpectedError />;
}
} else {
return <UnexpectedError />;
}
}
export default ErrorBoundary;

View File

@ -1,12 +0,0 @@
import { Dispatch, SetStateAction, createContext } from "react";
export const HeadingContext = createContext<
[string[], Dispatch<SetStateAction<string[]>>]
>([
[],
() => {
if (process.env && process.env.NODE_ENV === "development") {
console.log("HeadingContext outside");
}
},
]);

View File

@ -1,30 +0,0 @@
import { Link } from "react-router-dom";
import { Button } from "../components/Button";
function Home() {
return (
<main className="flex-grow h-full flex flex-col p-4 justify-center items-center">
<section className="h-full flex flex-col justify-center items-center text-center gap-8">
<header className="flex flex-col justify-center items-center gap-2">
<h1 className="text-4xl font-bold">
Build your components in isolation
</h1>
<p className="text-xl max-w-xl">
There are a lot of component libraries out there, but why it install
so many things?
</p>
</header>
<div className="flex flex-row justify-center items-center gap-2">
<Button asChild preset="default">
<Link to="/docs">Get Started</Link>
</Button>
<Button asChild preset="ghost">
<Link to="/docs/components">Components</Link>
</Button>
</div>
</section>
</main>
);
}
export default Home;

View File

@ -1,215 +0,0 @@
import { useEffect, useState } from "react";
import { Link, Outlet, useLocation } from "react-router-dom";
import { Button } from "../components/Button";
import RouteObject from "./RouteObject";
import { Toaster } from "@components/Toast";
import { Popover, PopoverContent, PopoverTrigger } from "@components/Popover";
import {
DrawerClose,
DrawerContent,
DrawerOverlay,
DrawerRoot,
DrawerTrigger,
} from "@components/Drawer";
type Theme = "light" | "dark" | "system";
function ThemeButton() {
const [theme, setTheme] = useState<Theme>(
(localStorage.getItem("theme") as Theme) || "system"
);
useEffect(() => {
document.documentElement.classList.toggle("dark", theme === "dark");
document.documentElement.classList.toggle("system", theme === "system");
localStorage.setItem("theme", theme);
}, [theme]);
return (
<Popover>
<PopoverTrigger>
<Button preset="ghost" size="icon">
{/* material-symbols:light-mode */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
className="dark:hidden"
>
<path
fill="currentColor"
d="M12 17q-2.075 0-3.537-1.463T7 12t1.463-3.537T12 7t3.538 1.463T17 12t-1.463 3.538T12 17m-7-4H1v-2h4zm18 0h-4v-2h4zM11 5V1h2v4zm0 18v-4h2v4zM6.4 7.75L3.875 5.325L5.3 3.85l2.4 2.5zm12.3 12.4l-2.425-2.525L17.6 16.25l2.525 2.425zM16.25 6.4l2.425-2.525L20.15 5.3l-2.5 2.4zM3.85 18.7l2.525-2.425L7.75 17.6l-2.425 2.525z"
/>
</svg>
{/* material-symbols:dark-mode */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
className="hidden dark:block"
>
<path
fill="currentColor"
d="M12 21q-3.75 0-6.375-2.625T3 12t2.625-6.375T12 3q.35 0 .688.025t.662.075q-1.025.725-1.638 1.888T11.1 7.5q0 2.25 1.575 3.825T16.5 12.9q1.375 0 2.525-.613T20.9 10.65q.05.325.075.662T21 12q0 3.75-2.625 6.375T12 21"
/>
</svg>
</Button>
</PopoverTrigger>
<PopoverContent anchor="bottomLeft" className="w-32">
<Button
preset="ghost"
onClick={() => setTheme("light")}
className="w-full px-2 py-1.5 text-sm"
>
Light
</Button>
<Button
preset="ghost"
onClick={() => setTheme("dark")}
className="w-full px-2 py-1.5 text-sm"
>
Dark
</Button>
<Button
preset="ghost"
onClick={() => setTheme("system")}
className="w-full px-2 py-1.5 text-sm"
>
System
</Button>
</PopoverContent>
</Popover>
);
}
function TopNav() {
const location = useLocation();
return (
<>
<nav className="sticky top-0 z-20 bg-transparent backdrop-blur-lg border-b border-neutral-200 dark:border-neutral-800 w-full max-w-screen px-8 flex flex-row justify-center items-center h-16">
<div
data-role="wrapper"
className="flex flex-row items-center justify-between w-full max-w-6xl text-lg"
>
<div
data-role="links"
className="hidden md:flex flex-row items-center gap-3"
>
<Link to="/" className="font-bold">
PSW/UI
</Link>
{RouteObject.mainNav.map((link) => {
return (
<Link
key={link.path}
to={link.path}
data-active={link.eq(location.pathname)}
className="font-light text-base data-[active=true]:text-current text-neutral-500 hover:text-neutral-700"
>
{link.name}
</Link>
);
})}
</div>
<div data-role="mobile-links" className="flex md:hidden">
<DrawerRoot>
<DrawerTrigger>
<Button preset="ghost" size="icon">
{/* mdi:menu */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"
/>
</svg>
</Button>
</DrawerTrigger>
<DrawerOverlay className="z-[99]">
<DrawerContent className="w-[300px] overflow-auto">
<DrawerClose className="absolute top-4 right-4">
<Button preset="ghost" size="icon">
{/* mdi:close */}
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M19 6.41L17.59 5 12 9.27 6.41 5 5 6.41 9.27 11 5 17.59 6.41 19 12 14.73 17.59 19 19 17.59 13.41 12 19 6.41"
/>
</svg>
</Button>
</DrawerClose>
<div className="flex flex-col justify-start items-start gap-6 text-lg">
<div className="flex flex-col justify-start items-start gap-3">
<DrawerClose>
<Link to="/" className="font-extrabold">
PSW/UI
</Link>
</DrawerClose>
{RouteObject.mainNav.map((link) => {
return (
<DrawerClose key={link.path}>
<Link to={link.path}>{link.name}</Link>
</DrawerClose>
);
})}
</div>
{Object.entries(RouteObject.sideNav).map(
([categoryName, links]) => {
return (
<div
className="flex flex-col justify-start items-start gap-3"
key={categoryName}
>
<h2 className="font-bold">{categoryName}</h2>
{links.map((link) => {
return (
<DrawerClose key={link.path}>
<Link
to={link.path}
className="text-base opacity-75"
>
{link.name}
</Link>
</DrawerClose>
);
})}
</div>
);
}
)}
</div>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
</div>
<div data-role="controls" className="flex flex-row items-center">
<ThemeButton />
</div>
</div>
</nav>
</>
);
}
function MainLayout() {
return (
<>
<Toaster className="top-16" />
<TopNav />
<Outlet />
</>
);
}
export default MainLayout;

View File

@ -1,59 +0,0 @@
const docsModules = import.meta.glob("./docs/components/*.mdx");
const mainNav = [
{
path: "/docs",
name: "Docs",
eq: (pathname: string) =>
pathname.startsWith("/docs") && !pathname.startsWith("/docs/components"),
},
{
path: "/docs/components",
name: "Components",
eq: (pathname: string) => pathname.startsWith("/docs/components"),
},
{
path: "https://github.com/p-sw/ui",
name: "Github",
eq: () => false,
},
];
const sideNav: Record<
string,
{ path: string; name: string; eq: (path: string) => boolean }[]
> = {
Documents: [
{
path: "/docs/introduction",
name: "Introduction",
eq: (pathname: string) => pathname === "/docs/introduction",
},
{
path: "/docs/installation",
name: "Installation",
eq: (pathname: string) => pathname === "/docs/installation",
},
{
path: "/docs/configuration",
name: "Configuration",
eq: (pathname: string) => pathname === "/docs/configuration",
},
],
Components: [],
};
Object.keys(docsModules).forEach((path) => {
const name = (path.split("/").pop() ?? "").replace(".mdx", "");
sideNav["Components"].push({
path: path.replace("./docs", "/docs").replace(".mdx", ""),
name: name.charAt(0).toUpperCase() + name.slice(1),
eq: (pathname: string) =>
pathname === path.replace("./docs", "/docs").replace(".mdx", ""),
});
});
export default {
mainNav,
sideNav,
};

View File

@ -1,118 +0,0 @@
import { forwardRef, useEffect, useState } from "react";
import SyntaxHighlighter from "react-syntax-highlighter";
import { gruvboxDark } from "react-syntax-highlighter/dist/cjs/styles/hljs";
import { Button } from "@components/Button";
import { useToast } from "@components/Toast";
import { twMerge } from "tailwind-merge";
export const GITHUB = "https://raw.githubusercontent.com/p-sw/ui/main";
export const LoadedCode = ({
from,
className,
}: {
from: string;
className?: string;
}) => {
const [state, setState] = useState<string | undefined | null>();
const { toast } = useToast();
useEffect(() => {
(async () => {
const res = await fetch(from);
const text = await res.text();
setState(text);
})();
}, [from]);
return (
<div className={twMerge("relative", className)}>
<Button
preset="default"
size="icon"
className="absolute top-4 right-4 text-black dark:text-white z-10"
onClick={() => {
if (state && state.length > 0) {
void navigator.clipboard.writeText(state ?? "");
toast({
title: "Copied",
description: "The code has been copied to your clipboard.",
status: "success",
});
} else {
toast({
title: "Error",
description: "It seems like code is not loaded yet.",
status: "error",
});
}
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M4 7v14h14v2H4c-1.1 0-2-.9-2-2V7zm16-4c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H8c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h3.18C11.6 1.84 12.7 1 14 1s2.4.84 2.82 2zm-6 0c-.55 0-1 .45-1 1s.45 1 1 1s1-.45 1-1s-.45-1-1-1m-4 4V5H8v12h12V5h-2v2z"
/>
</svg>
</Button>
<SyntaxHighlighter
language="typescript"
style={gruvboxDark}
className={`w-full h-64 rounded-lg ${!state ? "animate-pulse" : ""} scrollbar-none`}
customStyle={{ padding: "1rem" }}
>
{state ?? ""}
</SyntaxHighlighter>
</div>
);
};
export const Code = forwardRef<
HTMLDivElement,
{ children: string; className?: string; language: string }
>(({ children, className, language }, ref) => {
const { toast } = useToast();
return (
<div className={twMerge("relative", className)} ref={ref}>
<Button
preset="default"
size="icon"
className="absolute top-4 right-4 text-black dark:text-white z-10"
onClick={() => {
void navigator.clipboard.writeText(children ?? "");
toast({
title: "Copied",
description: "The code has been copied to your clipboard.",
status: "success",
});
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M4 7v14h14v2H4c-1.1 0-2-.9-2-2V7zm16-4c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H8c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2h3.18C11.6 1.84 12.7 1 14 1s2.4.84 2.82 2zm-6 0c-.55 0-1 .45-1 1s.45 1 1 1s1-.45 1-1s-.45-1-1-1m-4 4V5H8v12h12V5h-2v2z"
/>
</svg>
</Button>
<SyntaxHighlighter
language={language}
style={gruvboxDark}
className={`w-full h-auto max-h-64 rounded-lg scrollbar-none`}
customStyle={{ padding: "1rem" }}
>
{children}
</SyntaxHighlighter>
</div>
);
});

View File

@ -1,32 +0,0 @@
import React from "react";
import { twMerge } from "tailwind-merge";
const layoutClasses = {
default: "",
centered: "flex items-center justify-center",
};
const Story = React.forwardRef<
HTMLDivElement,
{
layout?: keyof typeof layoutClasses;
children: React.ReactNode;
className?: string;
id?: string;
}
>(({ layout = "default", children, className, id }, ref) => {
return (
<div
className={twMerge(
`bg-white dark:bg-black border border-neutral-300 dark:border-neutral-700 rounded-lg w-full p-4 min-h-48 h-auto my-8 not-prose ${layoutClasses[layout]}`,
className
)}
ref={ref}
id={id}
>
{children}
</div>
);
});
export { Story };

View File

@ -1,162 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { ButtonDemo } from "./ButtonBlocks/Preview";
import Examples from "./ButtonBlocks/Examples";
# Button
Displays a button or a component that looks like a button.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<ButtonDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Button.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Button.tsx`} />
## Usage
```tsx
import { Button } from "@components/Button";
```
```html
<Button>Button</Button>
```
## Props
### Variants
| Prop | Type | Default | Description |
|:-------------|:------------------------------------------------------------------------------|:------------|:----------------------------------------|
| `size` | `"link" \| "sm" \| "md" \| "lg" \| "icon"` | `"md"` | The size of the button |
| `border` | `"none" \| "solid" \| "success" \| "warning" \| "danger"` | `"solid"` | The border color of the button |
| `background` | `"default" \| "ghost" \| "success" \| "warning" \| "danger" \| "transparent"` | `"default"` | The background color of the button |
| `decoration` | `"none" \| "link"` | `"none"` | The inner text decoration of the button |
| `presets` | `"default" \| "ghost" \| "link" \| "success" \| "warning" \| "danger"` | `"default"` | The preset of the variant props |
### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:---------------------------------------------------------|
| `asChild` | `boolean` | `false` | Whether the button is rendered as a child of a component |
## Examples
### Default
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Default />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Examples/Default.tsx`} />
</TabContent>
</TabProvider>
### Ghost
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Ghost />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Examples/Ghost.tsx`} />
</TabContent>
</TabProvider>
### Link
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Link />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Examples/Link.tsx`} />
</TabContent>
</TabProvider>
### Success
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Success />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Examples/Success.tsx`} />
</TabContent>
</TabProvider>
### Warning
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Warning />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Examples/Warning.tsx`} />
</TabContent>
</TabProvider>
### Danger
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Danger />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ButtonBlocks/Examples/Danger.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export const Danger = () => {
return <Button preset="danger">Danger</Button>;
};

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export const Default = () => {
return <Button preset="default">Default</Button>;
};

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export const Ghost = () => {
return <Button preset="ghost">Ghost</Button>;
};

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export const Link = () => {
return <Button preset="link">Link</Button>;
};

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export const Success = () => {
return <Button preset="success">Success</Button>;
};

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export const Warning = () => {
return <Button preset="warning">Warning</Button>;
};

View File

@ -1,16 +0,0 @@
import { Danger } from "./Danger";
import { Warning } from "./Warning";
import { Success } from "./Success";
import { Link } from "./Link";
import { Ghost } from "./Ghost";
import { Default } from "./Default";
export default {
Danger,
Warning,
Success,
Link,
Ghost,
Default,
};

View File

@ -1,5 +0,0 @@
import { Button } from "@components/Button";
export function ButtonDemo() {
return <Button>Button</Button>;
}

View File

@ -1,84 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { CheckboxDemo } from "./CheckboxBlocks/Preview";
import Examples from "./CheckboxBlocks/Examples";
# Checkbox
A control that allows the user to toggle between checked and not checked.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<CheckboxDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/CheckboxBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Checkbox.mdx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Checkbox.tsx`} />
## Usage
```tsx
import { Checkbox } from "@components/Checkbox";
```
```html
<Checkbox />
```
## Props
### Variants
| Prop | Type | Default | Description |
|:-------|:-------------------------|:--------|:-------------------------|
| `size` | `"base" \| "md" \| "lg"` | `"md"` | The size of the checkbox |
## Examples
### Text
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Text />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/CheckboxBlocks/Examples/Text.tsx`} />
</TabContent>
</TabProvider>
### Disabled
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Disabled />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/CheckboxBlocks/Examples/Disabled.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Checkbox } from "@components/Checkbox";
export function Disabled() {
return (
<Label direction="horizontal">
<Checkbox size="base" disabled />
<span>Agree terms and conditions</span>
</Label>
);
}

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Checkbox } from "@components/Checkbox";
export function Text() {
return (
<Label direction="horizontal">
<Checkbox size="base" />
<span>Agree terms and conditions</span>
</Label>
);
}

View File

@ -1,5 +0,0 @@
import { Text } from "./Text";
import { Disabled } from "./Disabled";
export default { Text, Disabled };

View File

@ -1,11 +0,0 @@
import { Checkbox } from "@components/Checkbox";
import { Label } from "@components/Label";
export function CheckboxDemo() {
return (
<Label direction="horizontal">
<Checkbox />
<span>Checkbox</span>
</Label>
);
}

View File

@ -1,177 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { DialogDemo } from "./DialogBlocks/Preview";
import Examples from "./DialogBlocks/Examples";
# Dialog
A modal window that prompts the user to take an action or provides critical information.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<DialogDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DialogBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Dialog.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Dialog.tsx`} />
## Usage
```tsx
import {
DialogRoot,
DialogTrigger,
DialogOverlay,
DialogContent,
DialogHeader,
DialogTitle,
DialogSubtitle,
DialogFooter,
DialogClose,
} from "@components/Dialog";
```
```html
<DialogRoot>
<DialogTrigger>
<Button>Open Dialog</Button>
</DialogTrigger>
<DialogOverlay>
<DialogContent>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogSubtitle>Dialog Subtitle</DialogSubtitle>
</DialogHeader>
{/* Main Contents */}
<DialogFooter>
<DialogClose>
<Button>Close</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</DialogOverlay>
</DialogRoot>
```
> Note:
>
> DialogTrigger and DialogClose will merge its onClick event handler to its children.
> Also, there is no default element for those.
> So you always have to provide the clickable children for DialogTrigger and DialogClose.
>
> It is easier to understand if you think of this component as always having the `asChild` prop applied to it.
## Props
### DialogOverlay
#### Variants
| Prop | Type | Default | Description |
|:----------|:-----------------------|:--------|:---------------------------------------------|
| `blur` | `"sm" \| "md" \| "lg"` | `md` | Whether the background of dialog is blurred |
| `darken` | `"sm" \| "md" \| "lg"` | `md` | Whether the background of dialog is darkened |
| `padding` | `"sm" \| "md" \| "lg"` | `md` | Minimum margin of the dialog |
#### Special
| Prop | Type | Default | Description |
|:---------------|:----------|:--------|:-----------------------------------------------|
| `closeOnClick` | `boolean` | `false` | Whether the dialog will be closed when clicked |
### DialogContent
#### Variants
| Prop | Type | Default | Description |
|:----------|:---------------------------------------------------------------------|:--------|:-----------------------------------------------|
| `size` | `"fit" \| "fullSm" \| "fullMd" \| "fullLg" \| "fullXl" \| "full2xl"` | `fit` | Size of the dialog - width and max width |
| `rounded` | `"sm" \| "md" \| "lg" \| "xl"` | `md` | Roundness of the dialog |
| `padding` | `"sm" \| "md" \| "lg"` | `md` | Padding of the dialog |
| `gap` | `"sm" \| "md" \| "lg"` | `md` | Works like flex's gap - space between children |
### DialogHeader
#### Variants
| Prop | Type | Default | Description |
|:------|:-----------------------|:--------|:----------------------------------------------|
| `gap` | `"sm" \| "md" \| "lg"` | `sm` | Gap between the children - title and subtitle |
### DialogTitle
#### Variants
| Prop | Type | Default | Description |
|:---------|:-----------------------|:--------|:--------------------|
| `size` | `"sm" \| "md" \| "lg"` | `md` | Size of the title |
| `weight` | `"sm" \| "md" \| "lg"` | `lg` | Weight of the title |
### DialogSubtitle
#### Variants
| Prop | Type | Default | Description |
|:----------|:-----------------------|:--------|:------------------------|
| `size` | `"sm" \| "md" \| "lg"` | `sm` | Size of the subtitle |
| `weight` | `"sm" \| "md" \| "lg"` | `md` | Weight of the subtitle |
| `opacity` | `"sm" \| "md" \| "lg"` | `sm` | Opacity of the subtitle |
### DialogFooter
#### Variants
| Prop | Type | Default | Description |
|:------|:-----------------------|:--------|:-------------------------|
| `gap` | `"sm" \| "md" \| "lg"` | `sm` | Gap between the children |
## Examples
### Basic Informational Dialog
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.BasicInformationalDialog />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DialogBlocks/Examples/BasicInformationalDialog.tsx`} />
</TabContent>
</TabProvider>
### Deleting Item
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.DeletingItem />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DialogBlocks/Examples/DeletingItem.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,36 +0,0 @@
import { Button } from "@components/Button";
import {
DialogRoot,
DialogTrigger,
DialogOverlay,
DialogContent,
DialogHeader,
DialogTitle,
DialogSubtitle,
DialogFooter,
DialogClose,
} from "@components/Dialog";
export function BasicInformationalDialog() {
return (
<DialogRoot>
<DialogTrigger>
<Button preset="default">What is this?</Button>
</DialogTrigger>
<DialogOverlay>
<DialogContent size={"fullMd"}>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogSubtitle>Dialog Subtitle</DialogSubtitle>
</DialogHeader>
<p>This is a dialog. You can put the information you want to show.</p>
<DialogFooter>
<DialogClose>
<Button preset="default">Ok!</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</DialogOverlay>
</DialogRoot>
);
}

View File

@ -1,79 +0,0 @@
import {
DialogRoot,
DialogTrigger,
DialogOverlay,
DialogContent,
DialogHeader,
DialogTitle,
DialogSubtitle,
DialogFooter,
DialogClose,
} from "@components/Dialog";
import { Button } from "@components/Button";
import { useToast } from "@components/Toast";
export function DeletingItem() {
const { toast } = useToast();
return (
<DialogRoot>
<DialogTrigger>
<Button preset="danger">Delete Item</Button>
</DialogTrigger>
<DialogOverlay>
<DialogContent size={"fullMd"}>
<DialogHeader>
<DialogTitle>Delete Item</DialogTitle>
<DialogSubtitle>
Are you sure you want to delete this item?
</DialogSubtitle>
</DialogHeader>
<div className="flex flex-col gap-3">
<ul className="list-disc list-inside">
<li>This action will delete the item, and related data</li>
<li>This action cannot be undone</li>
</ul>
</div>
<DialogFooter>
<DialogClose>
<Button
preset="danger"
onClick={async () => {
const toasted = toast({
title: "Deleting Item",
description: "Item deletion is requested",
status: "loading",
});
await new Promise((r) => setTimeout(r, 1000));
toasted.update({
title: "Item Deleted",
description: "The item has been deleted",
status: "success",
});
}}
>
Delete
</Button>
</DialogClose>
<DialogClose>
<Button
preset="default"
onClick={() => {
toast({
title: "Action Canceled",
description: "The delete action has been canceled",
status: "error",
});
}}
>
Cancel
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</DialogOverlay>
</DialogRoot>
);
}

View File

@ -1,8 +0,0 @@
import { BasicInformationalDialog } from "./BasicInformationalDialog";
import { DeletingItem } from "./DeletingItem";
export default {
BasicInformationalDialog,
DeletingItem,
}

View File

@ -1,42 +0,0 @@
import {
DialogRoot,
DialogTrigger,
DialogOverlay,
DialogContent,
DialogHeader,
DialogTitle,
DialogSubtitle,
DialogFooter,
DialogClose,
} from "@components/Dialog";
import { Button } from "@components/Button";
export function DialogDemo() {
return (
<DialogRoot>
<DialogTrigger>
<Button preset="default">Open Dialog</Button>
</DialogTrigger>
<DialogOverlay>
<DialogContent size={"fullMd"}>
<DialogHeader>
<DialogTitle>Dialog Title</DialogTitle>
<DialogSubtitle>Dialog Subtitle</DialogSubtitle>
</DialogHeader>
<p>
Laborum non adipisicing enim enim culpa esse anim esse consequat
Lorem incididunt. Enim mollit laborum sunt cillum voluptate est
officia nostrud non consequat adipisicing cupidatat aliquip magna.
Voluptate nisi cupidatat qui nisi in pariatur. Sint consequat labore
pariatur mollit sint nostrud tempor commodo pariatur ea laboris.
</p>
<DialogFooter>
<DialogClose>
<Button preset="default">Close</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</DialogOverlay>
</DialogRoot>
);
}

View File

@ -1,203 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from '@/components/LoadedCode';
import { DrawerDemo } from "./DrawerBlocks/Preview";
import Examples from "./DrawerBlocks/Examples";
# Drawer
Displays a panel that slides out from the edge of the screen, typically used for navigation or additional content.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<DrawerDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DrawerBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Drawer.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Drawer.tsx`} />
## Usage
```tsx
import {
DrawerRoot,
DrawerTrigger,
DrawerOverlay,
DrawerContent,
DrawerClose,
DrawerHeader,
DrawerBody,
DrawerFooter,
} from "@components/Drawer";
```
```html
<DrawerRoot>
<DrawerTrigger>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerOverlay>
<DrawerContent>
<DrawerHeader>
<h1 className="text-2xl font-bold">Drawer</h1>
</DrawerHeader>
<DrawerBody>
{/* Main Contents */}
</DrawerBody>
<DrawerFooter>
<DrawerClose>
<Button>Close Drawer</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
```
> Note:
>
> DrawerTrigger and DrawerClose will merge its onClick event handler to its children.
> Also, there is no default element for those.
> So you always have to provide the clickable children for DialogTrigger and DialogClose.
>
> It is easier to understand if you think of this component as always having the `asChild` prop applied to it.
## Props
### DrawerRoot
#### Special
| Prop | Type | Default | Description |
|:-----------------|:----------|:---------------|:----------------------------------------------------------|
| `closeThreshold` | `number` | `0.3` | The threshold for the drawer to close with swipe or drag. |
| `opened` | `boolean` | - (Controlled) | Whether the drawer is opened. |
### DrawerOverlay
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:------------------------------------------------------------|
| `asChild` | `boolean` | `false` | Whether the component is rendered as a child of a component |
### DrawerContent
#### Variants
| Prop | Type | Default | Description |
|:-----------|:-----------------------------------------|:---------|:---------------------------|
| `position` | `"top" \| "bottom" \| "left" \| "right"` | `"left"` | The position of the drawer |
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:------------------------------------------------------------|
| `asChild` | `boolean` | `false` | Whether the component is rendered as a child of a component |
### DrawerHeader
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:------------------------------------------------------------|
| `asChild` | `boolean` | `false` | Whether the component is rendered as a child of a component |
### DrawerBody
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:------------------------------------------------------------|
| `asChild` | `boolean` | `false` | Whether the component is rendered as a child of a component |
### DrawerFooter
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:------------------------------------------------------------|
| `asChild` | `boolean` | `false` | Whether the component is rendered as a child of a component |
## Examples
### Left
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Left />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DrawerBlocks/Examples/Left.tsx`} />
</TabContent>
</TabProvider>
### Right
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Right />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DrawerBlocks/Examples/Right.tsx`} />
</TabContent>
</TabProvider>
### Top
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Top />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DrawerBlocks/Examples/Top.tsx`} />
</TabContent>
</TabProvider>
### Bottom
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Bottom />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/DrawerBlocks/Examples/Bottom.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,40 +0,0 @@
import {
DrawerRoot,
DrawerTrigger,
DrawerOverlay,
DrawerContent,
DrawerHeader,
DrawerBody,
DrawerFooter,
DrawerClose,
} from "@components/Drawer";
import { Button } from "@components/Button";
export const Bottom = () => {
return (
<DrawerRoot>
<DrawerTrigger>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerOverlay className="z-[99]">
<DrawerContent position="bottom">
<DrawerHeader>
<h1 className="text-2xl font-bold">Drawer</h1>
</DrawerHeader>
<DrawerBody>
<p>
Drawers are a type of overlay that slides in from the edge of the
screen. They are typically used for navigation or additional
content.
</p>
</DrawerBody>
<DrawerFooter>
<DrawerClose>
<Button>Done</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
);
};

View File

@ -1,40 +0,0 @@
import {
DrawerRoot,
DrawerTrigger,
DrawerOverlay,
DrawerContent,
DrawerHeader,
DrawerBody,
DrawerFooter,
DrawerClose,
} from "@components/Drawer";
import { Button } from "@components/Button";
export const Left = () => {
return (
<DrawerRoot>
<DrawerTrigger>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerOverlay className="z-[99]">
<DrawerContent position="left" className="max-w-[320px]">
<DrawerHeader>
<h1 className="text-2xl font-bold">Drawer</h1>
</DrawerHeader>
<DrawerBody>
<p>
Drawers are a type of overlay that slides in from the edge of the
screen. They are typically used for navigation or additional
content.
</p>
</DrawerBody>
<DrawerFooter>
<DrawerClose>
<Button>Done</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
);
};

View File

@ -1,40 +0,0 @@
import {
DrawerRoot,
DrawerTrigger,
DrawerOverlay,
DrawerContent,
DrawerHeader,
DrawerBody,
DrawerFooter,
DrawerClose,
} from "@components/Drawer";
import { Button } from "@components/Button";
export const Right = () => {
return (
<DrawerRoot>
<DrawerTrigger>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerOverlay className="z-[99]">
<DrawerContent position="right" className="max-w-[320px]">
<DrawerHeader>
<h1 className="text-2xl font-bold">Drawer</h1>
</DrawerHeader>
<DrawerBody>
<p>
Drawers are a type of overlay that slides in from the edge of the
screen. They are typically used for navigation or additional
content.
</p>
</DrawerBody>
<DrawerFooter>
<DrawerClose>
<Button>Done</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
);
};

View File

@ -1,40 +0,0 @@
import {
DrawerRoot,
DrawerTrigger,
DrawerOverlay,
DrawerContent,
DrawerHeader,
DrawerBody,
DrawerFooter,
DrawerClose,
} from "@components/Drawer";
import { Button } from "@components/Button";
export const Top = () => {
return (
<DrawerRoot>
<DrawerTrigger>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerOverlay className="z-[99]">
<DrawerContent position="top">
<DrawerHeader>
<h1 className="text-2xl font-bold">Drawer</h1>
</DrawerHeader>
<DrawerBody>
<p>
Drawers are a type of overlay that slides in from the edge of the
screen. They are typically used for navigation or additional
content.
</p>
</DrawerBody>
<DrawerFooter>
<DrawerClose>
<Button>Done</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
);
};

View File

@ -1,7 +0,0 @@
import { Left } from "./Left";
import { Right } from "./Right";
import { Top } from "./Top";
import { Bottom } from "./Bottom";
export default { Left, Right, Top, Bottom };

View File

@ -1,40 +0,0 @@
import { Button } from "@components/Button";
import {
DrawerRoot,
DrawerTrigger,
DrawerOverlay,
DrawerContent,
DrawerClose,
DrawerHeader,
DrawerBody,
DrawerFooter,
} from "@components/Drawer";
export const DrawerDemo = () => {
return (
<DrawerRoot>
<DrawerTrigger>
<Button>Open Drawer</Button>
</DrawerTrigger>
<DrawerOverlay className="z-[99]">
<DrawerContent className="max-w-[320px]">
<DrawerHeader>
<h1 className="text-2xl font-bold">Drawer</h1>
</DrawerHeader>
<DrawerBody>
<p>
Drawers are a type of overlay that slides in from the edge of the
screen. They are typically used for navigation or additional
content.
</p>
</DrawerBody>
<DrawerFooter>
<DrawerClose>
<Button>Close</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</DrawerOverlay>
</DrawerRoot>
);
};

View File

@ -1,123 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { InputDemo } from "./InputBlocks/Preview";
import { InputFrameDemo } from "./InputFrameBlocks/Preview";
import InputExamples from "./InputBlocks/Examples";
# Input
Element that captures user's input.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<InputDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/InputBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Input.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Input.tsx`} />
## Usage
```tsx
import { Input } from "@components/Input";
```
```html
<Input type="text" />
```
## Props
### Variants
| Prop | Type | Default | Description |
|:-----------|:----------|:--------|:-----------------------------------------------------------------------------------------|
| `unstyled` | `boolean` | `false` | Remove style of input, so it can be real transparent input. Mostly used with InputFrame. |
| `full` | `boolean` | `false` | Make input take full width of its container. |
## Examples
### Invalid
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<InputExamples.Invalid />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/InputBlocks/Examples/Invalid.tsx`} />
</TabContent>
</TabProvider>
### Disabled
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<InputExamples.Disabled />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/InputBlocks/Examples/Disabled.tsx`} />
</TabContent>
</TabProvider>
# InputFrame
Label with input's style.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<InputFrameDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/InputFrameBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
**Included in `Input.tsx`.**
## Usage
```tsx
import {
Input,
InputFrame,
} from "@components/Input";
```
```html
<InputFrame>
<Input type="text" unstyled />
</InputFrame>
```

View File

@ -1,5 +0,0 @@
import { Input } from "@components/Input";
export function Disabled() {
return <Input type="text" disabled />;
}

View File

@ -1,5 +0,0 @@
import { Input } from "@components/Input";
export function Invalid() {
return <Input type="text" invalid="Invalid Input" />;
}

View File

@ -1,5 +0,0 @@
import { Invalid } from "./Invalid";
import { Disabled } from "./Disabled";
export default { Invalid, Disabled };

View File

@ -1,5 +0,0 @@
import { Input } from "@components/Input";
export function InputDemo() {
return <Input type="text" />;
}

View File

@ -1,23 +0,0 @@
import { Button } from "@components/Button";
import { Input, InputFrame } from "@components/Input";
export function InputFrameDemo() {
return (
<InputFrame>
<Input type="text" unstyled />
<Button preset="success" size="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5l-1.5 1.5l-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16A6.5 6.5 0 0 1 3 9.5A6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14S14 12 14 9.5S12 5 9.5 5"
/>
</svg>
</Button>
</InputFrame>
);
}

View File

@ -1,125 +0,0 @@
import {
TabProvider, TabTrigger, TabContent, TabList
} from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { LabelDemo } from "./LabelBlocks/Preview";
import Examples from "./LabelBlocks/Examples"
# Label
A wrapper that used to tag and describe form elements clearly and accessibly.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<LabelDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/LabelBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Label.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Label.tsx`} />
## Usage
```tsx
import { Label } from "@components/Label"
```
```html
<Label>
<input />
</Label>
<Label htmlFor="input">Label</Label>
<input id="input" />
```
## Props
### Variants
| Prop | Type | Default | Description |
|:------------|:-----------------------------|:-------------|:----------------------------|
| `direction` | `"vertical" \| "horizontal"` | `"vertical"` | The direction of the label. |
## Examples
### Vertical
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Vertical />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/LabelBlocks/Examples/Vertical.tsx`} />
</TabContent>
</TabProvider>
### Horizontal
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Horizontal />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/LabelBlocks/Examples/Horizontal.tsx`} />
</TabContent>
</TabProvider>
### Invalid
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Invalid />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/LabelBlocks/Examples/Invalid.tsx`} />
</TabContent>
</TabProvider>
### Disabled
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Disabled />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/LabelBlocks/Examples/Disabled.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Input } from "@components/Input";
export function Disabled() {
return (
<Label direction="vertical">
<span>Email</span>
<Input type="email" disabled />
</Label>
);
}

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Checkbox } from "@components/Checkbox";
export function Horizontal() {
return (
<Label direction="horizontal">
<Checkbox />
<span>Checkbox</span>
</Label>
);
}

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Input } from "@components/Input";
export function Invalid() {
return (
<Label direction="vertical">
<span>Email</span>
<Input type="email" invalid="Invalid Email" />
</Label>
);
}

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Input } from "@components/Input";
export function Vertical() {
return (
<Label direction="vertical">
<span>Email</span>
<Input type="email" />
</Label>
);
}

View File

@ -1,12 +0,0 @@
import { Vertical } from "./Vertical";
import { Horizontal } from "./Horizontal";
import { Invalid } from "./Invalid";
import { Disabled } from "./Disabled";
export default {
Vertical,
Horizontal,
Invalid,
Disabled,
};

View File

@ -1,11 +0,0 @@
import { Label } from "@components/Label";
import { Input } from "@components/Input";
export function LabelDemo() {
return (
<Label direction="vertical">
<span>Email</span>
<Input type="email" />
</Label>
);
}

View File

@ -1,117 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { PopoverDemo } from "./PopoverBlocks/Preview";
import Examples from "./PopoverBlocks/Examples";
# Popover
Displays rich content in a portal, triggered by a button.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<PopoverDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/PopoverBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Popover.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Popover.tsx`} />
## Usage
```tsx
import { Popover, PopoverTrigger, PopoverContent } from "@components/popover"
```
```html
<Popover>
<PopoverTrigger>
<Button />
</PopoverTrigger>
<PopoverContent>
{/* content of popover */}
</PopoverContent>
</Popover
```
> Note:
>
> PopoverTrigger will merge its onClick event handler to its children.
> Also, there is no default element for those.
> So you always have to provide the clickable children for PopoverTrigger.
>
> It is easier to understand if you think of this component as always having the `asChild` prop applied to it.
## Props
### Popover
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:------------------------------------------------------------------|
| `opened` | `boolean` | `false` | Initial open state |
| `asChild` | `boolean` | `false` | Whether the root of popover is rendered as a child of a component |
### PopoverContent
#### Variants
| Prop | Type | Default | Description |
|:---------|:-------------------------------------------------------------------------|:-----------------|:--------------------------------|
| `anchor` | `` `${"top" \| "middle" \| "bottom"}${"Left" \| "Center" \| "Right"}` `` | `"bottomCenter"` | Position of Popover content |
| `offset` | `"sm" \| "md" \| "lg"` | `"md"` | Gap between trigger and popover |
#### Special
| Prop | Type | Default | Description |
|:----------|:----------|:--------|:--------------------------------------------------------------------------------|
| `asChild` | `boolean` | `false` | `Whether the container of popover content is rendered as a child of a component |
## Examples
### Theme Selector
<TabProvider defaultName={"preview"}>
<TabList>
<TabTrigger name={"preview"}>Preview</TabTrigger>
<TabTrigger name={"code"}>Code</TabTrigger>
</TabList>
<TabContent name={"preview"}>
<Story layout={"centered"}>
<Examples.ThemeSelector />
</Story>
</TabContent>
<TabContent name={"code"}>
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/PopoverBlocks/Examples/ThemeSelector.tsx`} />
</TabContent>
</TabProvider>
### User Control
<TabProvider defaultName={"preview"}>
<TabList>
<TabTrigger name={"preview"}>Preview</TabTrigger>
<TabTrigger name={"code"}>Code</TabTrigger>
</TabList>
<TabContent name={"preview"}>
<Story layout={"centered"}>
<Examples.UserControl />
</Story>
</TabContent>
<TabContent name={"code"}>
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/PopoverBlocks/Examples/UserControl.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,43 +0,0 @@
import { Popover, PopoverTrigger, PopoverContent } from "@components/Popover.tsx";
import { Button } from "@components/Button.tsx";
import { useState } from "react";
const DarkIcon = () => {
// ic:baseline-dark-mode
return <svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24">
<path fill="currentColor"
d="M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26a5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1"/>
</svg>
}
const LightIcon = () => {
// ic:baseline-light-mode
return <svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 24 24">
<path fill="currentColor"
d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5s5-2.24 5-5s-2.24-5-5-5M2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1m18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1M11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1m0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1M5.99 4.58a.996.996 0 0 0-1.41 0a.996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41zm12.37 12.37a.996.996 0 0 0-1.41 0a.996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41zm1.06-10.96a.996.996 0 0 0 0-1.41a.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0zM7.05 18.36a.996.996 0 0 0 0-1.41a.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0z"/>
</svg>
}
export const ThemeSelector = () => {
const [theme, setTheme] = useState<"light" | "dark">("dark");
return <Popover>
<PopoverTrigger>
<Button preset={"default"} size={"icon"}>
{
theme === "light" ? <LightIcon /> : <DarkIcon />
}
</Button>
</PopoverTrigger>
<PopoverContent anchor={"bottomCenter"}>
<Button onClick={() => setTheme("dark")} preset={"ghost"} className={"gap-2"}>
<DarkIcon />
<span className={"whitespace-nowrap"}>Dark Mode</span>
</Button>
<Button onClick={() => setTheme("light")} preset={"ghost"} className={"gap-2"}>
<LightIcon />
<span className={"whitespace-nowrap"}>Light Mode</span>
</Button>
</PopoverContent>
</Popover>
}

View File

@ -1,151 +0,0 @@
import {
Popover,
PopoverTrigger,
PopoverContent,
} from "@components/Popover.tsx";
import { Button } from "@components/Button.tsx";
import { useToast } from "@components/Toast.tsx";
import {
createContext,
Dispatch,
SetStateAction,
SVGProps,
useContext,
useState,
useTransition,
} from "react";
import { Label } from "@components/Label.tsx";
import { Input } from "@components/Input.tsx";
interface UserControlState {
signIn: boolean;
}
const initialState: UserControlState = {
signIn: false,
};
const UserControlContext = createContext<
[UserControlState, Dispatch<SetStateAction<UserControlState>>]
>([initialState, () => {}]);
const logInServerAction = async () => {
return new Promise((r) => setTimeout(r, 2000));
};
const logOutServerAction = async () => {
return new Promise((r) => setTimeout(r, 1000));
};
function MdiLoading(props: SVGProps<SVGSVGElement>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
{...props}
>
<path
fill="currentColor"
d="M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8"
></path>
</svg>
);
}
const SignInForm = () => {
const [isSigningIn, setIsSigningIn] = useState(false);
const transition = useTransition();
const [_, setState] = useContext(UserControlContext);
const { toast } = useToast();
function startSignIn() {
transition[1](() => {
setIsSigningIn(true);
const toasted = toast({
title: "Logging In...",
description: "Please wait until server responses",
status: "loading",
});
logInServerAction().then(() => {
toasted.update({
title: "Log In Success",
description: "Successfully logged in!",
status: "success",
});
setIsSigningIn(false);
setState((prev) => ({ ...prev, signIn: true }));
});
});
}
return (
<PopoverContent anchor={"bottomLeft"} className={"p-4 space-y-3"}>
<Label>
<span>Username</span>
<Input type={"text"} />
</Label>
<Label>
<span>Password</span>
<Input type={"password"} />
</Label>
<div className={"flex flex-row justify-end"}>
<Button preset={"success"} onClick={startSignIn}>
{isSigningIn ? <MdiLoading className={"animate-spin"} /> : "Sign In"}
</Button>
</div>
</PopoverContent>
);
};
const UserControlContent = () => {
const [isSigningOut, setIsSigningOut] = useState(false);
const transition = useTransition();
const [_, setState] = useContext(UserControlContext);
const { toast } = useToast();
function startSignOut() {
transition[1](() => {
setIsSigningOut(true);
const toasted = toast({
title: "Logging Out",
description: "Please wait until server responses",
status: "loading",
});
logOutServerAction().then(() => {
toasted.update({
title: "Log Out Success",
description: "Successfully logged out!",
status: "success",
});
setIsSigningOut(false);
setState((prev) => ({ ...prev, signIn: false }));
});
});
}
return (
<PopoverContent anchor={"bottomLeft"}>
<Button preset={"ghost"}>Dashboard</Button>
<Button preset={"ghost"} onClick={startSignOut}>
{isSigningOut ? <MdiLoading className={"animate-spin"} /> : "Sign Out"}
</Button>
</PopoverContent>
);
};
export const UserControl = () => {
const [state, setState] = useState<UserControlState>({
signIn: false,
});
return (
<Popover>
<PopoverTrigger>
<Button>{state.signIn ? "Log Out" : "Log In"}</Button>
</PopoverTrigger>
<UserControlContext.Provider value={[state, setState]}>
{state.signIn ? <UserControlContent /> : <SignInForm />}
</UserControlContext.Provider>
</Popover>
);
};

View File

@ -1,7 +0,0 @@
import { ThemeSelector } from "./ThemeSelector";
import { UserControl } from "./UserControl";
export default {
ThemeSelector,
UserControl,
}

View File

@ -1,54 +0,0 @@
import { Button } from "@components/Button";
import { Popover, PopoverContent, PopoverTrigger } from "@components/Popover";
export function PopoverDemo() {
return (
<Popover>
<PopoverTrigger>
<Button size="icon">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M12 4a4 4 0 0 1 4 4a4 4 0 0 1-4 4a4 4 0 0 1-4-4a4 4 0 0 1 4-4m0 10c4.42 0 8 1.79 8 4v2H4v-2c0-2.21 3.58-4 8-4"
/>
</svg>
</Button>
</PopoverTrigger>
<PopoverContent>
<Button preset="ghost" className="gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"
/>
</svg>
<span className="flex-grow text-left">Dashboard</span>
</Button>
<Button preset="ghost" className="gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="m17 7l-1.41 1.41L18.17 11H8v2h10.17l-2.58 2.58L17 17l5-5M4 5h8V3H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h8v-2H4z"
/>
</svg>
<span className="flex-grow text-left">Log out</span>
</Button>
</PopoverContent>
</Popover>
);
}

View File

@ -1,40 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { SwitchDemo } from "./SwitchBlocks/Preview";
# Switch
Toggle between two states with a sleek design. Perfect for enabling/disabling options.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<SwitchDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/SwitchBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Switch.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Switch.tsx`} />
## Usage
```tsx
import { Switch } from "@components/Switch";
```
```html
<Switch />
```

View File

@ -1,5 +0,0 @@
import { Switch } from "@components/Switch";
export function SwitchDemo() {
return <Switch />;
}

View File

@ -1,79 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { TabsDemo } from "./TabsBlocks/Preview";
# Tabs
Organizes content into multiple sections with tabbed navigation.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered" className="flex-col [&>*]:w-full">
<TabsDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TabsBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Tabs.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Tabs.tsx`} />
## Usage
```tsx
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
```
```html
<TabProvider defaultName="tab1">
<TabList>
<TabTrigger name="tab1">Tab 1</TabTrigger>
<TabTrigger name="tab2">Tab 2</TabTrigger>
</TabList>
<TabContent name="tab1">
<div>Tab 1 Content</div>
</TabContent>
<TabContent name="tab2">
<div>Tab 2 Content</div>
</TabContent>
</TabProvider>
```
> Note:
>
> TabContent requires a element as children.
> There is no default element in the tab, so you have to provide it.
## Props
### TabProvider
#### Special
| Name | Type | Default | Description |
|:--------------|:---------|:-----------------|:---------------------------------------------|
| `defaultName` | `string` | - (**required**) | The name of the tab to be active by default. |
### TabTrigger
#### Special
| Name | Type | Default | Description |
|:----------|:----------|:-----------------|:----------------------------------------------------------|
| `name` | `string` | - (**required**) | The name of the tab. |
| `asChild` | `boolean` | `false` | Whether the element is rendered as a child of a component |
### TabContent
#### Special
| Name | Type | Default | Description |
|:-------|:---------|:-----------------|:---------------------|
| `name` | `string` | - (**required**) | The name of the tab. |

View File

@ -1,18 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
export function TabsDemo() {
return (
<TabProvider defaultName="tab1">
<TabList>
<TabTrigger name="tab1">Tab 1</TabTrigger>
<TabTrigger name="tab2">Tab 2</TabTrigger>
</TabList>
<TabContent name="tab1">
<div className="w-full text-center">Tab 1 Content</div>
</TabContent>
<TabContent name="tab2">
<div className="w-full text-center">Tab 2 Content</div>
</TabContent>
</TabProvider>
);
}

View File

@ -1,182 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs"
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { ToastDemo } from "./ToastBlocks/Preview";
import Examples from "./ToastBlocks/Examples";
# Toast
A brief message alert to inform users about events or actions.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<ToastDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Toast.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Toast.tsx`} />
## Usage
```tsx
import { Toaster } from "@components/Toast";
```
```html
<Toaster />
```
> Note:
>
> You can put Toaster in anywhere. It will automatically go to document.body through portal.
> But, it is recommended to place it at the root of the application, just once.
---
```tsx
import { useToast } from "@components/Toast";
function App() {
const { toast } = useToast();
return <button onClick={() => toast("Hello, world!")}>Toast</button>;
}
```
## Props
### Toaster
#### Special
| Prop | Type | Default | Description |
|:----------------|:-----------------------|:---------------------|:--------------------------|
| `defaultOption` | `Partial<ToastOption>` | `defaultToastOption` | Global options for toast. |
```ts
interface ToastOption {
closeButton: boolean;
closeTimeout: number | null;
}
const defaultToastOption: ToastOption = {
closeButton: true,
closeTimeout: 3000,
};
```
## Examples
### Normal
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Normal />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
### Success
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Success />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
### Error
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Error />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
### Warning
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Warning />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
### Pending - Fail
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.PendingFail />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
### Pending - Success
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.PendingSuccess />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/ToastBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,29 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={() =>
toast({
title: "Toast Title",
description: "Toast Description",
status: "error",
})
}
>
Toast
</Button>
);
}
export function Error() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,29 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={() =>
toast({
title: "Toast Title",
description: "Toast Description",
status: "default",
})
}
>
Toast
</Button>
);
}
export function Normal() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,35 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={async () => {
const toasted = toast({
title: "Waiting...",
description: "Waiting for result...",
status: "loading",
});
await new Promise((r) => setTimeout(r, 1000));
toasted.update({
title: "Promise Failed",
description: "Something went wrong!",
status: "error",
});
}}
>
Toast
</Button>
);
}
export function PendingFail() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,37 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={async () => {
const toasted = toast({
title: "Waiting...",
description: "Waiting for result...",
status: "loading",
});
await new Promise((r) => setTimeout(r, 1000));
toasted.update({
title: "Promise Success",
description: "Promise resolved!",
status: "success",
});
}}
>
Toast
</Button>
);
}
export function PendingSuccess() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,29 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={() =>
toast({
title: "Toast Title",
description: "Toast Description",
status: "success",
})
}
>
Toast
</Button>
);
}
export function Success() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,29 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={() =>
toast({
title: "Toast Title",
description: "Toast Description",
status: "warning",
})
}
>
Toast
</Button>
);
}
export function Warning() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,16 +0,0 @@
import { Error } from "./Error";
import { Normal } from "./Normal";
import { PendingFail } from "./PendingFail";
import { PendingSuccess } from "./PendingSuccess";
import { Success } from "./Success";
import { Warning } from "./Warning";
export default {
Error,
Normal,
PendingFail,
PendingSuccess,
Success,
Warning,
};

View File

@ -1,25 +0,0 @@
import { Button } from "@components/Button";
import { Toaster, useToast } from "@components/Toast";
function Children() {
const { toast } = useToast();
return (
<Button
onClick={() =>
toast({ title: "Toast Title", description: "Toast Description" })
}
>
Toast
</Button>
);
}
export function ToastDemo() {
return (
<>
<Toaster />
<Children />
</>
);
}

View File

@ -1,206 +0,0 @@
import { TabProvider, TabTrigger, TabContent, TabList } from "@components/Tabs";
import { Story } from "@/components/Story";
import { LoadedCode, GITHUB } from "@/components/LoadedCode";
import { TooltipDemo } from "./TooltipBlocks/Preview";
import Examples from "./TooltipBlocks/Examples";
# Tooltip
A brief helper for providing contextual information or guiding user interactions.
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<TooltipDemo />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Preview.tsx`} />
</TabContent>
</TabProvider>
## Installation
1. Create a new file `Tooltip.tsx` in your component folder.
2. Copy and paste the following code into the file.
<LoadedCode from={`${GITHUB}/packages/react/components/Tooltip.tsx`} />
## Usage
```tsx
import { Tooltip, TooltipContent } from "@components/Tooltip";
```
```html
<Tooltip>
<TooltipContent>
{/* Tooltip Content */}
</TooltipContent>
{/* Tooltip Trigger */}
</Tooltip>
```
## Props
### Tooltip
#### Variants
| Prop | Type | Default | Description |
|:-------------|:-----------------------------------------|:--------|:----------------------------------------|
| `position` | `"bottom" \| "left" \| "right" \| "top"` | `"top"` | The position of the tooltip. |
| `controlled` | `boolean` | `false` | Blocks tooltip triggered by hover state |
| `opened` | `boolean` | `false` | Forces to be opened |
### TooltipContent
#### Variants
| Prop | Type | Default | Description |
|:---------|:------------------------------------------------|:-----------|:---------------------------------------------------|
| `offset` | `"sm" \| "md" \| "lg"` | `"md"` | Gap between the tooltip and the trigger. |
| `delay` | `"none" \| "early" \| "normal" \| "late"` | `"normal"` | The time between hover start and appear of tooltip |
| `status` | `"normal" \| "error" \| "success" \| "warning"` | `"normal"` | Color of tooltip |
## Examples
### Top
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Top />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/Top.tsx`} />
</TabContent>
</TabProvider>
### Bottom
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Bottom />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/Bottom.tsx`} />
</TabContent>
</TabProvider>
### Left
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Left />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/Left.tsx`} />
</TabContent>
</TabProvider>
### Right
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name="preview">Preview</TabTrigger>
<TabTrigger name="code">Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.Right />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/Right.tsx`} />
</TabContent>
</TabProvider>
### No Delay
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name={"preview"}>Preview</TabTrigger>
<TabTrigger name={"code"}>Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.NoDelay />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/NoDelay.tsx`} />
</TabContent>
</TabProvider>
### Early Delay
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name={"preview"}>Preview</TabTrigger>
<TabTrigger name={"code"}>Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.EarlyDelay />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/EarlyDelay.tsx`} />
</TabContent>
</TabProvider>
### Late Delay
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name={"preview"}>Preview</TabTrigger>
<TabTrigger name={"code"}>Code</TabTrigger>
</TabList>
<TabContent name="preview">
<Story layout="centered">
<Examples.LateDelay />
</Story>
</TabContent>
<TabContent name="code">
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/LateDelay.tsx`} />
</TabContent>
</TabProvider>
### Controlled
<TabProvider defaultName="preview">
<TabList>
<TabTrigger name={"preview"}>Preview</TabTrigger>
<TabTrigger name={"code"}>Code</TabTrigger>
</TabList>
<TabContent name={"preview"}>
<Story layout={"centered"}>
<Examples.Controlled />
</Story>
</TabContent>
<TabContent name={"code"}>
<LoadedCode from={`${GITHUB}/packages/react/src/docs/components/TooltipBlocks/Examples/Controlled.tsx`} />
</TabContent>
</TabProvider>

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function Bottom() {
return (
<Tooltip position="bottom">
<TooltipContent>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,16 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
import { useState } from "react";
export function Controlled() {
const [opened, setOpened] = useState(false);
return (
<Tooltip position="top" controlled opened={opened}>
<TooltipContent delay={"early"}>
<p>Tooltip!</p>
</TooltipContent>
<Button onClick={() => setOpened((p) => !p)}>Open hover</Button>
</Tooltip>
);
}

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function EarlyDelay() {
return (
<Tooltip position="bottom">
<TooltipContent delay={"early"}>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function LateDelay() {
return (
<Tooltip position="bottom">
<TooltipContent delay={"late"}>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function Left() {
return (
<Tooltip position="left">
<TooltipContent>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function NoDelay() {
return (
<Tooltip position="bottom">
<TooltipContent delay={"none"}>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function Right() {
return (
<Tooltip position="right">
<TooltipContent>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function Top() {
return (
<Tooltip position="top">
<TooltipContent>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,19 +0,0 @@
import { Bottom } from "./Bottom";
import { Left } from "./Left";
import { Right } from "./Right";
import { Top } from "./Top";
import { NoDelay } from "./NoDelay";
import { EarlyDelay } from "./EarlyDelay";
import { LateDelay } from "./LateDelay";
import { Controlled } from "./Controlled";
export default {
Bottom,
Left,
Right,
Top,
NoDelay,
EarlyDelay,
LateDelay,
Controlled,
};

View File

@ -1,13 +0,0 @@
import { Button } from "@components/Button";
import { Tooltip, TooltipContent } from "@components/Tooltip";
export function TooltipDemo() {
return (
<Tooltip>
<TooltipContent>
<p>Tooltip!</p>
</TooltipContent>
<Button>Hover me</Button>
</Tooltip>
);
}

View File

@ -1,64 +0,0 @@
# Configuration
## Library File
Library file is a shared utility container every component uses.
You can put it anywhere as long as you properly update import path.
PSW/UI manages its import path using tsconfig path.
If you want to follow our rule, you can add a path to your `tsconfig.json`.
```json
{
"compilerOptions": {
"paths": {
"@pswui-lib": ["./pswui/lib.tsx"]
}
}
}
```
## CLI
You can use configuration file to change things of CLI.
Default config file name is `pswui.config.js`.
Here is our config structure:
```typescript
export interface Config {
/**
* Path that cli will create a file.
*/
paths?: {
components?: 'src/pswui/components' | string
lib?: 'src/pswui/lib.tsx' | string
}
/**
* Absolute path that will used for import in component
*/
import?: {
lib?: '@pswui-lib' | string
}
}
```
You can import `Config` type or `buildConfig` function to use typescript intellisense.
```ts
import { Config } from "@psw-ui/cli"
const config: Config = {
/* ... */
}
export default config;
```
```ts
import { buildConfig } from "@psw-ui/cli"
export default buildConfig({
/* ... */
})
```

View File

@ -1,36 +0,0 @@
import {TabProvider, TabContent, TabList, TabTrigger} from "@components/Tabs";
import {Code} from "@/components/LoadedCode";
# Installation
<TabProvider defaultName="cli">
<TabList>
<TabTrigger name="cli">Using CLI</TabTrigger>
<TabTrigger name="manual">Manual Install</TabTrigger>
</TabList>
<TabContent name="cli">
1. Install [TailwindCSS](https://tailwindcss.com/docs/installation) and [tailwind-merge](https://github.com/dhiwise/tailwind-merge) and configure it yourself.
2. Add import alias for `@pswui-lib` in your `tsconfig.json` file.
<Code language={"json"}>
{`{\n "compilerOptions": {\n "paths": {\n "@pswui-lib": ["./pswui/lib.tsx"]\n }\n }\n}`}
</Code>
3. Install [@psw-ui/cli](https://www.npmjs.com/package/@psw-ui/cli).
<Code language={"plaintext"}>
{`$ npm install -D \@psw-ui/cli\n$ yarn add -D @psw-ui/cli\n$ pnpm add -D @psw-ui/cli`}
</Code>
4. Run CLI to add components
<Code language={"plaintext"}>
{`$ npx pswui add <component>\n$ yarn pswui add <component>\n$ pnpm pswui add <component>`}
</Code>
5. Import component, and use it.
</TabContent>
<TabContent name="manual">
1. Install [TailwindCSS](https://tailwindcss.com/docs/installation) and [tailwind-merge](https://github.com/dhiwise/tailwind-merge) and configure it yourself.
2. Add import alias for `@pswui-lib` in your `tsconfig.json` file.
<Code language={"json"}>
{`{\n "compilerOptions": {\n "paths": {\n "@pswui-lib": ["<your library file>"]\n }\n }\n}`}
</Code>
3. Grab the library file from [here](https://raw.githubusercontent.com/pswui/ui/main/packages/react/lib.tsx) and put it in the library file path in the tsconfig.
4. Now you can copy & paste your component in your project.
</TabContent>
</TabProvider>

View File

@ -1,41 +0,0 @@
# Introduction
> Beautifully designed, easily copy & pastable, fully customizable - that means it only depends on few dependencies.
This is **UI kit**, a collection of re-usable components that you can copy and paste into your apps.
This UI kit is inspired by [shadcn/ui](https://ui.shadcn.com/) - but it is more customizable.
**More customizable?**
shadcn/ui depends on a lot of packages to provide functionality to its components.
Radix UI, React DayPicker, Embla Carousel...
I'm not saying it's a bad thing.
But when you depends on a lot of package - you easily mess up your package.json, and you can't even edit a single feature.
The only thing you can customize is **style**.
If there's a bug that needs to be fixed quickly, or a feature that doesn't work the way you want it to,
you'll want to tweak it to your liking. This is where relying on a lot of packages can be poison.
PSW/UI solves this - by **NOT** depending on any other packages than framework like React, TailwindCSS, and tailwind-merge.
You can just copy it, and all functionality is contained in a single file.
# Roadmap
First of all, this project is alpha.
You can see a lot of components are missing, and some component is buggy.
I'm working with this priority:
1. Adding new component, with stable features.
2. Fixing bugs with existing components.
3. Make it looks nice.
Also, there is a [Github README](https://github.com/p-sw/ui) for component implementation plans.
You can see what component is implemented, or planned to be implemented.
If you have any ideas or suggestions, please let me know in [Github Issues](https://github.com/p-sw/ui/issues).

View File

@ -1,22 +0,0 @@
import { Link } from "react-router-dom";
import { Button } from "../../components/Button";
function PageNotFound() {
return (
<main className="flex-grow h-full flex flex-col justify-center items-center gap-8">
<section className="flex flex-col justify-center items-center text-center gap-2">
<h1 className="text-4xl font-bold">Page not found</h1>
<p className="text-base">
The page you are looking for does not exist.
</p>
</section>
<section className="flex flex-row justify-center items-center text-center gap-2">
<Button asChild preset="default">
<Link to="/">Go home</Link>
</Button>
</section>
</main>
);
}
export default PageNotFound;

View File

@ -1,22 +0,0 @@
import { Link } from "react-router-dom";
import { Button } from "../../components/Button";
function UnexpectedError() {
return (
<main className="flex-grow h-full flex flex-col justify-center items-center gap-8">
<section className="flex flex-col justify-center items-center text-center gap-2">
<h1 className="text-4xl font-bold">Something went wrong</h1>
<p className="text-base">
There was an unexpected error while loading the page.
</p>
</section>
<section className="flex flex-row justify-center items-center text-center gap-2">
<Button asChild preset="default">
<Link to="/">Go home</Link>
</Button>
</section>
</main>
);
}
export default UnexpectedError;

View File

@ -1,7 +0,0 @@
declare module '*.mdx' {
import type { MDXProps } from 'mdx/types'
import type { Toc } from '@stefanprobst/rehype-extract-toc'
export const tableOfContents: Toc
export default function MDXContent(props: MDXProps): JSX.Element
}

View File

@ -1,6 +0,0 @@
/// <reference types="vite/client" />
import { ImportGlobFunction } from "vite/types/importGlob";
interface ImportMeta {
glob: ImportGlobFunction;
}