This commit is contained in:
2026-10-01 08:02:47 +01:00
parent 6392457ffb
commit 3dc9f12ad4
104 changed files with 6536 additions and 1037 deletions
+65 -26
View File
@@ -1,32 +1,50 @@
import React, {
AnchorHTMLAttributes,
ButtonHTMLAttributes,
ComponentProps,
DetailedHTMLProps,
HTMLAttributeAnchorTarget,
HTMLAttributes,
type AnchorHTMLAttributes,
type ButtonHTMLAttributes,
type ComponentProps,
type DetailedHTMLProps,
type HTMLAttributeAnchorTarget,
type HTMLAttributes,
} from "react";
import { twMerge } from "tailwind-merge";
import Loading from "../elements/Loading";
import LucideIcon, { TWUILucideIconName } from "../elements/lucide-icon";
import LucideIcon, { type TWUILucideIconName } from "../elements/lucide-icon";
import type { LucideProps } from "lucide-react";
export const TWUIButtonColors = [
"primary",
"secondary",
"text",
"white",
"accent",
"gray",
"error",
"warning",
"success",
] as const;
export const TWUIButtonSizes = [
"small",
"smaller",
"normal",
"large",
"larger",
] as const;
export const TWUIButtonVariants = ["normal", "ghost", "outlined"] as const;
export type TWUIButtonColorType = (typeof TWUIButtonColors)[number];
export type TWUIButtonSizeType = (typeof TWUIButtonSizes)[number];
export type TWUIButtonVariantType = (typeof TWUIButtonVariants)[number];
export type TWUIButtonProps = DetailedHTMLProps<
ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
> & {
title: string;
variant?: "normal" | "ghost" | "outlined";
color?:
| "primary"
| "secondary"
| "text"
| "white"
| "accent"
| "gray"
| "error"
| "warning"
| "success";
size?: "small" | "smaller" | "normal" | "large" | "larger";
variant?: TWUIButtonVariantType;
color?: TWUIButtonColorType;
size?: TWUIButtonSizeType;
loadingIconSize?: React.ComponentProps<typeof Loading>["size"];
href?: string;
target?: HTMLAttributeAnchorTarget;
@@ -37,6 +55,10 @@ export type TWUIButtonProps = DetailedHTMLProps<
>;
beforeIcon?: TWUILucideIconName | React.JSX.Element;
afterIcon?: TWUILucideIconName | React.JSX.Element;
before_icon_name?: TWUILucideIconName;
after_icon_name?: TWUILucideIconName;
before_icon_props?: LucideProps;
after_icon_props?: LucideProps;
buttonContentProps?: DetailedHTMLProps<
HTMLAttributes<HTMLDivElement>,
HTMLDivElement
@@ -44,7 +66,7 @@ export type TWUIButtonProps = DetailedHTMLProps<
loadingProps?: ComponentProps<typeof Loading>;
};
const buttonClasses: Record<string, Record<string, string>> = {
export const ButtonClasses: Record<string, Record<string, string>> = {
normal: {
primary: twMerge(
"bg-primary hover:bg-primary-hover text-white",
@@ -96,8 +118,8 @@ const buttonClasses: Record<string, Record<string, string>> = {
"twui-button-accent-outlined",
),
gray: twMerge(
"bg-transparent outline outline-1 outline-slate-300",
"text-slate-600 dark:text-white/60 dark:outline-white/30",
"bg-transparent outline outline-1 outline-gray",
"text-dark dark:text-white/60 dark:outline-white/30",
"twui-button-gray-outlined",
),
white: twMerge(
@@ -110,6 +132,11 @@ const buttonClasses: Record<string, Record<string, string>> = {
"dark:outline-error dark:text-error-dark",
"twui-button-error-outlined",
),
warning: twMerge(
"bg-transparent outline outline-1 outline-warning text-warning",
"dark:outline-warning dark:text-warning-dark",
"twui-button-warning-outlined",
),
},
ghost: {
primary: twMerge(
@@ -226,9 +253,14 @@ export default function Button({
loading,
loadingIconSize,
loadingProps,
before_icon_name,
after_icon_name,
before_icon_props,
after_icon_props,
...props
}: TWUIButtonProps) {
const finalClassName = buttonClasses[variant || "normal"]?.[color || "primary"] ?? "";
const finalClassName =
ButtonClasses[variant || "normal"]?.[color || "primary"] ?? "";
const buttonComponent = (
<button
@@ -246,7 +278,7 @@ export default function Button({
? "text-lg twui-button-large"
: size == "larger"
? "px-5 py-3 text-xl twui-button-larger"
: "twui-button-base",
: "text-sm twui-button-base",
finalClassName,
loading ? "pointer-events-none opacity-80" : "",
props.className,
@@ -262,7 +294,12 @@ export default function Button({
buttonContentProps?.className,
)}
>
{beforeIcon ? (
{before_icon_name ? (
<LucideIcon
{...before_icon_props}
name={before_icon_name}
/>
) : beforeIcon ? (
typeof beforeIcon == "string" ? (
<LucideIcon name={beforeIcon as TWUILucideIconName} />
) : (
@@ -270,7 +307,9 @@ export default function Button({
)
) : null}
{props.children}
{afterIcon ? (
{after_icon_name ? (
<LucideIcon {...after_icon_props} name={after_icon_name} />
) : afterIcon ? (
typeof afterIcon == "string" ? (
<LucideIcon name={afterIcon as TWUILucideIconName} />
) : (