@m4l/components 9.4.6-BE20260108-beta.3 → 9.4.6-BE20260109-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
2
3
  import { useModuleDictionary } from "@m4l/core";
3
4
  import { useFormContext } from "react-hook-form";
4
5
  import { D as DataTypeComponent } from "../FieldTypes/DataTypeComponent.js";
5
6
  import { u as usePopoverFilter } from "./usePopoverFilter.js";
6
- import { P as POPOVER_CONTAINER_ID } from "../../../../hooks/usePopoverContainer/constants.js";
7
7
  import { u as usePopoverContainer } from "../../../../hooks/usePopoverContainer/usePopoverContainer.js";
8
8
  import { P as PopoverStyled, h as PopoverContainerFieldsStyled, i as PopoverHeaderActionsStyled } from "../../slots/dynamicFilterSlots.js";
9
9
  import { R as RHFormProvider } from "../../../hook-form/RHFormProvider/RHFormProvider.js";
@@ -43,7 +43,8 @@ function PopoverFilter() {
43
43
  statusLoad,
44
44
  canRender
45
45
  } = usePopoverFilter();
46
- const popoverContainerRef = usePopoverContainer(POPOVER_CONTAINER_ID, !!canRender);
46
+ const containerId = useId();
47
+ const popoverContainerRef = usePopoverContainer(containerId, !!canRender);
47
48
  if (!canRender) {
48
49
  return null;
49
50
  }
