@axzydev/axzy_ui_system 1.3.3 → 1.3.5

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 = __toESM(require("react"), 1);
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");
@@ -4625,7 +4425,7 @@ function ITDatePicker({
4625
4425
  onClick: handleIconClick
4626
4426
  }
4627
4427
  ),
4628
- isOpen && (0, import_react_dom3.createPortal)(
4428
+ isOpen && (0, import_react_dom4.createPortal)(
4629
4429
  /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4630
4430
  "div",
4631
4431
  {
@@ -4665,27 +4465,570 @@ function ITDatePicker({
4665
4465
  ] });
4666
4466
  }
4667
4467
 
4668
- // 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");
4672
-
4673
- // src/components/molecules/form-header/form-header.tsx
4674
- var import_fa13 = require("react-icons/fa");
4675
-
4676
- // src/theme/theme-context.ts
4677
- var import_react21 = require("react");
4678
- var ITThemeContext = (0, import_react21.createContext)(void 0);
4679
- var useITTheme = () => {
4680
- const context = (0, import_react21.useContext)(ITThemeContext);
4681
- if (!context) {
4682
- throw new Error("useITTheme must be used within an ITThemeProvider");
4683
- }
4684
- return context;
4685
- };
4686
- var useITThemeSafe = () => {
4687
- return (0, import_react21.useContext)(ITThemeContext);
4688
- };
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
+ function pinnedColumnWidth(col) {
4487
+ if (typeof col.width === "number") return col.width;
4488
+ if (typeof col.width === "string" && /^\d+(\.\d+)?px$/.test(col.width.trim())) {
4489
+ return parseFloat(col.width);
4490
+ }
4491
+ return col.minWidth ?? 0;
4492
+ }
4493
+ function getPinnedColumnMeta(columns) {
4494
+ const meta = {};
4495
+ let leftOffset = 0;
4496
+ for (const col of columns) {
4497
+ if (col.pinned === "left") {
4498
+ meta[col.key] = { side: "left", offset: leftOffset };
4499
+ leftOffset += pinnedColumnWidth(col);
4500
+ }
4501
+ }
4502
+ let rightOffset = 0;
4503
+ for (let i = columns.length - 1; i >= 0; i--) {
4504
+ const col = columns[i];
4505
+ if (col.pinned === "right") {
4506
+ meta[col.key] = { side: "right", offset: rightOffset };
4507
+ rightOffset += pinnedColumnWidth(col);
4508
+ }
4509
+ }
4510
+ return meta;
4511
+ }
4512
+
4513
+ // src/components/organisms/data-table/dataTable.tsx
4514
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4515
+ var getNestedValue2 = (obj, path) => {
4516
+ return path.split(".").reduce((acc, part) => acc && acc[part], obj);
4517
+ };
4518
+ var EMPTY_OBJECT = {};
4519
+ function ITDataTable({
4520
+ columns,
4521
+ fetchData,
4522
+ debounceMs = 500,
4523
+ externalFilters = EMPTY_OBJECT,
4524
+ loadingIndicator,
4525
+ fetchOnMount = true,
4526
+ reloadTrigger,
4527
+ containerClassName,
4528
+ className,
4529
+ variant = "default",
4530
+ size = "md",
4531
+ itemsPerPageOptions = [5, 10, 20],
4532
+ defaultItemsPerPage = 10,
4533
+ title,
4534
+ renderCard,
4535
+ defaultView,
4536
+ showVerticalBorder = true,
4537
+ verticalBorderClassname,
4538
+ onRowClick,
4539
+ layout = "auto",
4540
+ density = "normal",
4541
+ autoCardBreakpoint = 0,
4542
+ virtualized = false,
4543
+ virtualizedMaxHeight = 400,
4544
+ rowHeight,
4545
+ overscan = 5,
4546
+ stickyHeader = false
4547
+ }) {
4548
+ const [viewMode, setViewMode] = (0, import_react21.useState)(defaultView || "table");
4549
+ const { ref: rootRef, width: containerWidth } = useElementSize();
4550
+ const [data, setData] = (0, import_react21.useState)([]);
4551
+ const [totalItems, setTotalItems] = (0, import_react21.useState)(0);
4552
+ const [isLoading, setIsLoading] = (0, import_react21.useState)(fetchOnMount);
4553
+ const isFixed = layout === "fixed";
4554
+ const forcedCards = autoCardBreakpoint > 0 && containerWidth > 0 && containerWidth < autoCardBreakpoint;
4555
+ const effectiveView = forcedCards ? "cards" : viewMode;
4556
+ const hasColumnWidths = columns.some((col) => col.width != null);
4557
+ 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";
4558
+ const isTableVirtual = virtualized && effectiveView === "table";
4559
+ const isStickyHeader = stickyHeader && isTableVirtual;
4560
+ const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
4561
+ const columnCount = columns.length;
4562
+ const pinnedMeta = import_react21.default.useMemo(() => getPinnedColumnMeta(columns), [columns]);
4563
+ const scrollOuterClass = isTableVirtual ? "relative min-h-[200px]" : "overflow-x-auto relative min-h-[200px]";
4564
+ const {
4565
+ currentPage,
4566
+ itemsPerPage,
4567
+ filters,
4568
+ sortConfig,
4569
+ goToPage,
4570
+ handleFilterChange,
4571
+ handleSort,
4572
+ handleItemsPerPageChange
4573
+ } = useTableState({ defaultItemsPerPage });
4574
+ const {
4575
+ scrollRef,
4576
+ startIndex,
4577
+ endIndex,
4578
+ topSpacerHeight,
4579
+ bottomSpacerHeight
4580
+ } = useVirtualRows({
4581
+ count: data.length,
4582
+ rowHeight: resolvedRowHeight,
4583
+ overscan,
4584
+ enabled: isTableVirtual,
4585
+ resetKey: `${currentPage}-${itemsPerPage}`
4586
+ });
4587
+ const windowData = isTableVirtual ? data.slice(startIndex, endIndex + 1) : data;
4588
+ const debounceTimerRef = (0, import_react21.useRef)(null);
4589
+ const hasFetchedRef = (0, import_react21.useRef)(false);
4590
+ const fetchDataRef = (0, import_react21.useRef)(fetchData);
4591
+ fetchDataRef.current = fetchData;
4592
+ const externalFiltersRef = (0, import_react21.useRef)(externalFilters);
4593
+ externalFiltersRef.current = externalFilters;
4594
+ const externalKey = JSON.stringify(externalFilters);
4595
+ const computedTotalPages = Math.ceil(totalItems / itemsPerPage) || 1;
4596
+ const performFetch = (0, import_react21.useCallback)(async () => {
4597
+ setIsLoading(true);
4598
+ try {
4599
+ const response = await fetchDataRef.current({
4600
+ page: currentPage,
4601
+ limit: itemsPerPage,
4602
+ filters: { ...filters, ...externalFiltersRef.current },
4603
+ sort: sortConfig || void 0
4604
+ });
4605
+ setData(response.data || []);
4606
+ setTotalItems(response.total || 0);
4607
+ hasFetchedRef.current = true;
4608
+ } catch (error) {
4609
+ console.error("ITDataTable: Error fetching data", error);
4610
+ setData([]);
4611
+ setTotalItems(0);
4612
+ hasFetchedRef.current = true;
4613
+ } finally {
4614
+ setIsLoading(false);
4615
+ }
4616
+ }, [currentPage, itemsPerPage, filters, sortConfig]);
4617
+ const performFetchRef = (0, import_react21.useRef)(performFetch);
4618
+ performFetchRef.current = performFetch;
4619
+ (0, import_react21.useEffect)(() => {
4620
+ if (!fetchOnMount && !hasFetchedRef.current) return;
4621
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4622
+ debounceTimerRef.current = setTimeout(() => {
4623
+ performFetchRef.current();
4624
+ }, debounceMs);
4625
+ return () => {
4626
+ if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
4627
+ };
4628
+ }, [currentPage, itemsPerPage, sortConfig, filters, externalKey, reloadTrigger, fetchOnMount, debounceMs]);
4629
+ const renderFilterInput = (col) => {
4630
+ if (!col.filter) return null;
4631
+ if (col.type === "boolean") {
4632
+ const currentValue = filters[col.key];
4633
+ const nextValue = currentValue === void 0 ? true : currentValue === true ? false : void 0;
4634
+ const getToggleLabel = () => {
4635
+ if (currentValue === void 0) return "Mostrar todos";
4636
+ if (currentValue === true) return "Filtrar solo verdaderos";
4637
+ return "Filtrar solo falsos";
4638
+ };
4639
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4640
+ "button",
4641
+ {
4642
+ 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",
4643
+ onClick: () => handleFilterChange(col.key, nextValue),
4644
+ "aria-label": `${getToggleLabel()} para ${col.label}`,
4645
+ title: `${getToggleLabel()} para ${col.label}`,
4646
+ disabled: isLoading,
4647
+ 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)(
4648
+ "div",
4649
+ {
4650
+ className: (0, import_clsx23.default)(
4651
+ "absolute top-0.5 w-4 h-4 rounded-full transition-all duration-300 shadow-sm",
4652
+ {
4653
+ "left-0.5 bg-secondary-400": currentValue === void 0,
4654
+ "left-5 bg-slate-500": currentValue === true,
4655
+ "left-0.5 bg-secondary-500": currentValue === false
4656
+ }
4657
+ )
4658
+ }
4659
+ ) })
4660
+ }
4661
+ );
4662
+ }
4663
+ if (col.filter === "catalog" && col.catalogOptions) {
4664
+ if (col.catalogOptions.loading) {
4665
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4666
+ }
4667
+ if (col.catalogOptions.error) {
4668
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4669
+ }
4670
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4671
+ ITSelect,
4672
+ {
4673
+ name: `filter-${col.key}`,
4674
+ options: [
4675
+ { value: "", label: "Todos" },
4676
+ ...col.catalogOptions.data.map((item) => ({
4677
+ value: String(item.id),
4678
+ label: item.name
4679
+ }))
4680
+ ],
4681
+ value: String(filters[col.key] || ""),
4682
+ onChange: (e) => {
4683
+ const value = e.target.value === "" ? void 0 : e.target.value;
4684
+ handleFilterChange(col.key, value);
4685
+ },
4686
+ onBlur: () => {
4687
+ },
4688
+ className: "w-full text-xs",
4689
+ disabled: isLoading
4690
+ }
4691
+ );
4692
+ }
4693
+ if (col.filter === "search" && col.catalogOptions) {
4694
+ if (col.catalogOptions.loading) {
4695
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin", "aria-label": "Cargando opciones", title: "Cargando opciones" });
4696
+ }
4697
+ if (col.catalogOptions.error) {
4698
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
4699
+ }
4700
+ const searchValue = filters[col.key];
4701
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4702
+ ITSearchSelect,
4703
+ {
4704
+ name: `filter-${col.key}`,
4705
+ options: col.catalogOptions.data.map((item) => ({
4706
+ value: item.id,
4707
+ label: item.name
4708
+ })),
4709
+ value: typeof searchValue === "string" || typeof searchValue === "number" ? searchValue : "",
4710
+ onChange: (value) => handleFilterChange(col.key, value === "" ? void 0 : value),
4711
+ onSearch: col.catalogOptions.onSearch,
4712
+ isLoading: col.catalogOptions.loading,
4713
+ size: "sm",
4714
+ placeholder: "Buscar...",
4715
+ clearable: true,
4716
+ className: "w-full",
4717
+ onBlur: () => {
4718
+ },
4719
+ disabled: isLoading
4720
+ }
4721
+ );
4722
+ }
4723
+ if (col.filter === "date") {
4724
+ const dateValue = filters[col.key];
4725
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4726
+ ITDatePicker,
4727
+ {
4728
+ name: `filter-${col.key}`,
4729
+ value: dateValue instanceof Date ? dateValue : void 0,
4730
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4731
+ minDate: col.dateFilterOptions?.minDate,
4732
+ maxDate: col.dateFilterOptions?.maxDate,
4733
+ size: "sm",
4734
+ placeholder: "dd/mm/aaaa",
4735
+ className: "w-full",
4736
+ disabled: isLoading
4737
+ }
4738
+ );
4739
+ }
4740
+ if (col.filter === "date-range") {
4741
+ const rangeValue = filters[col.key];
4742
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4743
+ ITDatePicker,
4744
+ {
4745
+ name: `filter-${col.key}`,
4746
+ range: true,
4747
+ value: Array.isArray(rangeValue) ? rangeValue : void 0,
4748
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4749
+ minDate: col.dateFilterOptions?.minDate,
4750
+ maxDate: col.dateFilterOptions?.maxDate,
4751
+ size: "sm",
4752
+ placeholder: "dd/mm/aaaa - dd/mm/aaaa",
4753
+ className: "w-full",
4754
+ disabled: isLoading
4755
+ }
4756
+ );
4757
+ }
4758
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4759
+ ITInput,
4760
+ {
4761
+ name: `filter-${col.key}`,
4762
+ className: "w-full text-xs",
4763
+ placeholder: "Buscar...",
4764
+ value: String(filters[col.key] || ""),
4765
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
4766
+ onBlur: () => {
4767
+ },
4768
+ disabled: isLoading
4769
+ }
4770
+ );
4771
+ };
4772
+ const renderCellContent = (col, row) => {
4773
+ const value = getNestedValue2(row, col.key);
4774
+ if (col.render) return col.render(row);
4775
+ switch (col.type) {
4776
+ case "number":
4777
+ return typeof value === "number" && col.currencyMX ? formatCurrencyMX(value) : value;
4778
+ case "boolean":
4779
+ 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" });
4780
+ case "actions":
4781
+ return col.actions ? col.actions(row) : null;
4782
+ case "catalog":
4783
+ if (col.catalogOptions) {
4784
+ const catalogItem = col.catalogOptions.data.find((item) => item.id === value);
4785
+ return catalogItem?.name || value;
4786
+ }
4787
+ return value;
4788
+ default:
4789
+ return value;
4790
+ }
4791
+ };
4792
+ const renderDefaultCard = (row) => {
4793
+ const dataCols = columns.filter((c) => c.type !== "actions");
4794
+ const actionCol = columns.find((c) => c.type === "actions");
4795
+ 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: [
4796
+ dataCols.map((col) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
4797
+ /* @__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 }),
4798
+ /* @__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) })
4799
+ ] }, col.key)),
4800
+ 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) })
4801
+ ] });
4802
+ };
4803
+ 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"}`;
4804
+ const handleRowClick = (row) => (event) => {
4805
+ if (!onRowClick || isLoading || isInteractiveTarget(event.target, event.currentTarget)) return;
4806
+ onRowClick(row, event);
4807
+ };
4808
+ const handleRowKeyDown = (row) => (event) => {
4809
+ if (!onRowClick || isLoading) return;
4810
+ if (event.target !== event.currentTarget) return;
4811
+ if (event.key !== "Enter" && event.key !== " ") return;
4812
+ event.preventDefault();
4813
+ onRowClick(row, event);
4814
+ };
4815
+ const tableEl = /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4816
+ "table",
4817
+ {
4818
+ className: (0, import_clsx23.default)(
4819
+ tableLayoutClass,
4820
+ showVerticalBorder && "[&_th]:border-r [&_th:last-child]:border-r-0 [&_td]:border-r [&_td:last-child]:border-r-0",
4821
+ showVerticalBorder && (verticalBorderClassname || "[&_th]:border-slate-100 dark:[&_th]:border-slate-700/30 [&_td]:border-slate-100 dark:[&_td]:border-slate-700/30"),
4822
+ isLoading ? "opacity-50" : "opacity-100",
4823
+ variantStyles[variant],
4824
+ sizeStyles[size],
4825
+ className
4826
+ ),
4827
+ style: isFixed ? { tableLayout: "fixed" } : void 0,
4828
+ "aria-rowcount": isTableVirtual ? data.length + 1 : void 0,
4829
+ children: [
4830
+ hasColumnWidths && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("colgroup", { children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4831
+ "col",
4832
+ {
4833
+ style: col.width != null ? { width: typeof col.width === "number" ? `${col.width}px` : col.width } : void 0
4834
+ },
4835
+ col.key
4836
+ )) }),
4837
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4838
+ "tr",
4839
+ {
4840
+ className: (0, import_clsx23.default)(tableHeaderRow, "dark:text-slate-200"),
4841
+ "aria-rowindex": isTableVirtual ? 1 : void 0,
4842
+ children: columns.map((col) => {
4843
+ const pin = pinnedMeta[col.key];
4844
+ const isPinned = pin != null;
4845
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4846
+ "th",
4847
+ {
4848
+ scope: "col",
4849
+ className: (0, import_clsx23.default)(
4850
+ tableHeaderCell(col.className, density),
4851
+ col.align && tableAlignClasses[col.align],
4852
+ isPinned && "sticky",
4853
+ isStickyHeader && "sticky top-0 bg-secondary-50",
4854
+ isPinned ? "z-[15]" : isStickyHeader && "z-10",
4855
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right")
4856
+ ),
4857
+ style: col.minWidth != null || isStickyHeader || isPinned ? {
4858
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4859
+ ...isStickyHeader || isPinned ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {},
4860
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
4861
+ } : void 0,
4862
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
4863
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
4864
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
4865
+ col.sortable && col.type !== "actions" && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4866
+ "button",
4867
+ {
4868
+ onClick: () => handleSort(col.key),
4869
+ disabled: isLoading,
4870
+ 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`,
4871
+ title: `Ordenar por ${col.label}`,
4872
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_md.MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
4873
+ }
4874
+ )
4875
+ ] }),
4876
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
4877
+ ] })
4878
+ },
4879
+ col.key
4880
+ );
4881
+ })
4882
+ }
4883
+ ) }),
4884
+ /* @__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: [
4885
+ 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 } }) }),
4886
+ windowData.map((row, windowIndex) => {
4887
+ const absoluteIndex = isTableVirtual ? startIndex + windowIndex : windowIndex;
4888
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4889
+ "tr",
4890
+ {
4891
+ "aria-rowindex": isTableVirtual ? absoluteIndex + 2 : void 0,
4892
+ className: (0, import_clsx23.default)(
4893
+ tableRow,
4894
+ variant === "striped" && absoluteIndex % 2 === 0 && "bg-secondary-50/40 dark:bg-slate-800/20",
4895
+ onRowClick && !isLoading && tableRowClickable
4896
+ ),
4897
+ tabIndex: onRowClick && !isLoading ? 0 : void 0,
4898
+ onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4899
+ onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4900
+ children: columns.map((col) => {
4901
+ const rawValue = getNestedValue2(row, col.key);
4902
+ const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
4903
+ const pin = pinnedMeta[col.key];
4904
+ const isPinned = pin != null;
4905
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4906
+ "td",
4907
+ {
4908
+ className: (0, import_clsx23.default)(
4909
+ tableCell(col.className, density),
4910
+ col.align && tableAlignClasses[col.align],
4911
+ isPinned && "sticky bg-[var(--color-table-rowBg,white)] group-hover:bg-[var(--color-table-rowHover,var(--color-secondary-50))]",
4912
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right"),
4913
+ isPinned && "z-[1]"
4914
+ ),
4915
+ style: col.minWidth != null || isPinned ? {
4916
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
4917
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
4918
+ } : void 0,
4919
+ title: truncateTitle,
4920
+ 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) })
4921
+ },
4922
+ `${absoluteIndex}-${col.key}`
4923
+ );
4924
+ })
4925
+ },
4926
+ absoluteIndex
4927
+ );
4928
+ }),
4929
+ 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 } }) })
4930
+ ] }) : /* @__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: [
4931
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4932
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4933
+ ] }) }) }) })
4934
+ ]
4935
+ }
4936
+ );
4937
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { ref: rootRef, className: (0, import_clsx23.default)("space-y-4 w-full relative", containerClassName), children: [
4938
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: tableContainer, style: { backgroundColor: "var(--color-table-rowBg, #ffffff)" }, children: [
4939
+ 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: [
4940
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "h2", className: "text-xl font-bold text-secondary-900 leading-tight", children: title }),
4941
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-3", children: [
4942
+ 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" }) }),
4943
+ /* @__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: [
4944
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4945
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTable, { size: 11 }),
4946
+ "Table"
4947
+ ] }),
4948
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4949
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaThLarge, { size: 11 }),
4950
+ "Cards"
4951
+ ] })
4952
+ ] })
4953
+ ] })
4954
+ ] }),
4955
+ !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: [
4956
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("table"), disabled: forcedCards, className: segCtrlClass("table"), children: [
4957
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTable, { size: 11 }),
4958
+ "Table"
4959
+ ] }),
4960
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("button", { onClick: () => setViewMode("cards"), className: segCtrlClass("cards"), children: [
4961
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaThLarge, { size: 11 }),
4962
+ "Cards"
4963
+ ] })
4964
+ ] }) }),
4965
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: scrollOuterClass, children: [
4966
+ 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: [
4967
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaSpinner, { className: "animate-spin text-primary-500 text-4xl" }),
4968
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-sm font-semibold text-secondary-600 animate-pulse", children: "Cargando datos..." })
4969
+ ] }) }) }),
4970
+ 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)(
4971
+ "div",
4972
+ {
4973
+ className: (0, import_clsx23.default)(tableCardHover, onRowClick && !isLoading && tableCardClickable),
4974
+ role: onRowClick && !isLoading ? "button" : void 0,
4975
+ tabIndex: onRowClick && !isLoading ? 0 : void 0,
4976
+ onClick: onRowClick && !isLoading ? handleRowClick(row) : void 0,
4977
+ onKeyDown: onRowClick && !isLoading ? handleRowKeyDown(row) : void 0,
4978
+ children: renderCard ? renderCard(row) : renderDefaultCard(row)
4979
+ },
4980
+ i
4981
+ )) : !isLoading && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: (0, import_clsx23.default)(tableEmptyContent, "py-12"), children: [
4982
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-lg", children: "No se encontraron resultados" }),
4983
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ITText, { as: "span", className: "text-sm mt-1", children: "Intenta ajustar los filtros" })
4984
+ ] }) }) : isTableVirtual ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4985
+ "div",
4986
+ {
4987
+ ref: scrollRef,
4988
+ className: "overflow-x-auto overflow-y-auto",
4989
+ style: { maxHeight: virtualizedMaxHeight },
4990
+ children: tableEl
4991
+ }
4992
+ ) : tableEl
4993
+ ] })
4994
+ ] }),
4995
+ /* @__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)(
4996
+ ITPagination,
4997
+ {
4998
+ currentPage,
4999
+ totalPages: computedTotalPages,
5000
+ onPageChange: goToPage,
5001
+ color: "primary",
5002
+ itemsPerPageOptions,
5003
+ itemsPerPage,
5004
+ onItemsPerPageChange: handleItemsPerPageChange,
5005
+ totalItems
5006
+ }
5007
+ ) })
5008
+ ] });
5009
+ }
5010
+
5011
+ // src/components/organisms/dialog/dialog.tsx
5012
+ var import_react_dom5 = require("react-dom");
5013
+ var import_react23 = require("react");
5014
+ var import_fa15 = require("react-icons/fa");
5015
+
5016
+ // src/components/molecules/form-header/form-header.tsx
5017
+ var import_fa14 = require("react-icons/fa");
5018
+
5019
+ // src/theme/theme-context.ts
5020
+ var import_react22 = require("react");
5021
+ var ITThemeContext = (0, import_react22.createContext)(void 0);
5022
+ var useITTheme = () => {
5023
+ const context = (0, import_react22.useContext)(ITThemeContext);
5024
+ if (!context) {
5025
+ throw new Error("useITTheme must be used within an ITThemeProvider");
5026
+ }
5027
+ return context;
5028
+ };
5029
+ var useITThemeSafe = () => {
5030
+ return (0, import_react22.useContext)(ITThemeContext);
5031
+ };
4689
5032
 
4690
5033
  // src/utils/color.utils.ts
4691
5034
  var isLightColor = (hex) => {
@@ -4764,7 +5107,7 @@ var getContrastTextColor = (bgColor, palette2, isDarkMode) => {
4764
5107
  };
4765
5108
 
4766
5109
  // src/components/molecules/form-header/form-header.tsx
4767
- var import_jsx_runtime23 = require("react/jsx-runtime");
5110
+ var import_jsx_runtime24 = require("react/jsx-runtime");
4768
5111
  function ITFormHeader({
4769
5112
  title,
4770
5113
  onClose,
@@ -4778,23 +5121,23 @@ function ITFormHeader({
4778
5121
  palette2,
4779
5122
  isDarkMode
4780
5123
  );
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)(
5124
+ 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: [
5125
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(ITText, { as: "h2", className: "text-lg font-semibold text-center", style: { color: "inherit" }, children: title }),
5126
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
4784
5127
  "button",
4785
5128
  {
4786
5129
  onClick: onClose,
4787
5130
  className: `absolute right-4 ${textColorClass} hover:opacity-80 transition-colors duration-200 p-1 rounded-full`,
4788
5131
  style: { color: "inherit" },
4789
5132
  "aria-label": "Cerrar",
4790
- children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_fa13.FaTimes, { className: "w-4 h-4" })
5133
+ children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fa14.FaTimes, { className: "w-4 h-4" })
4791
5134
  }
4792
5135
  )
4793
5136
  ] });
4794
5137
  }
4795
5138
 
4796
5139
  // src/components/organisms/dialog/dialog.tsx
4797
- var import_jsx_runtime24 = require("react/jsx-runtime");
5140
+ var import_jsx_runtime25 = require("react/jsx-runtime");
4798
5141
  function ITDialog({
4799
5142
  isOpen,
4800
5143
  onClose,
@@ -4804,9 +5147,9 @@ function ITDialog({
4804
5147
  useFormHeader = false,
4805
5148
  fullScreen = false
4806
5149
  }) {
4807
- const modalRef = (0, import_react22.useRef)(null);
5150
+ const modalRef = (0, import_react23.useRef)(null);
4808
5151
  useClickOutside_default(modalRef, onClose);
4809
- (0, import_react22.useEffect)(() => {
5152
+ (0, import_react23.useEffect)(() => {
4810
5153
  const handleEscape = (event) => {
4811
5154
  if (event.key === "Escape") {
4812
5155
  onClose();
@@ -4821,12 +5164,12 @@ function ITDialog({
4821
5164
  }, [isOpen, onClose]);
4822
5165
  if (!isOpen) return null;
4823
5166
  if (typeof document === "undefined") return null;
4824
- const content = /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5167
+ const content = /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4825
5168
  "div",
4826
5169
  {
4827
5170
  "data-it-dialog": "true",
4828
5171
  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)(
5172
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4830
5173
  "div",
4831
5174
  {
4832
5175
  ref: modalRef,
@@ -4839,41 +5182,41 @@ function ITDialog({
4839
5182
  borderColor: theme.card.borderColor,
4840
5183
  borderStyle: "solid"
4841
5184
  },
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)(
5185
+ children: useFormHeader && title ? /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5186
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ITFormHeader, { title, onClose }),
5187
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: fullScreen ? "flex-1 overflow-auto p-6" : "p-6", children })
5188
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5189
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4847
5190
  "button",
4848
5191
  {
4849
5192
  className: "absolute top-2 right-2 text-secondary-600 hover:text-secondary-900",
4850
5193
  onClick: onClose,
4851
- children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_fa14.FaRegTimesCircle, {})
5194
+ children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_fa15.FaRegTimesCircle, {})
4852
5195
  }
4853
5196
  ),
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 })
5197
+ title && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ITText, { as: "h2", className: "text-xl font-semibold mb-4", children: title }),
5198
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { children })
4856
5199
  ] })
4857
5200
  }
4858
5201
  )
4859
5202
  }
4860
5203
  );
4861
- return (0, import_react_dom4.createPortal)(content, document.body);
5204
+ return (0, import_react_dom5.createPortal)(content, document.body);
4862
5205
  }
4863
5206
 
4864
5207
  // src/components/atoms/divider/divider.tsx
4865
- var import_clsx23 = __toESM(require("clsx"), 1);
4866
- var import_jsx_runtime25 = require("react/jsx-runtime");
5208
+ var import_clsx24 = __toESM(require("clsx"), 1);
5209
+ var import_jsx_runtime26 = require("react/jsx-runtime");
4867
5210
  function ITDivider({
4868
5211
  orientation = "horizontal",
4869
5212
  className,
4870
5213
  color = "bg-slate-200 dark:bg-slate-700",
4871
5214
  thickness = orientation === "horizontal" ? "h-px" : "w-px"
4872
5215
  }) {
4873
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5216
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
4874
5217
  "div",
4875
5218
  {
4876
- className: (0, import_clsx23.default)(
5219
+ className: (0, import_clsx24.default)(
4877
5220
  "flex-shrink-0",
4878
5221
  orientation === "horizontal" ? "w-full" : "self-stretch",
4879
5222
  thickness,
@@ -4885,10 +5228,10 @@ function ITDivider({
4885
5228
  }
4886
5229
 
4887
5230
  // 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");
5231
+ var import_clsx25 = __toESM(require("clsx"), 1);
5232
+ var import_fa16 = require("react-icons/fa");
5233
+ var import_react24 = require("react");
5234
+ var import_jsx_runtime27 = require("react/jsx-runtime");
4892
5235
  function ITDrawer({
4893
5236
  isOpen,
4894
5237
  onClose,
@@ -4899,15 +5242,15 @@ function ITDrawer({
4899
5242
  className,
4900
5243
  style
4901
5244
  }) {
4902
- const panelRef = (0, import_react23.useRef)(null);
5245
+ const panelRef = (0, import_react24.useRef)(null);
4903
5246
  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)(
5247
+ 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: [
5248
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "absolute inset-0 bg-black/40 backdrop-blur-sm transition-opacity" }),
5249
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(
4907
5250
  "div",
4908
5251
  {
4909
5252
  ref: panelRef,
4910
- className: (0, import_clsx24.default)(
5253
+ className: (0, import_clsx25.default)(
4911
5254
  "relative z-10 h-full bg-white dark:bg-slate-900 shadow-2xl flex flex-col transition-transform duration-300",
4912
5255
  position === "right" ? "ml-auto" : "mr-auto",
4913
5256
  size,
@@ -4915,18 +5258,18 @@ function ITDrawer({
4915
5258
  ),
4916
5259
  style,
4917
5260
  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)(
5261
+ 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: [
5262
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ITText, { as: "h2", className: "text-lg font-bold text-slate-800 dark:text-white", children: title }),
5263
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
4921
5264
  "button",
4922
5265
  {
4923
5266
  onClick: onClose,
4924
5267
  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 })
5268
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa16.FaTimes, { size: 14 })
4926
5269
  }
4927
5270
  )
4928
5271
  ] }),
4929
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { className: "flex-1 overflow-y-auto p-5", children })
5272
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "flex-1 overflow-y-auto p-5", children })
4930
5273
  ]
4931
5274
  }
4932
5275
  )
@@ -4934,27 +5277,27 @@ function ITDrawer({
4934
5277
  }
4935
5278
 
4936
5279
  // 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");
5280
+ var import_clsx26 = __toESM(require("clsx"), 1);
5281
+ var import_fa17 = require("react-icons/fa");
5282
+ var import_jsx_runtime28 = require("react/jsx-runtime");
4940
5283
  function ITEmptyState({
4941
- icon = /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_fa16.FaInbox, { size: 40 }),
5284
+ icon = /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_fa17.FaInbox, { size: 40 }),
4942
5285
  title,
4943
5286
  description,
4944
5287
  action,
4945
5288
  className
4946
5289
  }) {
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 })
5290
+ 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: [
5291
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "text-slate-300 dark:text-slate-600 mb-4", children: icon }),
5292
+ /* @__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 }),
5293
+ 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 }),
5294
+ action && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { children: action })
4952
5295
  ] });
4953
5296
  }
4954
5297
 
4955
5298
  // src/components/atoms/flex/flex.tsx
4956
- var import_clsx26 = __toESM(require("clsx"), 1);
4957
- var import_jsx_runtime28 = require("react/jsx-runtime");
5299
+ var import_clsx27 = __toESM(require("clsx"), 1);
5300
+ var import_jsx_runtime29 = require("react/jsx-runtime");
4958
5301
  var directionMap = {
4959
5302
  row: "flex-row",
4960
5303
  column: "flex-col",
@@ -5003,10 +5346,10 @@ function ITFlex({
5003
5346
  flexBasis: typeof basis === "number" ? `${basis * 0.25}rem` : basis,
5004
5347
  ...style
5005
5348
  };
5006
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5349
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5007
5350
  Component,
5008
5351
  {
5009
- className: (0, import_clsx26.default)(
5352
+ className: (0, import_clsx27.default)(
5010
5353
  "flex",
5011
5354
  directionMap[direction],
5012
5355
  align && alignMap[align],
@@ -5025,33 +5368,33 @@ function ITFlex({
5025
5368
  var import_react29 = require("react");
5026
5369
 
5027
5370
  // 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);
5371
+ var import_react25 = __toESM(require("react"), 1);
5372
+ var import_jsx_runtime30 = require("react/jsx-runtime");
5373
+ var ITFormBuilderContext = (0, import_react25.createContext)(void 0);
5031
5374
  var ITFormBuilderProvider = ({
5032
5375
  children,
5033
5376
  value
5034
5377
  }) => {
5035
- const [fieldRegistry, setFieldRegistry] = (0, import_react24.useState)({});
5036
- const registerField = import_react24.default.useCallback((name, config2) => {
5378
+ const [fieldRegistry, setFieldRegistry] = (0, import_react25.useState)({});
5379
+ const registerField = import_react25.default.useCallback((name, config2) => {
5037
5380
  setFieldRegistry((prev) => ({ ...prev, [name]: config2 }));
5038
5381
  }, []);
5039
- const unregisterField = import_react24.default.useCallback((name) => {
5382
+ const unregisterField = import_react25.default.useCallback((name) => {
5040
5383
  setFieldRegistry((prev) => {
5041
5384
  const next = { ...prev };
5042
5385
  delete next[name];
5043
5386
  return next;
5044
5387
  });
5045
5388
  }, []);
5046
- const getFieldConfig = import_react24.default.useCallback(
5389
+ const getFieldConfig = import_react25.default.useCallback(
5047
5390
  (name) => fieldRegistry[name],
5048
5391
  [fieldRegistry]
5049
5392
  );
5050
- const getAllFieldConfigs = import_react24.default.useCallback(
5393
+ const getAllFieldConfigs = import_react25.default.useCallback(
5051
5394
  () => Object.values(fieldRegistry),
5052
5395
  [fieldRegistry]
5053
5396
  );
5054
- const contextValue = import_react24.default.useMemo(
5397
+ const contextValue = import_react25.default.useMemo(
5055
5398
  () => ({
5056
5399
  ...value,
5057
5400
  registerField,
@@ -5061,10 +5404,10 @@ var ITFormBuilderProvider = ({
5061
5404
  }),
5062
5405
  [value, registerField, unregisterField, getFieldConfig, getAllFieldConfigs]
5063
5406
  );
5064
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ITFormBuilderContext.Provider, { value: contextValue, children });
5407
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ITFormBuilderContext.Provider, { value: contextValue, children });
5065
5408
  };
5066
5409
  var useITFormBuilderContext = () => {
5067
- const context = (0, import_react24.useContext)(ITFormBuilderContext);
5410
+ const context = (0, import_react25.useContext)(ITFormBuilderContext);
5068
5411
  if (!context) {
5069
5412
  throw new Error("useITFormBuilderContext must be used within an ITFormBuilderProvider");
5070
5413
  }
@@ -5074,13 +5417,13 @@ var useITFormBuilderContext = () => {
5074
5417
  // src/components/organisms/form-builder/fieldRenderer.tsx
5075
5418
  var import_react28 = require("react");
5076
5419
  var import_clsx29 = __toESM(require("clsx"), 1);
5077
-
5078
- // 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");
5420
+
5421
+ // src/components/molecules/time-picker/timePicker.tsx
5422
+ var import_clsx28 = __toESM(require("clsx"), 1);
5423
+ var import_react26 = require("react");
5424
+ var import_react_dom6 = require("react-dom");
5425
+ var import_fa18 = require("react-icons/fa");
5426
+ var import_jsx_runtime31 = require("react/jsx-runtime");
5084
5427
  function ITTimePicker({
5085
5428
  name,
5086
5429
  value,
@@ -5097,12 +5440,12 @@ function ITTimePicker({
5097
5440
  variant = "primary",
5098
5441
  color = "primary"
5099
5442
  }) {
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);
5443
+ const [isOpen, setIsOpen] = (0, import_react26.useState)(false);
5444
+ const [inputValue, setInputValue] = (0, import_react26.useState)(value || "");
5445
+ const [isValidTime, setIsValidTime] = (0, import_react26.useState)(true);
5446
+ const wrapperRef = (0, import_react26.useRef)(null);
5447
+ const hoursRef = (0, import_react26.useRef)(null);
5448
+ const minutesRef = (0, import_react26.useRef)(null);
5106
5449
  const { panelRef: dropdownRef, style: panelStyle } = useFloatingPanel(
5107
5450
  wrapperRef,
5108
5451
  isOpen && !disabled,
@@ -5116,7 +5459,7 @@ function ITTimePicker({
5116
5459
  const isThemeColor = color in theme.colors;
5117
5460
  const highlightColor = isThemeColor ? theme.colors[color][50] : "#f3f4f6";
5118
5461
  const activeColor = isThemeColor ? theme.colors[color][100] : "#e5e7eb";
5119
- (0, import_react25.useEffect)(() => {
5462
+ (0, import_react26.useEffect)(() => {
5120
5463
  setInputValue(value || "");
5121
5464
  }, [value]);
5122
5465
  const validateTime = (timeString) => {
@@ -5125,7 +5468,7 @@ function ITTimePicker({
5125
5468
  };
5126
5469
  const currentHour = validateTime(inputValue) ? inputValue.split(":")[0] : null;
5127
5470
  const currentMinute = validateTime(inputValue) ? inputValue.split(":")[1] : null;
5128
- (0, import_react25.useEffect)(() => {
5471
+ (0, import_react26.useEffect)(() => {
5129
5472
  if (isOpen) {
5130
5473
  setTimeout(() => {
5131
5474
  if (hoursRef.current && currentHour) {
@@ -5195,8 +5538,8 @@ function ITTimePicker({
5195
5538
  { length: 60 },
5196
5539
  (_, i) => i.toString().padStart(2, "0")
5197
5540
  );
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)(
5541
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { ref: wrapperRef, className: (0, import_clsx28.default)("relative w-full", className), children: [
5542
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5200
5543
  ITInput,
5201
5544
  {
5202
5545
  name,
@@ -5212,351 +5555,121 @@ function ITTimePicker({
5212
5555
  variant,
5213
5556
  size,
5214
5557
  touched,
5215
- error: !isValidTime ? "Hora inv\xE1lida" : typeof error === "string" ? error : void 0,
5216
- iconRight: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5217
- import_fa17.FaClock,
5218
- {
5219
- onClick: () => {
5220
- if (!disabled) {
5221
- setIsOpen(!isOpen);
5222
- }
5223
- },
5224
- className: (0, import_clsx27.default)(
5225
- "cursor-pointer transition-colors",
5226
- disabled ? "text-slate-400 cursor-not-allowed" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
5227
- )
5228
- }
5229
- )
5230
- }
5231
- ),
5232
- isOpen && !disabled && (0, import_react_dom5.createPortal)(
5233
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
5234
- "div",
5235
- {
5236
- ref: dropdownRef,
5237
- 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
- style: panelStyle,
5239
- 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" })
5243
- ] }),
5244
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { className: "flex h-56 relative bg-white", children: [
5245
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5246
- "div",
5247
- {
5248
- ref: hoursRef,
5249
- 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) => {
5251
- const isSelected = currentHour === h;
5252
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5253
- "div",
5254
- {
5255
- "data-value": h,
5256
- className: (0, import_clsx27.default)(
5257
- "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5258
- isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5259
- ),
5260
- style: {
5261
- backgroundColor: isSelected ? activeColor : void 0
5262
- },
5263
- onMouseEnter: (e) => {
5264
- if (!isSelected)
5265
- e.currentTarget.style.backgroundColor = highlightColor;
5266
- },
5267
- onMouseLeave: (e) => {
5268
- if (!isSelected)
5269
- e.currentTarget.style.backgroundColor = "transparent";
5270
- },
5271
- onClick: () => handleHourSelect(h),
5272
- children: h
5273
- },
5274
- h
5275
- );
5276
- }) })
5277
- }
5278
- ),
5279
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5280
- "div",
5281
- {
5282
- ref: minutesRef,
5283
- 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) => {
5285
- const isSelected = currentMinute === m;
5286
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5287
- "div",
5288
- {
5289
- "data-value": m,
5290
- className: (0, import_clsx27.default)(
5291
- "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5292
- isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5293
- ),
5294
- style: {
5295
- backgroundColor: isSelected ? activeColor : void 0
5296
- },
5297
- onMouseEnter: (e) => {
5298
- if (!isSelected)
5299
- e.currentTarget.style.backgroundColor = highlightColor;
5300
- },
5301
- onMouseLeave: (e) => {
5302
- if (!isSelected)
5303
- e.currentTarget.style.backgroundColor = "transparent";
5304
- },
5305
- onClick: () => handleMinuteSelect(m),
5306
- children: m
5307
- },
5308
- m
5309
- );
5310
- }) })
5311
- }
5312
- ),
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" })
5314
- ] }),
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)(
5316
- ITButton,
5317
- {
5318
- variant: "solid",
5319
- color,
5320
- size: "sm",
5321
- onClick: handleConfirm,
5322
- children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(ITText, { as: "span", children: "Aceptar" })
5323
- }
5324
- ) })
5325
- ]
5326
- }
5327
- ),
5328
- document.body
5329
- )
5330
- ] });
5331
- }
5332
-
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",
5558
+ error: !isValidTime ? "Hora inv\xE1lida" : typeof error === "string" ? error : void 0,
5559
+ iconRight: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5560
+ import_fa18.FaClock,
5497
5561
  {
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"
5562
+ onClick: () => {
5563
+ if (!disabled) {
5564
+ setIsOpen(!isOpen);
5565
+ }
5566
+ },
5567
+ className: (0, import_clsx28.default)(
5568
+ "cursor-pointer transition-colors",
5569
+ disabled ? "text-slate-400 cursor-not-allowed" : "text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-200"
5570
+ )
5510
5571
  }
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,
5572
+ )
5573
+ }
5574
+ ),
5575
+ isOpen && !disabled && (0, import_react_dom6.createPortal)(
5576
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
5577
+ "div",
5578
+ {
5579
+ ref: dropdownRef,
5580
+ 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",
5581
+ style: panelStyle,
5582
+ children: [
5583
+ /* @__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: [
5584
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "div", className: "flex-1 text-center py-2 border-r border-secondary-100", children: "Horas" }),
5585
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "div", className: "flex-1 text-center py-2", children: "Minutos" })
5586
+ ] }),
5587
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("div", { className: "flex h-56 relative bg-white", children: [
5588
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5589
+ "div",
5542
5590
  {
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 })
5591
+ ref: hoursRef,
5592
+ className: "flex-1 overflow-y-auto no-scrollbar border-r border-secondary-50 scroll-smooth relative",
5593
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "py-2", children: hoursList.map((h) => {
5594
+ const isSelected = currentHour === h;
5595
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5596
+ "div",
5597
+ {
5598
+ "data-value": h,
5599
+ className: (0, import_clsx28.default)(
5600
+ "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5601
+ isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5602
+ ),
5603
+ style: {
5604
+ backgroundColor: isSelected ? activeColor : void 0
5605
+ },
5606
+ onMouseEnter: (e) => {
5607
+ if (!isSelected)
5608
+ e.currentTarget.style.backgroundColor = highlightColor;
5609
+ },
5610
+ onMouseLeave: (e) => {
5611
+ if (!isSelected)
5612
+ e.currentTarget.style.backgroundColor = "transparent";
5613
+ },
5614
+ onClick: () => handleHourSelect(h),
5615
+ children: h
5616
+ },
5617
+ h
5618
+ );
5619
+ }) })
5620
+ }
5621
+ ),
5622
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5623
+ "div",
5624
+ {
5625
+ ref: minutesRef,
5626
+ className: "flex-1 overflow-y-auto no-scrollbar scroll-smooth relative",
5627
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "py-2", children: minutesList.map((m) => {
5628
+ const isSelected = currentMinute === m;
5629
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5630
+ "div",
5631
+ {
5632
+ "data-value": m,
5633
+ className: (0, import_clsx28.default)(
5634
+ "text-center py-2 cursor-pointer transition-all duration-200 text-sm font-medium mx-2 rounded-lg my-1",
5635
+ isSelected ? "text-slate-900 shadow-sm" : "text-slate-600 hover:text-slate-900"
5636
+ ),
5637
+ style: {
5638
+ backgroundColor: isSelected ? activeColor : void 0
5639
+ },
5640
+ onMouseEnter: (e) => {
5641
+ if (!isSelected)
5642
+ e.currentTarget.style.backgroundColor = highlightColor;
5643
+ },
5644
+ onMouseLeave: (e) => {
5645
+ if (!isSelected)
5646
+ e.currentTarget.style.backgroundColor = "transparent";
5647
+ },
5648
+ onClick: () => handleMinuteSelect(m),
5649
+ children: m
5650
+ },
5651
+ m
5652
+ );
5653
+ }) })
5654
+ }
5655
+ ),
5656
+ /* @__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" })
5657
+ ] }),
5658
+ /* @__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)(
5659
+ ITButton,
5660
+ {
5661
+ variant: "solid",
5662
+ color,
5663
+ size: "sm",
5664
+ onClick: handleConfirm,
5665
+ children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ITText, { as: "span", children: "Aceptar" })
5666
+ }
5667
+ ) })
5668
+ ]
5669
+ }
5670
+ ),
5671
+ document.body
5672
+ )
5560
5673
  ] });
5561
5674
  }
5562
5675
 
@@ -7497,6 +7610,14 @@ function ITSegmentedControl({
7497
7610
  var import_react35 = require("react");
7498
7611
  var import_fa26 = require("react-icons/fa");
7499
7612
  var import_jsx_runtime56 = require("react/jsx-runtime");
7613
+ function isSubItemGroup(entry) {
7614
+ return "items" in entry;
7615
+ }
7616
+ function flattenSubItems(entries) {
7617
+ return entries.flatMap(
7618
+ (entry) => isSubItemGroup(entry) ? entry.items : [entry]
7619
+ );
7620
+ }
7500
7621
  function ITSidebar({
7501
7622
  navigationItems = [],
7502
7623
  isCollapsed = false,
@@ -7542,7 +7663,7 @@ function ITSidebar({
7542
7663
  (0, import_react35.useEffect)(() => {
7543
7664
  const activeParents = /* @__PURE__ */ new Set();
7544
7665
  navigationItems.forEach((item) => {
7545
- if (item.subitems && item.subitems.some((sub) => sub.isActive)) {
7666
+ if (item.subitems && flattenSubItems(item.subitems).some((sub) => sub.isActive)) {
7546
7667
  activeParents.add(item.id);
7547
7668
  }
7548
7669
  });
@@ -7576,6 +7697,80 @@ function ITSidebar({
7576
7697
  };
7577
7698
  const isSidebarCollapsed = visibleOnMobile ? false : !isHovering && isCollapsed;
7578
7699
  const sidebarWidth = isSidebarCollapsed ? "w-[88px]" : "w-[280px]";
7700
+ const renderSubItem = (subitem) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
7701
+ "button",
7702
+ {
7703
+ "aria-current": subitem.isActive ? "page" : void 0,
7704
+ onClick: () => {
7705
+ if (subitem.action) subitem.action();
7706
+ if (onSubItemClick) onSubItemClick(subitem);
7707
+ },
7708
+ className: `flex items-center gap-2 w-full text-left px-3 py-1.5 rounded-xl transition-all duration-300`,
7709
+ style: {
7710
+ color: subitem.isActive ? "var(--it-sidebar-active-color, var(--color-secondary-900))" : "var(--it-sidebar-label-color, var(--color-secondary-600))",
7711
+ backgroundColor: subitem.isActive ? "var(--it-sidebar-active-bg, var(--color-secondary-50))" : "transparent",
7712
+ fontSize: "0.78rem",
7713
+ fontWeight: subitem.isActive ? 600 : 500,
7714
+ letterSpacing: "0.01em",
7715
+ marginLeft: subitemConnector === "|" ? "-1px" : "0"
7716
+ },
7717
+ onMouseEnter: (e) => {
7718
+ if (!subitem.isActive) {
7719
+ e.currentTarget.style.backgroundColor = "var(--it-sidebar-hover-bg, var(--color-secondary-100))";
7720
+ e.currentTarget.style.transform = "translateX(3px)";
7721
+ }
7722
+ },
7723
+ onMouseLeave: (e) => {
7724
+ if (!subitem.isActive) {
7725
+ e.currentTarget.style.backgroundColor = "transparent";
7726
+ e.currentTarget.style.transform = "translateX(0)";
7727
+ }
7728
+ },
7729
+ children: [
7730
+ subitem.isActive && subitemConnector === "|" && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7731
+ "div",
7732
+ {
7733
+ className: "absolute left-0 top-1/3 bottom-1/3 w-[2.5px] rounded-r-full transition-all",
7734
+ style: {
7735
+ backgroundColor: "var(--it-sidebar-active-icon, var(--color-primary-500))",
7736
+ boxShadow: "0 0 6px color-mix(in srgb, var(--it-sidebar-active-icon, var(--color-primary-500)) 25%, transparent)"
7737
+ }
7738
+ }
7739
+ ),
7740
+ subitemConnector === "dot" && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7741
+ "span",
7742
+ {
7743
+ className: `w-1.5 h-1.5 rounded-full flex-shrink-0 transition-all duration-300 ${subitem.isActive ? "scale-125" : ""}`,
7744
+ style: {
7745
+ backgroundColor: subitem.isActive ? "var(--it-sidebar-active-icon, var(--color-primary-500))" : "var(--it-sidebar-icon-color, var(--color-secondary-400))"
7746
+ }
7747
+ }
7748
+ ),
7749
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ITText, { as: "span", className: "truncate", children: subitem.label })
7750
+ ]
7751
+ }
7752
+ ) }, subitem.id);
7753
+ const renderSubItemGroup = (group, itemId) => {
7754
+ const headingId = `it-sidebar-subgroup-${itemId}-${group.id}`;
7755
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("li", { className: "relative", children: [
7756
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { id: headingId, className: "px-3 pt-2.5 pb-1 mt-1", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7757
+ ITText,
7758
+ {
7759
+ as: "span",
7760
+ className: "block",
7761
+ style: {
7762
+ color: "var(--it-sidebar-icon-color, var(--color-secondary-400))",
7763
+ fontSize: "0.68rem",
7764
+ fontWeight: 700,
7765
+ letterSpacing: "0.08em",
7766
+ textTransform: "uppercase"
7767
+ },
7768
+ children: group.label
7769
+ }
7770
+ ) }),
7771
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("ul", { "aria-labelledby": headingId, className: "flex flex-col gap-0", children: group.items.map(renderSubItem) })
7772
+ ] }, group.id);
7773
+ };
7579
7774
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
7580
7775
  "aside",
