beez-ui 0.9.1 → 0.11.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/CHANGELOG.md CHANGED
@@ -4,6 +4,20 @@ Todos los cambios relevantes de beez-ui se documentan en este archivo con el for
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.11.0] - 2026-10-03
8
+
9
+ - 859b7a6 agrega mejoras al sidebar y persistencia de estado
10
+
11
+ ## [0.10.0] - 2026-10-03
12
+
13
+ - 6769ea7 agrega funcionalidad de persistencia y animación al sidebar
14
+ - 3a84ef1 agrega actualización de la dependencia «beez-rp» a la versión 0.6.1
15
+ - 2723ab1 Bump beez-rp to 0.6.0 (#4)
16
+ - 811829a update «beez-rp» dependency to version 0.5.0
17
+ - ab5c997 build: bump beez-rp to 0.4.0
18
+ - d267b0b add checks configuration to prevent redundant validation before version bump
19
+ - 041a0f8 Migrate linting from ESLint to oxlint (#3)
20
+
7
21
  ## [0.9.1] - 2026-09-27
8
22
 
9
23
  ### Added
package/README.md CHANGED
@@ -80,7 +80,7 @@ siguen los tokens de [beui motion](https://beui.dev/components/motion):
80
80
  - `Dialog` y `AlertDialog` suben con spring; `Sheet` entra desde su borde con spring
81
81
  y sale con la curva de cajón (0.24 s), sin demorar la siguiente interacción.
82
82
  - `GlideSlot` desliza el indicador activo entre ítems como un `layoutId` compartido:
83
- la pestaña activa de `Tabs` (fondo o subrayado), el ítem activo de `SidebarMenu`, la
83
+ la pestaña activa de `Tabs` (fondo o subrayado), la
84
84
  página actual de `PaginationContent`, y al navegar con teclado el ítem resaltado de
85
85
  `DropdownMenu` y `Select` y la sugerencia activa de `FilterQueryBar`. Con el puntero,
86
86
  esos resaltados lo siguen al instante: el propio puntero ya marca la posición.
@@ -91,6 +91,10 @@ siguen los tokens de [beui motion](https://beui.dev/components/motion):
91
91
  (grupos y columnas) giran en lugar de cambiar de ícono; CSS define el ángulo final.
92
92
  - Las opciones del `Select` entran escalonadas con blur (las primeras 10; el resto
93
93
  solo se desvanece) y los checks de ítems de `Select` y `DropdownMenu` aparecen con pop.
94
+ - `Sidebar` sigue a [beui animated sidebar](https://beui.dev/components/motion/animated-sidebar):
95
+ el ancho cambia con un spring entre el panel y el riel de íconos, las etiquetas se
96
+ desvanecen al colapsar, una píldora compartida sigue al ítem activo y al hovereado, los
97
+ submenús se despliegan escalonados y en pantallas chicas se abre como hoja con foco atrapado.
94
98
  - El ícono de `AnimatedThemeToggler` cambia con blur y escala; el botón de cierre de
95
99
  `Dialog` aparece con un pop demorado.
96
100
  - El contenido de `Tabs` entra con un desplazamiento de 4 px y `Alert` entra con blur.
@@ -158,7 +162,7 @@ Next y TanStack Router son peers opcionales aislados en sus entrypoints. El prov
158
162
 
159
163
  - Tema: `AnimatedThemeToggler` y `ThemedToaster` consumen el contexto compartido. Sus props explícitas de tema siguen disponibles para usos controlados.
160
164
  - Navegación: `PaginationNext`, `PaginationPrevious` y `PaginationLink` usan anclas nativas. El prop opcional `component` admite el adaptador del router que elija la app. Sin proveedor usa el elemento nativo; con el proveedor de Next usa su navegación cliente.
161
- - Sidebar: `defaultOpen` y el modo controlado conservan la semántica de LaTribu. `storageKey` activa opcionalmente persistencia local segura tras hidratar, sin cambiar la cookie pública `sidebar_state` ni sus siete días de duración.
165
+ - Sidebar: en `SidebarProvider`, `defaultOpen` y el modo controlado conservan la semántica de LaTribu. Los ítems con `href` navegan con el adaptador de router del proveedor. `storageKey` activa opcionalmente persistencia local segura tras hidratar, sin cambiar la cookie pública `sidebar_state` ni sus siete días de duración; `cookieName` y `cookieMaxAge` la reemplazan cuando la app ya lee su propia cookie en el servidor. Para el contenido propio: `SidebarBrandButton` arma la fila de marca (sirve como `DropdownMenuTrigger asChild`), `SidebarLabel` saca del riel de íconos el texto que solo tiene sentido expandido, `useSidebarPanel()` expone `collapsed` y `AccountMenu` con `triggerVariant="sidebar"` se reduce solo al avatar. No dependas de los atributos `data-*` internos del sidebar: pueden cambiar entre versiones.
162
166
  - Formularios y tablas: el consumidor provee sus datos, validaciones y callbacks. No se importan servicios, modelos de negocio ni endpoints de agenda-mensual.
163
167
 
164
168
  ## Componentes incorporados desde agenda-mensual
@@ -222,11 +226,11 @@ pnpm build
222
226
  pnpm release:prepare
223
227
  ```
224
228
 
225
- `pnpm build` genera las declaraciones con TypeScript 7, JavaScript con Oxc/React Compiler y CSS con el CLI de Tailwind. `pnpm check` ejecuta ESLint 10, los typechecks separados de código y tests con TypeScript 7, y Vitest 5. `tests/tsconfig.json` incorpora los matchers de Testing Library y los tipos de Vite sin incluirlos en el código de producción. `test:browser` verifica una app React/Vite nativa y una app Next real en Chromium y WebKit, tanto en desktop como en móvil. Los tests unitarios importan los archivos compilados. Los consumidores de navegador no instalan plugins de Tailwind, y una prueba adicional sirve el tarball por HTTP sin procesadores CSS para verificar estilos computados y carga de fuentes. Una prueba adicional instala el tarball en un consumidor aislado sin Next y verifica render, filtrado y declaraciones públicas.
229
+ `pnpm build` genera las declaraciones con TypeScript 7, JavaScript con Oxc/React Compiler y CSS con el CLI de Tailwind. `pnpm check` ejecuta oxlint (configurado en `.oxlintrc.json`), los typechecks separados de código y tests con TypeScript 7, y Vitest 5. `tests/tsconfig.json` incorpora los matchers de Testing Library y los tipos de Vite sin incluirlos en el código de producción. `test:browser` verifica una app React/Vite nativa y una app Next real en Chromium y WebKit, tanto en desktop como en móvil. Los tests unitarios importan los archivos compilados. Los consumidores de navegador no instalan plugins de Tailwind, y una prueba adicional sirve el tarball por HTTP sin procesadores CSS para verificar estilos computados y carga de fuentes. Una prueba adicional instala el tarball en un consumidor aislado sin Next y verifica render, filtrado y declaraciones públicas.
226
230
 
227
231
  Los tests resuelven `beez-ui`, `beez-ui/next`, `beez-ui/tanstack` y `beez-ui/hooks` mediante rutas explícitas a las declaraciones compiladas en `tests/tsconfig.json`. Ejecutar `pnpm build` después de clonar o si falta `dist`; los comandos de validación completos ya lo hacen. Si el editor conserva diagnósticos anteriores después del build, reiniciar su servidor de TypeScript.
228
232
 
229
- El compilador `tsc` es TypeScript 7. Para `typescript-eslint`, se mantiene la [API de compatibilidad oficial de TypeScript 6](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0) mediante un alias; no reemplaza el compilador de los typechecks.
233
+ El compilador `tsc` es TypeScript 7. El paquete `typescript` apunta a la [API de compatibilidad oficial de TypeScript 6](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/#running-side-by-side-with-typescript-6.0) mediante un alias, porque el plugin de docgen de Storybook lo declara como dependencia peer; no reemplaza el compilador de los typechecks. El lint no depende de él: oxlint analiza TypeScript sin el compilador.
230
234
 
231
235
  ## Crear y publicar una versión
232
236
 
@@ -10,7 +10,7 @@ export interface AccountMenuLabels {
10
10
  export interface AccountMenuClassNames {
11
11
  trigger?: string;
12
12
  triggerAvatar?: string;
13
- /** Name and email block of the `sidebar` trigger, for example to hide it in a collapsed sidebar. */
13
+ /** Name and email block of the `sidebar` trigger; it already leaves the icon rail of a collapsed `Sidebar`. */
14
14
  triggerText?: string;
15
15
  triggerName?: string;
16
16
  triggerEmail?: string;
@@ -40,7 +40,10 @@ export interface AccountMenuProps {
40
40
  onSignIn?: () => void;
41
41
  /** Navigates to a sign-in page through the configured router adapter instead of calling `onSignIn`. */
42
42
  signInHref?: string;
43
- /** `avatar` shows only the avatar; `sidebar` also shows name, email and a chevron. */
43
+ /**
44
+ * `avatar` shows only the avatar; `sidebar` also shows name, email and a chevron, and inside the
45
+ * icon rail of a collapsed `Sidebar` shrinks to the centered avatar.
46
+ */
44
47
  triggerVariant?: "avatar" | "sidebar";
45
48
  /** Adds a connected/disconnected badge to the avatar and greys it out while signed out. */
46
49
  showStatusBadge?: boolean;
@@ -6,6 +6,7 @@ import { getNameInitials } from "../lib/name-initials.js";
6
6
  import { Avatar, AvatarBadge, AvatarFallback, AvatarImage } from "./avatar.js";
7
7
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "./dropdown-menu.js";
8
8
  import { Link } from "./link.js";
9
+ import { useOptionalSidebarPanel } from "./sidebar-panel-context.js";
9
10
  import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
10
11
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
12
  const ACCOUNT_MENU_DEFAULT_LABELS = {
@@ -105,7 +106,7 @@ function AccountAvatar(t0) {
105
106
  * @returns The trigger and its menu.
106
107
  */
107
108
  export function AccountMenu(t0) {
108
- const $ = _c(79);
109
+ const $ = _c(80);
109
110
  const { name, email, status, image: t1, avatarFallback, onSignOut, signOutDisabled: t2, onSignIn, signInHref, triggerVariant: t3, showStatusBadge: t4, tooltipLabel, labels, classNames, align: t5, side: t6, sideOffset: t7, children } = t0;
110
111
  const image = t1 === undefined ? null : t1;
111
112
  const signOutDisabled = t2 === undefined ? false : t2;
@@ -158,34 +159,38 @@ export function AccountMenu(t0) {
158
159
  t10 = $[11];
159
160
  }
160
161
  const avatarProps = t10;
162
+ const sidebarPanel = useOptionalSidebarPanel();
163
+ const showsSidebarIdentity = triggerVariant === "sidebar" && !sidebarPanel?.collapsed;
161
164
  const t11 = resolvedLabels.trigger;
162
165
  const t12 = triggerVariant === "sidebar" && "w-full min-w-0 gap-2.5 rounded-lg p-1.5 text-left";
163
- const t13 = classNames?.trigger;
164
- let t14;
165
- if ($[12] !== t12 || $[13] !== t13) {
166
- t14 = cn("inline-flex items-center rounded-full outline-none [-webkit-tap-highlight-color:transparent] transition-[box-shadow,opacity,transform] hover:opacity-90 active:scale-[0.96] focus-visible:shadow-[0_0_0_2px_var(--background),0_0_0_4px_var(--ring)] data-[state=open]:shadow-[0_0_0_2px_var(--background),0_0_0_4px_var(--ring)]", t12, t13);
166
+ const t13 = triggerVariant === "sidebar" && !showsSidebarIdentity && "justify-center gap-0";
167
+ const t14 = classNames?.trigger;
168
+ let t15;
169
+ if ($[12] !== t12 || $[13] !== t13 || $[14] !== t14) {
170
+ t15 = cn("inline-flex items-center rounded-full outline-none [-webkit-tap-highlight-color:transparent] transition-[box-shadow,opacity,transform] hover:opacity-90 active:scale-[0.96] focus-visible:shadow-[0_0_0_2px_var(--background),0_0_0_4px_var(--ring)] data-[state=open]:shadow-[0_0_0_2px_var(--background),0_0_0_4px_var(--ring)]", t12, t13, t14);
167
171
  $[12] = t12;
168
172
  $[13] = t13;
169
173
  $[14] = t14;
174
+ $[15] = t15;
170
175
  } else {
171
- t14 = $[14];
176
+ t15 = $[15];
172
177
  }
173
- const t15 = classNames?.triggerAvatar;
174
- let t16;
175
- if ($[15] !== avatarProps || $[16] !== t15) {
176
- t16 = /* @__PURE__ */ _jsx(AccountAvatar, {
178
+ const t16 = classNames?.triggerAvatar;
179
+ let t17;
180
+ if ($[16] !== avatarProps || $[17] !== t16) {
181
+ t17 = /* @__PURE__ */ _jsx(AccountAvatar, {
177
182
  ...avatarProps,
178
- className: t15
183
+ className: t16
179
184
  });
180
- $[15] = avatarProps;
181
- $[16] = t15;
185
+ $[16] = avatarProps;
182
186
  $[17] = t16;
187
+ $[18] = t17;
183
188
  } else {
184
- t16 = $[17];
189
+ t17 = $[18];
185
190
  }
186
- let t17;
187
- if ($[18] !== classNames?.triggerChevron || $[19] !== classNames?.triggerEmail || $[20] !== classNames?.triggerName || $[21] !== classNames?.triggerText || $[22] !== email || $[23] !== name || $[24] !== triggerVariant) {
188
- t17 = triggerVariant === "sidebar" ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsxs("span", {
191
+ let t18;
192
+ if ($[19] !== classNames?.triggerChevron || $[20] !== classNames?.triggerEmail || $[21] !== classNames?.triggerName || $[22] !== classNames?.triggerText || $[23] !== email || $[24] !== name || $[25] !== showsSidebarIdentity) {
193
+ t18 = showsSidebarIdentity ? /* @__PURE__ */ _jsxs(_Fragment, { children: [/* @__PURE__ */ _jsxs("span", {
189
194
  className: cn("grid min-w-0 flex-1", classNames?.triggerText),
190
195
  children: [/* @__PURE__ */ _jsx("span", {
191
196
  className: cn("truncate text-sm font-semibold", classNames?.triggerName),
@@ -198,142 +203,142 @@ export function AccountMenu(t0) {
198
203
  "aria-hidden": "true",
199
204
  className: cn("size-4 shrink-0 text-muted-foreground", classNames?.triggerChevron)
200
205
  })] }) : null;
201
- $[18] = classNames?.triggerChevron;
202
- $[19] = classNames?.triggerEmail;
203
- $[20] = classNames?.triggerName;
204
- $[21] = classNames?.triggerText;
205
- $[22] = email;
206
- $[23] = name;
207
- $[24] = triggerVariant;
208
- $[25] = t17;
206
+ $[19] = classNames?.triggerChevron;
207
+ $[20] = classNames?.triggerEmail;
208
+ $[21] = classNames?.triggerName;
209
+ $[22] = classNames?.triggerText;
210
+ $[23] = email;
211
+ $[24] = name;
212
+ $[25] = showsSidebarIdentity;
213
+ $[26] = t18;
209
214
  } else {
210
- t17 = $[25];
215
+ t18 = $[26];
211
216
  }
212
- let t18;
213
- if ($[26] !== resolvedLabels.trigger || $[27] !== t14 || $[28] !== t16 || $[29] !== t17 || $[30] !== triggerVariant) {
217
+ let t19;
218
+ if ($[27] !== resolvedLabels.trigger || $[28] !== t15 || $[29] !== t17 || $[30] !== t18 || $[31] !== triggerVariant) {
214
219
  const triggerButton = /* @__PURE__ */ _jsxs("button", {
215
220
  "data-slot": "account-menu-trigger",
216
221
  "data-variant": triggerVariant,
217
222
  "aria-label": t11,
218
223
  type: "button",
219
- className: t14,
220
- children: [t16, t17]
224
+ className: t15,
225
+ children: [t17, t18]
221
226
  });
222
- t18 = /* @__PURE__ */ _jsx(DropdownMenuTrigger, {
227
+ t19 = /* @__PURE__ */ _jsx(DropdownMenuTrigger, {
223
228
  asChild: true,
224
229
  children: triggerButton
225
230
  });
226
- $[26] = resolvedLabels.trigger;
227
- $[27] = t14;
228
- $[28] = t16;
231
+ $[27] = resolvedLabels.trigger;
232
+ $[28] = t15;
229
233
  $[29] = t17;
230
- $[30] = triggerVariant;
231
- $[31] = t18;
234
+ $[30] = t18;
235
+ $[31] = triggerVariant;
236
+ $[32] = t19;
232
237
  } else {
233
- t18 = $[31];
238
+ t19 = $[32];
234
239
  }
235
- const trigger = t18;
236
- let t19;
237
- if ($[32] !== tooltipLabel || $[33] !== trigger) {
238
- t19 = tooltipLabel ? /* @__PURE__ */ _jsx(TooltipTrigger, {
240
+ const trigger = t19;
241
+ let t20;
242
+ if ($[33] !== tooltipLabel || $[34] !== trigger) {
243
+ t20 = tooltipLabel ? /* @__PURE__ */ _jsx(TooltipTrigger, {
239
244
  asChild: true,
240
245
  children: trigger
241
246
  }) : trigger;
242
- $[32] = tooltipLabel;
243
- $[33] = trigger;
244
- $[34] = t19;
247
+ $[33] = tooltipLabel;
248
+ $[34] = trigger;
249
+ $[35] = t20;
245
250
  } else {
246
- t19 = $[34];
251
+ t20 = $[35];
247
252
  }
248
- const t20 = classNames?.content;
249
- let t21;
250
- if ($[35] !== t20) {
251
- t21 = cn("min-w-56", t20);
252
- $[35] = t20;
253
+ const t21 = classNames?.content;
254
+ let t22;
255
+ if ($[36] !== t21) {
256
+ t22 = cn("min-w-56", t21);
253
257
  $[36] = t21;
258
+ $[37] = t22;
254
259
  } else {
255
- t21 = $[36];
260
+ t22 = $[37];
256
261
  }
257
- const t22 = classNames?.header;
258
- let t23;
259
- if ($[37] !== t22) {
260
- t23 = cn("grid grid-cols-[auto_minmax(0,1fr)] items-center gap-2.5 px-2 py-1.5", t22);
261
- $[37] = t22;
262
+ const t23 = classNames?.header;
263
+ let t24;
264
+ if ($[38] !== t23) {
265
+ t24 = cn("grid grid-cols-[auto_minmax(0,1fr)] items-center gap-2.5 px-2 py-1.5", t23);
262
266
  $[38] = t23;
267
+ $[39] = t24;
263
268
  } else {
264
- t23 = $[38];
269
+ t24 = $[39];
265
270
  }
266
- const t24 = classNames?.headerAvatar;
267
- let t25;
268
- if ($[39] !== avatarProps || $[40] !== t24) {
269
- t25 = /* @__PURE__ */ _jsx(AccountAvatar, {
271
+ const t25 = classNames?.headerAvatar;
272
+ let t26;
273
+ if ($[40] !== avatarProps || $[41] !== t25) {
274
+ t26 = /* @__PURE__ */ _jsx(AccountAvatar, {
270
275
  ...avatarProps,
271
276
  isDecorative: true,
272
- className: t24
277
+ className: t25
273
278
  });
274
- $[39] = avatarProps;
275
- $[40] = t24;
279
+ $[40] = avatarProps;
276
280
  $[41] = t25;
281
+ $[42] = t26;
277
282
  } else {
278
- t25 = $[41];
283
+ t26 = $[42];
279
284
  }
280
- let t26;
281
- if ($[42] !== name) {
282
- t26 = /* @__PURE__ */ _jsx("span", {
285
+ let t27;
286
+ if ($[43] !== name) {
287
+ t27 = /* @__PURE__ */ _jsx("span", {
283
288
  className: "truncate text-sm leading-tight font-semibold",
284
289
  children: name
285
290
  });
286
- $[42] = name;
287
- $[43] = t26;
291
+ $[43] = name;
292
+ $[44] = t27;
288
293
  } else {
289
- t26 = $[43];
294
+ t27 = $[44];
290
295
  }
291
- let t27;
292
- if ($[44] !== email) {
293
- t27 = /* @__PURE__ */ _jsx("span", {
296
+ let t28;
297
+ if ($[45] !== email) {
298
+ t28 = /* @__PURE__ */ _jsx("span", {
294
299
  className: "truncate text-xs leading-tight text-muted-foreground",
295
300
  children: email
296
301
  });
297
- $[44] = email;
298
- $[45] = t27;
302
+ $[45] = email;
303
+ $[46] = t28;
299
304
  } else {
300
- t27 = $[45];
305
+ t28 = $[46];
301
306
  }
302
- let t28;
303
- if ($[46] !== t26 || $[47] !== t27) {
304
- t28 = /* @__PURE__ */ _jsxs("span", {
307
+ let t29;
308
+ if ($[47] !== t27 || $[48] !== t28) {
309
+ t29 = /* @__PURE__ */ _jsxs("span", {
305
310
  className: "grid min-w-0 gap-px",
306
- children: [t26, t27]
311
+ children: [t27, t28]
307
312
  });
308
- $[46] = t26;
309
313
  $[47] = t27;
310
314
  $[48] = t28;
315
+ $[49] = t29;
311
316
  } else {
312
- t28 = $[48];
317
+ t29 = $[49];
313
318
  }
314
- let t29;
315
- if ($[49] !== t23 || $[50] !== t25 || $[51] !== t28) {
316
- t29 = /* @__PURE__ */ _jsxs("div", {
317
- className: t23,
318
- children: [t25, t28]
319
+ let t30;
320
+ if ($[50] !== t24 || $[51] !== t26 || $[52] !== t29) {
321
+ t30 = /* @__PURE__ */ _jsxs("div", {
322
+ className: t24,
323
+ children: [t26, t29]
319
324
  });
320
- $[49] = t23;
321
- $[50] = t25;
322
- $[51] = t28;
325
+ $[50] = t24;
326
+ $[51] = t26;
323
327
  $[52] = t29;
324
- } else {
325
- t29 = $[52];
326
- }
327
- let t30;
328
- if ($[53] === Symbol.for("react.memo_cache_sentinel")) {
329
- t30 = /* @__PURE__ */ _jsx(DropdownMenuSeparator, {});
330
328
  $[53] = t30;
331
329
  } else {
332
330
  t30 = $[53];
333
331
  }
334
332
  let t31;
335
- if ($[54] !== classNames?.item || $[55] !== isAuthenticated || $[56] !== onSignIn || $[57] !== onSignOut || $[58] !== resolvedLabels.signIn || $[59] !== resolvedLabels.signOut || $[60] !== signInHref || $[61] !== signOutDisabled) {
336
- t31 = isAuthenticated ? /* @__PURE__ */ _jsxs(DropdownMenuItem, {
333
+ if ($[54] === Symbol.for("react.memo_cache_sentinel")) {
334
+ t31 = /* @__PURE__ */ _jsx(DropdownMenuSeparator, {});
335
+ $[54] = t31;
336
+ } else {
337
+ t31 = $[54];
338
+ }
339
+ let t32;
340
+ if ($[55] !== classNames?.item || $[56] !== isAuthenticated || $[57] !== onSignIn || $[58] !== onSignOut || $[59] !== resolvedLabels.signIn || $[60] !== resolvedLabels.signOut || $[61] !== signInHref || $[62] !== signOutDisabled) {
341
+ t32 = isAuthenticated ? /* @__PURE__ */ _jsxs(DropdownMenuItem, {
337
342
  className: classNames?.item,
338
343
  disabled: signOutDisabled,
339
344
  onSelect: () => void onSignOut(),
@@ -350,77 +355,77 @@ export function AccountMenu(t0) {
350
355
  onSelect: () => onSignIn?.(),
351
356
  children: [/* @__PURE__ */ _jsx(LogInIcon, { "aria-hidden": "true" }), resolvedLabels.signIn]
352
357
  });
353
- $[54] = classNames?.item;
354
- $[55] = isAuthenticated;
355
- $[56] = onSignIn;
356
- $[57] = onSignOut;
357
- $[58] = resolvedLabels.signIn;
358
- $[59] = resolvedLabels.signOut;
359
- $[60] = signInHref;
360
- $[61] = signOutDisabled;
361
- $[62] = t31;
358
+ $[55] = classNames?.item;
359
+ $[56] = isAuthenticated;
360
+ $[57] = onSignIn;
361
+ $[58] = onSignOut;
362
+ $[59] = resolvedLabels.signIn;
363
+ $[60] = resolvedLabels.signOut;
364
+ $[61] = signInHref;
365
+ $[62] = signOutDisabled;
366
+ $[63] = t32;
362
367
  } else {
363
- t31 = $[62];
368
+ t32 = $[63];
364
369
  }
365
- let t32;
366
- if ($[63] !== align || $[64] !== children || $[65] !== side || $[66] !== sideOffset || $[67] !== t21 || $[68] !== t29 || $[69] !== t31) {
367
- t32 = /* @__PURE__ */ _jsxs(DropdownMenuContent, {
370
+ let t33;
371
+ if ($[64] !== align || $[65] !== children || $[66] !== side || $[67] !== sideOffset || $[68] !== t22 || $[69] !== t30 || $[70] !== t32) {
372
+ t33 = /* @__PURE__ */ _jsxs(DropdownMenuContent, {
368
373
  "data-slot": "account-menu-content",
369
374
  align,
370
375
  side,
371
376
  sideOffset,
372
- className: t21,
377
+ className: t22,
373
378
  children: [
374
- t29,
375
379
  t30,
380
+ t31,
376
381
  children,
377
- t31
382
+ t32
378
383
  ]
379
384
  });
380
- $[63] = align;
381
- $[64] = children;
382
- $[65] = side;
383
- $[66] = sideOffset;
384
- $[67] = t21;
385
- $[68] = t29;
386
- $[69] = t31;
385
+ $[64] = align;
386
+ $[65] = children;
387
+ $[66] = side;
388
+ $[67] = sideOffset;
389
+ $[68] = t22;
390
+ $[69] = t30;
387
391
  $[70] = t32;
392
+ $[71] = t33;
388
393
  } else {
389
- t32 = $[70];
394
+ t33 = $[71];
390
395
  }
391
- let t33;
392
- if ($[71] !== t19 || $[72] !== t32) {
393
- t33 = /* @__PURE__ */ _jsxs(DropdownMenu, { children: [t19, t32] });
394
- $[71] = t19;
395
- $[72] = t32;
396
+ let t34;
397
+ if ($[72] !== t20 || $[73] !== t33) {
398
+ t34 = /* @__PURE__ */ _jsxs(DropdownMenu, { children: [t20, t33] });
399
+ $[72] = t20;
396
400
  $[73] = t33;
401
+ $[74] = t34;
397
402
  } else {
398
- t33 = $[73];
403
+ t34 = $[74];
399
404
  }
400
- const menu = t33;
405
+ const menu = t34;
401
406
  if (!tooltipLabel) {
402
407
  return menu;
403
408
  }
404
- let t34;
405
- if ($[74] !== tooltipLabel) {
406
- t34 = /* @__PURE__ */ _jsx(TooltipContent, {
409
+ let t35;
410
+ if ($[75] !== tooltipLabel) {
411
+ t35 = /* @__PURE__ */ _jsx(TooltipContent, {
407
412
  side: "bottom",
408
413
  sideOffset: 8,
409
414
  children: tooltipLabel
410
415
  });
411
- $[74] = tooltipLabel;
412
- $[75] = t34;
416
+ $[75] = tooltipLabel;
417
+ $[76] = t35;
413
418
  } else {
414
- t34 = $[75];
419
+ t35 = $[76];
415
420
  }
416
- let t35;
417
- if ($[76] !== menu || $[77] !== t34) {
418
- t35 = /* @__PURE__ */ _jsxs(Tooltip, { children: [menu, t34] });
419
- $[76] = menu;
420
- $[77] = t34;
421
+ let t36;
422
+ if ($[77] !== menu || $[78] !== t35) {
423
+ t36 = /* @__PURE__ */ _jsxs(Tooltip, { children: [menu, t35] });
424
+ $[77] = menu;
421
425
  $[78] = t35;
426
+ $[79] = t36;
422
427
  } else {
423
- t35 = $[78];
428
+ t36 = $[79];
424
429
  }
425
- return t35;
430
+ return t36;
426
431
  }
@@ -1,5 +1,5 @@
1
1
  /** Cross-fades between states of the same region, such as idle, loading and result. */
2
- import type { ReactNode } from "react";
2
+ import { type ReactNode } from "react";
3
3
  declare const PRESENCE_SWAP_ELEMENTS: {
4
4
  readonly div: import("motion/react").ForwardRefComponent<HTMLDivElement, import("motion/react").HTMLMotionProps<"div">>;
5
5
  readonly span: import("motion/react").ForwardRefComponent<HTMLSpanElement, import("motion/react").HTMLMotionProps<"span">>;
@@ -1,5 +1,7 @@
1
1
  "use client";
2
2
  import { c as _c } from "react/compiler-runtime";
3
+ /** Cross-fades between states of the same region, such as idle, loading and result. */
4
+ import { useState } from "react";
3
5
  import { AnimatePresence, motion, useIsPresent } from "motion/react";
4
6
  import { usePrefersReducedMotion } from "../hooks/use-prefers-reduced-motion.js";
5
7
  import { cn } from "../lib/utils.js";
@@ -20,8 +22,12 @@ function PresenceSwapItem(t0) {
20
22
  const { as, className, children } = t0;
21
23
  const MotionElement = PRESENCE_SWAP_ELEMENTS[as];
22
24
  const isPresent = useIsPresent();
25
+ const [isMountedExiting] = useState(!isPresent);
23
26
  const shouldReduceMotion = usePrefersReducedMotion();
24
27
  const distance = shouldReduceMotion ? 0 : MOTION_CONTENT_DISTANCE;
28
+ if (isMountedExiting) {
29
+ return null;
30
+ }
25
31
  const t1 = isPresent ? undefined : true;
26
32
  const t2 = !isPresent || undefined;
27
33
  let t3;
@@ -98,6 +104,47 @@ function PresenceSwapItem(t0) {
98
104
  return t8;
99
105
  }
100
106
  /**
107
+ * Gives every key change its own presence key. Motion keeps the exit bookkeeping of a key that
108
+ * already left, so a reused key (loading → error → loading) mounted already exiting would have
109
+ * its removal ignored and stall a `wait` swap forever.
110
+ * @param presenceKey - Key identifying the current state.
111
+ * @returns A key that is never reused within this swap.
112
+ */
113
+ function usePresenceSwapKey(presenceKey) {
114
+ const $ = _c(5);
115
+ let t0;
116
+ if ($[0] !== presenceKey) {
117
+ t0 = {
118
+ presenceKey,
119
+ generation: 0
120
+ };
121
+ $[0] = presenceKey;
122
+ $[1] = t0;
123
+ } else {
124
+ t0 = $[1];
125
+ }
126
+ const [current, setCurrent] = useState(t0);
127
+ if (current.presenceKey !== presenceKey) {
128
+ const t1 = current.generation + 1;
129
+ let t2;
130
+ if ($[2] !== presenceKey || $[3] !== t1) {
131
+ t2 = {
132
+ presenceKey,
133
+ generation: t1
134
+ };
135
+ $[2] = presenceKey;
136
+ $[3] = t1;
137
+ $[4] = t2;
138
+ } else {
139
+ t2 = $[4];
140
+ }
141
+ const next = t2;
142
+ setCurrent(next);
143
+ return `${next.generation}:${presenceKey}`;
144
+ }
145
+ return `${current.generation}:${presenceKey}`;
146
+ }
147
+ /**
101
148
  * Swaps keyed content with a short lift-and-fade; the first render is not animated.
102
149
  * @param props - Key identifying the current state and its content.
103
150
  * @returns The animated content.
@@ -107,6 +154,7 @@ export function PresenceSwap(t0) {
107
154
  const { presenceKey, children, as: t1, className, mode: t2 } = t0;
108
155
  const as = t1 === undefined ? "div" : t1;
109
156
  const mode = t2 === undefined ? "wait" : t2;
157
+ const itemKey = usePresenceSwapKey(presenceKey);
110
158
  const t3 = as === "span" && "inline-flex items-center";
111
159
  let t4;
112
160
  if ($[0] !== className || $[1] !== t3) {
@@ -118,15 +166,15 @@ export function PresenceSwap(t0) {
118
166
  t4 = $[2];
119
167
  }
120
168
  let t5;
121
- if ($[3] !== as || $[4] !== children || $[5] !== presenceKey || $[6] !== t4) {
169
+ if ($[3] !== as || $[4] !== children || $[5] !== itemKey || $[6] !== t4) {
122
170
  t5 = /* @__PURE__ */ _jsx(PresenceSwapItem, {
123
171
  as,
124
172
  className: t4,
125
173
  children
126
- }, presenceKey);
174
+ }, itemKey);
127
175
  $[3] = as;
128
176
  $[4] = children;
129
- $[5] = presenceKey;
177
+ $[5] = itemKey;
130
178
  $[6] = t4;
131
179
  $[7] = t5;
132
180
  } else {
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Internal: panel state shared by the sidebar parts and by components that adapt to the icon rail
3
+ * (such as `AccountMenu`), kept apart so they can read it without importing the sidebar itself.
4
+ */
5
+ import * as React from "react";
6
+ export type SidebarPanelState = {
7
+ /** Whether the desktop sidebar is shrunk to its icon rail; always false in the mobile sheet. */
8
+ collapsed: boolean;
9
+ collapsible: "offcanvas" | "icon" | "none";
10
+ side: "left" | "right";
11
+ };
12
+ export declare const SidebarPanelContext: React.Context<SidebarPanelState | null>;
13
+ /**
14
+ * Reads the panel state when rendered inside a `Sidebar`, and `null` anywhere else.
15
+ * @returns The panel state, or `null` outside a sidebar.
16
+ */
17
+ export declare function useOptionalSidebarPanel(): SidebarPanelState | null;
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ /**
3
+ * Internal: panel state shared by the sidebar parts and by components that adapt to the icon rail
4
+ * (such as `AccountMenu`), kept apart so they can read it without importing the sidebar itself.
5
+ */
6
+ import * as React from "react";
7
+ export const SidebarPanelContext = React.createContext(null);
8
+ /**
9
+ * Reads the panel state when rendered inside a `Sidebar`, and `null` anywhere else.
10
+ * @returns The panel state, or `null` outside a sidebar.
11
+ */
12
+ export function useOptionalSidebarPanel() {
13
+ return React.use(SidebarPanelContext);
14
+ }