@axzydev/axzy_ui_system 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -338,6 +338,11 @@ function useFloatingPanel(anchorRef, isOpen, {
338
338
 
339
339
  // src/hooks/useTableState.ts
340
340
  var import_react5 = require("react");
341
+ var isEmptyFilterValue = (value) => {
342
+ if (value === void 0 || value === null || value === "") return true;
343
+ if (Array.isArray(value)) return value[0] == null && value[1] == null;
344
+ return false;
345
+ };
341
346
  function useTableState({
342
347
  defaultItemsPerPage = 10,
343
348
  initialSort = null
@@ -362,7 +367,7 @@ function useTableState({
362
367
  const handleFilterChange = (0, import_react5.useCallback)(
363
368
  (key, value) => {
364
369
  setFilters((prev) => {
365
- if (value === void 0 || value === null || value === "") {
370
+ if (isEmptyFilterValue(value)) {
366
371
  const next = { ...prev };
367
372
  delete next[key];
368
373
  return next;
@@ -3682,9 +3687,9 @@ function useVirtualRows({
3682
3687
  }
3683
3688
 
3684
3689
  // src/components/organisms/data-table/dataTable.tsx
3685
- var import_clsx21 = __toESM(require("clsx"), 1);
3686
- var import_react19 = require("react");
3687
- var import_fa11 = require("react-icons/fa");
3690
+ var import_clsx23 = __toESM(require("clsx"), 1);
3691
+ var import_react21 = require("react");
3692
+ var import_fa13 = require("react-icons/fa");
3688
3693
  var import_md = require("react-icons/md");
3689
3694
 
3690
3695
  // src/components/molecules/pagination/pagination.tsx
@@ -3977,445 +3982,240 @@ function ITPagination({
3977
3982
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("nav", { "aria-label": "Pagination", className: (0, import_clsx20.default)("inline-flex", className), children: renderPaginationControls() });
3978
3983
  }
3979
3984
 
3980
- // src/utils/table.utils.ts
3981
- var formatCurrencyMX = (value) => {
3982
- return value.toLocaleString("es-MX", {
3983
- style: "currency",
3984
- currency: "MXN"
3985
- });
3986
- };
3987
- var getNestedValue = (obj, path) => {
3988
- return path.split(".").reduce((acc, part) => acc && acc[part], obj);
3989
- };
3990
- var ROW_CLICK_IGNORE_SELECTOR = 'button, a, input, select, textarea, [role="button"], [role="link"], [data-row-click-ignore]';
3991
- function isInteractiveTarget(target, boundary = null) {
3992
- if (!(target instanceof Element)) return false;
3993
- const interactive = target.closest(ROW_CLICK_IGNORE_SELECTOR);
3994
- if (!interactive) return false;
3995
- if (boundary instanceof Node && interactive === boundary) return false;
3996
- return true;
3997
- }
3998
-
3999
- // src/components/organisms/data-table/dataTable.tsx
3985
+ // src/components/molecules/search-select/search-select.tsx
3986
+ var import_react19 = require("react");
3987
+ var import_react_dom3 = require("react-dom");
3988
+ var import_clsx21 = __toESM(require("clsx"), 1);
3989
+ var import_fa11 = require("react-icons/fa");
4000
3990
  var import_jsx_runtime21 = require("react/jsx-runtime");
4001
- var getNestedValue2 = (obj, path) => {
4002
- return path.split(".").reduce((acc, part) => acc && acc[part], obj);
4003
- };
4004
- var EMPTY_OBJECT = {};
4005
- function ITDataTable({
4006
- columns,
4007
- fetchData,
4008
- debounceMs = 500,
4009
- externalFilters = EMPTY_OBJECT,
4010
- loadingIndicator,
4011
- fetchOnMount = true,
4012
- reloadTrigger,
4013
- containerClassName,
3991
+ function ITSearchSelect({
3992
+ name,
3993
+ options = [],
3994
+ label,
3995
+ placeholder = "Selecciona una opci\xF3n",
3996
+ valueField = "value",
3997
+ labelField = "label",
3998
+ value,
3999
+ onChange,
4000
+ onBlur,
4001
+ disabled = false,
4014
4002
  className,
4015
- variant = "default",
4003
+ touched,
4004
+ required,
4005
+ error,
4006
+ readOnly = false,
4007
+ onSearch,
4008
+ isLoading = false,
4009
+ noResultsMessage = "No se encontraron resultados",
4016
4010
  size = "md",
4017
- itemsPerPageOptions = [5, 10, 20],
4018
- defaultItemsPerPage = 10,
4019
- title,
4020
- renderCard,
4021
- defaultView,
4022
- showVerticalBorder = true,
4023
- verticalBorderClassname,
4024
- onRowClick,
4025
- layout = "auto",
4026
- density = "normal",
4027
- autoCardBreakpoint = 0,
4028
- virtualized = false,
4029
- virtualizedMaxHeight = 400,
4030
- rowHeight,
4031
- overscan = 5,
4032
- stickyHeader = false
4011
+ renderOption,
4012
+ clearable = true,
4013
+ onClear
4033
4014
  }) {
4034
- const [viewMode, setViewMode] = (0, import_react19.useState)(defaultView || "table");
4035
- const { ref: rootRef, width: containerWidth } = useElementSize();
4036
- const [data, setData] = (0, import_react19.useState)([]);
4037
- const [totalItems, setTotalItems] = (0, import_react19.useState)(0);
4038
- const [isLoading, setIsLoading] = (0, import_react19.useState)(fetchOnMount);
4039
- const isFixed = layout === "fixed";
4040
- const forcedCards = autoCardBreakpoint > 0 && containerWidth > 0 && containerWidth < autoCardBreakpoint;
4041
- const effectiveView = forcedCards ? "cards" : viewMode;
4042
- const hasColumnWidths = columns.some((col) => col.width != null);
4043
- const tableLayoutClass = isFixed ? "w-full text-sm text-left text-secondary-600 transition-opacity duration-300" : "min-w-max w-full text-sm text-left text-secondary-600 transition-opacity duration-300";
4044
- const isTableVirtual = virtualized && effectiveView === "table";
4045
- const isStickyHeader = stickyHeader && isTableVirtual;
4046
- const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
4047
- const columnCount = columns.length;
4048
- const scrollOuterClass = isTableVirtual ? "relative min-h-[200px]" : "overflow-x-auto relative min-h-[200px]";
4049
- const {
4050
- currentPage,
4051
- itemsPerPage,
4052
- filters,
4053
- sortConfig,
4054
- goToPage,
4055
- handleFilterChange,
4056
- handleSort,
4057
- handleItemsPerPageChange
4058
- } = useTableState({ defaultItemsPerPage });
4059
- const {
4060
- scrollRef,
4061
- startIndex,
4062
- endIndex,
4063
- topSpacerHeight,
4064
- bottomSpacerHeight
4065
- } = useVirtualRows({
4066
- count: data.length,
4067
- rowHeight: resolvedRowHeight,
4068
- overscan,
4069
- enabled: isTableVirtual,
4070
- resetKey: `${currentPage}-${itemsPerPage}`
4015
+ const [isOpen, setIsOpen] = (0, import_react19.useState)(false);
4016
+ const [searchTerm, setSearchTerm] = (0, import_react19.useState)("");
4017
+ const [isFocused, setIsFocused] = (0, import_react19.useState)(false);
4018
+ const [localTouched, setLocalTouched] = (0, import_react19.useState)(false);
4019
+ const containerRef = (0, import_react19.useRef)(null);
4020
+ const inputWrapperRef = (0, import_react19.useRef)(null);
4021
+ const timeoutRef = (0, import_react19.useRef)(null);
4022
+ const { panelRef, style: panelStyle } = useFloatingPanel(inputWrapperRef, isOpen, {
4023
+ estimatedHeight: 260,
4024
+ matchWidth: true
4071
4025
  });
4072
- const windowData = isTableVirtual ? data.slice(startIndex, endIndex + 1) : data;
4073
- const debounceTimerRef = (0, import_react19.useRef)(null);
4074
- const hasFetchedRef = (0, import_react19.useRef)(false);
4075
- const fetchDataRef = (0, import_react19.useRef)(fetchData);
4076
- fetchDataRef.current = fetchData;
4077
- const externalFiltersRef = (0, import_react19.useRef)(externalFilters);
4078
- externalFiltersRef.current = externalFilters;
4079
- const externalKey = JSON.stringify(externalFilters);
4080
- const computedTotalPages = Math.ceil(totalItems / itemsPerPage) || 1;
4081
- const performFetch = (0, import_react19.useCallback)(async () => {
4082
- setIsLoading(true);
4083
- try {
4084
- const response = await fetchDataRef.current({
4085
- page: currentPage,
4086
- limit: itemsPerPage,
4087
- filters: { ...filters, ...externalFiltersRef.current },
4088
- sort: sortConfig || void 0
4089
- });
4090
- setData(response.data || []);
4091
- setTotalItems(response.total || 0);
4092
- hasFetchedRef.current = true;
4093
- } catch (error) {
4094
- console.error("ITDataTable: Error fetching data", error);
4095
- setData([]);
4096
- setTotalItems(0);
4097
- hasFetchedRef.current = true;
4098
- } finally {
4099
- setIsLoading(false);
4100
- }
4101
- }, [currentPage, itemsPerPage, filters, sortConfig]);
4102
- const performFetchRef = (0, import_react19.useRef)(performFetch);
4103
- performFetchRef.current = performFetch;
4026
+ const selectedOption = (0, import_react19.useMemo)(() => {
4027
+ return options.find((opt) => opt[valueField] === value);
4028
+ }, [options, value, valueField]);
4104
4029
  (0, import_react19.useEffect)(() => {
4105
- if (!fetchOnMount && !hasFetchedRef.current) return;
4106
- if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4107
- debounceTimerRef.current = setTimeout(() => {
4108
- performFetchRef.current();
4109
- }, debounceMs);
4110
- return () => {
4111
- if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4112
- };
4113
- }, [currentPage, itemsPerPage, sortConfig, filters, externalKey, reloadTrigger, fetchOnMount, debounceMs]);
4114
- const renderFilterInput = (col) => {
4115
- if (!col.filter) return null;
4116
- if (col.type === "boolean") {
4117
- const currentValue = filters[col.key];
4118
- const nextValue = currentValue === void 0 ? true : currentValue === true ? false : void 0;
4119
- const getToggleLabel = () => {
4120
- if (currentValue === void 0) return "Mostrar todos";
4121
- if (currentValue === true) return "Filtrar solo verdaderos";
4122
- return "Filtrar solo falsos";
4123
- };
4124
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4125
- "button",
4126
- {
4127
- className: "flex items-center justify-center cursor-pointer focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 rounded-full p-1 transition-all duration-200",
4128
- onClick: () => handleFilterChange(col.key, nextValue),
4129
- "aria-label": `${getToggleLabel()} para ${col.label}`,
4130
- title: `${getToggleLabel()} para ${col.label}`,
4131
- disabled: isLoading,
4132
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "relative w-10 h-5 bg-secondary-300 rounded-full", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4133
- "div",
4134
- {
4135
- className: (0, import_clsx21.default)(
4136
- "absolute top-0.5 w-4 h-4 rounded-full transition-all duration-300 shadow-sm",
4137
- {
4138
- "left-0.5 bg-secondary-400": currentValue === void 0,
4139
- "left-5 bg-slate-500": currentValue === true,
4140
- "left-0.5 bg-secondary-500": currentValue === false
4141
- }
4142
- )
4143
- }
4144
- ) })
4145
- }
4146
- );
4030
+ if (!isFocused) {
4031
+ setSearchTerm(selectedOption ? String(selectedOption[labelField]) : "");
4147
4032
  }
4148
- if (col.filter === "catalog" && col.catalogOptions) {
4149
- if (col.catalogOptions.loading) {
4150
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4151
- }
4152
- if (col.catalogOptions.error) {
4153
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4033
+ }, [selectedOption, isFocused, labelField]);
4034
+ (0, import_react19.useEffect)(() => {
4035
+ function handleClickOutside(event) {
4036
+ const target = event.target;
4037
+ const inContainer = containerRef.current?.contains(target);
4038
+ const inPanel = panelRef.current?.contains(target);
4039
+ if (!inContainer && !inPanel) {
4040
+ setIsOpen(false);
4154
4041
  }
4155
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4156
- ITSelect,
4157
- {
4158
- name: `filter-${col.key}`,
4159
- options: [
4160
- { value: "", label: "Todos" },
4161
- ...col.catalogOptions.data.map((item) => ({
4162
- value: String(item.id),
4163
- label: item.name
4164
- }))
4165
- ],
4166
- value: String(filters[col.key] || ""),
4167
- onChange: (e) => {
4168
- const value = e.target.value === "" ? void 0 : e.target.value;
4169
- handleFilterChange(col.key, value);
4170
- },
4171
- onBlur: () => {
4172
- },
4173
- className: "w-full text-xs",
4174
- disabled: isLoading
4175
- }
4176
- );
4177
4042
  }
4178
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4179
- ITInput,
4180
- {
4181
- name: `filter-${col.key}`,
4182
- className: "w-full text-xs",
4183
- placeholder: "Buscar...",
4184
- value: String(filters[col.key] || ""),
4185
- onChange: (e) => handleFilterChange(col.key, e.target.value),
4186
- onBlur: () => {
4187
- },
4188
- disabled: isLoading
4189
- }
4043
+ document.addEventListener("mousedown", handleClickOutside);
4044
+ return () => document.removeEventListener("mousedown", handleClickOutside);
4045
+ }, []);
4046
+ const selectedLabel = selectedOption ? String(selectedOption[labelField]) : "";
4047
+ const filteredOptions = (0, import_react19.useMemo)(() => {
4048
+ if (onSearch) return options;
4049
+ if (!searchTerm || !isFocused || searchTerm === selectedLabel) return options;
4050
+ return options.filter(
4051
+ (opt) => String(opt[labelField]).toLowerCase().includes(searchTerm.toLowerCase())
4190
4052
  );
4053
+ }, [options, searchTerm, selectedLabel, onSearch, labelField, isFocused]);
4054
+ const handleInputChange = (e) => {
4055
+ const query = e.target.value;
4056
+ setSearchTerm(query);
4057
+ setIsOpen(true);
4058
+ if (onSearch) {
4059
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
4060
+ timeoutRef.current = setTimeout(() => {
4061
+ onSearch(query);
4062
+ }, 500);
4063
+ }
4191
4064
  };
4192
- const renderCellContent = (col, row) => {
4193
- const value = getNestedValue2(row, col.key);
4194
- if (col.render) return col.render(row);
4195
- switch (col.type) {
4196
- case "number":
4197
- return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
4198
- case "boolean":
4199
- return value ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaCheck, { className: "text-success-500", "aria-label": "Verdadero", title: "Verdadero" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaTimes, { className: "text-danger-500", "aria-label": "Falso", title: "Falso" });
4200
- case "actions":
4201
- return col.actions ? col.actions(row) : null;
4202
- case "catalog":
4203
- if (col.catalogOptions) {
4204
- const catalogItem = col.catalogOptions.data.find((item) => item.id === value);
4205
- return catalogItem?.name || value;
4206
- }
4207
- return value;
4208
- default:
4209
- return value;
4065
+ const handleSelect = (option) => {
4066
+ if (onChange) {
4067
+ onChange(option[valueField], option);
4210
4068
  }
4069
+ setSearchTerm(String(option[labelField]));
4070
+ setIsOpen(false);
4211
4071
  };
4212
- const renderDefaultCard = (row) => {
4213
- const dataCols = columns.filter((c) => c.type !== "actions");
4214
- const actionCol = columns.find((c) => c.type === "actions");
4215
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-3 space-y-2 shadow-sm", children: [
4216
- dataCols.map((col) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
4217
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-[10px] font-bold uppercase tracking-wider text-slate-400 whitespace-nowrap flex-shrink-0 min-w-[70px]", children: col.label }),
4218
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { className: "text-sm font-medium text-slate-800 dark:text-white text-right truncate", children: renderCellContent(col, row) })
4219
- ] }, col.key)),
4220
- actionCol?.actions && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex items-center justify-end gap-2 pt-2 border-t border-slate-100 dark:border-slate-700", children: actionCol.actions(row) })
4221
- ] });
4072
+ const handleClear = () => {
4073
+ setSearchTerm("");
4074
+ setIsOpen(true);
4075
+ if (onSearch) onSearch("");
4076
+ if (value !== void 0 && value !== null && value !== "") {
4077
+ onChange?.("", void 0);
4078
+ }
4079
+ onClear?.();
4222
4080
  };
4223
- const segCtrlClass = (mode) => `flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${effectiveView === mode ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"}`;
4224
- const handleRowClick = (row) => (event) => {
4225
- if (!onRowClick || isLoading || isInteractiveTarget(event.target, event.currentTarget)) return;
4226
- onRowClick(row, event);
4081
+ const handleFocus = () => {
4082
+ if (disabled || readOnly) return;
4083
+ setIsFocused(true);
4084
+ setIsOpen(true);
4227
4085
  };
4228
- const handleRowKeyDown = (row) => (event) => {
4229
- if (!onRowClick || isLoading) return;
4230
- if (event.target !== event.currentTarget) return;
4231
- if (event.key !== "Enter" && event.key !== " ") return;
4232
- event.preventDefault();
4233
- onRowClick(row, event);
4086
+ const handleInputBlur = (e) => {
4087
+ setTimeout(() => {
4088
+ setIsFocused(false);
4089
+ setLocalTouched(true);
4090
+ onBlur?.(e);
4091
+ }, 200);
4234
4092
  };
4235
- const tableEl = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4236
- "table",
4237
- {
4238
- className: (0, import_clsx21.default)(
4239
- tableLayoutClass,
4240
- showVerticalBorder && "[&_th]:border-r [&_th:last-child]:border-r-0 [&_td]:border-r [&_td:last-child]:border-r-0",
4241
- showVerticalBorder && (verticalBorderClassname || "[&_th]:border-slate-100 dark:[&_th]:border-slate-700/30 [&_td]:border-slate-100 dark:[&_td]:border-slate-700/30"),
4242
- isLoading ? "opacity-50" : "opacity-100",
4243
- variantStyles[variant],
4244
- sizeStyles[size],
4245
- className
4246
- ),
4247
- style: isFixed ? { tableLayout: "fixed" } : void 0,
4248
- "aria-rowcount": isTableVirtual ? data.length + 1 : void 0,
4249
- children: [
4250
- hasColumnWidths && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("colgroup", { children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4251
- "col",
4252
- {
4253
- style: col.width != null ? { width: typeof col.width === "number" ? `${col.width}px` : col.width } : void 0
4254
- },
4255
- col.key
4256
- )) }),
4257
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4258
- "tr",
4093
+ const inputTheme = theme.input || {};
4094
+ const isTouched = touched !== void 0 ? touched : localTouched;
4095
+ const isEmpty = value === void 0 || value === null || String(value).trim() === "";
4096
+ const effectiveError = error !== void 0 && error !== false ? error === true ? "Este campo es requerido" : error : required && isEmpty ? "Este campo es requerido" : void 0;
4097
+ const hasError = isTouched && !!effectiveError;
4098
+ const errorMessage = typeof effectiveError === "string" ? effectiveError : "Este campo es requerido";
4099
+ const showClearButton = clearable && !disabled && !readOnly && (searchTerm.length > 0 || !isEmpty);
4100
+ const getInputStyle = () => {
4101
+ const sizeConfig = inputSizeTokens[size] ?? inputSizeTokens.md;
4102
+ const style = {
4103
+ backgroundColor: inputTheme.backgroundColor || "#ffffff",
4104
+ borderColor: inputTheme.borderColor || "var(--color-secondary-300)",
4105
+ borderRadius: inputTheme.borderRadius || "0.5rem",
4106
+ padding: sizeConfig.padding,
4107
+ fontSize: sizeConfig.fontSize,
4108
+ borderWidth: "1px",
4109
+ borderStyle: "solid",
4110
+ transition: "all 0.2s",
4111
+ color: "var(--it-input-text-color, var(--color-secondary-900))",
4112
+ width: "100%"
4113
+ };
4114
+ if (disabled) {
4115
+ style.backgroundColor = inputTheme.disabled?.backgroundColor || "var(--color-secondary-100)";
4116
+ style.borderColor = inputTheme.disabled?.borderColor || "var(--color-secondary-200)";
4117
+ style.opacity = 0.7;
4118
+ style.cursor = "not-allowed";
4119
+ }
4120
+ if (hasError) {
4121
+ style.borderColor = inputTheme.error?.borderColor || "red";
4122
+ if (isFocused) {
4123
+ style.boxShadow = inputTheme.error?.ring;
4124
+ }
4125
+ } else if (isFocused && !readOnly) {
4126
+ style.boxShadow = inputTheme.focus?.ring;
4127
+ style.borderColor = inputTheme.focus?.borderColor;
4128
+ }
4129
+ return style;
4130
+ };
4131
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: (0, import_clsx21.default)("w-full flex flex-col gap-1.5", className, isOpen && "relative z-30"), ref: containerRef, children: [
4132
+ label && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
4133
+ ITText,
4134
+ {
4135
+ as: "label",
4136
+ className: (0, import_clsx21.default)("text-sm font-medium text-secondary-700 dark:text-slate-300", {
4137
+ "text-danger-500": hasError
4138
+ }),
4139
+ children: [
4140
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", children: label }),
4141
+ required && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-danger-500 ml-1", children: "*" })
4142
+ ]
4143
+ }
4144
+ ),
4145
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "relative", children: [
4146
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { ref: inputWrapperRef, className: "relative flex items-center", children: [
4147
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4148
+ "input",
4259
4149
  {
4260
- className: (0, import_clsx21.default)(tableHeaderRow, "dark:text-slate-200"),
4261
- "aria-rowindex": isTableVirtual ? 1 : void 0,
4262
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4263
- "th",
4264
- {
4265
- scope: "col",
4266
- className: (0, import_clsx21.default)(
4267
- tableHeaderCell(col.className, density),
4268
- col.align && tableAlignClasses[col.align],
4269
- isStickyHeader && "sticky top-0 z-10 bg-secondary-50"
4270
- ),
4271
- style: col.minWidth != null || isStickyHeader ? {
4272
- ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4273
- ...isStickyHeader ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {}
4274
- } : void 0,
4275
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
4276
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
4277
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
4278
- col.sortable && col.type !== "actions" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4279
- "button",
4280
- {
4281
- onClick: () => handleSort(col.key),
4282
- disabled: isLoading,
4283
- className: `p-1 rounded-md transition-colors ${sortConfig?.key === col.key ? "bg-secondary-200 text-secondary-900" : "hover:bg-secondary-200 text-secondary-400 hover:text-secondary-700"} disabled:opacity-50`,
4284
- title: `Ordenar por ${col.label}`,
4285
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_md.MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
4286
- }
4287
- )
4288
- ] }),
4289
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
4290
- ] })
4291
- },
4292
- col.key
4293
- ))
4150
+ type: "text",
4151
+ name,
4152
+ value: searchTerm,
4153
+ onChange: handleInputChange,
4154
+ onFocus: handleFocus,
4155
+ onBlur: handleInputBlur,
4156
+ disabled,
4157
+ readOnly,
4158
+ placeholder,
4159
+ className: "outline-none pr-10",
4160
+ style: getInputStyle(),
4161
+ autoComplete: "off"
4294
4162
  }
4295
- ) }),
4296
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tbody", { className: (0, import_clsx21.default)(tableBody, "dark:divide-slate-700/30"), children: data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
4297
- isTableVirtual && topSpacerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tr", { "aria-hidden": "true", style: { height: topSpacerHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) }),
4298
- windowData.map((row, windowIndex) => {
4299
- const absoluteIndex = isTableVirtual ? startIndex + windowIndex : windowIndex;
4300
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4301
- "tr",
4302
- {
4303
- "aria-rowindex": isTableVirtual ? absoluteIndex + 2 : void 0,
4304
- className: (0, import_clsx21.default)(
4305
- tableRow,
4306
- variant === "striped" && absoluteIndex % 2 === 0 && "bg-secondary-50/40 dark:bg-slate-800/20",
4307
- onRowClick && !isLoading && tableRowClickable
4308
- ),
4309
- tabIndex: onRowClick && !isLoading ? 0 : void 0,
4310
- onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4311
- onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4312
- children: columns.map((col) => {
4313
- const rawValue = getNestedValue2(row, col.key);
4314
- const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
4315
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4316
- "td",
4317
- {
4318
- className: (0, import_clsx21.default)(
4319
- tableCell(col.className, density),
4320
- col.align && tableAlignClasses[col.align]
4321
- ),
4322
- style: col.minWidth != null ? { minWidth: `${col.minWidth}px` } : void 0,
4323
- title: truncateTitle,
4324
- children: col.type === "actions" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: tableActionsCell, children: renderCellContent(col, row) }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: (0, import_clsx21.default)(tableCellText, col.truncate && "truncate"), children: renderCellContent(col, row) })
4325
- },
4326
- `${absoluteIndex}-${col.key}`
4327
- );
4328
- })
4163
+ ),
4164
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "absolute right-3 flex items-center gap-2 text-secondary-400", children: [
4165
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "pointer-events-none animate-spin h-4 w-4 border-2 border-primary-500 border-t-transparent rounded-full" }),
4166
+ !isLoading && showClearButton && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4167
+ "button",
4168
+ {
4169
+ type: "button",
4170
+ "aria-label": "Limpiar",
4171
+ title: "Limpiar",
4172
+ onMouseDown: (e) => {
4173
+ e.preventDefault();
4174
+ handleClear();
4329
4175
  },
4330
- absoluteIndex
4331
- );
4332
- }),
4333
- isTableVirtual && bottomSpacerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tr", { "aria-hidden": "true", style: { height: bottomSpacerHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) })
4334
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("td", { colSpan: columns.length, className: "px-6 py-12 text-center", children: !isLoading && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: tableEmptyContent, children: [
4335
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4336
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4337
- ] }) }) }) })
4338
- ]
4339
- }
4340
- );
4341
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { ref: rootRef, className: (0, import_clsx21.default)("space-y-4 w-full relative", containerClassName), children: [
4342
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: tableContainer, style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4343
- title && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "px-6 py-5 flex items-center justify-between", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4344
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "h2", className: "text-xl font-bold text-secondary-900 leading-tight", children: title }),
4345
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center gap-3", children: [
4346
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "text-secondary-400", children: loadingIndicator || /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaSpinner, { className: "animate-spin text-primary-500 text-xl" }) }),
4347
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center bg-slate-100 dark:bg-slate-800/80 rounded-lg p-0.5 border border-slate-200 dark:border-slate-700/50", children: [
4348
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4349
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaTable, { size: 11 }),
4350
- "Table"
4351
- ] }),
4352
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4353
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaThLarge, { size: 11 }),
4354
- "Cards"
4355
- ] })
4356
- ] })
4176
+ className: "flex items-center justify-center text-secondary-400 hover:text-secondary-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400 rounded-full",
4177
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaTimes, { size: 14 })
4178
+ }
4179
+ ),
4180
+ !isLoading && !showClearButton && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaSearch, { size: 14, className: (0, import_clsx21.default)("pointer-events-none", { "text-primary-500": isFocused }) })
4357
4181
  ] })
