/* * Copyright 2025 Palantir Technologies, Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import classNames from "classnames"; import { useCallback } from "react"; import { Classes, DISPLAYNAME_PREFIX, type Intent, type MaybeElement, type Props } from "../../common"; import { ALERT_WARN_CANCEL_ESCAPE_KEY, ALERT_WARN_CANCEL_OUTSIDE_CLICK, ALERT_WARN_CANCEL_PROPS, } from "../../common/errors"; import { useValidateProps } from "../../hooks/useValidateProps"; import { Button } from "../button/buttons"; import { Dialog } from "../dialog/dialog"; import { Icon, type IconName } from "../icon/icon"; import type { OverlayLifecycleProps } from "../overlay/overlayProps"; export interface AlertProps extends OverlayLifecycleProps, Props { /** * Whether pressing escape when focused on the Alert should cancel the alert. * If this prop is enabled, then either `onCancel` or `onClose` must also be defined. * * @default false */ canEscapeKeyCancel?: boolean; /** * Whether clicking outside the Alert should cancel the alert. * If this prop is enabled, then either `onCancel` or `onClose` must also be defined. * * @default false */ canOutsideClickCancel?: boolean; /** * The text for the cancel button. * If this prop is defined, then either `onCancel` or `onClose` must also be defined. */ cancelButtonText?: string; /** Dialog contents. */ children?: React.ReactNode; /** * The text for the confirm (right-most) button. * This button will always appear, and uses the value of the `intent` prop below. * * @default "OK" */ confirmButtonText?: string; /** Name of a Blueprint UI icon (or an icon element) to display on the left side. */ icon?: IconName | MaybeElement; /** * The intent to be applied to the confirm (right-most) button and the icon (if provided). */ intent?: Intent; /** * Toggles the visibility of the alert. * This prop is required because the component is controlled. */ isOpen: boolean; /** * If set to `true`, the confirm button will be set to its loading state. The cancel button, if * visible, will be disabled. * * @default false */ loading?: boolean; /** * CSS styles to apply to the alert. */ style?: React.CSSProperties; /** * Indicates how long (in milliseconds) the overlay's enter/leave transition takes. * This is used by React `CSSTransition` to know when a transition completes and must match * the duration of the animation in CSS. Only set this prop if you override Blueprint's default * transitions with new transitions of a different length. * * @default 300 */ transitionDuration?: number; /** * The container element into which the overlay renders its contents, when `usePortal` is `true`. * This prop is ignored if `usePortal` is `false`. * * @default document.body */ portalContainer?: HTMLElement; /** * Handler invoked when the alert is canceled. Alerts can be **canceled** in the following ways: * - clicking the cancel button (if `cancelButtonText` is defined) * - pressing the escape key (if `canEscapeKeyCancel` is enabled) * - clicking on the overlay backdrop (if `canOutsideClickCancel` is enabled) * * If any of the `cancel` props are defined, then either `onCancel` or `onClose` must be defined. */ onCancel?: (event?: React.SyntheticEvent) => void; /** * Handler invoked when the confirm button is clicked. Alerts can be **confirmed** in the following ways: * - clicking the confirm button * - focusing on the confirm button and pressing `enter` or `space` */ onConfirm?: (event?: React.SyntheticEvent) => void; /** * Handler invoked when the Alert is confirmed or canceled; see `onConfirm` and `onCancel` for more details. * First argument is `true` if confirmed, `false` otherwise. * This is an alternative to defining separate `onConfirm` and `onCancel` handlers. */ onClose?: (confirmed: boolean, event?: React.SyntheticEvent) => void; } /** * Alert component. * * @see https://blueprintjs.com/docs/#core/components/alert */ export const Alert: React.FC = props => { const { cancelButtonText, canEscapeKeyCancel = false, canOutsideClickCancel = false, children, className, confirmButtonText = "OK", icon, intent, isOpen = false, loading = false, onCancel, onClose, onConfirm, ...overlayProps } = props; useValidateProps(() => { if (onClose == null && (cancelButtonText == null) !== (onCancel == null)) { console.warn(ALERT_WARN_CANCEL_PROPS); } const hasCancelHandler = onCancel != null || onClose != null; if (canEscapeKeyCancel && !hasCancelHandler) { console.warn(ALERT_WARN_CANCEL_ESCAPE_KEY); } if (canOutsideClickCancel && !hasCancelHandler) { console.warn(ALERT_WARN_CANCEL_OUTSIDE_CLICK); } }, [canEscapeKeyCancel, canOutsideClickCancel, cancelButtonText, onCancel, onClose]); const internalHandleCallbacks = useCallback( (confirmed: boolean, event?: React.SyntheticEvent) => { (confirmed ? onConfirm : onCancel)?.(event); onClose?.(confirmed, event); }, [onCancel, onClose, onConfirm], ); const handleCancel = useCallback( (event?: React.SyntheticEvent) => internalHandleCallbacks(false, event), [internalHandleCallbacks], ); const handleConfirm = useCallback( (event: React.SyntheticEvent) => internalHandleCallbacks(true, event), [internalHandleCallbacks], ); return (
{children}
); }; Alert.displayName = `${DISPLAYNAME_PREFIX}.Alert`;