@beweco/aurora-ui 1.0.0-beta.151 → 1.0.0-beta.155

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/dist/index.cjs.js CHANGED
@@ -8113,9 +8113,30 @@ const MenuComponent = $8WNJc$react.memo(function Menu({ commerceInfo, userInfo,
8113
8113
  color: "default", className: " text-default-500 data-[hovered=true]:text-default-600", startContent: jsxRuntime.jsx(IconComponent, { className: "text-default-500", icon: "solar:info-circle-line-duotone", size: "md" }), variant: "light", onPress: handleHelpClick, isIconOnly: isCollapsed, children: !isCollapsed && (jsxRuntime.jsx("span", { className: "collapsible-item truncate", children: helpSection.title })) }) })) : null] }) })] }));
8114
8114
  });
8115
8115
 
8116
+ /**
8117
+ * «Cargar más» solo se ofrece si hay otra página, alguien que pueda pedirla y la lista
8118
+ * ya enseña todo lo recibido (desplegada, o sin ítems plegados tras «Ver más»).
8119
+ */
8120
+ function isLoadMoreVisible({ hasMore, hasOnLoadMore, isExpanded, hasHiddenItems, }) {
8121
+ return hasMore && hasOnLoadMore && (isExpanded || !hasHiddenItems);
8122
+ }
8123
+ /**
8124
+ * Pulsación de «Cargar más». Con una página en vuelo no hace nada: el botón no usa
8125
+ * `disabled` nativo (perdería el foco del teclado), así que la guarda vive aquí.
8126
+ * Si no, despliega la lista y pide la página, para que lo nuevo no quede tras «Ver más».
8127
+ */
8128
+ function pressLoadMore({ isLoadingMore, onLoadMore, expand, }) {
8129
+ if (isLoadingMore) {
8130
+ return;
8131
+ }
8132
+ expand();
8133
+ onLoadMore();
8134
+ }
8135
+
8116
8136
  /**
8117
8137
  * Sección de historial de conversaciones: botón de nueva conversación + lista de
8118
- * entradas recientes con "ver más".
8138
+ * entradas recientes con "ver más" y, si el consumidor tiene más páginas,
8139
+ * "cargar más".
8119
8140
  *
8120
8141
  * La lista tiene **scroll interno propio** (`flex-1 min-h-0 overflow-y-auto`) y
8121
8142
  * la sección está acotada en altura, para que crecer el historial no arrastre ni
@@ -8134,7 +8155,7 @@ const MenuComponent = $8WNJc$react.memo(function Menu({ commerceInfo, userInfo,
8134
8155
  * gana a sus `--button-*` porque las utilidades van en una capa posterior a la de
8135
8156
  * `.button`.
8136
8157
  */
8137
- const MenuClawHistoryPanel = $8WNJc$react.memo(function MenuClawHistoryPanel({ items, initialVisibleCount, onNewConversation, isCollapsed, title, newLabel, showMoreLabel, showLessLabel, onBeforeSelect, }) {
8158
+ const MenuClawHistoryPanel = $8WNJc$react.memo(function MenuClawHistoryPanel({ items, initialVisibleCount, onNewConversation, hasMore, onLoadMore, isLoadingMore, loadMoreLabel, isCollapsed, title, newLabel, showMoreLabel, showLessLabel, onBeforeSelect, }) {
8138
8159
  const [isExpanded, setIsExpanded] = $8WNJc$react.useState(false);
8139
8160
  const visibleItems = $8WNJc$react.useMemo(() => (isExpanded ? items : items.slice(0, initialVisibleCount)), [isExpanded, items, initialVisibleCount]);
8140
8161
  const hasHiddenItems = items.length > initialVisibleCount;
@@ -8161,7 +8182,17 @@ const MenuClawHistoryPanel = $8WNJc$react.memo(function MenuClawHistoryPanel({ i
8161
8182
  ? "cursor-not-allowed opacity-50"
8162
8183
  : "hover:bg-default-100"), children: [jsxRuntime.jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center text-default-400", children: jsxRuntime.jsx(IconComponent, { icon: "solar:chat-round-dots-linear", size: "md", "aria-hidden": true }) }), jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [jsxRuntime.jsx("span", { className: "truncate", children: item.title }), item.meta ? (jsxRuntime.jsx("span", { className: "truncate text-xs text-default-400", children: item.meta })) : null] })] }) }, item.id))) }), hasHiddenItems ? (jsxRuntime.jsxs("button", { type: "button", onClick: handleToggleExpand, "aria-expanded": isExpanded, className: "flex w-full shrink-0 items-center gap-1.5 rounded-lg px-2 py-2 text-xs font-medium text-default-500 transition-colors hover:bg-default-100 hover:text-default-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus", children: [jsxRuntime.jsx(IconComponent, { icon: isExpanded
8163
8184
  ? "solar:alt-arrow-up-linear"
8164
- : "solar:alt-arrow-down-linear", size: "sm", "aria-hidden": true }), isExpanded ? showLessLabel : showMoreLabel] })) : null] })) : null] }));
8185
+ : "solar:alt-arrow-down-linear", size: "sm", "aria-hidden": true }), isExpanded ? showLessLabel : showMoreLabel] })) : null, onLoadMore &&
8186
+ isLoadMoreVisible({
8187
+ hasMore,
8188
+ hasOnLoadMore: true,
8189
+ isExpanded,
8190
+ hasHiddenItems,
8191
+ }) ? (jsxRuntime.jsxs("button", { type: "button", onClick: () => pressLoadMore({
8192
+ isLoadingMore,
8193
+ onLoadMore,
8194
+ expand: () => setIsExpanded(true),
8195
+ }), "aria-disabled": isLoadingMore, "aria-busy": isLoadingMore, className: "flex w-full shrink-0 items-center gap-1.5 rounded-lg px-2 py-2 text-xs font-medium text-default-500 transition-colors hover:bg-default-100 hover:text-default-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus aria-disabled:cursor-not-allowed aria-disabled:opacity-50", children: [jsxRuntime.jsx(IconComponent, { icon: "solar:add-circle-linear", size: "sm", "aria-hidden": true }), loadMoreLabel] })) : null] })) : null] }));
8165
8196
  });
