@windrun-huaiin/third-ui 29.1.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.
Files changed (58) hide show
  1. package/dist/fuma/base/custom-header.js +6 -3
  2. package/dist/fuma/base/custom-header.mjs +6 -3
  3. package/dist/main/alert-dialog/confirm-dialog.d.ts +6 -3
  4. package/dist/main/alert-dialog/confirm-dialog.js +7 -7
  5. package/dist/main/alert-dialog/confirm-dialog.mjs +8 -8
  6. package/dist/main/alert-dialog/dialog-loading-action.d.ts +13 -0
  7. package/dist/main/alert-dialog/dialog-loading-action.js +42 -0
  8. package/dist/main/alert-dialog/dialog-loading-action.mjs +40 -0
  9. package/dist/main/alert-dialog/high-priority-confirm-dialog.d.ts +6 -3
  10. package/dist/main/alert-dialog/high-priority-confirm-dialog.js +10 -4
  11. package/dist/main/alert-dialog/high-priority-confirm-dialog.mjs +11 -5
  12. package/dist/main/alert-dialog/index.d.ts +1 -0
  13. package/dist/main/alert-dialog/info-dialog.d.ts +5 -2
  14. package/dist/main/alert-dialog/info-dialog.js +6 -5
  15. package/dist/main/alert-dialog/info-dialog.mjs +7 -6
  16. package/dist/main/alert-dialog/undoable-confirm-dialog.d.ts +7 -4
  17. package/dist/main/alert-dialog/undoable-confirm-dialog.js +18 -17
  18. package/dist/main/alert-dialog/undoable-confirm-dialog.mjs +19 -18
  19. package/dist/main/buttons/gradient-button.d.ts +3 -1
  20. package/dist/main/buttons/gradient-button.js +29 -3
  21. package/dist/main/buttons/gradient-button.mjs +29 -3
  22. package/dist/main/buttons/index.d.ts +1 -0
  23. package/dist/main/buttons/index.js +3 -0
  24. package/dist/main/buttons/index.mjs +1 -0
  25. package/dist/main/buttons/use-press-feedback.d.ts +18 -0
  26. package/dist/main/buttons/use-press-feedback.js +42 -0
  27. package/dist/main/buttons/use-press-feedback.mjs +39 -0
  28. package/dist/main/buttons/x-button.d.ts +3 -0
  29. package/dist/main/buttons/x-button.js +36 -6
  30. package/dist/main/buttons/x-button.mjs +36 -6
  31. package/dist/main/calendar/calendar-date-range-input.d.ts +17 -0
  32. package/dist/main/calendar/calendar-date-range-input.js +81 -0
  33. package/dist/main/calendar/calendar-date-range-input.mjs +79 -0
  34. package/dist/main/calendar/calendar-status-view.d.ts +23 -0
  35. package/dist/main/calendar/calendar-status-view.js +155 -0
  36. package/dist/main/calendar/calendar-status-view.mjs +153 -0
  37. package/dist/main/calendar/index.d.ts +3 -0
  38. package/dist/main/calendar/index.js +12 -0
  39. package/dist/main/calendar/index.mjs +4 -0
  40. package/dist/main/calendar/random-date-range-dialog.d.ts +18 -0
  41. package/dist/main/calendar/random-date-range-dialog.js +451 -0
  42. package/dist/main/calendar/random-date-range-dialog.mjs +449 -0
  43. package/package.json +6 -1
  44. package/src/fuma/base/custom-header.tsx +6 -3
  45. package/src/main/alert-dialog/confirm-dialog.tsx +54 -47
  46. package/src/main/alert-dialog/dialog-loading-action.tsx +78 -0
  47. package/src/main/alert-dialog/high-priority-confirm-dialog.tsx +63 -48
  48. package/src/main/alert-dialog/index.ts +1 -0
  49. package/src/main/alert-dialog/info-dialog.tsx +52 -44
  50. package/src/main/alert-dialog/undoable-confirm-dialog.tsx +90 -82
  51. package/src/main/buttons/gradient-button.tsx +36 -3
  52. package/src/main/buttons/index.ts +1 -0
  53. package/src/main/buttons/use-press-feedback.ts +58 -0
  54. package/src/main/buttons/x-button.tsx +53 -11
  55. package/src/main/calendar/calendar-date-range-input.tsx +173 -0
  56. package/src/main/calendar/calendar-status-view.tsx +365 -0
  57. package/src/main/calendar/index.ts +5 -0
  58. package/src/main/calendar/random-date-range-dialog.tsx +753 -0
@@ -1,14 +1,15 @@
1
1
  "use client";
2
2
  import { __awaiter } from 'tslib';
3
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
4
  import React__default from 'react';
5
5
  import { Trash2Icon, CircleAlertIcon, XIcon, Undo2Icon } from '@windrun-huaiin/base-ui/icons';
6
6
  import { themeIconColor } from '@windrun-huaiin/base-ui/lib';
7
7
  import { AlertDialog, AlertDialogContent, AlertDialogTitle, AlertDialogDescription } from '@windrun-huaiin/base-ui/ui';
8
8
  import { cn } from '@windrun-huaiin/lib/utils';
9
9
  import { dialogThemedOverlayClass, dialogHeaderClass, dialogTitleClass, closeButtonClass, dialogDescriptionClass, secondaryButtonClass, dangerButtonClass, dialogFooterClass, dialogContentClass } from './dialog-styles.mjs';
10
+ import { useDialogLoadingAction } from './dialog-loading-action.mjs';
10
11
 