7581
7776
  {
@@ -7709,7 +7904,7 @@ function ITSidebar({
7709
7904
  item.icon && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { style: { color: "var(--it-sidebar-active-icon, var(--color-primary-500))" }, className: "text-xl drop-shadow-sm", children: item.icon }),
7710
7905
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ITText, { as: "span", className: "tracking-wide text-[15px]", children: item.label })
7711
7906
  ] }),
7712
- item.subitems && item.subitems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "py-2", children: item.subitems.map((subitem) => /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
7907
+ item.subitems && item.subitems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "py-2", children: flattenSubItems(item.subitems).map((subitem) => /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
7713
7908
  "div",
7714
7909
  {
7715
7910
  className: `px-5 py-2.5 text-sm flex items-center gap-3 transition-colors relative`,
@@ -7733,66 +7928,16 @@ function ITSidebar({
7733
7928
  ]
7734
7929
  }
7735
7930
  ),
7736
- !isSidebarCollapsed && item.subitems && item.subitems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { id: submenuId, role: "group", "aria-label": item.label, className: `overflow-hidden transition-all duration-400 ease-[cubic-bezier(0.2,0,0,1)] ${expandedItems.has(item.id) ? "max-h-[500px] opacity-100 mt-1" : "max-h-0 opacity-0"}`, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7931
+ !isSidebarCollapsed && item.subitems && item.subitems.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { id: submenuId, role: "group", "aria-label": item.label, className: `overflow-hidden transition-all duration-400 ease-[cubic-bezier(0.2,0,0,1)] ${expandedItems.has(item.id) ? "max-h-[1000px] opacity-100 mt-1" : "max-h-0 opacity-0"}`, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7737
7932
  "ul",
7738
7933
  {
7739
7934
  className: "ml-4 flex flex-col gap-0 py-0.5",
7740
7935
  style: {
7741
7936
  borderLeft: subitemConnector === "|" ? "1px solid var(--it-sidebar-border, var(--color-secondary-200))" : "none"
7742
7937
  },
7743
- children: item.subitems.map((subitem) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("li", { className: "relative", children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
7744
- "button",
7745
- {
7746
- "aria-current": subitem.isActive ? "page" : void 0,
7747
- onClick: () => {
7748
- if (subitem.action) subitem.action();
7749
- if (onSubItemClick) onSubItemClick(subitem);
7750
- },
7751
- className: `flex items-center gap-2 w-full text-left px-3 py-1.5 rounded-xl transition-all duration-300`,
7752
- style: {
7753
- color: subitem.isActive ? "var(--it-sidebar-active-color, var(--color-secondary-900))" : "var(--it-sidebar-label-color, var(--color-secondary-600))",
7754
- backgroundColor: subitem.isActive ? "var(--it-sidebar-active-bg, var(--color-secondary-50))" : "transparent",
7755
- fontSize: "0.78rem",
7756
- fontWeight: subitem.isActive ? 600 : 500,
7757
- letterSpacing: "0.01em",
7758
- marginLeft: subitemConnector === "|" ? "-1px" : "0"
7759
- },
7760
- onMouseEnter: (e) => {
7761
- if (!subitem.isActive) {
7762
- e.currentTarget.style.backgroundColor = "var(--it-sidebar-hover-bg, var(--color-secondary-100))";
7763
- e.currentTarget.style.transform = "translateX(3px)";
7764
- }
7765
- },
7766
- onMouseLeave: (e) => {
7767
- if (!subitem.isActive) {
7768
- e.currentTarget.style.backgroundColor = "transparent";
7769
- e.currentTarget.style.transform = "translateX(0)";
7770
- }
7771
- },
7772
- children: [
7773
- subitem.isActive && subitemConnector === "|" && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7774
- "div",
7775
- {
7776
- className: "absolute left-0 top-1/3 bottom-1/3 w-[2.5px] rounded-r-full transition-all",
7777
- style: {
7778
- backgroundColor: "var(--it-sidebar-active-icon, var(--color-primary-500))",
7779
- boxShadow: "0 0 6px color-mix(in srgb, var(--it-sidebar-active-icon, var(--color-primary-500)) 25%, transparent)"
7780
- }
7781
- }
7782
- ),
7783
- subitemConnector === "dot" && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
7784
- "span",
7785
- {
7786
- className: `w-1.5 h-1.5 rounded-full flex-shrink-0 transition-all duration-300 ${subitem.isActive ? "scale-125" : ""}`,
7787
- style: {
7788
- backgroundColor: subitem.isActive ? "var(--it-sidebar-active-icon, var(--color-primary-500))" : "var(--it-sidebar-icon-color, var(--color-secondary-400))"
7789
- }
7790
- }
7791
- ),
7792
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ITText, { as: "span", className: "truncate", children: subitem.label })
7793
- ]
7794
- }
7795
- ) }, subitem.id))
7938
+ children: item.subitems.map(
7939
+ (entry) => isSubItemGroup(entry) ? renderSubItemGroup(entry, item.id) : renderSubItem(entry)
7940
+ )
7796
7941
  }