4358
4182
  ] }),
4359
- !title && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex justify-end px-4 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "flex items-center bg-slate-100 dark:bg-slate-800/80 rounded-lg p-0.5 border border-slate-200 dark:border-slate-700/50", children: [
4360
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4361
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaTable, { size: 11 }),
4362
- "Table"
4363
- ] }),
4364
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4365
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaThLarge, { size: 11 }),
4366
- "Cards"
4367
- ] })
4368
- ] }) }),
4369
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: scrollOuterClass, children: [
4370
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "absolute inset-0 z-20 flex items-center justify-center bg-white/40 backdrop-blur-[2px] transition-all duration-300", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "flex flex-col items-center gap-3 p-6 rounded-2xl shadow-xl border border-secondary-100 animate-in fade-in zoom-in duration-300", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: loadingIndicator || /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
4371
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_fa11.FaSpinner, { className: "animate-spin text-primary-500 text-4xl" }),
4372
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-sm font-semibold text-secondary-600 animate-pulse", children: "Cargando datos..." })
4373
- ] }) }) }),
4374
- effectiveView === "cards" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "p-4 space-y-3 max-h-[400px] overflow-y-auto", children: data.length > 0 ? data.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4375
- "div",
4376
- {
4377
- className: (0, import_clsx21.default)(tableCardHover, onRowClick && !isLoading && tableCardClickable),
4378
- role: onRowClick && !isLoading ? "button" : void 0,
4379
- tabIndex: onRowClick && !isLoading ? 0 : void 0,
4380
- onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4381
- onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4382
- children: renderCard ? renderCard(row) : renderDefaultCard(row)
4383
- },
4384
- i
4385
- )) : !isLoading && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: (0, import_clsx21.default)(tableEmptyContent, "py-12"), children: [
4386
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4387
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4388
- ] }) }) : isTableVirtual ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4183
+ isOpen && (0, import_react_dom3.createPortal)(
4184
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4389
4185
  "div",
4390
4186
  {
4391
- ref: scrollRef,
4392
- className: "overflow-x-auto overflow-y-auto",
4393
- style: { maxHeight: virtualizedMaxHeight },
4394
- children: tableEl
4187
+ ref: panelRef,
4188
+ style: panelStyle,
4189
+ className: "bg-white dark:bg-slate-900 border border-secondary-200 dark:border-slate-800 rounded-lg shadow-xl overflow-hidden animate-in fade-in zoom-in duration-200 origin-top",
4190
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-h-60 overflow-y-auto", children: filteredOptions.length > 0 ? filteredOptions.map((option) => {
4191
+ const isSelected = value === option[valueField];
4192
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4193
+ ITText,
4194
+ {
4195
+ as: "div",
4196
+ onClick: () => handleSelect(option),
4197
+ className: (0, import_clsx21.default)(
4198
+ "px-4 py-2 text-sm cursor-pointer transition-colors",
4199
+ isSelected ? "bg-primary-50 dark:bg-primary-950/40 text-primary-700 dark:text-primary-300 font-medium" : "hover:bg-secondary-50 dark:hover:bg-slate-800 text-secondary-700 dark:text-slate-300"
4200
+ ),
4201
+ children: renderOption ? renderOption(option, { isSelected, searchTerm }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "span", children: option[labelField] })
4202
+ },
4203
+ option[valueField]
4204
+ );
4205
+ }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "div", className: "px-4 py-6 text-sm text-center text-secondary-500 italic", children: isLoading ? "Cargando..." : noResultsMessage }) })
4395
4206
  }
