2025-11-26 15:13:55 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2025 Element Creations Ltd.
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
|
|
|
* Please see LICENSE files in the repository root for full details.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import classNames from "classnames";
|
|
|
|
|
import React, {
|
|
|
|
|
type MouseEventHandler,
|
|
|
|
|
type ReactElement,
|
|
|
|
|
type ReactNode,
|
|
|
|
|
type PropsWithChildren,
|
|
|
|
|
useMemo,
|
2026-01-12 21:13:15 +00:00
|
|
|
type HTMLAttributes,
|
2025-11-26 15:13:55 +00:00
|
|
|
} from "react";
|
|
|
|
|
import { Button } from "@vector-im/compound-web";
|
|
|
|
|
import CheckCircleIcon from "@vector-im/compound-design-tokens/assets/web/icons/check-circle";
|
|
|
|
|
import ErrorIcon from "@vector-im/compound-design-tokens/assets/web/icons/error-solid";
|
|
|
|
|
import InfoIcon from "@vector-im/compound-design-tokens/assets/web/icons/info";
|
|
|
|
|
|
|
|
|
|
import styles from "./Banner.module.css";
|
|
|
|
|
import { _t } from "../../utils/i18n";
|
|
|
|
|
|
|
|
|
|
interface BannerProps {
|
|
|
|
|
/**
|
|
|
|
|
* The type of the status banner.
|
|
|
|
|
*/
|
|
|
|
|
type?: "success" | "info" | "critical";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The banner avatar.
|
|
|
|
|
*/
|
|
|
|
|
avatar?: React.ReactNode;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Actions presented to the user in the right-hand side of the banner alongside the dismiss button.
|
|
|
|
|
*/
|
|
|
|
|
actions?: ReactNode;
|
|
|
|
|
/**
|
|
|
|
|
* Called when the user presses the "dismiss" button.
|
|
|
|
|
*/
|
2025-12-01 11:44:12 +00:00
|
|
|
onClose?: MouseEventHandler<HTMLButtonElement>;
|
2025-11-26 15:13:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A banner component used for displaying user-facing information above the message composer.
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* ```tsx
|
|
|
|
|
* <Banner onClose={onCloseHandler} />
|
|
|
|
|
* ```
|
|
|
|
|
*/
|
|
|
|
|
export function Banner({
|
|
|
|
|
type,
|
|
|
|
|
children,
|
|
|
|
|
avatar,
|
|
|
|
|
className,
|
|
|
|
|
actions,
|
|
|
|
|
onClose,
|
|
|
|
|
...props
|
2026-01-12 21:13:15 +00:00
|
|
|
}: PropsWithChildren<BannerProps & HTMLAttributes<HTMLDivElement>>): ReactElement {
|
2025-11-26 15:13:55 +00:00
|
|
|
const classes = classNames(styles.banner, className);
|
|
|
|
|
|
2026-01-12 21:13:15 +00:00
|
|
|
const icon = useMemo((): ReactElement => {
|
2025-11-26 15:13:55 +00:00
|
|
|
switch (type) {
|
|
|
|
|
case "critical":
|
2026-01-12 21:13:15 +00:00
|
|
|
return <ErrorIcon fontSize={24} />;
|
2025-11-26 15:13:55 +00:00
|
|
|
case "info":
|
2026-01-12 21:13:15 +00:00
|
|
|
return <InfoIcon fontSize={24} />;
|
2025-11-26 15:13:55 +00:00
|
|
|
case "success":
|
2026-01-12 21:13:15 +00:00
|
|
|
return <CheckCircleIcon fontSize={24} />;
|
2025-11-26 15:13:55 +00:00
|
|
|
default:
|
2026-01-12 21:13:15 +00:00
|
|
|
return <InfoIcon fontSize={24} />;
|
2025-11-26 15:13:55 +00:00
|
|
|
}
|
2026-01-12 21:13:15 +00:00
|
|
|
}, [type]);
|
2025-11-26 15:13:55 +00:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div {...props} className={classes} data-type={type}>
|
|
|
|
|
<div className={styles.icon}>{avatar ?? icon}</div>
|
2025-12-19 15:40:45 +00:00
|
|
|
<div className={styles.content}>{children}</div>
|
2025-11-26 15:13:55 +00:00
|
|
|
<div className={styles.actions}>
|
|
|
|
|
{actions}
|
2025-12-01 11:44:12 +00:00
|
|
|
{onClose && (
|
|
|
|
|
<Button kind="secondary" size="sm" onClick={onClose}>
|
|
|
|
|
{_t("action|dismiss")}
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
2025-11-26 15:13:55 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|