7797
7942
  ) })
7798
7943
  ] }, item.id);
@@ -7986,6 +8131,7 @@ var import_clsx43 = __toESM(require("clsx"), 1);
7986
8131
  var import_react37 = __toESM(require("react"), 1);
7987
8132
  var import_fa27 = require("react-icons/fa");
7988
8133
  var import_md2 = require("react-icons/md");
8134
+ var import_date_fns3 = require("date-fns");
7989
8135
  var import_jsx_runtime60 = require("react/jsx-runtime");
7990
8136
  function ITTable({
7991
8137
  columns,
@@ -8069,15 +8215,32 @@ function ITTable({
8069
8215
  }, [data, sortConfig, columns]);
8070
8216
  const filteredData = sortedData.filter(
8071
8217
  (row) => columns.every((col) => {
8072
- if (!col.filter || filters[col.key] === void 0 || filters[col.key] === "")
8218
+ const rawFilter = filters[col.key];
8219
+ if (!col.filter || rawFilter === void 0 || rawFilter === "") return true;
8220
+ if (Array.isArray(rawFilter) && rawFilter[0] == null && rawFilter[1] == null) {
8073
8221
  return true;
8222
+ }
8074
8223
  const value = getNestedValue(row, col.key);
8075
- const filterValue = String(filters[col.key]).toLowerCase();
8224
+ if (col.filter === "date" || col.filter === "date-range") {
8225
+ const rowDate = value instanceof Date ? value : new Date(String(value));
8226
+ if (isNaN(rowDate.getTime())) return false;
8227
+ if (col.filter === "date") {
8228
+ return (0, import_date_fns3.isSameDay)(rowDate, rawFilter);
8229
+ }
8230
+ const [start, end] = rawFilter;
8231
+ if (start && rowDate.getTime() < (0, import_date_fns3.startOfDay)(start).getTime()) return false;
8232
+ if (end && rowDate.getTime() > (0, import_date_fns3.endOfDay)(end).getTime()) return false;
8233
+ return true;
8234
+ }
8235
+ if (col.filter === "search") {
8236
+ return String(value) === String(rawFilter);
8237
+ }
8238
+ const filterValue = String(rawFilter).toLowerCase();
8076
8239
  switch (col.type) {
8077
8240
  case "number":
8078
8241
  return String(value).includes(filterValue);
8079
8242
  case "boolean":
8080
- return value === filters[col.key];
8243
+ return value === rawFilter;
8081
8244
  case "catalog": {
8082
8245
  if (!col.catalogOptions) return true;
8083
8246
  const catalogItem = col.catalogOptions.data.find(
@@ -8100,6 +8263,7 @@ function ITTable({
8100
8263
  const isStickyHeader = stickyHeader && isTableVirtual;
8101
8264
  const resolvedRowHeight = rowHeight ?? getRowHeight(size, density);
8102
8265
  const columnCount = columns.length;
8266
+ const pinnedMeta = import_react37.default.useMemo(() => getPinnedColumnMeta(columns), [columns]);
8103
8267
  const {
8104
8268
  scrollRef,
8105
8269
  startIndex,
@@ -8183,6 +8347,75 @@ function ITTable({
8183
8347
  }
8184
8348
  );
8185
8349
  }
8350
+ if (col.filter === "search" && col.catalogOptions) {
8351
+ if (col.catalogOptions.loading) {
8352
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8353
+ import_fa27.FaSpinner,
8354
+ {
8355
+ className: "animate-spin",
8356
+ "aria-label": "Cargando opciones",
8357
+ title: "Cargando opciones"
8358
+ }
8359
+ );
8360
+ }
8361
+ if (col.catalogOptions.error) {
8362
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ITText, { as: "span", className: "text-danger-500 text-xs", children: "Error cargando" });
8363
+ }
8364
+ const searchValue = filters[col.key];
8365
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8366
+ ITSearchSelect,
8367
+ {
8368
+ name: `filter-${col.key}`,
8369
+ options: col.catalogOptions.data.map((item) => ({
8370
+ value: item.id,
8371
+ label: item.name
8372
+ })),
8373
+ value: typeof searchValue === "string" || typeof searchValue === "number" ? searchValue : "",
8374
+ onChange: (value) => handleFilterChange(col.key, value === "" ? void 0 : value),
8375
+ onSearch: col.catalogOptions.onSearch,
8376
+ isLoading: col.catalogOptions.loading,
8377
+ size: "sm",
8378
+ placeholder: "Buscar...",
8379
+ clearable: true,
8380
+ className: "w-full",
8381
+ onBlur: () => {
8382
+ }
8383
+ }
8384
+ );
8385
+ }
8386
+ if (col.filter === "date") {
8387
+ const dateValue = filters[col.key];
8388
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8389
+ ITDatePicker,
8390
+ {
8391
+ name: `filter-${col.key}`,
8392
+ value: dateValue instanceof Date ? dateValue : void 0,
8393
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
8394
+ minDate: col.dateFilterOptions?.minDate,
8395
+ maxDate: col.dateFilterOptions?.maxDate,
8396
+ size: "sm",
8397
+ placeholder: "dd/mm/aaaa",
8398
+ className: "w-full"
8399
+ }
8400
+ );
8401
+ }
8402
+ if (col.filter === "date-range") {
8403
+ const rangeValue = filters[col.key];
8404
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8405
+ ITDatePicker,
8406
+ {
8407
+ name: `filter-${col.key}`,
8408
+ range: true,
8409
+ value: Array.isArray(rangeValue) ? rangeValue : void 0,
8410
+ onChange: (e) => handleFilterChange(col.key, e.target.value),
8411
+ minDate: col.dateFilterOptions?.minDate,
8412
+ maxDate: col.dateFilterOptions?.maxDate,
8413
+ size: "sm",
8414
+ placeholder: "dd/mm/aaaa - dd/mm/aaaa",
8415
+ className: "w-full"
8416
+ }
8417
+ );
8418
+ }
8186
8419
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8187
8420
  ITInput,
8188
8421
  {
@@ -8355,37 +8588,45 @@ function ITTable({
8355
8588
  {
8356
8589
  className: (0, import_clsx43.default)(tableHeaderRow, "dark:text-slate-200"),
8357
8590
  "aria-rowindex": isTableVirtual ? 1 : void 0,
8358
- children: columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8359
- "th",
8360
- {
8361
- scope: "col",
8362
- className: (0, import_clsx43.default)(
8363
- tableHeaderCell(col.className, density),
8364
- col.align && tableAlignClasses[col.align],
8365
- isStickyHeader && "sticky top-0 z-10 bg-secondary-50"
8366
- ),
8367
- style: col.minWidth != null || isStickyHeader ? {
8368
- ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
8369
- ...isStickyHeader ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {}
8370
- } : void 0,
8371
- children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
8372
- /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
8373
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
8374
- col.sortable && col.type !== "actions" && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8375
- "button",
8376
- {
8377
- onClick: () => handleSort(col.key),
8378
- 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"}`,
8379
- title: `Ordenar por ${col.label}`,
8380
- children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_md2.MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
8381
- }
8382
- )
8383
- ] }),
8384
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
8385
- ] })
8386
- },
8387
- col.key
8388
- ))
8591
+ children: columns.map((col) => {
8592
+ const pin = pinnedMeta[col.key];
8593
+ const isPinned = pin != null;
8594
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8595
+ "th",
8596
+ {
8597
+ scope: "col",
8598
+ className: (0, import_clsx43.default)(
8599
+ tableHeaderCell(col.className, density),
8600
+ col.align && tableAlignClasses[col.align],
8601
+ isPinned && "sticky",
8602
+ isStickyHeader && "sticky top-0 bg-secondary-50",
8603
+ isPinned ? "z-[15]" : isStickyHeader && "z-10",
8604
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right")
8605
+ ),
8606
+ style: col.minWidth != null || isStickyHeader || isPinned ? {
8607
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
8608
+ ...isStickyHeader || isPinned ? { backgroundColor: "var(--color-table-headerBg, #f8fafc)" } : {},
8609
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
8610
+ } : void 0,
8611
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: isFixed ? "flex flex-col gap-3" : "flex flex-col gap-3 min-w-[150px]", children: [
8612
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: "flex items-center justify-between gap-2", children: [
8613
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ITText, { as: "span", className: "text-slate-900 dark:text-white font-bold", children: col.label }),
8614
+ col.sortable && col.type !== "actions" && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8615
+ "button",
8616
+ {
8617
+ onClick: () => handleSort(col.key),
8618
+ 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"}`,
8619
+ title: `Ordenar por ${col.label}`,
8620
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_md2.MdOutlineSwapVert, { className: "w-4 h-4", "aria-hidden": "true" })
8621
+ }
8622
+ )
8623
+ ] }),
8624
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: "w-full", children: col.filter ? renderFilterInput(col) : null })
8625
+ ] })
8626
+ },
8627
+ col.key
8628
+ );
8629
+ })
8389
8630
  }
