@zauru-sdk/components 6.2.28 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/.ladle/components.tsx +30 -0
  2. package/.ladle/config.mjs +9 -0
  3. package/.ladle/vite.config.ts +23 -0
  4. package/CHANGELOG.md +14 -0
  5. package/PLAYGROUND.md +59 -0
  6. package/dist/Alerts/StaticAlert.d.ts +1 -1
  7. package/dist/Buttons/ActionList.d.ts +17 -0
  8. package/dist/Buttons/Button.d.ts +1 -1
  9. package/dist/Buttons/index.d.ts +1 -0
  10. package/dist/Containers/ButtonSectionContainer.d.ts +2 -0
  11. package/dist/Containers/Container.d.ts +3 -1
  12. package/dist/DynamicTable/GenericDynamicTable.d.ts +2 -0
  13. package/dist/Form/FileUpload/index.d.ts +1 -0
  14. package/dist/Form/FormLayout/index.d.ts +11 -0
  15. package/dist/Form/RadioButtonGroup/index.d.ts +1 -0
  16. package/dist/Form/SelectField/index.d.ts +4 -1
  17. package/dist/Form/index.d.ts +2 -0
  18. package/dist/Labels/SearchFiltersSummary.d.ts +12 -0
  19. package/dist/Labels/index.d.ts +1 -0
  20. package/dist/Layouts/errorLayout/index.d.ts +4 -1
  21. package/dist/NavBar/NavBar.d.ts +1 -1
  22. package/dist/NavBar/NavBar.types.d.ts +1 -0
  23. package/dist/Table/ZauruTable.d.ts +5 -0
  24. package/dist/Tooltip/Tooltip.d.ts +7 -0
  25. package/dist/Tooltip/index.d.ts +1 -0
  26. package/dist/WithTooltip/WithTooltip.d.ts +7 -0
  27. package/dist/WithTooltip/index.d.ts +1 -0
  28. package/dist/esm/Alerts/StaticAlert.js +6 -0
  29. package/dist/esm/BlockUI/BlockUI.js +1 -1
  30. package/dist/esm/Buttons/ActionList.js +8 -0
  31. package/dist/esm/Buttons/Button.js +5 -5
  32. package/dist/esm/Buttons/index.js +1 -0
  33. package/dist/esm/Containers/ButtonSectionContainer.js +2 -2
  34. package/dist/esm/Containers/Container.js +7 -2
  35. package/dist/esm/Containers/OutletContainer.js +1 -1
  36. package/dist/esm/DynamicTable/GenericDynamicTable.js +6 -3
  37. package/dist/esm/Footer/Footer.js +1 -1
  38. package/dist/esm/Form/FileUpload/index.js +2 -2
  39. package/dist/esm/Form/FormLayout/index.js +7 -0
  40. package/dist/esm/Form/RadioButtonGroup/index.js +1 -0
  41. package/dist/esm/Form/SelectField/index.js +16 -6
  42. package/dist/esm/Form/TextField/index.js +13 -3
  43. package/dist/esm/Form/index.js +2 -0
  44. package/dist/esm/Labels/SearchFiltersSummary.js +7 -0
  45. package/dist/esm/Labels/index.js +1 -0
  46. package/dist/esm/Layouts/errorLayout/index.js +9 -3
  47. package/dist/esm/Modal/ItemModal.js +7 -4
  48. package/dist/esm/NavBar/NavBar.js +8 -3
  49. package/dist/esm/Table/ZauruTable.js +67 -8
  50. package/dist/esm/Tooltip/Tooltip.js +14 -0
  51. package/dist/esm/Tooltip/index.js +1 -0
  52. package/dist/esm/WithTooltip/WithTooltip.js +5 -0
  53. package/dist/esm/WithTooltip/index.js +1 -0
  54. package/dist/esm/index.js +2 -0
  55. package/dist/index.d.ts +2 -0
  56. package/package.json +10 -3
  57. package/postcss.config.cjs +6 -0
  58. package/src/Alerts/StaticAlert.tsx +11 -1
  59. package/src/BlockUI/BlockUI.tsx +1 -1
  60. package/src/Buttons/ActionList.tsx +56 -0
  61. package/src/Buttons/Button.tsx +15 -9
  62. package/src/Buttons/index.ts +1 -0
  63. package/src/Containers/ButtonSectionContainer.tsx +4 -2
  64. package/src/Containers/Container.tsx +43 -13
  65. package/src/Containers/OutletContainer.tsx +1 -1
  66. package/src/DynamicTable/GenericDynamicTable.tsx +26 -9
  67. package/src/Footer/Footer.tsx +2 -1
  68. package/src/Form/FileUpload/index.tsx +3 -0
  69. package/src/Form/FormLayout/index.tsx +35 -0
  70. package/src/Form/RadioButtonGroup/index.tsx +4 -0
  71. package/src/Form/SelectField/index.tsx +44 -23
  72. package/src/Form/TextField/index.tsx +14 -1
  73. package/src/Form/index.ts +2 -0
  74. package/src/Labels/SearchFiltersSummary.tsx +34 -0
  75. package/src/Labels/index.tsx +1 -0
  76. package/src/Layouts/errorLayout/index.tsx +11 -2
  77. package/src/Modal/ItemModal.tsx +18 -5
  78. package/src/NavBar/NavBar.tsx +20 -2
  79. package/src/NavBar/NavBar.types.ts +1 -0
  80. package/src/Table/ZauruTable.tsx +83 -7
  81. package/src/Tooltip/Tooltip.tsx +42 -0
  82. package/src/Tooltip/index.ts +1 -0
  83. package/src/WithTooltip/WithTooltip.tsx +22 -0
  84. package/src/WithTooltip/index.tsx +1 -0
  85. package/src/index.ts +2 -0
  86. package/stories/Alerts.stories.tsx +17 -0
  87. package/stories/Button.stories.tsx +52 -0
  88. package/stories/Card.stories.tsx +7 -0
  89. package/stories/Container.stories.tsx +24 -0
  90. package/stories/Form.stories.tsx +58 -0
  91. package/stories/Labels.stories.tsx +17 -0
  92. package/stories/Modal.stories.tsx +21 -0
  93. package/stories/Tab.stories.tsx +10 -0
  94. package/stories/Table.stories.tsx +37 -0
  95. package/stories/Titles.stories.tsx +11 -0
  96. package/stories/Tooltip.stories.tsx +15 -0
  97. package/tailwind.config.cjs +12 -0
  98. package/tsconfig.json +1 -0
