@umituz/web-design-system 4.3.0 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/web-design-system",
3
- "version": "4.3.0",
3
+ "version": "4.4.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Web Design System - Tailwind v4 authored, precompiled CSS shipped. Atomic Design components (Atoms, Molecules, Organisms, Templates) for React applications.",
@@ -4,7 +4,7 @@
4
4
  * styles contract test).
5
5
  */
6
6
 
7
- import { describe, expect, it } from 'vitest';
7
+ import { describe, expect, it, vi } from 'vitest';
8
8
  import { act, fireEvent, render, screen } from '@testing-library/react';
9
9
  import { Button } from '../presentation/atoms/Button';
10
10
  import { Badge } from '../presentation/atoms/Badge';
@@ -104,6 +104,40 @@ describe('organisms', () => {
104
104
  expect(screen.getByText('Saved').closest('div')?.parentElement?.className).toContain('border-l-success');
105
105
  });
106
106
 
107
+ it('ToastProvider honors maxVisible and duration overrides', () => {
108
+ vi.useFakeTimers();
109
+ function Burst() {
110
+ const { toast } = useToast();
111
+ return (
112
+ <button
113
+ type="button"
114
+ onClick={() => {
115
+ toast({ kind: 'info', title: 'One' });
116
+ toast({ kind: 'info', title: 'Two' });
117
+ toast({ kind: 'info', title: 'Three' });
118
+ }}
119
+ >
120
+ burst
121
+ </button>
122
+ );
123
+ }
124
+ render(
125
+ <ToastProvider maxVisible={2} duration={500}>
126
+ <Burst />
127
+ </ToastProvider>,
128
+ );
129
+ act(() => {
130
+ fireEvent.click(screen.getByRole('button', { name: 'burst' }));
131
+ });
132
+ expect(screen.queryByText('One')).toBeNull();
133
+ expect(screen.getByText('Two')).toBeTruthy();
134
+ act(() => {
135
+ vi.advanceTimersByTime(600);
136
+ });
137
+ expect(screen.queryByText('Two')).toBeNull();
138
+ vi.useRealTimers();
139
+ });
140
+
107
141
  it('KeyValueList renders label/value pairs in a definition list', () => {
108
142
  render(
109
143
  <KeyValueList
@@ -43,9 +43,11 @@ const kindMeta: Record<ToastKind, { icon: typeof CheckCircle2; accent: string; i
43
43
 
44
44
  export interface ToastProviderProps {
45
45
  children: ReactNode;
46
+ maxVisible?: number;
47
+ duration?: number;
46
48
  }
47
49
 
48
- export function ToastProvider({ children }: ToastProviderProps) {
50
+ export function ToastProvider({ children, maxVisible = 4, duration = 4200 }: ToastProviderProps) {
49
51
  const [toasts, setToasts] = useState<ToastEntry[]>([]);
50
52
  const counter = useRef(0);
51
53
 
@@ -56,10 +58,10 @@ export function ToastProvider({ children }: ToastProviderProps) {
56
58
  const toast = useCallback(
57
59
  (t: ToastOptions) => {
58
60
  const id = ++counter.current;
59
- setToasts((list) => [...list.slice(-3), { id, ...t }]);
60
- setTimeout(() => dismiss(id), 4200);
61
+ setToasts((list) => [...list.slice(-(maxVisible - 1)), { id, ...t }]);
62
+ setTimeout(() => dismiss(id), duration);
61
63
  },
62
- [dismiss],
64
+ [dismiss, maxVisible, duration],
63
65
  );
64
66
 
65
67
  const value = useMemo(() => ({ toast }), [toast]);
@@ -68,6 +70,7 @@ export function ToastProvider({ children }: ToastProviderProps) {
68
70
  <ToastContext.Provider value={value}>
69
71
  {children}
70
72
  <div
73
+ role="status"
71
74
  aria-live="polite"
72
75
  className="pointer-events-none fixed bottom-4 right-4 z-[100] flex w-[340px] max-w-[calc(100vw-2rem)] flex-col gap-2"
73
76
  >