8390
8631
  ) }),
8391
8632
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("tbody", { className: (0, import_clsx43.default)(tableBody, "dark:divide-slate-700/30"), children: currentData.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_jsx_runtime60.Fragment, { children: [
@@ -8407,14 +8648,22 @@ function ITTable({
8407
8648
  children: columns.map((col) => {
8408
8649
  const rawValue = getNestedValue(row, col.key);
8409
8650
  const truncateTitle = col.truncate && (typeof rawValue === "string" || typeof rawValue === "number") ? String(rawValue) : void 0;
8651
+ const pin = pinnedMeta[col.key];
8652
+ const isPinned = pin != null;
8410
8653
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
8411
8654
  "td",
8412
8655
  {
8413
8656
  className: (0, import_clsx43.default)(
8414
8657
  tableCell(col.className, density),
8415
- col.align && tableAlignClasses[col.align]
8658
+ col.align && tableAlignClasses[col.align],
8659
+ isPinned && "sticky bg-[var(--color-table-rowBg,white)] group-hover:bg-[var(--color-table-rowHover,var(--color-secondary-50))]",
8660
+ isPinned && (col.pinned === "left" ? "it-table-pinned-left" : "it-table-pinned-right"),
8661
+ isPinned && "z-[1]"
8416
8662
  ),
8417
- style: col.minWidth != null ? { minWidth: `${col.minWidth}px` } : void 0,
8663
+ style: col.minWidth != null || isPinned ? {
8664
+ ...col.minWidth != null ? { minWidth: `${col.minWidth}px` } : {},
8665
+ ...isPinned ? pin.side === "left" ? { left: pin.offset } : { right: pin.offset } : {}
8666
+ } : void 0,
8418
8667
  title: truncateTitle,
8419
8668
  children: col.type === "actions" ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: tableActionsCell, children: renderCellContent(col, row) }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("div", { className: (0, import_clsx43.default)(tableCellText, col.truncate && "truncate"), children: renderCellContent(col, row) })
8420
8669
  },