8166
8197
 
8167
8198
  /** ¿Está la key seleccionada en este ítem o en cualquiera de sus descendientes? */
@@ -8225,6 +8256,7 @@ const DEFAULT_TRANSLATIONS$a = {
8225
8256
  historyNewLabel: "Nueva conversación",
8226
8257
  historyShowMoreLabel: "Ver más",
8227
8258
  historyShowLessLabel: "Ver menos",
8259
+ historyLoadMoreLabel: "Cargar más",
8228
8260
  };
8229
8261
  /** Ítems del historial visibles antes de pulsar "ver más". */
8230
8262
  const DEFAULT_HISTORY_VISIBLE_COUNT = 5;
@@ -8283,7 +8315,12 @@ const MenuClaw = $8WNJc$react.memo(function MenuClaw({ userInfo, helpButton, men
8283
8315
  const initialVisibleCount = typeof rawCount === "number" && Number.isFinite(rawCount) && rawCount > 0
8284
8316
  ? Math.floor(rawCount)
8285
8317
  : DEFAULT_HISTORY_VISIBLE_COUNT;
8286
- return { items, initialVisibleCount };
8318
+ return {
8319
+ items,
8320
+ initialVisibleCount,
8321
+ hasMore: history?.hasMore === true,
8322
+ isLoadingMore: history?.isLoadingMore === true,
8323
+ };
8287
8324
  }, [history]);
8288
8325
  const bottomBarItems = $8WNJc$react.useMemo(() => {
8289
8326
  if (!mobileBottomBarGroupKey) {
@@ -8328,7 +8365,7 @@ const MenuClaw = $8WNJc$react.memo(function MenuClaw({ userInfo, helpButton, men
8328
8365
  ? "solar:alt-arrow-right-linear"
8329
8366
  : "solar:alt-arrow-left-linear", size: "md", "aria-hidden": true }) })] }), jsxRuntime.jsxs("div", { className: cn("flex items-center py-3", collapsed ? "justify-center gap-0" : "gap-3"), children: [jsxRuntime.jsxs(react.Avatar, { size: "sm", className: "shrink-0", children: [userInfo?.avatar?.trim() ? (jsxRuntime.jsx(react.Avatar.Image, { src: userInfo.avatar, alt: userName })) : null, jsxRuntime.jsx(react.Avatar.Fallback, { className: userInfo?.avatar?.trim()
8330
8367
  ? undefined
8331
- : "bg-warning text-warning-foreground", children: getUserInitials(userName) })] }), !collapsed ? (jsxRuntime.jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: userName }), jsxRuntime.jsx("p", { className: "truncate text-xs text-default-400", children: userRole })] })) : null] }), jsxRuntime.jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history?.onNewConversation, isCollapsed: collapsed, title: t.historyTitle, newLabel: t.historyNewLabel, showMoreLabel: t.historyShowMoreLabel, showLessLabel: t.historyShowLessLabel, onBeforeSelect: handleSidebarClose }), jsxRuntime.jsx("nav", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: menuItems.items.map((group) => (jsxRuntime.jsxs("div", { className: "mb-2", children: [group.title && !collapsed ? (jsxRuntime.jsx("p", { className: "px-2 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5", children: (group.items ?? []).map((item) => (jsxRuntime.jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: collapsed, onSelect: handleMenuSelect }, item.key))) })] }, group.key))) }), helpSection ? (jsxRuntime.jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsxRuntime.jsx(Button, { fullWidth: true,
8368
+ : "bg-warning text-warning-foreground", children: getUserInitials(userName) })] }), !collapsed ? (jsxRuntime.jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsxRuntime.jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: userName }), jsxRuntime.jsx("p", { className: "truncate text-xs text-default-400", children: userRole })] })) : null] }), jsxRuntime.jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history?.onNewConversation, hasMore: historyConfig.hasMore, onLoadMore: history?.onLoadMore, isLoadingMore: historyConfig.isLoadingMore, isCollapsed: collapsed, title: t.historyTitle, newLabel: t.historyNewLabel, showMoreLabel: t.historyShowMoreLabel, showLessLabel: t.historyShowLessLabel, loadMoreLabel: t.historyLoadMoreLabel, onBeforeSelect: handleSidebarClose }), jsxRuntime.jsx("nav", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: menuItems.items.map((group) => (jsxRuntime.jsxs("div", { className: "mb-2", children: [group.title && !collapsed ? (jsxRuntime.jsx("p", { className: "px-2 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5", children: (group.items ?? []).map((item) => (jsxRuntime.jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: collapsed, onSelect: handleMenuSelect }, item.key))) })] }, group.key))) }), helpSection ? (jsxRuntime.jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsxRuntime.jsx(Button, { fullWidth: true,
8332
8369
  // TECH-2459 · G2 — la fachada propia de `Button` (D-G4-1) pinta
8333
8370
  // `color="primary"` por defecto; el crudo de v2 pintaba "default"
8334
8371
  // (gris). Se fija explícito para no teñir de azul un botón neutro.
@@ -12221,7 +12258,7 @@ function measureTextareaHeight(node, minRows, maxRows) {
12221
12258
  };
12222
12259
  }
12223
12260
  // `useLayoutEffect` en el servidor avisa en React 18; el alto solo tiene sentido en el cliente.
12224
- const useIsomorphicLayoutEffect = typeof window !== "undefined" ? $8WNJc$react.useLayoutEffect : $8WNJc$react.useEffect;
12261
+ const useIsomorphicLayoutEffect$1 = typeof window !== "undefined" ? $8WNJc$react.useLayoutEffect : $8WNJc$react.useEffect;
12225
12262
  /**
12226
12263
  * Autocrecimiento del `<textarea>` apuntado por `nodeRef`. Devuelve el `resize` para llamarlo
12227
12264
  * desde el `onChange` de la fachada.
@@ -12251,11 +12288,11 @@ function useTextareaAutosize(nodeRef, { enabled, minRows, maxRows }) {
12251
12288
  const resizeRef = $8WNJc$react.useRef(resize);
12252
12289
  resizeRef.current = resize;
12253
12290
  // Cada render, como v2: el valor controlado, el `size` o la clase pueden haber cambiado.
12254
- useIsomorphicLayoutEffect(() => {
12291
+ useIsomorphicLayoutEffect$1(() => {
12255
12292
  resize();
12256
12293
  });
12257
12294
  // Al apagar el autosize, se retira lo que se escribió a mano para que mande el CSS.
12258
- useIsomorphicLayoutEffect(() => {
12295
+ useIsomorphicLayoutEffect$1(() => {
12259
12296
  const node = nodeRef.current;
12260
12297
  if (enabled || !node) {
12261
12298
  return;
@@ -12703,6 +12740,68 @@ const useAuraToast = () => {
12703
12740
  return context;
12704
12741
  };
12705
12742
 
12743
+ const ToastHostContext = $8WNJc$react.createContext(null);
12744
+ // `useLayoutEffect` para que el cambio de quién pinta se resuelva antes de pintar (sin un frame
12745
+ // con cero o con dos toasts); en el servidor avisa en React 18, y ahí no hay nada que pintar.
12746
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? $8WNJc$react.useLayoutEffect : $8WNJc$react.useEffect;
12747
+ function pickActive(hosts) {
12748
+ let best = null;
12749
+ for (const entry of hosts) {
12750
+ if (best === null ||
12751
+ entry[1].priority > best[1].priority ||
12752
+ (entry[1].priority === best[1].priority && entry[1].seq < best[1].seq)) {
12753
+ best = entry;
12754
+ }
12755
+ }
12756
+ return best ? best[0] : null;
12757
+ }
12758
+ /** Estado del registro, para el provider. */
12759
+ function useToastHostRegistry() {
12760
+ const [hosts, setHosts] = $8WNJc$react.useState(() => new Map());
12761
+ const seqRef = $8WNJc$react.useRef(0);
12762
+ const register = $8WNJc$react.useCallback((id, priority) => {
12763
+ seqRef.current += 1;
12764
+ const seq = seqRef.current;
12765
+ setHosts((prev) => {
12766
+ const next = new Map(prev);
12767
+ next.set(id, { priority, seq });
12768
+ return next;
12769
+ });
12770
+ return () => {
12771
+ setHosts((prev) => {
12772
+ // Solo borra SU registro: si ya lo sustituyó otro con el mismo id, no lo toca.
12773
+ if (prev.get(id)?.seq !== seq) {
12774
+ return prev;
12775
+ }
12776
+ const next = new Map(prev);
12777
+ next.delete(id);
12778
+ return next;
12779
+ });
12780
+ };
12781
+ }, []);
12782
+ const activeId = $8WNJc$react.useMemo(() => pickActive(hosts), [hosts]);
12783
+ return $8WNJc$react.useMemo(() => ({ activeId, register }), [activeId, register]);
12784
+ }
12785
+ /**
12786
+ * Registra la instancia y dice si le toca pintar. Sin provider (sin registro) devuelve `true`:
12787
+ * el comportamiento de antes, que decide `useAuraToast`.
12788
+ */
12789
+ function useIsActiveToastHost(priority) {
12790
+ const registry = $8WNJc$react.useContext(ToastHostContext);
12791
+ const id = $8WNJc$react.useId();
12792
+ const register = registry?.register;
12793
+ useIsomorphicLayoutEffect(() => {
12794
+ if (!register) {
12795
+ return;
12796
+ }
12797
+ return register(id, priority);
12798
+ }, [register, id, priority]);
12799
+ if (!registry) {
12800
+ return true;
12801
+ }
12802
+ return registry.activeId === id;
12803
+ }
12804
+
12706
12805
  const VARIANT_BY_COLOR = {
12707
12806
  primary: "accent",
12708
12807
  secondary: "default",
@@ -12789,10 +12888,26 @@ const ICON_BY_COLOR = {
12789
12888
  const DEFAULT_TRANSLATIONS$6 = {
12790
12889
  closeButtonAriaLabel: "Cerrar notificación",
12791
12890
  };
12792
- function GlobalToast({ translations = {} } = {}) {
12891
+ /**
12892
+ * Toast global de la app. Idempotente: si bajo el mismo `AuraToastProvider` hay más de uno
12893
+ * montado (el que el provider monta por dentro + el que la app pone en su layout), pinta solo
12894
+ * uno — el de la app, y entre varios de la app el que recibe `translations` (ver
12895
+ * `_internal/toast-host.ts`).
12896
+ */
12897
+ function GlobalToast({ translations } = {}) {
12898
+ const priority = translations ? 2 : 1;
12899
+ return jsxRuntime.jsx(ToastSlot, { translations: translations, priority: priority });
12900
+ }
12901
+ /** El `GlobalToast` que `AuraToastProvider` monta por dentro: el de menor prioridad. */
12902
+ function ProviderToast() {
12903
+ return jsxRuntime.jsx(ToastSlot, { priority: 0 });
12904
+ }
12905
+ function ToastSlot({ translations = {}, priority, }) {
12906
+ // Sin provider, `useAuraToast` lanza igual que antes (no se cambia ese contrato).
12793
12907
  const { toast, hideToast } = useAuraToast();
12908
+ const isActive = useIsActiveToastHost(priority);
12794
12909
  const t = { ...DEFAULT_TRANSLATIONS$6, ...translations };
12795
- if (!toast.isVisible) {
12910
+ if (!(toast.isVisible && isActive)) {
12796
12911
  return null;
12797
12912
  }
12798
12913
  const color = toast.color ?? "primary";
@@ -19552,6 +19667,8 @@ const AuraToastProvider = ({ children }) => {
19552
19667
  color: "primary",
19553
19668
  duration: 8000,
19554
19669
  });
19670
+ // Registro de los `GlobalToast` montados debajo, para que pinte uno solo (ver toast-host.ts).
19671
+ const toastHosts = useToastHostRegistry();
19555
19672
  const timerRef = $8WNJc$react.useRef(null);
19556
19673
  const hideToast = $8WNJc$react.useCallback(() => {
19557
19674
  if (timerRef.current) {
@@ -19579,7 +19696,7 @@ const AuraToastProvider = ({ children }) => {
19579
19696
  }
19580
19697
  };
19581
19698
  }, []);
19582
- return (jsxRuntime.jsxs(ToastContext.Provider, { value: { toast, showToast, hideToast }, children: [jsxRuntime.jsx(GlobalToast, {}), children] }));
19699
+ return (jsxRuntime.jsx(ToastContext.Provider, { value: { toast, showToast, hideToast }, children: jsxRuntime.jsxs(ToastHostContext.Provider, { value: toastHosts, children: [jsxRuntime.jsx(ProviderToast, {}), children] }) }));
19583
19700
  };
19584
19701
 
19585
19702
  const NavigationLoadingContext = $8WNJc$react.createContext(undefined);
package/dist/index.esm.js CHANGED
@@ -8113,9 +8113,30 @@ const MenuComponent = $8WNJc$react.memo(function Menu({ commerceInfo, userInfo,
8113
8113
  color: "default", className: " text-default-500 data-[hovered=true]:text-default-600", startContent: jsx(IconComponent, { className: "text-default-500", icon: "solar:info-circle-line-duotone", size: "md" }), variant: "light", onPress: handleHelpClick, isIconOnly: isCollapsed, children: !isCollapsed && (jsx("span", { className: "collapsible-item truncate", children: helpSection.title })) }) })) : null] }) })] }));
