mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
Refresh action dialog chrome.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
b4286aa2d6
commit
3ab5db90ad
@ -2,11 +2,14 @@
|
||||
|
||||
import type { Icon as PhosphorIcon } from "@phosphor-icons/react";
|
||||
import { InfoIcon, WarningCircleIcon } from "@phosphor-icons/react";
|
||||
import {
|
||||
DesignButton,
|
||||
DesignDialog,
|
||||
type DesignDialogSize,
|
||||
} from "@stackframe/dashboard-ui-components";
|
||||
import React, { Suspense, useId } from "react";
|
||||
import { Alert } from "./alert";
|
||||
import { Button } from "./button";
|
||||
import { Checkbox } from "./checkbox";
|
||||
import { Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "./dialog";
|
||||
import { Label } from "./label";
|
||||
import { Skeleton } from "./skeleton";
|
||||
|
||||
@ -22,12 +25,12 @@ export type ActionDialogProps = {
|
||||
okButton?: boolean | Readonly<{
|
||||
label?: string,
|
||||
onClick?: () => Promise<"prevent-close" | undefined | void>,
|
||||
props?: Partial<React.ComponentProps<typeof Button>>,
|
||||
props?: Partial<React.ComponentProps<typeof DesignButton>>,
|
||||
}>,
|
||||
cancelButton?: boolean | Readonly<{
|
||||
label?: string,
|
||||
onClick?: () => Promise<"prevent-close" | undefined | void>,
|
||||
props?: Partial<React.ComponentProps<typeof Button>>,
|
||||
props?: Partial<React.ComponentProps<typeof DesignButton>>,
|
||||
}>,
|
||||
confirmText?: string,
|
||||
children?: React.ReactNode,
|
||||
@ -43,6 +46,7 @@ export type ActionDialogProps = {
|
||||
* (border, ring, bg, shadow, padding, rounded, etc.).
|
||||
*/
|
||||
contentClassName?: string,
|
||||
size?: DesignDialogSize,
|
||||
};
|
||||
|
||||
export function ActionDialog(props: ActionDialogProps) {
|
||||
@ -62,75 +66,43 @@ export function ActionDialog(props: ActionDialogProps) {
|
||||
|
||||
const blockDismissOnOutside = !!(props.preventClose || props.keepOpenOnOutsideInteraction);
|
||||
|
||||
const onOpenChange = (open: boolean) => {
|
||||
if (!open) {
|
||||
const onOpenChange = (nextOpen: boolean) => {
|
||||
if (!nextOpen) {
|
||||
props.onClose?.();
|
||||
setConfirmed(false);
|
||||
} else {
|
||||
setInvalidationCount(invalidationCount + 1);
|
||||
}
|
||||
setOpenState(open);
|
||||
props.onOpenChange?.(open);
|
||||
setOpenState(nextOpen);
|
||||
props.onOpenChange?.(nextOpen);
|
||||
};
|
||||
|
||||
const trigger = props.trigger != null && React.isValidElement(props.trigger)
|
||||
? props.trigger
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange} key={invalidationCount}>
|
||||
{props.trigger && <DialogTrigger asChild>
|
||||
{props.trigger}
|
||||
</DialogTrigger>}
|
||||
|
||||
<DialogContent
|
||||
onInteractOutside={blockDismissOnOutside ? (e) => e.preventDefault() : undefined}
|
||||
onPointerDownOutside={blockDismissOnOutside ? (e) => e.preventDefault() : undefined}
|
||||
onFocusOutside={blockDismissOnOutside ? (e) => e.preventDefault() : undefined}
|
||||
className={[
|
||||
props.preventClose ? "[&>button]:hidden" : "",
|
||||
props.contentClassName ?? "",
|
||||
].filter(Boolean).join(" ")}
|
||||
>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<TitleIcon className="h-4 w-4 mr-2"/>
|
||||
{title}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{props.description}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<DialogBody className="pb-2">
|
||||
<div>
|
||||
<Suspense fallback={
|
||||
<>
|
||||
<Skeleton className='h-9 w-2/3 self-center' />
|
||||
|
||||
<Skeleton className='h-3 w-16 mt-8' />
|
||||
<Skeleton className='h-9 w-full mt-1' />
|
||||
|
||||
<Skeleton className='h-3 w-24 mt-2' />
|
||||
<Skeleton className='h-9 w-full mt-1' />
|
||||
|
||||
<Skeleton className='h-9 w-full mt-6' />
|
||||
</>
|
||||
}>
|
||||
{props.children}
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
{props.confirmText && <Alert>
|
||||
<Label className="flex gap-4 items-center">
|
||||
<Checkbox id={confirmId} checked={confirmed} onCheckedChange={(v) => setConfirmed(!!v)}/>
|
||||
{props.confirmText}
|
||||
</Label>
|
||||
</Alert>}
|
||||
</DialogBody>
|
||||
|
||||
|
||||
{anyButton && <DialogFooter className="gap-2">
|
||||
<DesignDialog
|
||||
key={invalidationCount}
|
||||
open={open}
|
||||
onOpenChange={onOpenChange}
|
||||
trigger={trigger}
|
||||
size={props.size ?? "lg"}
|
||||
icon={TitleIcon}
|
||||
title={title}
|
||||
description={props.description}
|
||||
hideTopCloseButton={props.preventClose}
|
||||
className={props.contentClassName}
|
||||
contentProps={{
|
||||
onInteractOutside: blockDismissOnOutside ? (e) => e.preventDefault() : undefined,
|
||||
onPointerDownOutside: blockDismissOnOutside ? (e) => e.preventDefault() : undefined,
|
||||
onFocusOutside: blockDismissOnOutside ? (e) => e.preventDefault() : undefined,
|
||||
}}
|
||||
footer={anyButton ? (
|
||||
<div className="flex w-full flex-col-reverse gap-2 sm:flex-row sm:justify-end">
|
||||
{cancelButton && (
|
||||
<Button
|
||||
<DesignButton
|
||||
variant="secondary"
|
||||
color="neutral"
|
||||
onClick={async () => {
|
||||
if (await cancelButton.onClick?.() !== "prevent-close") {
|
||||
onOpenChange(false);
|
||||
@ -139,10 +111,10 @@ export function ActionDialog(props: ActionDialogProps) {
|
||||
{...cancelButton.props}
|
||||
>
|
||||
{cancelButton.label ?? "Cancel"}
|
||||
</Button>
|
||||
</DesignButton>
|
||||
)}
|
||||
{okButton && (
|
||||
<Button
|
||||
<DesignButton
|
||||
disabled={okButtonDisabled}
|
||||
variant={props.danger ? "destructive" : "default"}
|
||||
onClick={async () => {
|
||||
@ -153,10 +125,35 @@ export function ActionDialog(props: ActionDialogProps) {
|
||||
{...okButtonProps}
|
||||
>
|
||||
{okButton.label ?? "OK"}
|
||||
</Button>
|
||||
</DesignButton>
|
||||
)}
|
||||
</DialogFooter>}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
) : undefined}
|
||||
>
|
||||
<Suspense fallback={
|
||||
<>
|
||||
<Skeleton className='h-9 w-2/3 self-center' />
|
||||
|
||||
<Skeleton className='h-3 w-16 mt-8' />
|
||||
<Skeleton className='h-9 w-full mt-1' />
|
||||
|
||||
<Skeleton className='h-3 w-24 mt-2' />
|
||||
<Skeleton className='h-9 w-full mt-1' />
|
||||
|
||||
<Skeleton className='h-9 w-full mt-6' />
|
||||
</>
|
||||
}>
|
||||
{props.children}
|
||||
</Suspense>
|
||||
|
||||
{props.confirmText && (
|
||||
<Alert className="mt-4">
|
||||
<Label className="flex gap-4 items-center">
|
||||
<Checkbox id={confirmId} checked={confirmed} onCheckedChange={(v) => setConfirmed(!!v)}/>
|
||||
{props.confirmText}
|
||||
</Label>
|
||||
</Alert>
|
||||
)}
|
||||
</DesignDialog>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user