beez-ui 2.6.0 → 2.6.2

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/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ Todos los cambios relevantes de beez-ui se documentan en este archivo con el for
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.6.2] - 2026-10-16
8
+
9
+ ### Fixed
10
+
11
+ - El `Toaster` exportado por beez-ui (desde `beez-ui` y `beez-ui/sonner`) también responde al click y al teclado (Alt+T) mientras hay un `Dialog`, `AlertDialog` o `Sheet` abierto, y devuelve el foco al modal cuando se cierra el toast enfocado, sin cambiar su aspecto ni sus props.
12
+
13
+ ## [2.6.1] - 2026-10-16
14
+
15
+ ### Fixed
16
+
17
+ - Los botones de un toast de `ThemedToaster` (acción, cancelar o cerrar) responden mientras hay un `Dialog`, `AlertDialog` o `Sheet` abierto, y presionarlos ya no cierra el `Dialog` o el `Sheet`. También se alcanzan con el teclado mediante el atajo de Sonner (Alt+T), que ya no queda bloqueado por la trampa de foco del modal; si el control enfocado cierra su toast, el foco vuelve al modal en lugar de perderse.
18
+ - Presionar Escape en un menú, select o diálogo abierto desde el `Sidebar` en mobile cierra solo esa capa y deja el sidebar abierto.
19
+ - Abrir el `Sidebar` en mobile en una ventana de escritorio angosta ya no desplaza la página de costado cuando desaparece la barra de scroll.
20
+ - El contenido de `PopoverContent` más alto que el espacio disponible en pantalla se desplaza dentro del panel en lugar de quedar cortado fuera del viewport.
21
+
7
22
  ## [2.6.0] - 2026-10-15
8
23
 
9
24
  ### Added
package/README.md CHANGED
@@ -187,7 +187,7 @@ Next y TanStack Router son peers opcionales aislados en sus entrypoints. El prov
187
187
 
188
188
  La tabla conserva agrupación estable, columnas configurables, memoización, exclusiones y sincronización de qualifiers por identificadores. La barra conserva navegación por teclado, autocompletado y filtros de texto, rangos, fechas, presencia y carpetas. `Calendar` usa español por defecto y acepta otra locale. Los textos y configuraciones de filtros se pueden personalizar por props.
189
189
 
190
- Los componentes compartidos conservan el tema de LaTribu. Se incorporaron atributos `data-variant`/`data-size` del botón, scroll para paneles largos y persistencia opcional del sidebar. `Button` sigue la API de Arc: `variant` `primary`, `secondary`, `ghost` o `danger`, `size` `sm`, `md` o `lg` y `loading`; renderiza un `<button>` nativo con `type="button"` por defecto y no admite `asChild`: un link con aspecto de botón se estiliza como link. Se mantienen los estados deshabilitados y los skeletons deterministas. `AvatarImage` delega carga y fallback a Base UI; conserva carga diferida y recuperación al cambiar `src`. El export original `Toaster` permanece disponible; `ThemedToaster` agrega los estilos e iconos compartidos.
190
+ Los componentes compartidos conservan el tema de LaTribu. Se incorporaron atributos `data-variant`/`data-size` del botón, scroll para paneles largos y persistencia opcional del sidebar. `Button` sigue la API de Arc: `variant` `primary`, `secondary`, `ghost` o `danger`, `size` `sm`, `md` o `lg` y `loading`; renderiza un `<button>` nativo con `type="button"` por defecto y no admite `asChild`: un link con aspecto de botón se estiliza como link. Se mantienen los estados deshabilitados y los skeletons deterministas. `AvatarImage` delega carga y fallback a Base UI; conserva carga diferida y recuperación al cambiar `src`. El export `Toaster` conserva el aspecto y las props de Sonner, y sus toasts responden al click y al teclado (Alt+T) con un `Dialog`, `AlertDialog` o `Sheet` abierto; `ThemedToaster` se apoya en él y agrega los estilos e iconos compartidos.
191
191
 
192
192
  ## Componentes de producto reutilizables
193
193
 
