diff --git a/.changeset/clean-cameras-hunt.md b/.changeset/clean-cameras-hunt.md
new file mode 100644
index 000000000..e796094ed
--- /dev/null
+++ b/.changeset/clean-cameras-hunt.md
@@ -0,0 +1,38 @@
+---
+"@cube-dev/ui-kit": minor
+---
+
+**Breaking Change:** AlertDialog API cancel button behavior changed
+
+The `cancel` button in AlertDialog now rejects the promise instead of resolving with `'cancel'` status, aligning it with the dismiss (Escape key) behavior.
+
+**Migration Guide:**
+
+**Before:**
+```typescript
+alertDialogAPI.open({...})
+ .then((status) => {
+ if (status === 'cancel') {
+ // Handle cancel
+ } else if (status === 'confirm') {
+ // Handle confirm
+ }
+ })
+```
+
+**After:**
+```typescript
+alertDialogAPI.open({...})
+ .then((status) => {
+ if (status === 'confirm') {
+ // Handle confirm
+ } else if (status === 'secondary') {
+ // Handle secondary action
+ }
+ })
+ .catch(() => {
+ // Handle cancel or dismiss
+ })
+```
+
+**Note:** `AlertDialogResolveStatus` type no longer includes `'cancel'` - it now only contains `'confirm' | 'secondary'`.
diff --git a/src/components/overlays/AlertDialog/AlertDialogApiProvider.tsx b/src/components/overlays/AlertDialog/AlertDialogApiProvider.tsx
index 1af8af6db..7ce52d455 100644
--- a/src/components/overlays/AlertDialog/AlertDialogApiProvider.tsx
+++ b/src/components/overlays/AlertDialog/AlertDialogApiProvider.tsx
@@ -129,7 +129,19 @@ export function AlertDialogApiProvider(props) {
* cancelToken: abortDialog.signal
* });
*
- * openedDialog.then(() => console.log('closed'))
+ * openedDialog
+ * .then((status) => {
+ * // User confirmed or used secondary action
+ * if (status === 'confirm') {
+ * // Handle confirm
+ * } else if (status === 'secondary') {
+ * // Handle secondary action
+ * }
+ * })
+ * .catch(() => {
+ * // User cancelled or dismissed the dialog
+ * // Handle cancel/dismiss
+ * })
*
* return () => {
* abortDialog.abort();
@@ -141,6 +153,14 @@ export function AlertDialogApiProvider(props) {
*
* const onPress = useCallback(() => {
* alertDialogAPI.open({...})
+ * .then((status) => {
+ * if (status === 'confirm') {
+ * // Handle confirm
+ * }
+ * })
+ * .catch(() => {
+ * // Handle cancel/dismiss
+ * })
* }, [])
*
* return
diff --git a/src/components/overlays/AlertDialog/AlertDialogZone.tsx b/src/components/overlays/AlertDialog/AlertDialogZone.tsx
index 4d0ca86c7..1ad34d040 100644
--- a/src/components/overlays/AlertDialog/AlertDialogZone.tsx
+++ b/src/components/overlays/AlertDialog/AlertDialogZone.tsx
@@ -64,7 +64,20 @@ export function AlertDialogZone(props: DialogZoneProps) {
return {
confirm: mergeActionProps(actions.confirm, 'confirm'),
secondary: mergeActionProps(actions.secondary, 'secondary'),
- cancel: mergeActionProps(actions.cancel, 'cancel'),
+ cancel:
+ typeof actions.cancel === 'undefined'
+ ? undefined
+ : typeof actions.cancel === 'boolean'
+ ? actions.cancel
+ ? { onPress: () => reject(undefined) }
+ : false
+ : {
+ ...(actions.cancel as CubeButtonProps),
+ onPress: (e) => {
+ (actions.cancel as CubeButtonProps).onPress?.(e);
+ reject(undefined);
+ },
+ },
};
})();
diff --git a/src/components/overlays/AlertDialog/tests/use-alert-dialog-api.test.tsx b/src/components/overlays/AlertDialog/tests/use-alert-dialog-api.test.tsx
index 223810db5..5d411a0ff 100644
--- a/src/components/overlays/AlertDialog/tests/use-alert-dialog-api.test.tsx
+++ b/src/components/overlays/AlertDialog/tests/use-alert-dialog-api.test.tsx
@@ -89,4 +89,70 @@ describe('useAlertDialogApi()', () => {
expect(onReject).toHaveBeenCalled();
await expect(dialogPromise).rejects.toEqual(undefined);
});
+
+ it('should reject when cancel button (boolean) is clicked', async () => {
+ const { getByRole } = renderWithRoot(
+ ,
+ );
+ const showDialogButton = getByRole('button', { name: 'Open Dialog' });
+
+ await userEvent.click(showDialogButton);
+
+ const cancelButton = getByRole('button', { name: 'Cancel' });
+
+ await userEvent.click(cancelButton);
+
+ expect(onReject).toHaveBeenCalled();
+ await expect(dialogPromise).rejects.toEqual(undefined);
+ });
+
+ it('should reject when cancel button (object) is clicked', async () => {
+ const { getByRole } = renderWithRoot(
+ ,
+ );
+ const showDialogButton = getByRole('button', { name: 'Open Dialog' });
+
+ await userEvent.click(showDialogButton);
+
+ const cancelButton = getByRole('button', { name: 'No thanks' });
+
+ await userEvent.click(cancelButton);
+
+ expect(onReject).toHaveBeenCalled();
+ await expect(dialogPromise).rejects.toEqual(undefined);
+ });
+
+ it('should resolve when confirm button is clicked', async () => {
+ const { getByRole } = renderWithRoot(
+ ,
+ );
+ const showDialogButton = getByRole('button', { name: 'Open Dialog' });
+
+ await userEvent.click(showDialogButton);
+
+ const confirmButton = getByRole('button', { name: 'Ok' });
+
+ await userEvent.click(confirmButton);
+
+ expect(onResolve).toHaveBeenCalledWith('confirm');
+ await expect(dialogPromise).resolves.toEqual('confirm');
+ });
+
+ it('should resolve when secondary button is clicked', async () => {
+ const { getByRole } = renderWithRoot(
+ ,
+ );
+ const showDialogButton = getByRole('button', { name: 'Open Dialog' });
+
+ await userEvent.click(showDialogButton);
+
+ const secondaryButton = getByRole('button', { name: 'Later' });
+
+ await userEvent.click(secondaryButton);
+
+ expect(onResolve).toHaveBeenCalledWith('secondary');
+ await expect(dialogPromise).resolves.toEqual('secondary');
+ });
});
diff --git a/src/components/overlays/AlertDialog/types.ts b/src/components/overlays/AlertDialog/types.ts
index 4dbf08e43..0c5029959 100644
--- a/src/components/overlays/AlertDialog/types.ts
+++ b/src/components/overlays/AlertDialog/types.ts
@@ -22,7 +22,7 @@ export interface DialogProps
content: ReactNode | (({ resolve, reject }) => ReactNode);
}
-export type AlertDialogResolveStatus = 'confirm' | 'cancel' | 'secondary';
+export type AlertDialogResolveStatus = 'confirm' | 'secondary';
interface AlertDialogMeta {
id: number;