4396
- ) : tableEl
4397
- ] })
4207
+ ),
4208
+ document.body
4209
+ )
4398
4210
  ] }),
4399
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "rounded-b-xl px-6 py-4", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4400
- ITPagination,
4401
- {
4402
- currentPage,
4403
- totalPages: computedTotalPages,
4404
- onPageChange: goToPage,
4405
- color: "primary",
4406
- itemsPerPageOptions,
4407
- itemsPerPage,
4408
- onItemsPerPageChange: handleItemsPerPageChange,
4409
- totalItems
4410
- }
4411
- ) })
4211
+ hasError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ITText, { as: "p", className: "text-danger-500 text-xs mt-1", children: errorMessage })
4412
4212
  ] });
4413
4213
  }
4414
4214
 
4415
4215
  // src/components/molecules/date-picker/datePicker.tsx
4416
4216
  var import_clsx22 = __toESM(require("clsx"), 1);
4417
4217
  var import_react20 = __toESM(require("react"), 1);
4418
- var import_react_dom3 = require("react-dom");
4218
+ var import_react_dom4 = require("react-dom");
4419
4219
  var import_fa12 = require("react-icons/fa");
4420
4220
  var import_date_fns2 = require("date-fns");
4421
4221
  var import_jsx_runtime22 = require("react/jsx-runtime");
@@ -4597,94 +4397,594 @@ function ITDatePicker({
4597
4397
  }
4598
4398
  }
4599
4399
  };
