@beweco/aurora-ui 0.6.75 → 0.6.76-qa.103

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.
Files changed (34) hide show
  1. package/dist/assets/css/styles.css +1 -1
  2. package/dist/index.cjs.js +364 -109
  3. package/dist/index.esm.js +357 -110
  4. package/dist/types/components/area-line-chart/AreaLineChart.d.ts +1 -1
  5. package/dist/types/components/area-line-chart/AreaLineChart.d.ts.map +1 -1
  6. package/dist/types/components/area-line-chart/AreaLineChart.types.d.ts +12 -0
  7. package/dist/types/components/area-line-chart/AreaLineChart.types.d.ts.map +1 -1
  8. package/dist/types/components/autocomplete/AutoComplete.d.ts +16 -0
  9. package/dist/types/components/autocomplete/AutoComplete.d.ts.map +1 -1
  10. package/dist/types/components/autocomplete/AutoComplete.types.d.ts +12 -0
  11. package/dist/types/components/autocomplete/AutoComplete.types.d.ts.map +1 -1
  12. package/dist/types/components/button/Button.d.ts +1 -0
  13. package/dist/types/components/button/Button.d.ts.map +1 -1
  14. package/dist/types/components/button/Button.types.d.ts +15 -0
  15. package/dist/types/components/button/Button.types.d.ts.map +1 -1
  16. package/dist/types/components/donut-chart/DonutChart.d.ts.map +1 -1
  17. package/dist/types/components/donut-chart/DonutChart.types.d.ts +2 -0
  18. package/dist/types/components/donut-chart/DonutChart.types.d.ts.map +1 -1
  19. package/dist/types/components/donut-chart/donut-chart.utils.d.ts +7 -0
  20. package/dist/types/components/donut-chart/donut-chart.utils.d.ts.map +1 -1
  21. package/dist/types/components/donut-chart/index.d.ts +1 -1
  22. package/dist/types/components/donut-chart/index.d.ts.map +1 -1
  23. package/dist/types/components/phone/Phone.d.ts.map +1 -1
  24. package/dist/types/components/tags-filter/TagsFilter.d.ts.map +1 -1
  25. package/dist/types/index.d.ts +1 -0
  26. package/dist/types/index.d.ts.map +1 -1
  27. package/dist/types/providers/theme/index.d.ts +1 -0
  28. package/dist/types/providers/theme/index.d.ts.map +1 -1
  29. package/dist/types/providers/theme/linda-tones.d.ts +53 -0
  30. package/dist/types/providers/theme/linda-tones.d.ts.map +1 -0
  31. package/dist/types/providers/theme/useThemeManager.d.ts.map +1 -1
  32. package/dist/types/utils/dismiss-control.d.ts +47 -1
  33. package/dist/types/utils/dismiss-control.d.ts.map +1 -1
  34. package/package.json +1 -1
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) {
@@ -581,9 +599,9 @@ function ChartTooltip(_a) {
581
599
  })] }));
582
600
  }