@@ -1,11 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { IdeaIconSVG } from "@zauru-sdk/icons";
3
- import { useEffect, useState } from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
4
  import { useFormContext } from "react-hook-form";
5
5
  export const TextField = (props) => {
6
6
  const { id, name, defaultValue = "", hidden, type = "text", onChange, onKeyDown, disabled = false, readOnly = false, min, integer = false, stopChangeEvents, style, title, helpText, className = "", hint, required, autoComplete = "off", } = props;
7
7
  const [showTooltip, setShowTooltip] = useState(false);
8
8
  const [value, setValue] = useState(defaultValue);
9
+ const inputRef = useRef(null);
9
10
  const { register: tempRegister, formState: { errors }, setValue: setOnFormValue, } = useFormContext() || { formState: {} }; // Obtener el contexto solo si existe
10
11
  const error = errors ? errors[props.name ?? "-1"] : undefined;
11
12
  const register = tempRegister
@@ -14,12 +15,21 @@ export const TextField = (props) => {
14
15
  required,
15
16
  })
16
17
  : undefined; // Solo usar register si está disponible
18
+ const assignRef = (element) => {
19
+ inputRef.current = element;
20
+ if (typeof register?.ref === "function") {
21
+ register.ref(element);
22
+ }
23
+ };
17
24
  const color = error ? "red" : "gray";
18
25
  const isReadOnly = disabled || readOnly;
19
26
  const bgColor = isReadOnly ? "bg-gray-200" : `bg-${color}-50`;
20
27
  const textColor = isReadOnly ? "text-gray-500" : `text-${color}-900`;
21
28
  const borderColor = isReadOnly ? "border-gray-300" : `border-${color}-200`;
22
29
  useEffect(() => {
30
+ if (inputRef.current && document.activeElement === inputRef.current) {
31
+ return;
32
+ }
23
33
  if (setOnFormValue) {
24
34
  setOnFormValue(name ?? "-1", defaultValue);
25
35
  }
@@ -54,14 +64,14 @@ export const TextField = (props) => {
54
64
  }
55
65
  };
56
66
  if (hidden) {
57
- return (_jsx("input", { type: type, id: id ?? name, value: value, hidden: true, ...(register ?? {}), name: name, onChange: handleInputChange }));
67
+ return (_jsx("input", { type: type, id: id ?? name, value: value, hidden: true, ...(register ?? {}), ref: assignRef, name: name, onChange: handleInputChange }));
58
68
  }
59
69
  const inputComponent = (_jsx("input", { type: type, readOnly: isReadOnly, disabled: disabled, id: id ?? name, value: value, onWheel: (e) => {
60
70
  e.currentTarget.blur();
61
71
  }, step: type === "number" ? 0.01 : undefined, onKeyDown: (event) => {
62
72
  handleKeyDown(event);
63
73
  onKeyDown && onKeyDown(event);
64
- }, min: min, style: style, className: `block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`, ...(register ?? {}), name: name, autoComplete: autoComplete, onChange: handleInputChange }));
74
+ }, min: min, style: style, className: `block w-full rounded-md ${bgColor} ${borderColor} ${textColor} shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm`, ...(register ?? {}), ref: assignRef, name: name, autoComplete: autoComplete, onChange: handleInputChange }));
65
75
  if (!error && !title && !helpText) {
66
76
  return _jsx("div", { className: `${className}`, children: inputComponent });
67
77
  }
@@ -5,6 +5,7 @@ export * from "./DynamicBaculoForm/index.js";
5
5
  export * from "./FieldContainer/index.js";
6
6
  export * from "./FileUpload/index.js";
7
7
  export * from "./FormButtons/index.js";
8
+ export * from "./FormLayout/index.js";
8
9
  export * from "./SelectField/index.js";
9
10
  export * from "./TextArea/index.js";
10
11
  export * from "./TextField/index.js";
@@ -12,3 +13,4 @@ export * from "./TimePicker/index.js";
12
13
  export * from "./YesNo/index.js";
13
14
  export * from "./ReactZodForm/index.js";
14
15
  export * from "./RadioButton/index.js";
