@windrun-huaiin/third-ui 16.0.1 → 20.1.0

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.
Files changed (30) hide show
  1. package/dist/clerk/fingerprint/fingerprint-provider.js +58 -49
  2. package/dist/clerk/fingerprint/fingerprint-provider.mjs +58 -49
  3. package/dist/main/alert-dialog/ads-alert-dialog.d.ts +15 -0
  4. package/dist/main/alert-dialog/ads-alert-dialog.js +24 -0
  5. package/dist/main/alert-dialog/ads-alert-dialog.mjs +22 -0
  6. package/dist/main/alert-dialog/confirm-dialog.d.ts +15 -0
  7. package/dist/main/alert-dialog/confirm-dialog.js +40 -0
  8. package/dist/main/alert-dialog/confirm-dialog.mjs +38 -0
  9. package/dist/main/alert-dialog/dialog-styles.d.ts +14 -0
  10. package/dist/main/alert-dialog/dialog-styles.js +35 -0
  11. package/dist/main/alert-dialog/dialog-styles.mjs +20 -0
  12. package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +12 -0
  13. package/dist/main/alert-dialog/high-priority-confirm-dialog.js +23 -0
  14. package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +21 -0
  15. package/dist/main/alert-dialog/index.d.ts +4 -0
  16. package/dist/main/alert-dialog/info-dialog.d.ts +13 -0
  17. package/dist/main/alert-dialog/info-dialog.js +50 -0
  18. package/dist/main/alert-dialog/info-dialog.mjs +48 -0
  19. package/dist/main/index.d.ts +1 -1
  20. package/dist/main/index.js +7 -1
  21. package/dist/main/index.mjs +4 -1
  22. package/package.json +4 -4
  23. package/src/clerk/fingerprint/fingerprint-provider.tsx +155 -62
  24. package/src/main/{ads-alert-dialog.tsx → alert-dialog/ads-alert-dialog.tsx} +46 -29
  25. package/src/main/alert-dialog/confirm-dialog.tsx +131 -0
  26. package/src/main/alert-dialog/dialog-styles.ts +73 -0
  27. package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +94 -0
  28. package/src/main/alert-dialog/index.ts +7 -0
  29. package/src/main/alert-dialog/info-dialog.tsx +139 -0
  30. package/src/main/index.ts +1 -1
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import { CircleAlertIcon, CircleQuestionMarkIcon, XIcon } from '@windrun-huaiin/base-ui/icons';
5
+ import { themeBgColor, themeIconColor } from '@windrun-huaiin/base-ui/lib';
6
+ import {
7
+ AlertDialog,
8
+ AlertDialogAction,
9
+ AlertDialogCancel,
10
+ AlertDialogContent,
11
+ AlertDialogDescription,
12
+ AlertDialogTitle,
13
+ } from '@windrun-huaiin/base-ui/ui';
14
+ import { cn } from '@windrun-huaiin/lib/utils';
15
+ import {
16
+ closeButtonClass,
17
+ dangerButtonClass,
18
+ dialogContentClass,
19
+ dialogDescriptionClass,
20
+ dialogFooterClass,
21
+ dialogHeaderClass,
22
+ dialogThemedOverlayClass,
23
+ dialogTitleClass,
24
+ primaryButtonClass,
25
+ secondaryButtonClass,
26
+ } from './dialog-styles';
27
+
28
+ export type ConfirmDialogType = 'normal' | 'danger';
29
+
30
+ interface ConfirmDialogProps {
31
+ open: boolean;
32
+ onOpenChange: (open: boolean) => void;
33
+ type?: ConfirmDialogType;
34
+ title: React.ReactNode;
35
+ description: React.ReactNode;
36
+ cancelText?: string;
37
+ confirmText?: string;
38
+ onCancel?: () => void;
39
+ onConfirm?: () => void;
40
+ }
41
+
42
+ const confirmTypeClassMap: Record<ConfirmDialogType, {
43
+ content: string;
44
+ iconWrap: string;
45
+ icon: string;
46
+ action: string;
47
+ Icon: typeof CircleQuestionMarkIcon;
48
+ }> = {
49
+ normal: {
50
+ content: '',
51
+ iconWrap: cn(themeBgColor, 'ring-0'),
52
+ icon: themeIconColor,
53
+ action: primaryButtonClass,
54
+ Icon: CircleQuestionMarkIcon,
55
+ },
56
+ danger: {
57
+ content: 'border-red-300 dark:border-red-700',
58
+ iconWrap: 'bg-red-100 text-red-600 ring-red-200 dark:bg-red-950 dark:text-red-300 dark:ring-red-900',
59
+ icon: 'text-red-600 dark:text-red-300',
60
+ action: dangerButtonClass,
61
+ Icon: CircleAlertIcon,
62
+ },
63
+ };
64
+
65
+ export function ConfirmDialog({
66
+ open,
67
+ onOpenChange,
68
+ type = 'normal',
69
+ title,
70
+ description,
71
+ cancelText = 'Cancel',
72
+ confirmText = 'Confirm',
73
+ onCancel,
74
+ onConfirm,
75
+ }: ConfirmDialogProps) {
76
+ const typeClass = confirmTypeClassMap[type];
77
+ const Icon = typeClass.Icon;
78
+
79
+ const handleCancel = () => {
80
+ onOpenChange(false);
81
+ onCancel?.();
82
+ };
83
+
84
+ return (
85
+ <AlertDialog open={open} onOpenChange={onOpenChange}>
86
+ <AlertDialogContent
87
+ className={cn(dialogContentClass, typeClass.content)}
88
+ overlayClassName={dialogThemedOverlayClass}
89
+ onOverlayClick={handleCancel}
90
+ >
91
+ <div className={dialogHeaderClass}>
92
+ <AlertDialogTitle asChild>
93
+ <div className={dialogTitleClass}>
94
+ <span className={cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', typeClass.iconWrap)}>
95
+ <Icon className={cn('size-5', typeClass.icon)} />
96
+ </span>
97
+ <span className="min-w-0 truncate">{title}</span>
98
+ </div>
99
+ </AlertDialogTitle>
100
+ <button
101
+ type="button"
102
+ className={closeButtonClass}
103
+ onClick={handleCancel}
104
+ aria-label="Close"
105
+ >
106
+ <XIcon className="size-4" />
107
+ </button>
108
+ </div>
109
+
110
+ <AlertDialogDescription className={dialogDescriptionClass}>
111
+ {description}
112
+ </AlertDialogDescription>
113
+
114
+ <div className={dialogFooterClass}>
115
+ <AlertDialogCancel className={secondaryButtonClass} onClick={handleCancel}>
116
+ {cancelText}
117
+ </AlertDialogCancel>
118
+ <AlertDialogAction
119
+ className={typeClass.action}
120
+ onClick={() => {
121
+ onOpenChange(false);
122
+ onConfirm?.();
123
+ }}
124
+ >
125
+ {confirmText}
126
+ </AlertDialogAction>
127
+ </div>
128
+ </AlertDialogContent>
129
+ </AlertDialog>
130
+ );
131
+ }
@@ -0,0 +1,73 @@
1
+ 'use client';
2
+
3
+ import {
4
+ themeBgColor,
5
+ themeBorderColor,
6
+ themeButtonGradientClass,
7
+ themeButtonGradientHoverClass,
8
+ themeIconColor,
9
+ themeMainBgColor,
10
+ themeRingColor,
11
+ } from '@windrun-huaiin/base-ui/lib';
12
+ import { cn } from '@windrun-huaiin/lib/utils';
13
+
14
+ export const dialogSurfaceClass = cn(
15
+ 'w-[calc(100vw-2rem)] max-w-md rounded-2xl border bg-white p-5 text-neutral-950 shadow-2xl outline-none dark:bg-neutral-950 dark:text-neutral-50',
16
+ 'border-neutral-200 dark:border-neutral-800'
17
+ );
18
+
19
+ export const dialogThemedOverlayClass = cn(
20
+ themeMainBgColor,
21
+ 'opacity-90 backdrop-blur-[2px] dark:opacity-85'
22
+ );
23
+
24
+ export const dialogContentClass = cn(
25
+ 'fixed left-1/2 top-1/2 z-50 -translate-x-1/2 -translate-y-1/2',
26
+ dialogSurfaceClass
27
+ );
28
+
29
+ export const dialogHeaderClass = 'flex items-start justify-between gap-4';
30
+
31
+ export const dialogTitleClass =
32
+ 'flex min-w-0 items-center gap-2 text-lg font-bold leading-tight text-neutral-950 dark:text-neutral-50';
33
+
34
+ export const dialogDescriptionClass =
35
+ 'mt-3 text-sm font-medium leading-relaxed text-neutral-600 dark:text-neutral-300';
36
+
37
+ export const dialogFooterClass = 'mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end';
38
+
39
+ export const closeButtonClass =
40
+ 'inline-flex size-8 shrink-0 items-center justify-center rounded-full text-neutral-400 transition hover:bg-neutral-100 hover:text-neutral-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-neutral-200';
41
+
42
+ export const secondaryButtonClass =
43
+ 'inline-flex min-h-10 items-center justify-center rounded-full border border-neutral-300 bg-white px-5 py-2 text-sm font-semibold text-neutral-700 transition hover:bg-neutral-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 disabled:pointer-events-none disabled:opacity-60 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200 dark:hover:bg-neutral-800';
44
+
45
+ export const primaryButtonClass = cn(
46
+ 'inline-flex min-h-10 items-center justify-center rounded-full px-5 py-2 text-sm font-bold text-white shadow-sm transition hover:shadow-md focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-60',
47
+ themeButtonGradientClass,
48
+ themeButtonGradientHoverClass,
49
+ themeRingColor
50
+ );
51
+
52
+ export const subtlePrimaryButtonClass = cn(
53
+ 'inline-flex min-h-10 items-center justify-center rounded-full border px-5 py-2 text-sm font-bold transition hover:brightness-95 focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-60',
54
+ themeBgColor,
55
+ themeBorderColor,
56
+ themeIconColor,
57
+ themeRingColor
58
+ );
59
+
60
+ export const dangerButtonClass =
61
+ 'inline-flex min-h-10 items-center justify-center rounded-full bg-red-600 px-5 py-2 text-sm font-bold text-white shadow-sm transition hover:bg-red-700 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-500 disabled:pointer-events-none disabled:opacity-60 dark:bg-red-600 dark:hover:bg-red-500';
62
+
63
+ export const highPriorityTitleClass = cn(
64
+ 'flex min-w-0 items-center gap-2 text-lg font-bold leading-tight',
65
+ themeIconColor
66
+ );
67
+
68
+ export const highPrioritySurfaceClass = cn(
69
+ dialogSurfaceClass,
70
+ 'backdrop-blur-md ring-4 animate-in zoom-in-95 duration-300',
71
+ themeBorderColor,
72
+ themeRingColor
73
+ );
@@ -0,0 +1,94 @@
1
+ "use client";
2
+
3
+ import React, { useEffect, useState } from "react";
4
+ import { createPortal } from "react-dom";
5
+ import { FAQSIcon, XIcon } from "@windrun-huaiin/base-ui/icons";
6
+ import { cn } from "@windrun-huaiin/lib/utils";
7
+ import {
8
+ closeButtonClass,
9
+ dialogDescriptionClass,
10
+ dialogFooterClass,
11
+ dialogHeaderClass,
12
+ highPrioritySurfaceClass,
13
+ highPriorityTitleClass,
14
+ primaryButtonClass,
15
+ secondaryButtonClass,
16
+ } from "./dialog-styles";
17
+ import { themeBgColor, themeBorderColor, themeIconColor } from "@windrun-huaiin/base-ui/lib";
18
+
19
+ interface HighPriorityConfirmDialogProps {
20
+ open: boolean;
21
+ onCancel: () => void;
22
+ onConfirm: () => void;
23
+ title: string;
24
+ description: React.ReactNode;
25
+ confirmText?: string;
26
+ cancelText?: string;
27
+ }
28
+
29
+ export function HighPriorityConfirmDialog({
30
+ open,
31
+ onCancel,
32
+ onConfirm,
33
+ title,
34
+ description,
35
+ confirmText = "Confirm",
36
+ cancelText = "Cancel",
37
+ }: HighPriorityConfirmDialogProps) {
38
+ const [mounted, setMounted] = useState(false);
39
+
40
+ useEffect(() => {
41
+ // Ensure portal target exists and prevent hydration mismatch
42
+ setTimeout(() => setMounted(true), 0);
43
+ }, []);
44
+
45
+ if (!open || !mounted) return null;
46
+
47
+ return createPortal(
48
+ <div className="fixed inset-0 z-10000 flex items-center justify-center bg-black/60 backdrop-blur-sm animate-in fade-in duration-300">
49
+ <div
50
+ className={cn(highPrioritySurfaceClass, "scale-100")}
51
+ role="dialog"
52
+ aria-modal="true"
53
+ onClick={(e) => e.stopPropagation()}
54
+ >
55
+ <div className={dialogHeaderClass}>
56
+ <h3 className={highPriorityTitleClass}>
57
+ <span className={cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', themeBgColor, themeBorderColor)}>
58
+ <FAQSIcon className={cn('size-5', themeIconColor)} />
59
+ </span>
60
+ <span className="min-w-0 truncate">{title}</span>
61
+ </h3>
62
+ <button
63
+ type="button"
64
+ className={closeButtonClass}
65
+ onClick={onCancel}
66
+ aria-label="Close"
67
+ >
68
+ <XIcon className="size-4" />
69
+ </button>
70
+ </div>
71
+ <div className={dialogDescriptionClass}>
72
+ {description}
73
+ </div>
74
+ <div className={dialogFooterClass}>
75
+ <button
76
+ type="button"
77
+ onClick={onCancel}
78
+ className={secondaryButtonClass}
79
+ >
80
+ {cancelText}
81
+ </button>
82
+ <button
83
+ type="button"
84
+ onClick={onConfirm}
85
+ className={cn(primaryButtonClass, "hover:scale-105 active:scale-95")}
86
+ >
87
+ {confirmText}
88
+ </button>
89
+ </div>
90
+ </div>
91
+ </div>,
92
+ document.body
93
+ );
94
+ }
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+
3
+ export * from './ads-alert-dialog';
4
+ export * from './confirm-dialog';
5
+ export * from './high-priority-confirm-dialog';
6
+ export * from './info-dialog';
7
+
@@ -0,0 +1,139 @@
1
+ 'use client';
2
+
3
+ import React from 'react';
4
+ import {
5
+ BadgeAlertIcon,
6
+ BadgeCheckIcon,
7
+ BadgeInfoIcon,
8
+ BadgeXIcon,
9
+ XIcon,
10
+ } from '@windrun-huaiin/base-ui/icons';
11
+ import {
12
+ AlertDialog,
13
+ AlertDialogAction,
14
+ AlertDialogContent,
15
+ AlertDialogDescription,
16
+ AlertDialogTitle,
17
+ } from '@windrun-huaiin/base-ui/ui';
18
+ import { cn } from '@windrun-huaiin/lib/utils';
19
+ import {
20
+ closeButtonClass,
21
+ dialogContentClass,
22
+ dialogDescriptionClass,
23
+ dialogFooterClass,
24
+ dialogHeaderClass,
25
+ dialogThemedOverlayClass,
26
+ dialogTitleClass,
27
+ } from './dialog-styles';
28
+
29
+ export type InfoDialogType = 'info' | 'warn' | 'success' | 'error';
30
+ type InfoDialogIcon = typeof BadgeInfoIcon;
31
+
32
+ interface InfoDialogProps {
33
+ open: boolean;
34
+ onOpenChange: (open: boolean) => void;
35
+ type?: InfoDialogType;
36
+ title: React.ReactNode;
37
+ description: React.ReactNode;
38
+ confirmText?: string;
39
+ onConfirm?: () => void;
40
+ }
41
+
42
+ const infoTypeClassMap: Record<InfoDialogType, {
43
+ content: string;
44
+ iconWrap: string;
45
+ icon: string;
46
+ action: string;
47
+ Icon: InfoDialogIcon;
48
+ }> = {
49
+ info: {
50
+ content: 'border-sky-300 dark:border-sky-700',
51
+ iconWrap: 'bg-sky-100 text-sky-600 ring-sky-200 dark:bg-sky-950 dark:text-sky-300 dark:ring-sky-900',
52
+ icon: 'text-sky-600 dark:text-sky-300',
53
+ action: 'bg-sky-600 text-white hover:bg-sky-700 focus-visible:ring-sky-500 dark:bg-sky-500 dark:hover:bg-sky-400',
54
+ Icon: BadgeInfoIcon,
55
+ },
56
+ warn: {
57
+ content: 'border-amber-300 dark:border-amber-700',
58
+ iconWrap: 'bg-amber-100 text-amber-700 ring-amber-200 dark:bg-amber-950 dark:text-amber-300 dark:ring-amber-900',
59
+ icon: 'text-amber-700 dark:text-amber-300',
60
+ action: 'bg-amber-600 text-white hover:bg-amber-700 focus-visible:ring-amber-500 dark:bg-amber-500 dark:hover:bg-amber-400',
61
+ Icon: BadgeAlertIcon,
62
+ },
63
+ success: {
64
+ content: 'border-emerald-300 dark:border-emerald-700',
65
+ iconWrap: 'bg-emerald-100 text-emerald-600 ring-emerald-200 dark:bg-emerald-950 dark:text-emerald-300 dark:ring-emerald-900',
66
+ icon: 'text-emerald-600 dark:text-emerald-300',
67
+ action: 'bg-emerald-600 text-white hover:bg-emerald-700 focus-visible:ring-emerald-500 dark:bg-emerald-500 dark:hover:bg-emerald-400',
68
+ Icon: BadgeCheckIcon,
69
+ },
70
+ error: {
71
+ content: 'border-red-300 dark:border-red-700',
72
+ iconWrap: 'bg-red-100 text-red-600 ring-red-200 dark:bg-red-950 dark:text-red-300 dark:ring-red-900',
73
+ icon: 'text-red-600 dark:text-red-300',
74
+ action: 'bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500 dark:bg-red-600 dark:hover:bg-red-500',
75
+ Icon: BadgeXIcon,
76
+ },
77
+ };
78
+
79
+ export function InfoDialog({
80
+ open,
81
+ onOpenChange,
82
+ type = 'info',
83
+ title,
84
+ description,
85
+ confirmText = 'OK',
86
+ onConfirm,
87
+ }: InfoDialogProps) {
88
+ const typeClass = infoTypeClassMap[type];
89
+ const Icon = typeClass.Icon;
90
+ const handleClose = () => onOpenChange(false);
91
+
92
+ return (
93
+ <AlertDialog open={open} onOpenChange={onOpenChange}>
94
+ <AlertDialogContent
95
+ className={cn(dialogContentClass, typeClass.content)}
96
+ overlayClassName={dialogThemedOverlayClass}
97
+ onOverlayClick={handleClose}
98
+ >
99
+ <div className={dialogHeaderClass}>
100
+ <AlertDialogTitle asChild>
101
+ <div className={dialogTitleClass}>
102
+ <span className={cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', typeClass.iconWrap)}>
103
+ <Icon className={cn('size-5', typeClass.icon)} />
104
+ </span>
105
+ <span className="min-w-0 truncate">{title}</span>
106
+ </div>
107
+ </AlertDialogTitle>
108
+ <button
109
+ type="button"
110
+ className={closeButtonClass}
111
+ onClick={handleClose}
112
+ aria-label="Close"
113
+ >
114
+ <XIcon className="size-4" />
115
+ </button>
116
+ </div>
117
+
118
+ <AlertDialogDescription className={dialogDescriptionClass}>
119
+ {description}
120
+ </AlertDialogDescription>
121
+
122
+ <div className={dialogFooterClass}>
123
+ <AlertDialogAction
124
+ className={cn(
125
+ 'inline-flex min-h-10 items-center justify-center rounded-full px-5 py-2 text-sm font-bold transition focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-60',
126
+ typeClass.action
127
+ )}
128
+ onClick={() => {
129
+ onOpenChange(false);
130
+ onConfirm?.();
131
+ }}
132
+ >
133
+ {confirmText}
134
+ </AlertDialogAction>
135
+ </div>
136
+ </AlertDialogContent>
137
+ </AlertDialog>
138
+ );
139
+ }
package/src/main/index.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  export * from './go-to-top';
5
5
  export * from './loading';
6
6
  export * from './nprogress-bar';
7
- export * from './ads-alert-dialog';
7
+ export * from './alert-dialog';
8
8
  export * from './x-button'
9
9
  export * from './x-toggle-button'
10
10
  export * from './ai-prompt-textarea'