Implement a shared Banner component. (#31266)
* feat: Create composer `Banner` shared component. * fix: Yarn resolution issues corrupting package store. * chore: Revert "fix: Yarn resolution issues corrupting package store." This reverts commit 2c1335420331e9cf086cad5c68f7c7432af4b3a5. * fix: Revert lockfile changes. * chore: Resolve linting errors. * chore: Update playwright screenshots.
This commit is contained in:
@@ -46,6 +46,7 @@
|
||||
"test:storybook:update": "playwright-screenshots --entrypoint yarn --with-node-modules && playwright-screenshots --entrypoint /work/node_modules/.bin/test-storybook --with-node-modules --url http://host.docker.internal:6007/ --updateSnapshot"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vector-im/compound-design-tokens": "^6.3.0",
|
||||
"classnames": "^2.5.1",
|
||||
"counterpart": "^0.18.6",
|
||||
"lodash": "^4.17.21",
|
||||
@@ -88,7 +89,6 @@
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
|
||||
"peerDependencies": {
|
||||
"@vector-im/compound-design-tokens": "^6.0.0",
|
||||
"@vector-im/compound-web": "^8.2.5"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--cpd-color-gradient-critical-linear: linear-gradient(
|
||||
180deg,
|
||||
var(--cpd-color-alpha-red-500) 0%,
|
||||
var(--cpd-color-alpha-red-400) 20%,
|
||||
var(--cpd-color-alpha-red-300) 40%,
|
||||
var(--cpd-color-alpha-red-200) 60%,
|
||||
var(--cpd-color-alpha-red-100) 80%,
|
||||
var(--cpd-color-transparent) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.banner {
|
||||
container-type: inline-size;
|
||||
container-name: banner;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
gap: var(--cpd-space-3x);
|
||||
padding: var(--cpd-space-4x);
|
||||
|
||||
border-top: 1px solid var(--cpd-color-gray-400);
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.banner[data-type="success"] {
|
||||
background: var(--cpd-color-gradient-subtle-linear);
|
||||
border-color: var(--cpd-color-green-900);
|
||||
}
|
||||
|
||||
.banner[data-type="critical"] {
|
||||
background: var(--cpd-color-gradient-critical-linear);
|
||||
border-color: var(--cpd-color-border-critical-primary);
|
||||
}
|
||||
|
||||
.banner[data-type="info"] {
|
||||
background: var(--cpd-color-gradient-info-linear);
|
||||
border-color: var(--cpd-color-blue-900);
|
||||
}
|
||||
|
||||
.banner[data-type="info"] :is(svg) {
|
||||
color: var(--cpd-color-blue-900);
|
||||
}
|
||||
|
||||
.banner[data-type="success"] :is(.content, svg) {
|
||||
color: var(--cpd-color-green-900);
|
||||
}
|
||||
|
||||
.banner[data-type="critical"] :is(.content, svg) {
|
||||
color: var(--cpd-color-red-900);
|
||||
}
|
||||
|
||||
.banner p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
/* lock icon dimensions */
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
max-width: 32px;
|
||||
max-height: 32px;
|
||||
|
||||
margin: 4px;
|
||||
|
||||
/* centre svg icons, as they are not full width */
|
||||
flex: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.icon img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.actions {
|
||||
margin-left: auto;
|
||||
|
||||
flex: 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: var(--cpd-space-1x);
|
||||
align-self: center;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 React from "react";
|
||||
import { fn } from "storybook/test";
|
||||
import { type Meta, type StoryObj } from "@storybook/react-vite";
|
||||
import { Button } from "@vector-im/compound-web";
|
||||
|
||||
import { Banner } from "./Banner";
|
||||
import { _t } from "../../utils/i18n";
|
||||
|
||||
const meta = {
|
||||
title: "room/Banner",
|
||||
component: Banner,
|
||||
tags: ["autodocs"],
|
||||
args: {
|
||||
children: <p>Hello! This is a status banner.</p>,
|
||||
onClose: fn(),
|
||||
},
|
||||
} satisfies Meta<typeof Banner>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
export const Info: Story = {
|
||||
args: {
|
||||
type: "info",
|
||||
},
|
||||
};
|
||||
export const Success: Story = {
|
||||
args: {
|
||||
type: "success",
|
||||
},
|
||||
};
|
||||
export const Critical: Story = {
|
||||
args: {
|
||||
type: "critical",
|
||||
},
|
||||
};
|
||||
export const WithAction: Story = {
|
||||
args: {
|
||||
children: (
|
||||
<p>
|
||||
{_t(
|
||||
"encryption|pinned_identity_changed",
|
||||
{ displayName: "Alice", userId: "@alice:example.org" },
|
||||
{
|
||||
a: (sub) => <a href="https://example.org">{sub}</a>,
|
||||
b: (sub) => <b>{sub}</b>,
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
),
|
||||
actions: <Button kind="primary">{_t("encryption|withdraw_verification_action")}</Button>,
|
||||
},
|
||||
};
|
||||
|
||||
export const WithAvatarImage: Story = {
|
||||
args: {
|
||||
avatar: <img alt="Example" src="https://picsum.photos/32/32" />,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
import { composeStories } from "@storybook/react-vite";
|
||||
|
||||
import * as stories from "./Banner.stories.tsx";
|
||||
|
||||
const { Default, Info, Success, WithAction, WithAvatarImage, Critical } = composeStories(stories);
|
||||
|
||||
describe("AvatarWithDetails", () => {
|
||||
it("renders a default banner", () => {
|
||||
const { container } = render(<Default />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders a info banner", () => {
|
||||
const { container } = render(<Info />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders a success banner", () => {
|
||||
const { container } = render(<Success />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders a critical banner", () => {
|
||||
const { container } = render(<Critical />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders a banner with an action", () => {
|
||||
const { container } = render(<WithAction />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
it("renders a banner with an avatar iamge", () => {
|
||||
const { container } = render(<WithAvatarImage />);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
91
packages/shared-components/src/composer/Banner/Banner.tsx
Normal file
91
packages/shared-components/src/composer/Banner/Banner.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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,
|
||||
} 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;
|
||||
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
onClose: MouseEventHandler<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
}: PropsWithChildren<BannerProps>): ReactElement {
|
||||
const classes = classNames(styles.banner, className);
|
||||
|
||||
const icon = useMemo(() => {
|
||||
switch (type) {
|
||||
case "critical":
|
||||
return <ErrorIcon fontSize={24} {...props} />;
|
||||
case "info":
|
||||
return <InfoIcon fontSize={24} {...props} />;
|
||||
case "success":
|
||||
return <CheckCircleIcon fontSize={24} {...props} />;
|
||||
default:
|
||||
return <InfoIcon fontSize={24} {...props} />;
|
||||
}
|
||||
}, [type, props]);
|
||||
|
||||
return (
|
||||
<div {...props} className={classes} data-type={type}>
|
||||
<div className={styles.icon}>{avatar ?? icon}</div>
|
||||
<span className={styles.content}>{children}</span>
|
||||
<div className={styles.actions}>
|
||||
{actions}
|
||||
<Button kind="secondary" size="sm" onClick={onClose}>
|
||||
{_t("action|dismiss")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
|
||||
exports[`AvatarWithDetails renders a banner with an action 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="banner"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11.288 7.288A.97.97 0 0 1 12 7q.424 0 .713.287Q13 7.576 13 8t-.287.713A.97.97 0 0 1 12 9a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 8q0-.424.287-.713m.001 4.001A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713v4q0 .424-.287.712A.97.97 0 0 1 12 17a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 16v-4q0-.424.287-.713"
|
||||
/>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10m-2 0a8 8 0 1 1-16 0 8 8 0 0 1 16 0"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="content"
|
||||
>
|
||||
<p>
|
||||
encryption|pinned_identity_changed
|
||||
</p>
|
||||
</span>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
encryption|withdraw_verification_action
|
||||
</button>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AvatarWithDetails renders a banner with an avatar iamge 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="banner"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<img
|
||||
alt="Example"
|
||||
src="https://picsum.photos/32/32"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="content"
|
||||
>
|
||||
<p>
|
||||
Hello! This is a status banner.
|
||||
</p>
|
||||
</span>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AvatarWithDetails renders a critical banner 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="banner"
|
||||
data-type="critical"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M12 17q.424 0 .713-.288A.97.97 0 0 0 13 16a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 15a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 16q0 .424.287.712.288.288.713.288m0-4q.424 0 .713-.287A.97.97 0 0 0 13 12V8a.97.97 0 0 0-.287-.713A.97.97 0 0 0 12 7a.97.97 0 0 0-.713.287A.97.97 0 0 0 11 8v4q0 .424.287.713.288.287.713.287m0 9a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="content"
|
||||
>
|
||||
<p>
|
||||
Hello! This is a status banner.
|
||||
</p>
|
||||
</span>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AvatarWithDetails renders a default banner 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="banner"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11.288 7.288A.97.97 0 0 1 12 7q.424 0 .713.287Q13 7.576 13 8t-.287.713A.97.97 0 0 1 12 9a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 8q0-.424.287-.713m.001 4.001A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713v4q0 .424-.287.712A.97.97 0 0 1 12 17a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 16v-4q0-.424.287-.713"
|
||||
/>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10m-2 0a8 8 0 1 1-16 0 8 8 0 0 1 16 0"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="content"
|
||||
>
|
||||
<p>
|
||||
Hello! This is a status banner.
|
||||
</p>
|
||||
</span>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AvatarWithDetails renders a info banner 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="banner"
|
||||
data-type="info"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11.288 7.288A.97.97 0 0 1 12 7q.424 0 .713.287Q13 7.576 13 8t-.287.713A.97.97 0 0 1 12 9a.97.97 0 0 1-.713-.287A.97.97 0 0 1 11 8q0-.424.287-.713m.001 4.001A.97.97 0 0 1 12 11q.424 0 .713.287.287.288.287.713v4q0 .424-.287.712A.97.97 0 0 1 12 17a.97.97 0 0 1-.713-.288A.97.97 0 0 1 11 16v-4q0-.424.287-.713"
|
||||
/>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M22 12c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2s10 4.477 10 10m-2 0a8 8 0 1 1-16 0 8 8 0 0 1 16 0"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="content"
|
||||
>
|
||||
<p>
|
||||
Hello! This is a status banner.
|
||||
</p>
|
||||
</span>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AvatarWithDetails renders a success banner 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="banner"
|
||||
data-type="success"
|
||||
>
|
||||
<div
|
||||
class="icon"
|
||||
>
|
||||
<svg
|
||||
fill="currentColor"
|
||||
font-size="24"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="m10.6 13.8-2.15-2.15a.95.95 0 0 0-.7-.275.95.95 0 0 0-.7.275.95.95 0 0 0-.275.7q0 .425.275.7L9.9 15.9q.3.3.7.3t.7-.3l5.65-5.65a.95.95 0 0 0 .275-.7.95.95 0 0 0-.275-.7.95.95 0 0 0-.7-.275.95.95 0 0 0-.7.275zM12 22a9.7 9.7 0 0 1-3.9-.788 10.1 10.1 0 0 1-3.175-2.137q-1.35-1.35-2.137-3.175A9.7 9.7 0 0 1 2 12q0-2.075.788-3.9a10.1 10.1 0 0 1 2.137-3.175q1.35-1.35 3.175-2.137A9.7 9.7 0 0 1 12 2q2.075 0 3.9.788a10.1 10.1 0 0 1 3.175 2.137q1.35 1.35 2.137 3.175A9.7 9.7 0 0 1 22 12a9.7 9.7 0 0 1-.788 3.9 10.1 10.1 0 0 1-2.137 3.175q-1.35 1.35-3.175 2.137A9.7 9.7 0 0 1 12 22m0-2q3.35 0 5.675-2.325T20 12t-2.325-5.675T12 4 6.325 6.325 4 12t2.325 5.675T12 20"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="content"
|
||||
>
|
||||
<p>
|
||||
Hello! This is a status banner.
|
||||
</p>
|
||||
</span>
|
||||
<div
|
||||
class="actions"
|
||||
>
|
||||
<button
|
||||
class="_button_vczzf_8"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Dismiss
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
8
packages/shared-components/src/composer/Banner/index.ts
Normal file
8
packages/shared-components/src/composer/Banner/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export * from "./Banner";
|
||||
@@ -11,6 +11,7 @@ export * from "./audio/Clock";
|
||||
export * from "./audio/PlayPauseButton";
|
||||
export * from "./audio/SeekBar";
|
||||
export * from "./avatar/AvatarWithDetails";
|
||||
export * from "./composer/Banner";
|
||||
export * from "./event-tiles/TextualEventView";
|
||||
export * from "./message-body/MediaBody";
|
||||
export * from "./pill-input/Pill";
|
||||
|
||||
@@ -1959,6 +1959,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777"
|
||||
integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==
|
||||
|
||||
"@vector-im/compound-design-tokens@^6.3.0":
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-6.4.0.tgz#2e51f39f79ebda985a2f6cf80d567b9307aff03a"
|
||||
integrity sha512-93nYQZMgUt6apjCwwnMhMxN8VYQXN3GYOnwovwJjavImwsCGwI/e853BV/DstrWumYh6k5pZsP9e6AF+nz3SIQ==
|
||||
|
||||
"@vitest/expect@3.2.4":
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.4.tgz#8362124cd811a5ee11c5768207b9df53d34f2433"
|
||||
|
||||
Reference in New Issue
Block a user