16
+ export * from "./RadioButtonGroup/index.js";
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export const SearchFiltersSummary = ({ items, emptyText = "Sin filtros registrados", className = "", }) => {
3
+ if (!items?.length) {
4
+ return (_jsx("p", { className: `text-xs text-gray-400 ${className}`, children: emptyText }));
5
+ }
6
+ return (_jsx("dl", { className: `flex flex-col gap-1 text-xs text-gray-700 ${className}`, children: items.map((item) => (_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-1", children: [_jsxs("dt", { className: "font-semibold text-gray-500", children: [item.label, ":"] }), _jsx("dd", { className: "text-gray-800", children: item.value })] }, item.key))) }));
7
+ };
@@ -1 +1,2 @@
1
1
  export * from "./InfoLabel/index.js";
2
+ export * from "./SearchFiltersSummary.js";
@@ -1,17 +1,23 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { isRouteErrorResponse, Links, Meta, Scripts, useRouteError, Link, } from "@remix-run/react";
3
- import { useState } from "react";
4
- export const ErrorLayout = ({ from, isRootLevel = true, error: parentError, }) => {
3
+ import { useEffect, useState } from "react";
4
+ export const ErrorLayout = ({ from, isRootLevel = true, error: parentError, onError, }) => {
5
5
  try {
6
6
  const error = useRouteError();
7
7
  const [showDetails, setShowDetails] = useState(!!parentError);
8
+ useEffect(() => {
9
+ const reportable = error instanceof Error ? error : parentError;
10
+ if (reportable instanceof Error) {
11
+ onError?.(reportable, { from });
12
+ }
13
+ }, [error, parentError, from, onError]);
8
14
  const baseError = (_jsxs("div", { className: "min-h-screen flex flex-col items-center justify-center p-4", children: [_jsx("img", { src: "/logo.png", alt: "Zauru Logo", className: "mb-8 h-20" }), _jsx("h1", { className: "text-5xl font-extrabold text-red-500 mb-6", children: "\u00A1Ups!" }), _jsxs("div", { className: "w-full max-w-2xl flex flex-col items-center", children: [_jsx("p", { className: "text-2xl text-gray-300 mb-8 text-center", children: isRouteErrorResponse(error)
9
15
  ? `Error en request: ${error.status}: ${error.statusText} - PATH: ${error.data.path} - MESSAGE: ${error.data.message}`
10
16
  : error instanceof Error
11
17
  ? `Error: ${error.message} - NAME: ${error.name} - STACK: ${error.stack?.slice(0, 100)} - CAUSE: ${error.cause}`
12
18
  : `Ha ocurrido un error inesperado: ${error}` }), from && (_jsxs("p", { className: "text-lg text-gray-400 mb-4 text-center", children: [isRootLevel
13
19
  ? "(*) Error lanzado desde: "
14
- : "Error lanzado desde: ", from] })), parentError && (_jsxs("div", { className: "mb-4 text-center", children: [_jsx("button", { onClick: () => setShowDetails(!showDetails), className: "text-blue-400 hover:text-blue-300 transition duration-300", children: showDetails ? "Ocultar detalles" : "Ver más detalles" }), showDetails && (_jsx("p", { className: "mt-2 text-gray-400 text-sm", children: parentError instanceof Error
20
+ : "Error lanzado desde: ", from] })), parentError && (_jsxs("div", { className: "mb-4 text-center", children: [_jsx("button", { onClick: () => setShowDetails(!showDetails), className: "text-blue-400 hover:text-blue-300 transition duration-300 cursor-pointer", children: showDetails ? "Ocultar detalles" : "Ver más detalles" }), showDetails && (_jsx("p", { className: "mt-2 text-gray-400 text-sm", children: parentError instanceof Error
15
21
  ? parentError.message
16
22
  : String(parentError) }))] }))] }), _jsx(Link, { to: "/", className: "bg-blue-600 text-white py-3 px-8 rounded-full text-lg font-semibold hover:bg-blue-700 transition duration-300 transform hover:scale-105", children: "Regresar al inicio" }), _jsx("div", { className: "mt-12 text-gray-500 text-center", children: _jsx("p", { children: "Si el problema persiste, por favor contacta a soporte." }) })] }));
17
23
  if (!isRootLevel) {
@@ -29,7 +29,8 @@ const ItemSelectionModal = ({ itemList, onClose, config, categoryViewMode = "tex
29
29
  const filteredList = itemList
30
30
  .map((category) => ({
31
31
  ...category,
32
- items: category.items.filter((item) => item.name.toLowerCase().includes(searchTerm.toLowerCase())),
32
+ items: category.items.filter((item) => item.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
33
+ item.code.toLowerCase().includes(searchTerm.toLowerCase())),
33
34
  }))
34
35
  .filter((category) => category.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
35
36
  category.items.length > 0);
@@ -74,11 +75,13 @@ const ItemSelectionModal = ({ itemList, onClose, config, categoryViewMode = "tex
74
75
  };
75
76
  return (_jsx("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex justify-center items-center z-50", onClick: handleCloseModal, children: _jsxs("div", {
76
77
  //Le ponemos ref para poder scrollear al tope
77
- ref: modalContentRef, className: "bg-white p-4 rounded-lg shadow-lg w-11/12 max-w-4xl h-5/6 overflow-y-auto", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsx("h2", { className: "text-2xl font-bold", children: selectedItem ? "Confirmar selección" : "Seleccionar un Ítem" }), _jsx("button", { className: "text-gray-500 hover:text-gray-800 text-3xl", onClick: handleCloseModal, children: "\u00D7" })] }), !selectedItem ? (
78
+ ref: modalContentRef, className: "bg-white p-4 rounded-lg shadow-lg w-11/12 max-w-4xl h-5/6 overflow-y-auto", onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: "flex justify-between items-center mb-4", children: [_jsx("h2", { className: "text-2xl font-bold", children: selectedItem
79
+ ? "Confirmar selección"
80
+ : `Seleccionar un Ítem - (${itemList.reduce((acc, category) => acc + category.items.length, 0)} ítems disponibles)` }), _jsx("button", { className: "text-gray-500 hover:text-gray-800 text-3xl cursor-pointer", onClick: handleCloseModal, children: "\u00D7" })] }), !selectedItem ? (
78
81
  /* ==============================
79
82
  PASO 1: SELECCIONAR ÍTEM
80
83
  ============================== */
81
- _jsxs(_Fragment, { children: [_jsxs("div", { className: "relative mb-4", children: [_jsx("input", { type: "text", placeholder: "Buscar por nombre o categor\u00EDa...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "p-2 border rounded-lg w-full" }), searchTerm && (_jsx("button", { className: "absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-800", onClick: () => setSearchTerm(""), children: "\u00D7" }))] }), filteredList.length === 0 ? (_jsx("p", { className: "text-gray-500 text-center", children: "No se encontraron resultados." })) : (filteredList.map((category, index) => {
84
+ _jsxs(_Fragment, { children: [_jsxs("div", { className: "relative mb-4", children: [_jsx("input", { type: "text", placeholder: "Buscar por nombre, c\u00F3digo o categor\u00EDa...", value: searchTerm, onChange: (e) => setSearchTerm(e.target.value), className: "p-2 border rounded-lg w-full" }), searchTerm && (_jsx("button", { className: "absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-800", onClick: () => setSearchTerm(""), children: "\u00D7" }))] }), filteredList.length === 0 ? (_jsx("p", { className: "text-gray-500 text-center", children: "No se encontraron resultados." })) : (filteredList.map((category, index) => {
82
85
  const isExpanded = expandedCategories[category.name];
83
86
  // Estilos condicionales para "text" vs. "card"
84
87
  const categoryContainerClasses = categoryViewMode === "card"
@@ -107,7 +110,7 @@ const ItemSelectionModal = ({ itemList, onClose, config, categoryViewMode = "tex
107
110
  /* ==============================
108
111
  PASO 2: CONFIRMAR SELECCIÓN
109
112
  ============================== */
110
- _jsxs("div", { className: "flex flex-col items-center justify-center", children: [_jsx("img", { src: selectedItem.imageUrl, alt: selectedItem.name, className: "w-40 h-40 object-cover rounded mb-4 shadow-md" }), _jsx("p", { className: "mb-2 text-xl font-bold", children: selectedItem.name }), _jsxs("p", { className: "mb-2 text-base font-semibold text-gray-700", children: ["Stock disponible:", _jsx("span", { className: "ml-1 font-normal text-gray-800", children: selectedItem.stock })] }), !selectedItem.flexiblePrice && (_jsxs("p", { className: "mb-4 text-base font-semibold text-gray-700", children: ["Precio unitario:", _jsxs("span", { className: "ml-1 font-normal text-gray-800", children: [selectedItem.currencyPrefix, selectedItem.priceText] })] })), _jsxs("div", { className: "mb-4 w-full max-w-sm flex flex-col items-center", children: [_jsx("p", { className: "text-base font-semibold text-gray-700 mb-2", children: "Seleccionar cantidad" }), _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setQuantity((prev) => (prev > 1 ? prev - 1 : 1)), children: "-" }), _jsx("input", { className: "w-20 text-center border rounded text-lg", type: "number", min: 1, value: quantity, onChange: (e) => {
113
+ _jsxs("div", { className: "flex flex-col items-center justify-center", children: [_jsx("img", { src: selectedItem.imageUrl, alt: selectedItem.name, className: "w-40 h-40 object-cover rounded mb-4 shadow-md" }), _jsx("p", { className: "mb-2 text-xl font-bold", children: selectedItem.name }), _jsxs("p", { className: "mb-2 text-base font-semibold text-gray-700", children: ["C\u00F3digo:", _jsx("span", { className: "ml-1 font-normal text-gray-800", children: selectedItem.code })] }), _jsxs("p", { className: "mb-2 text-base font-semibold text-gray-700", children: ["Stock disponible:", _jsx("span", { className: "ml-1 font-normal text-gray-800", children: selectedItem.stock })] }), !selectedItem.flexiblePrice && (_jsxs("p", { className: "mb-4 text-base font-semibold text-gray-700", children: ["Precio unitario:", _jsxs("span", { className: "ml-1 font-normal text-gray-800", children: [selectedItem.currencyPrefix, selectedItem.priceText] })] })), _jsxs("div", { className: "mb-4 w-full max-w-sm flex flex-col items-center", children: [_jsx("p", { className: "text-base font-semibold text-gray-700 mb-2", children: "Seleccionar cantidad" }), _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setQuantity((prev) => (prev > 1 ? prev - 1 : 1)), children: "-" }), _jsx("input", { className: "w-20 text-center border rounded text-lg", type: "number", min: 1, value: quantity, onChange: (e) => {
111
114
  const val = parseInt(e.target.value, 10);
112
115
  setQuantity(isNaN(val) || val < 1 ? 1 : val);
113
116
  } }), _jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setQuantity((prev) => prev + 1), children: "+" })] })] }), selectedItem.flexiblePrice && (_jsxs("div", { className: "mb-4 w-full max-w-sm flex flex-col items-center", children: [_jsx("p", { className: "text-base font-semibold text-gray-700 mb-2", children: "Seleccionar precio" }), _jsxs("div", { className: "flex items-center space-x-4", children: [_jsx("button", { className: "bg-gray-300 rounded-full w-12 h-12 flex justify-center items-center text-2xl font-bold hover:bg-gray-400", onClick: () => setCustomPrice((prev) => {
@@ -6,7 +6,7 @@ import { Link, useNavigate, useLocation } from "@remix-run/react";
6
6
  import { useAppSelector } from "@zauru-sdk/redux";
7
7
  const OptionsDropDownButton = ({ color, options, name }) => {
8
8
  const [showOptionsMenu, setShowOptionsMenu] = useState(true);
9
- return (_jsx("div", { className: "nav-item ml-auto", children: _jsx("div", { className: "flex justify-center", children: _jsxs("div", { className: "relative inline-block", children: [_jsxs("button", { onClick: () => setShowOptionsMenu(!showOptionsMenu), className: `relative flex items-center p-2 text-xs text-white ${color.bg700} active:${color.bg900} border border-transparent rounded-full uppercase focus:ring-opacity-40 focus:outline-none`, children: [name ?? _jsx(OpcionButtonSvgIcon, {}), _jsx(DropDownArrowSvgIcon, {})] }), _jsx("div", { className: "absolute right-0 z-20 w-56 py-2 mt-2 overflow-hidden bg-white rounded-md shadow-xl dark:bg-gray-800", hidden: showOptionsMenu, onMouseLeave: () => setShowOptionsMenu(true), children: options.map((option, index) => (_jsx(React.Fragment, { children: option }, index))) })] }) }) }));
9
+ return (_jsx("div", { className: "nav-item ml-auto", children: _jsx("div", { className: "flex justify-center", children: _jsxs("div", { className: "relative inline-block", children: [_jsxs("button", { onClick: () => setShowOptionsMenu(!showOptionsMenu), className: `relative flex cursor-pointer items-center p-2 text-xs text-white ${color.bg700} active:${color.bg900} border border-transparent rounded-full uppercase focus:ring-opacity-40 focus:outline-none`, children: [name ?? _jsx(OpcionButtonSvgIcon, {}), _jsx(DropDownArrowSvgIcon, {})] }), _jsx("div", { className: "absolute right-0 z-20 w-56 py-2 mt-2 overflow-hidden bg-white rounded-md shadow-xl dark:bg-gray-800", hidden: showOptionsMenu, onMouseLeave: () => setShowOptionsMenu(true), children: options.map((option, index) => (_jsx(React.Fragment, { children: option }, index))) })] }) }) }));
10
10
  };
11
11
  const NavItem = ({ name, link, icon, selectedColor, childrens = [], reduxNotificationBadge, }) => {
12
12
  const location = useLocation();
@@ -30,11 +30,15 @@ const NavItem = ({ name, link, icon, selectedColor, childrens = [], reduxNotific
30
30
  // De lo contrario, usamos el color normal (bg700)
31
31
  className: `${isActive ? specialColor.bg900 : specialColor.bg700} container text-white w-full sm:w-auto h-10 text-sm py-1 uppercase shadow hover:shadow-lg outline-none rounded-full focus:outline-none my-auto sm:my-0 sm:mr-1 mb-1 ease-linear transition-all duration-150`, children: _jsxs(Link, { className: "px-3 flex items-center text-xs leading-snug text-white uppercase hover:opacity-75 relative", to: link, children: [_jsxs("div", { className: "mx-auto pt-2", children: [icon, _jsx("span", { children: name })] }), notificationBadge !== undefined && (_jsx("span", { className: "absolute -top-2 -right-2 bg-red-500 text-white text-xs font-bold rounded-full flex items-center justify-center w-5 h-5", children: notificationBadge }))] }) }) }));
32
32
  };
33
- export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadCatalogsOption, }) => {
33
+ export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadCatalogsOption, showDarkModeToggle = false, }) => {
34
34
  const color = COLORS[selectedColor];
35
35
  const [NavBarOpen, setNavBarOpen] = useState(false);
36
36
  const [currentVersion, setCurrentVersion] = useState(version);
37
+ const [isDarkMode, setIsDarkMode] = useState(false);
37
38
  const navigate = useNavigate();
39
+ useEffect(() => {
40
+ document.documentElement.classList.toggle("dark", isDarkMode);
41
+ }, [isDarkMode]);
38
42
  useEffect(() => {
39
43
  if (version !== currentVersion) {
40
44
  setCurrentVersion(version);
@@ -54,8 +58,9 @@ export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadC
54
58
  .filter((item) => item.loggedIn === loggedIn)
55
59
  .filter((item) => item.hide !== true)) }), _jsx("ul", { className: "sm:flex sm:flex-col lg:flex-row ml-auto", children: loggedIn && (_jsx(OptionsDropDownButton, { color: color, options: [
56
60
  reloadCatalogsOption && (_jsx(Link, { className: `block px-4 py-3 text-sm text-gray-600 capitalize transition-colors duration-200 transform dark:text-gray-300 hover:bg-red-100 dark:hover:bg-gray-700 dark:hover:text-white`, to: "/reload-catalogs", children: _jsxs("div", { className: "mx-auto pt-2", children: [_jsxs("svg", { className: `h-5 w-5 mr-1`, width: "24", height: "24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", viewBox: "0 0 24 24", strokeLinecap: "round", strokeLinejoin: "round", xmlns: "http://www.w3.org/2000/svg", children: [_jsx("path", { d: "M20.5 8c-1.392-3.179-4.823-5-8.522-5C7.299 3 3.453 6.552 3 11.1" }), _jsx("path", { d: "M16.489 8.4h3.97A.54.54 0 0 0 21 7.86V3.9M3.5 16c1.392 3.179 4.823 5 8.522 5 4.679 0 8.525-3.552 8.978-8.1" }), _jsx("path", { d: "M7.511 15.6h-3.97a.54.54 0 0 0-.541.54v3.96" })] }), _jsx("span", { children: "Recargar cat\u00E1logos" })] }) }, "recargar-catalogos")),
61
+ showDarkModeToggle && (_jsx("button", { type: "button", className: "block w-full cursor-pointer text-left px-4 py-3 text-sm text-gray-600 capitalize transition-colors duration-200 transform dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 dark:hover:text-white", onClick: () => setIsDarkMode((value) => !value), children: _jsx("div", { className: "mx-auto pt-2", children: _jsx("span", { children: isDarkMode ? "Modo claro" : "Modo oscuro" }) }) }, "dark-mode-toggle")),
57
62
  _jsx(Link, { className: `block px-4 py-3 text-sm text-gray-600 capitalize transition-colors duration-200 transform dark:text-gray-300 hover:bg-red-100 dark:hover:bg-gray-700 dark:hover:text-white`, to: "/logout", children: _jsxs("div", { className: "mx-auto pt-2", children: [_jsx(LogoutDropDownSvgIcon, {}), _jsx("span", { children: "Cerrar sesi\u00F3n" })] }) }, "cerrar-sesion"),
58
63
  ] })) })] }));
59
- }, [items, loggedIn, hiddenItemsChange]);
64
+ }, [items, loggedIn, hiddenItemsChange, showDarkModeToggle, isDarkMode]);
60
65
  return (_jsx("nav", { className: `py-3 ${color.bg600}`, children: _jsxs("div", { className: "flex items-center justify-between ml-5 mr-5", children: [_jsxs("div", { className: "flex justify-between items-center w-full lg:w-auto", children: [_jsxs(Link, { className: "text-sm font-bold leading-relaxed inline-block mr-4 py-2 whitespace-nowrap uppercase text-white", to: "/home", children: [_jsx("div", { className: "inline-block mr-2 mb-2 align-middle", children: _jsx("img", { className: "w-auto h-7", src: "/logo.png", alt: "logo-zauru" }) }), title] }), version !== currentVersion && (_jsx("button", { className: `ml-2 px-2 py-1 text-xs text-white ${color.bg700} rounded-full hover:${color.bg900} transition-colors duration-200`, onClick: refreshPage, children: "\uD83D\uDD04 Actualizar versi\u00F3n" })), _jsx("button", { className: `rounded lg:hidden focus:outline-none focus:ring focus:${color.ring600} focus:ring-opacity-50`, "aria-label": "Toggle mobile menu", type: "button", onClick: () => setNavBarOpen(!NavBarOpen), children: _jsx(MenuAlt4Svg, { open: NavBarOpen }) })] }), _jsx("div", { className: `lg:hidden fixed top-0 left-0 z-50 w-64 h-full ${color.bg700} dark:bg-gray-900 shadow-lg transform ${NavBarOpen ? "translate-x-0" : "-translate-x-full"} transition-transform duration-300 ease-in-out overflow-y-auto`, children: _jsx("div", { className: "p-4", children: options }) }), _jsx("div", { className: "hidden lg:flex lg:items-center w-full lg:w-auto", children: options })] }) }));
61
66
  };
@@ -5,16 +5,65 @@ import { createTheme } from "react-data-table-component";
5
5
  import { SearchSVG } from "@zauru-sdk/icons";
6
6
  import * as ReactDataTableComponent from "react-data-table-component";
7
7
  const DataTable = ReactDataTableComponent.default;
8
+ const headerTextWrapStyle = {
9
+ whiteSpace: "normal",
10
+ overflow: "visible",
11
+ textOverflow: "clip",
12
+ overflowWrap: "break-word",
13
+ wordBreak: "break-word",
14
+ lineHeight: "1.25",
15
+ };
8
16
  const customStyles = {
17
+ table: {
18
+ style: {
19
+ minWidth: 0,
20
+ },
21
+ },
22
+ tableWrapper: {
23
+ style: {
24
+ display: "block",
25
+ width: "100%",
26
+ maxWidth: "100%",
27
+ minWidth: 0,
28
+ overflowX: "auto",
29
+ },
30
+ },
31
+ responsiveWrapper: {
32
+ style: {
33
+ width: "100%",
34
+ maxWidth: "100%",
35
+ minWidth: 0,
36
+ overflowX: "auto",
37
+ },
38
+ },
39
+ headRow: {
40
+ style: {
41
+ minHeight: "40px",
42
+ height: "auto",
43
+ alignItems: "stretch",
44
+ },
45
+ denseStyle: {
46
+ minHeight: "36px",
47
+ height: "auto",
48
+ },
49
+ },
9
50
  headCells: {
10
51
  style: {
11
52
  color: "#202124",
12
53
  fontSize: "14px",
13
54
  justifyContent: "left",
14
- whiteSpace: "normal",
15
- wordBreak: "break-word",
16
- maxWidth: "250px",
17
- padding: "4px", // Add some padding
55
+ alignItems: "flex-start",
56
+ paddingTop: "8px",
57
+ paddingBottom: "8px",
58
+ ...headerTextWrapStyle,
59
+ ".rdt_TableCol_Sortable": {
60
+ height: "auto",
61
+ minHeight: "100%",
62
+ overflow: "visible",
63
+ whiteSpace: "normal",
64
+ alignItems: "flex-start",
65
+ },
66
+ ".rdt_TableCol_Sortable > div": headerTextWrapStyle,
18
67
  },
19
68
  },
20
69
  cells: {
@@ -23,6 +72,16 @@ const customStyles = {
23
72
  wordBreak: "break-word",
24
73
  },
25
74
  },
75
+ expanderRow: {
76
+ style: {
77
+ minWidth: 0,
78
+ width: "100%",
79
+ maxWidth: "100%",
80
+ overflowX: "auto",
81
+ display: "grid",
82
+ gridTemplateColumns: "minmax(0, 1fr)",
83
+ },
84
+ },
26
85
  rows: {
27
86
  highlightOnHoverStyle: {
28
87
  backgroundColor: "rgb(230, 244, 244)",
@@ -86,7 +145,7 @@ createTheme("subTable", {
86
145
  });
87
146
  //Documentación de la tabla https://react-data-table-component.netlify.app/?path=/docs/getting-started-intro--docs
88
147
  export const ZauruTable = (props) => {
89
- const { columns, conditionalRowStyles, data, loading = false, pagination, search, theme, className, offlineSearch = [], whitOutPagination = false, ...others } = props;
148
+ const { columns, conditionalRowStyles, data, loading = false, pagination, search, expandable, theme, className, offlineSearch = [], whitOutPagination = false, ...others } = props;
90
149
  const [, setSearchParams] = useSearchParams({
91
150
  page: "1",
92
151
  perPage: "10",
@@ -152,7 +211,7 @@ export const ZauruTable = (props) => {
152
211
  };
153
212
  const loadSubHeader = !!(search || offlineSearch.length > 0);
154
213
  const subHeaderComponent = loadSubHeader ? subHeaderComponentMemo : undefined;
155
- return (_jsx(DataTable, { className: className, subHeaderWrap: true, theme: theme ?? "solarized", columns: columns, conditionalRowStyles: conditionalRowStyles, data: filteredData, customStyles: customStyles, progressPending: loading, highlightOnHover: true, pointerOnHover: true, dense: true, striped: true, pagination: !whitOutPagination, persistTableHead: true, responsive: true, noHeader: true, subHeader: loadSubHeader, subHeaderComponent: subHeaderComponent, paginationServer: !!pagination, paginationTotalRows: pagination?.totalRows ?? undefined, onChangeRowsPerPage: pagination ? handlePerRowsChange : undefined, onChangePage: pagination ? handlePageChange : undefined, paginationComponentOptions: paginationComponentOptions, paginationRowsPerPageOptions: pagination?.rowsPerPageOptions
156
- ? pagination.rowsPerPageOptions
157
- : [10, 50, 100], ...others }));
214
+ return (_jsx("div", { className: "w-full min-w-0 max-w-full overflow-x-auto", children: _jsx(DataTable, { className: className, subHeaderWrap: true, theme: theme ?? "solarized", columns: columns, conditionalRowStyles: conditionalRowStyles, data: filteredData, customStyles: customStyles, progressPending: loading, highlightOnHover: true, pointerOnHover: true, dense: true, striped: true, pagination: !whitOutPagination, persistTableHead: true, responsive: true, noHeader: true, expandableRows: !!expandable, expandOnRowClicked: !!expandable, expandableRowExpanded: expandable ? expandable.expandableRowExpanded : undefined, expandableRowsComponent: expandable ? expandable.expandableRowsComponent : undefined, subHeader: loadSubHeader, subHeaderComponent: subHeaderComponent, paginationServer: !!pagination, paginationTotalRows: pagination?.totalRows ?? undefined, onChangeRowsPerPage: pagination ? handlePerRowsChange : undefined, onChangePage: pagination ? handlePageChange : undefined, paginationComponentOptions: paginationComponentOptions, paginationRowsPerPageOptions: pagination?.rowsPerPageOptions
215
+ ? pagination.rowsPerPageOptions
216
+ : [10, 50, 100], ...others }) }));
158
217
  };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ export const Tooltip = ({ children, text }) => {
5
+ const [show, setShow] = useState(false);
6
+ return (_jsxs("div", { className: "relative inline-block", children: [_jsx("div", { onMouseEnter: () => setShow(true), onMouseLeave: () => setShow(false), children: children }), show && (_jsxs("div", { className: "absolute z-10 bg-gray-700 text-white px-2 py-1 rounded-md bottom-full left-1/2 transform -translate-x-1/2", style: { whiteSpace: "nowrap", height: "2rem" }, children: [text, _jsx("div", { className: "absolute top-full left-1/2 transform -translate-x-1/2", style: {
7
+ width: "0",
8
+ height: "0",
9
+ borderTop: "6px solid transparent",
10
+ borderLeft: "6px solid transparent",
11
+ borderRight: "6px solid transparent",
12
+ borderBottom: "6px solid gray",
13
+ } })] }))] }));
14
+ };
@@ -0,0 +1 @@
1
+ export * from "./Tooltip.js";
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export const WithTooltip = (props) => {
3
+ const { children, text } = props;
4
+ return (_jsxs("div", { className: "group relative inline-block", children: [children, _jsx("div", { className: "pointer-events-none absolute left-1/2 -translate-x-1/2 bottom-full mb-2 opacity-0 transition-opacity duration-300 group-hover:opacity-100", children: _jsxs("div", { className: "relative bg-black text-white text-sm rounded py-1 px-2 text-wrap w-40", children: [text, _jsx("div", { className: "absolute top-full left-1/2 -translate-x-1/2 border-4 border-transparent border-t-black" })] }) })] }));
5
+ };
@@ -0,0 +1 @@
1
+ export * from "./WithTooltip.js";
package/dist/esm/index.js CHANGED
@@ -19,6 +19,8 @@ export * from "./Tab/index.js";
19
19
  export * from "./Table/index.js";
20
20
  export * from "./TaskList/index.js";
21
21
  export * from "./Titles/index.js";
22
+ export * from "./Tooltip/index.js";
23
+ export * from "./WithTooltip/index.js";
22
24
  export * from "./Wizards/index.js";
23
25
  export * from "./Zendesk/index.js";
24
26
  export * from "./HOC/ValidateEmployeeAccess/index.js";
package/dist/index.d.ts CHANGED
@@ -19,6 +19,8 @@ export * from "./Tab/index.js";
19
19
  export * from "./Table/index.js";
20
20
  export * from "./TaskList/index.js";
21
21
  export * from "./Titles/index.js";
22
+ export * from "./Tooltip/index.js";
23
+ export * from "./WithTooltip/index.js";
22
24
  export * from "./Wizards/index.js";
23
25
  export * from "./Zendesk/index.js";
24
26
  export * from "./HOC/ValidateEmployeeAccess/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zauru-sdk/components",
3
- "version": "6.2.28",
3
+ "version": "6.3.0",
4
4
  "description": "Componentes reutilizables en las WebApps de Zauru.",
5
5
  "main": "./dist/esm/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -13,6 +13,8 @@
13
13
  "scripts": {
14
14
  "build": "npm run build:esm",
15
15
  "build:esm": "tsc -p tsconfig.esm.json",
16
+ "play": "ladle serve --port 61000",
17
+ "play:build": "ladle build",
16
18
  "test": "echo \"Error: no test specified\" && exit 1"
17
19
  },
18
20
  "author": {
@@ -21,15 +23,20 @@
21
23
  },
22
24
  "license": "MIT",
23
25
  "devDependencies": {
26
+ "@ladle/react": "^5.1.1",
24
27
  "@tailwindcss/forms": "^0.5.7",
25
28
  "@types/jsonwebtoken": "^9.0.2",
26
29
  "@types/rails__activestorage": "^7.1.1",
27
30
  "@types/react": "^19.0.0",
28
31
  "@types/react-dom": "^19.0.0",
29
32
  "@types/styled-components": "^5.1.34",
33
+ "autoprefixer": "^10.6.0",
30
34
  "postcss": "^8.4.35",
35
+ "react-redux": "^9.1.2",
36
+ "react-router-dom": "6.26.2",
31
37
  "tailwindcss": "^3.4.1",
32
- "typescript": "^5.1.6"
38
+ "typescript": "^5.1.6",
39
+ "vite": "^8.3.0"
33
40
  },
34
41
  "dependencies": {
35
42
  "@hookform/resolvers": "^3.9.0",
@@ -55,5 +62,5 @@
55
62
  "styled-components": "^5.3.5",
56
63
  "zod": "^3.23.8"
57
64
  },
58
- "gitHead": "9e840d01a540f2ab49233dda2cb2b0c916ffba0b"
65
+ "gitHead": "27363fa3e10c6b9f3ca319b0529fae01da836f87"
59
66
  }
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
@@ -7,7 +7,7 @@ type Props = {
7
7
  description: any;
8
8
  showCloseButton?: boolean;
9
9
  onClose?: () => void;
10
- type?: "success" | "info";
10
+ type?: "success" | "info" | "warning";
11
11
  loading?: boolean;
12
12
  };
13
13
 
@@ -33,6 +33,16 @@ const getConfig = (type: string) => {
33
33
  <path d="M8.445 12.6675A.9.9 0 0 0 7.1424 13.91l2.5726 2.7448c.3679.3856.9884.3689 1.335-.036l5.591-7.0366a.9.9 0 0 0-1.3674-1.1705l-4.6548 5.9132a.4.4 0 0 1-.607.0252l-1.567-1.6826zM1.9995 12c0-5.5 4.5-10 10-10s10 4.5 10 10-4.5 10-10 10-10-4.5-10-10z"></path>
34
34
  ),
35
35
  };
36
+ case "warning":
37
+ return {
38
+ containerClassName:
39
+ "text-yellow-900 bg-yellow-100 border border-yellow-200 rounded-md",
40
+ buttonClassName:
41
+ "rounded-md focus:outline-none focus:ring-2 focus:ring-yellow-500",
42
+ path: (
43
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm.93 14.93h-1.86c-.41 0-.75-.34-.75-.75s.34-.75.75-.75h1.86c.41 0 .75.34.75.75s-.34.75-.75.75zm.57-4.42l-.57 2.36h-1.86l-.57-2.36c-.13-.54.21-1.08.76-1.08h1.48c.55 0 .88.54.76 1.08zm0-2.36h-2.58c-.55 0-.88-.54-.76-1.08l.57-2.36h1.86l.57 2.36c.12.54-.21 1.08-.76 1.08z"></path>
44
+ ),
45
+ };
36
46
  default:
37
47
  return {
38
48
  containerClassName:
@@ -20,7 +20,7 @@ export const BlockUI = (props: Props) => {
20
20
  <div className="flex items-center">
21
21
  <span className="text-3xl mr-4">{loadingText}</span>
22
22
  <svg
23
- className="animate-spin h-36 w-36 text-gray-600"
23
+ className="animate-spin h-5 w-5 text-gray-600"
24
24
  xmlns="http://www.w3.org/2000/svg"
25
25
  fill="none"
26
26
  viewBox="0 0 24 24"
@@ -0,0 +1,56 @@
1
+ import React from "react";
2
+
3
+ export type ActionListItem = {
4
+ key: string;
5
+ label: string;
6
+ loadingLabel?: string;
7
+ loading?: boolean;
8
+ badge?: string;
9
+ badgeClassName?: string;
10
+ disabled?: boolean;
11
+ onClick: () => void;
12
+ };
13
+
14
+ type ActionListProps = {
15
+ items: ActionListItem[];
16
+ disabled?: boolean;
17
+ className?: string;
18
+ };
19
+
20
+ export const ActionList = ({
21
+ items,
22
+ disabled = false,
23
+ className = "",
24
+ }: ActionListProps) => {
25
+ return (
26
+ <div className={`flex flex-col gap-1 ${className}`}>
27
+ {items.map((item) => {
28
+ const itemBusy = Boolean(item.loading);
29
+ const itemDisabled = disabled || item.disabled || itemBusy;
30
+
31
+ return (
32
+ <button
33
+ key={item.key}
34
+ type="button"
35
+ disabled={itemDisabled}
36
+ onClick={item.onClick}
37
+ className="flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-left text-sm text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-1 disabled:cursor-progress disabled:opacity-60"
38
+ >
39
+ {item.badge ? (
40
+ <span
41
+ className={`inline-flex min-w-[2.25rem] justify-center rounded px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide ${
42
+ item.badgeClassName ?? "bg-gray-100 text-gray-700"
43
+ }`}
44
+ >
45
+ {item.badge}
46
+ </span>
47
+ ) : null}
48
+ <span>
49
+ {itemBusy ? (item.loadingLabel ?? item.label) : item.label}
50
+ </span>
51
+ </button>
52
+ );
53
+ })}
54
+ </div>
55
+ );
56
+ };
@@ -2,7 +2,7 @@ import type { ColorInterface } from "../NavBar/NavBar.types.js";
2
2
  import { useFormContext } from "react-hook-form";
3
3
  import { useState, useRef, useEffect } from "react";
4
4
 
5
- type DropdownOption = {
5
+ export type DropdownOption = {
6
6
  label: string;
7
7
  value: string;
8
8
  onClick: () => void;
@@ -141,7 +141,7 @@ export const Button = (props: Props) => {
141
141
  className={`${isButtonDisabled ? " bg-opacity-25 " : ""} ${
142
142
  loading
143
143
  ? " cursor-progress"
144
- : `${isButtonDisabled ? "" : `hover:${color.bg700}`}`
144
+ : `${isButtonDisabled ? " cursor-not-allowed" : `cursor-pointer hover:${color.bg700}`}`
145
145
  } inline-flex justify-center rounded-md border border-transparent ${
146
146
  color.bg600
147
147
  } py-2 px-4 text-sm font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:${
@@ -174,11 +174,13 @@ export const Button = (props: Props) => {
174
174
  <button
175
175
  type="button"
176
176
  disabled={isButtonDisabled}
177
+ aria-haspopup="menu"
178
+ aria-expanded={isDropdownOpen}
177
179
  onClick={() => setIsDropdownOpen(!isDropdownOpen)}
178
180
  className={`${isButtonDisabled ? " bg-opacity-25 " : ""} ${
179
181
  loading
180
182
  ? " cursor-progress"
181
- : `${isButtonDisabled ? "" : `hover:${color.bg700}`}`
183
+ : `${isButtonDisabled ? " cursor-not-allowed" : `cursor-pointer hover:${color.bg700}`}`
182
184
  } inline-flex justify-center items-center rounded-md border border-transparent ${
183
185
  color.bg600
184
186
  } py-2 px-4 text-sm font-medium text-white shadow-sm focus:outline-none focus:ring-2 focus:${
@@ -205,25 +207,29 @@ export const Button = (props: Props) => {
205
207
  </button>
206
208
  </div>
207
209
 
208
- {isDropdownOpen && (
209
- <div className="absolute right-0 z-10 mt-2 w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
210
+ {isDropdownOpen && !isButtonDisabled ? (
211
+ <div
212
+ role="menu"
213
+ className="absolute right-0 z-10 mt-2 w-56 origin-top-right rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
214
+ >
210
215
  <div className="py-1">
211
- {dropdownOptions.map((option, index) => (
216
+ {dropdownOptions.map((option) => (
212
217
  <button
213
- key={index}
218
+ key={option.value}
214
219
  type="button"
220
+ role="menuitem"
215
221
  onClick={() => {
216
222
  option.onClick();
217
223
  setIsDropdownOpen(false);
218
224
  }}
219
- className="block w-full px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 text-left"
225
+ className="block w-full cursor-pointer px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 text-left"
220
226
  >
221
227
  {option.label}
222
228
  </button>
223
229
  ))}
224
230
  </div>
225
231
  </div>
226
- )}
232
+ ) : null}
227
233
  </div>
228
234
  );
229
235
 
@@ -1 +1,2 @@
1
1
  export * from "./Button.js";
2
+ export * from "./ActionList.js";
@@ -3,14 +3,16 @@ import React from "react";
3
3
  type Props = {
4
4
  children: React.ReactNode;
5
5
  className?: string;
6
+ /** Fondo gris de pie de formulario. El nombre `whitBg` se conserva por compatibilidad con las webapps. */
7
+ whitBg?: boolean;
6
8
  };
7
9
 
8
10
  export const ButtonSectionContainer = (props: Props) => {
9
- const { children, className } = props;
11
+ const { children, className, whitBg = false } = props;
10
12
 
11
13
  return (
12
14
  <div
13
- className={`mt-5 flex flex-col md:flex-row md:justify-end md:items-center space-x-0 space-y-4 md:space-y-0 md:space-x-4 ${className}`}
15
+ className={`${whitBg ? "bg-gray-50 px-4 py-3 sm:px-6" : ""} mt-5 flex flex-col md:flex-row md:justify-end md:items-center space-x-0 space-y-4 md:space-y-0 md:space-x-4 ${className}`}
14
16
  >
15
17
  {children}
16
18
  </div>