88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { ChevronLeft } from "lucide-react";
|
|
import Link, { type LinkProps } from "next/link";
|
|
|
|
interface BackButtonBaseProps {
|
|
className?: string;
|
|
ariaLabel?: string;
|
|
analyticsKey?: string;
|
|
iconSize?: number;
|
|
variant?: "floating" | "soft" | "ghost" | "dark" | "unstyled";
|
|
}
|
|
|
|
type BackButtonLinkProps = BackButtonBaseProps & {
|
|
href: LinkProps["href"];
|
|
onClick?: never;
|
|
};
|
|
|
|
type BackButtonActionProps = BackButtonBaseProps & {
|
|
href?: never;
|
|
onClick: () => void;
|
|
};
|
|
|
|
export type BackButtonProps = BackButtonLinkProps | BackButtonActionProps;
|
|
|
|
const BASE_CLASS_NAME =
|
|
"inline-flex cursor-pointer items-center justify-center rounded-full border-0 p-0 text-auth-text-primary no-underline transition-[background,box-shadow,transform] duration-150 ease-out focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-[#f657a0]";
|
|
|
|
const VARIANT_CLASS_NAMES = {
|
|
floating:
|
|
"absolute left-[calc(var(--spacing-xl,20px)+var(--app-safe-left,0))] top-[calc(var(--spacing-xl,20px)+var(--app-safe-top,0))] z-2 size-(--back-button-size) bg-(--color-auth-surface) pr-0.5 shadow-[0_2px_8px_rgba(0,0,0,0.1)] hover:bg-[rgba(0,0,0,0.04)] active:scale-96",
|
|
soft:
|
|
"size-(--responsive-icon-button-size,42px) border border-[rgba(25,19,22,0.08)] bg-[rgba(255,255,255,0.82)] text-[#21191d] shadow-[0_10px_22px_rgba(50,30,40,0.08)] hover:-translate-y-px hover:bg-white hover:shadow-[0_14px_26px_rgba(50,30,40,0.12)] active:translate-y-px",
|
|
ghost:
|
|
"size-8 bg-transparent text-black hover:opacity-70 active:scale-96",
|
|
dark:
|
|
"size-(--responsive-icon-button-size,42px) border border-[rgba(255,255,255,0.12)] bg-[rgba(13,11,20,0.7)] text-white shadow-[0_10px_24px_rgba(0,0,0,0.2)] backdrop-blur-md hover:bg-[rgba(28,24,39,0.82)] active:scale-96",
|
|
unstyled: "",
|
|
} satisfies Record<NonNullable<BackButtonBaseProps["variant"]>, string>;
|
|
|
|
export function BackButton({
|
|
href,
|
|
onClick,
|
|
className,
|
|
ariaLabel = "Back",
|
|
analyticsKey,
|
|
iconSize = 24,
|
|
variant = "floating",
|
|
}: BackButtonProps) {
|
|
const buttonClassName = [
|
|
BASE_CLASS_NAME,
|
|
VARIANT_CLASS_NAMES[variant],
|
|
className,
|
|
]
|
|
.filter(Boolean)
|
|
.join(" ");
|
|
const icon = (
|
|
<ChevronLeft size={iconSize} strokeWidth={2.5} aria-hidden="true" />
|
|
);
|
|
|
|
if (href) {
|
|
return (
|
|
<Link
|
|
href={href}
|
|
className={buttonClassName}
|
|
aria-label={ariaLabel}
|
|
data-analytics-key={analyticsKey}
|
|
data-analytics-label={ariaLabel}
|
|
>
|
|
{icon}
|
|
</Link>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
className={buttonClassName}
|
|
onClick={onClick}
|
|
aria-label={ariaLabel}
|
|
data-analytics-key={analyticsKey}
|
|
data-analytics-label={ariaLabel}
|
|
>
|
|
{icon}
|
|
</button>
|
|
);
|
|
}
|