11
- function UndoableConfirmDialog({ open, onOpenChange, title, description, pendingTitle, pendingDescription, cancelText = 'Cancel', confirmText = 'Delete', undoText = 'Undo', emphasis = 'confirm', countdownSeconds = 5, 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, }) {
12
13
  const safeCountdownSeconds = Math.max(1, Math.floor(countdownSeconds));
13
14
  const [pending, setPending] = React__default.useState(false);
14
15
  const [remainingSeconds, setRemainingSeconds] = React__default.useState(safeCountdownSeconds);
@@ -17,6 +18,7 @@ function UndoableConfirmDialog({ open, onOpenChange, title, description, pending
17
18
  const intervalRef = React__default.useRef(null);
18
19
  const cancelButtonClass = emphasis === 'cancel' ? dangerButtonClass : secondaryButtonClass;
19
20
  const confirmButtonClass = emphasis === 'cancel' ? secondaryButtonClass : dangerButtonClass;
21
+ const { dialogLoading, runDialogAction } = useDialogLoadingAction({ loadingActions, loadingFullPage, onOpenChange });
20
22
  const clearTimers = React__default.useCallback(() => {
21
23
  if (timeoutRef.current) {
22
24
  window.clearTimeout(timeoutRef.current);
@@ -45,13 +47,12 @@ function UndoableConfirmDialog({ open, onOpenChange, title, description, pending
45
47
  clearTimers();
46
48
  setConfirming(true);
47
49
  try {
48
- yield onConfirm();
49
- onOpenChange(false);
50
+ yield runDialogAction('confirm', onConfirm);
50
51
  }
51
52
  finally {
52
53
  setConfirming(false);
53
54
  }
54
- }), [clearTimers, onConfirm, onOpenChange]);
55
+ }), [clearTimers, onConfirm, runDialogAction]);
55
56
  const startCountdown = () => {
56
57
  clearTimers();
57
58
  setPending(true);
@@ -65,27 +66,27 @@ function UndoableConfirmDialog({ open, onOpenChange, title, description, pending
65
66
  };
66
67
  const handleCancel = () => {
67
68
  resetState();
68
- onOpenChange(false);
69
- onCancel === null || onCancel === void 0 ? void 0 : onCancel();
69
+ void runDialogAction('cancel', onCancel);
70
70
  };
71
71
  const handleClose = React__default.useCallback(() => {
72
72
  resetState();
73
73
  onOpenChange(false);
74
74
  }, [onOpenChange, resetState]);
75
- const handleUndo = () => {
75
+ const handleUndo = () => __awaiter(this, void 0, void 0, function* () {
76
76
  resetState();
77
- onOpenChange(false);
78
- onUndo === null || onUndo === void 0 ? void 0 : onUndo();
79
- };
77
+ yield runDialogAction('undo', onUndo);
78
+ });
80
79
  const displayTitle = pending ? pendingTitle !== null && pendingTitle !== void 0 ? pendingTitle : title : title;
81
80
  const displayDescription = pending ? pendingDescription !== null && pendingDescription !== void 0 ? pendingDescription : description : description;
82
- return (jsx(AlertDialog, { open: open, onOpenChange: (nextOpen) => {
83
- if (!nextOpen) {
84
- handleClose();
85
- return;
86
- }
87
- onOpenChange(nextOpen);
88
- }, children: jsxs(AlertDialogContent, { className: cn(dialogContentClass, 'border-red-300 dark:border-red-700'), overlayClassName: dialogThemedOverlayClass, onOverlayClick: pending ? undefined : handleClose, children: [jsxs("div", { className: dialogHeaderClass, children: [jsx(AlertDialogTitle, { asChild: true, children: jsxs("div", { className: dialogTitleClass, children: [jsx("span", { className: "inline-flex size-9 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-600 ring-1 ring-red-200 dark:bg-red-950 dark:text-red-300 dark:ring-red-900", children: pending ? jsx(Trash2Icon, { className: "size-5" }) : jsx(CircleAlertIcon, { className: "size-5" }) }), jsx("span", { className: "min-w-0 truncate", children: displayTitle })] }) }), jsx("button", { type: "button", className: closeButtonClass, onClick: handleClose, "aria-label": "Close", disabled: confirming, children: jsx(XIcon, { className: "size-4" }) })] }), jsx(AlertDialogDescription, { className: cn(dialogDescriptionClass, 'min-h-[44px]'), children: jsx("span", { children: displayDescription }) }), jsx("div", { className: "flex h-12 items-center justify-center py-1", children: jsxs("div", { className: "flex items-baseline justify-center gap-2", children: [jsx("span", { className: cn('text-4xl font-black leading-none tabular-nums', pending && 'animate-bounce', themeIconColor), children: pending ? remainingSeconds : safeCountdownSeconds }), jsx("span", { className: cn('text-sm font-bold', themeIconColor), children: "s" })] }) }), jsx("div", { className: cn(dialogFooterClass, 'min-h-[88px] sm:min-h-10 sm:items-center'), children: pending ? (jsxs("button", { type: "button", onClick: handleUndo, className: secondaryButtonClass, disabled: confirming, children: [jsx(Undo2Icon, { className: "mr-1.5 size-4" }), undoText] })) : (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: handleCancel, className: cancelButtonClass, children: cancelText }), jsx("button", { type: "button", onClick: startCountdown, className: confirmButtonClass, children: confirmText })] })) })] }) }));
81
+ return (jsxs(Fragment, { children: [jsx(AlertDialog, { open: open, onOpenChange: (nextOpen) => {
82
+ if (!nextOpen) {
83
+ handleClose();
84
+ return;
85
+ }
86
+ onOpenChange(nextOpen);
87
+ }, children: jsxs(AlertDialogContent, { className: cn(dialogContentClass, 'border-red-300 dark:border-red-700'), overlayClassName: dialogThemedOverlayClass, onOverlayClick: pending ? undefined : handleClose, children: [jsxs("div", { className: dialogHeaderClass, children: [jsx(AlertDialogTitle, { asChild: true, children: jsxs("div", { className: dialogTitleClass, children: [jsx("span", { className: "inline-flex size-9 shrink-0 items-center justify-center rounded-full bg-red-100 text-red-600 ring-1 ring-red-200 dark:bg-red-950 dark:text-red-300 dark:ring-red-900", children: pending ? jsx(Trash2Icon, { className: "size-5" }) : jsx(CircleAlertIcon, { className: "size-5" }) }), jsx("span", { className: "min-w-0 truncate", children: displayTitle })] }) }), jsx("button", { type: "button", className: closeButtonClass, onClick: handleClose, "aria-label": "Close", disabled: confirming, children: jsx(XIcon, { className: "size-4" }) })] }), jsx(AlertDialogDescription, { className: cn(dialogDescriptionClass, 'min-h-[44px]'), children: jsx("span", { children: displayDescription }) }), jsx("div", { className: "flex h-12 items-center justify-center py-1", children: jsxs("div", { className: "flex items-baseline justify-center gap-2", children: [jsx("span", { className: cn('text-4xl font-black leading-none tabular-nums', pending && 'animate-bounce', themeIconColor), children: pending ? remainingSeconds : safeCountdownSeconds }), jsx("span", { className: cn('text-sm font-bold', themeIconColor), children: "s" })] }) }), jsx("div", { className: cn(dialogFooterClass, 'min-h-[88px] sm:min-h-10 sm:items-center'), children: pending ? (jsxs("button", { type: "button", onClick: () => {
88
+ void handleUndo();
89
+ }, className: secondaryButtonClass, disabled: confirming, children: [jsx(Undo2Icon, { className: "mr-1.5 size-4" }), undoText] })) : (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: handleCancel, className: cancelButtonClass, children: cancelText }), jsx("button", { type: "button", onClick: startCountdown, className: confirmButtonClass, children: confirmText })] })) })] }) }), dialogLoading] }));
89
90
  }
