@windrun-huaiin/third-ui 29.2.0 → 29.2.1
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.
- package/dist/main/alert-dialog/confirm-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/confirm-dialog.js +2 -2
- package/dist/main/alert-dialog/confirm-dialog.mjs +2 -2
- package/dist/main/alert-dialog/dialog-loading-action.d.ts +2 -1
- package/dist/main/alert-dialog/dialog-loading-action.js +2 -2
- package/dist/main/alert-dialog/dialog-loading-action.mjs +2 -2
- package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/high-priority-confirm-dialog.js +2 -2
- package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +2 -2
- package/dist/main/alert-dialog/info-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/info-dialog.js +2 -2
- package/dist/main/alert-dialog/info-dialog.mjs +2 -2
- package/dist/main/alert-dialog/undoable-confirm-dialog.d.ts +2 -1
- package/dist/main/alert-dialog/undoable-confirm-dialog.js +2 -2
- package/dist/main/alert-dialog/undoable-confirm-dialog.mjs +2 -2
- package/dist/main/calendar/random-date-range-dialog.d.ts +5 -2
- package/dist/main/calendar/random-date-range-dialog.js +74 -70
- package/dist/main/calendar/random-date-range-dialog.mjs +76 -72
- package/package.json +3 -3
- package/src/main/alert-dialog/confirm-dialog.tsx +3 -1
- package/src/main/alert-dialog/dialog-loading-action.tsx +18 -3
- package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +3 -1
- package/src/main/alert-dialog/info-dialog.tsx +3 -1
- package/src/main/alert-dialog/undoable-confirm-dialog.tsx +3 -1
- package/src/main/calendar/random-date-range-dialog.tsx +19 -7
|
@@ -12,8 +12,9 @@ interface ConfirmDialogProps {
|
|
|
12
12
|
confirmText?: string;
|
|
13
13
|
emphasis?: ConfirmDialogEmphasis;
|
|
14
14
|
loadingActions?: readonly DialogLoadingAction[];
|
|
15
|
+
loadingFullPage?: boolean;
|
|
15
16
|
onCancel?: DialogActionHandler;
|
|
16
17
|
onConfirm?: DialogActionHandler;
|
|
17
18
|
}
|
|
18
|
-
export declare function ConfirmDialog({ open, onOpenChange, type, title, description, cancelText, confirmText, emphasis, loadingActions, onCancel, onConfirm, }: ConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
export declare function ConfirmDialog({ open, onOpenChange, type, title, description, cancelText, confirmText, emphasis, loadingActions, loadingFullPage, onCancel, onConfirm, }: ConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
19
20
|
export {};
|
|
@@ -25,12 +25,12 @@ const confirmTypeClassMap = {
|
|
|
25
25
|
Icon: icons.CircleAlertIcon,
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
|
-
function ConfirmDialog({ open, onOpenChange, type = 'normal', title, description, cancelText = 'Cancel', confirmText = 'Confirm', emphasis = 'confirm', loadingActions, onCancel, onConfirm, }) {
|
|
28
|
+
function ConfirmDialog({ open, onOpenChange, type = 'normal', title, description, cancelText = 'Cancel', confirmText = 'Confirm', emphasis = 'confirm', loadingActions, loadingFullPage, onCancel, onConfirm, }) {
|
|
29
29
|
const typeClass = confirmTypeClassMap[type];
|
|
30
30
|
const Icon = typeClass.Icon;
|
|
31
31
|
const cancelButtonClass = emphasis === 'cancel' ? typeClass.action : dialogStyles.secondaryButtonClass;
|
|
32
32
|
const confirmButtonClass = emphasis === 'cancel' ? dialogStyles.secondaryButtonClass : typeClass.action;
|
|
33
|
-
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
33
|
+
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
34
34
|
const handleCancel = () => {
|
|
35
35
|
void runDialogAction('cancel', onCancel);
|
|
36
36
|
};
|
|
@@ -23,12 +23,12 @@ const confirmTypeClassMap = {
|
|
|
23
23
|
Icon: CircleAlertIcon,
|
|
24
24
|
},
|
|
25
25
|
};
|
|
26
|
-
function ConfirmDialog({ open, onOpenChange, type = 'normal', title, description, cancelText = 'Cancel', confirmText = 'Confirm', emphasis = 'confirm', loadingActions, onCancel, onConfirm, }) {
|
|
26
|
+
function ConfirmDialog({ open, onOpenChange, type = 'normal', title, description, cancelText = 'Cancel', confirmText = 'Confirm', emphasis = 'confirm', loadingActions, loadingFullPage, onCancel, onConfirm, }) {
|
|
27
27
|
const typeClass = confirmTypeClassMap[type];
|
|
28
28
|
const Icon = typeClass.Icon;
|
|
29
29
|
const cancelButtonClass = emphasis === 'cancel' ? typeClass.action : secondaryButtonClass;
|
|
30
30
|
const confirmButtonClass = emphasis === 'cancel' ? secondaryButtonClass : typeClass.action;
|
|
31
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
31
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
32
32
|
const handleCancel = () => {
|
|
33
33
|
void runDialogAction('cancel', onCancel);
|
|
34
34
|
};
|
|
@@ -3,9 +3,10 @@ export type DialogLoadingAction = 'cancel' | 'confirm' | 'undo';
|
|
|
3
3
|
export type DialogActionHandler = () => void | Promise<void>;
|
|
4
4
|
interface UseDialogLoadingActionOptions {
|
|
5
5
|
loadingActions?: readonly DialogLoadingAction[];
|
|
6
|
+
loadingFullPage?: boolean;
|
|
6
7
|
onOpenChange: (open: boolean) => void;
|
|
7
8
|
}
|
|
8
|
-
export declare function useDialogLoadingAction({ loadingActions, onOpenChange, }: UseDialogLoadingActionOptions): {
|
|
9
|
+
export declare function useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange, }: UseDialogLoadingActionOptions): {
|
|
9
10
|
dialogLoading: React.ReactPortal | null;
|
|
10
11
|
runDialogAction: (action: DialogLoadingAction, handler?: DialogActionHandler) => Promise<void>;
|
|
11
12
|
};
|
|
@@ -7,7 +7,7 @@ var React = require('react');
|
|
|
7
7
|
var reactDom = require('react-dom');
|
|
8
8
|
var loading = require('../loading.js');
|
|
9
9
|
|
|
10
|
-
function useDialogLoadingAction({ loadingActions, onOpenChange, }) {
|
|
10
|
+
function useDialogLoadingAction({ loadingActions, loadingFullPage = false, onOpenChange, }) {
|
|
11
11
|
const [mounted, setMounted] = React.useState(false);
|
|
12
12
|
const [loading$1, setLoading] = React.useState(false);
|
|
13
13
|
React.useEffect(() => {
|
|
@@ -31,7 +31,7 @@ function useDialogLoadingAction({ loadingActions, onOpenChange, }) {
|
|
|
31
31
|
}
|
|
32
32
|
}), [loadingActions, onOpenChange]);
|
|
33
33
|
const dialogLoading = mounted && loading$1
|
|
34
|
-
? reactDom.createPortal(jsxRuntime.jsx("div", { className: "fixed inset-0 z-10000", children: jsxRuntime.jsx(loading.Loading, { className: "h-full w-full" }) }), document.body)
|
|
34
|
+
? reactDom.createPortal(loadingFullPage ? (jsxRuntime.jsx("div", { className: "fixed inset-0 z-10000", children: jsxRuntime.jsx(loading.Loading, { className: "h-full w-full" }) })) : (jsxRuntime.jsx("div", { className: "pointer-events-none fixed inset-0 z-10000 flex items-center justify-center p-4", children: jsxRuntime.jsx("div", { className: "pointer-events-auto overflow-hidden rounded-[28px] bg-neutral-50/58 shadow-[0_18px_56px_rgba(15,23,42,0.14)] backdrop-blur-md dark:bg-neutral-900/58 dark:shadow-[0_18px_56px_rgba(0,0,0,0.34)]", children: jsxRuntime.jsx(loading.Loading, { compact: true, label: "Loading", className: "min-h-[250px] w-[min(22rem,calc(100vw-2rem))] bg-transparent", labelClassName: "text-foreground" }) }) })), document.body)
|
|
35
35
|
: null;
|
|
36
36
|
return {
|
|
37
37
|
dialogLoading,
|
|
@@ -5,7 +5,7 @@ import React__default from 'react';
|
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
import { Loading } from '../loading.mjs';
|
|
7
7
|
|
|
8
|
-
function useDialogLoadingAction({ loadingActions, onOpenChange, }) {
|
|
8
|
+
function useDialogLoadingAction({ loadingActions, loadingFullPage = false, onOpenChange, }) {
|
|
9
9
|
const [mounted, setMounted] = React__default.useState(false);
|
|
10
10
|
const [loading, setLoading] = React__default.useState(false);
|
|
11
11
|
React__default.useEffect(() => {
|
|
@@ -29,7 +29,7 @@ function useDialogLoadingAction({ loadingActions, onOpenChange, }) {
|
|
|
29
29
|
}
|
|
30
30
|
}), [loadingActions, onOpenChange]);
|
|
31
31
|
const dialogLoading = mounted && loading
|
|
32
|
-
? createPortal(jsx("div", { className: "fixed inset-0 z-10000", children: jsx(Loading, { className: "h-full w-full" }) }), document.body)
|
|
32
|
+
? createPortal(loadingFullPage ? (jsx("div", { className: "fixed inset-0 z-10000", children: jsx(Loading, { className: "h-full w-full" }) })) : (jsx("div", { className: "pointer-events-none fixed inset-0 z-10000 flex items-center justify-center p-4", children: jsx("div", { className: "pointer-events-auto overflow-hidden rounded-[28px] bg-neutral-50/58 shadow-[0_18px_56px_rgba(15,23,42,0.14)] backdrop-blur-md dark:bg-neutral-900/58 dark:shadow-[0_18px_56px_rgba(0,0,0,0.34)]", children: jsx(Loading, { compact: true, label: "Loading", className: "min-h-[250px] w-[min(22rem,calc(100vw-2rem))] bg-transparent", labelClassName: "text-foreground" }) }) })), document.body)
|
|
33
33
|
: null;
|
|
34
34
|
return {
|
|
35
35
|
dialogLoading,
|
|
@@ -10,6 +10,7 @@ interface HighPriorityConfirmDialogProps {
|
|
|
10
10
|
confirmText?: string;
|
|
11
11
|
cancelText?: string;
|
|
12
12
|
loadingActions?: readonly DialogLoadingAction[];
|
|
13
|
+
loadingFullPage?: boolean;
|
|
13
14
|
}
|
|
14
|
-
export declare function HighPriorityConfirmDialog({ open, onOpenChange, onCancel, onConfirm, title, description, confirmText, cancelText, loadingActions, }: HighPriorityConfirmDialogProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
|
+
export declare function HighPriorityConfirmDialog({ open, onOpenChange, onCancel, onConfirm, title, description, confirmText, cancelText, loadingActions, loadingFullPage, }: HighPriorityConfirmDialogProps): import("react/jsx-runtime").JSX.Element | null;
|
|
15
16
|
export {};
|
|
@@ -10,9 +10,9 @@ var dialogStyles = require('./dialog-styles.js');
|
|
|
10
10
|
var lib = require('@windrun-huaiin/base-ui/lib');
|
|
11
11
|
var dialogLoadingAction = require('./dialog-loading-action.js');
|
|
12
12
|
|
|
13
|
-
function HighPriorityConfirmDialog({ open, onOpenChange, onCancel, onConfirm, title, description, confirmText = "Confirm", cancelText = "Cancel", loadingActions, }) {
|
|
13
|
+
function HighPriorityConfirmDialog({ open, onOpenChange, onCancel, onConfirm, title, description, confirmText = "Confirm", cancelText = "Cancel", loadingActions, loadingFullPage, }) {
|
|
14
14
|
const [mounted, setMounted] = React.useState(false);
|
|
15
|
-
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
15
|
+
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
16
16
|
React.useEffect(() => {
|
|
17
17
|
// Ensure portal target exists and prevent hydration mismatch
|
|
18
18
|
setTimeout(() => setMounted(true), 0);
|
|
@@ -8,9 +8,9 @@ import { dialogHeaderClass, highPriorityTitleClass, closeButtonClass, dialogDesc
|
|
|
8
8
|
import { themeIconColor, themeBgColor, themeBorderColor } from '@windrun-huaiin/base-ui/lib';
|
|
9
9
|
import { useDialogLoadingAction } from './dialog-loading-action.mjs';
|
|
10
10
|
|
|
11
|
-
function HighPriorityConfirmDialog({ open, onOpenChange, onCancel, onConfirm, title, description, confirmText = "Confirm", cancelText = "Cancel", loadingActions, }) {
|
|
11
|
+
function HighPriorityConfirmDialog({ open, onOpenChange, onCancel, onConfirm, title, description, confirmText = "Confirm", cancelText = "Cancel", loadingActions, loadingFullPage, }) {
|
|
12
12
|
const [mounted, setMounted] = useState(false);
|
|
13
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
13
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
// Ensure portal target exists and prevent hydration mismatch
|
|
16
16
|
setTimeout(() => setMounted(true), 0);
|
|
@@ -9,7 +9,8 @@ interface InfoDialogProps {
|
|
|
9
9
|
description: React.ReactNode;
|
|
10
10
|
confirmText?: string;
|
|
11
11
|
loadingActions?: readonly DialogLoadingAction[];
|
|
12
|
+
loadingFullPage?: boolean;
|
|
12
13
|
onConfirm?: DialogActionHandler;
|
|
13
14
|
}
|
|
14
|
-
export declare function InfoDialog({ open, onOpenChange, type, title, description, confirmText, loadingActions, onConfirm, }: InfoDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function InfoDialog({ open, onOpenChange, type, title, description, confirmText, loadingActions, loadingFullPage, onConfirm, }: InfoDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
15
16
|
export {};
|
|
@@ -38,11 +38,11 @@ const infoTypeClassMap = {
|
|
|
38
38
|
Icon: icons.BadgeXIcon,
|
|
39
39
|
},
|
|
40
40
|
};
|
|
41
|
-
function InfoDialog({ open, onOpenChange, type = 'info', title, description, confirmText = 'OK', loadingActions, onConfirm, }) {
|
|
41
|
+
function InfoDialog({ open, onOpenChange, type = 'info', title, description, confirmText = 'OK', loadingActions, loadingFullPage, onConfirm, }) {
|
|
42
42
|
const typeClass = infoTypeClassMap[type];
|
|
43
43
|
const Icon = typeClass.Icon;
|
|
44
44
|
const handleClose = () => onOpenChange(false);
|
|
45
|
-
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
45
|
+
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
46
46
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(ui.AlertDialog, { open: open, onOpenChange: onOpenChange, children: jsxRuntime.jsxs(ui.AlertDialogContent, { className: utils.cn(dialogStyles.dialogContentClass, typeClass.content), overlayClassName: dialogStyles.dialogThemedOverlayClass, onOverlayClick: handleClose, children: [jsxRuntime.jsxs("div", { className: dialogStyles.dialogHeaderClass, children: [jsxRuntime.jsx(ui.AlertDialogTitle, { asChild: true, children: jsxRuntime.jsxs("div", { className: dialogStyles.dialogTitleClass, children: [jsxRuntime.jsx("span", { className: utils.cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', typeClass.iconWrap), children: jsxRuntime.jsx(Icon, { className: utils.cn('size-5', typeClass.icon) }) }), jsxRuntime.jsx("span", { className: "min-w-0 truncate", children: title })] }) }), jsxRuntime.jsx("button", { type: "button", className: dialogStyles.closeButtonClass, onClick: handleClose, "aria-label": "Close", children: jsxRuntime.jsx(icons.XIcon, { className: "size-4" }) })] }), jsxRuntime.jsx(ui.AlertDialogDescription, { className: dialogStyles.dialogDescriptionClass, children: description }), jsxRuntime.jsx("div", { className: dialogStyles.dialogFooterClass, children: jsxRuntime.jsx(ui.AlertDialogAction, { className: utils.cn('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', typeClass.action), onClick: () => {
|
|
47
47
|
void runDialogAction('confirm', onConfirm);
|
|
48
48
|
}, children: confirmText }) })] }) }), dialogLoading] }));
|
|
@@ -36,11 +36,11 @@ const infoTypeClassMap = {
|
|
|
36
36
|
Icon: BadgeXIcon,
|
|
37
37
|
},
|
|
38
38
|
};
|
|
39
|
-
function InfoDialog({ open, onOpenChange, type = 'info', title, description, confirmText = 'OK', loadingActions, onConfirm, }) {
|
|
39
|
+
function InfoDialog({ open, onOpenChange, type = 'info', title, description, confirmText = 'OK', loadingActions, loadingFullPage, onConfirm, }) {
|
|
40
40
|
const typeClass = infoTypeClassMap[type];
|
|
41
41
|
const Icon = typeClass.Icon;
|
|
42
42
|
const handleClose = () => onOpenChange(false);
|
|
43
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
43
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
44
44
|
return (jsxs(Fragment, { children: [jsx(AlertDialog, { open: open, onOpenChange: onOpenChange, children: jsxs(AlertDialogContent, { className: cn(dialogContentClass, typeClass.content), overlayClassName: dialogThemedOverlayClass, onOverlayClick: handleClose, children: [jsxs("div", { className: dialogHeaderClass, children: [jsx(AlertDialogTitle, { asChild: true, children: jsxs("div", { className: dialogTitleClass, children: [jsx("span", { className: cn('inline-flex size-9 shrink-0 items-center justify-center rounded-full ring-1', typeClass.iconWrap), children: jsx(Icon, { className: cn('size-5', typeClass.icon) }) }), jsx("span", { className: "min-w-0 truncate", children: title })] }) }), jsx("button", { type: "button", className: closeButtonClass, onClick: handleClose, "aria-label": "Close", children: jsx(XIcon, { className: "size-4" }) })] }), jsx(AlertDialogDescription, { className: dialogDescriptionClass, children: description }), jsx("div", { className: dialogFooterClass, children: jsx(AlertDialogAction, { className: cn('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', typeClass.action), onClick: () => {
|
|
45
45
|
void runDialogAction('confirm', onConfirm);
|
|
46
46
|
}, children: confirmText }) })] }) }), dialogLoading] }));
|
|
@@ -14,8 +14,9 @@ export interface UndoableConfirmDialogProps {
|
|
|
14
14
|
emphasis?: ConfirmDialogEmphasis;
|
|
15
15
|
countdownSeconds?: number;
|
|
16
16
|
loadingActions?: readonly DialogLoadingAction[];
|
|
17
|
+
loadingFullPage?: boolean;
|
|
17
18
|
onCancel?: DialogActionHandler;
|
|
18
19
|
onConfirm: DialogActionHandler;
|
|
19
20
|
onUndo?: DialogActionHandler;
|
|
20
21
|
}
|
|
21
|
-
export declare function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText, confirmText, undoText, emphasis, countdownSeconds, loadingActions, onCancel, onConfirm, onUndo, }: UndoableConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
export declare function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText, confirmText, undoText, emphasis, countdownSeconds, loadingActions, loadingFullPage, onCancel, onConfirm, onUndo, }: UndoableConfirmDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -11,7 +11,7 @@ var utils = require('@windrun-huaiin/lib/utils');
|
|
|
11
11
|
var dialogStyles = require('./dialog-styles.js');
|
|
12
12
|
var dialogLoadingAction = require('./dialog-loading-action.js');
|
|
13
13
|
|
|
14
|
-
function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText = 'Cancel', confirmText = 'Delete', undoText = 'Undo', emphasis = 'confirm', countdownSeconds = 5, loadingActions, onCancel, onConfirm, onUndo, }) {
|
|
14
|
+
function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText = 'Cancel', confirmText = 'Delete', undoText = 'Undo', emphasis = 'confirm', countdownSeconds = 5, loadingActions, loadingFullPage, onCancel, onConfirm, onUndo, }) {
|
|
15
15
|
const safeCountdownSeconds = Math.max(1, Math.floor(countdownSeconds));
|
|
16
16
|
const [pending, setPending] = React.useState(false);
|
|
17
17
|
const [remainingSeconds, setRemainingSeconds] = React.useState(safeCountdownSeconds);
|
|
@@ -20,7 +20,7 @@ function UndoableConfirmDialog({ open, onOpenChange, title, description, pending
|
|
|
20
20
|
const intervalRef = React.useRef(null);
|
|
21
21
|
const cancelButtonClass = emphasis === 'cancel' ? dialogStyles.dangerButtonClass : dialogStyles.secondaryButtonClass;
|
|
22
22
|
const confirmButtonClass = emphasis === 'cancel' ? dialogStyles.secondaryButtonClass : dialogStyles.dangerButtonClass;
|
|
23
|
-
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
23
|
+
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
24
24
|
const clearTimers = React.useCallback(() => {
|
|
25
25
|
if (timeoutRef.current) {
|
|
26
26
|
window.clearTimeout(timeoutRef.current);
|
|
@@ -9,7 +9,7 @@ import { cn } from '@windrun-huaiin/lib/utils';
|
|
|
9
9
|
import { dialogThemedOverlayClass, dialogHeaderClass, dialogTitleClass, closeButtonClass, dialogDescriptionClass, secondaryButtonClass, dangerButtonClass, dialogFooterClass, dialogContentClass } from './dialog-styles.mjs';
|
|
10
10
|
import { useDialogLoadingAction } from './dialog-loading-action.mjs';
|
|
11
11
|
|
|
12
|
-
function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText = 'Cancel', confirmText = 'Delete', undoText = 'Undo', emphasis = 'confirm', countdownSeconds = 5, loadingActions, onCancel, onConfirm, onUndo, }) {
|
|
12
|
+
function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText = 'Cancel', confirmText = 'Delete', undoText = 'Undo', emphasis = 'confirm', countdownSeconds = 5, loadingActions, loadingFullPage, onCancel, onConfirm, onUndo, }) {
|
|
13
13
|
const safeCountdownSeconds = Math.max(1, Math.floor(countdownSeconds));
|
|
14
14
|
const [pending, setPending] = React__default.useState(false);
|
|
15
15
|
const [remainingSeconds, setRemainingSeconds] = React__default.useState(safeCountdownSeconds);
|
|
@@ -18,7 +18,7 @@ function UndoableConfirmDialog({ open, onOpenChange, title, description, pending
|
|
|
18
18
|
const intervalRef = React__default.useRef(null);
|
|
19
19
|
const cancelButtonClass = emphasis === 'cancel' ? dangerButtonClass : secondaryButtonClass;
|
|
20
20
|
const confirmButtonClass = emphasis === 'cancel' ? secondaryButtonClass : dangerButtonClass;
|
|
21
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
21
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
22
22
|
const clearTimers = React__default.useCallback(() => {
|
|
23
23
|
if (timeoutRef.current) {
|
|
24
24
|
window.clearTimeout(timeoutRef.current);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DialogLoadingAction } from '../alert-dialog/dialog-loading-action';
|
|
1
2
|
export type RandomCalendarRange = {
|
|
2
3
|
startDate: string | null;
|
|
3
4
|
endDate: string | null;
|
|
@@ -8,8 +9,10 @@ type RandomDateRangeDialogProps = {
|
|
|
8
9
|
anchorDate: string;
|
|
9
10
|
defaultRangeDays?: number;
|
|
10
11
|
onOpenChange: (open: boolean) => void;
|
|
11
|
-
|
|
12
|
+
loadingActions?: readonly DialogLoadingAction[];
|
|
13
|
+
loadingFullPage?: boolean;
|
|
14
|
+
onApply: (range: RandomCalendarRange) => void | Promise<void>;
|
|
12
15
|
onClear?: (range: RandomCalendarRange) => void;
|
|
13
16
|
};
|
|
14
|
-
export declare function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays, onOpenChange, onApply, onClear, }: RandomDateRangeDialogProps): import("react").
|
|
17
|
+
export declare function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays, onOpenChange, loadingActions, loadingFullPage, onApply, onClear, }: RandomDateRangeDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
15
18
|
export {};
|
|
@@ -6,6 +6,7 @@ var React = require('react');
|
|
|
6
6
|
var reactDom = require('react-dom');
|
|
7
7
|
var icons = require('@windrun-huaiin/base-ui/icons');
|
|
8
8
|
var utils = require('@windrun-huaiin/lib/utils');
|
|
9
|
+
var dialogLoadingAction = require('../alert-dialog/dialog-loading-action.js');
|
|
9
10
|
var usePressFeedback = require('../buttons/use-press-feedback.js');
|
|
10
11
|
|
|
11
12
|
const DEFAULT_RANGE_DAYS = 7;
|
|
@@ -118,7 +119,7 @@ function getMonthEnd(value) {
|
|
|
118
119
|
const date = parseDateString(value);
|
|
119
120
|
return formatDateString(new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)));
|
|
120
121
|
}
|
|
121
|
-
function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEFAULT_RANGE_DAYS, onOpenChange, onApply, onClear, }) {
|
|
122
|
+
function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEFAULT_RANGE_DAYS, onOpenChange, loadingActions, loadingFullPage, onApply, onClear, }) {
|
|
122
123
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
123
124
|
const resolvedDefaultRangeDays = clampWindowDays(defaultRangeDays);
|
|
124
125
|
const [draftRange, setDraftRange] = React.useState(value);
|
|
@@ -143,6 +144,7 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
|
|
|
143
144
|
const buildDraggedRangeRef = React.useRef(() => null);
|
|
144
145
|
const previousBodyOverflowRef = React.useRef(null);
|
|
145
146
|
const today = React.useMemo(() => getTodayString(), []);
|
|
147
|
+
const { dialogLoading, runDialogAction } = dialogLoadingAction.useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
146
148
|
const baseReferenceDate = anchorDate || today;
|
|
147
149
|
const previousOpenRef = React.useRef(false);
|
|
148
150
|
const startRatio = getRatioByDate((_a = draftRange.startDate) !== null && _a !== void 0 ? _a : baseReferenceDate, trackBounds);
|
|
@@ -160,6 +162,9 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
|
|
|
160
162
|
.map((item) => formatMonthShort(item));
|
|
161
163
|
return [...new Set(values)];
|
|
162
164
|
}, [trackBounds.endDate, trackBounds.startDate]);
|
|
165
|
+
const handleApply = React.useCallback(() => {
|
|
166
|
+
return onApply(draftRange);
|
|
167
|
+
}, [draftRange, onApply]);
|
|
163
168
|
React.useEffect(() => {
|
|
164
169
|
if (open && !previousOpenRef.current) {
|
|
165
170
|
const nextRange = {
|
|
@@ -372,76 +377,75 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
|
|
|
372
377
|
};
|
|
373
378
|
}, [open]);
|
|
374
379
|
if (!open) {
|
|
375
|
-
return
|
|
380
|
+
return jsxRuntime.jsx(jsxRuntime.Fragment, { children: dialogLoading });
|
|
376
381
|
}
|
|
377
|
-
return reactDom.createPortal(jsxRuntime.jsx("div", { className: "fixed inset-0 z-120 flex select-none items-center justify-center bg-slate-950/60 px-3 py-6 backdrop-blur-sm", children: jsxRuntime.jsx("div", { className: "w-full max-w-2xl overflow-hidden rounded-3xl border border-black/10 bg-white shadow-2xl dark:border-white/10 dark:bg-slate-950", children: jsxRuntime.jsxs("div", { className: "space-y-5 p-4", children: [jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center px-16 text-center", children: [jsxRuntime.jsx("div", { ref: resultLabelRef, className: "select-none text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsxRuntime.jsxs("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 items-center gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsxRuntime.jsx(icons.XIcon, { className: "h-4 w-4" }) }), jsxRuntime.jsx("button", { type: "button", onClick: () => {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}, "aria-label": "Adjust end date" })] }) })] })] })] }) }) }), document.body);
|
|
382
|
+
return reactDom.createPortal(jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "fixed inset-0 z-120 flex select-none items-center justify-center bg-slate-950/60 px-3 py-6 backdrop-blur-sm", children: jsxRuntime.jsx("div", { className: "w-full max-w-2xl overflow-hidden rounded-3xl border border-black/10 bg-white shadow-2xl dark:border-white/10 dark:bg-slate-950", children: jsxRuntime.jsxs("div", { className: "space-y-5 p-4", children: [jsxRuntime.jsxs("div", { className: "relative flex items-center justify-center px-16 text-center", children: [jsxRuntime.jsx("div", { ref: resultLabelRef, className: "select-none text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsxRuntime.jsxs("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 items-center gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsxRuntime.jsx(icons.XIcon, { className: "h-4 w-4" }) }), jsxRuntime.jsx("button", { type: "button", onClick: () => {
|
|
383
|
+
void runDialogAction('confirm', handleApply);
|
|
384
|
+
}, disabled: !draftRange.startDate || !draftRange.endDate, className: utils.cn(DIALOG_ICON_BUTTON_CLASS_NAME, 'text-slate-700 dark:text-slate-100', 'disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-black/10 disabled:hover:bg-white disabled:hover:text-slate-700 dark:disabled:hover:border-white/10 dark:disabled:hover:bg-slate-950 dark:disabled:hover:text-slate-100'), "aria-label": "Apply", children: jsxRuntime.jsx(icons.CheckCheckIcon, { className: "h-4 w-4" }) })] })] }), jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
385
|
+
flashNavButtonPress('prevYear');
|
|
386
|
+
shiftReferenceDateByYears(-1);
|
|
387
|
+
}, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevYear'
|
|
388
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
389
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('prevYear'), { "aria-label": "Previous year", title: "Previous year", children: jsxRuntime.jsx(icons.ChevronsLeftIcon, { className: "h-4 w-4" }) })), jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
390
|
+
flashNavButtonPress('prevMonth');
|
|
391
|
+
shiftReferenceDateByMonths(-1);
|
|
392
|
+
}, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevMonth'
|
|
393
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
394
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('prevMonth'), { "aria-label": "Previous month", title: "Previous month", children: jsxRuntime.jsx(icons.ChevronLeftIcon, { className: "h-4 w-4" }) }))] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("button", { type: "button", onClick: () => {
|
|
395
|
+
const nextRange = {
|
|
396
|
+
startDate: baseReferenceDate,
|
|
397
|
+
endDate: addDays(baseReferenceDate, resolvedDefaultRangeDays - 1),
|
|
398
|
+
};
|
|
399
|
+
setReferenceDate(baseReferenceDate);
|
|
400
|
+
setTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
|
|
401
|
+
setWindowDays(resolvedDefaultRangeDays);
|
|
402
|
+
setDraftRange(nextRange);
|
|
403
|
+
onClear === null || onClear === void 0 ? void 0 : onClear(nextRange);
|
|
404
|
+
}, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "Current Day" }), jsxRuntime.jsx("button", { type: "button", onClick: () => {
|
|
405
|
+
const nextRange = {
|
|
406
|
+
startDate: getMonthStart(referenceDate),
|
|
407
|
+
endDate: addDays(getMonthStart(referenceDate), MAX_RANGE_DAYS - 1),
|
|
408
|
+
};
|
|
409
|
+
const clampedEndDate = compareDateStrings(nextRange.endDate, getMonthEnd(referenceDate)) > 0
|
|
410
|
+
? getMonthEnd(referenceDate)
|
|
411
|
+
: nextRange.endDate;
|
|
412
|
+
const normalizedRange = {
|
|
413
|
+
startDate: nextRange.startDate,
|
|
414
|
+
endDate: clampedEndDate,
|
|
415
|
+
};
|
|
416
|
+
setDraftRange(normalizedRange);
|
|
417
|
+
setWindowDays(getInclusiveDayCount(normalizedRange));
|
|
418
|
+
setTrackBounds(buildTrackRange(normalizedRange.startDate, getInclusiveDayCount(normalizedRange)));
|
|
419
|
+
}, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "This Month" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
420
|
+
flashNavButtonPress('nextMonth');
|
|
421
|
+
shiftReferenceDateByMonths(1);
|
|
422
|
+
}, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextMonth'
|
|
423
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
424
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextMonth'), { "aria-label": "Next month", title: "Next month", children: jsxRuntime.jsx(icons.ChevronRightIcon, { className: "h-4 w-4" }) })), jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
425
|
+
flashNavButtonPress('nextYear');
|
|
426
|
+
shiftReferenceDateByYears(1);
|
|
427
|
+
}, className: utils.cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextYear'
|
|
428
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
429
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextYear'), { "aria-label": "Next year", title: "Next year", children: jsxRuntime.jsx(icons.ChevronsRightIcon, { className: "h-4 w-4" }) }))] })] }), jsxRuntime.jsxs("div", { className: "relative h-24", children: [jsxRuntime.jsxs("div", { className: "absolute inset-x-0 top-0 grid grid-cols-[3.5rem_minmax(0,1fr)_3.5rem] items-center gap-2 text-sm font-semibold text-slate-500 dark:text-slate-400", children: [jsxRuntime.jsxs("span", { className: "relative block select-none text-center", children: [(_g = monthLabels[0]) !== null && _g !== void 0 ? _g : formatMonthShort((_h = trackBounds.startDate) !== null && _h !== void 0 ? _h : baseReferenceDate), jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-1/2 top-7 h-2.5 w-2.5 -translate-x-1/2 rounded-full bg-slate-400 dark:bg-slate-500" }), jsxRuntime.jsx("span", { className: "pointer-events-none absolute left-1/2 top-[1.95rem] h-9 w-0.5 -translate-x-1/2 bg-slate-400 dark:bg-slate-500" })] }), jsxRuntime.jsx("div", { className: "flex min-w-0 items-center justify-center gap-1", children: [
|
|
430
|
+
{ label: '+7', days: 7 },
|
|
431
|
+
{ label: '+10', days: 10 },
|
|
432
|
+
{ label: '+15', days: 15 },
|
|
433
|
+
{ label: '+30', days: 30 },
|
|
434
|
+
].map((item) => (jsxRuntime.jsx("button", { type: "button", onClick: () => applyQuickRange(item.days), className: DIALOG_PILL_BUTTON_COMPACT_CLASS_NAME, children: item.label }, item.label))) }), jsxRuntime.jsxs("span", { className: "relative block select-none text-center", children: [(_j = monthLabels[1]) !== null && _j !== void 0 ? _j : formatMonthShort((_k = trackBounds.endDate) !== null && _k !== void 0 ? _k : baseReferenceDate), jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-1/2 top-7 h-2.5 w-2.5 translate-x-1/2 rounded-full bg-slate-400 dark:bg-slate-500" }), jsxRuntime.jsx("span", { className: "pointer-events-none absolute right-1/2 top-[1.95rem] h-9 w-0.5 translate-x-1/2 bg-slate-400 dark:bg-slate-500" })] })] }), jsxRuntime.jsx("div", { className: "absolute inset-x-0 top-[3.35rem] h-10 touch-none", onDoubleClick: (event) => {
|
|
435
|
+
event.stopPropagation();
|
|
436
|
+
resetReferenceFromClientX(event.clientX);
|
|
437
|
+
}, children: jsxRuntime.jsxs("div", { ref: trackRef, className: "absolute inset-x-0 top-1/2 h-3 -translate-y-1/2 rounded-full bg-slate-400/30 dark:bg-slate-500/25", children: [jsxRuntime.jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-1/2 grid h-8 -translate-y-1/2 items-center", style: { gridTemplateColumns: `repeat(${trackTickCount}, minmax(0, 1fr))` }, children: Array.from({ length: trackTickCount }, (_, index) => {
|
|
438
|
+
return (jsxRuntime.jsx("span", { className: "flex justify-center", children: jsxRuntime.jsx("span", { className: utils.cn('rounded-full bg-slate-400/55 dark:bg-slate-500/55', 'h-3 w-px') }) }, index));
|
|
439
|
+
}) }), jsxRuntime.jsx("div", { ref: selectionRef, className: "absolute top-1/2 z-10 h-4 touch-none -translate-y-1/2 overflow-visible rounded-md border border-sky-500 bg-white dark:border-sky-300 dark:bg-slate-950", style: { left: `${leftPercent}%`, width: `${widthPercent}%` }, onPointerDown: (event) => {
|
|
440
|
+
event.stopPropagation();
|
|
441
|
+
beginDrag('window', event.pointerId, event.clientX);
|
|
442
|
+
}, children: jsxRuntime.jsx("div", { ref: selectionDaysRef, className: "pointer-events-none absolute inset-0 z-30 flex select-none items-center justify-center text-xs font-semibold text-sky-700 dark:text-sky-100", children: `${getInclusiveDayCount(draftRange)}D` }) }), jsxRuntime.jsx("button", { ref: startHandleRef, type: "button", className: "absolute top-1/2 z-20 h-6 w-6 touch-none -translate-x-1/2 -translate-y-1/2 rounded-full border border-sky-500 bg-white shadow-sm dark:border-sky-300 dark:bg-slate-950", style: { left: `${startHandlePercent}%` }, onPointerDown: (event) => {
|
|
443
|
+
event.stopPropagation();
|
|
444
|
+
beginDrag('start', event.pointerId);
|
|
445
|
+
}, "aria-label": "Adjust start date" }), jsxRuntime.jsx("button", { ref: endHandleRef, type: "button", className: "absolute top-1/2 z-20 h-6 w-6 touch-none -translate-x-1/2 -translate-y-1/2 rounded-full border border-sky-500 bg-white shadow-sm dark:border-sky-300 dark:bg-slate-950", style: { left: `${endHandlePercent}%` }, onPointerDown: (event) => {
|
|
446
|
+
event.stopPropagation();
|
|
447
|
+
beginDrag('end', event.pointerId);
|
|
448
|
+
}, "aria-label": "Adjust end date" })] }) })] })] })] }) }) }), dialogLoading] }), document.body);
|
|
445
449
|
}
|
|
446
450
|
|
|
447
451
|
exports.RandomDateRangeDialog = RandomDateRangeDialog;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
-
import { useState, useRef, useMemo,
|
|
2
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import { useState, useRef, useMemo, useCallback, useEffect } from 'react';
|
|
4
4
|
import { createPortal } from 'react-dom';
|
|
5
5
|
import { XIcon, CheckCheckIcon, ChevronsLeftIcon, ChevronLeftIcon, ChevronRightIcon, ChevronsRightIcon } from '@windrun-huaiin/base-ui/icons';
|
|
6
6
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
7
|
+
import { useDialogLoadingAction } from '../alert-dialog/dialog-loading-action.mjs';
|
|
7
8
|
import { usePressFeedback } from '../buttons/use-press-feedback.mjs';
|
|
8
9
|
|
|
9
10
|
const DEFAULT_RANGE_DAYS = 7;
|
|
@@ -116,7 +117,7 @@ function getMonthEnd(value) {
|
|
|
116
117
|
const date = parseDateString(value);
|
|
117
118
|
return formatDateString(new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)));
|
|
118
119
|
}
|
|
119
|
-
function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEFAULT_RANGE_DAYS, onOpenChange, onApply, onClear, }) {
|
|
120
|
+
function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEFAULT_RANGE_DAYS, onOpenChange, loadingActions, loadingFullPage, onApply, onClear, }) {
|
|
120
121
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
121
122
|
const resolvedDefaultRangeDays = clampWindowDays(defaultRangeDays);
|
|
122
123
|
const [draftRange, setDraftRange] = useState(value);
|
|
@@ -141,6 +142,7 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
|
|
|
141
142
|
const buildDraggedRangeRef = useRef(() => null);
|
|
142
143
|
const previousBodyOverflowRef = useRef(null);
|
|
143
144
|
const today = useMemo(() => getTodayString(), []);
|
|
145
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
144
146
|
const baseReferenceDate = anchorDate || today;
|
|
145
147
|
const previousOpenRef = useRef(false);
|
|
146
148
|
const startRatio = getRatioByDate((_a = draftRange.startDate) !== null && _a !== void 0 ? _a : baseReferenceDate, trackBounds);
|
|
@@ -158,6 +160,9 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
|
|
|
158
160
|
.map((item) => formatMonthShort(item));
|
|
159
161
|
return [...new Set(values)];
|
|
160
162
|
}, [trackBounds.endDate, trackBounds.startDate]);
|
|
163
|
+
const handleApply = useCallback(() => {
|
|
164
|
+
return onApply(draftRange);
|
|
165
|
+
}, [draftRange, onApply]);
|
|
161
166
|
useEffect(() => {
|
|
162
167
|
if (open && !previousOpenRef.current) {
|
|
163
168
|
const nextRange = {
|
|
@@ -370,76 +375,75 @@ function RandomDateRangeDialog({ open, value, anchorDate, defaultRangeDays = DEF
|
|
|
370
375
|
};
|
|
371
376
|
}, [open]);
|
|
372
377
|
if (!open) {
|
|
373
|
-
return
|
|
378
|
+
return jsx(Fragment, { children: dialogLoading });
|
|
374
379
|
}
|
|
375
|
-
return createPortal(jsx("div", { className: "fixed inset-0 z-120 flex select-none items-center justify-center bg-slate-950/60 px-3 py-6 backdrop-blur-sm", children: jsx("div", { className: "w-full max-w-2xl overflow-hidden rounded-3xl border border-black/10 bg-white shadow-2xl dark:border-white/10 dark:bg-slate-950", children: jsxs("div", { className: "space-y-5 p-4", children: [jsxs("div", { className: "relative flex items-center justify-center px-16 text-center", children: [jsx("div", { ref: resultLabelRef, className: "select-none text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsxs("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 items-center gap-2", children: [jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsx(XIcon, { className: "h-4 w-4" }) }), jsx("button", { type: "button", onClick: () => {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}, "aria-label": "Adjust end date" })] }) })] })] })] }) }) }), document.body);
|
|
380
|
+
return createPortal(jsxs(Fragment, { children: [jsx("div", { className: "fixed inset-0 z-120 flex select-none items-center justify-center bg-slate-950/60 px-3 py-6 backdrop-blur-sm", children: jsx("div", { className: "w-full max-w-2xl overflow-hidden rounded-3xl border border-black/10 bg-white shadow-2xl dark:border-white/10 dark:bg-slate-950", children: jsxs("div", { className: "space-y-5 p-4", children: [jsxs("div", { className: "relative flex items-center justify-center px-16 text-center", children: [jsx("div", { ref: resultLabelRef, className: "select-none text-base font-semibold text-slate-900 dark:text-white", children: getRangeLabel(draftRange) }), jsxs("div", { className: "absolute right-0 top-1/2 flex -translate-y-1/2 items-center gap-2", children: [jsx("button", { type: "button", onClick: () => onOpenChange(false), className: DIALOG_ICON_BUTTON_CLASS_NAME, "aria-label": "Cancel", children: jsx(XIcon, { className: "h-4 w-4" }) }), jsx("button", { type: "button", onClick: () => {
|
|
381
|
+
void runDialogAction('confirm', handleApply);
|
|
382
|
+
}, disabled: !draftRange.startDate || !draftRange.endDate, className: cn(DIALOG_ICON_BUTTON_CLASS_NAME, 'text-slate-700 dark:text-slate-100', 'disabled:cursor-not-allowed disabled:opacity-40 disabled:hover:border-black/10 disabled:hover:bg-white disabled:hover:text-slate-700 dark:disabled:hover:border-white/10 dark:disabled:hover:bg-slate-950 dark:disabled:hover:text-slate-100'), "aria-label": "Apply", children: jsx(CheckCheckIcon, { className: "h-4 w-4" }) })] })] }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "flex items-center justify-between gap-2", children: [jsxs("div", { className: "flex items-center gap-1", children: [jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
383
|
+
flashNavButtonPress('prevYear');
|
|
384
|
+
shiftReferenceDateByYears(-1);
|
|
385
|
+
}, className: cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevYear'
|
|
386
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
387
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('prevYear'), { "aria-label": "Previous year", title: "Previous year", children: jsx(ChevronsLeftIcon, { className: "h-4 w-4" }) })), jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
388
|
+
flashNavButtonPress('prevMonth');
|
|
389
|
+
shiftReferenceDateByMonths(-1);
|
|
390
|
+
}, className: cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'prevMonth'
|
|
391
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
392
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('prevMonth'), { "aria-label": "Previous month", title: "Previous month", children: jsx(ChevronLeftIcon, { className: "h-4 w-4" }) }))] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx("button", { type: "button", onClick: () => {
|
|
393
|
+
const nextRange = {
|
|
394
|
+
startDate: baseReferenceDate,
|
|
395
|
+
endDate: addDays(baseReferenceDate, resolvedDefaultRangeDays - 1),
|
|
396
|
+
};
|
|
397
|
+
setReferenceDate(baseReferenceDate);
|
|
398
|
+
setTrackBounds(buildTrackRange(baseReferenceDate, resolvedDefaultRangeDays));
|
|
399
|
+
setWindowDays(resolvedDefaultRangeDays);
|
|
400
|
+
setDraftRange(nextRange);
|
|
401
|
+
onClear === null || onClear === void 0 ? void 0 : onClear(nextRange);
|
|
402
|
+
}, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "Current Day" }), jsx("button", { type: "button", onClick: () => {
|
|
403
|
+
const nextRange = {
|
|
404
|
+
startDate: getMonthStart(referenceDate),
|
|
405
|
+
endDate: addDays(getMonthStart(referenceDate), MAX_RANGE_DAYS - 1),
|
|
406
|
+
};
|
|
407
|
+
const clampedEndDate = compareDateStrings(nextRange.endDate, getMonthEnd(referenceDate)) > 0
|
|
408
|
+
? getMonthEnd(referenceDate)
|
|
409
|
+
: nextRange.endDate;
|
|
410
|
+
const normalizedRange = {
|
|
411
|
+
startDate: nextRange.startDate,
|
|
412
|
+
endDate: clampedEndDate,
|
|
413
|
+
};
|
|
414
|
+
setDraftRange(normalizedRange);
|
|
415
|
+
setWindowDays(getInclusiveDayCount(normalizedRange));
|
|
416
|
+
setTrackBounds(buildTrackRange(normalizedRange.startDate, getInclusiveDayCount(normalizedRange)));
|
|
417
|
+
}, className: DIALOG_PILL_BUTTON_CLASS_NAME, children: "This Month" })] }), jsxs("div", { className: "flex items-center gap-1", children: [jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
418
|
+
flashNavButtonPress('nextMonth');
|
|
419
|
+
shiftReferenceDateByMonths(1);
|
|
420
|
+
}, className: cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextMonth'
|
|
421
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
422
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextMonth'), { "aria-label": "Next month", title: "Next month", children: jsx(ChevronRightIcon, { className: "h-4 w-4" }) })), jsx("button", Object.assign({ type: "button", onClick: () => {
|
|
423
|
+
flashNavButtonPress('nextYear');
|
|
424
|
+
shiftReferenceDateByYears(1);
|
|
425
|
+
}, className: cn(DIALOG_NAV_BUTTON_CLASS_NAME, pressedNavButton === 'nextYear'
|
|
426
|
+
? DIALOG_NAV_BUTTON_PRESSED_CLASS_NAME
|
|
427
|
+
: DIALOG_NAV_BUTTON_REST_CLASS_NAME) }, getNavButtonPressProps('nextYear'), { "aria-label": "Next year", title: "Next year", children: jsx(ChevronsRightIcon, { className: "h-4 w-4" }) }))] })] }), jsxs("div", { className: "relative h-24", children: [jsxs("div", { className: "absolute inset-x-0 top-0 grid grid-cols-[3.5rem_minmax(0,1fr)_3.5rem] items-center gap-2 text-sm font-semibold text-slate-500 dark:text-slate-400", children: [jsxs("span", { className: "relative block select-none text-center", children: [(_g = monthLabels[0]) !== null && _g !== void 0 ? _g : formatMonthShort((_h = trackBounds.startDate) !== null && _h !== void 0 ? _h : baseReferenceDate), jsx("span", { className: "pointer-events-none absolute left-1/2 top-7 h-2.5 w-2.5 -translate-x-1/2 rounded-full bg-slate-400 dark:bg-slate-500" }), jsx("span", { className: "pointer-events-none absolute left-1/2 top-[1.95rem] h-9 w-0.5 -translate-x-1/2 bg-slate-400 dark:bg-slate-500" })] }), jsx("div", { className: "flex min-w-0 items-center justify-center gap-1", children: [
|
|
428
|
+
{ label: '+7', days: 7 },
|
|
429
|
+
{ label: '+10', days: 10 },
|
|
430
|
+
{ label: '+15', days: 15 },
|
|
431
|
+
{ label: '+30', days: 30 },
|
|
432
|
+
].map((item) => (jsx("button", { type: "button", onClick: () => applyQuickRange(item.days), className: DIALOG_PILL_BUTTON_COMPACT_CLASS_NAME, children: item.label }, item.label))) }), jsxs("span", { className: "relative block select-none text-center", children: [(_j = monthLabels[1]) !== null && _j !== void 0 ? _j : formatMonthShort((_k = trackBounds.endDate) !== null && _k !== void 0 ? _k : baseReferenceDate), jsx("span", { className: "pointer-events-none absolute right-1/2 top-7 h-2.5 w-2.5 translate-x-1/2 rounded-full bg-slate-400 dark:bg-slate-500" }), jsx("span", { className: "pointer-events-none absolute right-1/2 top-[1.95rem] h-9 w-0.5 translate-x-1/2 bg-slate-400 dark:bg-slate-500" })] })] }), jsx("div", { className: "absolute inset-x-0 top-[3.35rem] h-10 touch-none", onDoubleClick: (event) => {
|
|
433
|
+
event.stopPropagation();
|
|
434
|
+
resetReferenceFromClientX(event.clientX);
|
|
435
|
+
}, children: jsxs("div", { ref: trackRef, className: "absolute inset-x-0 top-1/2 h-3 -translate-y-1/2 rounded-full bg-slate-400/30 dark:bg-slate-500/25", children: [jsx("div", { "aria-hidden": "true", className: "pointer-events-none absolute inset-x-0 top-1/2 grid h-8 -translate-y-1/2 items-center", style: { gridTemplateColumns: `repeat(${trackTickCount}, minmax(0, 1fr))` }, children: Array.from({ length: trackTickCount }, (_, index) => {
|
|
436
|
+
return (jsx("span", { className: "flex justify-center", children: jsx("span", { className: cn('rounded-full bg-slate-400/55 dark:bg-slate-500/55', 'h-3 w-px') }) }, index));
|
|
437
|
+
}) }), jsx("div", { ref: selectionRef, className: "absolute top-1/2 z-10 h-4 touch-none -translate-y-1/2 overflow-visible rounded-md border border-sky-500 bg-white dark:border-sky-300 dark:bg-slate-950", style: { left: `${leftPercent}%`, width: `${widthPercent}%` }, onPointerDown: (event) => {
|
|
438
|
+
event.stopPropagation();
|
|
439
|
+
beginDrag('window', event.pointerId, event.clientX);
|
|
440
|
+
}, children: jsx("div", { ref: selectionDaysRef, className: "pointer-events-none absolute inset-0 z-30 flex select-none items-center justify-center text-xs font-semibold text-sky-700 dark:text-sky-100", children: `${getInclusiveDayCount(draftRange)}D` }) }), jsx("button", { ref: startHandleRef, type: "button", className: "absolute top-1/2 z-20 h-6 w-6 touch-none -translate-x-1/2 -translate-y-1/2 rounded-full border border-sky-500 bg-white shadow-sm dark:border-sky-300 dark:bg-slate-950", style: { left: `${startHandlePercent}%` }, onPointerDown: (event) => {
|
|
441
|
+
event.stopPropagation();
|
|
442
|
+
beginDrag('start', event.pointerId);
|
|
443
|
+
}, "aria-label": "Adjust start date" }), jsx("button", { ref: endHandleRef, type: "button", className: "absolute top-1/2 z-20 h-6 w-6 touch-none -translate-x-1/2 -translate-y-1/2 rounded-full border border-sky-500 bg-white shadow-sm dark:border-sky-300 dark:bg-slate-950", style: { left: `${endHandlePercent}%` }, onPointerDown: (event) => {
|
|
444
|
+
event.stopPropagation();
|
|
445
|
+
beginDrag('end', event.pointerId);
|
|
446
|
+
}, "aria-label": "Adjust end date" })] }) })] })] })] }) }) }), dialogLoading] }), document.body);
|
|
443
447
|
}
|
|
444
448
|
|
|
445
449
|
export { RandomDateRangeDialog };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/third-ui",
|
|
3
|
-
"version": "29.2.
|
|
3
|
+
"version": "29.2.1",
|
|
4
4
|
"description": "Third-party integrated UI components for windrun-huaiin projects",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./clerk": {
|
|
@@ -233,8 +233,8 @@
|
|
|
233
233
|
"unified": "^11.0.5",
|
|
234
234
|
"zod": "^4.3.6",
|
|
235
235
|
"@windrun-huaiin/base-ui": "^29.0.2",
|
|
236
|
-
"@windrun-huaiin/
|
|
237
|
-
"@windrun-huaiin/
|
|
236
|
+
"@windrun-huaiin/contracts": "^29.0.0",
|
|
237
|
+
"@windrun-huaiin/lib": "^29.0.0"
|
|
238
238
|
},
|
|
239
239
|
"peerDependencies": {
|
|
240
240
|
"clsx": "^2.1.1",
|
|
@@ -39,6 +39,7 @@ interface ConfirmDialogProps {
|
|
|
39
39
|
confirmText?: string;
|
|
40
40
|
emphasis?: ConfirmDialogEmphasis;
|
|
41
41
|
loadingActions?: readonly DialogLoadingAction[];
|
|
42
|
+
loadingFullPage?: boolean;
|
|
42
43
|
onCancel?: DialogActionHandler;
|
|
43
44
|
onConfirm?: DialogActionHandler;
|
|
44
45
|
}
|
|
@@ -76,6 +77,7 @@ export function ConfirmDialog({
|
|
|
76
77
|
confirmText = 'Confirm',
|
|
77
78
|
emphasis = 'confirm',
|
|
78
79
|
loadingActions,
|
|
80
|
+
loadingFullPage,
|
|
79
81
|
onCancel,
|
|
80
82
|
onConfirm,
|
|
81
83
|
}: ConfirmDialogProps) {
|
|
@@ -83,7 +85,7 @@ export function ConfirmDialog({
|
|
|
83
85
|
const Icon = typeClass.Icon;
|
|
84
86
|
const cancelButtonClass = emphasis === 'cancel' ? typeClass.action : secondaryButtonClass;
|
|
85
87
|
const confirmButtonClass = emphasis === 'cancel' ? secondaryButtonClass : typeClass.action;
|
|
86
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
88
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
87
89
|
|
|
88
90
|
const handleCancel = () => {
|
|
89
91
|
void runDialogAction('cancel', onCancel);
|
|
@@ -9,11 +9,13 @@ export type DialogActionHandler = () => void | Promise<void>;
|
|
|
9
9
|
|
|
10
10
|
interface UseDialogLoadingActionOptions {
|
|
11
11
|
loadingActions?: readonly DialogLoadingAction[];
|
|
12
|
+
loadingFullPage?: boolean;
|
|
12
13
|
onOpenChange: (open: boolean) => void;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function useDialogLoadingAction({
|
|
16
17
|
loadingActions,
|
|
18
|
+
loadingFullPage = false,
|
|
17
19
|
onOpenChange,
|
|
18
20
|
}: UseDialogLoadingActionOptions) {
|
|
19
21
|
const [mounted, setMounted] = React.useState(false);
|
|
@@ -49,9 +51,22 @@ export function useDialogLoadingAction({
|
|
|
49
51
|
|
|
50
52
|
const dialogLoading = mounted && loading
|
|
51
53
|
? createPortal(
|
|
52
|
-
|
|
53
|
-
<
|
|
54
|
-
|
|
54
|
+
loadingFullPage ? (
|
|
55
|
+
<div className="fixed inset-0 z-10000">
|
|
56
|
+
<Loading className="h-full w-full" />
|
|
57
|
+
</div>
|
|
58
|
+
) : (
|
|
59
|
+
<div className="pointer-events-none fixed inset-0 z-10000 flex items-center justify-center p-4">
|
|
60
|
+
<div className="pointer-events-auto overflow-hidden rounded-[28px] bg-neutral-50/58 shadow-[0_18px_56px_rgba(15,23,42,0.14)] backdrop-blur-md dark:bg-neutral-900/58 dark:shadow-[0_18px_56px_rgba(0,0,0,0.34)]">
|
|
61
|
+
<Loading
|
|
62
|
+
compact
|
|
63
|
+
label="Loading"
|
|
64
|
+
className="min-h-[250px] w-[min(22rem,calc(100vw-2rem))] bg-transparent"
|
|
65
|
+
labelClassName="text-foreground"
|
|
66
|
+
/>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
),
|
|
55
70
|
document.body
|
|
56
71
|
)
|
|
57
72
|
: null;
|
|
@@ -27,6 +27,7 @@ interface HighPriorityConfirmDialogProps {
|
|
|
27
27
|
confirmText?: string;
|
|
28
28
|
cancelText?: string;
|
|
29
29
|
loadingActions?: readonly DialogLoadingAction[];
|
|
30
|
+
loadingFullPage?: boolean;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
export function HighPriorityConfirmDialog({
|
|
@@ -39,9 +40,10 @@ export function HighPriorityConfirmDialog({
|
|
|
39
40
|
confirmText = "Confirm",
|
|
40
41
|
cancelText = "Cancel",
|
|
41
42
|
loadingActions,
|
|
43
|
+
loadingFullPage,
|
|
42
44
|
}: HighPriorityConfirmDialogProps) {
|
|
43
45
|
const [mounted, setMounted] = useState(false);
|
|
44
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
46
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
45
47
|
|
|
46
48
|
useEffect(() => {
|
|
47
49
|
// Ensure portal target exists and prevent hydration mismatch
|
|
@@ -38,6 +38,7 @@ interface InfoDialogProps {
|
|
|
38
38
|
description: React.ReactNode;
|
|
39
39
|
confirmText?: string;
|
|
40
40
|
loadingActions?: readonly DialogLoadingAction[];
|
|
41
|
+
loadingFullPage?: boolean;
|
|
41
42
|
onConfirm?: DialogActionHandler;
|
|
42
43
|
}
|
|
43
44
|
|
|
@@ -86,12 +87,13 @@ export function InfoDialog({
|
|
|
86
87
|
description,
|
|
87
88
|
confirmText = 'OK',
|
|
88
89
|
loadingActions,
|
|
90
|
+
loadingFullPage,
|
|
89
91
|
onConfirm,
|
|
90
92
|
}: InfoDialogProps) {
|
|
91
93
|
const typeClass = infoTypeClassMap[type];
|
|
92
94
|
const Icon = typeClass.Icon;
|
|
93
95
|
const handleClose = () => onOpenChange(false);
|
|
94
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
96
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
95
97
|
|
|
96
98
|
return (
|
|
97
99
|
<>
|
|
@@ -37,6 +37,7 @@ export interface UndoableConfirmDialogProps {
|
|
|
37
37
|
emphasis?: ConfirmDialogEmphasis;
|
|
38
38
|
countdownSeconds?: number;
|
|
39
39
|
loadingActions?: readonly DialogLoadingAction[];
|
|
40
|
+
loadingFullPage?: boolean;
|
|
40
41
|
onCancel?: DialogActionHandler;
|
|
41
42
|
onConfirm: DialogActionHandler;
|
|
42
43
|
onUndo?: DialogActionHandler;
|
|
@@ -55,6 +56,7 @@ export function UndoableConfirmDialog({
|
|
|
55
56
|
emphasis = 'confirm',
|
|
56
57
|
countdownSeconds = 5,
|
|
57
58
|
loadingActions,
|
|
59
|
+
loadingFullPage,
|
|
58
60
|
onCancel,
|
|
59
61
|
onConfirm,
|
|
60
62
|
onUndo,
|
|
@@ -67,7 +69,7 @@ export function UndoableConfirmDialog({
|
|
|
67
69
|
const intervalRef = React.useRef<number | null>(null);
|
|
68
70
|
const cancelButtonClass = emphasis === 'cancel' ? dangerButtonClass : secondaryButtonClass;
|
|
69
71
|
const confirmButtonClass = emphasis === 'cancel' ? secondaryButtonClass : dangerButtonClass;
|
|
70
|
-
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, onOpenChange });
|
|
72
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
71
73
|
|
|
72
74
|
const clearTimers = React.useCallback(() => {
|
|
73
75
|
if (timeoutRef.current) {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
XIcon,
|
|
12
12
|
} from '@windrun-huaiin/base-ui/icons';
|
|
13
13
|
import { cn } from '@windrun-huaiin/lib/utils';
|
|
14
|
+
import { DialogLoadingAction, DialogActionHandler, useDialogLoadingAction } from '../alert-dialog/dialog-loading-action';
|
|
14
15
|
import { usePressFeedback } from '../buttons/use-press-feedback';
|
|
15
16
|
|
|
16
17
|
export type RandomCalendarRange = {
|
|
@@ -24,7 +25,9 @@ type RandomDateRangeDialogProps = {
|
|
|
24
25
|
anchorDate: string;
|
|
25
26
|
defaultRangeDays?: number;
|
|
26
27
|
onOpenChange: (open: boolean) => void;
|
|
27
|
-
|
|
28
|
+
loadingActions?: readonly DialogLoadingAction[];
|
|
29
|
+
loadingFullPage?: boolean;
|
|
30
|
+
onApply: (range: RandomCalendarRange) => void | Promise<void>;
|
|
28
31
|
onClear?: (range: RandomCalendarRange) => void;
|
|
29
32
|
};
|
|
30
33
|
|
|
@@ -180,6 +183,8 @@ export function RandomDateRangeDialog({
|
|
|
180
183
|
anchorDate,
|
|
181
184
|
defaultRangeDays = DEFAULT_RANGE_DAYS,
|
|
182
185
|
onOpenChange,
|
|
186
|
+
loadingActions,
|
|
187
|
+
loadingFullPage,
|
|
183
188
|
onApply,
|
|
184
189
|
onClear,
|
|
185
190
|
}: RandomDateRangeDialogProps) {
|
|
@@ -210,6 +215,7 @@ export function RandomDateRangeDialog({
|
|
|
210
215
|
const buildDraggedRangeRef = useRef<(clientX: number) => RandomCalendarRange | null>(() => null);
|
|
211
216
|
const previousBodyOverflowRef = useRef<string | null>(null);
|
|
212
217
|
const today = useMemo(() => getTodayString(), []);
|
|
218
|
+
const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
|
|
213
219
|
const baseReferenceDate = anchorDate || today;
|
|
214
220
|
const previousOpenRef = useRef(false);
|
|
215
221
|
const startRatio = getRatioByDate(draftRange.startDate ?? baseReferenceDate, trackBounds);
|
|
@@ -229,6 +235,10 @@ export function RandomDateRangeDialog({
|
|
|
229
235
|
return [...new Set(values)];
|
|
230
236
|
}, [trackBounds.endDate, trackBounds.startDate]);
|
|
231
237
|
|
|
238
|
+
const handleApply = useCallback<DialogActionHandler>(() => {
|
|
239
|
+
return onApply(draftRange);
|
|
240
|
+
}, [draftRange, onApply]);
|
|
241
|
+
|
|
232
242
|
useEffect(() => {
|
|
233
243
|
if (open && !previousOpenRef.current) {
|
|
234
244
|
const nextRange = {
|
|
@@ -472,12 +482,13 @@ export function RandomDateRangeDialog({
|
|
|
472
482
|
}, [open]);
|
|
473
483
|
|
|
474
484
|
if (!open) {
|
|
475
|
-
return
|
|
485
|
+
return <>{dialogLoading}</>;
|
|
476
486
|
}
|
|
477
487
|
|
|
478
488
|
return createPortal(
|
|
479
|
-
|
|
480
|
-
<div className="
|
|
489
|
+
<>
|
|
490
|
+
<div className="fixed inset-0 z-120 flex select-none items-center justify-center bg-slate-950/60 px-3 py-6 backdrop-blur-sm">
|
|
491
|
+
<div className="w-full max-w-2xl overflow-hidden rounded-3xl border border-black/10 bg-white shadow-2xl dark:border-white/10 dark:bg-slate-950">
|
|
481
492
|
<div className="space-y-5 p-4">
|
|
482
493
|
<div className="relative flex items-center justify-center px-16 text-center">
|
|
483
494
|
<div ref={resultLabelRef} className="select-none text-base font-semibold text-slate-900 dark:text-white">{getRangeLabel(draftRange)}</div>
|
|
@@ -493,8 +504,7 @@ export function RandomDateRangeDialog({
|
|
|
493
504
|
<button
|
|
494
505
|
type="button"
|
|
495
506
|
onClick={() => {
|
|
496
|
-
|
|
497
|
-
onOpenChange(false);
|
|
507
|
+
void runDialogAction('confirm', handleApply);
|
|
498
508
|
}}
|
|
499
509
|
disabled={!draftRange.startDate || !draftRange.endDate}
|
|
500
510
|
className={cn(
|
|
@@ -734,8 +744,10 @@ export function RandomDateRangeDialog({
|
|
|
734
744
|
|
|
735
745
|
</div>
|
|
736
746
|
</div>
|
|
747
|
+
</div>
|
|
737
748
|
</div>
|
|
738
|
-
|
|
749
|
+
{dialogLoading}
|
|
750
|
+
</>,
|
|
739
751
|
document.body
|
|
740
752
|
);
|
|
741
753
|
}
|