@beweco/aurora-ui 0.6.74 → 0.6.76

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
@@ -284,6 +284,10 @@ exports.HolidayType = void 0;
284
284
  HolidayType["DateRange"] = "dateRange";
285
285
  })(exports.HolidayType || (exports.HolidayType = {}));
286
286
 
287
+ var CLASE_AURA = {
288
+ ring: "linda-aura-ring",
289
+ surface: "linda-aura",
290
+ };
287
291
  /**
288
292
  * Botón genérico basado en HeroUI siguiendo las reglas de diseño BeweOS.
289
293
  *
@@ -294,10 +298,24 @@ exports.HolidayType = void 0;
294
298
  * - isLoading: On, Off
295
299
  * - Radius: md (por defecto)
296
300
  * - isIconOnly: True, False
301
+ * - ai: aura de Linda para las acciones que hace la IA (ver `Button.types.ts`)
297
302
  */
298
303
  var Button = function (_a) {
299
- var _b = _a.color, color = _b === void 0 ? "primary" : _b, _c = _a.size, size = _c === void 0 ? "md" : _c, _d = _a.variant, variant = _d === void 0 ? "solid" : _d, _e = _a.radius, radius = _e === void 0 ? "sm" : _e, startContent = _a.startContent, endContent = _a.endContent, _f = _a.isLoading, isLoading = _f === void 0 ? false : _f, _g = _a.isIconOnly, isIconOnly = _g === void 0 ? false : _g, props = __rest(_a, ["color", "size", "variant", "radius", "startContent", "endContent", "isLoading", "isIconOnly"]);
300
- return (jsxRuntime.jsx(react.Button, __assign({}, props, { color: color, size: size, variant: variant, radius: radius, startContent: startContent, endContent: endContent, isLoading: isLoading, isIconOnly: isIconOnly })));
304
+ var _b = _a.color, color = _b === void 0 ? "primary" : _b, _c = _a.size, size = _c === void 0 ? "md" : _c, _d = _a.variant, variant = _d === void 0 ? "solid" : _d, _e = _a.radius, radius = _e === void 0 ? "sm" : _e, startContent = _a.startContent, endContent = _a.endContent, _f = _a.isLoading, isLoading = _f === void 0 ? false : _f, _g = _a.isIconOnly, isIconOnly = _g === void 0 ? false : _g, ai = _a.ai, className = _a.className, children = _a.children, props = __rest(_a, ["color", "size", "variant", "radius", "startContent", "endContent", "isLoading", "isIconOnly", "ai", "className", "children"]);
305
+ /*
306
+ * El contenido se envuelve para poder subirlo por encima del aura.
307
+ *
308
+ * Y tiene que ser un elemento: `<Button>Crear campaña</Button>` pasa un NODO DE
309
+ * TEXTO, que no es posicionable, así que ningún selector puede sacarlo del fondo del
310
+ * apilado —el aura, que sí está posicionada, le pasaría por encima—. Con `ring` daría
311
+ * igual porque esa capa es solo el canto; con `surface` el texto se leería a través
312
+ * del degradado.
313
+ */
314
+ var contenido = ai ? (jsxRuntime.jsx("span", { className: "linda-aura-content", children: children })) : (children);
315
+ var clases = [ai ? CLASE_AURA[ai] : "", className]
316
+ .filter(Boolean)
317
+ .join(" ");
318
+ return (jsxRuntime.jsx(react.Button, __assign({}, props, { color: color, size: size, variant: variant, radius: radius, startContent: startContent, endContent: endContent, isLoading: isLoading, isIconOnly: isIconOnly, className: clases || undefined, children: contenido })));
301
319
  };
302
320
 
