v3.5.3版本更新1
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-08-20 18:54:15 +08:00
parent ee493823bf
commit fc2e5b65de
65 changed files with 2297 additions and 875 deletions
@@ -0,0 +1,53 @@
import { createContext, useCallback, useContext, useEffect, useRef, useState, type ReactNode } from 'react';
import { registerShopToastListener, type ShopToastVariant } from '../lib/toast';
type ShopToastContextValue = {
showToast: (message: string, variant?: ShopToastVariant) => void;
};
const ShopToastContext = createContext<ShopToastContextValue | null>(null);
export function ShopToastProvider({ children }: { children: ReactNode }) {
const [toast, setToast] = useState('');
const [variant, setVariant] = useState<ShopToastVariant>('error');
const timerRef = useRef<number | null>(null);
const showToast = useCallback((message: string, nextVariant: ShopToastVariant = 'error') => {
if (timerRef.current) window.clearTimeout(timerRef.current);
setVariant(nextVariant);
setToast(message);
timerRef.current = window.setTimeout(() => {
setToast('');
timerRef.current = null;
}, nextVariant === 'error' ? 2800 : 2000);
}, []);
useEffect(() => {
registerShopToastListener(showToast);
return () => {
registerShopToastListener(null);
if (timerRef.current) window.clearTimeout(timerRef.current);
};
}, [showToast]);
return (
<ShopToastContext.Provider value={{ showToast }}>
{children}
{toast ? (
<div
className={`shop-float-toast${variant === 'error' ? ' shop-float-toast--error' : ''}`}
role="alert"
aria-live="assertive"
>
{toast}
</div>
) : null}
</ShopToastContext.Provider>
);
}
export function useShopToast(): ShopToastContextValue {
const ctx = useContext(ShopToastContext);
if (!ctx) throw new Error('useShopToast 必须在 ShopToastProvider 内使用');
return ctx;
}