4600
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { ref: wrapperRef, className: (0, import_clsx22.default)("relative w-full", className), children: [
4601
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4602
- ITInput,
4603
- {
4604
- name,
4605
- type: "text",
4606
- label,
4607
- placeholder,
4608
- value: inputValue,
4609
- onChange: handleInputChange,
4610
- onBlur: handleInputBlur,
4611
- maxLength: 10,
4612
- iconRight: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4613
- import_fa12.FaCalendarAlt,
4400
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { ref: wrapperRef, className: (0, import_clsx22.default)("relative w-full", className), children: [
4401
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4402
+ ITInput,
4403
+ {
4404
+ name,
4405
+ type: "text",
4406
+ label,
4407
+ placeholder,
4408
+ value: inputValue,
4409
+ onChange: handleInputChange,
4410
+ onBlur: handleInputBlur,
4411
+ maxLength: 10,
4412
+ iconRight: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4413
+ import_fa12.FaCalendarAlt,
4414
+ {
4415
+ onClick: handleIconClick,
4416
+ className: "text-slate-500 dark:text-slate-400 cursor-pointer"
4417
+ }
4418
+ ) }),
4419
+ variant,
4420
+ size,
4421
+ disabled,
4422
+ required,
4423
+ touched,
4424
+ error: !isValidDate ? "Fecha inv\xE1lida" : error,
4425
+ onClick: handleIconClick
4426
+ }
4427
+ ),
4428
+ isOpen && (0, import_react_dom4.createPortal)(
4429
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4430
+ "div",
4431
+ {
4432
+ ref: panelRef,
4433
+ className: (0, import_clsx22.default)(
4434
+ calendarClassName,
4435
+ range ? "w-[320px]" : "w-[280px]"
4436
+ ),
4437
+ style: {
4438
+ ...panelStyle,
4439
+ backgroundColor: theme.card.backgroundColor,
4440
+ borderColor: theme.card.borderColor,
4441
+ borderWidth: "1px",
4442
+ borderStyle: "solid",
4443
+ borderRadius: theme.card.borderRadius,
4444
+ boxShadow: theme.card.shadow,
4445
+ padding: "0.5rem"
4446
+ },
4447
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4448
+ calendar_default,
4449
+ {
4450
+ value: !range ? startDate : void 0,
4451
+ startDate,
4452
+ endDate,
4453
+ selectionMode: range ? "range" : "single",
4454
+ onChange: handleDateChange,
4455
+ minDate,
4456
+ maxDate,
4457
+ variant,
4458
+ className: "h-auto border-none shadow-none w-full"
4459
+ }
4460
+ )
4461
+ }
4462
+ ),
4463
+ document.body
4464
+ )
4465
+ ] });
4466
+ }
4467
+
4468
+ // src/utils/table.utils.ts
4469
+ var formatCurrencyMX = (value) => {
4470
+ return value.toLocaleString("es-MX", {
4471
+ style: "currency",
4472
+ currency: "MXN"
4473
+ });
4474
+ };
4475
+ var getNestedValue = (obj, path) => {
4476
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
4477
+ };
4478
+ var ROW_CLICK_IGNORE_SELECTOR = 'button, a, input, select, textarea, [role="button"], [role="link"], [data-row-click-ignore]';
4479
+ function isInteractiveTarget(target, boundary = null) {
4480
+ if (!(target instanceof Element)) return false;
4481
+ const interactive = target.closest(ROW_CLICK_IGNORE_SELECTOR);
4482
+ if (!interactive) return false;
4483
+ if (boundary instanceof Node && interactive === boundary) return false;
4484
+ return true;
4485
+ }
4486
+
4487
+ // src/components/organisms/data-table/dataTable.tsx
4488
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4489
+ var getNestedValue2 = (obj, path) => {
4490
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
4491
+ };
4492
+ var EMPTY_OBJECT = {};
4493
+ function ITDataTable({
4494
+ columns,
4495
+ fetchData,
4496
+ debounceMs = 500,
4497
+ externalFilters = EMPTY_OBJECT,
4498
+ loadingIndicator,
4499
+ fetchOnMount = true,
4500
+ reloadTrigger,
4501
+ containerClassName,
4502
+ className,
4503
+ variant = "default",
4504
+ size = "md",
4505
+ itemsPerPageOptions = [5, 10, 20],
4506
+ defaultItemsPerPage = 10,
4507
+ title,
4508
+ renderCard,
4509
+ defaultView,
4510
+ showVerticalBorder = true,
4511
+ verticalBorderClassname,
4512
+ onRowClick,
4513
+ layout = "auto",
4514
+ density = "normal",
4515
+ autoCardBreakpoint = 0,
4516
+ virtualized = false,
4517
+ virtualizedMaxHeight = 400,
4518
+ rowHeight,
4519
+ overscan = 5,
4520
+ stickyHeader = false
4521
+ }) {
4522
+ const [viewMode, setViewMode] = (0, import_react21.useState)(defaultView || "table");
4523
+ const { ref: rootRef, width: containerWidth } = useElementSize();
4524
+ const [data, setData] = (0, import_react21.useState)([]);
4525
+ const [totalItems, setTotalItems] = (0, import_react21.useState)(0);
4526
+ const [isLoading, setIsLoading] = (0, import_react21.useState)(fetchOnMount);
4527
+ const isFixed = layout === "fixed";
4528
+ const forcedCards = autoCardBreakpoint > 0 && containerWidth > 0 && containerWidth < autoCardBreakpoint;
4529
+ const effectiveView = forcedCards ? "cards" : viewMode;
4530
+ const hasColumnWidths = columns.some((col) => col.width != null);
4531
+ const tableLayoutClass = isFixed ? "w-full text-sm text-left text-secondary-600 transition-opacity duration-300" : "min-w-max w-full text-sm text-left text-secondary-600 transition-opacity duration-300";
4532
+ const isTableVirtual = virtualized && effectiveView === "table";
4533
+ const isStickyHeader = stickyHeader && isTableVirtual;
4534
+ const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
4535
+ const columnCount = columns.length;
4536
+ const scrollOuterClass = isTableVirtual ? "relative min-h-[200px]" : "overflow-x-auto relative min-h-[200px]";
4537
+ const {
4538
+ currentPage,
4539
+ itemsPerPage,
4540
+ filters,
4541
+ sortConfig,
4542
+ goToPage,
4543
+ handleFilterChange,
4544
+ handleSort,
4545
+ handleItemsPerPageChange
4546
+ } = useTableState({ defaultItemsPerPage });
4547
+ const {
4548
+ scrollRef,
4549
+ startIndex,
4550
+ endIndex,
4551
+ topSpacerHeight,
4552
+ bottomSpacerHeight
4553
+ } = useVirtualRows({
4554
+ count: data.length,
4555
+ rowHeight: resolvedRowHeight,
4556
+ overscan,
4557
+ enabled: isTableVirtual,
4558
+ resetKey: `${currentPage}-${itemsPerPage}`
4559
+ });
4560
+ const windowData = isTableVirtual ? data.slice(startIndex, endIndex + 1) : data;
4561
+ const debounceTimerRef = (0, import_react21.useRef)(null);
4562
+ const hasFetchedRef = (0, import_react21.useRef)(false);
4563
+ const fetchDataRef = (0, import_react21.useRef)(fetchData);
4564
+ fetchDataRef.current = fetchData;
4565
+ const externalFiltersRef = (0, import_react21.useRef)(externalFilters);
4566
+ externalFiltersRef.current = externalFilters;
4567
+ const externalKey = JSON.stringify(externalFilters);
4568
+ const computedTotalPages = Math.ceil(totalItems / itemsPerPage) || 1;
4569
+ const performFetch = (0, import_react21.useCallback)(async () => {
4570
+ setIsLoading(true);
4571
+ try {
4572
+ const response = await fetchDataRef.current({
4573
+ page: currentPage,
4574
+ limit: itemsPerPage,
4575
+ filters: { ...filters, ...externalFiltersRef.current },
4576
+ sort: sortConfig || void 0
4577
+ });
4578
+ setData(response.data || []);
4579
+ setTotalItems(response.total || 0);
4580
+ hasFetchedRef.current = true;
4581
+ } catch (error) {
4582
+ console.error("ITDataTable: Error fetching data", error);
4583
+ setData([]);
4584
+ setTotalItems(0);
4585
+ hasFetchedRef.current = true;
4586
+ } finally {
4587
+ setIsLoading(false);
4588
+ }
4589
+ }, [currentPage, itemsPerPage, filters, sortConfig]);
4590
+ const performFetchRef = (0, import_react21.useRef)(performFetch);
4591
+ performFetchRef.current = performFetch;
4592
+ (0, import_react21.useEffect)(() => {
4593
+ if (!fetchOnMount && !hasFetchedRef.current) return;
4594
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4595
+ debounceTimerRef.current = setTimeout(() => {
4596
+ performFetchRef.current();
4597
+ }, debounceMs);
4598
+ return () => {
4599
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4600
+ };
4601
+ }, [currentPage, itemsPerPage, sortConfig, filters, externalKey, reloadTrigger, fetchOnMount, debounceMs]);
4602
+ const renderFilterInput = (col) => {
4603
+ if (!col.filter) return null;
4604
+ if (col.type === "boolean") {
4605
+ const currentValue = filters[col.key];
4606
+ const nextValue = currentValue === void 0 ? true : currentValue === true ? false : void 0;
4607
+ const getToggleLabel = () => {
4608
+ if (currentValue === void 0) return "Mostrar todos";
4609
+ if (currentValue === true) return "Filtrar solo verdaderos";
4610
+ return "Filtrar solo falsos";
4611
+ };
4612
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4613
+ "button",
4614
+ {
4615
+ className: "flex items-center justify-center cursor-pointer focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 rounded-full p-1 transition-all duration-200",
4616
+ onClick: () => handleFilterChange(col.key, nextValue),
4617
+ "aria-label": `${getToggleLabel()} para ${col.label}`,
4618
+ title: `${getToggleLabel()} para ${col.label}`,
4619
+ disabled: isLoading,
4620
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "relative w-10 h-5 bg-secondary-300 rounded-full", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4621
+ "div",
4622
+ {
4623
+ className: (0, import_clsx23.default)(
4624
+ "absolute top-0.5 w-4 h-4 rounded-full transition-all duration-300 shadow-sm",
4625
+ {
4626
+ "left-0.5 bg-secondary-400": currentValue === void 0,
4627
+ "left-5 bg-slate-500": currentValue === true,
4628
+ "left-0.5 bg-secondary-500": currentValue === false
4629
+ }
4630
+ )
4631
+ }
4632
+ ) })
4633
+ }
4634
+ );
4635
+ }
4636
+ if (col.filter === "catalog" && col.catalogOptions) {
4637
+ if (col.catalogOptions.loading) {
4638
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4639
+ }
4640
+ if (col.catalogOptions.error) {
4641
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4642
+ }
4643
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4644
+ ITSelect,
4645
+ {
4646
+ name: `filter-${col.key}`,
4647
+ options: [
4648
+ { value: "", label: "Todos" },
4649
+ ...col.catalogOptions.data.map((item) => ({
4650
+ value: String(item.id),
4651
+ label: item.name
4652
+ }))
4653
+ ],
4654
+ value: String(filters[col.key] || ""),
4655
+ onChange: (e) => {
4656
+ const value = e.target.value === "" ? void 0 : e.target.value;
4657
+ handleFilterChange(col.key, value);
4658
+ },
4659
+ onBlur: () => {
4660
+ },
4661
+ className: "w-full text-xs",
4662
+ disabled: isLoading
4663
+ }
4664
+ );
4665
+ }
4666
+ if (col.filter === "search" && col.catalogOptions) {
4667
+ if (col.catalogOptions.loading) {
4668
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4669
+ }
4670
+ if (col.catalogOptions.error) {
4671
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4672
+ }
4673
+ const searchValue = filters[col.key];
4674
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4675
+ ITSearchSelect,
4676
+ {
4677
+ name: `filter-${col.key}`,
4678
+ options: col.catalogOptions.data.map((item) => ({
4679
+ value: item.id,
4680
+ label: item.name
4681
+ })),
4682
+ value: typeof searchValue === "string" || typeof searchValue === "number" ? searchValue : "",
4683
+ onChange: (value) => handleFilterChange(col.key, value === "" ? void 0 : value),
4684
+ onSearch: col.catalogOptions.onSearch,
4685
+ isLoading: col.catalogOptions.loading,
4686
+ size: "sm",
4687
+ placeholder: "Buscar...",
4688
+ clearable: true,
4689
+ className: "w-full",
4690
+ onBlur: () => {
4691
+ },
4692
+ disabled: isLoading
4693
+ }
4694
+ );
4695
+ }
4696
+ if (col.filter === "date") {
4697
+ const dateValue = filters[col.key];
4698
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4699
+ ITDatePicker,
4700
+ {
4701
+ name: `filter-${col.key}`,
4702
+ value: dateValue instanceof Date ? dateValue : void 0,
4703
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4704
+ minDate: col.dateFilterOptions?.minDate,
4705
+ maxDate: col.dateFilterOptions?.maxDate,
4706
+ size: "sm",
4707
+ placeholder: "dd/mm/aaaa",
4708
+ className: "w-full",
4709
+ disabled: isLoading
4710
+ }
4711
+ );
4712
+ }
4713
+ if (col.filter === "date-range") {
4714
+ const rangeValue = filters[col.key];
4715
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4716
+ ITDatePicker,
4717
+ {
4718
+ name: `filter-${col.key}`,
4719
+ range: true,
4720
+ value: Array.isArray(rangeValue) ? rangeValue : void 0,
4721
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4722
+ minDate: col.dateFilterOptions?.minDate,
4723
+ maxDate: col.dateFilterOptions?.maxDate,
4724
+ size: "sm",
4725
+ placeholder: "dd/mm/aaaa - dd/mm/aaaa",
4726
+ className: "w-full",
4727
+ disabled: isLoading
4728
+ }
4729
+ );
4730
+ }
4731
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4732
+ ITInput,
4733
+ {
4734
+ name: `filter-${col.key}`,
4735
+ className: "w-full text-xs",
4736
+ placeholder: "Buscar...",
4737
+ value: String(filters[col.key] || ""),
4738
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4739
+ onBlur: () => {
4740
+ },
4741
+ disabled: isLoading
4742
+ }
4743
+ );
4744
+ };
4745
+ const renderCellContent = (col, row) => {
4746
+ const value = getNestedValue2(row, col.key);
4747
+ if (col.render) return col.render(row);
4748
+ switch (col.type) {
4749
+ case "number":
4750
+ return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
4751
+ case "boolean":
4752
+ return value ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaCheck, { className: "text-success-500", "aria-label": "Verdadero", title: "Verdadero" }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTimes, { className: "text-danger-500", "aria-label": "Falso", title: "Falso" });
4753
+ case "actions":
4754
+ return col.actions ? col.actions(row) : null;
4755
+ case "catalog":
4756
+ if (col.catalogOptions) {
4757
+ const catalogItem = col.catalogOptions.data.find((item) => item.id === value);
4758
+ return catalogItem?.name || value;
4759
+ }
4760
+ return value;
4761
+ default:
4762
+ return value;
4763
+ }
4764
+ };
4765
+ const renderDefaultCard = (row) => {
4766
+ const dataCols = columns.filter((c) => c.type !== "actions");
4767
+ const actionCol = columns.find((c) => c.type === "actions");
4768
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-3 space-y-2 shadow-sm", children: [
4769
+ dataCols.map((col) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
4770
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-[10px] font-bold uppercase tracking-wider text-slate-400 whitespace-nowrap flex-shrink-0 min-w-[70px]", children: col.label }),
4771
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-sm font-medium text-slate-800 dark:text-white text-right truncate", children: renderCellContent(col, row) })
4772
+ ] }, col.key)),
4773
+ actionCol?.actions && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex items-center justify-end gap-2 pt-2 border-t border-slate-100 dark:border-slate-700", children: actionCol.actions(row) })
4774
+ ] });
4775
+ };
4776
+ const segCtrlClass = (mode) => `flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold transition-all ${effectiveView === mode ? "bg-white dark:bg-slate-900 text-slate-900 dark:text-white shadow-sm border border-slate-200/50 dark:border-slate-700" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"}`;
4777
+ const handleRowClick = (row) => (event) => {
4778
+ if (!onRowClick || isLoading || isInteractiveTarget(event.target, event.currentTarget)) return;
4779
+ onRowClick(row, event);
4780
+ };
4781
+ const handleRowKeyDown = (row) => (event) => {
4782
+ if (!onRowClick || isLoading) return;
4783
+ if (event.target !== event.currentTarget) return;
4784
+ if (event.key !== "Enter" && event.key !== " ") return;
4785
+ event.preventDefault();
4786
+ onRowClick(row, event);
4787
+ };
4788
+ const tableEl = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4789
+ "table",
4790
+ {
4791
+ className: (0, import_clsx23.default)(
4792
+ tableLayoutClass,
4793
+ showVerticalBorder && "[&_th]:border-r [&_th:last-child]:border-r-0 [&_td]:border-r [&_td:last-child]:border-r-0",
4794
+ showVerticalBorder && (verticalBorderClassname || "[&_th]:border-slate-100 dark:[&_th]:border-slate-700/30 [&_td]:border-slate-100 dark:[&_td]:border-slate-700/30"),
4795
+ isLoading ? "opacity-50" : "opacity-100",
4796
+ variantStyles[variant],
4797
+ sizeStyles[size],
4798
+ className
4799
+ ),
4800
+ style: isFixed ? { tableLayout: "fixed" } : void 0,
4801
+ "aria-rowcount": isTableVirtual ? data.length + 1 : void 0,
4802
+ children: [
4803
+ hasColumnWidths && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("colgroup", { children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4804
+ "col",
4614
4805
  {
4615
- onClick: handleIconClick,
4616
- className: "text-slate-500 dark:text-slate-400 cursor-pointer"
4806
+ style: col.width != null ? { width: typeof col.width === "number" ? `${col.width}px` : col.width } : void 0
4807
+ },
4808
+ col.key
4809
+ )) }),
4810
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4811
+ "tr",
4812
+ {
4813
+ className: (0, import_clsx23.default)(tableHeaderRow, "dark:text-slate-200"),
4814
+ "aria-rowindex": isTableVirtual ? 1 : void 0,
4815
+ children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4816
+ "th",
4817
+ {
4818
+ scope: "col",
4819
+ className: (0, import_clsx23.default)(
4820
+ tableHeaderCell(col.className, density),
4821
+ col.align && tableAlignClasses[col.align],
4822
+ isStickyHeader && "sticky top-0 z-10 bg-secondary-50"
4823
+ ),
4824
+ style: col.minWidth != null || isStickyHeader ? {
4825
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4826
+ ...isStickyHeader ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {}
4827
+ } : void 0,
4828
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
4829
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
4830
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
4831
+ col.sortable && col.type !== "actions" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4832
+ "button",
4833
+ {
4834
+ onClick: () => handleSort(col.key),
4835
+ disabled: isLoading,
4836
+ className: `p-1 rounded-md transition-colors ${sortConfig?.key === col.key ? "bg-secondary-200 text-secondary-900" : "hover:bg-secondary-200 text-secondary-400 hover:text-secondary-700"} disabled:opacity-50`,
4837
+ title: `Ordenar por ${col.label}`,
4838
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_md.MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
4839
+ }
4840
+ )
4841
+ ] }),
4842
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
4843
+ ] })
4844
+ },
4845
+ col.key
4846
+ ))
4617
4847
  }
