Remove BUI docs

Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
Charles de Dreuille
2026-02-05 13:49:59 +00:00
committed by Patrik Oldsberg
parent b4f5d20232
commit 7e743f4ad9
7 changed files with 39 additions and 792 deletions
+38
View File
@@ -0,0 +1,38 @@
---
'@backstage/frontend-plugin-api': minor
'@backstage/plugin-app': minor
---
Introduced a new `ToastApi` for displaying rich toast notifications in the new frontend system.
The new `ToastApi` provides enhanced notification capabilities compared to the existing `AlertApi`:
- **Title and Description**: Toasts support both a title and an optional description
- **Custom Timeouts**: Each toast can specify its own timeout duration
- **Links**: Toasts can include action links
- **Icons**: Support for custom icons or disabling the default icon
- **Programmatic Dismiss**: Toasts can be dismissed programmatically using the key returned from `post()`
**Usage:**
```typescript
import { toastApiRef, useApi } from '@backstage/frontend-plugin-api';
const toastApi = useApi(toastApiRef);
// Full-featured toast
toastApi.post({
title: 'Entity saved',
description: 'Your changes have been saved successfully.',
status: 'success',
timeout: 5000,
links: [{ label: 'View entity', href: '/catalog/entity' }],
});
// Programmatic dismiss
const key = toastApi.post({ title: 'Uploading...', status: 'info' });
// Later...
toastApi.close(key);
```
The `ToastDisplay` component subscribes to both `ToastApi` and `AlertApi`, providing a migration path where both systems work side by side until `AlertApi` is fully deprecated.
+1
View File
@@ -18,6 +18,7 @@ const allStories = isChromatic
'packages/ui',
'packages/core-components',
'packages/app',
'plugins/app',
'plugins/org',
'plugins/search',
'plugins/search-react',
@@ -1,320 +0,0 @@
'use client';
import { useState } from 'react';
import { ToastContainer, toastQueue, Button, Flex } from '@backstage/ui';
import type { ToastContent } from '@backstage/ui';
import { MemoryRouter } from 'react-router-dom';
/**
* Single shared ToastContainer for all examples on this page.
* This prevents duplicate toasts when multiple examples share the same queue.
* Wrapped in MemoryRouter to support Link components inside toasts.
*/
export function SharedToastContainer() {
return (
<MemoryRouter>
<ToastContainer queue={toastQueue} />
</MemoryRouter>
);
}
const randomToasts: ToastContent[] = [
// Info toasts
{ title: 'New notification', status: 'info' },
{
title: 'Update available',
description: 'A new version is ready to install.',
status: 'info',
},
{
title: 'Tip',
description: 'You can use keyboard shortcuts to navigate faster.',
status: 'info',
links: [{ label: 'View shortcuts', href: '/shortcuts' }],
},
// Success toasts
{ title: 'Saved', status: 'success' },
{
title: 'Files uploaded',
description: '3 files uploaded successfully.',
status: 'success',
},
{
title: 'Deployment complete',
description: 'Your application has been deployed to production.',
status: 'success',
links: [
{ label: 'View logs', href: '/logs' },
{ label: 'Open app', href: '/app' },
],
},
// Warning toasts
{ title: 'Storage almost full', status: 'warning' },
{
title: 'Session expiring',
description: 'Your session will expire in 5 minutes.',
status: 'warning',
},
{
title: 'Rate limit warning',
description: 'You are approaching your API rate limit.',
status: 'warning',
links: [{ label: 'Upgrade plan', href: '/billing' }],
},
// Danger toasts
{ title: 'Connection lost', status: 'danger' },
{
title: 'Error',
description: 'Something went wrong. Please try again.',
status: 'danger',
},
{
title: 'Build failed',
description: 'The build process encountered an error.',
status: 'danger',
links: [{ label: 'View error details', href: '/errors' }],
},
];
export function Default() {
return (
<Flex gap="3">
<Button
onPress={() => {
const toast =
randomToasts[Math.floor(Math.random() * randomToasts.length)];
toastQueue.add(toast);
}}
>
Show Random Toast
</Button>
<Button onPress={() => toastQueue.clear()}>Clear</Button>
</Flex>
);
}
export function StatusVariants() {
return (
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add({
title: 'Informational message',
description: 'Here is some helpful information.',
status: 'info',
})
}
>
Info Toast
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Success!',
description: 'Your changes have been saved.',
status: 'success',
})
}
>
Success Toast
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Warning',
description: 'This action may have consequences.',
status: 'warning',
})
}
>
Warning Toast
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Error',
description: 'Something went wrong.',
status: 'danger',
})
}
>
Danger Toast
</Button>
</Flex>
);
}
export function WithoutDescription() {
return (
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add({
title: 'File saved',
description: 'Your changes have been saved successfully.',
status: 'success',
})
}
>
Success
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Check for updates',
description: 'A new version is available.',
status: 'info',
})
}
>
Info
</Button>
</Flex>
);
}
export function WithLinks() {
return (
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add({
title: 'Deployment complete',
description: 'Your application has been deployed.',
status: 'success',
links: [
{ label: 'View logs', href: '/logs' },
{ label: 'Open dashboard', href: '/dashboard' },
],
})
}
>
Multiple Links
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'New update available',
status: 'info',
links: [{ label: 'View release notes', href: '/releases' }],
})
}
>
Single Link
</Button>
</Flex>
);
}
export function AutoDismiss() {
return (
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add(
{
title: 'Auto dismiss in 3 seconds',
description: 'This toast will disappear automatically.',
status: 'info',
},
{ timeout: 3000 },
)
}
>
3 Second Toast
</Button>
<Button
onPress={() =>
toastQueue.add(
{
title: 'Auto dismiss in 5 seconds',
description: 'Recommended minimum timeout for accessibility.',
status: 'success',
},
{ timeout: 5000 },
)
}
>
5 Second Toast
</Button>
</Flex>
);
}
export function ProgrammaticControl() {
const [toastKey, setToastKey] = useState<string | null>(null);
return (
<Button
onPress={() => {
if (!toastKey) {
const key = toastQueue.add(
{
title: 'Processing...',
description: 'Click the button again to dismiss.',
status: 'info',
},
{
onClose: () => setToastKey(null),
},
);
setToastKey(key);
} else {
toastQueue.close(toastKey);
}
}}
>
{toastKey ? 'Dismiss Toast' : 'Show Toast'}
</Button>
);
}
export function QueueManagement() {
return (
<Flex gap="3">
<Button
onPress={() => {
toastQueue.add({
title: 'First toast',
description: 'This is the first toast in the queue.',
status: 'info',
});
setTimeout(() => {
toastQueue.add({
title: 'Second toast',
description: 'This is the second toast.',
status: 'success',
});
}, 300);
setTimeout(() => {
toastQueue.add({
title: 'Third toast',
description: 'This is the third toast.',
status: 'warning',
});
}, 600);
}}
>
Show Multiple Toasts
</Button>
<Button
onPress={() => {
for (let i = 1; i <= 5; i++) {
setTimeout(() => {
toastQueue.add({
title: `Toast #${i}`,
description: `This is toast number ${i}.`,
status: ['info', 'success', 'warning', 'danger'][
(i - 1) % 4
] as unknown as ToastContent['status'],
});
}, i * 200);
}
}}
>
Show 5 Toasts
</Button>
<Button onPress={() => toastQueue.clear()}>Clear All Toasts</Button>
</Flex>
);
}
-136
View File
@@ -1,136 +0,0 @@
import { PropsTable } from '@/components/PropsTable';
import { Snippet } from '@/components/Snippet';
import { CodeBlock } from '@/components/CodeBlock';
import {
toastContentPropDefs,
toastContainerPropDefs,
} from './props-definition';
import {
toastUsageSnippet,
defaultSnippet,
statusVariantsSnippet,
withoutDescriptionSnippet,
withLinksSnippet,
autoDismissSnippet,
programmaticControlSnippet,
queueManagementSnippet,
} from './snippets';
import {
SharedToastContainer,
Default,
StatusVariants,
WithoutDescription,
WithLinks,
AutoDismiss,
ProgrammaticControl,
QueueManagement,
} from './components';
import { ChangelogComponent } from '@/components/ChangelogComponent';
import { PageTitle } from '@/components/PageTitle';
import { Theming } from '@/components/Theming';
import { ToastDefinition } from '../../../utils/definitions';
<PageTitle
title="Toast"
description="A Toast displays a brief, temporary notification of actions, errors, or other events."
/>
<SharedToastContainer />
<Snippet align="center" py={4} preview={<Default />} code={defaultSnippet} />
## Usage
The Toast component uses a global queue system. Place the `ToastContainer` once in your app root, then trigger toasts from anywhere using the `queue` API.
<CodeBlock code={toastUsageSnippet} />
## API reference
### ToastContent
The content object passed to `queue.add()`:
<PropsTable data={toastContentPropDefs} />
### ToastContainer
<PropsTable data={toastContainerPropDefs} />
## Examples
### Status Variants
The Toast component supports four status variants, each with its own color theme and icon.
<Snippet
align="center"
py={4}
open
preview={<StatusVariants />}
code={statusVariantsSnippet}
/>
### Without Description
Toasts can display a title only for simpler notifications.
<Snippet
align="center"
py={4}
open
preview={<WithoutDescription />}
code={withoutDescriptionSnippet}
/>
### With Links
Toasts can include links to provide quick actions or navigation.
<Snippet
align="center"
py={4}
open
preview={<WithLinks />}
code={withLinksSnippet}
/>
### Auto Dismiss
Toasts can automatically dismiss after a timeout. For accessibility, a minimum of 5 seconds is recommended. Timers automatically pause when users hover or focus on a toast.
<Snippet
align="center"
py={4}
open
preview={<AutoDismiss />}
code={autoDismissSnippet}
/>
### Programmatic Control
You can programmatically dismiss toasts using the key returned from `queue.add()`.
<Snippet
align="center"
py={4}
open
preview={<ProgrammaticControl />}
code={programmaticControlSnippet}
/>
### Queue Management
The toast queue supports multiple toasts with deep stacking. When multiple toasts are visible, they stack with the most recent toast fully visible and others slightly visible behind it with reduced opacity and scale. You can show multiple toasts at once or clear all toasts programmatically.
<Snippet
align="center"
py={4}
open
preview={<QueueManagement />}
code={queueManagementSnippet}
/>
<Theming definition={ToastDefinition} />
<ChangelogComponent component="toast" />
@@ -1,44 +0,0 @@
import {
classNamePropDefs,
stylePropDefs,
type PropDef,
} from '@/utils/propDefs';
export const toastContentPropDefs: Record<string, PropDef> = {
title: {
type: 'enum',
values: ['React.ReactNode'],
responsive: false,
},
description: {
type: 'enum',
values: ['React.ReactNode'],
responsive: false,
},
status: {
type: 'enum',
values: ['info', 'success', 'warning', 'danger'],
responsive: false,
default: 'info',
},
icon: {
type: 'enum',
values: ['boolean', 'React.ReactElement'],
responsive: false,
default: 'true',
},
links: {
type: 'enum',
values: ['ToastLink[]'],
responsive: false,
},
};
export const toastContainerPropDefs: Record<string, PropDef> = {
queue: {
type: 'enum',
values: ['ToastQueue<ToastContent>'],
responsive: false,
},
...classNamePropDefs,
};
@@ -1,287 +0,0 @@
export const toastUsageSnippet = `import { ToastContainer, toastQueue } from '@backstage/ui';
// Place ToastContainer once in your app root
function App() {
return (
<>
<ToastContainer queue={toastQueue} />
<YourAppContent />
</>
);
}
// Trigger toasts from anywhere
toastQueue.add({ title: 'Success!', status: 'success' });`;
export const defaultSnippet = `import { ToastContainer, toastQueue, Button } from '@backstage/ui';
export function Example() {
return (
<>
<ToastContainer queue={toastQueue} />
<Button
onPress={() =>
toastQueue.add({
title: 'Files uploaded',
description: '3 files uploaded successfully.',
})
}
>
Show Toast
</Button>
</>
);
}`;
export const statusVariantsSnippet = `import { ToastContainer, toastQueue, Button, Flex } from '@backstage/ui';
export function Example() {
return (
<>
<ToastContainer queue={toastQueue} />
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add({
title: 'Informational message',
description: 'Here is some helpful information.',
status: 'info',
})
}
>
Info Toast
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Success!',
description: 'Your changes have been saved.',
status: 'success',
})
}
>
Success Toast
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Warning',
description: 'This action may have consequences.',
status: 'warning',
})
}
>
Warning Toast
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Error',
description: 'Something went wrong.',
status: 'danger',
})
}
>
Danger Toast
</Button>
</Flex>
</>
);
}`;
export const withoutDescriptionSnippet = `import { ToastContainer, toastQueue, Button, Flex } from '@backstage/ui';
export function Example() {
return (
<>
<ToastContainer queue={toastQueue} />
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add({
title: 'File saved',
status: 'success',
})
}
>
Success
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'Check for updates',
status: 'info',
})
}
>
Info
</Button>
</Flex>
</>
);
}`;
export const withLinksSnippet = `import { ToastContainer, toastQueue, Button, Flex } from '@backstage/ui';
export function Example() {
return (
<>
<ToastContainer queue={toastQueue} />
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add({
title: 'Deployment complete',
description: 'Your application has been deployed.',
status: 'success',
links: [
{ label: 'View logs', href: '/logs' },
{ label: 'Open dashboard', href: '/dashboard' },
],
})
}
>
Multiple Links
</Button>
<Button
onPress={() =>
toastQueue.add({
title: 'New update available',
status: 'info',
links: [{ label: 'View release notes', href: '/releases' }],
})
}
>
Single Link
</Button>
</Flex>
</>
);
}`;
export const autoDismissSnippet = `import { ToastContainer, toastQueue, Button, Flex } from '@backstage/ui';
export function Example() {
return (
<>
<ToastContainer queue={toastQueue} />
<Flex gap="3">
<Button
onPress={() =>
toastQueue.add(
{
title: 'Auto dismiss in 3 seconds',
description: 'This toast will disappear automatically.',
status: 'info',
},
{ timeout: 3000 }
)
}
>
3 Second Toast
</Button>
<Button
onPress={() =>
toastQueue.add(
{
title: 'Auto dismiss in 5 seconds',
description: 'Recommended minimum timeout for accessibility.',
status: 'success',
},
{ timeout: 5000 }
)
}
>
5 Second Toast
</Button>
</Flex>
</>
);
}`;
export const programmaticControlSnippet = `import { useState } from 'react';
import { ToastContainer, toastQueue, Button } from '@backstage/ui';
export function Example() {
const [toastKey, setToastKey] = useState<string | null>(null);
return (
<>
<ToastContainer queue={toastQueue} />
<Button
onPress={() => {
if (!toastKey) {
const key = toastQueue.add(
{
title: 'Processing...',
description: 'Click the button again to dismiss.',
status: 'info',
},
{
onClose: () => setToastKey(null),
}
);
setToastKey(key);
} else {
toastQueue.close(toastKey);
}
}}
>
{toastKey ? 'Dismiss Toast' : 'Show Toast'}
</Button>
</>
);
}`;
export const queueManagementSnippet = `import { ToastContainer, toastQueue, Button, Flex } from '@backstage/ui';
export function Example() {
return (
<>
<ToastContainer queue={toastQueue} />
<Flex gap="3">
<Button
onPress={() => {
toastQueue.add({
title: 'First toast',
description: 'This is the first toast in the queue.',
status: 'info',
});
setTimeout(() => {
toastQueue.add({
title: 'Second toast',
description: 'This is the second toast.',
status: 'success',
});
}, 300);
setTimeout(() => {
toastQueue.add({
title: 'Third toast',
description: 'This is the third toast.',
status: 'warning',
});
}, 600);
}}
>
Show Multiple Toasts
</Button>
<Button
onPress={() => {
for (let i = 1; i <= 5; i++) {
setTimeout(() => {
toastQueue.add({
title: \`Toast #\${i}\`,
description: \`This is toast number \${i}.\`,
status: ['info', 'success', 'warning', 'danger'][(i - 1) % 4],
});
}, i * 200);
}
}}
>
Show 5 Toasts
</Button>
<Button onPress={() => toastQueue.clear()}>Clear All Toasts</Button>
</Flex>
</>
);
}`;
-5
View File
@@ -121,11 +121,6 @@ export const components: Page[] = [
title: 'TextField',
slug: 'text-field',
},
{
title: 'Toast',
slug: 'toast',
status: 'new',
},
{
title: 'ToggleButton',
slug: 'toggle-button',