84 lines
2.2 KiB
TypeScript
84 lines
2.2 KiB
TypeScript
|
|
import { useState, type ReactNode, type SyntheticEvent } from "react";
|
||
|
|
import {
|
||
|
|
AlertDialog,
|
||
|
|
AlertDialogAction,
|
||
|
|
AlertDialogCancel,
|
||
|
|
AlertDialogContent,
|
||
|
|
AlertDialogDescription,
|
||
|
|
AlertDialogFooter,
|
||
|
|
AlertDialogHeader,
|
||
|
|
AlertDialogTitle,
|
||
|
|
} from "@/components/ui/alert-dialog";
|
||
|
|
import { cn } from "@/lib/utils";
|
||
|
|
|
||
|
|
export type FeatureGateLabels = {
|
||
|
|
title: string;
|
||
|
|
description: string;
|
||
|
|
cancel: string;
|
||
|
|
confirm: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
type FeatureGateProps = {
|
||
|
|
enabled: boolean;
|
||
|
|
labels: FeatureGateLabels;
|
||
|
|
onEnable: () => void | Promise<void>;
|
||
|
|
className?: string;
|
||
|
|
children: ReactNode;
|
||
|
|
};
|
||
|
|
|
||
|
|
/** 功能关闭时拦截子区域交互,提示是否开启总开关 */
|
||
|
|
export function FeatureGate({
|
||
|
|
enabled,
|
||
|
|
labels,
|
||
|
|
onEnable,
|
||
|
|
className,
|
||
|
|
children,
|
||
|
|
}: FeatureGateProps) {
|
||
|
|
const [open, setOpen] = useState(false);
|
||
|
|
|
||
|
|
const intercept = (e: SyntheticEvent) => {
|
||
|
|
if (enabled) return;
|
||
|
|
e.preventDefault();
|
||
|
|
e.stopPropagation();
|
||
|
|
setOpen(true);
|
||
|
|
};
|
||
|
|
|
||
|
|
const handleConfirm = () => {
|
||
|
|
void Promise.resolve(onEnable()).then(() => setOpen(false));
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<div
|
||
|
|
className={cn(className)}
|
||
|
|
onPointerDownCapture={intercept}
|
||
|
|
onClickCapture={intercept}
|
||
|
|
>
|
||
|
|
{children}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<AlertDialog open={open} onOpenChange={setOpen}>
|
||
|
|
<AlertDialogContent className="border-white/10 bg-zinc-900 text-white sm:max-w-md">
|
||
|
|
<AlertDialogHeader>
|
||
|
|
<AlertDialogTitle className="text-white">{labels.title}</AlertDialogTitle>
|
||
|
|
<AlertDialogDescription className="text-white/60">
|
||
|
|
{labels.description}
|
||
|
|
</AlertDialogDescription>
|
||
|
|
</AlertDialogHeader>
|
||
|
|
<AlertDialogFooter>
|
||
|
|
<AlertDialogCancel className="border-white/20 bg-transparent text-white hover:bg-white/10">
|
||
|
|
{labels.cancel}
|
||
|
|
</AlertDialogCancel>
|
||
|
|
<AlertDialogAction
|
||
|
|
className="bg-[#00FFF6] text-black hover:brightness-95 focus-visible:ring-[#00FFF6]"
|
||
|
|
onClick={handleConfirm}
|
||
|
|
>
|
||
|
|
{labels.confirm}
|
||
|
|
</AlertDialogAction>
|
||
|
|
</AlertDialogFooter>
|
||
|
|
</AlertDialogContent>
|
||
|
|
</AlertDialog>
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|