4618
4848
  ) }),
4619
- variant,
4620
- size,
4621
- disabled,
4622
- required,
4623
- touched,
4624
- error: !isValidDate ? "Fecha inv\xE1lida" : error,
4625
- onClick: handleIconClick
4626
- }
4627
- ),
4628
- isOpen && (0, import_react_dom3.createPortal)(
4629
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4630
- "div",
4631
- {
4632
- ref: panelRef,
4633
- className: (0, import_clsx22.default)(
4634
- calendarClassName,
4635
- range ? "w-[320px]" : "w-[280px]"
4636
- ),
4637
- style: {
4638
- ...panelStyle,
4639
- backgroundColor: theme.card.backgroundColor,
4640
- borderColor: theme.card.borderColor,
4641
- borderWidth: "1px",
4642
- borderStyle: "solid",
4643
- borderRadius: theme.card.borderRadius,
4644
- boxShadow: theme.card.shadow,
4645
- padding: "0.5rem"
4849
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tbody", { className: (0, import_clsx23.default)(tableBody, "dark:divide-slate-700/30"), children: data.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
4850
+ isTableVirtual && topSpacerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tr", { "aria-hidden": "true", style: { height: topSpacerHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) }),
4851
+ windowData.map((row, windowIndex) => {
4852
+ const absoluteIndex = isTableVirtual ? startIndex + windowIndex : windowIndex;
4853
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4854
+ "tr",
4855
+ {
4856
+ "aria-rowindex": isTableVirtual ? absoluteIndex + 2 : void 0,
4857
+ className: (0, import_clsx23.default)(
4858
+ tableRow,
4859
+ variant === "striped" && absoluteIndex % 2 === 0 && "bg-secondary-50/40 dark:bg-slate-800/20",
4860
+ onRowClick && !isLoading && tableRowClickable
4861
+ ),
4862
+ tabIndex: onRowClick && !isLoading ? 0 : void 0,
4863
+ onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4864
+ onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4865
+ children: columns.map((col) => {
4866
+ const rawValue = getNestedValue2(row, col.key);
4867
+ const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
4868
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4869
+ "td",
4870
+ {
4871
+ className: (0, import_clsx23.default)(
4872
+ tableCell(col.className, density),
4873
+ col.align && tableAlignClasses[col.align]
4874
+ ),
4875
+ style: col.minWidth != null ? { minWidth: `${col.minWidth}px` } : void 0,
4876
+ title: truncateTitle,
4877
+ children: col.type === "actions" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: tableActionsCell, children: renderCellContent(col, row) }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: (0, import_clsx23.default)(tableCellText, col.truncate && "truncate"), children: renderCellContent(col, row) })
4878
+ },
4879
+ `${absoluteIndex}-${col.key}`
4880
+ );
4881
+ })
4882
+ },
4883
+ absoluteIndex
4884
+ );
4885
+ }),
4886
+ isTableVirtual && bottomSpacerHeight > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tr", { "aria-hidden": "true", style: { height: bottomSpacerHeight }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { colSpan: columnCount, style: { padding: 0, border: 0 } }) })
4887
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("td", { colSpan: columns.length, className: "px-6 py-12 text-center", children: !isLoading && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: tableEmptyContent, children: [
4888
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4889
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4890
+ ] }) }) }) })
4891
+ ]
4892
+ }
4893
+ );
4894
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { ref: rootRef, className: (0, import_clsx23.default)("space-y-4 w-full relative", containerClassName), children: [
4895
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: tableContainer, style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4896
+ title && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "px-6 py-5 flex items-center justify-between", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4897
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "h2", className: "text-xl font-bold text-secondary-900 leading-tight", children: title }),
4898
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-3", children: [
4899
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "text-secondary-400", children: loadingIndicator || /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin text-primary-500 text-xl" }) }),
4900
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center bg-slate-100 dark:bg-slate-800/80 rounded-lg p-0.5 border border-slate-200 dark:border-slate-700/50", children: [
4901
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4902
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTable, { size: 11 }),
4903
+ "Table"
4904
+ ] }),
4905
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4906
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaThLarge, { size: 11 }),
4907
+ "Cards"
4908
+ ] })
4909
+ ] })
4910
+ ] })
4911
+ ] }),
4912
+ !title && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex justify-end px-4 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center bg-slate-100 dark:bg-slate-800/80 rounded-lg p-0.5 border border-slate-200 dark:border-slate-700/50", children: [
4913
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4914
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTable, { size: 11 }),
4915
+ "Table"
4916
+ ] }),
4917
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4918
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaThLarge, { size: 11 }),
4919
+ "Cards"
4920
+ ] })
4921
+ ] }) }),
4922
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: scrollOuterClass, children: [
4923
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "absolute inset-0 z-20 flex items-center justify-center bg-white/40 backdrop-blur-[2px] transition-all duration-300", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "flex flex-col items-center gap-3 p-6 rounded-2xl shadow-xl border border-secondary-100 animate-in fade-in zoom-in duration-300", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: loadingIndicator || /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
4924
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin text-primary-500 text-4xl" }),
4925
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-sm font-semibold text-secondary-600 animate-pulse", children: "Cargando datos..." })
4926
+ ] }) }) }),
4927
+ effectiveView === "cards" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "p-4 space-y-3 max-h-[400px] overflow-y-auto", children: data.length > 0 ? data.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4928
+ "div",
4929
+ {
4930
+ className: (0, import_clsx23.default)(tableCardHover, onRowClick && !isLoading && tableCardClickable),
4931
+ role: onRowClick && !isLoading ? "button" : void 0,
4932
+ tabIndex: onRowClick && !isLoading ? 0 : void 0,
4933
+ onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4934
+ onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4935
+ children: renderCard ? renderCard(row) : renderDefaultCard(row)
4646
4936
  },
4647
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4648
- calendar_default,
4649
- {
4650
- value: !range ? startDate : void 0,
4651
- startDate,
4652
- endDate,
4653
- selectionMode: range ? "range" : "single",
4654
- onChange: handleDateChange,
4655
- minDate,
4656
- maxDate,
4657
- variant,
4658
- className: "h-auto border-none shadow-none w-full"
4659
- }
4660
- )
4661
- }
4662
- ),
4663
- document.body
4664
- )
4937
+ i
4938
+ )) : !isLoading && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: (0, import_clsx23.default)(tableEmptyContent, "py-12"), children: [
4939
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4940
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4941
+ ] }) }) : isTableVirtual ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4942
+ "div",
4943
+ {
4944
+ ref: scrollRef,
4945
+ className: "overflow-x-auto overflow-y-auto",
4946
+ style: { maxHeight: virtualizedMaxHeight },
4947
+ children: tableEl
4948
+ }
4949
+ ) : tableEl
4950
+ ] })
4951
+ ] }),
4952
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "rounded-b-xl px-6 py-4", style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4953
+ ITPagination,
4954
+ {
4955
+ currentPage,
4956
+ totalPages: computedTotalPages,
4957
+ onPageChange: goToPage,
4958
+ color: "primary",
4959
+ itemsPerPageOptions,
4960
+ itemsPerPage,
4961
+ onItemsPerPageChange: handleItemsPerPageChange,
4962
+ totalItems
4963
+ }
4964
+ ) })
4665
4965
  ] });
4666
4966
  }
4667
4967
 
4668
4968
  // src/components/organisms/dialog/dialog.tsx
4669
- var import_react_dom4 = require("react-dom");
4670
- var import_react22 = require("react");
4671
- var import_fa14 = require("react-icons/fa");
4969
+ var import_react_dom5 = require("react-dom");
4970
+ var import_react23 = require("react");
4971
+ var import_fa15 = require("react-icons/fa");
4672
4972
 
4673
4973
  // src/components/molecules/form-header/form-header.tsx
4674
- var import_fa13 = require("react-icons/fa");
4974
+ var import_fa14 = require("react-icons/fa");
4675
4975
 
4676
4976
  // src/theme/theme-context.ts
4677
- var import_react21 = require("react");
4678
- var ITThemeContext = (0, import_react21.createContext)(void 0);
4977
+ var import_react22 = require("react");
4978
+ var ITThemeContext = (0, import_react22.createContext)(void 0);
4679
4979
  var useITTheme = () => {
4680
- const context = (0, import_react21.useContext)(ITThemeContext);
4980
+ const context = (0, import_react22.useContext)(ITThemeContext);
4681
4981
  if (!context) {
4682
4982
  throw new Error("useITTheme must be used within an ITThemeProvider");
4683
4983
  }
4684
4984
  return context;
4685
4985
  };
4686
4986
  var useITThemeSafe = () => {
4687
- return (0, import_react21.useContext)(ITThemeContext);
4987
+ return (0, import_react22.useContext)(ITThemeContext);
4688
4988
  };
4689
4989
 
4690
4990
  // src/utils/color.utils.ts
@@ -4764,7 +5064,7 @@ var getContrastTextColor = (bgColor, palette2, isDarkMode) => {
4764
5064
  };
4765
5065
 
4766
5066
  // src/components/molecules/form-header/form-header.tsx
4767
- var import_jsx_runtime23 = require("react/jsx-runtime");
5067
+ var import_jsx_runtime24 = require("react/jsx-runtime");
4768
5068
  function ITFormHeader({
4769
5069
  title,
4770
5070
  onClose,
@@ -4778,23 +5078,23 @@ function ITFormHeader({
4778
5078
  palette2,
4779
5079
  isDarkMode
4780
5080
  );
4781
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: `bg-primary-500 ${textColorClass} px-6 py-4 rounded-t-lg flex justify-center items-center relative ${className}`, children: [
4782
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "h2", className: "text-lg font-semibold text-center", style: { color: "inherit" }, children: title }),
4783
- onClose && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5081
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: `bg-primary-500 ${textColorClass} px-6 py-4 rounded-t-lg flex justify-center items-center relative ${className}`, children: [
5082
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ITText, { as: "h2", className: "text-lg font-semibold text-center", style: { color: "inherit" }, children: title }),
5083
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4784
5084
  "button",
4785
5085
  {
4786
5086
  onClick: onClose,
4787
5087
  className: `absolute right-4 ${textColorClass} hover:opacity-80 transition-colors duration-200 p-1 rounded-full`,
4788
5088
  style: { color: "inherit" },
4789
5089
  "aria-label": "Cerrar",
4790
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTimes, { className: "w-4 h-4" })
5090
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fa14.FaTimes, { className: "w-4 h-4" })
4791
5091
  }
4792
5092
  )
4793
5093
  ] });
4794
5094
  }
4795
5095
 
4796
5096
  // src/components/organisms/dialog/dialog.tsx