8114
8114
  });
8115
8115
 
8116
+ /**
8117
+ * «Cargar más» solo se ofrece si hay otra página, alguien que pueda pedirla y la lista
8118
+ * ya enseña todo lo recibido (desplegada, o sin ítems plegados tras «Ver más»).
8119
+ */
8120
+ function isLoadMoreVisible({ hasMore, hasOnLoadMore, isExpanded, hasHiddenItems, }) {
8121
+ return hasMore && hasOnLoadMore && (isExpanded || !hasHiddenItems);
8122
+ }
8123
+ /**
8124
+ * Pulsación de «Cargar más». Con una página en vuelo no hace nada: el botón no usa
8125
+ * `disabled` nativo (perdería el foco del teclado), así que la guarda vive aquí.
8126
+ * Si no, despliega la lista y pide la página, para que lo nuevo no quede tras «Ver más».
8127
+ */
8128
+ function pressLoadMore({ isLoadingMore, onLoadMore, expand, }) {
8129
+ if (isLoadingMore) {
8130
+ return;
8131
+ }
8132
+ expand();
8133
+ onLoadMore();
8134
+ }
8135
+
8116
8136
  /**
8117
8137
  * Sección de historial de conversaciones: botón de nueva conversación + lista de
8118
- * entradas recientes con "ver más".
8138
+ * entradas recientes con "ver más" y, si el consumidor tiene más páginas,
8139
+ * "cargar más".
8119
8140
  *
8120
8141
  * La lista tiene **scroll interno propio** (`flex-1 min-h-0 overflow-y-auto`) y
8121
8142
  * la sección está acotada en altura, para que crecer el historial no arrastre ni
@@ -8134,7 +8155,7 @@ const MenuComponent = $8WNJc$react.memo(function Menu({ commerceInfo, userInfo,
8134
8155
  * gana a sus `--button-*` porque las utilidades van en una capa posterior a la de
8135
8156
  * `.button`.
8136
8157
  */
