Updates
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { ComponentProps, ReactNode } from "react";
|
||||
import { ArrowUpRight } from "lucide-react";
|
||||
import { TWUI_LINK_LIST_LINK_OBJECT } from "../elements/LinkList";
|
||||
import Link from "./Link";
|
||||
import Row from "./Row";
|
||||
|
||||
type Props = ComponentProps<typeof Link> & {
|
||||
link: TWUI_LINK_LIST_LINK_OBJECT;
|
||||
icon?: ReactNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Link With an Arrow
|
||||
* @className twui-arrowed-link
|
||||
*/
|
||||
export default function ArrowedLink({ link, icon, ...props }: Props) {
|
||||
return (
|
||||
<Link href={link.url} {...props} {...link.linkProps}>
|
||||
<Row>
|
||||
<span>{link.title}</span>
|
||||
{icon || <ArrowUpRight size={17} />}
|
||||
</Row>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
AnchorHTMLAttributes,
|
||||
ButtonHTMLAttributes,
|
||||
ComponentProps,
|
||||
DetailedHTMLProps,
|
||||
HTMLAttributeAnchorTarget,
|
||||
HTMLAttributes,
|
||||
@@ -12,10 +13,13 @@ export type TWUIButtonProps = DetailedHTMLProps<
|
||||
ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
HTMLButtonElement
|
||||
> & {
|
||||
title: string;
|
||||
variant?: "normal" | "ghost" | "outlined";
|
||||
color?:
|
||||
| "primary"
|
||||
| "secondary"
|
||||
| "text"
|
||||
| "white"
|
||||
| "accent"
|
||||
| "gray"
|
||||
| "error"
|
||||
@@ -36,6 +40,7 @@ export type TWUIButtonProps = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
>;
|
||||
loadingProps?: ComponentProps<typeof Loading>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -48,12 +53,48 @@ export type TWUIButtonProps = DetailedHTMLProps<
|
||||
* @className twui-button-secondary
|
||||
* @className twui-button-secondary-outlined
|
||||
* @className twui-button-secondary-ghost
|
||||
* @className twui-button-white
|
||||
* @className twui-button-white-outlined
|
||||
* @className twui-button-white-ghost
|
||||
* @className twui-button-accent
|
||||
* @className twui-button-accent-outlined
|
||||
* @className twui-button-accent-ghost
|
||||
* @className twui-button-gray
|
||||
* @className twui-button-gray-outlined
|
||||
* @className twui-button-gray-ghost
|
||||
*
|
||||
* @example
|
||||
```css
|
||||
CSS directive:
|
||||
|
||||
//@theme inline {
|
||||
--breakpoint-xs: 350px;
|
||||
--color-primary: #000000;
|
||||
--color-primary-hover: #29292b;
|
||||
--color-primary-outline: #29292b;
|
||||
--color-primary-text: #29292b;
|
||||
--color-primary-dark: #29292b;
|
||||
--color-primary-dark-hover: #4b4b4b;
|
||||
--color-primary-dark-outline: #4b4b4b;
|
||||
--color-primary-dark-text: #4b4b4b;
|
||||
--color-secondary: #000000;
|
||||
--color-secondary-hover: #dddddd;
|
||||
--color-secondary-outline: #dddddd;
|
||||
--color-secondary-text: #dddddd;
|
||||
--color-secondary-dark: #000000;
|
||||
--color-secondary-dark-hover: #dddddd;
|
||||
--color-secondary-dark-outline: #dddddd;
|
||||
--color-secondary-dark-text: #dddddd;
|
||||
--color-accent: #000000;
|
||||
--color-accent-hover: #dddddd;
|
||||
--color-accent-outline: #dddddd;
|
||||
--color-accent-text: #dddddd;
|
||||
--color-accent-dark: #000000;
|
||||
--color-accent-dark-hover: #dddddd;
|
||||
--color-accent-dark-outline: #dddddd;
|
||||
--color-accent-dark-text: #dddddd;
|
||||
}
|
||||
```
|
||||
*/
|
||||
export default function Button({
|
||||
href,
|
||||
@@ -67,47 +108,67 @@ export default function Button({
|
||||
afterIcon,
|
||||
loading,
|
||||
loadingIconSize,
|
||||
loadingProps,
|
||||
...props
|
||||
}: TWUIButtonProps) {
|
||||
const finalClassName: string = (() => {
|
||||
if (variant == "normal" || !variant) {
|
||||
if (color == "primary" || !color)
|
||||
return twMerge(
|
||||
"bg-blue-500 hover:bg-blue-600 text-white",
|
||||
"bg-primary hover:bg-primary-hover text-white",
|
||||
"dark:bg-primary-dark hover:dark:bg-primary-dark-hover text-white",
|
||||
"twui-button-primary"
|
||||
);
|
||||
if (color == "secondary")
|
||||
return twMerge(
|
||||
"bg-emerald-500 hover:bg-emerald-600 text-white",
|
||||
"bg-secondary hover:bg-secondary-hover text-white",
|
||||
"twui-button-secondary"
|
||||
);
|
||||
if (color == "white")
|
||||
return twMerge(
|
||||
"!bg-white hover:!bg-slate-200 !text-slate-800",
|
||||
"twui-button-white"
|
||||
);
|
||||
if (color == "accent")
|
||||
return twMerge(
|
||||
"bg-violet-500 hover:bg-violet-600 text-white",
|
||||
"bg-accent hover:bg-accent-hover text-white",
|
||||
"twui-button-accent"
|
||||
);
|
||||
if (color == "gray")
|
||||
return twMerge(
|
||||
"bg-slate-300 hover:bg-slate-200 text-slate-800",
|
||||
"bg-gray hover:bg-gray-hover text-foreground-light",
|
||||
"dark:bg-gray-dark hover:dark:bg-gray-dark-hover dark:text-foreground-dark",
|
||||
"twui-button-gray"
|
||||
);
|
||||
if (color == "success")
|
||||
return twMerge(
|
||||
"bg-success hover:bg-success-hover text-white",
|
||||
"dark:bg-success hover:dark:bg-success-hover text-white",
|
||||
"twui-button-success"
|
||||
);
|
||||
if (color == "error")
|
||||
return twMerge(
|
||||
"bg-error hover:bg-error-hover text-white",
|
||||
"dark:bg-error hover:dark:bg-error-hover text-white",
|
||||
"twui-button-error"
|
||||
);
|
||||
} else if (variant == "outlined") {
|
||||
if (color == "primary" || !color)
|
||||
return twMerge(
|
||||
"bg-transparent outline outline-1 outline-blue-500",
|
||||
"text-blue-500 dark:text-blue-400 dark:outline-blue-300",
|
||||
"bg-transparent outline outline-1 outline-primary",
|
||||
"text-primary-text dark:text-primary-dark-text dark:outline-primary-dark-outline",
|
||||
"twui-button-primary-outlined"
|
||||
);
|
||||
if (color == "secondary")
|
||||
return twMerge(
|
||||
"bg-transparent outline outline-1 outline-emerald-500",
|
||||
"text-emerald-500",
|
||||
"bg-transparent outline outline-1 outline-secondary",
|
||||
"text-secondary",
|
||||
"twui-button-secondary-outlined"
|
||||
);
|
||||
if (color == "accent")
|
||||
return twMerge(
|
||||
"bg-transparent outline outline-1 outline-violet-500",
|
||||
"text-violet-500",
|
||||
"bg-transparent outline outline-1 outline-accent",
|
||||
"text-accent",
|
||||
"twui-button-accent-outlined"
|
||||
);
|
||||
if (color == "gray")
|
||||
@@ -116,23 +177,41 @@ export default function Button({
|
||||
"text-slate-600 dark:text-white/60 dark:outline-white/30",
|
||||
"twui-button-gray-outlined"
|
||||
);
|
||||
if (color == "white")
|
||||
return twMerge(
|
||||
"bg-transparent outline outline-1 outline-white/50",
|
||||
"text-white",
|
||||
"twui-button-white-outlined"
|
||||
);
|
||||
if (color == "error")
|
||||
return twMerge(
|
||||
"bg-transparent outline outline-1 outline-error text-error",
|
||||
"dark:outline-error dark:text-error-dark",
|
||||
"twui-button-error-outlined"
|
||||
);
|
||||
} else if (variant == "ghost") {
|
||||
if (color == "primary" || !color)
|
||||
return twMerge(
|
||||
"bg-transparent dark:bg-transparent outline-none p-2",
|
||||
"text-blue-500 hover:bg-transparent dark:hover:bg-transparent",
|
||||
"text-primary-text dark:text-primary-dark-text hover:bg-transparent dark:hover:bg-transparent",
|
||||
"twui-button-primary-ghost"
|
||||
);
|
||||
if (color == "secondary")
|
||||
return twMerge(
|
||||
"bg-transparent dark:bg-transparent outline-none p-2",
|
||||
"text-emerald-500 hover:bg-transparent dark:hover:bg-transparent",
|
||||
"text-secondary hover:bg-transparent dark:hover:bg-transparent",
|
||||
"twui-button-secondary-ghost"
|
||||
);
|
||||
if (color == "text")
|
||||
return twMerge(
|
||||
"bg-transparent dark:bg-transparent outline-none p-2 dark:text-foreground-dark",
|
||||
"text-foreground-light hover:bg-transparent dark:hover:bg-transparent",
|
||||
"twui-button-secondary-ghost"
|
||||
);
|
||||
if (color == "accent")
|
||||
return twMerge(
|
||||
"bg-transparent dark:bg-transparent outline-none p-2",
|
||||
"text-violet-500 hover:bg-transparent dark:hover:bg-transparent",
|
||||
"text-accent hover:bg-transparent dark:hover:bg-transparent",
|
||||
"twui-button-accent-ghost"
|
||||
);
|
||||
if (color == "gray")
|
||||
@@ -156,9 +235,15 @@ export default function Button({
|
||||
if (color == "success")
|
||||
return twMerge(
|
||||
"bg-transparent outline-none p-2",
|
||||
"text-emerald-600",
|
||||
"text-success",
|
||||
"twui-button-success-ghost"
|
||||
);
|
||||
if (color == "white")
|
||||
return twMerge(
|
||||
"bg-transparent outline-none p-2",
|
||||
"text-white",
|
||||
"twui-button-white-ghost"
|
||||
);
|
||||
}
|
||||
|
||||
return "";
|
||||
@@ -168,17 +253,24 @@ export default function Button({
|
||||
<button
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"bg-blue-600 text-white text-base font-medium px-4 py-2 rounded",
|
||||
"flex items-center justify-center relative transition-all",
|
||||
"bg-primary text-white font-medium px-4 py-2 rounded-default",
|
||||
"flex items-center justify-center relative transition-all cursor-pointer",
|
||||
props.disabled ? "opacity-40 cursor-not-allowed" : "",
|
||||
"twui-button-general",
|
||||
size == "small" && "px-3 py-1.5 text-sm",
|
||||
size == "smaller" && "px-2 py-1 text-xs",
|
||||
size == "large" && "text-lg",
|
||||
size == "larger" && "px-5 py-3 text-xl",
|
||||
size == "small"
|
||||
? "px-3 py-1.5 text-sm twui-button-small"
|
||||
: size == "smaller"
|
||||
? "px-2 py-1 text-xs twui-button-smaller"
|
||||
: size == "large"
|
||||
? "text-lg twui-button-large"
|
||||
: size == "larger"
|
||||
? "px-5 py-3 text-xl twui-button-larger"
|
||||
: "twui-button-base",
|
||||
finalClassName,
|
||||
props.className,
|
||||
loading ? "pointer-events-none opacity-80" : "l"
|
||||
loading ? "pointer-events-none opacity-80" : "",
|
||||
props.className
|
||||
)}
|
||||
aria-label={props.title}
|
||||
>
|
||||
<div
|
||||
{...buttonContentProps}
|
||||
@@ -196,7 +288,6 @@ export default function Button({
|
||||
|
||||
{loading && (
|
||||
<Loading
|
||||
className="absolute"
|
||||
size={(() => {
|
||||
if (loadingIconSize) return loadingIconSize;
|
||||
switch (size) {
|
||||
@@ -209,6 +300,8 @@ export default function Button({
|
||||
return "normal";
|
||||
}
|
||||
})()}
|
||||
{...loadingProps}
|
||||
className={twMerge("absolute", loadingProps?.className)}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
@@ -216,7 +309,13 @@ export default function Button({
|
||||
|
||||
if (href)
|
||||
return (
|
||||
<a {...linkProps} href={href} target={target}>
|
||||
<a
|
||||
{...linkProps}
|
||||
href={href}
|
||||
target={target}
|
||||
title={props.title}
|
||||
aria-label={props.title}
|
||||
>
|
||||
{buttonComponent}
|
||||
</a>
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ export default function Center({
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"flex flex-col items-center justify-center gap-4 p-2 w-full",
|
||||
"twui-center",
|
||||
"h-full twui-center",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
import { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & {
|
||||
vertical?: boolean;
|
||||
dashed?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Vertical and Horizontal Divider
|
||||
* @className twui-divider
|
||||
* @className twui-divider-horizontal
|
||||
* @className twui-divider-vertical
|
||||
*/
|
||||
export default function Divider({
|
||||
vertical,
|
||||
...props
|
||||
}: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement> & {
|
||||
vertical?: boolean;
|
||||
}) {
|
||||
export default function Divider({ vertical, dashed, ...props }: Props) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"border-slate-200 dark:border-white/10 border-solid",
|
||||
"border-slate-200 dark:border-white/10",
|
||||
vertical
|
||||
? "border-0 border-l h-full min-h-5"
|
||||
: "border-0 border-t w-full",
|
||||
"twui-divider",
|
||||
vertical ? "twui-divider-vertical" : "twui-divider-horizontal",
|
||||
dashed ? "border-dashed" : "border-solid",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import Img, { TWUIImageProps } from "./Img";
|
||||
import Border from "../elements/Border";
|
||||
|
||||
export default function DocsImg({ ...props }: TWUIImageProps) {
|
||||
return (
|
||||
<Border className={twMerge("p-0 mb-10")}>
|
||||
<Img
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"w-full h-auto rounded-default overflow-hidden",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
</Border>
|
||||
);
|
||||
}
|
||||
@@ -11,7 +11,12 @@ export default function H1({
|
||||
return (
|
||||
<h1
|
||||
{...props}
|
||||
className={twMerge("text-5xl mb-4", "twui-h1", props.className)}
|
||||
className={twMerge(
|
||||
"text-4xl md:text-5xl mb-4",
|
||||
"twui-headings twui-heading",
|
||||
"twui-h1",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</h1>
|
||||
|
||||
@@ -11,7 +11,12 @@ export default function H2({
|
||||
return (
|
||||
<h2
|
||||
{...props}
|
||||
className={twMerge("text-3xl mb-4", "twui-h2", props.className)}
|
||||
className={twMerge(
|
||||
"text-2xl md:text-3xl mb-4",
|
||||
"twui-headings twui-heading",
|
||||
"twui-h2",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</h2>
|
||||
|
||||
@@ -11,7 +11,12 @@ export default function H3({
|
||||
return (
|
||||
<h3
|
||||
{...props}
|
||||
className={twMerge("text-xl mb-4", "twui-h3", props.className)}
|
||||
className={twMerge(
|
||||
"text-xl mb-4",
|
||||
"twui-headings twui-heading",
|
||||
"twui-h3",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</h3>
|
||||
|
||||
@@ -11,7 +11,12 @@ export default function H4({
|
||||
return (
|
||||
<h4
|
||||
{...props}
|
||||
className={twMerge("text-base mb-4", "twui-h4", props.className)}
|
||||
className={twMerge(
|
||||
"text-base mb-4",
|
||||
"twui-headings twui-heading",
|
||||
"twui-h4",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</h4>
|
||||
|
||||
@@ -11,7 +11,12 @@ export default function H5({
|
||||
return (
|
||||
<h5
|
||||
{...props}
|
||||
className={twMerge("text-sm mb-4", "twui-h5", props.className)}
|
||||
className={twMerge(
|
||||
"text-sm mb-4",
|
||||
"twui-headings twui-heading",
|
||||
"twui-h5",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</h5>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ComponentProps, ReactNode } from "react";
|
||||
import { TWUI_LINK_LIST_LINK_OBJECT } from "../elements/LinkList";
|
||||
import Link from "./Link";
|
||||
import Row from "./Row";
|
||||
|
||||
type Props = ComponentProps<typeof Link> & {
|
||||
link: TWUI_LINK_LIST_LINK_OBJECT;
|
||||
icon: ReactNode;
|
||||
iconPosition?: "before" | "after";
|
||||
};
|
||||
|
||||
/**
|
||||
* # Link With an Icon
|
||||
* @className twui-arrowed-link
|
||||
*/
|
||||
export default function IconLink({
|
||||
link,
|
||||
iconPosition,
|
||||
icon,
|
||||
...props
|
||||
}: Props) {
|
||||
return (
|
||||
<Link
|
||||
href={link.url}
|
||||
{...props}
|
||||
onClick={(e) => {
|
||||
link.onClick?.(e);
|
||||
props.onClick?.(e);
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
{iconPosition == "before" || !iconPosition ? icon : null}
|
||||
<span>{link.title}</span>
|
||||
{iconPosition == "after" ? icon : null}
|
||||
</Row>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export type TWUIImageProps = DetailedHTMLProps<
|
||||
ImgHTMLAttributes<HTMLImageElement>,
|
||||
HTMLImageElement
|
||||
> & {
|
||||
alt: string;
|
||||
size?: number;
|
||||
circle?: boolean;
|
||||
bgImg?: boolean;
|
||||
@@ -24,6 +25,8 @@ export default function Img({ ...props }: TWUIImageProps) {
|
||||
const height = props.size || props.height;
|
||||
const sizeRatio = width && height ? Number(width) / Number(height) : 1;
|
||||
|
||||
const [imageError, setImageError] = React.useState(false);
|
||||
|
||||
const finalProps = _.omit(props, [
|
||||
"size",
|
||||
"circle",
|
||||
@@ -53,30 +56,70 @@ export default function Img({ ...props }: TWUIImageProps) {
|
||||
}
|
||||
props.onError?.(e);
|
||||
},
|
||||
style: {
|
||||
...(props.size
|
||||
? {
|
||||
width: `${props.size}px`,
|
||||
minWidth: `${props.size}px`,
|
||||
height: `${props.size}px`,
|
||||
}
|
||||
: {}),
|
||||
...props.style,
|
||||
},
|
||||
};
|
||||
|
||||
if (imageError) {
|
||||
return (
|
||||
<img
|
||||
loading="lazy"
|
||||
{...interpolatedProps}
|
||||
src={
|
||||
"https://static.datasquirel.com/images/user-images/user-2/castcord-image-preset_thumbnail.jpg"
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (props.srcDark && props.srcLight) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<img
|
||||
loading="lazy"
|
||||
{...interpolatedProps}
|
||||
className={twMerge(
|
||||
"hidden dark:block",
|
||||
interpolatedProps.className
|
||||
)}
|
||||
src={props.srcDark}
|
||||
onError={(e) => {
|
||||
setImageError(true);
|
||||
props.onError?.(e);
|
||||
}}
|
||||
/>
|
||||
<img
|
||||
loading="lazy"
|
||||
{...interpolatedProps}
|
||||
className={twMerge(
|
||||
"block dark:hidden",
|
||||
interpolatedProps.className
|
||||
)}
|
||||
src={props.srcLight}
|
||||
onError={(e) => {
|
||||
setImageError(true);
|
||||
props.onError?.(e);
|
||||
}}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return <img {...interpolatedProps} />;
|
||||
return (
|
||||
<img
|
||||
{...interpolatedProps}
|
||||
onError={(e) => {
|
||||
setImageError(true);
|
||||
props.onError?.(e);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,29 +9,41 @@ type Props = DetailedHTMLProps<
|
||||
showArrow?: boolean;
|
||||
arrowSize?: number;
|
||||
arrowProps?: Omit<LucideProps, "ref"> & RefAttributes<SVGSVGElement>;
|
||||
strict?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* # General Anchor Elements
|
||||
* @className twui-a | twui-anchor
|
||||
* @info use `cancel-link` class name to prevent triggering this link from a child element
|
||||
*/
|
||||
export default function Link({
|
||||
showArrow,
|
||||
arrowSize = 20,
|
||||
arrowProps,
|
||||
strict,
|
||||
...props
|
||||
}: Props) {
|
||||
return (
|
||||
<a
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"text-base text-link-500 no-underline hover:text-link-500/50",
|
||||
"text-blue-600 dark:text-blue-400 hover:opacity-60 transition-all",
|
||||
"border-0 border-b border-blue-300 dark:border-blue-200/30 border-solid leading-4",
|
||||
"text-link-500 no-underline hover:text-link-500/50",
|
||||
"text-link dark:text-link-dark hover:opacity-80 transition-all",
|
||||
"border-0 border-b border-link dark:border-link-dark border-solid leading-4",
|
||||
"twui-anchor",
|
||||
"twui-a",
|
||||
props.className
|
||||
)}
|
||||
onClick={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
|
||||
if (target.closest(".cancel-link")) {
|
||||
e.preventDefault();
|
||||
}
|
||||
props?.onClick?.(e);
|
||||
}}
|
||||
data-strict={strict ? "yes" : undefined}
|
||||
>
|
||||
{props.children}
|
||||
{showArrow && (
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLHeadingElement>,
|
||||
HTMLHeadingElement
|
||||
> & {
|
||||
noMargin?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Paragraph Tag
|
||||
* @className twui-p | twui-paragraph
|
||||
*/
|
||||
export default function P({
|
||||
...props
|
||||
}: DetailedHTMLProps<HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) {
|
||||
export default function P({ noMargin, ...props }: Props) {
|
||||
return (
|
||||
<p
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"text-base py-4",
|
||||
"py-4",
|
||||
noMargin ? "!m-0 p-0" : "",
|
||||
"twui-p",
|
||||
"twui-paragraph",
|
||||
props.className
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & {
|
||||
noWrap?: boolean;
|
||||
itemsStart?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Flexbox Row
|
||||
* @className twui-row
|
||||
*/
|
||||
export default function Row({
|
||||
...props
|
||||
}: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>) {
|
||||
export default function Row({ noWrap, itemsStart, ...props }: Props) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"flex flex-row items-center gap-2 flex-wrap",
|
||||
"flex flex-row gap-2",
|
||||
noWrap ? "xl:flex-nowrap" : "flex-wrap",
|
||||
itemsStart ? "items-start" : "items-center",
|
||||
"twui-row",
|
||||
props.className
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import _ from "lodash";
|
||||
import { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & {
|
||||
horizontal?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Space Component
|
||||
* @className twui-spacer
|
||||
*/
|
||||
export default function Spacer({ horizontal, ...props }: Props) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"grow",
|
||||
horizontal ? "w-10" : "w-full h-10",
|
||||
"twui-spacer",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export default function Span({
|
||||
<span
|
||||
{...props}
|
||||
className={twMerge(
|
||||
"text-base",
|
||||
"",
|
||||
size == "small" && "text-sm",
|
||||
size == "smaller" && "text-xs",
|
||||
size == "large" && "text-lg",
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import _ from "lodash";
|
||||
import { DetailedHTMLProps, HTMLAttributes } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
type Props = DetailedHTMLProps<
|
||||
HTMLAttributes<HTMLDivElement>,
|
||||
HTMLDivElement
|
||||
> & {
|
||||
center?: boolean;
|
||||
gap?: number | string;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Flexbox Column
|
||||
* @className twui-stack
|
||||
*/
|
||||
export default function Stack({ gap, ...props }: Props) {
|
||||
const finalProps = _.omit(props, "center");
|
||||
return (
|
||||
<div
|
||||
{...finalProps}
|
||||
className={twMerge(
|
||||
"flex flex-col items-start gap-4",
|
||||
props.center && "items-center",
|
||||
gap
|
||||
? typeof gap == "string"
|
||||
? `gap-[${gap}]`
|
||||
: `gap-${gap}`
|
||||
: "",
|
||||
"twui-stack",
|
||||
props.className
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -7,13 +7,15 @@ type Props = DetailedHTMLProps<
|
||||
HTMLDivElement
|
||||
> & {
|
||||
center?: boolean;
|
||||
gap?: number | string;
|
||||
componentRef?: React.RefObject<HTMLDivElement>;
|
||||
};
|
||||
|
||||
/**
|
||||
* # Flexbox Column
|
||||
* @className twui-stack
|
||||
*/
|
||||
export default function Stack({ ...props }: Props) {
|
||||
export default function Stack({ gap, componentRef, ...props }: Props) {
|
||||
const finalProps = _.omit(props, "center");
|
||||
return (
|
||||
<div
|
||||
@@ -21,9 +23,15 @@ export default function Stack({ ...props }: Props) {
|
||||
className={twMerge(
|
||||
"flex flex-col items-start gap-4",
|
||||
props.center && "items-center",
|
||||
gap
|
||||
? typeof gap == "string"
|
||||
? `gap-[${gap}]`
|
||||
: `gap-${gap}`
|
||||
: "",
|
||||
"twui-stack",
|
||||
props.className
|
||||
)}
|
||||
ref={componentRef}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user