Improve package versioning and cleanup
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
committed by
Patrik Oldsberg
parent
54dd710eb1
commit
a47f27c0a9
@@ -1941,6 +1941,7 @@ export type ToastApi = {
|
||||
post(toast: ToastMessage): string;
|
||||
close(key: string): void;
|
||||
toast$(): Observable<ToastMessageWithKey>;
|
||||
close$(): Observable<string>;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -111,6 +111,12 @@ export type ToastApi = {
|
||||
* Observe toasts posted by other parts of the application.
|
||||
*/
|
||||
toast$(): Observable<ToastMessageWithKey>;
|
||||
|
||||
/**
|
||||
* Observe close events for programmatic toast dismissal.
|
||||
* Emits the key of the toast that should be closed.
|
||||
*/
|
||||
close$(): Observable<string>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,13 +65,12 @@
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.61",
|
||||
"@react-aria/button": "^3.13.3",
|
||||
"@react-aria/toast": "^3.0.9",
|
||||
"@react-hookz/web": "^24.0.0",
|
||||
"@react-stately/toast": "^3.1.2",
|
||||
"@remixicon/react": "^4.6.0",
|
||||
"motion": "^12.0.0",
|
||||
"react-aria": "^3.41.1",
|
||||
"react-aria-components": "^1.14.0",
|
||||
"react-stately": "^3.35.0",
|
||||
"react-use": "^17.2.4",
|
||||
"zen-observable": "^0.10.0",
|
||||
"zod": "^3.25.76"
|
||||
|
||||
@@ -88,6 +88,7 @@ export class ToastApiForwarder implements ToastApi {
|
||||
private readonly subject = new PublishSubject<ToastMessageWithKey>();
|
||||
private readonly closeSubject = new PublishSubject<string>();
|
||||
private readonly recentToasts: ToastMessageWithKey[] = [];
|
||||
private readonly closedKeys = new Set<string>();
|
||||
private readonly maxBufferSize = 10;
|
||||
|
||||
post(toast: ToastMessage): string {
|
||||
@@ -104,16 +105,28 @@ export class ToastApiForwarder implements ToastApi {
|
||||
}
|
||||
|
||||
close(key: string): void {
|
||||
// Track closed keys to prevent replaying dismissed toasts
|
||||
this.closedKeys.add(key);
|
||||
|
||||
// Remove from recent buffer if still there
|
||||
const index = this.recentToasts.findIndex(t => t.key === key);
|
||||
if (index !== -1) {
|
||||
this.recentToasts.splice(index, 1);
|
||||
}
|
||||
this.closeSubject.next(key);
|
||||
|
||||
// Clean up old closed keys when buffer is cleared
|
||||
if (this.recentToasts.length === 0) {
|
||||
this.closedKeys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
toast$(): Observable<ToastMessageWithKey> {
|
||||
return this.subject.asObservable(this.recentToasts);
|
||||
// Filter out any toasts that were closed to handle race conditions
|
||||
const activeToasts = this.recentToasts.filter(
|
||||
t => !this.closedKeys.has(t.key),
|
||||
);
|
||||
return this.subject.asObservable(activeToasts);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import { useToast } from '@react-aria/toast';
|
||||
import { Button } from 'react-aria-components';
|
||||
import { useButton } from '@react-aria/button';
|
||||
import { motion } from 'motion/react';
|
||||
import {
|
||||
RiInformationLine,
|
||||
@@ -76,6 +76,9 @@ export const Toast = forwardRef(
|
||||
toastRef,
|
||||
);
|
||||
|
||||
// Close button ref for useButton hook
|
||||
const closeButtonRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
// Extract only ARIA and accessibility props from toastProps to avoid
|
||||
// conflicts with motion.div's event handler types (motion has its own drag API)
|
||||
const ariaProps = {
|
||||
@@ -119,6 +122,15 @@ export const Toast = forwardRef(
|
||||
state.close(toast.key);
|
||||
};
|
||||
|
||||
// Get button props from useButton hook
|
||||
const { buttonProps } = useButton(
|
||||
{
|
||||
'aria-label': closeButtonProps['aria-label'],
|
||||
onPress: handleClose,
|
||||
},
|
||||
closeButtonRef,
|
||||
);
|
||||
|
||||
// Get content from toast
|
||||
const content = toast.content;
|
||||
const finalStatus = status || content.status || 'info';
|
||||
@@ -246,8 +258,8 @@ export const Toast = forwardRef(
|
||||
)}
|
||||
{content.links && content.links.length > 0 && (
|
||||
<div className="toast-links">
|
||||
{content.links.map((link, idx) => (
|
||||
<a key={idx} href={link.href}>
|
||||
{content.links.map(link => (
|
||||
<a key={link.href} href={link.href}>
|
||||
{link.label}
|
||||
</a>
|
||||
))}
|
||||
@@ -255,14 +267,14 @@ export const Toast = forwardRef(
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
slot="close"
|
||||
{/* eslint-disable-next-line react/forbid-elements */}
|
||||
<button
|
||||
{...buttonProps}
|
||||
ref={closeButtonRef}
|
||||
className="toast-close-button"
|
||||
aria-label={closeButtonProps['aria-label']}
|
||||
onPress={handleClose}
|
||||
>
|
||||
<RiCloseLine aria-hidden="true" />
|
||||
</Button>
|
||||
</button>
|
||||
</motion.div>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import { forwardRef, Ref, useState, useRef, useCallback, useMemo } from 'react';
|
||||
import { useToastRegion } from '@react-aria/toast';
|
||||
import { useToastQueue } from 'react-stately';
|
||||
import { useToastQueue } from '@react-stately/toast';
|
||||
import { AnimatePresence } from 'motion/react';
|
||||
import type { ToastContainerProps } from './types';
|
||||
import { useInvertedThemeMode } from '../../hooks/useInvertedThemeMode';
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { alertApiRef, useApi } from '@backstage/core-plugin-api';
|
||||
import { toastApiRef } from '@backstage/frontend-plugin-api';
|
||||
import { ToastApiForwarder } from '../../apis';
|
||||
import { ToastContainer } from './ToastContainer';
|
||||
import { toastQueue } from './ToastQueue';
|
||||
import type { ToastDisplayProps, ToastContent } from './types';
|
||||
@@ -103,15 +102,9 @@ export function ToastDisplay(props: ToastDisplayProps) {
|
||||
return () => subscription.unsubscribe();
|
||||
}, [toastApi]);
|
||||
|
||||
// Subscribe to ToastApi close events
|
||||
// Subscribe to ToastApi close events for programmatic dismissal
|
||||
useEffect(() => {
|
||||
// The ToastApiForwarder exposes a close$() method for programmatic close
|
||||
const forwarder = toastApi as ToastApiForwarder;
|
||||
if (!forwarder.close$) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const subscription = forwarder.close$().subscribe(apiKey => {
|
||||
const subscription = toastApi.close$().subscribe(apiKey => {
|
||||
const queueKey = toastKeyMap.current.get(apiKey);
|
||||
if (queueKey) {
|
||||
toastQueue.close(queueKey);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ToastQueue } from 'react-stately';
|
||||
import { ToastQueue } from '@react-stately/toast';
|
||||
import type { ToastContent } from './types';
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,10 +55,13 @@ export function useInvertedThemeMode(): ThemeMode {
|
||||
attributeFilter: ['data-theme-mode'],
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme-mode'],
|
||||
});
|
||||
// Body might not exist in some edge cases (e.g., during SSR or early lifecycle)
|
||||
if (document.body) {
|
||||
observer.observe(document.body, {
|
||||
attributes: true,
|
||||
attributeFilter: ['data-theme-mode'],
|
||||
});
|
||||
}
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
@@ -4301,8 +4301,10 @@ __metadata:
|
||||
"@material-ui/core": "npm:^4.9.13"
|
||||
"@material-ui/icons": "npm:^4.9.1"
|
||||
"@material-ui/lab": "npm:^4.0.0-alpha.61"
|
||||
"@react-aria/button": "npm:^3.13.3"
|
||||
"@react-aria/toast": "npm:^3.0.9"
|
||||
"@react-hookz/web": "npm:^24.0.0"
|
||||
"@react-stately/toast": "npm:^3.1.2"
|
||||
"@remixicon/react": "npm:^4.6.0"
|
||||
"@testing-library/jest-dom": "npm:^6.0.0"
|
||||
"@testing-library/react": "npm:^16.0.0"
|
||||
@@ -4311,11 +4313,8 @@ __metadata:
|
||||
motion: "npm:^12.0.0"
|
||||
msw: "npm:^1.0.0"
|
||||
react: "npm:^18.0.2"
|
||||
react-aria: "npm:^3.41.1"
|
||||
react-aria-components: "npm:^1.14.0"
|
||||
react-dom: "npm:^18.0.2"
|
||||
react-router-dom: "npm:^6.30.2"
|
||||
react-stately: "npm:^3.35.0"
|
||||
react-use: "npm:^17.2.4"
|
||||
zen-observable: "npm:^0.10.0"
|
||||
zod: "npm:^3.25.76"
|
||||
@@ -8121,7 +8120,6 @@ __metadata:
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/version-bridge": "workspace:^"
|
||||
"@react-aria/toast": "npm:^3.0.9"
|
||||
"@remixicon/react": "npm:^4.6.0"
|
||||
"@tanstack/react-table": "npm:^8.21.3"
|
||||
"@types/react": "npm:^18.0.0"
|
||||
@@ -8130,12 +8128,10 @@ __metadata:
|
||||
eslint-plugin-storybook: "npm:^10.3.0-alpha.1"
|
||||
glob: "npm:^11.0.1"
|
||||
globals: "npm:^15.11.0"
|
||||
motion: "npm:^12.0.0"
|
||||
react: "npm:^18.0.2"
|
||||
react-aria-components: "npm:^1.14.0"
|
||||
react-dom: "npm:^18.0.2"
|
||||
react-router-dom: "npm:^6.30.2"
|
||||
react-stately: "npm:^3.35.0"
|
||||
storybook: "npm:^10.3.0-alpha.1"
|
||||
peerDependencies:
|
||||
"@types/react": ^17.0.0 || ^18.0.0
|
||||
@@ -15568,7 +15564,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@react-aria/button@npm:^3.14.4":
|
||||
"@react-aria/button@npm:^3.13.3, @react-aria/button@npm:^3.14.4":
|
||||
version: 3.14.4
|
||||
resolution: "@react-aria/button@npm:3.14.4"
|
||||
dependencies:
|
||||
@@ -44135,7 +44131,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-aria@npm:^3.41.1, react-aria@npm:^3.45.0":
|
||||
"react-aria@npm:^3.45.0":
|
||||
version: 3.46.0
|
||||
resolution: "react-aria@npm:3.46.0"
|
||||
dependencies:
|
||||
@@ -44795,7 +44791,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-stately@npm:^3.35.0, react-stately@npm:^3.43.0":
|
||||
"react-stately@npm:^3.43.0":
|
||||
version: 3.43.0
|
||||
resolution: "react-stately@npm:3.43.0"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user