8137
- const MenuClawHistoryPanel = $8WNJc$react.memo(function MenuClawHistoryPanel({ items, initialVisibleCount, onNewConversation, isCollapsed, title, newLabel, showMoreLabel, showLessLabel, onBeforeSelect, }) {
8158
+ const MenuClawHistoryPanel = $8WNJc$react.memo(function MenuClawHistoryPanel({ items, initialVisibleCount, onNewConversation, hasMore, onLoadMore, isLoadingMore, loadMoreLabel, isCollapsed, title, newLabel, showMoreLabel, showLessLabel, onBeforeSelect, }) {
8138
8159
  const [isExpanded, setIsExpanded] = $8WNJc$react.useState(false);
8139
8160
  const visibleItems = useMemo(() => (isExpanded ? items : items.slice(0, initialVisibleCount)), [isExpanded, items, initialVisibleCount]);
8140
8161
  const hasHiddenItems = items.length > initialVisibleCount;
@@ -8161,7 +8182,17 @@ const MenuClawHistoryPanel = $8WNJc$react.memo(function MenuClawHistoryPanel({ i
8161
8182
  ? "cursor-not-allowed opacity-50"
8162
8183
  : "hover:bg-default-100"), children: [jsx("span", { className: "flex h-5 w-5 shrink-0 items-center justify-center text-default-400", children: jsx(IconComponent, { icon: "solar:chat-round-dots-linear", size: "md", "aria-hidden": true }) }), jsxs("span", { className: "flex min-w-0 flex-col", children: [jsx("span", { className: "truncate", children: item.title }), item.meta ? (jsx("span", { className: "truncate text-xs text-default-400", children: item.meta })) : null] })] }) }, item.id))) }), hasHiddenItems ? (jsxs("button", { type: "button", onClick: handleToggleExpand, "aria-expanded": isExpanded, className: "flex w-full shrink-0 items-center gap-1.5 rounded-lg px-2 py-2 text-xs font-medium text-default-500 transition-colors hover:bg-default-100 hover:text-default-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus", children: [jsx(IconComponent, { icon: isExpanded
8163
8184
  ? "solar:alt-arrow-up-linear"
8164
- : "solar:alt-arrow-down-linear", size: "sm", "aria-hidden": true }), isExpanded ? showLessLabel : showMoreLabel] })) : null] })) : null] }));
8185
+ : "solar:alt-arrow-down-linear", size: "sm", "aria-hidden": true }), isExpanded ? showLessLabel : showMoreLabel] })) : null, onLoadMore &&
8186
+ isLoadMoreVisible({
8187
+ hasMore,
8188
+ hasOnLoadMore: true,
8189
+ isExpanded,
8190
+ hasHiddenItems,
8191
+ }) ? (jsxs("button", { type: "button", onClick: () => pressLoadMore({
8192
+ isLoadingMore,
8193
+ onLoadMore,
8194
+ expand: () => setIsExpanded(true),
8195
+ }), "aria-disabled": isLoadingMore, "aria-busy": isLoadingMore, className: "flex w-full shrink-0 items-center gap-1.5 rounded-lg px-2 py-2 text-xs font-medium text-default-500 transition-colors hover:bg-default-100 hover:text-default-700 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus aria-disabled:cursor-not-allowed aria-disabled:opacity-50", children: [jsx(IconComponent, { icon: "solar:add-circle-linear", size: "sm", "aria-hidden": true }), loadMoreLabel] })) : null] })) : null] }));
8165
8196
  });