4797
- var import_jsx_runtime24 = require("react/jsx-runtime");
5097
+ var import_jsx_runtime25 = require("react/jsx-runtime");
4798
5098
  function ITDialog({
4799
5099
  isOpen,
4800
5100
  onClose,
@@ -4804,9 +5104,9 @@ function ITDialog({
4804
5104
  useFormHeader = false,
4805
5105
  fullScreen = false
4806
5106
  }) {
4807
- const modalRef = (0, import_react22.useRef)(null);
5107
+ const modalRef = (0, import_react23.useRef)(null);
4808
5108
  useClickOutside_default(modalRef, onClose);
4809
- (0, import_react22.useEffect)(() => {
5109
+ (0, import_react23.useEffect)(() => {
4810
5110
  const handleEscape = (event) => {
4811
5111
  if (event.key === "Escape") {
4812
5112
  onClose();
@@ -4821,12 +5121,12 @@ function ITDialog({
4821
5121
  }, [isOpen, onClose]);
4822
5122
  if (!isOpen) return null;
4823
5123
  if (typeof document === "undefined") return null;
4824
- const content = /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5124
+ const content = /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4825
5125
  "div",
4826
5126
  {
4827
5127
  "data-it-dialog": "true",
4828
5128
  className: `fixed inset-0 flex ${fullScreen ? "items-stretch" : "items-center justify-center"} bg-slate-900/50 z-[60]`,
4829
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5129
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4830
5130
  "div",
4831
5131
  {
4832
5132
  ref: modalRef,
@@ -4839,41 +5139,41 @@ function ITDialog({
4839
5139
  borderColor: theme.card.borderColor,
4840
5140
  borderStyle: "solid"
4841
5141
  },
4842
- children: useFormHeader && title ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
4843
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ITFormHeader, { title, onClose }),
4844
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: fullScreen ? "flex-1 overflow-auto p-6" : "p-6", children })
4845
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_jsx_runtime24.Fragment, { children: [
4846
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5142
+ children: useFormHeader && title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5143
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ITFormHeader, { title, onClose }),
5144
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: fullScreen ? "flex-1 overflow-auto p-6" : "p-6", children })
5145
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5146
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4847
5147
  "button",
4848
5148
  {
4849
5149
  className: "absolute top-2 right-2 text-secondary-600 hover:text-secondary-900",
4850
5150
  onClick: onClose,
4851
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fa14.FaRegTimesCircle, {})
5151
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_fa15.FaRegTimesCircle, {})
4852
5152
  }
4853
5153
  ),
4854
- title && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ITText, { as: "h2", className: "text-xl font-semibold mb-4", children: title }),
4855
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { children })
5154
+ title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ITText, { as: "h2", className: "text-xl font-semibold mb-4", children: title }),
5155
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { children })
4856
5156
  ] })
4857
5157
  }
4858
5158
  )
4859
5159
  }
4860
5160
  );
4861
- return (0, import_react_dom4.createPortal)(content, document.body);
5161
+ return (0, import_react_dom5.createPortal)(content, document.body);
4862
5162
  }
4863
5163
 
4864
5164
  // src/components/atoms/divider/divider.tsx
4865
- var import_clsx23 = __toESM(require("clsx"), 1);
4866
- var import_jsx_runtime25 = require("react/jsx-runtime");
5165
+ var import_clsx24 = __toESM(require("clsx"), 1);
5166
+ var import_jsx_runtime26 = require("react/jsx-runtime");
4867
5167
  function ITDivider({
4868
5168
  orientation = "horizontal",
4869
5169
  className,
4870
5170
  color = "bg-slate-200 dark:bg-slate-700",
4871
5171
  thickness = orientation === "horizontal" ? "h-px" : "w-px"
4872
5172
  }) {
4873
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5173
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
4874
5174
  "div",
4875
5175
  {
4876
- className: (0, import_clsx23.default)(
5176
+ className: (0, import_clsx24.default)(
4877
5177
  "flex-shrink-0",
4878
5178
  orientation === "horizontal" ? "w-full" : "self-stretch",
4879
5179
  thickness,
@@ -4885,10 +5185,10 @@ function ITDivider({
4885
5185
  }
4886
5186
 
4887
5187
  // src/components/organisms/drawer/drawer.tsx
4888
- var import_clsx24 = __toESM(require("clsx"), 1);
4889
- var import_fa15 = require("react-icons/fa");
4890
- var import_react23 = require("react");
4891
- var import_jsx_runtime26 = require("react/jsx-runtime");
5188
+ var import_clsx25 = __toESM(require("clsx"), 1);
5189
+ var import_fa16 = require("react-icons/fa");
5190
+ var import_react24 = require("react");
5191
+ var import_jsx_runtime27 = require("react/jsx-runtime");
4892
5192
  function ITDrawer({
4893
5193
  isOpen,
4894
5194
  onClose,
@@ -4899,15 +5199,15 @@ function ITDrawer({
4899
5199
  className,
4900
5200
  style
4901
5201
  }) {
4902
- const panelRef = (0, import_react23.useRef)(null);
5202
+ const panelRef = (0, import_react24.useRef)(null);
4903
5203
  useClickOutside_default(panelRef, onClose);
4904
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_jsx_runtime26.Fragment, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "fixed inset-0 z-[50] flex", children: [
4905
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity" }),
4906
- /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5204
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_jsx_runtime27.Fragment, { children: isOpen && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "fixed inset-0 z-[50] flex", children: [
5205
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity" }),
5206
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
4907
5207
  "div",
4908
5208
  {
4909
5209
  ref: panelRef,
4910
- className: (0, import_clsx24.default)(
5210
+ className: (0, import_clsx25.default)(
4911
5211
  "relative z-10 h-full bg-white dark:bg-slate-900 shadow-2xl flex flex-col transition-transform duration-300",
4912
5212
  position === "right" ? "ml-auto" : "mr-auto",
4913
5213
  size,
@@ -4915,18 +5215,18 @@ function ITDrawer({
4915
5215
  ),
4916
5216
  style,
4917
5217
  children: [
4918
- title && /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-slate-700", children: [
4919
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ITText, { as: "h2", className: "text-lg font-bold text-slate-800 dark:text-white", children: title }),
4920
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5218
+ title && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between px-5 py-4 border-b border-slate-200 dark:border-slate-700", children: [
5219
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ITText, { as: "h2", className: "text-lg font-bold text-slate-800 dark:text-white", children: title }),
5220
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
4921
5221
  "button",
4922
5222
  {
4923
5223
  onClick: onClose,
4924
5224
  className: "w-8 h-8 flex items-center justify-center rounded-lg hover:bg-slate-100 dark:hover:bg-slate-800 text-slate-400 hover:text-slate-600 transition-colors",
4925
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_fa15.FaTimes, { size: 14 })
5225
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa16.FaTimes, { size: 14 })
4926
5226
  }
4927
5227
  )
4928
5228
  ] }),
4929
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex-1 overflow-y-auto p-5", children })
5229
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex-1 overflow-y-auto p-5", children })
4930
5230
  ]
4931
5231
  }
4932
5232
  )
@@ -4934,27 +5234,27 @@ function ITDrawer({
4934
5234
  }
4935
5235
 
4936
5236
  // src/components/molecules/empty-state/empty-state.tsx
4937
- var import_clsx25 = __toESM(require("clsx"), 1);
4938
- var import_fa16 = require("react-icons/fa");
4939
- var import_jsx_runtime27 = require("react/jsx-runtime");
5237
+ var import_clsx26 = __toESM(require("clsx"), 1);
5238
+ var import_fa17 = require("react-icons/fa");
5239
+ var import_jsx_runtime28 = require("react/jsx-runtime");
4940
5240
  function ITEmptyState({
4941
- icon = /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa16.FaInbox, { size: 40 }),
5241
+ icon = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa17.FaInbox, { size: 40 }),
4942
5242
  title,
4943
5243
  description,
4944
5244
  action,
4945
5245
  className
4946
5246
  }) {
4947
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: (0, import_clsx25.default)("flex flex-col items-center justify-center py-16 px-6 text-center", className), children: [
4948
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "text-slate-300 dark:text-slate-600 mb-4", children: icon }),
4949
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ITText, { as: "h3", className: "text-lg font-bold text-slate-700 dark:text-slate-200 mb-1", children: title }),
4950
- description && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ITText, { as: "p", className: "text-sm text-slate-400 dark:text-slate-500 max-w-sm mb-4", children: description }),
4951
- action && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { children: action })
5247
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: (0, import_clsx26.default)("flex flex-col items-center justify-center py-16 px-6 text-center", className), children: [
5248
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-slate-300 dark:text-slate-600 mb-4", children: icon }),
5249
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ITText, { as: "h3", className: "text-lg font-bold text-slate-700 dark:text-slate-200 mb-1", children: title }),
5250
+ description && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(ITText, { as: "p", className: "text-sm text-slate-400 dark:text-slate-500 max-w-sm mb-4", children: description }),
5251
+ action && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { children: action })
4952
5252
  ] });
4953
5253
  }
4954
5254
 
4955
5255
  // src/components/atoms/flex/flex.tsx