90
91
 
91
92
  export { UndoableConfirmDialog };
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { PressFeedback } from './use-press-feedback';
2
3
  type GradientButtonVariant = 'default' | 'soft' | 'subtle';
3
4
  export interface GradientButtonProps {
4
5
  title: React.ReactNode;
@@ -15,6 +16,7 @@ export interface GradientButtonProps {
15
16
  loadingText?: React.ReactNode;
16
17
  preventDoubleClick?: boolean;
17
18
  variant?: GradientButtonVariant;
19
+ pressFeedback?: PressFeedback;
18
20
  }
19
- export declare function GradientButton({ title, icon, iconForcePosition, align, disabled, className, href, openInNewTab, preserveReferrer, onClick, loadingText, preventDoubleClick, iconClassName, variant, }: GradientButtonProps): import("react/jsx-runtime").JSX.Element;
21
+ export declare function GradientButton({ title, icon, iconForcePosition, align, disabled, className, href, openInNewTab, preserveReferrer, onClick, loadingText, preventDoubleClick, iconClassName, variant, pressFeedback, }: GradientButtonProps): import("react/jsx-runtime").JSX.Element;
20
22
  export {};
@@ -8,9 +8,15 @@ var icons = require('@windrun-huaiin/base-ui/icons');
8
8
  var lib = require('@windrun-huaiin/base-ui/lib');
9
9
  var Link = require('next/link');
10
10
  var React = require('react');
11
+ var usePressFeedback = require('./use-press-feedback.js');
11
12
 
12
- function GradientButton({ title, icon, iconForcePosition, align = 'left', disabled = false, className = "", href, openInNewTab = true, preserveReferrer = false, onClick, loadingText, preventDoubleClick = true, iconClassName, variant = 'default', }) {
13
+ const PRESS_FEEDBACK_MS = 180;
14
+ const gradientPressSubtleClass = 'translate-y-px scale-[0.98] shadow-inner brightness-95';
15
+ const gradientPressSolidClass = 'translate-y-[2px] scale-[0.96] shadow-[inset_0_2px_4px_rgba(15,23,42,0.22)] brightness-90';
16
+ function GradientButton({ title, icon, iconForcePosition, align = 'left', disabled = false, className = "", href, openInNewTab = true, preserveReferrer = false, onClick, loadingText, preventDoubleClick = true, iconClassName, variant = 'default', pressFeedback, }) {
13
17
  const [isLoading, setIsLoading] = React.useState(false);
18
+ const pressMode = usePressFeedback.resolvePressFeedbackMode(pressFeedback);
19
+ const { pressedKey, flash, getPressProps } = usePressFeedback.usePressFeedback(PRESS_FEEDBACK_MS);
14
20
  const actualLoadingText = loadingText || (title === null || title === void 0 ? void 0 : title.toString().trim()) || 'Loading...';
15
21
  const defaultIconClass = "h-4 w-4";
16
22
  const finalIconClass = utils.cn(variant === 'default' ? 'text-white' : lib.themeIconColor, iconClassName || defaultIconClass);
@@ -48,6 +54,12 @@ function GradientButton({ title, icon, iconForcePosition, align = 'left', disabl
48
54
  }
49
55
  });
50
56
  const isDisabled = disabled || isLoading;
57
+ const isPressed = pressMode !== 'none' && pressedKey === 'root' && !disabled;
58
+ const pressClassName = isPressed
59
+ ? pressMode === 'solid'
60
+ ? gradientPressSolidClass
61
+ : gradientPressSubtleClass
62
+ : null;
51
63
  const displayTitle = isLoading ? actualLoadingText : title;
52
64
  const iconProvided = icon !== undefined;
53
65
  const iconNode = (() => {
@@ -81,8 +93,22 @@ function GradientButton({ title, icon, iconForcePosition, align = 'left', disabl
81
93
  : variant === 'subtle'
82
94
  ? utils.cn(lib.themeMainBgColor, lib.themeIconColor, 'border border-neutral-200 shadow-sm hover:shadow-md hover:bg-neutral-50 dark:border-neutral-800 dark:hover:bg-neutral-800')
83
95
  : utils.cn(lib.themeButtonGradientClass, lib.themeButtonGradientHoverClass, 'text-white shadow-lg hover:shadow-xl');
84
- const buttonClassName = utils.cn(baseButtonStyles, variantClassName, 'text-base font-bold transition-all duration-300 rounded-full', alignmentClass, isDisabled && 'opacity-50 cursor-not-allowed', className);
85
- return (jsxRuntime.jsx("div", { className: `flex flex-row gap-3 ${getAlignmentClass()}`, children: onClick ? (jsxRuntime.jsx("button", { type: "button", className: buttonClassName, onClick: handleClick, disabled: isDisabled, children: buttonContent })) : (jsxRuntime.jsx(Link, Object.assign({ href: href || "#", className: utils.cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: preserveReferrer ? 'noopener' : 'noopener noreferrer' } : {}), { onClick: isDisabled ? (e) => e.preventDefault() : undefined, "aria-disabled": isDisabled, children: buttonContent }))) }));
96
+ const buttonClassName = utils.cn(baseButtonStyles, variantClassName, 'text-base font-bold transition-[transform,background-color,filter,box-shadow,border-color,color] duration-300 rounded-full', alignmentClass, pressClassName, isDisabled && 'opacity-50 cursor-not-allowed', className);
97
+ const pressProps = pressMode !== 'none' && !isDisabled ? getPressProps('root') : {};
98
+ return (jsxRuntime.jsx("div", { className: `flex flex-row gap-3 ${getAlignmentClass()}`, children: onClick ? (jsxRuntime.jsx("button", Object.assign({ type: "button", className: buttonClassName, onClick: (event) => {
99
+ if (!isDisabled && pressMode !== 'none') {
100
+ flash('root');
101
+ }
102
+ handleClick(event);
103
+ }, disabled: isDisabled }, pressProps, { children: buttonContent }))) : (jsxRuntime.jsx(Link, Object.assign({ href: href || "#", className: utils.cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: preserveReferrer ? 'noopener' : 'noopener noreferrer' } : {}), { onClick: (event) => {
104
+ if (isDisabled) {
105
+ event.preventDefault();
106
+ return;
107
+ }
108
+ if (pressMode !== 'none') {
109
+ flash('root');
110
+ }
111
+ }, "aria-disabled": isDisabled }, pressProps, { children: buttonContent }))) }));
86
112
  }
87
113
 
88
114
  exports.GradientButton = GradientButton;
@@ -6,9 +6,15 @@ import { Loader2Icon, ArrowRightIcon } from '@windrun-huaiin/base-ui/icons';
6
6
  import { themeIconColor, themeBgColor, themeBorderColor, themeMainBgColor, themeButtonGradientClass, themeButtonGradientHoverClass } from '@windrun-huaiin/base-ui/lib';
7
7
  import Link from 'next/link';
8
8
  import React__default, { useState } from 'react';
9
+ import { usePressFeedback, resolvePressFeedbackMode } from './use-press-feedback.mjs';
9
10
 
10
- function GradientButton({ title, icon, iconForcePosition, align = 'left', disabled = false, className = "", href, openInNewTab = true, preserveReferrer = false, onClick, loadingText, preventDoubleClick = true, iconClassName, variant = 'default', }) {
11
+ const PRESS_FEEDBACK_MS = 180;
12
+ const gradientPressSubtleClass = 'translate-y-px scale-[0.98] shadow-inner brightness-95';
13
+ const gradientPressSolidClass = 'translate-y-[2px] scale-[0.96] shadow-[inset_0_2px_4px_rgba(15,23,42,0.22)] brightness-90';
14
+ function GradientButton({ title, icon, iconForcePosition, align = 'left', disabled = false, className = "", href, openInNewTab = true, preserveReferrer = false, onClick, loadingText, preventDoubleClick = true, iconClassName, variant = 'default', pressFeedback, }) {
11
15
  const [isLoading, setIsLoading] = useState(false);
16
+ const pressMode = resolvePressFeedbackMode(pressFeedback);
17
+ const { pressedKey, flash, getPressProps } = usePressFeedback(PRESS_FEEDBACK_MS);
12
18
  const actualLoadingText = loadingText || (title === null || title === void 0 ? void 0 : title.toString().trim()) || 'Loading...';
13
19
  const defaultIconClass = "h-4 w-4";
14
20
  const finalIconClass = cn(variant === 'default' ? 'text-white' : themeIconColor, iconClassName || defaultIconClass);
@@ -46,6 +52,12 @@ function GradientButton({ title, icon, iconForcePosition, align = 'left', disabl
46
52
  }
47
53
  });
48
54
  const isDisabled = disabled || isLoading;
55
+ const isPressed = pressMode !== 'none' && pressedKey === 'root' && !disabled;
56
+ const pressClassName = isPressed
57
+ ? pressMode === 'solid'
58
+ ? gradientPressSolidClass
59
+ : gradientPressSubtleClass
60
+ : null;
49
61
  const displayTitle = isLoading ? actualLoadingText : title;
50
62
  const iconProvided = icon !== undefined;
51
63
  const iconNode = (() => {
@@ -79,8 +91,22 @@ function GradientButton({ title, icon, iconForcePosition, align = 'left', disabl
79
91
  : variant === 'subtle'
80
92
  ? cn(themeMainBgColor, themeIconColor, 'border border-neutral-200 shadow-sm hover:shadow-md hover:bg-neutral-50 dark:border-neutral-800 dark:hover:bg-neutral-800')
81
93
  : cn(themeButtonGradientClass, themeButtonGradientHoverClass, 'text-white shadow-lg hover:shadow-xl');
82
- const buttonClassName = cn(baseButtonStyles, variantClassName, 'text-base font-bold transition-all duration-300 rounded-full', alignmentClass, isDisabled && 'opacity-50 cursor-not-allowed', className);
83
- return (jsx("div", { className: `flex flex-row gap-3 ${getAlignmentClass()}`, children: onClick ? (jsx("button", { type: "button", className: buttonClassName, onClick: handleClick, disabled: isDisabled, children: buttonContent })) : (jsx(Link, Object.assign({ href: href || "#", className: cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: preserveReferrer ? 'noopener' : 'noopener noreferrer' } : {}), { onClick: isDisabled ? (e) => e.preventDefault() : undefined, "aria-disabled": isDisabled, children: buttonContent }))) }));
94
+ const buttonClassName = cn(baseButtonStyles, variantClassName, 'text-base font-bold transition-[transform,background-color,filter,box-shadow,border-color,color] duration-300 rounded-full', alignmentClass, pressClassName, isDisabled && 'opacity-50 cursor-not-allowed', className);
95
+ const pressProps = pressMode !== 'none' && !isDisabled ? getPressProps('root') : {};
96
+ return (jsx("div", { className: `flex flex-row gap-3 ${getAlignmentClass()}`, children: onClick ? (jsx("button", Object.assign({ type: "button", className: buttonClassName, onClick: (event) => {
97
+ if (!isDisabled && pressMode !== 'none') {
98
+ flash('root');
99
+ }
100
+ handleClick(event);
101
+ }, disabled: isDisabled }, pressProps, { children: buttonContent }))) : (jsx(Link, Object.assign({ href: href || "#", className: cn(buttonClassName, "no-underline hover:no-underline") }, (openInNewTab ? { target: "_blank", rel: preserveReferrer ? 'noopener' : 'noopener noreferrer' } : {}), { onClick: (event) => {
102
+ if (isDisabled) {
103
+ event.preventDefault();
104
+ return;
105
+ }
106
+ if (pressMode !== 'none') {
107
+ flash('root');
108
+ }
109
+ }, "aria-disabled": isDisabled }, pressProps, { children: buttonContent }))) }));
84
110
  }
85
111
 
86
112
  export { GradientButton };
@@ -1,4 +1,5 @@
1
1
  export * from './gradient-button';
2
+ export * from './use-press-feedback';
2
3
  export * from './x-button';
3
4
  export * from './x-switch-button';
4
5
  export * from './x-toggle-button';
@@ -2,6 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var gradientButton = require('./gradient-button.js');
5
+ var usePressFeedback = require('./use-press-feedback.js');
5
6
  var xButton = require('./x-button.js');
6
7
  var xSwitchButton = require('./x-switch-button.js');
7
8
  var xToggleButton = require('./x-toggle-button.js');
@@ -9,6 +10,8 @@ var xToggleButton = require('./x-toggle-button.js');
9
10
 
10
11
 
11
12
  exports.GradientButton = gradientButton.GradientButton;
13
+ exports.resolvePressFeedbackMode = usePressFeedback.resolvePressFeedbackMode;
14
+ exports.usePressFeedback = usePressFeedback.usePressFeedback;
12
15
  exports.XButton = xButton.XButton;
13
16
  exports.XSwitchButton = xSwitchButton.XSwitchButton;
14
17
  exports.XToggleButton = xToggleButton.XToggleButton;
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  export { GradientButton } from './gradient-button.mjs';
3
+ export { resolvePressFeedbackMode, usePressFeedback } from './use-press-feedback.mjs';
3
4
  export { XButton } from './x-button.mjs';
4
5
  export { XSwitchButton } from './x-switch-button.mjs';
5
6
  export { XToggleButton } from './x-toggle-button.mjs';
@@ -0,0 +1,18 @@
1
+ export type PressFeedbackKey = string;
2
+ export type PressFeedbackMode = 'none' | 'subtle' | 'solid';
3
+ export type PressFeedback = boolean | PressFeedbackMode;
4
+ export interface PressFeedbackProps<T extends PressFeedbackKey> {
5
+ onPointerDown: () => void;
6
+ onPointerUp: () => void;
7
+ onPointerLeave: () => void;
8
+ onPointerCancel: () => void;
9
+ onBlur: () => void;
10
+ }
11
+ export declare function resolvePressFeedbackMode(pressFeedback?: PressFeedback): PressFeedbackMode;
12
+ export declare function usePressFeedback<T extends PressFeedbackKey>(durationMs?: number): {
13
+ pressedKey: T | null;
14
+ trigger: (key: T) => void;
15
+ release: (key: T) => void;
16
+ flash: (key: T) => void;
17
+ getPressProps: (key: T) => PressFeedbackProps<T>;
18
+ };
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+
6
+ function resolvePressFeedbackMode(pressFeedback) {
7
+ if (pressFeedback === false || pressFeedback === 'none') {
8
+ return 'none';
9
+ }
10
+ if (pressFeedback === 'solid') {
11
+ return 'solid';
12
+ }
13
+ return 'subtle';
14
+ }
15
+ function usePressFeedback(durationMs = 180) {
16
+ const [pressedKey, setPressedKey] = React.useState(null);
17
+ function release(key) {
18
+ setPressedKey((current) => (current === key ? null : current));
19
+ }
20
+ function trigger(key) {
21
+ setPressedKey(key);
22
+ }
23
+ function flash(key) {
24
+ setPressedKey(key);
25
+ window.setTimeout(() => {
26
+ setPressedKey((current) => (current === key ? null : current));
27
+ }, durationMs);
28
+ }
29
+ function getPressProps(key) {
30
+ return {
31
+ onPointerDown: () => trigger(key),
32
+ onPointerUp: () => release(key),
33
+ onPointerLeave: () => release(key),
34
+ onPointerCancel: () => release(key),
35
+ onBlur: () => release(key),
36
+ };
37
+ }
38
+ return { pressedKey, trigger, release, flash, getPressProps };
39
+ }
40
+
41
+ exports.resolvePressFeedbackMode = resolvePressFeedbackMode;
42
+ exports.usePressFeedback = usePressFeedback;
@@ -0,0 +1,39 @@
1
+ "use client";
2
+ import { useState } from 'react';
3
+
4
+ function resolvePressFeedbackMode(pressFeedback) {
5
+ if (pressFeedback === false || pressFeedback === 'none') {
6
+ return 'none';
7
+ }
8
+ if (pressFeedback === 'solid') {
9
+ return 'solid';
10
+ }
11
+ return 'subtle';
12
+ }
13
+ function usePressFeedback(durationMs = 180) {
14
+ const [pressedKey, setPressedKey] = useState(null);
15
+ function release(key) {
16
+ setPressedKey((current) => (current === key ? null : current));
17
+ }
18
+ function trigger(key) {
19
+ setPressedKey(key);
20
+ }
21
+ function flash(key) {
22
+ setPressedKey(key);
23
+ window.setTimeout(() => {
24
+ setPressedKey((current) => (current === key ? null : current));
25
+ }, durationMs);
26
+ }
27
+ function getPressProps(key) {
28
+ return {
29
+ onPointerDown: () => trigger(key),
30
+ onPointerUp: () => release(key),
31
+ onPointerLeave: () => release(key),
32
+ onPointerCancel: () => release(key),
33
+ onBlur: () => release(key),
34
+ };
35
+ }
36
+ return { pressedKey, trigger, release, flash, getPressProps };
37
+ }
38
+
39
+ export { resolvePressFeedbackMode, usePressFeedback };
@@ -1,4 +1,5 @@
1
1
  import { ReactNode } from 'react';
2
+ import { PressFeedback } from './use-press-feedback';
2
3
  type XButtonVariant = 'default' | 'soft' | 'subtle';
3
4
  interface BaseButtonConfig {
4
5
  icon: ReactNode;
@@ -21,6 +22,7 @@ interface SingleButtonProps {
21
22
  className?: string;
22
23
  iconClassName?: string;
23
24
  variant?: XButtonVariant;
25
+ pressFeedback?: PressFeedback;
24
26
  }
25
27
  interface SplitButtonProps {
26
28
  type: 'split';
@@ -33,6 +35,7 @@ interface SplitButtonProps {
33
35
  dropdownButtonClassName?: string;
34
36
  iconClassName?: string;
35
37
  variant?: XButtonVariant;
38
+ pressFeedback?: PressFeedback;
36
39
  }
37
40
  type xButtonProps = SingleButtonProps | SplitButtonProps;
38
41
  export declare function XButton(props: xButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -7,12 +7,18 @@ var React = require('react');
7
7
  var icons = require('@windrun-huaiin/base-ui/icons');
8
8
  var lib = require('@windrun-huaiin/base-ui/lib');
9
9
  var utils = require('@windrun-huaiin/lib/utils');
10
+ var usePressFeedback = require('./use-press-feedback.js');
10
11
 
12
+ const PRESS_FEEDBACK_MS = 180;
13
+ const xButtonPressSubtleClass = 'translate-y-px scale-[0.98] shadow-inner brightness-95';
14
+ const xButtonPressSolidClass = 'translate-y-[2px] scale-[0.95] shadow-[inset_0_2px_4px_rgba(15,23,42,0.18)] brightness-95';
11
15
  function XButton(props) {
12
16
  var _a, _b, _c;
13
17
  const [isLoading, setIsLoading] = React.useState(false);
14
18
  const [menuOpen, setMenuOpen] = React.useState(false);
15
- const menuRef = React.useRef(null);
19
+ const splitRef = React.useRef(null);
20
+ const pressMode = usePressFeedback.resolvePressFeedbackMode(props.pressFeedback);
21
+ const { pressedKey, flash, getPressProps } = usePressFeedback.usePressFeedback(PRESS_FEEDBACK_MS);
16
22
  const { iconClassName } = props;
17
23
  const defaultIconClass = "w-5 h-5";
18
24
  const variant = (_a = props.variant) !== null && _a !== void 0 ? _a : 'default';
@@ -30,7 +36,7 @@ function XButton(props) {
30
36
  React.useEffect(() => {
31
37
  if (props.type === 'split') {
32
38
  const handleClickOutside = (event) => {
33
- if (menuRef.current && !menuRef.current.contains(event.target)) {
39
+ if (splitRef.current && !splitRef.current.contains(event.target)) {
34
40
  setMenuOpen(false);
35
41
  }
36
42
  };
@@ -56,7 +62,8 @@ function XButton(props) {
56
62
  setIsLoading(false);
57
63
  }
58
64
  });
59
- const baseButtonClass = "flex items-center justify-center gap-2 px-4 py-2 text-sm font-semibold transition-colors";
65
+ const getButtonPressClass = () => pressMode === 'solid' ? xButtonPressSolidClass : xButtonPressSubtleClass;
66
+ const baseButtonClass = "flex items-center justify-center gap-2 px-4 py-2 text-sm font-semibold transition-[transform,background-color,filter,box-shadow,border-color,color]";
60
67
  const singleButtonVariantClass = variant === 'soft'
61
68
  ? utils.cn(lib.themeBgColor, lib.themeIconColor, lib.themeBorderColor, "border hover:brightness-95")
62
69
  : variant === 'subtle'
@@ -72,18 +79,41 @@ function XButton(props) {
72
79
  : variant === 'subtle'
73
80
  ? utils.cn("bg-transparent hover:bg-neutral-50 dark:hover:bg-neutral-800 sm:border-l", lib.themeIconColor, "border-neutral-200 dark:border-neutral-800")
74
81
  : "bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white hover:bg-neutral-300 dark:hover:bg-neutral-700 sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700";
82
+ const splitContainerVariantClass = variant === 'soft'
83
+ ? utils.cn('border', lib.themeBorderColor)
84
+ : variant === 'subtle'
85
+ ? 'border border-neutral-200 dark:border-neutral-800'
86
+ : null;
75
87
  const disabledClass = "opacity-60 cursor-not-allowed";
76
88
  if (props.type === 'single') {
77
89
  const { button, loadingText, minWidth = 'min-w-[110px]', className = '' } = props;
78
90
  const isDisabled = button.disabled || isLoading;
91
+ const isPressed = pressMode !== 'none' && pressedKey === 'single' && !button.disabled;
79
92
  const actualLoadingText = loadingText || ((_b = button.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
80
- return (jsxRuntime.jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: utils.cn("w-full sm:w-auto", minWidth, baseButtonClass, singleButtonVariantClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.Loader2Icon, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderIcon(button.icon), jsxRuntime.jsx("span", { children: button.text })] })) }));
93
+ return (jsxRuntime.jsx("button", Object.assign({ onClick: () => {
94
+ if (!isDisabled && pressMode !== 'none') {
95
+ flash('single');
96
+ }
97
+ handleButtonClick(button.onClick);
98
+ }, disabled: isDisabled }, (pressMode !== 'none' && !isDisabled ? getPressProps('single') : {}), { className: utils.cn("w-full sm:w-auto", minWidth, baseButtonClass, singleButtonVariantClass, "rounded-full", isPressed && getButtonPressClass(), isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.Loader2Icon, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderIcon(button.icon), jsxRuntime.jsx("span", { children: button.text })] })) })));
81
99
  }
82
100
  const { mainButton, menuItems, loadingText, menuWidth = 'w-full sm:w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
83
101
  const isMainDisabled = mainButton.disabled || isLoading;
102
+ const isMainPressed = pressMode !== 'none' && pressedKey === 'main' && !mainButton.disabled;
103
+ const isDropdownPressed = pressMode !== 'none' && pressedKey === 'dropdown' && !isLoading;
84
104
  const actualLoadingText = loadingText || ((_c = mainButton.text) === null || _c === void 0 ? void 0 : _c.trim()) || 'Loading...';
85
- return (jsxRuntime.jsxs("div", { className: utils.cn("relative flex flex-row items-stretch w-full sm:w-auto rounded-full gap-0", menuOpen && "z-90", className), children: [jsxRuntime.jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: utils.cn("flex-1 min-w-0 sm:min-w-[100px] sm:flex-initial rounded-l-full", baseButtonClass, splitMainButtonVariantClass, isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
86
- e.preventDefault(); }, title: mainButton.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.Loader2Icon, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderIcon(mainButton.icon), jsxRuntime.jsx("span", { children: mainButton.text })] })) }), jsxRuntime.jsx("button", { type: "button", onClick: () => setMenuOpen(!menuOpen), disabled: isLoading, className: utils.cn("w-12 rounded-r-full", baseButtonClass, splitDropdownVariantClass, isLoading && disabledClass, dropdownButtonClassName), "aria-label": "Open menu", children: jsxRuntime.jsx(icons.ChevronDownIcon, { className: utils.cn(chevronIconClass, menuOpen && "rotate-180", "transition-transform") }) }), menuOpen && (jsxRuntime.jsx("div", { ref: menuRef, className: utils.cn("absolute top-full right-0 mt-2 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow-lg z-50 overflow-hidden", menuWidth), children: menuItems.map((item, index) => (jsxRuntime.jsxs("button", { type: "button", onClick: () => {
105
+ return (jsxRuntime.jsxs("div", { className: utils.cn("relative inline-flex flex-row items-stretch w-full sm:w-fit rounded-full gap-0", splitContainerVariantClass, menuOpen && "z-90", className), ref: splitRef, children: [jsxRuntime.jsx("button", Object.assign({ onClick: () => {
106
+ if (!isMainDisabled && pressMode !== 'none') {
107
+ flash('main');
108
+ }
109
+ handleButtonClick(mainButton.onClick);
110
+ }, disabled: isMainDisabled }, (pressMode !== 'none' && !isMainDisabled ? getPressProps('main') : {}), { className: utils.cn("flex-1 min-w-0 sm:min-w-[100px] sm:flex-initial rounded-l-full", baseButtonClass, splitMainButtonVariantClass, isMainPressed && getButtonPressClass(), isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
111
+ e.preventDefault(); }, title: mainButton.text, children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(icons.Loader2Icon, { className: loadingIconClass }), jsxRuntime.jsx("span", { children: actualLoadingText })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderIcon(mainButton.icon), jsxRuntime.jsx("span", { children: mainButton.text })] })) })), jsxRuntime.jsx("button", Object.assign({ type: "button", onClick: () => {
112
+ if (!isLoading && pressMode !== 'none') {
113
+ flash('dropdown');
114
+ }
115
+ setMenuOpen(!menuOpen);
116
+ }, disabled: isLoading }, (pressMode !== 'none' && !isLoading ? getPressProps('dropdown') : {}), { className: utils.cn("w-12 rounded-r-full", baseButtonClass, splitDropdownVariantClass, isDropdownPressed && getButtonPressClass(), isLoading && disabledClass, dropdownButtonClassName), "aria-label": "Open menu", children: jsxRuntime.jsx(icons.ChevronDownIcon, { className: utils.cn(chevronIconClass, menuOpen && "rotate-180", "transition-transform") }) })), menuOpen && (jsxRuntime.jsx("div", { className: utils.cn("absolute top-full right-0 mt-2 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow-lg z-50 overflow-hidden", menuWidth), children: menuItems.map((item, index) => (jsxRuntime.jsxs("button", { type: "button", onClick: () => {
87
117
  setMenuOpen(false);
88
118
  handleButtonClick(item.onClick);
89
119
  }, disabled: item.disabled || isLoading, className: utils.cn("w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-neutral-100 dark:hover:bg-neutral-700 transition-colors", item.disabled && disabledClass, item.splitTopBorder && "border-t border-neutral-200 dark:border-neutral-700"), children: [renderIcon(item.icon), jsxRuntime.jsx("span", { className: "flex-1", children: item.text }), item.tag && (jsxRuntime.jsx("span", { className: utils.cn("px-1.5 py-0.5 text-xs rounded", item.tag.color || "bg-blue-100 text-blue-800"), children: item.tag.text }))] }, index))) }))] }));
@@ -5,12 +5,18 @@ import React__default, { useState, useRef, useEffect } from 'react';
5
5
  import { Loader2Icon, ChevronDownIcon } from '@windrun-huaiin/base-ui/icons';
6
6
  import { themeIconColor, themeBgColor, themeBorderColor, themeMainBgColor } from '@windrun-huaiin/base-ui/lib';
7
7
  import { cn } from '@windrun-huaiin/lib/utils';
8
+ import { resolvePressFeedbackMode, usePressFeedback } from './use-press-feedback.mjs';
8
9
 
10
+ const PRESS_FEEDBACK_MS = 180;
11
+ const xButtonPressSubtleClass = 'translate-y-px scale-[0.98] shadow-inner brightness-95';
12
+ const xButtonPressSolidClass = 'translate-y-[2px] scale-[0.95] shadow-[inset_0_2px_4px_rgba(15,23,42,0.18)] brightness-95';
9
13
  function XButton(props) {
10
14
  var _a, _b, _c;
11
15
  const [isLoading, setIsLoading] = useState(false);
12
16
  const [menuOpen, setMenuOpen] = useState(false);
13
- const menuRef = useRef(null);
17
+ const splitRef = useRef(null);
18
+ const pressMode = resolvePressFeedbackMode(props.pressFeedback);
19
+ const { pressedKey, flash, getPressProps } = usePressFeedback(PRESS_FEEDBACK_MS);
14
20
  const { iconClassName } = props;
15
21
  const defaultIconClass = "w-5 h-5";
16
22
  const variant = (_a = props.variant) !== null && _a !== void 0 ? _a : 'default';
@@ -28,7 +34,7 @@ function XButton(props) {
28
34
  useEffect(() => {
29
35
  if (props.type === 'split') {
30
36
  const handleClickOutside = (event) => {
31
- if (menuRef.current && !menuRef.current.contains(event.target)) {
37
+ if (splitRef.current && !splitRef.current.contains(event.target)) {
32
38
  setMenuOpen(false);
33
39
  }
34
40
  };
@@ -54,7 +60,8 @@ function XButton(props) {
54
60
  setIsLoading(false);
55
61
  }
56
62
  });
57
- const baseButtonClass = "flex items-center justify-center gap-2 px-4 py-2 text-sm font-semibold transition-colors";
63
+ const getButtonPressClass = () => pressMode === 'solid' ? xButtonPressSolidClass : xButtonPressSubtleClass;
64
+ const baseButtonClass = "flex items-center justify-center gap-2 px-4 py-2 text-sm font-semibold transition-[transform,background-color,filter,box-shadow,border-color,color]";
58
65
  const singleButtonVariantClass = variant === 'soft'
59
66
  ? cn(themeBgColor, themeIconColor, themeBorderColor, "border hover:brightness-95")
60
67
  : variant === 'subtle'
@@ -70,18 +77,41 @@ function XButton(props) {
70
77
  : variant === 'subtle'
71
78
  ? cn("bg-transparent hover:bg-neutral-50 dark:hover:bg-neutral-800 sm:border-l", themeIconColor, "border-neutral-200 dark:border-neutral-800")
72
79
  : "bg-neutral-200 dark:bg-neutral-800 text-neutral-700 dark:text-white hover:bg-neutral-300 dark:hover:bg-neutral-700 sm:border-l sm:border-neutral-300 sm:dark:border-neutral-700";
80
+ const splitContainerVariantClass = variant === 'soft'
81
+ ? cn('border', themeBorderColor)
82
+ : variant === 'subtle'
83
+ ? 'border border-neutral-200 dark:border-neutral-800'
84
+ : null;
73
85
  const disabledClass = "opacity-60 cursor-not-allowed";
74
86
  if (props.type === 'single') {
75
87
  const { button, loadingText, minWidth = 'min-w-[110px]', className = '' } = props;
76
88
  const isDisabled = button.disabled || isLoading;
89
+ const isPressed = pressMode !== 'none' && pressedKey === 'single' && !button.disabled;
77
90
  const actualLoadingText = loadingText || ((_b = button.text) === null || _b === void 0 ? void 0 : _b.trim()) || 'Loading...';
78
- return (jsx("button", { onClick: () => handleButtonClick(button.onClick), disabled: isDisabled, className: cn("w-full sm:w-auto", minWidth, baseButtonClass, singleButtonVariantClass, "rounded-full", isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxs(Fragment, { children: [jsx(Loader2Icon, { className: loadingIconClass }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [renderIcon(button.icon), jsx("span", { children: button.text })] })) }));
91
+ return (jsx("button", Object.assign({ onClick: () => {
92
+ if (!isDisabled && pressMode !== 'none') {
93
+ flash('single');
94
+ }
95
+ handleButtonClick(button.onClick);
96
+ }, disabled: isDisabled }, (pressMode !== 'none' && !isDisabled ? getPressProps('single') : {}), { className: cn("w-full sm:w-auto", minWidth, baseButtonClass, singleButtonVariantClass, "rounded-full", isPressed && getButtonPressClass(), isDisabled && disabledClass, className), title: button.text, children: isLoading ? (jsxs(Fragment, { children: [jsx(Loader2Icon, { className: loadingIconClass }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [renderIcon(button.icon), jsx("span", { children: button.text })] })) })));
79
97
  }
80
98
  const { mainButton, menuItems, loadingText, menuWidth = 'w-full sm:w-40', className = '', mainButtonClassName = '', dropdownButtonClassName = '' } = props;
81
99
  const isMainDisabled = mainButton.disabled || isLoading;
100
+ const isMainPressed = pressMode !== 'none' && pressedKey === 'main' && !mainButton.disabled;
101
+ const isDropdownPressed = pressMode !== 'none' && pressedKey === 'dropdown' && !isLoading;
82
102
  const actualLoadingText = loadingText || ((_c = mainButton.text) === null || _c === void 0 ? void 0 : _c.trim()) || 'Loading...';
83
- return (jsxs("div", { className: cn("relative flex flex-row items-stretch w-full sm:w-auto rounded-full gap-0", menuOpen && "z-90", className), children: [jsx("button", { onClick: () => handleButtonClick(mainButton.onClick), disabled: isMainDisabled, className: cn("flex-1 min-w-0 sm:min-w-[100px] sm:flex-initial rounded-l-full", baseButtonClass, splitMainButtonVariantClass, isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
84
- e.preventDefault(); }, title: mainButton.text, children: isLoading ? (jsxs(Fragment, { children: [jsx(Loader2Icon, { className: loadingIconClass }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [renderIcon(mainButton.icon), jsx("span", { children: mainButton.text })] })) }), jsx("button", { type: "button", onClick: () => setMenuOpen(!menuOpen), disabled: isLoading, className: cn("w-12 rounded-r-full", baseButtonClass, splitDropdownVariantClass, isLoading && disabledClass, dropdownButtonClassName), "aria-label": "Open menu", children: jsx(ChevronDownIcon, { className: cn(chevronIconClass, menuOpen && "rotate-180", "transition-transform") }) }), menuOpen && (jsx("div", { ref: menuRef, className: cn("absolute top-full right-0 mt-2 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow-lg z-50 overflow-hidden", menuWidth), children: menuItems.map((item, index) => (jsxs("button", { type: "button", onClick: () => {
103
+ return (jsxs("div", { className: cn("relative inline-flex flex-row items-stretch w-full sm:w-fit rounded-full gap-0", splitContainerVariantClass, menuOpen && "z-90", className), ref: splitRef, children: [jsx("button", Object.assign({ onClick: () => {
104
+ if (!isMainDisabled && pressMode !== 'none') {
105
+ flash('main');
106
+ }
107
+ handleButtonClick(mainButton.onClick);
108
+ }, disabled: isMainDisabled }, (pressMode !== 'none' && !isMainDisabled ? getPressProps('main') : {}), { className: cn("flex-1 min-w-0 sm:min-w-[100px] sm:flex-initial rounded-l-full", baseButtonClass, splitMainButtonVariantClass, isMainPressed && getButtonPressClass(), isMainDisabled && disabledClass, mainButtonClassName), onMouseDown: e => { if (e.button === 2)
109
+ e.preventDefault(); }, title: mainButton.text, children: isLoading ? (jsxs(Fragment, { children: [jsx(Loader2Icon, { className: loadingIconClass }), jsx("span", { children: actualLoadingText })] })) : (jsxs(Fragment, { children: [renderIcon(mainButton.icon), jsx("span", { children: mainButton.text })] })) })), jsx("button", Object.assign({ type: "button", onClick: () => {
110
+ if (!isLoading && pressMode !== 'none') {
111
+ flash('dropdown');
112
+ }
113
+ setMenuOpen(!menuOpen);
114
+ }, disabled: isLoading }, (pressMode !== 'none' && !isLoading ? getPressProps('dropdown') : {}), { className: cn("w-12 rounded-r-full", baseButtonClass, splitDropdownVariantClass, isDropdownPressed && getButtonPressClass(), isLoading && disabledClass, dropdownButtonClassName), "aria-label": "Open menu", children: jsx(ChevronDownIcon, { className: cn(chevronIconClass, menuOpen && "rotate-180", "transition-transform") }) })), menuOpen && (jsx("div", { className: cn("absolute top-full right-0 mt-2 bg-white dark:bg-neutral-800 border border-neutral-200 dark:border-neutral-700 rounded-lg shadow-lg z-50 overflow-hidden", menuWidth), children: menuItems.map((item, index) => (jsxs("button", { type: "button", onClick: () => {
85
115
  setMenuOpen(false);
86
116
  handleButtonClick(item.onClick);
87
117
  }, disabled: item.disabled || isLoading, className: cn("w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-neutral-100 dark:hover:bg-neutral-700 transition-colors", item.disabled && disabledClass, item.splitTopBorder && "border-t border-neutral-200 dark:border-neutral-700"), children: [renderIcon(item.icon), jsx("span", { className: "flex-1", children: item.text }), item.tag && (jsx("span", { className: cn("px-1.5 py-0.5 text-xs rounded", item.tag.color || "bg-blue-100 text-blue-800"), children: item.tag.text }))] }, index))) }))] }));
@@ -0,0 +1,17 @@
1
+ import { type PressFeedback } from '../buttons/use-press-feedback';
2
+ import { type RandomCalendarRange } from './random-date-range-dialog';
3
+ export type CalendarDateRangeValue = RandomCalendarRange;
4
+ export type CalendarDateRangeInputProps = {
5
+ value: CalendarDateRangeValue;
6
+ onChange: (value: CalendarDateRangeValue) => void;
7
+ placeholder?: string;
8
+ defaultRangeDays?: number;
9
+ disabled?: boolean;
10
+ className?: string;
11
+ showDayCount?: boolean;
12
+ dayCountUnit?: string;
13
+ themedCalendarIcon?: boolean;
14
+ clearPressFeedback?: PressFeedback;
15
+ onOpenChange?: (open: boolean) => void;
16
+ };
17
+ export declare function CalendarDateRangeInput({ value, onChange, placeholder, defaultRangeDays, disabled, className, showDayCount, dayCountUnit, themedCalendarIcon, clearPressFeedback, onOpenChange, }: CalendarDateRangeInputProps): import("react/jsx-runtime").JSX.Element;