303
321
  var DatePicker = function (_a) {
@@ -3936,8 +3954,10 @@ var DEFAULT_HISTORY_VISIBLE_COUNT = 5;
3936
3954
  */
3937
3955
  var MenuClaw = React.memo(function MenuClaw(_a) {
3938
3956
  var _b, _c;
3939
- var userInfo = _a.userInfo, helpButton = _a.helpButton, menuItems = _a.menuItems, history = _a.history, isOpenSidebar = _a.isOpenSidebar, onOpenSidebarChange = _a.onOpenSidebarChange, mobileBottomBarGroupKey = _a.mobileBottomBarGroupKey, _d = _a.showNativeMenu, showNativeMenu = _d === void 0 ? true : _d, _e = _a.translations, translations = _e === void 0 ? {} : _e;
3940
- var _f = React.useState(false), isCollapsed = _f[0], setIsCollapsed = _f[1];
3957
+ var userInfo = _a.userInfo, helpButton = _a.helpButton, menuItems = _a.menuItems, history = _a.history, isOpenSidebar = _a.isOpenSidebar, onOpenSidebarChange = _a.onOpenSidebarChange, mobileBottomBarGroupKey = _a.mobileBottomBarGroupKey, _d = _a.showNativeMenu, showNativeMenu = _d === void 0 ? true : _d, _e = _a.translations, translations = _e === void 0 ? {} : _e, isCollapsedProp = _a.isCollapsed, onCollapsedChange = _a.onCollapsedChange, defaultCollapsed = _a.defaultCollapsed;
3958
+ var isControlled = isCollapsedProp !== undefined;
3959
+ var _f = React.useState(defaultCollapsed !== null && defaultCollapsed !== void 0 ? defaultCollapsed : false), internalCollapsed = _f[0], setInternalCollapsed = _f[1];
3960
+ var collapsed = isCollapsedProp !== null && isCollapsedProp !== void 0 ? isCollapsedProp : internalCollapsed;
3941
3961
  var t = __assign(__assign({}, DEFAULT_TRANSLATIONS$7), translations);
3942
3962
  var selectedKey = React.useMemo(function () {
3943
3963
  var _a, _b, _c;
@@ -3986,8 +4006,12 @@ var MenuClaw = React.memo(function MenuClaw(_a) {
3986
4006
  onOpenSidebarChange === null || onOpenSidebarChange === void 0 ? void 0 : onOpenSidebarChange(true);
3987
4007
  }, [onOpenSidebarChange]);
3988
4008
  var handleCollapseToggle = React.useCallback(function () {
3989
- setIsCollapsed(function (prev) { return !prev; });
3990
- }, []);
4009
+ var next = !collapsed;
4010
+ if (!isControlled) {
4011
+ setInternalCollapsed(next);
4012
+ }
4013
+ onCollapsedChange === null || onCollapsedChange === void 0 ? void 0 : onCollapsedChange(next);
4014
+ }, [collapsed, isControlled, onCollapsedChange]);
3991
4015
  var handleHelpClick = React.useCallback(function () {
3992
4016
  if (helpSection) {
3993
4017
  window.open(helpSection.redirect, "_blank");
@@ -4006,12 +4030,12 @@ var MenuClaw = React.memo(function MenuClaw(_a) {
4006
4030
  (_a = menuItems.onSelect) === null || _a === void 0 ? void 0 : _a.call(menuItems, key, href, "bottomBar");
4007
4031
  }, [onOpenSidebarChange, menuItems.onSelect]);
4008
4032
  var showBottomBar = (mobileBottomBarGroupKey && bottomBarItems.length > 0) || showNativeMenu;
4009
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [showBottomBar ? (jsxRuntime.jsx(MenuMobileBottomBar, { items: bottomBarItems, selectedKey: selectedKey, onSelect: handleBottomBarSelect, onMenuPress: handleSidebarOpen, menuLabel: t.menuLabel, navAriaLabel: t.mobileNavAriaLabel, forceVisible: showNativeMenu && bottomBarItems.length === 0 })) : null, jsxRuntime.jsx("button", { type: "button", "aria-label": t.closeSidebarAriaLabel, className: "menu-claw-overlay ".concat(isOpenSidebar ? "menu-claw-overlay--open" : ""), onClick: handleSidebarClose, tabIndex: isOpenSidebar ? 0 : -1 }), jsxRuntime.jsx("div", { className: react.cn("menu-claw", isCollapsed ? "menu-claw--collapsed" : "menu-claw--expanded", isOpenSidebar && "menu-claw--mobile-open"), "aria-hidden": !isOpenSidebar, children: jsxRuntime.jsxs("div", { className: "menu-claw__content", children: [jsxRuntime.jsxs("div", { className: react.cn("flex items-center", isCollapsed ? "justify-center" : "justify-end"), children: [jsxRuntime.jsx(IconComponent, { icon: "material-symbols-light:close", size: "lg", className: "block cursor-pointer sm:hidden", onClick: handleSidebarClose }), jsxRuntime.jsx("button", { type: "button", "aria-label": t.toggleSidebarAriaLabel, onClick: handleCollapseToggle, className: "hidden h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-lg text-default-500 transition-colors hover:bg-default-100 sm:flex", children: jsxRuntime.jsx(IconComponent, { icon: isCollapsed
4033
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [showBottomBar ? (jsxRuntime.jsx(MenuMobileBottomBar, { items: bottomBarItems, selectedKey: selectedKey, onSelect: handleBottomBarSelect, onMenuPress: handleSidebarOpen, menuLabel: t.menuLabel, navAriaLabel: t.mobileNavAriaLabel, forceVisible: showNativeMenu && bottomBarItems.length === 0 })) : null, jsxRuntime.jsx("button", { type: "button", "aria-label": t.closeSidebarAriaLabel, className: "menu-claw-overlay ".concat(isOpenSidebar ? "menu-claw-overlay--open" : ""), onClick: handleSidebarClose, tabIndex: isOpenSidebar ? 0 : -1 }), jsxRuntime.jsx("div", { className: react.cn("menu-claw", collapsed ? "menu-claw--collapsed" : "menu-claw--expanded", isOpenSidebar && "menu-claw--mobile-open"), "aria-hidden": !isOpenSidebar, children: jsxRuntime.jsxs("div", { className: "menu-claw__content", children: [jsxRuntime.jsxs("div", { className: react.cn("flex items-center", collapsed ? "justify-center" : "justify-end"), children: [jsxRuntime.jsx(IconComponent, { icon: "material-symbols-light:close", size: "lg", className: "block cursor-pointer sm:hidden", onClick: handleSidebarClose }), jsxRuntime.jsx("button", { type: "button", "aria-label": t.toggleSidebarAriaLabel, onClick: handleCollapseToggle, className: "hidden h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-lg text-default-500 transition-colors hover:bg-default-100 sm:flex", children: jsxRuntime.jsx(IconComponent, { icon: collapsed
4010
4034
  ? "solar:alt-arrow-right-linear"
4011
- : "solar:alt-arrow-left-linear", size: "md", "aria-hidden": true }) })] }), jsxRuntime.jsxs("div", { className: react.cn("flex items-center py-3", isCollapsed ? "justify-center gap-0" : "gap-3"), children: [jsxRuntime.jsx(react.Avatar, { size: "sm", src: ((_b = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, color: !((_c = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _c === void 0 ? void 0 : _c.trim()) ? "warning" : "default", name: userName, className: "shrink-0" }), !isCollapsed ? (jsxRuntime.jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsxRuntime.jsx("p", { className: "truncate text-small font-semibold text-foreground", children: userName }), jsxRuntime.jsx("p", { className: "truncate text-tiny text-default-400", children: userRole })] })) : null] }), jsxRuntime.jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history === null || history === void 0 ? void 0 : history.onNewConversation, isCollapsed: isCollapsed, 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(function (group) {
4035
+ : "solar:alt-arrow-left-linear", size: "md", "aria-hidden": true }) })] }), jsxRuntime.jsxs("div", { className: react.cn("flex items-center py-3", collapsed ? "justify-center gap-0" : "gap-3"), children: [jsxRuntime.jsx(react.Avatar, { size: "sm", src: ((_b = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, color: !((_c = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _c === void 0 ? void 0 : _c.trim()) ? "warning" : "default", name: userName, className: "shrink-0" }), !collapsed ? (jsxRuntime.jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsxRuntime.jsx("p", { className: "truncate text-small font-semibold text-foreground", children: userName }), jsxRuntime.jsx("p", { className: "truncate text-tiny text-default-400", children: userRole })] })) : null] }), jsxRuntime.jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history === null || history === void 0 ? void 0 : 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(function (group) {
4012
4036
  var _a;
4013
- return (jsxRuntime.jsxs("div", { className: "mb-2", children: [group.title && !isCollapsed ? (jsxRuntime.jsx("p", { className: "px-2 pb-1 pt-2 text-tiny font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5", children: ((_a = group.items) !== null && _a !== void 0 ? _a : []).map(function (item) { return (jsxRuntime.jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: isCollapsed, onSelect: handleMenuSelect }, item.key)); }) })] }, group.key));
4014
- }) }), helpSection ? (jsxRuntime.jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsxRuntime.jsx(react.Button, { fullWidth: true, className: "text-default-500 data-[hover=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: "menu-claw-collapsible truncate", children: helpSection.title })) : null }) })) : null] }) })] }));
4037
+ return (jsxRuntime.jsxs("div", { className: "mb-2", children: [group.title && !collapsed ? (jsxRuntime.jsx("p", { className: "px-2 pb-1 pt-2 text-tiny font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsxRuntime.jsx("ul", { className: "flex flex-col gap-0.5", children: ((_a = group.items) !== null && _a !== void 0 ? _a : []).map(function (item) { return (jsxRuntime.jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: collapsed, onSelect: handleMenuSelect }, item.key)); }) })] }, group.key));
4038
+ }) }), helpSection ? (jsxRuntime.jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsxRuntime.jsx(react.Button, { fullWidth: true, className: "text-default-500 data-[hover=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: collapsed, children: !collapsed ? (jsxRuntime.jsx("span", { className: "menu-claw-collapsible truncate", children: helpSection.title })) : null }) })) : null] }) })] }));
4015
4039
  });
4016
4040
 
4017
4041
  /**
@@ -9638,6 +9662,127 @@ function removeCustomPrimaryColor() {
9638
9662
  }
9639
9663
  }
9640
9664
 
9665
+ /**
9666
+ * Los tres tonos del aura de Linda, derivados del `primary` de la agencia.
9667
+ *
9668
+ * Linda no tiene color propio: es el `primary` que el negocio eligió en el onboarding,
9669
+ * y por eso aquí no hay ni un color escrito. Lo único que se fija es CUÁNTO se gira ese
9670
+ * tono y en qué banda de luz se pinta.
9671
+ */
9672
+ /**
9673
+ * Grados que se gira el `primary` para cada tono, en el orden en que se pintan.
9674
+ *
9675
+ * Son muchos grados a propósito. La gracia del aura es que haya MÁS DE UN COLOR: con
9676
+ * un giro discreto —del orden de 18°, el que usa un degradado de profundidad— salen
9677
+ * tres versiones del mismo tono y el resultado se lee como un plano. A ±55° el salto
9678
+ * se ve como otro color y sigue dentro de la familia del `primary`, que es lo que
9679
+ * permite que esto funcione con la agencia número siete sin tocar nada.
9680
+ *
9681
+ * El tono del medio va casi sin girar: es el que ancla el conjunto al color de la
9682
+ * agencia, para que el aura se lea como suya y no como una decoración pegada encima.
9683
+ */
9684
+ var GIROS = [-56, 8, 54];
9685
+ /**
9686
+ * Banda de luz en la que se pintan los tres tonos, en porcentaje HSL.
9687
+ *
9688
+ * Los tonos NO heredan la luz del `primary`, y esto es lo que más se nota: un primary
9689
+ * oscuro y poco saturado sobre una superficie clara se lee como una mancha gris —sucia,
9690
+ * no como color—, y uno casi blanco desaparece contra el fondo. Se llevan al paso medio
9691
+ * de la escala, que es el que funciona en los dos casos.
9692
+ */
9693
+ var BANDA_LUZ = { min: 52, max: 72 };
9694
+ /**
9695
+ * Banda de saturación de los tres tonos, en porcentaje HSL.
9696
+ *
9697
+ * El techo es lo que evita que el aura grite. A plena saturación los tonos dejan de ser
9698
+ * ambiente y pasan a ser tres focos de color encima de un control de 40 pt: bonito en
9699
+ * una captura, insoportable en una barra que se mira todo el día.
9700
+ *
9701
+ * ⚠️ **Y hay una razón que no es estética.** Girar el tono puede caer en un rojo vivo:
9702
+ * un `primary` amarillo —51°— girado −56° aterriza en 355°, que a saturación 100 se lee
9703
+ * como un estado de error alrededor de un botón que no ha fallado. Visto al renderizarlo,
9704
+ * no razonándolo. Bajado a 65 el mismo tono es un rosa apagado y vuelve a leerse como lo
9705
+ * que es: decoración.
9706
+ *
9707
+ * El suelo existe por lo contrario: un `primary` casi gris da tres tonos que no se
9708
+ * distinguen entre sí, y entonces no hay degradado que ver —el aura se lee como una
9709
+ * mancha plana—.
9710
+ */
9711
+ var BANDA_SATURACION = { min: 35, max: 65 };
9712
+ var VUELTA = 360;
9713
+ /** `H S% L%` — el formato exacto en el que HeroUI guarda sus variables de color. */
9714
+ var TRIPLETE = /^\s*(-?\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*$/;
9715
+ /**
9716
+ * Lee el triplete que HeroUI deja en una variable de color.
9717
+ *
9718
+ * Devuelve `null` en vez de lanzar: esto corre en un efecto de tema y el valor puede
9719
+ * no estar todavía —la clase del tema aún no está en el `<html>`, o el consumidor no
9720
+ * cargó la hoja de estilos—. Un aura que no se pinta es un problema menor; una
9721
+ * excepción que tumba el provider de tema, no.
9722
+ */
9723
+ function parseHslTriplet(value) {
9724
+ var encontrado = TRIPLETE.exec(value);
9725
+ if (!encontrado) {
9726
+ return null;
9727
+ }
9728
+ var h = encontrado[1], s = encontrado[2], l = encontrado[3];
9729
+ return { h: Number(h), s: Number(s), l: Number(l) };
9730
+ }
9731
+ /** Deja un ángulo dentro de `[0, 360)`, venga de donde venga. */
9732
+ function normalizarTono(grados) {
9733
+ return ((grados % VUELTA) + VUELTA) % VUELTA;
9734
+ }
9735
+ function acotar(valor, min, max) {
9736
+ return Math.min(Math.max(valor, min), max);
9737
+ }
9738
+ /**
9739
+ * Los tres tonos del aura, listos para escribirse en una variable CSS.
9740
+ *
9741
+ * Se redondean a entero: es un degradado decorativo, y las décimas de grado solo
9742
+ * alargan la hoja de estilos.
9743
+ */
9744
+ function deriveLindaTones(primary) {
9745
+ var luz = Math.round(acotar(primary.l, BANDA_LUZ.min, BANDA_LUZ.max));
9746
+ var saturacion = Math.round(acotar(primary.s, BANDA_SATURACION.min, BANDA_SATURACION.max));
9747
+ var tonos = GIROS.map(function (giro) {
9748
+ return "".concat(Math.round(normalizarTono(primary.h + giro)), " ").concat(saturacion, "% ").concat(luz, "%");
9749
+ });
9750
+ return tonos;
9751
+ }
9752
+ /** Las variables que se escriben en el `<html>`, en el orden en que se pintan. */
9753
+ var LINDA_TONE_PROPERTIES = [
9754
+ "--linda-1",
9755
+ "--linda-2",
9756
+ "--linda-3",
9757
+ ];
9758
+ /**
9759
+ * Escribe los tres tonos del aura a partir del valor de `--heroui-primary`.
9760
+ *
9761
+ * Si el primary no se puede leer, **borra los que hubiera** y devuelve `false`. Es lo
9762
+ * contrario de dejarlos: unos tonos viejos son de otro tema, y un aura del color
9763
+ * anterior es peor que un aura que no se pinta —la CSS del efecto ya está escrita para
9764
+ * desaparecer sin sus variables—.
9765
+ */
9766
+ function applyLindaTones(style, primaryValue) {
9767
+ var primary = parseHslTriplet(primaryValue);
9768
+ if (!primary) {
9769
+ removeLindaTones(style);
9770
+ return false;
9771
+ }
9772
+ var tonos = deriveLindaTones(primary);
9773
+ LINDA_TONE_PROPERTIES.forEach(function (propiedad, indice) {
9774
+ style.setProperty(propiedad, tonos[indice]);
9775
+ });
9776
+ return true;
9777
+ }
9778
+ /** Quita los tres tonos del aura. */
9779
+ function removeLindaTones(style) {
9780
+ for (var _i = 0, LINDA_TONE_PROPERTIES_1 = LINDA_TONE_PROPERTIES; _i < LINDA_TONE_PROPERTIES_1.length; _i++) {
9781
+ var propiedad = LINDA_TONE_PROPERTIES_1[_i];
9782
+ style.removeProperty(propiedad);
9783
+ }
9784
+ }
9785
+
9641
9786
  /**
9642
9787
  * Custom hook to manage the theme state and side effects.
9643
9788
  * Supports both named ThemeColor values and arbitrary hex colors.
@@ -9683,6 +9828,30 @@ var useThemeManager = function () {
9683
9828
  removeCustomPrimaryColor();
9684
9829
  }
9685
9830
  }, [customHex, mode]);
9831
+ /*
9832
+ * Los tres tonos del aura de Linda, derivados del primary que acaba de quedar fijado.
9833
+ *
9834
+ * Va DESPUÉS de los dos efectos de arriba y depende de lo mismo que ellos, que es lo
9835
+ * que garantiza que lea el primary definitivo: React ejecuta los efectos en orden de
9836
+ * declaración, así que aquí la clase del tema ya está en el `<html>` y el hex a medida
9837
+ * ya está escrito o retirado.
9838
+ *
9839
+ * Se lee del estilo COMPUTADO y no de `customHex` a propósito: el primary llega por
9840
+ * dos caminos —el hex del negocio o la clase de una de las familias de tema— y el
9841
+ * computado es el único sitio donde los dos han convergido. Derivarlo solo de
9842
+ * `customHex` dejaría sin aura a toda agencia que use una familia tal cual.
9843
+ */
9844
+ /*
9845
+ * `customHex` y `rawTheme` están en la lista aunque el cuerpo no los lea: son la señal
9846
+ * de que el `<html>` acaba de cambiar. La entrada real de este efecto es el estilo
9847
+ * computado, que la regla no puede ver, y sin ellos el aura se quedaría con los tonos
9848
+ * del tema anterior.
9849
+ */
9850
+ // biome-ignore lint/correctness/useExhaustiveDependencies: ver el comentario de arriba
9851
+ React.useEffect(function () {
9852
+ var html = document.documentElement;
9853
+ applyLindaTones(html.style, getComputedStyle(html).getPropertyValue("--heroui-primary"));
9854
+ }, [customHex, rawTheme]);
9686
9855
  var setMode = React.useCallback(function (newMode) {
9687
9856
  var effectiveMode = newMode === "dark" ? "light" : newMode;
9688
9857
  var newTheme = color === "blue" ? effectiveMode : "".concat(color, "-").concat(effectiveMode);
@@ -9855,6 +10024,7 @@ exports.InputPassword = InputPassword;
9855
10024
  exports.Kanban = Kanban;
9856
10025
  exports.KanbanCard = KanbanCard;
9857
10026
  exports.KanbanColumn = KanbanColumn;
10027
+ exports.LINDA_TONE_PROPERTIES = LINDA_TONE_PROPERTIES;
9858
10028
  exports.LindaIcon = LindaIcon;
9859
10029
  exports.MenuClaw = MenuClaw;
9860
10030
  exports.MenuComponent = MenuComponent;
@@ -9905,6 +10075,7 @@ exports.Wizard = Wizard;
9905
10075
  exports.WizardNavigation = WizardNavigation;
9906
10076
  exports.WizardSidebar = WizardSidebar;
9907
10077
  exports.applyCustomPrimaryColor = applyCustomPrimaryColor;
10078
+ exports.applyLindaTones = applyLindaTones;
9908
10079
  exports.computeBars = computeBars;
9909
10080
  exports.computeMax = computeMax;
9910
10081
  exports.computeSlices = computeSlices;
@@ -9914,6 +10085,7 @@ exports.createCurrencyFormatter = createCurrencyFormatter;
9914
10085
  exports.defaultCountries = uniqueCountries;
9915
10086
  exports.defaultCurrencyOptions = defaultCurrencyOptions;
9916
10087
  exports.defaultTranslations = defaultTranslations$5;
10088
+ exports.deriveLindaTones = deriveLindaTones;
9917
10089
  exports.dismissControlProps = dismissControlProps;
9918
10090
  exports.forceLightOnlyThemeBeforeReact = forceLightOnlyThemeBeforeReact;
9919
10091
  exports.formatAuroraThemeTooltip = formatAuroraThemeTooltip;
@@ -9931,7 +10103,9 @@ exports.isGroupState = isGroupState;
9931
10103
  exports.isHexColor = isHexColor;
9932
10104
  exports.isRankedBarListEmpty = isRankedBarListEmpty;
9933
10105
  exports.isSegmentationGroup = isSegmentationGroup;
10106
+ exports.parseHslTriplet = parseHslTriplet;
9934
10107
  exports.removeCustomPrimaryColor = removeCustomPrimaryColor;
10108
+ exports.removeLindaTones = removeLindaTones;
9935
10109
  exports.shouldClosePopoverOnInteractOutside = shouldClosePopoverOnInteractOutside;
9936
10110
  exports.sizeMap = sizeMap;
9937
10111
  exports.themeColors = themeColors;
package/dist/index.esm.js CHANGED
@@ -285,6 +285,10 @@ var HolidayType;
285
285
  HolidayType["DateRange"] = "dateRange";
286
286
  })(HolidayType || (HolidayType = {}));
287
287
 
288
+ var CLASE_AURA = {
289
+ ring: "linda-aura-ring",
290
+ surface: "linda-aura",
291
+ };
288
292
  /**
289
293
  * Botón genérico basado en HeroUI siguiendo las reglas de diseño BeweOS.
290
294
  *
@@ -295,10 +299,24 @@ var HolidayType;
295
299
  * - isLoading: On, Off
296
300
  * - Radius: md (por defecto)
297
301
  * - isIconOnly: True, False
302
+ * - ai: aura de Linda para las acciones que hace la IA (ver `Button.types.ts`)
298
303
  */
299
304
  var Button = function (_a) {
300
- var _b = _a.color, color = _b === void 0 ? "primary" : _b, _c = _a.size, size = _c === void 0 ? "md" : _c, _d = _a.variant, variant = _d === void 0 ? "solid" : _d, _e = _a.radius, radius = _e === void 0 ? "sm" : _e, startContent = _a.startContent, endContent = _a.endContent, _f = _a.isLoading, isLoading = _f === void 0 ? false : _f, _g = _a.isIconOnly, isIconOnly = _g === void 0 ? false : _g, props = __rest(_a, ["color", "size", "variant", "radius", "startContent", "endContent", "isLoading", "isIconOnly"]);
301
- return (jsx(Button$1, __assign({}, props, { color: color, size: size, variant: variant, radius: radius, startContent: startContent, endContent: endContent, isLoading: isLoading, isIconOnly: isIconOnly })));
305
+ var _b = _a.color, color = _b === void 0 ? "primary" : _b, _c = _a.size, size = _c === void 0 ? "md" : _c, _d = _a.variant, variant = _d === void 0 ? "solid" : _d, _e = _a.radius, radius = _e === void 0 ? "sm" : _e, startContent = _a.startContent, endContent = _a.endContent, _f = _a.isLoading, isLoading = _f === void 0 ? false : _f, _g = _a.isIconOnly, isIconOnly = _g === void 0 ? false : _g, ai = _a.ai, className = _a.className, children = _a.children, props = __rest(_a, ["color", "size", "variant", "radius", "startContent", "endContent", "isLoading", "isIconOnly", "ai", "className", "children"]);
306
+ /*
307
+ * El contenido se envuelve para poder subirlo por encima del aura.
308
+ *
309
+ * Y tiene que ser un elemento: `<Button>Crear campaña</Button>` pasa un NODO DE
310
+ * TEXTO, que no es posicionable, así que ningún selector puede sacarlo del fondo del
311
+ * apilado —el aura, que sí está posicionada, le pasaría por encima—. Con `ring` daría
312
+ * igual porque esa capa es solo el canto; con `surface` el texto se leería a través
313
+ * del degradado.
314
+ */
315
+ var contenido = ai ? (jsx("span", { className: "linda-aura-content", children: children })) : (children);
316
+ var clases = [ai ? CLASE_AURA[ai] : "", className]
317
+ .filter(Boolean)
318
+ .join(" ");
319
+ return (jsx(Button$1, __assign({}, props, { color: color, size: size, variant: variant, radius: radius, startContent: startContent, endContent: endContent, isLoading: isLoading, isIconOnly: isIconOnly, className: clases || undefined, children: contenido })));
302
320
  };
303
321
 
304
322
  var DatePicker = function (_a) {
@@ -3937,8 +3955,10 @@ var DEFAULT_HISTORY_VISIBLE_COUNT = 5;
3937
3955
  */
3938
3956
  var MenuClaw = React.memo(function MenuClaw(_a) {
3939
3957
  var _b, _c;
3940
- var userInfo = _a.userInfo, helpButton = _a.helpButton, menuItems = _a.menuItems, history = _a.history, isOpenSidebar = _a.isOpenSidebar, onOpenSidebarChange = _a.onOpenSidebarChange, mobileBottomBarGroupKey = _a.mobileBottomBarGroupKey, _d = _a.showNativeMenu, showNativeMenu = _d === void 0 ? true : _d, _e = _a.translations, translations = _e === void 0 ? {} : _e;
3941
- var _f = React.useState(false), isCollapsed = _f[0], setIsCollapsed = _f[1];
3958
+ var userInfo = _a.userInfo, helpButton = _a.helpButton, menuItems = _a.menuItems, history = _a.history, isOpenSidebar = _a.isOpenSidebar, onOpenSidebarChange = _a.onOpenSidebarChange, mobileBottomBarGroupKey = _a.mobileBottomBarGroupKey, _d = _a.showNativeMenu, showNativeMenu = _d === void 0 ? true : _d, _e = _a.translations, translations = _e === void 0 ? {} : _e, isCollapsedProp = _a.isCollapsed, onCollapsedChange = _a.onCollapsedChange, defaultCollapsed = _a.defaultCollapsed;
3959
+ var isControlled = isCollapsedProp !== undefined;
3960
+ var _f = React.useState(defaultCollapsed !== null && defaultCollapsed !== void 0 ? defaultCollapsed : false), internalCollapsed = _f[0], setInternalCollapsed = _f[1];
3961
+ var collapsed = isCollapsedProp !== null && isCollapsedProp !== void 0 ? isCollapsedProp : internalCollapsed;
3942
3962
  var t = __assign(__assign({}, DEFAULT_TRANSLATIONS$7), translations);
3943
3963
  var selectedKey = useMemo(function () {
3944
3964
  var _a, _b, _c;
@@ -3987,8 +4007,12 @@ var MenuClaw = React.memo(function MenuClaw(_a) {
3987
4007
  onOpenSidebarChange === null || onOpenSidebarChange === void 0 ? void 0 : onOpenSidebarChange(true);
3988
4008
  }, [onOpenSidebarChange]);
3989
4009
  var handleCollapseToggle = useCallback(function () {
3990
- setIsCollapsed(function (prev) { return !prev; });
3991
- }, []);
4010
+ var next = !collapsed;
4011
+ if (!isControlled) {
4012
+ setInternalCollapsed(next);
4013
+ }
4014
+ onCollapsedChange === null || onCollapsedChange === void 0 ? void 0 : onCollapsedChange(next);
4015
+ }, [collapsed, isControlled, onCollapsedChange]);
3992
4016
  var handleHelpClick = useCallback(function () {
3993
4017
  if (helpSection) {
3994
4018
  window.open(helpSection.redirect, "_blank");
@@ -4007,12 +4031,12 @@ var MenuClaw = React.memo(function MenuClaw(_a) {
4007
4031
  (_a = menuItems.onSelect) === null || _a === void 0 ? void 0 : _a.call(menuItems, key, href, "bottomBar");
4008
4032
  }, [onOpenSidebarChange, menuItems.onSelect]);
4009
4033
  var showBottomBar = (mobileBottomBarGroupKey && bottomBarItems.length > 0) || showNativeMenu;
4010
- return (jsxs(Fragment, { children: [showBottomBar ? (jsx(MenuMobileBottomBar, { items: bottomBarItems, selectedKey: selectedKey, onSelect: handleBottomBarSelect, onMenuPress: handleSidebarOpen, menuLabel: t.menuLabel, navAriaLabel: t.mobileNavAriaLabel, forceVisible: showNativeMenu && bottomBarItems.length === 0 })) : null, jsx("button", { type: "button", "aria-label": t.closeSidebarAriaLabel, className: "menu-claw-overlay ".concat(isOpenSidebar ? "menu-claw-overlay--open" : ""), onClick: handleSidebarClose, tabIndex: isOpenSidebar ? 0 : -1 }), jsx("div", { className: cn("menu-claw", isCollapsed ? "menu-claw--collapsed" : "menu-claw--expanded", isOpenSidebar && "menu-claw--mobile-open"), "aria-hidden": !isOpenSidebar, children: jsxs("div", { className: "menu-claw__content", children: [jsxs("div", { className: cn("flex items-center", isCollapsed ? "justify-center" : "justify-end"), children: [jsx(IconComponent, { icon: "material-symbols-light:close", size: "lg", className: "block cursor-pointer sm:hidden", onClick: handleSidebarClose }), jsx("button", { type: "button", "aria-label": t.toggleSidebarAriaLabel, onClick: handleCollapseToggle, className: "hidden h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-lg text-default-500 transition-colors hover:bg-default-100 sm:flex", children: jsx(IconComponent, { icon: isCollapsed
4034
+ return (jsxs(Fragment, { children: [showBottomBar ? (jsx(MenuMobileBottomBar, { items: bottomBarItems, selectedKey: selectedKey, onSelect: handleBottomBarSelect, onMenuPress: handleSidebarOpen, menuLabel: t.menuLabel, navAriaLabel: t.mobileNavAriaLabel, forceVisible: showNativeMenu && bottomBarItems.length === 0 })) : null, jsx("button", { type: "button", "aria-label": t.closeSidebarAriaLabel, className: "menu-claw-overlay ".concat(isOpenSidebar ? "menu-claw-overlay--open" : ""), onClick: handleSidebarClose, tabIndex: isOpenSidebar ? 0 : -1 }), jsx("div", { className: cn("menu-claw", collapsed ? "menu-claw--collapsed" : "menu-claw--expanded", isOpenSidebar && "menu-claw--mobile-open"), "aria-hidden": !isOpenSidebar, children: jsxs("div", { className: "menu-claw__content", children: [jsxs("div", { className: cn("flex items-center", collapsed ? "justify-center" : "justify-end"), children: [jsx(IconComponent, { icon: "material-symbols-light:close", size: "lg", className: "block cursor-pointer sm:hidden", onClick: handleSidebarClose }), jsx("button", { type: "button", "aria-label": t.toggleSidebarAriaLabel, onClick: handleCollapseToggle, className: "hidden h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-lg text-default-500 transition-colors hover:bg-default-100 sm:flex", children: jsx(IconComponent, { icon: collapsed
4011
4035
  ? "solar:alt-arrow-right-linear"
4012
- : "solar:alt-arrow-left-linear", size: "md", "aria-hidden": true }) })] }), jsxs("div", { className: cn("flex items-center py-3", isCollapsed ? "justify-center gap-0" : "gap-3"), children: [jsx(Avatar, { size: "sm", src: ((_b = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, color: !((_c = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _c === void 0 ? void 0 : _c.trim()) ? "warning" : "default", name: userName, className: "shrink-0" }), !isCollapsed ? (jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsx("p", { className: "truncate text-small font-semibold text-foreground", children: userName }), jsx("p", { className: "truncate text-tiny text-default-400", children: userRole })] })) : null] }), jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history === null || history === void 0 ? void 0 : history.onNewConversation, isCollapsed: isCollapsed, 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(function (group) {
4036
+ : "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: [jsx(Avatar, { size: "sm", src: ((_b = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _b === void 0 ? void 0 : _b.trim()) || undefined, color: !((_c = userInfo === null || userInfo === void 0 ? void 0 : userInfo.avatar) === null || _c === void 0 ? void 0 : _c.trim()) ? "warning" : "default", name: userName, className: "shrink-0" }), !collapsed ? (jsxs("div", { className: "menu-claw-collapsible flex min-w-0 flex-col overflow-hidden", children: [jsx("p", { className: "truncate text-small font-semibold text-foreground", children: userName }), jsx("p", { className: "truncate text-tiny text-default-400", children: userRole })] })) : null] }), jsx(MenuClawHistoryPanel, { items: historyConfig.items, initialVisibleCount: historyConfig.initialVisibleCount, onNewConversation: history === null || history === void 0 ? void 0 : 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(function (group) {
4013
4037
  var _a;
4014
- return (jsxs("div", { className: "mb-2", children: [group.title && !isCollapsed ? (jsx("p", { className: "px-2 pb-1 pt-2 text-tiny font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsx("ul", { className: "flex flex-col gap-0.5", children: ((_a = group.items) !== null && _a !== void 0 ? _a : []).map(function (item) { return (jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: isCollapsed, onSelect: handleMenuSelect }, item.key)); }) })] }, group.key));
4015
- }) }), helpSection ? (jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsx(Button$1, { fullWidth: true, className: "text-default-500 data-[hover=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: "menu-claw-collapsible truncate", children: helpSection.title })) : null }) })) : null] }) })] }));
4038
+ return (jsxs("div", { className: "mb-2", children: [group.title && !collapsed ? (jsx("p", { className: "px-2 pb-1 pt-2 text-tiny font-medium uppercase tracking-wide text-default-400", children: group.title })) : null, jsx("ul", { className: "flex flex-col gap-0.5", children: ((_a = group.items) !== null && _a !== void 0 ? _a : []).map(function (item) { return (jsx(MenuClawNavItem, { item: item, selectedKey: selectedKey, isCollapsed: collapsed, onSelect: handleMenuSelect }, item.key)); }) })] }, group.key));
4039
+ }) }), helpSection ? (jsx("div", { className: "mt-auto flex flex-col items-center justify-center", children: jsx(Button$1, { fullWidth: true, className: "text-default-500 data-[hover=true]:text-default-600", startContent: jsx(IconComponent, { className: "text-default-500", icon: "solar:info-circle-line-duotone", size: "md" }), variant: "light", onPress: handleHelpClick, isIconOnly: collapsed, children: !collapsed ? (jsx("span", { className: "menu-claw-collapsible truncate", children: helpSection.title })) : null }) })) : null] }) })] }));
4016
4040
  });
4017
4041
 
4018
4042
  /**
@@ -9639,6 +9663,127 @@ function removeCustomPrimaryColor() {
9639
9663
  }
9640
9664
  }
9641
9665
 
9666
+ /**
9667
+ * Los tres tonos del aura de Linda, derivados del `primary` de la agencia.
9668
+ *
9669
+ * Linda no tiene color propio: es el `primary` que el negocio eligió en el onboarding,
9670
+ * y por eso aquí no hay ni un color escrito. Lo único que se fija es CUÁNTO se gira ese
9671
+ * tono y en qué banda de luz se pinta.
9672
+ */
9673
+ /**
9674
+ * Grados que se gira el `primary` para cada tono, en el orden en que se pintan.
9675
+ *
9676
+ * Son muchos grados a propósito. La gracia del aura es que haya MÁS DE UN COLOR: con
9677
+ * un giro discreto —del orden de 18°, el que usa un degradado de profundidad— salen
9678
+ * tres versiones del mismo tono y el resultado se lee como un plano. A ±55° el salto
9679
+ * se ve como otro color y sigue dentro de la familia del `primary`, que es lo que
9680
+ * permite que esto funcione con la agencia número siete sin tocar nada.
9681
+ *
9682
+ * El tono del medio va casi sin girar: es el que ancla el conjunto al color de la
9683
+ * agencia, para que el aura se lea como suya y no como una decoración pegada encima.
9684
+ */
9685
+ var GIROS = [-56, 8, 54];
9686
+ /**
9687
+ * Banda de luz en la que se pintan los tres tonos, en porcentaje HSL.
9688
+ *
9689
+ * Los tonos NO heredan la luz del `primary`, y esto es lo que más se nota: un primary
9690
+ * oscuro y poco saturado sobre una superficie clara se lee como una mancha gris —sucia,
9691
+ * no como color—, y uno casi blanco desaparece contra el fondo. Se llevan al paso medio
9692
+ * de la escala, que es el que funciona en los dos casos.
9693
+ */
9694
+ var BANDA_LUZ = { min: 52, max: 72 };
9695
+ /**
9696
+ * Banda de saturación de los tres tonos, en porcentaje HSL.
9697
+ *
9698
+ * El techo es lo que evita que el aura grite. A plena saturación los tonos dejan de ser
9699
+ * ambiente y pasan a ser tres focos de color encima de un control de 40 pt: bonito en
9700
+ * una captura, insoportable en una barra que se mira todo el día.
9701
+ *
9702
+ * ⚠️ **Y hay una razón que no es estética.** Girar el tono puede caer en un rojo vivo:
9703
+ * un `primary` amarillo —51°— girado −56° aterriza en 355°, que a saturación 100 se lee
9704
+ * como un estado de error alrededor de un botón que no ha fallado. Visto al renderizarlo,
9705
+ * no razonándolo. Bajado a 65 el mismo tono es un rosa apagado y vuelve a leerse como lo
9706
+ * que es: decoración.
9707
+ *
9708
+ * El suelo existe por lo contrario: un `primary` casi gris da tres tonos que no se
9709
+ * distinguen entre sí, y entonces no hay degradado que ver —el aura se lee como una
9710
+ * mancha plana—.
9711
+ */
9712
+ var BANDA_SATURACION = { min: 35, max: 65 };
9713
+ var VUELTA = 360;
9714
+ /** `H S% L%` — el formato exacto en el que HeroUI guarda sus variables de color. */
9715
+ var TRIPLETE = /^\s*(-?\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*$/;
9716
+ /**
9717
+ * Lee el triplete que HeroUI deja en una variable de color.
9718
+ *
9719
+ * Devuelve `null` en vez de lanzar: esto corre en un efecto de tema y el valor puede
9720
+ * no estar todavía —la clase del tema aún no está en el `<html>`, o el consumidor no
9721
+ * cargó la hoja de estilos—. Un aura que no se pinta es un problema menor; una
9722
+ * excepción que tumba el provider de tema, no.
9723
+ */
9724
+ function parseHslTriplet(value) {
9725
+ var encontrado = TRIPLETE.exec(value);
9726
+ if (!encontrado) {
9727
+ return null;
9728
+ }
9729
+ var h = encontrado[1], s = encontrado[2], l = encontrado[3];
9730
+ return { h: Number(h), s: Number(s), l: Number(l) };
9731
+ }
9732
+ /** Deja un ángulo dentro de `[0, 360)`, venga de donde venga. */
9733
+ function normalizarTono(grados) {
9734
+ return ((grados % VUELTA) + VUELTA) % VUELTA;
9735
+ }
9736
+ function acotar(valor, min, max) {
9737
+ return Math.min(Math.max(valor, min), max);
9738
+ }
9739
+ /**
9740
+ * Los tres tonos del aura, listos para escribirse en una variable CSS.
9741
+ *
9742
+ * Se redondean a entero: es un degradado decorativo, y las décimas de grado solo
9743
+ * alargan la hoja de estilos.
9744
+ */
9745
+ function deriveLindaTones(primary) {
9746
+ var luz = Math.round(acotar(primary.l, BANDA_LUZ.min, BANDA_LUZ.max));
9747
+ var saturacion = Math.round(acotar(primary.s, BANDA_SATURACION.min, BANDA_SATURACION.max));
9748
+ var tonos = GIROS.map(function (giro) {
9749
+ return "".concat(Math.round(normalizarTono(primary.h + giro)), " ").concat(saturacion, "% ").concat(luz, "%");
9750
+ });
9751
+ return tonos;
9752
+ }
9753
+ /** Las variables que se escriben en el `<html>`, en el orden en que se pintan. */
9754
+ var LINDA_TONE_PROPERTIES = [
9755
+ "--linda-1",
9756
+ "--linda-2",
9757
+ "--linda-3",
9758
+ ];
9759
+ /**
9760
+ * Escribe los tres tonos del aura a partir del valor de `--heroui-primary`.
9761
+ *
9762
+ * Si el primary no se puede leer, **borra los que hubiera** y devuelve `false`. Es lo
9763
+ * contrario de dejarlos: unos tonos viejos son de otro tema, y un aura del color
9764
+ * anterior es peor que un aura que no se pinta —la CSS del efecto ya está escrita para
9765
+ * desaparecer sin sus variables—.
9766
+ */
9767
+ function applyLindaTones(style, primaryValue) {
9768
+ var primary = parseHslTriplet(primaryValue);
9769
+ if (!primary) {
9770
+ removeLindaTones(style);
9771
+ return false;
9772
+ }
9773
+ var tonos = deriveLindaTones(primary);
9774
+ LINDA_TONE_PROPERTIES.forEach(function (propiedad, indice) {
9775
+ style.setProperty(propiedad, tonos[indice]);
9776
+ });
9777
+ return true;
9778
+ }
9779
+ /** Quita los tres tonos del aura. */
9780
+ function removeLindaTones(style) {
9781
+ for (var _i = 0, LINDA_TONE_PROPERTIES_1 = LINDA_TONE_PROPERTIES; _i < LINDA_TONE_PROPERTIES_1.length; _i++) {
9782
+ var propiedad = LINDA_TONE_PROPERTIES_1[_i];
9783
+ style.removeProperty(propiedad);
9784
+ }
9785
+ }
9786
+
9642
9787
  /**
9643
9788
  * Custom hook to manage the theme state and side effects.
9644
9789
  * Supports both named ThemeColor values and arbitrary hex colors.
@@ -9684,6 +9829,30 @@ var useThemeManager = function () {
9684
9829
  removeCustomPrimaryColor();
9685
9830
  }
9686
9831
  }, [customHex, mode]);
9832
+ /*
9833
+ * Los tres tonos del aura de Linda, derivados del primary que acaba de quedar fijado.
9834
+ *
9835
+ * Va DESPUÉS de los dos efectos de arriba y depende de lo mismo que ellos, que es lo
9836
+ * que garantiza que lea el primary definitivo: React ejecuta los efectos en orden de
9837
+ * declaración, así que aquí la clase del tema ya está en el `<html>` y el hex a medida
9838
+ * ya está escrito o retirado.
9839
+ *
9840
+ * Se lee del estilo COMPUTADO y no de `customHex` a propósito: el primary llega por
9841
+ * dos caminos —el hex del negocio o la clase de una de las familias de tema— y el
9842
+ * computado es el único sitio donde los dos han convergido. Derivarlo solo de
9843
+ * `customHex` dejaría sin aura a toda agencia que use una familia tal cual.
9844
+ */
9845
+ /*
9846
+ * `customHex` y `rawTheme` están en la lista aunque el cuerpo no los lea: son la señal
9847
+ * de que el `<html>` acaba de cambiar. La entrada real de este efecto es el estilo
9848
+ * computado, que la regla no puede ver, y sin ellos el aura se quedaría con los tonos
9849
+ * del tema anterior.
9850
+ */
9851
+ // biome-ignore lint/correctness/useExhaustiveDependencies: ver el comentario de arriba
9852
+ useEffect(function () {
9853
+ var html = document.documentElement;
9854
+ applyLindaTones(html.style, getComputedStyle(html).getPropertyValue("--heroui-primary"));
9855
+ }, [customHex, rawTheme]);
9687
9856
  var setMode = useCallback(function (newMode) {
9688
9857
  var effectiveMode = newMode === "dark" ? "light" : newMode;
9689
9858
  var newTheme = color === "blue" ? effectiveMode : "".concat(color, "-").concat(effectiveMode);
@@ -9805,4 +9974,4 @@ var NavigationLoadingProvider = function (_a) {
9805
9974
  return (jsxs(NavigationLoadingContext.Provider, { value: value, children: [children, jsx(NavigationLoadingOverlay, { isVisible: isVisible })] }));
9806
9975
  };
9807
9976
 
9808
- export { ALL_THEMES, AURORA_THEME_FAMILIES, AURORA_THEME_REGISTRY, AccordionList, AddHolidayForm, AnalyticsCard, AreaLineChart, AuraAutocomplete, AuraTable, AuraToastProvider, BEWEOS_THEME_MODE_COOKIE_NAME, BreadcrumbsComponent, Button, CONTAINER_ATTRIBUTE, Card, Chip, ColorPicker, ColorSelector, ContentCarousel, Currency, DEFAULT_DONUT_COLORS, DEFAULT_PREDEFINED_COLORS, DEFAULT_RANKED_BAR_COLORS, DISMISS_CONTROL_ATTRIBUTE, DatePicker, DateRangePicker, DateSelector, DonutChart, DrawerFilters, EmailPreview, EnumMenuNavListItem, GlobalToast, H1, H2, H3, H4, HeaderComponent, HolidayType, IconComponent, ImagePreview, Input, InputPassword, Kanban, KanbanCard, KanbanColumn, LindaIcon, MenuClaw, MenuComponent, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, MultiStepWizard, NavigationLoadingContext, NavigationLoadingOverlay, NavigationLoadingProvider, P, Pagination, Phone, PromotionalBanner, REGISTERED_THEME_COLORS, RangeFilter, RankedBarList, RowSteps, DEFAULT_TRANSLATIONS$1 as SEGMENTATION_DEFAULT_TRANSLATIONS, ScheduleRow, SearchInput, SegmentationBuilder, Select, SimpleLineChart, SocialMediaBar, SocialMediaCarousel, SocialMediaPreview, StatTile, StepIndicator, Switch as SwitchComponent, THEME_COLOR_HEX_MAP, TagsFilter, Textarea, ThemeContext, ThemePicker, ThemeProvider, TimeInput as TimeInputComponent, ToastContext, Tooltip, TwoColumnLayoutAgent, UploadFile, VerticalSteps, ViolinPlot, WhatsAppPreview, Wizard, WizardNavigation, WizardSidebar, applyCustomPrimaryColor, computeBars, computeMax, computeSlices, computeTotal, containerProps, createCurrencyFormatter, uniqueCountries as defaultCountries, defaultCurrencyOptions, defaultTranslations$5 as defaultTranslations, dismissControlProps, forceLightOnlyThemeBeforeReact, formatAuroraThemeTooltip, generateThemeColorScale, getContrastForeground, getRegisteredThemeColorBases, getSelectedKeyFromPath, hexToThemeColor, hslToCssValue, isAuroraFullThemeId, isDismissControl, isDonutEmpty, isExactThemeColor, isGroupState, isHexColor, isRankedBarListEmpty, isSegmentationGroup, removeCustomPrimaryColor, shouldClosePopoverOnInteractOutside, sizeMap, themeColors, useAuraToast, useCloseOnAncestorScroll, useMediaQuery, useNavigationLoading, useThemeContext };
9977
+ export { ALL_THEMES, AURORA_THEME_FAMILIES, AURORA_THEME_REGISTRY, AccordionList, AddHolidayForm, AnalyticsCard, AreaLineChart, AuraAutocomplete, AuraTable, AuraToastProvider, BEWEOS_THEME_MODE_COOKIE_NAME, BreadcrumbsComponent, Button, CONTAINER_ATTRIBUTE, Card, Chip, ColorPicker, ColorSelector, ContentCarousel, Currency, DEFAULT_DONUT_COLORS, DEFAULT_PREDEFINED_COLORS, DEFAULT_RANKED_BAR_COLORS, DISMISS_CONTROL_ATTRIBUTE, DatePicker, DateRangePicker, DateSelector, DonutChart, DrawerFilters, EmailPreview, EnumMenuNavListItem, GlobalToast, H1, H2, H3, H4, HeaderComponent, HolidayType, IconComponent, ImagePreview, Input, InputPassword, Kanban, KanbanCard, KanbanColumn, LINDA_TONE_PROPERTIES, LindaIcon, MenuClaw, MenuComponent, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, MultiStepWizard, NavigationLoadingContext, NavigationLoadingOverlay, NavigationLoadingProvider, P, Pagination, Phone, PromotionalBanner, REGISTERED_THEME_COLORS, RangeFilter, RankedBarList, RowSteps, DEFAULT_TRANSLATIONS$1 as SEGMENTATION_DEFAULT_TRANSLATIONS, ScheduleRow, SearchInput, SegmentationBuilder, Select, SimpleLineChart, SocialMediaBar, SocialMediaCarousel, SocialMediaPreview, StatTile, StepIndicator, Switch as SwitchComponent, THEME_COLOR_HEX_MAP, TagsFilter, Textarea, ThemeContext, ThemePicker, ThemeProvider, TimeInput as TimeInputComponent, ToastContext, Tooltip, TwoColumnLayoutAgent, UploadFile, VerticalSteps, ViolinPlot, WhatsAppPreview, Wizard, WizardNavigation, WizardSidebar, applyCustomPrimaryColor, applyLindaTones, computeBars, computeMax, computeSlices, computeTotal, containerProps, createCurrencyFormatter, uniqueCountries as defaultCountries, defaultCurrencyOptions, defaultTranslations$5 as defaultTranslations, deriveLindaTones, dismissControlProps, forceLightOnlyThemeBeforeReact, formatAuroraThemeTooltip, generateThemeColorScale, getContrastForeground, getRegisteredThemeColorBases, getSelectedKeyFromPath, hexToThemeColor, hslToCssValue, isAuroraFullThemeId, isDismissControl, isDonutEmpty, isExactThemeColor, isGroupState, isHexColor, isRankedBarListEmpty, isSegmentationGroup, parseHslTriplet, removeCustomPrimaryColor, removeLindaTones, shouldClosePopoverOnInteractOutside, sizeMap, themeColors, useAuraToast, useCloseOnAncestorScroll, useMediaQuery, useNavigationLoading, useThemeContext };
@@ -10,6 +10,7 @@ import type { ButtonProps } from "./Button.types";
10
10
  * - isLoading: On, Off
11
11
  * - Radius: md (por defecto)
12
12
  * - isIconOnly: True, False
13
+ * - ai: aura de Linda para las acciones que hace la IA (ver `Button.types.ts`)
13
14
  */
14
15
  export declare const Button: React.FC<ButtonProps>;
15
16
  //# sourceMappingURL=Button.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/Button.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAwBxC,CAAC"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../../src/components/button/Button.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAOlD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAiDxC,CAAC"}
@@ -9,5 +9,20 @@ export type ButtonProps = Omit<HeroUIButtonProps, "color" | "size" | "variant" |
9
9
  endContent?: React.ReactNode;
10
10
  isLoading?: boolean;
11
11
  isIconOnly?: boolean;
12
+ /**
13
+ * Marca el botón como algo que hace la IA, con el aura viva de Linda.
14
+ *
15
+ * Los tres tonos salen del `primary` de la agencia, así que esto NO fija un color:
16
+ * en una agencia de marca amarilla el aura es amarilla. Los escribe el
17
+ * `ThemeProvider`; sin él, el aura sale monocroma en vez de no salir.
18
+ *
19
+ * - `"ring"` mueve solo el canto y deja el relleno intacto. Es la que va en un
20
+ * botón de acento pleno —un CTA como «Crear campaña»—: al no tocar el fondo, el
21
+ * contraste del texto no cambia.
22
+ * - `"surface"` pinta el degradado dentro. **Pide un fondo claro**: `bordered`,
23
+ * `flat` o `light`. Sobre `solid` los tonos aclaran el relleno y el texto se
24
+ * queda sin contraste.
25
+ */
26
+ ai?: "ring" | "surface";
12
27
  };
13
28
  //# sourceMappingURL=Button.types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../../src/components/button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,WAAW,GAAG,IAAI,CAC7B,iBAAiB,EACjB,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CACvC,GAAG;IACH,KAAK,CAAC,EACH,SAAS,GACT,SAAS,GACT,WAAW,GACX,SAAS,GACT,SAAS,GACT,QAAQ,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EACL,OAAO,GACP,UAAU,GACV,OAAO,GACP,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAC9C,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC"}
1
+ {"version":3,"file":"Button.types.d.ts","sourceRoot":"","sources":["../../../../src/components/button/Button.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,IAAI,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,MAAM,WAAW,GAAG,IAAI,CAC7B,iBAAiB,EACjB,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CACvC,GAAG;IACH,KAAK,CAAC,EACH,SAAS,GACT,SAAS,GACT,WAAW,GACX,SAAS,GACT,SAAS,GACT,QAAQ,CAAC;IACZ,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,OAAO,CAAC,EACL,OAAO,GACP,UAAU,GACV,OAAO,GACP,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IAC9C,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;OAaG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxB,CAAC"}
@@ -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;AACpD,OAAO,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAmB5E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA2Q3C,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;AACpD,OAAO,iBAAiB,CAAC;AAIzB,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAmB5E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAsR3C,CAAC"}
@@ -96,6 +96,25 @@ export interface MenuClawProps {
96
96
  history: MenuClawHistory;
97
97
  isOpenSidebar?: boolean;
98
98
  onOpenSidebarChange?: (open: boolean) => void;
99
+ /**
100
+ * Estado de plegado, en modo controlado. Si se omite, `MenuClaw` gestiona su
101
+ * propio estado interno (arranca expandido, o por `defaultCollapsed` si se
102
+ * indica) — comportamiento idéntico al de antes de esta prop.
103
+ */
104
+ isCollapsed?: boolean;
105
+ /**
106
+ * Se invoca cuando el usuario pulsa el botón de comprimir/expandir, tanto en
107
+ * modo controlado como no controlado. En modo controlado el consumidor debe
108
+ * aplicar el nuevo valor a `isCollapsed`; en modo no controlado es solo un
109
+ * aviso (el componente ya actualizó su estado interno).
110
+ */
111
+ onCollapsedChange?: (collapsed: boolean) => void;
112
+ /**
113
+ * Estado de plegado inicial en modo no controlado (sin `isCollapsed`). Se
114
+ * ignora si `isCollapsed` está presente.
115
+ * @default false
116
+ */
117
+ defaultCollapsed?: boolean;
99
118
  /**
100
119
  * Key del grupo cuyos ítems se muestran en la barra inferior móvil (hasta 4
101
120
  * + hamburguesa). Sin este valor no se muestra la barra inferior.