mirror of
https://github.com/tale/headplane.git
synced 2026-07-26 07:48:14 +00:00
75 lines
2.1 KiB
TypeScript
75 lines
2.1 KiB
TypeScript
import { AriaToastProps, AriaToastRegionProps, useToast, useToastRegion } from "@react-aria/toast";
|
|
import { ToastQueue, ToastState, useToastQueue } from "@react-stately/toast";
|
|
import { X } from "lucide-react";
|
|
import React, { useRef } from "react";
|
|
|
|
import Button from "~/components/button";
|
|
import cn from "~/utils/cn";
|
|
|
|
interface ToastProps extends AriaToastProps<React.ReactNode> {
|
|
state: ToastState<React.ReactNode>;
|
|
}
|
|
|
|
function Toast({ state, ...props }: ToastProps) {
|
|
const ref = useRef<HTMLDivElement | null>(null);
|
|
const { toastProps, contentProps, titleProps, closeButtonProps } = useToast(props, state, ref);
|
|
|
|
return (
|
|
<div
|
|
{...toastProps}
|
|
ref={ref}
|
|
className={cn(
|
|
"flex items-center justify-between gap-x-3 pl-4 pr-3",
|
|
"text-white shadow-overlay rounded-lg py-3",
|
|
"bg-mist-900 dark:bg-mist-950",
|
|
)}
|
|
>
|
|
<div {...contentProps} className="flex flex-col gap-2">
|
|
<div {...titleProps}>{props.toast.content}</div>
|
|
</div>
|
|
<Button
|
|
{...closeButtonProps}
|
|
aria-label="Close"
|
|
className={cn(
|
|
"rounded-full p-1",
|
|
"bg-transparent hover:bg-mist-700",
|
|
"dark:bg-transparent dark:hover:bg-mist-800",
|
|
)}
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface ToastRegionProps extends AriaToastRegionProps {
|
|
state: ToastState<React.ReactNode>;
|
|
}
|
|
|
|
function ToastRegion({ state, ...props }: ToastRegionProps) {
|
|
const ref = useRef<HTMLDivElement | null>(null);
|
|
const { regionProps } = useToastRegion(props, state, ref);
|
|
|
|
return (
|
|
<div
|
|
{...regionProps}
|
|
ref={ref}
|
|
className={cn("fixed bottom-20 right-4", "flex flex-col gap-4")}
|
|
>
|
|
{state.visibleToasts.map((toast) => (
|
|
<Toast key={toast.key} toast={toast} state={state} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export interface ToastProviderProps extends AriaToastRegionProps {
|
|
queue: ToastQueue<React.ReactNode>;
|
|
}
|
|
|
|
export default function ToastProvider({ queue, ...props }: ToastProviderProps) {
|
|
const state = useToastQueue(queue);
|
|
|
|
return <>{state.visibleToasts.length > 0 && <ToastRegion {...props} state={state} />}</>;
|
|
}
|