@@ -6,5 +6,5 @@ export type PopoverMenuFieldsProps = {
6
6
  /**
7
7
  * PopoverMenuFields: Componente encargado de mostrar el menú de campos para filtrar
8
8
  */
9
- declare function PopoverMenuFields(props: PopoverMenuFieldsProps): import("react/jsx-runtime").JSX.Element;
9
+ declare function PopoverMenuFields(props: PopoverMenuFieldsProps): import("react/jsx-runtime").JSX.Element | null;
10
10
  export default PopoverMenuFields;
@@ -1,19 +1,23 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
+ import { useId } from "react";
2
3
  import { M as MenuItem } from "../../../mui_extended/MenuItem/MenuItem.js";
3
4
  import { u as usePopoverMenuFields } from "./usePopoverMenuFields.js";
4
5
  import { u as useDynamicFilterBase } from "../DynamicFilterBase/useDynamicFilterBase.js";
5
6
  import { useModuleDictionary } from "@m4l/core";
6
7
  import { a as DICCTIONARY } from "../../dictionary.js";
7
8
  import { u as usePopoverContainer } from "../../../../hooks/usePopoverContainer/usePopoverContainer.js";
8
- import { P as POPOVER_CONTAINER_ID } from "../../../../hooks/usePopoverContainer/constants.js";
9
9
  import { j as PopoverMenuStyled } from "../../slots/dynamicFilterSlots.js";
10
10
  function PopoverMenuFields(props) {
11
11
  const { fields, selectFieldIndex } = props;
12
12
  const { elementRef, handleOpenPopUpClickItem, handleClosePopover, getItemLabel, isOpenPopoverMenuFields } = usePopoverMenuFields();
13
13
  const anchorEl = elementRef?.current;
14
14
  const { getLabel } = useModuleDictionary();
15
- const popoverContainerRef = usePopoverContainer(POPOVER_CONTAINER_ID, !!isOpenPopoverMenuFields);
15
+ const containerId = useId();
16
+ const popoverContainerRef = usePopoverContainer(containerId, !!isOpenPopoverMenuFields);
16
17
  const { size } = useDynamicFilterBase();
18
+ if (!isOpenPopoverMenuFields) {
19
+ return null;
20
+ }
17
21
  return /* @__PURE__ */ jsxs(
18
22
  PopoverMenuStyled,
19
23
  {
@@ -6,5 +6,5 @@ export type PopoverMenuFieldsProps = {
6
6
  /**
7
7
  * PopoverMenuFields es un componente que permite mostrar un menú desplegable con los campos disponibles para ordenar.
8
8
  */
9
- declare function PopoverMenuFields(props: PopoverMenuFieldsProps): import("react/jsx-runtime").JSX.Element;
9
+ declare function PopoverMenuFields(props: PopoverMenuFieldsProps): import("react/jsx-runtime").JSX.Element | null;
10
10
  export default PopoverMenuFields;
@@ -5,8 +5,8 @@ import { M as MenuItem } from "../../../mui_extended/MenuItem/MenuItem.js";
5
5
  import { I as Icon } from "../../../Icon/Icon.js";
6
6
  import { D as DICCTIONARY } from "../../dictionary.js";
7
7
  import { useModuleDictionary } from "@m4l/core";
8
+ import { useId } from "react";
8
9
  import { u as usePopoverContainer } from "../../../../hooks/usePopoverContainer/usePopoverContainer.js";
9
- import { P as POPOVER_CONTAINER_ID } from "../../../../hooks/usePopoverContainer/constants.js";
10
10
  import { P as PopoverMenuStyled } from "../../slots/DynamicSortSlots.js";
11
11
  function PopoverMenuFields(props) {
12
12
  const { fields, selectFieldIndex } = props;
@@ -14,7 +14,11 @@ function PopoverMenuFields(props) {
14
14
  const { size } = useDynamicSortBase();
15
15
  const anchorEl = elementRef?.current;
16
16
  const { getLabel } = useModuleDictionary();
17
- const popoverContainerRef = usePopoverContainer(POPOVER_CONTAINER_ID, !!isOpenPopoverMenuFields);
17
+ const containerId = useId();
18
+ const popoverContainerRef = usePopoverContainer(containerId, !!isOpenPopoverMenuFields);
19
+ if (!isOpenPopoverMenuFields) {
20
+ return null;
21
+ }
18
22
  return /* @__PURE__ */ jsxs(
19
23
  PopoverMenuStyled,
20
24
  {
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { useId } from "react";
2
3
  import { useModuleDictionary } from "@m4l/core";
3
4
  import { useFormContext } from "react-hook-form";
4
5
  import { u as useDynamicSortBase } from "../DynamicSortBase/useDynamicSortBase.js";
5
6
  import { D as DataTypeComponent } from "../FieldTypes/DataTypeComponent.js";
6
7
  import { u as usePopoverSort } from "./usePopoverSort.js";
7
8
  import { u as usePopoverContainer } from "../../../../hooks/usePopoverContainer/usePopoverContainer.js";
8
- import { P as POPOVER_CONTAINER_ID } from "../../../../hooks/usePopoverContainer/constants.js";
9
9
  import { e as PopoverStyled, f as PopoverContainerFieldsStyled, g as PopoverHeaderActionsStyled } from "../../slots/DynamicSortSlots.js";
10
10
  import { R as RHFormProvider } from "../../../hook-form/RHFormProvider/RHFormProvider.js";
11
11
  import { W as WindowBase } from "../../../WindowBase/WindowBase.js";
@@ -49,7 +49,8 @@ function PopoverSort() {
49
49
  canRender
50
50
  } = usePopoverSort();
51
51
  const { size } = useDynamicSortBase();
52
- const popoverContainerRef = usePopoverContainer(POPOVER_CONTAINER_ID, !!canRender);
52
+ const containerId = useId();
53
+ const popoverContainerRef = usePopoverContainer(containerId, !!canRender);
53
54
  if (!canRender) {
54
55
  return null;
55
56
  }
@@ -1,11 +1,37 @@
1
1
  /**
2
- * Hook para manejar un contenedor global para popovers. cuando se requiere que siga teniendo foco el anchorElement
3
- * Este hook garantiza que solo exista un contenedor con el ID especificado,
4
- * incluso si el hook se usa en múltiples componentes.
5
- * Utiliza un sistema de contador de referencias para evitar eliminar el contenedor
6
- * cuando hay múltiples popovers que lo necesitan simultáneamente.
7
- * @param containerId ID único para el contenedor
8
- * @param shouldMount Si es true, el contenedor se mantiene en el DOM. Si es false, se retira del DOM.
9
- * @returns Referencia al contenedor del popover
2
+ * Hook para manejar un contenedor global para popovers cuando se requiere que el anchorElement
3
+ * mantenga el foco mientras el popover está abierto.
4
+ *
5
+ * PROPÓSITO:
6
+ * Este hook crea y gestiona un contenedor DOM personalizado para popovers. Es especialmente útil
7
+ * cuando necesitas que el elemento ancla (anchorElement) mantenga el foco mientras el popover
8
+ * está visible, evitando que el foco se mueva automáticamente al popover.
9
+ *
10
+ * FUNCIONAMIENTO:
11
+ * 1. Busca un contenedor existente en el DOM con el ID especificado
12
+ * 2. Si no existe y `createContainer` es `true`, crea un nuevo contenedor y lo añade al body
13
+ * 3. Retorna una referencia al contenedor que debe pasarse a la prop `container` del Popover
14
+ *
15
+ * IMPORTANTE - TIMING Y RE-RENDERS:
16
+ * Este hook utiliza un re-render forzado para garantizar que el Popover se renderice con la
17
+ * referencia correcta del contenedor. Ver la documentación dentro del código para más detalles
18
+ * sobre por qué esto es necesario y qué ocurre si no se realiza.
19
+ * @param containerId ID único para el contenedor. Si no se proporciona, usa POPOVER_CONTAINER_ID por defecto
20
+ * @param createContainer Si es `true`, crea el contenedor si no existe. Si es `false`, solo busca uno existente
21
+ * @returns Referencia (ref) al contenedor del popover que debe pasarse a la prop `container` del Popover
22
+ * @example
23
+ * ```tsx
24
+ * const containerId = useId();
25
+ * const popoverContainerRef = usePopoverContainer(containerId, !!isOpen);
26
+ *
27
+ * return (
28
+ * <Popover
29
+ * open={isOpen}
30
+ * container={popoverContainerRef.current} // Pasa la referencia aquí
31
+ * >
32
+ * {/* contenido del popover *\/}
33
+ * </Popover>
34
+ * );
35
+ * ```
10
36
  */
11
- export declare function usePopoverContainer(containerId?: string, shouldMount?: boolean): import('react').MutableRefObject<HTMLDivElement | null>;
37
+ export declare function usePopoverContainer(containerId: string | undefined, createContainer: boolean): import('react').MutableRefObject<HTMLDivElement | null>;
@@ -1,87 +1,29 @@
1
- import { useRef, useEffect } from "react";
1
+ import { useRef, useState, useLayoutEffect } from "react";
2
2
  import { P as POPOVER_CONTAINER_ID } from "./constants.js";
3
- const containerRefCounts = /* @__PURE__ */ new Map();
4
- const containerCleanupTimeouts = /* @__PURE__ */ new Map();
5
- function usePopoverContainer(containerId = POPOVER_CONTAINER_ID, shouldMount = true) {
3
+ function usePopoverContainer(containerId = POPOVER_CONTAINER_ID, createContainer) {
6
4
  const containerRef = useRef(null);
7
- const hasRegisteredRef = useRef(false);
8
- if (shouldMount && typeof document !== "undefined") {
5
+ const [, forceUpdate] = useState({});
6
+ useLayoutEffect(() => {
7
+ if (typeof document === "undefined") {
8
+ return;
9
+ }
9
10
  let container = document.getElementById(containerId);
10
- if (!container) {
11
+ if (!container && createContainer) {
11
12
  container = document.createElement("div");
12
13
  container.id = containerId;
13
14
  document.body.appendChild(container);
14
- containerRef.current = container;
15
- } else if (containerRef.current !== container) {
16
- containerRef.current = container;
17
15
  }
18
- }
19
- useEffect(() => {
20
- if (shouldMount) {
21
- const existingTimeout = containerCleanupTimeouts.get(containerId);
22
- if (existingTimeout) {
23
- clearTimeout(existingTimeout);
24
- containerCleanupTimeouts.delete(containerId);
25
- }
26
- const currentCount = containerRefCounts.get(containerId) || 0;
27
- const newCount = currentCount + 1;
28
- containerRefCounts.set(containerId, newCount);
29
- hasRegisteredRef.current = true;
30
- let container = document.getElementById(containerId);
31
- if (!container) {
32
- container = document.createElement("div");
33
- container.id = containerId;
34
- document.body.appendChild(container);
35
- }
16
+ if (containerRef.current !== container) {
36
17
  containerRef.current = container;
37
- } else {
38
- if (hasRegisteredRef.current) {
39
- const currentCount = containerRefCounts.get(containerId) || 0;
40
- const newCount = Math.max(0, currentCount - 1);
41
- if (newCount === 0) {
42
- containerRefCounts.delete(containerId);
43
- const timeout = setTimeout(() => {
44
- const finalCount = containerRefCounts.get(containerId) || 0;
45
- if (finalCount === 0) {
46
- const container = document.getElementById(containerId);
47
- if (container && container.parentNode) {
48
- container.parentNode.removeChild(container);
49
- }
50
- }
51
- containerCleanupTimeouts.delete(containerId);
52
- }, 100);
53
- containerCleanupTimeouts.set(containerId, timeout);
54
- } else {
55
- containerRefCounts.set(containerId, newCount);
56
- }
57
- hasRegisteredRef.current = false;
58
- }
59
- containerRef.current = null;
18
+ forceUpdate({});
60
19
  }
61
20
  return () => {
62
- if (hasRegisteredRef.current) {
63
- const currentCount = containerRefCounts.get(containerId) || 0;
64
- const newCount = Math.max(0, currentCount - 1);
65
- if (newCount === 0) {
66
- containerRefCounts.delete(containerId);
67
- const timeout = setTimeout(() => {
68
- const finalCount = containerRefCounts.get(containerId) || 0;
69
- if (finalCount === 0) {
70
- const container = document.getElementById(containerId);
71
- if (container && container.parentNode) {
72
- container.parentNode.removeChild(container);
73
- }
74
- }
75
- containerCleanupTimeouts.delete(containerId);
76
- }, 100);
77
- containerCleanupTimeouts.set(containerId, timeout);
78
- } else {
79
- containerRefCounts.set(containerId, newCount);
80
- }
81
- hasRegisteredRef.current = false;
21
+ if (containerRef.current && containerRef.current.parentNode) {
22
+ containerRef.current.remove();
23
+ containerRef.current = null;
82
24
  }
83
25
  };
84
- }, [containerId, shouldMount]);
26
+ }, [containerId, createContainer]);
85
27
  return containerRef;
86
28
  }
87
29
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m4l/components",
3
- "version": "9.4.6-BE20260108-beta.3",
3
+ "version": "9.4.6-BE20260109-beta.2",
4
4
  "license": "UNLICENSED",
5
5
  "description": "M4L Components",
6
6
  "lint-staged": {