@orsetra/shared-ui 1.0.39 → 1.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -18,7 +18,7 @@ const AlertDialogOverlay = React.forwardRef<
|
|
|
18
18
|
>(({ className, ...props }, ref) => (
|
|
19
19
|
<AlertDialogPrimitive.Overlay
|
|
20
20
|
className={cn(
|
|
21
|
-
"fixed inset-0 z-50 bg-
|
|
21
|
+
"fixed inset-0 z-50 bg-ibm-gray-100/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
22
22
|
className
|
|
23
23
|
)}
|
|
24
24
|
{...props}
|
|
@@ -32,11 +32,10 @@ const AlertDialogContent = React.forwardRef<
|
|
|
32
32
|
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
33
33
|
>(({ className, ...props }, ref) => (
|
|
34
34
|
<AlertDialogPortal>
|
|
35
|
-
<AlertDialogOverlay />
|
|
36
35
|
<AlertDialogPrimitive.Content
|
|
37
36
|
ref={ref}
|
|
38
37
|
className={cn(
|
|
39
|
-
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-
|
|
38
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-ibm-gray-20 bg-white p-6 shadow-xl duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
|
|
40
39
|
className
|
|
41
40
|
)}
|
|
42
41
|
{...props}
|
|
@@ -79,7 +78,7 @@ const AlertDialogTitle = React.forwardRef<
|
|
|
79
78
|
>(({ className, ...props }, ref) => (
|
|
80
79
|
<AlertDialogPrimitive.Title
|
|
81
80
|
ref={ref}
|
|
82
|
-
className={cn("text-lg font-semibold", className)}
|
|
81
|
+
className={cn("text-lg font-semibold text-ibm-gray-100", className)}
|
|
83
82
|
{...props}
|
|
84
83
|
/>
|
|
85
84
|
))
|
|
@@ -91,7 +90,7 @@ const AlertDialogDescription = React.forwardRef<
|
|
|
91
90
|
>(({ className, ...props }, ref) => (
|
|
92
91
|
<AlertDialogPrimitive.Description
|
|
93
92
|
ref={ref}
|
|
94
|
-
className={cn("text-sm text-
|
|
93
|
+
className={cn("text-sm text-ibm-gray-70", className)}
|
|
95
94
|
{...props}
|
|
96
95
|
/>
|
|
97
96
|
))
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useState, useEffect } from "react"
|
|
4
|
+
import {
|
|
5
|
+
AlertDialog,
|
|
6
|
+
AlertDialogAction,
|
|
7
|
+
AlertDialogCancel,
|
|
8
|
+
AlertDialogContent,
|
|
9
|
+
AlertDialogDescription,
|
|
10
|
+
AlertDialogFooter,
|
|
11
|
+
AlertDialogHeader,
|
|
12
|
+
AlertDialogTitle,
|
|
13
|
+
AlertDialogTrigger,
|
|
14
|
+
} from "./alert-dialog"
|
|
15
|
+
import { AlertBanner, useAlertBanner } from "./alert-banner"
|
|
16
|
+
import { Input } from "./input"
|
|
17
|
+
import { Label } from "./label"
|
|
18
|
+
import type { ReactNode } from "react"
|
|
19
|
+
|
|
20
|
+
export interface ConfirmationDialogProps {
|
|
21
|
+
trigger: ReactNode
|
|
22
|
+
title: string
|
|
23
|
+
description: string | ReactNode
|
|
24
|
+
confirmText?: string
|
|
25
|
+
cancelText?: string
|
|
26
|
+
confirmVariant?: "default" | "destructive"
|
|
27
|
+
onConfirm: () => void | Promise<void>
|
|
28
|
+
onCancel?: () => void
|
|
29
|
+
requireTextConfirmation?: {
|
|
30
|
+
expectedText: string
|
|
31
|
+
label?: string
|
|
32
|
+
placeholder?: string
|
|
33
|
+
}
|
|
34
|
+
open?: boolean
|
|
35
|
+
onOpenChange?: (open: boolean) => void
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function ConfirmationDialog({
|
|
39
|
+
trigger,
|
|
40
|
+
title,
|
|
41
|
+
description,
|
|
42
|
+
confirmText = "Confirm",
|
|
43
|
+
cancelText = "Cancel",
|
|
44
|
+
confirmVariant = "default",
|
|
45
|
+
onConfirm,
|
|
46
|
+
onCancel,
|
|
47
|
+
requireTextConfirmation,
|
|
48
|
+
open: controlledOpen,
|
|
49
|
+
onOpenChange: controlledOnOpenChange,
|
|
50
|
+
}: ConfirmationDialogProps) {
|
|
51
|
+
const { alert, showSuccess, showError, hideAlert } = useAlertBanner()
|
|
52
|
+
const [loading, setLoading] = useState(false)
|
|
53
|
+
const [internalOpen, setInternalOpen] = useState(false)
|
|
54
|
+
const [confirmationText, setConfirmationText] = useState("")
|
|
55
|
+
|
|
56
|
+
const isControlled = controlledOpen !== undefined
|
|
57
|
+
const open = isControlled ? controlledOpen : internalOpen
|
|
58
|
+
const setOpen = isControlled ? controlledOnOpenChange! : setInternalOpen
|
|
59
|
+
|
|
60
|
+
const isConfirmDisabled =
|
|
61
|
+
loading ||
|
|
62
|
+
(requireTextConfirmation &&
|
|
63
|
+
confirmationText !== requireTextConfirmation.expectedText)
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!open) {
|
|
67
|
+
setConfirmationText("")
|
|
68
|
+
hideAlert()
|
|
69
|
+
}
|
|
70
|
+
}, [open])
|
|
71
|
+
|
|
72
|
+
const handleConfirm = async () => {
|
|
73
|
+
setLoading(true)
|
|
74
|
+
hideAlert()
|
|
75
|
+
try {
|
|
76
|
+
await onConfirm()
|
|
77
|
+
setOpen(false)
|
|
78
|
+
} catch (error: any) {
|
|
79
|
+
showError(error?.message || "Operation failed")
|
|
80
|
+
} finally {
|
|
81
|
+
setLoading(false)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const handleCancel = () => {
|
|
86
|
+
onCancel?.()
|
|
87
|
+
setOpen(false)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const confirmButtonClass =
|
|
91
|
+
confirmVariant === "destructive"
|
|
92
|
+
? "bg-red-600 hover:bg-red-700"
|
|
93
|
+
: undefined
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<AlertDialog open={open} onOpenChange={setOpen}>
|
|
97
|
+
<AlertDialogTrigger asChild>{trigger}</AlertDialogTrigger>
|
|
98
|
+
<AlertDialogContent>
|
|
99
|
+
<AlertDialogHeader>
|
|
100
|
+
<AlertDialogTitle>{title}</AlertDialogTitle>
|
|
101
|
+
<AlertDialogDescription>{description}</AlertDialogDescription>
|
|
102
|
+
</AlertDialogHeader>
|
|
103
|
+
|
|
104
|
+
{alert.show && (
|
|
105
|
+
<AlertBanner
|
|
106
|
+
variant={alert.variant}
|
|
107
|
+
message={alert.message}
|
|
108
|
+
onClose={hideAlert}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
{requireTextConfirmation && (
|
|
113
|
+
<div className="space-y-2">
|
|
114
|
+
<Label htmlFor="confirmation-input">
|
|
115
|
+
{requireTextConfirmation.label ||
|
|
116
|
+
`Type "${requireTextConfirmation.expectedText}" to confirm`}
|
|
117
|
+
</Label>
|
|
118
|
+
<Input
|
|
119
|
+
id="confirmation-input"
|
|
120
|
+
value={confirmationText}
|
|
121
|
+
onChange={(e) => setConfirmationText(e.target.value)}
|
|
122
|
+
placeholder={
|
|
123
|
+
requireTextConfirmation.placeholder ||
|
|
124
|
+
requireTextConfirmation.expectedText
|
|
125
|
+
}
|
|
126
|
+
disabled={loading}
|
|
127
|
+
autoComplete="off"
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
<AlertDialogFooter className="mt-6">
|
|
133
|
+
<AlertDialogCancel disabled={loading} onClick={handleCancel}>
|
|
134
|
+
{cancelText}
|
|
135
|
+
</AlertDialogCancel>
|
|
136
|
+
<AlertDialogAction
|
|
137
|
+
className={confirmButtonClass}
|
|
138
|
+
onClick={handleConfirm}
|
|
139
|
+
disabled={isConfirmDisabled}
|
|
140
|
+
>
|
|
141
|
+
{confirmText}
|
|
142
|
+
</AlertDialogAction>
|
|
143
|
+
</AlertDialogFooter>
|
|
144
|
+
</AlertDialogContent>
|
|
145
|
+
</AlertDialog>
|
|
146
|
+
)
|
|
147
|
+
}
|
package/components/ui/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './
|
|
|
23
23
|
export { AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel } from './alert-dialog'
|
|
24
24
|
export { Alert, AlertTitle, AlertDescription } from './alert'
|
|
25
25
|
export { AlertBanner, useAlertBanner, type AlertBannerProps, type AlertState } from './alert-banner'
|
|
26
|
+
export { ConfirmationDialog, type ConfirmationDialogProps } from './confirmation-dialog'
|
|
26
27
|
export { AspectRatio } from './aspect-ratio'
|
|
27
28
|
export { Badge } from './badge'
|
|
28
29
|
export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis } from './breadcrumb'
|