4956
- var import_clsx26 = __toESM(require("clsx"), 1);
4957
- var import_jsx_runtime28 = require("react/jsx-runtime");
5256
+ var import_clsx27 = __toESM(require("clsx"), 1);
5257
+ var import_jsx_runtime29 = require("react/jsx-runtime");
4958
5258
  var directionMap = {
4959
5259
  row: "flex-row",
4960
5260
  column: "flex-col",
@@ -5003,10 +5303,10 @@ function ITFlex({
5003
5303
  flexBasis: typeof basis === "number" ? `${basis * 0.25}rem` : basis,
5004
5304
  ...style
5005
5305
  };
5006
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5306
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5007
5307
  Component,
5008
5308
  {
5009
- className: (0, import_clsx26.default)(
5309
+ className: (0, import_clsx27.default)(
5010
5310
  "flex",
5011
5311
  directionMap[direction],
5012
5312
  align && alignMap[align],
@@ -5025,33 +5325,33 @@ function ITFlex({
5025
5325
  var import_react29 = require("react");
5026
5326
 
5027
5327
  // src/components/organisms/form-builder/formBuilder.context.tsx
5028
- var import_react24 = __toESM(require("react"), 1);
5029
- var import_jsx_runtime29 = require("react/jsx-runtime");
5030
- var ITFormBuilderContext = (0, import_react24.createContext)(void 0);
5328
+ var import_react25 = __toESM(require("react"), 1);
5329
+ var import_jsx_runtime30 = require("react/jsx-runtime");
5330
+ var ITFormBuilderContext = (0, import_react25.createContext)(void 0);
5031
5331
  var ITFormBuilderProvider = ({
5032
5332
  children,
5033
5333
  value
5034
5334
  }) => {
5035
- const [fieldRegistry, setFieldRegistry] = (0, import_react24.useState)({});
5036
- const registerField = import_react24.default.useCallback((name, config2) => {
5335
+ const [fieldRegistry, setFieldRegistry] = (0, import_react25.useState)({});
5336
+ const registerField = import_react25.default.useCallback((name, config2) => {
5037
5337
  setFieldRegistry((prev) => ({ ...prev, [name]: config2 }));
5038
5338
  }, []);
5039
- const unregisterField = import_react24.default.useCallback((name) => {
5339
+ const unregisterField = import_react25.default.useCallback((name) => {
5040
5340
  setFieldRegistry((prev) => {
5041
5341
  const next = { ...prev };
5042
5342
  delete next[name];
5043
5343
  return next;
5044
5344
  });
5045
5345
  }, []);
5046
- const getFieldConfig = import_react24.default.useCallback(
5346
+ const getFieldConfig = import_react25.default.useCallback(
5047
5347
  (name) => fieldRegistry[name],
5048
5348
  [fieldRegistry]
5049
5349
  );
5050
- const getAllFieldConfigs = import_react24.default.useCallback(
5350
+ const getAllFieldConfigs = import_react25.default.useCallback(
5051
5351
  () => Object.values(fieldRegistry),
5052
5352
  [fieldRegistry]
5053
5353
  );
5054
- const contextValue = import_react24.default.useMemo(
5354
+ const contextValue = import_react25.default.useMemo(
5055
5355
  () => ({
5056
5356
  ...value,
5057
5357
  registerField,
@@ -5061,10 +5361,10 @@ var ITFormBuilderProvider = ({
5061
5361
  }),
5062
5362
  [value, registerField, unregisterField, getFieldConfig, getAllFieldConfigs]
5063
5363
  );
5064
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ITFormBuilderContext.Provider, { value: contextValue, children });
5364
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ITFormBuilderContext.Provider, { value: contextValue, children });
5065
5365
  };
5066
5366
  var useITFormBuilderContext = () => {
5067
- const context = (0, import_react24.useContext)(ITFormBuilderContext);
5367
+ const context = (0, import_react25.useContext)(ITFormBuilderContext);
5068
5368
  if (!context) {
5069
5369
  throw new Error("useITFormBuilderContext must be used within an ITFormBuilderProvider");
5070
5370
  }
@@ -5076,11 +5376,11 @@ var import_react28 = require("react");
5076
5376
  var import_clsx29 = __toESM(require("clsx"), 1);
5077
5377
 
5078
5378
  // src/components/molecules/time-picker/timePicker.tsx
5079
- var import_clsx27 = __toESM(require("clsx"), 1);
5080
- var import_react25 = require("react");
5081
- var import_react_dom5 = require("react-dom");
5082
- var import_fa17 = require("react-icons/fa");
5083
- var import_jsx_runtime30 = require("react/jsx-runtime");
5379
+ var import_clsx28 = __toESM(require("clsx"), 1);
5380
+ var import_react26 = require("react");
5381
+ var import_react_dom6 = require("react-dom");
5382
+ var import_fa18 = require("react-icons/fa");
5383
+ var import_jsx_runtime31 = require("react/jsx-runtime");
5084
5384
  function ITTimePicker({
5085
5385
  name,
5086
5386
  value,
@@ -5097,12 +5397,12 @@ function ITTimePicker({
5097
5397
  variant = "primary",
5098
5398
  color = "primary"
5099
5399
  }) {
5100
- const [isOpen, setIsOpen] = (0, import_react25.useState)(false);
5101
- const [inputValue, setInputValue] = (0, import_react25.useState)(value || "");
5102
- const [isValidTime, setIsValidTime] = (0, import_react25.useState)(true);
5103
- const wrapperRef = (0, import_react25.useRef)(null);
5104
- const hoursRef = (0, import_react25.useRef)(null);
5105
- const minutesRef = (0, import_react25.useRef)(null);
5400
+ const [isOpen, setIsOpen] = (0, import_react26.useState)(false);
5401
+ const [inputValue, setInputValue] = (0, import_react26.useState)(value || "");
5402
+ const [isValidTime, setIsValidTime] = (0, import_react26.useState)(true);
5403
+ const wrapperRef = (0, import_react26.useRef)(null);
5404
+ const hoursRef = (0, import_react26.useRef)(null);
5405
+ const minutesRef = (0, import_react26.useRef)(null);
5106
5406
  const { panelRef: dropdownRef, style: panelStyle } = useFloatingPanel(
5107
5407
  wrapperRef,
5108
5408
  isOpen && !disabled,
@@ -5116,7 +5416,7 @@ function ITTimePicker({
5116
5416
  const isThemeColor = color in theme.colors;
5117
5417
  const highlightColor = isThemeColor ? theme.colors[color][50] : "#f3f4f6";
5118
5418
  const activeColor = isThemeColor ? theme.colors[color][100] : "#e5e7eb";
5119
- (0, import_react25.useEffect)(() => {
5419
+ (0, import_react26.useEffect)(() => {
5120
5420
  setInputValue(value || "");
5121
5421
  }, [value]);
5122
5422
  const validateTime = (timeString) => {
@@ -5125,7 +5425,7 @@ function ITTimePicker({
5125
5425
  };
5126
5426
  const currentHour = validateTime(inputValue) ? inputValue.split(":")[0] : null;
5127
5427
  const currentMinute = validateTime(inputValue) ? inputValue.split(":")[1] : null;
5128
- (0, import_react25.useEffect)(() => {
5428
+ (0, import_react26.useEffect)(() => {
5129
5429
  if (isOpen) {
5130
5430
  setTimeout(() => {
5131
5431
  if (hoursRef.current && currentHour) {
@@ -5195,8 +5495,8 @@ function ITTimePicker({
5195
5495
  { length: 60 },
5196
5496
  (_, i) => i.toString().padStart(2, "0")
5197
5497
  );
5198
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { ref: wrapperRef, className: (0, import_clsx27.default)("relative w-full", className), children: [
5199
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5498
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { ref: wrapperRef, className: (0, import_clsx28.default)("relative w-full", className), children: [
5499
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5200
5500
  ITInput,
5201
5501
  {
5202
5502
  name,
@@ -5213,15 +5513,15 @@ function ITTimePicker({
5213
5513
  size,
5214
5514
  touched,
5215
5515
  error: !isValidTime ? "Hora inv\xE1lida" : typeof error === "string" ? error : void 0,
5216
- iconRight: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5217
- import_fa17.FaClock,
5516
+ iconRight: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5517
+ import_fa18.FaClock,
5218
5518
  {
5219
5519
  onClick: () => {
5220
5520
  if (!disabled) {
5221
5521
  setIsOpen(!isOpen);
5222
5522
  }
5223
5523
  },
5224
- className: (0, import_clsx27.default)(
5524
+ className: (0, import_clsx28.default)(
5225
5525
  "cursor-pointer transition-colors",
5226
5526
  disabled ? "text-slate-400 cursor-not-allowed" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
5227
5527
  )
@@ -5229,31 +5529,31 @@ function ITTimePicker({
5229
5529
  )
5230
5530
  }
5231
5531
  ),
5232
- isOpen && !disabled && (0, import_react_dom5.createPortal)(
5233
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
5532
+ isOpen && !disabled && (0, import_react_dom6.createPortal)(
5533
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
5234
5534
  "div",
5235
5535
  {
5236
5536
  ref: dropdownRef,
5237
5537
  className: "bg-white border border-secondary-100 shadow-xl rounded-xl w-64 overflow-hidden flex flex-col animate-in fade-in zoom-in-95 duration-200 origin-top it-timepicker-dropdown",
5238
5538
  style: panelStyle,
5239
5539
  children: [
5240
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex bg-secondary-50 border-b border-secondary-100 text-xs font-semibold text-secondary-500 uppercase tracking-wider", children: [
5241
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ITText, { as: "div", className: "flex-1 text-center py-2 border-r border-secondary-100", children: "Horas" }),
5242
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ITText, { as: "div", className: "flex-1 text-center py-2", children: "Minutos" })
5540
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex bg-secondary-50 border-b border-secondary-100 text-xs font-semibold text-secondary-500 uppercase tracking-wider", children: [
5541
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "div", className: "flex-1 text-center py-2 border-r border-secondary-100", children: "Horas" }),
5542
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "div", className: "flex-1 text-center py-2", children: "Minutos" })
5243
5543
  ] }),
5244
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex h-56 relative bg-white", children: [
5245
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5544
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex h-56 relative bg-white", children: [
5545
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5246
5546
  "div",
5247
5547
  {
5248
5548
  ref: hoursRef,
5249
5549
  className: "flex-1 overflow-y-auto no-scrollbar border-r border-secondary-50 scroll-smooth relative",
5250
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "py-2", children: hoursList.map((h) => {
5550
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "py-2", children: hoursList.map((h) => {
5251
5551
  const isSelected = currentHour === h;
5252
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5552
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5253
5553
  "div",
5254
5554
  {
5255
5555
  "data-value": h,
5256
- className: (0, import_clsx27.default)(
5556
+ className: (0, import_clsx28.default)(
5257
5557
  "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5258
5558
  isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5259
5559
  ),
@@ -5276,18 +5576,18 @@ function ITTimePicker({
5276
5576
  }) })
5277
5577
  }
5278
5578
  ),
5279
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5579
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5280
5580
  "div",
5281
5581
  {
5282
5582
  ref: minutesRef,
5283
5583
  className: "flex-1 overflow-y-auto no-scrollbar scroll-smooth relative",
5284
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "py-2", children: minutesList.map((m) => {
5584
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "py-2", children: minutesList.map((m) => {
5285
5585
  const isSelected = currentMinute === m;
5286
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5586
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5287
5587
  "div",
5288
5588
  {
5289
5589
  "data-value": m,
5290
- className: (0, import_clsx27.default)(
5590
+ className: (0, import_clsx28.default)(
5291
5591
  "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5292
5592
  isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5293
5593
  ),
@@ -5310,16 +5610,16 @@ function ITTimePicker({
5310
5610
  }) })
5311
5611
  }
5312
5612
  ),
5313
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "absolute top-1/2 left-0 right-0 h-10 -mt-5 bg-black/5 pointer-events-none border-y border-black/10 z-10" })
5613
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "absolute top-1/2 left-0 right-0 h-10 -mt-5 bg-black/5 pointer-events-none border-y border-black/10 z-10" })
5314
5614
  ] }),
5315
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { className: "p-3 bg-secondary-50 border-t border-secondary-100 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5615
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "p-3 bg-secondary-50 border-t border-secondary-100 flex justify-end", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5316
5616
  ITButton,
5317
5617
  {
5318
5618
  variant: "solid",
5319
5619
  color,
5320
5620
  size: "sm",
5321
5621
  onClick: handleConfirm,
5322
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ITText, { as: "span", children: "Aceptar" })
5622
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "span", children: "Aceptar" })
5323
5623
  }
5324
5624
  ) })
5325
5625
  ]
@@ -5330,236 +5630,6 @@ function ITTimePicker({
5330
5630
  ] });
5331
5631
  }
5332
5632
 
5333
- // src/components/molecules/search-select/search-select.tsx
5334
- var import_react26 = require("react");
5335
- var import_react_dom6 = require("react-dom");
5336
- var import_clsx28 = __toESM(require("clsx"), 1);
5337
- var import_fa18 = require("react-icons/fa");
5338
- var import_jsx_runtime31 = require("react/jsx-runtime");
5339
- function ITSearchSelect({
5340
- name,
5341
- options = [],
5342
- label,
5343
- placeholder = "Selecciona una opci\xF3n",
5344
- valueField = "value",
5345
- labelField = "label",
5346
- value,
5347
- onChange,
5348
- onBlur,
5349
- disabled = false,
5350
- className,
5351
- touched,
5352
- required,
5353
- error,
5354
- readOnly = false,
5355
- onSearch,
5356
- isLoading = false,
5357
- noResultsMessage = "No se encontraron resultados",
5358
- size = "md",
5359
- renderOption,
5360
- clearable = true,
5361
- onClear
5362
- }) {
5363
- const [isOpen, setIsOpen] = (0, import_react26.useState)(false);
5364
- const [searchTerm, setSearchTerm] = (0, import_react26.useState)("");
5365
- const [isFocused, setIsFocused] = (0, import_react26.useState)(false);
5366
- const [localTouched, setLocalTouched] = (0, import_react26.useState)(false);
5367
- const containerRef = (0, import_react26.useRef)(null);
5368
- const inputWrapperRef = (0, import_react26.useRef)(null);
5369
- const timeoutRef = (0, import_react26.useRef)(null);
5370
- const { panelRef, style: panelStyle } = useFloatingPanel(inputWrapperRef, isOpen, {
5371
- estimatedHeight: 260,
5372
- matchWidth: true
5373
- });
5374
- const selectedOption = (0, import_react26.useMemo)(() => {
5375
- return options.find((opt) => opt[valueField] === value);
5376
- }, [options, value, valueField]);
5377
- (0, import_react26.useEffect)(() => {
5378
- if (!isFocused) {
5379
- setSearchTerm(selectedOption ? String(selectedOption[labelField]) : "");
5380
- }
5381
- }, [selectedOption, isFocused, labelField]);
5382
- (0, import_react26.useEffect)(() => {
5383
- function handleClickOutside(event) {
5384
- const target = event.target;
5385
- const inContainer = containerRef.current?.contains(target);
5386
- const inPanel = panelRef.current?.contains(target);
5387
- if (!inContainer && !inPanel) {
5388
- setIsOpen(false);
5389
- }
5390
- }
5391
- document.addEventListener("mousedown", handleClickOutside);
5392
- return () => document.removeEventListener("mousedown", handleClickOutside);
5393
- }, []);
5394
- const selectedLabel = selectedOption ? String(selectedOption[labelField]) : "";
5395
- const filteredOptions = (0, import_react26.useMemo)(() => {
5396
- if (onSearch) return options;
5397
- if (!searchTerm || !isFocused || searchTerm === selectedLabel) return options;
5398
- return options.filter(
5399
- (opt) => String(opt[labelField]).toLowerCase().includes(searchTerm.toLowerCase())
5400
- );
5401
- }, [options, searchTerm, selectedLabel, onSearch, labelField, isFocused]);
5402
- const handleInputChange = (e) => {
5403
- const query = e.target.value;
5404
- setSearchTerm(query);
5405
- setIsOpen(true);
5406
- if (onSearch) {
5407
- if (timeoutRef.current) clearTimeout(timeoutRef.current);
5408
- timeoutRef.current = setTimeout(() => {
5409
- onSearch(query);
5410
- }, 500);
5411
- }
5412
- };
5413
- const handleSelect = (option) => {
5414
- if (onChange) {
5415
- onChange(option[valueField], option);
5416
- }
5417
- setSearchTerm(String(option[labelField]));
5418
- setIsOpen(false);
5419
- };
5420
- const handleClear = () => {
5421
- setSearchTerm("");
5422
- setIsOpen(true);
5423
- if (onSearch) onSearch("");
5424
- if (value !== void 0 && value !== null && value !== "") {
5425
- onChange?.("", void 0);
5426
- }
5427
- onClear?.();
5428
- };
5429
- const handleFocus = () => {
5430
- if (disabled || readOnly) return;
5431
- setIsFocused(true);
5432
- setIsOpen(true);
5433
- };
5434
- const handleInputBlur = (e) => {
5435
- setTimeout(() => {
5436
- setIsFocused(false);
5437
- setLocalTouched(true);
5438
- onBlur?.(e);
5439
- }, 200);
5440
- };
5441
- const inputTheme = theme.input || {};
5442
- const isTouched = touched !== void 0 ? touched : localTouched;
5443
- const isEmpty = value === void 0 || value === null || String(value).trim() === "";
5444
- const effectiveError = error !== void 0 && error !== false ? error === true ? "Este campo es requerido" : error : required && isEmpty ? "Este campo es requerido" : void 0;
5445
- const hasError = isTouched && !!effectiveError;
5446
- const errorMessage = typeof effectiveError === "string" ? effectiveError : "Este campo es requerido";
5447
- const showClearButton = clearable && !disabled && !readOnly && (searchTerm.length > 0 || !isEmpty);
5448
- const getInputStyle = () => {
5449
- const sizeConfig = inputSizeTokens[size] ?? inputSizeTokens.md;
5450
- const style = {
5451
- backgroundColor: inputTheme.backgroundColor || "#ffffff",
5452
- borderColor: inputTheme.borderColor || "var(--color-secondary-300)",
5453
- borderRadius: inputTheme.borderRadius || "0.5rem",
5454
- padding: sizeConfig.padding,
5455
- fontSize: sizeConfig.fontSize,
5456
- borderWidth: "1px",
5457
- borderStyle: "solid",
5458
- transition: "all 0.2s",
5459
- color: "var(--it-input-text-color, var(--color-secondary-900))",
5460
- width: "100%"
5461
- };
5462
- if (disabled) {
5463
- style.backgroundColor = inputTheme.disabled?.backgroundColor || "var(--color-secondary-100)";
5464
- style.borderColor = inputTheme.disabled?.borderColor || "var(--color-secondary-200)";
5465
- style.opacity = 0.7;
5466
- style.cursor = "not-allowed";
5467
- }
5468
- if (hasError) {
5469
- style.borderColor = inputTheme.error?.borderColor || "red";
5470
- if (isFocused) {
5471
- style.boxShadow = inputTheme.error?.ring;
5472
- }
5473
- } else if (isFocused && !readOnly) {
5474
- style.boxShadow = inputTheme.focus?.ring;
5475
- style.borderColor = inputTheme.focus?.borderColor;
5476
- }
5477
- return style;
5478
- };
5479
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: (0, import_clsx28.default)("w-full flex flex-col gap-1.5", className, isOpen && "relative z-30"), ref: containerRef, children: [
5480
- label && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
5481
- ITText,
5482
- {
5483
- as: "label",
5484
- className: (0, import_clsx28.default)("text-sm font-medium text-secondary-700 dark:text-slate-300", {
5485
- "text-danger-500": hasError
5486
- }),
5487
- children: [
5488
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "span", children: label }),
5489
- required && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "span", className: "text-danger-500 ml-1", children: "*" })
5490
- ]
5491
- }
5492
- ),
5493
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "relative", children: [
5494
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { ref: inputWrapperRef, className: "relative flex items-center", children: [
5495
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5496
- "input",
5497
- {
5498
- type: "text",
5499
- name,
5500
- value: searchTerm,
5501
- onChange: handleInputChange,
5502
- onFocus: handleFocus,
5503
- onBlur: handleInputBlur,
5504
- disabled,
5505
- readOnly,
5506
- placeholder,
5507
- className: "outline-none pr-10",
5508
- style: getInputStyle(),
5509
- autoComplete: "off"
5510
- }
5511
- ),
5512
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "absolute right-3 flex items-center gap-2 text-secondary-400", children: [
5513
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "pointer-events-none animate-spin h-4 w-4 border-2 border-primary-500 border-t-transparent rounded-full" }),
5514
- !isLoading && showClearButton && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5515
- "button",
5516
- {
5517
- type: "button",
5518
- "aria-label": "Limpiar",
5519
- title: "Limpiar",
5520
- onMouseDown: (e) => {
5521
- e.preventDefault();
5522
- handleClear();
5523
- },
5524
- className: "flex items-center justify-center text-secondary-400 hover:text-secondary-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400 rounded-full",
5525
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fa18.FaTimes, { size: 14 })
5526
- }
5527
- ),
5528
- !isLoading && !showClearButton && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_fa18.FaSearch, { size: 14, className: (0, import_clsx28.default)("pointer-events-none", { "text-primary-500": isFocused }) })
5529
- ] })
5530
- ] }),
5531
- isOpen && (0, import_react_dom6.createPortal)(
5532
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5533
- "div",
5534
- {
5535
- ref: panelRef,
5536
- style: panelStyle,
5537
- className: "bg-white dark:bg-slate-900 border border-secondary-200 dark:border-slate-800 rounded-lg shadow-xl overflow-hidden animate-in fade-in zoom-in duration-200 origin-top",
5538
- children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "max-h-60 overflow-y-auto", children: filteredOptions.length > 0 ? filteredOptions.map((option) => {
5539
- const isSelected = value === option[valueField];
5540
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5541
- ITText,
5542
- {
5543
- as: "div",
5544
- onClick: () => handleSelect(option),
5545
- className: (0, import_clsx28.default)(
5546
- "px-4 py-2 text-sm cursor-pointer transition-colors",
5547
- isSelected ? "bg-primary-50 dark:bg-primary-950/40 text-primary-700 dark:text-primary-300 font-medium" : "hover:bg-secondary-50 dark:hover:bg-slate-800 text-secondary-700 dark:text-slate-300"
5548
- ),
5549
- children: renderOption ? renderOption(option, { isSelected, searchTerm }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "span", children: option[labelField] })
5550
- },
5551
- option[valueField]
5552
- );
5553
- }) : /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "div", className: "px-4 py-6 text-sm text-center text-secondary-500 italic", children: isLoading ? "Cargando..." : noResultsMessage }) })
5554
- }
5555
- ),
5556
- document.body
5557
- )
5558
- ] }),
5559
- hasError && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "p", className: "text-danger-500 text-xs mt-1", children: errorMessage })
5560
- ] });
5561
- }
5562
-
5563
5633
  // src/components/organisms/form-builder/useFormBuilder.ts
5564
5634
  var import_react27 = require("react");
5565
5635
  var useFieldRules = (config2, dependentValues) => {
@@ -7986,6 +8056,7 @@ var import_clsx43 = __toESM(require("clsx"), 1);
7986
8056
  var import_react37 = __toESM(require("react"), 1);
7987
8057
  var import_fa27 = require("react-icons/fa");
7988
8058
  var import_md2 = require("react-icons/md");
8059
+ var import_date_fns3 = require("date-fns");
7989
8060
  var import_jsx_runtime60 = require("react/jsx-runtime");
7990
8061
  function ITTable({
7991
8062
  columns,
@@ -8069,15 +8140,32 @@ function ITTable({
8069
8140
  }, [data, sortConfig, columns]);
8070
8141
  const filteredData = sortedData.filter(
8071
8142
  (row) => columns.every((col) => {
8072
- if (!col.filter || filters[col.key] === void 0 || filters[col.key] === "")
8143
+ const rawFilter = filters[col.key];
8144
+ if (!col.filter || rawFilter === void 0 || rawFilter === "") return true;
8145
+ if (Array.isArray(rawFilter) && rawFilter[0] == null && rawFilter[1] == null) {
8073
8146
  return true;
8147
+ }
8074
8148
  const value = getNestedValue(row, col.key);
8075
- const filterValue = String(filters[col.key]).toLowerCase();
8149
+ if (col.filter === "date" || col.filter === "date-range") {
8150
+ const rowDate = value instanceof Date ? value : new Date(String(value));
8151
+ if (isNaN(rowDate.getTime())) return false;
8152
+ if (col.filter === "date") {
8153
+ return (0, import_date_fns3.isSameDay)(rowDate, rawFilter);
8154
+ }
8155
+ const [start, end] = rawFilter;
8156
+ if (start && rowDate.getTime() < (0, import_date_fns3.startOfDay)(start).getTime()) return false;
8157
+ if (end && rowDate.getTime() > (0, import_date_fns3.endOfDay)(end).getTime()) return false;
8158
+ return true;
8159
+ }
8160
+ if (col.filter === "search") {
8161
+ return String(value) === String(rawFilter);
8162
+ }
8163
+ const filterValue = String(rawFilter).toLowerCase();
8076
8164
  switch (col.type) {
8077
8165
  case "number":
8078
8166
  return String(value).includes(filterValue);
8079
8167
  case "boolean":
8080
- return value === filters[col.key];
8168
+ return value === rawFilter;
8081
8169
  case "catalog": {
8082
8170
  if (!col.catalogOptions) return true;
8083
8171
  const catalogItem = col.catalogOptions.data.find(
@@ -8183,6 +8271,75 @@ function ITTable({
8183
8271
  }
8184
8272
  );
8185
8273
  }
8274
+ if (col.filter === "search" && col.catalogOptions) {
8275
+ if (col.catalogOptions.loading) {
8276
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8277
+ import_fa27.FaSpinner,
8278
+ {
8279
+ className: "animate-spin",
8280
+ "aria-label": "Cargando opciones",
8281
+ title: "Cargando opciones"
8282
+ }
8283
+ );
8284
+ }
8285
+ if (col.catalogOptions.error) {
8286
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
8287
+ }
8288
+ const searchValue = filters[col.key];
8289
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8290
+ ITSearchSelect,
8291
+ {
8292
+ name: `filter-${col.key}`,
8293
+ options: col.catalogOptions.data.map((item) => ({
8294
+ value: item.id,
8295
+ label: item.name
8296
+ })),
8297
+ value: typeof searchValue === "string" || typeof searchValue === "number" ? searchValue : "",
8298
+ onChange: (value) => handleFilterChange(col.key, value === "" ? void 0 : value),
8299
+ onSearch: col.catalogOptions.onSearch,
8300
+ isLoading: col.catalogOptions.loading,
8301
+ size: "sm",
8302
+ placeholder: "Buscar...",
8303
+ clearable: true,
8304
+ className: "w-full",
8305
+ onBlur: () => {
8306
+ }
8307
+ }
8308
+ );
8309
+ }
8310
+ if (col.filter === "date") {
8311
+ const dateValue = filters[col.key];
8312
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8313
+ ITDatePicker,
8314
+ {
8315
+ name: `filter-${col.key}`,
8316
+ value: dateValue instanceof Date ? dateValue : void 0,
8317
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
8318
+ minDate: col.dateFilterOptions?.minDate,
8319
+ maxDate: col.dateFilterOptions?.maxDate,
8320
+ size: "sm",
8321
+ placeholder: "dd/mm/aaaa",
8322
+ className: "w-full"
8323
+ }
8324
+ );
8325
+ }
8326
+ if (col.filter === "date-range") {
8327
+ const rangeValue = filters[col.key];
8328
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8329
+ ITDatePicker,
8330
+ {
8331
+ name: `filter-${col.key}`,
8332
+ range: true,
8333
+ value: Array.isArray(rangeValue) ? rangeValue : void 0,
8334
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
8335
+ minDate: col.dateFilterOptions?.minDate,
8336
+ maxDate: col.dateFilterOptions?.maxDate,
8337
+ size: "sm",
8338
+ placeholder: "dd/mm/aaaa - dd/mm/aaaa",
8339
+ className: "w-full"
8340
+ }
8341
+ );
8342
+ }
8186
8343
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8187
8344
  ITInput,
8188
8345
  {