@@ -11,6 +11,7 @@ import { Dialog as DialogPrimitive } from "radix-ui";
11
11
  import { MotionSlot } from "../motion/motion-slot.js";
12
12
  import { MotionPresence, MotionOpenProvider, useMotionOpenState } from "../motion/presence.js";
13
13
  import { cn } from "../lib/utils.js";
14
+ import { keepOpenOnToastInteraction } from "../lib/toast-layer.js";
14
15
  import { Button } from "./button.js";
15
16
  import { ControlButton } from "./control-button.js";
16
17
  import { XIcon } from "lucide-react";
@@ -210,7 +211,7 @@ function DialogViewportCloseButton() {
210
211
  * @returns The styled primitive with its original interaction contract.
211
212
  */
212
213
  function DialogContent(t0) {
213
- const $ = _c(26);
214
+ const $ = _c(29);
214
215
  let children;
215
216
  let className;
216
217
  let props;
@@ -256,17 +257,25 @@ function DialogContent(t0) {
256
257
  t7 = $[9];
257
258
  }
258
259
  let t8;
259
- if ($[10] !== closeButtonPlacement || $[11] !== showCloseButton) {
260
- t8 = showCloseButton && closeButtonPlacement === "viewport" && /* @__PURE__ */ _jsx(DialogViewportCloseButton, {});
261
- $[10] = closeButtonPlacement;
262
- $[11] = showCloseButton;
263
- $[12] = t8;
260
+ if ($[10] !== props.onInteractOutside) {
261
+ t8 = keepOpenOnToastInteraction(props.onInteractOutside);
262
+ $[10] = props.onInteractOutside;
263
+ $[11] = t8;
264
264
  } else {
265
- t8 = $[12];
265
+ t8 = $[11];
266
266
  }
267
267
  let t9;
268
- if ($[13] !== closeButtonPlacement || $[14] !== showCloseButton) {
269
- t9 = showCloseButton && closeButtonPlacement === "content" && /* @__PURE__ */ _jsx(DialogPrimitive.Close, {
268
+ if ($[12] !== closeButtonPlacement || $[13] !== showCloseButton) {
269
+ t9 = showCloseButton && closeButtonPlacement === "viewport" && /* @__PURE__ */ _jsx(DialogViewportCloseButton, {});
270
+ $[12] = closeButtonPlacement;
271
+ $[13] = showCloseButton;
272
+ $[14] = t9;
273
+ } else {
274
+ t9 = $[14];
275
+ }
276
+ let t10;
277
+ if ($[15] !== closeButtonPlacement || $[16] !== showCloseButton) {
278
+ t10 = showCloseButton && closeButtonPlacement === "content" && /* @__PURE__ */ _jsx(DialogPrimitive.Close, {
270
279
  "data-slot": "dialog-close",
271
280
  asChild: true,
272
281
  children: /* @__PURE__ */ _jsx(MotionSlot, {
@@ -282,15 +291,15 @@ function DialogContent(t0) {
282
291
  })
283
292
  })
284
293
  });
285
- $[13] = closeButtonPlacement;
286
- $[14] = showCloseButton;
287
- $[15] = t9;
294
+ $[15] = closeButtonPlacement;
295
+ $[16] = showCloseButton;
296
+ $[17] = t10;
288
297
  } else {
289
- t9 = $[15];
298
+ t10 = $[17];
290
299
  }
291
- let t10;
292
- if ($[16] !== children || $[17] !== props || $[18] !== t5 || $[19] !== t7 || $[20] !== t8 || $[21] !== t9) {
293
- t10 = /* @__PURE__ */ _jsxs(React.Fragment, { children: [t4, /* @__PURE__ */ _jsx(MotionSlot, {
300
+ let t11;
301
+ if ($[18] !== children || $[19] !== props || $[20] !== t10 || $[21] !== t5 || $[22] !== t7 || $[23] !== t8 || $[24] !== t9) {
302
+ t11 = /* @__PURE__ */ _jsxs(React.Fragment, { children: [t4, /* @__PURE__ */ _jsx(MotionSlot, {
294
303
  kind: "center-morph",
295
304
  children: /* @__PURE__ */ _jsxs(DialogPrimitive.Content, {
296
305
  forceMount: true,
@@ -298,40 +307,42 @@ function DialogContent(t0) {
298
307
  "data-close-button-placement": t5,
299
308
  className: t7,
300
309
  ...props,
310
+ onInteractOutside: t8,
301
311
  children: [
302
312
  children,
303
- t8,
304
- t9
313
+ t9,
314
+ t10
305
315
  ]
306
316
  })
307
317
  })] });
308
- $[16] = children;
309
- $[17] = props;
310
- $[18] = t5;
311
- $[19] = t7;
312
- $[20] = t8;
313
- $[21] = t9;
314
- $[22] = t10;
318
+ $[18] = children;
319
+ $[19] = props;
320
+ $[20] = t10;
321
+ $[21] = t5;
322
+ $[22] = t7;
323
+ $[23] = t8;
324
+ $[24] = t9;
325
+ $[25] = t11;
315
326
  } else {
316
- t10 = $[22];
327
+ t11 = $[25];
317
328
  }
318
- let t11;
319
- if ($[23] !== props.forceMount || $[24] !== t10) {
320
- t11 = /* @__PURE__ */ _jsx(DialogPortal, {
329
+ let t12;
330
+ if ($[26] !== props.forceMount || $[27] !== t11) {
331
+ t12 = /* @__PURE__ */ _jsx(DialogPortal, {
321
332
  forceMount: true,
322
333
  children: /* @__PURE__ */ _jsx(MotionPresence, {
323
334
  scope: "dialog",
324
335
  forceMount: t3,
325
- children: t10
336
+ children: t11
326
337
  })
327
338
  });
328
- $[23] = props.forceMount;
329
- $[24] = t10;
330
- $[25] = t11;
339
+ $[26] = props.forceMount;
340
+ $[27] = t11;
341
+ $[28] = t12;
331
342
  } else {
332
- t11 = $[25];
343
+ t12 = $[28];
333
344
  }
334
- return t11;
345
+ return t12;
335
346
  }
336
347
  /**
337
348
  * Stacks the title and description. While the panel shows its own close button, the header keeps Arc's gap to it so
@@ -11,6 +11,7 @@ declare function PopoverTrigger({ ...props }: React.ComponentProps<typeof Popove
11
11
  declare function PopoverClose({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Close>): React.JSX.Element;
12
12
  /**
13
13
  * Renders Arc's panel: raised surface, hairline border, panel radius and floating shadow, kept inside the viewport.
14
+ * Content taller than the room left on the placed side scrolls inside the panel instead of running off screen.
14
15
  * @param props - Radix content properties. `align` defaults to `center`, `sideOffset` to 6px and `collisionPadding`
15
16
  * to 10px.
16
17
  * @returns The portaled panel.
@@ -106,6 +106,7 @@ function resolvePopoverMotion() {
106
106
  }
107
107
  /**
108
108
  * Renders Arc's panel: raised surface, hairline border, panel radius and floating shadow, kept inside the viewport.
109
+ * Content taller than the room left on the placed side scrolls inside the panel instead of running off screen.
109
110
  * @param props - Radix content properties. `align` defaults to `center`, `sideOffset` to 6px and `collisionPadding`
110
111
  * to 10px.
111
112
  * @returns The portaled panel.
@@ -138,7 +139,7 @@ function PopoverContent(t0) {
138
139
  const t4 = props.forceMount;
139
140
  let t5;
140
141
  if ($[6] !== className) {
141
- t5 = cn("z-50 flex w-72 max-w-[calc(100vw-20px)] origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 rounded-(--radius-panel) border border-border bg-surface-raised p-(--space-4) text-sm leading-(--leading-body) text-foreground shadow-(--shadow-floating) outline-hidden", className);
142
+ t5 = cn("z-50 flex max-h-(--radix-popover-content-available-height) w-72 max-w-[calc(100vw-20px)] origin-(--radix-popover-content-transform-origin) flex-col gap-2.5 overflow-y-auto overscroll-contain *:shrink-0 rounded-(--radius-panel) border border-border bg-surface-raised p-(--space-4) text-sm leading-(--leading-body) text-foreground shadow-(--shadow-floating) outline-hidden", className);
142
143
  $[6] = className;
143
144
  $[7] = t5;
144
145
  } else {
@@ -5,6 +5,7 @@ import { Dialog as SheetPrimitive } from "radix-ui";
5
5
  import { MotionSlot } from "../motion/motion-slot.js";
6
6
  import { MotionPresence, MotionOpenProvider, useMotionOpenState } from "../motion/presence.js";
7
7
  import { cn } from "../lib/utils.js";
8
+ import { keepOpenOnToastInteraction } from "../lib/toast-layer.js";
8
9
  import { ControlButton } from "./control-button.js";
9
10
  import { XIcon } from "lucide-react";
10
11
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -160,7 +161,7 @@ function SheetOverlay(t0) {
160
161
  * @returns The styled primitive with its original interaction contract.
161
162
  */
162
163
  function SheetContent(t0) {
163
- const $ = _c(20);
164
+ const $ = _c(23);
164
165
  let children;
165
166
  let className;
166
167
  let props;
@@ -203,8 +204,16 @@ function SheetContent(t0) {
203
204
  t5 = $[8];
204
205
  }
205
206
  let t6;
206
- if ($[9] !== showCloseButton) {
207
- t6 = showCloseButton && /* @__PURE__ */ _jsx(SheetPrimitive.Close, {
207
+ if ($[9] !== props.onInteractOutside) {
208
+ t6 = keepOpenOnToastInteraction(props.onInteractOutside);
209
+ $[9] = props.onInteractOutside;
210
+ $[10] = t6;
211
+ } else {
212
+ t6 = $[10];
213
+ }
214
+ let t7;
215
+ if ($[11] !== showCloseButton) {
216
+ t7 = showCloseButton && /* @__PURE__ */ _jsx(SheetPrimitive.Close, {
208
217
  "data-slot": "sheet-close",
209
218
  asChild: true,
210
219
  children: /* @__PURE__ */ _jsx(MotionSlot, {
@@ -220,14 +229,14 @@ function SheetContent(t0) {
220
229
  })
221
230
  })
222
231
  });
223
- $[9] = showCloseButton;
224
- $[10] = t6;
232
+ $[11] = showCloseButton;
233
+ $[12] = t7;
225
234
  } else {
226
- t6 = $[10];
235
+ t7 = $[12];
227
236
  }
228
- let t7;
229
- if ($[11] !== children || $[12] !== props || $[13] !== side || $[14] !== t5 || $[15] !== t6) {
230
- t7 = /* @__PURE__ */ _jsxs(React.Fragment, { children: [t4, /* @__PURE__ */ _jsx(MotionSlot, {
237
+ let t8;
238
+ if ($[13] !== children || $[14] !== props || $[15] !== side || $[16] !== t5 || $[17] !== t6 || $[18] !== t7) {
239
+ t8 = /* @__PURE__ */ _jsxs(React.Fragment, { children: [t4, /* @__PURE__ */ _jsx(MotionSlot, {
231
240
  kind: "sheet",
232
241
  children: /* @__PURE__ */ _jsxs(SheetPrimitive.Content, {
233
242
  forceMount: true,
@@ -235,35 +244,37 @@ function SheetContent(t0) {
235
244
  "data-side": side,
236
245
  className: t5,
237
246
  ...props,
238
- children: [children, t6]
247
+ onInteractOutside: t6,
248
+ children: [children, t7]
239
249
  })
240
250
  })] });
241
- $[11] = children;
242
- $[12] = props;
243
- $[13] = side;
244
- $[14] = t5;
245
- $[15] = t6;
246
- $[16] = t7;
251
+ $[13] = children;
252
+ $[14] = props;
253
+ $[15] = side;
254
+ $[16] = t5;
255
+ $[17] = t6;
256
+ $[18] = t7;
257
+ $[19] = t8;
247
258
  } else {
248
- t7 = $[16];
259
+ t8 = $[19];
249
260
  }
250
- let t8;
251
- if ($[17] !== props.forceMount || $[18] !== t7) {
252
- t8 = /* @__PURE__ */ _jsx(SheetPortal, {
261
+ let t9;
262
+ if ($[20] !== props.forceMount || $[21] !== t8) {
263
+ t9 = /* @__PURE__ */ _jsx(SheetPortal, {
253
264
  forceMount: true,
254
265
  children: /* @__PURE__ */ _jsx(MotionPresence, {
255
266
  scope: "sheet",
256
267
  forceMount: t3,
257
- children: t7
268
+ children: t8
258
269
  })
259
270
  });
260
- $[17] = props.forceMount;
261
- $[18] = t7;
262
- $[19] = t8;
271
+ $[20] = props.forceMount;
272
+ $[21] = t8;
273
+ $[22] = t9;
263
274
  } else {
264
- t8 = $[19];
275
+ t9 = $[22];
265
276
  }
266
- return t8;
277
+ return t9;
267
278
  }
268
279
  function SheetHeader(t0) {
269
280
  const $ = _c(8);
@@ -404,15 +404,22 @@ function MobileSidebar(t0) {
404
404
  const previousBodyStyles = {
405
405
  left: body.style.left,
406
406
  overflow: body.style.overflow,
407
+ paddingRight: body.style.paddingRight,
407
408
  position: body.style.position,
408
409
  right: body.style.right,
409
410
  top: body.style.top
410
411
  };
412
+ const clientWidthBeforeLock = document.documentElement.clientWidth;
413
+ const bodyPaddingRight = Number.parseFloat(getComputedStyle(body).paddingRight) || 0;
411
414
  body.style.position = "fixed";
412
415
  body.style.top = `-${scrollY}px`;
413
416
  body.style.left = "0";
414
417
  body.style.right = "0";
415
418
  body.style.overflow = "hidden";
419
+ const scrollbarWidth = document.documentElement.clientWidth - clientWidthBeforeLock;
420
+ if (scrollbarWidth > 0) {
421
+ body.style.paddingRight = `${bodyPaddingRight + scrollbarWidth}px`;
422
+ }
416
423
  const restoreTriggerFocus = () => triggerRef.current?.focus({ preventScroll: true });
417
424
  const focusFrame = requestAnimationFrame(() => {
418
425
  const firstFocusable = panelRef.current?.querySelector(FOCUSABLE_SELECTOR);
@@ -425,6 +432,7 @@ function MobileSidebar(t0) {
425
432
  body.style.left = previousBodyStyles.left;
426
433
  body.style.right = previousBodyStyles.right;
427
434
  body.style.overflow = previousBodyStyles.overflow;
435
+ body.style.paddingRight = previousBodyStyles.paddingRight;
428
436
  window.scrollTo(0, scrollY);
429
437
  restoreTriggerFocus();
430
438
  };
@@ -447,6 +455,9 @@ function MobileSidebar(t0) {
447
455
  let t5;
448
456
  if ($[7] !== setOpenMobile) {
449
457
  t5 = (event) => {
458
+ if (event.defaultPrevented || !panelRef.current?.contains(event.target)) {
459
+ return;
460
+ }
450
461
  if (event.key === "Escape") {
451
462
  event.preventDefault();
452
463
  setOpenMobile(false);
@@ -1,4 +1,7 @@
1
- import { type ToasterProps } from "sonner";
2
- /** Renders shared notification styling using the consumer's resolved theme. */
3
- declare const ThemedToaster: ({ theme, ...props }: ToasterProps) => import("react").JSX.Element;
1
+ import type { ToasterProps } from "sonner";
2
+ /**
3
+ * Renders shared notification styling using the consumer's resolved theme, on top of beez-ui's `Toaster`, so its
4
+ * toasts stay usable from an open `Dialog`, `AlertDialog` or `Sheet`.
5
+ */
6
+ declare const ThemedToaster: ({ theme, className, ...props }: ToasterProps) => import("react").JSX.Element;
4
7
  export { ThemedToaster };
@@ -1,104 +1,120 @@
1
1
  "use client";
2
2
  import { c as _c } from "react/compiler-runtime";
3
3
  import { MotionSlot } from "../motion/motion-slot.js";
4
- import { Toaster as Sonner } from "sonner";
4
+ import { cn } from "../lib/utils.js";
5
+ import { Toaster } from "./toaster.js";
5
6
  import { useTheme } from "next-themes";
6
7
  import { CircleCheck, Info, TriangleAlert, OctagonAlert, Loader } from "lucide-react";
7
8
  import { jsx as _jsx } from "react/jsx-runtime";
8
- /** Renders shared notification styling using the consumer's resolved theme. */
9
+ /**
10
+ * Renders shared notification styling using the consumer's resolved theme, on top of beez-ui's `Toaster`, so its
11
+ * toasts stay usable from an open `Dialog`, `AlertDialog` or `Sheet`.
12
+ */
9
13
  const ThemedToaster = (t0) => {
10
- const $ = _c(12);
14
+ const $ = _c(16);
15
+ let className;
11
16
  let props;
12
17
  let theme;
13
18
  if ($[0] !== t0) {
14
- ({theme, ...props} = t0);
19
+ ({theme, className, ...props} = t0);
15
20
  $[0] = t0;
16
- $[1] = props;
17
- $[2] = theme;
21
+ $[1] = className;
22
+ $[2] = props;
23
+ $[3] = theme;
18
24
  } else {
19
- props = $[1];
20
- theme = $[2];
25
+ className = $[1];
26
+ props = $[2];
27
+ theme = $[3];
21
28
  }
22
29
  const { resolvedTheme } = useTheme();
23
30
  const activeTheme = theme ?? (resolvedTheme === "dark" ? "dark" : "light");
24
31
  let t1;
25
- if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
26
- t1 = /* @__PURE__ */ _jsx(MotionSlot, {
27
- kind: "selection",
28
- children: /* @__PURE__ */ _jsx(CircleCheck, { className: "size-4" })
29
- });
30
- $[3] = t1;
32
+ if ($[4] !== className) {
33
+ t1 = cn("toaster group", className);
34
+ $[4] = className;
35
+ $[5] = t1;
31
36
  } else {
32
- t1 = $[3];
37
+ t1 = $[5];
33
38
  }
34
39
  let t2;
35
- if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
40
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
36
41
  t2 = /* @__PURE__ */ _jsx(MotionSlot, {
37
42
  kind: "selection",
38
- children: /* @__PURE__ */ _jsx(Info, { className: "size-4" })
43
+ children: /* @__PURE__ */ _jsx(CircleCheck, { className: "size-4" })
39
44
  });
40
- $[4] = t2;
45
+ $[6] = t2;
41
46
  } else {
42
- t2 = $[4];
47
+ t2 = $[6];
43
48
  }
44
49
  let t3;
45
- if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
50
+ if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
46
51
  t3 = /* @__PURE__ */ _jsx(MotionSlot, {
47
52
  kind: "selection",
48
- children: /* @__PURE__ */ _jsx(TriangleAlert, { className: "size-4" })
53
+ children: /* @__PURE__ */ _jsx(Info, { className: "size-4" })
49
54
  });
50
- $[5] = t3;
55
+ $[7] = t3;
51
56
  } else {
52
- t3 = $[5];
57
+ t3 = $[7];
53
58
  }
54
59
  let t4;
60
+ if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
61
+ t4 = /* @__PURE__ */ _jsx(MotionSlot, {
62
+ kind: "selection",
63
+ children: /* @__PURE__ */ _jsx(TriangleAlert, { className: "size-4" })
64
+ });
65
+ $[8] = t4;
66
+ } else {
67
+ t4 = $[8];
68
+ }
55
69
  let t5;
56
- if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
57
- t4 = {
58
- success: t1,
59
- info: t2,
60
- warning: t3,
70
+ let t6;
71
+ if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
72
+ t5 = {
73
+ success: t2,
74
+ info: t3,
75
+ warning: t4,
61
76
  error: /* @__PURE__ */ _jsx(MotionSlot, {
62
77
  kind: "selection",
63
78
  children: /* @__PURE__ */ _jsx(OctagonAlert, { className: "size-4" })
64
79
  }),
65
80
  loading: /* @__PURE__ */ _jsx(Loader, { className: "size-4 animate-spin" })
66
81
  };
67
- t5 = {
82
+ t6 = {
68
83
  "--normal-bg": "var(--popover)",
69
84
  "--normal-text": "var(--popover-foreground)",
70
85
  "--normal-border": "var(--border)",
71
86
  "--border-radius": "var(--radius)"
72
87
  };
73
- $[6] = t4;
74
- $[7] = t5;
88
+ $[9] = t5;
89
+ $[10] = t6;
75
90
  } else {
76
- t4 = $[6];
77
- t5 = $[7];
91
+ t5 = $[9];
92
+ t6 = $[10];
78
93
  }
79
- let t6;
80
- if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
81
- t6 = { classNames: { toast: "cn-toast" } };
82
- $[8] = t6;
94
+ let t7;
95
+ if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
96
+ t7 = { classNames: { toast: "cn-toast" } };
97
+ $[11] = t7;
83
98
  } else {
84
- t6 = $[8];
99
+ t7 = $[11];
85
100
  }
86
- let t7;
87
- if ($[9] !== activeTheme || $[10] !== props) {
88
- t7 = /* @__PURE__ */ _jsx(Sonner, {
101
+ let t8;
102
+ if ($[12] !== activeTheme || $[13] !== props || $[14] !== t1) {
103
+ t8 = /* @__PURE__ */ _jsx(Toaster, {
89
104
  theme: activeTheme,
90
- className: "toaster group",
91
- icons: t4,
92
- style: t5,
93
- toastOptions: t6,
105
+ className: t1,
106
+ icons: t5,
107
+ style: t6,
108
+ toastOptions: t7,
94
109
  ...props
95
110
  });
96
- $[9] = activeTheme;
97
- $[10] = props;
98
- $[11] = t7;
111
+ $[12] = activeTheme;
112
+ $[13] = props;
113
+ $[14] = t1;
114
+ $[15] = t8;
99
115
  } else {
100
- t7 = $[11];
116
+ t8 = $[15];
101
117
  }
102
- return t7;
118
+ return t8;
103
119
  };
104
120
  export { ThemedToaster };
@@ -0,0 +1,12 @@
1
+ import { type ComponentProps } from "react";
2
+ import { Toaster as SonnerToaster } from "sonner";
3
+ /**
4
+ * Renders Sonner's toaster unchanged in look, but keeps its toasts usable while a modal `Dialog`, `AlertDialog` or
5
+ * `Sheet` is open: the toast layer takes pointer input even though the modal disables pointer events on the page,
6
+ * and Sonner's hotkey moves keyboard focus into the toasts past the modal's focus trap (focus returns to the modal
7
+ * when the focused toast goes away). Accepts every Sonner prop, including `ref`, and keeps the consumer's `className`.
8
+ * @param props - Sonner's toaster props.
9
+ * @returns The toast layer.
10
+ */
11
+ declare const Toaster: ({ className, ...props }: ComponentProps<typeof SonnerToaster>) => import("react").JSX.Element;
12
+ export { Toaster };
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { c as _c } from "react/compiler-runtime";
3
+ import { cn } from "../lib/utils.js";
4
+ import { letFocusReachToastLayer } from "../lib/toast-layer.js";
5
+ import { useEffect } from "react";
6
+ import { Toaster as SonnerToaster } from "sonner";
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ /**
9
+ * Renders Sonner's toaster unchanged in look, but keeps its toasts usable while a modal `Dialog`, `AlertDialog` or
10
+ * `Sheet` is open: the toast layer takes pointer input even though the modal disables pointer events on the page,
11
+ * and Sonner's hotkey moves keyboard focus into the toasts past the modal's focus trap (focus returns to the modal
12
+ * when the focused toast goes away). Accepts every Sonner prop, including `ref`, and keeps the consumer's `className`.
13
+ * @param props - Sonner's toaster props.
14
+ * @returns The toast layer.
15
+ */
16
+ const Toaster = (t0) => {
17
+ const $ = _c(9);
18
+ let className;
19
+ let props;
20
+ if ($[0] !== t0) {
21
+ ({className, ...props} = t0);
22
+ $[0] = t0;
23
+ $[1] = className;
24
+ $[2] = props;
25
+ } else {
26
+ className = $[1];
27
+ props = $[2];
28
+ }
29
+ let t1;
30
+ if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
31
+ t1 = [];
32
+ $[3] = t1;
33
+ } else {
34
+ t1 = $[3];
35
+ }
36
+ useEffect(_temp, t1);
37
+ let t2;
38
+ if ($[4] !== className) {
39
+ t2 = cn("pointer-events-auto", className);
40
+ $[4] = className;
41
+ $[5] = t2;
42
+ } else {
43
+ t2 = $[5];
44
+ }
45
+ let t3;
46
+ if ($[6] !== props || $[7] !== t2) {
47
+ t3 = /* @__PURE__ */ _jsx(SonnerToaster, {
48
+ className: t2,
49
+ ...props
50
+ });
51
+ $[6] = props;
52
+ $[7] = t2;
53
+ $[8] = t3;
54
+ } else {
55
+ t3 = $[8];
56
+ }
57
+ return t3;
58
+ };
59
+ export { Toaster };
60
+ function _temp() {
61
+ return letFocusReachToastLayer(document);
62
+ }
@@ -0,0 +1,3 @@
1
+ /** Contract with the toast layer rendered by `ThemedToaster` (Sonner). */
2
+ /** Selector of the list Sonner renders for each toast position, the outermost element of the toast layer. */
3
+ export declare const TOAST_LAYER_SELECTOR = "[data-sonner-toaster]";
@@ -0,0 +1,3 @@
1
+ /** Contract with the toast layer rendered by `ThemedToaster` (Sonner). */
2
+ /** Selector of the list Sonner renders for each toast position, the outermost element of the toast layer. */
3
+ export const TOAST_LAYER_SELECTOR = "[data-sonner-toaster]";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Tells whether an event target belongs to the toast layer.
3
+ * @param target - Target of the outside interaction.
4
+ * @returns `true` when the target is a toast or one of its controls.
5
+ */
6
+ export declare function isToastLayerTarget(target: EventTarget | null): boolean;
7
+ /**
8
+ * Lets keyboard focus enter the toast layer while a modal traps focus. Radix's focus trap listens for `focusin` and
9
+ * `focusout` on the document and pulls focus back into the modal whenever it lands outside, so Sonner's hotkey could
10
+ * never move focus to a toast's controls. Focus changes that land on a toast stop at the body, after React has run
11
+ * its own handlers and before the document-level trap sees them; every other focus change still reaches the trap.
12
+ * Because the trap never sees focus leave, it cannot pull it back either: when the focused toast control is removed
13
+ * (an action or close button dismisses its toast), focus returns to the element it came from instead of the body.
14
+ * @param ownerDocument - Document whose body hosts the app and the modal portals.
15
+ * @returns Removes the listeners.
16
+ */
17
+ export declare function letFocusReachToastLayer(ownerDocument: Document): () => void;
18
+ /**
19
+ * Wraps a modal's `onInteractOutside` so presses on toasts never dismiss it. The consumer's handler still runs first
20
+ * and can keep preventing dismissal for its own reasons.
21
+ * @param handler - The consumer's `onInteractOutside`, if any.
22
+ * @returns The handler to give the Radix content.
23
+ */
24
+ export declare function keepOpenOnToastInteraction<OutsideEvent extends Event>(handler?: (event: OutsideEvent) => void): (event: OutsideEvent) => void;