8166
8197
 
8167
8198
  /** ¿Está la key seleccionada en este ítem o en cualquiera de sus descendientes? */
@@ -8225,6 +8256,7 @@ const DEFAULT_TRANSLATIONS$a = {
8225
8256
  historyNewLabel: "Nueva conversación",
8226
8257
  historyShowMoreLabel: "Ver más",
8227
8258
  historyShowLessLabel: "Ver menos",
8259
+ historyLoadMoreLabel: "Cargar más",
8228
8260
  };
8229
8261
  /** Ítems del historial visibles antes de pulsar "ver más". */
8230
8262
  const DEFAULT_HISTORY_VISIBLE_COUNT = 5;
@@ -8283,7 +8315,12 @@ const MenuClaw = $8WNJc$react.memo(function MenuClaw({ userInfo, helpButton, men
8283
8315
  const initialVisibleCount = typeof rawCount === "number" && Number.isFinite(rawCount) && rawCount > 0
8284
8316
  ? Math.floor(rawCount)
8285
8317
  : DEFAULT_HISTORY_VISIBLE_COUNT;
8286
- return { items, initialVisibleCount };
8318
+ return {
8319
+ items,
8320
+ initialVisibleCount,
8321
+ hasMore: history?.hasMore === true,
8322
+ isLoadingMore: history?.isLoadingMore === true,
8323
+ };
8287
8324
  }, [history]);
8288
8325
  const bottomBarItems = useMemo(() => {
8289
8326
  if (!mobileBottomBarGroupKey) {
@@ -8328,7 +8365,7 @@ const MenuClaw = $8WNJc$react.memo(function MenuClaw({ userInfo, helpButton, men
8328
8365
  ? "solar:alt-arrow-right-linear"
8329
8366
  : "solar:alt-arrow-left-linear", size: "md", "aria-hidden": true }) })] }), jsxs("div", { className: cn("flex items-center py-3", collapsed ? "justify-center gap-0" : "gap-3"), children: [jsxs(Avatar, { size: "sm", className: "shrink-0", children: [userInfo?.avatar?.trim() ? (jsx(Avatar.Image, { src: userInfo.avatar, alt: userName })) : null, jsx(Avatar.Fallback, { className: userInfo?.avatar?.trim()
8330
8367
  ? undefined
8331
- : "bg-warning text-warning-foreground", children: getUserInitials(userName) })] }), !collapsed ? (jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: userName }), jsx("p", { className: "truncate text-xs text-default-400", children: userRole })] })) : null] }), jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history?.onNewConversation, isCollapsed: collapsed, title: t.historyTitle, newLabel: t.historyNewLabel, showMoreLabel: t.historyShowMoreLabel, showLessLabel: t.historyShowLessLabel, onBeforeSelect: handleSidebarClose }), jsx("nav", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: menuItems.items.map((group) => (jsxs("div", { className: "mb-2", children: [group.title && !collapsed ? (jsx("p", { className: "px-2 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsx("ul", { className: "flex flex-col gap-0.5", children: (group.items ?? []).map((item) => (jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: collapsed, onSelect: handleMenuSelect }, item.key))) })] }, group.key))) }), helpSection ? (jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsx(Button, { fullWidth: true,
8368
+ : "bg-warning text-warning-foreground", children: getUserInitials(userName) })] }), !collapsed ? (jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsx("p", { className: "truncate text-sm font-semibold text-foreground", children: userName }), jsx("p", { className: "truncate text-xs text-default-400", children: userRole })] })) : null] }), jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history?.onNewConversation, hasMore: historyConfig.hasMore, onLoadMore: history?.onLoadMore, isLoadingMore: historyConfig.isLoadingMore, isCollapsed: collapsed, title: t.historyTitle, newLabel: t.historyNewLabel, showMoreLabel: t.historyShowMoreLabel, showLessLabel: t.historyShowLessLabel, loadMoreLabel: t.historyLoadMoreLabel, onBeforeSelect: handleSidebarClose }), jsx("nav", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]", children: menuItems.items.map((group) => (jsxs("div", { className: "mb-2", children: [group.title && !collapsed ? (jsx("p", { className: "px-2 pb-1 pt-2 text-xs font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsx("ul", { className: "flex flex-col gap-0.5", children: (group.items ?? []).map((item) => (jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: collapsed, onSelect: handleMenuSelect }, item.key))) })] }, group.key))) }), helpSection ? (jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsx(Button, { fullWidth: true,
8332
8369
  // TECH-2459 · G2 — la fachada propia de `Button` (D-G4-1) pinta
8333
8370
  // `color="primary"` por defecto; el crudo de v2 pintaba "default"
8334
8371
  // (gris). Se fija explícito para no teñir de azul un botón neutro.
@@ -12221,7 +12258,7 @@ function measureTextareaHeight(node, minRows, maxRows) {
12221
12258
  };
12222
12259
  }
12223
12260
  // `useLayoutEffect` en el servidor avisa en React 18; el alto solo tiene sentido en el cliente.
12224
- const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
12261
+ const useIsomorphicLayoutEffect$1 = typeof window !== "undefined" ? useLayoutEffect : useEffect;
12225
12262
  /**
12226
12263
  * Autocrecimiento del `<textarea>` apuntado por `nodeRef`. Devuelve el `resize` para llamarlo
12227
12264
  * desde el `onChange` de la fachada.
@@ -12251,11 +12288,11 @@ function useTextareaAutosize(nodeRef, { enabled, minRows, maxRows }) {
12251
12288
  const resizeRef = useRef(resize);
12252
12289
  resizeRef.current = resize;
12253
12290
  // Cada render, como v2: el valor controlado, el `size` o la clase pueden haber cambiado.
12254
- useIsomorphicLayoutEffect(() => {
12291
+ useIsomorphicLayoutEffect$1(() => {
12255
12292
  resize();
12256
12293
  });
12257
12294
  // Al apagar el autosize, se retira lo que se escribió a mano para que mande el CSS.
12258
- useIsomorphicLayoutEffect(() => {
12295
+ useIsomorphicLayoutEffect$1(() => {
12259
12296
  const node = nodeRef.current;
12260
12297
  if (enabled || !node) {
12261
12298
  return;
@@ -12703,6 +12740,68 @@ const useAuraToast = () => {
12703
12740
  return context;
12704
12741
  };
12705
12742
 
12743
+ const ToastHostContext = createContext(null);
12744
+ // `useLayoutEffect` para que el cambio de quién pinta se resuelva antes de pintar (sin un frame
12745
+ // con cero o con dos toasts); en el servidor avisa en React 18, y ahí no hay nada que pintar.
12746
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
12747
+ function pickActive(hosts) {
12748
+ let best = null;
12749
+ for (const entry of hosts) {
12750
+ if (best === null ||
12751
+ entry[1].priority > best[1].priority ||
12752
+ (entry[1].priority === best[1].priority && entry[1].seq < best[1].seq)) {
12753
+ best = entry;
12754
+ }
12755
+ }
12756
+ return best ? best[0] : null;
12757
+ }
12758
+ /** Estado del registro, para el provider. */
12759
+ function useToastHostRegistry() {
12760
+ const [hosts, setHosts] = useState(() => new Map());
12761
+ const seqRef = useRef(0);
12762
+ const register = useCallback((id, priority) => {
12763
+ seqRef.current += 1;
12764
+ const seq = seqRef.current;
12765
+ setHosts((prev) => {
12766
+ const next = new Map(prev);
12767
+ next.set(id, { priority, seq });
12768
+ return next;
12769
+ });
12770
+ return () => {
12771
+ setHosts((prev) => {
12772
+ // Solo borra SU registro: si ya lo sustituyó otro con el mismo id, no lo toca.
12773
+ if (prev.get(id)?.seq !== seq) {
12774
+ return prev;
12775
+ }
12776
+ const next = new Map(prev);
12777
+ next.delete(id);
12778
+ return next;
12779
+ });
12780
+ };
12781
+ }, []);
12782
+ const activeId = useMemo(() => pickActive(hosts), [hosts]);
12783
+ return useMemo(() => ({ activeId, register }), [activeId, register]);
12784
+ }
12785
+ /**
12786
+ * Registra la instancia y dice si le toca pintar. Sin provider (sin registro) devuelve `true`:
12787
+ * el comportamiento de antes, que decide `useAuraToast`.
12788
+ */
12789
+ function useIsActiveToastHost(priority) {
12790
+ const registry = useContext(ToastHostContext);
12791
+ const id = useId();
12792
+ const register = registry?.register;
12793
+ useIsomorphicLayoutEffect(() => {
12794
+ if (!register) {
12795
+ return;
12796
+ }
12797
+ return register(id, priority);
12798
+ }, [register, id, priority]);
12799
+ if (!registry) {
12800
+ return true;
12801
+ }
12802
+ return registry.activeId === id;
12803
+ }
12804
+
12706
12805
  const VARIANT_BY_COLOR = {
12707
12806
  primary: "accent",
12708
12807
  secondary: "default",
@@ -12789,10 +12888,26 @@ const ICON_BY_COLOR = {
12789
12888
  const DEFAULT_TRANSLATIONS$6 = {
12790
12889
  closeButtonAriaLabel: "Cerrar notificación",
12791
12890
  };
12792
- function GlobalToast({ translations = {} } = {}) {
12891
+ /**
12892
+ * Toast global de la app. Idempotente: si bajo el mismo `AuraToastProvider` hay más de uno
12893
+ * montado (el que el provider monta por dentro + el que la app pone en su layout), pinta solo
12894
+ * uno — el de la app, y entre varios de la app el que recibe `translations` (ver
12895
+ * `_internal/toast-host.ts`).
12896
+ */
12897
+ function GlobalToast({ translations } = {}) {
12898
+ const priority = translations ? 2 : 1;
12899
+ return jsx(ToastSlot, { translations: translations, priority: priority });
12900
+ }
12901
+ /** El `GlobalToast` que `AuraToastProvider` monta por dentro: el de menor prioridad. */
12902
+ function ProviderToast() {
12903
+ return jsx(ToastSlot, { priority: 0 });
12904
+ }
12905
+ function ToastSlot({ translations = {}, priority, }) {
12906
+ // Sin provider, `useAuraToast` lanza igual que antes (no se cambia ese contrato).
12793
12907
  const { toast, hideToast } = useAuraToast();
12908
+ const isActive = useIsActiveToastHost(priority);
12794
12909
  const t = { ...DEFAULT_TRANSLATIONS$6, ...translations };
12795
- if (!toast.isVisible) {
12910
+ if (!(toast.isVisible && isActive)) {
12796
12911
  return null;
12797
12912
  }
12798
12913
  const color = toast.color ?? "primary";
@@ -19552,6 +19667,8 @@ const AuraToastProvider = ({ children }) => {
19552
19667
  color: "primary",
19553
19668
  duration: 8000,
19554
19669
  });
19670
+ // Registro de los `GlobalToast` montados debajo, para que pinte uno solo (ver toast-host.ts).
19671
+ const toastHosts = useToastHostRegistry();
19555
19672
  const timerRef = useRef(null);
19556
19673
  const hideToast = useCallback(() => {
19557
19674
  if (timerRef.current) {
@@ -19579,7 +19696,7 @@ const AuraToastProvider = ({ children }) => {
19579
19696
  }
19580
19697
  };
19581
19698
  }, []);
19582
- return (jsxs(ToastContext.Provider, { value: { toast, showToast, hideToast }, children: [jsx(GlobalToast, {}), children] }));
19699
+ return (jsx(ToastContext.Provider, { value: { toast, showToast, hideToast }, children: jsxs(ToastHostContext.Provider, { value: toastHosts, children: [jsx(ProviderToast, {}), children] }) }));
19583
19700
  };
19584
19701
 
19585
19702
  const NavigationLoadingContext = createContext(undefined);
@@ -1 +1 @@
1
- {"version":3,"file":"MenuClaw.d.ts","sourceRoot":"","sources":["../../../../src/components/menu-claw/MenuClaw.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAEpD,OAAO,iBAAiB,CAAC;AAMzB,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAmB5E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA+T3C,CAAC"}
1
+ {"version":3,"file":"MenuClaw.d.ts","sourceRoot":"","sources":["../../../../src/components/menu-claw/MenuClaw.tsx"],"names":[],"mappings":"AACA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAEpD,OAAO,iBAAiB,CAAC;AAMzB,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAoB5E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAwU3C,CAAC"}
@@ -37,6 +37,23 @@ export interface MenuClawHistory {
37
37
  * Si se proporciona, se muestra el botón de nueva conversación sobre la lista.
38
38
  */
39
39
  onNewConversation?: () => void;
40
+ /**
41
+ * `true` si el consumidor puede traer más entradas de las ya listadas (hay otra
42
+ * página en el servidor). Con `onLoadMore`, pinta «Cargar más» al final de la lista
43
+ * —cuando no quedan ítems plegados tras «Ver más»—. Sin esta prop, nada cambia.
44
+ * @default false
45
+ */
46
+ hasMore?: boolean;
47
+ /**
48
+ * Pide la página siguiente. Sin esta prop no se pinta «Cargar más» aunque `hasMore`
49
+ * sea `true`: no se promete una página que nadie puede pedir.
50
+ */
51
+ onLoadMore?: () => void;
52
+ /**
53
+ * Página siguiente en vuelo: «Cargar más» queda desactivado y con `aria-busy`.
54
+ * @default false
55
+ */
56
+ isLoadingMore?: boolean;
40
57
  }
41
58
  /**
42
59
  * Traducciones de MenuClaw. Todas opcionales para permitir traducciones
@@ -61,6 +78,8 @@ export type MenuClawTranslations = {
61
78
  historyShowMoreLabel?: string;
62
79
  /** Etiqueta del botón que vuelve a plegar el historial */
63
80
  historyShowLessLabel?: string;
81
+ /** Etiqueta del botón que pide la página siguiente del historial */
82
+ historyLoadMoreLabel?: string;
64
83
  };
65
84
  export interface MenuClawProps {
66
85
  userInfo: {
@@ -1 +1 @@
1
- {"version":3,"file":"MenuClaw.types.d.ts","sourceRoot":"","sources":["../../../../src/components/menu-claw/MenuClaw.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mDAAmD,CAAC;AAEzF,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAC;IACX,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,yDAAyD;IACzD,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAClC,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,MAAM,WAAW,aAAa;IAC7B,QAAQ,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACb,CAAC;IACF;;;OAGG;IACH,UAAU,CAAC,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,SAAS,EAAE;QACV,KAAK,EAAE,eAAe,EAAE,CAAC;QACzB;;;;WAIG;QACH,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,sEAAsE;QACtE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB;;;WAGG;QACH,QAAQ,CAAC,EAAE,CACV,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,SAAS,GAAG,WAAW,KAC5B,IAAI,CAAC;KACV,CAAC;IACF,uDAAuD;IACvD,OAAO,EAAE,eAAe,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iEAAiE;IACjE,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACpC"}
1
+ {"version":3,"file":"MenuClaw.types.d.ts","sourceRoot":"","sources":["../../../../src/components/menu-claw/MenuClaw.types.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,8 @@ import React from "react";
2
2
  import type { MenuClawHistoryPanelProps } from "./MenuClawHistoryPanel.types";
3
3
  /**
4
4
  * Sección de historial de conversaciones: botón de nueva conversación + lista de
5
- * entradas recientes con "ver más".
5
+ * entradas recientes con "ver más" y, si el consumidor tiene más páginas,
6
+ * "cargar más".
6
7
  *
7
8
  * La lista tiene **scroll interno propio** (`flex-1 min-h-0 overflow-y-auto`) y
8
9
  * la sección está acotada en altura, para que crecer el historial no arrastre ni
@@ -1 +1 @@
1
- {"version":3,"file":"MenuClawHistoryPanel.d.ts","sourceRoot":"","sources":["../../../../../../src/components/menu-claw/_internal/menu-claw-history/MenuClawHistoryPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAKpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA6IlE,CAAC"}
1
+ {"version":3,"file":"MenuClawHistoryPanel.d.ts","sourceRoot":"","sources":["../../../../../../src/components/menu-claw/_internal/menu-claw-history/MenuClawHistoryPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+B,MAAM,OAAO,CAAC;AAKpD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC;AAG9E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAmLlE,CAAC"}
@@ -6,6 +6,14 @@ export type MenuClawHistoryPanelProps = {
6
6
  initialVisibleCount: number;
7
7
  /** Si se proporciona, se muestra el botón de nueva conversación sobre la lista. */
8
8
  onNewConversation?: () => void;
9
+ /** Hay otra página en el servidor (ver `MenuClawHistory.hasMore`). */
10
+ hasMore: boolean;
11
+ /** Pide la página siguiente; sin ella no se pinta «Cargar más». */
12
+ onLoadMore?: () => void;
13
+ /** Página siguiente en vuelo: botón desactivado y `aria-busy`. */
14
+ isLoadingMore: boolean;
15
+ /** Etiqueta del botón que pide la página siguiente. */
16
+ loadMoreLabel: string;
9
17
  /** Lateral comprimido: solo el botón de nueva conversación, en modo icono. */
10
18
  isCollapsed: boolean;
11
19
  /** Título de la sección. */
@@ -1 +1 @@
1
- {"version":3,"file":"MenuClawHistoryPanel.types.d.ts","sourceRoot":"","sources":["../../../../../../src/components/menu-claw/_internal/menu-claw-history/MenuClawHistoryPanel.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,MAAM,yBAAyB,GAAG;IACvC,yDAAyD;IACzD,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,sDAAsD;IACtD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,8EAA8E;IAC9E,WAAW,EAAE,OAAO,CAAC;IACrB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC"}
1
+ {"version":3,"file":"MenuClawHistoryPanel.types.d.ts","sourceRoot":"","sources":["../../../../../../src/components/menu-claw/_internal/menu-claw-history/MenuClawHistoryPanel.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAEhE,MAAM,MAAM,yBAAyB,GAAG;IACvC,yDAAyD;IACzD,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,sDAAsD;IACtD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,sEAAsE;IACtE,OAAO,EAAE,OAAO,CAAC;IACjB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,kEAAkE;IAClE,aAAa,EAAE,OAAO,CAAC;IACvB,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;IACtB,8EAA8E;IAC9E,WAAW,EAAE,OAAO,CAAC;IACrB,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * «Cargar más» solo se ofrece si hay otra página, alguien que pueda pedirla y la lista
3
+ * ya enseña todo lo recibido (desplegada, o sin ítems plegados tras «Ver más»).
4
+ */
5
+ export declare function isLoadMoreVisible({ hasMore, hasOnLoadMore, isExpanded, hasHiddenItems, }: {
6
+ hasMore: boolean;
7
+ hasOnLoadMore: boolean;
8
+ isExpanded: boolean;
9
+ hasHiddenItems: boolean;
10
+ }): boolean;
11
+ /**
12
+ * Pulsación de «Cargar más». Con una página en vuelo no hace nada: el botón no usa
13
+ * `disabled` nativo (perdería el foco del teclado), así que la guarda vive aquí.
14
+ * Si no, despliega la lista y pide la página, para que lo nuevo no quede tras «Ver más».
15
+ */
16
+ export declare function pressLoadMore({ isLoadingMore, onLoadMore, expand, }: {
17
+ isLoadingMore: boolean;
18
+ onLoadMore: () => void;
19
+ expand: () => void;
20
+ }): void;
21
+ //# sourceMappingURL=menuClawHistoryLoadMore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menuClawHistoryLoadMore.d.ts","sourceRoot":"","sources":["../../../../../../src/components/menu-claw/_internal/menu-claw-history/menuClawHistoryLoadMore.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EACjC,OAAO,EACP,aAAa,EACb,UAAU,EACV,cAAc,GACd,EAAE;IACF,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;CACxB,GAAG,OAAO,CAEV;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC7B,aAAa,EACb,UAAU,EACV,MAAM,GACN,EAAE;IACF,aAAa,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;CACnB,GAAG,IAAI,CAMP"}
@@ -1,3 +1,11 @@
1
1
  import type { GlobalToastProps } from "./GlobalToast.types";
2
- export declare function GlobalToast({ translations }?: GlobalToastProps): import("react").JSX.Element | null;
2
+ /**
3
+ * Toast global de la app. Idempotente: si bajo el mismo `AuraToastProvider` hay más de uno
4
+ * montado (el que el provider monta por dentro + el que la app pone en su layout), pinta solo
5
+ * uno — el de la app, y entre varios de la app el que recibe `translations` (ver
6
+ * `_internal/toast-host.ts`).
7
+ */
8
+ export declare function GlobalToast({ translations }?: GlobalToastProps): import("react").JSX.Element;
9
+ /** El `GlobalToast` que `AuraToastProvider` monta por dentro: el de menor prioridad. */
10
+ export declare function ProviderToast(): import("react").JSX.Element;
3
11
  //# sourceMappingURL=GlobalToast.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"GlobalToast.d.ts","sourceRoot":"","sources":["../../../../src/components/toast/GlobalToast.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACX,gBAAgB,EAEhB,MAAM,qBAAqB,CAAC;AA+G7B,wBAAgB,WAAW,CAAC,EAAE,YAAiB,EAAE,GAAE,gBAAqB,sCAuEvE"}
1
+ {"version":3,"file":"GlobalToast.d.ts","sourceRoot":"","sources":["../../../../src/components/toast/GlobalToast.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACX,gBAAgB,EAEhB,MAAM,qBAAqB,CAAC;AAmH7B;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,YAAY,EAAE,GAAE,gBAAqB,+BAGlE;AAED,wFAAwF;AACxF,wBAAgB,aAAa,gCAE5B"}