583
601
  function AreaLineChart(_a) {
584
- var data = _a.data, xAxisKey = _a.xAxisKey, series = _a.series, title = _a.title, value = _a.value, trend = _a.trend, _b = _a.height, height = _b === void 0 ? 200 : _b, _c = _a.className, className = _c === void 0 ? "" : _c, _d = _a.wrappedInCard, wrappedInCard = _d === void 0 ? false : _d, formatTooltipValue = _a.formatTooltipValue, _e = _a.yAxisDomain, yAxisDomain = _e === void 0 ? [0, "dataMax + 100"] : _e;
602
+ var data = _a.data, xAxisKey = _a.xAxisKey, series = _a.series, title = _a.title, value = _a.value, trend = _a.trend, _b = _a.height, height = _b === void 0 ? 200 : _b, _c = _a.className, className = _c === void 0 ? "" : _c, _d = _a.wrappedInCard, wrappedInCard = _d === void 0 ? false : _d, formatTooltipValue = _a.formatTooltipValue, _e = _a.yAxisDomain, yAxisDomain = _e === void 0 ? [0, "dataMax + 100"] : _e, _f = _a.xAxisInterval, xAxisInterval = _f === void 0 ? "preserveStartEnd" : _f;
585
603
  var hasHeader = title != null || value != null || trend != null || series.length > 0;
586
- var content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasHeader && (jsxRuntime.jsxs("div", { className: "flex items-start justify-between mb-6", children: [jsxRuntime.jsxs("div", { children: [title != null && (jsxRuntime.jsx(H3, { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1", children: title })), value != null && (jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [jsxRuntime.jsx("span", { className: "text-2xl font-bold text-gray-900", children: value }), trend != null && (jsxRuntime.jsx("span", { className: "text-xs font-medium text-yellow-600 bg-yellow-50 px-2 py-1 rounded", children: trend }))] }))] }), series.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-4", children: series.map(function (s) { return (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("svg", { width: "16", height: "2", viewBox: "0 0 16 2", fill: "none", children: jsxRuntime.jsx("line", { x1: "0", y1: "1", x2: "16", y2: "1", stroke: s.color, strokeWidth: "2" }) }), jsxRuntime.jsx("span", { className: "text-xs text-gray-600 font-medium", children: s.label })] }, s.dataKey)); }) }))] })), jsxRuntime.jsx("div", { className: "w-full", style: { height: "".concat(height, "px") }, children: jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: jsxRuntime.jsxs(recharts.LineChart, { data: data, margin: { top: 5, right: 5, left: 5, bottom: 5 }, children: [jsxRuntime.jsx("defs", { children: series.map(function (s) { return (jsxRuntime.jsxs("linearGradient", { id: "area-line-chart-".concat(s.dataKey), x1: "0", y1: "0", x2: "0", y2: "1", children: [jsxRuntime.jsx("stop", { offset: "0%", stopColor: s.color, stopOpacity: 0.3 }), jsxRuntime.jsx("stop", { offset: "50%", stopColor: s.color, stopOpacity: 0.15 }), jsxRuntime.jsx("stop", { offset: "100%", stopColor: s.color, stopOpacity: 0 })] }, s.dataKey)); }) }), jsxRuntime.jsx(recharts.XAxis, { dataKey: xAxisKey, axisLine: false, tickLine: false, tick: { fill: "#9ca3af", fontSize: 12 }, dy: 10 }), jsxRuntime.jsx(recharts.YAxis, { axisLine: false, tickLine: false, tick: { fill: "transparent", fontSize: 0 }, width: 0, tickCount: 6, domain: yAxisDomain, allowDecimals: false }), jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: "#d1d5db", strokeOpacity: 0.5, vertical: false, horizontal: true }), jsxRuntime.jsx(recharts.Tooltip, { content: jsxRuntime.jsx(ChartTooltip, { series: series, formatValue: formatTooltipValue }) }), series.map(function (s) { return (jsxRuntime.jsx(recharts.Area, { type: "natural", dataKey: s.dataKey, stroke: "none", fill: "url(#area-line-chart-".concat(s.dataKey, ")"), animationDuration: 1500, animationEasing: "ease-in-out" }, "area-".concat(s.dataKey))); }), series.map(function (s) { return (jsxRuntime.jsx(recharts.Line, { type: "natural", dataKey: s.dataKey, name: s.dataKey, stroke: s.color, strokeWidth: 3, dot: false, activeDot: {
604
+ var content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [hasHeader && (jsxRuntime.jsxs("div", { className: "flex items-start justify-between mb-6", children: [jsxRuntime.jsxs("div", { children: [title != null && (jsxRuntime.jsx(H3, { className: "text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1", children: title })), value != null && (jsxRuntime.jsxs("div", { className: "flex items-baseline gap-2", children: [jsxRuntime.jsx("span", { className: "text-2xl font-bold text-gray-900", children: value }), trend != null && (jsxRuntime.jsx("span", { className: "text-xs font-medium text-yellow-600 bg-yellow-50 px-2 py-1 rounded", children: trend }))] }))] }), series.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-4", children: series.map(function (s) { return (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("svg", { width: "16", height: "2", viewBox: "0 0 16 2", fill: "none", children: jsxRuntime.jsx("line", { x1: "0", y1: "1", x2: "16", y2: "1", stroke: s.color, strokeWidth: "2" }) }), jsxRuntime.jsx("span", { className: "text-xs text-gray-600 font-medium", children: s.label })] }, s.dataKey)); }) }))] })), jsxRuntime.jsx("div", { className: "w-full", style: { height: "".concat(height, "px") }, children: jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: jsxRuntime.jsxs(recharts.LineChart, { data: data, margin: { top: 5, right: 5, left: 5, bottom: 5 }, children: [jsxRuntime.jsx("defs", { children: series.map(function (s) { return (jsxRuntime.jsxs("linearGradient", { id: "area-line-chart-".concat(s.dataKey), x1: "0", y1: "0", x2: "0", y2: "1", children: [jsxRuntime.jsx("stop", { offset: "0%", stopColor: s.color, stopOpacity: 0.3 }), jsxRuntime.jsx("stop", { offset: "50%", stopColor: s.color, stopOpacity: 0.15 }), jsxRuntime.jsx("stop", { offset: "100%", stopColor: s.color, stopOpacity: 0 })] }, s.dataKey)); }) }), jsxRuntime.jsx(recharts.XAxis, { dataKey: xAxisKey, axisLine: false, tickLine: false, tick: { fill: "#9ca3af", fontSize: 12 }, dy: 10, interval: xAxisInterval }), jsxRuntime.jsx(recharts.YAxis, { axisLine: false, tickLine: false, tick: { fill: "transparent", fontSize: 0 }, width: 0, tickCount: 6, domain: yAxisDomain, allowDecimals: false }), jsxRuntime.jsx(recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: "#d1d5db", strokeOpacity: 0.5, vertical: false, horizontal: true }), jsxRuntime.jsx(recharts.Tooltip, { content: jsxRuntime.jsx(ChartTooltip, { series: series, formatValue: formatTooltipValue }) }), series.map(function (s) { return (jsxRuntime.jsx(recharts.Area, { type: "natural", dataKey: s.dataKey, stroke: "none", fill: "url(#area-line-chart-".concat(s.dataKey, ")"), animationDuration: 1500, animationEasing: "ease-in-out" }, "area-".concat(s.dataKey))); }), series.map(function (s) { return (jsxRuntime.jsx(recharts.Line, { type: "natural", dataKey: s.dataKey, name: s.dataKey, stroke: s.color, strokeWidth: 3, dot: false, activeDot: {
587
605
  r: 6,
588
606
  fill: s.color,
589
607
  stroke: "#fff",
@@ -595,6 +613,139 @@ function AreaLineChart(_a) {
595
613
  return jsxRuntime.jsx("div", { className: className, children: content });
596
614
  }
597
615
 
616
+ /**
617
+ * Interacciones que un popover no-modal NO debe tratar como "clic fuera".
618
+ *
619
+ * El problema que resuelve: `useOverlay` de react-aria trata cualquier
620
+ * pulsación fuera del popover como interacción externa y, cuando el popover es
621
+ * el overlay visible más reciente, hace `stopPropagation()` + `preventDefault()`
622
+ * sobre el `pointerdown` **y** sobre el `click`
623
+ * (`@react-aria/overlays/useOverlay`). El evento nunca llega a su destino, así
624
+ * que `usePress` no registra la pulsación y `onPress` no se dispara: el primer
625
+ * clic solo cierra el desplegable.
626
+ *
627
+ * Para un clic en la página de fondo eso es lo correcto: descartar el
628
+ * desplegable sin activar nada por debajo. Dentro del mismo diálogo no: ahí el
629
+ * usuario está rellenando un formulario y espera que su clic llegue. Y como los
630
+ * buscadores se reabren al recuperar el foco, el clic siguiente se volvía a
631
+ * tragar — un callejón sin salida del que solo se salía vaciando el campo.
632
+ *
633
+ * La única palanca es `shouldCloseOnInteractOutside`: es el guardián de esos dos
634
+ * `preventDefault`. Devolviendo `false` para lo que no es realmente "fuera", la
635
+ * pulsación llega intacta. El desplegable sigue cerrándose igual, pero por
636
+ * pérdida de foco (`shouldCloseOnBlur`) en vez de por interacción externa.
637
+ */
638
+ var _a, _b;
639
+ /**
640
+ * Marca un botón como control de cierre de su contenedor. Los popovers de Aura
641
+ * no lo cuentan como interacción externa, así que su pulsación no se pierde.
642
+ */
643
+ var DISMISS_CONTROL_ATTRIBUTE = "data-aura-dismiss";
644
+ /** Props a esparcir en un control de cierre: `<Button {...dismissControlProps} />`. */
645
+ var dismissControlProps = (_a = {},
646
+ _a[DISMISS_CONTROL_ATTRIBUTE] = "true",
647
+ _a);
648
+ /**
649
+ * Marca el contenedor de una superficie modal propia (wizard, panel a medida).
650
+ * No hace falta en `Modal` ni `Drawer`: los diálogos de HeroUI ya traen
651
+ * `role="dialog"`, que cuenta igual.
652
+ */
653
+ var CONTAINER_ATTRIBUTE = "data-aura-container";
654
+ /** Props a esparcir en el contenedor: `<div {...containerProps}>`. */
655
+ var containerProps = (_b = {},
656
+ _b[CONTAINER_ATTRIBUTE] = "true",
657
+ _b);
658
+ /**
659
+ * Selector de controles de cierre. Incluye `[aria-label="Close"]` para cubrir
660
+ * los botones de cerrar internos de HeroUI (Modal, Drawer), que no admiten
661
+ * atributos propios.
662
+ */
663
+ var DISMISS_CONTROL_SELECTOR = "[".concat(DISMISS_CONTROL_ATTRIBUTE, "],[aria-label=\"Close\"]");
664
+ /** Selector del contenedor modal: el marcado de Aura o un diálogo estándar. */
665
+ var CONTAINER_SELECTOR = "[".concat(CONTAINER_ATTRIBUTE, "],[role=\"dialog\"],[role=\"alertdialog\"]");
666
+ var matchesAncestor = function (element, selector) {
667
+ if (!element || typeof element.closest !== "function") {
668
+ return false;
669
+ }
670
+ return element.closest(selector) != null;
671
+ };
672
+ /** `true` si el elemento es un control de cierre (o está dentro de uno). */
673
+ var isDismissControl = function (element) { return matchesAncestor(element, DISMISS_CONTROL_SELECTOR); };
674
+ /**
675
+ * `true` si el elemento vive dentro de una superficie modal: un diálogo estándar
676
+ * o un contenedor marcado con `containerProps`.
677
+ *
678
+ * Es la condición que decide si un componente con popover no-modal necesita el
679
+ * predicado de más abajo. Fuera de una superficie así, HeroUI ya resuelve el
680
+ * caso por su cuenta (`ariaShouldCloseOnInteractOutside` cierra el desplegable
681
+ * y devuelve `false`, de modo que la pulsación llega a su destino); solo falla
682
+ * cuando hay un diálogo de por medio, y ahí entra el nuestro.
683
+ */
684
+ var isInsideDismissContainer = function (element) { return matchesAncestor(element, CONTAINER_SELECTOR); };
685
+ /**
686
+ * Predicado listo para `popoverProps.shouldCloseOnInteractOutside` de un
687
+ * componente con popover no-modal.
688
+ *
689
+ * Devuelve `false` —no es interacción externa— en tres casos:
690
+ *
691
+ * 1. Dentro del propio componente: el popover vive en un portal, así que el
692
+ * campo de búsqueda queda fuera de él y una pulsación sobre el texto se
693
+ * contaba como externa.
694
+ * 2. Sobre un control de cierre del contenedor propio.
695
+ * 3. Dentro del mismo diálogo/contenedor que el componente: seguir rellenando
696
+ * el formulario no es descartar el desplegable.
697
+ *
698
+ * Las exenciones 2 y 3 se limitan al contenedor del propio componente. Un
699
+ * control de cierre suelto en la página —la X de un toast, la de un banner— no
700
+ * tiene nada que ver con este desplegable, así que sigue contando como externo
701
+ * y lo cierra.
702
+ *
703
+ * @param element Elemento donde ha empezado la interacción.
704
+ * @param root Raíz del componente.
705
+ */
706
+ var shouldClosePopoverOnInteractOutside = function (element, root) {
707
+ var _a;
708
+ if (root === null || root === void 0 ? void 0 : root.contains(element)) {
709
+ return false;
710
+ }
711
+ var container = (_a = root === null || root === void 0 ? void 0 : root.closest) === null || _a === void 0 ? void 0 : _a.call(root, CONTAINER_SELECTOR);
712
+ if (isDismissControl(element)) {
713
+ // Sin contenedor propio no hay a quién eximir: el control de cierre es
714
+ // de otra cosa y su pulsación descarta el desplegable como cualquier otra.
715
+ return container ? !container.contains(element) : true;
716
+ }
717
+ if (!matchesAncestor(element, CONTAINER_SELECTOR)) {
718
+ return true;
719
+ }
720
+ // Solo exime el contenedor propio: un diálogo distinto sigue siendo externo.
721
+ return !(container === null || container === void 0 ? void 0 : container.contains(element));
722
+ };
723
+ /**
724
+ * Mezcla las `popoverProps` de un consumidor con el predicado por defecto, para
725
+ * que un componente con popover no-modal no trate como "clic fuera" lo que no lo
726
+ * es (ver `shouldClosePopoverOnInteractOutside`).
727
+ *
728
+ * Llamar solo cuando el componente está dentro de una superficie modal
729
+ * (`isInsideDismissContainer`). Fuera de ella HeroUI trae su propio default y
730
+ * hay que dejárselo: instalar cualquier predicado lo desactiva, porque su mezcla
731
+ * es por truthiness (`@heroui/autocomplete` → `use-autocomplete`).
732
+ *
733
+ * El consumidor puede sustituir el predicado pasando el suyo — es la salida para
734
+ * casos a medida, no la puerta a `() => true`. Pasar `shouldCloseOnInteractOutside:
735
+ * undefined` NO desactiva el default: para eso hay que pasar un predicado propio.
736
+ *
737
+ * @param popoverProps Las que llegan del consumidor, si las hay.
738
+ * @param getRoot Lector de la raíz del componente. Es una función y no un
739
+ * valor porque el `ref` todavía es `null` en el primer
740
+ * render: hay que leerlo cuando ocurre la interacción.
741
+ */
742
+ var withPopoverDismissDefaults = function (popoverProps, getRoot) {
743
+ var _a;
744
+ return (__assign(__assign({}, popoverProps), { shouldCloseOnInteractOutside: (_a = popoverProps === null || popoverProps === void 0 ? void 0 : popoverProps.shouldCloseOnInteractOutside) !== null && _a !== void 0 ? _a : (function (element) {
745
+ return shouldClosePopoverOnInteractOutside(element, getRoot());
746
+ }) }));
747
+ };
748
+
598
749
  /** Clases del wrapper del icono: margen derecho y alineación igual para lupa e iconos custom */
599
750
  var ICON_WRAPPER_CLASSNAME = "mr-2 flex shrink-0 items-center [&_svg]:shrink-0";
600
751
  var DEFAULT_ICON = (jsxRuntime.jsx(IconComponent, { icon: "solar:magnifer-outline", className: "text-default-400 pointer-events-none shrink-0", size: "sm", "aria-hidden": true }));
@@ -607,15 +758,39 @@ var DEFAULT_ICON = (jsxRuntime.jsx(IconComponent, { icon: "solar:magnifer-outlin
607
758
  * - labelPlacement: Outside
608
759
  * - Size: sm, md, lg (configurable)
609
760
  * - Icono: lupa por defecto; acepta prop icon para personalizar u ocultar (null).
761
+ *
762
+ * **Dentro de un modal, drawer o contenedor marcado con `containerProps`**, el
763
+ * desplegable deja de contar como "clic fuera" lo que ocurre dentro del propio
764
+ * componente, sobre un control de cierre del contenedor o dentro de ese mismo
765
+ * contenedor: react-aria hace `preventDefault()` sobre esas pulsaciones y el
766
+ * control de destino nunca llegaba a recibir su `onPress` (ver
767
+ * `shouldClosePopoverOnInteractOutside`). Sigue cerrándose, por la vía del
768
+ * `shouldCloseOnBlur` del combobox de HeroUI — no por `onBlurWithin` del
769
+ * overlay, que está gateado por el mismo predicado.
770
+ *
771
+ * **Fuera de un contenedor así no se instala nada**: HeroUI ya resuelve ese caso
772
+ * con `ariaShouldCloseOnInteractOutside`, y como su mezcla es por truthiness,
773
+ * poner un predicado propio lo desactivaría y volvería a tragarse la pulsación.
774
+ *
775
+ * Un consumidor puede sustituir el predicado con su propio
776
+ * `popoverProps.shouldCloseOnInteractOutside`; entonces manda el suyo siempre.
610
777
  */
611
778
  var AuraAutocomplete = function (_a) {
612
- var label = _a.label, id = _a.id, icon = _a.icon, _b = _a.size, size = _b === void 0 ? "md" : _b, _c = _a.variant, variant = _c === void 0 ? "bordered" : _c, _d = _a.radius, radius = _d === void 0 ? "md" : _d, props = __rest(_a, ["label", "id", "icon", "size", "variant", "radius"]);
779
+ var label = _a.label, id = _a.id, icon = _a.icon, _b = _a.size, size = _b === void 0 ? "md" : _b, _c = _a.variant, variant = _c === void 0 ? "bordered" : _c, _d = _a.radius, radius = _d === void 0 ? "md" : _d, popoverProps = _a.popoverProps, props = __rest(_a, ["label", "id", "icon", "size", "variant", "radius", "popoverProps"]);
613
780
  var generatedId = React.useId();
781
+ // El desplegable se renderiza en un portal, así que el campo de búsqueda
782
+ // queda fuera de él. Sin esta raíz el predicado no puede distinguir lo que
783
+ // pasa dentro del componente de un clic real de fuera. Se guarda en estado
784
+ // —y no en un ref— porque de ella depende SI se instala el predicado, y eso
785
+ // hay que decidirlo en render: un ref no dispara el re-render que hace falta.
786
+ var _e = React.useState(null), root = _e[0], setRoot = _e[1];
614
787
  var autoId = id || generatedId;
615
788
  var resolvedIcon = icon === undefined ? DEFAULT_ICON : icon;
616
789
  var hasIcon = resolvedIcon != null;
617
790
  var endContent = hasIcon ? (jsxRuntime.jsx("span", { className: ICON_WRAPPER_CLASSNAME, children: resolvedIcon })) : null;
618
- return (jsxRuntime.jsxs("div", { children: [label && (jsxRuntime.jsx("label", { htmlFor: autoId, className: "block mb-2 text-tiny text-default-600", children: label })), jsxRuntime.jsx(react.Autocomplete, __assign({}, props, { id: autoId, label: undefined, labelPlacement: "outside", variant: variant, size: size, radius: radius, endContent: endContent, classNames: __assign({ base: "[&_[data-slot=input-wrapper][data-focus=true]]:!border-primary-500", popoverContent: "aura-popover-content [&_li[data-hover=true]]:!bg-primary-50 [&_li[data-hover=true]]:!text-default-600 [&_li]:!text-default-500" }, (hasIcon && { selectorButton: "!hidden" })) }))] }));
791
+ return (jsxRuntime.jsxs("div", { ref: setRoot, children: [label && (jsxRuntime.jsx("label", { htmlFor: autoId, className: "block mb-2 text-tiny text-default-600", children: label })), jsxRuntime.jsx(react.Autocomplete, __assign({}, props, { id: autoId, label: undefined, labelPlacement: "outside", variant: variant, size: size, radius: radius, endContent: endContent, popoverProps: isInsideDismissContainer(root)
792
+ ? withPopoverDismissDefaults(popoverProps, function () { return root; })
793
+ : popoverProps, classNames: __assign({ base: "[&_[data-slot=input-wrapper][data-focus=true]]:!border-primary-500", popoverContent: "aura-popover-content [&_li[data-hover=true]]:!bg-primary-50 [&_li[data-hover=true]]:!text-default-600 [&_li]:!text-default-500" }, (hasIcon && { selectorButton: "!hidden" })) }))] }));
619
794
  };
620
795
 
621
796
  /**
@@ -2967,6 +3142,20 @@ function computeTotal(data) {
2967
3142
  function isDonutEmpty(data) {
2968
3143
  return data.length === 0 || computeTotal(data) === 0;
2969
3144
  }
3145
+ /**
3146
+ * Formatea `percent` (0-1) como entero + "%", excepto cuando la porción es
3147
+ * real (>0) pero redondea a 0 — ahí muestra "<1%" en vez de "0%", que se lee
3148
+ * como "no hay nada" y confunde cuando sí hay dato (ej. 4 de 2357 = 0.17%).
3149
+ * `lessThanOneLabel` permite traducir el texto (ver `DonutChartTranslations`).
3150
+ */
3151
+ function formatDonutPercent(percent, lessThanOneLabel) {
3152
+ if (lessThanOneLabel === void 0) { lessThanOneLabel = "<1%"; }
3153
+ if (!Number.isFinite(percent) || percent <= 0) {
3154
+ return "0%";
3155
+ }
3156
+ var rounded = Math.round(percent * 100);
3157
+ return rounded === 0 ? lessThanOneLabel : "".concat(rounded, "%");
3158
+ }
2970
3159
  /**
2971
3160
  * Resuelve las proporciones y el color final de cada categoría.
2972
3161
  * El color propio de cada dato tiene prioridad; si falta, se cicla `palette` por índice.
@@ -2984,6 +3173,7 @@ function computeSlices(data, palette) {
2984
3173
  var DEFAULT_TRANSLATIONS$b = {
2985
3174
  emptyState: "Sin datos para mostrar",
2986
3175
  totalLabel: "Total",
3176
+ lessThanOnePercent: "<1%",
2987
3177
  };
2988
3178
  /**
2989
3179
  * DonutChart - Gráfico circular (pie o donut, según `innerRadiusRatio`) con
@@ -3002,7 +3192,7 @@ var DonutChart = function (_a) {
3002
3192
  return formatValue ? formatValue(value) : String(value);
3003
3193
  };
3004
3194
  var isDonut = innerRadiusRatio > 0;
3005
- return (jsxRuntime.jsxs("div", { className: className, children: [jsxRuntime.jsxs("div", { className: "relative w-full", style: { height: height }, children: [jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: jsxRuntime.jsxs(recharts.PieChart, { children: [jsxRuntime.jsx(recharts.Pie, { data: slices, dataKey: "value", nameKey: "name", innerRadius: isDonut ? "".concat(innerRadiusRatio * 100, "%") : 0, outerRadius: "90%", stroke: "none", children: slices.map(function (slice) { return (jsxRuntime.jsx(recharts.Cell, { fill: slice.color }, slice.name)); }) }), jsxRuntime.jsx(recharts.Tooltip, { formatter: function (value) { return format(value); } })] }) }), isDonut && showTotal && (jsxRuntime.jsxs("div", { className: "aurora-donut-total pointer-events-none absolute inset-0 flex flex-col items-center justify-center", "aria-hidden": "true", children: [jsxRuntime.jsx("span", { className: "text-xs text-foreground-500", children: t.totalLabel }), jsxRuntime.jsx("span", { className: "text-xl font-semibold", children: format(total) })] }))] }), showLegend && (jsxRuntime.jsx("ul", { className: "mt-3 flex flex-wrap gap-3", children: slices.map(function (slice) { return (jsxRuntime.jsxs("li", { className: "flex items-center gap-1.5 text-xs", children: [jsxRuntime.jsx("span", { className: "h-2 w-2 rounded-full", style: { backgroundColor: slice.color }, "aria-hidden": "true" }), jsxRuntime.jsx("span", { children: slice.name }), jsxRuntime.jsxs("span", { className: "text-foreground-500", children: [Math.round(slice.percent * 100), "%"] })] }, slice.name)); }) }))] }));
3195
+ return (jsxRuntime.jsxs("div", { className: className, children: [jsxRuntime.jsxs("div", { className: "relative w-full", style: { height: height }, children: [jsxRuntime.jsx(recharts.ResponsiveContainer, { width: "100%", height: "100%", children: jsxRuntime.jsxs(recharts.PieChart, { children: [jsxRuntime.jsx(recharts.Pie, { data: slices, dataKey: "value", nameKey: "name", innerRadius: isDonut ? "".concat(innerRadiusRatio * 100, "%") : 0, outerRadius: "90%", stroke: "none", children: slices.map(function (slice) { return (jsxRuntime.jsx(recharts.Cell, { fill: slice.color }, slice.name)); }) }), jsxRuntime.jsx(recharts.Tooltip, { formatter: function (value) { return format(value); } })] }) }), isDonut && showTotal && (jsxRuntime.jsxs("div", { className: "aurora-donut-total pointer-events-none absolute inset-0 flex flex-col items-center justify-center", "aria-hidden": "true", children: [jsxRuntime.jsx("span", { className: "text-xs text-foreground-500", children: t.totalLabel }), jsxRuntime.jsx("span", { className: "text-xl font-semibold", children: format(total) })] }))] }), showLegend && (jsxRuntime.jsx("ul", { className: "mt-3 flex flex-wrap gap-3", children: slices.map(function (slice) { return (jsxRuntime.jsxs("li", { className: "flex items-center gap-1.5 text-xs", children: [jsxRuntime.jsx("span", { className: "h-2 w-2 rounded-full", style: { backgroundColor: slice.color }, "aria-hidden": "true" }), jsxRuntime.jsx("span", { children: slice.name }), jsxRuntime.jsx("span", { className: "text-foreground-500", children: formatDonutPercent(slice.percent, t.lessThanOnePercent) })] }, slice.name)); }) }))] }));
3006
3196
  };
3007
3197
 
3008
3198
  var H1 = function (_a) {
@@ -4020,96 +4210,6 @@ var MenuClaw = React.memo(function MenuClaw(_a) {
4020
4210
  }) }), 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] }) })] }));
4021
4211
  });
4022
4212
 
4023
- /**
4024
- * Interacciones que un popover no-modal NO debe tratar como "clic fuera".
4025
- *
4026
- * El problema que resuelve: `useOverlay` de react-aria trata cualquier
4027
- * pulsación fuera del popover como interacción externa y, cuando el popover es
4028
- * el overlay visible más reciente, hace `stopPropagation()` + `preventDefault()`
4029
- * sobre el `pointerdown` **y** sobre el `click`
4030
- * (`@react-aria/overlays/useOverlay`). El evento nunca llega a su destino, así
4031
- * que `usePress` no registra la pulsación y `onPress` no se dispara: el primer
4032
- * clic solo cierra el desplegable.
4033
- *
4034
- * Para un clic en la página de fondo eso es lo correcto: descartar el
4035
- * desplegable sin activar nada por debajo. Dentro del mismo diálogo no: ahí el
4036
- * usuario está rellenando un formulario y espera que su clic llegue. Y como los
4037
- * buscadores se reabren al recuperar el foco, el clic siguiente se volvía a
4038
- * tragar — un callejón sin salida del que solo se salía vaciando el campo.
4039
- *
4040
- * La única palanca es `shouldCloseOnInteractOutside`: es el guardián de esos dos
4041
- * `preventDefault`. Devolviendo `false` para lo que no es realmente "fuera", la
4042
- * pulsación llega intacta. El desplegable sigue cerrándose igual, pero por
4043
- * pérdida de foco (`shouldCloseOnBlur`) en vez de por interacción externa.
4044
- */
4045
- var _a, _b;
4046
- /**
4047
- * Marca un botón como control de cierre de su contenedor. Los popovers de Aura
4048
- * no lo cuentan como interacción externa, así que su pulsación no se pierde.
4049
- */
4050
- var DISMISS_CONTROL_ATTRIBUTE = "data-aura-dismiss";
4051
- /** Props a esparcir en un control de cierre: `<Button {...dismissControlProps} />`. */
4052
- var dismissControlProps = (_a = {},
4053
- _a[DISMISS_CONTROL_ATTRIBUTE] = "true",
4054
- _a);
4055
- /**
4056
- * Marca el contenedor de una superficie modal propia (wizard, panel a medida).
4057
- * No hace falta en `Modal` ni `Drawer`: los diálogos de HeroUI ya traen
4058
- * `role="dialog"`, que cuenta igual.
4059
- */
4060
- var CONTAINER_ATTRIBUTE = "data-aura-container";
4061
- /** Props a esparcir en el contenedor: `<div {...containerProps}>`. */
4062
- var containerProps = (_b = {},
4063
- _b[CONTAINER_ATTRIBUTE] = "true",
4064
- _b);
4065
- /**
4066
- * Selector de controles de cierre. Incluye `[aria-label="Close"]` para cubrir
4067
- * los botones de cerrar internos de HeroUI (Modal, Drawer), que no admiten
4068
- * atributos propios.
4069
- */
4070
- var DISMISS_CONTROL_SELECTOR = "[".concat(DISMISS_CONTROL_ATTRIBUTE, "],[aria-label=\"Close\"]");
4071
- /** Selector del contenedor modal: el marcado de Aura o un diálogo estándar. */
4072
- var CONTAINER_SELECTOR = "[".concat(CONTAINER_ATTRIBUTE, "],[role=\"dialog\"],[role=\"alertdialog\"]");
4073
- var matchesAncestor = function (element, selector) {
4074
- if (!element || typeof element.closest !== "function") {
4075
- return false;
4076
- }
4077
- return element.closest(selector) != null;
4078
- };
4079
- /** `true` si el elemento es un control de cierre (o está dentro de uno). */
4080
- var isDismissControl = function (element) { return matchesAncestor(element, DISMISS_CONTROL_SELECTOR); };
4081
- /**
4082
- * Predicado listo para `popoverProps.shouldCloseOnInteractOutside` de un
4083
- * componente con popover no-modal.
4084
- *
4085
- * Devuelve `false` —no es interacción externa— en tres casos:
4086
- *
4087
- * 1. Dentro del propio componente: el popover vive en un portal, así que el
4088
- * campo de búsqueda queda fuera de él y una pulsación sobre el texto se
4089
- * contaba como externa.
4090
- * 2. Sobre un control de cierre del contenedor.
4091
- * 3. Dentro del mismo diálogo/contenedor que el componente: seguir rellenando
4092
- * el formulario no es descartar el desplegable.
4093
- *
4094
- * @param element Elemento donde ha empezado la interacción.
4095
- * @param root Raíz del componente.
4096
- */
4097
- var shouldClosePopoverOnInteractOutside = function (element, root) {
4098
- var _a;
4099
- if (root === null || root === void 0 ? void 0 : root.contains(element)) {
4100
- return false;
4101
- }
4102
- if (isDismissControl(element)) {
4103
- return false;
4104
- }
4105
- if (!matchesAncestor(element, CONTAINER_SELECTOR)) {
4106
- return true;
4107
- }
4108
- // Solo exime el contenedor propio: un diálogo distinto sigue siendo externo.
4109
- var container = (_a = root === null || root === void 0 ? void 0 : root.closest) === null || _a === void 0 ? void 0 : _a.call(root, CONTAINER_SELECTOR);
4110
- return !(container === null || container === void 0 ? void 0 : container.contains(element));
4111
- };
4112
-
4113
4213
  var StepIndicator = function (_a) {
4114
4214
  var currentStep = _a.currentStep, totalSteps = _a.totalSteps, _b = _a.color, color = _b === void 0 ? "primary" : _b, _c = _a.showStepText, showStepText = _c === void 0 ? true : _c, stepTextFormatter = _a.stepTextFormatter, className = _a.className, props = __rest(_a, ["currentStep", "totalSteps", "color", "showStepText", "stepTextFormatter", "className"]);
4115
4215
  var progressPercentage = Math.min((currentStep / totalSteps) * 100, 100);
@@ -4464,13 +4564,6 @@ var Phone = function (_a) {
4464
4564
  document.removeEventListener("mousedown", handleClickOutside);
4465
4565
  };
4466
4566
  }, [isDropdownOpen]);
4467
- // El dropdown se portea a `body` con posición absoluta fija; cerrarlo cuando
4468
- // un ancestro hace scroll para que no quede flotando fuera de lugar.
4469
- useCloseOnAncestorScroll({
4470
- isOpen: isDropdownOpen,
4471
- onClose: function () { return setIsDropdownOpen(false); },
4472
- contentRef: portalDropdownRef,
4473
- });
4474
4567
  var handleCountrySelect = function (country) {
4475
4568
  setSelectedCountry(country);
4476
4569
  setIsDropdownOpen(false);
@@ -8958,7 +9051,9 @@ function TagsFilter(_a) {
8958
9051
  var _m = React.useState(0), autocompleteKey = _m[0], setAutocompleteKey = _m[1];
8959
9052
  var selectedList = value !== null && value !== void 0 ? value : [];
8960
9053
  var _o = React.useState(null), sentinelNode = _o[0], setSentinelNode = _o[1];
8961
- var rootRef = React.useRef(null);
9054
+ // En estado y no en un ref: de la raíz depende SI se instala el predicado
9055
+ // (solo dentro de una superficie modal), y eso se decide en render.
9056
+ var _p = React.useState(null), root = _p[0], setRoot = _p[1];
8962
9057
  React.useEffect(function () {
8963
9058
  if (!onLoadMore || !sentinelNode || !hasMore) {
8964
9059
  return;
@@ -9030,7 +9125,7 @@ function TagsFilter(_a) {
9030
9125
  if (isLoading) {
9031
9126
  return (jsxRuntime.jsx("div", { className: "flex flex-col gap-4 ".concat(className), children: jsxRuntime.jsx("div", { className: "flex justify-center py-4", children: jsxRuntime.jsx(react.Spinner, { size: "sm" }) }) }));
9032
9127
  }
9033
- return (jsxRuntime.jsxs("div", { ref: rootRef, className: "flex flex-col gap-4 ".concat(className), children: [error && (jsxRuntime.jsxs("div", { className: "text-danger text-small py-2", children: [t.errorLoadingPrefix, ": ", error] })), !error && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [jsxRuntime.jsxs(H4, { className: "text-tiny text-left text-default-700", children: [t.labelSelect, required && jsxRuntime.jsx("span", { className: "text-danger ml-0.5", children: "*" })] }), jsxRuntime.jsx(AuraAutocomplete, { placeholder: t.placeholder, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : t.placeholder, inputValue: inputValue, onInputChange: function (v) {
9128
+ return (jsxRuntime.jsxs("div", { ref: setRoot, className: "flex flex-col gap-4 ".concat(className), children: [error && (jsxRuntime.jsxs("div", { className: "text-danger text-small py-2", children: [t.errorLoadingPrefix, ": ", error] })), !error && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [jsxRuntime.jsxs(H4, { className: "text-tiny text-left text-default-700", children: [t.labelSelect, required && jsxRuntime.jsx("span", { className: "text-danger ml-0.5", children: "*" })] }), jsxRuntime.jsx(AuraAutocomplete, { placeholder: t.placeholder, "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : t.placeholder, inputValue: inputValue, onInputChange: function (v) {
9034
9129
  setInputValue(v);
9035
9130
  onInputChange === null || onInputChange === void 0 ? void 0 : onInputChange(v);
9036
9131
  }, selectedKey: null, items: itemsWithSentinel, onSelectionChange: handleAutocompleteSelection,
@@ -9064,9 +9159,16 @@ function TagsFilter(_a) {
9064
9159
  // click de toda interacción externa, así que su `onPress` no se
9065
9160
  // disparaba y el contenedor no se podía cerrar mientras el
9066
9161
  // desplegable estuviera abierto (ver `shouldClosePopoverOnInteractOutside`).
9067
- shouldCloseOnInteractOutside: function (element) {
9068
- return shouldClosePopoverOnInteractOutside(element, rootRef.current);
9069
- },
9162
+ //
9163
+ // Solo dentro de una superficie modal: fuera de ella HeroUI ya
9164
+ // resuelve el caso por su cuenta, y como su mezcla es por
9165
+ // truthiness, instalar cualquier predicado lo desactivaría y la
9166
+ // pulsación volvería a perderse.
9167
+ shouldCloseOnInteractOutside: isInsideDismissContainer(root)
9168
+ ? function (element) {
9169
+ return shouldClosePopoverOnInteractOutside(element, root);
9170
+ }
9171
+ : undefined,
9070
9172
  }, listboxProps: {
9071
9173
  className: "max-h-[200px] overflow-y-auto",
9072
9174
  }, className: "w-full", children: function (item) {
@@ -9644,6 +9746,127 @@ function removeCustomPrimaryColor() {
9644
9746
  }
9645
9747
  }
9646
9748
 
9749
+ /**
9750
+ * Los tres tonos del aura de Linda, derivados del `primary` de la agencia.
9751
+ *
9752
+ * Linda no tiene color propio: es el `primary` que el negocio eligió en el onboarding,
9753
+ * y por eso aquí no hay ni un color escrito. Lo único que se fija es CUÁNTO se gira ese
9754
+ * tono y en qué banda de luz se pinta.
9755
+ */
9756
+ /**
9757
+ * Grados que se gira el `primary` para cada tono, en el orden en que se pintan.
9758
+ *
9759
+ * Son muchos grados a propósito. La gracia del aura es que haya MÁS DE UN COLOR: con
9760
+ * un giro discreto —del orden de 18°, el que usa un degradado de profundidad— salen
9761
+ * tres versiones del mismo tono y el resultado se lee como un plano. A ±55° el salto
9762
+ * se ve como otro color y sigue dentro de la familia del `primary`, que es lo que
9763
+ * permite que esto funcione con la agencia número siete sin tocar nada.
9764
+ *
9765
+ * El tono del medio va casi sin girar: es el que ancla el conjunto al color de la
9766
+ * agencia, para que el aura se lea como suya y no como una decoración pegada encima.
9767
+ */
9768
+ var GIROS = [-56, 8, 54];
9769
+ /**
9770
+ * Banda de luz en la que se pintan los tres tonos, en porcentaje HSL.
9771
+ *
9772
+ * Los tonos NO heredan la luz del `primary`, y esto es lo que más se nota: un primary
9773
+ * oscuro y poco saturado sobre una superficie clara se lee como una mancha gris —sucia,
9774
+ * no como color—, y uno casi blanco desaparece contra el fondo. Se llevan al paso medio
9775
+ * de la escala, que es el que funciona en los dos casos.
9776
+ */
9777
+ var BANDA_LUZ = { min: 52, max: 72 };
9778
+ /**
9779
+ * Banda de saturación de los tres tonos, en porcentaje HSL.
9780
+ *
9781
+ * El techo es lo que evita que el aura grite. A plena saturación los tonos dejan de ser
9782
+ * ambiente y pasan a ser tres focos de color encima de un control de 40 pt: bonito en
9783
+ * una captura, insoportable en una barra que se mira todo el día.
9784
+ *
9785
+ * ⚠️ **Y hay una razón que no es estética.** Girar el tono puede caer en un rojo vivo:
9786
+ * un `primary` amarillo —51°— girado −56° aterriza en 355°, que a saturación 100 se lee
9787
+ * como un estado de error alrededor de un botón que no ha fallado. Visto al renderizarlo,
9788
+ * no razonándolo. Bajado a 65 el mismo tono es un rosa apagado y vuelve a leerse como lo
9789
+ * que es: decoración.
9790
+ *
9791
+ * El suelo existe por lo contrario: un `primary` casi gris da tres tonos que no se
9792
+ * distinguen entre sí, y entonces no hay degradado que ver —el aura se lee como una
9793
+ * mancha plana—.
9794
+ */
9795
+ var BANDA_SATURACION = { min: 35, max: 65 };
9796
+ var VUELTA = 360;
9797
+ /** `H S% L%` — el formato exacto en el que HeroUI guarda sus variables de color. */
9798
+ var TRIPLETE = /^\s*(-?\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)%\s+(\d+(?:\.\d+)?)%\s*$/;
9799
+ /**
9800
+ * Lee el triplete que HeroUI deja en una variable de color.
9801
+ *
9802
+ * Devuelve `null` en vez de lanzar: esto corre en un efecto de tema y el valor puede
9803
+ * no estar todavía —la clase del tema aún no está en el `<html>`, o el consumidor no
9804
+ * cargó la hoja de estilos—. Un aura que no se pinta es un problema menor; una
9805
+ * excepción que tumba el provider de tema, no.
9806
+ */
9807
+ function parseHslTriplet(value) {
9808
+ var encontrado = TRIPLETE.exec(value);
9809
+ if (!encontrado) {
9810
+ return null;
9811
+ }
9812
+ var h = encontrado[1], s = encontrado[2], l = encontrado[3];
9813
+ return { h: Number(h), s: Number(s), l: Number(l) };
9814
+ }
9815
+ /** Deja un ángulo dentro de `[0, 360)`, venga de donde venga. */
9816
+ function normalizarTono(grados) {
9817
+ return ((grados % VUELTA) + VUELTA) % VUELTA;
9818
+ }
9819
+ function acotar(valor, min, max) {
9820
+ return Math.min(Math.max(valor, min), max);
9821
+ }
9822
+ /**
9823
+ * Los tres tonos del aura, listos para escribirse en una variable CSS.
9824
+ *
9825
+ * Se redondean a entero: es un degradado decorativo, y las décimas de grado solo
9826
+ * alargan la hoja de estilos.
9827
+ */
9828
+ function deriveLindaTones(primary) {
9829
+ var luz = Math.round(acotar(primary.l, BANDA_LUZ.min, BANDA_LUZ.max));
9830
+ var saturacion = Math.round(acotar(primary.s, BANDA_SATURACION.min, BANDA_SATURACION.max));
9831
+ var tonos = GIROS.map(function (giro) {
9832
+ return "".concat(Math.round(normalizarTono(primary.h + giro)), " ").concat(saturacion, "% ").concat(luz, "%");
9833
+ });
9834
+ return tonos;
9835
+ }
9836
+ /** Las variables que se escriben en el `<html>`, en el orden en que se pintan. */
9837
+ var LINDA_TONE_PROPERTIES = [
9838
+ "--linda-1",
9839
+ "--linda-2",
9840
+ "--linda-3",
9841
+ ];
9842
+ /**
9843
+ * Escribe los tres tonos del aura a partir del valor de `--heroui-primary`.
9844
+ *
9845
+ * Si el primary no se puede leer, **borra los que hubiera** y devuelve `false`. Es lo
9846
+ * contrario de dejarlos: unos tonos viejos son de otro tema, y un aura del color
9847
+ * anterior es peor que un aura que no se pinta —la CSS del efecto ya está escrita para
9848
+ * desaparecer sin sus variables—.
9849
+ */
9850
+ function applyLindaTones(style, primaryValue) {
9851
+ var primary = parseHslTriplet(primaryValue);
9852
+ if (!primary) {
9853
+ removeLindaTones(style);
9854
+ return false;
9855
+ }
9856
+ var tonos = deriveLindaTones(primary);
9857
+ LINDA_TONE_PROPERTIES.forEach(function (propiedad, indice) {
9858
+ style.setProperty(propiedad, tonos[indice]);
9859
+ });
9860
+ return true;
9861
+ }
9862
+ /** Quita los tres tonos del aura. */
9863
+ function removeLindaTones(style) {
9864
+ for (var _i = 0, LINDA_TONE_PROPERTIES_1 = LINDA_TONE_PROPERTIES; _i < LINDA_TONE_PROPERTIES_1.length; _i++) {
9865
+ var propiedad = LINDA_TONE_PROPERTIES_1[_i];
9866
+ style.removeProperty(propiedad);
9867
+ }
9868
+ }
9869
+
9647
9870
  /**
9648
9871
  * Custom hook to manage the theme state and side effects.
9649
9872
  * Supports both named ThemeColor values and arbitrary hex colors.
@@ -9689,6 +9912,30 @@ var useThemeManager = function () {
9689
9912
  removeCustomPrimaryColor();
9690
9913
  }
9691
9914
  }, [customHex, mode]);
9915
+ /*
9916
+ * Los tres tonos del aura de Linda, derivados del primary que acaba de quedar fijado.
9917
+ *
9918
+ * Va DESPUÉS de los dos efectos de arriba y depende de lo mismo que ellos, que es lo
9919
+ * que garantiza que lea el primary definitivo: React ejecuta los efectos en orden de
9920
+ * declaración, así que aquí la clase del tema ya está en el `<html>` y el hex a medida
9921
+ * ya está escrito o retirado.
9922
+ *
9923
+ * Se lee del estilo COMPUTADO y no de `customHex` a propósito: el primary llega por
9924
+ * dos caminos —el hex del negocio o la clase de una de las familias de tema— y el
9925
+ * computado es el único sitio donde los dos han convergido. Derivarlo solo de
9926
+ * `customHex` dejaría sin aura a toda agencia que use una familia tal cual.
9927
+ */
9928
+ /*
9929
+ * `customHex` y `rawTheme` están en la lista aunque el cuerpo no los lea: son la señal
9930
+ * de que el `<html>` acaba de cambiar. La entrada real de este efecto es el estilo
9931
+ * computado, que la regla no puede ver, y sin ellos el aura se quedaría con los tonos
9932
+ * del tema anterior.
9933
+ */
9934
+ // biome-ignore lint/correctness/useExhaustiveDependencies: ver el comentario de arriba
9935
+ React.useEffect(function () {
9936
+ var html = document.documentElement;
9937
+ applyLindaTones(html.style, getComputedStyle(html).getPropertyValue("--heroui-primary"));
9938
+ }, [customHex, rawTheme]);
9692
9939
  var setMode = React.useCallback(function (newMode) {
9693
9940
  var effectiveMode = newMode === "dark" ? "light" : newMode;
9694
9941
  var newTheme = color === "blue" ? effectiveMode : "".concat(color, "-").concat(effectiveMode);
@@ -9861,6 +10108,7 @@ exports.InputPassword = InputPassword;
9861
10108
  exports.Kanban = Kanban;
9862
10109
  exports.KanbanCard = KanbanCard;
9863
10110
  exports.KanbanColumn = KanbanColumn;
10111
+ exports.LINDA_TONE_PROPERTIES = LINDA_TONE_PROPERTIES;
9864
10112
  exports.LindaIcon = LindaIcon;
9865
10113
  exports.MenuClaw = MenuClaw;
9866
10114
  exports.MenuComponent = MenuComponent;
@@ -9911,6 +10159,7 @@ exports.Wizard = Wizard;
9911
10159
  exports.WizardNavigation = WizardNavigation;
9912
10160
  exports.WizardSidebar = WizardSidebar;
9913
10161
  exports.applyCustomPrimaryColor = applyCustomPrimaryColor;
10162
+ exports.applyLindaTones = applyLindaTones;
9914
10163
  exports.computeBars = computeBars;
9915
10164
  exports.computeMax = computeMax;
9916
10165
  exports.computeSlices = computeSlices;
@@ -9920,9 +10169,11 @@ exports.createCurrencyFormatter = createCurrencyFormatter;
9920
10169
  exports.defaultCountries = uniqueCountries;
9921
10170
  exports.defaultCurrencyOptions = defaultCurrencyOptions;
9922
10171
  exports.defaultTranslations = defaultTranslations$5;
10172
+ exports.deriveLindaTones = deriveLindaTones;
9923
10173
  exports.dismissControlProps = dismissControlProps;
9924
10174
  exports.forceLightOnlyThemeBeforeReact = forceLightOnlyThemeBeforeReact;
9925
10175
  exports.formatAuroraThemeTooltip = formatAuroraThemeTooltip;
10176
+ exports.formatDonutPercent = formatDonutPercent;
9926
10177
  exports.generateThemeColorScale = generateThemeColorScale;
9927
10178
  exports.getContrastForeground = getContrastForeground;
9928
10179
  exports.getRegisteredThemeColorBases = getRegisteredThemeColorBases;
@@ -9935,9 +10186,12 @@ exports.isDonutEmpty = isDonutEmpty;
9935
10186
  exports.isExactThemeColor = isExactThemeColor;
9936
10187
  exports.isGroupState = isGroupState;
9937
10188
  exports.isHexColor = isHexColor;
10189
+ exports.isInsideDismissContainer = isInsideDismissContainer;
9938
10190
  exports.isRankedBarListEmpty = isRankedBarListEmpty;
9939
10191
  exports.isSegmentationGroup = isSegmentationGroup;
10192
+ exports.parseHslTriplet = parseHslTriplet;
9940
10193
  exports.removeCustomPrimaryColor = removeCustomPrimaryColor;
10194
+ exports.removeLindaTones = removeLindaTones;
9941
10195
  exports.shouldClosePopoverOnInteractOutside = shouldClosePopoverOnInteractOutside;
9942
10196
  exports.sizeMap = sizeMap;
9943
10197
  exports.themeColors = themeColors;
@@ -9946,6 +10200,7 @@ exports.useCloseOnAncestorScroll = useCloseOnAncestorScroll;
9946
10200
  exports.useMediaQuery = useMediaQuery;
9947
10201
  exports.useNavigationLoading = useNavigationLoading;
9948
10202
  exports.useThemeContext = useThemeContext;
10203
+ exports.withPopoverDismissDefaults = withPopoverDismissDefaults;
9949
10204
  Object.keys(react).forEach(function (k) {
9950
10205
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
9951
10206
  enumerable: true,